]> 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 a473d21104202fcd31d33c90657bfcc53db103c6..7cd00624f5e39471c9b290dbec2bc4c9a9a138a5 100644 (file)
@@ -21,6 +21,9 @@
 #include "common/ieee802_11_common.h"
 #include "common/wpa_ctrl.h"
 #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"
@@ -61,6 +64,25 @@ prepare_auth_resp_fils(struct hostapd_data *hapd,
                       const u8 *msk, size_t msk_len,
                       int *is_pub);
 #endif /* CONFIG_FILS */
+static void handle_auth(struct hostapd_data *hapd,
+                       const struct ieee80211_mgmt *mgmt, size_t len,
+                       int rssi, int from_queue);
+
+
+u8 * hostapd_eid_multi_ap(struct hostapd_data *hapd, u8 *eid)
+{
+       u8 multi_ap_val = 0;
+
+       if (!hapd->conf->multi_ap)
+               return eid;
+       if (hapd->conf->multi_ap & BACKHAUL_BSS)
+               multi_ap_val |= MULTI_AP_BACKHAUL_BSS;
+       if (hapd->conf->multi_ap & FRONTHAUL_BSS)
+               multi_ap_val |= MULTI_AP_FRONTHAUL_BSS;
+
+       return eid + add_multi_ap_ie(eid, 9, multi_ap_val);
+}
+
 
 u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
 {
@@ -76,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 */
@@ -102,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;
 }
 
@@ -119,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;
@@ -148,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;
 }
 
@@ -277,7 +314,7 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
 static int send_auth_reply(struct hostapd_data *hapd,
                           const u8 *dst, const u8 *bssid,
                           u16 auth_alg, u16 auth_transaction, u16 resp,
-                          const u8 *ies, size_t ies_len)
+                          const u8 *ies, size_t ies_len, const char *dbg)
 {
        struct ieee80211_mgmt *reply;
        u8 *buf;
@@ -304,9 +341,9 @@ static int send_auth_reply(struct hostapd_data *hapd,
                os_memcpy(reply->u.auth.variable, ies, ies_len);
 
        wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR
-                  " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu)",
+                  " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu) (dbg=%s)",
                   MAC2STR(dst), auth_alg, auth_transaction,
-                  resp, (unsigned long) ies_len);
+                  resp, (unsigned long) ies_len, dbg);
        if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
                wpa_printf(MSG_INFO, "send_auth_reply: send failed");
        else
@@ -328,7 +365,8 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
        int reply_res;
 
        reply_res = send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT,
-                                   auth_transaction, status, ies, ies_len);
+                                   auth_transaction, status, ies, ies_len,
+                                   "auth-ft-finish");
 
        sta = ap_get_sta(hapd, dst);
        if (sta == NULL)
@@ -368,29 +406,67 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
                                             struct sta_info *sta, int update)
 {
        struct wpabuf *buf;
-       const char *password;
+       const char *password = NULL;
+       struct sae_password_entry *pw;
+       const char *rx_id = NULL;
+       int use_pt = 0;
+       struct sae_pt *pt = NULL;
 
-       password = hapd->conf->sae_password;
-       if (!password)
-               password = hapd->conf->ssid.wpa_passphrase;
+       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) &&
+                   os_memcmp(pw->peer_addr, sta->addr, ETH_ALEN) != 0)
+                       continue;
+               if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier))
+                       continue;
+               if (rx_id && pw->identifier &&
+                   os_strcmp(rx_id, pw->identifier) != 0)
+                       continue;
+               password = pw->password;
+               pt = pw->pt;
+               break;
+       }
        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),
+                              (u8 *) password, os_strlen(password), rx_id,
                               sta->sae) < 0) {
                wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
                return NULL;
        }
 
-       buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN);
+       if (pw && pw->vlan_id) {
+               if (!sta->sae->tmp) {
+                       wpa_printf(MSG_INFO,
+                                  "SAE: No temporary data allocated - cannot store VLAN ID");
+                       return NULL;
+               }
+               sta->sae->tmp->vlan_id = pw->vlan_id;
+       }
+
+       buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN +
+                          (rx_id ? 3 + os_strlen(rx_id) : 0));
        if (buf == NULL)
                return NULL;
        sae_write_commit(sta->sae, buf, sta->sae->tmp ?
-                        sta->sae->tmp->anti_clogging_token : NULL);
+                        sta->sae->tmp->anti_clogging_token : NULL, rx_id);
 
        return buf;
 }
@@ -417,14 +493,19 @@ 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)
+               return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
        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),
-                                   wpabuf_len(data));
+                                   status, wpabuf_head(data),
+                                   wpabuf_len(data), "sae-send-commit");
 
        wpabuf_free(data);
 
@@ -445,7 +526,7 @@ static int auth_sae_send_confirm(struct hostapd_data *hapd,
 
        reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 2,
                                    WLAN_STATUS_SUCCESS, wpabuf_head(data),
-                                   wpabuf_len(data));
+                                   wpabuf_len(data), "sae-send-confirm");
 
        wpabuf_free(data);
 
@@ -472,22 +553,58 @@ static int use_sae_anti_clogging(struct hostapd_data *hapd)
                        return 1;
        }
 
+       /* In addition to already existing open SAE sessions, check whether
+        * there are enough pending commit messages in the processing queue to
+        * potentially result in too many open sessions. */
+       if (open + dl_list_len(&hapd->sae_commit_queue) >=
+           hapd->conf->sae_anti_clogging_threshold)
+               return 1;
+
        return 0;
 }
 
 
+static u8 sae_token_hash(struct hostapd_data *hapd, const u8 *addr)
+{
+       u8 hash[SHA256_MAC_LEN];
+
+       hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+                   addr, ETH_ALEN, hash);
+       return hash[0];
+}
+
+
 static int check_sae_token(struct hostapd_data *hapd, const u8 *addr,
                           const u8 *token, size_t token_len)
 {
        u8 mac[SHA256_MAC_LEN];
+       const u8 *addrs[2];
+       size_t len[2];
+       u16 token_idx;
+       u8 idx;
 
        if (token_len != SHA256_MAC_LEN)
                return -1;
-       if (hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
-                       addr, ETH_ALEN, mac) < 0 ||
-           os_memcmp_const(token, mac, SHA256_MAC_LEN) != 0)
+       idx = sae_token_hash(hapd, addr);
+       token_idx = hapd->sae_pending_token_idx[idx];
+       if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) {
+               wpa_printf(MSG_DEBUG, "SAE: Invalid anti-clogging token from "
+                          MACSTR " - token_idx 0x%04x, expected 0x%04x",
+                          MAC2STR(addr), WPA_GET_BE16(token), token_idx);
+               return -1;
+       }
+
+       addrs[0] = addr;
+       len[0] = ETH_ALEN;
+       addrs[1] = token;
+       len[1] = 2;
+       if (hmac_sha256_vector(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+                              2, addrs, len, mac) < 0 ||
+           os_memcmp_const(token + 2, &mac[2], SHA256_MAC_LEN - 2) != 0)
                return -1;
 
+       hapd->sae_pending_token_idx[idx] = 0; /* invalidate used token */
+
        return 0;
 }
 
@@ -498,16 +615,25 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
        struct wpabuf *buf;
        u8 *token;
        struct os_reltime now;
+       u8 idx[2];
+       const u8 *addrs[2];
+       size_t len[2];
+       u8 p_idx;
+       u16 token_idx;
 
        os_get_reltime(&now);
        if (!os_reltime_initialized(&hapd->last_sae_token_key_update) ||
-           os_reltime_expired(&now, &hapd->last_sae_token_key_update, 60)) {
+           os_reltime_expired(&now, &hapd->last_sae_token_key_update, 60) ||
+           hapd->sae_token_idx == 0xffff) {
                if (random_get_bytes(hapd->sae_token_key,
                                     sizeof(hapd->sae_token_key)) < 0)
                        return NULL;
                wpa_hexdump(MSG_DEBUG, "SAE: Updated token key",
                            hapd->sae_token_key, sizeof(hapd->sae_token_key));
                hapd->last_sae_token_key_update = now;
+               hapd->sae_token_idx = 0;
+               os_memset(hapd->sae_pending_token_idx, 0,
+                         sizeof(hapd->sae_pending_token_idx));
        }
 
        buf = wpabuf_alloc(sizeof(le16) + SHA256_MAC_LEN);
@@ -516,9 +642,25 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
 
        wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
 
+       p_idx = sae_token_hash(hapd, addr);
+       token_idx = hapd->sae_pending_token_idx[p_idx];
+       if (!token_idx) {
+               hapd->sae_token_idx++;
+               token_idx = hapd->sae_token_idx;
+               hapd->sae_pending_token_idx[p_idx] = token_idx;
+       }
+       WPA_PUT_BE16(idx, token_idx);
        token = wpabuf_put(buf, SHA256_MAC_LEN);
-       hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
-                   addr, ETH_ALEN, token);
+       addrs[0] = addr;
+       len[0] = ETH_ALEN;
+       addrs[1] = idx;
+       len[1] = sizeof(idx);
+       if (hmac_sha256_vector(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+                              2, addrs, len, token) < 0) {
+               wpabuf_free(buf);
+               return NULL;
+       }
+       WPA_PUT_BE16(token, token_idx);
 
        return buf;
 }
@@ -590,8 +732,53 @@ static void sae_set_retransmit_timer(struct hostapd_data *hapd,
 }
 
 
+static void sae_sme_send_external_auth_status(struct hostapd_data *hapd,
+                                             struct sta_info *sta, u16 status)
+{
+       struct external_auth params;
+
+       os_memset(&params, 0, sizeof(params));
+       params.status = status;
+       params.bssid = sta->addr;
+       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);
+}
+
+
 void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
 {
+#ifndef CONFIG_NO_VLAN
+       struct vlan_description vlan_desc;
+
+       if (sta->sae->tmp && sta->sae->tmp->vlan_id > 0) {
+               wpa_printf(MSG_DEBUG, "SAE: Assign STA " MACSTR
+                          " to VLAN ID %d",
+                          MAC2STR(sta->addr), sta->sae->tmp->vlan_id);
+
+               os_memset(&vlan_desc, 0, sizeof(vlan_desc));
+               vlan_desc.notempty = 1;
+               vlan_desc.untagged = sta->sae->tmp->vlan_id;
+               if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
+                       wpa_printf(MSG_INFO,
+                                  "Invalid VLAN ID %d in sae_password",
+                                  sta->sae->tmp->vlan_id);
+                       return;
+               }
+
+               if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0 ||
+                   ap_sta_bind_vlan(hapd, sta) < 0) {
+                       wpa_printf(MSG_INFO,
+                                  "Failed to assign VLAN ID %d from sae_password to "
+                                  MACSTR, sta->sae->tmp->vlan_id,
+                                  MAC2STR(sta->addr));
+                       return;
+               }
+       }
+#endif /* CONFIG_NO_VLAN */
+
        sta->flags |= WLAN_STA_AUTH;
        sta->auth_alg = WLAN_AUTH_SAE;
        mlme_authenticate_indication(hapd, sta);
@@ -599,14 +786,18 @@ void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
        sae_set_state(sta, SAE_ACCEPTED, "Accept Confirm");
        wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
                               sta->sae->pmk, sta->sae->pmkid);
+       sae_sme_send_external_auth_status(hapd, sta, WLAN_STATUS_SUCCESS);
 }
 
 
 static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
-                      const u8 *bssid, u8 auth_transaction)
+                      const u8 *bssid, u16 auth_transaction, u16 status_code,
+                      int allow_reuse, int *sta_removed)
 {
        int ret;
 
+       *sta_removed = 0;
+
        if (auth_transaction != 1 && auth_transaction != 2)
                return WLAN_STATUS_UNSPECIFIED_FAILURE;
 
@@ -616,7 +807,11 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
        switch (sta->sae->state) {
        case SAE_NOTHING:
                if (auth_transaction == 1) {
-                       ret = auth_sae_send_commit(hapd, sta, bssid, 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)
                                return ret;
                        sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
@@ -625,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
@@ -705,7 +903,8 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
                         * step to get to Accepted without waiting for
                         * additional events.
                         */
-                       return sae_sm_step(hapd, sta, bssid, auth_transaction);
+                       return sae_sm_step(hapd, sta, bssid, auth_transaction,
+                                          WLAN_STATUS_SUCCESS, 0, sta_removed);
                }
                break;
        case SAE_CONFIRMED:
@@ -733,12 +932,25 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
                }
                break;
        case SAE_ACCEPTED:
-               if (auth_transaction == 1) {
+               if (auth_transaction == 1 &&
+                   (hapd->conf->mesh & MESH_ENABLED)) {
                        wpa_printf(MSG_DEBUG, "SAE: remove the STA (" MACSTR
                                   ") doing reauthentication",
                                   MAC2STR(sta->addr));
-                       ap_free_sta(hapd, sta);
                        wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+                       ap_free_sta(hapd, sta);
+                       *sta_removed = 1;
+               } else if (auth_transaction == 1) {
+                       wpa_printf(MSG_DEBUG, "SAE: Start reauthentication");
+                       ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+                       if (ret)
+                               return ret;
+                       sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
+
+                       if (sae_process_commit(sta->sae) < 0)
+                               return WLAN_STATUS_UNSPECIFIED_FAILURE;
+                       sta->sae->sync = 0;
+                       sae_set_retransmit_timer(hapd, sta);
                } else {
                        if (sae_check_big_sync(hapd, sta))
                                return WLAN_STATUS_SUCCESS;
@@ -763,18 +975,21 @@ static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta)
 {
        struct sae_data *sae = sta->sae;
        int i, *groups = hapd->conf->sae_groups;
+       int default_groups[] = { 19, 0 };
 
        if (sae->state != SAE_COMMITTED)
                return;
 
        wpa_printf(MSG_DEBUG, "SAE: Previously selected group: %d", sae->group);
 
-       for (i = 0; groups && groups[i] > 0; i++) {
+       if (!groups)
+               groups = default_groups;
+       for (i = 0; groups[i] > 0; i++) {
                if (sae->group == groups[i])
                        break;
        }
 
-       if (!groups || groups[i] <= 0) {
+       if (groups[i] <= 0) {
                wpa_printf(MSG_DEBUG,
                           "SAE: Previously selected group not found from the current configuration");
                return;
@@ -797,22 +1012,86 @@ 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)
 {
        int resp = WLAN_STATUS_SUCCESS;
        struct wpabuf *data = NULL;
+       int *groups = hapd->conf->sae_groups;
+       int default_groups[] = { 19, 0 };
+       const u8 *pos, *end;
+       int sta_removed = 0;
+
+       if (!groups)
+               groups = default_groups;
 
 #ifdef CONFIG_TESTING_OPTIONS
        if (hapd->conf->sae_reflection_attack && auth_transaction == 1) {
-               const u8 *pos, *end;
-
                wpa_printf(MSG_DEBUG, "SAE: TESTING - reflection attack");
                pos = mgmt->u.auth.variable;
                end = ((const u8 *) mgmt) + len;
                send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
-                               auth_transaction, resp, pos, end - pos);
+                               auth_transaction, resp, pos, end - pos,
+                               "auth-sae-reflection-attack");
                goto remove_sta;
        }
 
@@ -821,13 +1100,14 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
                                auth_transaction, resp,
                                wpabuf_head(hapd->conf->sae_commit_override),
-                               wpabuf_len(hapd->conf->sae_commit_override));
+                               wpabuf_len(hapd->conf->sae_commit_override),
+                               "sae-commit-override");
                goto remove_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;
                }
@@ -848,12 +1128,14 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
        }
 
        if (auth_transaction == 1) {
-               const u8 *token = NULL, *pos, *end;
+               const u8 *token = NULL;
                size_t token_len = 0;
+               int allow_reuse = 0;
+
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
                               HOSTAPD_LEVEL_DEBUG,
-                              "start SAE authentication (RX commit, status=%u)",
-                              status_code);
+                              "start SAE authentication (RX commit, status=%u (%s))",
+                              status_code, status2str(status_code));
 
                if ((hapd->conf->mesh & MESH_ENABLED) &&
                    status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
@@ -866,8 +1148,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                                resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
                                goto reply;
                        }
-                       resp = sae_group_allowed(sta->sae,
-                                                hapd->conf->sae_groups,
+                       resp = sae_group_allowed(sta->sae, groups,
                                                 WPA_GET_LE16(pos));
                        if (resp != WLAN_STATUS_SUCCESS) {
                                wpa_printf(MSG_ERROR,
@@ -916,19 +1197,58 @@ 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) &&
+                   sta->sae->state == SAE_COMMITTED) {
+                       /* This is needed in the infrastructure BSS case to
+                        * address a sequence where a STA entry may remain in
+                        * hostapd across two attempts to do SAE authentication
+                        * by the same STA. The second attempt may end up trying
+                        * to use a different group and that would not be
+                        * allowed if we remain in Committed state with the
+                        * previously set parameters. */
+                       pos = mgmt->u.auth.variable;
+                       end = ((const u8 *) mgmt) + len;
+                       if (end - pos >= (int) sizeof(le16) &&
+                           sae_group_allowed(sta->sae, groups,
+                                             WPA_GET_LE16(pos)) ==
+                           WLAN_STATUS_SUCCESS) {
+                               /* Do not waste resources deriving the same PWE
+                                * again since the same group is reused. */
+                               sae_set_state(sta, SAE_NOTHING,
+                                             "Allow previous PWE to be reused");
+                               allow_reuse = 1;
+                       } else {
+                               sae_set_state(sta, SAE_NOTHING,
+                                             "Clear existing state to allow restart");
+                               sae_clear_data(sta->sae);
+                       }
+               }
+
                resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
                                        ((const u8 *) mgmt) + len -
                                        mgmt->u.auth.variable, &token,
-                                       &token_len, hapd->conf->sae_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",
                                   MAC2STR(sta->addr));
                        goto remove_sta;
                }
+
+               if (resp == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER) {
+                       wpa_msg(hapd->msg_ctx, MSG_INFO,
+                               WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER
+                               MACSTR, MAC2STR(sta->addr));
+                       sae_clear_retransmit_timer(hapd, sta);
+                       sae_set_state(sta, SAE_NOTHING,
+                                     "Unknown Password Identifier");
+                       goto remove_sta;
+               }
+
                if (token && check_sae_token(hapd, sta->addr, token, token_len)
                    < 0) {
                        wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
@@ -941,7 +1261,14 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                if (resp != WLAN_STATUS_SUCCESS)
                        goto reply;
 
-               if (!token && use_sae_anti_clogging(hapd)) {
+               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 "
                                   MACSTR, MAC2STR(sta->addr));
@@ -954,12 +1281,13 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                        goto reply;
                }
 
-               resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction);
+               resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
+                                  status_code, allow_reuse, &sta_removed);
        } else if (auth_transaction == 2) {
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
                               HOSTAPD_LEVEL_DEBUG,
-                              "SAE authentication (RX confirm, status=%u)",
-                              status_code);
+                              "SAE authentication (RX confirm, status=%u (%s))",
+                              status_code, status2str(status_code));
                if (status_code != WLAN_STATUS_SUCCESS)
                        goto remove_sta;
                if (sta->sae->state >= SAE_CONFIRMED ||
@@ -995,28 +1323,41 @@ 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);
+               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,
-                              "unexpected SAE authentication transaction %u (status=%u)",
-                              auth_transaction, status_code);
+                              "unexpected SAE authentication transaction %u (status=%u (%s))",
+                              auth_transaction, status_code,
+                              status2str(status_code));
                if (status_code != WLAN_STATUS_SUCCESS)
                        goto remove_sta;
                resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
        }
 
 reply:
-       if (resp != WLAN_STATUS_SUCCESS) {
+       if (!sta_removed && resp != WLAN_STATUS_SUCCESS) {
+               pos = mgmt->u.auth.variable;
+               end = ((const u8 *) mgmt) + len;
+
+               /* Copy the Finite Cyclic Group field from the request if we
+                * rejected it as unsupported group. */
+               if (resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
+                   !data && end - pos >= 2)
+                       data = wpabuf_alloc_copy(pos, 2);
+
+               sae_sme_send_external_auth_status(hapd, sta, resp);
                send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
                                auth_transaction, resp,
                                data ? wpabuf_head(data) : (u8 *) "",
-                               data ? wpabuf_len(data) : 0);
+                               data ? wpabuf_len(data) : 0, "auth-sae");
        }
 
 remove_sta:
-       if (sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
-                                  status_code != WLAN_STATUS_SUCCESS)) {
+       if (!sta_removed && sta->added_unassoc &&
+           (resp != WLAN_STATUS_SUCCESS ||
+            status_code != WLAN_STATUS_SUCCESS)) {
                hostapd_drv_sta_remove(hapd, sta->addr);
                sta->added_unassoc = 0;
        }
@@ -1055,6 +1396,105 @@ int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta)
        return 0;
 }
 
+
+void auth_sae_process_commit(void *eloop_ctx, void *user_ctx)
+{
+       struct hostapd_data *hapd = eloop_ctx;
+       struct hostapd_sae_commit_queue *q;
+       unsigned int queue_len;
+
+       q = dl_list_first(&hapd->sae_commit_queue,
+                         struct hostapd_sae_commit_queue, list);
+       if (!q)
+               return;
+       wpa_printf(MSG_DEBUG,
+                  "SAE: Process next available message from queue");
+       dl_list_del(&q->list);
+       handle_auth(hapd, (const struct ieee80211_mgmt *) q->msg, q->len,
+                   q->rssi, 1);
+       os_free(q);
+
+       if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
+               return;
+       queue_len = dl_list_len(&hapd->sae_commit_queue);
+       eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
+                              hapd, NULL);
+}
+
+
+static void auth_sae_queue(struct hostapd_data *hapd,
+                          const struct ieee80211_mgmt *mgmt, size_t len,
+                          int rssi)
+{
+       struct hostapd_sae_commit_queue *q, *q2;
+       unsigned int queue_len;
+       const struct ieee80211_mgmt *mgmt2;
+
+       queue_len = dl_list_len(&hapd->sae_commit_queue);
+       if (queue_len >= 15) {
+               wpa_printf(MSG_DEBUG,
+                          "SAE: No more room in message queue - drop the new frame from "
+                          MACSTR, MAC2STR(mgmt->sa));
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG, "SAE: Queue Authentication message from "
+                  MACSTR " for processing (queue_len %u)", MAC2STR(mgmt->sa),
+                  queue_len);
+       q = os_zalloc(sizeof(*q) + len);
+       if (!q)
+               return;
+       q->rssi = rssi;
+       q->len = len;
+       os_memcpy(q->msg, mgmt, len);
+
+       /* Check whether there is already a queued Authentication frame from the
+        * same station with the same transaction number and if so, replace that
+        * queue entry with the new one. This avoids issues with a peer that
+        * sends multiple times (e.g., due to frequent SAE retries). There is no
+        * point in us trying to process the old attempts after a new one has
+        * obsoleted them. */
+       dl_list_for_each(q2, &hapd->sae_commit_queue,
+                        struct hostapd_sae_commit_queue, list) {
+               mgmt2 = (const struct ieee80211_mgmt *) q2->msg;
+               if (os_memcmp(mgmt->sa, mgmt2->sa, ETH_ALEN) == 0 &&
+                   mgmt->u.auth.auth_transaction ==
+                   mgmt2->u.auth.auth_transaction) {
+                       wpa_printf(MSG_DEBUG,
+                                  "SAE: Replace queued message from same STA with same transaction number");
+                       dl_list_add(&q2->list, &q->list);
+                       dl_list_del(&q2->list);
+                       os_free(q2);
+                       goto queued;
+               }
+       }
+
+       /* No pending identical entry, so add to the end of the queue */
+       dl_list_add_tail(&hapd->sae_commit_queue, &q->list);
+
+queued:
+       if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
+               return;
+       eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
+                              hapd, NULL);
+}
+
+
+static int auth_sae_queued_addr(struct hostapd_data *hapd, const u8 *addr)
+{
+       struct hostapd_sae_commit_queue *q;
+       const struct ieee80211_mgmt *mgmt;
+
+       dl_list_for_each(q, &hapd->sae_commit_queue,
+                        struct hostapd_sae_commit_queue, list) {
+               mgmt = (const struct ieee80211_mgmt *) q->msg;
+               if (os_memcmp(addr, mgmt->sa, ETH_ALEN) == 0)
+                       return 1;
+       }
+
+       return 0;
+}
+
 #endif /* CONFIG_SAE */
 
 
@@ -1068,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)
@@ -1214,7 +1652,10 @@ 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)
@@ -1413,8 +1854,11 @@ prepare_auth_resp_fils(struct hostapd_data *hapd,
        if (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm))) {
                /* FTE[R1KH-ID,R0KH-ID] when using FILS+FT */
                int res;
+               int use_sha384 = wpa_key_mgmt_sha384(
+                       wpa_auth_sta_key_mgmt(sta->wpa_sm));
 
-               res = wpa_auth_write_fte(hapd->wpa_auth, wpabuf_put(data, 0),
+               res = wpa_auth_write_fte(hapd->wpa_auth, use_sha384,
+                                        wpabuf_put(data, 0),
                                         wpabuf_tailroom(data));
                if (res < 0) {
                        *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -1469,15 +1913,27 @@ prepare_auth_resp_fils(struct hostapd_data *hapd,
                if (sta->fils_erp_pmkid_set) {
                        /* TODO: get PMKLifetime from WPA parameters */
                        unsigned int dot11RSNAConfigPMKLifetime = 43200;
+                       int session_timeout;
+
+                       session_timeout = dot11RSNAConfigPMKLifetime;
+                       if (sta->session_timeout_set) {
+                               struct os_reltime now, diff;
+
+                               os_get_reltime(&now);
+                               os_reltime_sub(&sta->session_timeout, &now,
+                                              &diff);
+                               session_timeout = diff.sec;
+                       }
 
                        sta->fils_erp_pmkid_set = 0;
-                       if (wpa_auth_pmksa_add2(
+                       wpa_auth_add_fils_pmk_pmkid(sta->wpa_sm, pmk, pmk_len,
+                                                   sta->fils_erp_pmkid);
+                       if (!hapd->conf->disable_pmksa_caching &&
+                           wpa_auth_pmksa_add2(
                                    hapd->wpa_auth, sta->addr,
                                    pmk, pmk_len,
                                    sta->fils_erp_pmkid,
-                                   sta->session_timeout_set ?
-                                   sta->session_timeout :
-                                   dot11RSNAConfigPMKLifetime,
+                                   session_timeout,
                                    wpa_auth_sta_key_mgmt(sta->wpa_sm)) < 0) {
                                wpa_printf(MSG_ERROR,
                                           "FILS: Failed to add PMKSA cache entry based on ERP");
@@ -1535,7 +1991,7 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd,
                WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
        send_auth_reply(hapd, sta->addr, hapd->own_addr, auth_alg, 2, resp,
                        data ? wpabuf_head(data) : (u8 *) "",
-                       data ? wpabuf_len(data) : 0);
+                       data ? wpabuf_len(data) : 0, "auth-fils-finish");
        wpabuf_free(data);
 
        if (resp == WLAN_STATUS_SUCCESS) {
@@ -1577,25 +2033,28 @@ void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
 #endif /* CONFIG_FILS */
 
 
-static int
+int
 ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
                           const u8 *msg, size_t len, u32 *session_timeout,
                           u32 *acct_interim_interval,
                           struct vlan_description *vlan_id,
                           struct hostapd_sta_wpa_psk_short **psk,
-                          char **identity, char **radius_cui)
+                          char **identity, char **radius_cui, int is_probe_req)
 {
        int res;
 
        os_memset(vlan_id, 0, sizeof(*vlan_id));
        res = hostapd_allowed_address(hapd, addr, msg, len,
                                      session_timeout, acct_interim_interval,
-                                     vlan_id, psk, identity, radius_cui);
+                                     vlan_id, psk, identity, radius_cui,
+                                     is_probe_req);
 
        if (res == HOSTAPD_ACL_REJECT) {
-               wpa_printf(MSG_INFO,
-                          "Station " MACSTR " not allowed to authenticate",
-                          MAC2STR(addr));
+               if (!is_probe_req)
+                       wpa_printf(MSG_DEBUG,
+                                  "Station " MACSTR
+                                  " not allowed to authenticate",
+                                  MAC2STR(addr));
                return HOSTAPD_ACL_REJECT;
        }
 
@@ -1644,24 +2103,33 @@ ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
                sta->psk = NULL;
        }
 
+       os_free(sta->identity);
        sta->identity = *identity;
        *identity = NULL;
+
+       os_free(sta->radius_cui);
        sta->radius_cui = *radius_cui;
        *radius_cui = NULL;
 
        if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
                sta->acct_interim_interval = acct_interim_interval;
-       if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
+       if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT) {
+               sta->session_timeout_set = 1;
+               os_get_reltime(&sta->session_timeout);
+               sta->session_timeout.sec += session_timeout;
                ap_sta_session_timeout(hapd, sta, session_timeout);
-       else
+       } else {
+               sta->session_timeout_set = 0;
                ap_sta_no_session_timeout(hapd, sta);
+       }
 
        return 0;
 }
 
 
 static void handle_auth(struct hostapd_data *hapd,
-                       const struct ieee80211_mgmt *mgmt, size_t len)
+                       const struct ieee80211_mgmt *mgmt, size_t len,
+                       int rssi, int from_queue)
 {
        u16 auth_alg, auth_transaction, status_code;
        u16 resp = WLAN_STATUS_SUCCESS;
@@ -1708,11 +2176,12 @@ static void handle_auth(struct hostapd_data *hapd,
 
        wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
                   "auth_transaction=%d status_code=%d wep=%d%s "
-                  "seq_ctrl=0x%x%s",
+                  "seq_ctrl=0x%x%s%s",
                   MAC2STR(mgmt->sa), auth_alg, auth_transaction,
                   status_code, !!(fc & WLAN_FC_ISWEP),
                   challenge ? " challenge" : "",
-                  seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
+                  seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "",
+                  from_queue ? " (from queue)" : "");
 
 #ifdef CONFIG_NO_RC4
        if (auth_alg == WLAN_AUTH_SHARED_KEY) {
@@ -1725,6 +2194,8 @@ static void handle_auth(struct hostapd_data *hapd,
 #endif /* CONFIG_NO_RC4 */
 
        if (hapd->tkip_countermeasures) {
+               wpa_printf(MSG_DEBUG,
+                          "Ongoing TKIP countermeasures (Michael MIC failure) - reject authentication");
                resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
                goto fail;
        }
@@ -1826,17 +2297,38 @@ static void handle_auth(struct hostapd_data *hapd,
 
        res = ieee802_11_allowed_address(
                hapd, mgmt->sa, (const u8 *) mgmt, len, &session_timeout,
-               &acct_interim_interval, &vlan_id, &psk, &identity, &radius_cui);
+               &acct_interim_interval, &vlan_id, &psk, &identity, &radius_cui,
+               0);
        if (res == HOSTAPD_ACL_REJECT) {
+               wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+                       "Ignore Authentication frame from " MACSTR
+                       " due to ACL reject", MAC2STR(mgmt->sa));
                resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
                goto fail;
        }
        if (res == HOSTAPD_ACL_PENDING)
                return;
 
+#ifdef CONFIG_SAE
+       if (auth_alg == WLAN_AUTH_SAE && !from_queue &&
+           (auth_transaction == 1 ||
+            (auth_transaction == 2 && auth_sae_queued_addr(hapd, mgmt->sa)))) {
+               /* Handle SAE Authentication commit message through a queue to
+                * provide more control for postponing the needed heavy
+                * processing under a possible DoS attack scenario. In addition,
+                * queue SAE Authentication confirm message if there happens to
+                * be a queued commit message from the same peer. This is needed
+                * to avoid reordering Authentication frames within the same
+                * SAE exchange. */
+               auth_sae_queue(hapd, mgmt, len, rssi);
+               return;
+       }
+#endif /* CONFIG_SAE */
+
        sta = ap_get_sta(hapd, mgmt->sa);
        if (sta) {
                sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
+               sta->ft_over_ds = 0;
                if ((fc & WLAN_FC_RETRY) &&
                    sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
                    sta->last_seq_ctrl == seq_ctrl &&
@@ -1878,17 +2370,22 @@ static void handle_auth(struct hostapd_data *hapd,
 
                sta = ap_sta_add(hapd, mgmt->sa);
                if (!sta) {
+                       wpa_printf(MSG_DEBUG, "ap_sta_add() failed");
                        resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
                        goto fail;
                }
        }
        sta->last_seq_ctrl = seq_ctrl;
        sta->last_subtype = WLAN_FC_STYPE_AUTH;
+#ifdef CONFIG_MBO
+       sta->auth_rssi = rssi;
+#endif /* CONFIG_MBO */
 
        res = ieee802_11_set_radius_info(
                hapd, sta, res, session_timeout, acct_interim_interval,
                &vlan_id, &psk, &identity, &radius_cui);
        if (res) {
+               wpa_printf(MSG_DEBUG, "ieee802_11_set_radius_info() failed");
                resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
                goto fail;
        }
@@ -1926,12 +2423,16 @@ static void handle_auth(struct hostapd_data *hapd,
                 * updated. To handle this, station's added_unassoc flag is
                 * cleared once the station has completed association.
                 */
+               ap_sta_set_authorized(hapd, sta, 0);
                hostapd_drv_sta_remove(hapd, sta->addr);
                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,
@@ -1957,6 +2458,9 @@ static void handle_auth(struct hostapd_data *hapd,
        case WLAN_AUTH_SHARED_KEY:
                resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
                                       fc & WLAN_FC_ISWEP);
+               if (resp != 0)
+                       wpa_printf(MSG_DEBUG,
+                                  "auth_shared_key() failed: status=%d", resp);
                sta->auth_alg = WLAN_AUTH_SHARED_KEY;
                mlme_authenticate_indication(hapd, sta);
                if (sta->challenge && auth_transaction == 1) {
@@ -2027,7 +2531,7 @@ static void handle_auth(struct hostapd_data *hapd,
 
        reply_res = send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
                                    auth_transaction + 1, resp, resp_ies,
-                                   resp_ies_len);
+                                   resp_ies_len, "handle-auth");
 
        if (sta && sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
                                          reply_res != WLAN_STATUS_SUCCESS)) {
@@ -2116,6 +2620,59 @@ static u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta,
        return WLAN_STATUS_SUCCESS;
 }
 
+static u16 check_multi_ap(struct hostapd_data *hapd, struct sta_info *sta,
+                         const u8 *multi_ap_ie, size_t multi_ap_len)
+{
+       u8 multi_ap_value = 0;
+
+       sta->flags &= ~WLAN_STA_MULTI_AP;
+
+       if (!hapd->conf->multi_ap)
+               return WLAN_STATUS_SUCCESS;
+
+       if (multi_ap_ie) {
+               const u8 *multi_ap_subelem;
+
+               multi_ap_subelem = get_ie(multi_ap_ie + 4,
+                                         multi_ap_len - 4,
+                                         MULTI_AP_SUB_ELEM_TYPE);
+               if (multi_ap_subelem && multi_ap_subelem[1] == 1) {
+                       multi_ap_value = multi_ap_subelem[2];
+               } else {
+                       hostapd_logger(hapd, sta->addr,
+                                      HOSTAPD_MODULE_IEEE80211,
+                                      HOSTAPD_LEVEL_INFO,
+                                      "Multi-AP IE has missing or invalid Multi-AP subelement");
+                       return WLAN_STATUS_INVALID_IE;
+               }
+       }
+
+       if (multi_ap_value && multi_ap_value != MULTI_AP_BACKHAUL_STA)
+               hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+                              HOSTAPD_LEVEL_INFO,
+                              "Multi-AP IE with unexpected value 0x%02x",
+                              multi_ap_value);
+
+       if (!(multi_ap_value & MULTI_AP_BACKHAUL_STA)) {
+               if (hapd->conf->multi_ap & FRONTHAUL_BSS)
+                       return WLAN_STATUS_SUCCESS;
+
+               hostapd_logger(hapd, sta->addr,
+                              HOSTAPD_MODULE_IEEE80211,
+                              HOSTAPD_LEVEL_INFO,
+                              "Non-Multi-AP STA tries to associate with backhaul-only BSS");
+               return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+       }
+
+       if (!(hapd->conf->multi_ap & BACKHAUL_BSS))
+               hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+                              HOSTAPD_LEVEL_DEBUG,
+                              "Backhaul STA tries to associate with fronthaul-only BSS");
+
+       sta->flags |= WLAN_STA_MULTI_AP;
+       return WLAN_STATUS_SUCCESS;
+}
+
 
 static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
                           struct ieee802_11_elems *elems)
@@ -2341,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 */
 
 
@@ -2372,6 +3046,11 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
        resp = copy_supp_rates(hapd, sta, &elems);
        if (resp != WLAN_STATUS_SUCCESS)
                return resp;
+
+       resp = check_multi_ap(hapd, sta, elems.multi_ap, elems.multi_ap_len);
+       if (resp != WLAN_STATUS_SUCCESS)
+               return resp;
+
 #ifdef CONFIG_IEEE80211N
        resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities);
        if (resp != WLAN_STATUS_SUCCESS)
@@ -2411,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) {
@@ -2483,18 +3171,25 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
                                   "state machine");
                        return WLAN_STATUS_UNSPECIFIED_FAILURE;
                }
+               wpa_auth_set_auth_alg(sta->wpa_sm, sta->auth_alg);
                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_MFP) && !sta->sa_query_timed_out &&
+               if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
+                   (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
+                   !sta->sa_query_timed_out &&
                    sta->sa_query_count > 0)
                        ap_check_sa_query_timeout(hapd, sta);
-               if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+               if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
+                   (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
+                   !sta->sa_query_timed_out &&
                    (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
                        /*
                         * STA has already been associated with MFP and SA
@@ -2513,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) {
@@ -2533,6 +3227,10 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
 #endif /* CONFIG_IEEE80211R_AP */
 
 #ifdef CONFIG_SAE
+               if (wpa_auth_uses_sae(sta->wpa_sm) && sta->sae &&
+                   sta->sae->state == SAE_ACCEPTED)
+                       wpa_auth_add_sae_pmkid(sta->wpa_sm, sta->sae->pmkid);
+
                if (wpa_auth_uses_sae(sta->wpa_sm) &&
                    sta->auth_alg == WLAN_AUTH_OPEN) {
                        struct rsn_pmksa_cache_entry *sa;
@@ -2567,6 +3265,37 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
                }
 #endif /* CONFIG_OWE */
 
+#ifdef CONFIG_DPP2
+               dpp_pfs_free(sta->dpp_pfs);
+               sta->dpp_pfs = NULL;
+
+               if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
+                   hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
+                   wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
+                   elems.owe_dh) {
+                       sta->dpp_pfs = dpp_pfs_init(
+                               wpabuf_head(hapd->conf->dpp_netaccesskey),
+                               wpabuf_len(hapd->conf->dpp_netaccesskey));
+                       if (!sta->dpp_pfs) {
+                               wpa_printf(MSG_DEBUG,
+                                          "DPP: Could not initialize PFS");
+                               /* Try to continue without PFS */
+                               goto pfs_fail;
+                       }
+
+                       if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh,
+                                           elems.owe_dh_len) < 0) {
+                               dpp_pfs_free(sta->dpp_pfs);
+                               sta->dpp_pfs = NULL;
+                               return WLAN_STATUS_UNSPECIFIED_FAILURE;
+                       }
+               }
+
+               wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ?
+                                  sta->dpp_pfs->secret : NULL);
+       pfs_fail:
+#endif /* CONFIG_DPP2 */
+
 #ifdef CONFIG_IEEE80211N
                if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
                    wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
@@ -2611,10 +3340,29 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
 #ifdef CONFIG_HS20
        wpabuf_free(sta->hs20_ie);
        if (elems.hs20 && elems.hs20_len > 4) {
+               int release;
+
                sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
                                                 elems.hs20_len - 4);
-       } else
+               release = ((elems.hs20[4] >> 4) & 0x0f) + 1;
+               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));
+                       return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
+               }
+       } else {
                sta->hs20_ie = NULL;
+       }
+
+       wpabuf_free(sta->roaming_consortium);
+       if (elems.roaming_cons_sel)
+               sta->roaming_consortium = wpabuf_alloc_copy(
+                       elems.roaming_cons_sel + 4,
+                       elems.roaming_cons_sel_len - 4);
+       else
+               sta->roaming_consortium = NULL;
 #endif /* CONFIG_HS20 */
 
 #ifdef CONFIG_FST
@@ -2637,6 +3385,35 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
        }
 #endif /* CONFIG_MBO */
 
+#if defined(CONFIG_FILS) && defined(CONFIG_OCV)
+       if (wpa_auth_uses_ocv(sta->wpa_sm) &&
+           (sta->auth_alg == WLAN_AUTH_FILS_SK ||
+            sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+            sta->auth_alg == WLAN_AUTH_FILS_PK)) {
+               struct wpa_channel_info ci;
+               int tx_chanwidth;
+               int tx_seg1_idx;
+
+               if (hostapd_drv_channel_info(hapd, &ci) != 0) {
+                       wpa_printf(MSG_WARNING,
+                                  "Failed to get channel info to validate received OCI in FILS (Re)Association Request frame");
+                       return WLAN_STATUS_UNSPECIFIED_FAILURE;
+               }
+
+               if (get_sta_tx_parameters(sta->wpa_sm,
+                                         channel_width_to_int(ci.chanwidth),
+                                         ci.seg1_idx, &tx_chanwidth,
+                                         &tx_seg1_idx) < 0)
+                       return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+               if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
+                                        tx_chanwidth, tx_seg1_idx) != 0) {
+                       wpa_printf(MSG_WARNING, "FILS: %s", ocv_errorstr);
+                       return WLAN_STATUS_UNSPECIFIED_FAILURE;
+               }
+       }
+#endif /* CONFIG_FILS && CONFIG_OCV */
+
        ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes,
                                    elems.supp_op_classes_len);
 
@@ -2681,10 +3458,11 @@ static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
 
 
 static int add_associated_sta(struct hostapd_data *hapd,
-                             struct sta_info *sta)
+                             struct sta_info *sta, int reassoc)
 {
        struct ieee80211_ht_capabilities ht_cap;
        struct ieee80211_vht_capabilities vht_cap;
+       struct ieee80211_he_capabilities he_cap;
        int set = 1;
 
        /*
@@ -2697,14 +3475,36 @@ static int add_associated_sta(struct hostapd_data *hapd,
         * Skip this if the STA has already completed FT reassociation and the
         * TK has been configured since the TX/RX PN must not be reset to 0 for
         * the same key.
+        *
+        * FT-over-the-DS has a special case where the STA entry (and as such,
+        * the TK) has not yet been configured to the driver depending on which
+        * driver interface is used. For that case, allow add-STA operation to
+        * be used (instead of set-STA). This is needed to allow mac80211-based
+        * drivers to accept the STA parameter configuration. Since this is
+        * after a new FT-over-DS exchange, a new TK has been derived, so key
+        * reinstallation is not a concern for this case.
         */
+       wpa_printf(MSG_DEBUG, "Add associated STA " MACSTR
+                  " (added_unassoc=%d auth_alg=%u ft_over_ds=%u reassoc=%d authorized=%d ft_tk=%d fils_tk=%d)",
+                  MAC2STR(sta->addr), sta->added_unassoc, sta->auth_alg,
+                  sta->ft_over_ds, reassoc,
+                  !!(sta->flags & WLAN_STA_AUTHORIZED),
+                  wpa_auth_sta_ft_tk_already_set(sta->wpa_sm),
+                  wpa_auth_sta_fils_tk_already_set(sta->wpa_sm));
+
        if (!sta->added_unassoc &&
            (!(sta->flags & WLAN_STA_AUTHORIZED) ||
+            (reassoc && sta->ft_over_ds && sta->auth_alg == WLAN_AUTH_FT) ||
             (!wpa_auth_sta_ft_tk_already_set(sta->wpa_sm) &&
              !wpa_auth_sta_fils_tk_already_set(sta->wpa_sm)))) {
                hostapd_drv_sta_remove(hapd, sta->addr);
                wpa_auth_sm_event(sta->wpa_sm, WPA_DRV_STA_REMOVED);
                set = 0;
+
+                /* Do not allow the FT-over-DS exception to be used more than
+                 * once per authentication exchange to guarantee a new TK is
+                 * used here */
+               sta->ft_over_ds = 0;
        }
 
 #ifdef CONFIG_IEEE80211N
@@ -2715,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
@@ -2726,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)) {
@@ -2750,7 +3558,7 @@ static int add_associated_sta(struct hostapd_data *hapd,
 
 static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
                           const u8 *addr, u16 status_code, int reassoc,
-                          const u8 *ies, size_t ies_len)
+                          const u8 *ies, size_t ies_len, int rssi)
 {
        int send_len;
        u8 *buf;
@@ -2763,11 +3571,17 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
 #ifdef CONFIG_FILS
        if (sta && sta->fils_hlp_resp)
                buflen += wpabuf_len(sta->fils_hlp_resp);
+       if (sta)
+               buflen += 150;
 #endif /* CONFIG_FILS */
 #ifdef CONFIG_OWE
        if (sta && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
                buflen += 150;
 #endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP2
+       if (sta && sta->dpp_pfs)
+               buflen += 5 + sta->dpp_pfs->curve->prime_len;
+#endif /* CONFIG_DPP2 */
        buf = os_zalloc(buflen);
        if (!buf) {
                res = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -2795,6 +3609,16 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
        /* Extended supported rates */
        p = hostapd_eid_ext_supp_rates(hapd, p);
 
+#ifdef CONFIG_MBO
+       if (status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
+           rssi != 0) {
+               int delta = hapd->iconf->rssi_reject_assoc_rssi - rssi;
+
+               p = hostapd_eid_mbo_rssi_assoc_rej(hapd, p, buf + buflen - p,
+                                                  delta);
+       }
+#endif /* CONFIG_MBO */
+
 #ifdef CONFIG_IEEE80211R_AP
        if (sta && status_code == WLAN_STATUS_SUCCESS) {
                /* IEEE 802.11r: Mobility Domain Information, Fast BSS
@@ -2802,20 +3626,34 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
                p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
                                                buf + buflen - p,
                                                sta->auth_alg, ies, ies_len);
+               if (!p) {
+                       wpa_printf(MSG_DEBUG,
+                                  "FT: Failed to write AssocResp IEs");
+                       res = WLAN_STATUS_UNSPECIFIED_FAILURE;
+                       goto done;
+               }
        }
 #endif /* CONFIG_IEEE80211R_AP */
+#ifdef CONFIG_FILS
+       if (sta && status_code == WLAN_STATUS_SUCCESS &&
+           (sta->auth_alg == WLAN_AUTH_FILS_SK ||
+            sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+            sta->auth_alg == WLAN_AUTH_FILS_PK))
+               p = wpa_auth_write_assoc_resp_fils(sta->wpa_sm, p,
+                                                  buf + buflen - p,
+                                                  ies, ies_len);
+#endif /* CONFIG_FILS */
 
 #ifdef CONFIG_OWE
-       if (sta && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
+       if (sta && status_code == WLAN_STATUS_SUCCESS &&
+           (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
                p = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, p,
                                                  buf + buflen - p,
                                                  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);
@@ -2823,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) {
@@ -2845,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)
@@ -2858,6 +3706,39 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
        }
 #endif /* CONFIG_FST */
 
+#ifdef CONFIG_OWE
+       if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
+           sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
+           wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE) {
+               struct wpabuf *pub;
+
+               pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
+               if (!pub) {
+                       res = WLAN_STATUS_UNSPECIFIED_FAILURE;
+                       goto done;
+               }
+               /* OWE Diffie-Hellman Parameter element */
+               *p++ = WLAN_EID_EXTENSION; /* Element ID */
+               *p++ = 1 + 2 + wpabuf_len(pub); /* Length */
+               *p++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension */
+               WPA_PUT_LE16(p, sta->owe_group);
+               p += 2;
+               os_memcpy(p, wpabuf_head(pub), wpabuf_len(pub));
+               p += wpabuf_len(pub);
+               wpabuf_free(pub);
+       }
+#endif /* CONFIG_OWE */
+
+#ifdef CONFIG_DPP2
+       if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
+           sta && sta->dpp_pfs && status_code == WLAN_STATUS_SUCCESS &&
+           wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP) {
+               os_memcpy(p, wpabuf_head(sta->dpp_pfs->ie),
+                         wpabuf_len(sta->dpp_pfs->ie));
+               p += wpabuf_len(sta->dpp_pfs->ie);
+       }
+#endif /* CONFIG_DPP2 */
+
 #ifdef CONFIG_IEEE80211AC
        if (sta && hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
                p = hostapd_eid_vendor_vht(hapd, p);
@@ -2879,6 +3760,9 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
        }
 #endif /* CONFIG_WPS */
 
+       if (sta && (sta->flags & WLAN_STA_MULTI_AP))
+               p = hostapd_eid_multi_ap(hapd, p);
+
 #ifdef CONFIG_P2P
        if (sta && sta->p2p_ie && hapd->p2p_group) {
                struct wpabuf *p2p_resp_ie;
@@ -2951,30 +3835,6 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
        }
 #endif /* CONFIG_FILS */
 
-#ifdef CONFIG_OWE
-       if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
-           sta && sta->owe_ecdh &&
-           wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE) {
-               struct wpabuf *pub;
-
-               pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
-               if (!pub) {
-                       res = WLAN_STATUS_UNSPECIFIED_FAILURE;
-                       goto done;
-               }
-               /* OWE Diffie-Hellman Parameter element */
-               *p++ = WLAN_EID_EXTENSION; /* Element ID */
-               *p++ = 1 + 2 + wpabuf_len(pub); /* Length */
-               *p++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension */
-               WPA_PUT_LE16(p, sta->owe_group);
-               p += 2;
-               os_memcpy(p, wpabuf_head(pub), wpabuf_len(pub));
-               p += wpabuf_len(pub);
-               send_len += 3 + 2 + wpabuf_len(pub);
-               wpabuf_free(pub);
-       }
-#endif /* CONFIG_OWE */
-
        if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) {
                wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
                           strerror(errno));
@@ -2988,11 +3848,18 @@ done:
 
 
 #ifdef CONFIG_OWE
-u8 * owe_auth_req_process(struct hostapd_data *hapd, struct sta_info *sta,
-                         const u8 *owe_dh, u8 owe_dh_len,
-                         u8 *owe_buf, size_t owe_buf_len, u16 *reason)
+u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
+                          const u8 *owe_dh, u8 owe_dh_len,
+                          u8 *owe_buf, size_t owe_buf_len, u16 *reason)
 {
-       struct wpabuf *pub;
+#ifdef CONFIG_TESTING_OPTIONS
+       if (hapd->conf->own_ie_override) {
+               wpa_printf(MSG_DEBUG, "OWE: Using IE override");
+               *reason = WLAN_STATUS_SUCCESS;
+               return wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
+                                                    owe_buf_len, NULL, 0);
+       }
+#endif /* CONFIG_TESTING_OPTIONS */
 
        if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
                wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
@@ -3002,25 +3869,40 @@ u8 * owe_auth_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;
-       pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
-       if (!pub) {
-               *reason = WLAN_STATUS_UNSPECIFIED_FAILURE;
-               return NULL;
+
+       owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
+                                               owe_buf_len, NULL, 0);
+
+       if (sta->owe_ecdh && owe_buf) {
+               struct wpabuf *pub;
+
+               pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
+               if (!pub) {
+                       *reason = WLAN_STATUS_UNSPECIFIED_FAILURE;
+                       return owe_buf;
+               }
+
+               /* 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);
        }
 
-       /* 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, OWE_DH_GROUP);
-       owe_buf += 2;
-       os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
-       owe_buf += wpabuf_len(pub);
-       wpabuf_free(pub);
-       *reason = WLAN_STATUS_SUCCESS;
        return owe_buf;
 }
 #endif /* CONFIG_OWE */
@@ -3040,7 +3922,7 @@ void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta)
        reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS,
                                    sta->fils_pending_assoc_is_reassoc,
                                    sta->fils_pending_assoc_req,
-                                   sta->fils_pending_assoc_req_len);
+                                   sta->fils_pending_assoc_req_len, 0);
        os_free(sta->fils_pending_assoc_req);
        sta->fils_pending_assoc_req = NULL;
        sta->fils_pending_assoc_req_len = 0;
@@ -3077,7 +3959,7 @@ void fils_hlp_timeout(void *eloop_ctx, void *eloop_data)
 
 static void handle_assoc(struct hostapd_data *hapd,
                         const struct ieee80211_mgmt *mgmt, size_t len,
-                        int reassoc)
+                        int reassoc, int rssi)
 {
        u16 capab_info, listen_interval, seq_ctrl, fc;
        u16 resp = WLAN_STATUS_SUCCESS, reply_res;
@@ -3173,8 +4055,12 @@ static void handle_assoc(struct hostapd_data *hapd,
                        acl_res = ieee802_11_allowed_address(
                                hapd, mgmt->sa, (const u8 *) mgmt, len,
                                &session_timeout, &acct_interim_interval,
-                               &vlan_id, &psk, &identity, &radius_cui);
+                               &vlan_id, &psk, &identity, &radius_cui, 0);
                        if (acl_res == HOSTAPD_ACL_REJECT) {
+                               wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+                                       "Ignore Association Request frame from "
+                                       MACSTR " due to ACL reject",
+                                       MAC2STR(mgmt->sa));
                                resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
                                goto fail;
                        }
@@ -3256,6 +4142,14 @@ static void handle_assoc(struct hostapd_data *hapd,
                resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
                goto fail;
        }
+
+       if (hapd->iconf->rssi_reject_assoc_rssi && rssi &&
+           rssi < hapd->iconf->rssi_reject_assoc_rssi &&
+           (sta->auth_rssi == 0 ||
+            sta->auth_rssi < hapd->iconf->rssi_reject_assoc_rssi)) {
+               resp = WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS;
+               goto fail;
+       }
 #endif /* CONFIG_MBO */
 
        /*
@@ -3358,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" : "");
@@ -3369,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. */
@@ -3413,10 +4305,24 @@ static void handle_assoc(struct hostapd_data *hapd,
         *    issues with processing other non-Data Class 3 frames during this
         *    window.
         */
-       if (resp == WLAN_STATUS_SUCCESS && sta && add_associated_sta(hapd, sta))
+       if (resp == WLAN_STATUS_SUCCESS && sta &&
+           add_associated_sta(hapd, sta, reassoc))
                resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
 
 #ifdef CONFIG_FILS
+       if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS &&
+           eloop_is_timeout_registered(fils_hlp_timeout, hapd, sta) &&
+           sta->fils_pending_assoc_req) {
+               /* Do not reschedule fils_hlp_timeout in case the station
+                * retransmits (Re)Association Request frame while waiting for
+                * the previously started FILS HLP wait, so that the timeout can
+                * be determined from the first pending attempt. */
+               wpa_printf(MSG_DEBUG,
+                          "FILS: Continue waiting for HLP processing before sending (Re)Association Response frame to "
+                          MACSTR, MAC2STR(sta->addr));
+               os_free(tmp);
+               return;
+       }
        if (sta) {
                eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
                os_free(sta->fils_pending_assoc_req);
@@ -3441,7 +4347,7 @@ static void handle_assoc(struct hostapd_data *hapd,
 #endif /* CONFIG_FILS */
 
        reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc, pos,
-                                   left);
+                                   left, rssi);
        os_free(tmp);
 
        /*
@@ -3580,35 +4486,11 @@ static void handle_beacon(struct hostapd_data *hapd,
 }
 
 
-#ifdef CONFIG_IEEE80211W
-
-static int hostapd_sa_query_action(struct hostapd_data *hapd,
-                                  const struct ieee80211_mgmt *mgmt,
-                                  size_t len)
-{
-       const u8 *end;
-
-       end = mgmt->u.action.u.sa_query_resp.trans_id +
-               WLAN_SA_QUERY_TR_ID_LEN;
-       if (((u8 *) mgmt) + len < end) {
-               wpa_printf(MSG_DEBUG, "IEEE 802.11: Too short SA Query Action "
-                          "frame (len=%lu)", (unsigned long) len);
-               return 0;
-       }
-
-       ieee802_11_sa_query_action(hapd, mgmt->sa,
-                                  mgmt->u.action.u.sa_query_resp.action,
-                                  mgmt->u.action.u.sa_query_resp.trans_id);
-       return 1;
-}
-
-
 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,
@@ -3616,9 +4498,9 @@ static int handle_action(struct hostapd_data *hapd,
                         unsigned int freq)
 {
        struct sta_info *sta;
-       sta = ap_get_sta(hapd, mgmt->sa);
+       u8 *action __maybe_unused;
 
-       if (len < IEEE80211_HDRLEN + 1) {
+       if (len < IEEE80211_HDRLEN + 2 + 1) {
                hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
                               HOSTAPD_LEVEL_DEBUG,
                               "handle_action - too short payload (len=%lu)",
@@ -3626,6 +4508,14 @@ static int handle_action(struct hostapd_data *hapd,
                return 0;
        }
 
+       action = (u8 *) &mgmt->u.action.u;
+       wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR
+                  " da " MACSTR " len %d freq %u",
+                  mgmt->u.action.category, *action,
+                  MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) len, freq);
+
+       sta = ap_get_sta(hapd, mgmt->sa);
+
        if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
            (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
                wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action "
@@ -3634,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)) {
@@ -3644,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);
@@ -3678,10 +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:
-               return hostapd_sa_query_action(hapd, mgmt, len);
-#endif /* CONFIG_IEEE80211W */
+               ieee802_11_sa_query_action(hapd, mgmt, len);
+               return 1;
 #ifdef CONFIG_WNM_AP
        case WLAN_ACTION_WNM:
                ieee802_11_rx_wnm_action_ap(hapd, mgmt, len);
@@ -3702,9 +4589,6 @@ static int handle_action(struct hostapd_data *hapd,
                if (len >= IEEE80211_HDRLEN + 2 &&
                    mgmt->u.action.u.public_action.action ==
                    WLAN_PA_20_40_BSS_COEX) {
-                       wpa_printf(MSG_DEBUG,
-                                  "HT20/40 coex mgmt frame received from STA "
-                                  MACSTR, MAC2STR(mgmt->sa));
                        hostapd_2040_coex_action(hapd, mgmt, len);
                        return 1;
                }
@@ -3822,6 +4706,7 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
        u16 fc, stype;
        int ret = 0;
        unsigned int freq;
+       int ssi_signal = fi ? fi->ssi_signal : 0;
 
        if (len < 24)
                return 0;
@@ -3835,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;
@@ -3857,7 +4754,7 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
 
 
        if (stype == WLAN_FC_STYPE_PROBE_REQ) {
-               handle_probe_req(hapd, mgmt, len, fi->ssi_signal);
+               handle_probe_req(hapd, mgmt, len, ssi_signal);
                return 1;
        }
 
@@ -3872,22 +4769,22 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
        }
 
        if (hapd->iconf->track_sta_max_num)
-               sta_track_add(hapd->iface, mgmt->sa, fi->ssi_signal);
+               sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
 
        switch (stype) {
        case WLAN_FC_STYPE_AUTH:
                wpa_printf(MSG_DEBUG, "mgmt::auth");
-               handle_auth(hapd, mgmt, len);
+               handle_auth(hapd, mgmt, len, ssi_signal, 0);
                ret = 1;
                break;
        case WLAN_FC_STYPE_ASSOC_REQ:
                wpa_printf(MSG_DEBUG, "mgmt::assoc_req");
-               handle_assoc(hapd, mgmt, len, 0);
+               handle_assoc(hapd, mgmt, len, 0, ssi_signal);
                ret = 1;
                break;
        case WLAN_FC_STYPE_REASSOC_REQ:
                wpa_printf(MSG_DEBUG, "mgmt::reassoc_req");
-               handle_assoc(hapd, mgmt, len, 1);
+               handle_assoc(hapd, mgmt, len, 1, ssi_signal);
                ret = 1;
                break;
        case WLAN_FC_STYPE_DISASSOC:
@@ -3924,7 +4821,8 @@ static void handle_auth_cb(struct hostapd_data *hapd,
 
        sta = ap_get_sta(hapd, mgmt->da);
        if (!sta) {
-               wpa_printf(MSG_INFO, "handle_auth_cb: STA " MACSTR " not found",
+               wpa_printf(MSG_DEBUG, "handle_auth_cb: STA " MACSTR
+                          " not found",
                           MAC2STR(mgmt->da));
                return;
        }
@@ -4064,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) {
                /*
@@ -4092,7 +4988,7 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
                sta->flags |= WLAN_STA_WDS;
        }
 
-       if (sta->flags & WLAN_STA_WDS) {
+       if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP)) {
                int ret;
                char ifname_wds[IFNAMSIZ + 1];
 
@@ -4459,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;
        }