wifi: mt76: check a remain-on-channel still belongs to the interface

roc_phy on the shared per-interface data names the phy of the one started last,
which may have ended or moved on to another interface since. Both users take it
at face value: an interface going away aborts whatever it names, and cancelling
one for an interface acts on it without asking whose it is.

Aborting a stranger's leaves the interface's own outstanding one behind, and its
work then runs once the interface is gone, tearing the link down through the
freed bss_conf:

  Unable to handle kernel paging request at virtual address 000043c218ce0afd
  Workqueue: phy0 mt76_roc_complete_work [mt76]
  pc : mt76_connac_mcu_sta_basic_tlv+0xdc/0x260 [mt76_connac_lib]
  Call trace:
   mt76_connac_mcu_sta_basic_tlv
   mt7996_mcu_add_sta
   mt7996_vif_link_destroy
   mt7996_vif_link_remove
   mt76_put_vif_phy_link
   mt76_roc_complete
   mt76_roc_complete_work

Check the interface before acting on it in both places.

Signed-off-by: Felix Fietkau <[email protected]>
This commit is contained in:
Felix Fietkau
2026-08-04 11:40:37 +02:00
parent 044081b202
commit d3b243c548
2 changed files with 2 additions and 2 deletions
+1 -1
View File
@@ -423,7 +423,7 @@ int mt76_cancel_remain_on_channel(struct ieee80211_hw *hw,
struct mt76_vif_data *mvif = mlink->mvif;
struct mt76_phy *phy = mvif->roc_phy;
if (!phy)
if (!phy || phy->roc_vif != vif)
return 0;
mt76_abort_roc(phy);
+1 -1
View File
@@ -2100,7 +2100,7 @@ void mt76_vif_cleanup(struct mt76_dev *dev, struct ieee80211_vif *vif)
rcu_assign_pointer(mvif->link[0], NULL);
mt76_abort_scan(dev);
if (mvif->roc_phy)
if (mvif->roc_phy && mvif->roc_phy->roc_vif == vif)
mt76_abort_roc(mvif->roc_phy);
}
EXPORT_SYMBOL_GPL(mt76_vif_cleanup);