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