X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=wpa_supplicant%2Fscan.c;h=50e81e3b15c0f2ea95ed46e32deeda26c6734e7b;hb=HEAD;hp=876710978a40bf309dab007f2abcf788f76884fc;hpb=2064c2f98515016c376f3b69bfe161c85639e764;p=wpasupplicant diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index 8767109..50e81e3 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -18,8 +18,10 @@ #include "eloop.h" #include "config.h" #include "wpa_supplicant_i.h" +#include "driver_i.h" #include "mlme.h" -#include "uuid.h" +#include "wps_supplicant.h" +#include "ctrl_iface_dbus.h" static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s) @@ -41,38 +43,165 @@ static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s) } -static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) +#ifdef CONFIG_WPS +static int wpas_wps_in_use(struct wpa_config *conf, + enum wps_request_type *req_type) { - 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 wps = 0; - if (wpa_s->disconnected && !wpa_s->scan_req) - return; + for (ssid = conf->ssid; ssid; ssid = ssid->next) { + if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS)) + continue; - enabled = 0; - ssid = wpa_s->conf->ssid; + wps = 1; + *req_type = wpas_wps_get_req_type(ssid); + if (!ssid->eap.phase1) + continue; + + if (os_strstr(ssid->eap.phase1, "pbc=1")) + return 2; + } + + return wps; +} +#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) { - enabled++; + if (!ssid->disabled) break; - } ssid = ssid->next; } - if (!enabled && !wpa_s->scan_req) { + + /* 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 scan_req = 0, ret; + struct wpabuf *wps_ie = NULL; + 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; + + 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 && os_strcmp(wpa_s->driver->name, "wired") == 0) { - wpa_printf(MSG_DEBUG, "Using wired driver - overriding " - "ap_scan configuration"); + (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; } @@ -81,12 +210,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; @@ -95,70 +254,103 @@ 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; + 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"); + } - if (wpa_s->scan_res_tried == 0 && wpa_s->conf->ap_scan == 1 && - !wpa_s->use_client_mlme) { - 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) { + 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); + wpa_supplicant_notify_scanning(wpa_s, 1); + + 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_notify_scanning(wpa_s, 0); wpa_supplicant_req_scan(wpa_s, 10, 0); - } + } else + wpa_s->scan_runs++; } @@ -214,3 +406,14 @@ void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s) wpa_msg(wpa_s, MSG_DEBUG, "Cancelling scan request"); eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); } + + +void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s, + int scanning) +{ + if (wpa_s->scanning != scanning) { + wpa_s->scanning = scanning; + wpa_supplicant_dbus_notify_scanning(wpa_s); + } +} +