diff options
-rw-r--r-- | net/mac80211/ieee80211_i.h | 1 | ||||
-rw-r--r-- | net/mac80211/offchannel.c | 27 |
2 files changed, 21 insertions, 7 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 222c28b75315..f169b6ee94ee 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -317,6 +317,7 @@ struct ieee80211_roc_work { | |||
317 | 317 | ||
318 | bool started, abort, hw_begun, notified; | 318 | bool started, abort, hw_begun, notified; |
319 | bool to_be_freed; | 319 | bool to_be_freed; |
320 | bool on_channel; | ||
320 | 321 | ||
321 | unsigned long hw_start_time; | 322 | unsigned long hw_start_time; |
322 | 323 | ||
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 6fb38558a5e6..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,14 +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 | ieee80211_offchannel_stop_vifs(local); | 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; | ||
359 | 367 | ||
360 | /* switch channel etc */ | 368 | /* start this ROC */ |
361 | ieee80211_recalc_idle(local); | 369 | ieee80211_recalc_idle(local); |
362 | 370 | ||
363 | local->tmp_channel = roc->chan; | 371 | if (!roc->on_channel) { |
364 | 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 | } | ||
365 | 377 | ||
366 | /* tell userspace or send frame */ | 378 | /* tell userspace or send frame */ |
367 | ieee80211_handle_roc_started(roc); | 379 | ieee80211_handle_roc_started(roc); |
@@ -380,9 +392,10 @@ void ieee80211_sw_roc_work(struct work_struct *work) | |||
380 | finish: | 392 | finish: |
381 | list_del(&roc->list); | 393 | list_del(&roc->list); |
382 | started = roc->started; | 394 | started = roc->started; |
395 | on_channel = roc->on_channel; | ||
383 | ieee80211_roc_notify_destroy(roc, !roc->abort); | 396 | ieee80211_roc_notify_destroy(roc, !roc->abort); |
384 | 397 | ||
385 | if (started) { | 398 | if (started && !on_channel) { |
386 | ieee80211_flush_queues(local, NULL); | 399 | ieee80211_flush_queues(local, NULL); |
387 | 400 | ||
388 | local->tmp_channel = NULL; | 401 | local->tmp_channel = NULL; |