]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - wpa_supplicant/events.c
WNM: Collocated Interference Reporting
[thirdparty/hostap.git] / wpa_supplicant / events.c
index 053fe15233fda6dbe2f9347e41f68b2235168f33..dd6dd52676b87eddfb77f990796967863e5cf1ab 100644 (file)
@@ -28,6 +28,7 @@
 #include "notify.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
+#include "common/gas_server.h"
 #include "crypto/random.h"
 #include "blacklist.h"
 #include "wpas_glue.h"
 #include "mesh.h"
 #include "mesh_mpm.h"
 #include "wmm_ac.h"
+#include "dpp_supplicant.h"
+
+
+#define MAX_OWE_TRANSITION_BSS_SELECT_COUNT 5
 
 
 #ifndef CONFIG_NO_SCAN_PROCESSING
@@ -54,8 +59,7 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_NO_SCAN_PROCESSING */
 
 
-static int wpas_temp_disabled(struct wpa_supplicant *wpa_s,
-                             struct wpa_ssid *ssid)
+int wpas_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
 {
        struct os_reltime now;
 
@@ -303,7 +307,8 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
        eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
        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_OWE ||
+           wpa_s->key_mgmt == WPA_KEY_MGMT_DPP)
                eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
        wpa_s->ap_ies_from_associnfo = 0;
        wpa_s->current_ssid = NULL;
@@ -312,6 +317,13 @@ 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;
 }
 
 
@@ -328,7 +340,7 @@ static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s)
        for (i = 0; i < ie.num_pmkid; i++) {
                pmksa_set = pmksa_cache_set_current(wpa_s->wpa,
                                                    ie.pmkid + i * PMKID_LEN,
-                                                   NULL, NULL, 0, NULL);
+                                                   NULL, NULL, 0, NULL, 0);
                if (pmksa_set == 0) {
                        eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
                        break;
@@ -480,6 +492,11 @@ static int wpa_supplicant_match_privacy(struct wpa_bss *bss,
                return 1;
 #endif /* CONFIG_WPS */
 
+#ifdef CONFIG_OWE
+       if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) && !ssid->owe_only)
+               return 1;
+#endif /* CONFIG_OWE */
+
        if (has_wep_key(ssid))
                privacy = 1;
 
@@ -523,7 +540,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)) {
@@ -542,7 +559,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");
@@ -563,6 +581,14 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
                        break;
                }
 
+               if (ssid->group_mgmt_cipher &&
+                   !(ie.mgmt_group_cipher & ssid->group_mgmt_cipher)) {
+                       if (debug_print)
+                               wpa_dbg(wpa_s, MSG_DEBUG,
+                                       "   skip RSN IE - group mgmt cipher mismatch");
+                       break;
+               }
+
                if (!(ie.key_mgmt & ssid->key_mgmt)) {
                        if (debug_print)
                                wpa_dbg(wpa_s, MSG_DEBUG,
@@ -607,7 +633,8 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
        }
 
 #ifdef CONFIG_IEEE80211W
-       if (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
+       if (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED &&
+           (!(ssid->key_mgmt & WPA_KEY_MGMT_OWE) || ssid->owe_only)) {
                if (debug_print)
                        wpa_dbg(wpa_s, MSG_DEBUG,
                                "   skip - MFP Required but network not MFP Capable");
@@ -677,6 +704,29 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
                return 1;
        }
 
+#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");
+               return 1;
+       }
+#endif /* CONFIG_OWE */
+
        if ((ssid->proto & (WPA_PROTO_WPA | WPA_PROTO_RSN)) &&
            wpa_key_mgmt_wpa(ssid->key_mgmt) && proto_match == 0) {
                if (debug_print)
@@ -869,6 +919,80 @@ static int addr_in_list(const u8 *addr, const u8 *list, size_t num)
 }
 
 
+static void owe_trans_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+                          const u8 **ret_ssid, size_t *ret_ssid_len)
+{
+#ifdef CONFIG_OWE
+       const u8 *owe, *pos, *end, *bssid;
+       u8 ssid_len;
+       struct wpa_bss *open_bss;
+
+       owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
+       if (!owe || !wpa_bss_get_ie(bss, WLAN_EID_RSN))
+               return;
+
+       pos = owe + 6;
+       end = owe + 2 + owe[1];
+
+       if (end - pos < ETH_ALEN + 1)
+               return;
+       bssid = pos;
+       pos += ETH_ALEN;
+       ssid_len = *pos++;
+       if (end - pos < ssid_len || ssid_len > SSID_MAX_LEN)
+               return;
+
+       /* Match the profile SSID against the OWE transition mode SSID on the
+        * open network. */
+       wpa_dbg(wpa_s, MSG_DEBUG, "OWE: transition mode BSSID: " MACSTR
+               " SSID: %s", MAC2STR(bssid), wpa_ssid_txt(pos, ssid_len));
+       *ret_ssid = pos;
+       *ret_ssid_len = ssid_len;
+
+       if (bss->ssid_len > 0)
+               return;
+
+       open_bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
+       if (!open_bss)
+               return;
+       if (ssid_len != open_bss->ssid_len ||
+           os_memcmp(pos, open_bss->ssid, ssid_len) != 0) {
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "OWE: transition mode SSID mismatch: %s",
+                       wpa_ssid_txt(open_bss->ssid, open_bss->ssid_len));
+               return;
+       }
+
+       owe = wpa_bss_get_vendor_ie(open_bss, OWE_IE_VENDOR_TYPE);
+       if (!owe || wpa_bss_get_ie(open_bss, WLAN_EID_RSN)) {
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "OWE: transition mode open BSS unexpected info");
+               return;
+       }
+
+       pos = owe + 6;
+       end = owe + 2 + owe[1];
+
+       if (end - pos < ETH_ALEN + 1)
+               return;
+       if (os_memcmp(pos, bss->bssid, ETH_ALEN) != 0) {
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "OWE: transition mode BSSID mismatch: " MACSTR,
+                       MAC2STR(pos));
+               return;
+       }
+       pos += ETH_ALEN;
+       ssid_len = *pos++;
+       if (end - pos < ssid_len || ssid_len > SSID_MAX_LEN)
+               return;
+       wpa_dbg(wpa_s, MSG_DEBUG, "OWE: learned transition mode OWE SSID: %s",
+               wpa_ssid_txt(pos, ssid_len));
+       os_memcpy(bss->ssid, pos, ssid_len);
+       bss->ssid_len = ssid_len;
+#endif /* CONFIG_OWE */
+}
+
+
 struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
                                     int i, struct wpa_bss *bss,
                                     struct wpa_ssid *group,
@@ -879,16 +1003,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;
@@ -932,7 +1062,11 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
                }
        }
 
-       if (bss->ssid_len == 0) {
+       match_ssid = bss->ssid;
+       match_ssid_len = bss->ssid_len;
+       owe_trans_ssid(wpa_s, bss, &match_ssid, &match_ssid_len);
+
+       if (match_ssid_len == 0) {
                if (debug_print)
                        wpa_dbg(wpa_s, MSG_DEBUG, "   skip - SSID not known");
                return NULL;
@@ -944,7 +1078,7 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
                return NULL;
        }
 
-       if (disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
+       if (disallowed_ssid(wpa_s, match_ssid, match_ssid_len)) {
                if (debug_print)
                        wpa_dbg(wpa_s, MSG_DEBUG, "   skip - SSID disallowed");
                return NULL;
@@ -999,8 +1133,8 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
                        check_ssid = 0;
 
                if (check_ssid &&
-                   (bss->ssid_len != ssid->ssid_len ||
-                    os_memcmp(bss->ssid, ssid->ssid, bss->ssid_len) != 0)) {
+                   (match_ssid_len != ssid->ssid_len ||
+                    os_memcmp(match_ssid, ssid->ssid, match_ssid_len) != 0)) {
                        if (debug_print)
                                wpa_dbg(wpa_s, MSG_DEBUG,
                                        "   skip - SSID mismatch");
@@ -1042,6 +1176,7 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
                if (!osen && !wpa &&
                    !(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
                    !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
+                   !(ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
                    !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) {
                        if (debug_print)
                                wpa_dbg(wpa_s, MSG_DEBUG,
@@ -1057,7 +1192,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");
@@ -1210,6 +1346,19 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_TESTING_OPTIONS */
 #endif /* CONFIG_MBO */
 
+#ifdef CONFIG_DPP
+               if ((ssid->key_mgmt & WPA_KEY_MGMT_DPP) &&
+                   !wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid) &&
+                   (!ssid->dpp_connector ||
+                    !ssid->dpp_netaccesskey ||
+                    !ssid->dpp_csign)) {
+                       if (debug_print)
+                               wpa_dbg(wpa_s, MSG_DEBUG,
+                                       "   skip - no PMKSA entry for DPP");
+                       continue;
+               }
+#endif /* CONFIG_DPP */
+
                /* Matching configuration found */
                return ssid;
        }
@@ -1255,8 +1404,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
@@ -1803,6 +1955,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
@@ -1904,6 +2057,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);
@@ -2152,9 +2316,9 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
 {
        int l, len, found = 0, wpa_found, rsn_found;
        const u8 *p;
-#ifdef CONFIG_IEEE80211R
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_OWE)
        u8 bssid[ETH_ALEN];
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R || CONFIG_OWE */
 
        wpa_dbg(wpa_s, MSG_DEBUG, "Association info event");
        if (data->assoc_info.req_ies)
@@ -2175,6 +2339,10 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
                interworking_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
                                                data->assoc_info.resp_ies_len);
 #endif /* CONFIG_INTERWORKING */
+               if (wpa_s->hw_capab == CAPAB_VHT &&
+                   get_ie(data->assoc_info.resp_ies,
+                          data->assoc_info.resp_ies_len, WLAN_EID_VHT_CAP))
+                       wpa_s->ieee80211ac = 1;
        }
        if (data->assoc_info.beacon_ies)
                wpa_hexdump(MSG_DEBUG, "beacon_ies",
@@ -2214,7 +2382,8 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
 
 #ifdef CONFIG_FILS
 #ifdef CONFIG_SME
-       if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS &&
+       if ((wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS ||
+            wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS_SK_PFS) &&
            (!data->assoc_info.resp_frame ||
             fils_process_assoc_resp(wpa_s->wpa,
                                     data->assoc_info.resp_frame,
@@ -2223,8 +2392,24 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
                return -1;
        }
 #endif /* CONFIG_SME */
+
+       /* Additional processing for FILS when SME is in driver */
+       if (wpa_s->auth_alg == WPA_AUTH_ALG_FILS &&
+           !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
+               wpa_sm_set_reset_fils_completed(wpa_s->wpa, 1);
 #endif /* CONFIG_FILS */
 
+#ifdef CONFIG_OWE
+       if (wpa_s->key_mgmt == WPA_KEY_MGMT_OWE &&
+           (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
+            owe_process_assoc_resp(wpa_s->wpa, bssid,
+                                   data->assoc_info.resp_ies,
+                                   data->assoc_info.resp_ies_len) < 0)) {
+               wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_UNSPECIFIED);
+               return -1;
+       }
+#endif /* CONFIG_OWE */
+
 #ifdef CONFIG_IEEE80211R
 #ifdef CONFIG_SME
        if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FT) {
@@ -2523,6 +2708,7 @@ static void wpa_supplicant_event_assoc(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_DPP ||
            wpa_s->key_mgmt == WPA_KEY_MGMT_OWE || ft_completed ||
            already_authorized)
                eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
@@ -2638,6 +2824,16 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
                if (wpa_s->reassoc_same_bss)
                        wmm_ac_restore_tspecs(wpa_s);
        }
+
+#ifdef CONFIG_FILS
+       if (wpa_key_mgmt_fils(wpa_s->key_mgmt)) {
+               struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, bssid);
+               const u8 *fils_cache_id = wpa_bss_get_fils_cache_id(bss);
+
+               if (fils_cache_id)
+                       wpa_sm_set_fils_cache_id(wpa_s->wpa, fils_cache_id);
+       }
+#endif /* CONFIG_FILS */
 }
 
 
@@ -3029,18 +3225,6 @@ wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
 }
 
 
-#ifdef CONFIG_PEERKEY
-static void
-wpa_supplicant_event_stkstart(struct wpa_supplicant *wpa_s,
-                             union wpa_event_data *data)
-{
-       if (data == NULL)
-               return;
-       wpa_sm_stkstart(wpa_s->wpa, data->stkstart.peer);
-}
-#endif /* CONFIG_PEERKEY */
-
-
 #ifdef CONFIG_TDLS
 static void wpa_supplicant_event_tdls(struct wpa_supplicant *wpa_s,
                                      union wpa_event_data *data)
@@ -3403,6 +3587,7 @@ static void wpa_supplicant_update_channel_list(
        struct wpa_supplicant *wpa_s, struct channel_list_changed *info)
 {
        struct wpa_supplicant *ifs;
+       u8 dfs_domain;
 
        /*
         * To allow backwards compatibility with higher level layers that
@@ -3427,7 +3612,7 @@ static void wpa_supplicant_update_channel_list(
                           ifs->ifname);
                free_hw_features(ifs);
                ifs->hw.modes = wpa_drv_get_hw_feature_data(
-                       ifs, &ifs->hw.num_modes, &ifs->hw.flags);
+                       ifs, &ifs->hw.num_modes, &ifs->hw.flags, &dfs_domain);
 
                /* Restart PNO/sched_scan with updated channel list */
                if (ifs->pno) {
@@ -3502,6 +3687,15 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
                return;
 #endif /* CONFIG_GAS */
 
+#ifdef CONFIG_GAS_SERVER
+       if ((mgmt->u.action.category == WLAN_ACTION_PUBLIC ||
+            mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL) &&
+           gas_server_rx(wpa_s->gas_server, mgmt->da, mgmt->sa, mgmt->bssid,
+                         mgmt->u.action.category,
+                         payload, plen, freq) == 0)
+               return;
+#endif /* CONFIG_GAS_SERVER */
+
 #ifdef CONFIG_TDLS
        if (category == WLAN_ACTION_PUBLIC && plen >= 4 &&
            payload[0] == WLAN_TDLS_DISCOVERY_RESPONSE) {
@@ -3530,6 +3724,7 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
        if (category == WLAN_ACTION_RADIO_MEASUREMENT &&
            payload[0] == WLAN_RRM_RADIO_MEASUREMENT_REQUEST) {
                wpas_rrm_handle_radio_measurement_request(wpa_s, mgmt->sa,
+                                                         mgmt->da,
                                                          payload + 1,
                                                          plen - 1);
                return;
@@ -3556,6 +3751,18 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_FST */
 
+#ifdef CONFIG_DPP
+       if (category == WLAN_ACTION_PUBLIC && plen >= 5 &&
+           payload[0] == WLAN_PA_VENDOR_SPECIFIC &&
+           WPA_GET_BE24(&payload[1]) == OUI_WFA &&
+           payload[4] == DPP_OUI_TYPE) {
+               payload++;
+               plen--;
+               wpas_dpp_rx_action(wpa_s, mgmt->sa, payload, plen, freq);
+               return;
+       }
+#endif /* CONFIG_DPP */
+
        wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
                           category, payload, plen, freq);
        if (wpa_s->ifmsh)
@@ -3596,23 +3803,226 @@ static void wpa_supplicant_notify_avoid_freq(struct wpa_supplicant *wpa_s,
 }
 
 
-static void wpa_supplicant_event_assoc_auth(struct wpa_supplicant *wpa_s,
-                                           union wpa_event_data *data)
+static void wpa_supplicant_event_port_authorized(struct wpa_supplicant *wpa_s)
 {
-       wpa_dbg(wpa_s, MSG_DEBUG,
-               "Connection authorized by device, previous state %d",
-               wpa_s->wpa_state);
        if (wpa_s->wpa_state == WPA_ASSOCIATED) {
                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);
        }
+}
+
+
+static unsigned int wpas_event_cac_ms(const struct wpa_supplicant *wpa_s,
+                                     int freq)
+{
+       size_t i;
+       int j;
+
+       for (i = 0; i < wpa_s->hw.num_modes; i++) {
+               const struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i];
+
+               for (j = 0; j < mode->num_channels; j++) {
+                       const struct hostapd_channel_data *chan;
+
+                       chan = &mode->channels[j];
+                       if (chan->freq == freq)
+                               return chan->dfs_cac_ms;
+               }
+       }
+
+       return 0;
+}
+
+
+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) {
+               wpas_ap_event_dfs_cac_started(wpa_s, radar);
+       } else
+#endif /* NEED_AP_MLME && CONFIG_AP */
+       {
+               unsigned int cac_time = wpas_event_cac_ms(wpa_s, radar->freq);
+
+               cac_time /= 1000; /* convert from ms to sec */
+               if (!cac_time)
+                       cac_time = 10 * 60; /* max timeout: 10 minutes */
+
+               /* Restart auth timeout: CAC time added to initial timeout */
+               wpas_auth_timeout_restart(wpa_s, cac_time);
+       }
+}
+
+
+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) {
+               wpas_ap_event_dfs_cac_finished(wpa_s, radar);
+       } else
+#endif /* NEED_AP_MLME && CONFIG_AP */
+       {
+               /* Restart auth timeout with original value after CAC is
+                * finished */
+               wpas_auth_timeout_restart(wpa_s, 0);
+       }
+}
+
+
+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) {
+               wpas_ap_event_dfs_cac_aborted(wpa_s, radar);
+       } else
+#endif /* NEED_AP_MLME && CONFIG_AP */
+       {
+               /* Restart auth timeout with original value after CAC is
+                * aborted */
+               wpas_auth_timeout_restart(wpa_s, 0);
+       }
+}
+
+
+static void wpa_supplicant_event_assoc_auth(struct wpa_supplicant *wpa_s,
+                                           union wpa_event_data *data)
+{
+       wpa_dbg(wpa_s, MSG_DEBUG,
+               "Connection authorized by device, previous state %d",
+               wpa_s->wpa_state);
+
+       wpa_supplicant_event_port_authorized(wpa_s);
+
        wpa_sm_set_rx_replay_ctr(wpa_s->wpa, data->assoc_info.key_replay_ctr);
        wpa_sm_set_ptk_kck_kek(wpa_s->wpa, data->assoc_info.ptk_kck,
                               data->assoc_info.ptk_kck_len,
                               data->assoc_info.ptk_kek,
                               data->assoc_info.ptk_kek_len);
+#ifdef CONFIG_FILS
+       if (wpa_s->auth_alg == WPA_AUTH_ALG_FILS) {
+               struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, wpa_s->bssid);
+               const u8 *fils_cache_id = wpa_bss_get_fils_cache_id(bss);
+
+               /* Update ERP next sequence number */
+               eapol_sm_update_erp_next_seq_num(
+                       wpa_s->eapol, data->assoc_info.fils_erp_next_seq_num);
+
+               if (data->assoc_info.fils_pmk && data->assoc_info.fils_pmkid) {
+                       /* Add the new PMK and PMKID to the PMKSA cache */
+                       wpa_sm_pmksa_cache_add(wpa_s->wpa,
+                                              data->assoc_info.fils_pmk,
+                                              data->assoc_info.fils_pmk_len,
+                                              data->assoc_info.fils_pmkid,
+                                              wpa_s->bssid, fils_cache_id);
+               } else if (data->assoc_info.fils_pmkid) {
+                       /* Update the current PMKSA used for this connection */
+                       pmksa_cache_set_current(wpa_s->wpa,
+                                               data->assoc_info.fils_pmkid,
+                                               NULL, NULL, 0, NULL, 0);
+               }
+       }
+#endif /* CONFIG_FILS */
+}
+
+
+static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s,
+                                   union wpa_event_data *data)
+{
+       const u8 *bssid = data->assoc_reject.bssid;
+
+       if (!bssid || is_zero_ether_addr(bssid))
+               bssid = wpa_s->pending_bssid;
+
+       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 */
+
+       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);
 }
 
 
@@ -3669,9 +4079,17 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                   "EVENT_ASSOC - ignore_auth_resp active!");
                        break;
                }
+               if (wpa_s->testing_resend_assoc) {
+                       wpa_printf(MSG_INFO,
+                                  "EVENT_DEAUTH - testing_resend_assoc");
+                       break;
+               }
 #endif /* CONFIG_TESTING_OPTIONS */
                wpa_supplicant_event_assoc(wpa_s, data);
-               if (data && data->assoc_info.authorized)
+               if (data &&
+                   (data->assoc_info.authorized ||
+                    (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+                     wpa_fils_is_completed(wpa_s->wpa))))
                        wpa_supplicant_event_assoc_auth(wpa_s, data);
                if (data) {
                        wpa_msg(wpa_s, MSG_INFO,
@@ -3690,6 +4108,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                   "EVENT_DEAUTH - ignore_auth_resp active!");
                        break;
                }
+               if (wpa_s->testing_resend_assoc) {
+                       wpa_printf(MSG_INFO,
+                                  "EVENT_DEAUTH - testing_resend_assoc");
+                       break;
+               }
 #endif /* CONFIG_TESTING_OPTIONS */
                wpas_event_deauth(wpa_s,
                                  data ? &data->deauth_info : NULL);
@@ -3762,11 +4185,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
        case EVENT_PMKID_CANDIDATE:
                wpa_supplicant_event_pmkid_candidate(wpa_s, data);
                break;
-#ifdef CONFIG_PEERKEY
-       case EVENT_STKSTART:
-               wpa_supplicant_event_stkstart(wpa_s, data);
-               break;
-#endif /* CONFIG_PEERKEY */
 #ifdef CONFIG_TDLS
        case EVENT_TDLS:
                wpa_supplicant_event_tdls(wpa_s, data);
@@ -3788,34 +4206,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);
-               if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
-                       sme_event_assoc_reject(wpa_s, data);
-               else {
-                       const u8 *bssid = data->assoc_reject.bssid;
-                       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 */
@@ -3917,6 +4308,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                ap_rx_from_unknown_sta(wpa_s, data->rx_from_unknown.addr,
                                       data->rx_from_unknown.wds);
                break;
+#endif /* CONFIG_AP */
        case EVENT_CH_SWITCH:
                if (!data || !wpa_s->current_ssid)
                        break;
@@ -3933,6 +4325,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                wpa_s->assoc_freq = data->ch_switch.freq;
                wpa_s->current_ssid->frequency = data->ch_switch.freq;
 
+#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 ==
@@ -3944,14 +4337,25 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                          data->ch_switch.cf1,
                                          data->ch_switch.cf2);
                }
+#endif /* CONFIG_AP */
 
                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
        case EVENT_DFS_RADAR_DETECTED:
                if (data)
-                       wpas_event_dfs_radar_detected(wpa_s, &data->dfs_event);
+                       wpas_ap_event_dfs_radar_detected(wpa_s,
+                                                        &data->dfs_event);
                break;
+       case EVENT_DFS_NOP_FINISHED:
+               if (data)
+                       wpas_ap_event_dfs_cac_nop_finished(wpa_s,
+                                                          &data->dfs_event);
+               break;
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_AP */
        case EVENT_DFS_CAC_STARTED:
                if (data)
                        wpas_event_dfs_cac_started(wpa_s, &data->dfs_event);
@@ -3964,13 +4368,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                if (data)
                        wpas_event_dfs_cac_aborted(wpa_s, &data->dfs_event);
                break;
-       case EVENT_DFS_NOP_FINISHED:
-               if (data)
-                       wpas_event_dfs_cac_nop_finished(wpa_s,
-                                                       &data->dfs_event);
-               break;
-#endif /* NEED_AP_MLME */
-#endif /* CONFIG_AP */
        case EVENT_RX_MGMT: {
                u16 fc, stype;
                const struct ieee80211_mgmt *mgmt;
@@ -4042,6 +4439,16 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                break;
                        }
 
+#ifdef CONFIG_SAE
+                       if (stype == WLAN_FC_STYPE_AUTH &&
+                           !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+                           (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) {
+                               sme_external_auth_mgmt_rx(
+                                       wpa_s, data->rx_mgmt.frame,
+                                       data->rx_mgmt.frame_len);
+                               break;
+                       }
+#endif /* CONFIG_SAE */
                        wpa_dbg(wpa_s, MSG_DEBUG, "AP: ignore received "
                                "management frame in non-AP mode");
                        break;
@@ -4106,6 +4513,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 #endif /* CONFIG_OFFCHANNEL */
                wpas_p2p_cancel_remain_on_channel_cb(
                        wpa_s, data->remain_on_channel.freq);
+#ifdef CONFIG_DPP
+               wpas_dpp_cancel_remain_on_channel_cb(
+                       wpa_s, data->remain_on_channel.freq);
+#endif /* CONFIG_DPP */
                break;
        case EVENT_EAPOL_RX:
                wpa_supplicant_rx_eapol(wpa_s, data->eapol_rx.src,
@@ -4127,6 +4538,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                        data->signal_change.current_noise,
                        data->signal_change.current_txrate);
                break;
+       case EVENT_INTERFACE_MAC_CHANGED:
+               wpa_supplicant_update_mac_addr(wpa_s);
+               break;
        case EVENT_INTERFACE_ENABLED:
                wpa_dbg(wpa_s, MSG_DEBUG, "Interface was enabled");
                if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
@@ -4350,6 +4764,30 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_BEACON_LOSS);
                bgscan_notify_beacon_loss(wpa_s);
                break;
+       case EVENT_EXTERNAL_AUTH:
+#ifdef CONFIG_SAE
+               if (!wpa_s->current_ssid) {
+                       wpa_printf(MSG_DEBUG, "SAE: current_ssid is NULL");
+                       break;
+               }
+               sme_external_auth_trigger(wpa_s, data);
+#endif /* CONFIG_SAE */
+               break;
+       case EVENT_PORT_AUTHORIZED:
+               wpa_supplicant_event_port_authorized(wpa_s);
+               break;
+       case EVENT_STATION_OPMODE_CHANGED:
+#ifdef CONFIG_AP
+               if (!wpa_s->ap_iface || !data)
+                       break;
+
+               hostapd_event_sta_opmode_changed(wpa_s->ap_iface->bss[0],
+                                                data->sta_opmode.addr,
+                                                data->sta_opmode.smps_mode,
+                                                data->sta_opmode.chan_width,
+                                                data->sta_opmode.rx_nss);
+#endif /* CONFIG_AP */
+               break;
        default:
                wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
                break;