diff options
-rw-r--r-- | include/net/mac80211.h | 83 | ||||
-rw-r--r-- | net/mac80211/key.c | 154 | ||||
-rw-r--r-- | net/mac80211/util.c | 2 |
3 files changed, 231 insertions, 8 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index df93c77c97ab..e3e303778936 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -3688,6 +3688,89 @@ void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf, | |||
3688 | int tid, struct ieee80211_key_seq *seq); | 3688 | int tid, struct ieee80211_key_seq *seq); |
3689 | 3689 | ||
3690 | /** | 3690 | /** |
3691 | * ieee80211_set_key_tx_seq - set key TX sequence counter | ||
3692 | * | ||
3693 | * @keyconf: the parameter passed with the set key | ||
3694 | * @seq: new sequence data | ||
3695 | * | ||
3696 | * This function allows a driver to set the current TX IV/PNs for the | ||
3697 | * given key. This is useful when resuming from WoWLAN sleep and the | ||
3698 | * device may have transmitted frames using the PTK, e.g. replies to | ||
3699 | * ARP requests. | ||
3700 | * | ||
3701 | * Note that this function may only be called when no TX processing | ||
3702 | * can be done concurrently. | ||
3703 | */ | ||
3704 | void ieee80211_set_key_tx_seq(struct ieee80211_key_conf *keyconf, | ||
3705 | struct ieee80211_key_seq *seq); | ||
3706 | |||
3707 | /** | ||
3708 | * ieee80211_set_key_rx_seq - set key RX sequence counter | ||
3709 | * | ||
3710 | * @keyconf: the parameter passed with the set key | ||
3711 | * @tid: The TID, or -1 for the management frame value (CCMP only); | ||
3712 | * the value on TID 0 is also used for non-QoS frames. For | ||
3713 | * CMAC, only TID 0 is valid. | ||
3714 | * @seq: new sequence data | ||
3715 | * | ||
3716 | * This function allows a driver to set the current RX IV/PNs for the | ||
3717 | * given key. This is useful when resuming from WoWLAN sleep and GTK | ||
3718 | * rekey may have been done while suspended. It should not be called | ||
3719 | * if IV checking is done by the device and not by mac80211. | ||
3720 | * | ||
3721 | * Note that this function may only be called when no RX processing | ||
3722 | * can be done concurrently. | ||
3723 | */ | ||
3724 | void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf, | ||
3725 | int tid, struct ieee80211_key_seq *seq); | ||
3726 | |||
3727 | /** | ||
3728 | * ieee80211_remove_key - remove the given key | ||
3729 | * @keyconf: the parameter passed with the set key | ||
3730 | * | ||
3731 | * Remove the given key. If the key was uploaded to the hardware at the | ||
3732 | * time this function is called, it is not deleted in the hardware but | ||
3733 | * instead assumed to have been removed already. | ||
3734 | * | ||
3735 | * Note that due to locking considerations this function can (currently) | ||
3736 | * only be called during key iteration (ieee80211_iter_keys().) | ||
3737 | */ | ||
3738 | void ieee80211_remove_key(struct ieee80211_key_conf *keyconf); | ||
3739 | |||
3740 | /** | ||
3741 | * ieee80211_gtk_rekey_add - add a GTK key from rekeying during WoWLAN | ||
3742 | * @vif: the virtual interface to add the key on | ||
3743 | * @keyconf: new key data | ||
3744 | * | ||
3745 | * When GTK rekeying was done while the system was suspended, (a) new | ||
3746 | * key(s) will be available. These will be needed by mac80211 for proper | ||
3747 | * RX processing, so this function allows setting them. | ||
3748 | * | ||
3749 | * The function returns the newly allocated key structure, which will | ||
3750 | * have similar contents to the passed key configuration but point to | ||
3751 | * mac80211-owned memory. In case of errors, the function returns an | ||
3752 | * ERR_PTR(), use IS_ERR() etc. | ||
3753 | * | ||
3754 | * Note that this function assumes the key isn't added to hardware | ||
3755 | * acceleration, so no TX will be done with the key. Since it's a GTK | ||
3756 | * on managed (station) networks, this is true anyway. If the driver | ||
3757 | * calls this function from the resume callback and subsequently uses | ||
3758 | * the return code 1 to reconfigure the device, this key will be part | ||
3759 | * of the reconfiguration. | ||
3760 | * | ||
3761 | * Note that the driver should also call ieee80211_set_key_rx_seq() | ||
3762 | * for the new key for each TID to set up sequence counters properly. | ||
3763 | * | ||
3764 | * IMPORTANT: If this replaces a key that is present in the hardware, | ||
3765 | * then it will attempt to remove it during this call. In many cases | ||
3766 | * this isn't what you want, so call ieee80211_remove_key() first for | ||
3767 | * the key that's being replaced. | ||
3768 | */ | ||
3769 | struct ieee80211_key_conf * | ||
3770 | ieee80211_gtk_rekey_add(struct ieee80211_vif *vif, | ||
3771 | struct ieee80211_key_conf *keyconf); | ||
3772 | |||
3773 | /** | ||
3691 | * ieee80211_gtk_rekey_notify - notify userspace supplicant of rekeying | 3774 | * ieee80211_gtk_rekey_notify - notify userspace supplicant of rekeying |
3692 | * @vif: virtual interface the rekeying was done on | 3775 | * @vif: virtual interface the rekeying was done on |
3693 | * @bssid: The BSSID of the AP, for checking association | 3776 | * @bssid: The BSSID of the AP, for checking association |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index e39cc91d0cf1..620677e897bd 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -93,6 +93,9 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
93 | 93 | ||
94 | might_sleep(); | 94 | might_sleep(); |
95 | 95 | ||
96 | if (key->flags & KEY_FLAG_TAINTED) | ||
97 | return -EINVAL; | ||
98 | |||
96 | if (!key->local->ops->set_key) | 99 | if (!key->local->ops->set_key) |
97 | goto out_unsupported; | 100 | goto out_unsupported; |
98 | 101 | ||
@@ -455,6 +458,7 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
455 | struct ieee80211_sub_if_data *sdata, | 458 | struct ieee80211_sub_if_data *sdata, |
456 | struct sta_info *sta) | 459 | struct sta_info *sta) |
457 | { | 460 | { |
461 | struct ieee80211_local *local = sdata->local; | ||
458 | struct ieee80211_key *old_key; | 462 | struct ieee80211_key *old_key; |
459 | int idx, ret; | 463 | int idx, ret; |
460 | bool pairwise; | 464 | bool pairwise; |
@@ -484,10 +488,13 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
484 | 488 | ||
485 | ieee80211_debugfs_key_add(key); | 489 | ieee80211_debugfs_key_add(key); |
486 | 490 | ||
487 | ret = ieee80211_key_enable_hw_accel(key); | 491 | if (!local->wowlan) { |
488 | 492 | ret = ieee80211_key_enable_hw_accel(key); | |
489 | if (ret) | 493 | if (ret) |
490 | ieee80211_key_free(key, true); | 494 | ieee80211_key_free(key, true); |
495 | } else { | ||
496 | ret = 0; | ||
497 | } | ||
491 | 498 | ||
492 | mutex_unlock(&sdata->local->key_mtx); | 499 | mutex_unlock(&sdata->local->key_mtx); |
493 | 500 | ||
@@ -540,7 +547,7 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw, | |||
540 | void *iter_data) | 547 | void *iter_data) |
541 | { | 548 | { |
542 | struct ieee80211_local *local = hw_to_local(hw); | 549 | struct ieee80211_local *local = hw_to_local(hw); |
543 | struct ieee80211_key *key; | 550 | struct ieee80211_key *key, *tmp; |
544 | struct ieee80211_sub_if_data *sdata; | 551 | struct ieee80211_sub_if_data *sdata; |
545 | 552 | ||
546 | ASSERT_RTNL(); | 553 | ASSERT_RTNL(); |
@@ -548,13 +555,14 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw, | |||
548 | mutex_lock(&local->key_mtx); | 555 | mutex_lock(&local->key_mtx); |
549 | if (vif) { | 556 | if (vif) { |
550 | sdata = vif_to_sdata(vif); | 557 | sdata = vif_to_sdata(vif); |
551 | list_for_each_entry(key, &sdata->key_list, list) | 558 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) |
552 | iter(hw, &sdata->vif, | 559 | iter(hw, &sdata->vif, |
553 | key->sta ? &key->sta->sta : NULL, | 560 | key->sta ? &key->sta->sta : NULL, |
554 | &key->conf, iter_data); | 561 | &key->conf, iter_data); |
555 | } else { | 562 | } else { |
556 | list_for_each_entry(sdata, &local->interfaces, list) | 563 | list_for_each_entry(sdata, &local->interfaces, list) |
557 | list_for_each_entry(key, &sdata->key_list, list) | 564 | list_for_each_entry_safe(key, tmp, |
565 | &sdata->key_list, list) | ||
558 | iter(hw, &sdata->vif, | 566 | iter(hw, &sdata->vif, |
559 | key->sta ? &key->sta->sta : NULL, | 567 | key->sta ? &key->sta->sta : NULL, |
560 | &key->conf, iter_data); | 568 | &key->conf, iter_data); |
@@ -751,3 +759,135 @@ void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf, | |||
751 | } | 759 | } |
752 | } | 760 | } |
753 | EXPORT_SYMBOL(ieee80211_get_key_rx_seq); | 761 | EXPORT_SYMBOL(ieee80211_get_key_rx_seq); |
762 | |||
763 | void ieee80211_set_key_tx_seq(struct ieee80211_key_conf *keyconf, | ||
764 | struct ieee80211_key_seq *seq) | ||
765 | { | ||
766 | struct ieee80211_key *key; | ||
767 | u64 pn64; | ||
768 | |||
769 | key = container_of(keyconf, struct ieee80211_key, conf); | ||
770 | |||
771 | switch (key->conf.cipher) { | ||
772 | case WLAN_CIPHER_SUITE_TKIP: | ||
773 | key->u.tkip.tx.iv32 = seq->tkip.iv32; | ||
774 | key->u.tkip.tx.iv16 = seq->tkip.iv16; | ||
775 | break; | ||
776 | case WLAN_CIPHER_SUITE_CCMP: | ||
777 | pn64 = (u64)seq->ccmp.pn[5] | | ||
778 | ((u64)seq->ccmp.pn[4] << 8) | | ||
779 | ((u64)seq->ccmp.pn[3] << 16) | | ||
780 | ((u64)seq->ccmp.pn[2] << 24) | | ||
781 | ((u64)seq->ccmp.pn[1] << 32) | | ||
782 | ((u64)seq->ccmp.pn[0] << 40); | ||
783 | atomic64_set(&key->u.ccmp.tx_pn, pn64); | ||
784 | break; | ||
785 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
786 | pn64 = (u64)seq->aes_cmac.pn[5] | | ||
787 | ((u64)seq->aes_cmac.pn[4] << 8) | | ||
788 | ((u64)seq->aes_cmac.pn[3] << 16) | | ||
789 | ((u64)seq->aes_cmac.pn[2] << 24) | | ||
790 | ((u64)seq->aes_cmac.pn[1] << 32) | | ||
791 | ((u64)seq->aes_cmac.pn[0] << 40); | ||
792 | atomic64_set(&key->u.aes_cmac.tx_pn, pn64); | ||
793 | break; | ||
794 | default: | ||
795 | WARN_ON(1); | ||
796 | break; | ||
797 | } | ||
798 | } | ||
799 | EXPORT_SYMBOL_GPL(ieee80211_set_key_tx_seq); | ||
800 | |||
801 | void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf, | ||
802 | int tid, struct ieee80211_key_seq *seq) | ||
803 | { | ||
804 | struct ieee80211_key *key; | ||
805 | u8 *pn; | ||
806 | |||
807 | key = container_of(keyconf, struct ieee80211_key, conf); | ||
808 | |||
809 | switch (key->conf.cipher) { | ||
810 | case WLAN_CIPHER_SUITE_TKIP: | ||
811 | if (WARN_ON(tid < 0 || tid >= IEEE80211_NUM_TIDS)) | ||
812 | return; | ||
813 | key->u.tkip.rx[tid].iv32 = seq->tkip.iv32; | ||
814 | key->u.tkip.rx[tid].iv16 = seq->tkip.iv16; | ||
815 | break; | ||
816 | case WLAN_CIPHER_SUITE_CCMP: | ||
817 | if (WARN_ON(tid < -1 || tid >= IEEE80211_NUM_TIDS)) | ||
818 | return; | ||
819 | if (tid < 0) | ||
820 | pn = key->u.ccmp.rx_pn[IEEE80211_NUM_TIDS]; | ||
821 | else | ||
822 | pn = key->u.ccmp.rx_pn[tid]; | ||
823 | memcpy(pn, seq->ccmp.pn, IEEE80211_CCMP_PN_LEN); | ||
824 | break; | ||
825 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
826 | if (WARN_ON(tid != 0)) | ||
827 | return; | ||
828 | pn = key->u.aes_cmac.rx_pn; | ||
829 | memcpy(pn, seq->aes_cmac.pn, IEEE80211_CMAC_PN_LEN); | ||
830 | break; | ||
831 | default: | ||
832 | WARN_ON(1); | ||
833 | break; | ||
834 | } | ||
835 | } | ||
836 | EXPORT_SYMBOL_GPL(ieee80211_set_key_rx_seq); | ||
837 | |||
838 | void ieee80211_remove_key(struct ieee80211_key_conf *keyconf) | ||
839 | { | ||
840 | struct ieee80211_key *key; | ||
841 | |||
842 | key = container_of(keyconf, struct ieee80211_key, conf); | ||
843 | |||
844 | assert_key_lock(key->local); | ||
845 | |||
846 | /* | ||
847 | * if key was uploaded, we assume the driver will/has remove(d) | ||
848 | * it, so adjust bookkeeping accordingly | ||
849 | */ | ||
850 | if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { | ||
851 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; | ||
852 | |||
853 | if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || | ||
854 | (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) || | ||
855 | (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE))) | ||
856 | increment_tailroom_need_count(key->sdata); | ||
857 | } | ||
858 | |||
859 | ieee80211_key_free(key, false); | ||
860 | } | ||
861 | EXPORT_SYMBOL_GPL(ieee80211_remove_key); | ||
862 | |||
863 | struct ieee80211_key_conf * | ||
864 | ieee80211_gtk_rekey_add(struct ieee80211_vif *vif, | ||
865 | struct ieee80211_key_conf *keyconf) | ||
866 | { | ||
867 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
868 | struct ieee80211_local *local = sdata->local; | ||
869 | struct ieee80211_key *key; | ||
870 | int err; | ||
871 | |||
872 | if (WARN_ON(!local->wowlan)) | ||
873 | return ERR_PTR(-EINVAL); | ||
874 | |||
875 | if (WARN_ON(vif->type != NL80211_IFTYPE_STATION)) | ||
876 | return ERR_PTR(-EINVAL); | ||
877 | |||
878 | key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx, | ||
879 | keyconf->keylen, keyconf->key, | ||
880 | 0, NULL); | ||
881 | if (IS_ERR(key)) | ||
882 | return ERR_PTR(PTR_ERR(key)); | ||
883 | |||
884 | if (sdata->u.mgd.mfp != IEEE80211_MFP_DISABLED) | ||
885 | key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT; | ||
886 | |||
887 | err = ieee80211_key_link(key, sdata, NULL); | ||
888 | if (err) | ||
889 | return ERR_PTR(err); | ||
890 | |||
891 | return &key->conf; | ||
892 | } | ||
893 | EXPORT_SYMBOL_GPL(ieee80211_gtk_rekey_add); | ||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index d23c5a705a68..e1b34a18b243 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1453,8 +1453,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1453 | local->resuming = true; | 1453 | local->resuming = true; |
1454 | 1454 | ||
1455 | if (local->wowlan) { | 1455 | if (local->wowlan) { |
1456 | local->wowlan = false; | ||
1457 | res = drv_resume(local); | 1456 | res = drv_resume(local); |
1457 | local->wowlan = false; | ||
1458 | if (res < 0) { | 1458 | if (res < 0) { |
1459 | local->resuming = false; | 1459 | local->resuming = false; |
1460 | return res; | 1460 | return res; |