diff options
Diffstat (limited to 'net/mac80211/sta_info.c')
-rw-r--r-- | net/mac80211/sta_info.c | 80 |
1 files changed, 57 insertions, 23 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 2a5a2f067bae..5497ca1843fe 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -36,16 +36,23 @@ | |||
36 | * (which is pretty useless) or insert it into the hash table using | 36 | * (which is pretty useless) or insert it into the hash table using |
37 | * sta_info_insert() which demotes the reference from ownership to a regular | 37 | * sta_info_insert() which demotes the reference from ownership to a regular |
38 | * RCU-protected reference; if the function is called without protection by an | 38 | * RCU-protected reference; if the function is called without protection by an |
39 | * RCU critical section the reference is instantly invalidated. | 39 | * RCU critical section the reference is instantly invalidated. Note that the |
40 | * caller may not do much with the STA info before inserting it, in particular, | ||
41 | * it may not start any mesh peer link management or add encryption keys. | ||
42 | * | ||
43 | * When the insertion fails (sta_info_insert()) returns non-zero), the | ||
44 | * structure will have been freed by sta_info_insert()! | ||
40 | * | 45 | * |
41 | * Because there are debugfs entries for each station, and adding those | 46 | * 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, | 47 | * 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. | 48 | * 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. | 49 | * See the comment in __sta_info_unlink() for more information, this is |
50 | * an internal capability only. | ||
45 | * | 51 | * |
46 | * In order to remove a STA info structure, the caller needs to first | 52 | * 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 | 53 | * 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 | 54 | * then destroy it while holding the RTNL; sta_info_destroy() will wait |
55 | * for an RCU grace period to elapse before actually freeing it. Due to | ||
49 | * the pinning and the possibility of multiple callers trying to remove | 56 | * 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 | 57 | * 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 | 58 | * STA info pointer it is passed to indicate that the STA info is owned |
@@ -127,12 +134,35 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, | |||
127 | return NULL; | 134 | return NULL; |
128 | } | 135 | } |
129 | 136 | ||
137 | /** | ||
138 | * __sta_info_free - internal STA free helper | ||
139 | * | ||
140 | * @sta: STA info to free | ||
141 | * | ||
142 | * This function must undo everything done by sta_info_alloc() | ||
143 | * that may happen before sta_info_insert(). | ||
144 | */ | ||
145 | static void __sta_info_free(struct ieee80211_local *local, | ||
146 | struct sta_info *sta) | ||
147 | { | ||
148 | DECLARE_MAC_BUF(mbuf); | ||
149 | |||
150 | rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); | ||
151 | rate_control_put(sta->rate_ctrl); | ||
152 | |||
153 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
154 | printk(KERN_DEBUG "%s: Destroyed STA %s\n", | ||
155 | wiphy_name(local->hw.wiphy), print_mac(mbuf, sta->addr)); | ||
156 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
157 | |||
158 | kfree(sta); | ||
159 | } | ||
160 | |||
130 | void sta_info_destroy(struct sta_info *sta) | 161 | void sta_info_destroy(struct sta_info *sta) |
131 | { | 162 | { |
132 | struct ieee80211_local *local; | 163 | struct ieee80211_local *local; |
133 | struct sk_buff *skb; | 164 | struct sk_buff *skb; |
134 | int i; | 165 | int i; |
135 | DECLARE_MAC_BUF(mbuf); | ||
136 | 166 | ||
137 | ASSERT_RTNL(); | 167 | ASSERT_RTNL(); |
138 | might_sleep(); | 168 | might_sleep(); |
@@ -182,15 +212,7 @@ void sta_info_destroy(struct sta_info *sta) | |||
182 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); | 212 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); |
183 | } | 213 | } |
184 | 214 | ||
185 | rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); | 215 | __sta_info_free(local, sta); |
186 | rate_control_put(sta->rate_ctrl); | ||
187 | |||
188 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
189 | printk(KERN_DEBUG "%s: Destroyed STA %s\n", | ||
190 | wiphy_name(local->hw.wiphy), print_mac(mbuf, sta->addr)); | ||
191 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
192 | |||
193 | kfree(sta); | ||
194 | } | 216 | } |
195 | 217 | ||
196 | 218 | ||
@@ -266,6 +288,7 @@ int sta_info_insert(struct sta_info *sta) | |||
266 | struct ieee80211_local *local = sta->local; | 288 | struct ieee80211_local *local = sta->local; |
267 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 289 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
268 | unsigned long flags; | 290 | unsigned long flags; |
291 | int err = 0; | ||
269 | DECLARE_MAC_BUF(mac); | 292 | DECLARE_MAC_BUF(mac); |
270 | 293 | ||
271 | /* | 294 | /* |
@@ -273,20 +296,23 @@ int sta_info_insert(struct sta_info *sta) | |||
273 | * something inserts a STA (on one CPU) without holding the RTNL | 296 | * something inserts a STA (on one CPU) without holding the RTNL |
274 | * and another CPU turns off the net device. | 297 | * and another CPU turns off the net device. |
275 | */ | 298 | */ |
276 | if (unlikely(!netif_running(sdata->dev))) | 299 | if (unlikely(!netif_running(sdata->dev))) { |
277 | return -ENETDOWN; | 300 | err = -ENETDOWN; |
278 | 301 | goto out_free; | |
279 | if (WARN_ON(compare_ether_addr(sta->addr, sdata->dev->dev_addr) == 0)) | 302 | } |
280 | return -EINVAL; | ||
281 | 303 | ||
282 | if (WARN_ON(is_multicast_ether_addr(sta->addr))) | 304 | if (WARN_ON(compare_ether_addr(sta->addr, sdata->dev->dev_addr) == 0 || |
283 | return -EINVAL; | 305 | is_multicast_ether_addr(sta->addr))) { |
306 | err = -EINVAL; | ||
307 | goto out_free; | ||
308 | } | ||
284 | 309 | ||
285 | spin_lock_irqsave(&local->sta_lock, flags); | 310 | spin_lock_irqsave(&local->sta_lock, flags); |
286 | /* check if STA exists already */ | 311 | /* check if STA exists already */ |
287 | if (__sta_info_find(local, sta->addr)) { | 312 | if (__sta_info_find(local, sta->addr)) { |
288 | spin_unlock_irqrestore(&local->sta_lock, flags); | 313 | spin_unlock_irqrestore(&local->sta_lock, flags); |
289 | return -EEXIST; | 314 | err = -EEXIST; |
315 | goto out_free; | ||
290 | } | 316 | } |
291 | list_add(&sta->list, &local->sta_list); | 317 | list_add(&sta->list, &local->sta_list); |
292 | local->num_sta++; | 318 | local->num_sta++; |
@@ -309,9 +335,13 @@ int sta_info_insert(struct sta_info *sta) | |||
309 | spin_unlock_irqrestore(&local->sta_lock, flags); | 335 | spin_unlock_irqrestore(&local->sta_lock, flags); |
310 | 336 | ||
311 | #ifdef CONFIG_MAC80211_DEBUGFS | 337 | #ifdef CONFIG_MAC80211_DEBUGFS |
312 | /* debugfs entry adding might sleep, so schedule process | 338 | /* |
339 | * Debugfs entry adding might sleep, so schedule process | ||
313 | * context task for adding entry for STAs that do not yet | 340 | * context task for adding entry for STAs that do not yet |
314 | * have one. */ | 341 | * have one. |
342 | * NOTE: due to auto-freeing semantics this may only be done | ||
343 | * if the insertion is successful! | ||
344 | */ | ||
315 | queue_work(local->hw.workqueue, &local->sta_debugfs_add); | 345 | queue_work(local->hw.workqueue, &local->sta_debugfs_add); |
316 | #endif | 346 | #endif |
317 | 347 | ||
@@ -319,6 +349,10 @@ int sta_info_insert(struct sta_info *sta) | |||
319 | mesh_accept_plinks_update(sdata); | 349 | mesh_accept_plinks_update(sdata); |
320 | 350 | ||
321 | return 0; | 351 | return 0; |
352 | out_free: | ||
353 | BUG_ON(!err); | ||
354 | __sta_info_free(local, sta); | ||
355 | return err; | ||
322 | } | 356 | } |
323 | 357 | ||
324 | static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) | 358 | static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) |