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