From 1359b631c7c8455de947b2cc44b335b0ebc84d9e Mon Sep 17 00:00:00 2001 From: Ruide Cao Date: Tue, 22 Sep 2026 23:38:54 +0800 Subject: [PATCH] wifi: mac80211: start next ROC after purging an interface When an interface owning the active hardware ROC is purged, a ROC queued for another interface can become the head of roc_list without being started. Subsequent requests only append to the non-empty list, so no driver work is scheduled and the entries are never freed. Flush pending ROC start work and cancel pending completion work before handing the remaining queue to the normal next-ROC path. This preserves the existing software ROC handling and avoids stale workers operating on the newly started ROC. Reported-by: Vega Assisted-by: LLM Signed-off-by: Ruide Cao Signed-off-by: Ren Wei Link: https://patch.msgid.link/6975ce9d8e9a153e8319d10e6e7c7be004d6df88.1787220252.git.vega.cover-letter@nebusec.ai Signed-off-by: Johannes Berg --- net/mac80211/offchannel.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 4b40b461ca78..c46cb81fab22 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -1075,10 +1075,14 @@ void ieee80211_roc_purge(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata) { struct ieee80211_roc_work *roc, *tmp; + bool start_next_roc = false; bool work_to_do = false; lockdep_assert_wiphy(local->hw.wiphy); + if (local->ops->remain_on_channel) + wiphy_work_flush(local->hw.wiphy, &local->hw_roc_start); + list_for_each_entry_safe(roc, tmp, &local->roc_list, list) { if (sdata && roc->sdata != sdata) continue; @@ -1088,6 +1092,7 @@ void ieee80211_roc_purge(struct ieee80211_local *local, /* can race, so ignore return value */ drv_cancel_remain_on_channel(local, roc->sdata); ieee80211_roc_notify_destroy(roc); + start_next_roc = true; } else { roc->abort = true; work_to_do = true; @@ -1098,4 +1103,9 @@ void ieee80211_roc_purge(struct ieee80211_local *local, } if (work_to_do) __ieee80211_roc_work(local); + else if (start_next_roc) { + wiphy_work_cancel(local->hw.wiphy, &local->hw_roc_done); + if (!list_empty(&local->roc_list)) + ieee80211_start_next_roc(local); + } }