* [PATCH 2/6] wifi: mt76: do not add non-sta wcid entries to the poll list
2025-08-27 8:53 [PATCH 1/6] wifi: mt76: mt7996: fix crash on some tx status reports Felix Fietkau
@ 2025-08-27 8:53 ` Felix Fietkau
2025-08-27 8:53 ` [PATCH 3/6] wifi: mt76: mt7996: add missing check for rx wcid entries Felix Fietkau
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Felix Fietkau @ 2025-08-27 8:53 UTC (permalink / raw)
To: linux-wireless
Polling and airtime reporting is valid for station entries only
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
drivers/net/wireless/mediatek/mt76/mac80211.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index 3afe4c4cd7bb..6b2641a9ae9a 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -1690,7 +1690,7 @@ EXPORT_SYMBOL_GPL(mt76_wcid_cleanup);
void mt76_wcid_add_poll(struct mt76_dev *dev, struct mt76_wcid *wcid)
{
- if (test_bit(MT76_MCU_RESET, &dev->phy.state))
+ if (test_bit(MT76_MCU_RESET, &dev->phy.state) || !wcid->sta)
return;
spin_lock_bh(&dev->sta_poll_lock);
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 3/6] wifi: mt76: mt7996: add missing check for rx wcid entries
2025-08-27 8:53 [PATCH 1/6] wifi: mt76: mt7996: fix crash on some tx status reports Felix Fietkau
2025-08-27 8:53 ` [PATCH 2/6] wifi: mt76: do not add non-sta wcid entries to the poll list Felix Fietkau
@ 2025-08-27 8:53 ` Felix Fietkau
2025-08-27 8:53 ` [PATCH 4/6] wifi: mt76: mt7915: fix list corruption after hardware restart Felix Fietkau
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Felix Fietkau @ 2025-08-27 8:53 UTC (permalink / raw)
To: linux-wireless
Non-station wcid entries must not be passed to the rx functions.
In case of the global wcid entry, it could even lead to corruption in the wcid
array due to pointer being casted to struct mt7996_sta_link using container_of.
Fixes: 7464b12b7d92 ("wifi: mt76: mt7996: rework mt7996_rx_get_wcid to support MLO")
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index 837deb41ae13..b3fcca9bbb95 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -62,7 +62,7 @@ static struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev,
int i;
wcid = mt76_wcid_ptr(dev, idx);
- if (!wcid)
+ if (!wcid || !wcid->sta)
return NULL;
if (!mt7996_band_valid(dev, band_idx))
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 4/6] wifi: mt76: mt7915: fix list corruption after hardware restart
2025-08-27 8:53 [PATCH 1/6] wifi: mt76: mt7996: fix crash on some tx status reports Felix Fietkau
2025-08-27 8:53 ` [PATCH 2/6] wifi: mt76: do not add non-sta wcid entries to the poll list Felix Fietkau
2025-08-27 8:53 ` [PATCH 3/6] wifi: mt76: mt7996: add missing check for rx wcid entries Felix Fietkau
@ 2025-08-27 8:53 ` Felix Fietkau
2025-08-27 8:53 ` [PATCH 5/6] wifi: mt76: free pending offchannel tx frames on wcid cleanup Felix Fietkau
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Felix Fietkau @ 2025-08-27 8:53 UTC (permalink / raw)
To: linux-wireless
Since stations are recreated from scratch, all lists that wcids are added
to must be cleared before calling ieee80211_restart_hw.
Set wcid->sta = 0 for each wcid entry in order to ensure that they are
not added again before they are ready.
Fixes: 8a55712d124f ("wifi: mt76: mt7915: enable full system reset support")
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
drivers/net/wireless/mediatek/mt76/mac80211.c | 37 +++++++++++++++++++
drivers/net/wireless/mediatek/mt76/mt76.h | 1 +
.../net/wireless/mediatek/mt76/mt7915/mac.c | 12 +++---
3 files changed, 43 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index 6b2641a9ae9a..0e0d7b3bfe42 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -818,6 +818,43 @@ void mt76_free_device(struct mt76_dev *dev)
}
EXPORT_SYMBOL_GPL(mt76_free_device);
+static void mt76_reset_phy(struct mt76_phy *phy)
+{
+ if (!phy)
+ return;
+
+ INIT_LIST_HEAD(&phy->tx_list);
+}
+
+void mt76_reset_device(struct mt76_dev *dev)
+{
+ int i;
+
+ rcu_read_lock();
+ for (i = 0; i < ARRAY_SIZE(dev->wcid); i++) {
+ struct mt76_wcid *wcid;
+
+ wcid = rcu_dereference(dev->wcid[i]);
+ if (!wcid)
+ continue;
+
+ wcid->sta = 0;
+ mt76_wcid_cleanup(dev, wcid);
+ rcu_assign_pointer(dev->wcid[i], NULL);
+ }
+ rcu_read_unlock();
+
+ INIT_LIST_HEAD(&dev->wcid_list);
+ INIT_LIST_HEAD(&dev->sta_poll_list);
+ dev->vif_mask = 0;
+ memset(dev->wcid_mask, 0, sizeof(dev->wcid_mask));
+
+ mt76_reset_phy(&dev->phy);
+ for (i = 0; i < ARRAY_SIZE(dev->phys); i++)
+ mt76_reset_phy(dev->phys[i]);
+}
+EXPORT_SYMBOL_GPL(mt76_reset_device);
+
struct mt76_phy *mt76_vif_phy(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index febe1dcb8d19..5c71226c8607 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -1247,6 +1247,7 @@ int mt76_register_device(struct mt76_dev *dev, bool vht,
struct ieee80211_rate *rates, int n_rates);
void mt76_unregister_device(struct mt76_dev *dev);
void mt76_free_device(struct mt76_dev *dev);
+void mt76_reset_device(struct mt76_dev *dev);
void mt76_unregister_phy(struct mt76_phy *phy);
struct mt76_phy *mt76_alloc_radio_phy(struct mt76_dev *dev, unsigned int size,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
index 09c92e4ae129..5da7bb90e209 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
@@ -1460,17 +1460,15 @@ mt7915_mac_full_reset(struct mt7915_dev *dev)
if (i == 10)
dev_err(dev->mt76.dev, "chip full reset failed\n");
- spin_lock_bh(&dev->mt76.sta_poll_lock);
- while (!list_empty(&dev->mt76.sta_poll_list))
- list_del_init(dev->mt76.sta_poll_list.next);
- spin_unlock_bh(&dev->mt76.sta_poll_lock);
-
- memset(dev->mt76.wcid_mask, 0, sizeof(dev->mt76.wcid_mask));
- dev->mt76.vif_mask = 0;
dev->phy.omac_mask = 0;
if (phy2)
phy2->omac_mask = 0;
+ mt76_reset_device(&dev->mt76);
+
+ INIT_LIST_HEAD(&dev->sta_rc_list);
+ INIT_LIST_HEAD(&dev->twt_list);
+
i = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA);
dev->mt76.global_wcid.idx = i;
dev->recovery.hw_full_reset = false;
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 5/6] wifi: mt76: free pending offchannel tx frames on wcid cleanup
2025-08-27 8:53 [PATCH 1/6] wifi: mt76: mt7996: fix crash on some tx status reports Felix Fietkau
` (2 preceding siblings ...)
2025-08-27 8:53 ` [PATCH 4/6] wifi: mt76: mt7915: fix list corruption after hardware restart Felix Fietkau
@ 2025-08-27 8:53 ` Felix Fietkau
2025-08-27 8:53 ` [PATCH 6/6] wifi: mt76: fix linked list corruption Felix Fietkau
2025-08-27 12:58 ` [PATCH 1/6] wifi: mt76: mt7996: fix crash on some tx status reports Lorenzo Bianconi
5 siblings, 0 replies; 7+ messages in thread
From: Felix Fietkau @ 2025-08-27 8:53 UTC (permalink / raw)
To: linux-wireless
Avoid leaking them or keeping the wcid on the tx list
Fixes: 0b3be9d1d34e ("wifi: mt76: add separate tx scheduling queue for off-channel tx")
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
drivers/net/wireless/mediatek/mt76/mac80211.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index 0e0d7b3bfe42..59adf3312617 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -1716,6 +1716,10 @@ void mt76_wcid_cleanup(struct mt76_dev *dev, struct mt76_wcid *wcid)
skb_queue_splice_tail_init(&wcid->tx_pending, &list);
spin_unlock(&wcid->tx_pending.lock);
+ spin_lock(&wcid->tx_offchannel.lock);
+ skb_queue_splice_tail_init(&wcid->tx_offchannel, &list);
+ spin_unlock(&wcid->tx_offchannel.lock);
+
spin_unlock_bh(&phy->tx_lock);
while ((skb = __skb_dequeue(&list)) != NULL) {
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 6/6] wifi: mt76: fix linked list corruption
2025-08-27 8:53 [PATCH 1/6] wifi: mt76: mt7996: fix crash on some tx status reports Felix Fietkau
` (3 preceding siblings ...)
2025-08-27 8:53 ` [PATCH 5/6] wifi: mt76: free pending offchannel tx frames on wcid cleanup Felix Fietkau
@ 2025-08-27 8:53 ` Felix Fietkau
2025-08-27 12:58 ` [PATCH 1/6] wifi: mt76: mt7996: fix crash on some tx status reports Lorenzo Bianconi
5 siblings, 0 replies; 7+ messages in thread
From: Felix Fietkau @ 2025-08-27 8:53 UTC (permalink / raw)
To: linux-wireless
Never leave scheduled wcid entries on the temporary on-stack list
Fixes: 0b3be9d1d34e ("wifi: mt76: add separate tx scheduling queue for off-channel tx")
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
drivers/net/wireless/mediatek/mt76/tx.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c
index 03b042fdf997..8ab5840fee57 100644
--- a/drivers/net/wireless/mediatek/mt76/tx.c
+++ b/drivers/net/wireless/mediatek/mt76/tx.c
@@ -646,6 +646,7 @@ mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid,
static void mt76_txq_schedule_pending(struct mt76_phy *phy)
{
LIST_HEAD(tx_list);
+ int ret = 0;
if (list_empty(&phy->tx_list))
return;
@@ -657,13 +658,13 @@ static void mt76_txq_schedule_pending(struct mt76_phy *phy)
list_splice_init(&phy->tx_list, &tx_list);
while (!list_empty(&tx_list)) {
struct mt76_wcid *wcid;
- int ret;
wcid = list_first_entry(&tx_list, struct mt76_wcid, tx_list);
list_del_init(&wcid->tx_list);
spin_unlock(&phy->tx_lock);
- ret = mt76_txq_schedule_pending_wcid(phy, wcid, &wcid->tx_offchannel);
+ if (ret >= 0)
+ ret = mt76_txq_schedule_pending_wcid(phy, wcid, &wcid->tx_offchannel);
if (ret >= 0 && !phy->offchannel)
ret = mt76_txq_schedule_pending_wcid(phy, wcid, &wcid->tx_pending);
spin_lock(&phy->tx_lock);
@@ -672,9 +673,6 @@ static void mt76_txq_schedule_pending(struct mt76_phy *phy)
!skb_queue_empty(&wcid->tx_offchannel) &&
list_empty(&wcid->tx_list))
list_add_tail(&wcid->tx_list, &phy->tx_list);
-
- if (ret < 0)
- break;
}
spin_unlock(&phy->tx_lock);
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH 1/6] wifi: mt76: mt7996: fix crash on some tx status reports
2025-08-27 8:53 [PATCH 1/6] wifi: mt76: mt7996: fix crash on some tx status reports Felix Fietkau
` (4 preceding siblings ...)
2025-08-27 8:53 ` [PATCH 6/6] wifi: mt76: fix linked list corruption Felix Fietkau
@ 2025-08-27 12:58 ` Lorenzo Bianconi
5 siblings, 0 replies; 7+ messages in thread
From: Lorenzo Bianconi @ 2025-08-27 12:58 UTC (permalink / raw)
To: Felix Fietkau; +Cc: linux-wireless
[-- Attachment #1: Type: text/plain, Size: 1254 bytes --]
> When a wcid can't be found, link_sta can be stale from a previous batch.
> The code currently assumes that if link_sta is set, wcid is also non-zero.
> Fix wcid NULL pointer dereference by resetting link_sta when a wcid entry
> can't be found.
>
> Fixes: 62da647a2b20 ("wifi: mt76: mt7996: Add MLO support to mt7996_tx_check_aggr()")
Acked-by: Lorenzo Bianconi <lorenzo@kernel.org>
> Signed-off-by: Felix Fietkau <nbd@nbd.name>
> ---
> drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
> index d6531b74be1f..837deb41ae13 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
> @@ -1247,8 +1247,10 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
> idx = FIELD_GET(MT_TXFREE_INFO_WLAN_ID, info);
> wcid = mt76_wcid_ptr(dev, idx);
> sta = wcid_to_sta(wcid);
> - if (!sta)
> + if (!sta) {
> + link_sta = NULL;
> goto next;
> + }
>
> link_sta = rcu_dereference(sta->link[wcid->link_id]);
> if (!link_sta)
> --
> 2.51.0
>
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread