* [PATCH 1/2] wifi: mt76: mt7996: fix out-of-bounds array access during hardware restart
@ 2026-03-24 15:49 Felix Fietkau
2026-03-24 15:49 ` [PATCH 2/2] wifi: mt76: mt7996: add missing max_remain_on_channel_duration Felix Fietkau
0 siblings, 1 reply; 2+ messages in thread
From: Felix Fietkau @ 2026-03-24 15:49 UTC (permalink / raw)
To: linux-wireless; +Cc: Chad Monroe
During hardware restart, link_id can be IEEE80211_LINK_UNSPECIFIED,
causing an out-of-bounds array access on msta->link[].
Add mt7996_sta_link() and mt7996_sta_link_protected() helper functions
for accessing sta links with proper RCU handling and bounds checking.
Use them for any sta link RCU access.
Reported-by: Chad Monroe <chad@monroe.io>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
.../wireless/mediatek/mt76/mt7996/debugfs.c | 4 ++--
.../net/wireless/mediatek/mt76/mt7996/mac.c | 6 ++---
.../net/wireless/mediatek/mt76/mt7996/main.c | 17 +++++++-------
.../net/wireless/mediatek/mt76/mt7996/mcu.c | 22 +++++++++----------
.../wireless/mediatek/mt76/mt7996/mt7996.h | 19 ++++++++++++++++
5 files changed, 43 insertions(+), 25 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c
index 34af800964d1..ef9a9204adf5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c
@@ -664,7 +664,7 @@ mt7996_sta_hw_queue_read(void *data, struct ieee80211_sta *sta)
if (!mlink)
continue;
- msta_link = rcu_dereference(msta->link[link_id]);
+ msta_link = mt7996_sta_link(msta, link_id);
if (!msta_link)
continue;
@@ -1042,7 +1042,7 @@ static ssize_t mt7996_link_sta_fixed_rate_set(struct file *file,
mutex_lock(&dev->mt76.mutex);
- msta_link = mt76_dereference(msta->link[link_sta->link_id], &dev->mt76);
+ msta_link = mt7996_sta_link_protected(dev, msta, link_sta->link_id);
if (!msta_link) {
ret = -EINVAL;
goto out;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index e2a83da3a09c..c98446057282 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -48,7 +48,7 @@ static struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev,
if (mlink->band_idx != band_idx)
continue;
- msta_link = rcu_dereference(msta->link[i]);
+ msta_link = mt7996_sta_link(msta, i);
break;
}
@@ -1038,7 +1038,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
if (link_id != wcid->link_id && link_id != IEEE80211_LINK_UNSPECIFIED) {
if (msta) {
struct mt7996_sta_link *msta_link =
- rcu_dereference(msta->link[link_id]);
+ mt7996_sta_link(msta, link_id);
if (msta_link)
wcid = &msta_link->wcid;
@@ -1346,7 +1346,7 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
IEEE80211_MLD_MAX_NUM_LINKS) {
struct mt7996_sta_link *msta_link;
- msta_link = rcu_dereference(msta->link[id]);
+ msta_link = mt7996_sta_link(msta, id);
if (!msta_link)
continue;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index a8a6552d49f6..796a8af565cb 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -207,8 +207,7 @@ mt7996_set_hw_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct mt7996_sta *msta;
msta = (struct mt7996_sta *)sta->drv_priv;
- msta_link = mt76_dereference(msta->link[link_id],
- &dev->mt76);
+ msta_link = mt7996_sta_link_protected(dev, msta, link_id);
if (!msta_link)
return 0;
@@ -1381,7 +1380,7 @@ mt7996_mac_sta_event(struct mt7996_dev *dev, struct ieee80211_vif *vif,
if (!link)
continue;
- msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
+ msta_link = mt7996_sta_link_protected(dev, msta, link_id);
if (!msta_link)
continue;
@@ -1573,7 +1572,7 @@ static void mt7996_tx(struct ieee80211_hw *hw,
if (msta) {
struct mt7996_sta_link *msta_link;
- msta_link = rcu_dereference(msta->link[link_id]);
+ msta_link = mt7996_sta_link(msta, link_id);
if (msta_link)
wcid = &msta_link->wcid;
}
@@ -1944,7 +1943,7 @@ static void mt7996_link_sta_rc_update(struct ieee80211_hw *hw,
rcu_read_lock();
- msta_link = rcu_dereference(msta->link[link_sta->link_id]);
+ msta_link = mt7996_sta_link(msta, link_sta->link_id);
if (msta_link) {
struct mt7996_dev *dev = mt7996_hw_dev(hw);
@@ -1961,7 +1960,7 @@ static void mt7996_sta_rate_ctrl_update(void *data, struct ieee80211_sta *sta)
struct mt7996_sta_link *msta_link;
u32 *changed = data;
- msta_link = rcu_dereference(msta->link[msta->deflink_id]);
+ msta_link = mt7996_sta_link(msta, msta->deflink_id);
if (msta_link)
mt7996_link_rate_ctrl_update(&changed, msta_link);
}
@@ -2011,7 +2010,7 @@ static void mt7996_sta_set_4addr(struct ieee80211_hw *hw,
if (!link)
continue;
- msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
+ msta_link = mt7996_sta_link_protected(dev, msta, link_id);
if (!msta_link)
continue;
@@ -2049,7 +2048,7 @@ static void mt7996_sta_set_decap_offload(struct ieee80211_hw *hw,
if (!link)
continue;
- msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
+ msta_link = mt7996_sta_link_protected(dev, msta, link_id);
if (!msta_link)
continue;
@@ -2389,7 +2388,7 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
if (!link)
return -EIO;
- msta_link = rcu_dereference(msta->link[msta->deflink_id]);
+ msta_link = mt7996_sta_link(msta, msta->deflink_id);
if (!msta_link)
return -EIO;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
index 16420375112d..9aef28e66665 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
@@ -1136,7 +1136,7 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
struct mt7996_sta_link *msta_link;
int link_id = link_conf->link_id;
- msta_link = rcu_dereference(msta->link[link_id]);
+ msta_link = mt7996_sta_link(msta, link_id);
if (msta_link)
sta_wlan_idx = msta_link->wcid.idx;
}
@@ -1429,7 +1429,7 @@ int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
struct mt7996_sta_link *msta_link;
struct mt7996_vif_link *link;
- msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
+ msta_link = mt7996_sta_link_protected(dev, msta, link_id);
if (!msta_link)
continue;
@@ -1463,7 +1463,7 @@ int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev,
struct mt7996_sta_link *msta_link;
struct mt7996_vif_link *link;
- msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
+ msta_link = mt7996_sta_link_protected(dev, msta, link_id);
if (!msta_link)
continue;
@@ -2200,7 +2200,7 @@ int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct mt7996_sta *msta,
if (!mlink)
goto error_unlock;
- msta_link = rcu_dereference(msta->link[link_id]);
+ msta_link = mt7996_sta_link(msta, link_id);
if (!msta_link)
goto error_unlock;
@@ -2290,7 +2290,7 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev, struct mt7996_sta *msta,
if (!link)
goto error_unlock;
- msta_link = rcu_dereference(msta->link[link_id]);
+ msta_link = mt7996_sta_link(msta, link_id);
if (!msta_link)
goto error_unlock;
@@ -2508,7 +2508,7 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct mt7996_sta *msta,
if (!link)
goto error_unlock;
- msta_link = rcu_dereference(msta->link[link_id]);
+ msta_link = mt7996_sta_link(msta, link_id);
if (!msta_link)
goto error_unlock;
@@ -2663,7 +2663,7 @@ mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
unsigned int link_id;
struct tlv *tlv;
- msta_link = mt76_dereference(msta->link[msta->deflink_id], &dev->mt76);
+ msta_link = mt7996_sta_link_protected(dev, msta, msta->deflink_id);
if (!msta_link)
return;
@@ -2677,8 +2677,8 @@ mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
mld_setup->primary_id = cpu_to_le16(msta_link->wcid.idx);
if (nlinks > 1) {
- msta_link = mt76_dereference(msta->link[msta->seclink_id],
- &dev->mt76);
+ msta_link = mt7996_sta_link_protected(dev, msta,
+ msta->seclink_id);
if (!msta_link)
return;
}
@@ -2689,7 +2689,7 @@ mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
for_each_sta_active_link(vif, sta, link_sta, link_id) {
struct mt7996_vif_link *link;
- msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
+ msta_link = mt7996_sta_link_protected(dev, msta, link_id);
if (!msta_link)
continue;
@@ -2837,7 +2837,7 @@ void mt7996_mcu_update_sta_rec_bw(void *data, struct ieee80211_sta *sta)
if (!link_sta)
return;
- msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
+ msta_link = mt7996_sta_link_protected(dev, msta, link_id);
if (!msta_link)
return;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
index bdcf72457954..0dc4198fcf8b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
@@ -642,6 +642,25 @@ mt7996_vif_conf_link(struct mt7996_dev *dev, struct ieee80211_vif *vif,
link_conf);
}
+static inline struct mt7996_sta_link *
+mt7996_sta_link(struct mt7996_sta *msta, u8 link_id)
+{
+ if (link_id >= IEEE80211_MLD_MAX_NUM_LINKS)
+ return NULL;
+
+ return rcu_dereference(msta->link[link_id]);
+}
+
+static inline struct mt7996_sta_link *
+mt7996_sta_link_protected(struct mt7996_dev *dev, struct mt7996_sta *msta,
+ u8 link_id)
+{
+ if (link_id >= IEEE80211_MLD_MAX_NUM_LINKS)
+ return NULL;
+
+ return mt76_dereference(msta->link[link_id], &dev->mt76);
+}
+
#define mt7996_for_each_phy(dev, phy) \
for (int __i = 0; __i < ARRAY_SIZE((dev)->radio_phy); __i++) \
if (((phy) = (dev)->radio_phy[__i]) != NULL)
--
2.51.0
^ permalink raw reply related [flat|nested] 2+ messages in thread* [PATCH 2/2] wifi: mt76: mt7996: add missing max_remain_on_channel_duration
2026-03-24 15:49 [PATCH 1/2] wifi: mt76: mt7996: fix out-of-bounds array access during hardware restart Felix Fietkau
@ 2026-03-24 15:49 ` Felix Fietkau
0 siblings, 0 replies; 2+ messages in thread
From: Felix Fietkau @ 2026-03-24 15:49 UTC (permalink / raw)
To: linux-wireless
Having this unset breaks remain-on-channel and mgmt TX.
Move setting it to mt76 core to keep it in one place.
Fixes: 69d54ce7491d0 ("wifi: mt76: mt7996: switch to single multi-radio wiphy")
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
drivers/net/wireless/mediatek/mt76/mac80211.c | 2 ++
drivers/net/wireless/mediatek/mt76/mt7615/init.c | 1 -
drivers/net/wireless/mediatek/mt76/mt792x_core.c | 1 -
3 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index 4ae5e4715a9c..dd68776ada28 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -449,6 +449,8 @@ mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL);
+ if (!wiphy->max_remain_on_channel_duration)
+ wiphy->max_remain_on_channel_duration = 5000;
if (!wiphy->available_antennas_tx)
wiphy->available_antennas_tx = phy->antenna_mask;
if (!wiphy->available_antennas_rx)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
index 42e11ba1206e..e437e088b2e9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
@@ -195,7 +195,6 @@ mt7615_check_offload_capability(struct mt7615_dev *dev)
ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
wiphy->flags &= ~WIPHY_FLAG_4ADDR_STATION;
- wiphy->max_remain_on_channel_duration = 5000;
wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c
index 152cfcca2f90..5a5d7534830b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c
@@ -657,7 +657,6 @@ int mt792x_init_wiphy(struct ieee80211_hw *hw)
BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_P2P_DEVICE);
- wiphy->max_remain_on_channel_duration = 5000;
wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN;
wiphy->max_scan_ssids = 4;
wiphy->max_sched_scan_plan_interval =
--
2.51.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-03-24 15:49 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-24 15:49 [PATCH 1/2] wifi: mt76: mt7996: fix out-of-bounds array access during hardware restart Felix Fietkau
2026-03-24 15:49 ` [PATCH 2/2] wifi: mt76: mt7996: add missing max_remain_on_channel_duration Felix Fietkau
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox