blob: 811777682e2b94ea876edab53ac5005d0ee63969 [file] [log] [blame]
Jeff Garzikb4538722005-05-12 22:48:20 -04001/*
2 * Host AP crypt: host-based TKIP encryption implementation for Host AP driver
3 *
Jouni Malinen85d32e72007-03-24 17:15:30 -07004 * Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
Jeff Garzikb4538722005-05-12 22:48:20 -04005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation. See README and COPYING for
9 * more details.
10 */
11
Herbert Xuf12cc202006-08-22 20:36:13 +100012#include <linux/err.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040013#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/slab.h>
16#include <linux/random.h>
Ralf Baechle11763602007-10-23 20:42:11 +020017#include <linux/scatterlist.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040018#include <linux/skbuff.h>
19#include <linux/netdevice.h>
Al Virod7fe0f22006-12-03 23:15:30 -050020#include <linux/mm.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040021#include <linux/if_ether.h>
22#include <linux/if_arp.h>
23#include <asm/string.h>
24
25#include <net/ieee80211.h>
26
Jeff Garzikb4538722005-05-12 22:48:20 -040027#include <linux/crypto.h>
28#include <asm/scatterlist.h>
29#include <linux/crc32.h>
30
31MODULE_AUTHOR("Jouni Malinen");
32MODULE_DESCRIPTION("Host AP crypt: TKIP");
33MODULE_LICENSE("GPL");
34
35struct ieee80211_tkip_data {
36#define TKIP_KEY_LEN 32
37 u8 key[TKIP_KEY_LEN];
38 int key_set;
39
40 u32 tx_iv32;
41 u16 tx_iv16;
42 u16 tx_ttak[5];
43 int tx_phase1_done;
44
45 u32 rx_iv32;
46 u16 rx_iv16;
47 u16 rx_ttak[5];
48 int rx_phase1_done;
49 u32 rx_iv32_new;
50 u16 rx_iv16_new;
51
52 u32 dot11RSNAStatsTKIPReplays;
53 u32 dot11RSNAStatsTKIPICVErrors;
54 u32 dot11RSNAStatsTKIPLocalMICFailures;
55
56 int key_idx;
57
Jeff Garzik28eb1772006-09-22 20:10:23 -040058 struct crypto_blkcipher *rx_tfm_arc4;
59 struct crypto_hash *rx_tfm_michael;
60 struct crypto_blkcipher *tx_tfm_arc4;
61 struct crypto_hash *tx_tfm_michael;
Jeff Garzikb4538722005-05-12 22:48:20 -040062
63 /* scratch buffers for virt_to_page() (crypto API) */
64 u8 rx_hdr[16], tx_hdr[16];
James Ketrenos20d64712005-09-21 11:53:43 -050065
James Ketrenos6eb6edf2005-09-22 10:34:15 +000066 unsigned long flags;
Jeff Garzikb4538722005-05-12 22:48:20 -040067};
68
James Ketrenos6eb6edf2005-09-22 10:34:15 +000069static unsigned long ieee80211_tkip_set_flags(unsigned long flags, void *priv)
70{
71 struct ieee80211_tkip_data *_priv = priv;
72 unsigned long old_flags = _priv->flags;
73 _priv->flags = flags;
74 return old_flags;
75}
76
77static unsigned long ieee80211_tkip_get_flags(void *priv)
78{
79 struct ieee80211_tkip_data *_priv = priv;
80 return _priv->flags;
81}
82
83static void *ieee80211_tkip_init(int key_idx)
Jeff Garzikb4538722005-05-12 22:48:20 -040084{
85 struct ieee80211_tkip_data *priv;
86
Zhu Yi8aa914b2006-01-19 16:22:07 +080087 priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
Jeff Garzikb4538722005-05-12 22:48:20 -040088 if (priv == NULL)
89 goto fail;
James Ketrenos20d64712005-09-21 11:53:43 -050090
Jeff Garzikb4538722005-05-12 22:48:20 -040091 priv->key_idx = key_idx;
92
Jeff Garzik28eb1772006-09-22 20:10:23 -040093 priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
Herbert Xuf12cc202006-08-22 20:36:13 +100094 CRYPTO_ALG_ASYNC);
Jeff Garzik28eb1772006-09-22 20:10:23 -040095 if (IS_ERR(priv->tx_tfm_arc4)) {
Jeff Garzikb4538722005-05-12 22:48:20 -040096 printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
97 "crypto API arc4\n");
Jeff Garzik18379872006-09-22 21:19:05 -040098 priv->tx_tfm_arc4 = NULL;
Jeff Garzikb4538722005-05-12 22:48:20 -040099 goto fail;
100 }
101
Jeff Garzik28eb1772006-09-22 20:10:23 -0400102 priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
103 CRYPTO_ALG_ASYNC);
104 if (IS_ERR(priv->tx_tfm_michael)) {
Zhu Yi5a656942006-08-21 11:33:56 +0800105 printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
106 "crypto API michael_mic\n");
Jeff Garzik18379872006-09-22 21:19:05 -0400107 priv->tx_tfm_michael = NULL;
Zhu Yi5a656942006-08-21 11:33:56 +0800108 goto fail;
109 }
110
Jeff Garzik28eb1772006-09-22 20:10:23 -0400111 priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
112 CRYPTO_ALG_ASYNC);
113 if (IS_ERR(priv->rx_tfm_arc4)) {
Zhu Yi5a656942006-08-21 11:33:56 +0800114 printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
115 "crypto API arc4\n");
Jeff Garzik18379872006-09-22 21:19:05 -0400116 priv->rx_tfm_arc4 = NULL;
Zhu Yi5a656942006-08-21 11:33:56 +0800117 goto fail;
118 }
119
Jeff Garzik28eb1772006-09-22 20:10:23 -0400120 priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
121 CRYPTO_ALG_ASYNC);
122 if (IS_ERR(priv->rx_tfm_michael)) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400123 printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
124 "crypto API michael_mic\n");
Jeff Garzik18379872006-09-22 21:19:05 -0400125 priv->rx_tfm_michael = NULL;
Jeff Garzikb4538722005-05-12 22:48:20 -0400126 goto fail;
127 }
128
129 return priv;
130
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400131 fail:
Jeff Garzikb4538722005-05-12 22:48:20 -0400132 if (priv) {
Zhu Yi5a656942006-08-21 11:33:56 +0800133 if (priv->tx_tfm_michael)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400134 crypto_free_hash(priv->tx_tfm_michael);
Zhu Yi5a656942006-08-21 11:33:56 +0800135 if (priv->tx_tfm_arc4)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400136 crypto_free_blkcipher(priv->tx_tfm_arc4);
Zhu Yi5a656942006-08-21 11:33:56 +0800137 if (priv->rx_tfm_michael)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400138 crypto_free_hash(priv->rx_tfm_michael);
Zhu Yi5a656942006-08-21 11:33:56 +0800139 if (priv->rx_tfm_arc4)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400140 crypto_free_blkcipher(priv->rx_tfm_arc4);
Jeff Garzikb4538722005-05-12 22:48:20 -0400141 kfree(priv);
142 }
143
144 return NULL;
145}
146
Jeff Garzikb4538722005-05-12 22:48:20 -0400147static void ieee80211_tkip_deinit(void *priv)
148{
149 struct ieee80211_tkip_data *_priv = priv;
Zhu Yi5a656942006-08-21 11:33:56 +0800150 if (_priv) {
151 if (_priv->tx_tfm_michael)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400152 crypto_free_hash(_priv->tx_tfm_michael);
Zhu Yi5a656942006-08-21 11:33:56 +0800153 if (_priv->tx_tfm_arc4)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400154 crypto_free_blkcipher(_priv->tx_tfm_arc4);
Zhu Yi5a656942006-08-21 11:33:56 +0800155 if (_priv->rx_tfm_michael)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400156 crypto_free_hash(_priv->rx_tfm_michael);
Zhu Yi5a656942006-08-21 11:33:56 +0800157 if (_priv->rx_tfm_arc4)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400158 crypto_free_blkcipher(_priv->rx_tfm_arc4);
Zhu Yi5a656942006-08-21 11:33:56 +0800159 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400160 kfree(priv);
161}
162
Jeff Garzikb4538722005-05-12 22:48:20 -0400163static inline u16 RotR1(u16 val)
164{
165 return (val >> 1) | (val << 15);
166}
167
Jeff Garzikb4538722005-05-12 22:48:20 -0400168static inline u8 Lo8(u16 val)
169{
170 return val & 0xff;
171}
172
Jeff Garzikb4538722005-05-12 22:48:20 -0400173static inline u8 Hi8(u16 val)
174{
175 return val >> 8;
176}
177
Jeff Garzikb4538722005-05-12 22:48:20 -0400178static inline u16 Lo16(u32 val)
179{
180 return val & 0xffff;
181}
182
Jeff Garzikb4538722005-05-12 22:48:20 -0400183static inline u16 Hi16(u32 val)
184{
185 return val >> 16;
186}
187
Jeff Garzikb4538722005-05-12 22:48:20 -0400188static inline u16 Mk16(u8 hi, u8 lo)
189{
190 return lo | (((u16) hi) << 8);
191}
192
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400193static inline u16 Mk16_le(u16 * v)
Jeff Garzikb4538722005-05-12 22:48:20 -0400194{
195 return le16_to_cpu(*v);
196}
197
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400198static const u16 Sbox[256] = {
Jeff Garzikb4538722005-05-12 22:48:20 -0400199 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
200 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
201 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
202 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
203 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
204 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
205 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
206 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
207 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
208 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
209 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
210 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
211 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
212 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
213 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
214 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
215 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
216 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
217 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
218 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
219 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
220 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
221 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
222 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
223 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
224 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
225 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
226 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
227 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
228 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
229 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
230 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
231};
232
Jeff Garzikb4538722005-05-12 22:48:20 -0400233static inline u16 _S_(u16 v)
234{
235 u16 t = Sbox[Hi8(v)];
236 return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8));
237}
238
Jeff Garzikb4538722005-05-12 22:48:20 -0400239#define PHASE1_LOOP_COUNT 8
240
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400241static void tkip_mixing_phase1(u16 * TTAK, const u8 * TK, const u8 * TA,
242 u32 IV32)
Jeff Garzikb4538722005-05-12 22:48:20 -0400243{
244 int i, j;
245
246 /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */
247 TTAK[0] = Lo16(IV32);
248 TTAK[1] = Hi16(IV32);
249 TTAK[2] = Mk16(TA[1], TA[0]);
250 TTAK[3] = Mk16(TA[3], TA[2]);
251 TTAK[4] = Mk16(TA[5], TA[4]);
252
253 for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
254 j = 2 * (i & 1);
255 TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j]));
256 TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j]));
257 TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j]));
258 TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j]));
259 TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i;
260 }
261}
262
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400263static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK,
Jeff Garzikb4538722005-05-12 22:48:20 -0400264 u16 IV16)
265{
266 /* Make temporary area overlap WEP seed so that the final copy can be
267 * avoided on little endian hosts. */
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400268 u16 *PPK = (u16 *) & WEPSeed[4];
Jeff Garzikb4538722005-05-12 22:48:20 -0400269
270 /* Step 1 - make copy of TTAK and bring in TSC */
271 PPK[0] = TTAK[0];
272 PPK[1] = TTAK[1];
273 PPK[2] = TTAK[2];
274 PPK[3] = TTAK[3];
275 PPK[4] = TTAK[4];
276 PPK[5] = TTAK[4] + IV16;
277
278 /* Step 2 - 96-bit bijective mixing using S-box */
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400279 PPK[0] += _S_(PPK[5] ^ Mk16_le((u16 *) & TK[0]));
280 PPK[1] += _S_(PPK[0] ^ Mk16_le((u16 *) & TK[2]));
281 PPK[2] += _S_(PPK[1] ^ Mk16_le((u16 *) & TK[4]));
282 PPK[3] += _S_(PPK[2] ^ Mk16_le((u16 *) & TK[6]));
283 PPK[4] += _S_(PPK[3] ^ Mk16_le((u16 *) & TK[8]));
284 PPK[5] += _S_(PPK[4] ^ Mk16_le((u16 *) & TK[10]));
Jeff Garzikb4538722005-05-12 22:48:20 -0400285
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400286 PPK[0] += RotR1(PPK[5] ^ Mk16_le((u16 *) & TK[12]));
287 PPK[1] += RotR1(PPK[0] ^ Mk16_le((u16 *) & TK[14]));
Jeff Garzikb4538722005-05-12 22:48:20 -0400288 PPK[2] += RotR1(PPK[1]);
289 PPK[3] += RotR1(PPK[2]);
290 PPK[4] += RotR1(PPK[3]);
291 PPK[5] += RotR1(PPK[4]);
292
293 /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value
294 * WEPSeed[0..2] is transmitted as WEP IV */
295 WEPSeed[0] = Hi8(IV16);
296 WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F;
297 WEPSeed[2] = Lo8(IV16);
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400298 WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((u16 *) & TK[0])) >> 1);
Jeff Garzikb4538722005-05-12 22:48:20 -0400299
300#ifdef __BIG_ENDIAN
301 {
302 int i;
303 for (i = 0; i < 6; i++)
304 PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8);
305 }
306#endif
307}
308
Zhu Yi9184d932006-01-19 16:22:32 +0800309static int ieee80211_tkip_hdr(struct sk_buff *skb, int hdr_len,
310 u8 * rc4key, int keylen, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400311{
312 struct ieee80211_tkip_data *tkey = priv;
313 int len;
Zhu Yi9184d932006-01-19 16:22:32 +0800314 u8 *pos;
James Ketrenosee34af32005-09-21 11:54:36 -0500315 struct ieee80211_hdr_4addr *hdr;
Jeff Garzikb4538722005-05-12 22:48:20 -0400316
James Ketrenosee34af32005-09-21 11:54:36 -0500317 hdr = (struct ieee80211_hdr_4addr *)skb->data;
James Ketrenos20d64712005-09-21 11:53:43 -0500318
James Ketrenos31b59ea2005-09-21 11:58:49 -0500319 if (skb_headroom(skb) < 8 || skb->len < hdr_len)
Zhu Yi9184d932006-01-19 16:22:32 +0800320 return -1;
321
322 if (rc4key == NULL || keylen < 16)
323 return -1;
Jeff Garzikb4538722005-05-12 22:48:20 -0400324
Jeff Garzikb4538722005-05-12 22:48:20 -0400325 if (!tkey->tx_phase1_done) {
326 tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2,
327 tkey->tx_iv32);
328 tkey->tx_phase1_done = 1;
329 }
330 tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16);
331
332 len = skb->len - hdr_len;
333 pos = skb_push(skb, 8);
334 memmove(pos, pos + 8, hdr_len);
335 pos += hdr_len;
Jeff Garzikb4538722005-05-12 22:48:20 -0400336
James Ketrenos31b59ea2005-09-21 11:58:49 -0500337 *pos++ = *rc4key;
338 *pos++ = *(rc4key + 1);
339 *pos++ = *(rc4key + 2);
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400340 *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */ ;
Jeff Garzikb4538722005-05-12 22:48:20 -0400341 *pos++ = tkey->tx_iv32 & 0xff;
342 *pos++ = (tkey->tx_iv32 >> 8) & 0xff;
343 *pos++ = (tkey->tx_iv32 >> 16) & 0xff;
344 *pos++ = (tkey->tx_iv32 >> 24) & 0xff;
345
Zhu Yi9184d932006-01-19 16:22:32 +0800346 tkey->tx_iv16++;
347 if (tkey->tx_iv16 == 0) {
348 tkey->tx_phase1_done = 0;
349 tkey->tx_iv32++;
350 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400351
Zhu Yi9184d932006-01-19 16:22:32 +0800352 return 8;
James Ketrenos31b59ea2005-09-21 11:58:49 -0500353}
354
355static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
356{
357 struct ieee80211_tkip_data *tkey = priv;
Jeff Garzik28eb1772006-09-22 20:10:23 -0400358 struct blkcipher_desc desc = { .tfm = tkey->tx_tfm_arc4 };
James Ketrenos31b59ea2005-09-21 11:58:49 -0500359 int len;
Zhu Yi9184d932006-01-19 16:22:32 +0800360 u8 rc4key[16], *pos, *icv;
361 u32 crc;
James Ketrenos31b59ea2005-09-21 11:58:49 -0500362 struct scatterlist sg;
Joe Perches0795af52007-10-03 17:59:30 -0700363 DECLARE_MAC_BUF(mac);
James Ketrenos31b59ea2005-09-21 11:58:49 -0500364
James Ketrenos6eb6edf2005-09-22 10:34:15 +0000365 if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
James Ketrenos31b59ea2005-09-21 11:58:49 -0500366 if (net_ratelimit()) {
367 struct ieee80211_hdr_4addr *hdr =
368 (struct ieee80211_hdr_4addr *)skb->data;
Zhu Yi9184d932006-01-19 16:22:32 +0800369 printk(KERN_DEBUG ": TKIP countermeasures: dropped "
Joe Perches0795af52007-10-03 17:59:30 -0700370 "TX packet to %s\n",
371 print_mac(mac, hdr->addr1));
James Ketrenos31b59ea2005-09-21 11:58:49 -0500372 }
373 return -1;
374 }
375
376 if (skb_tailroom(skb) < 4 || skb->len < hdr_len)
377 return -1;
378
379 len = skb->len - hdr_len;
380 pos = skb->data + hdr_len;
381
Zhu Yi9184d932006-01-19 16:22:32 +0800382 if ((ieee80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0)
James Ketrenos31b59ea2005-09-21 11:58:49 -0500383 return -1;
384
Zhu Yi9184d932006-01-19 16:22:32 +0800385 icv = skb_put(skb, 4);
386
387 crc = ~crc32_le(~0, pos, len);
388 icv[0] = crc;
389 icv[1] = crc >> 8;
390 icv[2] = crc >> 16;
391 icv[3] = crc >> 24;
392
Jeff Garzik28eb1772006-09-22 20:10:23 -0400393 crypto_blkcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
Jens Axboefa05f122007-10-22 19:44:26 +0200394 sg_init_one(&sg, pos, len + 4);
Herbert Xuf12cc202006-08-22 20:36:13 +1000395 return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
Zhu Yib4328d82006-08-21 11:33:09 +0800396}
397
Jeff Garzik18379872006-09-22 21:19:05 -0400398/*
399 * deal with seq counter wrapping correctly.
400 * refer to timer_after() for jiffies wrapping handling
401 */
402static inline int tkip_replay_check(u32 iv32_n, u16 iv16_n,
403 u32 iv32_o, u16 iv16_o)
404{
405 if ((s32)iv32_n - (s32)iv32_o < 0 ||
406 (iv32_n == iv32_o && iv16_n <= iv16_o))
407 return 1;
408 return 0;
409}
410
Jeff Garzikb4538722005-05-12 22:48:20 -0400411static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
412{
413 struct ieee80211_tkip_data *tkey = priv;
Jeff Garzik28eb1772006-09-22 20:10:23 -0400414 struct blkcipher_desc desc = { .tfm = tkey->rx_tfm_arc4 };
Jeff Garzikb4538722005-05-12 22:48:20 -0400415 u8 rc4key[16];
416 u8 keyidx, *pos;
417 u32 iv32;
418 u16 iv16;
James Ketrenosee34af32005-09-21 11:54:36 -0500419 struct ieee80211_hdr_4addr *hdr;
Jeff Garzikb4538722005-05-12 22:48:20 -0400420 u8 icv[4];
421 u32 crc;
422 struct scatterlist sg;
423 int plen;
Joe Perches0795af52007-10-03 17:59:30 -0700424 DECLARE_MAC_BUF(mac);
Jeff Garzikb4538722005-05-12 22:48:20 -0400425
James Ketrenosee34af32005-09-21 11:54:36 -0500426 hdr = (struct ieee80211_hdr_4addr *)skb->data;
James Ketrenos20d64712005-09-21 11:53:43 -0500427
James Ketrenos6eb6edf2005-09-22 10:34:15 +0000428 if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
James Ketrenos20d64712005-09-21 11:53:43 -0500429 if (net_ratelimit()) {
Zhu Yi9184d932006-01-19 16:22:32 +0800430 printk(KERN_DEBUG ": TKIP countermeasures: dropped "
Joe Perches0795af52007-10-03 17:59:30 -0700431 "received packet from %s\n",
432 print_mac(mac, 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"
Joe Perches0795af52007-10-03 17:59:30 -0700445 " flag from %s\n", print_mac(mac, 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()) {
Joe Perches0795af52007-10-03 17:59:30 -0700457 printk(KERN_DEBUG "TKIP: received packet from %s"
Jeff Garzikb4538722005-05-12 22:48:20 -0400458 " with keyid=%d that does not have a configured"
Joe Perches0795af52007-10-03 17:59:30 -0700459 " key\n", print_mac(mac, 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)) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400468 if (net_ratelimit()) {
Joe Perches0795af52007-10-03 17:59:30 -0700469 IEEE80211_DEBUG_DROP("TKIP: replay detected: STA=%s"
Jeff Garzikb4538722005-05-12 22:48:20 -0400470 " previous TSC %08x%04x received TSC "
Joe Perches0795af52007-10-03 17:59:30 -0700471 "%08x%04x\n", print_mac(mac, hdr->addr2),
Jeff Garzikb4538722005-05-12 22:48:20 -0400472 tkey->rx_iv32, tkey->rx_iv16, iv32, iv16);
473 }
474 tkey->dot11RSNAStatsTKIPReplays++;
475 return -4;
476 }
477
478 if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) {
479 tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32);
480 tkey->rx_phase1_done = 1;
481 }
482 tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16);
483
484 plen = skb->len - hdr_len - 12;
485
Jeff Garzik28eb1772006-09-22 20:10:23 -0400486 crypto_blkcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
Jens Axboefa05f122007-10-22 19:44:26 +0200487 sg_init_one(&sg, pos, plen + 4);
Herbert Xuf12cc202006-08-22 20:36:13 +1000488 if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) {
489 if (net_ratelimit()) {
490 printk(KERN_DEBUG ": TKIP: failed to decrypt "
Joe Perches0795af52007-10-03 17:59:30 -0700491 "received packet from %s\n",
492 print_mac(mac, hdr->addr2));
Herbert Xuf12cc202006-08-22 20:36:13 +1000493 }
494 return -7;
495 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400496
497 crc = ~crc32_le(~0, pos, plen);
498 icv[0] = crc;
499 icv[1] = crc >> 8;
500 icv[2] = crc >> 16;
501 icv[3] = crc >> 24;
502 if (memcmp(icv, pos + plen, 4) != 0) {
503 if (iv32 != tkey->rx_iv32) {
504 /* Previously cached Phase1 result was already lost, so
505 * it needs to be recalculated for the next packet. */
506 tkey->rx_phase1_done = 0;
507 }
508 if (net_ratelimit()) {
Larry Fingeraeb998c2007-04-09 11:24:41 -0500509 IEEE80211_DEBUG_DROP("TKIP: ICV error detected: STA="
Joe Perches0795af52007-10-03 17:59:30 -0700510 "%s\n", print_mac(mac, hdr->addr2));
Jeff Garzikb4538722005-05-12 22:48:20 -0400511 }
512 tkey->dot11RSNAStatsTKIPICVErrors++;
513 return -5;
514 }
515
516 /* Update real counters only after Michael MIC verification has
517 * completed */
518 tkey->rx_iv32_new = iv32;
519 tkey->rx_iv16_new = iv16;
520
521 /* Remove IV and ICV */
522 memmove(skb->data + 8, skb->data, hdr_len);
523 skb_pull(skb, 8);
524 skb_trim(skb, skb->len - 4);
525
526 return keyidx;
527}
528
Jeff Garzik28eb1772006-09-22 20:10:23 -0400529static int michael_mic(struct crypto_hash *tfm_michael, u8 * key, u8 * hdr,
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400530 u8 * data, size_t data_len, u8 * mic)
Jeff Garzikb4538722005-05-12 22:48:20 -0400531{
Herbert Xu35058682006-08-24 19:10:20 +1000532 struct hash_desc desc;
Jeff Garzikb4538722005-05-12 22:48:20 -0400533 struct scatterlist sg[2];
534
Zhu Yi5a656942006-08-21 11:33:56 +0800535 if (tfm_michael == NULL) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400536 printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n");
537 return -1;
538 }
Jens Axboefa05f122007-10-22 19:44:26 +0200539 sg_init_table(sg, 2);
540 sg_set_page(&sg[0], virt_to_page(hdr));
Jeff Garzikb4538722005-05-12 22:48:20 -0400541 sg[0].offset = offset_in_page(hdr);
542 sg[0].length = 16;
543
Jens Axboefa05f122007-10-22 19:44:26 +0200544 sg_set_page(&sg[1], virt_to_page(data));
Jeff Garzikb4538722005-05-12 22:48:20 -0400545 sg[1].offset = offset_in_page(data);
546 sg[1].length = data_len;
547
Jeff Garzik28eb1772006-09-22 20:10:23 -0400548 if (crypto_hash_setkey(tfm_michael, key, 8))
Herbert Xu35058682006-08-24 19:10:20 +1000549 return -1;
Jeff Garzikb4538722005-05-12 22:48:20 -0400550
Jeff Garzik28eb1772006-09-22 20:10:23 -0400551 desc.tfm = tfm_michael;
Herbert Xu35058682006-08-24 19:10:20 +1000552 desc.flags = 0;
553 return crypto_hash_digest(&desc, sg, data_len + 16, mic);
Jeff Garzikb4538722005-05-12 22:48:20 -0400554}
555
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400556static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr)
Jeff Garzikb4538722005-05-12 22:48:20 -0400557{
James Ketrenosee34af32005-09-21 11:54:36 -0500558 struct ieee80211_hdr_4addr *hdr11;
Zhu Yiea284152006-04-13 17:17:06 +0800559 u16 stype;
Jeff Garzikb4538722005-05-12 22:48:20 -0400560
James Ketrenosee34af32005-09-21 11:54:36 -0500561 hdr11 = (struct ieee80211_hdr_4addr *)skb->data;
Zhu Yiea284152006-04-13 17:17:06 +0800562 stype = WLAN_FC_GET_STYPE(le16_to_cpu(hdr11->frame_ctl));
563
Jeff Garzikb4538722005-05-12 22:48:20 -0400564 switch (le16_to_cpu(hdr11->frame_ctl) &
565 (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
566 case IEEE80211_FCTL_TODS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400567 memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
568 memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400569 break;
570 case IEEE80211_FCTL_FROMDS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400571 memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
572 memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400573 break;
574 case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400575 memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
576 memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400577 break;
578 case 0:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400579 memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
580 memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400581 break;
582 }
583
Zhu Yiea284152006-04-13 17:17:06 +0800584 if (stype & IEEE80211_STYPE_QOS_DATA) {
585 const struct ieee80211_hdr_3addrqos *qoshdr =
586 (struct ieee80211_hdr_3addrqos *)skb->data;
Johannes Berge797aa12007-10-15 16:50:54 +0200587 hdr[12] = le16_to_cpu(qoshdr->qos_ctl) & IEEE80211_QCTL_TID;
Zhu Yiea284152006-04-13 17:17:06 +0800588 } else
589 hdr[12] = 0; /* priority */
590
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400591 hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */
Jeff Garzikb4538722005-05-12 22:48:20 -0400592}
593
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400594static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len,
595 void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400596{
597 struct ieee80211_tkip_data *tkey = priv;
598 u8 *pos;
599
600 if (skb_tailroom(skb) < 8 || skb->len < hdr_len) {
601 printk(KERN_DEBUG "Invalid packet for Michael MIC add "
602 "(tailroom=%d hdr_len=%d skb->len=%d)\n",
603 skb_tailroom(skb), hdr_len, skb->len);
604 return -1;
605 }
606
607 michael_mic_hdr(skb, tkey->tx_hdr);
608 pos = skb_put(skb, 8);
Zhu Yi5a656942006-08-21 11:33:56 +0800609 if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr,
Jeff Garzikb4538722005-05-12 22:48:20 -0400610 skb->data + hdr_len, skb->len - 8 - hdr_len, pos))
611 return -1;
612
613 return 0;
614}
615
Jeff Garzikb4538722005-05-12 22:48:20 -0400616static void ieee80211_michael_mic_failure(struct net_device *dev,
James Ketrenosee34af32005-09-21 11:54:36 -0500617 struct ieee80211_hdr_4addr *hdr,
618 int keyidx)
Jeff Garzikb4538722005-05-12 22:48:20 -0400619{
620 union iwreq_data wrqu;
621 struct iw_michaelmicfailure ev;
622
623 /* TODO: needed parameters: count, keyid, key type, TSC */
624 memset(&ev, 0, sizeof(ev));
625 ev.flags = keyidx & IW_MICFAILURE_KEY_ID;
626 if (hdr->addr1[0] & 0x01)
627 ev.flags |= IW_MICFAILURE_GROUP;
628 else
629 ev.flags |= IW_MICFAILURE_PAIRWISE;
630 ev.src_addr.sa_family = ARPHRD_ETHER;
631 memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN);
632 memset(&wrqu, 0, sizeof(wrqu));
633 wrqu.data.length = sizeof(ev);
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400634 wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev);
Jeff Garzikb4538722005-05-12 22:48:20 -0400635}
Jeff Garzikb4538722005-05-12 22:48:20 -0400636
637static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400638 int hdr_len, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400639{
640 struct ieee80211_tkip_data *tkey = priv;
641 u8 mic[8];
Joe Perches0795af52007-10-03 17:59:30 -0700642 DECLARE_MAC_BUF(mac);
Jeff Garzikb4538722005-05-12 22:48:20 -0400643
644 if (!tkey->key_set)
645 return -1;
646
647 michael_mic_hdr(skb, tkey->rx_hdr);
Zhu Yi5a656942006-08-21 11:33:56 +0800648 if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr,
Jeff Garzikb4538722005-05-12 22:48:20 -0400649 skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
650 return -1;
651 if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
James Ketrenosee34af32005-09-21 11:54:36 -0500652 struct ieee80211_hdr_4addr *hdr;
653 hdr = (struct ieee80211_hdr_4addr *)skb->data;
Jeff Garzikb4538722005-05-12 22:48:20 -0400654 printk(KERN_DEBUG "%s: Michael MIC verification failed for "
Joe Perches0795af52007-10-03 17:59:30 -0700655 "MSDU from %s keyidx=%d\n",
656 skb->dev ? skb->dev->name : "N/A", print_mac(mac, hdr->addr2),
Jeff Garzikb4538722005-05-12 22:48:20 -0400657 keyidx);
658 if (skb->dev)
659 ieee80211_michael_mic_failure(skb->dev, hdr, keyidx);
660 tkey->dot11RSNAStatsTKIPLocalMICFailures++;
661 return -1;
662 }
663
664 /* Update TSC counters for RX now that the packet verification has
665 * completed. */
666 tkey->rx_iv32 = tkey->rx_iv32_new;
667 tkey->rx_iv16 = tkey->rx_iv16_new;
668
669 skb_trim(skb, skb->len - 8);
670
671 return 0;
672}
673
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400674static int ieee80211_tkip_set_key(void *key, int len, u8 * seq, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400675{
676 struct ieee80211_tkip_data *tkey = priv;
677 int keyidx;
Jeff Garzik28eb1772006-09-22 20:10:23 -0400678 struct crypto_hash *tfm = tkey->tx_tfm_michael;
679 struct crypto_blkcipher *tfm2 = tkey->tx_tfm_arc4;
680 struct crypto_hash *tfm3 = tkey->rx_tfm_michael;
681 struct crypto_blkcipher *tfm4 = tkey->rx_tfm_arc4;
Jeff Garzikb4538722005-05-12 22:48:20 -0400682
683 keyidx = tkey->key_idx;
684 memset(tkey, 0, sizeof(*tkey));
685 tkey->key_idx = keyidx;
Zhu Yi5a656942006-08-21 11:33:56 +0800686 tkey->tx_tfm_michael = tfm;
687 tkey->tx_tfm_arc4 = tfm2;
688 tkey->rx_tfm_michael = tfm3;
689 tkey->rx_tfm_arc4 = tfm4;
Jeff Garzikb4538722005-05-12 22:48:20 -0400690 if (len == TKIP_KEY_LEN) {
691 memcpy(tkey->key, key, TKIP_KEY_LEN);
692 tkey->key_set = 1;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400693 tkey->tx_iv16 = 1; /* TSC is initialized to 1 */
Jeff Garzikb4538722005-05-12 22:48:20 -0400694 if (seq) {
695 tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) |
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400696 (seq[3] << 8) | seq[2];
Jeff Garzikb4538722005-05-12 22:48:20 -0400697 tkey->rx_iv16 = (seq[1] << 8) | seq[0];
698 }
699 } else if (len == 0)
700 tkey->key_set = 0;
701 else
702 return -1;
703
704 return 0;
705}
706
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400707static int ieee80211_tkip_get_key(void *key, int len, u8 * seq, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400708{
709 struct ieee80211_tkip_data *tkey = priv;
710
711 if (len < TKIP_KEY_LEN)
712 return -1;
713
714 if (!tkey->key_set)
715 return 0;
716 memcpy(key, tkey->key, TKIP_KEY_LEN);
717
718 if (seq) {
719 /* Return the sequence number of the last transmitted frame. */
720 u16 iv16 = tkey->tx_iv16;
721 u32 iv32 = tkey->tx_iv32;
722 if (iv16 == 0)
723 iv32--;
724 iv16--;
725 seq[0] = tkey->tx_iv16;
726 seq[1] = tkey->tx_iv16 >> 8;
727 seq[2] = tkey->tx_iv32;
728 seq[3] = tkey->tx_iv32 >> 8;
729 seq[4] = tkey->tx_iv32 >> 16;
730 seq[5] = tkey->tx_iv32 >> 24;
731 }
732
733 return TKIP_KEY_LEN;
734}
735
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400736static char *ieee80211_tkip_print_stats(char *p, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400737{
738 struct ieee80211_tkip_data *tkip = priv;
739 p += sprintf(p, "key[%d] alg=TKIP key_set=%d "
740 "tx_pn=%02x%02x%02x%02x%02x%02x "
741 "rx_pn=%02x%02x%02x%02x%02x%02x "
742 "replays=%d icv_errors=%d local_mic_failures=%d\n",
743 tkip->key_idx, tkip->key_set,
744 (tkip->tx_iv32 >> 24) & 0xff,
745 (tkip->tx_iv32 >> 16) & 0xff,
746 (tkip->tx_iv32 >> 8) & 0xff,
747 tkip->tx_iv32 & 0xff,
748 (tkip->tx_iv16 >> 8) & 0xff,
749 tkip->tx_iv16 & 0xff,
750 (tkip->rx_iv32 >> 24) & 0xff,
751 (tkip->rx_iv32 >> 16) & 0xff,
752 (tkip->rx_iv32 >> 8) & 0xff,
753 tkip->rx_iv32 & 0xff,
754 (tkip->rx_iv16 >> 8) & 0xff,
755 tkip->rx_iv16 & 0xff,
756 tkip->dot11RSNAStatsTKIPReplays,
757 tkip->dot11RSNAStatsTKIPICVErrors,
758 tkip->dot11RSNAStatsTKIPLocalMICFailures);
759 return p;
760}
761
Jeff Garzikb4538722005-05-12 22:48:20 -0400762static struct ieee80211_crypto_ops ieee80211_crypt_tkip = {
James Ketrenos74079fd2005-09-13 17:35:21 -0500763 .name = "TKIP",
764 .init = ieee80211_tkip_init,
765 .deinit = ieee80211_tkip_deinit,
Zhu Yi9184d932006-01-19 16:22:32 +0800766 .build_iv = ieee80211_tkip_hdr,
James Ketrenos74079fd2005-09-13 17:35:21 -0500767 .encrypt_mpdu = ieee80211_tkip_encrypt,
768 .decrypt_mpdu = ieee80211_tkip_decrypt,
769 .encrypt_msdu = ieee80211_michael_mic_add,
770 .decrypt_msdu = ieee80211_michael_mic_verify,
771 .set_key = ieee80211_tkip_set_key,
772 .get_key = ieee80211_tkip_get_key,
773 .print_stats = ieee80211_tkip_print_stats,
James Ketrenos1264fc02005-09-21 11:54:53 -0500774 .extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */
775 .extra_mpdu_postfix_len = 4, /* ICV */
776 .extra_msdu_postfix_len = 8, /* MIC */
James Ketrenos6eb6edf2005-09-22 10:34:15 +0000777 .get_flags = ieee80211_tkip_get_flags,
778 .set_flags = ieee80211_tkip_set_flags,
James Ketrenos74079fd2005-09-13 17:35:21 -0500779 .owner = THIS_MODULE,
Jeff Garzikb4538722005-05-12 22:48:20 -0400780};
781
Jeff Garzikb4538722005-05-12 22:48:20 -0400782static int __init ieee80211_crypto_tkip_init(void)
783{
784 return ieee80211_register_crypto_ops(&ieee80211_crypt_tkip);
785}
786
Jeff Garzikb4538722005-05-12 22:48:20 -0400787static void __exit ieee80211_crypto_tkip_exit(void)
788{
789 ieee80211_unregister_crypto_ops(&ieee80211_crypt_tkip);
790}
791
Jeff Garzikb4538722005-05-12 22:48:20 -0400792module_init(ieee80211_crypto_tkip_init);
793module_exit(ieee80211_crypto_tkip_exit);