diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/cfg.c | 2 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 2 | ||||
-rw-r--r-- | net/mac80211/iface.c | 2 | ||||
-rw-r--r-- | net/mac80211/key.c | 63 | ||||
-rw-r--r-- | net/mac80211/key.h | 4 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 6 |
6 files changed, 68 insertions, 11 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index f9cbdc29946d..8baa561c8f5b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -254,7 +254,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
254 | goto out_unlock; | 254 | goto out_unlock; |
255 | } | 255 | } |
256 | 256 | ||
257 | __ieee80211_key_free(key); | 257 | __ieee80211_key_free(key, true); |
258 | 258 | ||
259 | ret = 0; | 259 | ret = 0; |
260 | out_unlock: | 260 | out_unlock: |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 0acc07b852a9..54d09ec3fe68 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -680,6 +680,8 @@ struct ieee80211_sub_if_data { | |||
680 | 680 | ||
681 | /* count for keys needing tailroom space allocation */ | 681 | /* count for keys needing tailroom space allocation */ |
682 | int crypto_tx_tailroom_needed_cnt; | 682 | int crypto_tx_tailroom_needed_cnt; |
683 | int crypto_tx_tailroom_pending_dec; | ||
684 | struct delayed_work dec_tailroom_needed_wk; | ||
683 | 685 | ||
684 | struct net_device *dev; | 686 | struct net_device *dev; |
685 | struct ieee80211_local *local; | 687 | struct ieee80211_local *local; |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 1ee10cd1d5b6..8e0bf34f3f68 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -1543,6 +1543,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1543 | INIT_WORK(&sdata->cleanup_stations_wk, ieee80211_cleanup_sdata_stas_wk); | 1543 | INIT_WORK(&sdata->cleanup_stations_wk, ieee80211_cleanup_sdata_stas_wk); |
1544 | INIT_DELAYED_WORK(&sdata->dfs_cac_timer_work, | 1544 | INIT_DELAYED_WORK(&sdata->dfs_cac_timer_work, |
1545 | ieee80211_dfs_cac_timer_work); | 1545 | ieee80211_dfs_cac_timer_work); |
1546 | INIT_DELAYED_WORK(&sdata->dec_tailroom_needed_wk, | ||
1547 | ieee80211_delayed_tailroom_dec); | ||
1546 | 1548 | ||
1547 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | 1549 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { |
1548 | struct ieee80211_supported_band *sband; | 1550 | struct ieee80211_supported_band *sband; |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 6eb4888a70ed..99e9f6ae6a54 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -397,7 +397,8 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
397 | return key; | 397 | return key; |
398 | } | 398 | } |
399 | 399 | ||
400 | static void __ieee80211_key_destroy(struct ieee80211_key *key) | 400 | static void __ieee80211_key_destroy(struct ieee80211_key *key, |
401 | bool delay_tailroom) | ||
401 | { | 402 | { |
402 | if (!key) | 403 | if (!key) |
403 | return; | 404 | return; |
@@ -416,8 +417,18 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key) | |||
416 | if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC) | 417 | if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC) |
417 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); | 418 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); |
418 | if (key->local) { | 419 | if (key->local) { |
420 | struct ieee80211_sub_if_data *sdata = key->sdata; | ||
421 | |||
419 | ieee80211_debugfs_key_remove(key); | 422 | ieee80211_debugfs_key_remove(key); |
420 | key->sdata->crypto_tx_tailroom_needed_cnt--; | 423 | |
424 | if (delay_tailroom) { | ||
425 | /* see ieee80211_delayed_tailroom_dec */ | ||
426 | sdata->crypto_tx_tailroom_pending_dec++; | ||
427 | schedule_delayed_work(&sdata->dec_tailroom_needed_wk, | ||
428 | HZ/2); | ||
429 | } else { | ||
430 | sdata->crypto_tx_tailroom_needed_cnt--; | ||
431 | } | ||
421 | } | 432 | } |
422 | 433 | ||
423 | kfree(key); | 434 | kfree(key); |
@@ -452,7 +463,7 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
452 | increment_tailroom_need_count(sdata); | 463 | increment_tailroom_need_count(sdata); |
453 | 464 | ||
454 | __ieee80211_key_replace(sdata, sta, pairwise, old_key, key); | 465 | __ieee80211_key_replace(sdata, sta, pairwise, old_key, key); |
455 | __ieee80211_key_destroy(old_key); | 466 | __ieee80211_key_destroy(old_key, true); |
456 | 467 | ||
457 | ieee80211_debugfs_key_add(key); | 468 | ieee80211_debugfs_key_add(key); |
458 | 469 | ||
@@ -463,7 +474,7 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
463 | return ret; | 474 | return ret; |
464 | } | 475 | } |
465 | 476 | ||
466 | void __ieee80211_key_free(struct ieee80211_key *key) | 477 | void __ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom) |
467 | { | 478 | { |
468 | if (!key) | 479 | if (!key) |
469 | return; | 480 | return; |
@@ -475,14 +486,14 @@ void __ieee80211_key_free(struct ieee80211_key *key) | |||
475 | __ieee80211_key_replace(key->sdata, key->sta, | 486 | __ieee80211_key_replace(key->sdata, key->sta, |
476 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, | 487 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, |
477 | key, NULL); | 488 | key, NULL); |
478 | __ieee80211_key_destroy(key); | 489 | __ieee80211_key_destroy(key, delay_tailroom); |
479 | } | 490 | } |
480 | 491 | ||
481 | void ieee80211_key_free(struct ieee80211_local *local, | 492 | void ieee80211_key_free(struct ieee80211_local *local, |
482 | struct ieee80211_key *key) | 493 | struct ieee80211_key *key) |
483 | { | 494 | { |
484 | mutex_lock(&local->key_mtx); | 495 | mutex_lock(&local->key_mtx); |
485 | __ieee80211_key_free(key); | 496 | __ieee80211_key_free(key, true); |
486 | mutex_unlock(&local->key_mtx); | 497 | mutex_unlock(&local->key_mtx); |
487 | } | 498 | } |
488 | 499 | ||
@@ -544,18 +555,56 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) | |||
544 | { | 555 | { |
545 | struct ieee80211_key *key, *tmp; | 556 | struct ieee80211_key *key, *tmp; |
546 | 557 | ||
558 | cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk); | ||
559 | |||
547 | mutex_lock(&sdata->local->key_mtx); | 560 | mutex_lock(&sdata->local->key_mtx); |
548 | 561 | ||
562 | sdata->crypto_tx_tailroom_needed_cnt -= | ||
563 | sdata->crypto_tx_tailroom_pending_dec; | ||
564 | sdata->crypto_tx_tailroom_pending_dec = 0; | ||
565 | |||
549 | ieee80211_debugfs_key_remove_mgmt_default(sdata); | 566 | ieee80211_debugfs_key_remove_mgmt_default(sdata); |
550 | 567 | ||
551 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) | 568 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) |
552 | __ieee80211_key_free(key); | 569 | __ieee80211_key_free(key, false); |
553 | 570 | ||
554 | ieee80211_debugfs_key_update_default(sdata); | 571 | ieee80211_debugfs_key_update_default(sdata); |
555 | 572 | ||
573 | WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt || | ||
574 | sdata->crypto_tx_tailroom_pending_dec); | ||
575 | |||
556 | mutex_unlock(&sdata->local->key_mtx); | 576 | mutex_unlock(&sdata->local->key_mtx); |
557 | } | 577 | } |
558 | 578 | ||
579 | void ieee80211_delayed_tailroom_dec(struct work_struct *wk) | ||
580 | { | ||
581 | struct ieee80211_sub_if_data *sdata; | ||
582 | |||
583 | sdata = container_of(wk, struct ieee80211_sub_if_data, | ||
584 | dec_tailroom_needed_wk.work); | ||
585 | |||
586 | /* | ||
587 | * The reason for the delayed tailroom needed decrementing is to | ||
588 | * make roaming faster: during roaming, all keys are first deleted | ||
589 | * and then new keys are installed. The first new key causes the | ||
590 | * crypto_tx_tailroom_needed_cnt to go from 0 to 1, which invokes | ||
591 | * the cost of synchronize_net() (which can be slow). Avoid this | ||
592 | * by deferring the crypto_tx_tailroom_needed_cnt decrementing on | ||
593 | * key removal for a while, so if we roam the value is larger than | ||
594 | * zero and no 0->1 transition happens. | ||
595 | * | ||
596 | * The cost is that if the AP switching was from an AP with keys | ||
597 | * to one without, we still allocate tailroom while it would no | ||
598 | * longer be needed. However, in the typical (fast) roaming case | ||
599 | * within an ESS this usually won't happen. | ||
600 | */ | ||
601 | |||
602 | mutex_lock(&sdata->local->key_mtx); | ||
603 | sdata->crypto_tx_tailroom_needed_cnt -= | ||
604 | sdata->crypto_tx_tailroom_pending_dec; | ||
605 | sdata->crypto_tx_tailroom_pending_dec = 0; | ||
606 | mutex_unlock(&sdata->local->key_mtx); | ||
607 | } | ||
559 | 608 | ||
560 | void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid, | 609 | void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid, |
561 | const u8 *replay_ctr, gfp_t gfp) | 610 | const u8 *replay_ctr, gfp_t gfp) |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 8b037307a586..2a682d81cee9 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -134,7 +134,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
134 | int __must_check ieee80211_key_link(struct ieee80211_key *key, | 134 | int __must_check ieee80211_key_link(struct ieee80211_key *key, |
135 | struct ieee80211_sub_if_data *sdata, | 135 | struct ieee80211_sub_if_data *sdata, |
136 | struct sta_info *sta); | 136 | struct sta_info *sta); |
137 | void __ieee80211_key_free(struct ieee80211_key *key); | 137 | void __ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom); |
138 | void ieee80211_key_free(struct ieee80211_local *local, | 138 | void ieee80211_key_free(struct ieee80211_local *local, |
139 | struct ieee80211_key *key); | 139 | struct ieee80211_key *key); |
140 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, | 140 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, |
@@ -147,4 +147,6 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); | |||
147 | #define key_mtx_dereference(local, ref) \ | 147 | #define key_mtx_dereference(local, ref) \ |
148 | rcu_dereference_protected(ref, lockdep_is_held(&((local)->key_mtx))) | 148 | rcu_dereference_protected(ref, lockdep_is_held(&((local)->key_mtx))) |
149 | 149 | ||
150 | void ieee80211_delayed_tailroom_dec(struct work_struct *wk); | ||
151 | |||
150 | #endif /* IEEE80211_KEY_H */ | 152 | #endif /* IEEE80211_KEY_H */ |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a79ce820cb50..0141e4951adf 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -794,9 +794,11 @@ int __must_check __sta_info_destroy(struct sta_info *sta) | |||
794 | 794 | ||
795 | mutex_lock(&local->key_mtx); | 795 | mutex_lock(&local->key_mtx); |
796 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) | 796 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) |
797 | __ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i])); | 797 | __ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i]), |
798 | true); | ||
798 | if (sta->ptk) | 799 | if (sta->ptk) |
799 | __ieee80211_key_free(key_mtx_dereference(local, sta->ptk)); | 800 | __ieee80211_key_free(key_mtx_dereference(local, sta->ptk), |
801 | true); | ||
800 | mutex_unlock(&local->key_mtx); | 802 | mutex_unlock(&local->key_mtx); |
801 | 803 | ||
802 | sta->dead = true; | 804 | sta->dead = true; |