xref: /freebsd-src/sys/net80211/ieee80211_crypto_tkip.c (revision 37e54466cf7a7c60f3d57c23c09b832db876e2fc)
18a1b9b6aSSam Leffler /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni  *
4b032f27cSSam Leffler  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
58a1b9b6aSSam Leffler  * All rights reserved.
68a1b9b6aSSam Leffler  *
78a1b9b6aSSam Leffler  * Redistribution and use in source and binary forms, with or without
88a1b9b6aSSam Leffler  * modification, are permitted provided that the following conditions
98a1b9b6aSSam Leffler  * are met:
108a1b9b6aSSam Leffler  * 1. Redistributions of source code must retain the above copyright
118a1b9b6aSSam Leffler  *    notice, this list of conditions and the following disclaimer.
128a1b9b6aSSam Leffler  * 2. Redistributions in binary form must reproduce the above copyright
138a1b9b6aSSam Leffler  *    notice, this list of conditions and the following disclaimer in the
148a1b9b6aSSam Leffler  *    documentation and/or other materials provided with the distribution.
158a1b9b6aSSam Leffler  *
168a1b9b6aSSam Leffler  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
178a1b9b6aSSam Leffler  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
188a1b9b6aSSam Leffler  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
198a1b9b6aSSam Leffler  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
208a1b9b6aSSam Leffler  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
218a1b9b6aSSam Leffler  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
228a1b9b6aSSam Leffler  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
238a1b9b6aSSam Leffler  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
248a1b9b6aSSam Leffler  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
258a1b9b6aSSam Leffler  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
268a1b9b6aSSam Leffler  */
278a1b9b6aSSam Leffler 
288a1b9b6aSSam Leffler #include <sys/cdefs.h>
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 *);
57c0cb9349SAdrian Chadd static	void tkip_setiv(struct ieee80211_key *, uint8_t *);
58ef0d8f63SAdrian Chadd static	int tkip_encap(struct ieee80211_key *, struct mbuf *);
5996d88463SSam Leffler static	int tkip_enmic(struct ieee80211_key *, struct mbuf *, int);
602cc12adeSSam Leffler static	int tkip_decap(struct ieee80211_key *, struct mbuf *, int);
6196d88463SSam Leffler static	int tkip_demic(struct ieee80211_key *, struct mbuf *, int);
628a1b9b6aSSam Leffler 
638a1b9b6aSSam Leffler static const struct ieee80211_cipher tkip  = {
648a1b9b6aSSam Leffler 	.ic_name	= "TKIP",
658a1b9b6aSSam Leffler 	.ic_cipher	= IEEE80211_CIPHER_TKIP,
668a1b9b6aSSam Leffler 	.ic_header	= IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
678a1b9b6aSSam Leffler 			  IEEE80211_WEP_EXTIVLEN,
688a1b9b6aSSam Leffler 	.ic_trailer	= IEEE80211_WEP_CRCLEN,
698a1b9b6aSSam Leffler 	.ic_miclen	= IEEE80211_WEP_MICLEN,
708a1b9b6aSSam Leffler 	.ic_attach	= tkip_attach,
718a1b9b6aSSam Leffler 	.ic_detach	= tkip_detach,
728a1b9b6aSSam Leffler 	.ic_setkey	= tkip_setkey,
73c0cb9349SAdrian Chadd 	.ic_setiv	= tkip_setiv,
748a1b9b6aSSam Leffler 	.ic_encap	= tkip_encap,
758a1b9b6aSSam Leffler 	.ic_decap	= tkip_decap,
768a1b9b6aSSam Leffler 	.ic_enmic	= tkip_enmic,
778a1b9b6aSSam Leffler 	.ic_demic	= tkip_demic,
788a1b9b6aSSam Leffler };
798a1b9b6aSSam Leffler 
808a1b9b6aSSam Leffler typedef	uint8_t u8;
818a1b9b6aSSam Leffler typedef	uint16_t u16;
828a1b9b6aSSam Leffler typedef	uint32_t __u32;
838a1b9b6aSSam Leffler typedef	uint32_t u32;
848a1b9b6aSSam Leffler 
858a1b9b6aSSam Leffler struct tkip_ctx {
86b032f27cSSam Leffler 	struct ieee80211vap *tc_vap;	/* for diagnostics+statistics */
878a1b9b6aSSam Leffler 
888a1b9b6aSSam Leffler 	u16	tx_ttak[5];
898a1b9b6aSSam Leffler 	u8	tx_rc4key[16];		/* XXX for test module; make locals? */
908a1b9b6aSSam Leffler 
918a1b9b6aSSam Leffler 	u16	rx_ttak[5];
928a1b9b6aSSam Leffler 	int	rx_phase1_done;
938a1b9b6aSSam Leffler 	u8	rx_rc4key[16];		/* XXX for test module; make locals? */
948a1b9b6aSSam Leffler 	uint64_t rx_rsc;		/* held until MIC verified */
958a1b9b6aSSam Leffler };
968a1b9b6aSSam Leffler 
978a1b9b6aSSam Leffler static	void michael_mic(struct tkip_ctx *, const u8 *key,
988a1b9b6aSSam Leffler 		struct mbuf *m, u_int off, size_t data_len,
998a1b9b6aSSam Leffler 		u8 mic[IEEE80211_WEP_MICLEN]);
1008a1b9b6aSSam Leffler static	int tkip_encrypt(struct tkip_ctx *, struct ieee80211_key *,
1018a1b9b6aSSam Leffler 		struct mbuf *, int hdr_len);
1028a1b9b6aSSam Leffler static	int tkip_decrypt(struct tkip_ctx *, struct ieee80211_key *,
1038a1b9b6aSSam Leffler 		struct mbuf *, int hdr_len);
1048a1b9b6aSSam Leffler 
105d16441fdSSam Leffler /* number of references from net80211 layer */
106d16441fdSSam Leffler static	int nrefs = 0;
107d16441fdSSam Leffler 
1088a1b9b6aSSam Leffler static void *
109b032f27cSSam Leffler tkip_attach(struct ieee80211vap *vap, struct ieee80211_key *k)
1108a1b9b6aSSam Leffler {
1118a1b9b6aSSam Leffler 	struct tkip_ctx *ctx;
1128a1b9b6aSSam Leffler 
113b9b53389SAdrian Chadd 	ctx = (struct tkip_ctx *) IEEE80211_MALLOC(sizeof(struct tkip_ctx),
114b9b53389SAdrian Chadd 		M_80211_CRYPTO, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
1158a1b9b6aSSam Leffler 	if (ctx == NULL) {
116b032f27cSSam Leffler 		vap->iv_stats.is_crypto_nomem++;
1178a1b9b6aSSam Leffler 		return NULL;
1188a1b9b6aSSam Leffler 	}
1198a1b9b6aSSam Leffler 
120b032f27cSSam Leffler 	ctx->tc_vap = vap;
121d16441fdSSam Leffler 	nrefs++;			/* NB: we assume caller locking */
1228a1b9b6aSSam Leffler 	return ctx;
1238a1b9b6aSSam Leffler }
1248a1b9b6aSSam Leffler 
1258a1b9b6aSSam Leffler static void
1268a1b9b6aSSam Leffler tkip_detach(struct ieee80211_key *k)
1278a1b9b6aSSam Leffler {
1288a1b9b6aSSam Leffler 	struct tkip_ctx *ctx = k->wk_private;
1298a1b9b6aSSam Leffler 
130b9b53389SAdrian Chadd 	IEEE80211_FREE(ctx, M_80211_CRYPTO);
131d16441fdSSam Leffler 	KASSERT(nrefs > 0, ("imbalanced attach/detach"));
132d16441fdSSam Leffler 	nrefs--;			/* NB: we assume caller locking */
1338a1b9b6aSSam Leffler }
1348a1b9b6aSSam Leffler 
1358a1b9b6aSSam Leffler static int
1368a1b9b6aSSam Leffler tkip_setkey(struct ieee80211_key *k)
1378a1b9b6aSSam Leffler {
1388a1b9b6aSSam Leffler 	struct tkip_ctx *ctx = k->wk_private;
1398a1b9b6aSSam Leffler 
1408a1b9b6aSSam Leffler 	if (k->wk_keylen != (128/NBBY)) {
1418a1b9b6aSSam Leffler 		(void) ctx;		/* XXX */
142b032f27cSSam Leffler 		IEEE80211_DPRINTF(ctx->tc_vap, IEEE80211_MSG_CRYPTO,
1438a1b9b6aSSam Leffler 			"%s: Invalid key length %u, expecting %u\n",
1448a1b9b6aSSam Leffler 			__func__, k->wk_keylen, 128/NBBY);
1458a1b9b6aSSam Leffler 		return 0;
1468a1b9b6aSSam Leffler 	}
14798f160d9SBernhard Schmidt 	ctx->rx_phase1_done = 0;
1488a1b9b6aSSam Leffler 	return 1;
1498a1b9b6aSSam Leffler }
1508a1b9b6aSSam Leffler 
151c0cb9349SAdrian Chadd static void
152c0cb9349SAdrian Chadd tkip_setiv(struct ieee80211_key *k, uint8_t *ivp)
153c0cb9349SAdrian Chadd {
154c0cb9349SAdrian Chadd 	struct tkip_ctx *ctx = k->wk_private;
155c0cb9349SAdrian Chadd 	struct ieee80211vap *vap = ctx->tc_vap;
156c0cb9349SAdrian Chadd 	uint8_t keyid;
157c0cb9349SAdrian Chadd 
158c0cb9349SAdrian Chadd 	keyid = ieee80211_crypto_get_keyid(vap, k) << 6;
159c0cb9349SAdrian Chadd 
160c0cb9349SAdrian Chadd 	k->wk_keytsc++;
161c0cb9349SAdrian Chadd 	ivp[0] = k->wk_keytsc >> 8;		/* TSC1 */
162c0cb9349SAdrian Chadd 	ivp[1] = (ivp[0] | 0x20) & 0x7f;	/* WEP seed */
163c0cb9349SAdrian Chadd 	ivp[2] = k->wk_keytsc >> 0;		/* TSC0 */
164c0cb9349SAdrian Chadd 	ivp[3] = keyid | IEEE80211_WEP_EXTIV;	/* KeyID | ExtID */
165c0cb9349SAdrian Chadd 	ivp[4] = k->wk_keytsc >> 16;		/* TSC2 */
166c0cb9349SAdrian Chadd 	ivp[5] = k->wk_keytsc >> 24;		/* TSC3 */
167c0cb9349SAdrian Chadd 	ivp[6] = k->wk_keytsc >> 32;		/* TSC4 */
168c0cb9349SAdrian Chadd 	ivp[7] = k->wk_keytsc >> 40;		/* TSC5 */
169c0cb9349SAdrian Chadd }
170c0cb9349SAdrian Chadd 
1718a1b9b6aSSam Leffler /*
1728a1b9b6aSSam Leffler  * Add privacy headers and do any s/w encryption required.
1738a1b9b6aSSam Leffler  */
1748a1b9b6aSSam Leffler static int
175ef0d8f63SAdrian Chadd tkip_encap(struct ieee80211_key *k, struct mbuf *m)
1768a1b9b6aSSam Leffler {
1778a1b9b6aSSam Leffler 	struct tkip_ctx *ctx = k->wk_private;
178b032f27cSSam Leffler 	struct ieee80211vap *vap = ctx->tc_vap;
179b032f27cSSam Leffler 	struct ieee80211com *ic = vap->iv_ic;
180fe75b452SAdrian Chadd 	struct ieee80211_frame *wh;
18168e8e04eSSam Leffler 	uint8_t *ivp;
1828a1b9b6aSSam Leffler 	int hdrlen;
183fe75b452SAdrian Chadd 	int is_mgmt;
184fe75b452SAdrian Chadd 
185fe75b452SAdrian Chadd 	wh = mtod(m, struct ieee80211_frame *);
186fe75b452SAdrian Chadd 	is_mgmt = IEEE80211_IS_MGMT(wh);
1878a1b9b6aSSam Leffler 
1888a1b9b6aSSam Leffler 	/*
1898a1b9b6aSSam Leffler 	 * Handle TKIP counter measures requirement.
1908a1b9b6aSSam Leffler 	 */
191b032f27cSSam Leffler 	if (vap->iv_flags & IEEE80211_F_COUNTERM) {
1928a1b9b6aSSam Leffler #ifdef IEEE80211_DEBUG
1938a1b9b6aSSam Leffler 		struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
1948a1b9b6aSSam Leffler #endif
1958a1b9b6aSSam Leffler 
196b032f27cSSam Leffler 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
197b032f27cSSam Leffler 		    "discard frame due to countermeasures (%s)", __func__);
198b032f27cSSam Leffler 		vap->iv_stats.is_crypto_tkipcm++;
1998a1b9b6aSSam Leffler 		return 0;
2008a1b9b6aSSam Leffler 	}
201fe75b452SAdrian Chadd 
202fe75b452SAdrian Chadd 	/*
203fe75b452SAdrian Chadd 	 * Check to see whether IV needs to be included.
204fe75b452SAdrian Chadd 	 */
205fe75b452SAdrian Chadd 	if (is_mgmt && (k->wk_flags & IEEE80211_KEY_NOIVMGT))
206fe75b452SAdrian Chadd 		return 1;
207fe75b452SAdrian Chadd 	if ((! is_mgmt) && (k->wk_flags & IEEE80211_KEY_NOIV))
208fe75b452SAdrian Chadd 		return 1;
209fe75b452SAdrian Chadd 
2104e844c94SSam Leffler 	hdrlen = ieee80211_hdrspace(ic, mtod(m, void *));
2118a1b9b6aSSam Leffler 
2128a1b9b6aSSam Leffler 	/*
2138a1b9b6aSSam Leffler 	 * Copy down 802.11 header and add the IV, KeyID, and ExtIV.
2148a1b9b6aSSam Leffler 	 */
215bd29f817SBjoern A. Zeeb 	M_PREPEND(m, tkip.ic_header, IEEE80211_M_NOWAIT);
2168a1b9b6aSSam Leffler 	if (m == NULL)
2178a1b9b6aSSam Leffler 		return 0;
21868e8e04eSSam Leffler 	ivp = mtod(m, uint8_t *);
2198a1b9b6aSSam Leffler 	memmove(ivp, ivp + tkip.ic_header, hdrlen);
2208a1b9b6aSSam Leffler 	ivp += hdrlen;
2218a1b9b6aSSam Leffler 
222c0cb9349SAdrian Chadd 	tkip_setiv(k, ivp);
2238a1b9b6aSSam Leffler 
2248a1b9b6aSSam Leffler 	/*
225bf0b7b45SAdrian Chadd 	 * Finally, do software encrypt if needed.
2268a1b9b6aSSam Leffler 	 */
227483755beSAdrian Chadd 	if ((k->wk_flags & IEEE80211_KEY_SWENCRYPT) &&
228483755beSAdrian Chadd 	    !tkip_encrypt(ctx, k, m, hdrlen))
2298a1b9b6aSSam Leffler 		return 0;
2308a1b9b6aSSam Leffler 
2318a1b9b6aSSam Leffler 	return 1;
2328a1b9b6aSSam Leffler }
2338a1b9b6aSSam Leffler 
2348a1b9b6aSSam Leffler /*
2358a1b9b6aSSam Leffler  * Add MIC to the frame as needed.
2368a1b9b6aSSam Leffler  */
2378a1b9b6aSSam Leffler static int
23896d88463SSam Leffler tkip_enmic(struct ieee80211_key *k, struct mbuf *m, int force)
2398a1b9b6aSSam Leffler {
2408a1b9b6aSSam Leffler 	struct tkip_ctx *ctx = k->wk_private;
241fe75b452SAdrian Chadd 	struct ieee80211_frame *wh;
242fe75b452SAdrian Chadd 	int is_mgmt;
243fe75b452SAdrian Chadd 
244fe75b452SAdrian Chadd 	wh = mtod(m, struct ieee80211_frame *);
245fe75b452SAdrian Chadd 	is_mgmt = IEEE80211_IS_MGMT(wh);
246fe75b452SAdrian Chadd 
247fe75b452SAdrian Chadd 	/*
248fe75b452SAdrian Chadd 	 * Check to see whether MIC needs to be included.
249fe75b452SAdrian Chadd 	 */
250fe75b452SAdrian Chadd 	if (is_mgmt && (k->wk_flags & IEEE80211_KEY_NOMICMGT))
251fe75b452SAdrian Chadd 		return 1;
252fe75b452SAdrian Chadd 	if ((! is_mgmt) && (k->wk_flags & IEEE80211_KEY_NOMIC))
253fe75b452SAdrian Chadd 		return 1;
2548a1b9b6aSSam Leffler 
2555c1f7f19SSam Leffler 	if (force || (k->wk_flags & IEEE80211_KEY_SWENMIC)) {
2568a1b9b6aSSam Leffler 		struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
257b032f27cSSam Leffler 		struct ieee80211vap *vap = ctx->tc_vap;
258b032f27cSSam Leffler 		struct ieee80211com *ic = vap->iv_ic;
2594e844c94SSam Leffler 		int hdrlen;
2608a1b9b6aSSam Leffler 		uint8_t mic[IEEE80211_WEP_MICLEN];
2618a1b9b6aSSam Leffler 
262b032f27cSSam Leffler 		vap->iv_stats.is_crypto_tkipenmic++;
2634e844c94SSam Leffler 
2644e844c94SSam Leffler 		hdrlen = ieee80211_hdrspace(ic, wh);
2658a1b9b6aSSam Leffler 
2668a1b9b6aSSam Leffler 		michael_mic(ctx, k->wk_txmic,
2678a1b9b6aSSam Leffler 			m, hdrlen, m->m_pkthdr.len - hdrlen, mic);
2688a1b9b6aSSam Leffler 		return m_append(m, tkip.ic_miclen, mic);
2698a1b9b6aSSam Leffler 	}
2708a1b9b6aSSam Leffler 	return 1;
2718a1b9b6aSSam Leffler }
2728a1b9b6aSSam Leffler 
2738a1b9b6aSSam Leffler static __inline uint64_t
2748a1b9b6aSSam Leffler READ_6(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5)
2758a1b9b6aSSam Leffler {
2768a1b9b6aSSam Leffler 	uint32_t iv32 = (b0 << 0) | (b1 << 8) | (b2 << 16) | (b3 << 24);
2778a1b9b6aSSam Leffler 	uint16_t iv16 = (b4 << 0) | (b5 << 8);
2788a1b9b6aSSam Leffler 	return (((uint64_t)iv16) << 32) | iv32;
2798a1b9b6aSSam Leffler }
2808a1b9b6aSSam Leffler 
2818a1b9b6aSSam Leffler /*
2828a1b9b6aSSam Leffler  * Validate and strip privacy headers (and trailer) for a
2838a1b9b6aSSam Leffler  * received frame.  If necessary, decrypt the frame using
2848a1b9b6aSSam Leffler  * the specified key.
2858a1b9b6aSSam Leffler  */
2868a1b9b6aSSam Leffler static int
2872cc12adeSSam Leffler tkip_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen)
2888a1b9b6aSSam Leffler {
289fe75b452SAdrian Chadd 	const struct ieee80211_rx_stats *rxs;
2908a1b9b6aSSam Leffler 	struct tkip_ctx *ctx = k->wk_private;
291b032f27cSSam Leffler 	struct ieee80211vap *vap = ctx->tc_vap;
2928a1b9b6aSSam Leffler 	struct ieee80211_frame *wh;
293b032f27cSSam Leffler 	uint8_t *ivp, tid;
2948a1b9b6aSSam Leffler 
295fe75b452SAdrian Chadd 	rxs = ieee80211_get_rx_params_ptr(m);
296fe75b452SAdrian Chadd 
297fe75b452SAdrian Chadd 	/*
298fe75b452SAdrian Chadd 	 * If IV has been stripped, we skip most of the below.
299fe75b452SAdrian Chadd 	 */
300fe75b452SAdrian Chadd 	if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP))
301fe75b452SAdrian Chadd 		goto finish;
302fe75b452SAdrian Chadd 
3038a1b9b6aSSam Leffler 	/*
3048a1b9b6aSSam Leffler 	 * Header should have extended IV and sequence number;
3058a1b9b6aSSam Leffler 	 * verify the former and validate the latter.
3068a1b9b6aSSam Leffler 	 */
3078a1b9b6aSSam Leffler 	wh = mtod(m, struct ieee80211_frame *);
3088a1b9b6aSSam Leffler 	ivp = mtod(m, uint8_t *) + hdrlen;
3098a1b9b6aSSam Leffler 	if ((ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV) == 0) {
3108a1b9b6aSSam Leffler 		/*
3118a1b9b6aSSam Leffler 		 * No extended IV; discard frame.
3128a1b9b6aSSam Leffler 		 */
313b032f27cSSam Leffler 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
314b032f27cSSam Leffler 		    "%s", "missing ExtIV for TKIP cipher");
315b032f27cSSam Leffler 		vap->iv_stats.is_rx_tkipformat++;
3168a1b9b6aSSam Leffler 		return 0;
3178a1b9b6aSSam Leffler 	}
3188a1b9b6aSSam Leffler 	/*
3198a1b9b6aSSam Leffler 	 * Handle TKIP counter measures requirement.
3208a1b9b6aSSam Leffler 	 */
321b032f27cSSam Leffler 	if (vap->iv_flags & IEEE80211_F_COUNTERM) {
322b032f27cSSam Leffler 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
323b032f27cSSam Leffler 		    "discard frame due to countermeasures (%s)", __func__);
324b032f27cSSam Leffler 		vap->iv_stats.is_crypto_tkipcm++;
3258a1b9b6aSSam Leffler 		return 0;
3268a1b9b6aSSam Leffler 	}
3278a1b9b6aSSam Leffler 
328b032f27cSSam Leffler 	tid = ieee80211_gettid(wh);
329f287c95bSSam Leffler 	ctx->rx_rsc = READ_6(ivp[2], ivp[0], ivp[4], ivp[5], ivp[6], ivp[7]);
3305d766a09SBernhard Schmidt 	if (ctx->rx_rsc <= k->wk_keyrsc[tid] &&
3315d766a09SBernhard Schmidt 	    (k->wk_flags & IEEE80211_KEY_NOREPLAY) == 0) {
3328a1b9b6aSSam Leffler 		/*
3338a1b9b6aSSam Leffler 		 * Replay violation; notify upper layer.
3348a1b9b6aSSam Leffler 		 */
335ebaf87ebSSam Leffler 		ieee80211_notify_replay_failure(vap, wh, k, ctx->rx_rsc, tid);
336b032f27cSSam Leffler 		vap->iv_stats.is_rx_tkipreplay++;
3378a1b9b6aSSam Leffler 		return 0;
3388a1b9b6aSSam Leffler 	}
3398a1b9b6aSSam Leffler 	/*
3408a1b9b6aSSam Leffler 	 * NB: We can't update the rsc in the key until MIC is verified.
3418a1b9b6aSSam Leffler 	 *
3428a1b9b6aSSam Leffler 	 * We assume we are not preempted between doing the check above
3438a1b9b6aSSam Leffler 	 * and updating wk_keyrsc when stripping the MIC in tkip_demic.
3448a1b9b6aSSam Leffler 	 * Otherwise we might process another packet and discard it as
3458a1b9b6aSSam Leffler 	 * a replay.
3468a1b9b6aSSam Leffler 	 */
3478a1b9b6aSSam Leffler 
3488a1b9b6aSSam Leffler 	/*
3498a1b9b6aSSam Leffler 	 * Check if the device handled the decrypt in hardware.
3508a1b9b6aSSam Leffler 	 * If so we just strip the header; otherwise we need to
3518a1b9b6aSSam Leffler 	 * handle the decrypt in software.
3528a1b9b6aSSam Leffler 	 */
3535c1f7f19SSam Leffler 	if ((k->wk_flags & IEEE80211_KEY_SWDECRYPT) &&
3548a1b9b6aSSam Leffler 	    !tkip_decrypt(ctx, k, m, hdrlen))
3558a1b9b6aSSam Leffler 		return 0;
3568a1b9b6aSSam Leffler 
357fe75b452SAdrian Chadd finish:
358fe75b452SAdrian Chadd 
3598a1b9b6aSSam Leffler 	/*
360fe75b452SAdrian Chadd 	 * Copy up 802.11 header and strip crypto bits - but only if we
361fe75b452SAdrian Chadd 	 * are required to.
3628a1b9b6aSSam Leffler 	 */
363fe75b452SAdrian Chadd 	if (! ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP))) {
364fe75b452SAdrian Chadd 		memmove(mtod(m, uint8_t *) + tkip.ic_header, mtod(m, void *),
365fe75b452SAdrian Chadd 		    hdrlen);
3668a1b9b6aSSam Leffler 		m_adj(m, tkip.ic_header);
367fe75b452SAdrian Chadd 	}
368fe75b452SAdrian Chadd 
369fe75b452SAdrian Chadd 	/*
370fe75b452SAdrian Chadd 	 * XXX TODO: do we need an option to potentially not strip the
371fe75b452SAdrian Chadd 	 * WEP trailer?  Does "MMIC_STRIP" also mean this? Or?
372fe75b452SAdrian Chadd 	 */
3738a1b9b6aSSam Leffler 	m_adj(m, -tkip.ic_trailer);
3748a1b9b6aSSam Leffler 
3758a1b9b6aSSam Leffler 	return 1;
3768a1b9b6aSSam Leffler }
3778a1b9b6aSSam Leffler 
3788a1b9b6aSSam Leffler /*
3798a1b9b6aSSam Leffler  * Verify and strip MIC from the frame.
3808a1b9b6aSSam Leffler  */
3818a1b9b6aSSam Leffler static int
38296d88463SSam Leffler tkip_demic(struct ieee80211_key *k, struct mbuf *m, int force)
3838a1b9b6aSSam Leffler {
384fe75b452SAdrian Chadd 	const struct ieee80211_rx_stats *rxs;
3858a1b9b6aSSam Leffler 	struct tkip_ctx *ctx = k->wk_private;
386b032f27cSSam Leffler 	struct ieee80211_frame *wh;
387b032f27cSSam Leffler 	uint8_t tid;
3888a1b9b6aSSam Leffler 
389b032f27cSSam Leffler 	wh = mtod(m, struct ieee80211_frame *);
390fe75b452SAdrian Chadd 	rxs = ieee80211_get_rx_params_ptr(m);
391fe75b452SAdrian Chadd 
392fe75b452SAdrian Chadd 	/*
393fe75b452SAdrian Chadd 	 * If we are told about a MIC failure from the driver,
394fe75b452SAdrian Chadd 	 * directly notify as a michael failure to the upper
395fe75b452SAdrian Chadd 	 * layers.
396fe75b452SAdrian Chadd 	 */
397fe75b452SAdrian Chadd 	if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_FAIL_MIC)) {
398fe75b452SAdrian Chadd 		struct ieee80211vap *vap = ctx->tc_vap;
399fe75b452SAdrian Chadd 		ieee80211_notify_michael_failure(vap, wh,
400fe75b452SAdrian Chadd 		    k->wk_rxkeyix != IEEE80211_KEYIX_NONE ?
401fe75b452SAdrian Chadd 		    k->wk_rxkeyix : k->wk_keyix);
402fe75b452SAdrian Chadd 		return 0;
403fe75b452SAdrian Chadd 	}
404fe75b452SAdrian Chadd 
405fe75b452SAdrian Chadd 	/*
406fe75b452SAdrian Chadd 	 * If IV has been stripped, we skip most of the below.
407fe75b452SAdrian Chadd 	 */
408fe75b452SAdrian Chadd 	if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_MMIC_STRIP))
409fe75b452SAdrian Chadd 		goto finish;
410fe75b452SAdrian Chadd 
4115c1f7f19SSam Leffler 	if ((k->wk_flags & IEEE80211_KEY_SWDEMIC) || force) {
412b032f27cSSam Leffler 		struct ieee80211vap *vap = ctx->tc_vap;
413b032f27cSSam Leffler 		int hdrlen = ieee80211_hdrspace(vap->iv_ic, wh);
4148a1b9b6aSSam Leffler 		u8 mic[IEEE80211_WEP_MICLEN];
4158a1b9b6aSSam Leffler 		u8 mic0[IEEE80211_WEP_MICLEN];
4168a1b9b6aSSam Leffler 
417b032f27cSSam Leffler 		vap->iv_stats.is_crypto_tkipdemic++;
4188a1b9b6aSSam Leffler 
4198a1b9b6aSSam Leffler 		michael_mic(ctx, k->wk_rxmic,
4208a1b9b6aSSam Leffler 			m, hdrlen, m->m_pkthdr.len - (hdrlen + tkip.ic_miclen),
4218a1b9b6aSSam Leffler 			mic);
4228a1b9b6aSSam Leffler 		m_copydata(m, m->m_pkthdr.len - tkip.ic_miclen,
4238a1b9b6aSSam Leffler 			tkip.ic_miclen, mic0);
4248a1b9b6aSSam Leffler 		if (memcmp(mic, mic0, tkip.ic_miclen)) {
4258a1b9b6aSSam Leffler 			/* NB: 802.11 layer handles statistic and debug msg */
426b032f27cSSam Leffler 			ieee80211_notify_michael_failure(vap, wh,
427c1225b52SSam Leffler 				k->wk_rxkeyix != IEEE80211_KEYIX_NONE ?
428c1225b52SSam Leffler 					k->wk_rxkeyix : k->wk_keyix);
4298a1b9b6aSSam Leffler 			return 0;
4308a1b9b6aSSam Leffler 		}
4318a1b9b6aSSam Leffler 	}
4328a1b9b6aSSam Leffler 	/*
4338a1b9b6aSSam Leffler 	 * Strip MIC from the tail.
4348a1b9b6aSSam Leffler 	 */
4358a1b9b6aSSam Leffler 	m_adj(m, -tkip.ic_miclen);
4368a1b9b6aSSam Leffler 
4378a1b9b6aSSam Leffler 	/*
4388a1b9b6aSSam Leffler 	 * Ok to update rsc now that MIC has been verified.
4398a1b9b6aSSam Leffler 	 */
440b032f27cSSam Leffler 	tid = ieee80211_gettid(wh);
441b032f27cSSam Leffler 	k->wk_keyrsc[tid] = ctx->rx_rsc;
4428a1b9b6aSSam Leffler 
443fe75b452SAdrian Chadd finish:
4448a1b9b6aSSam Leffler 	return 1;
4458a1b9b6aSSam Leffler }
4468a1b9b6aSSam Leffler 
4478a1b9b6aSSam Leffler /*
4488a1b9b6aSSam Leffler  * Host AP crypt: host-based TKIP encryption implementation for Host AP driver
4498a1b9b6aSSam Leffler  *
4508a1b9b6aSSam Leffler  * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
4518a1b9b6aSSam Leffler  *
4528a1b9b6aSSam Leffler  * This program is free software; you can redistribute it and/or modify
4538a1b9b6aSSam Leffler  * it under the terms of the GNU General Public License version 2 as
4548a1b9b6aSSam Leffler  * published by the Free Software Foundation. See README and COPYING for
4558a1b9b6aSSam Leffler  * more details.
4568a1b9b6aSSam Leffler  *
4578a1b9b6aSSam Leffler  * Alternatively, this software may be distributed under the terms of BSD
4588a1b9b6aSSam Leffler  * license.
4598a1b9b6aSSam Leffler  */
4608a1b9b6aSSam Leffler 
4618a1b9b6aSSam Leffler static const __u32 crc32_table[256] = {
4628a1b9b6aSSam Leffler 	0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
4638a1b9b6aSSam Leffler 	0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
4648a1b9b6aSSam Leffler 	0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
4658a1b9b6aSSam Leffler 	0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
4668a1b9b6aSSam Leffler 	0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
4678a1b9b6aSSam Leffler 	0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
4688a1b9b6aSSam Leffler 	0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
4698a1b9b6aSSam Leffler 	0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
4708a1b9b6aSSam Leffler 	0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
4718a1b9b6aSSam Leffler 	0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
4728a1b9b6aSSam Leffler 	0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
4738a1b9b6aSSam Leffler 	0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
4748a1b9b6aSSam Leffler 	0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
4758a1b9b6aSSam Leffler 	0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
4768a1b9b6aSSam Leffler 	0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
4778a1b9b6aSSam Leffler 	0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
4788a1b9b6aSSam Leffler 	0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
4798a1b9b6aSSam Leffler 	0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
4808a1b9b6aSSam Leffler 	0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
4818a1b9b6aSSam Leffler 	0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
4828a1b9b6aSSam Leffler 	0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
4838a1b9b6aSSam Leffler 	0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
4848a1b9b6aSSam Leffler 	0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
4858a1b9b6aSSam Leffler 	0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
4868a1b9b6aSSam Leffler 	0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
4878a1b9b6aSSam Leffler 	0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
4888a1b9b6aSSam Leffler 	0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
4898a1b9b6aSSam Leffler 	0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
4908a1b9b6aSSam Leffler 	0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
4918a1b9b6aSSam Leffler 	0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
4928a1b9b6aSSam Leffler 	0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
4938a1b9b6aSSam Leffler 	0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
4948a1b9b6aSSam Leffler 	0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
4958a1b9b6aSSam Leffler 	0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
4968a1b9b6aSSam Leffler 	0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
4978a1b9b6aSSam Leffler 	0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
4988a1b9b6aSSam Leffler 	0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
4998a1b9b6aSSam Leffler 	0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
5008a1b9b6aSSam Leffler 	0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
5018a1b9b6aSSam Leffler 	0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
5028a1b9b6aSSam Leffler 	0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
5038a1b9b6aSSam Leffler 	0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
5048a1b9b6aSSam Leffler 	0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
5058a1b9b6aSSam Leffler 	0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
5068a1b9b6aSSam Leffler 	0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
5078a1b9b6aSSam Leffler 	0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
5088a1b9b6aSSam Leffler 	0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
5098a1b9b6aSSam Leffler 	0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
5108a1b9b6aSSam Leffler 	0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
5118a1b9b6aSSam Leffler 	0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
5128a1b9b6aSSam Leffler 	0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
5138a1b9b6aSSam Leffler 	0x2d02ef8dL
5148a1b9b6aSSam Leffler };
5158a1b9b6aSSam Leffler 
5168a1b9b6aSSam Leffler static __inline u16 RotR1(u16 val)
5178a1b9b6aSSam Leffler {
5188a1b9b6aSSam Leffler 	return (val >> 1) | (val << 15);
5198a1b9b6aSSam Leffler }
5208a1b9b6aSSam Leffler 
5218a1b9b6aSSam Leffler static __inline u8 Lo8(u16 val)
5228a1b9b6aSSam Leffler {
5238a1b9b6aSSam Leffler 	return val & 0xff;
5248a1b9b6aSSam Leffler }
5258a1b9b6aSSam Leffler 
5268a1b9b6aSSam Leffler static __inline u8 Hi8(u16 val)
5278a1b9b6aSSam Leffler {
5288a1b9b6aSSam Leffler 	return val >> 8;
5298a1b9b6aSSam Leffler }
5308a1b9b6aSSam Leffler 
5318a1b9b6aSSam Leffler static __inline u16 Lo16(u32 val)
5328a1b9b6aSSam Leffler {
5338a1b9b6aSSam Leffler 	return val & 0xffff;
5348a1b9b6aSSam Leffler }
5358a1b9b6aSSam Leffler 
5368a1b9b6aSSam Leffler static __inline u16 Hi16(u32 val)
5378a1b9b6aSSam Leffler {
5388a1b9b6aSSam Leffler 	return val >> 16;
5398a1b9b6aSSam Leffler }
5408a1b9b6aSSam Leffler 
5418a1b9b6aSSam Leffler static __inline u16 Mk16(u8 hi, u8 lo)
5428a1b9b6aSSam Leffler {
5438a1b9b6aSSam Leffler 	return lo | (((u16) hi) << 8);
5448a1b9b6aSSam Leffler }
5458a1b9b6aSSam Leffler 
5468a1b9b6aSSam Leffler static __inline u16 Mk16_le(const u16 *v)
5478a1b9b6aSSam Leffler {
5488a1b9b6aSSam Leffler 	return le16toh(*v);
5498a1b9b6aSSam Leffler }
5508a1b9b6aSSam Leffler 
5518a1b9b6aSSam Leffler static const u16 Sbox[256] = {
5528a1b9b6aSSam Leffler 	0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
5538a1b9b6aSSam Leffler 	0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
5548a1b9b6aSSam Leffler 	0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
5558a1b9b6aSSam Leffler 	0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
5568a1b9b6aSSam Leffler 	0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
5578a1b9b6aSSam Leffler 	0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
5588a1b9b6aSSam Leffler 	0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
5598a1b9b6aSSam Leffler 	0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
5608a1b9b6aSSam Leffler 	0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
5618a1b9b6aSSam Leffler 	0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
5628a1b9b6aSSam Leffler 	0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
5638a1b9b6aSSam Leffler 	0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
5648a1b9b6aSSam Leffler 	0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
5658a1b9b6aSSam Leffler 	0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
5668a1b9b6aSSam Leffler 	0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
5678a1b9b6aSSam Leffler 	0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
5688a1b9b6aSSam Leffler 	0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
5698a1b9b6aSSam Leffler 	0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
5708a1b9b6aSSam Leffler 	0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
5718a1b9b6aSSam Leffler 	0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
5728a1b9b6aSSam Leffler 	0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
5738a1b9b6aSSam Leffler 	0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
5748a1b9b6aSSam Leffler 	0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
5758a1b9b6aSSam Leffler 	0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
5768a1b9b6aSSam Leffler 	0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
5778a1b9b6aSSam Leffler 	0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
5788a1b9b6aSSam Leffler 	0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
5798a1b9b6aSSam Leffler 	0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
5808a1b9b6aSSam Leffler 	0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
5818a1b9b6aSSam Leffler 	0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
5828a1b9b6aSSam Leffler 	0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
5838a1b9b6aSSam Leffler 	0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
5848a1b9b6aSSam Leffler };
5858a1b9b6aSSam Leffler 
5868a1b9b6aSSam Leffler static __inline u16 _S_(u16 v)
5878a1b9b6aSSam Leffler {
5888a1b9b6aSSam Leffler 	u16 t = Sbox[Hi8(v)];
5898a1b9b6aSSam Leffler 	return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8));
5908a1b9b6aSSam Leffler }
5918a1b9b6aSSam Leffler 
5928a1b9b6aSSam Leffler #define PHASE1_LOOP_COUNT 8
5938a1b9b6aSSam Leffler 
5948a1b9b6aSSam Leffler static void tkip_mixing_phase1(u16 *TTAK, const u8 *TK, const u8 *TA, u32 IV32)
5958a1b9b6aSSam Leffler {
5968a1b9b6aSSam Leffler 	int i, j;
5978a1b9b6aSSam Leffler 
5988a1b9b6aSSam Leffler 	/* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */
5998a1b9b6aSSam Leffler 	TTAK[0] = Lo16(IV32);
6008a1b9b6aSSam Leffler 	TTAK[1] = Hi16(IV32);
6018a1b9b6aSSam Leffler 	TTAK[2] = Mk16(TA[1], TA[0]);
6028a1b9b6aSSam Leffler 	TTAK[3] = Mk16(TA[3], TA[2]);
6038a1b9b6aSSam Leffler 	TTAK[4] = Mk16(TA[5], TA[4]);
6048a1b9b6aSSam Leffler 
6058a1b9b6aSSam Leffler 	for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
6068a1b9b6aSSam Leffler 		j = 2 * (i & 1);
6078a1b9b6aSSam Leffler 		TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j]));
6088a1b9b6aSSam Leffler 		TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j]));
6098a1b9b6aSSam Leffler 		TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j]));
6108a1b9b6aSSam Leffler 		TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j]));
6118a1b9b6aSSam Leffler 		TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i;
6128a1b9b6aSSam Leffler 	}
6138a1b9b6aSSam Leffler }
6148a1b9b6aSSam Leffler 
6158a1b9b6aSSam Leffler #ifndef _BYTE_ORDER
6168a1b9b6aSSam Leffler #error "Don't know native byte order"
6178a1b9b6aSSam Leffler #endif
6188a1b9b6aSSam Leffler 
6198a1b9b6aSSam Leffler static void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK,
6208a1b9b6aSSam Leffler 			       u16 IV16)
6218a1b9b6aSSam Leffler {
6228a1b9b6aSSam Leffler 	/* Make temporary area overlap WEP seed so that the final copy can be
6238a1b9b6aSSam Leffler 	 * avoided on little endian hosts. */
6248a1b9b6aSSam Leffler 	u16 *PPK = (u16 *) &WEPSeed[4];
6258a1b9b6aSSam Leffler 
6268a1b9b6aSSam Leffler 	/* Step 1 - make copy of TTAK and bring in TSC */
6278a1b9b6aSSam Leffler 	PPK[0] = TTAK[0];
6288a1b9b6aSSam Leffler 	PPK[1] = TTAK[1];
6298a1b9b6aSSam Leffler 	PPK[2] = TTAK[2];
6308a1b9b6aSSam Leffler 	PPK[3] = TTAK[3];
6318a1b9b6aSSam Leffler 	PPK[4] = TTAK[4];
6328a1b9b6aSSam Leffler 	PPK[5] = TTAK[4] + IV16;
6338a1b9b6aSSam Leffler 
6348a1b9b6aSSam Leffler 	/* Step 2 - 96-bit bijective mixing using S-box */
6358a1b9b6aSSam Leffler 	PPK[0] += _S_(PPK[5] ^ Mk16_le((const u16 *) &TK[0]));
6368a1b9b6aSSam Leffler 	PPK[1] += _S_(PPK[0] ^ Mk16_le((const u16 *) &TK[2]));
6378a1b9b6aSSam Leffler 	PPK[2] += _S_(PPK[1] ^ Mk16_le((const u16 *) &TK[4]));
6388a1b9b6aSSam Leffler 	PPK[3] += _S_(PPK[2] ^ Mk16_le((const u16 *) &TK[6]));
6398a1b9b6aSSam Leffler 	PPK[4] += _S_(PPK[3] ^ Mk16_le((const u16 *) &TK[8]));
6408a1b9b6aSSam Leffler 	PPK[5] += _S_(PPK[4] ^ Mk16_le((const u16 *) &TK[10]));
6418a1b9b6aSSam Leffler 
6428a1b9b6aSSam Leffler 	PPK[0] += RotR1(PPK[5] ^ Mk16_le((const u16 *) &TK[12]));
6438a1b9b6aSSam Leffler 	PPK[1] += RotR1(PPK[0] ^ Mk16_le((const u16 *) &TK[14]));
6448a1b9b6aSSam Leffler 	PPK[2] += RotR1(PPK[1]);
6458a1b9b6aSSam Leffler 	PPK[3] += RotR1(PPK[2]);
6468a1b9b6aSSam Leffler 	PPK[4] += RotR1(PPK[3]);
6478a1b9b6aSSam Leffler 	PPK[5] += RotR1(PPK[4]);
6488a1b9b6aSSam Leffler 
6498a1b9b6aSSam Leffler 	/* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value
6508a1b9b6aSSam Leffler 	 * WEPSeed[0..2] is transmitted as WEP IV */
6518a1b9b6aSSam Leffler 	WEPSeed[0] = Hi8(IV16);
6528a1b9b6aSSam Leffler 	WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F;
6538a1b9b6aSSam Leffler 	WEPSeed[2] = Lo8(IV16);
6548a1b9b6aSSam Leffler 	WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((const u16 *) &TK[0])) >> 1);
6558a1b9b6aSSam Leffler 
6568a1b9b6aSSam Leffler #if _BYTE_ORDER == _BIG_ENDIAN
6578a1b9b6aSSam Leffler 	{
6588a1b9b6aSSam Leffler 		int i;
6598a1b9b6aSSam Leffler 		for (i = 0; i < 6; i++)
6608a1b9b6aSSam Leffler 			PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8);
6618a1b9b6aSSam Leffler 	}
6628a1b9b6aSSam Leffler #endif
6638a1b9b6aSSam Leffler }
6648a1b9b6aSSam Leffler 
6658a1b9b6aSSam Leffler static void
6668a1b9b6aSSam Leffler wep_encrypt(u8 *key, struct mbuf *m0, u_int off, size_t data_len,
6678a1b9b6aSSam Leffler 	uint8_t icv[IEEE80211_WEP_CRCLEN])
6688a1b9b6aSSam Leffler {
6698a1b9b6aSSam Leffler 	u32 i, j, k, crc;
6708a1b9b6aSSam Leffler 	size_t buflen;
6718a1b9b6aSSam Leffler 	u8 S[256];
6728a1b9b6aSSam Leffler 	u8 *pos;
6738a1b9b6aSSam Leffler 	struct mbuf *m;
6748a1b9b6aSSam Leffler #define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
6758a1b9b6aSSam Leffler 
6768a1b9b6aSSam Leffler 	/* Setup RC4 state */
6778a1b9b6aSSam Leffler 	for (i = 0; i < 256; i++)
6788a1b9b6aSSam Leffler 		S[i] = i;
6798a1b9b6aSSam Leffler 	j = 0;
6808a1b9b6aSSam Leffler 	for (i = 0; i < 256; i++) {
6818a1b9b6aSSam Leffler 		j = (j + S[i] + key[i & 0x0f]) & 0xff;
6828a1b9b6aSSam Leffler 		S_SWAP(i, j);
6838a1b9b6aSSam Leffler 	}
6848a1b9b6aSSam Leffler 
6858a1b9b6aSSam Leffler 	/* Compute CRC32 over unencrypted data and apply RC4 to data */
6868a1b9b6aSSam Leffler 	crc = ~0;
6878a1b9b6aSSam Leffler 	i = j = 0;
6888a1b9b6aSSam Leffler 	m = m0;
6898a1b9b6aSSam Leffler 	pos = mtod(m, uint8_t *) + off;
6908a1b9b6aSSam Leffler 	buflen = m->m_len - off;
6918a1b9b6aSSam Leffler 	for (;;) {
6928a1b9b6aSSam Leffler 		if (buflen > data_len)
6938a1b9b6aSSam Leffler 			buflen = data_len;
6948a1b9b6aSSam Leffler 		data_len -= buflen;
6958a1b9b6aSSam Leffler 		for (k = 0; k < buflen; k++) {
6968a1b9b6aSSam Leffler 			crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8);
6978a1b9b6aSSam Leffler 			i = (i + 1) & 0xff;
6988a1b9b6aSSam Leffler 			j = (j + S[i]) & 0xff;
6998a1b9b6aSSam Leffler 			S_SWAP(i, j);
7008a1b9b6aSSam Leffler 			*pos++ ^= S[(S[i] + S[j]) & 0xff];
7018a1b9b6aSSam Leffler 		}
7028a1b9b6aSSam Leffler 		m = m->m_next;
7038a1b9b6aSSam Leffler 		if (m == NULL) {
7048a1b9b6aSSam Leffler 			KASSERT(data_len == 0,
70516574882SSam Leffler 			    ("out of buffers with data_len %zu\n", data_len));
7068a1b9b6aSSam Leffler 			break;
7078a1b9b6aSSam Leffler 		}
7088a1b9b6aSSam Leffler 		pos = mtod(m, uint8_t *);
7098a1b9b6aSSam Leffler 		buflen = m->m_len;
7108a1b9b6aSSam Leffler 	}
7118a1b9b6aSSam Leffler 	crc = ~crc;
7128a1b9b6aSSam Leffler 
7138a1b9b6aSSam Leffler 	/* Append little-endian CRC32 and encrypt it to produce ICV */
7148a1b9b6aSSam Leffler 	icv[0] = crc;
7158a1b9b6aSSam Leffler 	icv[1] = crc >> 8;
7168a1b9b6aSSam Leffler 	icv[2] = crc >> 16;
7178a1b9b6aSSam Leffler 	icv[3] = crc >> 24;
7188a1b9b6aSSam Leffler 	for (k = 0; k < IEEE80211_WEP_CRCLEN; k++) {
7198a1b9b6aSSam Leffler 		i = (i + 1) & 0xff;
7208a1b9b6aSSam Leffler 		j = (j + S[i]) & 0xff;
7218a1b9b6aSSam Leffler 		S_SWAP(i, j);
7228a1b9b6aSSam Leffler 		icv[k] ^= S[(S[i] + S[j]) & 0xff];
7238a1b9b6aSSam Leffler 	}
7248a1b9b6aSSam Leffler }
7258a1b9b6aSSam Leffler 
7268a1b9b6aSSam Leffler static int
7278a1b9b6aSSam Leffler wep_decrypt(u8 *key, struct mbuf *m, u_int off, size_t data_len)
7288a1b9b6aSSam Leffler {
7298a1b9b6aSSam Leffler 	u32 i, j, k, crc;
7308a1b9b6aSSam Leffler 	u8 S[256];
7318a1b9b6aSSam Leffler 	u8 *pos, icv[4];
7328a1b9b6aSSam Leffler 	size_t buflen;
7338a1b9b6aSSam Leffler 
7348a1b9b6aSSam Leffler 	/* Setup RC4 state */
7358a1b9b6aSSam Leffler 	for (i = 0; i < 256; i++)
7368a1b9b6aSSam Leffler 		S[i] = i;
7378a1b9b6aSSam Leffler 	j = 0;
7388a1b9b6aSSam Leffler 	for (i = 0; i < 256; i++) {
7398a1b9b6aSSam Leffler 		j = (j + S[i] + key[i & 0x0f]) & 0xff;
7408a1b9b6aSSam Leffler 		S_SWAP(i, j);
7418a1b9b6aSSam Leffler 	}
7428a1b9b6aSSam Leffler 
7438a1b9b6aSSam Leffler 	/* Apply RC4 to data and compute CRC32 over decrypted data */
7448a1b9b6aSSam Leffler 	crc = ~0;
7458a1b9b6aSSam Leffler 	i = j = 0;
7468a1b9b6aSSam Leffler 	pos = mtod(m, uint8_t *) + off;
7478a1b9b6aSSam Leffler 	buflen = m->m_len - off;
7488a1b9b6aSSam Leffler 	for (;;) {
7498a1b9b6aSSam Leffler 		if (buflen > data_len)
7508a1b9b6aSSam Leffler 			buflen = data_len;
7518a1b9b6aSSam Leffler 		data_len -= buflen;
7528a1b9b6aSSam Leffler 		for (k = 0; k < buflen; k++) {
7538a1b9b6aSSam Leffler 			i = (i + 1) & 0xff;
7548a1b9b6aSSam Leffler 			j = (j + S[i]) & 0xff;
7558a1b9b6aSSam Leffler 			S_SWAP(i, j);
7568a1b9b6aSSam Leffler 			*pos ^= S[(S[i] + S[j]) & 0xff];
7578a1b9b6aSSam Leffler 			crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8);
7588a1b9b6aSSam Leffler 			pos++;
7598a1b9b6aSSam Leffler 		}
7608a1b9b6aSSam Leffler 		m = m->m_next;
7618a1b9b6aSSam Leffler 		if (m == NULL) {
7628a1b9b6aSSam Leffler 			KASSERT(data_len == 0,
76316574882SSam Leffler 			    ("out of buffers with data_len %zu\n", data_len));
7648a1b9b6aSSam Leffler 			break;
7658a1b9b6aSSam Leffler 		}
7668a1b9b6aSSam Leffler 		pos = mtod(m, uint8_t *);
7678a1b9b6aSSam Leffler 		buflen = m->m_len;
7688a1b9b6aSSam Leffler 	}
7698a1b9b6aSSam Leffler 	crc = ~crc;
7708a1b9b6aSSam Leffler 
7718a1b9b6aSSam Leffler 	/* Encrypt little-endian CRC32 and verify that it matches with the
7728a1b9b6aSSam Leffler 	 * received ICV */
7738a1b9b6aSSam Leffler 	icv[0] = crc;
7748a1b9b6aSSam Leffler 	icv[1] = crc >> 8;
7758a1b9b6aSSam Leffler 	icv[2] = crc >> 16;
7768a1b9b6aSSam Leffler 	icv[3] = crc >> 24;
7778a1b9b6aSSam Leffler 	for (k = 0; k < 4; k++) {
7788a1b9b6aSSam Leffler 		i = (i + 1) & 0xff;
7798a1b9b6aSSam Leffler 		j = (j + S[i]) & 0xff;
7808a1b9b6aSSam Leffler 		S_SWAP(i, j);
7818a1b9b6aSSam Leffler 		if ((icv[k] ^ S[(S[i] + S[j]) & 0xff]) != *pos++) {
7828a1b9b6aSSam Leffler 			/* ICV mismatch - drop frame */
7838a1b9b6aSSam Leffler 			return -1;
7848a1b9b6aSSam Leffler 		}
7858a1b9b6aSSam Leffler 	}
7868a1b9b6aSSam Leffler 
7878a1b9b6aSSam Leffler 	return 0;
7888a1b9b6aSSam Leffler }
7898a1b9b6aSSam Leffler 
7908a1b9b6aSSam Leffler static __inline u32 rotl(u32 val, int bits)
7918a1b9b6aSSam Leffler {
7928a1b9b6aSSam Leffler 	return (val << bits) | (val >> (32 - bits));
7938a1b9b6aSSam Leffler }
7948a1b9b6aSSam Leffler 
7958a1b9b6aSSam Leffler static __inline u32 rotr(u32 val, int bits)
7968a1b9b6aSSam Leffler {
7978a1b9b6aSSam Leffler 	return (val >> bits) | (val << (32 - bits));
7988a1b9b6aSSam Leffler }
7998a1b9b6aSSam Leffler 
8008a1b9b6aSSam Leffler static __inline u32 xswap(u32 val)
8018a1b9b6aSSam Leffler {
8028a1b9b6aSSam Leffler 	return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8);
8038a1b9b6aSSam Leffler }
8048a1b9b6aSSam Leffler 
8058a1b9b6aSSam Leffler #define michael_block(l, r)	\
8068a1b9b6aSSam Leffler do {				\
8078a1b9b6aSSam Leffler 	r ^= rotl(l, 17);	\
8088a1b9b6aSSam Leffler 	l += r;			\
8098a1b9b6aSSam Leffler 	r ^= xswap(l);		\
8108a1b9b6aSSam Leffler 	l += r;			\
8118a1b9b6aSSam Leffler 	r ^= rotl(l, 3);	\
8128a1b9b6aSSam Leffler 	l += r;			\
8138a1b9b6aSSam Leffler 	r ^= rotr(l, 2);	\
8148a1b9b6aSSam Leffler 	l += r;			\
8158a1b9b6aSSam Leffler } while (0)
8168a1b9b6aSSam Leffler 
8178a1b9b6aSSam Leffler static __inline u32 get_le32_split(u8 b0, u8 b1, u8 b2, u8 b3)
8188a1b9b6aSSam Leffler {
8198a1b9b6aSSam Leffler 	return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
8208a1b9b6aSSam Leffler }
8218a1b9b6aSSam Leffler 
8228a1b9b6aSSam Leffler static __inline u32 get_le32(const u8 *p)
8238a1b9b6aSSam Leffler {
8248a1b9b6aSSam Leffler 	return get_le32_split(p[0], p[1], p[2], p[3]);
8258a1b9b6aSSam Leffler }
8268a1b9b6aSSam Leffler 
8278a1b9b6aSSam Leffler static __inline void put_le32(u8 *p, u32 v)
8288a1b9b6aSSam Leffler {
8298a1b9b6aSSam Leffler 	p[0] = v;
8308a1b9b6aSSam Leffler 	p[1] = v >> 8;
8318a1b9b6aSSam Leffler 	p[2] = v >> 16;
8328a1b9b6aSSam Leffler 	p[3] = v >> 24;
8338a1b9b6aSSam Leffler }
8348a1b9b6aSSam Leffler 
8358a1b9b6aSSam Leffler /*
8368a1b9b6aSSam Leffler  * Craft pseudo header used to calculate the MIC.
8378a1b9b6aSSam Leffler  */
8388a1b9b6aSSam Leffler static void
8398a1b9b6aSSam Leffler michael_mic_hdr(const struct ieee80211_frame *wh0, uint8_t hdr[16])
8408a1b9b6aSSam Leffler {
8418a1b9b6aSSam Leffler 	const struct ieee80211_frame_addr4 *wh =
8428a1b9b6aSSam Leffler 		(const struct ieee80211_frame_addr4 *) wh0;
8438a1b9b6aSSam Leffler 
8448a1b9b6aSSam Leffler 	switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
8458a1b9b6aSSam Leffler 	case IEEE80211_FC1_DIR_NODS:
8468a1b9b6aSSam Leffler 		IEEE80211_ADDR_COPY(hdr, wh->i_addr1); /* DA */
8478a1b9b6aSSam Leffler 		IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr2);
8488a1b9b6aSSam Leffler 		break;
8498a1b9b6aSSam Leffler 	case IEEE80211_FC1_DIR_TODS:
8508a1b9b6aSSam Leffler 		IEEE80211_ADDR_COPY(hdr, wh->i_addr3); /* DA */
8518a1b9b6aSSam Leffler 		IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr2);
8528a1b9b6aSSam Leffler 		break;
8538a1b9b6aSSam Leffler 	case IEEE80211_FC1_DIR_FROMDS:
8548a1b9b6aSSam Leffler 		IEEE80211_ADDR_COPY(hdr, wh->i_addr1); /* DA */
8558a1b9b6aSSam Leffler 		IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr3);
8568a1b9b6aSSam Leffler 		break;
8578a1b9b6aSSam Leffler 	case IEEE80211_FC1_DIR_DSTODS:
8588a1b9b6aSSam Leffler 		IEEE80211_ADDR_COPY(hdr, wh->i_addr3); /* DA */
8598a1b9b6aSSam Leffler 		IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr4);
8608a1b9b6aSSam Leffler 		break;
8618a1b9b6aSSam Leffler 	}
8628a1b9b6aSSam Leffler 
863*37e54466SAdrian Chadd 	/* Match on any QOS frame, not just data */
864*37e54466SAdrian Chadd 	if (IEEE80211_IS_QOS_ANY(wh)) {
865ecca7ea2SSam Leffler 		const struct ieee80211_qosframe *qwh =
866ecca7ea2SSam Leffler 			(const struct ieee80211_qosframe *) wh;
867ecca7ea2SSam Leffler 		hdr[12] = qwh->i_qos[0] & IEEE80211_QOS_TID;
868ecca7ea2SSam Leffler 	} else
869ecca7ea2SSam Leffler 		hdr[12] = 0;
8708a1b9b6aSSam Leffler 	hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */
8718a1b9b6aSSam Leffler }
8728a1b9b6aSSam Leffler 
8738a1b9b6aSSam Leffler static void
8748a1b9b6aSSam Leffler michael_mic(struct tkip_ctx *ctx, const u8 *key,
8758a1b9b6aSSam Leffler 	struct mbuf *m, u_int off, size_t data_len,
8768a1b9b6aSSam Leffler 	u8 mic[IEEE80211_WEP_MICLEN])
8778a1b9b6aSSam Leffler {
8788a1b9b6aSSam Leffler 	uint8_t hdr[16];
8798a1b9b6aSSam Leffler 	u32 l, r;
8808a1b9b6aSSam Leffler 	const uint8_t *data;
8818a1b9b6aSSam Leffler 	u_int space;
8828a1b9b6aSSam Leffler 
8838a1b9b6aSSam Leffler 	michael_mic_hdr(mtod(m, struct ieee80211_frame *), hdr);
8848a1b9b6aSSam Leffler 
8858a1b9b6aSSam Leffler 	l = get_le32(key);
8868a1b9b6aSSam Leffler 	r = get_le32(key + 4);
8878a1b9b6aSSam Leffler 
8888a1b9b6aSSam Leffler 	/* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */
8898a1b9b6aSSam Leffler 	l ^= get_le32(hdr);
8908a1b9b6aSSam Leffler 	michael_block(l, r);
8918a1b9b6aSSam Leffler 	l ^= get_le32(&hdr[4]);
8928a1b9b6aSSam Leffler 	michael_block(l, r);
8938a1b9b6aSSam Leffler 	l ^= get_le32(&hdr[8]);
8948a1b9b6aSSam Leffler 	michael_block(l, r);
8958a1b9b6aSSam Leffler 	l ^= get_le32(&hdr[12]);
8968a1b9b6aSSam Leffler 	michael_block(l, r);
8978a1b9b6aSSam Leffler 
8988a1b9b6aSSam Leffler 	/* first buffer has special handling */
8998a1b9b6aSSam Leffler 	data = mtod(m, const uint8_t *) + off;
9008a1b9b6aSSam Leffler 	space = m->m_len - off;
9018a1b9b6aSSam Leffler 	for (;;) {
9028a1b9b6aSSam Leffler 		if (space > data_len)
9038a1b9b6aSSam Leffler 			space = data_len;
9048a1b9b6aSSam Leffler 		/* collect 32-bit blocks from current buffer */
9058a1b9b6aSSam Leffler 		while (space >= sizeof(uint32_t)) {
9068a1b9b6aSSam Leffler 			l ^= get_le32(data);
9078a1b9b6aSSam Leffler 			michael_block(l, r);
9088a1b9b6aSSam Leffler 			data += sizeof(uint32_t), space -= sizeof(uint32_t);
9098a1b9b6aSSam Leffler 			data_len -= sizeof(uint32_t);
9108a1b9b6aSSam Leffler 		}
91102a1ebb4SSam Leffler 		/*
91202a1ebb4SSam Leffler 		 * NB: when space is zero we make one more trip around
91302a1ebb4SSam Leffler 		 * the loop to advance to the next mbuf where there is
91402a1ebb4SSam Leffler 		 * data.  This handles the case where there are 4*n
91502a1ebb4SSam Leffler 		 * bytes in an mbuf followed by <4 bytes in a later mbuf.
91602a1ebb4SSam Leffler 		 * By making an extra trip we'll drop out of the loop
91702a1ebb4SSam Leffler 		 * with m pointing at the mbuf with 3 bytes and space
91802a1ebb4SSam Leffler 		 * set as required by the remainder handling below.
91902a1ebb4SSam Leffler 		 */
92002a1ebb4SSam Leffler 		if (data_len == 0 ||
92102a1ebb4SSam Leffler 		    (data_len < sizeof(uint32_t) && space != 0))
9228a1b9b6aSSam Leffler 			break;
9238a1b9b6aSSam Leffler 		m = m->m_next;
9248a1b9b6aSSam Leffler 		if (m == NULL) {
92516574882SSam Leffler 			KASSERT(0, ("out of data, data_len %zu\n", data_len));
9268a1b9b6aSSam Leffler 			break;
9278a1b9b6aSSam Leffler 		}
9288a1b9b6aSSam Leffler 		if (space != 0) {
9298a1b9b6aSSam Leffler 			const uint8_t *data_next;
9308a1b9b6aSSam Leffler 			/*
9318a1b9b6aSSam Leffler 			 * Block straddles buffers, split references.
9328a1b9b6aSSam Leffler 			 */
9338a1b9b6aSSam Leffler 			data_next = mtod(m, const uint8_t *);
9348a1b9b6aSSam Leffler 			KASSERT(m->m_len >= sizeof(uint32_t) - space,
9358a1b9b6aSSam Leffler 				("not enough data in following buffer, "
93616574882SSam Leffler 				"m_len %u need %zu\n", m->m_len,
9378a1b9b6aSSam Leffler 				sizeof(uint32_t) - space));
9388a1b9b6aSSam Leffler 			switch (space) {
9398a1b9b6aSSam Leffler 			case 1:
9408a1b9b6aSSam Leffler 				l ^= get_le32_split(data[0], data_next[0],
9418a1b9b6aSSam Leffler 					data_next[1], data_next[2]);
9428a1b9b6aSSam Leffler 				data = data_next + 3;
9438a1b9b6aSSam Leffler 				space = m->m_len - 3;
9448a1b9b6aSSam Leffler 				break;
9458a1b9b6aSSam Leffler 			case 2:
9468a1b9b6aSSam Leffler 				l ^= get_le32_split(data[0], data[1],
9478a1b9b6aSSam Leffler 					data_next[0], data_next[1]);
9488a1b9b6aSSam Leffler 				data = data_next + 2;
9498a1b9b6aSSam Leffler 				space = m->m_len - 2;
9508a1b9b6aSSam Leffler 				break;
9518a1b9b6aSSam Leffler 			case 3:
9528a1b9b6aSSam Leffler 				l ^= get_le32_split(data[0], data[1],
9538a1b9b6aSSam Leffler 					data[2], data_next[0]);
9548a1b9b6aSSam Leffler 				data = data_next + 1;
9558a1b9b6aSSam Leffler 				space = m->m_len - 1;
9568a1b9b6aSSam Leffler 				break;
9578a1b9b6aSSam Leffler 			}
9588a1b9b6aSSam Leffler 			michael_block(l, r);
9598a1b9b6aSSam Leffler 			data_len -= sizeof(uint32_t);
9608a1b9b6aSSam Leffler 		} else {
9618a1b9b6aSSam Leffler 			/*
9628a1b9b6aSSam Leffler 			 * Setup for next buffer.
9638a1b9b6aSSam Leffler 			 */
9648a1b9b6aSSam Leffler 			data = mtod(m, const uint8_t *);
9658a1b9b6aSSam Leffler 			space = m->m_len;
9668a1b9b6aSSam Leffler 		}
9678a1b9b6aSSam Leffler 	}
96802a1ebb4SSam Leffler 	/*
96902a1ebb4SSam Leffler 	 * Catch degenerate cases like mbuf[4*n+1 bytes] followed by
97002a1ebb4SSam Leffler 	 * mbuf[2 bytes].  I don't believe these should happen; if they
97102a1ebb4SSam Leffler 	 * do then we'll need more involved logic.
97202a1ebb4SSam Leffler 	 */
97302a1ebb4SSam Leffler 	KASSERT(data_len <= space,
9742bc01c3aSTai-hwa Liang 	    ("not enough data, data_len %zu space %u\n", data_len, space));
97502a1ebb4SSam Leffler 
9768a1b9b6aSSam Leffler 	/* Last block and padding (0x5a, 4..7 x 0) */
9778a1b9b6aSSam Leffler 	switch (data_len) {
9788a1b9b6aSSam Leffler 	case 0:
9798a1b9b6aSSam Leffler 		l ^= get_le32_split(0x5a, 0, 0, 0);
9808a1b9b6aSSam Leffler 		break;
9818a1b9b6aSSam Leffler 	case 1:
9828a1b9b6aSSam Leffler 		l ^= get_le32_split(data[0], 0x5a, 0, 0);
9838a1b9b6aSSam Leffler 		break;
9848a1b9b6aSSam Leffler 	case 2:
9858a1b9b6aSSam Leffler 		l ^= get_le32_split(data[0], data[1], 0x5a, 0);
9868a1b9b6aSSam Leffler 		break;
9878a1b9b6aSSam Leffler 	case 3:
9888a1b9b6aSSam Leffler 		l ^= get_le32_split(data[0], data[1], data[2], 0x5a);
9898a1b9b6aSSam Leffler 		break;
9908a1b9b6aSSam Leffler 	}
9918a1b9b6aSSam Leffler 	michael_block(l, r);
9928a1b9b6aSSam Leffler 	/* l ^= 0; */
9938a1b9b6aSSam Leffler 	michael_block(l, r);
9948a1b9b6aSSam Leffler 
9958a1b9b6aSSam Leffler 	put_le32(mic, l);
9968a1b9b6aSSam Leffler 	put_le32(mic + 4, r);
9978a1b9b6aSSam Leffler }
9988a1b9b6aSSam Leffler 
9998a1b9b6aSSam Leffler static int
10008a1b9b6aSSam Leffler tkip_encrypt(struct tkip_ctx *ctx, struct ieee80211_key *key,
10018a1b9b6aSSam Leffler 	struct mbuf *m, int hdrlen)
10028a1b9b6aSSam Leffler {
10038a1b9b6aSSam Leffler 	struct ieee80211_frame *wh;
10048a1b9b6aSSam Leffler 	uint8_t icv[IEEE80211_WEP_CRCLEN];
10058a1b9b6aSSam Leffler 
1006b032f27cSSam Leffler 	ctx->tc_vap->iv_stats.is_crypto_tkip++;
10078a1b9b6aSSam Leffler 
10088a1b9b6aSSam Leffler 	wh = mtod(m, struct ieee80211_frame *);
1009483755beSAdrian Chadd 	if ((u16)(key->wk_keytsc) == 0 || key->wk_keytsc == 1) {
10108a1b9b6aSSam Leffler 		tkip_mixing_phase1(ctx->tx_ttak, key->wk_key, wh->i_addr2,
10118a1b9b6aSSam Leffler 				   (u32)(key->wk_keytsc >> 16));
10128a1b9b6aSSam Leffler 	}
10138a1b9b6aSSam Leffler 	tkip_mixing_phase2(ctx->tx_rc4key, key->wk_key, ctx->tx_ttak,
10148a1b9b6aSSam Leffler 		(u16) key->wk_keytsc);
10158a1b9b6aSSam Leffler 
10168a1b9b6aSSam Leffler 	wep_encrypt(ctx->tx_rc4key,
10178a1b9b6aSSam Leffler 		m, hdrlen + tkip.ic_header,
10188a1b9b6aSSam Leffler 		m->m_pkthdr.len - (hdrlen + tkip.ic_header),
10198a1b9b6aSSam Leffler 		icv);
10208a1b9b6aSSam Leffler 	(void) m_append(m, IEEE80211_WEP_CRCLEN, icv);	/* XXX check return */
10218a1b9b6aSSam Leffler 
10228a1b9b6aSSam Leffler 	return 1;
10238a1b9b6aSSam Leffler }
10248a1b9b6aSSam Leffler 
10258a1b9b6aSSam Leffler static int
10268a1b9b6aSSam Leffler tkip_decrypt(struct tkip_ctx *ctx, struct ieee80211_key *key,
10278a1b9b6aSSam Leffler 	struct mbuf *m, int hdrlen)
10288a1b9b6aSSam Leffler {
10298a1b9b6aSSam Leffler 	struct ieee80211_frame *wh;
1030b032f27cSSam Leffler 	struct ieee80211vap *vap = ctx->tc_vap;
10318a1b9b6aSSam Leffler 	u32 iv32;
10328a1b9b6aSSam Leffler 	u16 iv16;
1033b032f27cSSam Leffler 	u8 tid;
10348a1b9b6aSSam Leffler 
1035b032f27cSSam Leffler 	vap->iv_stats.is_crypto_tkip++;
10368a1b9b6aSSam Leffler 
10378a1b9b6aSSam Leffler 	wh = mtod(m, struct ieee80211_frame *);
10388a1b9b6aSSam Leffler 	/* NB: tkip_decap already verified header and left seq in rx_rsc */
10398a1b9b6aSSam Leffler 	iv16 = (u16) ctx->rx_rsc;
10408a1b9b6aSSam Leffler 	iv32 = (u32) (ctx->rx_rsc >> 16);
10418a1b9b6aSSam Leffler 
1042b032f27cSSam Leffler 	tid = ieee80211_gettid(wh);
1043b032f27cSSam Leffler 	if (iv32 != (u32)(key->wk_keyrsc[tid] >> 16) || !ctx->rx_phase1_done) {
10448a1b9b6aSSam Leffler 		tkip_mixing_phase1(ctx->rx_ttak, key->wk_key,
10458a1b9b6aSSam Leffler 			wh->i_addr2, iv32);
10468a1b9b6aSSam Leffler 		ctx->rx_phase1_done = 1;
10478a1b9b6aSSam Leffler 	}
10488a1b9b6aSSam Leffler 	tkip_mixing_phase2(ctx->rx_rc4key, key->wk_key, ctx->rx_ttak, iv16);
10498a1b9b6aSSam Leffler 
10508a1b9b6aSSam Leffler 	/* NB: m is unstripped; deduct headers + ICV to get payload */
10518a1b9b6aSSam Leffler 	if (wep_decrypt(ctx->rx_rc4key,
10528a1b9b6aSSam Leffler 		m, hdrlen + tkip.ic_header,
10538a1b9b6aSSam Leffler 	        m->m_pkthdr.len - (hdrlen + tkip.ic_header + tkip.ic_trailer))) {
1054b032f27cSSam Leffler 		if (iv32 != (u32)(key->wk_keyrsc[tid] >> 16)) {
10558a1b9b6aSSam Leffler 			/* Previously cached Phase1 result was already lost, so
10568a1b9b6aSSam Leffler 			 * it needs to be recalculated for the next packet. */
10578a1b9b6aSSam Leffler 			ctx->rx_phase1_done = 0;
10588a1b9b6aSSam Leffler 		}
1059b032f27cSSam Leffler 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
1060b032f27cSSam Leffler 		    "%s", "TKIP ICV mismatch on decrypt");
1061b032f27cSSam Leffler 		vap->iv_stats.is_rx_tkipicv++;
10628a1b9b6aSSam Leffler 		return 0;
10638a1b9b6aSSam Leffler 	}
10648a1b9b6aSSam Leffler 	return 1;
10658a1b9b6aSSam Leffler }
10668a1b9b6aSSam Leffler 
10678a1b9b6aSSam Leffler /*
10688a1b9b6aSSam Leffler  * Module glue.
10698a1b9b6aSSam Leffler  */
107068e8e04eSSam Leffler IEEE80211_CRYPTO_MODULE(tkip, 1);
1071