xref: /freebsd/sys/net80211/ieee80211_crypto_tkip.c (revision ef0d8f6351ef193da64ddcc50f012140d89c66c5)
18a1b9b6aSSam Leffler /*-
2b032f27cSSam Leffler  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
38a1b9b6aSSam Leffler  * All rights reserved.
48a1b9b6aSSam Leffler  *
58a1b9b6aSSam Leffler  * Redistribution and use in source and binary forms, with or without
68a1b9b6aSSam Leffler  * modification, are permitted provided that the following conditions
78a1b9b6aSSam Leffler  * are met:
88a1b9b6aSSam Leffler  * 1. Redistributions of source code must retain the above copyright
98a1b9b6aSSam Leffler  *    notice, this list of conditions and the following disclaimer.
108a1b9b6aSSam Leffler  * 2. Redistributions in binary form must reproduce the above copyright
118a1b9b6aSSam Leffler  *    notice, this list of conditions and the following disclaimer in the
128a1b9b6aSSam Leffler  *    documentation and/or other materials provided with the distribution.
138a1b9b6aSSam Leffler  *
148a1b9b6aSSam Leffler  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
158a1b9b6aSSam Leffler  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
168a1b9b6aSSam Leffler  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
178a1b9b6aSSam Leffler  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
188a1b9b6aSSam Leffler  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
198a1b9b6aSSam Leffler  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
208a1b9b6aSSam Leffler  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
218a1b9b6aSSam Leffler  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
228a1b9b6aSSam Leffler  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
238a1b9b6aSSam Leffler  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
248a1b9b6aSSam Leffler  */
258a1b9b6aSSam Leffler 
268a1b9b6aSSam Leffler #include <sys/cdefs.h>
278a1b9b6aSSam Leffler __FBSDID("$FreeBSD$");
288a1b9b6aSSam Leffler 
298a1b9b6aSSam Leffler /*
308a1b9b6aSSam Leffler  * IEEE 802.11i TKIP crypto support.
318a1b9b6aSSam Leffler  *
328a1b9b6aSSam Leffler  * Part of this module is derived from similar code in the Host
338a1b9b6aSSam Leffler  * AP driver. The code is used with the consent of the author and
348a1b9b6aSSam Leffler  * it's license is included below.
358a1b9b6aSSam Leffler  */
36b032f27cSSam Leffler #include "opt_wlan.h"
37b032f27cSSam Leffler 
388a1b9b6aSSam Leffler #include <sys/param.h>
398a1b9b6aSSam Leffler #include <sys/systm.h>
408a1b9b6aSSam Leffler #include <sys/mbuf.h>
418a1b9b6aSSam Leffler #include <sys/malloc.h>
428a1b9b6aSSam Leffler #include <sys/kernel.h>
438a1b9b6aSSam Leffler #include <sys/module.h>
448a1b9b6aSSam Leffler #include <sys/endian.h>
458a1b9b6aSSam Leffler 
468a1b9b6aSSam Leffler #include <sys/socket.h>
478a1b9b6aSSam Leffler 
488a1b9b6aSSam Leffler #include <net/if.h>
498a1b9b6aSSam Leffler #include <net/if_media.h>
508a1b9b6aSSam Leffler #include <net/ethernet.h>
518a1b9b6aSSam Leffler 
528a1b9b6aSSam Leffler #include <net80211/ieee80211_var.h>
538a1b9b6aSSam Leffler 
54b032f27cSSam Leffler static	void *tkip_attach(struct ieee80211vap *, struct ieee80211_key *);
558a1b9b6aSSam Leffler static	void tkip_detach(struct ieee80211_key *);
568a1b9b6aSSam Leffler static	int tkip_setkey(struct ieee80211_key *);
57*ef0d8f63SAdrian Chadd static	int tkip_encap(struct ieee80211_key *, struct mbuf *);
5896d88463SSam Leffler static	int tkip_enmic(struct ieee80211_key *, struct mbuf *, int);
592cc12adeSSam Leffler static	int tkip_decap(struct ieee80211_key *, struct mbuf *, int);
6096d88463SSam Leffler static	int tkip_demic(struct ieee80211_key *, struct mbuf *, int);
618a1b9b6aSSam Leffler 
628a1b9b6aSSam Leffler static const struct ieee80211_cipher tkip  = {
638a1b9b6aSSam Leffler 	.ic_name	= "TKIP",
648a1b9b6aSSam Leffler 	.ic_cipher	= IEEE80211_CIPHER_TKIP,
658a1b9b6aSSam Leffler 	.ic_header	= IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
668a1b9b6aSSam Leffler 			  IEEE80211_WEP_EXTIVLEN,
678a1b9b6aSSam Leffler 	.ic_trailer	= IEEE80211_WEP_CRCLEN,
688a1b9b6aSSam Leffler 	.ic_miclen	= IEEE80211_WEP_MICLEN,
698a1b9b6aSSam Leffler 	.ic_attach	= tkip_attach,
708a1b9b6aSSam Leffler 	.ic_detach	= tkip_detach,
718a1b9b6aSSam Leffler 	.ic_setkey	= tkip_setkey,
728a1b9b6aSSam Leffler 	.ic_encap	= tkip_encap,
738a1b9b6aSSam Leffler 	.ic_decap	= tkip_decap,
748a1b9b6aSSam Leffler 	.ic_enmic	= tkip_enmic,
758a1b9b6aSSam Leffler 	.ic_demic	= tkip_demic,
768a1b9b6aSSam Leffler };
778a1b9b6aSSam Leffler 
788a1b9b6aSSam Leffler typedef	uint8_t u8;
798a1b9b6aSSam Leffler typedef	uint16_t u16;
808a1b9b6aSSam Leffler typedef	uint32_t __u32;
818a1b9b6aSSam Leffler typedef	uint32_t u32;
828a1b9b6aSSam Leffler 
838a1b9b6aSSam Leffler struct tkip_ctx {
84b032f27cSSam Leffler 	struct ieee80211vap *tc_vap;	/* for diagnostics+statistics */
858a1b9b6aSSam Leffler 
868a1b9b6aSSam Leffler 	u16	tx_ttak[5];
878a1b9b6aSSam Leffler 	int	tx_phase1_done;
888a1b9b6aSSam Leffler 	u8	tx_rc4key[16];		/* XXX for test module; make locals? */
898a1b9b6aSSam Leffler 
908a1b9b6aSSam Leffler 	u16	rx_ttak[5];
918a1b9b6aSSam Leffler 	int	rx_phase1_done;
928a1b9b6aSSam Leffler 	u8	rx_rc4key[16];		/* XXX for test module; make locals? */
938a1b9b6aSSam Leffler 	uint64_t rx_rsc;		/* held until MIC verified */
948a1b9b6aSSam Leffler };
958a1b9b6aSSam Leffler 
968a1b9b6aSSam Leffler static	void michael_mic(struct tkip_ctx *, const u8 *key,
978a1b9b6aSSam Leffler 		struct mbuf *m, u_int off, size_t data_len,
988a1b9b6aSSam Leffler 		u8 mic[IEEE80211_WEP_MICLEN]);
998a1b9b6aSSam Leffler static	int tkip_encrypt(struct tkip_ctx *, struct ieee80211_key *,
1008a1b9b6aSSam Leffler 		struct mbuf *, int hdr_len);
1018a1b9b6aSSam Leffler static	int tkip_decrypt(struct tkip_ctx *, struct ieee80211_key *,
1028a1b9b6aSSam Leffler 		struct mbuf *, int hdr_len);
1038a1b9b6aSSam Leffler 
104d16441fdSSam Leffler /* number of references from net80211 layer */
105d16441fdSSam Leffler static	int nrefs = 0;
106d16441fdSSam Leffler 
1078a1b9b6aSSam Leffler static void *
108b032f27cSSam Leffler tkip_attach(struct ieee80211vap *vap, struct ieee80211_key *k)
1098a1b9b6aSSam Leffler {
1108a1b9b6aSSam Leffler 	struct tkip_ctx *ctx;
1118a1b9b6aSSam Leffler 
112b9b53389SAdrian Chadd 	ctx = (struct tkip_ctx *) IEEE80211_MALLOC(sizeof(struct tkip_ctx),
113b9b53389SAdrian Chadd 		M_80211_CRYPTO, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
1148a1b9b6aSSam Leffler 	if (ctx == NULL) {
115b032f27cSSam Leffler 		vap->iv_stats.is_crypto_nomem++;
1168a1b9b6aSSam Leffler 		return NULL;
1178a1b9b6aSSam Leffler 	}
1188a1b9b6aSSam Leffler 
119b032f27cSSam Leffler 	ctx->tc_vap = vap;
120d16441fdSSam Leffler 	nrefs++;			/* NB: we assume caller locking */
1218a1b9b6aSSam Leffler 	return ctx;
1228a1b9b6aSSam Leffler }
1238a1b9b6aSSam Leffler 
1248a1b9b6aSSam Leffler static void
1258a1b9b6aSSam Leffler tkip_detach(struct ieee80211_key *k)
1268a1b9b6aSSam Leffler {
1278a1b9b6aSSam Leffler 	struct tkip_ctx *ctx = k->wk_private;
1288a1b9b6aSSam Leffler 
129b9b53389SAdrian Chadd 	IEEE80211_FREE(ctx, M_80211_CRYPTO);
130d16441fdSSam Leffler 	KASSERT(nrefs > 0, ("imbalanced attach/detach"));
131d16441fdSSam Leffler 	nrefs--;			/* NB: we assume caller locking */
1328a1b9b6aSSam Leffler }
1338a1b9b6aSSam Leffler 
1348a1b9b6aSSam Leffler static int
1358a1b9b6aSSam Leffler tkip_setkey(struct ieee80211_key *k)
1368a1b9b6aSSam Leffler {
1378a1b9b6aSSam Leffler 	struct tkip_ctx *ctx = k->wk_private;
1388a1b9b6aSSam Leffler 
1398a1b9b6aSSam Leffler 	if (k->wk_keylen != (128/NBBY)) {
1408a1b9b6aSSam Leffler 		(void) ctx;		/* XXX */
141b032f27cSSam Leffler 		IEEE80211_DPRINTF(ctx->tc_vap, IEEE80211_MSG_CRYPTO,
1428a1b9b6aSSam Leffler 			"%s: Invalid key length %u, expecting %u\n",
1438a1b9b6aSSam Leffler 			__func__, k->wk_keylen, 128/NBBY);
1448a1b9b6aSSam Leffler 		return 0;
1458a1b9b6aSSam Leffler 	}
1468a1b9b6aSSam Leffler 	k->wk_keytsc = 1;		/* TSC starts at 1 */
14798f160d9SBernhard Schmidt 	ctx->rx_phase1_done = 0;
1488a1b9b6aSSam Leffler 	return 1;
1498a1b9b6aSSam Leffler }
1508a1b9b6aSSam Leffler 
1518a1b9b6aSSam Leffler /*
1528a1b9b6aSSam Leffler  * Add privacy headers and do any s/w encryption required.
1538a1b9b6aSSam Leffler  */
1548a1b9b6aSSam Leffler static int
155*ef0d8f63SAdrian Chadd tkip_encap(struct ieee80211_key *k, struct mbuf *m)
1568a1b9b6aSSam Leffler {
1578a1b9b6aSSam Leffler 	struct tkip_ctx *ctx = k->wk_private;
158b032f27cSSam Leffler 	struct ieee80211vap *vap = ctx->tc_vap;
159b032f27cSSam Leffler 	struct ieee80211com *ic = vap->iv_ic;
16068e8e04eSSam Leffler 	uint8_t *ivp;
161*ef0d8f63SAdrian Chadd 	uint8_t keyid;
1628a1b9b6aSSam Leffler 	int hdrlen;
1638a1b9b6aSSam Leffler 
1648a1b9b6aSSam Leffler 	/*
1658a1b9b6aSSam Leffler 	 * Handle TKIP counter measures requirement.
1668a1b9b6aSSam Leffler 	 */
167b032f27cSSam Leffler 	if (vap->iv_flags & IEEE80211_F_COUNTERM) {
1688a1b9b6aSSam Leffler #ifdef IEEE80211_DEBUG
1698a1b9b6aSSam Leffler 		struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
1708a1b9b6aSSam Leffler #endif
1718a1b9b6aSSam Leffler 
172b032f27cSSam Leffler 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
173b032f27cSSam Leffler 		    "discard frame due to countermeasures (%s)", __func__);
174b032f27cSSam Leffler 		vap->iv_stats.is_crypto_tkipcm++;
1758a1b9b6aSSam Leffler 		return 0;
1768a1b9b6aSSam Leffler 	}
1774e844c94SSam Leffler 	hdrlen = ieee80211_hdrspace(ic, mtod(m, void *));
1788a1b9b6aSSam Leffler 
1798a1b9b6aSSam Leffler 	/*
1808a1b9b6aSSam Leffler 	 * Copy down 802.11 header and add the IV, KeyID, and ExtIV.
1818a1b9b6aSSam Leffler 	 */
1828a1b9b6aSSam Leffler 	M_PREPEND(m, tkip.ic_header, M_NOWAIT);
1838a1b9b6aSSam Leffler 	if (m == NULL)
1848a1b9b6aSSam Leffler 		return 0;
18568e8e04eSSam Leffler 	ivp = mtod(m, uint8_t *);
1868a1b9b6aSSam Leffler 	memmove(ivp, ivp + tkip.ic_header, hdrlen);
1878a1b9b6aSSam Leffler 	ivp += hdrlen;
1888a1b9b6aSSam Leffler 
189*ef0d8f63SAdrian Chadd 	keyid = ieee80211_crypto_get_keyid(vap, k) << 6;
190*ef0d8f63SAdrian Chadd 
1918a1b9b6aSSam Leffler 	ivp[0] = k->wk_keytsc >> 8;		/* TSC1 */
1928a1b9b6aSSam Leffler 	ivp[1] = (ivp[0] | 0x20) & 0x7f;	/* WEP seed */
1938a1b9b6aSSam Leffler 	ivp[2] = k->wk_keytsc >> 0;		/* TSC0 */
1948a1b9b6aSSam Leffler 	ivp[3] = keyid | IEEE80211_WEP_EXTIV;	/* KeyID | ExtID */
1958a1b9b6aSSam Leffler 	ivp[4] = k->wk_keytsc >> 16;		/* TSC2 */
1968a1b9b6aSSam Leffler 	ivp[5] = k->wk_keytsc >> 24;		/* TSC3 */
1978a1b9b6aSSam Leffler 	ivp[6] = k->wk_keytsc >> 32;		/* TSC4 */
1988a1b9b6aSSam Leffler 	ivp[7] = k->wk_keytsc >> 40;		/* TSC5 */
1998a1b9b6aSSam Leffler 
2008a1b9b6aSSam Leffler 	/*
201bf0b7b45SAdrian Chadd 	 * Finally, do software encrypt if needed.
2028a1b9b6aSSam Leffler 	 */
2035c1f7f19SSam Leffler 	if (k->wk_flags & IEEE80211_KEY_SWENCRYPT) {
2048a1b9b6aSSam Leffler 		if (!tkip_encrypt(ctx, k, m, hdrlen))
2058a1b9b6aSSam Leffler 			return 0;
2068a1b9b6aSSam Leffler 		/* NB: tkip_encrypt handles wk_keytsc */
2078a1b9b6aSSam Leffler 	} else
208f287c95bSSam Leffler 		k->wk_keytsc++;
2098a1b9b6aSSam Leffler 
2108a1b9b6aSSam Leffler 	return 1;
2118a1b9b6aSSam Leffler }
2128a1b9b6aSSam Leffler 
2138a1b9b6aSSam Leffler /*
2148a1b9b6aSSam Leffler  * Add MIC to the frame as needed.
2158a1b9b6aSSam Leffler  */
2168a1b9b6aSSam Leffler static int
21796d88463SSam Leffler tkip_enmic(struct ieee80211_key *k, struct mbuf *m, int force)
2188a1b9b6aSSam Leffler {
2198a1b9b6aSSam Leffler 	struct tkip_ctx *ctx = k->wk_private;
2208a1b9b6aSSam Leffler 
2215c1f7f19SSam Leffler 	if (force || (k->wk_flags & IEEE80211_KEY_SWENMIC)) {
2228a1b9b6aSSam Leffler 		struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
223b032f27cSSam Leffler 		struct ieee80211vap *vap = ctx->tc_vap;
224b032f27cSSam Leffler 		struct ieee80211com *ic = vap->iv_ic;
2254e844c94SSam Leffler 		int hdrlen;
2268a1b9b6aSSam Leffler 		uint8_t mic[IEEE80211_WEP_MICLEN];
2278a1b9b6aSSam Leffler 
228b032f27cSSam Leffler 		vap->iv_stats.is_crypto_tkipenmic++;
2294e844c94SSam Leffler 
2304e844c94SSam Leffler 		hdrlen = ieee80211_hdrspace(ic, wh);
2318a1b9b6aSSam Leffler 
2328a1b9b6aSSam Leffler 		michael_mic(ctx, k->wk_txmic,
2338a1b9b6aSSam Leffler 			m, hdrlen, m->m_pkthdr.len - hdrlen, mic);
2348a1b9b6aSSam Leffler 		return m_append(m, tkip.ic_miclen, mic);
2358a1b9b6aSSam Leffler 	}
2368a1b9b6aSSam Leffler 	return 1;
2378a1b9b6aSSam Leffler }
2388a1b9b6aSSam Leffler 
2398a1b9b6aSSam Leffler static __inline uint64_t
2408a1b9b6aSSam Leffler READ_6(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5)
2418a1b9b6aSSam Leffler {
2428a1b9b6aSSam Leffler 	uint32_t iv32 = (b0 << 0) | (b1 << 8) | (b2 << 16) | (b3 << 24);
2438a1b9b6aSSam Leffler 	uint16_t iv16 = (b4 << 0) | (b5 << 8);
2448a1b9b6aSSam Leffler 	return (((uint64_t)iv16) << 32) | iv32;
2458a1b9b6aSSam Leffler }
2468a1b9b6aSSam Leffler 
2478a1b9b6aSSam Leffler /*
2488a1b9b6aSSam Leffler  * Validate and strip privacy headers (and trailer) for a
2498a1b9b6aSSam Leffler  * received frame.  If necessary, decrypt the frame using
2508a1b9b6aSSam Leffler  * the specified key.
2518a1b9b6aSSam Leffler  */
2528a1b9b6aSSam Leffler static int
2532cc12adeSSam Leffler tkip_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen)
2548a1b9b6aSSam Leffler {
2558a1b9b6aSSam Leffler 	struct tkip_ctx *ctx = k->wk_private;
256b032f27cSSam Leffler 	struct ieee80211vap *vap = ctx->tc_vap;
2578a1b9b6aSSam Leffler 	struct ieee80211_frame *wh;
258b032f27cSSam Leffler 	uint8_t *ivp, tid;
2598a1b9b6aSSam Leffler 
2608a1b9b6aSSam Leffler 	/*
2618a1b9b6aSSam Leffler 	 * Header should have extended IV and sequence number;
2628a1b9b6aSSam Leffler 	 * verify the former and validate the latter.
2638a1b9b6aSSam Leffler 	 */
2648a1b9b6aSSam Leffler 	wh = mtod(m, struct ieee80211_frame *);
2658a1b9b6aSSam Leffler 	ivp = mtod(m, uint8_t *) + hdrlen;
2668a1b9b6aSSam Leffler 	if ((ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV) == 0) {
2678a1b9b6aSSam Leffler 		/*
2688a1b9b6aSSam Leffler 		 * No extended IV; discard frame.
2698a1b9b6aSSam Leffler 		 */
270b032f27cSSam Leffler 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
271b032f27cSSam Leffler 		    "%s", "missing ExtIV for TKIP cipher");
272b032f27cSSam Leffler 		vap->iv_stats.is_rx_tkipformat++;
2738a1b9b6aSSam Leffler 		return 0;
2748a1b9b6aSSam Leffler 	}
2758a1b9b6aSSam Leffler 	/*
2768a1b9b6aSSam Leffler 	 * Handle TKIP counter measures requirement.
2778a1b9b6aSSam Leffler 	 */
278b032f27cSSam Leffler 	if (vap->iv_flags & IEEE80211_F_COUNTERM) {
279b032f27cSSam Leffler 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
280b032f27cSSam Leffler 		    "discard frame due to countermeasures (%s)", __func__);
281b032f27cSSam Leffler 		vap->iv_stats.is_crypto_tkipcm++;
2828a1b9b6aSSam Leffler 		return 0;
2838a1b9b6aSSam Leffler 	}
2848a1b9b6aSSam Leffler 
285b032f27cSSam Leffler 	tid = ieee80211_gettid(wh);
286f287c95bSSam Leffler 	ctx->rx_rsc = READ_6(ivp[2], ivp[0], ivp[4], ivp[5], ivp[6], ivp[7]);
2875d766a09SBernhard Schmidt 	if (ctx->rx_rsc <= k->wk_keyrsc[tid] &&
2885d766a09SBernhard Schmidt 	    (k->wk_flags & IEEE80211_KEY_NOREPLAY) == 0) {
2898a1b9b6aSSam Leffler 		/*
2908a1b9b6aSSam Leffler 		 * Replay violation; notify upper layer.
2918a1b9b6aSSam Leffler 		 */
292ebaf87ebSSam Leffler 		ieee80211_notify_replay_failure(vap, wh, k, ctx->rx_rsc, tid);
293b032f27cSSam Leffler 		vap->iv_stats.is_rx_tkipreplay++;
2948a1b9b6aSSam Leffler 		return 0;
2958a1b9b6aSSam Leffler 	}
2968a1b9b6aSSam Leffler 	/*
2978a1b9b6aSSam Leffler 	 * NB: We can't update the rsc in the key until MIC is verified.
2988a1b9b6aSSam Leffler 	 *
2998a1b9b6aSSam Leffler 	 * We assume we are not preempted between doing the check above
3008a1b9b6aSSam Leffler 	 * and updating wk_keyrsc when stripping the MIC in tkip_demic.
3018a1b9b6aSSam Leffler 	 * Otherwise we might process another packet and discard it as
3028a1b9b6aSSam Leffler 	 * a replay.
3038a1b9b6aSSam Leffler 	 */
3048a1b9b6aSSam Leffler 
3058a1b9b6aSSam Leffler 	/*
3068a1b9b6aSSam Leffler 	 * Check if the device handled the decrypt in hardware.
3078a1b9b6aSSam Leffler 	 * If so we just strip the header; otherwise we need to
3088a1b9b6aSSam Leffler 	 * handle the decrypt in software.
3098a1b9b6aSSam Leffler 	 */
3105c1f7f19SSam Leffler 	if ((k->wk_flags & IEEE80211_KEY_SWDECRYPT) &&
3118a1b9b6aSSam Leffler 	    !tkip_decrypt(ctx, k, m, hdrlen))
3128a1b9b6aSSam Leffler 		return 0;
3138a1b9b6aSSam Leffler 
3148a1b9b6aSSam Leffler 	/*
3158a1b9b6aSSam Leffler 	 * Copy up 802.11 header and strip crypto bits.
3168a1b9b6aSSam Leffler 	 */
3178a1b9b6aSSam Leffler 	memmove(mtod(m, uint8_t *) + tkip.ic_header, mtod(m, void *), hdrlen);
3188a1b9b6aSSam Leffler 	m_adj(m, tkip.ic_header);
3198a1b9b6aSSam Leffler 	m_adj(m, -tkip.ic_trailer);
3208a1b9b6aSSam Leffler 
3218a1b9b6aSSam Leffler 	return 1;
3228a1b9b6aSSam Leffler }
3238a1b9b6aSSam Leffler 
3248a1b9b6aSSam Leffler /*
3258a1b9b6aSSam Leffler  * Verify and strip MIC from the frame.
3268a1b9b6aSSam Leffler  */
3278a1b9b6aSSam Leffler static int
32896d88463SSam Leffler tkip_demic(struct ieee80211_key *k, struct mbuf *m, int force)
3298a1b9b6aSSam Leffler {
3308a1b9b6aSSam Leffler 	struct tkip_ctx *ctx = k->wk_private;
331b032f27cSSam Leffler 	struct ieee80211_frame *wh;
332b032f27cSSam Leffler 	uint8_t tid;
3338a1b9b6aSSam Leffler 
334b032f27cSSam Leffler 	wh = mtod(m, struct ieee80211_frame *);
3355c1f7f19SSam Leffler 	if ((k->wk_flags & IEEE80211_KEY_SWDEMIC) || force) {
336b032f27cSSam Leffler 		struct ieee80211vap *vap = ctx->tc_vap;
337b032f27cSSam Leffler 		int hdrlen = ieee80211_hdrspace(vap->iv_ic, wh);
3388a1b9b6aSSam Leffler 		u8 mic[IEEE80211_WEP_MICLEN];
3398a1b9b6aSSam Leffler 		u8 mic0[IEEE80211_WEP_MICLEN];
3408a1b9b6aSSam Leffler 
341b032f27cSSam Leffler 		vap->iv_stats.is_crypto_tkipdemic++;
3428a1b9b6aSSam Leffler 
3438a1b9b6aSSam Leffler 		michael_mic(ctx, k->wk_rxmic,
3448a1b9b6aSSam Leffler 			m, hdrlen, m->m_pkthdr.len - (hdrlen + tkip.ic_miclen),
3458a1b9b6aSSam Leffler 			mic);
3468a1b9b6aSSam Leffler 		m_copydata(m, m->m_pkthdr.len - tkip.ic_miclen,
3478a1b9b6aSSam Leffler 			tkip.ic_miclen, mic0);
3488a1b9b6aSSam Leffler 		if (memcmp(mic, mic0, tkip.ic_miclen)) {
3498a1b9b6aSSam Leffler 			/* NB: 802.11 layer handles statistic and debug msg */
350b032f27cSSam Leffler 			ieee80211_notify_michael_failure(vap, wh,
351c1225b52SSam Leffler 				k->wk_rxkeyix != IEEE80211_KEYIX_NONE ?
352c1225b52SSam Leffler 					k->wk_rxkeyix : k->wk_keyix);
3538a1b9b6aSSam Leffler 			return 0;
3548a1b9b6aSSam Leffler 		}
3558a1b9b6aSSam Leffler 	}
3568a1b9b6aSSam Leffler 	/*
3578a1b9b6aSSam Leffler 	 * Strip MIC from the tail.
3588a1b9b6aSSam Leffler 	 */
3598a1b9b6aSSam Leffler 	m_adj(m, -tkip.ic_miclen);
3608a1b9b6aSSam Leffler 
3618a1b9b6aSSam Leffler 	/*
3628a1b9b6aSSam Leffler 	 * Ok to update rsc now that MIC has been verified.
3638a1b9b6aSSam Leffler 	 */
364b032f27cSSam Leffler 	tid = ieee80211_gettid(wh);
365b032f27cSSam Leffler 	k->wk_keyrsc[tid] = ctx->rx_rsc;
3668a1b9b6aSSam Leffler 
3678a1b9b6aSSam Leffler 	return 1;
3688a1b9b6aSSam Leffler }
3698a1b9b6aSSam Leffler 
3708a1b9b6aSSam Leffler /*
3718a1b9b6aSSam Leffler  * Host AP crypt: host-based TKIP encryption implementation for Host AP driver
3728a1b9b6aSSam Leffler  *
3738a1b9b6aSSam Leffler  * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
3748a1b9b6aSSam Leffler  *
3758a1b9b6aSSam Leffler  * This program is free software; you can redistribute it and/or modify
3768a1b9b6aSSam Leffler  * it under the terms of the GNU General Public License version 2 as
3778a1b9b6aSSam Leffler  * published by the Free Software Foundation. See README and COPYING for
3788a1b9b6aSSam Leffler  * more details.
3798a1b9b6aSSam Leffler  *
3808a1b9b6aSSam Leffler  * Alternatively, this software may be distributed under the terms of BSD
3818a1b9b6aSSam Leffler  * license.
3828a1b9b6aSSam Leffler  */
3838a1b9b6aSSam Leffler 
3848a1b9b6aSSam Leffler static const __u32 crc32_table[256] = {
3858a1b9b6aSSam Leffler 	0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
3868a1b9b6aSSam Leffler 	0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
3878a1b9b6aSSam Leffler 	0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
3888a1b9b6aSSam Leffler 	0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
3898a1b9b6aSSam Leffler 	0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
3908a1b9b6aSSam Leffler 	0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
3918a1b9b6aSSam Leffler 	0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
3928a1b9b6aSSam Leffler 	0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
3938a1b9b6aSSam Leffler 	0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
3948a1b9b6aSSam Leffler 	0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
3958a1b9b6aSSam Leffler 	0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
3968a1b9b6aSSam Leffler 	0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
3978a1b9b6aSSam Leffler 	0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
3988a1b9b6aSSam Leffler 	0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
3998a1b9b6aSSam Leffler 	0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
4008a1b9b6aSSam Leffler 	0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
4018a1b9b6aSSam Leffler 	0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
4028a1b9b6aSSam Leffler 	0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
4038a1b9b6aSSam Leffler 	0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
4048a1b9b6aSSam Leffler 	0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
4058a1b9b6aSSam Leffler 	0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
4068a1b9b6aSSam Leffler 	0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
4078a1b9b6aSSam Leffler 	0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
4088a1b9b6aSSam Leffler 	0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
4098a1b9b6aSSam Leffler 	0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
4108a1b9b6aSSam Leffler 	0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
4118a1b9b6aSSam Leffler 	0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
4128a1b9b6aSSam Leffler 	0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
4138a1b9b6aSSam Leffler 	0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
4148a1b9b6aSSam Leffler 	0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
4158a1b9b6aSSam Leffler 	0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
4168a1b9b6aSSam Leffler 	0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
4178a1b9b6aSSam Leffler 	0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
4188a1b9b6aSSam Leffler 	0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
4198a1b9b6aSSam Leffler 	0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
4208a1b9b6aSSam Leffler 	0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
4218a1b9b6aSSam Leffler 	0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
4228a1b9b6aSSam Leffler 	0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
4238a1b9b6aSSam Leffler 	0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
4248a1b9b6aSSam Leffler 	0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
4258a1b9b6aSSam Leffler 	0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
4268a1b9b6aSSam Leffler 	0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
4278a1b9b6aSSam Leffler 	0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
4288a1b9b6aSSam Leffler 	0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
4298a1b9b6aSSam Leffler 	0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
4308a1b9b6aSSam Leffler 	0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
4318a1b9b6aSSam Leffler 	0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
4328a1b9b6aSSam Leffler 	0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
4338a1b9b6aSSam Leffler 	0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
4348a1b9b6aSSam Leffler 	0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
4358a1b9b6aSSam Leffler 	0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
4368a1b9b6aSSam Leffler 	0x2d02ef8dL
4378a1b9b6aSSam Leffler };
4388a1b9b6aSSam Leffler 
4398a1b9b6aSSam Leffler static __inline u16 RotR1(u16 val)
4408a1b9b6aSSam Leffler {
4418a1b9b6aSSam Leffler 	return (val >> 1) | (val << 15);
4428a1b9b6aSSam Leffler }
4438a1b9b6aSSam Leffler 
4448a1b9b6aSSam Leffler static __inline u8 Lo8(u16 val)
4458a1b9b6aSSam Leffler {
4468a1b9b6aSSam Leffler 	return val & 0xff;
4478a1b9b6aSSam Leffler }
4488a1b9b6aSSam Leffler 
4498a1b9b6aSSam Leffler static __inline u8 Hi8(u16 val)
4508a1b9b6aSSam Leffler {
4518a1b9b6aSSam Leffler 	return val >> 8;
4528a1b9b6aSSam Leffler }
4538a1b9b6aSSam Leffler 
4548a1b9b6aSSam Leffler static __inline u16 Lo16(u32 val)
4558a1b9b6aSSam Leffler {
4568a1b9b6aSSam Leffler 	return val & 0xffff;
4578a1b9b6aSSam Leffler }
4588a1b9b6aSSam Leffler 
4598a1b9b6aSSam Leffler static __inline u16 Hi16(u32 val)
4608a1b9b6aSSam Leffler {
4618a1b9b6aSSam Leffler 	return val >> 16;
4628a1b9b6aSSam Leffler }
4638a1b9b6aSSam Leffler 
4648a1b9b6aSSam Leffler static __inline u16 Mk16(u8 hi, u8 lo)
4658a1b9b6aSSam Leffler {
4668a1b9b6aSSam Leffler 	return lo | (((u16) hi) << 8);
4678a1b9b6aSSam Leffler }
4688a1b9b6aSSam Leffler 
4698a1b9b6aSSam Leffler static __inline u16 Mk16_le(const u16 *v)
4708a1b9b6aSSam Leffler {
4718a1b9b6aSSam Leffler 	return le16toh(*v);
4728a1b9b6aSSam Leffler }
4738a1b9b6aSSam Leffler 
4748a1b9b6aSSam Leffler static const u16 Sbox[256] = {
4758a1b9b6aSSam Leffler 	0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
4768a1b9b6aSSam Leffler 	0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
4778a1b9b6aSSam Leffler 	0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
4788a1b9b6aSSam Leffler 	0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
4798a1b9b6aSSam Leffler 	0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
4808a1b9b6aSSam Leffler 	0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
4818a1b9b6aSSam Leffler 	0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
4828a1b9b6aSSam Leffler 	0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
4838a1b9b6aSSam Leffler 	0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
4848a1b9b6aSSam Leffler 	0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
4858a1b9b6aSSam Leffler 	0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
4868a1b9b6aSSam Leffler 	0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
4878a1b9b6aSSam Leffler 	0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
4888a1b9b6aSSam Leffler 	0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
4898a1b9b6aSSam Leffler 	0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
4908a1b9b6aSSam Leffler 	0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
4918a1b9b6aSSam Leffler 	0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
4928a1b9b6aSSam Leffler 	0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
4938a1b9b6aSSam Leffler 	0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
4948a1b9b6aSSam Leffler 	0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
4958a1b9b6aSSam Leffler 	0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
4968a1b9b6aSSam Leffler 	0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
4978a1b9b6aSSam Leffler 	0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
4988a1b9b6aSSam Leffler 	0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
4998a1b9b6aSSam Leffler 	0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
5008a1b9b6aSSam Leffler 	0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
5018a1b9b6aSSam Leffler 	0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
5028a1b9b6aSSam Leffler 	0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
5038a1b9b6aSSam Leffler 	0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
5048a1b9b6aSSam Leffler 	0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
5058a1b9b6aSSam Leffler 	0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
5068a1b9b6aSSam Leffler 	0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
5078a1b9b6aSSam Leffler };
5088a1b9b6aSSam Leffler 
5098a1b9b6aSSam Leffler static __inline u16 _S_(u16 v)
5108a1b9b6aSSam Leffler {
5118a1b9b6aSSam Leffler 	u16 t = Sbox[Hi8(v)];
5128a1b9b6aSSam Leffler 	return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8));
5138a1b9b6aSSam Leffler }
5148a1b9b6aSSam Leffler 
5158a1b9b6aSSam Leffler #define PHASE1_LOOP_COUNT 8
5168a1b9b6aSSam Leffler 
5178a1b9b6aSSam Leffler static void tkip_mixing_phase1(u16 *TTAK, const u8 *TK, const u8 *TA, u32 IV32)
5188a1b9b6aSSam Leffler {
5198a1b9b6aSSam Leffler 	int i, j;
5208a1b9b6aSSam Leffler 
5218a1b9b6aSSam Leffler 	/* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */
5228a1b9b6aSSam Leffler 	TTAK[0] = Lo16(IV32);
5238a1b9b6aSSam Leffler 	TTAK[1] = Hi16(IV32);
5248a1b9b6aSSam Leffler 	TTAK[2] = Mk16(TA[1], TA[0]);
5258a1b9b6aSSam Leffler 	TTAK[3] = Mk16(TA[3], TA[2]);
5268a1b9b6aSSam Leffler 	TTAK[4] = Mk16(TA[5], TA[4]);
5278a1b9b6aSSam Leffler 
5288a1b9b6aSSam Leffler 	for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
5298a1b9b6aSSam Leffler 		j = 2 * (i & 1);
5308a1b9b6aSSam Leffler 		TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j]));
5318a1b9b6aSSam Leffler 		TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j]));
5328a1b9b6aSSam Leffler 		TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j]));
5338a1b9b6aSSam Leffler 		TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j]));
5348a1b9b6aSSam Leffler 		TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i;
5358a1b9b6aSSam Leffler 	}
5368a1b9b6aSSam Leffler }
5378a1b9b6aSSam Leffler 
5388a1b9b6aSSam Leffler #ifndef _BYTE_ORDER
5398a1b9b6aSSam Leffler #error "Don't know native byte order"
5408a1b9b6aSSam Leffler #endif
5418a1b9b6aSSam Leffler 
5428a1b9b6aSSam Leffler static void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK,
5438a1b9b6aSSam Leffler 			       u16 IV16)
5448a1b9b6aSSam Leffler {
5458a1b9b6aSSam Leffler 	/* Make temporary area overlap WEP seed so that the final copy can be
5468a1b9b6aSSam Leffler 	 * avoided on little endian hosts. */
5478a1b9b6aSSam Leffler 	u16 *PPK = (u16 *) &WEPSeed[4];
5488a1b9b6aSSam Leffler 
5498a1b9b6aSSam Leffler 	/* Step 1 - make copy of TTAK and bring in TSC */
5508a1b9b6aSSam Leffler 	PPK[0] = TTAK[0];
5518a1b9b6aSSam Leffler 	PPK[1] = TTAK[1];
5528a1b9b6aSSam Leffler 	PPK[2] = TTAK[2];
5538a1b9b6aSSam Leffler 	PPK[3] = TTAK[3];
5548a1b9b6aSSam Leffler 	PPK[4] = TTAK[4];
5558a1b9b6aSSam Leffler 	PPK[5] = TTAK[4] + IV16;
5568a1b9b6aSSam Leffler 
5578a1b9b6aSSam Leffler 	/* Step 2 - 96-bit bijective mixing using S-box */
5588a1b9b6aSSam Leffler 	PPK[0] += _S_(PPK[5] ^ Mk16_le((const u16 *) &TK[0]));
5598a1b9b6aSSam Leffler 	PPK[1] += _S_(PPK[0] ^ Mk16_le((const u16 *) &TK[2]));
5608a1b9b6aSSam Leffler 	PPK[2] += _S_(PPK[1] ^ Mk16_le((const u16 *) &TK[4]));
5618a1b9b6aSSam Leffler 	PPK[3] += _S_(PPK[2] ^ Mk16_le((const u16 *) &TK[6]));
5628a1b9b6aSSam Leffler 	PPK[4] += _S_(PPK[3] ^ Mk16_le((const u16 *) &TK[8]));
5638a1b9b6aSSam Leffler 	PPK[5] += _S_(PPK[4] ^ Mk16_le((const u16 *) &TK[10]));
5648a1b9b6aSSam Leffler 
5658a1b9b6aSSam Leffler 	PPK[0] += RotR1(PPK[5] ^ Mk16_le((const u16 *) &TK[12]));
5668a1b9b6aSSam Leffler 	PPK[1] += RotR1(PPK[0] ^ Mk16_le((const u16 *) &TK[14]));
5678a1b9b6aSSam Leffler 	PPK[2] += RotR1(PPK[1]);
5688a1b9b6aSSam Leffler 	PPK[3] += RotR1(PPK[2]);
5698a1b9b6aSSam Leffler 	PPK[4] += RotR1(PPK[3]);
5708a1b9b6aSSam Leffler 	PPK[5] += RotR1(PPK[4]);
5718a1b9b6aSSam Leffler 
5728a1b9b6aSSam Leffler 	/* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value
5738a1b9b6aSSam Leffler 	 * WEPSeed[0..2] is transmitted as WEP IV */
5748a1b9b6aSSam Leffler 	WEPSeed[0] = Hi8(IV16);
5758a1b9b6aSSam Leffler 	WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F;
5768a1b9b6aSSam Leffler 	WEPSeed[2] = Lo8(IV16);
5778a1b9b6aSSam Leffler 	WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((const u16 *) &TK[0])) >> 1);
5788a1b9b6aSSam Leffler 
5798a1b9b6aSSam Leffler #if _BYTE_ORDER == _BIG_ENDIAN
5808a1b9b6aSSam Leffler 	{
5818a1b9b6aSSam Leffler 		int i;
5828a1b9b6aSSam Leffler 		for (i = 0; i < 6; i++)
5838a1b9b6aSSam Leffler 			PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8);
5848a1b9b6aSSam Leffler 	}
5858a1b9b6aSSam Leffler #endif
5868a1b9b6aSSam Leffler }
5878a1b9b6aSSam Leffler 
5888a1b9b6aSSam Leffler static void
5898a1b9b6aSSam Leffler wep_encrypt(u8 *key, struct mbuf *m0, u_int off, size_t data_len,
5908a1b9b6aSSam Leffler 	uint8_t icv[IEEE80211_WEP_CRCLEN])
5918a1b9b6aSSam Leffler {
5928a1b9b6aSSam Leffler 	u32 i, j, k, crc;
5938a1b9b6aSSam Leffler 	size_t buflen;
5948a1b9b6aSSam Leffler 	u8 S[256];
5958a1b9b6aSSam Leffler 	u8 *pos;
5968a1b9b6aSSam Leffler 	struct mbuf *m;
5978a1b9b6aSSam Leffler #define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
5988a1b9b6aSSam Leffler 
5998a1b9b6aSSam Leffler 	/* Setup RC4 state */
6008a1b9b6aSSam Leffler 	for (i = 0; i < 256; i++)
6018a1b9b6aSSam Leffler 		S[i] = i;
6028a1b9b6aSSam Leffler 	j = 0;
6038a1b9b6aSSam Leffler 	for (i = 0; i < 256; i++) {
6048a1b9b6aSSam Leffler 		j = (j + S[i] + key[i & 0x0f]) & 0xff;
6058a1b9b6aSSam Leffler 		S_SWAP(i, j);
6068a1b9b6aSSam Leffler 	}
6078a1b9b6aSSam Leffler 
6088a1b9b6aSSam Leffler 	/* Compute CRC32 over unencrypted data and apply RC4 to data */
6098a1b9b6aSSam Leffler 	crc = ~0;
6108a1b9b6aSSam Leffler 	i = j = 0;
6118a1b9b6aSSam Leffler 	m = m0;
6128a1b9b6aSSam Leffler 	pos = mtod(m, uint8_t *) + off;
6138a1b9b6aSSam Leffler 	buflen = m->m_len - off;
6148a1b9b6aSSam Leffler 	for (;;) {
6158a1b9b6aSSam Leffler 		if (buflen > data_len)
6168a1b9b6aSSam Leffler 			buflen = data_len;
6178a1b9b6aSSam Leffler 		data_len -= buflen;
6188a1b9b6aSSam Leffler 		for (k = 0; k < buflen; k++) {
6198a1b9b6aSSam Leffler 			crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8);
6208a1b9b6aSSam Leffler 			i = (i + 1) & 0xff;
6218a1b9b6aSSam Leffler 			j = (j + S[i]) & 0xff;
6228a1b9b6aSSam Leffler 			S_SWAP(i, j);
6238a1b9b6aSSam Leffler 			*pos++ ^= S[(S[i] + S[j]) & 0xff];
6248a1b9b6aSSam Leffler 		}
6258a1b9b6aSSam Leffler 		m = m->m_next;
6268a1b9b6aSSam Leffler 		if (m == NULL) {
6278a1b9b6aSSam Leffler 			KASSERT(data_len == 0,
62816574882SSam Leffler 			    ("out of buffers with data_len %zu\n", data_len));
6298a1b9b6aSSam Leffler 			break;
6308a1b9b6aSSam Leffler 		}
6318a1b9b6aSSam Leffler 		pos = mtod(m, uint8_t *);
6328a1b9b6aSSam Leffler 		buflen = m->m_len;
6338a1b9b6aSSam Leffler 	}
6348a1b9b6aSSam Leffler 	crc = ~crc;
6358a1b9b6aSSam Leffler 
6368a1b9b6aSSam Leffler 	/* Append little-endian CRC32 and encrypt it to produce ICV */
6378a1b9b6aSSam Leffler 	icv[0] = crc;
6388a1b9b6aSSam Leffler 	icv[1] = crc >> 8;
6398a1b9b6aSSam Leffler 	icv[2] = crc >> 16;
6408a1b9b6aSSam Leffler 	icv[3] = crc >> 24;
6418a1b9b6aSSam Leffler 	for (k = 0; k < IEEE80211_WEP_CRCLEN; k++) {
6428a1b9b6aSSam Leffler 		i = (i + 1) & 0xff;
6438a1b9b6aSSam Leffler 		j = (j + S[i]) & 0xff;
6448a1b9b6aSSam Leffler 		S_SWAP(i, j);
6458a1b9b6aSSam Leffler 		icv[k] ^= S[(S[i] + S[j]) & 0xff];
6468a1b9b6aSSam Leffler 	}
6478a1b9b6aSSam Leffler }
6488a1b9b6aSSam Leffler 
6498a1b9b6aSSam Leffler static int
6508a1b9b6aSSam Leffler wep_decrypt(u8 *key, struct mbuf *m, u_int off, size_t data_len)
6518a1b9b6aSSam Leffler {
6528a1b9b6aSSam Leffler 	u32 i, j, k, crc;
6538a1b9b6aSSam Leffler 	u8 S[256];
6548a1b9b6aSSam Leffler 	u8 *pos, icv[4];
6558a1b9b6aSSam Leffler 	size_t buflen;
6568a1b9b6aSSam Leffler 
6578a1b9b6aSSam Leffler 	/* Setup RC4 state */
6588a1b9b6aSSam Leffler 	for (i = 0; i < 256; i++)
6598a1b9b6aSSam Leffler 		S[i] = i;
6608a1b9b6aSSam Leffler 	j = 0;
6618a1b9b6aSSam Leffler 	for (i = 0; i < 256; i++) {
6628a1b9b6aSSam Leffler 		j = (j + S[i] + key[i & 0x0f]) & 0xff;
6638a1b9b6aSSam Leffler 		S_SWAP(i, j);
6648a1b9b6aSSam Leffler 	}
6658a1b9b6aSSam Leffler 
6668a1b9b6aSSam Leffler 	/* Apply RC4 to data and compute CRC32 over decrypted data */
6678a1b9b6aSSam Leffler 	crc = ~0;
6688a1b9b6aSSam Leffler 	i = j = 0;
6698a1b9b6aSSam Leffler 	pos = mtod(m, uint8_t *) + off;
6708a1b9b6aSSam Leffler 	buflen = m->m_len - off;
6718a1b9b6aSSam Leffler 	for (;;) {
6728a1b9b6aSSam Leffler 		if (buflen > data_len)
6738a1b9b6aSSam Leffler 			buflen = data_len;
6748a1b9b6aSSam Leffler 		data_len -= buflen;
6758a1b9b6aSSam Leffler 		for (k = 0; k < buflen; k++) {
6768a1b9b6aSSam Leffler 			i = (i + 1) & 0xff;
6778a1b9b6aSSam Leffler 			j = (j + S[i]) & 0xff;
6788a1b9b6aSSam Leffler 			S_SWAP(i, j);
6798a1b9b6aSSam Leffler 			*pos ^= S[(S[i] + S[j]) & 0xff];
6808a1b9b6aSSam Leffler 			crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8);
6818a1b9b6aSSam Leffler 			pos++;
6828a1b9b6aSSam Leffler 		}
6838a1b9b6aSSam Leffler 		m = m->m_next;
6848a1b9b6aSSam Leffler 		if (m == NULL) {
6858a1b9b6aSSam Leffler 			KASSERT(data_len == 0,
68616574882SSam Leffler 			    ("out of buffers with data_len %zu\n", data_len));
6878a1b9b6aSSam Leffler 			break;
6888a1b9b6aSSam Leffler 		}
6898a1b9b6aSSam Leffler 		pos = mtod(m, uint8_t *);
6908a1b9b6aSSam Leffler 		buflen = m->m_len;
6918a1b9b6aSSam Leffler 	}
6928a1b9b6aSSam Leffler 	crc = ~crc;
6938a1b9b6aSSam Leffler 
6948a1b9b6aSSam Leffler 	/* Encrypt little-endian CRC32 and verify that it matches with the
6958a1b9b6aSSam Leffler 	 * received ICV */
6968a1b9b6aSSam Leffler 	icv[0] = crc;
6978a1b9b6aSSam Leffler 	icv[1] = crc >> 8;
6988a1b9b6aSSam Leffler 	icv[2] = crc >> 16;
6998a1b9b6aSSam Leffler 	icv[3] = crc >> 24;
7008a1b9b6aSSam Leffler 	for (k = 0; k < 4; k++) {
7018a1b9b6aSSam Leffler 		i = (i + 1) & 0xff;
7028a1b9b6aSSam Leffler 		j = (j + S[i]) & 0xff;
7038a1b9b6aSSam Leffler 		S_SWAP(i, j);
7048a1b9b6aSSam Leffler 		if ((icv[k] ^ S[(S[i] + S[j]) & 0xff]) != *pos++) {
7058a1b9b6aSSam Leffler 			/* ICV mismatch - drop frame */
7068a1b9b6aSSam Leffler 			return -1;
7078a1b9b6aSSam Leffler 		}
7088a1b9b6aSSam Leffler 	}
7098a1b9b6aSSam Leffler 
7108a1b9b6aSSam Leffler 	return 0;
7118a1b9b6aSSam Leffler }
7128a1b9b6aSSam Leffler 
7138a1b9b6aSSam Leffler 
7148a1b9b6aSSam Leffler static __inline u32 rotl(u32 val, int bits)
7158a1b9b6aSSam Leffler {
7168a1b9b6aSSam Leffler 	return (val << bits) | (val >> (32 - bits));
7178a1b9b6aSSam Leffler }
7188a1b9b6aSSam Leffler 
7198a1b9b6aSSam Leffler 
7208a1b9b6aSSam Leffler static __inline u32 rotr(u32 val, int bits)
7218a1b9b6aSSam Leffler {
7228a1b9b6aSSam Leffler 	return (val >> bits) | (val << (32 - bits));
7238a1b9b6aSSam Leffler }
7248a1b9b6aSSam Leffler 
7258a1b9b6aSSam Leffler 
7268a1b9b6aSSam Leffler static __inline u32 xswap(u32 val)
7278a1b9b6aSSam Leffler {
7288a1b9b6aSSam Leffler 	return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8);
7298a1b9b6aSSam Leffler }
7308a1b9b6aSSam Leffler 
7318a1b9b6aSSam Leffler 
7328a1b9b6aSSam Leffler #define michael_block(l, r)	\
7338a1b9b6aSSam Leffler do {				\
7348a1b9b6aSSam Leffler 	r ^= rotl(l, 17);	\
7358a1b9b6aSSam Leffler 	l += r;			\
7368a1b9b6aSSam Leffler 	r ^= xswap(l);		\
7378a1b9b6aSSam Leffler 	l += r;			\
7388a1b9b6aSSam Leffler 	r ^= rotl(l, 3);	\
7398a1b9b6aSSam Leffler 	l += r;			\
7408a1b9b6aSSam Leffler 	r ^= rotr(l, 2);	\
7418a1b9b6aSSam Leffler 	l += r;			\
7428a1b9b6aSSam Leffler } while (0)
7438a1b9b6aSSam Leffler 
7448a1b9b6aSSam Leffler 
7458a1b9b6aSSam Leffler static __inline u32 get_le32_split(u8 b0, u8 b1, u8 b2, u8 b3)
7468a1b9b6aSSam Leffler {
7478a1b9b6aSSam Leffler 	return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
7488a1b9b6aSSam Leffler }
7498a1b9b6aSSam Leffler 
7508a1b9b6aSSam Leffler static __inline u32 get_le32(const u8 *p)
7518a1b9b6aSSam Leffler {
7528a1b9b6aSSam Leffler 	return get_le32_split(p[0], p[1], p[2], p[3]);
7538a1b9b6aSSam Leffler }
7548a1b9b6aSSam Leffler 
7558a1b9b6aSSam Leffler 
7568a1b9b6aSSam Leffler static __inline void put_le32(u8 *p, u32 v)
7578a1b9b6aSSam Leffler {
7588a1b9b6aSSam Leffler 	p[0] = v;
7598a1b9b6aSSam Leffler 	p[1] = v >> 8;
7608a1b9b6aSSam Leffler 	p[2] = v >> 16;
7618a1b9b6aSSam Leffler 	p[3] = v >> 24;
7628a1b9b6aSSam Leffler }
7638a1b9b6aSSam Leffler 
7648a1b9b6aSSam Leffler /*
7658a1b9b6aSSam Leffler  * Craft pseudo header used to calculate the MIC.
7668a1b9b6aSSam Leffler  */
7678a1b9b6aSSam Leffler static void
7688a1b9b6aSSam Leffler michael_mic_hdr(const struct ieee80211_frame *wh0, uint8_t hdr[16])
7698a1b9b6aSSam Leffler {
7708a1b9b6aSSam Leffler 	const struct ieee80211_frame_addr4 *wh =
7718a1b9b6aSSam Leffler 		(const struct ieee80211_frame_addr4 *) wh0;
7728a1b9b6aSSam Leffler 
7738a1b9b6aSSam Leffler 	switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
7748a1b9b6aSSam Leffler 	case IEEE80211_FC1_DIR_NODS:
7758a1b9b6aSSam Leffler 		IEEE80211_ADDR_COPY(hdr, wh->i_addr1); /* DA */
7768a1b9b6aSSam Leffler 		IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr2);
7778a1b9b6aSSam Leffler 		break;
7788a1b9b6aSSam Leffler 	case IEEE80211_FC1_DIR_TODS:
7798a1b9b6aSSam Leffler 		IEEE80211_ADDR_COPY(hdr, wh->i_addr3); /* DA */
7808a1b9b6aSSam Leffler 		IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr2);
7818a1b9b6aSSam Leffler 		break;
7828a1b9b6aSSam Leffler 	case IEEE80211_FC1_DIR_FROMDS:
7838a1b9b6aSSam Leffler 		IEEE80211_ADDR_COPY(hdr, wh->i_addr1); /* DA */
7848a1b9b6aSSam Leffler 		IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr3);
7858a1b9b6aSSam Leffler 		break;
7868a1b9b6aSSam Leffler 	case IEEE80211_FC1_DIR_DSTODS:
7878a1b9b6aSSam Leffler 		IEEE80211_ADDR_COPY(hdr, wh->i_addr3); /* DA */
7888a1b9b6aSSam Leffler 		IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr4);
7898a1b9b6aSSam Leffler 		break;
7908a1b9b6aSSam Leffler 	}
7918a1b9b6aSSam Leffler 
792ecca7ea2SSam Leffler 	if (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) {
793ecca7ea2SSam Leffler 		const struct ieee80211_qosframe *qwh =
794ecca7ea2SSam Leffler 			(const struct ieee80211_qosframe *) wh;
795ecca7ea2SSam Leffler 		hdr[12] = qwh->i_qos[0] & IEEE80211_QOS_TID;
796ecca7ea2SSam Leffler 	} else
797ecca7ea2SSam Leffler 		hdr[12] = 0;
7988a1b9b6aSSam Leffler 	hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */
7998a1b9b6aSSam Leffler }
8008a1b9b6aSSam Leffler 
8018a1b9b6aSSam Leffler static void
8028a1b9b6aSSam Leffler michael_mic(struct tkip_ctx *ctx, const u8 *key,
8038a1b9b6aSSam Leffler 	struct mbuf *m, u_int off, size_t data_len,
8048a1b9b6aSSam Leffler 	u8 mic[IEEE80211_WEP_MICLEN])
8058a1b9b6aSSam Leffler {
8068a1b9b6aSSam Leffler 	uint8_t hdr[16];
8078a1b9b6aSSam Leffler 	u32 l, r;
8088a1b9b6aSSam Leffler 	const uint8_t *data;
8098a1b9b6aSSam Leffler 	u_int space;
8108a1b9b6aSSam Leffler 
8118a1b9b6aSSam Leffler 	michael_mic_hdr(mtod(m, struct ieee80211_frame *), hdr);
8128a1b9b6aSSam Leffler 
8138a1b9b6aSSam Leffler 	l = get_le32(key);
8148a1b9b6aSSam Leffler 	r = get_le32(key + 4);
8158a1b9b6aSSam Leffler 
8168a1b9b6aSSam Leffler 	/* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */
8178a1b9b6aSSam Leffler 	l ^= get_le32(hdr);
8188a1b9b6aSSam Leffler 	michael_block(l, r);
8198a1b9b6aSSam Leffler 	l ^= get_le32(&hdr[4]);
8208a1b9b6aSSam Leffler 	michael_block(l, r);
8218a1b9b6aSSam Leffler 	l ^= get_le32(&hdr[8]);
8228a1b9b6aSSam Leffler 	michael_block(l, r);
8238a1b9b6aSSam Leffler 	l ^= get_le32(&hdr[12]);
8248a1b9b6aSSam Leffler 	michael_block(l, r);
8258a1b9b6aSSam Leffler 
8268a1b9b6aSSam Leffler 	/* first buffer has special handling */
8278a1b9b6aSSam Leffler 	data = mtod(m, const uint8_t *) + off;
8288a1b9b6aSSam Leffler 	space = m->m_len - off;
8298a1b9b6aSSam Leffler 	for (;;) {
8308a1b9b6aSSam Leffler 		if (space > data_len)
8318a1b9b6aSSam Leffler 			space = data_len;
8328a1b9b6aSSam Leffler 		/* collect 32-bit blocks from current buffer */
8338a1b9b6aSSam Leffler 		while (space >= sizeof(uint32_t)) {
8348a1b9b6aSSam Leffler 			l ^= get_le32(data);
8358a1b9b6aSSam Leffler 			michael_block(l, r);
8368a1b9b6aSSam Leffler 			data += sizeof(uint32_t), space -= sizeof(uint32_t);
8378a1b9b6aSSam Leffler 			data_len -= sizeof(uint32_t);
8388a1b9b6aSSam Leffler 		}
83902a1ebb4SSam Leffler 		/*
84002a1ebb4SSam Leffler 		 * NB: when space is zero we make one more trip around
84102a1ebb4SSam Leffler 		 * the loop to advance to the next mbuf where there is
84202a1ebb4SSam Leffler 		 * data.  This handles the case where there are 4*n
84302a1ebb4SSam Leffler 		 * bytes in an mbuf followed by <4 bytes in a later mbuf.
84402a1ebb4SSam Leffler 		 * By making an extra trip we'll drop out of the loop
84502a1ebb4SSam Leffler 		 * with m pointing at the mbuf with 3 bytes and space
84602a1ebb4SSam Leffler 		 * set as required by the remainder handling below.
84702a1ebb4SSam Leffler 		 */
84802a1ebb4SSam Leffler 		if (data_len == 0 ||
84902a1ebb4SSam Leffler 		    (data_len < sizeof(uint32_t) && space != 0))
8508a1b9b6aSSam Leffler 			break;
8518a1b9b6aSSam Leffler 		m = m->m_next;
8528a1b9b6aSSam Leffler 		if (m == NULL) {
85316574882SSam Leffler 			KASSERT(0, ("out of data, data_len %zu\n", data_len));
8548a1b9b6aSSam Leffler 			break;
8558a1b9b6aSSam Leffler 		}
8568a1b9b6aSSam Leffler 		if (space != 0) {
8578a1b9b6aSSam Leffler 			const uint8_t *data_next;
8588a1b9b6aSSam Leffler 			/*
8598a1b9b6aSSam Leffler 			 * Block straddles buffers, split references.
8608a1b9b6aSSam Leffler 			 */
8618a1b9b6aSSam Leffler 			data_next = mtod(m, const uint8_t *);
8628a1b9b6aSSam Leffler 			KASSERT(m->m_len >= sizeof(uint32_t) - space,
8638a1b9b6aSSam Leffler 				("not enough data in following buffer, "
86416574882SSam Leffler 				"m_len %u need %zu\n", m->m_len,
8658a1b9b6aSSam Leffler 				sizeof(uint32_t) - space));
8668a1b9b6aSSam Leffler 			switch (space) {
8678a1b9b6aSSam Leffler 			case 1:
8688a1b9b6aSSam Leffler 				l ^= get_le32_split(data[0], data_next[0],
8698a1b9b6aSSam Leffler 					data_next[1], data_next[2]);
8708a1b9b6aSSam Leffler 				data = data_next + 3;
8718a1b9b6aSSam Leffler 				space = m->m_len - 3;
8728a1b9b6aSSam Leffler 				break;
8738a1b9b6aSSam Leffler 			case 2:
8748a1b9b6aSSam Leffler 				l ^= get_le32_split(data[0], data[1],
8758a1b9b6aSSam Leffler 					data_next[0], data_next[1]);
8768a1b9b6aSSam Leffler 				data = data_next + 2;
8778a1b9b6aSSam Leffler 				space = m->m_len - 2;
8788a1b9b6aSSam Leffler 				break;
8798a1b9b6aSSam Leffler 			case 3:
8808a1b9b6aSSam Leffler 				l ^= get_le32_split(data[0], data[1],
8818a1b9b6aSSam Leffler 					data[2], data_next[0]);
8828a1b9b6aSSam Leffler 				data = data_next + 1;
8838a1b9b6aSSam Leffler 				space = m->m_len - 1;
8848a1b9b6aSSam Leffler 				break;
8858a1b9b6aSSam Leffler 			}
8868a1b9b6aSSam Leffler 			michael_block(l, r);
8878a1b9b6aSSam Leffler 			data_len -= sizeof(uint32_t);
8888a1b9b6aSSam Leffler 		} else {
8898a1b9b6aSSam Leffler 			/*
8908a1b9b6aSSam Leffler 			 * Setup for next buffer.
8918a1b9b6aSSam Leffler 			 */
8928a1b9b6aSSam Leffler 			data = mtod(m, const uint8_t *);
8938a1b9b6aSSam Leffler 			space = m->m_len;
8948a1b9b6aSSam Leffler 		}
8958a1b9b6aSSam Leffler 	}
89602a1ebb4SSam Leffler 	/*
89702a1ebb4SSam Leffler 	 * Catch degenerate cases like mbuf[4*n+1 bytes] followed by
89802a1ebb4SSam Leffler 	 * mbuf[2 bytes].  I don't believe these should happen; if they
89902a1ebb4SSam Leffler 	 * do then we'll need more involved logic.
90002a1ebb4SSam Leffler 	 */
90102a1ebb4SSam Leffler 	KASSERT(data_len <= space,
9022bc01c3aSTai-hwa Liang 	    ("not enough data, data_len %zu space %u\n", data_len, space));
90302a1ebb4SSam Leffler 
9048a1b9b6aSSam Leffler 	/* Last block and padding (0x5a, 4..7 x 0) */
9058a1b9b6aSSam Leffler 	switch (data_len) {
9068a1b9b6aSSam Leffler 	case 0:
9078a1b9b6aSSam Leffler 		l ^= get_le32_split(0x5a, 0, 0, 0);
9088a1b9b6aSSam Leffler 		break;
9098a1b9b6aSSam Leffler 	case 1:
9108a1b9b6aSSam Leffler 		l ^= get_le32_split(data[0], 0x5a, 0, 0);
9118a1b9b6aSSam Leffler 		break;
9128a1b9b6aSSam Leffler 	case 2:
9138a1b9b6aSSam Leffler 		l ^= get_le32_split(data[0], data[1], 0x5a, 0);
9148a1b9b6aSSam Leffler 		break;
9158a1b9b6aSSam Leffler 	case 3:
9168a1b9b6aSSam Leffler 		l ^= get_le32_split(data[0], data[1], data[2], 0x5a);
9178a1b9b6aSSam Leffler 		break;
9188a1b9b6aSSam Leffler 	}
9198a1b9b6aSSam Leffler 	michael_block(l, r);
9208a1b9b6aSSam Leffler 	/* l ^= 0; */
9218a1b9b6aSSam Leffler 	michael_block(l, r);
9228a1b9b6aSSam Leffler 
9238a1b9b6aSSam Leffler 	put_le32(mic, l);
9248a1b9b6aSSam Leffler 	put_le32(mic + 4, r);
9258a1b9b6aSSam Leffler }
9268a1b9b6aSSam Leffler 
9278a1b9b6aSSam Leffler static int
9288a1b9b6aSSam Leffler tkip_encrypt(struct tkip_ctx *ctx, struct ieee80211_key *key,
9298a1b9b6aSSam Leffler 	struct mbuf *m, int hdrlen)
9308a1b9b6aSSam Leffler {
9318a1b9b6aSSam Leffler 	struct ieee80211_frame *wh;
9328a1b9b6aSSam Leffler 	uint8_t icv[IEEE80211_WEP_CRCLEN];
9338a1b9b6aSSam Leffler 
934b032f27cSSam Leffler 	ctx->tc_vap->iv_stats.is_crypto_tkip++;
9358a1b9b6aSSam Leffler 
9368a1b9b6aSSam Leffler 	wh = mtod(m, struct ieee80211_frame *);
9378a1b9b6aSSam Leffler 	if (!ctx->tx_phase1_done) {
9388a1b9b6aSSam Leffler 		tkip_mixing_phase1(ctx->tx_ttak, key->wk_key, wh->i_addr2,
9398a1b9b6aSSam Leffler 				   (u32)(key->wk_keytsc >> 16));
9408a1b9b6aSSam Leffler 		ctx->tx_phase1_done = 1;
9418a1b9b6aSSam Leffler 	}
9428a1b9b6aSSam Leffler 	tkip_mixing_phase2(ctx->tx_rc4key, key->wk_key, ctx->tx_ttak,
9438a1b9b6aSSam Leffler 		(u16) key->wk_keytsc);
9448a1b9b6aSSam Leffler 
9458a1b9b6aSSam Leffler 	wep_encrypt(ctx->tx_rc4key,
9468a1b9b6aSSam Leffler 		m, hdrlen + tkip.ic_header,
9478a1b9b6aSSam Leffler 		m->m_pkthdr.len - (hdrlen + tkip.ic_header),
9488a1b9b6aSSam Leffler 		icv);
9498a1b9b6aSSam Leffler 	(void) m_append(m, IEEE80211_WEP_CRCLEN, icv);	/* XXX check return */
9508a1b9b6aSSam Leffler 
951f287c95bSSam Leffler 	key->wk_keytsc++;
9528a1b9b6aSSam Leffler 	if ((u16)(key->wk_keytsc) == 0)
9538a1b9b6aSSam Leffler 		ctx->tx_phase1_done = 0;
9548a1b9b6aSSam Leffler 	return 1;
9558a1b9b6aSSam Leffler }
9568a1b9b6aSSam Leffler 
9578a1b9b6aSSam Leffler static int
9588a1b9b6aSSam Leffler tkip_decrypt(struct tkip_ctx *ctx, struct ieee80211_key *key,
9598a1b9b6aSSam Leffler 	struct mbuf *m, int hdrlen)
9608a1b9b6aSSam Leffler {
9618a1b9b6aSSam Leffler 	struct ieee80211_frame *wh;
962b032f27cSSam Leffler 	struct ieee80211vap *vap = ctx->tc_vap;
9638a1b9b6aSSam Leffler 	u32 iv32;
9648a1b9b6aSSam Leffler 	u16 iv16;
965b032f27cSSam Leffler 	u8 tid;
9668a1b9b6aSSam Leffler 
967b032f27cSSam Leffler 	vap->iv_stats.is_crypto_tkip++;
9688a1b9b6aSSam Leffler 
9698a1b9b6aSSam Leffler 	wh = mtod(m, struct ieee80211_frame *);
9708a1b9b6aSSam Leffler 	/* NB: tkip_decap already verified header and left seq in rx_rsc */
9718a1b9b6aSSam Leffler 	iv16 = (u16) ctx->rx_rsc;
9728a1b9b6aSSam Leffler 	iv32 = (u32) (ctx->rx_rsc >> 16);
9738a1b9b6aSSam Leffler 
974b032f27cSSam Leffler 	tid = ieee80211_gettid(wh);
975b032f27cSSam Leffler 	if (iv32 != (u32)(key->wk_keyrsc[tid] >> 16) || !ctx->rx_phase1_done) {
9768a1b9b6aSSam Leffler 		tkip_mixing_phase1(ctx->rx_ttak, key->wk_key,
9778a1b9b6aSSam Leffler 			wh->i_addr2, iv32);
9788a1b9b6aSSam Leffler 		ctx->rx_phase1_done = 1;
9798a1b9b6aSSam Leffler 	}
9808a1b9b6aSSam Leffler 	tkip_mixing_phase2(ctx->rx_rc4key, key->wk_key, ctx->rx_ttak, iv16);
9818a1b9b6aSSam Leffler 
9828a1b9b6aSSam Leffler 	/* NB: m is unstripped; deduct headers + ICV to get payload */
9838a1b9b6aSSam Leffler 	if (wep_decrypt(ctx->rx_rc4key,
9848a1b9b6aSSam Leffler 		m, hdrlen + tkip.ic_header,
9858a1b9b6aSSam Leffler 	        m->m_pkthdr.len - (hdrlen + tkip.ic_header + tkip.ic_trailer))) {
986b032f27cSSam Leffler 		if (iv32 != (u32)(key->wk_keyrsc[tid] >> 16)) {
9878a1b9b6aSSam Leffler 			/* Previously cached Phase1 result was already lost, so
9888a1b9b6aSSam Leffler 			 * it needs to be recalculated for the next packet. */
9898a1b9b6aSSam Leffler 			ctx->rx_phase1_done = 0;
9908a1b9b6aSSam Leffler 		}
991b032f27cSSam Leffler 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
992b032f27cSSam Leffler 		    "%s", "TKIP ICV mismatch on decrypt");
993b032f27cSSam Leffler 		vap->iv_stats.is_rx_tkipicv++;
9948a1b9b6aSSam Leffler 		return 0;
9958a1b9b6aSSam Leffler 	}
9968a1b9b6aSSam Leffler 	return 1;
9978a1b9b6aSSam Leffler }
9988a1b9b6aSSam Leffler 
9998a1b9b6aSSam Leffler /*
10008a1b9b6aSSam Leffler  * Module glue.
10018a1b9b6aSSam Leffler  */
100268e8e04eSSam Leffler IEEE80211_CRYPTO_MODULE(tkip, 1);
1003