aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <jouni@qca.qualcomm.com>2015-01-24 12:52:08 -0500
committerJohannes Berg <johannes.berg@intel.com>2015-01-27 05:09:13 -0500
commit56c52da2d554f081e8fce58ecbcf6a40c605b95b (patch)
tree9c28bdf5c73f2f2a3a6d87880a9422e6d16f9d30
parent2b2ba0db1c820d04d5143452d70012cd44d7b578 (diff)
mac80111: Add BIP-CMAC-256 cipher
This allows mac80211 to configure BIP-CMAC-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/linux/ieee80211.h9
-rw-r--r--net/mac80211/aes_cmac.c34
-rw-r--r--net/mac80211/aes_cmac.h5
-rw-r--r--net/mac80211/cfg.c2
-rw-r--r--net/mac80211/debugfs_key.c4
-rw-r--r--net/mac80211/key.c14
-rw-r--r--net/mac80211/main.c13
-rw-r--r--net/mac80211/rx.c21
-rw-r--r--net/mac80211/tx.c3
-rw-r--r--net/mac80211/wpa.c92
-rw-r--r--net/mac80211/wpa.h4
11 files changed, 180 insertions, 21 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index dbf417bf25bf..b9c7897dc566 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1017,6 +1017,15 @@ struct ieee80211_mmie {
1017 u8 mic[8]; 1017 u8 mic[8];
1018} __packed; 1018} __packed;
1019 1019
1020/* Management MIC information element (IEEE 802.11w) for GMAC and CMAC-256 */
1021struct ieee80211_mmie_16 {
1022 u8 element_id;
1023 u8 length;
1024 __le16 key_id;
1025 u8 sequence_number[6];
1026 u8 mic[16];
1027} __packed;
1028
1020struct ieee80211_vendor_ie { 1029struct ieee80211_vendor_ie {
1021 u8 element_id; 1030 u8 element_id;
1022 u8 len; 1031 u8 len;
diff --git a/net/mac80211/aes_cmac.c b/net/mac80211/aes_cmac.c
index 9b9009f99551..4192806be3d3 100644
--- a/net/mac80211/aes_cmac.c
+++ b/net/mac80211/aes_cmac.c
@@ -18,8 +18,8 @@
18#include "key.h" 18#include "key.h"
19#include "aes_cmac.h" 19#include "aes_cmac.h"
20 20
21#define AES_CMAC_KEY_LEN 16
22#define CMAC_TLEN 8 /* CMAC TLen = 64 bits (8 octets) */ 21#define CMAC_TLEN 8 /* CMAC TLen = 64 bits (8 octets) */
22#define CMAC_TLEN_256 16 /* CMAC TLen = 128 bits (16 octets) */
23#define AAD_LEN 20 23#define AAD_LEN 20
24 24
25 25
@@ -35,9 +35,9 @@ static void gf_mulx(u8 *pad)
35 pad[AES_BLOCK_SIZE - 1] ^= 0x87; 35 pad[AES_BLOCK_SIZE - 1] ^= 0x87;
36} 36}
37 37
38 38static void aes_cmac_vector(struct crypto_cipher *tfm, size_t num_elem,
39static void aes_128_cmac_vector(struct crypto_cipher *tfm, size_t num_elem, 39 const u8 *addr[], const size_t *len, u8 *mac,
40 const u8 *addr[], const size_t *len, u8 *mac) 40 size_t mac_len)
41{ 41{
42 u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE]; 42 u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE];
43 const u8 *pos, *end; 43 const u8 *pos, *end;
@@ -88,7 +88,7 @@ static void aes_128_cmac_vector(struct crypto_cipher *tfm, size_t num_elem,
88 for (i = 0; i < AES_BLOCK_SIZE; i++) 88 for (i = 0; i < AES_BLOCK_SIZE; i++)
89 pad[i] ^= cbc[i]; 89 pad[i] ^= cbc[i];
90 crypto_cipher_encrypt_one(tfm, pad, pad); 90 crypto_cipher_encrypt_one(tfm, pad, pad);
91 memcpy(mac, pad, CMAC_TLEN); 91 memcpy(mac, pad, mac_len);
92} 92}
93 93
94 94
@@ -107,17 +107,35 @@ void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad,
107 addr[2] = zero; 107 addr[2] = zero;
108 len[2] = CMAC_TLEN; 108 len[2] = CMAC_TLEN;
109 109
110 aes_128_cmac_vector(tfm, 3, addr, len, mic); 110 aes_cmac_vector(tfm, 3, addr, len, mic, CMAC_TLEN);
111} 111}
112 112
113void ieee80211_aes_cmac_256(struct crypto_cipher *tfm, const u8 *aad,
114 const u8 *data, size_t data_len, u8 *mic)
115{
116 const u8 *addr[3];
117 size_t len[3];
118 u8 zero[CMAC_TLEN_256];
119
120 memset(zero, 0, CMAC_TLEN_256);
121 addr[0] = aad;
122 len[0] = AAD_LEN;
123 addr[1] = data;
124 len[1] = data_len - CMAC_TLEN_256;
125 addr[2] = zero;
126 len[2] = CMAC_TLEN_256;
127
128 aes_cmac_vector(tfm, 3, addr, len, mic, CMAC_TLEN_256);
129}
113 130
114struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[]) 131struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[],
132 size_t key_len)
115{ 133{
116 struct crypto_cipher *tfm; 134 struct crypto_cipher *tfm;
117 135
118 tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); 136 tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
119 if (!IS_ERR(tfm)) 137 if (!IS_ERR(tfm))
120 crypto_cipher_setkey(tfm, key, AES_CMAC_KEY_LEN); 138 crypto_cipher_setkey(tfm, key, key_len);
121 139
122 return tfm; 140 return tfm;
123} 141}
diff --git a/net/mac80211/aes_cmac.h b/net/mac80211/aes_cmac.h
index 0ce6487af795..3702041f44fd 100644
--- a/net/mac80211/aes_cmac.h
+++ b/net/mac80211/aes_cmac.h
@@ -11,9 +11,12 @@
11 11
12#include <linux/crypto.h> 12#include <linux/crypto.h>
13 13
14struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[]); 14struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[],
15 size_t key_len);
15void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad, 16void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad,
16 const u8 *data, size_t data_len, u8 *mic); 17 const u8 *data, size_t data_len, u8 *mic);
18void ieee80211_aes_cmac_256(struct crypto_cipher *tfm, const u8 *aad,
19 const u8 *data, size_t data_len, u8 *mic);
17void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm); 20void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm);
18 21
19#endif /* AES_CMAC_H */ 22#endif /* AES_CMAC_H */
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index ef84441c119c..b7e528bbecce 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -164,6 +164,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
164 case WLAN_CIPHER_SUITE_CCMP: 164 case WLAN_CIPHER_SUITE_CCMP:
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_GCMP: 168 case WLAN_CIPHER_SUITE_GCMP:
168 case WLAN_CIPHER_SUITE_GCMP_256: 169 case WLAN_CIPHER_SUITE_GCMP_256:
169 break; 170 break;
@@ -362,6 +363,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
362 params.seq_len = 6; 363 params.seq_len = 6;
363 break; 364 break;
364 case WLAN_CIPHER_SUITE_AES_CMAC: 365 case WLAN_CIPHER_SUITE_AES_CMAC:
366 case WLAN_CIPHER_SUITE_BIP_CMAC_256:
365 pn64 = atomic64_read(&key->u.aes_cmac.tx_pn); 367 pn64 = atomic64_read(&key->u.aes_cmac.tx_pn);
366 seq[0] = pn64; 368 seq[0] = pn64;
367 seq[1] = pn64 >> 8; 369 seq[1] = pn64 >> 8;
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c
index 64de07b16092..d1b60eb014a8 100644
--- a/net/mac80211/debugfs_key.c
+++ b/net/mac80211/debugfs_key.c
@@ -101,6 +101,7 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
101 (u8)(pn >> 16), (u8)(pn >> 8), (u8)pn); 101 (u8)(pn >> 16), (u8)(pn >> 8), (u8)pn);
102 break; 102 break;
103 case WLAN_CIPHER_SUITE_AES_CMAC: 103 case WLAN_CIPHER_SUITE_AES_CMAC:
104 case WLAN_CIPHER_SUITE_BIP_CMAC_256:
104 pn = atomic64_read(&key->u.aes_cmac.tx_pn); 105 pn = atomic64_read(&key->u.aes_cmac.tx_pn);
105 len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", 106 len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n",
106 (u8)(pn >> 40), (u8)(pn >> 32), (u8)(pn >> 24), 107 (u8)(pn >> 40), (u8)(pn >> 32), (u8)(pn >> 24),
@@ -153,6 +154,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
153 len = p - buf; 154 len = p - buf;
154 break; 155 break;
155 case WLAN_CIPHER_SUITE_AES_CMAC: 156 case WLAN_CIPHER_SUITE_AES_CMAC:
157 case WLAN_CIPHER_SUITE_BIP_CMAC_256:
156 rpn = key->u.aes_cmac.rx_pn; 158 rpn = key->u.aes_cmac.rx_pn;
157 p += scnprintf(p, sizeof(buf)+buf-p, 159 p += scnprintf(p, sizeof(buf)+buf-p,
158 "%02x%02x%02x%02x%02x%02x\n", 160 "%02x%02x%02x%02x%02x%02x\n",
@@ -191,6 +193,7 @@ static ssize_t key_replays_read(struct file *file, char __user *userbuf,
191 len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays); 193 len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays);
192 break; 194 break;
193 case WLAN_CIPHER_SUITE_AES_CMAC: 195 case WLAN_CIPHER_SUITE_AES_CMAC:
196 case WLAN_CIPHER_SUITE_BIP_CMAC_256:
194 len = scnprintf(buf, sizeof(buf), "%u\n", 197 len = scnprintf(buf, sizeof(buf), "%u\n",
195 key->u.aes_cmac.replays); 198 key->u.aes_cmac.replays);
196 break; 199 break;
@@ -214,6 +217,7 @@ static ssize_t key_icverrors_read(struct file *file, char __user *userbuf,
214 217
215 switch (key->conf.cipher) { 218 switch (key->conf.cipher) {
216 case WLAN_CIPHER_SUITE_AES_CMAC: 219 case WLAN_CIPHER_SUITE_AES_CMAC:
220 case WLAN_CIPHER_SUITE_BIP_CMAC_256:
217 len = scnprintf(buf, sizeof(buf), "%u\n", 221 len = scnprintf(buf, sizeof(buf), "%u\n",
218 key->u.aes_cmac.icverrors); 222 key->u.aes_cmac.icverrors);
219 break; 223 break;
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 83c61085c3f0..7ceea9d9fcd2 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -165,6 +165,7 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
165 case WLAN_CIPHER_SUITE_CCMP: 165 case WLAN_CIPHER_SUITE_CCMP:
166 case WLAN_CIPHER_SUITE_CCMP_256: 166 case WLAN_CIPHER_SUITE_CCMP_256:
167 case WLAN_CIPHER_SUITE_AES_CMAC: 167 case WLAN_CIPHER_SUITE_AES_CMAC:
168 case WLAN_CIPHER_SUITE_BIP_CMAC_256:
168 case WLAN_CIPHER_SUITE_GCMP: 169 case WLAN_CIPHER_SUITE_GCMP:
169 case WLAN_CIPHER_SUITE_GCMP_256: 170 case WLAN_CIPHER_SUITE_GCMP_256:
170 /* all of these we can do in software - if driver can */ 171 /* all of these we can do in software - if driver can */
@@ -417,8 +418,12 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
417 } 418 }
418 break; 419 break;
419 case WLAN_CIPHER_SUITE_AES_CMAC: 420 case WLAN_CIPHER_SUITE_AES_CMAC:
421 case WLAN_CIPHER_SUITE_BIP_CMAC_256:
420 key->conf.iv_len = 0; 422 key->conf.iv_len = 0;
421 key->conf.icv_len = sizeof(struct ieee80211_mmie); 423 if (cipher == WLAN_CIPHER_SUITE_AES_CMAC)
424 key->conf.icv_len = sizeof(struct ieee80211_mmie);
425 else
426 key->conf.icv_len = sizeof(struct ieee80211_mmie_16);
422 if (seq) 427 if (seq)
423 for (j = 0; j < IEEE80211_CMAC_PN_LEN; j++) 428 for (j = 0; j < IEEE80211_CMAC_PN_LEN; j++)
424 key->u.aes_cmac.rx_pn[j] = 429 key->u.aes_cmac.rx_pn[j] =
@@ -428,7 +433,7 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
428 * it does not need to be initialized for every packet. 433 * it does not need to be initialized for every packet.
429 */ 434 */
430 key->u.aes_cmac.tfm = 435 key->u.aes_cmac.tfm =
431 ieee80211_aes_cmac_key_setup(key_data); 436 ieee80211_aes_cmac_key_setup(key_data, key_len);
432 if (IS_ERR(key->u.aes_cmac.tfm)) { 437 if (IS_ERR(key->u.aes_cmac.tfm)) {
433 err = PTR_ERR(key->u.aes_cmac.tfm); 438 err = PTR_ERR(key->u.aes_cmac.tfm);
434 kfree(key); 439 kfree(key);
@@ -481,6 +486,7 @@ static void ieee80211_key_free_common(struct ieee80211_key *key)
481 ieee80211_aes_key_free(key->u.ccmp.tfm); 486 ieee80211_aes_key_free(key->u.ccmp.tfm);
482 break; 487 break;
483 case WLAN_CIPHER_SUITE_AES_CMAC: 488 case WLAN_CIPHER_SUITE_AES_CMAC:
489 case WLAN_CIPHER_SUITE_BIP_CMAC_256:
484 ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); 490 ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
485 break; 491 break;
486 case WLAN_CIPHER_SUITE_GCMP: 492 case WLAN_CIPHER_SUITE_GCMP:
@@ -804,6 +810,7 @@ void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf,
804 seq->ccmp.pn[0] = pn64 >> 40; 810 seq->ccmp.pn[0] = pn64 >> 40;
805 break; 811 break;
806 case WLAN_CIPHER_SUITE_AES_CMAC: 812 case WLAN_CIPHER_SUITE_AES_CMAC:
813 case WLAN_CIPHER_SUITE_BIP_CMAC_256:
807 pn64 = atomic64_read(&key->u.aes_cmac.tx_pn); 814 pn64 = atomic64_read(&key->u.aes_cmac.tx_pn);
808 seq->ccmp.pn[5] = pn64; 815 seq->ccmp.pn[5] = pn64;
809 seq->ccmp.pn[4] = pn64 >> 8; 816 seq->ccmp.pn[4] = pn64 >> 8;
@@ -854,6 +861,7 @@ void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf,
854 memcpy(seq->ccmp.pn, pn, IEEE80211_CCMP_PN_LEN); 861 memcpy(seq->ccmp.pn, pn, IEEE80211_CCMP_PN_LEN);
855 break; 862 break;
856 case WLAN_CIPHER_SUITE_AES_CMAC: 863 case WLAN_CIPHER_SUITE_AES_CMAC:
864 case WLAN_CIPHER_SUITE_BIP_CMAC_256:
857 if (WARN_ON(tid != 0)) 865 if (WARN_ON(tid != 0))
858 return; 866 return;
859 pn = key->u.aes_cmac.rx_pn; 867 pn = key->u.aes_cmac.rx_pn;
@@ -897,6 +905,7 @@ void ieee80211_set_key_tx_seq(struct ieee80211_key_conf *keyconf,
897 atomic64_set(&key->u.ccmp.tx_pn, pn64); 905 atomic64_set(&key->u.ccmp.tx_pn, pn64);
898 break; 906 break;
899 case WLAN_CIPHER_SUITE_AES_CMAC: 907 case WLAN_CIPHER_SUITE_AES_CMAC:
908 case WLAN_CIPHER_SUITE_BIP_CMAC_256:
900 pn64 = (u64)seq->aes_cmac.pn[5] | 909 pn64 = (u64)seq->aes_cmac.pn[5] |
901 ((u64)seq->aes_cmac.pn[4] << 8) | 910 ((u64)seq->aes_cmac.pn[4] << 8) |
902 ((u64)seq->aes_cmac.pn[3] << 16) | 911 ((u64)seq->aes_cmac.pn[3] << 16) |
@@ -948,6 +957,7 @@ void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf,
948 memcpy(pn, seq->ccmp.pn, IEEE80211_CCMP_PN_LEN); 957 memcpy(pn, seq->ccmp.pn, IEEE80211_CCMP_PN_LEN);
949 break; 958 break;
950 case WLAN_CIPHER_SUITE_AES_CMAC: 959 case WLAN_CIPHER_SUITE_AES_CMAC:
960 case WLAN_CIPHER_SUITE_BIP_CMAC_256:
951 if (WARN_ON(tid != 0)) 961 if (WARN_ON(tid != 0))
952 return; 962 return;
953 pn = key->u.aes_cmac.rx_pn; 963 pn = key->u.aes_cmac.rx_pn;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index a5ad2d5bb29b..053a17c5023a 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -671,7 +671,8 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local)
671 WLAN_CIPHER_SUITE_GCMP_256, 671 WLAN_CIPHER_SUITE_GCMP_256,
672 672
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 }; 676 };
676 677
677 if (local->hw.flags & IEEE80211_HW_SW_CRYPTO_CONTROL || 678 if (local->hw.flags & IEEE80211_HW_SW_CRYPTO_CONTROL ||
@@ -710,7 +711,7 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local)
710 local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); 711 local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
711 712
712 if (!have_mfp) 713 if (!have_mfp)
713 local->hw.wiphy->n_cipher_suites--; 714 local->hw.wiphy->n_cipher_suites -= 2;
714 715
715 if (!have_wep) { 716 if (!have_wep) {
716 local->hw.wiphy->cipher_suites += 2; 717 local->hw.wiphy->cipher_suites += 2;
@@ -736,9 +737,9 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local)
736 if (have_wep) 737 if (have_wep)
737 n_suites += 2; 738 n_suites += 2;
738 739
739 /* check if we have AES_CMAC */ 740 /* check if we have AES_CMAC, BIP-CMAC-256 */
740 if (have_mfp) 741 if (have_mfp)
741 n_suites++; 742 n_suites += 2;
742 743
743 suites = kmalloc(sizeof(u32) * n_suites, GFP_KERNEL); 744 suites = kmalloc(sizeof(u32) * n_suites, GFP_KERNEL);
744 if (!suites) 745 if (!suites)
@@ -755,8 +756,10 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local)
755 suites[w++] = WLAN_CIPHER_SUITE_WEP104; 756 suites[w++] = WLAN_CIPHER_SUITE_WEP104;
756 } 757 }
757 758
758 if (have_mfp) 759 if (have_mfp) {
759 suites[w++] = WLAN_CIPHER_SUITE_AES_CMAC; 760 suites[w++] = WLAN_CIPHER_SUITE_AES_CMAC;
761 suites[w++] = WLAN_CIPHER_SUITE_BIP_CMAC_256;
762 }
760 763
761 for (r = 0; r < local->hw.n_cipher_schemes; r++) 764 for (r = 0; r < local->hw.n_cipher_schemes; r++)
762 suites[w++] = cs[r].cipher; 765 suites[w++] = cs[r].cipher;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index e8c6ba5ce70b..93ebc9525478 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -647,6 +647,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
647{ 647{
648 struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data; 648 struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data;
649 struct ieee80211_mmie *mmie; 649 struct ieee80211_mmie *mmie;
650 struct ieee80211_mmie_16 *mmie16;
650 651
651 if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da)) 652 if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da))
652 return -1; 653 return -1;
@@ -656,11 +657,18 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
656 657
657 mmie = (struct ieee80211_mmie *) 658 mmie = (struct ieee80211_mmie *)
658 (skb->data + skb->len - sizeof(*mmie)); 659 (skb->data + skb->len - sizeof(*mmie));
659 if (mmie->element_id != WLAN_EID_MMIE || 660 if (mmie->element_id == WLAN_EID_MMIE &&
660 mmie->length != sizeof(*mmie) - 2) 661 mmie->length == sizeof(*mmie) - 2)
661 return -1; 662 return le16_to_cpu(mmie->key_id);
662 663
663 return le16_to_cpu(mmie->key_id); 664 mmie16 = (struct ieee80211_mmie_16 *)
665 (skb->data + skb->len - sizeof(*mmie16));
666 if (skb->len >= 24 + sizeof(*mmie16) &&
667 mmie16->element_id == WLAN_EID_MMIE &&
668 mmie16->length == sizeof(*mmie16) - 2)
669 return le16_to_cpu(mmie16->key_id);
670
671 return -1;
664} 672}
665 673
666static int iwl80211_get_cs_keyid(const struct ieee80211_cipher_scheme *cs, 674static int iwl80211_get_cs_keyid(const struct ieee80211_cipher_scheme *cs,
@@ -1660,6 +1668,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
1660 case WLAN_CIPHER_SUITE_AES_CMAC: 1668 case WLAN_CIPHER_SUITE_AES_CMAC:
1661 result = ieee80211_crypto_aes_cmac_decrypt(rx); 1669 result = ieee80211_crypto_aes_cmac_decrypt(rx);
1662 break; 1670 break;
1671 case WLAN_CIPHER_SUITE_BIP_CMAC_256:
1672 result = ieee80211_crypto_aes_cmac_256_decrypt(rx);
1673 break;
1663 case WLAN_CIPHER_SUITE_GCMP: 1674 case WLAN_CIPHER_SUITE_GCMP:
1664 case WLAN_CIPHER_SUITE_GCMP_256: 1675 case WLAN_CIPHER_SUITE_GCMP_256:
1665 result = ieee80211_crypto_gcmp_decrypt(rx); 1676 result = ieee80211_crypto_gcmp_decrypt(rx);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index be57e0afd019..909c27be1fdc 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -639,6 +639,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
639 ieee80211_is_mgmt(hdr->frame_control); 639 ieee80211_is_mgmt(hdr->frame_control);
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 if (!ieee80211_is_mgmt(hdr->frame_control)) 643 if (!ieee80211_is_mgmt(hdr->frame_control))
643 tx->key = NULL; 644 tx->key = NULL;
644 break; 645 break;
@@ -1021,6 +1022,8 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
1021 tx, IEEE80211_CCMP_256_MIC_LEN); 1022 tx, IEEE80211_CCMP_256_MIC_LEN);
1022 case WLAN_CIPHER_SUITE_AES_CMAC: 1023 case WLAN_CIPHER_SUITE_AES_CMAC:
1023 return ieee80211_crypto_aes_cmac_encrypt(tx); 1024 return ieee80211_crypto_aes_cmac_encrypt(tx);
1025 case WLAN_CIPHER_SUITE_BIP_CMAC_256:
1026 return ieee80211_crypto_aes_cmac_256_encrypt(tx);
1024 case WLAN_CIPHER_SUITE_GCMP: 1027 case WLAN_CIPHER_SUITE_GCMP:
1025 case WLAN_CIPHER_SUITE_GCMP_256: 1028 case WLAN_CIPHER_SUITE_GCMP_256:
1026 return ieee80211_crypto_gcmp_encrypt(tx); 1029 return ieee80211_crypto_gcmp_encrypt(tx);
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index ae654de9782a..549af118de9f 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -955,6 +955,48 @@ ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx)
955 return TX_CONTINUE; 955 return TX_CONTINUE;
956} 956}
957 957
958ieee80211_tx_result
959ieee80211_crypto_aes_cmac_256_encrypt(struct ieee80211_tx_data *tx)
960{
961 struct sk_buff *skb;
962 struct ieee80211_tx_info *info;
963 struct ieee80211_key *key = tx->key;
964 struct ieee80211_mmie_16 *mmie;
965 u8 aad[20];
966 u64 pn64;
967
968 if (WARN_ON(skb_queue_len(&tx->skbs) != 1))
969 return TX_DROP;
970
971 skb = skb_peek(&tx->skbs);
972
973 info = IEEE80211_SKB_CB(skb);
974
975 if (info->control.hw_key)
976 return TX_CONTINUE;
977
978 if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie)))
979 return TX_DROP;
980
981 mmie = (struct ieee80211_mmie_16 *)skb_put(skb, sizeof(*mmie));
982 mmie->element_id = WLAN_EID_MMIE;
983 mmie->length = sizeof(*mmie) - 2;
984 mmie->key_id = cpu_to_le16(key->conf.keyidx);
985
986 /* PN = PN + 1 */
987 pn64 = atomic64_inc_return(&key->u.aes_cmac.tx_pn);
988
989 bip_ipn_set64(mmie->sequence_number, pn64);
990
991 bip_aad(skb, aad);
992
993 /* MIC = AES-256-CMAC(IGTK, AAD || Management Frame Body || MMIE, 128)
994 */
995 ieee80211_aes_cmac_256(key->u.aes_cmac.tfm, aad,
996 skb->data + 24, skb->len - 24, mmie->mic);
997
998 return TX_CONTINUE;
999}
958 1000
959ieee80211_rx_result 1001ieee80211_rx_result
960ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx) 1002ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx)
@@ -1006,6 +1048,56 @@ ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx)
1006 return RX_CONTINUE; 1048 return RX_CONTINUE;
1007} 1049}
1008 1050
1051ieee80211_rx_result
1052ieee80211_crypto_aes_cmac_256_decrypt(struct ieee80211_rx_data *rx)
1053{
1054 struct sk_buff *skb = rx->skb;
1055 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
1056 struct ieee80211_key *key = rx->key;
1057 struct ieee80211_mmie_16 *mmie;
1058 u8 aad[20], mic[16], ipn[6];
1059 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
1060
1061 if (!ieee80211_is_mgmt(hdr->frame_control))
1062 return RX_CONTINUE;
1063
1064 /* management frames are already linear */
1065
1066 if (skb->len < 24 + sizeof(*mmie))
1067 return RX_DROP_UNUSABLE;
1068
1069 mmie = (struct ieee80211_mmie_16 *)
1070 (skb->data + skb->len - sizeof(*mmie));
1071 if (mmie->element_id != WLAN_EID_MMIE ||
1072 mmie->length != sizeof(*mmie) - 2)
1073 return RX_DROP_UNUSABLE; /* Invalid MMIE */
1074
1075 bip_ipn_swap(ipn, mmie->sequence_number);
1076
1077 if (memcmp(ipn, key->u.aes_cmac.rx_pn, 6) <= 0) {
1078 key->u.aes_cmac.replays++;
1079 return RX_DROP_UNUSABLE;
1080 }
1081
1082 if (!(status->flag & RX_FLAG_DECRYPTED)) {
1083 /* hardware didn't decrypt/verify MIC */
1084 bip_aad(skb, aad);
1085 ieee80211_aes_cmac_256(key->u.aes_cmac.tfm, aad,
1086 skb->data + 24, skb->len - 24, mic);
1087 if (memcmp(mic, mmie->mic, sizeof(mmie->mic)) != 0) {
1088 key->u.aes_cmac.icverrors++;
1089 return RX_DROP_UNUSABLE;
1090 }
1091 }
1092
1093 memcpy(key->u.aes_cmac.rx_pn, ipn, 6);
1094
1095 /* Remove MMIE */
1096 skb_trim(skb, skb->len - sizeof(*mmie));
1097
1098 return RX_CONTINUE;
1099}
1100
1009ieee80211_tx_result 1101ieee80211_tx_result
1010ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) 1102ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx)
1011{ 1103{
diff --git a/net/mac80211/wpa.h b/net/mac80211/wpa.h
index 43e109f27a89..06b7f167a176 100644
--- a/net/mac80211/wpa.h
+++ b/net/mac80211/wpa.h
@@ -32,8 +32,12 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx,
32 32
33ieee80211_tx_result 33ieee80211_tx_result
34ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx); 34ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx);
35ieee80211_tx_result
36ieee80211_crypto_aes_cmac_256_encrypt(struct ieee80211_tx_data *tx);
35ieee80211_rx_result 37ieee80211_rx_result
36ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx); 38ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx);
39ieee80211_rx_result
40ieee80211_crypto_aes_cmac_256_decrypt(struct ieee80211_rx_data *rx);
37ieee80211_tx_result 41ieee80211_tx_result
38ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx); 42ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx);
39ieee80211_rx_result 43ieee80211_rx_result