Date: Sun, 21 Dec 2014 04:58:46 +0000 (UTC) From: Adrian Chadd <adrian@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r275984 - head/sys/net80211 Message-ID: <201412210458.sBL4wkfd080567@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201412210458.sBL4wkfd080567>