X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=wpa_supplicant%2Fscan.c;h=1f53e23afbcbd5b0267489a8dc5efee9a4de718e;hb=d3a9822542166e7adec16e24622486ba90359ef5;hp=afc341189fe96d6d3b5cdab74f8677a8c8ef0b84;hpb=f90c86d4a3b73d1a4db69f2e97009eab3ee2d28e;p=wpasupplicant diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index afc3411..1f53e23 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -18,6 +18,7 @@ #include "eloop.h" #include "config.h" #include "wpa_supplicant_i.h" +#include "driver_i.h" #include "mlme.h" #include "wps_supplicant.h" @@ -65,41 +66,139 @@ static int wpas_wps_in_use(struct wpa_config *conf, } #endif /* CONFIG_WPS */ + +static int wpa_supplicant_enabled_networks(struct wpa_config *conf) +{ + struct wpa_ssid *ssid = conf->ssid; + while (ssid) { + if (!ssid->disabled) + return 1; + ssid = ssid->next; + } + return 0; +} + + +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_printf(MSG_DEBUG, "wpa_supplicant_scan: 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); +} + + +static int int_array_len(const int *a) +{ + int i; + for (i = 0; a && a[i]; i++) + ; + return i; +} + + +static void int_array_concat(int **res, const int *a) +{ + int reslen, alen, i; + int *n; + + reslen = int_array_len(*res); + alen = int_array_len(a); + + n = os_realloc(*res, (reslen + alen + 1) * sizeof(int)); + if (n == NULL) { + os_free(*res); + *res = NULL; + } + for (i = 0; i <= alen; i++) + n[reslen + i] = a[i]; + *res = n; +} + + +static int freq_cmp(const void *a, const void *b) +{ + int _a = *(int *) a; + int _b = *(int *) b; + + if (_a == 0) + return 1; + if (_b == 0) + return -1; + return _a - _b; +} + + +static void int_array_sort_unique(int *a) +{ + int alen; + int i, j; + + if (a == NULL) + return; + + alen = int_array_len(a); + qsort(a, alen, sizeof(int), freq_cmp); + + i = 0; + j = 1; + while (a[i] && a[j]) { + if (a[i] == a[j]) { + j++; + continue; + } + a[++i] = a[j++]; + } + if (a[i]) + i++; + a[i] = 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; + 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 */ + struct wpa_driver_scan_params params; + size_t max_ssids; if (wpa_s->disconnected && !wpa_s->scan_req) return; - enabled = 0; - ssid = wpa_s->conf->ssid; - while (ssid) { - if (!ssid->disabled) { - enabled++; - break; - } - ssid = ssid->next; - } - if (!enabled && !wpa_s->scan_req) { + 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_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)) { wpa_printf(MSG_DEBUG, "Using wired authentication - " "overriding ap_scan configuration"); wpa_s->conf->ap_scan = 0; @@ -110,12 +209,42 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) 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 */ + + 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)); + 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 != BROADCAST_SSID_SCAN) { + if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) { while (ssid) { if (ssid == wpa_s->prev_scan_ssid) { ssid = ssid->next; @@ -124,58 +253,68 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) 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) { + wpa_supplicant_assoc_try(wpa_s, ssid); + return; + } else if (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. + * User-initiated scan request in ap_scan == 2; scan with + * wildcard SSID. */ - 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; + ssid = NULL; + } else { + struct wpa_ssid *start = ssid; + 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; } - 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; + + for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { + if (ssid->disabled) + continue; + if ((params.freqs || !freqs_set) && ssid->scan_freq) { + int_array_concat(¶ms.freqs, + ssid->scan_freq); + } else { + os_free(params.freqs); + params.freqs = NULL; + } + freqs_set = 1; } - wpa_supplicant_associate(wpa_s, NULL, ssid); - return; + int_array_sort_unique(params.freqs); } - 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; - -#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; + if (max_ssids > 1) { + wpa_printf(MSG_DEBUG, "Include wildcard SSID in the " + "scan request"); + params.num_ssids++; + } + wpa_printf(MSG_DEBUG, "Starting AP scan for specific SSID(s)"); + } else { + wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; + params.num_ssids++; + wpa_printf(MSG_DEBUG, "Starting AP scan for wildcard SSID"); } #ifdef CONFIG_WPS @@ -183,28 +322,31 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) 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); + params.extra_ies = wpabuf_head(wps_ie); + params.extra_ies_len = wpabuf_len(wps_ie); } } #endif /* CONFIG_WPS */ - 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); + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) { + ieee80211_sta_set_probe_req_ie(wpa_s, params.extra_ies, + params.extra_ies_len); + ret = ieee80211_sta_req_scan(wpa_s, params.ssids[0].ssid, + params.ssids[0].ssid_len); } 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); + wpa_drv_set_probe_req_ie(wpa_s, params.extra_ies, + params.extra_ies_len); + ret = wpa_drv_scan(wpa_s, ¶ms); } wpabuf_free(wps_ie); + os_free(params.freqs); if (ret) { wpa_printf(MSG_WARNING, "Failed to initiate AP scan."); wpa_supplicant_req_scan(wpa_s, 10, 0); - } + } else + wpa_s->scan_runs++; }