diff options
-rw-r--r-- | net/mac80211/cfg.c | 2 | ||||
-rw-r--r-- | net/mac80211/ieee80211.c | 2 | ||||
-rw-r--r-- | net/mac80211/ieee80211_sta.c | 5 | ||||
-rw-r--r-- | net/mac80211/mesh_plink.c | 6 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 80 |
5 files changed, 64 insertions, 31 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 6b183a3526b0..fbd462c78e18 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -672,7 +672,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
672 | 672 | ||
673 | err = sta_info_insert(sta); | 673 | err = sta_info_insert(sta); |
674 | if (err) { | 674 | if (err) { |
675 | sta_info_destroy(sta); | 675 | /* STA has been freed */ |
676 | rcu_read_unlock(); | 676 | rcu_read_unlock(); |
677 | return err; | 677 | return err; |
678 | } | 678 | } |
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 8c0f782d21e3..5ee431b6256c 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c | |||
@@ -268,7 +268,7 @@ static int ieee80211_open(struct net_device *dev) | |||
268 | 268 | ||
269 | res = sta_info_insert(sta); | 269 | res = sta_info_insert(sta); |
270 | if (res) { | 270 | if (res) { |
271 | sta_info_destroy(sta); | 271 | /* STA has been freed */ |
272 | return res; | 272 | return res; |
273 | } | 273 | } |
274 | break; | 274 | break; |
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index baa68575b98a..00fde111c268 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c | |||
@@ -1942,7 +1942,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1942 | if (err) { | 1942 | if (err) { |
1943 | printk(KERN_DEBUG "%s: failed to insert STA entry for" | 1943 | printk(KERN_DEBUG "%s: failed to insert STA entry for" |
1944 | " the AP (error %d)\n", dev->name, err); | 1944 | " the AP (error %d)\n", dev->name, err); |
1945 | sta_info_destroy(sta); | ||
1946 | rcu_read_unlock(); | 1945 | rcu_read_unlock(); |
1947 | return; | 1946 | return; |
1948 | } | 1947 | } |
@@ -4172,10 +4171,8 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, | |||
4172 | 4171 | ||
4173 | rate_control_rate_init(sta, local); | 4172 | rate_control_rate_init(sta, local); |
4174 | 4173 | ||
4175 | if (sta_info_insert(sta)) { | 4174 | if (sta_info_insert(sta)) |
4176 | sta_info_destroy(sta); | ||
4177 | return NULL; | 4175 | return NULL; |
4178 | } | ||
4179 | 4176 | ||
4180 | return sta; | 4177 | return sta; |
4181 | } | 4178 | } |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 18fe52436c47..56c54e321b38 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -89,6 +89,10 @@ static inline void mesh_plink_fsm_restart(struct sta_info *sta) | |||
89 | sta->plink_retries = 0; | 89 | sta->plink_retries = 0; |
90 | } | 90 | } |
91 | 91 | ||
92 | /* | ||
93 | * NOTE: This is just an alias for sta_info_alloc(), see notes | ||
94 | * on it in the lifecycle management section! | ||
95 | */ | ||
92 | static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, | 96 | static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, |
93 | u8 *hw_addr, u64 rates) | 97 | u8 *hw_addr, u64 rates) |
94 | { | 98 | { |
@@ -235,7 +239,6 @@ void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev, | |||
235 | return; | 239 | return; |
236 | } | 240 | } |
237 | if (sta_info_insert(sta)) { | 241 | if (sta_info_insert(sta)) { |
238 | sta_info_destroy(sta); | ||
239 | rcu_read_unlock(); | 242 | rcu_read_unlock(); |
240 | return; | 243 | return; |
241 | } | 244 | } |
@@ -506,7 +509,6 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | |||
506 | return; | 509 | return; |
507 | } | 510 | } |
508 | if (sta_info_insert(sta)) { | 511 | if (sta_info_insert(sta)) { |
509 | sta_info_destroy(sta); | ||
510 | rcu_read_unlock(); | 512 | rcu_read_unlock(); |
511 | return; | 513 | return; |
512 | } | 514 | } |
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) |