root/dev/ic/awi_wep.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. arc4_ctxlen
  2. arc4_setkey
  3. arc4_encrypt
  4. awi_wep_setnwkey
  5. awi_wep_getnwkey
  6. awi_wep_getalgo
  7. awi_wep_setalgo
  8. awi_wep_setkey
  9. awi_wep_getkey
  10. awi_wep_encrypt
  11. awi_crc_init
  12. awi_crc_update
  13. awi_null_ctxlen
  14. awi_null_setkey
  15. awi_null_copy

    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 }

/* [<][>][^][v][top][bottom][index][help] */