现在我们来看看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
@Override public 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_SCAN case 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 newline if (reply_len > 0 && replybuf[reply_len-1] == '\n') replybuf[reply_len-1] = '\0'; else replybuf[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_conn ctrl_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_conn monitor_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(¶ms, 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(¶ms); 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_FILE wpa_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); } } else wpa_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) { ... // 这里第二个参数便是handler eloop_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_s struct 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; else reply_len = 2; } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen, buf + 6)) reply_len = 1; else reply_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, ¶ms.num_filter_ssids); // 注意这里 ret = wpa_supplicant_trigger_scan(wpa_s, ¶ms); 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); } else wpa_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 s32 brcmf_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 s32 brcmf_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_escan err = brcmf_do_escan(cfg, wiphy, ndev, request); if (err) goto scan_out; } ... return 0; ... }
20. 调用brcmf_do_escan()
static s32 brcmf_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 s32 brcmf_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(¶ms->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"); else brcmf_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); else brcmf_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(¶ms_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()
s32 brcmf_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 s32 brcmf_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); else err = brcmf_proto_cdc_query_dcmd(drvr, ifp->ifidx, cmd, data, len); if (err >= 0) err = 0; else brcmf_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 inline int brcmf_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint len) { return bus->ops->txctl(bus->dev, msg, len); }
上一节已经分析过,这里bus->ops->txctl就是调用brcmf_sdbrcm_bus_txctl()
static int brcmf_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); else brcmf_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 for specific 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); // 现在我们只关心scan brcmf_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 s32 brcmf_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); } else brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n", status); } exit: return err;
8. 调用brcmf_notify_escan_complete()
s32 brcmf_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 50 int freqs[MAX_REPORT_FREQS]; int num_freqs = 0; os_memset(&event, 0, sizeof(event)); info = &event.scan_info; info->aborted = aborted; ... // 注意事件EVENT_SCAN_RESULTS wpa_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_PROCESSING case 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_AP if (wpa_s->ap_iface) ap = 1; #endif /* CONFIG_AP */ wpa_supplicant_notify_scanning(wpa_s, 0); // 去从driver取得scan result scan_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 InfiniteLoopStatement for (;;) { 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; ... else event = 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 " — " */ void handleEvent(int event, String remainder) { switch (event) { ... // 处理scan result case SCAN_RESULTS: mStateMachine.sendMessage(SCAN_RESULTS_EVENT); break; case UNKNOWN: break; } } ... }
18. 很明显,将会到WifiStateMachine中进一步处理SCAN_RESULT_EVENT
class SupplicantStartedState extends State { ... @Override public 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; } ListscanList = new ArrayList (); 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获取的扫描结果的格式。