Blame view

net/wireless/lib80211_crypt_tkip.c 20.7 KB
b453872c3   Jeff Garzik   [NET] ieee80211 s...
1
  /*
274bfb8dc   John W. Linville   lib80211: absorb ...
2
   * lib80211 crypt: host-based TKIP encryption implementation for lib80211
b453872c3   Jeff Garzik   [NET] ieee80211 s...
3
   *
85d32e7b0   Jouni Malinen   [PATCH] Update my...
4
   * Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
274bfb8dc   John W. Linville   lib80211: absorb ...
5
   * Copyright (c) 2008, John W. Linville <linville@tuxdriver.com>
b453872c3   Jeff Garzik   [NET] ieee80211 s...
6
7
8
9
10
11
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation. See README and COPYING for
   * more details.
   */
e9c0268f0   Joe Perches   net/wireless: Use...
12
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
f12cc2090   Herbert Xu   [CRYPTO] users: U...
13
  #include <linux/err.h>
b453872c3   Jeff Garzik   [NET] ieee80211 s...
14
15
16
17
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/slab.h>
  #include <linux/random.h>
117636092   Ralf Baechle   [PATCH] Fix break...
18
  #include <linux/scatterlist.h>
b453872c3   Jeff Garzik   [NET] ieee80211 s...
19
20
  #include <linux/skbuff.h>
  #include <linux/netdevice.h>
d7fe0f241   Al Viro   [PATCH] severing ...
21
  #include <linux/mm.h>
b453872c3   Jeff Garzik   [NET] ieee80211 s...
22
23
24
  #include <linux/if_ether.h>
  #include <linux/if_arp.h>
  #include <asm/string.h>
274bfb8dc   John W. Linville   lib80211: absorb ...
25
26
27
  #include <linux/wireless.h>
  #include <linux/ieee80211.h>
  #include <net/iw_handler.h>
b453872c3   Jeff Garzik   [NET] ieee80211 s...
28

b453872c3   Jeff Garzik   [NET] ieee80211 s...
29
  #include <linux/crypto.h>
b453872c3   Jeff Garzik   [NET] ieee80211 s...
30
  #include <linux/crc32.h>
274bfb8dc   John W. Linville   lib80211: absorb ...
31
  #include <net/lib80211.h>
b453872c3   Jeff Garzik   [NET] ieee80211 s...
32
  MODULE_AUTHOR("Jouni Malinen");
274bfb8dc   John W. Linville   lib80211: absorb ...
33
  MODULE_DESCRIPTION("lib80211 crypt: TKIP");
b453872c3   Jeff Garzik   [NET] ieee80211 s...
34
  MODULE_LICENSE("GPL");
299af9d3d   Andriy Tkachuk   lib80211: Introdu...
35
  #define TKIP_HDR_LEN 8
274bfb8dc   John W. Linville   lib80211: absorb ...
36
  struct lib80211_tkip_data {
b453872c3   Jeff Garzik   [NET] ieee80211 s...
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
  #define TKIP_KEY_LEN 32
  	u8 key[TKIP_KEY_LEN];
  	int key_set;
  
  	u32 tx_iv32;
  	u16 tx_iv16;
  	u16 tx_ttak[5];
  	int tx_phase1_done;
  
  	u32 rx_iv32;
  	u16 rx_iv16;
  	u16 rx_ttak[5];
  	int rx_phase1_done;
  	u32 rx_iv32_new;
  	u16 rx_iv16_new;
  
  	u32 dot11RSNAStatsTKIPReplays;
  	u32 dot11RSNAStatsTKIPICVErrors;
  	u32 dot11RSNAStatsTKIPLocalMICFailures;
  
  	int key_idx;
28eb177df   Jeff Garzik   Merge branch 'mas...
58
59
60
61
  	struct crypto_blkcipher *rx_tfm_arc4;
  	struct crypto_hash *rx_tfm_michael;
  	struct crypto_blkcipher *tx_tfm_arc4;
  	struct crypto_hash *tx_tfm_michael;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
62
63
64
  
  	/* scratch buffers for virt_to_page() (crypto API) */
  	u8 rx_hdr[16], tx_hdr[16];
20d64713a   James Ketrenos   [PATCH] ieee80211...
65

6eb6edf04   James Ketrenos   [PATCH] ieee80211...
66
  	unsigned long flags;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
67
  };
274bfb8dc   John W. Linville   lib80211: absorb ...
68
  static unsigned long lib80211_tkip_set_flags(unsigned long flags, void *priv)
6eb6edf04   James Ketrenos   [PATCH] ieee80211...
69
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
70
  	struct lib80211_tkip_data *_priv = priv;
6eb6edf04   James Ketrenos   [PATCH] ieee80211...
71
72
73
74
  	unsigned long old_flags = _priv->flags;
  	_priv->flags = flags;
  	return old_flags;
  }
274bfb8dc   John W. Linville   lib80211: absorb ...
75
  static unsigned long lib80211_tkip_get_flags(void *priv)
6eb6edf04   James Ketrenos   [PATCH] ieee80211...
76
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
77
  	struct lib80211_tkip_data *_priv = priv;
6eb6edf04   James Ketrenos   [PATCH] ieee80211...
78
79
  	return _priv->flags;
  }
274bfb8dc   John W. Linville   lib80211: absorb ...
80
  static void *lib80211_tkip_init(int key_idx)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
81
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
82
  	struct lib80211_tkip_data *priv;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
83

8aa914b74   Zhu Yi   [PATCH] ieee80211...
84
  	priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
b453872c3   Jeff Garzik   [NET] ieee80211 s...
85
86
  	if (priv == NULL)
  		goto fail;
20d64713a   James Ketrenos   [PATCH] ieee80211...
87

b453872c3   Jeff Garzik   [NET] ieee80211 s...
88
  	priv->key_idx = key_idx;
28eb177df   Jeff Garzik   Merge branch 'mas...
89
  	priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
f12cc2090   Herbert Xu   [CRYPTO] users: U...
90
  						CRYPTO_ALG_ASYNC);
28eb177df   Jeff Garzik   Merge branch 'mas...
91
  	if (IS_ERR(priv->tx_tfm_arc4)) {
183798799   Jeff Garzik   net/ieee80211: fi...
92
  		priv->tx_tfm_arc4 = NULL;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
93
94
  		goto fail;
  	}
28eb177df   Jeff Garzik   Merge branch 'mas...
95
96
97
  	priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
  						 CRYPTO_ALG_ASYNC);
  	if (IS_ERR(priv->tx_tfm_michael)) {
183798799   Jeff Garzik   net/ieee80211: fi...
98
  		priv->tx_tfm_michael = NULL;
5a6569497   Zhu Yi   [PATCH] ieee80211...
99
100
  		goto fail;
  	}
28eb177df   Jeff Garzik   Merge branch 'mas...
101
102
103
  	priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
  						CRYPTO_ALG_ASYNC);
  	if (IS_ERR(priv->rx_tfm_arc4)) {
183798799   Jeff Garzik   net/ieee80211: fi...
104
  		priv->rx_tfm_arc4 = NULL;
5a6569497   Zhu Yi   [PATCH] ieee80211...
105
106
  		goto fail;
  	}
28eb177df   Jeff Garzik   Merge branch 'mas...
107
108
109
  	priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
  						 CRYPTO_ALG_ASYNC);
  	if (IS_ERR(priv->rx_tfm_michael)) {
183798799   Jeff Garzik   net/ieee80211: fi...
110
  		priv->rx_tfm_michael = NULL;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
111
112
113
114
  		goto fail;
  	}
  
  	return priv;
0edd5b449   Jeff Garzik   [wireless ieee802...
115
        fail:
b453872c3   Jeff Garzik   [NET] ieee80211 s...
116
  	if (priv) {
5a6569497   Zhu Yi   [PATCH] ieee80211...
117
  		if (priv->tx_tfm_michael)
28eb177df   Jeff Garzik   Merge branch 'mas...
118
  			crypto_free_hash(priv->tx_tfm_michael);
5a6569497   Zhu Yi   [PATCH] ieee80211...
119
  		if (priv->tx_tfm_arc4)
28eb177df   Jeff Garzik   Merge branch 'mas...
120
  			crypto_free_blkcipher(priv->tx_tfm_arc4);
5a6569497   Zhu Yi   [PATCH] ieee80211...
121
  		if (priv->rx_tfm_michael)
28eb177df   Jeff Garzik   Merge branch 'mas...
122
  			crypto_free_hash(priv->rx_tfm_michael);
5a6569497   Zhu Yi   [PATCH] ieee80211...
123
  		if (priv->rx_tfm_arc4)
28eb177df   Jeff Garzik   Merge branch 'mas...
124
  			crypto_free_blkcipher(priv->rx_tfm_arc4);
b453872c3   Jeff Garzik   [NET] ieee80211 s...
125
126
127
128
129
  		kfree(priv);
  	}
  
  	return NULL;
  }
274bfb8dc   John W. Linville   lib80211: absorb ...
130
  static void lib80211_tkip_deinit(void *priv)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
131
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
132
  	struct lib80211_tkip_data *_priv = priv;
5a6569497   Zhu Yi   [PATCH] ieee80211...
133
134
  	if (_priv) {
  		if (_priv->tx_tfm_michael)
28eb177df   Jeff Garzik   Merge branch 'mas...
135
  			crypto_free_hash(_priv->tx_tfm_michael);
5a6569497   Zhu Yi   [PATCH] ieee80211...
136
  		if (_priv->tx_tfm_arc4)
28eb177df   Jeff Garzik   Merge branch 'mas...
137
  			crypto_free_blkcipher(_priv->tx_tfm_arc4);
5a6569497   Zhu Yi   [PATCH] ieee80211...
138
  		if (_priv->rx_tfm_michael)
28eb177df   Jeff Garzik   Merge branch 'mas...
139
  			crypto_free_hash(_priv->rx_tfm_michael);
5a6569497   Zhu Yi   [PATCH] ieee80211...
140
  		if (_priv->rx_tfm_arc4)
28eb177df   Jeff Garzik   Merge branch 'mas...
141
  			crypto_free_blkcipher(_priv->rx_tfm_arc4);
5a6569497   Zhu Yi   [PATCH] ieee80211...
142
  	}
b453872c3   Jeff Garzik   [NET] ieee80211 s...
143
144
  	kfree(priv);
  }
b453872c3   Jeff Garzik   [NET] ieee80211 s...
145
146
147
148
  static inline u16 RotR1(u16 val)
  {
  	return (val >> 1) | (val << 15);
  }
b453872c3   Jeff Garzik   [NET] ieee80211 s...
149
150
151
152
  static inline u8 Lo8(u16 val)
  {
  	return val & 0xff;
  }
b453872c3   Jeff Garzik   [NET] ieee80211 s...
153
154
155
156
  static inline u8 Hi8(u16 val)
  {
  	return val >> 8;
  }
b453872c3   Jeff Garzik   [NET] ieee80211 s...
157
158
159
160
  static inline u16 Lo16(u32 val)
  {
  	return val & 0xffff;
  }
b453872c3   Jeff Garzik   [NET] ieee80211 s...
161
162
163
164
  static inline u16 Hi16(u32 val)
  {
  	return val >> 16;
  }
b453872c3   Jeff Garzik   [NET] ieee80211 s...
165
166
167
168
  static inline u16 Mk16(u8 hi, u8 lo)
  {
  	return lo | (((u16) hi) << 8);
  }
d9e94d564   Al Viro   ieee80211: fix mi...
169
  static inline u16 Mk16_le(__le16 * v)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
170
171
172
  {
  	return le16_to_cpu(*v);
  }
0edd5b449   Jeff Garzik   [wireless ieee802...
173
  static const u16 Sbox[256] = {
b453872c3   Jeff Garzik   [NET] ieee80211 s...
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
  	0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
  	0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
  	0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
  	0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
  	0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
  	0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
  	0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
  	0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
  	0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
  	0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
  	0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
  	0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
  	0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
  	0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
  	0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
  	0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
  	0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
  	0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
  	0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
  	0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
  	0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
  	0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
  	0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
  	0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
  	0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
  	0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
  	0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
  	0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
  	0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
  	0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
  	0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
  	0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
  };
b453872c3   Jeff Garzik   [NET] ieee80211 s...
207
208
209
210
211
  static inline u16 _S_(u16 v)
  {
  	u16 t = Sbox[Hi8(v)];
  	return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8));
  }
b453872c3   Jeff Garzik   [NET] ieee80211 s...
212
  #define PHASE1_LOOP_COUNT 8
0edd5b449   Jeff Garzik   [wireless ieee802...
213
214
  static void tkip_mixing_phase1(u16 * TTAK, const u8 * TK, const u8 * TA,
  			       u32 IV32)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
  {
  	int i, j;
  
  	/* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */
  	TTAK[0] = Lo16(IV32);
  	TTAK[1] = Hi16(IV32);
  	TTAK[2] = Mk16(TA[1], TA[0]);
  	TTAK[3] = Mk16(TA[3], TA[2]);
  	TTAK[4] = Mk16(TA[5], TA[4]);
  
  	for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
  		j = 2 * (i & 1);
  		TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j]));
  		TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j]));
  		TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j]));
  		TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j]));
  		TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i;
  	}
  }
0edd5b449   Jeff Garzik   [wireless ieee802...
234
  static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK,
b453872c3   Jeff Garzik   [NET] ieee80211 s...
235
236
237
238
  			       u16 IV16)
  {
  	/* Make temporary area overlap WEP seed so that the final copy can be
  	 * avoided on little endian hosts. */
0edd5b449   Jeff Garzik   [wireless ieee802...
239
  	u16 *PPK = (u16 *) & WEPSeed[4];
b453872c3   Jeff Garzik   [NET] ieee80211 s...
240
241
242
243
244
245
246
247
248
249
  
  	/* Step 1 - make copy of TTAK and bring in TSC */
  	PPK[0] = TTAK[0];
  	PPK[1] = TTAK[1];
  	PPK[2] = TTAK[2];
  	PPK[3] = TTAK[3];
  	PPK[4] = TTAK[4];
  	PPK[5] = TTAK[4] + IV16;
  
  	/* Step 2 - 96-bit bijective mixing using S-box */
d9e94d564   Al Viro   ieee80211: fix mi...
250
251
252
253
254
255
256
257
258
  	PPK[0] += _S_(PPK[5] ^ Mk16_le((__le16 *) & TK[0]));
  	PPK[1] += _S_(PPK[0] ^ Mk16_le((__le16 *) & TK[2]));
  	PPK[2] += _S_(PPK[1] ^ Mk16_le((__le16 *) & TK[4]));
  	PPK[3] += _S_(PPK[2] ^ Mk16_le((__le16 *) & TK[6]));
  	PPK[4] += _S_(PPK[3] ^ Mk16_le((__le16 *) & TK[8]));
  	PPK[5] += _S_(PPK[4] ^ Mk16_le((__le16 *) & TK[10]));
  
  	PPK[0] += RotR1(PPK[5] ^ Mk16_le((__le16 *) & TK[12]));
  	PPK[1] += RotR1(PPK[0] ^ Mk16_le((__le16 *) & TK[14]));
b453872c3   Jeff Garzik   [NET] ieee80211 s...
259
260
261
262
263
264
265
266
267
268
  	PPK[2] += RotR1(PPK[1]);
  	PPK[3] += RotR1(PPK[2]);
  	PPK[4] += RotR1(PPK[3]);
  	PPK[5] += RotR1(PPK[4]);
  
  	/* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value
  	 * WEPSeed[0..2] is transmitted as WEP IV */
  	WEPSeed[0] = Hi8(IV16);
  	WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F;
  	WEPSeed[2] = Lo8(IV16);
d9e94d564   Al Viro   ieee80211: fix mi...
269
  	WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((__le16 *) & TK[0])) >> 1);
b453872c3   Jeff Garzik   [NET] ieee80211 s...
270
271
272
273
274
275
276
277
278
  
  #ifdef __BIG_ENDIAN
  	{
  		int i;
  		for (i = 0; i < 6; i++)
  			PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8);
  	}
  #endif
  }
274bfb8dc   John W. Linville   lib80211: absorb ...
279
  static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len,
9184d9348   Zhu Yi   [PATCH] ieee80211...
280
  			      u8 * rc4key, int keylen, void *priv)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
281
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
282
  	struct lib80211_tkip_data *tkey = priv;
9184d9348   Zhu Yi   [PATCH] ieee80211...
283
  	u8 *pos;
274bfb8dc   John W. Linville   lib80211: absorb ...
284
  	struct ieee80211_hdr *hdr;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
285

274bfb8dc   John W. Linville   lib80211: absorb ...
286
  	hdr = (struct ieee80211_hdr *)skb->data;
20d64713a   James Ketrenos   [PATCH] ieee80211...
287

299af9d3d   Andriy Tkachuk   lib80211: Introdu...
288
  	if (skb_headroom(skb) < TKIP_HDR_LEN || skb->len < hdr_len)
9184d9348   Zhu Yi   [PATCH] ieee80211...
289
290
291
292
  		return -1;
  
  	if (rc4key == NULL || keylen < 16)
  		return -1;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
293

b453872c3   Jeff Garzik   [NET] ieee80211 s...
294
295
296
297
298
299
  	if (!tkey->tx_phase1_done) {
  		tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2,
  				   tkey->tx_iv32);
  		tkey->tx_phase1_done = 1;
  	}
  	tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16);
299af9d3d   Andriy Tkachuk   lib80211: Introdu...
300
301
  	pos = skb_push(skb, TKIP_HDR_LEN);
  	memmove(pos, pos + TKIP_HDR_LEN, hdr_len);
b453872c3   Jeff Garzik   [NET] ieee80211 s...
302
  	pos += hdr_len;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
303

31b59eaee   James Ketrenos   [PATCH] ieee80211...
304
305
306
  	*pos++ = *rc4key;
  	*pos++ = *(rc4key + 1);
  	*pos++ = *(rc4key + 2);
0edd5b449   Jeff Garzik   [wireless ieee802...
307
  	*pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */ ;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
308
309
310
311
  	*pos++ = tkey->tx_iv32 & 0xff;
  	*pos++ = (tkey->tx_iv32 >> 8) & 0xff;
  	*pos++ = (tkey->tx_iv32 >> 16) & 0xff;
  	*pos++ = (tkey->tx_iv32 >> 24) & 0xff;
9184d9348   Zhu Yi   [PATCH] ieee80211...
312
313
314
315
316
  	tkey->tx_iv16++;
  	if (tkey->tx_iv16 == 0) {
  		tkey->tx_phase1_done = 0;
  		tkey->tx_iv32++;
  	}
b453872c3   Jeff Garzik   [NET] ieee80211 s...
317

299af9d3d   Andriy Tkachuk   lib80211: Introdu...
318
  	return TKIP_HDR_LEN;
31b59eaee   James Ketrenos   [PATCH] ieee80211...
319
  }
274bfb8dc   John W. Linville   lib80211: absorb ...
320
  static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
31b59eaee   James Ketrenos   [PATCH] ieee80211...
321
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
322
  	struct lib80211_tkip_data *tkey = priv;
28eb177df   Jeff Garzik   Merge branch 'mas...
323
  	struct blkcipher_desc desc = { .tfm = tkey->tx_tfm_arc4 };
31b59eaee   James Ketrenos   [PATCH] ieee80211...
324
  	int len;
9184d9348   Zhu Yi   [PATCH] ieee80211...
325
326
  	u8 rc4key[16], *pos, *icv;
  	u32 crc;
31b59eaee   James Ketrenos   [PATCH] ieee80211...
327
  	struct scatterlist sg;
6eb6edf04   James Ketrenos   [PATCH] ieee80211...
328
  	if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
31b59eaee   James Ketrenos   [PATCH] ieee80211...
329
  		if (net_ratelimit()) {
274bfb8dc   John W. Linville   lib80211: absorb ...
330
331
  			struct ieee80211_hdr *hdr =
  			    (struct ieee80211_hdr *)skb->data;
9184d9348   Zhu Yi   [PATCH] ieee80211...
332
  			printk(KERN_DEBUG ": TKIP countermeasures: dropped "
e174961ca   Johannes Berg   net: convert prin...
333
334
  			       "TX packet to %pM
  ", hdr->addr1);
31b59eaee   James Ketrenos   [PATCH] ieee80211...
335
336
337
338
339
340
341
342
343
  		}
  		return -1;
  	}
  
  	if (skb_tailroom(skb) < 4 || skb->len < hdr_len)
  		return -1;
  
  	len = skb->len - hdr_len;
  	pos = skb->data + hdr_len;
274bfb8dc   John W. Linville   lib80211: absorb ...
344
  	if ((lib80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0)
31b59eaee   James Ketrenos   [PATCH] ieee80211...
345
  		return -1;
9184d9348   Zhu Yi   [PATCH] ieee80211...
346
  	crc = ~crc32_le(~0, pos, len);
d0833a6a2   Andriy Tkachuk   lib80211: Cosmeti...
347
  	icv = skb_put(skb, 4);
9184d9348   Zhu Yi   [PATCH] ieee80211...
348
349
350
351
  	icv[0] = crc;
  	icv[1] = crc >> 8;
  	icv[2] = crc >> 16;
  	icv[3] = crc >> 24;
28eb177df   Jeff Garzik   Merge branch 'mas...
352
  	crypto_blkcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
fa05f1286   Jens Axboe   Update net/ to us...
353
  	sg_init_one(&sg, pos, len + 4);
f12cc2090   Herbert Xu   [CRYPTO] users: U...
354
  	return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
b4328d87e   Zhu Yi   [PATCH] ieee80211...
355
  }
183798799   Jeff Garzik   net/ieee80211: fi...
356
357
358
359
360
361
362
363
364
365
366
367
  /*
   * deal with seq counter wrapping correctly.
   * refer to timer_after() for jiffies wrapping handling
   */
  static inline int tkip_replay_check(u32 iv32_n, u16 iv16_n,
  				    u32 iv32_o, u16 iv16_o)
  {
  	if ((s32)iv32_n - (s32)iv32_o < 0 ||
  	    (iv32_n == iv32_o && iv16_n <= iv16_o))
  		return 1;
  	return 0;
  }
274bfb8dc   John W. Linville   lib80211: absorb ...
368
  static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
369
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
370
  	struct lib80211_tkip_data *tkey = priv;
28eb177df   Jeff Garzik   Merge branch 'mas...
371
  	struct blkcipher_desc desc = { .tfm = tkey->rx_tfm_arc4 };
b453872c3   Jeff Garzik   [NET] ieee80211 s...
372
373
374
375
  	u8 rc4key[16];
  	u8 keyidx, *pos;
  	u32 iv32;
  	u16 iv16;
274bfb8dc   John W. Linville   lib80211: absorb ...
376
  	struct ieee80211_hdr *hdr;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
377
378
379
380
  	u8 icv[4];
  	u32 crc;
  	struct scatterlist sg;
  	int plen;
274bfb8dc   John W. Linville   lib80211: absorb ...
381
  	hdr = (struct ieee80211_hdr *)skb->data;
20d64713a   James Ketrenos   [PATCH] ieee80211...
382

6eb6edf04   James Ketrenos   [PATCH] ieee80211...
383
  	if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
20d64713a   James Ketrenos   [PATCH] ieee80211...
384
  		if (net_ratelimit()) {
9184d9348   Zhu Yi   [PATCH] ieee80211...
385
  			printk(KERN_DEBUG ": TKIP countermeasures: dropped "
e174961ca   Johannes Berg   net: convert prin...
386
387
  			       "received packet from %pM
  ", hdr->addr2);
20d64713a   James Ketrenos   [PATCH] ieee80211...
388
389
390
  		}
  		return -1;
  	}
299af9d3d   Andriy Tkachuk   lib80211: Introdu...
391
  	if (skb->len < hdr_len + TKIP_HDR_LEN + 4)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
392
  		return -1;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
393
394
395
396
397
  	pos = skb->data + hdr_len;
  	keyidx = pos[3];
  	if (!(keyidx & (1 << 5))) {
  		if (net_ratelimit()) {
  			printk(KERN_DEBUG "TKIP: received packet without ExtIV"
e174961ca   Johannes Berg   net: convert prin...
398
399
  			       " flag from %pM
  ", hdr->addr2);
b453872c3   Jeff Garzik   [NET] ieee80211 s...
400
401
402
403
404
405
406
407
408
409
410
411
  		}
  		return -2;
  	}
  	keyidx >>= 6;
  	if (tkey->key_idx != keyidx) {
  		printk(KERN_DEBUG "TKIP: RX tkey->key_idx=%d frame "
  		       "keyidx=%d priv=%p
  ", tkey->key_idx, keyidx, priv);
  		return -6;
  	}
  	if (!tkey->key_set) {
  		if (net_ratelimit()) {
e174961ca   Johannes Berg   net: convert prin...
412
  			printk(KERN_DEBUG "TKIP: received packet from %pM"
b453872c3   Jeff Garzik   [NET] ieee80211 s...
413
  			       " with keyid=%d that does not have a configured"
e174961ca   Johannes Berg   net: convert prin...
414
415
  			       " key
  ", hdr->addr2, keyidx);
b453872c3   Jeff Garzik   [NET] ieee80211 s...
416
417
418
419
420
  		}
  		return -3;
  	}
  	iv16 = (pos[0] << 8) | pos[2];
  	iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
299af9d3d   Andriy Tkachuk   lib80211: Introdu...
421
  	pos += TKIP_HDR_LEN;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
422

b4328d87e   Zhu Yi   [PATCH] ieee80211...
423
  	if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) {
6f16bf3bd   John W. Linville   lib80211: silence...
424
  #ifdef CONFIG_LIB80211_DEBUG
274bfb8dc   John W. Linville   lib80211: absorb ...
425
426
  		if (net_ratelimit()) {
  			printk(KERN_DEBUG "TKIP: replay detected: STA=%pM"
b453872c3   Jeff Garzik   [NET] ieee80211 s...
427
  			       " previous TSC %08x%04x received TSC "
e174961ca   Johannes Berg   net: convert prin...
428
429
  			       "%08x%04x
  ", hdr->addr2,
b453872c3   Jeff Garzik   [NET] ieee80211 s...
430
431
  			       tkey->rx_iv32, tkey->rx_iv16, iv32, iv16);
  		}
6f16bf3bd   John W. Linville   lib80211: silence...
432
  #endif
b453872c3   Jeff Garzik   [NET] ieee80211 s...
433
434
435
436
437
438
439
440
441
442
443
  		tkey->dot11RSNAStatsTKIPReplays++;
  		return -4;
  	}
  
  	if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) {
  		tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32);
  		tkey->rx_phase1_done = 1;
  	}
  	tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16);
  
  	plen = skb->len - hdr_len - 12;
28eb177df   Jeff Garzik   Merge branch 'mas...
444
  	crypto_blkcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
fa05f1286   Jens Axboe   Update net/ to us...
445
  	sg_init_one(&sg, pos, plen + 4);
f12cc2090   Herbert Xu   [CRYPTO] users: U...
446
447
448
  	if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) {
  		if (net_ratelimit()) {
  			printk(KERN_DEBUG ": TKIP: failed to decrypt "
e174961ca   Johannes Berg   net: convert prin...
449
450
451
  			       "received packet from %pM
  ",
  			       hdr->addr2);
f12cc2090   Herbert Xu   [CRYPTO] users: U...
452
453
454
  		}
  		return -7;
  	}
b453872c3   Jeff Garzik   [NET] ieee80211 s...
455
456
457
458
459
460
461
462
463
464
465
466
  
  	crc = ~crc32_le(~0, pos, plen);
  	icv[0] = crc;
  	icv[1] = crc >> 8;
  	icv[2] = crc >> 16;
  	icv[3] = crc >> 24;
  	if (memcmp(icv, pos + plen, 4) != 0) {
  		if (iv32 != tkey->rx_iv32) {
  			/* Previously cached Phase1 result was already lost, so
  			 * it needs to be recalculated for the next packet. */
  			tkey->rx_phase1_done = 0;
  		}
6f16bf3bd   John W. Linville   lib80211: silence...
467
  #ifdef CONFIG_LIB80211_DEBUG
274bfb8dc   John W. Linville   lib80211: absorb ...
468
469
  		if (net_ratelimit()) {
  			printk(KERN_DEBUG "TKIP: ICV error detected: STA="
e174961ca   Johannes Berg   net: convert prin...
470
471
  			       "%pM
  ", hdr->addr2);
b453872c3   Jeff Garzik   [NET] ieee80211 s...
472
  		}
6f16bf3bd   John W. Linville   lib80211: silence...
473
  #endif
b453872c3   Jeff Garzik   [NET] ieee80211 s...
474
475
476
477
478
479
480
481
482
483
  		tkey->dot11RSNAStatsTKIPICVErrors++;
  		return -5;
  	}
  
  	/* Update real counters only after Michael MIC verification has
  	 * completed */
  	tkey->rx_iv32_new = iv32;
  	tkey->rx_iv16_new = iv16;
  
  	/* Remove IV and ICV */
299af9d3d   Andriy Tkachuk   lib80211: Introdu...
484
485
  	memmove(skb->data + TKIP_HDR_LEN, skb->data, hdr_len);
  	skb_pull(skb, TKIP_HDR_LEN);
b453872c3   Jeff Garzik   [NET] ieee80211 s...
486
487
488
489
  	skb_trim(skb, skb->len - 4);
  
  	return keyidx;
  }
28eb177df   Jeff Garzik   Merge branch 'mas...
490
  static int michael_mic(struct crypto_hash *tfm_michael, u8 * key, u8 * hdr,
0edd5b449   Jeff Garzik   [wireless ieee802...
491
  		       u8 * data, size_t data_len, u8 * mic)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
492
  {
350586879   Herbert Xu   [CRYPTO] users: U...
493
  	struct hash_desc desc;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
494
  	struct scatterlist sg[2];
5a6569497   Zhu Yi   [PATCH] ieee80211...
495
  	if (tfm_michael == NULL) {
e9c0268f0   Joe Perches   net/wireless: Use...
496
497
  		pr_warn("%s(): tfm_michael == NULL
  ", __func__);
b453872c3   Jeff Garzik   [NET] ieee80211 s...
498
499
  		return -1;
  	}
fa05f1286   Jens Axboe   Update net/ to us...
500
  	sg_init_table(sg, 2);
642f14903   Jens Axboe   SG: Change sg_set...
501
502
  	sg_set_buf(&sg[0], hdr, 16);
  	sg_set_buf(&sg[1], data, data_len);
b453872c3   Jeff Garzik   [NET] ieee80211 s...
503

28eb177df   Jeff Garzik   Merge branch 'mas...
504
  	if (crypto_hash_setkey(tfm_michael, key, 8))
350586879   Herbert Xu   [CRYPTO] users: U...
505
  		return -1;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
506

28eb177df   Jeff Garzik   Merge branch 'mas...
507
  	desc.tfm = tfm_michael;
350586879   Herbert Xu   [CRYPTO] users: U...
508
509
  	desc.flags = 0;
  	return crypto_hash_digest(&desc, sg, data_len + 16, mic);
b453872c3   Jeff Garzik   [NET] ieee80211 s...
510
  }
0edd5b449   Jeff Garzik   [wireless ieee802...
511
  static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
512
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
513
  	struct ieee80211_hdr *hdr11;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
514

274bfb8dc   John W. Linville   lib80211: absorb ...
515
  	hdr11 = (struct ieee80211_hdr *)skb->data;
ea2841521   Zhu Yi   [PATCH] ieee80211...
516

274bfb8dc   John W. Linville   lib80211: absorb ...
517
  	switch (le16_to_cpu(hdr11->frame_control) &
b453872c3   Jeff Garzik   [NET] ieee80211 s...
518
519
  		(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
  	case IEEE80211_FCTL_TODS:
0edd5b449   Jeff Garzik   [wireless ieee802...
520
521
  		memcpy(hdr, hdr11->addr3, ETH_ALEN);	/* DA */
  		memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN);	/* SA */
b453872c3   Jeff Garzik   [NET] ieee80211 s...
522
523
  		break;
  	case IEEE80211_FCTL_FROMDS:
0edd5b449   Jeff Garzik   [wireless ieee802...
524
525
  		memcpy(hdr, hdr11->addr1, ETH_ALEN);	/* DA */
  		memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN);	/* SA */
b453872c3   Jeff Garzik   [NET] ieee80211 s...
526
527
  		break;
  	case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
0edd5b449   Jeff Garzik   [wireless ieee802...
528
529
  		memcpy(hdr, hdr11->addr3, ETH_ALEN);	/* DA */
  		memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN);	/* SA */
b453872c3   Jeff Garzik   [NET] ieee80211 s...
530
531
  		break;
  	case 0:
0edd5b449   Jeff Garzik   [wireless ieee802...
532
533
  		memcpy(hdr, hdr11->addr1, ETH_ALEN);	/* DA */
  		memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN);	/* SA */
b453872c3   Jeff Garzik   [NET] ieee80211 s...
534
535
  		break;
  	}
274bfb8dc   John W. Linville   lib80211: absorb ...
536
  	if (ieee80211_is_data_qos(hdr11->frame_control)) {
3f6ff6bac   John W. Linville   wireless: correct...
537
  		hdr[12] = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(hdr11)))
274bfb8dc   John W. Linville   lib80211: absorb ...
538
  			& IEEE80211_QOS_CTL_TID_MASK;
ea2841521   Zhu Yi   [PATCH] ieee80211...
539
540
  	} else
  		hdr[12] = 0;		/* priority */
0edd5b449   Jeff Garzik   [wireless ieee802...
541
  	hdr[13] = hdr[14] = hdr[15] = 0;	/* reserved */
b453872c3   Jeff Garzik   [NET] ieee80211 s...
542
  }
274bfb8dc   John W. Linville   lib80211: absorb ...
543
  static int lib80211_michael_mic_add(struct sk_buff *skb, int hdr_len,
0edd5b449   Jeff Garzik   [wireless ieee802...
544
  				     void *priv)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
545
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
546
  	struct lib80211_tkip_data *tkey = priv;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
547
548
549
550
551
552
553
554
555
556
557
558
  	u8 *pos;
  
  	if (skb_tailroom(skb) < 8 || skb->len < hdr_len) {
  		printk(KERN_DEBUG "Invalid packet for Michael MIC add "
  		       "(tailroom=%d hdr_len=%d skb->len=%d)
  ",
  		       skb_tailroom(skb), hdr_len, skb->len);
  		return -1;
  	}
  
  	michael_mic_hdr(skb, tkey->tx_hdr);
  	pos = skb_put(skb, 8);
5a6569497   Zhu Yi   [PATCH] ieee80211...
559
  	if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr,
b453872c3   Jeff Garzik   [NET] ieee80211 s...
560
561
562
563
564
  			skb->data + hdr_len, skb->len - 8 - hdr_len, pos))
  		return -1;
  
  	return 0;
  }
274bfb8dc   John W. Linville   lib80211: absorb ...
565
566
  static void lib80211_michael_mic_failure(struct net_device *dev,
  					  struct ieee80211_hdr *hdr,
ee34af37c   James Ketrenos   [PATCH] ieee80211...
567
  					  int keyidx)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
  {
  	union iwreq_data wrqu;
  	struct iw_michaelmicfailure ev;
  
  	/* TODO: needed parameters: count, keyid, key type, TSC */
  	memset(&ev, 0, sizeof(ev));
  	ev.flags = keyidx & IW_MICFAILURE_KEY_ID;
  	if (hdr->addr1[0] & 0x01)
  		ev.flags |= IW_MICFAILURE_GROUP;
  	else
  		ev.flags |= IW_MICFAILURE_PAIRWISE;
  	ev.src_addr.sa_family = ARPHRD_ETHER;
  	memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN);
  	memset(&wrqu, 0, sizeof(wrqu));
  	wrqu.data.length = sizeof(ev);
0edd5b449   Jeff Garzik   [wireless ieee802...
583
  	wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev);
b453872c3   Jeff Garzik   [NET] ieee80211 s...
584
  }
b453872c3   Jeff Garzik   [NET] ieee80211 s...
585

274bfb8dc   John W. Linville   lib80211: absorb ...
586
  static int lib80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
0edd5b449   Jeff Garzik   [wireless ieee802...
587
  					int hdr_len, void *priv)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
588
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
589
  	struct lib80211_tkip_data *tkey = priv;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
590
591
592
593
594
595
  	u8 mic[8];
  
  	if (!tkey->key_set)
  		return -1;
  
  	michael_mic_hdr(skb, tkey->rx_hdr);
5a6569497   Zhu Yi   [PATCH] ieee80211...
596
  	if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr,
b453872c3   Jeff Garzik   [NET] ieee80211 s...
597
598
599
  			skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
  		return -1;
  	if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
274bfb8dc   John W. Linville   lib80211: absorb ...
600
601
  		struct ieee80211_hdr *hdr;
  		hdr = (struct ieee80211_hdr *)skb->data;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
602
  		printk(KERN_DEBUG "%s: Michael MIC verification failed for "
e174961ca   Johannes Berg   net: convert prin...
603
604
605
  		       "MSDU from %pM keyidx=%d
  ",
  		       skb->dev ? skb->dev->name : "N/A", hdr->addr2,
b453872c3   Jeff Garzik   [NET] ieee80211 s...
606
607
  		       keyidx);
  		if (skb->dev)
274bfb8dc   John W. Linville   lib80211: absorb ...
608
  			lib80211_michael_mic_failure(skb->dev, hdr, keyidx);
b453872c3   Jeff Garzik   [NET] ieee80211 s...
609
610
611
612
613
614
615
616
617
618
619
620
621
  		tkey->dot11RSNAStatsTKIPLocalMICFailures++;
  		return -1;
  	}
  
  	/* Update TSC counters for RX now that the packet verification has
  	 * completed. */
  	tkey->rx_iv32 = tkey->rx_iv32_new;
  	tkey->rx_iv16 = tkey->rx_iv16_new;
  
  	skb_trim(skb, skb->len - 8);
  
  	return 0;
  }
274bfb8dc   John W. Linville   lib80211: absorb ...
622
  static int lib80211_tkip_set_key(void *key, int len, u8 * seq, void *priv)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
623
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
624
  	struct lib80211_tkip_data *tkey = priv;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
625
  	int keyidx;
28eb177df   Jeff Garzik   Merge branch 'mas...
626
627
628
629
  	struct crypto_hash *tfm = tkey->tx_tfm_michael;
  	struct crypto_blkcipher *tfm2 = tkey->tx_tfm_arc4;
  	struct crypto_hash *tfm3 = tkey->rx_tfm_michael;
  	struct crypto_blkcipher *tfm4 = tkey->rx_tfm_arc4;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
630
631
632
633
  
  	keyidx = tkey->key_idx;
  	memset(tkey, 0, sizeof(*tkey));
  	tkey->key_idx = keyidx;
5a6569497   Zhu Yi   [PATCH] ieee80211...
634
635
636
637
  	tkey->tx_tfm_michael = tfm;
  	tkey->tx_tfm_arc4 = tfm2;
  	tkey->rx_tfm_michael = tfm3;
  	tkey->rx_tfm_arc4 = tfm4;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
638
639
640
  	if (len == TKIP_KEY_LEN) {
  		memcpy(tkey->key, key, TKIP_KEY_LEN);
  		tkey->key_set = 1;
0edd5b449   Jeff Garzik   [wireless ieee802...
641
  		tkey->tx_iv16 = 1;	/* TSC is initialized to 1 */
b453872c3   Jeff Garzik   [NET] ieee80211 s...
642
643
  		if (seq) {
  			tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) |
0edd5b449   Jeff Garzik   [wireless ieee802...
644
  			    (seq[3] << 8) | seq[2];
b453872c3   Jeff Garzik   [NET] ieee80211 s...
645
646
647
648
649
650
651
652
653
  			tkey->rx_iv16 = (seq[1] << 8) | seq[0];
  		}
  	} else if (len == 0)
  		tkey->key_set = 0;
  	else
  		return -1;
  
  	return 0;
  }
274bfb8dc   John W. Linville   lib80211: absorb ...
654
  static int lib80211_tkip_get_key(void *key, int len, u8 * seq, void *priv)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
655
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
656
  	struct lib80211_tkip_data *tkey = priv;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
  
  	if (len < TKIP_KEY_LEN)
  		return -1;
  
  	if (!tkey->key_set)
  		return 0;
  	memcpy(key, tkey->key, TKIP_KEY_LEN);
  
  	if (seq) {
  		/* Return the sequence number of the last transmitted frame. */
  		u16 iv16 = tkey->tx_iv16;
  		u32 iv32 = tkey->tx_iv32;
  		if (iv16 == 0)
  			iv32--;
  		iv16--;
  		seq[0] = tkey->tx_iv16;
  		seq[1] = tkey->tx_iv16 >> 8;
  		seq[2] = tkey->tx_iv32;
  		seq[3] = tkey->tx_iv32 >> 8;
  		seq[4] = tkey->tx_iv32 >> 16;
  		seq[5] = tkey->tx_iv32 >> 24;
  	}
  
  	return TKIP_KEY_LEN;
  }
274bfb8dc   John W. Linville   lib80211: absorb ...
682
  static char *lib80211_tkip_print_stats(char *p, void *priv)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
683
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
684
  	struct lib80211_tkip_data *tkip = priv;
b453872c3   Jeff Garzik   [NET] ieee80211 s...
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
  	p += sprintf(p, "key[%d] alg=TKIP key_set=%d "
  		     "tx_pn=%02x%02x%02x%02x%02x%02x "
  		     "rx_pn=%02x%02x%02x%02x%02x%02x "
  		     "replays=%d icv_errors=%d local_mic_failures=%d
  ",
  		     tkip->key_idx, tkip->key_set,
  		     (tkip->tx_iv32 >> 24) & 0xff,
  		     (tkip->tx_iv32 >> 16) & 0xff,
  		     (tkip->tx_iv32 >> 8) & 0xff,
  		     tkip->tx_iv32 & 0xff,
  		     (tkip->tx_iv16 >> 8) & 0xff,
  		     tkip->tx_iv16 & 0xff,
  		     (tkip->rx_iv32 >> 24) & 0xff,
  		     (tkip->rx_iv32 >> 16) & 0xff,
  		     (tkip->rx_iv32 >> 8) & 0xff,
  		     tkip->rx_iv32 & 0xff,
  		     (tkip->rx_iv16 >> 8) & 0xff,
  		     tkip->rx_iv16 & 0xff,
  		     tkip->dot11RSNAStatsTKIPReplays,
  		     tkip->dot11RSNAStatsTKIPICVErrors,
  		     tkip->dot11RSNAStatsTKIPLocalMICFailures);
  	return p;
  }
274bfb8dc   John W. Linville   lib80211: absorb ...
708
  static struct lib80211_crypto_ops lib80211_crypt_tkip = {
74079fdce   James Ketrenos   [PATCH] ieee80211...
709
  	.name = "TKIP",
274bfb8dc   John W. Linville   lib80211: absorb ...
710
711
  	.init = lib80211_tkip_init,
  	.deinit = lib80211_tkip_deinit,
274bfb8dc   John W. Linville   lib80211: absorb ...
712
713
714
715
716
717
718
  	.encrypt_mpdu = lib80211_tkip_encrypt,
  	.decrypt_mpdu = lib80211_tkip_decrypt,
  	.encrypt_msdu = lib80211_michael_mic_add,
  	.decrypt_msdu = lib80211_michael_mic_verify,
  	.set_key = lib80211_tkip_set_key,
  	.get_key = lib80211_tkip_get_key,
  	.print_stats = lib80211_tkip_print_stats,
1264fc049   James Ketrenos   [PATCH] ieee80211...
719
720
721
  	.extra_mpdu_prefix_len = 4 + 4,	/* IV + ExtIV */
  	.extra_mpdu_postfix_len = 4,	/* ICV */
  	.extra_msdu_postfix_len = 8,	/* MIC */
274bfb8dc   John W. Linville   lib80211: absorb ...
722
723
  	.get_flags = lib80211_tkip_get_flags,
  	.set_flags = lib80211_tkip_set_flags,
74079fdce   James Ketrenos   [PATCH] ieee80211...
724
  	.owner = THIS_MODULE,
b453872c3   Jeff Garzik   [NET] ieee80211 s...
725
  };
274bfb8dc   John W. Linville   lib80211: absorb ...
726
  static int __init lib80211_crypto_tkip_init(void)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
727
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
728
  	return lib80211_register_crypto_ops(&lib80211_crypt_tkip);
b453872c3   Jeff Garzik   [NET] ieee80211 s...
729
  }
274bfb8dc   John W. Linville   lib80211: absorb ...
730
  static void __exit lib80211_crypto_tkip_exit(void)
b453872c3   Jeff Garzik   [NET] ieee80211 s...
731
  {
274bfb8dc   John W. Linville   lib80211: absorb ...
732
  	lib80211_unregister_crypto_ops(&lib80211_crypt_tkip);
b453872c3   Jeff Garzik   [NET] ieee80211 s...
733
  }
274bfb8dc   John W. Linville   lib80211: absorb ...
734
735
  module_init(lib80211_crypto_tkip_init);
  module_exit(lib80211_crypto_tkip_exit);