diff options
Diffstat (limited to 'net/mac80211/sta_info.c')
-rw-r--r-- | net/mac80211/sta_info.c | 175 |
1 files changed, 162 insertions, 13 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 594f2318c3d8..71f370dd24bc 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -116,14 +116,15 @@ struct sta_info *sta_info_get(struct ieee80211_local *local, const u8 *addr) | |||
116 | return sta; | 116 | return sta; |
117 | } | 117 | } |
118 | 118 | ||
119 | struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, | 119 | struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata, |
120 | struct net_device *dev) | 120 | int idx) |
121 | { | 121 | { |
122 | struct ieee80211_local *local = sdata->local; | ||
122 | struct sta_info *sta; | 123 | struct sta_info *sta; |
123 | int i = 0; | 124 | int i = 0; |
124 | 125 | ||
125 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | 126 | list_for_each_entry_rcu(sta, &local->sta_list, list) { |
126 | if (dev && dev != sta->sdata->dev) | 127 | if (sdata != sta->sdata) |
127 | continue; | 128 | continue; |
128 | if (i < idx) { | 129 | if (i < idx) { |
129 | ++i; | 130 | ++i; |
@@ -147,8 +148,10 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, | |||
147 | static void __sta_info_free(struct ieee80211_local *local, | 148 | static void __sta_info_free(struct ieee80211_local *local, |
148 | struct sta_info *sta) | 149 | struct sta_info *sta) |
149 | { | 150 | { |
150 | rate_control_free_sta(sta); | 151 | if (sta->rate_ctrl) { |
151 | rate_control_put(sta->rate_ctrl); | 152 | rate_control_free_sta(sta); |
153 | rate_control_put(sta->rate_ctrl); | ||
154 | } | ||
152 | 155 | ||
153 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 156 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
154 | printk(KERN_DEBUG "%s: Destroyed STA %pM\n", | 157 | printk(KERN_DEBUG "%s: Destroyed STA %pM\n", |
@@ -171,6 +174,8 @@ void sta_info_destroy(struct sta_info *sta) | |||
171 | 174 | ||
172 | local = sta->local; | 175 | local = sta->local; |
173 | 176 | ||
177 | cancel_work_sync(&sta->drv_unblock_wk); | ||
178 | |||
174 | rate_control_remove_sta_debugfs(sta); | 179 | rate_control_remove_sta_debugfs(sta); |
175 | ieee80211_sta_debugfs_remove(sta); | 180 | ieee80211_sta_debugfs_remove(sta); |
176 | 181 | ||
@@ -259,6 +264,38 @@ static void sta_info_hash_add(struct ieee80211_local *local, | |||
259 | rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta); | 264 | rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta); |
260 | } | 265 | } |
261 | 266 | ||
267 | static void sta_unblock(struct work_struct *wk) | ||
268 | { | ||
269 | struct sta_info *sta; | ||
270 | |||
271 | sta = container_of(wk, struct sta_info, drv_unblock_wk); | ||
272 | |||
273 | if (sta->dead) | ||
274 | return; | ||
275 | |||
276 | if (!test_sta_flags(sta, WLAN_STA_PS_STA)) | ||
277 | ieee80211_sta_ps_deliver_wakeup(sta); | ||
278 | else if (test_and_clear_sta_flags(sta, WLAN_STA_PSPOLL)) | ||
279 | ieee80211_sta_ps_deliver_poll_response(sta); | ||
280 | } | ||
281 | |||
282 | static int sta_prepare_rate_control(struct ieee80211_local *local, | ||
283 | struct sta_info *sta, gfp_t gfp) | ||
284 | { | ||
285 | if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) | ||
286 | return 0; | ||
287 | |||
288 | sta->rate_ctrl = rate_control_get(local->rate_ctrl); | ||
289 | sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, | ||
290 | &sta->sta, gfp); | ||
291 | if (!sta->rate_ctrl_priv) { | ||
292 | rate_control_put(sta->rate_ctrl); | ||
293 | return -ENOMEM; | ||
294 | } | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
262 | struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | 299 | struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, |
263 | u8 *addr, gfp_t gfp) | 300 | u8 *addr, gfp_t gfp) |
264 | { | 301 | { |
@@ -272,16 +309,13 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
272 | 309 | ||
273 | spin_lock_init(&sta->lock); | 310 | spin_lock_init(&sta->lock); |
274 | spin_lock_init(&sta->flaglock); | 311 | spin_lock_init(&sta->flaglock); |
312 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); | ||
275 | 313 | ||
276 | memcpy(sta->sta.addr, addr, ETH_ALEN); | 314 | memcpy(sta->sta.addr, addr, ETH_ALEN); |
277 | sta->local = local; | 315 | sta->local = local; |
278 | sta->sdata = sdata; | 316 | sta->sdata = sdata; |
279 | 317 | ||
280 | sta->rate_ctrl = rate_control_get(local->rate_ctrl); | 318 | if (sta_prepare_rate_control(local, sta, gfp)) { |
281 | sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, | ||
282 | &sta->sta, gfp); | ||
283 | if (!sta->rate_ctrl_priv) { | ||
284 | rate_control_put(sta->rate_ctrl); | ||
285 | kfree(sta); | 319 | kfree(sta); |
286 | return NULL; | 320 | return NULL; |
287 | } | 321 | } |
@@ -478,8 +512,10 @@ static void __sta_info_unlink(struct sta_info **sta) | |||
478 | } | 512 | } |
479 | 513 | ||
480 | list_del(&(*sta)->list); | 514 | list_del(&(*sta)->list); |
515 | (*sta)->dead = true; | ||
481 | 516 | ||
482 | if (test_and_clear_sta_flags(*sta, WLAN_STA_PS)) { | 517 | if (test_and_clear_sta_flags(*sta, |
518 | WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) { | ||
483 | BUG_ON(!sdata->bss); | 519 | BUG_ON(!sdata->bss); |
484 | 520 | ||
485 | atomic_dec(&sdata->bss->num_sta_ps); | 521 | atomic_dec(&sdata->bss->num_sta_ps); |
@@ -489,6 +525,9 @@ static void __sta_info_unlink(struct sta_info **sta) | |||
489 | local->num_sta--; | 525 | local->num_sta--; |
490 | local->sta_generation++; | 526 | local->sta_generation++; |
491 | 527 | ||
528 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
529 | rcu_assign_pointer(sdata->u.vlan.sta, NULL); | ||
530 | |||
492 | if (local->ops->sta_notify) { | 531 | if (local->ops->sta_notify) { |
493 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 532 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
494 | sdata = container_of(sdata->bss, | 533 | sdata = container_of(sdata->bss, |
@@ -801,8 +840,8 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, | |||
801 | sta_info_destroy(sta); | 840 | sta_info_destroy(sta); |
802 | } | 841 | } |
803 | 842 | ||
804 | struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, | 843 | struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, |
805 | const u8 *addr) | 844 | const u8 *addr) |
806 | { | 845 | { |
807 | struct sta_info *sta = sta_info_get(hw_to_local(hw), addr); | 846 | struct sta_info *sta = sta_info_get(hw_to_local(hw), addr); |
808 | 847 | ||
@@ -810,4 +849,114 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, | |||
810 | return NULL; | 849 | return NULL; |
811 | return &sta->sta; | 850 | return &sta->sta; |
812 | } | 851 | } |
852 | EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw); | ||
853 | |||
854 | struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, | ||
855 | const u8 *addr) | ||
856 | { | ||
857 | struct ieee80211_sub_if_data *sdata; | ||
858 | |||
859 | if (!vif) | ||
860 | return NULL; | ||
861 | |||
862 | sdata = vif_to_sdata(vif); | ||
863 | |||
864 | return ieee80211_find_sta_by_hw(&sdata->local->hw, addr); | ||
865 | } | ||
813 | EXPORT_SYMBOL(ieee80211_find_sta); | 866 | EXPORT_SYMBOL(ieee80211_find_sta); |
867 | |||
868 | /* powersave support code */ | ||
869 | void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | ||
870 | { | ||
871 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
872 | struct ieee80211_local *local = sdata->local; | ||
873 | int sent, buffered; | ||
874 | |||
875 | drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta); | ||
876 | |||
877 | if (!skb_queue_empty(&sta->ps_tx_buf)) | ||
878 | sta_info_clear_tim_bit(sta); | ||
879 | |||
880 | /* Send all buffered frames to the station */ | ||
881 | sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered); | ||
882 | buffered = ieee80211_add_pending_skbs(local, &sta->ps_tx_buf); | ||
883 | sent += buffered; | ||
884 | local->total_ps_buffered -= buffered; | ||
885 | |||
886 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | ||
887 | printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames " | ||
888 | "since STA not sleeping anymore\n", sdata->dev->name, | ||
889 | sta->sta.addr, sta->sta.aid, sent - buffered, buffered); | ||
890 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ | ||
891 | } | ||
892 | |||
893 | void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta) | ||
894 | { | ||
895 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
896 | struct ieee80211_local *local = sdata->local; | ||
897 | struct sk_buff *skb; | ||
898 | int no_pending_pkts; | ||
899 | |||
900 | skb = skb_dequeue(&sta->tx_filtered); | ||
901 | if (!skb) { | ||
902 | skb = skb_dequeue(&sta->ps_tx_buf); | ||
903 | if (skb) | ||
904 | local->total_ps_buffered--; | ||
905 | } | ||
906 | no_pending_pkts = skb_queue_empty(&sta->tx_filtered) && | ||
907 | skb_queue_empty(&sta->ps_tx_buf); | ||
908 | |||
909 | if (skb) { | ||
910 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
911 | struct ieee80211_hdr *hdr = | ||
912 | (struct ieee80211_hdr *) skb->data; | ||
913 | |||
914 | /* | ||
915 | * Tell TX path to send this frame even though the STA may | ||
916 | * still remain is PS mode after this frame exchange. | ||
917 | */ | ||
918 | info->flags |= IEEE80211_TX_CTL_PSPOLL_RESPONSE; | ||
919 | |||
920 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | ||
921 | printk(KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n", | ||
922 | sta->sta.addr, sta->sta.aid, | ||
923 | skb_queue_len(&sta->ps_tx_buf)); | ||
924 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ | ||
925 | |||
926 | /* Use MoreData flag to indicate whether there are more | ||
927 | * buffered frames for this STA */ | ||
928 | if (no_pending_pkts) | ||
929 | hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA); | ||
930 | else | ||
931 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); | ||
932 | |||
933 | ieee80211_add_pending_skb(local, skb); | ||
934 | |||
935 | if (no_pending_pkts) | ||
936 | sta_info_clear_tim_bit(sta); | ||
937 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | ||
938 | } else { | ||
939 | /* | ||
940 | * FIXME: This can be the result of a race condition between | ||
941 | * us expiring a frame and the station polling for it. | ||
942 | * Should we send it a null-func frame indicating we | ||
943 | * have nothing buffered for it? | ||
944 | */ | ||
945 | printk(KERN_DEBUG "%s: STA %pM sent PS Poll even " | ||
946 | "though there are no buffered frames for it\n", | ||
947 | sdata->dev->name, sta->sta.addr); | ||
948 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ | ||
949 | } | ||
950 | } | ||
951 | |||
952 | void ieee80211_sta_block_awake(struct ieee80211_hw *hw, | ||
953 | struct ieee80211_sta *pubsta, bool block) | ||
954 | { | ||
955 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | ||
956 | |||
957 | if (block) | ||
958 | set_sta_flags(sta, WLAN_STA_PS_DRIVER); | ||
959 | else | ||
960 | ieee80211_queue_work(hw, &sta->drv_unblock_wk); | ||
961 | } | ||
962 | EXPORT_SYMBOL(ieee80211_sta_block_awake); | ||