Commit 7907c7d3 authored by Johannes Berg's avatar Johannes Berg

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: default avatarJohannes Berg <johannes.berg@intel.com>
parent e716251d
...@@ -1098,10 +1098,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) ...@@ -1098,10 +1098,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
kfree_rcu(old_probe_resp, rcu_head); kfree_rcu(old_probe_resp, rcu_head);
__sta_info_flush(sdata, true); __sta_info_flush(sdata, true);
synchronize_net(); ieee80211_free_keys(sdata, true);
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
ieee80211_free_keys(vlan);
ieee80211_free_keys(sdata);
sdata->vif.bss_conf.enable_beacon = false; sdata->vif.bss_conf.enable_beacon = false;
sdata->vif.bss_conf.ssid_len = 0; sdata->vif.bss_conf.ssid_len = 0;
......
...@@ -889,18 +889,15 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, ...@@ -889,18 +889,15 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
cancel_work_sync(&sdata->work); cancel_work_sync(&sdata->work);
/* /*
* When we get here, the interface is marked down. * When we get here, the interface is marked down.
* Free the remaining keys, if there are any
* (shouldn't be, except maybe in WDS mode?)
* *
* We need synchronize_rcu() to wait for the RX path in * Force the key freeing to always synchronize_net()
* case it is using the interface and enqueuing frames * to wait for the RX path in case it is using this
* at this very time on another CPU. * interface enqueuing frames * at this very time on
* another CPU.
*/ */
synchronize_rcu(); ieee80211_free_keys(sdata, true);
/*
* Free all remaining keys, there shouldn't be any,
* except maybe in WDS mode?
*/
ieee80211_free_keys(sdata);
/* fall through */ /* fall through */
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
...@@ -1026,7 +1023,7 @@ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata) ...@@ -1026,7 +1023,7 @@ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
int i; int i;
/* free extra data */ /* free extra data */
ieee80211_free_keys(sdata); ieee80211_free_keys(sdata, false);
ieee80211_debugfs_remove_netdev(sdata); ieee80211_debugfs_remove_netdev(sdata);
......
...@@ -589,14 +589,10 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw, ...@@ -589,14 +589,10 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw,
} }
EXPORT_SYMBOL(ieee80211_iter_keys); EXPORT_SYMBOL(ieee80211_iter_keys);
void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) static void ieee80211_free_keys_iface(struct ieee80211_sub_if_data *sdata,
struct list_head *keys)
{ {
struct ieee80211_key *key, *tmp; struct ieee80211_key *key, *tmp;
LIST_HEAD(keys);
cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk);
mutex_lock(&sdata->local->key_mtx);
sdata->crypto_tx_tailroom_needed_cnt -= sdata->crypto_tx_tailroom_needed_cnt -=
sdata->crypto_tx_tailroom_pending_dec; sdata->crypto_tx_tailroom_pending_dec;
...@@ -608,21 +604,45 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) ...@@ -608,21 +604,45 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
ieee80211_key_replace(key->sdata, key->sta, ieee80211_key_replace(key->sdata, key->sta,
key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
key, NULL); key, NULL);
list_add_tail(&key->list, &keys); list_add_tail(&key->list, keys);
} }
ieee80211_debugfs_key_update_default(sdata); ieee80211_debugfs_key_update_default(sdata);
}
if (!list_empty(&keys)) { void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata,
synchronize_net(); bool force_synchronize)
list_for_each_entry_safe(key, tmp, &keys, list) {
__ieee80211_key_destroy(key, false); struct ieee80211_local *local = sdata->local;
struct ieee80211_sub_if_data *vlan;
struct ieee80211_key *key, *tmp;
LIST_HEAD(keys);
cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk);
mutex_lock(&local->key_mtx);
ieee80211_free_keys_iface(sdata, &keys);
if (sdata->vif.type == NL80211_IFTYPE_AP) {
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
ieee80211_free_keys_iface(vlan, &keys);
} }
if (!list_empty(&keys) || force_synchronize)
synchronize_net();
list_for_each_entry_safe(key, tmp, &keys, list)
__ieee80211_key_destroy(key, false);
WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt || WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt ||
sdata->crypto_tx_tailroom_pending_dec); sdata->crypto_tx_tailroom_pending_dec);
if (sdata->vif.type == NL80211_IFTYPE_AP) {
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
WARN_ON_ONCE(vlan->crypto_tx_tailroom_needed_cnt ||
vlan->crypto_tx_tailroom_pending_dec);
}
mutex_unlock(&sdata->local->key_mtx); mutex_unlock(&local->key_mtx);
} }
void ieee80211_free_sta_keys(struct ieee80211_local *local, void ieee80211_free_sta_keys(struct ieee80211_local *local,
......
...@@ -136,7 +136,8 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, ...@@ -136,7 +136,8 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx,
bool uni, bool multi); bool uni, bool multi);
void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
int idx); int idx);
void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata,
bool force_synchronize);
void ieee80211_free_sta_keys(struct ieee80211_local *local, void ieee80211_free_sta_keys(struct ieee80211_local *local,
struct sta_info *sta); struct sta_info *sta);
void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment