]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - src/ap/ieee802_11.c
Store a copy of Association Request RSNXE in AP mode for later use
[thirdparty/hostap.git] / src / ap / ieee802_11.c
index 890da7aa915da4850d0261d5e91ecb6c05801a32..7cd00624f5e39471c9b290dbec2bc4c9a9a138a5 100644 (file)
@@ -23,6 +23,7 @@
 #include "common/sae.h"
 #include "common/dpp.h"
 #include "common/ocv.h"
+#include "common/wpa_common.h"
 #include "radius/radius.h"
 #include "radius/radius_client.h"
 #include "p2p/p2p.h"
@@ -97,6 +98,8 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
                num++;
        if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
                num++;
+       if (hapd->conf->sae_pwe == 1)
+               num++;
        if (num > 8) {
                /* rest of the rates are encoded in Extended supported
                 * rates element */
@@ -123,6 +126,11 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
                *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
        }
 
+       if (hapd->conf->sae_pwe == 1 && count < 8) {
+               count++;
+               *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
+       }
+
        return pos;
 }
 
@@ -140,6 +148,8 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
                num++;
        if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
                num++;
+       if (hapd->conf->sae_pwe == 1)
+               num++;
        if (num <= 8)
                return eid;
        num -= 8;
@@ -169,6 +179,12 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
                        *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
        }
 
+       if (hapd->conf->sae_pwe == 1) {
+               count++;
+               if (count > 8)
+                       *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
+       }
+
        return pos;
 }
 
@@ -393,9 +409,13 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
        const char *password = NULL;
        struct sae_password_entry *pw;
        const char *rx_id = NULL;
+       int use_pt = 0;
+       struct sae_pt *pt = NULL;
 
-       if (sta->sae->tmp)
+       if (sta->sae->tmp) {
                rx_id = sta->sae->tmp->pw_id;
+               use_pt = sta->sae->tmp->h2e;
+       }
 
        for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
                if (!is_broadcast_ether_addr(pw->peer_addr) &&
@@ -407,16 +427,24 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
                    os_strcmp(rx_id, pw->identifier) != 0)
                        continue;
                password = pw->password;
+               pt = pw->pt;
                break;
        }
-       if (!password)
-               password = hapd->conf->ssid.wpa_passphrase;
        if (!password) {
+               password = hapd->conf->ssid.wpa_passphrase;
+               pt = hapd->conf->ssid.pt;
+       }
+       if (!password || (use_pt && !pt)) {
                wpa_printf(MSG_DEBUG, "SAE: No password available");
                return NULL;
        }
 
-       if (update &&
+       if (update && use_pt &&
+           sae_prepare_commit_pt(sta->sae, pt, hapd->own_addr, sta->addr,
+                                 NULL) < 0)
+               return NULL;
+
+       if (update && !use_pt &&
            sae_prepare_commit(hapd->own_addr, sta->addr,
                               (u8 *) password, os_strlen(password), rx_id,
                               sta->sae) < 0) {
@@ -465,6 +493,7 @@ static int auth_sae_send_commit(struct hostapd_data *hapd,
 {
        struct wpabuf *data;
        int reply_res;
+       u16 status;
 
        data = auth_build_sae_commit(hapd, sta, update);
        if (!data && sta->sae->tmp && sta->sae->tmp->pw_id)
@@ -472,8 +501,10 @@ static int auth_sae_send_commit(struct hostapd_data *hapd,
        if (data == NULL)
                return WLAN_STATUS_UNSPECIFIED_FAILURE;
 
+       status = (sta->sae->tmp && sta->sae->tmp->h2e) ?
+               WLAN_STATUS_SAE_HASH_TO_ELEMENT : WLAN_STATUS_SUCCESS;
        reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 1,
-                                   WLAN_STATUS_SUCCESS, wpabuf_head(data),
+                                   status, wpabuf_head(data),
                                    wpabuf_len(data), "sae-send-commit");
 
        wpabuf_free(data);
@@ -709,7 +740,8 @@ static void sae_sme_send_external_auth_status(struct hostapd_data *hapd,
        os_memset(&params, 0, sizeof(params));
        params.status = status;
        params.bssid = sta->addr;
-       if (status == WLAN_STATUS_SUCCESS && sta->sae)
+       if (status == WLAN_STATUS_SUCCESS && sta->sae &&
+           !hapd->conf->disable_pmksa_caching)
                params.pmkid = sta->sae->pmkid;
 
        hostapd_drv_send_external_auth_status(hapd, &params);
@@ -759,8 +791,8 @@ void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
 
 
 static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
-                      const u8 *bssid, u8 auth_transaction, int allow_reuse,
-                      int *sta_removed)
+                      const u8 *bssid, u16 auth_transaction, u16 status_code,
+                      int allow_reuse, int *sta_removed)
 {
        int ret;
 
@@ -775,6 +807,9 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
        switch (sta->sae->state) {
        case SAE_NOTHING:
                if (auth_transaction == 1) {
+                       if (sta->sae->tmp)
+                               sta->sae->tmp->h2e = status_code ==
+                                       WLAN_STATUS_SAE_HASH_TO_ELEMENT;
                        ret = auth_sae_send_commit(hapd, sta, bssid,
                                                   !allow_reuse);
                        if (ret)
@@ -785,14 +820,17 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
                                return WLAN_STATUS_UNSPECIFIED_FAILURE;
 
                        /*
-                        * In mesh case, both Commit and Confirm can be sent
-                        * immediately. In infrastructure BSS, only a single
-                        * Authentication frame (Commit) is expected from the AP
-                        * here and the second one (Confirm) will be sent once
-                        * the STA has sent its second Authentication frame
-                        * (Confirm).
+                        * In mesh case, both Commit and Confirm are sent
+                        * immediately. In infrastructure BSS, by default, only
+                        * a single Authentication frame (Commit) is expected
+                        * from the AP here and the second one (Confirm) will
+                        * be sent once the STA has sent its second
+                        * Authentication frame (Confirm). This behavior can be
+                        * overridden with explicit configuration so that the
+                        * infrastructure BSS case sends both frames together.
                         */
-                       if (hapd->conf->mesh & MESH_ENABLED) {
+                       if ((hapd->conf->mesh & MESH_ENABLED) ||
+                           hapd->conf->sae_confirm_immediate) {
                                /*
                                 * Send both Commit and Confirm immediately
                                 * based on SAE finite state machine
@@ -866,7 +904,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
                         * additional events.
                         */
                        return sae_sm_step(hapd, sta, bssid, auth_transaction,
-                                          0, sta_removed);
+                                          WLAN_STATUS_SUCCESS, 0, sta_removed);
                }
                break;
        case SAE_CONFIRMED:
@@ -974,6 +1012,64 @@ static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta)
 }
 
 
+static int sae_status_success(struct hostapd_data *hapd, u16 status_code)
+{
+       return (hapd->conf->sae_pwe == 0 &&
+               status_code == WLAN_STATUS_SUCCESS) ||
+               (hapd->conf->sae_pwe == 1 &&
+                status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) ||
+               (hapd->conf->sae_pwe == 2 &&
+                (status_code == WLAN_STATUS_SUCCESS ||
+                 status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT));
+}
+
+
+static int sae_is_group_enabled(struct hostapd_data *hapd, int group)
+{
+       int *groups = hapd->conf->sae_groups;
+       int default_groups[] = { 19, 0 };
+       int i;
+
+       if (!groups)
+               groups = default_groups;
+
+       for (i = 0; groups[i] > 0; i++) {
+               if (groups[i] == group)
+                       return 1;
+       }
+
+       return 0;
+}
+
+
+static int check_sae_rejected_groups(struct hostapd_data *hapd,
+                                    const struct wpabuf *groups)
+{
+       size_t i, count;
+       const u8 *pos;
+
+       if (!groups)
+               return 0;
+
+       pos = wpabuf_head(groups);
+       count = wpabuf_len(groups) / 2;
+       for (i = 0; i < count; i++) {
+               int enabled;
+               u16 group;
+
+               group = WPA_GET_LE16(pos);
+               pos += 2;
+               enabled = sae_is_group_enabled(hapd, group);
+               wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
+                          group, enabled ? "enabled" : "disabled");
+               if (enabled)
+                       return 1;
+       }
+
+       return 0;
+}
+
+
 static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                            const struct ieee80211_mgmt *mgmt, size_t len,
                            u16 auth_transaction, u16 status_code)
@@ -1011,7 +1107,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
 #endif /* CONFIG_TESTING_OPTIONS */
        if (!sta->sae) {
                if (auth_transaction != 1 ||
-                   status_code != WLAN_STATUS_SUCCESS) {
+                   !sae_status_success(hapd, status_code)) {
                        resp = -1;
                        goto remove_sta;
                }
@@ -1101,7 +1197,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                        goto remove_sta;
                }
 
-               if (status_code != WLAN_STATUS_SUCCESS)
+               if (!sae_status_success(hapd, status_code))
                        goto remove_sta;
 
                if (!(hapd->conf->mesh & MESH_ENABLED) &&
@@ -1134,7 +1230,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
                                        ((const u8 *) mgmt) + len -
                                        mgmt->u.auth.variable, &token,
-                                       &token_len, groups);
+                                       &token_len, groups, status_code ==
+                                       WLAN_STATUS_SAE_HASH_TO_ELEMENT);
                if (resp == SAE_SILENTLY_DISCARD) {
                        wpa_printf(MSG_DEBUG,
                                   "SAE: Drop commit message from " MACSTR " due to reflection attack",
@@ -1164,6 +1261,13 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                if (resp != WLAN_STATUS_SUCCESS)
                        goto reply;
 
+               if (sta->sae->tmp &&
+                   check_sae_rejected_groups(
+                           hapd, sta->sae->tmp->peer_rejected_groups) < 0) {
+                       resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+                       goto remove_sta;
+               }
+
                if (!token && use_sae_anti_clogging(hapd) && !allow_reuse) {
                        wpa_printf(MSG_DEBUG,
                                   "SAE: Request anti-clogging token from "
@@ -1178,7 +1282,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                }
 
                resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
-                                  allow_reuse, &sta_removed);
+                                  status_code, allow_reuse, &sta_removed);
        } else if (auth_transaction == 2) {
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
                               HOSTAPD_LEVEL_DEBUG,
@@ -1219,8 +1323,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                        }
                        sta->sae->rc = peer_send_confirm;
                }
-               resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction, 0,
-                       &sta_removed);
+               resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
+                                  status_code, 0, &sta_removed);
        } else {
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
                               HOSTAPD_LEVEL_DEBUG,
@@ -1404,12 +1508,10 @@ static u16 wpa_res_to_status_code(int res)
                return WLAN_STATUS_AKMP_NOT_VALID;
        if (res == WPA_ALLOC_FAIL)
                return WLAN_STATUS_UNSPECIFIED_FAILURE;
-#ifdef CONFIG_IEEE80211W
        if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
                return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
        if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
                return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
-#endif /* CONFIG_IEEE80211W */
        if (res == WPA_INVALID_MDIE)
                return WLAN_STATUS_INVALID_MDIE;
        if (res == WPA_INVALID_PMKID)
@@ -1552,6 +1654,8 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
        res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
                                  hapd->iface->freq,
                                  elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+                                 elems.rsnxe ? elems.rsnxe - 2 : NULL,
+                                 elems.rsnxe ? elems.rsnxe_len + 2 : 0,
                                  elems.mdie, elems.mdie_len, NULL, 0);
        resp = wpa_res_to_status_code(res);
        if (resp != WLAN_STATUS_SUCCESS)
@@ -2324,8 +2428,11 @@ static void handle_auth(struct hostapd_data *hapd,
                sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH |
                                WLAN_STA_AUTHORIZED);
 
-               if (hostapd_sta_add(hapd, sta->addr, 0, 0, NULL, 0, 0,
-                                   NULL, NULL, sta->flags, 0, 0, 0, 0)) {
+               if (hostapd_sta_add(hapd, sta->addr, 0, 0,
+                                   sta->supported_rates,
+                                   sta->supported_rates_len,
+                                   0, NULL, NULL, NULL, 0,
+                                   sta->flags, 0, 0, 0, 0)) {
                        hostapd_logger(hapd, sta->addr,
                                       HOSTAPD_MODULE_IEEE80211,
                                       HOSTAPD_LEVEL_NOTICE,
@@ -2791,6 +2898,123 @@ static u16 owe_process_assoc_req(struct hostapd_data *hapd,
        return WLAN_STATUS_SUCCESS;
 }
 
+
+u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer,
+                        const u8 *rsn_ie, size_t rsn_ie_len,
+                        const u8 *owe_dh, size_t owe_dh_len)
+{
+       struct wpa_ie_data data;
+       int res;
+
+       if (!rsn_ie || rsn_ie_len < 2) {
+               wpa_printf(MSG_DEBUG, "OWE: Invalid RSNE from " MACSTR,
+                          MAC2STR(peer));
+               return WLAN_STATUS_INVALID_IE;
+       }
+       rsn_ie -= 2;
+       rsn_ie_len += 2;
+
+       res = wpa_parse_wpa_ie_rsn(rsn_ie, rsn_ie_len, &data);
+       if (res) {
+               wpa_printf(MSG_DEBUG, "Failed to parse RSNE from " MACSTR
+                          " (res=%d)", MAC2STR(peer), res);
+               wpa_hexdump(MSG_DEBUG, "RSNE", rsn_ie, rsn_ie_len);
+               return wpa_res_to_status_code(res);
+       }
+       if (!(data.key_mgmt & WPA_KEY_MGMT_OWE)) {
+               wpa_printf(MSG_DEBUG,
+                          "OWE: Unexpected key mgmt 0x%x from " MACSTR,
+                          (unsigned int) data.key_mgmt, MAC2STR(peer));
+               return WLAN_STATUS_AKMP_NOT_VALID;
+       }
+       if (!owe_dh) {
+               wpa_printf(MSG_DEBUG,
+                          "OWE: No Diffie-Hellman Parameter element from "
+                          MACSTR, MAC2STR(peer));
+               return WLAN_STATUS_AKMP_NOT_VALID;
+       }
+
+       return WLAN_STATUS_SUCCESS;
+}
+
+
+u16 owe_process_rsn_ie(struct hostapd_data *hapd,
+                      struct sta_info *sta,
+                      const u8 *rsn_ie, size_t rsn_ie_len,
+                      const u8 *owe_dh, size_t owe_dh_len)
+{
+       u16 status;
+       u8 *owe_buf, ie[256 * 2];
+       size_t ie_len = 0;
+       int res;
+
+       if (!rsn_ie || rsn_ie_len < 2) {
+               wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq");
+               status = WLAN_STATUS_INVALID_IE;
+               goto end;
+       }
+
+       if (!sta->wpa_sm)
+               sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
+                                               NULL);
+       if (!sta->wpa_sm) {
+               wpa_printf(MSG_WARNING,
+                          "OWE: Failed to initialize WPA state machine");
+               status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+               goto end;
+       }
+       rsn_ie -= 2;
+       rsn_ie_len += 2;
+       res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+                                 hapd->iface->freq, rsn_ie, rsn_ie_len,
+                                 NULL, 0, NULL, 0, owe_dh, owe_dh_len);
+       status = wpa_res_to_status_code(res);
+       if (status != WLAN_STATUS_SUCCESS)
+               goto end;
+       status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
+       if (status != WLAN_STATUS_SUCCESS)
+               goto end;
+       owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, ie, sizeof(ie),
+                                               NULL, 0);
+       if (!owe_buf) {
+               status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+               goto end;
+       }
+
+       if (sta->owe_ecdh) {
+               struct wpabuf *pub;
+
+               pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
+               if (!pub) {
+                       status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+                       goto end;
+               }
+
+               /* OWE Diffie-Hellman Parameter element */
+               *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
+               *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
+               *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
+                                                        */
+               WPA_PUT_LE16(owe_buf, sta->owe_group);
+               owe_buf += 2;
+               os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
+               owe_buf += wpabuf_len(pub);
+               wpabuf_free(pub);
+               sta->external_dh_updated = 1;
+       }
+       ie_len = owe_buf - ie;
+
+end:
+       wpa_printf(MSG_DEBUG, "OWE: Update status %d, ie len %d for peer "
+                             MACSTR, status, (unsigned int) ie_len,
+                             MAC2STR(sta->addr));
+       hostapd_drv_update_dh_ie(hapd, sta->addr, status,
+                                status == WLAN_STATUS_SUCCESS ? ie : NULL,
+                                ie_len);
+
+       return status;
+}
+
 #endif /* CONFIG_OWE */
 
 
@@ -2866,6 +3090,15 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
                        return resp;
        }
 #endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+       if (hapd->iconf->ieee80211ax) {
+               resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP,
+                                        elems.he_capabilities,
+                                        elems.he_capabilities_len);
+               if (resp != WLAN_STATUS_SUCCESS)
+                       return resp;
+       }
+#endif /* CONFIG_IEEE80211AX */
 
 #ifdef CONFIG_P2P
        if (elems.p2p) {
@@ -2942,12 +3175,13 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
                res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
                                          hapd->iface->freq,
                                          wpa_ie, wpa_ie_len,
+                                         elems.rsnxe ? elems.rsnxe - 2 : NULL,
+                                         elems.rsnxe ? elems.rsnxe_len + 2 : 0,
                                          elems.mdie, elems.mdie_len,
                                          elems.owe_dh, elems.owe_dh_len);
                resp = wpa_res_to_status_code(res);
                if (resp != WLAN_STATUS_SUCCESS)
                        return resp;
-#ifdef CONFIG_IEEE80211W
                if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
                    (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
                    !sta->sa_query_timed_out &&
@@ -2974,7 +3208,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
                        sta->flags |= WLAN_STA_MFP;
                else
                        sta->flags &= ~WLAN_STA_MFP;
-#endif /* CONFIG_IEEE80211W */
 
 #ifdef CONFIG_IEEE80211R_AP
                if (sta->auth_alg == WLAN_AUTH_FT) {
@@ -3112,7 +3345,8 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
                sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
                                                 elems.hs20_len - 4);
                release = ((elems.hs20[4] >> 4) & 0x0f) + 1;
-               if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm)) {
+               if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm) &&
+                   hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
                        wpa_printf(MSG_DEBUG,
                                   "HS 2.0: PMF not negotiated by release %d station "
                                   MACSTR, release, MAC2STR(sta->addr));
@@ -3228,6 +3462,7 @@ static int add_associated_sta(struct hostapd_data *hapd,
 {
        struct ieee80211_ht_capabilities ht_cap;
        struct ieee80211_vht_capabilities vht_cap;
+       struct ieee80211_he_capabilities he_cap;
        int set = 1;
 
        /*
@@ -3280,6 +3515,12 @@ static int add_associated_sta(struct hostapd_data *hapd,
        if (sta->flags & WLAN_STA_VHT)
                hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
 #endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+       if (sta->flags & WLAN_STA_HE) {
+               hostapd_get_he_capab(hapd, sta->he_capab, &he_cap,
+                                    sta->he_capab_len);
+       }
+#endif /* CONFIG_IEEE80211AX */
 
        /*
         * Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
@@ -3291,6 +3532,8 @@ static int add_associated_sta(struct hostapd_data *hapd,
                            sta->listen_interval,
                            sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
                            sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
+                           sta->flags & WLAN_STA_HE ? &he_cap : NULL,
+                           sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0,
                            sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
                            sta->vht_opmode, sta->p2p_ie ? 1 : 0,
                            set)) {
@@ -3409,10 +3652,8 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
                                                  ies, ies_len);
 #endif /* CONFIG_OWE */
 
-#ifdef CONFIG_IEEE80211W
        if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
                p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
-#endif /* CONFIG_IEEE80211W */
 
 #ifdef CONFIG_IEEE80211N
        p = hostapd_eid_ht_capabilities(hapd, p);
@@ -3420,7 +3661,8 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
 #endif /* CONFIG_IEEE80211N */
 
 #ifdef CONFIG_IEEE80211AC
-       if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+       if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
+           !is_6ghz_op_class(hapd->iconf->op_class)) {
                u32 nsts = 0, sta_nsts;
 
                if (sta && hapd->conf->use_sta_nsts && sta->vht_capabilities) {
@@ -3442,6 +3684,15 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
        }
 #endif /* CONFIG_IEEE80211AC */
 
+#ifdef CONFIG_IEEE80211AX
+       if (hapd->iconf->ieee80211ax) {
+               p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
+               p = hostapd_eid_he_operation(hapd, p);
+               p = hostapd_eid_spatial_reuse(hapd, p);
+               p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
+       }
+#endif /* CONFIG_IEEE80211AX */
+
        p = hostapd_eid_ext_capab(hapd, p);
        p = hostapd_eid_bss_max_idle_period(hapd, p);
        if (sta && sta->qos_map_enabled)
@@ -3618,6 +3869,12 @@ u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
                return owe_buf;
        }
 
+       if (sta->owe_pmk && sta->external_dh_updated) {
+               wpa_printf(MSG_DEBUG, "OWE: Using previously derived PMK");
+               *reason = WLAN_STATUS_SUCCESS;
+               return owe_buf;
+       }
+
        *reason = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
        if (*reason != WLAN_STATUS_SUCCESS)
                return NULL;
@@ -3995,7 +4252,6 @@ static void handle_assoc(struct hostapd_data *hapd,
         */
        sta->flags |= WLAN_STA_ASSOC_REQ_OK;
 
-#ifdef CONFIG_IEEE80211W
        if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) {
                wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out "
                           "SA Query procedure", reassoc ? "re" : "");
@@ -4006,7 +4262,6 @@ static void handle_assoc(struct hostapd_data *hapd,
                 * trying to associate.
                 */
        }
-#endif /* CONFIG_IEEE80211W */
 
        /* Make sure that the previously registered inactivity timer will not
         * remove the STA immediately. */
@@ -4231,13 +4486,11 @@ static void handle_beacon(struct hostapd_data *hapd,
 }
 
 
-#ifdef CONFIG_IEEE80211W
 static int robust_action_frame(u8 category)
 {
        return category != WLAN_ACTION_PUBLIC &&
                category != WLAN_ACTION_HT;
 }
-#endif /* CONFIG_IEEE80211W */
 
 
 static int handle_action(struct hostapd_data *hapd,
@@ -4271,7 +4524,6 @@ static int handle_action(struct hostapd_data *hapd,
                return 0;
        }
 
-#ifdef CONFIG_IEEE80211W
        if (sta && (sta->flags & WLAN_STA_MFP) &&
            !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP)) &&
            robust_action_frame(mgmt->u.action.category)) {
@@ -4281,7 +4533,6 @@ static int handle_action(struct hostapd_data *hapd,
                               "an MFP STA");
                return 0;
        }
-#endif /* CONFIG_IEEE80211W */
 
        if (sta) {
                u16 fc = le_to_host16(mgmt->frame_control);
@@ -4315,11 +4566,9 @@ static int handle_action(struct hostapd_data *hapd,
        case WLAN_ACTION_WMM:
                hostapd_wmm_action(hapd, mgmt, len);
                return 1;
-#ifdef CONFIG_IEEE80211W
        case WLAN_ACTION_SA_QUERY:
                ieee802_11_sa_query_action(hapd, mgmt, len);
                return 1;
-#endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_WNM_AP
        case WLAN_ACTION_WNM:
                ieee802_11_rx_wnm_action_ap(hapd, mgmt, len);
@@ -4471,6 +4720,18 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
        fc = le_to_host16(mgmt->frame_control);
        stype = WLAN_FC_GET_STYPE(fc);
 
+       if (is_multicast_ether_addr(mgmt->sa) ||
+           is_zero_ether_addr(mgmt->sa) ||
+           os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
+               /* Do not process any frames with unexpected/invalid SA so that
+                * we do not add any state for unexpected STA addresses or end
+                * up sending out frames to unexpected destination. */
+               wpa_printf(MSG_DEBUG, "MGMT: Invalid SA=" MACSTR
+                          " in received frame - ignore this frame silently",
+                          MAC2STR(mgmt->sa));
+               return 0;
+       }
+
        if (stype == WLAN_FC_STYPE_BEACON) {
                handle_beacon(hapd, mgmt, len, fi);
                return 1;
@@ -4701,9 +4962,7 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
        else
                mlme_associate_indication(hapd, sta);
 
-#ifdef CONFIG_IEEE80211W
        sta->sa_query_timed_out = 0;
-#endif /* CONFIG_IEEE80211W */
 
        if (sta->eapol_sm == NULL) {
                /*
@@ -5096,8 +5355,10 @@ void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
 
        wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA "
                   MACSTR, MAC2STR(src));
-       if (is_multicast_ether_addr(src)) {
-               /* Broadcast bit set in SA?! Ignore the frame silently. */
+       if (is_multicast_ether_addr(src) || is_zero_ether_addr(src) ||
+           os_memcmp(src, hapd->own_addr, ETH_ALEN) == 0) {
+               /* Broadcast bit set in SA or unexpected SA?! Ignore the frame
+                * silently. */
                return;
        }