[3.11.y.z extended stable] Patch "mac80211: fix on-channel remain-on-channel" has been added to staging queue

Luis Henriques luis.henriques at canonical.com
Fri Jun 6 15:03:50 UTC 2014


This is a note to let you know that I have just added a patch titled

    mac80211: fix on-channel remain-on-channel

to the linux-3.11.y-queue branch of the 3.11.y.z extended stable tree 
which can be found at:

 http://kernel.ubuntu.com/git?p=ubuntu/linux.git;a=shortlog;h=refs/heads/linux-3.11.y-queue

If you, or anyone else, feels it should not be added to this tree, please 
reply to this email.

For more information about the 3.11.y.z tree, see
https://wiki.ubuntu.com/Kernel/Dev/ExtendedStable

Thanks.
-Luis

------

>From e5fd02f4ff663f5ec6ad56079c631ad1d1a4a03b Mon Sep 17 00:00:00 2001
From: Johannes Berg <johannes.berg at intel.com>
Date: Wed, 14 May 2014 15:34:41 +0200
Subject: mac80211: fix on-channel remain-on-channel

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 at w1.fi>
Tested-by: Jouni Malinen <j at w1.fi>
Signed-off-by: Johannes Berg <johannes.berg at intel.com>
Signed-off-by: Luis Henriques <luis.henriques at canonical.com>
---
 net/mac80211/ieee80211_i.h |  1 +
 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 735349bd9a07..18e16d05292b 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -312,6 +312,7 @@ struct ieee80211_roc_work {

 	bool started, abort, hw_begun, notified;
 	bool to_be_freed;
+	bool on_channel;

 	unsigned long hw_start_time;

diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index 11d3f227e11e..e554a246e52c 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -333,7 +333,7 @@ void ieee80211_sw_roc_work(struct work_struct *work)
 		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,26 @@ void ieee80211_sw_roc_work(struct work_struct *work)
 	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 &&
+				  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);

-		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 +392,10 @@ void ieee80211_sw_roc_work(struct work_struct *work)
  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;
--
1.9.1





More information about the kernel-team mailing list