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