diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-12-04 17:47:09 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-12-16 05:29:48 -0500 |
commit | 7907c7d33c3733b2265dadc6385fe028af72b4c7 (patch) | |
tree | 820eefc2cecdc675d9346f46e438a19318814ea0 /net/mac80211 | |
parent | e716251d776ce92eb5169522f565ada3deed2a2a (diff) |
mac80211: free all AP/VLAN keys at once
When the AP interface is stopped, free all AP and VLAN keys at
once to only require synchronize_net() once. Since that does
synchronize_net(), also move two such calls into the function
(using the new force_synchronize parameter) to avoid doing it
twice.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/cfg.c | 5 | ||||
-rw-r--r-- | net/mac80211/iface.c | 19 | ||||
-rw-r--r-- | net/mac80211/key.c | 44 | ||||
-rw-r--r-- | net/mac80211/key.h | 3 |
4 files changed, 43 insertions, 28 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 18b56fb7911e..8718401cbd89 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1098,10 +1098,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
1098 | kfree_rcu(old_probe_resp, rcu_head); | 1098 | kfree_rcu(old_probe_resp, rcu_head); |
1099 | 1099 | ||
1100 | __sta_info_flush(sdata, true); | 1100 | __sta_info_flush(sdata, true); |
1101 | synchronize_net(); | 1101 | ieee80211_free_keys(sdata, true); |
1102 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | ||
1103 | ieee80211_free_keys(vlan); | ||
1104 | ieee80211_free_keys(sdata); | ||
1105 | 1102 | ||
1106 | sdata->vif.bss_conf.enable_beacon = false; | 1103 | sdata->vif.bss_conf.enable_beacon = false; |
1107 | sdata->vif.bss_conf.ssid_len = 0; | 1104 | sdata->vif.bss_conf.ssid_len = 0; |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 687d4eacd6ff..3d2168c3269e 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -889,18 +889,15 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
889 | cancel_work_sync(&sdata->work); | 889 | cancel_work_sync(&sdata->work); |
890 | /* | 890 | /* |
891 | * When we get here, the interface is marked down. | 891 | * When we get here, the interface is marked down. |
892 | * Free the remaining keys, if there are any | ||
893 | * (shouldn't be, except maybe in WDS mode?) | ||
892 | * | 894 | * |
893 | * We need synchronize_rcu() to wait for the RX path in | 895 | * Force the key freeing to always synchronize_net() |
894 | * case it is using the interface and enqueuing frames | 896 | * to wait for the RX path in case it is using this |
895 | * at this very time on another CPU. | 897 | * interface enqueuing frames * at this very time on |
898 | * another CPU. | ||
896 | */ | 899 | */ |
897 | synchronize_rcu(); | 900 | ieee80211_free_keys(sdata, true); |
898 | |||
899 | /* | ||
900 | * Free all remaining keys, there shouldn't be any, | ||
901 | * except maybe in WDS mode? | ||
902 | */ | ||
903 | ieee80211_free_keys(sdata); | ||
904 | 901 | ||
905 | /* fall through */ | 902 | /* fall through */ |
906 | case NL80211_IFTYPE_AP: | 903 | case NL80211_IFTYPE_AP: |
@@ -1026,7 +1023,7 @@ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata) | |||
1026 | int i; | 1023 | int i; |
1027 | 1024 | ||
1028 | /* free extra data */ | 1025 | /* free extra data */ |
1029 | ieee80211_free_keys(sdata); | 1026 | ieee80211_free_keys(sdata, false); |
1030 | 1027 | ||
1031 | ieee80211_debugfs_remove_netdev(sdata); | 1028 | ieee80211_debugfs_remove_netdev(sdata); |
1032 | 1029 | ||
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 12e61543a37c..6ff65a1ebaa9 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -589,14 +589,10 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw, | |||
589 | } | 589 | } |
590 | EXPORT_SYMBOL(ieee80211_iter_keys); | 590 | EXPORT_SYMBOL(ieee80211_iter_keys); |
591 | 591 | ||
592 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) | 592 | static void ieee80211_free_keys_iface(struct ieee80211_sub_if_data *sdata, |
593 | struct list_head *keys) | ||
593 | { | 594 | { |
594 | struct ieee80211_key *key, *tmp; | 595 | struct ieee80211_key *key, *tmp; |
595 | LIST_HEAD(keys); | ||
596 | |||
597 | cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk); | ||
598 | |||
599 | mutex_lock(&sdata->local->key_mtx); | ||
600 | 596 | ||
601 | sdata->crypto_tx_tailroom_needed_cnt -= | 597 | sdata->crypto_tx_tailroom_needed_cnt -= |
602 | sdata->crypto_tx_tailroom_pending_dec; | 598 | sdata->crypto_tx_tailroom_pending_dec; |
@@ -608,21 +604,45 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) | |||
608 | ieee80211_key_replace(key->sdata, key->sta, | 604 | ieee80211_key_replace(key->sdata, key->sta, |
609 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, | 605 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, |
610 | key, NULL); | 606 | key, NULL); |
611 | list_add_tail(&key->list, &keys); | 607 | list_add_tail(&key->list, keys); |
612 | } | 608 | } |
613 | 609 | ||
614 | ieee80211_debugfs_key_update_default(sdata); | 610 | ieee80211_debugfs_key_update_default(sdata); |
611 | } | ||
615 | 612 | ||
616 | if (!list_empty(&keys)) { | 613 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata, |
617 | synchronize_net(); | 614 | bool force_synchronize) |
618 | list_for_each_entry_safe(key, tmp, &keys, list) | 615 | { |
619 | __ieee80211_key_destroy(key, false); | 616 | struct ieee80211_local *local = sdata->local; |
617 | struct ieee80211_sub_if_data *vlan; | ||
618 | struct ieee80211_key *key, *tmp; | ||
619 | LIST_HEAD(keys); | ||
620 | |||
621 | cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk); | ||
622 | |||
623 | mutex_lock(&local->key_mtx); | ||
624 | |||
625 | ieee80211_free_keys_iface(sdata, &keys); | ||
626 | |||
627 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | ||
628 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | ||
629 | ieee80211_free_keys_iface(vlan, &keys); | ||
620 | } | 630 | } |
621 | 631 | ||
632 | if (!list_empty(&keys) || force_synchronize) | ||
633 | synchronize_net(); | ||
634 | list_for_each_entry_safe(key, tmp, &keys, list) | ||
635 | __ieee80211_key_destroy(key, false); | ||
636 | |||
622 | WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt || | 637 | WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt || |
623 | sdata->crypto_tx_tailroom_pending_dec); | 638 | sdata->crypto_tx_tailroom_pending_dec); |
639 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | ||
640 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | ||
641 | WARN_ON_ONCE(vlan->crypto_tx_tailroom_needed_cnt || | ||
642 | vlan->crypto_tx_tailroom_pending_dec); | ||
643 | } | ||
624 | 644 | ||
625 | mutex_unlock(&sdata->local->key_mtx); | 645 | mutex_unlock(&local->key_mtx); |
626 | } | 646 | } |
627 | 647 | ||
628 | void ieee80211_free_sta_keys(struct ieee80211_local *local, | 648 | void ieee80211_free_sta_keys(struct ieee80211_local *local, |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 0aebb889caba..19db68663d75 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -136,7 +136,8 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, | |||
136 | bool uni, bool multi); | 136 | bool uni, bool multi); |
137 | void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, | 137 | void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, |
138 | int idx); | 138 | int idx); |
139 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); | 139 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata, |
140 | bool force_synchronize); | ||
140 | void ieee80211_free_sta_keys(struct ieee80211_local *local, | 141 | void ieee80211_free_sta_keys(struct ieee80211_local *local, |
141 | struct sta_info *sta); | 142 | struct sta_info *sta); |
142 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); | 143 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); |