summaryrefslogtreecommitdiffstats
path: root/net/mac80211/cfg.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/cfg.c
parentd0709a65181beb787ef3f58cfe45536a2bb254c8 (diff)
downloadlinux-stable-73651ee6396c499ccb59ebc84c9274db01ed026d.tar.gz
linux-stable-73651ee6396c499ccb59ebc84c9274db01ed026d.tar.bz2
linux-stable-73651ee6396c499ccb59ebc84c9274db01ed026d.zip
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/cfg.c')
-rw-r--r--net/mac80211/cfg.c42
1 files changed, 33 insertions, 9 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index e9ba6fcc0e45..6263cfc148c0 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -571,6 +571,12 @@ static void sta_apply_parameters(struct ieee80211_local *local,
struct ieee80211_supported_band *sband;
struct ieee80211_sub_if_data *sdata = sta->sdata;
+ /*
+ * FIXME: updating the flags is racy when this function is
+ * called from ieee80211_change_station(), this will
+ * be resolved in a future patch.
+ */
+
if (params->station_flags & STATION_FLAG_CHANGED) {
sta->flags &= ~WLAN_STA_AUTHORIZED;
if (params->station_flags & STATION_FLAG_AUTHORIZED)
@@ -585,6 +591,13 @@ static void sta_apply_parameters(struct ieee80211_local *local,
sta->flags |= WLAN_STA_WME;
}
+ /*
+ * FIXME: updating the following information is racy when this
+ * function is called from ieee80211_change_station().
+ * However, all this information should be static so
+ * maybe we should just reject attemps to change it.
+ */
+
if (params->aid) {
sta->aid = params->aid;
if (sta->aid > IEEE80211_MAX_AID)
@@ -626,6 +639,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
struct ieee80211_sub_if_data *sdata;
+ int err;
/* Prevent a race with changing the rate control algorithm */
if (!netif_running(dev))
@@ -641,16 +655,11 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (ieee80211_vif_is_mesh(&sdata->vif))
- sta = mesh_plink_add(mac, DEFAULT_RATES, sdata);
+ sta = mesh_plink_alloc(sdata, mac, DEFAULT_RATES, GFP_KERNEL);
else
- sta = sta_info_add(sdata, mac);
-
- if (IS_ERR(sta))
- return PTR_ERR(sta);
-
- if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN ||
- sdata->vif.type == IEEE80211_IF_TYPE_AP)
- ieee80211_send_layer2_update(sta);
+ sta = sta_info_alloc(sdata, mac, GFP_KERNEL);
+ if (!sta)
+ return -ENOMEM;
sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
@@ -658,6 +667,21 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
rate_control_rate_init(sta, local);
+ rcu_read_lock();
+
+ err = sta_info_insert(sta);
+ if (err) {
+ sta_info_destroy(sta);
+ rcu_read_unlock();
+ return err;
+ }
+
+ if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN ||
+ sdata->vif.type == IEEE80211_IF_TYPE_AP)
+ ieee80211_send_layer2_update(sta);
+
+ rcu_read_unlock();
+
return 0;
}