X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=wpa_supplicant%2Fscan.c;h=ee105d902c8aa10f2136817d6fe31ba10fc79b9c;hb=HEAD;hp=56f062f56b42b01787858d71d039109ce1baf0cd;hpb=d1f9c410c1ba8b8d007c53a01da7aa2eae4d81c9;p=libeap.git diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index 56f062f..ee105d9 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -22,6 +22,8 @@ #include "driver_i.h" #include "mlme.h" #include "wps_supplicant.h" +#include "p2p_supplicant.h" +#include "p2p/p2p.h" #include "notify.h" #include "bss.h" #include "scan.h" @@ -204,18 +206,57 @@ int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s, } +static struct wpa_driver_scan_filter * +wpa_supplicant_build_filter_ssids(struct wpa_config *conf, size_t *num_ssids) +{ + struct wpa_driver_scan_filter *ssids; + struct wpa_ssid *ssid; + size_t count; + + *num_ssids = 0; + if (!conf->filter_ssids) + return NULL; + + for (count = 0, ssid = conf->ssid; ssid; ssid = ssid->next) { + if (ssid->ssid && ssid->ssid_len) + count++; + } + if (count == 0) + return NULL; + ssids = os_zalloc(count * sizeof(struct wpa_driver_scan_filter)); + if (ssids == NULL) + return NULL; + + for (ssid = conf->ssid; ssid; ssid = ssid->next) { + if (!ssid->ssid || !ssid->ssid_len) + continue; + os_memcpy(ssids[*num_ssids].ssid, ssid->ssid, ssid->ssid_len); + ssids[*num_ssids].ssid_len = ssid->ssid_len; + (*num_ssids)++; + } + + return ssids; +} + + 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; - int wps = 0; #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_printf(MSG_DEBUG, "Skip scan - interface disabled"); + return; + } if (wpa_s->disconnected && !wpa_s->scan_req) { wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); @@ -255,22 +296,12 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) 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->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) && - wps != 2) { - 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; - } - 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); @@ -287,7 +318,9 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) } } - if (scan_req != 2 && wpa_s->conf->ap_scan == 2) { + 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) { @@ -350,7 +383,50 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) wpa_printf(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_printf(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->go_params->freq_list[0]) { + wpa_printf(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_printf(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); @@ -361,16 +437,31 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) } #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 */ + + 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."); - wpa_supplicant_req_scan(wpa_s, 10, 0); - } else - wpa_s->scan_runs++; + if (prev_state != wpa_s->wpa_state) + wpa_supplicant_set_state(wpa_s, prev_state); + wpa_supplicant_req_scan(wpa_s, 1, 0); + } } @@ -531,6 +622,40 @@ struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res, } +struct wpabuf * wpa_scan_get_vendor_ie_multi_beacon( + const struct wpa_scan_res *res, u32 vendor_type) +{ + struct wpabuf *buf; + const u8 *end, *pos; + + if (res->beacon_ie_len == 0) + return NULL; + buf = wpabuf_alloc(res->beacon_ie_len); + if (buf == NULL) + return NULL; + + pos = (const u8 *) (res + 1); + pos += res->ie_len; + end = pos + res->beacon_ie_len; + + while (pos + 1 < end) { + if (pos + 2 + pos[1] > end) + break; + if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && + vendor_type == WPA_GET_BE32(&pos[2])) + wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4); + pos += 2 + pos[1]; + } + + if (wpabuf_len(buf) == 0) { + wpabuf_free(buf); + buf = NULL; + } + + return buf; +} + + /* Compare function for sorting scan results. Return >0 if @b is considered * better. */ static int wpa_scan_result_compar(const void *a, const void *b) @@ -580,6 +705,54 @@ static int wpa_scan_result_compar(const void *a, const void *b) } +#ifdef CONFIG_WPS +/* Compare function for sorting scan results when searching a WPS AP for + * provisioning. Return >0 if @b is considered better. */ +static int wpa_scan_result_wps_compar(const void *a, const void *b) +{ + struct wpa_scan_res **_wa = (void *) a; + struct wpa_scan_res **_wb = (void *) b; + struct wpa_scan_res *wa = *_wa; + struct wpa_scan_res *wb = *_wb; + int uses_wps_a, uses_wps_b; + struct wpabuf *wps_a, *wps_b; + int res; + + /* Optimization - check WPS IE existence before allocated memory and + * doing full reassembly. */ + uses_wps_a = wpa_scan_get_vendor_ie(wa, WPS_IE_VENDOR_TYPE) != NULL; + uses_wps_b = wpa_scan_get_vendor_ie(wb, WPS_IE_VENDOR_TYPE) != NULL; + if (uses_wps_a && !uses_wps_b) + return -1; + if (!uses_wps_a && uses_wps_b) + return 1; + + if (uses_wps_a && uses_wps_b) { + wps_a = wpa_scan_get_vendor_ie_multi(wa, WPS_IE_VENDOR_TYPE); + wps_b = wpa_scan_get_vendor_ie_multi(wb, WPS_IE_VENDOR_TYPE); + res = wps_ap_priority_compar(wps_a, wps_b); + wpabuf_free(wps_a); + wpabuf_free(wps_b); + if (res) + return res; + } + + /* + * Do not use current AP security policy as a sorting criteria during + * WPS provisioning step since the AP may get reconfigured at the + * completion of provisioning. + */ + + /* all things being equal, use signal level; if signal levels are + * identical, use quality values since some drivers may only report + * that value and leave the signal level zero */ + if (wb->level == wa->level) + return wb->qual - wa->qual; + return wb->level - wa->level; +} +#endif /* CONFIG_WPS */ + + /** * wpa_supplicant_get_scan_results - Get scan results * @wpa_s: Pointer to wpa_supplicant data @@ -597,6 +770,7 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s, { struct wpa_scan_results *scan_res; size_t i; + int (*compar)(const void *, const void *) = wpa_scan_result_compar; if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) scan_res = ieee80211_sta_get_scan_results(wpa_s); @@ -607,8 +781,16 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s, return NULL; } +#ifdef CONFIG_WPS + if (wpas_wps_in_progress(wpa_s)) { + wpa_printf(MSG_DEBUG, "WPS: Order scan results with WPS " + "provisioning rules"); + compar = wpa_scan_result_wps_compar; + } +#endif /* CONFIG_WPS */ + qsort(scan_res->res, scan_res->num, sizeof(struct wpa_scan_res *), - wpa_scan_result_compar); + compar); wpa_bss_update_start(wpa_s); for (i = 0; i < scan_res->num; i++)