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