mac80211: Inform AP when returning operating channel

Because we can miss AP wakeup (beacon) while scanning other channels,
it's better go into wakeup state and inform the AP of that upon
returning to the operating channel, rather than staying asleep and
waiting for the next TIM indicating traffic for us.

This saves precious time, especially when we only have 200ms inter-
scan period for monitoring the active connection.

Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
Link: https://lore.kernel.org/r/1593420923-26668-1-git-send-email-loic.poulain@linaro.org
[rewrite commit message a bit]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Loic Poulain 2020-06-29 10:55:23 +02:00 committed by Johannes Berg
parent 0675c285ea
commit dba0491f00
2 changed files with 9 additions and 30 deletions

View file

@ -1376,7 +1376,6 @@ struct ieee80211_local {
*/
bool pspolling;
bool offchannel_ps_enabled;
/*
* PS can only be enabled when we have exactly one managed
* interface (and monitors) in PS, this then points there.

View file

@ -26,8 +26,7 @@ static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
local->offchannel_ps_enabled = false;
bool offchannel_ps_enabled = false;
/* FIXME: what to do when local->pspolling is true? */
@ -38,12 +37,12 @@ static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
cancel_work_sync(&local->dynamic_ps_enable_work);
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
local->offchannel_ps_enabled = true;
offchannel_ps_enabled = true;
local->hw.conf.flags &= ~IEEE80211_CONF_PS;
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
}
if (!local->offchannel_ps_enabled ||
if (!offchannel_ps_enabled ||
!ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK))
/*
* If power save was enabled, no need to send a nullfunc
@ -58,38 +57,19 @@ static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
ieee80211_send_nullfunc(local, sdata, true);
}
/* inform AP that we are awake again, unless power save is enabled */
/* inform AP that we are awake again */
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, false);
else if (local->offchannel_ps_enabled) {
else if (local->hw.conf.dynamic_ps_timeout > 0) {
/*
* In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware
* will send a nullfunc frame with the powersave bit set
* even though the AP already knows that we are sleeping.
* This could be avoided by sending a null frame with power
* save bit disabled before enabling the power save, but
* this doesn't gain anything.
*
* When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need
* to send a nullfunc frame because AP already knows that
* 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?
*/
local->hw.conf.flags |= IEEE80211_CONF_PS;
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
} else if (local->hw.conf.dynamic_ps_timeout > 0) {
/*
* If IEEE80211_CONF_PS was not set 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.
* 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 so that AP sends
* the buffered packets (if any).
*/
ieee80211_send_nullfunc(local, sdata, false);
mod_timer(&local->dynamic_ps_timer, jiffies +