blob: 8c90ba79e56e33bfefba9b014d35f7d48bbe45ed [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
Joe Perchese9c02682010-11-16 19:56:49 -080013#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14
Herbert Xuf12cc202006-08-22 20:36:13 +100015#include <linux/err.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040016#include <linux/module.h>
17#include <linux/init.h>
18#include <linux/slab.h>
19#include <linux/random.h>
Ralf Baechle11763602007-10-23 20:42:11 +020020#include <linux/scatterlist.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040021#include <linux/skbuff.h>
22#include <linux/netdevice.h>
Al Virod7fe0f22006-12-03 23:15:30 -050023#include <linux/mm.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040024#include <linux/if_ether.h>
25#include <linux/if_arp.h>
26#include <asm/string.h>
27
John W. Linville274bfb82008-10-29 11:35:05 -040028#include <linux/wireless.h>
29#include <linux/ieee80211.h>
30#include <net/iw_handler.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040031
Jeff Garzikb4538722005-05-12 22:48:20 -040032#include <linux/crypto.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040033#include <linux/crc32.h>
34
John W. Linville274bfb82008-10-29 11:35:05 -040035#include <net/lib80211.h>
36
Jeff Garzikb4538722005-05-12 22:48:20 -040037MODULE_AUTHOR("Jouni Malinen");
John W. Linville274bfb82008-10-29 11:35:05 -040038MODULE_DESCRIPTION("lib80211 crypt: TKIP");
Jeff Garzikb4538722005-05-12 22:48:20 -040039MODULE_LICENSE("GPL");
40
Andriy Tkachuk299af9d2010-02-02 16:33:53 +020041#define TKIP_HDR_LEN 8
42
John W. Linville274bfb82008-10-29 11:35:05 -040043struct lib80211_tkip_data {
Jeff Garzikb4538722005-05-12 22:48:20 -040044#define TKIP_KEY_LEN 32
45 u8 key[TKIP_KEY_LEN];
46 int key_set;
47
48 u32 tx_iv32;
49 u16 tx_iv16;
50 u16 tx_ttak[5];
51 int tx_phase1_done;
52
53 u32 rx_iv32;
54 u16 rx_iv16;
55 u16 rx_ttak[5];
56 int rx_phase1_done;
57 u32 rx_iv32_new;
58 u16 rx_iv16_new;
59
60 u32 dot11RSNAStatsTKIPReplays;
61 u32 dot11RSNAStatsTKIPICVErrors;
62 u32 dot11RSNAStatsTKIPLocalMICFailures;
63
64 int key_idx;
65
Jeff Garzik28eb1772006-09-22 20:10:23 -040066 struct crypto_blkcipher *rx_tfm_arc4;
67 struct crypto_hash *rx_tfm_michael;
68 struct crypto_blkcipher *tx_tfm_arc4;
69 struct crypto_hash *tx_tfm_michael;
Jeff Garzikb4538722005-05-12 22:48:20 -040070
71 /* scratch buffers for virt_to_page() (crypto API) */
72 u8 rx_hdr[16], tx_hdr[16];
James Ketrenos20d64712005-09-21 11:53:43 -050073
James Ketrenos6eb6edf2005-09-22 10:34:15 +000074 unsigned long flags;
Jeff Garzikb4538722005-05-12 22:48:20 -040075};
76
John W. Linville274bfb82008-10-29 11:35:05 -040077static unsigned long lib80211_tkip_set_flags(unsigned long flags, void *priv)
James Ketrenos6eb6edf2005-09-22 10:34:15 +000078{
John W. Linville274bfb82008-10-29 11:35:05 -040079 struct lib80211_tkip_data *_priv = priv;
James Ketrenos6eb6edf2005-09-22 10:34:15 +000080 unsigned long old_flags = _priv->flags;
81 _priv->flags = flags;
82 return old_flags;
83}
84
John W. Linville274bfb82008-10-29 11:35:05 -040085static unsigned long lib80211_tkip_get_flags(void *priv)
James Ketrenos6eb6edf2005-09-22 10:34:15 +000086{
John W. Linville274bfb82008-10-29 11:35:05 -040087 struct lib80211_tkip_data *_priv = priv;
James Ketrenos6eb6edf2005-09-22 10:34:15 +000088 return _priv->flags;
89}
90
John W. Linville274bfb82008-10-29 11:35:05 -040091static void *lib80211_tkip_init(int key_idx)
Jeff Garzikb4538722005-05-12 22:48:20 -040092{
John W. Linville274bfb82008-10-29 11:35:05 -040093 struct lib80211_tkip_data *priv;
Jeff Garzikb4538722005-05-12 22:48:20 -040094
Zhu Yi8aa914b2006-01-19 16:22:07 +080095 priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
Jeff Garzikb4538722005-05-12 22:48:20 -040096 if (priv == NULL)
97 goto fail;
James Ketrenos20d64712005-09-21 11:53:43 -050098
Jeff Garzikb4538722005-05-12 22:48:20 -040099 priv->key_idx = key_idx;
100
Jeff Garzik28eb1772006-09-22 20:10:23 -0400101 priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
Herbert Xuf12cc202006-08-22 20:36:13 +1000102 CRYPTO_ALG_ASYNC);
Jeff Garzik28eb1772006-09-22 20:10:23 -0400103 if (IS_ERR(priv->tx_tfm_arc4)) {
Jeff Garzik18379872006-09-22 21:19:05 -0400104 priv->tx_tfm_arc4 = NULL;
Jeff Garzikb4538722005-05-12 22:48:20 -0400105 goto fail;
106 }
107
Jeff Garzik28eb1772006-09-22 20:10:23 -0400108 priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
109 CRYPTO_ALG_ASYNC);
110 if (IS_ERR(priv->tx_tfm_michael)) {
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)) {
Jeff Garzik18379872006-09-22 21:19:05 -0400118 priv->rx_tfm_arc4 = NULL;
Zhu Yi5a656942006-08-21 11:33:56 +0800119 goto fail;
120 }
121
Jeff Garzik28eb1772006-09-22 20:10:23 -0400122 priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
123 CRYPTO_ALG_ASYNC);
124 if (IS_ERR(priv->rx_tfm_michael)) {
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
John W. Linville274bfb82008-10-29 11:35:05 -0400147static void lib80211_tkip_deinit(void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400148{
John W. Linville274bfb82008-10-29 11:35:05 -0400149 struct lib80211_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
Al Virod9e94d52007-12-29 05:01:07 -0500193static inline u16 Mk16_le(__le16 * 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 */
Al Virod9e94d52007-12-29 05:01:07 -0500279 PPK[0] += _S_(PPK[5] ^ Mk16_le((__le16 *) & TK[0]));
280 PPK[1] += _S_(PPK[0] ^ Mk16_le((__le16 *) & TK[2]));
281 PPK[2] += _S_(PPK[1] ^ Mk16_le((__le16 *) & TK[4]));
282 PPK[3] += _S_(PPK[2] ^ Mk16_le((__le16 *) & TK[6]));
283 PPK[4] += _S_(PPK[3] ^ Mk16_le((__le16 *) & TK[8]));
284 PPK[5] += _S_(PPK[4] ^ Mk16_le((__le16 *) & TK[10]));
Jeff Garzikb4538722005-05-12 22:48:20 -0400285
Al Virod9e94d52007-12-29 05:01:07 -0500286 PPK[0] += RotR1(PPK[5] ^ Mk16_le((__le16 *) & TK[12]));
287 PPK[1] += RotR1(PPK[0] ^ Mk16_le((__le16 *) & 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);
Al Virod9e94d52007-12-29 05:01:07 -0500298 WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((__le16 *) & 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
John W. Linville274bfb82008-10-29 11:35:05 -0400309static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len,
Zhu Yi9184d932006-01-19 16:22:32 +0800310 u8 * rc4key, int keylen, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400311{
John W. Linville274bfb82008-10-29 11:35:05 -0400312 struct lib80211_tkip_data *tkey = priv;
Zhu Yi9184d932006-01-19 16:22:32 +0800313 u8 *pos;
John W. Linville274bfb82008-10-29 11:35:05 -0400314 struct ieee80211_hdr *hdr;
Jeff Garzikb4538722005-05-12 22:48:20 -0400315
John W. Linville274bfb82008-10-29 11:35:05 -0400316 hdr = (struct ieee80211_hdr *)skb->data;
James Ketrenos20d64712005-09-21 11:53:43 -0500317
Andriy Tkachuk299af9d2010-02-02 16:33:53 +0200318 if (skb_headroom(skb) < TKIP_HDR_LEN || skb->len < hdr_len)
Zhu Yi9184d932006-01-19 16:22:32 +0800319 return -1;
320
321 if (rc4key == NULL || keylen < 16)
322 return -1;
Jeff Garzikb4538722005-05-12 22:48:20 -0400323
Jeff Garzikb4538722005-05-12 22:48:20 -0400324 if (!tkey->tx_phase1_done) {
325 tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2,
326 tkey->tx_iv32);
327 tkey->tx_phase1_done = 1;
328 }
329 tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16);
330
Andriy Tkachuk299af9d2010-02-02 16:33:53 +0200331 pos = skb_push(skb, TKIP_HDR_LEN);
332 memmove(pos, pos + TKIP_HDR_LEN, hdr_len);
Jeff Garzikb4538722005-05-12 22:48:20 -0400333 pos += hdr_len;
Jeff Garzikb4538722005-05-12 22:48:20 -0400334
James Ketrenos31b59ea2005-09-21 11:58:49 -0500335 *pos++ = *rc4key;
336 *pos++ = *(rc4key + 1);
337 *pos++ = *(rc4key + 2);
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400338 *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */ ;
Jeff Garzikb4538722005-05-12 22:48:20 -0400339 *pos++ = tkey->tx_iv32 & 0xff;
340 *pos++ = (tkey->tx_iv32 >> 8) & 0xff;
341 *pos++ = (tkey->tx_iv32 >> 16) & 0xff;
342 *pos++ = (tkey->tx_iv32 >> 24) & 0xff;
343
Zhu Yi9184d932006-01-19 16:22:32 +0800344 tkey->tx_iv16++;
345 if (tkey->tx_iv16 == 0) {
346 tkey->tx_phase1_done = 0;
347 tkey->tx_iv32++;
348 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400349
Andriy Tkachuk299af9d2010-02-02 16:33:53 +0200350 return TKIP_HDR_LEN;
James Ketrenos31b59ea2005-09-21 11:58:49 -0500351}
352
John W. Linville274bfb82008-10-29 11:35:05 -0400353static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
James Ketrenos31b59ea2005-09-21 11:58:49 -0500354{
John W. Linville274bfb82008-10-29 11:35:05 -0400355 struct lib80211_tkip_data *tkey = priv;
Jeff Garzik28eb1772006-09-22 20:10:23 -0400356 struct blkcipher_desc desc = { .tfm = tkey->tx_tfm_arc4 };
James Ketrenos31b59ea2005-09-21 11:58:49 -0500357 int len;
Zhu Yi9184d932006-01-19 16:22:32 +0800358 u8 rc4key[16], *pos, *icv;
359 u32 crc;
James Ketrenos31b59ea2005-09-21 11:58:49 -0500360 struct scatterlist sg;
361
James Ketrenos6eb6edf2005-09-22 10:34:15 +0000362 if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
Joe Perchese87cc472012-05-13 21:56:26 +0000363 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
364 net_dbg_ratelimited("TKIP countermeasures: dropped TX packet to %pM\n",
365 hdr->addr1);
James Ketrenos31b59ea2005-09-21 11:58:49 -0500366 return -1;
367 }
368
369 if (skb_tailroom(skb) < 4 || skb->len < hdr_len)
370 return -1;
371
372 len = skb->len - hdr_len;
373 pos = skb->data + hdr_len;
374
John W. Linville274bfb82008-10-29 11:35:05 -0400375 if ((lib80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0)
James Ketrenos31b59ea2005-09-21 11:58:49 -0500376 return -1;
377
Zhu Yi9184d932006-01-19 16:22:32 +0800378 crc = ~crc32_le(~0, pos, len);
Andriy Tkachukd0833a62010-02-02 15:58:53 +0200379 icv = skb_put(skb, 4);
Zhu Yi9184d932006-01-19 16:22:32 +0800380 icv[0] = crc;
381 icv[1] = crc >> 8;
382 icv[2] = crc >> 16;
383 icv[3] = crc >> 24;
384
Jeff Garzik28eb1772006-09-22 20:10:23 -0400385 crypto_blkcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
Jens Axboefa05f122007-10-22 19:44:26 +0200386 sg_init_one(&sg, pos, len + 4);
Herbert Xuf12cc202006-08-22 20:36:13 +1000387 return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
Zhu Yib4328d82006-08-21 11:33:09 +0800388}
389
Jeff Garzik18379872006-09-22 21:19:05 -0400390/*
391 * deal with seq counter wrapping correctly.
392 * refer to timer_after() for jiffies wrapping handling
393 */
394static inline int tkip_replay_check(u32 iv32_n, u16 iv16_n,
395 u32 iv32_o, u16 iv16_o)
396{
397 if ((s32)iv32_n - (s32)iv32_o < 0 ||
398 (iv32_n == iv32_o && iv16_n <= iv16_o))
399 return 1;
400 return 0;
401}
402
John W. Linville274bfb82008-10-29 11:35:05 -0400403static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400404{
John W. Linville274bfb82008-10-29 11:35:05 -0400405 struct lib80211_tkip_data *tkey = priv;
Jeff Garzik28eb1772006-09-22 20:10:23 -0400406 struct blkcipher_desc desc = { .tfm = tkey->rx_tfm_arc4 };
Jeff Garzikb4538722005-05-12 22:48:20 -0400407 u8 rc4key[16];
408 u8 keyidx, *pos;
409 u32 iv32;
410 u16 iv16;
John W. Linville274bfb82008-10-29 11:35:05 -0400411 struct ieee80211_hdr *hdr;
Jeff Garzikb4538722005-05-12 22:48:20 -0400412 u8 icv[4];
413 u32 crc;
414 struct scatterlist sg;
415 int plen;
416
John W. Linville274bfb82008-10-29 11:35:05 -0400417 hdr = (struct ieee80211_hdr *)skb->data;
James Ketrenos20d64712005-09-21 11:53:43 -0500418
James Ketrenos6eb6edf2005-09-22 10:34:15 +0000419 if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
Joe Perchese87cc472012-05-13 21:56:26 +0000420 net_dbg_ratelimited("TKIP countermeasures: dropped received packet from %pM\n",
421 hdr->addr2);
James Ketrenos20d64712005-09-21 11:53:43 -0500422 return -1;
423 }
424
Andriy Tkachuk299af9d2010-02-02 16:33:53 +0200425 if (skb->len < hdr_len + TKIP_HDR_LEN + 4)
Jeff Garzikb4538722005-05-12 22:48:20 -0400426 return -1;
427
Jeff Garzikb4538722005-05-12 22:48:20 -0400428 pos = skb->data + hdr_len;
429 keyidx = pos[3];
430 if (!(keyidx & (1 << 5))) {
Joe Perchese87cc472012-05-13 21:56:26 +0000431 net_dbg_ratelimited("TKIP: received packet without ExtIV flag from %pM\n",
432 hdr->addr2);
Jeff Garzikb4538722005-05-12 22:48:20 -0400433 return -2;
434 }
435 keyidx >>= 6;
436 if (tkey->key_idx != keyidx) {
437 printk(KERN_DEBUG "TKIP: RX tkey->key_idx=%d frame "
438 "keyidx=%d priv=%p\n", tkey->key_idx, keyidx, priv);
439 return -6;
440 }
441 if (!tkey->key_set) {
Joe Perchese87cc472012-05-13 21:56:26 +0000442 net_dbg_ratelimited("TKIP: received packet from %pM with keyid=%d that does not have a configured key\n",
443 hdr->addr2, keyidx);
Jeff Garzikb4538722005-05-12 22:48:20 -0400444 return -3;
445 }
446 iv16 = (pos[0] << 8) | pos[2];
447 iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
Andriy Tkachuk299af9d2010-02-02 16:33:53 +0200448 pos += TKIP_HDR_LEN;
Jeff Garzikb4538722005-05-12 22:48:20 -0400449
Zhu Yib4328d82006-08-21 11:33:09 +0800450 if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) {
John W. Linville6f16bf32009-03-11 11:05:25 -0400451#ifdef CONFIG_LIB80211_DEBUG
Joe Perchese87cc472012-05-13 21:56:26 +0000452 net_dbg_ratelimited("TKIP: replay detected: STA=%pM previous TSC %08x%04x received TSC %08x%04x\n",
453 hdr->addr2, tkey->rx_iv32, tkey->rx_iv16,
454 iv32, iv16);
John W. Linville6f16bf32009-03-11 11:05:25 -0400455#endif
Jeff Garzikb4538722005-05-12 22:48:20 -0400456 tkey->dot11RSNAStatsTKIPReplays++;
457 return -4;
458 }
459
460 if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) {
461 tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32);
462 tkey->rx_phase1_done = 1;
463 }
464 tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16);
465
466 plen = skb->len - hdr_len - 12;
467
Jeff Garzik28eb1772006-09-22 20:10:23 -0400468 crypto_blkcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
Jens Axboefa05f122007-10-22 19:44:26 +0200469 sg_init_one(&sg, pos, plen + 4);
Herbert Xuf12cc202006-08-22 20:36:13 +1000470 if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) {
Joe Perchese87cc472012-05-13 21:56:26 +0000471 net_dbg_ratelimited("TKIP: failed to decrypt received packet from %pM\n",
472 hdr->addr2);
Herbert Xuf12cc202006-08-22 20:36:13 +1000473 return -7;
474 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400475
476 crc = ~crc32_le(~0, pos, plen);
477 icv[0] = crc;
478 icv[1] = crc >> 8;
479 icv[2] = crc >> 16;
480 icv[3] = crc >> 24;
481 if (memcmp(icv, pos + plen, 4) != 0) {
482 if (iv32 != tkey->rx_iv32) {
483 /* Previously cached Phase1 result was already lost, so
484 * it needs to be recalculated for the next packet. */
485 tkey->rx_phase1_done = 0;
486 }
John W. Linville6f16bf32009-03-11 11:05:25 -0400487#ifdef CONFIG_LIB80211_DEBUG
Joe Perchese87cc472012-05-13 21:56:26 +0000488 net_dbg_ratelimited("TKIP: ICV error detected: STA=%pM\n",
489 hdr->addr2);
John W. Linville6f16bf32009-03-11 11:05:25 -0400490#endif
Jeff Garzikb4538722005-05-12 22:48:20 -0400491 tkey->dot11RSNAStatsTKIPICVErrors++;
492 return -5;
493 }
494
495 /* Update real counters only after Michael MIC verification has
496 * completed */
497 tkey->rx_iv32_new = iv32;
498 tkey->rx_iv16_new = iv16;
499
500 /* Remove IV and ICV */
Andriy Tkachuk299af9d2010-02-02 16:33:53 +0200501 memmove(skb->data + TKIP_HDR_LEN, skb->data, hdr_len);
502 skb_pull(skb, TKIP_HDR_LEN);
Jeff Garzikb4538722005-05-12 22:48:20 -0400503 skb_trim(skb, skb->len - 4);
504
505 return keyidx;
506}
507
Jeff Garzik28eb1772006-09-22 20:10:23 -0400508static int michael_mic(struct crypto_hash *tfm_michael, u8 * key, u8 * hdr,
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400509 u8 * data, size_t data_len, u8 * mic)
Jeff Garzikb4538722005-05-12 22:48:20 -0400510{
Herbert Xu35058682006-08-24 19:10:20 +1000511 struct hash_desc desc;
Jeff Garzikb4538722005-05-12 22:48:20 -0400512 struct scatterlist sg[2];
513
Zhu Yi5a656942006-08-21 11:33:56 +0800514 if (tfm_michael == NULL) {
Joe Perchese9c02682010-11-16 19:56:49 -0800515 pr_warn("%s(): tfm_michael == NULL\n", __func__);
Jeff Garzikb4538722005-05-12 22:48:20 -0400516 return -1;
517 }
Jens Axboefa05f122007-10-22 19:44:26 +0200518 sg_init_table(sg, 2);
Jens Axboe642f1492007-10-24 11:20:47 +0200519 sg_set_buf(&sg[0], hdr, 16);
520 sg_set_buf(&sg[1], data, data_len);
Jeff Garzikb4538722005-05-12 22:48:20 -0400521
Jeff Garzik28eb1772006-09-22 20:10:23 -0400522 if (crypto_hash_setkey(tfm_michael, key, 8))
Herbert Xu35058682006-08-24 19:10:20 +1000523 return -1;
Jeff Garzikb4538722005-05-12 22:48:20 -0400524
Jeff Garzik28eb1772006-09-22 20:10:23 -0400525 desc.tfm = tfm_michael;
Herbert Xu35058682006-08-24 19:10:20 +1000526 desc.flags = 0;
527 return crypto_hash_digest(&desc, sg, data_len + 16, mic);
Jeff Garzikb4538722005-05-12 22:48:20 -0400528}
529
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400530static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr)
Jeff Garzikb4538722005-05-12 22:48:20 -0400531{
John W. Linville274bfb82008-10-29 11:35:05 -0400532 struct ieee80211_hdr *hdr11;
Jeff Garzikb4538722005-05-12 22:48:20 -0400533
John W. Linville274bfb82008-10-29 11:35:05 -0400534 hdr11 = (struct ieee80211_hdr *)skb->data;
Zhu Yiea284152006-04-13 17:17:06 +0800535
John W. Linville274bfb82008-10-29 11:35:05 -0400536 switch (le16_to_cpu(hdr11->frame_control) &
Jeff Garzikb4538722005-05-12 22:48:20 -0400537 (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
538 case IEEE80211_FCTL_TODS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400539 memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
540 memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400541 break;
542 case IEEE80211_FCTL_FROMDS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400543 memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
544 memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400545 break;
546 case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400547 memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
548 memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400549 break;
550 case 0:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400551 memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
552 memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400553 break;
554 }
555
John W. Linville274bfb82008-10-29 11:35:05 -0400556 if (ieee80211_is_data_qos(hdr11->frame_control)) {
John W. Linville3f6ff6b2010-07-20 12:09:11 -0400557 hdr[12] = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(hdr11)))
John W. Linville274bfb82008-10-29 11:35:05 -0400558 & IEEE80211_QOS_CTL_TID_MASK;
Zhu Yiea284152006-04-13 17:17:06 +0800559 } else
560 hdr[12] = 0; /* priority */
561
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400562 hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */
Jeff Garzikb4538722005-05-12 22:48:20 -0400563}
564
John W. Linville274bfb82008-10-29 11:35:05 -0400565static int lib80211_michael_mic_add(struct sk_buff *skb, int hdr_len,
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400566 void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400567{
John W. Linville274bfb82008-10-29 11:35:05 -0400568 struct lib80211_tkip_data *tkey = priv;
Jeff Garzikb4538722005-05-12 22:48:20 -0400569 u8 *pos;
570
571 if (skb_tailroom(skb) < 8 || skb->len < hdr_len) {
572 printk(KERN_DEBUG "Invalid packet for Michael MIC add "
573 "(tailroom=%d hdr_len=%d skb->len=%d)\n",
574 skb_tailroom(skb), hdr_len, skb->len);
575 return -1;
576 }
577
578 michael_mic_hdr(skb, tkey->tx_hdr);
579 pos = skb_put(skb, 8);
Zhu Yi5a656942006-08-21 11:33:56 +0800580 if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr,
Jeff Garzikb4538722005-05-12 22:48:20 -0400581 skb->data + hdr_len, skb->len - 8 - hdr_len, pos))
582 return -1;
583
584 return 0;
585}
586
John W. Linville274bfb82008-10-29 11:35:05 -0400587static void lib80211_michael_mic_failure(struct net_device *dev,
588 struct ieee80211_hdr *hdr,
James Ketrenosee34af32005-09-21 11:54:36 -0500589 int keyidx)
Jeff Garzikb4538722005-05-12 22:48:20 -0400590{
591 union iwreq_data wrqu;
592 struct iw_michaelmicfailure ev;
593
594 /* TODO: needed parameters: count, keyid, key type, TSC */
595 memset(&ev, 0, sizeof(ev));
596 ev.flags = keyidx & IW_MICFAILURE_KEY_ID;
597 if (hdr->addr1[0] & 0x01)
598 ev.flags |= IW_MICFAILURE_GROUP;
599 else
600 ev.flags |= IW_MICFAILURE_PAIRWISE;
601 ev.src_addr.sa_family = ARPHRD_ETHER;
602 memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN);
603 memset(&wrqu, 0, sizeof(wrqu));
604 wrqu.data.length = sizeof(ev);
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400605 wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev);
Jeff Garzikb4538722005-05-12 22:48:20 -0400606}
Jeff Garzikb4538722005-05-12 22:48:20 -0400607
John W. Linville274bfb82008-10-29 11:35:05 -0400608static int lib80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400609 int hdr_len, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400610{
John W. Linville274bfb82008-10-29 11:35:05 -0400611 struct lib80211_tkip_data *tkey = priv;
Jeff Garzikb4538722005-05-12 22:48:20 -0400612 u8 mic[8];
613
614 if (!tkey->key_set)
615 return -1;
616
617 michael_mic_hdr(skb, tkey->rx_hdr);
Zhu Yi5a656942006-08-21 11:33:56 +0800618 if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr,
Jeff Garzikb4538722005-05-12 22:48:20 -0400619 skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
620 return -1;
621 if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
John W. Linville274bfb82008-10-29 11:35:05 -0400622 struct ieee80211_hdr *hdr;
623 hdr = (struct ieee80211_hdr *)skb->data;
Jeff Garzikb4538722005-05-12 22:48:20 -0400624 printk(KERN_DEBUG "%s: Michael MIC verification failed for "
Johannes Berge1749612008-10-27 15:59:26 -0700625 "MSDU from %pM keyidx=%d\n",
626 skb->dev ? skb->dev->name : "N/A", hdr->addr2,
Jeff Garzikb4538722005-05-12 22:48:20 -0400627 keyidx);
628 if (skb->dev)
John W. Linville274bfb82008-10-29 11:35:05 -0400629 lib80211_michael_mic_failure(skb->dev, hdr, keyidx);
Jeff Garzikb4538722005-05-12 22:48:20 -0400630 tkey->dot11RSNAStatsTKIPLocalMICFailures++;
631 return -1;
632 }
633
634 /* Update TSC counters for RX now that the packet verification has
635 * completed. */
636 tkey->rx_iv32 = tkey->rx_iv32_new;
637 tkey->rx_iv16 = tkey->rx_iv16_new;
638
639 skb_trim(skb, skb->len - 8);
640
641 return 0;
642}
643
John W. Linville274bfb82008-10-29 11:35:05 -0400644static int lib80211_tkip_set_key(void *key, int len, u8 * seq, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400645{
John W. Linville274bfb82008-10-29 11:35:05 -0400646 struct lib80211_tkip_data *tkey = priv;
Jeff Garzikb4538722005-05-12 22:48:20 -0400647 int keyidx;
Jeff Garzik28eb1772006-09-22 20:10:23 -0400648 struct crypto_hash *tfm = tkey->tx_tfm_michael;
649 struct crypto_blkcipher *tfm2 = tkey->tx_tfm_arc4;
650 struct crypto_hash *tfm3 = tkey->rx_tfm_michael;
651 struct crypto_blkcipher *tfm4 = tkey->rx_tfm_arc4;
Jeff Garzikb4538722005-05-12 22:48:20 -0400652
653 keyidx = tkey->key_idx;
654 memset(tkey, 0, sizeof(*tkey));
655 tkey->key_idx = keyidx;
Zhu Yi5a656942006-08-21 11:33:56 +0800656 tkey->tx_tfm_michael = tfm;
657 tkey->tx_tfm_arc4 = tfm2;
658 tkey->rx_tfm_michael = tfm3;
659 tkey->rx_tfm_arc4 = tfm4;
Jeff Garzikb4538722005-05-12 22:48:20 -0400660 if (len == TKIP_KEY_LEN) {
661 memcpy(tkey->key, key, TKIP_KEY_LEN);
662 tkey->key_set = 1;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400663 tkey->tx_iv16 = 1; /* TSC is initialized to 1 */
Jeff Garzikb4538722005-05-12 22:48:20 -0400664 if (seq) {
665 tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) |
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400666 (seq[3] << 8) | seq[2];
Jeff Garzikb4538722005-05-12 22:48:20 -0400667 tkey->rx_iv16 = (seq[1] << 8) | seq[0];
668 }
669 } else if (len == 0)
670 tkey->key_set = 0;
671 else
672 return -1;
673
674 return 0;
675}
676
John W. Linville274bfb82008-10-29 11:35:05 -0400677static int lib80211_tkip_get_key(void *key, int len, u8 * seq, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400678{
John W. Linville274bfb82008-10-29 11:35:05 -0400679 struct lib80211_tkip_data *tkey = priv;
Jeff Garzikb4538722005-05-12 22:48:20 -0400680
681 if (len < TKIP_KEY_LEN)
682 return -1;
683
684 if (!tkey->key_set)
685 return 0;
686 memcpy(key, tkey->key, TKIP_KEY_LEN);
687
688 if (seq) {
689 /* Return the sequence number of the last transmitted frame. */
690 u16 iv16 = tkey->tx_iv16;
691 u32 iv32 = tkey->tx_iv32;
692 if (iv16 == 0)
693 iv32--;
694 iv16--;
695 seq[0] = tkey->tx_iv16;
696 seq[1] = tkey->tx_iv16 >> 8;
697 seq[2] = tkey->tx_iv32;
698 seq[3] = tkey->tx_iv32 >> 8;
699 seq[4] = tkey->tx_iv32 >> 16;
700 seq[5] = tkey->tx_iv32 >> 24;
701 }
702
703 return TKIP_KEY_LEN;
704}
705
David Howells6bbefe82013-04-10 21:13:23 +0100706static void lib80211_tkip_print_stats(struct seq_file *m, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400707{
John W. Linville274bfb82008-10-29 11:35:05 -0400708 struct lib80211_tkip_data *tkip = priv;
David Howells6bbefe82013-04-10 21:13:23 +0100709 seq_printf(m,
710 "key[%d] alg=TKIP key_set=%d "
711 "tx_pn=%02x%02x%02x%02x%02x%02x "
712 "rx_pn=%02x%02x%02x%02x%02x%02x "
713 "replays=%d icv_errors=%d local_mic_failures=%d\n",
714 tkip->key_idx, tkip->key_set,
715 (tkip->tx_iv32 >> 24) & 0xff,
716 (tkip->tx_iv32 >> 16) & 0xff,
717 (tkip->tx_iv32 >> 8) & 0xff,
718 tkip->tx_iv32 & 0xff,
719 (tkip->tx_iv16 >> 8) & 0xff,
720 tkip->tx_iv16 & 0xff,
721 (tkip->rx_iv32 >> 24) & 0xff,
722 (tkip->rx_iv32 >> 16) & 0xff,
723 (tkip->rx_iv32 >> 8) & 0xff,
724 tkip->rx_iv32 & 0xff,
725 (tkip->rx_iv16 >> 8) & 0xff,
726 tkip->rx_iv16 & 0xff,
727 tkip->dot11RSNAStatsTKIPReplays,
728 tkip->dot11RSNAStatsTKIPICVErrors,
729 tkip->dot11RSNAStatsTKIPLocalMICFailures);
Jeff Garzikb4538722005-05-12 22:48:20 -0400730}
731
John W. Linville274bfb82008-10-29 11:35:05 -0400732static struct lib80211_crypto_ops lib80211_crypt_tkip = {
James Ketrenos74079fd2005-09-13 17:35:21 -0500733 .name = "TKIP",
John W. Linville274bfb82008-10-29 11:35:05 -0400734 .init = lib80211_tkip_init,
735 .deinit = lib80211_tkip_deinit,
John W. Linville274bfb82008-10-29 11:35:05 -0400736 .encrypt_mpdu = lib80211_tkip_encrypt,
737 .decrypt_mpdu = lib80211_tkip_decrypt,
738 .encrypt_msdu = lib80211_michael_mic_add,
739 .decrypt_msdu = lib80211_michael_mic_verify,
740 .set_key = lib80211_tkip_set_key,
741 .get_key = lib80211_tkip_get_key,
742 .print_stats = lib80211_tkip_print_stats,
James Ketrenos1264fc02005-09-21 11:54:53 -0500743 .extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */
744 .extra_mpdu_postfix_len = 4, /* ICV */
745 .extra_msdu_postfix_len = 8, /* MIC */
John W. Linville274bfb82008-10-29 11:35:05 -0400746 .get_flags = lib80211_tkip_get_flags,
747 .set_flags = lib80211_tkip_set_flags,
James Ketrenos74079fd2005-09-13 17:35:21 -0500748 .owner = THIS_MODULE,
Jeff Garzikb4538722005-05-12 22:48:20 -0400749};
750
John W. Linville274bfb82008-10-29 11:35:05 -0400751static int __init lib80211_crypto_tkip_init(void)
Jeff Garzikb4538722005-05-12 22:48:20 -0400752{
John W. Linville274bfb82008-10-29 11:35:05 -0400753 return lib80211_register_crypto_ops(&lib80211_crypt_tkip);
Jeff Garzikb4538722005-05-12 22:48:20 -0400754}
755
John W. Linville274bfb82008-10-29 11:35:05 -0400756static void __exit lib80211_crypto_tkip_exit(void)
Jeff Garzikb4538722005-05-12 22:48:20 -0400757{
John W. Linville274bfb82008-10-29 11:35:05 -0400758 lib80211_unregister_crypto_ops(&lib80211_crypt_tkip);
Jeff Garzikb4538722005-05-12 22:48:20 -0400759}
760
John W. Linville274bfb82008-10-29 11:35:05 -0400761module_init(lib80211_crypto_tkip_init);
762module_exit(lib80211_crypto_tkip_exit);