|
@@ -227,82 +227,9 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * inform AP that we will go to sleep so that it will buffer the frames
|
|
|
- * while we scan
|
|
|
- */
|
|
|
-static void ieee80211_scan_ps_enable(struct ieee80211_sub_if_data *sdata)
|
|
|
-{
|
|
|
- struct ieee80211_local *local = sdata->local;
|
|
|
-
|
|
|
- local->scan_ps_enabled = false;
|
|
|
-
|
|
|
- /* FIXME: what to do when local->pspolling is true? */
|
|
|
-
|
|
|
- del_timer_sync(&local->dynamic_ps_timer);
|
|
|
- cancel_work_sync(&local->dynamic_ps_enable_work);
|
|
|
-
|
|
|
- if (local->hw.conf.flags & IEEE80211_CONF_PS) {
|
|
|
- local->scan_ps_enabled = true;
|
|
|
- local->hw.conf.flags &= ~IEEE80211_CONF_PS;
|
|
|
- ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
|
|
|
- }
|
|
|
-
|
|
|
- if (!(local->scan_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
|
|
|
- * hardware is creating the nullfunc frame for power save
|
|
|
- * status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not
|
|
|
- * enabled) and power save was enabled, the firmware just
|
|
|
- * 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.
|
|
|
- */
|
|
|
- ieee80211_send_nullfunc(local, sdata, 1);
|
|
|
-}
|
|
|
-
|
|
|
-/* inform AP that we are awake again, unless power save is enabled */
|
|
|
-static void ieee80211_scan_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->scan_ps_enabled) {
|
|
|
- /*
|
|
|
- * 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.
|
|
|
- */
|
|
|
- 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.
|
|
|
- */
|
|
|
- ieee80211_send_nullfunc(local, sdata, 0);
|
|
|
- mod_timer(&local->dynamic_ps_timer, jiffies +
|
|
|
- msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
|
|
|
{
|
|
|
struct ieee80211_local *local = hw_to_local(hw);
|
|
|
- struct ieee80211_sub_if_data *sdata;
|
|
|
bool was_hw_scan;
|
|
|
|
|
|
mutex_lock(&local->scan_mtx);
|
|
@@ -351,28 +278,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
|
|
|
|
|
|
drv_sw_scan_complete(local);
|
|
|
|
|
|
- mutex_lock(&local->iflist_mtx);
|
|
|
- list_for_each_entry(sdata, &local->interfaces, list) {
|
|
|
- if (!ieee80211_sdata_running(sdata))
|
|
|
- continue;
|
|
|
-
|
|
|
- /* Tell AP we're back */
|
|
|
- if (sdata->vif.type == NL80211_IFTYPE_STATION) {
|
|
|
- if (sdata->u.mgd.associated) {
|
|
|
- ieee80211_scan_ps_disable(sdata);
|
|
|
- netif_wake_queue(sdata->dev);
|
|
|
- }
|
|
|
- } else
|
|
|
- netif_wake_queue(sdata->dev);
|
|
|
-
|
|
|
- /* re-enable 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);
|
|
|
- }
|
|
|
- mutex_unlock(&local->iflist_mtx);
|
|
|
+ ieee80211_offchannel_return(local, true);
|
|
|
|
|
|
done:
|
|
|
ieee80211_recalc_idle(local);
|
|
@@ -384,8 +290,6 @@ EXPORT_SYMBOL(ieee80211_scan_completed);
|
|
|
|
|
|
static int ieee80211_start_sw_scan(struct ieee80211_local *local)
|
|
|
{
|
|
|
- struct ieee80211_sub_if_data *sdata;
|
|
|
-
|
|
|
/*
|
|
|
* Hardware/driver doesn't support hw_scan, so use software
|
|
|
* scanning instead. First send a nullfunc frame with power save
|
|
@@ -401,26 +305,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
|
|
|
*/
|
|
|
drv_sw_scan_start(local);
|
|
|
|
|
|
- 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 the scan state machine
|
|
|
- */
|
|
|
- if (sdata->vif.type != NL80211_IFTYPE_STATION)
|
|
|
- netif_stop_queue(sdata->dev);
|
|
|
- }
|
|
|
- mutex_unlock(&local->iflist_mtx);
|
|
|
+ ieee80211_offchannel_stop_beaconing(local);
|
|
|
|
|
|
local->next_scan_state = SCAN_DECISION;
|
|
|
local->scan_channel_idx = 0;
|
|
@@ -568,23 +453,7 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
|
|
|
static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local,
|
|
|
unsigned long *next_delay)
|
|
|
{
|
|
|
- struct ieee80211_sub_if_data *sdata;
|
|
|
-
|
|
|
- /*
|
|
|
- * 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) {
|
|
|
- netif_stop_queue(sdata->dev);
|
|
|
- if (sdata->u.mgd.associated)
|
|
|
- ieee80211_scan_ps_enable(sdata);
|
|
|
- }
|
|
|
- }
|
|
|
- mutex_unlock(&local->iflist_mtx);
|
|
|
+ ieee80211_offchannel_stop_station(local);
|
|
|
|
|
|
__set_bit(SCAN_OFF_CHANNEL, &local->scanning);
|
|
|
|
|
@@ -604,28 +473,15 @@ static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *loca
|
|
|
static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local,
|
|
|
unsigned long *next_delay)
|
|
|
{
|
|
|
- struct ieee80211_sub_if_data *sdata = local->scan_sdata;
|
|
|
-
|
|
|
/* switch back to the operating channel */
|
|
|
local->scan_channel = NULL;
|
|
|
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
|
|
|
|
|
|
/*
|
|
|
- * notify the AP about us being back and restart all STA interfaces
|
|
|
+ * Only re-enable station mode interface now; beaconing will be
|
|
|
+ * re-enabled once the full scan has been completed.
|
|
|
*/
|
|
|
- mutex_lock(&local->iflist_mtx);
|
|
|
- list_for_each_entry(sdata, &local->interfaces, list) {
|
|
|
- if (!ieee80211_sdata_running(sdata))
|
|
|
- continue;
|
|
|
-
|
|
|
- /* Tell AP we're back */
|
|
|
- if (sdata->vif.type == NL80211_IFTYPE_STATION) {
|
|
|
- if (sdata->u.mgd.associated)
|
|
|
- ieee80211_scan_ps_disable(sdata);
|
|
|
- netif_wake_queue(sdata->dev);
|
|
|
- }
|
|
|
- }
|
|
|
- mutex_unlock(&local->iflist_mtx);
|
|
|
+ ieee80211_offchannel_return(local, false);
|
|
|
|
|
|
__clear_bit(SCAN_OFF_CHANNEL, &local->scanning);
|
|
|
|