aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-04-01 09:21:00 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-04-01 17:14:10 -0400
commit93e5deb1ae39b56f4743955e76c72251256f23c1 (patch)
tree415d4f11449452822bdd1a97760de67ffd8c452d /net
parent97bff8ecf4e4e26749a67dcfbb7565d8a0f4acb4 (diff)
mac80211: automatically free sta struct when insertion fails
When STA structure insertion fails, it has been allocated but isn't really alive yet, it isn't reachable by any other code and also can't yet have much configured. This patch changes the code so that when the insertion fails, the resulting STA pointer is no longer valid because it is freed. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/cfg.c2
-rw-r--r--net/mac80211/ieee80211.c2
-rw-r--r--net/mac80211/ieee80211_sta.c5
-rw-r--r--net/mac80211/mesh_plink.c6
-rw-r--r--net/mac80211/sta_info.c80
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 */
92static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, 96static 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 */
145static 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
130void sta_info_destroy(struct sta_info *sta) 161void 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
324static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) 358static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid)