summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIlan Peer <ilan.peer@intel.com>2022-04-27 18:02:10 +0300
committerJohannes Berg <johannes.berg@intel.com>2022-07-15 12:43:14 +0300
commit1e0b3b0b6cb5e04bcb25fbe4164180d64e3ace07 (patch)
treede88c552833b9e318e7224e38ca0477cbe2da8d8
parent28977e790b5d0e6d37db6e659cfbcde9d24ae718 (diff)
downloadlinux-1e0b3b0b6cb5e04bcb25fbe4164180d64e3ace07.tar.xz
wifi: mac80211: Align with Draft P802.11be_D1.5
Align the mac80211 implementation with P802.11be_D1.5. Signed-off-by: Ilan Peer <ilan.peer@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--include/linux/ieee80211.h52
-rw-r--r--net/mac80211/ieee80211_i.h4
-rw-r--r--net/mac80211/mlme.c32
-rw-r--r--net/mac80211/util.c87
4 files changed, 128 insertions, 47 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index f386f9ed41f3..e75c73ca11ec 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -2046,25 +2046,38 @@ struct ieee80211_eht_cap_elem {
u8 optional[];
} __packed;
+#define IEEE80211_EHT_OPER_INFO_PRESENT 0x1
+#define IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT 0x2
+
/**
* struct ieee80211_eht_operation - eht operation element
*
* This structure is the "EHT Operation Element" fields as
- * described in P802.11be_D1.4 section 9.4.2.311
+ * described in P802.11be_D1.5 section 9.4.2.311
*
- * FIXME: The spec is unclear how big the fields are, and doesn't
- * indicate the "Disabled Subchannel Bitmap Present" in the
- * structure (Figure 9-1002a) at all ...
+ * @params: EHT operation element parameters. See &IEEE80211_EHT_OPER_*
+ * @optional: optional parts
*/
struct ieee80211_eht_operation {
- u8 chan_width;
- u8 ccfs;
- u8 present_bm;
-
- u8 disable_subchannel_bitmap[];
+ u8 params;
+ u8 optional[];
} __packed;
-#define IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT 0x1
+/**
+ * struct ieee80211_eht_operation_info - eht operation information
+ *
+ * @control: EHT operation information control.
+ * @ccfs0: defines a channel center frequency for a 20, 40, 80, 160, or 320 MHz
+ * EHT BSS.
+ * @ccfs1: defines a channel center frequency for a 160 or 320 MHz EHT BSS.
+ * @optional: optional parts
+ */
+struct ieee80211_eht_operation_info {
+ u8 control;
+ u8 ccfs0;
+ u8 ccfs1;
+ u8 optional[];
+} __packed;
/* 802.11ac VHT Capabilities */
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 0x00000000
@@ -2773,10 +2786,12 @@ ieee80211_he_spr_size(const u8 *he_spr_ie)
#define IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE2 0x08
#define IEEE80211_EHT_MAC_CAP0_RESTRICTED_TWT 0x10
#define IEEE80211_EHT_MAC_CAP0_SCS_TRAFFIC_DESC 0x20
-#define IEEE80211_EHT_MAC_CAP0_MAX_AMPDU_LEN_MASK 0xc0
-#define IEEE80211_EHT_MAC_CAP0_MAX_AMPDU_LEN_3895 0
-#define IEEE80211_EHT_MAC_CAP0_MAX_AMPDU_LEN_7991 1
-#define IEEE80211_EHT_MAC_CAP0_MAX_AMPDU_LEN_11454 2
+#define IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK 0xc0
+#define IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_3895 0
+#define IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991 1
+#define IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_11454 2
+
+#define IEEE80211_EHT_MAC_CAP1_MAX_AMPDU_LEN_MASK 0x01
/* EHT PHY capabilities as defined in P802.11be_D1.4 section 9.4.2.313.3 */
#define IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ 0x02
@@ -2949,8 +2964,13 @@ ieee80211_eht_oper_size_ok(const u8 *data, u8 len)
if (len < needed)
return false;
- if (elem->present_bm & IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT)
- needed += 2;
+ if (elem->params & IEEE80211_EHT_OPER_INFO_PRESENT) {
+ needed += 3;
+
+ if (elem->params &
+ IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT)
+ needed += 2;
+ }
return len >= needed;
}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index f6791b47f78f..aa1e438ee61e 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2326,6 +2326,10 @@ bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw, u32 vht_cap_info,
const struct ieee80211_vht_operation *oper,
const struct ieee80211_ht_operation *htop,
struct cfg80211_chan_def *chandef);
+void ieee80211_chandef_eht_oper(struct ieee80211_sub_if_data *sdata,
+ const struct ieee80211_eht_operation *eht_oper,
+ bool support_160, bool support_320,
+ struct cfg80211_chan_def *chandef);
bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
const struct ieee80211_he_operation *he_oper,
const struct ieee80211_eht_operation *eht_oper,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index e5c058db451d..39f13f3c29bf 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -303,6 +303,38 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
*chandef = vht_chandef;
+ /*
+ * handle the case that the EHT operation indicates that it holds EHT
+ * operation information (in case that the channel width differs from
+ * the channel width reported in HT/VHT/HE).
+ */
+ if (eht_oper && (eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT)) {
+ struct cfg80211_chan_def eht_chandef = *chandef;
+
+ ieee80211_chandef_eht_oper(sdata, eht_oper,
+ eht_chandef.width ==
+ NL80211_CHAN_WIDTH_160,
+ false, &eht_chandef);
+
+ if (!cfg80211_chandef_valid(&eht_chandef)) {
+ if (!(ifmgd->flags & IEEE80211_STA_DISABLE_EHT))
+ sdata_info(sdata,
+ "AP EHT information is invalid, disabling EHT\n");
+ ret = IEEE80211_STA_DISABLE_EHT;
+ goto out;
+ }
+
+ if (!cfg80211_chandef_compatible(chandef, &eht_chandef)) {
+ if (!(ifmgd->flags & IEEE80211_STA_DISABLE_EHT))
+ sdata_info(sdata,
+ "AP EHT information is incompatible, disabling EHT\n");
+ ret = IEEE80211_STA_DISABLE_EHT;
+ goto out;
+ }
+
+ *chandef = eht_chandef;
+ }
+
ret = 0;
out:
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 3e29ef1f81ad..924192238042 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -3459,6 +3459,58 @@ bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw, u32 vht_cap_info,
return true;
}
+void ieee80211_chandef_eht_oper(struct ieee80211_sub_if_data *sdata,
+ const struct ieee80211_eht_operation *eht_oper,
+ bool support_160, bool support_320,
+ struct cfg80211_chan_def *chandef)
+{
+ struct ieee80211_eht_operation_info *info = (void *)eht_oper->optional;
+
+ chandef->center_freq1 =
+ ieee80211_channel_to_frequency(info->ccfs0,
+ chandef->chan->band);
+
+ switch (u8_get_bits(info->control,
+ IEEE80211_EHT_OPER_CHAN_WIDTH)) {
+ case IEEE80211_EHT_OPER_CHAN_WIDTH_20MHZ:
+ chandef->width = NL80211_CHAN_WIDTH_20;
+ break;
+ case IEEE80211_EHT_OPER_CHAN_WIDTH_40MHZ:
+ chandef->width = NL80211_CHAN_WIDTH_40;
+ break;
+ case IEEE80211_EHT_OPER_CHAN_WIDTH_80MHZ:
+ chandef->width = NL80211_CHAN_WIDTH_80;
+ break;
+ case IEEE80211_EHT_OPER_CHAN_WIDTH_160MHZ:
+ if (support_160) {
+ chandef->width = NL80211_CHAN_WIDTH_160;
+ chandef->center_freq1 =
+ ieee80211_channel_to_frequency(info->ccfs1,
+ chandef->chan->band);
+ } else {
+ chandef->width = NL80211_CHAN_WIDTH_80;
+ }
+ break;
+ case IEEE80211_EHT_OPER_CHAN_WIDTH_320MHZ:
+ if (support_320) {
+ chandef->width = NL80211_CHAN_WIDTH_320;
+ chandef->center_freq1 =
+ ieee80211_channel_to_frequency(info->ccfs1,
+ chandef->chan->band);
+ } else if (support_160) {
+ chandef->width = NL80211_CHAN_WIDTH_160;
+ } else {
+ chandef->width = NL80211_CHAN_WIDTH_80;
+
+ if (chandef->center_freq1 > chandef->chan->center_freq)
+ chandef->center_freq1 -= 40;
+ else
+ chandef->center_freq1 += 40;
+ }
+ break;
+ }
+}
+
bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
const struct ieee80211_he_operation *he_oper,
const struct ieee80211_eht_operation *eht_oper,
@@ -3539,7 +3591,8 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
break;
}
- if (!eht_oper) {
+ if (!eht_oper ||
+ !(eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT)) {
switch (u8_get_bits(he_6ghz_oper->control,
IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH)) {
case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_20MHZ:
@@ -3583,36 +3636,8 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
support_320 =
eht_phy_cap & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ;
- switch (u8_get_bits(eht_oper->chan_width,
- IEEE80211_EHT_OPER_CHAN_WIDTH)) {
- case IEEE80211_EHT_OPER_CHAN_WIDTH_20MHZ:
- he_chandef.width = NL80211_CHAN_WIDTH_20;
- break;
- case IEEE80211_EHT_OPER_CHAN_WIDTH_40MHZ:
- he_chandef.width = NL80211_CHAN_WIDTH_40;
- break;
- case IEEE80211_EHT_OPER_CHAN_WIDTH_80MHZ:
- he_chandef.width = NL80211_CHAN_WIDTH_80;
- break;
- case IEEE80211_EHT_OPER_CHAN_WIDTH_160MHZ:
- if (support_160)
- he_chandef.width = NL80211_CHAN_WIDTH_160;
- else
- he_chandef.width = NL80211_CHAN_WIDTH_80;
- break;
- case IEEE80211_EHT_OPER_CHAN_WIDTH_320MHZ:
- if (support_320)
- he_chandef.width = NL80211_CHAN_WIDTH_320;
- else if (support_160)
- he_chandef.width = NL80211_CHAN_WIDTH_160;
- else
- he_chandef.width = NL80211_CHAN_WIDTH_80;
- break;
- }
-
- he_chandef.center_freq1 =
- ieee80211_channel_to_frequency(eht_oper->ccfs,
- NL80211_BAND_6GHZ);
+ ieee80211_chandef_eht_oper(sdata, eht_oper, support_160,
+ support_320, &he_chandef);
}
if (!cfg80211_chandef_valid(&he_chandef)) {