Skip to content

Commit

Permalink
mac80211: free all AP/VLAN keys at once
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Johannes Berg committed Dec 16, 2013
1 parent e716251 commit 7907c7d
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 28 deletions.
5 changes: 1 addition & 4 deletions net/mac80211/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -1098,10 +1098,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
kfree_rcu(old_probe_resp, rcu_head);

__sta_info_flush(sdata, true);
synchronize_net();
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
ieee80211_free_keys(vlan);
ieee80211_free_keys(sdata);
ieee80211_free_keys(sdata, true);

sdata->vif.bss_conf.enable_beacon = false;
sdata->vif.bss_conf.ssid_len = 0;
Expand Down
19 changes: 8 additions & 11 deletions net/mac80211/iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -889,18 +889,15 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
cancel_work_sync(&sdata->work);
/*
* 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
* case it is using the interface and enqueuing frames
* at this very time on another CPU.
* Force the key freeing to always synchronize_net()
* to wait for the RX path in case it is using this
* interface enqueuing frames * at this very time on
* another CPU.
*/
synchronize_rcu();

/*
* Free all remaining keys, there shouldn't be any,
* except maybe in WDS mode?
*/
ieee80211_free_keys(sdata);
ieee80211_free_keys(sdata, true);

/* fall through */
case NL80211_IFTYPE_AP:
Expand Down Expand Up @@ -1026,7 +1023,7 @@ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
int i;

/* free extra data */
ieee80211_free_keys(sdata);
ieee80211_free_keys(sdata, false);

ieee80211_debugfs_remove_netdev(sdata);

Expand Down
44 changes: 32 additions & 12 deletions net/mac80211/key.c
Original file line number Diff line number Diff line change
Expand Up @@ -589,14 +589,10 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw,
}
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;
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_pending_dec;
Expand All @@ -608,21 +604,45 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
ieee80211_key_replace(key->sdata, key->sta,
key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
key, NULL);
list_add_tail(&key->list, &keys);
list_add_tail(&key->list, keys);
}

ieee80211_debugfs_key_update_default(sdata);
}

if (!list_empty(&keys)) {
synchronize_net();
list_for_each_entry_safe(key, tmp, &keys, list)
__ieee80211_key_destroy(key, false);
void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata,
bool force_synchronize)
{
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 ||
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,
Expand Down
3 changes: 2 additions & 1 deletion net/mac80211/key.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx,
bool uni, bool multi);
void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
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,
struct sta_info *sta);
void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata);
Expand Down

0 comments on commit 7907c7d

Please sign in to comment.