static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s) { struct wpabuf *extra_ie = NULL; #ifdef CONFIG_WPS int wps = 0; enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO; #endif /* CONFIG_WPS */ #ifdef CONFIG_INTERWORKING if (wpa_s->conf->interworking && wpabuf_resize(&extra_ie, 100) == 0) wpas_add_interworking_elements(wpa_s, extra_ie); #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_WPS wps = wpas_wps_in_use(wpa_s, &req_type); if (wps) { struct wpabuf *wps_ie; wps_ie = wps_build_probe_req_ie(wps == 2 ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT, &wpa_s->wps->dev, wpa_s->wps->uuid, req_type, 0, NULL); if (wps_ie) { if (wpabuf_resize(&extra_ie, wpabuf_len(wps_ie)) == 0) wpabuf_put_buf(extra_ie, wps_ie); wpabuf_free(wps_ie); } } #ifdef CONFIG_P2P if (wps) { size_t ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p); if (wpabuf_resize(&extra_ie, ielen) == 0) wpas_p2p_scan_ie(wpa_s, extra_ie); } #endif /* CONFIG_P2P */ #endif /* CONFIG_WPS */ #ifdef CONFIG_HS20 if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 7) == 0) wpas_hs20_add_indication(extra_ie); #endif /* CONFIG_HS20 */ return extra_ie; }
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; #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; 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; } if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) || 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; } #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); /* 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)) { wpa_s->connect_without_scan = 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 (!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) { 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 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, wpa_s->wps->config_methods); 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); } }