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.c127
1 files changed, 79 insertions, 48 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index c8be8eff70d..b7f4f5c1f69 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 189
184 /* 190 /*
@@ -188,6 +194,20 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
188 */ 194 */
189 clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); 195 clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
190 196
197 /*
198 * There might be a few packets being processed right now (on
199 * another CPU) that have already gotten past the aggregation
200 * check when it was still OPERATIONAL and consequently have
201 * IEEE80211_TX_CTL_AMPDU set. In that case, this code might
202 * call into the driver at the same time or even before the
203 * TX paths calls into it, which could confuse the driver.
204 *
205 * Wait for all currently running TX paths to finish before
206 * telling the driver. New packets will not go through since
207 * the aggregation session is no longer OPERATIONAL.
208 */
209 synchronize_net();
210
191 tid_tx->stop_initiator = initiator; 211 tid_tx->stop_initiator = initiator;
192 tid_tx->tx_stop = tx; 212 tid_tx->tx_stop = tx;
193 213
@@ -284,6 +304,38 @@ ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid)
284 __release(agg_queue); 304 __release(agg_queue);
285} 305}
286 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
287void 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)
288{ 340{
289 struct tid_ampdu_tx *tid_tx; 341 struct tid_ampdu_tx *tid_tx;
@@ -295,19 +347,17 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
295 tid_tx = rcu_dereference_protected_tid_tx(sta, tid); 347 tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
296 348
297 /* 349 /*
298 * While we're asking the driver about the aggregation, 350 * Start queuing up packets for this aggregation session.
299 * 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
300 * about frames that came in while we were doing that, 352 * that.
301 * which would require us to put them to the AC pending
302 * afterwards which just makes the code more complex.
303 */ 353 */
304 ieee80211_stop_queue_agg(local, tid);
305
306 clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state); 354 clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state);
307 355
308 /* 356 /*
309 * make sure no packets are being processed to get 357 * Make sure no packets are being processed. This ensures that
310 * 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.
311 */ 361 */
312 synchronize_net(); 362 synchronize_net();
313 363
@@ -321,17 +371,15 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
321 " tid %d\n", tid); 371 " tid %d\n", tid);
322#endif 372#endif
323 spin_lock_bh(&sta->lock); 373 spin_lock_bh(&sta->lock);
374 ieee80211_agg_splice_packets(local, tid_tx, tid);
324 ieee80211_assign_tid_tx(sta, tid, NULL); 375 ieee80211_assign_tid_tx(sta, tid, NULL);
376 ieee80211_agg_splice_finish(local, tid);
325 spin_unlock_bh(&sta->lock); 377 spin_unlock_bh(&sta->lock);
326 378
327 ieee80211_wake_queue_agg(local, tid);
328 kfree_rcu(tid_tx, rcu_head); 379 kfree_rcu(tid_tx, rcu_head);
329 return; 380 return;
330 } 381 }
331 382
332 /* we can take packets again now */
333 ieee80211_wake_queue_agg(local, tid);
334
335 /* activate the timer for the recipient's addBA response */ 383 /* activate the timer for the recipient's addBA response */
336 mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL); 384 mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL);
337#ifdef CONFIG_MAC80211_HT_DEBUG 385#ifdef CONFIG_MAC80211_HT_DEBUG
@@ -451,38 +499,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
451} 499}
452EXPORT_SYMBOL(ieee80211_start_tx_ba_session); 500EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
453 501
454/*
455 * splice packets from the STA's pending to the local pending,
456 * requires a call to ieee80211_agg_splice_finish later
457 */
458static void __acquires(agg_queue)
459ieee80211_agg_splice_packets(struct ieee80211_local *local,
460 struct tid_ampdu_tx *tid_tx, u16 tid)
461{
462 int queue = ieee80211_ac_from_tid(tid);
463 unsigned long flags;
464
465 ieee80211_stop_queue_agg(local, tid);
466
467 if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates"
468 " from the pending queue\n", tid))
469 return;
470
471 if (!skb_queue_empty(&tid_tx->pending)) {
472 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
473 /* copy over remaining packets */
474 skb_queue_splice_tail_init(&tid_tx->pending,
475 &local->pending[queue]);
476 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
477 }
478}
479
480static void __releases(agg_queue)
481ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid)
482{
483 ieee80211_wake_queue_agg(local, tid);
484}
485
486static void ieee80211_agg_tx_operational(struct ieee80211_local *local, 502static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
487 struct sta_info *sta, u16 tid) 503 struct sta_info *sta, u16 tid)
488{ 504{
@@ -772,12 +788,27 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
772 goto out; 788 goto out;
773 } 789 }
774 790
775 del_timer(&tid_tx->addba_resp_timer); 791 del_timer_sync(&tid_tx->addba_resp_timer);
776 792
777#ifdef CONFIG_MAC80211_HT_DEBUG 793#ifdef CONFIG_MAC80211_HT_DEBUG
778 printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid); 794 printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid);
779#endif 795#endif
780 796
797 /*
798 * addba_resp_timer may have fired before we got here, and
799 * caused WANT_STOP to be set. If the stop then was already
800 * processed further, STOPPING might be set.
801 */
802 if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) ||
803 test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
804#ifdef CONFIG_MAC80211_HT_DEBUG
805 printk(KERN_DEBUG
806 "got addBA resp for tid %d but we already gave up\n",
807 tid);
808#endif
809 goto out;
810 }
811
781 if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) 812 if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
782 == WLAN_STATUS_SUCCESS) { 813 == WLAN_STATUS_SUCCESS) {
783 /* 814 /*