summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-11-22 14:28:41 +0300
committerJohn W. Linville <linville@tuxdriver.com>2009-11-30 21:55:51 +0300
commit827d42c9ac91ddd728e4f4a31fefb906ef2ceff7 (patch)
treee29371d79d63d0a3ec2cb6d010b71147853fc771 /drivers
parent4253119acf412fd686ef4bd8749b5a4d70ea3a51 (diff)
downloadlinux-827d42c9ac91ddd728e4f4a31fefb906ef2ceff7.tar.xz
mac80211: fix spurious delBA handling
Lennert Buytenhek noticed that delBA handling in mac80211 was broken and has remotely triggerable problems, some of which are due to some code shuffling I did that ended up changing the order in which things were done -- this was commit d75636ef9c1af224f1097941879d5a8db7cd04e5 Author: Johannes Berg <johannes@sipsolutions.net> Date: Tue Feb 10 21:25:53 2009 +0100 mac80211: RX aggregation: clean up stop session and other parts were already present in the original commit d92684e66091c0f0101819619b315b4bb8b5bcc5 Author: Ron Rindjunsky <ron.rindjunsky@intel.com> Date: Mon Jan 28 14:07:22 2008 +0200 mac80211: A-MPDU Tx add delBA from recipient support The first problem is that I moved a BUG_ON before various checks -- thereby making it possible to hit. As the comment indicates, the BUG_ON can be removed since the ampdu_action callback must already exist when the state is != IDLE. The second problem isn't easily exploitable but there's a race condition due to unconditionally setting the state to OPERATIONAL when a delBA frame is received, even when no aggregation session was ever initiated. All the drivers accept stopping the session even then, but that opens a race window where crashes could happen before the driver accepts it. Right now, a WARN_ON may happen with non-HT drivers, while the race opens only for HT drivers. For this case, there are two things necessary to fix it: 1) don't process spurious delBA frames, and be more careful about the session state; don't drop the lock 2) HT drivers need to be prepared to handle a session stop even before the session was really started -- this is true for all drivers (that support aggregation) but iwlwifi which can be fixed easily. The other HT drivers (ath9k and ar9170) are behaving properly already. Reported-by: Lennert Buytenhek <buytenh@marvell.com> Cc: stable@kernel.org Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c10
1 files changed, 9 insertions, 1 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index fb9bcfa6d947..b7e196e3c8d3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -1277,8 +1277,16 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid)
return -ENXIO;
}
+ if (priv->stations[sta_id].tid[tid].agg.state ==
+ IWL_EMPTYING_HW_QUEUE_ADDBA) {
+ IWL_DEBUG_HT(priv, "AGG stop before setup done\n");
+ ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, ra, tid);
+ priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
+ return 0;
+ }
+
if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON)
- IWL_WARN(priv, "Stopping AGG while state not IWL_AGG_ON\n");
+ IWL_WARN(priv, "Stopping AGG while state not ON or starting\n");
tid_data = &priv->stations[sta_id].tid[tid];
ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4;