--- /dev/null
+From b4b177a5556a686909e643f1e9b6434c10de079f Mon Sep 17 00:00:00 2001
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Wed, 14 May 2014 15:34:41 +0200
+Subject: mac80211: fix on-channel remain-on-channel
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+commit b4b177a5556a686909e643f1e9b6434c10de079f upstream.
+
+Jouni reported that if a remain-on-channel was active on the
+same channel as the current operating channel, then the ROC
+would start, but any frames transmitted using mgmt-tx on the
+same channel would get delayed until after the ROC.
+
+The reason for this is that the ROC starts, but doesn't have
+any handling for "remain on the same channel", so it stops
+the interface queues. The later mgmt-tx then puts the frame
+on the interface queues (since it's on the current operating
+channel) and thus they get delayed until after the ROC.
+
+To fix this, add some logic to handle remaining on the same
+channel specially and not stop the queues etc. in this case.
+This not only fixes the bug but also improves behaviour in
+this case as data frames etc. can continue to flow.
+
+Reported-by: Jouni Malinen <j@w1.fi>
+Tested-by: Jouni Malinen <j@w1.fi>
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ net/mac80211/ieee80211_i.h | 1 +
+ net/mac80211/offchannel.c | 25 ++++++++++++++++++-------
+ 2 files changed, 19 insertions(+), 7 deletions(-)
+
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -311,6 +311,7 @@ struct ieee80211_roc_work {
+
+ bool started, abort, hw_begun, notified;
+ bool to_be_freed;
++ bool on_channel;
+
+ unsigned long hw_start_time;
+
+--- a/net/mac80211/offchannel.c
++++ b/net/mac80211/offchannel.c
+@@ -333,7 +333,7 @@ void ieee80211_sw_roc_work(struct work_s
+ container_of(work, struct ieee80211_roc_work, work.work);
+ struct ieee80211_sub_if_data *sdata = roc->sdata;
+ struct ieee80211_local *local = sdata->local;
+- bool started;
++ bool started, on_channel;
+
+ mutex_lock(&local->mtx);
+
+@@ -354,14 +354,24 @@ void ieee80211_sw_roc_work(struct work_s
+ if (!roc->started) {
+ 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;
+
+- /* switch channel etc */
++ /* start this ROC */
+ 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 */
+ ieee80211_handle_roc_started(roc);
+@@ -380,9 +390,10 @@ void ieee80211_sw_roc_work(struct work_s
+ finish:
+ list_del(&roc->list);
+ started = roc->started;
++ on_channel = roc->on_channel;
+ ieee80211_roc_notify_destroy(roc, !roc->abort);
+
+- if (started) {
++ if (started && !on_channel) {
+ ieee80211_flush_queues(local, NULL);
+
+ local->tmp_channel = NULL;