diff options
author | Jouni Malinen <jouni@qca.qualcomm.com> | 2015-01-24 12:52:06 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2015-01-27 05:06:09 -0500 |
commit | 00b9cfa3ff38401bd70c34b250ca13e5ea347b4a (patch) | |
tree | 1c3564bf28a6f4b49140a5e023520a1dc658d5c6 | |
parent | cfcf1682c4ca8f601a4702255958e0b1c9aa12cc (diff) |
mac80111: Add GCMP and GCMP-256 ciphers
This allows mac80211 to configure GCMP and GCMP-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>
[remove a spurious newline]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | include/net/mac80211.h | 15 | ||||
-rw-r--r-- | net/mac80211/Kconfig | 1 | ||||
-rw-r--r-- | net/mac80211/Makefile | 1 | ||||
-rw-r--r-- | net/mac80211/aes_gcm.c | 95 | ||||
-rw-r--r-- | net/mac80211/aes_gcm.h | 22 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 13 | ||||
-rw-r--r-- | net/mac80211/debugfs_key.c | 22 | ||||
-rw-r--r-- | net/mac80211/key.c | 74 | ||||
-rw-r--r-- | net/mac80211/key.h | 11 | ||||
-rw-r--r-- | net/mac80211/main.c | 9 | ||||
-rw-r--r-- | net/mac80211/rx.c | 4 | ||||
-rw-r--r-- | net/mac80211/tx.c | 5 | ||||
-rw-r--r-- | net/mac80211/wpa.c | 224 | ||||
-rw-r--r-- | net/mac80211/wpa.h | 5 |
14 files changed, 492 insertions, 9 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 866073e27ea2..ae6638436112 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -1294,8 +1294,8 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev); | |||
1294 | * @IEEE80211_KEY_FLAG_PAIRWISE: Set by mac80211, this flag indicates | 1294 | * @IEEE80211_KEY_FLAG_PAIRWISE: Set by mac80211, this flag indicates |
1295 | * that the key is pairwise rather then a shared key. | 1295 | * that the key is pairwise rather then a shared key. |
1296 | * @IEEE80211_KEY_FLAG_SW_MGMT_TX: This flag should be set by the driver for a | 1296 | * @IEEE80211_KEY_FLAG_SW_MGMT_TX: This flag should be set by the driver for a |
1297 | * CCMP key if it requires CCMP encryption of management frames (MFP) to | 1297 | * CCMP/GCMP key if it requires CCMP/GCMP encryption of management frames |
1298 | * be done in software. | 1298 | * (MFP) to be done in software. |
1299 | * @IEEE80211_KEY_FLAG_PUT_IV_SPACE: This flag should be set by the driver | 1299 | * @IEEE80211_KEY_FLAG_PUT_IV_SPACE: This flag should be set by the driver |
1300 | * if space should be prepared for the IV, but the IV | 1300 | * if space should be prepared for the IV, but the IV |
1301 | * itself should not be generated. Do not set together with | 1301 | * itself should not be generated. Do not set together with |
@@ -1310,7 +1310,7 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev); | |||
1310 | * RX, if your crypto engine can't deal with TX you can also set the | 1310 | * RX, if your crypto engine can't deal with TX you can also set the |
1311 | * %IEEE80211_KEY_FLAG_SW_MGMT_TX flag to encrypt such frames in SW. | 1311 | * %IEEE80211_KEY_FLAG_SW_MGMT_TX flag to encrypt such frames in SW. |
1312 | * @IEEE80211_KEY_FLAG_GENERATE_IV_MGMT: This flag should be set by the | 1312 | * @IEEE80211_KEY_FLAG_GENERATE_IV_MGMT: This flag should be set by the |
1313 | * driver for a CCMP key to indicate that is requires IV generation | 1313 | * driver for a CCMP/GCMP key to indicate that is requires IV generation |
1314 | * only for managment frames (MFP). | 1314 | * only for managment frames (MFP). |
1315 | * @IEEE80211_KEY_FLAG_RESERVE_TAILROOM: This flag should be set by the | 1315 | * @IEEE80211_KEY_FLAG_RESERVE_TAILROOM: This flag should be set by the |
1316 | * driver for a key to indicate that sufficient tailroom must always | 1316 | * driver for a key to indicate that sufficient tailroom must always |
@@ -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 | * @gcmp: PN data, most significant byte first (big endian, | ||
4102 | * reverse order than in packet) | ||
4101 | */ | 4103 | */ |
4102 | struct ieee80211_key_seq { | 4104 | struct ieee80211_key_seq { |
4103 | union { | 4105 | union { |
@@ -4111,6 +4113,9 @@ struct ieee80211_key_seq { | |||
4111 | struct { | 4113 | struct { |
4112 | u8 pn[6]; | 4114 | u8 pn[6]; |
4113 | } aes_cmac; | 4115 | } aes_cmac; |
4116 | struct { | ||
4117 | u8 pn[6]; | ||
4118 | } gcmp; | ||
4114 | }; | 4119 | }; |
4115 | }; | 4120 | }; |
4116 | 4121 | ||
@@ -4135,7 +4140,7 @@ void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf, | |||
4135 | * ieee80211_get_key_rx_seq - get key RX sequence counter | 4140 | * ieee80211_get_key_rx_seq - get key RX sequence counter |
4136 | * | 4141 | * |
4137 | * @keyconf: the parameter passed with the set key | 4142 | * @keyconf: the parameter passed with the set key |
4138 | * @tid: The TID, or -1 for the management frame value (CCMP only); | 4143 | * @tid: The TID, or -1 for the management frame value (CCMP/GCMP only); |
4139 | * the value on TID 0 is also used for non-QoS frames. For | 4144 | * the value on TID 0 is also used for non-QoS frames. For |
4140 | * CMAC, only TID 0 is valid. | 4145 | * CMAC, only TID 0 is valid. |
4141 | * @seq: buffer to receive the sequence data | 4146 | * @seq: buffer to receive the sequence data |
@@ -4171,7 +4176,7 @@ void ieee80211_set_key_tx_seq(struct ieee80211_key_conf *keyconf, | |||
4171 | * ieee80211_set_key_rx_seq - set key RX sequence counter | 4176 | * ieee80211_set_key_rx_seq - set key RX sequence counter |
4172 | * | 4177 | * |
4173 | * @keyconf: the parameter passed with the set key | 4178 | * @keyconf: the parameter passed with the set key |
4174 | * @tid: The TID, or -1 for the management frame value (CCMP only); | 4179 | * @tid: The TID, or -1 for the management frame value (CCMP/GCMP only); |
4175 | * the value on TID 0 is also used for non-QoS frames. For | 4180 | * the value on TID 0 is also used for non-QoS frames. For |
4176 | * CMAC, only TID 0 is valid. | 4181 | * CMAC, only TID 0 is valid. |
4177 | * @seq: new sequence data | 4182 | * @seq: new sequence data |
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 75cc6801a431..64a012a0c6e5 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
@@ -5,6 +5,7 @@ config MAC80211 | |||
5 | select CRYPTO_ARC4 | 5 | select CRYPTO_ARC4 |
6 | select CRYPTO_AES | 6 | select CRYPTO_AES |
7 | select CRYPTO_CCM | 7 | select CRYPTO_CCM |
8 | select CRYPTO_GCM | ||
8 | select CRC32 | 9 | select CRC32 |
9 | select AVERAGE | 10 | select AVERAGE |
10 | ---help--- | 11 | ---help--- |
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index e53671b1105e..0cbf93618433 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile | |||
@@ -15,6 +15,7 @@ mac80211-y := \ | |||
15 | michael.o \ | 15 | michael.o \ |
16 | tkip.o \ | 16 | tkip.o \ |
17 | aes_ccm.o \ | 17 | aes_ccm.o \ |
18 | aes_gcm.o \ | ||
18 | aes_cmac.o \ | 19 | aes_cmac.o \ |
19 | cfg.o \ | 20 | cfg.o \ |
20 | ethtool.o \ | 21 | ethtool.o \ |
diff --git a/net/mac80211/aes_gcm.c b/net/mac80211/aes_gcm.c new file mode 100644 index 000000000000..c2bf6698d738 --- /dev/null +++ b/net/mac80211/aes_gcm.c | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * Copyright 2014-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 | #include <linux/kernel.h> | ||
10 | #include <linux/types.h> | ||
11 | #include <linux/crypto.h> | ||
12 | #include <linux/err.h> | ||
13 | #include <crypto/aes.h> | ||
14 | |||
15 | #include <net/mac80211.h> | ||
16 | #include "key.h" | ||
17 | #include "aes_gcm.h" | ||
18 | |||
19 | void ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, | ||
20 | u8 *data, size_t data_len, u8 *mic) | ||
21 | { | ||
22 | struct scatterlist assoc, pt, ct[2]; | ||
23 | |||
24 | char aead_req_data[sizeof(struct aead_request) + | ||
25 | crypto_aead_reqsize(tfm)] | ||
26 | __aligned(__alignof__(struct aead_request)); | ||
27 | struct aead_request *aead_req = (void *)aead_req_data; | ||
28 | |||
29 | memset(aead_req, 0, sizeof(aead_req_data)); | ||
30 | |||
31 | sg_init_one(&pt, data, data_len); | ||
32 | sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad)); | ||
33 | sg_init_table(ct, 2); | ||
34 | sg_set_buf(&ct[0], data, data_len); | ||
35 | sg_set_buf(&ct[1], mic, IEEE80211_GCMP_MIC_LEN); | ||
36 | |||
37 | aead_request_set_tfm(aead_req, tfm); | ||
38 | aead_request_set_assoc(aead_req, &assoc, assoc.length); | ||
39 | aead_request_set_crypt(aead_req, &pt, ct, data_len, j_0); | ||
40 | |||
41 | crypto_aead_encrypt(aead_req); | ||
42 | } | ||
43 | |||
44 | int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, | ||
45 | u8 *data, size_t data_len, u8 *mic) | ||
46 | { | ||
47 | struct scatterlist assoc, pt, ct[2]; | ||
48 | char aead_req_data[sizeof(struct aead_request) + | ||
49 | crypto_aead_reqsize(tfm)] | ||
50 | __aligned(__alignof__(struct aead_request)); | ||
51 | struct aead_request *aead_req = (void *)aead_req_data; | ||
52 | |||
53 | if (data_len == 0) | ||
54 | return -EINVAL; | ||
55 | |||
56 | memset(aead_req, 0, sizeof(aead_req_data)); | ||
57 | |||
58 | sg_init_one(&pt, data, data_len); | ||
59 | sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad)); | ||
60 | sg_init_table(ct, 2); | ||
61 | sg_set_buf(&ct[0], data, data_len); | ||
62 | sg_set_buf(&ct[1], mic, IEEE80211_GCMP_MIC_LEN); | ||
63 | |||
64 | aead_request_set_tfm(aead_req, tfm); | ||
65 | aead_request_set_assoc(aead_req, &assoc, assoc.length); | ||
66 | aead_request_set_crypt(aead_req, ct, &pt, | ||
67 | data_len + IEEE80211_GCMP_MIC_LEN, j_0); | ||
68 | |||
69 | return crypto_aead_decrypt(aead_req); | ||
70 | } | ||
71 | |||
72 | struct crypto_aead *ieee80211_aes_gcm_key_setup_encrypt(const u8 key[], | ||
73 | size_t key_len) | ||
74 | { | ||
75 | struct crypto_aead *tfm; | ||
76 | int err; | ||
77 | |||
78 | tfm = crypto_alloc_aead("gcm(aes)", 0, CRYPTO_ALG_ASYNC); | ||
79 | if (IS_ERR(tfm)) | ||
80 | return tfm; | ||
81 | |||
82 | err = crypto_aead_setkey(tfm, key, key_len); | ||
83 | if (!err) | ||
84 | err = crypto_aead_setauthsize(tfm, IEEE80211_GCMP_MIC_LEN); | ||
85 | if (!err) | ||
86 | return tfm; | ||
87 | |||
88 | crypto_free_aead(tfm); | ||
89 | return ERR_PTR(err); | ||
90 | } | ||
91 | |||
92 | void ieee80211_aes_gcm_key_free(struct crypto_aead *tfm) | ||
93 | { | ||
94 | crypto_free_aead(tfm); | ||
95 | } | ||
diff --git a/net/mac80211/aes_gcm.h b/net/mac80211/aes_gcm.h new file mode 100644 index 000000000000..1347fda6b76a --- /dev/null +++ b/net/mac80211/aes_gcm.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * Copyright 2014-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_GCM_H | ||
10 | #define AES_GCM_H | ||
11 | |||
12 | #include <linux/crypto.h> | ||
13 | |||
14 | void ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, | ||
15 | u8 *data, size_t data_len, u8 *mic); | ||
16 | int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, | ||
17 | u8 *data, size_t data_len, u8 *mic); | ||
18 | struct crypto_aead *ieee80211_aes_gcm_key_setup_encrypt(const u8 key[], | ||
19 | size_t key_len); | ||
20 | void ieee80211_aes_gcm_key_free(struct crypto_aead *tfm); | ||
21 | |||
22 | #endif /* AES_GCM_H */ | ||
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index a777114d663b..1c1d061cff56 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_AES_CMAC: | 165 | case WLAN_CIPHER_SUITE_AES_CMAC: |
166 | case WLAN_CIPHER_SUITE_GCMP: | 166 | case WLAN_CIPHER_SUITE_GCMP: |
167 | case WLAN_CIPHER_SUITE_GCMP_256: | ||
167 | break; | 168 | break; |
168 | default: | 169 | default: |
169 | cs = ieee80211_cs_get(local, params->cipher, sdata->vif.type); | 170 | cs = ieee80211_cs_get(local, params->cipher, sdata->vif.type); |
@@ -369,6 +370,18 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
369 | params.seq = seq; | 370 | params.seq = seq; |
370 | params.seq_len = 6; | 371 | params.seq_len = 6; |
371 | break; | 372 | break; |
373 | case WLAN_CIPHER_SUITE_GCMP: | ||
374 | case WLAN_CIPHER_SUITE_GCMP_256: | ||
375 | pn64 = atomic64_read(&key->u.gcmp.tx_pn); | ||
376 | seq[0] = pn64; | ||
377 | seq[1] = pn64 >> 8; | ||
378 | seq[2] = pn64 >> 16; | ||
379 | seq[3] = pn64 >> 24; | ||
380 | seq[4] = pn64 >> 32; | ||
381 | seq[5] = pn64 >> 40; | ||
382 | params.seq = seq; | ||
383 | params.seq_len = 6; | ||
384 | break; | ||
372 | } | 385 | } |
373 | 386 | ||
374 | params.key = key->conf.key; | 387 | params.key = key->conf.key; |
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 5523b94c7c90..0e223e602296 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c | |||
@@ -105,6 +105,13 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf, | |||
105 | (u8)(pn >> 40), (u8)(pn >> 32), (u8)(pn >> 24), | 105 | (u8)(pn >> 40), (u8)(pn >> 32), (u8)(pn >> 24), |
106 | (u8)(pn >> 16), (u8)(pn >> 8), (u8)pn); | 106 | (u8)(pn >> 16), (u8)(pn >> 8), (u8)pn); |
107 | break; | 107 | break; |
108 | case WLAN_CIPHER_SUITE_GCMP: | ||
109 | case WLAN_CIPHER_SUITE_GCMP_256: | ||
110 | pn = atomic64_read(&key->u.gcmp.tx_pn); | ||
111 | len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", | ||
112 | (u8)(pn >> 40), (u8)(pn >> 32), (u8)(pn >> 24), | ||
113 | (u8)(pn >> 16), (u8)(pn >> 8), (u8)pn); | ||
114 | break; | ||
108 | default: | 115 | default: |
109 | return 0; | 116 | return 0; |
110 | } | 117 | } |
@@ -151,6 +158,17 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, | |||
151 | rpn[3], rpn[4], rpn[5]); | 158 | rpn[3], rpn[4], rpn[5]); |
152 | len = p - buf; | 159 | len = p - buf; |
153 | break; | 160 | break; |
161 | case WLAN_CIPHER_SUITE_GCMP: | ||
162 | case WLAN_CIPHER_SUITE_GCMP_256: | ||
163 | for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) { | ||
164 | rpn = key->u.gcmp.rx_pn[i]; | ||
165 | p += scnprintf(p, sizeof(buf)+buf-p, | ||
166 | "%02x%02x%02x%02x%02x%02x\n", | ||
167 | rpn[0], rpn[1], rpn[2], | ||
168 | rpn[3], rpn[4], rpn[5]); | ||
169 | } | ||
170 | len = p - buf; | ||
171 | break; | ||
154 | default: | 172 | default: |
155 | return 0; | 173 | return 0; |
156 | } | 174 | } |
@@ -173,6 +191,10 @@ static ssize_t key_replays_read(struct file *file, char __user *userbuf, | |||
173 | len = scnprintf(buf, sizeof(buf), "%u\n", | 191 | len = scnprintf(buf, sizeof(buf), "%u\n", |
174 | key->u.aes_cmac.replays); | 192 | key->u.aes_cmac.replays); |
175 | break; | 193 | break; |
194 | case WLAN_CIPHER_SUITE_GCMP: | ||
195 | case WLAN_CIPHER_SUITE_GCMP_256: | ||
196 | len = scnprintf(buf, sizeof(buf), "%u\n", key->u.gcmp.replays); | ||
197 | break; | ||
176 | default: | 198 | default: |
177 | return 0; | 199 | return 0; |
178 | } | 200 | } |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 5167c53aa15f..cbee2f5180ce 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_gcm.h" | ||
27 | 28 | ||
28 | 29 | ||
29 | /** | 30 | /** |
@@ -163,6 +164,8 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
163 | case WLAN_CIPHER_SUITE_TKIP: | 164 | case WLAN_CIPHER_SUITE_TKIP: |
164 | case WLAN_CIPHER_SUITE_CCMP: | 165 | case WLAN_CIPHER_SUITE_CCMP: |
165 | case WLAN_CIPHER_SUITE_AES_CMAC: | 166 | case WLAN_CIPHER_SUITE_AES_CMAC: |
167 | case WLAN_CIPHER_SUITE_GCMP: | ||
168 | case WLAN_CIPHER_SUITE_GCMP_256: | ||
166 | /* all of these we can do in software - if driver can */ | 169 | /* all of these we can do in software - if driver can */ |
167 | if (ret == 1) | 170 | if (ret == 1) |
168 | return 0; | 171 | return 0; |
@@ -412,6 +415,25 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
412 | return ERR_PTR(err); | 415 | return ERR_PTR(err); |
413 | } | 416 | } |
414 | break; | 417 | break; |
418 | case WLAN_CIPHER_SUITE_GCMP: | ||
419 | case WLAN_CIPHER_SUITE_GCMP_256: | ||
420 | key->conf.iv_len = IEEE80211_GCMP_HDR_LEN; | ||
421 | key->conf.icv_len = IEEE80211_GCMP_MIC_LEN; | ||
422 | for (i = 0; seq && i < IEEE80211_NUM_TIDS + 1; i++) | ||
423 | for (j = 0; j < IEEE80211_GCMP_PN_LEN; j++) | ||
424 | key->u.gcmp.rx_pn[i][j] = | ||
425 | seq[IEEE80211_GCMP_PN_LEN - j - 1]; | ||
426 | /* Initialize AES key state here as an optimization so that | ||
427 | * it does not need to be initialized for every packet. | ||
428 | */ | ||
429 | key->u.gcmp.tfm = ieee80211_aes_gcm_key_setup_encrypt(key_data, | ||
430 | key_len); | ||
431 | if (IS_ERR(key->u.gcmp.tfm)) { | ||
432 | err = PTR_ERR(key->u.gcmp.tfm); | ||
433 | kfree(key); | ||
434 | return ERR_PTR(err); | ||
435 | } | ||
436 | break; | ||
415 | default: | 437 | default: |
416 | if (cs) { | 438 | if (cs) { |
417 | size_t len = (seq_len > MAX_PN_LEN) ? | 439 | size_t len = (seq_len > MAX_PN_LEN) ? |
@@ -433,10 +455,18 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
433 | 455 | ||
434 | static void ieee80211_key_free_common(struct ieee80211_key *key) | 456 | static void ieee80211_key_free_common(struct ieee80211_key *key) |
435 | { | 457 | { |
436 | if (key->conf.cipher == WLAN_CIPHER_SUITE_CCMP) | 458 | switch (key->conf.cipher) { |
459 | case WLAN_CIPHER_SUITE_CCMP: | ||
437 | ieee80211_aes_key_free(key->u.ccmp.tfm); | 460 | ieee80211_aes_key_free(key->u.ccmp.tfm); |
438 | if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC) | 461 | break; |
462 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
439 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); | 463 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); |
464 | break; | ||
465 | case WLAN_CIPHER_SUITE_GCMP: | ||
466 | case WLAN_CIPHER_SUITE_GCMP_256: | ||
467 | ieee80211_aes_gcm_key_free(key->u.gcmp.tfm); | ||
468 | break; | ||
469 | } | ||
440 | kzfree(key); | 470 | kzfree(key); |
441 | } | 471 | } |
442 | 472 | ||
@@ -760,6 +790,16 @@ void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf, | |||
760 | seq->ccmp.pn[1] = pn64 >> 32; | 790 | seq->ccmp.pn[1] = pn64 >> 32; |
761 | seq->ccmp.pn[0] = pn64 >> 40; | 791 | seq->ccmp.pn[0] = pn64 >> 40; |
762 | break; | 792 | break; |
793 | case WLAN_CIPHER_SUITE_GCMP: | ||
794 | case WLAN_CIPHER_SUITE_GCMP_256: | ||
795 | pn64 = atomic64_read(&key->u.gcmp.tx_pn); | ||
796 | seq->gcmp.pn[5] = pn64; | ||
797 | seq->gcmp.pn[4] = pn64 >> 8; | ||
798 | seq->gcmp.pn[3] = pn64 >> 16; | ||
799 | seq->gcmp.pn[2] = pn64 >> 24; | ||
800 | seq->gcmp.pn[1] = pn64 >> 32; | ||
801 | seq->gcmp.pn[0] = pn64 >> 40; | ||
802 | break; | ||
763 | default: | 803 | default: |
764 | WARN_ON(1); | 804 | WARN_ON(1); |
765 | } | 805 | } |
@@ -796,6 +836,16 @@ void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf, | |||
796 | pn = key->u.aes_cmac.rx_pn; | 836 | pn = key->u.aes_cmac.rx_pn; |
797 | memcpy(seq->aes_cmac.pn, pn, IEEE80211_CMAC_PN_LEN); | 837 | memcpy(seq->aes_cmac.pn, pn, IEEE80211_CMAC_PN_LEN); |
798 | break; | 838 | break; |
839 | case WLAN_CIPHER_SUITE_GCMP: | ||
840 | case WLAN_CIPHER_SUITE_GCMP_256: | ||
841 | if (WARN_ON(tid < -1 || tid >= IEEE80211_NUM_TIDS)) | ||
842 | return; | ||
843 | if (tid < 0) | ||
844 | pn = key->u.gcmp.rx_pn[IEEE80211_NUM_TIDS]; | ||
845 | else | ||
846 | pn = key->u.gcmp.rx_pn[tid]; | ||
847 | memcpy(seq->gcmp.pn, pn, IEEE80211_GCMP_PN_LEN); | ||
848 | break; | ||
799 | } | 849 | } |
800 | } | 850 | } |
801 | EXPORT_SYMBOL(ieee80211_get_key_rx_seq); | 851 | EXPORT_SYMBOL(ieee80211_get_key_rx_seq); |
@@ -831,6 +881,16 @@ void ieee80211_set_key_tx_seq(struct ieee80211_key_conf *keyconf, | |||
831 | ((u64)seq->aes_cmac.pn[0] << 40); | 881 | ((u64)seq->aes_cmac.pn[0] << 40); |
832 | atomic64_set(&key->u.aes_cmac.tx_pn, pn64); | 882 | atomic64_set(&key->u.aes_cmac.tx_pn, pn64); |
833 | break; | 883 | break; |
884 | case WLAN_CIPHER_SUITE_GCMP: | ||
885 | case WLAN_CIPHER_SUITE_GCMP_256: | ||
886 | pn64 = (u64)seq->gcmp.pn[5] | | ||
887 | ((u64)seq->gcmp.pn[4] << 8) | | ||
888 | ((u64)seq->gcmp.pn[3] << 16) | | ||
889 | ((u64)seq->gcmp.pn[2] << 24) | | ||
890 | ((u64)seq->gcmp.pn[1] << 32) | | ||
891 | ((u64)seq->gcmp.pn[0] << 40); | ||
892 | atomic64_set(&key->u.gcmp.tx_pn, pn64); | ||
893 | break; | ||
834 | default: | 894 | default: |
835 | WARN_ON(1); | 895 | WARN_ON(1); |
836 | break; | 896 | break; |
@@ -868,6 +928,16 @@ void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf, | |||
868 | pn = key->u.aes_cmac.rx_pn; | 928 | pn = key->u.aes_cmac.rx_pn; |
869 | memcpy(pn, seq->aes_cmac.pn, IEEE80211_CMAC_PN_LEN); | 929 | memcpy(pn, seq->aes_cmac.pn, IEEE80211_CMAC_PN_LEN); |
870 | break; | 930 | break; |
931 | case WLAN_CIPHER_SUITE_GCMP: | ||
932 | case WLAN_CIPHER_SUITE_GCMP_256: | ||
933 | if (WARN_ON(tid < -1 || tid >= IEEE80211_NUM_TIDS)) | ||
934 | return; | ||
935 | if (tid < 0) | ||
936 | pn = key->u.gcmp.rx_pn[IEEE80211_NUM_TIDS]; | ||
937 | else | ||
938 | pn = key->u.gcmp.rx_pn[tid]; | ||
939 | memcpy(pn, seq->gcmp.pn, IEEE80211_GCMP_PN_LEN); | ||
940 | break; | ||
871 | default: | 941 | default: |
872 | WARN_ON(1); | 942 | WARN_ON(1); |
873 | break; | 943 | break; |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 19db68663d75..27580da851c8 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -95,6 +95,17 @@ struct ieee80211_key { | |||
95 | u32 icverrors; /* dot11RSNAStatsCMACICVErrors */ | 95 | u32 icverrors; /* dot11RSNAStatsCMACICVErrors */ |
96 | } aes_cmac; | 96 | } aes_cmac; |
97 | struct { | 97 | struct { |
98 | atomic64_t tx_pn; | ||
99 | /* Last received packet number. The first | ||
100 | * IEEE80211_NUM_TIDS counters are used with Data | ||
101 | * frames and the last counter is used with Robust | ||
102 | * Management frames. | ||
103 | */ | ||
104 | u8 rx_pn[IEEE80211_NUM_TIDS + 1][IEEE80211_GCMP_PN_LEN]; | ||
105 | struct crypto_aead *tfm; | ||
106 | u32 replays; /* dot11RSNAStatsGCMPReplays */ | ||
107 | } gcmp; | ||
108 | struct { | ||
98 | /* generic cipher scheme */ | 109 | /* generic cipher scheme */ |
99 | u8 rx_pn[IEEE80211_NUM_TIDS + 1][MAX_PN_LEN]; | 110 | u8 rx_pn[IEEE80211_NUM_TIDS + 1][MAX_PN_LEN]; |
100 | } gen; | 111 | } gen; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index ea6b82ac4f0b..7223b4e16752 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -666,6 +666,8 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) | |||
666 | WLAN_CIPHER_SUITE_WEP104, | 666 | WLAN_CIPHER_SUITE_WEP104, |
667 | WLAN_CIPHER_SUITE_TKIP, | 667 | WLAN_CIPHER_SUITE_TKIP, |
668 | WLAN_CIPHER_SUITE_CCMP, | 668 | WLAN_CIPHER_SUITE_CCMP, |
669 | WLAN_CIPHER_SUITE_GCMP, | ||
670 | WLAN_CIPHER_SUITE_GCMP_256, | ||
669 | 671 | ||
670 | /* keep last -- depends on hw flags! */ | 672 | /* keep last -- depends on hw flags! */ |
671 | WLAN_CIPHER_SUITE_AES_CMAC | 673 | WLAN_CIPHER_SUITE_AES_CMAC |
@@ -724,9 +726,10 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) | |||
724 | /* Driver specifies cipher schemes only (but not cipher suites | 726 | /* Driver specifies cipher schemes only (but not cipher suites |
725 | * including the schemes) | 727 | * including the schemes) |
726 | * | 728 | * |
727 | * We start counting ciphers defined by schemes, TKIP and CCMP | 729 | * We start counting ciphers defined by schemes, TKIP, CCMP, |
730 | * GCMP, and GCMP-256 | ||
728 | */ | 731 | */ |
729 | n_suites = local->hw.n_cipher_schemes + 2; | 732 | n_suites = local->hw.n_cipher_schemes + 4; |
730 | 733 | ||
731 | /* check if we have WEP40 and WEP104 */ | 734 | /* check if we have WEP40 and WEP104 */ |
732 | if (have_wep) | 735 | if (have_wep) |
@@ -742,6 +745,8 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) | |||
742 | 745 | ||
743 | suites[w++] = WLAN_CIPHER_SUITE_CCMP; | 746 | suites[w++] = WLAN_CIPHER_SUITE_CCMP; |
744 | suites[w++] = WLAN_CIPHER_SUITE_TKIP; | 747 | suites[w++] = WLAN_CIPHER_SUITE_TKIP; |
748 | suites[w++] = WLAN_CIPHER_SUITE_GCMP; | ||
749 | suites[w++] = WLAN_CIPHER_SUITE_GCMP_256; | ||
745 | 750 | ||
746 | if (have_wep) { | 751 | if (have_wep) { |
747 | suites[w++] = WLAN_CIPHER_SUITE_WEP40; | 752 | suites[w++] = WLAN_CIPHER_SUITE_WEP40; |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index ed516ae80a3b..a11d2518c365 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1655,6 +1655,10 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1655 | case WLAN_CIPHER_SUITE_AES_CMAC: | 1655 | case WLAN_CIPHER_SUITE_AES_CMAC: |
1656 | result = ieee80211_crypto_aes_cmac_decrypt(rx); | 1656 | result = ieee80211_crypto_aes_cmac_decrypt(rx); |
1657 | break; | 1657 | break; |
1658 | case WLAN_CIPHER_SUITE_GCMP: | ||
1659 | case WLAN_CIPHER_SUITE_GCMP_256: | ||
1660 | result = ieee80211_crypto_gcmp_decrypt(rx); | ||
1661 | break; | ||
1658 | default: | 1662 | default: |
1659 | result = ieee80211_crypto_hw_decrypt(rx); | 1663 | result = ieee80211_crypto_hw_decrypt(rx); |
1660 | } | 1664 | } |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 02ed6f60629a..e4c6fbc4bf7a 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -626,6 +626,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
626 | tx->key = NULL; | 626 | tx->key = NULL; |
627 | break; | 627 | break; |
628 | case WLAN_CIPHER_SUITE_CCMP: | 628 | case WLAN_CIPHER_SUITE_CCMP: |
629 | case WLAN_CIPHER_SUITE_GCMP: | ||
630 | case WLAN_CIPHER_SUITE_GCMP_256: | ||
629 | if (!ieee80211_is_data_present(hdr->frame_control) && | 631 | if (!ieee80211_is_data_present(hdr->frame_control) && |
630 | !ieee80211_use_mfp(hdr->frame_control, tx->sta, | 632 | !ieee80211_use_mfp(hdr->frame_control, tx->sta, |
631 | tx->skb)) | 633 | tx->skb)) |
@@ -1014,6 +1016,9 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) | |||
1014 | return ieee80211_crypto_ccmp_encrypt(tx); | 1016 | return ieee80211_crypto_ccmp_encrypt(tx); |
1015 | case WLAN_CIPHER_SUITE_AES_CMAC: | 1017 | case WLAN_CIPHER_SUITE_AES_CMAC: |
1016 | return ieee80211_crypto_aes_cmac_encrypt(tx); | 1018 | return ieee80211_crypto_aes_cmac_encrypt(tx); |
1019 | case WLAN_CIPHER_SUITE_GCMP: | ||
1020 | case WLAN_CIPHER_SUITE_GCMP_256: | ||
1021 | return ieee80211_crypto_gcmp_encrypt(tx); | ||
1017 | default: | 1022 | default: |
1018 | return ieee80211_crypto_hw_encrypt(tx); | 1023 | return ieee80211_crypto_hw_encrypt(tx); |
1019 | } | 1024 | } |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 12398fde02e8..96b65c240109 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_gcm.h" | ||
25 | #include "wpa.h" | 26 | #include "wpa.h" |
26 | 27 | ||
27 | ieee80211_tx_result | 28 | ieee80211_tx_result |
@@ -546,6 +547,229 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) | |||
546 | return RX_CONTINUE; | 547 | return RX_CONTINUE; |
547 | } | 548 | } |
548 | 549 | ||
550 | static void gcmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *j_0, u8 *aad) | ||
551 | { | ||
552 | __le16 mask_fc; | ||
553 | u8 qos_tid; | ||
554 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
555 | |||
556 | memcpy(j_0, hdr->addr2, ETH_ALEN); | ||
557 | memcpy(&j_0[ETH_ALEN], pn, IEEE80211_GCMP_PN_LEN); | ||
558 | j_0[13] = 0; | ||
559 | j_0[14] = 0; | ||
560 | j_0[AES_BLOCK_SIZE - 1] = 0x01; | ||
561 | |||
562 | /* AAD (extra authenticate-only data) / masked 802.11 header | ||
563 | * FC | A1 | A2 | A3 | SC | [A4] | [QC] | ||
564 | */ | ||
565 | put_unaligned_be16(ieee80211_hdrlen(hdr->frame_control) - 2, &aad[0]); | ||
566 | /* Mask FC: zero subtype b4 b5 b6 (if not mgmt) | ||
567 | * Retry, PwrMgt, MoreData; set Protected | ||
568 | */ | ||
569 | mask_fc = hdr->frame_control; | ||
570 | mask_fc &= ~cpu_to_le16(IEEE80211_FCTL_RETRY | | ||
571 | IEEE80211_FCTL_PM | IEEE80211_FCTL_MOREDATA); | ||
572 | if (!ieee80211_is_mgmt(hdr->frame_control)) | ||
573 | mask_fc &= ~cpu_to_le16(0x0070); | ||
574 | mask_fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | ||
575 | |||
576 | put_unaligned(mask_fc, (__le16 *)&aad[2]); | ||
577 | memcpy(&aad[4], &hdr->addr1, 3 * ETH_ALEN); | ||
578 | |||
579 | /* Mask Seq#, leave Frag# */ | ||
580 | aad[22] = *((u8 *)&hdr->seq_ctrl) & 0x0f; | ||
581 | aad[23] = 0; | ||
582 | |||
583 | if (ieee80211_is_data_qos(hdr->frame_control)) | ||
584 | qos_tid = *ieee80211_get_qos_ctl(hdr) & | ||
585 | IEEE80211_QOS_CTL_TID_MASK; | ||
586 | else | ||
587 | qos_tid = 0; | ||
588 | |||
589 | if (ieee80211_has_a4(hdr->frame_control)) { | ||
590 | memcpy(&aad[24], hdr->addr4, ETH_ALEN); | ||
591 | aad[30] = qos_tid; | ||
592 | aad[31] = 0; | ||
593 | } else { | ||
594 | memset(&aad[24], 0, ETH_ALEN + IEEE80211_QOS_CTL_LEN); | ||
595 | aad[24] = qos_tid; | ||
596 | } | ||
597 | } | ||
598 | |||
599 | static inline void gcmp_pn2hdr(u8 *hdr, const u8 *pn, int key_id) | ||
600 | { | ||
601 | hdr[0] = pn[5]; | ||
602 | hdr[1] = pn[4]; | ||
603 | hdr[2] = 0; | ||
604 | hdr[3] = 0x20 | (key_id << 6); | ||
605 | hdr[4] = pn[3]; | ||
606 | hdr[5] = pn[2]; | ||
607 | hdr[6] = pn[1]; | ||
608 | hdr[7] = pn[0]; | ||
609 | } | ||
610 | |||
611 | static inline void gcmp_hdr2pn(u8 *pn, const u8 *hdr) | ||
612 | { | ||
613 | pn[0] = hdr[7]; | ||
614 | pn[1] = hdr[6]; | ||
615 | pn[2] = hdr[5]; | ||
616 | pn[3] = hdr[4]; | ||
617 | pn[4] = hdr[1]; | ||
618 | pn[5] = hdr[0]; | ||
619 | } | ||
620 | |||
621 | static int gcmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | ||
622 | { | ||
623 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
624 | struct ieee80211_key *key = tx->key; | ||
625 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
626 | int hdrlen, len, tail; | ||
627 | u8 *pos; | ||
628 | u8 pn[6]; | ||
629 | u64 pn64; | ||
630 | u8 aad[2 * AES_BLOCK_SIZE]; | ||
631 | u8 j_0[AES_BLOCK_SIZE]; | ||
632 | |||
633 | if (info->control.hw_key && | ||
634 | !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) && | ||
635 | !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) && | ||
636 | !((info->control.hw_key->flags & | ||
637 | IEEE80211_KEY_FLAG_GENERATE_IV_MGMT) && | ||
638 | ieee80211_is_mgmt(hdr->frame_control))) { | ||
639 | /* hwaccel has no need for preallocated room for GCMP | ||
640 | * header or MIC fields | ||
641 | */ | ||
642 | return 0; | ||
643 | } | ||
644 | |||
645 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
646 | len = skb->len - hdrlen; | ||
647 | |||
648 | if (info->control.hw_key) | ||
649 | tail = 0; | ||
650 | else | ||
651 | tail = IEEE80211_GCMP_MIC_LEN; | ||
652 | |||
653 | if (WARN_ON(skb_tailroom(skb) < tail || | ||
654 | skb_headroom(skb) < IEEE80211_GCMP_HDR_LEN)) | ||
655 | return -1; | ||
656 | |||
657 | pos = skb_push(skb, IEEE80211_GCMP_HDR_LEN); | ||
658 | memmove(pos, pos + IEEE80211_GCMP_HDR_LEN, hdrlen); | ||
659 | skb_set_network_header(skb, skb_network_offset(skb) + | ||
660 | IEEE80211_GCMP_HDR_LEN); | ||
661 | |||
662 | /* the HW only needs room for the IV, but not the actual IV */ | ||
663 | if (info->control.hw_key && | ||
664 | (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) | ||
665 | return 0; | ||
666 | |||
667 | hdr = (struct ieee80211_hdr *)pos; | ||
668 | pos += hdrlen; | ||
669 | |||
670 | pn64 = atomic64_inc_return(&key->u.gcmp.tx_pn); | ||
671 | |||
672 | pn[5] = pn64; | ||
673 | pn[4] = pn64 >> 8; | ||
674 | pn[3] = pn64 >> 16; | ||
675 | pn[2] = pn64 >> 24; | ||
676 | pn[1] = pn64 >> 32; | ||
677 | pn[0] = pn64 >> 40; | ||
678 | |||
679 | gcmp_pn2hdr(pos, pn, key->conf.keyidx); | ||
680 | |||
681 | /* hwaccel - with software GCMP header */ | ||
682 | if (info->control.hw_key) | ||
683 | return 0; | ||
684 | |||
685 | pos += IEEE80211_GCMP_HDR_LEN; | ||
686 | gcmp_special_blocks(skb, pn, j_0, aad); | ||
687 | ieee80211_aes_gcm_encrypt(key->u.gcmp.tfm, j_0, aad, pos, len, | ||
688 | skb_put(skb, IEEE80211_GCMP_MIC_LEN)); | ||
689 | |||
690 | return 0; | ||
691 | } | ||
692 | |||
693 | ieee80211_tx_result | ||
694 | ieee80211_crypto_gcmp_encrypt(struct ieee80211_tx_data *tx) | ||
695 | { | ||
696 | struct sk_buff *skb; | ||
697 | |||
698 | ieee80211_tx_set_protected(tx); | ||
699 | |||
700 | skb_queue_walk(&tx->skbs, skb) { | ||
701 | if (gcmp_encrypt_skb(tx, skb) < 0) | ||
702 | return TX_DROP; | ||
703 | } | ||
704 | |||
705 | return TX_CONTINUE; | ||
706 | } | ||
707 | |||
708 | ieee80211_rx_result | ||
709 | ieee80211_crypto_gcmp_decrypt(struct ieee80211_rx_data *rx) | ||
710 | { | ||
711 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | ||
712 | int hdrlen; | ||
713 | struct ieee80211_key *key = rx->key; | ||
714 | struct sk_buff *skb = rx->skb; | ||
715 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | ||
716 | u8 pn[IEEE80211_GCMP_PN_LEN]; | ||
717 | int data_len; | ||
718 | int queue; | ||
719 | |||
720 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
721 | |||
722 | if (!ieee80211_is_data(hdr->frame_control) && | ||
723 | !ieee80211_is_robust_mgmt_frame(skb)) | ||
724 | return RX_CONTINUE; | ||
725 | |||
726 | data_len = skb->len - hdrlen - IEEE80211_GCMP_HDR_LEN - | ||
727 | IEEE80211_GCMP_MIC_LEN; | ||
728 | if (!rx->sta || data_len < 0) | ||
729 | return RX_DROP_UNUSABLE; | ||
730 | |||
731 | if (status->flag & RX_FLAG_DECRYPTED) { | ||
732 | if (!pskb_may_pull(rx->skb, hdrlen + IEEE80211_GCMP_HDR_LEN)) | ||
733 | return RX_DROP_UNUSABLE; | ||
734 | } else { | ||
735 | if (skb_linearize(rx->skb)) | ||
736 | return RX_DROP_UNUSABLE; | ||
737 | } | ||
738 | |||
739 | gcmp_hdr2pn(pn, skb->data + hdrlen); | ||
740 | |||
741 | queue = rx->security_idx; | ||
742 | |||
743 | if (memcmp(pn, key->u.gcmp.rx_pn[queue], IEEE80211_GCMP_PN_LEN) <= 0) { | ||
744 | key->u.gcmp.replays++; | ||
745 | return RX_DROP_UNUSABLE; | ||
746 | } | ||
747 | |||
748 | if (!(status->flag & RX_FLAG_DECRYPTED)) { | ||
749 | u8 aad[2 * AES_BLOCK_SIZE]; | ||
750 | u8 j_0[AES_BLOCK_SIZE]; | ||
751 | /* hardware didn't decrypt/verify MIC */ | ||
752 | gcmp_special_blocks(skb, pn, j_0, aad); | ||
753 | |||
754 | if (ieee80211_aes_gcm_decrypt( | ||
755 | key->u.gcmp.tfm, j_0, aad, | ||
756 | skb->data + hdrlen + IEEE80211_GCMP_HDR_LEN, | ||
757 | data_len, | ||
758 | skb->data + skb->len - IEEE80211_GCMP_MIC_LEN)) | ||
759 | return RX_DROP_UNUSABLE; | ||
760 | } | ||
761 | |||
762 | memcpy(key->u.gcmp.rx_pn[queue], pn, IEEE80211_GCMP_PN_LEN); | ||
763 | |||
764 | /* Remove GCMP header and MIC */ | ||
765 | if (pskb_trim(skb, skb->len - IEEE80211_GCMP_MIC_LEN)) | ||
766 | return RX_DROP_UNUSABLE; | ||
767 | memmove(skb->data + IEEE80211_GCMP_HDR_LEN, skb->data, hdrlen); | ||
768 | skb_pull(skb, IEEE80211_GCMP_HDR_LEN); | ||
769 | |||
770 | return RX_CONTINUE; | ||
771 | } | ||
772 | |||
549 | static ieee80211_tx_result | 773 | static ieee80211_tx_result |
550 | ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx, | 774 | ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx, |
551 | struct sk_buff *skb) | 775 | struct sk_buff *skb) |
diff --git a/net/mac80211/wpa.h b/net/mac80211/wpa.h index 62e5a12dfe0a..ea955f278351 100644 --- a/net/mac80211/wpa.h +++ b/net/mac80211/wpa.h | |||
@@ -37,4 +37,9 @@ ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx); | |||
37 | ieee80211_rx_result | 37 | ieee80211_rx_result |
38 | ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx); | 38 | ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx); |
39 | 39 | ||
40 | ieee80211_tx_result | ||
41 | ieee80211_crypto_gcmp_encrypt(struct ieee80211_tx_data *tx); | ||
42 | ieee80211_rx_result | ||
43 | ieee80211_crypto_gcmp_decrypt(struct ieee80211_rx_data *rx); | ||
44 | |||
40 | #endif /* WPA_H */ | 45 | #endif /* WPA_H */ |