]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - wpa_supplicant/wpa_supplicant.c
Test functionality to override driver reported signal levels
[thirdparty/hostap.git] / wpa_supplicant / wpa_supplicant.c
index feeafc62073addeb8c047e6d9c32332ec05efecb..0a9e37c3b01cd530d86d810d0763eb343cf80cb0 100644 (file)
 #include "rsn_supp/preauth.h"
 #include "rsn_supp/pmksa_cache.h"
 #include "common/wpa_ctrl.h"
+#include "common/ieee802_11_common.h"
 #include "common/ieee802_11_defs.h"
 #include "common/hw_features_common.h"
 #include "common/gas_server.h"
+#include "common/dpp.h"
 #include "p2p/p2p.h"
 #include "fst/fst.h"
 #include "blacklist.h"
@@ -123,6 +125,9 @@ static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx);
 #if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
 static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s);
 #endif /* CONFIG_FILS && IEEE8021X_EAPOL */
+#ifdef CONFIG_OWE
+static void wpas_update_owe_connect_params(struct wpa_supplicant *wpa_s);
+#endif /* CONFIG_OWE */
 
 
 /* Configure default/group WEP keys for static WEP */
@@ -397,7 +402,10 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
                wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
        wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
        wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
+       wpa_sm_set_ap_rsnxe(wpa_s->wpa, NULL, 0);
        wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+       wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+       wpa_s->rsnxe_len = 0;
        wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
        wpa_s->group_cipher = WPA_CIPHER_NONE;
        wpa_s->mgmt_group_cipher = 0;
@@ -419,10 +427,8 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
        wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
                         wpa_s->pairwise_cipher);
        wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
-#ifdef CONFIG_IEEE80211W
        wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
                         wpa_s->mgmt_group_cipher);
-#endif /* CONFIG_IEEE80211W */
 
        pmksa_cache_clear_current(wpa_s->wpa);
 }
@@ -470,6 +476,31 @@ void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s)
 }
 
 
+void wpas_clear_disabled_interface(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+
+       if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
+               return;
+       wpa_dbg(wpa_s, MSG_DEBUG, "Clear cached state on disabled interface");
+       wpa_bss_flush(wpa_s);
+}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+void wpas_clear_driver_signal_override(struct wpa_supplicant *wpa_s)
+{
+       struct driver_signal_override *dso;
+
+       while ((dso = dl_list_first(&wpa_s->drv_signal_override,
+                                   struct driver_signal_override, list))) {
+               dl_list_del(&dso->list);
+               os_free(dso);
+       }
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
 static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 {
        int i;
@@ -493,6 +524,13 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
        wpa_s->get_pref_freq_list_override = NULL;
        wpabuf_free(wpa_s->last_assoc_req_wpa_ie);
        wpa_s->last_assoc_req_wpa_ie = NULL;
+       os_free(wpa_s->extra_sae_rejected_groups);
+       wpa_s->extra_sae_rejected_groups = NULL;
+       wpabuf_free(wpa_s->rsnxe_override_assoc);
+       wpa_s->rsnxe_override_assoc = NULL;
+       wpabuf_free(wpa_s->rsnxe_override_eapol);
+       wpa_s->rsnxe_override_eapol = NULL;
+       wpas_clear_driver_signal_override(wpa_s);
 #endif /* CONFIG_TESTING_OPTIONS */
 
        if (wpa_s->conf != NULL) {
@@ -539,6 +577,7 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 #endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
 
        eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+       eloop_cancel_timeout(wpas_clear_disabled_interface, wpa_s, NULL);
 
        wpas_wps_deinit(wpa_s);
 
@@ -672,6 +711,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 
 #ifdef CONFIG_DPP
        wpas_dpp_deinit(wpa_s);
+       dpp_global_deinit(wpa_s->dpp);
+       wpa_s->dpp = NULL;
 #endif /* CONFIG_DPP */
 }
 
@@ -686,13 +727,7 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
  */
 void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
 {
-       int i, max;
-
-#ifdef CONFIG_IEEE80211W
-       max = 6;
-#else /* CONFIG_IEEE80211W */
-       max = 4;
-#endif /* CONFIG_IEEE80211W */
+       int i, max = 6;
 
        /* MLME-DELETEKEYS.request */
        for (i = 0; i < max; i++) {
@@ -841,6 +876,9 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
                              enum wpa_states state)
 {
        enum wpa_states old_state = wpa_s->wpa_state;
+#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
+       Boolean update_fils_connect_params = FALSE;
+#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
 
        wpa_dbg(wpa_s, MSG_DEBUG, "State: %s -> %s",
                wpa_supplicant_state_txt(wpa_s->wpa_state),
@@ -938,8 +976,12 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
 
 #if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
                if (!fils_hlp_sent && ssid && ssid->eap.erp)
-                       wpas_update_fils_connect_params(wpa_s);
+                       update_fils_connect_params = TRUE;
 #endif /* CONFIG_FILS && IEEE8021X_EAPOL */
+#ifdef CONFIG_OWE
+               if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_OWE))
+                       wpas_update_owe_connect_params(wpa_s);
+#endif /* CONFIG_OWE */
        } else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
                   state == WPA_ASSOCIATED) {
                wpa_s->new_connection = 1;
@@ -958,7 +1000,7 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
                wpa_supplicant_stop_bgscan(wpa_s);
 #endif /* CONFIG_BGSCAN */
 
-       if (state == WPA_AUTHENTICATING)
+       if (state > WPA_SCANNING)
                wpa_supplicant_stop_autoscan(wpa_s);
 
        if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
@@ -979,7 +1021,15 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
                if (wpa_s->wpa_state == WPA_COMPLETED ||
                    old_state == WPA_COMPLETED)
                        wpas_notify_auth_changed(wpa_s);
+#ifdef CONFIG_DPP2
+               if (wpa_s->wpa_state == WPA_COMPLETED)
+                       wpas_dpp_connected(wpa_s);
+#endif /* CONFIG_DPP2 */
        }
+#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
+       if (update_fils_connect_params)
+               wpas_update_fils_connect_params(wpa_s);
+#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
 }
 
 
@@ -1175,7 +1225,6 @@ static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
                return -1;
        }
 
-#ifdef CONFIG_IEEE80211W
        if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
            wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
                wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
@@ -1183,12 +1232,23 @@ static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
                        "reject");
                return -1;
        }
-#endif /* CONFIG_IEEE80211W */
 
        return 0;
 }
 
 
+static int matching_ciphers(struct wpa_ssid *ssid, struct wpa_ie_data *ie,
+                           int freq)
+{
+       if (!ie->has_group)
+               ie->group_cipher = wpa_default_rsn_cipher(freq);
+       if (!ie->has_pairwise)
+               ie->pairwise_cipher = wpa_default_rsn_cipher(freq);
+       return (ie->group_cipher & ssid->group_cipher) &&
+               (ie->pairwise_cipher & ssid->pairwise_cipher);
+}
+
+
 /**
  * wpa_supplicant_set_suites - Set authentication and encryption parameters
  * @wpa_s: Pointer to wpa_supplicant data
@@ -1209,19 +1269,20 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 {
        struct wpa_ie_data ie;
        int sel, proto;
-       const u8 *bss_wpa, *bss_rsn, *bss_osen;
+       const u8 *bss_wpa, *bss_rsn, *bss_rsnx, *bss_osen;
 
        if (bss) {
                bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
                bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+               bss_rsnx = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
                bss_osen = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
-       } else
-               bss_wpa = bss_rsn = bss_osen = NULL;
+       } else {
+               bss_wpa = bss_rsn = bss_rsnx = bss_osen = NULL;
+       }
 
        if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) &&
            wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
-           (ie.group_cipher & ssid->group_cipher) &&
-           (ie.pairwise_cipher & ssid->pairwise_cipher) &&
+           matching_ciphers(ssid, &ie, bss->freq) &&
            (ie.key_mgmt & ssid->key_mgmt)) {
                wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
                proto = WPA_PROTO_RSN;
@@ -1297,7 +1358,6 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                        ie.group_cipher = ssid->group_cipher;
                        ie.pairwise_cipher = ssid->pairwise_cipher;
                        ie.key_mgmt = ssid->key_mgmt;
-#ifdef CONFIG_IEEE80211W
                        ie.mgmt_group_cipher = 0;
                        if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
                                if (ssid->group_mgmt_cipher &
@@ -1316,7 +1376,6 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                                        ie.mgmt_group_cipher =
                                                WPA_CIPHER_AES_128_CMAC;
                        }
-#endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_OWE
                        if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
                            !ssid->owe_only &&
@@ -1336,12 +1395,10 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
        wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected cipher suites: group %d "
                "pairwise %d key_mgmt %d proto %d",
                ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt, proto);
-#ifdef CONFIG_IEEE80211W
        if (ssid->ieee80211w) {
                wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected mgmt group cipher %d",
                        ie.mgmt_group_cipher);
        }
-#endif /* CONFIG_IEEE80211W */
 
        wpa_s->wpa_proto = proto;
        wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
@@ -1352,7 +1409,9 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
                                         bss_wpa ? 2 + bss_wpa[1] : 0) ||
                    wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
-                                        bss_rsn ? 2 + bss_rsn[1] : 0))
+                                        bss_rsn ? 2 + bss_rsn[1] : 0) ||
+                   wpa_sm_set_ap_rsnxe(wpa_s->wpa, bss_rsnx,
+                                       bss_rsnx ? 2 + bss_rsnx[1] : 0))
                        return -1;
        }
 
@@ -1361,6 +1420,9 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
        wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
 #else /* CONFIG_NO_WPA */
        sel = ie.group_cipher & ssid->group_cipher;
+       wpa_dbg(wpa_s, MSG_DEBUG,
+               "WPA: AP group 0x%x network profile group 0x%x; available group 0x%x",
+               ie.group_cipher, ssid->group_cipher, sel);
        wpa_s->group_cipher = wpa_pick_group_cipher(sel);
        if (wpa_s->group_cipher < 0) {
                wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select group "
@@ -1371,6 +1433,9 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                wpa_cipher_txt(wpa_s->group_cipher));
 
        sel = ie.pairwise_cipher & ssid->pairwise_cipher;
+       wpa_dbg(wpa_s, MSG_DEBUG,
+               "WPA: AP pairwise 0x%x network profile pairwise 0x%x; available pairwise 0x%x",
+               ie.pairwise_cipher, ssid->pairwise_cipher, sel);
        wpa_s->pairwise_cipher = wpa_pick_pairwise_cipher(sel, 1);
        if (wpa_s->pairwise_cipher < 0) {
                wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select pairwise "
@@ -1382,11 +1447,31 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_NO_WPA */
 
        sel = ie.key_mgmt & ssid->key_mgmt;
+       wpa_dbg(wpa_s, MSG_DEBUG,
+               "WPA: AP key_mgmt 0x%x network profile key_mgmt 0x%x; available key_mgmt 0x%x",
+               ie.key_mgmt, ssid->key_mgmt, sel);
 #ifdef CONFIG_SAE
        if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE))
                sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
 #endif /* CONFIG_SAE */
        if (0) {
+#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_SHA384
+       } else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) &&
+                  os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) {
+               wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "WPA: using KEY_MGMT FT/802.1X-SHA384");
+               if (!ssid->ft_eap_pmksa_caching &&
+                   pmksa_cache_get_current(wpa_s->wpa)) {
+                       /* PMKSA caching with FT may have interoperability
+                        * issues, so disable that case by default for now. */
+                       wpa_dbg(wpa_s, MSG_DEBUG,
+                               "WPA: Disable PMKSA caching for FT/802.1X connection");
+                       pmksa_cache_clear_current(wpa_s->wpa);
+               }
+#endif /* CONFIG_SHA384 */
+#endif /* CONFIG_IEEE80211R */
 #ifdef CONFIG_SUITEB192
        } else if (sel & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
                wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
@@ -1416,42 +1501,37 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA256");
 #endif /* CONFIG_FILS */
 #ifdef CONFIG_IEEE80211R
-#ifdef CONFIG_SHA384
-       } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
-               wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
-               wpa_dbg(wpa_s, MSG_DEBUG,
-                       "WPA: using KEY_MGMT FT/802.1X-SHA384");
-               if (pmksa_cache_get_current(wpa_s->wpa)) {
-                       /* PMKSA caching with FT is not fully functional, so
-                        * disable the case for now. */
-                       wpa_dbg(wpa_s, MSG_DEBUG,
-                               "WPA: Disable PMKSA caching for FT/802.1X connection");
-                       pmksa_cache_clear_current(wpa_s->wpa);
-               }
-#endif /* CONFIG_SHA384 */
-       } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
+       } else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X) &&
+                  os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) {
                wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
                wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/802.1X");
-               if (pmksa_cache_get_current(wpa_s->wpa)) {
-                       /* PMKSA caching with FT is not fully functional, so
-                        * disable the case for now. */
+               if (!ssid->ft_eap_pmksa_caching &&
+                   pmksa_cache_get_current(wpa_s->wpa)) {
+                       /* PMKSA caching with FT may have interoperability
+                        * issues, so disable that case by default for now. */
                        wpa_dbg(wpa_s, MSG_DEBUG,
                                "WPA: Disable PMKSA caching for FT/802.1X connection");
                        pmksa_cache_clear_current(wpa_s->wpa);
                }
-       } else if (sel & WPA_KEY_MGMT_FT_PSK) {
-               wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
-               wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_DPP
+       } else if (sel & WPA_KEY_MGMT_DPP) {
+               wpa_s->key_mgmt = WPA_KEY_MGMT_DPP;
+               wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT DPP");
+#endif /* CONFIG_DPP */
 #ifdef CONFIG_SAE
-       } else if (sel & WPA_KEY_MGMT_SAE) {
-               wpa_s->key_mgmt = WPA_KEY_MGMT_SAE;
-               wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE");
        } else if (sel & WPA_KEY_MGMT_FT_SAE) {
                wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE;
                wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT FT/SAE");
+       } else if (sel & WPA_KEY_MGMT_SAE) {
+               wpa_s->key_mgmt = WPA_KEY_MGMT_SAE;
+               wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE");
 #endif /* CONFIG_SAE */
-#ifdef CONFIG_IEEE80211W
+#ifdef CONFIG_IEEE80211R
+       } else if (sel & WPA_KEY_MGMT_FT_PSK) {
+               wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
+#endif /* CONFIG_IEEE80211R */
        } else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
                wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
                wpa_dbg(wpa_s, MSG_DEBUG,
@@ -1460,7 +1540,6 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                wpa_s->key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
                wpa_dbg(wpa_s, MSG_DEBUG,
                        "WPA: using KEY_MGMT PSK with SHA256");
-#endif /* CONFIG_IEEE80211W */
        } else if (sel & WPA_KEY_MGMT_IEEE8021X) {
                wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
                wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X");
@@ -1480,11 +1559,6 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                wpa_s->key_mgmt = WPA_KEY_MGMT_OWE;
                wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT OWE");
 #endif /* CONFIG_OWE */
-#ifdef CONFIG_DPP
-       } else if (sel & WPA_KEY_MGMT_DPP) {
-               wpa_s->key_mgmt = WPA_KEY_MGMT_DPP;
-               wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT DPP");
-#endif /* CONFIG_DPP */
        } else {
                wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select "
                        "authenticated key management type");
@@ -1496,13 +1570,22 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                         wpa_s->pairwise_cipher);
        wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
 
-#ifdef CONFIG_IEEE80211W
+       if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
+           wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
+               wpa_msg(wpa_s, MSG_INFO,
+                       "RSN: Management frame protection required but the selected AP does not enable it");
+               return -1;
+       }
+
        sel = ie.mgmt_group_cipher;
        if (ssid->group_mgmt_cipher)
                sel &= ssid->group_mgmt_cipher;
        if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION ||
            !(ie.capabilities & WPA_CAPABILITY_MFPC))
                sel = 0;
+       wpa_dbg(wpa_s, MSG_DEBUG,
+               "WPA: AP mgmt_group_cipher 0x%x network profile mgmt_group_cipher 0x%x; available mgmt_group_cipher 0x%x",
+               ie.mgmt_group_cipher, ssid->group_mgmt_cipher, sel);
        if (sel & WPA_CIPHER_AES_128_CMAC) {
                wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
                wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
@@ -1527,17 +1610,30 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                         wpa_s->mgmt_group_cipher);
        wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
                         wpas_get_ssid_pmf(wpa_s, ssid));
-#endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_OCV
        wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, ssid->ocv);
 #endif /* CONFIG_OCV */
+       wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PWE, wpa_s->conf->sae_pwe);
 
        if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
                wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE");
                return -1;
        }
 
-       if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
+       wpa_s->rsnxe_len = sizeof(wpa_s->rsnxe);
+       if (wpa_sm_set_assoc_rsnxe_default(wpa_s->wpa, wpa_s->rsnxe,
+                                          &wpa_s->rsnxe_len)) {
+               wpa_msg(wpa_s, MSG_WARNING, "RSN: Failed to generate RSNXE");
+               return -1;
+       }
+
+       if (0) {
+#ifdef CONFIG_DPP
+       } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP) {
+               /* Use PMK from DPP network introduction (PMKSA entry) */
+               wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
+#endif /* CONFIG_DPP */
+       } else if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
                int psk_set = 0;
                int sae_only;
 
@@ -1672,7 +1768,8 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
        case 2: /* Bits 16-23 */
 #ifdef CONFIG_WNM
                *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
-               *pos |= 0x08; /* Bit 19 - BSS Transition */
+               if (!wpa_s->disable_mbo_oce && !wpa_s->conf->disable_btm)
+                       *pos |= 0x08; /* Bit 19 - BSS Transition */
 #endif /* CONFIG_WNM */
                break;
        case 3: /* Bits 24-31 */
@@ -1878,6 +1975,58 @@ int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s)
 }
 
 
+static void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_SAE
+       int *groups = conf->sae_groups;
+       int default_groups[] = { 19, 20, 21, 0 };
+       const char *password;
+
+       if (!groups || groups[0] <= 0)
+               groups = default_groups;
+
+       password = ssid->sae_password;
+       if (!password)
+               password = ssid->passphrase;
+
+       if (conf->sae_pwe == 0 || !password) {
+               /* PT derivation not needed */
+               sae_deinit_pt(ssid->pt);
+               ssid->pt = NULL;
+               return;
+       }
+
+       if (ssid->pt)
+               return; /* PT already derived */
+       ssid->pt = sae_derive_pt(groups, ssid->ssid, ssid->ssid_len,
+                                (const u8 *) password, os_strlen(password),
+                                ssid->sae_password_id);
+#endif /* CONFIG_SAE */
+}
+
+
+static void wpa_s_clear_sae_rejected(struct wpa_supplicant *wpa_s)
+{
+#if defined(CONFIG_SAE) && defined(CONFIG_SME)
+       os_free(wpa_s->sme.sae_rejected_groups);
+       wpa_s->sme.sae_rejected_groups = NULL;
+#ifdef CONFIG_TESTING_OPTIONS
+       if (wpa_s->extra_sae_rejected_groups) {
+               int i, *groups = wpa_s->extra_sae_rejected_groups;
+
+               for (i = 0; groups[i]; i++) {
+                       wpa_printf(MSG_DEBUG,
+                                  "TESTING: Indicate rejection of an extra SAE group %d",
+                                  groups[i]);
+                       int_array_add_unique(&wpa_s->sme.sae_rejected_groups,
+                                            groups[i]);
+               }
+       }
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_SAE && CONFIG_SME */
+}
+
+
 static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit);
 
 /**
@@ -1924,6 +2073,11 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                } else if (wpa_s->current_bss && wpa_s->current_bss != bss) {
                        os_get_reltime(&wpa_s->roam_start);
                }
+       } else {
+#ifdef CONFIG_SAE
+               wpa_s_clear_sae_rejected(wpa_s);
+               wpa_s_setup_sae_pt(wpa_s->conf, ssid);
+#endif /* CONFIG_SAE */
        }
 
        if (rand_style > 0 && !wpa_s->reassoc_same_ess) {
@@ -2025,8 +2179,12 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                                bss->ie_len);
 #endif /* CONFIG_TDLS */
 
+#ifdef CONFIG_MBO
+       wpas_mbo_check_pmf(wpa_s, bss, ssid);
+#endif /* CONFIG_MBO */
+
        if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
-           ssid->mode == IEEE80211_MODE_INFRA) {
+           ssid->mode == WPAS_MODE_INFRA) {
                sme_authenticate(wpa_s, bss, ssid);
                return;
        }
@@ -2100,6 +2258,7 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
                          const struct wpa_ssid *ssid,
                          struct hostapd_freq_params *freq)
 {
+       int ieee80211_mode = wpas_mode_to_ieee80211_mode(ssid->mode);
        enum hostapd_hw_mode hw_mode;
        struct hostapd_hw_modes *mode = NULL;
        int ht40plus[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
@@ -2112,6 +2271,7 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
        struct hostapd_freq_params vht_freq;
        int chwidth, seg0, seg1;
        u32 vht_caps = 0;
+       int is_24ghz;
 
        freq->freq = ssid->frequency;
 
@@ -2163,6 +2323,9 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
        if (!mode)
                return;
 
+       is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
+               hw_mode == HOSTAPD_MODE_IEEE80211B;
+
 #ifdef CONFIG_HT_OVERRIDES
        if (ssid->disable_ht) {
                freq->ht_enabled = 0;
@@ -2174,6 +2337,10 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
        if (!freq->ht_enabled)
                return;
 
+       /* Allow HE on 2.4 GHz without VHT: see nl80211_put_freq_params() */
+       if (is_24ghz)
+               freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported;
+
        /* Setup higher BW only for 5 GHz */
        if (mode->mode != HOSTAPD_MODE_IEEE80211A)
                return;
@@ -2191,9 +2358,14 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
        if (pri_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
                return;
 
+       freq->channel = pri_chan->chan;
+
 #ifdef CONFIG_HT_OVERRIDES
-       if (ssid->disable_ht40)
-               return;
+       if (ssid->disable_ht40) {
+               if (ssid->disable_vht)
+                       return;
+               goto skip_ht40;
+       }
 #endif /* CONFIG_HT_OVERRIDES */
 
        /* Check/setup HT40+/HT40- */
@@ -2218,8 +2390,6 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
        if (sec_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
                return;
 
-       freq->channel = pri_chan->chan;
-
        if (ht40 == -1) {
                if (!(pri_chan->flag & HOSTAPD_CHAN_HT40MINUS))
                        return;
@@ -2239,8 +2409,7 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
                        return;
                }
 
-               res = check_40mhz_5g(mode, scan_res, pri_chan->chan,
-                                    sec_chan->chan);
+               res = check_40mhz_5g(scan_res, pri_chan, sec_chan);
                switch (res) {
                case 0:
                        /* Back to HT20 */
@@ -2263,6 +2432,9 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
                wpa_scan_results_free(scan_res);
        }
 
+#ifdef CONFIG_HT_OVERRIDES
+skip_ht40:
+#endif /* CONFIG_HT_OVERRIDES */
        wpa_printf(MSG_DEBUG,
                   "IBSS/mesh: setup freq channel %d, sec_channel_offset %d",
                   freq->channel, freq->sec_channel_offset);
@@ -2288,6 +2460,9 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
        if (!vht_freq.vht_enabled)
                return;
 
+       /* Enable HE for VHT */
+       vht_freq.he_enabled = mode->he_capab[ieee80211_mode].he_supported;
+
        /* setup center_freq1, bandwidth */
        for (j = 0; j < ARRAY_SIZE(vht80); j++) {
                if (freq->channel >= vht80[j] &&
@@ -2310,11 +2485,11 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
                        return;
        }
 
-       chwidth = VHT_CHANWIDTH_80MHZ;
+       chwidth = CHANWIDTH_80MHZ;
        seg0 = vht80[j] + 6;
        seg1 = 0;
 
-       if (ssid->max_oper_chwidth == VHT_CHANWIDTH_80P80MHZ) {
+       if (ssid->max_oper_chwidth == CHANWIDTH_80P80MHZ) {
                /* setup center_freq2, bandwidth */
                for (k = 0; k < ARRAY_SIZE(vht80); k++) {
                        /* Only accept 80 MHz segments separated by a gap */
@@ -2333,35 +2508,41 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
                                        continue;
 
                                /* Found a suitable second segment for 80+80 */
-                               chwidth = VHT_CHANWIDTH_80P80MHZ;
+                               chwidth = CHANWIDTH_80P80MHZ;
                                vht_caps |=
                                        VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
                                seg1 = vht80[k] + 6;
                        }
 
-                       if (chwidth == VHT_CHANWIDTH_80P80MHZ)
+                       if (chwidth == CHANWIDTH_80P80MHZ)
                                break;
                }
-       } else if (ssid->max_oper_chwidth == VHT_CHANWIDTH_160MHZ) {
+       } else if (ssid->max_oper_chwidth == CHANWIDTH_160MHZ) {
                if (freq->freq == 5180) {
-                       chwidth = VHT_CHANWIDTH_160MHZ;
+                       chwidth = CHANWIDTH_160MHZ;
                        vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
                        seg0 = 50;
                } else if (freq->freq == 5520) {
-                       chwidth = VHT_CHANWIDTH_160MHZ;
+                       chwidth = CHANWIDTH_160MHZ;
                        vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
                        seg0 = 114;
                }
-       } else if (ssid->max_oper_chwidth == VHT_CHANWIDTH_USE_HT) {
-               chwidth = VHT_CHANWIDTH_USE_HT;
+       } else if (ssid->max_oper_chwidth == CHANWIDTH_USE_HT) {
+               chwidth = CHANWIDTH_USE_HT;
                seg0 = vht80[j] + 2;
+#ifdef CONFIG_HT_OVERRIDES
+               if (ssid->disable_ht40)
+                       seg0 = 0;
+#endif /* CONFIG_HT_OVERRIDES */
        }
 
        if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
-                                   freq->channel, freq->ht_enabled,
-                                   vht_freq.vht_enabled,
+                                   freq->channel, ssid->enable_edmg,
+                                   ssid->edmg_channel, freq->ht_enabled,
+                                   vht_freq.vht_enabled, freq->he_enabled,
                                    freq->sec_channel_offset,
-                                   chwidth, seg0, seg1, vht_caps) != 0)
+                                   chwidth, seg0, seg1, vht_caps,
+                                   &mode->he_capab[ieee80211_mode]) != 0)
                return;
 
        *freq = vht_freq;
@@ -2475,6 +2656,9 @@ static u8 * wpas_populate_assoc_ies(
 #ifdef CONFIG_MBO
        const u8 *mbo_ie;
 #endif
+#ifdef CONFIG_SAE
+       int sae_pmksa_cached = 0;
+#endif /* CONFIG_SAE */
 #ifdef CONFIG_FILS
        const u8 *realm, *username, *rrk;
        size_t realm_len, username_len, rrk_len;
@@ -2512,8 +2696,12 @@ static u8 * wpas_populate_assoc_ies(
 #endif /* CONFIG_FILS */
                if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
                                            ssid, try_opportunistic,
-                                           cache_id, 0) == 0)
+                                           cache_id, 0) == 0) {
                        eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
+#ifdef CONFIG_SAE
+                       sae_pmksa_cached = 1;
+#endif /* CONFIG_SAE */
+               }
                wpa_ie_len = max_wpa_ie_len;
                if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
                                              wpa_ie, &wpa_ie_len)) {
@@ -2626,6 +2814,14 @@ static u8 * wpas_populate_assoc_ies(
                        "Overriding auth_alg selection: 0x%x", algs);
        }
 
+#ifdef CONFIG_SAE
+       if (sae_pmksa_cached && algs == WPA_AUTH_ALG_SAE) {
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "SAE: Use WPA_AUTH_ALG_OPEN for PMKSA caching attempt");
+               algs = WPA_AUTH_ALG_OPEN;
+       }
+#endif /* CONFIG_SAE */
+
 #ifdef CONFIG_P2P
        if (wpa_s->global->p2p) {
                u8 *pos;
@@ -2658,7 +2854,7 @@ static u8 * wpas_populate_assoc_ies(
 #endif /* CONFIG_P2P */
 
        if (bss) {
-               wpa_ie_len += wpas_supp_op_class_ie(wpa_s, bss->freq,
+               wpa_ie_len += wpas_supp_op_class_ie(wpa_s, ssid, bss->freq,
                                                    wpa_ie + wpa_ie_len,
                                                    max_wpa_ie_len -
                                                    wpa_ie_len);
@@ -2745,7 +2941,7 @@ static u8 * wpas_populate_assoc_ies(
 
 #ifdef CONFIG_MBO
        mbo_ie = bss ? wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE) : NULL;
-       if (mbo_ie) {
+       if (!wpa_s->disable_mbo_oce && mbo_ie) {
                int len;
 
                len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
@@ -2800,11 +2996,33 @@ static u8 * wpas_populate_assoc_ies(
                        os_memcpy(wpa_ie + wpa_ie_len,
                                  wpabuf_head(owe_ie), wpabuf_len(owe_ie));
                        wpa_ie_len += wpabuf_len(owe_ie);
-                       wpabuf_free(owe_ie);
                }
+               wpabuf_free(owe_ie);
        }
 #endif /* CONFIG_OWE */
 
+#ifdef CONFIG_DPP2
+       if (wpa_sm_get_key_mgmt(wpa_s->wpa) == WPA_KEY_MGMT_DPP &&
+           ssid->dpp_netaccesskey) {
+               dpp_pfs_free(wpa_s->dpp_pfs);
+               wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey,
+                                             ssid->dpp_netaccesskey_len);
+               if (!wpa_s->dpp_pfs) {
+                       wpa_printf(MSG_DEBUG, "DPP: Could not initialize PFS");
+                       /* Try to continue without PFS */
+                       goto pfs_fail;
+               }
+               if (wpabuf_len(wpa_s->dpp_pfs->ie) <=
+                   max_wpa_ie_len - wpa_ie_len) {
+                       os_memcpy(wpa_ie + wpa_ie_len,
+                                 wpabuf_head(wpa_s->dpp_pfs->ie),
+                                 wpabuf_len(wpa_s->dpp_pfs->ie));
+                       wpa_ie_len += wpabuf_len(wpa_s->dpp_pfs->ie);
+               }
+       }
+pfs_fail:
+#endif /* CONFIG_DPP2 */
+
 #ifdef CONFIG_IEEE80211R
        /*
         * Add MDIE under these conditions: the network profile allows FT,
@@ -2838,6 +3056,23 @@ static u8 * wpas_populate_assoc_ies(
        }
 #endif /* CONFIG_IEEE80211R */
 
+#ifdef CONFIG_TESTING_OPTIONS
+       if (wpa_s->rsnxe_override_assoc &&
+           wpabuf_len(wpa_s->rsnxe_override_assoc) <=
+           max_wpa_ie_len - wpa_ie_len) {
+               wpa_printf(MSG_DEBUG, "TESTING: RSNXE AssocReq override");
+               os_memcpy(wpa_ie + wpa_ie_len,
+                         wpabuf_head(wpa_s->rsnxe_override_assoc),
+                         wpabuf_len(wpa_s->rsnxe_override_assoc));
+               wpa_ie_len += wpabuf_len(wpa_s->rsnxe_override_assoc);
+       } else
+#endif /* CONFIG_TESTING_OPTIONS */
+       if (wpa_s->rsnxe_len > 0 &&
+           wpa_s->rsnxe_len <= max_wpa_ie_len - wpa_ie_len) {
+               os_memcpy(wpa_ie + wpa_ie_len, wpa_s->rsnxe, wpa_s->rsnxe_len);
+               wpa_ie_len += wpa_s->rsnxe_len;
+       }
+
        if (ssid->multi_ap_backhaul_sta) {
                size_t multi_ap_ie_len;
 
@@ -2863,6 +3098,24 @@ static u8 * wpas_populate_assoc_ies(
 }
 
 
+#ifdef CONFIG_OWE
+static void wpas_update_owe_connect_params(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_driver_associate_params params;
+       u8 *wpa_ie;
+
+       os_memset(&params, 0, sizeof(params));
+       wpa_ie = wpas_populate_assoc_ies(wpa_s, wpa_s->current_bss,
+                                        wpa_s->current_ssid, &params, NULL);
+       if (!wpa_ie)
+               return;
+
+       wpa_drv_update_connect_params(wpa_s, &params, WPA_DRV_UPDATE_ASSOC_IES);
+       os_free(wpa_ie);
+}
+#endif /* CONFIG_OWE */
+
+
 #if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
 static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s)
 {
@@ -2891,6 +3144,145 @@ static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s)
 #endif /* CONFIG_FILS && IEEE8021X_EAPOL */
 
 
+static u8 wpa_ie_get_edmg_oper_chans(const u8 *edmg_ie)
+{
+       if (!edmg_ie || edmg_ie[1] < 6)
+               return 0;
+       return edmg_ie[EDMG_BSS_OPERATING_CHANNELS_OFFSET];
+}
+
+
+static u8 wpa_ie_get_edmg_oper_chan_width(const u8 *edmg_ie)
+{
+       if (!edmg_ie || edmg_ie[1] < 6)
+               return 0;
+       return edmg_ie[EDMG_OPERATING_CHANNEL_WIDTH_OFFSET];
+}
+
+
+/* Returns the intersection of two EDMG configurations.
+ * Note: The current implementation is limited to CB2 only (CB1 included),
+ * i.e., the implementation supports up to 2 contiguous channels.
+ * For supporting non-contiguous (aggregated) channels and for supporting
+ * CB3 and above, this function will need to be extended.
+ */
+static struct ieee80211_edmg_config
+get_edmg_intersection(struct ieee80211_edmg_config a,
+                     struct ieee80211_edmg_config b,
+                     u8 primary_channel)
+{
+       struct ieee80211_edmg_config result;
+       int i, contiguous = 0;
+       int max_contiguous = 0;
+
+       result.channels = b.channels & a.channels;
+       if (!result.channels) {
+               wpa_printf(MSG_DEBUG,
+                          "EDMG not possible: cannot intersect channels 0x%x and 0x%x",
+                          a.channels, b.channels);
+               goto fail;
+       }
+
+       if (!(result.channels & BIT(primary_channel - 1))) {
+               wpa_printf(MSG_DEBUG,
+                          "EDMG not possible: the primary channel %d is not one of the intersected channels 0x%x",
+                          primary_channel, result.channels);
+               goto fail;
+       }
+
+       /* Find max contiguous channels */
+       for (i = 0; i < 6; i++) {
+               if (result.channels & BIT(i))
+                       contiguous++;
+               else
+                       contiguous = 0;
+
+               if (contiguous > max_contiguous)
+                       max_contiguous = contiguous;
+       }
+
+       /* Assuming AP and STA supports ONLY contiguous channels,
+        * bw configuration can have value between 4-7.
+        */
+       if ((b.bw_config < a.bw_config))
+               result.bw_config = b.bw_config;
+       else
+               result.bw_config = a.bw_config;
+
+       if ((max_contiguous >= 2 && result.bw_config < EDMG_BW_CONFIG_5) ||
+           (max_contiguous >= 1 && result.bw_config < EDMG_BW_CONFIG_4)) {
+               wpa_printf(MSG_DEBUG,
+                          "EDMG not possible: not enough contiguous channels %d for supporting CB1 or CB2",
+                          max_contiguous);
+               goto fail;
+       }
+
+       return result;
+
+fail:
+       result.channels = 0;
+       result.bw_config = 0;
+       return result;
+}
+
+
+static struct ieee80211_edmg_config
+get_supported_edmg(struct wpa_supplicant *wpa_s,
+                  struct hostapd_freq_params *freq,
+                  struct ieee80211_edmg_config request_edmg)
+{
+       enum hostapd_hw_mode hw_mode;
+       struct hostapd_hw_modes *mode = NULL;
+       u8 primary_channel;
+
+       if (!wpa_s->hw.modes)
+               goto fail;
+
+       hw_mode = ieee80211_freq_to_chan(freq->freq, &primary_channel);
+       if (hw_mode == NUM_HOSTAPD_MODES)
+               goto fail;
+
+       mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, hw_mode);
+       if (!mode)
+               goto fail;
+
+       return get_edmg_intersection(mode->edmg, request_edmg, primary_channel);
+
+fail:
+       request_edmg.channels = 0;
+       request_edmg.bw_config = 0;
+       return request_edmg;
+}
+
+
+#ifdef CONFIG_MBO
+void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_driver_associate_params params;
+       u8 *wpa_ie;
+
+       /*
+        * Update MBO connect params only in case of change of MBO attributes
+        * when connected, if the AP support MBO.
+        */
+
+       if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid ||
+           !wpa_s->current_bss ||
+           !wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE))
+               return;
+
+       os_memset(&params, 0, sizeof(params));
+       wpa_ie = wpas_populate_assoc_ies(wpa_s, wpa_s->current_bss,
+                                        wpa_s->current_ssid, &params, NULL);
+       if (!wpa_ie)
+               return;
+
+       wpa_drv_update_connect_params(wpa_s, &params, WPA_DRV_UPDATE_ASSOC_IES);
+       os_free(wpa_ie);
+}
+#endif /* CONFIG_MBO */
+
+
 static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
 {
        struct wpa_connect_work *cwork = work->ctx;
@@ -2898,6 +3290,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        struct wpa_ssid *ssid = cwork->ssid;
        struct wpa_supplicant *wpa_s = work->wpa_s;
        u8 *wpa_ie;
+       const u8 *edmg_ie_oper;
        int use_crypt, ret, i, bssid_changed;
        unsigned int cipher_pairwise, cipher_group, cipher_group_mgmt;
        struct wpa_driver_associate_params params;
@@ -2990,6 +3383,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        /* Starting new association, so clear the possibly used WPA IE from the
         * previous association. */
        wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+       wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+       wpa_s->rsnxe_len = 0;
 
        wpa_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, &params, NULL);
        if (!wpa_ie) {
@@ -3081,6 +3476,71 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                        params.beacon_int = wpa_s->conf->beacon_int;
        }
 
+       if (bss && ssid->enable_edmg)
+               edmg_ie_oper = get_ie_ext((const u8 *) (bss + 1), bss->ie_len,
+                                         WLAN_EID_EXT_EDMG_OPERATION);
+       else
+               edmg_ie_oper = NULL;
+
+       if (edmg_ie_oper) {
+               params.freq.edmg.channels =
+                       wpa_ie_get_edmg_oper_chans(edmg_ie_oper);
+               params.freq.edmg.bw_config =
+                       wpa_ie_get_edmg_oper_chan_width(edmg_ie_oper);
+               wpa_printf(MSG_DEBUG,
+                          "AP supports EDMG channels 0x%x, bw_config %d",
+                          params.freq.edmg.channels,
+                          params.freq.edmg.bw_config);
+
+               /* User may ask for specific EDMG channel for EDMG connection
+                * (must be supported by AP)
+                */
+               if (ssid->edmg_channel) {
+                       struct ieee80211_edmg_config configured_edmg;
+                       enum hostapd_hw_mode hw_mode;
+                       u8 primary_channel;
+
+                       hw_mode = ieee80211_freq_to_chan(bss->freq,
+                                                        &primary_channel);
+                       if (hw_mode == NUM_HOSTAPD_MODES)
+                               goto edmg_fail;
+
+                       hostapd_encode_edmg_chan(ssid->enable_edmg,
+                                                ssid->edmg_channel,
+                                                primary_channel,
+                                                &configured_edmg);
+
+                       if (ieee802_edmg_is_allowed(params.freq.edmg,
+                                                   configured_edmg)) {
+                               params.freq.edmg = configured_edmg;
+                               wpa_printf(MSG_DEBUG,
+                                          "Use EDMG channel %d for connection",
+                                          ssid->edmg_channel);
+                       } else {
+                       edmg_fail:
+                               params.freq.edmg.channels = 0;
+                               params.freq.edmg.bw_config = 0;
+                               wpa_printf(MSG_WARNING,
+                                          "EDMG channel %d not supported by AP, fallback to DMG",
+                                          ssid->edmg_channel);
+                       }
+               }
+
+               if (params.freq.edmg.channels) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EDMG before: channels 0x%x, bw_config %d",
+                                  params.freq.edmg.channels,
+                                  params.freq.edmg.bw_config);
+                       params.freq.edmg = get_supported_edmg(wpa_s,
+                                                             &params.freq,
+                                                             params.freq.edmg);
+                       wpa_printf(MSG_DEBUG,
+                                  "EDMG after: channels 0x%x, bw_config %d",
+                                  params.freq.edmg.channels,
+                                  params.freq.edmg.bw_config);
+               }
+       }
+
        params.pairwise_suite = cipher_pairwise;
        params.group_suite = cipher_group;
        params.mgmt_group_suite = cipher_group_mgmt;
@@ -3096,7 +3556,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        }
        params.wep_tx_keyidx = ssid->wep_tx_keyidx;
 
-       if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
+       if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
            (params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
             params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) {
                params.passphrase = ssid->passphrase;
@@ -3104,6 +3564,13 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                        params.psk = ssid->psk;
        }
 
+       if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) &&
+           (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
+            params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
+            params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
+            params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192))
+               params.req_handshake_offload = 1;
+
        if (wpa_s->conf->key_mgmt_offload) {
                if (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
                    params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
@@ -3124,7 +3591,6 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
 
        params.drop_unencrypted = use_crypt;
 
-#ifdef CONFIG_IEEE80211W
        params.mgmt_frame_protection = wpas_get_ssid_pmf(wpa_s, ssid);
        if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) {
                const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
@@ -3143,7 +3609,6 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
 #endif /* CONFIG_OWE */
                }
        }
-#endif /* CONFIG_IEEE80211W */
 
        params.p2p = ssid->p2p_group;
 
@@ -3303,16 +3768,17 @@ static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
  * current AP.
  */
 void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
-                                  int reason_code)
+                                  u16 reason_code)
 {
        u8 *addr = NULL;
        union wpa_event_data event;
        int zero_addr = 0;
 
        wpa_dbg(wpa_s, MSG_DEBUG, "Request to deauthenticate - bssid=" MACSTR
-               " pending_bssid=" MACSTR " reason=%d state=%s",
+               " pending_bssid=" MACSTR " reason=%d (%s) state=%s",
                MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
-               reason_code, wpa_supplicant_state_txt(wpa_s->wpa_state));
+               reason_code, reason2str(reason_code),
+               wpa_supplicant_state_txt(wpa_s->wpa_state));
 
        if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
            (wpa_s->wpa_state == WPA_AUTHENTICATING ||
@@ -3354,7 +3820,7 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
        if (addr) {
                wpa_drv_deauthenticate(wpa_s, addr, reason_code);
                os_memset(&event, 0, sizeof(event));
-               event.deauth_info.reason_code = (u16) reason_code;
+               event.deauth_info.reason_code = reason_code;
                event.deauth_info.locally_generated = 1;
                wpa_supplicant_event(wpa_s, EVENT_DEAUTH, &event);
                if (zero_addr)
@@ -3635,9 +4101,12 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
 
        wpa_s->disconnected = 0;
        wpa_s->reassociate = 1;
+       wpa_s_clear_sae_rejected(wpa_s);
        wpa_s->last_owe_group = 0;
-       if (ssid)
+       if (ssid) {
                ssid->owe_transition_bss_select_count = 0;
+               wpa_s_setup_sae_pt(wpa_s->conf, ssid);
+       }
 
        if (wpa_s->connect_without_scan ||
            wpa_supplicant_fast_associate(wpa_s) != 1) {
@@ -3925,7 +4394,9 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
        while (entry) {
                if (!wpas_network_disabled(wpa_s, entry) &&
                    ((ssid_len == entry->ssid_len &&
-                     os_memcmp(ssid, entry->ssid, ssid_len) == 0) || wired) &&
+                     (!entry->ssid ||
+                      os_memcmp(ssid, entry->ssid, ssid_len) == 0)) ||
+                    wired) &&
                    (!entry->bssid_set ||
                     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
                        return entry;
@@ -4103,11 +4574,11 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
        }
 
        if (wpa_s->eapol_received == 0 &&
-           (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) ||
+           (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) ||
             !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
             wpa_s->wpa_state != WPA_COMPLETED) &&
            (wpa_s->current_ssid == NULL ||
-            wpa_s->current_ssid->mode != IEEE80211_MODE_IBSS)) {
+            wpa_s->current_ssid->mode != WPAS_MODE_IBSS)) {
                /* Timeout for completing IEEE 802.1X and WPA authentication */
                int timeout = 10;
 
@@ -4169,7 +4640,7 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
            eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
                return;
        wpa_drv_poll(wpa_s);
-       if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+       if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK))
                wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
        else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
                /*
@@ -4212,6 +4683,12 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
        }
 
        wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
+       wpas_wps_update_mac_addr(wpa_s);
+
+#ifdef CONFIG_FST
+       if (wpa_s->fst)
+               fst_update_mac_addr(wpa_s->fst, wpa_s->own_addr);
+#endif /* CONFIG_FST */
 
        return 0;
 }
@@ -4340,6 +4817,9 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent)
 
        dl_list_init(&wpa_s->bss_tmp_disallowed);
        dl_list_init(&wpa_s->fils_hlp_req);
+#ifdef CONFIG_TESTING_OPTIONS
+       dl_list_init(&wpa_s->drv_signal_override);
+#endif /* CONFIG_TESTING_OPTIONS */
 
        return wpa_s;
 }
@@ -4411,11 +4891,11 @@ static int wpa_disable_max_amsdu(struct wpa_supplicant *wpa_s,
 {
        le16 msk;
 
-       wpa_msg(wpa_s, MSG_DEBUG, "set_disable_max_amsdu: %d", disabled);
-
        if (disabled == -1)
                return 0;
 
+       wpa_msg(wpa_s, MSG_DEBUG, "set_disable_max_amsdu: %d", disabled);
+
        msk = host_to_le16(HT_CAP_INFO_MAX_AMSDU_SIZE);
        htcaps_mask->ht_capabilities_info |= msk;
        if (disabled)
@@ -4432,11 +4912,11 @@ static int wpa_set_ampdu_factor(struct wpa_supplicant *wpa_s,
                                struct ieee80211_ht_capabilities *htcaps_mask,
                                int factor)
 {
-       wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_factor: %d", factor);
-
        if (factor == -1)
                return 0;
 
+       wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_factor: %d", factor);
+
        if (factor < 0 || factor > 3) {
                wpa_msg(wpa_s, MSG_ERROR, "ampdu_factor: %d out of range. "
                        "Must be 0-3 or -1", factor);
@@ -4456,11 +4936,11 @@ static int wpa_set_ampdu_density(struct wpa_supplicant *wpa_s,
                                 struct ieee80211_ht_capabilities *htcaps_mask,
                                 int density)
 {
-       wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_density: %d", density);
-
        if (density == -1)
                return 0;
 
+       wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_density: %d", density);
+
        if (density < 0 || density > 7) {
                wpa_msg(wpa_s, MSG_ERROR,
                        "ampdu_density: %d out of range. Must be 0-7 or -1.",
@@ -4481,7 +4961,8 @@ static int wpa_set_disable_ht40(struct wpa_supplicant *wpa_s,
                                struct ieee80211_ht_capabilities *htcaps_mask,
                                int disabled)
 {
-       wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled);
+       if (disabled)
+               wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled);
 
        set_disable_ht40(htcaps, disabled);
        set_disable_ht40(htcaps_mask, 0);
@@ -4499,7 +4980,8 @@ static int wpa_set_disable_sgi(struct wpa_supplicant *wpa_s,
        le16 msk = host_to_le16(HT_CAP_INFO_SHORT_GI20MHZ |
                                HT_CAP_INFO_SHORT_GI40MHZ);
 
-       wpa_msg(wpa_s, MSG_DEBUG, "set_disable_sgi: %d", disabled);
+       if (disabled)
+               wpa_msg(wpa_s, MSG_DEBUG, "set_disable_sgi: %d", disabled);
 
        if (disabled)
                htcaps->ht_capabilities_info &= ~msk;
@@ -4520,7 +5002,8 @@ static int wpa_set_disable_ldpc(struct wpa_supplicant *wpa_s,
        /* Masking these out disables LDPC */
        le16 msk = host_to_le16(HT_CAP_INFO_LDPC_CODING_CAP);
 
-       wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ldpc: %d", disabled);
+       if (disabled)
+               wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ldpc: %d", disabled);
 
        if (disabled)
                htcaps->ht_capabilities_info &= ~msk;
@@ -4540,11 +5023,11 @@ static int wpa_set_tx_stbc(struct wpa_supplicant *wpa_s,
 {
        le16 msk = host_to_le16(HT_CAP_INFO_TX_STBC);
 
-       wpa_msg(wpa_s, MSG_DEBUG, "set_tx_stbc: %d", tx_stbc);
-
        if (tx_stbc == -1)
                return 0;
 
+       wpa_msg(wpa_s, MSG_DEBUG, "set_tx_stbc: %d", tx_stbc);
+
        if (tx_stbc < 0 || tx_stbc > 1) {
                wpa_msg(wpa_s, MSG_ERROR,
                        "tx_stbc: %d out of range. Must be 0-1 or -1", tx_stbc);
@@ -4566,11 +5049,11 @@ static int wpa_set_rx_stbc(struct wpa_supplicant *wpa_s,
 {
        le16 msk = host_to_le16(HT_CAP_INFO_RX_STBC_MASK);
 
-       wpa_msg(wpa_s, MSG_DEBUG, "set_rx_stbc: %d", rx_stbc);
-
        if (rx_stbc == -1)
                return 0;
 
+       wpa_msg(wpa_s, MSG_DEBUG, "set_rx_stbc: %d", rx_stbc);
+
        if (rx_stbc < 0 || rx_stbc > 3) {
                wpa_msg(wpa_s, MSG_ERROR,
                        "rx_stbc: %d out of range. Must be 0-3 or -1", rx_stbc);
@@ -5818,7 +6301,7 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
        hs20_init(wpa_s);
 #endif /* CONFIG_HS20 */
 #ifdef CONFIG_MBO
-       if (wpa_s->conf->oce) {
+       if (!wpa_s->disable_mbo_oce && wpa_s->conf->oce) {
                if ((wpa_s->conf->oce & OCE_STA) &&
                    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA))
                        wpa_s->enable_oce = OCE_STA;
@@ -5865,11 +6348,17 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
 
        wpa_s->disconnected = 1;
        if (wpa_s->drv_priv) {
-               wpa_supplicant_deauthenticate(wpa_s,
-                                             WLAN_REASON_DEAUTH_LEAVING);
+               /* Don't deauthenticate if WoWLAN is enabled */
+               if (!wpa_drv_get_wowlan(wpa_s)) {
+                       wpa_supplicant_deauthenticate(
+                               wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 
-               wpa_drv_set_countermeasures(wpa_s, 0);
-               wpa_clear_keys(wpa_s, NULL);
+                       wpa_drv_set_countermeasures(wpa_s, 0);
+                       wpa_clear_keys(wpa_s, NULL);
+               } else {
+                       wpa_msg(wpa_s, MSG_INFO,
+                               "Do not deauthenticate as part of interface deinit since WoWLAN is enabled");
+               }
        }
 
        wpa_supplicant_cleanup(wpa_s);
@@ -5916,6 +6405,7 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
        }
 
        os_free(wpa_s->ssids_from_scan_req);
+       os_free(wpa_s->last_scan_freqs);
 
        os_free(wpa_s);
 }
@@ -6247,7 +6737,7 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
 
        if (params->wpa_debug_file_path)
                wpa_debug_open_file(params->wpa_debug_file_path);
-       else
+       if (!params->wpa_debug_file_path && !params->wpa_debug_syslog)
                wpa_debug_setup_stdout();
        if (params->wpa_debug_syslog)
                wpa_debug_open_syslog();
@@ -6503,6 +6993,9 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
                                   wpa_s->conf->wowlan_triggers);
        }
 
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_DISABLE_BTM)
+               wpa_supplicant_set_default_scan_ies(wpa_s);
+
 #ifdef CONFIG_WPS
        wpas_wps_update_config(wpa_s);
 #endif /* CONFIG_WPS */
@@ -6657,6 +7150,9 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
         * TODO: if more than one possible AP is available in scan results,
         * could try the other ones before requesting a new scan.
         */
+
+       /* speed up the connection attempt with normal scan */
+       wpa_s->normal_scans = 0;
        wpa_supplicant_req_scan(wpa_s, timeout / 1000,
                                1000 * (timeout % 1000));
 }
@@ -6737,8 +7233,8 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
                        wpa_s->reassociate = 1;
                break;
        case WPA_CTRL_REQ_EAP_PIN:
-               str_clear_free(eap->pin);
-               eap->pin = os_strdup(value);
+               str_clear_free(eap->cert.pin);
+               eap->cert.pin = os_strdup(value);
                eap->pending_req_pin = 0;
                if (ssid == wpa_s->current_ssid)
                        wpa_s->reassociate = 1;
@@ -6752,8 +7248,8 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
                eap->pending_req_otp_len = 0;
                break;
        case WPA_CTRL_REQ_EAP_PASSPHRASE:
-               str_clear_free(eap->private_key_passwd);
-               eap->private_key_passwd = os_strdup(value);
+               str_clear_free(eap->cert.private_key_passwd);
+               eap->cert.private_key_passwd = os_strdup(value);
                eap->pending_req_passphrase = 0;
                if (ssid == wpa_s->current_ssid)
                        wpa_s->reassociate = 1;
@@ -6840,7 +7336,6 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
 
 int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
 {
-#ifdef CONFIG_IEEE80211W
        if (ssid == NULL || ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
                if (wpa_s->conf->pmf == MGMT_FRAME_PROTECTION_OPTIONAL &&
                    !(wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)) {
@@ -6869,9 +7364,6 @@ int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
        }
 
        return ssid->ieee80211w;
-#else /* CONFIG_IEEE80211W */
-       return NO_MGMT_FRAME_PROTECTION;
-#endif /* CONFIG_IEEE80211W */
 }
 
 
@@ -7042,6 +7534,8 @@ void wpas_request_disconnection(struct wpa_supplicant *wpa_s)
        wpa_supplicant_cancel_scan(wpa_s);
        wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
        eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+       radio_remove_works(wpa_s, "connect", 0);
+       radio_remove_works(wpa_s, "sme-connect", 0);
 }
 
 
@@ -7345,3 +7839,150 @@ int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s,
 
        return 1;
 }
+
+
+int wpas_enable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
+                                      unsigned int type, const u8 *addr,
+                                      const u8 *mask)
+{
+       if ((addr && !mask) || (!addr && mask)) {
+               wpa_printf(MSG_INFO,
+                          "MAC_ADDR_RAND_SCAN invalid addr/mask combination");
+               return -1;
+       }
+
+       if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
+               wpa_printf(MSG_INFO,
+                          "MAC_ADDR_RAND_SCAN cannot allow multicast address");
+               return -1;
+       }
+
+       if (type & MAC_ADDR_RAND_SCAN) {
+               if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
+                                               addr, mask))
+                       return -1;
+       }
+
+       if (type & MAC_ADDR_RAND_SCHED_SCAN) {
+               if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
+                                               addr, mask))
+                       return -1;
+
+               if (wpa_s->sched_scanning && !wpa_s->pno)
+                       wpas_scan_restart_sched_scan(wpa_s);
+       }
+
+       if (type & MAC_ADDR_RAND_PNO) {
+               if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
+                                               addr, mask))
+                       return -1;
+
+               if (wpa_s->pno) {
+                       wpas_stop_pno(wpa_s);
+                       wpas_start_pno(wpa_s);
+               }
+       }
+
+       return 0;
+}
+
+
+int wpas_disable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
+                                       unsigned int type)
+{
+       wpas_mac_addr_rand_scan_clear(wpa_s, type);
+       if (wpa_s->pno) {
+               if (type & MAC_ADDR_RAND_PNO) {
+                       wpas_stop_pno(wpa_s);
+                       wpas_start_pno(wpa_s);
+               }
+       } else if (wpa_s->sched_scanning && (type & MAC_ADDR_RAND_SCHED_SCAN)) {
+               wpas_scan_restart_sched_scan(wpa_s);
+       }
+
+       return 0;
+}
+
+
+int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
+                       struct wpa_signal_info *si)
+{
+       int res;
+
+       if (!wpa_s->driver->signal_poll)
+               return -1;
+
+       res = wpa_s->driver->signal_poll(wpa_s->drv_priv, si);
+
+#ifdef CONFIG_TESTING_OPTIONS
+       if (res == 0) {
+               struct driver_signal_override *dso;
+
+               dl_list_for_each(dso, &wpa_s->drv_signal_override,
+                                struct driver_signal_override, list) {
+                       if (os_memcmp(wpa_s->bssid, dso->bssid,
+                                     ETH_ALEN) != 0)
+                               continue;
+                       wpa_printf(MSG_DEBUG,
+                                  "Override driver signal_poll information: current_signal: %d->%d avg_signal: %d->%d avg_beacon_signal: %d->%d current_noise: %d->%d",
+                                  si->current_signal,
+                                  dso->si_current_signal,
+                                  si->avg_signal,
+                                  dso->si_avg_signal,
+                                  si->avg_beacon_signal,
+                                  dso->si_avg_beacon_signal,
+                                  si->current_noise,
+                                  dso->si_current_noise);
+                       si->current_signal = dso->si_current_signal;
+                       si->avg_signal = dso->si_avg_signal;
+                       si->avg_beacon_signal = dso->si_avg_beacon_signal;
+                       si->current_noise = dso->si_current_noise;
+                       break;
+               }
+       }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+       return res;
+}
+
+
+struct wpa_scan_results *
+wpa_drv_get_scan_results2(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_scan_results *scan_res;
+#ifdef CONFIG_TESTING_OPTIONS
+       size_t idx;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+       if (!wpa_s->driver->get_scan_results2)
+               return NULL;
+
+       scan_res = wpa_s->driver->get_scan_results2(wpa_s->drv_priv);
+
+#ifdef CONFIG_TESTING_OPTIONS
+       for (idx = 0; scan_res && idx < scan_res->num; idx++) {
+               struct driver_signal_override *dso;
+               struct wpa_scan_res *res = scan_res->res[idx];
+
+               dl_list_for_each(dso, &wpa_s->drv_signal_override,
+                                struct driver_signal_override, list) {
+                       if (os_memcmp(res->bssid, dso->bssid, ETH_ALEN) != 0)
+                               continue;
+                       wpa_printf(MSG_DEBUG,
+                                  "Override driver scan signal level %d->%d for "
+                                  MACSTR,
+                                  res->level, dso->scan_level,
+                                  MAC2STR(res->bssid));
+                       res->flags |= WPA_SCAN_QUAL_INVALID;
+                       if (dso->scan_level < 0)
+                               res->flags |= WPA_SCAN_LEVEL_DBM;
+                       else
+                               res->flags &= ~WPA_SCAN_LEVEL_DBM;
+                       res->level = dso->scan_level;
+                       break;
+               }
+       }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+       return scan_res;
+}