diff options
Diffstat (limited to 'net/mac80211/key.c')
-rw-r--r-- | net/mac80211/key.c | 122 |
1 files changed, 76 insertions, 46 deletions
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 3e51dd7d98b3..6ff65a1ebaa9 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -260,25 +260,29 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
260 | int idx; | 260 | int idx; |
261 | bool defunikey, defmultikey, defmgmtkey; | 261 | bool defunikey, defmultikey, defmgmtkey; |
262 | 262 | ||
263 | /* caller must provide at least one old/new */ | ||
264 | if (WARN_ON(!new && !old)) | ||
265 | return; | ||
266 | |||
263 | if (new) | 267 | if (new) |
264 | list_add_tail(&new->list, &sdata->key_list); | 268 | list_add_tail(&new->list, &sdata->key_list); |
265 | 269 | ||
266 | if (sta && pairwise) { | 270 | WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); |
267 | rcu_assign_pointer(sta->ptk, new); | ||
268 | } else if (sta) { | ||
269 | if (old) | ||
270 | idx = old->conf.keyidx; | ||
271 | else | ||
272 | idx = new->conf.keyidx; | ||
273 | rcu_assign_pointer(sta->gtk[idx], new); | ||
274 | } else { | ||
275 | WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); | ||
276 | 271 | ||
277 | if (old) | 272 | if (old) |
278 | idx = old->conf.keyidx; | 273 | idx = old->conf.keyidx; |
279 | else | 274 | else |
280 | idx = new->conf.keyidx; | 275 | idx = new->conf.keyidx; |
281 | 276 | ||
277 | if (sta) { | ||
278 | if (pairwise) { | ||
279 | rcu_assign_pointer(sta->ptk[idx], new); | ||
280 | sta->ptk_idx = idx; | ||
281 | } else { | ||
282 | rcu_assign_pointer(sta->gtk[idx], new); | ||
283 | sta->gtk_idx = idx; | ||
284 | } | ||
285 | } else { | ||
282 | defunikey = old && | 286 | defunikey = old && |
283 | old == key_mtx_dereference(sdata->local, | 287 | old == key_mtx_dereference(sdata->local, |
284 | sdata->default_unicast_key); | 288 | sdata->default_unicast_key); |
@@ -312,9 +316,11 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
312 | list_del(&old->list); | 316 | list_del(&old->list); |
313 | } | 317 | } |
314 | 318 | ||
315 | struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | 319 | struct ieee80211_key * |
316 | const u8 *key_data, | 320 | ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, |
317 | size_t seq_len, const u8 *seq) | 321 | const u8 *key_data, |
322 | size_t seq_len, const u8 *seq, | ||
323 | const struct ieee80211_cipher_scheme *cs) | ||
318 | { | 324 | { |
319 | struct ieee80211_key *key; | 325 | struct ieee80211_key *key; |
320 | int i, j, err; | 326 | int i, j, err; |
@@ -393,6 +399,18 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
393 | return ERR_PTR(err); | 399 | return ERR_PTR(err); |
394 | } | 400 | } |
395 | break; | 401 | break; |
402 | default: | ||
403 | if (cs) { | ||
404 | size_t len = (seq_len > MAX_PN_LEN) ? | ||
405 | MAX_PN_LEN : seq_len; | ||
406 | |||
407 | key->conf.iv_len = cs->hdr_len; | ||
408 | key->conf.icv_len = cs->mic_len; | ||
409 | for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) | ||
410 | for (j = 0; j < len; j++) | ||
411 | key->u.gen.rx_pn[i][j] = | ||
412 | seq[len - j - 1]; | ||
413 | } | ||
396 | } | 414 | } |
397 | memcpy(key->conf.key, key_data, key_len); | 415 | memcpy(key->conf.key, key_data, key_len); |
398 | INIT_LIST_HEAD(&key->list); | 416 | INIT_LIST_HEAD(&key->list); |
@@ -475,7 +493,7 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
475 | mutex_lock(&sdata->local->key_mtx); | 493 | mutex_lock(&sdata->local->key_mtx); |
476 | 494 | ||
477 | if (sta && pairwise) | 495 | if (sta && pairwise) |
478 | old_key = key_mtx_dereference(sdata->local, sta->ptk); | 496 | old_key = key_mtx_dereference(sdata->local, sta->ptk[idx]); |
479 | else if (sta) | 497 | else if (sta) |
480 | old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]); | 498 | old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]); |
481 | else | 499 | else |
@@ -571,14 +589,10 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw, | |||
571 | } | 589 | } |
572 | EXPORT_SYMBOL(ieee80211_iter_keys); | 590 | EXPORT_SYMBOL(ieee80211_iter_keys); |
573 | 591 | ||
574 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) | 592 | static void ieee80211_free_keys_iface(struct ieee80211_sub_if_data *sdata, |
593 | struct list_head *keys) | ||
575 | { | 594 | { |
576 | struct ieee80211_key *key, *tmp; | 595 | struct ieee80211_key *key, *tmp; |
577 | LIST_HEAD(keys); | ||
578 | |||
579 | cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk); | ||
580 | |||
581 | mutex_lock(&sdata->local->key_mtx); | ||
582 | 596 | ||
583 | sdata->crypto_tx_tailroom_needed_cnt -= | 597 | sdata->crypto_tx_tailroom_needed_cnt -= |
584 | sdata->crypto_tx_tailroom_pending_dec; | 598 | sdata->crypto_tx_tailroom_pending_dec; |
@@ -590,28 +604,51 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) | |||
590 | ieee80211_key_replace(key->sdata, key->sta, | 604 | ieee80211_key_replace(key->sdata, key->sta, |
591 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, | 605 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, |
592 | key, NULL); | 606 | key, NULL); |
593 | list_add_tail(&key->list, &keys); | 607 | list_add_tail(&key->list, keys); |
594 | } | 608 | } |
595 | 609 | ||
596 | ieee80211_debugfs_key_update_default(sdata); | 610 | ieee80211_debugfs_key_update_default(sdata); |
611 | } | ||
597 | 612 | ||
598 | if (!list_empty(&keys)) { | 613 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata, |
599 | synchronize_net(); | 614 | bool force_synchronize) |
600 | list_for_each_entry_safe(key, tmp, &keys, list) | 615 | { |
601 | __ieee80211_key_destroy(key, false); | 616 | struct ieee80211_local *local = sdata->local; |
617 | struct ieee80211_sub_if_data *vlan; | ||
618 | struct ieee80211_key *key, *tmp; | ||
619 | LIST_HEAD(keys); | ||
620 | |||
621 | cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk); | ||
622 | |||
623 | mutex_lock(&local->key_mtx); | ||
624 | |||
625 | ieee80211_free_keys_iface(sdata, &keys); | ||
626 | |||
627 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | ||
628 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | ||
629 | ieee80211_free_keys_iface(vlan, &keys); | ||
602 | } | 630 | } |
603 | 631 | ||
632 | if (!list_empty(&keys) || force_synchronize) | ||
633 | synchronize_net(); | ||
634 | list_for_each_entry_safe(key, tmp, &keys, list) | ||
635 | __ieee80211_key_destroy(key, false); | ||
636 | |||
604 | WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt || | 637 | WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt || |
605 | sdata->crypto_tx_tailroom_pending_dec); | 638 | sdata->crypto_tx_tailroom_pending_dec); |
639 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | ||
640 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | ||
641 | WARN_ON_ONCE(vlan->crypto_tx_tailroom_needed_cnt || | ||
642 | vlan->crypto_tx_tailroom_pending_dec); | ||
643 | } | ||
606 | 644 | ||
607 | mutex_unlock(&sdata->local->key_mtx); | 645 | mutex_unlock(&local->key_mtx); |
608 | } | 646 | } |
609 | 647 | ||
610 | void ieee80211_free_sta_keys(struct ieee80211_local *local, | 648 | void ieee80211_free_sta_keys(struct ieee80211_local *local, |
611 | struct sta_info *sta) | 649 | struct sta_info *sta) |
612 | { | 650 | { |
613 | struct ieee80211_key *key, *tmp; | 651 | struct ieee80211_key *key; |
614 | LIST_HEAD(keys); | ||
615 | int i; | 652 | int i; |
616 | 653 | ||
617 | mutex_lock(&local->key_mtx); | 654 | mutex_lock(&local->key_mtx); |
@@ -622,25 +659,18 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local, | |||
622 | ieee80211_key_replace(key->sdata, key->sta, | 659 | ieee80211_key_replace(key->sdata, key->sta, |
623 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, | 660 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, |
624 | key, NULL); | 661 | key, NULL); |
625 | list_add(&key->list, &keys); | 662 | __ieee80211_key_destroy(key, true); |
626 | } | 663 | } |
627 | 664 | ||
628 | key = key_mtx_dereference(local, sta->ptk); | 665 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) { |
629 | if (key) { | 666 | key = key_mtx_dereference(local, sta->ptk[i]); |
667 | if (!key) | ||
668 | continue; | ||
630 | ieee80211_key_replace(key->sdata, key->sta, | 669 | ieee80211_key_replace(key->sdata, key->sta, |
631 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, | 670 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, |
632 | key, NULL); | 671 | key, NULL); |
633 | list_add(&key->list, &keys); | ||
634 | } | ||
635 | |||
636 | /* | ||
637 | * NB: the station code relies on this being | ||
638 | * done even if there aren't any keys | ||
639 | */ | ||
640 | synchronize_net(); | ||
641 | |||
642 | list_for_each_entry_safe(key, tmp, &keys, list) | ||
643 | __ieee80211_key_destroy(key, true); | 672 | __ieee80211_key_destroy(key, true); |
673 | } | ||
644 | 674 | ||
645 | mutex_unlock(&local->key_mtx); | 675 | mutex_unlock(&local->key_mtx); |
646 | } | 676 | } |
@@ -877,7 +907,7 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif, | |||
877 | 907 | ||
878 | key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx, | 908 | key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx, |
879 | keyconf->keylen, keyconf->key, | 909 | keyconf->keylen, keyconf->key, |
880 | 0, NULL); | 910 | 0, NULL, NULL); |
881 | if (IS_ERR(key)) | 911 | if (IS_ERR(key)) |
882 | return ERR_CAST(key); | 912 | return ERR_CAST(key); |
883 | 913 | ||