diff options
Diffstat (limited to 'net/mac80211/sta_info.c')
-rw-r--r-- | net/mac80211/sta_info.c | 52 |
1 files changed, 31 insertions, 21 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 13e8c30adf01..b83870bf60fa 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -67,7 +67,8 @@ static int sta_info_hash_del(struct ieee80211_local *local, | |||
67 | { | 67 | { |
68 | struct sta_info *s; | 68 | struct sta_info *s; |
69 | 69 | ||
70 | s = local->sta_hash[STA_HASH(sta->sta.addr)]; | 70 | s = rcu_dereference_protected(local->sta_hash[STA_HASH(sta->sta.addr)], |
71 | lockdep_is_held(&local->sta_lock)); | ||
71 | if (!s) | 72 | if (!s) |
72 | return -ENOENT; | 73 | return -ENOENT; |
73 | if (s == sta) { | 74 | if (s == sta) { |
@@ -76,9 +77,11 @@ static int sta_info_hash_del(struct ieee80211_local *local, | |||
76 | return 0; | 77 | return 0; |
77 | } | 78 | } |
78 | 79 | ||
79 | while (s->hnext && s->hnext != sta) | 80 | while (rcu_access_pointer(s->hnext) && |
80 | s = s->hnext; | 81 | rcu_access_pointer(s->hnext) != sta) |
81 | if (s->hnext) { | 82 | s = rcu_dereference_protected(s->hnext, |
83 | lockdep_is_held(&local->sta_lock)); | ||
84 | if (rcu_access_pointer(s->hnext)) { | ||
82 | rcu_assign_pointer(s->hnext, sta->hnext); | 85 | rcu_assign_pointer(s->hnext, sta->hnext); |
83 | return 0; | 86 | return 0; |
84 | } | 87 | } |
@@ -228,6 +231,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
228 | { | 231 | { |
229 | struct ieee80211_local *local = sdata->local; | 232 | struct ieee80211_local *local = sdata->local; |
230 | struct sta_info *sta; | 233 | struct sta_info *sta; |
234 | struct timespec uptime; | ||
231 | int i; | 235 | int i; |
232 | 236 | ||
233 | sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp); | 237 | sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp); |
@@ -245,6 +249,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
245 | sta->sdata = sdata; | 249 | sta->sdata = sdata; |
246 | sta->last_rx = jiffies; | 250 | sta->last_rx = jiffies; |
247 | 251 | ||
252 | do_posix_clock_monotonic_gettime(&uptime); | ||
253 | sta->last_connected = uptime.tv_sec; | ||
248 | ewma_init(&sta->avg_signal, 1024, 8); | 254 | ewma_init(&sta->avg_signal, 1024, 8); |
249 | 255 | ||
250 | if (sta_prepare_rate_control(local, sta, gfp)) { | 256 | if (sta_prepare_rate_control(local, sta, gfp)) { |
@@ -271,7 +277,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
271 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 277 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
272 | 278 | ||
273 | #ifdef CONFIG_MAC80211_MESH | 279 | #ifdef CONFIG_MAC80211_MESH |
274 | sta->plink_state = PLINK_LISTEN; | 280 | sta->plink_state = NL80211_PLINK_LISTEN; |
275 | init_timer(&sta->plink_timer); | 281 | init_timer(&sta->plink_timer); |
276 | #endif | 282 | #endif |
277 | 283 | ||
@@ -584,7 +590,6 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, | |||
584 | { | 590 | { |
585 | unsigned long flags; | 591 | unsigned long flags; |
586 | struct sk_buff *skb; | 592 | struct sk_buff *skb; |
587 | struct ieee80211_sub_if_data *sdata; | ||
588 | 593 | ||
589 | if (skb_queue_empty(&sta->ps_tx_buf)) | 594 | if (skb_queue_empty(&sta->ps_tx_buf)) |
590 | return false; | 595 | return false; |
@@ -601,7 +606,6 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, | |||
601 | if (!skb) | 606 | if (!skb) |
602 | break; | 607 | break; |
603 | 608 | ||
604 | sdata = sta->sdata; | ||
605 | local->total_ps_buffered--; | 609 | local->total_ps_buffered--; |
606 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 610 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
607 | printk(KERN_DEBUG "Buffered frame expired (STA %pM)\n", | 611 | printk(KERN_DEBUG "Buffered frame expired (STA %pM)\n", |
@@ -609,7 +613,8 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, | |||
609 | #endif | 613 | #endif |
610 | dev_kfree_skb(skb); | 614 | dev_kfree_skb(skb); |
611 | 615 | ||
612 | if (skb_queue_empty(&sta->ps_tx_buf)) | 616 | if (skb_queue_empty(&sta->ps_tx_buf) && |
617 | !test_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF)) | ||
613 | sta_info_clear_tim_bit(sta); | 618 | sta_info_clear_tim_bit(sta); |
614 | } | 619 | } |
615 | 620 | ||
@@ -650,10 +655,12 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
650 | if (ret) | 655 | if (ret) |
651 | return ret; | 656 | return ret; |
652 | 657 | ||
658 | mutex_lock(&local->key_mtx); | ||
653 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) | 659 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) |
654 | ieee80211_key_free(local, sta->gtk[i]); | 660 | __ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i])); |
655 | if (sta->ptk) | 661 | if (sta->ptk) |
656 | ieee80211_key_free(local, sta->ptk); | 662 | __ieee80211_key_free(key_mtx_dereference(local, sta->ptk)); |
663 | mutex_unlock(&local->key_mtx); | ||
657 | 664 | ||
658 | sta->dead = true; | 665 | sta->dead = true; |
659 | 666 | ||
@@ -698,6 +705,8 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
698 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 705 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
699 | cancel_work_sync(&sta->drv_unblock_wk); | 706 | cancel_work_sync(&sta->drv_unblock_wk); |
700 | 707 | ||
708 | cfg80211_del_sta(sdata->dev, sta->sta.addr, GFP_KERNEL); | ||
709 | |||
701 | rate_control_remove_sta_debugfs(sta); | 710 | rate_control_remove_sta_debugfs(sta); |
702 | ieee80211_sta_debugfs_remove(sta); | 711 | ieee80211_sta_debugfs_remove(sta); |
703 | 712 | ||
@@ -766,9 +775,8 @@ static void sta_info_cleanup(unsigned long data) | |||
766 | if (!timer_needed) | 775 | if (!timer_needed) |
767 | return; | 776 | return; |
768 | 777 | ||
769 | local->sta_cleanup.expires = | 778 | mod_timer(&local->sta_cleanup, |
770 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); | 779 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL)); |
771 | add_timer(&local->sta_cleanup); | ||
772 | } | 780 | } |
773 | 781 | ||
774 | void sta_info_init(struct ieee80211_local *local) | 782 | void sta_info_init(struct ieee80211_local *local) |
@@ -781,14 +789,6 @@ void sta_info_init(struct ieee80211_local *local) | |||
781 | 789 | ||
782 | setup_timer(&local->sta_cleanup, sta_info_cleanup, | 790 | setup_timer(&local->sta_cleanup, sta_info_cleanup, |
783 | (unsigned long)local); | 791 | (unsigned long)local); |
784 | local->sta_cleanup.expires = | ||
785 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); | ||
786 | } | ||
787 | |||
788 | int sta_info_start(struct ieee80211_local *local) | ||
789 | { | ||
790 | add_timer(&local->sta_cleanup); | ||
791 | return 0; | ||
792 | } | 792 | } |
793 | 793 | ||
794 | void sta_info_stop(struct ieee80211_local *local) | 794 | void sta_info_stop(struct ieee80211_local *local) |
@@ -900,6 +900,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | |||
900 | struct ieee80211_local *local = sdata->local; | 900 | struct ieee80211_local *local = sdata->local; |
901 | int sent, buffered; | 901 | int sent, buffered; |
902 | 902 | ||
903 | clear_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF); | ||
903 | if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) | 904 | if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) |
904 | drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta); | 905 | drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta); |
905 | 906 | ||
@@ -992,3 +993,12 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw, | |||
992 | ieee80211_queue_work(hw, &sta->drv_unblock_wk); | 993 | ieee80211_queue_work(hw, &sta->drv_unblock_wk); |
993 | } | 994 | } |
994 | EXPORT_SYMBOL(ieee80211_sta_block_awake); | 995 | EXPORT_SYMBOL(ieee80211_sta_block_awake); |
996 | |||
997 | void ieee80211_sta_set_tim(struct ieee80211_sta *pubsta) | ||
998 | { | ||
999 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | ||
1000 | |||
1001 | set_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF); | ||
1002 | sta_info_set_tim_bit(sta); | ||
1003 | } | ||
1004 | EXPORT_SYMBOL(ieee80211_sta_set_tim); | ||