diff options
Diffstat (limited to 'net/mac80211/sta_info.c')
| -rw-r--r-- | net/mac80211/sta_info.c | 107 |
1 files changed, 45 insertions, 62 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index fb12cec4d333..ba9360a475b0 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
| @@ -250,9 +250,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
| 250 | * enable session_timer's data differentiation. refer to | 250 | * enable session_timer's data differentiation. refer to |
| 251 | * sta_rx_agg_session_timer_expired for useage */ | 251 | * sta_rx_agg_session_timer_expired for useage */ |
| 252 | sta->timer_to_tid[i] = i; | 252 | sta->timer_to_tid[i] = i; |
| 253 | /* rx */ | ||
| 254 | sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE; | ||
| 255 | sta->ampdu_mlme.tid_rx[i] = NULL; | ||
| 256 | /* tx */ | 253 | /* tx */ |
| 257 | sta->ampdu_mlme.tid_state_tx[i] = HT_AGG_STATE_IDLE; | 254 | sta->ampdu_mlme.tid_state_tx[i] = HT_AGG_STATE_IDLE; |
| 258 | sta->ampdu_mlme.tid_tx[i] = NULL; | 255 | sta->ampdu_mlme.tid_tx[i] = NULL; |
| @@ -262,7 +259,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
| 262 | skb_queue_head_init(&sta->tx_filtered); | 259 | skb_queue_head_init(&sta->tx_filtered); |
| 263 | 260 | ||
| 264 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) | 261 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) |
| 265 | sta->last_seq_ctrl[i] = cpu_to_le16(USHORT_MAX); | 262 | sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX); |
| 266 | 263 | ||
| 267 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 264 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
| 268 | printk(KERN_DEBUG "%s: Allocated STA %pM\n", | 265 | printk(KERN_DEBUG "%s: Allocated STA %pM\n", |
| @@ -578,7 +575,7 @@ static int sta_info_buffer_expired(struct sta_info *sta, | |||
| 578 | } | 575 | } |
| 579 | 576 | ||
| 580 | 577 | ||
| 581 | static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, | 578 | static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, |
| 582 | struct sta_info *sta) | 579 | struct sta_info *sta) |
| 583 | { | 580 | { |
| 584 | unsigned long flags; | 581 | unsigned long flags; |
| @@ -586,7 +583,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, | |||
| 586 | struct ieee80211_sub_if_data *sdata; | 583 | struct ieee80211_sub_if_data *sdata; |
| 587 | 584 | ||
| 588 | if (skb_queue_empty(&sta->ps_tx_buf)) | 585 | if (skb_queue_empty(&sta->ps_tx_buf)) |
| 589 | return; | 586 | return false; |
| 590 | 587 | ||
| 591 | for (;;) { | 588 | for (;;) { |
| 592 | spin_lock_irqsave(&sta->ps_tx_buf.lock, flags); | 589 | spin_lock_irqsave(&sta->ps_tx_buf.lock, flags); |
| @@ -611,6 +608,8 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, | |||
| 611 | if (skb_queue_empty(&sta->ps_tx_buf)) | 608 | if (skb_queue_empty(&sta->ps_tx_buf)) |
| 612 | sta_info_clear_tim_bit(sta); | 609 | sta_info_clear_tim_bit(sta); |
| 613 | } | 610 | } |
| 611 | |||
| 612 | return true; | ||
| 614 | } | 613 | } |
| 615 | 614 | ||
| 616 | static int __must_check __sta_info_destroy(struct sta_info *sta) | 615 | static int __must_check __sta_info_destroy(struct sta_info *sta) |
| @@ -619,7 +618,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
| 619 | struct ieee80211_sub_if_data *sdata; | 618 | struct ieee80211_sub_if_data *sdata; |
| 620 | struct sk_buff *skb; | 619 | struct sk_buff *skb; |
| 621 | unsigned long flags; | 620 | unsigned long flags; |
| 622 | int ret, i; | 621 | int ret; |
| 623 | 622 | ||
| 624 | might_sleep(); | 623 | might_sleep(); |
| 625 | 624 | ||
| @@ -629,6 +628,15 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
| 629 | local = sta->local; | 628 | local = sta->local; |
| 630 | sdata = sta->sdata; | 629 | sdata = sta->sdata; |
| 631 | 630 | ||
| 631 | /* | ||
| 632 | * Before removing the station from the driver and | ||
| 633 | * rate control, it might still start new aggregation | ||
| 634 | * sessions -- block that to make sure the tear-down | ||
| 635 | * will be sufficient. | ||
| 636 | */ | ||
| 637 | set_sta_flags(sta, WLAN_STA_BLOCK_BA); | ||
| 638 | ieee80211_sta_tear_down_BA_sessions(sta); | ||
| 639 | |||
| 632 | spin_lock_irqsave(&local->sta_lock, flags); | 640 | spin_lock_irqsave(&local->sta_lock, flags); |
| 633 | ret = sta_info_hash_del(local, sta); | 641 | ret = sta_info_hash_del(local, sta); |
| 634 | /* this might still be the pending list ... which is fine */ | 642 | /* this might still be the pending list ... which is fine */ |
| @@ -645,9 +653,6 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
| 645 | * may mean it is removed from hardware which requires that | 653 | * may mean it is removed from hardware which requires that |
| 646 | * the key->sta pointer is still valid, so flush the key todo | 654 | * the key->sta pointer is still valid, so flush the key todo |
| 647 | * list here. | 655 | * list here. |
| 648 | * | ||
| 649 | * ieee80211_key_todo() will synchronize_rcu() so after this | ||
| 650 | * nothing can reference this sta struct any more. | ||
| 651 | */ | 656 | */ |
| 652 | ieee80211_key_todo(); | 657 | ieee80211_key_todo(); |
| 653 | 658 | ||
| @@ -679,11 +684,17 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
| 679 | sdata = sta->sdata; | 684 | sdata = sta->sdata; |
| 680 | } | 685 | } |
| 681 | 686 | ||
| 687 | /* | ||
| 688 | * At this point, after we wait for an RCU grace period, | ||
| 689 | * neither mac80211 nor the driver can reference this | ||
| 690 | * sta struct any more except by still existing timers | ||
| 691 | * associated with this station that we clean up below. | ||
| 692 | */ | ||
| 693 | synchronize_rcu(); | ||
| 694 | |||
| 682 | #ifdef CONFIG_MAC80211_MESH | 695 | #ifdef CONFIG_MAC80211_MESH |
| 683 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 696 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
| 684 | mesh_accept_plinks_update(sdata); | 697 | mesh_accept_plinks_update(sdata); |
| 685 | del_timer(&sta->plink_timer); | ||
| 686 | } | ||
| 687 | #endif | 698 | #endif |
| 688 | 699 | ||
| 689 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 700 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
| @@ -710,50 +721,6 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
| 710 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) | 721 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) |
| 711 | dev_kfree_skb_any(skb); | 722 | dev_kfree_skb_any(skb); |
| 712 | 723 | ||
| 713 | for (i = 0; i < STA_TID_NUM; i++) { | ||
| 714 | struct tid_ampdu_rx *tid_rx; | ||
| 715 | struct tid_ampdu_tx *tid_tx; | ||
| 716 | |||
| 717 | spin_lock_bh(&sta->lock); | ||
| 718 | tid_rx = sta->ampdu_mlme.tid_rx[i]; | ||
| 719 | /* Make sure timer won't free the tid_rx struct, see below */ | ||
| 720 | if (tid_rx) | ||
| 721 | tid_rx->shutdown = true; | ||
| 722 | |||
| 723 | spin_unlock_bh(&sta->lock); | ||
| 724 | |||
| 725 | /* | ||
| 726 | * Outside spinlock - shutdown is true now so that the timer | ||
| 727 | * won't free tid_rx, we have to do that now. Can't let the | ||
| 728 | * timer do it because we have to sync the timer outside the | ||
| 729 | * lock that it takes itself. | ||
| 730 | */ | ||
| 731 | if (tid_rx) { | ||
| 732 | del_timer_sync(&tid_rx->session_timer); | ||
| 733 | kfree(tid_rx); | ||
| 734 | } | ||
| 735 | |||
| 736 | /* | ||
| 737 | * No need to do such complications for TX agg sessions, the | ||
| 738 | * path leading to freeing the tid_tx struct goes via a call | ||
| 739 | * from the driver, and thus needs to look up the sta struct | ||
| 740 | * again, which cannot be found when we get here. Hence, we | ||
| 741 | * just need to delete the timer and free the aggregation | ||
| 742 | * info; we won't be telling the peer about it then but that | ||
| 743 | * doesn't matter if we're not talking to it again anyway. | ||
| 744 | */ | ||
| 745 | tid_tx = sta->ampdu_mlme.tid_tx[i]; | ||
| 746 | if (tid_tx) { | ||
| 747 | del_timer_sync(&tid_tx->addba_resp_timer); | ||
| 748 | /* | ||
| 749 | * STA removed while aggregation session being | ||
| 750 | * started? Bit odd, but purge frames anyway. | ||
| 751 | */ | ||
| 752 | skb_queue_purge(&tid_tx->pending); | ||
| 753 | kfree(tid_tx); | ||
| 754 | } | ||
| 755 | } | ||
| 756 | |||
| 757 | __sta_info_free(local, sta); | 724 | __sta_info_free(local, sta); |
| 758 | 725 | ||
| 759 | return 0; | 726 | return 0; |
| @@ -790,15 +757,20 @@ static void sta_info_cleanup(unsigned long data) | |||
| 790 | { | 757 | { |
| 791 | struct ieee80211_local *local = (struct ieee80211_local *) data; | 758 | struct ieee80211_local *local = (struct ieee80211_local *) data; |
| 792 | struct sta_info *sta; | 759 | struct sta_info *sta; |
| 760 | bool timer_needed = false; | ||
| 793 | 761 | ||
| 794 | rcu_read_lock(); | 762 | rcu_read_lock(); |
| 795 | list_for_each_entry_rcu(sta, &local->sta_list, list) | 763 | list_for_each_entry_rcu(sta, &local->sta_list, list) |
| 796 | sta_info_cleanup_expire_buffered(local, sta); | 764 | if (sta_info_cleanup_expire_buffered(local, sta)) |
| 765 | timer_needed = true; | ||
| 797 | rcu_read_unlock(); | 766 | rcu_read_unlock(); |
| 798 | 767 | ||
| 799 | if (local->quiescing) | 768 | if (local->quiescing) |
| 800 | return; | 769 | return; |
| 801 | 770 | ||
| 771 | if (!timer_needed) | ||
| 772 | return; | ||
| 773 | |||
| 802 | local->sta_cleanup.expires = | 774 | local->sta_cleanup.expires = |
| 803 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); | 775 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); |
| 804 | add_timer(&local->sta_cleanup); | 776 | add_timer(&local->sta_cleanup); |
| @@ -883,8 +855,12 @@ struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, | |||
| 883 | struct sta_info *sta, *nxt; | 855 | struct sta_info *sta, *nxt; |
| 884 | 856 | ||
| 885 | /* Just return a random station ... first in list ... */ | 857 | /* Just return a random station ... first in list ... */ |
| 886 | for_each_sta_info(hw_to_local(hw), addr, sta, nxt) | 858 | for_each_sta_info(hw_to_local(hw), addr, sta, nxt) { |
| 859 | if (!sta->uploaded) | ||
| 860 | return NULL; | ||
| 887 | return &sta->sta; | 861 | return &sta->sta; |
| 862 | } | ||
| 863 | |||
| 888 | return NULL; | 864 | return NULL; |
| 889 | } | 865 | } |
| 890 | EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw); | 866 | EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw); |
| @@ -892,14 +868,19 @@ EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw); | |||
| 892 | struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, | 868 | struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, |
| 893 | const u8 *addr) | 869 | const u8 *addr) |
| 894 | { | 870 | { |
| 895 | struct ieee80211_sub_if_data *sdata; | 871 | struct sta_info *sta; |
| 896 | 872 | ||
| 897 | if (!vif) | 873 | if (!vif) |
| 898 | return NULL; | 874 | return NULL; |
| 899 | 875 | ||
| 900 | sdata = vif_to_sdata(vif); | 876 | sta = sta_info_get_bss(vif_to_sdata(vif), addr); |
| 877 | if (!sta) | ||
| 878 | return NULL; | ||
| 879 | |||
| 880 | if (!sta->uploaded) | ||
| 881 | return NULL; | ||
| 901 | 882 | ||
| 902 | return ieee80211_find_sta_by_hw(&sdata->local->hw, addr); | 883 | return &sta->sta; |
| 903 | } | 884 | } |
| 904 | EXPORT_SYMBOL(ieee80211_find_sta); | 885 | EXPORT_SYMBOL(ieee80211_find_sta); |
| 905 | 886 | ||
| @@ -992,6 +973,8 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw, | |||
| 992 | { | 973 | { |
| 993 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | 974 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); |
| 994 | 975 | ||
| 976 | trace_api_sta_block_awake(sta->local, pubsta, block); | ||
| 977 | |||
| 995 | if (block) | 978 | if (block) |
| 996 | set_sta_flags(sta, WLAN_STA_PS_DRIVER); | 979 | set_sta_flags(sta, WLAN_STA_PS_DRIVER); |
| 997 | else | 980 | else |
