xref: /dflybsd-src/sys/netproto/802_11/wlan_tkip/ieee80211_crypto_tkip.c (revision bff82488b6f45c2f067e4c552e649b1d3e07cd7c)
132176cfdSRui Paulo /*-
232176cfdSRui Paulo  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3841ab66cSSepherosa Ziehau  * All rights reserved.
4841ab66cSSepherosa Ziehau  *
5841ab66cSSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
6841ab66cSSepherosa Ziehau  * modification, are permitted provided that the following conditions
7841ab66cSSepherosa Ziehau  * are met:
8841ab66cSSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
9841ab66cSSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer.
10841ab66cSSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
11841ab66cSSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
12841ab66cSSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
13841ab66cSSepherosa Ziehau  *
14841ab66cSSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15841ab66cSSepherosa Ziehau  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16841ab66cSSepherosa Ziehau  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17841ab66cSSepherosa Ziehau  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18841ab66cSSepherosa Ziehau  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19841ab66cSSepherosa Ziehau  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20841ab66cSSepherosa Ziehau  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21841ab66cSSepherosa Ziehau  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22841ab66cSSepherosa Ziehau  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23841ab66cSSepherosa Ziehau  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24841ab66cSSepherosa Ziehau  */
25841ab66cSSepherosa Ziehau 
26085ff963SMatthew Dillon #include <sys/cdefs.h>
27085ff963SMatthew Dillon __FBSDID("$FreeBSD$");
28085ff963SMatthew Dillon 
29841ab66cSSepherosa Ziehau /*
30841ab66cSSepherosa Ziehau  * IEEE 802.11i TKIP crypto support.
31841ab66cSSepherosa Ziehau  *
32841ab66cSSepherosa Ziehau  * Part of this module is derived from similar code in the Host
33841ab66cSSepherosa Ziehau  * AP driver. The code is used with the consent of the author and
34841ab66cSSepherosa Ziehau  * it's license is included below.
35841ab66cSSepherosa Ziehau  */
3632176cfdSRui Paulo #include "opt_wlan.h"
3732176cfdSRui Paulo 
38841ab66cSSepherosa Ziehau #include <sys/param.h>
39841ab66cSSepherosa Ziehau #include <sys/systm.h>
40841ab66cSSepherosa Ziehau #include <sys/mbuf.h>
41841ab66cSSepherosa Ziehau #include <sys/malloc.h>
42841ab66cSSepherosa Ziehau #include <sys/kernel.h>
43841ab66cSSepherosa Ziehau #include <sys/module.h>
44841ab66cSSepherosa Ziehau #include <sys/endian.h>
45841ab66cSSepherosa Ziehau 
46841ab66cSSepherosa Ziehau #include <sys/socket.h>
47841ab66cSSepherosa Ziehau 
48841ab66cSSepherosa Ziehau #include <net/if.h>
49*bff82488SAaron LI #include <net/if_var.h>
50841ab66cSSepherosa Ziehau #include <net/if_media.h>
51841ab66cSSepherosa Ziehau #include <net/ethernet.h>
52841ab66cSSepherosa Ziehau 
53841ab66cSSepherosa Ziehau #include <netproto/802_11/ieee80211_var.h>
54841ab66cSSepherosa Ziehau 
5532176cfdSRui Paulo static	void *tkip_attach(struct ieee80211vap *, struct ieee80211_key *);
56841ab66cSSepherosa Ziehau static	void tkip_detach(struct ieee80211_key *);
57841ab66cSSepherosa Ziehau static	int tkip_setkey(struct ieee80211_key *);
584f655ef5SMatthew Dillon static	void tkip_setiv(struct ieee80211_key *, uint8_t *);
594f655ef5SMatthew Dillon static	int tkip_encap(struct ieee80211_key *, struct mbuf *);
60841ab66cSSepherosa Ziehau static	int tkip_enmic(struct ieee80211_key *, struct mbuf *, int);
61841ab66cSSepherosa Ziehau static	int tkip_decap(struct ieee80211_key *, struct mbuf *, int);
62841ab66cSSepherosa Ziehau static	int tkip_demic(struct ieee80211_key *, struct mbuf *, int);
63841ab66cSSepherosa Ziehau 
64841ab66cSSepherosa Ziehau static const struct ieee80211_cipher tkip  = {
65841ab66cSSepherosa Ziehau 	.ic_name	= "TKIP",
66841ab66cSSepherosa Ziehau 	.ic_cipher	= IEEE80211_CIPHER_TKIP,
67841ab66cSSepherosa Ziehau 	.ic_header	= IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
68841ab66cSSepherosa Ziehau 			  IEEE80211_WEP_EXTIVLEN,
69841ab66cSSepherosa Ziehau 	.ic_trailer	= IEEE80211_WEP_CRCLEN,
70841ab66cSSepherosa Ziehau 	.ic_miclen	= IEEE80211_WEP_MICLEN,
71841ab66cSSepherosa Ziehau 	.ic_attach	= tkip_attach,
72841ab66cSSepherosa Ziehau 	.ic_detach	= tkip_detach,
73841ab66cSSepherosa Ziehau 	.ic_setkey	= tkip_setkey,
744f655ef5SMatthew Dillon 	.ic_setiv	= tkip_setiv,
75841ab66cSSepherosa Ziehau 	.ic_encap	= tkip_encap,
76841ab66cSSepherosa Ziehau 	.ic_decap	= tkip_decap,
77841ab66cSSepherosa Ziehau 	.ic_enmic	= tkip_enmic,
78841ab66cSSepherosa Ziehau 	.ic_demic	= tkip_demic,
79841ab66cSSepherosa Ziehau };
80841ab66cSSepherosa Ziehau 
8132176cfdSRui Paulo typedef	uint8_t u8;
8232176cfdSRui Paulo typedef	uint16_t u16;
8332176cfdSRui Paulo typedef	uint32_t __u32;
8432176cfdSRui Paulo typedef	uint32_t u32;
85841ab66cSSepherosa Ziehau 
86841ab66cSSepherosa Ziehau struct tkip_ctx {
8732176cfdSRui Paulo 	struct ieee80211vap *tc_vap;	/* for diagnostics+statistics */
88841ab66cSSepherosa Ziehau 
8932176cfdSRui Paulo 	u16	tx_ttak[5];
9032176cfdSRui Paulo 	u8	tx_rc4key[16];		/* XXX for test module; make locals? */
91841ab66cSSepherosa Ziehau 
9232176cfdSRui Paulo 	u16	rx_ttak[5];
93841ab66cSSepherosa Ziehau 	int	rx_phase1_done;
9432176cfdSRui Paulo 	u8	rx_rc4key[16];		/* XXX for test module; make locals? */
95841ab66cSSepherosa Ziehau 	uint64_t rx_rsc;		/* held until MIC verified */
96841ab66cSSepherosa Ziehau };
97841ab66cSSepherosa Ziehau 
9832176cfdSRui Paulo static	void michael_mic(struct tkip_ctx *, const u8 *key,
99841ab66cSSepherosa Ziehau 		struct mbuf *m, u_int off, size_t data_len,
10032176cfdSRui Paulo 		u8 mic[IEEE80211_WEP_MICLEN]);
101841ab66cSSepherosa Ziehau static	int tkip_encrypt(struct tkip_ctx *, struct ieee80211_key *,
102841ab66cSSepherosa Ziehau 		struct mbuf *, int hdr_len);
103841ab66cSSepherosa Ziehau static	int tkip_decrypt(struct tkip_ctx *, struct ieee80211_key *,
104841ab66cSSepherosa Ziehau 		struct mbuf *, int hdr_len);
105841ab66cSSepherosa Ziehau 
106841ab66cSSepherosa Ziehau /* number of references from net80211 layer */
107841ab66cSSepherosa Ziehau static	int nrefs = 0;
108841ab66cSSepherosa Ziehau 
109841ab66cSSepherosa Ziehau static void *
tkip_attach(struct ieee80211vap * vap,struct ieee80211_key * k)11032176cfdSRui Paulo tkip_attach(struct ieee80211vap *vap, struct ieee80211_key *k)
111841ab66cSSepherosa Ziehau {
112841ab66cSSepherosa Ziehau 	struct tkip_ctx *ctx;
113841ab66cSSepherosa Ziehau 
1144f655ef5SMatthew Dillon #if defined(__DragonFly__)
11532176cfdSRui Paulo 	ctx = (struct tkip_ctx *) kmalloc(sizeof(struct tkip_ctx),
116c567b546SJoe Talbott 		M_80211_CRYPTO, M_INTWAIT | M_ZERO);
1174f655ef5SMatthew Dillon #else
1184f655ef5SMatthew Dillon 	ctx = (struct tkip_ctx *) IEEE80211_MALLOC(sizeof(struct tkip_ctx),
1194f655ef5SMatthew Dillon 		M_80211_CRYPTO, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
1204f655ef5SMatthew Dillon #endif
121841ab66cSSepherosa Ziehau 	if (ctx == NULL) {
12232176cfdSRui Paulo 		vap->iv_stats.is_crypto_nomem++;
123841ab66cSSepherosa Ziehau 		return NULL;
124841ab66cSSepherosa Ziehau 	}
125841ab66cSSepherosa Ziehau 
12632176cfdSRui Paulo 	ctx->tc_vap = vap;
127841ab66cSSepherosa Ziehau 	nrefs++;			/* NB: we assume caller locking */
128841ab66cSSepherosa Ziehau 	return ctx;
129841ab66cSSepherosa Ziehau }
130841ab66cSSepherosa Ziehau 
131841ab66cSSepherosa Ziehau static void
tkip_detach(struct ieee80211_key * k)132841ab66cSSepherosa Ziehau tkip_detach(struct ieee80211_key *k)
133841ab66cSSepherosa Ziehau {
134841ab66cSSepherosa Ziehau 	struct tkip_ctx *ctx = k->wk_private;
135841ab66cSSepherosa Ziehau 
1364f655ef5SMatthew Dillon 	IEEE80211_FREE(ctx, M_80211_CRYPTO);
137841ab66cSSepherosa Ziehau 	KASSERT(nrefs > 0, ("imbalanced attach/detach"));
138841ab66cSSepherosa Ziehau 	nrefs--;			/* NB: we assume caller locking */
139841ab66cSSepherosa Ziehau }
140841ab66cSSepherosa Ziehau 
141841ab66cSSepherosa Ziehau static int
tkip_setkey(struct ieee80211_key * k)142841ab66cSSepherosa Ziehau tkip_setkey(struct ieee80211_key *k)
143841ab66cSSepherosa Ziehau {
144841ab66cSSepherosa Ziehau 	struct tkip_ctx *ctx = k->wk_private;
145841ab66cSSepherosa Ziehau 
146841ab66cSSepherosa Ziehau 	if (k->wk_keylen != (128/NBBY)) {
147841ab66cSSepherosa Ziehau 		(void) ctx;		/* XXX */
14832176cfdSRui Paulo 		IEEE80211_DPRINTF(ctx->tc_vap, IEEE80211_MSG_CRYPTO,
149841ab66cSSepherosa Ziehau 			"%s: Invalid key length %u, expecting %u\n",
150841ab66cSSepherosa Ziehau 			__func__, k->wk_keylen, 128/NBBY);
151841ab66cSSepherosa Ziehau 		return 0;
152841ab66cSSepherosa Ziehau 	}
15332176cfdSRui Paulo 	ctx->rx_phase1_done = 0;
154841ab66cSSepherosa Ziehau 	return 1;
155841ab66cSSepherosa Ziehau }
156841ab66cSSepherosa Ziehau 
1574f655ef5SMatthew Dillon static void
tkip_setiv(struct ieee80211_key * k,uint8_t * ivp)1584f655ef5SMatthew Dillon tkip_setiv(struct ieee80211_key *k, uint8_t *ivp)
1594f655ef5SMatthew Dillon {
1604f655ef5SMatthew Dillon 	struct tkip_ctx *ctx = k->wk_private;
1614f655ef5SMatthew Dillon 	struct ieee80211vap *vap = ctx->tc_vap;
1624f655ef5SMatthew Dillon 	uint8_t keyid;
1634f655ef5SMatthew Dillon 
1644f655ef5SMatthew Dillon 	keyid = ieee80211_crypto_get_keyid(vap, k) << 6;
1654f655ef5SMatthew Dillon 
1664f655ef5SMatthew Dillon 	k->wk_keytsc++;
1674f655ef5SMatthew Dillon 	ivp[0] = k->wk_keytsc >> 8;		/* TSC1 */
1684f655ef5SMatthew Dillon 	ivp[1] = (ivp[0] | 0x20) & 0x7f;	/* WEP seed */
1694f655ef5SMatthew Dillon 	ivp[2] = k->wk_keytsc >> 0;		/* TSC0 */
1704f655ef5SMatthew Dillon 	ivp[3] = keyid | IEEE80211_WEP_EXTIV;	/* KeyID | ExtID */
1714f655ef5SMatthew Dillon 	ivp[4] = k->wk_keytsc >> 16;		/* TSC2 */
1724f655ef5SMatthew Dillon 	ivp[5] = k->wk_keytsc >> 24;		/* TSC3 */
1734f655ef5SMatthew Dillon 	ivp[6] = k->wk_keytsc >> 32;		/* TSC4 */
1744f655ef5SMatthew Dillon 	ivp[7] = k->wk_keytsc >> 40;		/* TSC5 */
1754f655ef5SMatthew Dillon }
1764f655ef5SMatthew Dillon 
177841ab66cSSepherosa Ziehau /*
178841ab66cSSepherosa Ziehau  * Add privacy headers and do any s/w encryption required.
179841ab66cSSepherosa Ziehau  */
180841ab66cSSepherosa Ziehau static int
tkip_encap(struct ieee80211_key * k,struct mbuf * m)1814f655ef5SMatthew Dillon tkip_encap(struct ieee80211_key *k, struct mbuf *m)
182841ab66cSSepherosa Ziehau {
183841ab66cSSepherosa Ziehau 	struct tkip_ctx *ctx = k->wk_private;
18432176cfdSRui Paulo 	struct ieee80211vap *vap = ctx->tc_vap;
18532176cfdSRui Paulo 	struct ieee80211com *ic = vap->iv_ic;
186841ab66cSSepherosa Ziehau 	uint8_t *ivp;
187841ab66cSSepherosa Ziehau 	int hdrlen;
188841ab66cSSepherosa Ziehau 
189841ab66cSSepherosa Ziehau 	/*
190841ab66cSSepherosa Ziehau 	 * Handle TKIP counter measures requirement.
191841ab66cSSepherosa Ziehau 	 */
19232176cfdSRui Paulo 	if (vap->iv_flags & IEEE80211_F_COUNTERM) {
193841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG
194841ab66cSSepherosa Ziehau 		struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
195841ab66cSSepherosa Ziehau #endif
196841ab66cSSepherosa Ziehau 
19732176cfdSRui Paulo 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
19832176cfdSRui Paulo 		    "discard frame due to countermeasures (%s)", __func__);
19932176cfdSRui Paulo 		vap->iv_stats.is_crypto_tkipcm++;
200841ab66cSSepherosa Ziehau 		return 0;
201841ab66cSSepherosa Ziehau 	}
202841ab66cSSepherosa Ziehau 	hdrlen = ieee80211_hdrspace(ic, mtod(m, void *));
203841ab66cSSepherosa Ziehau 
204841ab66cSSepherosa Ziehau 	/*
205841ab66cSSepherosa Ziehau 	 * Copy down 802.11 header and add the IV, KeyID, and ExtIV.
206841ab66cSSepherosa Ziehau 	 */
207b5523eacSSascha Wildner 	M_PREPEND(m, tkip.ic_header, M_NOWAIT);
208841ab66cSSepherosa Ziehau 	if (m == NULL)
209841ab66cSSepherosa Ziehau 		return 0;
210841ab66cSSepherosa Ziehau 	ivp = mtod(m, uint8_t *);
211841ab66cSSepherosa Ziehau 	memmove(ivp, ivp + tkip.ic_header, hdrlen);
212841ab66cSSepherosa Ziehau 	ivp += hdrlen;
213841ab66cSSepherosa Ziehau 
2144f655ef5SMatthew Dillon 	tkip_setiv(k, ivp);
215841ab66cSSepherosa Ziehau 
216841ab66cSSepherosa Ziehau 	/*
2174f655ef5SMatthew Dillon 	 * Finally, do software encrypt if needed.
218841ab66cSSepherosa Ziehau 	 */
2194f655ef5SMatthew Dillon 	if ((k->wk_flags & IEEE80211_KEY_SWENCRYPT) &&
2204f655ef5SMatthew Dillon 	    !tkip_encrypt(ctx, k, m, hdrlen))
221841ab66cSSepherosa Ziehau 		return 0;
222841ab66cSSepherosa Ziehau 
223841ab66cSSepherosa Ziehau 	return 1;
224841ab66cSSepherosa Ziehau }
225841ab66cSSepherosa Ziehau 
226841ab66cSSepherosa Ziehau /*
227841ab66cSSepherosa Ziehau  * Add MIC to the frame as needed.
228841ab66cSSepherosa Ziehau  */
229841ab66cSSepherosa Ziehau static int
tkip_enmic(struct ieee80211_key * k,struct mbuf * m,int force)230841ab66cSSepherosa Ziehau tkip_enmic(struct ieee80211_key *k, struct mbuf *m, int force)
231841ab66cSSepherosa Ziehau {
232841ab66cSSepherosa Ziehau 	struct tkip_ctx *ctx = k->wk_private;
233841ab66cSSepherosa Ziehau 
23432176cfdSRui Paulo 	if (force || (k->wk_flags & IEEE80211_KEY_SWENMIC)) {
235841ab66cSSepherosa Ziehau 		struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
23632176cfdSRui Paulo 		struct ieee80211vap *vap = ctx->tc_vap;
23732176cfdSRui Paulo 		struct ieee80211com *ic = vap->iv_ic;
238841ab66cSSepherosa Ziehau 		int hdrlen;
239841ab66cSSepherosa Ziehau 		uint8_t mic[IEEE80211_WEP_MICLEN];
240841ab66cSSepherosa Ziehau 
24132176cfdSRui Paulo 		vap->iv_stats.is_crypto_tkipenmic++;
242841ab66cSSepherosa Ziehau 
243841ab66cSSepherosa Ziehau 		hdrlen = ieee80211_hdrspace(ic, wh);
244841ab66cSSepherosa Ziehau 
245841ab66cSSepherosa Ziehau 		michael_mic(ctx, k->wk_txmic,
246841ab66cSSepherosa Ziehau 			m, hdrlen, m->m_pkthdr.len - hdrlen, mic);
24732176cfdSRui Paulo 		return m_append(m, tkip.ic_miclen, mic);
248841ab66cSSepherosa Ziehau 	}
249841ab66cSSepherosa Ziehau 	return 1;
250841ab66cSSepherosa Ziehau }
251841ab66cSSepherosa Ziehau 
252841ab66cSSepherosa Ziehau static __inline uint64_t
READ_6(uint8_t b0,uint8_t b1,uint8_t b2,uint8_t b3,uint8_t b4,uint8_t b5)253841ab66cSSepherosa Ziehau READ_6(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5)
254841ab66cSSepherosa Ziehau {
255841ab66cSSepherosa Ziehau 	uint32_t iv32 = (b0 << 0) | (b1 << 8) | (b2 << 16) | (b3 << 24);
256841ab66cSSepherosa Ziehau 	uint16_t iv16 = (b4 << 0) | (b5 << 8);
257841ab66cSSepherosa Ziehau 	return (((uint64_t)iv16) << 32) | iv32;
258841ab66cSSepherosa Ziehau }
259841ab66cSSepherosa Ziehau 
260841ab66cSSepherosa Ziehau /*
261841ab66cSSepherosa Ziehau  * Validate and strip privacy headers (and trailer) for a
262841ab66cSSepherosa Ziehau  * received frame.  If necessary, decrypt the frame using
263841ab66cSSepherosa Ziehau  * the specified key.
264841ab66cSSepherosa Ziehau  */
265841ab66cSSepherosa Ziehau static int
tkip_decap(struct ieee80211_key * k,struct mbuf * m,int hdrlen)266841ab66cSSepherosa Ziehau tkip_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen)
267841ab66cSSepherosa Ziehau {
268841ab66cSSepherosa Ziehau 	struct tkip_ctx *ctx = k->wk_private;
26932176cfdSRui Paulo 	struct ieee80211vap *vap = ctx->tc_vap;
270841ab66cSSepherosa Ziehau 	struct ieee80211_frame *wh;
27132176cfdSRui Paulo 	uint8_t *ivp, tid;
272841ab66cSSepherosa Ziehau 
273841ab66cSSepherosa Ziehau 	/*
274841ab66cSSepherosa Ziehau 	 * Header should have extended IV and sequence number;
275841ab66cSSepherosa Ziehau 	 * verify the former and validate the latter.
276841ab66cSSepherosa Ziehau 	 */
277841ab66cSSepherosa Ziehau 	wh = mtod(m, struct ieee80211_frame *);
278841ab66cSSepherosa Ziehau 	ivp = mtod(m, uint8_t *) + hdrlen;
279841ab66cSSepherosa Ziehau 	if ((ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV) == 0) {
280841ab66cSSepherosa Ziehau 		/*
281841ab66cSSepherosa Ziehau 		 * No extended IV; discard frame.
282841ab66cSSepherosa Ziehau 		 */
28332176cfdSRui Paulo 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
28432176cfdSRui Paulo 		    "%s", "missing ExtIV for TKIP cipher");
28532176cfdSRui Paulo 		vap->iv_stats.is_rx_tkipformat++;
286841ab66cSSepherosa Ziehau 		return 0;
287841ab66cSSepherosa Ziehau 	}
288841ab66cSSepherosa Ziehau 	/*
289841ab66cSSepherosa Ziehau 	 * Handle TKIP counter measures requirement.
290841ab66cSSepherosa Ziehau 	 */
29132176cfdSRui Paulo 	if (vap->iv_flags & IEEE80211_F_COUNTERM) {
29232176cfdSRui Paulo 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
29332176cfdSRui Paulo 		    "discard frame due to countermeasures (%s)", __func__);
29432176cfdSRui Paulo 		vap->iv_stats.is_crypto_tkipcm++;
295841ab66cSSepherosa Ziehau 		return 0;
296841ab66cSSepherosa Ziehau 	}
297841ab66cSSepherosa Ziehau 
29832176cfdSRui Paulo 	tid = ieee80211_gettid(wh);
299841ab66cSSepherosa Ziehau 	ctx->rx_rsc = READ_6(ivp[2], ivp[0], ivp[4], ivp[5], ivp[6], ivp[7]);
300085ff963SMatthew Dillon 	if (ctx->rx_rsc <= k->wk_keyrsc[tid] &&
301085ff963SMatthew Dillon 	    (k->wk_flags & IEEE80211_KEY_NOREPLAY) == 0) {
302841ab66cSSepherosa Ziehau 		/*
303841ab66cSSepherosa Ziehau 		 * Replay violation; notify upper layer.
304841ab66cSSepherosa Ziehau 		 */
30532176cfdSRui Paulo 		ieee80211_notify_replay_failure(vap, wh, k, ctx->rx_rsc, tid);
30632176cfdSRui Paulo 		vap->iv_stats.is_rx_tkipreplay++;
307841ab66cSSepherosa Ziehau 		return 0;
308841ab66cSSepherosa Ziehau 	}
309841ab66cSSepherosa Ziehau 	/*
310841ab66cSSepherosa Ziehau 	 * NB: We can't update the rsc in the key until MIC is verified.
311841ab66cSSepherosa Ziehau 	 *
312841ab66cSSepherosa Ziehau 	 * We assume we are not preempted between doing the check above
313841ab66cSSepherosa Ziehau 	 * and updating wk_keyrsc when stripping the MIC in tkip_demic.
314841ab66cSSepherosa Ziehau 	 * Otherwise we might process another packet and discard it as
315841ab66cSSepherosa Ziehau 	 * a replay.
316841ab66cSSepherosa Ziehau 	 */
317841ab66cSSepherosa Ziehau 
318841ab66cSSepherosa Ziehau 	/*
319841ab66cSSepherosa Ziehau 	 * Check if the device handled the decrypt in hardware.
320841ab66cSSepherosa Ziehau 	 * If so we just strip the header; otherwise we need to
321841ab66cSSepherosa Ziehau 	 * handle the decrypt in software.
322841ab66cSSepherosa Ziehau 	 */
32332176cfdSRui Paulo 	if ((k->wk_flags & IEEE80211_KEY_SWDECRYPT) &&
324841ab66cSSepherosa Ziehau 	    !tkip_decrypt(ctx, k, m, hdrlen))
325841ab66cSSepherosa Ziehau 		return 0;
326841ab66cSSepherosa Ziehau 
327841ab66cSSepherosa Ziehau 	/*
328841ab66cSSepherosa Ziehau 	 * Copy up 802.11 header and strip crypto bits.
329841ab66cSSepherosa Ziehau 	 */
330841ab66cSSepherosa Ziehau 	memmove(mtod(m, uint8_t *) + tkip.ic_header, mtod(m, void *), hdrlen);
331841ab66cSSepherosa Ziehau 	m_adj(m, tkip.ic_header);
332841ab66cSSepherosa Ziehau 	m_adj(m, -tkip.ic_trailer);
333841ab66cSSepherosa Ziehau 
334841ab66cSSepherosa Ziehau 	return 1;
335841ab66cSSepherosa Ziehau }
336841ab66cSSepherosa Ziehau 
337841ab66cSSepherosa Ziehau /*
338841ab66cSSepherosa Ziehau  * Verify and strip MIC from the frame.
339841ab66cSSepherosa Ziehau  */
340841ab66cSSepherosa Ziehau static int
tkip_demic(struct ieee80211_key * k,struct mbuf * m,int force)341841ab66cSSepherosa Ziehau tkip_demic(struct ieee80211_key *k, struct mbuf *m, int force)
342841ab66cSSepherosa Ziehau {
343841ab66cSSepherosa Ziehau 	struct tkip_ctx *ctx = k->wk_private;
34432176cfdSRui Paulo 	struct ieee80211_frame *wh;
34532176cfdSRui Paulo 	uint8_t tid;
346841ab66cSSepherosa Ziehau 
34732176cfdSRui Paulo 	wh = mtod(m, struct ieee80211_frame *);
34832176cfdSRui Paulo 	if ((k->wk_flags & IEEE80211_KEY_SWDEMIC) || force) {
34932176cfdSRui Paulo 		struct ieee80211vap *vap = ctx->tc_vap;
35032176cfdSRui Paulo 		int hdrlen = ieee80211_hdrspace(vap->iv_ic, wh);
35132176cfdSRui Paulo 		u8 mic[IEEE80211_WEP_MICLEN];
35232176cfdSRui Paulo 		u8 mic0[IEEE80211_WEP_MICLEN];
353841ab66cSSepherosa Ziehau 
35432176cfdSRui Paulo 		vap->iv_stats.is_crypto_tkipdemic++;
355841ab66cSSepherosa Ziehau 
356841ab66cSSepherosa Ziehau 		michael_mic(ctx, k->wk_rxmic,
357841ab66cSSepherosa Ziehau 			m, hdrlen, m->m_pkthdr.len - (hdrlen + tkip.ic_miclen),
358841ab66cSSepherosa Ziehau 			mic);
359841ab66cSSepherosa Ziehau 		m_copydata(m, m->m_pkthdr.len - tkip.ic_miclen,
36032176cfdSRui Paulo 			tkip.ic_miclen, mic0);
361841ab66cSSepherosa Ziehau 		if (memcmp(mic, mic0, tkip.ic_miclen)) {
362841ab66cSSepherosa Ziehau 			/* NB: 802.11 layer handles statistic and debug msg */
36332176cfdSRui Paulo 			ieee80211_notify_michael_failure(vap, wh,
364841ab66cSSepherosa Ziehau 				k->wk_rxkeyix != IEEE80211_KEYIX_NONE ?
365841ab66cSSepherosa Ziehau 					k->wk_rxkeyix : k->wk_keyix);
366841ab66cSSepherosa Ziehau 			return 0;
367841ab66cSSepherosa Ziehau 		}
368841ab66cSSepherosa Ziehau 	}
369841ab66cSSepherosa Ziehau 	/*
370841ab66cSSepherosa Ziehau 	 * Strip MIC from the tail.
371841ab66cSSepherosa Ziehau 	 */
372841ab66cSSepherosa Ziehau 	m_adj(m, -tkip.ic_miclen);
373841ab66cSSepherosa Ziehau 
374841ab66cSSepherosa Ziehau 	/*
375841ab66cSSepherosa Ziehau 	 * Ok to update rsc now that MIC has been verified.
376841ab66cSSepherosa Ziehau 	 */
37732176cfdSRui Paulo 	tid = ieee80211_gettid(wh);
37832176cfdSRui Paulo 	k->wk_keyrsc[tid] = ctx->rx_rsc;
379841ab66cSSepherosa Ziehau 
380841ab66cSSepherosa Ziehau 	return 1;
381841ab66cSSepherosa Ziehau }
382841ab66cSSepherosa Ziehau 
383841ab66cSSepherosa Ziehau /*
384841ab66cSSepherosa Ziehau  * Host AP crypt: host-based TKIP encryption implementation for Host AP driver
385841ab66cSSepherosa Ziehau  *
386841ab66cSSepherosa Ziehau  * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
387841ab66cSSepherosa Ziehau  *
388841ab66cSSepherosa Ziehau  * This program is free software; you can redistribute it and/or modify
389841ab66cSSepherosa Ziehau  * it under the terms of the GNU General Public License version 2 as
390841ab66cSSepherosa Ziehau  * published by the Free Software Foundation. See README and COPYING for
391841ab66cSSepherosa Ziehau  * more details.
392841ab66cSSepherosa Ziehau  *
393841ab66cSSepherosa Ziehau  * Alternatively, this software may be distributed under the terms of BSD
394841ab66cSSepherosa Ziehau  * license.
395841ab66cSSepherosa Ziehau  */
396841ab66cSSepherosa Ziehau 
39732176cfdSRui Paulo static const __u32 crc32_table[256] = {
398841ab66cSSepherosa Ziehau 	0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
399841ab66cSSepherosa Ziehau 	0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
400841ab66cSSepherosa Ziehau 	0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
401841ab66cSSepherosa Ziehau 	0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
402841ab66cSSepherosa Ziehau 	0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
403841ab66cSSepherosa Ziehau 	0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
404841ab66cSSepherosa Ziehau 	0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
405841ab66cSSepherosa Ziehau 	0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
406841ab66cSSepherosa Ziehau 	0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
407841ab66cSSepherosa Ziehau 	0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
408841ab66cSSepherosa Ziehau 	0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
409841ab66cSSepherosa Ziehau 	0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
410841ab66cSSepherosa Ziehau 	0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
411841ab66cSSepherosa Ziehau 	0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
412841ab66cSSepherosa Ziehau 	0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
413841ab66cSSepherosa Ziehau 	0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
414841ab66cSSepherosa Ziehau 	0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
415841ab66cSSepherosa Ziehau 	0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
416841ab66cSSepherosa Ziehau 	0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
417841ab66cSSepherosa Ziehau 	0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
418841ab66cSSepherosa Ziehau 	0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
419841ab66cSSepherosa Ziehau 	0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
420841ab66cSSepherosa Ziehau 	0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
421841ab66cSSepherosa Ziehau 	0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
422841ab66cSSepherosa Ziehau 	0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
423841ab66cSSepherosa Ziehau 	0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
424841ab66cSSepherosa Ziehau 	0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
425841ab66cSSepherosa Ziehau 	0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
426841ab66cSSepherosa Ziehau 	0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
427841ab66cSSepherosa Ziehau 	0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
428841ab66cSSepherosa Ziehau 	0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
429841ab66cSSepherosa Ziehau 	0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
430841ab66cSSepherosa Ziehau 	0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
431841ab66cSSepherosa Ziehau 	0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
432841ab66cSSepherosa Ziehau 	0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
433841ab66cSSepherosa Ziehau 	0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
434841ab66cSSepherosa Ziehau 	0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
435841ab66cSSepherosa Ziehau 	0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
436841ab66cSSepherosa Ziehau 	0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
437841ab66cSSepherosa Ziehau 	0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
438841ab66cSSepherosa Ziehau 	0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
439841ab66cSSepherosa Ziehau 	0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
440841ab66cSSepherosa Ziehau 	0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
441841ab66cSSepherosa Ziehau 	0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
442841ab66cSSepherosa Ziehau 	0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
443841ab66cSSepherosa Ziehau 	0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
444841ab66cSSepherosa Ziehau 	0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
445841ab66cSSepherosa Ziehau 	0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
446841ab66cSSepherosa Ziehau 	0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
447841ab66cSSepherosa Ziehau 	0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
448841ab66cSSepherosa Ziehau 	0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
449841ab66cSSepherosa Ziehau 	0x2d02ef8dL
450841ab66cSSepherosa Ziehau };
451841ab66cSSepherosa Ziehau 
RotR1(u16 val)45232176cfdSRui Paulo static __inline u16 RotR1(u16 val)
453841ab66cSSepherosa Ziehau {
454841ab66cSSepherosa Ziehau 	return (val >> 1) | (val << 15);
455841ab66cSSepherosa Ziehau }
456841ab66cSSepherosa Ziehau 
Lo8(u16 val)45732176cfdSRui Paulo static __inline u8 Lo8(u16 val)
458841ab66cSSepherosa Ziehau {
459841ab66cSSepherosa Ziehau 	return val & 0xff;
460841ab66cSSepherosa Ziehau }
461841ab66cSSepherosa Ziehau 
Hi8(u16 val)46232176cfdSRui Paulo static __inline u8 Hi8(u16 val)
463841ab66cSSepherosa Ziehau {
464841ab66cSSepherosa Ziehau 	return val >> 8;
465841ab66cSSepherosa Ziehau }
466841ab66cSSepherosa Ziehau 
Lo16(u32 val)46732176cfdSRui Paulo static __inline u16 Lo16(u32 val)
468841ab66cSSepherosa Ziehau {
469841ab66cSSepherosa Ziehau 	return val & 0xffff;
470841ab66cSSepherosa Ziehau }
471841ab66cSSepherosa Ziehau 
Hi16(u32 val)47232176cfdSRui Paulo static __inline u16 Hi16(u32 val)
473841ab66cSSepherosa Ziehau {
474841ab66cSSepherosa Ziehau 	return val >> 16;
475841ab66cSSepherosa Ziehau }
476841ab66cSSepherosa Ziehau 
Mk16(u8 hi,u8 lo)47732176cfdSRui Paulo static __inline u16 Mk16(u8 hi, u8 lo)
478841ab66cSSepherosa Ziehau {
47932176cfdSRui Paulo 	return lo | (((u16) hi) << 8);
480841ab66cSSepherosa Ziehau }
481841ab66cSSepherosa Ziehau 
Mk16_le(const u16 * v)48232176cfdSRui Paulo static __inline u16 Mk16_le(const u16 *v)
483841ab66cSSepherosa Ziehau {
484841ab66cSSepherosa Ziehau 	return le16toh(*v);
485841ab66cSSepherosa Ziehau }
486841ab66cSSepherosa Ziehau 
48732176cfdSRui Paulo static const u16 Sbox[256] = {
488841ab66cSSepherosa Ziehau 	0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
489841ab66cSSepherosa Ziehau 	0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
490841ab66cSSepherosa Ziehau 	0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
491841ab66cSSepherosa Ziehau 	0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
492841ab66cSSepherosa Ziehau 	0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
493841ab66cSSepherosa Ziehau 	0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
494841ab66cSSepherosa Ziehau 	0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
495841ab66cSSepherosa Ziehau 	0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
496841ab66cSSepherosa Ziehau 	0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
497841ab66cSSepherosa Ziehau 	0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
498841ab66cSSepherosa Ziehau 	0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
499841ab66cSSepherosa Ziehau 	0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
500841ab66cSSepherosa Ziehau 	0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
501841ab66cSSepherosa Ziehau 	0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
502841ab66cSSepherosa Ziehau 	0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
503841ab66cSSepherosa Ziehau 	0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
504841ab66cSSepherosa Ziehau 	0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
505841ab66cSSepherosa Ziehau 	0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
506841ab66cSSepherosa Ziehau 	0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
507841ab66cSSepherosa Ziehau 	0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
508841ab66cSSepherosa Ziehau 	0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
509841ab66cSSepherosa Ziehau 	0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
510841ab66cSSepherosa Ziehau 	0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
511841ab66cSSepherosa Ziehau 	0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
512841ab66cSSepherosa Ziehau 	0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
513841ab66cSSepherosa Ziehau 	0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
514841ab66cSSepherosa Ziehau 	0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
515841ab66cSSepherosa Ziehau 	0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
516841ab66cSSepherosa Ziehau 	0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
517841ab66cSSepherosa Ziehau 	0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
518841ab66cSSepherosa Ziehau 	0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
519841ab66cSSepherosa Ziehau 	0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
520841ab66cSSepherosa Ziehau };
521841ab66cSSepherosa Ziehau 
_S_(u16 v)52232176cfdSRui Paulo static __inline u16 _S_(u16 v)
523841ab66cSSepherosa Ziehau {
52432176cfdSRui Paulo 	u16 t = Sbox[Hi8(v)];
525841ab66cSSepherosa Ziehau 	return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8));
526841ab66cSSepherosa Ziehau }
527841ab66cSSepherosa Ziehau 
528841ab66cSSepherosa Ziehau #define PHASE1_LOOP_COUNT 8
529841ab66cSSepherosa Ziehau 
tkip_mixing_phase1(u16 * TTAK,const u8 * TK,const u8 * TA,u32 IV32)53032176cfdSRui Paulo static void tkip_mixing_phase1(u16 *TTAK, const u8 *TK, const u8 *TA, u32 IV32)
531841ab66cSSepherosa Ziehau {
532841ab66cSSepherosa Ziehau 	int i, j;
533841ab66cSSepherosa Ziehau 
534841ab66cSSepherosa Ziehau 	/* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */
535841ab66cSSepherosa Ziehau 	TTAK[0] = Lo16(IV32);
536841ab66cSSepherosa Ziehau 	TTAK[1] = Hi16(IV32);
537841ab66cSSepherosa Ziehau 	TTAK[2] = Mk16(TA[1], TA[0]);
538841ab66cSSepherosa Ziehau 	TTAK[3] = Mk16(TA[3], TA[2]);
539841ab66cSSepherosa Ziehau 	TTAK[4] = Mk16(TA[5], TA[4]);
540841ab66cSSepherosa Ziehau 
541841ab66cSSepherosa Ziehau 	for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
542841ab66cSSepherosa Ziehau 		j = 2 * (i & 1);
543841ab66cSSepherosa Ziehau 		TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j]));
544841ab66cSSepherosa Ziehau 		TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j]));
545841ab66cSSepherosa Ziehau 		TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j]));
546841ab66cSSepherosa Ziehau 		TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j]));
547841ab66cSSepherosa Ziehau 		TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i;
548841ab66cSSepherosa Ziehau 	}
549841ab66cSSepherosa Ziehau }
550841ab66cSSepherosa Ziehau 
551841ab66cSSepherosa Ziehau #ifndef _BYTE_ORDER
552841ab66cSSepherosa Ziehau #error "Don't know native byte order"
553841ab66cSSepherosa Ziehau #endif
554841ab66cSSepherosa Ziehau 
tkip_mixing_phase2(u8 * WEPSeed,const u8 * TK,const u16 * TTAK,u16 IV16)55532176cfdSRui Paulo static void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK,
55632176cfdSRui Paulo 			       u16 IV16)
557841ab66cSSepherosa Ziehau {
558841ab66cSSepherosa Ziehau 	/* Make temporary area overlap WEP seed so that the final copy can be
559841ab66cSSepherosa Ziehau 	 * avoided on little endian hosts. */
56032176cfdSRui Paulo 	u16 *PPK = (u16 *) &WEPSeed[4];
561841ab66cSSepherosa Ziehau 
562841ab66cSSepherosa Ziehau 	/* Step 1 - make copy of TTAK and bring in TSC */
563841ab66cSSepherosa Ziehau 	PPK[0] = TTAK[0];
564841ab66cSSepherosa Ziehau 	PPK[1] = TTAK[1];
565841ab66cSSepherosa Ziehau 	PPK[2] = TTAK[2];
566841ab66cSSepherosa Ziehau 	PPK[3] = TTAK[3];
567841ab66cSSepherosa Ziehau 	PPK[4] = TTAK[4];
568841ab66cSSepherosa Ziehau 	PPK[5] = TTAK[4] + IV16;
569841ab66cSSepherosa Ziehau 
570841ab66cSSepherosa Ziehau 	/* Step 2 - 96-bit bijective mixing using S-box */
57132176cfdSRui Paulo 	PPK[0] += _S_(PPK[5] ^ Mk16_le((const u16 *) &TK[0]));
57232176cfdSRui Paulo 	PPK[1] += _S_(PPK[0] ^ Mk16_le((const u16 *) &TK[2]));
57332176cfdSRui Paulo 	PPK[2] += _S_(PPK[1] ^ Mk16_le((const u16 *) &TK[4]));
57432176cfdSRui Paulo 	PPK[3] += _S_(PPK[2] ^ Mk16_le((const u16 *) &TK[6]));
57532176cfdSRui Paulo 	PPK[4] += _S_(PPK[3] ^ Mk16_le((const u16 *) &TK[8]));
57632176cfdSRui Paulo 	PPK[5] += _S_(PPK[4] ^ Mk16_le((const u16 *) &TK[10]));
577841ab66cSSepherosa Ziehau 
57832176cfdSRui Paulo 	PPK[0] += RotR1(PPK[5] ^ Mk16_le((const u16 *) &TK[12]));
57932176cfdSRui Paulo 	PPK[1] += RotR1(PPK[0] ^ Mk16_le((const u16 *) &TK[14]));
580841ab66cSSepherosa Ziehau 	PPK[2] += RotR1(PPK[1]);
581841ab66cSSepherosa Ziehau 	PPK[3] += RotR1(PPK[2]);
582841ab66cSSepherosa Ziehau 	PPK[4] += RotR1(PPK[3]);
583841ab66cSSepherosa Ziehau 	PPK[5] += RotR1(PPK[4]);
584841ab66cSSepherosa Ziehau 
585841ab66cSSepherosa Ziehau 	/* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value
586841ab66cSSepherosa Ziehau 	 * WEPSeed[0..2] is transmitted as WEP IV */
587841ab66cSSepherosa Ziehau 	WEPSeed[0] = Hi8(IV16);
588841ab66cSSepherosa Ziehau 	WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F;
589841ab66cSSepherosa Ziehau 	WEPSeed[2] = Lo8(IV16);
59032176cfdSRui Paulo 	WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((const u16 *) &TK[0])) >> 1);
591841ab66cSSepherosa Ziehau 
592841ab66cSSepherosa Ziehau #if _BYTE_ORDER == _BIG_ENDIAN
593841ab66cSSepherosa Ziehau 	{
594841ab66cSSepherosa Ziehau 		int i;
595841ab66cSSepherosa Ziehau 		for (i = 0; i < 6; i++)
596841ab66cSSepherosa Ziehau 			PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8);
597841ab66cSSepherosa Ziehau 	}
598841ab66cSSepherosa Ziehau #endif
599841ab66cSSepherosa Ziehau }
600841ab66cSSepherosa Ziehau 
601841ab66cSSepherosa Ziehau static void
wep_encrypt(u8 * key,struct mbuf * m0,u_int off,size_t data_len,uint8_t icv[IEEE80211_WEP_CRCLEN])60232176cfdSRui Paulo wep_encrypt(u8 *key, struct mbuf *m0, u_int off, size_t data_len,
603841ab66cSSepherosa Ziehau 	uint8_t icv[IEEE80211_WEP_CRCLEN])
604841ab66cSSepherosa Ziehau {
60532176cfdSRui Paulo 	u32 i, j, k, crc;
606841ab66cSSepherosa Ziehau 	size_t buflen;
60732176cfdSRui Paulo 	u8 S[256];
60832176cfdSRui Paulo 	u8 *pos;
609841ab66cSSepherosa Ziehau 	struct mbuf *m;
61032176cfdSRui Paulo #define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
611841ab66cSSepherosa Ziehau 
612841ab66cSSepherosa Ziehau 	/* Setup RC4 state */
613841ab66cSSepherosa Ziehau 	for (i = 0; i < 256; i++)
614841ab66cSSepherosa Ziehau 		S[i] = i;
615841ab66cSSepherosa Ziehau 	j = 0;
616841ab66cSSepherosa Ziehau 	for (i = 0; i < 256; i++) {
617841ab66cSSepherosa Ziehau 		j = (j + S[i] + key[i & 0x0f]) & 0xff;
618841ab66cSSepherosa Ziehau 		S_SWAP(i, j);
619841ab66cSSepherosa Ziehau 	}
620841ab66cSSepherosa Ziehau 
621841ab66cSSepherosa Ziehau 	/* Compute CRC32 over unencrypted data and apply RC4 to data */
622841ab66cSSepherosa Ziehau 	crc = ~0;
623841ab66cSSepherosa Ziehau 	i = j = 0;
624841ab66cSSepherosa Ziehau 	m = m0;
625841ab66cSSepherosa Ziehau 	pos = mtod(m, uint8_t *) + off;
626841ab66cSSepherosa Ziehau 	buflen = m->m_len - off;
627841ab66cSSepherosa Ziehau 	for (;;) {
628841ab66cSSepherosa Ziehau 		if (buflen > data_len)
629841ab66cSSepherosa Ziehau 			buflen = data_len;
630841ab66cSSepherosa Ziehau 		data_len -= buflen;
631841ab66cSSepherosa Ziehau 		for (k = 0; k < buflen; k++) {
632841ab66cSSepherosa Ziehau 			crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8);
633841ab66cSSepherosa Ziehau 			i = (i + 1) & 0xff;
634841ab66cSSepherosa Ziehau 			j = (j + S[i]) & 0xff;
635841ab66cSSepherosa Ziehau 			S_SWAP(i, j);
636841ab66cSSepherosa Ziehau 			*pos++ ^= S[(S[i] + S[j]) & 0xff];
637841ab66cSSepherosa Ziehau 		}
638841ab66cSSepherosa Ziehau 		m = m->m_next;
639841ab66cSSepherosa Ziehau 		if (m == NULL) {
640841ab66cSSepherosa Ziehau 			KASSERT(data_len == 0,
641085ff963SMatthew Dillon 			    ("out of buffers with data_len %zu\n", data_len));
642841ab66cSSepherosa Ziehau 			break;
643841ab66cSSepherosa Ziehau 		}
644841ab66cSSepherosa Ziehau 		pos = mtod(m, uint8_t *);
645841ab66cSSepherosa Ziehau 		buflen = m->m_len;
646841ab66cSSepherosa Ziehau 	}
647841ab66cSSepherosa Ziehau 	crc = ~crc;
648841ab66cSSepherosa Ziehau 
649841ab66cSSepherosa Ziehau 	/* Append little-endian CRC32 and encrypt it to produce ICV */
650841ab66cSSepherosa Ziehau 	icv[0] = crc;
651841ab66cSSepherosa Ziehau 	icv[1] = crc >> 8;
652841ab66cSSepherosa Ziehau 	icv[2] = crc >> 16;
653841ab66cSSepherosa Ziehau 	icv[3] = crc >> 24;
654841ab66cSSepherosa Ziehau 	for (k = 0; k < IEEE80211_WEP_CRCLEN; k++) {
655841ab66cSSepherosa Ziehau 		i = (i + 1) & 0xff;
656841ab66cSSepherosa Ziehau 		j = (j + S[i]) & 0xff;
657841ab66cSSepherosa Ziehau 		S_SWAP(i, j);
658841ab66cSSepherosa Ziehau 		icv[k] ^= S[(S[i] + S[j]) & 0xff];
659841ab66cSSepherosa Ziehau 	}
660841ab66cSSepherosa Ziehau }
661841ab66cSSepherosa Ziehau 
662841ab66cSSepherosa Ziehau static int
wep_decrypt(u8 * key,struct mbuf * m,u_int off,size_t data_len)66332176cfdSRui Paulo wep_decrypt(u8 *key, struct mbuf *m, u_int off, size_t data_len)
664841ab66cSSepherosa Ziehau {
66532176cfdSRui Paulo 	u32 i, j, k, crc;
66632176cfdSRui Paulo 	u8 S[256];
66732176cfdSRui Paulo 	u8 *pos, icv[4];
668841ab66cSSepherosa Ziehau 	size_t buflen;
669841ab66cSSepherosa Ziehau 
670841ab66cSSepherosa Ziehau 	/* Setup RC4 state */
671841ab66cSSepherosa Ziehau 	for (i = 0; i < 256; i++)
672841ab66cSSepherosa Ziehau 		S[i] = i;
673841ab66cSSepherosa Ziehau 	j = 0;
674841ab66cSSepherosa Ziehau 	for (i = 0; i < 256; i++) {
675841ab66cSSepherosa Ziehau 		j = (j + S[i] + key[i & 0x0f]) & 0xff;
676841ab66cSSepherosa Ziehau 		S_SWAP(i, j);
677841ab66cSSepherosa Ziehau 	}
678841ab66cSSepherosa Ziehau 
679841ab66cSSepherosa Ziehau 	/* Apply RC4 to data and compute CRC32 over decrypted data */
680841ab66cSSepherosa Ziehau 	crc = ~0;
681841ab66cSSepherosa Ziehau 	i = j = 0;
682841ab66cSSepherosa Ziehau 	pos = mtod(m, uint8_t *) + off;
683841ab66cSSepherosa Ziehau 	buflen = m->m_len - off;
684841ab66cSSepherosa Ziehau 	for (;;) {
685841ab66cSSepherosa Ziehau 		if (buflen > data_len)
686841ab66cSSepherosa Ziehau 			buflen = data_len;
687841ab66cSSepherosa Ziehau 		data_len -= buflen;
688841ab66cSSepherosa Ziehau 		for (k = 0; k < buflen; k++) {
689841ab66cSSepherosa Ziehau 			i = (i + 1) & 0xff;
690841ab66cSSepherosa Ziehau 			j = (j + S[i]) & 0xff;
691841ab66cSSepherosa Ziehau 			S_SWAP(i, j);
692841ab66cSSepherosa Ziehau 			*pos ^= S[(S[i] + S[j]) & 0xff];
693841ab66cSSepherosa Ziehau 			crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8);
694841ab66cSSepherosa Ziehau 			pos++;
695841ab66cSSepherosa Ziehau 		}
696841ab66cSSepherosa Ziehau 		m = m->m_next;
697841ab66cSSepherosa Ziehau 		if (m == NULL) {
698841ab66cSSepherosa Ziehau 			KASSERT(data_len == 0,
699085ff963SMatthew Dillon 			    ("out of buffers with data_len %zu\n", data_len));
700841ab66cSSepherosa Ziehau 			break;
701841ab66cSSepherosa Ziehau 		}
702841ab66cSSepherosa Ziehau 		pos = mtod(m, uint8_t *);
703841ab66cSSepherosa Ziehau 		buflen = m->m_len;
704841ab66cSSepherosa Ziehau 	}
705841ab66cSSepherosa Ziehau 	crc = ~crc;
706841ab66cSSepherosa Ziehau 
707841ab66cSSepherosa Ziehau 	/* Encrypt little-endian CRC32 and verify that it matches with the
708841ab66cSSepherosa Ziehau 	 * received ICV */
709841ab66cSSepherosa Ziehau 	icv[0] = crc;
710841ab66cSSepherosa Ziehau 	icv[1] = crc >> 8;
711841ab66cSSepherosa Ziehau 	icv[2] = crc >> 16;
712841ab66cSSepherosa Ziehau 	icv[3] = crc >> 24;
713841ab66cSSepherosa Ziehau 	for (k = 0; k < 4; k++) {
714841ab66cSSepherosa Ziehau 		i = (i + 1) & 0xff;
715841ab66cSSepherosa Ziehau 		j = (j + S[i]) & 0xff;
716841ab66cSSepherosa Ziehau 		S_SWAP(i, j);
717841ab66cSSepherosa Ziehau 		if ((icv[k] ^ S[(S[i] + S[j]) & 0xff]) != *pos++) {
718841ab66cSSepherosa Ziehau 			/* ICV mismatch - drop frame */
719841ab66cSSepherosa Ziehau 			return -1;
720841ab66cSSepherosa Ziehau 		}
721841ab66cSSepherosa Ziehau 	}
722841ab66cSSepherosa Ziehau 
723841ab66cSSepherosa Ziehau 	return 0;
724841ab66cSSepherosa Ziehau }
725841ab66cSSepherosa Ziehau 
726841ab66cSSepherosa Ziehau 
rotl(u32 val,int bits)72732176cfdSRui Paulo static __inline u32 rotl(u32 val, int bits)
728841ab66cSSepherosa Ziehau {
729841ab66cSSepherosa Ziehau 	return (val << bits) | (val >> (32 - bits));
730841ab66cSSepherosa Ziehau }
731841ab66cSSepherosa Ziehau 
732841ab66cSSepherosa Ziehau 
rotr(u32 val,int bits)73332176cfdSRui Paulo static __inline u32 rotr(u32 val, int bits)
734841ab66cSSepherosa Ziehau {
735841ab66cSSepherosa Ziehau 	return (val >> bits) | (val << (32 - bits));
736841ab66cSSepherosa Ziehau }
737841ab66cSSepherosa Ziehau 
738841ab66cSSepherosa Ziehau 
xswap(u32 val)73932176cfdSRui Paulo static __inline u32 xswap(u32 val)
740841ab66cSSepherosa Ziehau {
741841ab66cSSepherosa Ziehau 	return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8);
742841ab66cSSepherosa Ziehau }
743841ab66cSSepherosa Ziehau 
744841ab66cSSepherosa Ziehau 
745841ab66cSSepherosa Ziehau #define michael_block(l, r)	\
746841ab66cSSepherosa Ziehau do {				\
747841ab66cSSepherosa Ziehau 	r ^= rotl(l, 17);	\
748841ab66cSSepherosa Ziehau 	l += r;			\
749841ab66cSSepherosa Ziehau 	r ^= xswap(l);		\
750841ab66cSSepherosa Ziehau 	l += r;			\
751841ab66cSSepherosa Ziehau 	r ^= rotl(l, 3);	\
752841ab66cSSepherosa Ziehau 	l += r;			\
753841ab66cSSepherosa Ziehau 	r ^= rotr(l, 2);	\
754841ab66cSSepherosa Ziehau 	l += r;			\
755841ab66cSSepherosa Ziehau } while (0)
756841ab66cSSepherosa Ziehau 
757841ab66cSSepherosa Ziehau 
get_le32_split(u8 b0,u8 b1,u8 b2,u8 b3)75832176cfdSRui Paulo static __inline u32 get_le32_split(u8 b0, u8 b1, u8 b2, u8 b3)
759841ab66cSSepherosa Ziehau {
760841ab66cSSepherosa Ziehau 	return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
761841ab66cSSepherosa Ziehau }
762841ab66cSSepherosa Ziehau 
get_le32(const u8 * p)76332176cfdSRui Paulo static __inline u32 get_le32(const u8 *p)
764841ab66cSSepherosa Ziehau {
765841ab66cSSepherosa Ziehau 	return get_le32_split(p[0], p[1], p[2], p[3]);
766841ab66cSSepherosa Ziehau }
767841ab66cSSepherosa Ziehau 
768841ab66cSSepherosa Ziehau 
put_le32(u8 * p,u32 v)76932176cfdSRui Paulo static __inline void put_le32(u8 *p, u32 v)
770841ab66cSSepherosa Ziehau {
771841ab66cSSepherosa Ziehau 	p[0] = v;
772841ab66cSSepherosa Ziehau 	p[1] = v >> 8;
773841ab66cSSepherosa Ziehau 	p[2] = v >> 16;
774841ab66cSSepherosa Ziehau 	p[3] = v >> 24;
775841ab66cSSepherosa Ziehau }
776841ab66cSSepherosa Ziehau 
777841ab66cSSepherosa Ziehau /*
778841ab66cSSepherosa Ziehau  * Craft pseudo header used to calculate the MIC.
779841ab66cSSepherosa Ziehau  */
780841ab66cSSepherosa Ziehau static void
michael_mic_hdr(const struct ieee80211_frame * wh0,uint8_t hdr[16])781841ab66cSSepherosa Ziehau michael_mic_hdr(const struct ieee80211_frame *wh0, uint8_t hdr[16])
782841ab66cSSepherosa Ziehau {
783841ab66cSSepherosa Ziehau 	const struct ieee80211_frame_addr4 *wh =
784841ab66cSSepherosa Ziehau 		(const struct ieee80211_frame_addr4 *) wh0;
785841ab66cSSepherosa Ziehau 
786841ab66cSSepherosa Ziehau 	switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
787841ab66cSSepherosa Ziehau 	case IEEE80211_FC1_DIR_NODS:
788841ab66cSSepherosa Ziehau 		IEEE80211_ADDR_COPY(hdr, wh->i_addr1); /* DA */
789841ab66cSSepherosa Ziehau 		IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr2);
790841ab66cSSepherosa Ziehau 		break;
791841ab66cSSepherosa Ziehau 	case IEEE80211_FC1_DIR_TODS:
792841ab66cSSepherosa Ziehau 		IEEE80211_ADDR_COPY(hdr, wh->i_addr3); /* DA */
793841ab66cSSepherosa Ziehau 		IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr2);
794841ab66cSSepherosa Ziehau 		break;
795841ab66cSSepherosa Ziehau 	case IEEE80211_FC1_DIR_FROMDS:
796841ab66cSSepherosa Ziehau 		IEEE80211_ADDR_COPY(hdr, wh->i_addr1); /* DA */
797841ab66cSSepherosa Ziehau 		IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr3);
798841ab66cSSepherosa Ziehau 		break;
799841ab66cSSepherosa Ziehau 	case IEEE80211_FC1_DIR_DSTODS:
800841ab66cSSepherosa Ziehau 		IEEE80211_ADDR_COPY(hdr, wh->i_addr3); /* DA */
801841ab66cSSepherosa Ziehau 		IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr4);
802841ab66cSSepherosa Ziehau 		break;
803841ab66cSSepherosa Ziehau 	}
804841ab66cSSepherosa Ziehau 
805841ab66cSSepherosa Ziehau 	if (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) {
806841ab66cSSepherosa Ziehau 		const struct ieee80211_qosframe *qwh =
807841ab66cSSepherosa Ziehau 			(const struct ieee80211_qosframe *) wh;
808841ab66cSSepherosa Ziehau 		hdr[12] = qwh->i_qos[0] & IEEE80211_QOS_TID;
809841ab66cSSepherosa Ziehau 	} else
810841ab66cSSepherosa Ziehau 		hdr[12] = 0;
811841ab66cSSepherosa Ziehau 	hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */
812841ab66cSSepherosa Ziehau }
813841ab66cSSepherosa Ziehau 
814841ab66cSSepherosa Ziehau static void
michael_mic(struct tkip_ctx * ctx,const u8 * key,struct mbuf * m,u_int off,size_t data_len,u8 mic[IEEE80211_WEP_MICLEN])81532176cfdSRui Paulo michael_mic(struct tkip_ctx *ctx, const u8 *key,
816841ab66cSSepherosa Ziehau 	struct mbuf *m, u_int off, size_t data_len,
81732176cfdSRui Paulo 	u8 mic[IEEE80211_WEP_MICLEN])
818841ab66cSSepherosa Ziehau {
819841ab66cSSepherosa Ziehau 	uint8_t hdr[16];
82032176cfdSRui Paulo 	u32 l, r;
821841ab66cSSepherosa Ziehau 	const uint8_t *data;
822841ab66cSSepherosa Ziehau 	u_int space;
823841ab66cSSepherosa Ziehau 
824841ab66cSSepherosa Ziehau 	michael_mic_hdr(mtod(m, struct ieee80211_frame *), hdr);
825841ab66cSSepherosa Ziehau 
826841ab66cSSepherosa Ziehau 	l = get_le32(key);
827841ab66cSSepherosa Ziehau 	r = get_le32(key + 4);
828841ab66cSSepherosa Ziehau 
829841ab66cSSepherosa Ziehau 	/* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */
830841ab66cSSepherosa Ziehau 	l ^= get_le32(hdr);
831841ab66cSSepherosa Ziehau 	michael_block(l, r);
832841ab66cSSepherosa Ziehau 	l ^= get_le32(&hdr[4]);
833841ab66cSSepherosa Ziehau 	michael_block(l, r);
834841ab66cSSepherosa Ziehau 	l ^= get_le32(&hdr[8]);
835841ab66cSSepherosa Ziehau 	michael_block(l, r);
836841ab66cSSepherosa Ziehau 	l ^= get_le32(&hdr[12]);
837841ab66cSSepherosa Ziehau 	michael_block(l, r);
838841ab66cSSepherosa Ziehau 
839841ab66cSSepherosa Ziehau 	/* first buffer has special handling */
840841ab66cSSepherosa Ziehau 	data = mtod(m, const uint8_t *) + off;
841841ab66cSSepherosa Ziehau 	space = m->m_len - off;
842841ab66cSSepherosa Ziehau 	for (;;) {
843841ab66cSSepherosa Ziehau 		if (space > data_len)
844841ab66cSSepherosa Ziehau 			space = data_len;
845841ab66cSSepherosa Ziehau 		/* collect 32-bit blocks from current buffer */
846841ab66cSSepherosa Ziehau 		while (space >= sizeof(uint32_t)) {
847841ab66cSSepherosa Ziehau 			l ^= get_le32(data);
848841ab66cSSepherosa Ziehau 			michael_block(l, r);
849841ab66cSSepherosa Ziehau 			data += sizeof(uint32_t), space -= sizeof(uint32_t);
850841ab66cSSepherosa Ziehau 			data_len -= sizeof(uint32_t);
851841ab66cSSepherosa Ziehau 		}
85232176cfdSRui Paulo 		/*
85332176cfdSRui Paulo 		 * NB: when space is zero we make one more trip around
85432176cfdSRui Paulo 		 * the loop to advance to the next mbuf where there is
85532176cfdSRui Paulo 		 * data.  This handles the case where there are 4*n
85632176cfdSRui Paulo 		 * bytes in an mbuf followed by <4 bytes in a later mbuf.
85732176cfdSRui Paulo 		 * By making an extra trip we'll drop out of the loop
85832176cfdSRui Paulo 		 * with m pointing at the mbuf with 3 bytes and space
85932176cfdSRui Paulo 		 * set as required by the remainder handling below.
86032176cfdSRui Paulo 		 */
86132176cfdSRui Paulo 		if (data_len == 0 ||
86232176cfdSRui Paulo 		    (data_len < sizeof(uint32_t) && space != 0))
863841ab66cSSepherosa Ziehau 			break;
864841ab66cSSepherosa Ziehau 		m = m->m_next;
865841ab66cSSepherosa Ziehau 		if (m == NULL) {
866085ff963SMatthew Dillon 			KASSERT(0, ("out of data, data_len %zu\n", data_len));
867841ab66cSSepherosa Ziehau 			break;
868841ab66cSSepherosa Ziehau 		}
869841ab66cSSepherosa Ziehau 		if (space != 0) {
870841ab66cSSepherosa Ziehau 			const uint8_t *data_next;
871841ab66cSSepherosa Ziehau 			/*
872841ab66cSSepherosa Ziehau 			 * Block straddles buffers, split references.
873841ab66cSSepherosa Ziehau 			 */
874841ab66cSSepherosa Ziehau 			data_next = mtod(m, const uint8_t *);
875841ab66cSSepherosa Ziehau 			KASSERT(m->m_len >= sizeof(uint32_t) - space,
876841ab66cSSepherosa Ziehau 				("not enough data in following buffer, "
877085ff963SMatthew Dillon 				"m_len %u need %zu\n", m->m_len,
878841ab66cSSepherosa Ziehau 				sizeof(uint32_t) - space));
879841ab66cSSepherosa Ziehau 			switch (space) {
880841ab66cSSepherosa Ziehau 			case 1:
881841ab66cSSepherosa Ziehau 				l ^= get_le32_split(data[0], data_next[0],
882841ab66cSSepherosa Ziehau 					data_next[1], data_next[2]);
883841ab66cSSepherosa Ziehau 				data = data_next + 3;
884841ab66cSSepherosa Ziehau 				space = m->m_len - 3;
885841ab66cSSepherosa Ziehau 				break;
886841ab66cSSepherosa Ziehau 			case 2:
887841ab66cSSepherosa Ziehau 				l ^= get_le32_split(data[0], data[1],
888841ab66cSSepherosa Ziehau 					data_next[0], data_next[1]);
889841ab66cSSepherosa Ziehau 				data = data_next + 2;
890841ab66cSSepherosa Ziehau 				space = m->m_len - 2;
891841ab66cSSepherosa Ziehau 				break;
892841ab66cSSepherosa Ziehau 			case 3:
893841ab66cSSepherosa Ziehau 				l ^= get_le32_split(data[0], data[1],
894841ab66cSSepherosa Ziehau 					data[2], data_next[0]);
895841ab66cSSepherosa Ziehau 				data = data_next + 1;
896841ab66cSSepherosa Ziehau 				space = m->m_len - 1;
897841ab66cSSepherosa Ziehau 				break;
898841ab66cSSepherosa Ziehau 			}
899841ab66cSSepherosa Ziehau 			michael_block(l, r);
900841ab66cSSepherosa Ziehau 			data_len -= sizeof(uint32_t);
901841ab66cSSepherosa Ziehau 		} else {
902841ab66cSSepherosa Ziehau 			/*
903841ab66cSSepherosa Ziehau 			 * Setup for next buffer.
904841ab66cSSepherosa Ziehau 			 */
905841ab66cSSepherosa Ziehau 			data = mtod(m, const uint8_t *);
906841ab66cSSepherosa Ziehau 			space = m->m_len;
907841ab66cSSepherosa Ziehau 		}
908841ab66cSSepherosa Ziehau 	}
90932176cfdSRui Paulo 	/*
91032176cfdSRui Paulo 	 * Catch degenerate cases like mbuf[4*n+1 bytes] followed by
91132176cfdSRui Paulo 	 * mbuf[2 bytes].  I don't believe these should happen; if they
91232176cfdSRui Paulo 	 * do then we'll need more involved logic.
91332176cfdSRui Paulo 	 */
91432176cfdSRui Paulo 	KASSERT(data_len <= space,
915085ff963SMatthew Dillon 	    ("not enough data, data_len %zu space %u\n", data_len, space));
91632176cfdSRui Paulo 
917841ab66cSSepherosa Ziehau 	/* Last block and padding (0x5a, 4..7 x 0) */
918841ab66cSSepherosa Ziehau 	switch (data_len) {
919841ab66cSSepherosa Ziehau 	case 0:
920841ab66cSSepherosa Ziehau 		l ^= get_le32_split(0x5a, 0, 0, 0);
921841ab66cSSepherosa Ziehau 		break;
922841ab66cSSepherosa Ziehau 	case 1:
923841ab66cSSepherosa Ziehau 		l ^= get_le32_split(data[0], 0x5a, 0, 0);
924841ab66cSSepherosa Ziehau 		break;
925841ab66cSSepherosa Ziehau 	case 2:
926841ab66cSSepherosa Ziehau 		l ^= get_le32_split(data[0], data[1], 0x5a, 0);
927841ab66cSSepherosa Ziehau 		break;
928841ab66cSSepherosa Ziehau 	case 3:
929841ab66cSSepherosa Ziehau 		l ^= get_le32_split(data[0], data[1], data[2], 0x5a);
930841ab66cSSepherosa Ziehau 		break;
931841ab66cSSepherosa Ziehau 	}
932841ab66cSSepherosa Ziehau 	michael_block(l, r);
933841ab66cSSepherosa Ziehau 	/* l ^= 0; */
934841ab66cSSepherosa Ziehau 	michael_block(l, r);
935841ab66cSSepherosa Ziehau 
936841ab66cSSepherosa Ziehau 	put_le32(mic, l);
937841ab66cSSepherosa Ziehau 	put_le32(mic + 4, r);
938841ab66cSSepherosa Ziehau }
939841ab66cSSepherosa Ziehau 
940841ab66cSSepherosa Ziehau static int
tkip_encrypt(struct tkip_ctx * ctx,struct ieee80211_key * key,struct mbuf * m,int hdrlen)941841ab66cSSepherosa Ziehau tkip_encrypt(struct tkip_ctx *ctx, struct ieee80211_key *key,
942841ab66cSSepherosa Ziehau 	struct mbuf *m, int hdrlen)
943841ab66cSSepherosa Ziehau {
944841ab66cSSepherosa Ziehau 	struct ieee80211_frame *wh;
945841ab66cSSepherosa Ziehau 	uint8_t icv[IEEE80211_WEP_CRCLEN];
946841ab66cSSepherosa Ziehau 
94732176cfdSRui Paulo 	ctx->tc_vap->iv_stats.is_crypto_tkip++;
948841ab66cSSepherosa Ziehau 
949841ab66cSSepherosa Ziehau 	wh = mtod(m, struct ieee80211_frame *);
9504f655ef5SMatthew Dillon 	if ((u16)(key->wk_keytsc) == 0 || key->wk_keytsc == 1) {
951841ab66cSSepherosa Ziehau 		tkip_mixing_phase1(ctx->tx_ttak, key->wk_key, wh->i_addr2,
95232176cfdSRui Paulo 				   (u32)(key->wk_keytsc >> 16));
953841ab66cSSepherosa Ziehau 	}
954841ab66cSSepherosa Ziehau 	tkip_mixing_phase2(ctx->tx_rc4key, key->wk_key, ctx->tx_ttak,
95532176cfdSRui Paulo 		(u16) key->wk_keytsc);
956841ab66cSSepherosa Ziehau 
957841ab66cSSepherosa Ziehau 	wep_encrypt(ctx->tx_rc4key,
958841ab66cSSepherosa Ziehau 		m, hdrlen + tkip.ic_header,
959841ab66cSSepherosa Ziehau 		m->m_pkthdr.len - (hdrlen + tkip.ic_header),
960841ab66cSSepherosa Ziehau 		icv);
96132176cfdSRui Paulo 	(void) m_append(m, IEEE80211_WEP_CRCLEN, icv);	/* XXX check return */
962841ab66cSSepherosa Ziehau 
963841ab66cSSepherosa Ziehau 	return 1;
964841ab66cSSepherosa Ziehau }
965841ab66cSSepherosa Ziehau 
966841ab66cSSepherosa Ziehau static int
tkip_decrypt(struct tkip_ctx * ctx,struct ieee80211_key * key,struct mbuf * m,int hdrlen)967841ab66cSSepherosa Ziehau tkip_decrypt(struct tkip_ctx *ctx, struct ieee80211_key *key,
968841ab66cSSepherosa Ziehau 	struct mbuf *m, int hdrlen)
969841ab66cSSepherosa Ziehau {
970841ab66cSSepherosa Ziehau 	struct ieee80211_frame *wh;
97132176cfdSRui Paulo 	struct ieee80211vap *vap = ctx->tc_vap;
97232176cfdSRui Paulo 	u32 iv32;
97332176cfdSRui Paulo 	u16 iv16;
97432176cfdSRui Paulo 	u8 tid;
975841ab66cSSepherosa Ziehau 
97632176cfdSRui Paulo 	vap->iv_stats.is_crypto_tkip++;
977841ab66cSSepherosa Ziehau 
978841ab66cSSepherosa Ziehau 	wh = mtod(m, struct ieee80211_frame *);
979841ab66cSSepherosa Ziehau 	/* NB: tkip_decap already verified header and left seq in rx_rsc */
98032176cfdSRui Paulo 	iv16 = (u16) ctx->rx_rsc;
98132176cfdSRui Paulo 	iv32 = (u32) (ctx->rx_rsc >> 16);
982841ab66cSSepherosa Ziehau 
98332176cfdSRui Paulo 	tid = ieee80211_gettid(wh);
98432176cfdSRui Paulo 	if (iv32 != (u32)(key->wk_keyrsc[tid] >> 16) || !ctx->rx_phase1_done) {
985841ab66cSSepherosa Ziehau 		tkip_mixing_phase1(ctx->rx_ttak, key->wk_key,
986841ab66cSSepherosa Ziehau 			wh->i_addr2, iv32);
987841ab66cSSepherosa Ziehau 		ctx->rx_phase1_done = 1;
988841ab66cSSepherosa Ziehau 	}
989841ab66cSSepherosa Ziehau 	tkip_mixing_phase2(ctx->rx_rc4key, key->wk_key, ctx->rx_ttak, iv16);
990841ab66cSSepherosa Ziehau 
991841ab66cSSepherosa Ziehau 	/* NB: m is unstripped; deduct headers + ICV to get payload */
992841ab66cSSepherosa Ziehau 	if (wep_decrypt(ctx->rx_rc4key,
993841ab66cSSepherosa Ziehau 		m, hdrlen + tkip.ic_header,
994841ab66cSSepherosa Ziehau 	        m->m_pkthdr.len - (hdrlen + tkip.ic_header + tkip.ic_trailer))) {
99532176cfdSRui Paulo 		if (iv32 != (u32)(key->wk_keyrsc[tid] >> 16)) {
996841ab66cSSepherosa Ziehau 			/* Previously cached Phase1 result was already lost, so
997841ab66cSSepherosa Ziehau 			 * it needs to be recalculated for the next packet. */
998841ab66cSSepherosa Ziehau 			ctx->rx_phase1_done = 0;
999841ab66cSSepherosa Ziehau 		}
100032176cfdSRui Paulo 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
100132176cfdSRui Paulo 		    "%s", "TKIP ICV mismatch on decrypt");
100232176cfdSRui Paulo 		vap->iv_stats.is_rx_tkipicv++;
1003841ab66cSSepherosa Ziehau 		return 0;
1004841ab66cSSepherosa Ziehau 	}
1005841ab66cSSepherosa Ziehau 	return 1;
1006841ab66cSSepherosa Ziehau }
1007841ab66cSSepherosa Ziehau 
1008841ab66cSSepherosa Ziehau /*
1009841ab66cSSepherosa Ziehau  * Module glue.
1010841ab66cSSepherosa Ziehau  */
101132176cfdSRui Paulo IEEE80211_CRYPTO_MODULE(tkip, 1);
1012