Commit b3239498 authored by Johannes Berg's avatar Johannes Berg

wifi: mac80211: use bandwidth indication element for CSA

In CSA, parse the (EHT) bandwidth indication element and
use it (in fact prefer it if present).
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarGregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230920211508.43ef01920556.If4f24a61cd634ab1e50eba43899b9e992bf25602@changeidSigned-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent bb55441c
...@@ -3139,6 +3139,28 @@ ieee80211_eht_oper_size_ok(const u8 *data, u8 len) ...@@ -3139,6 +3139,28 @@ ieee80211_eht_oper_size_ok(const u8 *data, u8 len)
return len >= needed; return len >= needed;
} }
#define IEEE80211_BW_IND_DIS_SUBCH_PRESENT BIT(1)
struct ieee80211_bandwidth_indication {
u8 params;
struct ieee80211_eht_operation_info info;
} __packed;
static inline bool
ieee80211_bandwidth_indication_size_ok(const u8 *data, u8 len)
{
const struct ieee80211_bandwidth_indication *bwi = (const void *)data;
if (len < sizeof(*bwi))
return false;
if (bwi->params & IEEE80211_BW_IND_DIS_SUBCH_PRESENT &&
len < sizeof(*bwi) + 2)
return false;
return true;
}
#define LISTEN_INT_USF GENMASK(15, 14) #define LISTEN_INT_USF GENMASK(15, 14)
#define LISTEN_INT_UI GENMASK(13, 0) #define LISTEN_INT_UI GENMASK(13, 0)
...@@ -3596,6 +3618,7 @@ enum ieee80211_eid_ext { ...@@ -3596,6 +3618,7 @@ enum ieee80211_eid_ext {
WLAN_EID_EXT_EHT_OPERATION = 106, WLAN_EID_EXT_EHT_OPERATION = 106,
WLAN_EID_EXT_EHT_MULTI_LINK = 107, WLAN_EID_EXT_EHT_MULTI_LINK = 107,
WLAN_EID_EXT_EHT_CAPABILITY = 108, WLAN_EID_EXT_EHT_CAPABILITY = 108,
WLAN_EID_EXT_BANDWIDTH_INDICATION = 135,
}; };
/* Action category code */ /* Action category code */
......
...@@ -1677,6 +1677,7 @@ struct ieee802_11_elems { ...@@ -1677,6 +1677,7 @@ struct ieee802_11_elems {
const struct ieee80211_eht_operation *eht_operation; const struct ieee80211_eht_operation *eht_operation;
const struct ieee80211_multi_link_elem *ml_basic; const struct ieee80211_multi_link_elem *ml_basic;
const struct ieee80211_multi_link_elem *ml_reconf; const struct ieee80211_multi_link_elem *ml_reconf;
const struct ieee80211_bandwidth_indication *bandwidth_indication;
/* length of them, respectively */ /* length of them, respectively */
u8 ext_capab_len; u8 ext_capab_len;
...@@ -2463,7 +2464,7 @@ bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw, u32 vht_cap_info, ...@@ -2463,7 +2464,7 @@ 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(const struct ieee80211_eht_operation *eht_oper, void ieee80211_chandef_eht_oper(const struct ieee80211_eht_operation_info *info,
bool support_160, bool support_320, bool support_160, bool support_320,
struct cfg80211_chan_def *chandef); 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,
......
...@@ -109,7 +109,8 @@ ieee80211_extract_dis_subch_bmap(const struct ieee80211_eht_operation *eht_oper, ...@@ -109,7 +109,8 @@ ieee80211_extract_dis_subch_bmap(const struct ieee80211_eht_operation *eht_oper,
return 0; return 0;
/* set 160/320 supported to get the full AP definition */ /* set 160/320 supported to get the full AP definition */
ieee80211_chandef_eht_oper(eht_oper, true, true, &ap_chandef); ieee80211_chandef_eht_oper((const void *)eht_oper->optional,
true, true, &ap_chandef);
ap_center_freq = ap_chandef.center_freq1; ap_center_freq = ap_chandef.center_freq1;
ap_bw = 20 * BIT(u8_get_bits(info->control, ap_bw = 20 * BIT(u8_get_bits(info->control,
IEEE80211_EHT_OPER_CHAN_WIDTH)); IEEE80211_EHT_OPER_CHAN_WIDTH));
...@@ -387,7 +388,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, ...@@ -387,7 +388,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
if (eht_oper && (eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT)) { if (eht_oper && (eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT)) {
struct cfg80211_chan_def eht_chandef = *chandef; struct cfg80211_chan_def eht_chandef = *chandef;
ieee80211_chandef_eht_oper(eht_oper, ieee80211_chandef_eht_oper((const void *)eht_oper->optional,
eht_chandef.width == eht_chandef.width ==
NL80211_CHAN_WIDTH_160, NL80211_CHAN_WIDTH_160,
false, &eht_chandef); false, &eht_chandef);
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Copyright 2007, Michael Wu <flamingice@sourmilk.net> * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
* Copyright 2007-2008, Intel Corporation * Copyright 2007-2008, Intel Corporation
* Copyright 2008, Johannes Berg <johannes@sipsolutions.net> * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
* Copyright (C) 2018, 2020, 2022 Intel Corporation * Copyright (C) 2018, 2020, 2022-2023 Intel Corporation
*/ */
#include <linux/ieee80211.h> #include <linux/ieee80211.h>
...@@ -33,12 +33,14 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, ...@@ -33,12 +33,14 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
struct cfg80211_chan_def new_vht_chandef = {}; struct cfg80211_chan_def new_vht_chandef = {};
const struct ieee80211_sec_chan_offs_ie *sec_chan_offs; const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie; const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie;
const struct ieee80211_bandwidth_indication *bwi;
int secondary_channel_offset = -1; int secondary_channel_offset = -1;
memset(csa_ie, 0, sizeof(*csa_ie)); memset(csa_ie, 0, sizeof(*csa_ie));
sec_chan_offs = elems->sec_chan_offs; sec_chan_offs = elems->sec_chan_offs;
wide_bw_chansw_ie = elems->wide_bw_chansw_ie; wide_bw_chansw_ie = elems->wide_bw_chansw_ie;
bwi = elems->bandwidth_indication;
if (conn_flags & (IEEE80211_CONN_DISABLE_HT | if (conn_flags & (IEEE80211_CONN_DISABLE_HT |
IEEE80211_CONN_DISABLE_40MHZ)) { IEEE80211_CONN_DISABLE_40MHZ)) {
...@@ -132,7 +134,14 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, ...@@ -132,7 +134,14 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
break; break;
} }
if (wide_bw_chansw_ie) { if (bwi) {
/* start with the CSA one */
new_vht_chandef = csa_ie->chandef;
/* and update the width accordingly */
/* FIXME: support 160/320 */
ieee80211_chandef_eht_oper(&bwi->info, true, true,
&new_vht_chandef);
} else if (wide_bw_chansw_ie) {
u8 new_seg1 = wide_bw_chansw_ie->new_center_freq_seg1; u8 new_seg1 = wide_bw_chansw_ie->new_center_freq_seg1;
struct ieee80211_vht_operation vht_oper = { struct ieee80211_vht_operation vht_oper = {
.chan_width = .chan_width =
......
...@@ -990,6 +990,11 @@ ieee80211_parse_extension_element(u32 *crc, ...@@ -990,6 +990,11 @@ ieee80211_parse_extension_element(u32 *crc,
} }
} }
break; break;
case WLAN_EID_EXT_BANDWIDTH_INDICATION:
if (ieee80211_bandwidth_indication_size_ok(data, len))
elems->bandwidth_indication = data;
calc_crc = true;
break;
} }
if (crc && calc_crc) if (crc && calc_crc)
...@@ -1005,11 +1010,11 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, ...@@ -1005,11 +1010,11 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
bool calc_crc = params->filter != 0; bool calc_crc = params->filter != 0;
DECLARE_BITMAP(seen_elems, 256); DECLARE_BITMAP(seen_elems, 256);
u32 crc = params->crc; u32 crc = params->crc;
const u8 *ie;
bitmap_zero(seen_elems, 256); bitmap_zero(seen_elems, 256);
for_each_element(elem, params->start, params->len) { for_each_element(elem, params->start, params->len) {
const struct element *subelem;
bool elem_parse_failed; bool elem_parse_failed;
u8 id = elem->id; u8 id = elem->id;
u8 elen = elem->datalen; u8 elen = elem->datalen;
...@@ -1267,15 +1272,27 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, ...@@ -1267,15 +1272,27 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
} }
/* /*
* This is a bit tricky, but as we only care about * This is a bit tricky, but as we only care about
* the wide bandwidth channel switch element, so * a few elements, parse them out manually.
* just parse it out manually.
*/ */
ie = cfg80211_find_ie(WLAN_EID_WIDE_BW_CHANNEL_SWITCH, subelem = cfg80211_find_elem(WLAN_EID_WIDE_BW_CHANNEL_SWITCH,
pos, elen); pos, elen);
if (ie) { if (subelem) {
if (ie[1] >= sizeof(*elems->wide_bw_chansw_ie)) if (subelem->datalen >= sizeof(*elems->wide_bw_chansw_ie))
elems->wide_bw_chansw_ie = elems->wide_bw_chansw_ie =
(void *)(ie + 2); (void *)subelem->data;
else
elem_parse_failed = true;
}
subelem = cfg80211_find_ext_elem(WLAN_EID_EXT_BANDWIDTH_INDICATION,
pos, elen);
if (subelem) {
const void *edata = subelem->data + 1;
u8 edatalen = subelem->datalen - 1;
if (ieee80211_bandwidth_indication_size_ok(edata,
edatalen))
elems->bandwidth_indication = edata;
else else
elem_parse_failed = true; elem_parse_failed = true;
} }
...@@ -3746,12 +3763,10 @@ bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw, u32 vht_cap_info, ...@@ -3746,12 +3763,10 @@ bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw, u32 vht_cap_info,
return true; return true;
} }
void ieee80211_chandef_eht_oper(const struct ieee80211_eht_operation *eht_oper, void ieee80211_chandef_eht_oper(const struct ieee80211_eht_operation_info *info,
bool support_160, bool support_320, bool support_160, bool support_320,
struct cfg80211_chan_def *chandef) struct cfg80211_chan_def *chandef)
{ {
struct ieee80211_eht_operation_info *info = (void *)eht_oper->optional;
chandef->center_freq1 = chandef->center_freq1 =
ieee80211_channel_to_frequency(info->ccfs0, ieee80211_channel_to_frequency(info->ccfs0,
chandef->chan->band); chandef->chan->band);
...@@ -3920,8 +3935,9 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata, ...@@ -3920,8 +3935,9 @@ 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;
ieee80211_chandef_eht_oper(eht_oper, support_160, ieee80211_chandef_eht_oper((const void *)eht_oper->optional,
support_320, &he_chandef); support_160, support_320,
&he_chandef);
} }
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