[kernel/f16] Apply patch to revert mac80211 scan optimizations (rhbz #731365)

Josh Boyer jwboyer at fedoraproject.org
Thu Dec 1 14:13:14 UTC 2011


commit 67de50b811ecec877c8ca1a9309f0567141b9269
Author: Josh Boyer <jwboyer at redhat.com>
Date:   Thu Dec 1 09:10:14 2011 -0500

    Apply patch to revert mac80211 scan optimizations (rhbz #731365)

 kernel.spec                             |   11 +-
 mac80211_offchannel_rework_revert.patch |  594 +++++++++++++++++++++++++++++++
 2 files changed, 604 insertions(+), 1 deletions(-)
---
diff --git a/kernel.spec b/kernel.spec
index d60e469..ddef925 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -54,7 +54,7 @@ Summary: The Linux kernel
 # For non-released -rc kernels, this will be appended after the rcX and
 # gitX tags, so a 3 here would become part of release "0.rcX.gitX.3"
 #
-%global baserelease 3
+%global baserelease 4
 %global fedora_build %{baserelease}
 
 # base_sublevel is the kernel version we're starting with and patching
@@ -794,6 +794,9 @@ Patch21101: hpsa-add-irqf-shared.patch
 #rhbz 755154
 Patch21200: rtlwifi-fix-lps_lock-deadlock.patch
 
+#rhbz 731365
+Patch21220: mac80211_offchannel_rework_revert.patch
+
 %endif
 
 BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root
@@ -1457,6 +1460,9 @@ ApplyPatch hpsa-add-irqf-shared.patch
 #rhbz 755154
 ApplyPatch rtlwifi-fix-lps_lock-deadlock.patch
 
+#rhbz 731365
+ApplyPatch mac80211_offchannel_rework_revert.patch
+
 # END OF PATCH APPLICATIONS
 
 %endif
@@ -2188,6 +2194,9 @@ fi
 # and build.
 
 %changelog
+* Thu Dec 01 2011 Josh Boyer <jwboyer at redhat.com>
+- Apply patch to revert mac80211 scan optimizations (rhbz #731365)
+
 * Wed Nov 30 2011 Josh Boyer <jwboyer at redhat.com>
 - Include commit 3940d6185 from JJ Ding in elantech.patch
 
diff --git a/mac80211_offchannel_rework_revert.patch b/mac80211_offchannel_rework_revert.patch
new file mode 100644
index 0000000..8597997
--- /dev/null
+++ b/mac80211_offchannel_rework_revert.patch
@@ -0,0 +1,594 @@
+diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
+index 9fab144..4f8cf7f 100644
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -694,6 +694,8 @@ struct tpt_led_trigger {
+  *	well be on the operating channel
+  * @SCAN_HW_SCANNING: The hardware is scanning for us, we have no way to
+  *	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
+  *	that the scan completed.
+  * @SCAN_ABORTED: Set for our scan work function when the driver reported
+@@ -702,6 +704,7 @@ struct tpt_led_trigger {
+ enum {
+ 	SCAN_SW_SCANNING,
+ 	SCAN_HW_SCANNING,
++	SCAN_OFF_CHANNEL,
+ 	SCAN_COMPLETED,
+ 	SCAN_ABORTED,
+ };
+@@ -1197,14 +1200,10 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata);
+ void ieee80211_sched_scan_stopped_work(struct work_struct *work);
+ 
+ /* off-channel helpers */
+-bool ieee80211_cfg_on_oper_channel(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_stop_beaconing(struct ieee80211_local *local);
++void ieee80211_offchannel_stop_station(struct ieee80211_local *local);
+ void ieee80211_offchannel_return(struct ieee80211_local *local,
+-				 bool enable_beaconing,
+-				 bool offchannel_ps_disable);
++				 bool enable_beaconing);
+ void ieee80211_hw_roc_setup(struct ieee80211_local *local);
+ 
+ /* interface handling */
+diff --git a/net/mac80211/main.c b/net/mac80211/main.c
+index acb4423..2d607e5 100644
+--- a/net/mac80211/main.c
++++ b/net/mac80211/main.c
+@@ -92,47 +92,6 @@ static void ieee80211_reconfig_filter(struct work_struct *work)
+ 	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;
+-		/* If scanning on oper channel, use whatever channel-type
+-		 * is currently in use.
+-		 */
+-		if (chan == local->oper_channel)
+-			channel_type = local->_oper_channel_type;
+-		else
+-			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)
+ {
+ 	struct ieee80211_channel *chan, *scan_chan;
+@@ -145,9 +104,6 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
+ 
+ 	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;
+ 	if (scan_chan) {
+ 		chan = scan_chan;
+@@ -158,19 +114,17 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
+ 			channel_type = local->_oper_channel_type;
+ 		else
+ 			channel_type = NL80211_CHAN_NO_HT;
+-	} else if (local->tmp_channel) {
++		local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
++	} else if (local->tmp_channel &&
++		   local->oper_channel != local->tmp_channel) {
+ 		chan = scan_chan = local->tmp_channel;
+ 		channel_type = local->tmp_channel_type;
++		local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
+ 	} else {
+ 		chan = local->oper_channel;
+ 		channel_type = local->_oper_channel_type;
+-	}
+-
+-	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;
+ 
+@@ -279,7 +233,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
+ 
+ 	if (changed & BSS_CHANGED_BEACON_ENABLED) {
+ 		if (local->quiescing || !ieee80211_sdata_running(sdata) ||
+-		    test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state)) {
++		    test_bit(SCAN_SW_SCANNING, &local->scanning)) {
+ 			sdata->vif.bss_conf.enable_beacon = false;
+ 		} else {
+ 			/*
+diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
+index 13427b1..b4e5267 100644
+--- a/net/mac80211/offchannel.c
++++ b/net/mac80211/offchannel.c
+@@ -17,14 +17,10 @@
+ #include "driver-trace.h"
+ 
+ /*
+- * 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.
++ * inform AP that we will go to sleep so that it will buffer the frames
++ * while we scan
+  */
+-static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata,
+-					   bool tell_ap)
++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;
+@@ -45,8 +41,8 @@ static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata,
+ 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+ 	}
+ 
+-	if (tell_ap && (!local->offchannel_ps_enabled ||
+-			!(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)))
++	if (!(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
+@@ -81,9 +77,6 @@ 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) {
+@@ -102,61 +95,63 @@ static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
+ 	ieee80211_sta_reset_conn_monitor(sdata);
+ }
+ 
+-void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
+-				    bool offchannel_ps_enable)
++void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local)
+ {
+ 	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_MONITOR)
+-			set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
+-
+-		/* Check to see if we should disable beaconing. */
++		/* 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) {
++		/*
++		 * 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);
+-			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)
++void ieee80211_offchannel_stop_station(struct ieee80211_local *local)
+ {
+ 	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 &&
+-		    sdata->u.mgd.associated)
+-			ieee80211_offchannel_ps_enable(sdata, tell_ap);
++		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
++			set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
++			netif_tx_stop_all_queues(sdata->dev);
++			if (sdata->u.mgd.associated)
++				ieee80211_offchannel_ps_enable(sdata);
++		}
+ 	}
+ 	mutex_unlock(&local->iflist_mtx);
+ }
+ 
+ void ieee80211_offchannel_return(struct ieee80211_local *local,
+-				 bool enable_beaconing,
+-				 bool offchannel_ps_disable)
++				 bool enable_beaconing)
+ {
+ 	struct ieee80211_sub_if_data *sdata;
+ 
+@@ -166,8 +161,7 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
+ 			continue;
+ 
+ 		/* Tell AP we're back */
+-		if (offchannel_ps_disable &&
+-		    sdata->vif.type == NL80211_IFTYPE_STATION) {
++		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+ 			if (sdata->u.mgd.associated)
+ 				ieee80211_offchannel_ps_disable(sdata);
+ 		}
+@@ -187,7 +181,7 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
+ 			netif_tx_wake_all_queues(sdata->dev);
+ 		}
+ 
+-		/* Check to see if we should re-enable beaconing */
++		/* re-enable beaconing */
+ 		if (enable_beaconing &&
+ 		    (sdata->vif.type == NL80211_IFTYPE_AP ||
+ 		     sdata->vif.type == NL80211_IFTYPE_ADHOC ||
+diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
+index fe2c2a7..b46880e 100644
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -417,10 +417,16 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
+ 		return RX_CONTINUE;
+ 
+ 	if (test_bit(SCAN_HW_SCANNING, &local->scanning) ||
+-	    test_bit(SCAN_SW_SCANNING, &local->scanning) ||
+ 	    local->sched_scanning)
+ 		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 */
+ 	I802_DEBUG_INC(local->rx_handlers_drop_passive_scan);
+ 	return RX_DROP_UNUSABLE;
+@@ -2771,7 +2777,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
+ 		local->dot11ReceivedFragmentCount++;
+ 
+ 	if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
+-		     test_bit(SCAN_SW_SCANNING, &local->scanning)))
++		     test_bit(SCAN_OFF_CHANNEL, &local->scanning)))
+ 		status->rx_flags |= IEEE80211_RX_IN_SCAN;
+ 
+ 	if (ieee80211_is_mgmt(fc))
+diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
+index 6f09eca..2ba4977 100644
+--- a/net/mac80211/scan.c
++++ b/net/mac80211/scan.c
+@@ -212,14 +212,6 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
+ 	if (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);
+ 	return RX_QUEUED;
+ }
+@@ -262,8 +254,6 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
+ 				       bool was_hw_scan)
+ {
+ 	struct ieee80211_local *local = hw_to_local(hw);
+-	bool on_oper_chan;
+-	bool enable_beacons = false;
+ 
+ 	lockdep_assert_held(&local->mtx);
+ 
+@@ -296,25 +286,11 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
+ 	local->scanning = 0;
+ 	local->scan_channel = NULL;
+ 
+-	on_oper_chan = ieee80211_cfg_on_oper_channel(local);
+-
+-	if (was_hw_scan || !on_oper_chan)
+-		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+-	else
+-		/* Set power back to normal operating levels. */
+-		ieee80211_hw_config(local, 0);
+-
++	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+ 	if (!was_hw_scan) {
+-		bool on_oper_chan2;
+ 		ieee80211_configure_filter(local);
+ 		drv_sw_scan_complete(local);
+-		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);
++		ieee80211_offchannel_return(local, true);
+ 	}
+ 
+ 	ieee80211_recalc_idle(local);
+@@ -355,15 +331,13 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
+ 	 */
+ 	drv_sw_scan_start(local);
+ 
++	ieee80211_offchannel_stop_beaconing(local);
++
+ 	local->leave_oper_channel_time = 0;
+ 	local->next_scan_state = SCAN_DECISION;
+ 	local->scan_channel_idx = 0;
+ 
+-	/* 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);
++	drv_flush(local, false);
+ 
+ 	ieee80211_configure_filter(local);
+ 
+@@ -506,20 +480,7 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
+ 	}
+ 	mutex_unlock(&local->iflist_mtx);
+ 
+-	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)
+-			/* 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 {
++	if (local->scan_channel) {
+ 		/*
+ 		 * we're currently scanning a different channel, let's
+ 		 * see if we can scan another channel without interfering
+@@ -535,6 +496,7 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
+ 		 *
+ 		 * Otherwise switch back to the operating channel.
+ 		 */
++		next_chan = local->scan_req->channels[local->scan_channel_idx];
+ 
+ 		bad_latency = time_after(jiffies +
+ 				ieee80211_scan_get_channel_time(next_chan),
+@@ -552,6 +514,12 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
+ 			local->next_scan_state = SCAN_ENTER_OPER_CHANNEL;
+ 		else
+ 			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;
+@@ -560,10 +528,9 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
+ static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local,
+ 						    unsigned long *next_delay)
+ {
+-	/* PS will already be in off-channel mode,
+-	 * we do that once at the beginning of scanning.
+-	 */
+-	ieee80211_offchannel_stop_vifs(local, false);
++	ieee80211_offchannel_stop_station(local);
++
++	__set_bit(SCAN_OFF_CHANNEL, &local->scanning);
+ 
+ 	/*
+ 	 * What if the nullfunc frames didn't arrive?
+@@ -586,15 +553,15 @@ static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *loca
+ {
+ 	/* switch back to the operating channel */
+ 	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);
+ 
+ 	/*
+-	 * Re-enable vifs and beaconing.  Leave PS
+-	 * in off-channel state..will put that back
+-	 * on-channel at the end of scanning.
++	 * Only re-enable station mode interface now; beaconing will be
++	 * re-enabled once the full scan has been completed.
+ 	 */
+-	ieee80211_offchannel_return(local, true, false);
++	ieee80211_offchannel_return(local, false);
++
++	__clear_bit(SCAN_OFF_CHANNEL, &local->scanning);
+ 
+ 	*next_delay = HZ / 5;
+ 	local->next_scan_state = SCAN_DECISION;
+diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
+index 8cb0d2d..54ea022 100644
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -258,8 +258,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
+ 	if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED))
+ 		return TX_CONTINUE;
+ 
+-	if (unlikely(test_bit(SCAN_SW_SCANNING, &tx->local->scanning)) &&
+-	    test_bit(SDATA_STATE_OFFCHANNEL, &tx->sdata->state) &&
++	if (unlikely(test_bit(SCAN_OFF_CHANNEL, &tx->local->scanning)) &&
+ 	    !ieee80211_is_probe_req(hdr->frame_control) &&
+ 	    !ieee80211_is_nullfunc(hdr->frame_control))
+ 		/*
+diff --git a/net/mac80211/work.c b/net/mac80211/work.c
+index 7737f20..b76bf33 100644
+--- a/net/mac80211/work.c
++++ b/net/mac80211/work.c
+@@ -901,26 +901,6 @@ static bool ieee80211_work_ct_coexists(enum nl80211_channel_type wk_ct,
+ 	return false;
+ }
+ 
+-static enum nl80211_channel_type
+-ieee80211_calc_ct(enum nl80211_channel_type wk_ct,
+-		  enum nl80211_channel_type oper_ct)
+-{
+-	switch (wk_ct) {
+-	case NL80211_CHAN_NO_HT:
+-		return oper_ct;
+-	case NL80211_CHAN_HT20:
+-		if (oper_ct != NL80211_CHAN_NO_HT)
+-			return oper_ct;
+-		return wk_ct;
+-	case NL80211_CHAN_HT40MINUS:
+-	case NL80211_CHAN_HT40PLUS:
+-		return wk_ct;
+-	}
+-	WARN_ON(1); /* shouldn't get here */
+-	return wk_ct;
+-}
+-
+-
+ static void ieee80211_work_timer(unsigned long data)
+ {
+ 	struct ieee80211_local *local = (void *) data;
+@@ -971,52 +951,18 @@ static void ieee80211_work_work(struct work_struct *work)
+ 		}
+ 
+ 		if (!started && !local->tmp_channel) {
+-			bool on_oper_chan;
+-			bool tmp_chan_changed = false;
+-			bool on_oper_chan2;
+-			enum nl80211_channel_type wk_ct;
+-			on_oper_chan = ieee80211_cfg_on_oper_channel(local);
+-
+-			/* Work with existing channel type if possible. */
+-			wk_ct = wk->chan_type;
+-			if (wk->chan == local->hw.conf.channel)
+-				wk_ct = ieee80211_calc_ct(wk->chan_type,
+-						local->hw.conf.channel_type);
+-
+-			if (local->tmp_channel)
+-				if ((local->tmp_channel != wk->chan) ||
+-				    (local->tmp_channel_type != wk_ct))
+-					tmp_chan_changed = true;
+-
+-			local->tmp_channel = wk->chan;
+-			local->tmp_channel_type = wk_ct;
+ 			/*
+-			 * Leave the station vifs in awake mode if they
+-			 * happen to be on the same channel as
+-			 * the requested channel.
++			 * TODO: could optimize this by leaving the
++			 *	 station vifs in awake mode if they
++			 *	 happen to be on the same channel as
++			 *	 the requested channel
+ 			 */
+-			on_oper_chan2 = ieee80211_cfg_on_oper_channel(local);
+-			if (on_oper_chan != on_oper_chan2) {
+-				if (on_oper_chan2) {
+-					/* going off oper channel, PS too */
+-					ieee80211_offchannel_stop_vifs(local,
+-								       true);
+-					ieee80211_hw_config(local, 0);
+-				} else {
+-					/* going on channel, but leave PS
+-					 * off-channel. */
+-					ieee80211_hw_config(local, 0);
+-					ieee80211_offchannel_return(local,
+-								    true,
+-								    false);
+-				}
+-			} else if (tmp_chan_changed)
+-				/* Still off-channel, but on some other
+-				 * channel, so update hardware.
+-				 * PS should already be off-channel.
+-				 */
+-				ieee80211_hw_config(local, 0);
++			ieee80211_offchannel_stop_beaconing(local);
++			ieee80211_offchannel_stop_station(local);
+ 
++			local->tmp_channel = wk->chan;
++			local->tmp_channel_type = wk->chan_type;
++			ieee80211_hw_config(local, 0);
+ 			started = true;
+ 			wk->timeout = jiffies;
+ 		}
+@@ -1102,8 +1048,7 @@ static void ieee80211_work_work(struct work_struct *work)
+ 		 * we still need to do a hardware config.  Currently,
+ 		 * we cannot be here while scanning, however.
+ 		 */
+-		if (!ieee80211_cfg_on_oper_channel(local))
+-			ieee80211_hw_config(local, 0);
++		ieee80211_hw_config(local, 0);
+ 
+ 		/* At the least, we need to disable offchannel_ps,
+ 		 * so just go ahead and run the entire offchannel
+@@ -1111,7 +1056,7 @@ static void ieee80211_work_work(struct work_struct *work)
+ 		 * beaconing if we were already on-oper-channel
+ 		 * as a future optimization.
+ 		 */
+-		ieee80211_offchannel_return(local, true, true);
++		ieee80211_offchannel_return(local, true);
+ 
+ 		/* give connection some time to breathe */
+ 		run_again(local, jiffies + HZ/2);


More information about the scm-commits mailing list