diff options
author | Johannes Berg <johannes.berg@intel.com> | 2011-07-07 12:58:00 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-07-08 11:42:22 -0400 |
commit | 3ea542d3c2862142ae511fac5ce2dfc7419dcc53 (patch) | |
tree | 472807c6d2a0aefa050a63cc34d9e2a2f7a3f2a6 | |
parent | 9e26297a56453315ae6829aec609b5a6309af7b4 (diff) |
mac80211: allow drivers to access key sequence counter
In order to implement GTK rekeying, the device needs
to be able to encrypt frames with the right PN/IV and
check the PN/IV in RX frames. To be able to tell it
about all those counters, we need to be able to get
them from mac80211, this adds the required API.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | include/net/mac80211.h | 60 | ||||
-rw-r--r-- | net/mac80211/key.c | 74 | ||||
-rw-r--r-- | net/mac80211/key.h | 5 |
3 files changed, 137 insertions, 2 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 0aae7bc1eeae..84770cedae2d 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -2592,6 +2592,66 @@ void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf, | |||
2592 | struct sk_buff *skb, u8 *p2k); | 2592 | struct sk_buff *skb, u8 *p2k); |
2593 | 2593 | ||
2594 | /** | 2594 | /** |
2595 | * struct ieee80211_key_seq - key sequence counter | ||
2596 | * | ||
2597 | * @tkip: TKIP data, containing IV32 and IV16 in host byte order | ||
2598 | * @ccmp: PN data, most significant byte first (big endian, | ||
2599 | * reverse order than in packet) | ||
2600 | * @aes_cmac: PN data, most significant byte first (big endian, | ||
2601 | * reverse order than in packet) | ||
2602 | */ | ||
2603 | struct ieee80211_key_seq { | ||
2604 | union { | ||
2605 | struct { | ||
2606 | u32 iv32; | ||
2607 | u16 iv16; | ||
2608 | } tkip; | ||
2609 | struct { | ||
2610 | u8 pn[6]; | ||
2611 | } ccmp; | ||
2612 | struct { | ||
2613 | u8 pn[6]; | ||
2614 | } aes_cmac; | ||
2615 | }; | ||
2616 | }; | ||
2617 | |||
2618 | /** | ||
2619 | * ieee80211_get_key_tx_seq - get key TX sequence counter | ||
2620 | * | ||
2621 | * @keyconf: the parameter passed with the set key | ||
2622 | * @seq: buffer to receive the sequence data | ||
2623 | * | ||
2624 | * This function allows a driver to retrieve the current TX IV/PN | ||
2625 | * for the given key. It must not be called if IV generation is | ||
2626 | * offloaded to the device. | ||
2627 | * | ||
2628 | * Note that this function may only be called when no TX processing | ||
2629 | * can be done concurrently, for example when queues are stopped | ||
2630 | * and the stop has been synchronized. | ||
2631 | */ | ||
2632 | void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf, | ||
2633 | struct ieee80211_key_seq *seq); | ||
2634 | |||
2635 | /** | ||
2636 | * ieee80211_get_key_rx_seq - get key RX sequence counter | ||
2637 | * | ||
2638 | * @keyconf: the parameter passed with the set key | ||
2639 | * @tid: The TID, or -1 for the management frame value (CCMP only); | ||
2640 | * the value on TID 0 is also used for non-QoS frames. For | ||
2641 | * CMAC, only TID 0 is valid. | ||
2642 | * @seq: buffer to receive the sequence data | ||
2643 | * | ||
2644 | * This function allows a driver to retrieve the current RX IV/PNs | ||
2645 | * for the given key. It must not be called if IV checking is done | ||
2646 | * by the device and not by mac80211. | ||
2647 | * | ||
2648 | * Note that this function may only be called when no RX processing | ||
2649 | * can be done concurrently. | ||
2650 | */ | ||
2651 | void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf, | ||
2652 | int tid, struct ieee80211_key_seq *seq); | ||
2653 | |||
2654 | /** | ||
2595 | * ieee80211_gtk_rekey_notify - notify userspace supplicant of rekeying | 2655 | * ieee80211_gtk_rekey_notify - notify userspace supplicant of rekeying |
2596 | * @vif: virtual interface the rekeying was done on | 2656 | * @vif: virtual interface the rekeying was done on |
2597 | * @bssid: The BSSID of the AP, for checking association | 2657 | * @bssid: The BSSID of the AP, for checking association |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index d930d4d4876d..739bee13e813 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -626,3 +626,77 @@ void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid, | |||
626 | cfg80211_gtk_rekey_notify(sdata->dev, bssid, replay_ctr, gfp); | 626 | cfg80211_gtk_rekey_notify(sdata->dev, bssid, replay_ctr, gfp); |
627 | } | 627 | } |
628 | EXPORT_SYMBOL_GPL(ieee80211_gtk_rekey_notify); | 628 | EXPORT_SYMBOL_GPL(ieee80211_gtk_rekey_notify); |
629 | |||
630 | void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf, | ||
631 | struct ieee80211_key_seq *seq) | ||
632 | { | ||
633 | struct ieee80211_key *key; | ||
634 | u64 pn64; | ||
635 | |||
636 | if (WARN_ON(!(keyconf->flags & IEEE80211_KEY_FLAG_GENERATE_IV))) | ||
637 | return; | ||
638 | |||
639 | key = container_of(keyconf, struct ieee80211_key, conf); | ||
640 | |||
641 | switch (key->conf.cipher) { | ||
642 | case WLAN_CIPHER_SUITE_TKIP: | ||
643 | seq->tkip.iv32 = key->u.tkip.tx.iv32; | ||
644 | seq->tkip.iv16 = key->u.tkip.tx.iv16; | ||
645 | break; | ||
646 | case WLAN_CIPHER_SUITE_CCMP: | ||
647 | pn64 = atomic64_read(&key->u.ccmp.tx_pn); | ||
648 | seq->ccmp.pn[5] = pn64; | ||
649 | seq->ccmp.pn[4] = pn64 >> 8; | ||
650 | seq->ccmp.pn[3] = pn64 >> 16; | ||
651 | seq->ccmp.pn[2] = pn64 >> 24; | ||
652 | seq->ccmp.pn[1] = pn64 >> 32; | ||
653 | seq->ccmp.pn[0] = pn64 >> 40; | ||
654 | break; | ||
655 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
656 | pn64 = atomic64_read(&key->u.aes_cmac.tx_pn); | ||
657 | seq->ccmp.pn[5] = pn64; | ||
658 | seq->ccmp.pn[4] = pn64 >> 8; | ||
659 | seq->ccmp.pn[3] = pn64 >> 16; | ||
660 | seq->ccmp.pn[2] = pn64 >> 24; | ||
661 | seq->ccmp.pn[1] = pn64 >> 32; | ||
662 | seq->ccmp.pn[0] = pn64 >> 40; | ||
663 | break; | ||
664 | default: | ||
665 | WARN_ON(1); | ||
666 | } | ||
667 | } | ||
668 | EXPORT_SYMBOL(ieee80211_get_key_tx_seq); | ||
669 | |||
670 | void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf, | ||
671 | int tid, struct ieee80211_key_seq *seq) | ||
672 | { | ||
673 | struct ieee80211_key *key; | ||
674 | const u8 *pn; | ||
675 | |||
676 | key = container_of(keyconf, struct ieee80211_key, conf); | ||
677 | |||
678 | switch (key->conf.cipher) { | ||
679 | case WLAN_CIPHER_SUITE_TKIP: | ||
680 | if (WARN_ON(tid < 0 || tid >= NUM_RX_DATA_QUEUES)) | ||
681 | return; | ||
682 | seq->tkip.iv32 = key->u.tkip.rx[tid].iv32; | ||
683 | seq->tkip.iv16 = key->u.tkip.rx[tid].iv16; | ||
684 | break; | ||
685 | case WLAN_CIPHER_SUITE_CCMP: | ||
686 | if (WARN_ON(tid < -1 || tid >= NUM_RX_DATA_QUEUES)) | ||
687 | return; | ||
688 | if (tid < 0) | ||
689 | pn = key->u.ccmp.rx_pn[NUM_RX_DATA_QUEUES]; | ||
690 | else | ||
691 | pn = key->u.ccmp.rx_pn[tid]; | ||
692 | memcpy(seq->ccmp.pn, pn, CCMP_PN_LEN); | ||
693 | break; | ||
694 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
695 | if (WARN_ON(tid != 0)) | ||
696 | return; | ||
697 | pn = key->u.aes_cmac.rx_pn; | ||
698 | memcpy(seq->aes_cmac.pn, pn, CMAC_PN_LEN); | ||
699 | break; | ||
700 | } | ||
701 | } | ||
702 | EXPORT_SYMBOL(ieee80211_get_key_rx_seq); | ||
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index beb9c20ff48c..86b216b01415 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -28,6 +28,7 @@ | |||
28 | #define CCMP_PN_LEN 6 | 28 | #define CCMP_PN_LEN 6 |
29 | #define TKIP_IV_LEN 8 | 29 | #define TKIP_IV_LEN 8 |
30 | #define TKIP_ICV_LEN 4 | 30 | #define TKIP_ICV_LEN 4 |
31 | #define CMAC_PN_LEN 6 | ||
31 | 32 | ||
32 | #define NUM_RX_DATA_QUEUES 16 | 33 | #define NUM_RX_DATA_QUEUES 16 |
33 | 34 | ||
@@ -89,13 +90,13 @@ struct ieee80211_key { | |||
89 | * frames and the last counter is used with Robust | 90 | * frames and the last counter is used with Robust |
90 | * Management frames. | 91 | * Management frames. |
91 | */ | 92 | */ |
92 | u8 rx_pn[NUM_RX_DATA_QUEUES + 1][6]; | 93 | u8 rx_pn[NUM_RX_DATA_QUEUES + 1][CCMP_PN_LEN]; |
93 | struct crypto_cipher *tfm; | 94 | struct crypto_cipher *tfm; |
94 | u32 replays; /* dot11RSNAStatsCCMPReplays */ | 95 | u32 replays; /* dot11RSNAStatsCCMPReplays */ |
95 | } ccmp; | 96 | } ccmp; |
96 | struct { | 97 | struct { |
97 | atomic64_t tx_pn; | 98 | atomic64_t tx_pn; |
98 | u8 rx_pn[6]; | 99 | u8 rx_pn[CMAC_PN_LEN]; |
99 | struct crypto_cipher *tfm; | 100 | struct crypto_cipher *tfm; |
100 | u32 replays; /* dot11RSNAStatsCMACReplays */ | 101 | u32 replays; /* dot11RSNAStatsCMACReplays */ |
101 | u32 icverrors; /* dot11RSNAStatsCMACICVErrors */ | 102 | u32 icverrors; /* dot11RSNAStatsCMACICVErrors */ |