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.c128
1 files changed, 80 insertions, 48 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index b3f65520e7a7..2e4b961648d4 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -161,6 +161,12 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
161 return -ENOENT; 161 return -ENOENT;
162 } 162 }
163 163
164 /* if we're already stopping ignore any new requests to stop */
165 if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
166 spin_unlock_bh(&sta->lock);
167 return -EALREADY;
168 }
169
164 if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { 170 if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
165 /* not even started yet! */ 171 /* not even started yet! */
166 ieee80211_assign_tid_tx(sta, tid, NULL); 172 ieee80211_assign_tid_tx(sta, tid, NULL);
@@ -169,6 +175,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
169 return 0; 175 return 0;
170 } 176 }
171 177
178 set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state);
179
172 spin_unlock_bh(&sta->lock); 180 spin_unlock_bh(&sta->lock);
173 181
174#ifdef CONFIG_MAC80211_HT_DEBUG 182#ifdef CONFIG_MAC80211_HT_DEBUG
@@ -176,8 +184,6 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
176 sta->sta.addr, tid); 184 sta->sta.addr, tid);
177#endif /* CONFIG_MAC80211_HT_DEBUG */ 185#endif /* CONFIG_MAC80211_HT_DEBUG */
178 186
179 set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state);
180
181 del_timer_sync(&tid_tx->addba_resp_timer); 187 del_timer_sync(&tid_tx->addba_resp_timer);
182 188
183 /* 189 /*
@@ -187,6 +193,20 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
187 */ 193 */
188 clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); 194 clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
189 195
196 /*
197 * There might be a few packets being processed right now (on
198 * another CPU) that have already gotten past the aggregation
199 * check when it was still OPERATIONAL and consequently have
200 * IEEE80211_TX_CTL_AMPDU set. In that case, this code might
201 * call into the driver at the same time or even before the
202 * TX paths calls into it, which could confuse the driver.
203 *
204 * Wait for all currently running TX paths to finish before
205 * telling the driver. New packets will not go through since
206 * the aggregation session is no longer OPERATIONAL.
207 */
208 synchronize_net();
209
190 tid_tx->stop_initiator = initiator; 210 tid_tx->stop_initiator = initiator;
191 tid_tx->tx_stop = tx; 211 tid_tx->tx_stop = tx;
192 212
@@ -283,6 +303,38 @@ ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid)
283 __release(agg_queue); 303 __release(agg_queue);
284} 304}
285 305
306/*
307 * splice packets from the STA's pending to the local pending,
308 * requires a call to ieee80211_agg_splice_finish later
309 */
310static void __acquires(agg_queue)
311ieee80211_agg_splice_packets(struct ieee80211_local *local,
312 struct tid_ampdu_tx *tid_tx, u16 tid)
313{
314 int queue = ieee80211_ac_from_tid(tid);
315 unsigned long flags;
316
317 ieee80211_stop_queue_agg(local, tid);
318
319 if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates"
320 " from the pending queue\n", tid))
321 return;
322
323 if (!skb_queue_empty(&tid_tx->pending)) {
324 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
325 /* copy over remaining packets */
326 skb_queue_splice_tail_init(&tid_tx->pending,
327 &local->pending[queue]);
328 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
329 }
330}
331
332static void __releases(agg_queue)
333ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid)
334{
335 ieee80211_wake_queue_agg(local, tid);
336}
337
286void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) 338void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
287{ 339{
288 struct tid_ampdu_tx *tid_tx; 340 struct tid_ampdu_tx *tid_tx;
@@ -294,19 +346,17 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
294 tid_tx = rcu_dereference_protected_tid_tx(sta, tid); 346 tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
295 347
296 /* 348 /*
297 * While we're asking the driver about the aggregation, 349 * Start queuing up packets for this aggregation session.
298 * stop the AC queue so that we don't have to worry 350 * We're going to release them once the driver is OK with
299 * about frames that came in while we were doing that, 351 * that.
300 * which would require us to put them to the AC pending
301 * afterwards which just makes the code more complex.
302 */ 352 */
303 ieee80211_stop_queue_agg(local, tid);
304
305 clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state); 353 clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state);
306 354
307 /* 355 /*
308 * make sure no packets are being processed to get 356 * Make sure no packets are being processed. This ensures that
309 * valid starting sequence number 357 * we have a valid starting sequence number and that in-flight
358 * packets have been flushed out and no packets for this TID
359 * will go into the driver during the ampdu_action call.
310 */ 360 */
311 synchronize_net(); 361 synchronize_net();
312 362
@@ -320,17 +370,15 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
320 " tid %d\n", tid); 370 " tid %d\n", tid);
321#endif 371#endif
322 spin_lock_bh(&sta->lock); 372 spin_lock_bh(&sta->lock);
373 ieee80211_agg_splice_packets(local, tid_tx, tid);
323 ieee80211_assign_tid_tx(sta, tid, NULL); 374 ieee80211_assign_tid_tx(sta, tid, NULL);
375 ieee80211_agg_splice_finish(local, tid);
324 spin_unlock_bh(&sta->lock); 376 spin_unlock_bh(&sta->lock);
325 377
326 ieee80211_wake_queue_agg(local, tid);
327 kfree_rcu(tid_tx, rcu_head); 378 kfree_rcu(tid_tx, rcu_head);
328 return; 379 return;
329 } 380 }
330 381
331 /* we can take packets again now */
332 ieee80211_wake_queue_agg(local, tid);
333
334 /* activate the timer for the recipient's addBA response */ 382 /* activate the timer for the recipient's addBA response */
335 mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL); 383 mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL);
336#ifdef CONFIG_MAC80211_HT_DEBUG 384#ifdef CONFIG_MAC80211_HT_DEBUG
@@ -446,38 +494,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
446} 494}
447EXPORT_SYMBOL(ieee80211_start_tx_ba_session); 495EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
448 496
449/*
450 * splice packets from the STA's pending to the local pending,
451 * requires a call to ieee80211_agg_splice_finish later
452 */
453static void __acquires(agg_queue)
454ieee80211_agg_splice_packets(struct ieee80211_local *local,
455 struct tid_ampdu_tx *tid_tx, u16 tid)
456{
457 int queue = ieee80211_ac_from_tid(tid);
458 unsigned long flags;
459
460 ieee80211_stop_queue_agg(local, tid);
461
462 if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates"
463 " from the pending queue\n", tid))
464 return;
465
466 if (!skb_queue_empty(&tid_tx->pending)) {
467 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
468 /* copy over remaining packets */
469 skb_queue_splice_tail_init(&tid_tx->pending,
470 &local->pending[queue]);
471 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
472 }
473}
474
475static void __releases(agg_queue)
476ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid)
477{
478 ieee80211_wake_queue_agg(local, tid);
479}
480
481static void ieee80211_agg_tx_operational(struct ieee80211_local *local, 497static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
482 struct sta_info *sta, u16 tid) 498 struct sta_info *sta, u16 tid)
483{ 499{
@@ -757,11 +773,27 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
757 goto out; 773 goto out;
758 } 774 }
759 775
760 del_timer(&tid_tx->addba_resp_timer); 776 del_timer_sync(&tid_tx->addba_resp_timer);
761 777
762#ifdef CONFIG_MAC80211_HT_DEBUG 778#ifdef CONFIG_MAC80211_HT_DEBUG
763 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);
764#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
765 /* 797 /*
766 * IEEE 802.11-2007 7.3.1.14: 798 * IEEE 802.11-2007 7.3.1.14:
767 * In an ADDBA Response frame, when the Status Code field 799 * In an ADDBA Response frame, when the Status Code field