diff options
-rw-r--r-- | net/mac80211/key.c | 84 | ||||
-rw-r--r-- | net/mac80211/key.h | 11 |
2 files changed, 59 insertions, 36 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 | ||
361 | void ieee80211_key_free(struct ieee80211_key *key) | 361 | static 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 | ||
381 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) | 373 | void 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 | */ | ||
392 | static 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 | ||
398 | void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata) | 408 | void 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) | 418 | void 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 | ||
412 | static void __ieee80211_key_free(struct ieee80211_key *key) | 425 | static 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) | |||
482 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) | 500 | void 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 | ||
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 5d48518985b3..f52c3df1fe9a 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -54,16 +54,19 @@ struct sta_info; | |||
54 | * @KEY_FLAG_TODO_DELETE: Key is marked for deletion and will, after an | 54 | * @KEY_FLAG_TODO_DELETE: Key is marked for deletion and will, after an |
55 | * RCU grace period, no longer be reachable other than from the | 55 | * RCU grace period, no longer be reachable other than from the |
56 | * todo list. | 56 | * todo list. |
57 | * @KEY_FLAG_TODO_HWACCEL: Key needs to be added to hardware acceleration. | 57 | * @KEY_FLAG_TODO_HWACCEL_ADD: Key needs to be added to hardware acceleration. |
58 | * @KEY_FLAG_TODO_HWACCEL_REMOVE: Key needs to be removed from hardware | ||
59 | * acceleration. | ||
58 | * @KEY_FLAG_TODO_DEFKEY: Key is default key and debugfs needs to be updated. | 60 | * @KEY_FLAG_TODO_DEFKEY: Key is default key and debugfs needs to be updated. |
59 | * @KEY_FLAG_TODO_ADD_DEBUGFS: Key needs to be added to debugfs. | 61 | * @KEY_FLAG_TODO_ADD_DEBUGFS: Key needs to be added to debugfs. |
60 | */ | 62 | */ |
61 | enum ieee80211_internal_key_flags { | 63 | enum ieee80211_internal_key_flags { |
62 | KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0), | 64 | KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0), |
63 | KEY_FLAG_TODO_DELETE = BIT(1), | 65 | KEY_FLAG_TODO_DELETE = BIT(1), |
64 | KEY_FLAG_TODO_HWACCEL = BIT(2), | 66 | KEY_FLAG_TODO_HWACCEL_ADD = BIT(2), |
65 | KEY_FLAG_TODO_DEFKEY = BIT(3), | 67 | KEY_FLAG_TODO_HWACCEL_REMOVE = BIT(3), |
66 | KEY_FLAG_TODO_ADD_DEBUGFS = BIT(4), | 68 | KEY_FLAG_TODO_DEFKEY = BIT(4), |
69 | KEY_FLAG_TODO_ADD_DEBUGFS = BIT(5), | ||
67 | }; | 70 | }; |
68 | 71 | ||
69 | struct ieee80211_key { | 72 | struct ieee80211_key { |