Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

wifi: mac80211: do not permit 40 MHz EHT operation on 5/6 GHz

The EHT PHY requirements state that 80 MHz must be supported on the 5
and 6 GHz bands unless the STA is 20 MHz only. So if the channel width
is limited to 40 MHz on a band other than 2.4 GHz, then disable EHT and
downgrade to HE.

The primary case where this can happen is if the hardware disables
puncturing using IEEE80211_HW_DISALLOW_PUNCTURING.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
Cc: stable@vger.kernel.org
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20250826202553.a6582f3abf57.Ic670429dc7127f68c818b4290d950ebfb5a0b9e1@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Benjamin Berg and committed by
Johannes Berg
75575e2d 7e2f3213

+33 -5
+8
net/mac80211/mlme.c
··· 1189 1189 "required MCSes not supported, disabling EHT\n"); 1190 1190 } 1191 1191 1192 + if (conn->mode >= IEEE80211_CONN_MODE_EHT && 1193 + channel->band != NL80211_BAND_2GHZ && 1194 + conn->bw_limit == IEEE80211_CONN_BW_LIMIT_40) { 1195 + conn->mode = IEEE80211_CONN_MODE_HE; 1196 + link_id_info(sdata, link_id, 1197 + "required bandwidth not supported, disabling EHT\n"); 1198 + } 1199 + 1192 1200 /* the mode can only decrease, so this must terminate */ 1193 1201 if (ap_mode != conn->mode) { 1194 1202 kfree(elems);
+25 -5
net/mac80211/tests/chan-mode.c
··· 2 2 /* 3 3 * KUnit tests for channel mode functions 4 4 * 5 - * Copyright (C) 2024 Intel Corporation 5 + * Copyright (C) 2024-2025 Intel Corporation 6 6 */ 7 7 #include <net/cfg80211.h> 8 8 #include <kunit/test.h> ··· 28 28 u8 vht_basic_mcs_1_4, vht_basic_mcs_5_8; 29 29 u8 he_basic_mcs_1_4, he_basic_mcs_5_8; 30 30 u8 eht_mcs7_min_nss; 31 + u16 eht_disabled_subchannels; 32 + u8 eht_bw; 33 + enum ieee80211_conn_bw_limit conn_bw_limit; 34 + enum ieee80211_conn_bw_limit expected_bw_limit; 31 35 int error; 32 36 } determine_chan_mode_cases[] = { 33 37 { ··· 132 128 .conn_mode = IEEE80211_CONN_MODE_EHT, 133 129 .eht_mcs7_min_nss = 0x15, 134 130 .error = EINVAL, 131 + }, { 132 + .desc = "80 MHz EHT is downgraded to 40 MHz HE due to puncturing", 133 + .conn_mode = IEEE80211_CONN_MODE_EHT, 134 + .expected_mode = IEEE80211_CONN_MODE_HE, 135 + .conn_bw_limit = IEEE80211_CONN_BW_LIMIT_80, 136 + .expected_bw_limit = IEEE80211_CONN_BW_LIMIT_40, 137 + .eht_disabled_subchannels = 0x08, 138 + .eht_bw = IEEE80211_EHT_OPER_CHAN_WIDTH_80MHZ, 135 139 } 136 140 }; 137 141 KUNIT_ARRAY_PARAM_DESC(determine_chan_mode, determine_chan_mode_cases, desc) ··· 150 138 struct t_sdata *t_sdata = T_SDATA(test); 151 139 struct ieee80211_conn_settings conn = { 152 140 .mode = params->conn_mode, 153 - .bw_limit = IEEE80211_CONN_BW_LIMIT_20, 141 + .bw_limit = params->conn_bw_limit, 154 142 }; 155 143 struct cfg80211_bss cbss = { 156 144 .channel = &t_sdata->band_5ghz.channels[0], ··· 203 191 0x7f, 0x01, 0x00, 0x88, 0x88, 0x88, 0x00, 0x00, 204 192 0x00, 205 193 /* EHT Operation */ 206 - WLAN_EID_EXTENSION, 0x09, WLAN_EID_EXT_EHT_OPERATION, 207 - 0x01, params->eht_mcs7_min_nss ? params->eht_mcs7_min_nss : 0x11, 208 - 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 194 + WLAN_EID_EXTENSION, 0x0b, WLAN_EID_EXT_EHT_OPERATION, 195 + 0x03, params->eht_mcs7_min_nss ? params->eht_mcs7_min_nss : 0x11, 196 + 0x00, 0x00, 0x00, params->eht_bw, 197 + params->eht_bw == IEEE80211_EHT_OPER_CHAN_WIDTH_80MHZ ? 42 : 36, 198 + 0x00, 199 + u16_get_bits(params->eht_disabled_subchannels, 0xff), 200 + u16_get_bits(params->eht_disabled_subchannels, 0xff00), 209 201 }; 210 202 struct ieee80211_chan_req chanreq = {}; 211 203 struct cfg80211_chan_def ap_chandef = {}; 212 204 struct ieee802_11_elems *elems; 205 + 206 + /* To force EHT downgrade to HE on punctured 80 MHz downgraded to 40 MHz */ 207 + set_bit(IEEE80211_HW_DISALLOW_PUNCTURING, t_sdata->local.hw.flags); 213 208 214 209 if (params->strict) 215 210 set_bit(IEEE80211_HW_STRICT, t_sdata->local.hw.flags); ··· 256 237 } else { 257 238 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, elems); 258 239 KUNIT_ASSERT_EQ(test, conn.mode, params->expected_mode); 240 + KUNIT_ASSERT_EQ(test, conn.bw_limit, params->expected_bw_limit); 259 241 } 260 242 } 261 243