]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - wpa_supplicant/wpa_supplicant.c
SAE: Support external authentication offload for driver-SME cases
[thirdparty/hostap.git] / wpa_supplicant / wpa_supplicant.c
index 3f1d08b830da1069a87bd874e53f0b8018c12306..4209c41452a4f192080b7750f81c813a589c3ace 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant
- * Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -38,6 +38,7 @@
 #include "common/wpa_ctrl.h"
 #include "common/ieee802_11_defs.h"
 #include "common/hw_features_common.h"
+#include "common/gas_server.h"
 #include "p2p/p2p.h"
 #include "fst/fst.h"
 #include "blacklist.h"
 #include "wnm_sta.h"
 #include "wpas_kay.h"
 #include "mesh.h"
+#include "dpp_supplicant.h"
+#ifdef CONFIG_MESH
+#include "ap/ap_config.h"
+#include "ap/hostapd.h"
+#endif /* CONFIG_MESH */
 
 const char *const wpa_supplicant_version =
 "wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi> and contributors";
 
 const char *const wpa_supplicant_license =
 "This software may be distributed under the terms of the BSD license.\n"
@@ -112,6 +118,13 @@ const char *const wpa_supplicant_full_license5 =
 "\n";
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 
+
+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 */
+
+
 /* Configure default/group WEP keys for static WEP */
 int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
 {
@@ -192,7 +205,9 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
 {
        struct wpa_supplicant *wpa_s = eloop_ctx;
        const u8 *bssid = wpa_s->bssid;
-       if (is_zero_ether_addr(bssid))
+       if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
+           (wpa_s->wpa_state == WPA_AUTHENTICATING ||
+            wpa_s->wpa_state == WPA_ASSOCIATING))
                bssid = wpa_s->pending_bssid;
        wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.",
                MAC2STR(bssid));
@@ -327,7 +342,12 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
 
        eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
 
-       ieee802_1x_alloc_kay_sm(wpa_s, ssid);
+#ifdef CONFIG_MACSEC
+       if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE && ssid->mka_psk_set)
+               ieee802_1x_create_preshared_mka(wpa_s, ssid);
+       else
+               ieee802_1x_alloc_kay_sm(wpa_s, ssid);
+#endif /* CONFIG_MACSEC */
 #endif /* IEEE8021X_EAPOL */
 }
 
@@ -407,12 +427,26 @@ static void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s)
 
        dl_list_for_each_safe(bss, prev, &wpa_s->bss_tmp_disallowed,
                              struct wpa_bss_tmp_disallowed, list) {
+               eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss);
                dl_list_del(&bss->list);
                os_free(bss);
        }
 }
 
 
+void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s)
+{
+       struct fils_hlp_req *req;
+
+       while ((req = dl_list_first(&wpa_s->fils_hlp_req, struct fils_hlp_req,
+                                   list)) != NULL) {
+               dl_list_del(&req->list);
+               wpabuf_free(req->pkt);
+               os_free(req);
+       }
+}
+
+
 static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 {
        int i;
@@ -432,6 +466,10 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 #ifdef CONFIG_TESTING_OPTIONS
        l2_packet_deinit(wpa_s->l2_test);
        wpa_s->l2_test = NULL;
+       os_free(wpa_s->get_pref_freq_list_override);
+       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;
 #endif /* CONFIG_TESTING_OPTIONS */
 
        if (wpa_s->conf != NULL) {
@@ -504,6 +542,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 
        os_free(wpa_s->manual_scan_freqs);
        wpa_s->manual_scan_freqs = NULL;
+       os_free(wpa_s->select_network_scan_freqs);
+       wpa_s->select_network_scan_freqs = NULL;
 
        os_free(wpa_s->manual_sched_scan_freqs);
        wpa_s->manual_sched_scan_freqs = NULL;
@@ -522,6 +562,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
                radio_remove_works(wpa_s, "gas-query", 0);
        gas_query_deinit(wpa_s->gas);
        wpa_s->gas = NULL;
+       gas_server_deinit(wpa_s->gas_server);
+       wpa_s->gas_server = NULL;
 
        free_hw_features(wpa_s);
 
@@ -552,6 +594,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
        wpa_s->last_scan_res = NULL;
 
 #ifdef CONFIG_HS20
+       if (wpa_s->drv_priv)
+               wpa_drv_configure_frame_filters(wpa_s, 0);
        hs20_deinit(wpa_s);
 #endif /* CONFIG_HS20 */
 
@@ -573,6 +617,35 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 #endif /* CONFIG_MBO */
 
        free_bss_tmp_disallowed(wpa_s);
+
+       wpabuf_free(wpa_s->lci);
+       wpa_s->lci = NULL;
+       wpas_clear_beacon_rep_data(wpa_s);
+
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+#ifdef CONFIG_MESH
+       {
+               struct external_pmksa_cache *entry;
+
+               while ((entry = dl_list_last(&wpa_s->mesh_external_pmksa_cache,
+                                            struct external_pmksa_cache,
+                                            list)) != NULL) {
+                       dl_list_del(&entry->list);
+                       os_free(entry->pmksa_cache);
+                       os_free(entry);
+               }
+       }
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
+       wpas_flush_fils_hlp_req(wpa_s);
+
+       wpabuf_free(wpa_s->ric_ies);
+       wpa_s->ric_ies = NULL;
+
+#ifdef CONFIG_DPP
+       wpas_dpp_deinit(wpa_s);
+#endif /* CONFIG_DPP */
 }
 
 
@@ -786,12 +859,24 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
 
        if (state == WPA_COMPLETED && wpa_s->new_connection) {
                struct wpa_ssid *ssid = wpa_s->current_ssid;
+               int fils_hlp_sent = 0;
+
+#ifdef CONFIG_SME
+               if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+                   wpa_auth_alg_fils(wpa_s->sme.auth_alg))
+                       fils_hlp_sent = 1;
+#endif /* CONFIG_SME */
+               if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+                   wpa_auth_alg_fils(wpa_s->auth_alg))
+                       fils_hlp_sent = 1;
+
 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
                wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to "
-                       MACSTR " completed [id=%d id_str=%s]",
+                       MACSTR " completed [id=%d id_str=%s%s]",
                        MAC2STR(wpa_s->bssid),
                        ssid ? ssid->id : -1,
-                       ssid && ssid->id_str ? ssid->id_str : "");
+                       ssid && ssid->id_str ? ssid->id_str : "",
+                       fils_hlp_sent ? " FILS_HLP_SENT" : "");
 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
                wpas_clear_temp_disabled(wpa_s, ssid, 1);
                wpa_blacklist_clear(wpa_s);
@@ -806,6 +891,11 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
                wpas_p2p_completed(wpa_s);
 
                sme_sched_obss_scan(wpa_s, 1);
+
+#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
+               if (!fils_hlp_sent && ssid && ssid->eap.erp)
+                       wpas_update_fils_connect_params(wpa_s);
+#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
        } else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
                   state == WPA_ASSOCIATED) {
                wpa_s->new_connection = 1;
@@ -946,7 +1036,9 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
         * TODO: should notify EAPOL SM about changes in opensc_engine_path,
         * pkcs11_engine_path, pkcs11_module_path, openssl_ciphers.
         */
-       if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
+       if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
+           wpa_s->key_mgmt == WPA_KEY_MGMT_OWE ||
+           wpa_s->key_mgmt == WPA_KEY_MGMT_DPP) {
                /*
                 * Clear forced success to clear EAP state for next
                 * authentication.
@@ -1150,10 +1242,34 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                        ie.pairwise_cipher = ssid->pairwise_cipher;
                        ie.key_mgmt = ssid->key_mgmt;
 #ifdef CONFIG_IEEE80211W
-                       ie.mgmt_group_cipher =
-                               ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION ?
-                               WPA_CIPHER_AES_128_CMAC : 0;
+                       ie.mgmt_group_cipher = 0;
+                       if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+                               if (ssid->group_mgmt_cipher &
+                                   WPA_CIPHER_BIP_GMAC_256)
+                                       ie.mgmt_group_cipher =
+                                               WPA_CIPHER_BIP_GMAC_256;
+                               else if (ssid->group_mgmt_cipher &
+                                        WPA_CIPHER_BIP_CMAC_256)
+                                       ie.mgmt_group_cipher =
+                                               WPA_CIPHER_BIP_CMAC_256;
+                               else if (ssid->group_mgmt_cipher &
+                                        WPA_CIPHER_BIP_GMAC_128)
+                                       ie.mgmt_group_cipher =
+                                               WPA_CIPHER_BIP_GMAC_128;
+                               else
+                                       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 &&
+                           !bss_wpa && !bss_rsn && !bss_osen) {
+                               wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+                               wpa_s->wpa_proto = 0;
+                               return 0;
+                       }
+#endif /* CONFIG_OWE */
                        wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Set cipher suites "
                                "based on configuration");
                } else
@@ -1226,6 +1342,22 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                wpa_dbg(wpa_s, MSG_DEBUG,
                        "WPA: using KEY_MGMT 802.1X with Suite B");
 #endif /* CONFIG_SUITEB */
+#ifdef CONFIG_FILS
+#ifdef CONFIG_IEEE80211R
+       } else if (sel & WPA_KEY_MGMT_FT_FILS_SHA384) {
+               wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA384;
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA384");
+       } else if (sel & WPA_KEY_MGMT_FT_FILS_SHA256) {
+               wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA256;
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA256");
+#endif /* CONFIG_IEEE80211R */
+       } else if (sel & WPA_KEY_MGMT_FILS_SHA384) {
+               wpa_s->key_mgmt = WPA_KEY_MGMT_FILS_SHA384;
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA384");
+       } else if (sel & WPA_KEY_MGMT_FILS_SHA256) {
+               wpa_s->key_mgmt = WPA_KEY_MGMT_FILS_SHA256;
+               wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA256");
+#endif /* CONFIG_FILS */
 #ifdef CONFIG_IEEE80211R
        } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
                wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
@@ -1266,6 +1398,16 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                wpa_s->key_mgmt = WPA_KEY_MGMT_OSEN;
                wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: using KEY_MGMT OSEN");
 #endif /* CONFIG_HS20 */
+#ifdef CONFIG_OWE
+       } else if (sel & WPA_KEY_MGMT_OWE) {
+               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");
@@ -1279,6 +1421,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 
 #ifdef CONFIG_IEEE80211W
        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;
@@ -1321,6 +1465,10 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                                       NULL);
                        psk_set = 1;
                }
+
+               if (wpa_key_mgmt_sae(ssid->key_mgmt) && ssid->sae_password)
+                       psk_set = 1;
+
 #ifndef CONFIG_NO_PBKDF2
                if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
                    ssid->passphrase) {
@@ -1403,6 +1551,12 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                                "No PSK available for association");
                        return -1;
                }
+#ifdef CONFIG_OWE
+       } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_OWE) {
+               /* OWE Diffie-Hellman exchange in (Re)Association
+                * Request/Response frames set the PMK, so do not override it
+                * here. */
+#endif /* CONFIG_OWE */
        } else
                wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
 
@@ -1451,6 +1605,20 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
                break;
        case 6: /* Bits 48-55 */
                break;
+       case 7: /* Bits 56-63 */
+               break;
+       case 8: /* Bits 64-71 */
+               if (wpa_s->conf->ftm_responder)
+                       *pos |= 0x40; /* Bit 70 - FTM responder */
+               if (wpa_s->conf->ftm_initiator)
+                       *pos |= 0x80; /* Bit 71 - FTM initiator */
+               break;
+       case 9: /* Bits 72-79 */
+#ifdef CONFIG_FILS
+               if (!wpa_s->disable_fils)
+                       *pos |= 0x01;
+#endif /* CONFIG_FILS */
+               break;
        }
 }
 
@@ -1458,7 +1626,7 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
 int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen)
 {
        u8 *pos = buf;
-       u8 len = 6, i;
+       u8 len = 10, i;
 
        if (len < wpa_s->extended_capa_len)
                len = wpa_s->extended_capa_len;
@@ -1647,6 +1815,9 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        wmm_ac_clear_saved_tspecs(wpa_s);
        wpa_s->reassoc_same_bss = 0;
        wpa_s->reassoc_same_ess = 0;
+#ifdef CONFIG_TESTING_OPTIONS
+       wpa_s->testing_resend_assoc = 0;
+#endif /* CONFIG_TESTING_OPTIONS */
 
        if (wpa_s->last_ssid == ssid) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Re-association to the same ESS");
@@ -1655,11 +1826,13 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                        wmm_ac_save_tspecs(wpa_s);
                        wpa_s->reassoc_same_bss = 1;
                }
-       } else if (rand_style > 0) {
+       }
+
+       if (rand_style > 0 && !wpa_s->reassoc_same_ess) {
                if (wpas_update_random_addr(wpa_s, rand_style) < 0)
                        return;
                wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
-       } else if (wpa_s->mac_addr_changed) {
+       } else if (rand_style == 0 && wpa_s->mac_addr_changed) {
                if (wpa_drv_set_mac_addr(wpa_s, NULL) < 0) {
                        wpa_msg(wpa_s, MSG_INFO,
                                "Could not restore permanent MAC address");
@@ -1678,6 +1851,13 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 #ifdef CONFIG_IBSS_RSN
        ibss_rsn_deinit(wpa_s->ibss_rsn);
        wpa_s->ibss_rsn = NULL;
+#else /* CONFIG_IBSS_RSN */
+       if (ssid->mode == WPAS_MODE_IBSS &&
+           !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPA_NONE))) {
+               wpa_msg(wpa_s, MSG_INFO,
+                       "IBSS RSN not supported in the build");
+               return;
+       }
 #endif /* CONFIG_IBSS_RSN */
 
        if (ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO ||
@@ -1719,6 +1899,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_STARTED "ssid=\"%s\" id=%d",
                        wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
                        ssid->id);
+               wpas_notify_mesh_group_started(wpa_s, ssid);
 #else /* CONFIG_MESH */
                wpa_msg(wpa_s, MSG_ERROR,
                        "mesh mode support not included in the build");
@@ -1726,6 +1907,20 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                return;
        }
 
+       /*
+        * Set WPA state machine configuration to match the selected network now
+        * so that the information is available before wpas_start_assoc_cb()
+        * gets called. This is needed at least for RSN pre-authentication where
+        * candidate APs are added to a list based on scan result processing
+        * before completion of the first association.
+        */
+       wpa_supplicant_rsn_supp_set_config(wpa_s, ssid);
+
+#ifdef CONFIG_DPP
+       if (wpas_dpp_check_connect(wpa_s, ssid, bss) != 0)
+               return;
+#endif /* CONFIG_DPP */
+
 #ifdef CONFIG_TDLS
        if (bss)
                wpa_tdls_ap_ies(wpa_s->wpa, (const u8 *) (bss + 1),
@@ -1748,6 +1943,13 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                return;
        }
 
+#ifdef CONFIG_SME
+       if (ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) {
+               /* Clear possibly set auth_alg, if any, from last attempt. */
+               wpa_s->sme.auth_alg = WPA_AUTH_ALG_OPEN;
+       }
+#endif /* CONFIG_SME */
+
        wpas_abort_ongoing_scan(wpa_s);
 
        cwork = os_zalloc(sizeof(*cwork));
@@ -1779,11 +1981,6 @@ static int drv_supports_vht(struct wpa_supplicant *wpa_s,
        u8 channel;
        int i;
 
-#ifdef CONFIG_HT_OVERRIDES
-       if (ssid->disable_ht)
-               return 0;
-#endif /* CONFIG_HT_OVERRIDES */
-
        hw_mode = ieee80211_freq_to_chan(ssid->frequency, &channel);
        if (hw_mode == NUM_HOSTAPD_MODES)
                return 0;
@@ -1868,6 +2065,13 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
        if (!mode)
                return;
 
+#ifdef CONFIG_HT_OVERRIDES
+       if (ssid->disable_ht) {
+               freq->ht_enabled = 0;
+               return;
+       }
+#endif /* CONFIG_HT_OVERRIDES */
+
        freq->ht_enabled = ht_supported(mode);
        if (!freq->ht_enabled)
                return;
@@ -1889,6 +2093,11 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
        if (pri_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
                return;
 
+#ifdef CONFIG_HT_OVERRIDES
+       if (ssid->disable_ht40)
+               return;
+#endif /* CONFIG_HT_OVERRIDES */
+
        /* Check/setup HT40+/HT40- */
        for (j = 0; j < ARRAY_SIZE(ht40plus); j++) {
                if (ht40plus[j] == channel) {
@@ -1913,22 +2122,16 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
 
        freq->channel = pri_chan->chan;
 
-       switch (ht40) {
-       case -1:
+       if (ht40 == -1) {
                if (!(pri_chan->flag & HOSTAPD_CHAN_HT40MINUS))
                        return;
-               freq->sec_channel_offset = -1;
-               break;
-       case 1:
+       } else {
                if (!(pri_chan->flag & HOSTAPD_CHAN_HT40PLUS))
                        return;
-               freq->sec_channel_offset = 1;
-               break;
-       default:
-               break;
        }
+       freq->sec_channel_offset = ht40;
 
-       if (freq->sec_channel_offset && obss_scan) {
+       if (obss_scan) {
                struct wpa_scan_results *scan_res;
 
                scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0);
@@ -1976,6 +2179,13 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
 
        vht_freq = *freq;
 
+#ifdef CONFIG_VHT_OVERRIDES
+       if (ssid->disable_vht) {
+               freq->vht_enabled = 0;
+               return;
+       }
+#endif /* CONFIG_VHT_OVERRIDES */
+
        vht_freq.vht_enabled = vht_supported(mode);
        if (!vht_freq.vht_enabled)
                return;
@@ -2034,6 +2244,16 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
                        if (chwidth == VHT_CHANWIDTH_80P80MHZ)
                                break;
                }
+       } else if (ssid->max_oper_chwidth == VHT_CHANWIDTH_160MHZ) {
+               if (freq->freq == 5180) {
+                       chwidth = VHT_CHANWIDTH_160MHZ;
+                       vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+                       seg0 = 50;
+               } else if (freq->freq == 5520) {
+                       chwidth = VHT_CHANWIDTH_160MHZ;
+                       vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+                       seg0 = 114;
+               }
        }
 
        if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
@@ -2050,143 +2270,132 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
 }
 
 
-static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
+#ifdef CONFIG_FILS
+static size_t wpas_add_fils_hlp_req(struct wpa_supplicant *wpa_s, u8 *ie_buf,
+                                   size_t ie_buf_len)
 {
-       struct wpa_connect_work *cwork = work->ctx;
-       struct wpa_bss *bss = cwork->bss;
-       struct wpa_ssid *ssid = cwork->ssid;
-       struct wpa_supplicant *wpa_s = work->wpa_s;
-       u8 wpa_ie[200];
-       size_t wpa_ie_len;
-       int use_crypt, ret, i, bssid_changed;
-       int algs = WPA_AUTH_ALG_OPEN;
-       unsigned int cipher_pairwise, cipher_group;
-       struct wpa_driver_associate_params params;
-       int wep_keys_set = 0;
-       int assoc_failed = 0;
-       struct wpa_ssid *old_ssid;
-       u8 prev_bssid[ETH_ALEN];
-#ifdef CONFIG_HT_OVERRIDES
-       struct ieee80211_ht_capabilities htcaps;
-       struct ieee80211_ht_capabilities htcaps_mask;
-#endif /* CONFIG_HT_OVERRIDES */
-#ifdef CONFIG_VHT_OVERRIDES
-       struct ieee80211_vht_capabilities vhtcaps;
-       struct ieee80211_vht_capabilities vhtcaps_mask;
-#endif /* CONFIG_VHT_OVERRIDES */
-#ifdef CONFIG_MBO
-       const u8 *mbo = NULL;
-#endif /* CONFIG_MBO */
+       struct fils_hlp_req *req;
+       size_t rem_len, hdr_len, hlp_len, len, ie_len = 0;
+       const u8 *pos;
+       u8 *buf = ie_buf;
 
-       if (deinit) {
-               if (work->started) {
-                       wpa_s->connect_work = NULL;
+       dl_list_for_each(req, &wpa_s->fils_hlp_req, struct fils_hlp_req,
+                        list) {
+               rem_len = ie_buf_len - ie_len;
+               pos = wpabuf_head(req->pkt);
+               hdr_len = 1 + 2 * ETH_ALEN + 6;
+               hlp_len = wpabuf_len(req->pkt);
 
-                       /* cancel possible auth. timeout */
-                       eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s,
-                                            NULL);
+               if (rem_len < 2 + hdr_len + hlp_len) {
+                       wpa_printf(MSG_ERROR,
+                                  "FILS: Cannot fit HLP - rem_len=%lu to_fill=%lu",
+                                  (unsigned long) rem_len,
+                                  (unsigned long) (2 + hdr_len + hlp_len));
+                       break;
                }
-               wpas_connect_work_free(cwork);
-               return;
-       }
-
-       wpa_s->connect_work = work;
-
-       if (cwork->bss_removed || !wpas_valid_bss_ssid(wpa_s, bss, ssid) ||
-           wpas_network_disabled(wpa_s, ssid)) {
-               wpa_dbg(wpa_s, MSG_DEBUG, "BSS/SSID entry for association not valid anymore - drop connection attempt");
-               wpas_connect_work_done(wpa_s);
-               return;
-       }
 
-       os_memcpy(prev_bssid, wpa_s->bssid, ETH_ALEN);
-       os_memset(&params, 0, sizeof(params));
-       wpa_s->reassociate = 0;
-       wpa_s->eap_expected_failure = 0;
-       if (bss &&
-           (!wpas_driver_bss_selection(wpa_s) || wpas_wps_searching(wpa_s))) {
-#ifdef CONFIG_IEEE80211R
-               const u8 *ie, *md = NULL;
-#endif /* CONFIG_IEEE80211R */
-               wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR
-                       " (SSID='%s' freq=%d MHz)", MAC2STR(bss->bssid),
-                       wpa_ssid_txt(bss->ssid, bss->ssid_len), bss->freq);
-               bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
-               os_memset(wpa_s->bssid, 0, ETH_ALEN);
-               os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
-               if (bssid_changed)
-                       wpas_notify_bssid_changed(wpa_s);
-#ifdef CONFIG_IEEE80211R
-               ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
-               if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
-                       md = ie + 2;
-               wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0);
-               if (md) {
-                       /* Prepare for the next transition */
-                       wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
+               len = (hdr_len + hlp_len) > 255 ? 255 : hdr_len + hlp_len;
+               /* Element ID */
+               *buf++ = WLAN_EID_EXTENSION;
+               /* Length */
+               *buf++ = len;
+               /* Element ID Extension */
+               *buf++ = WLAN_EID_EXT_FILS_HLP_CONTAINER;
+               /* Destination MAC address */
+               os_memcpy(buf, req->dst, ETH_ALEN);
+               buf += ETH_ALEN;
+               /* Source MAC address */
+               os_memcpy(buf, wpa_s->own_addr, ETH_ALEN);
+               buf += ETH_ALEN;
+               /* LLC/SNAP Header */
+               os_memcpy(buf, "\xaa\xaa\x03\x00\x00\x00", 6);
+               buf += 6;
+               /* HLP Packet */
+               os_memcpy(buf, pos, len - hdr_len);
+               buf += len - hdr_len;
+               pos += len - hdr_len;
+
+               hlp_len -= len - hdr_len;
+               ie_len += 2 + len;
+               rem_len -= 2 + len;
+
+               while (hlp_len) {
+                       len = (hlp_len > 255) ? 255 : hlp_len;
+                       if (rem_len < 2 + len)
+                               break;
+                       *buf++ = WLAN_EID_FRAGMENT;
+                       *buf++ = len;
+                       os_memcpy(buf, pos, len);
+                       buf += len;
+                       pos += len;
+
+                       hlp_len -= len;
+                       ie_len += 2 + len;
+                       rem_len -= 2 + len;
                }
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_WPS
-       } else if ((ssid->ssid == NULL || ssid->ssid_len == 0) &&
-                  wpa_s->conf->ap_scan == 2 &&
-                  (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
-               /* Use ap_scan==1 style network selection to find the network
-                */
-               wpas_connect_work_done(wpa_s);
-               wpa_s->scan_req = MANUAL_SCAN_REQ;
-               wpa_s->reassociate = 1;
-               wpa_supplicant_req_scan(wpa_s, 0, 0);
-               return;
-#endif /* CONFIG_WPS */
-       } else {
-               wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'",
-                       wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
-               os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
        }
-       if (!wpa_s->pno)
-               wpa_supplicant_cancel_sched_scan(wpa_s);
 
-       wpa_supplicant_cancel_scan(wpa_s);
+       return ie_len;
+}
+#endif /* CONFIG_FILS */
 
-       /* 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);
 
-#ifdef IEEE8021X_EAPOL
-       if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
-               if (ssid->leap) {
-                       if (ssid->non_leap == 0)
-                               algs = WPA_AUTH_ALG_LEAP;
-                       else
-                               algs |= WPA_AUTH_ALG_LEAP;
-               }
+static u8 * wpas_populate_assoc_ies(
+       struct wpa_supplicant *wpa_s,
+       struct wpa_bss *bss, struct wpa_ssid *ssid,
+       struct wpa_driver_associate_params *params,
+       enum wpa_drv_update_connect_params_mask *mask)
+{
+       u8 *wpa_ie;
+       size_t max_wpa_ie_len = 500;
+       size_t wpa_ie_len;
+       int algs = WPA_AUTH_ALG_OPEN;
+#ifdef CONFIG_FILS
+       const u8 *realm, *username, *rrk;
+       size_t realm_len, username_len, rrk_len;
+       u16 next_seq_num;
+       struct fils_hlp_req *req;
+
+       dl_list_for_each(req, &wpa_s->fils_hlp_req, struct fils_hlp_req,
+                        list) {
+               max_wpa_ie_len += 3 + 2 * ETH_ALEN + 6 + wpabuf_len(req->pkt) +
+                                 2 + 2 * wpabuf_len(req->pkt) / 255;
        }
-#endif /* IEEE8021X_EAPOL */
-       wpa_dbg(wpa_s, MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs);
-       if (ssid->auth_alg) {
-               algs = ssid->auth_alg;
-               wpa_dbg(wpa_s, MSG_DEBUG, "Overriding auth_alg selection: "
-                       "0x%x", algs);
+#endif /* CONFIG_FILS */
+
+       wpa_ie = os_malloc(max_wpa_ie_len);
+       if (!wpa_ie) {
+               wpa_printf(MSG_ERROR,
+                          "Failed to allocate connect IE buffer for %lu bytes",
+                          (unsigned long) max_wpa_ie_len);
+               return NULL;
        }
 
        if (bss && (wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
                    wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
            wpa_key_mgmt_wpa(ssid->key_mgmt)) {
                int try_opportunistic;
+               const u8 *cache_id = NULL;
+
                try_opportunistic = (ssid->proactive_key_caching < 0 ?
                                     wpa_s->conf->okc :
                                     ssid->proactive_key_caching) &&
                        (ssid->proto & WPA_PROTO_RSN);
+#ifdef CONFIG_FILS
+               if (wpa_key_mgmt_fils(ssid->key_mgmt))
+                       cache_id = wpa_bss_get_fils_cache_id(bss);
+#endif /* CONFIG_FILS */
                if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
-                                           ssid, try_opportunistic) == 0)
+                                           ssid, try_opportunistic,
+                                           cache_id) == 0)
                        eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
-               wpa_ie_len = sizeof(wpa_ie);
+               wpa_ie_len = max_wpa_ie_len;
                if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
                                              wpa_ie, &wpa_ie_len)) {
                        wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
                                "key management and encryption suites");
-                       wpas_connect_work_done(wpa_s);
-                       return;
+                       os_free(wpa_ie);
+                       return NULL;
                }
        } else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && bss &&
                   wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) {
@@ -2199,20 +2408,20 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                wpa_ie_len = 0;
                wpa_s->wpa_proto = 0;
        } else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
-               wpa_ie_len = sizeof(wpa_ie);
+               wpa_ie_len = max_wpa_ie_len;
                if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
                                              wpa_ie, &wpa_ie_len)) {
                        wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
                                "key management and encryption suites (no "
                                "scan results)");
-                       wpas_connect_work_done(wpa_s);
-                       return;
+                       os_free(wpa_ie);
+                       return NULL;
                }
 #ifdef CONFIG_WPS
        } else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
                struct wpabuf *wps_ie;
                wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid));
-               if (wps_ie && wpabuf_len(wps_ie) <= sizeof(wpa_ie)) {
+               if (wps_ie && wpabuf_len(wps_ie) <= max_wpa_ie_len) {
                        wpa_ie_len = wpabuf_len(wps_ie);
                        os_memcpy(wpa_ie, wpabuf_head(wps_ie), wpa_ie_len);
                } else
@@ -2220,9 +2429,9 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                wpabuf_free(wps_ie);
                wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
                if (!bss || (bss->caps & IEEE80211_CAP_PRIVACY))
-                       params.wps = WPS_MODE_PRIVACY;
+                       params->wps = WPS_MODE_PRIVACY;
                else
-                       params.wps = WPS_MODE_OPEN;
+                       params->wps = WPS_MODE_OPEN;
                wpa_s->wpa_proto = 0;
 #endif /* CONFIG_WPS */
        } else {
@@ -2231,13 +2440,58 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                wpa_s->wpa_proto = 0;
        }
 
+#ifdef IEEE8021X_EAPOL
+       if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+               if (ssid->leap) {
+                       if (ssid->non_leap == 0)
+                               algs = WPA_AUTH_ALG_LEAP;
+                       else
+                               algs |= WPA_AUTH_ALG_LEAP;
+               }
+       }
+
+#ifdef CONFIG_FILS
+       /* Clear FILS association */
+       wpa_sm_set_reset_fils_completed(wpa_s->wpa, 0);
+
+       if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD) &&
+           ssid->eap.erp && wpa_key_mgmt_fils(wpa_s->key_mgmt) &&
+           eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap, &username,
+                                 &username_len, &realm, &realm_len,
+                                 &next_seq_num, &rrk, &rrk_len) == 0) {
+               algs = WPA_AUTH_ALG_FILS;
+               params->fils_erp_username = username;
+               params->fils_erp_username_len = username_len;
+               params->fils_erp_realm = realm;
+               params->fils_erp_realm_len = realm_len;
+               params->fils_erp_next_seq_num = next_seq_num;
+               params->fils_erp_rrk = rrk;
+               params->fils_erp_rrk_len = rrk_len;
+
+               if (mask)
+                       *mask |= WPA_DRV_UPDATE_FILS_ERP_INFO;
+       }
+#endif /* CONFIG_FILS */
+#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_SAE
+       if (wpa_s->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE))
+               algs = WPA_AUTH_ALG_SAE;
+#endif /* CONFIG_SAE */
+
+       wpa_dbg(wpa_s, MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs);
+       if (ssid->auth_alg) {
+               algs = ssid->auth_alg;
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "Overriding auth_alg selection: 0x%x", algs);
+       }
+
 #ifdef CONFIG_P2P
        if (wpa_s->global->p2p) {
                u8 *pos;
                size_t len;
                int res;
                pos = wpa_ie + wpa_ie_len;
-               len = sizeof(wpa_ie) - wpa_ie_len;
+               len = max_wpa_ie_len - wpa_ie_len;
                res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len,
                                            ssid->p2p_group);
                if (res >= 0)
@@ -2262,21 +2516,12 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        os_memset(wpa_s->p2p_ip_addr_info, 0, sizeof(wpa_s->p2p_ip_addr_info));
 #endif /* CONFIG_P2P */
 
-#ifdef CONFIG_MBO
        if (bss) {
-               mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
-               if (mbo) {
-                       int len;
-
-                       len = wpas_mbo_supp_op_class_ie(wpa_s, bss->freq,
-                                                       wpa_ie + wpa_ie_len,
-                                                       sizeof(wpa_ie) -
-                                                       wpa_ie_len);
-                       if (len > 0)
-                               wpa_ie_len += len;
-               }
+               wpa_ie_len += wpas_supp_op_class_ie(wpa_s, bss->freq,
+                                                   wpa_ie + wpa_ie_len,
+                                                   max_wpa_ie_len -
+                                                   wpa_ie_len);
        }
-#endif /* CONFIG_MBO */
 
        /*
         * Workaround: Add Extended Capabilities element only if the AP
@@ -2286,12 +2531,18 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
         * element in all cases, it is justifiable to skip it to avoid
         * interoperability issues.
         */
+       if (ssid->p2p_group)
+               wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
+       else
+               wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
+
        if (!bss || wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB)) {
                u8 ext_capab[18];
                int ext_capab_len;
                ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
                                                     sizeof(ext_capab));
-               if (ext_capab_len > 0) {
+               if (ext_capab_len > 0 &&
+                   wpa_ie_len + ext_capab_len <= max_wpa_ie_len) {
                        u8 *pos = wpa_ie;
                        if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
                                pos += 2 + pos[1];
@@ -2312,13 +2563,15 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                        size_t len;
 
                        wpas_hs20_add_indication(hs20, pps_mo_id);
-                       len = sizeof(wpa_ie) - wpa_ie_len;
+                       len = max_wpa_ie_len - wpa_ie_len;
                        if (wpabuf_len(hs20) <= len) {
                                os_memcpy(wpa_ie + wpa_ie_len,
                                          wpabuf_head(hs20), wpabuf_len(hs20));
                                wpa_ie_len += wpabuf_len(hs20);
                        }
                        wpabuf_free(hs20);
+
+                       hs20_configure_frame_filters(wpa_s);
                }
        }
 #endif /* CONFIG_HS20 */
@@ -2327,7 +2580,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ];
                size_t len;
 
-               len = sizeof(wpa_ie) - wpa_ie_len;
+               len = max_wpa_ie_len - wpa_ie_len;
                if (wpabuf_len(buf) <= len) {
                        os_memcpy(wpa_ie + wpa_ie_len,
                                  wpabuf_head(buf), wpabuf_len(buf));
@@ -2339,7 +2592,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        if (wpa_s->fst_ies) {
                int fst_ies_len = wpabuf_len(wpa_s->fst_ies);
 
-               if (wpa_ie_len + fst_ies_len <= sizeof(wpa_ie)) {
+               if (wpa_ie_len + fst_ies_len <= max_wpa_ie_len) {
                        os_memcpy(wpa_ie + wpa_ie_len,
                                  wpabuf_head(wpa_s->fst_ies), fst_ies_len);
                        wpa_ie_len += fst_ies_len;
@@ -2348,20 +2601,209 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
 #endif /* CONFIG_FST */
 
 #ifdef CONFIG_MBO
-       if (mbo) {
+       if (bss && wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE)) {
                int len;
 
                len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
-                                 sizeof(wpa_ie) - wpa_ie_len);
+                                 max_wpa_ie_len - wpa_ie_len);
                if (len >= 0)
                        wpa_ie_len += len;
        }
 #endif /* CONFIG_MBO */
 
+#ifdef CONFIG_FILS
+       if (algs == WPA_AUTH_ALG_FILS) {
+               size_t len;
+
+               len = wpas_add_fils_hlp_req(wpa_s, wpa_ie + wpa_ie_len,
+                                           max_wpa_ie_len - wpa_ie_len);
+               wpa_ie_len += len;
+       }
+#endif /* CONFIG_FILS */
+
+#ifdef CONFIG_OWE
+#ifdef CONFIG_TESTING_OPTIONS
+       if (get_ie_ext(wpa_ie, wpa_ie_len, WLAN_EID_EXT_OWE_DH_PARAM)) {
+               wpa_printf(MSG_INFO, "TESTING: Override OWE DH element");
+       } else
+#endif /* CONFIG_TESTING_OPTIONS */
+       if (algs == WPA_AUTH_ALG_OPEN &&
+           ssid->key_mgmt == WPA_KEY_MGMT_OWE) {
+               struct wpabuf *owe_ie;
+               u16 group;
+
+               if (ssid->owe_group) {
+                       group = ssid->owe_group;
+               } else {
+                       if (wpa_s->last_owe_group == 19)
+                               group = 20;
+                       else if (wpa_s->last_owe_group == 20)
+                               group = 21;
+                       else
+                               group = OWE_DH_GROUP;
+               }
+               wpa_s->last_owe_group = group;
+               wpa_printf(MSG_DEBUG, "OWE: Try to use group %u", group);
+               owe_ie = owe_build_assoc_req(wpa_s->wpa, group);
+               if (owe_ie &&
+                   wpabuf_len(owe_ie) <= max_wpa_ie_len - wpa_ie_len) {
+                       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);
+               }
+       }
+#endif /* CONFIG_OWE */
+
+       params->wpa_ie = wpa_ie;
+       params->wpa_ie_len = wpa_ie_len;
+       params->auth_alg = algs;
+       if (mask)
+               *mask |= WPA_DRV_UPDATE_ASSOC_IES | WPA_DRV_UPDATE_AUTH_TYPE;
+
+       return wpa_ie;
+}
+
+
+#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
+static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_driver_associate_params params;
+       enum wpa_drv_update_connect_params_mask mask = 0;
+       u8 *wpa_ie;
+
+       if (wpa_s->auth_alg != WPA_AUTH_ALG_OPEN)
+               return; /* nothing to do */
+
+       os_memset(&params, 0, sizeof(params));
+       wpa_ie = wpas_populate_assoc_ies(wpa_s, wpa_s->current_bss,
+                                        wpa_s->current_ssid, &params, &mask);
+       if (!wpa_ie)
+               return;
+
+       if (params.auth_alg != WPA_AUTH_ALG_FILS) {
+               os_free(wpa_ie);
+               return;
+       }
+
+       wpa_s->auth_alg = params.auth_alg;
+       wpa_drv_update_connect_params(wpa_s, &params, mask);
+       os_free(wpa_ie);
+}
+#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
+
+
+static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
+{
+       struct wpa_connect_work *cwork = work->ctx;
+       struct wpa_bss *bss = cwork->bss;
+       struct wpa_ssid *ssid = cwork->ssid;
+       struct wpa_supplicant *wpa_s = work->wpa_s;
+       u8 *wpa_ie;
+       int use_crypt, ret, i, bssid_changed;
+       unsigned int cipher_pairwise, cipher_group, cipher_group_mgmt;
+       struct wpa_driver_associate_params params;
+       int wep_keys_set = 0;
+       int assoc_failed = 0;
+       struct wpa_ssid *old_ssid;
+       u8 prev_bssid[ETH_ALEN];
+#ifdef CONFIG_HT_OVERRIDES
+       struct ieee80211_ht_capabilities htcaps;
+       struct ieee80211_ht_capabilities htcaps_mask;
+#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+       struct ieee80211_vht_capabilities vhtcaps;
+       struct ieee80211_vht_capabilities vhtcaps_mask;
+#endif /* CONFIG_VHT_OVERRIDES */
+
+       if (deinit) {
+               if (work->started) {
+                       wpa_s->connect_work = NULL;
+
+                       /* cancel possible auth. timeout */
+                       eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s,
+                                            NULL);
+               }
+               wpas_connect_work_free(cwork);
+               return;
+       }
+
+       wpa_s->connect_work = work;
+
+       if (cwork->bss_removed || !wpas_valid_bss_ssid(wpa_s, bss, ssid) ||
+           wpas_network_disabled(wpa_s, ssid)) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "BSS/SSID entry for association not valid anymore - drop connection attempt");
+               wpas_connect_work_done(wpa_s);
+               return;
+       }
+
+       os_memcpy(prev_bssid, wpa_s->bssid, ETH_ALEN);
+       os_memset(&params, 0, sizeof(params));
+       wpa_s->reassociate = 0;
+       wpa_s->eap_expected_failure = 0;
+       if (bss &&
+           (!wpas_driver_bss_selection(wpa_s) || wpas_wps_searching(wpa_s))) {
+#ifdef CONFIG_IEEE80211R
+               const u8 *ie, *md = NULL;
+#endif /* CONFIG_IEEE80211R */
+               wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR
+                       " (SSID='%s' freq=%d MHz)", MAC2STR(bss->bssid),
+                       wpa_ssid_txt(bss->ssid, bss->ssid_len), bss->freq);
+               bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
+               os_memset(wpa_s->bssid, 0, ETH_ALEN);
+               os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
+               if (bssid_changed)
+                       wpas_notify_bssid_changed(wpa_s);
+#ifdef CONFIG_IEEE80211R
+               ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
+               if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
+                       md = ie + 2;
+               wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0);
+               if (md) {
+                       /* Prepare for the next transition */
+                       wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
+               }
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_WPS
+       } else if ((ssid->ssid == NULL || ssid->ssid_len == 0) &&
+                  wpa_s->conf->ap_scan == 2 &&
+                  (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
+               /* Use ap_scan==1 style network selection to find the network
+                */
+               wpas_connect_work_done(wpa_s);
+               wpa_s->scan_req = MANUAL_SCAN_REQ;
+               wpa_s->reassociate = 1;
+               wpa_supplicant_req_scan(wpa_s, 0, 0);
+               return;
+#endif /* CONFIG_WPS */
+       } else {
+               wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'",
+                       wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+               if (bss)
+                       os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
+               else
+                       os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+       }
+       if (!wpa_s->pno)
+               wpa_supplicant_cancel_sched_scan(wpa_s);
+
+       wpa_supplicant_cancel_scan(wpa_s);
+
+       /* 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_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, &params, NULL);
+       if (!wpa_ie) {
+               wpas_connect_work_done(wpa_s);
+               return;
+       }
+
        wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
        use_crypt = 1;
        cipher_pairwise = wpa_s->pairwise_cipher;
        cipher_group = wpa_s->group_cipher;
+       cipher_group_mgmt = wpa_s->mgmt_group_cipher;
        if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
            wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
                if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE)
@@ -2399,12 +2841,14 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        if (bss) {
                params.ssid = bss->ssid;
                params.ssid_len = bss->ssid_len;
-               if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) {
+               if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set ||
+                   wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
                        wpa_printf(MSG_DEBUG, "Limit connection to BSSID "
                                   MACSTR " freq=%u MHz based on scan results "
-                                  "(bssid_set=%d)",
+                                  "(bssid_set=%d wps=%d)",
                                   MAC2STR(bss->bssid), bss->freq,
-                                  ssid->bssid_set);
+                                  ssid->bssid_set,
+                                  wpa_s->key_mgmt == WPA_KEY_MGMT_WPS);
                        params.bssid = bss->bssid;
                        params.freq.freq = bss->freq;
                }
@@ -2412,6 +2856,9 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                params.freq_hint = bss->freq;
                params.pbss = bss_is_pbss(bss);
        } else {
+               if (ssid->bssid_hint_set)
+                       params.bssid_hint = ssid->bssid_hint;
+
                params.ssid = ssid->ssid;
                params.ssid_len = ssid->ssid_len;
                params.pbss = (ssid->pbss != 2) ? ssid->pbss : 0;
@@ -2436,13 +2883,12 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                        params.beacon_int = wpa_s->conf->beacon_int;
        }
 
-       params.wpa_ie = wpa_ie;
-       params.wpa_ie_len = wpa_ie_len;
        params.pairwise_suite = cipher_pairwise;
        params.group_suite = cipher_group;
+       params.mgmt_group_suite = cipher_group_mgmt;
        params.key_mgmt_suite = wpa_s->key_mgmt;
        params.wpa_proto = wpa_s->wpa_proto;
-       params.auth_alg = algs;
+       wpa_s->auth_alg = params.auth_alg;
        params.mode = ssid->mode;
        params.bg_scan_period = ssid->bg_scan_period;
        for (i = 0; i < NUM_WEP_KEYS; i++) {
@@ -2534,6 +2980,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                        if (wpas_p2p_handle_frequency_conflicts(
                                    wpa_s, params.freq.freq, ssid) < 0) {
                                wpas_connect_work_done(wpa_s);
+                               os_free(wpa_ie);
                                return;
                        }
                }
@@ -2545,6 +2992,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                params.prev_bssid = prev_bssid;
 
        ret = wpa_drv_associate(wpa_s, &params);
+       os_free(wpa_ie);
        if (ret < 0) {
                wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
                        "failed");
@@ -2611,8 +3059,14 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        }
        old_ssid = wpa_s->current_ssid;
        wpa_s->current_ssid = ssid;
-       if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set)
+
+       if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) {
                wpa_s->current_bss = bss;
+#ifdef CONFIG_HS20
+               hs20_configure_frame_filters(wpa_s);
+#endif /* CONFIG_HS20 */
+       }
+
        wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
        wpa_supplicant_initiate_eapol(wpa_s);
        if (old_ssid != wpa_s->current_ssid)
@@ -2657,12 +3111,12 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
                MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
                reason_code, wpa_supplicant_state_txt(wpa_s->wpa_state));
 
-       if (!is_zero_ether_addr(wpa_s->bssid))
-               addr = wpa_s->bssid;
-       else if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
-                (wpa_s->wpa_state == WPA_AUTHENTICATING ||
-                 wpa_s->wpa_state == WPA_ASSOCIATING))
+       if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
+           (wpa_s->wpa_state == WPA_AUTHENTICATING ||
+            wpa_s->wpa_state == WPA_ASSOCIATING))
                addr = wpa_s->pending_bssid;
+       else if (!is_zero_ether_addr(wpa_s->bssid))
+               addr = wpa_s->bssid;
        else if (wpa_s->wpa_state == WPA_ASSOCIATING) {
                /*
                 * When using driver-based BSS selection, we may not know the
@@ -2680,8 +3134,13 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
 
 #ifdef CONFIG_MESH
        if (wpa_s->ifmsh) {
+               struct mesh_conf *mconf;
+
+               mconf = wpa_s->ifmsh->mconf;
                wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_REMOVED "%s",
                        wpa_s->ifname);
+               wpas_notify_mesh_group_removed(wpa_s, mconf->meshid,
+                                              mconf->meshid_len, reason_code);
                wpa_supplicant_leave_mesh(wpa_s);
        }
 #endif /* CONFIG_MESH */
@@ -2696,25 +3155,114 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
                        addr = NULL;
        }
 
-       wpa_supplicant_clear_connection(wpa_s, addr);
-}
+       wpa_supplicant_clear_connection(wpa_s, addr);
+}
+
+static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s,
+                                             struct wpa_ssid *ssid)
+{
+       if (!ssid || !ssid->disabled || ssid->disabled == 2)
+               return;
+
+       ssid->disabled = 0;
+       wpas_clear_temp_disabled(wpa_s, ssid, 1);
+       wpas_notify_network_enabled_changed(wpa_s, ssid);
+
+       /*
+        * Try to reassociate since there is no current configuration and a new
+        * network was made available.
+        */
+       if (!wpa_s->current_ssid && !wpa_s->disconnected)
+               wpa_s->reassociate = 1;
+}
+
+
+/**
+ * wpa_supplicant_add_network - Add a new network
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: The new network configuration or %NULL if operation failed
+ *
+ * This function performs the following operations:
+ * 1. Adds a new network.
+ * 2. Send network addition notification.
+ * 3. Marks the network disabled.
+ * 4. Set network default parameters.
+ */
+struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_ssid *ssid;
+
+       ssid = wpa_config_add_network(wpa_s->conf);
+       if (!ssid)
+               return NULL;
+       wpas_notify_network_added(wpa_s, ssid);
+       ssid->disabled = 1;
+       wpa_config_set_network_defaults(ssid);
+
+       return ssid;
+}
+
+
+/**
+ * wpa_supplicant_remove_network - Remove a configured network based on id
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @id: Unique network id to search for
+ * Returns: 0 on success, or -1 if the network was not found, -2 if the network
+ * could not be removed
+ *
+ * This function performs the following operations:
+ * 1. Removes the network.
+ * 2. Send network removal notification.
+ * 3. Update internal state machines.
+ * 4. Stop any running sched scans.
+ */
+int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id)
+{
+       struct wpa_ssid *ssid;
+       int was_disabled;
+
+       ssid = wpa_config_get_network(wpa_s->conf, id);
+       if (!ssid)
+               return -1;
+       wpas_notify_network_removed(wpa_s, ssid);
+
+       if (wpa_s->last_ssid == ssid)
+               wpa_s->last_ssid = NULL;
+
+       if (ssid == wpa_s->current_ssid || !wpa_s->current_ssid) {
+#ifdef CONFIG_SME
+               wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+               /*
+                * Invalidate the EAP session cache if the current or
+                * previously used network is removed.
+                */
+               eapol_sm_invalidate_cached_session(wpa_s->eapol);
+       }
+
+       if (ssid == wpa_s->current_ssid) {
+               wpa_sm_set_config(wpa_s->wpa, NULL);
+               eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+
+               if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+                       wpa_s->own_disconnect_req = 1;
+               wpa_supplicant_deauthenticate(wpa_s,
+                                             WLAN_REASON_DEAUTH_LEAVING);
+       }
+
+       was_disabled = ssid->disabled;
 
-static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s,
-                                             struct wpa_ssid *ssid)
-{
-       if (!ssid || !ssid->disabled || ssid->disabled == 2)
-               return;
+       if (wpa_config_remove_network(wpa_s->conf, id) < 0)
+               return -2;
 
-       ssid->disabled = 0;
-       wpas_clear_temp_disabled(wpa_s, ssid, 1);
-       wpas_notify_network_enabled_changed(wpa_s, ssid);
+       if (!was_disabled && wpa_s->sched_scanning) {
+               wpa_printf(MSG_DEBUG,
+                          "Stop ongoing sched_scan to remove network from filters");
+               wpa_supplicant_cancel_sched_scan(wpa_s);
+               wpa_supplicant_req_scan(wpa_s, 0, 0);
+       }
 
-       /*
-        * Try to reassociate since there is no current configuration and a new
-        * network was made available.
-        */
-       if (!wpa_s->current_ssid && !wpa_s->disconnected)
-               wpa_s->reassociate = 1;
+       return 0;
 }
 
 
@@ -2782,13 +3330,19 @@ void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
                                wpas_notify_network_enabled_changed(
                                        wpa_s, other_ssid);
                }
-               if (wpa_s->current_ssid)
+               if (wpa_s->current_ssid) {
+                       if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+                               wpa_s->own_disconnect_req = 1;
                        wpa_supplicant_deauthenticate(
                                wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+               }
        } else if (ssid->disabled != 2) {
-               if (ssid == wpa_s->current_ssid)
+               if (ssid == wpa_s->current_ssid) {
+                       if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+                               wpa_s->own_disconnect_req = 1;
                        wpa_supplicant_deauthenticate(
                                wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+               }
 
                was_disabled = ssid->disabled;
 
@@ -2874,10 +3428,12 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
 
        wpa_s->disconnected = 0;
        wpa_s->reassociate = 1;
+       wpa_s->last_owe_group = 0;
 
        if (wpa_s->connect_without_scan ||
            wpa_supplicant_fast_associate(wpa_s) != 1) {
                wpa_s->scan_req = NORMAL_SCAN_REQ;
+               wpas_scan_reset_sched_scan(wpa_s);
                wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
        }
 
@@ -3090,6 +3646,41 @@ int wpa_supplicant_set_debug_params(struct wpa_global *global, int debug_level,
 }
 
 
+#ifdef CONFIG_OWE
+static int owe_trans_ssid_match(struct wpa_supplicant *wpa_s, const u8 *bssid,
+                               const u8 *entry_ssid, size_t entry_ssid_len)
+{
+       const u8 *owe, *pos, *end;
+       u8 ssid_len;
+       struct wpa_bss *bss;
+
+       /* Check network profile SSID aganst the SSID in the
+        * OWE Transition Mode element. */
+
+       bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
+       if (!bss)
+               return 0;
+
+       owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
+       if (!owe)
+               return 0;
+
+       pos = owe + 6;
+       end = owe + 2 + owe[1];
+
+       if (end - pos < ETH_ALEN + 1)
+               return 0;
+       pos += ETH_ALEN;
+       ssid_len = *pos++;
+       if (end - pos < ssid_len || ssid_len > SSID_MAX_LEN)
+               return 0;
+
+       return entry_ssid_len == ssid_len &&
+               os_memcmp(pos, entry_ssid, ssid_len) == 0;
+}
+#endif /* CONFIG_OWE */
+
+
 /**
  * wpa_supplicant_get_ssid - Get a pointer to the current network structure
  * @wpa_s: Pointer to wpa_supplicant data
@@ -3138,6 +3729,15 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
                        return entry;
 #endif /* CONFIG_WPS */
 
+#ifdef CONFIG_OWE
+               if (!wpas_network_disabled(wpa_s, entry) &&
+                   owe_trans_ssid_match(wpa_s, bssid, entry->ssid,
+                   entry->ssid_len) &&
+                   (!entry->bssid_set ||
+                    os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
+                       return entry;
+#endif /* CONFIG_OWE */
+
                if (!wpas_network_disabled(wpa_s, entry) && entry->bssid_set &&
                    entry->ssid_len == 0 &&
                    os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)
@@ -3238,15 +3838,12 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
        wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
        wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
 
-#ifdef CONFIG_PEERKEY
-       if (wpa_s->wpa_state > WPA_ASSOCIATED && wpa_s->current_ssid &&
-           wpa_s->current_ssid->peerkey &&
-           !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
-           wpa_sm_rx_eapol_peerkey(wpa_s->wpa, src_addr, buf, len) == 1) {
-               wpa_dbg(wpa_s, MSG_DEBUG, "RSN: Processed PeerKey EAPOL-Key");
+#ifdef CONFIG_TESTING_OPTIONS
+       if (wpa_s->ignore_auth_resp) {
+               wpa_printf(MSG_INFO, "RX EAPOL - ignore_auth_resp active!");
                return;
        }
-#endif /* CONFIG_PEERKEY */
+#endif /* CONFIG_TESTING_OPTIONS */
 
        if (wpa_s->wpa_state < WPA_ASSOCIATED ||
            (wpa_s->last_eapol_matches_bssid &&
@@ -3358,6 +3955,8 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
 
        os_memcpy(wpa_s->last_eapol_src, src_addr, ETH_ALEN);
        if (!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) &&
+           wpa_s->key_mgmt != WPA_KEY_MGMT_OWE &&
+           wpa_s->key_mgmt != WPA_KEY_MGMT_DPP &&
            eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
                return;
        wpa_drv_poll(wpa_s);
@@ -3526,6 +4125,7 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent)
        wpa_s->sched_scanning = 0;
 
        dl_list_init(&wpa_s->bss_tmp_disallowed);
+       dl_list_init(&wpa_s->fils_hlp_req);
 
        return wpa_s;
 }
@@ -3553,8 +4153,11 @@ static int wpa_set_htcap_mcs(struct wpa_supplicant *wpa_s,
        wpa_msg(wpa_s, MSG_DEBUG, "set_htcap, ht_mcs -:%s:-", ht_mcs);
 
        for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
+               long v;
+
                errno = 0;
-               long v = strtol(tmp, &end, 16);
+               v = strtol(tmp, &end, 16);
+
                if (errno == 0) {
                        wpa_msg(wpa_s, MSG_DEBUG,
                                "htcap value[%i]: %ld end: %p  tmp: %p",
@@ -3664,18 +4267,10 @@ static int wpa_set_disable_ht40(struct wpa_supplicant *wpa_s,
                                struct ieee80211_ht_capabilities *htcaps_mask,
                                int disabled)
 {
-       /* Masking these out disables HT40 */
-       le16 msk = host_to_le16(HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET |
-                               HT_CAP_INFO_SHORT_GI40MHZ);
-
        wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled);
 
-       if (disabled)
-               htcaps->ht_capabilities_info &= ~msk;
-       else
-               htcaps->ht_capabilities_info |= msk;
-
-       htcaps_mask->ht_capabilities_info |= msk;
+       set_disable_ht40(htcaps, disabled);
+       set_disable_ht40(htcaps_mask, 0);
 
        return 0;
 }
@@ -3778,8 +4373,8 @@ void wpa_supplicant_apply_vht_overrides(
        if (!vhtcaps || !vhtcaps_mask)
                return;
 
-       vhtcaps->vht_capabilities_info = ssid->vht_capa;
-       vhtcaps_mask->vht_capabilities_info = ssid->vht_capa_mask;
+       vhtcaps->vht_capabilities_info = host_to_le32(ssid->vht_capa);
+       vhtcaps_mask->vht_capabilities_info = host_to_le32(ssid->vht_capa_mask);
 
 #ifdef CONFIG_HT_OVERRIDES
        /* if max ampdu is <= 3, we have to make the HT cap the same */
@@ -3801,15 +4396,17 @@ void wpa_supplicant_apply_vht_overrides(
 #define OVERRIDE_MCS(i)                                                        \
        if (ssid->vht_tx_mcs_nss_ ##i >= 0) {                           \
                vhtcaps_mask->vht_supported_mcs_set.tx_map |=           \
-                       3 << 2 * (i - 1);                               \
+                       host_to_le16(3 << 2 * (i - 1));                 \
                vhtcaps->vht_supported_mcs_set.tx_map |=                \
-                       ssid->vht_tx_mcs_nss_ ##i << 2 * (i - 1);       \
+                       host_to_le16(ssid->vht_tx_mcs_nss_ ##i <<       \
+                                    2 * (i - 1));                      \
        }                                                               \
        if (ssid->vht_rx_mcs_nss_ ##i >= 0) {                           \
                vhtcaps_mask->vht_supported_mcs_set.rx_map |=           \
-                       3 << 2 * (i - 1);                               \
+                       host_to_le16(3 << 2 * (i - 1));                 \
                vhtcaps->vht_supported_mcs_set.rx_map |=                \
-                       ssid->vht_rx_mcs_nss_ ##i << 2 * (i - 1);       \
+                       host_to_le16(ssid->vht_rx_mcs_nss_ ##i <<       \
+                                    2 * (i - 1));                      \
        }
 
        OVERRIDE_MCS(1);
@@ -3949,10 +4546,14 @@ static int wpas_fst_send_action_cb(void *ctx, const u8 *da, struct wpabuf *data)
 {
        struct wpa_supplicant *wpa_s = ctx;
 
-       WPA_ASSERT(os_memcmp(wpa_s->bssid, da, ETH_ALEN) == 0);
+       if (os_memcmp(wpa_s->bssid, da, ETH_ALEN) != 0) {
+               wpa_printf(MSG_INFO, "FST:%s:bssid=" MACSTR " != da=" MACSTR,
+                          __func__, MAC2STR(wpa_s->bssid), MAC2STR(da));
+               return -1;
+       }
        return wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
-                                         wpa_s->own_addr, wpa_s->bssid,
-                                         wpabuf_head(data), wpabuf_len(data),
+                                  wpa_s->own_addr, wpa_s->bssid,
+                                  wpabuf_head(data), wpabuf_len(data),
                                   0);
 }
 
@@ -3981,8 +4582,9 @@ static void wpas_fst_update_mb_ie_cb(void *ctx, const u8 *addr,
 }
 
 
-const u8 * wpas_fst_get_peer_first(void *ctx, struct fst_get_peer_ctx **get_ctx,
-                                  Boolean mb_only)
+static const u8 * wpas_fst_get_peer_first(void *ctx,
+                                         struct fst_get_peer_ctx **get_ctx,
+                                         Boolean mb_only)
 {
        struct wpa_supplicant *wpa_s = ctx;
 
@@ -3994,8 +4596,9 @@ const u8 * wpas_fst_get_peer_first(void *ctx, struct fst_get_peer_ctx **get_ctx,
 }
 
 
-const u8 * wpas_fst_get_peer_next(void *ctx, struct fst_get_peer_ctx **get_ctx,
-                                 Boolean mb_only)
+static const u8 * wpas_fst_get_peer_next(void *ctx,
+                                        struct fst_get_peer_ctx **get_ctx,
+                                        Boolean mb_only)
 {
        return NULL;
 }
@@ -4138,7 +4741,7 @@ static void radio_work_free(struct wpa_radio_work *work)
        if (work->started) {
                work->wpa_s->radio->num_active_works--;
                wpa_dbg(work->wpa_s, MSG_DEBUG,
-                       "radio_work_free('%s'@%p: num_active_works --> %u",
+                       "radio_work_free('%s'@%p): num_active_works --> %u",
                        work->type, work,
                        work->wpa_s->radio->num_active_works);
        }
@@ -4148,6 +4751,20 @@ static void radio_work_free(struct wpa_radio_work *work)
 }
 
 
+static int radio_work_is_connect(struct wpa_radio_work *work)
+{
+       return os_strcmp(work->type, "sme-connect") == 0 ||
+               os_strcmp(work->type, "connect") == 0;
+}
+
+
+static int radio_work_is_scan(struct wpa_radio_work *work)
+{
+       return os_strcmp(work->type, "scan") == 0 ||
+               os_strcmp(work->type, "p2p-scan") == 0;
+}
+
+
 static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
 {
        struct wpa_radio_work *active_work = NULL;
@@ -4177,8 +4794,7 @@ static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
                return NULL;
        }
 
-       if (os_strcmp(active_work->type, "sme-connect") == 0 ||
-           os_strcmp(active_work->type, "connect") == 0) {
+       if (radio_work_is_connect(active_work)) {
                /*
                 * If the active work is either connect or sme-connect,
                 * do not parallelize them with other radio works.
@@ -4197,10 +4813,20 @@ static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
                 * If connect or sme-connect are enqueued, parallelize only
                 * those operations ahead of them in the queue.
                 */
-               if (os_strcmp(tmp->type, "connect") == 0 ||
-                   os_strcmp(tmp->type, "sme-connect") == 0)
+               if (radio_work_is_connect(tmp))
                        break;
 
+               /* Serialize parallel scan and p2p_scan operations on the same
+                * interface since the driver_nl80211 mechanism for tracking
+                * scan cookies does not yet have support for this. */
+               if (active_work->wpa_s == tmp->wpa_s &&
+                   radio_work_is_scan(active_work) &&
+                   radio_work_is_scan(tmp)) {
+                       wpa_dbg(active_work->wpa_s, MSG_DEBUG,
+                               "Do not start work '%s' when another work '%s' is already scheduled",
+                               tmp->type, active_work->type);
+                       continue;
+               }
                /*
                 * Check that the radio works are distinct and
                 * on different bands.
@@ -4522,11 +5148,47 @@ next_driver:
 }
 
 
+#ifdef CONFIG_GAS_SERVER
+
+static void wpas_gas_server_tx_status(struct wpa_supplicant *wpa_s,
+                                     unsigned int freq, const u8 *dst,
+                                     const u8 *src, const u8 *bssid,
+                                     const u8 *data, size_t data_len,
+                                     enum offchannel_send_action_result result)
+{
+       wpa_printf(MSG_DEBUG, "GAS: TX status: freq=%u dst=" MACSTR
+                  " result=%s",
+                  freq, MAC2STR(dst),
+                  result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
+                  (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
+                   "FAILED"));
+       gas_server_tx_status(wpa_s->gas_server, dst, data, data_len,
+                            result == OFFCHANNEL_SEND_ACTION_SUCCESS);
+}
+
+
+static void wpas_gas_server_tx(void *ctx, int freq, const u8 *da,
+                              struct wpabuf *buf, unsigned int wait_time)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+       if (wait_time > wpa_s->max_remain_on_chan)
+               wait_time = wpa_s->max_remain_on_chan;
+
+       offchannel_send_action(wpa_s, freq, da, wpa_s->own_addr, broadcast,
+                              wpabuf_head(buf), wpabuf_len(buf),
+                              wait_time, wpas_gas_server_tx_status, 0);
+}
+
+#endif /* CONFIG_GAS_SERVER */
+
 static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
                                     struct wpa_interface *iface)
 {
        struct wpa_driver_capa capa;
        int capa_res;
+       u8 dfs_domain;
 
        wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver "
                   "'%s' ctrl_interface '%s' bridge '%s'", iface->ifname,
@@ -4654,7 +5316,8 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
 
        wpa_s->hw.modes = wpa_drv_get_hw_feature_data(wpa_s,
                                                      &wpa_s->hw.num_modes,
-                                                     &wpa_s->hw.flags);
+                                                     &wpa_s->hw.flags,
+                                                     &dfs_domain);
        if (wpa_s->hw.modes) {
                u16 i;
 
@@ -4764,6 +5427,19 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
        if (wpas_wps_init(wpa_s))
                return -1;
 
+#ifdef CONFIG_GAS_SERVER
+       wpa_s->gas_server = gas_server_init(wpa_s, wpas_gas_server_tx);
+       if (!wpa_s->gas_server) {
+               wpa_printf(MSG_ERROR, "Failed to initialize GAS server");
+               return -1;
+       }
+#endif /* CONFIG_GAS_SERVER */
+
+#ifdef CONFIG_DPP
+       if (wpas_dpp_init(wpa_s) < 0)
+               return -1;
+#endif /* CONFIG_DPP */
+
        if (wpa_supplicant_init_eapol(wpa_s) < 0)
                return -1;
        wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
@@ -4796,6 +5472,12 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
        if (wpa_bss_init(wpa_s) < 0)
                return -1;
 
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+#ifdef CONFIG_MESH
+       dl_list_init(&wpa_s->mesh_external_pmksa_cache);
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
        /*
         * Set Wake-on-WLAN triggers, if configured.
         * Note: We don't restore/remove the triggers on shutdown (it doesn't
@@ -4807,8 +5489,8 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
 #ifdef CONFIG_EAP_PROXY
 {
        size_t len;
-       wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, wpa_s->imsi,
-                                                    &len);
+       wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, -1,
+                                                    wpa_s->imsi, &len);
        if (wpa_s->mnc_len > 0) {
                wpa_s->imsi[len] = '\0';
                wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)",
@@ -4833,9 +5515,22 @@ 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->conf->oce & OCE_STA) &&
+                   (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA))
+                       wpa_s->enable_oce = OCE_STA;
+               if ((wpa_s->conf->oce & OCE_STA_CFON) &&
+                   (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA_CFON)) {
+                       /* TODO: Need to add STA-CFON support */
+                       wpa_printf(MSG_ERROR,
+                                  "OCE STA-CFON feature is not yet supported");
+               }
+       }
        wpas_mbo_update_non_pref_chan(wpa_s, wpa_s->conf->non_pref_chan);
 #endif /* CONFIG_MBO */
 
+       wpa_supplicant_set_default_scan_ies(wpa_s);
+
        return 0;
 }
 
@@ -5095,6 +5790,7 @@ int wpa_supplicant_remove_iface(struct wpa_global *global,
 #ifdef CONFIG_MESH
        unsigned int mesh_if_created = wpa_s->mesh_if_created;
        char *ifname = NULL;
+       struct wpa_supplicant *parent = wpa_s->parent;
 #endif /* CONFIG_MESH */
 
        /* Remove interface from the global list of interfaces */
@@ -5130,7 +5826,7 @@ int wpa_supplicant_remove_iface(struct wpa_global *global,
 
 #ifdef CONFIG_MESH
        if (mesh_if_created) {
-               wpa_drv_if_remove(global->ifaces, WPA_IF_MESH, ifname);
+               wpa_drv_if_remove(parent, WPA_IF_MESH, ifname);
                os_free(ifname);
        }
 #endif /* CONFIG_MESH */
@@ -5494,6 +6190,16 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
        if (wpa_s->conf->changed_parameters & CFG_CHANGED_SCHED_SCAN_PLANS)
                wpas_sched_scan_plans_set(wpa_s, wpa_s->conf->sched_scan_plans);
 
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_WOWLAN_TRIGGERS) {
+               struct wpa_driver_capa capa;
+               int res = wpa_drv_get_capa(wpa_s, &capa);
+
+               if (res == 0 && wpas_set_wowlan_triggers(wpa_s, &capa) < 0)
+                       wpa_printf(MSG_ERROR,
+                                  "Failed to update wowlan_triggers to '%s'",
+                                  wpa_s->conf->wowlan_triggers);
+       }
+
 #ifdef CONFIG_WPS
        wpas_wps_update_config(wpa_s);
 #endif /* CONFIG_WPS */
@@ -5723,6 +6429,7 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
        case WPA_CTRL_REQ_SIM:
                str_clear_free(eap->external_sim_resp);
                eap->external_sim_resp = os_strdup(value);
+               eap->pending_req_sim = 0;
                break;
        case WPA_CTRL_REQ_PSK_PASSPHRASE:
                if (wpa_config_set(ssid, "psk", value, 0) < 0)
@@ -5791,6 +6498,7 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
 
        if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
            (!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk &&
+           !(wpa_key_mgmt_sae(ssid->key_mgmt) && ssid->sae_password) &&
            !ssid->mem_only_psk)
                return 1;
 
@@ -5812,6 +6520,19 @@ int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
                        return NO_MGMT_FRAME_PROTECTION;
                }
 
+               if (ssid &&
+                   (ssid->key_mgmt &
+                    ~(WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPS |
+                      WPA_KEY_MGMT_IEEE8021X_NO_WPA)) == 0) {
+                       /*
+                        * Do not use the default PMF value for non-RSN networks
+                        * since PMF is available only with RSN and pmf=2
+                        * configuration would otherwise prevent connections to
+                        * all open networks.
+                        */
+                       return NO_MGMT_FRAME_PROTECTION;
+               }
+
                return wpa_s->conf->pmf;
        }
 
@@ -5962,6 +6683,7 @@ void wpas_request_connection(struct wpa_supplicant *wpa_s)
        wpa_s->extra_blacklist_count = 0;
        wpa_s->disconnected = 0;
        wpa_s->reassociate = 1;
+       wpa_s->last_owe_group = 0;
 
        if (wpa_supplicant_fast_associate(wpa_s) != 1)
                wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -5970,6 +6692,27 @@ void wpas_request_connection(struct wpa_supplicant *wpa_s)
 }
 
 
+/**
+ * wpas_request_disconnection - Request disconnection
+ * @wpa_s: Pointer to the network interface
+ *
+ * This function is used to request disconnection from the currently connected
+ * network. This will stop any ongoing scans and initiate deauthentication.
+ */
+void wpas_request_disconnection(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_SME
+       wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+       wpa_s->reassociate = 0;
+       wpa_s->disconnected = 1;
+       wpa_supplicant_cancel_sched_scan(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);
+}
+
+
 void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title,
                    struct wpa_used_freq_data *freqs_data,
                    unsigned int len)
@@ -6067,271 +6810,6 @@ int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
 }
 
 
-static void wpas_rrm_neighbor_rep_timeout_handler(void *data, void *user_ctx)
-{
-       struct rrm_data *rrm = data;
-
-       if (!rrm->notify_neighbor_rep) {
-               wpa_printf(MSG_ERROR,
-                          "RRM: Unexpected neighbor report timeout");
-               return;
-       }
-
-       wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report - NONE");
-       rrm->notify_neighbor_rep(rrm->neighbor_rep_cb_ctx, NULL);
-
-       rrm->notify_neighbor_rep = NULL;
-       rrm->neighbor_rep_cb_ctx = NULL;
-}
-
-
-/*
- * wpas_rrm_reset - Clear and reset all RRM data in wpa_supplicant
- * @wpa_s: Pointer to wpa_supplicant
- */
-void wpas_rrm_reset(struct wpa_supplicant *wpa_s)
-{
-       wpa_s->rrm.rrm_used = 0;
-
-       eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
-                            NULL);
-       if (wpa_s->rrm.notify_neighbor_rep)
-               wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL);
-       wpa_s->rrm.next_neighbor_rep_token = 1;
-}
-
-
-/*
- * wpas_rrm_process_neighbor_rep - Handle incoming neighbor report
- * @wpa_s: Pointer to wpa_supplicant
- * @report: Neighbor report buffer, prefixed by a 1-byte dialog token
- * @report_len: Length of neighbor report buffer
- */
-void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
-                                  const u8 *report, size_t report_len)
-{
-       struct wpabuf *neighbor_rep;
-
-       wpa_hexdump(MSG_DEBUG, "RRM: New Neighbor Report", report, report_len);
-       if (report_len < 1)
-               return;
-
-       if (report[0] != wpa_s->rrm.next_neighbor_rep_token - 1) {
-               wpa_printf(MSG_DEBUG,
-                          "RRM: Discarding neighbor report with token %d (expected %d)",
-                          report[0], wpa_s->rrm.next_neighbor_rep_token - 1);
-               return;
-       }
-
-       eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
-                            NULL);
-
-       if (!wpa_s->rrm.notify_neighbor_rep) {
-               wpa_printf(MSG_ERROR, "RRM: Unexpected neighbor report");
-               return;
-       }
-
-       /* skipping the first byte, which is only an id (dialog token) */
-       neighbor_rep = wpabuf_alloc(report_len - 1);
-       if (neighbor_rep == NULL)
-               return;
-       wpabuf_put_data(neighbor_rep, report + 1, report_len - 1);
-       wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)",
-                  report[0]);
-       wpa_s->rrm.notify_neighbor_rep(wpa_s->rrm.neighbor_rep_cb_ctx,
-                                      neighbor_rep);
-       wpa_s->rrm.notify_neighbor_rep = NULL;
-       wpa_s->rrm.neighbor_rep_cb_ctx = NULL;
-}
-
-
-#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
-/* Workaround different, undefined for Windows, error codes used here */
-#define ENOTCONN -1
-#define EOPNOTSUPP -1
-#define ECANCELED -1
-#endif
-
-/**
- * wpas_rrm_send_neighbor_rep_request - Request a neighbor report from our AP
- * @wpa_s: Pointer to wpa_supplicant
- * @ssid: if not null, this is sent in the request. Otherwise, no SSID IE
- *       is sent in the request.
- * @cb: Callback function to be called once the requested report arrives, or
- *     timed out after RRM_NEIGHBOR_REPORT_TIMEOUT seconds.
- *     In the former case, 'neighbor_rep' is a newly allocated wpabuf, and it's
- *     the requester's responsibility to free it.
- *     In the latter case NULL will be sent in 'neighbor_rep'.
- * @cb_ctx: Context value to send the callback function
- * Returns: 0 in case of success, negative error code otherwise
- *
- * In case there is a previous request which has not been answered yet, the
- * new request fails. The caller may retry after RRM_NEIGHBOR_REPORT_TIMEOUT.
- * Request must contain a callback function.
- */
-int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
-                                      const struct wpa_ssid *ssid,
-                                      void (*cb)(void *ctx,
-                                                 struct wpabuf *neighbor_rep),
-                                      void *cb_ctx)
-{
-       struct wpabuf *buf;
-       const u8 *rrm_ie;
-
-       if (wpa_s->wpa_state != WPA_COMPLETED || wpa_s->current_ssid == NULL) {
-               wpa_printf(MSG_DEBUG, "RRM: No connection, no RRM.");
-               return -ENOTCONN;
-       }
-
-       if (!wpa_s->rrm.rrm_used) {
-               wpa_printf(MSG_DEBUG, "RRM: No RRM in current connection.");
-               return -EOPNOTSUPP;
-       }
-
-       rrm_ie = wpa_bss_get_ie(wpa_s->current_bss,
-                               WLAN_EID_RRM_ENABLED_CAPABILITIES);
-       if (!rrm_ie || !(wpa_s->current_bss->caps & IEEE80211_CAP_RRM) ||
-           !(rrm_ie[2] & WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
-               wpa_printf(MSG_DEBUG,
-                          "RRM: No network support for Neighbor Report.");
-               return -EOPNOTSUPP;
-       }
-
-       if (!cb) {
-               wpa_printf(MSG_DEBUG,
-                          "RRM: Neighbor Report request must provide a callback.");
-               return -EINVAL;
-       }
-
-       /* Refuse if there's a live request */
-       if (wpa_s->rrm.notify_neighbor_rep) {
-               wpa_printf(MSG_DEBUG,
-                          "RRM: Currently handling previous Neighbor Report.");
-               return -EBUSY;
-       }
-
-       /* 3 = action category + action code + dialog token */
-       buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0));
-       if (buf == NULL) {
-               wpa_printf(MSG_DEBUG,
-                          "RRM: Failed to allocate Neighbor Report Request");
-               return -ENOMEM;
-       }
-
-       wpa_printf(MSG_DEBUG, "RRM: Neighbor report request (for %s), token=%d",
-                  (ssid ? wpa_ssid_txt(ssid->ssid, ssid->ssid_len) : ""),
-                  wpa_s->rrm.next_neighbor_rep_token);
-
-       wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
-       wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_REQUEST);
-       wpabuf_put_u8(buf, wpa_s->rrm.next_neighbor_rep_token);
-       if (ssid) {
-               wpabuf_put_u8(buf, WLAN_EID_SSID);
-               wpabuf_put_u8(buf, ssid->ssid_len);
-               wpabuf_put_data(buf, ssid->ssid, ssid->ssid_len);
-       }
-
-       wpa_s->rrm.next_neighbor_rep_token++;
-
-       if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
-                               wpa_s->own_addr, wpa_s->bssid,
-                               wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
-               wpa_printf(MSG_DEBUG,
-                          "RRM: Failed to send Neighbor Report Request");
-               wpabuf_free(buf);
-               return -ECANCELED;
-       }
-
-       wpa_s->rrm.neighbor_rep_cb_ctx = cb_ctx;
-       wpa_s->rrm.notify_neighbor_rep = cb;
-       eloop_register_timeout(RRM_NEIGHBOR_REPORT_TIMEOUT, 0,
-                              wpas_rrm_neighbor_rep_timeout_handler,
-                              &wpa_s->rrm, NULL);
-
-       wpabuf_free(buf);
-       return 0;
-}
-
-
-void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
-                                             const u8 *src,
-                                             const u8 *frame, size_t len,
-                                             int rssi)
-{
-       struct wpabuf *buf;
-       const struct rrm_link_measurement_request *req;
-       struct rrm_link_measurement_report report;
-
-       if (wpa_s->wpa_state != WPA_COMPLETED) {
-               wpa_printf(MSG_INFO,
-                          "RRM: Ignoring link measurement request. Not associated");
-               return;
-       }
-
-       if (!wpa_s->rrm.rrm_used) {
-               wpa_printf(MSG_INFO,
-                          "RRM: Ignoring link measurement request. Not RRM network");
-               return;
-       }
-
-       if (!(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) {
-               wpa_printf(MSG_INFO,
-                          "RRM: Measurement report failed. TX power insertion not supported");
-               return;
-       }
-
-       req = (const struct rrm_link_measurement_request *) frame;
-       if (len < sizeof(*req)) {
-               wpa_printf(MSG_INFO,
-                          "RRM: Link measurement report failed. Request too short");
-               return;
-       }
-
-       os_memset(&report, 0, sizeof(report));
-       report.tpc.eid = WLAN_EID_TPC_REPORT;
-       report.tpc.len = 2;
-       report.rsni = 255; /* 255 indicates that RSNI is not available */
-       report.dialog_token = req->dialog_token;
-
-       /*
-        * It's possible to estimate RCPI based on RSSI in dBm. This
-        * calculation will not reflect the correct value for high rates,
-        * but it's good enough for Action frames which are transmitted
-        * with up to 24 Mbps rates.
-        */
-       if (!rssi)
-               report.rcpi = 255; /* not available */
-       else if (rssi < -110)
-               report.rcpi = 0;
-       else if (rssi > 0)
-               report.rcpi = 220;
-       else
-               report.rcpi = (rssi + 110) * 2;
-
-       /* action_category + action_code */
-       buf = wpabuf_alloc(2 + sizeof(report));
-       if (buf == NULL) {
-               wpa_printf(MSG_ERROR,
-                          "RRM: Link measurement report failed. Buffer allocation failed");
-               return;
-       }
-
-       wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
-       wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REPORT);
-       wpabuf_put_data(buf, &report, sizeof(report));
-       wpa_hexdump(MSG_DEBUG, "RRM: Link measurement report:",
-                   wpabuf_head(buf), wpabuf_len(buf));
-
-       if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src,
-                               wpa_s->own_addr, wpa_s->bssid,
-                               wpabuf_head(buf), wpabuf_len(buf), 0)) {
-               wpa_printf(MSG_ERROR,
-                          "RRM: Link measurement report failed. Send action failed");
-       }
-       wpabuf_free(buf);
-}
-
-
 struct wpa_supplicant *
 wpas_vendor_elem(struct wpa_supplicant *wpa_s, enum wpa_vendor_elem_frame frame)
 {
@@ -6445,18 +6923,56 @@ wpa_bss_tmp_disallowed * wpas_get_disallowed_bss(struct wpa_supplicant *wpa_s,
 }
 
 
+static int wpa_set_driver_tmp_disallow_list(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_bss_tmp_disallowed *tmp;
+       unsigned int num_bssid = 0;
+       u8 *bssids;
+       int ret;
+
+       bssids = os_malloc(dl_list_len(&wpa_s->bss_tmp_disallowed) * ETH_ALEN);
+       if (!bssids)
+               return -1;
+       dl_list_for_each(tmp, &wpa_s->bss_tmp_disallowed,
+                        struct wpa_bss_tmp_disallowed, list) {
+               os_memcpy(&bssids[num_bssid * ETH_ALEN], tmp->bssid,
+                         ETH_ALEN);
+               num_bssid++;
+       }
+       ret = wpa_drv_set_bssid_blacklist(wpa_s, num_bssid, bssids);
+       os_free(bssids);
+       return ret;
+}
+
+
+static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+       struct wpa_bss_tmp_disallowed *tmp, *bss = timeout_ctx;
+
+       /* Make sure the bss is not already freed */
+       dl_list_for_each(tmp, &wpa_s->bss_tmp_disallowed,
+                        struct wpa_bss_tmp_disallowed, list) {
+               if (bss == tmp) {
+                       dl_list_del(&tmp->list);
+                       os_free(tmp);
+                       wpa_set_driver_tmp_disallow_list(wpa_s);
+                       break;
+               }
+       }
+}
+
+
 void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
                          unsigned int sec)
 {
        struct wpa_bss_tmp_disallowed *bss;
-       struct os_reltime until;
-
-       os_get_reltime(&until);
-       until.sec += sec;
 
        bss = wpas_get_disallowed_bss(wpa_s, bssid);
        if (bss) {
-               bss->disallowed_until = until;
+               eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss);
+               eloop_register_timeout(sec, 0, wpa_bss_tmp_disallow_timeout,
+                                      wpa_s, bss);
                return;
        }
 
@@ -6467,27 +6983,20 @@ void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
                return;
        }
 
-       bss->disallowed_until = until;
        os_memcpy(bss->bssid, bssid, ETH_ALEN);
        dl_list_add(&wpa_s->bss_tmp_disallowed, &bss->list);
+       wpa_set_driver_tmp_disallow_list(wpa_s);
+       eloop_register_timeout(sec, 0, wpa_bss_tmp_disallow_timeout,
+                              wpa_s, bss);
 }
 
 
 int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, const u8 *bssid)
 {
        struct wpa_bss_tmp_disallowed *bss = NULL, *tmp, *prev;
-       struct os_reltime now, age;
-
-       os_get_reltime(&now);
 
        dl_list_for_each_safe(tmp, prev, &wpa_s->bss_tmp_disallowed,
                         struct wpa_bss_tmp_disallowed, list) {
-               if (!os_reltime_before(&now, &tmp->disallowed_until)) {
-                       /* This BSS is not disallowed anymore */
-                       dl_list_del(&tmp->list);
-                       os_free(tmp);
-                       continue;
-               }
                if (os_memcmp(bssid, tmp->bssid, ETH_ALEN) == 0) {
                        bss = tmp;
                        break;
@@ -6496,9 +7005,5 @@ int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, const u8 *bssid)
        if (!bss)
                return 0;
 
-       os_reltime_sub(&bss->disallowed_until, &now, &age);
-       wpa_printf(MSG_DEBUG,
-                  "BSS " MACSTR " disabled for %ld.%0ld seconds",
-                  MAC2STR(bss->bssid), age.sec, age.usec);
        return 1;
 }