Commit 1e0b3b0b authored by Ilan Peer's avatar Ilan Peer Committed by Johannes Berg

wifi: mac80211: Align with Draft P802.11be_D1.5

Align the mac80211 implementation with P802.11be_D1.5.
Signed-off-by: default avatarIlan Peer <ilan.peer@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 28977e79
...@@ -2046,25 +2046,38 @@ struct ieee80211_eht_cap_elem { ...@@ -2046,25 +2046,38 @@ struct ieee80211_eht_cap_elem {
u8 optional[]; u8 optional[];
} __packed; } __packed;
#define IEEE80211_EHT_OPER_INFO_PRESENT 0x1
#define IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT 0x2
/** /**
* struct ieee80211_eht_operation - eht operation element * struct ieee80211_eht_operation - eht operation element
* *
* This structure is the "EHT Operation Element" fields as * 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 * @params: EHT operation element parameters. See &IEEE80211_EHT_OPER_*
* indicate the "Disabled Subchannel Bitmap Present" in the * @optional: optional parts
* structure (Figure 9-1002a) at all ...
*/ */
struct ieee80211_eht_operation { struct ieee80211_eht_operation {
u8 chan_width; u8 params;
u8 ccfs; u8 optional[];
u8 present_bm;
u8 disable_subchannel_bitmap[];
} __packed; } __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 */ /* 802.11ac VHT Capabilities */
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 0x00000000 #define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 0x00000000
...@@ -2773,10 +2786,12 @@ ieee80211_he_spr_size(const u8 *he_spr_ie) ...@@ -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_TRIG_TXOP_SHARING_MODE2 0x08
#define IEEE80211_EHT_MAC_CAP0_RESTRICTED_TWT 0x10 #define IEEE80211_EHT_MAC_CAP0_RESTRICTED_TWT 0x10
#define IEEE80211_EHT_MAC_CAP0_SCS_TRAFFIC_DESC 0x20 #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_MPDU_LEN_MASK 0xc0
#define IEEE80211_EHT_MAC_CAP0_MAX_AMPDU_LEN_3895 0 #define IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_3895 0
#define IEEE80211_EHT_MAC_CAP0_MAX_AMPDU_LEN_7991 1 #define IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991 1
#define IEEE80211_EHT_MAC_CAP0_MAX_AMPDU_LEN_11454 2 #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 */ /* 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 #define IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ 0x02
...@@ -2949,8 +2964,13 @@ ieee80211_eht_oper_size_ok(const u8 *data, u8 len) ...@@ -2949,8 +2964,13 @@ ieee80211_eht_oper_size_ok(const u8 *data, u8 len)
if (len < needed) if (len < needed)
return false; return false;
if (elem->present_bm & IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT) if (elem->params & IEEE80211_EHT_OPER_INFO_PRESENT) {
needed += 3;
if (elem->params &
IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT)
needed += 2; needed += 2;
}
return len >= needed; return len >= needed;
} }
......
...@@ -2326,6 +2326,10 @@ bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw, u32 vht_cap_info, ...@@ -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_vht_operation *oper,
const struct ieee80211_ht_operation *htop, const struct ieee80211_ht_operation *htop,
struct cfg80211_chan_def *chandef); 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, bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
const struct ieee80211_he_operation *he_oper, const struct ieee80211_he_operation *he_oper,
const struct ieee80211_eht_operation *eht_oper, const struct ieee80211_eht_operation *eht_oper,
......
...@@ -303,6 +303,38 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, ...@@ -303,6 +303,38 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
*chandef = vht_chandef; *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; ret = 0;
out: out:
......
...@@ -3459,6 +3459,58 @@ bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw, u32 vht_cap_info, ...@@ -3459,6 +3459,58 @@ bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw, u32 vht_cap_info,
return true; 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, bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
const struct ieee80211_he_operation *he_oper, const struct ieee80211_he_operation *he_oper,
const struct ieee80211_eht_operation *eht_oper, const struct ieee80211_eht_operation *eht_oper,
...@@ -3539,7 +3591,8 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata, ...@@ -3539,7 +3591,8 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
break; break;
} }
if (!eht_oper) { if (!eht_oper ||
!(eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT)) {
switch (u8_get_bits(he_6ghz_oper->control, switch (u8_get_bits(he_6ghz_oper->control,
IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH)) { IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH)) {
case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_20MHZ: case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_20MHZ:
...@@ -3583,36 +3636,8 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata, ...@@ -3583,36 +3636,8 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
support_320 = support_320 =
eht_phy_cap & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ; eht_phy_cap & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ;
switch (u8_get_bits(eht_oper->chan_width, ieee80211_chandef_eht_oper(sdata, eht_oper, support_160,
IEEE80211_EHT_OPER_CHAN_WIDTH)) { support_320, &he_chandef);
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);
} }
if (!cfg80211_chandef_valid(&he_chandef)) { if (!cfg80211_chandef_valid(&he_chandef)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment