blob: 11eaa5956f001806012e74cbee9deb1e15837c5f [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
Herbert Xu608fb342016-01-24 21:18:09 +080032#include <crypto/hash.h>
Johannes Bergb802a5d2018-10-01 09:16:08 +020033#include <linux/crypto.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040034#include <linux/crc32.h>
35
John W. Linville274bfb82008-10-29 11:35:05 -040036#include <net/lib80211.h>
37
Jeff Garzikb4538722005-05-12 22:48:20 -040038MODULE_AUTHOR("Jouni Malinen");
John W. Linville274bfb82008-10-29 11:35:05 -040039MODULE_DESCRIPTION("lib80211 crypt: TKIP");
Jeff Garzikb4538722005-05-12 22:48:20 -040040MODULE_LICENSE("GPL");
41
Andriy Tkachuk299af9d2010-02-02 16:33:53 +020042#define TKIP_HDR_LEN 8
43
John W. Linville274bfb82008-10-29 11:35:05 -040044struct lib80211_tkip_data {
Jeff Garzikb4538722005-05-12 22:48:20 -040045#define TKIP_KEY_LEN 32
46 u8 key[TKIP_KEY_LEN];
47 int key_set;
48
49 u32 tx_iv32;
50 u16 tx_iv16;
51 u16 tx_ttak[5];
52 int tx_phase1_done;
53
54 u32 rx_iv32;
55 u16 rx_iv16;
56 u16 rx_ttak[5];
57 int rx_phase1_done;
58 u32 rx_iv32_new;
59 u16 rx_iv16_new;
60
61 u32 dot11RSNAStatsTKIPReplays;
62 u32 dot11RSNAStatsTKIPICVErrors;
63 u32 dot11RSNAStatsTKIPLocalMICFailures;
64
65 int key_idx;
66
Johannes Bergb802a5d2018-10-01 09:16:08 +020067 struct crypto_cipher *rx_tfm_arc4;
Kees Cookd17504b2018-07-15 20:52:26 -070068 struct crypto_shash *rx_tfm_michael;
Johannes Bergb802a5d2018-10-01 09:16:08 +020069 struct crypto_cipher *tx_tfm_arc4;
Kees Cookd17504b2018-07-15 20:52:26 -070070 struct crypto_shash *tx_tfm_michael;
Jeff Garzikb4538722005-05-12 22:48:20 -040071
72 /* scratch buffers for virt_to_page() (crypto API) */
73 u8 rx_hdr[16], tx_hdr[16];
James Ketrenos20d64712005-09-21 11:53:43 -050074
James Ketrenos6eb6edf2005-09-22 10:34:15 +000075 unsigned long flags;
Jeff Garzikb4538722005-05-12 22:48:20 -040076};
77
John W. Linville274bfb82008-10-29 11:35:05 -040078static unsigned long lib80211_tkip_set_flags(unsigned long flags, void *priv)
James Ketrenos6eb6edf2005-09-22 10:34:15 +000079{
John W. Linville274bfb82008-10-29 11:35:05 -040080 struct lib80211_tkip_data *_priv = priv;
James Ketrenos6eb6edf2005-09-22 10:34:15 +000081 unsigned long old_flags = _priv->flags;
82 _priv->flags = flags;
83 return old_flags;
84}
85
John W. Linville274bfb82008-10-29 11:35:05 -040086static unsigned long lib80211_tkip_get_flags(void *priv)
James Ketrenos6eb6edf2005-09-22 10:34:15 +000087{
John W. Linville274bfb82008-10-29 11:35:05 -040088 struct lib80211_tkip_data *_priv = priv;
James Ketrenos6eb6edf2005-09-22 10:34:15 +000089 return _priv->flags;
90}
91
John W. Linville274bfb82008-10-29 11:35:05 -040092static void *lib80211_tkip_init(int key_idx)
Jeff Garzikb4538722005-05-12 22:48:20 -040093{
John W. Linville274bfb82008-10-29 11:35:05 -040094 struct lib80211_tkip_data *priv;
Jeff Garzikb4538722005-05-12 22:48:20 -040095
Zhu Yi8aa914b2006-01-19 16:22:07 +080096 priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
Jeff Garzikb4538722005-05-12 22:48:20 -040097 if (priv == NULL)
98 goto fail;
James Ketrenos20d64712005-09-21 11:53:43 -050099
Jeff Garzikb4538722005-05-12 22:48:20 -0400100 priv->key_idx = key_idx;
101
Eric Biggers1ad0f162018-11-14 12:19:39 -0800102 priv->tx_tfm_arc4 = crypto_alloc_cipher("arc4", 0, 0);
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
Kees Cookd17504b2018-07-15 20:52:26 -0700108 priv->tx_tfm_michael = crypto_alloc_shash("michael_mic", 0, 0);
Jeff Garzik28eb1772006-09-22 20:10:23 -0400109 if (IS_ERR(priv->tx_tfm_michael)) {
Jeff Garzik18379872006-09-22 21:19:05 -0400110 priv->tx_tfm_michael = NULL;
Zhu Yi5a656942006-08-21 11:33:56 +0800111 goto fail;
112 }
113
Eric Biggers1ad0f162018-11-14 12:19:39 -0800114 priv->rx_tfm_arc4 = crypto_alloc_cipher("arc4", 0, 0);
Jeff Garzik28eb1772006-09-22 20:10:23 -0400115 if (IS_ERR(priv->rx_tfm_arc4)) {
Jeff Garzik18379872006-09-22 21:19:05 -0400116 priv->rx_tfm_arc4 = NULL;
Zhu Yi5a656942006-08-21 11:33:56 +0800117 goto fail;
118 }
119
Kees Cookd17504b2018-07-15 20:52:26 -0700120 priv->rx_tfm_michael = crypto_alloc_shash("michael_mic", 0, 0);
Jeff Garzik28eb1772006-09-22 20:10:23 -0400121 if (IS_ERR(priv->rx_tfm_michael)) {
Jeff Garzik18379872006-09-22 21:19:05 -0400122 priv->rx_tfm_michael = NULL;
Jeff Garzikb4538722005-05-12 22:48:20 -0400123 goto fail;
124 }
125
126 return priv;
127
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400128 fail:
Jeff Garzikb4538722005-05-12 22:48:20 -0400129 if (priv) {
Kees Cookd17504b2018-07-15 20:52:26 -0700130 crypto_free_shash(priv->tx_tfm_michael);
Johannes Bergb802a5d2018-10-01 09:16:08 +0200131 crypto_free_cipher(priv->tx_tfm_arc4);
Kees Cookd17504b2018-07-15 20:52:26 -0700132 crypto_free_shash(priv->rx_tfm_michael);
Johannes Bergb802a5d2018-10-01 09:16:08 +0200133 crypto_free_cipher(priv->rx_tfm_arc4);
Jeff Garzikb4538722005-05-12 22:48:20 -0400134 kfree(priv);
135 }
136
137 return NULL;
138}
139
John W. Linville274bfb82008-10-29 11:35:05 -0400140static void lib80211_tkip_deinit(void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400141{
John W. Linville274bfb82008-10-29 11:35:05 -0400142 struct lib80211_tkip_data *_priv = priv;
Zhu Yi5a656942006-08-21 11:33:56 +0800143 if (_priv) {
Kees Cookd17504b2018-07-15 20:52:26 -0700144 crypto_free_shash(_priv->tx_tfm_michael);
Johannes Bergb802a5d2018-10-01 09:16:08 +0200145 crypto_free_cipher(_priv->tx_tfm_arc4);
Kees Cookd17504b2018-07-15 20:52:26 -0700146 crypto_free_shash(_priv->rx_tfm_michael);
Johannes Bergb802a5d2018-10-01 09:16:08 +0200147 crypto_free_cipher(_priv->rx_tfm_arc4);
Zhu Yi5a656942006-08-21 11:33:56 +0800148 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400149 kfree(priv);
150}
151
Jeff Garzikb4538722005-05-12 22:48:20 -0400152static inline u16 RotR1(u16 val)
153{
154 return (val >> 1) | (val << 15);
155}
156
Jeff Garzikb4538722005-05-12 22:48:20 -0400157static inline u8 Lo8(u16 val)
158{
159 return val & 0xff;
160}
161
Jeff Garzikb4538722005-05-12 22:48:20 -0400162static inline u8 Hi8(u16 val)
163{
164 return val >> 8;
165}
166
Jeff Garzikb4538722005-05-12 22:48:20 -0400167static inline u16 Lo16(u32 val)
168{
169 return val & 0xffff;
170}
171
Jeff Garzikb4538722005-05-12 22:48:20 -0400172static inline u16 Hi16(u32 val)
173{
174 return val >> 16;
175}
176
Jeff Garzikb4538722005-05-12 22:48:20 -0400177static inline u16 Mk16(u8 hi, u8 lo)
178{
179 return lo | (((u16) hi) << 8);
180}
181
Al Virod9e94d52007-12-29 05:01:07 -0500182static inline u16 Mk16_le(__le16 * v)
Jeff Garzikb4538722005-05-12 22:48:20 -0400183{
184 return le16_to_cpu(*v);
185}
186
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400187static const u16 Sbox[256] = {
Jeff Garzikb4538722005-05-12 22:48:20 -0400188 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
189 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
190 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
191 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
192 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
193 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
194 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
195 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
196 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
197 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
198 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
199 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
200 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
201 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
202 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
203 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
204 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
205 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
206 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
207 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
208 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
209 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
210 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
211 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
212 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
213 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
214 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
215 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
216 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
217 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
218 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
219 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
220};
221
Jeff Garzikb4538722005-05-12 22:48:20 -0400222static inline u16 _S_(u16 v)
223{
224 u16 t = Sbox[Hi8(v)];
225 return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8));
226}
227
Jeff Garzikb4538722005-05-12 22:48:20 -0400228#define PHASE1_LOOP_COUNT 8
229
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400230static void tkip_mixing_phase1(u16 * TTAK, const u8 * TK, const u8 * TA,
231 u32 IV32)
Jeff Garzikb4538722005-05-12 22:48:20 -0400232{
233 int i, j;
234
235 /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */
236 TTAK[0] = Lo16(IV32);
237 TTAK[1] = Hi16(IV32);
238 TTAK[2] = Mk16(TA[1], TA[0]);
239 TTAK[3] = Mk16(TA[3], TA[2]);
240 TTAK[4] = Mk16(TA[5], TA[4]);
241
242 for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
243 j = 2 * (i & 1);
244 TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j]));
245 TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j]));
246 TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j]));
247 TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j]));
248 TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i;
249 }
250}
251
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400252static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK,
Jeff Garzikb4538722005-05-12 22:48:20 -0400253 u16 IV16)
254{
255 /* Make temporary area overlap WEP seed so that the final copy can be
256 * avoided on little endian hosts. */
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400257 u16 *PPK = (u16 *) & WEPSeed[4];
Jeff Garzikb4538722005-05-12 22:48:20 -0400258
259 /* Step 1 - make copy of TTAK and bring in TSC */
260 PPK[0] = TTAK[0];
261 PPK[1] = TTAK[1];
262 PPK[2] = TTAK[2];
263 PPK[3] = TTAK[3];
264 PPK[4] = TTAK[4];
265 PPK[5] = TTAK[4] + IV16;
266
267 /* Step 2 - 96-bit bijective mixing using S-box */
Al Virod9e94d52007-12-29 05:01:07 -0500268 PPK[0] += _S_(PPK[5] ^ Mk16_le((__le16 *) & TK[0]));
269 PPK[1] += _S_(PPK[0] ^ Mk16_le((__le16 *) & TK[2]));
270 PPK[2] += _S_(PPK[1] ^ Mk16_le((__le16 *) & TK[4]));
271 PPK[3] += _S_(PPK[2] ^ Mk16_le((__le16 *) & TK[6]));
272 PPK[4] += _S_(PPK[3] ^ Mk16_le((__le16 *) & TK[8]));
273 PPK[5] += _S_(PPK[4] ^ Mk16_le((__le16 *) & TK[10]));
Jeff Garzikb4538722005-05-12 22:48:20 -0400274
Al Virod9e94d52007-12-29 05:01:07 -0500275 PPK[0] += RotR1(PPK[5] ^ Mk16_le((__le16 *) & TK[12]));
276 PPK[1] += RotR1(PPK[0] ^ Mk16_le((__le16 *) & TK[14]));
Jeff Garzikb4538722005-05-12 22:48:20 -0400277 PPK[2] += RotR1(PPK[1]);
278 PPK[3] += RotR1(PPK[2]);
279 PPK[4] += RotR1(PPK[3]);
280 PPK[5] += RotR1(PPK[4]);
281
282 /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value
283 * WEPSeed[0..2] is transmitted as WEP IV */
284 WEPSeed[0] = Hi8(IV16);
285 WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F;
286 WEPSeed[2] = Lo8(IV16);
Al Virod9e94d52007-12-29 05:01:07 -0500287 WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((__le16 *) & TK[0])) >> 1);
Jeff Garzikb4538722005-05-12 22:48:20 -0400288
289#ifdef __BIG_ENDIAN
290 {
291 int i;
292 for (i = 0; i < 6; i++)
293 PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8);
294 }
295#endif
296}
297
John W. Linville274bfb82008-10-29 11:35:05 -0400298static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len,
Zhu Yi9184d932006-01-19 16:22:32 +0800299 u8 * rc4key, int keylen, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400300{
John W. Linville274bfb82008-10-29 11:35:05 -0400301 struct lib80211_tkip_data *tkey = priv;
Zhu Yi9184d932006-01-19 16:22:32 +0800302 u8 *pos;
John W. Linville274bfb82008-10-29 11:35:05 -0400303 struct ieee80211_hdr *hdr;
Jeff Garzikb4538722005-05-12 22:48:20 -0400304
John W. Linville274bfb82008-10-29 11:35:05 -0400305 hdr = (struct ieee80211_hdr *)skb->data;
James Ketrenos20d64712005-09-21 11:53:43 -0500306
Andriy Tkachuk299af9d2010-02-02 16:33:53 +0200307 if (skb_headroom(skb) < TKIP_HDR_LEN || skb->len < hdr_len)
Zhu Yi9184d932006-01-19 16:22:32 +0800308 return -1;
309
310 if (rc4key == NULL || keylen < 16)
311 return -1;
Jeff Garzikb4538722005-05-12 22:48:20 -0400312
Jeff Garzikb4538722005-05-12 22:48:20 -0400313 if (!tkey->tx_phase1_done) {
314 tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2,
315 tkey->tx_iv32);
316 tkey->tx_phase1_done = 1;
317 }
318 tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16);
319
Andriy Tkachuk299af9d2010-02-02 16:33:53 +0200320 pos = skb_push(skb, TKIP_HDR_LEN);
321 memmove(pos, pos + TKIP_HDR_LEN, hdr_len);
Jeff Garzikb4538722005-05-12 22:48:20 -0400322 pos += hdr_len;
Jeff Garzikb4538722005-05-12 22:48:20 -0400323
James Ketrenos31b59ea2005-09-21 11:58:49 -0500324 *pos++ = *rc4key;
325 *pos++ = *(rc4key + 1);
326 *pos++ = *(rc4key + 2);
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400327 *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */ ;
Jeff Garzikb4538722005-05-12 22:48:20 -0400328 *pos++ = tkey->tx_iv32 & 0xff;
329 *pos++ = (tkey->tx_iv32 >> 8) & 0xff;
330 *pos++ = (tkey->tx_iv32 >> 16) & 0xff;
331 *pos++ = (tkey->tx_iv32 >> 24) & 0xff;
332
Zhu Yi9184d932006-01-19 16:22:32 +0800333 tkey->tx_iv16++;
334 if (tkey->tx_iv16 == 0) {
335 tkey->tx_phase1_done = 0;
336 tkey->tx_iv32++;
337 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400338
Andriy Tkachuk299af9d2010-02-02 16:33:53 +0200339 return TKIP_HDR_LEN;
James Ketrenos31b59ea2005-09-21 11:58:49 -0500340}
341
John W. Linville274bfb82008-10-29 11:35:05 -0400342static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
James Ketrenos31b59ea2005-09-21 11:58:49 -0500343{
John W. Linville274bfb82008-10-29 11:35:05 -0400344 struct lib80211_tkip_data *tkey = priv;
James Ketrenos31b59ea2005-09-21 11:58:49 -0500345 int len;
Zhu Yi9184d932006-01-19 16:22:32 +0800346 u8 rc4key[16], *pos, *icv;
347 u32 crc;
Johannes Bergb802a5d2018-10-01 09:16:08 +0200348 int i;
James Ketrenos31b59ea2005-09-21 11:58:49 -0500349
James Ketrenos6eb6edf2005-09-22 10:34:15 +0000350 if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
Joe Perchese87cc472012-05-13 21:56:26 +0000351 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
352 net_dbg_ratelimited("TKIP countermeasures: dropped TX packet to %pM\n",
353 hdr->addr1);
James Ketrenos31b59ea2005-09-21 11:58:49 -0500354 return -1;
355 }
356
357 if (skb_tailroom(skb) < 4 || skb->len < hdr_len)
358 return -1;
359
360 len = skb->len - hdr_len;
361 pos = skb->data + hdr_len;
362
John W. Linville274bfb82008-10-29 11:35:05 -0400363 if ((lib80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0)
James Ketrenos31b59ea2005-09-21 11:58:49 -0500364 return -1;
365
Zhu Yi9184d932006-01-19 16:22:32 +0800366 crc = ~crc32_le(~0, pos, len);
Andriy Tkachukd0833a62010-02-02 15:58:53 +0200367 icv = skb_put(skb, 4);
Zhu Yi9184d932006-01-19 16:22:32 +0800368 icv[0] = crc;
369 icv[1] = crc >> 8;
370 icv[2] = crc >> 16;
371 icv[3] = crc >> 24;
372
Johannes Bergb802a5d2018-10-01 09:16:08 +0200373 crypto_cipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
374 for (i = 0; i < len + 4; i++)
375 crypto_cipher_encrypt_one(tkey->tx_tfm_arc4, pos + i, pos + i);
376 return 0;
Zhu Yib4328d82006-08-21 11:33:09 +0800377}
378
Jeff Garzik18379872006-09-22 21:19:05 -0400379/*
380 * deal with seq counter wrapping correctly.
381 * refer to timer_after() for jiffies wrapping handling
382 */
383static inline int tkip_replay_check(u32 iv32_n, u16 iv16_n,
384 u32 iv32_o, u16 iv16_o)
385{
386 if ((s32)iv32_n - (s32)iv32_o < 0 ||
387 (iv32_n == iv32_o && iv16_n <= iv16_o))
388 return 1;
389 return 0;
390}
391
John W. Linville274bfb82008-10-29 11:35:05 -0400392static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400393{
John W. Linville274bfb82008-10-29 11:35:05 -0400394 struct lib80211_tkip_data *tkey = priv;
Jeff Garzikb4538722005-05-12 22:48:20 -0400395 u8 rc4key[16];
396 u8 keyidx, *pos;
397 u32 iv32;
398 u16 iv16;
John W. Linville274bfb82008-10-29 11:35:05 -0400399 struct ieee80211_hdr *hdr;
Jeff Garzikb4538722005-05-12 22:48:20 -0400400 u8 icv[4];
401 u32 crc;
Jeff Garzikb4538722005-05-12 22:48:20 -0400402 int plen;
Johannes Bergb802a5d2018-10-01 09:16:08 +0200403 int i;
Jeff Garzikb4538722005-05-12 22:48:20 -0400404
John W. Linville274bfb82008-10-29 11:35:05 -0400405 hdr = (struct ieee80211_hdr *)skb->data;
James Ketrenos20d64712005-09-21 11:53:43 -0500406
James Ketrenos6eb6edf2005-09-22 10:34:15 +0000407 if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
Joe Perchese87cc472012-05-13 21:56:26 +0000408 net_dbg_ratelimited("TKIP countermeasures: dropped received packet from %pM\n",
409 hdr->addr2);
James Ketrenos20d64712005-09-21 11:53:43 -0500410 return -1;
411 }
412
Andriy Tkachuk299af9d2010-02-02 16:33:53 +0200413 if (skb->len < hdr_len + TKIP_HDR_LEN + 4)
Jeff Garzikb4538722005-05-12 22:48:20 -0400414 return -1;
415
Jeff Garzikb4538722005-05-12 22:48:20 -0400416 pos = skb->data + hdr_len;
417 keyidx = pos[3];
418 if (!(keyidx & (1 << 5))) {
Joe Perchese87cc472012-05-13 21:56:26 +0000419 net_dbg_ratelimited("TKIP: received packet without ExtIV flag from %pM\n",
420 hdr->addr2);
Jeff Garzikb4538722005-05-12 22:48:20 -0400421 return -2;
422 }
423 keyidx >>= 6;
424 if (tkey->key_idx != keyidx) {
Johannes Berg996bf992015-11-06 12:02:31 +0100425 net_dbg_ratelimited("TKIP: RX tkey->key_idx=%d frame keyidx=%d\n",
426 tkey->key_idx, keyidx);
Jeff Garzikb4538722005-05-12 22:48:20 -0400427 return -6;
428 }
429 if (!tkey->key_set) {
Joe Perchese87cc472012-05-13 21:56:26 +0000430 net_dbg_ratelimited("TKIP: received packet from %pM with keyid=%d that does not have a configured key\n",
431 hdr->addr2, keyidx);
Jeff Garzikb4538722005-05-12 22:48:20 -0400432 return -3;
433 }
434 iv16 = (pos[0] << 8) | pos[2];
435 iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
Andriy Tkachuk299af9d2010-02-02 16:33:53 +0200436 pos += TKIP_HDR_LEN;
Jeff Garzikb4538722005-05-12 22:48:20 -0400437
Zhu Yib4328d82006-08-21 11:33:09 +0800438 if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) {
John W. Linville6f16bf32009-03-11 11:05:25 -0400439#ifdef CONFIG_LIB80211_DEBUG
Joe Perchese87cc472012-05-13 21:56:26 +0000440 net_dbg_ratelimited("TKIP: replay detected: STA=%pM previous TSC %08x%04x received TSC %08x%04x\n",
441 hdr->addr2, tkey->rx_iv32, tkey->rx_iv16,
442 iv32, iv16);
John W. Linville6f16bf32009-03-11 11:05:25 -0400443#endif
Jeff Garzikb4538722005-05-12 22:48:20 -0400444 tkey->dot11RSNAStatsTKIPReplays++;
445 return -4;
446 }
447
448 if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) {
449 tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32);
450 tkey->rx_phase1_done = 1;
451 }
452 tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16);
453
454 plen = skb->len - hdr_len - 12;
455
Johannes Bergb802a5d2018-10-01 09:16:08 +0200456 crypto_cipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
457 for (i = 0; i < plen + 4; i++)
458 crypto_cipher_decrypt_one(tkey->rx_tfm_arc4, pos + i, pos + i);
Jeff Garzikb4538722005-05-12 22:48:20 -0400459
460 crc = ~crc32_le(~0, pos, plen);
461 icv[0] = crc;
462 icv[1] = crc >> 8;
463 icv[2] = crc >> 16;
464 icv[3] = crc >> 24;
465 if (memcmp(icv, pos + plen, 4) != 0) {
466 if (iv32 != tkey->rx_iv32) {
467 /* Previously cached Phase1 result was already lost, so
468 * it needs to be recalculated for the next packet. */
469 tkey->rx_phase1_done = 0;
470 }
John W. Linville6f16bf32009-03-11 11:05:25 -0400471#ifdef CONFIG_LIB80211_DEBUG
Joe Perchese87cc472012-05-13 21:56:26 +0000472 net_dbg_ratelimited("TKIP: ICV error detected: STA=%pM\n",
473 hdr->addr2);
John W. Linville6f16bf32009-03-11 11:05:25 -0400474#endif
Jeff Garzikb4538722005-05-12 22:48:20 -0400475 tkey->dot11RSNAStatsTKIPICVErrors++;
476 return -5;
477 }
478
479 /* Update real counters only after Michael MIC verification has
480 * completed */
481 tkey->rx_iv32_new = iv32;
482 tkey->rx_iv16_new = iv16;
483
484 /* Remove IV and ICV */
Andriy Tkachuk299af9d2010-02-02 16:33:53 +0200485 memmove(skb->data + TKIP_HDR_LEN, skb->data, hdr_len);
486 skb_pull(skb, TKIP_HDR_LEN);
Jeff Garzikb4538722005-05-12 22:48:20 -0400487 skb_trim(skb, skb->len - 4);
488
489 return keyidx;
490}
491
Kees Cookd17504b2018-07-15 20:52:26 -0700492static int michael_mic(struct crypto_shash *tfm_michael, u8 *key, u8 *hdr,
493 u8 *data, size_t data_len, u8 *mic)
Jeff Garzikb4538722005-05-12 22:48:20 -0400494{
Kees Cookd17504b2018-07-15 20:52:26 -0700495 SHASH_DESC_ON_STACK(desc, tfm_michael);
Herbert Xu608fb342016-01-24 21:18:09 +0800496 int err;
Jeff Garzikb4538722005-05-12 22:48:20 -0400497
Zhu Yi5a656942006-08-21 11:33:56 +0800498 if (tfm_michael == NULL) {
Joe Perchese9c02682010-11-16 19:56:49 -0800499 pr_warn("%s(): tfm_michael == NULL\n", __func__);
Jeff Garzikb4538722005-05-12 22:48:20 -0400500 return -1;
501 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400502
Kees Cookd17504b2018-07-15 20:52:26 -0700503 desc->tfm = tfm_michael;
Kees Cookd17504b2018-07-15 20:52:26 -0700504
505 if (crypto_shash_setkey(tfm_michael, key, 8))
Herbert Xu35058682006-08-24 19:10:20 +1000506 return -1;
Jeff Garzikb4538722005-05-12 22:48:20 -0400507
Kees Cookd17504b2018-07-15 20:52:26 -0700508 err = crypto_shash_init(desc);
509 if (err)
510 goto out;
511 err = crypto_shash_update(desc, hdr, 16);
512 if (err)
513 goto out;
514 err = crypto_shash_update(desc, data, data_len);
515 if (err)
516 goto out;
517 err = crypto_shash_final(desc, mic);
518
519out:
520 shash_desc_zero(desc);
Herbert Xu608fb342016-01-24 21:18:09 +0800521 return err;
Jeff Garzikb4538722005-05-12 22:48:20 -0400522}
523
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400524static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr)
Jeff Garzikb4538722005-05-12 22:48:20 -0400525{
John W. Linville274bfb82008-10-29 11:35:05 -0400526 struct ieee80211_hdr *hdr11;
Jeff Garzikb4538722005-05-12 22:48:20 -0400527
John W. Linville274bfb82008-10-29 11:35:05 -0400528 hdr11 = (struct ieee80211_hdr *)skb->data;
Zhu Yiea284152006-04-13 17:17:06 +0800529
John W. Linville274bfb82008-10-29 11:35:05 -0400530 switch (le16_to_cpu(hdr11->frame_control) &
Jeff Garzikb4538722005-05-12 22:48:20 -0400531 (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
532 case IEEE80211_FCTL_TODS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400533 memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
534 memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400535 break;
536 case IEEE80211_FCTL_FROMDS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400537 memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
538 memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400539 break;
540 case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400541 memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
542 memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400543 break;
Arnd Bergmann10f33662016-10-24 17:38:35 +0200544 default:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400545 memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
546 memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400547 break;
548 }
549
John W. Linville274bfb82008-10-29 11:35:05 -0400550 if (ieee80211_is_data_qos(hdr11->frame_control)) {
John W. Linville3f6ff6b2010-07-20 12:09:11 -0400551 hdr[12] = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(hdr11)))
John W. Linville274bfb82008-10-29 11:35:05 -0400552 & IEEE80211_QOS_CTL_TID_MASK;
Zhu Yiea284152006-04-13 17:17:06 +0800553 } else
554 hdr[12] = 0; /* priority */
555
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400556 hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */
Jeff Garzikb4538722005-05-12 22:48:20 -0400557}
558
John W. Linville274bfb82008-10-29 11:35:05 -0400559static int lib80211_michael_mic_add(struct sk_buff *skb, int hdr_len,
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400560 void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400561{
John W. Linville274bfb82008-10-29 11:35:05 -0400562 struct lib80211_tkip_data *tkey = priv;
Jeff Garzikb4538722005-05-12 22:48:20 -0400563 u8 *pos;
564
565 if (skb_tailroom(skb) < 8 || skb->len < hdr_len) {
566 printk(KERN_DEBUG "Invalid packet for Michael MIC add "
567 "(tailroom=%d hdr_len=%d skb->len=%d)\n",
568 skb_tailroom(skb), hdr_len, skb->len);
569 return -1;
570 }
571
572 michael_mic_hdr(skb, tkey->tx_hdr);
573 pos = skb_put(skb, 8);
Zhu Yi5a656942006-08-21 11:33:56 +0800574 if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr,
Jeff Garzikb4538722005-05-12 22:48:20 -0400575 skb->data + hdr_len, skb->len - 8 - hdr_len, pos))
576 return -1;
577
578 return 0;
579}
580
John W. Linville274bfb82008-10-29 11:35:05 -0400581static void lib80211_michael_mic_failure(struct net_device *dev,
582 struct ieee80211_hdr *hdr,
James Ketrenosee34af32005-09-21 11:54:36 -0500583 int keyidx)
Jeff Garzikb4538722005-05-12 22:48:20 -0400584{
585 union iwreq_data wrqu;
586 struct iw_michaelmicfailure ev;
587
588 /* TODO: needed parameters: count, keyid, key type, TSC */
589 memset(&ev, 0, sizeof(ev));
590 ev.flags = keyidx & IW_MICFAILURE_KEY_ID;
591 if (hdr->addr1[0] & 0x01)
592 ev.flags |= IW_MICFAILURE_GROUP;
593 else
594 ev.flags |= IW_MICFAILURE_PAIRWISE;
595 ev.src_addr.sa_family = ARPHRD_ETHER;
596 memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN);
597 memset(&wrqu, 0, sizeof(wrqu));
598 wrqu.data.length = sizeof(ev);
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400599 wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev);
Jeff Garzikb4538722005-05-12 22:48:20 -0400600}
Jeff Garzikb4538722005-05-12 22:48:20 -0400601
John W. Linville274bfb82008-10-29 11:35:05 -0400602static int lib80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400603 int hdr_len, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400604{
John W. Linville274bfb82008-10-29 11:35:05 -0400605 struct lib80211_tkip_data *tkey = priv;
Jeff Garzikb4538722005-05-12 22:48:20 -0400606 u8 mic[8];
607
608 if (!tkey->key_set)
609 return -1;
610
611 michael_mic_hdr(skb, tkey->rx_hdr);
Zhu Yi5a656942006-08-21 11:33:56 +0800612 if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr,
Jeff Garzikb4538722005-05-12 22:48:20 -0400613 skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
614 return -1;
615 if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
John W. Linville274bfb82008-10-29 11:35:05 -0400616 struct ieee80211_hdr *hdr;
617 hdr = (struct ieee80211_hdr *)skb->data;
Jeff Garzikb4538722005-05-12 22:48:20 -0400618 printk(KERN_DEBUG "%s: Michael MIC verification failed for "
Johannes Berge1749612008-10-27 15:59:26 -0700619 "MSDU from %pM keyidx=%d\n",
620 skb->dev ? skb->dev->name : "N/A", hdr->addr2,
Jeff Garzikb4538722005-05-12 22:48:20 -0400621 keyidx);
622 if (skb->dev)
John W. Linville274bfb82008-10-29 11:35:05 -0400623 lib80211_michael_mic_failure(skb->dev, hdr, keyidx);
Jeff Garzikb4538722005-05-12 22:48:20 -0400624 tkey->dot11RSNAStatsTKIPLocalMICFailures++;
625 return -1;
626 }
627
628 /* Update TSC counters for RX now that the packet verification has
629 * completed. */
630 tkey->rx_iv32 = tkey->rx_iv32_new;
631 tkey->rx_iv16 = tkey->rx_iv16_new;
632
633 skb_trim(skb, skb->len - 8);
634
635 return 0;
636}
637
John W. Linville274bfb82008-10-29 11:35:05 -0400638static int lib80211_tkip_set_key(void *key, int len, u8 * seq, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400639{
John W. Linville274bfb82008-10-29 11:35:05 -0400640 struct lib80211_tkip_data *tkey = priv;
Jeff Garzikb4538722005-05-12 22:48:20 -0400641 int keyidx;
Kees Cookd17504b2018-07-15 20:52:26 -0700642 struct crypto_shash *tfm = tkey->tx_tfm_michael;
Johannes Bergb802a5d2018-10-01 09:16:08 +0200643 struct crypto_cipher *tfm2 = tkey->tx_tfm_arc4;
Kees Cookd17504b2018-07-15 20:52:26 -0700644 struct crypto_shash *tfm3 = tkey->rx_tfm_michael;
Johannes Bergb802a5d2018-10-01 09:16:08 +0200645 struct crypto_cipher *tfm4 = tkey->rx_tfm_arc4;
Jeff Garzikb4538722005-05-12 22:48:20 -0400646
647 keyidx = tkey->key_idx;
648 memset(tkey, 0, sizeof(*tkey));
649 tkey->key_idx = keyidx;
Zhu Yi5a656942006-08-21 11:33:56 +0800650 tkey->tx_tfm_michael = tfm;
651 tkey->tx_tfm_arc4 = tfm2;
652 tkey->rx_tfm_michael = tfm3;
653 tkey->rx_tfm_arc4 = tfm4;
Jeff Garzikb4538722005-05-12 22:48:20 -0400654 if (len == TKIP_KEY_LEN) {
655 memcpy(tkey->key, key, TKIP_KEY_LEN);
656 tkey->key_set = 1;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400657 tkey->tx_iv16 = 1; /* TSC is initialized to 1 */
Jeff Garzikb4538722005-05-12 22:48:20 -0400658 if (seq) {
659 tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) |
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400660 (seq[3] << 8) | seq[2];
Jeff Garzikb4538722005-05-12 22:48:20 -0400661 tkey->rx_iv16 = (seq[1] << 8) | seq[0];
662 }
663 } else if (len == 0)
664 tkey->key_set = 0;
665 else
666 return -1;
667
668 return 0;
669}
670
John W. Linville274bfb82008-10-29 11:35:05 -0400671static int lib80211_tkip_get_key(void *key, int len, u8 * seq, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400672{
John W. Linville274bfb82008-10-29 11:35:05 -0400673 struct lib80211_tkip_data *tkey = priv;
Jeff Garzikb4538722005-05-12 22:48:20 -0400674
675 if (len < TKIP_KEY_LEN)
676 return -1;
677
678 if (!tkey->key_set)
679 return 0;
680 memcpy(key, tkey->key, TKIP_KEY_LEN);
681
682 if (seq) {
683 /* Return the sequence number of the last transmitted frame. */
684 u16 iv16 = tkey->tx_iv16;
685 u32 iv32 = tkey->tx_iv32;
686 if (iv16 == 0)
687 iv32--;
688 iv16--;
689 seq[0] = tkey->tx_iv16;
690 seq[1] = tkey->tx_iv16 >> 8;
691 seq[2] = tkey->tx_iv32;
692 seq[3] = tkey->tx_iv32 >> 8;
693 seq[4] = tkey->tx_iv32 >> 16;
694 seq[5] = tkey->tx_iv32 >> 24;
695 }
696
697 return TKIP_KEY_LEN;
698}
699
David Howells6bbefe82013-04-10 21:13:23 +0100700static void lib80211_tkip_print_stats(struct seq_file *m, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400701{
John W. Linville274bfb82008-10-29 11:35:05 -0400702 struct lib80211_tkip_data *tkip = priv;
David Howells6bbefe82013-04-10 21:13:23 +0100703 seq_printf(m,
704 "key[%d] alg=TKIP key_set=%d "
705 "tx_pn=%02x%02x%02x%02x%02x%02x "
706 "rx_pn=%02x%02x%02x%02x%02x%02x "
707 "replays=%d icv_errors=%d local_mic_failures=%d\n",
708 tkip->key_idx, tkip->key_set,
709 (tkip->tx_iv32 >> 24) & 0xff,
710 (tkip->tx_iv32 >> 16) & 0xff,
711 (tkip->tx_iv32 >> 8) & 0xff,
712 tkip->tx_iv32 & 0xff,
713 (tkip->tx_iv16 >> 8) & 0xff,
714 tkip->tx_iv16 & 0xff,
715 (tkip->rx_iv32 >> 24) & 0xff,
716 (tkip->rx_iv32 >> 16) & 0xff,
717 (tkip->rx_iv32 >> 8) & 0xff,
718 tkip->rx_iv32 & 0xff,
719 (tkip->rx_iv16 >> 8) & 0xff,
720 tkip->rx_iv16 & 0xff,
721 tkip->dot11RSNAStatsTKIPReplays,
722 tkip->dot11RSNAStatsTKIPICVErrors,
723 tkip->dot11RSNAStatsTKIPLocalMICFailures);
Jeff Garzikb4538722005-05-12 22:48:20 -0400724}
725
John W. Linville274bfb82008-10-29 11:35:05 -0400726static struct lib80211_crypto_ops lib80211_crypt_tkip = {
James Ketrenos74079fd2005-09-13 17:35:21 -0500727 .name = "TKIP",
John W. Linville274bfb82008-10-29 11:35:05 -0400728 .init = lib80211_tkip_init,
729 .deinit = lib80211_tkip_deinit,
John W. Linville274bfb82008-10-29 11:35:05 -0400730 .encrypt_mpdu = lib80211_tkip_encrypt,
731 .decrypt_mpdu = lib80211_tkip_decrypt,
732 .encrypt_msdu = lib80211_michael_mic_add,
733 .decrypt_msdu = lib80211_michael_mic_verify,
734 .set_key = lib80211_tkip_set_key,
735 .get_key = lib80211_tkip_get_key,
736 .print_stats = lib80211_tkip_print_stats,
James Ketrenos1264fc02005-09-21 11:54:53 -0500737 .extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */
738 .extra_mpdu_postfix_len = 4, /* ICV */
739 .extra_msdu_postfix_len = 8, /* MIC */
John W. Linville274bfb82008-10-29 11:35:05 -0400740 .get_flags = lib80211_tkip_get_flags,
741 .set_flags = lib80211_tkip_set_flags,
James Ketrenos74079fd2005-09-13 17:35:21 -0500742 .owner = THIS_MODULE,
Jeff Garzikb4538722005-05-12 22:48:20 -0400743};
744
John W. Linville274bfb82008-10-29 11:35:05 -0400745static int __init lib80211_crypto_tkip_init(void)
Jeff Garzikb4538722005-05-12 22:48:20 -0400746{
John W. Linville274bfb82008-10-29 11:35:05 -0400747 return lib80211_register_crypto_ops(&lib80211_crypt_tkip);
Jeff Garzikb4538722005-05-12 22:48:20 -0400748}
749
John W. Linville274bfb82008-10-29 11:35:05 -0400750static void __exit lib80211_crypto_tkip_exit(void)
Jeff Garzikb4538722005-05-12 22:48:20 -0400751{
John W. Linville274bfb82008-10-29 11:35:05 -0400752 lib80211_unregister_crypto_ops(&lib80211_crypt_tkip);
Jeff Garzikb4538722005-05-12 22:48:20 -0400753}
754
John W. Linville274bfb82008-10-29 11:35:05 -0400755module_init(lib80211_crypto_tkip_init);
756module_exit(lib80211_crypto_tkip_exit);