aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/ieee80211.c6
-rw-r--r--net/mac80211/ieee80211_i.h11
-rw-r--r--net/mac80211/ieee80211_iface.c2
-rw-r--r--net/mac80211/ieee80211_sta.c20
-rw-r--r--net/mac80211/sta_info.c184
-rw-r--r--net/mac80211/sta_info.h11
-rw-r--r--net/mac80211/tx.c8
7 files changed, 108 insertions, 134 deletions
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 1981058907b7..566bdca32b86 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -628,8 +628,8 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr)
628 /* Remove STA entry for the old peer */ 628 /* Remove STA entry for the old peer */
629 sta = sta_info_get(local, sdata->u.wds.remote_addr); 629 sta = sta_info_get(local, sdata->u.wds.remote_addr);
630 if (sta) { 630 if (sta) {
631 sta_info_free(sta);
631 sta_info_put(sta); 632 sta_info_put(sta);
632 sta_info_free(sta, 0);
633 } else { 633 } else {
634 printk(KERN_DEBUG "%s: could not find STA entry for WDS link " 634 printk(KERN_DEBUG "%s: could not find STA entry for WDS link "
635 "peer " MAC_FMT "\n", 635 "peer " MAC_FMT "\n",
@@ -776,13 +776,13 @@ static void ieee80211_stat_refresh(unsigned long data)
776 return; 776 return;
777 777
778 /* go through all stations */ 778 /* go through all stations */
779 spin_lock_bh(&local->sta_lock); 779 read_lock_bh(&local->sta_lock);
780 list_for_each_entry(sta, &local->sta_list, list) { 780 list_for_each_entry(sta, &local->sta_list, list) {
781 sta->channel_use = (sta->channel_use_raw / local->stat_time) / 781 sta->channel_use = (sta->channel_use_raw / local->stat_time) /
782 CHAN_UTIL_PER_10MS; 782 CHAN_UTIL_PER_10MS;
783 sta->channel_use_raw = 0; 783 sta->channel_use_raw = 0;
784 } 784 }
785 spin_unlock_bh(&local->sta_lock); 785 read_unlock_bh(&local->sta_lock);
786 786
787 /* go through all subinterfaces */ 787 /* go through all subinterfaces */
788 read_lock(&local->sub_if_lock); 788 read_lock(&local->sub_if_lock);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index ed00552b3418..e76a58678959 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -417,10 +417,9 @@ struct ieee80211_local {
417 struct sk_buff_head skb_queue_unreliable; 417 struct sk_buff_head skb_queue_unreliable;
418 418
419 /* Station data structures */ 419 /* Station data structures */
420 spinlock_t sta_lock; /* mutex for STA data structures */ 420 rwlock_t sta_lock; /* protects STA data structures */
421 int num_sta; /* number of stations in sta_list */ 421 int num_sta; /* number of stations in sta_list */
422 struct list_head sta_list; 422 struct list_head sta_list;
423 struct list_head deleted_sta_list;
424 struct sta_info *sta_hash[STA_HASH_SIZE]; 423 struct sta_info *sta_hash[STA_HASH_SIZE];
425 struct timer_list sta_cleanup; 424 struct timer_list sta_cleanup;
426 425
@@ -669,9 +668,9 @@ static inline void __bss_tim_set(struct ieee80211_if_ap *bss, int aid)
669static inline void bss_tim_set(struct ieee80211_local *local, 668static inline void bss_tim_set(struct ieee80211_local *local,
670 struct ieee80211_if_ap *bss, int aid) 669 struct ieee80211_if_ap *bss, int aid)
671{ 670{
672 spin_lock_bh(&local->sta_lock); 671 read_lock_bh(&local->sta_lock);
673 __bss_tim_set(bss, aid); 672 __bss_tim_set(bss, aid);
674 spin_unlock_bh(&local->sta_lock); 673 read_unlock_bh(&local->sta_lock);
675} 674}
676 675
677static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, int aid) 676static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, int aid)
@@ -686,9 +685,9 @@ static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, int aid)
686static inline void bss_tim_clear(struct ieee80211_local *local, 685static inline void bss_tim_clear(struct ieee80211_local *local,
687 struct ieee80211_if_ap *bss, int aid) 686 struct ieee80211_if_ap *bss, int aid)
688{ 687{
689 spin_lock_bh(&local->sta_lock); 688 read_lock_bh(&local->sta_lock);
690 __bss_tim_clear(bss, aid); 689 __bss_tim_clear(bss, aid);
691 spin_unlock_bh(&local->sta_lock); 690 read_unlock_bh(&local->sta_lock);
692} 691}
693 692
694/** 693/**
diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c
index 8532a5ccdd1e..6db67767801d 100644
--- a/net/mac80211/ieee80211_iface.c
+++ b/net/mac80211/ieee80211_iface.c
@@ -272,8 +272,8 @@ void ieee80211_if_reinit(struct net_device *dev)
272 case IEEE80211_IF_TYPE_WDS: 272 case IEEE80211_IF_TYPE_WDS:
273 sta = sta_info_get(local, sdata->u.wds.remote_addr); 273 sta = sta_info_get(local, sdata->u.wds.remote_addr);
274 if (sta) { 274 if (sta) {
275 sta_info_free(sta);
275 sta_info_put(sta); 276 sta_info_put(sta);
276 sta_info_free(sta, 0);
277 } else { 277 } else {
278#ifdef CONFIG_MAC80211_VERBOSE_DEBUG 278#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
279 printk(KERN_DEBUG "%s: Someone had deleted my STA " 279 printk(KERN_DEBUG "%s: Someone had deleted my STA "
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index 0d99b685df5f..9aee1abae127 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -773,7 +773,7 @@ static void ieee80211_associated(struct net_device *dev,
773 "range\n", 773 "range\n",
774 dev->name, MAC_ARG(ifsta->bssid)); 774 dev->name, MAC_ARG(ifsta->bssid));
775 disassoc = 1; 775 disassoc = 1;
776 sta_info_free(sta, 0); 776 sta_info_free(sta);
777 ifsta->probereq_poll = 0; 777 ifsta->probereq_poll = 0;
778 } else { 778 } else {
779 ieee80211_send_probe_req(dev, ifsta->bssid, 779 ieee80211_send_probe_req(dev, ifsta->bssid,
@@ -1890,7 +1890,7 @@ static int ieee80211_sta_active_ibss(struct net_device *dev)
1890 int active = 0; 1890 int active = 0;
1891 struct sta_info *sta; 1891 struct sta_info *sta;
1892 1892
1893 spin_lock_bh(&local->sta_lock); 1893 read_lock_bh(&local->sta_lock);
1894 list_for_each_entry(sta, &local->sta_list, list) { 1894 list_for_each_entry(sta, &local->sta_list, list) {
1895 if (sta->dev == dev && 1895 if (sta->dev == dev &&
1896 time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, 1896 time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL,
@@ -1899,7 +1899,7 @@ static int ieee80211_sta_active_ibss(struct net_device *dev)
1899 break; 1899 break;
1900 } 1900 }
1901 } 1901 }
1902 spin_unlock_bh(&local->sta_lock); 1902 read_unlock_bh(&local->sta_lock);
1903 1903
1904 return active; 1904 return active;
1905} 1905}
@@ -1909,16 +1909,24 @@ static void ieee80211_sta_expire(struct net_device *dev)
1909{ 1909{
1910 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); 1910 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
1911 struct sta_info *sta, *tmp; 1911 struct sta_info *sta, *tmp;
1912 LIST_HEAD(tmp_list);
1912 1913
1913 spin_lock_bh(&local->sta_lock); 1914 write_lock_bh(&local->sta_lock);
1914 list_for_each_entry_safe(sta, tmp, &local->sta_list, list) 1915 list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
1915 if (time_after(jiffies, sta->last_rx + 1916 if (time_after(jiffies, sta->last_rx +
1916 IEEE80211_IBSS_INACTIVITY_LIMIT)) { 1917 IEEE80211_IBSS_INACTIVITY_LIMIT)) {
1917 printk(KERN_DEBUG "%s: expiring inactive STA " MAC_FMT 1918 printk(KERN_DEBUG "%s: expiring inactive STA " MAC_FMT
1918 "\n", dev->name, MAC_ARG(sta->addr)); 1919 "\n", dev->name, MAC_ARG(sta->addr));
1919 sta_info_free(sta, 1); 1920 __sta_info_get(sta);
1921 sta_info_remove(sta);
1922 list_add(&sta->list, &tmp_list);
1920 } 1923 }
1921 spin_unlock_bh(&local->sta_lock); 1924 write_unlock_bh(&local->sta_lock);
1925
1926 list_for_each_entry_safe(sta, tmp, &tmp_list, list) {
1927 sta_info_free(sta);
1928 sta_info_put(sta);
1929 }
1922} 1930}
1923 1931
1924 1932
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index ab7b1f067c6e..34245b882c2b 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -32,38 +32,34 @@ static void sta_info_hash_add(struct ieee80211_local *local,
32 32
33 33
34/* Caller must hold local->sta_lock */ 34/* Caller must hold local->sta_lock */
35static void sta_info_hash_del(struct ieee80211_local *local, 35static int sta_info_hash_del(struct ieee80211_local *local,
36 struct sta_info *sta) 36 struct sta_info *sta)
37{ 37{
38 struct sta_info *s; 38 struct sta_info *s;
39 39
40 s = local->sta_hash[STA_HASH(sta->addr)]; 40 s = local->sta_hash[STA_HASH(sta->addr)];
41 if (!s) 41 if (!s)
42 return; 42 return -ENOENT;
43 if (memcmp(s->addr, sta->addr, ETH_ALEN) == 0) { 43 if (s == sta) {
44 local->sta_hash[STA_HASH(sta->addr)] = s->hnext; 44 local->sta_hash[STA_HASH(sta->addr)] = s->hnext;
45 return; 45 return 0;
46 } 46 }
47 47
48 while (s->hnext && memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0) 48 while (s->hnext && s->hnext != sta)
49 s = s->hnext; 49 s = s->hnext;
50 if (s->hnext) 50 if (s->hnext) {
51 s->hnext = s->hnext->hnext; 51 s->hnext = sta->hnext;
52 else 52 return 0;
53 printk(KERN_ERR "%s: could not remove STA " MAC_FMT " from " 53 }
54 "hash table\n", local->mdev->name, MAC_ARG(sta->addr));
55}
56 54
57static inline void __sta_info_get(struct sta_info *sta) 55 return -ENOENT;
58{
59 kref_get(&sta->kref);
60} 56}
61 57
62struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) 58struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr)
63{ 59{
64 struct sta_info *sta; 60 struct sta_info *sta;
65 61
66 spin_lock_bh(&local->sta_lock); 62 read_lock_bh(&local->sta_lock);
67 sta = local->sta_hash[STA_HASH(addr)]; 63 sta = local->sta_hash[STA_HASH(addr)];
68 while (sta) { 64 while (sta) {
69 if (memcmp(sta->addr, addr, ETH_ALEN) == 0) { 65 if (memcmp(sta->addr, addr, ETH_ALEN) == 0) {
@@ -72,7 +68,7 @@ struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr)
72 } 68 }
73 sta = sta->hnext; 69 sta = sta->hnext;
74 } 70 }
75 spin_unlock_bh(&local->sta_lock); 71 read_unlock_bh(&local->sta_lock);
76 72
77 return sta; 73 return sta;
78} 74}
@@ -85,7 +81,7 @@ int sta_info_min_txrate_get(struct ieee80211_local *local)
85 int min_txrate = 9999999; 81 int min_txrate = 9999999;
86 int i; 82 int i;
87 83
88 spin_lock_bh(&local->sta_lock); 84 read_lock_bh(&local->sta_lock);
89 mode = local->oper_hw_mode; 85 mode = local->oper_hw_mode;
90 for (i = 0; i < STA_HASH_SIZE; i++) { 86 for (i = 0; i < STA_HASH_SIZE; i++) {
91 sta = local->sta_hash[i]; 87 sta = local->sta_hash[i];
@@ -95,7 +91,7 @@ int sta_info_min_txrate_get(struct ieee80211_local *local)
95 sta = sta->hnext; 91 sta = sta->hnext;
96 } 92 }
97 } 93 }
98 spin_unlock_bh(&local->sta_lock); 94 read_unlock_bh(&local->sta_lock);
99 if (min_txrate == 9999999) 95 if (min_txrate == 9999999)
100 min_txrate = 0; 96 min_txrate = 0;
101 97
@@ -150,7 +146,6 @@ struct sta_info * sta_info_add(struct ieee80211_local *local,
150 sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, gfp); 146 sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, gfp);
151 if (!sta->rate_ctrl_priv) { 147 if (!sta->rate_ctrl_priv) {
152 rate_control_put(sta->rate_ctrl); 148 rate_control_put(sta->rate_ctrl);
153 kref_put(&sta->kref, sta_info_release);
154 kfree(sta); 149 kfree(sta);
155 return NULL; 150 return NULL;
156 } 151 }
@@ -162,14 +157,14 @@ struct sta_info * sta_info_add(struct ieee80211_local *local,
162 skb_queue_head_init(&sta->tx_filtered); 157 skb_queue_head_init(&sta->tx_filtered);
163 __sta_info_get(sta); /* sta used by caller, decremented by 158 __sta_info_get(sta); /* sta used by caller, decremented by
164 * sta_info_put() */ 159 * sta_info_put() */
165 spin_lock_bh(&local->sta_lock); 160 write_lock_bh(&local->sta_lock);
166 list_add(&sta->list, &local->sta_list); 161 list_add(&sta->list, &local->sta_list);
167 local->num_sta++; 162 local->num_sta++;
168 sta_info_hash_add(local, sta); 163 sta_info_hash_add(local, sta);
169 spin_unlock_bh(&local->sta_lock);
170 if (local->ops->sta_table_notification) 164 if (local->ops->sta_table_notification)
171 local->ops->sta_table_notification(local_to_hw(local), 165 local->ops->sta_table_notification(local_to_hw(local),
172 local->num_sta); 166 local->num_sta);
167 write_unlock_bh(&local->sta_lock);
173 sta->key_idx_compression = HW_KEY_IDX_INVALID; 168 sta->key_idx_compression = HW_KEY_IDX_INVALID;
174 169
175#ifdef CONFIG_MAC80211_VERBOSE_DEBUG 170#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
@@ -178,47 +173,25 @@ struct sta_info * sta_info_add(struct ieee80211_local *local,
178#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ 173#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
179 174
180#ifdef CONFIG_MAC80211_DEBUGFS 175#ifdef CONFIG_MAC80211_DEBUGFS
181 if (!in_interrupt()) { 176 /* debugfs entry adding might sleep, so schedule process
182 sta->debugfs_registered = 1; 177 * context task for adding entry for STAs that do not yet
183 ieee80211_sta_debugfs_add(sta); 178 * have one. */
184 rate_control_add_sta_debugfs(sta); 179 queue_work(local->hw.workqueue, &local->sta_debugfs_add);
185 } else {
186 /* debugfs entry adding might sleep, so schedule process
187 * context task for adding entry for STAs that do not yet
188 * have one. */
189 queue_work(local->hw.workqueue, &local->sta_debugfs_add);
190 }
191#endif 180#endif
192 181
193 return sta; 182 return sta;
194} 183}
195 184
196static void finish_sta_info_free(struct ieee80211_local *local, 185/* Caller must hold local->sta_lock */
197 struct sta_info *sta) 186void sta_info_remove(struct sta_info *sta)
198{
199#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
200 printk(KERN_DEBUG "%s: Removed STA " MAC_FMT "\n",
201 local->mdev->name, MAC_ARG(sta->addr));
202#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
203
204 if (sta->key) {
205 ieee80211_debugfs_key_remove(sta->key);
206 ieee80211_key_free(sta->key);
207 sta->key = NULL;
208 }
209
210 rate_control_remove_sta_debugfs(sta);
211 ieee80211_sta_debugfs_remove(sta);
212
213 sta_info_put(sta);
214}
215
216static void sta_info_remove(struct sta_info *sta)
217{ 187{
218 struct ieee80211_local *local = sta->local; 188 struct ieee80211_local *local = sta->local;
219 struct ieee80211_sub_if_data *sdata; 189 struct ieee80211_sub_if_data *sdata;
220 190
221 sta_info_hash_del(local, sta); 191 /* don't do anything if we've been removed already */
192 if (sta_info_hash_del(local, sta))
193 return;
194
222 list_del(&sta->list); 195 list_del(&sta->list);
223 sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); 196 sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
224 if (sta->flags & WLAN_STA_PS) { 197 if (sta->flags & WLAN_STA_PS) {
@@ -228,30 +201,29 @@ static void sta_info_remove(struct sta_info *sta)
228 } 201 }
229 local->num_sta--; 202 local->num_sta--;
230 sta_info_remove_aid_ptr(sta); 203 sta_info_remove_aid_ptr(sta);
204
205 if (local->ops->sta_table_notification)
206 local->ops->sta_table_notification(local_to_hw(local),
207 local->num_sta);
231} 208}
232 209
233void sta_info_free(struct sta_info *sta, int locked) 210void sta_info_free(struct sta_info *sta)
234{ 211{
235 struct sk_buff *skb; 212 struct sk_buff *skb;
236 struct ieee80211_local *local = sta->local; 213 struct ieee80211_local *local = sta->local;
237 214
238 if (!locked) { 215 might_sleep();
239 spin_lock_bh(&local->sta_lock); 216
240 sta_info_remove(sta); 217 write_lock_bh(&local->sta_lock);
241 spin_unlock_bh(&local->sta_lock); 218 sta_info_remove(sta);
242 } else { 219 write_unlock_bh(&local->sta_lock);
243 sta_info_remove(sta);
244 }
245 if (local->ops->sta_table_notification)
246 local->ops->sta_table_notification(local_to_hw(local),
247 local->num_sta);
248 220
249 while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { 221 while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
250 local->total_ps_buffered--; 222 local->total_ps_buffered--;
251 dev_kfree_skb_any(skb); 223 dev_kfree_skb(skb);
252 } 224 }
253 while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { 225 while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
254 dev_kfree_skb_any(skb); 226 dev_kfree_skb(skb);
255 } 227 }
256 228
257 if (sta->key) { 229 if (sta->key) {
@@ -276,13 +248,21 @@ void sta_info_free(struct sta_info *sta, int locked)
276 sta->key_idx_compression = HW_KEY_IDX_INVALID; 248 sta->key_idx_compression = HW_KEY_IDX_INVALID;
277 } 249 }
278 250
279#ifdef CONFIG_MAC80211_DEBUGFS 251#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
280 if (in_atomic()) { 252 printk(KERN_DEBUG "%s: Removed STA " MAC_FMT "\n",
281 list_add(&sta->list, &local->deleted_sta_list); 253 local->mdev->name, MAC_ARG(sta->addr));
282 queue_work(local->hw.workqueue, &local->sta_debugfs_add); 254#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
283 } else 255
284#endif 256 if (sta->key) {
285 finish_sta_info_free(local, sta); 257 ieee80211_debugfs_key_remove(sta->key);
258 ieee80211_key_free(sta->key);
259 sta->key = NULL;
260 }
261
262 rate_control_remove_sta_debugfs(sta);
263 ieee80211_sta_debugfs_remove(sta);
264
265 sta_info_put(sta);
286} 266}
287 267
288 268
@@ -343,13 +323,13 @@ static void sta_info_cleanup(unsigned long data)
343 struct ieee80211_local *local = (struct ieee80211_local *) data; 323 struct ieee80211_local *local = (struct ieee80211_local *) data;
344 struct sta_info *sta; 324 struct sta_info *sta;
345 325
346 spin_lock_bh(&local->sta_lock); 326 read_lock_bh(&local->sta_lock);
347 list_for_each_entry(sta, &local->sta_list, list) { 327 list_for_each_entry(sta, &local->sta_list, list) {
348 __sta_info_get(sta); 328 __sta_info_get(sta);
349 sta_info_cleanup_expire_buffered(local, sta); 329 sta_info_cleanup_expire_buffered(local, sta);
350 sta_info_put(sta); 330 sta_info_put(sta);
351 } 331 }
352 spin_unlock_bh(&local->sta_lock); 332 read_unlock_bh(&local->sta_lock);
353 333
354 local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL; 334 local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL;
355 add_timer(&local->sta_cleanup); 335 add_timer(&local->sta_cleanup);
@@ -363,35 +343,20 @@ static void sta_info_debugfs_add_task(struct work_struct *work)
363 struct sta_info *sta, *tmp; 343 struct sta_info *sta, *tmp;
364 344
365 while (1) { 345 while (1) {
366 spin_lock_bh(&local->sta_lock);
367 if (!list_empty(&local->deleted_sta_list)) {
368 sta = list_entry(local->deleted_sta_list.next,
369 struct sta_info, list);
370 list_del(local->deleted_sta_list.next);
371 } else
372 sta = NULL;
373 spin_unlock_bh(&local->sta_lock);
374 if (!sta)
375 break;
376 finish_sta_info_free(local, sta);
377 }
378
379 while (1) {
380 sta = NULL; 346 sta = NULL;
381 spin_lock_bh(&local->sta_lock); 347 read_lock_bh(&local->sta_lock);
382 list_for_each_entry(tmp, &local->sta_list, list) { 348 list_for_each_entry(tmp, &local->sta_list, list) {
383 if (!tmp->debugfs_registered) { 349 if (!tmp->debugfs.dir) {
384 sta = tmp; 350 sta = tmp;
385 __sta_info_get(sta); 351 __sta_info_get(sta);
386 break; 352 break;
387 } 353 }
388 } 354 }
389 spin_unlock_bh(&local->sta_lock); 355 read_unlock_bh(&local->sta_lock);
390 356
391 if (!sta) 357 if (!sta)
392 break; 358 break;
393 359
394 sta->debugfs_registered = 1;
395 ieee80211_sta_debugfs_add(sta); 360 ieee80211_sta_debugfs_add(sta);
396 rate_control_add_sta_debugfs(sta); 361 rate_control_add_sta_debugfs(sta);
397 sta_info_put(sta); 362 sta_info_put(sta);
@@ -401,9 +366,8 @@ static void sta_info_debugfs_add_task(struct work_struct *work)
401 366
402void sta_info_init(struct ieee80211_local *local) 367void sta_info_init(struct ieee80211_local *local)
403{ 368{
404 spin_lock_init(&local->sta_lock); 369 rwlock_init(&local->sta_lock);
405 INIT_LIST_HEAD(&local->sta_list); 370 INIT_LIST_HEAD(&local->sta_list);
406 INIT_LIST_HEAD(&local->deleted_sta_list);
407 371
408 init_timer(&local->sta_cleanup); 372 init_timer(&local->sta_cleanup);
409 local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL; 373 local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL;
@@ -423,17 +387,8 @@ int sta_info_start(struct ieee80211_local *local)
423 387
424void sta_info_stop(struct ieee80211_local *local) 388void sta_info_stop(struct ieee80211_local *local)
425{ 389{
426 struct sta_info *sta, *tmp;
427
428 del_timer(&local->sta_cleanup); 390 del_timer(&local->sta_cleanup);
429 391 sta_info_flush(local, NULL);
430 list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
431 /* sta_info_free must be called with 0 as the last
432 * parameter to ensure all debugfs sta entries are
433 * unregistered. We don't need locking at this
434 * point. */
435 sta_info_free(sta, 0);
436 }
437} 392}
438 393
439void sta_info_remove_aid_ptr(struct sta_info *sta) 394void sta_info_remove_aid_ptr(struct sta_info *sta)
@@ -461,10 +416,19 @@ void sta_info_remove_aid_ptr(struct sta_info *sta)
461void sta_info_flush(struct ieee80211_local *local, struct net_device *dev) 416void sta_info_flush(struct ieee80211_local *local, struct net_device *dev)
462{ 417{
463 struct sta_info *sta, *tmp; 418 struct sta_info *sta, *tmp;
419 LIST_HEAD(tmp_list);
464 420
465 spin_lock_bh(&local->sta_lock); 421 write_lock_bh(&local->sta_lock);
466 list_for_each_entry_safe(sta, tmp, &local->sta_list, list) 422 list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
467 if (!dev || dev == sta->dev) 423 if (!dev || dev == sta->dev) {
468 sta_info_free(sta, 1); 424 __sta_info_get(sta);
469 spin_unlock_bh(&local->sta_lock); 425 sta_info_remove(sta);
426 list_add_tail(&sta->list, &tmp_list);
427 }
428 write_unlock_bh(&local->sta_lock);
429
430 list_for_each_entry_safe(sta, tmp, &tmp_list, list) {
431 sta_info_free(sta);
432 sta_info_put(sta);
433 }
470} 434}
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index b5591d2f60a4..b5ef72379add 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -98,9 +98,6 @@ struct sta_info {
98 * filtering; used only if sta->key is not 98 * filtering; used only if sta->key is not
99 * set */ 99 * set */
100 100
101#ifdef CONFIG_MAC80211_DEBUGFS
102 int debugfs_registered;
103#endif
104 int assoc_ap; /* whether this is an AP that we are 101 int assoc_ap; /* whether this is an AP that we are
105 * associated with as a client */ 102 * associated with as a client */
106 103
@@ -149,12 +146,18 @@ struct sta_info {
149 */ 146 */
150#define STA_INFO_CLEANUP_INTERVAL (10 * HZ) 147#define STA_INFO_CLEANUP_INTERVAL (10 * HZ)
151 148
149static inline void __sta_info_get(struct sta_info *sta)
150{
151 kref_get(&sta->kref);
152}
153
152struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr); 154struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr);
153int sta_info_min_txrate_get(struct ieee80211_local *local); 155int sta_info_min_txrate_get(struct ieee80211_local *local);
154void sta_info_put(struct sta_info *sta); 156void sta_info_put(struct sta_info *sta);
155struct sta_info * sta_info_add(struct ieee80211_local *local, 157struct sta_info * sta_info_add(struct ieee80211_local *local,
156 struct net_device *dev, u8 *addr, gfp_t gfp); 158 struct net_device *dev, u8 *addr, gfp_t gfp);
157void sta_info_free(struct sta_info *sta, int locked); 159void sta_info_remove(struct sta_info *sta);
160void sta_info_free(struct sta_info *sta);
158void sta_info_init(struct ieee80211_local *local); 161void sta_info_init(struct ieee80211_local *local);
159int sta_info_start(struct ieee80211_local *local); 162int sta_info_start(struct ieee80211_local *local);
160void sta_info_stop(struct ieee80211_local *local); 163void sta_info_stop(struct ieee80211_local *local);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index dc128b412eab..2a1a7d457136 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -306,7 +306,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
306 } 306 }
307 read_unlock(&local->sub_if_lock); 307 read_unlock(&local->sub_if_lock);
308 308
309 spin_lock_bh(&local->sta_lock); 309 read_lock_bh(&local->sta_lock);
310 list_for_each_entry(sta, &local->sta_list, list) { 310 list_for_each_entry(sta, &local->sta_list, list) {
311 skb = skb_dequeue(&sta->ps_tx_buf); 311 skb = skb_dequeue(&sta->ps_tx_buf);
312 if (skb) { 312 if (skb) {
@@ -315,7 +315,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
315 } 315 }
316 total += skb_queue_len(&sta->ps_tx_buf); 316 total += skb_queue_len(&sta->ps_tx_buf);
317 } 317 }
318 spin_unlock_bh(&local->sta_lock); 318 read_unlock_bh(&local->sta_lock);
319 319
320 local->total_ps_buffered = total; 320 local->total_ps_buffered = total;
321 printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n", 321 printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n",
@@ -1629,7 +1629,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
1629 1629
1630 /* Generate bitmap for TIM only if there are any STAs in power save 1630 /* Generate bitmap for TIM only if there are any STAs in power save
1631 * mode. */ 1631 * mode. */
1632 spin_lock_bh(&local->sta_lock); 1632 read_lock_bh(&local->sta_lock);
1633 if (atomic_read(&bss->num_sta_ps) > 0) 1633 if (atomic_read(&bss->num_sta_ps) > 0)
1634 /* in the hope that this is faster than 1634 /* in the hope that this is faster than
1635 * checking byte-for-byte */ 1635 * checking byte-for-byte */
@@ -1680,7 +1680,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
1680 *pos++ = aid0; /* Bitmap control */ 1680 *pos++ = aid0; /* Bitmap control */
1681 *pos++ = 0; /* Part Virt Bitmap */ 1681 *pos++ = 0; /* Part Virt Bitmap */
1682 } 1682 }
1683 spin_unlock_bh(&local->sta_lock); 1683 read_unlock_bh(&local->sta_lock);
1684} 1684}
1685 1685
1686struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id, 1686struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id,