]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/awi/awi_wep.c
This commit was generated by cvs2svn to compensate for changes in r100490,
[FreeBSD/FreeBSD.git] / sys / dev / awi / awi_wep.c
1 /*      $NetBSD: awi_wep.c,v 1.4 2000/08/14 11:28:03 onoe Exp $ */
2 /* $FreeBSD$ */
3
4 /*
5  * Copyright (c) 2000 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Atsushi Onoe.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *      This product includes software developed by the NetBSD
22  *      Foundation, Inc. and its contributors.
23  * 4. Neither the name of The NetBSD Foundation nor the names of its
24  *    contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39
40 /*
41  * WEP support framework for the awi driver.
42  *
43  * No actual encryption capability is provided here, but any can be added
44  * to awi_wep_algo table below.
45  *
46  * Note that IEEE802.11 specification states WEP uses RC4 with 40bit key,
47  * which is a proprietary encryption algorithm available under license
48  * from RSA Data Security Inc.  Using another algorithm, includes null
49  * encryption provided here, the awi driver cannot be able to communicate
50  * with other stations.
51  */
52
53 #include <sys/param.h>
54 #include <sys/systm.h>
55 #include <sys/kernel.h>
56 #include <sys/mbuf.h>
57 #include <sys/proc.h>
58 #include <sys/malloc.h>
59 #include <sys/socket.h>
60 #include <sys/errno.h>
61 #include <sys/sockio.h>
62 #if defined(__FreeBSD__) && __FreeBSD_version >= 400000
63 #include <sys/bus.h>
64 #else
65 #include <sys/device.h>
66 #endif
67
68 #include <net/if.h>
69 #include <net/if_dl.h>
70 #ifdef __FreeBSD__
71 #include <net/ethernet.h>
72 #include <net/if_arp.h>
73 #else
74 #include <net/if_ether.h>
75 #endif
76 #include <net/if_media.h>
77 #include <net/if_ieee80211.h>
78
79 #include <machine/cpu.h>
80 #include <machine/bus.h>
81 #ifdef __FreeBSD__
82 #endif
83
84 #ifdef __NetBSD__
85 #include <dev/ic/am79c930reg.h>
86 #include <dev/ic/am79c930var.h>
87 #include <dev/ic/awireg.h>
88 #include <dev/ic/awivar.h>
89
90 #include <crypto/arc4/arc4.h>
91 #endif
92
93 #ifdef __FreeBSD__
94 #include <dev/awi/am79c930reg.h>
95 #include <dev/awi/am79c930var.h>
96 #include <dev/awi/awireg.h>
97 #include <dev/awi/awivar.h>
98
99 #include <crypto/rc4/rc4.h>
100 static __inline int
101 arc4_ctxlen(void)
102 {
103         return sizeof(struct rc4_state);
104 }
105
106 static __inline void
107 arc4_setkey(void *ctx, u_int8_t *key, int keylen)
108 {
109         rc4_init(ctx, key, keylen);
110 }
111
112 static __inline void
113 arc4_encrypt(void *ctx, u_int8_t *dst, u_int8_t *src, int len)
114 {
115         rc4_crypt(ctx, src, dst, len);
116 }
117 #endif
118
119 static void awi_crc_init(void);
120 static u_int32_t awi_crc_update(u_int32_t crc, u_int8_t *buf, int len);
121
122 static int awi_null_ctxlen(void);
123 static void awi_null_setkey(void *ctx, u_int8_t *key, int keylen);
124 static void awi_null_copy(void *ctx, u_int8_t *dst, u_int8_t *src, int len);
125
126 /* XXX: the order should be known to wiconfig/user */
127
128 static struct awi_wep_algo awi_wep_algo[] = {
129 /* 0: no wep */
130         { "no" },       /* dummy for no wep */
131
132 /* 1: normal wep (arc4) */
133         { "arc4", arc4_ctxlen, arc4_setkey,
134             arc4_encrypt, arc4_encrypt },
135
136 /* 2: debug wep (null) */
137         { "null", awi_null_ctxlen, awi_null_setkey,
138             awi_null_copy, awi_null_copy },
139                         /* dummy for wep without encryption */
140 };
141
142 int
143 awi_wep_setnwkey(sc, nwkey)
144         struct awi_softc *sc;
145         struct ieee80211_nwkey *nwkey;
146 {
147         int i, len, error;
148         u_int8_t keybuf[AWI_MAX_KEYLEN];
149
150         if (nwkey->i_defkid <= 0 ||
151             nwkey->i_defkid > IEEE80211_WEP_NKID)
152                 return EINVAL;
153         error = 0;
154         for (i = 0; i < IEEE80211_WEP_NKID; i++) {
155                 if (nwkey->i_key[i].i_keydat == NULL)
156                         continue;
157                 len = nwkey->i_key[i].i_keylen;
158                 if (len > sizeof(keybuf)) {
159                         error = EINVAL;
160                         break;
161                 }
162                 error = copyin(nwkey->i_key[i].i_keydat, keybuf, len);
163                 if (error)
164                         break;
165                 error = awi_wep_setkey(sc, i, keybuf, len);
166                 if (error)
167                         break;
168         }
169         if (error == 0) {
170                 sc->sc_wep_defkid = nwkey->i_defkid - 1;
171                 error = awi_wep_setalgo(sc, nwkey->i_wepon);
172                 if (error == 0 && sc->sc_enabled) {
173                         awi_stop(sc);
174                         error = awi_init(sc);
175                 }
176         }
177         return error;
178 }
179
180 int
181 awi_wep_getnwkey(sc, nwkey)
182         struct awi_softc *sc;
183         struct ieee80211_nwkey *nwkey;
184 {
185         int i, len, error, suerr;
186         u_int8_t keybuf[AWI_MAX_KEYLEN];
187
188         nwkey->i_wepon = awi_wep_getalgo(sc);
189         nwkey->i_defkid = sc->sc_wep_defkid + 1;
190         /* do not show any keys to non-root user */
191 #ifdef __FreeBSD__
192 #if __FreeBSD_version < 500028
193         suerr = suser(curproc);
194 #else
195         suerr = suser(curthread);
196 #endif
197 #else
198         suerr = suser(curproc->p_ucred, &curproc->p_acflag);
199 #endif
200         error = 0;
201         for (i = 0; i < IEEE80211_WEP_NKID; i++) {
202                 if (nwkey->i_key[i].i_keydat == NULL)
203                         continue;
204                 if (suerr) {
205                         error = suerr;
206                         break;
207                 }
208                 len = sizeof(keybuf);
209                 error = awi_wep_getkey(sc, i, keybuf, &len);
210                 if (error)
211                         break;
212                 if (nwkey->i_key[i].i_keylen < len) {
213                         error = ENOSPC;
214                         break;
215                 }
216                 nwkey->i_key[i].i_keylen = len;
217                 error = copyout(keybuf, nwkey->i_key[i].i_keydat, len);
218                 if (error)
219                         break;
220         }
221         return error;
222 }
223
224 int
225 awi_wep_getalgo(sc)
226         struct awi_softc *sc;
227 {
228
229         if (sc->sc_wep_algo == NULL)
230                 return 0;
231         return sc->sc_wep_algo - awi_wep_algo;
232 }
233
234 int
235 awi_wep_setalgo(sc, algo)
236         struct awi_softc *sc;
237         int algo;
238 {
239         struct awi_wep_algo *awa;
240         int ctxlen;
241
242         awi_crc_init(); /* XXX: not belongs here */
243         if (algo < 0 || algo > sizeof(awi_wep_algo)/sizeof(awi_wep_algo[0]))
244                 return EINVAL;
245         awa = &awi_wep_algo[algo];
246         if (awa->awa_name == NULL)
247                 return EINVAL;
248         if (awa->awa_ctxlen == NULL) {
249                 awa = NULL;
250                 ctxlen = 0;
251         } else
252                 ctxlen = awa->awa_ctxlen();
253         if (sc->sc_wep_ctx != NULL) {
254                 free(sc->sc_wep_ctx, M_DEVBUF);
255                 sc->sc_wep_ctx = NULL;
256         }
257         if (ctxlen) {
258                 sc->sc_wep_ctx = malloc(ctxlen, M_DEVBUF, M_NOWAIT);
259                 if (sc->sc_wep_ctx == NULL)
260                         return ENOMEM;
261         }
262         sc->sc_wep_algo = awa;
263         return 0;
264 }
265
266 int
267 awi_wep_setkey(sc, kid, key, keylen)
268         struct awi_softc *sc;
269         int kid;
270         unsigned char *key;
271         int keylen;
272 {
273
274         if (kid < 0 || kid >= IEEE80211_WEP_NKID)
275                 return EINVAL;
276         if (keylen < 0 || keylen + IEEE80211_WEP_IVLEN > AWI_MAX_KEYLEN)
277                 return EINVAL;
278         sc->sc_wep_keylen[kid] = keylen;
279         if (keylen > 0)
280                 memcpy(sc->sc_wep_key[kid] + IEEE80211_WEP_IVLEN, key, keylen);
281         return 0;
282 }
283
284 int
285 awi_wep_getkey(sc, kid, key, keylen)
286         struct awi_softc *sc;
287         int kid;
288         unsigned char *key;
289         int *keylen;
290 {
291
292         if (kid < 0 || kid >= IEEE80211_WEP_NKID)
293                 return EINVAL;
294         if (*keylen < sc->sc_wep_keylen[kid])
295                 return ENOSPC;
296         *keylen = sc->sc_wep_keylen[kid];
297         if (*keylen > 0)
298                 memcpy(key, sc->sc_wep_key[kid] + IEEE80211_WEP_IVLEN, *keylen);
299         return 0;
300 }
301
302 struct mbuf *
303 awi_wep_encrypt(sc, m0, txflag)
304         struct awi_softc *sc;
305         struct mbuf *m0;
306         int txflag;
307 {
308         struct mbuf *m, *n, *n0;
309         struct ieee80211_frame *wh;
310         struct awi_wep_algo *awa;
311         int left, len, moff, noff, keylen, kid;
312         u_int32_t iv, crc;
313         u_int8_t *key, *ivp;
314         void *ctx;
315         u_int8_t crcbuf[IEEE80211_WEP_CRCLEN];
316
317         n0 = NULL;
318         awa = sc->sc_wep_algo;
319         if (awa == NULL)
320                 goto fail;
321         ctx = sc->sc_wep_ctx;
322         m = m0;
323         left = m->m_pkthdr.len;
324         MGET(n, M_DONTWAIT, m->m_type);
325         n0 = n;
326         if (n == NULL)
327                 goto fail;
328         M_COPY_PKTHDR(n, m);
329         len = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
330         if (txflag) {
331                 n->m_pkthdr.len += len;
332         } else {
333                 n->m_pkthdr.len -= len;
334                 left -= len;
335         }
336         n->m_len = MHLEN;
337         if (n->m_pkthdr.len >= MINCLSIZE) {
338                 MCLGET(n, M_DONTWAIT);
339                 if (n->m_flags & M_EXT)
340                         n->m_len = n->m_ext.ext_size;
341         }
342         len = sizeof(struct ieee80211_frame);
343         memcpy(mtod(n, caddr_t), mtod(m, caddr_t), len);
344         left -= len;
345         moff = len;
346         noff = len;
347         if (txflag) {
348                 kid = sc->sc_wep_defkid;
349                 wh = mtod(n, struct ieee80211_frame *);
350                 wh->i_fc[1] |= IEEE80211_FC1_WEP;
351                 iv = random();
352                 /*
353                  * store IV, byte order is not the matter since it's random.
354                  * assuming IEEE80211_WEP_IVLEN is 3
355                  */
356                 ivp = mtod(n, u_int8_t *) + noff;
357                 ivp[0] = (iv >> 16) & 0xff;
358                 ivp[1] = (iv >> 8) & 0xff;
359                 ivp[2] = iv & 0xff;
360                 ivp[IEEE80211_WEP_IVLEN] = kid << 6;    /* pad and keyid */
361                 noff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
362         } else {
363                 ivp = mtod(m, u_int8_t *) + moff;
364                 kid = ivp[IEEE80211_WEP_IVLEN] >> 6;
365                 moff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
366         }
367         key = sc->sc_wep_key[kid];
368         keylen = sc->sc_wep_keylen[kid];
369         /* assuming IEEE80211_WEP_IVLEN is 3 */
370         key[0] = ivp[0];
371         key[1] = ivp[1];
372         key[2] = ivp[2];
373         awa->awa_setkey(ctx, key, IEEE80211_WEP_IVLEN + keylen);
374
375         /* encrypt with calculating CRC */
376         crc = ~0;
377         while (left > 0) {
378                 len = m->m_len - moff;
379                 if (len == 0) {
380                         m = m->m_next;
381                         moff = 0;
382                         continue;
383                 }
384                 if (len > n->m_len - noff) {
385                         len = n->m_len - noff;
386                         if (len == 0) {
387                                 MGET(n->m_next, M_DONTWAIT, n->m_type);
388                                 if (n->m_next == NULL)
389                                         goto fail;
390                                 n = n->m_next;
391                                 n->m_len = MLEN;
392                                 if (left >= MINCLSIZE) {
393                                         MCLGET(n, M_DONTWAIT);
394                                         if (n->m_flags & M_EXT)
395                                                 n->m_len = n->m_ext.ext_size;
396                                 }
397                                 noff = 0;
398                                 continue;
399                         }
400                 }
401                 if (len > left)
402                         len = left;
403                 if (txflag) {
404                         awa->awa_encrypt(ctx, mtod(n, caddr_t) + noff,
405                             mtod(m, caddr_t) + moff, len);
406                         crc = awi_crc_update(crc, mtod(m, caddr_t) + moff, len);
407                 } else {
408                         awa->awa_decrypt(ctx, mtod(n, caddr_t) + noff,
409                             mtod(m, caddr_t) + moff, len);
410                         crc = awi_crc_update(crc, mtod(n, caddr_t) + noff, len);
411                 }
412                 left -= len;
413                 moff += len;
414                 noff += len;
415         }
416         crc = ~crc;
417         if (txflag) {
418                 LE_WRITE_4(crcbuf, crc);
419                 if (n->m_len >= noff + sizeof(crcbuf))
420                         n->m_len = noff + sizeof(crcbuf);
421                 else {
422                         n->m_len = noff;
423                         MGET(n->m_next, M_DONTWAIT, n->m_type);
424                         if (n->m_next == NULL)
425                                 goto fail;
426                         n = n->m_next;
427                         n->m_len = sizeof(crcbuf);
428                         noff = 0;
429                 }
430                 awa->awa_encrypt(ctx, mtod(n, caddr_t) + noff, crcbuf,
431                     sizeof(crcbuf));
432         } else {
433                 n->m_len = noff;
434                 for (noff = 0; noff < sizeof(crcbuf); noff += len) {
435                         len = sizeof(crcbuf) - noff;
436                         if (len > m->m_len - moff)
437                                 len = m->m_len - moff;
438                         if (len > 0)
439                                 awa->awa_decrypt(ctx, crcbuf + noff,
440                                     mtod(m, caddr_t) + moff, len);
441                         m = m->m_next;
442                         moff = 0;
443                 }
444                 if (crc != LE_READ_4(crcbuf))
445                         goto fail;
446         }
447         m_freem(m0);
448         return n0;
449
450   fail:
451         m_freem(m0);
452         m_freem(n0);
453         return NULL;
454 }
455
456 /*
457  * CRC 32 -- routine from RFC 2083
458  */
459
460 /* Table of CRCs of all 8-bit messages */
461 static u_int32_t awi_crc_table[256];
462 static int awi_crc_table_computed = 0;
463
464 /* Make the table for a fast CRC. */
465 static void
466 awi_crc_init()
467 {
468         u_int32_t c;
469         int n, k;
470
471         if (awi_crc_table_computed)
472                 return;
473         for (n = 0; n < 256; n++) {
474                 c = (u_int32_t)n;
475                 for (k = 0; k < 8; k++) {
476                         if (c & 1)
477                                 c = 0xedb88320UL ^ (c >> 1);
478                         else
479                                 c = c >> 1;
480                 }
481                 awi_crc_table[n] = c;
482         }
483         awi_crc_table_computed = 1;
484 }
485
486 /*
487  * Update a running CRC with the bytes buf[0..len-1]--the CRC
488  * should be initialized to all 1's, and the transmitted value
489  * is the 1's complement of the final running CRC
490  */
491
492 static u_int32_t
493 awi_crc_update(crc, buf, len)
494         u_int32_t crc;
495         u_int8_t *buf;
496         int len;
497 {
498         u_int8_t *endbuf;
499
500         for (endbuf = buf + len; buf < endbuf; buf++)
501                 crc = awi_crc_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
502         return crc;
503 }
504
505 /*
506  * Null -- do nothing but copy.
507  */
508
509 static int
510 awi_null_ctxlen()
511 {
512
513         return 0;
514 }
515
516 static void
517 awi_null_setkey(ctx, key, keylen)
518         void *ctx;
519         u_char *key;
520         int keylen;
521 {
522 }
523
524 static void
525 awi_null_copy(ctx, dst, src, len)
526         void *ctx;
527         u_char *dst;
528         u_char *src;
529         int len;
530 {
531
532         memcpy(dst, src, len);
533 }