svn commit: r275984 - head/sys/net80211

Adrian Chadd adrian at FreeBSD.org
Sun Dec 21 04:58:47 UTC 2014


Author: adrian
Date: Sun Dec 21 04:58:45 2014
New Revision: 275984
URL: https://svnweb.freebsd.org/changeset/base/275984

Log:
  Update ieee80211_sta_tim_notify() to do double duty - handle STA sleep
  to awake transition as well as handle waking up a VAP in STA powersave
  mode if it's in bgscan.
  
  This was a reasonably hairy bug to try and figure out and it became
  more obvious because of stuff I've done.
  
  Specifically:
  
  * a NIC would go into bgscan mode - either because of a bgscan timer
    or wpa_supplicant asked it to;
  * the AP would indicate there's traffic for the STA by setting the TIM
    bitmap bit for it;
  * mindwell would be met during scan, so it'd wake up and break out of
    the scan loop in scan_task(), but
  * because the scan wasn't completed, it wouldn't bring the VAP out of
    STA mode powersave (so it wouldn't tell the AP about it and it would
    block VAP TX);
  * .. but because we kept seeing the TIM bit set, ic->ic_lastdata was
    being constantly updated, and ..
  * bgscancont() would thus never say "yes we can continue a bgscan"
    so the bgscan would hang and never make progress.
  
  Now, I do see this particular state occur on iwn(4) - /however/ -
  this NIC has the firmware call ieee80211_scan_next() once the firmware
  scan for that channel has completed.  This has the effect of moving
  the scan along to the next channel.  I do see the debug that I'm adding
  where we see a beacon with a TIM bit set whilst we're in bgscan, so
  the condition about waking up to receive traffic is triggering.
  It just won't cause a hang.
  
  For other NICs - all of the USB ones and at least ath(4) -
  ieee80211_scan_next() / ieee80211_scan_done() isn't called.
  So it relies upon the mindwell timer, the beacon receive and the
  beacon / probe response -> ieee80211_add_scan() to move along
  the scan state.
  
  In the above case, mindwell triggered, there's no beacons triggering
  the scan_add code to move things along, and we weren't waking things
  up when seeing the TIM set for us.  So it just hung until the interface
  was dropped.
  
  So, the short-term fix here is to do what the comment in scan_task()
  says - if we are in bgscan mode and we see our TIM bit set, just wake
  up the VAP.  If it's already awake then it's a nop.  If we're awake
  then we transition to awake and handle the traffic.  Once there's no
  TX or RX traffic going on, ic->ic_lastdata won't be updated anymore
  and bgscancont() will continue.
  
  This was triggered more often after my initial SLEEP state handling
  for software sleep states - because now I update ic->ic_lastdata
  upon seeing a TIM bit set, not just the RX of the subsequent traffic.
  That's needed so the thing doesn't ping-pong up and down between
  seeing the TIM bit set, sending the "I'm awake" NULL data frame, and
  starting to receive data from the AP.
  
  I'd like to subsequently split ic_lastdata into two - one for TX and
  one for RX - so it becomes easier to use the correct one (or both!)
  when making decisions like whether to scan, go to sleep, etc.
  
  I'd appreciate this getting some further testing.
  
  Tested:
  
  * rsu(4), STA mode, bgscan on
  * iwn(4), STA mode, bgscan on

Modified:
  head/sys/net80211/ieee80211_power.c

Modified: head/sys/net80211/ieee80211_power.c
==============================================================================
--- head/sys/net80211/ieee80211_power.c	Sun Dec 21 04:48:54 2014	(r275983)
+++ head/sys/net80211/ieee80211_power.c	Sun Dec 21 04:58:45 2014	(r275984)
@@ -560,10 +560,15 @@ ieee80211_sta_pwrsave(struct ieee80211va
  * Handle being notified that we have data available for us in a TIM/ATIM.
  *
  * This may schedule a transition from _SLEEP -> _RUN if it's appropriate.
+ *
+ * In STA mode, we may have put to sleep during scan and need to be dragged
+ * back out of powersave mode.
  */
 void
 ieee80211_sta_tim_notify(struct ieee80211vap *vap, int set)
 {
+	struct ieee80211com *ic = vap->iv_ic;
+
 	/*
 	 * Schedule the driver state change.  It'll happen at some point soon.
 	 * Since the hardware shouldn't know that we're running just yet
@@ -574,10 +579,24 @@ ieee80211_sta_tim_notify(struct ieee8021
 	 * XXX TODO: verify that the transition to RUN will wake up the
 	 * BSS node!
 	 */
-	IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER, "%s: TIM=%d\n", __func__, set);
 	IEEE80211_LOCK(vap->iv_ic);
 	if (set == 1 && vap->iv_state == IEEE80211_S_SLEEP) {
 		ieee80211_new_state_locked(vap, IEEE80211_S_RUN, 0);
+		IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER,
+		    "%s: TIM=%d; wakeup\n", __func__, set);
+	} else if ((set == 1) && (ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN)) {
+		/*
+		 * XXX only do this if we're in RUN state?
+		 */
+		IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER,
+		    "%s: wake up from bgscan vap sleep\n",
+		    __func__);
+		/*
+		 * We may be in BGSCAN mode - this means the VAP is is in STA
+		 * mode powersave.  If it is, we need to wake it up so we
+		 * can process outbound traffic.
+		 */
+		vap->iv_sta_ps(vap, 0);
 	}
 	IEEE80211_UNLOCK(vap->iv_ic);
 }


More information about the svn-src-head mailing list