aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-03-06 17:09:11 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-03-11 09:16:42 -0400
commit6d10e46be5ac1d0ae787babd3dafd52b30686db5 (patch)
tree5377578eb94c2329d944ebf6ec657e8df5006e02 /net/mac80211
parent3b8d9c290364c86fc9f4baff7c82264a96f706d6 (diff)
mac80211: batch key free synchronize_net()
Instead of calling synchronize_net() for every key on an interface or when a station is removed, do it only once for all keys in both of these cases. As a side-effect, removing station keys now always calls synchronize_net() even if there are no keys, which fixes an issue with station removal happening in the driver while the station could still be used for TX. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/key.c81
-rw-r--r--net/mac80211/key.h2
-rw-r--r--net/mac80211/sta_info.c12
3 files changed, 73 insertions, 22 deletions
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 953887bdc638..67059b88fea5 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -406,18 +406,9 @@ static void ieee80211_key_free_common(struct ieee80211_key *key)
406 kfree(key); 406 kfree(key);
407} 407}
408 408
409static void ieee80211_key_destroy(struct ieee80211_key *key, 409static void __ieee80211_key_destroy(struct ieee80211_key *key,
410 bool delay_tailroom) 410 bool delay_tailroom)
411{ 411{
412 if (!key)
413 return;
414
415 /*
416 * Synchronize so the TX path can no longer be using
417 * this key before we free/remove it.
418 */
419 synchronize_net();
420
421 if (key->local) 412 if (key->local)
422 ieee80211_key_disable_hw_accel(key); 413 ieee80211_key_disable_hw_accel(key);
423 414
@@ -439,6 +430,21 @@ static void ieee80211_key_destroy(struct ieee80211_key *key,
439 ieee80211_key_free_common(key); 430 ieee80211_key_free_common(key);
440} 431}
441 432
433static void ieee80211_key_destroy(struct ieee80211_key *key,
434 bool delay_tailroom)
435{
436 if (!key)
437 return;
438
439 /*
440 * Synchronize so the TX path can no longer be using
441 * this key before we free/remove it.
442 */
443 synchronize_net();
444
445 __ieee80211_key_destroy(key, delay_tailroom);
446}
447
442void ieee80211_key_free_unused(struct ieee80211_key *key) 448void ieee80211_key_free_unused(struct ieee80211_key *key)
443{ 449{
444 WARN_ON(key->sdata || key->local); 450 WARN_ON(key->sdata || key->local);
@@ -560,6 +566,7 @@ EXPORT_SYMBOL(ieee80211_iter_keys);
560void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) 566void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
561{ 567{
562 struct ieee80211_key *key, *tmp; 568 struct ieee80211_key *key, *tmp;
569 LIST_HEAD(keys);
563 570
564 cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk); 571 cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk);
565 572
@@ -571,17 +578,65 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
571 578
572 ieee80211_debugfs_key_remove_mgmt_default(sdata); 579 ieee80211_debugfs_key_remove_mgmt_default(sdata);
573 580
574 list_for_each_entry_safe(key, tmp, &sdata->key_list, list) 581 list_for_each_entry_safe(key, tmp, &sdata->key_list, list) {
575 ieee80211_key_free(key, false); 582 ieee80211_key_replace(key->sdata, key->sta,
583 key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
584 key, NULL);
585 list_add_tail(&key->list, &keys);
586 }
576 587
577 ieee80211_debugfs_key_update_default(sdata); 588 ieee80211_debugfs_key_update_default(sdata);
578 589
590 if (!list_empty(&keys)) {
591 synchronize_net();
592 list_for_each_entry_safe(key, tmp, &keys, list)
593 __ieee80211_key_destroy(key, false);
594 }
595
579 WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt || 596 WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt ||
580 sdata->crypto_tx_tailroom_pending_dec); 597 sdata->crypto_tx_tailroom_pending_dec);
581 598
582 mutex_unlock(&sdata->local->key_mtx); 599 mutex_unlock(&sdata->local->key_mtx);
583} 600}
584 601
602void ieee80211_free_sta_keys(struct ieee80211_local *local,
603 struct sta_info *sta)
604{
605 struct ieee80211_key *key, *tmp;
606 LIST_HEAD(keys);
607 int i;
608
609 mutex_lock(&local->key_mtx);
610 for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
611 key = key_mtx_dereference(local, sta->gtk[i]);
612 if (!key)
613 continue;
614 ieee80211_key_replace(key->sdata, key->sta,
615 key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
616 key, NULL);
617 list_add(&key->list, &keys);
618 }
619
620 key = key_mtx_dereference(local, sta->ptk);
621 if (key) {
622 ieee80211_key_replace(key->sdata, key->sta,
623 key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
624 key, NULL);
625 list_add(&key->list, &keys);
626 }
627
628 /*
629 * NB: the station code relies on this being
630 * done even if there aren't any keys
631 */
632 synchronize_net();
633
634 list_for_each_entry_safe(key, tmp, &keys, list)
635 __ieee80211_key_destroy(key, true);
636
637 mutex_unlock(&local->key_mtx);
638}
639
585void ieee80211_delayed_tailroom_dec(struct work_struct *wk) 640void ieee80211_delayed_tailroom_dec(struct work_struct *wk)
586{ 641{
587 struct ieee80211_sub_if_data *sdata; 642 struct ieee80211_sub_if_data *sdata;
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index a353ddd63b5b..e8de3e6d7804 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -141,6 +141,8 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx,
141void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, 141void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
142 int idx); 142 int idx);
143void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); 143void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata);
144void ieee80211_free_sta_keys(struct ieee80211_local *local,
145 struct sta_info *sta);
144void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); 146void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata);
145 147
146#define key_mtx_dereference(local, ref) \ 148#define key_mtx_dereference(local, ref) \
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 2961f3d6b209..11216bc13b27 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -783,7 +783,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
783{ 783{
784 struct ieee80211_local *local; 784 struct ieee80211_local *local;
785 struct ieee80211_sub_if_data *sdata; 785 struct ieee80211_sub_if_data *sdata;
786 int ret, i; 786 int ret;
787 787
788 might_sleep(); 788 might_sleep();
789 789
@@ -810,14 +810,8 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
810 810
811 list_del_rcu(&sta->list); 811 list_del_rcu(&sta->list);
812 812
813 mutex_lock(&local->key_mtx); 813 /* this always calls synchronize_net() */
814 for (i = 0; i < NUM_DEFAULT_KEYS; i++) 814 ieee80211_free_sta_keys(local, sta);
815 ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i]),
816 true);
817 if (sta->ptk)
818 ieee80211_key_free(key_mtx_dereference(local, sta->ptk),
819 true);
820 mutex_unlock(&local->key_mtx);
821 815
822 sta->dead = true; 816 sta->dead = true;
823 817