diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2008-09-08 11:44:29 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-09-11 15:53:37 -0400 |
commit | bacac545f10f2bf6e5ceff0d8e2b82dfc493602a (patch) | |
tree | 16c590d0c71e5368e75e7a108fa4df0fa196767f /net | |
parent | 44d414dbff9d5bf46fc09f2e68567b5848cbbfd3 (diff) |
mac80211: move some HT code out of main.c
Now that I've created ht.c, I can move the aggregation
code from main.c into it.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/ht.c | 377 | ||||
-rw-r--r-- | net/mac80211/main.c | 373 |
2 files changed, 375 insertions, 375 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 | ||
22 | int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie, | 23 | int 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 | ||
330 | int 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 | |||
459 | err_unlock_queue: | ||
460 | kfree(sta->ampdu_mlme.tid_tx[tid]); | ||
461 | sta->ampdu_mlme.tid_tx[tid] = NULL; | ||
462 | ret = -EBUSY; | ||
463 | err_unlock_sta: | ||
464 | spin_unlock_bh(&sta->lock); | ||
465 | exit: | ||
466 | rcu_read_unlock(); | ||
467 | return ret; | ||
468 | } | ||
469 | EXPORT_SYMBOL(ieee80211_start_tx_ba_session); | ||
470 | |||
471 | int 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 | |||
522 | stop_BA_exit: | ||
523 | spin_unlock_bh(&sta->lock); | ||
524 | rcu_read_unlock(); | ||
525 | return ret; | ||
526 | } | ||
527 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); | ||
528 | |||
529 | void 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 | } | ||
581 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); | ||
582 | |||
583 | void 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 | } | ||
651 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); | ||
652 | |||
653 | void 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 | } | ||
676 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe); | ||
677 | |||
678 | void 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 | } | ||
701 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe); | ||
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 6df4a2e15098..f90254a5948e 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -593,379 +593,6 @@ static int ieee80211_stop(struct net_device *dev) | |||
593 | return 0; | 593 | return 0; |
594 | } | 594 | } |
595 | 595 | ||
596 | int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | ||
597 | { | ||
598 | struct ieee80211_local *local = hw_to_local(hw); | ||
599 | struct sta_info *sta; | ||
600 | struct ieee80211_sub_if_data *sdata; | ||
601 | u16 start_seq_num; | ||
602 | u8 *state; | ||
603 | int ret; | ||
604 | DECLARE_MAC_BUF(mac); | ||
605 | |||
606 | if (tid >= STA_TID_NUM) | ||
607 | return -EINVAL; | ||
608 | |||
609 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
610 | printk(KERN_DEBUG "Open BA session requested for %s tid %u\n", | ||
611 | print_mac(mac, ra), tid); | ||
612 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
613 | |||
614 | rcu_read_lock(); | ||
615 | |||
616 | sta = sta_info_get(local, ra); | ||
617 | if (!sta) { | ||
618 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
619 | printk(KERN_DEBUG "Could not find the station\n"); | ||
620 | #endif | ||
621 | ret = -ENOENT; | ||
622 | goto exit; | ||
623 | } | ||
624 | |||
625 | spin_lock_bh(&sta->lock); | ||
626 | |||
627 | /* we have tried too many times, receiver does not want A-MPDU */ | ||
628 | if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { | ||
629 | ret = -EBUSY; | ||
630 | goto err_unlock_sta; | ||
631 | } | ||
632 | |||
633 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
634 | /* check if the TID is not in aggregation flow already */ | ||
635 | if (*state != HT_AGG_STATE_IDLE) { | ||
636 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
637 | printk(KERN_DEBUG "BA request denied - session is not " | ||
638 | "idle on tid %u\n", tid); | ||
639 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
640 | ret = -EAGAIN; | ||
641 | goto err_unlock_sta; | ||
642 | } | ||
643 | |||
644 | /* prepare A-MPDU MLME for Tx aggregation */ | ||
645 | sta->ampdu_mlme.tid_tx[tid] = | ||
646 | kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC); | ||
647 | if (!sta->ampdu_mlme.tid_tx[tid]) { | ||
648 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
649 | if (net_ratelimit()) | ||
650 | printk(KERN_ERR "allocate tx mlme to tid %d failed\n", | ||
651 | tid); | ||
652 | #endif | ||
653 | ret = -ENOMEM; | ||
654 | goto err_unlock_sta; | ||
655 | } | ||
656 | /* Tx timer */ | ||
657 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = | ||
658 | sta_addba_resp_timer_expired; | ||
659 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data = | ||
660 | (unsigned long)&sta->timer_to_tid[tid]; | ||
661 | init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); | ||
662 | |||
663 | /* create a new queue for this aggregation */ | ||
664 | ret = ieee80211_ht_agg_queue_add(local, sta, tid); | ||
665 | |||
666 | /* case no queue is available to aggregation | ||
667 | * don't switch to aggregation */ | ||
668 | if (ret) { | ||
669 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
670 | printk(KERN_DEBUG "BA request denied - queue unavailable for" | ||
671 | " tid %d\n", tid); | ||
672 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
673 | goto err_unlock_queue; | ||
674 | } | ||
675 | sdata = sta->sdata; | ||
676 | |||
677 | /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the | ||
678 | * call back right away, it must see that the flow has begun */ | ||
679 | *state |= HT_ADDBA_REQUESTED_MSK; | ||
680 | |||
681 | /* This is slightly racy because the queue isn't stopped */ | ||
682 | start_seq_num = sta->tid_seq[tid]; | ||
683 | |||
684 | if (local->ops->ampdu_action) | ||
685 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START, | ||
686 | ra, tid, &start_seq_num); | ||
687 | |||
688 | if (ret) { | ||
689 | /* No need to requeue the packets in the agg queue, since we | ||
690 | * held the tx lock: no packet could be enqueued to the newly | ||
691 | * allocated queue */ | ||
692 | ieee80211_ht_agg_queue_remove(local, sta, tid, 0); | ||
693 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
694 | printk(KERN_DEBUG "BA request denied - HW unavailable for" | ||
695 | " tid %d\n", tid); | ||
696 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
697 | *state = HT_AGG_STATE_IDLE; | ||
698 | goto err_unlock_queue; | ||
699 | } | ||
700 | |||
701 | /* Will put all the packets in the new SW queue */ | ||
702 | ieee80211_requeue(local, ieee802_1d_to_ac[tid]); | ||
703 | spin_unlock_bh(&sta->lock); | ||
704 | |||
705 | /* send an addBA request */ | ||
706 | sta->ampdu_mlme.dialog_token_allocator++; | ||
707 | sta->ampdu_mlme.tid_tx[tid]->dialog_token = | ||
708 | sta->ampdu_mlme.dialog_token_allocator; | ||
709 | sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; | ||
710 | |||
711 | |||
712 | ieee80211_send_addba_request(sta->sdata, ra, tid, | ||
713 | sta->ampdu_mlme.tid_tx[tid]->dialog_token, | ||
714 | sta->ampdu_mlme.tid_tx[tid]->ssn, | ||
715 | 0x40, 5000); | ||
716 | /* activate the timer for the recipient's addBA response */ | ||
717 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires = | ||
718 | jiffies + ADDBA_RESP_INTERVAL; | ||
719 | add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); | ||
720 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
721 | printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); | ||
722 | #endif | ||
723 | goto exit; | ||
724 | |||
725 | err_unlock_queue: | ||
726 | kfree(sta->ampdu_mlme.tid_tx[tid]); | ||
727 | sta->ampdu_mlme.tid_tx[tid] = NULL; | ||
728 | ret = -EBUSY; | ||
729 | err_unlock_sta: | ||
730 | spin_unlock_bh(&sta->lock); | ||
731 | exit: | ||
732 | rcu_read_unlock(); | ||
733 | return ret; | ||
734 | } | ||
735 | EXPORT_SYMBOL(ieee80211_start_tx_ba_session); | ||
736 | |||
737 | int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, | ||
738 | u8 *ra, u16 tid, | ||
739 | enum ieee80211_back_parties initiator) | ||
740 | { | ||
741 | struct ieee80211_local *local = hw_to_local(hw); | ||
742 | struct sta_info *sta; | ||
743 | u8 *state; | ||
744 | int ret = 0; | ||
745 | DECLARE_MAC_BUF(mac); | ||
746 | |||
747 | if (tid >= STA_TID_NUM) | ||
748 | return -EINVAL; | ||
749 | |||
750 | rcu_read_lock(); | ||
751 | sta = sta_info_get(local, ra); | ||
752 | if (!sta) { | ||
753 | rcu_read_unlock(); | ||
754 | return -ENOENT; | ||
755 | } | ||
756 | |||
757 | /* check if the TID is in aggregation */ | ||
758 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
759 | spin_lock_bh(&sta->lock); | ||
760 | |||
761 | if (*state != HT_AGG_STATE_OPERATIONAL) { | ||
762 | ret = -ENOENT; | ||
763 | goto stop_BA_exit; | ||
764 | } | ||
765 | |||
766 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
767 | printk(KERN_DEBUG "Tx BA session stop requested for %s tid %u\n", | ||
768 | print_mac(mac, ra), tid); | ||
769 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
770 | |||
771 | ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]); | ||
772 | |||
773 | *state = HT_AGG_STATE_REQ_STOP_BA_MSK | | ||
774 | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); | ||
775 | |||
776 | if (local->ops->ampdu_action) | ||
777 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP, | ||
778 | ra, tid, NULL); | ||
779 | |||
780 | /* case HW denied going back to legacy */ | ||
781 | if (ret) { | ||
782 | WARN_ON(ret != -EBUSY); | ||
783 | *state = HT_AGG_STATE_OPERATIONAL; | ||
784 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); | ||
785 | goto stop_BA_exit; | ||
786 | } | ||
787 | |||
788 | stop_BA_exit: | ||
789 | spin_unlock_bh(&sta->lock); | ||
790 | rcu_read_unlock(); | ||
791 | return ret; | ||
792 | } | ||
793 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); | ||
794 | |||
795 | void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) | ||
796 | { | ||
797 | struct ieee80211_local *local = hw_to_local(hw); | ||
798 | struct sta_info *sta; | ||
799 | u8 *state; | ||
800 | DECLARE_MAC_BUF(mac); | ||
801 | |||
802 | if (tid >= STA_TID_NUM) { | ||
803 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
804 | printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", | ||
805 | tid, STA_TID_NUM); | ||
806 | #endif | ||
807 | return; | ||
808 | } | ||
809 | |||
810 | rcu_read_lock(); | ||
811 | sta = sta_info_get(local, ra); | ||
812 | if (!sta) { | ||
813 | rcu_read_unlock(); | ||
814 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
815 | printk(KERN_DEBUG "Could not find station: %s\n", | ||
816 | print_mac(mac, ra)); | ||
817 | #endif | ||
818 | return; | ||
819 | } | ||
820 | |||
821 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
822 | spin_lock_bh(&sta->lock); | ||
823 | |||
824 | if (!(*state & HT_ADDBA_REQUESTED_MSK)) { | ||
825 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
826 | printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", | ||
827 | *state); | ||
828 | #endif | ||
829 | spin_unlock_bh(&sta->lock); | ||
830 | rcu_read_unlock(); | ||
831 | return; | ||
832 | } | ||
833 | |||
834 | WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK); | ||
835 | |||
836 | *state |= HT_ADDBA_DRV_READY_MSK; | ||
837 | |||
838 | if (*state == HT_AGG_STATE_OPERATIONAL) { | ||
839 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
840 | printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); | ||
841 | #endif | ||
842 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); | ||
843 | } | ||
844 | spin_unlock_bh(&sta->lock); | ||
845 | rcu_read_unlock(); | ||
846 | } | ||
847 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); | ||
848 | |||
849 | void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) | ||
850 | { | ||
851 | struct ieee80211_local *local = hw_to_local(hw); | ||
852 | struct sta_info *sta; | ||
853 | u8 *state; | ||
854 | int agg_queue; | ||
855 | DECLARE_MAC_BUF(mac); | ||
856 | |||
857 | if (tid >= STA_TID_NUM) { | ||
858 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
859 | printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", | ||
860 | tid, STA_TID_NUM); | ||
861 | #endif | ||
862 | return; | ||
863 | } | ||
864 | |||
865 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
866 | printk(KERN_DEBUG "Stopping Tx BA session for %s tid %d\n", | ||
867 | print_mac(mac, ra), tid); | ||
868 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
869 | |||
870 | rcu_read_lock(); | ||
871 | sta = sta_info_get(local, ra); | ||
872 | if (!sta) { | ||
873 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
874 | printk(KERN_DEBUG "Could not find station: %s\n", | ||
875 | print_mac(mac, ra)); | ||
876 | #endif | ||
877 | rcu_read_unlock(); | ||
878 | return; | ||
879 | } | ||
880 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
881 | |||
882 | /* NOTE: no need to use sta->lock in this state check, as | ||
883 | * ieee80211_stop_tx_ba_session will let only one stop call to | ||
884 | * pass through per sta/tid | ||
885 | */ | ||
886 | if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { | ||
887 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
888 | printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); | ||
889 | #endif | ||
890 | rcu_read_unlock(); | ||
891 | return; | ||
892 | } | ||
893 | |||
894 | if (*state & HT_AGG_STATE_INITIATOR_MSK) | ||
895 | ieee80211_send_delba(sta->sdata, ra, tid, | ||
896 | WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); | ||
897 | |||
898 | agg_queue = sta->tid_to_tx_q[tid]; | ||
899 | |||
900 | ieee80211_ht_agg_queue_remove(local, sta, tid, 1); | ||
901 | |||
902 | /* We just requeued the all the frames that were in the | ||
903 | * removed queue, and since we might miss a softirq we do | ||
904 | * netif_schedule_queue. ieee80211_wake_queue is not used | ||
905 | * here as this queue is not necessarily stopped | ||
906 | */ | ||
907 | netif_schedule_queue(netdev_get_tx_queue(local->mdev, agg_queue)); | ||
908 | spin_lock_bh(&sta->lock); | ||
909 | *state = HT_AGG_STATE_IDLE; | ||
910 | sta->ampdu_mlme.addba_req_num[tid] = 0; | ||
911 | kfree(sta->ampdu_mlme.tid_tx[tid]); | ||
912 | sta->ampdu_mlme.tid_tx[tid] = NULL; | ||
913 | spin_unlock_bh(&sta->lock); | ||
914 | |||
915 | rcu_read_unlock(); | ||
916 | } | ||
917 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); | ||
918 | |||
919 | void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, | ||
920 | const u8 *ra, u16 tid) | ||
921 | { | ||
922 | struct ieee80211_local *local = hw_to_local(hw); | ||
923 | struct ieee80211_ra_tid *ra_tid; | ||
924 | struct sk_buff *skb = dev_alloc_skb(0); | ||
925 | |||
926 | if (unlikely(!skb)) { | ||
927 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
928 | if (net_ratelimit()) | ||
929 | printk(KERN_WARNING "%s: Not enough memory, " | ||
930 | "dropping start BA session", skb->dev->name); | ||
931 | #endif | ||
932 | return; | ||
933 | } | ||
934 | ra_tid = (struct ieee80211_ra_tid *) &skb->cb; | ||
935 | memcpy(&ra_tid->ra, ra, ETH_ALEN); | ||
936 | ra_tid->tid = tid; | ||
937 | |||
938 | skb->pkt_type = IEEE80211_ADDBA_MSG; | ||
939 | skb_queue_tail(&local->skb_queue, skb); | ||
940 | tasklet_schedule(&local->tasklet); | ||
941 | } | ||
942 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe); | ||
943 | |||
944 | void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, | ||
945 | const u8 *ra, u16 tid) | ||
946 | { | ||
947 | struct ieee80211_local *local = hw_to_local(hw); | ||
948 | struct ieee80211_ra_tid *ra_tid; | ||
949 | struct sk_buff *skb = dev_alloc_skb(0); | ||
950 | |||
951 | if (unlikely(!skb)) { | ||
952 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
953 | if (net_ratelimit()) | ||
954 | printk(KERN_WARNING "%s: Not enough memory, " | ||
955 | "dropping stop BA session", skb->dev->name); | ||
956 | #endif | ||
957 | return; | ||
958 | } | ||
959 | ra_tid = (struct ieee80211_ra_tid *) &skb->cb; | ||
960 | memcpy(&ra_tid->ra, ra, ETH_ALEN); | ||
961 | ra_tid->tid = tid; | ||
962 | |||
963 | skb->pkt_type = IEEE80211_DELBA_MSG; | ||
964 | skb_queue_tail(&local->skb_queue, skb); | ||
965 | tasklet_schedule(&local->tasklet); | ||
966 | } | ||
967 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe); | ||
968 | |||
969 | static void ieee80211_set_multicast_list(struct net_device *dev) | 596 | static void ieee80211_set_multicast_list(struct net_device *dev) |
970 | { | 597 | { |
971 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 598 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |