diff options
Diffstat (limited to 'net/mac80211/offchannel.c')
-rw-r--r-- | net/mac80211/offchannel.c | 26 |
1 files changed, 20 insertions, 6 deletions
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 0c2a29484c07..7a17decd27f9 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c | |||
@@ -333,7 +333,7 @@ void ieee80211_sw_roc_work(struct work_struct *work) | |||
333 | container_of(work, struct ieee80211_roc_work, work.work); | 333 | container_of(work, struct ieee80211_roc_work, work.work); |
334 | struct ieee80211_sub_if_data *sdata = roc->sdata; | 334 | struct ieee80211_sub_if_data *sdata = roc->sdata; |
335 | struct ieee80211_local *local = sdata->local; | 335 | struct ieee80211_local *local = sdata->local; |
336 | bool started; | 336 | bool started, on_channel; |
337 | 337 | ||
338 | mutex_lock(&local->mtx); | 338 | mutex_lock(&local->mtx); |
339 | 339 | ||
@@ -354,13 +354,26 @@ void ieee80211_sw_roc_work(struct work_struct *work) | |||
354 | if (!roc->started) { | 354 | if (!roc->started) { |
355 | struct ieee80211_roc_work *dep; | 355 | struct ieee80211_roc_work *dep; |
356 | 356 | ||
357 | /* start this ROC */ | 357 | WARN_ON(local->use_chanctx); |
358 | |||
359 | /* If actually operating on the desired channel (with at least | ||
360 | * 20 MHz channel width) don't stop all the operations but still | ||
361 | * treat it as though the ROC operation started properly, so | ||
362 | * other ROC operations won't interfere with this one. | ||
363 | */ | ||
364 | roc->on_channel = roc->chan == local->_oper_chandef.chan && | ||
365 | local->_oper_chandef.width != NL80211_CHAN_WIDTH_5 && | ||
366 | local->_oper_chandef.width != NL80211_CHAN_WIDTH_10; | ||
358 | 367 | ||
359 | /* switch channel etc */ | 368 | /* start this ROC */ |
360 | ieee80211_recalc_idle(local); | 369 | ieee80211_recalc_idle(local); |
361 | 370 | ||
362 | local->tmp_channel = roc->chan; | 371 | if (!roc->on_channel) { |
363 | ieee80211_hw_config(local, 0); | 372 | ieee80211_offchannel_stop_vifs(local); |
373 | |||
374 | local->tmp_channel = roc->chan; | ||
375 | ieee80211_hw_config(local, 0); | ||
376 | } | ||
364 | 377 | ||
365 | /* tell userspace or send frame */ | 378 | /* tell userspace or send frame */ |
366 | ieee80211_handle_roc_started(roc); | 379 | ieee80211_handle_roc_started(roc); |
@@ -379,9 +392,10 @@ void ieee80211_sw_roc_work(struct work_struct *work) | |||
379 | finish: | 392 | finish: |
380 | list_del(&roc->list); | 393 | list_del(&roc->list); |
381 | started = roc->started; | 394 | started = roc->started; |
395 | on_channel = roc->on_channel; | ||
382 | ieee80211_roc_notify_destroy(roc, !roc->abort); | 396 | ieee80211_roc_notify_destroy(roc, !roc->abort); |
383 | 397 | ||
384 | if (started) { | 398 | if (started && !on_channel) { |
385 | ieee80211_flush_queues(local, NULL); | 399 | ieee80211_flush_queues(local, NULL); |
386 | 400 | ||
387 | local->tmp_channel = NULL; | 401 | local->tmp_channel = NULL; |