Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH] PCI: Disable NoSnoop and Relaxed ordering for Intel wireless BE200
From: Emmanuel Grumbach @ 2026-06-21  6:54 UTC (permalink / raw)
  To: linux-pci, helgaas; +Cc: linux-wireless, Miri Korenblit, Emmanuel Grumbach

The Intel wireless BE200 device fails to copy the TLP Attributes from a
Request to the Completion.
Since there is no caching involved the device anyway, disable the
NoSnoop and Relaxed ordering on the root port.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
---
 drivers/pci/quirks.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index c0242f3e9f06..e9f070d07b2c 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -4674,6 +4674,13 @@ static void quirk_chelsio_T5_disable_root_port_attributes(struct pci_dev *pdev)
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID,
 			 quirk_chelsio_T5_disable_root_port_attributes);
 
+/*
+ * The Intel wireless BE200 fails to copy TLP Attributes from a Request to the
+ * Completion it generates.
+ */
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x272b,
+			 quirk_disable_root_port_attributes);
+
 /*
  * pci_acs_ctrl_enabled - compare desired ACS controls with those provided
  *			  by a device
-- 
2.54.0


^ permalink raw reply related

* [PATCH] wifi: mac80211_hwsim: clamp virtio RX length before skb_put
From: Bryam Vargas via B4 Relay @ 2026-06-21  2:45 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, linux-kernel

From: Bryam Vargas <hexlabsecurity@proton.me>

hwsim_virtio_rx_work() passes the virtqueue used-ring length reported by
the device straight to skb_put() on a fixed-size receive skb. A backend
reporting a length larger than the skb tailroom drives skb_put() past the
buffer end and hits skb_over_panic() -- a host-triggerable guest panic
(denial of service).

Clamp the length to the skb's available room before skb_put(). A
conforming device never reports more than the posted buffer size, so valid
frames are unaffected; a truncated over-report then fails the
length/header checks in hwsim_virtio_handle_cmd() and is dropped, so
truncating rather than dropping here cannot be turned into a parsing
problem.

Fixes: 5d44fe7c9808 ("mac80211_hwsim: add frame transmission support over virtio")
Cc: stable@vger.kernel.org
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
---
 drivers/net/wireless/virtual/mac80211_hwsim_main.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/wireless/virtual/mac80211_hwsim_main.c b/drivers/net/wireless/virtual/mac80211_hwsim_main.c
index 0dd8a6c85953..5c1718277599 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim_main.c
+++ b/drivers/net/wireless/virtual/mac80211_hwsim_main.c
@@ -7289,6 +7289,7 @@ static void hwsim_virtio_rx_work(struct work_struct *work)
 
 	skb->data = skb->head;
 	skb_reset_tail_pointer(skb);
+	len = min(len, skb_end_offset(skb));
 	skb_put(skb, len);
 	hwsim_virtio_handle_cmd(skb);
 

---
base-commit: 1a3746ccbb0a97bed3c06ccde6b880013b1dddc1
change-id: 20260620-b4-disp-474bee37-bec999926dc2

Best regards,
-- 
Bryam Vargas <hexlabsecurity@proton.me>



^ permalink raw reply related

* [PATCH] wifi: cfg80211: Fix an error handling path in cfg80211_wext_siwscan()
From: Christophe JAILLET @ 2026-06-20 19:48 UTC (permalink / raw)
  To: Johannes Berg, John W. Linville
  Cc: linux-kernel, kernel-janitors, Christophe JAILLET, linux-wireless

If the test against IEEE80211_MAX_SSID_LEN fails, then 'creq' leaks.
Use the existing error handling path to fix it.

Fixes: 2a5193119269 ("cfg80211/nl80211: scanning (and mac80211 update to use it)")
Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
---
Compile tested only
---
 net/wireless/scan.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 05b7dc6b766c..38001684014d 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -3612,8 +3612,10 @@ int cfg80211_wext_siwscan(struct net_device *dev,
 	/* translate "Scan for SSID" request */
 	if (wreq) {
 		if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
-			if (wreq->essid_len > IEEE80211_MAX_SSID_LEN)
-				return -EINVAL;
+			if (wreq->essid_len > IEEE80211_MAX_SSID_LEN) {
+				err = -EINVAL;
+				goto out;
+			}
 			memcpy(creq->req.ssids[0].ssid, wreq->essid,
 			       wreq->essid_len);
 			creq->req.ssids[0].ssid_len = wreq->essid_len;
-- 
2.54.0


^ permalink raw reply related

* [PATCH] wifi: mt76: mt7915: guard HE capability lookups
From: Ruoyu Wang @ 2026-06-20 15:53 UTC (permalink / raw)
  To: Felix Fietkau, Lorenzo Bianconi, Ryder Lee, Shayne Chen,
	Sean Wang, Matthias Brugger, AngeloGioacchino Del Regno
  Cc: linux-wireless, linux-kernel, linux-arm-kernel, linux-mediatek,
	Ruoyu Wang

mt7915_mcu_bss_he_tlv() and mt7915_mcu_sta_bfer_tlv() both run after
checking HE support, then dereference the HE PHY capability returned by
mt76_connac_get_he_phy_cap(). That helper can return NULL when no
capability entry matches the vif type.

Fetch the capability before appending the TLV and skip the HE-specific
setup when no matching capability is available.

Fixes: e6d557a78b60 ("mt76: mt7915: rely on mt76_connac_get_phy utilities")
Signed-off-by: Ruoyu Wang <ruoyuw560@gmail.com>
---
 .../net/wireless/mediatek/mt76/mt7915/mcu.c    | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
index 318c38149463..391c91675130 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
@@ -595,6 +595,8 @@ mt7915_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
 	struct tlv *tlv;
 
 	cap = mt76_connac_get_he_phy_cap(phy->mt76, vif);
+	if (!cap)
+		return;
 
 	tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_HE_BASIC, sizeof(*he));
 
@@ -1177,13 +1179,12 @@ mt7915_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7915_phy *phy,
 }
 
 static void
-mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
-		       struct mt7915_phy *phy, struct sta_rec_bf *bf)
+mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta,
+		       const struct ieee80211_sta_he_cap *vc,
+		       struct sta_rec_bf *bf)
 {
 	struct ieee80211_sta_he_cap *pc = &sta->deflink.he_cap;
 	struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem;
-	const struct ieee80211_sta_he_cap *vc =
-		mt76_connac_get_he_phy_cap(phy->mt76, vif);
 	const struct ieee80211_he_cap_elem *ve = &vc->he_cap_elem;
 	u16 mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80);
 	u8 nss_mcs = mt7915_mcu_get_sta_nss(mcs_map);
@@ -1242,6 +1243,7 @@ mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
 {
 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
 	struct mt7915_phy *phy = mvif->phy;
+	const struct ieee80211_sta_he_cap *vc = NULL;
 	int tx_ant = hweight8(phy->mt76->chainmask) - 1;
 	struct sta_rec_bf *bf;
 	struct tlv *tlv;
@@ -1260,6 +1262,12 @@ mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
 	if (!ebf && !dev->ibf)
 		return;
 
+	if (sta->deflink.he_cap.has_he && ebf) {
+		vc = mt76_connac_get_he_phy_cap(phy->mt76, vif);
+		if (!vc)
+			return;
+	}
+
 	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BF, sizeof(*bf));
 	bf = (struct sta_rec_bf *)tlv;
 
@@ -1268,7 +1276,7 @@ mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
 	 * ht: iBF only, since mac80211 lacks of eBF support
 	 */
 	if (sta->deflink.he_cap.has_he && ebf)
-		mt7915_mcu_sta_bfer_he(sta, vif, phy, bf);
+		mt7915_mcu_sta_bfer_he(sta, vc, bf);
 	else if (sta->deflink.vht_cap.vht_supported)
 		mt7915_mcu_sta_bfer_vht(sta, phy, bf, ebf);
 	else if (sta->deflink.ht_cap.ht_supported)

^ permalink raw reply related

* Re: [PATCH v1 1/2] overflow: Allow to sum a few arguments at once
From: Andy Shevchenko @ 2026-06-20  6:56 UTC (permalink / raw)
  To: Kees Cook
  Cc: Johannes Berg, linux-hardening, linux-kernel, linux-wireless,
	Gustavo A. R. Silva, Johannes Berg
In-Reply-To: <202606192025.CF68F2E@keescook>

On Fri, Jun 19, 2026 at 08:27:33PM -0700, Kees Cook wrote:
> On Fri, Jun 19, 2026 at 09:45:18AM +0300, Andy Shevchenko wrote:
> > On Thu, Jun 18, 2026 at 08:47:34PM -0700, Kees Cook wrote:
> > > On Wed, Jun 17, 2026 at 01:12:36PM +0200, Andy Shevchenko wrote:

...

> > > > +#define __size_add4(addend1, addend2, addend3, addend4, addend5, ...)		\
> > > > +	__size_add(__size_add3(addend1,  addend2, addend3, addend4), addend5)
> > > 
> > > Is 4 the max seen in practice?
> > 
> > In patch 2 there are 5! In cover letter I also mentioned a new user
> > (there are actually three). And I remember seeing 3 somewhere else.
> 
> I feel like we should allow size_mul() to work this way too, though I
> don't find any users that would need it, so I guess just size_add()?

For now, yes. The array_size() can be modified as we have already two of them,
but I don't remember seeing more than 3, so it might look like an unneeded
churn.

> I'm fine for this to go via whatever tree is first to use it:
> 
> Acked-by: Kees Cook <kees@kernel.org>

Thanks!

Johannes, are you okay to take a new version (I assume the wish is to have
the balanced additions)? If so, I will prepare one.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply

* [PATCH v2] wifi: ipw2100: fix potential memory leak in ipw2100_pci_init_one()
From: Abdun Nihaal @ 2026-06-20  6:52 UTC (permalink / raw)
  To: stas.yakovlev; +Cc: Abdun Nihaal, linux-wireless, linux-kernel, stable

The memory allocated in the ipw2100_alloc_device() function is not freed
in some of the error paths in ipw2100_pci_init_one(). Fix that by
converting the direct return into a goto to the error path return.

The error path when pci_enable_device() fails cannot jump to fail, since
at this point priv is not set, so perform error handling inline.

Cc: stable@vger.kernel.org
Fixes: 2c86c275015c ("Add ipw2100 wireless driver.")
Signed-off-by: Abdun Nihaal <nihaal@cse.iitm.ac.in>
---
Compile tested only. Issue found using static analysis.

v1->v2:
- Converted the added goto fail statement into an inline error handling
  when pci_enable_device() fails, because Sashiko pointed out that there
  could be a null pointer dereference as the priv is only set after, but
  is dereferenced in the 'fail' error path.

Link to v1: https://patchwork.kernel.org/project/linux-wireless/patch/20260620055558.75740-1-nihaal@cse.iitm.ac.in/

 drivers/net/wireless/intel/ipw2x00/ipw2100.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c
index c11428485dcc..2b8a23865bfb 100644
--- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c
@@ -6157,6 +6157,8 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
 	if (err) {
 		printk(KERN_WARNING DRV_NAME
 		       "Error calling pci_enable_device.\n");
+		free_libipw(dev, 0);
+		pci_iounmap(pci_dev, ioaddr);
 		return err;
 	}
 
@@ -6169,16 +6171,14 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
 	if (err) {
 		printk(KERN_WARNING DRV_NAME
 		       "Error calling pci_set_dma_mask.\n");
-		pci_disable_device(pci_dev);
-		return err;
+		goto fail;
 	}
 
 	err = pci_request_regions(pci_dev, DRV_NAME);
 	if (err) {
 		printk(KERN_WARNING DRV_NAME
 		       "Error calling pci_request_regions.\n");
-		pci_disable_device(pci_dev);
-		return err;
+		goto fail;
 	}
 
 	/* We disable the RETRY_TIMEOUT register (0x41) to keep
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH] wifi: ipw2100: fix potential memory leak in ipw2100_pci_init_one()
From: Abdun Nihaal @ 2026-06-20  6:50 UTC (permalink / raw)
  To: stas.yakovlev; +Cc: linux-wireless, linux-kernel, stable
In-Reply-To: <20260620055558.75740-1-nihaal@cse.iitm.ac.in>

On Sat, Jun 20, 2026 at 11:25:54AM +0530, Abdun Nihaal wrote:
> The memory allocated in the ipw2100_alloc_device() function is not freed
> in some of the error paths in ipw2100_pci_init_one(). Fix that by
> converting the direct return into a goto to the error path return.
> 
> Cc: stable@vger.kernel.org
> Fixes: 2c86c275015c ("Add ipw2100 wireless driver.")
> Signed-off-by: Abdun Nihaal <nihaal@cse.iitm.ac.in>

Sashiko reports a null pointer dereference introduced by the above
patch, and I realized I made a mistake in the first goto error path.

https://sashiko.dev/#/patchset/20260620055558.75740-1-nihaal%40cse.iitm.ac.in

Please ignore this patch. I'll send a v2 with the correct fix.

Regards,
Nihaal

^ permalink raw reply

* [PATCH] wifi: ipw2100: fix potential memory leak in ipw2100_pci_init_one()
From: Abdun Nihaal @ 2026-06-20  5:55 UTC (permalink / raw)
  To: stas.yakovlev; +Cc: Abdun Nihaal, linux-wireless, linux-kernel, stable

The memory allocated in the ipw2100_alloc_device() function is not freed
in some of the error paths in ipw2100_pci_init_one(). Fix that by
converting the direct return into a goto to the error path return.

Cc: stable@vger.kernel.org
Fixes: 2c86c275015c ("Add ipw2100 wireless driver.")
Signed-off-by: Abdun Nihaal <nihaal@cse.iitm.ac.in>
---
Compile tested only. Issue found using static analysis.

 drivers/net/wireless/intel/ipw2x00/ipw2100.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c
index c11428485dcc..82280890f1c0 100644
--- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c
@@ -6157,7 +6157,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
 	if (err) {
 		printk(KERN_WARNING DRV_NAME
 		       "Error calling pci_enable_device.\n");
-		return err;
+		goto fail;
 	}
 
 	priv = libipw_priv(dev);
@@ -6169,16 +6169,14 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
 	if (err) {
 		printk(KERN_WARNING DRV_NAME
 		       "Error calling pci_set_dma_mask.\n");
-		pci_disable_device(pci_dev);
-		return err;
+		goto fail;
 	}
 
 	err = pci_request_regions(pci_dev, DRV_NAME);
 	if (err) {
 		printk(KERN_WARNING DRV_NAME
 		       "Error calling pci_request_regions.\n");
-		pci_disable_device(pci_dev);
-		return err;
+		goto fail;
 	}
 
 	/* We disable the RETRY_TIMEOUT register (0x41) to keep
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH v1 1/2] overflow: Allow to sum a few arguments at once
From: Kees Cook @ 2026-06-20  3:27 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Johannes Berg, linux-hardening, linux-kernel, linux-wireless,
	Gustavo A. R. Silva, Johannes Berg
In-Reply-To: <ajTlfuOFHXlA7xdu@ashevche-desk.local>

On Fri, Jun 19, 2026 at 09:45:18AM +0300, Andy Shevchenko wrote:
> On Thu, Jun 18, 2026 at 08:47:34PM -0700, Kees Cook wrote:
> > On Wed, Jun 17, 2026 at 01:12:36PM +0200, Andy Shevchenko wrote:
> > > Convert size_add() to take variadic argument, so we can simplify users
> > > with using a macro only once.
> > 
> > Oh, this is fun. I like it. :)
> 
> He-he :-)
> 
> ...
> 
> > > +#define __size_add4(addend1, addend2, addend3, addend4, addend5, ...)		\
> > > +	__size_add(__size_add3(addend1,  addend2, addend3, addend4), addend5)
> > 
> > Is 4 the max seen in practice?
> 
> In patch 2 there are 5! In cover letter I also mentioned a new user
> (there are actually three). And I remember seeing 3 somewhere else.

I feel like we should allow size_mul() to work this way too, though I
don't find any users that would need it, so I guess just size_add()?

I'm fine for this to go via whatever tree is first to use it:

Acked-by: Kees Cook <kees@kernel.org>


-- 
Kees Cook

^ permalink raw reply

* [PATCH wireless] wifi: rtlwifi: rtl8192du: check QoS TID before indexing tids
From: Runyu Xiao @ 2026-06-20  2:56 UTC (permalink / raw)
  To: Ping-Ke Shih, linux-wireless
  Cc: Bitterblue Smith, linux-kernel, Runyu Xiao, Jianhao Xu, stable

rtl92du_tx_fill_desc() uses ieee80211_get_tid() to read the QoS TID
from the 802.11 header and then uses it as an index into
sta_entry->tids[]. ieee80211_get_tid() returns the low 4-bit QoS TID
value, so the result can be in the range 0..15.

rtlwifi only allocates MAX_TID_COUNT entries for sta_entry->tids[], and
MAX_TID_COUNT is 9. A QoS TID greater than 8 therefore indexes past the
aggregation state array. Keep the default RTL_AGG_STOP state for
out-of-range TIDs, matching rtl92cu_tx_fill_desc().

This issue was detected by our static analysis tool and confirmed by
manual audit. UBSAN validation for the same bug pattern reports an
array-index-out-of-bounds access with index 10 for type
'rtl_tid_data [9]'.

Fixes: 8321424134a4 ("wifi: rtlwifi: Add rtl8192du/trx.{c,h}")
Cc: stable@vger.kernel.org
Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
---
 drivers/net/wireless/realtek/rtlwifi/rtl8192du/trx.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192du/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192du/trx.c
index 743ce0cfffe6..c608c51f1b78 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192du/trx.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192du/trx.c
@@ -106,7 +106,8 @@ void rtl92du_tx_fill_desc(struct ieee80211_hw *hw,
 	if (sta) {
 		sta_entry = (struct rtl_sta_info *)sta->drv_priv;
 		tid = ieee80211_get_tid(hdr);
-		agg_state = sta_entry->tids[tid].agg.agg_state;
+		if (tid < MAX_TID_COUNT)
+			agg_state = sta_entry->tids[tid].agg.agg_state;
 		ampdu_density = sta->deflink.ht_cap.ampdu_density;
 	}
 
-- 
2.34.1


^ permalink raw reply related

* [PATCH] wifi: mt76: mt7996: expose per-band MAC addresses to cfg80211
From: Kenneth Kasilag @ 2026-06-20  1:38 UTC (permalink / raw)
  To: Felix Fietkau, Lorenzo Bianconi
  Cc: Ryder Lee, Shayne Chen, Sean Wang, linux-wireless,
	Kenneth Kasilag

mt7996/mt7992 are single-wiphy, multi-band devices. The driver assigns
each band its own MAC address from a per-band EEPROM entry, or derives
it from the primary band's address when that entry is empty, however
only the primary band's is published as perm_addr. The per-band
addresses are not exposed to cfg80211, so consumers usually fall back
to deriving one from perm_addr.

Store each band's address in wiphy->addresses[], indexed by radio, so
cfg80211 exposes the address the hardware actually uses for that radio.
addresses[0] is the primary band and matches perm_addr, as cfg80211
requires.

Link: https://github.com/openwrt/openwrt/issues/23578
Tested-on: Gemtek W1700K (MT7996)
Signed-off-by: Kenneth Kasilag <kenneth@kasilag.me>
---
 drivers/net/wireless/mediatek/mt76/mt7996/init.c   | 3 +++
 drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h | 1 +
 2 files changed, 4 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
index d6f9aa1ab52d..dbea4887b7ad 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
@@ -463,6 +463,8 @@ mt7996_init_wiphy_band(struct ieee80211_hw *hw, struct mt7996_phy *phy)
 	radio->n_freq_range = 1;
 	radio->iface_combinations = &if_comb;
 	radio->n_iface_combinations = 1;
+	memcpy(dev->radio_addrs[n_radios].addr, phy->mt76->macaddr, ETH_ALEN);
+	hw->wiphy->n_addresses++;
 	hw->wiphy->n_radio++;
 
 	wiphy->available_antennas_rx |= phy->mt76->chainmask;
@@ -505,6 +507,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
 	wiphy->n_iface_combinations = 1;
 
 	wiphy->radio = dev->radios;
+	wiphy->addresses = dev->radio_addrs;
 
 	wiphy->reg_notifier = mt7996_regd_notifier;
 	wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
index 0d6488522ba7..cb5e60b25b89 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
@@ -411,6 +411,7 @@ struct mt7996_dev {
 	struct mt7996_phy *radio_phy[MT7996_MAX_RADIOS];
 	struct wiphy_radio radios[MT7996_MAX_RADIOS];
 	struct wiphy_radio_freq_range radio_freqs[MT7996_MAX_RADIOS];
+	struct mac_address radio_addrs[MT7996_MAX_RADIOS];
 
 	struct mt7996_hif *hif2;
 	struct mt7996_reg_desc reg;
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply related

* [PATCH] wifi: carl9170: clamp command response copy to the read buffer size
From: Doruk Tan Ozturk @ 2026-06-19 22:48 UTC (permalink / raw)
  To: Christian Lamparter, Johannes Berg, Jeff Johnson
  Cc: linux-wireless, linux-kernel, stable

carl9170_cmd_callback() copies len - 4 bytes from the device command
response into ar->readbuf, which was allocated by the caller with
ar->readlen bytes. When the firmware/device returns a response whose
payload is larger than the requested ar->readlen, the mismatch is only
logged (and the device is restarted via carl9170_restart()); the code
then still performs the full-length memcpy(), writing past the end of
ar->readbuf -- an out-of-bounds write driven by an attacker-controlled
(malicious/compromised) carl9170 USB device.

Clamp the copy to ar->readlen so an over-sized response can never write
past the caller's buffer. A response that fails the length check is
already discarded by the restart, so copying only the buffer-sized
prefix changes nothing for the valid path.

Reported-by: syzbot+5c1ca6ccaa1215781cac@syzkaller.appspotmail.com
Tested-by: syzbot+5c1ca6ccaa1215781cac@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=5c1ca6ccaa1215781cac
Fixes: a84fab3cbfdc ("carl9170: 802.11 rx/tx processing and usb backend")
Cc: stable@vger.kernel.org
Signed-off-by: Doruk Tan Ozturk <doruk@0sec.ai>
---
Verified with syzbot via "#syz test" against the public C reproducer
(Tested-by above); I do not have carl9170 hardware locally.

 drivers/net/wireless/ath/carl9170/rx.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
index 908c4c8..897e682 100644
--- a/drivers/net/wireless/ath/carl9170/rx.c
+++ b/drivers/net/wireless/ath/carl9170/rx.c
@@ -150,7 +150,8 @@ static void carl9170_cmd_callback(struct ar9170 *ar, u32 len, void *buffer)
 	spin_lock(&ar->cmd_lock);
 	if (ar->readbuf) {
 		if (len >= 4)
-			memcpy(ar->readbuf, buffer + 4, len - 4);
+			memcpy(ar->readbuf, buffer + 4,
+			       min_t(unsigned int, len - 4, ar->readlen));
 
 		ar->readbuf = NULL;
 	}
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH ath-next v2] wifi: ath12k: add QMI capability negotiation for dynamic memory mode
From: Rameshkumar Sundaram @ 2026-06-19 18:30 UTC (permalink / raw)
  To: Aaradhana Sahu, ath12k; +Cc: linux-wireless
In-Reply-To: <20260619065816.2139392-1-aaradhana.sahu@oss.qualcomm.com>

On 6/19/2026 12:28 PM, Aaradhana Sahu wrote:
> On AHB platforms, firmware operates in two modes: fixed-memory mode where
> firmware uses hardcoded addresses for memory regions such as BDF and does
> not request HOST_DDR memory from the host, and dynamic-memory mode where
> firmware expects the host to provide memory addresses including HOST_DDR
> after the Q6 read-only region and relies on host allocation for all memory
> types.
> 
> Introduce QMI capability negotiation to support both modes. Add a new QMI
> PHY capability flag dynamic_ddr_support which is advertised by firmware to
> indicate it supports dynamic memory mode. When the host detects this
> capability, set the dynamic_mem_support flag in the host capability message
> to signal the host is ready to provide dynamic memory allocation. This
> triggers firmware to send the HOST_DDR memory request and use the
> host-provided address.
> 
> For backward compatibility, if firmware doesn't advertise
> dynamic_ddr_support, the firmware continues to operate in fixed-memory mode
> where firmware uses predefined addresses.
> 
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1
> Tested-on: IPQ5332 hw1.0 AHB WLAN.WBE.1.6-01275-QCAHKSWPL_SILICONZ-1
> 
> Signed-off-by: Aaradhana Sahu <aaradhana.sahu@oss.qualcomm.com>
Reviewed-by: Rameshkumar Sundaram <rameshkumar.sundaram@oss.qualcomm.com>

^ permalink raw reply

* Re: [PATCH ath-next] wifi: ath12k: advertise ieee_link_id in vdev start MLO params
From: Rameshkumar Sundaram @ 2026-06-19 18:28 UTC (permalink / raw)
  To: Manish Dharanenthiran, ath12k
  Cc: linux-wireless, Hari Naraayana Desikan Kannan, Karthik M
In-Reply-To: <20260619-ieee_link_id-v1-1-36cf573cb81d@oss.qualcomm.com>

On 6/19/2026 11:25 AM, Manish Dharanenthiran wrote:
> Firmware builds the AP MLD partner profile from the hw_link_id passed in
> the vdev start parameters. However, hw_link_id is not always the same as
> the logical per-MLD ieee_link_id, since ieee_link_id is assigned per MLD
> and not per pdev.
> 
> This matters in mixed MLO and SLO setups. For example:
> 
>    MLD 1 - 5 GHz + 6 GHz (2-link MLO): ieee_link_id 0 and 1
>    MLD 2 - 6 GHz only    (1-link SLO): ieee_link_id 0
>    MLD 3 - 5 GHz only    (1-link SLO): ieee_link_id 0
> 
> The same physical 6 GHz radio can use ieee_link_id 1 for one
> MLD and ieee_link_id 0 for another. Pass the correct ieee_link_id to
> firmware so it can build accurate per-STA profile elements.
> 
> Add ieee_link_id to wmi_vdev_start_mlo_params for the self link and to
> wmi_partner_link_info for each partner link. Populate these fields in
> ath12k_mac_mlo_get_vdev_args() from the corresponding vdev link_id
> before encoding the WMI command.
> 
> Introduce two new flags in ML params to indicate to firmware when
> the new fields are valid:
> 
>    ATH12K_WMI_FLAG_MLO_IEEE_LINK_IDX_VALID         BIT(18) for the self link
>    ATH12K_WMI_FLAG_MLO_IEEE_LINK_IDX_VALID_PARTNER BIT(19) for partner links
> 
> Firmware parses ieee_link_id only when the matching flag is set.
> 
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1
> 
> Co-developed-by: Hari Naraayana Desikan Kannan <hari.kannan@oss.qualcomm.com>
> Signed-off-by: Hari Naraayana Desikan Kannan <hari.kannan@oss.qualcomm.com>
> Co-developed-by: Karthik M <karthik.m@oss.qualcomm.com>
> Signed-off-by: Karthik M <karthik.m@oss.qualcomm.com>
> Signed-off-by: Manish Dharanenthiran <manish.dharanenthiran@oss.qualcomm.com>
> ---
>   drivers/net/wireless/ath/ath12k/mac.c |  3 +++
>   drivers/net/wireless/ath/ath12k/wmi.c | 32 ++++++++++++++++++++------------
>   drivers/net/wireless/ath/ath12k/wmi.h |  7 +++++++
>   3 files changed, 30 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index af354bef5c0d..773ecd6da8e5 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -11253,6 +11253,8 @@ ath12k_mac_mlo_get_vdev_args(struct ath12k_link_vif *arvif,
>   
>   	ml_arg->assoc_link = arvif->is_sta_assoc_link;
>   
> +	ml_arg->ieee_link_id = arvif->link_id;
> +
>   	partner_info = ml_arg->partner_info;
>   
>   	links = ahvif->links_map;
> @@ -11276,6 +11278,7 @@ ath12k_mac_mlo_get_vdev_args(struct ath12k_link_vif *arvif,
>   
>   		partner_info->vdev_id = arvif_p->vdev_id;
>   		partner_info->hw_link_id = arvif_p->ar->pdev->hw_link_id;
> +		partner_info->ieee_link_id = arvif_p->link_id;
>   		ether_addr_copy(partner_info->addr, link_conf->addr);
>   		ml_arg->num_partner_links++;
>   		partner_info++;
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index 84a31b953db8..a0e8b5678ae3 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -1228,10 +1228,14 @@ int ath12k_wmi_vdev_start(struct ath12k *ar, struct wmi_vdev_start_req_arg *arg,
>   				   le32_encode_bits(arg->ml.mcast_link,
>   						    ATH12K_WMI_FLAG_MLO_MCAST_VDEV) |
>   				   le32_encode_bits(arg->ml.link_add,
> -						    ATH12K_WMI_FLAG_MLO_LINK_ADD);
> +						    ATH12K_WMI_FLAG_MLO_LINK_ADD) |
> +				   cpu_to_le32(ATH12K_WMI_FLAG_MLO_IEEE_LINK_IDX_VALID);
>   
> -		ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "vdev %d start ml flags 0x%x\n",
> -			   arg->vdev_id, ml_params->flags);
> +		ml_params->ieee_link_id = cpu_to_le32(arg->ml.ieee_link_id);
> +
> +		ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "vdev %d start link_id %d ml flags 0x%x\n",

%u for vdev and link_id ?
Also this part of change is not describe in commit text.

> +			   arg->vdev_id, arg->ml.ieee_link_id,
> +			   le32_to_cpu(ml_params->flags));
>   
>   		ptr += sizeof(*ml_params);
>   
> @@ -1244,19 +1248,23 @@ int ath12k_wmi_vdev_start(struct ath12k *ar, struct wmi_vdev_start_req_arg *arg,
>   		partner_info = ptr;
>   
>   		for (i = 0; i < arg->ml.num_partner_links; i++) {
> +			struct wmi_ml_partner_info *pinfo = &arg->ml.partner_info[i];
> +
>   			partner_info->tlv_header =
>   				ath12k_wmi_tlv_cmd_hdr(WMI_TAG_MLO_PARTNER_LINK_PARAMS,
>   						       sizeof(*partner_info));
> -			partner_info->vdev_id =
> -				cpu_to_le32(arg->ml.partner_info[i].vdev_id);
> -			partner_info->hw_link_id =
> -				cpu_to_le32(arg->ml.partner_info[i].hw_link_id);
> +			partner_info->vdev_id = cpu_to_le32(pinfo->vdev_id);
> +			partner_info->hw_link_id = cpu_to_le32(pinfo->hw_link_id);
>   			ether_addr_copy(partner_info->vdev_addr.addr,
> -					arg->ml.partner_info[i].addr);
> -
> -			ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "partner vdev %d hw_link_id %d macaddr%pM\n",
> -				   partner_info->vdev_id, partner_info->hw_link_id,
> -				   partner_info->vdev_addr.addr);
> +					pinfo->addr);
> +			partner_info->flags =
> +				cpu_to_le32(ATH12K_WMI_FLAG_MLO_IEEE_LINK_IDX_VALID_PARTNER);
> +			partner_info->ieee_link_id = cpu_to_le32(pinfo->ieee_link_id);
> +
> +			ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "partner vdev %d hw_link_id %d macaddr %pM link_id %d ml flags 0x%x\n",

%u for vdev_id, hw_link_id  and ieee_link_id ?

> +				   pinfo->vdev_id, pinfo->hw_link_id,
> +				   pinfo->addr, pinfo->ieee_link_id,
> +				   le32_to_cpu(partner_info->flags));
>   
>   			partner_info++;
>   		}
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
> index c452e3d57a29..51f3426e1fcd 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.h
> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
> @@ -2954,10 +2954,13 @@ struct wmi_vdev_create_mlo_params {
>   #define ATH12K_WMI_FLAG_MLO_EMLSR_SUPPORT		BIT(6)
>   #define ATH12K_WMI_FLAG_MLO_FORCED_INACTIVE		BIT(7)
>   #define ATH12K_WMI_FLAG_MLO_LINK_ADD			BIT(8)
> +#define ATH12K_WMI_FLAG_MLO_IEEE_LINK_IDX_VALID		BIT(18)
> +#define ATH12K_WMI_FLAG_MLO_IEEE_LINK_IDX_VALID_PARTNER	BIT(19)
>   
>   struct wmi_vdev_start_mlo_params {
>   	__le32 tlv_header;
>   	__le32 flags;
> +	__le32 ieee_link_id;
>   } __packed;
>   
>   struct wmi_partner_link_info {
> @@ -2965,6 +2968,8 @@ struct wmi_partner_link_info {
>   	__le32 vdev_id;
>   	__le32 hw_link_id;
>   	struct ath12k_wmi_mac_addr_params vdev_addr;
> +	__le32 flags;
> +	__le32 ieee_link_id;
>   } __packed;
>   
>   struct wmi_vdev_delete_cmd {
> @@ -3120,6 +3125,7 @@ struct wmi_ml_partner_info {
>   	bool primary_umac;
>   	bool logical_link_idx_valid;
>   	u32 logical_link_idx;
> +	u32 ieee_link_id;
>   };
>   
>   struct wmi_ml_arg {
> @@ -3127,6 +3133,7 @@ struct wmi_ml_arg {
>   	bool assoc_link;
>   	bool mcast_link;
>   	bool link_add;
> +	u32 ieee_link_id;
>   	u8 num_partner_links;
>   	struct wmi_ml_partner_info partner_info[ATH12K_WMI_MLO_MAX_LINKS];
>   };
> 
> ---
> base-commit: 63abe299b12b317dfee5bcd09037da4668a4431a
> change-id: 20260610-ieee_link_id-3424c332b216
> 
> 



--
Ramesh

^ permalink raw reply

* [PATCHv2 ath-next] wifi: ath9k: mark static arrays as const
From: Rosen Penev @ 2026-06-19 17:52 UTC (permalink / raw)
  To: linux-wireless; +Cc: Toke Høiland-Jørgensen, open list

PN9Data is a read-only lookup table and is never modified.  Adding const
lets the compiler place it in .rodata and prevents accidental writes.

Use the same treatment for bits_per_symbol. It's not modified either.

Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
 v2: mention bits_per_symbol.
 drivers/net/wireless/ath/ath9k/tx99.c | 16 ++++++++--------
 drivers/net/wireless/ath/ath9k/xmit.c |  2 +-
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c
index f2144fd39093..b52d84f6cbc9 100644
--- a/drivers/net/wireless/ath/ath9k/tx99.c
+++ b/drivers/net/wireless/ath/ath9k/tx99.c
@@ -39,14 +39,14 @@ static void ath9k_tx99_stop(struct ath_softc *sc)

 static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
 {
-	static u8 PN9Data[] = {0xff, 0x87, 0xb8, 0x59, 0xb7, 0xa1, 0xcc, 0x24,
-			       0x57, 0x5e, 0x4b, 0x9c, 0x0e, 0xe9, 0xea, 0x50,
-			       0x2a, 0xbe, 0xb4, 0x1b, 0xb6, 0xb0, 0x5d, 0xf1,
-			       0xe6, 0x9a, 0xe3, 0x45, 0xfd, 0x2c, 0x53, 0x18,
-			       0x0c, 0xca, 0xc9, 0xfb, 0x49, 0x37, 0xe5, 0xa8,
-			       0x51, 0x3b, 0x2f, 0x61, 0xaa, 0x72, 0x18, 0x84,
-			       0x02, 0x23, 0x23, 0xab, 0x63, 0x89, 0x51, 0xb3,
-			       0xe7, 0x8b, 0x72, 0x90, 0x4c, 0xe8, 0xfb, 0xc0};
+	static const u8 PN9Data[] = {0xff, 0x87, 0xb8, 0x59, 0xb7, 0xa1, 0xcc, 0x24,
+			             0x57, 0x5e, 0x4b, 0x9c, 0x0e, 0xe9, 0xea, 0x50,
+			             0x2a, 0xbe, 0xb4, 0x1b, 0xb6, 0xb0, 0x5d, 0xf1,
+			             0xe6, 0x9a, 0xe3, 0x45, 0xfd, 0x2c, 0x53, 0x18,
+			             0x0c, 0xca, 0xc9, 0xfb, 0x49, 0x37, 0xe5, 0xa8,
+			             0x51, 0x3b, 0x2f, 0x61, 0xaa, 0x72, 0x18, 0x84,
+			             0x02, 0x23, 0x23, 0xab, 0x63, 0x89, 0x51, 0xb3,
+			             0xe7, 0x8b, 0x72, 0x90, 0x4c, 0xe8, 0xfb, 0xc0};
 	u32 len = 1200;
 	struct ieee80211_tx_rate *rate;
 	struct ieee80211_hw *hw = sc->hw;
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 89d8b3178784..57e451548958 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -41,7 +41,7 @@
 #define ATH9K_PWRTBL_11NG_HT_SHIFT      12


-static u16 bits_per_symbol[][2] = {
+static const u16 bits_per_symbol[][2] = {
 	/* 20MHz 40MHz */
 	{    26,   54 },     /*  0: BPSK */
 	{    52,  108 },     /*  1: QPSK 1/2 */
--
2.54.0


^ permalink raw reply related

* [PATCH] wifi: cfg80211: cancel sched scan results work on unregister
From: Cen Zhang @ 2026-06-19 16:25 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, linux-kernel, baijiaju1990, zzzccc427

cfg80211_sched_scan_results() can queue rdev->sched_scan_res_wk from a
driver result notification while a scheduled scan request is present. The
work callback recovers the containing cfg80211_registered_device and then
locks the wiphy and walks the scheduled-scan request list.

wiphy_unregister() already makes the wiphy unreachable and drains rdev work
items before cfg80211_dev_free() can release the object, but it does not
drain sched_scan_res_wk. A queued or running result work item can therefore
cross the unregister/free boundary and access freed rdev state.

The buggy scenario involves two paths, with each column showing the order
within that path:

scheduled-scan result path:        unregister/free path:
1. cfg80211_sched_scan_results()   1. interface teardown stops and
   queues rdev->sched_scan_res_wk.    removes the scheduled scan request.
2. cfg80211_wq starts the work     2. wiphy_unregister() drains other
   item and recovers rdev.            rdev work items.
3. The worker locks rdev->wiphy    3. cfg80211_dev_free() destroys and
   and walks rdev state.              frees rdev.

Cancel sched_scan_res_wk in wiphy_unregister() alongside the other rdev
work items. cancel_work_sync() removes a pending result notification and
waits for an already running callback, so cfg80211_dev_free() cannot free
rdev while this work item is still active.

Validation reproduced this kernel report:
BUG: KASAN: use-after-free in cfg80211_sched_scan_results_wk+0x4a6/0x530
Workqueue: cfg80211 cfg80211_sched_scan_results_wk [cfg80211]
Read of size 8
Call trace:
  dump_stack_lvl+0x66/0xa0
  print_report+0xce/0x630
  cfg80211_sched_scan_results_wk+0x4a6/0x530
  srso_alias_return_thunk+0x5/0xfbef5
  __virt_addr_valid+0x224/0x430
  kasan_report+0xac/0xe0
  lockdep_hardirqs_on_prepare+0xea/0x1a0
  process_one_work+0x8d0/0x18f0 (kernel/workqueue.c:3212)
  lock_is_held_type+0x8f/0x100
  worker_thread+0x5ad/0xfd0
  __kthread_parkme+0xc6/0x200
  kthread+0x31e/0x410
  trace_hardirqs_on+0x1a/0x170
  ret_from_fork+0x576/0x810
  __switch_to+0x57e/0xe20
  __switch_to_asm+0x33/0x70
  ret_from_fork_asm+0x1a/0x30

Fixes: 807f8a8c3004 ("cfg80211/nl80211: add support for scheduled scans")
Assisted-by: Codex:gpt-5.5
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
---
 net/wireless/core.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/net/wireless/core.c b/net/wireless/core.c
index 3dcf63b04c41..2c729a7aca12 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -1335,6 +1335,7 @@ void wiphy_unregister(struct wiphy *wiphy)
 	/* this has nothing to do now but make sure it's gone */
 	cancel_work_sync(&rdev->wiphy_work);
 
+	cancel_work_sync(&rdev->sched_scan_res_wk);
 	cancel_work_sync(&rdev->rfkill_block);
 	cancel_work_sync(&rdev->conn_work);
 	flush_work(&rdev->event_work);
-- 
2.43.0


^ permalink raw reply related

* [PATCH] wifi: nl80211: serialize socket owner release with netdev teardown
From: Cen Zhang @ 2026-06-19 16:25 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, linux-kernel, baijiaju1990, zzzccc427

nl80211_netlink_notify() walks the cfg80211 wireless device list when a
NETLINK_GENERIC socket is released. If the socket owns a connection, the
notifier queues the embedded wdev->disconnect_wk work item.

NETDEV_GOING_DOWN tears the interface down and cancels disconnect_wk, and
NETDEV_UNREGISTER removes the wireless device from the cfg80211 list. There
is no ordering between those paths today, so the netlink notifier can pass
the conn_owner_nlportid check before teardown clears it, then queue
disconnect_wk after the NETDEV_GOING_DOWN cancel has already returned.
synchronize_net() only waits for the notifier to finish; it does not drain
the work that the notifier just queued.

The buggy scenario involves two paths, with each column showing the order
within that path:

NETLINK_URELEASE path:              netdev teardown path:
1. enter nl80211_netlink_notify()   1. run NETDEV_GOING_DOWN
2. match conn_owner_nlportid        2. clear connection owner state
3. get preempted before scheduling  3. cancel disconnect_wk
4. schedule disconnect_wk           4. unregister and free the netdev

Take RTNL while the notifier walks cfg80211 devices and schedules owner
cleanup work. Netdevice notifier delivery already runs under RTNL, so the
schedule and cancel are ordered: either the work is queued before
NETDEV_GOING_DOWN and the existing cancel drains it, or teardown runs first
and the notifier no longer queues work for that connection owner.

Validation reproduced this kernel report:
BUG: KASAN: use-after-free in cfg80211_autodisconnect_wk+0x338/0x3a0
Workqueue: events cfg80211_autodisconnect_wk [cfg80211]
Read of size 8
Call trace:
  dump_stack_lvl+0x66/0xa0
  print_report+0xce/0x630
  cfg80211_autodisconnect_wk+0x338/0x3a0
  srso_alias_return_thunk+0x5/0xfbef5
  __virt_addr_valid+0x224/0x430
  kasan_report+0xac/0xe0
  process_one_work+0x8d0/0x18f0 (kernel/workqueue.c:3212)
  lock_is_held_type+0x8f/0x100
  worker_thread+0x5ad/0xfd0
  __kthread_parkme+0xc6/0x200
  kthread+0x31e/0x410
  trace_hardirqs_on+0x1a/0x170
  ret_from_fork+0x576/0x810
  __switch_to+0x57e/0xe20
  __switch_to_asm+0x33/0x70
  ret_from_fork_asm+0x1a/0x30

Fixes: bd2522b16884 ("cfg80211: NL80211_ATTR_SOCKET_OWNER support for CMD_CONNECT")
Assisted-by: Codex:gpt-5.5
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
---
 net/wireless/nl80211.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 53b4b3f76697..1e30673d1e79 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -22920,6 +22920,11 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
 	if (state != NETLINK_URELEASE || notify->protocol != NETLINK_GENERIC)
 		return NOTIFY_DONE;
 
+	/*
+	 * Keep disconnect_wk scheduling ordered with NETDEV_GOING_DOWN's
+	 * cancel_work_sync() and NETDEV_UNREGISTER's wdev list removal.
+	 */
+	rtnl_lock();
 	rcu_read_lock();
 
 	list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
@@ -22961,6 +22966,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
 	}
 
 	rcu_read_unlock();
+	rtnl_unlock();
 
 	/*
 	 * It is possible that the user space process that is controlling the
-- 
2.43.0


^ permalink raw reply related

* [PATCH] wifi: mac80211_hwsim: remove radios from rhashtable before freeing
From: Cen Zhang @ 2026-06-19 16:24 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, linux-kernel, baijiaju1990, zzzccc427

mac80211_hwsim_new_radio() publishes each registered radio on the
hwsim_radios list and in hwsim_radios_rht. The generic-netlink and
virtio command paths use the rhashtable to find radios by address.

Most radio removal paths remove the hash entry while holding
hwsim_radio_lock before unregistering and freeing the radio. However,
mac80211_hwsim_free() only removes the list entry. During init error
unwinding after hwsim netlink and virtio registration, this can leave a
freed radio reachable from hwsim_radios_rht until the callback surfaces
are unpublished and the rhashtable is destroyed.

The buggy scenario involves two paths, with each column showing the order
within that path:

init error unwind path:              hwsim command path:
1. create and hash a radio           1. receive a command by address
2. hit a later init failure          2. look up hwsim_radios_rht
3. call mac80211_hwsim_free()        3. get the stale radio pointer
4. free the radio                    4. dereference the freed radio
5. unregister netlink and virtio

Remove each radio from hwsim_radios_rht in mac80211_hwsim_free(),
matching the other radio removal paths, before releasing the lock and
freeing the hw object.

Validation reproduced this kernel report:
BUG: KASAN: slab-use-after-free in memcmp+0x1ab/0x1d0

Call Trace:
 <TASK>
 dump_stack_lvl+0x66/0xa0
 print_report+0xce/0x630
 ? memcmp+0x1ab/0x1d0
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? __virt_addr_valid+0x224/0x430
 ? memcmp+0x1ab/0x1d0
 kasan_report+0xac/0xe0
 ? memcmp+0x1ab/0x1d0
 memcmp+0x1ab/0x1d0
 get_hwsim_data_ref_from_addr+0x15b/0x4d0 [mac80211_hwsim]
 hwsim_cloned_frame_received_nl+0x1ff/0xce0 [mac80211_hwsim]
 ? __pfx_hwsim_cloned_frame_received_nl+0x10/0x10 [mac80211_hwsim]
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? kasan_save_track+0x14/0x30
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? __kasan_kmalloc+0xaa/0xb0
 ? __nla_parse+0x24/0x30
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? genl_family_rcv_msg_attrs_parse.isra.0+0x17f/0x290
 genl_family_rcv_msg_doit+0x1e5/0x2c0
 ? __pfx_genl_family_rcv_msg_doit+0x10/0x10
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? kasan_save_stack+0x42/0x60
 ? kasan_save_stack+0x33/0x60
 ? kasan_save_track+0x14/0x30
 genl_rcv_msg+0x432/0x6f0
 ? __pfx_genl_rcv_msg+0x10/0x10
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? __pfx_hwsim_cloned_frame_received_nl+0x10/0x10 [mac80211_hwsim]
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? __lock_acquire+0x466/0x2260
 netlink_rcv_skb+0x124/0x350
 ? __pfx_genl_rcv_msg+0x10/0x10
 ? __pfx_netlink_rcv_skb+0x10/0x10
 ? lock_acquire+0x187/0x300
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? netlink_deliver_tap+0x150/0xac0
 genl_rcv+0x28/0x40
 netlink_unicast+0x47c/0x790
 ? __pfx_netlink_unicast+0x10/0x10
 netlink_sendmsg+0x767/0xc30
 ? __pfx_netlink_sendmsg+0x10/0x10
 ? lock_release+0xc8/0x290
 __sys_sendto+0x34f/0x3a0
 ? __pfx___sys_sendto+0x10/0x10
 ? lockdep_hardirqs_on_prepare+0xea/0x1a0
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? __x64_sys_poll+0x181/0x3e0
 ? __pfx___x64_sys_poll+0x10/0x10
 __x64_sys_sendto+0xe0/0x1c0
 ? srso_alias_return_thunk+0x5/0xfbef5
 ? trace_hardirqs_on+0x1a/0x170
 do_syscall_64+0x115/0x6a0
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Allocated by task 444:
 kasan_save_stack+0x33/0x60
 kasan_save_track+0x14/0x30
 __kasan_kmalloc+0xaa/0xb0
 __kmalloc_noprof+0x292/0x770
 p9_fcall_init+0xe5/0x400
 p9_tag_alloc+0x1b8/0x700
 p9_client_prepare_req+0x107/0x3e0
 p9_client_zc_rpc.constprop.0+0xf1/0x860
 p9_client_write+0x36d/0x780
 v9fs_issue_write+0xdd/0x170
 netfs_unbuffered_write+0x339/0x2680
 netfs_unbuffered_write_iter_locked+0x6c4/0x960
 netfs_unbuffered_write_iter+0x2d5/0x540
 vfs_write+0x5fb/0x1230
 ksys_write+0xf9/0x1d0
 do_syscall_64+0x115/0x6a0
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Freed by task 444:
 kasan_save_stack+0x33/0x60
 kasan_save_track+0x14/0x30
 kasan_save_free_info+0x3b/0x60

Fixes: c6509cc3b3e8 ("mac80211_hwsim: add hashtable with mac address keys for faster lookup")
Assisted-by: Codex:gpt-5.5
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
---
 drivers/net/wireless/virtual/mac80211_hwsim_main.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/net/wireless/virtual/mac80211_hwsim_main.c b/drivers/net/wireless/virtual/mac80211_hwsim_main.c
index 0dd8a6c85953..8e83ebdf4563 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim_main.c
+++ b/drivers/net/wireless/virtual/mac80211_hwsim_main.c
@@ -6274,6 +6274,9 @@ static void mac80211_hwsim_free(void)
 						struct mac80211_hwsim_data,
 						list))) {
 		list_del(&data->list);
+		rhashtable_remove_fast(&hwsim_radios_rht, &data->rht,
+				       hwsim_rht_params);
+		hwsim_radios_generation++;
 		spin_unlock_bh(&hwsim_radio_lock);
 		mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy),
 					 NULL);
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH wireless] wifi: rt2x00: avoid full teardown before work setup in probe
From: Stanislaw Gruszka @ 2026-06-19 14:31 UTC (permalink / raw)
  To: Runyu Xiao
  Cc: Gertjan van Wingerde, John W . Linville, Ivo van Doorn,
	linux-wireless, linux-kernel, stable
In-Reply-To: <20260619073104.1809161-1-runyu.xiao@seu.edu.cn>

Hi, 

On Fri, Jun 19, 2026 at 03:31:04PM +0800, Runyu Xiao wrote:
> rt2x00lib_probe_dev() uses the full rt2x00lib_remove_dev() teardown for
> all probe failures. However, drv_data allocation and workqueue allocation
> can fail before intf_work, autowakeup_work and sleep_work have been
> initialized.
> 
> Do not enter the full remove path until the probe has reached the point
> where those work items are set up. Return directly for drv_data allocation
> failure, and use a small early cleanup path for workqueue allocation
> failure.
>
> This issue was found by our static analysis tool and then confirmed by
> manual review of rt2x00lib_probe_dev() and rt2x00lib_remove_dev(). The
> early probe exits should not call a common teardown path that assumes the
> later work setup has already completed.
> 
> A QEMU PoC forced alloc_ordered_workqueue() to fail before the work
> initializers are reached. The resulting fail path entered
> rt2x00lib_remove_dev(), and DEBUG_OBJECTS reported invalid work drains with
> rt2x00lib_probe_dev() and rt2x00lib_remove_dev() in the stack.

Thanks for finding and fixing those bugs. The patch looks fine, but I think
it could be a bit simpler, see the comments below.

> Fixes: 1ebbc48520a0 ("rt2x00: Introduce concept of driver data in struct rt2x00_dev.")
> Fixes: 0439f5367c8d ("rt2x00: Move TX/RX work into dedicated workqueue")
> Cc: stable@vger.kernel.org
> Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
> ---
>  drivers/net/wireless/ralink/rt2x00/rt2x00dev.c | 12 ++++++++++--
>  1 file changed, 10 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
> index f8a6f9c968a1..847b64e586f6 100644
> --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
> +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
> @@ -1382,7 +1382,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
>  			                      GFP_KERNEL);
>  		if (!rt2x00dev->drv_data) {
>  			retval = -ENOMEM;
> -			goto exit;
> +			return retval;

This can be just "return -ENOMEM;"

>  		}
>  	}
>  
> @@ -1416,7 +1416,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
>  	    alloc_ordered_workqueue("%s", 0, wiphy_name(rt2x00dev->hw->wiphy));
>  	if (!rt2x00dev->workqueue) {
>  		retval = -ENOMEM;
> -		goto exit;
> +		goto exit_free_drv_data;
>  	}
>  
>  	INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
I think should be sufficient to move INIT_*WORK's lines before
alloc_ordered_workqueue() to avoid cancel_*_work_sync() on uninitialized data.
And other de-init code from rt2x00lib_remove_dev() should work fine at this
point.

Regards
Stanislaw
> @@ -1488,6 +1488,14 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
>  exit:
>  	rt2x00lib_remove_dev(rt2x00dev);
>  
> +	return retval;
> +
> +exit_free_drv_data:
> +	clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
> +
> +	kfree(rt2x00dev->drv_data);
> +	rt2x00dev->drv_data = NULL;
> +
>  	return retval;
>  }
>  EXPORT_SYMBOL_GPL(rt2x00lib_probe_dev);
> -- 
> 2.34.1
> 

^ permalink raw reply

* [PATCH wireless-next] wifi: cfg80211: remove WIPHY_FLAG_DISABLE_WEXT
From: Johannes Berg @ 2026-06-19 12:21 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

There are only two drivers left setting it, but they're
both also setting WIPHY_FLAG_SUPPORTS_MLO for the relevant
devices, so we can now remove WIPHY_FLAG_DISABLE_WEXT.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 drivers/net/wireless/ath/ath12k/mac.c     | 6 ------
 drivers/net/wireless/realtek/rtw89/core.c | 3 ---
 include/net/cfg80211.h                    | 3 +--
 net/wireless/wext-core.c                  | 6 ++----
 4 files changed, 3 insertions(+), 15 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index af354bef5c0d..9775a87b3db3 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -14871,12 +14871,6 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah)
 
 	wiphy->features |= NL80211_FEATURE_TX_POWER_INSERTION;
 
-	/* MLO is not yet supported so disable Wireless Extensions for now
-	 * to make sure ath12k users don't use it. This flag can be removed
-	 * once WIPHY_FLAG_SUPPORTS_MLO is enabled.
-	 */
-	wiphy->flags |= WIPHY_FLAG_DISABLE_WEXT;
-
 	/* Copy over MLO related capabilities received from
 	 * WMI_SERVICE_READY_EXT2_EVENT if single_chip_mlo_supp is set.
 	 */
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index 68dad6090f87..0f0e46cb4260 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -7432,9 +7432,6 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev)
 	if (!chip->support_rnr)
 		hw->wiphy->flags |= WIPHY_FLAG_SPLIT_SCAN_6GHZ;
 
-	if (chip->chip_gen == RTW89_CHIP_BE)
-		hw->wiphy->flags |= WIPHY_FLAG_DISABLE_WEXT;
-
 	if (rtwdev->support_mlo) {
 		hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_MLO;
 		hw->wiphy->iftype_ext_capab = rtw89_iftypes_ext_capa;
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 8188ad200de5..69bb864ac34d 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -5690,7 +5690,6 @@ struct cfg80211_ops {
  *	set this flag to update channels on beacon hints.
  * @WIPHY_FLAG_SUPPORTS_NSTR_NONPRIMARY: support connection to non-primary link
  *	of an NSTR mobile AP MLD.
- * @WIPHY_FLAG_DISABLE_WEXT: disable wireless extensions for this device
  */
 enum wiphy_flags {
 	WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK		= BIT(0),
@@ -5702,7 +5701,7 @@ enum wiphy_flags {
 	WIPHY_FLAG_4ADDR_STATION		= BIT(6),
 	WIPHY_FLAG_CONTROL_PORT_PROTOCOL	= BIT(7),
 	WIPHY_FLAG_IBSS_RSN			= BIT(8),
-	WIPHY_FLAG_DISABLE_WEXT			= BIT(9),
+	/* reuse bit 9 */
 	WIPHY_FLAG_MESH_AUTH			= BIT(10),
 	WIPHY_FLAG_SUPPORTS_EXT_KCK_32          = BIT(11),
 	WIPHY_FLAG_SUPPORTS_NSTR_NONPRIMARY	= BIT(12),
diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c
index c19dece2bc6e..db77912b3994 100644
--- a/net/wireless/wext-core.c
+++ b/net/wireless/wext-core.c
@@ -660,8 +660,7 @@ struct iw_statistics *get_wireless_stats(struct net_device *dev)
 	    dev->ieee80211_ptr->wiphy->wext &&
 	    dev->ieee80211_ptr->wiphy->wext->get_wireless_stats) {
 		wireless_warn_cfg80211_wext();
-		if (dev->ieee80211_ptr->wiphy->flags & (WIPHY_FLAG_SUPPORTS_MLO |
-							WIPHY_FLAG_DISABLE_WEXT))
+		if (dev->ieee80211_ptr->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO)
 			return NULL;
 		return dev->ieee80211_ptr->wiphy->wext->get_wireless_stats(dev);
 	}
@@ -703,8 +702,7 @@ static iw_handler get_handler(struct net_device *dev, unsigned int cmd)
 #ifdef CONFIG_CFG80211_WEXT
 	if (dev->ieee80211_ptr && dev->ieee80211_ptr->wiphy) {
 		wireless_warn_cfg80211_wext();
-		if (dev->ieee80211_ptr->wiphy->flags & (WIPHY_FLAG_SUPPORTS_MLO |
-							WIPHY_FLAG_DISABLE_WEXT))
+		if (dev->ieee80211_ptr->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO)
 			return NULL;
 		handlers = dev->ieee80211_ptr->wiphy->wext;
 	}
-- 
2.53.0


^ permalink raw reply related

* [PATCH ath-next] wifi: ath12k: reset REOQ LUT addresses before firmware stop
From: Aishwarya R @ 2026-06-19 12:07 UTC (permalink / raw)
  To: ath12k; +Cc: linux-wireless, Aishwarya R, P Praneesh

During module removal, REOQ LUT cleanup writes 0 to the REOQ/ML-REOQ
LUT address registers. That cleanup runs from ath12k_core_stop(),
after ath12k_qmi_firmware_stop() has already stopped the
firmware (mode OFF), so the register writes can hit an invalid target
access.

Move the REOQ LUT register reset before ath12k_qmi_firmware_stop(),
so the registers are cleared before stopping the firmware,
while register access is still valid.

Additionally, handle the error path where firmware-ready setup fails
after LUT programming but before core_stop() is reached, ensuring the
registers are properly reset in that case as well.

On the crash-recovery path, ath12k_core_reconfigure_on_crash() calls
ath12k_core_qmi_firmware_ready(), which re-enters ath12k_dp_setup()
and ath12k_dp_reoq_lut_setup(), so the LUT registers are reprogrammed
before use and stale values do not persist across recovery.

There is a brief window between the crash and when the LUT registers
are reprogrammed during recovery, during which the registers still hold
the freed DMA memory addresses. This is safe because the device is
non-functional in that window and will not initiate any DMA access
until firmware is restarted and the registers are reprogrammed.

No functional issue has been observed so far due to this sequence.
However, this change proactively avoids potential issues such as
invalid register accesses after firmware stop during module
removal and error handling.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1

Co-developed-by: P Praneesh <praneesh.p@oss.qualcomm.com>
Signed-off-by: P Praneesh <praneesh.p@oss.qualcomm.com>
Signed-off-by: Aishwarya R <aishwarya.r@oss.qualcomm.com>
---
 drivers/net/wireless/ath/ath12k/core.c |  5 ++++-
 drivers/net/wireless/ath/ath12k/dp.c   | 14 ++++++++++++--
 drivers/net/wireless/ath/ath12k/dp.h   |  1 +
 3 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 742d4fd1b598..efe37dc91afd 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -708,8 +708,10 @@ static void ath12k_core_stop(struct ath12k_base *ab)
 
 	ath12k_core_to_group_ref_put(ab);
 
-	if (!test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags))
+	if (!test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags)) {
+		ath12k_dp_reoq_lut_addr_reset(ath12k_ab_to_dp(ab));
 		ath12k_qmi_firmware_stop(ab);
+	}
 
 	ath12k_acpi_stop(ab);
 
@@ -1371,6 +1373,7 @@ int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab)
 	goto exit;
 
 err_deinit:
+	ath12k_dp_reoq_lut_addr_reset(ath12k_ab_to_dp(ab));
 	ath12k_dp_cmn_device_deinit(ath12k_ab_to_dp(ab));
 	mutex_unlock(&ab->core_lock);
 	mutex_unlock(&ag->mutex);
diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c
index af5f11fc1d84..fbc0788b37a0 100644
--- a/drivers/net/wireless/ath/ath12k/dp.c
+++ b/drivers/net/wireless/ath/ath12k/dp.c
@@ -1097,7 +1097,6 @@ static void ath12k_dp_reoq_lut_cleanup(struct ath12k_base *ab)
 		return;
 
 	if (dp->reoq_lut.vaddr_unaligned) {
-		ath12k_hal_write_reoq_lut_addr(ab, 0);
 		dma_free_coherent(ab->dev, dp->reoq_lut.size,
 				  dp->reoq_lut.vaddr_unaligned,
 				  dp->reoq_lut.paddr_unaligned);
@@ -1105,7 +1104,6 @@ static void ath12k_dp_reoq_lut_cleanup(struct ath12k_base *ab)
 	}
 
 	if (dp->ml_reoq_lut.vaddr_unaligned) {
-		ath12k_hal_write_ml_reoq_lut_addr(ab, 0);
 		dma_free_coherent(ab->dev, dp->ml_reoq_lut.size,
 				  dp->ml_reoq_lut.vaddr_unaligned,
 				  dp->ml_reoq_lut.paddr_unaligned);
@@ -1568,6 +1566,7 @@ static int ath12k_dp_setup(struct ath12k_base *ab)
 	ath12k_dp_rx_free(ab);
 
 fail_cmn_reoq_cleanup:
+	ath12k_dp_reoq_lut_addr_reset(dp);
 	ath12k_dp_reoq_lut_cleanup(ab);
 
 fail_cmn_srng_cleanup:
@@ -1627,3 +1626,14 @@ void ath12k_dp_cmn_hw_group_assign(struct ath12k_dp *dp,
 	dp->device_id = ab->device_id;
 	dp_hw_grp->dp[dp->device_id] = dp;
 }
+
+void ath12k_dp_reoq_lut_addr_reset(struct ath12k_dp *dp)
+{
+	struct ath12k_base *ab = dp->ab;
+
+	if (dp->reoq_lut.vaddr_unaligned)
+		ath12k_hal_write_reoq_lut_addr(ab, 0);
+
+	if (dp->ml_reoq_lut.vaddr_unaligned)
+		ath12k_hal_write_ml_reoq_lut_addr(ab, 0);
+}
diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h
index f8cfc7bb29dd..9b39146e65e1 100644
--- a/drivers/net/wireless/ath/ath12k/dp.h
+++ b/drivers/net/wireless/ath/ath12k/dp.h
@@ -701,4 +701,5 @@ struct ath12k_rx_desc_info *ath12k_dp_get_rx_desc(struct ath12k_dp *dp,
 						  u32 cookie);
 struct ath12k_tx_desc_info *ath12k_dp_get_tx_desc(struct ath12k_dp *dp,
 						  u32 desc_id);
+void ath12k_dp_reoq_lut_addr_reset(struct ath12k_dp *dp);
 #endif

base-commit: 972c4dd19cb92e03d75b66c426cfade07582a1ba
-- 
2.34.1


^ permalink raw reply related

* Re: [PATCH ath-next] ath9k: eeprom: alias vpdTableI onto vpdTableL to shrink stack frame
From: Toke Høiland-Jørgensen @ 2026-06-19 10:23 UTC (permalink / raw)
  To: Rosen Penev, Rosen Penev, linux-wireless
  Cc: Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt,
	open list,
	open list:CLANG/LLVM BUILD SUPPORT:Keyword:b(?i:clang|llvm)b
In-Reply-To: <DJCF38062Q69.1WQ853JSRMFQ9@gmail.com>

"Rosen Penev" <rosenp@gmail.com> writes:

> On Thu Jun 18, 2026 at 2:51 AM PDT, Toke Høiland-Jørgensen wrote:
>> Rosen Penev <rosenp@gmail.com> writes:
>>
>>> vpdTableL, vpdTableR, and vpdTableI are never live simultaneously.
>>> vpdTableL and vpdTableR are consumed during the frequency-interpolation
>>> step that writes vpdTableI; after the if/else they are never read
>>> again.  Reuse vpdTableL for the interpolated result (what was
>>> vpdTableI), reducing the stack frame by one 256-byte array.
>>>
>>> The read-via-write in the else branch is safe: ath9k_hw_interpolate()
>>> receives vpdTableL[i][j] by value as a function argument before the
>>> return value is written back to vpdTableL[i][j].
>>>
>>> Stack frame size change (x86_64, clang):
>>>   before: 0x440 (1088 B)
>>>   after:  0x330 (816 B)
>>
>> Huh? These are static variables, how is this affecting stack usage?
>> I assume this is against your previous (broken) patch?
> It's only broken on ARM + GCC. GCC + anything else and Clang + anything
> else is fine.

That's still broken, though :)

>> Anyway, adding this kind of aliasing to fix a problem that you
>> introduced by changing working code with no real benefit is not an
>> improvement. I'm OK with fixing actual bugs, but this is just mindless
>> churn...
> Fixing actual bugs is the goal yes. It makes sense to split up into
> multiple parts IMO.

If you're fixing an actual bug, include that in the patch description,
and if it requires multiple patches include them in a series. Sending
these out of context patches that just shuffle code around is just
churn...

-Toke

^ permalink raw reply

* [PATCH wireless] wifi: rt2x00: avoid full teardown before work setup in probe
From: Runyu Xiao @ 2026-06-19  7:31 UTC (permalink / raw)
  To: Stanislaw Gruszka
  Cc: Gertjan van Wingerde, John W . Linville, Ivo van Doorn,
	linux-wireless, linux-kernel, Runyu Xiao, stable

rt2x00lib_probe_dev() uses the full rt2x00lib_remove_dev() teardown for
all probe failures. However, drv_data allocation and workqueue allocation
can fail before intf_work, autowakeup_work and sleep_work have been
initialized.

Do not enter the full remove path until the probe has reached the point
where those work items are set up. Return directly for drv_data allocation
failure, and use a small early cleanup path for workqueue allocation
failure.

This issue was found by our static analysis tool and then confirmed by
manual review of rt2x00lib_probe_dev() and rt2x00lib_remove_dev(). The
early probe exits should not call a common teardown path that assumes the
later work setup has already completed.

A QEMU PoC forced alloc_ordered_workqueue() to fail before the work
initializers are reached. The resulting fail path entered
rt2x00lib_remove_dev(), and DEBUG_OBJECTS reported invalid work drains with
rt2x00lib_probe_dev() and rt2x00lib_remove_dev() in the stack.

Fixes: 1ebbc48520a0 ("rt2x00: Introduce concept of driver data in struct rt2x00_dev.")
Fixes: 0439f5367c8d ("rt2x00: Move TX/RX work into dedicated workqueue")
Cc: stable@vger.kernel.org
Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
---
 drivers/net/wireless/ralink/rt2x00/rt2x00dev.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
index f8a6f9c968a1..847b64e586f6 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
@@ -1382,7 +1382,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
 			                      GFP_KERNEL);
 		if (!rt2x00dev->drv_data) {
 			retval = -ENOMEM;
-			goto exit;
+			return retval;
 		}
 	}
 
@@ -1416,7 +1416,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
 	    alloc_ordered_workqueue("%s", 0, wiphy_name(rt2x00dev->hw->wiphy));
 	if (!rt2x00dev->workqueue) {
 		retval = -ENOMEM;
-		goto exit;
+		goto exit_free_drv_data;
 	}
 
 	INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
@@ -1488,6 +1488,14 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
 exit:
 	rt2x00lib_remove_dev(rt2x00dev);
 
+	return retval;
+
+exit_free_drv_data:
+	clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
+
+	kfree(rt2x00dev->drv_data);
+	rt2x00dev->drv_data = NULL;
+
 	return retval;
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_probe_dev);
-- 
2.34.1


^ permalink raw reply related

* [PATCH ath-next v2] wifi: ath12k: add QMI capability negotiation for dynamic memory mode
From: Aaradhana Sahu @ 2026-06-19  6:58 UTC (permalink / raw)
  To: ath12k; +Cc: linux-wireless, Aaradhana Sahu

On AHB platforms, firmware operates in two modes: fixed-memory mode where
firmware uses hardcoded addresses for memory regions such as BDF and does
not request HOST_DDR memory from the host, and dynamic-memory mode where
firmware expects the host to provide memory addresses including HOST_DDR
after the Q6 read-only region and relies on host allocation for all memory
types.

Introduce QMI capability negotiation to support both modes. Add a new QMI
PHY capability flag dynamic_ddr_support which is advertised by firmware to
indicate it supports dynamic memory mode. When the host detects this
capability, set the dynamic_mem_support flag in the host capability message
to signal the host is ready to provide dynamic memory allocation. This
triggers firmware to send the HOST_DDR memory request and use the
host-provided address.

For backward compatibility, if firmware doesn't advertise
dynamic_ddr_support, the firmware continues to operate in fixed-memory mode
where firmware uses predefined addresses.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1
Tested-on: IPQ5332 hw1.0 AHB WLAN.WBE.1.6-01275-QCAHKSWPL_SILICONZ-1

Signed-off-by: Aaradhana Sahu <aaradhana.sahu@oss.qualcomm.com>
---
v2:
  -Dropped QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN and QMI_WLANFW_PHY_CAP_RESP_MSG_V01_MAX_LEN changes.
  -Used %u instead of %d in the debug log.
---
 drivers/net/wireless/ath/ath12k/qmi.c | 50 +++++++++++++++++++++++++--
 drivers/net/wireless/ath/ath12k/qmi.h |  6 +++-
 2 files changed, 52 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c
index fd762b5d7bb5..e15a0c0120d3 100644
--- a/drivers/net/wireless/ath/ath12k/qmi.c
+++ b/drivers/net/wireless/ath/ath12k/qmi.c
@@ -506,6 +506,24 @@ static const struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = {
 		.offset		= offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
 					   feature_list),
 	},
+	{
+		.data_type	= QMI_OPT_FLAG,
+		.elem_len	= 1,
+		.elem_size	= sizeof(u8),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= 0x33,
+		.offset		= offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+					   dynamic_mem_support_valid),
+	},
+	{
+		.data_type	= QMI_UNSIGNED_1_BYTE,
+		.elem_len	= 1,
+		.elem_size	= sizeof(u8),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= 0x33,
+		.offset		= offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+					   dynamic_mem_support),
+	},
 	{
 		.data_type	= QMI_EOTI,
 		.array_type	= NO_ARRAY,
@@ -602,6 +620,24 @@ static const struct qmi_elem_info qmi_wlanfw_phy_cap_resp_msg_v01_ei[] = {
 		.offset         = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01,
 					   single_chip_mlo_support),
 	},
+	{
+		.data_type	= QMI_OPT_FLAG,
+		.elem_len	= 1,
+		.elem_size	= sizeof(u8),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= 0x17,
+		.offset		= offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01,
+					   dynamic_ddr_support_valid),
+	},
+	{
+		.data_type	= QMI_UNSIGNED_1_BYTE,
+		.elem_len	= 1,
+		.elem_size	= sizeof(u8),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= 0x17,
+		.offset		= offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01,
+					   dynamic_ddr_support),
+	},
 	{
 		.data_type	= QMI_EOTI,
 		.array_type	= NO_ARRAY,
@@ -2248,6 +2284,11 @@ int ath12k_qmi_host_cap_send(struct ath12k_base *ab)
 	if (ret < 0)
 		goto out;
 
+	if (ab->qmi.dynamic_ddr_support) {
+		req.dynamic_mem_support_valid = 1;
+		req.dynamic_mem_support = 1;
+	}
+
 	ret = qmi_txn_init(&ab->qmi.handle, &txn,
 			   qmi_wlanfw_host_cap_resp_msg_v01_ei, &resp);
 	if (ret < 0)
@@ -2319,11 +2360,14 @@ static void ath12k_qmi_phy_cap_send(struct ath12k_base *ab)
 
 	ab->qmi.num_radios = resp.num_phy;
 
+	if (resp.dynamic_ddr_support_valid)
+		ab->qmi.dynamic_ddr_support = resp.dynamic_ddr_support;
+
 	ath12k_dbg(ab, ATH12K_DBG_QMI,
-		   "phy capability resp valid %d single_chip_mlo_support %d valid %d num_phy %d valid %d board_id %d\n",
+		   "phy capability resp valid %d single_chip_mlo_support %d valid %d num_phy %d valid %d board_id %d dynamic_ddr_valid %u dynamic_ddr_support %u\n",
 		   resp.single_chip_mlo_support_valid, resp.single_chip_mlo_support,
-		   resp.num_phy_valid, resp.num_phy,
-		   resp.board_id_valid, resp.board_id);
+		   resp.num_phy_valid, resp.num_phy, resp.board_id_valid, resp.board_id,
+		   resp.dynamic_ddr_support_valid, resp.dynamic_ddr_support);
 
 	return;
 
diff --git a/drivers/net/wireless/ath/ath12k/qmi.h b/drivers/net/wireless/ath/ath12k/qmi.h
index 2a63e214eb42..08225242d30a 100644
--- a/drivers/net/wireless/ath/ath12k/qmi.h
+++ b/drivers/net/wireless/ath/ath12k/qmi.h
@@ -156,6 +156,7 @@ struct ath12k_qmi {
 	struct m3_mem_region aux_uc_mem;
 	unsigned int service_ins_id;
 	struct dev_mem_info dev_mem[ATH12K_QMI_WLFW_MAX_DEV_MEM_NUM_V01];
+	u8 dynamic_ddr_support;
 };
 
 #define QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN		261
@@ -258,7 +259,8 @@ struct qmi_wlanfw_host_cap_req_msg_v01 {
 	struct wlfw_host_mlo_chip_info_s_v01 mlo_chip_info[QMI_WLFW_MAX_NUM_MLO_CHIPS_V01];
 	u8 feature_list_valid;
 	u64 feature_list;
-
+	u8 dynamic_mem_support_valid;
+	u8 dynamic_mem_support;
 };
 
 struct qmi_wlanfw_host_cap_resp_msg_v01 {
@@ -281,6 +283,8 @@ struct qmi_wlanfw_phy_cap_resp_msg_v01 {
 	u32 board_id;
 	u8 single_chip_mlo_support_valid;
 	u8 single_chip_mlo_support;
+	u8 dynamic_ddr_support_valid;
+	u8 dynamic_ddr_support;
 };
 
 #define QMI_WLANFW_IND_REGISTER_REQ_MSG_V01_MAX_LEN		54

base-commit: 83f028be15fe071efbee8e27837538d6cca77e87
-- 
2.34.1


^ permalink raw reply related

* [PATCH wireless] wifi: brcmfmac: initialize SDIO data work before cleanup
From: Runyu Xiao @ 2026-06-19  6:44 UTC (permalink / raw)
  To: Arend van Spriel, Kalle Valo
  Cc: Pieter-Paul Giesberts, Hante Meuleman, Daniel Kim, Franky Lin,
	linux-wireless, brcm80211, brcm80211-dev-list.pdl, linux-kernel,
	Runyu Xiao, stable

brcmf_sdio_probe() stores the newly allocated bus in sdiodev->bus before
allocating the ordered workqueue. If that allocation fails, the function
jumps to fail and calls brcmf_sdio_remove().

brcmf_sdio_remove() unconditionally cancels bus->datawork. Initialize the
work item before the first failure path that can reach brcmf_sdio_remove(),
so the cleanup path always observes a valid work object.

This issue was found by our static analysis tool and then confirmed by
manual review of the probe error path and the remove-time work drain. The
problem pattern is an early setup failure that reaches a cleanup helper
which cancels an embedded work item before its initializer has run.

A QEMU PoC forced alloc_ordered_workqueue() to fail at the same point in
brcmf_sdio_probe(), before INIT_WORK(&bus->datawork) is reached. The
resulting fail path calls brcmf_sdio_remove(), and DEBUG_OBJECTS reports
the invalid work drain with brcmf_sdio_probe() and brcmf_sdio_remove() in
the stack.

Fixes: 9982464379e8 ("brcmfmac: make sdio suspend wait for threads to freeze")
Cc: stable@vger.kernel.org
Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
---
 drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index 4e6ed02c1591..a7d84ad6ed54 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -4464,6 +4464,7 @@ int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
 	bus->sdiodev = sdiodev;
 	sdiodev->bus = bus;
 	skb_queue_head_init(&bus->glom);
+	INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
 	bus->txbound = BRCMF_TXBOUND;
 	bus->rxbound = BRCMF_RXBOUND;
 	bus->txminmax = BRCMF_TXMINMAX;
@@ -4478,7 +4479,6 @@ int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
 		goto fail;
 	}
 	brcmf_sdiod_freezer_count(sdiodev);
-	INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
 	bus->brcmf_wq = wq;
 
 	/* attempt to attach to the dongle */
-- 
2.34.1


^ 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