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