[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260129081839.179709-3-zac@zacbowling.com>
Date: Thu, 29 Jan 2026 00:18:35 -0800
From: Zac <zac@...bowling.com>
To: nbd@....name
Cc: deren.wu@...iatek.com,
kvalo@...nel.org,
linux-kernel@...r.kernel.org,
linux-mediatek@...ts.infradead.org,
linux-wireless@...r.kernel.org,
linux@...me.work,
lorenzo@...nel.org,
ryder.lee@...iatek.com,
sean.wang@...nel.org,
sean.wang@...iatek.com,
zac@...bowling.com,
zbowling@...il.com
Subject: [PATCH v7 2/6] wifi: mt76: mt7925: add NULL pointer protection for MLO state transitions
Add NULL pointer checks for functions that return pointers to link-related
structures throughout the mt7925 driver. During MLO state transitions,
these functions can return NULL when link configuration is not synchronized.
Functions protected:
- mt792x_vif_to_bss_conf(): Returns link BSS configuration
- mt792x_vif_to_link(): Returns driver link state
- mt792x_sta_to_link(): Returns station link state
Key changes:
1. mt7925_set_link_key():
- Check link_conf, mconf, mlink before use
- During MLO roaming, allow key removal to succeed if link is already gone
2. mt7925_mac_link_sta_add():
- Check mlink and mconf before WCID allocation
- Check link_conf before BSS info update
- Add proper WCID cleanup on error paths (err_wcid label)
- Check MCU return values and propagate errors
3. mt7925_mac_link_sta_assoc():
- Check mlink before use
- Check link_conf and mconf before BSS info update
4. mt7925_mac_link_sta_remove():
- Check mlink before use
- Check link_conf and mconf before cleanup operations
Prevents crashes during:
- BSSID roaming transitions
- MLO setup and teardown
- Hardware reset operations
Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 device")
Signed-off-by: Zac Bowling <zac@...bowling.com>
---
.../net/wireless/mediatek/mt76/mt7925/main.c | 66 ++++++++++++++-----
1 file changed, 51 insertions(+), 15 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index fad3b1505f67..88ee90709b75 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -612,6 +612,17 @@ static int mt7925_set_link_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
link_sta = sta ? mt792x_sta_to_link_sta(vif, sta, link_id) : NULL;
mconf = mt792x_vif_to_link(mvif, link_id);
mlink = mt792x_sta_to_link(msta, link_id);
+
+ if (!link_conf || !mconf || !mlink) {
+ /* During MLO roaming, link state may be torn down before
+ * mac80211 requests key removal. If removing a key and
+ * the link is already gone, consider it successfully removed.
+ */
+ if (cmd != SET_KEY)
+ return 0;
+ return -EINVAL;
+ }
+
wcid = &mlink->wcid;
wcid_keyidx = &wcid->hw_key_idx;
@@ -864,12 +875,17 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
msta = (struct mt792x_sta *)link_sta->sta->drv_priv;
mlink = mt792x_sta_to_link(msta, link_id);
+ if (!mlink)
+ return -EINVAL;
+
+ mconf = mt792x_vif_to_link(mvif, link_id);
+ if (!mconf)
+ return -EINVAL;
idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1);
if (idx < 0)
return -ENOSPC;
- mconf = mt792x_vif_to_link(mvif, link_id);
mt76_wcid_init(&mlink->wcid, 0);
mlink->wcid.sta = 1;
mlink->wcid.idx = idx;
@@ -888,21 +904,28 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
ret = mt76_connac_pm_wake(&dev->mphy, &dev->pm);
if (ret)
- return ret;
+ goto err_wcid;
mt7925_mac_wtbl_update(dev, idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
link_conf = mt792x_vif_to_bss_conf(vif, link_id);
+ if (!link_conf) {
+ ret = -EINVAL;
+ goto err_wcid;
+ }
/* should update bss info before STA add */
if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) {
if (ieee80211_vif_is_mld(vif))
- mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx,
- link_conf, link_sta, link_sta != mlink->pri_link);
+ ret = mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx,
+ link_conf, link_sta,
+ link_sta != mlink->pri_link);
else
- mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx,
- link_conf, link_sta, false);
+ ret = mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx,
+ link_conf, link_sta, false);
+ if (ret)
+ goto err_wcid;
}
if (ieee80211_vif_is_mld(vif) &&
@@ -910,28 +933,34 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
ret = mt7925_mcu_sta_update(dev, link_sta, vif, true,
MT76_STA_INFO_STATE_NONE);
if (ret)
- return ret;
+ goto err_wcid;
} else if (ieee80211_vif_is_mld(vif) &&
link_sta != mlink->pri_link) {
ret = mt7925_mcu_sta_update(dev, mlink->pri_link, vif,
true, MT76_STA_INFO_STATE_ASSOC);
if (ret)
- return ret;
+ goto err_wcid;
ret = mt7925_mcu_sta_update(dev, link_sta, vif, true,
MT76_STA_INFO_STATE_ASSOC);
if (ret)
- return ret;
+ goto err_wcid;
} else {
ret = mt7925_mcu_sta_update(dev, link_sta, vif, true,
MT76_STA_INFO_STATE_NONE);
if (ret)
- return ret;
+ goto err_wcid;
}
mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
return 0;
+
+err_wcid:
+ rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
+ mt76_wcid_mask_clear(dev->mt76.wcid_mask, idx);
+ mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
+ return ret;
}
static int
@@ -1039,6 +1068,8 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev,
msta = (struct mt792x_sta *)link_sta->sta->drv_priv;
mlink = mt792x_sta_to_link(msta, link_sta->link_id);
+ if (!mlink)
+ return;
mt792x_mutex_acquire(dev);
@@ -1048,12 +1079,13 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev,
link_conf = mt792x_vif_to_bss_conf(vif, vif->bss_conf.link_id);
}
- if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) {
+ if (link_conf && vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) {
struct mt792x_bss_conf *mconf;
mconf = mt792x_link_conf_to_mconf(link_conf);
- mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx,
- link_conf, link_sta, true);
+ if (mconf)
+ mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx,
+ link_conf, link_sta, true);
}
ewma_avg_signal_init(&mlink->avg_ack_signal);
@@ -1100,6 +1132,8 @@ static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev,
msta = (struct mt792x_sta *)link_sta->sta->drv_priv;
mlink = mt792x_sta_to_link(msta, link_id);
+ if (!mlink)
+ return;
mt7925_roc_abort_sync(dev);
@@ -1113,10 +1147,12 @@ static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev,
link_conf = mt792x_vif_to_bss_conf(vif, link_id);
- if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) {
+ if (link_conf && vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) {
struct mt792x_bss_conf *mconf;
mconf = mt792x_link_conf_to_mconf(link_conf);
+ if (!mconf)
+ goto out;
if (ieee80211_vif_is_mld(vif))
mt792x_mac_link_bss_remove(dev, mconf, mlink);
@@ -1124,7 +1160,7 @@ static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev,
mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, link_conf,
link_sta, false);
}
-
+out:
spin_lock_bh(&mdev->sta_poll_lock);
if (!list_empty(&mlink->wcid.poll_list))
list_del_init(&mlink->wcid.poll_list);
--
2.52.0
Powered by blists - more mailing lists