2 * WPA Supplicant - Scanning
3 * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
20 #include "wpa_supplicant_i.h"
23 #include "wps_supplicant.h"
27 static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant
*wpa_s
)
29 struct wpa_ssid
*ssid
;
30 union wpa_event_data data
;
32 ssid
= wpa_supplicant_get_ssid(wpa_s
);
36 if (wpa_s
->current_ssid
== NULL
) {
37 wpa_s
->current_ssid
= ssid
;
38 if (wpa_s
->current_ssid
!= NULL
)
39 wpas_notify_network_changed(wpa_s
);
41 wpa_supplicant_initiate_eapol(wpa_s
);
42 wpa_printf(MSG_DEBUG
, "Already associated with a configured network - "
43 "generating associated event");
44 os_memset(&data
, 0, sizeof(data
));
45 wpa_supplicant_event(wpa_s
, EVENT_ASSOC
, &data
);
50 static int wpas_wps_in_use(struct wpa_config
*conf
,
51 enum wps_request_type
*req_type
)
53 struct wpa_ssid
*ssid
;
56 for (ssid
= conf
->ssid
; ssid
; ssid
= ssid
->next
) {
57 if (!(ssid
->key_mgmt
& WPA_KEY_MGMT_WPS
))
61 *req_type
= wpas_wps_get_req_type(ssid
);
62 if (!ssid
->eap
.phase1
)
65 if (os_strstr(ssid
->eap
.phase1
, "pbc=1"))
71 #endif /* CONFIG_WPS */
74 int wpa_supplicant_enabled_networks(struct wpa_config
*conf
)
76 struct wpa_ssid
*ssid
= conf
->ssid
;
86 static void wpa_supplicant_assoc_try(struct wpa_supplicant
*wpa_s
,
87 struct wpa_ssid
*ssid
)
95 /* ap_scan=2 mode - try to associate with each SSID. */
97 wpa_printf(MSG_DEBUG
, "wpa_supplicant_scan: Reached "
98 "end of scan list - go back to beginning");
99 wpa_s
->prev_scan_ssid
= WILDCARD_SSID_SCAN
;
100 wpa_supplicant_req_scan(wpa_s
, 0, 0);
104 /* Continue from the next SSID on the next attempt. */
105 wpa_s
->prev_scan_ssid
= ssid
;
107 /* Start from the beginning of the SSID list. */
108 wpa_s
->prev_scan_ssid
= WILDCARD_SSID_SCAN
;
110 wpa_supplicant_associate(wpa_s
, NULL
, ssid
);
114 static int int_array_len(const int *a
)
117 for (i
= 0; a
&& a
[i
]; i
++)
123 static void int_array_concat(int **res
, const int *a
)
128 reslen
= int_array_len(*res
);
129 alen
= int_array_len(a
);
131 n
= os_realloc(*res
, (reslen
+ alen
+ 1) * sizeof(int));
137 for (i
= 0; i
<= alen
; i
++)
138 n
[reslen
+ i
] = a
[i
];
143 static int freq_cmp(const void *a
, const void *b
)
156 static void int_array_sort_unique(int *a
)
164 alen
= int_array_len(a
);
165 qsort(a
, alen
, sizeof(int), freq_cmp
);
169 while (a
[i
] && a
[j
]) {
182 int wpa_supplicant_trigger_scan(struct wpa_supplicant
*wpa_s
,
183 struct wpa_driver_scan_params
*params
)
187 wpa_supplicant_notify_scanning(wpa_s
, 1);
189 if (wpa_s
->drv_flags
& WPA_DRIVER_FLAGS_USER_SPACE_MLME
)
190 ret
= ieee80211_sta_req_scan(wpa_s
, params
);
192 ret
= wpa_drv_scan(wpa_s
, params
);
195 wpa_supplicant_notify_scanning(wpa_s
, 0);
196 wpas_notify_scan_done(wpa_s
, 0);
204 static void wpa_supplicant_scan(void *eloop_ctx
, void *timeout_ctx
)
206 struct wpa_supplicant
*wpa_s
= eloop_ctx
;
207 struct wpa_ssid
*ssid
;
208 int scan_req
= 0, ret
;
209 struct wpabuf
*wps_ie
= NULL
;
212 enum wps_request_type req_type
= WPS_REQ_ENROLLEE_INFO
;
213 #endif /* CONFIG_WPS */
214 struct wpa_driver_scan_params params
;
217 if (wpa_s
->disconnected
&& !wpa_s
->scan_req
) {
218 wpa_supplicant_set_state(wpa_s
, WPA_DISCONNECTED
);
222 if (!wpa_supplicant_enabled_networks(wpa_s
->conf
) &&
224 wpa_printf(MSG_DEBUG
, "No enabled networks - do not scan");
225 wpa_supplicant_set_state(wpa_s
, WPA_INACTIVE
);
229 if (wpa_s
->conf
->ap_scan
!= 0 &&
230 (wpa_s
->drv_flags
& WPA_DRIVER_FLAGS_WIRED
)) {
231 wpa_printf(MSG_DEBUG
, "Using wired authentication - "
232 "overriding ap_scan configuration");
233 wpa_s
->conf
->ap_scan
= 0;
234 wpas_notify_ap_scan_changed(wpa_s
);
237 if (wpa_s
->conf
->ap_scan
== 0) {
238 wpa_supplicant_gen_assoc_event(wpa_s
);
242 if ((wpa_s
->drv_flags
& WPA_DRIVER_FLAGS_USER_SPACE_MLME
) ||
243 wpa_s
->conf
->ap_scan
== 2)
246 max_ssids
= wpa_s
->max_scan_ssids
;
247 if (max_ssids
> WPAS_MAX_SCAN_SSIDS
)
248 max_ssids
= WPAS_MAX_SCAN_SSIDS
;
252 wps
= wpas_wps_in_use(wpa_s
->conf
, &req_type
);
253 #endif /* CONFIG_WPS */
255 if (wpa_s
->scan_res_tried
== 0 && wpa_s
->conf
->ap_scan
== 1 &&
256 !(wpa_s
->drv_flags
& WPA_DRIVER_FLAGS_USER_SPACE_MLME
) &&
258 wpa_s
->scan_res_tried
++;
259 wpa_printf(MSG_DEBUG
, "Trying to get current scan results "
260 "first without requesting a new scan to speed up "
261 "initial association");
262 wpa_supplicant_event(wpa_s
, EVENT_SCAN_RESULTS
, NULL
);
266 scan_req
= wpa_s
->scan_req
;
269 os_memset(¶ms
, 0, sizeof(params
));
271 if (wpa_s
->wpa_state
== WPA_DISCONNECTED
||
272 wpa_s
->wpa_state
== WPA_INACTIVE
)
273 wpa_supplicant_set_state(wpa_s
, WPA_SCANNING
);
275 /* Find the starting point from which to continue scanning */
276 ssid
= wpa_s
->conf
->ssid
;
277 if (wpa_s
->prev_scan_ssid
!= WILDCARD_SSID_SCAN
) {
279 if (ssid
== wpa_s
->prev_scan_ssid
) {
287 if (scan_req
!= 2 && wpa_s
->conf
->ap_scan
== 2) {
288 wpa_supplicant_assoc_try(wpa_s
, ssid
);
290 } else if (wpa_s
->conf
->ap_scan
== 2) {
292 * User-initiated scan request in ap_scan == 2; scan with
297 struct wpa_ssid
*start
= ssid
, *tssid
;
299 if (ssid
== NULL
&& max_ssids
> 1)
300 ssid
= wpa_s
->conf
->ssid
;
302 if (!ssid
->disabled
&& ssid
->scan_ssid
) {
303 wpa_hexdump_ascii(MSG_DEBUG
, "Scan SSID",
304 ssid
->ssid
, ssid
->ssid_len
);
305 params
.ssids
[params
.num_ssids
].ssid
=
307 params
.ssids
[params
.num_ssids
].ssid_len
=
310 if (params
.num_ssids
+ 1 >= max_ssids
)
316 if (ssid
== NULL
&& max_ssids
> 1 &&
317 start
!= wpa_s
->conf
->ssid
)
318 ssid
= wpa_s
->conf
->ssid
;
321 for (tssid
= wpa_s
->conf
->ssid
; tssid
; tssid
= tssid
->next
) {
324 if ((params
.freqs
|| !freqs_set
) && tssid
->scan_freq
) {
325 int_array_concat(¶ms
.freqs
,
328 os_free(params
.freqs
);
333 int_array_sort_unique(params
.freqs
);
337 wpa_s
->prev_scan_ssid
= ssid
;
339 wpa_printf(MSG_DEBUG
, "Include wildcard SSID in the "
343 wpa_printf(MSG_DEBUG
, "Starting AP scan for specific SSID(s)");
345 wpa_s
->prev_scan_ssid
= WILDCARD_SSID_SCAN
;
347 wpa_printf(MSG_DEBUG
, "Starting AP scan for wildcard SSID");
352 wps_ie
= wps_build_probe_req_ie(wps
== 2, &wpa_s
->wps
->dev
,
353 wpa_s
->wps
->uuid
, req_type
);
355 params
.extra_ies
= wpabuf_head(wps_ie
);
356 params
.extra_ies_len
= wpabuf_len(wps_ie
);
359 #endif /* CONFIG_WPS */
361 ret
= wpa_supplicant_trigger_scan(wpa_s
, ¶ms
);
364 os_free(params
.freqs
);
367 wpa_printf(MSG_WARNING
, "Failed to initiate AP scan.");
368 wpa_supplicant_req_scan(wpa_s
, 10, 0);
375 * wpa_supplicant_req_scan - Schedule a scan for neighboring access points
376 * @wpa_s: Pointer to wpa_supplicant data
377 * @sec: Number of seconds after which to scan
378 * @usec: Number of microseconds after which to scan
380 * This function is used to schedule a scan for neighboring access points after
381 * the specified time.
383 void wpa_supplicant_req_scan(struct wpa_supplicant
*wpa_s
, int sec
, int usec
)
385 /* If there's at least one network that should be specifically scanned
386 * then don't cancel the scan and reschedule. Some drivers do
387 * background scanning which generates frequent scan results, and that
388 * causes the specific SSID scan to get continually pushed back and
389 * never happen, which causes hidden APs to never get probe-scanned.
391 if (eloop_is_timeout_registered(wpa_supplicant_scan
, wpa_s
, NULL
) &&
392 wpa_s
->conf
->ap_scan
== 1) {
393 struct wpa_ssid
*ssid
= wpa_s
->conf
->ssid
;
396 if (!ssid
->disabled
&& ssid
->scan_ssid
)
401 wpa_msg(wpa_s
, MSG_DEBUG
, "Not rescheduling scan to "
402 "ensure that specific SSID scans occur");
407 wpa_msg(wpa_s
, MSG_DEBUG
, "Setting scan request: %d sec %d usec",
409 eloop_cancel_timeout(wpa_supplicant_scan
, wpa_s
, NULL
);
410 eloop_register_timeout(sec
, usec
, wpa_supplicant_scan
, wpa_s
, NULL
);
415 * wpa_supplicant_cancel_scan - Cancel a scheduled scan request
416 * @wpa_s: Pointer to wpa_supplicant data
418 * This function is used to cancel a scan request scheduled with
419 * wpa_supplicant_req_scan().
421 void wpa_supplicant_cancel_scan(struct wpa_supplicant
*wpa_s
)
423 wpa_msg(wpa_s
, MSG_DEBUG
, "Cancelling scan request");
424 eloop_cancel_timeout(wpa_supplicant_scan
, wpa_s
, NULL
);
428 void wpa_supplicant_notify_scanning(struct wpa_supplicant
*wpa_s
,
431 if (wpa_s
->scanning
!= scanning
) {
432 wpa_s
->scanning
= scanning
;
433 wpas_notify_scanning(wpa_s
);