]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
mac80211: limit bandwidth in HE capabilities
authorJohannes Berg <johannes.berg@intel.com>
Wed, 2 Feb 2022 08:49:34 +0000 (10:49 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 8 Apr 2022 11:58:03 +0000 (13:58 +0200)
[ Upstream commit 1f2c104448477512fcf7296df54bfbc3a6f9a765 ]

If we're limiting bandwidth for some reason such as regulatory
restrictions, then advertise that limitation just like we do
for VHT today, so the AP is aware we cannot use the higher BW
it might be using.

Fixes: 41cbb0f5a295 ("mac80211: add support for HE")
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Link: https://lore.kernel.org/r/iwlwifi.20220202104617.70c8e3e7ee76.If317630de69ff1146bec7d47f5b83038695eb71d@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
net/mac80211/ieee80211_i.h
net/mac80211/mesh.c
net/mac80211/mlme.c
net/mac80211/util.c

index e87bccaab561f449e0bc9770a6ba307a4aa94ca6..95aaf00c876c3e7741e3199e2ceb667d67a5654d 100644 (file)
@@ -2380,7 +2380,7 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
 u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
                                const struct cfg80211_chan_def *chandef);
 u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata, u8 iftype);
-u8 *ieee80211_ie_build_he_cap(u8 *pos,
+u8 *ieee80211_ie_build_he_cap(u32 disable_flags, u8 *pos,
                              const struct ieee80211_sta_he_cap *he_cap,
                              u8 *end);
 void ieee80211_ie_build_he_6ghz_cap(struct ieee80211_sub_if_data *sdata,
index 15ac08d111ea110a57a117d65db7d4fd19773893..6847fdf934392ebbdff323cae065aca5b557002c 100644 (file)
@@ -580,7 +580,7 @@ int mesh_add_he_cap_ie(struct ieee80211_sub_if_data *sdata,
                return -ENOMEM;
 
        pos = skb_put(skb, ie_len);
-       ieee80211_ie_build_he_cap(pos, he_cap, pos + ie_len);
+       ieee80211_ie_build_he_cap(0, pos, he_cap, pos + ie_len);
 
        return 0;
 }
index 744842c4513b1f6d488b3eb5ac728e76c774ff80..c4d3e2da73f23b69b5348856f9ae2611207dfcc7 100644 (file)
@@ -636,7 +636,7 @@ static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata,
                                struct sk_buff *skb,
                                struct ieee80211_supported_band *sband)
 {
-       u8 *pos;
+       u8 *pos, *pre_he_pos;
        const struct ieee80211_sta_he_cap *he_cap = NULL;
        struct ieee80211_chanctx_conf *chanctx_conf;
        u8 he_cap_size;
@@ -653,16 +653,21 @@ static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata,
 
        he_cap = ieee80211_get_he_iftype_cap(sband,
                                             ieee80211_vif_type_p2p(&sdata->vif));
-       if (!he_cap || !reg_cap)
+       if (!he_cap || !chanctx_conf || !reg_cap)
                return;
 
+       /* get a max size estimate */
        he_cap_size =
                2 + 1 + sizeof(he_cap->he_cap_elem) +
                ieee80211_he_mcs_nss_size(&he_cap->he_cap_elem) +
                ieee80211_he_ppe_size(he_cap->ppe_thres[0],
                                      he_cap->he_cap_elem.phy_cap_info);
        pos = skb_put(skb, he_cap_size);
-       ieee80211_ie_build_he_cap(pos, he_cap, pos + he_cap_size);
+       pre_he_pos = pos;
+       pos = ieee80211_ie_build_he_cap(sdata->u.mgd.flags,
+                                       pos, he_cap, pos + he_cap_size);
+       /* trim excess if any */
+       skb_trim(skb, skb->len - (pre_he_pos + he_cap_size - pos));
 
        ieee80211_ie_build_he_6ghz_cap(sdata, skb);
 }
index f71b042a5c8bb8b0a878eb26847ce57daa5c0b44..342c2bfe27091d2e93711e1f0230cacb0269b6b2 100644 (file)
@@ -1974,7 +1974,7 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata,
        if (he_cap &&
            cfg80211_any_usable_channels(local->hw.wiphy, BIT(sband->band),
                                         IEEE80211_CHAN_NO_HE)) {
-               pos = ieee80211_ie_build_he_cap(pos, he_cap, end);
+               pos = ieee80211_ie_build_he_cap(0, pos, he_cap, end);
                if (!pos)
                        goto out_err;
        }
@@ -2918,10 +2918,11 @@ u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata, u8 iftype)
                                     he_cap->he_cap_elem.phy_cap_info);
 }
 
-u8 *ieee80211_ie_build_he_cap(u8 *pos,
+u8 *ieee80211_ie_build_he_cap(u32 disable_flags, u8 *pos,
                              const struct ieee80211_sta_he_cap *he_cap,
                              u8 *end)
 {
+       struct ieee80211_he_cap_elem elem;
        u8 n;
        u8 ie_len;
        u8 *orig_pos = pos;
@@ -2934,7 +2935,23 @@ u8 *ieee80211_ie_build_he_cap(u8 *pos,
        if (!he_cap)
                return orig_pos;
 
-       n = ieee80211_he_mcs_nss_size(&he_cap->he_cap_elem);
+       /* modify on stack first to calculate 'n' and 'ie_len' correctly */
+       elem = he_cap->he_cap_elem;
+
+       if (disable_flags & IEEE80211_STA_DISABLE_40MHZ)
+               elem.phy_cap_info[0] &=
+                       ~(IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
+                         IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G);
+
+       if (disable_flags & IEEE80211_STA_DISABLE_160MHZ)
+               elem.phy_cap_info[0] &=
+                       ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
+
+       if (disable_flags & IEEE80211_STA_DISABLE_80P80MHZ)
+               elem.phy_cap_info[0] &=
+                       ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G;
+
+       n = ieee80211_he_mcs_nss_size(&elem);
        ie_len = 2 + 1 +
                 sizeof(he_cap->he_cap_elem) + n +
                 ieee80211_he_ppe_size(he_cap->ppe_thres[0],
@@ -2948,8 +2965,8 @@ u8 *ieee80211_ie_build_he_cap(u8 *pos,
        *pos++ = WLAN_EID_EXT_HE_CAPABILITY;
 
        /* Fixed data */
-       memcpy(pos, &he_cap->he_cap_elem, sizeof(he_cap->he_cap_elem));
-       pos += sizeof(he_cap->he_cap_elem);
+       memcpy(pos, &elem, sizeof(elem));
+       pos += sizeof(elem);
 
        memcpy(pos, &he_cap->he_mcs_nss_supp, n);
        pos += n;