aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/agg-tx.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/agg-tx.c')
-rw-r--r--net/mac80211/agg-tx.c42
1 files changed, 39 insertions, 3 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 39d72ccaffb3..556765749b9c 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -162,6 +162,12 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
162 return -ENOENT; 162 return -ENOENT;
163 } 163 }
164 164
165 /* if we're already stopping ignore any new requests to stop */
166 if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
167 spin_unlock_bh(&sta->lock);
168 return -EALREADY;
169 }
170
165 if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { 171 if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
166 /* not even started yet! */ 172 /* not even started yet! */
167 ieee80211_assign_tid_tx(sta, tid, NULL); 173 ieee80211_assign_tid_tx(sta, tid, NULL);
@@ -170,6 +176,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
170 return 0; 176 return 0;
171 } 177 }
172 178
179 set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state);
180
173 spin_unlock_bh(&sta->lock); 181 spin_unlock_bh(&sta->lock);
174 182
175#ifdef CONFIG_MAC80211_HT_DEBUG 183#ifdef CONFIG_MAC80211_HT_DEBUG
@@ -177,8 +185,6 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
177 sta->sta.addr, tid); 185 sta->sta.addr, tid);
178#endif /* CONFIG_MAC80211_HT_DEBUG */ 186#endif /* CONFIG_MAC80211_HT_DEBUG */
179 187
180 set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state);
181
182 del_timer_sync(&tid_tx->addba_resp_timer); 188 del_timer_sync(&tid_tx->addba_resp_timer);
183 189
184 /* 190 /*
@@ -188,6 +194,20 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
188 */ 194 */
189 clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); 195 clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
190 196
197 /*
198 * There might be a few packets being processed right now (on
199 * another CPU) that have already gotten past the aggregation
200 * check when it was still OPERATIONAL and consequently have
201 * IEEE80211_TX_CTL_AMPDU set. In that case, this code might
202 * call into the driver at the same time or even before the
203 * TX paths calls into it, which could confuse the driver.
204 *
205 * Wait for all currently running TX paths to finish before
206 * telling the driver. New packets will not go through since
207 * the aggregation session is no longer OPERATIONAL.
208 */
209 synchronize_net();
210
191 tid_tx->stop_initiator = initiator; 211 tid_tx->stop_initiator = initiator;
192 tid_tx->tx_stop = tx; 212 tid_tx->tx_stop = tx;
193 213
@@ -753,11 +773,27 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
753 goto out; 773 goto out;
754 } 774 }
755 775
756 del_timer(&tid_tx->addba_resp_timer); 776 del_timer_sync(&tid_tx->addba_resp_timer);
757 777
758#ifdef CONFIG_MAC80211_HT_DEBUG 778#ifdef CONFIG_MAC80211_HT_DEBUG
759 printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid); 779 printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid);
760#endif 780#endif
781
782 /*
783 * addba_resp_timer may have fired before we got here, and
784 * caused WANT_STOP to be set. If the stop then was already
785 * processed further, STOPPING might be set.
786 */
787 if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) ||
788 test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
789#ifdef CONFIG_MAC80211_HT_DEBUG
790 printk(KERN_DEBUG
791 "got addBA resp for tid %d but we already gave up\n",
792 tid);
793#endif
794 goto out;
795 }
796
761 /* 797 /*
762 * IEEE 802.11-2007 7.3.1.14: 798 * IEEE 802.11-2007 7.3.1.14:
763 * In an ADDBA Response frame, when the Status Code field 799 * In an ADDBA Response frame, when the Status Code field