ieee80211_crypto_tkip.c revision 147045
1138568Ssam/*-
2139530Ssam * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
3138568Ssam * All rights reserved.
4138568Ssam *
5138568Ssam * Redistribution and use in source and binary forms, with or without
6138568Ssam * modification, are permitted provided that the following conditions
7138568Ssam * are met:
8138568Ssam * 1. Redistributions of source code must retain the above copyright
9138568Ssam *    notice, this list of conditions and the following disclaimer.
10138568Ssam * 2. Redistributions in binary form must reproduce the above copyright
11138568Ssam *    notice, this list of conditions and the following disclaimer in the
12138568Ssam *    documentation and/or other materials provided with the distribution.
13138568Ssam * 3. The name of the author may not be used to endorse or promote products
14138568Ssam *    derived from this software without specific prior written permission.
15138568Ssam *
16138568Ssam * Alternatively, this software may be distributed under the terms of the
17138568Ssam * GNU General Public License ("GPL") version 2 as published by the Free
18138568Ssam * Software Foundation.
19138568Ssam *
20138568Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21138568Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22138568Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23138568Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24138568Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25138568Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26138568Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27138568Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28138568Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29138568Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30138568Ssam */
31138568Ssam
32138568Ssam#include <sys/cdefs.h>
33138568Ssam__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_crypto_tkip.c 147045 2005-06-06 04:04:38Z sam $");
34138568Ssam
35138568Ssam/*
36138568Ssam * IEEE 802.11i TKIP crypto support.
37138568Ssam *
38138568Ssam * Part of this module is derived from similar code in the Host
39138568Ssam * AP driver. The code is used with the consent of the author and
40138568Ssam * it's license is included below.
41138568Ssam */
42138568Ssam#include <sys/param.h>
43138568Ssam#include <sys/systm.h>
44138568Ssam#include <sys/mbuf.h>
45138568Ssam#include <sys/malloc.h>
46138568Ssam#include <sys/kernel.h>
47138568Ssam#include <sys/module.h>
48138568Ssam#include <sys/endian.h>
49138568Ssam
50138568Ssam#include <sys/socket.h>
51138568Ssam
52138568Ssam#include <net/if.h>
53138568Ssam#include <net/if_media.h>
54138568Ssam#include <net/ethernet.h>
55138568Ssam
56138568Ssam#include <net80211/ieee80211_var.h>
57138568Ssam
58138568Ssamstatic	void *tkip_attach(struct ieee80211com *, struct ieee80211_key *);
59138568Ssamstatic	void tkip_detach(struct ieee80211_key *);
60138568Ssamstatic	int tkip_setkey(struct ieee80211_key *);
61138568Ssamstatic	int tkip_encap(struct ieee80211_key *, struct mbuf *m, u_int8_t keyid);
62147045Ssamstatic	int tkip_enmic(struct ieee80211_key *, struct mbuf *, int);
63138568Ssamstatic	int tkip_decap(struct ieee80211_key *, struct mbuf *);
64147045Ssamstatic	int tkip_demic(struct ieee80211_key *, struct mbuf *, int);
65138568Ssam
66138568Ssamstatic const struct ieee80211_cipher tkip  = {
67138568Ssam	.ic_name	= "TKIP",
68138568Ssam	.ic_cipher	= IEEE80211_CIPHER_TKIP,
69138568Ssam	.ic_header	= IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
70138568Ssam			  IEEE80211_WEP_EXTIVLEN,
71138568Ssam	.ic_trailer	= IEEE80211_WEP_CRCLEN,
72138568Ssam	.ic_miclen	= IEEE80211_WEP_MICLEN,
73138568Ssam	.ic_attach	= tkip_attach,
74138568Ssam	.ic_detach	= tkip_detach,
75138568Ssam	.ic_setkey	= tkip_setkey,
76138568Ssam	.ic_encap	= tkip_encap,
77138568Ssam	.ic_decap	= tkip_decap,
78138568Ssam	.ic_enmic	= tkip_enmic,
79138568Ssam	.ic_demic	= tkip_demic,
80138568Ssam};
81138568Ssam
82138568Ssamtypedef	uint8_t u8;
83138568Ssamtypedef	uint16_t u16;
84138568Ssamtypedef	uint32_t __u32;
85138568Ssamtypedef	uint32_t u32;
86138568Ssam#define	memmove(dst, src, n)	ovbcopy(src, dst, n)
87138568Ssam
88138568Ssamstruct tkip_ctx {
89138568Ssam	struct ieee80211com *tc_ic;	/* for diagnostics */
90138568Ssam
91138568Ssam	u16	tx_ttak[5];
92138568Ssam	int	tx_phase1_done;
93138568Ssam	u8	tx_rc4key[16];		/* XXX for test module; make locals? */
94138568Ssam
95138568Ssam	u16	rx_ttak[5];
96138568Ssam	int	rx_phase1_done;
97138568Ssam	u8	rx_rc4key[16];		/* XXX for test module; make locals? */
98138568Ssam	uint64_t rx_rsc;		/* held until MIC verified */
99138568Ssam};
100138568Ssam
101138568Ssamstatic	void michael_mic(struct tkip_ctx *, const u8 *key,
102138568Ssam		struct mbuf *m, u_int off, size_t data_len,
103138568Ssam		u8 mic[IEEE80211_WEP_MICLEN]);
104138568Ssamstatic	int tkip_encrypt(struct tkip_ctx *, struct ieee80211_key *,
105138568Ssam		struct mbuf *, int hdr_len);
106138568Ssamstatic	int tkip_decrypt(struct tkip_ctx *, struct ieee80211_key *,
107138568Ssam		struct mbuf *, int hdr_len);
108138568Ssam
109138568Ssamstatic void *
110138568Ssamtkip_attach(struct ieee80211com *ic, struct ieee80211_key *k)
111138568Ssam{
112138568Ssam	struct tkip_ctx *ctx;
113138568Ssam
114138568Ssam	MALLOC(ctx, struct tkip_ctx *, sizeof(struct tkip_ctx),
115138568Ssam		M_DEVBUF, M_NOWAIT | M_ZERO);
116138568Ssam	if (ctx == NULL) {
117138568Ssam		ic->ic_stats.is_crypto_nomem++;
118138568Ssam		return NULL;
119138568Ssam	}
120138568Ssam
121138568Ssam	ctx->tc_ic = ic;
122138568Ssam	return ctx;
123138568Ssam}
124138568Ssam
125138568Ssamstatic void
126138568Ssamtkip_detach(struct ieee80211_key *k)
127138568Ssam{
128138568Ssam	struct tkip_ctx *ctx = k->wk_private;
129138568Ssam
130138568Ssam	FREE(ctx, M_DEVBUF);
131138568Ssam}
132138568Ssam
133138568Ssamstatic int
134138568Ssamtkip_setkey(struct ieee80211_key *k)
135138568Ssam{
136138568Ssam	struct tkip_ctx *ctx = k->wk_private;
137138568Ssam
138138568Ssam	if (k->wk_keylen != (128/NBBY)) {
139138568Ssam		(void) ctx;		/* XXX */
140138568Ssam		IEEE80211_DPRINTF(ctx->tc_ic, IEEE80211_MSG_CRYPTO,
141138568Ssam			"%s: Invalid key length %u, expecting %u\n",
142138568Ssam			__func__, k->wk_keylen, 128/NBBY);
143138568Ssam		return 0;
144138568Ssam	}
145138568Ssam	k->wk_keytsc = 1;		/* TSC starts at 1 */
146138568Ssam	return 1;
147138568Ssam}
148138568Ssam
149138568Ssam/*
150138568Ssam * Add privacy headers and do any s/w encryption required.
151138568Ssam */
152138568Ssamstatic int
153138568Ssamtkip_encap(struct ieee80211_key *k, struct mbuf *m, u_int8_t keyid)
154138568Ssam{
155138568Ssam	struct tkip_ctx *ctx = k->wk_private;
156138568Ssam	struct ieee80211com *ic = ctx->tc_ic;
157138568Ssam	u_int8_t *ivp;
158138568Ssam	int hdrlen;
159138568Ssam
160138568Ssam	/*
161138568Ssam	 * Handle TKIP counter measures requirement.
162138568Ssam	 */
163138568Ssam	if (ic->ic_flags & IEEE80211_F_COUNTERM) {
164138568Ssam#ifdef IEEE80211_DEBUG
165138568Ssam		struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
166138568Ssam#endif
167138568Ssam
168138568Ssam		IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
169138568Ssam			"[%s] Discard frame due to countermeasures (%s)\n",
170138568Ssam			ether_sprintf(wh->i_addr2), __func__);
171138568Ssam		ic->ic_stats.is_crypto_tkipcm++;
172138568Ssam		return 0;
173138568Ssam	}
174139508Ssam	hdrlen = ieee80211_hdrspace(ic, mtod(m, void *));
175138568Ssam
176138568Ssam	/*
177138568Ssam	 * Copy down 802.11 header and add the IV, KeyID, and ExtIV.
178138568Ssam	 */
179138568Ssam	M_PREPEND(m, tkip.ic_header, M_NOWAIT);
180138568Ssam	if (m == NULL)
181138568Ssam		return 0;
182138568Ssam	ivp = mtod(m, u_int8_t *);
183138568Ssam	memmove(ivp, ivp + tkip.ic_header, hdrlen);
184138568Ssam	ivp += hdrlen;
185138568Ssam
186138568Ssam	ivp[0] = k->wk_keytsc >> 8;		/* TSC1 */
187138568Ssam	ivp[1] = (ivp[0] | 0x20) & 0x7f;	/* WEP seed */
188138568Ssam	ivp[2] = k->wk_keytsc >> 0;		/* TSC0 */
189138568Ssam	ivp[3] = keyid | IEEE80211_WEP_EXTIV;	/* KeyID | ExtID */
190138568Ssam	ivp[4] = k->wk_keytsc >> 16;		/* TSC2 */
191138568Ssam	ivp[5] = k->wk_keytsc >> 24;		/* TSC3 */
192138568Ssam	ivp[6] = k->wk_keytsc >> 32;		/* TSC4 */
193138568Ssam	ivp[7] = k->wk_keytsc >> 40;		/* TSC5 */
194138568Ssam
195138568Ssam	/*
196138568Ssam	 * Finally, do software encrypt if neeed.
197138568Ssam	 */
198138568Ssam	if (k->wk_flags & IEEE80211_KEY_SWCRYPT) {
199138568Ssam		if (!tkip_encrypt(ctx, k, m, hdrlen))
200138568Ssam			return 0;
201138568Ssam		/* NB: tkip_encrypt handles wk_keytsc */
202138568Ssam	} else
203139510Ssam		k->wk_keytsc++;
204138568Ssam
205138568Ssam	return 1;
206138568Ssam}
207138568Ssam
208138568Ssam/*
209138568Ssam * Add MIC to the frame as needed.
210138568Ssam */
211138568Ssamstatic int
212147045Ssamtkip_enmic(struct ieee80211_key *k, struct mbuf *m, int force)
213138568Ssam{
214138568Ssam	struct tkip_ctx *ctx = k->wk_private;
215138568Ssam
216147045Ssam	if (force || (k->wk_flags & IEEE80211_KEY_SWMIC)) {
217138568Ssam		struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
218139508Ssam		struct ieee80211com *ic = ctx->tc_ic;
219139508Ssam		int hdrlen;
220138568Ssam		uint8_t mic[IEEE80211_WEP_MICLEN];
221138568Ssam
222139508Ssam		ic->ic_stats.is_crypto_tkipenmic++;
223138568Ssam
224139508Ssam		hdrlen = ieee80211_hdrspace(ic, wh);
225139508Ssam
226138568Ssam		michael_mic(ctx, k->wk_txmic,
227138568Ssam			m, hdrlen, m->m_pkthdr.len - hdrlen, mic);
228138568Ssam		return m_append(m, tkip.ic_miclen, mic);
229138568Ssam	}
230138568Ssam	return 1;
231138568Ssam}
232138568Ssam
233138568Ssamstatic __inline uint64_t
234138568SsamREAD_6(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5)
235138568Ssam{
236138568Ssam	uint32_t iv32 = (b0 << 0) | (b1 << 8) | (b2 << 16) | (b3 << 24);
237138568Ssam	uint16_t iv16 = (b4 << 0) | (b5 << 8);
238138568Ssam	return (((uint64_t)iv16) << 32) | iv32;
239138568Ssam}
240138568Ssam
241138568Ssam/*
242138568Ssam * Validate and strip privacy headers (and trailer) for a
243138568Ssam * received frame.  If necessary, decrypt the frame using
244138568Ssam * the specified key.
245138568Ssam */
246138568Ssamstatic int
247138568Ssamtkip_decap(struct ieee80211_key *k, struct mbuf *m)
248138568Ssam{
249138568Ssam	struct tkip_ctx *ctx = k->wk_private;
250138568Ssam	struct ieee80211com *ic = ctx->tc_ic;
251138568Ssam	struct ieee80211_frame *wh;
252138568Ssam	uint8_t *ivp;
253138568Ssam	int hdrlen;
254138568Ssam
255138568Ssam	/*
256138568Ssam	 * Header should have extended IV and sequence number;
257138568Ssam	 * verify the former and validate the latter.
258138568Ssam	 */
259138568Ssam	wh = mtod(m, struct ieee80211_frame *);
260138568Ssam	hdrlen = ieee80211_hdrsize(wh);
261138568Ssam	ivp = mtod(m, uint8_t *) + hdrlen;
262138568Ssam	if ((ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV) == 0) {
263138568Ssam		/*
264138568Ssam		 * No extended IV; discard frame.
265138568Ssam		 */
266138568Ssam		IEEE80211_DPRINTF(ctx->tc_ic, IEEE80211_MSG_CRYPTO,
267139510Ssam			"[%s] missing ExtIV for TKIP cipher\n",
268138568Ssam			ether_sprintf(wh->i_addr2));
269138568Ssam		ctx->tc_ic->ic_stats.is_rx_tkipformat++;
270138568Ssam		return 0;
271138568Ssam	}
272138568Ssam	/*
273138568Ssam	 * Handle TKIP counter measures requirement.
274138568Ssam	 */
275138568Ssam	if (ic->ic_flags & IEEE80211_F_COUNTERM) {
276138568Ssam		IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
277139510Ssam			"[%s] discard frame due to countermeasures (%s)\n",
278138568Ssam			ether_sprintf(wh->i_addr2), __func__);
279138568Ssam		ic->ic_stats.is_crypto_tkipcm++;
280138568Ssam		return 0;
281138568Ssam	}
282138568Ssam
283139510Ssam	ctx->rx_rsc = READ_6(ivp[2], ivp[0], ivp[4], ivp[5], ivp[6], ivp[7]);
284138568Ssam	if (ctx->rx_rsc <= k->wk_keyrsc) {
285138568Ssam		/*
286138568Ssam		 * Replay violation; notify upper layer.
287138568Ssam		 */
288138568Ssam		ieee80211_notify_replay_failure(ctx->tc_ic, wh, k, ctx->rx_rsc);
289138568Ssam		ctx->tc_ic->ic_stats.is_rx_tkipreplay++;
290138568Ssam		return 0;
291138568Ssam	}
292138568Ssam	/*
293138568Ssam	 * NB: We can't update the rsc in the key until MIC is verified.
294138568Ssam	 *
295138568Ssam	 * We assume we are not preempted between doing the check above
296138568Ssam	 * and updating wk_keyrsc when stripping the MIC in tkip_demic.
297138568Ssam	 * Otherwise we might process another packet and discard it as
298138568Ssam	 * a replay.
299138568Ssam	 */
300138568Ssam
301138568Ssam	/*
302138568Ssam	 * Check if the device handled the decrypt in hardware.
303138568Ssam	 * If so we just strip the header; otherwise we need to
304138568Ssam	 * handle the decrypt in software.
305138568Ssam	 */
306138568Ssam	if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) &&
307138568Ssam	    !tkip_decrypt(ctx, k, m, hdrlen))
308138568Ssam		return 0;
309138568Ssam
310138568Ssam	/*
311138568Ssam	 * Copy up 802.11 header and strip crypto bits.
312138568Ssam	 */
313138568Ssam	memmove(mtod(m, uint8_t *) + tkip.ic_header, mtod(m, void *), hdrlen);
314138568Ssam	m_adj(m, tkip.ic_header);
315138568Ssam	m_adj(m, -tkip.ic_trailer);
316138568Ssam
317138568Ssam	return 1;
318138568Ssam}
319138568Ssam
320138568Ssam/*
321138568Ssam * Verify and strip MIC from the frame.
322138568Ssam */
323138568Ssamstatic int
324147045Ssamtkip_demic(struct ieee80211_key *k, struct mbuf *m, int force)
325138568Ssam{
326138568Ssam	struct tkip_ctx *ctx = k->wk_private;
327138568Ssam
328147045Ssam	if (force || (k->wk_flags & IEEE80211_KEY_SWMIC)) {
329138568Ssam		struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
330138568Ssam		int hdrlen = ieee80211_hdrsize(wh);
331138568Ssam		u8 mic[IEEE80211_WEP_MICLEN];
332138568Ssam		u8 mic0[IEEE80211_WEP_MICLEN];
333138568Ssam
334138568Ssam		ctx->tc_ic->ic_stats.is_crypto_tkipdemic++;
335138568Ssam
336138568Ssam		michael_mic(ctx, k->wk_rxmic,
337138568Ssam			m, hdrlen, m->m_pkthdr.len - (hdrlen + tkip.ic_miclen),
338138568Ssam			mic);
339138568Ssam		m_copydata(m, m->m_pkthdr.len - tkip.ic_miclen,
340138568Ssam			tkip.ic_miclen, mic0);
341138568Ssam		if (memcmp(mic, mic0, tkip.ic_miclen)) {
342138568Ssam			/* NB: 802.11 layer handles statistic and debug msg */
343138568Ssam			ieee80211_notify_michael_failure(ctx->tc_ic, wh,
344138568Ssam				k->wk_keyix);
345138568Ssam			return 0;
346138568Ssam		}
347138568Ssam	}
348138568Ssam	/*
349138568Ssam	 * Strip MIC from the tail.
350138568Ssam	 */
351138568Ssam	m_adj(m, -tkip.ic_miclen);
352138568Ssam
353138568Ssam	/*
354138568Ssam	 * Ok to update rsc now that MIC has been verified.
355138568Ssam	 */
356138568Ssam	k->wk_keyrsc = ctx->rx_rsc;
357138568Ssam
358138568Ssam	return 1;
359138568Ssam}
360138568Ssam
361138568Ssam/*
362138568Ssam * Host AP crypt: host-based TKIP encryption implementation for Host AP driver
363138568Ssam *
364138568Ssam * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
365138568Ssam *
366138568Ssam * This program is free software; you can redistribute it and/or modify
367138568Ssam * it under the terms of the GNU General Public License version 2 as
368138568Ssam * published by the Free Software Foundation. See README and COPYING for
369138568Ssam * more details.
370138568Ssam *
371138568Ssam * Alternatively, this software may be distributed under the terms of BSD
372138568Ssam * license.
373138568Ssam */
374138568Ssam
375138568Ssamstatic const __u32 crc32_table[256] = {
376138568Ssam	0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
377138568Ssam	0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
378138568Ssam	0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
379138568Ssam	0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
380138568Ssam	0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
381138568Ssam	0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
382138568Ssam	0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
383138568Ssam	0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
384138568Ssam	0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
385138568Ssam	0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
386138568Ssam	0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
387138568Ssam	0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
388138568Ssam	0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
389138568Ssam	0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
390138568Ssam	0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
391138568Ssam	0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
392138568Ssam	0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
393138568Ssam	0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
394138568Ssam	0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
395138568Ssam	0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
396138568Ssam	0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
397138568Ssam	0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
398138568Ssam	0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
399138568Ssam	0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
400138568Ssam	0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
401138568Ssam	0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
402138568Ssam	0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
403138568Ssam	0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
404138568Ssam	0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
405138568Ssam	0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
406138568Ssam	0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
407138568Ssam	0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
408138568Ssam	0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
409138568Ssam	0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
410138568Ssam	0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
411138568Ssam	0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
412138568Ssam	0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
413138568Ssam	0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
414138568Ssam	0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
415138568Ssam	0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
416138568Ssam	0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
417138568Ssam	0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
418138568Ssam	0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
419138568Ssam	0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
420138568Ssam	0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
421138568Ssam	0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
422138568Ssam	0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
423138568Ssam	0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
424138568Ssam	0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
425138568Ssam	0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
426138568Ssam	0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
427138568Ssam	0x2d02ef8dL
428138568Ssam};
429138568Ssam
430138568Ssamstatic __inline u16 RotR1(u16 val)
431138568Ssam{
432138568Ssam	return (val >> 1) | (val << 15);
433138568Ssam}
434138568Ssam
435138568Ssamstatic __inline u8 Lo8(u16 val)
436138568Ssam{
437138568Ssam	return val & 0xff;
438138568Ssam}
439138568Ssam
440138568Ssamstatic __inline u8 Hi8(u16 val)
441138568Ssam{
442138568Ssam	return val >> 8;
443138568Ssam}
444138568Ssam
445138568Ssamstatic __inline u16 Lo16(u32 val)
446138568Ssam{
447138568Ssam	return val & 0xffff;
448138568Ssam}
449138568Ssam
450138568Ssamstatic __inline u16 Hi16(u32 val)
451138568Ssam{
452138568Ssam	return val >> 16;
453138568Ssam}
454138568Ssam
455138568Ssamstatic __inline u16 Mk16(u8 hi, u8 lo)
456138568Ssam{
457138568Ssam	return lo | (((u16) hi) << 8);
458138568Ssam}
459138568Ssam
460138568Ssamstatic __inline u16 Mk16_le(const u16 *v)
461138568Ssam{
462138568Ssam	return le16toh(*v);
463138568Ssam}
464138568Ssam
465138568Ssamstatic const u16 Sbox[256] = {
466138568Ssam	0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
467138568Ssam	0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
468138568Ssam	0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
469138568Ssam	0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
470138568Ssam	0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
471138568Ssam	0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
472138568Ssam	0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
473138568Ssam	0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
474138568Ssam	0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
475138568Ssam	0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
476138568Ssam	0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
477138568Ssam	0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
478138568Ssam	0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
479138568Ssam	0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
480138568Ssam	0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
481138568Ssam	0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
482138568Ssam	0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
483138568Ssam	0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
484138568Ssam	0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
485138568Ssam	0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
486138568Ssam	0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
487138568Ssam	0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
488138568Ssam	0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
489138568Ssam	0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
490138568Ssam	0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
491138568Ssam	0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
492138568Ssam	0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
493138568Ssam	0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
494138568Ssam	0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
495138568Ssam	0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
496138568Ssam	0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
497138568Ssam	0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
498138568Ssam};
499138568Ssam
500138568Ssamstatic __inline u16 _S_(u16 v)
501138568Ssam{
502138568Ssam	u16 t = Sbox[Hi8(v)];
503138568Ssam	return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8));
504138568Ssam}
505138568Ssam
506138568Ssam#define PHASE1_LOOP_COUNT 8
507138568Ssam
508138568Ssamstatic void tkip_mixing_phase1(u16 *TTAK, const u8 *TK, const u8 *TA, u32 IV32)
509138568Ssam{
510138568Ssam	int i, j;
511138568Ssam
512138568Ssam	/* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */
513138568Ssam	TTAK[0] = Lo16(IV32);
514138568Ssam	TTAK[1] = Hi16(IV32);
515138568Ssam	TTAK[2] = Mk16(TA[1], TA[0]);
516138568Ssam	TTAK[3] = Mk16(TA[3], TA[2]);
517138568Ssam	TTAK[4] = Mk16(TA[5], TA[4]);
518138568Ssam
519138568Ssam	for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
520138568Ssam		j = 2 * (i & 1);
521138568Ssam		TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j]));
522138568Ssam		TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j]));
523138568Ssam		TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j]));
524138568Ssam		TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j]));
525138568Ssam		TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i;
526138568Ssam	}
527138568Ssam}
528138568Ssam
529138568Ssam#ifndef _BYTE_ORDER
530138568Ssam#error "Don't know native byte order"
531138568Ssam#endif
532138568Ssam
533138568Ssamstatic void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK,
534138568Ssam			       u16 IV16)
535138568Ssam{
536138568Ssam	/* Make temporary area overlap WEP seed so that the final copy can be
537138568Ssam	 * avoided on little endian hosts. */
538138568Ssam	u16 *PPK = (u16 *) &WEPSeed[4];
539138568Ssam
540138568Ssam	/* Step 1 - make copy of TTAK and bring in TSC */
541138568Ssam	PPK[0] = TTAK[0];
542138568Ssam	PPK[1] = TTAK[1];
543138568Ssam	PPK[2] = TTAK[2];
544138568Ssam	PPK[3] = TTAK[3];
545138568Ssam	PPK[4] = TTAK[4];
546138568Ssam	PPK[5] = TTAK[4] + IV16;
547138568Ssam
548138568Ssam	/* Step 2 - 96-bit bijective mixing using S-box */
549138568Ssam	PPK[0] += _S_(PPK[5] ^ Mk16_le((const u16 *) &TK[0]));
550138568Ssam	PPK[1] += _S_(PPK[0] ^ Mk16_le((const u16 *) &TK[2]));
551138568Ssam	PPK[2] += _S_(PPK[1] ^ Mk16_le((const u16 *) &TK[4]));
552138568Ssam	PPK[3] += _S_(PPK[2] ^ Mk16_le((const u16 *) &TK[6]));
553138568Ssam	PPK[4] += _S_(PPK[3] ^ Mk16_le((const u16 *) &TK[8]));
554138568Ssam	PPK[5] += _S_(PPK[4] ^ Mk16_le((const u16 *) &TK[10]));
555138568Ssam
556138568Ssam	PPK[0] += RotR1(PPK[5] ^ Mk16_le((const u16 *) &TK[12]));
557138568Ssam	PPK[1] += RotR1(PPK[0] ^ Mk16_le((const u16 *) &TK[14]));
558138568Ssam	PPK[2] += RotR1(PPK[1]);
559138568Ssam	PPK[3] += RotR1(PPK[2]);
560138568Ssam	PPK[4] += RotR1(PPK[3]);
561138568Ssam	PPK[5] += RotR1(PPK[4]);
562138568Ssam
563138568Ssam	/* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value
564138568Ssam	 * WEPSeed[0..2] is transmitted as WEP IV */
565138568Ssam	WEPSeed[0] = Hi8(IV16);
566138568Ssam	WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F;
567138568Ssam	WEPSeed[2] = Lo8(IV16);
568138568Ssam	WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((const u16 *) &TK[0])) >> 1);
569138568Ssam
570138568Ssam#if _BYTE_ORDER == _BIG_ENDIAN
571138568Ssam	{
572138568Ssam		int i;
573138568Ssam		for (i = 0; i < 6; i++)
574138568Ssam			PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8);
575138568Ssam	}
576138568Ssam#endif
577138568Ssam}
578138568Ssam
579138568Ssamstatic void
580138568Ssamwep_encrypt(u8 *key, struct mbuf *m0, u_int off, size_t data_len,
581138568Ssam	uint8_t icv[IEEE80211_WEP_CRCLEN])
582138568Ssam{
583138568Ssam	u32 i, j, k, crc;
584138568Ssam	size_t buflen;
585138568Ssam	u8 S[256];
586138568Ssam	u8 *pos;
587138568Ssam	struct mbuf *m;
588138568Ssam#define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
589138568Ssam
590138568Ssam	/* Setup RC4 state */
591138568Ssam	for (i = 0; i < 256; i++)
592138568Ssam		S[i] = i;
593138568Ssam	j = 0;
594138568Ssam	for (i = 0; i < 256; i++) {
595138568Ssam		j = (j + S[i] + key[i & 0x0f]) & 0xff;
596138568Ssam		S_SWAP(i, j);
597138568Ssam	}
598138568Ssam
599138568Ssam	/* Compute CRC32 over unencrypted data and apply RC4 to data */
600138568Ssam	crc = ~0;
601138568Ssam	i = j = 0;
602138568Ssam	m = m0;
603138568Ssam	pos = mtod(m, uint8_t *) + off;
604138568Ssam	buflen = m->m_len - off;
605138568Ssam	for (;;) {
606138568Ssam		if (buflen > data_len)
607138568Ssam			buflen = data_len;
608138568Ssam		data_len -= buflen;
609138568Ssam		for (k = 0; k < buflen; k++) {
610138568Ssam			crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8);
611138568Ssam			i = (i + 1) & 0xff;
612138568Ssam			j = (j + S[i]) & 0xff;
613138568Ssam			S_SWAP(i, j);
614138568Ssam			*pos++ ^= S[(S[i] + S[j]) & 0xff];
615138568Ssam		}
616138568Ssam		m = m->m_next;
617138568Ssam		if (m == NULL) {
618138568Ssam			KASSERT(data_len == 0,
619138609Ssam			    ("out of buffers with data_len %zu\n", data_len));
620138568Ssam			break;
621138568Ssam		}
622138568Ssam		pos = mtod(m, uint8_t *);
623138568Ssam		buflen = m->m_len;
624138568Ssam	}
625138568Ssam	crc = ~crc;
626138568Ssam
627138568Ssam	/* Append little-endian CRC32 and encrypt it to produce ICV */
628138568Ssam	icv[0] = crc;
629138568Ssam	icv[1] = crc >> 8;
630138568Ssam	icv[2] = crc >> 16;
631138568Ssam	icv[3] = crc >> 24;
632138568Ssam	for (k = 0; k < IEEE80211_WEP_CRCLEN; k++) {
633138568Ssam		i = (i + 1) & 0xff;
634138568Ssam		j = (j + S[i]) & 0xff;
635138568Ssam		S_SWAP(i, j);
636138568Ssam		icv[k] ^= S[(S[i] + S[j]) & 0xff];
637138568Ssam	}
638138568Ssam}
639138568Ssam
640138568Ssamstatic int
641138568Ssamwep_decrypt(u8 *key, struct mbuf *m, u_int off, size_t data_len)
642138568Ssam{
643138568Ssam	u32 i, j, k, crc;
644138568Ssam	u8 S[256];
645138568Ssam	u8 *pos, icv[4];
646138568Ssam	size_t buflen;
647138568Ssam
648138568Ssam	/* Setup RC4 state */
649138568Ssam	for (i = 0; i < 256; i++)
650138568Ssam		S[i] = i;
651138568Ssam	j = 0;
652138568Ssam	for (i = 0; i < 256; i++) {
653138568Ssam		j = (j + S[i] + key[i & 0x0f]) & 0xff;
654138568Ssam		S_SWAP(i, j);
655138568Ssam	}
656138568Ssam
657138568Ssam	/* Apply RC4 to data and compute CRC32 over decrypted data */
658138568Ssam	crc = ~0;
659138568Ssam	i = j = 0;
660138568Ssam	pos = mtod(m, uint8_t *) + off;
661138568Ssam	buflen = m->m_len - off;
662138568Ssam	for (;;) {
663138568Ssam		if (buflen > data_len)
664138568Ssam			buflen = data_len;
665138568Ssam		data_len -= buflen;
666138568Ssam		for (k = 0; k < buflen; k++) {
667138568Ssam			i = (i + 1) & 0xff;
668138568Ssam			j = (j + S[i]) & 0xff;
669138568Ssam			S_SWAP(i, j);
670138568Ssam			*pos ^= S[(S[i] + S[j]) & 0xff];
671138568Ssam			crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8);
672138568Ssam			pos++;
673138568Ssam		}
674138568Ssam		m = m->m_next;
675138568Ssam		if (m == NULL) {
676138568Ssam			KASSERT(data_len == 0,
677138609Ssam			    ("out of buffers with data_len %zu\n", data_len));
678138568Ssam			break;
679138568Ssam		}
680138568Ssam		pos = mtod(m, uint8_t *);
681138568Ssam		buflen = m->m_len;
682138568Ssam	}
683138568Ssam	crc = ~crc;
684138568Ssam
685138568Ssam	/* Encrypt little-endian CRC32 and verify that it matches with the
686138568Ssam	 * received ICV */
687138568Ssam	icv[0] = crc;
688138568Ssam	icv[1] = crc >> 8;
689138568Ssam	icv[2] = crc >> 16;
690138568Ssam	icv[3] = crc >> 24;
691138568Ssam	for (k = 0; k < 4; k++) {
692138568Ssam		i = (i + 1) & 0xff;
693138568Ssam		j = (j + S[i]) & 0xff;
694138568Ssam		S_SWAP(i, j);
695138568Ssam		if ((icv[k] ^ S[(S[i] + S[j]) & 0xff]) != *pos++) {
696138568Ssam			/* ICV mismatch - drop frame */
697138568Ssam			return -1;
698138568Ssam		}
699138568Ssam	}
700138568Ssam
701138568Ssam	return 0;
702138568Ssam}
703138568Ssam
704138568Ssam
705138568Ssamstatic __inline u32 rotl(u32 val, int bits)
706138568Ssam{
707138568Ssam	return (val << bits) | (val >> (32 - bits));
708138568Ssam}
709138568Ssam
710138568Ssam
711138568Ssamstatic __inline u32 rotr(u32 val, int bits)
712138568Ssam{
713138568Ssam	return (val >> bits) | (val << (32 - bits));
714138568Ssam}
715138568Ssam
716138568Ssam
717138568Ssamstatic __inline u32 xswap(u32 val)
718138568Ssam{
719138568Ssam	return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8);
720138568Ssam}
721138568Ssam
722138568Ssam
723138568Ssam#define michael_block(l, r)	\
724138568Ssamdo {				\
725138568Ssam	r ^= rotl(l, 17);	\
726138568Ssam	l += r;			\
727138568Ssam	r ^= xswap(l);		\
728138568Ssam	l += r;			\
729138568Ssam	r ^= rotl(l, 3);	\
730138568Ssam	l += r;			\
731138568Ssam	r ^= rotr(l, 2);	\
732138568Ssam	l += r;			\
733138568Ssam} while (0)
734138568Ssam
735138568Ssam
736138568Ssamstatic __inline u32 get_le32_split(u8 b0, u8 b1, u8 b2, u8 b3)
737138568Ssam{
738138568Ssam	return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
739138568Ssam}
740138568Ssam
741138568Ssamstatic __inline u32 get_le32(const u8 *p)
742138568Ssam{
743138568Ssam	return get_le32_split(p[0], p[1], p[2], p[3]);
744138568Ssam}
745138568Ssam
746138568Ssam
747138568Ssamstatic __inline void put_le32(u8 *p, u32 v)
748138568Ssam{
749138568Ssam	p[0] = v;
750138568Ssam	p[1] = v >> 8;
751138568Ssam	p[2] = v >> 16;
752138568Ssam	p[3] = v >> 24;
753138568Ssam}
754138568Ssam
755138568Ssam/*
756138568Ssam * Craft pseudo header used to calculate the MIC.
757138568Ssam */
758138568Ssamstatic void
759138568Ssammichael_mic_hdr(const struct ieee80211_frame *wh0, uint8_t hdr[16])
760138568Ssam{
761138568Ssam	const struct ieee80211_frame_addr4 *wh =
762138568Ssam		(const struct ieee80211_frame_addr4 *) wh0;
763138568Ssam
764138568Ssam	switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
765138568Ssam	case IEEE80211_FC1_DIR_NODS:
766138568Ssam		IEEE80211_ADDR_COPY(hdr, wh->i_addr1); /* DA */
767138568Ssam		IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr2);
768138568Ssam		break;
769138568Ssam	case IEEE80211_FC1_DIR_TODS:
770138568Ssam		IEEE80211_ADDR_COPY(hdr, wh->i_addr3); /* DA */
771138568Ssam		IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr2);
772138568Ssam		break;
773138568Ssam	case IEEE80211_FC1_DIR_FROMDS:
774138568Ssam		IEEE80211_ADDR_COPY(hdr, wh->i_addr1); /* DA */
775138568Ssam		IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr3);
776138568Ssam		break;
777138568Ssam	case IEEE80211_FC1_DIR_DSTODS:
778138568Ssam		IEEE80211_ADDR_COPY(hdr, wh->i_addr3); /* DA */
779138568Ssam		IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr4);
780138568Ssam		break;
781138568Ssam	}
782138568Ssam
783139511Ssam	if (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) {
784139511Ssam		const struct ieee80211_qosframe *qwh =
785139511Ssam			(const struct ieee80211_qosframe *) wh;
786139511Ssam		hdr[12] = qwh->i_qos[0] & IEEE80211_QOS_TID;
787139511Ssam	} else
788139511Ssam		hdr[12] = 0;
789138568Ssam	hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */
790138568Ssam}
791138568Ssam
792138568Ssamstatic void
793138568Ssammichael_mic(struct tkip_ctx *ctx, const u8 *key,
794138568Ssam	struct mbuf *m, u_int off, size_t data_len,
795138568Ssam	u8 mic[IEEE80211_WEP_MICLEN])
796138568Ssam{
797138568Ssam	uint8_t hdr[16];
798138568Ssam	u32 l, r;
799138568Ssam	const uint8_t *data;
800138568Ssam	u_int space;
801138568Ssam
802138568Ssam	michael_mic_hdr(mtod(m, struct ieee80211_frame *), hdr);
803138568Ssam
804138568Ssam	l = get_le32(key);
805138568Ssam	r = get_le32(key + 4);
806138568Ssam
807138568Ssam	/* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */
808138568Ssam	l ^= get_le32(hdr);
809138568Ssam	michael_block(l, r);
810138568Ssam	l ^= get_le32(&hdr[4]);
811138568Ssam	michael_block(l, r);
812138568Ssam	l ^= get_le32(&hdr[8]);
813138568Ssam	michael_block(l, r);
814138568Ssam	l ^= get_le32(&hdr[12]);
815138568Ssam	michael_block(l, r);
816138568Ssam
817138568Ssam	/* first buffer has special handling */
818138568Ssam	data = mtod(m, const uint8_t *) + off;
819138568Ssam	space = m->m_len - off;
820138568Ssam	for (;;) {
821138568Ssam		if (space > data_len)
822138568Ssam			space = data_len;
823138568Ssam		/* collect 32-bit blocks from current buffer */
824138568Ssam		while (space >= sizeof(uint32_t)) {
825138568Ssam			l ^= get_le32(data);
826138568Ssam			michael_block(l, r);
827138568Ssam			data += sizeof(uint32_t), space -= sizeof(uint32_t);
828138568Ssam			data_len -= sizeof(uint32_t);
829138568Ssam		}
830138568Ssam		if (data_len < sizeof(uint32_t))
831138568Ssam			break;
832138568Ssam		m = m->m_next;
833138568Ssam		if (m == NULL) {
834138609Ssam			KASSERT(0, ("out of data, data_len %zu\n", data_len));
835138568Ssam			break;
836138568Ssam		}
837138568Ssam		if (space != 0) {
838138568Ssam			const uint8_t *data_next;
839138568Ssam			/*
840138568Ssam			 * Block straddles buffers, split references.
841138568Ssam			 */
842138568Ssam			data_next = mtod(m, const uint8_t *);
843138568Ssam			KASSERT(m->m_len >= sizeof(uint32_t) - space,
844138568Ssam				("not enough data in following buffer, "
845138609Ssam				"m_len %u need %zu\n", m->m_len,
846138568Ssam				sizeof(uint32_t) - space));
847138568Ssam			switch (space) {
848138568Ssam			case 1:
849138568Ssam				l ^= get_le32_split(data[0], data_next[0],
850138568Ssam					data_next[1], data_next[2]);
851138568Ssam				data = data_next + 3;
852138568Ssam				space = m->m_len - 3;
853138568Ssam				break;
854138568Ssam			case 2:
855138568Ssam				l ^= get_le32_split(data[0], data[1],
856138568Ssam					data_next[0], data_next[1]);
857138568Ssam				data = data_next + 2;
858138568Ssam				space = m->m_len - 2;
859138568Ssam				break;
860138568Ssam			case 3:
861138568Ssam				l ^= get_le32_split(data[0], data[1],
862138568Ssam					data[2], data_next[0]);
863138568Ssam				data = data_next + 1;
864138568Ssam				space = m->m_len - 1;
865138568Ssam				break;
866138568Ssam			}
867138568Ssam			michael_block(l, r);
868138568Ssam			data_len -= sizeof(uint32_t);
869138568Ssam		} else {
870138568Ssam			/*
871138568Ssam			 * Setup for next buffer.
872138568Ssam			 */
873138568Ssam			data = mtod(m, const uint8_t *);
874138568Ssam			space = m->m_len;
875138568Ssam		}
876138568Ssam	}
877138568Ssam	/* Last block and padding (0x5a, 4..7 x 0) */
878138568Ssam	switch (data_len) {
879138568Ssam	case 0:
880138568Ssam		l ^= get_le32_split(0x5a, 0, 0, 0);
881138568Ssam		break;
882138568Ssam	case 1:
883138568Ssam		l ^= get_le32_split(data[0], 0x5a, 0, 0);
884138568Ssam		break;
885138568Ssam	case 2:
886138568Ssam		l ^= get_le32_split(data[0], data[1], 0x5a, 0);
887138568Ssam		break;
888138568Ssam	case 3:
889138568Ssam		l ^= get_le32_split(data[0], data[1], data[2], 0x5a);
890138568Ssam		break;
891138568Ssam	}
892138568Ssam	michael_block(l, r);
893138568Ssam	/* l ^= 0; */
894138568Ssam	michael_block(l, r);
895138568Ssam
896138568Ssam	put_le32(mic, l);
897138568Ssam	put_le32(mic + 4, r);
898138568Ssam}
899138568Ssam
900138568Ssamstatic int
901138568Ssamtkip_encrypt(struct tkip_ctx *ctx, struct ieee80211_key *key,
902138568Ssam	struct mbuf *m, int hdrlen)
903138568Ssam{
904138568Ssam	struct ieee80211_frame *wh;
905138568Ssam	uint8_t icv[IEEE80211_WEP_CRCLEN];
906138568Ssam
907138568Ssam	ctx->tc_ic->ic_stats.is_crypto_tkip++;
908138568Ssam
909138568Ssam	wh = mtod(m, struct ieee80211_frame *);
910138568Ssam	if (!ctx->tx_phase1_done) {
911138568Ssam		tkip_mixing_phase1(ctx->tx_ttak, key->wk_key, wh->i_addr2,
912138568Ssam				   (u32)(key->wk_keytsc >> 16));
913138568Ssam		ctx->tx_phase1_done = 1;
914138568Ssam	}
915138568Ssam	tkip_mixing_phase2(ctx->tx_rc4key, key->wk_key, ctx->tx_ttak,
916138568Ssam		(u16) key->wk_keytsc);
917138568Ssam
918138568Ssam	wep_encrypt(ctx->tx_rc4key,
919138568Ssam		m, hdrlen + tkip.ic_header,
920138568Ssam		m->m_pkthdr.len - (hdrlen + tkip.ic_header),
921138568Ssam		icv);
922138568Ssam	(void) m_append(m, IEEE80211_WEP_CRCLEN, icv);	/* XXX check return */
923138568Ssam
924139510Ssam	key->wk_keytsc++;
925138568Ssam	if ((u16)(key->wk_keytsc) == 0)
926138568Ssam		ctx->tx_phase1_done = 0;
927138568Ssam	return 1;
928138568Ssam}
929138568Ssam
930138568Ssamstatic int
931138568Ssamtkip_decrypt(struct tkip_ctx *ctx, struct ieee80211_key *key,
932138568Ssam	struct mbuf *m, int hdrlen)
933138568Ssam{
934138568Ssam	struct ieee80211_frame *wh;
935138568Ssam	u32 iv32;
936138568Ssam	u16 iv16;
937138568Ssam
938138568Ssam	ctx->tc_ic->ic_stats.is_crypto_tkip++;
939138568Ssam
940138568Ssam	wh = mtod(m, struct ieee80211_frame *);
941138568Ssam	/* NB: tkip_decap already verified header and left seq in rx_rsc */
942138568Ssam	iv16 = (u16) ctx->rx_rsc;
943138568Ssam	iv32 = (u32) (ctx->rx_rsc >> 16);
944138568Ssam
945138568Ssam	if (iv32 != (u32)(key->wk_keyrsc >> 16) || !ctx->rx_phase1_done) {
946138568Ssam		tkip_mixing_phase1(ctx->rx_ttak, key->wk_key,
947138568Ssam			wh->i_addr2, iv32);
948138568Ssam		ctx->rx_phase1_done = 1;
949138568Ssam	}
950138568Ssam	tkip_mixing_phase2(ctx->rx_rc4key, key->wk_key, ctx->rx_ttak, iv16);
951138568Ssam
952138568Ssam	/* NB: m is unstripped; deduct headers + ICV to get payload */
953138568Ssam	if (wep_decrypt(ctx->rx_rc4key,
954138568Ssam		m, hdrlen + tkip.ic_header,
955138568Ssam	        m->m_pkthdr.len - (hdrlen + tkip.ic_header + tkip.ic_trailer))) {
956138568Ssam		if (iv32 != (u32)(key->wk_keyrsc >> 16)) {
957138568Ssam			/* Previously cached Phase1 result was already lost, so
958138568Ssam			 * it needs to be recalculated for the next packet. */
959138568Ssam			ctx->rx_phase1_done = 0;
960138568Ssam		}
961138568Ssam		IEEE80211_DPRINTF(ctx->tc_ic, IEEE80211_MSG_CRYPTO,
962138568Ssam		    "[%s] TKIP ICV mismatch on decrypt\n",
963138568Ssam		    ether_sprintf(wh->i_addr2));
964138568Ssam		ctx->tc_ic->ic_stats.is_rx_tkipicv++;
965138568Ssam		return 0;
966138568Ssam	}
967138568Ssam	return 1;
968138568Ssam}
969138568Ssam
970138568Ssam/*
971138568Ssam * Module glue.
972138568Ssam */
973138568Ssamstatic int
974138568Ssamtkip_modevent(module_t mod, int type, void *unused)
975138568Ssam{
976138568Ssam	switch (type) {
977138568Ssam	case MOD_LOAD:
978138568Ssam		ieee80211_crypto_register(&tkip);
979138568Ssam		return 0;
980138568Ssam	case MOD_UNLOAD:
981138568Ssam		ieee80211_crypto_unregister(&tkip);
982138568Ssam		return 0;
983138568Ssam	}
984138568Ssam	return EINVAL;
985138568Ssam}
986138568Ssam
987138568Ssamstatic moduledata_t tkip_mod = {
988138568Ssam	"wlan_tkip",
989138568Ssam	tkip_modevent,
990138568Ssam	0
991138568Ssam};
992138568SsamDECLARE_MODULE(wlan_tkip, tkip_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
993138568SsamMODULE_VERSION(wlan_tkip, 1);
994138816SsamMODULE_DEPEND(wlan_tkip, wlan, 1, 1, 1);
995