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