3 * Copyright (c) 2009-2010, 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.
18 #include "common/ieee802_11_defs.h"
19 #include "common/ieee802_11_common.h"
20 #include "eapol_supp/eapol_supp_sm.h"
21 #include "common/wpa_common.h"
22 #include "rsn_supp/wpa.h"
23 #include "rsn_supp/pmksa_cache.h"
25 #include "wpa_supplicant_i.h"
27 #include "wpas_glue.h"
28 #include "wps_supplicant.h"
29 #include "p2p_supplicant.h"
31 #include "blacklist.h"
36 static int sme_another_bss_in_ess(struct wpa_supplicant
*wpa_s
)
38 struct wpa_bss
*bss
, *cbss
;
40 cbss
= wpa_s
->current_bss
;
42 dl_list_for_each(bss
, &wpa_s
->bss
, struct wpa_bss
, list
) {
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
)
55 static void sme_connection_failed(struct wpa_supplicant
*wpa_s
,
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.
69 count
= wpa_blacklist_add(wpa_s
, bssid
);
70 if (count
== 1 && wpa_s
->current_bss
) {
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.
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
);
99 * TODO: if more than one possible AP is available in scan results,
100 * could try the other ones before requesting a new scan.
102 wpa_supplicant_req_scan(wpa_s
, timeout
/ 1000,
103 1000 * (timeout
% 1000));
107 void sme_authenticate(struct wpa_supplicant
*wpa_s
,
108 struct wpa_bss
*bss
, struct wpa_ssid
*ssid
)
110 struct wpa_driver_auth_params params
;
111 struct wpa_ssid
*old_ssid
;
112 #ifdef CONFIG_IEEE80211R
114 #endif /* CONFIG_IEEE80211R */
115 #ifdef CONFIG_IEEE80211R
117 #endif /* CONFIG_IEEE80211R */
118 int i
, bssid_changed
;
121 wpa_printf(MSG_ERROR
, "SME: No scan result available for the "
126 wpa_s
->current_bss
= bss
;
128 os_memset(¶ms
, 0, sizeof(params
));
129 wpa_s
->reassociate
= 0;
131 params
.freq
= bss
->freq
;
132 params
.bssid
= bss
->bssid
;
133 params
.ssid
= bss
->ssid
;
134 params
.ssid_len
= bss
->ssid_len
;
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;
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
;
144 params
.auth_alg
= WPA_AUTH_ALG_OPEN
;
145 #ifdef IEEE8021X_EAPOL
146 if (ssid
->key_mgmt
& WPA_KEY_MGMT_IEEE8021X_NO_WPA
) {
148 if (ssid
->non_leap
== 0)
149 params
.auth_alg
= WPA_AUTH_ALG_LEAP
;
151 params
.auth_alg
|= WPA_AUTH_ALG_LEAP
;
154 #endif /* IEEE8021X_EAPOL */
155 wpa_printf(MSG_DEBUG
, "Automatic auth_alg selection: 0x%x",
157 if (ssid
->auth_alg
) {
158 params
.auth_alg
= ssid
->auth_alg
;
159 wpa_printf(MSG_DEBUG
, "Overriding auth_alg selection: 0x%x",
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
];
168 params
.wep_tx_keyidx
= ssid
->wep_tx_keyidx
;
170 bssid_changed
= !is_zero_ether_addr(wpa_s
->bssid
);
171 os_memset(wpa_s
->bssid
, 0, ETH_ALEN
);
172 os_memcpy(wpa_s
->pending_bssid
, bss
->bssid
, ETH_ALEN
);
174 wpas_notify_bssid_changed(wpa_s
);
176 if ((wpa_bss_get_vendor_ie(bss
, WPA_IE_VENDOR_TYPE
) ||
177 wpa_bss_get_ie(bss
, WLAN_EID_RSN
)) &&
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
,
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");
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 "
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
);
222 wpa_s
->sme
.assoc_req_ie_len
= 0;
224 wpa_supplicant_set_non_wpa_policy(wpa_s
, ssid
);
225 #endif /* CONFIG_WPS */
227 wpa_supplicant_set_non_wpa_policy(wpa_s
, ssid
);
228 wpa_s
->sme
.assoc_req_ie_len
= 0;
231 #ifdef CONFIG_IEEE80211R
232 ie
= wpa_bss_get_ie(bss
, WLAN_EID_MOBILITY_DOMAIN
);
233 if (ie
&& ie
[1] >= MOBILITY_DOMAIN_ID_LEN
)
235 wpa_sm_set_ft_params(wpa_s
->wpa
, ie
, ie
? 2 + ie
[1] : 0);
237 /* Prepare for the next transition */
238 wpa_ft_prepare_auth_request(wpa_s
->wpa
, ie
);
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
);
253 mdie
->ft_capab
= md
[MOBILITY_DOMAIN_ID_LEN
];
254 wpa_s
->sme
.assoc_req_ie_len
+= 5;
257 if (wpa_s
->sme
.ft_used
&&
258 os_memcmp(md
, wpa_s
->sme
.mobility_domain
, 2) == 0 &&
259 wpa_sm_has_ptk(wpa_s
->wpa
)) {
260 wpa_printf(MSG_DEBUG
, "SME: Trying to use FT "
262 params
.auth_alg
= WPA_AUTH_ALG_FT
;
263 params
.ie
= wpa_s
->sme
.ft_ies
;
264 params
.ie_len
= wpa_s
->sme
.ft_ies_len
;
267 #endif /* CONFIG_IEEE80211R */
269 #ifdef CONFIG_IEEE80211W
270 wpa_s
->sme
.mfp
= ssid
->ieee80211w
;
271 if (ssid
->ieee80211w
!= NO_MGMT_FRAME_PROTECTION
) {
272 const u8
*rsn
= wpa_bss_get_ie(bss
, WLAN_EID_RSN
);
273 struct wpa_ie_data _ie
;
274 if (rsn
&& wpa_parse_wpa_ie(rsn
, 2 + rsn
[1], &_ie
) == 0 &&
276 (WPA_CAPABILITY_MFPC
| WPA_CAPABILITY_MFPR
)) {
277 wpa_printf(MSG_DEBUG
, "WPA: Selected AP supports MFP: "
279 wpa_s
->sme
.mfp
= MGMT_FRAME_PROTECTION_REQUIRED
;
282 #endif /* CONFIG_IEEE80211W */
285 if (wpa_s
->global
->p2p
) {
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
;
294 res
= wpas_p2p_assoc_req_ie(wpa_s
, bss
, pos
, len
, p2p_group
);
296 wpa_s
->sme
.assoc_req_ie_len
+= res
;
298 #endif /* CONFIG_P2P */
300 wpa_supplicant_cancel_scan(wpa_s
);
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
);
306 wpa_clear_keys(wpa_s
, bss
->bssid
);
307 wpa_supplicant_set_state(wpa_s
, WPA_AUTHENTICATING
);
308 old_ssid
= wpa_s
->current_ssid
;
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
);
312 if (old_ssid
!= wpa_s
->current_ssid
)
313 wpas_notify_network_changed(wpa_s
);
315 wpa_s
->sme
.auth_alg
= params
.auth_alg
;
316 if (wpa_drv_authenticate(wpa_s
, ¶ms
) < 0) {
317 wpa_msg(wpa_s
, MSG_INFO
, "Authentication request to the "
319 wpa_supplicant_req_scan(wpa_s
, 1, 0);
323 /* TODO: add timeout on authentication */
326 * Association will be started based on the authentication event from
332 void sme_event_auth(struct wpa_supplicant
*wpa_s
, union wpa_event_data
*data
)
334 struct wpa_ssid
*ssid
= wpa_s
->current_ssid
;
337 wpa_printf(MSG_DEBUG
, "SME: Ignore authentication event when "
338 "network is not selected");
342 if (wpa_s
->wpa_state
!= WPA_AUTHENTICATING
) {
343 wpa_printf(MSG_DEBUG
, "SME: Ignore authentication event when "
344 "not in authenticating state");
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
));
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
);
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
);
366 if (data
->auth
.status_code
!=
367 WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG
||
368 wpa_s
->sme
.auth_alg
== data
->auth
.auth_type
||
369 wpa_s
->current_ssid
->auth_alg
== WPA_AUTH_ALG_LEAP
) {
370 sme_connection_failed(wpa_s
, wpa_s
->pending_bssid
);
374 switch (data
->auth
.auth_type
) {
376 wpa_s
->current_ssid
->auth_alg
= WPA_AUTH_ALG_SHARED
;
378 wpa_printf(MSG_DEBUG
, "SME: Trying SHARED auth");
379 wpa_supplicant_associate(wpa_s
, wpa_s
->current_bss
,
380 wpa_s
->current_ssid
);
383 case WLAN_AUTH_SHARED_KEY
:
384 wpa_s
->current_ssid
->auth_alg
= WPA_AUTH_ALG_LEAP
;
386 wpa_printf(MSG_DEBUG
, "SME: Trying LEAP auth");
387 wpa_supplicant_associate(wpa_s
, wpa_s
->current_bss
,
388 wpa_s
->current_ssid
);
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
);
405 #endif /* CONFIG_IEEE80211R */
407 sme_associate(wpa_s
, ssid
->mode
, data
->auth
.peer
,
408 data
->auth
.auth_type
);
412 void sme_associate(struct wpa_supplicant
*wpa_s
, enum wpas_mode mode
,
413 const u8
*bssid
, u16 auth_type
)
415 struct wpa_driver_associate_params params
;
416 struct ieee802_11_elems elems
;
418 os_memset(¶ms
, 0, sizeof(params
));
419 params
.bssid
= bssid
;
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
427 if (auth_type
== WLAN_AUTH_FT
&& wpa_s
->sme
.ft_ies
) {
428 params
.wpa_ie
= wpa_s
->sme
.ft_ies
;
429 params
.wpa_ie_len
= wpa_s
->sme
.ft_ies_len
;
431 #endif /* CONFIG_IEEE80211R */
433 params
.mgmt_frame_protection
= wpa_s
->sme
.mfp
;
434 if (wpa_s
->sme
.prev_bssid_set
)
435 params
.prev_bssid
= wpa_s
->sme
.prev_bssid
;
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
) : "",
442 wpa_supplicant_set_state(wpa_s
, WPA_ASSOCIATING
);
444 if (params
.wpa_ie
== NULL
||
445 ieee802_11_parse_elems(params
.wpa_ie
, params
.wpa_ie_len
, &elems
, 0)
447 wpa_printf(MSG_DEBUG
, "SME: Could not parse own IEs?!");
448 os_memset(&elems
, 0, sizeof(elems
));
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);
457 wpa_sm_set_assoc_wpa_ie(wpa_s
->wpa
, NULL
, 0);
459 (wpa_s
->drv_flags
& WPA_DRIVER_FLAGS_P2P_CAPABLE
))
462 if (wpa_s
->parent
->set_sta_uapsd
)
463 params
.uapsd
= wpa_s
->parent
->sta_uapsd
;
467 if (wpa_drv_associate(wpa_s
, ¶ms
) < 0) {
468 wpa_msg(wpa_s
, MSG_INFO
, "Association request to the driver "
470 wpa_supplicant_req_scan(wpa_s
, 5, 0);
474 /* TODO: add timeout on association */
478 int sme_update_ft_ies(struct wpa_supplicant
*wpa_s
, const u8
*md
,
479 const u8
*ies
, size_t ies_len
)
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;
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
)
496 os_memcpy(wpa_s
->sme
.ft_ies
, ies
, ies_len
);
497 wpa_s
->sme
.ft_ies_len
= ies_len
;
502 void sme_event_assoc_reject(struct wpa_supplicant
*wpa_s
,
503 union wpa_event_data
*data
)
507 wpa_printf(MSG_DEBUG
, "SME: Association with " MACSTR
" failed: "
508 "status code %d", MAC2STR(wpa_s
->pending_bssid
),
509 data
->assoc_reject
.status_code
);
511 bssid_changed
= !is_zero_ether_addr(wpa_s
->bssid
);
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.
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");
525 wpa_s
->sme
.prev_bssid_set
= 0;
527 sme_connection_failed(wpa_s
, wpa_s
->pending_bssid
);
528 wpa_supplicant_set_state(wpa_s
, WPA_DISCONNECTED
);
529 os_memset(wpa_s
->bssid
, 0, ETH_ALEN
);
530 os_memset(wpa_s
->pending_bssid
, 0, ETH_ALEN
);
532 wpas_notify_bssid_changed(wpa_s
);
536 void sme_event_auth_timed_out(struct wpa_supplicant
*wpa_s
,
537 union wpa_event_data
*data
)
539 wpa_printf(MSG_DEBUG
, "SME: Authentication timed out");
540 sme_connection_failed(wpa_s
, wpa_s
->pending_bssid
);
544 void sme_event_assoc_timed_out(struct wpa_supplicant
*wpa_s
,
545 union wpa_event_data
*data
)
547 wpa_printf(MSG_DEBUG
, "SME: Association timed out");
548 sme_connection_failed(wpa_s
, wpa_s
->pending_bssid
);
549 wpa_supplicant_mark_disassoc(wpa_s
);
553 void sme_event_disassoc(struct wpa_supplicant
*wpa_s
,
554 union wpa_event_data
*data
)
556 wpa_printf(MSG_DEBUG
, "SME: Disassociation event received");
557 if (wpa_s
->sme
.prev_bssid_set
&&
558 !(wpa_s
->drv_flags
& WPA_DRIVER_FLAGS_USER_SPACE_MLME
)) {
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.
565 wpa_printf(MSG_DEBUG
, "SME: Deauthenticate to clear driver "
567 wpa_drv_deauthenticate(wpa_s
, wpa_s
->sme
.prev_bssid
,
568 WLAN_REASON_DEAUTH_LEAVING
);