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"
30
#include "blacklist.h"
35
static void add_freq(int *freqs, int *num_freqs, int freq)
39
for (i = 0; i < *num_freqs; i++) {
44
freqs[*num_freqs] = freq;
49
static int * sme_another_bss_in_ess(struct wpa_supplicant *wpa_s)
51
struct wpa_bss *bss, *cbss;
52
const int max_freqs = 10;
56
freqs = os_zalloc(sizeof(int) * (max_freqs + 1));
60
cbss = wpa_s->current_bss;
62
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
65
if (bss->ssid_len == cbss->ssid_len &&
66
os_memcmp(bss->ssid, cbss->ssid, bss->ssid_len) == 0 &&
67
wpa_blacklist_get(wpa_s, bss->bssid) == NULL) {
68
add_freq(freqs, &num_freqs, bss->freq);
69
if (num_freqs == max_freqs)
83
static void sme_connection_failed(struct wpa_supplicant *wpa_s,
91
* Add the failed BSSID into the blacklist and speed up next scan
92
* attempt if there could be other APs that could accept association.
93
* The current blacklist count indicates how many times we have tried
94
* connecting to this AP and multiple attempts mean that other APs are
95
* either not available or has already been tried, so that we can start
96
* increasing the delay here to avoid constant scanning.
98
count = wpa_blacklist_add(wpa_s, bssid);
99
if (count == 1 && wpa_s->current_bss) {
101
* This BSS was not in the blacklist before. If there is
102
* another BSS available for the same ESS, we should try that
103
* next. Otherwise, we may as well try this one once more
104
* before allowing other, likely worse, ESSes to be considered.
106
freqs = sme_another_bss_in_ess(wpa_s);
108
wpa_printf(MSG_DEBUG, "SME: Another BSS in this ESS "
109
"has been seen; try it next");
110
wpa_blacklist_add(wpa_s, bssid);
112
* On the next scan, go through only the known channels
113
* used in this ESS based on previous scans to speed up
114
* common load balancing use case.
116
os_free(wpa_s->next_scan_freqs);
117
wpa_s->next_scan_freqs = freqs;
136
* TODO: if more than one possible AP is available in scan results,
137
* could try the other ones before requesting a new scan.
139
wpa_supplicant_req_scan(wpa_s, timeout / 1000,
140
1000 * (timeout % 1000));
144
void sme_authenticate(struct wpa_supplicant *wpa_s,
145
struct wpa_bss *bss, struct wpa_ssid *ssid)
147
struct wpa_driver_auth_params params;
148
struct wpa_ssid *old_ssid;
149
#ifdef CONFIG_IEEE80211R
151
#endif /* CONFIG_IEEE80211R */
152
#ifdef CONFIG_IEEE80211R
154
#endif /* CONFIG_IEEE80211R */
155
int i, bssid_changed;
158
wpa_printf(MSG_ERROR, "SME: No scan result available for the "
163
wpa_s->current_bss = bss;
165
os_memset(¶ms, 0, sizeof(params));
166
wpa_s->reassociate = 0;
168
params.freq = bss->freq;
169
params.bssid = bss->bssid;
170
params.ssid = bss->ssid;
171
params.ssid_len = bss->ssid_len;
173
if (wpa_s->sme.ssid_len != params.ssid_len ||
174
os_memcmp(wpa_s->sme.ssid, params.ssid, params.ssid_len) != 0)
175
wpa_s->sme.prev_bssid_set = 0;
177
wpa_s->sme.freq = params.freq;
178
os_memcpy(wpa_s->sme.ssid, params.ssid, params.ssid_len);
179
wpa_s->sme.ssid_len = params.ssid_len;
181
params.auth_alg = WPA_AUTH_ALG_OPEN;
182
#ifdef IEEE8021X_EAPOL
183
if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
185
if (ssid->non_leap == 0)
186
params.auth_alg = WPA_AUTH_ALG_LEAP;
188
params.auth_alg |= WPA_AUTH_ALG_LEAP;
191
#endif /* IEEE8021X_EAPOL */
192
wpa_printf(MSG_DEBUG, "Automatic auth_alg selection: 0x%x",
194
if (ssid->auth_alg) {
195
params.auth_alg = ssid->auth_alg;
196
wpa_printf(MSG_DEBUG, "Overriding auth_alg selection: 0x%x",
200
for (i = 0; i < NUM_WEP_KEYS; i++) {
201
if (ssid->wep_key_len[i])
202
params.wep_key[i] = ssid->wep_key[i];
203
params.wep_key_len[i] = ssid->wep_key_len[i];
205
params.wep_tx_keyidx = ssid->wep_tx_keyidx;
207
bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
208
os_memset(wpa_s->bssid, 0, ETH_ALEN);
209
os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
211
wpas_notify_bssid_changed(wpa_s);
213
if ((wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
214
wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
215
(ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK |
216
WPA_KEY_MGMT_FT_IEEE8021X |
217
WPA_KEY_MGMT_FT_PSK |
218
WPA_KEY_MGMT_IEEE8021X_SHA256 |
219
WPA_KEY_MGMT_PSK_SHA256))) {
220
int try_opportunistic;
221
try_opportunistic = ssid->proactive_key_caching &&
222
(ssid->proto & WPA_PROTO_RSN);
223
if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
225
try_opportunistic) == 0)
226
eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
227
wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
228
if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
229
wpa_s->sme.assoc_req_ie,
230
&wpa_s->sme.assoc_req_ie_len)) {
231
wpa_printf(MSG_WARNING, "SME: Failed to set WPA key "
232
"management and encryption suites");
235
} else if (ssid->key_mgmt &
236
(WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
237
WPA_KEY_MGMT_WPA_NONE | WPA_KEY_MGMT_FT_PSK |
238
WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_PSK_SHA256 |
239
WPA_KEY_MGMT_IEEE8021X_SHA256)) {
240
wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
241
if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
242
wpa_s->sme.assoc_req_ie,
243
&wpa_s->sme.assoc_req_ie_len)) {
244
wpa_printf(MSG_WARNING, "SME: Failed to set WPA key "
245
"management and encryption suites (no scan "
250
} else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
251
struct wpabuf *wps_ie;
252
wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid));
253
if (wps_ie && wpabuf_len(wps_ie) <=
254
sizeof(wpa_s->sme.assoc_req_ie)) {
255
wpa_s->sme.assoc_req_ie_len = wpabuf_len(wps_ie);
256
os_memcpy(wpa_s->sme.assoc_req_ie, wpabuf_head(wps_ie),
257
wpa_s->sme.assoc_req_ie_len);
259
wpa_s->sme.assoc_req_ie_len = 0;
261
wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
262
#endif /* CONFIG_WPS */
264
wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
265
wpa_s->sme.assoc_req_ie_len = 0;
268
#ifdef CONFIG_IEEE80211R
269
ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
270
if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
272
wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0);
274
/* Prepare for the next transition */
275
wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
278
if (md && ssid->key_mgmt & (WPA_KEY_MGMT_FT_PSK |
279
WPA_KEY_MGMT_FT_IEEE8021X)) {
280
if (wpa_s->sme.assoc_req_ie_len + 5 <
281
sizeof(wpa_s->sme.assoc_req_ie)) {
282
struct rsn_mdie *mdie;
283
u8 *pos = wpa_s->sme.assoc_req_ie +
284
wpa_s->sme.assoc_req_ie_len;
285
*pos++ = WLAN_EID_MOBILITY_DOMAIN;
286
*pos++ = sizeof(*mdie);
287
mdie = (struct rsn_mdie *) pos;
288
os_memcpy(mdie->mobility_domain, md,
289
MOBILITY_DOMAIN_ID_LEN);
290
mdie->ft_capab = md[MOBILITY_DOMAIN_ID_LEN];
291
wpa_s->sme.assoc_req_ie_len += 5;
294
if (wpa_s->sme.ft_used &&
295
os_memcmp(md, wpa_s->sme.mobility_domain, 2) == 0 &&
296
wpa_sm_has_ptk(wpa_s->wpa)) {
297
wpa_printf(MSG_DEBUG, "SME: Trying to use FT "
299
params.auth_alg = WPA_AUTH_ALG_FT;
300
params.ie = wpa_s->sme.ft_ies;
301
params.ie_len = wpa_s->sme.ft_ies_len;
304
#endif /* CONFIG_IEEE80211R */
306
#ifdef CONFIG_IEEE80211W
307
wpa_s->sme.mfp = ssid->ieee80211w;
308
if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
309
const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
310
struct wpa_ie_data _ie;
311
if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &_ie) == 0 &&
313
(WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) {
314
wpa_printf(MSG_DEBUG, "WPA: Selected AP supports MFP: "
316
wpa_s->sme.mfp = MGMT_FRAME_PROTECTION_REQUIRED;
319
#endif /* CONFIG_IEEE80211W */
321
wpa_supplicant_cancel_scan(wpa_s);
323
wpa_msg(wpa_s, MSG_INFO, "Trying to authenticate with " MACSTR
324
" (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid),
325
wpa_ssid_txt(params.ssid, params.ssid_len), params.freq);
327
wpa_clear_keys(wpa_s, bss->bssid);
328
wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
329
old_ssid = wpa_s->current_ssid;
330
wpa_s->current_ssid = ssid;
331
wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
332
wpa_supplicant_initiate_eapol(wpa_s);
333
if (old_ssid != wpa_s->current_ssid)
334
wpas_notify_network_changed(wpa_s);
336
wpa_s->sme.auth_alg = params.auth_alg;
337
if (wpa_drv_authenticate(wpa_s, ¶ms) < 0) {
338
wpa_msg(wpa_s, MSG_INFO, "Authentication request to the "
340
wpa_supplicant_req_scan(wpa_s, 1, 0);
344
/* TODO: add timeout on authentication */
347
* Association will be started based on the authentication event from
353
void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
355
struct wpa_ssid *ssid = wpa_s->current_ssid;
358
wpa_printf(MSG_DEBUG, "SME: Ignore authentication event when "
359
"network is not selected");
363
if (wpa_s->wpa_state != WPA_AUTHENTICATING) {
364
wpa_printf(MSG_DEBUG, "SME: Ignore authentication event when "
365
"not in authenticating state");
369
if (os_memcmp(wpa_s->pending_bssid, data->auth.peer, ETH_ALEN) != 0) {
370
wpa_printf(MSG_DEBUG, "SME: Ignore authentication with "
371
"unexpected peer " MACSTR,
372
MAC2STR(data->auth.peer));
376
wpa_printf(MSG_DEBUG, "SME: Authentication response: peer=" MACSTR
377
" auth_type=%d status_code=%d",
378
MAC2STR(data->auth.peer), data->auth.auth_type,
379
data->auth.status_code);
380
wpa_hexdump(MSG_MSGDUMP, "SME: Authentication response IEs",
381
data->auth.ies, data->auth.ies_len);
383
if (data->auth.status_code != WLAN_STATUS_SUCCESS) {
384
wpa_printf(MSG_DEBUG, "SME: Authentication failed (status "
385
"code %d)", data->auth.status_code);
387
if (data->auth.status_code !=
388
WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG ||
389
wpa_s->sme.auth_alg == data->auth.auth_type ||
390
wpa_s->current_ssid->auth_alg == WPA_AUTH_ALG_LEAP) {
391
sme_connection_failed(wpa_s, wpa_s->pending_bssid);
395
switch (data->auth.auth_type) {
397
wpa_s->current_ssid->auth_alg = WPA_AUTH_ALG_SHARED;
399
wpa_printf(MSG_DEBUG, "SME: Trying SHARED auth");
400
wpa_supplicant_associate(wpa_s, wpa_s->current_bss,
401
wpa_s->current_ssid);
404
case WLAN_AUTH_SHARED_KEY:
405
wpa_s->current_ssid->auth_alg = WPA_AUTH_ALG_LEAP;
407
wpa_printf(MSG_DEBUG, "SME: Trying LEAP auth");
408
wpa_supplicant_associate(wpa_s, wpa_s->current_bss,
409
wpa_s->current_ssid);
417
#ifdef CONFIG_IEEE80211R
418
if (data->auth.auth_type == WLAN_AUTH_FT) {
419
union wpa_event_data edata;
420
os_memset(&edata, 0, sizeof(edata));
421
edata.ft_ies.ies = data->auth.ies;
422
edata.ft_ies.ies_len = data->auth.ies_len;
423
os_memcpy(edata.ft_ies.target_ap, data->auth.peer, ETH_ALEN);
424
wpa_supplicant_event(wpa_s, EVENT_FT_RESPONSE, &edata);
426
#endif /* CONFIG_IEEE80211R */
428
sme_associate(wpa_s, ssid->mode, data->auth.peer,
429
data->auth.auth_type);
433
void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
434
const u8 *bssid, u16 auth_type)
436
struct wpa_driver_associate_params params;
437
struct ieee802_11_elems elems;
439
os_memset(¶ms, 0, sizeof(params));
440
params.bssid = bssid;
441
params.ssid = wpa_s->sme.ssid;
442
params.ssid_len = wpa_s->sme.ssid_len;
443
params.freq = wpa_s->sme.freq;
444
params.wpa_ie = wpa_s->sme.assoc_req_ie_len ?
445
wpa_s->sme.assoc_req_ie : NULL;
446
params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
447
#ifdef CONFIG_IEEE80211R
448
if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) {
449
params.wpa_ie = wpa_s->sme.ft_ies;
450
params.wpa_ie_len = wpa_s->sme.ft_ies_len;
452
#endif /* CONFIG_IEEE80211R */
454
params.mgmt_frame_protection = wpa_s->sme.mfp;
455
if (wpa_s->sme.prev_bssid_set)
456
params.prev_bssid = wpa_s->sme.prev_bssid;
458
wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR
459
" (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid),
460
params.ssid ? wpa_ssid_txt(params.ssid, params.ssid_len) : "",
463
wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
465
if (params.wpa_ie == NULL ||
466
ieee802_11_parse_elems(params.wpa_ie, params.wpa_ie_len, &elems, 0)
468
wpa_printf(MSG_DEBUG, "SME: Could not parse own IEs?!");
469
os_memset(&elems, 0, sizeof(elems));
472
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.rsn_ie - 2,
473
elems.rsn_ie_len + 2);
474
else if (elems.wpa_ie)
475
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.wpa_ie - 2,
476
elems.wpa_ie_len + 2);
478
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
480
if (wpa_drv_associate(wpa_s, ¶ms) < 0) {
481
wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
483
wpa_supplicant_req_scan(wpa_s, 5, 0);
487
/* TODO: add timeout on association */
491
int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
492
const u8 *ies, size_t ies_len)
494
if (md == NULL || ies == NULL) {
495
wpa_printf(MSG_DEBUG, "SME: Remove mobility domain");
496
os_free(wpa_s->sme.ft_ies);
497
wpa_s->sme.ft_ies = NULL;
498
wpa_s->sme.ft_ies_len = 0;
499
wpa_s->sme.ft_used = 0;
503
os_memcpy(wpa_s->sme.mobility_domain, md, MOBILITY_DOMAIN_ID_LEN);
504
wpa_hexdump(MSG_DEBUG, "SME: FT IEs", ies, ies_len);
505
os_free(wpa_s->sme.ft_ies);
506
wpa_s->sme.ft_ies = os_malloc(ies_len);
507
if (wpa_s->sme.ft_ies == NULL)
509
os_memcpy(wpa_s->sme.ft_ies, ies, ies_len);
510
wpa_s->sme.ft_ies_len = ies_len;
515
void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
516
union wpa_event_data *data)
520
wpa_printf(MSG_DEBUG, "SME: Association with " MACSTR " failed: "
521
"status code %d", MAC2STR(wpa_s->pending_bssid),
522
data->assoc_reject.status_code);
524
bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
527
* For now, unconditionally terminate the previous authentication. In
528
* theory, this should not be needed, but mac80211 gets quite confused
529
* if the authentication is left pending.. Some roaming cases might
530
* benefit from using the previous authentication, so this could be
531
* optimized in the future.
533
if (wpa_drv_deauthenticate(wpa_s, wpa_s->pending_bssid,
534
WLAN_REASON_DEAUTH_LEAVING) < 0) {
535
wpa_msg(wpa_s, MSG_INFO,
536
"Deauth request to the driver failed");
538
wpa_s->sme.prev_bssid_set = 0;
540
sme_connection_failed(wpa_s, wpa_s->pending_bssid);
541
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
542
os_memset(wpa_s->bssid, 0, ETH_ALEN);
543
os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
545
wpas_notify_bssid_changed(wpa_s);
549
void sme_event_auth_timed_out(struct wpa_supplicant *wpa_s,
550
union wpa_event_data *data)
552
wpa_printf(MSG_DEBUG, "SME: Authentication timed out");
553
sme_connection_failed(wpa_s, wpa_s->pending_bssid);
557
void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
558
union wpa_event_data *data)
560
wpa_printf(MSG_DEBUG, "SME: Association timed out");
561
sme_connection_failed(wpa_s, wpa_s->pending_bssid);
562
wpa_supplicant_mark_disassoc(wpa_s);
566
void sme_event_disassoc(struct wpa_supplicant *wpa_s,
567
union wpa_event_data *data)
569
wpa_printf(MSG_DEBUG, "SME: Disassociation event received");
570
if (wpa_s->sme.prev_bssid_set &&
571
!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)) {
573
* cfg80211/mac80211 can get into somewhat confused state if
574
* the AP only disassociates us and leaves us in authenticated
575
* state. For now, force the state to be cleared to avoid
576
* confusing errors if we try to associate with the AP again.
578
wpa_printf(MSG_DEBUG, "SME: Deauthenticate to clear driver "
580
wpa_drv_deauthenticate(wpa_s, wpa_s->sme.prev_bssid,
581
WLAN_REASON_DEAUTH_LEAVING);