mac80211: Optimize scans on current operating channel.
This should decrease un-necessary flushes, on/off channel work, and channel changes in cases where the only scanned channel is the current operating channel. * Removes SCAN_OFF_CHANNEL flag, uses SDATA_STATE_OFFCHANNEL and is-scanning flags instead. * Add helper method to determine if we are currently configured for the operating channel. * Do no blindly go off/on channel in work.c Instead, only call appropriate on/off code when we really need to change channels. Always enable offchannel-ps mode when starting work, and disable it when we are done. * Consolidate ieee80211_offchannel_stop_station and ieee80211_offchannel_stop_beaconing, call it ieee80211_offchannel_stop_vifs instead. * Accept non-beacon frames when scanning on operating channel. * Scan state machine optimized to minimize on/off channel transitions. Also, when going on-channel, go ahead and re-enable beaconing. We're going to be there for 200ms, so seems like some useful beaconing could happen. Always enable offchannel-ps mode when starting software scan, and disable it when we are done. * Grab local->mtx earlier in __ieee80211_scan_completed_finish so that we are protected when calling hw_config(), etc. * Pass probe-responses up the stack if scanning on local channel, so that mlme can take a look. Signed-off-by: Ben Greear <greearb@candelatech.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
committed by
John W. Linville
parent
cb8d61de2d
commit
b23b025fe2
@@ -17,10 +17,14 @@
|
||||
#include "driver-trace.h"
|
||||
|
||||
/*
|
||||
* inform AP that we will go to sleep so that it will buffer the frames
|
||||
* while we scan
|
||||
* Tell our hardware to disable PS.
|
||||
* Optionally inform AP that we will go to sleep so that it will buffer
|
||||
* the frames while we are doing off-channel work. This is optional
|
||||
* because we *may* be doing work on-operating channel, and want our
|
||||
* hardware unconditionally awake, but still let the AP send us normal frames.
|
||||
*/
|
||||
static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
|
||||
static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata,
|
||||
bool tell_ap)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
@@ -41,8 +45,8 @@ static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
|
||||
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
|
||||
}
|
||||
|
||||
if (!(local->offchannel_ps_enabled) ||
|
||||
!(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
|
||||
if (tell_ap && (!local->offchannel_ps_enabled ||
|
||||
!(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)))
|
||||
/*
|
||||
* If power save was enabled, no need to send a nullfunc
|
||||
* frame because AP knows that we are sleeping. But if the
|
||||
@@ -77,6 +81,9 @@ 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?
|
||||
*/
|
||||
local->hw.conf.flags |= IEEE80211_CONF_PS;
|
||||
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
|
||||
} else if (local->hw.conf.dynamic_ps_timeout > 0) {
|
||||
@@ -95,63 +102,61 @@ static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
|
||||
ieee80211_sta_reset_conn_monitor(sdata);
|
||||
}
|
||||
|
||||
void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
continue;
|
||||
|
||||
/* disable beaconing */
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||
sdata->vif.type == NL80211_IFTYPE_ADHOC ||
|
||||
sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
|
||||
ieee80211_bss_info_change_notify(
|
||||
sdata, BSS_CHANGED_BEACON_ENABLED);
|
||||
|
||||
/*
|
||||
* only handle non-STA interfaces here, STA interfaces
|
||||
* are handled in ieee80211_offchannel_stop_station(),
|
||||
* e.g., from the background scan state machine.
|
||||
*
|
||||
* In addition, do not stop monitor interface to allow it to be
|
||||
* used from user space controlled off-channel operations.
|
||||
*/
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
|
||||
sdata->vif.type != NL80211_IFTYPE_MONITOR) {
|
||||
set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
|
||||
netif_tx_stop_all_queues(sdata->dev);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
}
|
||||
|
||||
void ieee80211_offchannel_stop_station(struct ieee80211_local *local)
|
||||
void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
|
||||
bool offchannel_ps_enable)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
/*
|
||||
* notify the AP about us leaving the channel and stop all STA interfaces
|
||||
* notify the AP about us leaving the channel and stop all
|
||||
* STA interfaces.
|
||||
*/
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
continue;
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
|
||||
if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
|
||||
set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
|
||||
|
||||
/* Check to see if we should disable beaconing. */
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||
sdata->vif.type == NL80211_IFTYPE_ADHOC ||
|
||||
sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
|
||||
ieee80211_bss_info_change_notify(
|
||||
sdata, BSS_CHANGED_BEACON_ENABLED);
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
|
||||
netif_tx_stop_all_queues(sdata->dev);
|
||||
if (sdata->u.mgd.associated)
|
||||
ieee80211_offchannel_ps_enable(sdata);
|
||||
if (offchannel_ps_enable &&
|
||||
(sdata->vif.type == NL80211_IFTYPE_STATION) &&
|
||||
sdata->u.mgd.associated)
|
||||
ieee80211_offchannel_ps_enable(sdata, true);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
}
|
||||
|
||||
void ieee80211_offchannel_enable_all_ps(struct ieee80211_local *local,
|
||||
bool tell_ap)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
continue;
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
sdata->u.mgd.associated)
|
||||
ieee80211_offchannel_ps_enable(sdata, tell_ap);
|
||||
}
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
}
|
||||
|
||||
void ieee80211_offchannel_return(struct ieee80211_local *local,
|
||||
bool enable_beaconing)
|
||||
bool enable_beaconing,
|
||||
bool offchannel_ps_disable)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
@@ -161,7 +166,8 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
|
||||
continue;
|
||||
|
||||
/* Tell AP we're back */
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
|
||||
if (offchannel_ps_disable &&
|
||||
sdata->vif.type == NL80211_IFTYPE_STATION) {
|
||||
if (sdata->u.mgd.associated)
|
||||
ieee80211_offchannel_ps_disable(sdata);
|
||||
}
|
||||
@@ -181,7 +187,7 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
|
||||
netif_tx_wake_all_queues(sdata->dev);
|
||||
}
|
||||
|
||||
/* re-enable beaconing */
|
||||
/* Check to see if we should re-enable beaconing */
|
||||
if (enable_beaconing &&
|
||||
(sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||
sdata->vif.type == NL80211_IFTYPE_ADHOC ||
|
||||
|
Reference in New Issue
Block a user