aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/ht.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/ht.c')
-rw-r--r--net/mac80211/ht.c377
1 files changed, 375 insertions, 2 deletions
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 5ccf1bc17466..c72b3fe3ccdb 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -2,8 +2,8 @@
2 * HT handling 2 * HT handling
3 * 3 *
4 * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi> 4 * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
5 * Copyright 2004, Instant802 Networks, Inc. 5 * Copyright 2002-2005, Instant802 Networks, Inc.
6 * Copyright 2005, Devicescape Software, Inc. 6 * Copyright 2005-2006, Devicescape Software, Inc.
7 * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> 7 * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
8 * Copyright 2007, Michael Wu <flamingice@sourmilk.net> 8 * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
9 * Copyright 2007-2008, Intel Corporation 9 * Copyright 2007-2008, Intel Corporation
@@ -18,6 +18,7 @@
18#include <net/mac80211.h> 18#include <net/mac80211.h>
19#include "ieee80211_i.h" 19#include "ieee80211_i.h"
20#include "sta_info.h" 20#include "sta_info.h"
21#include "wme.h"
21 22
22int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie, 23int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
23 struct ieee80211_ht_info *ht_info) 24 struct ieee80211_ht_info *ht_info)
@@ -326,3 +327,375 @@ void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8
326 } 327 }
327} 328}
328 329
330int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
331{
332 struct ieee80211_local *local = hw_to_local(hw);
333 struct sta_info *sta;
334 struct ieee80211_sub_if_data *sdata;
335 u16 start_seq_num;
336 u8 *state;
337 int ret;
338 DECLARE_MAC_BUF(mac);
339
340 if (tid >= STA_TID_NUM)
341 return -EINVAL;
342
343#ifdef CONFIG_MAC80211_HT_DEBUG
344 printk(KERN_DEBUG "Open BA session requested for %s tid %u\n",
345 print_mac(mac, ra), tid);
346#endif /* CONFIG_MAC80211_HT_DEBUG */
347
348 rcu_read_lock();
349
350 sta = sta_info_get(local, ra);
351 if (!sta) {
352#ifdef CONFIG_MAC80211_HT_DEBUG
353 printk(KERN_DEBUG "Could not find the station\n");
354#endif
355 ret = -ENOENT;
356 goto exit;
357 }
358
359 spin_lock_bh(&sta->lock);
360
361 /* we have tried too many times, receiver does not want A-MPDU */
362 if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
363 ret = -EBUSY;
364 goto err_unlock_sta;
365 }
366
367 state = &sta->ampdu_mlme.tid_state_tx[tid];
368 /* check if the TID is not in aggregation flow already */
369 if (*state != HT_AGG_STATE_IDLE) {
370#ifdef CONFIG_MAC80211_HT_DEBUG
371 printk(KERN_DEBUG "BA request denied - session is not "
372 "idle on tid %u\n", tid);
373#endif /* CONFIG_MAC80211_HT_DEBUG */
374 ret = -EAGAIN;
375 goto err_unlock_sta;
376 }
377
378 /* prepare A-MPDU MLME for Tx aggregation */
379 sta->ampdu_mlme.tid_tx[tid] =
380 kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
381 if (!sta->ampdu_mlme.tid_tx[tid]) {
382#ifdef CONFIG_MAC80211_HT_DEBUG
383 if (net_ratelimit())
384 printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
385 tid);
386#endif
387 ret = -ENOMEM;
388 goto err_unlock_sta;
389 }
390 /* Tx timer */
391 sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
392 sta_addba_resp_timer_expired;
393 sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data =
394 (unsigned long)&sta->timer_to_tid[tid];
395 init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
396
397 /* create a new queue for this aggregation */
398 ret = ieee80211_ht_agg_queue_add(local, sta, tid);
399
400 /* case no queue is available to aggregation
401 * don't switch to aggregation */
402 if (ret) {
403#ifdef CONFIG_MAC80211_HT_DEBUG
404 printk(KERN_DEBUG "BA request denied - queue unavailable for"
405 " tid %d\n", tid);
406#endif /* CONFIG_MAC80211_HT_DEBUG */
407 goto err_unlock_queue;
408 }
409 sdata = sta->sdata;
410
411 /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the
412 * call back right away, it must see that the flow has begun */
413 *state |= HT_ADDBA_REQUESTED_MSK;
414
415 /* This is slightly racy because the queue isn't stopped */
416 start_seq_num = sta->tid_seq[tid];
417
418 if (local->ops->ampdu_action)
419 ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START,
420 ra, tid, &start_seq_num);
421
422 if (ret) {
423 /* No need to requeue the packets in the agg queue, since we
424 * held the tx lock: no packet could be enqueued to the newly
425 * allocated queue */
426 ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
427#ifdef CONFIG_MAC80211_HT_DEBUG
428 printk(KERN_DEBUG "BA request denied - HW unavailable for"
429 " tid %d\n", tid);
430#endif /* CONFIG_MAC80211_HT_DEBUG */
431 *state = HT_AGG_STATE_IDLE;
432 goto err_unlock_queue;
433 }
434
435 /* Will put all the packets in the new SW queue */
436 ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
437 spin_unlock_bh(&sta->lock);
438
439 /* send an addBA request */
440 sta->ampdu_mlme.dialog_token_allocator++;
441 sta->ampdu_mlme.tid_tx[tid]->dialog_token =
442 sta->ampdu_mlme.dialog_token_allocator;
443 sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
444
445
446 ieee80211_send_addba_request(sta->sdata, ra, tid,
447 sta->ampdu_mlme.tid_tx[tid]->dialog_token,
448 sta->ampdu_mlme.tid_tx[tid]->ssn,
449 0x40, 5000);
450 /* activate the timer for the recipient's addBA response */
451 sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
452 jiffies + ADDBA_RESP_INTERVAL;
453 add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
454#ifdef CONFIG_MAC80211_HT_DEBUG
455 printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
456#endif
457 goto exit;
458
459err_unlock_queue:
460 kfree(sta->ampdu_mlme.tid_tx[tid]);
461 sta->ampdu_mlme.tid_tx[tid] = NULL;
462 ret = -EBUSY;
463err_unlock_sta:
464 spin_unlock_bh(&sta->lock);
465exit:
466 rcu_read_unlock();
467 return ret;
468}
469EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
470
471int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
472 u8 *ra, u16 tid,
473 enum ieee80211_back_parties initiator)
474{
475 struct ieee80211_local *local = hw_to_local(hw);
476 struct sta_info *sta;
477 u8 *state;
478 int ret = 0;
479 DECLARE_MAC_BUF(mac);
480
481 if (tid >= STA_TID_NUM)
482 return -EINVAL;
483
484 rcu_read_lock();
485 sta = sta_info_get(local, ra);
486 if (!sta) {
487 rcu_read_unlock();
488 return -ENOENT;
489 }
490
491 /* check if the TID is in aggregation */
492 state = &sta->ampdu_mlme.tid_state_tx[tid];
493 spin_lock_bh(&sta->lock);
494
495 if (*state != HT_AGG_STATE_OPERATIONAL) {
496 ret = -ENOENT;
497 goto stop_BA_exit;
498 }
499
500#ifdef CONFIG_MAC80211_HT_DEBUG
501 printk(KERN_DEBUG "Tx BA session stop requested for %s tid %u\n",
502 print_mac(mac, ra), tid);
503#endif /* CONFIG_MAC80211_HT_DEBUG */
504
505 ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]);
506
507 *state = HT_AGG_STATE_REQ_STOP_BA_MSK |
508 (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
509
510 if (local->ops->ampdu_action)
511 ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP,
512 ra, tid, NULL);
513
514 /* case HW denied going back to legacy */
515 if (ret) {
516 WARN_ON(ret != -EBUSY);
517 *state = HT_AGG_STATE_OPERATIONAL;
518 ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
519 goto stop_BA_exit;
520 }
521
522stop_BA_exit:
523 spin_unlock_bh(&sta->lock);
524 rcu_read_unlock();
525 return ret;
526}
527EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
528
529void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
530{
531 struct ieee80211_local *local = hw_to_local(hw);
532 struct sta_info *sta;
533 u8 *state;
534 DECLARE_MAC_BUF(mac);
535
536 if (tid >= STA_TID_NUM) {
537#ifdef CONFIG_MAC80211_HT_DEBUG
538 printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
539 tid, STA_TID_NUM);
540#endif
541 return;
542 }
543
544 rcu_read_lock();
545 sta = sta_info_get(local, ra);
546 if (!sta) {
547 rcu_read_unlock();
548#ifdef CONFIG_MAC80211_HT_DEBUG
549 printk(KERN_DEBUG "Could not find station: %s\n",
550 print_mac(mac, ra));
551#endif
552 return;
553 }
554
555 state = &sta->ampdu_mlme.tid_state_tx[tid];
556 spin_lock_bh(&sta->lock);
557
558 if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
559#ifdef CONFIG_MAC80211_HT_DEBUG
560 printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
561 *state);
562#endif
563 spin_unlock_bh(&sta->lock);
564 rcu_read_unlock();
565 return;
566 }
567
568 WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK);
569
570 *state |= HT_ADDBA_DRV_READY_MSK;
571
572 if (*state == HT_AGG_STATE_OPERATIONAL) {
573#ifdef CONFIG_MAC80211_HT_DEBUG
574 printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
575#endif
576 ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
577 }
578 spin_unlock_bh(&sta->lock);
579 rcu_read_unlock();
580}
581EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
582
583void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
584{
585 struct ieee80211_local *local = hw_to_local(hw);
586 struct sta_info *sta;
587 u8 *state;
588 int agg_queue;
589 DECLARE_MAC_BUF(mac);
590
591 if (tid >= STA_TID_NUM) {
592#ifdef CONFIG_MAC80211_HT_DEBUG
593 printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
594 tid, STA_TID_NUM);
595#endif
596 return;
597 }
598
599#ifdef CONFIG_MAC80211_HT_DEBUG
600 printk(KERN_DEBUG "Stopping Tx BA session for %s tid %d\n",
601 print_mac(mac, ra), tid);
602#endif /* CONFIG_MAC80211_HT_DEBUG */
603
604 rcu_read_lock();
605 sta = sta_info_get(local, ra);
606 if (!sta) {
607#ifdef CONFIG_MAC80211_HT_DEBUG
608 printk(KERN_DEBUG "Could not find station: %s\n",
609 print_mac(mac, ra));
610#endif
611 rcu_read_unlock();
612 return;
613 }
614 state = &sta->ampdu_mlme.tid_state_tx[tid];
615
616 /* NOTE: no need to use sta->lock in this state check, as
617 * ieee80211_stop_tx_ba_session will let only one stop call to
618 * pass through per sta/tid
619 */
620 if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
621#ifdef CONFIG_MAC80211_HT_DEBUG
622 printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
623#endif
624 rcu_read_unlock();
625 return;
626 }
627
628 if (*state & HT_AGG_STATE_INITIATOR_MSK)
629 ieee80211_send_delba(sta->sdata, ra, tid,
630 WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
631
632 agg_queue = sta->tid_to_tx_q[tid];
633
634 ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
635
636 /* We just requeued the all the frames that were in the
637 * removed queue, and since we might miss a softirq we do
638 * netif_schedule_queue. ieee80211_wake_queue is not used
639 * here as this queue is not necessarily stopped
640 */
641 netif_schedule_queue(netdev_get_tx_queue(local->mdev, agg_queue));
642 spin_lock_bh(&sta->lock);
643 *state = HT_AGG_STATE_IDLE;
644 sta->ampdu_mlme.addba_req_num[tid] = 0;
645 kfree(sta->ampdu_mlme.tid_tx[tid]);
646 sta->ampdu_mlme.tid_tx[tid] = NULL;
647 spin_unlock_bh(&sta->lock);
648
649 rcu_read_unlock();
650}
651EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
652
653void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
654 const u8 *ra, u16 tid)
655{
656 struct ieee80211_local *local = hw_to_local(hw);
657 struct ieee80211_ra_tid *ra_tid;
658 struct sk_buff *skb = dev_alloc_skb(0);
659
660 if (unlikely(!skb)) {
661#ifdef CONFIG_MAC80211_HT_DEBUG
662 if (net_ratelimit())
663 printk(KERN_WARNING "%s: Not enough memory, "
664 "dropping start BA session", skb->dev->name);
665#endif
666 return;
667 }
668 ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
669 memcpy(&ra_tid->ra, ra, ETH_ALEN);
670 ra_tid->tid = tid;
671
672 skb->pkt_type = IEEE80211_ADDBA_MSG;
673 skb_queue_tail(&local->skb_queue, skb);
674 tasklet_schedule(&local->tasklet);
675}
676EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
677
678void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
679 const u8 *ra, u16 tid)
680{
681 struct ieee80211_local *local = hw_to_local(hw);
682 struct ieee80211_ra_tid *ra_tid;
683 struct sk_buff *skb = dev_alloc_skb(0);
684
685 if (unlikely(!skb)) {
686#ifdef CONFIG_MAC80211_HT_DEBUG
687 if (net_ratelimit())
688 printk(KERN_WARNING "%s: Not enough memory, "
689 "dropping stop BA session", skb->dev->name);
690#endif
691 return;
692 }
693 ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
694 memcpy(&ra_tid->ra, ra, ETH_ALEN);
695 ra_tid->tid = tid;
696
697 skb->pkt_type = IEEE80211_DELBA_MSG;
698 skb_queue_tail(&local->skb_queue, skb);
699 tasklet_schedule(&local->tasklet);
700}
701EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe);