void wpa_supplicant_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *selected, struct wpa_ssid *ssid) { if (wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) { wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP "PBC session overlap"); #ifdef CONFIG_P2P if (wpas_p2p_notif_pbc_overlap(wpa_s) == 1) return; #endif /* CONFIG_P2P */ wpas_wps_cancel(wpa_s); return; } /* * Do not trigger new association unless the BSSID has changed or if * reassociation is requested. If we are in process of associating with * the selected BSSID, do not trigger new attempt. */ if (wpa_s->reassociate || (os_memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0 && (wpa_s->wpa_state != WPA_ASSOCIATING || os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) != 0))) { if (wpa_supplicant_scard_init(wpa_s, ssid)) { wpa_supplicant_req_new_scan(wpa_s, 10, 0); return; } wpa_supplicant_associate(wpa_s, selected, ssid); } else { wpa_printf(MSG_DEBUG, "Already associated with the selected " "AP"); } }
static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { while (ssid) { if (!ssid->disabled) break; ssid = ssid->next; } /* ap_scan=2 mode - try to associate with each SSID. */ if (ssid == NULL) { wpa_dbg(wpa_s, MSG_DEBUG, "wpa_supplicant_assoc_try: Reached " "end of scan list - go back to beginning"); wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; wpa_supplicant_req_scan(wpa_s, 0, 0); return; } if (ssid->next) { /* Continue from the next SSID on the next attempt. */ wpa_s->prev_scan_ssid = ssid; } else { /* Start from the beginning of the SSID list. */ wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; } wpa_supplicant_associate(wpa_s, NULL, ssid); }
void wpa_supplicant_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *selected, struct wpa_ssid *ssid) { if (wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) { wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP "PBC session overlap"); wpa_supplicant_req_new_scan(wpa_s, 10, 0); return; } /* * Do not trigger new association unless the BSSID has changed or if * reassociation is requested. If we are in process of associating with * the selected BSSID, do not trigger new attempt. */ if (wpa_s->reassociate || (os_memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0 && ((wpa_s->wpa_state != WPA_ASSOCIATING && wpa_s->wpa_state != WPA_AUTHENTICATING) || os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) != 0))) { if (wpa_supplicant_scard_init(wpa_s, ssid)) { wpa_supplicant_req_new_scan(wpa_s, 10, 0); return; } wpa_msg(wpa_s, MSG_DEBUG, "Request association: " "reassociate: %d selected: "MACSTR " bssid: " MACSTR " pending: " MACSTR " wpa_state: %s", wpa_s->reassociate, MAC2STR(selected->bssid), MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid), wpa_supplicant_state_txt(wpa_s->wpa_state)); wpa_supplicant_associate(wpa_s, selected, ssid); } else { wpa_printf(MSG_DEBUG, "Already associated with the selected " "AP"); } }
static void wpa_supplicant_scan_results(struct wpa_supplicant *wpa_s) { dladm_wlan_ess_t results[MAX_SCANRESULTS]; int num; dladm_wlan_ess_t *selected = NULL; struct wpa_ssid *ssid; (void) memset(results, 0, sizeof (dladm_wlan_ess_t) * MAX_SCANRESULTS); num = wpa_s->driver->get_scan_results(wpa_s->linkid, results, MAX_SCANRESULTS); wpa_printf(MSG_DEBUG, "Scan results: %d", num); if (num < 0) return; if (num > MAX_SCANRESULTS) { wpa_printf(MSG_INFO, "Not enough room for all APs (%d < %d)", num, MAX_SCANRESULTS); num = MAX_SCANRESULTS; } selected = wpa_supplicant_select_bss(wpa_s, wpa_s->conf->ssid, results, num, &ssid); if (selected) { if (wpa_s->reassociate || memcmp(selected->we_bssid.wb_bytes, wpa_s->bssid, IEEE80211_ADDR_LEN) != 0) { wpa_supplicant_associate(wpa_s, selected, ssid); } else { wpa_printf(MSG_DEBUG, "Already associated with the " "selected AP."); } } else { wpa_printf(MSG_DEBUG, "No suitable AP found."); wpa_supplicant_req_scan(wpa_s, 5, 0); /* wait 5 seconds */ } }
void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { struct wpa_ssid *ssid = wpa_s->current_ssid; if (ssid == NULL) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: Ignore authentication event " "when network is not selected"); return; } if (wpa_s->wpa_state != WPA_AUTHENTICATING) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: Ignore authentication event " "when not in authenticating state"); return; } if (os_memcmp(wpa_s->pending_bssid, data->auth.peer, ETH_ALEN) != 0) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: Ignore authentication with " "unexpected peer " MACSTR, MAC2STR(data->auth.peer)); return; } wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication response: peer=" MACSTR " auth_type=%d status_code=%d", MAC2STR(data->auth.peer), data->auth.auth_type, data->auth.status_code); wpa_hexdump(MSG_MSGDUMP, "SME: Authentication response IEs", data->auth.ies, data->auth.ies_len); eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL); if (data->auth.status_code != WLAN_STATUS_SUCCESS) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication failed (status " "code %d)", data->auth.status_code); if (data->auth.status_code != WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG || wpa_s->sme.auth_alg == data->auth.auth_type || wpa_s->current_ssid->auth_alg == WPA_AUTH_ALG_LEAP) { wpas_connection_failed(wpa_s, wpa_s->pending_bssid); wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); return; } switch (data->auth.auth_type) { case WLAN_AUTH_OPEN: wpa_s->current_ssid->auth_alg = WPA_AUTH_ALG_SHARED; wpa_dbg(wpa_s, MSG_DEBUG, "SME: Trying SHARED auth"); wpa_supplicant_associate(wpa_s, wpa_s->current_bss, wpa_s->current_ssid); return; case WLAN_AUTH_SHARED_KEY: wpa_s->current_ssid->auth_alg = WPA_AUTH_ALG_LEAP; wpa_dbg(wpa_s, MSG_DEBUG, "SME: Trying LEAP auth"); wpa_supplicant_associate(wpa_s, wpa_s->current_bss, wpa_s->current_ssid); return; default: return; } } #ifdef CONFIG_IEEE80211R if (data->auth.auth_type == WLAN_AUTH_FT) { union wpa_event_data edata; os_memset(&edata, 0, sizeof(edata)); edata.ft_ies.ies = data->auth.ies; edata.ft_ies.ies_len = data->auth.ies_len; os_memcpy(edata.ft_ies.target_ap, data->auth.peer, ETH_ALEN); wpa_supplicant_event(wpa_s, EVENT_FT_RESPONSE, &edata); } #endif /* CONFIG_IEEE80211R */ sme_associate(wpa_s, ssid->mode, data->auth.peer, data->auth.auth_type); }
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; const u8 *extra_ie = NULL; size_t extra_ie_len = 0; int wps = 0; #ifdef CONFIG_WPS enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO; #endif /* CONFIG_WPS */ wpa_printf(MSG_DEBUG, "%s: scan_req = %d, ap_scan = %d", __func__, wpa_s->scan_req, wpa_s->conf->ap_scan); #if ICS_LEGACY_WLAN_SUPPORT if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { wpa_printf(MSG_DEBUG, "Skip scan - interface disabled"); return; } #endif 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_printf(MSG_DEBUG, "No enabled networks - do not scan"); wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); return; } scan_req = wpa_s->scan_req; wpa_s->scan_req = 0; if (wpa_s->conf->ap_scan != 0 && wpa_s->driver && IS_WIRED(wpa_s->driver)) { wpa_printf(MSG_DEBUG, "Using wired authentication - " "overriding ap_scan configuration"); wpa_s->conf->ap_scan = 0; } if (wpa_s->conf->ap_scan == 0) { wpa_supplicant_gen_assoc_event(wpa_s); return; } if (wpa_s->wpa_state == WPA_DISCONNECTED || wpa_s->wpa_state == WPA_INACTIVE) wpa_supplicant_set_state(wpa_s, WPA_SCANNING); ssid = wpa_s->conf->ssid; if (wpa_s->prev_scan_ssid != BROADCAST_SSID_SCAN) { while (ssid) { if (ssid == wpa_s->prev_scan_ssid) { ssid = ssid->next; break; } ssid = ssid->next; } } while (ssid) { //MTK_OP01_PROTECT_START #ifdef CONFIG_CMCC_SUPPORT /* CMCC */ if ( #else //MTK_OP01_PROTECT_END if (!ssid->disabled && //MTK_OP01_PROTECT_START #endif //MTK_OP01_PROTECT_END (ssid->scan_ssid || wpa_s->conf->ap_scan == 2)) break; ssid = ssid->next; } if (scan_req != 2 && wpa_s->conf->ap_scan == 2) { /* * ap_scan=2 mode - try to associate with each SSID instead of * scanning for each scan_ssid=1 network. */ if (ssid == NULL) { wpa_printf(MSG_DEBUG, "wpa_supplicant_scan: Reached " "end of scan list - go back to beginning"); wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN; wpa_supplicant_req_scan(wpa_s, 0, 0); return; } if (ssid->next) { /* Continue from the next SSID on the next attempt. */ wpa_s->prev_scan_ssid = ssid; } else { /* Start from the beginning of the SSID list. */ wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN; } wpa_supplicant_associate(wpa_s, NULL, ssid); return; } #ifdef CONFIG_WPS wps = wpas_wps_in_use(wpa_s->conf, &req_type); #endif /* CONFIG_WPS */ if (wpa_s->scan_res_tried == 0 && wpa_s->conf->ap_scan == 1 && !wpa_s->use_client_mlme && wps != 2) { wpa_s->scan_res_tried++; wpa_s->scan_req = scan_req; wpa_printf(MSG_DEBUG, "Trying to get current scan results " "first without requesting a new scan to speed up " "initial association"); wpa_supplicant_event(wpa_s, EVENT_SCAN_RESULTS, NULL); return; } #ifdef CONFIG_WPS if (wps) { wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev, wpa_s->wps->uuid, req_type); if (wps_ie) { extra_ie = wpabuf_head(wps_ie); extra_ie_len = wpabuf_len(wps_ie); } } #endif /* CONFIG_WPS */ wpa_supplicant_notify_scanning(wpa_s, 1); wpa_printf(MSG_DEBUG, "Starting AP scan (%s SSID)", ssid ? "specific": "broadcast"); if (ssid) { wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID", ssid->ssid, ssid->ssid_len); wpa_s->prev_scan_ssid = ssid; } else wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN; if (wpa_s->use_client_mlme) { ieee80211_sta_set_probe_req_ie(wpa_s, extra_ie, extra_ie_len); ret = ieee80211_sta_req_scan(wpa_s, ssid ? ssid->ssid : NULL, ssid ? ssid->ssid_len : 0); } else { wpa_drv_set_probe_req_ie(wpa_s, extra_ie, extra_ie_len); ret = wpa_drv_scan(wpa_s, &ssid); } wpabuf_free(wps_ie); if (ret) { wpa_printf(MSG_WARNING, "Failed to initiate AP scan."); wpa_supplicant_notify_scanning(wpa_s, 0); wpa_supplicant_req_scan(wpa_s, 10, 0); } else { wpa_s->scan_runs++; } }
static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s) { int prio, timeout; struct wpa_scan_res *selected = NULL; struct wpa_ssid *ssid = NULL; wpa_supplicant_notify_scanning(wpa_s, 0); if (wpa_supplicant_get_scan_results(wpa_s) < 0) { if (wpa_s->conf->ap_scan == 2) return; wpa_printf(MSG_DEBUG, "Failed to get scan results - try " "scanning again"); timeout = 1; goto req_scan; } /* * Don't post the results if this was the initial cached * and there were no results. */ if (wpa_s->scan_res_tried == 1 && wpa_s->conf->ap_scan == 1 && wpa_s->scan_res->num == 0) { wpa_msg(wpa_s, MSG_DEBUG, "Cached scan results are " "empty - not posting"); } else { wpa_printf(MSG_DEBUG, "New scan results available"); wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS); wpa_supplicant_dbus_notify_scan_results(wpa_s); wpas_wps_notify_scan_results(wpa_s); } if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s))) return; if (wpa_s->disconnected) { wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); return; } while (selected == NULL) { for (prio = 0; prio < wpa_s->conf->num_prio; prio++) { selected = wpa_supplicant_select_bss( wpa_s, wpa_s->conf->pssid[prio], &ssid); if (selected) break; } if (selected == NULL && wpa_s->blacklist) { wpa_printf(MSG_DEBUG, "No APs found - clear blacklist " "and try again"); wpa_blacklist_clear(wpa_s); wpa_s->blacklist_cleared++; } else if (selected == NULL) { break; } } if (selected) { if (wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) { wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP "PBC session overlap"); timeout = 10; goto req_scan; } /* Do not trigger new association unless the BSSID has changed * or if reassociation is requested. If we are in process of * associating with the selected BSSID, do not trigger new * attempt. */ if (wpa_s->reassociate || (os_memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0 && (wpa_s->wpa_state != WPA_ASSOCIATING || os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) != 0))) { if (wpa_supplicant_scard_init(wpa_s, ssid)) { wpa_supplicant_req_scan(wpa_s, 10, 0); return; } wpa_supplicant_associate(wpa_s, selected, ssid); } else { wpa_printf(MSG_DEBUG, "Already associated with the " "selected AP."); } rsn_preauth_scan_results(wpa_s->wpa, wpa_s->scan_res); } else { wpa_printf(MSG_DEBUG, "No suitable AP found."); timeout = 5; goto req_scan; } return; req_scan: if (wpa_s->scan_res_tried == 1 && wpa_s->conf->ap_scan == 1) { /* * Quick recovery if the initial scan results were not * complete when fetched before the first scan request. */ wpa_s->scan_res_tried++; timeout = 0; } else if (!wpa_supplicant_enabled_networks(wpa_s->conf)) { /* * No networks are enabled; short-circuit request so * we don't wait timeout seconds before transitioning * to INACTIVE state. */ wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); return; } wpa_supplicant_req_scan(wpa_s, timeout, 0); }
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); 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"); wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS); wpas_notify_scan_results(wpa_s); wpas_notify_scan_done(wpa_s, 1); if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s))) { wpa_scan_results_free(scan_res); return; } if (wpa_s->disconnected) { wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); wpa_scan_results_free(scan_res); return; } wpa_supplicant_rsn_preauth_scan_results(wpa_s, scan_res); selected = wpa_supplicant_pick_network(wpa_s, scan_res, &ssid); if (selected) { int skip; skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid, scan_res); wpa_scan_results_free(scan_res); if (skip) return; wpa_supplicant_connect(wpa_s, selected, ssid); } else { wpa_scan_results_free(scan_res); wpa_printf(MSG_DEBUG, "No suitable network found"); ssid = wpa_supplicant_pick_new_network(wpa_s); if (ssid) { wpa_printf(MSG_DEBUG, "Setup a new network"); wpa_supplicant_associate(wpa_s, NULL, ssid); } else { int timeout_sec = 5; int timeout_usec = 0; #ifdef CONFIG_P2P if (wpa_s->p2p_in_provisioning) { /* * Use shorter wait during P2P Provisioning * state to speed up group formation. */ timeout_sec = 0; timeout_usec = 250000; } #endif /* CONFIG_P2P */ wpa_supplicant_req_new_scan(wpa_s, timeout_sec, timeout_usec); } } }
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 *extra_ie; struct wpa_driver_scan_params params; size_t max_ssids; enum wpa_states prev_state; 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) { wpa_supplicant_gen_assoc_event(wpa_s); return; } #ifdef CONFIG_P2P if (wpas_p2p_in_progress(wpa_s)) { if (wpa_s->sta_scan_pending && wpas_p2p_in_progress(wpa_s) == 2 && wpa_s->global->p2p_cb_on_scan_complete) { wpa_dbg(wpa_s, MSG_DEBUG, "Process pending station " "mode scan during P2P search"); } else { wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan " "while P2P operation is in progress"); wpa_s->sta_scan_pending = 1; wpa_supplicant_req_scan(wpa_s, 5, 0); return; } } #endif /* CONFIG_P2P */ 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; } 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_s->prev_scan_wildcard = 0; wpa_supplicant_assoc_try(wpa_s, ssid); return; #ifndef ANDROID } else if (wpa_s->conf->ap_scan == 2) { /* * User-initiated scan request in ap_scan == 2; scan with * wildcard SSID. */ ssid = NULL; #endif } 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 && 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 { wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; params.num_ssids++; wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard " "SSID"); } wpa_supplicant_optimize_freqs(wpa_s, ¶ms); extra_ie = wpa_supplicant_extra_ies(wpa_s, ¶ms); #ifdef CONFIG_HS20 if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 6) == 0) wpas_hs20_add_indication(extra_ie); #endif /* CONFIG_HS20 */ 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); if (extra_ie) { params.extra_ies = wpabuf_head(extra_ie); params.extra_ies_len = wpabuf_len(extra_ie); } #ifdef CONFIG_P2P if (wpa_s->p2p_in_provisioning) { /* * The interface may not yet be in P2P mode, so we have to * explicitly request P2P probe to disable CCK rates. */ params.p2p_probe = 1; } #endif /* CONFIG_P2P */ ret = wpa_supplicant_trigger_scan(wpa_s, ¶ms); 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 (prev_state != wpa_s->wpa_state) wpa_supplicant_set_state(wpa_s, prev_state); /* Restore scan_req since we will try to scan again */ wpa_s->scan_req = scan_req; wpa_supplicant_req_scan(wpa_s, 1, 0); } }
static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; struct wpa_ssid *ssid; int ret; struct wpabuf *extra_ie = NULL; struct wpa_driver_scan_params params; struct wpa_driver_scan_params *scan_params; size_t max_ssids; enum wpa_states prev_state; if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled"); wpas_p2p_continue_after_scan(wpa_s); 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); wpas_p2p_continue_after_scan(wpa_s); 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; } 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); wpas_p2p_continue_after_scan(wpa_s); 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; } #ifdef CONFIG_P2P if (wpas_p2p_in_progress(wpa_s) || wpas_wpa_is_in_progress(wpa_s, 0)) { if (wpa_s->sta_scan_pending && wpas_p2p_in_progress(wpa_s) == 2 && wpa_s->global->p2p_cb_on_scan_complete) { wpa_dbg(wpa_s, MSG_DEBUG, "Process pending station " "mode scan during P2P search"); } else { wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan " "while P2P operation is in progress"); wpa_s->sta_scan_pending = 1; wpa_supplicant_req_scan(wpa_s, 5, 0); return; } } #endif /* CONFIG_P2P */ #ifdef CONFIG_GAS if (gas_query_in_progress(wpa_s->gas)) { wpa_dbg(wpa_s, MSG_DEBUG, "Delay scan while GAS query is in progress"); wpa_supplicant_req_scan(wpa_s, 1, 0); return; } #endif /* CONFIG_GAS */ 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; 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 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_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; } } #ifdef CONFIG_P2P if ((wpa_s->p2p_in_provisioning || wpa_s->show_group_started) && wpa_s->go_params) { wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during P2P group formation (p2p_in_provisioning=%d show_group_started=%d)", wpa_s->p2p_in_provisioning, wpa_s->show_group_started); params.ssids[0].ssid = wpa_s->go_params->ssid; params.ssids[0].ssid_len = wpa_s->go_params->ssid_len; params.num_ssids = 1; goto ssid_list_set; } #endif /* CONFIG_P2P */ /* 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 (wpa_s->last_scan_req != MANUAL_SCAN_REQ && 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 { struct wpa_ssid *start = ssid, *tssid; int freqs_set = 0; if (ssid == NULL && max_ssids > 1) ssid = wpa_s->conf->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++; 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 (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 { 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 ssid_list_set: #endif /* CONFIG_P2P */ wpa_supplicant_optimize_freqs(wpa_s, ¶ms); extra_ie = wpa_supplicant_extra_ies(wpa_s); 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); } #ifdef CONFIG_P2P if (wpa_s->p2p_in_provisioning || (wpa_s->show_group_started && wpa_s->go_params)) { /* * The interface may not yet be in P2P mode, so we have to * explicitly request P2P probe to disable CCK rates. */ params.p2p_probe = 1; } #endif /* CONFIG_P2P */ scan_params = ¶ms; scan: #ifdef CONFIG_P2P /* * If the driver does not support multi-channel concurrency and a * virtual interface that shares the same radio with the wpa_s interface * is operating there may not be need to scan other channels apart from * the current operating channel on the other virtual interface. Filter * out other channels in case we are trying to find a connection for a * station interface when we are not configured to prefer station * connection and a concurrent operation is already in process. */ if (wpa_s->scan_for_connection && wpa_s->last_scan_req == NORMAL_SCAN_REQ && !scan_params->freqs && !params.freqs && wpas_is_p2p_prioritized(wpa_s) && wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE && non_p2p_network_enabled(wpa_s)) { 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 && num == wpa_s->num_multichan_concurrent) { wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the current operating channels since all channels are already used"); } else { os_free(params.freqs); params.freqs = NULL; } } } #endif /* CONFIG_P2P */ ret = wpa_supplicant_trigger_scan(wpa_s, scan_params); 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 (prev_state != wpa_s->wpa_state) wpa_supplicant_set_state(wpa_s, prev_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; } }
static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; struct wpa_ssid *ssid; int enabled, scan_req = 0, ret; const u8 *extra_ie = NULL; size_t extra_ie_len = 0; int scan_ssid_all = 1; if (wpa_s->disconnected && !wpa_s->scan_req) return; enabled = 0; /* check if all configured ssids should be scanned directly */ ssid = wpa_s->conf->ssid; while (ssid) { if (!ssid->scan_ssid) { scan_ssid_all = 0; break; } ssid = ssid->next; } ssid = wpa_s->conf->ssid; while (ssid) { if (!ssid->disabled) { enabled++; break; } ssid = ssid->next; } if (!enabled && !wpa_s->scan_req) { wpa_printf(MSG_DEBUG, "No enabled networks - do not scan"); wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); return; } scan_req = wpa_s->scan_req; wpa_s->scan_req = 0; if (wpa_s->conf->ap_scan != 0 && wpa_s->driver && os_strcmp(wpa_s->driver->name, "wired") == 0) { wpa_printf(MSG_DEBUG, "Using wired driver - overriding " "ap_scan configuration"); wpa_s->conf->ap_scan = 0; } if (wpa_s->conf->ap_scan == 0) { wpa_supplicant_gen_assoc_event(wpa_s); return; } if (wpa_s->wpa_state == WPA_DISCONNECTED || wpa_s->wpa_state == WPA_INACTIVE) wpa_supplicant_set_state(wpa_s, WPA_SCANNING); ssid = wpa_s->conf->ssid; if (wpa_s->prev_scan_ssid != BROADCAST_SSID_SCAN) { while (ssid) { if (ssid == wpa_s->prev_scan_ssid) { ssid = ssid->next; break; } ssid = ssid->next; } } while (ssid) { if (!ssid->disabled && (ssid->scan_ssid || wpa_s->conf->ap_scan == 2)) break; ssid = ssid->next; } if (scan_req != 2 && wpa_s->conf->ap_scan == 2) { /* * ap_scan=2 mode - try to associate with each SSID instead of * scanning for each scan_ssid=1 network. */ if (ssid == NULL) { wpa_printf(MSG_DEBUG, "wpa_supplicant_scan: Reached " "end of scan list - go back to beginning"); wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN; wpa_supplicant_req_scan(wpa_s, 0, 0); return; } if (ssid->next) { /* Continue from the next SSID on the next attempt. */ wpa_s->prev_scan_ssid = ssid; } else { /* Start from the beginning of the SSID list. */ wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN; } wpa_supplicant_associate(wpa_s, NULL, ssid); return; } if (scan_ssid_all && !ssid) { ssid = wpa_s->conf->ssid; } wpa_printf(MSG_DEBUG, "Starting AP scan (%s SSID)", ssid ? "specific": "broadcast"); if (ssid) { wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID", ssid->ssid, ssid->ssid_len); wpa_s->prev_scan_ssid = ssid; } else wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN; if (!wpa_supplicant_may_scan(wpa_s) || (wpa_s->scan_res_tried == 0 && wpa_s->conf->ap_scan == 1 && !wpa_s->use_client_mlme)) { wpa_s->scan_res_tried++; wpa_printf(MSG_DEBUG, "Trying to get current scan results " "first without requesting a new scan to speed up " "initial association"); wpa_supplicant_event(wpa_s, EVENT_SCAN_RESULTS, NULL); return; } wpa_drv_flush_pmkid(wpa_s); if (wpa_s->use_client_mlme) { ieee80211_sta_set_probe_req_ie(wpa_s, extra_ie, extra_ie_len); ret = ieee80211_sta_req_scan(wpa_s, ssid ? ssid->ssid : NULL, ssid ? ssid->ssid_len : 0); } else { wpa_drv_set_probe_req_ie(wpa_s, extra_ie, extra_ie_len); ret = wpa_drv_scan(wpa_s, ssid ? ssid->ssid : NULL, ssid ? ssid->ssid_len : 0); } if (ret) { wpa_printf(MSG_WARNING, "Failed to initiate AP scan."); wpa_supplicant_req_scan(wpa_s, 3, 0); } }
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; wpa_supplicant_notify_scanning(wpa_s, 0); 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) return; wpa_printf(MSG_DEBUG, "Failed to get scan results - try " "scanning again"); wpa_supplicant_req_new_scan(wpa_s, 1); return; } /* * Don't post the results if this was the initial cached * and there were no results. */ if (wpa_s->scan_res_tried == 1 && wpa_s->conf->ap_scan == 1 && scan_res->num == 0) { wpa_msg(wpa_s, MSG_DEBUG, "Cached scan results are " "empty - not posting"); } else { wpa_printf(MSG_DEBUG, "New scan results available"); wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS); wpas_notify_scan_results(wpa_s); } wpas_notify_scan_done(wpa_s, 1); if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s))) { wpa_scan_results_free(scan_res); return; } if (wpa_s->disconnected) { wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); wpa_scan_results_free(scan_res); return; } if (bgscan_notify_scan(wpa_s) == 1) { wpa_scan_results_free(scan_res); return; } wpa_supplicant_rsn_preauth_scan_results(wpa_s, scan_res); selected = wpa_supplicant_pick_network(wpa_s, scan_res, &ssid); if (selected) { int skip; skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid, scan_res); wpa_scan_results_free(scan_res); if (skip) return; wpa_supplicant_connect(wpa_s, selected, ssid); } else { wpa_scan_results_free(scan_res); wpa_printf(MSG_DEBUG, "No suitable network found"); ssid = wpa_supplicant_pick_new_network(wpa_s); if (ssid) { wpa_printf(MSG_DEBUG, "Setup a new network"); wpa_supplicant_associate(wpa_s, NULL, ssid); } else wpa_supplicant_req_new_scan(wpa_s, 5); } }
static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s) { int num, prio, timeout; struct wpa_scan_result *selected = NULL; struct wpa_ssid *ssid = NULL; struct wpa_scan_result *results; if (wpa_supplicant_get_scan_results(wpa_s) < 0) { if (wpa_s->conf->ap_scan == 2) return; wpa_printf(MSG_DEBUG, "Failed to get scan results - try " "scanning again"); timeout = 1; goto req_scan; } wpa_supplicant_dbus_notify_scan_results(wpa_s); if (wpa_s->conf->ap_scan == 2) return; results = wpa_s->scan_results; num = wpa_s->num_scan_results; while (selected == NULL) { for (prio = 0; prio < wpa_s->conf->num_prio; prio++) { selected = wpa_supplicant_select_bss( wpa_s, wpa_s->conf->pssid[prio], results, num, &ssid); if (selected) break; } if (selected == NULL && wpa_s->blacklist) { wpa_printf(MSG_DEBUG, "No APs found - clear blacklist " "and try again"); wpa_blacklist_clear(wpa_s); } else if (selected == NULL) { break; } } if (selected) { /* Do not trigger new association unless the BSSID has changed * or if reassociation is requested. If we are in process of * associating with the selected BSSID, do not trigger new * attempt. */ if (wpa_s->reassociate || (os_memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0 && (wpa_s->wpa_state != WPA_ASSOCIATING || os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) != 0))) { if (wpa_supplicant_scard_init(wpa_s, ssid)) { wpa_supplicant_req_scan(wpa_s, 10, 0); return; } wpa_supplicant_associate(wpa_s, selected, ssid); } else { wpa_printf(MSG_DEBUG, "Already associated with the " "selected AP."); } rsn_preauth_scan_results(wpa_s->wpa, results, num); } else { wpa_printf(MSG_DEBUG, "No suitable AP found."); timeout = 5; goto req_scan; } return; req_scan: if (wpa_s->scan_res_tried == 1 && wpa_s->conf->ap_scan == 1) { /* * Quick recovery if the initial scan results were not * complete when fetched before the first scan request. */ wpa_s->scan_res_tried++; timeout = 0; } wpa_supplicant_req_scan(wpa_s, timeout, 0); }