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 | |
| 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>
| -rw-r--r-- | include/net/mac80211.h | 5 | ||||
| -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 |
13 files changed, 344 insertions, 3 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index ae6638436112..d52914b75331 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
| @@ -4098,6 +4098,8 @@ void ieee80211_aes_cmac_calculate_k1_k2(struct ieee80211_key_conf *keyconf, | |||
| 4098 | * reverse order than in packet) | 4098 | * reverse order than in packet) |
| 4099 | * @aes_cmac: PN data, most significant byte first (big endian, | 4099 | * @aes_cmac: PN data, most significant byte first (big endian, |
| 4100 | * reverse order than in packet) | 4100 | * reverse order than in packet) |
| 4101 | * @aes_gmac: PN data, most significant byte first (big endian, | ||
| 4102 | * reverse order than in packet) | ||
| 4101 | * @gcmp: PN data, most significant byte first (big endian, | 4103 | * @gcmp: PN data, most significant byte first (big endian, |
| 4102 | * reverse order than in packet) | 4104 | * reverse order than in packet) |
| 4103 | */ | 4105 | */ |
| @@ -4115,6 +4117,9 @@ struct ieee80211_key_seq { | |||
| 4115 | } aes_cmac; | 4117 | } aes_cmac; |
| 4116 | struct { | 4118 | struct { |
| 4117 | u8 pn[6]; | 4119 | u8 pn[6]; |
| 4120 | } aes_gmac; | ||
| 4121 | struct { | ||
| 4122 | u8 pn[6]; | ||
| 4118 | } gcmp; | 4123 | } gcmp; |
| 4119 | }; | 4124 | }; |
| 4120 | }; | 4125 | }; |
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); |
