]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - wpa_supplicant/events.c
EAP: Increase the maximum number of message exchanges
[thirdparty/hostap.git] / wpa_supplicant / events.c
index 1fd5116d9a7820d224c1d708d0b5f2576a799353..7ba4345b642bdd2cefc6e7362eadad49ddc96212 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - Driver event processing
- * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -29,6 +29,7 @@
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "common/gas_server.h"
+#include "common/dpp.h"
 #include "crypto/random.h"
 #include "blacklist.h"
 #include "wpas_glue.h"
@@ -50,6 +51,9 @@
 #include "dpp_supplicant.h"
 
 
+#define MAX_OWE_TRANSITION_BSS_SELECT_COUNT 5
+
+
 #ifndef CONFIG_NO_SCAN_PROCESSING
 static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
                                              int new_scan, int own_request);
@@ -290,6 +294,13 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
        if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
                return;
 
+       if (os_reltime_initialized(&wpa_s->session_start)) {
+               os_reltime_age(&wpa_s->session_start, &wpa_s->session_length);
+               wpa_s->session_start.sec = 0;
+               wpa_s->session_start.usec = 0;
+               wpas_notify_session_length(wpa_s);
+       }
+
        wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
        bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
        os_memset(wpa_s->bssid, 0, ETH_ALEN);
@@ -305,8 +316,9 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
        eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
        if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
            wpa_s->key_mgmt == WPA_KEY_MGMT_OWE ||
-           wpa_s->key_mgmt == WPA_KEY_MGMT_DPP)
+           wpa_s->key_mgmt == WPA_KEY_MGMT_DPP || wpa_s->drv_authorized_port)
                eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+       wpa_s->drv_authorized_port = 0;
        wpa_s->ap_ies_from_associnfo = 0;
        wpa_s->current_ssid = NULL;
        eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
@@ -314,12 +326,16 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
 
        wpas_rrm_reset(wpa_s);
        wpa_s->wnmsleep_used = 0;
+       wnm_clear_coloc_intf_reporting(wpa_s);
 
 #ifdef CONFIG_TESTING_OPTIONS
        wpa_s->last_tk_alg = WPA_ALG_NONE;
        os_memset(wpa_s->last_tk, 0, sizeof(wpa_s->last_tk));
 #endif /* CONFIG_TESTING_OPTIONS */
        wpa_s->ieee80211ac = 0;
+
+       if (wpa_s->enabled_4addr_mode && wpa_drv_set_4addr_mode(wpa_s, 0) == 0)
+               wpa_s->enabled_4addr_mode = 0;
 }
 
 
@@ -524,6 +540,9 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
        const u8 *rsn_ie, *wpa_ie;
        int ret;
        int wep_ok;
+#ifdef CONFIG_MBO
+       const u8 *oce_capa_attr;
+#endif /* CONFIG_MBO */
 
        ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss);
        if (ret >= 0)
@@ -536,7 +555,7 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
                 (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA));
 
        rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
-       while ((ssid->proto & WPA_PROTO_RSN) && rsn_ie) {
+       while ((ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN)) && rsn_ie) {
                proto_match++;
 
                if (wpa_parse_wpa_ie(rsn_ie, 2 + rsn_ie[1], &ie)) {
@@ -545,6 +564,10 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
                                        "   skip RSN IE - parse failed");
                        break;
                }
+               if (!ie.has_pairwise)
+                       ie.pairwise_cipher = wpa_default_rsn_cipher(bss->freq);
+               if (!ie.has_group)
+                       ie.group_cipher = wpa_default_rsn_cipher(bss->freq);
 
                if (wep_ok &&
                    (ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
@@ -555,7 +578,8 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
                        return 1;
                }
 
-               if (!(ie.proto & ssid->proto)) {
+               if (!(ie.proto & ssid->proto) &&
+                   !(ssid->proto & WPA_PROTO_OSEN)) {
                        if (debug_print)
                                wpa_dbg(wpa_s, MSG_DEBUG,
                                        "   skip RSN IE - proto mismatch");
@@ -610,13 +634,17 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
                        break;
                }
 #ifdef CONFIG_MBO
+               oce_capa_attr = wpas_mbo_get_bss_attr(bss,
+                                                     OCE_ATTR_ID_CAPA_IND);
                if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
-                   wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND) &&
+                   (wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND) ||
+                    (oce_capa_attr && oce_capa_attr[1] >= 1 &&
+                     !(oce_capa_attr[2] & OCE_IS_STA_CFON))) &&
                    wpas_get_ssid_pmf(wpa_s, ssid) !=
                    NO_MGMT_FRAME_PROTECTION) {
                        if (debug_print)
                                wpa_dbg(wpa_s, MSG_DEBUG,
-                                       "   skip RSN IE - no mgmt frame protection enabled on MBO AP");
+                                       "   skip RSN IE - no mgmt frame protection enabled on MBO/OCE AP");
                        break;
                }
 #endif /* CONFIG_MBO */
@@ -702,6 +730,19 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
 #ifdef CONFIG_OWE
        if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) && !ssid->owe_only &&
            !wpa_ie && !rsn_ie) {
+               if (wpa_s->owe_transition_select &&
+                   wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE) &&
+                   ssid->owe_transition_bss_select_count + 1 <=
+                   MAX_OWE_TRANSITION_BSS_SELECT_COUNT) {
+                       ssid->owe_transition_bss_select_count++;
+                       if (debug_print)
+                               wpa_dbg(wpa_s, MSG_DEBUG,
+                                       "   skip OWE transition BSS (selection count %d does not exceed %d)",
+                                       ssid->owe_transition_bss_select_count,
+                                       MAX_OWE_TRANSITION_BSS_SELECT_COUNT);
+                       wpa_s->owe_transition_search = 1;
+                       return 0;
+               }
                if (debug_print)
                        wpa_dbg(wpa_s, MSG_DEBUG,
                                "   allow in OWE transition mode");
@@ -985,18 +1026,22 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
        struct wpa_blacklist *e;
        const u8 *ie;
        struct wpa_ssid *ssid;
-       int osen;
+       int osen, rsn_osen = 0;
 #ifdef CONFIG_MBO
        const u8 *assoc_disallow;
 #endif /* CONFIG_MBO */
        const u8 *match_ssid;
        size_t match_ssid_len;
+       struct wpa_ie_data data;
 
        ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
        wpa_ie_len = ie ? ie[1] : 0;
 
        ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
        rsn_ie_len = ie ? ie[1] : 0;
+       if (ie && wpa_parse_wpa_ie_rsn(ie, 2 + ie[1], &data) == 0 &&
+           (data.key_mgmt & WPA_KEY_MGMT_OSEN))
+               rsn_osen = 1;
 
        ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
        osen = ie != NULL;
@@ -1170,7 +1215,8 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
                        continue;
                }
 
-               if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen) {
+               if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen &&
+                   !rsn_osen) {
                        if (debug_print)
                                wpa_dbg(wpa_s, MSG_DEBUG,
                                        "   skip - non-OSEN network not allowed");
@@ -1184,7 +1230,7 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
                        continue;
                }
 
-               if (ssid->mode != IEEE80211_MODE_MESH && !bss_is_ess(bss) &&
+               if (ssid->mode != WPAS_MODE_MESH && !bss_is_ess(bss) &&
                    !bss_is_pbss(bss)) {
                        if (debug_print)
                                wpa_dbg(wpa_s, MSG_DEBUG,
@@ -1208,7 +1254,7 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
                }
 
 #ifdef CONFIG_MESH
-               if (ssid->mode == IEEE80211_MODE_MESH && ssid->frequency > 0 &&
+               if (ssid->mode == WPAS_MODE_MESH && ssid->frequency > 0 &&
                    ssid->frequency != bss->freq) {
                        if (debug_print)
                                wpa_dbg(wpa_s, MSG_DEBUG,
@@ -1312,10 +1358,10 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
                        continue;
                }
 
-               if (wpa_is_bss_tmp_disallowed(wpa_s, bss->bssid)) {
+               if (wpa_is_bss_tmp_disallowed(wpa_s, bss)) {
                        if (debug_print)
                                wpa_dbg(wpa_s, MSG_DEBUG,
-                                       "   skip - MBO retry delay has not passed yet");
+                                       "   skip - AP temporarily disallowed");
                        continue;
                }
 #ifdef CONFIG_TESTING_OPTIONS
@@ -1381,8 +1427,11 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s,
 
        for (i = 0; i < wpa_s->last_scan_res_used; i++) {
                struct wpa_bss *bss = wpa_s->last_scan_res[i];
+
+               wpa_s->owe_transition_select = 1;
                *selected_ssid = wpa_scan_res_match(wpa_s, i, bss, group,
                                                    only_first_ssid, 1);
+               wpa_s->owe_transition_select = 0;
                if (!*selected_ssid)
                        continue;
                wpa_dbg(wpa_s, MSG_DEBUG, "   selected BSS " MACSTR
@@ -1574,9 +1623,9 @@ wpa_supplicant_pick_new_network(struct wpa_supplicant *wpa_s)
                                continue;
                        }
 #endif /* !CONFIG_IBSS_RSN */
-                       if (ssid->mode == IEEE80211_MODE_IBSS ||
-                           ssid->mode == IEEE80211_MODE_AP ||
-                           ssid->mode == IEEE80211_MODE_MESH)
+                       if (ssid->mode == WPAS_MODE_IBSS ||
+                           ssid->mode == WPAS_MODE_AP ||
+                           ssid->mode == WPAS_MODE_MESH)
                                return ssid;
                }
        }
@@ -1863,7 +1912,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
        if (sme_proc_obss_scan(wpa_s) > 0)
                goto scan_work_done;
 
-       if (own_request &&
+       if (own_request && data &&
            wpas_beacon_rep_scan_process(wpa_s, scan_res, &data->scan_info) > 0)
                goto scan_work_done;
 
@@ -1929,6 +1978,7 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
        if (wpa_s->p2p_mgmt)
                return 0; /* no normal connection on p2p_mgmt interface */
 
+       wpa_s->owe_transition_search = 0;
        selected = wpa_supplicant_pick_network(wpa_s, &ssid);
 
 #ifdef CONFIG_MESH
@@ -2030,6 +2080,17 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
                                return 0;
                        }
 #endif /* CONFIG_WPS */
+#ifdef CONFIG_OWE
+                       if (wpa_s->owe_transition_search) {
+                               wpa_dbg(wpa_s, MSG_DEBUG,
+                                       "OWE: Use shorter wait during transition mode search");
+                               timeout_sec = 0;
+                               timeout_usec = 500000;
+                               wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
+                                                           timeout_usec);
+                               return 0;
+                       }
+#endif /* CONFIG_OWE */
                        if (wpa_supplicant_req_sched_scan(wpa_s))
                                wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
                                                            timeout_usec);
@@ -2229,6 +2290,57 @@ static void interworking_process_assoc_resp(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_INTERWORKING */
 
 
+static void multi_ap_process_assoc_resp(struct wpa_supplicant *wpa_s,
+                                       const u8 *ies, size_t ies_len)
+{
+       struct ieee802_11_elems elems;
+       const u8 *map_sub_elem, *pos;
+       size_t len;
+
+       if (!wpa_s->current_ssid ||
+           !wpa_s->current_ssid->multi_ap_backhaul_sta ||
+           !ies ||
+           ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed)
+               return;
+
+       if (!elems.multi_ap || elems.multi_ap_len < 7) {
+               wpa_printf(MSG_INFO, "AP doesn't support Multi-AP protocol");
+               goto fail;
+       }
+
+       pos = elems.multi_ap + 4;
+       len = elems.multi_ap_len - 4;
+
+       map_sub_elem = get_ie(pos, len, MULTI_AP_SUB_ELEM_TYPE);
+       if (!map_sub_elem || map_sub_elem[1] < 1) {
+               wpa_printf(MSG_INFO, "invalid Multi-AP sub elem type");
+               goto fail;
+       }
+
+       if (!(map_sub_elem[2] & MULTI_AP_BACKHAUL_BSS)) {
+               if ((map_sub_elem[2] & MULTI_AP_FRONTHAUL_BSS) &&
+                   wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
+                       wpa_printf(MSG_INFO,
+                                  "WPS active, accepting fronthaul-only BSS");
+                       /* Don't set 4addr mode in this case, so just return */
+                       return;
+               }
+               wpa_printf(MSG_INFO, "AP doesn't support backhaul BSS");
+               goto fail;
+       }
+
+       if (wpa_drv_set_4addr_mode(wpa_s, 1) < 0) {
+               wpa_printf(MSG_ERROR, "Failed to set 4addr mode");
+               goto fail;
+       }
+       wpa_s->enabled_4addr_mode = 1;
+       return;
+
+fail:
+       wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+}
+
+
 #ifdef CONFIG_FST
 static int wpas_fst_update_mbie(struct wpa_supplicant *wpa_s,
                                const u8 *ie, size_t ie_len)
@@ -2305,6 +2417,9 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
                    get_ie(data->assoc_info.resp_ies,
                           data->assoc_info.resp_ies_len, WLAN_EID_VHT_CAP))
                        wpa_s->ieee80211ac = 1;
+
+               multi_ap_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
+                                           data->assoc_info.resp_ies_len);
        }
        if (data->assoc_info.beacon_ies)
                wpa_hexdump(MSG_DEBUG, "beacon_ies",
@@ -2314,6 +2429,26 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
                wpa_dbg(wpa_s, MSG_DEBUG, "freq=%u MHz",
                        data->assoc_info.freq);
 
+       wpa_s->connection_set = 0;
+       if (data->assoc_info.req_ies && data->assoc_info.resp_ies) {
+               struct ieee802_11_elems req_elems, resp_elems;
+
+               if (ieee802_11_parse_elems(data->assoc_info.req_ies,
+                                          data->assoc_info.req_ies_len,
+                                          &req_elems, 0) != ParseFailed &&
+                   ieee802_11_parse_elems(data->assoc_info.resp_ies,
+                                          data->assoc_info.resp_ies_len,
+                                          &resp_elems, 0) != ParseFailed) {
+                       wpa_s->connection_set = 1;
+                       wpa_s->connection_ht = req_elems.ht_capabilities &&
+                               resp_elems.ht_capabilities;
+                       wpa_s->connection_vht = req_elems.vht_capabilities &&
+                               resp_elems.vht_capabilities;
+                       wpa_s->connection_he = req_elems.he_capabilities &&
+                               resp_elems.he_capabilities;
+               }
+       }
+
        p = data->assoc_info.req_ies;
        l = data->assoc_info.req_ies_len;
 
@@ -2372,6 +2507,28 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_OWE */
 
+#ifdef CONFIG_DPP2
+       wpa_sm_set_dpp_z(wpa_s->wpa, NULL);
+       if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP && wpa_s->dpp_pfs) {
+               struct ieee802_11_elems elems;
+
+               if (ieee802_11_parse_elems(data->assoc_info.resp_ies,
+                                          data->assoc_info.resp_ies_len,
+                                          &elems, 0) == ParseFailed ||
+                   !elems.owe_dh)
+                       goto no_pfs;
+               if (dpp_pfs_process(wpa_s->dpp_pfs, elems.owe_dh,
+                                   elems.owe_dh_len) < 0) {
+                       wpa_supplicant_deauthenticate(wpa_s,
+                                                     WLAN_REASON_UNSPECIFIED);
+                       return -1;
+               }
+
+               wpa_sm_set_dpp_z(wpa_s->wpa, wpa_s->dpp_pfs->secret);
+       }
+no_pfs:
+#endif /* CONFIG_DPP2 */
+
 #ifdef CONFIG_IEEE80211R
 #ifdef CONFIG_SME
        if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FT) {
@@ -2610,6 +2767,16 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
 
        wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED);
        if (os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) {
+               if (os_reltime_initialized(&wpa_s->session_start)) {
+                       os_reltime_age(&wpa_s->session_start,
+                                      &wpa_s->session_length);
+                       wpa_s->session_start.sec = 0;
+                       wpa_s->session_start.usec = 0;
+                       wpas_notify_session_length(wpa_s);
+               } else {
+                       wpas_notify_auth_changed(wpa_s);
+                       os_get_reltime(&wpa_s->session_start);
+               }
                wpa_dbg(wpa_s, MSG_DEBUG, "Associated to a new BSS: BSSID="
                        MACSTR, MAC2STR(bssid));
                new_bss = 1;
@@ -2672,7 +2839,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
        if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
            wpa_s->key_mgmt == WPA_KEY_MGMT_DPP ||
            wpa_s->key_mgmt == WPA_KEY_MGMT_OWE || ft_completed ||
-           already_authorized)
+           already_authorized || wpa_s->drv_authorized_port)
                eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
        /* 802.1X::portControl = Auto */
        eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
@@ -2680,7 +2847,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
        if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
            wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE ||
            (wpa_s->current_ssid &&
-            wpa_s->current_ssid->mode == IEEE80211_MODE_IBSS)) {
+            wpa_s->current_ssid->mode == WPAS_MODE_IBSS)) {
                if (wpa_s->current_ssid &&
                    wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE &&
                    (wpa_s->drv_flags &
@@ -2700,8 +2867,17 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
        }
        wpa_supplicant_cancel_scan(wpa_s);
 
-       if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
-           wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
+       if (ft_completed) {
+               /*
+                * FT protocol completed - make sure EAPOL state machine ends
+                * up in authenticated.
+                */
+               wpa_supplicant_cancel_auth_timeout(wpa_s);
+               wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+               eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+               eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
+       } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
+                  wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
                /*
                 * We are done; the driver will take care of RSN 4-way
                 * handshake.
@@ -2710,7 +2886,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
                wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
                eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
                eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
-       } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
+       } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) &&
                   wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
                /*
                 * The driver will take care of RSN 4-way handshake, so we need
@@ -2718,15 +2894,6 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
                 * waiting for WPA supplicant.
                 */
                eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
-       } else if (ft_completed) {
-               /*
-                * FT protocol completed - make sure EAPOL state machine ends
-                * up in authenticated.
-                */
-               wpa_supplicant_cancel_auth_timeout(wpa_s);
-               wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
-               eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
-               eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
        }
 
        wpa_s->last_eapol_matches_bssid = 0;
@@ -2972,7 +3139,7 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
            !disallowed_ssid(wpa_s, fast_reconnect->ssid,
                             fast_reconnect->ssid_len) &&
            !wpas_temp_disabled(wpa_s, fast_reconnect_ssid) &&
-           !wpa_is_bss_tmp_disallowed(wpa_s, fast_reconnect->bssid)) {
+           !wpa_is_bss_tmp_disallowed(wpa_s, fast_reconnect)) {
 #ifndef CONFIG_NO_SCAN_PROCESSING
                wpa_dbg(wpa_s, MSG_DEBUG, "Try to reconnect to the same BSS");
                if (wpa_supplicant_connect(wpa_s, fast_reconnect,
@@ -3437,8 +3604,9 @@ static void wpas_event_disassoc(struct wpa_supplicant *wpa_s,
                ie_len = info->ie_len;
                reason_code = info->reason_code;
                locally_generated = info->locally_generated;
-               wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s", reason_code,
-                       locally_generated ? " (locally generated)" : "");
+               wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u (%s)%s", reason_code,
+                       reason2str(reason_code),
+                       locally_generated ? " locally_generated=1" : "");
                if (addr)
                        wpa_dbg(wpa_s, MSG_DEBUG, " * address " MACSTR,
                                MAC2STR(addr));
@@ -3491,9 +3659,9 @@ static void wpas_event_deauth(struct wpa_supplicant *wpa_s,
                ie_len = info->ie_len;
                reason_code = info->reason_code;
                locally_generated = info->locally_generated;
-               wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s",
-                       reason_code,
-                       locally_generated ? " (locally generated)" : "");
+               wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u (%s)%s",
+                       reason_code, reason2str(reason_code),
+                       locally_generated ? " locally_generated=1" : "");
                if (addr) {
                        wpa_dbg(wpa_s, MSG_DEBUG, " * address " MACSTR,
                                MAC2STR(addr));
@@ -3545,8 +3713,8 @@ static const char * reg_type_str(enum reg_type type)
 }
 
 
-static void wpa_supplicant_update_channel_list(
-       struct wpa_supplicant *wpa_s, struct channel_list_changed *info)
+void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s,
+                                       struct channel_list_changed *info)
 {
        struct wpa_supplicant *ifs;
        u8 dfs_domain;
@@ -3560,10 +3728,13 @@ static void wpa_supplicant_update_channel_list(
        for (ifs = wpa_s; ifs->parent && ifs != ifs->parent; ifs = ifs->parent)
                ;
 
-       wpa_msg(ifs, MSG_INFO, WPA_EVENT_REGDOM_CHANGE "init=%s type=%s%s%s",
-               reg_init_str(info->initiator), reg_type_str(info->type),
-               info->alpha2[0] ? " alpha2=" : "",
-               info->alpha2[0] ? info->alpha2 : "");
+       if (info) {
+               wpa_msg(ifs, MSG_INFO,
+                       WPA_EVENT_REGDOM_CHANGE "init=%s type=%s%s%s",
+                       reg_init_str(info->initiator), reg_type_str(info->type),
+                       info->alpha2[0] ? " alpha2=" : "",
+                       info->alpha2[0] ? info->alpha2 : "");
+       }
 
        if (wpa_s->drv_priv == NULL)
                return; /* Ignore event during drv initialization */
@@ -3772,6 +3943,7 @@ static void wpa_supplicant_event_port_authorized(struct wpa_supplicant *wpa_s)
                wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
                eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
                eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
+               wpa_s->drv_authorized_port = 1;
        }
 }
 
@@ -3802,7 +3974,7 @@ static void wpas_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
                                       struct dfs_event *radar)
 {
 #if defined(NEED_AP_MLME) && defined(CONFIG_AP)
-       if (wpa_s->ap_iface) {
+       if (wpa_s->ap_iface || wpa_s->ifmsh) {
                wpas_ap_event_dfs_cac_started(wpa_s, radar);
        } else
 #endif /* NEED_AP_MLME && CONFIG_AP */
@@ -3823,7 +3995,7 @@ static void wpas_event_dfs_cac_finished(struct wpa_supplicant *wpa_s,
                                        struct dfs_event *radar)
 {
 #if defined(NEED_AP_MLME) && defined(CONFIG_AP)
-       if (wpa_s->ap_iface) {
+       if (wpa_s->ap_iface || wpa_s->ifmsh) {
                wpas_ap_event_dfs_cac_finished(wpa_s, radar);
        } else
 #endif /* NEED_AP_MLME && CONFIG_AP */
@@ -3839,7 +4011,7 @@ static void wpas_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s,
                                       struct dfs_event *radar)
 {
 #if defined(NEED_AP_MLME) && defined(CONFIG_AP)
-       if (wpa_s->ap_iface) {
+       if (wpa_s->ap_iface || wpa_s->ifmsh) {
                wpas_ap_event_dfs_cac_aborted(wpa_s, radar);
        } else
 #endif /* NEED_AP_MLME && CONFIG_AP */
@@ -3892,11 +4064,143 @@ static void wpa_supplicant_event_assoc_auth(struct wpa_supplicant *wpa_s,
 }
 
 
+static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s,
+                                   union wpa_event_data *data)
+{
+       const u8 *bssid = data->assoc_reject.bssid;
+#ifdef CONFIG_MBO
+       struct wpa_bss *reject_bss;
+#endif /* CONFIG_MBO */
+
+       if (!bssid || is_zero_ether_addr(bssid))
+               bssid = wpa_s->pending_bssid;
+#ifdef CONFIG_MBO
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+               reject_bss = wpa_s->current_bss;
+       else
+               reject_bss = wpa_bss_get_bssid(wpa_s, bssid);
+#endif /* CONFIG_MBO */
+
+       if (data->assoc_reject.bssid)
+               wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
+                       "bssid=" MACSTR " status_code=%u%s%s%s",
+                       MAC2STR(data->assoc_reject.bssid),
+                       data->assoc_reject.status_code,
+                       data->assoc_reject.timed_out ? " timeout" : "",
+                       data->assoc_reject.timeout_reason ? "=" : "",
+                       data->assoc_reject.timeout_reason ?
+                       data->assoc_reject.timeout_reason : "");
+       else
+               wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
+                       "status_code=%u%s%s%s",
+                       data->assoc_reject.status_code,
+                       data->assoc_reject.timed_out ? " timeout" : "",
+                       data->assoc_reject.timeout_reason ? "=" : "",
+                       data->assoc_reject.timeout_reason ?
+                       data->assoc_reject.timeout_reason : "");
+       wpa_s->assoc_status_code = data->assoc_reject.status_code;
+       wpas_notify_assoc_status_code(wpa_s);
+
+#ifdef CONFIG_OWE
+       if (data->assoc_reject.status_code ==
+           WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
+           wpa_s->key_mgmt == WPA_KEY_MGMT_OWE &&
+           wpa_s->current_ssid &&
+           wpa_s->current_ssid->owe_group == 0 &&
+           wpa_s->last_owe_group != 21) {
+               struct wpa_ssid *ssid = wpa_s->current_ssid;
+               struct wpa_bss *bss = wpa_s->current_bss;
+
+               if (!bss) {
+                       bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
+                       if (!bss) {
+                               wpas_connection_failed(wpa_s, bssid);
+                               wpa_supplicant_mark_disassoc(wpa_s);
+                               return;
+                       }
+               }
+               wpa_printf(MSG_DEBUG, "OWE: Try next supported DH group");
+               wpas_connect_work_done(wpa_s);
+               wpa_supplicant_mark_disassoc(wpa_s);
+               wpa_supplicant_connect(wpa_s, bss, ssid);
+               return;
+       }
+#endif /* CONFIG_OWE */
+
+#ifdef CONFIG_MBO
+       if (data->assoc_reject.status_code ==
+           WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
+           reject_bss && data->assoc_reject.resp_ies) {
+               const u8 *rssi_rej;
+
+               rssi_rej = mbo_get_attr_from_ies(
+                       data->assoc_reject.resp_ies,
+                       data->assoc_reject.resp_ies_len,
+                       OCE_ATTR_ID_RSSI_BASED_ASSOC_REJECT);
+               if (rssi_rej && rssi_rej[1] == 2) {
+                       wpa_printf(MSG_DEBUG,
+                                  "OCE: RSSI-based association rejection from "
+                                  MACSTR " (Delta RSSI: %u, Retry Delay: %u)",
+                                  MAC2STR(reject_bss->bssid),
+                                  rssi_rej[2], rssi_rej[3]);
+                       wpa_bss_tmp_disallow(wpa_s,
+                                            reject_bss->bssid,
+                                            rssi_rej[3],
+                                            rssi_rej[2] + reject_bss->level);
+               }
+       }
+#endif /* CONFIG_MBO */
+
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) {
+               sme_event_assoc_reject(wpa_s, data);
+               return;
+       }
+
+       /* Driver-based SME cases */
+
+#ifdef CONFIG_SAE
+       if (wpa_s->current_ssid &&
+           wpa_key_mgmt_sae(wpa_s->current_ssid->key_mgmt) &&
+           !data->assoc_reject.timed_out) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "SAE: Drop PMKSA cache entry");
+               wpa_sm_aborted_cached(wpa_s->wpa);
+               wpa_sm_pmksa_cache_flush(wpa_s->wpa, wpa_s->current_ssid);
+       }
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_DPP
+       if (wpa_s->current_ssid &&
+           wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_DPP &&
+           !data->assoc_reject.timed_out) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "DPP: Drop PMKSA cache entry");
+               wpa_sm_aborted_cached(wpa_s->wpa);
+               wpa_sm_pmksa_cache_flush(wpa_s->wpa, wpa_s->current_ssid);
+       }
+#endif /* CONFIG_DPP */
+
+#ifdef CONFIG_FILS
+       /* Update ERP next sequence number */
+       if (wpa_s->auth_alg == WPA_AUTH_ALG_FILS) {
+               eapol_sm_update_erp_next_seq_num(
+                       wpa_s->eapol,
+                       data->assoc_reject.fils_erp_next_seq_num);
+               fils_connection_failure(wpa_s);
+       }
+#endif /* CONFIG_FILS */
+
+       wpas_connection_failed(wpa_s, bssid);
+       wpa_supplicant_mark_disassoc(wpa_s);
+}
+
+
 void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                          union wpa_event_data *data)
 {
        struct wpa_supplicant *wpa_s = ctx;
        int resched;
+#ifndef CONFIG_NO_STDOUT_DEBUG
+       int level = MSG_DEBUG;
+#endif /* CONFIG_NO_STDOUT_DEBUG */
 
        if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED &&
            event != EVENT_INTERFACE_ENABLED &&
@@ -3910,9 +4214,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
        }
 
 #ifndef CONFIG_NO_STDOUT_DEBUG
-{
-       int level = MSG_DEBUG;
-
        if (event == EVENT_RX_MGMT && data->rx_mgmt.frame_len >= 24) {
                const struct ieee80211_hdr *hdr;
                u16 fc;
@@ -3925,7 +4226,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 
        wpa_dbg(wpa_s, level, "Event %s (%d) received",
                event_to_string(event), event);
-}
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 
        switch (event) {
@@ -3937,6 +4237,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                   "FST: MB IEs updated from auth IE");
 #endif /* CONFIG_FST */
                sme_event_auth(wpa_s, data);
+               wpa_s->auth_status_code = data->auth.status_code;
+               wpas_notify_auth_status_code(wpa_s);
                break;
        case EVENT_ASSOC:
 #ifdef CONFIG_TESTING_OPTIONS
@@ -3952,6 +4254,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                }
 #endif /* CONFIG_TESTING_OPTIONS */
                wpa_supplicant_event_assoc(wpa_s, data);
+               wpa_s->assoc_status_code = WLAN_STATUS_SUCCESS;
                if (data &&
                    (data->assoc_info.authorized ||
                     (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
@@ -4072,63 +4375,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                break;
 #endif /* CONFIG_IBSS_RSN */
        case EVENT_ASSOC_REJECT:
-               if (data->assoc_reject.bssid)
-                       wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
-                               "bssid=" MACSTR " status_code=%u%s%s%s",
-                               MAC2STR(data->assoc_reject.bssid),
-                               data->assoc_reject.status_code,
-                               data->assoc_reject.timed_out ? " timeout" : "",
-                               data->assoc_reject.timeout_reason ? "=" : "",
-                               data->assoc_reject.timeout_reason ?
-                               data->assoc_reject.timeout_reason : "");
-               else
-                       wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
-                               "status_code=%u%s%s%s",
-                               data->assoc_reject.status_code,
-                               data->assoc_reject.timed_out ? " timeout" : "",
-                               data->assoc_reject.timeout_reason ? "=" : "",
-                               data->assoc_reject.timeout_reason ?
-                               data->assoc_reject.timeout_reason : "");
-               wpa_s->assoc_status_code = data->assoc_reject.status_code;
-               wpas_notify_assoc_status_code(wpa_s);
-
-#ifdef CONFIG_OWE
-               if (data->assoc_reject.status_code ==
-                   WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
-                   wpa_s->key_mgmt == WPA_KEY_MGMT_OWE &&
-                   wpa_s->current_ssid &&
-                   wpa_s->current_ssid->owe_group == 0 &&
-                   wpa_s->last_owe_group != 21) {
-                       struct wpa_ssid *ssid = wpa_s->current_ssid;
-                       struct wpa_bss *bss = wpa_s->current_bss;
-
-                       wpa_printf(MSG_DEBUG,
-                                  "OWE: Try next supported DH group");
-                       wpas_connect_work_done(wpa_s);
-                       wpa_supplicant_mark_disassoc(wpa_s);
-                       wpa_supplicant_connect(wpa_s, bss, ssid);
-                       break;
-               }
-#endif /* CONFIG_OWE */
-
-               if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
-                       sme_event_assoc_reject(wpa_s, data);
-               else {
-                       const u8 *bssid = data->assoc_reject.bssid;
-
-#ifdef CONFIG_FILS
-                       /* Update ERP next sequence number */
-                       if (wpa_s->auth_alg == WPA_AUTH_ALG_FILS)
-                               eapol_sm_update_erp_next_seq_num(
-                                     wpa_s->eapol,
-                                     data->assoc_reject.fils_erp_next_seq_num);
-#endif /* CONFIG_FILS */
-
-                       if (bssid == NULL || is_zero_ether_addr(bssid))
-                               bssid = wpa_s->pending_bssid;
-                       wpas_connection_failed(wpa_s, bssid);
-                       wpa_supplicant_mark_disassoc(wpa_s);
-               }
+               wpas_event_assoc_reject(wpa_s, data);
                break;
        case EVENT_AUTH_TIMED_OUT:
                /* It is possible to get this event from earlier connection */
@@ -4231,18 +4478,24 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                       data->rx_from_unknown.wds);
                break;
 #endif /* CONFIG_AP */
+
+       case EVENT_CH_SWITCH_STARTED:
        case EVENT_CH_SWITCH:
                if (!data || !wpa_s->current_ssid)
                        break;
 
-               wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CHANNEL_SWITCH
-                       "freq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d",
+               wpa_msg(wpa_s, MSG_INFO,
+                       "%sfreq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d",
+                       event == EVENT_CH_SWITCH ? WPA_EVENT_CHANNEL_SWITCH :
+                       WPA_EVENT_CHANNEL_SWITCH_STARTED,
                        data->ch_switch.freq,
                        data->ch_switch.ht_enabled,
                        data->ch_switch.ch_offset,
                        channel_width_to_string(data->ch_switch.ch_width),
                        data->ch_switch.cf1,
                        data->ch_switch.cf2);
+               if (event == EVENT_CH_SWITCH_STARTED)
+                       break;
 
                wpa_s->assoc_freq = data->ch_switch.freq;
                wpa_s->current_ssid->frequency = data->ch_switch.freq;
@@ -4250,6 +4503,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 #ifdef CONFIG_AP
                if (wpa_s->current_ssid->mode == WPAS_MODE_AP ||
                    wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO ||
+                   wpa_s->current_ssid->mode == WPAS_MODE_MESH ||
                    wpa_s->current_ssid->mode ==
                    WPAS_MODE_P2P_GROUP_FORMATION) {
                        wpas_ap_ch_switch(wpa_s, data->ch_switch.freq,
@@ -4257,11 +4511,16 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                          data->ch_switch.ch_offset,
                                          data->ch_switch.ch_width,
                                          data->ch_switch.cf1,
-                                         data->ch_switch.cf2);
+                                         data->ch_switch.cf2,
+                                         1);
                }
 #endif /* CONFIG_AP */
 
+#ifdef CONFIG_IEEE80211W
+               sme_event_ch_switch(wpa_s);
+#endif /* CONFIG_IEEE80211W */
                wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_CS);
+               wnm_clear_coloc_intf_reporting(wpa_s);
                break;
 #ifdef CONFIG_AP
 #ifdef NEED_AP_MLME
@@ -4466,6 +4725,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                wpa_dbg(wpa_s, MSG_DEBUG, "Interface was enabled");
                if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
                        wpa_supplicant_update_mac_addr(wpa_s);
+                       wpa_supplicant_set_default_scan_ies(wpa_s);
                        if (wpa_s->p2p_mgmt) {
                                wpa_supplicant_set_state(wpa_s,
                                                         WPA_DISCONNECTED);
@@ -4628,7 +4888,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                break;
        case EVENT_WPS_BUTTON_PUSHED:
 #ifdef CONFIG_WPS
-               wpas_wps_start_pbc(wpa_s, NULL, 0);
+               wpas_wps_start_pbc(wpa_s, NULL, 0, 0);
 #endif /* CONFIG_WPS */
                break;
        case EVENT_AVOID_FREQUENCIES: