]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - src/ap/beacon.c
Allow RSNXE to be removed from Beacon frames for testing purposes
[thirdparty/hostap.git] / src / ap / beacon.c
index 19bff7bb855f241e59bf0ea9fbaf2238b591638b..ff760a0d1a9e772ace6f4da02f7f9b99ea96634c 100644 (file)
@@ -16,6 +16,7 @@
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "common/hw_features_common.h"
+#include "common/wpa_ctrl.h"
 #include "wps/wps_defs.h"
 #include "p2p/p2p.h"
 #include "hostapd.h"
 #include "beacon.h"
 #include "hs20.h"
 #include "dfs.h"
+#include "taxonomy.h"
+#include "ieee802_11_auth.h"
 
 
 #ifdef NEED_AP_MLME
 
-static u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
-                                        size_t len)
-{
-       if (!hapd->conf->radio_measurements || len < 2 + 4)
-               return eid;
-
-       *eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
-       *eid++ = 5;
-       *eid++ = (hapd->conf->radio_measurements & BIT(0)) ?
-               WLAN_RRM_CAPS_NEIGHBOR_REPORT : 0x00;
-       *eid++ = 0x00;
-       *eid++ = 0x00;
-       *eid++ = 0x00;
-       *eid++ = 0x00;
-       return eid;
-}
-
-
 static u8 * hostapd_eid_bss_load(struct hostapd_data *hapd, u8 *eid, size_t len)
 {
        if (len < 2 + 5)
@@ -281,17 +266,101 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
 }
 
 
-static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len)
+static const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid)
+{
+       const u8 *ies;
+       size_t ies_len;
+
+       ies = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ies_len);
+       if (!ies)
+               return NULL;
+
+       return get_ie(ies, ies_len, eid);
+}
+
+
+static const u8 * hostapd_vendor_wpa_ie(struct hostapd_data *hapd,
+                                       u32 vendor_type)
+{
+       const u8 *ies;
+       size_t ies_len;
+
+       ies = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ies_len);
+       if (!ies)
+               return NULL;
+
+       return get_vendor_ie(ies, ies_len, vendor_type);
+}
+
+
+static u8 * hostapd_get_rsne(struct hostapd_data *hapd, u8 *pos, size_t len)
 {
        const u8 *ie;
-       size_t ielen;
 
-       ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
-       if (ie == NULL || ielen > len)
-               return eid;
+       ie = hostapd_wpa_ie(hapd, WLAN_EID_RSN);
+       if (!ie || 2U + ie[1] > len)
+               return pos;
+
+       os_memcpy(pos, ie, 2 + ie[1]);
+       return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_mde(struct hostapd_data *hapd, u8 *pos, size_t len)
+{
+       const u8 *ie;
+
+       ie = hostapd_wpa_ie(hapd, WLAN_EID_MOBILITY_DOMAIN);
+       if (!ie || 2U + ie[1] > len)
+               return pos;
 
-       os_memcpy(eid, ie, ielen);
-       return eid + ielen;
+       os_memcpy(pos, ie, 2 + ie[1]);
+       return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_rsnxe(struct hostapd_data *hapd, u8 *pos, size_t len)
+{
+       const u8 *ie;
+
+#ifdef CONFIG_TESTING_OPTIONS
+       if (hapd->conf->no_beacon_rsnxe) {
+               wpa_printf(MSG_INFO, "TESTING: Do not add RSNXE into Beacon");
+               return pos;
+       }
+#endif /* CONFIG_TESTING_OPTIONS */
+       ie = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
+       if (!ie || 2U + ie[1] > len)
+               return pos;
+
+       os_memcpy(pos, ie, 2 + ie[1]);
+       return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_wpa_ie(struct hostapd_data *hapd, u8 *pos, size_t len)
+{
+       const u8 *ie;
+
+       ie = hostapd_vendor_wpa_ie(hapd, WPA_IE_VENDOR_TYPE);
+       if (!ie || 2U + ie[1] > len)
+               return pos;
+
+       os_memcpy(pos, ie, 2 + ie[1]);
+       return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_osen_ie(struct hostapd_data *hapd, u8 *pos, size_t len)
+{
+       const u8 *ie;
+
+       ie = hostapd_vendor_wpa_ie(hapd, OSEN_IE_VENDOR_TYPE);
+       if (!ie || 2U + ie[1] > len)
+               return pos;
+
+       os_memcpy(pos, ie, 2 + ie[1]);
+       return pos + 2 + ie[1];
 }
 
 
@@ -341,7 +410,7 @@ static u8 * hostapd_eid_supported_op_classes(struct hostapd_data *hapd, u8 *eid)
 
        if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
                                          hapd->iconf->secondary_channel,
-                                         hapd->iconf->vht_oper_chwidth,
+                                         hostapd_get_oper_chwidth(hapd->iconf),
                                          &op_class, &channel) ==
            NUM_HOSTAPD_MODES)
                return eid;
@@ -388,7 +457,17 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
                        2 + sizeof(struct ieee80211_vht_operation);
        }
 
+#ifdef CONFIG_IEEE80211AX
+       if (hapd->iconf->ieee80211ax) {
+               buflen += 3 + sizeof(struct ieee80211_he_capabilities) +
+                       3 + sizeof(struct ieee80211_he_operation) +
+                       3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
+                       3 + sizeof(struct ieee80211_spatial_reuse);
+       }
+#endif /* CONFIG_IEEE80211AX */
+
        buflen += hostapd_mbo_ie_len(hapd);
+       buflen += hostapd_eid_owe_trans_len(hapd);
 
        resp = os_zalloc(buflen);
        if (resp == NULL)
@@ -439,12 +518,10 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
        /* Extended supported rates */
        pos = hostapd_eid_ext_supp_rates(hapd, pos);
 
-       /* RSN, MDIE, WPA */
-       pos = hostapd_eid_wpa(hapd, pos, epos - pos);
-
+       pos = hostapd_get_rsne(hapd, pos, epos - pos);
        pos = hostapd_eid_bss_load(hapd, pos, epos - pos);
-
        pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos);
+       pos = hostapd_get_mde(hapd, pos, epos - pos);
 
        /* eCSA IE */
        csa_pos = hostapd_eid_ecsa(hapd, pos);
@@ -453,15 +530,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
        pos = csa_pos;
 
        pos = hostapd_eid_supported_op_classes(hapd, pos);
-
-#ifdef CONFIG_IEEE80211N
-       /* Secondary Channel Offset element */
-       /* TODO: The standard doesn't specify a position for this element. */
-       pos = hostapd_eid_secondary_channel(hapd, pos);
-
        pos = hostapd_eid_ht_capabilities(hapd, pos);
        pos = hostapd_eid_ht_operation(hapd, pos);
-#endif /* CONFIG_IEEE80211N */
 
        pos = hostapd_eid_ext_capab(hapd, pos);
 
@@ -481,16 +551,36 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
 #endif /* CONFIG_FST */
 
 #ifdef CONFIG_IEEE80211AC
-       if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
-               pos = hostapd_eid_vht_capabilities(hapd, pos);
+       if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
+           !is_6ghz_op_class(hapd->iconf->op_class)) {
+               pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
                pos = hostapd_eid_vht_operation(hapd, pos);
                pos = hostapd_eid_txpower_envelope(hapd, pos);
                pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
        }
+#endif /* CONFIG_IEEE80211AC */
+
+       pos = hostapd_eid_fils_indic(hapd, pos, 0);
+       pos = hostapd_get_rsnxe(hapd, pos, epos - pos);
+
+#ifdef CONFIG_IEEE80211AX
+       if (hapd->iconf->ieee80211ax) {
+               pos = hostapd_eid_he_capab(hapd, pos, IEEE80211_MODE_AP);
+               pos = hostapd_eid_he_operation(hapd, pos);
+               pos = hostapd_eid_spatial_reuse(hapd, pos);
+               pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos);
+       }
+#endif /* CONFIG_IEEE80211AX */
+
+#ifdef CONFIG_IEEE80211AC
        if (hapd->conf->vendor_vht)
                pos = hostapd_eid_vendor_vht(hapd, pos);
 #endif /* CONFIG_IEEE80211AC */
 
+       /* WPA / OSEN */
+       pos = hostapd_get_wpa_ie(hapd, pos, epos - pos);
+       pos = hostapd_get_osen_ie(hapd, pos, epos - pos);
+
        /* Wi-Fi Alliance WMM */
        pos = hostapd_eid_wmm(hapd, pos);
 
@@ -518,10 +608,10 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
 
 #ifdef CONFIG_HS20
        pos = hostapd_eid_hs20_indication(hapd, pos);
-       pos = hostapd_eid_osen(hapd, pos);
 #endif /* CONFIG_HS20 */
 
        pos = hostapd_eid_mbo(hapd, pos, (u8 *) resp + buflen - pos);
+       pos = hostapd_eid_owe_trans(hapd, pos, (u8 *) resp + buflen - pos);
 
        if (hapd->conf->vendor_elements) {
                os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements),
@@ -543,7 +633,9 @@ enum ssid_match_result {
 static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
                                         const u8 *ssid, size_t ssid_len,
                                         const u8 *ssid_list,
-                                        size_t ssid_list_len)
+                                        size_t ssid_list_len,
+                                        const u8 *short_ssid_list,
+                                        size_t short_ssid_list_len)
 {
        const u8 *pos, *end;
        int wildcard = 0;
@@ -554,20 +646,30 @@ static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
            os_memcmp(ssid, hapd->conf->ssid.ssid, ssid_len) == 0)
                return EXACT_SSID_MATCH;
 
-       if (ssid_list == NULL)
-               return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH;
+       if (ssid_list) {
+               pos = ssid_list;
+               end = ssid_list + ssid_list_len;
+               while (end - pos >= 2) {
+                       if (2 + pos[1] > end - pos)
+                               break;
+                       if (pos[1] == 0)
+                               wildcard = 1;
+                       if (pos[1] == hapd->conf->ssid.ssid_len &&
+                           os_memcmp(pos + 2, hapd->conf->ssid.ssid,
+                                     pos[1]) == 0)
+                               return EXACT_SSID_MATCH;
+                       pos += 2 + pos[1];
+               }
+       }
 
-       pos = ssid_list;
-       end = ssid_list + ssid_list_len;
-       while (end - pos >= 1) {
-               if (2 + pos[1] > end - pos)
-                       break;
-               if (pos[1] == 0)
-                       wildcard = 1;
-               if (pos[1] == hapd->conf->ssid.ssid_len &&
-                   os_memcmp(pos + 2, hapd->conf->ssid.ssid, pos[1]) == 0)
-                       return EXACT_SSID_MATCH;
-               pos += 2 + pos[1];
+       if (short_ssid_list) {
+               pos = short_ssid_list;
+               end = short_ssid_list + short_ssid_list_len;
+               while (end - pos >= 4) {
+                       if (hapd->conf->ssid.short_ssid == WPA_GET_LE32(pos))
+                               return EXACT_SSID_MATCH;
+                       pos += 4;
+               }
        }
 
        return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH;
@@ -596,7 +698,7 @@ void sta_track_expire(struct hostapd_iface *iface, int force)
                           MAC2STR(info->addr));
                dl_list_del(&info->list);
                iface->num_sta_seen--;
-               os_free(info);
+               sta_track_del(info);
        }
 }
 
@@ -614,7 +716,7 @@ static struct hostapd_sta_info * sta_track_get(struct hostapd_iface *iface,
 }
 
 
-void sta_track_add(struct hostapd_iface *iface, const u8 *addr)
+void sta_track_add(struct hostapd_iface *iface, const u8 *addr, int ssi_signal)
 {
        struct hostapd_sta_info *info;
 
@@ -624,13 +726,17 @@ void sta_track_add(struct hostapd_iface *iface, const u8 *addr)
                dl_list_del(&info->list);
                dl_list_add_tail(&iface->sta_seen, &info->list);
                os_get_reltime(&info->last_seen);
+               info->ssi_signal = ssi_signal;
                return;
        }
 
        /* Add a new entry */
        info = os_zalloc(sizeof(*info));
+       if (info == NULL)
+               return;
        os_memcpy(info->addr, addr, ETH_ALEN);
        os_get_reltime(&info->last_seen);
+       info->ssi_signal = ssi_signal;
 
        if (iface->num_sta_seen >= iface->conf->track_sta_max_num) {
                /* Expire oldest entry to make room for a new one */
@@ -670,6 +776,23 @@ sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
 }
 
 
+#ifdef CONFIG_TAXONOMY
+void sta_track_claim_taxonomy_info(struct hostapd_iface *iface, const u8 *addr,
+                                  struct wpabuf **probe_ie_taxonomy)
+{
+       struct hostapd_sta_info *info;
+
+       info = sta_track_get(iface, addr);
+       if (!info)
+               return;
+
+       wpabuf_free(*probe_ie_taxonomy);
+       *probe_ie_taxonomy = info->probe_ie_taxonomy;
+       info->probe_ie_taxonomy = NULL;
+}
+#endif /* CONFIG_TAXONOMY */
+
+
 void handle_probe_req(struct hostapd_data *hapd,
                      const struct ieee80211_mgmt *mgmt, size_t len,
                      int ssi_signal)
@@ -684,21 +807,31 @@ void handle_probe_req(struct hostapd_data *hapd,
        int ret;
        u16 csa_offs[2];
        size_t csa_offs_len;
+       struct radius_sta rad_info;
 
        if (len < IEEE80211_HDRLEN)
                return;
        ie = ((const u8 *) mgmt) + IEEE80211_HDRLEN;
        if (hapd->iconf->track_sta_max_num)
-               sta_track_add(hapd->iface, mgmt->sa);
+               sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
        ie_len = len - IEEE80211_HDRLEN;
 
+       ret = hostapd_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
+                                     &rad_info, 1);
+       if (ret == HOSTAPD_ACL_REJECT) {
+               wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+                       "Ignore Probe Request frame from " MACSTR
+                       " due to ACL reject ", MAC2STR(mgmt->sa));
+               return;
+       }
+
        for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
                if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
                                            mgmt->sa, mgmt->da, mgmt->bssid,
                                            ie, ie_len, ssi_signal) > 0)
                        return;
 
-       if (!hapd->iconf->send_probe_response)
+       if (!hapd->conf->send_probe_response)
                return;
 
        if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) {
@@ -763,7 +896,7 @@ void handle_probe_req(struct hostapd_data *hapd,
 #endif /* CONFIG_P2P */
 
        if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0 &&
-           elems.ssid_list_len == 0) {
+           elems.ssid_list_len == 0 && elems.short_ssid_list_len == 0) {
                wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
                           "broadcast SSID ignored", MAC2STR(mgmt->sa));
                return;
@@ -779,8 +912,24 @@ void handle_probe_req(struct hostapd_data *hapd,
        }
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_TAXONOMY
+       {
+               struct sta_info *sta;
+               struct hostapd_sta_info *info;
+
+               if ((sta = ap_get_sta(hapd, mgmt->sa)) != NULL) {
+                       taxonomy_sta_info_probe_req(hapd, sta, ie, ie_len);
+               } else if ((info = sta_track_get(hapd->iface,
+                                                mgmt->sa)) != NULL) {
+                       taxonomy_hostapd_sta_info_probe_req(hapd, info,
+                                                           ie, ie_len);
+               }
+       }
+#endif /* CONFIG_TAXONOMY */
+
        res = ssid_match(hapd, elems.ssid, elems.ssid_len,
-                        elems.ssid_list, elems.ssid_list_len);
+                        elems.ssid_list, elems.ssid_list_len,
+                        elems.short_ssid_list, elems.short_ssid_list_len);
        if (res == NO_SSID_MATCH) {
                if (!(mgmt->da[0] & 0x01)) {
                        wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
@@ -793,6 +942,12 @@ void handle_probe_req(struct hostapd_data *hapd,
                return;
        }
 
+       if (hapd->conf->ignore_broadcast_ssid && res == WILDCARD_SSID_MATCH) {
+               wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
+                          "broadcast SSID ignored", MAC2STR(mgmt->sa));
+               return;
+       }
+
 #ifdef CONFIG_INTERWORKING
        if (hapd->conf->interworking &&
            elems.interworking && elems.interworking_len >= 1) {
@@ -871,6 +1026,9 @@ void handle_probe_req(struct hostapd_data *hapd,
        }
 #endif /* CONFIG_TESTING_OPTIONS */
 
+       wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, RX_PROBE_REQUEST "sa=" MACSTR
+                    " signal=%d", MAC2STR(mgmt->sa), ssi_signal);
+
        resp = hostapd_gen_probe_resp(hapd, mgmt, elems.p2p != NULL,
                                      &resp_len);
        if (resp == NULL)
@@ -894,9 +1052,9 @@ void handle_probe_req(struct hostapd_data *hapd,
                                hapd->cs_c_off_ecsa_proberesp;
        }
 
-       ret = hostapd_drv_send_mlme_csa(hapd, resp, resp_len, noack,
-                                       csa_offs_len ? csa_offs : NULL,
-                                       csa_offs_len);
+       ret = hostapd_drv_send_mlme(hapd, resp, resp_len, noack,
+                                   csa_offs_len ? csa_offs : NULL,
+                                   csa_offs_len, 0);
 
        if (ret < 0)
                wpa_printf(MSG_INFO, "handle_probe_req: send failed");
@@ -947,6 +1105,16 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
 #endif /* NEED_AP_MLME */
 
 
+void sta_track_del(struct hostapd_sta_info *info)
+{
+#ifdef CONFIG_TAXONOMY
+       wpabuf_free(info->probe_ie_taxonomy);
+       info->probe_ie_taxonomy = NULL;
+#endif /* CONFIG_TAXONOMY */
+       os_free(info);
+}
+
+
 int ieee802_11_build_ap_params(struct hostapd_data *hapd,
                               struct wpa_driver_ap_params *params)
 {
@@ -957,7 +1125,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
        size_t resp_len = 0;
 #ifdef NEED_AP_MLME
        u16 capab_info;
-       u8 *pos, *tailpos, *csa_pos;
+       u8 *pos, *tailpos, *tailend, *csa_pos;
 
 #define BEACON_HEAD_BUF_SIZE 256
 #define BEACON_TAIL_BUF_SIZE 512
@@ -985,7 +1153,17 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
        }
 #endif /* CONFIG_IEEE80211AC */
 
+#ifdef CONFIG_IEEE80211AX
+       if (hapd->iconf->ieee80211ax) {
+               tail_len += 3 + sizeof(struct ieee80211_he_capabilities) +
+                       3 + sizeof(struct ieee80211_he_operation) +
+                       3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
+                       3 + sizeof(struct ieee80211_spatial_reuse);
+       }
+#endif /* CONFIG_IEEE80211AX */
+
        tail_len += hostapd_mbo_ie_len(hapd);
+       tail_len += hostapd_eid_owe_trans_len(hapd);
 
        tailpos = tail = os_malloc(tail_len);
        if (head == NULL || tail == NULL) {
@@ -994,6 +1172,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
                os_free(tail);
                return -1;
        }
+       tailend = tail + tail_len;
 
        head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
                                           WLAN_FC_STYPE_BEACON);
@@ -1034,8 +1213,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 
        head_len = pos - (u8 *) head;
 
-       tailpos = hostapd_eid_country(hapd, tailpos,
-                                     tail + BEACON_TAIL_BUF_SIZE - tailpos);
+       tailpos = hostapd_eid_country(hapd, tailpos, tailend - tailpos);
 
        /* Power Constraint element */
        tailpos = hostapd_eid_pwr_constraint(hapd, tailpos);
@@ -1052,16 +1230,11 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
        /* Extended supported rates */
        tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
 
-       /* RSN, MDIE, WPA */
-       tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
-                                 tailpos);
-
+       tailpos = hostapd_get_rsne(hapd, tailpos, tailend - tailpos);
+       tailpos = hostapd_eid_bss_load(hapd, tailpos, tailend - tailpos);
        tailpos = hostapd_eid_rm_enabled_capab(hapd, tailpos,
-                                              tail + BEACON_TAIL_BUF_SIZE -
-                                              tailpos);
-
-       tailpos = hostapd_eid_bss_load(hapd, tailpos,
-                                      tail + BEACON_TAIL_BUF_SIZE - tailpos);
+                                              tailend - tailpos);
+       tailpos = hostapd_get_mde(hapd, tailpos, tailend - tailpos);
 
        /* eCSA IE */
        csa_pos = hostapd_eid_ecsa(hapd, tailpos);
@@ -1070,15 +1243,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
        tailpos = csa_pos;
 
        tailpos = hostapd_eid_supported_op_classes(hapd, tailpos);
-
-#ifdef CONFIG_IEEE80211N
-       /* Secondary Channel Offset element */
-       /* TODO: The standard doesn't specify a position for this element. */
-       tailpos = hostapd_eid_secondary_channel(hapd, tailpos);
-
        tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
        tailpos = hostapd_eid_ht_operation(hapd, tailpos);
-#endif /* CONFIG_IEEE80211N */
 
        tailpos = hostapd_eid_ext_capab(hapd, tailpos);
 
@@ -1102,15 +1268,35 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 
 #ifdef CONFIG_IEEE80211AC
        if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
-               tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
+               tailpos = hostapd_eid_vht_capabilities(hapd, tailpos, 0);
                tailpos = hostapd_eid_vht_operation(hapd, tailpos);
                tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
                tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
        }
+#endif /* CONFIG_IEEE80211AC */
+
+       tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0);
+       tailpos = hostapd_get_rsnxe(hapd, tailpos, tailend - tailpos);
+
+#ifdef CONFIG_IEEE80211AX
+       if (hapd->iconf->ieee80211ax) {
+               tailpos = hostapd_eid_he_capab(hapd, tailpos,
+                                              IEEE80211_MODE_AP);
+               tailpos = hostapd_eid_he_operation(hapd, tailpos);
+               tailpos = hostapd_eid_spatial_reuse(hapd, tailpos);
+               tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos);
+       }
+#endif /* CONFIG_IEEE80211AX */
+
+#ifdef CONFIG_IEEE80211AC
        if (hapd->conf->vendor_vht)
                tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
 #endif /* CONFIG_IEEE80211AC */
 
+       /* WPA / OSEN */
+       tailpos = hostapd_get_wpa_ie(hapd, tailpos, tailend - tailpos);
+       tailpos = hostapd_get_osen_ie(hapd, tailpos, tailend - tailpos);
+
        /* Wi-Fi Alliance WMM */
        tailpos = hostapd_eid_wmm(hapd, tailpos);
 
@@ -1137,10 +1323,11 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 
 #ifdef CONFIG_HS20
        tailpos = hostapd_eid_hs20_indication(hapd, tailpos);
-       tailpos = hostapd_eid_osen(hapd, tailpos);
 #endif /* CONFIG_HS20 */
 
        tailpos = hostapd_eid_mbo(hapd, tailpos, tail + tail_len - tailpos);
+       tailpos = hostapd_eid_owe_trans(hapd, tailpos,
+                                       tail + tail_len - tailpos);
 
        if (hapd->conf->vendor_elements) {
                os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements),
@@ -1163,6 +1350,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
        params->dtim_period = hapd->conf->dtim_period;
        params->beacon_int = hapd->iconf->beacon_int;
        params->basic_rates = hapd->iface->basic_rates;
+       params->beacon_rate = hapd->iconf->beacon_rate;
+       params->rate_type = hapd->iconf->rate_type;
        params->ssid = hapd->conf->ssid.ssid;
        params->ssid_len = hapd->conf->ssid.ssid_len;
        if ((hapd->conf->wpa & (WPA_PROTO_WPA | WPA_PROTO_RSN)) ==
@@ -1177,10 +1366,13 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
        params->key_mgmt_suites = hapd->conf->wpa_key_mgmt;
        params->auth_algs = hapd->conf->auth_algs;
        params->wpa_version = hapd->conf->wpa;
-       params->privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa ||
+       params->privacy = hapd->conf->wpa;
+#ifdef CONFIG_WEP
+       params->privacy |= hapd->conf->ssid.wep.keys_set ||
                (hapd->conf->ieee802_1x &&
                 (hapd->conf->default_wep_key_len ||
                  hapd->conf->individual_wep_key_len));
+#endif /* CONFIG_WEP */
        switch (hapd->conf->ignore_broadcast_ssid) {
        case 0:
                params->hide_ssid = NO_SSID_HIDING;
@@ -1193,7 +1385,6 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
                break;
        }
        params->isolate = hapd->conf->isolate;
-       params->smps_mode = hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_MASK;
 #ifdef NEED_AP_MLME
        params->cts_protect = !!(ieee802_11_erp_info(hapd) &
                                ERP_INFO_USE_PROTECTION);
@@ -1226,7 +1417,20 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
                params->osen = 1;
        }
 #endif /* CONFIG_HS20 */
+       params->multicast_to_unicast = hapd->conf->multicast_to_unicast;
        params->pbss = hapd->conf->pbss;
+
+       if (hapd->conf->ftm_responder) {
+               if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_FTM_RESPONDER) {
+                       params->ftm_responder = 1;
+                       params->lci = hapd->iface->conf->lci;
+                       params->civic = hapd->iface->conf->civic;
+               } else {
+                       wpa_printf(MSG_WARNING,
+                                  "Not configuring FTM responder as the driver doesn't advertise support for it");
+               }
+       }
+
        return 0;
 }
 
@@ -1248,6 +1452,7 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
        struct hostapd_freq_params freq;
        struct hostapd_iface *iface = hapd->iface;
        struct hostapd_config *iconf = iface->conf;
+       struct hostapd_hw_modes *cmode = iface->current_mode;
        struct wpabuf *beacon, *proberesp, *assocresp;
        int res, ret = -1;
 
@@ -1269,17 +1474,33 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
        params.proberesp_ies = proberesp;
        params.assocresp_ies = assocresp;
        params.reenable = hapd->reenable_beacon;
+#ifdef CONFIG_IEEE80211AX
+       params.he_spr = !!hapd->iface->conf->spr.sr_control;
+       params.he_spr_srg_obss_pd_min_offset =
+               hapd->iface->conf->spr.srg_obss_pd_min_offset;
+       params.he_spr_srg_obss_pd_max_offset =
+               hapd->iface->conf->spr.srg_obss_pd_max_offset;
+       params.he_bss_color_disabled =
+               hapd->iface->conf->he_op.he_bss_color_disabled;
+       params.he_bss_color_partial =
+               hapd->iface->conf->he_op.he_bss_color_partial;
+       params.he_bss_color = hapd->iface->conf->he_op.he_bss_color;
+       params.twt_responder = hostapd_get_he_twt_responder(hapd,
+                                                           IEEE80211_MODE_AP);
+#endif /* CONFIG_IEEE80211AX */
        hapd->reenable_beacon = 0;
 
-       if (iface->current_mode &&
+       if (cmode &&
            hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
-                                   iconf->channel, iconf->ieee80211n,
-                                   iconf->ieee80211ac,
+                                   iconf->channel, iconf->enable_edmg,
+                                   iconf->edmg_channel, iconf->ieee80211n,
+                                   iconf->ieee80211ac, iconf->ieee80211ax,
                                    iconf->secondary_channel,
-                                   iconf->vht_oper_chwidth,
-                                   iconf->vht_oper_centr_freq_seg0_idx,
-                                   iconf->vht_oper_centr_freq_seg1_idx,
-                                   iface->current_mode->vht_capab) == 0)
+                                   hostapd_get_oper_chwidth(iconf),
+                                   hostapd_get_oper_centr_freq_seg0_idx(iconf),
+                                   hostapd_get_oper_centr_freq_seg1_idx(iconf),
+                                   cmode->vht_capab,
+                                   &cmode->he_capab[IEEE80211_MODE_AP]) == 0)
                params.freq = &freq;
 
        res = hostapd_drv_set_ap(hapd, &params);