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