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@zacbowling.com>
---
.../net/wireless/mediatek/mt76/mt7925/main.c | 67 ++++++++++++++-----
1 file changed, 52 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..1400633712b7 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,35 @@ 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_cleanup(&dev->mt76, wcid);
+ mt76_wcid_mask_clear(dev->mt76.wcid_mask, idx);
+ mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
+ return ret;
}
static int
@@ -1039,6 +1069,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 +1080,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 +1133,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 +1148,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 +1161,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
Add error logging in mt7925_mac_set_links() when mt7925_set_mlo_roc()
fails. Previously the error return was silently ignored since the
callback function is void.
The function now logs non-ENOLINK errors as warnings. ENOLINK errors
are expected during link transitions when the link configuration is
not yet ready, and mac80211 will retry the operation later.
This complements the error handling changes in mt7925_mcu_set_mlo_roc()
where WARN_ON_ONCE was replaced with proper -ENOLINK returns.
Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 device")
Signed-off-by: Zac Bowling <zac@zacbowling.com>
---
drivers/net/wireless/mediatek/mt76/mt7925/main.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 0b088c448151..769c09e99d48 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -1048,11 +1048,16 @@ mt7925_mac_set_links(struct mt76_dev *mdev, struct ieee80211_vif *vif)
if (band == NL80211_BAND_2GHZ ||
(band == NL80211_BAND_5GHZ && secondary_band == NL80211_BAND_6GHZ)) {
+ int ret;
+
mt7925_abort_roc(mvif->phy, &mvif->bss_conf);
mt792x_mutex_acquire(dev);
- mt7925_set_mlo_roc(mvif->phy, &mvif->bss_conf, sel_links);
+ ret = mt7925_set_mlo_roc(mvif->phy, &mvif->bss_conf, sel_links);
+ if (ret && ret != -ENOLINK)
+ dev_warn(dev->mt76.dev,
+ "MLO ROC setup failed in set_links: %d\n", ret);
mt792x_mutex_release(dev);
}
--
2.52.0
© 2016 - 2026 Red Hat, Inc.