Linux wireless drivers development
 help / color / mirror / Atom feed
* RE: [PATCH 2/3] wifi: iwlwifi: mld: fix TSO segmentation explosion when AMSDU is disabled
From: Korenblit, Miriam Rachel @ 2026-04-12  3:47 UTC (permalink / raw)
  To: Cole Leavitt, linux-wireless@vger.kernel.org
  Cc: greearb@candelatech.com, johannes@sipsolutions.net
In-Reply-To: <20260405054145.1064152-3-cole@unwrap.rs>



> -----Original Message-----
> From: Cole Leavitt <cole@unwrap.rs>
> Sent: Sunday, April 5, 2026 8:42 AM
> To: linux-wireless@vger.kernel.org
> Cc: greearb@candelatech.com; Korenblit, Miriam Rachel
> <miriam.rachel.korenblit@intel.com>; johannes@sipsolutions.net;
> cole@unwrap.rs
> Subject: [PATCH 2/3] wifi: iwlwifi: mld: fix TSO segmentation explosion when
> AMSDU is disabled
> 
> When the TLC notification disables AMSDU for a TID, the MLD driver sets
> max_tid_amsdu_len to the sentinel value 1. The TSO segmentation path in
> iwl_mld_tx_tso_segment() checks for zero but not for this sentinel, allowing it to
> reach the num_subframes calculation:
> 
>   num_subframes = (max_tid_amsdu_len + pad) / (subf_len + pad)
>                 = (1 + 2) / (1534 + 2) = 0
> 
> This zero propagates to iwl_tx_tso_segment() which sets:
> 
>   gso_size = num_subframes * mss = 0
> 
> Calling skb_gso_segment() with gso_size=0 creates over 32000 tiny segments
> from a single GSO skb. This floods the TX ring with ~1024 micro-frames (the rest
> are purged), creating a massive burst of TX completion events that can lead to
> memory corruption and a subsequent use-after-free in TCP's retransmit queue
> (refcount underflow in tcp_shifted_skb, NULL deref in tcp_rack_detect_loss).

And why not fixing this issue?

> 
> The MVM driver is immune because it checks mvmsta->amsdu_enabled before
> reaching the num_subframes calculation. The MLD driver has no equivalent
> bitmap check and relies solely on max_tid_amsdu_len, which does not catch the
> sentinel value.
> 
> Fix this by detecting the sentinel value (max_tid_amsdu_len == 1) at the existing
> check and falling back to non-AMSDU TSO segmentation. Also add a
> WARN_ON_ONCE guard after the num_subframes division as defense-in-depth
> to catch any future code paths that produce zero through a different mechanism.
> 
> Suggested-by: Miriam Rachel Korenblit <miriam.rachel.korenblit@intel.com>
> Fixes: d1e879ec600f ("wifi: iwlwifi: add iwlmld sub-driver")
> Signed-off-by: Cole Leavitt <cole@unwrap.rs>
> ---
>  drivers/net/wireless/intel/iwlwifi/mld/tx.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tx.c
> b/drivers/net/wireless/intel/iwlwifi/mld/tx.c
> index e341d12e5233..8af58aabcd68 100644
> --- a/drivers/net/wireless/intel/iwlwifi/mld/tx.c
> +++ b/drivers/net/wireless/intel/iwlwifi/mld/tx.c
> @@ -823,7 +823,7 @@ static int iwl_mld_tx_tso_segment(struct iwl_mld *mld,
> struct sk_buff *skb,
>  		return -EINVAL;
> 
>  	max_tid_amsdu_len = sta->cur->max_tid_amsdu_len[tid];
> -	if (!max_tid_amsdu_len)
> +	if (!max_tid_amsdu_len || max_tid_amsdu_len == 1)
>  		return iwl_tx_tso_segment(skb, 1, netdev_flags, mpdus_skbs);
> 
>  	/* Sub frame header + SNAP + IP header + TCP header + MSS */ @@ -
> 835,6 +835,9 @@ static int iwl_mld_tx_tso_segment(struct iwl_mld *mld, struct
> sk_buff *skb,
>  	 */
>  	num_subframes = (max_tid_amsdu_len + pad) / (subf_len + pad);
> 
> +	if (WARN_ON_ONCE(!num_subframes))
> +		return iwl_tx_tso_segment(skb, 1, netdev_flags, mpdus_skbs);
> +
>  	if (sta->max_amsdu_subframes &&
>  	    num_subframes > sta->max_amsdu_subframes)
>  		num_subframes = sta->max_amsdu_subframes;
> --
> 2.52.0


^ permalink raw reply

* Re: [PATCH wireless v2] wifi: iwlwifi: mld: stop TX during firmware restart
From: Sheroz Juraev @ 2026-04-11 21:27 UTC (permalink / raw)
  To: Miri Korenblit; +Cc: Johannes Berg, linux-wireless, stable
In-Reply-To: <20260315081221.2678478-1-goodmartiandev@gmail.com>

Gentle ping.

This v2 was posted on 2026-03-15 and hasn't received any review
feedback yet. I realized after sending that I dropped you from the
direct To: line in v2 (it only went to the list), so this ping is
mostly to make sure it didn't slip through the cracks.

Since we're currently in the 7.0-rc stabilization window, I wanted to
check whether this small bugfix could still be picked up for the
wireless tree, or if there's anything you'd like me to change.

Patchwork:
https://patchwork.kernel.org/project/linux-wireless/patch/20260315081221.2678478-1-goodmartiandev@gmail.com/

Thanks,
Sheroz

^ permalink raw reply

* Re: [PATCH rtw-next] wifi: rtw88: 8814a: add __packed to ensure efuse map size
From: Ping-Ke Shih @ 2026-04-11  7:29 UTC (permalink / raw)
  To: Bitterblue Smith, linux-wireless@vger.kernel.org; +Cc: lkp@intel.com
In-Reply-To: <7c65e315-5a2e-455e-87ee-8fc6d60ed807@gmail.com>

Bitterblue Smith <rtl8821cerfe2@gmail.com> wrote:

> On 10/04/2026 16:13, Ping-Ke Shih wrote:
> > All nested sture/union used by efuse map should be packed. Otherwise, a
> > arm-linux-gnueabi-gcc compiler might throw errors due to size assertion.
> >
> >    In file included from include/linux/bitfield.h:10,
> >                     from include/linux/fortify-string.h:5,
> >                     from include/linux/string.h:389,
> >                     from include/linux/uuid.h:11,
> >                     from include/linux/mod_devicetable.h:14,
> >                     from include/linux/usb.h:5,
> >                     from drivers/net/wireless/realtek/rtw88/rtw8814a.c:5:
> >>> include/linux/build_bug.h:78:41: error: static assertion failed: "sizeof(struct rtw8814a_efuse) == 512"
> >     #define __static_assert(expr, msg, ...) _Static_assert(expr, msg)
> >                                             ^~~~~~~~~~~~~~
> >
> > Fixes: 1a7545784642 ("wifi: rtw88: Add rtw8814a.{c,h}")
> > Reported-by: kernel test robot <lkp@intel.com>
> > Closes:  https://lore.kernel.org/oe-kbuild-all/202604101721.fsv5XmCX-lkp@intel.com/
> > Cc: Bitterblue Smith <rtl8821cerfe2@gmail.com>
> > Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
> > ---
> >  drivers/net/wireless/realtek/rtw88/main.h     | 2 +-
> >  drivers/net/wireless/realtek/rtw88/rtw8814a.h | 2 +-
> >  2 files changed, 2 insertions(+), 2 deletions(-)
> >
> 
> Thank you for taking care of this. Actually, every chip's efuse struct
> has a union like this missing __packed, not just RTL8814A. Most of them
> don't have a static_assert.
> 

Indeed. I added size assetion of efuse map entirely to rtw88 and rtw89 [1],
hoping we can find and address this kind of problem earlier.

[1] https://lore.kernel.org/linux-wireless/20260411072413.1556575-1-pkshih@realtek.com/T/#t


^ permalink raw reply

* [PATCH wireless-next] wifi: mac80211: add __packed to union members of struct ieee80211_rx_status
From: Ping-Ke Shih @ 2026-04-11  7:25 UTC (permalink / raw)
  To: johannes, linux-wireless

The arm-linux-gnueabi-gcc compiler, align the field followed by union
members, causing size of struct ieee80211_rx_status over skb->cb
(48 bytes). By investigation, the union member starts at offset 32,
and the offset of next field rate_idx is 36 instead of expected 33, and
the total size is (unexpected) 52.

When compiling rtw88 driver, it throws:

In file included from /work/linux-src/linux-stable/include/linux/string.h:386,
                 from /work/linux-src/linux-stable/include/linux/bitmap.h:13,
                 from /work/linux-src/linux-stable/include/linux/cpumask.h:11,
                 from /work/linux-src/linux-stable/include/linux/smp.h:13,
                 from /work/linux-src/linux-stable/include/linux/lockdep.h:14,
                 from /work/linux-src/linux-stable/include/linux/mutex.h:17,
                 from /work/linux-src/linux-stable/include/linux/kernfs.h:11,
                 from /work/linux-src/linux-stable/include/linux/sysfs.h:16,
                 from /work/linux-src/linux-stable/include/linux/kobject.h:20,
                 from /work/linux-src/linux-stable/include/linux/dmi.h:6,
                 from pci.c:5:
In function 'fortify_memcpy_chk',
    inlined from 'rtw_pci_rx_napi.constprop' at pci.c:1095:4:
/work/linux-src/linux-stable/include/linux/fortify-string.h:569:25: warning: call to '__write_overflow_field' declared with attribute warning: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Wattribute-warning]
  569 |                         __write_overflow_field(p_size_field, size);
      |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

After this patch, the size of struct ieee80211_rx_status is 48.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
Because of size assertion of rtw88's efuse map [1], I found
arm-linux-gnueabi-gcc compiler throws this warning, but x86 gcc is absolutely
silent and expected without this patch.

[1] https://lore.kernel.org/linux-wireless/7c65e315-5a2e-455e-87ee-8fc6d60ed807@gmail.com/T/#m43fdf8a1c2b8cff92c1ef50faab7993522647162
---
 include/net/mac80211.h | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 40cb20d9309c..02318a4be0e1 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1747,18 +1747,18 @@ struct ieee80211_rx_status {
 			u8 he_ru:3;
 			u8 he_gi:2;
 			u8 he_dcm:1;
-		};
+		} __packed;
 		struct {
 			u8 ru:4;
 			u8 gi:2;
-		} eht;
+		} __packed eht;
 		struct {
 			u8 ru:4;
 			u8 gi:2;
 			u8 elr:1;
 			u8 im:1;
-		} uhr;
-	};
+		} __packed uhr;
+	} __packed;
 	u8 rate_idx;
 	u8 nss;
 	u8 rx_flags;
@@ -1771,6 +1771,8 @@ struct ieee80211_rx_status {
 	u8 link_valid:1, link_id:4;
 };
 
+static_assert(sizeof(struct ieee80211_rx_status) <= sizeof_field(struct sk_buff, cb));
+
 static inline u32
 ieee80211_rx_status_to_khz(struct ieee80211_rx_status *rx_status)
 {
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 2/2] wifi: rtw89: add __packed to efuse map and do assertion
From: Ping-Ke Shih @ 2026-04-11  7:24 UTC (permalink / raw)
  To: linux-wireless; +Cc: rtl8821cerfe2
In-Reply-To: <20260411072413.1556575-1-pkshih@realtek.com>

As arm-linux-gnueabi-gcc compiler align struct field is not always like
gcc on x86 target, the efuse map layout might not be expected. Add __packed
and do assertion to ensure it is expected.

Complied test only with arm-linux-gnueabi-gcc and x86 gcc.

Cc: Bitterblue Smith <rtl8821cerfe2@gmail.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/rtw8851b.h        | 8 +++++---
 drivers/net/wireless/realtek/rtw89/rtw8852a.h        | 8 +++++---
 drivers/net/wireless/realtek/rtw89/rtw8852b_common.h | 8 +++++---
 drivers/net/wireless/realtek/rtw89/rtw8852c.h        | 8 +++++---
 drivers/net/wireless/realtek/rtw89/rtw8922a.h        | 2 ++
 drivers/net/wireless/realtek/rtw89/rtw8922d.h        | 2 ++
 6 files changed, 24 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.h b/drivers/net/wireless/realtek/rtw89/rtw8851b.h
index 1a5c52654d8a..5c2e26c04cd9 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8851b.h
+++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.h
@@ -13,11 +13,11 @@
 struct rtw8851bu_efuse {
 	u8 rsvd[0x88];
 	u8 mac_addr[ETH_ALEN];
-};
+} __packed;
 
 struct rtw8851be_efuse {
 	u8 mac_addr[ETH_ALEN];
-};
+} __packed;
 
 struct rtw8851b_tssi_offset {
 	u8 cck_tssi[TSSI_CCK_CH_GROUP_NUM];
@@ -68,9 +68,11 @@ struct rtw8851b_efuse {
 	union {
 		struct rtw8851bu_efuse u;
 		struct rtw8851be_efuse e;
-	};
+	} __packed;
 } __packed;
 
+static_assert(sizeof(struct rtw8851b_efuse) == 0x48e);
+
 extern const struct rtw89_chip_info rtw8851b_chip_info;
 
 #endif
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.h b/drivers/net/wireless/realtek/rtw89/rtw8852a.h
index d6c1acd09238..0d381f6fd182 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852a.h
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.h
@@ -19,11 +19,11 @@ enum rtw8852a_pmac_mode {
 struct rtw8852au_efuse {
 	u8 rsvd[0x38];
 	u8 mac_addr[ETH_ALEN];
-};
+} __packed;
 
 struct rtw8852ae_efuse {
 	u8 mac_addr[ETH_ALEN];
-};
+} __packed;
 
 struct rtw8852a_tssi_offset {
 	u8 cck_tssi[TSSI_CCK_CH_GROUP_NUM];
@@ -78,9 +78,11 @@ struct rtw8852a_efuse {
 	union {
 		struct rtw8852au_efuse u;
 		struct rtw8852ae_efuse e;
-	};
+	} __packed;
 } __packed;
 
+static_assert(sizeof(struct rtw8852a_efuse) == 0x43e);
+
 struct rtw8852a_bb_pmac_info {
 	u8 en_pmac_tx:1;
 	u8 is_cck:1;
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.h b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.h
index 3dce5422f41e..89e936e4b211 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.h
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.h
@@ -20,11 +20,11 @@ enum rtw8852bx_pmac_mode {
 struct rtw8852bx_u_efuse {
 	u8 rsvd[0x88];
 	u8 mac_addr[ETH_ALEN];
-};
+} __packed;
 
 struct rtw8852bx_e_efuse {
 	u8 mac_addr[ETH_ALEN];
-};
+} __packed;
 
 struct rtw8852bx_tssi_offset {
 	u8 cck_tssi[TSSI_CCK_CH_GROUP_NUM];
@@ -89,9 +89,11 @@ struct rtw8852bx_efuse {
 	union {
 		struct rtw8852bx_u_efuse u;
 		struct rtw8852bx_e_efuse e;
-	};
+	} __packed;
 } __packed;
 
+static_assert(sizeof(struct rtw8852bx_efuse) == 0x48e);
+
 struct rtw8852bx_bb_pmac_info {
 	u8 en_pmac_tx:1;
 	u8 is_cck:1;
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.h b/drivers/net/wireless/realtek/rtw89/rtw8852c.h
index 8585921ac6c4..49cb6b4b3b7c 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.h
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.h
@@ -13,11 +13,11 @@
 struct rtw8852c_u_efuse {
 	u8 rsvd[0x88];
 	u8 mac_addr[ETH_ALEN];
-};
+} __packed;
 
 struct rtw8852c_e_efuse {
 	u8 mac_addr[ETH_ALEN];
-};
+} __packed;
 
 struct rtw8852c_tssi_offset {
 	u8 cck_tssi[TSSI_CCK_CH_GROUP_NUM];
@@ -95,9 +95,11 @@ struct rtw8852c_efuse {
 	union {
 		struct rtw8852c_u_efuse u;
 		struct rtw8852c_e_efuse e;
-	};
+	} __packed;
 } __packed;
 
+static_assert(sizeof(struct rtw8852c_efuse) == 0x48e);
+
 extern const struct rtw89_chip_info rtw8852c_chip_info;
 
 #endif
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.h b/drivers/net/wireless/realtek/rtw89/rtw8922a.h
index a29cfa5b4291..33c87bcc403c 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922a.h
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.h
@@ -68,6 +68,8 @@ struct rtw8922a_efuse {
 	struct rtw8922a_rx_gain_6g rx_gain_6g_b;
 } __packed;
 
+static_assert(sizeof(struct rtw8922a_efuse) == 0x1b8);
+
 extern const struct rtw89_chip_info rtw8922a_chip_info;
 extern const struct rtw89_chip_variant rtw8922ae_vs_variant;
 
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.h b/drivers/net/wireless/realtek/rtw89/rtw8922d.h
index 22a7d1cc244f..6d0fb01c1216 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.h
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.h
@@ -77,6 +77,8 @@ struct rtw8922d_efuse {
 	struct rtw8922d_rx_gain_6g rx_gain_6g_b_2;
 } __packed;
 
+static_assert(sizeof(struct rtw8922d_efuse) == 0x222);
+
 extern const struct rtw89_chip_info rtw8922d_chip_info;
 extern const struct rtw89_chip_variant rtw8922de_vs_variant;
 
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 1/2] wifi: rtw88: add __packed to efuse map and do assertion
From: Ping-Ke Shih @ 2026-04-11  7:24 UTC (permalink / raw)
  To: linux-wireless; +Cc: rtl8821cerfe2

As arm-linux-gnueabi-gcc compiler align struct field is not always like
gcc on x86 target, the efuse map layout might not be expected. Add __packed
and do assertion to ensure it is expected.

Complied test only with arm-linux-gnueabi-gcc and x86 gcc.

Cc: Bitterblue Smith <rtl8821cerfe2@gmail.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw88/rtw8703b.h | 2 ++
 drivers/net/wireless/realtek/rtw88/rtw8723x.h | 4 +++-
 drivers/net/wireless/realtek/rtw88/rtw8821c.h | 4 +++-
 drivers/net/wireless/realtek/rtw88/rtw8822b.h | 4 +++-
 drivers/net/wireless/realtek/rtw88/rtw8822c.h | 4 +++-
 drivers/net/wireless/realtek/rtw88/rtw88xxa.h | 2 +-
 6 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw88/rtw8703b.h b/drivers/net/wireless/realtek/rtw88/rtw8703b.h
index 3e2da2e6739d..e3d709635902 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8703b.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw8703b.h
@@ -70,6 +70,8 @@ struct phy_status_8703b {
 #endif
 } __packed;
 
+static_assert(sizeof(struct phy_status_8703b) == 28);
+
 /* Baseband registers */
 #define REG_BB_PWR_SAV5_11N 0x0818
 /* BIT(11) should be 1 for 8703B *and* 8723D, which means LNA uses 4
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723x.h b/drivers/net/wireless/realtek/rtw88/rtw8723x.h
index 0fc70dfdfc8b..da674ab7cb78 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8723x.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw8723x.h
@@ -95,9 +95,11 @@ struct rtw8723x_efuse {
 		struct rtw8723xe_efuse e;
 		struct rtw8723xu_efuse u;
 		struct rtw8723xs_efuse s;
-	};
+	} __packed;
 } __packed;
 
+static_assert(sizeof(struct rtw8723x_efuse) == 0x120);
+
 #define RTW8723X_IQK_ADDA_REG_NUM	16
 #define RTW8723X_IQK_MAC8_REG_NUM	3
 #define RTW8723X_IQK_MAC32_REG_NUM	1
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.h b/drivers/net/wireless/realtek/rtw88/rtw8821c.h
index 954e93c8020d..ac9773b6dee5 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8821c.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.h
@@ -101,9 +101,11 @@ struct rtw8821c_efuse {
 		struct rtw8821ce_efuse e;
 		struct rtw8821cu_efuse u;
 		struct rtw8821cs_efuse s;
-	};
+	} __packed;
 } __packed;
 
+static_assert(sizeof(struct rtw8821c_efuse) == 0x200);
+
 static inline void
 _rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data)
 {
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.h b/drivers/net/wireless/realtek/rtw88/rtw8822b.h
index 9fca9ba67c90..656f8830a394 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822b.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.h
@@ -103,9 +103,11 @@ struct rtw8822b_efuse {
 		struct rtw8822be_efuse e;
 		struct rtw8822bu_efuse u;
 		struct rtw8822bs_efuse s;
-	};
+	} __packed;
 } __packed;
 
+static_assert(sizeof(struct rtw8822b_efuse) == 0x200);
+
 static inline void
 _rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data)
 {
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.h b/drivers/net/wireless/realtek/rtw88/rtw8822c.h
index fc62b67a15f2..e1423448c453 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.h
@@ -102,9 +102,11 @@ struct rtw8822c_efuse {
 		struct rtw8822ce_efuse e;
 		struct rtw8822cu_efuse u;
 		struct rtw8822cs_efuse s;
-	};
+	} __packed;
 } __packed;
 
+static_assert(sizeof(struct rtw8822c_efuse) == 0x19a);
+
 enum rtw8822c_dpk_agc_phase {
 	RTW_DPK_GAIN_CHECK,
 	RTW_DPK_GAIN_LARGE,
diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.h b/drivers/net/wireless/realtek/rtw88/rtw88xxa.h
index 09a45c1a4129..1b5297c942d8 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw88xxa.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.h
@@ -58,7 +58,7 @@ struct rtw88xxa_efuse {
 	union {
 		struct rtw8821au_efuse rtw8821au;
 		struct rtw8812au_efuse rtw8812au;
-	};
+	} __packed;
 } __packed;
 
 static_assert(sizeof(struct rtw88xxa_efuse) == 512);
-- 
2.25.1


^ permalink raw reply related

* [wireless-next:main] BUILD SUCCESS fa489a77e3267e05df95db96ba98e141ec07cbd9
From: kernel test robot @ 2026-04-11  7:01 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless

tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git main
branch HEAD: fa489a77e3267e05df95db96ba98e141ec07cbd9  wifi: cfg80211: Explicitly include <linux/export.h> in michael-mic.c

elapsed time: 818m

configs tested: 189
configs skipped: 2

The following configs have been built successfully.
More configs may be tested in the coming days.

tested configs:
alpha                             allnoconfig    gcc-15.2.0
alpha                            allyesconfig    gcc-15.2.0
alpha                               defconfig    gcc-15.2.0
arc                              allmodconfig    gcc-15.2.0
arc                               allnoconfig    gcc-15.2.0
arc                              allyesconfig    gcc-15.2.0
arc                                 defconfig    gcc-15.2.0
arc                   randconfig-001-20260411    gcc-12.5.0
arc                   randconfig-002-20260411    gcc-12.5.0
arm                               allnoconfig    clang-23
arm                               allnoconfig    gcc-15.2.0
arm                              allyesconfig    gcc-15.2.0
arm                                 defconfig    gcc-15.2.0
arm                   randconfig-001-20260411    gcc-12.5.0
arm                   randconfig-002-20260411    gcc-12.5.0
arm                   randconfig-003-20260411    gcc-12.5.0
arm                   randconfig-004-20260411    gcc-12.5.0
arm                        shmobile_defconfig    gcc-15.2.0
arm64                            allmodconfig    clang-19
arm64                             allnoconfig    gcc-15.2.0
arm64                               defconfig    gcc-15.2.0
arm64                 randconfig-001-20260411    clang-23
arm64                 randconfig-002-20260411    clang-23
arm64                 randconfig-003-20260411    clang-23
arm64                 randconfig-004-20260411    clang-23
csky                             allmodconfig    gcc-15.2.0
csky                              allnoconfig    gcc-15.2.0
csky                                defconfig    gcc-15.2.0
csky                  randconfig-001-20260411    clang-23
csky                  randconfig-002-20260411    clang-23
hexagon                          allmodconfig    clang-17
hexagon                          allmodconfig    gcc-15.2.0
hexagon                           allnoconfig    clang-23
hexagon                           allnoconfig    gcc-15.2.0
hexagon                             defconfig    gcc-15.2.0
hexagon               randconfig-001-20260411    gcc-14.3.0
hexagon               randconfig-002-20260411    gcc-14.3.0
i386                             allmodconfig    clang-20
i386                              allnoconfig    gcc-14
i386                              allnoconfig    gcc-15.2.0
i386                             allyesconfig    clang-20
i386        buildonly-randconfig-001-20260411    gcc-14
i386        buildonly-randconfig-002-20260411    gcc-14
i386        buildonly-randconfig-003-20260411    gcc-14
i386        buildonly-randconfig-004-20260411    gcc-14
i386        buildonly-randconfig-005-20260411    gcc-14
i386        buildonly-randconfig-006-20260411    gcc-14
i386                                defconfig    gcc-15.2.0
i386                  randconfig-001-20260411    clang-20
i386                  randconfig-002-20260411    clang-20
i386                  randconfig-003-20260411    clang-20
i386                  randconfig-004-20260411    clang-20
i386                  randconfig-005-20260411    clang-20
i386                  randconfig-006-20260411    clang-20
i386                  randconfig-007-20260411    clang-20
i386                  randconfig-011-20260411    clang-20
i386                  randconfig-012-20260411    clang-20
i386                  randconfig-013-20260411    clang-20
i386                  randconfig-014-20260411    clang-20
i386                  randconfig-015-20260411    clang-20
i386                  randconfig-016-20260411    clang-20
i386                  randconfig-017-20260411    clang-20
loongarch                        allmodconfig    clang-19
loongarch                         allnoconfig    clang-23
loongarch                         allnoconfig    gcc-15.2.0
loongarch                           defconfig    clang-19
loongarch             randconfig-001-20260411    gcc-14.3.0
loongarch             randconfig-002-20260411    gcc-14.3.0
m68k                             allmodconfig    gcc-15.2.0
m68k                              allnoconfig    gcc-15.2.0
m68k                             allyesconfig    gcc-15.2.0
m68k                                defconfig    clang-19
microblaze                        allnoconfig    gcc-15.2.0
microblaze                       allyesconfig    gcc-15.2.0
microblaze                          defconfig    clang-19
mips                             allmodconfig    gcc-15.2.0
mips                              allnoconfig    gcc-15.2.0
mips                             allyesconfig    gcc-15.2.0
nios2                            allmodconfig    clang-23
nios2                            allmodconfig    gcc-11.5.0
nios2                             allnoconfig    clang-23
nios2                             allnoconfig    gcc-11.5.0
nios2                               defconfig    clang-19
nios2                 randconfig-001-20260411    gcc-14.3.0
nios2                 randconfig-002-20260411    gcc-14.3.0
openrisc                         allmodconfig    clang-23
openrisc                         allmodconfig    gcc-15.2.0
openrisc                          allnoconfig    clang-23
openrisc                          allnoconfig    gcc-15.2.0
openrisc                            defconfig    gcc-15.2.0
parisc                           allmodconfig    gcc-15.2.0
parisc                            allnoconfig    clang-23
parisc                            allnoconfig    gcc-15.2.0
parisc                           allyesconfig    clang-19
parisc                           allyesconfig    gcc-15.2.0
parisc                              defconfig    gcc-15.2.0
parisc                randconfig-001-20260411    gcc-11.5.0
parisc                randconfig-002-20260411    gcc-11.5.0
parisc64                            defconfig    clang-19
powerpc                          allmodconfig    gcc-15.2.0
powerpc                           allnoconfig    clang-23
powerpc                           allnoconfig    gcc-15.2.0
powerpc               randconfig-001-20260411    gcc-11.5.0
powerpc               randconfig-002-20260411    gcc-11.5.0
powerpc64             randconfig-001-20260411    gcc-11.5.0
powerpc64             randconfig-002-20260411    gcc-11.5.0
riscv                            allmodconfig    clang-23
riscv                             allnoconfig    clang-23
riscv                             allnoconfig    gcc-15.2.0
riscv                            allyesconfig    clang-16
riscv                               defconfig    gcc-15.2.0
riscv                 randconfig-001-20260411    gcc-10.5.0
riscv                 randconfig-002-20260411    gcc-10.5.0
s390                             allmodconfig    clang-18
s390                             allmodconfig    clang-19
s390                              allnoconfig    clang-23
s390                             allyesconfig    gcc-15.2.0
s390                                defconfig    gcc-15.2.0
s390                  randconfig-001-20260411    gcc-10.5.0
s390                  randconfig-002-20260411    gcc-10.5.0
sh                               allmodconfig    gcc-15.2.0
sh                                allnoconfig    clang-23
sh                                allnoconfig    gcc-15.2.0
sh                               allyesconfig    clang-19
sh                               allyesconfig    gcc-15.2.0
sh                                  defconfig    gcc-14
sh                    randconfig-001-20260411    gcc-10.5.0
sh                    randconfig-002-20260411    gcc-10.5.0
sparc                             allnoconfig    clang-23
sparc                             allnoconfig    gcc-15.2.0
sparc                               defconfig    gcc-15.2.0
sparc                 randconfig-001-20260411    gcc-14
sparc                 randconfig-002-20260411    gcc-14
sparc64                          allmodconfig    clang-23
sparc64                             defconfig    gcc-14
sparc64               randconfig-001-20260411    gcc-14
sparc64               randconfig-002-20260411    gcc-14
um                               allmodconfig    clang-19
um                                allnoconfig    clang-23
um                               allyesconfig    gcc-14
um                               allyesconfig    gcc-15.2.0
um                                  defconfig    gcc-14
um                             i386_defconfig    gcc-14
um                    randconfig-001-20260411    gcc-14
um                    randconfig-002-20260411    gcc-14
um                           x86_64_defconfig    gcc-14
x86_64                           allmodconfig    clang-20
x86_64                            allnoconfig    clang-20
x86_64                            allnoconfig    clang-23
x86_64                           allyesconfig    clang-20
x86_64      buildonly-randconfig-001-20260411    gcc-14
x86_64      buildonly-randconfig-002-20260411    gcc-14
x86_64      buildonly-randconfig-003-20260411    gcc-14
x86_64      buildonly-randconfig-004-20260411    gcc-14
x86_64      buildonly-randconfig-005-20260411    gcc-14
x86_64      buildonly-randconfig-006-20260411    gcc-14
x86_64                              defconfig    gcc-14
x86_64                                  kexec    clang-20
x86_64                randconfig-001-20260411    gcc-14
x86_64                randconfig-002-20260411    gcc-14
x86_64                randconfig-003-20260411    gcc-14
x86_64                randconfig-004-20260411    gcc-14
x86_64                randconfig-005-20260411    gcc-14
x86_64                randconfig-006-20260411    gcc-14
x86_64                randconfig-011-20260411    clang-20
x86_64                randconfig-012-20260411    clang-20
x86_64                randconfig-013-20260411    clang-20
x86_64                randconfig-014-20260411    clang-20
x86_64                randconfig-015-20260411    clang-20
x86_64                randconfig-016-20260411    clang-20
x86_64                randconfig-071-20260411    clang-20
x86_64                randconfig-072-20260411    clang-20
x86_64                randconfig-073-20260411    clang-20
x86_64                randconfig-074-20260411    clang-20
x86_64                randconfig-075-20260411    clang-20
x86_64                randconfig-076-20260411    clang-20
x86_64                               rhel-9.4    clang-20
x86_64                           rhel-9.4-bpf    gcc-14
x86_64                          rhel-9.4-func    clang-20
x86_64                    rhel-9.4-kselftests    clang-20
x86_64                         rhel-9.4-kunit    gcc-14
x86_64                           rhel-9.4-ltp    gcc-14
x86_64                          rhel-9.4-rust    clang-20
xtensa                            allnoconfig    clang-23
xtensa                            allnoconfig    gcc-15.2.0
xtensa                           allyesconfig    clang-23
xtensa                           allyesconfig    gcc-15.2.0
xtensa                randconfig-001-20260411    gcc-14
xtensa                randconfig-002-20260411    gcc-14

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply

* [PATCH 1/1] add wake_up call inside if_usb_disconnect
From: Jakov Novak @ 2026-04-10 21:32 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kees Cook, Szymon Wilczek, Ingo Molnar, Johannes Berg,
	Thomas Gleixner, John W . Linville, Dan Williams, libertas-dev,
	linux-kernel, skhan, Jakov Novak, syzbot+c99d17aa44dbdba16ad2
In-Reply-To: <20260410213241.1177592-1-jakovnovak30@gmail.com>

Fixes: 954ee164f4f45
Reported-and-tested-by: syzbot+c99d17aa44dbdba16ad2@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=c99d17aa44dbdba16ad2
Signed-off-by: Jakov Novak <jakovnovak30@gmail.com>
---
 drivers/net/wireless/marvell/libertas/if_usb.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c
index 8a6bf1365cfa..245c902a7e42 100644
--- a/drivers/net/wireless/marvell/libertas/if_usb.c
+++ b/drivers/net/wireless/marvell/libertas/if_usb.c
@@ -310,6 +310,7 @@ static void if_usb_disconnect(struct usb_interface *intf)
 	struct lbs_private *priv = cardp->priv;
 
 	cardp->surprise_removed = 1;
+	wake_up(&cardp->fw_wq);
 
 	if (priv) {
 		lbs_stop_card(priv);
-- 
2.53.0


^ permalink raw reply related

* [PATCH 0/1] usb: fix bug in marvell libertas driver
From: Jakov Novak @ 2026-04-10 21:32 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kees Cook, Szymon Wilczek, Ingo Molnar, Johannes Berg,
	Thomas Gleixner, John W . Linville, Dan Williams, libertas-dev,
	linux-kernel, skhan, Jakov Novak

This patch fixes a bug inside the Marvell Libertas driver.
The problem was the if_usb_disconnect function not properly
calling wake_up(), which lead to if_usb_prog_firmware being
stuck on initialization. This caused the lbs_wait_for_firmware_load
to be stuck as well and to trigger the error message.
The solution was to add the wake_up() call inside if_usb_disconnect.

Jakov Novak (1):
  add wake_up call inside if_usb_disconnect

 drivers/net/wireless/marvell/libertas/if_usb.c | 1 +
 1 file changed, 1 insertion(+)

-- 
2.53.0


^ permalink raw reply

* [patch V1.1 11/38] misc: sgi-gru: Remove get_cycles() [ab]use
From: Thomas Gleixner @ 2026-04-10 20:56 UTC (permalink / raw)
  To: LKML
  Cc: Arnd Bergmann, x86, Lu Baolu, iommu, Michael Grzeschik, netdev,
	linux-wireless, Herbert Xu, linux-crypto, Vlastimil Babka,
	linux-mm, David Woodhouse, Bernie Thompson, linux-fbdev,
	Theodore Tso, linux-ext4, Andrew Morton, Uladzislau Rezki,
	Marco Elver, Dmitry Vyukov, kasan-dev, Andrey Ryabinin,
	Thomas Sailer, linux-hams, Jason A. Donenfeld, Richard Henderson,
	linux-alpha, Russell King, linux-arm-kernel, Catalin Marinas,
	Huacai Chen, loongarch, Geert Uytterhoeven, linux-m68k,
	Dinh Nguyen, Jonas Bonn, linux-openrisc, Helge Deller,
	linux-parisc, Michael Ellerman, linuxppc-dev, Paul Walmsley,
	linux-riscv, Heiko Carstens, linux-s390, David S. Miller,
	sparclinux
In-Reply-To: <20260410120318.320727701@kernel.org>

Calculating a timeout from get_cycles() is a historical leftover without
any functional requirement.

Use ktime_get() instead.

Signed-off-by: Thomas Gleixner <tglx@kernel.org>
---
V2: Fix typo
---
 drivers/misc/sgi-gru/gruhandles.c   |   20 ++++++++------------
 drivers/misc/sgi-gru/grukservices.c |    3 ++-
 drivers/misc/sgi-gru/grutlbpurge.c  |    5 ++---
 3 files changed, 12 insertions(+), 16 deletions(-)

--- a/drivers/misc/sgi-gru/gruhandles.c
+++ b/drivers/misc/sgi-gru/gruhandles.c
@@ -6,26 +6,22 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/timekeeping.h>
 #include "gru.h"
 #include "grulib.h"
 #include "grutables.h"
 
-/* 10 sec */
 #include <linux/sync_core.h>
-#include <asm/tsc.h>
-#define GRU_OPERATION_TIMEOUT	((cycles_t) tsc_khz*10*1000)
-#define CLKS2NSEC(c)		((c) * 1000000 / tsc_khz)
+
+#define GRU_OPERATION_TIMEOUT_NSEC	(((ktime_t)10 * NSEC_PER_SEC))
 
 /* Extract the status field from a kernel handle */
 #define GET_MSEG_HANDLE_STATUS(h)	(((*(unsigned long *)(h)) >> 16) & 3)
 
 struct mcs_op_statistic mcs_op_statistics[mcsop_last];
 
-static void update_mcs_stats(enum mcs_op op, unsigned long clks)
+static void update_mcs_stats(enum mcs_op op, unsigned long nsec)
 {
-	unsigned long nsec;
-
-	nsec = CLKS2NSEC(clks);
 	atomic_long_inc(&mcs_op_statistics[op].count);
 	atomic_long_add(nsec, &mcs_op_statistics[op].total);
 	if (mcs_op_statistics[op].max < nsec)
@@ -58,21 +54,21 @@ static void report_instruction_timeout(v
 
 static int wait_instruction_complete(void *h, enum mcs_op opc)
 {
+	ktime_t start_time = ktime_get();
 	int status;
-	unsigned long start_time = get_cycles();
 
 	while (1) {
 		cpu_relax();
 		status = GET_MSEG_HANDLE_STATUS(h);
 		if (status != CCHSTATUS_ACTIVE)
 			break;
-		if (GRU_OPERATION_TIMEOUT < (get_cycles() - start_time)) {
+		if (GRU_OPERATION_TIMEOUT_NSEC < (ktime_get() - start_time)) {
 			report_instruction_timeout(h);
-			start_time = get_cycles();
+			start_time = ktime_get();
 		}
 	}
 	if (gru_options & OPT_STATS)
-		update_mcs_stats(opc, get_cycles() - start_time);
+		update_mcs_stats(opc, (unsigned long)(ktime_get() - start_time));
 	return status;
 }
 
--- a/drivers/misc/sgi-gru/grukservices.c
+++ b/drivers/misc/sgi-gru/grukservices.c
@@ -20,6 +20,7 @@
 #include <linux/uaccess.h>
 #include <linux/delay.h>
 #include <linux/export.h>
+#include <linux/random.h>
 #include <asm/io_apic.h>
 #include "gru.h"
 #include "grulib.h"
@@ -1106,7 +1107,7 @@ static int quicktest3(unsigned long arg)
 	int ret = 0;
 
 	memset(buf2, 0, sizeof(buf2));
-	memset(buf1, get_cycles() & 255, sizeof(buf1));
+	memset(buf1, get_random_u32() & 255, sizeof(buf1));
 	gru_copy_gpa(uv_gpa(buf2), uv_gpa(buf1), BUFSIZE);
 	if (memcmp(buf1, buf2, BUFSIZE)) {
 		printk(KERN_DEBUG "GRU:%d quicktest3 error\n", smp_processor_id());
--- a/drivers/misc/sgi-gru/grutlbpurge.c
+++ b/drivers/misc/sgi-gru/grutlbpurge.c
@@ -22,13 +22,12 @@
 #include <linux/delay.h>
 #include <linux/timex.h>
 #include <linux/srcu.h>
+#include <linux/random.h>
 #include <asm/processor.h>
 #include "gru.h"
 #include "grutables.h"
 #include <asm/uv/uv_hub.h>
 
-#define gru_random()	get_cycles()
-
 /* ---------------------------------- TLB Invalidation functions --------
  * get_tgh_handle
  *
@@ -49,7 +48,7 @@ static inline int get_off_blade_tgh(stru
 	int n;
 
 	n = GRU_NUM_TGH - gru->gs_tgh_first_remote;
-	n = gru_random() % n;
+	n = get_random_u32() % n;
 	n += gru->gs_tgh_first_remote;
 	return n;
 }

^ permalink raw reply

* [patch V1.1 02/38] x86: Cleanup include recursion hell
From: Thomas Gleixner @ 2026-04-10 20:55 UTC (permalink / raw)
  To: LKML
  Cc: Arnd Bergmann, x86, Lu Baolu, iommu, Michael Grzeschik, netdev,
	linux-wireless, Herbert Xu, linux-crypto, Vlastimil Babka,
	linux-mm, David Woodhouse, Bernie Thompson, linux-fbdev,
	Theodore Tso, linux-ext4, Andrew Morton, Uladzislau Rezki,
	Marco Elver, Dmitry Vyukov, kasan-dev, Andrey Ryabinin,
	Thomas Sailer, linux-hams, Jason A. Donenfeld, Richard Henderson,
	linux-alpha, Russell King, linux-arm-kernel, Catalin Marinas,
	Huacai Chen, loongarch, Geert Uytterhoeven, linux-m68k,
	Dinh Nguyen, Jonas Bonn, linux-openrisc, Helge Deller,
	linux-parisc, Michael Ellerman, linuxppc-dev, Paul Walmsley,
	linux-riscv, Heiko Carstens, linux-s390, David S. Miller,
	sparclinux
In-Reply-To: <20260410120317.709923681@kernel.org>

Including a random architecture specific header which requires global
headers just to avoid including that header at the two usage sites is
really beyond lazy and tasteless. Including global headers just to get the
__percpu macro from linux/compiler_types.h falls into the same category.

Remove the linux/percpu.h and asm/cpumask.h includes from msr.h and smp.h
and fix the resulting fallout by a simple forward struct declaration and by
including the x86 specific asm/cpumask.h header where it is actually
required.

Signed-off-by: Thomas Gleixner <tglx@kernel.org>
---
V1.1: Fix PARAVIRT_XXL fallout....
---
 arch/x86/include/asm/cache.h             |    1 +
 arch/x86/include/asm/msr.h               |    5 +++--
 arch/x86/include/asm/paravirt.h          |    3 ++-
 arch/x86/include/asm/pvclock.h           |    1 +
 arch/x86/include/asm/smp.h               |    2 --
 arch/x86/include/asm/vdso/gettimeofday.h |    5 ++---
 arch/x86/kernel/cpu/mce/core.c           |    1 +
 arch/x86/kernel/nmi.c                    |    1 +
 arch/x86/kernel/smpboot.c                |    1 +
 9 files changed, 12 insertions(+), 8 deletions(-)

--- a/arch/x86/include/asm/cache.h
+++ b/arch/x86/include/asm/cache.h
@@ -2,6 +2,7 @@
 #ifndef _ASM_X86_CACHE_H
 #define _ASM_X86_CACHE_H
 
+#include <vdso/page.h>
 #include <linux/linkage.h>
 
 /* L1 cache line size */
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -8,12 +8,11 @@
 
 #include <asm/asm.h>
 #include <asm/errno.h>
-#include <asm/cpumask.h>
 #include <uapi/asm/msr.h>
 #include <asm/shared/msr.h>
 
+#include <linux/compiler_types.h>
 #include <linux/types.h>
-#include <linux/percpu.h>
 
 struct msr_info {
 	u32			msr_no;
@@ -256,6 +255,8 @@ int msr_set_bit(u32 msr, u8 bit);
 int msr_clear_bit(u32 msr, u8 bit);
 
 #ifdef CONFIG_SMP
+struct cpumask;
+
 int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
 int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
 int rdmsrq_on_cpu(unsigned int cpu, u32 msr_no, u64 *q);
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -16,9 +16,10 @@
 
 #ifndef __ASSEMBLER__
 #include <linux/types.h>
-#include <linux/cpumask.h>
 #include <asm/frame.h>
 
+struct cpumask;
+
 /* The paravirtualized I/O functions */
 static inline void slow_down_io(void)
 {
--- a/arch/x86/include/asm/pvclock.h
+++ b/arch/x86/include/asm/pvclock.h
@@ -2,6 +2,7 @@
 #ifndef _ASM_X86_PVCLOCK_H
 #define _ASM_X86_PVCLOCK_H
 
+#include <asm/barrier.h>
 #include <asm/clocksource.h>
 #include <asm/pvclock-abi.h>
 
--- a/arch/x86/include/asm/smp.h
+++ b/arch/x86/include/asm/smp.h
@@ -5,8 +5,6 @@
 #include <linux/cpumask.h>
 #include <linux/thread_info.h>
 
-#include <asm/cpumask.h>
-
 DECLARE_PER_CPU_CACHE_HOT(int, cpu_number);
 
 DECLARE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_sibling_map);
--- a/arch/x86/include/asm/vdso/gettimeofday.h
+++ b/arch/x86/include/asm/vdso/gettimeofday.h
@@ -11,13 +11,12 @@
 #define __ASM_VDSO_GETTIMEOFDAY_H
 
 #ifndef __ASSEMBLER__
-
+#include <clocksource/hyperv_timer.h>
 #include <uapi/linux/time.h>
+
 #include <asm/vgtod.h>
 #include <asm/unistd.h>
-#include <asm/msr.h>
 #include <asm/pvclock.h>
-#include <clocksource/hyperv_timer.h>
 #include <asm/vdso/sys_call.h>
 
 #define VDSO_HAS_TIME 1
--- a/arch/x86/kernel/cpu/mce/core.c
+++ b/arch/x86/kernel/cpu/mce/core.c
@@ -48,6 +48,7 @@
 #include <linux/vmcore_info.h>
 
 #include <asm/fred.h>
+#include <asm/cpumask.h>
 #include <asm/cpu_device_id.h>
 #include <asm/processor.h>
 #include <asm/traps.h>
--- a/arch/x86/kernel/nmi.c
+++ b/arch/x86/kernel/nmi.c
@@ -26,6 +26,7 @@
 #include <linux/sched/clock.h>
 #include <linux/kvm_types.h>
 
+#include <asm/cpumask.h>
 #include <asm/cpu_entry_area.h>
 #include <asm/traps.h>
 #include <asm/mach_traps.h>
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -70,6 +70,7 @@
 #include <asm/irq.h>
 #include <asm/realmode.h>
 #include <asm/cpu.h>
+#include <asm/cpumask.h>
 #include <asm/numa.h>
 #include <asm/tlbflush.h>
 #include <asm/mtrr.h>

^ permalink raw reply

* Re: [RFC PATCH 2/7] wifi: make EHT capa size check not read reserved bits
From: Johannes Berg @ 2026-04-10 20:35 UTC (permalink / raw)
  To: Pablo Martin-Gomez; +Cc: linux-wireless
In-Reply-To: <20260410190354.394742-3-pmartin-gomez@freebox.fr>

On Fri, 2026-04-10 at 21:03 +0200, Pablo Martin-Gomez wrote:
> 
>  drivers/net/wireless/ath/ath12k/mac.c |  3 +-
>  include/linux/ieee80211-eht.h         | 58 ++++++++++++++++-----------
>  net/mac80211/eht.c                    |  3 +-
>  net/mac80211/util.c                   |  8 ++--
>  net/wireless/nl80211.c                | 13 ++++--
> 

>  static inline bool
>  ieee80211_eht_capa_size_ok(const u8 *he_capa, const u8 *data, u8 len,
> -			   bool from_ap)
> +			   bool from_ap, enum nl80211_band band)

I don't see how this can build without adjusting net/mac80211/parse.c?

johannes

^ permalink raw reply

* Re: [RFC PATCH 1/7] wifi: nl80211: remove EHT IE size validation
From: Johannes Berg @ 2026-04-10 20:25 UTC (permalink / raw)
  To: Pablo Martin-Gomez; +Cc: linux-wireless
In-Reply-To: <20260410190354.394742-2-pmartin-gomez@freebox.fr>

On Fri, 2026-04-10 at 21:03 +0200, Pablo Martin-Gomez wrote:
> Remove ieee802_eht_capa_size_ok() calls from the middle of nl80211
> packet processing paths. There is no reason why EHT Capabilities elem
> size should be checked here while HE & UHR are not.

That's not right: NL80211_ATTR_HE_CAPABILITY and
NL80211_ATTR_UHR_CAPABILITY have policy validation functions. It's just
that NL80211_ATTR_EHT_CAPABILITY doesn't, because it cannot, because it
depends on the HE capability (validating EHT requires access to HE data,
and policy validation functions can't do that.)

johannes

^ permalink raw reply

* [RFC PATCH 7/7] wifi: mt76: do not read band-dependent reserved bits
From: Pablo Martin-Gomez @ 2026-04-10 19:03 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Pablo Martin-Gomez
In-Reply-To: <20260410190354.394742-1-pmartin-gomez@freebox.fr>

Bits in Supported Channel Width Set subfield of the HE PHY
Capabilities Information field and Support For 320 MHz in 6 GHz
of the EHT PHY Capabilities Information field are reserved depending on
the current band.

Check the current band to make sure the bits that are being read are not
reserved.

Signed-off-by: Pablo Martin-Gomez <pmartin-gomez@freebox.fr>
---
 drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
index 16420375112d..3b58fe86e1fc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
@@ -1544,7 +1544,8 @@ mt7996_mcu_sta_he_6g_tlv(struct sk_buff *skb,
 
 static void
 mt7996_mcu_sta_eht_tlv(struct sk_buff *skb,
-		       struct ieee80211_link_sta *link_sta)
+		       struct ieee80211_link_sta *link_sta,
+		       enum nl80211_band band)
 {
 	struct mt7996_sta *msta = (struct mt7996_sta *)link_sta->sta->drv_priv;
 	struct ieee80211_vif *vif = container_of((void *)msta->vif,
@@ -1569,11 +1570,12 @@ mt7996_mcu_sta_eht_tlv(struct sk_buff *skb,
 	eht->phy_cap_ext = cpu_to_le64(elem->phy_cap_info[8]);
 
 	if (vif->type != NL80211_IFTYPE_STATION &&
-	    (link_sta->he_cap.he_cap_elem.phy_cap_info[0] &
-	     (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
-	      IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
-	      IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
-	      IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)) == 0) {
+		((band == NL80211_BAND_2GHZ && (link_sta->he_cap.he_cap_elem.phy_cap_info[0] &
+		     IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G) == 0) ||
+		    (band != NL80211_BAND_2GHZ && (link_sta->he_cap.he_cap_elem.phy_cap_info[0] &
+		     (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
+		      IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
+		      IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)) == 0))) {
 		memcpy(eht->mcs_map_bw20, &mcs_map->only_20mhz,
 		       sizeof(eht->mcs_map_bw20));
 		return;
@@ -2773,7 +2775,7 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev,
 		/* starec he 6g*/
 		mt7996_mcu_sta_he_6g_tlv(skb, link_sta);
 		/* starec eht */
-		mt7996_mcu_sta_eht_tlv(skb, link_sta);
+		mt7996_mcu_sta_eht_tlv(skb, link_sta, link_conf->chanreq.oper.chan->band);
 		/* starec muru */
 		mt7996_mcu_sta_muru_tlv(dev, skb, link_conf, link_sta);
 
-- 
2.43.0


^ permalink raw reply related

* [RFC PATCH 6/7] wifi: ath12k: do not read band-dependent reserved bits
From: Pablo Martin-Gomez @ 2026-04-10 19:03 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Pablo Martin-Gomez
In-Reply-To: <20260410190354.394742-1-pmartin-gomez@freebox.fr>

Bits in Supported Channel Width Set subfield of the HE PHY
Capabilities Information field and Support For 320 MHz in 6 GHz
of the EHT PHY Capabilities Information field are reserved depending on
the current band.

Check the current band to make sure the bits that are being read are not
reserved.

Signed-off-by: Pablo Martin-Gomez <pmartin-gomez@freebox.fr>
---
 drivers/net/wireless/ath/ath12k/mac.c | 32 ++++++++++++++++-----------
 1 file changed, 19 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 6e4cfbb0e5bd..51b5a9ceff75 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -4,6 +4,7 @@
  * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
  */
 
+#include <linux/nl80211.h>
 #include <net/mac80211.h>
 #include <net/cfg80211.h>
 #include <linux/etherdevice.h>
@@ -8703,28 +8704,32 @@ static void
 ath12k_mac_copy_eht_mcs_nss(struct ath12k_band_cap *band_cap,
 			    struct ieee80211_eht_mcs_nss_supp *mcs_nss,
 			    const struct ieee80211_he_cap_elem *he_cap,
-			    const struct ieee80211_eht_cap_elem_fixed *eht_cap)
+			    const struct ieee80211_eht_cap_elem_fixed *eht_cap,
+			    enum nl80211_band band)
 {
-	if ((he_cap->phy_cap_info[0] &
-	     (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
-	      IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
+	if ((band == NL80211_BAND_2GHZ && (he_cap->phy_cap_info[0] &
+	     IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G) == 0) ||
+	    (band != NL80211_BAND_2GHZ && (he_cap->phy_cap_info[0] &
+	     (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
 	      IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
-	      IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)) == 0)
+	      IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)) == 0))
 		memcpy(&mcs_nss->only_20mhz, &band_cap->eht_mcs_20_only,
 		       sizeof(struct ieee80211_eht_mcs_nss_supp_20mhz_only));
 
-	if (he_cap->phy_cap_info[0] &
-	    (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
-	     IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G))
+	if ((band == NL80211_BAND_2GHZ && (he_cap->phy_cap_info[0] &
+	     IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G)) ||
+	    (band != NL80211_BAND_2GHZ && (he_cap->phy_cap_info[0] &
+	     IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)))
 		memcpy(&mcs_nss->bw._80, &band_cap->eht_mcs_80,
 		       sizeof(struct ieee80211_eht_mcs_nss_supp_bw));
 
-	if (he_cap->phy_cap_info[0] &
+	if (band != NL80211_BAND_2GHZ && he_cap->phy_cap_info[0] &
 	    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G)
 		memcpy(&mcs_nss->bw._160, &band_cap->eht_mcs_160,
 		       sizeof(struct ieee80211_eht_mcs_nss_supp_bw));
 
-	if (eht_cap->phy_cap_info[0] & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ)
+	if (band == NL80211_BAND_6GHZ &&
+	    eht_cap->phy_cap_info[0] & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ)
 		memcpy(&mcs_nss->bw._320, &band_cap->eht_mcs_320,
 		       sizeof(struct ieee80211_eht_mcs_nss_supp_bw));
 }
@@ -8809,7 +8814,8 @@ static void ath12k_mac_copy_eht_cap(struct ath12k *ar,
 				    struct ath12k_band_cap *band_cap,
 				    struct ieee80211_he_cap_elem *he_cap_elem,
 				    int iftype,
-				    struct ieee80211_sta_eht_cap *eht_cap)
+				    struct ieee80211_sta_eht_cap *eht_cap,
+				    enum nl80211_band band)
 {
 	struct ieee80211_eht_cap_elem_fixed *eht_cap_elem = &eht_cap->eht_cap_elem;
 
@@ -8852,7 +8858,7 @@ static void ath12k_mac_copy_eht_cap(struct ath12k *ar,
 	}
 
 	ath12k_mac_copy_eht_mcs_nss(band_cap, &eht_cap->eht_mcs_nss_supp,
-				    he_cap_elem, eht_cap_elem);
+				    he_cap_elem, eht_cap_elem, band);
 
 	if (eht_cap_elem->phy_cap_info[5] &
 	    IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT)
@@ -8888,7 +8894,7 @@ static int ath12k_mac_copy_sband_iftype_data(struct ath12k *ar,
 				ath12k_mac_setup_he_6ghz_cap(cap, band_cap);
 		}
 		ath12k_mac_copy_eht_cap(ar, band_cap, &he_cap->he_cap_elem, i,
-					&data[idx].eht_cap);
+					&data[idx].eht_cap, band);
 		idx++;
 	}
 
-- 
2.43.0


^ permalink raw reply related

* [RFC PATCH 5/7] wifi: ath11k: do not read band-dependent reserved bits
From: Pablo Martin-Gomez @ 2026-04-10 19:03 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Pablo Martin-Gomez
In-Reply-To: <20260410190354.394742-1-pmartin-gomez@freebox.fr>

Bits in Supported Channel Width Set subfield of the HE PHY
Capabilities Information field and Support For 320 MHz in 6 GHz
of the EHT PHY Capabilities Information field are reserved depending on
the current band.

Check the current band to make sure the bits that are being read are not
reserved.

Signed-off-by: Pablo Martin-Gomez <pmartin-gomez@freebox.fr>
---
 drivers/net/wireless/ath/ath11k/mac.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index a48b6bf1f29a..eb3dc5770077 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -2383,7 +2383,7 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar,
 		return;
 
 	arg->he_flag = true;
-	support_160 = !!(he_cap->he_cap_elem.phy_cap_info[0] &
+	support_160 = band != NL80211_BAND_2GHZ && !!(he_cap->he_cap_elem.phy_cap_info[0] &
 		  IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G);
 
 	/* Supported HE-MCS and NSS Set of peer he_cap is intersection with self he_cp */
@@ -8683,13 +8683,14 @@ ath11k_mac_has_single_legacy_rate(struct ath11k *ar,
 }
 
 static __le16
-ath11k_mac_get_tx_mcs_map(const struct ieee80211_sta_he_cap *he_cap)
+ath11k_mac_get_tx_mcs_map(const struct ieee80211_sta_he_cap *he_cap,
+			  enum nl80211_band band)
 {
-	if (he_cap->he_cap_elem.phy_cap_info[0] &
+	if (band != NL80211_BAND_2GHZ && he_cap->he_cap_elem.phy_cap_info[0] &
 	    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
 		return he_cap->he_mcs_nss_supp.tx_mcs_80p80;
 
-	if (he_cap->he_cap_elem.phy_cap_info[0] &
+	if (band != NL80211_BAND_2GHZ && he_cap->he_cap_elem.phy_cap_info[0] &
 	    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G)
 		return he_cap->he_mcs_nss_supp.tx_mcs_160;
 
@@ -8740,7 +8741,7 @@ ath11k_mac_bitrate_mask_get_single_nss(struct ath11k *ar,
 	if (!he_cap)
 		return false;
 
-	he_mcs_map = le16_to_cpu(ath11k_mac_get_tx_mcs_map(he_cap));
+	he_mcs_map = le16_to_cpu(ath11k_mac_get_tx_mcs_map(he_cap, sband->band));
 
 	for (i = 0; i < ARRAY_SIZE(mask->control[band].he_mcs); i++) {
 		if (mask->control[band].he_mcs[i] == 0)
-- 
2.43.0


^ permalink raw reply related

* [RFC PATCH 4/7] wifi: do not read band-dependent reserved bits
From: Pablo Martin-Gomez @ 2026-04-10 19:03 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Pablo Martin-Gomez
In-Reply-To: <20260410190354.394742-1-pmartin-gomez@freebox.fr>

Bits in Supported Channel Width Set subfield of the HE PHY
Capabilities Information field and Support For 320 MHz in 6 GHz
of the EHT PHY Capabilities Information field are reserved depending on
the current band.

Check the current band to make sure the bits that are being read are not
reserved.

Signed-off-by: Pablo Martin-Gomez <pmartin-gomez@freebox.fr>
---
 net/mac80211/debugfs_sta.c |  7 +++--
 net/mac80211/he.c          | 64 ++++++++++++++++++++------------------
 net/mac80211/mlme.c        |  5 +--
 net/mac80211/vht.c         |  2 +-
 4 files changed, 41 insertions(+), 37 deletions(-)

diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index ef75255d47d5..ea792660fe25 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -1003,13 +1003,14 @@ static ssize_t link_sta_he_capa_read(struct file *file, char __user *userbuf,
 	PRINT_NSS_SUPP(rx_mcs_80, "RX-MCS-80");
 	PRINT_NSS_SUPP(tx_mcs_80, "TX-MCS-80");
 
-	if (cap[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) {
+	if (band != NL80211_BAND_2GHZ &&
+	    cap[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) {
 		PRINT_NSS_SUPP(rx_mcs_160, "RX-MCS-160");
 		PRINT_NSS_SUPP(tx_mcs_160, "TX-MCS-160");
 	}
 
-	if (cap[0] &
-	    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) {
+	if (band != NL80211_BAND_2GHZ &&
+	    cap[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) {
 		PRINT_NSS_SUPP(rx_mcs_80p80, "RX-MCS-80P80");
 		PRINT_NSS_SUPP(tx_mcs_80p80, "TX-MCS-80P80");
 	}
diff --git a/net/mac80211/he.c b/net/mac80211/he.c
index 4f3bafceb243..95ec76eda951 100644
--- a/net/mac80211/he.c
+++ b/net/mac80211/he.c
@@ -168,38 +168,40 @@ _ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata,
 				      &own_he_cap.he_mcs_nss_supp.tx_mcs_80,
 				      &he_cap->he_mcs_nss_supp.tx_mcs_80);
 
-	own_160 = own_he_cap.he_cap_elem.phy_cap_info[0] &
-		  IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
-	peer_160 = he_cap->he_cap_elem.phy_cap_info[0] &
-		   IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
-
-	if (peer_160 && own_160) {
-		ieee80211_he_mcs_intersection(&own_he_cap.he_mcs_nss_supp.rx_mcs_160,
-					      &he_cap->he_mcs_nss_supp.rx_mcs_160,
-					      &own_he_cap.he_mcs_nss_supp.tx_mcs_160,
-					      &he_cap->he_mcs_nss_supp.tx_mcs_160);
-	} else if (peer_160 && !own_160) {
-		ieee80211_he_mcs_disable(&he_cap->he_mcs_nss_supp.rx_mcs_160);
-		ieee80211_he_mcs_disable(&he_cap->he_mcs_nss_supp.tx_mcs_160);
-		he_cap->he_cap_elem.phy_cap_info[0] &=
-			~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
-	}
+	if (band != NL80211_BAND_2GHZ) {
+		own_160 = own_he_cap.he_cap_elem.phy_cap_info[0] &
+			  IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
+		peer_160 = he_cap->he_cap_elem.phy_cap_info[0] &
+			   IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
+
+		if (peer_160 && own_160) {
+			ieee80211_he_mcs_intersection(&own_he_cap.he_mcs_nss_supp.rx_mcs_160,
+						      &he_cap->he_mcs_nss_supp.rx_mcs_160,
+						      &own_he_cap.he_mcs_nss_supp.tx_mcs_160,
+						      &he_cap->he_mcs_nss_supp.tx_mcs_160);
+		} else if (peer_160 && !own_160) {
+			ieee80211_he_mcs_disable(&he_cap->he_mcs_nss_supp.rx_mcs_160);
+			ieee80211_he_mcs_disable(&he_cap->he_mcs_nss_supp.tx_mcs_160);
+			he_cap->he_cap_elem.phy_cap_info[0] &=
+				~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
+		}
 
-	own_80p80 = own_he_cap.he_cap_elem.phy_cap_info[0] &
-		    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G;
-	peer_80p80 = he_cap->he_cap_elem.phy_cap_info[0] &
-		     IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G;
-
-	if (peer_80p80 && own_80p80) {
-		ieee80211_he_mcs_intersection(&own_he_cap.he_mcs_nss_supp.rx_mcs_80p80,
-					      &he_cap->he_mcs_nss_supp.rx_mcs_80p80,
-					      &own_he_cap.he_mcs_nss_supp.tx_mcs_80p80,
-					      &he_cap->he_mcs_nss_supp.tx_mcs_80p80);
-	} else if (peer_80p80 && !own_80p80) {
-		ieee80211_he_mcs_disable(&he_cap->he_mcs_nss_supp.rx_mcs_80p80);
-		ieee80211_he_mcs_disable(&he_cap->he_mcs_nss_supp.tx_mcs_80p80);
-		he_cap->he_cap_elem.phy_cap_info[0] &=
-			~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G;
+		own_80p80 = own_he_cap.he_cap_elem.phy_cap_info[0] &
+			    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G;
+		peer_80p80 = he_cap->he_cap_elem.phy_cap_info[0] &
+			     IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G;
+
+		if (peer_80p80 && own_80p80) {
+			ieee80211_he_mcs_intersection(&own_he_cap.he_mcs_nss_supp.rx_mcs_80p80,
+						      &he_cap->he_mcs_nss_supp.rx_mcs_80p80,
+						      &own_he_cap.he_mcs_nss_supp.tx_mcs_80p80,
+						      &he_cap->he_mcs_nss_supp.tx_mcs_80p80);
+		} else if (peer_80p80 && !own_80p80) {
+			ieee80211_he_mcs_disable(&he_cap->he_mcs_nss_supp.rx_mcs_80p80);
+			ieee80211_he_mcs_disable(&he_cap->he_mcs_nss_supp.tx_mcs_80p80);
+			he_cap->he_cap_elem.phy_cap_info[0] &=
+				~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G;
+		}
 	}
 }
 
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 4c1e5259837e..d840177fcd62 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -716,13 +716,14 @@ ieee80211_get_eht_cap_mcs_nss(const struct ieee80211_sta_he_cap *sta_he_cap,
 	case 0:
 		return sta_eht_cap->eht_mcs_nss_supp.bw._80.rx_tx_max_nss[idx];
 	case 1:
-		if (!(he_phy_cap0 &
+		if (band == NL80211_BAND_2GHZ || !(he_phy_cap0 &
 		      (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
 		       IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)))
 			return 0xff; /* pass check */
 		return sta_eht_cap->eht_mcs_nss_supp.bw._160.rx_tx_max_nss[idx];
 	case 2:
-		if (!(eht_phy_cap0 & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ))
+		if (band != NL80211_BAND_6GHZ ||
+		    !(eht_phy_cap0 & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ))
 			return 0xff; /* pass check */
 		return sta_eht_cap->eht_mcs_nss_supp.bw._320.rx_tx_max_nss[idx];
 	}
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
index a6570781740a..8b1e4bf43475 100644
--- a/net/mac80211/vht.c
+++ b/net/mac80211/vht.c
@@ -595,7 +595,7 @@ void ieee80211_sta_init_nss(struct link_sta_info *link_sta)
 			}
 		}
 
-		support_160 = he_cap->he_cap_elem.phy_cap_info[0] &
+		support_160 = band != NL80211_BAND_2GHZ && he_cap->he_cap_elem.phy_cap_info[0] &
 			      IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
 
 		if (support_160)
-- 
2.43.0


^ permalink raw reply related

* [RFC PATCH 3/7] wifi: make HE capa size check not read reserved bits
From: Pablo Martin-Gomez @ 2026-04-10 19:03 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Pablo Martin-Gomez
In-Reply-To: <20260410190354.394742-1-pmartin-gomez@freebox.fr>

ieee80211_he_mcs_nss_size() reads the value of reserved bits to deduce
the current band used assuming the reserved bits are set to 0.

However, Mediatek's chipsets MT7927 and MT7925 with Windows driver 5.4.0.3044
(and earlier versions) set the bits in Supported Channel Width Set subfield
of the HE PHY Capabilities Information field, regardless of the current band.
This causes the kernel to miscalculate mcs_nss_size to 3 bytes, resulting in
a incorrect rx/tx nss map, so the sta is believed to have 0 NSS for 160/320.

Pass the band to ieee80211_he_mcs_nss_size() to only read non reserved
bits in the Supported Channel Width Set subfield.

Signed-off-by: Pablo Martin-Gomez <pmartin-gomez@freebox.fr>
---
 include/linux/ieee80211-he.h | 21 ++++++++++++---------
 net/mac80211/he.c            |  9 ++++++---
 net/mac80211/mlme.c          |  2 +-
 net/mac80211/util.c          |  4 ++--
 4 files changed, 21 insertions(+), 15 deletions(-)

diff --git a/include/linux/ieee80211-he.h b/include/linux/ieee80211-he.h
index a08c446fbb04..7b2f160a15b5 100644
--- a/include/linux/ieee80211-he.h
+++ b/include/linux/ieee80211-he.h
@@ -17,6 +17,7 @@
 
 #include <linux/types.h>
 #include <linux/if_ether.h>
+#include <linux/nl80211.h>
 
 #define IEEE80211_TWT_CONTROL_NDP			BIT(0)
 #define IEEE80211_TWT_CONTROL_RESP_MODE			BIT(1)
@@ -452,17 +453,19 @@ enum ieee80211_he_highest_mcs_supported_subfield_enc {
 
 /* Calculate 802.11ax HE capabilities IE Tx/Rx HE MCS NSS Support Field size */
 static inline u8
-ieee80211_he_mcs_nss_size(const struct ieee80211_he_cap_elem *he_cap)
+ieee80211_he_mcs_nss_size(const struct ieee80211_he_cap_elem *he_cap, enum nl80211_band band)
 {
 	u8 count = 4;
 
-	if (he_cap->phy_cap_info[0] &
-	    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G)
-		count += 4;
+	if (band == NL80211_BAND_5GHZ || band == NL80211_BAND_6GHZ) {
+		if (he_cap->phy_cap_info[0] &
+		    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G)
+			count += 4;
 
-	if (he_cap->phy_cap_info[0] &
-	    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
-		count += 4;
+		if (he_cap->phy_cap_info[0] &
+		    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
+			count += 4;
+	}
 
 	return count;
 }
@@ -506,7 +509,7 @@ ieee80211_he_ppe_size(u8 ppe_thres_hdr, const u8 *phy_cap_info)
 	return n;
 }
 
-static inline bool ieee80211_he_capa_size_ok(const u8 *data, u8 len)
+static inline bool ieee80211_he_capa_size_ok(const u8 *data, u8 len, enum nl80211_band band)
 {
 	const struct ieee80211_he_cap_elem *he_cap_ie_elem = (const void *)data;
 	u8 needed = sizeof(*he_cap_ie_elem);
@@ -514,7 +517,7 @@ static inline bool ieee80211_he_capa_size_ok(const u8 *data, u8 len)
 	if (len < needed)
 		return false;
 
-	needed += ieee80211_he_mcs_nss_size(he_cap_ie_elem);
+	needed += ieee80211_he_mcs_nss_size(he_cap_ie_elem, band);
 	if (len < needed)
 		return false;
 
diff --git a/net/mac80211/he.c b/net/mac80211/he.c
index 93e0342cff4f..4f3bafceb243 100644
--- a/net/mac80211/he.c
+++ b/net/mac80211/he.c
@@ -8,6 +8,7 @@
 
 #include "ieee80211_i.h"
 #include "rate.h"
+#include <linux/nl80211.h>
 
 static void
 ieee80211_update_from_he_6ghz_capa(const struct ieee80211_he_6ghz_capa *he_6ghz_capa,
@@ -112,7 +113,8 @@ _ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata,
 				   const struct ieee80211_sta_he_cap *own_he_cap_ptr,
 				   const u8 *he_cap_ie, u8 he_cap_len,
 				   const struct ieee80211_he_6ghz_capa *he_6ghz_capa,
-				   struct link_sta_info *link_sta)
+				   struct link_sta_info *link_sta,
+				   enum nl80211_band band)
 {
 	struct ieee80211_sta_he_cap *he_cap = &link_sta->pub->he_cap;
 	struct ieee80211_sta_he_cap own_he_cap;
@@ -130,7 +132,7 @@ _ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata,
 	own_he_cap = *own_he_cap_ptr;
 
 	/* Make sure size is OK */
-	mcs_nss_size = ieee80211_he_mcs_nss_size(he_cap_ie_elem);
+	mcs_nss_size = ieee80211_he_mcs_nss_size(he_cap_ie_elem, band);
 	he_ppe_size =
 		ieee80211_he_ppe_size(he_cap_ie[sizeof(he_cap->he_cap_elem) +
 						mcs_nss_size],
@@ -215,7 +217,8 @@ ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata,
 					   he_cap_len,
 					   (sband->band == NL80211_BAND_6GHZ) ?
 						he_6ghz_capa : NULL,
-					   link_sta);
+					   link_sta,
+					   sband->band);
 }
 
 void
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 7fc5616cb244..4c1e5259837e 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -5933,7 +5933,7 @@ static u8 ieee80211_max_rx_chains(struct ieee80211_link_data *link,
 
 	/* skip one byte ext_tag_id */
 	he_cap = (void *)(he_cap_elem->data + 1);
-	mcs_nss_size = ieee80211_he_mcs_nss_size(he_cap);
+	mcs_nss_size = ieee80211_he_mcs_nss_size(he_cap, cbss->channel->band);
 
 	/* invalid HE IE */
 	if (he_cap_elem->datalen < 1 + mcs_nss_size + sizeof(*he_cap))
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 8e0c7ec95827..e2e44f3f4670 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2491,7 +2491,7 @@ u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata)
 	if (!he_cap)
 		return 0;
 
-	n = ieee80211_he_mcs_nss_size(&he_cap->he_cap_elem);
+	n = ieee80211_he_mcs_nss_size(&he_cap->he_cap_elem, sband->band);
 	return 2 + 1 +
 	       sizeof(he_cap->he_cap_elem) + n +
 	       ieee80211_he_ppe_size(he_cap->ppe_thres[0],
@@ -2568,7 +2568,7 @@ int ieee80211_put_he_cap(struct sk_buff *skb,
 	/* modify on stack first to calculate 'n' and 'ie_len' correctly */
 	ieee80211_get_adjusted_he_cap(conn, he_cap, &elem);
 
-	n = ieee80211_he_mcs_nss_size(&elem);
+	n = ieee80211_he_mcs_nss_size(&elem, sband->band);
 	ie_len = 2 + 1 +
 		 sizeof(he_cap->he_cap_elem) + n +
 		 ieee80211_he_ppe_size(he_cap->ppe_thres[0],
-- 
2.43.0


^ permalink raw reply related

* [RFC PATCH 2/7] wifi: make EHT capa size check not read reserved bits
From: Pablo Martin-Gomez @ 2026-04-10 19:03 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Pablo Martin-Gomez
In-Reply-To: <20260410190354.394742-1-pmartin-gomez@freebox.fr>

ieee80211_eht_mcs_nss_size() reads the value of reserved bits to deduce
the current band used assuming the reserved bits are set to 0.

However, Mediatek's chipsets MT7927 and MT7925 with Windows driver 5.4.0.3044
(and earlier versions) set the bits in Supported Channel Width Set subfield
of the HE PHY Capabilities Information field, regardless of the current band.
This causes the kernel to miscalculate mcs_nss_size to 3 bytes, resulting in
a incorrect rx/tx nss map, so the sta is believed to have 0 NSS for 160/320.

Pass the band to ieee80211_eht_mcs_nss_size() to only read non reserved
bits in the Supported Channel Width Set subfield.

Signed-off-by: Pablo Martin-Gomez <pmartin-gomez@freebox.fr>
---
 drivers/net/wireless/ath/ath12k/mac.c |  3 +-
 include/linux/ieee80211-eht.h         | 58 ++++++++++++++++-----------
 net/mac80211/eht.c                    |  3 +-
 net/mac80211/util.c                   |  8 ++--
 net/wireless/nl80211.c                | 13 ++++--
 5 files changed, 53 insertions(+), 32 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 553ec28b6aaa..6e4cfbb0e5bd 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -12537,7 +12537,8 @@ ath12k_mac_bitrate_mask_get_single_nss(struct ath12k *ar,
 
 	mcs_nss_len = ieee80211_eht_mcs_nss_size(&data->he_cap.he_cap_elem,
 						 &data->eht_cap.eht_cap_elem,
-						 false);
+						 false,
+						 sband->band);
 	if (mcs_nss_len == 4) {
 		/* 20 MHz only STA case */
 		const struct ieee80211_eht_mcs_nss_supp_20mhz_only *eht_mcs_nss =
diff --git a/include/linux/ieee80211-eht.h b/include/linux/ieee80211-eht.h
index 76e1cb80dcc7..d6f7072df5d6 100644
--- a/include/linux/ieee80211-eht.h
+++ b/include/linux/ieee80211-eht.h
@@ -17,6 +17,7 @@
 
 #include <linux/types.h>
 #include <linux/if_ether.h>
+#include <linux/nl80211.h>
 /* need HE definitions for the inlines here */
 #include <linux/ieee80211-he.h>
 
@@ -283,31 +284,41 @@ struct ieee80211_eht_operation_info {
 static inline u8
 ieee80211_eht_mcs_nss_size(const struct ieee80211_he_cap_elem *he_cap,
 			   const struct ieee80211_eht_cap_elem_fixed *eht_cap,
-			   bool from_ap)
+			   bool from_ap,
+			   enum nl80211_band band)
 {
 	u8 count = 0;
 
-	/* on 2.4 GHz, if it supports 40 MHz, the result is 3 */
-	if (he_cap->phy_cap_info[0] &
-	    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G)
-		return 3;
-
-	/* on 2.4 GHz, these three bits are reserved, so should be 0 */
-	if (he_cap->phy_cap_info[0] &
-	    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)
-		count += 3;
-
-	if (he_cap->phy_cap_info[0] &
-	    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G)
-		count += 3;
-
-	if (eht_cap->phy_cap_info[0] & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ)
-		count += 3;
-
-	if (count)
-		return count;
+	switch (band) {
+	case NL80211_BAND_2GHZ:
+		if (from_ap || he_cap->phy_cap_info[0] &
+		    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G)
+			count += 3;
+		else
+			count = 4;
+	break;
+	case NL80211_BAND_6GHZ:
+		if (eht_cap->phy_cap_info[0] & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ)
+			count += 3;
+	fallthrough;
+	case NL80211_BAND_5GHZ:
+		if (he_cap->phy_cap_info[0] &
+		    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G)
+			count += 3;
+		if (he_cap->phy_cap_info[0] &
+		    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)
+			count += 3;
+		if (!from_ap && (he_cap->phy_cap_info[0] &
+		    (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
+		    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
+		    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)) == 0)
+			count = 4;
+	break;
+	default:
+	break;
+	}
 
-	return from_ap ? 3 : 4;
+	return count;
 }
 
 /* 802.11be EHT PPE Thresholds */
@@ -344,7 +355,7 @@ ieee80211_eht_ppe_size(u16 ppe_thres_hdr, const u8 *phy_cap_info)
 
 static inline bool
 ieee80211_eht_capa_size_ok(const u8 *he_capa, const u8 *data, u8 len,
-			   bool from_ap)
+			   bool from_ap, enum nl80211_band band)
 {
 	const struct ieee80211_eht_cap_elem_fixed *elem = (const void *)data;
 	u8 needed = sizeof(struct ieee80211_eht_cap_elem_fixed);
@@ -354,7 +365,8 @@ ieee80211_eht_capa_size_ok(const u8 *he_capa, const u8 *data, u8 len,
 
 	needed += ieee80211_eht_mcs_nss_size((const void *)he_capa,
 					     (const void *)data,
-					     from_ap);
+					     from_ap,
+					     band);
 	if (len < needed)
 		return false;
 
diff --git a/net/mac80211/eht.c b/net/mac80211/eht.c
index e88f28edfd57..37b8387bd728 100644
--- a/net/mac80211/eht.c
+++ b/net/mac80211/eht.c
@@ -32,7 +32,8 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata,
 	mcs_nss_size = ieee80211_eht_mcs_nss_size(he_cap_ie_elem,
 						  &eht_cap_ie_elem->fixed,
 						  sdata->vif.type ==
-							NL80211_IFTYPE_STATION);
+							NL80211_IFTYPE_STATION,
+						  sband->band);
 
 	eht_total_size += mcs_nss_size;
 
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 8987a4504520..8e0c7ec95827 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -4431,7 +4431,8 @@ u8 ieee80211_ie_len_eht_cap(struct ieee80211_sub_if_data *sdata)
 
 	n = ieee80211_eht_mcs_nss_size(&he_cap->he_cap_elem,
 				       &eht_cap->eht_cap_elem,
-				       is_ap);
+				       is_ap,
+				       sband->band);
 	return 2 + 1 +
 	       sizeof(eht_cap->eht_cap_elem) + n +
 	       ieee80211_eht_ppe_size(eht_cap->eht_ppe_thres[0],
@@ -4464,7 +4465,8 @@ int ieee80211_put_eht_cap(struct sk_buff *skb,
 
 	orig_mcs_nss_len = ieee80211_eht_mcs_nss_size(&he_cap->he_cap_elem,
 						      &eht_cap->eht_cap_elem,
-						      for_ap);
+						      for_ap,
+						      sband->band);
 
 	ieee80211_get_adjusted_he_cap(conn, he_cap, &he);
 
@@ -4498,7 +4500,7 @@ int ieee80211_put_eht_cap(struct sk_buff *skb,
 		fixed.phy_cap_info[0] &=
 			~IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ;
 
-	mcs_nss_len = ieee80211_eht_mcs_nss_size(&he, &fixed, for_ap);
+	mcs_nss_len = ieee80211_eht_mcs_nss_size(&he, &fixed, for_ap, sband->band);
 	ppet_len = ieee80211_eht_ppe_size(eht_cap->eht_ppe_thres[0],
 					  fixed.phy_cap_info);
 
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index fb0bb4a957d9..3c29872073f8 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2137,7 +2137,8 @@ nl80211_send_iftype_data(struct sk_buff *msg,
 		mcs_nss_size =
 			ieee80211_eht_mcs_nss_size(&he_cap->he_cap_elem,
 						   &eht_cap->eht_cap_elem,
-						   is_ap);
+						   is_ap,
+						   sband->band);
 
 		ppe_thres_hdr = get_unaligned_le16(&eht_cap->eht_ppe_thres[0]);
 		ppe_thresh_size =
@@ -5919,7 +5920,8 @@ static bool eht_set_mcs_mask(struct genl_info *info, struct wireless_dev *wdev,
 	mcs_nss_len = ieee80211_eht_mcs_nss_size(&he_cap->he_cap_elem,
 						 &eht_cap->eht_cap_elem,
 						 wdev->iftype ==
-							NL80211_IFTYPE_STATION);
+							NL80211_IFTYPE_STATION,
+						 sband->band);
 
 	if (mcs_nss_len == 3) {
 		/* Supported iftypes for setting non-20 MHZ only EHT MCS */
@@ -6007,7 +6009,8 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
 		mcs_nss_len = ieee80211_eht_mcs_nss_size(&he_cap->he_cap_elem,
 							 &eht_cap->eht_cap_elem,
 							 wdev->iftype ==
-							 NL80211_IFTYPE_STATION);
+								NL80211_IFTYPE_STATION,
+							 sband->band);
 
 		eht_build_mcs_mask(info, eht_cap, mcs_nss_len,
 				   mask->control[i].eht_mcs);
@@ -6686,7 +6689,9 @@ static int nl80211_calculate_ap_params(struct cfg80211_ap_settings *params)
 		params->eht_cap = (void *)(cap->data + 1);
 		if (!ieee80211_eht_capa_size_ok((const u8 *)params->he_cap,
 						(const u8 *)params->eht_cap,
-						cap->datalen - 1, true))
+						cap->datalen - 1,
+						true,
+						params->chandef.chan->band))
 			return -EINVAL;
 	}
 	cap = cfg80211_find_ext_elem(WLAN_EID_EXT_EHT_OPERATION, ies, ies_len);
-- 
2.43.0


^ permalink raw reply related

* [RFC PATCH 1/7] wifi: nl80211: remove EHT IE size validation
From: Pablo Martin-Gomez @ 2026-04-10 19:03 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Pablo Martin-Gomez
In-Reply-To: <20260410190354.394742-1-pmartin-gomez@freebox.fr>

Remove ieee802_eht_capa_size_ok() calls from the middle of nl80211
packet processing paths. There is no reason why EHT Capabilities elem
size should be checked here while HE & UHR are not.

Signed-off-by: Pablo Martin-Gomez <pmartin-gomez@freebox.fr>
---
 net/wireless/nl80211.c | 18 ------------------
 1 file changed, 18 deletions(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index f334cdef8958..fb0bb4a957d9 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -8624,12 +8624,6 @@ static int nl80211_set_station_tdls(struct genl_info *info,
 				nla_data(info->attrs[NL80211_ATTR_EHT_CAPABILITY]);
 			params->link_sta_params.eht_capa_len =
 				nla_len(info->attrs[NL80211_ATTR_EHT_CAPABILITY]);
-
-			if (!ieee80211_eht_capa_size_ok((const u8 *)params->link_sta_params.he_capa,
-							(const u8 *)params->link_sta_params.eht_capa,
-							params->link_sta_params.eht_capa_len,
-							false))
-				return -EINVAL;
 		}
 	}
 
@@ -8984,12 +8978,6 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
 				nla_data(info->attrs[NL80211_ATTR_EHT_CAPABILITY]);
 			params.link_sta_params.eht_capa_len =
 				nla_len(info->attrs[NL80211_ATTR_EHT_CAPABILITY]);
-
-			if (!ieee80211_eht_capa_size_ok((const u8 *)params.link_sta_params.he_capa,
-							(const u8 *)params.link_sta_params.eht_capa,
-							params.link_sta_params.eht_capa_len,
-							false))
-				return -EINVAL;
 		}
 	}
 
@@ -18550,12 +18538,6 @@ nl80211_add_mod_link_station(struct sk_buff *skb, struct genl_info *info,
 				nla_data(info->attrs[NL80211_ATTR_EHT_CAPABILITY]);
 			params.eht_capa_len =
 				nla_len(info->attrs[NL80211_ATTR_EHT_CAPABILITY]);
-
-			if (!ieee80211_eht_capa_size_ok((const u8 *)params.he_capa,
-							(const u8 *)params.eht_capa,
-							params.eht_capa_len,
-							false))
-				return -EINVAL;
 		}
 	}
 
-- 
2.43.0


^ permalink raw reply related

* [RFC PATCH 0/7] Do not read band-dependent reserved bits
From: Pablo Martin-Gomez @ 2026-04-10 19:03 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Pablo Martin-Gomez

This series is a recyclying and extension of a previous attempt [1] to 
not read reserved bits depending on the current band for HE/EHT STAs.

Convention (section 9.2.2 of 802.11-2024) states that reserved bits
should be set to 0 (unless stated otherwise) and not to be read. Some
STAs do not respect the convention in transmission and the kernel do not
respect the convention in reception. The practical effect can be a
really low throughtput between a MT7927 Windows STA and a ath12k Linux AP.

I've been quite drastic and added a check of the current band before
read a bit that might be reserved whatever it's from an IE that was
received or an IE will be sent. I also removed checks where they didn't
make much sense and the current band was complicated/impossible to
retrieve. That is why I'm positing this as a RFC.

[1]: https://lore.kernel.org/linux-wireless/20250120114551.1542812-1-pmartin-gomez@freebox.fr/


Pablo Martin-Gomez (7):
  wifi: nl80211: remove EHT IE size validation
  wifi: make EHT capa size check not read reserved bits
  wifi: make HE capa size check not read reserved bits
  wifi: do not read band-dependent reserved bits
  wifi: ath11k: do not read band-dependent reserved bits
  wifi: ath12k: do not read band-dependent reserved bits
  wifi: mt76: do not read band-dependent reserved bits

 drivers/net/wireless/ath/ath11k/mac.c         | 11 +--
 drivers/net/wireless/ath/ath12k/mac.c         | 35 +++++----
 .../net/wireless/mediatek/mt76/mt7996/mcu.c   | 16 ++--
 include/linux/ieee80211-eht.h                 | 58 +++++++++------
 include/linux/ieee80211-he.h                  | 21 +++---
 net/mac80211/debugfs_sta.c                    |  7 +-
 net/mac80211/eht.c                            |  3 +-
 net/mac80211/he.c                             | 73 ++++++++++---------
 net/mac80211/mlme.c                           |  7 +-
 net/mac80211/util.c                           | 12 +--
 net/mac80211/vht.c                            |  2 +-
 net/wireless/nl80211.c                        | 31 +++-----
 12 files changed, 149 insertions(+), 127 deletions(-)

-- 
2.43.0


^ permalink raw reply

* [wireless:for-next] BUILD SUCCESS d65b175cfac64ee65506eea7fa573d291a9694ca
From: kernel test robot @ 2026-04-10 18:06 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: Johannes Berg, linux-wireless

tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless.git for-next
branch HEAD: d65b175cfac64ee65506eea7fa573d291a9694ca  Merge tag 'wireless-2026-04-08' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless

elapsed time: 730m

configs tested: 162
configs skipped: 2

The following configs have been built successfully.
More configs may be tested in the coming days.

tested configs:
alpha                             allnoconfig    gcc-15.2.0
alpha                            allyesconfig    gcc-15.2.0
alpha                               defconfig    gcc-15.2.0
arc                              allmodconfig    clang-16
arc                               allnoconfig    gcc-15.2.0
arc                              allyesconfig    clang-23
arc                                 defconfig    gcc-15.2.0
arc                   randconfig-001-20260410    gcc-8.5.0
arc                   randconfig-002-20260410    gcc-8.5.0
arm                               allnoconfig    gcc-15.2.0
arm                              allyesconfig    clang-16
arm                                 defconfig    gcc-15.2.0
arm                   randconfig-001-20260410    gcc-8.5.0
arm                   randconfig-002-20260410    gcc-8.5.0
arm                   randconfig-003-20260410    gcc-8.5.0
arm                   randconfig-004-20260410    gcc-8.5.0
arm64                            allmodconfig    clang-23
arm64                             allnoconfig    gcc-15.2.0
arm64                               defconfig    gcc-15.2.0
arm64                 randconfig-001-20260410    gcc-10.5.0
arm64                 randconfig-002-20260410    gcc-10.5.0
arm64                 randconfig-003-20260410    gcc-10.5.0
arm64                 randconfig-004-20260410    gcc-10.5.0
csky                             allmodconfig    gcc-15.2.0
csky                              allnoconfig    gcc-15.2.0
csky                                defconfig    gcc-15.2.0
csky                  randconfig-001-20260410    gcc-10.5.0
csky                  randconfig-002-20260410    gcc-10.5.0
hexagon                          allmodconfig    gcc-15.2.0
hexagon                           allnoconfig    gcc-15.2.0
hexagon                             defconfig    gcc-15.2.0
hexagon               randconfig-001-20260410    gcc-15.2.0
hexagon               randconfig-002-20260410    gcc-15.2.0
i386                             allmodconfig    clang-20
i386                              allnoconfig    gcc-15.2.0
i386                             allyesconfig    clang-20
i386        buildonly-randconfig-001-20260410    clang-20
i386        buildonly-randconfig-002-20260410    clang-20
i386        buildonly-randconfig-003-20260410    clang-20
i386        buildonly-randconfig-004-20260410    clang-20
i386        buildonly-randconfig-005-20260410    clang-20
i386        buildonly-randconfig-006-20260410    clang-20
i386                                defconfig    gcc-15.2.0
i386                  randconfig-001-20260410    gcc-14
i386                  randconfig-002-20260410    gcc-14
i386                  randconfig-003-20260410    gcc-14
i386                  randconfig-004-20260410    gcc-14
i386                  randconfig-005-20260410    gcc-14
i386                  randconfig-006-20260410    gcc-14
i386                  randconfig-007-20260410    gcc-14
i386                  randconfig-011-20260410    clang-20
i386                  randconfig-012-20260410    clang-20
i386                  randconfig-013-20260410    clang-20
i386                  randconfig-014-20260410    clang-20
i386                  randconfig-015-20260410    clang-20
i386                  randconfig-016-20260410    clang-20
i386                  randconfig-017-20260410    clang-20
loongarch                        allmodconfig    clang-23
loongarch                         allnoconfig    gcc-15.2.0
loongarch                           defconfig    clang-19
loongarch             randconfig-001-20260410    gcc-15.2.0
loongarch             randconfig-002-20260410    gcc-15.2.0
m68k                             allmodconfig    gcc-15.2.0
m68k                              allnoconfig    gcc-15.2.0
m68k                             allyesconfig    clang-16
m68k                                defconfig    clang-19
microblaze                        allnoconfig    gcc-15.2.0
microblaze                       allyesconfig    gcc-15.2.0
microblaze                          defconfig    clang-19
mips                             allmodconfig    gcc-15.2.0
mips                              allnoconfig    gcc-15.2.0
mips                             allyesconfig    gcc-15.2.0
mips                        vocore2_defconfig    clang-23
nios2                            allmodconfig    clang-23
nios2                             allnoconfig    clang-23
nios2                               defconfig    clang-19
nios2                 randconfig-001-20260410    gcc-15.2.0
nios2                 randconfig-002-20260410    gcc-15.2.0
openrisc                         allmodconfig    clang-23
openrisc                          allnoconfig    clang-23
openrisc                            defconfig    gcc-15.2.0
parisc                           allmodconfig    gcc-15.2.0
parisc                            allnoconfig    clang-23
parisc                           allyesconfig    clang-19
parisc                              defconfig    gcc-15.2.0
parisc                randconfig-001-20260410    gcc-14.3.0
parisc                randconfig-002-20260410    gcc-14.3.0
parisc64                            defconfig    clang-19
powerpc                          allmodconfig    gcc-15.2.0
powerpc                           allnoconfig    clang-23
powerpc               randconfig-001-20260410    gcc-14.3.0
powerpc               randconfig-002-20260410    gcc-14.3.0
powerpc64             randconfig-001-20260410    gcc-14.3.0
powerpc64             randconfig-002-20260410    gcc-14.3.0
riscv                            allmodconfig    clang-23
riscv                             allnoconfig    clang-23
riscv                            allyesconfig    clang-16
riscv                               defconfig    gcc-15.2.0
s390                             allmodconfig    clang-19
s390                              allnoconfig    clang-23
s390                             allyesconfig    gcc-15.2.0
s390                                defconfig    gcc-15.2.0
sh                               allmodconfig    gcc-15.2.0
sh                                allnoconfig    clang-23
sh                               allyesconfig    clang-19
sh                                  defconfig    gcc-14
sparc                             allnoconfig    clang-23
sparc                               defconfig    gcc-15.2.0
sparc                 randconfig-001-20260410    clang-23
sparc                 randconfig-002-20260410    clang-23
sparc64                          allmodconfig    clang-23
sparc64                             defconfig    gcc-14
sparc64               randconfig-001-20260410    clang-23
sparc64               randconfig-002-20260410    clang-23
um                               allmodconfig    clang-19
um                                allnoconfig    clang-23
um                               allyesconfig    gcc-15.2.0
um                                  defconfig    gcc-14
um                             i386_defconfig    gcc-14
um                    randconfig-001-20260410    clang-23
um                    randconfig-002-20260410    clang-23
um                           x86_64_defconfig    gcc-14
x86_64                           allmodconfig    clang-20
x86_64                            allnoconfig    clang-23
x86_64                           allyesconfig    clang-20
x86_64      buildonly-randconfig-001-20260410    clang-20
x86_64      buildonly-randconfig-002-20260410    clang-20
x86_64      buildonly-randconfig-003-20260410    clang-20
x86_64      buildonly-randconfig-004-20260410    clang-20
x86_64      buildonly-randconfig-005-20260410    clang-20
x86_64      buildonly-randconfig-006-20260410    clang-20
x86_64                              defconfig    gcc-14
x86_64                                  kexec    clang-20
x86_64                randconfig-001-20260410    clang-20
x86_64                randconfig-002-20260410    clang-20
x86_64                randconfig-003-20260410    clang-20
x86_64                randconfig-004-20260410    clang-20
x86_64                randconfig-005-20260410    clang-20
x86_64                randconfig-006-20260410    clang-20
x86_64                randconfig-011-20260410    gcc-14
x86_64                randconfig-012-20260410    gcc-14
x86_64                randconfig-013-20260410    gcc-14
x86_64                randconfig-014-20260410    gcc-14
x86_64                randconfig-015-20260410    gcc-14
x86_64                randconfig-016-20260410    gcc-14
x86_64                randconfig-071-20260410    clang-20
x86_64                randconfig-072-20260410    clang-20
x86_64                randconfig-073-20260410    clang-20
x86_64                randconfig-074-20260410    clang-20
x86_64                randconfig-075-20260410    clang-20
x86_64                randconfig-076-20260410    clang-20
x86_64                               rhel-9.4    clang-20
x86_64                           rhel-9.4-bpf    gcc-14
x86_64                          rhel-9.4-func    clang-20
x86_64                    rhel-9.4-kselftests    clang-20
x86_64                         rhel-9.4-kunit    gcc-14
x86_64                           rhel-9.4-ltp    gcc-14
x86_64                          rhel-9.4-rust    clang-20
xtensa                            allnoconfig    clang-23
xtensa                           allyesconfig    clang-23
xtensa                randconfig-001-20260410    clang-23
xtensa                randconfig-002-20260410    clang-23

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply

* Re: [PATCH ath-next 1/5] wifi: ath12k: handle thermal throttle stats WMI event
From: Jeff Johnson @ 2026-04-10 17:24 UTC (permalink / raw)
  To: Maharaja Kennadyrajan, ath12k; +Cc: linux-wireless
In-Reply-To: <20260331142446.2951809-2-maharaja.kennadyrajan@oss.qualcomm.com>

On 3/31/2026 7:24 AM, Maharaja Kennadyrajan wrote:
> +static void ath12k_wmi_thermal_throt_stats_event(struct ath12k_base *ab,
> +						 struct sk_buff *skb)
> +{
> +	const struct wmi_therm_throt_stats_event *ev;
> +	struct ath12k *ar;
> +
> +	const void **tb __free(kfree) = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);

please rebase on current ath-main, this interface changed with:
https://msgid.link/20260407095426.3285574-1-nico.escande@gmail.com

/jeff

^ permalink raw reply

* [PATCH v3 4/4] wifi: Update EML function documentation to remove EMLSR-specific references
From: Pablo Martin-Gomez @ 2026-04-10 17:04 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Pablo Martin-Gomez
In-Reply-To: <20260410170429.343617-1-pmartin-gomez@freebox.fr>

Transition Timeout is not specific to EMLSR, and is used by both EMLSR
and EMLMR mode.

Signed-off-by: Pablo Martin-Gomez <pmartin-gomez@freebox.fr>
---
 include/linux/ieee80211-eht.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/linux/ieee80211-eht.h b/include/linux/ieee80211-eht.h
index e24f95db6087..335e78bd4b5d 100644
--- a/include/linux/ieee80211-eht.h
+++ b/include/linux/ieee80211-eht.h
@@ -1236,11 +1236,11 @@ static inline u32 ieee80211_emlmr_trans_delay_in_us(u16 eml_cap)
 }
 
 /**
- * ieee80211_eml_trans_timeout_in_us - Fetch the EMLSR Transition
+ * ieee80211_eml_trans_timeout_in_us - Fetch the EML Transition
  *	timeout value in microseconds
  * @eml_cap: EML capabilities field value from common info field of
  *	the Multi-link element
- * Return: the EMLSR Transition timeout (in microseconds) encoded in
+ * Return: the EML Transition timeout (in microseconds) encoded in
  *	the EML Capabilities field
  */
 
-- 
2.43.0


^ permalink raw reply related

* [PATCH v3 3/4] wifi: Rename EMLSR delay constants and add EMLMR helpers and definitions
From: Pablo Martin-Gomez @ 2026-04-10 17:04 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Pablo Martin-Gomez
In-Reply-To: <20260410170429.343617-1-pmartin-gomez@freebox.fr>

In the final version of 802.11be-2024, Transition Delay and Padding
Delay subfield are for both EMLSR and EMLMR. Depending if the mode is
EMLSR or EMLMR, the interpretation of the encoded value might change.

Define all the constants and helpers to interpret delay subfields both
in EMLSR and EMLMR mode.

Signed-off-by: Pablo Martin-Gomez <pmartin-gomez@freebox.fr>
---
 .../net/wireless/intel/iwlwifi/mld/mac80211.c |   6 +-
 .../net/wireless/intel/iwlwifi/mvm/mac80211.c |   6 +-
 .../net/wireless/mediatek/mt76/mt7925/mcu.c   |   4 +-
 drivers/net/wireless/realtek/rtw89/fw.c       |   2 +-
 include/linux/ieee80211-eht.h                 | 102 ++++++++++++++++--
 net/mac80211/eht.c                            |   6 +-
 6 files changed, 104 insertions(+), 22 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
index e3aec814aa0d..5a7a6377b2b1 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
@@ -114,10 +114,10 @@ static const u8 ext_capa_base[IWL_MLD_STA_EXT_CAPA_SIZE] = {
 };
 
 #define IWL_MLD_EMLSR_CAPA	(IEEE80211_EML_CAP_EMLSR_SUPP | \
-				 IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_32US << \
-					__bf_shf(IEEE80211_EML_CAP_EMLSR_PADDING_DELAY) | \
+				 IEEE80211_EML_CAP_EML_PADDING_DELAY_32US << \
+					__bf_shf(IEEE80211_EML_CAP_EML_PADDING_DELAY) | \
 				 IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_64US << \
-					__bf_shf(IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY))
+					__bf_shf(IEEE80211_EML_CAP_EML_TRANSITION_DELAY))
 #define IWL_MLD_CAPA_OPS (FIELD_PREP_CONST( \
 			IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP, \
 			IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP_SAME) | \
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 1ec9807e4827..214e6d10081b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -263,10 +263,10 @@ static const u8 tm_if_types_ext_capa_sta[] = {
  */
 
 #define IWL_MVM_EMLSR_CAPA	(IEEE80211_EML_CAP_EMLSR_SUPP | \
-				 IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_32US << \
-					__bf_shf(IEEE80211_EML_CAP_EMLSR_PADDING_DELAY) | \
+				 IEEE80211_EML_CAP_EML_PADDING_DELAY_32US << \
+					__bf_shf(IEEE80211_EML_CAP_EML_PADDING_DELAY) | \
 				 IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_64US << \
-					__bf_shf(IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY))
+					__bf_shf(IEEE80211_EML_CAP_EML_TRANSITION_DELAY))
 #define IWL_MVM_MLD_CAPA_OPS (FIELD_PREP_CONST( \
 			IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP, \
 			IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP_SAME) | \
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index 37cdf3e8a067..22bad3cba8df 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -1880,8 +1880,8 @@ mt7925_mcu_sta_eht_mld_tlv(struct sk_buff *skb,
 
 	eml_cap = (vif->cfg.eml_cap & (IEEE80211_EML_CAP_EMLSR_SUPP |
 				       IEEE80211_EML_CAP_TRANSITION_TIMEOUT)) |
-		  (ext_capa->eml_capabilities & (IEEE80211_EML_CAP_EMLSR_PADDING_DELAY |
-						IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY));
+		  (ext_capa->eml_capabilities & (IEEE80211_EML_CAP_EML_PADDING_DELAY |
+						IEEE80211_EML_CAP_EML_TRANSITION_DELAY));
 
 	if (eml_cap & IEEE80211_EML_CAP_EMLSR_SUPP) {
 		eht_mld->eml_cap[0] = u16_get_bits(eml_cap, GENMASK(7, 0));
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index c52f9e11a8b2..1f624ea8cece 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -5022,7 +5022,7 @@ int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwv
 		     le32_encode_bits(0, RTW89_H2C_JOININFO_W1_EMLSR_CAB) |
 		     le32_encode_bits(0, RTW89_H2C_JOININFO_W1_NSTR_EN) |
 		     le32_encode_bits(init_ps, RTW89_H2C_JOININFO_W1_INIT_PWR_STATE) |
-		     le32_encode_bits(IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_256US,
+		     le32_encode_bits(IEEE80211_EML_CAP_EML_PADDING_DELAY_256US,
 				      RTW89_H2C_JOININFO_W1_EMLSR_PADDING) |
 		     le32_encode_bits(IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_256US,
 				      RTW89_H2C_JOININFO_W1_EMLSR_TRANS_DELAY) |
diff --git a/include/linux/ieee80211-eht.h b/include/linux/ieee80211-eht.h
index 6324d888073b..e24f95db6087 100644
--- a/include/linux/ieee80211-eht.h
+++ b/include/linux/ieee80211-eht.h
@@ -485,19 +485,27 @@ struct ieee80211_multi_link_elem {
 #define IEEE80211_MED_SYNC_DELAY_DEFAULT		0x10ac
 
 #define IEEE80211_EML_CAP_EMLSR_SUPP			0x0001
-#define IEEE80211_EML_CAP_EMLSR_PADDING_DELAY		0x000e
-#define  IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_0US		0
-#define  IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_32US		1
-#define  IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_64US		2
-#define  IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_128US		3
-#define  IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_256US		4
-#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY	0x0070
+#define IEEE80211_EML_CAP_EML_PADDING_DELAY		0x000e
+/* Described Tables 9-417i & 9-417k in 802.11be-2024, which have the same values */
+#define  IEEE80211_EML_CAP_EML_PADDING_DELAY_0US		0
+#define  IEEE80211_EML_CAP_EML_PADDING_DELAY_32US		1
+#define  IEEE80211_EML_CAP_EML_PADDING_DELAY_64US		2
+#define  IEEE80211_EML_CAP_EML_PADDING_DELAY_128US		3
+#define  IEEE80211_EML_CAP_EML_PADDING_DELAY_256US		4
+#define IEEE80211_EML_CAP_EML_TRANSITION_DELAY	0x0070
+/* Described in Table 9-417j in 802.11be-2024 */
 #define  IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_0US		0
 #define  IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_16US		1
 #define  IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_32US		2
 #define  IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_64US		3
 #define  IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_128US		4
 #define  IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_256US		5
+/* Described in Table 9-417l in 802.11be-2024 */
+#define  IEEE80211_EML_CAP_EMLMR_TRANSITION_DELAY_0US		0
+#define  IEEE80211_EML_CAP_EMLMR_TRANSITION_DELAY_32US		1
+#define  IEEE80211_EML_CAP_EMLMR_TRANSITION_DELAY_64US		2
+#define  IEEE80211_EML_CAP_EMLMR_TRANSITION_DELAY_128US		3
+#define  IEEE80211_EML_CAP_EMLMR_TRANSITION_DELAY_256US		4
 #define IEEE80211_EML_CAP_EMLMR_SUPPORT			0x0080
 #define IEEE80211_EML_CAP_TRANSITION_TIMEOUT		0x7800
 #define  IEEE80211_EML_CAP_TRANSITION_TIMEOUT_0			0
@@ -1114,14 +1122,20 @@ static inline bool ieee80211_tid_to_link_map_size_ok(const u8 *data, size_t len)
 
 static inline u32 ieee80211_emlsr_pad_delay_in_us(u16 eml_cap)
 {
+	u32 emlsr_supp =
+		u16_get_bits(eml_cap, IEEE80211_EML_CAP_EMLSR_SUPP);
+
+	if (!emlsr_supp)
+		return 0;
+
 	/* IEEE Std 802.11be-2024 Table 9-417i—Encoding of the EMLSR
 	 * Padding Delay subfield.
 	 */
 	u32 pad_delay = u16_get_bits(eml_cap,
-				     IEEE80211_EML_CAP_EMLSR_PADDING_DELAY);
+				     IEEE80211_EML_CAP_EML_PADDING_DELAY);
 
 	if (!pad_delay ||
-	    pad_delay > IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_256US)
+	    pad_delay > IEEE80211_EML_CAP_EML_PADDING_DELAY_256US)
 		return 0;
 
 	return 32 * (1 << (pad_delay - 1));
@@ -1138,12 +1152,18 @@ static inline u32 ieee80211_emlsr_pad_delay_in_us(u16 eml_cap)
 
 static inline u32 ieee80211_emlsr_trans_delay_in_us(u16 eml_cap)
 {
+	u32 emlsr_supp =
+		u16_get_bits(eml_cap, IEEE80211_EML_CAP_EMLSR_SUPP);
+
+	if (!emlsr_supp)
+		return 0;
+
 	/* IEEE Std 802.11be-2024 Table 9-417j—Encoding of the EMLSR
 	 * Transition Delay subfield.
 	 */
 	u32 trans_delay =
 		u16_get_bits(eml_cap,
-			     IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY);
+			     IEEE80211_EML_CAP_EML_TRANSITION_DELAY);
 
 	/* invalid values also just use 0 */
 	if (!trans_delay ||
@@ -1153,6 +1173,68 @@ static inline u32 ieee80211_emlsr_trans_delay_in_us(u16 eml_cap)
 	return 16 * (1 << (trans_delay - 1));
 }
 
+/**
+ * ieee80211_emlmr_pad_delay_in_us - Fetch the EMLMR Padding delay
+ *	in microseconds
+ * @eml_cap: EML capabilities field value from common info field of
+ *	the Multi-link element
+ * Return: the EMLMR Padding delay (in microseconds) encoded in the
+ *	EML Capabilities field
+ */
+
+static inline u32 ieee80211_emlmr_pad_delay_in_us(u16 eml_cap)
+{
+	u32 emlmr_supp =
+		u16_get_bits(eml_cap, IEEE80211_EML_CAP_EMLMR_SUPPORT);
+
+	if (!emlmr_supp)
+		return 0;
+
+	/* IEEE Std 802.11be-2024 Table 9-417k—Encoding of the EMLMR
+	 * Padding Delay subfield.
+	 */
+	u32 pad_delay = u16_get_bits(eml_cap,
+				     IEEE80211_EML_CAP_EML_PADDING_DELAY);
+
+	if (!pad_delay ||
+	    pad_delay > IEEE80211_EML_CAP_EML_PADDING_DELAY_256US)
+		return 0;
+
+	return 32 * (1 << (pad_delay - 1));
+}
+
+/**
+ * ieee80211_emlmr_trans_delay_in_us - Fetch the EMLMR Transition
+ *	delay in microseconds
+ * @eml_cap: EML capabilities field value from common info field of
+ *	the Multi-link element
+ * Return: the EMLMR Transition delay (in microseconds) encoded in the
+ *	EML Capabilities field
+ */
+
+static inline u32 ieee80211_emlmr_trans_delay_in_us(u16 eml_cap)
+{
+	u32 emlmr_supp =
+		u16_get_bits(eml_cap, IEEE80211_EML_CAP_EMLMR_SUPPORT);
+
+	if (!emlmr_supp)
+		return 0;
+
+	/* IEEE Std 802.11be-2024 Table 9-417l—Encoding of the EMLMR
+	 * Transition Delay subfield.
+	 */
+	u32 trans_delay =
+		u16_get_bits(eml_cap,
+			     IEEE80211_EML_CAP_EML_TRANSITION_DELAY);
+
+	/* invalid values also just use 0 */
+	if (!trans_delay ||
+	    trans_delay > IEEE80211_EML_CAP_EMLMR_TRANSITION_DELAY_256US)
+		return 0;
+
+	return 32 * (1 << (trans_delay - 1));
+}
+
 /**
  * ieee80211_eml_trans_timeout_in_us - Fetch the EMLSR Transition
  *	timeout value in microseconds
diff --git a/net/mac80211/eht.c b/net/mac80211/eht.c
index 768bfc4e737d..e88f28edfd57 100644
--- a/net/mac80211/eht.c
+++ b/net/mac80211/eht.c
@@ -204,7 +204,7 @@ void ieee80211_rx_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata,
 			pad_delay = u8_get_bits(ptr[2],
 						IEEE80211_EML_EMLSR_PAD_DELAY);
 			if (pad_delay >
-			    IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_256US)
+			    IEEE80211_EML_CAP_EML_PADDING_DELAY_256US)
 				return;
 
 			trans_delay = u8_get_bits(ptr[2],
@@ -217,11 +217,11 @@ void ieee80211_rx_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata,
 			sta->sta.eml_cap =
 				u8_replace_bits(sta->sta.eml_cap,
 						pad_delay,
-						IEEE80211_EML_CAP_EMLSR_PADDING_DELAY);
+						IEEE80211_EML_CAP_EML_PADDING_DELAY);
 			sta->sta.eml_cap =
 				u8_replace_bits(sta->sta.eml_cap,
 						trans_delay,
-						IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY);
+						IEEE80211_EML_CAP_EML_TRANSITION_DELAY);
 		}
 	}
 
-- 
2.43.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox