]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - wpa_supplicant/wpa_supplicant.c
Test functionality to override driver reported signal levels
[thirdparty/hostap.git] / wpa_supplicant / wpa_supplicant.c
index be45f2e38fdb1202edfff81669e72e2ec1a728d8..0a9e37c3b01cd530d86d810d0763eb343cf80cb0 100644 (file)
@@ -125,6 +125,9 @@ static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx);
 #if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
 static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s);
 #endif /* CONFIG_FILS && IEEE8021X_EAPOL */
+#ifdef CONFIG_OWE
+static void wpas_update_owe_connect_params(struct wpa_supplicant *wpa_s);
+#endif /* CONFIG_OWE */
 
 
 /* Configure default/group WEP keys for static WEP */
@@ -399,7 +402,10 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
                wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
        wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
        wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
+       wpa_sm_set_ap_rsnxe(wpa_s->wpa, NULL, 0);
        wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+       wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+       wpa_s->rsnxe_len = 0;
        wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
        wpa_s->group_cipher = WPA_CIPHER_NONE;
        wpa_s->mgmt_group_cipher = 0;
@@ -421,10 +427,8 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
        wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
                         wpa_s->pairwise_cipher);
        wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
-#ifdef CONFIG_IEEE80211W
        wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
                         wpa_s->mgmt_group_cipher);
-#endif /* CONFIG_IEEE80211W */
 
        pmksa_cache_clear_current(wpa_s->wpa);
 }
@@ -472,6 +476,31 @@ void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s)
 }
 
 
+void wpas_clear_disabled_interface(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+
+       if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
+               return;
+       wpa_dbg(wpa_s, MSG_DEBUG, "Clear cached state on disabled interface");
+       wpa_bss_flush(wpa_s);
+}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+void wpas_clear_driver_signal_override(struct wpa_supplicant *wpa_s)
+{
+       struct driver_signal_override *dso;
+
+       while ((dso = dl_list_first(&wpa_s->drv_signal_override,
+                                   struct driver_signal_override, list))) {
+               dl_list_del(&dso->list);
+               os_free(dso);
+       }
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
 static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 {
        int i;
@@ -495,6 +524,13 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
        wpa_s->get_pref_freq_list_override = NULL;
        wpabuf_free(wpa_s->last_assoc_req_wpa_ie);
        wpa_s->last_assoc_req_wpa_ie = NULL;
+       os_free(wpa_s->extra_sae_rejected_groups);
+       wpa_s->extra_sae_rejected_groups = NULL;
+       wpabuf_free(wpa_s->rsnxe_override_assoc);
+       wpa_s->rsnxe_override_assoc = NULL;
+       wpabuf_free(wpa_s->rsnxe_override_eapol);
+       wpa_s->rsnxe_override_eapol = NULL;
+       wpas_clear_driver_signal_override(wpa_s);
 #endif /* CONFIG_TESTING_OPTIONS */
 
        if (wpa_s->conf != NULL) {
@@ -541,6 +577,7 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 #endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
 
        eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+       eloop_cancel_timeout(wpas_clear_disabled_interface, wpa_s, NULL);
 
        wpas_wps_deinit(wpa_s);
 
@@ -690,13 +727,7 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
  */
 void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
 {
-       int i, max;
-
-#ifdef CONFIG_IEEE80211W
-       max = 6;
-#else /* CONFIG_IEEE80211W */
-       max = 4;
-#endif /* CONFIG_IEEE80211W */
+       int i, max = 6;
 
        /* MLME-DELETEKEYS.request */
        for (i = 0; i < max; i++) {
@@ -845,6 +876,9 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
                              enum wpa_states state)
 {
        enum wpa_states old_state = wpa_s->wpa_state;
+#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
+       Boolean update_fils_connect_params = FALSE;
+#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
 
        wpa_dbg(wpa_s, MSG_DEBUG, "State: %s -> %s",
                wpa_supplicant_state_txt(wpa_s->wpa_state),
@@ -942,8 +976,12 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
 
 #if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
                if (!fils_hlp_sent && ssid && ssid->eap.erp)
-                       wpas_update_fils_connect_params(wpa_s);
+                       update_fils_connect_params = TRUE;
 #endif /* CONFIG_FILS && IEEE8021X_EAPOL */
+#ifdef CONFIG_OWE
+               if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_OWE))
+                       wpas_update_owe_connect_params(wpa_s);
+#endif /* CONFIG_OWE */
        } else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
                   state == WPA_ASSOCIATED) {
                wpa_s->new_connection = 1;
@@ -983,7 +1021,15 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
                if (wpa_s->wpa_state == WPA_COMPLETED ||
                    old_state == WPA_COMPLETED)
                        wpas_notify_auth_changed(wpa_s);
+#ifdef CONFIG_DPP2
+               if (wpa_s->wpa_state == WPA_COMPLETED)
+                       wpas_dpp_connected(wpa_s);
+#endif /* CONFIG_DPP2 */
        }
+#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
+       if (update_fils_connect_params)
+               wpas_update_fils_connect_params(wpa_s);
+#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
 }
 
 
@@ -1179,7 +1225,6 @@ static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
                return -1;
        }
 
-#ifdef CONFIG_IEEE80211W
        if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
            wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
                wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
@@ -1187,7 +1232,6 @@ static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
                        "reject");
                return -1;
        }
-#endif /* CONFIG_IEEE80211W */
 
        return 0;
 }
@@ -1225,14 +1269,16 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 {
        struct wpa_ie_data ie;
        int sel, proto;
-       const u8 *bss_wpa, *bss_rsn, *bss_osen;
+       const u8 *bss_wpa, *bss_rsn, *bss_rsnx, *bss_osen;
 
        if (bss) {
                bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
                bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+               bss_rsnx = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
                bss_osen = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
-       } else
-               bss_wpa = bss_rsn = bss_osen = NULL;
+       } else {
+               bss_wpa = bss_rsn = bss_rsnx = bss_osen = NULL;
+       }
 
        if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) &&
            wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
@@ -1312,7 +1358,6 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                        ie.group_cipher = ssid->group_cipher;
                        ie.pairwise_cipher = ssid->pairwise_cipher;
                        ie.key_mgmt = ssid->key_mgmt;
-#ifdef CONFIG_IEEE80211W
                        ie.mgmt_group_cipher = 0;
                        if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
                                if (ssid->group_mgmt_cipher &
@@ -1331,7 +1376,6 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                                        ie.mgmt_group_cipher =
                                                WPA_CIPHER_AES_128_CMAC;
                        }
-#endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_OWE
                        if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
                            !ssid->owe_only &&
@@ -1351,12 +1395,10 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
        wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected cipher suites: group %d "
                "pairwise %d key_mgmt %d proto %d",
                ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt, proto);
-#ifdef CONFIG_IEEE80211W
        if (ssid->ieee80211w) {
                wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected mgmt group cipher %d",
                        ie.mgmt_group_cipher);
        }
-#endif /* CONFIG_IEEE80211W */
 
        wpa_s->wpa_proto = proto;
        wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
@@ -1367,7 +1409,9 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
                                         bss_wpa ? 2 + bss_wpa[1] : 0) ||
                    wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
-                                        bss_rsn ? 2 + bss_rsn[1] : 0))
+                                        bss_rsn ? 2 + bss_rsn[1] : 0) ||
+                   wpa_sm_set_ap_rsnxe(wpa_s->wpa, bss_rsnx,
+                                       bss_rsnx ? 2 + bss_rsnx[1] : 0))
                        return -1;
        }
 
@@ -1413,7 +1457,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
        if (0) {
 #ifdef CONFIG_IEEE80211R
 #ifdef CONFIG_SHA384
-       } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
+       } else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) &&
+                  os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) {
                wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
                wpa_dbg(wpa_s, MSG_DEBUG,
                        "WPA: using KEY_MGMT FT/802.1X-SHA384");
@@ -1456,7 +1501,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA256");
 #endif /* CONFIG_FILS */
 #ifdef CONFIG_IEEE80211R
-       } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
+       } else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X) &&
+                  os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) {
                wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
                wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/802.1X");
                if (!ssid->ft_eap_pmksa_caching &&
@@ -1486,7 +1532,6 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
                wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
 #endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
        } else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
                wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
                wpa_dbg(wpa_s, MSG_DEBUG,
@@ -1495,7 +1540,6 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                wpa_s->key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
                wpa_dbg(wpa_s, MSG_DEBUG,
                        "WPA: using KEY_MGMT PSK with SHA256");
-#endif /* CONFIG_IEEE80211W */
        } else if (sel & WPA_KEY_MGMT_IEEE8021X) {
                wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
                wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X");
@@ -1526,7 +1570,13 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                         wpa_s->pairwise_cipher);
        wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
 
-#ifdef CONFIG_IEEE80211W
+       if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
+           wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
+               wpa_msg(wpa_s, MSG_INFO,
+                       "RSN: Management frame protection required but the selected AP does not enable it");
+               return -1;
+       }
+
        sel = ie.mgmt_group_cipher;
        if (ssid->group_mgmt_cipher)
                sel &= ssid->group_mgmt_cipher;
@@ -1560,16 +1610,23 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                         wpa_s->mgmt_group_cipher);
        wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
                         wpas_get_ssid_pmf(wpa_s, ssid));
-#endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_OCV
        wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, ssid->ocv);
 #endif /* CONFIG_OCV */
+       wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PWE, wpa_s->conf->sae_pwe);
 
        if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
                wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE");
                return -1;
        }
 
+       wpa_s->rsnxe_len = sizeof(wpa_s->rsnxe);
+       if (wpa_sm_set_assoc_rsnxe_default(wpa_s->wpa, wpa_s->rsnxe,
+                                          &wpa_s->rsnxe_len)) {
+               wpa_msg(wpa_s, MSG_WARNING, "RSN: Failed to generate RSNXE");
+               return -1;
+       }
+
        if (0) {
 #ifdef CONFIG_DPP
        } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP) {
@@ -1711,7 +1768,7 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
        case 2: /* Bits 16-23 */
 #ifdef CONFIG_WNM
                *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
-               if (!wpa_s->conf->disable_btm)
+               if (!wpa_s->disable_mbo_oce && !wpa_s->conf->disable_btm)
                        *pos |= 0x08; /* Bit 19 - BSS Transition */
 #endif /* CONFIG_WNM */
                break;
@@ -1918,6 +1975,58 @@ int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s)
 }
 
 
+static void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_SAE
+       int *groups = conf->sae_groups;
+       int default_groups[] = { 19, 20, 21, 0 };
+       const char *password;
+
+       if (!groups || groups[0] <= 0)
+               groups = default_groups;
+
+       password = ssid->sae_password;
+       if (!password)
+               password = ssid->passphrase;
+
+       if (conf->sae_pwe == 0 || !password) {
+               /* PT derivation not needed */
+               sae_deinit_pt(ssid->pt);
+               ssid->pt = NULL;
+               return;
+       }
+
+       if (ssid->pt)
+               return; /* PT already derived */
+       ssid->pt = sae_derive_pt(groups, ssid->ssid, ssid->ssid_len,
+                                (const u8 *) password, os_strlen(password),
+                                ssid->sae_password_id);
+#endif /* CONFIG_SAE */
+}
+
+
+static void wpa_s_clear_sae_rejected(struct wpa_supplicant *wpa_s)
+{
+#if defined(CONFIG_SAE) && defined(CONFIG_SME)
+       os_free(wpa_s->sme.sae_rejected_groups);
+       wpa_s->sme.sae_rejected_groups = NULL;
+#ifdef CONFIG_TESTING_OPTIONS
+       if (wpa_s->extra_sae_rejected_groups) {
+               int i, *groups = wpa_s->extra_sae_rejected_groups;
+
+               for (i = 0; groups[i]; i++) {
+                       wpa_printf(MSG_DEBUG,
+                                  "TESTING: Indicate rejection of an extra SAE group %d",
+                                  groups[i]);
+                       int_array_add_unique(&wpa_s->sme.sae_rejected_groups,
+                                            groups[i]);
+               }
+       }
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_SAE && CONFIG_SME */
+}
+
+
 static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit);
 
 /**
@@ -1964,6 +2073,11 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                } else if (wpa_s->current_bss && wpa_s->current_bss != bss) {
                        os_get_reltime(&wpa_s->roam_start);
                }
+       } else {
+#ifdef CONFIG_SAE
+               wpa_s_clear_sae_rejected(wpa_s);
+               wpa_s_setup_sae_pt(wpa_s->conf, ssid);
+#endif /* CONFIG_SAE */
        }
 
        if (rand_style > 0 && !wpa_s->reassoc_same_ess) {
@@ -2065,6 +2179,10 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                                bss->ie_len);
 #endif /* CONFIG_TDLS */
 
+#ifdef CONFIG_MBO
+       wpas_mbo_check_pmf(wpa_s, bss, ssid);
+#endif /* CONFIG_MBO */
+
        if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
            ssid->mode == WPAS_MODE_INFRA) {
                sme_authenticate(wpa_s, bss, ssid);
@@ -2153,6 +2271,7 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
        struct hostapd_freq_params vht_freq;
        int chwidth, seg0, seg1;
        u32 vht_caps = 0;
+       int is_24ghz;
 
        freq->freq = ssid->frequency;
 
@@ -2204,8 +2323,8 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
        if (!mode)
                return;
 
-       /* HE can work without HT + VHT */
-       freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported;
+       is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
+               hw_mode == HOSTAPD_MODE_IEEE80211B;
 
 #ifdef CONFIG_HT_OVERRIDES
        if (ssid->disable_ht) {
@@ -2218,6 +2337,10 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
        if (!freq->ht_enabled)
                return;
 
+       /* Allow HE on 2.4 GHz without VHT: see nl80211_put_freq_params() */
+       if (is_24ghz)
+               freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported;
+
        /* Setup higher BW only for 5 GHz */
        if (mode->mode != HOSTAPD_MODE_IEEE80211A)
                return;
@@ -2286,8 +2409,7 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
                        return;
                }
 
-               res = check_40mhz_5g(mode, scan_res, pri_chan->chan,
-                                    sec_chan->chan);
+               res = check_40mhz_5g(scan_res, pri_chan, sec_chan);
                switch (res) {
                case 0:
                        /* Back to HT20 */
@@ -2338,6 +2460,9 @@ skip_ht40:
        if (!vht_freq.vht_enabled)
                return;
 
+       /* Enable HE for VHT */
+       vht_freq.he_enabled = mode->he_capab[ieee80211_mode].he_supported;
+
        /* setup center_freq1, bandwidth */
        for (j = 0; j < ARRAY_SIZE(vht80); j++) {
                if (freq->channel >= vht80[j] &&
@@ -2412,7 +2537,8 @@ skip_ht40:
        }
 
        if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
-                                   freq->channel, freq->ht_enabled,
+                                   freq->channel, ssid->enable_edmg,
+                                   ssid->edmg_channel, freq->ht_enabled,
                                    vht_freq.vht_enabled, freq->he_enabled,
                                    freq->sec_channel_offset,
                                    chwidth, seg0, seg1, vht_caps,
@@ -2815,7 +2941,7 @@ static u8 * wpas_populate_assoc_ies(
 
 #ifdef CONFIG_MBO
        mbo_ie = bss ? wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE) : NULL;
-       if (mbo_ie) {
+       if (!wpa_s->disable_mbo_oce && mbo_ie) {
                int len;
 
                len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
@@ -2930,6 +3056,23 @@ pfs_fail:
        }
 #endif /* CONFIG_IEEE80211R */
 
+#ifdef CONFIG_TESTING_OPTIONS
+       if (wpa_s->rsnxe_override_assoc &&
+           wpabuf_len(wpa_s->rsnxe_override_assoc) <=
+           max_wpa_ie_len - wpa_ie_len) {
+               wpa_printf(MSG_DEBUG, "TESTING: RSNXE AssocReq override");
+               os_memcpy(wpa_ie + wpa_ie_len,
+                         wpabuf_head(wpa_s->rsnxe_override_assoc),
+                         wpabuf_len(wpa_s->rsnxe_override_assoc));
+               wpa_ie_len += wpabuf_len(wpa_s->rsnxe_override_assoc);
+       } else
+#endif /* CONFIG_TESTING_OPTIONS */
+       if (wpa_s->rsnxe_len > 0 &&
+           wpa_s->rsnxe_len <= max_wpa_ie_len - wpa_ie_len) {
+               os_memcpy(wpa_ie + wpa_ie_len, wpa_s->rsnxe, wpa_s->rsnxe_len);
+               wpa_ie_len += wpa_s->rsnxe_len;
+       }
+
        if (ssid->multi_ap_backhaul_sta) {
                size_t multi_ap_ie_len;
 
@@ -2955,6 +3098,24 @@ pfs_fail:
 }
 
 
+#ifdef CONFIG_OWE
+static void wpas_update_owe_connect_params(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_driver_associate_params params;
+       u8 *wpa_ie;
+
+       os_memset(&params, 0, sizeof(params));
+       wpa_ie = wpas_populate_assoc_ies(wpa_s, wpa_s->current_bss,
+                                        wpa_s->current_ssid, &params, NULL);
+       if (!wpa_ie)
+               return;
+
+       wpa_drv_update_connect_params(wpa_s, &params, WPA_DRV_UPDATE_ASSOC_IES);
+       os_free(wpa_ie);
+}
+#endif /* CONFIG_OWE */
+
+
 #if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
 static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s)
 {
@@ -2983,6 +3144,117 @@ static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s)
 #endif /* CONFIG_FILS && IEEE8021X_EAPOL */
 
 
+static u8 wpa_ie_get_edmg_oper_chans(const u8 *edmg_ie)
+{
+       if (!edmg_ie || edmg_ie[1] < 6)
+               return 0;
+       return edmg_ie[EDMG_BSS_OPERATING_CHANNELS_OFFSET];
+}
+
+
+static u8 wpa_ie_get_edmg_oper_chan_width(const u8 *edmg_ie)
+{
+       if (!edmg_ie || edmg_ie[1] < 6)
+               return 0;
+       return edmg_ie[EDMG_OPERATING_CHANNEL_WIDTH_OFFSET];
+}
+
+
+/* Returns the intersection of two EDMG configurations.
+ * Note: The current implementation is limited to CB2 only (CB1 included),
+ * i.e., the implementation supports up to 2 contiguous channels.
+ * For supporting non-contiguous (aggregated) channels and for supporting
+ * CB3 and above, this function will need to be extended.
+ */
+static struct ieee80211_edmg_config
+get_edmg_intersection(struct ieee80211_edmg_config a,
+                     struct ieee80211_edmg_config b,
+                     u8 primary_channel)
+{
+       struct ieee80211_edmg_config result;
+       int i, contiguous = 0;
+       int max_contiguous = 0;
+
+       result.channels = b.channels & a.channels;
+       if (!result.channels) {
+               wpa_printf(MSG_DEBUG,
+                          "EDMG not possible: cannot intersect channels 0x%x and 0x%x",
+                          a.channels, b.channels);
+               goto fail;
+       }
+
+       if (!(result.channels & BIT(primary_channel - 1))) {
+               wpa_printf(MSG_DEBUG,
+                          "EDMG not possible: the primary channel %d is not one of the intersected channels 0x%x",
+                          primary_channel, result.channels);
+               goto fail;
+       }
+
+       /* Find max contiguous channels */
+       for (i = 0; i < 6; i++) {
+               if (result.channels & BIT(i))
+                       contiguous++;
+               else
+                       contiguous = 0;
+
+               if (contiguous > max_contiguous)
+                       max_contiguous = contiguous;
+       }
+
+       /* Assuming AP and STA supports ONLY contiguous channels,
+        * bw configuration can have value between 4-7.
+        */
+       if ((b.bw_config < a.bw_config))
+               result.bw_config = b.bw_config;
+       else
+               result.bw_config = a.bw_config;
+
+       if ((max_contiguous >= 2 && result.bw_config < EDMG_BW_CONFIG_5) ||
+           (max_contiguous >= 1 && result.bw_config < EDMG_BW_CONFIG_4)) {
+               wpa_printf(MSG_DEBUG,
+                          "EDMG not possible: not enough contiguous channels %d for supporting CB1 or CB2",
+                          max_contiguous);
+               goto fail;
+       }
+
+       return result;
+
+fail:
+       result.channels = 0;
+       result.bw_config = 0;
+       return result;
+}
+
+
+static struct ieee80211_edmg_config
+get_supported_edmg(struct wpa_supplicant *wpa_s,
+                  struct hostapd_freq_params *freq,
+                  struct ieee80211_edmg_config request_edmg)
+{
+       enum hostapd_hw_mode hw_mode;
+       struct hostapd_hw_modes *mode = NULL;
+       u8 primary_channel;
+
+       if (!wpa_s->hw.modes)
+               goto fail;
+
+       hw_mode = ieee80211_freq_to_chan(freq->freq, &primary_channel);
+       if (hw_mode == NUM_HOSTAPD_MODES)
+               goto fail;
+
+       mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, hw_mode);
+       if (!mode)
+               goto fail;
+
+       return get_edmg_intersection(mode->edmg, request_edmg, primary_channel);
+
+fail:
+       request_edmg.channels = 0;
+       request_edmg.bw_config = 0;
+       return request_edmg;
+}
+
+
 #ifdef CONFIG_MBO
 void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s)
 {
@@ -3018,6 +3290,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        struct wpa_ssid *ssid = cwork->ssid;
        struct wpa_supplicant *wpa_s = work->wpa_s;
        u8 *wpa_ie;
+       const u8 *edmg_ie_oper;
        int use_crypt, ret, i, bssid_changed;
        unsigned int cipher_pairwise, cipher_group, cipher_group_mgmt;
        struct wpa_driver_associate_params params;
@@ -3110,6 +3383,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        /* Starting new association, so clear the possibly used WPA IE from the
         * previous association. */
        wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+       wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+       wpa_s->rsnxe_len = 0;
 
        wpa_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, &params, NULL);
        if (!wpa_ie) {
@@ -3201,6 +3476,71 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                        params.beacon_int = wpa_s->conf->beacon_int;
        }
 
+       if (bss && ssid->enable_edmg)
+               edmg_ie_oper = get_ie_ext((const u8 *) (bss + 1), bss->ie_len,
+                                         WLAN_EID_EXT_EDMG_OPERATION);
+       else
+               edmg_ie_oper = NULL;
+
+       if (edmg_ie_oper) {
+               params.freq.edmg.channels =
+                       wpa_ie_get_edmg_oper_chans(edmg_ie_oper);
+               params.freq.edmg.bw_config =
+                       wpa_ie_get_edmg_oper_chan_width(edmg_ie_oper);
+               wpa_printf(MSG_DEBUG,
+                          "AP supports EDMG channels 0x%x, bw_config %d",
+                          params.freq.edmg.channels,
+                          params.freq.edmg.bw_config);
+
+               /* User may ask for specific EDMG channel for EDMG connection
+                * (must be supported by AP)
+                */
+               if (ssid->edmg_channel) {
+                       struct ieee80211_edmg_config configured_edmg;
+                       enum hostapd_hw_mode hw_mode;
+                       u8 primary_channel;
+
+                       hw_mode = ieee80211_freq_to_chan(bss->freq,
+                                                        &primary_channel);
+                       if (hw_mode == NUM_HOSTAPD_MODES)
+                               goto edmg_fail;
+
+                       hostapd_encode_edmg_chan(ssid->enable_edmg,
+                                                ssid->edmg_channel,
+                                                primary_channel,
+                                                &configured_edmg);
+
+                       if (ieee802_edmg_is_allowed(params.freq.edmg,
+                                                   configured_edmg)) {
+                               params.freq.edmg = configured_edmg;
+                               wpa_printf(MSG_DEBUG,
+                                          "Use EDMG channel %d for connection",
+                                          ssid->edmg_channel);
+                       } else {
+                       edmg_fail:
+                               params.freq.edmg.channels = 0;
+                               params.freq.edmg.bw_config = 0;
+                               wpa_printf(MSG_WARNING,
+                                          "EDMG channel %d not supported by AP, fallback to DMG",
+                                          ssid->edmg_channel);
+                       }
+               }
+
+               if (params.freq.edmg.channels) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EDMG before: channels 0x%x, bw_config %d",
+                                  params.freq.edmg.channels,
+                                  params.freq.edmg.bw_config);
+                       params.freq.edmg = get_supported_edmg(wpa_s,
+                                                             &params.freq,
+                                                             params.freq.edmg);
+                       wpa_printf(MSG_DEBUG,
+                                  "EDMG after: channels 0x%x, bw_config %d",
+                                  params.freq.edmg.channels,
+                                  params.freq.edmg.bw_config);
+               }
+       }
+
        params.pairwise_suite = cipher_pairwise;
        params.group_suite = cipher_group;
        params.mgmt_group_suite = cipher_group_mgmt;
@@ -3229,7 +3569,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
             params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
             params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
             params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192))
-               params.req_key_mgmt_offload = 1;
+               params.req_handshake_offload = 1;
 
        if (wpa_s->conf->key_mgmt_offload) {
                if (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
@@ -3251,7 +3591,6 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
 
        params.drop_unencrypted = use_crypt;
 
-#ifdef CONFIG_IEEE80211W
        params.mgmt_frame_protection = wpas_get_ssid_pmf(wpa_s, ssid);
        if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) {
                const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
@@ -3270,7 +3609,6 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
 #endif /* CONFIG_OWE */
                }
        }
-#endif /* CONFIG_IEEE80211W */
 
        params.p2p = ssid->p2p_group;
 
@@ -3763,9 +4101,12 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
 
        wpa_s->disconnected = 0;
        wpa_s->reassociate = 1;
+       wpa_s_clear_sae_rejected(wpa_s);
        wpa_s->last_owe_group = 0;
-       if (ssid)
+       if (ssid) {
                ssid->owe_transition_bss_select_count = 0;
+               wpa_s_setup_sae_pt(wpa_s->conf, ssid);
+       }
 
        if (wpa_s->connect_without_scan ||
            wpa_supplicant_fast_associate(wpa_s) != 1) {
@@ -4342,6 +4683,12 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
        }
 
        wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
+       wpas_wps_update_mac_addr(wpa_s);
+
+#ifdef CONFIG_FST
+       if (wpa_s->fst)
+               fst_update_mac_addr(wpa_s->fst, wpa_s->own_addr);
+#endif /* CONFIG_FST */
 
        return 0;
 }
@@ -4470,6 +4817,9 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent)
 
        dl_list_init(&wpa_s->bss_tmp_disallowed);
        dl_list_init(&wpa_s->fils_hlp_req);
+#ifdef CONFIG_TESTING_OPTIONS
+       dl_list_init(&wpa_s->drv_signal_override);
+#endif /* CONFIG_TESTING_OPTIONS */
 
        return wpa_s;
 }
@@ -5951,7 +6301,7 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
        hs20_init(wpa_s);
 #endif /* CONFIG_HS20 */
 #ifdef CONFIG_MBO
-       if (wpa_s->conf->oce) {
+       if (!wpa_s->disable_mbo_oce && wpa_s->conf->oce) {
                if ((wpa_s->conf->oce & OCE_STA) &&
                    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA))
                        wpa_s->enable_oce = OCE_STA;
@@ -5998,11 +6348,17 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
 
        wpa_s->disconnected = 1;
        if (wpa_s->drv_priv) {
-               wpa_supplicant_deauthenticate(wpa_s,
-                                             WLAN_REASON_DEAUTH_LEAVING);
+               /* Don't deauthenticate if WoWLAN is enabled */
+               if (!wpa_drv_get_wowlan(wpa_s)) {
+                       wpa_supplicant_deauthenticate(
+                               wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 
-               wpa_drv_set_countermeasures(wpa_s, 0);
-               wpa_clear_keys(wpa_s, NULL);
+                       wpa_drv_set_countermeasures(wpa_s, 0);
+                       wpa_clear_keys(wpa_s, NULL);
+               } else {
+                       wpa_msg(wpa_s, MSG_INFO,
+                               "Do not deauthenticate as part of interface deinit since WoWLAN is enabled");
+               }
        }
 
        wpa_supplicant_cleanup(wpa_s);
@@ -6049,6 +6405,7 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
        }
 
        os_free(wpa_s->ssids_from_scan_req);
+       os_free(wpa_s->last_scan_freqs);
 
        os_free(wpa_s);
 }
@@ -6380,7 +6737,7 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
 
        if (params->wpa_debug_file_path)
                wpa_debug_open_file(params->wpa_debug_file_path);
-       else
+       if (!params->wpa_debug_file_path && !params->wpa_debug_syslog)
                wpa_debug_setup_stdout();
        if (params->wpa_debug_syslog)
                wpa_debug_open_syslog();
@@ -6876,8 +7233,8 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
                        wpa_s->reassociate = 1;
                break;
        case WPA_CTRL_REQ_EAP_PIN:
-               str_clear_free(eap->pin);
-               eap->pin = os_strdup(value);
+               str_clear_free(eap->cert.pin);
+               eap->cert.pin = os_strdup(value);
                eap->pending_req_pin = 0;
                if (ssid == wpa_s->current_ssid)
                        wpa_s->reassociate = 1;
@@ -6891,8 +7248,8 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
                eap->pending_req_otp_len = 0;
                break;
        case WPA_CTRL_REQ_EAP_PASSPHRASE:
-               str_clear_free(eap->private_key_passwd);
-               eap->private_key_passwd = os_strdup(value);
+               str_clear_free(eap->cert.private_key_passwd);
+               eap->cert.private_key_passwd = os_strdup(value);
                eap->pending_req_passphrase = 0;
                if (ssid == wpa_s->current_ssid)
                        wpa_s->reassociate = 1;
@@ -6979,7 +7336,6 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
 
 int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
 {
-#ifdef CONFIG_IEEE80211W
        if (ssid == NULL || ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
                if (wpa_s->conf->pmf == MGMT_FRAME_PROTECTION_OPTIONAL &&
                    !(wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)) {
@@ -7008,9 +7364,6 @@ int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
        }
 
        return ssid->ieee80211w;
-#else /* CONFIG_IEEE80211W */
-       return NO_MGMT_FRAME_PROTECTION;
-#endif /* CONFIG_IEEE80211W */
 }
 
 
@@ -7486,3 +7839,150 @@ int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s,
 
        return 1;
 }
+
+
+int wpas_enable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
+                                      unsigned int type, const u8 *addr,
+                                      const u8 *mask)
+{
+       if ((addr && !mask) || (!addr && mask)) {
+               wpa_printf(MSG_INFO,
+                          "MAC_ADDR_RAND_SCAN invalid addr/mask combination");
+               return -1;
+       }
+
+       if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
+               wpa_printf(MSG_INFO,
+                          "MAC_ADDR_RAND_SCAN cannot allow multicast address");
+               return -1;
+       }
+
+       if (type & MAC_ADDR_RAND_SCAN) {
+               if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
+                                               addr, mask))
+                       return -1;
+       }
+
+       if (type & MAC_ADDR_RAND_SCHED_SCAN) {
+               if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
+                                               addr, mask))
+                       return -1;
+
+               if (wpa_s->sched_scanning && !wpa_s->pno)
+                       wpas_scan_restart_sched_scan(wpa_s);
+       }
+
+       if (type & MAC_ADDR_RAND_PNO) {
+               if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
+                                               addr, mask))
+                       return -1;
+
+               if (wpa_s->pno) {
+                       wpas_stop_pno(wpa_s);
+                       wpas_start_pno(wpa_s);
+               }
+       }
+
+       return 0;
+}
+
+
+int wpas_disable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
+                                       unsigned int type)
+{
+       wpas_mac_addr_rand_scan_clear(wpa_s, type);
+       if (wpa_s->pno) {
+               if (type & MAC_ADDR_RAND_PNO) {
+                       wpas_stop_pno(wpa_s);
+                       wpas_start_pno(wpa_s);
+               }
+       } else if (wpa_s->sched_scanning && (type & MAC_ADDR_RAND_SCHED_SCAN)) {
+               wpas_scan_restart_sched_scan(wpa_s);
+       }
+
+       return 0;
+}
+
+
+int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
+                       struct wpa_signal_info *si)
+{
+       int res;
+
+       if (!wpa_s->driver->signal_poll)
+               return -1;
+
+       res = wpa_s->driver->signal_poll(wpa_s->drv_priv, si);
+
+#ifdef CONFIG_TESTING_OPTIONS
+       if (res == 0) {
+               struct driver_signal_override *dso;
+
+               dl_list_for_each(dso, &wpa_s->drv_signal_override,
+                                struct driver_signal_override, list) {
+                       if (os_memcmp(wpa_s->bssid, dso->bssid,
+                                     ETH_ALEN) != 0)
+                               continue;
+                       wpa_printf(MSG_DEBUG,
+                                  "Override driver signal_poll information: current_signal: %d->%d avg_signal: %d->%d avg_beacon_signal: %d->%d current_noise: %d->%d",
+                                  si->current_signal,
+                                  dso->si_current_signal,
+                                  si->avg_signal,
+                                  dso->si_avg_signal,
+                                  si->avg_beacon_signal,
+                                  dso->si_avg_beacon_signal,
+                                  si->current_noise,
+                                  dso->si_current_noise);
+                       si->current_signal = dso->si_current_signal;
+                       si->avg_signal = dso->si_avg_signal;
+                       si->avg_beacon_signal = dso->si_avg_beacon_signal;
+                       si->current_noise = dso->si_current_noise;
+                       break;
+               }
+       }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+       return res;
+}
+
+
+struct wpa_scan_results *
+wpa_drv_get_scan_results2(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_scan_results *scan_res;
+#ifdef CONFIG_TESTING_OPTIONS
+       size_t idx;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+       if (!wpa_s->driver->get_scan_results2)
+               return NULL;
+
+       scan_res = wpa_s->driver->get_scan_results2(wpa_s->drv_priv);
+
+#ifdef CONFIG_TESTING_OPTIONS
+       for (idx = 0; scan_res && idx < scan_res->num; idx++) {
+               struct driver_signal_override *dso;
+               struct wpa_scan_res *res = scan_res->res[idx];
+
+               dl_list_for_each(dso, &wpa_s->drv_signal_override,
+                                struct driver_signal_override, list) {
+                       if (os_memcmp(res->bssid, dso->bssid, ETH_ALEN) != 0)
+                               continue;
+                       wpa_printf(MSG_DEBUG,
+                                  "Override driver scan signal level %d->%d for "
+                                  MACSTR,
+                                  res->level, dso->scan_level,
+                                  MAC2STR(res->bssid));
+                       res->flags |= WPA_SCAN_QUAL_INVALID;
+                       if (dso->scan_level < 0)
+                               res->flags |= WPA_SCAN_LEVEL_DBM;
+                       else
+                               res->flags &= ~WPA_SCAN_LEVEL_DBM;
+                       res->level = dso->scan_level;
+                       break;
+               }
+       }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+       return scan_res;
+}