wireless: fix wrong 160/80+80 MHz setting
authorShay Bar <shay.bar@celeno.com>
Wed, 26 Aug 2020 14:31:39 +0000 (17:31 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Thu, 27 Aug 2020 08:46:53 +0000 (10:46 +0200)
Fix cfg80211_chandef_usable():
consider IEEE80211_VHT_CAP_EXT_NSS_BW when verifying 160/80+80 MHz.

Based on:
"Table 9-272 — Setting of the Supported Channel Width Set subfield and Extended NSS BW
Support subfield at a STA transmitting the VHT Capabilities Information field"
From "Draft P802.11REVmd_D3.0.pdf"

Signed-off-by: Aviad Brikman <aviad.brikman@celeno.com>
Signed-off-by: Shay Bar <shay.bar@celeno.com>
Link: https://lore.kernel.org/r/20200826143139.25976-1-shay.bar@celeno.com
[reformat the code a bit and use u32_get_bits()]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/wireless/chan.c

index 90f0f82cd9ca76722e529573b4fa0ff9da2055ff..edee3a645c068047daa49868405442e597af6bc9 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/export.h>
+#include <linux/bitfield.h>
 #include <net/cfg80211.h>
 #include "core.h"
 #include "rdev-ops.h"
@@ -912,6 +913,7 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
        struct ieee80211_sta_vht_cap *vht_cap;
        struct ieee80211_edmg *edmg_cap;
        u32 width, control_freq, cap;
+       bool support_80_80 = false;
 
        if (WARN_ON(!cfg80211_chandef_valid(chandef)))
                return false;
@@ -979,9 +981,13 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
                        return false;
                break;
        case NL80211_CHAN_WIDTH_80P80:
-               cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
-               if (chandef->chan->band != NL80211_BAND_6GHZ &&
-                   cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
+               cap = vht_cap->cap;
+               support_80_80 =
+                       (cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) ||
+                       (cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ &&
+                        cap & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) ||
+                       u32_get_bits(cap, IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) > 1;
+               if (chandef->chan->band != NL80211_BAND_6GHZ && !support_80_80)
                        return false;
                /* fall through */
        case NL80211_CHAN_WIDTH_80:
@@ -1001,7 +1007,8 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
                        return false;
                cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
                if (cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ &&
-                   cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
+                   cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ &&
+                   !(vht_cap->cap & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK))
                        return false;
                break;
        default: