]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/net80211/ieee80211_crypto_wep.c
libucl: import snapshot 2024-02-06
[FreeBSD/FreeBSD.git] / sys / net80211 / ieee80211_crypto_wep.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
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 /*
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         net80211_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, IEEE80211_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         const struct ieee80211_rx_stats *rxs;
243
244         rxs = ieee80211_get_rx_params_ptr(m);
245
246         if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP))
247                 goto finish;
248
249         /*
250          * Check if the device handled the decrypt in hardware.
251          * If so we just strip the header; otherwise we need to
252          * handle the decrypt in software.
253          */
254         if ((k->wk_flags & IEEE80211_KEY_SWDECRYPT) &&
255             !wep_decrypt(k, m, hdrlen)) {
256 #ifdef IEEE80211_DEBUG
257                 struct ieee80211_frame *wh;
258
259                 wh = mtod(m, struct ieee80211_frame *);
260 #endif
261                 IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
262                     "%s", "WEP ICV mismatch on decrypt");
263                 vap->iv_stats.is_rx_wepfail++;
264                 return 0;
265         }
266
267         /*
268          * Copy up 802.11 header and strip crypto bits.
269          */
270         ovbcopy(mtod(m, void *), mtod(m, uint8_t *) + wep.ic_header, hdrlen);
271         m_adj(m, wep.ic_header);
272
273 finish:
274         /* XXX TODO: do we have to strip this for offload devices? */
275         m_adj(m, -wep.ic_trailer);
276
277         return 1;
278 }
279
280 /*
281  * Verify and strip MIC from the frame.
282  */
283 static int
284 wep_demic(struct ieee80211_key *k, struct mbuf *skb, int force)
285 {
286         return 1;
287 }
288
289 static const uint32_t crc32_table[256] = {
290         0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
291         0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
292         0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
293         0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
294         0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
295         0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
296         0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
297         0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
298         0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
299         0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
300         0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
301         0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
302         0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
303         0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
304         0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
305         0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
306         0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
307         0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
308         0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
309         0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
310         0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
311         0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
312         0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
313         0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
314         0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
315         0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
316         0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
317         0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
318         0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
319         0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
320         0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
321         0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
322         0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
323         0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
324         0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
325         0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
326         0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
327         0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
328         0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
329         0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
330         0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
331         0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
332         0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
333         0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
334         0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
335         0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
336         0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
337         0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
338         0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
339         0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
340         0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
341         0x2d02ef8dL
342 };
343
344 static int
345 wep_encrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
346 {
347 #define S_SWAP(a,b) do { uint8_t t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
348         struct wep_ctx *ctx = key->wk_private;
349         struct ieee80211vap *vap = ctx->wc_vap;
350         struct mbuf *m = m0;
351         uint8_t rc4key[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE];
352         uint8_t icv[IEEE80211_WEP_CRCLEN];
353         uint32_t i, j, k, crc;
354         size_t buflen, data_len;
355         uint8_t S[256];
356         uint8_t *pos;
357         u_int off, keylen;
358
359         vap->iv_stats.is_crypto_wep++;
360
361         /* NB: this assumes the header was pulled up */
362         memcpy(rc4key, mtod(m, uint8_t *) + hdrlen, IEEE80211_WEP_IVLEN);
363         memcpy(rc4key + IEEE80211_WEP_IVLEN, key->wk_key, key->wk_keylen);
364
365         /* Setup RC4 state */
366         for (i = 0; i < 256; i++)
367                 S[i] = i;
368         j = 0;
369         keylen = key->wk_keylen + IEEE80211_WEP_IVLEN;
370         for (i = 0; i < 256; i++) {
371                 j = (j + S[i] + rc4key[i % keylen]) & 0xff;
372                 S_SWAP(i, j);
373         }
374
375         off = hdrlen + wep.ic_header;
376         data_len = m->m_pkthdr.len - off;
377
378         /* Compute CRC32 over unencrypted data and apply RC4 to data */
379         crc = ~0;
380         i = j = 0;
381         pos = mtod(m, uint8_t *) + off;
382         buflen = m->m_len - off;
383         for (;;) {
384                 if (buflen > data_len)
385                         buflen = data_len;
386                 data_len -= buflen;
387                 for (k = 0; k < buflen; k++) {
388                         crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8);
389                         i = (i + 1) & 0xff;
390                         j = (j + S[i]) & 0xff;
391                         S_SWAP(i, j);
392                         *pos++ ^= S[(S[i] + S[j]) & 0xff];
393                 }
394                 if (m->m_next == NULL) {
395                         if (data_len != 0) {            /* out of data */
396                                 IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO,
397                                     ether_sprintf(mtod(m0,
398                                         struct ieee80211_frame *)->i_addr2),
399                                     "out of data for WEP (data_len %zu)",
400                                     data_len);
401                                 /* XXX stat */
402                                 return 0;
403                         }
404                         break;
405                 }
406                 m = m->m_next;
407                 pos = mtod(m, uint8_t *);
408                 buflen = m->m_len;
409         }
410         crc = ~crc;
411
412         /* Append little-endian CRC32 and encrypt it to produce ICV */
413         icv[0] = crc;
414         icv[1] = crc >> 8;
415         icv[2] = crc >> 16;
416         icv[3] = crc >> 24;
417         for (k = 0; k < IEEE80211_WEP_CRCLEN; k++) {
418                 i = (i + 1) & 0xff;
419                 j = (j + S[i]) & 0xff;
420                 S_SWAP(i, j);
421                 icv[k] ^= S[(S[i] + S[j]) & 0xff];
422         }
423         return m_append(m0, IEEE80211_WEP_CRCLEN, icv);
424 #undef S_SWAP
425 }
426
427 static int
428 wep_decrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
429 {
430 #define S_SWAP(a,b) do { uint8_t t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
431         struct wep_ctx *ctx = key->wk_private;
432         struct ieee80211vap *vap = ctx->wc_vap;
433         struct mbuf *m = m0;
434         uint8_t rc4key[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE];
435         uint8_t icv[IEEE80211_WEP_CRCLEN];
436         uint32_t i, j, k, crc;
437         size_t buflen, data_len;
438         uint8_t S[256];
439         uint8_t *pos;
440         u_int off, keylen;
441
442         vap->iv_stats.is_crypto_wep++;
443
444         /* NB: this assumes the header was pulled up */
445         memcpy(rc4key, mtod(m, uint8_t *) + hdrlen, IEEE80211_WEP_IVLEN);
446         memcpy(rc4key + IEEE80211_WEP_IVLEN, key->wk_key, key->wk_keylen);
447
448         /* Setup RC4 state */
449         for (i = 0; i < 256; i++)
450                 S[i] = i;
451         j = 0;
452         keylen = key->wk_keylen + IEEE80211_WEP_IVLEN;
453         for (i = 0; i < 256; i++) {
454                 j = (j + S[i] + rc4key[i % keylen]) & 0xff;
455                 S_SWAP(i, j);
456         }
457
458         off = hdrlen + wep.ic_header;
459         data_len = m->m_pkthdr.len - (off + wep.ic_trailer);
460
461         /* Compute CRC32 over unencrypted data and apply RC4 to data */
462         crc = ~0;
463         i = j = 0;
464         pos = mtod(m, uint8_t *) + off;
465         buflen = m->m_len - off;
466         for (;;) {
467                 if (buflen > data_len)
468                         buflen = data_len;
469                 data_len -= buflen;
470                 for (k = 0; k < buflen; k++) {
471                         i = (i + 1) & 0xff;
472                         j = (j + S[i]) & 0xff;
473                         S_SWAP(i, j);
474                         *pos ^= S[(S[i] + S[j]) & 0xff];
475                         crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8);
476                         pos++;
477                 }
478                 m = m->m_next;
479                 if (m == NULL) {
480                         if (data_len != 0) {            /* out of data */
481                                 IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO,
482                                     mtod(m0, struct ieee80211_frame *)->i_addr2,
483                                     "out of data for WEP (data_len %zu)",
484                                     data_len);
485                                 return 0;
486                         }
487                         break;
488                 }
489                 pos = mtod(m, uint8_t *);
490                 buflen = m->m_len;
491         }
492         crc = ~crc;
493
494         /* Encrypt little-endian CRC32 and verify that it matches with
495          * received ICV */
496         icv[0] = crc;
497         icv[1] = crc >> 8;
498         icv[2] = crc >> 16;
499         icv[3] = crc >> 24;
500         for (k = 0; k < IEEE80211_WEP_CRCLEN; k++) {
501                 i = (i + 1) & 0xff;
502                 j = (j + S[i]) & 0xff;
503                 S_SWAP(i, j);
504                 /* XXX assumes ICV is contiguous in mbuf */
505                 if ((icv[k] ^ S[(S[i] + S[j]) & 0xff]) != *pos++) {
506                         /* ICV mismatch - drop frame */
507                         return 0;
508                 }
509         }
510         return 1;
511 #undef S_SWAP
512 }
513
514 /*
515  * Module glue.
516  */
517 IEEE80211_CRYPTO_MODULE(wep, 1);