BroadcomfullmacWLAN驱动解析(转)

来源:互联网 发布:北京知行 pt 编辑:程序博客网 时间:2024/04/28 15:05

现在我们来看看scan是怎么处理的。

一、先来看看如何发送scan command给WLAN firmware

以Android平台为例,我们从Android framework的code开始看起。

1. 在WifiStateMachine.java中有如下函数

 public void startScan(boolean forceActive) {sendMessage(obtainMessage(CMD_START_SCAN, forceActive ?SCAN_ACTIVE : SCAN_PASSIVE, 0));}

2. processMessage()函数会处理CMD_START_SCAN

 @Overridepublic boolean processMessage(Message message) {if (DBG) log(getName() + message.toString() + "\n");boolean eventLoggingEnabled = true;switch(message.what) {case CMD_SET_SCAN_TYPE:if (message.arg1 == SCAN_ACTIVE) {WifiNative.setScanModeCommand(true);} else {WifiNative.setScanModeCommand(false);}break;// 处理CMD_START_SCANcase CMD_START_SCAN:eventLoggingEnabled = false;WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE);mScanResultIsPending = true;break;...default:return NOT_HANDLED;}if (eventLoggingEnabled) {EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);}return HANDLED;}

3. 接下来就会执行到JNI函数里面

static jboolean android_net_wifi_scanCommand(JNIEnv* env, jobject, jboolean forceActive){jboolean result;// Ignore any error from setting the scan mode.// The scan will still work.if (forceActive && !sScanModeActive)doSetScanMode(true);// 关键是这里,"SCAN"这个字符串命令result = doBooleanCommand("OK", "SCAN");if (forceActive && !sScanModeActive)doSetScanMode(sScanModeActive);return result;}

4. 继续跟进doBooleanCommand()

static jboolean doBooleanCommand(const char* expect, const char* fmt, ...){char buf[BUF_SIZE];va_list args;va_start(args, fmt);int byteCount = vsnprintf(buf, sizeof(buf), fmt, args);va_end(args);if (byteCount < 0 || byteCount >= BUF_SIZE) {return JNI_FALSE;}char reply[BUF_SIZE];if (doCommand(buf, reply, sizeof(reply)) != 0) {return JNI_FALSE;}return (strcmp(reply, expect) == 0);}

5. 调用doCommand()

static int doCommand(const char *cmd, char *replybuf, int replybuflen){size_t reply_len = replybuflen - 1;// 这里已经调用Android HAL层的API了if (::wifi_command(cmd, replybuf, &reply_len) != 0)return -1;else {// Strip off trailing newlineif (reply_len > 0 && replybuf[reply_len-1] == '\n')replybuf[reply_len-1] = '\0';elsereplybuf[reply_len] = '\0';return 0;}}

6. 执行到了wifi.c中的wifi_command()

int wifi_command(const char *command, char *reply, size_t *reply_len){// 后面会提到ctrl_conn是怎么来的return wifi_send_command(ctrl_conn, command, reply, reply_len);}
int wifi_send_command(struct wpa_ctrl *ctrl, const char *cmd, char *reply, size_t *reply_len){int ret;if (ctrl_conn == NULL) {LOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd);return -1;}// 注意这里,调用了wpa_supplicant的接口!这里cmd就是之前传递的参数"SCAN"ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), reply, reply_len, NULL);if (ret == -2) {LOGD("'%s' command timed out.\n", cmd);/* unblocks the monitor receive socket for termination */write(exit_sockets[0], "T", 1);return -2;} else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) {return -1;}if (strncmp(cmd, "PING", 4) == 0) {reply[*reply_len] = '\0';}return 0;}

7. wpa_ctrl_request要能成功发送command的话,之前就必须先得调用wpa_ctrl_open(), 所以我们来看一下wifi_connect_to_supplicant():

int wifi_connect_to_supplicant(){char ifname[256];char supp_status[PROPERTY_VALUE_MAX] = {'\0'};/* Make sure supplicant is running */if (!property_get(SUPP_PROP_NAME, supp_status, NULL)|| strcmp(supp_status, "running") != 0) {LOGE("Supplicant not running, cannot connect");return -1;}if (access(IFACE_DIR, F_OK) == 0) {snprintf(ifname, sizeof(ifname), "%s/%s", IFACE_DIR, iface);} else {strlcpy(ifname, iface, sizeof(ifname));}// 这里是ctrl_connctrl_conn = wpa_ctrl_open(ifname);if (ctrl_conn == NULL) {LOGE("Unable to open connection to supplicant on \"%s\": %s",ifname, strerror(errno));return -1;}// 这里是monitor_connmonitor_conn = wpa_ctrl_open(ifname);if (monitor_conn == NULL) {wpa_ctrl_close(ctrl_conn);ctrl_conn = NULL;return -1;}if (wpa_ctrl_attach(monitor_conn) != 0) {wpa_ctrl_close(monitor_conn);wpa_ctrl_close(ctrl_conn);ctrl_conn = monitor_conn = NULL;return -1;}if (socketpair(AF_UNIX, SOCK_STREAM, 0, exit_sockets) == -1) {wpa_ctrl_close(monitor_conn);wpa_ctrl_close(ctrl_conn);ctrl_conn = monitor_conn = NULL;return -1;}return 0;}

这里的iface是从property中取出来的:

property_get("wifi.interface", iface, WIFI_TEST_INTERFACE);

这个值是预先由OEM厂商设定好的,比如device/samsung/tuna/device.mk中有下面的code:

wifi.interface=wlan0

8. 那接下来就是要走到wpa_supplicant中了,要去处理这个"SCAN" command。要知道是在哪里处理command, 还得看一下wpa_supplicant的初始化过程:

8.1 从main()开始看起

int main(int argc, char *argv[]){int c, i;struct wpa_interface *ifaces, *iface;int iface_count, exitcode = -1;struct wpa_params params;struct wpa_global *global;if (os_program_init())return -1;os_memset(&params, 0, sizeof(params));params.wpa_debug_level = MSG_INFO;iface = ifaces = os_zalloc(sizeof(struct wpa_interface));if (ifaces == NULL)return -1;iface_count = 1;wpa_supplicant_fd_workaround();...exitcode = 0;global = wpa_supplicant_init(&params);if (global == NULL) {wpa_printf(MSG_ERROR, "Failed to initialize wpa_supplicant");exitcode = -1;goto out;}for (i = 0; exitcode == 0 && i < iface_count; i++) {if ((ifaces[i].confname == NULL &&ifaces[i].ctrl_interface == NULL) ||ifaces[i].ifname == NULL) {if (iface_count == 1 && (params.ctrl_interface ||params.dbus_ctrl_interface))break;usage();exitcode = -1;break;}// 注意这里if (wpa_supplicant_add_iface(global, &ifaces[i]) == NULL)exitcode = -1;}...return exitcode;}

8.2 调用wpa_supplicant_add_iface()

struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,struct wpa_interface *iface){struct wpa_supplicant *wpa_s;struct wpa_interface t_iface;struct wpa_ssid *ssid;if (global == NULL || iface == NULL)return NULL;// 非常重要!这里给wpa_s分配了内存空间wpa_s = wpa_supplicant_alloc();if (wpa_s == NULL)return NULL;wpa_s->global = global;t_iface = *iface;...// 注意这里,wpa_s作为参数传递给了wpa_supplicant_init_iface()if (wpa_supplicant_init_iface(wpa_s, &t_iface)) {wpa_printf(MSG_DEBUG, "Failed to add interface %s",iface->ifname);wpa_supplicant_deinit_iface(wpa_s, 0);os_free(wpa_s);return NULL;}...return wpa_s;}

8.3 调用wpa_supplicant_init_iface()

static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,struct wpa_interface *iface){const char *ifname, *driver;struct wpa_driver_capa capa;...// 在main()中,iface->confname是由-c参数传进来的if (iface->confname) {#ifdef CONFIG_BACKEND_FILEwpa_s->confname = os_rel2abs_path(iface->confname);if (wpa_s->confname == NULL) {wpa_printf(MSG_ERROR, "Failed to get absolute path ""for configuration file '%s'.",iface->confname);return -1;}wpa_printf(MSG_DEBUG, "Configuration file '%s' -> '%s'",iface->confname, wpa_s->confname);#else /* CONFIG_BACKEND_FILE */wpa_s->confname = os_strdup(iface->confname);#endif /* CONFIG_BACKEND_FILE */// 注意wpa_s->conf是从iface->confname指向的那个文件读取来的// 也就是启动wpa_supplicant的命令行中-c参数后面的那个文件名wpa_s->conf = wpa_config_read(wpa_s->confname);if (wpa_s->conf == NULL) {wpa_printf(MSG_ERROR, "Failed to read or parse ""configuration '%s'.", wpa_s->confname);return -1;}/** Override ctrl_interface and driver_param if set on command* line.*/if (iface->ctrl_interface) {os_free(wpa_s->conf->ctrl_interface);wpa_s->conf->ctrl_interface =os_strdup(iface->ctrl_interface);}if (iface->driver_param) {os_free(wpa_s->conf->driver_param);wpa_s->conf->driver_param =os_strdup(iface->driver_param);}} elsewpa_s->conf = wpa_config_alloc_empty(iface->ctrl_interface,iface->driver_param);...if (wpa_supplicant_driver_init(wpa_s) < 0)return -1;if (wpa_s->conf->country[0] && wpa_s->conf->country[1] &&wpa_drv_set_country(wpa_s, wpa_s->conf->country)) {wpa_printf(MSG_DEBUG, "Failed to set country");return -1;}wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);if (wpas_wps_init(wpa_s))return -1;if (wpa_supplicant_init_eapol(wpa_s) < 0)return -1;wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);// 目前我们只关心这里,注意wpa_s作为参数传给了wpa_supplicant_ctrl_iface_init()wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);...if (wpa_bss_init(wpa_s) < 0)return -1;return 0;}

8.4 调用wpa_supplicant_ctrl_iface_init()

struct ctrl_iface_priv *wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s){...// 这里第二个参数便是handlereloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,wpa_s, priv);wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);os_free(buf);return priv;...}

8.5 显然所有的command将会在wpa_supplicant_ctrl_iface_receive()中收到

static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,void *sock_ctx){// 注意这里得到了wpa_sstruct wpa_supplicant *wpa_s = eloop_ctx;struct ctrl_iface_priv *priv = sock_ctx;char buf[256];int res;struct sockaddr_un from;socklen_t fromlen = sizeof(from);char *reply = NULL;size_t reply_len = 0;int new_attached = 0;res = recvfrom(sock, buf, sizeof(buf) - 1, 0,(struct sockaddr *) &from, &fromlen);if (res < 0) {perror("recvfrom(ctrl_iface)");return;}buf[res] = '\0';if (os_strcmp(buf, "ATTACH") == 0) {if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen))reply_len = 1;else {new_attached = 1;reply_len = 2;}} else if (os_strcmp(buf, "DETACH") == 0) {if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen))reply_len = 1;elsereply_len = 2;} else if (os_strncmp(buf, "LEVEL ", 6) == 0) {if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen,buf + 6))reply_len = 1;elsereply_len = 2;} else {// 除了上面三种command之外的其它command,就在下面得到处理reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,&reply_len);}if (reply) {sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,fromlen);os_free(reply);} else if (reply_len == 1) {sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,fromlen);} else if (reply_len == 2) {sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,fromlen);}if (new_attached)eapol_sm_notify_ctrl_attached(wpa_s->eapol);}

9. 在wpa_supplicant_ctrl_iface_process()中处理"SCAN" command

char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,char *buf, size_t *resp_len){char *reply;const int reply_size = 2048;int ctrl_rsp = 0;int reply_len;...reply = os_malloc(reply_size);if (reply == NULL) {*resp_len = 1;return NULL;}os_memcpy(reply, "OK\n", 3);reply_len = 3;if (os_strcmp(buf, "PING") == 0) {os_memcpy(reply, "PONG\n", 5);reply_len = 5;}...else if (os_strcmp(buf, "SCAN") == 0) {wpa_s->scan_req = 2;// 注意这里wpa_supplicant_req_scan(wpa_s, 0, 0);} else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {reply_len = wpa_supplicant_ctrl_iface_scan_results(wpa_s, reply, reply_size);}...else {os_memcpy(reply, "UNKNOWN COMMAND\n", 16);reply_len = 16;}if (reply_len < 0) {os_memcpy(reply, "FAIL\n", 5);reply_len = 5;}if (ctrl_rsp)eapol_sm_notify_ctrl_response(wpa_s->eapol);*resp_len = reply_len;return reply;}

10. 调用wpa_supplicant_req_scan() 

void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec){...if (eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL) &&wpa_s->conf->ap_scan == 1) {// 可以看到ssid是从wpa_s->conf中得到的// 在Android framework中,当用户在UI在选定一个AP/SSID连接时,// Settings App会调用到WifiManager的方法addNetwork()// 从而最终set到wpa_s->conf->ssid// 而WifiManager的另外一个方法saveNetwork()则会让wpa_supplicant// 把wpa_s->conf再写到iface->confname指向的文件中// 以后会把这部分逻辑分析一下struct wpa_ssid *ssid = wpa_s->conf->ssid;while (ssid) {if (!ssid->disabled && ssid->scan_ssid)break;ssid = ssid->next;}if (ssid) {wpa_msg(wpa_s, MSG_DEBUG, "Not rescheduling scan to ""ensure that specific SSID scans occur");return;}}wpa_msg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec",sec, usec);eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);// 注意第三个参数是handler eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL);}

可以看到通过timer的handler即将会触发wpa_supplicant_scan().

11. 调用wpa_supplicant_scan()

static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx){struct wpa_supplicant *wpa_s = eloop_ctx;struct wpa_ssid *ssid;int scan_req = 0, ret;struct wpabuf *wps_ie = NULL;...params.filter_ssids = wpa_supplicant_build_filter_ssids(wpa_s->conf, &params.num_filter_ssids);// 注意这里ret = wpa_supplicant_trigger_scan(wpa_s, &params);wpabuf_free(wps_ie);os_free(params.freqs);os_free(params.filter_ssids);if (ret) {wpa_printf(MSG_WARNING, "Failed to initiate AP scan.");if (prev_state != wpa_s->wpa_state)wpa_supplicant_set_state(wpa_s, prev_state);wpa_supplicant_req_scan(wpa_s, 1, 0);}}

 12. 调用wpa_supplicant_trigger_scan() 

int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,struct wpa_driver_scan_params *params){int ret;wpa_supplicant_notify_scanning(wpa_s, 1);if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)ret = ieee80211_sta_req_scan(wpa_s, params);else // 注意这里ret = wpa_drv_scan(wpa_s, params);if (ret) {wpa_supplicant_notify_scanning(wpa_s, 0);wpas_notify_scan_done(wpa_s, 0);} elsewpa_s->scan_runs++;return ret;}

13. 调用wpa_drv_scan()

static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s,struct wpa_driver_scan_params *params){if (wpa_s->driver->scan2)return wpa_s->driver->scan2(wpa_s->drv_priv, params);return -1;}

14. 这里我们假定采用了nl80211接口,那么driver_nl80211.c中的wpa_driver_nl80211_scan()将会被触发

static int wpa_driver_nl80211_scan(void *priv,struct wpa_driver_scan_params *params){struct i802_bss *bss = priv;struct wpa_driver_nl80211_data *drv = bss->drv;int ret = 0, timeout;struct nl_msg *msg, *ssids, *freqs;size_t i;msg = nlmsg_alloc();ssids = nlmsg_alloc();freqs = nlmsg_alloc();if (!msg || !ssids || !freqs) {nlmsg_free(msg);nlmsg_free(ssids);nlmsg_free(freqs);return -1;}os_free(drv->filter_ssids);drv->filter_ssids = params->filter_ssids;params->filter_ssids = NULL;drv->num_filter_ssids = params->num_filter_ssids;// 关键是这个NL80211_CMD_TRIGGER_SCAN命令genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,NL80211_CMD_TRIGGER_SCAN, 0);NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);for (i = 0; i < params->num_ssids; i++) {wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",params->ssids[i].ssid,params->ssids[i].ssid_len);NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len,params->ssids[i].ssid);}if (params->num_ssids)nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);if (params->extra_ies) {wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan extra IEs",params->extra_ies, params->extra_ies_len);NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len,params->extra_ies);}if (params->freqs) {for (i = 0; params->freqs[i]; i++) {wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u ""MHz", params->freqs[i]);NLA_PUT_U32(freqs, i + 1, params->freqs[i]);}nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);}ret = send_and_recv_msgs(drv, msg, NULL, NULL);msg = NULL;...}

15. scan message经由netlink进入到Linux内核当中去处理。

由nl80211.c中的nl80211_ops中的定义可以知道对应的command handler:

 {.cmd = NL80211_CMD_TRIGGER_SCAN,.doit = nl80211_trigger_scan,.policy = nl80211_policy,.flags = GENL_ADMIN_PERM,.internal_flags = NL80211_FLAG_NEED_WDEV_UP |NL80211_FLAG_NEED_RTNL,},

16. 调用nl80211_trigger_scan()

static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info){...request->wdev = wdev;request->wiphy = &rdev->wiphy;request->scan_start = jiffies;rdev->scan_req = request;// 只看这边最关键的代码:err = rdev_scan(rdev, request);if (!err) {nl80211_send_scan_start(rdev, wdev);if (wdev->netdev)dev_hold(wdev->netdev);} else {out_free:rdev->scan_req = NULL;kfree(request);}return err;}

17. 调用rdev_scan()

static inline int rdev_scan(struct cfg80211_registered_device *rdev,struct cfg80211_scan_request *request){int ret;trace_rdev_scan(&rdev->wiphy, request);ret = rdev->ops->scan(&rdev->wiphy, request);trace_rdev_return_int(&rdev->wiphy, ret);return ret;}

18. 根据上一节的分析,brcmf_cfg80211_scan()被调用

static s32brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request){struct net_device *ndev = request->wdev->netdev;s32 err = 0;brcmf_dbg(TRACE, "Enter\n");if (!check_vif_up(container_of(request->wdev,struct brcmf_cfg80211_vif, wdev)))return -EIO;err = brcmf_cfg80211_escan(wiphy, ndev, request, NULL);if (err)brcmf_err("scan error (%d)\n", err);brcmf_dbg(TRACE, "Exit\n");return err;}

19. 调用brcmf_cfg80211_escan()

static s32brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,struct cfg80211_scan_request *request,struct cfg80211_ssid *this_ssid){struct brcmf_if *ifp = netdev_priv(ndev);struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);struct cfg80211_ssid *ssids;struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int;u32 passive_scan;bool escan_req;bool spec_scan;s32 err;u32 SSID_len;...escan_req = false;if (request) {/* scan bss */ssids = request->ssids;escan_req = true;} else {/* scan in ibss *//* we don't do escan in ibss */ssids = this_ssid;}cfg->scan_request = request;set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);if (escan_req) {// 注意这里给run函数指针赋值cfg->escan_info.run = brcmf_run_escan;err = brcmf_p2p_scan_prep(wiphy, request, ifp->vif);if (err)goto scan_out;// 执行brcmf_do_escanerr = brcmf_do_escan(cfg, wiphy, ndev, request);if (err)goto scan_out;}...return 0;...}

20. 调用brcmf_do_escan()

static s32brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,struct net_device *ndev, struct cfg80211_scan_request *request){s32 err;u32 passive_scan;struct brcmf_scan_results *results;struct escan_info *escan = &cfg->escan_info;brcmf_dbg(SCAN, "Enter\n");escan->ndev = ndev;escan->wiphy = wiphy;escan->escan_state = WL_ESCAN_STATE_SCANNING;passive_scan = cfg->active_scan ? 0 : 1;err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PASSIVE_SCAN,passive_scan);if (err) {brcmf_err("error (%d)\n", err);return err;}brcmf_set_mpc(ndev, 0);results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;results->version = 0;results->count = 0;results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;// 执行run函数err = escan->run(cfg, ndev, request, WL_ESCAN_ACTION_START);if (err)brcmf_set_mpc(ndev, 1);return err;}

21. 调用brcmf_run_escan()

static s32brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev,struct cfg80211_scan_request *request, u16 action){s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +offsetof(struct brcmf_escan_params_le, params_le);struct brcmf_escan_params_le *params;s32 err = 0;brcmf_dbg(SCAN, "E-SCAN START\n");if (request != NULL) {/* Allocate space for populating ssids in struct */params_size += sizeof(u32) * ((request->n_channels + 1) / 2);/* Allocate space for populating ssids in struct */params_size += sizeof(struct brcmf_ssid) * request->n_ssids;}params = kzalloc(params_size, GFP_KERNEL);if (!params) {err = -ENOMEM;goto exit;}BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);// 配置scan参数brcmf_escan_prep(&params->params_le, request);params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);params->action = cpu_to_le16(action);params->sync_id = cpu_to_le16(0x1234);// 向firmware发送"escan"命令err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "escan",params, params_size);if (err) {if (err == -EBUSY)brcmf_dbg(INFO, "system busy : escan canceled\n");elsebrcmf_err("error (%d)\n", err);}kfree(params);exit:return err;}

这里有必要进入brcmf_run_escan()看看,因为这里涉及到scan参数的配置。

static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,struct cfg80211_scan_request *request){u32 n_ssids;u32 n_channels;s32 i;s32 offset;u16 chanspec;char *ptr;struct brcmf_ssid_le ssid_le;...if (n_ssids > 0) {// 这种情况应该是active scan?offset = offsetof(struct brcmf_scan_params_le, channel_list) +n_channels * sizeof(u16);offset = roundup(offset, sizeof(u32));ptr = (char *)params_le + offset;for (i = 0; i < n_ssids; i++) {memset(&ssid_le, 0, sizeof(ssid_le));ssid_le.SSID_len =cpu_to_le32(request->ssids[i].ssid_len);memcpy(ssid_le.SSID, request->ssids[i].ssid,request->ssids[i].ssid_len);if (!ssid_le.SSID_len)brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);elsebrcmf_dbg(SCAN, "%d: scan for %s size =%d\n",i, ssid_le.SSID, ssid_le.SSID_len);memcpy(ptr, &ssid_le, sizeof(ssid_le));ptr += sizeof(ssid_le);}} else {// n_ssids为0的情况应该是passive scan?brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);if ((request->ssids) && request->ssids->ssid_len) {brcmf_dbg(SCAN, "SSID %s len=%d\n",params_le->ssid_le.SSID,request->ssids->ssid_len);params_le->ssid_le.SSID_len =cpu_to_le32(request->ssids->ssid_len);memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,request->ssids->ssid_len);}}/* Adding mask to channel numbers */params_le->channel_num =cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |(n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));}

这里关于active scan/passive scan目前还是我的猜测,依据是wpa_supplicant中关于wpa_driver_scan_params的一些注释:

/*** struct wpa_driver_scan_params - Scan parameters* Data for struct wpa_driver_ops::scan2().*/struct wpa_driver_scan_params {/*** ssids - SSIDs to scan for*/struct wpa_driver_scan_ssid {/*** ssid - specific SSID to scan for (ProbeReq)* %NULL or zero-length SSID is used to indicate active scan* with wildcard SSID.*/const u8 *ssid;/*** ssid_len: Length of the SSID in octets*/size_t ssid_len;} ssids[WPAS_MAX_SCAN_SSIDS];/*** num_ssids - Number of entries in ssids array* Zero indicates a request for a passive scan.*/size_t num_ssids;/*** extra_ies - Extra IE(s) to add into Probe Request or %NULL*/const u8 *extra_ies;/*** extra_ies_len - Length of extra_ies in octets*/size_t extra_ies_len;/*** freqs - Array of frequencies to scan or %NULL for all frequencies** The frequency is set in MHz. The array is zero-terminated.*/int *freqs;/*** filter_ssids - Filter for reporting SSIDs** This optional parameter can be used to request the driver wrapper to* filter scan results to include only the specified SSIDs. %NULL* indicates that no filtering is to be done. This can be used to* reduce memory needs for scan results in environments that have large* number of APs with different SSIDs.** The driver wrapper is allowed to take this allocated buffer into its* own use by setting the pointer to %NULL. In that case, the driver* wrapper is responsible for freeing the buffer with os_free() once it* is not needed anymore.*/struct wpa_driver_scan_filter {u8 ssid[32];size_t ssid_len;} *filter_ssids;/*** num_filter_ssids - Number of entries in filter_ssids array*/size_t num_filter_ssids;};

22. 调用brcmf_fil_iovar_data_set()

s32brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, void *data,u32 len){struct brcmf_pub *drvr = ifp->drvr;s32 err;u32 buflen;mutex_lock(&drvr->proto_block);brcmf_dbg(FIL, "name=%s, len=%d\n", name, len);brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,min_t(uint, len, MAX_HEX_DUMP_LEN), "data");buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf,sizeof(drvr->proto_buf));if (buflen) {// 注意这里err = brcmf_fil_cmd_data(ifp, BRCMF_C_SET_VAR, drvr->proto_buf,buflen, true);} else {err = -EPERM;brcmf_err("Creating iovar failed\n");}mutex_unlock(&drvr->proto_block);return err;}

23. 调用brcmf_fil_cmd_data()

static s32brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set){struct brcmf_pub *drvr = ifp->drvr;s32 err;if (drvr->bus_if->state != BRCMF_BUS_DATA) {brcmf_err("bus is down. we have nothing to do.\n");return -EIO;}if (data != NULL)len = min_t(uint, len, BRCMF_DCMD_MAXLEN);if (set)err = brcmf_proto_cdc_set_dcmd(drvr, ifp->ifidx, cmd, data,len);elseerr = brcmf_proto_cdc_query_dcmd(drvr, ifp->ifidx, cmd, data,len);if (err >= 0)err = 0;elsebrcmf_err("Failed err=%d\n", err);return err;}

24. 调用brcmf_proto_cdc_set_dcmd()

int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,void *buf, uint len){struct brcmf_proto *prot = drvr->prot;struct brcmf_proto_cdc_dcmd *msg = &prot->msg;int ret = 0;u32 flags, id;brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len);memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd));msg->cmd = cpu_to_le32(cmd);msg->len = cpu_to_le32(len);flags = (++prot->reqid << CDC_DCMD_ID_SHIFT) | CDC_DCMD_SET;flags = (flags & ~CDC_DCMD_IF_MASK) |(ifidx << CDC_DCMD_IF_SHIFT);msg->flags = cpu_to_le32(flags);if (buf)memcpy(prot->buf, buf, len);// 注意这里ret = brcmf_proto_cdc_msg(drvr);if (ret < 0)goto done;ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len);if (ret < 0)goto done;...done:return ret;}

25. 调用brcmf_proto_cdc_msg()

static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr){struct brcmf_proto *prot = drvr->prot;int len = le32_to_cpu(prot->msg.len) +sizeof(struct brcmf_proto_cdc_dcmd);brcmf_dbg(CDC, "Enter\n");/* NOTE : cdc->msg.len holds the desired length of the buffer to be* returned. Only up to CDC_MAX_MSG_SIZE of this buffer area* is actually sent to the dongle*/if (len > CDC_MAX_MSG_SIZE)len = CDC_MAX_MSG_SIZE;/* Send request */return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&prot->msg, len);}

26. 通过brcmf_bus_txctl()发送request

static inlineint brcmf_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint len){return bus->ops->txctl(bus->dev, msg, len);}

27. 上一节已经分析过,这里会调用brcmf_sdbrcm_bus_txctl()

static intbrcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen){u8 *frame;u16 len;u32 swheader;uint retries = 0;u8 doff = 0;int ret = -1;struct brcmf_bus *bus_if = dev_get_drvdata(dev);struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;struct brcmf_sdio *bus = sdiodev->bus;unsigned long flags;...if (ret == -1) {brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(),frame, len, "Tx Frame:\n");brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() && BRCMF_CTL_ON()) &&BRCMF_HDRS_ON(),frame, min_t(u16, len, 16), "TxHdr:\n");do {sdio_claim_host(bus->sdiodev->func[1]);// 通过brcmf_tx_frame发送数据ret = brcmf_tx_frame(bus, frame, len);sdio_release_host(bus->sdiodev->func[1]);} while (ret < 0 && retries++ < TXRETRIES);}...}

至此,已经把scan command和对应的参数发给WLAN firmware了。接下来就是等待scan result.

二、从WLAN firmware接收scan result

我们从上一节分析过的brcmf_rx_frames()开始看起。

1. 触发brcmf_rx_frames()

void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list){...skb_queue_walk_safe(skb_list, skb, pnext) {skb_unlink(skb, skb_list);.../* Process special event packets and then discard them */// scan result就是special event packets// 所以要在这边处理brcmf_fweh_process_skb(drvr, skb, &ifidx);if (drvr->iflist[ifidx]) {ifp = drvr->iflist[ifidx];ifp->ndev->last_rx = jiffies;}if (!(ifp->ndev->flags & IFF_UP)) {brcmu_pkt_buf_free_skb(skb);continue;}ifp->stats.rx_bytes += skb->len;ifp->stats.rx_packets++;if (in_interrupt())netif_rx(skb);else/* If the receive is not processed inside an ISR,* the softirqd must be woken explicitly to service* the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled* by netif_rx_ni(), but in earlier kernels, we need* to do it manually.*/netif_rx_ni(skb);}}

2. 进入到brcmf_fweh_process_skb()

static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr,struct sk_buff *skb, u8 *ifidx){struct brcmf_event *event_packet;u8 *data;u16 usr_stype;/* only process events when protocol matches */if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL))return;/* check for BRCM oui match */event_packet = (struct brcmf_event *)skb_mac_header(skb);data = (u8 *)event_packet;data += BRCMF_EVENT_OUI_OFFSET;if (memcmp(BRCM_OUI, data, DOT11_OUI_LEN))return;/* final match on usr_subtype */data += DOT11_OUI_LEN;usr_stype = get_unaligned_be16(data);if (usr_stype != BCMILCP_BCM_SUBTYPE_EVENT)return;// 注意这里 brcmf_fweh_process_event(drvr, event_packet, ifidx);}

3. 调用brcmf_fweh_process_event()

void brcmf_fweh_process_event(struct brcmf_pub *drvr,struct brcmf_event *event_packet, u8 *ifidx){...event = kzalloc(sizeof(*event) + datalen, alloc_flag);if (!event)return;event->code = code;event->ifidx = *ifidx;/* use memcpy to get aligned event message */memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg));memcpy(event->data, data, datalen);memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN);// 注意这里brcmf_fweh_queue_event(fweh, event);}

4. 调用brcmf_fweh_queue_event()

static void brcmf_fweh_queue_event(struct brcmf_fweh_info *fweh,struct brcmf_fweh_queue_item *event){ulong flags;spin_lock_irqsave(&fweh->evt_q_lock, flags);list_add_tail(&event->q, &fweh->event_q);spin_unlock_irqrestore(&fweh->evt_q_lock, flags);schedule_work(&fweh->event_work); // 注意这个work queue}

这里的event_work()是在brcmf_fweh_attach()中初始化的(调用顺序:brcmf_sdbrcm_probe() -> brcmf_attach() -> brcmf_fweh_attach())

void brcmf_fweh_attach(struct brcmf_pub *drvr){struct brcmf_fweh_info *fweh = &drvr->fweh;INIT_WORK(&fweh->event_work, brcmf_fweh_event_worker);spin_lock_init(&fweh->evt_q_lock);INIT_LIST_HEAD(&fweh->event_q);}

5. 显然brcmf_fweh_event_worker()将会被调用

static void brcmf_fweh_event_worker(struct work_struct *work){...while ((event = brcmf_fweh_dequeue_event(fweh))) {.../* special handling of interface event */if (event->code == BRCMF_E_IF) {brcmf_fweh_handle_if_event(drvr, &emsg, event->data);goto event_free;}ifp = drvr->iflist[emsg.bsscfgidx];// 目前我们只关心brcmf_fweh_call_event_handler()err = brcmf_fweh_call_event_handler(ifp, event->code, &emsg,event->data);if (err) {brcmf_err("event handler failed (%d)\n",event->code);err = 0;}event_free:kfree(event);}

6. 进入到brcmf_fweh_call_event_handler()

static int brcmf_fweh_call_event_handler(struct brcmf_if *ifp,enum brcmf_fweh_event_code code,struct brcmf_event_msg *emsg,void *data){struct brcmf_fweh_info *fweh;int err = -EINVAL;if (ifp) {fweh = &ifp->drvr->fweh;/* handle the event if valid interface and handler */if (ifp->ndev && fweh->evt_handler[code])err = fweh->evt_handler[code](ifp, emsg, data);elsebrcmf_err("unhandled event %d ignored\n", code);} else {brcmf_err("no interface object\n");}return err;}

代码很清楚的显示这里firmware的事件是由fweh->evt_handler来处理的。那我们必须得了解fweh->evt_handler是怎么被初始化的。

在上一节中曾经分析过brcmf_cfg80211_attach(), 该函数会调用wl_init_priv():

static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg){s32 err = 0;cfg->scan_request = NULL;cfg->pwr_save = true;cfg->roam_on = true; /* roam on & off switch.we enable roam per default */cfg->active_scan = true; /* we do active scan forspecific scan per default */cfg->dongle_up = false; /* dongle is not up yet */err = brcmf_init_priv_mem(cfg);if (err)return err;brcmf_register_event_handlers(cfg);mutex_init(&cfg->usr_sync);brcmf_init_escan(cfg); // 现在我们只关心scanbrcmf_init_conf(cfg->conf);init_completion(&cfg->vif_disabled);return err;}

继续跟进brcmf_init_ecan():

static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg){// 这里注册了handler!brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,brcmf_cfg80211_escan_handler);cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;/* Init scan_timeout timer */init_timer(&cfg->escan_timeout);cfg->escan_timeout.data = (unsigned long) cfg;cfg->escan_timeout.function = brcmf_escan_timeout;INIT_WORK(&cfg->escan_timeout_work,brcmf_cfg80211_escan_timeout_worker);}

很显然,对于firmware报上来的BRCMF_E_ESCAN_RESULT事件,fweh->evt_handler就是brcmf_cfg80211_escan_handler().

7. 调用brcmf_cfg80211_escan_handler()

static s32brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,const struct brcmf_event_msg *e, void *data){...if (status == BRCMF_E_STATUS_PARTIAL) {...} else {cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))goto exit;if (cfg->scan_request) {cfg->bss_list = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;brcmf_inform_bss(cfg);aborted = status != BRCMF_E_STATUS_SUCCESS;// 注意这里 brcmf_notify_escan_complete(cfg, ndev, aborted,false);} elsebrcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",status);}exit:return err;

8. 调用brcmf_notify_escan_complete()

s32brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,struct net_device *ndev,bool aborted, bool fw_abort){.../** e-scan can be initiated by scheduled scan* which takes precedence.*/if (cfg->sched_escan) {brcmf_dbg(SCAN, "scheduled scan completed\n");cfg->sched_escan = false;if (!aborted)cfg80211_sched_scan_results(cfg_to_wiphy(cfg));brcmf_set_mpc(ndev, 1);} else if (scan_request) {brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",aborted ? "Aborted" : "Done");// 注意这里 cfg80211_scan_done(scan_request, aborted);brcmf_set_mpc(ndev, 1);}if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");return err;}

9. 调用cfg80211_scan_done()

void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted){trace_cfg80211_scan_done(request, aborted);WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);request->aborted = aborted;queue_work(cfg80211_wq, &wiphy_to_dev(request->wiphy)->scan_done_wk); // 又是work queue}

这里的work queue是在wiphy_new()被初始化的:

INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);

10. 那么接下来就是调用__cfg80211_scan_done()

void __cfg80211_scan_done(struct work_struct *wk){struct cfg80211_registered_device *rdev;rdev = container_of(wk, struct cfg80211_registered_device,scan_done_wk);cfg80211_lock_rdev(rdev);___cfg80211_scan_done(rdev, false);cfg80211_unlock_rdev(rdev);}

11. 调用___cfg80211_scan_done()

void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak){.../** This must be before sending the other events!* Otherwise, wpa_supplicant gets completely confused with* wext events.*/if (wdev->netdev)cfg80211_sme_scan_done(wdev->netdev);if (request->aborted) {nl80211_send_scan_aborted(rdev, wdev);} else {if (request->flags & NL80211_SCAN_FLAG_FLUSH) {/* flush entries from previous scans */spin_lock_bh(&rdev->bss_lock);__cfg80211_bss_expire(rdev, request->scan_start);spin_unlock_bh(&rdev->bss_lock);}// 这里通过nl80211去通知user space nl80211_send_scan_done(rdev, wdev);}...}

12. 调用nl80211_send_scan_done()

void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,struct wireless_dev *wdev){struct sk_buff *msg;msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);if (!msg)return;// 注意这里的消息名字if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0,NL80211_CMD_NEW_SCAN_RESULTS) < 0) {nlmsg_free(msg);return;}genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,nl80211_scan_mcgrp.id, GFP_KERNEL);}

13. 接下来wpa_supplicant就会接收到NL80211_CMD_NEW_SCAN_RESULTS

static int process_event(struct nl_msg *msg, void *arg){struct wpa_driver_nl80211_data *drv = arg;struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));struct nlattr *tb[NL80211_ATTR_MAX + 1];union wpa_event_data data;...switch (gnlh->cmd) {...case NL80211_CMD_NEW_SCAN_RESULTS:wpa_printf(MSG_DEBUG, "nl80211: New scan results available");drv->scan_complete_events = 1;eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,drv->ctx);send_scan_event(drv, 0, tb);break;...default:wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event ""(cmd=%d)", gnlh->cmd);break;}return NL_SKIP;}

14. 调用send_scan_event()

static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,struct nlattr *tb[]){union wpa_event_data event;struct nlattr *nl;int rem;struct scan_info *info;#define MAX_REPORT_FREQS 50int freqs[MAX_REPORT_FREQS];int num_freqs = 0;os_memset(&event, 0, sizeof(event));info = &event.scan_info;info->aborted = aborted;...// 注意事件EVENT_SCAN_RESULTSwpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);}

15. 进入到wpa_supplicant_event()

void wpa_supplicant_event(void *ctx, enum wpa_event_type event,union wpa_event_data *data){struct wpa_supplicant *wpa_s = ctx;u16 reason_code = 0;switch (event) {...#ifndef CONFIG_NO_SCAN_PROCESSINGcase EVENT_SCAN_RESULTS:wpa_supplicant_event_scan_results(wpa_s, data);break;#endif /* CONFIG_NO_SCAN_PROCESSING */...default:wpa_printf(MSG_INFO, "Unknown event %d", event);break;}}

16. 调用wpa_supplicant_event_scan_results()

static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,union wpa_event_data *data){struct wpa_bss *selected;struct wpa_ssid *ssid = NULL;struct wpa_scan_results *scan_res;int ap = 0;#ifdef CONFIG_APif (wpa_s->ap_iface)ap = 1;#endif /* CONFIG_AP */wpa_supplicant_notify_scanning(wpa_s, 0);// 去从driver取得scan resultscan_res = wpa_supplicant_get_scan_results(wpa_s,data ? &data->scan_info :NULL, 1);if (scan_res == NULL) {if (wpa_s->conf->ap_scan == 2 || ap)return;wpa_printf(MSG_DEBUG, "Failed to get scan results - try ""scanning again");wpa_supplicant_req_new_scan(wpa_s, 1, 0);return;}if (wpa_s->scan_res_handler) {wpa_s->scan_res_handler(wpa_s, scan_res);wpa_s->scan_res_handler = NULL;wpa_scan_results_free(scan_res);return;}if (ap) {wpa_printf(MSG_DEBUG, "Ignore scan results in AP mode");wpa_scan_results_free(scan_res);return;}wpa_printf(MSG_DEBUG, "New scan results available");// 发出事件"CTRL-EVENT-SCAN-RESULTS "// Android framework中的WifiMonitor将会收到 wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);wpas_notify_scan_results(wpa_s);wpas_notify_scan_done(wpa_s, 1);...}

这里需要一下wpa_supplicant_get_scan_results(), 它非常重要。

struct wpa_scan_results *wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,struct scan_info *info, int new_scan){struct wpa_scan_results *scan_res;size_t i;if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)scan_res = ieee80211_sta_get_scan_results(wpa_s);else// 这个函数最终会触发了wpa_driver_nl80211_get_scan_results(),// 从而向driver发出了NL80211_CMD_GET_SCAN命令,收到这个命令之后,// driver会把scan result dump出来。scan_res = wpa_drv_get_scan_results2(wpa_s);if (scan_res == NULL) {wpa_printf(MSG_DEBUG, "Failed to get scan results");return NULL;}// 排序扫描结果qsort(scan_res->res, scan_res->num, sizeof(struct wpa_scan_res *),wpa_scan_result_compar);wpa_bss_update_start(wpa_s);for (i = 0; i < scan_res->num; i++)// 把扫描结果update到wpa_s结果中去,后面要用到wpa_bss_update_scan_res(wpa_s, scan_res->res[i]);wpa_bss_update_end(wpa_s, info, new_scan);return scan_res;}

17. 前面提到了Android framework中的WifiMonitor. 现在就进入到WifiMonitor中来分析如何处理事件"CTRL-EVENT-SCAN-RESULTS "的

 class MonitorThread extends Thread {public MonitorThread() {super("WifiMonitor");}public void run() {if (connectToSupplicant()) {// Send a message indicating that it is now possible to send commands// to the supplicant mStateMachine.sendMessage(SUP_CONNECTION_EVENT);} else {mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);return;}//noinspection InfiniteLoopStatementfor (;;) {String eventStr = WifiNative.waitForEvent();.../** Map event name into event enum*/int event;if (eventName.equals(CONNECTED_STR))event = CONNECTED;...// 这里便是scan result的事件else if (eventName.equals(SCAN_RESULTS_STR))event = SCAN_RESULTS;...elseevent = UNKNOWN;...if (event == STATE_CHANGE) {handleSupplicantStateChange(eventData);}...else {handleEvent(event, eventData);}mRecvErrors = 0;}}.../*** Handle all supplicant events except STATE-CHANGE* @param event the event type* @param remainder the rest of the string following the* event name and &quot;&#8195;&#8212;&#8195;&quot;*/void handleEvent(int event, String remainder) {switch (event) {...// 处理scan resultcase SCAN_RESULTS:mStateMachine.sendMessage(SCAN_RESULTS_EVENT);break;case UNKNOWN:break;}}...}

18. 很明显,将会到WifiStateMachine中进一步处理SCAN_RESULT_EVENT

 class SupplicantStartedState extends State {...@Overridepublic boolean processMessage(Message message) {if (DBG) log(getName() + message.toString() + "\n");WifiConfiguration config;boolean eventLoggingEnabled = true;switch(message.what) {...case WifiMonitor.SCAN_RESULTS_EVENT:eventLoggingEnabled = false;setScanResults(WifiNative.scanResultsCommand());sendScanResultsAvailableBroadcast();mScanResultIsPending = false;break;...default:return NOT_HANDLED;}if (eventLoggingEnabled) {EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);}return HANDLED;}...}

19. 这里先调用WifiNative.scanResultsCommand()去获取扫描结果,然后传递给setScanResult()。我们进入到JNI函数去看看

static jstring android_net_wifi_scanResultsCommand(JNIEnv* env, jobject){return doStringCommand(env, "SCAN_RESULTS");}

20. 又发了"SCAN_RESULT"这个命令给wpa_supplicant

wpa_supplicant_ctrl_iface_process()调用wpa_supplicant_ctrl_iface_scan_results来处理该命令:

static int wpa_supplicant_ctrl_iface_scan_results(struct wpa_supplicant *wpa_s, char *buf, size_t buflen){char *pos, *end;struct wpa_bss *bss;int ret;pos = buf;end = buf + buflen;ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / ""flags / ssid\n");if (ret < 0 || ret >= end - pos)return pos - buf;pos += ret;dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {// 前面我们提到,wpa_supplicant_get_scan_results()中已经把扫描结果update到wpa_s结构中// 那么这儿就用到了,针对wpa_s->bss_id中的每个bss做处理ret = wpa_supplicant_ctrl_iface_scan_result(bss, pos,end - pos);if (ret < 0 || ret >= end - pos)return pos - buf;pos += ret;}return pos - buf;}

21. 调用wpa_supplicant_ctrl_iface_scan_result()去格式化字符串

/* Format one result on one text line into a buffer. */static int wpa_supplicant_ctrl_iface_scan_result(const struct wpa_bss *bss, char *buf, size_t buflen){...}

最终,Android framework就拿到了格式化好的扫描结果。

22. 调用setScanResults()

 /*** scanResults input format* 00:bb:cc:dd:cc:ee 2427 166 [WPA-EAP-TKIP][WPA2-EAP-CCMP] Net1* 00:bb:cc:dd:cc:ff 2412 165 [WPA-EAP-TKIP][WPA2-EAP-CCMP] Net2*/private void setScanResults(String scanResults) {if (scanResults == null) {return;}List<ScanResult> scanList = new ArrayList<ScanResult>();int lineCount = 0;int scanResultsLen = scanResults.length();// Parse the result string, keeping in mind that the last line does// not end with a newline.for (int lineBeg = 0, lineEnd = 0; lineEnd <= scanResultsLen; ++lineEnd) {if (lineEnd == scanResultsLen || scanResults.charAt(lineEnd) == '\n') {++lineCount;if (lineCount == 1) {lineBeg = lineEnd + 1;continue;}if (lineEnd > lineBeg) {String line = scanResults.substring(lineBeg, lineEnd);ScanResult scanResult = parseScanResult(line);if (scanResult != null) {scanList.add(scanResult);} else {//TODO: hidden network handling }}lineBeg = lineEnd + 1;}}mScanResults = scanList;}

该函数的注释就很清楚的显示了从wpa_supplicant获取的扫描结果的格式。

原创粉丝点击