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