|
@@ -397,7 +397,8 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
|
|
|
return key;
|
|
|
}
|
|
|
|
|
|
-static void __ieee80211_key_destroy(struct ieee80211_key *key)
|
|
|
+static void __ieee80211_key_destroy(struct ieee80211_key *key,
|
|
|
+ bool delay_tailroom)
|
|
|
{
|
|
|
if (!key)
|
|
|
return;
|
|
@@ -416,8 +417,18 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key)
|
|
|
if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC)
|
|
|
ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
|
|
|
if (key->local) {
|
|
|
+ struct ieee80211_sub_if_data *sdata = key->sdata;
|
|
|
+
|
|
|
ieee80211_debugfs_key_remove(key);
|
|
|
- key->sdata->crypto_tx_tailroom_needed_cnt--;
|
|
|
+
|
|
|
+ if (delay_tailroom) {
|
|
|
+ /* see ieee80211_delayed_tailroom_dec */
|
|
|
+ sdata->crypto_tx_tailroom_pending_dec++;
|
|
|
+ schedule_delayed_work(&sdata->dec_tailroom_needed_wk,
|
|
|
+ HZ/2);
|
|
|
+ } else {
|
|
|
+ sdata->crypto_tx_tailroom_needed_cnt--;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
kfree(key);
|
|
@@ -452,7 +463,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
|
|
|
increment_tailroom_need_count(sdata);
|
|
|
|
|
|
__ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
|
|
|
- __ieee80211_key_destroy(old_key);
|
|
|
+ __ieee80211_key_destroy(old_key, true);
|
|
|
|
|
|
ieee80211_debugfs_key_add(key);
|
|
|
|
|
@@ -463,7 +474,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-void __ieee80211_key_free(struct ieee80211_key *key)
|
|
|
+void __ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom)
|
|
|
{
|
|
|
if (!key)
|
|
|
return;
|
|
@@ -475,14 +486,14 @@ void __ieee80211_key_free(struct ieee80211_key *key)
|
|
|
__ieee80211_key_replace(key->sdata, key->sta,
|
|
|
key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
|
|
|
key, NULL);
|
|
|
- __ieee80211_key_destroy(key);
|
|
|
+ __ieee80211_key_destroy(key, delay_tailroom);
|
|
|
}
|
|
|
|
|
|
void ieee80211_key_free(struct ieee80211_local *local,
|
|
|
struct ieee80211_key *key)
|
|
|
{
|
|
|
mutex_lock(&local->key_mtx);
|
|
|
- __ieee80211_key_free(key);
|
|
|
+ __ieee80211_key_free(key, true);
|
|
|
mutex_unlock(&local->key_mtx);
|
|
|
}
|
|
|
|
|
@@ -544,18 +555,56 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
|
|
|
{
|
|
|
struct ieee80211_key *key, *tmp;
|
|
|
|
|
|
+ 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;
|
|
|
+ sdata->crypto_tx_tailroom_pending_dec = 0;
|
|
|
+
|
|
|
ieee80211_debugfs_key_remove_mgmt_default(sdata);
|
|
|
|
|
|
list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
|
|
|
- __ieee80211_key_free(key);
|
|
|
+ __ieee80211_key_free(key, false);
|
|
|
|
|
|
ieee80211_debugfs_key_update_default(sdata);
|
|
|
|
|
|
+ WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt ||
|
|
|
+ sdata->crypto_tx_tailroom_pending_dec);
|
|
|
+
|
|
|
mutex_unlock(&sdata->local->key_mtx);
|
|
|
}
|
|
|
|
|
|
+void ieee80211_delayed_tailroom_dec(struct work_struct *wk)
|
|
|
+{
|
|
|
+ struct ieee80211_sub_if_data *sdata;
|
|
|
+
|
|
|
+ sdata = container_of(wk, struct ieee80211_sub_if_data,
|
|
|
+ dec_tailroom_needed_wk.work);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * The reason for the delayed tailroom needed decrementing is to
|
|
|
+ * make roaming faster: during roaming, all keys are first deleted
|
|
|
+ * and then new keys are installed. The first new key causes the
|
|
|
+ * crypto_tx_tailroom_needed_cnt to go from 0 to 1, which invokes
|
|
|
+ * the cost of synchronize_net() (which can be slow). Avoid this
|
|
|
+ * by deferring the crypto_tx_tailroom_needed_cnt decrementing on
|
|
|
+ * key removal for a while, so if we roam the value is larger than
|
|
|
+ * zero and no 0->1 transition happens.
|
|
|
+ *
|
|
|
+ * The cost is that if the AP switching was from an AP with keys
|
|
|
+ * to one without, we still allocate tailroom while it would no
|
|
|
+ * longer be needed. However, in the typical (fast) roaming case
|
|
|
+ * within an ESS this usually won't happen.
|
|
|
+ */
|
|
|
+
|
|
|
+ mutex_lock(&sdata->local->key_mtx);
|
|
|
+ sdata->crypto_tx_tailroom_needed_cnt -=
|
|
|
+ sdata->crypto_tx_tailroom_pending_dec;
|
|
|
+ sdata->crypto_tx_tailroom_pending_dec = 0;
|
|
|
+ mutex_unlock(&sdata->local->key_mtx);
|
|
|
+}
|
|
|
|
|
|
void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid,
|
|
|
const u8 *replay_ctr, gfp_t gfp)
|