]>
Commit | Line | Data |
---|---|---|
6fc6879b JM |
1 | /* |
2 | * WPA Supplicant - Scanning | |
3 | * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi> | |
4 | * | |
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. | |
8 | * | |
9 | * Alternatively, this software may be distributed under the terms of BSD | |
10 | * license. | |
11 | * | |
12 | * See README and COPYING for more details. | |
13 | */ | |
14 | ||
15 | #include "includes.h" | |
16 | ||
17 | #include "common.h" | |
18 | #include "eloop.h" | |
19 | #include "config.h" | |
20 | #include "wpa_supplicant_i.h" | |
21 | #include "mlme.h" | |
b01c18a8 | 22 | #include "wps_supplicant.h" |
6fc6879b JM |
23 | |
24 | ||
25 | static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s) | |
26 | { | |
27 | struct wpa_ssid *ssid; | |
28 | union wpa_event_data data; | |
29 | ||
30 | ssid = wpa_supplicant_get_ssid(wpa_s); | |
31 | if (ssid == NULL) | |
32 | return; | |
33 | ||
34 | if (wpa_s->current_ssid == NULL) | |
35 | wpa_s->current_ssid = ssid; | |
36 | wpa_supplicant_initiate_eapol(wpa_s); | |
37 | wpa_printf(MSG_DEBUG, "Already associated with a configured network - " | |
38 | "generating associated event"); | |
39 | os_memset(&data, 0, sizeof(data)); | |
40 | wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data); | |
41 | } | |
42 | ||
43 | ||
ad08c363 | 44 | #ifdef CONFIG_WPS |
f90c86d4 JM |
45 | static int wpas_wps_in_use(struct wpa_config *conf, |
46 | enum wps_request_type *req_type) | |
ad08c363 JM |
47 | { |
48 | struct wpa_ssid *ssid; | |
49 | int wps = 0; | |
ad08c363 JM |
50 | |
51 | for (ssid = conf->ssid; ssid; ssid = ssid->next) { | |
52 | if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS)) | |
53 | continue; | |
54 | ||
55 | wps = 1; | |
b01c18a8 | 56 | *req_type = wpas_wps_get_req_type(ssid); |
ad08c363 JM |
57 | if (!ssid->eap.phase1) |
58 | continue; | |
59 | ||
ad08c363 JM |
60 | if (os_strstr(ssid->eap.phase1, "pbc=1")) |
61 | return 2; | |
62 | } | |
63 | ||
64 | return wps; | |
65 | } | |
66 | #endif /* CONFIG_WPS */ | |
67 | ||
6fc6879b JM |
68 | static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) |
69 | { | |
70 | struct wpa_supplicant *wpa_s = eloop_ctx; | |
71 | struct wpa_ssid *ssid; | |
72 | int enabled, scan_req = 0, ret; | |
ad08c363 | 73 | struct wpabuf *wps_ie = NULL; |
6fc6879b JM |
74 | const u8 *extra_ie = NULL; |
75 | size_t extra_ie_len = 0; | |
ad08c363 | 76 | int wps = 0; |
b01c18a8 | 77 | #ifdef CONFIG_WPS |
f90c86d4 | 78 | enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO; |
b01c18a8 | 79 | #endif /* CONFIG_WPS */ |
6fc6879b JM |
80 | |
81 | if (wpa_s->disconnected && !wpa_s->scan_req) | |
82 | return; | |
83 | ||
84 | enabled = 0; | |
85 | ssid = wpa_s->conf->ssid; | |
86 | while (ssid) { | |
87 | if (!ssid->disabled) { | |
88 | enabled++; | |
89 | break; | |
90 | } | |
91 | ssid = ssid->next; | |
92 | } | |
93 | if (!enabled && !wpa_s->scan_req) { | |
94 | wpa_printf(MSG_DEBUG, "No enabled networks - do not scan"); | |
95 | wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); | |
96 | return; | |
97 | } | |
98 | scan_req = wpa_s->scan_req; | |
99 | wpa_s->scan_req = 0; | |
100 | ||
101 | if (wpa_s->conf->ap_scan != 0 && | |
e519314e JW |
102 | wpa_s->driver && IS_WIRED(wpa_s->driver)) { |
103 | wpa_printf(MSG_DEBUG, "Using wired authentication - " | |
104 | "overriding ap_scan configuration"); | |
6fc6879b JM |
105 | wpa_s->conf->ap_scan = 0; |
106 | } | |
107 | ||
108 | if (wpa_s->conf->ap_scan == 0) { | |
109 | wpa_supplicant_gen_assoc_event(wpa_s); | |
110 | return; | |
111 | } | |
112 | ||
113 | if (wpa_s->wpa_state == WPA_DISCONNECTED || | |
114 | wpa_s->wpa_state == WPA_INACTIVE) | |
115 | wpa_supplicant_set_state(wpa_s, WPA_SCANNING); | |
116 | ||
117 | ssid = wpa_s->conf->ssid; | |
118 | if (wpa_s->prev_scan_ssid != BROADCAST_SSID_SCAN) { | |
119 | while (ssid) { | |
120 | if (ssid == wpa_s->prev_scan_ssid) { | |
121 | ssid = ssid->next; | |
122 | break; | |
123 | } | |
124 | ssid = ssid->next; | |
125 | } | |
126 | } | |
127 | while (ssid) { | |
128 | if (!ssid->disabled && | |
129 | (ssid->scan_ssid || wpa_s->conf->ap_scan == 2)) | |
130 | break; | |
131 | ssid = ssid->next; | |
132 | } | |
133 | ||
134 | if (scan_req != 2 && wpa_s->conf->ap_scan == 2) { | |
135 | /* | |
136 | * ap_scan=2 mode - try to associate with each SSID instead of | |
137 | * scanning for each scan_ssid=1 network. | |
138 | */ | |
139 | if (ssid == NULL) { | |
140 | wpa_printf(MSG_DEBUG, "wpa_supplicant_scan: Reached " | |
141 | "end of scan list - go back to beginning"); | |
142 | wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN; | |
143 | wpa_supplicant_req_scan(wpa_s, 0, 0); | |
144 | return; | |
145 | } | |
146 | if (ssid->next) { | |
147 | /* Continue from the next SSID on the next attempt. */ | |
148 | wpa_s->prev_scan_ssid = ssid; | |
149 | } else { | |
150 | /* Start from the beginning of the SSID list. */ | |
151 | wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN; | |
152 | } | |
153 | wpa_supplicant_associate(wpa_s, NULL, ssid); | |
154 | return; | |
155 | } | |
156 | ||
157 | wpa_printf(MSG_DEBUG, "Starting AP scan (%s SSID)", | |
158 | ssid ? "specific": "broadcast"); | |
159 | if (ssid) { | |
160 | wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID", | |
161 | ssid->ssid, ssid->ssid_len); | |
162 | wpa_s->prev_scan_ssid = ssid; | |
163 | } else | |
164 | wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN; | |
165 | ||
ad08c363 | 166 | #ifdef CONFIG_WPS |
b01c18a8 | 167 | wps = wpas_wps_in_use(wpa_s->conf, &req_type); |
ad08c363 JM |
168 | #endif /* CONFIG_WPS */ |
169 | ||
6fc6879b | 170 | if (wpa_s->scan_res_tried == 0 && wpa_s->conf->ap_scan == 1 && |
ad08c363 | 171 | !wpa_s->use_client_mlme && wps != 2) { |
6fc6879b | 172 | wpa_s->scan_res_tried++; |
2064c2f9 | 173 | wpa_s->scan_req = scan_req; |
6fc6879b JM |
174 | wpa_printf(MSG_DEBUG, "Trying to get current scan results " |
175 | "first without requesting a new scan to speed up " | |
176 | "initial association"); | |
177 | wpa_supplicant_event(wpa_s, EVENT_SCAN_RESULTS, NULL); | |
178 | return; | |
179 | } | |
180 | ||
ad08c363 JM |
181 | #ifdef CONFIG_WPS |
182 | if (wps) { | |
c0d041d9 | 183 | wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev, |
79da74a2 | 184 | wpa_s->wps->uuid, req_type); |
ad08c363 JM |
185 | if (wps_ie) { |
186 | extra_ie = wpabuf_head(wps_ie); | |
187 | extra_ie_len = wpabuf_len(wps_ie); | |
188 | } | |
189 | } | |
190 | #endif /* CONFIG_WPS */ | |
191 | ||
6fc6879b JM |
192 | if (wpa_s->use_client_mlme) { |
193 | ieee80211_sta_set_probe_req_ie(wpa_s, extra_ie, extra_ie_len); | |
194 | ret = ieee80211_sta_req_scan(wpa_s, ssid ? ssid->ssid : NULL, | |
195 | ssid ? ssid->ssid_len : 0); | |
196 | } else { | |
197 | wpa_drv_set_probe_req_ie(wpa_s, extra_ie, extra_ie_len); | |
198 | ret = wpa_drv_scan(wpa_s, ssid ? ssid->ssid : NULL, | |
199 | ssid ? ssid->ssid_len : 0); | |
200 | } | |
201 | ||
ad08c363 JM |
202 | wpabuf_free(wps_ie); |
203 | ||
6fc6879b JM |
204 | if (ret) { |
205 | wpa_printf(MSG_WARNING, "Failed to initiate AP scan."); | |
206 | wpa_supplicant_req_scan(wpa_s, 10, 0); | |
207 | } | |
208 | } | |
209 | ||
210 | ||
211 | /** | |
212 | * wpa_supplicant_req_scan - Schedule a scan for neighboring access points | |
213 | * @wpa_s: Pointer to wpa_supplicant data | |
214 | * @sec: Number of seconds after which to scan | |
215 | * @usec: Number of microseconds after which to scan | |
216 | * | |
217 | * This function is used to schedule a scan for neighboring access points after | |
218 | * the specified time. | |
219 | */ | |
220 | void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec) | |
221 | { | |
7e148849 DW |
222 | /* If there's at least one network that should be specifically scanned |
223 | * then don't cancel the scan and reschedule. Some drivers do | |
224 | * background scanning which generates frequent scan results, and that | |
225 | * causes the specific SSID scan to get continually pushed back and | |
226 | * never happen, which causes hidden APs to never get probe-scanned. | |
227 | */ | |
228 | if (eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL) && | |
229 | wpa_s->conf->ap_scan == 1) { | |
230 | struct wpa_ssid *ssid = wpa_s->conf->ssid; | |
231 | ||
232 | while (ssid) { | |
233 | if (!ssid->disabled && ssid->scan_ssid) | |
234 | break; | |
235 | ssid = ssid->next; | |
236 | } | |
237 | if (ssid) { | |
238 | wpa_msg(wpa_s, MSG_DEBUG, "Not rescheduling scan to " | |
239 | "ensure that specific SSID scans occur"); | |
240 | return; | |
241 | } | |
242 | } | |
243 | ||
6fc6879b JM |
244 | wpa_msg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec", |
245 | sec, usec); | |
246 | eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); | |
247 | eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL); | |
248 | } | |
249 | ||
250 | ||
251 | /** | |
252 | * wpa_supplicant_cancel_scan - Cancel a scheduled scan request | |
253 | * @wpa_s: Pointer to wpa_supplicant data | |
254 | * | |
255 | * This function is used to cancel a scan request scheduled with | |
256 | * wpa_supplicant_req_scan(). | |
257 | */ | |
258 | void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s) | |
259 | { | |
260 | wpa_msg(wpa_s, MSG_DEBUG, "Cancelling scan request"); | |
261 | eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); | |
262 | } |