blob: b31a627ff97fecc4f0390e94c6a458d29819d8e8 [file] [log] [blame]
Jiri Bencf0706e822007-05-05 11:45:53 -07001/*
2 * Copyright 2002-2005, Instant802 Networks, Inc.
3 * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9
10#include <linux/module.h>
11#include <linux/init.h>
12#include <linux/netdevice.h>
13#include <linux/types.h>
14#include <linux/slab.h>
15#include <linux/skbuff.h>
16#include <linux/if_arp.h>
Johannes Berg0d174402007-12-17 15:07:43 +010017#include <linux/timer.h>
Jiri Bencf0706e822007-05-05 11:45:53 -070018
19#include <net/mac80211.h>
20#include "ieee80211_i.h"
21#include "ieee80211_rate.h"
22#include "sta_info.h"
Jiri Bence9f207f2007-05-05 11:46:38 -070023#include "debugfs_sta.h"
Jiri Bencf0706e822007-05-05 11:45:53 -070024
25/* Caller must hold local->sta_lock */
26static void sta_info_hash_add(struct ieee80211_local *local,
27 struct sta_info *sta)
28{
29 sta->hnext = local->sta_hash[STA_HASH(sta->addr)];
30 local->sta_hash[STA_HASH(sta->addr)] = sta;
31}
32
33
34/* Caller must hold local->sta_lock */
Michael Wube8755e2007-07-27 15:43:23 +020035static int sta_info_hash_del(struct ieee80211_local *local,
36 struct sta_info *sta)
Jiri Bencf0706e822007-05-05 11:45:53 -070037{
38 struct sta_info *s;
39
40 s = local->sta_hash[STA_HASH(sta->addr)];
41 if (!s)
Michael Wube8755e2007-07-27 15:43:23 +020042 return -ENOENT;
43 if (s == sta) {
Jiri Bencf0706e822007-05-05 11:45:53 -070044 local->sta_hash[STA_HASH(sta->addr)] = s->hnext;
Michael Wube8755e2007-07-27 15:43:23 +020045 return 0;
Jiri Bencf0706e822007-05-05 11:45:53 -070046 }
47
Michael Wube8755e2007-07-27 15:43:23 +020048 while (s->hnext && s->hnext != sta)
Jiri Bencf0706e822007-05-05 11:45:53 -070049 s = s->hnext;
Michael Wube8755e2007-07-27 15:43:23 +020050 if (s->hnext) {
51 s->hnext = sta->hnext;
52 return 0;
53 }
Jiri Bencf0706e822007-05-05 11:45:53 -070054
Michael Wube8755e2007-07-27 15:43:23 +020055 return -ENOENT;
Jiri Bencf0706e822007-05-05 11:45:53 -070056}
57
58struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr)
59{
60 struct sta_info *sta;
61
Michael Wube8755e2007-07-27 15:43:23 +020062 read_lock_bh(&local->sta_lock);
Jiri Bencf0706e822007-05-05 11:45:53 -070063 sta = local->sta_hash[STA_HASH(addr)];
64 while (sta) {
65 if (memcmp(sta->addr, addr, ETH_ALEN) == 0) {
66 __sta_info_get(sta);
67 break;
68 }
69 sta = sta->hnext;
70 }
Michael Wube8755e2007-07-27 15:43:23 +020071 read_unlock_bh(&local->sta_lock);
Jiri Bencf0706e822007-05-05 11:45:53 -070072
73 return sta;
74}
75EXPORT_SYMBOL(sta_info_get);
76
Jiri Bencf0706e822007-05-05 11:45:53 -070077
78static void sta_info_release(struct kref *kref)
79{
80 struct sta_info *sta = container_of(kref, struct sta_info, kref);
81 struct ieee80211_local *local = sta->local;
82 struct sk_buff *skb;
Ron Rindjunsky07db2182007-12-25 17:00:33 +020083 int i;
Jiri Bencf0706e822007-05-05 11:45:53 -070084
85 /* free sta structure; it has already been removed from
86 * hash table etc. external structures. Make sure that all
87 * buffered frames are release (one might have been added
88 * after sta_info_free() was called). */
89 while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
90 local->total_ps_buffered--;
91 dev_kfree_skb_any(skb);
92 }
93 while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
94 dev_kfree_skb_any(skb);
95 }
Ron Rindjunskyfe3bf0f2008-01-28 14:07:19 +020096 for (i = 0; i < STA_TID_NUM; i++) {
Ron Rindjunsky07db2182007-12-25 17:00:33 +020097 del_timer_sync(&sta->ampdu_mlme.tid_rx[i].session_timer);
Ron Rindjunskyfe3bf0f2008-01-28 14:07:19 +020098 del_timer_sync(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer);
99 }
Jiri Bencf0706e822007-05-05 11:45:53 -0700100 rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv);
101 rate_control_put(sta->rate_ctrl);
102 kfree(sta);
103}
104
105
106void sta_info_put(struct sta_info *sta)
107{
108 kref_put(&sta->kref, sta_info_release);
109}
110EXPORT_SYMBOL(sta_info_put);
111
112
113struct sta_info * sta_info_add(struct ieee80211_local *local,
114 struct net_device *dev, u8 *addr, gfp_t gfp)
115{
116 struct sta_info *sta;
Ron Rindjunsky16c5f152007-12-25 17:00:34 +0200117 int i;
Joe Perches0795af52007-10-03 17:59:30 -0700118 DECLARE_MAC_BUF(mac);
Jiri Bencf0706e822007-05-05 11:45:53 -0700119
120 sta = kzalloc(sizeof(*sta), gfp);
121 if (!sta)
122 return NULL;
123
124 kref_init(&sta->kref);
125
126 sta->rate_ctrl = rate_control_get(local->rate_ctrl);
127 sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, gfp);
128 if (!sta->rate_ctrl_priv) {
129 rate_control_put(sta->rate_ctrl);
Jiri Bencf0706e822007-05-05 11:45:53 -0700130 kfree(sta);
131 return NULL;
132 }
133
134 memcpy(sta->addr, addr, ETH_ALEN);
135 sta->local = local;
136 sta->dev = dev;
Ron Rindjunsky16c5f152007-12-25 17:00:34 +0200137 spin_lock_init(&sta->ampdu_mlme.ampdu_rx);
Ron Rindjunskyfe3bf0f2008-01-28 14:07:19 +0200138 spin_lock_init(&sta->ampdu_mlme.ampdu_tx);
Ron Rindjunsky16c5f152007-12-25 17:00:34 +0200139 for (i = 0; i < STA_TID_NUM; i++) {
140 /* timer_to_tid must be initialized with identity mapping to
141 * enable session_timer's data differentiation. refer to
142 * sta_rx_agg_session_timer_expired for useage */
143 sta->timer_to_tid[i] = i;
Ron Rindjunskyfe3bf0f2008-01-28 14:07:19 +0200144 /* tid to tx queue: initialize according to HW (0 is valid) */
145 sta->tid_to_tx_q[i] = local->hw.queues;
Ron Rindjunsky16c5f152007-12-25 17:00:34 +0200146 /* rx timers */
147 sta->ampdu_mlme.tid_rx[i].session_timer.function =
148 sta_rx_agg_session_timer_expired;
149 sta->ampdu_mlme.tid_rx[i].session_timer.data =
150 (unsigned long)&sta->timer_to_tid[i];
151 init_timer(&sta->ampdu_mlme.tid_rx[i].session_timer);
Ron Rindjunskyfe3bf0f2008-01-28 14:07:19 +0200152 /* tx timers */
153 sta->ampdu_mlme.tid_tx[i].addba_resp_timer.function =
154 sta_addba_resp_timer_expired;
155 sta->ampdu_mlme.tid_tx[i].addba_resp_timer.data =
156 (unsigned long)&sta->timer_to_tid[i];
157 init_timer(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer);
Ron Rindjunsky16c5f152007-12-25 17:00:34 +0200158 }
Jiri Bencf0706e822007-05-05 11:45:53 -0700159 skb_queue_head_init(&sta->ps_tx_buf);
160 skb_queue_head_init(&sta->tx_filtered);
161 __sta_info_get(sta); /* sta used by caller, decremented by
162 * sta_info_put() */
Michael Wube8755e2007-07-27 15:43:23 +0200163 write_lock_bh(&local->sta_lock);
Jiri Bencf0706e822007-05-05 11:45:53 -0700164 list_add(&sta->list, &local->sta_list);
165 local->num_sta++;
166 sta_info_hash_add(local, sta);
Johannes Berg32bfd352007-12-19 01:31:26 +0100167 if (local->ops->sta_notify) {
168 struct ieee80211_sub_if_data *sdata;
169
170 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
Johannes Berg51fb61e2007-12-19 01:31:27 +0100171 if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
Johannes Berg32bfd352007-12-19 01:31:26 +0100172 sdata = sdata->u.vlan.ap;
173
174 local->ops->sta_notify(local_to_hw(local), &sdata->vif,
175 STA_NOTIFY_ADD, addr);
176 }
Michael Wube8755e2007-07-27 15:43:23 +0200177 write_unlock_bh(&local->sta_lock);
Jiri Bencf0706e822007-05-05 11:45:53 -0700178
179#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
Joe Perches0795af52007-10-03 17:59:30 -0700180 printk(KERN_DEBUG "%s: Added STA %s\n",
Johannes Bergdd1cd4c2007-09-18 17:29:20 -0400181 wiphy_name(local->hw.wiphy), print_mac(mac, addr));
Jiri Bencf0706e822007-05-05 11:45:53 -0700182#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
183
Jiri Bence9f207f2007-05-05 11:46:38 -0700184#ifdef CONFIG_MAC80211_DEBUGFS
Michael Wube8755e2007-07-27 15:43:23 +0200185 /* debugfs entry adding might sleep, so schedule process
186 * context task for adding entry for STAs that do not yet
187 * have one. */
188 queue_work(local->hw.workqueue, &local->sta_debugfs_add);
Jiri Bence9f207f2007-05-05 11:46:38 -0700189#endif
190
Jiri Bencf0706e822007-05-05 11:45:53 -0700191 return sta;
192}
193
Johannes Berg004c8722008-02-20 11:21:35 +0100194static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid)
195{
196 /*
197 * This format has been mandated by the IEEE specifications,
198 * so this line may not be changed to use the __set_bit() format.
199 */
200 bss->tim[aid / 8] |= (1 << (aid % 8));
201}
202
203static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid)
204{
205 /*
206 * This format has been mandated by the IEEE specifications,
207 * so this line may not be changed to use the __clear_bit() format.
208 */
209 bss->tim[aid / 8] &= ~(1 << (aid % 8));
210}
211
212static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss,
213 struct sta_info *sta)
214{
215 if (bss)
216 __bss_tim_set(bss, sta->aid);
217 if (sta->local->ops->set_tim)
218 sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 1);
219}
220
221void sta_info_set_tim_bit(struct sta_info *sta)
222{
223 struct ieee80211_sub_if_data *sdata;
224
225 sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
226
227 read_lock_bh(&sta->local->sta_lock);
228 __sta_info_set_tim_bit(sdata->bss, sta);
229 read_unlock_bh(&sta->local->sta_lock);
230}
231
232static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss,
233 struct sta_info *sta)
234{
235 if (bss)
236 __bss_tim_clear(bss, sta->aid);
237 if (sta->local->ops->set_tim)
238 sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 0);
239}
240
241void sta_info_clear_tim_bit(struct sta_info *sta)
242{
243 struct ieee80211_sub_if_data *sdata;
244
245 sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
246
247 read_lock_bh(&sta->local->sta_lock);
248 __sta_info_clear_tim_bit(sdata->bss, sta);
249 read_unlock_bh(&sta->local->sta_lock);
250}
251
Michael Wube8755e2007-07-27 15:43:23 +0200252/* Caller must hold local->sta_lock */
253void sta_info_remove(struct sta_info *sta)
Jiri Bencf0706e822007-05-05 11:45:53 -0700254{
255 struct ieee80211_local *local = sta->local;
256 struct ieee80211_sub_if_data *sdata;
257
Michael Wube8755e2007-07-27 15:43:23 +0200258 /* don't do anything if we've been removed already */
259 if (sta_info_hash_del(local, sta))
260 return;
261
Jiri Bencf0706e822007-05-05 11:45:53 -0700262 list_del(&sta->list);
263 sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
264 if (sta->flags & WLAN_STA_PS) {
265 sta->flags &= ~WLAN_STA_PS;
266 if (sdata->bss)
267 atomic_dec(&sdata->bss->num_sta_ps);
Johannes Berg004c8722008-02-20 11:21:35 +0100268 __sta_info_clear_tim_bit(sdata->bss, sta);
Jiri Bencf0706e822007-05-05 11:45:53 -0700269 }
270 local->num_sta--;
Jiri Bencf0706e822007-05-05 11:45:53 -0700271}
272
Michael Wube8755e2007-07-27 15:43:23 +0200273void sta_info_free(struct sta_info *sta)
Jiri Bencf0706e822007-05-05 11:45:53 -0700274{
275 struct sk_buff *skb;
276 struct ieee80211_local *local = sta->local;
Joe Perches0795af52007-10-03 17:59:30 -0700277 DECLARE_MAC_BUF(mac);
Jiri Bencf0706e822007-05-05 11:45:53 -0700278
Michael Wube8755e2007-07-27 15:43:23 +0200279 might_sleep();
280
281 write_lock_bh(&local->sta_lock);
282 sta_info_remove(sta);
283 write_unlock_bh(&local->sta_lock);
Jiri Bencf0706e822007-05-05 11:45:53 -0700284
285 while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
286 local->total_ps_buffered--;
Michael Wube8755e2007-07-27 15:43:23 +0200287 dev_kfree_skb(skb);
Jiri Bencf0706e822007-05-05 11:45:53 -0700288 }
289 while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
Michael Wube8755e2007-07-27 15:43:23 +0200290 dev_kfree_skb(skb);
Jiri Bencf0706e822007-05-05 11:45:53 -0700291 }
292
Michael Wube8755e2007-07-27 15:43:23 +0200293#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
Joe Perches0795af52007-10-03 17:59:30 -0700294 printk(KERN_DEBUG "%s: Removed STA %s\n",
Johannes Bergdd1cd4c2007-09-18 17:29:20 -0400295 wiphy_name(local->hw.wiphy), print_mac(mac, sta->addr));
Michael Wube8755e2007-07-27 15:43:23 +0200296#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
297
Johannes Berg11a843b2007-08-28 17:01:55 -0400298 ieee80211_key_free(sta->key);
299 sta->key = NULL;
Michael Wube8755e2007-07-27 15:43:23 +0200300
Johannes Berg32bfd352007-12-19 01:31:26 +0100301 if (local->ops->sta_notify) {
302 struct ieee80211_sub_if_data *sdata;
303
304 sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
305
Johannes Berg51fb61e2007-12-19 01:31:27 +0100306 if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
Johannes Berg32bfd352007-12-19 01:31:26 +0100307 sdata = sdata->u.vlan.ap;
308
309 local->ops->sta_notify(local_to_hw(local), &sdata->vif,
310 STA_NOTIFY_REMOVE, sta->addr);
311 }
Tomas Winkler478f8d22007-09-30 13:52:37 +0200312
Michael Wube8755e2007-07-27 15:43:23 +0200313 rate_control_remove_sta_debugfs(sta);
314 ieee80211_sta_debugfs_remove(sta);
315
316 sta_info_put(sta);
Jiri Bencf0706e822007-05-05 11:45:53 -0700317}
318
319
320static inline int sta_info_buffer_expired(struct ieee80211_local *local,
321 struct sta_info *sta,
322 struct sk_buff *skb)
323{
324 struct ieee80211_tx_packet_data *pkt_data;
325 int timeout;
326
327 if (!skb)
328 return 0;
329
330 pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
331
332 /* Timeout: (2 * listen_interval * beacon_int * 1024 / 1000000) sec */
333 timeout = (sta->listen_interval * local->hw.conf.beacon_int * 32 /
334 15625) * HZ;
335 if (timeout < STA_TX_BUFFER_EXPIRE)
336 timeout = STA_TX_BUFFER_EXPIRE;
337 return time_after(jiffies, pkt_data->jiffies + timeout);
338}
339
340
341static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
342 struct sta_info *sta)
343{
344 unsigned long flags;
345 struct sk_buff *skb;
Johannes Berg836341a2008-02-20 02:07:21 +0100346 struct ieee80211_sub_if_data *sdata;
Joe Perches0795af52007-10-03 17:59:30 -0700347 DECLARE_MAC_BUF(mac);
Jiri Bencf0706e822007-05-05 11:45:53 -0700348
349 if (skb_queue_empty(&sta->ps_tx_buf))
350 return;
351
352 for (;;) {
353 spin_lock_irqsave(&sta->ps_tx_buf.lock, flags);
354 skb = skb_peek(&sta->ps_tx_buf);
Johannes Berg836341a2008-02-20 02:07:21 +0100355 if (sta_info_buffer_expired(local, sta, skb))
Jiri Bencf0706e822007-05-05 11:45:53 -0700356 skb = __skb_dequeue(&sta->ps_tx_buf);
Johannes Berg836341a2008-02-20 02:07:21 +0100357 else
Jiri Bencf0706e822007-05-05 11:45:53 -0700358 skb = NULL;
359 spin_unlock_irqrestore(&sta->ps_tx_buf.lock, flags);
360
Johannes Berg836341a2008-02-20 02:07:21 +0100361 if (!skb)
Jiri Bencf0706e822007-05-05 11:45:53 -0700362 break;
Johannes Berg836341a2008-02-20 02:07:21 +0100363
364 sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
365 local->total_ps_buffered--;
366 printk(KERN_DEBUG "Buffered frame expired (STA "
367 "%s)\n", print_mac(mac, sta->addr));
368 dev_kfree_skb(skb);
369
Johannes Berg004c8722008-02-20 11:21:35 +0100370 if (skb_queue_empty(&sta->ps_tx_buf))
371 sta_info_clear_tim_bit(sta);
Jiri Bencf0706e822007-05-05 11:45:53 -0700372 }
373}
374
375
376static void sta_info_cleanup(unsigned long data)
377{
378 struct ieee80211_local *local = (struct ieee80211_local *) data;
379 struct sta_info *sta;
380
Michael Wube8755e2007-07-27 15:43:23 +0200381 read_lock_bh(&local->sta_lock);
Jiri Bencf0706e822007-05-05 11:45:53 -0700382 list_for_each_entry(sta, &local->sta_list, list) {
383 __sta_info_get(sta);
384 sta_info_cleanup_expire_buffered(local, sta);
385 sta_info_put(sta);
386 }
Michael Wube8755e2007-07-27 15:43:23 +0200387 read_unlock_bh(&local->sta_lock);
Jiri Bencf0706e822007-05-05 11:45:53 -0700388
Johannes Berg0d174402007-12-17 15:07:43 +0100389 local->sta_cleanup.expires =
390 round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL);
Jiri Bencf0706e822007-05-05 11:45:53 -0700391 add_timer(&local->sta_cleanup);
392}
393
Jiri Bence9f207f2007-05-05 11:46:38 -0700394#ifdef CONFIG_MAC80211_DEBUGFS
395static void sta_info_debugfs_add_task(struct work_struct *work)
396{
397 struct ieee80211_local *local =
398 container_of(work, struct ieee80211_local, sta_debugfs_add);
399 struct sta_info *sta, *tmp;
400
401 while (1) {
Jiri Bence9f207f2007-05-05 11:46:38 -0700402 sta = NULL;
Michael Wube8755e2007-07-27 15:43:23 +0200403 read_lock_bh(&local->sta_lock);
Jiri Bence9f207f2007-05-05 11:46:38 -0700404 list_for_each_entry(tmp, &local->sta_list, list) {
Michael Wube8755e2007-07-27 15:43:23 +0200405 if (!tmp->debugfs.dir) {
Jiri Bence9f207f2007-05-05 11:46:38 -0700406 sta = tmp;
407 __sta_info_get(sta);
408 break;
409 }
410 }
Michael Wube8755e2007-07-27 15:43:23 +0200411 read_unlock_bh(&local->sta_lock);
Jiri Bence9f207f2007-05-05 11:46:38 -0700412
413 if (!sta)
414 break;
415
Jiri Bence9f207f2007-05-05 11:46:38 -0700416 ieee80211_sta_debugfs_add(sta);
417 rate_control_add_sta_debugfs(sta);
418 sta_info_put(sta);
419 }
420}
421#endif
422
Jiri Bencf0706e822007-05-05 11:45:53 -0700423void sta_info_init(struct ieee80211_local *local)
424{
Michael Wube8755e2007-07-27 15:43:23 +0200425 rwlock_init(&local->sta_lock);
Jiri Bencf0706e822007-05-05 11:45:53 -0700426 INIT_LIST_HEAD(&local->sta_list);
Jiri Bencf0706e822007-05-05 11:45:53 -0700427
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800428 setup_timer(&local->sta_cleanup, sta_info_cleanup,
429 (unsigned long)local);
Johannes Berg0d174402007-12-17 15:07:43 +0100430 local->sta_cleanup.expires =
431 round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL);
Jiri Bence9f207f2007-05-05 11:46:38 -0700432
433#ifdef CONFIG_MAC80211_DEBUGFS
434 INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_task);
435#endif
Jiri Bencf0706e822007-05-05 11:45:53 -0700436}
437
438int sta_info_start(struct ieee80211_local *local)
439{
440 add_timer(&local->sta_cleanup);
441 return 0;
442}
443
444void sta_info_stop(struct ieee80211_local *local)
445{
Jiri Bencf0706e822007-05-05 11:45:53 -0700446 del_timer(&local->sta_cleanup);
Michael Wube8755e2007-07-27 15:43:23 +0200447 sta_info_flush(local, NULL);
Jiri Bencf0706e822007-05-05 11:45:53 -0700448}
449
Jiri Bencf0706e822007-05-05 11:45:53 -0700450/**
451 * sta_info_flush - flush matching STA entries from the STA table
452 * @local: local interface data
453 * @dev: matching rule for the net device (sta->dev) or %NULL to match all STAs
454 */
455void sta_info_flush(struct ieee80211_local *local, struct net_device *dev)
456{
457 struct sta_info *sta, *tmp;
Michael Wube8755e2007-07-27 15:43:23 +0200458 LIST_HEAD(tmp_list);
Jiri Bencf0706e822007-05-05 11:45:53 -0700459
Michael Wube8755e2007-07-27 15:43:23 +0200460 write_lock_bh(&local->sta_lock);
Jiri Bencf0706e822007-05-05 11:45:53 -0700461 list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
Michael Wube8755e2007-07-27 15:43:23 +0200462 if (!dev || dev == sta->dev) {
463 __sta_info_get(sta);
464 sta_info_remove(sta);
465 list_add_tail(&sta->list, &tmp_list);
466 }
467 write_unlock_bh(&local->sta_lock);
468
469 list_for_each_entry_safe(sta, tmp, &tmp_list, list) {
470 sta_info_free(sta);
471 sta_info_put(sta);
472 }
Jiri Bencf0706e822007-05-05 11:45:53 -0700473}