blob: c36287399d7ea2155f53a535a1e0ad540e104be3 [file] [log] [blame]
Jeff Garzikb4538722005-05-12 22:48:20 -04001/*
John W. Linville274bfb82008-10-29 11:35:05 -04002 * lib80211 crypt: host-based TKIP encryption implementation for lib80211
Jeff Garzikb4538722005-05-12 22:48:20 -04003 *
Jouni Malinen85d32e72007-03-24 17:15:30 -07004 * Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
John W. Linville274bfb82008-10-29 11:35:05 -04005 * Copyright (c) 2008, John W. Linville <linville@tuxdriver.com>
Jeff Garzikb4538722005-05-12 22:48:20 -04006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation. See README and COPYING for
10 * more details.
11 */
12
Herbert Xuf12cc202006-08-22 20:36:13 +100013#include <linux/err.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040014#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/slab.h>
17#include <linux/random.h>
Ralf Baechle11763602007-10-23 20:42:11 +020018#include <linux/scatterlist.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040019#include <linux/skbuff.h>
20#include <linux/netdevice.h>
Al Virod7fe0f22006-12-03 23:15:30 -050021#include <linux/mm.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040022#include <linux/if_ether.h>
23#include <linux/if_arp.h>
24#include <asm/string.h>
25
John W. Linville274bfb82008-10-29 11:35:05 -040026#include <linux/wireless.h>
27#include <linux/ieee80211.h>
28#include <net/iw_handler.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040029
Jeff Garzikb4538722005-05-12 22:48:20 -040030#include <linux/crypto.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040031#include <linux/crc32.h>
32
John W. Linville274bfb82008-10-29 11:35:05 -040033#include <net/lib80211.h>
34
Jeff Garzikb4538722005-05-12 22:48:20 -040035MODULE_AUTHOR("Jouni Malinen");
John W. Linville274bfb82008-10-29 11:35:05 -040036MODULE_DESCRIPTION("lib80211 crypt: TKIP");
Jeff Garzikb4538722005-05-12 22:48:20 -040037MODULE_LICENSE("GPL");
38
John W. Linville274bfb82008-10-29 11:35:05 -040039struct lib80211_tkip_data {
Jeff Garzikb4538722005-05-12 22:48:20 -040040#define TKIP_KEY_LEN 32
41 u8 key[TKIP_KEY_LEN];
42 int key_set;
43
44 u32 tx_iv32;
45 u16 tx_iv16;
46 u16 tx_ttak[5];
47 int tx_phase1_done;
48
49 u32 rx_iv32;
50 u16 rx_iv16;
51 u16 rx_ttak[5];
52 int rx_phase1_done;
53 u32 rx_iv32_new;
54 u16 rx_iv16_new;
55
56 u32 dot11RSNAStatsTKIPReplays;
57 u32 dot11RSNAStatsTKIPICVErrors;
58 u32 dot11RSNAStatsTKIPLocalMICFailures;
59
60 int key_idx;
61
Jeff Garzik28eb1772006-09-22 20:10:23 -040062 struct crypto_blkcipher *rx_tfm_arc4;
63 struct crypto_hash *rx_tfm_michael;
64 struct crypto_blkcipher *tx_tfm_arc4;
65 struct crypto_hash *tx_tfm_michael;
Jeff Garzikb4538722005-05-12 22:48:20 -040066
67 /* scratch buffers for virt_to_page() (crypto API) */
68 u8 rx_hdr[16], tx_hdr[16];
James Ketrenos20d64712005-09-21 11:53:43 -050069
James Ketrenos6eb6edf2005-09-22 10:34:15 +000070 unsigned long flags;
Jeff Garzikb4538722005-05-12 22:48:20 -040071};
72
John W. Linville274bfb82008-10-29 11:35:05 -040073static unsigned long lib80211_tkip_set_flags(unsigned long flags, void *priv)
James Ketrenos6eb6edf2005-09-22 10:34:15 +000074{
John W. Linville274bfb82008-10-29 11:35:05 -040075 struct lib80211_tkip_data *_priv = priv;
James Ketrenos6eb6edf2005-09-22 10:34:15 +000076 unsigned long old_flags = _priv->flags;
77 _priv->flags = flags;
78 return old_flags;
79}
80
John W. Linville274bfb82008-10-29 11:35:05 -040081static unsigned long lib80211_tkip_get_flags(void *priv)
James Ketrenos6eb6edf2005-09-22 10:34:15 +000082{
John W. Linville274bfb82008-10-29 11:35:05 -040083 struct lib80211_tkip_data *_priv = priv;
James Ketrenos6eb6edf2005-09-22 10:34:15 +000084 return _priv->flags;
85}
86
John W. Linville274bfb82008-10-29 11:35:05 -040087static void *lib80211_tkip_init(int key_idx)
Jeff Garzikb4538722005-05-12 22:48:20 -040088{
John W. Linville274bfb82008-10-29 11:35:05 -040089 struct lib80211_tkip_data *priv;
Jeff Garzikb4538722005-05-12 22:48:20 -040090
Zhu Yi8aa914b2006-01-19 16:22:07 +080091 priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
Jeff Garzikb4538722005-05-12 22:48:20 -040092 if (priv == NULL)
93 goto fail;
James Ketrenos20d64712005-09-21 11:53:43 -050094
Jeff Garzikb4538722005-05-12 22:48:20 -040095 priv->key_idx = key_idx;
96
Jeff Garzik28eb1772006-09-22 20:10:23 -040097 priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
Herbert Xuf12cc202006-08-22 20:36:13 +100098 CRYPTO_ALG_ASYNC);
Jeff Garzik28eb1772006-09-22 20:10:23 -040099 if (IS_ERR(priv->tx_tfm_arc4)) {
John W. Linville274bfb82008-10-29 11:35:05 -0400100 printk(KERN_DEBUG "lib80211_crypt_tkip: could not allocate "
Jeff Garzikb4538722005-05-12 22:48:20 -0400101 "crypto API arc4\n");
Jeff Garzik18379872006-09-22 21:19:05 -0400102 priv->tx_tfm_arc4 = NULL;
Jeff Garzikb4538722005-05-12 22:48:20 -0400103 goto fail;
104 }
105
Jeff Garzik28eb1772006-09-22 20:10:23 -0400106 priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
107 CRYPTO_ALG_ASYNC);
108 if (IS_ERR(priv->tx_tfm_michael)) {
John W. Linville274bfb82008-10-29 11:35:05 -0400109 printk(KERN_DEBUG "lib80211_crypt_tkip: could not allocate "
Zhu Yi5a656942006-08-21 11:33:56 +0800110 "crypto API michael_mic\n");
Jeff Garzik18379872006-09-22 21:19:05 -0400111 priv->tx_tfm_michael = NULL;
Zhu Yi5a656942006-08-21 11:33:56 +0800112 goto fail;
113 }
114
Jeff Garzik28eb1772006-09-22 20:10:23 -0400115 priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
116 CRYPTO_ALG_ASYNC);
117 if (IS_ERR(priv->rx_tfm_arc4)) {
John W. Linville274bfb82008-10-29 11:35:05 -0400118 printk(KERN_DEBUG "lib80211_crypt_tkip: could not allocate "
Zhu Yi5a656942006-08-21 11:33:56 +0800119 "crypto API arc4\n");
Jeff Garzik18379872006-09-22 21:19:05 -0400120 priv->rx_tfm_arc4 = NULL;
Zhu Yi5a656942006-08-21 11:33:56 +0800121 goto fail;
122 }
123
Jeff Garzik28eb1772006-09-22 20:10:23 -0400124 priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
125 CRYPTO_ALG_ASYNC);
126 if (IS_ERR(priv->rx_tfm_michael)) {
John W. Linville274bfb82008-10-29 11:35:05 -0400127 printk(KERN_DEBUG "lib80211_crypt_tkip: could not allocate "
Jeff Garzikb4538722005-05-12 22:48:20 -0400128 "crypto API michael_mic\n");
Jeff Garzik18379872006-09-22 21:19:05 -0400129 priv->rx_tfm_michael = NULL;
Jeff Garzikb4538722005-05-12 22:48:20 -0400130 goto fail;
131 }
132
133 return priv;
134
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400135 fail:
Jeff Garzikb4538722005-05-12 22:48:20 -0400136 if (priv) {
Zhu Yi5a656942006-08-21 11:33:56 +0800137 if (priv->tx_tfm_michael)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400138 crypto_free_hash(priv->tx_tfm_michael);
Zhu Yi5a656942006-08-21 11:33:56 +0800139 if (priv->tx_tfm_arc4)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400140 crypto_free_blkcipher(priv->tx_tfm_arc4);
Zhu Yi5a656942006-08-21 11:33:56 +0800141 if (priv->rx_tfm_michael)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400142 crypto_free_hash(priv->rx_tfm_michael);
Zhu Yi5a656942006-08-21 11:33:56 +0800143 if (priv->rx_tfm_arc4)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400144 crypto_free_blkcipher(priv->rx_tfm_arc4);
Jeff Garzikb4538722005-05-12 22:48:20 -0400145 kfree(priv);
146 }
147
148 return NULL;
149}
150
John W. Linville274bfb82008-10-29 11:35:05 -0400151static void lib80211_tkip_deinit(void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400152{
John W. Linville274bfb82008-10-29 11:35:05 -0400153 struct lib80211_tkip_data *_priv = priv;
Zhu Yi5a656942006-08-21 11:33:56 +0800154 if (_priv) {
155 if (_priv->tx_tfm_michael)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400156 crypto_free_hash(_priv->tx_tfm_michael);
Zhu Yi5a656942006-08-21 11:33:56 +0800157 if (_priv->tx_tfm_arc4)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400158 crypto_free_blkcipher(_priv->tx_tfm_arc4);
Zhu Yi5a656942006-08-21 11:33:56 +0800159 if (_priv->rx_tfm_michael)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400160 crypto_free_hash(_priv->rx_tfm_michael);
Zhu Yi5a656942006-08-21 11:33:56 +0800161 if (_priv->rx_tfm_arc4)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400162 crypto_free_blkcipher(_priv->rx_tfm_arc4);
Zhu Yi5a656942006-08-21 11:33:56 +0800163 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400164 kfree(priv);
165}
166
Jeff Garzikb4538722005-05-12 22:48:20 -0400167static inline u16 RotR1(u16 val)
168{
169 return (val >> 1) | (val << 15);
170}
171
Jeff Garzikb4538722005-05-12 22:48:20 -0400172static inline u8 Lo8(u16 val)
173{
174 return val & 0xff;
175}
176
Jeff Garzikb4538722005-05-12 22:48:20 -0400177static inline u8 Hi8(u16 val)
178{
179 return val >> 8;
180}
181
Jeff Garzikb4538722005-05-12 22:48:20 -0400182static inline u16 Lo16(u32 val)
183{
184 return val & 0xffff;
185}
186
Jeff Garzikb4538722005-05-12 22:48:20 -0400187static inline u16 Hi16(u32 val)
188{
189 return val >> 16;
190}
191
Jeff Garzikb4538722005-05-12 22:48:20 -0400192static inline u16 Mk16(u8 hi, u8 lo)
193{
194 return lo | (((u16) hi) << 8);
195}
196
Al Virod9e94d52007-12-29 05:01:07 -0500197static inline u16 Mk16_le(__le16 * v)
Jeff Garzikb4538722005-05-12 22:48:20 -0400198{
199 return le16_to_cpu(*v);
200}
201
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400202static const u16 Sbox[256] = {
Jeff Garzikb4538722005-05-12 22:48:20 -0400203 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
204 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
205 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
206 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
207 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
208 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
209 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
210 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
211 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
212 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
213 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
214 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
215 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
216 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
217 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
218 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
219 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
220 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
221 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
222 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
223 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
224 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
225 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
226 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
227 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
228 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
229 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
230 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
231 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
232 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
233 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
234 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
235};
236
Jeff Garzikb4538722005-05-12 22:48:20 -0400237static inline u16 _S_(u16 v)
238{
239 u16 t = Sbox[Hi8(v)];
240 return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8));
241}
242
Jeff Garzikb4538722005-05-12 22:48:20 -0400243#define PHASE1_LOOP_COUNT 8
244
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400245static void tkip_mixing_phase1(u16 * TTAK, const u8 * TK, const u8 * TA,
246 u32 IV32)
Jeff Garzikb4538722005-05-12 22:48:20 -0400247{
248 int i, j;
249
250 /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */
251 TTAK[0] = Lo16(IV32);
252 TTAK[1] = Hi16(IV32);
253 TTAK[2] = Mk16(TA[1], TA[0]);
254 TTAK[3] = Mk16(TA[3], TA[2]);
255 TTAK[4] = Mk16(TA[5], TA[4]);
256
257 for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
258 j = 2 * (i & 1);
259 TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j]));
260 TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j]));
261 TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j]));
262 TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j]));
263 TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i;
264 }
265}
266
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400267static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK,
Jeff Garzikb4538722005-05-12 22:48:20 -0400268 u16 IV16)
269{
270 /* Make temporary area overlap WEP seed so that the final copy can be
271 * avoided on little endian hosts. */
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400272 u16 *PPK = (u16 *) & WEPSeed[4];
Jeff Garzikb4538722005-05-12 22:48:20 -0400273
274 /* Step 1 - make copy of TTAK and bring in TSC */
275 PPK[0] = TTAK[0];
276 PPK[1] = TTAK[1];
277 PPK[2] = TTAK[2];
278 PPK[3] = TTAK[3];
279 PPK[4] = TTAK[4];
280 PPK[5] = TTAK[4] + IV16;
281
282 /* Step 2 - 96-bit bijective mixing using S-box */
Al Virod9e94d52007-12-29 05:01:07 -0500283 PPK[0] += _S_(PPK[5] ^ Mk16_le((__le16 *) & TK[0]));
284 PPK[1] += _S_(PPK[0] ^ Mk16_le((__le16 *) & TK[2]));
285 PPK[2] += _S_(PPK[1] ^ Mk16_le((__le16 *) & TK[4]));
286 PPK[3] += _S_(PPK[2] ^ Mk16_le((__le16 *) & TK[6]));
287 PPK[4] += _S_(PPK[3] ^ Mk16_le((__le16 *) & TK[8]));
288 PPK[5] += _S_(PPK[4] ^ Mk16_le((__le16 *) & TK[10]));
Jeff Garzikb4538722005-05-12 22:48:20 -0400289
Al Virod9e94d52007-12-29 05:01:07 -0500290 PPK[0] += RotR1(PPK[5] ^ Mk16_le((__le16 *) & TK[12]));
291 PPK[1] += RotR1(PPK[0] ^ Mk16_le((__le16 *) & TK[14]));
Jeff Garzikb4538722005-05-12 22:48:20 -0400292 PPK[2] += RotR1(PPK[1]);
293 PPK[3] += RotR1(PPK[2]);
294 PPK[4] += RotR1(PPK[3]);
295 PPK[5] += RotR1(PPK[4]);
296
297 /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value
298 * WEPSeed[0..2] is transmitted as WEP IV */
299 WEPSeed[0] = Hi8(IV16);
300 WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F;
301 WEPSeed[2] = Lo8(IV16);
Al Virod9e94d52007-12-29 05:01:07 -0500302 WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((__le16 *) & TK[0])) >> 1);
Jeff Garzikb4538722005-05-12 22:48:20 -0400303
304#ifdef __BIG_ENDIAN
305 {
306 int i;
307 for (i = 0; i < 6; i++)
308 PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8);
309 }
310#endif
311}
312
John W. Linville274bfb82008-10-29 11:35:05 -0400313static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len,
Zhu Yi9184d932006-01-19 16:22:32 +0800314 u8 * rc4key, int keylen, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400315{
John W. Linville274bfb82008-10-29 11:35:05 -0400316 struct lib80211_tkip_data *tkey = priv;
Jeff Garzikb4538722005-05-12 22:48:20 -0400317 int len;
Zhu Yi9184d932006-01-19 16:22:32 +0800318 u8 *pos;
John W. Linville274bfb82008-10-29 11:35:05 -0400319 struct ieee80211_hdr *hdr;
Jeff Garzikb4538722005-05-12 22:48:20 -0400320
John W. Linville274bfb82008-10-29 11:35:05 -0400321 hdr = (struct ieee80211_hdr *)skb->data;
James Ketrenos20d64712005-09-21 11:53:43 -0500322
James Ketrenos31b59ea2005-09-21 11:58:49 -0500323 if (skb_headroom(skb) < 8 || skb->len < hdr_len)
Zhu Yi9184d932006-01-19 16:22:32 +0800324 return -1;
325
326 if (rc4key == NULL || keylen < 16)
327 return -1;
Jeff Garzikb4538722005-05-12 22:48:20 -0400328
Jeff Garzikb4538722005-05-12 22:48:20 -0400329 if (!tkey->tx_phase1_done) {
330 tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2,
331 tkey->tx_iv32);
332 tkey->tx_phase1_done = 1;
333 }
334 tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16);
335
336 len = skb->len - hdr_len;
337 pos = skb_push(skb, 8);
338 memmove(pos, pos + 8, hdr_len);
339 pos += hdr_len;
Jeff Garzikb4538722005-05-12 22:48:20 -0400340
James Ketrenos31b59ea2005-09-21 11:58:49 -0500341 *pos++ = *rc4key;
342 *pos++ = *(rc4key + 1);
343 *pos++ = *(rc4key + 2);
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400344 *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */ ;
Jeff Garzikb4538722005-05-12 22:48:20 -0400345 *pos++ = tkey->tx_iv32 & 0xff;
346 *pos++ = (tkey->tx_iv32 >> 8) & 0xff;
347 *pos++ = (tkey->tx_iv32 >> 16) & 0xff;
348 *pos++ = (tkey->tx_iv32 >> 24) & 0xff;
349
Zhu Yi9184d932006-01-19 16:22:32 +0800350 tkey->tx_iv16++;
351 if (tkey->tx_iv16 == 0) {
352 tkey->tx_phase1_done = 0;
353 tkey->tx_iv32++;
354 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400355
Zhu Yi9184d932006-01-19 16:22:32 +0800356 return 8;
James Ketrenos31b59ea2005-09-21 11:58:49 -0500357}
358
John W. Linville274bfb82008-10-29 11:35:05 -0400359static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
James Ketrenos31b59ea2005-09-21 11:58:49 -0500360{
John W. Linville274bfb82008-10-29 11:35:05 -0400361 struct lib80211_tkip_data *tkey = priv;
Jeff Garzik28eb1772006-09-22 20:10:23 -0400362 struct blkcipher_desc desc = { .tfm = tkey->tx_tfm_arc4 };
James Ketrenos31b59ea2005-09-21 11:58:49 -0500363 int len;
Zhu Yi9184d932006-01-19 16:22:32 +0800364 u8 rc4key[16], *pos, *icv;
365 u32 crc;
James Ketrenos31b59ea2005-09-21 11:58:49 -0500366 struct scatterlist sg;
367
James Ketrenos6eb6edf2005-09-22 10:34:15 +0000368 if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
James Ketrenos31b59ea2005-09-21 11:58:49 -0500369 if (net_ratelimit()) {
John W. Linville274bfb82008-10-29 11:35:05 -0400370 struct ieee80211_hdr *hdr =
371 (struct ieee80211_hdr *)skb->data;
Zhu Yi9184d932006-01-19 16:22:32 +0800372 printk(KERN_DEBUG ": TKIP countermeasures: dropped "
Johannes Berge1749612008-10-27 15:59:26 -0700373 "TX packet to %pM\n", hdr->addr1);
James Ketrenos31b59ea2005-09-21 11:58:49 -0500374 }
375 return -1;
376 }
377
378 if (skb_tailroom(skb) < 4 || skb->len < hdr_len)
379 return -1;
380
381 len = skb->len - hdr_len;
382 pos = skb->data + hdr_len;
383
John W. Linville274bfb82008-10-29 11:35:05 -0400384 if ((lib80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0)
James Ketrenos31b59ea2005-09-21 11:58:49 -0500385 return -1;
386
Zhu Yi9184d932006-01-19 16:22:32 +0800387 icv = skb_put(skb, 4);
388
389 crc = ~crc32_le(~0, pos, len);
390 icv[0] = crc;
391 icv[1] = crc >> 8;
392 icv[2] = crc >> 16;
393 icv[3] = crc >> 24;
394
Jeff Garzik28eb1772006-09-22 20:10:23 -0400395 crypto_blkcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
Jens Axboefa05f122007-10-22 19:44:26 +0200396 sg_init_one(&sg, pos, len + 4);
Herbert Xuf12cc202006-08-22 20:36:13 +1000397 return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
Zhu Yib4328d82006-08-21 11:33:09 +0800398}
399
Jeff Garzik18379872006-09-22 21:19:05 -0400400/*
401 * deal with seq counter wrapping correctly.
402 * refer to timer_after() for jiffies wrapping handling
403 */
404static inline int tkip_replay_check(u32 iv32_n, u16 iv16_n,
405 u32 iv32_o, u16 iv16_o)
406{
407 if ((s32)iv32_n - (s32)iv32_o < 0 ||
408 (iv32_n == iv32_o && iv16_n <= iv16_o))
409 return 1;
410 return 0;
411}
412
John W. Linville274bfb82008-10-29 11:35:05 -0400413static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400414{
John W. Linville274bfb82008-10-29 11:35:05 -0400415 struct lib80211_tkip_data *tkey = priv;
Jeff Garzik28eb1772006-09-22 20:10:23 -0400416 struct blkcipher_desc desc = { .tfm = tkey->rx_tfm_arc4 };
Jeff Garzikb4538722005-05-12 22:48:20 -0400417 u8 rc4key[16];
418 u8 keyidx, *pos;
419 u32 iv32;
420 u16 iv16;
John W. Linville274bfb82008-10-29 11:35:05 -0400421 struct ieee80211_hdr *hdr;
Jeff Garzikb4538722005-05-12 22:48:20 -0400422 u8 icv[4];
423 u32 crc;
424 struct scatterlist sg;
425 int plen;
426
John W. Linville274bfb82008-10-29 11:35:05 -0400427 hdr = (struct ieee80211_hdr *)skb->data;
James Ketrenos20d64712005-09-21 11:53:43 -0500428
James Ketrenos6eb6edf2005-09-22 10:34:15 +0000429 if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
James Ketrenos20d64712005-09-21 11:53:43 -0500430 if (net_ratelimit()) {
Zhu Yi9184d932006-01-19 16:22:32 +0800431 printk(KERN_DEBUG ": TKIP countermeasures: dropped "
Johannes Berge1749612008-10-27 15:59:26 -0700432 "received packet from %pM\n", hdr->addr2);
James Ketrenos20d64712005-09-21 11:53:43 -0500433 }
434 return -1;
435 }
436
Jeff Garzikb4538722005-05-12 22:48:20 -0400437 if (skb->len < hdr_len + 8 + 4)
438 return -1;
439
Jeff Garzikb4538722005-05-12 22:48:20 -0400440 pos = skb->data + hdr_len;
441 keyidx = pos[3];
442 if (!(keyidx & (1 << 5))) {
443 if (net_ratelimit()) {
444 printk(KERN_DEBUG "TKIP: received packet without ExtIV"
Johannes Berge1749612008-10-27 15:59:26 -0700445 " flag from %pM\n", hdr->addr2);
Jeff Garzikb4538722005-05-12 22:48:20 -0400446 }
447 return -2;
448 }
449 keyidx >>= 6;
450 if (tkey->key_idx != keyidx) {
451 printk(KERN_DEBUG "TKIP: RX tkey->key_idx=%d frame "
452 "keyidx=%d priv=%p\n", tkey->key_idx, keyidx, priv);
453 return -6;
454 }
455 if (!tkey->key_set) {
456 if (net_ratelimit()) {
Johannes Berge1749612008-10-27 15:59:26 -0700457 printk(KERN_DEBUG "TKIP: received packet from %pM"
Jeff Garzikb4538722005-05-12 22:48:20 -0400458 " with keyid=%d that does not have a configured"
Johannes Berge1749612008-10-27 15:59:26 -0700459 " key\n", hdr->addr2, keyidx);
Jeff Garzikb4538722005-05-12 22:48:20 -0400460 }
461 return -3;
462 }
463 iv16 = (pos[0] << 8) | pos[2];
464 iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
465 pos += 8;
466
Zhu Yib4328d82006-08-21 11:33:09 +0800467 if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) {
John W. Linville6f16bf32009-03-11 11:05:25 -0400468#ifdef CONFIG_LIB80211_DEBUG
John W. Linville274bfb82008-10-29 11:35:05 -0400469 if (net_ratelimit()) {
470 printk(KERN_DEBUG "TKIP: replay detected: STA=%pM"
Jeff Garzikb4538722005-05-12 22:48:20 -0400471 " previous TSC %08x%04x received TSC "
Johannes Berge1749612008-10-27 15:59:26 -0700472 "%08x%04x\n", hdr->addr2,
Jeff Garzikb4538722005-05-12 22:48:20 -0400473 tkey->rx_iv32, tkey->rx_iv16, iv32, iv16);
474 }
John W. Linville6f16bf32009-03-11 11:05:25 -0400475#endif
Jeff Garzikb4538722005-05-12 22:48:20 -0400476 tkey->dot11RSNAStatsTKIPReplays++;
477 return -4;
478 }
479
480 if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) {
481 tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32);
482 tkey->rx_phase1_done = 1;
483 }
484 tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16);
485
486 plen = skb->len - hdr_len - 12;
487
Jeff Garzik28eb1772006-09-22 20:10:23 -0400488 crypto_blkcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
Jens Axboefa05f122007-10-22 19:44:26 +0200489 sg_init_one(&sg, pos, plen + 4);
Herbert Xuf12cc202006-08-22 20:36:13 +1000490 if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) {
491 if (net_ratelimit()) {
492 printk(KERN_DEBUG ": TKIP: failed to decrypt "
Johannes Berge1749612008-10-27 15:59:26 -0700493 "received packet from %pM\n",
494 hdr->addr2);
Herbert Xuf12cc202006-08-22 20:36:13 +1000495 }
496 return -7;
497 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400498
499 crc = ~crc32_le(~0, pos, plen);
500 icv[0] = crc;
501 icv[1] = crc >> 8;
502 icv[2] = crc >> 16;
503 icv[3] = crc >> 24;
504 if (memcmp(icv, pos + plen, 4) != 0) {
505 if (iv32 != tkey->rx_iv32) {
506 /* Previously cached Phase1 result was already lost, so
507 * it needs to be recalculated for the next packet. */
508 tkey->rx_phase1_done = 0;
509 }
John W. Linville6f16bf32009-03-11 11:05:25 -0400510#ifdef CONFIG_LIB80211_DEBUG
John W. Linville274bfb82008-10-29 11:35:05 -0400511 if (net_ratelimit()) {
512 printk(KERN_DEBUG "TKIP: ICV error detected: STA="
Johannes Berge1749612008-10-27 15:59:26 -0700513 "%pM\n", hdr->addr2);
Jeff Garzikb4538722005-05-12 22:48:20 -0400514 }
John W. Linville6f16bf32009-03-11 11:05:25 -0400515#endif
Jeff Garzikb4538722005-05-12 22:48:20 -0400516 tkey->dot11RSNAStatsTKIPICVErrors++;
517 return -5;
518 }
519
520 /* Update real counters only after Michael MIC verification has
521 * completed */
522 tkey->rx_iv32_new = iv32;
523 tkey->rx_iv16_new = iv16;
524
525 /* Remove IV and ICV */
526 memmove(skb->data + 8, skb->data, hdr_len);
527 skb_pull(skb, 8);
528 skb_trim(skb, skb->len - 4);
529
530 return keyidx;
531}
532
Jeff Garzik28eb1772006-09-22 20:10:23 -0400533static int michael_mic(struct crypto_hash *tfm_michael, u8 * key, u8 * hdr,
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400534 u8 * data, size_t data_len, u8 * mic)
Jeff Garzikb4538722005-05-12 22:48:20 -0400535{
Herbert Xu35058682006-08-24 19:10:20 +1000536 struct hash_desc desc;
Jeff Garzikb4538722005-05-12 22:48:20 -0400537 struct scatterlist sg[2];
538
Zhu Yi5a656942006-08-21 11:33:56 +0800539 if (tfm_michael == NULL) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400540 printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n");
541 return -1;
542 }
Jens Axboefa05f122007-10-22 19:44:26 +0200543 sg_init_table(sg, 2);
Jens Axboe642f1492007-10-24 11:20:47 +0200544 sg_set_buf(&sg[0], hdr, 16);
545 sg_set_buf(&sg[1], data, data_len);
Jeff Garzikb4538722005-05-12 22:48:20 -0400546
Jeff Garzik28eb1772006-09-22 20:10:23 -0400547 if (crypto_hash_setkey(tfm_michael, key, 8))
Herbert Xu35058682006-08-24 19:10:20 +1000548 return -1;
Jeff Garzikb4538722005-05-12 22:48:20 -0400549
Jeff Garzik28eb1772006-09-22 20:10:23 -0400550 desc.tfm = tfm_michael;
Herbert Xu35058682006-08-24 19:10:20 +1000551 desc.flags = 0;
552 return crypto_hash_digest(&desc, sg, data_len + 16, mic);
Jeff Garzikb4538722005-05-12 22:48:20 -0400553}
554
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400555static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr)
Jeff Garzikb4538722005-05-12 22:48:20 -0400556{
John W. Linville274bfb82008-10-29 11:35:05 -0400557 struct ieee80211_hdr *hdr11;
Jeff Garzikb4538722005-05-12 22:48:20 -0400558
John W. Linville274bfb82008-10-29 11:35:05 -0400559 hdr11 = (struct ieee80211_hdr *)skb->data;
Zhu Yiea284152006-04-13 17:17:06 +0800560
John W. Linville274bfb82008-10-29 11:35:05 -0400561 switch (le16_to_cpu(hdr11->frame_control) &
Jeff Garzikb4538722005-05-12 22:48:20 -0400562 (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
563 case IEEE80211_FCTL_TODS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400564 memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
565 memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400566 break;
567 case IEEE80211_FCTL_FROMDS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400568 memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
569 memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400570 break;
571 case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400572 memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
573 memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400574 break;
575 case 0:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400576 memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
577 memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400578 break;
579 }
580
John W. Linville274bfb82008-10-29 11:35:05 -0400581 if (ieee80211_is_data_qos(hdr11->frame_control)) {
582 hdr[12] = le16_to_cpu(*ieee80211_get_qos_ctl(hdr11))
583 & IEEE80211_QOS_CTL_TID_MASK;
Zhu Yiea284152006-04-13 17:17:06 +0800584 } else
585 hdr[12] = 0; /* priority */
586
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400587 hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */
Jeff Garzikb4538722005-05-12 22:48:20 -0400588}
589
John W. Linville274bfb82008-10-29 11:35:05 -0400590static int lib80211_michael_mic_add(struct sk_buff *skb, int hdr_len,
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400591 void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400592{
John W. Linville274bfb82008-10-29 11:35:05 -0400593 struct lib80211_tkip_data *tkey = priv;
Jeff Garzikb4538722005-05-12 22:48:20 -0400594 u8 *pos;
595
596 if (skb_tailroom(skb) < 8 || skb->len < hdr_len) {
597 printk(KERN_DEBUG "Invalid packet for Michael MIC add "
598 "(tailroom=%d hdr_len=%d skb->len=%d)\n",
599 skb_tailroom(skb), hdr_len, skb->len);
600 return -1;
601 }
602
603 michael_mic_hdr(skb, tkey->tx_hdr);
604 pos = skb_put(skb, 8);
Zhu Yi5a656942006-08-21 11:33:56 +0800605 if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr,
Jeff Garzikb4538722005-05-12 22:48:20 -0400606 skb->data + hdr_len, skb->len - 8 - hdr_len, pos))
607 return -1;
608
609 return 0;
610}
611
John W. Linville274bfb82008-10-29 11:35:05 -0400612static void lib80211_michael_mic_failure(struct net_device *dev,
613 struct ieee80211_hdr *hdr,
James Ketrenosee34af32005-09-21 11:54:36 -0500614 int keyidx)
Jeff Garzikb4538722005-05-12 22:48:20 -0400615{
616 union iwreq_data wrqu;
617 struct iw_michaelmicfailure ev;
618
619 /* TODO: needed parameters: count, keyid, key type, TSC */
620 memset(&ev, 0, sizeof(ev));
621 ev.flags = keyidx & IW_MICFAILURE_KEY_ID;
622 if (hdr->addr1[0] & 0x01)
623 ev.flags |= IW_MICFAILURE_GROUP;
624 else
625 ev.flags |= IW_MICFAILURE_PAIRWISE;
626 ev.src_addr.sa_family = ARPHRD_ETHER;
627 memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN);
628 memset(&wrqu, 0, sizeof(wrqu));
629 wrqu.data.length = sizeof(ev);
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400630 wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev);
Jeff Garzikb4538722005-05-12 22:48:20 -0400631}
Jeff Garzikb4538722005-05-12 22:48:20 -0400632
John W. Linville274bfb82008-10-29 11:35:05 -0400633static int lib80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400634 int hdr_len, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400635{
John W. Linville274bfb82008-10-29 11:35:05 -0400636 struct lib80211_tkip_data *tkey = priv;
Jeff Garzikb4538722005-05-12 22:48:20 -0400637 u8 mic[8];
638
639 if (!tkey->key_set)
640 return -1;
641
642 michael_mic_hdr(skb, tkey->rx_hdr);
Zhu Yi5a656942006-08-21 11:33:56 +0800643 if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr,
Jeff Garzikb4538722005-05-12 22:48:20 -0400644 skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
645 return -1;
646 if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
John W. Linville274bfb82008-10-29 11:35:05 -0400647 struct ieee80211_hdr *hdr;
648 hdr = (struct ieee80211_hdr *)skb->data;
Jeff Garzikb4538722005-05-12 22:48:20 -0400649 printk(KERN_DEBUG "%s: Michael MIC verification failed for "
Johannes Berge1749612008-10-27 15:59:26 -0700650 "MSDU from %pM keyidx=%d\n",
651 skb->dev ? skb->dev->name : "N/A", hdr->addr2,
Jeff Garzikb4538722005-05-12 22:48:20 -0400652 keyidx);
653 if (skb->dev)
John W. Linville274bfb82008-10-29 11:35:05 -0400654 lib80211_michael_mic_failure(skb->dev, hdr, keyidx);
Jeff Garzikb4538722005-05-12 22:48:20 -0400655 tkey->dot11RSNAStatsTKIPLocalMICFailures++;
656 return -1;
657 }
658
659 /* Update TSC counters for RX now that the packet verification has
660 * completed. */
661 tkey->rx_iv32 = tkey->rx_iv32_new;
662 tkey->rx_iv16 = tkey->rx_iv16_new;
663
664 skb_trim(skb, skb->len - 8);
665
666 return 0;
667}
668
John W. Linville274bfb82008-10-29 11:35:05 -0400669static int lib80211_tkip_set_key(void *key, int len, u8 * seq, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400670{
John W. Linville274bfb82008-10-29 11:35:05 -0400671 struct lib80211_tkip_data *tkey = priv;
Jeff Garzikb4538722005-05-12 22:48:20 -0400672 int keyidx;
Jeff Garzik28eb1772006-09-22 20:10:23 -0400673 struct crypto_hash *tfm = tkey->tx_tfm_michael;
674 struct crypto_blkcipher *tfm2 = tkey->tx_tfm_arc4;
675 struct crypto_hash *tfm3 = tkey->rx_tfm_michael;
676 struct crypto_blkcipher *tfm4 = tkey->rx_tfm_arc4;
Jeff Garzikb4538722005-05-12 22:48:20 -0400677
678 keyidx = tkey->key_idx;
679 memset(tkey, 0, sizeof(*tkey));
680 tkey->key_idx = keyidx;
Zhu Yi5a656942006-08-21 11:33:56 +0800681 tkey->tx_tfm_michael = tfm;
682 tkey->tx_tfm_arc4 = tfm2;
683 tkey->rx_tfm_michael = tfm3;
684 tkey->rx_tfm_arc4 = tfm4;
Jeff Garzikb4538722005-05-12 22:48:20 -0400685 if (len == TKIP_KEY_LEN) {
686 memcpy(tkey->key, key, TKIP_KEY_LEN);
687 tkey->key_set = 1;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400688 tkey->tx_iv16 = 1; /* TSC is initialized to 1 */
Jeff Garzikb4538722005-05-12 22:48:20 -0400689 if (seq) {
690 tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) |
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400691 (seq[3] << 8) | seq[2];
Jeff Garzikb4538722005-05-12 22:48:20 -0400692 tkey->rx_iv16 = (seq[1] << 8) | seq[0];
693 }
694 } else if (len == 0)
695 tkey->key_set = 0;
696 else
697 return -1;
698
699 return 0;
700}
701
John W. Linville274bfb82008-10-29 11:35:05 -0400702static int lib80211_tkip_get_key(void *key, int len, u8 * seq, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400703{
John W. Linville274bfb82008-10-29 11:35:05 -0400704 struct lib80211_tkip_data *tkey = priv;
Jeff Garzikb4538722005-05-12 22:48:20 -0400705
706 if (len < TKIP_KEY_LEN)
707 return -1;
708
709 if (!tkey->key_set)
710 return 0;
711 memcpy(key, tkey->key, TKIP_KEY_LEN);
712
713 if (seq) {
714 /* Return the sequence number of the last transmitted frame. */
715 u16 iv16 = tkey->tx_iv16;
716 u32 iv32 = tkey->tx_iv32;
717 if (iv16 == 0)
718 iv32--;
719 iv16--;
720 seq[0] = tkey->tx_iv16;
721 seq[1] = tkey->tx_iv16 >> 8;
722 seq[2] = tkey->tx_iv32;
723 seq[3] = tkey->tx_iv32 >> 8;
724 seq[4] = tkey->tx_iv32 >> 16;
725 seq[5] = tkey->tx_iv32 >> 24;
726 }
727
728 return TKIP_KEY_LEN;
729}
730
John W. Linville274bfb82008-10-29 11:35:05 -0400731static char *lib80211_tkip_print_stats(char *p, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400732{
John W. Linville274bfb82008-10-29 11:35:05 -0400733 struct lib80211_tkip_data *tkip = priv;
Jeff Garzikb4538722005-05-12 22:48:20 -0400734 p += sprintf(p, "key[%d] alg=TKIP key_set=%d "
735 "tx_pn=%02x%02x%02x%02x%02x%02x "
736 "rx_pn=%02x%02x%02x%02x%02x%02x "
737 "replays=%d icv_errors=%d local_mic_failures=%d\n",
738 tkip->key_idx, tkip->key_set,
739 (tkip->tx_iv32 >> 24) & 0xff,
740 (tkip->tx_iv32 >> 16) & 0xff,
741 (tkip->tx_iv32 >> 8) & 0xff,
742 tkip->tx_iv32 & 0xff,
743 (tkip->tx_iv16 >> 8) & 0xff,
744 tkip->tx_iv16 & 0xff,
745 (tkip->rx_iv32 >> 24) & 0xff,
746 (tkip->rx_iv32 >> 16) & 0xff,
747 (tkip->rx_iv32 >> 8) & 0xff,
748 tkip->rx_iv32 & 0xff,
749 (tkip->rx_iv16 >> 8) & 0xff,
750 tkip->rx_iv16 & 0xff,
751 tkip->dot11RSNAStatsTKIPReplays,
752 tkip->dot11RSNAStatsTKIPICVErrors,
753 tkip->dot11RSNAStatsTKIPLocalMICFailures);
754 return p;
755}
756
John W. Linville274bfb82008-10-29 11:35:05 -0400757static struct lib80211_crypto_ops lib80211_crypt_tkip = {
James Ketrenos74079fd2005-09-13 17:35:21 -0500758 .name = "TKIP",
John W. Linville274bfb82008-10-29 11:35:05 -0400759 .init = lib80211_tkip_init,
760 .deinit = lib80211_tkip_deinit,
761 .build_iv = lib80211_tkip_hdr,
762 .encrypt_mpdu = lib80211_tkip_encrypt,
763 .decrypt_mpdu = lib80211_tkip_decrypt,
764 .encrypt_msdu = lib80211_michael_mic_add,
765 .decrypt_msdu = lib80211_michael_mic_verify,
766 .set_key = lib80211_tkip_set_key,
767 .get_key = lib80211_tkip_get_key,
768 .print_stats = lib80211_tkip_print_stats,
James Ketrenos1264fc02005-09-21 11:54:53 -0500769 .extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */
770 .extra_mpdu_postfix_len = 4, /* ICV */
771 .extra_msdu_postfix_len = 8, /* MIC */
John W. Linville274bfb82008-10-29 11:35:05 -0400772 .get_flags = lib80211_tkip_get_flags,
773 .set_flags = lib80211_tkip_set_flags,
James Ketrenos74079fd2005-09-13 17:35:21 -0500774 .owner = THIS_MODULE,
Jeff Garzikb4538722005-05-12 22:48:20 -0400775};
776
John W. Linville274bfb82008-10-29 11:35:05 -0400777static int __init lib80211_crypto_tkip_init(void)
Jeff Garzikb4538722005-05-12 22:48:20 -0400778{
John W. Linville274bfb82008-10-29 11:35:05 -0400779 return lib80211_register_crypto_ops(&lib80211_crypt_tkip);
Jeff Garzikb4538722005-05-12 22:48:20 -0400780}
781
John W. Linville274bfb82008-10-29 11:35:05 -0400782static void __exit lib80211_crypto_tkip_exit(void)
Jeff Garzikb4538722005-05-12 22:48:20 -0400783{
John W. Linville274bfb82008-10-29 11:35:05 -0400784 lib80211_unregister_crypto_ops(&lib80211_crypt_tkip);
Jeff Garzikb4538722005-05-12 22:48:20 -0400785}
786
John W. Linville274bfb82008-10-29 11:35:05 -0400787module_init(lib80211_crypto_tkip_init);
788module_exit(lib80211_crypto_tkip_exit);