Android wifi 掃描流程 分析
阿新 • • 發佈:2018-11-14
void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec) { int res; if (wpa_s->p2p_mgmt) { wpa_dbg(wpa_s, MSG_DEBUG, "Ignore scan request (%d.%06d sec) on p2p_mgmt interface", sec, usec); return; } res = eloop_deplete_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL); if (res == 1) { wpa_dbg(wpa_s, MSG_DEBUG, "Rescheduling scan request: %d.%06d sec", sec, usec); } else if (res == 0) { wpa_dbg(wpa_s, MSG_DEBUG, "Ignore new scan request for %d.%06d sec since an earlier request is scheduled to trigger sooner", sec, usec); } else { wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d.%06d sec", sec, usec); eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL); } } static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; struct wpa_ssid *ssid; int ret, p2p_in_prog; struct wpabuf *extra_ie = NULL; struct wpa_driver_scan_params params; struct wpa_driver_scan_params *scan_params; size_t max_ssids; int connect_without_scan = 0; wpa_s->ignore_post_flush_scan_res = 0; // 介面未使能 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 == NORMAL_SCAN_REQ) { wpa_dbg(wpa_s, MSG_DEBUG, "Disconnected - do not scan"); wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); return; } // 如果正在掃描, 推遲本次掃描 if (wpa_s->scanning) { /* * If we are already in scanning state, we shall reschedule the * the incoming scan request. */ wpa_dbg(wpa_s, MSG_DEBUG, "Already scanning - Reschedule the incoming scan req"); wpa_supplicant_req_scan(wpa_s, 1, 0); return; } // 檢視是否有使能的ssid if (!wpa_supplicant_enabled_networks(wpa_s) && wpa_s->scan_req == NORMAL_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) { wpa_supplicant_gen_assoc_event(wpa_s); return; } ssid = NULL; if (wpa_s->scan_req != MANUAL_SCAN_REQ && wpa_s->connect_without_scan) { connect_without_scan = 1; for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { if (ssid == wpa_s->connect_without_scan) break; } } p2p_in_prog = wpas_p2p_in_progress(wpa_s); if (p2p_in_prog && p2p_in_prog != 2 && (!ssid || (ssid->mode != WPAS_MODE_AP && ssid->mode != WPAS_MODE_P2P_GO))) { wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan while P2P operation is in progress"); wpa_supplicant_req_scan(wpa_s, 5, 0); return; } /* * Don't cancel the scan based on ongoing PNO; defer it. Some scans are * used for changing modes inside wpa_supplicant (roaming, * auto-reconnect, etc). Discarding the scan might hurt these processes. * The normal use case for PNO is to suspend the host immediately after * starting PNO, so the periodic 100 ms attempts to run the scan do not * normally happen in practice multiple times, i.e., this is simply * restarting scanning once the host is woken up and PNO stopped. */ if (wpa_s->pno || wpa_s->pno_sched_pending) { wpa_dbg(wpa_s, MSG_DEBUG, "Defer scan - PNO is in progress"); wpa_supplicant_req_scan(wpa_s, 0, 100000); return; } if (wpa_s->conf->ap_scan == 2) max_ssids = 1; else { max_ssids = wpa_s->max_scan_ssids; if (max_ssids > WPAS_MAX_SCAN_SSIDS) max_ssids = WPAS_MAX_SCAN_SSIDS; } wpa_s->last_scan_req = wpa_s->scan_req; wpa_s->scan_req = NORMAL_SCAN_REQ; // 如果設定了connect_without_scan, 連線之前選擇的網路,不進行掃描,直接關聯 if (connect_without_scan) { 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; } } os_memset(¶ms, 0, sizeof(params)); // 設定狀態為掃描 wpa_s->scan_prev_wpa_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 autoscan has set its own scanning parameters */ if (wpa_s->autoscan_params != NULL) { scan_params = wpa_s->autoscan_params; goto scan; } if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && wpa_set_ssids_from_scan_req(wpa_s, ¶ms, max_ssids)) { wpa_printf(MSG_DEBUG, "Use specific SSIDs from SCAN command"); goto ssid_list_set; } ...... /* Find the starting point from which to continue scanning */ // 查詢開始掃描的ssid ssid = wpa_s->conf->ssid; // 從這裡看,應該是連結串列裡面下一個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 (wpa_s->last_scan_req != MANUAL_SCAN_REQ && #ifdef CONFIG_AP !wpa_s->ap_iface && #endif /* CONFIG_AP */ wpa_s->conf->ap_scan == 2) { wpa_s->connect_without_scan = NULL; wpa_s->prev_scan_wildcard = 0; wpa_supplicant_assoc_try(wpa_s, ssid); return; } else if (wpa_s->conf->ap_scan == 2) { /* * User-initiated scan request in ap_scan == 2; scan with * wildcard SSID. */ ssid = NULL; } else if (wpa_s->reattach && wpa_s->current_ssid != NULL) { // 實行單通道,單個ssid掃描。難道是漫遊的操作? // reassoicate重關聯 /* * Perform single-channel single-SSID scan for * reassociate-to-same-BSS operation. */ /* Setup SSID */ ssid = wpa_s->current_ssid; wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID", ssid->ssid, ssid->ssid_len); params.ssids[0].ssid = ssid->ssid; params.ssids[0].ssid_len = ssid->ssid_len; params.num_ssids = 1; /* * Allocate memory for frequency array, allocate one extra * slot for the zero-terminator. */ params.freqs = os_malloc(sizeof(int) * 2); if (params.freqs) { params.freqs[0] = wpa_s->assoc_freq; params.freqs[1] = 0; } /* * Reset the reattach flag so that we fall back to full scan if * this scan fails. */ wpa_s->reattach = 0; } else { struct wpa_ssid *start = ssid, *tssid; int freqs_set = 0; if (ssid == NULL && max_ssids > 1) ssid = wpa_s->conf->ssid; // 獲取配置檔案中的ssid while (ssid) { if (!wpas_network_disabled(wpa_s, ssid) && 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++; // 達到所能支援的最大ssid個數,退出迴圈 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; } if (wpa_s->scan_id_count && wpa_s->last_scan_req == MANUAL_SCAN_REQ) wpa_set_scan_ssids(wpa_s, ¶ms, max_ssids); for (tssid = wpa_s->conf->ssid; wpa_s->last_scan_req != MANUAL_SCAN_REQ && tssid; tssid = tssid->next) { // 網路關閉,不進行掃描 if (wpas_network_disabled(wpa_s, tssid)) 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 && max_ssids == 1) { /* * If the driver is limited to 1 SSID at a time interleave * wildcard SSID scans with specific SSID scans to avoid * waiting a long time for a wildcard scan. */ if (!wpa_s->prev_scan_wildcard) { params.ssids[0].ssid = NULL; params.ssids[0].ssid_len = 0; wpa_s->prev_scan_wildcard = 1; wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for " "wildcard SSID (Interleave with specific)"); } else { wpa_s->prev_scan_ssid = ssid; wpa_s->prev_scan_wildcard = 0; wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for specific SSID: %s", wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); } } else if (ssid) { /* max_ssids > 1 */ wpa_s->prev_scan_ssid = ssid; wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in " "the scan request"); params.num_ssids++; } else if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && wpa_s->manual_scan_passive && params.num_ssids == 0) { wpa_dbg(wpa_s, MSG_DEBUG, "Use passive scan based on manual request"); } else if (wpa_s->conf->passive_scan) { wpa_dbg(wpa_s, MSG_DEBUG, "Use passive scan based on configuration"); } else { wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; params.num_ssids++; wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard " "SSID"); } ssid_list_set: wpa_supplicant_optimize_freqs(wpa_s, ¶ms); extra_ie = wpa_supplicant_extra_ies(wpa_s); // 手動發起的掃描 if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && wpa_s->manual_scan_only_new) { wpa_printf(MSG_DEBUG, "Request driver to clear scan cache due to manual only_new=1 scan"); params.only_new_results = 1; } if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs == NULL && wpa_s->manual_scan_freqs) { wpa_dbg(wpa_s, MSG_DEBUG, "Limit manual scan to specified channels"); params.freqs = wpa_s->manual_scan_freqs; wpa_s->manual_scan_freqs = NULL; } if (params.freqs == NULL && wpa_s->select_network_scan_freqs) { wpa_dbg(wpa_s, MSG_DEBUG, "Limit select_network scan to specified channels"); params.freqs = wpa_s->select_network_scan_freqs; wpa_s->select_network_scan_freqs = NULL; } // 引數裡面的頻率為空 // 優化掃描,基於的頻率列表 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; wpa_setband_scan_freqs(wpa_s, ¶ms); /* See if user specified frequencies. If so, scan only those. */ if (wpa_s->conf->freq_list && !params.freqs) { wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on conf->freq_list"); int_array_concat(¶ms.freqs, wpa_s->conf->freq_list); } /* Use current associated channel? */ // 是否只掃描當前通道 if (wpa_s->conf->scan_cur_freq && !params.freqs) { unsigned int num = wpa_s->num_multichan_concurrent; params.freqs = os_calloc(num + 1, sizeof(int)); if (params.freqs) { num = get_shared_radio_freqs(wpa_s, params.freqs, num); if (num > 0) { wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the " "current operating channels since " "scan_cur_freq is enabled"); } else { os_free(params.freqs); params.freqs = NULL; } } } params.filter_ssids = wpa_supplicant_build_filter_ssids( wpa_s->conf, ¶ms.num_filter_ssids); if (extra_ie) { params.extra_ies = wpabuf_head(extra_ie); params.extra_ies_len = wpabuf_len(extra_ie); } ... if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) && wpa_s->wpa_state <= WPA_SCANNING) { params.mac_addr_rand = 1; if (wpa_s->mac_addr_scan) { params.mac_addr = wpa_s->mac_addr_scan; params.mac_addr_mask = wpa_s->mac_addr_scan + ETH_ALEN; } } if (!is_zero_ether_addr(wpa_s->next_scan_bssid)) { struct wpa_bss *bss; params.bssid = wpa_s->next_scan_bssid; bss = wpa_bss_get_bssid_latest(wpa_s, params.bssid); if (bss && bss->ssid_len && params.num_ssids == 1 && params.ssids[0].ssid_len == 0) { params.ssids[0].ssid = bss->ssid; params.ssids[0].ssid_len = bss->ssid_len; wpa_dbg(wpa_s, MSG_DEBUG, "Scan a previously specified BSSID " MACSTR " and SSID %s", MAC2STR(params.bssid), wpa_ssid_txt(bss->ssid, bss->ssid_len)); } else { wpa_dbg(wpa_s, MSG_DEBUG, "Scan a previously specified BSSID " MACSTR, MAC2STR(params.bssid)); } } scan_params = ¶ms; scan: ... ret = wpa_supplicant_trigger_scan(wpa_s, scan_params); if (ret && wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs && !wpa_s->manual_scan_freqs) { /* Restore manual_scan_freqs for the next attempt */ wpa_s->manual_scan_freqs = params.freqs; params.freqs = NULL; } wpabuf_free(extra_ie); os_free(params.freqs); os_free(params.filter_ssids); if (ret) { wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan"); if (wpa_s->scan_prev_wpa_state != wpa_s->wpa_state) wpa_supplicant_set_state(wpa_s, wpa_s->scan_prev_wpa_state); /* Restore scan_req since we will try to scan again */ wpa_s->scan_req = wpa_s->last_scan_req; wpa_supplicant_req_scan(wpa_s, 1, 0); } else { wpa_s->scan_for_connection = 0; #ifdef CONFIG_INTERWORKING wpa_s->interworking_fast_assoc_tried = 0; #endif /* CONFIG_INTERWORKING */ if (params.bssid) os_memset(wpa_s->next_scan_bssid, 0, ETH_ALEN); } } wpa_supplicant_trigger_scan --> wpas_trigger_scan_cb --> wpa_drv_scan(wpa_s, params); --> wpa_s->driver->scan2(wpa_s->drv_priv, params); external\wpa_supplicant_8\src\drivers\driver_nl80211.c const struct wpa_driver_ops wpa_driver_nl80211_ops = { .name = "nl80211", .desc = "Linux nl80211/cfg80211", .get_bssid = wpa_driver_nl80211_get_bssid, .get_ssid = wpa_driver_nl80211_get_ssid, .set_key = driver_nl80211_set_key, .scan2 = driver_nl80211_scan2, ... } static int driver_nl80211_scan2(void *priv, struct wpa_driver_scan_params *params) { struct i802_bss *bss = priv; #ifdef CONFIG_DRIVER_NL80211_QCA struct wpa_driver_nl80211_data *drv = bss->drv; /* * Do a vendor specific scan if possible. If only_new_results is * set, do a normal scan since a kernel (cfg80211) BSS cache flush * cannot be achieved through a vendor scan. The below condition may * need to be modified if new scan flags are added in the future whose * functionality can only be achieved through a normal scan. */ if (drv->scan_vendor_cmd_avail && !params->only_new_results) return wpa_driver_nl80211_vendor_scan(bss, params); #endif /* CONFIG_DRIVER_NL80211_QCA */ return wpa_driver_nl80211_scan(bss, params); } external\wpa_supplicant_8\hostapd\src\drivers\driver_nl80211_scan.c int wpa_driver_nl80211_scan(struct i802_bss *bss, struct wpa_driver_scan_params *params) { struct wpa_driver_nl80211_data *drv = bss->drv; int ret = -1, timeout; struct nl_msg *msg = NULL; wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request"); drv->scan_for_auth = 0; if (TEST_FAIL()) return -1; msg = nl80211_scan_common(bss, NL80211_CMD_TRIGGER_SCAN, params); if (!msg) return -1; if (params->p2p_probe) { struct nlattr *rates; wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates"); rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES); if (rates == NULL) goto fail; /* * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates * by masking out everything else apart from the OFDM rates 6, * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz * rates are left enabled. */ if (nla_put(msg, NL80211_BAND_2GHZ, 8, "\x0c\x12\x18\x24\x30\x48\x60\x6c")) goto fail; nla_nest_end(msg, rates); if (nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE)) goto fail; } if (params->bssid) { wpa_printf(MSG_DEBUG, "nl80211: Scan for a specific BSSID: " MACSTR, MAC2STR(params->bssid)); if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid)) goto fail; } ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d " "(%s)", ret, strerror(-ret)); if (drv->hostapd && is_ap_interface(drv->nlmode)) { enum nl80211_iftype old_mode = drv->nlmode; /* * mac80211 does not allow scan requests in AP mode, so * try to do this in station mode. */ if (wpa_driver_nl80211_set_mode( bss, NL80211_IFTYPE_STATION)) goto fail; if (wpa_driver_nl80211_scan(bss, params)) { wpa_driver_nl80211_set_mode(bss, old_mode); goto fail; } /* Restore AP mode when processing scan results */ drv->ap_scan_as_station = old_mode; ret = 0; } else goto fail; } drv->scan_state = SCAN_REQUESTED; /* Not all drivers generate "scan completed" wireless event, so try to * read results after a timeout. */ // 掃描超時時間,超時之後讀取結果。 timeout = 10; if (drv->scan_complete_events) { /* * The driver seems to deliver events to notify when scan is * complete, so use longer timeout to avoid race conditions * with scanning and following association request. */ timeout = 30; } wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d " "seconds", ret, timeout); eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx); eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout, drv, drv->ctx); drv->last_scan_cmd = NL80211_CMD_TRIGGER_SCAN; fail: nlmsg_free(msg); return ret; } static struct nl_msg * nl80211_scan_common(struct i802_bss *bss, u8 cmd, struct wpa_driver_scan_params *params) { struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; size_t i; u32 scan_flags = 0; msg = nl80211_cmd_msg(bss, 0, cmd); if (!msg) return NULL; if (params->num_ssids) { struct nlattr *ssids; ssids = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS); if (ssids == NULL) goto fail; 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); if (nla_put(msg, i + 1, params->ssids[i].ssid_len, params->ssids[i].ssid)) goto fail; } nla_nest_end(msg, ssids); } else { wpa_printf(MSG_DEBUG, "nl80211: Passive scan requested"); } if (params->extra_ies) { wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs", params->extra_ies, params->extra_ies_len); if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len, params->extra_ies)) goto fail; } // 掃描頻率 if (params->freqs) { struct nlattr *freqs; freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES); if (freqs == NULL) goto fail; for (i = 0; params->freqs[i]; i++) { wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u " "MHz", params->freqs[i]); if (nla_put_u32(msg, i + 1, params->freqs[i])) goto fail; } nla_nest_end(msg, freqs); } os_free(drv->filter_ssids); drv->filter_ssids = params->filter_ssids; params->filter_ssids = NULL; drv->num_filter_ssids = params->num_filter_ssids; if (params->only_new_results) { wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH"); scan_flags |= NL80211_SCAN_FLAG_FLUSH; } if (params->low_priority && drv->have_low_prio_scan) { wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_LOW_PRIORITY"); scan_flags |= NL80211_SCAN_FLAG_LOW_PRIORITY; } if (params->mac_addr_rand) { wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_RANDOM_ADDR"); scan_flags |= NL80211_SCAN_FLAG_RANDOM_ADDR; if (params->mac_addr) { wpa_printf(MSG_DEBUG, "nl80211: MAC address: " MACSTR, MAC2STR(params->mac_addr)); if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->mac_addr)) goto fail; } if (params->mac_addr_mask) { wpa_printf(MSG_DEBUG, "nl80211: MAC address mask: " MACSTR, MAC2STR(params->mac_addr_mask)); if (nla_put(msg, NL80211_ATTR_MAC_MASK, ETH_ALEN, params->mac_addr_mask)) goto fail; } } if (params->duration) { if (!(drv->capa.rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL) || nla_put_u16(msg, NL80211_ATTR_MEASUREMENT_DURATION, params->duration)) goto fail; if (params->duration_mandatory && nla_put_flag(msg, NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY)) goto fail; } if (scan_flags && nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags)) goto fail; return msg; fail: nlmsg_free(msg); return NULL; }
2018-11-14