]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
HE: Add AP mode MLME/SME handling for HE stations
authorJohn Crispin <john@phrozen.org>
Mon, 20 May 2019 07:55:05 +0000 (09:55 +0200)
committerJouni Malinen <j@w1.fi>
Mon, 27 May 2019 13:40:48 +0000 (16:40 +0300)
Process HE information in (Re)Association Request frames and add HE
elements into (Re)Association Response frames when HE is enabled in the
BSS.

Signed-off-by: Shashidhar Lakkavalli <slakkavalli@datto.com>
Signed-off-by: John Crispin <john@phrozen.org>
src/ap/ap_drv_ops.c
src/ap/ap_drv_ops.h
src/ap/ieee802_11.c
src/ap/ieee802_11.h
src/ap/ieee802_11_he.c
src/ap/sta_info.c
src/ap/sta_info.h
src/common/ieee802_11_defs.h

index 9d7759d46ecd8bbbfde04fb7dd7c673e86f2f89e..8bdacf6ff05aca695df5641c2fbcd9eb4d12741f 100644 (file)
@@ -413,6 +413,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
                    u16 listen_interval,
                    const struct ieee80211_ht_capabilities *ht_capab,
                    const struct ieee80211_vht_capabilities *vht_capab,
+                   const struct ieee80211_he_capabilities *he_capab,
+                   size_t he_capab_len,
                    u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
                    int set)
 {
@@ -432,6 +434,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
        params.listen_interval = listen_interval;
        params.ht_capabilities = ht_capab;
        params.vht_capabilities = vht_capab;
+       params.he_capab = he_capab;
+       params.he_capab_len = he_capab_len;
        params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED);
        params.vht_opmode = vht_opmode;
        params.flags = hostapd_sta_flags_to_drv(flags);
index 8758ec1046466a7f4356a706b918619153a28e1a..4357ceed3a273b9d15666595bb4157729693893b 100644 (file)
@@ -41,6 +41,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
                    u16 listen_interval,
                    const struct ieee80211_ht_capabilities *ht_capab,
                    const struct ieee80211_vht_capabilities *vht_capab,
+                   const struct ieee80211_he_capabilities *he_capab,
+                   size_t he_capab_len,
                    u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
                    int set);
 int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
index 890da7aa915da4850d0261d5e91ecb6c05801a32..f050336557fcc6dc6f17d4ef4320953d1befdd89 100644 (file)
@@ -2325,7 +2325,8 @@ static void handle_auth(struct hostapd_data *hapd,
                                WLAN_STA_AUTHORIZED);
 
                if (hostapd_sta_add(hapd, sta->addr, 0, 0, NULL, 0, 0,
-                                   NULL, NULL, sta->flags, 0, 0, 0, 0)) {
+                                   NULL, NULL, NULL, 0,
+                                   sta->flags, 0, 0, 0, 0)) {
                        hostapd_logger(hapd, sta->addr,
                                       HOSTAPD_MODULE_IEEE80211,
                                       HOSTAPD_LEVEL_NOTICE,
@@ -2866,6 +2867,14 @@ 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, elems.he_capabilities,
+                                        elems.he_capabilities_len);
+               if (resp != WLAN_STATUS_SUCCESS)
+                       return resp;
+       }
+#endif /* CONFIG_IEEE80211AX */
 
 #ifdef CONFIG_P2P
        if (elems.p2p) {
@@ -3228,6 +3237,7 @@ static int add_associated_sta(struct hostapd_data *hapd,
 {
        struct ieee80211_ht_capabilities ht_cap;
        struct ieee80211_vht_capabilities vht_cap;
+       struct ieee80211_he_capabilities he_cap;
        int set = 1;
 
        /*
@@ -3280,6 +3290,12 @@ static int add_associated_sta(struct hostapd_data *hapd,
        if (sta->flags & WLAN_STA_VHT)
                hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
 #endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+       if (sta->flags & WLAN_STA_HE) {
+               hostapd_get_he_capab(hapd, sta->he_capab, &he_cap,
+                                    sta->he_capab_len);
+       }
+#endif /* CONFIG_IEEE80211AX */
 
        /*
         * Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
@@ -3291,6 +3307,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)) {
@@ -3442,6 +3460,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);
+               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)
index 3699246b309fba5a6fbe6361bc1a319b435c0c9f..914cd1f19e98349637d4107e6f761e56fc506677 100644 (file)
@@ -71,6 +71,10 @@ void hostapd_get_ht_capab(struct hostapd_data *hapd,
 void hostapd_get_vht_capab(struct hostapd_data *hapd,
                           struct ieee80211_vht_capabilities *vht_cap,
                           struct ieee80211_vht_capabilities *neg_vht_cap);
+void hostapd_get_he_capab(struct hostapd_data *hapd,
+                         const struct ieee80211_he_capabilities *he_cap,
+                         struct ieee80211_he_capabilities *neg_he_cap,
+                         size_t he_capab_len);
 int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta);
 u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
                      const u8 *ht_capab);
@@ -86,6 +90,8 @@ u16 copy_sta_vht_oper(struct hostapd_data *hapd, struct sta_info *sta,
                      const u8 *vht_oper);
 u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
                       const u8 *vht_opmode);
+u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
+                     const u8 *he_capab, size_t he_capab_len);
 void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
                       const u8 *buf, size_t len, int ack);
 void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
index c22427a7e3a5a5bf8fd093742a2e4ffdbdeb09da..066a032c0f3978a214818efd343944219a7b57a0 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * hostapd / IEEE 802.11ax HE
  * Copyright (c) 2016-2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2019 John Crispin <john@phrozen.org>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -13,6 +14,7 @@
 #include "hostapd.h"
 #include "ap_config.h"
 #include "beacon.h"
+#include "sta_info.h"
 #include "ieee802_11.h"
 #include "dfs.h"
 
@@ -236,3 +238,104 @@ u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid)
 
        return pos;
 }
+
+
+void hostapd_get_he_capab(struct hostapd_data *hapd,
+                         const struct ieee80211_he_capabilities *he_cap,
+                         struct ieee80211_he_capabilities *neg_he_cap,
+                         size_t he_capab_len)
+{
+       if (!he_cap)
+               return;
+
+       if (he_capab_len > sizeof(*neg_he_cap))
+               he_capab_len = sizeof(*neg_he_cap);
+       /* TODO: mask out unsupported features */
+
+       os_memcpy(neg_he_cap, he_cap, he_capab_len);
+}
+
+
+static int check_valid_he_mcs(struct hostapd_data *hapd, const u8 *sta_he_capab)
+{
+       u16 sta_rx_mcs_set, ap_tx_mcs_set;
+       u8 mcs_count = 0;
+       const u16 *ap_mcs_set, *sta_mcs_set;
+       int i;
+
+       if (!hapd->iface->current_mode)
+               return 1;
+       ap_mcs_set = (u16 *) hapd->iface->current_mode->he_capab.mcs;
+       sta_mcs_set = (u16 *) ((const struct ieee80211_he_capabilities *)
+                              sta_he_capab)->optional;
+
+       /*
+        * Disable HE capabilities for STAs for which there is not even a single
+        * allowed MCS in any supported number of streams, i.e., STA is
+        * advertising 3 (not supported) as HE MCS rates for all supported
+        * band/stream cases.
+        */
+       switch (hapd->iface->conf->he_oper_chwidth) {
+       case CHANWIDTH_80P80MHZ:
+               mcs_count = 3;
+               break;
+       case CHANWIDTH_160MHZ:
+               mcs_count = 2;
+               break;
+       default:
+               mcs_count = 1;
+               break;
+       }
+
+       for (i = 0; i < mcs_count; i++) {
+               int j;
+
+               /* AP Tx MCS map vs. STA Rx MCS map */
+               sta_rx_mcs_set = WPA_GET_LE16((const u8 *) &sta_mcs_set[i * 2]);
+               ap_tx_mcs_set = WPA_GET_LE16((const u8 *)
+                                            &ap_mcs_set[(i * 2) + 1]);
+
+               for (j = 0; j < HE_NSS_MAX_STREAMS; j++) {
+                       if (((ap_tx_mcs_set >> (j * 2)) & 0x3) == 3)
+                               continue;
+
+                       if (((sta_rx_mcs_set >> (j * 2)) & 0x3) == 3)
+                               continue;
+
+                       return 1;
+               }
+       }
+
+       wpa_printf(MSG_DEBUG,
+                  "No matching HE MCS found between AP TX and STA RX");
+
+       return 0;
+}
+
+
+u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
+                     const u8 *he_capab, size_t he_capab_len)
+{
+       if (!he_capab || !hapd->iconf->ieee80211ax ||
+           !check_valid_he_mcs(hapd, he_capab) ||
+           he_capab_len > sizeof(struct ieee80211_he_capabilities)) {
+               sta->flags &= ~WLAN_STA_HE;
+               os_free(sta->he_capab);
+               sta->he_capab = NULL;
+               return WLAN_STATUS_SUCCESS;
+       }
+
+       if (!sta->he_capab) {
+               sta->he_capab =
+                       os_zalloc(sizeof(struct ieee80211_he_capabilities));
+               if (!sta->he_capab)
+                       return WLAN_STATUS_UNSPECIFIED_FAILURE;
+       }
+
+       sta->flags |= WLAN_STA_HE;
+       os_memset(sta->he_capab, 0, sizeof(struct ieee80211_he_capabilities));
+       os_memcpy(sta->he_capab, he_capab, he_capab_len);
+       sta->he_capab_len = he_capab_len;
+
+       return WLAN_STATUS_SUCCESS;
+}
index 4f9eae8477b63217dc9226b927419034ea9ee674..98b609c18a60be77f926ee973d646715457a2e51 100644 (file)
@@ -330,6 +330,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
        os_free(sta->ht_capabilities);
        os_free(sta->vht_capabilities);
        os_free(sta->vht_operation);
+       os_free(sta->he_capab);
        hostapd_free_psk_list(sta->psk);
        os_free(sta->identity);
        os_free(sta->radius_cui);
index c185d7a0a0bf3cffebf312743b0f313b83f9b458..9a081cb2352af9bf31d8ecabf2c6d1ab334a45c1 100644 (file)
@@ -37,6 +37,7 @@
 #define WLAN_STA_VENDOR_VHT BIT(21)
 #define WLAN_STA_PENDING_FILS_ERP BIT(22)
 #define WLAN_STA_MULTI_AP BIT(23)
+#define WLAN_STA_HE BIT(24)
 #define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
 #define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
 #define WLAN_STA_NONERP BIT(31)
@@ -166,6 +167,8 @@ struct sta_info {
        struct ieee80211_vht_capabilities *vht_capabilities;
        struct ieee80211_vht_operation *vht_operation;
        u8 vht_opmode;
+       struct ieee80211_he_capabilities *he_capab;
+       size_t he_capab_len;
 
 #ifdef CONFIG_IEEE80211W
        int sa_query_count; /* number of pending SA Query requests;
index dbe832c2eaaf5f6e57bfd105423a6eb7fd788c8c..e6ffc1030f7b52edb478f51057071d953bff5f89 100644 (file)
@@ -1280,6 +1280,8 @@ struct ieee80211_ampe_ie {
 #define CHANWIDTH_160MHZ       2
 #define CHANWIDTH_80P80MHZ     3
 
+#define HE_NSS_MAX_STREAMS                         8
+
 #define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
                                * 00:50:F2 */
 #define WPA_IE_VENDOR_TYPE 0x0050f201