* [PATCH] wifi: cfg80211: validate IEs in cfg80211_wext_siwgenie()
From: Deepanshu Kartikey @ 2026-07-10 2:46 UTC (permalink / raw)
To: johannes
Cc: linux-wireless, linux-kernel, Deepanshu Kartikey,
syzbot+cc867e537e4bd36f69bb
Syzkaller reported a KASAN slab-out-of-bounds read in skip_ie()
and a fortify memcpy panic in cfg80211_sme_get_conn_ies().
The KASAN allocation trace shows that a malformed IE buffer is
stored via SIOCSIWGENIE (cfg80211_wext_siwgenie()) without any
validation. The crash trace shows that a subsequent SIOCSIWESSID
triggers a connection attempt which calls cfg80211_sme_get_conn_ies()
to process the stored IE buffer, causing:
- An out-of-bounds read in skip_ie() which reads ies[pos+1]
(the length byte) past the end of the 1-byte buffer.
- An integer underflow in the memcpy size argument when offs
returned by ieee80211_ie_split() exceeds ies_len, causing
unsigned subtraction to wrap to SIZE_MAX and triggering a
fortify panic.
Fix this by validating the IE buffer in cfg80211_wext_siwgenie()
before storing it. Add cfg80211_validate_ies() which walks the
buffer and verifies every element has at least 2 bytes (type +
length) and sufficient data bytes as indicated by its length
field. Return -EINVAL if validation fails.
Reported-by: syzbot+cc867e537e4bd36f69bb@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=cc867e537e4bd36f69bb
Tested-by: syzbot+cc867e537e4bd36f69bb@syzkaller.appspotmail.com
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
include/net/cfg80211.h | 1 +
net/wireless/util.c | 16 ++++++++++++++++
net/wireless/wext-sme.c | 2 ++
3 files changed, 19 insertions(+)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 8188ad200de5..32cef926f8a4 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -10992,4 +10992,5 @@ void cfg80211_incumbent_signal_notify(struct wiphy *wiphy,
u32 signal_interference_bitmap,
gfp_t gfp);
+bool cfg80211_validate_ies(const u8 *ies, size_t ies_len);
#endif /* __NET_CFG80211_H */
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 24527bf321b2..a685020c8efc 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -3083,3 +3083,19 @@ bool cfg80211_wdev_channel_allowed(struct wireless_dev *wdev,
return false;
}
EXPORT_SYMBOL(cfg80211_wdev_channel_allowed);
+
+bool cfg80211_validate_ies(const u8 *ies, size_t ies_len)
+{
+ size_t pos = 0;
+
+ while (pos < ies_len) {
+ if (pos + 2 > ies_len)
+ return false;
+ if (pos + 2 + ies[pos + 1] > ies_len)
+ return false;
+ pos += 2 + ies[pos + 1];
+ }
+
+ return true;
+}
+EXPORT_SYMBOL(cfg80211_validate_ies);
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
index 573b6b15a446..3e9b071f6d66 100644
--- a/net/wireless/wext-sme.c
+++ b/net/wireless/wext-sme.c
@@ -319,6 +319,8 @@ int cfg80211_wext_siwgenie(struct net_device *dev,
return 0;
if (ie_len) {
+ if (!cfg80211_validate_ies(extra, ie_len))
+ return -EINVAL;
ie = kmemdup(extra, ie_len, GFP_KERNEL);
if (!ie)
return -ENOMEM;
--
2.43.0
^ permalink raw reply related
* Re: [PATCH] wifi: brcmfmac: drain bus_reset work on device removal
From: Fan Wu @ 2026-07-10 2:21 UTC (permalink / raw)
To: Eddie Phillips
Cc: Fan Wu, Arend van Spriel, Kalle Valo, Franky Lin, Hante Meuleman,
Chi-Hsien Lin, Wright Feng, Chung-Hsien Hsu, David S . Miller,
Jakub Kicinski, linux-wireless, brcm80211-dev-list.pdl,
SHA-cyfmac-dev-list, netdev, linux-kernel, stable
In-Reply-To: <20260710002451.500112-1-eddiephillips@google.com>
On Thu, Jul 09, 2026 at 05:23:37PM -0700, Eddie Phillips wrote:
> Is this safe in a softIRQ context?
> mutex_lock() sleeps until it can get the lock.
Thanks for taking a look. I agree this is not the right interface shape.
The current call sites I traced reach brcmf_fw_crashed() from the PCIe
threaded IRQ path or from SDIO workqueue context, but brcmf_fw_crashed()
is a core helper and the reset scheduling path should not grow a hidden
sleepable-context requirement. I will respin this part so the arming gate
does not use a mutex.
> How about if brcmf_pcie_remove() calls brcmf_bus_cancel_reset_work(),
> takes the lock and calls cancel_work_sync(), sleeps. If debugfs
> path is already running, it can invoke the worker thread. Is there
> potential that both try to reset?
Yes, that is a real issue with this version. The lock only serializes
scheduling against the cancel point. If the reset work has already started,
cancel_work_sync() waits for it, but the worker may already be executing the
bus reset teardown path; remove can then continue and run its own teardown
afterwards.
So the patch needs a stronger state/ownership model than just
schedule-vs-cancel serialization. I will rework it so reset and remove cannot
both own the same teardown sequence, and will send a v2 after auditing the
PCIe/SDIO/USB paths again.
Thanks,
Fan
^ permalink raw reply
* Re: [PATCH] wifi: brcmfmac: drain bus_reset work on device removal
From: Eddie Phillips @ 2026-07-10 0:23 UTC (permalink / raw)
To: eddiephillips, Fan Wu
Cc: Arend van Spriel, Kalle Valo, Franky Lin, Hante Meuleman,
Chi-Hsien Lin, Wright Feng, Chung-Hsien Hsu, David S . Miller,
Jakub Kicinski, linux-wireless, brcm80211-dev-list.pdl,
SHA-cyfmac-dev-list, netdev, linux-kernel, stable
In-Reply-To: <20260709101635.103005-1-fanwu01@zju.edu.cn>
On Thu, 9 Jul 2026 10:16:35 +0000 Fan Wu <fanwu01@zju.edu.cn> wrote:
> brcmf_fw_crashed() and the debugfs "reset" entry both schedule
> drvr->bus_reset, whose callback recovers drvr through container_of()
> and dereferences it. The teardown paths free drvr (brcmf_free ->
> wiphy_free) without draining the work, so a bus_reset callback pending
> or running during removal can outlive drvr.
>
> Cancellation cannot live in brcmf_detach() or brcmf_free(): the work
> callback reaches teardown through the bus .reset op (PCIe
> brcmf_pcie_reset -> brcmf_detach; SDIO brcmf_sdio_bus_reset ->
> brcmf_sdiod_remove -> brcmf_free), so cancelling there would wait for
> the running work and deadlock. Arming and the drain must also be
> mutually exclusive: a debugfs writer can otherwise schedule bus_reset
> after the drain and before the debugfs file is removed in
> brcmf_cfg80211_detach(), re-opening the window.
>
> Add a per-bus mutex and route all arming through
> brcmf_bus_schedule_reset(), which under the lock skips when the bus is
> marked removing. Each bus remove entry calls
> brcmf_bus_cancel_reset_work(), which under the same lock sets removing
> and cancels the work. Where applicable the remove entry first stops
> the firmware-crash producer: on PCIe mask the mailbox and
> synchronize_irq; on SDIO unregister the bus interrupt and cancel the
> data worker, which also reports firmware halts through
> brcmf_fw_crashed(). The mutex is initialized at bus allocation so it
> is ready before any firmware-probe or removal path can reach it. The
> SDIO suspend power-off path frees drvr through the same
> brcmf_sdiod_remove() and takes the same lock; resume re-allows the work
> only on a successful re-probe.
>
> This issue was found by an in-house static analysis tool.
>
> Fixes: 4684997d9eea ("brcmfmac: reset PCIe bus on a firmware crash")
> Cc: stable@vger.kernel.org
> Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>
> Assisted-by: Codex:gpt-5.5
> ---
> .../broadcom/brcm80211/brcmfmac/bcmsdh.c | 13 ++++++++
> .../broadcom/brcm80211/brcmfmac/bus.h | 6 ++++
> .../broadcom/brcm80211/brcmfmac/core.c | 33 +++++++++++++++++--
> .../broadcom/brcm80211/brcmfmac/pcie.c | 6 ++++
> .../broadcom/brcm80211/brcmfmac/sdio.c | 6 ++++
> .../broadcom/brcm80211/brcmfmac/sdio.h | 1 +
> .../broadcom/brcm80211/brcmfmac/usb.c | 3 ++
> 7 files changed, 66 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
> index ac02244a6..c4bb32aec 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
> @@ -1043,6 +1043,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
> bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL);
> if (!bus_if)
> return -ENOMEM;
> + mutex_init(&bus_if->bus_reset_lock);
> sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL);
> if (!sdiodev) {
> kfree(bus_if);
> @@ -1102,6 +1103,14 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func)
> if (func->num != 1)
> return;
>
> + /* Drain bus_reset before the shared brcmf_sdiod_remove()
> + * teardown, which the SDIO reset callback also reaches. The
> + * data worker can arm bus_reset via brcmf_fw_crashed(); cancel
> + * it first.
> + */
> + brcmf_sdio_cancel_datawork(sdiodev->bus);
> + brcmf_bus_cancel_reset_work(bus_if);
> +
> /* only proceed with rest of cleanup if func 1 */
> brcmf_sdiod_remove(sdiodev);
>
> @@ -1163,6 +1172,8 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
> } else {
> /* power will be cut so remove device, probe again in resume */
> brcmf_sdiod_intr_unregister(sdiodev);
> + brcmf_sdio_cancel_datawork(sdiodev->bus);
> + brcmf_bus_cancel_reset_work(bus_if);
> ret = brcmf_sdiod_remove(sdiodev);
> if (ret)
> brcmf_err("Failed to remove device on suspend\n");
> @@ -1188,6 +1199,8 @@ static int brcmf_ops_sdio_resume(struct device *dev)
> ret = brcmf_sdiod_probe(sdiodev);
> if (ret)
> brcmf_err("Failed to probe device on resume\n");
> + else
> + brcmf_bus_allow_reset_work(bus_if);
> } else {
> if (sdiodev->wowl_enabled &&
> sdiodev->settings->bus.sdio.oob_irq_supported)
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
> index 3f5da3bb6..b606094af 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
> @@ -6,6 +6,7 @@
> #ifndef BRCMFMAC_BUS_H
> #define BRCMFMAC_BUS_H
>
> +#include <linux/mutex.h>
> #include "debug.h"
>
> /* IDs of the 6 default common rings of msgbuf protocol */
> @@ -149,11 +150,16 @@ struct brcmf_bus {
> u32 chiprev;
> bool always_use_fws_queue;
> bool wowl_supported;
> + bool removing; /* device removal in progress; quiesce async work */
> + struct mutex bus_reset_lock;
>
> const struct brcmf_bus_ops *ops;
> struct brcmf_bus_msgbuf *msgbuf;
> };
>
> +void brcmf_bus_cancel_reset_work(struct brcmf_bus *bus_if);
> +void brcmf_bus_allow_reset_work(struct brcmf_bus *bus_if);
> +
> /*
> * callback wrappers
> */
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
> index fed9cd5f2..b934feb9b 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
> @@ -1164,6 +1164,35 @@ static int brcmf_revinfo_read(struct seq_file *s, void *data)
> return 0;
> }
>
> +/* Serialize bus_reset arming (debugfs reset write, brcmf_fw_crashed) against the
> + * teardown drain: the remove path takes bus_reset_lock, sets ->removing and cancels
> + * the work under it, so a racing armer either schedules before the cancel (and is
> + * drained) or observes ->removing and desists.
> + */
> +static void brcmf_bus_schedule_reset(struct brcmf_bus *bus_if)
> +{
> + mutex_lock(&bus_if->bus_reset_lock);
> + if (bus_if->drvr && bus_if->drvr->bus_reset.func && !bus_if->removing)
> + schedule_work(&bus_if->drvr->bus_reset);
> + mutex_unlock(&bus_if->bus_reset_lock);
> +}
Is this safe in a softIRQ context?
mutex_lock() sleeps until it can get the lock.
> +
> +void brcmf_bus_cancel_reset_work(struct brcmf_bus *bus_if)
> +{
> + mutex_lock(&bus_if->bus_reset_lock);
> + bus_if->removing = true;
> + if (bus_if->drvr)
> + cancel_work_sync(&bus_if->drvr->bus_reset);
> + mutex_unlock(&bus_if->bus_reset_lock);
> +}
How about if brcmf_pcie_remove() calls brcmf_bus_cancel_reset_work(),
takes the lock and calls cancel_work_sync(), sleeps. If debugfs
path is already running, it can invoke the worker thread. Is there
potential that both try to reset?
> +
> +void brcmf_bus_allow_reset_work(struct brcmf_bus *bus_if)
> +{
> + mutex_lock(&bus_if->bus_reset_lock);
> + bus_if->removing = false;
> + mutex_unlock(&bus_if->bus_reset_lock);
> +}
> +
> static void brcmf_core_bus_reset(struct work_struct *work)
> {
> struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,
> @@ -1184,7 +1213,7 @@ static ssize_t bus_reset_write(struct file *file, const char __user *user_buf,
> if (value != 1)
> return -EINVAL;
>
> - schedule_work(&drvr->bus_reset);
> + brcmf_bus_schedule_reset(drvr->bus_if);
>
> return count;
> }
> @@ -1408,7 +1437,7 @@ void brcmf_fw_crashed(struct device *dev)
>
> brcmf_dev_coredump(dev);
>
> - schedule_work(&drvr->bus_reset);
> + brcmf_bus_schedule_reset(bus_if);
> }
>
> void brcmf_detach(struct device *dev)
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
> index 8b149996f..3c6775166 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
> @@ -1914,6 +1914,7 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> ret = -ENOMEM;
> goto fail;
> }
> + mutex_init(&bus->bus_reset_lock);
> bus->msgbuf = kzalloc(sizeof(*bus->msgbuf), GFP_KERNEL);
> if (!bus->msgbuf) {
> ret = -ENOMEM;
> @@ -1985,6 +1986,11 @@ brcmf_pcie_remove(struct pci_dev *pdev)
> if (devinfo->ci)
> brcmf_pcie_intr_disable(devinfo);
>
> + if (devinfo->irq_allocated)
> + synchronize_irq(pdev->irq);
> +
> + brcmf_bus_cancel_reset_work(bus);
> +
> brcmf_detach(&pdev->dev);
> brcmf_free(&pdev->dev);
>
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
> index 8effeb7a7..31e37b0d4 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
> @@ -4541,6 +4541,12 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
> return NULL;
> }
>
> +void brcmf_sdio_cancel_datawork(struct brcmf_sdio *bus)
> +{
> + if (bus)
> + cancel_work_sync(&bus->datawork);
> +}
> +
> /* Detach and free everything */
> void brcmf_sdio_remove(struct brcmf_sdio *bus)
> {
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
> index 15d2c02fa..3c68ebf8e 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
> @@ -373,6 +373,7 @@ int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev);
> struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev);
> void brcmf_sdio_remove(struct brcmf_sdio *bus);
> void brcmf_sdio_isr(struct brcmf_sdio *bus, bool in_isr);
> +void brcmf_sdio_cancel_datawork(struct brcmf_sdio *bus);
>
> void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, bool active);
> void brcmf_sdio_wowl_config(struct device *dev, bool enabled);
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
> index 9fb68c2dc..97d65ba36 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
> @@ -1271,6 +1271,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
> ret = -ENOMEM;
> goto fail;
> }
> + mutex_init(&bus->bus_reset_lock);
>
> bus->dev = dev;
> bus_pub->bus = bus;
> @@ -1336,6 +1337,8 @@ brcmf_usb_disconnect_cb(struct brcmf_usbdev_info *devinfo)
> return;
> brcmf_dbg(USB, "Enter, bus_pub %p\n", devinfo);
>
> + brcmf_bus_cancel_reset_work(devinfo->bus_pub.bus);
> +
> brcmf_detach(devinfo->dev);
> brcmf_free(devinfo->dev);
> kfree(devinfo->bus_pub.bus);
> --
> 2.34.1
Sent using hkml (https://github.com/sjp38/hackermail)
^ permalink raw reply
* [PATCH] rtlwifi: rtl8192d: remove dead SMPS rate mask code
From: Chelsy Ratnawat @ 2026-07-09 19:43 UTC (permalink / raw)
To: pkshih; +Cc: linux-wireless, linux-kernel, Chelsy Ratnawat
mimo_ps is initialized to IEEE80211_SMPS_OFF and never modified in
rtl92d_update_hal_rate_table(). Therefore, the IEEE80211_SMPS_STATIC
case is unreachable.
Remove the unused mimo_ps variable and the dead branch.
Signed-off-by: Chelsy Ratnawat <chelsyratnawat2001@gmail.com>
---
.../realtek/rtlwifi/rtl8192d/hw_common.c | 21 +++++++------------
1 file changed, 8 insertions(+), 13 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192d/hw_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192d/hw_common.c
index 97e0d9c01e0a..cfefbe86380f 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192d/hw_common.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192d/hw_common.c
@@ -775,7 +775,6 @@ static void rtl92d_update_hal_rate_table(struct ieee80211_hw *hw,
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &rtlpriv->phy;
enum wireless_mode wirelessmode;
- u8 mimo_ps = IEEE80211_SMPS_OFF;
u8 curtxbw_40mhz = mac->bw_40;
u8 nmode = mac->ht_enable;
u8 curshortgi_40mhz;
@@ -784,6 +783,7 @@ static void rtl92d_update_hal_rate_table(struct ieee80211_hw *hw,
u8 ratr_index = 0;
u16 shortgi_rate;
u32 ratr_value;
+ u32 ratr_mask;
curshortgi_40mhz = !!(sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40);
curshortgi_20mhz = !!(sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20);
@@ -811,20 +811,15 @@ static void rtl92d_update_hal_rate_table(struct ieee80211_hw *hw,
case WIRELESS_MODE_N_24G:
case WIRELESS_MODE_N_5G:
nmode = 1;
- if (mimo_ps == IEEE80211_SMPS_STATIC) {
- ratr_value &= 0x0007F005;
- } else {
- u32 ratr_mask;
- if (get_rf_type(rtlphy) == RF_1T2R ||
- get_rf_type(rtlphy) == RF_1T1R) {
- ratr_mask = 0x000ff005;
- } else {
- ratr_mask = 0x0f0ff005;
- }
-
- ratr_value &= ratr_mask;
+ if (get_rf_type(rtlphy) == RF_1T2R ||
+ get_rf_type(rtlphy) == RF_1T1R) {
+ ratr_mask = 0x000ff005;
+ } else {
+ ratr_mask = 0x0f0ff005;
}
+
+ ratr_value &= ratr_mask;
break;
default:
if (rtlphy->rf_type == RF_1T2R)
--
2.43.0
^ permalink raw reply related
* Re: (subset) [PATCH v9 00/14] firmware: qcom: Add OP-TEE PAS service support
From: Bjorn Andersson @ 2026-07-09 19:32 UTC (permalink / raw)
To: konradybcio, Sumit Garg
Cc: linux-arm-msm, devicetree, dri-devel, freedreno, linux-media,
netdev, linux-wireless, ath12k, linux-remoteproc, robh, krzk+dt,
conor+dt, robin.clark, sean, akhilpo, lumag, abhinav.kumar,
jesszhan0024, marijn.suijten, airlied, simona, vikash.garodia,
bod, mchehab, elder, andrew+netdev, davem, edumazet, kuba, pabeni,
jjohnson, mathieu.poirier, trilokkumar.soni, mukesh.ojha,
pavan.kondeti, jorge.ramirez, tonyh, vignesh.viswanathan,
srinivas.kandagatla, amirreza.zarrabi, jenswi, op-tee, apurupa,
skare, linux-kernel, Sumit Garg
In-Reply-To: <20260702115835.167602-1-sumit.garg@kernel.org>
On Thu, 02 Jul 2026 17:28:16 +0530, Sumit Garg wrote:
> From: Sumit Garg <sumit.garg@oss.qualcomm.com>
>
> Qcom platforms has the legacy of using non-standard SCM calls
> splintered over the various kernel drivers. These SCM calls aren't
> compliant with the standard SMC calling conventions which is a
> prerequisite to enable migration to the FF-A specifications from Arm.
>
> [...]
Applied, thanks!
[01/14] firmware: qcom: Add a generic PAS service
commit: 08314e7c2c38b9ae6a5e01c58ed10a950859404d
[02/14] firmware: qcom_scm: Migrate to generic PAS service
commit: 5c1a2975d23c51c01aca51945d0f10a4ee4c9020
[03/14] firmware: qcom: Add a PAS TEE service
commit: b6f7978da0c4d26fe465aa6634f5a0b48f900de0
[14/14] MAINTAINERS: Add maintainer entry for Qualcomm PAS TZ service
commit: 6701259025d49139131a0eb2257659a066dcca22
This is available as an immutable branch, for other subsystems to pull at:
https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux.git 20260702115835.167602-2-sumit.garg@kernel.org
[04/14] remoteproc: qcom_q6v5_pas: Switch over to generic PAS TZ APIs
commit: 254030af0d81b12b7624d9ce85c6bdd3171629c6
[05/14] remoteproc: qcom_q6v5_mss: Switch to generic PAS TZ APIs
commit: f3b1357673ddb37ae8b9a8fe44df73cbd2a519c5
[06/14] remoteproc: qcom_wcnss: Switch to generic PAS TZ APIs
commit: ea3b5245f5deba916320b32a8e6510a74c034c17
[07/14] remoteproc: qcom: Select QCOM_PAS generic service
commit: c4383254ac7a529736577e304176a10371c2ee0b
Best regards,
--
Bjorn Andersson <andersson@kernel.org>
^ permalink raw reply
* [syzbot] [wireless?] KASAN: slab-out-of-bounds Read in ieee80211_ie_split_ric (3)
From: syzbot @ 2026-07-09 16:33 UTC (permalink / raw)
To: johannes, linux-kernel, linux-wireless, netdev, syzkaller-bugs
Hello,
syzbot found the following issue on:
HEAD commit: a52d6c7160f7 selftests/arm64: fix spelling errors in comme..
git tree: git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-kernelci
console output: https://syzkaller.appspot.com/x/log.txt?x=17ddd739580000
kernel config: https://syzkaller.appspot.com/x/.config?x=ecdef466b08b9772
dashboard link: https://syzkaller.appspot.com/bug?extid=cc867e537e4bd36f69bb
compiler: Debian clang version 22.1.8 (++20260613092233+e80beda6e255-1~exp1~20260613092250.77), Debian LLD 22.1.8
userspace arch: arm64
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=13940432580000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=156e7d89580000
Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/af2ea186884f/disk-a52d6c71.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/cef93b18732f/vmlinux-a52d6c71.xz
kernel image: https://storage.googleapis.com/syzbot-assets/b9f9b8922f14/Image-a52d6c71.gz.xz
IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+cc867e537e4bd36f69bb@syzkaller.appspotmail.com
==================================================================
BUG: KASAN: slab-out-of-bounds in skip_ie net/wireless/util.c:2068 [inline]
BUG: KASAN: slab-out-of-bounds in ieee80211_ie_split_ric+0x4a8/0x508 net/wireless/util.c:-1
Read of size 1 at addr ffff0000c2aac9c1 by task syz.0.18/4930
CPU: 0 UID: 0 PID: 4930 Comm: syz.0.18 Not tainted syzkaller #0 PREEMPT
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 06/02/2026
Call trace:
show_stack+0x2c/0x3c arch/arm64/kernel/stacktrace.c:499 (C)
__dump_stack+0x30/0x40 lib/dump_stack.c:94
dump_stack_lvl+0xd8/0x12c lib/dump_stack.c:120
print_address_description+0xb0/0x238 mm/kasan/report.c:378
print_report+0x68/0x84 mm/kasan/report.c:482
kasan_report+0x8c/0xc4 mm/kasan/report.c:595
__asan_report_load1_noabort+0x20/0x2c mm/kasan/report_generic.c:378
skip_ie net/wireless/util.c:2068 [inline]
ieee80211_ie_split_ric+0x4a8/0x508 net/wireless/util.c:-1
ieee80211_ie_split include/net/cfg80211.h:10226 [inline]
cfg80211_sme_get_conn_ies net/wireless/sme.c:529 [inline]
cfg80211_sme_connect net/wireless/sme.c:586 [inline]
cfg80211_connect+0xca8/0x1be4 net/wireless/sme.c:1528
cfg80211_mgd_wext_connect+0x3ac/0x508 net/wireless/wext-sme.c:57
cfg80211_mgd_wext_siwessid+0x2c4/0x40c net/wireless/wext-sme.c:184
cfg80211_wext_siwessid+0xc4/0x13c net/wireless/wext-compat.c:1415
ioctl_standard_iw_point+0x678/0xb04 net/wireless/wext-core.c:864
ioctl_standard_call+0xb4/0x178 net/wireless/wext-core.c:1049
wireless_process_ioctl net/wireless/wext-core.c:-1 [inline]
wext_ioctl_dispatch+0x104/0x36c net/wireless/wext-core.c:1013
wext_handle_ioctl+0x154/0x288 net/wireless/wext-core.c:1074
sock_ioctl+0x154/0x7ec net/socket.c:1353
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl fs/ioctl.c:583 [inline]
__arm64_sys_ioctl+0x14c/0x1c4 fs/ioctl.c:583
__invoke_syscall arch/arm64/kernel/syscall.c:35 [inline]
invoke_syscall+0x98/0x244 arch/arm64/kernel/syscall.c:49
el0_svc_common+0xec/0x23c arch/arm64/kernel/syscall.c:121
do_el0_svc+0x4c/0x5c arch/arm64/kernel/syscall.c:140
el0_svc+0x64/0x260 arch/arm64/kernel/entry-common.c:736
el0t_64_sync_handler+0x48/0x148 arch/arm64/kernel/entry-common.c:755
el0t_64_sync+0x198/0x19c arch/arm64/kernel/entry.S:594
Allocated by task 4930:
kasan_save_stack mm/kasan/common.c:57 [inline]
kasan_save_track+0x40/0x78 mm/kasan/common.c:78
kasan_save_alloc_info+0x44/0x54 mm/kasan/generic.c:570
poison_kmalloc_redzone mm/kasan/common.c:398 [inline]
__kasan_kmalloc+0x9c/0xb4 mm/kasan/common.c:415
kasan_kmalloc include/linux/kasan.h:263 [inline]
__do_kmalloc_node mm/slub.c:5362 [inline]
__kmalloc_node_track_caller_noprof+0x434/0x6d4 mm/slub.c:5497
kmemdup_noprof+0x44/0x8c mm/util.c:138
kmemdup_noprof include/linux/fortify-string.h:715 [inline]
cfg80211_wext_siwgenie+0x170/0x28c net/wireless/wext-sme.c:322
ioctl_standard_iw_point+0x678/0xb04 net/wireless/wext-core.c:864
ioctl_standard_call+0xb4/0x178 net/wireless/wext-core.c:1049
wireless_process_ioctl net/wireless/wext-core.c:-1 [inline]
wext_ioctl_dispatch+0x104/0x36c net/wireless/wext-core.c:1013
wext_handle_ioctl+0x154/0x288 net/wireless/wext-core.c:1074
sock_ioctl+0x154/0x7ec net/socket.c:1353
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl fs/ioctl.c:583 [inline]
__arm64_sys_ioctl+0x14c/0x1c4 fs/ioctl.c:583
__invoke_syscall arch/arm64/kernel/syscall.c:35 [inline]
invoke_syscall+0x98/0x244 arch/arm64/kernel/syscall.c:49
el0_svc_common+0xec/0x23c arch/arm64/kernel/syscall.c:121
do_el0_svc+0x4c/0x5c arch/arm64/kernel/syscall.c:140
el0_svc+0x64/0x260 arch/arm64/kernel/entry-common.c:736
el0t_64_sync_handler+0x48/0x148 arch/arm64/kernel/entry-common.c:755
el0t_64_sync+0x198/0x19c arch/arm64/kernel/entry.S:594
The buggy address belongs to the object at ffff0000c2aac9c0
which belongs to the cache kmalloc-8 of size 8
The buggy address is located 0 bytes to the right of
allocated 1-byte region [ffff0000c2aac9c0, ffff0000c2aac9c1)
The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff0000c2aaca20 pfn:0x102aac
flags: 0x5ffc00000000200(workingset|node=0|zone=2|lastcpupid=0x7ff)
page_type: f5(slab)
raw: 05ffc00000000200 ffff0000c0001500 ffff0000c0000348 fffffdffc30937d0
raw: ffff0000c2aaca20 0000000800800064 00000000f5000000 0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff0000c2aac880: fa fc fc fc fa fc fc fc fa fc fc fc fa fc fc fc
ffff0000c2aac900: fa fc fc fc fa fc fc fc fa fc fc fc fa fc fc fc
>ffff0000c2aac980: fa fc fc fc fa fc fc fc 01 fc fc fc fa fc fc fc
^
ffff0000c2aaca00: fa fc fc fc fa fc fc fc fa fc fc fc fa fc fc fc
ffff0000c2aaca80: fa fc fc fc fa fc fc fc fa fc fc fc fa fc fc fc
==================================================================
------------[ cut here ]------------
memcpy: detected buffer overflow: 18446744073709551615 byte write of buffer size 0
WARNING: lib/string_helpers.c:1037 at __fortify_report+0xa0/0xb8 lib/string_helpers.c:1036, CPU#0: syz.0.18/4930
Modules linked in:
CPU: 0 UID: 0 PID: 4930 Comm: syz.0.18 Tainted: G B syzkaller #0 PREEMPT
Tainted: [B]=BAD_PAGE
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 06/02/2026
pstate: 63400005 (nZCv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
pc : __fortify_report+0xa0/0xb8 lib/string_helpers.c:1036
lr : __fortify_report+0xa0/0xb8 lib/string_helpers.c:1036
sp : ffff8000986876a0
x29: ffff8000986876a0 x28: 1fffe000199c09e6 x27: 1fffe000199c09da
x26: ffff0000c2aac9c0 x25: 0000000000000001 x24: ffff0000d02ad200
x23: ffff0000cce04ed0 x22: ffff800086cbcad8 x21: 0000000000000001
x20: ffffffffffffffff x19: 0000000000000000 x18: 0000000000000000
x17: 3d3d3d3d3d3d3d3d x16: 3d3d3d3d3d3d3d3d x15: 3d3d3d3d3d3d3d3d
x14: 0000000000000000 x13: 0000000000000001 x12: 0000000000000000
x11: 0000000000000000 x10: 0000000000000002 x9 : e75ac9114b2ee700
x8 : e75ac9114b2ee700 x7 : 0000000000000000 x6 : ffff80008048ce60
x5 : 0000000000000000 x4 : 0000000000000000 x3 : ffff8000802f7010
x2 : 0000000100000000 x1 : ffff0000d1543a80 x0 : 0000000000000000
Call trace:
__fortify_report+0xa0/0xb8 lib/string_helpers.c:1036 (P)
__fortify_panic+0x10/0x14 lib/string_helpers.c:1043
fortify_memcpy_chk include/linux/fortify-string.h:547 [inline]
cfg80211_sme_get_conn_ies net/wireless/sme.c:533 [inline]
cfg80211_sme_connect net/wireless/sme.c:586 [inline]
cfg80211_connect+0x1918/0x1be4 net/wireless/sme.c:1528
cfg80211_mgd_wext_connect+0x3ac/0x508 net/wireless/wext-sme.c:57
cfg80211_mgd_wext_siwessid+0x2c4/0x40c net/wireless/wext-sme.c:184
cfg80211_wext_siwessid+0xc4/0x13c net/wireless/wext-compat.c:1415
ioctl_standard_iw_point+0x678/0xb04 net/wireless/wext-core.c:864
ioctl_standard_call+0xb4/0x178 net/wireless/wext-core.c:1049
wireless_process_ioctl net/wireless/wext-core.c:-1 [inline]
wext_ioctl_dispatch+0x104/0x36c net/wireless/wext-core.c:1013
wext_handle_ioctl+0x154/0x288 net/wireless/wext-core.c:1074
sock_ioctl+0x154/0x7ec net/socket.c:1353
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl fs/ioctl.c:583 [inline]
__arm64_sys_ioctl+0x14c/0x1c4 fs/ioctl.c:583
__invoke_syscall arch/arm64/kernel/syscall.c:35 [inline]
invoke_syscall+0x98/0x244 arch/arm64/kernel/syscall.c:49
el0_svc_common+0xec/0x23c arch/arm64/kernel/syscall.c:121
do_el0_svc+0x4c/0x5c arch/arm64/kernel/syscall.c:140
el0_svc+0x64/0x260 arch/arm64/kernel/entry-common.c:736
el0t_64_sync_handler+0x48/0x148 arch/arm64/kernel/entry-common.c:755
el0t_64_sync+0x198/0x19c arch/arm64/kernel/entry.S:594
irq event stamp: 1077
hardirqs last enabled at (1077): [<ffff8000868c3474>] irqentry_exit_to_kernel_mode_after_preempt include/linux/irq-entry-common.h:507 [inline]
hardirqs last enabled at (1077): [<ffff8000868c3474>] arm64_exit_to_kernel_mode+0x80/0x94 arch/arm64/kernel/entry-common.c:62
hardirqs last disabled at (1076): [<ffff8000868bf484>] __el1_irq arch/arm64/kernel/entry-common.c:506 [inline]
hardirqs last disabled at (1076): [<ffff8000868bf484>] el1_interrupt+0x28/0x60 arch/arm64/kernel/entry-common.c:522
softirqs last enabled at (978): [<ffff800084c68eac>] local_bh_enable include/linux/bottom_half.h:33 [inline]
softirqs last enabled at (978): [<ffff800084c68eac>] rcu_read_unlock_bh include/linux/rcupdate.h:914 [inline]
softirqs last enabled at (978): [<ffff800084c68eac>] __dev_queue_xmit+0x14d0/0x2ba4 net/core/dev.c:4907
softirqs last disabled at (972): [<ffff800084c67bd8>] local_bh_disable include/linux/bottom_half.h:20 [inline]
softirqs last disabled at (972): [<ffff800084c67bd8>] rcu_read_lock_bh include/linux/rcupdate.h:893 [inline]
softirqs last disabled at (972): [<ffff800084c67bd8>] __dev_queue_xmit+0x1fc/0x2ba4 net/core/dev.c:4793
---[ end trace 0000000000000000 ]---
------------[ cut here ]------------
kernel BUG at lib/string_helpers.c:1044!
Internal error: Oops - BUG: 00000000f2000800 [#1] SMP
Modules linked in:
CPU: 1 UID: 0 PID: 4930 Comm: syz.0.18 Tainted: G B W syzkaller #0 PREEMPT
Tainted: [B]=BAD_PAGE, [W]=WARN
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 06/02/2026
pstate: 63400005 (nZCv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
pc : __fortify_panic+0x10/0x14 lib/string_helpers.c:1043
lr : __fortify_panic+0x10/0x14 lib/string_helpers.c:1043
sp : ffff8000986876d0
x29: ffff8000986876d0 x28: 1fffe000199c09e6 x27: 1fffe000199c09da
x26: ffff0000c2aac9c0 x25: 0000000000000001 x24: ffff0000d02ad200
x23: ffff0000cce04ed0 x22: 0000000000000002 x21: 0000000000000000
x20: ffff0000e2cc0740 x19: ffffffffffffffff x18: 0000000000000000
x17: 3d3d3d3d3d3d3d3d x16: 3d3d3d3d3d3d3d3d x15: 3d3d3d3d3d3d3d3d
x14: 0000000000000000 x13: 0000000000000001 x12: 0000000000000000
x11: 0000000000000000 x10: 0000000000000002 x9 : e75ac9114b2ee700
x8 : e75ac9114b2ee700 x7 : 0000000000000000 x6 : ffff80008048ce60
x5 : 0000000000000000 x4 : 0000000000000000 x3 : ffff8000802f7010
x2 : 0000000100000000 x1 : ffff0000d1543a80 x0 : 0000000000000000
Call trace:
__fortify_panic+0x10/0x14 lib/string_helpers.c:1043 (P)
fortify_memcpy_chk include/linux/fortify-string.h:547 [inline]
cfg80211_sme_get_conn_ies net/wireless/sme.c:533 [inline]
cfg80211_sme_connect net/wireless/sme.c:586 [inline]
cfg80211_connect+0x1918/0x1be4 net/wireless/sme.c:1528
cfg80211_mgd_wext_connect+0x3ac/0x508 net/wireless/wext-sme.c:57
cfg80211_mgd_wext_siwessid+0x2c4/0x40c net/wireless/wext-sme.c:184
cfg80211_wext_siwessid+0xc4/0x13c net/wireless/wext-compat.c:1415
ioctl_standard_iw_point+0x678/0xb04 net/wireless/wext-core.c:864
ioctl_standard_call+0xb4/0x178 net/wireless/wext-core.c:1049
wireless_process_ioctl net/wireless/wext-core.c:-1 [inline]
wext_ioctl_dispatch+0x104/0x36c net/wireless/wext-core.c:1013
wext_handle_ioctl+0x154/0x288 net/wireless/wext-core.c:1074
sock_ioctl+0x154/0x7ec net/socket.c:1353
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl fs/ioctl.c:583 [inline]
__arm64_sys_ioctl+0x14c/0x1c4 fs/ioctl.c:583
__invoke_syscall arch/arm64/kernel/syscall.c:35 [inline]
invoke_syscall+0x98/0x244 arch/arm64/kernel/syscall.c:49
el0_svc_common+0xec/0x23c arch/arm64/kernel/syscall.c:121
do_el0_svc+0x4c/0x5c arch/arm64/kernel/syscall.c:140
el0_svc+0x64/0x260 arch/arm64/kernel/entry-common.c:736
el0t_64_sync_handler+0x48/0x148 arch/arm64/kernel/entry-common.c:755
el0t_64_sync+0x198/0x19c arch/arm64/kernel/entry.S:594
Code: d503233f a9bf7bfd 910003fd 94618cfa (d4210000)
---[ end trace 0000000000000000 ]---
---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.
syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.
If the report is already addressed, let syzbot know by replying with:
#syz fix: exact-commit-title
If you want syzbot to run the reproducer, reply with:
#syz test: git://repo/address.git branch-or-commit-hash
If you attach or paste a git patch, syzbot will apply it before testing.
If you want to overwrite report's subsystems, reply with:
#syz set subsystems: new-subsystem
(See the list of subsystem names on the web dashboard)
If the report is a duplicate of another one, reply with:
#syz dup: exact-subject-of-another-report
If you want to undo deduplication, reply with:
#syz undup
^ permalink raw reply
* Re: [PATCH] wifi: mac80211: Fix cryptographic MAC comparison to be constant-time
From: Eric Biggers @ 2026-07-09 15:20 UTC (permalink / raw)
To: Johannes Berg
Cc: linux-wireless, Jouni Malinen, linux-crypto, linux-kernel, stable
In-Reply-To: <3e8e6ff58a0809b0346d133c01eda720367eb511.camel@sipsolutions.net>
On Thu, Jul 09, 2026 at 08:45:35AM +0200, Johannes Berg wrote:
> On Wed, 2026-07-08 at 22:44 -0400, Eric Biggers wrote:
> > To prevent timing attacks, the comparison of cryptographic message
> > authentication codes (MACs) needs to have data-independent timing.
> > Replace the memcmp() with the correct function, crypto_memneq().
> >
> > Fixes: 39404feee691 ("mac80211: FILS AEAD protection for station mode association frames")
> > Cc: stable@vger.kernel.org
>
> I guess I'll apply (a variant of) this patch for -next, but that commit
> log really makes it sound like something is actually broken and needs
> fixing, and I don't think that's true in this specific context.
>
> What happens is that the frame is validated and then we associate
> successfully (upon success) or drop the frame (upon failure). Only the
> failure case is relevant for the timing issue, but in that case we
> simply drop the frame and there isn't really an observable signal -
> nothing else happens, at least not immediately, we may retry the request
> later after a timer.
>
> So sure, it looks better to have a crypto_memneq() in AES-SIV related
> code, but in practice I don't see how it would make a difference now,
> and it's even unlikely this code will ever matter for anything else in
> the future, given that things are moving more and more towards full
> frame encryption, including association request/response now.
Surely the other end of the connection could observe a difference in
timing at some point? Even if only a very small amount and not right
away? A timing attack doesn't take much.
It's safest to assume that this is a bug fix.
We've gone through similar crypto_memneq() conversions in other
subsystems, where maintainers try to come up with some heuristic
argument that timing attacks don't apply. Those arguments tend to have
holes. I'm not sure why people are so eager to risk it.
> I saw you originally had this in the "use libraries" patch [1], I'm also
> good with you just keeping the change there. This might even be better
> if you're planning to have this in -next soon, where it would otherwise
> conflict if I keep this to -next.
>
> [1] https://lore.kernel.org/linux-crypto/20260707053503.209874-24-ebiggers@kernel.org/
I just figured this is a bug fix worth splitting out.
Only patches 1-13 of that series are intended for 7.3, so this would be
a good time to get any preliminary fixes in to code that is going to get
converted to use the library later.
- Eric
^ permalink raw reply
* Re: [PATCH 1/2] wifi: ath11k: Flush the posted write after writing to PCIE_SOC_GLOBAL_RESET
From: Jeff Johnson @ 2026-07-09 14:49 UTC (permalink / raw)
To: jjohnson, Manivannan Sadhasivam
Cc: linux-wireless, ath12k, ath11k, linux-kernel, mani,
Alex Williamson
In-Reply-To: <20260623141649.41087-1-manivannan.sadhasivam@oss.qualcomm.com>
On Tue, 23 Jun 2026 16:16:48 +0200, Manivannan Sadhasivam wrote:
> ath11k_pci_soc_global_reset() tries to reset the device by writing to the
> PCIE_SOC_GLOBAL_RESET register. But it doesn't do a read-back to ensure
> that the write gets flushed to the device before the delay.
>
> This may lead to the delay on the host to be insufficient, if the posted
> write doesn't reach the device before the delay.
>
> [...]
Applied, thanks!
[1/2] wifi: ath11k: Flush the posted write after writing to PCIE_SOC_GLOBAL_RESET
commit: 0fe8010fc5b147607fc19ba010ba469afc95f35f
[2/2] wifi: ath12k: Flush the posted write after writing to PCIE_SOC_GLOBAL_RESET
commit: 55f3aa06951cac78b0206bde961c8cf11929a27a
Best regards,
--
Jeff Johnson <jeff.johnson@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH] wifi: ath11k: fix potential buffer underflow in ath11k_hal_rx_msdu_list_get()
From: Jeff Johnson @ 2026-07-09 14:49 UTC (permalink / raw)
To: Jeff Johnson, Dmitry Morgun
Cc: linux-wireless, ath11k, linux-kernel, lvc-project, stable
In-Reply-To: <20260530114252.42615-1-d.morgun@ispras.ru>
On Sat, 30 May 2026 11:42:52 +0000, Dmitry Morgun wrote:
> When the first entry in msdu_details has a zero buffer address,
> the code accesses msdu_details[i - 1] with i == 0, causing a
> buffer underflow.
>
> Fix similarly to ath12k_wifi7_hal_rx_msdu_list_get() by adding
> a separate check for i == 0 before the main condition to prevent
> the out-of-bounds access.
>
> [...]
Applied, thanks!
[1/1] wifi: ath11k: fix potential buffer underflow in ath11k_hal_rx_msdu_list_get()
commit: 7f11e70629650ff6ea140984e5ce188b775b2683
Best regards,
--
Jeff Johnson <jeff.johnson@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH ath-next] wifi: ath10k: fix skb leak on incomplete msdu during rx pop
From: Jeff Johnson @ 2026-07-09 14:49 UTC (permalink / raw)
To: ath10k, Manikanta Pubbisetty; +Cc: linux-wireless
In-Reply-To: <20260623064355.1876743-1-manikanta.pubbisetty@oss.qualcomm.com>
On Tue, 23 Jun 2026 12:13:55 +0530, Manikanta Pubbisetty wrote:
> When ath10k_htt_rx_pop_paddr32_list() or
> ath10k_htt_rx_pop_paddr64_list() encounters an incomplete frame
> (RX_ATTENTION_FLAGS_MSDU_DONE not set), it returns -EIO without
> purging the skb list built up so far, leaking any skbs already
> queued in the list.
>
> Other early-exit paths within these same functions already call
> __skb_queue_purge() before returning an error. Add it before the
> -EIO return as well to be consistent and prevent the leak.
>
> [...]
Applied, thanks!
[1/1] wifi: ath10k: fix skb leak on incomplete msdu during rx pop
commit: 7393878255e492515858f751ba4c260f248fb108
Best regards,
--
Jeff Johnson <jeff.johnson@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH] wifi: ath11k: fix refcount leak in ath11k_ahb_fw_resources_init()
From: Jeff Johnson @ 2026-07-09 14:49 UTC (permalink / raw)
To: jjohnson, Wentao Liang; +Cc: linux-wireless, ath11k, linux-kernel, stable
In-Reply-To: <20260609092528.220547-1-vulab@iscas.ac.cn>
On Tue, 09 Jun 2026 09:25:28 +0000, Wentao Liang wrote:
> of_get_child_by_name() returns a node pointer with refcount
> incremented, but the error path when ath11k_ahb_setup_msa_resources()
> fails does not release it. Add the missing of_node_put() to avoid
> leaking the reference.
>
>
Applied, thanks!
[1/1] wifi: ath11k: fix refcount leak in ath11k_ahb_fw_resources_init()
commit: 0e120ee0822b7cc650bd7b29682a34e137cec10d
Best regards,
--
Jeff Johnson <jeff.johnson@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH rtw-next 08/16] wifi: rtw89: add IO offload support via firmware
From: Bitterblue Smith @ 2026-07-09 14:25 UTC (permalink / raw)
To: Ping-Ke Shih, linux-wireless
Cc: leo.li, gary.chang, echuang, wenjie.tsai, phhuang, isaiah,
kevin_yang, mh_chen
In-Reply-To: <20260420034051.17666-9-pkshih@realtek.com>
On 20/04/2026 06:40, Ping-Ke Shih wrote:
> +static void rtw89_fw_cmd_ofld_udelay(struct rtw89_dev *rtwdev, u32 us)
> +{
> + struct rtw89_fw_cmd_ofld_arg cmd = {
> + .src = RTW89_FW_CMD_OFLD_SRC_OTHER,
> + .type = RTW89_FW_CMD_OFLD_DELAY,
> + .value = us,
> + };
> + int ret;
> +
> + ret = rtw89_fw_cmd_ofld_enqueue(rtwdev, &cmd);
> + if (ret)
> + udelay(us);
> +}
> +
> +static void rtw89_fw_cmd_ofld_mdelay(struct rtw89_dev *rtwdev, u32 ms)
> +{
> + struct rtw89_fw_cmd_ofld_arg cmd = {
> + .src = RTW89_FW_CMD_OFLD_SRC_OTHER,
> + .type = RTW89_FW_CMD_OFLD_DELAY,
> + .value = ms * 1000,
> + };
> + int ret;
> +
> + ret = rtw89_fw_cmd_ofld_enqueue(rtwdev, &cmd);
> + if (ret)
> + mdelay(ms);
> +}
This can fail to compile with some kernel configurations because
RTW89_FW_CMD_OFLD_SRC_OTHER (4) doesn't fit in the mask
RTW89_H2C_CMD_OFLD_W0_SRC (GENMASK(0, 1)):
In file included from core.h:10,
from cam.h:8,
from fw.c:6:
In function ‘le32_encode_bits’,
inlined from ‘rtw89_fw_cmd_ofld_enqueue’ at fw.c:11655:12,
inlined from ‘rtw89_fw_cmd_ofld_udelay’ at fw.c:11858:8:
/usr/lib/modules/7.1.3-zen1-1-zen/build/include/linux/bitfield.h:217:17: error: call to ‘__field_overflow’ declared with attribute error: value doesn't fit into mask
217 | __field_overflow(); \
| ^~~~~~~~~~~~~~~~~~
/usr/lib/modules/7.1.3-zen1-1-zen/build/include/linux/bitfield.h:235:9: note: in expansion of macro ‘____MAKE_OP’
235 | ____MAKE_OP(le##size,u##size,cpu_to_le##size,le##size##_to_cpu) \
| ^~~~~~~~~~~
/usr/lib/modules/7.1.3-zen1-1-zen/build/include/linux/bitfield.h:240:1: note: in expansion of macro ‘__MAKE_OP’
240 | __MAKE_OP(32)
| ^~~~~~~~~
In function ‘le32_encode_bits’,
inlined from ‘rtw89_fw_cmd_ofld_enqueue’ at fw.c:11655:12,
inlined from ‘rtw89_fw_cmd_ofld_mdelay’ at fw.c:11872:8:
/usr/lib/modules/7.1.3-zen1-1-zen/build/include/linux/bitfield.h:217:17: error: call to ‘__field_overflow’ declared with attribute error: value doesn't fit into mask
217 | __field_overflow(); \
| ^~~~~~~~~~~~~~~~~~
/usr/lib/modules/7.1.3-zen1-1-zen/build/include/linux/bitfield.h:235:9: note: in expansion of macro ‘____MAKE_OP’
235 | ____MAKE_OP(le##size,u##size,cpu_to_le##size,le##size##_to_cpu) \
| ^~~~~~~~~~~
/usr/lib/modules/7.1.3-zen1-1-zen/build/include/linux/bitfield.h:240:1: note: in expansion of macro ‘__MAKE_OP’
240 | __MAKE_OP(32)
| ^~~~~~~~~
https://github.com/morrownr/rtw89/issues/111
https://github.com/morrownr/rtw89/issues/106
The reports are about the code from that repository, not the kernel,
but I assume the same thing will happen when someone tries to build
kernel 7.2 with the Zen config.
Using the same GCC 16.1.1, this fails on 7.1.3-zen1 but compiles on
7.1.3-arch1 (the standard Arch Linux kernel). This is the difference
between their /proc/config.gz:
3c3
< # Linux/x86 7.1.3-arch1 Kernel Configuration
---
> # Linux/x86 7.1.3-zen1 Kernel Configuration
40a41
> CONFIG_ZEN_INTERACTIVE=y
148a150
> # CONFIG_PREEMPT_RT is not set
218a221
> # CONFIG_SCHED_ALT is not set
270a274
> CONFIG_USER_NS_UNPRIVILEGED=y
290c294,295
< CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
---
> # CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE is not set
> CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y
1264c1269
< CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1
---
> CONFIG_COMPACT_UNEVICTABLE_DEFAULT=0
1477a1483
> CONFIG_TCP_CONG_BBR3=m
3057a3064
> CONFIG_VHBA=m
So I guess the error happens when rtw89 is compiled with -O3.
^ permalink raw reply
* [PATCH] nl80211.h: fix compiler warning
From: Gerrit Renker @ 2026-07-09 13:43 UTC (permalink / raw)
To: linux-wireless
[-- Attachment #1.1: Type: text/plain, Size: 25 bytes --]
Happens with -Wpedantic.
[-- Attachment #1.2: Type: text/html, Size: 46 bytes --]
[-- Attachment #2: 0001-nl80211.h-fix-compiler-warning.patch --]
[-- Type: text/x-patch, Size: 1238 bytes --]
From 73330fcb1b43dcc5e559b54d61f5ad96f6c4937d Mon Sep 17 00:00:00 2001
From: Gerrit Renker <grenker@aurora.tech>
Date: Thu, 9 Jul 2026 09:36:18 -0400
Subject: [PATCH] nl80211.h: fix compiler warning
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This addresses the following compiler warning occurring under `-Wpedantic`:
```console
nl80211.h:6601:59: warning: ISO C restricts enumerator values to range of ‘int’ [-Wpedantic]
6601 | NL80211_FEATURE_ND_RANDOM_MAC_ADDR = 1U << 31,
|
```
The problem is that `1 << 31` equals the value of `INT_MIN` (`-INT_MAX - 1)`, which is one
value higher than the maximum positive value `INT_MAX`.
This is not supported by ISO C before C23.
Signed-off-by: Gerrit Renker <grenker@aurora.tech>
diff --git a/nl80211.h b/nl80211.h
index 67d7640..6fc3d99 100644
--- a/nl80211.h
+++ b/nl80211.h
@@ -6598,7 +6598,7 @@ enum nl80211_feature_flags {
NL80211_FEATURE_TDLS_CHANNEL_SWITCH = 1 << 28,
NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR = 1 << 29,
NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR = 1 << 30,
- NL80211_FEATURE_ND_RANDOM_MAC_ADDR = 1U << 31,
+ NL80211_FEATURE_ND_RANDOM_MAC_ADDR = (int)(1U << 31),
};
/**
--
2.52.0
^ permalink raw reply related
* Re: [GIT PULL] wireless-2026-07-09
From: Paolo Abeni @ 2026-07-09 13:40 UTC (permalink / raw)
To: Johannes Berg, netdev; +Cc: linux-wireless
In-Reply-To: <20260709115038.243870-3-johannes@sipsolutions.net>
On 7/9/26 1:49 PM, Johannes Berg wrote:
> Sorry, I meant to send this yesterday, hoping it'd get
> in/out before netdevconf and all that, because it's
> actually really big. Mostly I've now collected many
> random LLM-induced robustness fixes (I can't really
> call most of them security fixes, though there likely
> are a few).
>
> Please pull and let us know if there's any problem.
I'm sorry I was already finalizing the rc3 net PR (which is already
quite big). I think it's not bad if this one lands in afterwards.
/P
^ permalink raw reply
* [PATCH] wifi: brcmfmac: cyw: clean up PMKID and cookie code
From: Bogdan Nicolae @ 2026-07-09 12:23 UTC (permalink / raw)
To: arend.vanspriel
Cc: Bogdan Nicolae, linux-wireless, brcm80211, brcm80211-dev-list.pdl,
linux-kernel, Bogdan Nicolae
Avoid setting packet_id to cookie, which is always 0. Instead, use an
increasing atomic counter. Avoids mismatches of completion events later
in brcmf_notify_mgmt_tx_status, where packet_id != vif->mgmt_tx_id is
checked.
Also, zero out auth_status on initialization. Otherwise, garbage will
leak from the stack to the firmware (when bssid is less than 32 bytes
and/or when params->pmkid is set). Then, pass the params->pmkid to the
firmware (without it, the firmware caches a garbage PMKID on successful
authentication and denies a subsequent association request that includes
the PMKID).
Signed-off-by: Bogdan Nicolae <bogdan.nicolae@acm.org>
---
.../net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c
index ce09d44fa..cca53ff19 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c
@@ -23,6 +23,8 @@
#define MGMT_AUTH_FRAME_DWELL_TIME 4000
#define MGMT_AUTH_FRAME_WAIT_TIME (MGMT_AUTH_FRAME_DWELL_TIME + 100)
+static atomic_t brcmf_cyw_mgmt_tx_id = ATOMIC_INIT(0);
+
static int brcmf_cyw_set_sae_pwd(struct brcmf_if *ifp,
struct cfg80211_crypto_settings *crypto)
{
@@ -155,7 +157,7 @@ int brcmf_cyw_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
memcpy(&mf_params->da[0], &mgmt->da[0], ETH_ALEN);
memcpy(&mf_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
- mf_params->packet_id = cpu_to_le32(*cookie);
+ mf_params->packet_id = cpu_to_le32(atomic_inc_return(&brcmf_cyw_mgmt_tx_id));
memcpy(mf_params->data, &buf[DOT11_MGMT_HDR_LEN],
le16_to_cpu(mf_params->len));
@@ -200,7 +202,7 @@ brcmf_cyw_external_auth(struct wiphy *wiphy, struct net_device *dev,
{
struct brcmf_if *ifp;
struct brcmf_pub *drvr;
- struct brcmf_auth_req_status_le auth_status;
+ struct brcmf_auth_req_status_le auth_status = {};
int ret = 0;
brcmf_dbg(TRACE, "Enter\n");
@@ -208,6 +210,8 @@ brcmf_cyw_external_auth(struct wiphy *wiphy, struct net_device *dev,
ifp = netdev_priv(dev);
drvr = ifp->drvr;
if (params->status == WLAN_STATUS_SUCCESS) {
+ if (params->pmkid)
+ memcpy(auth_status.pmkid, params->pmkid, WLAN_PMKID_LEN);
auth_status.flags = cpu_to_le16(BRCMF_EXTAUTH_SUCCESS);
} else {
bphy_err(drvr, "External authentication failed: status=%d\n",
--
2.55.0
^ permalink raw reply related
* [PATCH] wifi: brcmfmac: cyw: clean up PMKID and cookie code
From: Bogdan Nicolae @ 2026-07-09 12:16 UTC (permalink / raw)
To: arend.vanspriel
Cc: Bogdan Nicolae, linux-wireless, brcm80211, brcm80211-dev-list.pdl,
linux-kernel
Avoid setting packet_id to cookie, which is always 0. Instead, use an
increasing atomic counter. Avoids mismatches of completion events later
in brcmf_notify_mgmt_tx_status, where packet_id != vif->mgmt_tx_id is
checked.
Also, zero out auth_status on initialization. Otherwise, garbage will
leak from the stack to the firmware (when bssid is less than 32 bytes
and/or when params->pmkid is set). Then, pass the params->pmkid to the
firmware (without it, the firmware caches a garbage PMKID on successful
authentication and denies a subsequent association request that includes
the PMKID).
Signed-off-by: Bogdan Nicolae <bogdan.nicolae@acm.org>
---
.../net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c
index ce09d44fa..cca53ff19 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c
@@ -23,6 +23,8 @@
#define MGMT_AUTH_FRAME_DWELL_TIME 4000
#define MGMT_AUTH_FRAME_WAIT_TIME (MGMT_AUTH_FRAME_DWELL_TIME + 100)
+static atomic_t brcmf_cyw_mgmt_tx_id = ATOMIC_INIT(0);
+
static int brcmf_cyw_set_sae_pwd(struct brcmf_if *ifp,
struct cfg80211_crypto_settings *crypto)
{
@@ -155,7 +157,7 @@ int brcmf_cyw_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
memcpy(&mf_params->da[0], &mgmt->da[0], ETH_ALEN);
memcpy(&mf_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
- mf_params->packet_id = cpu_to_le32(*cookie);
+ mf_params->packet_id = cpu_to_le32(atomic_inc_return(&brcmf_cyw_mgmt_tx_id));
memcpy(mf_params->data, &buf[DOT11_MGMT_HDR_LEN],
le16_to_cpu(mf_params->len));
@@ -200,7 +202,7 @@ brcmf_cyw_external_auth(struct wiphy *wiphy, struct net_device *dev,
{
struct brcmf_if *ifp;
struct brcmf_pub *drvr;
- struct brcmf_auth_req_status_le auth_status;
+ struct brcmf_auth_req_status_le auth_status = {};
int ret = 0;
brcmf_dbg(TRACE, "Enter\n");
@@ -208,6 +210,8 @@ brcmf_cyw_external_auth(struct wiphy *wiphy, struct net_device *dev,
ifp = netdev_priv(dev);
drvr = ifp->drvr;
if (params->status == WLAN_STATUS_SUCCESS) {
+ if (params->pmkid)
+ memcpy(auth_status.pmkid, params->pmkid, WLAN_PMKID_LEN);
auth_status.flags = cpu_to_le16(BRCMF_EXTAUTH_SUCCESS);
} else {
bphy_err(drvr, "External authentication failed: status=%d\n",
--
2.55.0
^ permalink raw reply related
* [GIT PULL] wireless-2026-07-09
From: Johannes Berg @ 2026-07-09 11:49 UTC (permalink / raw)
To: netdev; +Cc: linux-wireless
Hi,
Sorry, I meant to send this yesterday, hoping it'd get
in/out before netdevconf and all that, because it's
actually really big. Mostly I've now collected many
random LLM-induced robustness fixes (I can't really
call most of them security fixes, though there likely
are a few).
Please pull and let us know if there's any problem.
Thanks,
johannes
The following changes since commit 87320be9f0d24fce67631b7eef919f0b79c3e45c:
Merge tag 'net-7.2-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net (2026-07-02 06:01:12 -1000)
are available in the Git repository at:
https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless.git tags/wireless-2026-07-09
for you to fetch changes up to cb8afea4655ff004fa7feee825d5c79783525383:
wifi: cfg80211: bound element ID read when checking non-inheritance (2026-07-07 14:00:35 +0200)
----------------------------------------------------------------
Too many robustness fixes to list. Mostly for
- slight out-of-bounds reads of SKBs,
- leaks on error conditions, and
- malformed netlink input rejection.
----------------------------------------------------------------
Abdun Nihaal (1):
wifi: ipw2100: fix potential memory leak in ipw2100_pci_init_one()
Arnd Bergmann (1):
wifi: mac80211: allocate backup ieee80211_nan_sched_cfg off stack
Bryam Vargas (1):
wifi: mac80211_hwsim: clamp virtio RX length before skb_put
Cen Zhang (3):
wifi: cfg80211: cancel sched scan results work on unregister
wifi: mac80211: free AP_VLAN bc_buf SKBs outside IRQ lock
wifi: cfg80211: use wiphy work for socket owner autodisconnect
Christophe JAILLET (1):
wifi: cfg80211: Fix an error handling path in cfg80211_wext_siwscan()
Corentin Labbe (1):
wifi: ralink: RT2X00: init EEPROM properly
Dawei Feng (2):
wifi: libertas: fix memory leak in helper_firmware_cb()
wifi: mac80211: fix memory leak in ieee80211_register_hw()
HE WEI (ギカク) (1):
wifi: cfg80211: bound element ID read when checking non-inheritance
Haofeng Li (1):
wifi: cfg80211: validate EHT MLE before MLD ID read
Maoyi Xie (3):
wifi: libertas_tf: fix use-after-free in lbtf_free_adapter()
wifi: mac80211: defer link RX stats percpu free to RCU
wifi: brcmfmac: cyw: fix heap overflow on a short auth frame
Pagadala Yesu Anjaneyulu (1):
wifi: mac80211: ibss: wait for in-flight TX on disconnect
Peddolla Harshavardhan Reddy (1):
wifi: cfg80211: convert pmsr_free_wk to wiphy_work to fix deadlock
Pengpeng Hou (5):
wifi: rsi: avoid reading TKIP MIC keys for non-TKIP ciphers
wifi: libertas: reject short monitor TX frames
wifi: rsi: bound background scan probe request copy
wifi: libipw: fix key index receive bound checks
wifi: rsi: validate beacon length before fixed buffer copy
Rafael Beims (2):
wifi: mwifiex: fix roaming to different channel in host_mlme mode
wifi: mwifiex: fix permanently busy scans after multiple roam iterations
Runyu Xiao (2):
wifi: rt2x00: avoid full teardown before work setup in probe
wifi: brcmfmac: initialize SDIO data work before cleanup
Shahar Tzarfati (1):
wifi: mac80211: recalculate rx_nss on IBSS peer capability update
Xiang Mei (3):
wifi: mac80211: fix unsol_bcast_probe_resp double free on alloc failure
wifi: mac80211: fix fils_discovery double free on alloc failure
wifi: p54: validate RX frame length in p54_rx_eeprom_readback()
Yousef Alhouseen (1):
wifi: mac80211_hwsim: avoid treating MCS as legacy rate index
Zhao Li (14):
wifi: nl80211: free RNR data on MBSSID mismatch
wifi: mac80211: validate extension-frame layout before RX
wifi: cfg80211: derive S1G beacon TSF from S1G fields
wifi: ieee80211: validate MLE common info length
wifi: nl80211: validate nested MBSSID IE blobs
wifi: nl80211: constrain MBSSID TX link ID range
wifi: cfg80211: validate PMSR measurement type data
wifi: cfg80211: validate PMSR FTM preamble range
wifi: cfg80211: reject unsupported PMSR FTM location requests
wifi: cfg80211: reject empty PMSR peer lists
wifi: mac80211: avoid non-S1G AID fallback for S1G assoc
wifi: mac80211: validate deauth frame length before reason access
wifi: cfg80211: validate rx/tx MLME callback frame lengths before access
wifi: cfg80211: validate assoc response length before status and IE access
Zhiling Zou (1):
wifi: mac80211: free ack status frame on TX header build failure
.../broadcom/brcm80211/brcmfmac/cyw/core.c | 6 ++
.../wireless/broadcom/brcm80211/brcmfmac/sdio.c | 2 +-
drivers/net/wireless/intel/ipw2x00/ipw2100.c | 8 +-
drivers/net/wireless/intel/ipw2x00/libipw_rx.c | 4 +-
drivers/net/wireless/intersil/p54/txrx.c | 8 ++
drivers/net/wireless/marvell/libertas/firmware.c | 1 +
drivers/net/wireless/marvell/libertas/tx.c | 7 ++
drivers/net/wireless/marvell/libertas_tf/main.c | 2 +-
drivers/net/wireless/marvell/mwifiex/cfg80211.c | 2 +-
drivers/net/wireless/marvell/mwifiex/join.c | 1 -
drivers/net/wireless/ralink/rt2x00/rt2400pci.c | 2 +-
drivers/net/wireless/ralink/rt2x00/rt2500pci.c | 2 +-
drivers/net/wireless/ralink/rt2x00/rt2800pci.c | 2 +-
drivers/net/wireless/ralink/rt2x00/rt2x00dev.c | 12 ++-
drivers/net/wireless/ralink/rt2x00/rt61pci.c | 2 +-
drivers/net/wireless/rsi/rsi_91x_hal.c | 8 ++
drivers/net/wireless/rsi/rsi_91x_mgmt.c | 12 ++-
drivers/net/wireless/virtual/mac80211_hwsim_main.c | 16 +++-
include/linux/ieee80211-eht.h | 12 +--
include/net/cfg80211.h | 4 +-
net/mac80211/cfg.c | 11 ++-
net/mac80211/ibss.c | 13 +--
net/mac80211/iface.c | 8 +-
net/mac80211/main.c | 3 +-
net/mac80211/mlme.c | 12 ++-
net/mac80211/nan.c | 35 +++----
net/mac80211/rx.c | 34 ++++++-
net/mac80211/sta_info.c | 15 ++-
net/mac80211/tx.c | 17 +++-
net/mac80211/util.c | 3 +
net/wireless/core.c | 14 +--
net/wireless/core.h | 4 +-
net/wireless/mlme.c | 105 +++++++++++++++------
net/wireless/nl80211.c | 25 +++--
net/wireless/pmsr.c | 34 +++++--
net/wireless/scan.c | 18 ++--
net/wireless/sme.c | 6 +-
37 files changed, 336 insertions(+), 134 deletions(-)
^ permalink raw reply
* [PATCH wireless-next v6 4/4] wifi: mac80211_hwsim: report TX status link_id
From: Priyansha Tiwari @ 2026-07-09 11:42 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, veerendranath.jakkam
In-Reply-To: <20260709114228.672317-1-pritiwa@qti.qualcomm.com>
From: Priyansha Tiwari <priyansha.tiwari@oss.qualcomm.com>
Populate link_valid/link_id in mac80211_hwsim TX status so the
transmitted link is reported to mac80211.
Set the link information in both the direct TX status path and the
wmediumd/netlink TX status path.
Signed-off-by: Priyansha Tiwari <priyansha.tiwari@oss.qualcomm.com>
---
.../wireless/virtual/mac80211_hwsim_main.c | 43 +++++++++++++++++--
1 file changed, 40 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/virtual/mac80211_hwsim_main.c b/drivers/net/wireless/virtual/mac80211_hwsim_main.c
index 0dd8a6c85953..61fd8d8ba1a0 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim_main.c
+++ b/drivers/net/wireless/virtual/mac80211_hwsim_main.c
@@ -2103,6 +2103,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
bool ack, unicast_data;
enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT;
u32 _portid, i;
+ int tx_link_id = -1;
if (WARN_ON(skb->len < 10)) {
/* Should not happen; just a sanity check for addr1 use */
@@ -2160,6 +2161,9 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
hdr, &link_sta);
}
+ if (bss_conf)
+ tx_link_id = bss_conf->link_id;
+
if (unlikely(!bss_conf)) {
/* if it's an MLO STA, it might have deactivated all
* links temporarily - but we don't handle real PS in
@@ -2271,6 +2275,12 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && ack)
txi->flags |= IEEE80211_TX_STAT_ACK;
+
+ if (tx_link_id >= 0) {
+ txi->status.link_valid = 1;
+ txi->status.link_id = tx_link_id;
+ }
+
ieee80211_tx_status_irqsafe(hw, skb);
}
@@ -6092,6 +6102,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_PUNCT);
+ wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_PROBE_AP);
for (i = 0; i < ARRAY_SIZE(data->link_data); i++) {
hrtimer_setup(&data->link_data[i].beacon_timer, mac80211_hwsim_beacon,
@@ -6317,6 +6328,27 @@ static void hwsim_register_wmediumd(struct net *net, u32 portid)
spin_unlock_bh(&hwsim_radio_lock);
}
+static int mac80211_hwsim_get_link_id(struct ieee80211_vif *vif,
+ struct ieee80211_hdr *hdr)
+{
+ int i;
+
+ if (!vif || !ieee80211_vif_is_mld(vif))
+ return -1;
+
+ for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {
+ struct ieee80211_bss_conf *link_conf;
+
+ link_conf = rcu_dereference(vif->link_conf[i]);
+ if (!link_conf)
+ continue;
+ if (ether_addr_equal(link_conf->addr, hdr->addr2))
+ return i;
+ }
+
+ return -1;
+}
+
static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
struct genl_info *info)
{
@@ -6397,13 +6429,18 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
txi->status.ack_signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]);
+ hdr = (struct ieee80211_hdr *)skb->data;
+ i = mac80211_hwsim_get_link_id(txi->control.vif, hdr);
+ if (i >= 0) {
+ txi->status.link_valid = 1;
+ txi->status.link_id = i;
+ }
+
if (!(hwsim_flags & HWSIM_TX_CTL_NO_ACK) &&
(hwsim_flags & HWSIM_TX_STAT_ACK)) {
- if (skb->len >= 16) {
- hdr = (struct ieee80211_hdr *) skb->data;
+ if (skb->len >= 16)
mac80211_hwsim_monitor_ack(data2->channel,
hdr->addr2);
- }
txi->flags |= IEEE80211_TX_STAT_ACK;
}
--
2.34.1
^ permalink raw reply related
* [PATCH wireless-next v6 3/4] wifi: mac80211: implement STA-mode peer probing
From: Priyansha Tiwari @ 2026-07-09 11:42 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, veerendranath.jakkam
In-Reply-To: <20260709114228.672317-1-pritiwa@qti.qualcomm.com>
From: Priyansha Tiwari <priyansha.tiwari@oss.qualcomm.com>
Add STA/P2P-client support to ieee80211_probe_peer(): when called
for a station interface, send a null-data frame (TODS) to the
associated AP and report the ACK via cfg80211_probe_status().
For MLO connections the driver/firmware selects the link
(IEEE80211_LINK_UNSPECIFIED); for non-MLO the single link is used.
Signed-off-by: Priyansha Tiwari <priyansha.tiwari@oss.qualcomm.com>
---
include/net/mac80211.h | 7 ++-
net/mac80211/cfg.c | 117 ++++++++++++++++++++---------------------
net/mac80211/status.c | 5 +-
3 files changed, 67 insertions(+), 62 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 4f95da023746..78beb6e3bdd4 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1342,6 +1342,11 @@ ieee80211_rate_get_vht_nss(const struct ieee80211_tx_rate *rate)
* @status.tx_time: airtime consumed for transmission; note this is only
* used for WMM AC, not for airtime fairness
* @status.flags: status flags, see &enum mac80211_tx_status_flags
+ * @status.link_valid: if the link which is identified by @status.link_id is
+ * valid. This flag is set by the driver in the TX status callback when the
+ * connection is MLO and the driver knows which link was used for TX.
+ * @status.link_id: id of the link used to transmit the packet. This is used
+ * along with @status.link_valid.
* @status.status_driver_data: driver use area
* @ack: union part for pure ACK data
* @ack.cookie: cookie for the ACK
@@ -1396,7 +1401,7 @@ struct ieee80211_tx_info {
u8 pad;
u16 tx_time;
u8 flags;
- u8 pad2;
+ u8 link_valid:1, link_id:4;
void *status_driver_data[16 / sizeof(void *)];
} status;
struct {
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 9c311c8290f7..df68a5bdeb2f 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -4956,99 +4956,100 @@ static int ieee80211_probe_peer(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_local *local = sdata->local;
struct ieee80211_qos_hdr *nullfunc;
struct sk_buff *skb;
- int size = sizeof(*nullfunc);
__le16 fc;
- bool qos;
+ bool qos, fromds;
+ struct ieee80211_bss_conf *conf;
struct ieee80211_tx_info *info;
struct sta_info *sta;
struct ieee80211_chanctx_conf *chanctx_conf;
- struct ieee80211_bss_conf *conf;
enum nl80211_band band;
- u8 link_id;
+ const u8 *dst_addr;
+ const u8 *src_addr;
+ int link_id;
+ int size;
int ret;
/* the lock is needed to assign the cookie later */
lockdep_assert_wiphy(local->hw.wiphy);
- rcu_read_lock();
- sta = sta_info_get_bss(sdata, peer);
- if (!sta) {
- ret = -ENOLINK;
- goto unlock;
+ switch (ieee80211_vif_type_p2p(&sdata->vif)) {
+ case NL80211_IFTYPE_AP:
+ fromds = true;
+ break;
+ case NL80211_IFTYPE_STATION:
+ /* For STA, the peer is always the associated AP/GO */
+ peer = sdata->vif.cfg.ap_addr;
+ fromds = false;
+ break;
+ default:
+ return -EOPNOTSUPP;
}
+ sta = sta_info_get_bss(sdata, peer);
+ if (!sta)
+ return -ENOLINK;
+
qos = sta->sta.wme;
+ dst_addr = sta->sta.addr;
if (ieee80211_vif_is_mld(&sdata->vif)) {
- if (sta->sta.mlo) {
- link_id = IEEE80211_LINK_UNSPECIFIED;
- } else {
+ if (fromds && !sta->sta.mlo) {
/*
- * For non-MLO clients connected to an AP MLD, band
- * information is not used; instead, sta->deflink is
- * used to send packets.
+ * AP mode, non-MLO client on AP MLD: use the
+ * per-link address for the client's link.
*/
link_id = sta->deflink.link_id;
-
- conf = rcu_dereference(sdata->vif.link_conf[link_id]);
-
- if (unlikely(!conf)) {
- ret = -ENOLINK;
- goto unlock;
- }
+ conf = wiphy_dereference(local->hw.wiphy,
+ sdata->vif.link_conf[link_id]);
+ if (!conf)
+ return -ENOLINK;
+ src_addr = conf->addr;
+ } else {
+ /*
+ * MLO client (AP or STA mode), or STA mode:
+ * always use LINK_UNSPECIFIED and MLD address.
+ */
+ link_id = IEEE80211_LINK_UNSPECIFIED;
+ src_addr = sdata->vif.addr;
}
/* MLD transmissions must not rely on the band */
band = 0;
} else {
- chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
- if (WARN_ON(!chanctx_conf)) {
- ret = -EINVAL;
- goto unlock;
- }
+ chanctx_conf = wiphy_dereference(local->hw.wiphy,
+ sdata->vif.bss_conf.chanctx_conf);
+ if (WARN_ON(!chanctx_conf))
+ return -EINVAL;
band = chanctx_conf->def.chan->band;
link_id = 0;
+ src_addr = sdata->vif.addr;
}
- if (qos) {
- fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
- IEEE80211_STYPE_QOS_NULLFUNC |
- IEEE80211_FCTL_FROMDS);
- } else {
+ size = sizeof(*nullfunc);
+ fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
+ (qos ? IEEE80211_STYPE_QOS_NULLFUNC
+ : IEEE80211_STYPE_NULLFUNC) |
+ (fromds ? IEEE80211_FCTL_FROMDS : IEEE80211_FCTL_TODS));
+ if (!qos)
size -= 2;
- fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
- IEEE80211_STYPE_NULLFUNC |
- IEEE80211_FCTL_FROMDS);
- }
skb = dev_alloc_skb(local->hw.extra_tx_headroom + size);
- if (!skb) {
- ret = -ENOMEM;
- goto unlock;
- }
+ if (!skb)
+ return -ENOMEM;
skb->dev = dev;
-
skb_reserve(skb, local->hw.extra_tx_headroom);
- nullfunc = skb_put(skb, size);
+ nullfunc = skb_put_zero(skb, size);
nullfunc->frame_control = fc;
- nullfunc->duration_id = 0;
- memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN);
- if (ieee80211_vif_is_mld(&sdata->vif) && !sta->sta.mlo) {
- memcpy(nullfunc->addr2, conf->addr, ETH_ALEN);
- memcpy(nullfunc->addr3, conf->addr, ETH_ALEN);
- } else {
- memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
- memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN);
- }
- nullfunc->seq_ctrl = 0;
- info = IEEE80211_SKB_CB(skb);
+ memcpy(nullfunc->addr1, dst_addr, ETH_ALEN);
+ memcpy(nullfunc->addr2, src_addr, ETH_ALEN);
+ memcpy(nullfunc->addr3, fromds ? src_addr : dst_addr, ETH_ALEN);
+ info = IEEE80211_SKB_CB(skb);
info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS |
IEEE80211_TX_INTFL_NL80211_FRAME_TX;
info->band = band;
-
info->control.flags |= u32_encode_bits(link_id,
IEEE80211_TX_CTRL_MLO_LINK);
skb_set_queue_mapping(skb, IEEE80211_AC_VO);
@@ -5059,18 +5060,14 @@ static int ieee80211_probe_peer(struct wiphy *wiphy, struct net_device *dev,
ret = ieee80211_attach_ack_skb(local, skb, cookie, GFP_ATOMIC);
if (ret) {
kfree_skb(skb);
- goto unlock;
+ return ret;
}
local_bh_disable();
ieee80211_xmit(sdata, sta, skb);
local_bh_enable();
- ret = 0;
-unlock:
- rcu_read_unlock();
-
- return ret;
+ return 0;
}
static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index c3d29aed93fe..d635490f59d3 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -655,7 +655,10 @@ static void ieee80211_report_ack_skb(struct ieee80211_local *local,
GFP_ATOMIC);
else if (ieee80211_is_any_nullfunc(hdr->frame_control))
cfg80211_probe_status(sdata->dev, hdr->addr1,
- cookie, -1, acked,
+ cookie,
+ info->status.link_valid ?
+ info->status.link_id : -1,
+ acked,
info->status.ack_signal,
is_valid_ack_signal,
GFP_ATOMIC);
--
2.34.1
^ permalink raw reply related
* [PATCH wireless-next v6 0/4] wifi: nl80211: introduce PROBE_PEER for AP and STA
From: Priyansha Tiwari @ 2026-07-09 11:42 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, veerendranath.jakkam
From: Priyansha Tiwari <priyansha.tiwari@oss.qualcomm.com>
This series introduces a unified mechanism to probe connected peers.
It generalizes the legacy AP-only PROBE_CLIENT functionality by adding
NL80211_CMD_PROBE_PEER and enabling (feature-gated) STA-side probing.
With this, AP/GO continues to probe associated stations as before, and
STA/P2P-client can probe the connected AP for faster link health checks.
For MLO connections, mac80211 supports per-link STA probing to obtain
link-specific ACK information.
Patch 1 renames NL80211_CMD_PROBE_CLIENT to NL80211_CMD_PROBE_PEER in
the UAPI enum (keeping PROBE_CLIENT as a compatibility alias) and renames
the .probe_client cfg80211_ops callback to .probe_peer. All in-tree users
(wil6210, mwifiex, mac80211) are updated so the tree builds after this
patch. This is a pure rename with no behaviour change; documentation is
intentionally left unchanged.
Patch 2 updates the @probe_peer documentation in cfg80211_ops to describe
the STA-mode semantics, adds NL80211_EXT_FEATURE_PROBE_AP to advertise
STA-side support, extends cfg80211_probe_status() to carry an optional
peer address and a link_id (-1 for non-MLO), and extends the nl80211
handler to accept STA/P2P-client interfaces when the driver advertises
the feature (MAC attribute must be omitted; the AP is implied by the
association). All callers of cfg80211_probe_status() are updated.
Patch 3 adds per-link PROBE_PEER support in mac80211 for STA/P2P-client
mode. For STA/P2P-client, it uses IEEE80211_LINK_UNSPECIFIED together
with the associated AP/GO address and lets the driver select the link.
For non-MLO connections, mac80211 still fills info->band from the
current chanctx so legacy transmissions continue to carry the correct
band information. The link_valid/link_id bitfields added to
ieee80211_tx_info.status are filled by the driver in the TX status
callback and read back in ieee80211_report_ack_skb() to report the
actual link_id to userspace. AP/GO behaviour is unchanged.
Patch 4 makes mac80211_hwsim populate link_valid/link_id in TX status
for both the direct TX status path and the wmediumd/netlink TX status
path.
---
Changes in v6:
- Patch 3:
* Dropped the remaining rcu_read_lock()/rcu_read_unlock() — the
function now runs entirely under wiphy_lock, so sta_info_get_bss()
is called without an explicit RCU lock and goto unlock is replaced
with direct return statements.
* Restructured the MLD branch: flipped the condition to
fromds && !sta->sta.mlo for the AP-mode non-MLO client case,
making the STA/MLO path the default else branch.
* Added src_addr variable to unify address construction, replacing
the conditional memcpy blocks.
* Used skb_put_zero() to zero-initialise the frame, removing manual
field zeroing (duration_id, seq_ctrl).
* Simplified frame control and addr3 construction into single
expressions.
* Removed the pre-setting of info->status.link_valid/link_id in
ieee80211_probe_peer() before TX — status fields must be filled
by the driver in the TX status callback, not by the caller.
ieee80211_report_ack_skb() reads link_valid/link_id from the
driver-filled TX status to report the actual link_id to userspace.
Changes in v5:
- Patch 3:
* Renamed peer_addr to dst_addr for clarity.
* Reworked ieee80211_probe_peer() to share more logic between
AP and STA modes by using ieee80211_vif_type_p2p(),
overriding the STA peer to the associated AP/GO address,
and pulling the common sta lookup/qos handling out of the
switch.
* Kept the remaining AP/STA difference limited to the DS bits,
while preserving the existing MLO/non-MLO address and band
handling.
Changes in v4:
- Patch 3:
* Dropped guard(rcu)() from ieee80211_probe_peer() and used
wiphy_dereference() under the already held wiphy lock.
* Simplified STA/P2P-client probing to use
IEEE80211_LINK_UNSPECIFIED together with the associated
AP/GO address for both MLO and non-MLO cases.
* Kept the non-MLO band lookup via chanctx so legacy
transmissions still carry the correct band.
* Return -ENOLINK when the associated AP STA entry is missing,
instead of falling back to non-QoS probing.
Changes in v3:
- Restructured patch split:
* Patch 1: pure rename (probe_client -> probe_peer), no doc changes
* Patch 2: documentation update for STA-mode semantics +
nl80211 API logic change + cfg80211_probe_status update
* Patch 3: mac80211 implementation
- Removed unnecessary bitfield padding (no pad2:3)
- Moved MAC-omission check for STA mode into cfg80211/nl80211
(not mac80211).
- Used switch statement in both nl80211_probe_peer() and
ieee80211_probe_peer().
- Used guard(rcu)() instead of manual rcu_read_lock/unlock
- Return -ENOLINK (not -ENOTCONN) for unconnected STA, consistent
with cfg80211 conventions
Priyansha Tiwari (4):
wifi: nl80211/cfg80211: rename probe_client to probe_peer
wifi: cfg80211/nl80211: add STA-mode peer probing
wifi: mac80211: implement STA-mode peer probing
wifi: mac80211_hwsim: report TX status link_id
drivers/net/wireless/ath/wil6210/cfg80211.c | 10 +-
.../net/wireless/marvell/mwifiex/cfg80211.c | 8 +-
.../wireless/virtual/mac80211_hwsim_main.c | 43 +++++-
include/net/cfg80211.h | 18 +--
include/net/mac80211.h | 7 +-
include/uapi/linux/nl80211.h | 23 ++--
net/mac80211/cfg.c | 123 +++++++++---------
net/mac80211/status.c | 5 +-
net/wireless/nl80211.c | 69 ++++++----
net/wireless/rdev-ops.h | 10 +-
net/wireless/trace.h | 2 +-
11 files changed, 194 insertions(+), 124 deletions(-)
--
2.34.1
^ permalink raw reply
* [PATCH v2] wifi: rtw89: advertise EML capabilities for 8922a
From: Louis Kotze @ 2026-07-09 10:31 UTC (permalink / raw)
To: Ping-Ke Shih; +Cc: linux-wireless, linux-kernel, loukot
The driver implements the EMLSR operating mode for 8922a and selects
it when an interface has more than one active link (enum
rtw89_mlo_mode, rtw89_ops_vif_cfg_changed()), but leaves
eml_capabilities = 0 in the STA iftype-ext-cap. mac80211 therefore
advertises no EML capabilities in the Multi-Link element, so an
EMLSR-capable AP cannot negotiate EMLSR with this STA.
Populate eml_capabilities with IEEE80211_EML_CAP_EMLSR_SUPP, an EML
padding delay of 256 us and an EMLSR transition delay of 32 us,
following the same layout iwlwifi uses (iwlwifi advertises 32 us and
64 us). These values have run stably on my RTL8922AU since late
April; if Realtek has recommended values for this silicon I am happy
to adjust them.
In A/B testing against a TP-Link Deco BE63 (EMLSR-capable Wi-Fi 7
AP), ML association without this change came up with a single link;
with it, both the 5 GHz and 6 GHz links are set up (debugfs shows
link-1 and link-2 with active_links behaving as expected for EMLSR),
stable across 60+ hour soaks with no kernel or wpa_supplicant
errors.
EMLMR is deliberately not advertised: the chip has a single shared
2T2R RF block (rf_path_num = 2) and the driver has no EMLMR mode, so
EMLSR is the architectural ceiling for this silicon. Realtek's Wi-Fi
Alliance certification of RTL8922AE (WFA129313) likewise lists EMLSR
but not EMLMR; the certification was obtained with the Windows
driver, so it is cited only as evidence of silicon and firmware
capability.
Signed-off-by: Louis Kotze <loukot@gmail.com>
---
Changes in v2 (was patch 1/4 of "advertise WFA-certified EHT
capabilities for 8922a"):
- Narrowed the series to this single patch; see the reply on the v1
thread for why the other three capabilities are deferred.
- Dropped Restricted TWT from this patch: no in-tree driver
advertises it for a STA yet and I cannot verify the firmware side.
- Dropped the WFA certificate Link: trailer; the certification was
obtained with the Windows driver, so it is cited in the body only
as silicon-side evidence.
- Stated the advertised delay values and their testing basis
explicitly, and switched to the __bf_shf() layout iwlwifi uses.
- Rebased onto wireless-next; also applies cleanly on rtw-next
(2b7858891b10).
drivers/net/wireless/realtek/rtw89/core.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index 0f0e46cb4260..69eaae3586cb 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -217,7 +217,12 @@ static const struct wiphy_iftype_ext_capab rtw89_iftypes_ext_capa[] = {
.extended_capabilities_mask = rtw89_ext_capa_sta,
.extended_capabilities_len = sizeof(rtw89_ext_capa_sta),
/* relevant only if EHT is supported */
- .eml_capabilities = 0,
+ .eml_capabilities =
+ IEEE80211_EML_CAP_EMLSR_SUPP |
+ IEEE80211_EML_CAP_EML_PADDING_DELAY_256US <<
+ __bf_shf(IEEE80211_EML_CAP_EML_PADDING_DELAY) |
+ IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_32US <<
+ __bf_shf(IEEE80211_EML_CAP_EML_TRANSITION_DELAY),
.mld_capa_and_ops = 0,
},
};
base-commit: ac798f757d6475dc6fee2ec899980d6740714596
--
2.55.0
^ permalink raw reply related
* Re: [PATCH 0/4] wifi: rtw89: advertise WFA-certified EHT capabilities for 8922a
From: Louis Kotze @ 2026-07-09 10:31 UTC (permalink / raw)
To: Ping-Ke Shih; +Cc: linux-wireless, linux-kernel, loukot
In-Reply-To: <7e092f6cf82c4bb18b59ba5eca40dbb5@realtek.com>
On Tue, 6 May 2026, Ping-Ke Shih wrote:
> Wi-Fi Component Operating System: Windows
>
> That means hardware is capable, but Linux driver might need more
> implementation, not just declaration. I will ask internal to check them.
>
> But I think it is not necessary to add this link as reference.
Agreed on both points, thanks for the correction. I went back over
each capability with that lens, and it changed the series more than
I expected:
- TTLM (was 3/4): you are right. H2C_FUNC_MLO_TTLM is defined but
not wired anywhere in the driver, so advertising it would be
declaration without implementation. Dropped.
- Restricted TWT (was part of 1/4): no in-tree driver advertises
IEEE80211_EHT_MAC_CAP0_RESTRICTED_TWT for a STA today, and I
cannot verify what the firmware needs. Dropped.
- Rx 1024/4096-QAM in less-than-242-tone RU (was 2/4): I had
mischaracterized this bit as generic multi-RU receive support;
it is specifically about high-order QAM on small RUs, which I
cannot verify at the PHY level. Dropped.
- EHT OM Control (was 4/4): the drivers that set this for a STA
(iwlwifi, mt7925) also advertise HE OMI control on the STA
iftype, which rtw89 sets only for AP. Advertising the EHT
extension without the HE base looked inconsistent, so I dropped
it rather than widen the change to the shared HE path.
If your internal check concludes any of these are supportable as-is,
I am happy to bring them back as follow-ups with the right
justification.
> I'd like to know if these patches have explicit improvement to you?
> Or you only test these without regression?
Only the EML capabilities patch has an explicit improvement: in A/B
testing on my RTL8922AU against a TP-Link Deco BE63, ML association
without it came up with a single link, and with it both the 5 GHz
and 6 GHz links are set up (debugfs link-1/link-2, active_links
behaving as expected for EMLSR), stable across 60+ hour soaks. The
other three were no-regression only, which is part of why v2 drops
them.
v2 is therefore that single patch, and follows.
Louis
^ permalink raw reply
* [PATCH] wifi: brcmfmac: drain bus_reset work on device removal
From: Fan Wu @ 2026-07-09 10:16 UTC (permalink / raw)
To: Arend van Spriel, Kalle Valo
Cc: Franky Lin, Hante Meuleman, Chi-Hsien Lin, Wright Feng,
Chung-Hsien Hsu, David S . Miller, Jakub Kicinski, linux-wireless,
brcm80211-dev-list.pdl, SHA-cyfmac-dev-list, netdev, linux-kernel,
Fan Wu, stable
brcmf_fw_crashed() and the debugfs "reset" entry both schedule
drvr->bus_reset, whose callback recovers drvr through container_of()
and dereferences it. The teardown paths free drvr (brcmf_free ->
wiphy_free) without draining the work, so a bus_reset callback pending
or running during removal can outlive drvr.
Cancellation cannot live in brcmf_detach() or brcmf_free(): the work
callback reaches teardown through the bus .reset op (PCIe
brcmf_pcie_reset -> brcmf_detach; SDIO brcmf_sdio_bus_reset ->
brcmf_sdiod_remove -> brcmf_free), so cancelling there would wait for
the running work and deadlock. Arming and the drain must also be
mutually exclusive: a debugfs writer can otherwise schedule bus_reset
after the drain and before the debugfs file is removed in
brcmf_cfg80211_detach(), re-opening the window.
Add a per-bus mutex and route all arming through
brcmf_bus_schedule_reset(), which under the lock skips when the bus is
marked removing. Each bus remove entry calls
brcmf_bus_cancel_reset_work(), which under the same lock sets removing
and cancels the work. Where applicable the remove entry first stops
the firmware-crash producer: on PCIe mask the mailbox and
synchronize_irq; on SDIO unregister the bus interrupt and cancel the
data worker, which also reports firmware halts through
brcmf_fw_crashed(). The mutex is initialized at bus allocation so it
is ready before any firmware-probe or removal path can reach it. The
SDIO suspend power-off path frees drvr through the same
brcmf_sdiod_remove() and takes the same lock; resume re-allows the work
only on a successful re-probe.
This issue was found by an in-house static analysis tool.
Fixes: 4684997d9eea ("brcmfmac: reset PCIe bus on a firmware crash")
Cc: stable@vger.kernel.org
Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>
Assisted-by: Codex:gpt-5.5
---
.../broadcom/brcm80211/brcmfmac/bcmsdh.c | 13 ++++++++
.../broadcom/brcm80211/brcmfmac/bus.h | 6 ++++
.../broadcom/brcm80211/brcmfmac/core.c | 33 +++++++++++++++++--
.../broadcom/brcm80211/brcmfmac/pcie.c | 6 ++++
.../broadcom/brcm80211/brcmfmac/sdio.c | 6 ++++
.../broadcom/brcm80211/brcmfmac/sdio.h | 1 +
.../broadcom/brcm80211/brcmfmac/usb.c | 3 ++
7 files changed, 66 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
index ac02244a6..c4bb32aec 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
@@ -1043,6 +1043,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL);
if (!bus_if)
return -ENOMEM;
+ mutex_init(&bus_if->bus_reset_lock);
sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL);
if (!sdiodev) {
kfree(bus_if);
@@ -1102,6 +1103,14 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func)
if (func->num != 1)
return;
+ /* Drain bus_reset before the shared brcmf_sdiod_remove()
+ * teardown, which the SDIO reset callback also reaches. The
+ * data worker can arm bus_reset via brcmf_fw_crashed(); cancel
+ * it first.
+ */
+ brcmf_sdio_cancel_datawork(sdiodev->bus);
+ brcmf_bus_cancel_reset_work(bus_if);
+
/* only proceed with rest of cleanup if func 1 */
brcmf_sdiod_remove(sdiodev);
@@ -1163,6 +1172,8 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
} else {
/* power will be cut so remove device, probe again in resume */
brcmf_sdiod_intr_unregister(sdiodev);
+ brcmf_sdio_cancel_datawork(sdiodev->bus);
+ brcmf_bus_cancel_reset_work(bus_if);
ret = brcmf_sdiod_remove(sdiodev);
if (ret)
brcmf_err("Failed to remove device on suspend\n");
@@ -1188,6 +1199,8 @@ static int brcmf_ops_sdio_resume(struct device *dev)
ret = brcmf_sdiod_probe(sdiodev);
if (ret)
brcmf_err("Failed to probe device on resume\n");
+ else
+ brcmf_bus_allow_reset_work(bus_if);
} else {
if (sdiodev->wowl_enabled &&
sdiodev->settings->bus.sdio.oob_irq_supported)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
index 3f5da3bb6..b606094af 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
@@ -6,6 +6,7 @@
#ifndef BRCMFMAC_BUS_H
#define BRCMFMAC_BUS_H
+#include <linux/mutex.h>
#include "debug.h"
/* IDs of the 6 default common rings of msgbuf protocol */
@@ -149,11 +150,16 @@ struct brcmf_bus {
u32 chiprev;
bool always_use_fws_queue;
bool wowl_supported;
+ bool removing; /* device removal in progress; quiesce async work */
+ struct mutex bus_reset_lock;
const struct brcmf_bus_ops *ops;
struct brcmf_bus_msgbuf *msgbuf;
};
+void brcmf_bus_cancel_reset_work(struct brcmf_bus *bus_if);
+void brcmf_bus_allow_reset_work(struct brcmf_bus *bus_if);
+
/*
* callback wrappers
*/
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index fed9cd5f2..b934feb9b 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -1164,6 +1164,35 @@ static int brcmf_revinfo_read(struct seq_file *s, void *data)
return 0;
}
+/* Serialize bus_reset arming (debugfs reset write, brcmf_fw_crashed) against the
+ * teardown drain: the remove path takes bus_reset_lock, sets ->removing and cancels
+ * the work under it, so a racing armer either schedules before the cancel (and is
+ * drained) or observes ->removing and desists.
+ */
+static void brcmf_bus_schedule_reset(struct brcmf_bus *bus_if)
+{
+ mutex_lock(&bus_if->bus_reset_lock);
+ if (bus_if->drvr && bus_if->drvr->bus_reset.func && !bus_if->removing)
+ schedule_work(&bus_if->drvr->bus_reset);
+ mutex_unlock(&bus_if->bus_reset_lock);
+}
+
+void brcmf_bus_cancel_reset_work(struct brcmf_bus *bus_if)
+{
+ mutex_lock(&bus_if->bus_reset_lock);
+ bus_if->removing = true;
+ if (bus_if->drvr)
+ cancel_work_sync(&bus_if->drvr->bus_reset);
+ mutex_unlock(&bus_if->bus_reset_lock);
+}
+
+void brcmf_bus_allow_reset_work(struct brcmf_bus *bus_if)
+{
+ mutex_lock(&bus_if->bus_reset_lock);
+ bus_if->removing = false;
+ mutex_unlock(&bus_if->bus_reset_lock);
+}
+
static void brcmf_core_bus_reset(struct work_struct *work)
{
struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,
@@ -1184,7 +1213,7 @@ static ssize_t bus_reset_write(struct file *file, const char __user *user_buf,
if (value != 1)
return -EINVAL;
- schedule_work(&drvr->bus_reset);
+ brcmf_bus_schedule_reset(drvr->bus_if);
return count;
}
@@ -1408,7 +1437,7 @@ void brcmf_fw_crashed(struct device *dev)
brcmf_dev_coredump(dev);
- schedule_work(&drvr->bus_reset);
+ brcmf_bus_schedule_reset(bus_if);
}
void brcmf_detach(struct device *dev)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
index 8b149996f..3c6775166 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
@@ -1914,6 +1914,7 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ret = -ENOMEM;
goto fail;
}
+ mutex_init(&bus->bus_reset_lock);
bus->msgbuf = kzalloc(sizeof(*bus->msgbuf), GFP_KERNEL);
if (!bus->msgbuf) {
ret = -ENOMEM;
@@ -1985,6 +1986,11 @@ brcmf_pcie_remove(struct pci_dev *pdev)
if (devinfo->ci)
brcmf_pcie_intr_disable(devinfo);
+ if (devinfo->irq_allocated)
+ synchronize_irq(pdev->irq);
+
+ brcmf_bus_cancel_reset_work(bus);
+
brcmf_detach(&pdev->dev);
brcmf_free(&pdev->dev);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index 8effeb7a7..31e37b0d4 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -4541,6 +4541,12 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
return NULL;
}
+void brcmf_sdio_cancel_datawork(struct brcmf_sdio *bus)
+{
+ if (bus)
+ cancel_work_sync(&bus->datawork);
+}
+
/* Detach and free everything */
void brcmf_sdio_remove(struct brcmf_sdio *bus)
{
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
index 15d2c02fa..3c68ebf8e 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
@@ -373,6 +373,7 @@ int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev);
struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev);
void brcmf_sdio_remove(struct brcmf_sdio *bus);
void brcmf_sdio_isr(struct brcmf_sdio *bus, bool in_isr);
+void brcmf_sdio_cancel_datawork(struct brcmf_sdio *bus);
void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, bool active);
void brcmf_sdio_wowl_config(struct device *dev, bool enabled);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
index 9fb68c2dc..97d65ba36 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
@@ -1271,6 +1271,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
ret = -ENOMEM;
goto fail;
}
+ mutex_init(&bus->bus_reset_lock);
bus->dev = dev;
bus_pub->bus = bus;
@@ -1336,6 +1337,8 @@ brcmf_usb_disconnect_cb(struct brcmf_usbdev_info *devinfo)
return;
brcmf_dbg(USB, "Enter, bus_pub %p\n", devinfo);
+ brcmf_bus_cancel_reset_work(devinfo->bus_pub.bus);
+
brcmf_detach(devinfo->dev);
brcmf_free(devinfo->dev);
kfree(devinfo->bus_pub.bus);
--
2.34.1
^ permalink raw reply related
* [PATCH] wifi: mwifiex: validate HT/VHT capability and operation IE lengths
From: Doruk Tan Ozturk @ 2026-07-09 10:08 UTC (permalink / raw)
To: Brian Norris
Cc: Francesco Dolcini, Kees Cook, linux-wireless, linux-kernel,
stable, Doruk Tan Ozturk
mwifiex_update_bss_desc_with_ie() records raw pointers to the HT
Capabilities, HT Operation, VHT Capabilities, VHT Operation, 20/40 BSS
Coexistence and Operating Mode Notification elements taken straight out
of a beacon/probe-response buffer, without checking that each element is
long enough for the fixed-size structure that later consumers read. The
buffer is a tight kmemdup() of the on-air IEs (beacon_buf_size ==
ies->len), so a truncated element placed last leaves the stored pointer
one past the end of the allocation.
At association time these pointers are dereferenced at fixed offsets
regardless of the on-air length: mwifiex_cmd_append_11n_tlv() memcpy()s
sizeof(struct ieee80211_ht_cap) (26 bytes) from bcn_ht_cap and reads
bcn_ht_oper->ht_param, and mwifiex_cmd_append_11ac_tlv() memcpy()s
sizeof(struct ieee80211_vht_cap) (12 bytes) from bcn_vht_cap and reads
bcn_vht_oper->chan_width. A nearby AP (rogue / evil-twin; an open SSID
needs no credentials) advertising a BSS with a truncated HT/VHT cap
element therefore triggers a slab out-of-bounds read on the victim's
association attempt. This out-of-bounds read is the primary issue.
For the HT-Cap copy the over-read bytes are additionally placed into the
outgoing association request, so a limited amount of adjacent heap memory
can leak over the air. In station mode this is small (single-digit
bytes), because mwifiex_fill_cap_info() rewrites most of the copied
HT-Cap before transmission; the leak is a secondary effect.
mwifiex_set_sta_ht_cap() has the same missing-length pattern: in uAP mode
it reads two bytes of ieee80211_ht_cap.cap_info from a
cfg80211_find_ie(WLAN_EID_HT_CAPABILITY) result in a client association
request without checking the element length, a 1-2 byte out-of-bounds
read (used only to select an A-MSDU size, not leaked).
Reject (skip) any of these elements whose payload is shorter than the
structure the driver later reads, matching the length validation the
FH/DS/CF/IBSS parameter-set cases in the same beacon parser already
perform.
No dynamic reproducer: mwifiex is a fullmac driver for Marvell hardware
with no mac80211_hwsim equivalent, so this was confirmed by source and
structure-offset analysis only.
Found by 0sec automated security-research tooling (https://0sec.ai).
Fixes: 5e6e3a92b9a4 ("wireless: mwifiex: initial commit for Marvell mwifiex driver")
Cc: stable@vger.kernel.org
Assisted-by: 0sec:claude-opus-4-8
Signed-off-by: Doruk Tan Ozturk <doruk@0sec.ai>
---
drivers/net/wireless/marvell/mwifiex/scan.c | 12 ++++++++++++
drivers/net/wireless/marvell/mwifiex/util.c | 2 +-
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c
index 97c0ec3b822e..997e7e19525b 100644
--- a/drivers/net/wireless/marvell/mwifiex/scan.c
+++ b/drivers/net/wireless/marvell/mwifiex/scan.c
@@ -1384,6 +1384,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
bss_entry->beacon_buf);
break;
case WLAN_EID_HT_CAPABILITY:
+ if (element_len < sizeof(struct ieee80211_ht_cap))
+ break;
bss_entry->bcn_ht_cap = (struct ieee80211_ht_cap *)
(current_ptr +
sizeof(struct ieee_types_header));
@@ -1392,6 +1394,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
bss_entry->beacon_buf);
break;
case WLAN_EID_HT_OPERATION:
+ if (element_len < sizeof(struct ieee80211_ht_operation))
+ break;
bss_entry->bcn_ht_oper =
(struct ieee80211_ht_operation *)(current_ptr +
sizeof(struct ieee_types_header));
@@ -1400,6 +1404,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
bss_entry->beacon_buf);
break;
case WLAN_EID_VHT_CAPABILITY:
+ if (element_len < sizeof(struct ieee80211_vht_cap))
+ break;
bss_entry->disable_11ac = false;
bss_entry->bcn_vht_cap =
(void *)(current_ptr +
@@ -1409,6 +1415,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
bss_entry->beacon_buf);
break;
case WLAN_EID_VHT_OPERATION:
+ if (element_len < sizeof(struct ieee80211_vht_operation))
+ break;
bss_entry->bcn_vht_oper =
(void *)(current_ptr +
sizeof(struct ieee_types_header));
@@ -1417,6 +1425,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
bss_entry->beacon_buf);
break;
case WLAN_EID_BSS_COEX_2040:
+ if (!element_len)
+ break;
bss_entry->bcn_bss_co_2040 = current_ptr;
bss_entry->bss_co_2040_offset =
(u16) (current_ptr - bss_entry->beacon_buf);
@@ -1427,6 +1437,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
(u16) (current_ptr - bss_entry->beacon_buf);
break;
case WLAN_EID_OPMODE_NOTIF:
+ if (!element_len)
+ break;
bss_entry->oper_mode = (void *)current_ptr;
bss_entry->oper_mode_offset =
(u16)((u8 *)bss_entry->oper_mode -
diff --git a/drivers/net/wireless/marvell/mwifiex/util.c b/drivers/net/wireless/marvell/mwifiex/util.c
index 7d3631d21223..844223c04e2e 100644
--- a/drivers/net/wireless/marvell/mwifiex/util.c
+++ b/drivers/net/wireless/marvell/mwifiex/util.c
@@ -721,7 +721,7 @@ mwifiex_set_sta_ht_cap(struct mwifiex_private *priv, const u8 *ies,
ht_cap_ie = (void *)cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies,
ies_len);
- if (ht_cap_ie) {
+ if (ht_cap_ie && ht_cap_ie->len >= sizeof(struct ieee80211_ht_cap)) {
ht_cap = (void *)(ht_cap_ie + 1);
node->is_11n_enabled = 1;
node->max_amsdu = le16_to_cpu(ht_cap->cap_info) &
--
2.43.0
^ permalink raw reply related
* Re: [PATCH 2/3] wifi: mt76: mt792x: Add TX page pool support for IOMMU-enabled systems
From: Lorenzo Bianconi @ 2026-07-09 8:27 UTC (permalink / raw)
To: Eason Lai
Cc: nbd, linux-wireless, linux-mediatek, Yf.Luo, kun.wu, deren.wu,
sean.wang, quan.zhou, ryder.lee, leon.yen, litien.chang, jb.tsai
In-Reply-To: <20260709075558.1654164-3-eason.lai@mediatek.com>
[-- Attachment #1: Type: text/plain, Size: 15545 bytes --]
On Jul 09, Eason Lai wrote:
> From: Eason Lai <Eason.Lai@mediatek.com>
>
> Add support for TX page pool allocation in mt792x devices when IOMMU is
> enabled. This optimization reduces DMA mapping overhead by
> pre-allocating and reusing page pool buffers for TX operations.
Can you please provide some test results here? In particular regarding the
resulting throughput.
>
> Key changes:
> - Export DMA helper functions and ops for mt792x usage
> - Add tx_prealloc_enabled flag to track page pool state
> - Implement mt792x-specific DMA queue operations with TX page pool
> - Create page pools per TX queue when IOMMU is detected
> - Handle page pool buffer cleanup in both success and error
> paths
> - Add proper skip_unmap flag handling for page pool buffers
>
> The page pool path is used for linear skbs without fragments, falling
> back to standard DMA mapping for complex skb structures.
>
> Signed-off-by: Eason Lai <Eason.Lai@mediatek.com>
> ---
[...]
>
> -static void
> +void
> mt76_dma_kick_queue(struct mt76_dev *dev, struct mt76_queue *q)
> {
> wmb();
> @@ -409,6 +417,7 @@ mt76_dma_kick_queue(struct mt76_dev *dev, struct mt76_queue *q)
> else
> Q_WRITE(q, cpu_idx, q->head);
> }
> +EXPORT_SYMBOL_GPL(mt76_dma_kick_queue);
this is already available in mt76_queue_ops struct.
>
> static void
> mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush)
> @@ -1152,7 +1161,7 @@ mt76_dma_init(struct mt76_dev *dev,
> return 0;
> }
>
> -static const struct mt76_queue_ops mt76_dma_ops = {
> +const struct mt76_queue_ops mt76_dma_ops = {
> .init = mt76_dma_init,
> .alloc = mt76_dma_alloc_queue,
> .reset_q = mt76_dma_queue_reset,
> @@ -1164,6 +1173,7 @@ static const struct mt76_queue_ops mt76_dma_ops = {
> .rx_reset = mt76_dma_rx_reset,
> .kick = mt76_dma_kick_queue,
> };
> +EXPORT_SYMBOL_GPL(mt76_dma_ops);
>
> void mt76_dma_attach(struct mt76_dev *dev)
> {
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
> index 927c21536f4e..25e24fa36eca 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt76.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt76.h
> @@ -957,6 +957,8 @@ struct mt76_dev {
> int tx_dma_idx[4];
> enum mt76_hwrro_mode hwrro_mode;
>
> + bool tx_prealloc_enabled;
> +
> struct mt76_worker tx_worker;
> struct napi_struct tx_napi;
>
> @@ -1785,7 +1787,16 @@ mt76_tx_status_get_hw(struct mt76_dev *dev, struct sk_buff *skb)
>
> void mt76_put_txwi(struct mt76_dev *dev, struct mt76_txwi_cache *t);
> void mt76_put_rxwi(struct mt76_dev *dev, struct mt76_txwi_cache *t);
> +struct mt76_txwi_cache *mt76_get_txwi(struct mt76_dev *dev);
> struct mt76_txwi_cache *mt76_get_rxwi(struct mt76_dev *dev);
> +int mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
> + struct mt76_queue_buf *buf, int nbufs, u32 info,
> + struct sk_buff *skb, void *txwi);
> +void mt76_dma_tx_cleanup_idx(struct mt76_dev *dev, struct mt76_queue *q, int idx,
> + struct mt76_queue_entry *prev_e);
> +void mt76_dma_kick_queue(struct mt76_dev *dev, struct mt76_queue *q);
> +void mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q);
> +extern const struct mt76_queue_ops mt76_dma_ops;
> void mt76_free_pending_rxwi(struct mt76_dev *dev);
> void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
> struct napi_struct *napi);
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
> index 0339e2e7ab60..d4b36b0832b8 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
> @@ -250,6 +250,12 @@ void mt76_connac_txp_skb_unmap(struct mt76_dev *dev,
> {
> struct mt76_connac_txp_common *txp;
>
> + if (t->page_pool_buf) {
> + mt76_put_page_pool_buf(t->page_pool_buf, false);
> + t->page_pool_buf = NULL;
> + return;
> + }
> +
> txp = mt76_connac_txwi_to_txp(dev, t);
> if (is_mt76_fw_txp(dev))
> mt76_connac_txp_skb_unmap_fw(dev, &txp->fw);
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
> index c4161754c01d..3d69d8c67dea 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
> @@ -214,7 +214,7 @@ static int mt7925_dma_init(struct mt792x_dev *dev)
> {
> int ret;
>
> - mt76_dma_attach(&dev->mt76);
> + mt792x_dma_attach(&dev->mt76);
>
> ret = mt792x_dma_disable(dev, true);
> if (ret)
> @@ -263,6 +263,8 @@ static int mt7925_dma_init(struct mt792x_dev *dev)
> mt792x_poll_tx);
> napi_enable(&dev->mt76.tx_napi);
>
> + mt792x_dma_tx_page_pool_init(dev);
> +
> return mt792x_dma_enable(dev);
> }
>
> diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h
> index 4ff93f2cd624..7ac0318dc249 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt792x.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h
> @@ -418,8 +418,10 @@ void mt792x_sta_statistics(struct ieee80211_hw *hw,
> struct station_info *sinfo);
> void mt792x_set_coverage_class(struct ieee80211_hw *hw, int radio_idx,
> s16 coverage_class);
> +void mt792x_dma_attach(struct mt76_dev *dev);
> void mt792x_dma_cleanup(struct mt792x_dev *dev);
> int mt792x_dma_enable(struct mt792x_dev *dev);
> +int mt792x_dma_tx_page_pool_init(struct mt792x_dev *dev);
> int mt792x_wpdma_reset(struct mt792x_dev *dev, bool force);
> int mt792x_wpdma_reinit_cond(struct mt792x_dev *dev);
> int mt792x_dma_disable(struct mt792x_dev *dev, bool force);
> diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_dma.c b/drivers/net/wireless/mediatek/mt76/mt792x_dma.c
> index 002aece857b2..b341f1cb3ce0 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt792x_dma.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt792x_dma.c
> @@ -3,6 +3,9 @@
>
> #include <linux/module.h>
> #include <linux/firmware.h>
> +#include <linux/iommu.h>
> +#include <net/page_pool/helpers.h>
> +#include <linux/of.h>
>
> #include "mt792x.h"
> #include "dma.h"
> @@ -266,6 +269,323 @@ int mt792x_wpdma_reinit_cond(struct mt792x_dev *dev)
> }
> EXPORT_SYMBOL_GPL(mt792x_wpdma_reinit_cond);
>
> +static int mt792x_create_tx_page_pool(struct mt76_dev *dev, struct mt76_queue *q)
> +{
> + struct page_pool_params pp_params = {
> + .order = 0,
> + .flags = 0,
> + .nid = NUMA_NO_NODE,
> + .dev = dev->dma_dev,
> + };
> +
> + if (!q || !dev->tx_prealloc_enabled)
> + return 0;
> +
> + if (!mt76_is_mmio(dev))
> + return 0;
do you really need this check? you already check it in
mt792x_dma_tx_page_pool_init().
> +
> + pp_params.pool_size = 256;
> + pp_params.flags |= PP_FLAG_DMA_MAP;
> + pp_params.dma_dir = DMA_BIDIRECTIONAL;
> + pp_params.max_len = PAGE_SIZE;
> + pp_params.offset = 0;
> +
> + q->page_pool = page_pool_create(&pp_params);
> + if (IS_ERR(q->page_pool)) {
> + int err = PTR_ERR(q->page_pool);
> +
> + q->page_pool = NULL;
> + dev_warn(dev->dev, "Failed to create TX page pool for queue %d (err=%d)\n",
> + q->hw_idx, err);
> + return 0;
> + }
> +
> + return 0;
> +}
> +
> +int mt792x_dma_tx_page_pool_init(struct mt792x_dev *dev)
> +{
> + struct mt76_dev *mdev = &dev->mt76;
> + int i, ret, pool_count = 0;
> +
> + if (!iommu_get_domain_for_dev(mdev->dma_dev))
> + return 0;
> +
> + if (!mt76_is_mmio(mdev))
> + return 0;
> +
> + mdev->tx_prealloc_enabled = true;
> +
> + for (i = 0; i < ARRAY_SIZE(mdev->phy.q_tx); i++) {
> + struct mt76_queue *q = mdev->phy.q_tx[i];
> +
> + if (!q)
> + continue;
> +
> + ret = mt792x_create_tx_page_pool(mdev, q);
> + if (ret)
> + return ret;
> +
> + if (q->page_pool)
> + pool_count++;
> + }
> +
> + if (pool_count > 0)
> + dev_info(mdev->dev,
> + "IOMMU enabled, created %d TX page pools\n", pool_count);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(mt792x_dma_tx_page_pool_init);
> +
> +static void mt792x_dma_tx_page_pool_cleanup(struct mt792x_dev *dev)
> +{
> + struct mt76_dev *mdev = &dev->mt76;
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(mdev->phy.q_tx); i++) {
> + struct mt76_queue *q = mdev->phy.q_tx[i];
> +
> + if (!q || !q->page_pool)
> + continue;
> +
> + page_pool_destroy(q->page_pool);
> + q->page_pool = NULL;
> + }
> +
> + mdev->tx_prealloc_enabled = false;
> +}
> +
> +static void *
> +mt792x_dma_tx_alloc_page_pool_buf(struct mt76_dev *dev, struct mt76_queue *q,
> + struct sk_buff *skb, dma_addr_t *dma_addr,
> + int *buf_len)
> +{
> + struct page *page;
> + void *buf;
> + int len;
> + u32 offset;
> +
> + if (!q->page_pool || !dev->tx_prealloc_enabled)
> + return NULL;
> +
> + len = skb_headlen(skb);
> + if (len > PAGE_SIZE)
> + return NULL;
> +
> + buf = mt76_get_page_pool_buf(q, &offset, len);
> + if (!buf)
> + return NULL;
> +
> + page = virt_to_head_page(buf);
> + *dma_addr = page_pool_get_dma_addr(page) + offset;
> + if (unlikely(!*dma_addr)) {
> + dev_warn_ratelimited(dev->dev, "Page pool returned NULL DMA address\n");
> + mt76_put_page_pool_buf(buf, false);
> + return NULL;
> + }
> +
> + *buf_len = len;
> +
> + dma_sync_single_for_cpu(dev->dma_dev, *dma_addr, len, DMA_TO_DEVICE);
> + skb_copy_from_linear_data(skb, buf, len);
I would like to see some results here since usually it is not a good idea to
copy all the packets (even if it is just the linear part).
> + dma_sync_single_for_device(dev->dma_dev, *dma_addr, len, DMA_TO_DEVICE);
> +
> + return buf;
> +}
> +
> +static int
> +mt792x_dma_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q,
> + enum mt76_txq_id qid, struct sk_buff *skb,
> + struct mt76_wcid *wcid, struct ieee80211_sta *sta)
> +{
> + struct ieee80211_tx_status status = {
> + .sta = sta,
> + };
> + struct mt76_tx_info tx_info = {
> + .skb = skb,
> + };
> + struct mt76_dev *dev = phy->dev;
> + struct ieee80211_hw *hw;
> + int len, n = 0, ret = -ENOMEM;
> + struct mt76_txwi_cache *t;
> + struct sk_buff *iter;
> + dma_addr_t addr;
> + u8 *txwi;
> +
> + if (test_bit(MT76_RESET, &phy->state))
> + goto free_skb;
> +
> + t = mt76_get_txwi(dev);
> + if (!t)
> + goto free_skb;
> +
> + txwi = mt76_get_txwi_ptr(dev, t);
> +
> + skb->prev = NULL;
> + skb->next = NULL;
> + if (dev->drv->drv_flags & MT_DRV_TX_ALIGNED4_SKBS)
> + mt76_insert_hdr_pad(skb);
> +
> + len = skb_headlen(skb);
> +
> + if (dev->tx_prealloc_enabled && q->page_pool &&
> + !skb_has_frag_list(skb) && !skb_shinfo(skb)->nr_frags) {
> + void *buf;
> + int pp_len;
> +
> + buf = mt792x_dma_tx_alloc_page_pool_buf(dev, q, skb, &addr, &pp_len);
> + if (buf) {
> + t->page_pool_buf = buf;
> + len = pp_len;
> +
> + tx_info.buf[n].addr = t->dma_addr;
> + tx_info.buf[n++].len = dev->drv->txwi_size;
> + tx_info.buf[n].addr = addr;
> + tx_info.buf[n].len = len;
> + tx_info.buf[n].skip_unmap = true;
> + n++;
> +
> + goto skip_dma_map;
> + }
> + }
> +
> + addr = dma_map_single(dev->dma_dev, skb->data, len, DMA_TO_DEVICE);
> + if (unlikely(dma_mapping_error(dev->dma_dev, addr)))
> + goto free;
> +
> + t->page_pool_buf = NULL;
> +
> + tx_info.buf[n].addr = t->dma_addr;
> + tx_info.buf[n++].len = dev->drv->txwi_size;
> + tx_info.buf[n].addr = addr;
> + tx_info.buf[n++].len = len;
> +
> +skip_dma_map:
> + skb_walk_frags(skb, iter) {
> + if (n == ARRAY_SIZE(tx_info.buf))
> + goto unmap;
> +
> + addr = dma_map_single(dev->dma_dev, iter->data, iter->len,
> + DMA_TO_DEVICE);
> + if (unlikely(dma_mapping_error(dev->dma_dev, addr)))
> + goto unmap;
> +
> + tx_info.buf[n].addr = addr;
> + tx_info.buf[n].skip_unmap = false;
> + tx_info.buf[n++].len = iter->len;
> + }
> + tx_info.nbuf = n;
> +
> + if (q->queued + (tx_info.nbuf + 1) / 2 >= q->ndesc - 1) {
> + ret = -ENOMEM;
> + goto unmap;
> + }
> +
> + dma_sync_single_for_cpu(dev->dma_dev, t->dma_addr, dev->drv->txwi_size,
> + DMA_TO_DEVICE);
> + ret = dev->drv->tx_prepare_skb(dev, txwi, qid, wcid, sta, &tx_info);
> + dma_sync_single_for_device(dev->dma_dev, t->dma_addr, dev->drv->txwi_size,
> + DMA_TO_DEVICE);
> + if (ret < 0)
> + goto unmap;
> +
> + return mt76_dma_add_buf(dev, q, tx_info.buf, tx_info.nbuf,
> + tx_info.info, tx_info.skb, t);
> +
> +unmap:
> + for (n--; n > 0; n--) {
> + if (!tx_info.buf[n].skip_unmap)
> + dma_unmap_single(dev->dma_dev, tx_info.buf[n].addr,
> + tx_info.buf[n].len, DMA_TO_DEVICE);
> + }
> +
> + if (t->page_pool_buf) {
> + mt76_put_page_pool_buf(t->page_pool_buf, false);
> + t->page_pool_buf = NULL;
> + }
> +
> +free:
> +#ifdef CONFIG_NL80211_TESTMODE
> + if (mt76_is_testmode_skb(dev, skb, &hw)) {
> + struct mt76_phy *phy = hw->priv;
> +
> + if (tx_info.skb == phy->test.tx_skb)
> + phy->test.tx_done--;
> + }
> +#endif
> +
> + mt76_put_txwi(dev, t);
> +
> +free_skb:
> + status.skb = tx_info.skb;
> + hw = mt76_tx_status_get_hw(dev, tx_info.skb);
> + spin_lock_bh(&dev->rx_lock);
> + ieee80211_tx_status_ext(hw, &status);
> + spin_unlock_bh(&dev->rx_lock);
> +
> + return ret;
> +}
> +
> +static void
> +mt792x_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush)
this is almost a copy of mt76_dma_tx_cleanup(). Can we do something better
here?
> +{
> + struct mt76_queue_entry entry;
> + int last;
> +
> + if (!q || !q->ndesc)
> + return;
> +
> + spin_lock_bh(&q->cleanup_lock);
> + if (flush)
> + last = -1;
> + else
> + last = Q_READ(q, dma_idx);
> +
> + while (q->queued > 0 && q->tail != last) {
> + mt76_dma_tx_cleanup_idx(dev, q, q->tail, &entry);
> + mt76_npu_txdesc_cleanup(q, q->tail);
> + mt76_queue_tx_complete(dev, q, &entry);
> +
> + if (entry.txwi) {
> + if (entry.skb && entry.txwi->page_pool_buf) {
> + mt76_put_page_pool_buf(entry.txwi->page_pool_buf, false);
> + entry.txwi->page_pool_buf = NULL;
> + }
> +
> + if (!(dev->drv->drv_flags & MT_DRV_TXWI_NO_FREE))
> + mt76_put_txwi(dev, entry.txwi);
> + }
> +
> + if (!flush && q->tail == last)
> + last = Q_READ(q, dma_idx);
> + }
> + spin_unlock_bh(&q->cleanup_lock);
> +
> + if (flush) {
> + spin_lock_bh(&q->lock);
> + mt76_dma_sync_idx(dev, q);
> + mt76_dma_kick_queue(dev, q);
> + spin_unlock_bh(&q->lock);
> + }
> +
> + if (!q->queued)
> + wake_up(&dev->tx_wait);
> +}
> +
> +static struct mt76_queue_ops mt792x_queue_ops;
> +
> +void mt792x_dma_attach(struct mt76_dev *dev)
> +{
> + mt792x_queue_ops = mt76_dma_ops;
can you please take a look to mt7615_mmio_probe()?
Regards,
Lorenzo
> +
> + mt792x_queue_ops.tx_queue_skb = mt792x_dma_tx_queue_skb;
> + mt792x_queue_ops.tx_cleanup = mt792x_dma_tx_cleanup;
> +
> + dev->queue_ops = &mt792x_queue_ops;
> +}
> +EXPORT_SYMBOL_GPL(mt792x_dma_attach);
> +
> int mt792x_dma_disable(struct mt792x_dev *dev, bool force)
> {
> /* disable WFDMA0 */
> @@ -326,6 +646,8 @@ void mt792x_dma_cleanup(struct mt792x_dev *dev)
> MT_WFDMA0_RST_LOGIC_RST);
>
> mt76_dma_cleanup(&dev->mt76);
> +
> + mt792x_dma_tx_page_pool_cleanup(dev);
> }
> EXPORT_SYMBOL_GPL(mt792x_dma_cleanup);
>
> --
> 2.45.2
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox