|
@@ -333,7 +333,7 @@ void ieee80211_sw_roc_work(struct work_struct *work)
|
|
container_of(work, struct ieee80211_roc_work, work.work);
|
|
container_of(work, struct ieee80211_roc_work, work.work);
|
|
struct ieee80211_sub_if_data *sdata = roc->sdata;
|
|
struct ieee80211_sub_if_data *sdata = roc->sdata;
|
|
struct ieee80211_local *local = sdata->local;
|
|
struct ieee80211_local *local = sdata->local;
|
|
- bool started;
|
|
|
|
|
|
+ bool started, on_channel;
|
|
|
|
|
|
mutex_lock(&local->mtx);
|
|
mutex_lock(&local->mtx);
|
|
|
|
|
|
@@ -354,14 +354,26 @@ void ieee80211_sw_roc_work(struct work_struct *work)
|
|
if (!roc->started) {
|
|
if (!roc->started) {
|
|
struct ieee80211_roc_work *dep;
|
|
struct ieee80211_roc_work *dep;
|
|
|
|
|
|
- /* start this ROC */
|
|
|
|
- ieee80211_offchannel_stop_vifs(local);
|
|
|
|
|
|
+ WARN_ON(local->use_chanctx);
|
|
|
|
+
|
|
|
|
+ /* If actually operating on the desired channel (with at least
|
|
|
|
+ * 20 MHz channel width) don't stop all the operations but still
|
|
|
|
+ * treat it as though the ROC operation started properly, so
|
|
|
|
+ * other ROC operations won't interfere with this one.
|
|
|
|
+ */
|
|
|
|
+ roc->on_channel = roc->chan == local->_oper_chandef.chan &&
|
|
|
|
+ local->_oper_chandef.width != NL80211_CHAN_WIDTH_5 &&
|
|
|
|
+ local->_oper_chandef.width != NL80211_CHAN_WIDTH_10;
|
|
|
|
|
|
- /* switch channel etc */
|
|
|
|
|
|
+ /* start this ROC */
|
|
ieee80211_recalc_idle(local);
|
|
ieee80211_recalc_idle(local);
|
|
|
|
|
|
- local->tmp_channel = roc->chan;
|
|
|
|
- ieee80211_hw_config(local, 0);
|
|
|
|
|
|
+ if (!roc->on_channel) {
|
|
|
|
+ ieee80211_offchannel_stop_vifs(local);
|
|
|
|
+
|
|
|
|
+ local->tmp_channel = roc->chan;
|
|
|
|
+ ieee80211_hw_config(local, 0);
|
|
|
|
+ }
|
|
|
|
|
|
/* tell userspace or send frame */
|
|
/* tell userspace or send frame */
|
|
ieee80211_handle_roc_started(roc);
|
|
ieee80211_handle_roc_started(roc);
|
|
@@ -380,9 +392,10 @@ void ieee80211_sw_roc_work(struct work_struct *work)
|
|
finish:
|
|
finish:
|
|
list_del(&roc->list);
|
|
list_del(&roc->list);
|
|
started = roc->started;
|
|
started = roc->started;
|
|
|
|
+ on_channel = roc->on_channel;
|
|
ieee80211_roc_notify_destroy(roc, !roc->abort);
|
|
ieee80211_roc_notify_destroy(roc, !roc->abort);
|
|
|
|
|
|
- if (started) {
|
|
|
|
|
|
+ if (started && !on_channel) {
|
|
ieee80211_flush_queues(local, NULL);
|
|
ieee80211_flush_queues(local, NULL);
|
|
|
|
|
|
local->tmp_channel = NULL;
|
|
local->tmp_channel = NULL;
|