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