欢迎转载,转载时请保留作者链接,尊重原作者:http://blog.csdn.net/ivan_
wifi技术交流群QQ:92953762
我们使用wext方式与wifi driver交互
当我们在终端中执行wpa_cli scan时,就会触发wpa_supplicant发起扫描流程:
wpa_supplicant_ctrl_iface_receive() ->
wpa_supplicant_ctrl_iface_process()->
wpa_supplicant_req_scan()->
wpa_supplicant_scan()->
wpa_supplicant_trigger_scan()->
wpa_drv_scan()->
wpa_driver_wext_scan()->
ioctl()->pass scan data to wifi driver
以下是核心代码:
/** * wpa_supplicant_req_scan - Schedule a scan for neighboring access points * @wpa_s: Pointer to wpa_supplicant data * @sec: Number of seconds after which to scan * @usec: Number of microseconds after which to scan * * This function is used to schedule a scan for neighboring access points after * the specified time. */ void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec) { #ifndef ANDROID /* If there's at least one network that should be specifically scanned * then don't cancel the scan and reschedule. Some drivers do * background scanning which generates frequent scan results, and that * causes the specific SSID scan to get continually pushed back and * never happen, which causes hidden APs to never get probe-scanned. */ if (eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL) && wpa_s->conf->ap_scan == 1) { struct wpa_ssid *ssid = wpa_s->conf->ssid; while (ssid) { if (!ssid->disabled && ssid->scan_ssid) break; ssid = ssid->next; } if (ssid) { wpa_dbg(wpa_s, MSG_DEBUG, "Not rescheduling scan to " "ensure that specific SSID scans occur"); return; } } #endif /* !ANDROID */ wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec", sec, usec); eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL); }
//发起扫描 /***************************************************************** * * * * *****************************************************************/ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) { wpa_printf(MSG_DEBUG,"ivan:%s \n",__FUNCTION__); struct wpa_supplicant *wpa_s = eloop_ctx; struct wpa_ssid *ssid; int scan_req = 0, ret; struct wpabuf *wps_ie = NULL; #ifdef CONFIG_WPS int wps = 0; enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO; #endif /* CONFIG_WPS */ struct wpa_driver_scan_params params; size_t max_ssids; enum wpa_states prev_state; //wlan0 or ra0已经被禁用 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled"); return; } if (wpa_s->disconnected && !wpa_s->scan_req) { wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); return; } if (!wpa_supplicant_enabled_networks(wpa_s->conf) && !wpa_s->scan_req) { wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan"); wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); return; } if (wpa_s->conf->ap_scan != 0 && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)) { wpa_dbg(wpa_s, MSG_DEBUG, "Using wired authentication - " "overriding ap_scan configuration"); wpa_s->conf->ap_scan = 0; wpas_notify_ap_scan_changed(wpa_s); } if (wpa_s->conf->ap_scan == 0) {//ap_scan == 0??? wpa_supplicant_gen_assoc_event(wpa_s); return; } if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) || #ifdef ANDROID (wpa_s->max_scan_ssids == 1 && wpa_s->conf->ap_scan == 2)) #else wpa_s->conf->ap_scan == 2) #endif /* ANDROID for combo scan */ max_ssids = 1; else { max_ssids = wpa_s->max_scan_ssids; if (max_ssids > WPAS_MAX_SCAN_SSIDS) max_ssids = WPAS_MAX_SCAN_SSIDS; } #ifdef CONFIG_WPS wps = wpas_wps_in_use(wpa_s->conf, &req_type); #endif /* CONFIG_WPS */ scan_req = wpa_s->scan_req; wpa_s->scan_req = 0; os_memset(¶ms, 0, sizeof(params)); prev_state = wpa_s->wpa_state; if (wpa_s->wpa_state == WPA_DISCONNECTED || wpa_s->wpa_state == WPA_INACTIVE) wpa_supplicant_set_state(wpa_s, WPA_SCANNING); if (scan_req != 2 && wpa_s->connect_without_scan) {//无需扫描 直接发起连接 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { if (ssid == wpa_s->connect_without_scan) break; } wpa_s->connect_without_scan = NULL; if (ssid) { wpa_printf(MSG_DEBUG, "Start a pre-selected network " "without scan step"); wpa_supplicant_associate(wpa_s, NULL, ssid); return; } } /* Find the starting point from which to continue scanning */ ssid = wpa_s->conf->ssid; if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) { while (ssid) { if (ssid == wpa_s->prev_scan_ssid) { ssid = ssid->next; break; } ssid = ssid->next; } } if (scan_req != 2 && wpa_s->conf->ap_scan == 2) { wpa_s->connect_without_scan = NULL; wpa_supplicant_assoc_try(wpa_s, ssid); return; #ifdef ANDROID } else if ( max_ssids == 1 && wpa_s->conf->ap_scan == 2) { #else } else if (wpa_s->conf->ap_scan == 2) { #endif /* ANDROID for combo scan */ /* * User-initiated scan request in ap_scan == 2; scan with * wildcard SSID. */ ssid = NULL; } else { struct wpa_ssid *start = ssid, *tssid; int freqs_set = 0; if (ssid == NULL && max_ssids > 1) ssid = wpa_s->conf->ssid; while (ssid) { if (!ssid->disabled && ssid->scan_ssid) { wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID", ssid->ssid, ssid->ssid_len); params.ssids[params.num_ssids].ssid = ssid->ssid; params.ssids[params.num_ssids].ssid_len = ssid->ssid_len; params.num_ssids++; if (params.num_ssids + 1 >= max_ssids) break; } ssid = ssid->next; if (ssid == start) break; if (ssid == NULL && max_ssids > 1 && start != wpa_s->conf->ssid) ssid = wpa_s->conf->ssid; } for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) { if (tssid->disabled) continue; if ((params.freqs || !freqs_set) && tssid->scan_freq) { int_array_concat(¶ms.freqs, tssid->scan_freq); } else { os_free(params.freqs); params.freqs = NULL; } freqs_set = 1; } int_array_sort_unique(params.freqs); } if (ssid) {//扫描指定的SSID wpa_s->prev_scan_ssid = ssid; if (max_ssids > 1) { wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in " "the scan request"); params.num_ssids++; } wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for specific " "SSID(s)"); } else { wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; params.num_ssids++; wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard " "SSID"); } #ifdef CONFIG_P2P if(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) { wpa_s->wps->dev.p2p = 1; if (!wps) { wps = 1; req_type = WPS_REQ_ENROLLEE_INFO; } } if (params.freqs == NULL && wpa_s->p2p_in_provisioning && wpa_s->go_params) { /* Optimize provisioning state scan based on GO information */ if (wpa_s->p2p_in_provisioning < 5 && wpa_s->go_params->freq > 0) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO " "preferred frequency %d MHz", wpa_s->go_params->freq); params.freqs = os_zalloc(2 * sizeof(int)); if (params.freqs) params.freqs[0] = wpa_s->go_params->freq; } else if (wpa_s->p2p_in_provisioning < 8 && wpa_s->go_params->freq_list[0]) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only common " "channels"); int_array_concat(¶ms.freqs, wpa_s->go_params->freq_list); if (params.freqs) int_array_sort_unique(params.freqs); } wpa_s->p2p_in_provisioning++; } #endif /* CONFIG_P2P */ #ifdef CONFIG_WPS if (params.freqs == NULL && wpa_s->after_wps && wpa_s->wps_freq) { /* * Optimize post-provisioning scan based on channel used * during provisioning. */ wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz " "that was used during provisioning", wpa_s->wps_freq); params.freqs = os_zalloc(2 * sizeof(int)); if (params.freqs) params.freqs[0] = wpa_s->wps_freq; wpa_s->after_wps--; } if (wps) { wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev, wpa_s->wps->uuid, req_type, 0, NULL); if (wps_ie) { params.extra_ies = wpabuf_head(wps_ie); params.extra_ies_len = wpabuf_len(wps_ie); } } #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P if (wps_ie) { if (wpabuf_resize(&wps_ie, 100) == 0) { wpas_p2p_scan_ie(wpa_s, wps_ie); params.extra_ies = wpabuf_head(wps_ie); params.extra_ies_len = wpabuf_len(wps_ie); } } #endif /* CONFIG_P2P */ //扫描指定的信道 if (params.freqs == NULL && wpa_s->next_scan_freqs) { wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously " "generated frequency list"); params.freqs = wpa_s->next_scan_freqs; } else os_free(wpa_s->next_scan_freqs); wpa_s->next_scan_freqs = 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_msg(wpa_s, 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); } } /** * wpa_supplicant_req_scan - Schedule a scan for neighboring access points * @wpa_s: Pointer to wpa_supplicant data * @sec: Number of seconds after which to scan * @usec: Number of microseconds after which to scan * * This function is used to schedule a scan for neighboring access points after * the specified time. */ void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec) { #ifndef ANDROID /* If there's at least one network that should be specifically scanned * then don't cancel the scan and reschedule. Some drivers do * background scanning which generates frequent scan results, and that * causes the specific SSID scan to get continually pushed back and * never happen, which causes hidden APs to never get probe-scanned. */ if (eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL) && wpa_s->conf->ap_scan == 1) { struct wpa_ssid *ssid = wpa_s->conf->ssid; while (ssid) { if (!ssid->disabled && ssid->scan_ssid) break; ssid = ssid->next; } if (ssid) { wpa_dbg(wpa_s, MSG_DEBUG, "Not rescheduling scan to " "ensure that specific SSID scans occur"); return; } } #endif /* !ANDROID */ wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec", sec, usec); eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL); }
int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params) { int ret; //printf("wpa_supplicant_trigger_scan\n"); wpa_msg(wpa_s, MSG_DEBUG, "%s",__FUNCTION__); 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; }
/** * wpa_driver_wext_scan - Request the driver to initiate scan * @priv: Pointer to private wext data from wpa_driver_wext_init() * @param: Scan parameters (specific SSID to scan for (ProbeReq), etc.) * Returns: 0 on success, -1 on failure */ //发起扫描 int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params) { wpa_printf(MSG_DEBUG, "ivan:%s\n",__FUNCTION__); struct wpa_driver_wext_data *drv = priv; struct iwreq iwr; int ret = 0, timeout; struct iw_scan_req req; const u8 *ssid = params->ssids[0].ssid; size_t ssid_len = params->ssids[0].ssid_len; #ifdef ANDROID struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)(drv->ctx); int scan_probe_flag = 0; #endif if (ssid_len > IW_ESSID_MAX_SIZE) { wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)", __FUNCTION__, (unsigned long) ssid_len); return -1; } os_memset(&iwr, 0, sizeof(iwr)); os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); #ifdef ANDROID if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) { scan_probe_flag = wpa_s->prev_scan_ssid->scan_ssid; } wpa_printf(MSG_DEBUG, "%s: specific scan = %d", __func__, (scan_probe_flag && (ssid && ssid_len)) ? 1 : 0); if (scan_probe_flag && (ssid && ssid_len)) { #else if (ssid && ssid_len) {//扫描特定热点 #endif os_memset(&req, 0, sizeof(req)); req.essid_len = ssid_len; req.bssid.sa_family = ARPHRD_ETHER; os_memset(req.bssid.sa_data, 0xff, ETH_ALEN); os_memcpy(req.essid, ssid, ssid_len); iwr.u.data.pointer = (caddr_t) &req; iwr.u.data.length = sizeof(req); iwr.u.data.flags = IW_SCAN_THIS_ESSID; } if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) { perror("ioctl[SIOCSIWSCAN]"); ret = -1; } /* Not all drivers generate "scan completed" wireless event, so try to * read results after a timeout. */ timeout = 5; if (drv->scan_complete_events) { /* * The driver seems to deliver SIOCGIWSCAN events to notify * when scan is complete, so use longer timeout to avoid race * conditions with scanning and following association request. */ //timeout = 30;//Default timeout = 5;//modify by ivanhuang @20131018 } wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d " "seconds", ret, timeout); eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx); eloop_register_timeout(timeout, 0, wpa_driver_wext_scan_timeout, drv, drv->ctx); return ret; }
欢迎转载,转载时请保留作者链接,尊重原作者:http://blog.csdn.net/ivan_
wifi技术交流群QQ:92953762