diff options
Diffstat (limited to 'net/mac80211/key.c')
-rw-r--r-- | net/mac80211/key.c | 408 |
1 files changed, 264 insertions, 144 deletions
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 5df9e0cc009f..711e36e54ff8 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Copyright 2002-2005, Instant802 Networks, Inc. | 2 | * Copyright 2002-2005, Instant802 Networks, Inc. |
3 | * Copyright 2005-2006, Devicescape Software, Inc. | 3 | * Copyright 2005-2006, Devicescape Software, Inc. |
4 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | 4 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
5 | * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> | 5 | * Copyright 2007-2008 Johannes Berg <johannes@sipsolutions.net> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
@@ -33,17 +33,78 @@ | |||
33 | * There is currently no way of knowing this except by looking into | 33 | * There is currently no way of knowing this except by looking into |
34 | * debugfs. | 34 | * debugfs. |
35 | * | 35 | * |
36 | * All operations here are called under RTNL so no extra locking is | 36 | * All key operations are protected internally so you can call them at |
37 | * required. | 37 | * any time. |
38 | * | 38 | * |
39 | * NOTE: This code requires that sta info *destruction* is done under | 39 | * Within mac80211, key references are, just as STA structure references, |
40 | * RTNL, otherwise it can try to access already freed STA structs | 40 | * protected by RCU. Note, however, that some things are unprotected, |
41 | * when a STA key is being freed. | 41 | * namely the key->sta dereferences within the hardware acceleration |
42 | * functions. This means that sta_info_destroy() must flush the key todo | ||
43 | * list. | ||
44 | * | ||
45 | * All the direct key list manipulation functions must not sleep because | ||
46 | * they can operate on STA info structs that are protected by RCU. | ||
42 | */ | 47 | */ |
43 | 48 | ||
44 | static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; | 49 | static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; |
45 | static const u8 zero_addr[ETH_ALEN]; | 50 | static const u8 zero_addr[ETH_ALEN]; |
46 | 51 | ||
52 | /* key mutex: used to synchronise todo runners */ | ||
53 | static DEFINE_MUTEX(key_mutex); | ||
54 | static DEFINE_SPINLOCK(todo_lock); | ||
55 | static LIST_HEAD(todo_list); | ||
56 | |||
57 | static void key_todo(struct work_struct *work) | ||
58 | { | ||
59 | ieee80211_key_todo(); | ||
60 | } | ||
61 | |||
62 | static DECLARE_WORK(todo_work, key_todo); | ||
63 | |||
64 | /** | ||
65 | * add_todo - add todo item for a key | ||
66 | * | ||
67 | * @key: key to add to do item for | ||
68 | * @flag: todo flag(s) | ||
69 | */ | ||
70 | static void add_todo(struct ieee80211_key *key, u32 flag) | ||
71 | { | ||
72 | if (!key) | ||
73 | return; | ||
74 | |||
75 | spin_lock(&todo_lock); | ||
76 | key->flags |= flag; | ||
77 | /* only add if not already added */ | ||
78 | if (list_empty(&key->todo)) | ||
79 | list_add(&key->todo, &todo_list); | ||
80 | schedule_work(&todo_work); | ||
81 | spin_unlock(&todo_lock); | ||
82 | } | ||
83 | |||
84 | /** | ||
85 | * ieee80211_key_lock - lock the mac80211 key operation lock | ||
86 | * | ||
87 | * This locks the (global) mac80211 key operation lock, all | ||
88 | * key operations must be done under this lock. | ||
89 | */ | ||
90 | static void ieee80211_key_lock(void) | ||
91 | { | ||
92 | mutex_lock(&key_mutex); | ||
93 | } | ||
94 | |||
95 | /** | ||
96 | * ieee80211_key_unlock - unlock the mac80211 key operation lock | ||
97 | */ | ||
98 | static void ieee80211_key_unlock(void) | ||
99 | { | ||
100 | mutex_unlock(&key_mutex); | ||
101 | } | ||
102 | |||
103 | static void assert_key_lock(void) | ||
104 | { | ||
105 | WARN_ON(!mutex_is_locked(&key_mutex)); | ||
106 | } | ||
107 | |||
47 | static const u8 *get_mac_for_key(struct ieee80211_key *key) | 108 | static const u8 *get_mac_for_key(struct ieee80211_key *key) |
48 | { | 109 | { |
49 | const u8 *addr = bcast_addr; | 110 | const u8 *addr = bcast_addr; |
@@ -70,26 +131,23 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
70 | int ret; | 131 | int ret; |
71 | DECLARE_MAC_BUF(mac); | 132 | DECLARE_MAC_BUF(mac); |
72 | 133 | ||
134 | assert_key_lock(); | ||
135 | might_sleep(); | ||
136 | |||
73 | if (!key->local->ops->set_key) | 137 | if (!key->local->ops->set_key) |
74 | return; | 138 | return; |
75 | 139 | ||
76 | /* | ||
77 | * This makes sure that all pending flushes have | ||
78 | * actually completed prior to uploading new key | ||
79 | * material to the hardware. That is necessary to | ||
80 | * avoid races between flushing STAs and adding | ||
81 | * new keys for them. | ||
82 | */ | ||
83 | __ieee80211_run_pending_flush(key->local); | ||
84 | |||
85 | addr = get_mac_for_key(key); | 140 | addr = get_mac_for_key(key); |
86 | 141 | ||
87 | ret = key->local->ops->set_key(local_to_hw(key->local), SET_KEY, | 142 | ret = key->local->ops->set_key(local_to_hw(key->local), SET_KEY, |
88 | key->sdata->dev->dev_addr, addr, | 143 | key->sdata->dev->dev_addr, addr, |
89 | &key->conf); | 144 | &key->conf); |
90 | 145 | ||
91 | if (!ret) | 146 | if (!ret) { |
147 | spin_lock(&todo_lock); | ||
92 | key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; | 148 | key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; |
149 | spin_unlock(&todo_lock); | ||
150 | } | ||
93 | 151 | ||
94 | if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP) | 152 | if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP) |
95 | printk(KERN_ERR "mac80211-%s: failed to set key " | 153 | printk(KERN_ERR "mac80211-%s: failed to set key " |
@@ -98,26 +156,24 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
98 | key->conf.keyidx, print_mac(mac, addr), ret); | 156 | key->conf.keyidx, print_mac(mac, addr), ret); |
99 | } | 157 | } |
100 | 158 | ||
101 | static void ieee80211_key_mark_hw_accel_off(struct ieee80211_key *key) | ||
102 | { | ||
103 | if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { | ||
104 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; | ||
105 | key->flags |= KEY_FLAG_REMOVE_FROM_HARDWARE; | ||
106 | } | ||
107 | } | ||
108 | |||
109 | static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | 159 | static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) |
110 | { | 160 | { |
111 | const u8 *addr; | 161 | const u8 *addr; |
112 | int ret; | 162 | int ret; |
113 | DECLARE_MAC_BUF(mac); | 163 | DECLARE_MAC_BUF(mac); |
114 | 164 | ||
165 | assert_key_lock(); | ||
166 | might_sleep(); | ||
167 | |||
115 | if (!key || !key->local->ops->set_key) | 168 | if (!key || !key->local->ops->set_key) |
116 | return; | 169 | return; |
117 | 170 | ||
118 | if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && | 171 | spin_lock(&todo_lock); |
119 | !(key->flags & KEY_FLAG_REMOVE_FROM_HARDWARE)) | 172 | if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { |
173 | spin_unlock(&todo_lock); | ||
120 | return; | 174 | return; |
175 | } | ||
176 | spin_unlock(&todo_lock); | ||
121 | 177 | ||
122 | addr = get_mac_for_key(key); | 178 | addr = get_mac_for_key(key); |
123 | 179 | ||
@@ -131,8 +187,72 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | |||
131 | wiphy_name(key->local->hw.wiphy), | 187 | wiphy_name(key->local->hw.wiphy), |
132 | key->conf.keyidx, print_mac(mac, addr), ret); | 188 | key->conf.keyidx, print_mac(mac, addr), ret); |
133 | 189 | ||
134 | key->flags &= ~(KEY_FLAG_UPLOADED_TO_HARDWARE | | 190 | spin_lock(&todo_lock); |
135 | KEY_FLAG_REMOVE_FROM_HARDWARE); | 191 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; |
192 | spin_unlock(&todo_lock); | ||
193 | } | ||
194 | |||
195 | static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, | ||
196 | int idx) | ||
197 | { | ||
198 | struct ieee80211_key *key = NULL; | ||
199 | |||
200 | if (idx >= 0 && idx < NUM_DEFAULT_KEYS) | ||
201 | key = sdata->keys[idx]; | ||
202 | |||
203 | rcu_assign_pointer(sdata->default_key, key); | ||
204 | |||
205 | if (key) | ||
206 | add_todo(key, KEY_FLAG_TODO_DEFKEY); | ||
207 | } | ||
208 | |||
209 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx) | ||
210 | { | ||
211 | unsigned long flags; | ||
212 | |||
213 | spin_lock_irqsave(&sdata->local->sta_lock, flags); | ||
214 | __ieee80211_set_default_key(sdata, idx); | ||
215 | spin_unlock_irqrestore(&sdata->local->sta_lock, flags); | ||
216 | } | ||
217 | |||
218 | |||
219 | static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | ||
220 | struct sta_info *sta, | ||
221 | struct ieee80211_key *old, | ||
222 | struct ieee80211_key *new) | ||
223 | { | ||
224 | int idx, defkey; | ||
225 | |||
226 | if (new) | ||
227 | list_add(&new->list, &sdata->key_list); | ||
228 | |||
229 | if (sta) { | ||
230 | rcu_assign_pointer(sta->key, new); | ||
231 | } else { | ||
232 | WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); | ||
233 | |||
234 | if (old) | ||
235 | idx = old->conf.keyidx; | ||
236 | else | ||
237 | idx = new->conf.keyidx; | ||
238 | |||
239 | defkey = old && sdata->default_key == old; | ||
240 | |||
241 | if (defkey && !new) | ||
242 | __ieee80211_set_default_key(sdata, -1); | ||
243 | |||
244 | rcu_assign_pointer(sdata->keys[idx], new); | ||
245 | if (defkey && new) | ||
246 | __ieee80211_set_default_key(sdata, new->conf.keyidx); | ||
247 | } | ||
248 | |||
249 | if (old) { | ||
250 | /* | ||
251 | * We'll use an empty list to indicate that the key | ||
252 | * has already been removed. | ||
253 | */ | ||
254 | list_del_init(&old->list); | ||
255 | } | ||
136 | } | 256 | } |
137 | 257 | ||
138 | struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | 258 | struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, |
@@ -160,6 +280,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | |||
160 | key->conf.keylen = key_len; | 280 | key->conf.keylen = key_len; |
161 | memcpy(key->conf.key, key_data, key_len); | 281 | memcpy(key->conf.key, key_data, key_len); |
162 | INIT_LIST_HEAD(&key->list); | 282 | INIT_LIST_HEAD(&key->list); |
283 | INIT_LIST_HEAD(&key->todo); | ||
163 | 284 | ||
164 | if (alg == ALG_CCMP) { | 285 | if (alg == ALG_CCMP) { |
165 | /* | 286 | /* |
@@ -168,7 +289,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | |||
168 | */ | 289 | */ |
169 | key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(key_data); | 290 | key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(key_data); |
170 | if (!key->u.ccmp.tfm) { | 291 | if (!key->u.ccmp.tfm) { |
171 | ieee80211_key_free(key); | 292 | kfree(key); |
172 | return NULL; | 293 | return NULL; |
173 | } | 294 | } |
174 | } | 295 | } |
@@ -176,56 +297,14 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | |||
176 | return key; | 297 | return key; |
177 | } | 298 | } |
178 | 299 | ||
179 | static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | ||
180 | struct sta_info *sta, | ||
181 | struct ieee80211_key *key, | ||
182 | struct ieee80211_key *new) | ||
183 | { | ||
184 | int idx, defkey; | ||
185 | |||
186 | if (new) | ||
187 | list_add(&new->list, &sdata->key_list); | ||
188 | |||
189 | if (sta) { | ||
190 | rcu_assign_pointer(sta->key, new); | ||
191 | } else { | ||
192 | WARN_ON(new && key && new->conf.keyidx != key->conf.keyidx); | ||
193 | |||
194 | if (key) | ||
195 | idx = key->conf.keyidx; | ||
196 | else | ||
197 | idx = new->conf.keyidx; | ||
198 | |||
199 | defkey = key && sdata->default_key == key; | ||
200 | |||
201 | if (defkey && !new) | ||
202 | ieee80211_set_default_key(sdata, -1); | ||
203 | |||
204 | rcu_assign_pointer(sdata->keys[idx], new); | ||
205 | if (defkey && new) | ||
206 | ieee80211_set_default_key(sdata, new->conf.keyidx); | ||
207 | } | ||
208 | |||
209 | if (key) { | ||
210 | ieee80211_key_mark_hw_accel_off(key); | ||
211 | /* | ||
212 | * We'll use an empty list to indicate that the key | ||
213 | * has already been removed. | ||
214 | */ | ||
215 | list_del_init(&key->list); | ||
216 | } | ||
217 | } | ||
218 | |||
219 | void ieee80211_key_link(struct ieee80211_key *key, | 300 | void ieee80211_key_link(struct ieee80211_key *key, |
220 | struct ieee80211_sub_if_data *sdata, | 301 | struct ieee80211_sub_if_data *sdata, |
221 | struct sta_info *sta) | 302 | struct sta_info *sta) |
222 | { | 303 | { |
223 | struct ieee80211_key *old_key; | 304 | struct ieee80211_key *old_key; |
305 | unsigned long flags; | ||
224 | int idx; | 306 | int idx; |
225 | 307 | ||
226 | ASSERT_RTNL(); | ||
227 | might_sleep(); | ||
228 | |||
229 | BUG_ON(!sdata); | 308 | BUG_ON(!sdata); |
230 | BUG_ON(!key); | 309 | BUG_ON(!key); |
231 | 310 | ||
@@ -234,11 +313,7 @@ void ieee80211_key_link(struct ieee80211_key *key, | |||
234 | key->sdata = sdata; | 313 | key->sdata = sdata; |
235 | key->sta = sta; | 314 | key->sta = sta; |
236 | 315 | ||
237 | ieee80211_debugfs_key_add(key->local, key); | ||
238 | |||
239 | if (sta) { | 316 | if (sta) { |
240 | ieee80211_debugfs_key_sta_link(key, sta); | ||
241 | |||
242 | /* | 317 | /* |
243 | * some hardware cannot handle TKIP with QoS, so | 318 | * some hardware cannot handle TKIP with QoS, so |
244 | * we indicate whether QoS could be in use. | 319 | * we indicate whether QoS could be in use. |
@@ -249,7 +324,10 @@ void ieee80211_key_link(struct ieee80211_key *key, | |||
249 | if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { | 324 | if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { |
250 | struct sta_info *ap; | 325 | struct sta_info *ap; |
251 | 326 | ||
252 | rcu_read_lock(); | 327 | /* |
328 | * We're getting a sta pointer in, | ||
329 | * so must be under RCU read lock. | ||
330 | */ | ||
253 | 331 | ||
254 | /* same here, the AP could be using QoS */ | 332 | /* same here, the AP could be using QoS */ |
255 | ap = sta_info_get(key->local, key->sdata->u.sta.bssid); | 333 | ap = sta_info_get(key->local, key->sdata->u.sta.bssid); |
@@ -258,11 +336,11 @@ void ieee80211_key_link(struct ieee80211_key *key, | |||
258 | key->conf.flags |= | 336 | key->conf.flags |= |
259 | IEEE80211_KEY_FLAG_WMM_STA; | 337 | IEEE80211_KEY_FLAG_WMM_STA; |
260 | } | 338 | } |
261 | |||
262 | rcu_read_unlock(); | ||
263 | } | 339 | } |
264 | } | 340 | } |
265 | 341 | ||
342 | spin_lock_irqsave(&sdata->local->sta_lock, flags); | ||
343 | |||
266 | if (sta) | 344 | if (sta) |
267 | old_key = sta->key; | 345 | old_key = sta->key; |
268 | else | 346 | else |
@@ -270,108 +348,150 @@ void ieee80211_key_link(struct ieee80211_key *key, | |||
270 | 348 | ||
271 | __ieee80211_key_replace(sdata, sta, old_key, key); | 349 | __ieee80211_key_replace(sdata, sta, old_key, key); |
272 | 350 | ||
273 | if (old_key) { | 351 | spin_unlock_irqrestore(&sdata->local->sta_lock, flags); |
274 | synchronize_rcu(); | 352 | |
275 | ieee80211_key_free(old_key); | 353 | /* free old key later */ |
276 | } | 354 | add_todo(old_key, KEY_FLAG_TODO_DELETE); |
277 | 355 | ||
356 | add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS); | ||
278 | if (netif_running(sdata->dev)) | 357 | if (netif_running(sdata->dev)) |
279 | ieee80211_key_enable_hw_accel(key); | 358 | add_todo(key, KEY_FLAG_TODO_HWACCEL); |
280 | } | 359 | } |
281 | 360 | ||
282 | void ieee80211_key_free(struct ieee80211_key *key) | 361 | void ieee80211_key_free(struct ieee80211_key *key) |
283 | { | 362 | { |
284 | ASSERT_RTNL(); | 363 | unsigned long flags; |
285 | might_sleep(); | ||
286 | 364 | ||
287 | if (!key) | 365 | if (!key) |
288 | return; | 366 | return; |
289 | 367 | ||
368 | /* | ||
369 | * Replace key with nothingness if it was ever used. | ||
370 | */ | ||
290 | if (key->sdata) { | 371 | if (key->sdata) { |
291 | /* | 372 | spin_lock_irqsave(&key->sdata->local->sta_lock, flags); |
292 | * Replace key with nothingness. | 373 | __ieee80211_key_replace(key->sdata, key->sta, |
293 | * | 374 | key, NULL); |
294 | * Because other code may have key reference (RCU protected) | 375 | spin_unlock_irqrestore(&key->sdata->local->sta_lock, flags); |
295 | * right now, we then wait for a grace period before freeing | 376 | } |
296 | * it. | ||
297 | * An empty list indicates it was never added to the key list | ||
298 | * or has been removed already. It may, however, still be in | ||
299 | * hardware for acceleration. | ||
300 | */ | ||
301 | if (!list_empty(&key->list)) | ||
302 | __ieee80211_key_replace(key->sdata, key->sta, | ||
303 | key, NULL); | ||
304 | 377 | ||
305 | /* | 378 | add_todo(key, KEY_FLAG_TODO_DELETE); |
306 | * Do NOT remove this without looking at sta_info_destroy() | 379 | } |
307 | */ | ||
308 | synchronize_rcu(); | ||
309 | 380 | ||
310 | /* | 381 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) |
311 | * Remove from hwaccel if appropriate, this will | 382 | { |
312 | * only happen when the key is actually unlinked, | 383 | struct ieee80211_key *key; |
313 | * it will already be done when the key was replaced. | ||
314 | */ | ||
315 | ieee80211_key_disable_hw_accel(key); | ||
316 | } | ||
317 | 384 | ||
318 | if (key->conf.alg == ALG_CCMP) | 385 | might_sleep(); |
319 | ieee80211_aes_key_free(key->u.ccmp.tfm); | ||
320 | ieee80211_debugfs_key_remove(key); | ||
321 | 386 | ||
322 | kfree(key); | 387 | if (WARN_ON(!netif_running(sdata->dev))) |
388 | return; | ||
389 | |||
390 | ieee80211_key_lock(); | ||
391 | |||
392 | list_for_each_entry(key, &sdata->key_list, list) | ||
393 | ieee80211_key_enable_hw_accel(key); | ||
394 | |||
395 | ieee80211_key_unlock(); | ||
323 | } | 396 | } |
324 | 397 | ||
325 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx) | 398 | void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata) |
326 | { | 399 | { |
327 | struct ieee80211_key *key = NULL; | 400 | struct ieee80211_key *key; |
328 | 401 | ||
329 | if (idx >= 0 && idx < NUM_DEFAULT_KEYS) | 402 | might_sleep(); |
330 | key = sdata->keys[idx]; | ||
331 | 403 | ||
332 | if (sdata->default_key != key) { | 404 | ieee80211_key_lock(); |
333 | ieee80211_debugfs_key_remove_default(sdata); | ||
334 | 405 | ||
335 | rcu_assign_pointer(sdata->default_key, key); | 406 | list_for_each_entry(key, &sdata->key_list, list) |
407 | ieee80211_key_disable_hw_accel(key); | ||
336 | 408 | ||
337 | if (sdata->default_key) | 409 | ieee80211_key_unlock(); |
338 | ieee80211_debugfs_key_add_default(sdata); | ||
339 | } | ||
340 | } | 410 | } |
341 | 411 | ||
342 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) | 412 | static void __ieee80211_key_free(struct ieee80211_key *key) |
343 | { | 413 | { |
344 | struct ieee80211_key *key, *tmp; | 414 | if (!key) |
345 | LIST_HEAD(tmp_list); | 415 | return; |
346 | 416 | ||
347 | ASSERT_RTNL(); | 417 | ieee80211_key_disable_hw_accel(key); |
348 | might_sleep(); | ||
349 | 418 | ||
350 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) | 419 | if (key->conf.alg == ALG_CCMP) |
351 | ieee80211_key_free(key); | 420 | ieee80211_aes_key_free(key->u.ccmp.tfm); |
421 | ieee80211_debugfs_key_remove(key); | ||
422 | |||
423 | kfree(key); | ||
352 | } | 424 | } |
353 | 425 | ||
354 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) | 426 | static void __ieee80211_key_todo(void) |
355 | { | 427 | { |
356 | struct ieee80211_key *key; | 428 | struct ieee80211_key *key; |
429 | bool work_done; | ||
430 | u32 todoflags; | ||
357 | 431 | ||
358 | ASSERT_RTNL(); | 432 | /* |
359 | might_sleep(); | 433 | * NB: sta_info_destroy relies on this! |
434 | */ | ||
435 | synchronize_rcu(); | ||
436 | |||
437 | spin_lock(&todo_lock); | ||
438 | while (!list_empty(&todo_list)) { | ||
439 | key = list_first_entry(&todo_list, struct ieee80211_key, todo); | ||
440 | list_del_init(&key->todo); | ||
441 | todoflags = key->flags & (KEY_FLAG_TODO_ADD_DEBUGFS | | ||
442 | KEY_FLAG_TODO_DEFKEY | | ||
443 | KEY_FLAG_TODO_HWACCEL | | ||
444 | KEY_FLAG_TODO_DELETE); | ||
445 | key->flags &= ~todoflags; | ||
446 | spin_unlock(&todo_lock); | ||
447 | |||
448 | work_done = false; | ||
449 | |||
450 | if (todoflags & KEY_FLAG_TODO_ADD_DEBUGFS) { | ||
451 | ieee80211_debugfs_key_add(key); | ||
452 | work_done = true; | ||
453 | } | ||
454 | if (todoflags & KEY_FLAG_TODO_DEFKEY) { | ||
455 | ieee80211_debugfs_key_remove_default(key->sdata); | ||
456 | ieee80211_debugfs_key_add_default(key->sdata); | ||
457 | work_done = true; | ||
458 | } | ||
459 | if (todoflags & KEY_FLAG_TODO_HWACCEL) { | ||
460 | ieee80211_key_enable_hw_accel(key); | ||
461 | work_done = true; | ||
462 | } | ||
463 | if (todoflags & KEY_FLAG_TODO_DELETE) { | ||
464 | __ieee80211_key_free(key); | ||
465 | work_done = true; | ||
466 | } | ||
360 | 467 | ||
361 | if (WARN_ON(!netif_running(sdata->dev))) | 468 | WARN_ON(!work_done); |
362 | return; | ||
363 | 469 | ||
364 | list_for_each_entry(key, &sdata->key_list, list) | 470 | spin_lock(&todo_lock); |
365 | ieee80211_key_enable_hw_accel(key); | 471 | } |
472 | spin_unlock(&todo_lock); | ||
366 | } | 473 | } |
367 | 474 | ||
368 | void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata) | 475 | void ieee80211_key_todo(void) |
369 | { | 476 | { |
370 | struct ieee80211_key *key; | 477 | ieee80211_key_lock(); |
478 | __ieee80211_key_todo(); | ||
479 | ieee80211_key_unlock(); | ||
480 | } | ||
371 | 481 | ||
372 | ASSERT_RTNL(); | 482 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) |
373 | might_sleep(); | 483 | { |
484 | struct ieee80211_key *key, *tmp; | ||
485 | LIST_HEAD(tmp_list); | ||
374 | 486 | ||
375 | list_for_each_entry(key, &sdata->key_list, list) | 487 | ieee80211_key_lock(); |
376 | ieee80211_key_disable_hw_accel(key); | 488 | |
489 | ieee80211_debugfs_key_remove_default(sdata); | ||
490 | |||
491 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) | ||
492 | ieee80211_key_free(key); | ||
493 | |||
494 | __ieee80211_key_todo(); | ||
495 | |||
496 | ieee80211_key_unlock(); | ||
377 | } | 497 | } |