Home | History | Annotate | Line # | Download | only in net80211
ieee80211_crypto_wep.c revision 1.12.2.2
      1 /*	$NetBSD: ieee80211_crypto_wep.c,v 1.12.2.2 2018/07/12 16:35:34 phil Exp $ */
      2 
      3 /*-
      4  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
      5  *
      6  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
      7  * All rights reserved.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 #include <sys/cdefs.h>
     31 #if  __FreeBSD__
     32 __FBSDID("$FreeBSD$");
     33 #endif
     34 
     35 /*
     36  * IEEE 802.11 WEP crypto support.
     37  */
     38 #include "opt_wlan.h"
     39 
     40 #include <sys/param.h>
     41 #include <sys/systm.h>
     42 #include <sys/mbuf.h>
     43 #include <sys/malloc.h>
     44 #include <sys/kernel.h>
     45 #include <sys/module.h>
     46 #include <sys/endian.h>
     47 
     48 #include <sys/socket.h>
     49 
     50 #include <net/if.h>
     51 #include <net/if_media.h>
     52 #if  __FreeBSD__
     53 #include <net/ethernet.h>
     54 #endif
     55 #ifdef __NetBSD__
     56 #include <net/route.h>
     57 #endif
     58 
     59 #include <net80211/ieee80211_var.h>
     60 
     61 #ifdef __NetBSD__
     62 #undef  KASSERT
     63 #define KASSERT(__cond, __complaint) FBSDKASSERT(__cond, __complaint)
     64 #endif
     65 
     66 static	void *wep_attach(struct ieee80211vap *, struct ieee80211_key *);
     67 static	void wep_detach(struct ieee80211_key *);
     68 static	int wep_setkey(struct ieee80211_key *);
     69 static	void wep_setiv(struct ieee80211_key *, uint8_t *);
     70 static	int wep_encap(struct ieee80211_key *, struct mbuf *);
     71 static	int wep_decap(struct ieee80211_key *, struct mbuf *, int);
     72 static	int wep_enmic(struct ieee80211_key *, struct mbuf *, int);
     73 static	int wep_demic(struct ieee80211_key *, struct mbuf *, int);
     74 
     75 static const struct ieee80211_cipher wep = {
     76 	.ic_name	= "WEP",
     77 	.ic_cipher	= IEEE80211_CIPHER_WEP,
     78 	.ic_header	= IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN,
     79 	.ic_trailer	= IEEE80211_WEP_CRCLEN,
     80 	.ic_miclen	= 0,
     81 	.ic_attach	= wep_attach,
     82 	.ic_detach	= wep_detach,
     83 	.ic_setkey	= wep_setkey,
     84 	.ic_setiv	= wep_setiv,
     85 	.ic_encap	= wep_encap,
     86 	.ic_decap	= wep_decap,
     87 	.ic_enmic	= wep_enmic,
     88 	.ic_demic	= wep_demic,
     89 };
     90 
     91 static	int wep_encrypt(struct ieee80211_key *, struct mbuf *, int hdrlen);
     92 static	int wep_decrypt(struct ieee80211_key *, struct mbuf *, int hdrlen);
     93 
     94 struct wep_ctx {
     95 	struct ieee80211vap *wc_vap;	/* for diagnostics+statistics */
     96 	struct ieee80211com *wc_ic;
     97 	uint32_t	wc_iv;		/* initial vector for crypto */
     98 };
     99 
    100 /* number of references from net80211 layer */
    101 static	int nrefs = 0;
    102 
    103 static void *
    104 wep_attach(struct ieee80211vap *vap, struct ieee80211_key *k)
    105 {
    106 	struct wep_ctx *ctx;
    107 
    108 	ctx = (struct wep_ctx *) IEEE80211_MALLOC(sizeof(struct wep_ctx),
    109 		M_80211_CRYPTO, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
    110 	if (ctx == NULL) {
    111 		vap->iv_stats.is_crypto_nomem++;
    112 		return NULL;
    113 	}
    114 
    115 	ctx->wc_vap = vap;
    116 	ctx->wc_ic = vap->iv_ic;
    117 	get_random_bytes(&ctx->wc_iv, sizeof(ctx->wc_iv));
    118 	nrefs++;			/* NB: we assume caller locking */
    119 	return ctx;
    120 }
    121 
    122 static void
    123 wep_detach(struct ieee80211_key *k)
    124 {
    125 	struct wep_ctx *ctx = k->wk_private;
    126 
    127 	IEEE80211_FREE(ctx, M_80211_CRYPTO);
    128 	KASSERT(nrefs > 0, ("imbalanced attach/detach"));
    129 	nrefs--;			/* NB: we assume caller locking */
    130 }
    131 
    132 static int
    133 wep_setkey(struct ieee80211_key *k)
    134 {
    135 	return k->wk_keylen >= 40/NBBY;
    136 }
    137 
    138 static void
    139 wep_setiv(struct ieee80211_key *k, uint8_t *ivp)
    140 {
    141 	struct wep_ctx *ctx = k->wk_private;
    142 	struct ieee80211vap *vap = ctx->wc_vap;
    143 	uint32_t iv;
    144 	uint8_t keyid;
    145 
    146 	keyid = ieee80211_crypto_get_keyid(vap, k) << 6;
    147 
    148 	/*
    149 	 * XXX
    150 	 * IV must not duplicate during the lifetime of the key.
    151 	 * But no mechanism to renew keys is defined in IEEE 802.11
    152 	 * for WEP.  And the IV may be duplicated at other stations
    153 	 * because the session key itself is shared.  So we use a
    154 	 * pseudo random IV for now, though it is not the right way.
    155 	 *
    156 	 * NB: Rather than use a strictly random IV we select a
    157 	 * random one to start and then increment the value for
    158 	 * each frame.  This is an explicit tradeoff between
    159 	 * overhead and security.  Given the basic insecurity of
    160 	 * WEP this seems worthwhile.
    161 	 */
    162 
    163 	/*
    164 	 * Skip 'bad' IVs from Fluhrer/Mantin/Shamir:
    165 	 * (B, 255, N) with 3 <= B < 16 and 0 <= N <= 255
    166 	 */
    167 	iv = ctx->wc_iv;
    168 	if ((iv & 0xff00) == 0xff00) {
    169 		int B = (iv & 0xff0000) >> 16;
    170 		if (3 <= B && B < 16)
    171 			iv += 0x0100;
    172 	}
    173 	ctx->wc_iv = iv + 1;
    174 
    175 	/*
    176 	 * NB: Preserve byte order of IV for packet
    177 	 *     sniffers; it doesn't matter otherwise.
    178 	 */
    179 #if _BYTE_ORDER == _BIG_ENDIAN
    180 	ivp[0] = iv >> 0;
    181 	ivp[1] = iv >> 8;
    182 	ivp[2] = iv >> 16;
    183 #else
    184 	ivp[2] = iv >> 0;
    185 	ivp[1] = iv >> 8;
    186 	ivp[0] = iv >> 16;
    187 #endif
    188 	ivp[3] = keyid;
    189 }
    190 
    191 /*
    192  * Add privacy headers appropriate for the specified key.
    193  */
    194 static int
    195 wep_encap(struct ieee80211_key *k, struct mbuf *m)
    196 {
    197 	struct wep_ctx *ctx = k->wk_private;
    198 	struct ieee80211com *ic = ctx->wc_ic;
    199 	struct ieee80211_frame *wh;
    200 	uint8_t *ivp;
    201 	int hdrlen;
    202 	int is_mgmt;
    203 
    204 	hdrlen = ieee80211_hdrspace(ic, mtod(m, void *));
    205 	wh = mtod(m, struct ieee80211_frame *);
    206 	is_mgmt = IEEE80211_IS_MGMT(wh);
    207 
    208 	/*
    209 	 * Check to see if IV is required.
    210 	 */
    211 	if (is_mgmt && (k->wk_flags & IEEE80211_KEY_NOIVMGT))
    212 		return 1;
    213 	if ((! is_mgmt) && (k->wk_flags & IEEE80211_KEY_NOIV))
    214 		return 1;
    215 
    216 	/*
    217 	 * Copy down 802.11 header and add the IV + KeyID.
    218 	 */
    219 	M_PREPEND(m, wep.ic_header, M_NOWAIT);
    220 	if (m == NULL)
    221 		return 0;
    222 	ivp = mtod(m, uint8_t *);
    223 	ovbcopy(ivp + wep.ic_header, ivp, hdrlen);
    224 	ivp += hdrlen;
    225 
    226 	wep_setiv(k, ivp);
    227 
    228 	/*
    229 	 * Finally, do software encrypt if needed.
    230 	 */
    231 	if ((k->wk_flags & IEEE80211_KEY_SWENCRYPT) &&
    232 	    !wep_encrypt(k, m, hdrlen))
    233 		return 0;
    234 
    235 	return 1;
    236 }
    237 
    238 /*
    239  * Add MIC to the frame as needed.
    240  */
    241 static int
    242 wep_enmic(struct ieee80211_key *k, struct mbuf *m, int force)
    243 {
    244 
    245 	return 1;
    246 }
    247 
    248 /*
    249  * Validate and strip privacy headers (and trailer) for a
    250  * received frame.  If necessary, decrypt the frame using
    251  * the specified key.
    252  */
    253 static int
    254 wep_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen)
    255 {
    256 	struct wep_ctx *ctx = k->wk_private;
    257 	struct ieee80211vap *vap = ctx->wc_vap;
    258 #if  __FreeBSD__
    259 	struct ieee80211_frame *wh;
    260 #elif __NetBSD__
    261 	/* Compiler complains even though it looks used below. */
    262 	struct ieee80211_frame *wh __unused;
    263 #endif
    264 	const struct ieee80211_rx_stats *rxs;
    265 
    266 	wh = mtod(m, struct ieee80211_frame *);
    267 
    268 	rxs = ieee80211_get_rx_params_ptr(m);
    269 
    270 	if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP))
    271 		goto finish;
    272 
    273 	/*
    274 	 * Check if the device handled the decrypt in hardware.
    275 	 * If so we just strip the header; otherwise we need to
    276 	 * handle the decrypt in software.
    277 	 */
    278 	if ((k->wk_flags & IEEE80211_KEY_SWDECRYPT) &&
    279 	    !wep_decrypt(k, m, hdrlen)) {
    280 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
    281 		    "%s", "WEP ICV mismatch on decrypt");
    282 		vap->iv_stats.is_rx_wepfail++;
    283 		return 0;
    284 	}
    285 
    286 	/*
    287 	 * Copy up 802.11 header and strip crypto bits.
    288 	 */
    289 	ovbcopy(mtod(m, void *), mtod(m, uint8_t *) + wep.ic_header, hdrlen);
    290 	m_adj(m, wep.ic_header);
    291 
    292 finish:
    293 	/* XXX TODO: do we have to strip this for offload devices? */
    294 	m_adj(m, -wep.ic_trailer);
    295 
    296 	return 1;
    297 }
    298 
    299 /*
    300  * Verify and strip MIC from the frame.
    301  */
    302 static int
    303 wep_demic(struct ieee80211_key *k, struct mbuf *skb, int force)
    304 {
    305 	return 1;
    306 }
    307 
    308 static const uint32_t crc32_table[256] = {
    309 	0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
    310 	0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
    311 	0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
    312 	0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
    313 	0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
    314 	0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
    315 	0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
    316 	0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
    317 	0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
    318 	0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
    319 	0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
    320 	0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
    321 	0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
    322 	0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
    323 	0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
    324 	0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
    325 	0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
    326 	0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
    327 	0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
    328 	0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
    329 	0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
    330 	0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
    331 	0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
    332 	0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
    333 	0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
    334 	0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
    335 	0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
    336 	0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
    337 	0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
    338 	0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
    339 	0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
    340 	0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
    341 	0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
    342 	0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
    343 	0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
    344 	0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
    345 	0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
    346 	0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
    347 	0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
    348 	0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
    349 	0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
    350 	0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
    351 	0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
    352 	0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
    353 	0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
    354 	0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
    355 	0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
    356 	0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
    357 	0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
    358 	0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
    359 	0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
    360 	0x2d02ef8dL
    361 };
    362 
    363 static int
    364 wep_encrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
    365 {
    366 #define S_SWAP(a,b) do { uint8_t t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
    367 	struct wep_ctx *ctx = key->wk_private;
    368 	struct ieee80211vap *vap = ctx->wc_vap;
    369 	struct mbuf *m = m0;
    370 	uint8_t rc4key[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE];
    371 	uint8_t icv[IEEE80211_WEP_CRCLEN];
    372 	uint32_t i, j, k, crc;
    373 	size_t buflen, data_len;
    374 	uint8_t S[256];
    375 	uint8_t *pos;
    376 	u_int off, keylen;
    377 
    378 	vap->iv_stats.is_crypto_wep++;
    379 
    380 	/* NB: this assumes the header was pulled up */
    381 	memcpy(rc4key, mtod(m, uint8_t *) + hdrlen, IEEE80211_WEP_IVLEN);
    382 	memcpy(rc4key + IEEE80211_WEP_IVLEN, key->wk_key, key->wk_keylen);
    383 
    384 	/* Setup RC4 state */
    385 	for (i = 0; i < 256; i++)
    386 		S[i] = i;
    387 	j = 0;
    388 	keylen = key->wk_keylen + IEEE80211_WEP_IVLEN;
    389 	for (i = 0; i < 256; i++) {
    390 		j = (j + S[i] + rc4key[i % keylen]) & 0xff;
    391 		S_SWAP(i, j);
    392 	}
    393 
    394 	off = hdrlen + wep.ic_header;
    395 	data_len = m->m_pkthdr.len - off;
    396 
    397 	/* Compute CRC32 over unencrypted data and apply RC4 to data */
    398 	crc = ~0;
    399 	i = j = 0;
    400 	pos = mtod(m, uint8_t *) + off;
    401 	buflen = m->m_len - off;
    402 	for (;;) {
    403 		if (buflen > data_len)
    404 			buflen = data_len;
    405 		data_len -= buflen;
    406 		for (k = 0; k < buflen; k++) {
    407 			crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8);
    408 			i = (i + 1) & 0xff;
    409 			j = (j + S[i]) & 0xff;
    410 			S_SWAP(i, j);
    411 			*pos++ ^= S[(S[i] + S[j]) & 0xff];
    412 		}
    413 		if (m->m_next == NULL) {
    414 			if (data_len != 0) {		/* out of data */
    415 				IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO,
    416 				    ether_sprintf(mtod(m0,
    417 					struct ieee80211_frame *)->i_addr2),
    418 				    "out of data for WEP (data_len %zu)",
    419 				    data_len);
    420 				/* XXX stat */
    421 				return 0;
    422 			}
    423 			break;
    424 		}
    425 		m = m->m_next;
    426 		pos = mtod(m, uint8_t *);
    427 		buflen = m->m_len;
    428 	}
    429 	crc = ~crc;
    430 
    431 	/* Append little-endian CRC32 and encrypt it to produce ICV */
    432 	icv[0] = crc;
    433 	icv[1] = crc >> 8;
    434 	icv[2] = crc >> 16;
    435 	icv[3] = crc >> 24;
    436 	for (k = 0; k < IEEE80211_WEP_CRCLEN; k++) {
    437 		i = (i + 1) & 0xff;
    438 		j = (j + S[i]) & 0xff;
    439 		S_SWAP(i, j);
    440 		icv[k] ^= S[(S[i] + S[j]) & 0xff];
    441 	}
    442 	return m_append(m0, IEEE80211_WEP_CRCLEN, icv);
    443 #undef S_SWAP
    444 }
    445 
    446 static int
    447 wep_decrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
    448 {
    449 #define S_SWAP(a,b) do { uint8_t t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
    450 	struct wep_ctx *ctx = key->wk_private;
    451 	struct ieee80211vap *vap = ctx->wc_vap;
    452 	struct mbuf *m = m0;
    453 	uint8_t rc4key[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE];
    454 	uint8_t icv[IEEE80211_WEP_CRCLEN];
    455 	uint32_t i, j, k, crc;
    456 	size_t buflen, data_len;
    457 	uint8_t S[256];
    458 	uint8_t *pos;
    459 	u_int off, keylen;
    460 
    461 	vap->iv_stats.is_crypto_wep++;
    462 
    463 	/* NB: this assumes the header was pulled up */
    464 	memcpy(rc4key, mtod(m, uint8_t *) + hdrlen, IEEE80211_WEP_IVLEN);
    465 	memcpy(rc4key + IEEE80211_WEP_IVLEN, key->wk_key, key->wk_keylen);
    466 
    467 	/* Setup RC4 state */
    468 	for (i = 0; i < 256; i++)
    469 		S[i] = i;
    470 	j = 0;
    471 	keylen = key->wk_keylen + IEEE80211_WEP_IVLEN;
    472 	for (i = 0; i < 256; i++) {
    473 		j = (j + S[i] + rc4key[i % keylen]) & 0xff;
    474 		S_SWAP(i, j);
    475 	}
    476 
    477 	off = hdrlen + wep.ic_header;
    478 	data_len = m->m_pkthdr.len - (off + wep.ic_trailer);
    479 
    480 	/* Compute CRC32 over unencrypted data and apply RC4 to data */
    481 	crc = ~0;
    482 	i = j = 0;
    483 	pos = mtod(m, uint8_t *) + off;
    484 	buflen = m->m_len - off;
    485 	for (;;) {
    486 		if (buflen > data_len)
    487 			buflen = data_len;
    488 		data_len -= buflen;
    489 		for (k = 0; k < buflen; k++) {
    490 			i = (i + 1) & 0xff;
    491 			j = (j + S[i]) & 0xff;
    492 			S_SWAP(i, j);
    493 			*pos ^= S[(S[i] + S[j]) & 0xff];
    494 			crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8);
    495 			pos++;
    496 		}
    497 		m = m->m_next;
    498 		if (m == NULL) {
    499 			if (data_len != 0) {		/* out of data */
    500 				IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO,
    501 				    mtod(m0, struct ieee80211_frame *)->i_addr2,
    502 				    "out of data for WEP (data_len %zu)",
    503 				    data_len);
    504 				return 0;
    505 			}
    506 			break;
    507 		}
    508 		pos = mtod(m, uint8_t *);
    509 		buflen = m->m_len;
    510 	}
    511 	crc = ~crc;
    512 
    513 	/* Encrypt little-endian CRC32 and verify that it matches with
    514 	 * received ICV */
    515 	icv[0] = crc;
    516 	icv[1] = crc >> 8;
    517 	icv[2] = crc >> 16;
    518 	icv[3] = crc >> 24;
    519 	for (k = 0; k < IEEE80211_WEP_CRCLEN; k++) {
    520 		i = (i + 1) & 0xff;
    521 		j = (j + S[i]) & 0xff;
    522 		S_SWAP(i, j);
    523 		/* XXX assumes ICV is contiguous in mbuf */
    524 		if ((icv[k] ^ S[(S[i] + S[j]) & 0xff]) != *pos++) {
    525 			/* ICV mismatch - drop frame */
    526 			return 0;
    527 		}
    528 	}
    529 	return 1;
    530 #undef S_SWAP
    531 }
    532 
    533 /*
    534  * Module glue.
    535  */
    536 IEEE80211_CRYPTO_MODULE(wep, 1);
    537