blob: f973d6cb8248705b02fe1955a16af7f43fb1825a [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 *
4 * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
5 *
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
12#include <linux/config.h>
13#include <linux/version.h>
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/slab.h>
17#include <linux/random.h>
18#include <linux/skbuff.h>
19#include <linux/netdevice.h>
20#include <linux/if_ether.h>
21#include <linux/if_arp.h>
22#include <asm/string.h>
23
24#include <net/ieee80211.h>
25
Jeff Garzikb4538722005-05-12 22:48:20 -040026#include <linux/crypto.h>
27#include <asm/scatterlist.h>
28#include <linux/crc32.h>
29
30MODULE_AUTHOR("Jouni Malinen");
31MODULE_DESCRIPTION("Host AP crypt: TKIP");
32MODULE_LICENSE("GPL");
33
34struct ieee80211_tkip_data {
35#define TKIP_KEY_LEN 32
36 u8 key[TKIP_KEY_LEN];
37 int key_set;
38
39 u32 tx_iv32;
40 u16 tx_iv16;
41 u16 tx_ttak[5];
42 int tx_phase1_done;
43
44 u32 rx_iv32;
45 u16 rx_iv16;
46 u16 rx_ttak[5];
47 int rx_phase1_done;
48 u32 rx_iv32_new;
49 u16 rx_iv16_new;
50
51 u32 dot11RSNAStatsTKIPReplays;
52 u32 dot11RSNAStatsTKIPICVErrors;
53 u32 dot11RSNAStatsTKIPLocalMICFailures;
54
55 int key_idx;
56
57 struct crypto_tfm *tfm_arc4;
58 struct crypto_tfm *tfm_michael;
59
60 /* scratch buffers for virt_to_page() (crypto API) */
61 u8 rx_hdr[16], tx_hdr[16];
James Ketrenos20d64712005-09-21 11:53:43 -050062
63 struct ieee80211_device *ieee;
Jeff Garzikb4538722005-05-12 22:48:20 -040064};
65
James Ketrenos20d64712005-09-21 11:53:43 -050066static void *ieee80211_tkip_init(struct ieee80211_device *ieee, int key_idx)
Jeff Garzikb4538722005-05-12 22:48:20 -040067{
68 struct ieee80211_tkip_data *priv;
69
70 priv = kmalloc(sizeof(*priv), GFP_ATOMIC);
71 if (priv == NULL)
72 goto fail;
73 memset(priv, 0, sizeof(*priv));
James Ketrenos20d64712005-09-21 11:53:43 -050074
75 priv->ieee = ieee;
76
Jeff Garzikb4538722005-05-12 22:48:20 -040077 priv->key_idx = key_idx;
78
79 priv->tfm_arc4 = crypto_alloc_tfm("arc4", 0);
80 if (priv->tfm_arc4 == NULL) {
81 printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
82 "crypto API arc4\n");
83 goto fail;
84 }
85
86 priv->tfm_michael = crypto_alloc_tfm("michael_mic", 0);
87 if (priv->tfm_michael == NULL) {
88 printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
89 "crypto API michael_mic\n");
90 goto fail;
91 }
92
93 return priv;
94
Jeff Garzik0edd5b42005-09-07 00:48:31 -040095 fail:
Jeff Garzikb4538722005-05-12 22:48:20 -040096 if (priv) {
97 if (priv->tfm_michael)
98 crypto_free_tfm(priv->tfm_michael);
99 if (priv->tfm_arc4)
100 crypto_free_tfm(priv->tfm_arc4);
101 kfree(priv);
102 }
103
104 return NULL;
105}
106
Jeff Garzikb4538722005-05-12 22:48:20 -0400107static void ieee80211_tkip_deinit(void *priv)
108{
109 struct ieee80211_tkip_data *_priv = priv;
110 if (_priv && _priv->tfm_michael)
111 crypto_free_tfm(_priv->tfm_michael);
112 if (_priv && _priv->tfm_arc4)
113 crypto_free_tfm(_priv->tfm_arc4);
114 kfree(priv);
115}
116
Jeff Garzikb4538722005-05-12 22:48:20 -0400117static inline u16 RotR1(u16 val)
118{
119 return (val >> 1) | (val << 15);
120}
121
Jeff Garzikb4538722005-05-12 22:48:20 -0400122static inline u8 Lo8(u16 val)
123{
124 return val & 0xff;
125}
126
Jeff Garzikb4538722005-05-12 22:48:20 -0400127static inline u8 Hi8(u16 val)
128{
129 return val >> 8;
130}
131
Jeff Garzikb4538722005-05-12 22:48:20 -0400132static inline u16 Lo16(u32 val)
133{
134 return val & 0xffff;
135}
136
Jeff Garzikb4538722005-05-12 22:48:20 -0400137static inline u16 Hi16(u32 val)
138{
139 return val >> 16;
140}
141
Jeff Garzikb4538722005-05-12 22:48:20 -0400142static inline u16 Mk16(u8 hi, u8 lo)
143{
144 return lo | (((u16) hi) << 8);
145}
146
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400147static inline u16 Mk16_le(u16 * v)
Jeff Garzikb4538722005-05-12 22:48:20 -0400148{
149 return le16_to_cpu(*v);
150}
151
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400152static const u16 Sbox[256] = {
Jeff Garzikb4538722005-05-12 22:48:20 -0400153 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
154 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
155 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
156 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
157 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
158 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
159 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
160 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
161 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
162 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
163 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
164 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
165 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
166 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
167 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
168 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
169 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
170 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
171 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
172 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
173 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
174 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
175 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
176 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
177 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
178 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
179 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
180 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
181 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
182 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
183 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
184 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
185};
186
Jeff Garzikb4538722005-05-12 22:48:20 -0400187static inline u16 _S_(u16 v)
188{
189 u16 t = Sbox[Hi8(v)];
190 return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8));
191}
192
Jeff Garzikb4538722005-05-12 22:48:20 -0400193#define PHASE1_LOOP_COUNT 8
194
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400195static void tkip_mixing_phase1(u16 * TTAK, const u8 * TK, const u8 * TA,
196 u32 IV32)
Jeff Garzikb4538722005-05-12 22:48:20 -0400197{
198 int i, j;
199
200 /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */
201 TTAK[0] = Lo16(IV32);
202 TTAK[1] = Hi16(IV32);
203 TTAK[2] = Mk16(TA[1], TA[0]);
204 TTAK[3] = Mk16(TA[3], TA[2]);
205 TTAK[4] = Mk16(TA[5], TA[4]);
206
207 for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
208 j = 2 * (i & 1);
209 TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j]));
210 TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j]));
211 TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j]));
212 TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j]));
213 TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i;
214 }
215}
216
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400217static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK,
Jeff Garzikb4538722005-05-12 22:48:20 -0400218 u16 IV16)
219{
220 /* Make temporary area overlap WEP seed so that the final copy can be
221 * avoided on little endian hosts. */
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400222 u16 *PPK = (u16 *) & WEPSeed[4];
Jeff Garzikb4538722005-05-12 22:48:20 -0400223
224 /* Step 1 - make copy of TTAK and bring in TSC */
225 PPK[0] = TTAK[0];
226 PPK[1] = TTAK[1];
227 PPK[2] = TTAK[2];
228 PPK[3] = TTAK[3];
229 PPK[4] = TTAK[4];
230 PPK[5] = TTAK[4] + IV16;
231
232 /* Step 2 - 96-bit bijective mixing using S-box */
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400233 PPK[0] += _S_(PPK[5] ^ Mk16_le((u16 *) & TK[0]));
234 PPK[1] += _S_(PPK[0] ^ Mk16_le((u16 *) & TK[2]));
235 PPK[2] += _S_(PPK[1] ^ Mk16_le((u16 *) & TK[4]));
236 PPK[3] += _S_(PPK[2] ^ Mk16_le((u16 *) & TK[6]));
237 PPK[4] += _S_(PPK[3] ^ Mk16_le((u16 *) & TK[8]));
238 PPK[5] += _S_(PPK[4] ^ Mk16_le((u16 *) & TK[10]));
Jeff Garzikb4538722005-05-12 22:48:20 -0400239
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400240 PPK[0] += RotR1(PPK[5] ^ Mk16_le((u16 *) & TK[12]));
241 PPK[1] += RotR1(PPK[0] ^ Mk16_le((u16 *) & TK[14]));
Jeff Garzikb4538722005-05-12 22:48:20 -0400242 PPK[2] += RotR1(PPK[1]);
243 PPK[3] += RotR1(PPK[2]);
244 PPK[4] += RotR1(PPK[3]);
245 PPK[5] += RotR1(PPK[4]);
246
247 /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value
248 * WEPSeed[0..2] is transmitted as WEP IV */
249 WEPSeed[0] = Hi8(IV16);
250 WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F;
251 WEPSeed[2] = Lo8(IV16);
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400252 WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((u16 *) & TK[0])) >> 1);
Jeff Garzikb4538722005-05-12 22:48:20 -0400253
254#ifdef __BIG_ENDIAN
255 {
256 int i;
257 for (i = 0; i < 6; i++)
258 PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8);
259 }
260#endif
261}
262
263static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
264{
265 struct ieee80211_tkip_data *tkey = priv;
266 int len;
267 u8 rc4key[16], *pos, *icv;
James Ketrenosee34af32005-09-21 11:54:36 -0500268 struct ieee80211_hdr_4addr *hdr;
Jeff Garzikb4538722005-05-12 22:48:20 -0400269 u32 crc;
270 struct scatterlist sg;
271
James Ketrenosee34af32005-09-21 11:54:36 -0500272 hdr = (struct ieee80211_hdr_4addr *)skb->data;
James Ketrenos20d64712005-09-21 11:53:43 -0500273
274 if (tkey->ieee->tkip_countermeasures) {
275 if (net_ratelimit()) {
276 printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
277 "TX packet to " MAC_FMT "\n",
278 tkey->ieee->dev->name, MAC_ARG(hdr->addr1));
279 }
280 return -1;
281 }
282
Jeff Garzikb4538722005-05-12 22:48:20 -0400283 if (skb_headroom(skb) < 8 || skb_tailroom(skb) < 4 ||
284 skb->len < hdr_len)
285 return -1;
286
Jeff Garzikb4538722005-05-12 22:48:20 -0400287 if (!tkey->tx_phase1_done) {
288 tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2,
289 tkey->tx_iv32);
290 tkey->tx_phase1_done = 1;
291 }
292 tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16);
293
294 len = skb->len - hdr_len;
295 pos = skb_push(skb, 8);
296 memmove(pos, pos + 8, hdr_len);
297 pos += hdr_len;
298 icv = skb_put(skb, 4);
299
300 *pos++ = rc4key[0];
301 *pos++ = rc4key[1];
302 *pos++ = rc4key[2];
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400303 *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */ ;
Jeff Garzikb4538722005-05-12 22:48:20 -0400304 *pos++ = tkey->tx_iv32 & 0xff;
305 *pos++ = (tkey->tx_iv32 >> 8) & 0xff;
306 *pos++ = (tkey->tx_iv32 >> 16) & 0xff;
307 *pos++ = (tkey->tx_iv32 >> 24) & 0xff;
308
309 crc = ~crc32_le(~0, pos, len);
310 icv[0] = crc;
311 icv[1] = crc >> 8;
312 icv[2] = crc >> 16;
313 icv[3] = crc >> 24;
314
315 crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16);
316 sg.page = virt_to_page(pos);
317 sg.offset = offset_in_page(pos);
318 sg.length = len + 4;
319 crypto_cipher_encrypt(tkey->tfm_arc4, &sg, &sg, len + 4);
320
321 tkey->tx_iv16++;
322 if (tkey->tx_iv16 == 0) {
323 tkey->tx_phase1_done = 0;
324 tkey->tx_iv32++;
325 }
326
327 return 0;
328}
329
330static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
331{
332 struct ieee80211_tkip_data *tkey = priv;
333 u8 rc4key[16];
334 u8 keyidx, *pos;
335 u32 iv32;
336 u16 iv16;
James Ketrenosee34af32005-09-21 11:54:36 -0500337 struct ieee80211_hdr_4addr *hdr;
Jeff Garzikb4538722005-05-12 22:48:20 -0400338 u8 icv[4];
339 u32 crc;
340 struct scatterlist sg;
341 int plen;
342
James Ketrenosee34af32005-09-21 11:54:36 -0500343 hdr = (struct ieee80211_hdr_4addr *)skb->data;
James Ketrenos20d64712005-09-21 11:53:43 -0500344
345 if (tkey->ieee->tkip_countermeasures) {
346 if (net_ratelimit()) {
347 printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
348 "received packet from " MAC_FMT "\n",
349 tkey->ieee->dev->name, MAC_ARG(hdr->addr2));
350 }
351 return -1;
352 }
353
Jeff Garzikb4538722005-05-12 22:48:20 -0400354 if (skb->len < hdr_len + 8 + 4)
355 return -1;
356
Jeff Garzikb4538722005-05-12 22:48:20 -0400357 pos = skb->data + hdr_len;
358 keyidx = pos[3];
359 if (!(keyidx & (1 << 5))) {
360 if (net_ratelimit()) {
361 printk(KERN_DEBUG "TKIP: received packet without ExtIV"
362 " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2));
363 }
364 return -2;
365 }
366 keyidx >>= 6;
367 if (tkey->key_idx != keyidx) {
368 printk(KERN_DEBUG "TKIP: RX tkey->key_idx=%d frame "
369 "keyidx=%d priv=%p\n", tkey->key_idx, keyidx, priv);
370 return -6;
371 }
372 if (!tkey->key_set) {
373 if (net_ratelimit()) {
374 printk(KERN_DEBUG "TKIP: received packet from " MAC_FMT
375 " with keyid=%d that does not have a configured"
376 " key\n", MAC_ARG(hdr->addr2), keyidx);
377 }
378 return -3;
379 }
380 iv16 = (pos[0] << 8) | pos[2];
381 iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
382 pos += 8;
383
384 if (iv32 < tkey->rx_iv32 ||
385 (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) {
386 if (net_ratelimit()) {
387 printk(KERN_DEBUG "TKIP: replay detected: STA=" MAC_FMT
388 " previous TSC %08x%04x received TSC "
389 "%08x%04x\n", MAC_ARG(hdr->addr2),
390 tkey->rx_iv32, tkey->rx_iv16, iv32, iv16);
391 }
392 tkey->dot11RSNAStatsTKIPReplays++;
393 return -4;
394 }
395
396 if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) {
397 tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32);
398 tkey->rx_phase1_done = 1;
399 }
400 tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16);
401
402 plen = skb->len - hdr_len - 12;
403
404 crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16);
405 sg.page = virt_to_page(pos);
406 sg.offset = offset_in_page(pos);
407 sg.length = plen + 4;
408 crypto_cipher_decrypt(tkey->tfm_arc4, &sg, &sg, plen + 4);
409
410 crc = ~crc32_le(~0, pos, plen);
411 icv[0] = crc;
412 icv[1] = crc >> 8;
413 icv[2] = crc >> 16;
414 icv[3] = crc >> 24;
415 if (memcmp(icv, pos + plen, 4) != 0) {
416 if (iv32 != tkey->rx_iv32) {
417 /* Previously cached Phase1 result was already lost, so
418 * it needs to be recalculated for the next packet. */
419 tkey->rx_phase1_done = 0;
420 }
421 if (net_ratelimit()) {
422 printk(KERN_DEBUG "TKIP: ICV error detected: STA="
423 MAC_FMT "\n", MAC_ARG(hdr->addr2));
424 }
425 tkey->dot11RSNAStatsTKIPICVErrors++;
426 return -5;
427 }
428
429 /* Update real counters only after Michael MIC verification has
430 * completed */
431 tkey->rx_iv32_new = iv32;
432 tkey->rx_iv16_new = iv16;
433
434 /* Remove IV and ICV */
435 memmove(skb->data + 8, skb->data, hdr_len);
436 skb_pull(skb, 8);
437 skb_trim(skb, skb->len - 4);
438
439 return keyidx;
440}
441
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400442static int michael_mic(struct ieee80211_tkip_data *tkey, u8 * key, u8 * hdr,
443 u8 * data, size_t data_len, u8 * mic)
Jeff Garzikb4538722005-05-12 22:48:20 -0400444{
445 struct scatterlist sg[2];
446
447 if (tkey->tfm_michael == NULL) {
448 printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n");
449 return -1;
450 }
451 sg[0].page = virt_to_page(hdr);
452 sg[0].offset = offset_in_page(hdr);
453 sg[0].length = 16;
454
455 sg[1].page = virt_to_page(data);
456 sg[1].offset = offset_in_page(data);
457 sg[1].length = data_len;
458
459 crypto_digest_init(tkey->tfm_michael);
460 crypto_digest_setkey(tkey->tfm_michael, key, 8);
461 crypto_digest_update(tkey->tfm_michael, sg, 2);
462 crypto_digest_final(tkey->tfm_michael, mic);
463
464 return 0;
465}
466
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400467static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr)
Jeff Garzikb4538722005-05-12 22:48:20 -0400468{
James Ketrenosee34af32005-09-21 11:54:36 -0500469 struct ieee80211_hdr_4addr *hdr11;
Jeff Garzikb4538722005-05-12 22:48:20 -0400470
James Ketrenosee34af32005-09-21 11:54:36 -0500471 hdr11 = (struct ieee80211_hdr_4addr *)skb->data;
Jeff Garzikb4538722005-05-12 22:48:20 -0400472 switch (le16_to_cpu(hdr11->frame_ctl) &
473 (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
474 case IEEE80211_FCTL_TODS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400475 memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
476 memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400477 break;
478 case IEEE80211_FCTL_FROMDS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400479 memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
480 memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400481 break;
482 case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400483 memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
484 memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400485 break;
486 case 0:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400487 memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
488 memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400489 break;
490 }
491
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400492 hdr[12] = 0; /* priority */
493 hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */
Jeff Garzikb4538722005-05-12 22:48:20 -0400494}
495
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400496static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len,
497 void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400498{
499 struct ieee80211_tkip_data *tkey = priv;
500 u8 *pos;
501
502 if (skb_tailroom(skb) < 8 || skb->len < hdr_len) {
503 printk(KERN_DEBUG "Invalid packet for Michael MIC add "
504 "(tailroom=%d hdr_len=%d skb->len=%d)\n",
505 skb_tailroom(skb), hdr_len, skb->len);
506 return -1;
507 }
508
509 michael_mic_hdr(skb, tkey->tx_hdr);
510 pos = skb_put(skb, 8);
511 if (michael_mic(tkey, &tkey->key[16], tkey->tx_hdr,
512 skb->data + hdr_len, skb->len - 8 - hdr_len, pos))
513 return -1;
514
515 return 0;
516}
517
Jeff Garzikb4538722005-05-12 22:48:20 -0400518#if WIRELESS_EXT >= 18
519static void ieee80211_michael_mic_failure(struct net_device *dev,
James Ketrenosee34af32005-09-21 11:54:36 -0500520 struct ieee80211_hdr_4addr *hdr,
521 int keyidx)
Jeff Garzikb4538722005-05-12 22:48:20 -0400522{
523 union iwreq_data wrqu;
524 struct iw_michaelmicfailure ev;
525
526 /* TODO: needed parameters: count, keyid, key type, TSC */
527 memset(&ev, 0, sizeof(ev));
528 ev.flags = keyidx & IW_MICFAILURE_KEY_ID;
529 if (hdr->addr1[0] & 0x01)
530 ev.flags |= IW_MICFAILURE_GROUP;
531 else
532 ev.flags |= IW_MICFAILURE_PAIRWISE;
533 ev.src_addr.sa_family = ARPHRD_ETHER;
534 memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN);
535 memset(&wrqu, 0, sizeof(wrqu));
536 wrqu.data.length = sizeof(ev);
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400537 wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev);
Jeff Garzikb4538722005-05-12 22:48:20 -0400538}
539#elif WIRELESS_EXT >= 15
540static void ieee80211_michael_mic_failure(struct net_device *dev,
James Ketrenosee34af32005-09-21 11:54:36 -0500541 struct ieee80211_hdr_4addr *hdr,
542 int keyidx)
Jeff Garzikb4538722005-05-12 22:48:20 -0400543{
544 union iwreq_data wrqu;
545 char buf[128];
546
547 /* TODO: needed parameters: count, keyid, key type, TSC */
548 sprintf(buf, "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr="
549 MAC_FMT ")", keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni",
550 MAC_ARG(hdr->addr2));
551 memset(&wrqu, 0, sizeof(wrqu));
552 wrqu.data.length = strlen(buf);
553 wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
554}
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400555#else /* WIRELESS_EXT >= 15 */
James Ketrenosee34af32005-09-21 11:54:36 -0500556static inline void ieee80211_michael_mic_failure(struct net_device *dev, struct ieee80211_hdr_4addr
557 *hdr, int keyidx)
Jeff Garzikb4538722005-05-12 22:48:20 -0400558{
559}
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400560#endif /* WIRELESS_EXT >= 15 */
Jeff Garzikb4538722005-05-12 22:48:20 -0400561
562static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400563 int hdr_len, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400564{
565 struct ieee80211_tkip_data *tkey = priv;
566 u8 mic[8];
567
568 if (!tkey->key_set)
569 return -1;
570
571 michael_mic_hdr(skb, tkey->rx_hdr);
572 if (michael_mic(tkey, &tkey->key[24], tkey->rx_hdr,
573 skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
574 return -1;
575 if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
James Ketrenosee34af32005-09-21 11:54:36 -0500576 struct ieee80211_hdr_4addr *hdr;
577 hdr = (struct ieee80211_hdr_4addr *)skb->data;
Jeff Garzikb4538722005-05-12 22:48:20 -0400578 printk(KERN_DEBUG "%s: Michael MIC verification failed for "
579 "MSDU from " MAC_FMT " keyidx=%d\n",
580 skb->dev ? skb->dev->name : "N/A", MAC_ARG(hdr->addr2),
581 keyidx);
582 if (skb->dev)
583 ieee80211_michael_mic_failure(skb->dev, hdr, keyidx);
584 tkey->dot11RSNAStatsTKIPLocalMICFailures++;
585 return -1;
586 }
587
588 /* Update TSC counters for RX now that the packet verification has
589 * completed. */
590 tkey->rx_iv32 = tkey->rx_iv32_new;
591 tkey->rx_iv16 = tkey->rx_iv16_new;
592
593 skb_trim(skb, skb->len - 8);
594
595 return 0;
596}
597
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400598static int ieee80211_tkip_set_key(void *key, int len, u8 * seq, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400599{
600 struct ieee80211_tkip_data *tkey = priv;
601 int keyidx;
602 struct crypto_tfm *tfm = tkey->tfm_michael;
603 struct crypto_tfm *tfm2 = tkey->tfm_arc4;
604
605 keyidx = tkey->key_idx;
606 memset(tkey, 0, sizeof(*tkey));
607 tkey->key_idx = keyidx;
608 tkey->tfm_michael = tfm;
609 tkey->tfm_arc4 = tfm2;
610 if (len == TKIP_KEY_LEN) {
611 memcpy(tkey->key, key, TKIP_KEY_LEN);
612 tkey->key_set = 1;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400613 tkey->tx_iv16 = 1; /* TSC is initialized to 1 */
Jeff Garzikb4538722005-05-12 22:48:20 -0400614 if (seq) {
615 tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) |
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400616 (seq[3] << 8) | seq[2];
Jeff Garzikb4538722005-05-12 22:48:20 -0400617 tkey->rx_iv16 = (seq[1] << 8) | seq[0];
618 }
619 } else if (len == 0)
620 tkey->key_set = 0;
621 else
622 return -1;
623
624 return 0;
625}
626
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400627static int ieee80211_tkip_get_key(void *key, int len, u8 * seq, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400628{
629 struct ieee80211_tkip_data *tkey = priv;
630
631 if (len < TKIP_KEY_LEN)
632 return -1;
633
634 if (!tkey->key_set)
635 return 0;
636 memcpy(key, tkey->key, TKIP_KEY_LEN);
637
638 if (seq) {
639 /* Return the sequence number of the last transmitted frame. */
640 u16 iv16 = tkey->tx_iv16;
641 u32 iv32 = tkey->tx_iv32;
642 if (iv16 == 0)
643 iv32--;
644 iv16--;
645 seq[0] = tkey->tx_iv16;
646 seq[1] = tkey->tx_iv16 >> 8;
647 seq[2] = tkey->tx_iv32;
648 seq[3] = tkey->tx_iv32 >> 8;
649 seq[4] = tkey->tx_iv32 >> 16;
650 seq[5] = tkey->tx_iv32 >> 24;
651 }
652
653 return TKIP_KEY_LEN;
654}
655
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400656static char *ieee80211_tkip_print_stats(char *p, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400657{
658 struct ieee80211_tkip_data *tkip = priv;
659 p += sprintf(p, "key[%d] alg=TKIP key_set=%d "
660 "tx_pn=%02x%02x%02x%02x%02x%02x "
661 "rx_pn=%02x%02x%02x%02x%02x%02x "
662 "replays=%d icv_errors=%d local_mic_failures=%d\n",
663 tkip->key_idx, tkip->key_set,
664 (tkip->tx_iv32 >> 24) & 0xff,
665 (tkip->tx_iv32 >> 16) & 0xff,
666 (tkip->tx_iv32 >> 8) & 0xff,
667 tkip->tx_iv32 & 0xff,
668 (tkip->tx_iv16 >> 8) & 0xff,
669 tkip->tx_iv16 & 0xff,
670 (tkip->rx_iv32 >> 24) & 0xff,
671 (tkip->rx_iv32 >> 16) & 0xff,
672 (tkip->rx_iv32 >> 8) & 0xff,
673 tkip->rx_iv32 & 0xff,
674 (tkip->rx_iv16 >> 8) & 0xff,
675 tkip->rx_iv16 & 0xff,
676 tkip->dot11RSNAStatsTKIPReplays,
677 tkip->dot11RSNAStatsTKIPICVErrors,
678 tkip->dot11RSNAStatsTKIPLocalMICFailures);
679 return p;
680}
681
Jeff Garzikb4538722005-05-12 22:48:20 -0400682static struct ieee80211_crypto_ops ieee80211_crypt_tkip = {
James Ketrenos74079fd2005-09-13 17:35:21 -0500683 .name = "TKIP",
684 .init = ieee80211_tkip_init,
685 .deinit = ieee80211_tkip_deinit,
686 .encrypt_mpdu = ieee80211_tkip_encrypt,
687 .decrypt_mpdu = ieee80211_tkip_decrypt,
688 .encrypt_msdu = ieee80211_michael_mic_add,
689 .decrypt_msdu = ieee80211_michael_mic_verify,
690 .set_key = ieee80211_tkip_set_key,
691 .get_key = ieee80211_tkip_get_key,
692 .print_stats = ieee80211_tkip_print_stats,
James Ketrenos1264fc02005-09-21 11:54:53 -0500693 .extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */
694 .extra_mpdu_postfix_len = 4, /* ICV */
695 .extra_msdu_postfix_len = 8, /* MIC */
James Ketrenos74079fd2005-09-13 17:35:21 -0500696 .owner = THIS_MODULE,
Jeff Garzikb4538722005-05-12 22:48:20 -0400697};
698
Jeff Garzikb4538722005-05-12 22:48:20 -0400699static int __init ieee80211_crypto_tkip_init(void)
700{
701 return ieee80211_register_crypto_ops(&ieee80211_crypt_tkip);
702}
703
Jeff Garzikb4538722005-05-12 22:48:20 -0400704static void __exit ieee80211_crypto_tkip_exit(void)
705{
706 ieee80211_unregister_crypto_ops(&ieee80211_crypt_tkip);
707}
708
Jeff Garzikb4538722005-05-12 22:48:20 -0400709module_init(ieee80211_crypto_tkip_init);
710module_exit(ieee80211_crypto_tkip_exit);