Initial import from FreeBSD RELENG_4:
[games.git] / sys / dev / netif / awi / awi_wep.c
1 /*      $NetBSD: awi_wep.c,v 1.4 2000/08/14 11:28:03 onoe Exp $ */
2 /* $FreeBSD: src/sys/dev/awi/awi_wep.c,v 1.3.2.2 2003/01/23 21:06:42 sam Exp $ */
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/malloc.h>
58 #include <sys/proc.h>
59 #include <sys/socket.h>
60 #include <sys/errno.h>
61 #include <sys/sockio.h>
62 #if defined(__FreeBSD__) && __FreeBSD__ >= 4
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 #include <machine/clock.h>
83 #endif
84
85 #ifdef __NetBSD__
86 #include <dev/ic/am79c930reg.h>
87 #include <dev/ic/am79c930var.h>
88 #include <dev/ic/awireg.h>
89 #include <dev/ic/awivar.h>
90
91 #include <crypto/arc4/arc4.h>
92 #endif
93
94 #ifdef __FreeBSD__
95 #include <dev/awi/am79c930reg.h>
96 #include <dev/awi/am79c930var.h>
97 #include <dev/awi/awireg.h>
98 #include <dev/awi/awivar.h>
99
100 #include <crypto/rc4/rc4.h>
101 static __inline int
102 arc4_ctxlen(void)
103 {
104         return sizeof(struct rc4_state);
105 }
106
107 static __inline void
108 arc4_setkey(void *ctx, u_int8_t *key, int keylen)
109 {
110         rc4_init(ctx, key, keylen);
111 }
112
113 static __inline void
114 arc4_encrypt(void *ctx, u_int8_t *dst, u_int8_t *src, int len)
115 {
116         rc4_crypt(ctx, src, dst, len);
117 }
118 #endif
119
120 static void awi_crc_init __P((void));
121 static u_int32_t awi_crc_update __P((u_int32_t crc, u_int8_t *buf, int len));
122
123 static int awi_null_ctxlen __P((void));
124 static void awi_null_setkey __P((void *ctx, u_int8_t *key, int keylen));
125 static void awi_null_copy __P((void *ctx, u_int8_t *dst, u_int8_t *src, int len));
126
127 /* XXX: the order should be known to wiconfig/user */
128
129 static struct awi_wep_algo awi_wep_algo[] = {
130 /* 0: no wep */
131         { "no" },       /* dummy for no wep */
132
133 /* 1: normal wep (arc4) */
134         { "arc4", arc4_ctxlen, arc4_setkey,
135             arc4_encrypt, arc4_encrypt },
136
137 /* 2: debug wep (null) */
138         { "null", awi_null_ctxlen, awi_null_setkey,
139             awi_null_copy, awi_null_copy },
140                         /* dummy for wep without encryption */
141 };
142
143 int
144 awi_wep_setnwkey(sc, nwkey)
145         struct awi_softc *sc;
146         struct ieee80211_nwkey *nwkey;
147 {
148         int i, len, error;
149         u_int8_t keybuf[AWI_MAX_KEYLEN];
150
151         if (nwkey->i_defkid <= 0 ||
152             nwkey->i_defkid > IEEE80211_WEP_NKID)
153                 return EINVAL;
154         error = 0;
155         for (i = 0; i < IEEE80211_WEP_NKID; i++) {
156                 if (nwkey->i_key[i].i_keydat == NULL)
157                         continue;
158                 len = nwkey->i_key[i].i_keylen;
159                 if (len > sizeof(keybuf)) {
160                         error = EINVAL;
161                         break;
162                 }
163                 error = copyin(nwkey->i_key[i].i_keydat, keybuf, len);
164                 if (error)
165                         break;
166                 error = awi_wep_setkey(sc, i, keybuf, len);
167                 if (error)
168                         break;
169         }
170         if (error == 0) {
171                 sc->sc_wep_defkid = nwkey->i_defkid - 1;
172                 error = awi_wep_setalgo(sc, nwkey->i_wepon);
173                 if (error == 0 && sc->sc_enabled) {
174                         awi_stop(sc);
175                         error = awi_init(sc);
176                 }
177         }
178         return error;
179 }
180
181 int
182 awi_wep_getnwkey(sc, nwkey)
183         struct awi_softc *sc;
184         struct ieee80211_nwkey *nwkey;
185 {
186         int i, len, error, suerr;
187         u_int8_t keybuf[AWI_MAX_KEYLEN];
188
189         nwkey->i_wepon = awi_wep_getalgo(sc);
190         nwkey->i_defkid = sc->sc_wep_defkid + 1;
191         /* do not show any keys to non-root user */
192 #ifdef __FreeBSD__
193         suerr = suser(curproc);
194 #else
195         suerr = suser(curproc->p_ucred, &curproc->p_acflag);
196 #endif
197         error = 0;
198         for (i = 0; i < IEEE80211_WEP_NKID; i++) {
199                 if (nwkey->i_key[i].i_keydat == NULL)
200                         continue;
201                 if (suerr) {
202                         error = suerr;
203                         break;
204                 }
205                 len = sizeof(keybuf);
206                 error = awi_wep_getkey(sc, i, keybuf, &len);
207                 if (error)
208                         break;
209                 if (nwkey->i_key[i].i_keylen < len) {
210                         error = ENOSPC;
211                         break;
212                 }
213                 nwkey->i_key[i].i_keylen = len;
214                 error = copyout(keybuf, nwkey->i_key[i].i_keydat, len);
215                 if (error)
216                         break;
217         }
218         return error;
219 }
220
221 int
222 awi_wep_getalgo(sc)
223         struct awi_softc *sc;
224 {
225
226         if (sc->sc_wep_algo == NULL)
227                 return 0;
228         return sc->sc_wep_algo - awi_wep_algo;
229 }
230
231 int
232 awi_wep_setalgo(sc, algo)
233         struct awi_softc *sc;
234         int algo;
235 {
236         struct awi_wep_algo *awa;
237         int ctxlen;
238
239         awi_crc_init(); /* XXX: not belongs here */
240         if (algo < 0 || algo > sizeof(awi_wep_algo)/sizeof(awi_wep_algo[0]))
241                 return EINVAL;
242         awa = &awi_wep_algo[algo];
243         if (awa->awa_name == NULL)
244                 return EINVAL;
245         if (awa->awa_ctxlen == NULL) {
246                 awa = NULL;
247                 ctxlen = 0;
248         } else
249                 ctxlen = awa->awa_ctxlen();
250         if (sc->sc_wep_ctx != NULL) {
251                 free(sc->sc_wep_ctx, M_DEVBUF);
252                 sc->sc_wep_ctx = NULL;
253         }
254         if (ctxlen) {
255                 sc->sc_wep_ctx = malloc(ctxlen, M_DEVBUF, M_NOWAIT);
256                 if (sc->sc_wep_ctx == NULL)
257                         return ENOMEM;
258         }
259         sc->sc_wep_algo = awa;
260         return 0;
261 }
262
263 int
264 awi_wep_setkey(sc, kid, key, keylen)
265         struct awi_softc *sc;
266         int kid;
267         unsigned char *key;
268         int keylen;
269 {
270
271         if (kid < 0 || kid >= IEEE80211_WEP_NKID)
272                 return EINVAL;
273         if (keylen < 0 || keylen + IEEE80211_WEP_IVLEN > AWI_MAX_KEYLEN)
274                 return EINVAL;
275         sc->sc_wep_keylen[kid] = keylen;
276         if (keylen > 0)
277                 memcpy(sc->sc_wep_key[kid] + IEEE80211_WEP_IVLEN, key, keylen);
278         return 0;
279 }
280
281 int
282 awi_wep_getkey(sc, kid, key, keylen)
283         struct awi_softc *sc;
284         int kid;
285         unsigned char *key;
286         int *keylen;
287 {
288
289         if (kid < 0 || kid >= IEEE80211_WEP_NKID)
290                 return EINVAL;
291         if (*keylen < sc->sc_wep_keylen[kid])
292                 return ENOSPC;
293         *keylen = sc->sc_wep_keylen[kid];
294         if (*keylen > 0)
295                 memcpy(key, sc->sc_wep_key[kid] + IEEE80211_WEP_IVLEN, *keylen);
296         return 0;
297 }
298
299 struct mbuf *
300 awi_wep_encrypt(sc, m0, txflag)
301         struct awi_softc *sc;
302         struct mbuf *m0;
303         int txflag;
304 {
305         struct mbuf *m, *n, *n0;
306         struct ieee80211_frame *wh;
307         struct awi_wep_algo *awa;
308         int left, len, moff, noff, keylen, kid;
309         u_int32_t iv, crc;
310         u_int8_t *key, *ivp;
311         void *ctx;
312         u_int8_t crcbuf[IEEE80211_WEP_CRCLEN];
313
314         n0 = NULL;
315         awa = sc->sc_wep_algo;
316         if (awa == NULL)
317                 goto fail;
318         ctx = sc->sc_wep_ctx;
319         m = m0;
320         left = m->m_pkthdr.len;
321         MGET(n, M_DONTWAIT, m->m_type);
322         n0 = n;
323         if (n == NULL)
324                 goto fail;
325         M_MOVE_PKTHDR(n, m);
326         len = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
327         if (txflag) {
328                 n->m_pkthdr.len += len;
329         } else {
330                 n->m_pkthdr.len -= len;
331                 left -= len;
332         }
333         n->m_len = MHLEN;
334         if (n->m_pkthdr.len >= MINCLSIZE) {
335                 MCLGET(n, M_DONTWAIT);
336                 if (n->m_flags & M_EXT)
337                         n->m_len = n->m_ext.ext_size;
338         }
339         len = sizeof(struct ieee80211_frame);
340         memcpy(mtod(n, caddr_t), mtod(m, caddr_t), len);
341         left -= len;
342         moff = len;
343         noff = len;
344         if (txflag) {
345                 kid = sc->sc_wep_defkid;
346                 wh = mtod(n, struct ieee80211_frame *);
347                 wh->i_fc[1] |= IEEE80211_FC1_WEP;
348                 iv = random();
349                 /*
350                  * store IV, byte order is not the matter since it's random.
351                  * assuming IEEE80211_WEP_IVLEN is 3
352                  */
353                 ivp = mtod(n, u_int8_t *) + noff;
354                 ivp[0] = (iv >> 16) & 0xff;
355                 ivp[1] = (iv >> 8) & 0xff;
356                 ivp[2] = iv & 0xff;
357                 ivp[3] = kid & 0x03;    /* clear pad and keyid */
358                 noff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
359         } else {
360                 ivp = mtod(m, u_int8_t *) + moff;
361                 moff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
362                 kid = ivp[IEEE80211_WEP_IVLEN] & 0x03;
363         }
364         key = sc->sc_wep_key[kid];
365         keylen = sc->sc_wep_keylen[kid];
366         /* assuming IEEE80211_WEP_IVLEN is 3 */
367         key[0] = ivp[0];
368         key[1] = ivp[1];
369         key[2] = ivp[2];
370         awa->awa_setkey(ctx, key, IEEE80211_WEP_IVLEN + keylen);
371
372         /* encrypt with calculating CRC */
373         crc = ~0;
374         while (left > 0) {
375                 len = m->m_len - moff;
376                 if (len == 0) {
377                         m = m->m_next;
378                         moff = 0;
379                         continue;
380                 }
381                 if (len > n->m_len - noff) {
382                         len = n->m_len - noff;
383                         if (len == 0) {
384                                 MGET(n->m_next, M_DONTWAIT, n->m_type);
385                                 if (n->m_next == NULL)
386                                         goto fail;
387                                 n = n->m_next;
388                                 n->m_len = MLEN;
389                                 if (left >= MINCLSIZE) {
390                                         MCLGET(n, M_DONTWAIT);
391                                         if (n->m_flags & M_EXT)
392                                                 n->m_len = n->m_ext.ext_size;
393                                 }
394                                 noff = 0;
395                                 continue;
396                         }
397                 }
398                 if (len > left)
399                         len = left;
400                 if (txflag) {
401                         awa->awa_encrypt(ctx, mtod(n, caddr_t) + noff,
402                             mtod(m, caddr_t) + moff, len);
403                         crc = awi_crc_update(crc, mtod(m, caddr_t) + moff, len);
404                 } else {
405                         awa->awa_decrypt(ctx, mtod(n, caddr_t) + noff,
406                             mtod(m, caddr_t) + moff, len);
407                         crc = awi_crc_update(crc, mtod(n, caddr_t) + noff, len);
408                 }
409                 left -= len;
410                 moff += len;
411                 noff += len;
412         }
413         crc = ~crc;
414         if (txflag) {
415                 LE_WRITE_4(crcbuf, crc);
416                 if (n->m_len >= noff + sizeof(crcbuf))
417                         n->m_len = noff + sizeof(crcbuf);
418                 else {
419                         n->m_len = noff;
420                         MGET(n->m_next, M_DONTWAIT, n->m_type);
421                         if (n->m_next == NULL)
422                                 goto fail;
423                         n = n->m_next;
424                         n->m_len = sizeof(crcbuf);
425                         noff = 0;
426                 }
427                 awa->awa_encrypt(ctx, mtod(n, caddr_t) + noff, crcbuf,
428                     sizeof(crcbuf));
429         } else {
430                 n->m_len = noff;
431                 for (noff = 0; noff < sizeof(crcbuf); noff += len) {
432                         len = sizeof(crcbuf) - noff;
433                         if (len > m->m_len - moff)
434                                 len = m->m_len - moff;
435                         if (len > 0)
436                                 awa->awa_decrypt(ctx, crcbuf + noff,
437                                     mtod(m, caddr_t) + moff, len);
438                         m = m->m_next;
439                         moff = 0;
440                 }
441                 if (crc != LE_READ_4(crcbuf))
442                         goto fail;
443         }
444         m_freem(m0);
445         return n0;
446
447   fail:
448         m_freem(m0);
449         m_freem(n0);
450         return NULL;
451 }
452
453 /*
454  * CRC 32 -- routine from RFC 2083
455  */
456
457 /* Table of CRCs of all 8-bit messages */
458 static u_int32_t awi_crc_table[256];
459 static int awi_crc_table_computed = 0;
460
461 /* Make the table for a fast CRC. */
462 static void
463 awi_crc_init()
464 {
465         u_int32_t c;
466         int n, k;
467
468         if (awi_crc_table_computed)
469                 return;
470         for (n = 0; n < 256; n++) {
471                 c = (u_int32_t)n;
472                 for (k = 0; k < 8; k++) {
473                         if (c & 1)
474                                 c = 0xedb88320UL ^ (c >> 1);
475                         else
476                                 c = c >> 1;
477                 }
478                 awi_crc_table[n] = c;
479         }
480         awi_crc_table_computed = 1;
481 }
482
483 /*
484  * Update a running CRC with the bytes buf[0..len-1]--the CRC
485  * should be initialized to all 1's, and the transmitted value
486  * is the 1's complement of the final running CRC
487  */
488
489 static u_int32_t
490 awi_crc_update(crc, buf, len)
491         u_int32_t crc;
492         u_int8_t *buf;
493         int len;
494 {
495         u_int8_t *endbuf;
496
497         for (endbuf = buf + len; buf < endbuf; buf++)
498                 crc = awi_crc_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
499         return crc;
500 }
501
502 /*
503  * Null -- do nothing but copy.
504  */
505
506 static int
507 awi_null_ctxlen()
508 {
509
510         return 0;
511 }
512
513 static void
514 awi_null_setkey(ctx, key, keylen)
515         void *ctx;
516         u_char *key;
517         int keylen;
518 {
519 }
520
521 static void
522 awi_null_copy(ctx, dst, src, len)
523         void *ctx;
524         u_char *dst;
525         u_char *src;
526         int len;
527 {
528
529         memcpy(dst, src, len);
530 }