diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-03-06 17:09:11 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-03-11 09:16:42 -0400 |
commit | 6d10e46be5ac1d0ae787babd3dafd52b30686db5 (patch) | |
tree | 5377578eb94c2329d944ebf6ec657e8df5006e02 /net/mac80211 | |
parent | 3b8d9c290364c86fc9f4baff7c82264a96f706d6 (diff) |
mac80211: batch key free synchronize_net()
Instead of calling synchronize_net() for every key
on an interface or when a station is removed, do it
only once for all keys in both of these cases.
As a side-effect, removing station keys now always
calls synchronize_net() even if there are no keys,
which fixes an issue with station removal happening
in the driver while the station could still be used
for TX.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/key.c | 81 | ||||
-rw-r--r-- | net/mac80211/key.h | 2 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 12 |
3 files changed, 73 insertions, 22 deletions
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 953887bdc638..67059b88fea5 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -406,18 +406,9 @@ static void ieee80211_key_free_common(struct ieee80211_key *key) | |||
406 | kfree(key); | 406 | kfree(key); |
407 | } | 407 | } |
408 | 408 | ||
409 | static void ieee80211_key_destroy(struct ieee80211_key *key, | 409 | static void __ieee80211_key_destroy(struct ieee80211_key *key, |
410 | bool delay_tailroom) | 410 | bool delay_tailroom) |
411 | { | 411 | { |
412 | if (!key) | ||
413 | return; | ||
414 | |||
415 | /* | ||
416 | * Synchronize so the TX path can no longer be using | ||
417 | * this key before we free/remove it. | ||
418 | */ | ||
419 | synchronize_net(); | ||
420 | |||
421 | if (key->local) | 412 | if (key->local) |
422 | ieee80211_key_disable_hw_accel(key); | 413 | ieee80211_key_disable_hw_accel(key); |
423 | 414 | ||
@@ -439,6 +430,21 @@ static void ieee80211_key_destroy(struct ieee80211_key *key, | |||
439 | ieee80211_key_free_common(key); | 430 | ieee80211_key_free_common(key); |
440 | } | 431 | } |
441 | 432 | ||
433 | static void ieee80211_key_destroy(struct ieee80211_key *key, | ||
434 | bool delay_tailroom) | ||
435 | { | ||
436 | if (!key) | ||
437 | return; | ||
438 | |||
439 | /* | ||
440 | * Synchronize so the TX path can no longer be using | ||
441 | * this key before we free/remove it. | ||
442 | */ | ||
443 | synchronize_net(); | ||
444 | |||
445 | __ieee80211_key_destroy(key, delay_tailroom); | ||
446 | } | ||
447 | |||
442 | void ieee80211_key_free_unused(struct ieee80211_key *key) | 448 | void ieee80211_key_free_unused(struct ieee80211_key *key) |
443 | { | 449 | { |
444 | WARN_ON(key->sdata || key->local); | 450 | WARN_ON(key->sdata || key->local); |
@@ -560,6 +566,7 @@ EXPORT_SYMBOL(ieee80211_iter_keys); | |||
560 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) | 566 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) |
561 | { | 567 | { |
562 | struct ieee80211_key *key, *tmp; | 568 | struct ieee80211_key *key, *tmp; |
569 | LIST_HEAD(keys); | ||
563 | 570 | ||
564 | cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk); | 571 | cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk); |
565 | 572 | ||
@@ -571,17 +578,65 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) | |||
571 | 578 | ||
572 | ieee80211_debugfs_key_remove_mgmt_default(sdata); | 579 | ieee80211_debugfs_key_remove_mgmt_default(sdata); |
573 | 580 | ||
574 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) | 581 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) { |
575 | ieee80211_key_free(key, false); | 582 | ieee80211_key_replace(key->sdata, key->sta, |
583 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, | ||
584 | key, NULL); | ||
585 | list_add_tail(&key->list, &keys); | ||
586 | } | ||
576 | 587 | ||
577 | ieee80211_debugfs_key_update_default(sdata); | 588 | ieee80211_debugfs_key_update_default(sdata); |
578 | 589 | ||
590 | if (!list_empty(&keys)) { | ||
591 | synchronize_net(); | ||
592 | list_for_each_entry_safe(key, tmp, &keys, list) | ||
593 | __ieee80211_key_destroy(key, false); | ||
594 | } | ||
595 | |||
579 | WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt || | 596 | WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt || |
580 | sdata->crypto_tx_tailroom_pending_dec); | 597 | sdata->crypto_tx_tailroom_pending_dec); |
581 | 598 | ||
582 | mutex_unlock(&sdata->local->key_mtx); | 599 | mutex_unlock(&sdata->local->key_mtx); |
583 | } | 600 | } |
584 | 601 | ||
602 | void ieee80211_free_sta_keys(struct ieee80211_local *local, | ||
603 | struct sta_info *sta) | ||
604 | { | ||
605 | struct ieee80211_key *key, *tmp; | ||
606 | LIST_HEAD(keys); | ||
607 | int i; | ||
608 | |||
609 | mutex_lock(&local->key_mtx); | ||
610 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) { | ||
611 | key = key_mtx_dereference(local, sta->gtk[i]); | ||
612 | if (!key) | ||
613 | continue; | ||
614 | ieee80211_key_replace(key->sdata, key->sta, | ||
615 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, | ||
616 | key, NULL); | ||
617 | list_add(&key->list, &keys); | ||
618 | } | ||
619 | |||
620 | key = key_mtx_dereference(local, sta->ptk); | ||
621 | if (key) { | ||
622 | ieee80211_key_replace(key->sdata, key->sta, | ||
623 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, | ||
624 | key, NULL); | ||
625 | list_add(&key->list, &keys); | ||
626 | } | ||
627 | |||
628 | /* | ||
629 | * NB: the station code relies on this being | ||
630 | * done even if there aren't any keys | ||
631 | */ | ||
632 | synchronize_net(); | ||
633 | |||
634 | list_for_each_entry_safe(key, tmp, &keys, list) | ||
635 | __ieee80211_key_destroy(key, true); | ||
636 | |||
637 | mutex_unlock(&local->key_mtx); | ||
638 | } | ||
639 | |||
585 | void ieee80211_delayed_tailroom_dec(struct work_struct *wk) | 640 | void ieee80211_delayed_tailroom_dec(struct work_struct *wk) |
586 | { | 641 | { |
587 | struct ieee80211_sub_if_data *sdata; | 642 | struct ieee80211_sub_if_data *sdata; |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index a353ddd63b5b..e8de3e6d7804 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -141,6 +141,8 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, | |||
141 | void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, | 141 | void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, |
142 | int idx); | 142 | int idx); |
143 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); | 143 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); |
144 | void ieee80211_free_sta_keys(struct ieee80211_local *local, | ||
145 | struct sta_info *sta); | ||
144 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); | 146 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); |
145 | 147 | ||
146 | #define key_mtx_dereference(local, ref) \ | 148 | #define key_mtx_dereference(local, ref) \ |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 2961f3d6b209..11216bc13b27 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -783,7 +783,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta) | |||
783 | { | 783 | { |
784 | struct ieee80211_local *local; | 784 | struct ieee80211_local *local; |
785 | struct ieee80211_sub_if_data *sdata; | 785 | struct ieee80211_sub_if_data *sdata; |
786 | int ret, i; | 786 | int ret; |
787 | 787 | ||
788 | might_sleep(); | 788 | might_sleep(); |
789 | 789 | ||
@@ -810,14 +810,8 @@ int __must_check __sta_info_destroy(struct sta_info *sta) | |||
810 | 810 | ||
811 | list_del_rcu(&sta->list); | 811 | list_del_rcu(&sta->list); |
812 | 812 | ||
813 | mutex_lock(&local->key_mtx); | 813 | /* this always calls synchronize_net() */ |
814 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) | 814 | ieee80211_free_sta_keys(local, sta); |
815 | ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i]), | ||
816 | true); | ||
817 | if (sta->ptk) | ||
818 | ieee80211_key_free(key_mtx_dereference(local, sta->ptk), | ||
819 | true); | ||
820 | mutex_unlock(&local->key_mtx); | ||
821 | 815 | ||
822 | sta->dead = true; | 816 | sta->dead = true; |
823 | 817 | ||