blob: 0fd155c4e0a6d931cff9e14bb94698cf8c90cb3c [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>
Ard Biesheuvel4be29702019-06-12 18:19:56 +020016#include <linux/fips.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040017#include <linux/module.h>
18#include <linux/init.h>
19#include <linux/slab.h>
20#include <linux/random.h>
Ralf Baechle11763602007-10-23 20:42:11 +020021#include <linux/scatterlist.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040022#include <linux/skbuff.h>
23#include <linux/netdevice.h>
Al Virod7fe0f22006-12-03 23:15:30 -050024#include <linux/mm.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040025#include <linux/if_ether.h>
26#include <linux/if_arp.h>
27#include <asm/string.h>
28
John W. Linville274bfb82008-10-29 11:35:05 -040029#include <linux/wireless.h>
30#include <linux/ieee80211.h>
31#include <net/iw_handler.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040032
Ard Biesheuvel4be29702019-06-12 18:19:56 +020033#include <crypto/arc4.h>
Herbert Xu608fb342016-01-24 21:18:09 +080034#include <crypto/hash.h>
Johannes Bergb802a5d2018-10-01 09:16:08 +020035#include <linux/crypto.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040036#include <linux/crc32.h>
37
John W. Linville274bfb82008-10-29 11:35:05 -040038#include <net/lib80211.h>
39
Jeff Garzikb4538722005-05-12 22:48:20 -040040MODULE_AUTHOR("Jouni Malinen");
John W. Linville274bfb82008-10-29 11:35:05 -040041MODULE_DESCRIPTION("lib80211 crypt: TKIP");
Jeff Garzikb4538722005-05-12 22:48:20 -040042MODULE_LICENSE("GPL");
43
Andriy Tkachuk299af9d2010-02-02 16:33:53 +020044#define TKIP_HDR_LEN 8
45
John W. Linville274bfb82008-10-29 11:35:05 -040046struct lib80211_tkip_data {
Jeff Garzikb4538722005-05-12 22:48:20 -040047#define TKIP_KEY_LEN 32
48 u8 key[TKIP_KEY_LEN];
49 int key_set;
50
51 u32 tx_iv32;
52 u16 tx_iv16;
53 u16 tx_ttak[5];
54 int tx_phase1_done;
55
56 u32 rx_iv32;
57 u16 rx_iv16;
58 u16 rx_ttak[5];
59 int rx_phase1_done;
60 u32 rx_iv32_new;
61 u16 rx_iv16_new;
62
63 u32 dot11RSNAStatsTKIPReplays;
64 u32 dot11RSNAStatsTKIPICVErrors;
65 u32 dot11RSNAStatsTKIPLocalMICFailures;
66
67 int key_idx;
68
Ard Biesheuvel4be29702019-06-12 18:19:56 +020069 struct arc4_ctx rx_ctx_arc4;
70 struct arc4_ctx tx_ctx_arc4;
Kees Cookd17504b2018-07-15 20:52:26 -070071 struct crypto_shash *rx_tfm_michael;
Kees Cookd17504b2018-07-15 20:52:26 -070072 struct crypto_shash *tx_tfm_michael;
Jeff Garzikb4538722005-05-12 22:48:20 -040073
74 /* scratch buffers for virt_to_page() (crypto API) */
75 u8 rx_hdr[16], tx_hdr[16];
James Ketrenos20d64712005-09-21 11:53:43 -050076
James Ketrenos6eb6edf2005-09-22 10:34:15 +000077 unsigned long flags;
Jeff Garzikb4538722005-05-12 22:48:20 -040078};
79
John W. Linville274bfb82008-10-29 11:35:05 -040080static unsigned long lib80211_tkip_set_flags(unsigned long flags, void *priv)
James Ketrenos6eb6edf2005-09-22 10:34:15 +000081{
John W. Linville274bfb82008-10-29 11:35:05 -040082 struct lib80211_tkip_data *_priv = priv;
James Ketrenos6eb6edf2005-09-22 10:34:15 +000083 unsigned long old_flags = _priv->flags;
84 _priv->flags = flags;
85 return old_flags;
86}
87
John W. Linville274bfb82008-10-29 11:35:05 -040088static unsigned long lib80211_tkip_get_flags(void *priv)
James Ketrenos6eb6edf2005-09-22 10:34:15 +000089{
John W. Linville274bfb82008-10-29 11:35:05 -040090 struct lib80211_tkip_data *_priv = priv;
James Ketrenos6eb6edf2005-09-22 10:34:15 +000091 return _priv->flags;
92}
93
John W. Linville274bfb82008-10-29 11:35:05 -040094static void *lib80211_tkip_init(int key_idx)
Jeff Garzikb4538722005-05-12 22:48:20 -040095{
John W. Linville274bfb82008-10-29 11:35:05 -040096 struct lib80211_tkip_data *priv;
Jeff Garzikb4538722005-05-12 22:48:20 -040097
Ard Biesheuvel4be29702019-06-12 18:19:56 +020098 if (fips_enabled)
99 return NULL;
100
Zhu Yi8aa914b2006-01-19 16:22:07 +0800101 priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
Jeff Garzikb4538722005-05-12 22:48:20 -0400102 if (priv == NULL)
103 goto fail;
James Ketrenos20d64712005-09-21 11:53:43 -0500104
Jeff Garzikb4538722005-05-12 22:48:20 -0400105 priv->key_idx = key_idx;
106
Kees Cookd17504b2018-07-15 20:52:26 -0700107 priv->tx_tfm_michael = crypto_alloc_shash("michael_mic", 0, 0);
Jeff Garzik28eb1772006-09-22 20:10:23 -0400108 if (IS_ERR(priv->tx_tfm_michael)) {
Jeff Garzik18379872006-09-22 21:19:05 -0400109 priv->tx_tfm_michael = NULL;
Zhu Yi5a656942006-08-21 11:33:56 +0800110 goto fail;
111 }
112
Kees Cookd17504b2018-07-15 20:52:26 -0700113 priv->rx_tfm_michael = crypto_alloc_shash("michael_mic", 0, 0);
Jeff Garzik28eb1772006-09-22 20:10:23 -0400114 if (IS_ERR(priv->rx_tfm_michael)) {
Jeff Garzik18379872006-09-22 21:19:05 -0400115 priv->rx_tfm_michael = NULL;
Jeff Garzikb4538722005-05-12 22:48:20 -0400116 goto fail;
117 }
118
119 return priv;
120
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400121 fail:
Jeff Garzikb4538722005-05-12 22:48:20 -0400122 if (priv) {
Kees Cookd17504b2018-07-15 20:52:26 -0700123 crypto_free_shash(priv->tx_tfm_michael);
Kees Cookd17504b2018-07-15 20:52:26 -0700124 crypto_free_shash(priv->rx_tfm_michael);
Jeff Garzikb4538722005-05-12 22:48:20 -0400125 kfree(priv);
126 }
127
128 return NULL;
129}
130
John W. Linville274bfb82008-10-29 11:35:05 -0400131static void lib80211_tkip_deinit(void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400132{
John W. Linville274bfb82008-10-29 11:35:05 -0400133 struct lib80211_tkip_data *_priv = priv;
Zhu Yi5a656942006-08-21 11:33:56 +0800134 if (_priv) {
Kees Cookd17504b2018-07-15 20:52:26 -0700135 crypto_free_shash(_priv->tx_tfm_michael);
Kees Cookd17504b2018-07-15 20:52:26 -0700136 crypto_free_shash(_priv->rx_tfm_michael);
Zhu Yi5a656942006-08-21 11:33:56 +0800137 }
Ard Biesheuvel4be29702019-06-12 18:19:56 +0200138 kzfree(priv);
Jeff Garzikb4538722005-05-12 22:48:20 -0400139}
140
Jeff Garzikb4538722005-05-12 22:48:20 -0400141static inline u16 RotR1(u16 val)
142{
143 return (val >> 1) | (val << 15);
144}
145
Jeff Garzikb4538722005-05-12 22:48:20 -0400146static inline u8 Lo8(u16 val)
147{
148 return val & 0xff;
149}
150
Jeff Garzikb4538722005-05-12 22:48:20 -0400151static inline u8 Hi8(u16 val)
152{
153 return val >> 8;
154}
155
Jeff Garzikb4538722005-05-12 22:48:20 -0400156static inline u16 Lo16(u32 val)
157{
158 return val & 0xffff;
159}
160
Jeff Garzikb4538722005-05-12 22:48:20 -0400161static inline u16 Hi16(u32 val)
162{
163 return val >> 16;
164}
165
Jeff Garzikb4538722005-05-12 22:48:20 -0400166static inline u16 Mk16(u8 hi, u8 lo)
167{
168 return lo | (((u16) hi) << 8);
169}
170
Al Virod9e94d52007-12-29 05:01:07 -0500171static inline u16 Mk16_le(__le16 * v)
Jeff Garzikb4538722005-05-12 22:48:20 -0400172{
173 return le16_to_cpu(*v);
174}
175
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400176static const u16 Sbox[256] = {
Jeff Garzikb4538722005-05-12 22:48:20 -0400177 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
178 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
179 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
180 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
181 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
182 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
183 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
184 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
185 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
186 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
187 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
188 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
189 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
190 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
191 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
192 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
193 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
194 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
195 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
196 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
197 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
198 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
199 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
200 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
201 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
202 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
203 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
204 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
205 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
206 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
207 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
208 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
209};
210
Jeff Garzikb4538722005-05-12 22:48:20 -0400211static inline u16 _S_(u16 v)
212{
213 u16 t = Sbox[Hi8(v)];
214 return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8));
215}
216
Jeff Garzikb4538722005-05-12 22:48:20 -0400217#define PHASE1_LOOP_COUNT 8
218
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400219static void tkip_mixing_phase1(u16 * TTAK, const u8 * TK, const u8 * TA,
220 u32 IV32)
Jeff Garzikb4538722005-05-12 22:48:20 -0400221{
222 int i, j;
223
224 /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */
225 TTAK[0] = Lo16(IV32);
226 TTAK[1] = Hi16(IV32);
227 TTAK[2] = Mk16(TA[1], TA[0]);
228 TTAK[3] = Mk16(TA[3], TA[2]);
229 TTAK[4] = Mk16(TA[5], TA[4]);
230
231 for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
232 j = 2 * (i & 1);
233 TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j]));
234 TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j]));
235 TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j]));
236 TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j]));
237 TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i;
238 }
239}
240
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400241static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK,
Jeff Garzikb4538722005-05-12 22:48:20 -0400242 u16 IV16)
243{
244 /* Make temporary area overlap WEP seed so that the final copy can be
245 * avoided on little endian hosts. */
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400246 u16 *PPK = (u16 *) & WEPSeed[4];
Jeff Garzikb4538722005-05-12 22:48:20 -0400247
248 /* Step 1 - make copy of TTAK and bring in TSC */
249 PPK[0] = TTAK[0];
250 PPK[1] = TTAK[1];
251 PPK[2] = TTAK[2];
252 PPK[3] = TTAK[3];
253 PPK[4] = TTAK[4];
254 PPK[5] = TTAK[4] + IV16;
255
256 /* Step 2 - 96-bit bijective mixing using S-box */
Al Virod9e94d52007-12-29 05:01:07 -0500257 PPK[0] += _S_(PPK[5] ^ Mk16_le((__le16 *) & TK[0]));
258 PPK[1] += _S_(PPK[0] ^ Mk16_le((__le16 *) & TK[2]));
259 PPK[2] += _S_(PPK[1] ^ Mk16_le((__le16 *) & TK[4]));
260 PPK[3] += _S_(PPK[2] ^ Mk16_le((__le16 *) & TK[6]));
261 PPK[4] += _S_(PPK[3] ^ Mk16_le((__le16 *) & TK[8]));
262 PPK[5] += _S_(PPK[4] ^ Mk16_le((__le16 *) & TK[10]));
Jeff Garzikb4538722005-05-12 22:48:20 -0400263
Al Virod9e94d52007-12-29 05:01:07 -0500264 PPK[0] += RotR1(PPK[5] ^ Mk16_le((__le16 *) & TK[12]));
265 PPK[1] += RotR1(PPK[0] ^ Mk16_le((__le16 *) & TK[14]));
Jeff Garzikb4538722005-05-12 22:48:20 -0400266 PPK[2] += RotR1(PPK[1]);
267 PPK[3] += RotR1(PPK[2]);
268 PPK[4] += RotR1(PPK[3]);
269 PPK[5] += RotR1(PPK[4]);
270
271 /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value
272 * WEPSeed[0..2] is transmitted as WEP IV */
273 WEPSeed[0] = Hi8(IV16);
274 WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F;
275 WEPSeed[2] = Lo8(IV16);
Al Virod9e94d52007-12-29 05:01:07 -0500276 WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((__le16 *) & TK[0])) >> 1);
Jeff Garzikb4538722005-05-12 22:48:20 -0400277
278#ifdef __BIG_ENDIAN
279 {
280 int i;
281 for (i = 0; i < 6; i++)
282 PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8);
283 }
284#endif
285}
286
John W. Linville274bfb82008-10-29 11:35:05 -0400287static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len,
Zhu Yi9184d932006-01-19 16:22:32 +0800288 u8 * rc4key, int keylen, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400289{
John W. Linville274bfb82008-10-29 11:35:05 -0400290 struct lib80211_tkip_data *tkey = priv;
Zhu Yi9184d932006-01-19 16:22:32 +0800291 u8 *pos;
John W. Linville274bfb82008-10-29 11:35:05 -0400292 struct ieee80211_hdr *hdr;
Jeff Garzikb4538722005-05-12 22:48:20 -0400293
John W. Linville274bfb82008-10-29 11:35:05 -0400294 hdr = (struct ieee80211_hdr *)skb->data;
James Ketrenos20d64712005-09-21 11:53:43 -0500295
Andriy Tkachuk299af9d2010-02-02 16:33:53 +0200296 if (skb_headroom(skb) < TKIP_HDR_LEN || skb->len < hdr_len)
Zhu Yi9184d932006-01-19 16:22:32 +0800297 return -1;
298
299 if (rc4key == NULL || keylen < 16)
300 return -1;
Jeff Garzikb4538722005-05-12 22:48:20 -0400301
Jeff Garzikb4538722005-05-12 22:48:20 -0400302 if (!tkey->tx_phase1_done) {
303 tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2,
304 tkey->tx_iv32);
305 tkey->tx_phase1_done = 1;
306 }
307 tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16);
308
Andriy Tkachuk299af9d2010-02-02 16:33:53 +0200309 pos = skb_push(skb, TKIP_HDR_LEN);
310 memmove(pos, pos + TKIP_HDR_LEN, hdr_len);
Jeff Garzikb4538722005-05-12 22:48:20 -0400311 pos += hdr_len;
Jeff Garzikb4538722005-05-12 22:48:20 -0400312
James Ketrenos31b59ea2005-09-21 11:58:49 -0500313 *pos++ = *rc4key;
314 *pos++ = *(rc4key + 1);
315 *pos++ = *(rc4key + 2);
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400316 *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */ ;
Jeff Garzikb4538722005-05-12 22:48:20 -0400317 *pos++ = tkey->tx_iv32 & 0xff;
318 *pos++ = (tkey->tx_iv32 >> 8) & 0xff;
319 *pos++ = (tkey->tx_iv32 >> 16) & 0xff;
320 *pos++ = (tkey->tx_iv32 >> 24) & 0xff;
321
Zhu Yi9184d932006-01-19 16:22:32 +0800322 tkey->tx_iv16++;
323 if (tkey->tx_iv16 == 0) {
324 tkey->tx_phase1_done = 0;
325 tkey->tx_iv32++;
326 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400327
Andriy Tkachuk299af9d2010-02-02 16:33:53 +0200328 return TKIP_HDR_LEN;
James Ketrenos31b59ea2005-09-21 11:58:49 -0500329}
330
John W. Linville274bfb82008-10-29 11:35:05 -0400331static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
James Ketrenos31b59ea2005-09-21 11:58:49 -0500332{
John W. Linville274bfb82008-10-29 11:35:05 -0400333 struct lib80211_tkip_data *tkey = priv;
James Ketrenos31b59ea2005-09-21 11:58:49 -0500334 int len;
Zhu Yi9184d932006-01-19 16:22:32 +0800335 u8 rc4key[16], *pos, *icv;
336 u32 crc;
James Ketrenos31b59ea2005-09-21 11:58:49 -0500337
James Ketrenos6eb6edf2005-09-22 10:34:15 +0000338 if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
Joe Perchese87cc472012-05-13 21:56:26 +0000339 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
340 net_dbg_ratelimited("TKIP countermeasures: dropped TX packet to %pM\n",
341 hdr->addr1);
James Ketrenos31b59ea2005-09-21 11:58:49 -0500342 return -1;
343 }
344
345 if (skb_tailroom(skb) < 4 || skb->len < hdr_len)
346 return -1;
347
348 len = skb->len - hdr_len;
349 pos = skb->data + hdr_len;
350
John W. Linville274bfb82008-10-29 11:35:05 -0400351 if ((lib80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0)
James Ketrenos31b59ea2005-09-21 11:58:49 -0500352 return -1;
353
Zhu Yi9184d932006-01-19 16:22:32 +0800354 crc = ~crc32_le(~0, pos, len);
Andriy Tkachukd0833a62010-02-02 15:58:53 +0200355 icv = skb_put(skb, 4);
Zhu Yi9184d932006-01-19 16:22:32 +0800356 icv[0] = crc;
357 icv[1] = crc >> 8;
358 icv[2] = crc >> 16;
359 icv[3] = crc >> 24;
360
Ard Biesheuvel4be29702019-06-12 18:19:56 +0200361 arc4_setkey(&tkey->tx_ctx_arc4, rc4key, 16);
362 arc4_crypt(&tkey->tx_ctx_arc4, pos, pos, len + 4);
363
Johannes Bergb802a5d2018-10-01 09:16:08 +0200364 return 0;
Zhu Yib4328d82006-08-21 11:33:09 +0800365}
366
Jeff Garzik18379872006-09-22 21:19:05 -0400367/*
368 * deal with seq counter wrapping correctly.
369 * refer to timer_after() for jiffies wrapping handling
370 */
371static inline int tkip_replay_check(u32 iv32_n, u16 iv16_n,
372 u32 iv32_o, u16 iv16_o)
373{
374 if ((s32)iv32_n - (s32)iv32_o < 0 ||
375 (iv32_n == iv32_o && iv16_n <= iv16_o))
376 return 1;
377 return 0;
378}
379
John W. Linville274bfb82008-10-29 11:35:05 -0400380static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400381{
John W. Linville274bfb82008-10-29 11:35:05 -0400382 struct lib80211_tkip_data *tkey = priv;
Jeff Garzikb4538722005-05-12 22:48:20 -0400383 u8 rc4key[16];
384 u8 keyidx, *pos;
385 u32 iv32;
386 u16 iv16;
John W. Linville274bfb82008-10-29 11:35:05 -0400387 struct ieee80211_hdr *hdr;
Jeff Garzikb4538722005-05-12 22:48:20 -0400388 u8 icv[4];
389 u32 crc;
Jeff Garzikb4538722005-05-12 22:48:20 -0400390 int plen;
391
John W. Linville274bfb82008-10-29 11:35:05 -0400392 hdr = (struct ieee80211_hdr *)skb->data;
James Ketrenos20d64712005-09-21 11:53:43 -0500393
James Ketrenos6eb6edf2005-09-22 10:34:15 +0000394 if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
Joe Perchese87cc472012-05-13 21:56:26 +0000395 net_dbg_ratelimited("TKIP countermeasures: dropped received packet from %pM\n",
396 hdr->addr2);
James Ketrenos20d64712005-09-21 11:53:43 -0500397 return -1;
398 }
399
Andriy Tkachuk299af9d2010-02-02 16:33:53 +0200400 if (skb->len < hdr_len + TKIP_HDR_LEN + 4)
Jeff Garzikb4538722005-05-12 22:48:20 -0400401 return -1;
402
Jeff Garzikb4538722005-05-12 22:48:20 -0400403 pos = skb->data + hdr_len;
404 keyidx = pos[3];
405 if (!(keyidx & (1 << 5))) {
Joe Perchese87cc472012-05-13 21:56:26 +0000406 net_dbg_ratelimited("TKIP: received packet without ExtIV flag from %pM\n",
407 hdr->addr2);
Jeff Garzikb4538722005-05-12 22:48:20 -0400408 return -2;
409 }
410 keyidx >>= 6;
411 if (tkey->key_idx != keyidx) {
Johannes Berg996bf992015-11-06 12:02:31 +0100412 net_dbg_ratelimited("TKIP: RX tkey->key_idx=%d frame keyidx=%d\n",
413 tkey->key_idx, keyidx);
Jeff Garzikb4538722005-05-12 22:48:20 -0400414 return -6;
415 }
416 if (!tkey->key_set) {
Joe Perchese87cc472012-05-13 21:56:26 +0000417 net_dbg_ratelimited("TKIP: received packet from %pM with keyid=%d that does not have a configured key\n",
418 hdr->addr2, keyidx);
Jeff Garzikb4538722005-05-12 22:48:20 -0400419 return -3;
420 }
421 iv16 = (pos[0] << 8) | pos[2];
422 iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
Andriy Tkachuk299af9d2010-02-02 16:33:53 +0200423 pos += TKIP_HDR_LEN;
Jeff Garzikb4538722005-05-12 22:48:20 -0400424
Zhu Yib4328d82006-08-21 11:33:09 +0800425 if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) {
John W. Linville6f16bf32009-03-11 11:05:25 -0400426#ifdef CONFIG_LIB80211_DEBUG
Joe Perchese87cc472012-05-13 21:56:26 +0000427 net_dbg_ratelimited("TKIP: replay detected: STA=%pM previous TSC %08x%04x received TSC %08x%04x\n",
428 hdr->addr2, tkey->rx_iv32, tkey->rx_iv16,
429 iv32, iv16);
John W. Linville6f16bf32009-03-11 11:05:25 -0400430#endif
Jeff Garzikb4538722005-05-12 22:48:20 -0400431 tkey->dot11RSNAStatsTKIPReplays++;
432 return -4;
433 }
434
435 if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) {
436 tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32);
437 tkey->rx_phase1_done = 1;
438 }
439 tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16);
440
441 plen = skb->len - hdr_len - 12;
442
Ard Biesheuvel4be29702019-06-12 18:19:56 +0200443 arc4_setkey(&tkey->rx_ctx_arc4, rc4key, 16);
444 arc4_crypt(&tkey->rx_ctx_arc4, pos, pos, plen + 4);
Jeff Garzikb4538722005-05-12 22:48:20 -0400445
446 crc = ~crc32_le(~0, pos, plen);
447 icv[0] = crc;
448 icv[1] = crc >> 8;
449 icv[2] = crc >> 16;
450 icv[3] = crc >> 24;
451 if (memcmp(icv, pos + plen, 4) != 0) {
452 if (iv32 != tkey->rx_iv32) {
453 /* Previously cached Phase1 result was already lost, so
454 * it needs to be recalculated for the next packet. */
455 tkey->rx_phase1_done = 0;
456 }
John W. Linville6f16bf32009-03-11 11:05:25 -0400457#ifdef CONFIG_LIB80211_DEBUG
Joe Perchese87cc472012-05-13 21:56:26 +0000458 net_dbg_ratelimited("TKIP: ICV error detected: STA=%pM\n",
459 hdr->addr2);
John W. Linville6f16bf32009-03-11 11:05:25 -0400460#endif
Jeff Garzikb4538722005-05-12 22:48:20 -0400461 tkey->dot11RSNAStatsTKIPICVErrors++;
462 return -5;
463 }
464
465 /* Update real counters only after Michael MIC verification has
466 * completed */
467 tkey->rx_iv32_new = iv32;
468 tkey->rx_iv16_new = iv16;
469
470 /* Remove IV and ICV */
Andriy Tkachuk299af9d2010-02-02 16:33:53 +0200471 memmove(skb->data + TKIP_HDR_LEN, skb->data, hdr_len);
472 skb_pull(skb, TKIP_HDR_LEN);
Jeff Garzikb4538722005-05-12 22:48:20 -0400473 skb_trim(skb, skb->len - 4);
474
475 return keyidx;
476}
477
Kees Cookd17504b2018-07-15 20:52:26 -0700478static int michael_mic(struct crypto_shash *tfm_michael, u8 *key, u8 *hdr,
479 u8 *data, size_t data_len, u8 *mic)
Jeff Garzikb4538722005-05-12 22:48:20 -0400480{
Kees Cookd17504b2018-07-15 20:52:26 -0700481 SHASH_DESC_ON_STACK(desc, tfm_michael);
Herbert Xu608fb342016-01-24 21:18:09 +0800482 int err;
Jeff Garzikb4538722005-05-12 22:48:20 -0400483
Zhu Yi5a656942006-08-21 11:33:56 +0800484 if (tfm_michael == NULL) {
Joe Perchese9c02682010-11-16 19:56:49 -0800485 pr_warn("%s(): tfm_michael == NULL\n", __func__);
Jeff Garzikb4538722005-05-12 22:48:20 -0400486 return -1;
487 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400488
Kees Cookd17504b2018-07-15 20:52:26 -0700489 desc->tfm = tfm_michael;
Kees Cookd17504b2018-07-15 20:52:26 -0700490
491 if (crypto_shash_setkey(tfm_michael, key, 8))
Herbert Xu35058682006-08-24 19:10:20 +1000492 return -1;
Jeff Garzikb4538722005-05-12 22:48:20 -0400493
Kees Cookd17504b2018-07-15 20:52:26 -0700494 err = crypto_shash_init(desc);
495 if (err)
496 goto out;
497 err = crypto_shash_update(desc, hdr, 16);
498 if (err)
499 goto out;
500 err = crypto_shash_update(desc, data, data_len);
501 if (err)
502 goto out;
503 err = crypto_shash_final(desc, mic);
504
505out:
506 shash_desc_zero(desc);
Herbert Xu608fb342016-01-24 21:18:09 +0800507 return err;
Jeff Garzikb4538722005-05-12 22:48:20 -0400508}
509
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400510static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr)
Jeff Garzikb4538722005-05-12 22:48:20 -0400511{
John W. Linville274bfb82008-10-29 11:35:05 -0400512 struct ieee80211_hdr *hdr11;
Jeff Garzikb4538722005-05-12 22:48:20 -0400513
John W. Linville274bfb82008-10-29 11:35:05 -0400514 hdr11 = (struct ieee80211_hdr *)skb->data;
Zhu Yiea284152006-04-13 17:17:06 +0800515
John W. Linville274bfb82008-10-29 11:35:05 -0400516 switch (le16_to_cpu(hdr11->frame_control) &
Jeff Garzikb4538722005-05-12 22:48:20 -0400517 (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
518 case IEEE80211_FCTL_TODS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400519 memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
520 memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400521 break;
522 case IEEE80211_FCTL_FROMDS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400523 memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
524 memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400525 break;
526 case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400527 memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
528 memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400529 break;
Arnd Bergmann10f33662016-10-24 17:38:35 +0200530 default:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400531 memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
532 memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400533 break;
534 }
535
John W. Linville274bfb82008-10-29 11:35:05 -0400536 if (ieee80211_is_data_qos(hdr11->frame_control)) {
John W. Linville3f6ff6b2010-07-20 12:09:11 -0400537 hdr[12] = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(hdr11)))
John W. Linville274bfb82008-10-29 11:35:05 -0400538 & IEEE80211_QOS_CTL_TID_MASK;
Zhu Yiea284152006-04-13 17:17:06 +0800539 } else
540 hdr[12] = 0; /* priority */
541
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400542 hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */
Jeff Garzikb4538722005-05-12 22:48:20 -0400543}
544
John W. Linville274bfb82008-10-29 11:35:05 -0400545static int lib80211_michael_mic_add(struct sk_buff *skb, int hdr_len,
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400546 void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400547{
John W. Linville274bfb82008-10-29 11:35:05 -0400548 struct lib80211_tkip_data *tkey = priv;
Jeff Garzikb4538722005-05-12 22:48:20 -0400549 u8 *pos;
550
551 if (skb_tailroom(skb) < 8 || skb->len < hdr_len) {
552 printk(KERN_DEBUG "Invalid packet for Michael MIC add "
553 "(tailroom=%d hdr_len=%d skb->len=%d)\n",
554 skb_tailroom(skb), hdr_len, skb->len);
555 return -1;
556 }
557
558 michael_mic_hdr(skb, tkey->tx_hdr);
559 pos = skb_put(skb, 8);
Zhu Yi5a656942006-08-21 11:33:56 +0800560 if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr,
Jeff Garzikb4538722005-05-12 22:48:20 -0400561 skb->data + hdr_len, skb->len - 8 - hdr_len, pos))
562 return -1;
563
564 return 0;
565}
566
John W. Linville274bfb82008-10-29 11:35:05 -0400567static void lib80211_michael_mic_failure(struct net_device *dev,
568 struct ieee80211_hdr *hdr,
James Ketrenosee34af32005-09-21 11:54:36 -0500569 int keyidx)
Jeff Garzikb4538722005-05-12 22:48:20 -0400570{
571 union iwreq_data wrqu;
572 struct iw_michaelmicfailure ev;
573
574 /* TODO: needed parameters: count, keyid, key type, TSC */
575 memset(&ev, 0, sizeof(ev));
576 ev.flags = keyidx & IW_MICFAILURE_KEY_ID;
577 if (hdr->addr1[0] & 0x01)
578 ev.flags |= IW_MICFAILURE_GROUP;
579 else
580 ev.flags |= IW_MICFAILURE_PAIRWISE;
581 ev.src_addr.sa_family = ARPHRD_ETHER;
582 memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN);
583 memset(&wrqu, 0, sizeof(wrqu));
584 wrqu.data.length = sizeof(ev);
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400585 wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev);
Jeff Garzikb4538722005-05-12 22:48:20 -0400586}
Jeff Garzikb4538722005-05-12 22:48:20 -0400587
John W. Linville274bfb82008-10-29 11:35:05 -0400588static int lib80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400589 int hdr_len, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400590{
John W. Linville274bfb82008-10-29 11:35:05 -0400591 struct lib80211_tkip_data *tkey = priv;
Jeff Garzikb4538722005-05-12 22:48:20 -0400592 u8 mic[8];
593
594 if (!tkey->key_set)
595 return -1;
596
597 michael_mic_hdr(skb, tkey->rx_hdr);
Zhu Yi5a656942006-08-21 11:33:56 +0800598 if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr,
Jeff Garzikb4538722005-05-12 22:48:20 -0400599 skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
600 return -1;
601 if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
John W. Linville274bfb82008-10-29 11:35:05 -0400602 struct ieee80211_hdr *hdr;
603 hdr = (struct ieee80211_hdr *)skb->data;
Jeff Garzikb4538722005-05-12 22:48:20 -0400604 printk(KERN_DEBUG "%s: Michael MIC verification failed for "
Johannes Berge1749612008-10-27 15:59:26 -0700605 "MSDU from %pM keyidx=%d\n",
606 skb->dev ? skb->dev->name : "N/A", hdr->addr2,
Jeff Garzikb4538722005-05-12 22:48:20 -0400607 keyidx);
608 if (skb->dev)
John W. Linville274bfb82008-10-29 11:35:05 -0400609 lib80211_michael_mic_failure(skb->dev, hdr, keyidx);
Jeff Garzikb4538722005-05-12 22:48:20 -0400610 tkey->dot11RSNAStatsTKIPLocalMICFailures++;
611 return -1;
612 }
613
614 /* Update TSC counters for RX now that the packet verification has
615 * completed. */
616 tkey->rx_iv32 = tkey->rx_iv32_new;
617 tkey->rx_iv16 = tkey->rx_iv16_new;
618
619 skb_trim(skb, skb->len - 8);
620
621 return 0;
622}
623
John W. Linville274bfb82008-10-29 11:35:05 -0400624static int lib80211_tkip_set_key(void *key, int len, u8 * seq, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400625{
John W. Linville274bfb82008-10-29 11:35:05 -0400626 struct lib80211_tkip_data *tkey = priv;
Jeff Garzikb4538722005-05-12 22:48:20 -0400627 int keyidx;
Kees Cookd17504b2018-07-15 20:52:26 -0700628 struct crypto_shash *tfm = tkey->tx_tfm_michael;
Ard Biesheuvel4be29702019-06-12 18:19:56 +0200629 struct arc4_ctx *tfm2 = &tkey->tx_ctx_arc4;
Kees Cookd17504b2018-07-15 20:52:26 -0700630 struct crypto_shash *tfm3 = tkey->rx_tfm_michael;
Ard Biesheuvel4be29702019-06-12 18:19:56 +0200631 struct arc4_ctx *tfm4 = &tkey->rx_ctx_arc4;
Jeff Garzikb4538722005-05-12 22:48:20 -0400632
633 keyidx = tkey->key_idx;
634 memset(tkey, 0, sizeof(*tkey));
635 tkey->key_idx = keyidx;
Zhu Yi5a656942006-08-21 11:33:56 +0800636 tkey->tx_tfm_michael = tfm;
Ard Biesheuvel4be29702019-06-12 18:19:56 +0200637 tkey->tx_ctx_arc4 = *tfm2;
Zhu Yi5a656942006-08-21 11:33:56 +0800638 tkey->rx_tfm_michael = tfm3;
Ard Biesheuvel4be29702019-06-12 18:19:56 +0200639 tkey->rx_ctx_arc4 = *tfm4;
Jeff Garzikb4538722005-05-12 22:48:20 -0400640 if (len == TKIP_KEY_LEN) {
641 memcpy(tkey->key, key, TKIP_KEY_LEN);
642 tkey->key_set = 1;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400643 tkey->tx_iv16 = 1; /* TSC is initialized to 1 */
Jeff Garzikb4538722005-05-12 22:48:20 -0400644 if (seq) {
645 tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) |
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400646 (seq[3] << 8) | seq[2];
Jeff Garzikb4538722005-05-12 22:48:20 -0400647 tkey->rx_iv16 = (seq[1] << 8) | seq[0];
648 }
649 } else if (len == 0)
650 tkey->key_set = 0;
651 else
652 return -1;
653
654 return 0;
655}
656
John W. Linville274bfb82008-10-29 11:35:05 -0400657static int lib80211_tkip_get_key(void *key, int len, u8 * seq, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400658{
John W. Linville274bfb82008-10-29 11:35:05 -0400659 struct lib80211_tkip_data *tkey = priv;
Jeff Garzikb4538722005-05-12 22:48:20 -0400660
661 if (len < TKIP_KEY_LEN)
662 return -1;
663
664 if (!tkey->key_set)
665 return 0;
666 memcpy(key, tkey->key, TKIP_KEY_LEN);
667
668 if (seq) {
669 /* Return the sequence number of the last transmitted frame. */
670 u16 iv16 = tkey->tx_iv16;
671 u32 iv32 = tkey->tx_iv32;
672 if (iv16 == 0)
673 iv32--;
674 iv16--;
675 seq[0] = tkey->tx_iv16;
676 seq[1] = tkey->tx_iv16 >> 8;
677 seq[2] = tkey->tx_iv32;
678 seq[3] = tkey->tx_iv32 >> 8;
679 seq[4] = tkey->tx_iv32 >> 16;
680 seq[5] = tkey->tx_iv32 >> 24;
681 }
682
683 return TKIP_KEY_LEN;
684}
685
David Howells6bbefe82013-04-10 21:13:23 +0100686static void lib80211_tkip_print_stats(struct seq_file *m, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400687{
John W. Linville274bfb82008-10-29 11:35:05 -0400688 struct lib80211_tkip_data *tkip = priv;
David Howells6bbefe82013-04-10 21:13:23 +0100689 seq_printf(m,
690 "key[%d] alg=TKIP key_set=%d "
691 "tx_pn=%02x%02x%02x%02x%02x%02x "
692 "rx_pn=%02x%02x%02x%02x%02x%02x "
693 "replays=%d icv_errors=%d local_mic_failures=%d\n",
694 tkip->key_idx, tkip->key_set,
695 (tkip->tx_iv32 >> 24) & 0xff,
696 (tkip->tx_iv32 >> 16) & 0xff,
697 (tkip->tx_iv32 >> 8) & 0xff,
698 tkip->tx_iv32 & 0xff,
699 (tkip->tx_iv16 >> 8) & 0xff,
700 tkip->tx_iv16 & 0xff,
701 (tkip->rx_iv32 >> 24) & 0xff,
702 (tkip->rx_iv32 >> 16) & 0xff,
703 (tkip->rx_iv32 >> 8) & 0xff,
704 tkip->rx_iv32 & 0xff,
705 (tkip->rx_iv16 >> 8) & 0xff,
706 tkip->rx_iv16 & 0xff,
707 tkip->dot11RSNAStatsTKIPReplays,
708 tkip->dot11RSNAStatsTKIPICVErrors,
709 tkip->dot11RSNAStatsTKIPLocalMICFailures);
Jeff Garzikb4538722005-05-12 22:48:20 -0400710}
711
John W. Linville274bfb82008-10-29 11:35:05 -0400712static struct lib80211_crypto_ops lib80211_crypt_tkip = {
James Ketrenos74079fd2005-09-13 17:35:21 -0500713 .name = "TKIP",
John W. Linville274bfb82008-10-29 11:35:05 -0400714 .init = lib80211_tkip_init,
715 .deinit = lib80211_tkip_deinit,
John W. Linville274bfb82008-10-29 11:35:05 -0400716 .encrypt_mpdu = lib80211_tkip_encrypt,
717 .decrypt_mpdu = lib80211_tkip_decrypt,
718 .encrypt_msdu = lib80211_michael_mic_add,
719 .decrypt_msdu = lib80211_michael_mic_verify,
720 .set_key = lib80211_tkip_set_key,
721 .get_key = lib80211_tkip_get_key,
722 .print_stats = lib80211_tkip_print_stats,
James Ketrenos1264fc02005-09-21 11:54:53 -0500723 .extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */
724 .extra_mpdu_postfix_len = 4, /* ICV */
725 .extra_msdu_postfix_len = 8, /* MIC */
John W. Linville274bfb82008-10-29 11:35:05 -0400726 .get_flags = lib80211_tkip_get_flags,
727 .set_flags = lib80211_tkip_set_flags,
James Ketrenos74079fd2005-09-13 17:35:21 -0500728 .owner = THIS_MODULE,
Jeff Garzikb4538722005-05-12 22:48:20 -0400729};
730
John W. Linville274bfb82008-10-29 11:35:05 -0400731static int __init lib80211_crypto_tkip_init(void)
Jeff Garzikb4538722005-05-12 22:48:20 -0400732{
John W. Linville274bfb82008-10-29 11:35:05 -0400733 return lib80211_register_crypto_ops(&lib80211_crypt_tkip);
Jeff Garzikb4538722005-05-12 22:48:20 -0400734}
735
John W. Linville274bfb82008-10-29 11:35:05 -0400736static void __exit lib80211_crypto_tkip_exit(void)
Jeff Garzikb4538722005-05-12 22:48:20 -0400737{
John W. Linville274bfb82008-10-29 11:35:05 -0400738 lib80211_unregister_crypto_ops(&lib80211_crypt_tkip);
Jeff Garzikb4538722005-05-12 22:48:20 -0400739}
740
John W. Linville274bfb82008-10-29 11:35:05 -0400741module_init(lib80211_crypto_tkip_init);
742module_exit(lib80211_crypto_tkip_exit);