diff options
Diffstat (limited to 'net/mac80211/agg-tx.c')
-rw-r--r-- | net/mac80211/agg-tx.c | 128 |
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 | */ | ||
310 | static void __acquires(agg_queue) | ||
311 | ieee80211_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 | |||
332 | static void __releases(agg_queue) | ||
333 | ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid) | ||
334 | { | ||
335 | ieee80211_wake_queue_agg(local, tid); | ||
336 | } | ||
337 | |||
286 | void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | 338 | void 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 | } |
447 | EXPORT_SYMBOL(ieee80211_start_tx_ba_session); | 495 | EXPORT_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 | */ | ||
453 | static void __acquires(agg_queue) | ||
454 | ieee80211_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 | |||
475 | static void __releases(agg_queue) | ||
476 | ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid) | ||
477 | { | ||
478 | ieee80211_wake_queue_agg(local, tid); | ||
479 | } | ||
480 | |||
481 | static void ieee80211_agg_tx_operational(struct ieee80211_local *local, | 497 | static 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 |