aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/key.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/key.c')
-rw-r--r--net/mac80211/key.c101
1 files changed, 62 insertions, 39 deletions
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 711e36e54ff8..150d66dbda9d 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -74,9 +74,12 @@ static void add_todo(struct ieee80211_key *key, u32 flag)
74 74
75 spin_lock(&todo_lock); 75 spin_lock(&todo_lock);
76 key->flags |= flag; 76 key->flags |= flag;
77 /* only add if not already added */ 77 /*
78 if (list_empty(&key->todo)) 78 * Remove again if already on the list so that we move it to the end.
79 list_add(&key->todo, &todo_list); 79 */
80 if (!list_empty(&key->todo))
81 list_del(&key->todo);
82 list_add_tail(&key->todo, &todo_list);
80 schedule_work(&todo_work); 83 schedule_work(&todo_work);
81 spin_unlock(&todo_lock); 84 spin_unlock(&todo_lock);
82} 85}
@@ -210,9 +213,9 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx)
210{ 213{
211 unsigned long flags; 214 unsigned long flags;
212 215
213 spin_lock_irqsave(&sdata->local->sta_lock, flags); 216 spin_lock_irqsave(&sdata->local->key_lock, flags);
214 __ieee80211_set_default_key(sdata, idx); 217 __ieee80211_set_default_key(sdata, idx);
215 spin_unlock_irqrestore(&sdata->local->sta_lock, flags); 218 spin_unlock_irqrestore(&sdata->local->key_lock, flags);
216} 219}
217 220
218 221
@@ -339,7 +342,7 @@ void ieee80211_key_link(struct ieee80211_key *key,
339 } 342 }
340 } 343 }
341 344
342 spin_lock_irqsave(&sdata->local->sta_lock, flags); 345 spin_lock_irqsave(&sdata->local->key_lock, flags);
343 346
344 if (sta) 347 if (sta)
345 old_key = sta->key; 348 old_key = sta->key;
@@ -348,68 +351,81 @@ void ieee80211_key_link(struct ieee80211_key *key,
348 351
349 __ieee80211_key_replace(sdata, sta, old_key, key); 352 __ieee80211_key_replace(sdata, sta, old_key, key);
350 353
351 spin_unlock_irqrestore(&sdata->local->sta_lock, flags); 354 spin_unlock_irqrestore(&sdata->local->key_lock, flags);
352 355
353 /* free old key later */ 356 /* free old key later */
354 add_todo(old_key, KEY_FLAG_TODO_DELETE); 357 add_todo(old_key, KEY_FLAG_TODO_DELETE);
355 358
356 add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS); 359 add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS);
357 if (netif_running(sdata->dev)) 360 if (netif_running(sdata->dev))
358 add_todo(key, KEY_FLAG_TODO_HWACCEL); 361 add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD);
359} 362}
360 363
361void ieee80211_key_free(struct ieee80211_key *key) 364static void __ieee80211_key_free(struct ieee80211_key *key)
362{ 365{
363 unsigned long flags;
364
365 if (!key)
366 return;
367
368 /* 366 /*
369 * Replace key with nothingness if it was ever used. 367 * Replace key with nothingness if it was ever used.
370 */ 368 */
371 if (key->sdata) { 369 if (key->sdata)
372 spin_lock_irqsave(&key->sdata->local->sta_lock, flags);
373 __ieee80211_key_replace(key->sdata, key->sta, 370 __ieee80211_key_replace(key->sdata, key->sta,
374 key, NULL); 371 key, NULL);
375 spin_unlock_irqrestore(&key->sdata->local->sta_lock, flags);
376 }
377 372
378 add_todo(key, KEY_FLAG_TODO_DELETE); 373 add_todo(key, KEY_FLAG_TODO_DELETE);
379} 374}
380 375
381void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) 376void ieee80211_key_free(struct ieee80211_key *key)
382{ 377{
383 struct ieee80211_key *key; 378 unsigned long flags;
384
385 might_sleep();
386 379
387 if (WARN_ON(!netif_running(sdata->dev))) 380 if (!key)
388 return; 381 return;
389 382
390 ieee80211_key_lock(); 383 spin_lock_irqsave(&key->sdata->local->key_lock, flags);
384 __ieee80211_key_free(key);
385 spin_unlock_irqrestore(&key->sdata->local->key_lock, flags);
386}
387
388/*
389 * To be safe against concurrent manipulations of the list (which shouldn't
390 * actually happen) we need to hold the spinlock. But under the spinlock we
391 * can't actually do much, so we defer processing to the todo list. Then run
392 * the todo list to be sure the operation and possibly previously pending
393 * operations are completed.
394 */
395static void ieee80211_todo_for_each_key(struct ieee80211_sub_if_data *sdata,
396 u32 todo_flags)
397{
398 struct ieee80211_key *key;
399 unsigned long flags;
391 400
401 might_sleep();
402
403 spin_lock_irqsave(&sdata->local->key_lock, flags);
392 list_for_each_entry(key, &sdata->key_list, list) 404 list_for_each_entry(key, &sdata->key_list, list)
393 ieee80211_key_enable_hw_accel(key); 405 add_todo(key, todo_flags);
406 spin_unlock_irqrestore(&sdata->local->key_lock, flags);
394 407
395 ieee80211_key_unlock(); 408 ieee80211_key_todo();
396} 409}
397 410
398void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata) 411void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
399{ 412{
400 struct ieee80211_key *key; 413 ASSERT_RTNL();
401 414
402 might_sleep(); 415 if (WARN_ON(!netif_running(sdata->dev)))
416 return;
403 417
404 ieee80211_key_lock(); 418 ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_ADD);
419}
405 420
406 list_for_each_entry(key, &sdata->key_list, list) 421void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata)
407 ieee80211_key_disable_hw_accel(key); 422{
423 ASSERT_RTNL();
408 424
409 ieee80211_key_unlock(); 425 ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_REMOVE);
410} 426}
411 427
412static void __ieee80211_key_free(struct ieee80211_key *key) 428static void __ieee80211_key_destroy(struct ieee80211_key *key)
413{ 429{
414 if (!key) 430 if (!key)
415 return; 431 return;
@@ -440,7 +456,8 @@ static void __ieee80211_key_todo(void)
440 list_del_init(&key->todo); 456 list_del_init(&key->todo);
441 todoflags = key->flags & (KEY_FLAG_TODO_ADD_DEBUGFS | 457 todoflags = key->flags & (KEY_FLAG_TODO_ADD_DEBUGFS |
442 KEY_FLAG_TODO_DEFKEY | 458 KEY_FLAG_TODO_DEFKEY |
443 KEY_FLAG_TODO_HWACCEL | 459 KEY_FLAG_TODO_HWACCEL_ADD |
460 KEY_FLAG_TODO_HWACCEL_REMOVE |
444 KEY_FLAG_TODO_DELETE); 461 KEY_FLAG_TODO_DELETE);
445 key->flags &= ~todoflags; 462 key->flags &= ~todoflags;
446 spin_unlock(&todo_lock); 463 spin_unlock(&todo_lock);
@@ -456,12 +473,16 @@ static void __ieee80211_key_todo(void)
456 ieee80211_debugfs_key_add_default(key->sdata); 473 ieee80211_debugfs_key_add_default(key->sdata);
457 work_done = true; 474 work_done = true;
458 } 475 }
459 if (todoflags & KEY_FLAG_TODO_HWACCEL) { 476 if (todoflags & KEY_FLAG_TODO_HWACCEL_ADD) {
460 ieee80211_key_enable_hw_accel(key); 477 ieee80211_key_enable_hw_accel(key);
461 work_done = true; 478 work_done = true;
462 } 479 }
480 if (todoflags & KEY_FLAG_TODO_HWACCEL_REMOVE) {
481 ieee80211_key_disable_hw_accel(key);
482 work_done = true;
483 }
463 if (todoflags & KEY_FLAG_TODO_DELETE) { 484 if (todoflags & KEY_FLAG_TODO_DELETE) {
464 __ieee80211_key_free(key); 485 __ieee80211_key_destroy(key);
465 work_done = true; 486 work_done = true;
466 } 487 }
467 488
@@ -482,14 +503,16 @@ void ieee80211_key_todo(void)
482void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) 503void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
483{ 504{
484 struct ieee80211_key *key, *tmp; 505 struct ieee80211_key *key, *tmp;
485 LIST_HEAD(tmp_list); 506 unsigned long flags;
486 507
487 ieee80211_key_lock(); 508 ieee80211_key_lock();
488 509
489 ieee80211_debugfs_key_remove_default(sdata); 510 ieee80211_debugfs_key_remove_default(sdata);
490 511
512 spin_lock_irqsave(&sdata->local->key_lock, flags);
491 list_for_each_entry_safe(key, tmp, &sdata->key_list, list) 513 list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
492 ieee80211_key_free(key); 514 __ieee80211_key_free(key);
515 spin_unlock_irqrestore(&sdata->local->key_lock, flags);
493 516
494 __ieee80211_key_todo(); 517 __ieee80211_key_todo();
495 518