aboutsummaryrefslogtreecommitdiff
path: root/net/mac80211/ieee80211.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-02-25 16:27:47 +0100
committerJohn W. Linville <linville@tuxdriver.com>2008-03-06 15:30:47 -0500
commit73651ee6396c499ccb59ebc84c9274db01ed026d (patch)
tree1d59027cbdaec732f3e1378770cbf7b42b48cd70 /net/mac80211/ieee80211.c
parentd0709a65181beb787ef3f58cfe45536a2bb254c8 (diff)
mac80211: split sta_info_add
sta_info_add() has two functions: allocating a station info structure and inserting it into the hash table/list. Splitting these two functions allows allocating with GFP_KERNEL in many places instead of GFP_ATOMIC which is now required by the RCU protection. Additionally, in many places RCU protection is now no longer needed at all because between sta_info_alloc() and sta_info_insert() the caller owns the structure. This fixes a few race conditions with setting initial flags and similar, but not all (see comments in ieee80211_sta.c and cfg.c). More documentation on the existing races will be in a follow-up patch. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/ieee80211.c')
-rw-r--r--net/mac80211/ieee80211.c18
1 files changed, 11 insertions, 7 deletions
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 85b1391375c..22cba82a0c6 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -899,6 +899,7 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr)
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct sta_info *sta;
+ int err;
DECLARE_MAC_BUF(mac);
might_sleep();
@@ -906,16 +907,19 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr)
if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0)
return 0;
- rcu_read_lock();
-
/* Create STA entry for the new peer */
- sta = sta_info_add(sdata, remote_addr);
- if (IS_ERR(sta)) {
- rcu_read_unlock();
- return PTR_ERR(sta);
- }
+ sta = sta_info_alloc(sdata, remote_addr, GFP_KERNEL);
+ if (!sta)
+ return -ENOMEM;
sta->flags |= WLAN_STA_AUTHORIZED;
+ err = sta_info_insert(sta);
+ if (err) {
+ sta_info_destroy(sta);
+ return err;
+ }
+
+ rcu_read_lock();
/* Remove STA entry for the old peer */
sta = sta_info_get(local, sdata->u.wds.remote_addr);