Skip to content

Commit 2a333a0

Browse files
committed
mac80211: avoid using ext NSS high BW if not supported
If the AP advertises inconsistent data, namely it has CCFS1 or CCFS2, but doesn't advertise support for 160/80+80 bandwidth or "Extended NSS BW Support", then we cannot use any MCSes in the the higher bandwidth. Thus, avoid connecting with higher bandwidth since it's less efficient that way. Link: https://lore.kernel.org/r/20200528213443.0e55d40c3ccc.I6fd0b4708ebd087e5e46466c3e91f6efbcbef668@changeid Signed-off-by: Johannes Berg <[email protected]>
1 parent 607ca9e commit 2a333a0

File tree

7 files changed

+100
-17
lines changed

7 files changed

+100
-17
lines changed

net/mac80211/ibss.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* Copyright 2009, Johannes Berg <[email protected]>
1010
* Copyright 2013-2014 Intel Mobile Communications GmbH
1111
* Copyright(c) 2016 Intel Deutschland GmbH
12-
* Copyright(c) 2018-2019 Intel Corporation
12+
* Copyright(c) 2018-2020 Intel Corporation
1313
*/
1414

1515
#include <linux/delay.h>
@@ -781,6 +781,7 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
781781
enum nl80211_channel_type ch_type;
782782
int err;
783783
u32 sta_flags;
784+
u32 vht_cap_info = 0;
784785

785786
sdata_assert_lock(sdata);
786787

@@ -798,9 +799,13 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
798799
break;
799800
}
800801

802+
if (elems->vht_cap_elem)
803+
vht_cap_info = le32_to_cpu(elems->vht_cap_elem->vht_cap_info);
804+
801805
memset(&params, 0, sizeof(params));
802806
err = ieee80211_parse_ch_switch_ie(sdata, elems,
803807
ifibss->chandef.chan->band,
808+
vht_cap_info,
804809
sta_flags, ifibss->bssid, &csa_ie);
805810
/* can't switch to destination channel, fail */
806811
if (err < 0)
@@ -1060,8 +1065,10 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata,
10601065
/* we both use VHT */
10611066
struct ieee80211_vht_cap cap_ie;
10621067
struct ieee80211_sta_vht_cap cap = sta->sta.vht_cap;
1068+
u32 vht_cap_info =
1069+
le32_to_cpu(elems->vht_cap_elem->vht_cap_info);
10631070

1064-
ieee80211_chandef_vht_oper(&local->hw,
1071+
ieee80211_chandef_vht_oper(&local->hw, vht_cap_info,
10651072
elems->vht_operation,
10661073
elems->ht_operation,
10671074
&chandef);

net/mac80211/ieee80211_i.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ struct ieee80211_bss {
111111
size_t supp_rates_len;
112112
struct ieee80211_rate *beacon_rate;
113113

114+
u32 vht_cap_info;
115+
114116
/*
115117
* During association, we save an ERP value from a probe response so
116118
* that we can feed ERP info to the driver when handling the
@@ -1915,6 +1917,7 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
19151917
* @sdata: the sdata of the interface which has received the frame
19161918
* @elems: parsed 802.11 elements received with the frame
19171919
* @current_band: indicates the current band
1920+
* @vht_cap_info: VHT capabilities of the transmitter
19181921
* @sta_flags: contains information about own capabilities and restrictions
19191922
* to decide which channel switch announcements can be accepted. Only the
19201923
* following subset of &enum ieee80211_sta_flags are evaluated:
@@ -1929,6 +1932,7 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
19291932
int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
19301933
struct ieee802_11_elems *elems,
19311934
enum nl80211_band current_band,
1935+
u32 vht_cap_info,
19321936
u32 sta_flags, u8 *bssid,
19331937
struct ieee80211_csa_ie *csa_ie);
19341938

@@ -2194,7 +2198,7 @@ u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo);
21942198
/* channel management */
21952199
bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,
21962200
struct cfg80211_chan_def *chandef);
2197-
bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw,
2201+
bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw, u32 vht_cap_info,
21982202
const struct ieee80211_vht_operation *oper,
21992203
const struct ieee80211_ht_operation *htop,
22002204
struct cfg80211_chan_def *chandef);

net/mac80211/mesh.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// SPDX-License-Identifier: GPL-2.0-only
22
/*
33
* Copyright (c) 2008, 2009 open80211s Ltd.
4-
* Copyright (C) 2018 - 2019 Intel Corporation
4+
* Copyright (C) 2018 - 2020 Intel Corporation
55
* Authors: Luis Carlos Cobo <[email protected]>
66
* Javier Cardona <[email protected]>
77
*/
@@ -63,6 +63,7 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
6363
u32 basic_rates = 0;
6464
struct cfg80211_chan_def sta_chan_def;
6565
struct ieee80211_supported_band *sband;
66+
u32 vht_cap_info = 0;
6667

6768
/*
6869
* As support for each feature is added, check for matching
@@ -96,7 +97,11 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
9697
cfg80211_chandef_create(&sta_chan_def, sdata->vif.bss_conf.chandef.chan,
9798
NL80211_CHAN_NO_HT);
9899
ieee80211_chandef_ht_oper(ie->ht_operation, &sta_chan_def);
99-
ieee80211_chandef_vht_oper(&sdata->local->hw,
100+
101+
if (ie->vht_cap_elem)
102+
vht_cap_info = le32_to_cpu(ie->vht_cap_elem->vht_cap_info);
103+
104+
ieee80211_chandef_vht_oper(&sdata->local->hw, vht_cap_info,
100105
ie->vht_operation, ie->ht_operation,
101106
&sta_chan_def);
102107

@@ -1076,7 +1081,7 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
10761081
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
10771082
struct ieee80211_supported_band *sband;
10781083
int err;
1079-
u32 sta_flags;
1084+
u32 sta_flags, vht_cap_info = 0;
10801085

10811086
sdata_assert_lock(sdata);
10821087

@@ -1099,8 +1104,13 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
10991104
break;
11001105
}
11011106

1107+
if (elems->vht_cap_elem)
1108+
vht_cap_info =
1109+
le32_to_cpu(elems->vht_cap_elem->vht_cap_info);
1110+
11021111
memset(&params, 0, sizeof(params));
11031112
err = ieee80211_parse_ch_switch_ie(sdata, elems, sband->band,
1113+
vht_cap_info,
11041114
sta_flags, sdata->vif.addr,
11051115
&csa_ie);
11061116
if (err < 0)

net/mac80211/mlme.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ static u32
145145
ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
146146
struct ieee80211_supported_band *sband,
147147
struct ieee80211_channel *channel,
148+
u32 vht_cap_info,
148149
const struct ieee80211_ht_operation *ht_oper,
149150
const struct ieee80211_vht_operation *vht_oper,
150151
const struct ieee80211_he_operation *he_oper,
@@ -223,7 +224,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
223224
memcpy(&he_oper_vht_cap, he_oper->optional, 3);
224225
he_oper_vht_cap.basic_mcs_set = cpu_to_le16(0);
225226

226-
if (!ieee80211_chandef_vht_oper(&sdata->local->hw,
227+
if (!ieee80211_chandef_vht_oper(&sdata->local->hw, vht_cap_info,
227228
&he_oper_vht_cap, ht_oper,
228229
&vht_chandef)) {
229230
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE))
@@ -232,8 +233,10 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
232233
ret = IEEE80211_STA_DISABLE_HE;
233234
goto out;
234235
}
235-
} else if (!ieee80211_chandef_vht_oper(&sdata->local->hw, vht_oper,
236-
ht_oper, &vht_chandef)) {
236+
} else if (!ieee80211_chandef_vht_oper(&sdata->local->hw,
237+
vht_cap_info,
238+
vht_oper, ht_oper,
239+
&vht_chandef)) {
237240
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
238241
sdata_info(sdata,
239242
"AP VHT information is invalid, disable VHT\n");
@@ -329,6 +332,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
329332
static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
330333
struct sta_info *sta,
331334
const struct ieee80211_ht_cap *ht_cap,
335+
const struct ieee80211_vht_cap *vht_cap,
332336
const struct ieee80211_ht_operation *ht_oper,
333337
const struct ieee80211_vht_operation *vht_oper,
334338
const struct ieee80211_he_operation *he_oper,
@@ -343,6 +347,7 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
343347
u16 ht_opmode;
344348
u32 flags;
345349
enum ieee80211_sta_rx_bandwidth new_sta_bw;
350+
u32 vht_cap_info = 0;
346351
int ret;
347352

348353
/* if HT was/is disabled, don't track any bandwidth changes */
@@ -371,8 +376,11 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
371376
sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
372377
}
373378

379+
if (vht_cap)
380+
vht_cap_info = le32_to_cpu(vht_cap->vht_cap_info);
381+
374382
/* calculate new channel (type) based on HT/VHT/HE operation IEs */
375-
flags = ieee80211_determine_chantype(sdata, sband, chan,
383+
flags = ieee80211_determine_chantype(sdata, sband, chan, vht_cap_info,
376384
ht_oper, vht_oper, he_oper,
377385
&chandef, true);
378386

@@ -1327,6 +1335,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
13271335
enum nl80211_band current_band;
13281336
struct ieee80211_csa_ie csa_ie;
13291337
struct ieee80211_channel_switch ch_switch;
1338+
struct ieee80211_bss *bss;
13301339
int res;
13311340

13321341
sdata_assert_lock(sdata);
@@ -1338,7 +1347,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
13381347
return;
13391348

13401349
current_band = cbss->channel->band;
1350+
bss = (void *)cbss->priv;
13411351
res = ieee80211_parse_ch_switch_ie(sdata, elems, current_band,
1352+
bss->vht_cap_info,
13421353
ifmgd->flags,
13431354
ifmgd->associated->bssid, &csa_ie);
13441355

@@ -4097,8 +4108,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
40974108

40984109
changed |= ieee80211_recalc_twt_req(sdata, sta, &elems);
40994110

4100-
if (ieee80211_config_bw(sdata, sta,
4101-
elems.ht_cap_elem, elems.ht_operation,
4111+
if (ieee80211_config_bw(sdata, sta, elems.ht_cap_elem,
4112+
elems.vht_cap_elem, elems.ht_operation,
41024113
elems.vht_operation, elems.he_operation,
41034114
bssid, &changed)) {
41044115
mutex_unlock(&local->sta_mtx);
@@ -4815,6 +4826,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
48154826
const struct ieee80211_he_operation *he_oper = NULL;
48164827
struct ieee80211_supported_band *sband;
48174828
struct cfg80211_chan_def chandef;
4829+
struct ieee80211_bss *bss = (void *)cbss->priv;
48184830
int ret;
48194831
u32 i;
48204832
bool have_80mhz;
@@ -4913,6 +4925,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
49134925

49144926
ifmgd->flags |= ieee80211_determine_chantype(sdata, sband,
49154927
cbss->channel,
4928+
bss->vht_cap_info,
49164929
ht_oper, vht_oper, he_oper,
49174930
&chandef, false);
49184931

net/mac80211/scan.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,12 @@ ieee80211_update_bss_from_elems(struct ieee80211_local *local,
132132
bss->beacon_rate =
133133
&sband->bitrates[rx_status->rate_idx];
134134
}
135+
136+
if (elems->vht_cap_elem)
137+
bss->vht_cap_info =
138+
le32_to_cpu(elems->vht_cap_elem->vht_cap_info);
139+
else
140+
bss->vht_cap_info = 0;
135141
}
136142

137143
struct ieee80211_bss *

net/mac80211/spectmgmt.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* Copyright 2007, Michael Wu <[email protected]>
1010
* Copyright 2007-2008, Intel Corporation
1111
* Copyright 2008, Johannes Berg <[email protected]>
12-
* Copyright (C) 2018 Intel Corporation
12+
* Copyright (C) 2018, 2020 Intel Corporation
1313
*/
1414

1515
#include <linux/ieee80211.h>
@@ -22,6 +22,7 @@
2222
int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
2323
struct ieee802_11_elems *elems,
2424
enum nl80211_band current_band,
25+
u32 vht_cap_info,
2526
u32 sta_flags, u8 *bssid,
2627
struct ieee80211_csa_ie *csa_ie)
2728
{
@@ -150,6 +151,7 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
150151

151152
/* ignore if parsing fails */
152153
if (!ieee80211_chandef_vht_oper(&sdata->local->hw,
154+
vht_cap_info,
153155
&vht_oper, &ht_oper,
154156
&new_vht_chandef))
155157
new_vht_chandef.chan = NULL;

net/mac80211/util.c

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3120,7 +3120,7 @@ bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,
31203120
return true;
31213121
}
31223122

3123-
bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw,
3123+
bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw, u32 vht_cap_info,
31243124
const struct ieee80211_vht_operation *oper,
31253125
const struct ieee80211_ht_operation *htop,
31263126
struct cfg80211_chan_def *chandef)
@@ -3132,6 +3132,10 @@ bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw,
31323132
u32 vht_cap;
31333133
bool support_80_80 = false;
31343134
bool support_160 = false;
3135+
u8 ext_nss_bw_supp = u32_get_bits(vht_cap_info,
3136+
IEEE80211_VHT_CAP_EXT_NSS_BW_MASK);
3137+
u8 supp_chwidth = u32_get_bits(vht_cap_info,
3138+
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK);
31353139

31363140
if (!oper || !htop)
31373141
return false;
@@ -3151,11 +3155,48 @@ bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw,
31513155
IEEE80211_HT_OP_MODE_CCFS2_MASK)
31523156
>> IEEE80211_HT_OP_MODE_CCFS2_SHIFT;
31533157

3154-
/* when parsing (and we know how to) CCFS1 and CCFS2 are equivalent */
31553158
ccf0 = ccfs0;
3156-
ccf1 = ccfs1;
3157-
if (!ccfs1 && ieee80211_hw_check(hw, SUPPORTS_VHT_EXT_NSS_BW))
3159+
3160+
/* if not supported, parse as though we didn't understand it */
3161+
if (!ieee80211_hw_check(hw, SUPPORTS_VHT_EXT_NSS_BW))
3162+
ext_nss_bw_supp = 0;
3163+
3164+
/*
3165+
* Cf. IEEE 802.11 Table 9-250
3166+
*
3167+
* We really just consider that because it's inefficient to connect
3168+
* at a higher bandwidth than we'll actually be able to use.
3169+
*/
3170+
switch ((supp_chwidth << 4) | ext_nss_bw_supp) {
3171+
default:
3172+
case 0x00:
3173+
ccf1 = 0;
3174+
support_160 = false;
3175+
support_80_80 = false;
3176+
break;
3177+
case 0x01:
3178+
support_80_80 = false;
3179+
/* fall through */
3180+
case 0x02:
3181+
case 0x03:
31583182
ccf1 = ccfs2;
3183+
break;
3184+
case 0x10:
3185+
ccf1 = ccfs1;
3186+
break;
3187+
case 0x11:
3188+
case 0x12:
3189+
if (!ccfs1)
3190+
ccf1 = ccfs2;
3191+
else
3192+
ccf1 = ccfs1;
3193+
break;
3194+
case 0x13:
3195+
case 0x20:
3196+
case 0x23:
3197+
ccf1 = ccfs1;
3198+
break;
3199+
}
31593200

31603201
cf0 = ieee80211_channel_to_frequency(ccf0, chandef->chan->band);
31613202
cf1 = ieee80211_channel_to_frequency(ccf1, chandef->chan->band);

0 commit comments

Comments
 (0)