]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - wpa_supplicant/sme.c
Support HT capability overrides
[thirdparty/hostap.git] / wpa_supplicant / sme.c
index 018b372838154a326ca44c2ae45f97daf122c25f..c07b7a6316fdfebe38cf630cc4922f42ef7a7436 100644 (file)
 #include "wps_supplicant.h"
 #include "p2p_supplicant.h"
 #include "notify.h"
-#include "blacklist.h"
 #include "bss.h"
 #include "scan.h"
 #include "sme.h"
 
+#define SME_AUTH_TIMEOUT 5
+#define SME_ASSOC_TIMEOUT 5
+
+static void sme_auth_timer(void *eloop_ctx, void *timeout_ctx);
+static void sme_assoc_timer(void *eloop_ctx, void *timeout_ctx);
+#ifdef CONFIG_IEEE80211W
+static void sme_stop_sa_query(struct wpa_supplicant *wpa_s);
+#endif /* CONFIG_IEEE80211W */
+
+
 void sme_authenticate(struct wpa_supplicant *wpa_s,
                      struct wpa_bss *bss, struct wpa_ssid *ssid)
 {
@@ -48,8 +57,8 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
        int i, bssid_changed;
 
        if (bss == NULL) {
-               wpa_printf(MSG_ERROR, "SME: No scan result available for the "
-                          "network");
+               wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
+                       "the network");
                return;
        }
 
@@ -62,6 +71,7 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
        params.bssid = bss->bssid;
        params.ssid = bss->ssid;
        params.ssid_len = bss->ssid_len;
+       params.p2p = ssid->p2p_group;
 
        if (wpa_s->sme.ssid_len != params.ssid_len ||
            os_memcmp(wpa_s->sme.ssid, params.ssid, params.ssid_len) != 0)
@@ -82,12 +92,12 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
                }
        }
 #endif /* IEEE8021X_EAPOL */
-       wpa_printf(MSG_DEBUG, "Automatic auth_alg selection: 0x%x",
-                  params.auth_alg);
+       wpa_dbg(wpa_s, MSG_DEBUG, "Automatic auth_alg selection: 0x%x",
+               params.auth_alg);
        if (ssid->auth_alg) {
                params.auth_alg = ssid->auth_alg;
-               wpa_printf(MSG_DEBUG, "Overriding auth_alg selection: 0x%x",
-                          params.auth_alg);
+               wpa_dbg(wpa_s, MSG_DEBUG, "Overriding auth_alg selection: "
+                       "0x%x", params.auth_alg);
        }
 
        for (i = 0; i < NUM_WEP_KEYS; i++) {
@@ -105,11 +115,7 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
 
        if ((wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
             wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
-           (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK |
-                              WPA_KEY_MGMT_FT_IEEE8021X |
-                              WPA_KEY_MGMT_FT_PSK |
-                              WPA_KEY_MGMT_IEEE8021X_SHA256 |
-                              WPA_KEY_MGMT_PSK_SHA256))) {
+           wpa_key_mgmt_wpa(ssid->key_mgmt)) {
                int try_opportunistic;
                try_opportunistic = ssid->proactive_key_caching &&
                        (ssid->proto & WPA_PROTO_RSN);
@@ -121,22 +127,18 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
                if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
                                              wpa_s->sme.assoc_req_ie,
                                              &wpa_s->sme.assoc_req_ie_len)) {
-                       wpa_printf(MSG_WARNING, "SME: Failed to set WPA key "
-                                  "management and encryption suites");
+                       wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
+                               "key management and encryption suites");
                        return;
                }
-       } else if (ssid->key_mgmt &
-                  (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
-                   WPA_KEY_MGMT_WPA_NONE | WPA_KEY_MGMT_FT_PSK |
-                   WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_PSK_SHA256 |
-                   WPA_KEY_MGMT_IEEE8021X_SHA256)) {
+       } else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
                wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
                if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
                                              wpa_s->sme.assoc_req_ie,
                                              &wpa_s->sme.assoc_req_ie_len)) {
-                       wpa_printf(MSG_WARNING, "SME: Failed to set WPA key "
-                                  "management and encryption suites (no scan "
-                                  "results)");
+                       wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
+                               "key management and encryption suites (no "
+                               "scan results)");
                        return;
                }
 #ifdef CONFIG_WPS
@@ -168,8 +170,7 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
                wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
        }
 
-       if (md && ssid->key_mgmt & (WPA_KEY_MGMT_FT_PSK |
-                                   WPA_KEY_MGMT_FT_IEEE8021X)) {
+       if (md && wpa_key_mgmt_ft(ssid->key_mgmt)) {
                if (wpa_s->sme.assoc_req_ie_len + 5 <
                    sizeof(wpa_s->sme.assoc_req_ie)) {
                        struct rsn_mdie *mdie;
@@ -187,8 +188,8 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
                if (wpa_s->sme.ft_used &&
                    os_memcmp(md, wpa_s->sme.mobility_domain, 2) == 0 &&
                    wpa_sm_has_ptk(wpa_s->wpa)) {
-                       wpa_printf(MSG_DEBUG, "SME: Trying to use FT "
-                                  "over-the-air");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Trying to use FT "
+                               "over-the-air");
                        params.auth_alg = WPA_AUTH_ALG_FT;
                        params.ie = wpa_s->sme.ft_ies;
                        params.ie_len = wpa_s->sme.ft_ies_len;
@@ -204,8 +205,8 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
                if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &_ie) == 0 &&
                    _ie.capabilities &
                    (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) {
-                       wpa_printf(MSG_DEBUG, "WPA: Selected AP supports MFP: "
-                                  "require MFP");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Selected AP supports "
+                               "MFP: require MFP");
                        wpa_s->sme.mfp = MGMT_FRAME_PROTECTION_REQUIRED;
                }
        }
@@ -216,20 +217,38 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
                u8 *pos;
                size_t len;
                int res;
-               int p2p_group;
-               p2p_group = wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE;
                pos = wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len;
                len = sizeof(wpa_s->sme.assoc_req_ie) -
                        wpa_s->sme.assoc_req_ie_len;
-               res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len, p2p_group);
+               res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len,
+                                           ssid->p2p_group);
                if (res >= 0)
                        wpa_s->sme.assoc_req_ie_len += res;
        }
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_INTERWORKING
+       if (wpa_s->conf->interworking) {
+               u8 *pos = wpa_s->sme.assoc_req_ie;
+               if (wpa_s->sme.assoc_req_ie_len > 0 && pos[0] == WLAN_EID_RSN)
+                       pos += 2 + pos[1];
+               os_memmove(pos + 6, pos,
+                          wpa_s->sme.assoc_req_ie_len -
+                          (pos - wpa_s->sme.assoc_req_ie));
+               wpa_s->sme.assoc_req_ie_len += 6;
+               *pos++ = WLAN_EID_EXT_CAPAB;
+               *pos++ = 4;
+               *pos++ = 0x00;
+               *pos++ = 0x00;
+               *pos++ = 0x00;
+               *pos++ = 0x80; /* Bit 31 - Interworking */
+       }
+#endif /* CONFIG_INTERWORKING */
+
+       wpa_supplicant_cancel_sched_scan(wpa_s);
        wpa_supplicant_cancel_scan(wpa_s);
 
-       wpa_msg(wpa_s, MSG_INFO, "Trying to authenticate with " MACSTR
+       wpa_msg(wpa_s, MSG_INFO, "SME: Trying to authenticate with " MACSTR
                " (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid),
                wpa_ssid_txt(params.ssid, params.ssid_len), params.freq);
 
@@ -244,13 +263,15 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
 
        wpa_s->sme.auth_alg = params.auth_alg;
        if (wpa_drv_authenticate(wpa_s, &params) < 0) {
-               wpa_msg(wpa_s, MSG_INFO, "Authentication request to the "
+               wpa_msg(wpa_s, MSG_INFO, "SME: Authentication request to the "
                        "driver failed");
-               wpa_supplicant_req_scan(wpa_s, 1, 0);
+               wpas_connection_failed(wpa_s, bss->bssid);
+               wpa_supplicant_mark_disassoc(wpa_s);
                return;
        }
 
-       /* TODO: add timeout on authentication */
+       eloop_register_timeout(SME_AUTH_TIMEOUT, 0, sme_auth_timer, wpa_s,
+                              NULL);
 
        /*
         * Association will be started based on the authentication event from
@@ -264,34 +285,36 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
        struct wpa_ssid *ssid = wpa_s->current_ssid;
 
        if (ssid == NULL) {
-               wpa_printf(MSG_DEBUG, "SME: Ignore authentication event when "
-                          "network is not selected");
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME: Ignore authentication event "
+                       "when network is not selected");
                return;
        }
 
        if (wpa_s->wpa_state != WPA_AUTHENTICATING) {
-               wpa_printf(MSG_DEBUG, "SME: Ignore authentication event when "
-                          "not in authenticating state");
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME: Ignore authentication event "
+                       "when not in authenticating state");
                return;
        }
 
        if (os_memcmp(wpa_s->pending_bssid, data->auth.peer, ETH_ALEN) != 0) {
-               wpa_printf(MSG_DEBUG, "SME: Ignore authentication with "
-                          "unexpected peer " MACSTR,
-                          MAC2STR(data->auth.peer));
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME: Ignore authentication with "
+                       "unexpected peer " MACSTR,
+                       MAC2STR(data->auth.peer));
                return;
        }
 
-       wpa_printf(MSG_DEBUG, "SME: Authentication response: peer=" MACSTR
-                  " auth_type=%d status_code=%d",
-                  MAC2STR(data->auth.peer), data->auth.auth_type,
-                  data->auth.status_code);
+       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication response: peer=" MACSTR
+               " auth_type=%d status_code=%d",
+               MAC2STR(data->auth.peer), data->auth.auth_type,
+               data->auth.status_code);
        wpa_hexdump(MSG_MSGDUMP, "SME: Authentication response IEs",
                    data->auth.ies, data->auth.ies_len);
 
+       eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
+
        if (data->auth.status_code != WLAN_STATUS_SUCCESS) {
-               wpa_printf(MSG_DEBUG, "SME: Authentication failed (status "
-                          "code %d)", data->auth.status_code);
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication failed (status "
+                       "code %d)", data->auth.status_code);
 
                if (data->auth.status_code !=
                    WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG ||
@@ -305,7 +328,7 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
                case WLAN_AUTH_OPEN:
                        wpa_s->current_ssid->auth_alg = WPA_AUTH_ALG_SHARED;
 
-                       wpa_printf(MSG_DEBUG, "SME: Trying SHARED auth");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Trying SHARED auth");
                        wpa_supplicant_associate(wpa_s, wpa_s->current_bss,
                                                 wpa_s->current_ssid);
                        return;
@@ -313,7 +336,7 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
                case WLAN_AUTH_SHARED_KEY:
                        wpa_s->current_ssid->auth_alg = WPA_AUTH_ALG_LEAP;
 
-                       wpa_printf(MSG_DEBUG, "SME: Trying LEAP auth");
+                       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Trying LEAP auth");
                        wpa_supplicant_associate(wpa_s, wpa_s->current_bss,
                                                 wpa_s->current_ssid);
                        return;
@@ -344,6 +367,10 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
 {
        struct wpa_driver_associate_params params;
        struct ieee802_11_elems elems;
+#ifdef CONFIG_HT_OVERRIDES
+       struct ieee80211_ht_capabilities htcaps;
+       struct ieee80211_ht_capabilities htcaps_mask;
+#endif /* CONFIG_HT_OVERRIDES */
 
        os_memset(&params, 0, sizeof(params));
        params.bssid = bssid;
@@ -355,6 +382,13 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
        params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
        params.pairwise_suite = cipher_suite2driver(wpa_s->pairwise_cipher);
        params.group_suite = cipher_suite2driver(wpa_s->group_cipher);
+#ifdef CONFIG_HT_OVERRIDES
+       os_memset(&htcaps, 0, sizeof(htcaps));
+       os_memset(&htcaps_mask, 0, sizeof(htcaps_mask));
+       params.htcaps = (u8 *) &htcaps;
+       params.htcaps_mask = (u8 *) &htcaps_mask;
+       wpa_supplicant_apply_ht_overrides(wpa_s, wpa_s->current_ssid, &params);
+#endif /* CONFIG_HT_OVERRIDES */
 #ifdef CONFIG_IEEE80211R
        if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) {
                params.wpa_ie = wpa_s->sme.ft_ies;
@@ -376,19 +410,20 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
        if (params.wpa_ie == NULL ||
            ieee802_11_parse_elems(params.wpa_ie, params.wpa_ie_len, &elems, 0)
            < 0) {
-               wpa_printf(MSG_DEBUG, "SME: Could not parse own IEs?!");
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME: Could not parse own IEs?!");
                os_memset(&elems, 0, sizeof(elems));
        }
-       if (elems.rsn_ie)
+       if (elems.rsn_ie) {
+               params.wpa_proto = WPA_PROTO_RSN;
                wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.rsn_ie - 2,
                                        elems.rsn_ie_len + 2);
-       else if (elems.wpa_ie)
+       } else if (elems.wpa_ie) {
+               params.wpa_proto = WPA_PROTO_WPA;
                wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.wpa_ie - 2,
                                        elems.wpa_ie_len + 2);
-       else
+       else
                wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
-       if (elems.p2p &&
-           (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE))
+       if (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group)
                params.p2p = 1;
 
        if (wpa_s->parent->set_sta_uapsd)
@@ -397,14 +432,15 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
                params.uapsd = -1;
 
        if (wpa_drv_associate(wpa_s, &params) < 0) {
-               wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
-                       "failed");
+               wpa_msg(wpa_s, MSG_INFO, "SME: Association request to the "
+                       "driver failed");
                wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
                os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
                return;
        }
 
-       /* TODO: add timeout on association */
+       eloop_register_timeout(SME_ASSOC_TIMEOUT, 0, sme_assoc_timer, wpa_s,
+                              NULL);
 }
 
 
@@ -412,7 +448,7 @@ int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
                      const u8 *ies, size_t ies_len)
 {
        if (md == NULL || ies == NULL) {
-               wpa_printf(MSG_DEBUG, "SME: Remove mobility domain");
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME: Remove mobility domain");
                os_free(wpa_s->sme.ft_ies);
                wpa_s->sme.ft_ies = NULL;
                wpa_s->sme.ft_ies_len = 0;
@@ -432,28 +468,16 @@ int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
 }
 
 
-void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
-                           union wpa_event_data *data)
+static void sme_deauth(struct wpa_supplicant *wpa_s)
 {
        int bssid_changed;
 
-       wpa_printf(MSG_DEBUG, "SME: Association with " MACSTR " failed: "
-                  "status code %d", MAC2STR(wpa_s->pending_bssid),
-                  data->assoc_reject.status_code);
-
        bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
 
-       /*
-        * For now, unconditionally terminate the previous authentication. In
-        * theory, this should not be needed, but mac80211 gets quite confused
-        * if the authentication is left pending.. Some roaming cases might
-        * benefit from using the previous authentication, so this could be
-        * optimized in the future.
-        */
        if (wpa_drv_deauthenticate(wpa_s, wpa_s->pending_bssid,
                                   WLAN_REASON_DEAUTH_LEAVING) < 0) {
-               wpa_msg(wpa_s, MSG_INFO,
-                       "Deauth request to the driver failed");
+               wpa_msg(wpa_s, MSG_INFO, "SME: Deauth request to the driver "
+                       "failed");
        }
        wpa_s->sme.prev_bssid_set = 0;
 
@@ -466,18 +490,39 @@ void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
 }
 
 
+void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
+                           union wpa_event_data *data)
+{
+       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Association with " MACSTR " failed: "
+               "status code %d", MAC2STR(wpa_s->pending_bssid),
+               data->assoc_reject.status_code);
+
+       eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
+
+       /*
+        * For now, unconditionally terminate the previous authentication. In
+        * theory, this should not be needed, but mac80211 gets quite confused
+        * if the authentication is left pending.. Some roaming cases might
+        * benefit from using the previous authentication, so this could be
+        * optimized in the future.
+        */
+       sme_deauth(wpa_s);
+}
+
+
 void sme_event_auth_timed_out(struct wpa_supplicant *wpa_s,
                              union wpa_event_data *data)
 {
-       wpa_printf(MSG_DEBUG, "SME: Authentication timed out");
+       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication timed out");
        wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+       wpa_supplicant_mark_disassoc(wpa_s);
 }
 
 
 void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
                               union wpa_event_data *data)
 {
-       wpa_printf(MSG_DEBUG, "SME: Association timed out");
+       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Association timed out");
        wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
        wpa_supplicant_mark_disassoc(wpa_s);
 }
@@ -486,23 +531,88 @@ void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
 void sme_event_disassoc(struct wpa_supplicant *wpa_s,
                        union wpa_event_data *data)
 {
-       wpa_printf(MSG_DEBUG, "SME: Disassociation event received");
-       if (wpa_s->sme.prev_bssid_set &&
-           !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)) {
+       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Disassociation event received");
+       if (wpa_s->sme.prev_bssid_set) {
                /*
                 * cfg80211/mac80211 can get into somewhat confused state if
                 * the AP only disassociates us and leaves us in authenticated
                 * state. For now, force the state to be cleared to avoid
                 * confusing errors if we try to associate with the AP again.
                 */
-               wpa_printf(MSG_DEBUG, "SME: Deauthenticate to clear driver "
-                          "state");
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME: Deauthenticate to clear "
+                       "driver state");
                wpa_drv_deauthenticate(wpa_s, wpa_s->sme.prev_bssid,
                                       WLAN_REASON_DEAUTH_LEAVING);
        }
 }
 
 
+static void sme_auth_timer(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+       if (wpa_s->wpa_state == WPA_AUTHENTICATING) {
+               wpa_msg(wpa_s, MSG_DEBUG, "SME: Authentication timeout");
+               sme_deauth(wpa_s);
+       }
+}
+
+
+static void sme_assoc_timer(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+       if (wpa_s->wpa_state == WPA_ASSOCIATING) {
+               wpa_msg(wpa_s, MSG_DEBUG, "SME: Association timeout");
+               sme_deauth(wpa_s);
+       }
+}
+
+
+void sme_state_changed(struct wpa_supplicant *wpa_s)
+{
+       /* Make sure timers are cleaned up appropriately. */
+       if (wpa_s->wpa_state != WPA_ASSOCIATING)
+               eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
+       if (wpa_s->wpa_state != WPA_AUTHENTICATING)
+               eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
+}
+
+
+void sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s,
+                                      const u8 *prev_pending_bssid)
+{
+       /*
+        * mac80211-workaround to force deauth on failed auth cmd,
+        * requires us to remain in authenticating state to allow the
+        * second authentication attempt to be continued properly.
+        */
+       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Allow pending authentication "
+               "to proceed after disconnection event");
+       wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
+       os_memcpy(wpa_s->pending_bssid, prev_pending_bssid, ETH_ALEN);
+
+       /*
+        * Re-arm authentication timer in case auth fails for whatever reason.
+        */
+       eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
+       eloop_register_timeout(SME_AUTH_TIMEOUT, 0, sme_auth_timer, wpa_s,
+                              NULL);
+}
+
+
+void sme_deinit(struct wpa_supplicant *wpa_s)
+{
+       os_free(wpa_s->sme.ft_ies);
+       wpa_s->sme.ft_ies = NULL;
+       wpa_s->sme.ft_ies_len = 0;
+#ifdef CONFIG_IEEE80211W
+       sme_stop_sa_query(wpa_s);
+#endif /* CONFIG_IEEE80211W */
+
+       eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
+       eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
+}
+
+
 #ifdef CONFIG_IEEE80211W
 
 static const unsigned int sa_query_max_timeout = 1000;
@@ -516,7 +626,7 @@ static int sme_check_sa_query_timeout(struct wpa_supplicant *wpa_s)
        os_time_sub(&now, &wpa_s->sme.sa_query_start, &passed);
        tu = (passed.sec * 1000000 + passed.usec) / 1024;
        if (sa_query_max_timeout < tu) {
-               wpa_printf(MSG_DEBUG, "SME: SA Query timed out");
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME: SA Query timed out");
                sme_stop_sa_query(wpa_s);
                wpa_supplicant_deauthenticate(
                        wpa_s, WLAN_REASON_PREV_AUTH_NOT_VALID);
@@ -531,17 +641,18 @@ static void sme_send_sa_query_req(struct wpa_supplicant *wpa_s,
                                  const u8 *trans_id)
 {
        u8 req[2 + WLAN_SA_QUERY_TR_ID_LEN];
-       wpa_printf(MSG_DEBUG, "SME: Sending SA Query Request to "
-                  MACSTR, MAC2STR(wpa_s->bssid));
+       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Sending SA Query Request to "
+               MACSTR, MAC2STR(wpa_s->bssid));
        wpa_hexdump(MSG_DEBUG, "SME: SA Query Transaction ID",
                    trans_id, WLAN_SA_QUERY_TR_ID_LEN);
        req[0] = WLAN_ACTION_SA_QUERY;
        req[1] = WLAN_SA_QUERY_REQUEST;
        os_memcpy(req + 2, trans_id, WLAN_SA_QUERY_TR_ID_LEN);
-       if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, wpa_s->bssid,
+       if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
                                wpa_s->own_addr, wpa_s->bssid,
-                               req, sizeof(req)) < 0)
-               wpa_printf(MSG_INFO, "SME: Failed to send SA Query Request");
+                               req, sizeof(req), 0) < 0)
+               wpa_msg(wpa_s, MSG_INFO, "SME: Failed to send SA Query "
+                       "Request");
 }
 
 
@@ -575,8 +686,8 @@ static void sme_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
        usec = (timeout % 1000) * 1024;
        eloop_register_timeout(sec, usec, sme_sa_query_timer, wpa_s, NULL);
 
-       wpa_printf(MSG_DEBUG, "SME: Association SA Query attempt %d",
-                  wpa_s->sme.sa_query_count);
+       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Association SA Query attempt %d",
+               wpa_s->sme.sa_query_count);
 
        sme_send_sa_query_req(wpa_s, trans_id);
 }
@@ -588,7 +699,7 @@ static void sme_start_sa_query(struct wpa_supplicant *wpa_s)
 }
 
 
-void sme_stop_sa_query(struct wpa_supplicant *wpa_s)
+static void sme_stop_sa_query(struct wpa_supplicant *wpa_s)
 {
        eloop_cancel_timeout(sme_sa_query_timer, wpa_s, NULL);
        os_free(wpa_s->sme.sa_query_trans_id);
@@ -617,8 +728,8 @@ void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa,
        if (wpa_s->sme.sa_query_count > 0)
                return;
 
-       wpa_printf(MSG_DEBUG, "SME: Unprotected disconnect dropped - possible "
-                  "AP/STA state mismatch - trigger SA Query");
+       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Unprotected disconnect dropped - "
+               "possible AP/STA state mismatch - trigger SA Query");
        sme_start_sa_query(wpa_s);
 }
 
@@ -632,9 +743,8 @@ void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
            len < 1 + WLAN_SA_QUERY_TR_ID_LEN ||
            data[0] != WLAN_SA_QUERY_RESPONSE)
                return;
-       wpa_printf(MSG_DEBUG, "SME: Received SA Query response from " MACSTR
-                  " (trans_id %02x%02x)",
-                  MAC2STR(sa), data[1], data[2]);
+       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Received SA Query response from "
+               MACSTR " (trans_id %02x%02x)", MAC2STR(sa), data[1], data[2]);
 
        if (os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0)
                return;
@@ -647,13 +757,13 @@ void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
        }
 
        if (i >= wpa_s->sme.sa_query_count) {
-               wpa_printf(MSG_DEBUG, "SME: No matching SA Query "
-                          "transaction identifier found");
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME: No matching SA Query "
+                       "transaction identifier found");
                return;
        }
 
-       wpa_printf(MSG_DEBUG, "SME: Reply to pending SA Query received from "
-                  MACSTR, MAC2STR(sa));
+       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Reply to pending SA Query received "
+               "from " MACSTR, MAC2STR(sa));
        sme_stop_sa_query(wpa_s);
 }