Annotation of sys/dev/ic/awi_wep.c, Revision 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