aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/cfg.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-04-08 11:56:52 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-04-08 16:44:45 -0400
commit3b96766f0e643f52ae19e134664df6730c737e87 (patch)
treeb1707d94a14c9777f09b1aab33970e7741190d4c /net/mac80211/cfg.c
parent7d1559f1737d5ca27b267b0392015f42b3bbe2fa (diff)
mac80211: fix key vs. sta locking problems
Up to now, key manipulation is supposed to run under RTNL to avoid concurrent manipulations and also allow the set_key() hardware callback to sleep. This is not feasible because STA structs are rcu-protected and thus a lot of operations there cannot take the RTNL. Also, key references are rcu-protected so we cannot do things atomically. This patch changes key locking completely: * key operations are now atomic * hardware crypto offload is enabled and disabled from a workqueue, due to that key freeing is also delayed * debugfs code is also run from a workqueue * keys reference STAs (and vice versa!) so during STA unlink the STAs key reference is removed but not the keys STA reference, to avoid races key todo work is run before STA destruction. * fewer STA operations now need the RTNL which was required due to key operations This fixes the locking problems lockdep pointed out and also makes things more light-weight because the rtnl isn't required as much. Note that the key todo lock/key mutex are global locks, this is not required, of course, they could be per-hardware instead. 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.c44
1 files changed, 34 insertions, 10 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 5f8db5cab65d..fe05a7b85dc6 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -135,6 +135,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
135 struct sta_info *sta = NULL; 135 struct sta_info *sta = NULL;
136 enum ieee80211_key_alg alg; 136 enum ieee80211_key_alg alg;
137 struct ieee80211_key *key; 137 struct ieee80211_key *key;
138 int err;
138 139
139 sdata = IEEE80211_DEV_TO_SUB_IF(dev); 140 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
140 141
@@ -157,17 +158,24 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
157 if (!key) 158 if (!key)
158 return -ENOMEM; 159 return -ENOMEM;
159 160
161 rcu_read_lock();
162
160 if (mac_addr) { 163 if (mac_addr) {
161 sta = sta_info_get(sdata->local, mac_addr); 164 sta = sta_info_get(sdata->local, mac_addr);
162 if (!sta) { 165 if (!sta) {
163 ieee80211_key_free(key); 166 ieee80211_key_free(key);
164 return -ENOENT; 167 err = -ENOENT;
168 goto out_unlock;
165 } 169 }
166 } 170 }
167 171
168 ieee80211_key_link(key, sdata, sta); 172 ieee80211_key_link(key, sdata, sta);
169 173
170 return 0; 174 err = 0;
175 out_unlock:
176 rcu_read_unlock();
177
178 return err;
171} 179}
172 180
173static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, 181static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
@@ -179,28 +187,37 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
179 187
180 sdata = IEEE80211_DEV_TO_SUB_IF(dev); 188 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
181 189
190 rcu_read_lock();
191
182 if (mac_addr) { 192 if (mac_addr) {
193 ret = -ENOENT;
194
183 sta = sta_info_get(sdata->local, mac_addr); 195 sta = sta_info_get(sdata->local, mac_addr);
184 if (!sta) 196 if (!sta)
185 return -ENOENT; 197 goto out_unlock;
186 198
187 ret = 0;
188 if (sta->key) { 199 if (sta->key) {
189 ieee80211_key_free(sta->key); 200 ieee80211_key_free(sta->key);
190 WARN_ON(sta->key); 201 WARN_ON(sta->key);
191 } else 202 ret = 0;
192 ret = -ENOENT; 203 }
193 204
194 return ret; 205 goto out_unlock;
195 } 206 }
196 207
197 if (!sdata->keys[key_idx]) 208 if (!sdata->keys[key_idx]) {
198 return -ENOENT; 209 ret = -ENOENT;
210 goto out_unlock;
211 }
199 212
200 ieee80211_key_free(sdata->keys[key_idx]); 213 ieee80211_key_free(sdata->keys[key_idx]);
201 WARN_ON(sdata->keys[key_idx]); 214 WARN_ON(sdata->keys[key_idx]);
202 215
203 return 0; 216 ret = 0;
217 out_unlock:
218 rcu_read_unlock();
219
220 return ret;
204} 221}
205 222
206static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, 223static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
@@ -217,6 +234,8 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
217 u16 iv16; 234 u16 iv16;
218 int err = -ENOENT; 235 int err = -ENOENT;
219 236
237 rcu_read_lock();
238
220 if (mac_addr) { 239 if (mac_addr) {
221 sta = sta_info_get(sdata->local, mac_addr); 240 sta = sta_info_get(sdata->local, mac_addr);
222 if (!sta) 241 if (!sta)
@@ -280,6 +299,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
280 err = 0; 299 err = 0;
281 300
282 out: 301 out:
302 rcu_read_unlock();
283 return err; 303 return err;
284} 304}
285 305
@@ -289,9 +309,13 @@ static int ieee80211_config_default_key(struct wiphy *wiphy,
289{ 309{
290 struct ieee80211_sub_if_data *sdata; 310 struct ieee80211_sub_if_data *sdata;
291 311
312 rcu_read_lock();
313
292 sdata = IEEE80211_DEV_TO_SUB_IF(dev); 314 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
293 ieee80211_set_default_key(sdata, key_idx); 315 ieee80211_set_default_key(sdata, key_idx);
294 316
317 rcu_read_unlock();
318
295 return 0; 319 return 0;
296} 320}
297 321