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 266cc871c72d..2c2e9519a2e7 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 del_timer_sync(&tid_tx->session_timer); 189 del_timer_sync(&tid_tx->session_timer);
184 190
@@ -189,6 +195,20 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
189 */ 195 */
190 clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); 196 clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
191 197
198 /*
199 * There might be a few packets being processed right now (on
200 * another CPU) that have already gotten past the aggregation
201 * check when it was still OPERATIONAL and consequently have
202 * IEEE80211_TX_CTL_AMPDU set. In that case, this code might
203 * call into the driver at the same time or even before the
204 * TX paths calls into it, which could confuse the driver.
205 *
206 * Wait for all currently running TX paths to finish before
207 * telling the driver. New packets will not go through since
208 * the aggregation session is no longer OPERATIONAL.
209 */
210 synchronize_net();
211
192 tid_tx->stop_initiator = initiator; 212 tid_tx->stop_initiator = initiator;
193 tid_tx->tx_stop = tx; 213 tid_tx->tx_stop = tx;
194 214
@@ -781,11 +801,27 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
781 goto out; 801 goto out;
782 } 802 }
783 803
784 del_timer(&tid_tx->addba_resp_timer); 804 del_timer_sync(&tid_tx->addba_resp_timer);
785 805
786#ifdef CONFIG_MAC80211_HT_DEBUG 806#ifdef CONFIG_MAC80211_HT_DEBUG
787 printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid); 807 printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid);
788#endif 808#endif
809
810 /*
811 * addba_resp_timer may have fired before we got here, and
812 * caused WANT_STOP to be set. If the stop then was already
813 * processed further, STOPPING might be set.
814 */
815 if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) ||
816 test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
817#ifdef CONFIG_MAC80211_HT_DEBUG
818 printk(KERN_DEBUG
819 "got addBA resp for tid %d but we already gave up\n",
820 tid);
821#endif
822 goto out;
823 }
824
789 /* 825 /*
790 * IEEE 802.11-2007 7.3.1.14: 826 * IEEE 802.11-2007 7.3.1.14:
791 * In an ADDBA Response frame, when the Status Code field 827 * In an ADDBA Response frame, when the Status Code field