aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-12-07 03:02:21 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2012-01-06 17:13:48 -0500
commitafa2450ce311b3182c737c3fda59bb557da93409 (patch)
tree408d7e9eb3a6e0ddf17bdd7da3d55682b8940a27 /net
parentd27020f6c090faf3688324af9a8b496435285039 (diff)
mac80211: fix another race in aggregation start
commit 15062e6a8524f5977f2cbdf6e3eb2f144262f74e upstream. 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.) 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> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'net')
-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 db7db43ccf4..b7f4f5c1f69 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -304,6 +304,38 @@ ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid)
304 __release(agg_queue); 304 __release(agg_queue);
305} 305}
306 306
307/*
308 * splice packets from the STA's pending to the local pending,
309 * requires a call to ieee80211_agg_splice_finish later
310 */
311static void __acquires(agg_queue)
312ieee80211_agg_splice_packets(struct ieee80211_local *local,
313 struct tid_ampdu_tx *tid_tx, u16 tid)
314{
315 int queue = ieee80211_ac_from_tid(tid);
316 unsigned long flags;
317
318 ieee80211_stop_queue_agg(local, tid);
319
320 if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates"
321 " from the pending queue\n", tid))
322 return;
323
324 if (!skb_queue_empty(&tid_tx->pending)) {
325 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
326 /* copy over remaining packets */
327 skb_queue_splice_tail_init(&tid_tx->pending,
328 &local->pending[queue]);
329 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
330 }
331}
332
333static void __releases(agg_queue)
334ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid)
335{
336 ieee80211_wake_queue_agg(local, tid);
337}
338
307void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) 339void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
308{ 340{
309 struct tid_ampdu_tx *tid_tx; 341 struct tid_ampdu_tx *tid_tx;
@@ -315,19 +347,17 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
315 tid_tx = rcu_dereference_protected_tid_tx(sta, tid); 347 tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
316 348
317 /* 349 /*
318 * While we're asking the driver about the aggregation, 350 * Start queuing up packets for this aggregation session.
319 * stop the AC queue so that we don't have to worry 351 * We're going to release them once the driver is OK with
320 * about frames that came in while we were doing that, 352 * that.
321 * which would require us to put them to the AC pending
322 * afterwards which just makes the code more complex.
323 */ 353 */
324 ieee80211_stop_queue_agg(local, tid);
325
326 clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state); 354 clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state);
327 355
328 /* 356 /*
329 * make sure no packets are being processed to get 357 * Make sure no packets are being processed. This ensures that
330 * valid starting sequence number 358 * we have a valid starting sequence number and that in-flight
359 * packets have been flushed out and no packets for this TID
360 * will go into the driver during the ampdu_action call.
331 */ 361 */
332 synchronize_net(); 362 synchronize_net();
333 363
@@ -341,17 +371,15 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
341 " tid %d\n", tid); 371 " tid %d\n", tid);
342#endif 372#endif
343 spin_lock_bh(&sta->lock); 373 spin_lock_bh(&sta->lock);
374 ieee80211_agg_splice_packets(local, tid_tx, tid);
344 ieee80211_assign_tid_tx(sta, tid, NULL); 375 ieee80211_assign_tid_tx(sta, tid, NULL);
376 ieee80211_agg_splice_finish(local, tid);
345 spin_unlock_bh(&sta->lock); 377 spin_unlock_bh(&sta->lock);
346 378
347 ieee80211_wake_queue_agg(local, tid);
348 kfree_rcu(tid_tx, rcu_head); 379 kfree_rcu(tid_tx, rcu_head);
349 return; 380 return;
350 } 381 }
351 382
352 /* we can take packets again now */
353 ieee80211_wake_queue_agg(local, tid);
354
355 /* activate the timer for the recipient's addBA response */ 383 /* activate the timer for the recipient's addBA response */
356 mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL); 384 mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL);
357#ifdef CONFIG_MAC80211_HT_DEBUG 385#ifdef CONFIG_MAC80211_HT_DEBUG
@@ -471,38 +499,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
471} 499}
472EXPORT_SYMBOL(ieee80211_start_tx_ba_session); 500EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
473 501
474/*
475 * splice packets from the STA's pending to the local pending,
476 * requires a call to ieee80211_agg_splice_finish later
477 */
478static void __acquires(agg_queue)
479ieee80211_agg_splice_packets(struct ieee80211_local *local,
480 struct tid_ampdu_tx *tid_tx, u16 tid)
481{
482 int queue = ieee80211_ac_from_tid(tid);
483 unsigned long flags;
484
485 ieee80211_stop_queue_agg(local, tid);
486
487 if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates"
488 " from the pending queue\n", tid))
489 return;
490
491 if (!skb_queue_empty(&tid_tx->pending)) {
492 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
493 /* copy over remaining packets */
494 skb_queue_splice_tail_init(&tid_tx->pending,
495 &local->pending[queue]);
496 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
497 }
498}
499
500static void __releases(agg_queue)
501ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid)
502{
503 ieee80211_wake_queue_agg(local, tid);
504}
505
506static void ieee80211_agg_tx_operational(struct ieee80211_local *local, 502static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
507 struct sta_info *sta, u16 tid) 503 struct sta_info *sta, u16 tid)
508{ 504{