Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Loic Poulain and committed by
Johannes Berg
dba0491f 0675c285

+9 -30
-1
net/mac80211/ieee80211_i.h
··· 1376 1376 */ 1377 1377 1378 1378 bool pspolling; 1379 - bool offchannel_ps_enabled; 1380 1379 /* 1381 1380 * PS can only be enabled when we have exactly one managed 1382 1381 * interface (and monitors) in PS, this then points there.
+9 -29
net/mac80211/offchannel.c
··· 26 26 { 27 27 struct ieee80211_local *local = sdata->local; 28 28 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 29 - 30 - local->offchannel_ps_enabled = false; 29 + bool offchannel_ps_enabled = false; 31 30 32 31 /* FIXME: what to do when local->pspolling is true? */ 33 32 ··· 37 38 cancel_work_sync(&local->dynamic_ps_enable_work); 38 39 39 40 if (local->hw.conf.flags & IEEE80211_CONF_PS) { 40 - local->offchannel_ps_enabled = true; 41 + offchannel_ps_enabled = true; 41 42 local->hw.conf.flags &= ~IEEE80211_CONF_PS; 42 43 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); 43 44 } 44 45 45 - if (!local->offchannel_ps_enabled || 46 + if (!offchannel_ps_enabled || 46 47 !ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK)) 47 48 /* 48 49 * If power save was enabled, no need to send a nullfunc ··· 57 58 ieee80211_send_nullfunc(local, sdata, true); 58 59 } 59 60 60 - /* inform AP that we are awake again, unless power save is enabled */ 61 + /* inform AP that we are awake again */ 61 62 static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata) 62 63 { 63 64 struct ieee80211_local *local = sdata->local; 64 65 65 66 if (!local->ps_sdata) 66 67 ieee80211_send_nullfunc(local, sdata, false); 67 - else if (local->offchannel_ps_enabled) { 68 + else if (local->hw.conf.dynamic_ps_timeout > 0) { 68 69 /* 69 - * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware 70 - * will send a nullfunc frame with the powersave bit set 71 - * even though the AP already knows that we are sleeping. 72 - * This could be avoided by sending a null frame with power 73 - * save bit disabled before enabling the power save, but 74 - * this doesn't gain anything. 75 - * 76 - * When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need 77 - * to send a nullfunc frame because AP already knows that 78 - * we are sleeping, let's just enable power save mode in 79 - * hardware. 80 - */ 81 - /* TODO: Only set hardware if CONF_PS changed? 82 - * TODO: Should we set offchannel_ps_enabled to false? 83 - */ 84 - local->hw.conf.flags |= IEEE80211_CONF_PS; 85 - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); 86 - } else if (local->hw.conf.dynamic_ps_timeout > 0) { 87 - /* 88 - * If IEEE80211_CONF_PS was not set and the dynamic_ps_timer 89 - * had been running before leaving the operating channel, 90 - * restart the timer now and send a nullfunc frame to inform 91 - * the AP that we are awake. 70 + * the dynamic_ps_timer had been running before leaving the 71 + * operating channel, restart the timer now and send a nullfunc 72 + * frame to inform the AP that we are awake so that AP sends 73 + * the buffered packets (if any). 92 74 */ 93 75 ieee80211_send_nullfunc(local, sdata, false); 94 76 mod_timer(&local->dynamic_ps_timer, jiffies +