wifi: mac80211: Align with Draft P802.11be_D1.5
authorIlan Peer <ilan.peer@intel.com>
Wed, 27 Apr 2022 15:02:10 +0000 (18:02 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 15 Jul 2022 09:43:14 +0000 (11:43 +0200)
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>
include/linux/ieee80211.h
net/mac80211/ieee80211_i.h
net/mac80211/mlme.c
net/mac80211/util.c

index f386f9ed41f390969094f894271f1ec3a04cf9d0..e75c73ca11ec9a21feb248d9d3feb070b1c904eb 100644 (file)
@@ -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;
 }
index f6791b47f78f85390c9f7573ecdc8e91c9b5327e..aa1e438ee61ecd1b47361d859a2ad91c8bd72271 100644 (file)
@@ -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,
index e5c058db451d5e73ed6e65936d5174dcd9ab0120..39f13f3c29bf507caadcbdfffafebe105ba8d91c 100644 (file)
@@ -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:
index 3e29ef1f81ad3df3fedb52b3f6d2cb711731ecfc..924192238042f6566a72fd1cf012e4018e79cd31 100644 (file)
@@ -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)) {