aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/cfg.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-02-25 10:27:45 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-02-29 15:42:04 -0500
commitdb4d1169d0b893bfb7923b6526748fe2c5a7373f (patch)
treeebd5ac06685bacc069b162b31f99b33c6191b4c3 /net/mac80211/cfg.c
parent6f48422a29714ed92f6136d9e7d3ff39c75607d7 (diff)
mac80211: split ieee80211_key_alloc/free
In order to RCU-ify sta_info, we need to be able to allocate a key without linking it to an sdata/sta structure (because allocation cannot be done in an rcu critical section). This patch splits up ieee80211_key_alloc() and updates all users appropriately. While at it, this patch fixes a number of race conditions such as finally making key replacement atomic, unfortunately at the expense of more complex code. Note that this patch documents /existing/ bugs with sta info and key interaction, there is currently a race condition when a sta info is freed without holding the RTNL. This will finally be fixed by a followup 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.c27
1 files changed, 19 insertions, 8 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index b0c41a0cee79..e7535ffc8e1c 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -123,6 +123,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
123 struct sta_info *sta = NULL; 123 struct sta_info *sta = NULL;
124 enum ieee80211_key_alg alg; 124 enum ieee80211_key_alg alg;
125 int ret; 125 int ret;
126 struct ieee80211_key *key;
126 127
127 sdata = IEEE80211_DEV_TO_SUB_IF(dev); 128 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
128 129
@@ -141,16 +142,21 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
141 return -EINVAL; 142 return -EINVAL;
142 } 143 }
143 144
145 key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key);
146 if (!key)
147 return -ENOMEM;
148
144 if (mac_addr) { 149 if (mac_addr) {
145 sta = sta_info_get(sdata->local, mac_addr); 150 sta = sta_info_get(sdata->local, mac_addr);
146 if (!sta) 151 if (!sta) {
152 ieee80211_key_free(key);
147 return -ENOENT; 153 return -ENOENT;
154 }
148 } 155 }
149 156
157 ieee80211_key_link(key, sdata, sta);
158
150 ret = 0; 159 ret = 0;
151 if (!ieee80211_key_alloc(sdata, sta, alg, key_idx,
152 params->key_len, params->key))
153 ret = -ENOMEM;
154 160
155 if (sta) 161 if (sta)
156 sta_info_put(sta); 162 sta_info_put(sta);
@@ -164,6 +170,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
164 struct ieee80211_sub_if_data *sdata; 170 struct ieee80211_sub_if_data *sdata;
165 struct sta_info *sta; 171 struct sta_info *sta;
166 int ret; 172 int ret;
173 struct ieee80211_key *key;
167 174
168 sdata = IEEE80211_DEV_TO_SUB_IF(dev); 175 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
169 176
@@ -173,9 +180,11 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
173 return -ENOENT; 180 return -ENOENT;
174 181
175 ret = 0; 182 ret = 0;
176 if (sta->key) 183 if (sta->key) {
177 ieee80211_key_free(sta->key); 184 key = sta->key;
178 else 185 ieee80211_key_free(key);
186 WARN_ON(sta->key);
187 } else
179 ret = -ENOENT; 188 ret = -ENOENT;
180 189
181 sta_info_put(sta); 190 sta_info_put(sta);
@@ -185,7 +194,9 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
185 if (!sdata->keys[key_idx]) 194 if (!sdata->keys[key_idx])
186 return -ENOENT; 195 return -ENOENT;
187 196
188 ieee80211_key_free(sdata->keys[key_idx]); 197 key = sdata->keys[key_idx];
198 ieee80211_key_free(key);
199 WARN_ON(sdata->keys[key_idx]);
189 200
190 return 0; 201 return 0;
191} 202}