Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b23b025f authored by Ben Greear's avatar Ben Greear Committed by John W. Linville
Browse files

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: default avatarBen Greear <greearb@candelatech.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent cb8d61de
Loading
Loading
Loading
Loading
+7 −6
Original line number Original line Diff line number Diff line
@@ -655,8 +655,6 @@ struct tpt_led_trigger {
 *	well be on the operating channel
 *	well be on the operating channel
 * @SCAN_HW_SCANNING: The hardware is scanning for us, we have no way to
 * @SCAN_HW_SCANNING: The hardware is scanning for us, we have no way to
 *	determine if we are on the operating channel or not
 *	determine if we are on the operating channel or not
 * @SCAN_OFF_CHANNEL: We're off our operating channel for scanning,
 *	gets only set in conjunction with SCAN_SW_SCANNING
 * @SCAN_COMPLETED: Set for our scan work function when the driver reported
 * @SCAN_COMPLETED: Set for our scan work function when the driver reported
 *	that the scan completed.
 *	that the scan completed.
 * @SCAN_ABORTED: Set for our scan work function when the driver reported
 * @SCAN_ABORTED: Set for our scan work function when the driver reported
@@ -665,7 +663,6 @@ struct tpt_led_trigger {
enum {
enum {
	SCAN_SW_SCANNING,
	SCAN_SW_SCANNING,
	SCAN_HW_SCANNING,
	SCAN_HW_SCANNING,
	SCAN_OFF_CHANNEL,
	SCAN_COMPLETED,
	SCAN_COMPLETED,
	SCAN_ABORTED,
	SCAN_ABORTED,
};
};
@@ -1148,10 +1145,14 @@ void ieee80211_rx_bss_put(struct ieee80211_local *local,
			  struct ieee80211_bss *bss);
			  struct ieee80211_bss *bss);


/* off-channel helpers */
/* off-channel helpers */
void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local);
bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local);
void ieee80211_offchannel_stop_station(struct ieee80211_local *local);
void ieee80211_offchannel_enable_all_ps(struct ieee80211_local *local,
					bool tell_ap);
void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
				    bool offchannel_ps_enable);
void ieee80211_offchannel_return(struct ieee80211_local *local,
void ieee80211_offchannel_return(struct ieee80211_local *local,
				 bool enable_beaconing);
				 bool enable_beaconing,
				 bool offchannel_ps_disable);
void ieee80211_hw_roc_setup(struct ieee80211_local *local);
void ieee80211_hw_roc_setup(struct ieee80211_local *local);


/* interface handling */
/* interface handling */
+47 −6
Original line number Original line Diff line number Diff line
@@ -98,6 +98,41 @@ static void ieee80211_reconfig_filter(struct work_struct *work)
	ieee80211_configure_filter(local);
	ieee80211_configure_filter(local);
}
}


/*
 * Returns true if we are logically configured to be on
 * the operating channel AND the hardware-conf is currently
 * configured on the operating channel.  Compares channel-type
 * as well.
 */
bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local)
{
	struct ieee80211_channel *chan, *scan_chan;
	enum nl80211_channel_type channel_type;

	/* This logic needs to match logic in ieee80211_hw_config */
	if (local->scan_channel) {
		chan = local->scan_channel;
		channel_type = NL80211_CHAN_NO_HT;
	} else if (local->tmp_channel) {
		chan = scan_chan = local->tmp_channel;
		channel_type = local->tmp_channel_type;
	} else {
		chan = local->oper_channel;
		channel_type = local->_oper_channel_type;
	}

	if (chan != local->oper_channel ||
	    channel_type != local->_oper_channel_type)
		return false;

	/* Check current hardware-config against oper_channel. */
	if ((local->oper_channel != local->hw.conf.channel) ||
	    (local->_oper_channel_type != local->hw.conf.channel_type))
		return false;

	return true;
}

int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
{
{
	struct ieee80211_channel *chan, *scan_chan;
	struct ieee80211_channel *chan, *scan_chan;
@@ -110,21 +145,27 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)


	scan_chan = local->scan_channel;
	scan_chan = local->scan_channel;


	/* If this off-channel logic ever changes,  ieee80211_on_oper_channel
	 * may need to change as well.
	 */
	offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
	offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
	if (scan_chan) {
	if (scan_chan) {
		chan = scan_chan;
		chan = scan_chan;
		channel_type = NL80211_CHAN_NO_HT;
		channel_type = NL80211_CHAN_NO_HT;
		local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
	} else if (local->tmp_channel) {
	} else if (local->tmp_channel &&
		   local->oper_channel != local->tmp_channel) {
		chan = scan_chan = local->tmp_channel;
		chan = scan_chan = local->tmp_channel;
		channel_type = local->tmp_channel_type;
		channel_type = local->tmp_channel_type;
		local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
	} else {
	} else {
		chan = local->oper_channel;
		chan = local->oper_channel;
		channel_type = local->_oper_channel_type;
		channel_type = local->_oper_channel_type;
		local->hw.conf.flags &= ~IEEE80211_CONF_OFFCHANNEL;
	}
	}

	if (chan != local->oper_channel ||
	    channel_type != local->_oper_channel_type)
		local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
	else
		local->hw.conf.flags &= ~IEEE80211_CONF_OFFCHANNEL;

	offchannel_flag ^= local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
	offchannel_flag ^= local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;


	if (offchannel_flag || chan != local->hw.conf.channel ||
	if (offchannel_flag || chan != local->hw.conf.channel ||
@@ -231,7 +272,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,


	if (changed & BSS_CHANGED_BEACON_ENABLED) {
	if (changed & BSS_CHANGED_BEACON_ENABLED) {
		if (local->quiescing || !ieee80211_sdata_running(sdata) ||
		if (local->quiescing || !ieee80211_sdata_running(sdata) ||
		    test_bit(SCAN_SW_SCANNING, &local->scanning)) {
		    test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state)) {
			sdata->vif.bss_conf.enable_beacon = false;
			sdata->vif.bss_conf.enable_beacon = false;
		} else {
		} else {
			/*
			/*
+37 −31
Original line number Original line Diff line number Diff line
@@ -17,10 +17,14 @@
#include "driver-trace.h"
#include "driver-trace.h"


/*
/*
 * inform AP that we will go to sleep so that it will buffer the frames
 * Tell our hardware to disable PS.
 * while we scan
 * 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_local *local = sdata->local;
	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
	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);
		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
	}
	}


	if (!(local->offchannel_ps_enabled) ||
	if (tell_ap && (!local->offchannel_ps_enabled ||
	    !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
			!(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)))
		/*
		/*
		 * If power save was enabled, no need to send a nullfunc
		 * If power save was enabled, no need to send a nullfunc
		 * frame because AP knows that we are sleeping. But if the
		 * 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
		 * we are sleeping, let's just enable power save mode in
		 * hardware.
		 * 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;
		local->hw.conf.flags |= IEEE80211_CONF_PS;
		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
	} else if (local->hw.conf.dynamic_ps_timeout > 0) {
	} 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);
	ieee80211_sta_reset_conn_monitor(sdata);
}
}


void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local)
void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
				    bool offchannel_ps_enable)
{
{
	struct ieee80211_sub_if_data *sdata;
	struct ieee80211_sub_if_data *sdata;


	/*
	 * notify the AP about us leaving the channel and stop all
	 * STA interfaces.
	 */
	mutex_lock(&local->iflist_mtx);
	mutex_lock(&local->iflist_mtx);
	list_for_each_entry(sdata, &local->interfaces, list) {
	list_for_each_entry(sdata, &local->interfaces, list) {
		if (!ieee80211_sdata_running(sdata))
		if (!ieee80211_sdata_running(sdata))
			continue;
			continue;


		/* disable beaconing */
		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 ||
		if (sdata->vif.type == NL80211_IFTYPE_AP ||
		    sdata->vif.type == NL80211_IFTYPE_ADHOC ||
		    sdata->vif.type == NL80211_IFTYPE_ADHOC ||
		    sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
		    sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
			ieee80211_bss_info_change_notify(
			ieee80211_bss_info_change_notify(
				sdata, BSS_CHANGED_BEACON_ENABLED);
				sdata, BSS_CHANGED_BEACON_ENABLED);


		/*
		if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
		 * 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);
			netif_tx_stop_all_queues(sdata->dev);
			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);
	mutex_unlock(&local->iflist_mtx);
}
}


void ieee80211_offchannel_stop_station(struct ieee80211_local *local)
void ieee80211_offchannel_enable_all_ps(struct ieee80211_local *local,
					bool tell_ap)
{
{
	struct ieee80211_sub_if_data *sdata;
	struct ieee80211_sub_if_data *sdata;


	/*
	 * notify the AP about us leaving the channel and stop all STA interfaces
	 */
	mutex_lock(&local->iflist_mtx);
	mutex_lock(&local->iflist_mtx);
	list_for_each_entry(sdata, &local->interfaces, list) {
	list_for_each_entry(sdata, &local->interfaces, list) {
		if (!ieee80211_sdata_running(sdata))
		if (!ieee80211_sdata_running(sdata))
			continue;
			continue;


		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
		if (sdata->vif.type == NL80211_IFTYPE_STATION &&
			set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
		    sdata->u.mgd.associated)
			netif_tx_stop_all_queues(sdata->dev);
			ieee80211_offchannel_ps_enable(sdata, tell_ap);
			if (sdata->u.mgd.associated)
				ieee80211_offchannel_ps_enable(sdata);
		}
	}
	}
	mutex_unlock(&local->iflist_mtx);
	mutex_unlock(&local->iflist_mtx);
}
}


void ieee80211_offchannel_return(struct ieee80211_local *local,
void ieee80211_offchannel_return(struct ieee80211_local *local,
				 bool enable_beaconing)
				 bool enable_beaconing,
				 bool offchannel_ps_disable)
{
{
	struct ieee80211_sub_if_data *sdata;
	struct ieee80211_sub_if_data *sdata;


@@ -161,7 +166,8 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
			continue;
			continue;


		/* Tell AP we're back */
		/* 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)
			if (sdata->u.mgd.associated)
				ieee80211_offchannel_ps_disable(sdata);
				ieee80211_offchannel_ps_disable(sdata);
		}
		}
@@ -181,7 +187,7 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
			netif_tx_wake_all_queues(sdata->dev);
			netif_tx_wake_all_queues(sdata->dev);
		}
		}


		/* re-enable beaconing */
		/* Check to see if we should re-enable beaconing */
		if (enable_beaconing &&
		if (enable_beaconing &&
		    (sdata->vif.type == NL80211_IFTYPE_AP ||
		    (sdata->vif.type == NL80211_IFTYPE_AP ||
		     sdata->vif.type == NL80211_IFTYPE_ADHOC ||
		     sdata->vif.type == NL80211_IFTYPE_ADHOC ||
+3 −9
Original line number Original line Diff line number Diff line
@@ -409,16 +409,10 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
	if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN)))
	if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN)))
		return RX_CONTINUE;
		return RX_CONTINUE;


	if (test_bit(SCAN_HW_SCANNING, &local->scanning))
	if (test_bit(SCAN_HW_SCANNING, &local->scanning) ||
	    test_bit(SCAN_SW_SCANNING, &local->scanning))
		return ieee80211_scan_rx(rx->sdata, skb);
		return ieee80211_scan_rx(rx->sdata, skb);


	if (test_bit(SCAN_SW_SCANNING, &local->scanning)) {
		/* drop all the other packets during a software scan anyway */
		if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED)
			dev_kfree_skb(skb);
		return RX_QUEUED;
	}

	/* scanning finished during invoking of handlers */
	/* scanning finished during invoking of handlers */
	I802_DEBUG_INC(local->rx_handlers_drop_passive_scan);
	I802_DEBUG_INC(local->rx_handlers_drop_passive_scan);
	return RX_DROP_UNUSABLE;
	return RX_DROP_UNUSABLE;
@@ -2793,7 +2787,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
		local->dot11ReceivedFragmentCount++;
		local->dot11ReceivedFragmentCount++;


	if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
	if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
		     test_bit(SCAN_OFF_CHANNEL, &local->scanning)))
		     test_bit(SCAN_SW_SCANNING, &local->scanning)))
		status->rx_flags |= IEEE80211_RX_IN_SCAN;
		status->rx_flags |= IEEE80211_RX_IN_SCAN;


	if (ieee80211_is_mgmt(fc))
	if (ieee80211_is_mgmt(fc))
+63 −25
Original line number Original line Diff line number Diff line
@@ -212,6 +212,14 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
	if (bss)
	if (bss)
		ieee80211_rx_bss_put(sdata->local, bss);
		ieee80211_rx_bss_put(sdata->local, bss);


	/* If we are on-operating-channel, and this packet is for the
	 * current channel, pass the pkt on up the stack so that
	 * the rest of the stack can make use of it.
	 */
	if (ieee80211_cfg_on_oper_channel(sdata->local)
	    && (channel == sdata->local->oper_channel))
		return RX_CONTINUE;

	dev_kfree_skb(skb);
	dev_kfree_skb(skb);
	return RX_QUEUED;
	return RX_QUEUED;
}
}
@@ -293,15 +301,31 @@ static void __ieee80211_scan_completed_finish(struct ieee80211_hw *hw,
					      bool was_hw_scan)
					      bool was_hw_scan)
{
{
	struct ieee80211_local *local = hw_to_local(hw);
	struct ieee80211_local *local = hw_to_local(hw);
	bool on_oper_chan;
	bool enable_beacons = false;

	mutex_lock(&local->mtx);
	on_oper_chan = ieee80211_cfg_on_oper_channel(local);


	if (was_hw_scan || !on_oper_chan) {
		if (WARN_ON(local->scan_channel))
			local->scan_channel = NULL;
		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
	}

	if (!was_hw_scan) {
	if (!was_hw_scan) {
		bool on_oper_chan2;
		ieee80211_configure_filter(local);
		ieee80211_configure_filter(local);
		drv_sw_scan_complete(local);
		drv_sw_scan_complete(local);
		ieee80211_offchannel_return(local, true);
		on_oper_chan2 = ieee80211_cfg_on_oper_channel(local);
		/* We should always be on-channel at this point. */
		WARN_ON(!on_oper_chan2);
		if (on_oper_chan2 && (on_oper_chan != on_oper_chan2))
			enable_beacons = true;

		ieee80211_offchannel_return(local, enable_beacons, true);
	}
	}


	mutex_lock(&local->mtx);
	ieee80211_recalc_idle(local);
	ieee80211_recalc_idle(local);
	mutex_unlock(&local->mtx);
	mutex_unlock(&local->mtx);


@@ -341,13 +365,15 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
	 */
	 */
	drv_sw_scan_start(local);
	drv_sw_scan_start(local);


	ieee80211_offchannel_stop_beaconing(local);

	local->leave_oper_channel_time = 0;
	local->leave_oper_channel_time = 0;
	local->next_scan_state = SCAN_DECISION;
	local->next_scan_state = SCAN_DECISION;
	local->scan_channel_idx = 0;
	local->scan_channel_idx = 0;


	drv_flush(local, false);
	/* We always want to use off-channel PS, even if we
	 * are not really leaving oper-channel.  Don't
	 * tell the AP though, as long as we are on-channel.
	 */
	ieee80211_offchannel_enable_all_ps(local, false);


	ieee80211_configure_filter(local);
	ieee80211_configure_filter(local);


@@ -487,7 +513,21 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
	}
	}
	mutex_unlock(&local->iflist_mtx);
	mutex_unlock(&local->iflist_mtx);


	if (local->scan_channel) {
	next_chan = local->scan_req->channels[local->scan_channel_idx];

	if (ieee80211_cfg_on_oper_channel(local)) {
		/* We're currently on operating channel. */
		if ((next_chan == local->oper_channel) &&
		    (local->_oper_channel_type == NL80211_CHAN_NO_HT))
			/* We don't need to move off of operating channel. */
			local->next_scan_state = SCAN_SET_CHANNEL;
		else
			/*
			 * We do need to leave operating channel, as next
			 * scan is somewhere else.
			 */
			local->next_scan_state = SCAN_LEAVE_OPER_CHANNEL;
	} else {
		/*
		/*
		 * we're currently scanning a different channel, let's
		 * we're currently scanning a different channel, let's
		 * see if we can scan another channel without interfering
		 * see if we can scan another channel without interfering
@@ -503,7 +543,6 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
		 *
		 *
		 * Otherwise switch back to the operating channel.
		 * Otherwise switch back to the operating channel.
		 */
		 */
		next_chan = local->scan_req->channels[local->scan_channel_idx];


		bad_latency = time_after(jiffies +
		bad_latency = time_after(jiffies +
				ieee80211_scan_get_channel_time(next_chan),
				ieee80211_scan_get_channel_time(next_chan),
@@ -521,12 +560,6 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
			local->next_scan_state = SCAN_ENTER_OPER_CHANNEL;
			local->next_scan_state = SCAN_ENTER_OPER_CHANNEL;
		else
		else
			local->next_scan_state = SCAN_SET_CHANNEL;
			local->next_scan_state = SCAN_SET_CHANNEL;
	} else {
		/*
		 * we're on the operating channel currently, let's
		 * leave that channel now to scan another one
		 */
		local->next_scan_state = SCAN_LEAVE_OPER_CHANNEL;
	}
	}


	*next_delay = 0;
	*next_delay = 0;
@@ -535,9 +568,10 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local,
static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local,
						    unsigned long *next_delay)
						    unsigned long *next_delay)
{
{
	ieee80211_offchannel_stop_station(local);
	/* PS will already be in off-channel mode,

	 * we do that once at the beginning of scanning.
	__set_bit(SCAN_OFF_CHANNEL, &local->scanning);
	 */
	ieee80211_offchannel_stop_vifs(local, false);


	/*
	/*
	 * What if the nullfunc frames didn't arrive?
	 * What if the nullfunc frames didn't arrive?
@@ -560,15 +594,15 @@ static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *loca
{
{
	/* switch back to the operating channel */
	/* switch back to the operating channel */
	local->scan_channel = NULL;
	local->scan_channel = NULL;
	if (!ieee80211_cfg_on_oper_channel(local))
		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);


	/*
	/*
	 * Only re-enable station mode interface now; beaconing will be
	 * Re-enable vifs and beaconing.  Leave PS
	 * re-enabled once the full scan has been completed.
	 * in off-channel state..will put that back
	 * on-channel at the end of scanning.
	 */
	 */
	ieee80211_offchannel_return(local, false);
	ieee80211_offchannel_return(local, true, false);

	__clear_bit(SCAN_OFF_CHANNEL, &local->scanning);


	*next_delay = HZ / 5;
	*next_delay = HZ / 5;
	local->next_scan_state = SCAN_DECISION;
	local->next_scan_state = SCAN_DECISION;
@@ -584,6 +618,10 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
	chan = local->scan_req->channels[local->scan_channel_idx];
	chan = local->scan_req->channels[local->scan_channel_idx];


	local->scan_channel = chan;
	local->scan_channel = chan;

	/* Only call hw-config if we really need to change channels. */
	if ((chan != local->hw.conf.channel) ||
	    (local->hw.conf.channel_type != NL80211_CHAN_NO_HT))
		if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL))
		if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL))
			skip = 1;
			skip = 1;


Loading