diff mbox

[RFC,1/3] mac80211: Add flushes to ensure off-channel PS is enabled during sw scans

Message ID 1357668645-5101-2-git-send-email-seth.forshee@canonical.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Seth Forshee Jan. 8, 2013, 6:10 p.m. UTC
We've got a couple of races when enabling powersave with an AP for
off-channel operation. The first is fairly simple. If we go off-channel
prior to the nullfunc frame to enable PS is actually transmitted then it
may not be received by the AP. Add a flush after enabling off-channel PS
to prevent this from happening.

The second race is a bit more subtle. If the driver supports QoS and has
frames queued when the nullfunc frame is queued, those frames may get
transmitted after the nullfunc frame. If PM is not set then the AP is
being told that we've exited PS before we go off-channel and may try to
deliver frames. To prevent this, add a flush after stopping the netdev
queues but before passing the nullfunc frame to the driver.

Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
---
 net/mac80211/offchannel.c |   17 ++++++++++++++++-
 net/mac80211/scan.c       |    8 ++++++++
 2 files changed, 24 insertions(+), 1 deletion(-)

Comments

Johannes Berg Jan. 16, 2013, 11:34 p.m. UTC | #1
On Tue, 2013-01-08 at 12:10 -0600, Seth Forshee wrote:

> +++ b/net/mac80211/offchannel.c
> @@ -136,8 +136,23 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
>  			netif_tx_stop_all_queues(sdata->dev);
>  			if (offchannel_ps_enable &&
>  			    (sdata->vif.type == NL80211_IFTYPE_STATION) &&
> -			    sdata->u.mgd.associated)
> +			    sdata->u.mgd.associated) {
> +				/*
> +				 * Need to flush frames in driver queues
> +				 * before sending nullfunc. Otherwise
> +				 * devices which support QoS may send the
> +				 * nullfunc before these queued frames, and
> +				 * those frames may not have PM set.
> +				 *
> +				 * XXX: Would be nice to not flush for each
> +				 * vif, however I don't see that there's any
> +				 * protection to prevent frames being handed
> +				 * to the driver before stopping the netdev
> +				 * queue.
> +				 */
> +				drv_flush(local, false);
>  				ieee80211_offchannel_ps_enable(sdata);

Could we split the loop, and send the frames in a second loop, to
combine the flushes into a single one?

johannes

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Seth Forshee Jan. 17, 2013, 5:34 a.m. UTC | #2
On Thu, Jan 17, 2013 at 12:34:14AM +0100, Johannes Berg wrote:
> On Tue, 2013-01-08 at 12:10 -0600, Seth Forshee wrote:
> 
> > +++ b/net/mac80211/offchannel.c
> > @@ -136,8 +136,23 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
> >  			netif_tx_stop_all_queues(sdata->dev);
> >  			if (offchannel_ps_enable &&
> >  			    (sdata->vif.type == NL80211_IFTYPE_STATION) &&
> > -			    sdata->u.mgd.associated)
> > +			    sdata->u.mgd.associated) {
> > +				/*
> > +				 * Need to flush frames in driver queues
> > +				 * before sending nullfunc. Otherwise
> > +				 * devices which support QoS may send the
> > +				 * nullfunc before these queued frames, and
> > +				 * those frames may not have PM set.
> > +				 *
> > +				 * XXX: Would be nice to not flush for each
> > +				 * vif, however I don't see that there's any
> > +				 * protection to prevent frames being handed
> > +				 * to the driver before stopping the netdev
> > +				 * queue.
> > +				 */
> > +				drv_flush(local, false);
> >  				ieee80211_offchannel_ps_enable(sdata);
> 
> Could we split the loop, and send the frames in a second loop, to
> combine the flushes into a single one?

I started thinking about just that earlier today. Seems like it ought to
be possible.

Seth
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index a5379ae..ccb91a2 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -136,8 +136,23 @@  void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
 			netif_tx_stop_all_queues(sdata->dev);
 			if (offchannel_ps_enable &&
 			    (sdata->vif.type == NL80211_IFTYPE_STATION) &&
-			    sdata->u.mgd.associated)
+			    sdata->u.mgd.associated) {
+				/*
+				 * Need to flush frames in driver queues
+				 * before sending nullfunc. Otherwise
+				 * devices which support QoS may send the
+				 * nullfunc before these queued frames, and
+				 * those frames may not have PM set.
+				 *
+				 * XXX: Would be nice to not flush for each
+				 * vif, however I don't see that there's any
+				 * protection to prevent frames being handed
+				 * to the driver before stopping the netdev
+				 * queue.
+				 */
+				drv_flush(local, false);
 				ieee80211_offchannel_ps_enable(sdata);
+			}
 		}
 	}
 	mutex_unlock(&local->iflist_mtx);
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 8ed83dc..a875f74 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -355,6 +355,14 @@  static int ieee80211_start_sw_scan(struct ieee80211_local *local)
 
 	ieee80211_offchannel_stop_vifs(local, true);
 
+	/*
+	 * Flush hw queues to ensure that the nullfunc to enable powersave
+	 * gets sent before going off-channel.
+	 *
+	 * XXX: Delay for drivers not supporting flush?
+	 */
+	drv_flush(local, false);
+
 	ieee80211_configure_filter(local);
 
 	/* We need to set power level at maximum rate for scanning. */