[PATCH AUTOSEL 6.16] wifi: mt76: do not add non-sta wcid entries to the poll list

Sasha Levin posted 1 patch 3 weeks, 2 days ago
drivers/net/wireless/mediatek/mt76/mac80211.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
[PATCH AUTOSEL 6.16] wifi: mt76: do not add non-sta wcid entries to the poll list
Posted by Sasha Levin 3 weeks, 2 days ago
From: Felix Fietkau <nbd@nbd.name>

[ Upstream commit a3c99ef88a084e1c2b99dd56bbfa7f89c9be3e92 ]

Polling and airtime reporting is valid for station entries only

Link: https://patch.msgid.link/20250827085352.51636-2-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

**Backport Status: YES**

## Extensive Analysis

This commit adds a critical safety check to prevent non-station wcid
entries from being incorrectly added to the polling list in the mt76
wireless driver.

### Bug Being Fixed

The commit fixes a bug where non-station wcid (wireless client ID)
entries could be added to the `sta_poll_list`. Looking at the code
change in `mt76_wcid_add_poll()`:

```c
- if (test_bit(MT76_MCU_RESET, &dev->phy.state))
+       if (test_bit(MT76_MCU_RESET, &dev->phy.state) || !wcid->sta)
                return;
```

The addition of `|| !wcid->sta` prevents wcid entries that don't
represent actual wireless stations from being added to the polling list.

### Why This is a Critical Fix

1. **Prevents Kernel Crashes**: The polling mechanism (seen in files
   like mt7915/mac.c:100-150) assumes that wcids in the poll list have
   valid `ieee80211_sta` structures. When processing the poll list, the
   code does:
  ```c
  sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
  ieee80211_sta_register_airtime(sta, tid, tx_cur, rx_cur);
  ```
  For non-sta wcids (like global_wcid, group_wcid, or interface wcids),
  this would dereference invalid memory and cause a kernel panic.

2. **Affects All mt76-based Hardware**: This bug affects multiple
   MediaTek WiFi chipsets including mt7603, mt7615, mt7915, mt7921,
   mt7925, and mt7996, as evidenced by the calls to
   `mt76_wcid_add_poll()` across all these driver variants.

3. **Simple and Contained Fix**: The fix is a single-line addition of a
   boolean check that has minimal risk of introducing regressions. It
   only adds a safety check without changing any existing logic flow.

### Evidence from Code Analysis

The wcid structure (mt76.h:348-378) contains a `sta` field (line 365)
that's a 1-bit flag distinguishing between:
- Station wcids (`sta=1`): Real wireless clients
- Non-sta wcids (`sta=0`): Internal entries like global_wcid,
  group_wcid, interface wcids

The polling mechanism is specifically designed for collecting airtime
statistics from real stations for:
- Airtime fairness scheduling
- Rate control adaptation
- TX/RX time accounting

Non-sta wcids don't have associated `ieee80211_sta` structures and don't
participate in these mechanisms, so polling them is both meaningless and
dangerous.

### Stable Tree Criteria Assessment

✓ **Fixes a real bug**: Prevents potential kernel crashes from invalid
memory access
✓ **Small and contained**: Single-line boolean check addition
✓ **Clear bug fix**: Not a new feature or architectural change
✓ **Low regression risk**: Only adds a safety check, doesn't modify
existing behavior for valid cases
✓ **Affects users**: Can cause kernel panics in production WiFi systems
✓ **Driver-specific**: Confined to mt76 wireless subsystem

This is an ideal candidate for stable backporting as it fixes a clear
bug that can cause system crashes, the fix is minimal and safe, and it
affects widely-used MediaTek WiFi hardware.

 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 45c8db939d554..13dc868076f08 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