iwlwifi: mvm: Use CS tx block bit for AP/GO

An AP/GO may perform the channel switch slightly before its stations.
This scenario may result in packet loss, since the transmission may start
before the client is actually on a new channel. In order to prevent
potential packet loss disable tx to all the stations when the channel
switch flow starts. Clear the disable_tx bit when a station is seen on a
target channel, or after IWL_MVM_CS_UNBLOCK_TX_TIMEOUT beacons on a new
channel. In addition call ieee80211_sta_block_awake in order to inform
mac80211 that the frames for this station should be buffered.

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c
index cf72769..4b98987 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rx.c
@@ -259,6 +259,23 @@
 	memset(&rx_status, 0, sizeof(rx_status));
 
 	/*
+	 * We have tx blocked stations (with CS bit). If we heard frames from
+	 * a blocked station on a new channel we can TX to it again.
+	 */
+	if (unlikely(mvm->csa_tx_block_bcn_timeout)) {
+		struct ieee80211_sta *sta;
+
+		rcu_read_lock();
+
+		sta = ieee80211_find_sta(
+			rcu_dereference(mvm->csa_tx_blocked_vif), hdr->addr2);
+		if (sta)
+			iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, false);
+
+		rcu_read_unlock();
+	}
+
+	/*
 	 * drop the packet if it has failed being decrypted by HW
 	 */
 	if (iwl_mvm_set_mac80211_rx_flag(mvm, hdr, &rx_status, rx_pkt_status)) {