@@ -868,6 +868,10 @@ struct ieee80211_rx_status {
* up for beacons and is able to transmit and receive the possible
* acknowledgement frames. Not to be confused with hardware specific
* wakeup/sleep states; the driver is responsible for that.
+ * @IEEE80211_PS_OFFCHANNEL: The hardware is fully awake and is able to
+ * transmit and receive frames, but the AP is asked to buffer frames
+ * as during powersave. This is used for temporarily leaving the
+ * operating channel.
* @IEEE80211_CONF_IDLE: The device is running, but idle; if the flag is set
* the driver should be prepared to handle configuration requests but
* may turn the device off as much as possible. Typically, this flag will
@@ -881,6 +885,7 @@ enum ieee80211_conf_flags {
IEEE80211_CONF_PS_MASK = (3<<1),
IEEE80211_PS_AWAKE = (0<<1),
IEEE80211_PS_DOZE = (1<<1),
+ IEEE80211_PS_OFFCHANNEL = (2<<1),
IEEE80211_CONF_IDLE = (1<<3),
IEEE80211_CONF_OFFCHANNEL = (1<<4),
};
@@ -1662,7 +1667,9 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
* %IEEE80211_HW_SUPPORTS_PS_DOZE clear to avoid being placed into a low-
* power state. %IEEE80211_HW_PS_NULLFUNC_STACK should be set if the
* hardware requires that mac80211 generate nullfunc frames when
- * transitioning between powersave modes.
+ * transitioning between powersave modes. The %IEEE80211_PS_DOZE and
+ * %IEEE80211_PS_OFFCHANNEL modes must be supported by all drivers, but for
+ * most hardware these states are equivalent.
*
* Hardware which supports a low-power "doze" state should set the
* %IEEE80211_HW_SUPPORTS_PS_DOZE hardware flag. This will make it possible
@@ -40,11 +40,11 @@ static bool ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
cancel_work_sync(&local->dynamic_ps_enable_work);
- if (ieee80211_conf_ps_mode(&local->hw.conf) == IEEE80211_PS_DOZE) {
+ if (ieee80211_conf_ps_mode(&local->hw.conf) == IEEE80211_PS_DOZE)
local->offchannel_ps_enabled = true;
- ieee80211_conf_set_ps_mode(&local->hw.conf, IEEE80211_PS_AWAKE);
- ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
- }
+
+ ieee80211_conf_set_ps_mode(&local->hw.conf, IEEE80211_PS_OFFCHANNEL);
+ ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
if (!local->offchannel_ps_enabled ||
!(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
@@ -57,6 +57,12 @@ static bool ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
* sent a null frame with power save disabled. So we need
* to send a new nullfunc frame to inform the AP that we
* are again sleeping.
+ *
+ * XXX: This should no longer be necessary with the off-
+ * channel PS state when the hw is creating the nullfunc
+ * frame, as hardware should have enough information to
+ * send the correct nullfunc frames. It remains to be seen
+ * whether or not this holds in practice.
*/
ret = ieee80211_send_nullfunc(local, sdata, 1);
@@ -68,9 +74,7 @@ static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
- if (!local->ps_sdata)
- ieee80211_send_nullfunc(local, sdata, 0);
- else if (local->offchannel_ps_enabled) {
+ if (local->offchannel_ps_enabled) {
/*
* In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware
* will send a nullfunc frame with the powersave bit set
@@ -84,21 +88,23 @@ static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
* we are sleeping, let's just enable power save mode in
* hardware.
*/
- /* TODO: Only set hardware if CONF_PS changed?
- * TODO: Should we set offchannel_ps_enabled to false?
+ /* TODO: Should we set offchannel_ps_enabled to false?
*/
ieee80211_conf_set_ps_mode(&local->hw.conf, IEEE80211_PS_DOZE);
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
- } else if (local->hw.conf.dynamic_ps_timeout > 0) {
+ } else {
+ ieee80211_conf_set_ps_mode(&local->hw.conf, IEEE80211_PS_AWAKE);
+ ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+ ieee80211_send_nullfunc(local, sdata, 0);
+
/*
* If the powersave mode was awake and the dynamic_ps_timer
* had been running before leaving the operating channel,
- * restart the timer now and send a nullfunc frame to inform
- * the AP that we are awake.
+ * restart the timer now.
*/
- ieee80211_send_nullfunc(local, sdata, 0);
- mod_timer(&local->dynamic_ps_timer, jiffies +
- msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
+ if (local->hw.conf.dynamic_ps_timeout > 0)
+ mod_timer(&local->dynamic_ps_timer, jiffies +
+ msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
}
ieee80211_sta_reset_beacon_monitor(sdata);
Add a new powersave state for off-channel operation and transition to the off-channel code to using this state. Signed-off-by: Seth Forshee <seth.forshee@canonical.com> --- include/net/mac80211.h | 9 ++++++++- net/mac80211/offchannel.c | 36 +++++++++++++++++++++--------------- 2 files changed, 29 insertions(+), 16 deletions(-)