diff options
Diffstat (limited to 'net/mac80211/sta_info.c')
-rw-r--r-- | net/mac80211/sta_info.c | 387 |
1 files changed, 240 insertions, 147 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 81c4e3392f40..ee5b66abc0f1 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/skbuff.h> | 15 | #include <linux/skbuff.h> |
16 | #include <linux/if_arp.h> | 16 | #include <linux/if_arp.h> |
17 | #include <linux/timer.h> | 17 | #include <linux/timer.h> |
18 | #include <linux/rtnetlink.h> | ||
18 | 19 | ||
19 | #include <net/mac80211.h> | 20 | #include <net/mac80211.h> |
20 | #include "ieee80211_i.h" | 21 | #include "ieee80211_i.h" |
@@ -23,14 +24,43 @@ | |||
23 | #include "debugfs_sta.h" | 24 | #include "debugfs_sta.h" |
24 | #include "mesh.h" | 25 | #include "mesh.h" |
25 | 26 | ||
26 | /* Caller must hold local->sta_lock */ | 27 | /** |
27 | static void sta_info_hash_add(struct ieee80211_local *local, | 28 | * DOC: STA information lifetime rules |
28 | struct sta_info *sta) | 29 | * |
29 | { | 30 | * STA info structures (&struct sta_info) are managed in a hash table |
30 | sta->hnext = local->sta_hash[STA_HASH(sta->addr)]; | 31 | * for faster lookup and a list for iteration. They are managed using |
31 | local->sta_hash[STA_HASH(sta->addr)] = sta; | 32 | * RCU, i.e. access to the list and hash table is protected by RCU. |
32 | } | 33 | * |
33 | 34 | * STA info structures are always "alive" when they are added with | |
35 | * @sta_info_add() [this may be changed in the future to allow allocating | ||
36 | * outside of a critical section!], they are then added to the hash | ||
37 | * table and list. Therefore, @sta_info_add() must also be RCU protected, | ||
38 | * also, the caller of @sta_info_add() cannot assume that it owns the | ||
39 | * structure. | ||
40 | * | ||
41 | * Because there are debugfs entries for each station, and adding those | ||
42 | * must be able to sleep, it is also possible to "pin" a station entry, | ||
43 | * that means it can be removed from the hash table but not be freed. | ||
44 | * See the comment in @__sta_info_unlink() for more information. | ||
45 | * | ||
46 | * In order to remove a STA info structure, the caller needs to first | ||
47 | * unlink it (@sta_info_unlink()) from the list and hash tables and | ||
48 | * then wait for an RCU synchronisation before it can be freed. Due to | ||
49 | * the pinning and the possibility of multiple callers trying to remove | ||
50 | * the same STA info at the same time, @sta_info_unlink() can clear the | ||
51 | * STA info pointer it is passed to indicate that the STA info is owned | ||
52 | * by somebody else now. | ||
53 | * | ||
54 | * If @sta_info_unlink() did not clear the pointer then the caller owns | ||
55 | * the STA info structure now and is responsible of destroying it with | ||
56 | * a call to @sta_info_destroy(), not before RCU synchronisation, of | ||
57 | * course. Note that sta_info_destroy() must be protected by the RTNL. | ||
58 | * | ||
59 | * In all other cases, there is no concept of ownership on a STA entry, | ||
60 | * each structure is owned by the global hash table/list until it is | ||
61 | * removed. All users of the structure need to be RCU protected so that | ||
62 | * the structure won't be freed before they are done using it. | ||
63 | */ | ||
34 | 64 | ||
35 | /* Caller must hold local->sta_lock */ | 65 | /* Caller must hold local->sta_lock */ |
36 | static int sta_info_hash_del(struct ieee80211_local *local, | 66 | static int sta_info_hash_del(struct ieee80211_local *local, |
@@ -42,46 +72,39 @@ static int sta_info_hash_del(struct ieee80211_local *local, | |||
42 | if (!s) | 72 | if (!s) |
43 | return -ENOENT; | 73 | return -ENOENT; |
44 | if (s == sta) { | 74 | if (s == sta) { |
45 | local->sta_hash[STA_HASH(sta->addr)] = s->hnext; | 75 | rcu_assign_pointer(local->sta_hash[STA_HASH(sta->addr)], |
76 | s->hnext); | ||
46 | return 0; | 77 | return 0; |
47 | } | 78 | } |
48 | 79 | ||
49 | while (s->hnext && s->hnext != sta) | 80 | while (s->hnext && s->hnext != sta) |
50 | s = s->hnext; | 81 | s = s->hnext; |
51 | if (s->hnext) { | 82 | if (s->hnext) { |
52 | s->hnext = sta->hnext; | 83 | rcu_assign_pointer(s->hnext, sta->hnext); |
53 | return 0; | 84 | return 0; |
54 | } | 85 | } |
55 | 86 | ||
56 | return -ENOENT; | 87 | return -ENOENT; |
57 | } | 88 | } |
58 | 89 | ||
59 | /* must hold local->sta_lock */ | 90 | /* protected by RCU */ |
60 | static struct sta_info *__sta_info_find(struct ieee80211_local *local, | 91 | static struct sta_info *__sta_info_find(struct ieee80211_local *local, |
61 | u8 *addr) | 92 | u8 *addr) |
62 | { | 93 | { |
63 | struct sta_info *sta; | 94 | struct sta_info *sta; |
64 | 95 | ||
65 | sta = local->sta_hash[STA_HASH(addr)]; | 96 | sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]); |
66 | while (sta) { | 97 | while (sta) { |
67 | if (compare_ether_addr(sta->addr, addr) == 0) | 98 | if (compare_ether_addr(sta->addr, addr) == 0) |
68 | break; | 99 | break; |
69 | sta = sta->hnext; | 100 | sta = rcu_dereference(sta->hnext); |
70 | } | 101 | } |
71 | return sta; | 102 | return sta; |
72 | } | 103 | } |
73 | 104 | ||
74 | struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) | 105 | struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) |
75 | { | 106 | { |
76 | struct sta_info *sta; | 107 | return __sta_info_find(local, addr); |
77 | |||
78 | read_lock_bh(&local->sta_lock); | ||
79 | sta = __sta_info_find(local, addr); | ||
80 | if (sta) | ||
81 | __sta_info_get(sta); | ||
82 | read_unlock_bh(&local->sta_lock); | ||
83 | |||
84 | return sta; | ||
85 | } | 108 | } |
86 | EXPORT_SYMBOL(sta_info_get); | 109 | EXPORT_SYMBOL(sta_info_get); |
87 | 110 | ||
@@ -91,81 +114,101 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, | |||
91 | struct sta_info *sta; | 114 | struct sta_info *sta; |
92 | int i = 0; | 115 | int i = 0; |
93 | 116 | ||
94 | read_lock_bh(&local->sta_lock); | 117 | list_for_each_entry_rcu(sta, &local->sta_list, list) { |
95 | list_for_each_entry(sta, &local->sta_list, list) { | ||
96 | if (i < idx) { | 118 | if (i < idx) { |
97 | ++i; | 119 | ++i; |
98 | continue; | 120 | continue; |
99 | } else if (!dev || dev == sta->dev) { | 121 | } else if (!dev || dev == sta->sdata->dev) { |
100 | __sta_info_get(sta); | ||
101 | read_unlock_bh(&local->sta_lock); | ||
102 | return sta; | 122 | return sta; |
103 | } | 123 | } |
104 | } | 124 | } |
105 | read_unlock_bh(&local->sta_lock); | ||
106 | 125 | ||
107 | return NULL; | 126 | return NULL; |
108 | } | 127 | } |
109 | 128 | ||
110 | static void sta_info_release(struct kref *kref) | 129 | void sta_info_destroy(struct sta_info *sta) |
111 | { | 130 | { |
112 | struct sta_info *sta = container_of(kref, struct sta_info, kref); | ||
113 | struct ieee80211_local *local = sta->local; | 131 | struct ieee80211_local *local = sta->local; |
114 | struct sk_buff *skb; | 132 | struct sk_buff *skb; |
115 | int i; | 133 | int i; |
116 | 134 | ||
117 | /* free sta structure; it has already been removed from | 135 | ASSERT_RTNL(); |
118 | * hash table etc. external structures. Make sure that all | 136 | might_sleep(); |
119 | * buffered frames are release (one might have been added | 137 | |
120 | * after sta_info_free() was called). */ | 138 | rate_control_remove_sta_debugfs(sta); |
139 | ieee80211_sta_debugfs_remove(sta); | ||
140 | |||
141 | #ifdef CONFIG_MAC80211_MESH | ||
142 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) | ||
143 | mesh_plink_deactivate(sta); | ||
144 | #endif | ||
145 | |||
146 | /* | ||
147 | * NOTE: This will call synchronize_rcu() internally to | ||
148 | * make sure no key references can be in use. We rely on | ||
149 | * that here for the mesh code! | ||
150 | */ | ||
151 | ieee80211_key_free(sta->key); | ||
152 | WARN_ON(sta->key); | ||
153 | |||
154 | #ifdef CONFIG_MAC80211_MESH | ||
155 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) | ||
156 | del_timer_sync(&sta->plink_timer); | ||
157 | #endif | ||
158 | |||
121 | while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { | 159 | while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { |
122 | local->total_ps_buffered--; | 160 | local->total_ps_buffered--; |
123 | dev_kfree_skb_any(skb); | 161 | dev_kfree_skb_any(skb); |
124 | } | 162 | } |
125 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { | 163 | |
164 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) | ||
126 | dev_kfree_skb_any(skb); | 165 | dev_kfree_skb_any(skb); |
127 | } | 166 | |
128 | for (i = 0; i < STA_TID_NUM; i++) { | 167 | for (i = 0; i < STA_TID_NUM; i++) { |
129 | del_timer_sync(&sta->ampdu_mlme.tid_rx[i].session_timer); | 168 | del_timer_sync(&sta->ampdu_mlme.tid_rx[i].session_timer); |
130 | del_timer_sync(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer); | 169 | del_timer_sync(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer); |
131 | } | 170 | } |
132 | rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); | 171 | rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); |
133 | rate_control_put(sta->rate_ctrl); | 172 | rate_control_put(sta->rate_ctrl); |
173 | |||
134 | kfree(sta); | 174 | kfree(sta); |
135 | } | 175 | } |
136 | 176 | ||
137 | 177 | ||
138 | void sta_info_put(struct sta_info *sta) | 178 | /* Caller must hold local->sta_lock */ |
179 | static void sta_info_hash_add(struct ieee80211_local *local, | ||
180 | struct sta_info *sta) | ||
139 | { | 181 | { |
140 | kref_put(&sta->kref, sta_info_release); | 182 | sta->hnext = local->sta_hash[STA_HASH(sta->addr)]; |
183 | rcu_assign_pointer(local->sta_hash[STA_HASH(sta->addr)], sta); | ||
141 | } | 184 | } |
142 | EXPORT_SYMBOL(sta_info_put); | ||
143 | |||
144 | 185 | ||
145 | struct sta_info *sta_info_add(struct ieee80211_local *local, | 186 | struct sta_info *sta_info_add(struct ieee80211_sub_if_data *sdata, |
146 | struct net_device *dev, u8 *addr, gfp_t gfp) | 187 | u8 *addr) |
147 | { | 188 | { |
189 | struct ieee80211_local *local = sdata->local; | ||
148 | struct sta_info *sta; | 190 | struct sta_info *sta; |
149 | int i; | 191 | int i; |
150 | DECLARE_MAC_BUF(mac); | 192 | DECLARE_MAC_BUF(mac); |
193 | unsigned long flags; | ||
151 | 194 | ||
152 | sta = kzalloc(sizeof(*sta), gfp); | 195 | sta = kzalloc(sizeof(*sta), GFP_ATOMIC); |
153 | if (!sta) | 196 | if (!sta) |
154 | return ERR_PTR(-ENOMEM); | 197 | return ERR_PTR(-ENOMEM); |
155 | 198 | ||
156 | kref_init(&sta->kref); | 199 | memcpy(sta->addr, addr, ETH_ALEN); |
200 | sta->local = local; | ||
201 | sta->sdata = sdata; | ||
157 | 202 | ||
158 | sta->rate_ctrl = rate_control_get(local->rate_ctrl); | 203 | sta->rate_ctrl = rate_control_get(local->rate_ctrl); |
159 | sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, gfp); | 204 | sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, |
205 | GFP_ATOMIC); | ||
160 | if (!sta->rate_ctrl_priv) { | 206 | if (!sta->rate_ctrl_priv) { |
161 | rate_control_put(sta->rate_ctrl); | 207 | rate_control_put(sta->rate_ctrl); |
162 | kfree(sta); | 208 | kfree(sta); |
163 | return ERR_PTR(-ENOMEM); | 209 | return ERR_PTR(-ENOMEM); |
164 | } | 210 | } |
165 | 211 | ||
166 | memcpy(sta->addr, addr, ETH_ALEN); | ||
167 | sta->local = local; | ||
168 | sta->dev = dev; | ||
169 | spin_lock_init(&sta->ampdu_mlme.ampdu_rx); | 212 | spin_lock_init(&sta->ampdu_mlme.ampdu_rx); |
170 | spin_lock_init(&sta->ampdu_mlme.ampdu_tx); | 213 | spin_lock_init(&sta->ampdu_mlme.ampdu_tx); |
171 | for (i = 0; i < STA_TID_NUM; i++) { | 214 | for (i = 0; i < STA_TID_NUM; i++) { |
@@ -190,29 +233,26 @@ struct sta_info *sta_info_add(struct ieee80211_local *local, | |||
190 | } | 233 | } |
191 | skb_queue_head_init(&sta->ps_tx_buf); | 234 | skb_queue_head_init(&sta->ps_tx_buf); |
192 | skb_queue_head_init(&sta->tx_filtered); | 235 | skb_queue_head_init(&sta->tx_filtered); |
193 | write_lock_bh(&local->sta_lock); | 236 | spin_lock_irqsave(&local->sta_lock, flags); |
194 | /* mark sta as used (by caller) */ | ||
195 | __sta_info_get(sta); | ||
196 | /* check if STA exists already */ | 237 | /* check if STA exists already */ |
197 | if (__sta_info_find(local, addr)) { | 238 | if (__sta_info_find(local, addr)) { |
198 | write_unlock_bh(&local->sta_lock); | 239 | spin_unlock_irqrestore(&local->sta_lock, flags); |
199 | sta_info_put(sta); | ||
200 | return ERR_PTR(-EEXIST); | 240 | return ERR_PTR(-EEXIST); |
201 | } | 241 | } |
202 | list_add(&sta->list, &local->sta_list); | 242 | list_add(&sta->list, &local->sta_list); |
203 | local->num_sta++; | 243 | local->num_sta++; |
204 | sta_info_hash_add(local, sta); | 244 | sta_info_hash_add(local, sta); |
205 | if (local->ops->sta_notify) { | ||
206 | struct ieee80211_sub_if_data *sdata; | ||
207 | 245 | ||
208 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 246 | /* notify driver */ |
247 | if (local->ops->sta_notify) { | ||
209 | if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) | 248 | if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) |
210 | sdata = sdata->u.vlan.ap; | 249 | sdata = sdata->u.vlan.ap; |
211 | 250 | ||
212 | local->ops->sta_notify(local_to_hw(local), &sdata->vif, | 251 | local->ops->sta_notify(local_to_hw(local), &sdata->vif, |
213 | STA_NOTIFY_ADD, addr); | 252 | STA_NOTIFY_ADD, addr); |
214 | } | 253 | } |
215 | write_unlock_bh(&local->sta_lock); | 254 | |
255 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
216 | 256 | ||
217 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 257 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
218 | printk(KERN_DEBUG "%s: Added STA %s\n", | 258 | printk(KERN_DEBUG "%s: Added STA %s\n", |
@@ -252,19 +292,20 @@ static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss, | |||
252 | { | 292 | { |
253 | if (bss) | 293 | if (bss) |
254 | __bss_tim_set(bss, sta->aid); | 294 | __bss_tim_set(bss, sta->aid); |
255 | if (sta->local->ops->set_tim) | 295 | if (sta->local->ops->set_tim) { |
296 | sta->local->tim_in_locked_section = true; | ||
256 | sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 1); | 297 | sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 1); |
298 | sta->local->tim_in_locked_section = false; | ||
299 | } | ||
257 | } | 300 | } |
258 | 301 | ||
259 | void sta_info_set_tim_bit(struct sta_info *sta) | 302 | void sta_info_set_tim_bit(struct sta_info *sta) |
260 | { | 303 | { |
261 | struct ieee80211_sub_if_data *sdata; | 304 | unsigned long flags; |
262 | |||
263 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | ||
264 | 305 | ||
265 | read_lock_bh(&sta->local->sta_lock); | 306 | spin_lock_irqsave(&sta->local->sta_lock, flags); |
266 | __sta_info_set_tim_bit(sdata->bss, sta); | 307 | __sta_info_set_tim_bit(sta->sdata->bss, sta); |
267 | read_unlock_bh(&sta->local->sta_lock); | 308 | spin_unlock_irqrestore(&sta->local->sta_lock, flags); |
268 | } | 309 | } |
269 | 310 | ||
270 | static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss, | 311 | static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss, |
@@ -272,93 +313,135 @@ static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss, | |||
272 | { | 313 | { |
273 | if (bss) | 314 | if (bss) |
274 | __bss_tim_clear(bss, sta->aid); | 315 | __bss_tim_clear(bss, sta->aid); |
275 | if (sta->local->ops->set_tim) | 316 | if (sta->local->ops->set_tim) { |
317 | sta->local->tim_in_locked_section = true; | ||
276 | sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 0); | 318 | sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 0); |
319 | sta->local->tim_in_locked_section = false; | ||
320 | } | ||
277 | } | 321 | } |
278 | 322 | ||
279 | void sta_info_clear_tim_bit(struct sta_info *sta) | 323 | void sta_info_clear_tim_bit(struct sta_info *sta) |
280 | { | 324 | { |
281 | struct ieee80211_sub_if_data *sdata; | 325 | unsigned long flags; |
282 | |||
283 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | ||
284 | 326 | ||
285 | read_lock_bh(&sta->local->sta_lock); | 327 | spin_lock_irqsave(&sta->local->sta_lock, flags); |
286 | __sta_info_clear_tim_bit(sdata->bss, sta); | 328 | __sta_info_clear_tim_bit(sta->sdata->bss, sta); |
287 | read_unlock_bh(&sta->local->sta_lock); | 329 | spin_unlock_irqrestore(&sta->local->sta_lock, flags); |
288 | } | 330 | } |
289 | 331 | ||
290 | /* Caller must hold local->sta_lock */ | 332 | /* |
291 | void sta_info_remove(struct sta_info *sta) | 333 | * See comment in __sta_info_unlink, |
334 | * caller must hold local->sta_lock. | ||
335 | */ | ||
336 | static void __sta_info_pin(struct sta_info *sta) | ||
292 | { | 337 | { |
293 | struct ieee80211_local *local = sta->local; | 338 | WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_NORMAL); |
294 | struct ieee80211_sub_if_data *sdata; | 339 | sta->pin_status = STA_INFO_PIN_STAT_PINNED; |
340 | } | ||
295 | 341 | ||
296 | /* don't do anything if we've been removed already */ | 342 | /* |
297 | if (sta_info_hash_del(local, sta)) | 343 | * See comment in __sta_info_unlink, returns sta if it |
298 | return; | 344 | * needs to be destroyed. |
345 | */ | ||
346 | static struct sta_info *__sta_info_unpin(struct sta_info *sta) | ||
347 | { | ||
348 | struct sta_info *ret = NULL; | ||
349 | unsigned long flags; | ||
299 | 350 | ||
300 | list_del(&sta->list); | 351 | spin_lock_irqsave(&sta->local->sta_lock, flags); |
301 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 352 | WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_DESTROY && |
302 | if (sta->flags & WLAN_STA_PS) { | 353 | sta->pin_status != STA_INFO_PIN_STAT_PINNED); |
303 | sta->flags &= ~WLAN_STA_PS; | 354 | if (sta->pin_status == STA_INFO_PIN_STAT_DESTROY) |
304 | if (sdata->bss) | 355 | ret = sta; |
305 | atomic_dec(&sdata->bss->num_sta_ps); | 356 | sta->pin_status = STA_INFO_PIN_STAT_NORMAL; |
306 | __sta_info_clear_tim_bit(sdata->bss, sta); | 357 | spin_unlock_irqrestore(&sta->local->sta_lock, flags); |
307 | } | ||
308 | local->num_sta--; | ||
309 | 358 | ||
310 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 359 | return ret; |
311 | mesh_accept_plinks_update(sdata->dev); | ||
312 | } | 360 | } |
313 | 361 | ||
314 | void sta_info_free(struct sta_info *sta) | 362 | static void __sta_info_unlink(struct sta_info **sta) |
315 | { | 363 | { |
316 | struct sk_buff *skb; | 364 | struct ieee80211_local *local = (*sta)->local; |
317 | struct ieee80211_local *local = sta->local; | 365 | struct ieee80211_sub_if_data *sdata = (*sta)->sdata; |
318 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 366 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
319 | 367 | DECLARE_MAC_BUF(mbuf); | |
320 | DECLARE_MAC_BUF(mac); | 368 | #endif |
321 | 369 | /* | |
322 | might_sleep(); | 370 | * pull caller's reference if we're already gone. |
371 | */ | ||
372 | if (sta_info_hash_del(local, *sta)) { | ||
373 | *sta = NULL; | ||
374 | return; | ||
375 | } | ||
323 | 376 | ||
324 | write_lock_bh(&local->sta_lock); | 377 | /* |
325 | sta_info_remove(sta); | 378 | * Also pull caller's reference if the STA is pinned by the |
326 | write_unlock_bh(&local->sta_lock); | 379 | * task that is adding the debugfs entries. In that case, we |
380 | * leave the STA "to be freed". | ||
381 | * | ||
382 | * The rules are not trivial, but not too complex either: | ||
383 | * (1) pin_status is only modified under the sta_lock | ||
384 | * (2) sta_info_debugfs_add_work() will set the status | ||
385 | * to PINNED when it found an item that needs a new | ||
386 | * debugfs directory created. In that case, that item | ||
387 | * must not be freed although all *RCU* users are done | ||
388 | * with it. Hence, we tell the caller of _unlink() | ||
389 | * that the item is already gone (as can happen when | ||
390 | * two tasks try to unlink/destroy at the same time) | ||
391 | * (3) We set the pin_status to DESTROY here when we | ||
392 | * find such an item. | ||
393 | * (4) sta_info_debugfs_add_work() will reset the pin_status | ||
394 | * from PINNED to NORMAL when it is done with the item, | ||
395 | * but will check for DESTROY before resetting it in | ||
396 | * which case it will free the item. | ||
397 | */ | ||
398 | if ((*sta)->pin_status == STA_INFO_PIN_STAT_PINNED) { | ||
399 | (*sta)->pin_status = STA_INFO_PIN_STAT_DESTROY; | ||
400 | *sta = NULL; | ||
401 | return; | ||
402 | } | ||
327 | 403 | ||
328 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 404 | list_del(&(*sta)->list); |
329 | mesh_plink_deactivate(sta); | ||
330 | 405 | ||
331 | while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { | 406 | if ((*sta)->flags & WLAN_STA_PS) { |
332 | local->total_ps_buffered--; | 407 | (*sta)->flags &= ~WLAN_STA_PS; |
333 | dev_kfree_skb(skb); | 408 | if (sdata->bss) |
334 | } | 409 | atomic_dec(&sdata->bss->num_sta_ps); |
335 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { | 410 | __sta_info_clear_tim_bit(sdata->bss, *sta); |
336 | dev_kfree_skb(skb); | ||
337 | } | 411 | } |
338 | 412 | ||
339 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 413 | local->num_sta--; |
340 | printk(KERN_DEBUG "%s: Removed STA %s\n", | ||
341 | wiphy_name(local->hw.wiphy), print_mac(mac, sta->addr)); | ||
342 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
343 | |||
344 | ieee80211_key_free(sta->key); | ||
345 | WARN_ON(sta->key); | ||
346 | 414 | ||
347 | if (local->ops->sta_notify) { | 415 | if (local->ops->sta_notify) { |
348 | |||
349 | if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) | 416 | if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) |
350 | sdata = sdata->u.vlan.ap; | 417 | sdata = sdata->u.vlan.ap; |
351 | 418 | ||
352 | local->ops->sta_notify(local_to_hw(local), &sdata->vif, | 419 | local->ops->sta_notify(local_to_hw(local), &sdata->vif, |
353 | STA_NOTIFY_REMOVE, sta->addr); | 420 | STA_NOTIFY_REMOVE, (*sta)->addr); |
354 | } | 421 | } |
355 | 422 | ||
356 | rate_control_remove_sta_debugfs(sta); | 423 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
357 | ieee80211_sta_debugfs_remove(sta); | 424 | mesh_accept_plinks_update(sdata); |
425 | #ifdef CONFIG_MAC80211_MESH | ||
426 | del_timer(&(*sta)->plink_timer); | ||
427 | #endif | ||
428 | } | ||
358 | 429 | ||
359 | sta_info_put(sta); | 430 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
431 | printk(KERN_DEBUG "%s: Removed STA %s\n", | ||
432 | wiphy_name(local->hw.wiphy), print_mac(mbuf, (*sta)->addr)); | ||
433 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
360 | } | 434 | } |
361 | 435 | ||
436 | void sta_info_unlink(struct sta_info **sta) | ||
437 | { | ||
438 | struct ieee80211_local *local = (*sta)->local; | ||
439 | unsigned long flags; | ||
440 | |||
441 | spin_lock_irqsave(&local->sta_lock, flags); | ||
442 | __sta_info_unlink(sta); | ||
443 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
444 | } | ||
362 | 445 | ||
363 | static inline int sta_info_buffer_expired(struct ieee80211_local *local, | 446 | static inline int sta_info_buffer_expired(struct ieee80211_local *local, |
364 | struct sta_info *sta, | 447 | struct sta_info *sta, |
@@ -404,7 +487,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, | |||
404 | if (!skb) | 487 | if (!skb) |
405 | break; | 488 | break; |
406 | 489 | ||
407 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 490 | sdata = sta->sdata; |
408 | local->total_ps_buffered--; | 491 | local->total_ps_buffered--; |
409 | printk(KERN_DEBUG "Buffered frame expired (STA " | 492 | printk(KERN_DEBUG "Buffered frame expired (STA " |
410 | "%s)\n", print_mac(mac, sta->addr)); | 493 | "%s)\n", print_mac(mac, sta->addr)); |
@@ -421,13 +504,10 @@ static void sta_info_cleanup(unsigned long data) | |||
421 | struct ieee80211_local *local = (struct ieee80211_local *) data; | 504 | struct ieee80211_local *local = (struct ieee80211_local *) data; |
422 | struct sta_info *sta; | 505 | struct sta_info *sta; |
423 | 506 | ||
424 | read_lock_bh(&local->sta_lock); | 507 | rcu_read_lock(); |
425 | list_for_each_entry(sta, &local->sta_list, list) { | 508 | list_for_each_entry_rcu(sta, &local->sta_list, list) |
426 | __sta_info_get(sta); | ||
427 | sta_info_cleanup_expire_buffered(local, sta); | 509 | sta_info_cleanup_expire_buffered(local, sta); |
428 | sta_info_put(sta); | 510 | rcu_read_unlock(); |
429 | } | ||
430 | read_unlock_bh(&local->sta_lock); | ||
431 | 511 | ||
432 | local->sta_cleanup.expires = | 512 | local->sta_cleanup.expires = |
433 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); | 513 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); |
@@ -435,37 +515,45 @@ static void sta_info_cleanup(unsigned long data) | |||
435 | } | 515 | } |
436 | 516 | ||
437 | #ifdef CONFIG_MAC80211_DEBUGFS | 517 | #ifdef CONFIG_MAC80211_DEBUGFS |
438 | static void sta_info_debugfs_add_task(struct work_struct *work) | 518 | static void sta_info_debugfs_add_work(struct work_struct *work) |
439 | { | 519 | { |
440 | struct ieee80211_local *local = | 520 | struct ieee80211_local *local = |
441 | container_of(work, struct ieee80211_local, sta_debugfs_add); | 521 | container_of(work, struct ieee80211_local, sta_debugfs_add); |
442 | struct sta_info *sta, *tmp; | 522 | struct sta_info *sta, *tmp; |
523 | unsigned long flags; | ||
443 | 524 | ||
444 | while (1) { | 525 | while (1) { |
445 | sta = NULL; | 526 | sta = NULL; |
446 | read_lock_bh(&local->sta_lock); | 527 | |
528 | spin_lock_irqsave(&local->sta_lock, flags); | ||
447 | list_for_each_entry(tmp, &local->sta_list, list) { | 529 | list_for_each_entry(tmp, &local->sta_list, list) { |
448 | if (!tmp->debugfs.dir) { | 530 | if (!tmp->debugfs.dir) { |
449 | sta = tmp; | 531 | sta = tmp; |
450 | __sta_info_get(sta); | 532 | __sta_info_pin(sta); |
451 | break; | 533 | break; |
452 | } | 534 | } |
453 | } | 535 | } |
454 | read_unlock_bh(&local->sta_lock); | 536 | spin_unlock_irqrestore(&local->sta_lock, flags); |
455 | 537 | ||
456 | if (!sta) | 538 | if (!sta) |
457 | break; | 539 | break; |
458 | 540 | ||
459 | ieee80211_sta_debugfs_add(sta); | 541 | ieee80211_sta_debugfs_add(sta); |
460 | rate_control_add_sta_debugfs(sta); | 542 | rate_control_add_sta_debugfs(sta); |
461 | sta_info_put(sta); | 543 | |
544 | sta = __sta_info_unpin(sta); | ||
545 | |||
546 | if (sta) { | ||
547 | synchronize_rcu(); | ||
548 | sta_info_destroy(sta); | ||
549 | } | ||
462 | } | 550 | } |
463 | } | 551 | } |
464 | #endif | 552 | #endif |
465 | 553 | ||
466 | void sta_info_init(struct ieee80211_local *local) | 554 | void sta_info_init(struct ieee80211_local *local) |
467 | { | 555 | { |
468 | rwlock_init(&local->sta_lock); | 556 | spin_lock_init(&local->sta_lock); |
469 | INIT_LIST_HEAD(&local->sta_list); | 557 | INIT_LIST_HEAD(&local->sta_list); |
470 | 558 | ||
471 | setup_timer(&local->sta_cleanup, sta_info_cleanup, | 559 | setup_timer(&local->sta_cleanup, sta_info_cleanup, |
@@ -474,7 +562,7 @@ void sta_info_init(struct ieee80211_local *local) | |||
474 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); | 562 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); |
475 | 563 | ||
476 | #ifdef CONFIG_MAC80211_DEBUGFS | 564 | #ifdef CONFIG_MAC80211_DEBUGFS |
477 | INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_task); | 565 | INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_work); |
478 | #endif | 566 | #endif |
479 | } | 567 | } |
480 | 568 | ||
@@ -493,24 +581,29 @@ void sta_info_stop(struct ieee80211_local *local) | |||
493 | /** | 581 | /** |
494 | * sta_info_flush - flush matching STA entries from the STA table | 582 | * sta_info_flush - flush matching STA entries from the STA table |
495 | * @local: local interface data | 583 | * @local: local interface data |
496 | * @dev: matching rule for the net device (sta->dev) or %NULL to match all STAs | 584 | * @sdata: matching rule for the net device (sta->dev) or %NULL to match all STAs |
497 | */ | 585 | */ |
498 | void sta_info_flush(struct ieee80211_local *local, struct net_device *dev) | 586 | void sta_info_flush(struct ieee80211_local *local, |
587 | struct ieee80211_sub_if_data *sdata) | ||
499 | { | 588 | { |
500 | struct sta_info *sta, *tmp; | 589 | struct sta_info *sta, *tmp; |
501 | LIST_HEAD(tmp_list); | 590 | LIST_HEAD(tmp_list); |
591 | unsigned long flags; | ||
502 | 592 | ||
503 | write_lock_bh(&local->sta_lock); | 593 | might_sleep(); |
504 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) | ||
505 | if (!dev || dev == sta->dev) { | ||
506 | __sta_info_get(sta); | ||
507 | sta_info_remove(sta); | ||
508 | list_add_tail(&sta->list, &tmp_list); | ||
509 | } | ||
510 | write_unlock_bh(&local->sta_lock); | ||
511 | 594 | ||
512 | list_for_each_entry_safe(sta, tmp, &tmp_list, list) { | 595 | spin_lock_irqsave(&local->sta_lock, flags); |
513 | sta_info_free(sta); | 596 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { |
514 | sta_info_put(sta); | 597 | if (!sdata || sdata == sta->sdata) { |
598 | __sta_info_unlink(&sta); | ||
599 | if (sta) | ||
600 | list_add_tail(&sta->list, &tmp_list); | ||
601 | } | ||
515 | } | 602 | } |
603 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
604 | |||
605 | synchronize_rcu(); | ||
606 | |||
607 | list_for_each_entry_safe(sta, tmp, &tmp_list, list) | ||
608 | sta_info_destroy(sta); | ||
516 | } | 609 | } |