diff options
author | Jouni Malinen <jouni@qca.qualcomm.com> | 2015-01-24 12:52:09 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2015-01-27 05:10:13 -0500 |
commit | 8ade538bf39b1ee53418528fdacd36b8e65621b9 (patch) | |
tree | f7bd85219ee6946b493252effe9a39918b309fb4 /net | |
parent | 56c52da2d554f081e8fce58ecbcf6a40c605b95b (diff) |
mac80111: Add BIP-GMAC-128 and BIP-GMAC-256 ciphers
This allows mac80211 to configure BIP-GMAC-128 and BIP-GMAC-256 to the
driver and also use software-implementation within mac80211 when the
driver does not support this with hardware accelaration.
Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/Makefile | 1 | ||||
-rw-r--r-- | net/mac80211/aes_gmac.c | 84 | ||||
-rw-r--r-- | net/mac80211/aes_gmac.h | 20 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 14 | ||||
-rw-r--r-- | net/mac80211/debugfs_key.c | 26 | ||||
-rw-r--r-- | net/mac80211/key.c | 60 | ||||
-rw-r--r-- | net/mac80211/key.h | 7 | ||||
-rw-r--r-- | net/mac80211/main.c | 12 | ||||
-rw-r--r-- | net/mac80211/rx.c | 4 | ||||
-rw-r--r-- | net/mac80211/tx.c | 5 | ||||
-rw-r--r-- | net/mac80211/wpa.c | 105 | ||||
-rw-r--r-- | net/mac80211/wpa.h | 4 |
12 files changed, 339 insertions, 3 deletions
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 0cbf93618433..3275f01881be 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile | |||
@@ -17,6 +17,7 @@ mac80211-y := \ | |||
17 | aes_ccm.o \ | 17 | aes_ccm.o \ |
18 | aes_gcm.o \ | 18 | aes_gcm.o \ |
19 | aes_cmac.o \ | 19 | aes_cmac.o \ |
20 | aes_gmac.o \ | ||
20 | cfg.o \ | 21 | cfg.o \ |
21 | ethtool.o \ | 22 | ethtool.o \ |
22 | rx.o \ | 23 | rx.o \ |
diff --git a/net/mac80211/aes_gmac.c b/net/mac80211/aes_gmac.c new file mode 100644 index 000000000000..1c72edcb0083 --- /dev/null +++ b/net/mac80211/aes_gmac.c | |||
@@ -0,0 +1,84 @@ | |||
1 | /* | ||
2 | * AES-GMAC for IEEE 802.11 BIP-GMAC-128 and BIP-GMAC-256 | ||
3 | * Copyright 2015, Qualcomm Atheros, Inc. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/types.h> | ||
12 | #include <linux/crypto.h> | ||
13 | #include <linux/err.h> | ||
14 | #include <crypto/aes.h> | ||
15 | |||
16 | #include <net/mac80211.h> | ||
17 | #include "key.h" | ||
18 | #include "aes_gmac.h" | ||
19 | |||
20 | #define GMAC_MIC_LEN 16 | ||
21 | #define GMAC_NONCE_LEN 12 | ||
22 | #define AAD_LEN 20 | ||
23 | |||
24 | int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce, | ||
25 | const u8 *data, size_t data_len, u8 *mic) | ||
26 | { | ||
27 | struct scatterlist sg[3], ct[1]; | ||
28 | char aead_req_data[sizeof(struct aead_request) + | ||
29 | crypto_aead_reqsize(tfm)] | ||
30 | __aligned(__alignof__(struct aead_request)); | ||
31 | struct aead_request *aead_req = (void *)aead_req_data; | ||
32 | u8 zero[GMAC_MIC_LEN], iv[AES_BLOCK_SIZE]; | ||
33 | |||
34 | if (data_len < GMAC_MIC_LEN) | ||
35 | return -EINVAL; | ||
36 | |||
37 | memset(aead_req, 0, sizeof(aead_req_data)); | ||
38 | |||
39 | memset(zero, 0, GMAC_MIC_LEN); | ||
40 | sg_init_table(sg, 3); | ||
41 | sg_set_buf(&sg[0], aad, AAD_LEN); | ||
42 | sg_set_buf(&sg[1], data, data_len - GMAC_MIC_LEN); | ||
43 | sg_set_buf(&sg[2], zero, GMAC_MIC_LEN); | ||
44 | |||
45 | memcpy(iv, nonce, GMAC_NONCE_LEN); | ||
46 | memset(iv + GMAC_NONCE_LEN, 0, sizeof(iv) - GMAC_NONCE_LEN); | ||
47 | iv[AES_BLOCK_SIZE - 1] = 0x01; | ||
48 | |||
49 | sg_init_table(ct, 1); | ||
50 | sg_set_buf(&ct[0], mic, GMAC_MIC_LEN); | ||
51 | |||
52 | aead_request_set_tfm(aead_req, tfm); | ||
53 | aead_request_set_assoc(aead_req, sg, AAD_LEN + data_len); | ||
54 | aead_request_set_crypt(aead_req, NULL, ct, 0, iv); | ||
55 | |||
56 | crypto_aead_encrypt(aead_req); | ||
57 | |||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | struct crypto_aead *ieee80211_aes_gmac_key_setup(const u8 key[], | ||
62 | size_t key_len) | ||
63 | { | ||
64 | struct crypto_aead *tfm; | ||
65 | int err; | ||
66 | |||
67 | tfm = crypto_alloc_aead("gcm(aes)", 0, CRYPTO_ALG_ASYNC); | ||
68 | if (IS_ERR(tfm)) | ||
69 | return tfm; | ||
70 | |||
71 | err = crypto_aead_setkey(tfm, key, key_len); | ||
72 | if (!err) | ||
73 | return tfm; | ||
74 | if (!err) | ||
75 | err = crypto_aead_setauthsize(tfm, GMAC_MIC_LEN); | ||
76 | |||
77 | crypto_free_aead(tfm); | ||
78 | return ERR_PTR(err); | ||
79 | } | ||
80 | |||
81 | void ieee80211_aes_gmac_key_free(struct crypto_aead *tfm) | ||
82 | { | ||
83 | crypto_free_aead(tfm); | ||
84 | } | ||
diff --git a/net/mac80211/aes_gmac.h b/net/mac80211/aes_gmac.h new file mode 100644 index 000000000000..d328204d73a8 --- /dev/null +++ b/net/mac80211/aes_gmac.h | |||
@@ -0,0 +1,20 @@ | |||
1 | /* | ||
2 | * Copyright 2015, Qualcomm Atheros, Inc. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #ifndef AES_GMAC_H | ||
10 | #define AES_GMAC_H | ||
11 | |||
12 | #include <linux/crypto.h> | ||
13 | |||
14 | struct crypto_aead *ieee80211_aes_gmac_key_setup(const u8 key[], | ||
15 | size_t key_len); | ||
16 | int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce, | ||
17 | const u8 *data, size_t data_len, u8 *mic); | ||
18 | void ieee80211_aes_gmac_key_free(struct crypto_aead *tfm); | ||
19 | |||
20 | #endif /* AES_GMAC_H */ | ||
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index b7e528bbecce..dd4ff36c557a 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -165,6 +165,8 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
165 | case WLAN_CIPHER_SUITE_CCMP_256: | 165 | case WLAN_CIPHER_SUITE_CCMP_256: |
166 | case WLAN_CIPHER_SUITE_AES_CMAC: | 166 | case WLAN_CIPHER_SUITE_AES_CMAC: |
167 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | 167 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: |
168 | case WLAN_CIPHER_SUITE_BIP_GMAC_128: | ||
169 | case WLAN_CIPHER_SUITE_BIP_GMAC_256: | ||
168 | case WLAN_CIPHER_SUITE_GCMP: | 170 | case WLAN_CIPHER_SUITE_GCMP: |
169 | case WLAN_CIPHER_SUITE_GCMP_256: | 171 | case WLAN_CIPHER_SUITE_GCMP_256: |
170 | break; | 172 | break; |
@@ -374,6 +376,18 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
374 | params.seq = seq; | 376 | params.seq = seq; |
375 | params.seq_len = 6; | 377 | params.seq_len = 6; |
376 | break; | 378 | break; |
379 | case WLAN_CIPHER_SUITE_BIP_GMAC_128: | ||
380 | case WLAN_CIPHER_SUITE_BIP_GMAC_256: | ||
381 | pn64 = atomic64_read(&key->u.aes_gmac.tx_pn); | ||
382 | seq[0] = pn64; | ||
383 | seq[1] = pn64 >> 8; | ||
384 | seq[2] = pn64 >> 16; | ||
385 | seq[3] = pn64 >> 24; | ||
386 | seq[4] = pn64 >> 32; | ||
387 | seq[5] = pn64 >> 40; | ||
388 | params.seq = seq; | ||
389 | params.seq_len = 6; | ||
390 | break; | ||
377 | case WLAN_CIPHER_SUITE_GCMP: | 391 | case WLAN_CIPHER_SUITE_GCMP: |
378 | case WLAN_CIPHER_SUITE_GCMP_256: | 392 | case WLAN_CIPHER_SUITE_GCMP_256: |
379 | pn64 = atomic64_read(&key->u.gcmp.tx_pn); | 393 | pn64 = atomic64_read(&key->u.gcmp.tx_pn); |
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index d1b60eb014a8..71ac1b5f4da5 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c | |||
@@ -107,6 +107,13 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf, | |||
107 | (u8)(pn >> 40), (u8)(pn >> 32), (u8)(pn >> 24), | 107 | (u8)(pn >> 40), (u8)(pn >> 32), (u8)(pn >> 24), |
108 | (u8)(pn >> 16), (u8)(pn >> 8), (u8)pn); | 108 | (u8)(pn >> 16), (u8)(pn >> 8), (u8)pn); |
109 | break; | 109 | break; |
110 | case WLAN_CIPHER_SUITE_BIP_GMAC_128: | ||
111 | case WLAN_CIPHER_SUITE_BIP_GMAC_256: | ||
112 | pn = atomic64_read(&key->u.aes_gmac.tx_pn); | ||
113 | len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", | ||
114 | (u8)(pn >> 40), (u8)(pn >> 32), (u8)(pn >> 24), | ||
115 | (u8)(pn >> 16), (u8)(pn >> 8), (u8)pn); | ||
116 | break; | ||
110 | case WLAN_CIPHER_SUITE_GCMP: | 117 | case WLAN_CIPHER_SUITE_GCMP: |
111 | case WLAN_CIPHER_SUITE_GCMP_256: | 118 | case WLAN_CIPHER_SUITE_GCMP_256: |
112 | pn = atomic64_read(&key->u.gcmp.tx_pn); | 119 | pn = atomic64_read(&key->u.gcmp.tx_pn); |
@@ -162,6 +169,15 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, | |||
162 | rpn[3], rpn[4], rpn[5]); | 169 | rpn[3], rpn[4], rpn[5]); |
163 | len = p - buf; | 170 | len = p - buf; |
164 | break; | 171 | break; |
172 | case WLAN_CIPHER_SUITE_BIP_GMAC_128: | ||
173 | case WLAN_CIPHER_SUITE_BIP_GMAC_256: | ||
174 | rpn = key->u.aes_gmac.rx_pn; | ||
175 | p += scnprintf(p, sizeof(buf)+buf-p, | ||
176 | "%02x%02x%02x%02x%02x%02x\n", | ||
177 | rpn[0], rpn[1], rpn[2], | ||
178 | rpn[3], rpn[4], rpn[5]); | ||
179 | len = p - buf; | ||
180 | break; | ||
165 | case WLAN_CIPHER_SUITE_GCMP: | 181 | case WLAN_CIPHER_SUITE_GCMP: |
166 | case WLAN_CIPHER_SUITE_GCMP_256: | 182 | case WLAN_CIPHER_SUITE_GCMP_256: |
167 | for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) { | 183 | for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) { |
@@ -197,6 +213,11 @@ static ssize_t key_replays_read(struct file *file, char __user *userbuf, | |||
197 | len = scnprintf(buf, sizeof(buf), "%u\n", | 213 | len = scnprintf(buf, sizeof(buf), "%u\n", |
198 | key->u.aes_cmac.replays); | 214 | key->u.aes_cmac.replays); |
199 | break; | 215 | break; |
216 | case WLAN_CIPHER_SUITE_BIP_GMAC_128: | ||
217 | case WLAN_CIPHER_SUITE_BIP_GMAC_256: | ||
218 | len = scnprintf(buf, sizeof(buf), "%u\n", | ||
219 | key->u.aes_gmac.replays); | ||
220 | break; | ||
200 | case WLAN_CIPHER_SUITE_GCMP: | 221 | case WLAN_CIPHER_SUITE_GCMP: |
201 | case WLAN_CIPHER_SUITE_GCMP_256: | 222 | case WLAN_CIPHER_SUITE_GCMP_256: |
202 | len = scnprintf(buf, sizeof(buf), "%u\n", key->u.gcmp.replays); | 223 | len = scnprintf(buf, sizeof(buf), "%u\n", key->u.gcmp.replays); |
@@ -221,6 +242,11 @@ static ssize_t key_icverrors_read(struct file *file, char __user *userbuf, | |||
221 | len = scnprintf(buf, sizeof(buf), "%u\n", | 242 | len = scnprintf(buf, sizeof(buf), "%u\n", |
222 | key->u.aes_cmac.icverrors); | 243 | key->u.aes_cmac.icverrors); |
223 | break; | 244 | break; |
245 | case WLAN_CIPHER_SUITE_BIP_GMAC_128: | ||
246 | case WLAN_CIPHER_SUITE_BIP_GMAC_256: | ||
247 | len = scnprintf(buf, sizeof(buf), "%u\n", | ||
248 | key->u.aes_gmac.icverrors); | ||
249 | break; | ||
224 | default: | 250 | default: |
225 | return 0; | 251 | return 0; |
226 | } | 252 | } |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 7ceea9d9fcd2..0825d76edcfc 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "debugfs_key.h" | 24 | #include "debugfs_key.h" |
25 | #include "aes_ccm.h" | 25 | #include "aes_ccm.h" |
26 | #include "aes_cmac.h" | 26 | #include "aes_cmac.h" |
27 | #include "aes_gmac.h" | ||
27 | #include "aes_gcm.h" | 28 | #include "aes_gcm.h" |
28 | 29 | ||
29 | 30 | ||
@@ -166,6 +167,8 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
166 | case WLAN_CIPHER_SUITE_CCMP_256: | 167 | case WLAN_CIPHER_SUITE_CCMP_256: |
167 | case WLAN_CIPHER_SUITE_AES_CMAC: | 168 | case WLAN_CIPHER_SUITE_AES_CMAC: |
168 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | 169 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: |
170 | case WLAN_CIPHER_SUITE_BIP_GMAC_128: | ||
171 | case WLAN_CIPHER_SUITE_BIP_GMAC_256: | ||
169 | case WLAN_CIPHER_SUITE_GCMP: | 172 | case WLAN_CIPHER_SUITE_GCMP: |
170 | case WLAN_CIPHER_SUITE_GCMP_256: | 173 | case WLAN_CIPHER_SUITE_GCMP_256: |
171 | /* all of these we can do in software - if driver can */ | 174 | /* all of these we can do in software - if driver can */ |
@@ -440,6 +443,25 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
440 | return ERR_PTR(err); | 443 | return ERR_PTR(err); |
441 | } | 444 | } |
442 | break; | 445 | break; |
446 | case WLAN_CIPHER_SUITE_BIP_GMAC_128: | ||
447 | case WLAN_CIPHER_SUITE_BIP_GMAC_256: | ||
448 | key->conf.iv_len = 0; | ||
449 | key->conf.icv_len = sizeof(struct ieee80211_mmie_16); | ||
450 | if (seq) | ||
451 | for (j = 0; j < IEEE80211_GMAC_PN_LEN; j++) | ||
452 | key->u.aes_gmac.rx_pn[j] = | ||
453 | seq[IEEE80211_GMAC_PN_LEN - j - 1]; | ||
454 | /* Initialize AES key state here as an optimization so that | ||
455 | * it does not need to be initialized for every packet. | ||
456 | */ | ||
457 | key->u.aes_gmac.tfm = | ||
458 | ieee80211_aes_gmac_key_setup(key_data, key_len); | ||
459 | if (IS_ERR(key->u.aes_gmac.tfm)) { | ||
460 | err = PTR_ERR(key->u.aes_gmac.tfm); | ||
461 | kfree(key); | ||
462 | return ERR_PTR(err); | ||
463 | } | ||
464 | break; | ||
443 | case WLAN_CIPHER_SUITE_GCMP: | 465 | case WLAN_CIPHER_SUITE_GCMP: |
444 | case WLAN_CIPHER_SUITE_GCMP_256: | 466 | case WLAN_CIPHER_SUITE_GCMP_256: |
445 | key->conf.iv_len = IEEE80211_GCMP_HDR_LEN; | 467 | key->conf.iv_len = IEEE80211_GCMP_HDR_LEN; |
@@ -489,6 +511,10 @@ static void ieee80211_key_free_common(struct ieee80211_key *key) | |||
489 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | 511 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: |
490 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); | 512 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); |
491 | break; | 513 | break; |
514 | case WLAN_CIPHER_SUITE_BIP_GMAC_128: | ||
515 | case WLAN_CIPHER_SUITE_BIP_GMAC_256: | ||
516 | ieee80211_aes_gmac_key_free(key->u.aes_gmac.tfm); | ||
517 | break; | ||
492 | case WLAN_CIPHER_SUITE_GCMP: | 518 | case WLAN_CIPHER_SUITE_GCMP: |
493 | case WLAN_CIPHER_SUITE_GCMP_256: | 519 | case WLAN_CIPHER_SUITE_GCMP_256: |
494 | ieee80211_aes_gcm_key_free(key->u.gcmp.tfm); | 520 | ieee80211_aes_gcm_key_free(key->u.gcmp.tfm); |
@@ -819,6 +845,16 @@ void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf, | |||
819 | seq->ccmp.pn[1] = pn64 >> 32; | 845 | seq->ccmp.pn[1] = pn64 >> 32; |
820 | seq->ccmp.pn[0] = pn64 >> 40; | 846 | seq->ccmp.pn[0] = pn64 >> 40; |
821 | break; | 847 | break; |
848 | case WLAN_CIPHER_SUITE_BIP_GMAC_128: | ||
849 | case WLAN_CIPHER_SUITE_BIP_GMAC_256: | ||
850 | pn64 = atomic64_read(&key->u.aes_gmac.tx_pn); | ||
851 | seq->ccmp.pn[5] = pn64; | ||
852 | seq->ccmp.pn[4] = pn64 >> 8; | ||
853 | seq->ccmp.pn[3] = pn64 >> 16; | ||
854 | seq->ccmp.pn[2] = pn64 >> 24; | ||
855 | seq->ccmp.pn[1] = pn64 >> 32; | ||
856 | seq->ccmp.pn[0] = pn64 >> 40; | ||
857 | break; | ||
822 | case WLAN_CIPHER_SUITE_GCMP: | 858 | case WLAN_CIPHER_SUITE_GCMP: |
823 | case WLAN_CIPHER_SUITE_GCMP_256: | 859 | case WLAN_CIPHER_SUITE_GCMP_256: |
824 | pn64 = atomic64_read(&key->u.gcmp.tx_pn); | 860 | pn64 = atomic64_read(&key->u.gcmp.tx_pn); |
@@ -867,6 +903,13 @@ void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf, | |||
867 | pn = key->u.aes_cmac.rx_pn; | 903 | pn = key->u.aes_cmac.rx_pn; |
868 | memcpy(seq->aes_cmac.pn, pn, IEEE80211_CMAC_PN_LEN); | 904 | memcpy(seq->aes_cmac.pn, pn, IEEE80211_CMAC_PN_LEN); |
869 | break; | 905 | break; |
906 | case WLAN_CIPHER_SUITE_BIP_GMAC_128: | ||
907 | case WLAN_CIPHER_SUITE_BIP_GMAC_256: | ||
908 | if (WARN_ON(tid != 0)) | ||
909 | return; | ||
910 | pn = key->u.aes_gmac.rx_pn; | ||
911 | memcpy(seq->aes_gmac.pn, pn, IEEE80211_GMAC_PN_LEN); | ||
912 | break; | ||
870 | case WLAN_CIPHER_SUITE_GCMP: | 913 | case WLAN_CIPHER_SUITE_GCMP: |
871 | case WLAN_CIPHER_SUITE_GCMP_256: | 914 | case WLAN_CIPHER_SUITE_GCMP_256: |
872 | if (WARN_ON(tid < -1 || tid >= IEEE80211_NUM_TIDS)) | 915 | if (WARN_ON(tid < -1 || tid >= IEEE80211_NUM_TIDS)) |
@@ -914,6 +957,16 @@ void ieee80211_set_key_tx_seq(struct ieee80211_key_conf *keyconf, | |||
914 | ((u64)seq->aes_cmac.pn[0] << 40); | 957 | ((u64)seq->aes_cmac.pn[0] << 40); |
915 | atomic64_set(&key->u.aes_cmac.tx_pn, pn64); | 958 | atomic64_set(&key->u.aes_cmac.tx_pn, pn64); |
916 | break; | 959 | break; |
960 | case WLAN_CIPHER_SUITE_BIP_GMAC_128: | ||
961 | case WLAN_CIPHER_SUITE_BIP_GMAC_256: | ||
962 | pn64 = (u64)seq->aes_gmac.pn[5] | | ||
963 | ((u64)seq->aes_gmac.pn[4] << 8) | | ||
964 | ((u64)seq->aes_gmac.pn[3] << 16) | | ||
965 | ((u64)seq->aes_gmac.pn[2] << 24) | | ||
966 | ((u64)seq->aes_gmac.pn[1] << 32) | | ||
967 | ((u64)seq->aes_gmac.pn[0] << 40); | ||
968 | atomic64_set(&key->u.aes_gmac.tx_pn, pn64); | ||
969 | break; | ||
917 | case WLAN_CIPHER_SUITE_GCMP: | 970 | case WLAN_CIPHER_SUITE_GCMP: |
918 | case WLAN_CIPHER_SUITE_GCMP_256: | 971 | case WLAN_CIPHER_SUITE_GCMP_256: |
919 | pn64 = (u64)seq->gcmp.pn[5] | | 972 | pn64 = (u64)seq->gcmp.pn[5] | |
@@ -963,6 +1016,13 @@ void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf, | |||
963 | pn = key->u.aes_cmac.rx_pn; | 1016 | pn = key->u.aes_cmac.rx_pn; |
964 | memcpy(pn, seq->aes_cmac.pn, IEEE80211_CMAC_PN_LEN); | 1017 | memcpy(pn, seq->aes_cmac.pn, IEEE80211_CMAC_PN_LEN); |
965 | break; | 1018 | break; |
1019 | case WLAN_CIPHER_SUITE_BIP_GMAC_128: | ||
1020 | case WLAN_CIPHER_SUITE_BIP_GMAC_256: | ||
1021 | if (WARN_ON(tid != 0)) | ||
1022 | return; | ||
1023 | pn = key->u.aes_gmac.rx_pn; | ||
1024 | memcpy(pn, seq->aes_gmac.pn, IEEE80211_GMAC_PN_LEN); | ||
1025 | break; | ||
966 | case WLAN_CIPHER_SUITE_GCMP: | 1026 | case WLAN_CIPHER_SUITE_GCMP: |
967 | case WLAN_CIPHER_SUITE_GCMP_256: | 1027 | case WLAN_CIPHER_SUITE_GCMP_256: |
968 | if (WARN_ON(tid < -1 || tid >= IEEE80211_NUM_TIDS)) | 1028 | if (WARN_ON(tid < -1 || tid >= IEEE80211_NUM_TIDS)) |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 27580da851c8..d57a9915494f 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -96,6 +96,13 @@ struct ieee80211_key { | |||
96 | } aes_cmac; | 96 | } aes_cmac; |
97 | struct { | 97 | struct { |
98 | atomic64_t tx_pn; | 98 | atomic64_t tx_pn; |
99 | u8 rx_pn[IEEE80211_GMAC_PN_LEN]; | ||
100 | struct crypto_aead *tfm; | ||
101 | u32 replays; /* dot11RSNAStatsCMACReplays */ | ||
102 | u32 icverrors; /* dot11RSNAStatsCMACICVErrors */ | ||
103 | } aes_gmac; | ||
104 | struct { | ||
105 | atomic64_t tx_pn; | ||
99 | /* Last received packet number. The first | 106 | /* Last received packet number. The first |
100 | * IEEE80211_NUM_TIDS counters are used with Data | 107 | * IEEE80211_NUM_TIDS counters are used with Data |
101 | * frames and the last counter is used with Robust | 108 | * frames and the last counter is used with Robust |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 053a17c5023a..5e09d354c5a5 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -673,6 +673,8 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) | |||
673 | /* keep last -- depends on hw flags! */ | 673 | /* keep last -- depends on hw flags! */ |
674 | WLAN_CIPHER_SUITE_AES_CMAC, | 674 | WLAN_CIPHER_SUITE_AES_CMAC, |
675 | WLAN_CIPHER_SUITE_BIP_CMAC_256, | 675 | WLAN_CIPHER_SUITE_BIP_CMAC_256, |
676 | WLAN_CIPHER_SUITE_BIP_GMAC_128, | ||
677 | WLAN_CIPHER_SUITE_BIP_GMAC_256, | ||
676 | }; | 678 | }; |
677 | 679 | ||
678 | if (local->hw.flags & IEEE80211_HW_SW_CRYPTO_CONTROL || | 680 | if (local->hw.flags & IEEE80211_HW_SW_CRYPTO_CONTROL || |
@@ -711,7 +713,7 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) | |||
711 | local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); | 713 | local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); |
712 | 714 | ||
713 | if (!have_mfp) | 715 | if (!have_mfp) |
714 | local->hw.wiphy->n_cipher_suites -= 2; | 716 | local->hw.wiphy->n_cipher_suites -= 4; |
715 | 717 | ||
716 | if (!have_wep) { | 718 | if (!have_wep) { |
717 | local->hw.wiphy->cipher_suites += 2; | 719 | local->hw.wiphy->cipher_suites += 2; |
@@ -737,9 +739,11 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) | |||
737 | if (have_wep) | 739 | if (have_wep) |
738 | n_suites += 2; | 740 | n_suites += 2; |
739 | 741 | ||
740 | /* check if we have AES_CMAC, BIP-CMAC-256 */ | 742 | /* check if we have AES_CMAC, BIP-CMAC-256, BIP-GMAC-128, |
743 | * BIP-GMAC-256 | ||
744 | */ | ||
741 | if (have_mfp) | 745 | if (have_mfp) |
742 | n_suites += 2; | 746 | n_suites += 4; |
743 | 747 | ||
744 | suites = kmalloc(sizeof(u32) * n_suites, GFP_KERNEL); | 748 | suites = kmalloc(sizeof(u32) * n_suites, GFP_KERNEL); |
745 | if (!suites) | 749 | if (!suites) |
@@ -759,6 +763,8 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) | |||
759 | if (have_mfp) { | 763 | if (have_mfp) { |
760 | suites[w++] = WLAN_CIPHER_SUITE_AES_CMAC; | 764 | suites[w++] = WLAN_CIPHER_SUITE_AES_CMAC; |
761 | suites[w++] = WLAN_CIPHER_SUITE_BIP_CMAC_256; | 765 | suites[w++] = WLAN_CIPHER_SUITE_BIP_CMAC_256; |
766 | suites[w++] = WLAN_CIPHER_SUITE_BIP_GMAC_128; | ||
767 | suites[w++] = WLAN_CIPHER_SUITE_BIP_GMAC_256; | ||
762 | } | 768 | } |
763 | 769 | ||
764 | for (r = 0; r < local->hw.n_cipher_schemes; r++) | 770 | for (r = 0; r < local->hw.n_cipher_schemes; r++) |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 93ebc9525478..ed38d8302659 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1671,6 +1671,10 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1671 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | 1671 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: |
1672 | result = ieee80211_crypto_aes_cmac_256_decrypt(rx); | 1672 | result = ieee80211_crypto_aes_cmac_256_decrypt(rx); |
1673 | break; | 1673 | break; |
1674 | case WLAN_CIPHER_SUITE_BIP_GMAC_128: | ||
1675 | case WLAN_CIPHER_SUITE_BIP_GMAC_256: | ||
1676 | result = ieee80211_crypto_aes_gmac_decrypt(rx); | ||
1677 | break; | ||
1674 | case WLAN_CIPHER_SUITE_GCMP: | 1678 | case WLAN_CIPHER_SUITE_GCMP: |
1675 | case WLAN_CIPHER_SUITE_GCMP_256: | 1679 | case WLAN_CIPHER_SUITE_GCMP_256: |
1676 | result = ieee80211_crypto_gcmp_decrypt(rx); | 1680 | result = ieee80211_crypto_gcmp_decrypt(rx); |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 909c27be1fdc..88a18ffe2975 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -640,6 +640,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
640 | break; | 640 | break; |
641 | case WLAN_CIPHER_SUITE_AES_CMAC: | 641 | case WLAN_CIPHER_SUITE_AES_CMAC: |
642 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | 642 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: |
643 | case WLAN_CIPHER_SUITE_BIP_GMAC_128: | ||
644 | case WLAN_CIPHER_SUITE_BIP_GMAC_256: | ||
643 | if (!ieee80211_is_mgmt(hdr->frame_control)) | 645 | if (!ieee80211_is_mgmt(hdr->frame_control)) |
644 | tx->key = NULL; | 646 | tx->key = NULL; |
645 | break; | 647 | break; |
@@ -1024,6 +1026,9 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) | |||
1024 | return ieee80211_crypto_aes_cmac_encrypt(tx); | 1026 | return ieee80211_crypto_aes_cmac_encrypt(tx); |
1025 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | 1027 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: |
1026 | return ieee80211_crypto_aes_cmac_256_encrypt(tx); | 1028 | return ieee80211_crypto_aes_cmac_256_encrypt(tx); |
1029 | case WLAN_CIPHER_SUITE_BIP_GMAC_128: | ||
1030 | case WLAN_CIPHER_SUITE_BIP_GMAC_256: | ||
1031 | return ieee80211_crypto_aes_gmac_encrypt(tx); | ||
1027 | case WLAN_CIPHER_SUITE_GCMP: | 1032 | case WLAN_CIPHER_SUITE_GCMP: |
1028 | case WLAN_CIPHER_SUITE_GCMP_256: | 1033 | case WLAN_CIPHER_SUITE_GCMP_256: |
1029 | return ieee80211_crypto_gcmp_encrypt(tx); | 1034 | return ieee80211_crypto_gcmp_encrypt(tx); |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 549af118de9f..75de6fac40d1 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include "tkip.h" | 22 | #include "tkip.h" |
23 | #include "aes_ccm.h" | 23 | #include "aes_ccm.h" |
24 | #include "aes_cmac.h" | 24 | #include "aes_cmac.h" |
25 | #include "aes_gmac.h" | ||
25 | #include "aes_gcm.h" | 26 | #include "aes_gcm.h" |
26 | #include "wpa.h" | 27 | #include "wpa.h" |
27 | 28 | ||
@@ -1099,6 +1100,110 @@ ieee80211_crypto_aes_cmac_256_decrypt(struct ieee80211_rx_data *rx) | |||
1099 | } | 1100 | } |
1100 | 1101 | ||
1101 | ieee80211_tx_result | 1102 | ieee80211_tx_result |
1103 | ieee80211_crypto_aes_gmac_encrypt(struct ieee80211_tx_data *tx) | ||
1104 | { | ||
1105 | struct sk_buff *skb; | ||
1106 | struct ieee80211_tx_info *info; | ||
1107 | struct ieee80211_key *key = tx->key; | ||
1108 | struct ieee80211_mmie_16 *mmie; | ||
1109 | struct ieee80211_hdr *hdr; | ||
1110 | u8 aad[20]; | ||
1111 | u64 pn64; | ||
1112 | u8 nonce[12]; | ||
1113 | |||
1114 | if (WARN_ON(skb_queue_len(&tx->skbs) != 1)) | ||
1115 | return TX_DROP; | ||
1116 | |||
1117 | skb = skb_peek(&tx->skbs); | ||
1118 | |||
1119 | info = IEEE80211_SKB_CB(skb); | ||
1120 | |||
1121 | if (info->control.hw_key) | ||
1122 | return TX_CONTINUE; | ||
1123 | |||
1124 | if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie))) | ||
1125 | return TX_DROP; | ||
1126 | |||
1127 | mmie = (struct ieee80211_mmie_16 *)skb_put(skb, sizeof(*mmie)); | ||
1128 | mmie->element_id = WLAN_EID_MMIE; | ||
1129 | mmie->length = sizeof(*mmie) - 2; | ||
1130 | mmie->key_id = cpu_to_le16(key->conf.keyidx); | ||
1131 | |||
1132 | /* PN = PN + 1 */ | ||
1133 | pn64 = atomic64_inc_return(&key->u.aes_gmac.tx_pn); | ||
1134 | |||
1135 | bip_ipn_set64(mmie->sequence_number, pn64); | ||
1136 | |||
1137 | bip_aad(skb, aad); | ||
1138 | |||
1139 | hdr = (struct ieee80211_hdr *)skb->data; | ||
1140 | memcpy(nonce, hdr->addr2, ETH_ALEN); | ||
1141 | bip_ipn_swap(nonce + ETH_ALEN, mmie->sequence_number); | ||
1142 | |||
1143 | /* MIC = AES-GMAC(IGTK, AAD || Management Frame Body || MMIE, 128) */ | ||
1144 | if (ieee80211_aes_gmac(key->u.aes_gmac.tfm, aad, nonce, | ||
1145 | skb->data + 24, skb->len - 24, mmie->mic) < 0) | ||
1146 | return TX_DROP; | ||
1147 | |||
1148 | return TX_CONTINUE; | ||
1149 | } | ||
1150 | |||
1151 | ieee80211_rx_result | ||
1152 | ieee80211_crypto_aes_gmac_decrypt(struct ieee80211_rx_data *rx) | ||
1153 | { | ||
1154 | struct sk_buff *skb = rx->skb; | ||
1155 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | ||
1156 | struct ieee80211_key *key = rx->key; | ||
1157 | struct ieee80211_mmie_16 *mmie; | ||
1158 | u8 aad[20], mic[16], ipn[6], nonce[12]; | ||
1159 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
1160 | |||
1161 | if (!ieee80211_is_mgmt(hdr->frame_control)) | ||
1162 | return RX_CONTINUE; | ||
1163 | |||
1164 | /* management frames are already linear */ | ||
1165 | |||
1166 | if (skb->len < 24 + sizeof(*mmie)) | ||
1167 | return RX_DROP_UNUSABLE; | ||
1168 | |||
1169 | mmie = (struct ieee80211_mmie_16 *) | ||
1170 | (skb->data + skb->len - sizeof(*mmie)); | ||
1171 | if (mmie->element_id != WLAN_EID_MMIE || | ||
1172 | mmie->length != sizeof(*mmie) - 2) | ||
1173 | return RX_DROP_UNUSABLE; /* Invalid MMIE */ | ||
1174 | |||
1175 | bip_ipn_swap(ipn, mmie->sequence_number); | ||
1176 | |||
1177 | if (memcmp(ipn, key->u.aes_gmac.rx_pn, 6) <= 0) { | ||
1178 | key->u.aes_gmac.replays++; | ||
1179 | return RX_DROP_UNUSABLE; | ||
1180 | } | ||
1181 | |||
1182 | if (!(status->flag & RX_FLAG_DECRYPTED)) { | ||
1183 | /* hardware didn't decrypt/verify MIC */ | ||
1184 | bip_aad(skb, aad); | ||
1185 | |||
1186 | memcpy(nonce, hdr->addr2, ETH_ALEN); | ||
1187 | memcpy(nonce + ETH_ALEN, ipn, 6); | ||
1188 | |||
1189 | if (ieee80211_aes_gmac(key->u.aes_gmac.tfm, aad, nonce, | ||
1190 | skb->data + 24, skb->len - 24, | ||
1191 | mic) < 0 || | ||
1192 | memcmp(mic, mmie->mic, sizeof(mmie->mic)) != 0) { | ||
1193 | key->u.aes_gmac.icverrors++; | ||
1194 | return RX_DROP_UNUSABLE; | ||
1195 | } | ||
1196 | } | ||
1197 | |||
1198 | memcpy(key->u.aes_gmac.rx_pn, ipn, 6); | ||
1199 | |||
1200 | /* Remove MMIE */ | ||
1201 | skb_trim(skb, skb->len - sizeof(*mmie)); | ||
1202 | |||
1203 | return RX_CONTINUE; | ||
1204 | } | ||
1205 | |||
1206 | ieee80211_tx_result | ||
1102 | ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) | 1207 | ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) |
1103 | { | 1208 | { |
1104 | struct sk_buff *skb; | 1209 | struct sk_buff *skb; |
diff --git a/net/mac80211/wpa.h b/net/mac80211/wpa.h index 06b7f167a176..d98011ee8f55 100644 --- a/net/mac80211/wpa.h +++ b/net/mac80211/wpa.h | |||
@@ -39,6 +39,10 @@ ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx); | |||
39 | ieee80211_rx_result | 39 | ieee80211_rx_result |
40 | ieee80211_crypto_aes_cmac_256_decrypt(struct ieee80211_rx_data *rx); | 40 | ieee80211_crypto_aes_cmac_256_decrypt(struct ieee80211_rx_data *rx); |
41 | ieee80211_tx_result | 41 | ieee80211_tx_result |
42 | ieee80211_crypto_aes_gmac_encrypt(struct ieee80211_tx_data *tx); | ||
43 | ieee80211_rx_result | ||
44 | ieee80211_crypto_aes_gmac_decrypt(struct ieee80211_rx_data *rx); | ||
45 | ieee80211_tx_result | ||
42 | ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx); | 46 | ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx); |
43 | ieee80211_rx_result | 47 | ieee80211_rx_result |
44 | ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx); | 48 | ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx); |