]> www.infradead.org Git - users/griffoul/linux.git/commitdiff
wifi: mac80211: do not permit 40 MHz EHT operation on 5/6 GHz
authorBenjamin Berg <benjamin.berg@intel.com>
Tue, 26 Aug 2025 17:26:01 +0000 (20:26 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Thu, 28 Aug 2025 11:39:16 +0000 (13:39 +0200)
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>
net/mac80211/mlme.c
net/mac80211/tests/chan-mode.c

index 1008eb8e9b13beb269e423f011b3356a0c28651c..dd650a127a3174c25cd20251773798f39c436ee5 100644 (file)
@@ -1189,6 +1189,14 @@ again:
                             "required MCSes not supported, disabling EHT\n");
        }
 
+       if (conn->mode >= IEEE80211_CONN_MODE_EHT &&
+           channel->band != NL80211_BAND_2GHZ &&
+           conn->bw_limit == IEEE80211_CONN_BW_LIMIT_40) {
+               conn->mode = IEEE80211_CONN_MODE_HE;
+               link_id_info(sdata, link_id,
+                            "required bandwidth not supported, disabling EHT\n");
+       }
+
        /* the mode can only decrease, so this must terminate */
        if (ap_mode != conn->mode) {
                kfree(elems);
index 96c7b3ab27444d4beaf57f59c6f48119d83a8f27..adc069065e73dd2bf12049e214c33105bc1ad9fb 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * KUnit tests for channel mode functions
  *
- * Copyright (C) 2024 Intel Corporation
+ * Copyright (C) 2024-2025 Intel Corporation
  */
 #include <net/cfg80211.h>
 #include <kunit/test.h>
@@ -28,6 +28,10 @@ static const struct determine_chan_mode_case {
        u8 vht_basic_mcs_1_4, vht_basic_mcs_5_8;
        u8 he_basic_mcs_1_4, he_basic_mcs_5_8;
        u8 eht_mcs7_min_nss;
+       u16 eht_disabled_subchannels;
+       u8 eht_bw;
+       enum ieee80211_conn_bw_limit conn_bw_limit;
+       enum ieee80211_conn_bw_limit expected_bw_limit;
        int error;
 } determine_chan_mode_cases[] = {
        {
@@ -128,6 +132,14 @@ static const struct determine_chan_mode_case {
                .conn_mode = IEEE80211_CONN_MODE_EHT,
                .eht_mcs7_min_nss = 0x15,
                .error = EINVAL,
+       }, {
+               .desc = "80 MHz EHT is downgraded to 40 MHz HE due to puncturing",
+               .conn_mode = IEEE80211_CONN_MODE_EHT,
+               .expected_mode = IEEE80211_CONN_MODE_HE,
+               .conn_bw_limit = IEEE80211_CONN_BW_LIMIT_80,
+               .expected_bw_limit = IEEE80211_CONN_BW_LIMIT_40,
+               .eht_disabled_subchannels = 0x08,
+               .eht_bw = IEEE80211_EHT_OPER_CHAN_WIDTH_80MHZ,
        }
 };
 KUNIT_ARRAY_PARAM_DESC(determine_chan_mode, determine_chan_mode_cases, desc)
@@ -138,7 +150,7 @@ static void test_determine_chan_mode(struct kunit *test)
        struct t_sdata *t_sdata = T_SDATA(test);
        struct ieee80211_conn_settings conn = {
                .mode = params->conn_mode,
-               .bw_limit = IEEE80211_CONN_BW_LIMIT_20,
+               .bw_limit = params->conn_bw_limit,
        };
        struct cfg80211_bss cbss = {
                .channel = &t_sdata->band_5ghz.channels[0],
@@ -191,14 +203,21 @@ static void test_determine_chan_mode(struct kunit *test)
                0x7f, 0x01, 0x00, 0x88, 0x88, 0x88, 0x00, 0x00,
                0x00,
                /* EHT Operation */
-               WLAN_EID_EXTENSION, 0x09, WLAN_EID_EXT_EHT_OPERATION,
-               0x01, params->eht_mcs7_min_nss ? params->eht_mcs7_min_nss : 0x11,
-               0x00, 0x00, 0x00, 0x00, 0x24, 0x00,
+               WLAN_EID_EXTENSION, 0x0b, WLAN_EID_EXT_EHT_OPERATION,
+               0x03, params->eht_mcs7_min_nss ? params->eht_mcs7_min_nss : 0x11,
+               0x00, 0x00, 0x00, params->eht_bw,
+               params->eht_bw == IEEE80211_EHT_OPER_CHAN_WIDTH_80MHZ ? 42 : 36,
+               0x00,
+               u16_get_bits(params->eht_disabled_subchannels, 0xff),
+               u16_get_bits(params->eht_disabled_subchannels, 0xff00),
        };
        struct ieee80211_chan_req chanreq = {};
        struct cfg80211_chan_def ap_chandef = {};
        struct ieee802_11_elems *elems;
 
+       /* To force EHT downgrade to HE on punctured 80 MHz downgraded to 40 MHz */
+       set_bit(IEEE80211_HW_DISALLOW_PUNCTURING, t_sdata->local.hw.flags);
+
        if (params->strict)
                set_bit(IEEE80211_HW_STRICT, t_sdata->local.hw.flags);
        else
@@ -237,6 +256,7 @@ static void test_determine_chan_mode(struct kunit *test)
        } else {
                KUNIT_ASSERT_NOT_ERR_OR_NULL(test, elems);
                KUNIT_ASSERT_EQ(test, conn.mode, params->expected_mode);
+               KUNIT_ASSERT_EQ(test, conn.bw_limit, params->expected_bw_limit);
        }
 }