aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2010-06-01 04:19:19 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-06-03 14:10:46 -0400
commitad0e2b5a00dbec303e4682b403bb6703d11dcdb2 (patch)
treeb7aeb06a284af0cfb4aa1de840592478b373f554 /net
parentefe4c457a1d4e56840c42bf2e409dc04e8ad4304 (diff)
mac80211: simplify key locking
Since I recently made station management able to sleep, I can now rework key management as well; since it will no longer need a spinlock and can also use a mutex instead, a bunch of code to allow drivers' set_key to sleep while key management is protected by a spinlock can now be removed. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/cfg.c18
-rw-r--r--net/mac80211/ieee80211_i.h4
-rw-r--r--net/mac80211/iface.c5
-rw-r--r--net/mac80211/key.c288
-rw-r--r--net/mac80211/key.h22
-rw-r--r--net/mac80211/main.c2
-rw-r--r--net/mac80211/sta_info.c8
7 files changed, 80 insertions, 267 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index f8c49c5ad8aa..952845e7072a 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -120,6 +120,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
120 struct ieee80211_key *key; 120 struct ieee80211_key *key;
121 int err; 121 int err;
122 122
123 if (!netif_running(dev))
124 return -ENETDOWN;
125
123 sdata = IEEE80211_DEV_TO_SUB_IF(dev); 126 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
124 127
125 switch (params->cipher) { 128 switch (params->cipher) {
@@ -145,7 +148,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
145 if (!key) 148 if (!key)
146 return -ENOMEM; 149 return -ENOMEM;
147 150
148 rcu_read_lock(); 151 mutex_lock(&sdata->local->sta_mtx);
149 152
150 if (mac_addr) { 153 if (mac_addr) {
151 sta = sta_info_get_bss(sdata, mac_addr); 154 sta = sta_info_get_bss(sdata, mac_addr);
@@ -160,7 +163,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
160 163
161 err = 0; 164 err = 0;
162 out_unlock: 165 out_unlock:
163 rcu_read_unlock(); 166 mutex_unlock(&sdata->local->sta_mtx);
164 167
165 return err; 168 return err;
166} 169}
@@ -174,7 +177,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
174 177
175 sdata = IEEE80211_DEV_TO_SUB_IF(dev); 178 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
176 179
177 rcu_read_lock(); 180 mutex_lock(&sdata->local->sta_mtx);
178 181
179 if (mac_addr) { 182 if (mac_addr) {
180 ret = -ENOENT; 183 ret = -ENOENT;
@@ -202,7 +205,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
202 205
203 ret = 0; 206 ret = 0;
204 out_unlock: 207 out_unlock:
205 rcu_read_unlock(); 208 mutex_unlock(&sdata->local->sta_mtx);
206 209
207 return ret; 210 return ret;
208} 211}
@@ -305,15 +308,10 @@ static int ieee80211_config_default_key(struct wiphy *wiphy,
305 struct net_device *dev, 308 struct net_device *dev,
306 u8 key_idx) 309 u8 key_idx)
307{ 310{
308 struct ieee80211_sub_if_data *sdata; 311 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
309
310 rcu_read_lock();
311 312
312 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
313 ieee80211_set_default_key(sdata, key_idx); 313 ieee80211_set_default_key(sdata, key_idx);
314 314
315 rcu_read_unlock();
316
317 return 0; 315 return 0;
318} 316}
319 317
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 47d67537f170..4d3883e20fc1 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -746,10 +746,10 @@ struct ieee80211_local {
746 struct mutex iflist_mtx; 746 struct mutex iflist_mtx;
747 747
748 /* 748 /*
749 * Key lock, protects sdata's key_list and sta_info's 749 * Key mutex, protects sdata's key_list and sta_info's
750 * key pointers (write access, they're RCU.) 750 * key pointers (write access, they're RCU.)
751 */ 751 */
752 spinlock_t key_lock; 752 struct mutex key_mtx;
753 753
754 754
755 /* Scanning and BSS list */ 755 /* Scanning and BSS list */
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 3d3a094d3987..1afa9ec81fe8 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -268,7 +268,6 @@ static int ieee80211_open(struct net_device *dev)
268 268
269 changed |= ieee80211_reset_erp_info(sdata); 269 changed |= ieee80211_reset_erp_info(sdata);
270 ieee80211_bss_info_change_notify(sdata, changed); 270 ieee80211_bss_info_change_notify(sdata, changed);
271 ieee80211_enable_keys(sdata);
272 271
273 if (sdata->vif.type == NL80211_IFTYPE_STATION) 272 if (sdata->vif.type == NL80211_IFTYPE_STATION)
274 netif_carrier_off(dev); 273 netif_carrier_off(dev);
@@ -522,8 +521,8 @@ static int ieee80211_stop(struct net_device *dev)
522 BSS_CHANGED_BEACON_ENABLED); 521 BSS_CHANGED_BEACON_ENABLED);
523 } 522 }
524 523
525 /* disable all keys for as long as this netdev is down */ 524 /* free all remaining keys, there shouldn't be any */
526 ieee80211_disable_keys(sdata); 525 ieee80211_free_keys(sdata);
527 drv_remove_interface(local, &sdata->vif); 526 drv_remove_interface(local, &sdata->vif);
528 } 527 }
529 528
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index e8f6e3b252d8..d0d9001a4a6a 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -36,80 +36,20 @@
36 * There is currently no way of knowing this except by looking into 36 * There is currently no way of knowing this except by looking into
37 * debugfs. 37 * debugfs.
38 * 38 *
39 * All key operations are protected internally so you can call them at 39 * All key operations are protected internally.
40 * any time.
41 * 40 *
42 * Within mac80211, key references are, just as STA structure references, 41 * Within mac80211, key references are, just as STA structure references,
43 * protected by RCU. Note, however, that some things are unprotected, 42 * protected by RCU. Note, however, that some things are unprotected,
44 * namely the key->sta dereferences within the hardware acceleration 43 * namely the key->sta dereferences within the hardware acceleration
45 * functions. This means that sta_info_destroy() must flush the key todo 44 * functions. This means that sta_info_destroy() must remove the key
46 * list. 45 * which waits for an RCU grace period.
47 *
48 * All the direct key list manipulation functions must not sleep because
49 * they can operate on STA info structs that are protected by RCU.
50 */ 46 */
51 47
52static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 48static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
53 49
54/* key mutex: used to synchronise todo runners */ 50static void assert_key_lock(struct ieee80211_local *local)
55static DEFINE_MUTEX(key_mutex);
56static DEFINE_SPINLOCK(todo_lock);
57static LIST_HEAD(todo_list);
58
59static void key_todo(struct work_struct *work)
60{ 51{
61 ieee80211_key_todo(); 52 WARN_ON(!mutex_is_locked(&local->key_mtx));
62}
63
64static DECLARE_WORK(todo_work, key_todo);
65
66/**
67 * add_todo - add todo item for a key
68 *
69 * @key: key to add to do item for
70 * @flag: todo flag(s)
71 *
72 * Must be called with IRQs or softirqs disabled.
73 */
74static void add_todo(struct ieee80211_key *key, u32 flag)
75{
76 if (!key)
77 return;
78
79 spin_lock(&todo_lock);
80 key->flags |= flag;
81 /*
82 * Remove again if already on the list so that we move it to the end.
83 */
84 if (!list_empty(&key->todo))
85 list_del(&key->todo);
86 list_add_tail(&key->todo, &todo_list);
87 schedule_work(&todo_work);
88 spin_unlock(&todo_lock);
89}
90
91/**
92 * ieee80211_key_lock - lock the mac80211 key operation lock
93 *
94 * This locks the (global) mac80211 key operation lock, all
95 * key operations must be done under this lock.
96 */
97static void ieee80211_key_lock(void)
98{
99 mutex_lock(&key_mutex);
100}
101
102/**
103 * ieee80211_key_unlock - unlock the mac80211 key operation lock
104 */
105static void ieee80211_key_unlock(void)
106{
107 mutex_unlock(&key_mutex);
108}
109
110static void assert_key_lock(void)
111{
112 WARN_ON(!mutex_is_locked(&key_mutex));
113} 53}
114 54
115static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key) 55static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key)
@@ -126,12 +66,13 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
126 struct ieee80211_sta *sta; 66 struct ieee80211_sta *sta;
127 int ret; 67 int ret;
128 68
129 assert_key_lock();
130 might_sleep(); 69 might_sleep();
131 70
132 if (!key->local->ops->set_key) 71 if (!key->local->ops->set_key)
133 return; 72 return;
134 73
74 assert_key_lock(key->local);
75
135 sta = get_sta_for_key(key); 76 sta = get_sta_for_key(key);
136 77
137 sdata = key->sdata; 78 sdata = key->sdata;
@@ -142,11 +83,8 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
142 83
143 ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf); 84 ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf);
144 85
145 if (!ret) { 86 if (!ret)
146 spin_lock_bh(&todo_lock);
147 key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; 87 key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
148 spin_unlock_bh(&todo_lock);
149 }
150 88
151 if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP) 89 if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP)
152 printk(KERN_ERR "mac80211-%s: failed to set key " 90 printk(KERN_ERR "mac80211-%s: failed to set key "
@@ -161,18 +99,15 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
161 struct ieee80211_sta *sta; 99 struct ieee80211_sta *sta;
162 int ret; 100 int ret;
163 101
164 assert_key_lock();
165 might_sleep(); 102 might_sleep();
166 103
167 if (!key || !key->local->ops->set_key) 104 if (!key || !key->local->ops->set_key)
168 return; 105 return;
169 106
170 spin_lock_bh(&todo_lock); 107 assert_key_lock(key->local);
171 if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { 108
172 spin_unlock_bh(&todo_lock); 109 if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
173 return; 110 return;
174 }
175 spin_unlock_bh(&todo_lock);
176 111
177 sta = get_sta_for_key(key); 112 sta = get_sta_for_key(key);
178 sdata = key->sdata; 113 sdata = key->sdata;
@@ -191,9 +126,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
191 wiphy_name(key->local->hw.wiphy), 126 wiphy_name(key->local->hw.wiphy),
192 key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); 127 key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
193 128
194 spin_lock_bh(&todo_lock);
195 key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; 129 key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
196 spin_unlock_bh(&todo_lock);
197} 130}
198 131
199static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, 132static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
@@ -201,22 +134,24 @@ static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
201{ 134{
202 struct ieee80211_key *key = NULL; 135 struct ieee80211_key *key = NULL;
203 136
137 assert_key_lock(sdata->local);
138
204 if (idx >= 0 && idx < NUM_DEFAULT_KEYS) 139 if (idx >= 0 && idx < NUM_DEFAULT_KEYS)
205 key = sdata->keys[idx]; 140 key = sdata->keys[idx];
206 141
207 rcu_assign_pointer(sdata->default_key, key); 142 rcu_assign_pointer(sdata->default_key, key);
208 143
209 if (key) 144 if (key) {
210 add_todo(key, KEY_FLAG_TODO_DEFKEY); 145 ieee80211_debugfs_key_remove_default(key->sdata);
146 ieee80211_debugfs_key_add_default(key->sdata);
147 }
211} 148}
212 149
213void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx) 150void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx)
214{ 151{
215 unsigned long flags; 152 mutex_lock(&sdata->local->key_mtx);
216
217 spin_lock_irqsave(&sdata->local->key_lock, flags);
218 __ieee80211_set_default_key(sdata, idx); 153 __ieee80211_set_default_key(sdata, idx);
219 spin_unlock_irqrestore(&sdata->local->key_lock, flags); 154 mutex_unlock(&sdata->local->key_mtx);
220} 155}
221 156
222static void 157static void
@@ -224,24 +159,26 @@ __ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, int idx)
224{ 159{
225 struct ieee80211_key *key = NULL; 160 struct ieee80211_key *key = NULL;
226 161
162 assert_key_lock(sdata->local);
163
227 if (idx >= NUM_DEFAULT_KEYS && 164 if (idx >= NUM_DEFAULT_KEYS &&
228 idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) 165 idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
229 key = sdata->keys[idx]; 166 key = sdata->keys[idx];
230 167
231 rcu_assign_pointer(sdata->default_mgmt_key, key); 168 rcu_assign_pointer(sdata->default_mgmt_key, key);
232 169
233 if (key) 170 if (key) {
234 add_todo(key, KEY_FLAG_TODO_DEFMGMTKEY); 171 ieee80211_debugfs_key_remove_mgmt_default(key->sdata);
172 ieee80211_debugfs_key_add_mgmt_default(key->sdata);
173 }
235} 174}
236 175
237void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, 176void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
238 int idx) 177 int idx)
239{ 178{
240 unsigned long flags; 179 mutex_lock(&sdata->local->key_mtx);
241
242 spin_lock_irqsave(&sdata->local->key_lock, flags);
243 __ieee80211_set_default_mgmt_key(sdata, idx); 180 __ieee80211_set_default_mgmt_key(sdata, idx);
244 spin_unlock_irqrestore(&sdata->local->key_lock, flags); 181 mutex_unlock(&sdata->local->key_mtx);
245} 182}
246 183
247 184
@@ -352,7 +289,6 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
352 } 289 }
353 memcpy(key->conf.key, key_data, key_len); 290 memcpy(key->conf.key, key_data, key_len);
354 INIT_LIST_HEAD(&key->list); 291 INIT_LIST_HEAD(&key->list);
355 INIT_LIST_HEAD(&key->todo);
356 292
357 if (alg == ALG_CCMP) { 293 if (alg == ALG_CCMP) {
358 /* 294 /*
@@ -382,12 +318,27 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
382 return key; 318 return key;
383} 319}
384 320
321static void __ieee80211_key_destroy(struct ieee80211_key *key)
322{
323 if (!key)
324 return;
325
326 ieee80211_key_disable_hw_accel(key);
327
328 if (key->conf.alg == ALG_CCMP)
329 ieee80211_aes_key_free(key->u.ccmp.tfm);
330 if (key->conf.alg == ALG_AES_CMAC)
331 ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
332 ieee80211_debugfs_key_remove(key);
333
334 kfree(key);
335}
336
385void ieee80211_key_link(struct ieee80211_key *key, 337void ieee80211_key_link(struct ieee80211_key *key,
386 struct ieee80211_sub_if_data *sdata, 338 struct ieee80211_sub_if_data *sdata,
387 struct sta_info *sta) 339 struct sta_info *sta)
388{ 340{
389 struct ieee80211_key *old_key; 341 struct ieee80211_key *old_key;
390 unsigned long flags;
391 int idx; 342 int idx;
392 343
393 BUG_ON(!sdata); 344 BUG_ON(!sdata);
@@ -431,7 +382,7 @@ void ieee80211_key_link(struct ieee80211_key *key,
431 } 382 }
432 } 383 }
433 384
434 spin_lock_irqsave(&sdata->local->key_lock, flags); 385 mutex_lock(&sdata->local->key_mtx);
435 386
436 if (sta) 387 if (sta)
437 old_key = sta->key; 388 old_key = sta->key;
@@ -439,15 +390,13 @@ void ieee80211_key_link(struct ieee80211_key *key,
439 old_key = sdata->keys[idx]; 390 old_key = sdata->keys[idx];
440 391
441 __ieee80211_key_replace(sdata, sta, old_key, key); 392 __ieee80211_key_replace(sdata, sta, old_key, key);
393 __ieee80211_key_destroy(old_key);
442 394
443 /* free old key later */ 395 ieee80211_debugfs_key_add(key);
444 add_todo(old_key, KEY_FLAG_TODO_DELETE);
445 396
446 add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS); 397 ieee80211_key_enable_hw_accel(key);
447 if (ieee80211_sdata_running(sdata))
448 add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD);
449 398
450 spin_unlock_irqrestore(&sdata->local->key_lock, flags); 399 mutex_unlock(&sdata->local->key_mtx);
451} 400}
452 401
453static void __ieee80211_key_free(struct ieee80211_key *key) 402static void __ieee80211_key_free(struct ieee80211_key *key)
@@ -458,170 +407,65 @@ static void __ieee80211_key_free(struct ieee80211_key *key)
458 if (key->sdata) 407 if (key->sdata)
459 __ieee80211_key_replace(key->sdata, key->sta, 408 __ieee80211_key_replace(key->sdata, key->sta,
460 key, NULL); 409 key, NULL);
461 410 __ieee80211_key_destroy(key);
462 add_todo(key, KEY_FLAG_TODO_DELETE);
463} 411}
464 412
465void ieee80211_key_free(struct ieee80211_key *key) 413void ieee80211_key_free(struct ieee80211_key *key)
466{ 414{
467 unsigned long flags; 415 struct ieee80211_local *local;
468 416
469 if (!key) 417 if (!key)
470 return; 418 return;
471 419
472 if (!key->sdata) { 420 local = key->sdata->local;
473 /* The key has not been linked yet, simply free it
474 * and don't Oops */
475 if (key->conf.alg == ALG_CCMP)
476 ieee80211_aes_key_free(key->u.ccmp.tfm);
477 kfree(key);
478 return;
479 }
480 421
481 spin_lock_irqsave(&key->sdata->local->key_lock, flags); 422 mutex_lock(&local->key_mtx);
482 __ieee80211_key_free(key); 423 __ieee80211_key_free(key);
483 spin_unlock_irqrestore(&key->sdata->local->key_lock, flags); 424 mutex_unlock(&local->key_mtx);
484} 425}
485 426
486/* 427void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
487 * To be safe against concurrent manipulations of the list (which shouldn't
488 * actually happen) we need to hold the spinlock. But under the spinlock we
489 * can't actually do much, so we defer processing to the todo list. Then run
490 * the todo list to be sure the operation and possibly previously pending
491 * operations are completed.
492 */
493static void ieee80211_todo_for_each_key(struct ieee80211_sub_if_data *sdata,
494 u32 todo_flags)
495{ 428{
496 struct ieee80211_key *key; 429 struct ieee80211_key *key;
497 unsigned long flags;
498
499 might_sleep();
500
501 spin_lock_irqsave(&sdata->local->key_lock, flags);
502 list_for_each_entry(key, &sdata->key_list, list)
503 add_todo(key, todo_flags);
504 spin_unlock_irqrestore(&sdata->local->key_lock, flags);
505
506 ieee80211_key_todo();
507}
508 430
509void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
510{
511 ASSERT_RTNL(); 431 ASSERT_RTNL();
512 432
513 if (WARN_ON(!ieee80211_sdata_running(sdata))) 433 if (WARN_ON(!ieee80211_sdata_running(sdata)))
514 return; 434 return;
515 435
516 ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_ADD); 436 mutex_lock(&sdata->local->key_mtx);
517}
518
519void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata)
520{
521 ASSERT_RTNL();
522
523 ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_REMOVE);
524}
525
526static void __ieee80211_key_destroy(struct ieee80211_key *key)
527{
528 if (!key)
529 return;
530
531 ieee80211_key_disable_hw_accel(key);
532 437
533 if (key->conf.alg == ALG_CCMP) 438 list_for_each_entry(key, &sdata->key_list, list)
534 ieee80211_aes_key_free(key->u.ccmp.tfm); 439 ieee80211_key_enable_hw_accel(key);
535 if (key->conf.alg == ALG_AES_CMAC)
536 ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
537 ieee80211_debugfs_key_remove(key);
538 440
539 kfree(key); 441 mutex_unlock(&sdata->local->key_mtx);
540} 442}
541 443
542static void __ieee80211_key_todo(void) 444void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata)
543{ 445{
544 struct ieee80211_key *key; 446 struct ieee80211_key *key;
545 bool work_done;
546 u32 todoflags;
547 447
548 /* 448 ASSERT_RTNL();
549 * NB: sta_info_destroy relies on this!
550 */
551 synchronize_rcu();
552
553 spin_lock_bh(&todo_lock);
554 while (!list_empty(&todo_list)) {
555 key = list_first_entry(&todo_list, struct ieee80211_key, todo);
556 list_del_init(&key->todo);
557 todoflags = key->flags & (KEY_FLAG_TODO_ADD_DEBUGFS |
558 KEY_FLAG_TODO_DEFKEY |
559 KEY_FLAG_TODO_DEFMGMTKEY |
560 KEY_FLAG_TODO_HWACCEL_ADD |
561 KEY_FLAG_TODO_HWACCEL_REMOVE |
562 KEY_FLAG_TODO_DELETE);
563 key->flags &= ~todoflags;
564 spin_unlock_bh(&todo_lock);
565
566 work_done = false;
567
568 if (todoflags & KEY_FLAG_TODO_ADD_DEBUGFS) {
569 ieee80211_debugfs_key_add(key);
570 work_done = true;
571 }
572 if (todoflags & KEY_FLAG_TODO_DEFKEY) {
573 ieee80211_debugfs_key_remove_default(key->sdata);
574 ieee80211_debugfs_key_add_default(key->sdata);
575 work_done = true;
576 }
577 if (todoflags & KEY_FLAG_TODO_DEFMGMTKEY) {
578 ieee80211_debugfs_key_remove_mgmt_default(key->sdata);
579 ieee80211_debugfs_key_add_mgmt_default(key->sdata);
580 work_done = true;
581 }
582 if (todoflags & KEY_FLAG_TODO_HWACCEL_ADD) {
583 ieee80211_key_enable_hw_accel(key);
584 work_done = true;
585 }
586 if (todoflags & KEY_FLAG_TODO_HWACCEL_REMOVE) {
587 ieee80211_key_disable_hw_accel(key);
588 work_done = true;
589 }
590 if (todoflags & KEY_FLAG_TODO_DELETE) {
591 __ieee80211_key_destroy(key);
592 work_done = true;
593 }
594 449
595 WARN_ON(!work_done); 450 mutex_lock(&sdata->local->key_mtx);
596 451
597 spin_lock_bh(&todo_lock); 452 list_for_each_entry(key, &sdata->key_list, list)
598 } 453 ieee80211_key_disable_hw_accel(key);
599 spin_unlock_bh(&todo_lock);
600}
601 454
602void ieee80211_key_todo(void) 455 mutex_unlock(&sdata->local->key_mtx);
603{
604 ieee80211_key_lock();
605 __ieee80211_key_todo();
606 ieee80211_key_unlock();
607} 456}
608 457
609void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) 458void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
610{ 459{
611 struct ieee80211_key *key, *tmp; 460 struct ieee80211_key *key, *tmp;
612 unsigned long flags;
613 461
614 ieee80211_key_lock(); 462 mutex_lock(&sdata->local->key_mtx);
615 463
616 ieee80211_debugfs_key_remove_default(sdata); 464 ieee80211_debugfs_key_remove_default(sdata);
617 ieee80211_debugfs_key_remove_mgmt_default(sdata); 465 ieee80211_debugfs_key_remove_mgmt_default(sdata);
618 466
619 spin_lock_irqsave(&sdata->local->key_lock, flags);
620 list_for_each_entry_safe(key, tmp, &sdata->key_list, list) 467 list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
621 __ieee80211_key_free(key); 468 __ieee80211_key_free(key);
622 spin_unlock_irqrestore(&sdata->local->key_lock, flags);
623
624 __ieee80211_key_todo();
625 469
626 ieee80211_key_unlock(); 470 mutex_unlock(&sdata->local->key_mtx);
627} 471}
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index bdc2968c2bbe..9996e3be6e63 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -38,25 +38,9 @@ struct sta_info;
38 * 38 *
39 * @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present 39 * @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present
40 * in the hardware for TX crypto hardware acceleration. 40 * in the hardware for TX crypto hardware acceleration.
41 * @KEY_FLAG_TODO_DELETE: Key is marked for deletion and will, after an
42 * RCU grace period, no longer be reachable other than from the
43 * todo list.
44 * @KEY_FLAG_TODO_HWACCEL_ADD: Key needs to be added to hardware acceleration.
45 * @KEY_FLAG_TODO_HWACCEL_REMOVE: Key needs to be removed from hardware
46 * acceleration.
47 * @KEY_FLAG_TODO_DEFKEY: Key is default key and debugfs needs to be updated.
48 * @KEY_FLAG_TODO_ADD_DEBUGFS: Key needs to be added to debugfs.
49 * @KEY_FLAG_TODO_DEFMGMTKEY: Key is default management key and debugfs needs
50 * to be updated.
51 */ 41 */
52enum ieee80211_internal_key_flags { 42enum ieee80211_internal_key_flags {
53 KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0), 43 KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0),
54 KEY_FLAG_TODO_DELETE = BIT(1),
55 KEY_FLAG_TODO_HWACCEL_ADD = BIT(2),
56 KEY_FLAG_TODO_HWACCEL_REMOVE = BIT(3),
57 KEY_FLAG_TODO_DEFKEY = BIT(4),
58 KEY_FLAG_TODO_ADD_DEBUGFS = BIT(5),
59 KEY_FLAG_TODO_DEFMGMTKEY = BIT(6),
60}; 44};
61 45
62enum ieee80211_internal_tkip_state { 46enum ieee80211_internal_tkip_state {
@@ -79,10 +63,8 @@ struct ieee80211_key {
79 63
80 /* for sdata list */ 64 /* for sdata list */
81 struct list_head list; 65 struct list_head list;
82 /* for todo list */
83 struct list_head todo;
84 66
85 /* protected by todo lock! */ 67 /* protected by key mutex */
86 unsigned int flags; 68 unsigned int flags;
87 69
88 union { 70 union {
@@ -155,6 +137,4 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata);
155void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); 137void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata);
156void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata); 138void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata);
157 139
158void ieee80211_key_todo(void);
159
160#endif /* IEEE80211_KEY_H */ 140#endif /* IEEE80211_KEY_H */
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 4051b232c6e6..045ead9507aa 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -448,7 +448,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
448 mutex_init(&local->iflist_mtx); 448 mutex_init(&local->iflist_mtx);
449 mutex_init(&local->scan_mtx); 449 mutex_init(&local->scan_mtx);
450 450
451 spin_lock_init(&local->key_lock); 451 mutex_init(&local->key_mtx);
452 spin_lock_init(&local->filter_lock); 452 spin_lock_init(&local->filter_lock);
453 spin_lock_init(&local->queue_stop_reason_lock); 453 spin_lock_init(&local->queue_stop_reason_lock);
454 454
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 730197591ab5..c426c572d984 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -648,14 +648,6 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
648 648
649 if (sta->key) { 649 if (sta->key) {
650 ieee80211_key_free(sta->key); 650 ieee80211_key_free(sta->key);
651 /*
652 * We have only unlinked the key, and actually destroying it
653 * may mean it is removed from hardware which requires that
654 * the key->sta pointer is still valid, so flush the key todo
655 * list here.
656 */
657 ieee80211_key_todo();
658
659 WARN_ON(sta->key); 651 WARN_ON(sta->key);
660 } 652 }
661 653