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.c84
1 files changed, 52 insertions, 32 deletions
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 711e36e54ff8..acf8d0370a37 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -355,61 +355,74 @@ void ieee80211_key_link(struct ieee80211_key *key,
355 355
356 add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS); 356 add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS);
357 if (netif_running(sdata->dev)) 357 if (netif_running(sdata->dev))
358 add_todo(key, KEY_FLAG_TODO_HWACCEL); 358 add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD);
359} 359}
360 360
361void ieee80211_key_free(struct ieee80211_key *key) 361static void __ieee80211_key_free(struct ieee80211_key *key)
362{ 362{
363 unsigned long flags;
364
365 if (!key)
366 return;
367
368 /* 363 /*
369 * Replace key with nothingness if it was ever used. 364 * Replace key with nothingness if it was ever used.
370 */ 365 */
371 if (key->sdata) { 366 if (key->sdata)
372 spin_lock_irqsave(&key->sdata->local->sta_lock, flags);
373 __ieee80211_key_replace(key->sdata, key->sta, 367 __ieee80211_key_replace(key->sdata, key->sta,
374 key, NULL); 368 key, NULL);
375 spin_unlock_irqrestore(&key->sdata->local->sta_lock, flags);
376 }
377 369
378 add_todo(key, KEY_FLAG_TODO_DELETE); 370 add_todo(key, KEY_FLAG_TODO_DELETE);
379} 371}
380 372
381void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) 373void ieee80211_key_free(struct ieee80211_key *key)
382{ 374{
383 struct ieee80211_key *key; 375 unsigned long flags;
384
385 might_sleep();
386 376
387 if (WARN_ON(!netif_running(sdata->dev))) 377 if (!key)
388 return; 378 return;
389 379
390 ieee80211_key_lock(); 380 spin_lock_irqsave(&key->sdata->local->sta_lock, flags);
381 __ieee80211_key_free(key);
382 spin_unlock_irqrestore(&key->sdata->local->sta_lock, flags);
383}
384
385/*
386 * To be safe against concurrent manipulations of the list (which shouldn't
387 * actually happen) we need to hold the spinlock. But under the spinlock we
388 * can't actually do much, so we defer processing to the todo list. Then run
389 * the todo list to be sure the operation and possibly previously pending
390 * operations are completed.
391 */
392static void ieee80211_todo_for_each_key(struct ieee80211_sub_if_data *sdata,
393 u32 todo_flags)
394{
395 struct ieee80211_key *key;
396 unsigned long flags;
391 397
398 might_sleep();
399
400 spin_lock_irqsave(&sdata->local->sta_lock, flags);
392 list_for_each_entry(key, &sdata->key_list, list) 401 list_for_each_entry(key, &sdata->key_list, list)
393 ieee80211_key_enable_hw_accel(key); 402 add_todo(key, todo_flags);
403 spin_unlock_irqrestore(&sdata->local->sta_lock, flags);
394 404
395 ieee80211_key_unlock(); 405 ieee80211_key_todo();
396} 406}
397 407
398void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata) 408void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
399{ 409{
400 struct ieee80211_key *key; 410 ASSERT_RTNL();
401 411
402 might_sleep(); 412 if (WARN_ON(!netif_running(sdata->dev)))
413 return;
403 414
404 ieee80211_key_lock(); 415 ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_ADD);
416}
405 417
406 list_for_each_entry(key, &sdata->key_list, list) 418void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata)
407 ieee80211_key_disable_hw_accel(key); 419{
420 ASSERT_RTNL();
408 421
409 ieee80211_key_unlock(); 422 ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_REMOVE);
410} 423}
411 424
412static void __ieee80211_key_free(struct ieee80211_key *key) 425static void __ieee80211_key_destroy(struct ieee80211_key *key)
413{ 426{
414 if (!key) 427 if (!key)
415 return; 428 return;
@@ -440,7 +453,8 @@ static void __ieee80211_key_todo(void)
440 list_del_init(&key->todo); 453 list_del_init(&key->todo);
441 todoflags = key->flags & (KEY_FLAG_TODO_ADD_DEBUGFS | 454 todoflags = key->flags & (KEY_FLAG_TODO_ADD_DEBUGFS |
442 KEY_FLAG_TODO_DEFKEY | 455 KEY_FLAG_TODO_DEFKEY |
443 KEY_FLAG_TODO_HWACCEL | 456 KEY_FLAG_TODO_HWACCEL_ADD |
457 KEY_FLAG_TODO_HWACCEL_REMOVE |
444 KEY_FLAG_TODO_DELETE); 458 KEY_FLAG_TODO_DELETE);
445 key->flags &= ~todoflags; 459 key->flags &= ~todoflags;
446 spin_unlock(&todo_lock); 460 spin_unlock(&todo_lock);
@@ -456,12 +470,16 @@ static void __ieee80211_key_todo(void)
456 ieee80211_debugfs_key_add_default(key->sdata); 470 ieee80211_debugfs_key_add_default(key->sdata);
457 work_done = true; 471 work_done = true;
458 } 472 }
459 if (todoflags & KEY_FLAG_TODO_HWACCEL) { 473 if (todoflags & KEY_FLAG_TODO_HWACCEL_ADD) {
460 ieee80211_key_enable_hw_accel(key); 474 ieee80211_key_enable_hw_accel(key);
461 work_done = true; 475 work_done = true;
462 } 476 }
477 if (todoflags & KEY_FLAG_TODO_HWACCEL_REMOVE) {
478 ieee80211_key_disable_hw_accel(key);
479 work_done = true;
480 }
463 if (todoflags & KEY_FLAG_TODO_DELETE) { 481 if (todoflags & KEY_FLAG_TODO_DELETE) {
464 __ieee80211_key_free(key); 482 __ieee80211_key_destroy(key);
465 work_done = true; 483 work_done = true;
466 } 484 }
467 485
@@ -482,14 +500,16 @@ void ieee80211_key_todo(void)
482void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) 500void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
483{ 501{
484 struct ieee80211_key *key, *tmp; 502 struct ieee80211_key *key, *tmp;
485 LIST_HEAD(tmp_list); 503 unsigned long flags;
486 504
487 ieee80211_key_lock(); 505 ieee80211_key_lock();
488 506
489 ieee80211_debugfs_key_remove_default(sdata); 507 ieee80211_debugfs_key_remove_default(sdata);
490 508
509 spin_lock_irqsave(&sdata->local->sta_lock, flags);
491 list_for_each_entry_safe(key, tmp, &sdata->key_list, list) 510 list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
492 ieee80211_key_free(key); 511 __ieee80211_key_free(key);
512 spin_unlock_irqrestore(&sdata->local->sta_lock, flags);
493 513
494 __ieee80211_key_todo(); 514 __ieee80211_key_todo();
495 515