Skip to content

Commit 71ecfa1

Browse files
jmberg-intellinvjw
authored andcommitted
mac80211: clean up remain-on-channel on interface stop
When any interface goes down, it could be the one that we were doing a remain-on-channel with. We therefore need to cancel the remain-on-channel and flush the related work structs so they don't run after the interface has been removed or even destroyed. It's also possible in this case that an off-channel SKB was never transmitted, so free it if this is the case. Note that this can also happen if the driver finishes the off-channel period without ever starting it. Cc: [email protected] Reported-by: Nirav Shah <[email protected]> Signed-off-by: Johannes Berg <[email protected]> Signed-off-by: John W. Linville <[email protected]>
1 parent 1ae2fc2 commit 71ecfa1

File tree

2 files changed

+28
-0
lines changed

2 files changed

+28
-0
lines changed

net/mac80211/iface.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,18 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
637637
ieee80211_configure_filter(local);
638638
break;
639639
default:
640+
mutex_lock(&local->mtx);
641+
if (local->hw_roc_dev == sdata->dev &&
642+
local->hw_roc_channel) {
643+
/* ignore return value since this is racy */
644+
drv_cancel_remain_on_channel(local);
645+
ieee80211_queue_work(&local->hw, &local->hw_roc_done);
646+
}
647+
mutex_unlock(&local->mtx);
648+
649+
flush_work(&local->hw_roc_start);
650+
flush_work(&local->hw_roc_done);
651+
640652
flush_work(&sdata->work);
641653
/*
642654
* When we get here, the interface is marked down.

net/mac80211/offchannel.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,22 @@ static void ieee80211_hw_roc_done(struct work_struct *work)
234234
return;
235235
}
236236

237+
/* was never transmitted */
238+
if (local->hw_roc_skb) {
239+
u64 cookie;
240+
241+
cookie = local->hw_roc_cookie ^ 2;
242+
243+
cfg80211_mgmt_tx_status(local->hw_roc_dev, cookie,
244+
local->hw_roc_skb->data,
245+
local->hw_roc_skb->len, false,
246+
GFP_KERNEL);
247+
248+
kfree_skb(local->hw_roc_skb);
249+
local->hw_roc_skb = NULL;
250+
local->hw_roc_skb_for_status = NULL;
251+
}
252+
237253
if (!local->hw_roc_for_tx)
238254
cfg80211_remain_on_channel_expired(local->hw_roc_dev,
239255
local->hw_roc_cookie,

0 commit comments

Comments
 (0)