--- /dev/null
+From johannes@sipsolutions.net Sat Dec 10 09:04:20 2011
+From: Nikolay Martynov <mar.kolya@gmail.com>
+Date: Sat, 10 Dec 2011 17:31:23 +0100
+Subject: mac80211: fix race condition caused by late addBA response
+To: Greg KH <gregkh@suse.de>
+Cc: Greg KH <greg@kroah.com>, Nikolay Martynov <mar.kolya@gmail.com>, John Linville <linville@tuxdriver.com>, stable@vger.kernel.org
+Message-ID: <1323534683.3344.30.camel@jlt3.sipsolutions.net>
+
+
+From: Nikolay Martynov <mar.kolya@gmail.com>
+
+Upstream commit d305a6557b2c4dca0110f05ffe745b1ef94adb80.
+
+If addBA responses comes in just after addba_resp_timer has
+expired mac80211 will still accept it and try to open the
+aggregation session. This causes drivers to be confused and
+in some cases even crash.
+
+This patch fixes the race condition and makes sure that if
+addba_resp_timer has expired addBA response is not longer
+accepted and we do not try to open half-closed session.
+
+Signed-off-by: Nikolay Martynov <mar.kolya@gmail.com>
+[some adjustments]
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/mac80211/agg-tx.c | 17 ++++++++++++++++-
+ 1 file changed, 16 insertions(+), 1 deletion(-)
+
+--- a/net/mac80211/agg-tx.c
++++ b/net/mac80211/agg-tx.c
+@@ -792,12 +792,27 @@ void ieee80211_process_addba_resp(struct
+ goto out;
+ }
+
+- del_timer(&tid_tx->addba_resp_timer);
++ del_timer_sync(&tid_tx->addba_resp_timer);
+
+ #ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid);
+ #endif
+
++ /*
++ * addba_resp_timer may have fired before we got here, and
++ * caused WANT_STOP to be set. If the stop then was already
++ * processed further, STOPPING might be set.
++ */
++ if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) ||
++ test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
++#ifdef CONFIG_MAC80211_HT_DEBUG
++ printk(KERN_DEBUG
++ "got addBA resp for tid %d but we already gave up\n",
++ tid);
++#endif
++ goto out;
++ }
++
+ if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
+ == WLAN_STATUS_SUCCESS) {
+ /*