]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
nl80211: Add driver multi iftype HE capability parsing
authorSven Eckelmann <seckelmann@datto.com>
Fri, 14 Jun 2019 14:49:20 +0000 (16:49 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 23 Jun 2019 15:03:51 +0000 (18:03 +0300)
The HE capabilities are no longer per PHY but per iftype on this
specific PHY. It is therefore no longer enough to just parse the AP
capabilities.

The he_capabilities are now duplicated to store all information for
IEEE80211_MODE_* which hostap cares about. The nl80211 driver fills in
this information when the iftype supports HE. The rest of the code still
only uses the IEEE80211_HE_AP portion but can be extended later to also
use other HE capabilities.

Signed-off-by: Sven Eckelmann <seckelmann@datto.com>
src/ap/ap_drv_ops.c
src/ap/beacon.c
src/ap/dfs.c
src/ap/hostapd.c
src/ap/ieee802_11.c
src/ap/ieee802_11.h
src/ap/ieee802_11_he.c
src/drivers/driver.h
src/drivers/driver_nl80211_capa.c

index 7c9dcf9b9a0bb06ac76d41bccbd8af54670123dd..c0ededabe9794e0cd104e841458c0fa8067243b5 100644 (file)
@@ -546,14 +546,15 @@ int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
                     int center_segment0, int center_segment1)
 {
        struct hostapd_freq_params data;
+       struct hostapd_hw_modes *cmode = hapd->iface->current_mode;
 
        if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
                                    vht_enabled, he_enabled, sec_channel_offset,
                                    oper_chwidth,
                                    center_segment0, center_segment1,
-                                   hapd->iface->current_mode ?
-                                   hapd->iface->current_mode->vht_capab : 0,
-                                   &hapd->iface->current_mode->he_capab))
+                                   cmode ? cmode->vht_capab : 0,
+                                   cmode ?
+                                   &cmode->he_capab[IEEE80211_MODE_AP] : NULL))
                return -1;
 
        if (hapd->driver == NULL)
@@ -798,8 +799,9 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
        struct hostapd_data *hapd = iface->bss[0];
        struct hostapd_freq_params data;
        int res;
+       struct hostapd_hw_modes *cmode = iface->current_mode;
 
-       if (!hapd->driver || !hapd->driver->start_dfs_cac)
+       if (!hapd->driver || !hapd->driver->start_dfs_cac || !cmode)
                return 0;
 
        if (!iface->conf->ieee80211h) {
@@ -812,8 +814,8 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
                                    vht_enabled, he_enabled, sec_channel_offset,
                                    oper_chwidth, center_segment0,
                                    center_segment1,
-                                   iface->current_mode->vht_capab,
-                                   &iface->current_mode->he_capab)) {
+                                   cmode->vht_capab,
+                                   &cmode->he_capab[IEEE80211_MODE_AP])) {
                wpa_printf(MSG_ERROR, "Can't set freq params");
                return -1;
        }
index 1838c1c843093600df68e11548de9c00513e3160..a51b94960bed5da2243458baad4a4b7cedb86236 100644 (file)
@@ -510,7 +510,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
 
 #ifdef CONFIG_IEEE80211AX
        if (hapd->iconf->ieee80211ax) {
-               pos = hostapd_eid_he_capab(hapd, pos);
+               pos = hostapd_eid_he_capab(hapd, pos, IEEE80211_MODE_AP);
                pos = hostapd_eid_he_operation(hapd, pos);
                pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos);
                pos = hostapd_eid_spatial_reuse(hapd, pos);
@@ -1226,7 +1226,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 
 #ifdef CONFIG_IEEE80211AX
        if (hapd->iconf->ieee80211ax) {
-               tailpos = hostapd_eid_he_capab(hapd, tailpos);
+               tailpos = hostapd_eid_he_capab(hapd, tailpos,
+                                              IEEE80211_MODE_AP);
                tailpos = hostapd_eid_he_operation(hapd, tailpos);
                tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos);
                tailpos = hostapd_eid_spatial_reuse(hapd, tailpos);
@@ -1398,6 +1399,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;
 
@@ -1421,7 +1423,7 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
        params.reenable = hapd->reenable_beacon;
        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->ieee80211ax,
@@ -1429,8 +1431,8 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
                                    hostapd_get_oper_chwidth(iconf),
                                    hostapd_get_oper_centr_freq_seg0_idx(iconf),
                                    hostapd_get_oper_centr_freq_seg1_idx(iconf),
-                                   iface->current_mode->vht_capab,
-                                   &iface->current_mode->he_capab) == 0)
+                                   cmode->vht_capab,
+                                   &cmode->he_capab[IEEE80211_MODE_AP]) == 0)
                params.freq = &freq;
 
        res = hostapd_drv_set_ap(hapd, &params);
index a3c9aa26f4a39b7cccca892d7d7e900f7ca24d5b..ac23c2b1bc9fa356b81aceb9608a22c3af8125e4 100644 (file)
@@ -888,6 +888,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
        struct csa_settings csa_settings;
        unsigned int i;
        int err = 1;
+       struct hostapd_hw_modes *cmode = iface->current_mode;
 
        wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
                   __func__, iface->cac_started ? "yes" : "no",
@@ -966,8 +967,8 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
                                      hostapd_get_oper_chwidth(iface->conf),
                                      oper_centr_freq_seg0_idx,
                                      oper_centr_freq_seg1_idx,
-                                     iface->current_mode->vht_capab,
-                                     &iface->current_mode->he_capab);
+                                     cmode->vht_capab,
+                                     &cmode->he_capab[IEEE80211_MODE_AP]);
 
        if (err) {
                wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
index c83fb2a4649c29ca942f29f254feb7b46c7d5157..cc75a7765a80f01e35dad7dd00ea34ad47d7bdad 100644 (file)
@@ -3241,7 +3241,8 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
                                    hostapd_get_oper_centr_freq_seg0_idx(conf),
                                    hostapd_get_oper_centr_freq_seg1_idx(conf),
                                    conf->vht_capab,
-                                   mode ? &mode->he_capab : NULL))
+                                   mode ? &mode->he_capab[IEEE80211_MODE_AP] :
+                                   NULL))
                return -1;
 
        switch (params->bandwidth) {
index 4aef59e88bc2187036a4f894ebc6835f58071348..c85a28db44b7e2ffe8a1a21b5477572ab32bc255 100644 (file)
@@ -2990,7 +2990,8 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
 #endif /* CONFIG_IEEE80211AC */
 #ifdef CONFIG_IEEE80211AX
        if (hapd->iconf->ieee80211ax) {
-               resp = copy_sta_he_capab(hapd, sta, elems.he_capabilities,
+               resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP,
+                                        elems.he_capabilities,
                                         elems.he_capabilities_len);
                if (resp != WLAN_STATUS_SUCCESS)
                        return resp;
@@ -3583,7 +3584,7 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
 
 #ifdef CONFIG_IEEE80211AX
        if (hapd->iconf->ieee80211ax) {
-               p = hostapd_eid_he_capab(hapd, p);
+               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);
index 8822a1785c775be8a49fb95357b1895c3a2eddf1..b8453c992a9c8ce99328e3f7929baa39bd033808 100644 (file)
@@ -18,6 +18,7 @@ struct ieee80211_vht_capabilities;
 struct ieee80211_mgmt;
 struct vlan_description;
 struct hostapd_sta_wpa_psk_short;
+enum ieee80211_op_mode;
 
 int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
                    struct hostapd_frame_info *fi);
@@ -57,7 +58,8 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid);
-u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
+                         enum ieee80211_op_mode opmode);
 u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid);
@@ -91,7 +93,8 @@ u16 copy_sta_vht_oper(struct hostapd_data *hapd, struct sta_info *sta,
 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);
+                     enum ieee80211_op_mode opmode, 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 d3d3c1db3e3940490ed2277d9e0aacb3d4a0dc48..a51f3fcb0eae4e0fcd7c765c22ae53e9b55b69ba 100644 (file)
@@ -44,7 +44,8 @@ static u8 ieee80211_he_ppet_size(u8 ppe_thres_hdr, const u8 *phy_cap_info)
 }
 
 
-u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid)
+u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
+                         enum ieee80211_op_mode opmode)
 {
        struct ieee80211_he_capabilities *cap;
        struct hostapd_hw_modes *mode = hapd->iface->current_mode;
@@ -56,8 +57,8 @@ u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid)
                return eid;
 
        ie_size = sizeof(struct ieee80211_he_capabilities);
-       ppet_size = ieee80211_he_ppet_size(mode->he_capab.ppet[0],
-                                          mode->he_capab.phy_cap);
+       ppet_size = ieee80211_he_ppet_size(mode->he_capab[opmode].ppet[0],
+                                          mode->he_capab[opmode].phy_cap);
 
        switch (hapd->iface->conf->he_oper_chwidth) {
        case CHANWIDTH_80P80MHZ:
@@ -86,14 +87,14 @@ u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid)
        cap = (struct ieee80211_he_capabilities *) pos;
        os_memset(cap, 0, sizeof(*cap));
 
-       os_memcpy(cap->he_mac_capab_info, mode->he_capab.mac_cap,
+       os_memcpy(cap->he_mac_capab_info, mode->he_capab[opmode].mac_cap,
                  HE_MAX_MAC_CAPAB_SIZE);
-       os_memcpy(cap->he_phy_capab_info, mode->he_capab.phy_cap,
+       os_memcpy(cap->he_phy_capab_info, mode->he_capab[opmode].phy_cap,
                  HE_MAX_PHY_CAPAB_SIZE);
-       os_memcpy(cap->optional, mode->he_capab.mcs, mcs_nss_size);
+       os_memcpy(cap->optional, mode->he_capab[opmode].mcs, mcs_nss_size);
        if (ppet_size)
-               os_memcpy(&cap->optional[mcs_nss_size], mode->he_capab.ppet,
-                         ppet_size);
+               os_memcpy(&cap->optional[mcs_nss_size],
+                         mode->he_capab[opmode].ppet,  ppet_size);
 
        if (hapd->iface->conf->he_phy_capab.he_su_beamformer)
                cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX] |=
@@ -260,7 +261,8 @@ void hostapd_get_he_capab(struct hostapd_data *hapd,
 }
 
 
-static int check_valid_he_mcs(struct hostapd_data *hapd, const u8 *sta_he_capab)
+static int check_valid_he_mcs(struct hostapd_data *hapd, const u8 *sta_he_capab,
+                             enum ieee80211_op_mode opmode)
 {
        u16 sta_rx_mcs_set, ap_tx_mcs_set;
        u8 mcs_count = 0;
@@ -269,7 +271,7 @@ static int check_valid_he_mcs(struct hostapd_data *hapd, const u8 *sta_he_capab)
 
        if (!hapd->iface->current_mode)
                return 1;
-       ap_mcs_set = (u16 *) hapd->iface->current_mode->he_capab.mcs;
+       ap_mcs_set = (u16 *) hapd->iface->current_mode->he_capab[opmode].mcs;
        sta_mcs_set = (u16 *) ((const struct ieee80211_he_capabilities *)
                               sta_he_capab)->optional;
 
@@ -318,10 +320,11 @@ static int check_valid_he_mcs(struct hostapd_data *hapd, const u8 *sta_he_capab)
 
 
 u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
-                     const u8 *he_capab, size_t he_capab_len)
+                     enum ieee80211_op_mode opmode, const u8 *he_capab,
+                     size_t he_capab_len)
 {
        if (!he_capab || !hapd->iconf->ieee80211ax ||
-           !check_valid_he_mcs(hapd, he_capab) ||
+           !check_valid_he_mcs(hapd, he_capab, opmode) ||
            he_capab_len > sizeof(struct ieee80211_he_capabilities)) {
                sta->flags &= ~WLAN_STA_HE;
                os_free(sta->he_capab);
index d0f449f72472027b8b01cb3921705a5a5750fd14..ee11387e9bfea163fd25bb26eceb5e8dba4c64d8 100644 (file)
@@ -200,6 +200,17 @@ struct he_capabilities {
 #define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
 #define HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN BIT(1)
 
+
+enum ieee80211_op_mode {
+       IEEE80211_MODE_INFRA = 0,
+       IEEE80211_MODE_IBSS = 1,
+       IEEE80211_MODE_AP = 2,
+       IEEE80211_MODE_MESH = 5,
+
+       /* only add new entries before IEEE80211_MODE_NUM */
+       IEEE80211_MODE_NUM
+};
+
 /**
  * struct hostapd_hw_modes - Supported hardware mode information
  */
@@ -259,15 +270,10 @@ struct hostapd_hw_modes {
        /**
         * he_capab - HE (IEEE 802.11ax) capabilities
         */
-       struct he_capabilities he_capab;
+       struct he_capabilities he_capab[IEEE80211_MODE_NUM];
 };
 
 
-#define IEEE80211_MODE_INFRA   0
-#define IEEE80211_MODE_IBSS    1
-#define IEEE80211_MODE_AP      2
-#define IEEE80211_MODE_MESH    5
-
 #define IEEE80211_CAP_ESS      0x0001
 #define IEEE80211_CAP_IBSS     0x0002
 #define IEEE80211_CAP_PRIVACY  0x0010
index ab9b19f393b3d85299db967f0edbcb36b95613d2..8318b10ab9e7846e7f36996a5a9b9865ec671238 100644 (file)
@@ -1551,26 +1551,32 @@ static int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb)
 }
 
 
-static int phy_info_iftype(struct hostapd_hw_modes *mode,
-                          struct nlattr *nl_iftype)
+static void phy_info_iftype_copy(struct he_capabilities *he_capab,
+                                enum ieee80211_op_mode opmode,
+                                struct nlattr **tb, struct nlattr **tb_flags)
 {
-       struct nlattr *tb[NL80211_BAND_IFTYPE_ATTR_MAX + 1];
-       struct he_capabilities *he_capab = &mode->he_capab;
-       struct nlattr *tb_flags[NL80211_IFTYPE_MAX + 1];
+       enum nl80211_iftype iftype;
        size_t len;
 
-       nla_parse(tb, NL80211_BAND_IFTYPE_ATTR_MAX,
-                 nla_data(nl_iftype), nla_len(nl_iftype), NULL);
-
-       if (!tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES])
-               return NL_STOP;
-
-       if (nla_parse_nested(tb_flags, NL80211_IFTYPE_MAX,
-                            tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES], NULL))
-               return NL_STOP;
+       switch (opmode) {
+       case IEEE80211_MODE_INFRA:
+               iftype = NL80211_IFTYPE_STATION;
+               break;
+       case IEEE80211_MODE_IBSS:
+               iftype = NL80211_IFTYPE_ADHOC;
+               break;
+       case IEEE80211_MODE_AP:
+               iftype = NL80211_IFTYPE_AP;
+               break;
+       case IEEE80211_MODE_MESH:
+               iftype = NL80211_IFTYPE_MESH_POINT;
+               break;
+       default:
+               return;
+       }
 
-       if (!nla_get_flag(tb_flags[NL80211_IFTYPE_AP]))
-               return NL_OK;
+       if (!nla_get_flag(tb_flags[iftype]))
+               return;
 
        he_capab->he_supported = 1;
 
@@ -1613,6 +1619,28 @@ static int phy_info_iftype(struct hostapd_hw_modes *mode,
                          nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]),
                          len);
        }
+}
+
+
+static int phy_info_iftype(struct hostapd_hw_modes *mode,
+                          struct nlattr *nl_iftype)
+{
+       struct nlattr *tb[NL80211_BAND_IFTYPE_ATTR_MAX + 1];
+       struct nlattr *tb_flags[NL80211_IFTYPE_MAX + 1];
+       unsigned int i;
+
+       nla_parse(tb, NL80211_BAND_IFTYPE_ATTR_MAX,
+                 nla_data(nl_iftype), nla_len(nl_iftype), NULL);
+
+       if (!tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES])
+               return NL_STOP;
+
+       if (nla_parse_nested(tb_flags, NL80211_IFTYPE_MAX,
+                            tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES], NULL))
+               return NL_STOP;
+
+       for (i = 0; i < IEEE80211_MODE_NUM; i++)
+               phy_info_iftype_copy(&mode->he_capab[i], i, tb, tb_flags);
 
        return NL_OK;
 }