]>
Commit | Line | Data |
---|---|---|
c2a04078 JM |
1 | /* |
2 | * wpa_supplicant - SME | |
71024cb2 | 3 | * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi> |
c2a04078 JM |
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" | |
90973fb2 | 18 | #include "common/ieee802_11_defs.h" |
d9a27b04 | 19 | #include "common/ieee802_11_common.h" |
c2a04078 | 20 | #include "eapol_supp/eapol_supp_sm.h" |
90973fb2 | 21 | #include "common/wpa_common.h" |
3acb5005 JM |
22 | #include "rsn_supp/wpa.h" |
23 | #include "rsn_supp/pmksa_cache.h" | |
c2a04078 JM |
24 | #include "config.h" |
25 | #include "wpa_supplicant_i.h" | |
2d5b792d | 26 | #include "driver_i.h" |
c2a04078 JM |
27 | #include "wpas_glue.h" |
28 | #include "wps_supplicant.h" | |
5f3a6aa0 | 29 | #include "p2p_supplicant.h" |
8bac466b | 30 | #include "notify.h" |
76d11d3f | 31 | #include "blacklist.h" |
6fa81a3b | 32 | #include "bss.h" |
9ba9fa07 | 33 | #include "scan.h" |
c2a04078 JM |
34 | #include "sme.h" |
35 | ||
7e6646c7 JM |
36 | static int sme_another_bss_in_ess(struct wpa_supplicant *wpa_s) |
37 | { | |
38 | struct wpa_bss *bss, *cbss; | |
39 | ||
40 | cbss = wpa_s->current_bss; | |
41 | ||
42 | dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { | |
43 | if (bss == cbss) | |
44 | continue; | |
45 | if (bss->ssid_len == cbss->ssid_len && | |
46 | os_memcmp(bss->ssid, cbss->ssid, bss->ssid_len) == 0 && | |
47 | wpa_blacklist_get(wpa_s, bss->bssid) == NULL) | |
48 | return 1; | |
49 | } | |
50 | ||
51 | return 0; | |
52 | } | |
53 | ||
54 | ||
55 | static void sme_connection_failed(struct wpa_supplicant *wpa_s, | |
56 | const u8 *bssid) | |
57 | { | |
58 | int timeout; | |
59 | int count; | |
60 | ||
61 | /* | |
62 | * Add the failed BSSID into the blacklist and speed up next scan | |
63 | * attempt if there could be other APs that could accept association. | |
64 | * The current blacklist count indicates how many times we have tried | |
65 | * connecting to this AP and multiple attempts mean that other APs are | |
66 | * either not available or has already been tried, so that we can start | |
67 | * increasing the delay here to avoid constant scanning. | |
68 | */ | |
69 | count = wpa_blacklist_add(wpa_s, bssid); | |
70 | if (count == 1 && wpa_s->current_bss) { | |
71 | /* | |
72 | * This BSS was not in the blacklist before. If there is | |
73 | * another BSS available for the same ESS, we should try that | |
74 | * next. Otherwise, we may as well try this one once more | |
75 | * before allowing other, likely worse, ESSes to be considered. | |
76 | */ | |
77 | if (sme_another_bss_in_ess(wpa_s)) { | |
78 | wpa_printf(MSG_DEBUG, "SME: Another BSS in this ESS " | |
79 | "has been seen; try it next"); | |
80 | wpa_blacklist_add(wpa_s, bssid); | |
81 | } | |
82 | } | |
83 | ||
84 | switch (count) { | |
85 | case 1: | |
86 | timeout = 100; | |
87 | break; | |
88 | case 2: | |
89 | timeout = 500; | |
90 | break; | |
91 | case 3: | |
92 | timeout = 1000; | |
93 | break; | |
94 | default: | |
95 | timeout = 5000; | |
96 | } | |
97 | ||
98 | /* | |
99 | * TODO: if more than one possible AP is available in scan results, | |
100 | * could try the other ones before requesting a new scan. | |
101 | */ | |
102 | wpa_supplicant_req_scan(wpa_s, timeout / 1000, | |
103 | 1000 * (timeout % 1000)); | |
104 | } | |
105 | ||
106 | ||
c2a04078 | 107 | void sme_authenticate(struct wpa_supplicant *wpa_s, |
6fa81a3b | 108 | struct wpa_bss *bss, struct wpa_ssid *ssid) |
c2a04078 JM |
109 | { |
110 | struct wpa_driver_auth_params params; | |
8bac466b | 111 | struct wpa_ssid *old_ssid; |
fdbe50ed | 112 | #ifdef CONFIG_IEEE80211R |
c2a04078 | 113 | const u8 *ie; |
fdbe50ed | 114 | #endif /* CONFIG_IEEE80211R */ |
c2a04078 JM |
115 | #ifdef CONFIG_IEEE80211R |
116 | const u8 *md = NULL; | |
117 | #endif /* CONFIG_IEEE80211R */ | |
8bac466b | 118 | int i, bssid_changed; |
c2a04078 JM |
119 | |
120 | if (bss == NULL) { | |
121 | wpa_printf(MSG_ERROR, "SME: No scan result available for the " | |
122 | "network"); | |
123 | return; | |
124 | } | |
125 | ||
8f770587 JM |
126 | wpa_s->current_bss = bss; |
127 | ||
c2a04078 JM |
128 | os_memset(¶ms, 0, sizeof(params)); |
129 | wpa_s->reassociate = 0; | |
130 | ||
131 | params.freq = bss->freq; | |
132 | params.bssid = bss->bssid; | |
6fa81a3b JM |
133 | params.ssid = bss->ssid; |
134 | params.ssid_len = bss->ssid_len; | |
c2a04078 | 135 | |
62fa124c JM |
136 | if (wpa_s->sme.ssid_len != params.ssid_len || |
137 | os_memcmp(wpa_s->sme.ssid, params.ssid, params.ssid_len) != 0) | |
138 | wpa_s->sme.prev_bssid_set = 0; | |
139 | ||
c2a04078 JM |
140 | wpa_s->sme.freq = params.freq; |
141 | os_memcpy(wpa_s->sme.ssid, params.ssid, params.ssid_len); | |
142 | wpa_s->sme.ssid_len = params.ssid_len; | |
143 | ||
abd9fafa | 144 | params.auth_alg = WPA_AUTH_ALG_OPEN; |
c2a04078 JM |
145 | #ifdef IEEE8021X_EAPOL |
146 | if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) { | |
147 | if (ssid->leap) { | |
148 | if (ssid->non_leap == 0) | |
abd9fafa | 149 | params.auth_alg = WPA_AUTH_ALG_LEAP; |
c2a04078 | 150 | else |
abd9fafa | 151 | params.auth_alg |= WPA_AUTH_ALG_LEAP; |
c2a04078 JM |
152 | } |
153 | } | |
154 | #endif /* IEEE8021X_EAPOL */ | |
155 | wpa_printf(MSG_DEBUG, "Automatic auth_alg selection: 0x%x", | |
156 | params.auth_alg); | |
157 | if (ssid->auth_alg) { | |
abd9fafa | 158 | params.auth_alg = ssid->auth_alg; |
c2a04078 JM |
159 | wpa_printf(MSG_DEBUG, "Overriding auth_alg selection: 0x%x", |
160 | params.auth_alg); | |
161 | } | |
162 | ||
a0b2f99b JM |
163 | for (i = 0; i < NUM_WEP_KEYS; i++) { |
164 | if (ssid->wep_key_len[i]) | |
165 | params.wep_key[i] = ssid->wep_key[i]; | |
166 | params.wep_key_len[i] = ssid->wep_key_len[i]; | |
167 | } | |
168 | params.wep_tx_keyidx = ssid->wep_tx_keyidx; | |
169 | ||
8bac466b | 170 | bssid_changed = !is_zero_ether_addr(wpa_s->bssid); |
c2a04078 JM |
171 | os_memset(wpa_s->bssid, 0, ETH_ALEN); |
172 | os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN); | |
8bac466b JM |
173 | if (bssid_changed) |
174 | wpas_notify_bssid_changed(wpa_s); | |
c2a04078 | 175 | |
f337f0e9 JM |
176 | if ((wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) || |
177 | wpa_bss_get_ie(bss, WLAN_EID_RSN)) && | |
c2a04078 JM |
178 | (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK | |
179 | WPA_KEY_MGMT_FT_IEEE8021X | | |
180 | WPA_KEY_MGMT_FT_PSK | | |
181 | WPA_KEY_MGMT_IEEE8021X_SHA256 | | |
182 | WPA_KEY_MGMT_PSK_SHA256))) { | |
183 | int try_opportunistic; | |
184 | try_opportunistic = ssid->proactive_key_caching && | |
185 | (ssid->proto & WPA_PROTO_RSN); | |
186 | if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, | |
187 | wpa_s->current_ssid, | |
188 | try_opportunistic) == 0) | |
189 | eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1); | |
190 | wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie); | |
191 | if (wpa_supplicant_set_suites(wpa_s, bss, ssid, | |
192 | wpa_s->sme.assoc_req_ie, | |
193 | &wpa_s->sme.assoc_req_ie_len)) { | |
194 | wpa_printf(MSG_WARNING, "SME: Failed to set WPA key " | |
195 | "management and encryption suites"); | |
196 | return; | |
197 | } | |
198 | } else if (ssid->key_mgmt & | |
199 | (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X | | |
200 | WPA_KEY_MGMT_WPA_NONE | WPA_KEY_MGMT_FT_PSK | | |
201 | WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_PSK_SHA256 | | |
202 | WPA_KEY_MGMT_IEEE8021X_SHA256)) { | |
203 | wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie); | |
204 | if (wpa_supplicant_set_suites(wpa_s, NULL, ssid, | |
205 | wpa_s->sme.assoc_req_ie, | |
206 | &wpa_s->sme.assoc_req_ie_len)) { | |
207 | wpa_printf(MSG_WARNING, "SME: Failed to set WPA key " | |
208 | "management and encryption suites (no scan " | |
209 | "results)"); | |
210 | return; | |
211 | } | |
212 | #ifdef CONFIG_WPS | |
213 | } else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) { | |
214 | struct wpabuf *wps_ie; | |
215 | wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid)); | |
216 | if (wps_ie && wpabuf_len(wps_ie) <= | |
217 | sizeof(wpa_s->sme.assoc_req_ie)) { | |
218 | wpa_s->sme.assoc_req_ie_len = wpabuf_len(wps_ie); | |
219 | os_memcpy(wpa_s->sme.assoc_req_ie, wpabuf_head(wps_ie), | |
220 | wpa_s->sme.assoc_req_ie_len); | |
221 | } else | |
222 | wpa_s->sme.assoc_req_ie_len = 0; | |
223 | wpabuf_free(wps_ie); | |
224 | wpa_supplicant_set_non_wpa_policy(wpa_s, ssid); | |
225 | #endif /* CONFIG_WPS */ | |
226 | } else { | |
227 | wpa_supplicant_set_non_wpa_policy(wpa_s, ssid); | |
228 | wpa_s->sme.assoc_req_ie_len = 0; | |
229 | } | |
230 | ||
231 | #ifdef CONFIG_IEEE80211R | |
6fa81a3b | 232 | ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN); |
c2a04078 JM |
233 | if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN) |
234 | md = ie + 2; | |
e7846b68 | 235 | wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0); |
c2a04078 JM |
236 | if (md) { |
237 | /* Prepare for the next transition */ | |
76b7981d | 238 | wpa_ft_prepare_auth_request(wpa_s->wpa, ie); |
c2a04078 JM |
239 | } |
240 | ||
241 | if (md && ssid->key_mgmt & (WPA_KEY_MGMT_FT_PSK | | |
242 | WPA_KEY_MGMT_FT_IEEE8021X)) { | |
243 | if (wpa_s->sme.assoc_req_ie_len + 5 < | |
244 | sizeof(wpa_s->sme.assoc_req_ie)) { | |
245 | struct rsn_mdie *mdie; | |
246 | u8 *pos = wpa_s->sme.assoc_req_ie + | |
247 | wpa_s->sme.assoc_req_ie_len; | |
248 | *pos++ = WLAN_EID_MOBILITY_DOMAIN; | |
249 | *pos++ = sizeof(*mdie); | |
250 | mdie = (struct rsn_mdie *) pos; | |
251 | os_memcpy(mdie->mobility_domain, md, | |
252 | MOBILITY_DOMAIN_ID_LEN); | |
f4ec630d | 253 | mdie->ft_capab = md[MOBILITY_DOMAIN_ID_LEN]; |
c2a04078 JM |
254 | wpa_s->sme.assoc_req_ie_len += 5; |
255 | } | |
256 | ||
257 | if (wpa_s->sme.ft_used && | |
0d7b4409 JM |
258 | os_memcmp(md, wpa_s->sme.mobility_domain, 2) == 0 && |
259 | wpa_sm_has_ptk(wpa_s->wpa)) { | |
c2a04078 JM |
260 | wpa_printf(MSG_DEBUG, "SME: Trying to use FT " |
261 | "over-the-air"); | |
abd9fafa | 262 | params.auth_alg = WPA_AUTH_ALG_FT; |
c2a04078 JM |
263 | params.ie = wpa_s->sme.ft_ies; |
264 | params.ie_len = wpa_s->sme.ft_ies_len; | |
265 | } | |
266 | } | |
267 | #endif /* CONFIG_IEEE80211R */ | |
268 | ||
269 | #ifdef CONFIG_IEEE80211W | |
70f8cc8e | 270 | wpa_s->sme.mfp = ssid->ieee80211w; |
f337f0e9 | 271 | if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) { |
6fa81a3b | 272 | const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN); |
c2a04078 JM |
273 | struct wpa_ie_data _ie; |
274 | if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &_ie) == 0 && | |
275 | _ie.capabilities & | |
276 | (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) { | |
277 | wpa_printf(MSG_DEBUG, "WPA: Selected AP supports MFP: " | |
278 | "require MFP"); | |
279 | wpa_s->sme.mfp = MGMT_FRAME_PROTECTION_REQUIRED; | |
280 | } | |
281 | } | |
282 | #endif /* CONFIG_IEEE80211W */ | |
283 | ||
5f3a6aa0 JM |
284 | #ifdef CONFIG_P2P |
285 | if (wpa_s->global->p2p) { | |
286 | u8 *pos; | |
287 | size_t len; | |
288 | int res; | |
289 | int p2p_group; | |
290 | p2p_group = wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE; | |
291 | pos = wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len; | |
292 | len = sizeof(wpa_s->sme.assoc_req_ie) - | |
293 | wpa_s->sme.assoc_req_ie_len; | |
4c08c0bd | 294 | res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len, p2p_group); |
5f3a6aa0 JM |
295 | if (res >= 0) |
296 | wpa_s->sme.assoc_req_ie_len += res; | |
297 | } | |
298 | #endif /* CONFIG_P2P */ | |
299 | ||
c2a04078 JM |
300 | wpa_supplicant_cancel_scan(wpa_s); |
301 | ||
302 | wpa_msg(wpa_s, MSG_INFO, "Trying to authenticate with " MACSTR | |
303 | " (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid), | |
304 | wpa_ssid_txt(params.ssid, params.ssid_len), params.freq); | |
305 | ||
306 | wpa_clear_keys(wpa_s, bss->bssid); | |
307 | wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING); | |
8bac466b | 308 | old_ssid = wpa_s->current_ssid; |
c2a04078 JM |
309 | wpa_s->current_ssid = ssid; |
310 | wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid); | |
311 | wpa_supplicant_initiate_eapol(wpa_s); | |
8bac466b JM |
312 | if (old_ssid != wpa_s->current_ssid) |
313 | wpas_notify_network_changed(wpa_s); | |
c2a04078 | 314 | |
62c72d72 | 315 | wpa_s->sme.auth_alg = params.auth_alg; |
c2a04078 JM |
316 | if (wpa_drv_authenticate(wpa_s, ¶ms) < 0) { |
317 | wpa_msg(wpa_s, MSG_INFO, "Authentication request to the " | |
318 | "driver failed"); | |
6e3f7173 | 319 | wpa_supplicant_req_scan(wpa_s, 1, 0); |
c2a04078 JM |
320 | return; |
321 | } | |
322 | ||
323 | /* TODO: add timeout on authentication */ | |
324 | ||
325 | /* | |
326 | * Association will be started based on the authentication event from | |
327 | * the driver. | |
328 | */ | |
329 | } | |
330 | ||
331 | ||
332 | void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data) | |
333 | { | |
c2a04078 JM |
334 | struct wpa_ssid *ssid = wpa_s->current_ssid; |
335 | ||
336 | if (ssid == NULL) { | |
337 | wpa_printf(MSG_DEBUG, "SME: Ignore authentication event when " | |
338 | "network is not selected"); | |
339 | return; | |
340 | } | |
341 | ||
342 | if (wpa_s->wpa_state != WPA_AUTHENTICATING) { | |
343 | wpa_printf(MSG_DEBUG, "SME: Ignore authentication event when " | |
344 | "not in authenticating state"); | |
345 | return; | |
346 | } | |
347 | ||
348 | if (os_memcmp(wpa_s->pending_bssid, data->auth.peer, ETH_ALEN) != 0) { | |
349 | wpa_printf(MSG_DEBUG, "SME: Ignore authentication with " | |
350 | "unexpected peer " MACSTR, | |
351 | MAC2STR(data->auth.peer)); | |
352 | return; | |
353 | } | |
354 | ||
355 | wpa_printf(MSG_DEBUG, "SME: Authentication response: peer=" MACSTR | |
356 | " auth_type=%d status_code=%d", | |
357 | MAC2STR(data->auth.peer), data->auth.auth_type, | |
358 | data->auth.status_code); | |
359 | wpa_hexdump(MSG_MSGDUMP, "SME: Authentication response IEs", | |
360 | data->auth.ies, data->auth.ies_len); | |
361 | ||
362 | if (data->auth.status_code != WLAN_STATUS_SUCCESS) { | |
363 | wpa_printf(MSG_DEBUG, "SME: Authentication failed (status " | |
364 | "code %d)", data->auth.status_code); | |
cb1583f6 SO |
365 | |
366 | if (data->auth.status_code != | |
367 | WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG || | |
368 | wpa_s->sme.auth_alg == data->auth.auth_type || | |
7e6646c7 JM |
369 | wpa_s->current_ssid->auth_alg == WPA_AUTH_ALG_LEAP) { |
370 | sme_connection_failed(wpa_s, wpa_s->pending_bssid); | |
cb1583f6 | 371 | return; |
7e6646c7 | 372 | } |
cb1583f6 SO |
373 | |
374 | switch (data->auth.auth_type) { | |
375 | case WLAN_AUTH_OPEN: | |
376 | wpa_s->current_ssid->auth_alg = WPA_AUTH_ALG_SHARED; | |
377 | ||
378 | wpa_printf(MSG_DEBUG, "SME: Trying SHARED auth"); | |
379 | wpa_supplicant_associate(wpa_s, wpa_s->current_bss, | |
380 | wpa_s->current_ssid); | |
381 | return; | |
382 | ||
383 | case WLAN_AUTH_SHARED_KEY: | |
384 | wpa_s->current_ssid->auth_alg = WPA_AUTH_ALG_LEAP; | |
385 | ||
386 | wpa_printf(MSG_DEBUG, "SME: Trying LEAP auth"); | |
387 | wpa_supplicant_associate(wpa_s, wpa_s->current_bss, | |
388 | wpa_s->current_ssid); | |
389 | return; | |
390 | ||
391 | default: | |
392 | return; | |
393 | } | |
c2a04078 JM |
394 | } |
395 | ||
396 | #ifdef CONFIG_IEEE80211R | |
397 | if (data->auth.auth_type == WLAN_AUTH_FT) { | |
398 | union wpa_event_data edata; | |
399 | os_memset(&edata, 0, sizeof(edata)); | |
400 | edata.ft_ies.ies = data->auth.ies; | |
401 | edata.ft_ies.ies_len = data->auth.ies_len; | |
402 | os_memcpy(edata.ft_ies.target_ap, data->auth.peer, ETH_ALEN); | |
403 | wpa_supplicant_event(wpa_s, EVENT_FT_RESPONSE, &edata); | |
404 | } | |
405 | #endif /* CONFIG_IEEE80211R */ | |
406 | ||
71024cb2 JM |
407 | sme_associate(wpa_s, ssid->mode, data->auth.peer, |
408 | data->auth.auth_type); | |
409 | } | |
410 | ||
411 | ||
412 | void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, | |
413 | const u8 *bssid, u16 auth_type) | |
414 | { | |
415 | struct wpa_driver_associate_params params; | |
d9a27b04 | 416 | struct ieee802_11_elems elems; |
71024cb2 | 417 | |
c2a04078 | 418 | os_memset(¶ms, 0, sizeof(params)); |
71024cb2 | 419 | params.bssid = bssid; |
c2a04078 JM |
420 | params.ssid = wpa_s->sme.ssid; |
421 | params.ssid_len = wpa_s->sme.ssid_len; | |
422 | params.freq = wpa_s->sme.freq; | |
423 | params.wpa_ie = wpa_s->sme.assoc_req_ie_len ? | |
424 | wpa_s->sme.assoc_req_ie : NULL; | |
425 | params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len; | |
426 | #ifdef CONFIG_IEEE80211R | |
71024cb2 | 427 | if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) { |
c2a04078 JM |
428 | params.wpa_ie = wpa_s->sme.ft_ies; |
429 | params.wpa_ie_len = wpa_s->sme.ft_ies_len; | |
430 | } | |
431 | #endif /* CONFIG_IEEE80211R */ | |
71024cb2 | 432 | params.mode = mode; |
c2a04078 | 433 | params.mgmt_frame_protection = wpa_s->sme.mfp; |
62fa124c JM |
434 | if (wpa_s->sme.prev_bssid_set) |
435 | params.prev_bssid = wpa_s->sme.prev_bssid; | |
c2a04078 JM |
436 | |
437 | wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR | |
438 | " (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid), | |
439 | params.ssid ? wpa_ssid_txt(params.ssid, params.ssid_len) : "", | |
440 | params.freq); | |
441 | ||
442 | wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING); | |
443 | ||
9efc3f2a JM |
444 | if (params.wpa_ie == NULL || |
445 | ieee802_11_parse_elems(params.wpa_ie, params.wpa_ie_len, &elems, 0) | |
d9a27b04 JM |
446 | < 0) { |
447 | wpa_printf(MSG_DEBUG, "SME: Could not parse own IEs?!"); | |
448 | os_memset(&elems, 0, sizeof(elems)); | |
449 | } | |
450 | if (elems.rsn_ie) | |
451 | wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.rsn_ie - 2, | |
452 | elems.rsn_ie_len + 2); | |
453 | else if (elems.wpa_ie) | |
454 | wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.wpa_ie - 2, | |
455 | elems.wpa_ie_len + 2); | |
456 | else | |
457 | wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0); | |
6e3f4b89 JM |
458 | if (elems.p2p && |
459 | (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE)) | |
460 | params.p2p = 1; | |
d9a27b04 | 461 | |
eea2fd9e JM |
462 | if (wpa_s->parent->set_sta_uapsd) |
463 | params.uapsd = wpa_s->parent->sta_uapsd; | |
464 | else | |
465 | params.uapsd = -1; | |
466 | ||
c2a04078 JM |
467 | if (wpa_drv_associate(wpa_s, ¶ms) < 0) { |
468 | wpa_msg(wpa_s, MSG_INFO, "Association request to the driver " | |
469 | "failed"); | |
b85e7724 | 470 | wpa_supplicant_req_scan(wpa_s, 5, 0); |
c2a04078 JM |
471 | return; |
472 | } | |
473 | ||
474 | /* TODO: add timeout on association */ | |
475 | } | |
476 | ||
477 | ||
478 | int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md, | |
479 | const u8 *ies, size_t ies_len) | |
480 | { | |
481 | if (md == NULL || ies == NULL) { | |
482 | wpa_printf(MSG_DEBUG, "SME: Remove mobility domain"); | |
483 | os_free(wpa_s->sme.ft_ies); | |
484 | wpa_s->sme.ft_ies = NULL; | |
485 | wpa_s->sme.ft_ies_len = 0; | |
486 | wpa_s->sme.ft_used = 0; | |
487 | return 0; | |
488 | } | |
489 | ||
490 | os_memcpy(wpa_s->sme.mobility_domain, md, MOBILITY_DOMAIN_ID_LEN); | |
491 | wpa_hexdump(MSG_DEBUG, "SME: FT IEs", ies, ies_len); | |
492 | os_free(wpa_s->sme.ft_ies); | |
493 | wpa_s->sme.ft_ies = os_malloc(ies_len); | |
494 | if (wpa_s->sme.ft_ies == NULL) | |
495 | return -1; | |
496 | os_memcpy(wpa_s->sme.ft_ies, ies, ies_len); | |
497 | wpa_s->sme.ft_ies_len = ies_len; | |
498 | return 0; | |
499 | } | |
efa46078 JM |
500 | |
501 | ||
502 | void sme_event_assoc_reject(struct wpa_supplicant *wpa_s, | |
503 | union wpa_event_data *data) | |
504 | { | |
8bac466b JM |
505 | int bssid_changed; |
506 | ||
76d11d3f JM |
507 | wpa_printf(MSG_DEBUG, "SME: Association with " MACSTR " failed: " |
508 | "status code %d", MAC2STR(wpa_s->pending_bssid), | |
efa46078 JM |
509 | data->assoc_reject.status_code); |
510 | ||
8bac466b | 511 | bssid_changed = !is_zero_ether_addr(wpa_s->bssid); |
76d11d3f JM |
512 | |
513 | /* | |
514 | * For now, unconditionally terminate the previous authentication. In | |
515 | * theory, this should not be needed, but mac80211 gets quite confused | |
516 | * if the authentication is left pending.. Some roaming cases might | |
517 | * benefit from using the previous authentication, so this could be | |
518 | * optimized in the future. | |
519 | */ | |
520 | if (wpa_drv_deauthenticate(wpa_s, wpa_s->pending_bssid, | |
521 | WLAN_REASON_DEAUTH_LEAVING) < 0) { | |
522 | wpa_msg(wpa_s, MSG_INFO, | |
523 | "Deauth request to the driver failed"); | |
524 | } | |
62fa124c | 525 | wpa_s->sme.prev_bssid_set = 0; |
76d11d3f | 526 | |
7e6646c7 | 527 | sme_connection_failed(wpa_s, wpa_s->pending_bssid); |
76d11d3f | 528 | wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); |
efa46078 JM |
529 | os_memset(wpa_s->bssid, 0, ETH_ALEN); |
530 | os_memset(wpa_s->pending_bssid, 0, ETH_ALEN); | |
8bac466b JM |
531 | if (bssid_changed) |
532 | wpas_notify_bssid_changed(wpa_s); | |
efa46078 | 533 | } |
da1fb17c JM |
534 | |
535 | ||
536 | void sme_event_auth_timed_out(struct wpa_supplicant *wpa_s, | |
537 | union wpa_event_data *data) | |
538 | { | |
539 | wpa_printf(MSG_DEBUG, "SME: Authentication timed out"); | |
7e6646c7 | 540 | sme_connection_failed(wpa_s, wpa_s->pending_bssid); |
da1fb17c JM |
541 | } |
542 | ||
543 | ||
544 | void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s, | |
545 | union wpa_event_data *data) | |
546 | { | |
547 | wpa_printf(MSG_DEBUG, "SME: Association timed out"); | |
7e6646c7 | 548 | sme_connection_failed(wpa_s, wpa_s->pending_bssid); |
da1fb17c | 549 | wpa_supplicant_mark_disassoc(wpa_s); |
da1fb17c | 550 | } |
a84ed99e JM |
551 | |
552 | ||
553 | void sme_event_disassoc(struct wpa_supplicant *wpa_s, | |
554 | union wpa_event_data *data) | |
555 | { | |
556 | wpa_printf(MSG_DEBUG, "SME: Disassociation event received"); | |
7e26053a | 557 | if (wpa_s->sme.prev_bssid_set && |
a84ed99e JM |
558 | !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)) { |
559 | /* | |
560 | * cfg80211/mac80211 can get into somewhat confused state if | |
561 | * the AP only disassociates us and leaves us in authenticated | |
562 | * state. For now, force the state to be cleared to avoid | |
563 | * confusing errors if we try to associate with the AP again. | |
564 | */ | |
565 | wpa_printf(MSG_DEBUG, "SME: Deauthenticate to clear driver " | |
566 | "state"); | |
7e26053a | 567 | wpa_drv_deauthenticate(wpa_s, wpa_s->sme.prev_bssid, |
a84ed99e JM |
568 | WLAN_REASON_DEAUTH_LEAVING); |
569 | } | |
570 | } |