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.c177
1 files changed, 125 insertions, 52 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 7f2042d37904..ee8bfe18b488 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -146,6 +146,13 @@ static int ___ieee80211_stop_tx_ba_session(
146 if (WARN_ON(!tid_tx)) 146 if (WARN_ON(!tid_tx))
147 return -ENOENT; 147 return -ENOENT;
148 148
149 if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
150 /* not even started yet! */
151 rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL);
152 call_rcu(&tid_tx->rcu_head, kfree_tid_tx);
153 return 0;
154 }
155
149#ifdef CONFIG_MAC80211_HT_DEBUG 156#ifdef CONFIG_MAC80211_HT_DEBUG
150 printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n", 157 printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n",
151 sta->sta.addr, tid); 158 sta->sta.addr, tid);
@@ -255,6 +262,94 @@ ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid)
255 __release(agg_queue); 262 __release(agg_queue);
256} 263}
257 264
265static void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
266{
267 struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid];
268 struct ieee80211_local *local = sta->local;
269 struct ieee80211_sub_if_data *sdata = sta->sdata;
270 u16 start_seq_num;
271 int ret;
272
273 /*
274 * While we're asking the driver about the aggregation,
275 * stop the AC queue so that we don't have to worry
276 * about frames that came in while we were doing that,
277 * which would require us to put them to the AC pending
278 * afterwards which just makes the code more complex.
279 */
280 ieee80211_stop_queue_agg(local, tid);
281
282 clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state);
283
284 /*
285 * This might be off by one due to a race that we can't
286 * really prevent here without synchronize_net() which
287 * can't be called now.
288 */
289 start_seq_num = sta->tid_seq[tid] >> 4;
290
291 ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START,
292 &sta->sta, tid, &start_seq_num);
293 if (ret) {
294#ifdef CONFIG_MAC80211_HT_DEBUG
295 printk(KERN_DEBUG "BA request denied - HW unavailable for"
296 " tid %d\n", tid);
297#endif
298 rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL);
299 ieee80211_wake_queue_agg(local, tid);
300 call_rcu(&tid_tx->rcu_head, kfree_tid_tx);
301 return;
302 }
303
304 /* we can take packets again now */
305 ieee80211_wake_queue_agg(local, tid);
306
307 /* activate the timer for the recipient's addBA response */
308 mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL);
309#ifdef CONFIG_MAC80211_HT_DEBUG
310 printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
311#endif
312
313 sta->ampdu_mlme.addba_req_num[tid]++;
314
315 /* send AddBA request */
316 ieee80211_send_addba_request(sdata, sta->sta.addr, tid,
317 tid_tx->dialog_token, start_seq_num,
318 0x40, 5000);
319}
320
321void ieee80211_tx_ba_session_work(struct work_struct *work)
322{
323 struct sta_info *sta =
324 container_of(work, struct sta_info, ampdu_mlme.work);
325 struct tid_ampdu_tx *tid_tx;
326 int tid;
327
328 /*
329 * When this flag is set, new sessions should be
330 * blocked, and existing sessions will be torn
331 * down by the code that set the flag, so this
332 * need not run.
333 */
334 if (test_sta_flags(sta, WLAN_STA_BLOCK_BA))
335 return;
336
337 spin_lock_bh(&sta->lock);
338 for (tid = 0; tid < STA_TID_NUM; tid++) {
339 tid_tx = sta->ampdu_mlme.tid_tx[tid];
340 if (!tid_tx)
341 continue;
342
343 if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state))
344 ieee80211_tx_ba_session_handle_start(sta, tid);
345 else if (test_and_clear_bit(HT_AGG_STATE_WANT_STOP,
346 &tid_tx->state))
347 ___ieee80211_stop_tx_ba_session(sta, tid,
348 WLAN_BACK_INITIATOR);
349 }
350 spin_unlock_bh(&sta->lock);
351}
352
258int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) 353int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
259{ 354{
260 struct sta_info *sta = container_of(pubsta, struct sta_info, sta); 355 struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
@@ -262,7 +357,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
262 struct ieee80211_local *local = sdata->local; 357 struct ieee80211_local *local = sdata->local;
263 struct tid_ampdu_tx *tid_tx; 358 struct tid_ampdu_tx *tid_tx;
264 int ret = 0; 359 int ret = 0;
265 u16 start_seq_num;
266 360
267 trace_api_start_tx_ba_session(pubsta, tid); 361 trace_api_start_tx_ba_session(pubsta, tid);
268 362
@@ -316,15 +410,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
316 goto err_unlock_sta; 410 goto err_unlock_sta;
317 } 411 }
318 412
319 /*
320 * While we're asking the driver about the aggregation,
321 * stop the AC queue so that we don't have to worry
322 * about frames that came in while we were doing that,
323 * which would require us to put them to the AC pending
324 * afterwards which just makes the code more complex.
325 */
326 ieee80211_stop_queue_agg(local, tid);
327
328 /* prepare A-MPDU MLME for Tx aggregation */ 413 /* prepare A-MPDU MLME for Tx aggregation */
329 tid_tx = kzalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC); 414 tid_tx = kzalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
330 if (!tid_tx) { 415 if (!tid_tx) {
@@ -334,59 +419,27 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
334 tid); 419 tid);
335#endif 420#endif
336 ret = -ENOMEM; 421 ret = -ENOMEM;
337 goto err_wake_queue; 422 goto err_unlock_sta;
338 } 423 }
339 424
340 skb_queue_head_init(&tid_tx->pending); 425 skb_queue_head_init(&tid_tx->pending);
426 __set_bit(HT_AGG_STATE_WANT_START, &tid_tx->state);
341 427
342 /* Tx timer */ 428 /* Tx timer */
343 tid_tx->addba_resp_timer.function = sta_addba_resp_timer_expired; 429 tid_tx->addba_resp_timer.function = sta_addba_resp_timer_expired;
344 tid_tx->addba_resp_timer.data = (unsigned long)&sta->timer_to_tid[tid]; 430 tid_tx->addba_resp_timer.data = (unsigned long)&sta->timer_to_tid[tid];
345 init_timer(&tid_tx->addba_resp_timer); 431 init_timer(&tid_tx->addba_resp_timer);
346 432
347 start_seq_num = sta->tid_seq[tid] >> 4; 433 /* assign a dialog token */
348
349 ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START,
350 pubsta, tid, &start_seq_num);
351 if (ret) {
352#ifdef CONFIG_MAC80211_HT_DEBUG
353 printk(KERN_DEBUG "BA request denied - HW unavailable for"
354 " tid %d\n", tid);
355#endif /* CONFIG_MAC80211_HT_DEBUG */
356 goto err_free;
357 }
358
359 rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx);
360
361 /* Driver vetoed or OKed, but we can take packets again now */
362 ieee80211_wake_queue_agg(local, tid);
363
364 /* activate the timer for the recipient's addBA response */
365 tid_tx->addba_resp_timer.expires = jiffies + ADDBA_RESP_INTERVAL;
366 add_timer(&tid_tx->addba_resp_timer);
367#ifdef CONFIG_MAC80211_HT_DEBUG
368 printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
369#endif
370
371 /* prepare tid data */
372 sta->ampdu_mlme.dialog_token_allocator++; 434 sta->ampdu_mlme.dialog_token_allocator++;
373 tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator; 435 tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator;
374 tid_tx->ssn = start_seq_num;
375
376 sta->ampdu_mlme.addba_req_num[tid]++;
377 436
378 spin_unlock_bh(&sta->lock); 437 /* finally, assign it to the array */
438 rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx);
379 439
380 /* send AddBA request */ 440 ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work);
381 ieee80211_send_addba_request(sdata, pubsta->addr, tid,
382 tid_tx->dialog_token, tid_tx->ssn,
383 0x40, 5000);
384 return 0;
385 441
386 err_free: 442 /* this flow continues off the work */
387 kfree(tid_tx);
388 err_wake_queue:
389 ieee80211_wake_queue_agg(local, tid);
390 err_unlock_sta: 443 err_unlock_sta:
391 spin_unlock_bh(&sta->lock); 444 spin_unlock_bh(&sta->lock);
392 return ret; 445 return ret;
@@ -534,8 +587,7 @@ int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
534 spin_lock_bh(&sta->lock); 587 spin_lock_bh(&sta->lock);
535 tid_tx = sta->ampdu_mlme.tid_tx[tid]; 588 tid_tx = sta->ampdu_mlme.tid_tx[tid];
536 589
537 /* check if the TID is in aggregation */ 590 if (!tid_tx) {
538 if (!tid_tx || !test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
539 ret = -ENOENT; 591 ret = -ENOENT;
540 goto unlock; 592 goto unlock;
541 } 593 }
@@ -552,6 +604,8 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
552 struct sta_info *sta = container_of(pubsta, struct sta_info, sta); 604 struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
553 struct ieee80211_sub_if_data *sdata = sta->sdata; 605 struct ieee80211_sub_if_data *sdata = sta->sdata;
554 struct ieee80211_local *local = sdata->local; 606 struct ieee80211_local *local = sdata->local;
607 struct tid_ampdu_tx *tid_tx;
608 int ret = 0;
555 609
556 trace_api_stop_tx_ba_session(pubsta, tid); 610 trace_api_stop_tx_ba_session(pubsta, tid);
557 611
@@ -561,7 +615,26 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
561 if (tid >= STA_TID_NUM) 615 if (tid >= STA_TID_NUM)
562 return -EINVAL; 616 return -EINVAL;
563 617
564 return __ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR); 618 spin_lock_bh(&sta->lock);
619 tid_tx = sta->ampdu_mlme.tid_tx[tid];
620
621 if (!tid_tx) {
622 ret = -ENOENT;
623 goto unlock;
624 }
625
626 if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
627 /* already in progress stopping it */
628 ret = 0;
629 goto unlock;
630 }
631
632 set_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state);
633 ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work);
634
635 unlock:
636 spin_unlock_bh(&sta->lock);
637 return ret;
565} 638}
566EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); 639EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
567 640