]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - src/ap/ieee802_11.c
Introduce and add key_flag
[thirdparty/hostap.git] / src / ap / ieee802_11.c
index c85a28db44b7e2ffe8a1a21b5477572ab32bc255..cd61077944a9624c5a59c82ca53dad5e3d5b6353 100644 (file)
@@ -98,6 +98,9 @@ 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 &&
+           wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt))
+               num++;
        if (num > 8) {
                /* rest of the rates are encoded in Extended supported
                 * rates element */
@@ -124,6 +127,13 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
                *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
        }
 
+       if (hapd->conf->sae_pwe == 1 &&
+           wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+           count < 8) {
+               count++;
+               *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
+       }
+
        return pos;
 }
 
@@ -141,6 +151,9 @@ 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 &&
+           wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt))
+               num++;
        if (num <= 8)
                return eid;
        num -= 8;
@@ -170,6 +183,13 @@ 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 &&
+           wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt)) {
+               count++;
+               if (count > 8)
+                       *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
+       }
+
        return pos;
 }
 
@@ -296,7 +316,7 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
 #endif /* CONFIG_NO_RC4 */
 
 
-static int send_auth_reply(struct hostapd_data *hapd,
+static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta,
                           const u8 *dst, const u8 *bssid,
                           u16 auth_alg, u16 auth_transaction, u16 resp,
                           const u8 *ies, size_t ies_len, const char *dbg)
@@ -329,7 +349,37 @@ static int send_auth_reply(struct hostapd_data *hapd,
                   " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu) (dbg=%s)",
                   MAC2STR(dst), auth_alg, auth_transaction,
                   resp, (unsigned long) ies_len, dbg);
-       if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
+#ifdef CONFIG_TESTING_OPTIONS
+#ifdef CONFIG_SAE
+       if (hapd->conf->sae_confirm_immediate == 2 &&
+           auth_alg == WLAN_AUTH_SAE) {
+               if (auth_transaction == 1 &&
+                   (resp == WLAN_STATUS_SUCCESS ||
+                    resp == WLAN_STATUS_SAE_HASH_TO_ELEMENT)) {
+                       wpa_printf(MSG_DEBUG,
+                                  "TESTING: Postpone SAE Commit transmission until Confirm is ready");
+                       os_free(sta->sae_postponed_commit);
+                       sta->sae_postponed_commit = buf;
+                       sta->sae_postponed_commit_len = rlen;
+                       return WLAN_STATUS_SUCCESS;
+               }
+
+               if (auth_transaction == 2 && sta && sta->sae_postponed_commit) {
+                       wpa_printf(MSG_DEBUG,
+                                  "TESTING: Send postponed SAE Commit first, immediately followed by SAE Confirm");
+                       if (hostapd_drv_send_mlme(hapd,
+                                                 sta->sae_postponed_commit,
+                                                 sta->sae_postponed_commit_len,
+                                                 0, NULL, 0, 0) < 0)
+                               wpa_printf(MSG_INFO, "send_auth_reply: send failed");
+                       os_free(sta->sae_postponed_commit);
+                       sta->sae_postponed_commit = NULL;
+                       sta->sae_postponed_commit_len = 0;
+               }
+       }
+#endif /* CONFIG_SAE */
+#endif /* CONFIG_TESTING_OPTIONS */
+       if (hostapd_drv_send_mlme(hapd, reply, rlen, 0, NULL, 0, 0) < 0)
                wpa_printf(MSG_INFO, "send_auth_reply: send failed");
        else
                reply_res = WLAN_STATUS_SUCCESS;
@@ -349,7 +399,7 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
        struct sta_info *sta;
        int reply_res;
 
-       reply_res = send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT,
+       reply_res = send_auth_reply(hapd, NULL, dst, bssid, WLAN_AUTH_FT,
                                    auth_transaction, status, ies, ies_len,
                                    "auth-ft-finish");
 
@@ -388,15 +438,25 @@ static void sae_set_state(struct sta_info *sta, enum sae_state state,
 
 
 static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
-                                            struct sta_info *sta, int update)
+                                            struct sta_info *sta, int update,
+                                            int status_code)
 {
        struct wpabuf *buf;
        const char *password = NULL;
        struct sae_password_entry *pw;
        const char *rx_id = NULL;
+       int use_pt = 0;
+       struct sae_pt *pt = NULL;
 
-       if (sta->sae->tmp)
+       if (sta->sae->tmp) {
                rx_id = sta->sae->tmp->pw_id;
+               use_pt = sta->sae->tmp->h2e;
+       }
+
+       if (status_code == WLAN_STATUS_SUCCESS)
+               use_pt = 0;
+       else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT)
+               use_pt = 1;
 
        for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
                if (!is_broadcast_ether_addr(pw->peer_addr) &&
@@ -408,16 +468,24 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
                    os_strcmp(rx_id, pw->identifier) != 0)
                        continue;
                password = pw->password;
+               pt = pw->pt;
                break;
        }
-       if (!password)
-               password = hapd->conf->ssid.wpa_passphrase;
        if (!password) {
+               password = hapd->conf->ssid.wpa_passphrase;
+               pt = hapd->conf->ssid.pt;
+       }
+       if (!password || (use_pt && !pt)) {
                wpa_printf(MSG_DEBUG, "SAE: No password available");
                return NULL;
        }
 
-       if (update &&
+       if (update && use_pt &&
+           sae_prepare_commit_pt(sta->sae, pt, hapd->own_addr, sta->addr,
+                                 NULL) < 0)
+               return NULL;
+
+       if (update && !use_pt &&
            sae_prepare_commit(hapd->own_addr, sta->addr,
                               (u8 *) password, os_strlen(password), rx_id,
                               sta->sae) < 0) {
@@ -462,19 +530,23 @@ static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
 
 static int auth_sae_send_commit(struct hostapd_data *hapd,
                                struct sta_info *sta,
-                               const u8 *bssid, int update)
+                               const u8 *bssid, int update, int status_code)
 {
        struct wpabuf *data;
        int reply_res;
+       u16 status;
 
-       data = auth_build_sae_commit(hapd, sta, update);
+       data = auth_build_sae_commit(hapd, sta, update, status_code);
        if (!data && sta->sae->tmp && sta->sae->tmp->pw_id)
                return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
        if (data == NULL)
                return WLAN_STATUS_UNSPECIFIED_FAILURE;
 
-       reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 1,
-                                   WLAN_STATUS_SUCCESS, wpabuf_head(data),
+       status = (sta->sae->tmp && sta->sae->tmp->h2e) ?
+               WLAN_STATUS_SAE_HASH_TO_ELEMENT : WLAN_STATUS_SUCCESS;
+       reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
+                                   WLAN_AUTH_SAE, 1,
+                                   status, wpabuf_head(data),
                                    wpabuf_len(data), "sae-send-commit");
 
        wpabuf_free(data);
@@ -494,7 +566,8 @@ static int auth_sae_send_confirm(struct hostapd_data *hapd,
        if (data == NULL)
                return WLAN_STATUS_UNSPECIFIED_FAILURE;
 
-       reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 2,
+       reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
+                                   WLAN_AUTH_SAE, 2,
                                    WLAN_STATUS_SUCCESS, wpabuf_head(data),
                                    wpabuf_len(data), "sae-send-confirm");
 
@@ -663,7 +736,7 @@ static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
 
        switch (sta->sae->state) {
        case SAE_COMMITTED:
-               ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
+               ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
                eloop_register_timeout(0,
                                       hapd->dot11RSNASAERetransPeriod * 1000,
                                       auth_sae_retransmit_timer, hapd, sta);
@@ -761,8 +834,8 @@ void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
 
 
 static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
-                      const u8 *bssid, u8 auth_transaction, int allow_reuse,
-                      int *sta_removed)
+                      const u8 *bssid, u16 auth_transaction, u16 status_code,
+                      int allow_reuse, int *sta_removed)
 {
        int ret;
 
@@ -777,8 +850,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) {
+                       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);
+                                                  !allow_reuse, status_code);
                        if (ret)
                                return ret;
                        sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
@@ -787,14 +863,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
@@ -845,7 +924,8 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
                                return WLAN_STATUS_SUCCESS;
                        sta->sae->sync++;
 
-                       ret = auth_sae_send_commit(hapd, sta, bssid, 0);
+                       ret = auth_sae_send_commit(hapd, sta, bssid, 0,
+                                                  status_code);
                        if (ret)
                                return ret;
 
@@ -868,7 +948,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
                         * additional events.
                         */
                        return sae_sm_step(hapd, sta, bssid, auth_transaction,
-                                          0, sta_removed);
+                                          WLAN_STATUS_SUCCESS, 0, sta_removed);
                }
                break;
        case SAE_CONFIRMED:
@@ -878,7 +958,8 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
                                return WLAN_STATUS_SUCCESS;
                        sta->sae->sync++;
 
-                       ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+                       ret = auth_sae_send_commit(hapd, sta, bssid, 1,
+                                                  status_code);
                        if (ret)
                                return ret;
 
@@ -906,7 +987,8 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *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);
+                       ret = auth_sae_send_commit(hapd, sta, bssid, 1,
+                                                  status_code);
                        if (ret)
                                return ret;
                        sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
@@ -976,6 +1058,64 @@ static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta)
 }
 
 
+static int sae_status_success(struct hostapd_data *hapd, u16 status_code)
+{
+       return (hapd->conf->sae_pwe == 0 &&
+               status_code == WLAN_STATUS_SUCCESS) ||
+               (hapd->conf->sae_pwe == 1 &&
+                status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) ||
+               (hapd->conf->sae_pwe == 2 &&
+                (status_code == WLAN_STATUS_SUCCESS ||
+                 status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT));
+}
+
+
+static int sae_is_group_enabled(struct hostapd_data *hapd, int group)
+{
+       int *groups = hapd->conf->sae_groups;
+       int default_groups[] = { 19, 0 };
+       int i;
+
+       if (!groups)
+               groups = default_groups;
+
+       for (i = 0; groups[i] > 0; i++) {
+               if (groups[i] == group)
+                       return 1;
+       }
+
+       return 0;
+}
+
+
+static int check_sae_rejected_groups(struct hostapd_data *hapd,
+                                    const struct wpabuf *groups)
+{
+       size_t i, count;
+       const u8 *pos;
+
+       if (!groups)
+               return 0;
+
+       pos = wpabuf_head(groups);
+       count = wpabuf_len(groups) / 2;
+       for (i = 0; i < count; i++) {
+               int enabled;
+               u16 group;
+
+               group = WPA_GET_LE16(pos);
+               pos += 2;
+               enabled = sae_is_group_enabled(hapd, group);
+               wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
+                          group, enabled ? "enabled" : "disabled");
+               if (enabled)
+                       return 1;
+       }
+
+       return 0;
+}
+
+
 static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                            const struct ieee80211_mgmt *mgmt, size_t len,
                            u16 auth_transaction, u16 status_code)
@@ -995,7 +1135,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                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,
+               send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
                                auth_transaction, resp, pos, end - pos,
                                "auth-sae-reflection-attack");
                goto remove_sta;
@@ -1003,7 +1143,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
 
        if (hapd->conf->sae_commit_override && auth_transaction == 1) {
                wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override");
-               send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
+               send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
                                auth_transaction, resp,
                                wpabuf_head(hapd->conf->sae_commit_override),
                                wpabuf_len(hapd->conf->sae_commit_override),
@@ -1013,9 +1153,11 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
 #endif /* CONFIG_TESTING_OPTIONS */
        if (!sta->sae) {
                if (auth_transaction != 1 ||
-                   status_code != WLAN_STATUS_SUCCESS) {
-                       resp = -1;
-                       goto remove_sta;
+                   !sae_status_success(hapd, status_code)) {
+                       wpa_printf(MSG_DEBUG, "SAE: Unexpected Status Code %u",
+                                  status_code);
+                       resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+                       goto reply;
                }
                sta->sae = os_zalloc(sizeof(*sta->sae));
                if (!sta->sae) {
@@ -1080,7 +1222,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                         * Authentication frame, and the commit-scalar and
                         * COMMIT-ELEMENT previously sent.
                         */
-                       resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0);
+                       resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0,
+                                                   status_code);
                        if (resp != WLAN_STATUS_SUCCESS) {
                                wpa_printf(MSG_ERROR,
                                           "SAE: Failed to send commit message");
@@ -1103,7 +1246,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                        goto remove_sta;
                }
 
-               if (status_code != WLAN_STATUS_SUCCESS)
+               if (!sae_status_success(hapd, status_code))
                        goto remove_sta;
 
                if (!(hapd->conf->mesh & MESH_ENABLED) &&
@@ -1136,7 +1279,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
                                        ((const u8 *) mgmt) + len -
                                        mgmt->u.auth.variable, &token,
-                                       &token_len, groups);
+                                       &token_len, groups, status_code ==
+                                       WLAN_STATUS_SAE_HASH_TO_ELEMENT);
                if (resp == SAE_SILENTLY_DISCARD) {
                        wpa_printf(MSG_DEBUG,
                                   "SAE: Drop commit message from " MACSTR " due to reflection attack",
@@ -1166,6 +1310,13 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                if (resp != WLAN_STATUS_SUCCESS)
                        goto reply;
 
+               if (sta->sae->tmp &&
+                   check_sae_rejected_groups(
+                           hapd, sta->sae->tmp->peer_rejected_groups)) {
+                       resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+                       goto reply;
+               }
+
                if (!token && use_sae_anti_clogging(hapd) && !allow_reuse) {
                        wpa_printf(MSG_DEBUG,
                                   "SAE: Request anti-clogging token from "
@@ -1180,7 +1331,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                }
 
                resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
-                                  allow_reuse, &sta_removed);
+                                  status_code, allow_reuse, &sta_removed);
        } else if (auth_transaction == 2) {
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
                               HOSTAPD_LEVEL_DEBUG,
@@ -1221,8 +1372,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                        }
                        sta->sae->rc = peer_send_confirm;
                }
-               resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction, 0,
-                       &sta_removed);
+               resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
+                                  status_code, 0, &sta_removed);
        } else {
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
                               HOSTAPD_LEVEL_DEBUG,
@@ -1246,7 +1397,7 @@ reply:
                        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,
+               send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
                                auth_transaction, resp,
                                data ? wpabuf_head(data) : (u8 *) "",
                                data ? wpabuf_len(data) : 0, "auth-sae");
@@ -1283,7 +1434,7 @@ int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta)
        if (sta->sae->state != SAE_NOTHING)
                return -1;
 
-       ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
+       ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
        if (ret)
                return -1;
 
@@ -1406,12 +1557,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)
@@ -1554,6 +1703,8 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
        res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
                                  hapd->iface->freq,
                                  elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+                                 elems.rsnxe ? elems.rsnxe - 2 : NULL,
+                                 elems.rsnxe ? elems.rsnxe_len + 2 : 0,
                                  elems.mdie, elems.mdie_len, NULL, 0);
        resp = wpa_res_to_status_code(res);
        if (resp != WLAN_STATUS_SUCCESS)
@@ -1887,7 +2038,7 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd,
        auth_alg = (pub ||
                    resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) ?
                WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
-       send_auth_reply(hapd, sta->addr, hapd->own_addr, auth_alg, 2, resp,
+       send_auth_reply(hapd, sta, sta->addr, hapd->own_addr, auth_alg, 2, resp,
                        data ? wpabuf_head(data) : (u8 *) "",
                        data ? wpabuf_len(data) : 0, "auth-fils-finish");
        wpabuf_free(data);
@@ -1931,28 +2082,18 @@ void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
 #endif /* CONFIG_FILS */
 
 
-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, int is_probe_req)
+static int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
+                                     const u8 *msg, size_t len,
+                                     struct radius_sta *info)
 {
        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,
-                                     is_probe_req);
+       res = hostapd_allowed_address(hapd, addr, msg, len, info, 0);
 
        if (res == HOSTAPD_ACL_REJECT) {
-               if (!is_probe_req)
-                       wpa_printf(MSG_DEBUG,
-                                  "Station " MACSTR
-                                  " not allowed to authenticate",
-                                  MAC2STR(addr));
+               wpa_printf(MSG_DEBUG, "Station " MACSTR
+                          " not allowed to authenticate",
+                          MAC2STR(addr));
                return HOSTAPD_ACL_REJECT;
        }
 
@@ -1972,12 +2113,15 @@ ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
 
 static int
 ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
-                          int res, u32 session_timeout,
-                          u32 acct_interim_interval,
-                          struct vlan_description *vlan_id,
-                          struct hostapd_sta_wpa_psk_short **psk,
-                          char **identity, char **radius_cui)
+                          int res, struct radius_sta *info)
 {
+       u32 session_timeout = info->session_timeout;
+       u32 acct_interim_interval = info->acct_interim_interval;
+       struct vlan_description *vlan_id = &info->vlan_id;
+       struct hostapd_sta_wpa_psk_short *psk = info->psk;
+       char *identity = info->identity;
+       char *radius_cui = info->radius_cui;
+
        if (vlan_id->notempty &&
            !hostapd_vlan_valid(hapd->conf->vlan, vlan_id)) {
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
@@ -1994,20 +2138,22 @@ ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
                               HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
 
        hostapd_free_psk_list(sta->psk);
-       if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
-               sta->psk = *psk;
-               *psk = NULL;
-       } else {
+       if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED)
+               hostapd_copy_psk_list(&sta->psk, psk);
+       else
                sta->psk = NULL;
-       }
 
        os_free(sta->identity);
-       sta->identity = *identity;
-       *identity = NULL;
+       if (identity)
+               sta->identity = os_strdup(identity);
+       else
+               sta->identity = NULL;
 
        os_free(sta->radius_cui);
-       sta->radius_cui = *radius_cui;
-       *radius_cui = NULL;
+       if (radius_cui)
+               sta->radius_cui = os_strdup(radius_cui);
+       else
+               sta->radius_cui = NULL;
 
        if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
                sta->acct_interim_interval = acct_interim_interval;
@@ -2035,14 +2181,10 @@ static void handle_auth(struct hostapd_data *hapd,
        int res, reply_res;
        u16 fc;
        const u8 *challenge = NULL;
-       u32 session_timeout, acct_interim_interval;
-       struct vlan_description vlan_id;
-       struct hostapd_sta_wpa_psk_short *psk = NULL;
        u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
        size_t resp_ies_len = 0;
-       char *identity = NULL;
-       char *radius_cui = NULL;
        u16 seq_ctrl;
+       struct radius_sta rad_info;
 
        if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
                wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
@@ -2193,10 +2335,8 @@ 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,
-               0);
+       res = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
+                                        &rad_info);
        if (res == HOSTAPD_ACL_REJECT) {
                wpa_msg(hapd->msg_ctx, MSG_DEBUG,
                        "Ignore Authentication frame from " MACSTR
@@ -2279,9 +2419,7 @@ static void handle_auth(struct hostapd_data *hapd,
        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);
+       res = ieee802_11_set_radius_info(hapd, sta, res, &rad_info);
        if (res) {
                wpa_printf(MSG_DEBUG, "ieee802_11_set_radius_info() failed");
                resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -2423,11 +2561,7 @@ static void handle_auth(struct hostapd_data *hapd,
        }
 
  fail:
-       os_free(identity);
-       os_free(radius_cui);
-       hostapd_free_psk_list(psk);
-
-       reply_res = send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
+       reply_res = send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, auth_alg,
                                    auth_transaction + 1, resp, resp_ies,
                                    resp_ies_len, "handle-auth");
 
@@ -2865,7 +2999,7 @@ u16 owe_process_rsn_ie(struct hostapd_data *hapd,
        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, owe_dh, owe_dh_len);
+                                 NULL, 0, NULL, 0, owe_dh, owe_dh_len);
        status = wpa_res_to_status_code(res);
        if (status != WLAN_STATUS_SUCCESS)
                goto end;
@@ -3073,12 +3207,13 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
                res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
                                          hapd->iface->freq,
                                          wpa_ie, wpa_ie_len,
+                                         elems.rsnxe ? elems.rsnxe - 2 : NULL,
+                                         elems.rsnxe ? elems.rsnxe_len + 2 : 0,
                                          elems.mdie, elems.mdie_len,
                                          elems.owe_dh, elems.owe_dh_len);
                resp = wpa_res_to_status_code(res);
                if (resp != WLAN_STATUS_SUCCESS)
                        return resp;
-#ifdef CONFIG_IEEE80211W
                if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
                    (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
                    !sta->sa_query_timed_out &&
@@ -3105,7 +3240,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) {
@@ -3150,6 +3284,17 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
                                   MAC2STR(sta->addr), sta->auth_alg);
                        return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
                }
+
+               if (hapd->conf->sae_pwe == 2 &&
+                   sta->auth_alg == WLAN_AUTH_SAE &&
+                   sta->sae && sta->sae->tmp && !sta->sae->tmp->h2e &&
+                   elems.rsnxe && elems.rsnxe_len >= 1 &&
+                   (elems.rsnxe[0] & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) {
+                       wpa_printf(MSG_INFO, "SAE: " MACSTR
+                                  " indicates support for SAE H2E, but did not use it",
+                                  MAC2STR(sta->addr));
+                       return WLAN_STATUS_UNSPECIFIED_FAILURE;
+               }
 #endif /* CONFIG_SAE */
 
 #ifdef CONFIG_OWE
@@ -3243,7 +3388,8 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
                sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
                                                 elems.hs20_len - 4);
                release = ((elems.hs20[4] >> 4) & 0x0f) + 1;
-               if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm)) {
+               if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm) &&
+                   hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
                        wpa_printf(MSG_DEBUG,
                                   "HS 2.0: PMF not negotiated by release %d station "
                                   MACSTR, release, MAC2STR(sta->addr));
@@ -3348,7 +3494,7 @@ static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
        send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
        reply.u.deauth.reason_code = host_to_le16(reason_code);
 
-       if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0) < 0)
+       if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0, NULL, 0, 0) < 0)
                wpa_printf(MSG_INFO, "Failed to send deauth: %s",
                           strerror(errno));
 }
@@ -3549,10 +3695,8 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
                                                  ies, ies_len);
 #endif /* CONFIG_OWE */
 
-#ifdef CONFIG_IEEE80211W
        if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
                p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
-#endif /* CONFIG_IEEE80211W */
 
 #ifdef CONFIG_IEEE80211N
        p = hostapd_eid_ht_capabilities(hapd, p);
@@ -3560,7 +3704,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) {
@@ -3604,6 +3749,8 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
        }
 #endif /* CONFIG_FST */
 
+       p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p);
+
 #ifdef CONFIG_OWE
        if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
            sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
@@ -3733,7 +3880,7 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
        }
 #endif /* CONFIG_FILS */
 
-       if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) {
+       if (hostapd_drv_send_mlme(hapd, reply, send_len, 0, NULL, 0, 0) < 0) {
                wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
                           strerror(errno));
                res = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -3865,9 +4012,6 @@ static void handle_assoc(struct hostapd_data *hapd,
        int left, i;
        struct sta_info *sta;
        u8 *tmp = NULL;
-       struct hostapd_sta_wpa_psk_short *psk = NULL;
-       char *identity = NULL;
-       char *radius_cui = NULL;
 #ifdef CONFIG_FILS
        int delay_assoc = 0;
 #endif /* CONFIG_FILS */
@@ -3947,13 +4091,11 @@ static void handle_assoc(struct hostapd_data *hapd,
                    hapd->iface->current_mode->mode ==
                        HOSTAPD_MODE_IEEE80211AD) {
                        int acl_res;
-                       u32 session_timeout, acct_interim_interval;
-                       struct vlan_description vlan_id;
+                       struct radius_sta info;
 
-                       acl_res = ieee802_11_allowed_address(
-                               hapd, mgmt->sa, (const u8 *) mgmt, len,
-                               &session_timeout, &acct_interim_interval,
-                               &vlan_id, &psk, &identity, &radius_cui, 0);
+                       acl_res = ieee802_11_allowed_address(hapd, mgmt->sa,
+                                                            (const u8 *) mgmt,
+                                                            len, &info);
                        if (acl_res == HOSTAPD_ACL_REJECT) {
                                wpa_msg(hapd->msg_ctx, MSG_DEBUG,
                                        "Ignore Association Request frame from "
@@ -3978,9 +4120,7 @@ static void handle_assoc(struct hostapd_data *hapd,
                        }
 
                        acl_res = ieee802_11_set_radius_info(
-                               hapd, sta, acl_res, session_timeout,
-                               acct_interim_interval, &vlan_id, &psk,
-                               &identity, &radius_cui);
+                               hapd, sta, acl_res, &info);
                        if (acl_res) {
                                resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
                                goto fail;
@@ -4150,7 +4290,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" : "");
@@ -4161,7 +4300,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. */
@@ -4183,9 +4321,6 @@ static void handle_assoc(struct hostapd_data *hapd,
 #endif /* CONFIG_FILS */
 
  fail:
-       os_free(identity);
-       os_free(radius_cui);
-       hostapd_free_psk_list(psk);
 
        /*
         * In case of a successful response, add the station to the driver.
@@ -4386,13 +4521,11 @@ static void handle_beacon(struct hostapd_data *hapd,
 }
 
 
-#ifdef CONFIG_IEEE80211W
 static int robust_action_frame(u8 category)
 {
        return category != WLAN_ACTION_PUBLIC &&
                category != WLAN_ACTION_HT;
 }
-#endif /* CONFIG_IEEE80211W */
 
 
 static int handle_action(struct hostapd_data *hapd,
@@ -4426,7 +4559,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)) {
@@ -4436,7 +4568,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);
@@ -4470,11 +4601,9 @@ static int handle_action(struct hostapd_data *hapd,
        case WLAN_ACTION_WMM:
                hostapd_wmm_action(hapd, mgmt, len);
                return 1;
-#ifdef CONFIG_IEEE80211W
        case WLAN_ACTION_SA_QUERY:
                ieee802_11_sa_query_action(hapd, mgmt, len);
                return 1;
-#endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_WNM_AP
        case WLAN_ACTION_WNM:
                ieee802_11_rx_wnm_action_ap(hapd, mgmt, len);
@@ -4581,7 +4710,7 @@ static int handle_action(struct hostapd_data *hapd,
                os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
                resp->u.action.category |= 0x80;
 
-               if (hostapd_drv_send_mlme(hapd, resp, len, 0) < 0) {
+               if (hostapd_drv_send_mlme(hapd, resp, len, 0, NULL, 0, 0) < 0) {
                        wpa_printf(MSG_ERROR, "IEEE 802.11: Failed to send "
                                   "Action frame");
                }
@@ -4626,6 +4755,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;
@@ -4770,8 +4911,11 @@ static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
        for (i = 0; i < 4; i++) {
                if (ssid->wep.key[i] &&
                    hostapd_drv_set_key(ifname_wds, hapd, WPA_ALG_WEP, NULL, i,
-                                       i == ssid->wep.idx, NULL, 0,
-                                       ssid->wep.key[i], ssid->wep.len[i])) {
+                                       0, i == ssid->wep.idx, NULL, 0,
+                                       ssid->wep.key[i], ssid->wep.len[i],
+                                       i == ssid->wep.idx ?
+                                       KEY_FLAG_GROUP_RX_TX_DEFAULT :
+                                       KEY_FLAG_GROUP_RX_TX)) {
                        wpa_printf(MSG_WARNING,
                                   "Could not set WEP keys for WDS interface; %s",
                                   ifname_wds);
@@ -4856,9 +5000,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) {
                /*
@@ -5251,8 +5393,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;
        }