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