aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-12-07 03:02:21 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-12-07 15:09:53 -0500
commit15062e6a8524f5977f2cbdf6e3eb2f144262f74e (patch)
tree264d7fec9152ea4ce7cb176be94dc7a5e332093a /net/mac80211
parent162d12de656bc76786ba5fad6dac7bd238de9657 (diff)
mac80211: fix another race in aggregation start
Emmanuel noticed that when mac80211 stops the queues for aggregation that can leave a packet pending. This packet will be given to the driver after the AMPDU callback, but as a non-aggregated packet which messes up the sequence number etc. I also noticed by looking at the code that if packets are being processed while we clear the WANT_START bit, they might see it cleared already and queue up on tid_tx->pending. If the driver then rejects the new aggregation session we leak the packet. Fix both of these issues by changing this code to not stop the queues at all. Instead, let packets queue up on the tid_tx->pending queue instead of letting them get to the driver, and add code to recover properly in case the driver rejects the session. (The patch looks large because it has to move two functions to before their new use.) Cc: stable@vger.kernel.org Reported-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/agg-tx.c86
1 files changed, 41 insertions, 45 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 331472ce038c..d448f7a3dbc0 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -302,6 +302,38 @@ ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid)
302 __release(agg_queue); 302 __release(agg_queue);
303} 303}
304 304
305/*
306 * splice packets from the STA's pending to the local pending,
307 * requires a call to ieee80211_agg_splice_finish later
308 */
309static void __acquires(agg_queue)
310ieee80211_agg_splice_packets(struct ieee80211_local *local,
311 struct tid_ampdu_tx *tid_tx, u16 tid)
312{
313 int queue = ieee80211_ac_from_tid(tid);
314 unsigned long flags;
315
316 ieee80211_stop_queue_agg(local, tid);
317
318 if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates"
319 " from the pending queue\n", tid))
320 return;
321
322 if (!skb_queue_empty(&tid_tx->pending)) {
323 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
324 /* copy over remaining packets */
325 skb_queue_splice_tail_init(&tid_tx->pending,
326 &local->pending[queue]);
327 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
328 }
329}
330
331static void __releases(agg_queue)
332ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid)
333{
334 ieee80211_wake_queue_agg(local, tid);
335}
336
305void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) 337void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
306{ 338{
307 struct tid_ampdu_tx *tid_tx; 339 struct tid_ampdu_tx *tid_tx;
@@ -313,19 +345,17 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
313 tid_tx = rcu_dereference_protected_tid_tx(sta, tid); 345 tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
314 346
315 /* 347 /*
316 * While we're asking the driver about the aggregation, 348 * Start queuing up packets for this aggregation session.
317 * stop the AC queue so that we don't have to worry 349 * We're going to release them once the driver is OK with
318 * about frames that came in while we were doing that, 350 * that.
319 * which would require us to put them to the AC pending
320 * afterwards which just makes the code more complex.
321 */ 351 */
322 ieee80211_stop_queue_agg(local, tid);
323
324 clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state); 352 clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state);
325 353
326 /* 354 /*
327 * make sure no packets are being processed to get 355 * Make sure no packets are being processed. This ensures that
328 * valid starting sequence number 356 * we have a valid starting sequence number and that in-flight
357 * packets have been flushed out and no packets for this TID
358 * will go into the driver during the ampdu_action call.
329 */ 359 */
330 synchronize_net(); 360 synchronize_net();
331 361
@@ -339,17 +369,15 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
339 " tid %d\n", tid); 369 " tid %d\n", tid);
340#endif 370#endif
341 spin_lock_bh(&sta->lock); 371 spin_lock_bh(&sta->lock);
372 ieee80211_agg_splice_packets(local, tid_tx, tid);
342 ieee80211_assign_tid_tx(sta, tid, NULL); 373 ieee80211_assign_tid_tx(sta, tid, NULL);
374 ieee80211_agg_splice_finish(local, tid);
343 spin_unlock_bh(&sta->lock); 375 spin_unlock_bh(&sta->lock);
344 376
345 ieee80211_wake_queue_agg(local, tid);
346 kfree_rcu(tid_tx, rcu_head); 377 kfree_rcu(tid_tx, rcu_head);
347 return; 378 return;
348 } 379 }
349 380
350 /* we can take packets again now */
351 ieee80211_wake_queue_agg(local, tid);
352
353 /* activate the timer for the recipient's addBA response */ 381 /* activate the timer for the recipient's addBA response */
354 mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL); 382 mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL);
355#ifdef CONFIG_MAC80211_HT_DEBUG 383#ifdef CONFIG_MAC80211_HT_DEBUG
@@ -465,38 +493,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
465} 493}
466EXPORT_SYMBOL(ieee80211_start_tx_ba_session); 494EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
467 495
468/*
469 * splice packets from the STA's pending to the local pending,
470 * requires a call to ieee80211_agg_splice_finish later
471 */
472static void __acquires(agg_queue)
473ieee80211_agg_splice_packets(struct ieee80211_local *local,
474 struct tid_ampdu_tx *tid_tx, u16 tid)
475{
476 int queue = ieee80211_ac_from_tid(tid);
477 unsigned long flags;
478
479 ieee80211_stop_queue_agg(local, tid);
480
481 if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates"
482 " from the pending queue\n", tid))
483 return;
484
485 if (!skb_queue_empty(&tid_tx->pending)) {
486 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
487 /* copy over remaining packets */
488 skb_queue_splice_tail_init(&tid_tx->pending,
489 &local->pending[queue]);
490 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
491 }
492}
493
494static void __releases(agg_queue)
495ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid)
496{
497 ieee80211_wake_queue_agg(local, tid);
498}
499
500static void ieee80211_agg_tx_operational(struct ieee80211_local *local, 496static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
501 struct sta_info *sta, u16 tid) 497 struct sta_info *sta, u16 tid)
502{ 498{