[BACK]Return to rln.c CVS log [TXT][DIR] Up to [local] / sys / dev / ic

Annotation of sys/dev/ic/rln.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: rln.c,v 1.18 2006/03/25 22:41:43 djm Exp $    */
                      2: /*
                      3:  * David Leonard <d@openbsd.org>, 1999. Public Domain.
                      4:  *
                      5:  * Driver for the Proxim RangeLAN2 wireless network adaptor.
                      6:  *
                      7:  * Information and ideas gleaned from disassembly of Dave Koberstein's
                      8:  * <davek@komacke.com> Linux driver (apparently based on Proxim source),
                      9:  * from Yoichi Shinoda's <shinoda@cs.washington.edu> BSDI driver, and
                     10:  * Geoff Voelker's <voelker@cs.washington.edu> Linux port of the same.
                     11:  *
                     12:  */
                     13:
                     14: #include "bpfilter.h"
                     15:
                     16: #include <sys/param.h>
                     17: #include <sys/systm.h>
                     18: #include <sys/mbuf.h>
                     19: #include <sys/socket.h>
                     20: #include <sys/ioctl.h>
                     21: #include <sys/syslog.h>
                     22: #include <sys/device.h>
                     23: #include <sys/kernel.h>
                     24:
                     25: #include <net/if.h>
                     26: #include <net/if_media.h>
                     27:
                     28: #ifdef INET
                     29: #include <netinet/in.h>
                     30: #include <netinet/if_ether.h>
                     31: #endif
                     32:
                     33: #if NBPFILTER > 0
                     34: #include <net/bpf.h>
                     35: #endif
                     36:
                     37: #include <machine/bus.h>
                     38: #include <machine/intr.h>
                     39:
                     40: #include <dev/ic/rln.h>
                     41: #include <dev/ic/rlnvar.h>
                     42: #include <dev/ic/rlnreg.h>
                     43: #include <dev/ic/rlncmd.h>
                     44:
                     45: /* Autoconfig definition of driver back-end. */
                     46: struct cfdriver rln_cd = {
                     47:        NULL, "rln", DV_IFNET
                     48: };
                     49:
                     50: void   rlninit(struct rln_softc *);
                     51: void   rlnstart(struct ifnet*);
                     52: void   rlnwatchdog(struct ifnet*);
                     53: int    rlnioctl(struct ifnet *, u_long, caddr_t);
                     54: void   rlnstop(struct rln_softc *);
                     55:
                     56: /* Interrupt handler. */
                     57: void   rlnsoftintr(void *);
                     58:
                     59: /* Packet I/O. */
                     60: int    rln_transmit(struct rln_softc *, struct mbuf *,
                     61:                        int, int);
                     62: struct mbuf * rlnget(struct rln_softc *, struct rln_mm_cmd *,
                     63:                        int);
                     64:
                     65: /* Card protocol-level functions. */
                     66: int    rln_getenaddr(struct rln_softc *, u_int8_t *);
                     67: int    rln_getpromvers(struct rln_softc *, char *, int);
                     68: int    rln_sendinit(struct rln_softc *);
                     69: #if notyet
                     70: int    rln_roamconfig(struct rln_softc *);
                     71: int    rln_roam(struct rln_softc *);
                     72: int    rln_multicast(struct rln_softc *, int);
                     73: int    rln_searchsync(struct rln_softc *);
                     74: int    rln_iosetparam(struct rln_softc *, struct rln_param *);
                     75: int    rln_lockprom(struct rln_softc *);
                     76: int    rln_ito(struct rln_softc *);
                     77: int    rln_standby(struct rln_softc *);
                     78: #endif
                     79:
                     80: /* Back-end attach and configure. Assumes card has been reset. */
                     81: void
                     82: rlnconfig(sc)
                     83:        struct rln_softc * sc;
                     84: {
                     85:        struct ifnet *  ifp = &sc->sc_arpcom.ac_if;
                     86:        char            promvers[7];
                     87:        int             i;
                     88:
                     89:        dprintf(" [attach %p]", sc);
                     90:
                     91:        /* Use the flags supplied from config. */
                     92:        sc->sc_cardtype |= sc->sc_dev.dv_cfdata->cf_flags;
                     93:
                     94:        /* Initialise values in the soft state. */
                     95:        sc->sc_pktseq = 0;      /* rln_newseq() */
                     96:        sc->sc_txseq = 0;
                     97:        sc->sc_state = 0;
                     98:
                     99:        /* Initialise user-configurable params. */
                    100:        sc->sc_param.rp_roam_config = RLN_ROAM_NORMAL;
                    101:        sc->sc_param.rp_security = RLN_SECURITY_DEFAULT;
                    102:        sc->sc_param.rp_station_type = RLN_STATIONTYPE_ALTMASTER;
                    103:        sc->sc_param.rp_domain = 0;
                    104:        sc->sc_param.rp_channel = 1;
                    105:        sc->sc_param.rp_subchannel = 1;
                    106:
                    107:        bzero(sc->sc_param.rp_master, sizeof sc->sc_param.rp_master);
                    108:
                    109:        /* Initialise the message mailboxes. */
                    110:        for (i = 0; i < RLN_NMBOX; i++)
                    111:                sc->sc_mbox[i].mb_state = RLNMBOX_VOID;
                    112:
                    113:        /* Probe for some properties. */
                    114:        printf(", %s-piece",
                    115:            (sc->sc_cardtype & RLN_CTYPE_ONE_PIECE) ? "one" : "two");
                    116:        if (sc->sc_cardtype & RLN_CTYPE_OEM)
                    117:                printf(" oem");
                    118:        if (sc->sc_cardtype & RLN_CTYPE_UISA)
                    119:                printf(" micro-isa");
                    120:
                    121:        /* Read the card's PROM revision. */
                    122:        if (rln_getpromvers(sc, promvers, sizeof promvers)) {
                    123:                printf(": could not read PROM version\n");
                    124:                return;
                    125:        }
                    126:        printf(", fw %.7s", promvers);
                    127:
                    128:        /* Fetch the card's MAC address. */
                    129:        if (rln_getenaddr(sc, sc->sc_arpcom.ac_enaddr)) {
                    130:                printf(": could not read MAC address\n");
                    131:                return;
                    132:        }
                    133:        printf(", addr %s", ether_sprintf(sc->sc_arpcom.ac_enaddr));
                    134:
                    135:        timeout_set(&sc->sc_timeout, rlnsoftintr, sc);
                    136:
                    137:        /* Attach as a network interface. */
                    138:        bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
                    139:        ifp->if_softc = sc;
                    140:        ifp->if_start = rlnstart;
                    141:        ifp->if_ioctl = rlnioctl;
                    142:        ifp->if_watchdog = rlnwatchdog;
                    143:        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
                    144:        IFQ_SET_READY(&ifp->if_snd);
                    145:        if_attach(ifp);
                    146:        ether_ifattach(ifp);
                    147: }
                    148:
                    149: /* Bring device up. */
                    150: void
                    151: rlninit(sc)
                    152:        struct rln_softc * sc;
                    153: {
                    154:        /* LLDInit() */
                    155:        struct ifnet * ifp = &sc->sc_arpcom.ac_if;
                    156:        int s;
                    157:
                    158:        s = splnet();
                    159:        dprintf(" [init]");
                    160:
                    161:        sc->sc_intsel = 0;
                    162:        sc->sc_status = 0;
                    163:        sc->sc_control = 0;
                    164:        ifp->if_flags &= ~IFF_RUNNING;
                    165:        ifp->if_flags &= ~IFF_OACTIVE;
                    166:
                    167:        /* Do a hard reset. */
                    168:        if (rln_reset(sc)) {
                    169:                printf("%s: could not reset card\n", sc->sc_dev.dv_xname);
                    170:                goto fail;
                    171:        }
                    172:        sc->sc_state = 0;       /* Also clears RLN_STATE_NEEDINIT. */
                    173:
                    174:        /* Use this host's name as a master name. */
                    175:        if (!cold && sc->sc_param.rp_master[0] == '\0') {
                    176:                bcopy(hostname, sc->sc_param.rp_master,
                    177:                    min(hostnamelen, sizeof sc->sc_param.rp_master));
                    178:        }
                    179:
                    180:        rln_enable(sc, 1);
                    181:
                    182:        /* Initialise operational params. */
                    183:        if (rln_sendinit(sc)) {
                    184:                printf("%s: could not set card parameters\n",
                    185:                    sc->sc_dev.dv_xname);
                    186:                goto fail;
                    187:        }
                    188: #if 0
                    189:        rln_roamconfig(sc);
                    190:        /* rln_lockprom(sc); */
                    191:        /* SendSetITO() */
                    192:        rln_multicast(sc, 1);
                    193:        rln_roam(sc);
                    194:
                    195:        /* Synchronise with something. */
                    196:        rln_searchsync(sc);
                    197: #endif
                    198:        ifp->if_flags |= IFF_RUNNING;
                    199:        rlnstart(ifp);
                    200:        splx(s);
                    201:
                    202:        return;
                    203:
                    204:     fail:
                    205:        ifp->if_flags &= ~IFF_UP;
                    206:        splx(s);
                    207:        return;
                    208: }
                    209:
                    210: /* Start outputting on interface. This is always called at splnet(). */
                    211: void
                    212: rlnstart(ifp)
                    213:        struct ifnet *  ifp;
                    214: {
                    215:        struct rln_softc * sc = (struct rln_softc *)ifp->if_softc;
                    216:        struct mbuf *   m0;
                    217:        int             len, pad, ret, s;
                    218:
                    219:        dprintf(" start[");
                    220:
                    221:        if (sc->sc_state & RLN_STATE_NEEDINIT)
                    222:                rlninit(sc);
                    223:
                    224:        /* Don't transmit if interface is busy or not running. */
                    225:        if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) {
                    226:                dprintf(" %s] ", (ifp->if_flags & IFF_OACTIVE) ?
                    227:                    "busy" : "stopped");
                    228:                return;
                    229:        }
                    230:
                    231:        /* Don't transmit if we are not synchronised. */
                    232:        if ((sc->sc_state & RLN_STATE_SYNC) == 0) {
                    233:                dprintf(" nosync]");
                    234:                return;
                    235:        }
                    236:
                    237:        rln_enable(sc, 1);
                    238:
                    239:     startagain:
                    240:        s = splnet();
                    241:        IFQ_DEQUEUE(&ifp->if_snd, m0);
                    242:        splx(s);
                    243:
                    244:        if (m0 == NULL) {
                    245:                dprintf(" empty]");
                    246:                return;
                    247:        }
                    248:
                    249: #if NBPFILTER > 0
                    250:        /* Tap packet stream here for BPF listeners. */
                    251:        if (ifp->if_bpf)
                    252:                bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
                    253: #endif
                    254:
                    255:        /* We need to use m->m_pkthdr.len, so require the header. */
                    256:        if ((m0->m_flags & M_PKTHDR) == 0) {
                    257:                printf("%s: no mbuf header\n", sc->sc_dev.dv_xname);
                    258:                goto oerror;
                    259:        }
                    260:
                    261:        len = m0->m_pkthdr.len;
                    262:
                    263: #define PACKETMIN      (sizeof (struct ether_header) + ETHERMIN)
                    264: #define PACKETMAX      (sizeof (struct ether_header) + ETHERMTU + 4)
                    265:
                    266:        /* Packet size has to be an even number between 60 and 1518 octets. */
                    267:        pad = len & 1;
                    268:        if (len + pad < PACKETMIN)
                    269:                pad = PACKETMIN - len;
                    270:
                    271:        if (len + pad > PACKETMAX) {
                    272:                printf("%s: packet too big (%d > %d)\n",
                    273:                    sc->sc_dev.dv_xname, len + pad,
                    274:                    PACKETMAX);
                    275:                ++ifp->if_oerrors;
                    276:                m_freem(m0);
                    277:                goto startagain;
                    278:        }
                    279:
                    280:        ret = rln_transmit(sc, m0, len, pad);
                    281:        if (ret)
                    282:                goto oerror;
                    283:
                    284:        ifp->if_flags |= IFF_OACTIVE;
                    285:        m_freem(m0);
                    286:
                    287:        dprintf(" sent]");
                    288:        return;
                    289:
                    290: oerror:
                    291:        ++ifp->if_oerrors;
                    292:        m_freem(m0);
                    293:        rln_need_reset(sc);
                    294:        return;
                    295: }
                    296:
                    297: /* Transmit one packet. */
                    298: int
                    299: rln_transmit(sc, m0, len, pad)
                    300:        struct rln_softc *      sc;
                    301:        struct mbuf *   m0;
                    302:        int             len;
                    303:        int             pad;
                    304: {
                    305:        struct mbuf *   m;
                    306:        int             zfirst;
                    307:        int             actlen;
                    308:        int             tlen = len + pad;
                    309:        struct rln_msg_tx_state state;
                    310:        static u_int8_t zeroes[60];
                    311:        struct rln_mm_sendpacket cmd = { RLN_MM_SENDPACKET };
                    312:
                    313:        /* Does the packet start with a zero bit? */
                    314:        zfirst = ((*mtod(m0, u_int8_t *) & 1) == 0);
                    315:
                    316:        cmd.mode =
                    317:                RLN_MM_SENDPACKET_MODE_BIT7 |
                    318:                   (zfirst ? RLN_MM_SENDPACKET_MODE_ZFIRST : 0) |
                    319:                   (0 ? RLN_MM_SENDPACKET_MODE_QFSK : 0),       /* sc->qfsk? */
                    320:        cmd.power = 0x70;       /* 0x70 or 0xf0 */
                    321:        cmd.length_lo = htons(4 + tlen) & 0xff;
                    322:        cmd.length_hi = (htons(4 + tlen) >> 8) & 0xff;
                    323:        cmd.xxx1 = 0;
                    324:        cmd.xxx2 = 0;
                    325:        cmd.xxx3 = 0;
                    326:
                    327:        /* A unique packet-level sequence number, independent of sc_seq. */
                    328:        cmd.sequence = sc->sc_txseq;
                    329:        sc->sc_txseq++;
                    330:        if (sc->sc_txseq > RLN_MAXSEQ)
                    331:                sc->sc_txseq = 0;
                    332:
                    333:        dprintf(" T[%d+%d", len, pad);
                    334:
                    335:        if (rln_msg_tx_start(sc, &cmd, sizeof cmd + tlen, &state))
                    336:                goto error;
                    337:
                    338:        cmd.mm_cmd.cmd_seq = rln_newseq(sc);
                    339:
                    340:        /* Send the SENDPACKET command header  */
                    341: #ifdef RLNDUMP
                    342:        printf("%s: send %c%d seq %d data ", sc->sc_dev.dv_xname,
                    343:            cmd.mm_cmd.cmd_letter, cmd.mm_cmd.cmd_fn, cmd.mm_cmd.cmd_seq);
                    344:        RLNDUMPHEX(&cmd, sizeof cmd);
                    345:        printf(":");
                    346: #endif
                    347:        rln_msg_tx_data(sc, &cmd, sizeof cmd, &state);
                    348:
                    349:        /* XXX do we need to insert a hardware header here??? */
                    350:
                    351:        /* Follow the header immediately with the packet payload */
                    352:        actlen = 0;
                    353:        for (m = m0; m; m = m->m_next)  {
                    354:                if (m->m_len) {
                    355: #ifdef RLNDUMP
                    356:                        RLNDUMPHEX(mtod(m, void *), m->m_len);
                    357: #endif
                    358:                        rln_msg_tx_data(sc, mtod(m, void *), m->m_len, &state);
                    359:                }
                    360:                if (m->m_next)
                    361:                        printf("|");
                    362:                actlen += m->m_len;
                    363:        }
                    364: #ifdef DIAGNOSTIC
                    365:        if (actlen != len)
                    366:                panic("rln_transmit: len %d != %d", actlen, len);
                    367:        if (pad > sizeof zeroes)
                    368:                panic("rln_transmit: pad %d > %d", pad, sizeof zeroes);
                    369: #endif
                    370:        if (pad) {
                    371: #ifdef RLNDUMP
                    372:                printf(":");
                    373:                RLNDUMPHEX(zeroes, pad);
                    374: #endif
                    375:                rln_msg_tx_data(sc, zeroes, pad, &state);
                    376:        }
                    377:
                    378: #ifdef RLNDUMP
                    379:        printf("\n");
                    380: #endif
                    381:        if (rln_msg_tx_end(sc, &state))
                    382:                goto error;
                    383:        return (0);
                    384:
                    385:     error:
                    386:        dprintf(" error]");
                    387:        return (-1);
                    388: }
                    389:
                    390: /* (Supposedly) called when interrupts are suspiciously absent. */
                    391: void
                    392: rlnwatchdog(ifp)
                    393:        struct ifnet * ifp;
                    394: {
                    395:        struct rln_softc * sc = (struct rln_softc *)ifp->if_softc;
                    396:
                    397:        log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
                    398:        ++sc->sc_arpcom.ac_if.if_oerrors;
                    399:        rlninit(sc);
                    400:        rln_enable(sc, 1);
                    401: }
                    402:
                    403: /* Handle single card interrupt. */
                    404: int
                    405: rlnintr(arg)
                    406:        void *  arg;
                    407: {
                    408:        struct rln_softc * sc = (struct rln_softc *)arg;
                    409:
                    410:        dprintf("!");
                    411:
                    412:        /* Tell card not to interrupt any more. */
                    413:        rln_enable(sc, 0);
                    414:
                    415:        if (cold)
                    416:                /* During autoconfig - must handle interrupts now. */
                    417:                rlnsoftintr(sc);
                    418:        else
                    419:                /* Handle later. */
                    420:                timeout_add(&sc->sc_timeout, 1);
                    421:
                    422:        return (1);
                    423: }
                    424:
                    425: /* Process earlier card interrupt at splsoftnet. */
                    426: void
                    427: rlnsoftintr(arg)
                    428:        void * arg;
                    429: {
                    430:        struct rln_softc *sc = (struct rln_softc *)arg;
                    431:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
                    432:        int len;
                    433:        u_int8_t w;
                    434:        struct rln_mm_cmd hdr;
                    435:        int s;
                    436:
                    437:        s = splsoftnet();
                    438:        dprintf(" si(");
                    439:
                    440:     again:
                    441:        /* Save wakeup state. */
                    442:        w = rln_wakeup(sc, RLN_WAKEUP_SET);
                    443:
                    444:        if ((len = rln_rx_request(sc, 300)) < 0) {
                    445:                /* Error in transfer. */
                    446:                rln_need_reset(sc);
                    447:                rln_rx_end(sc);
                    448:        } else if (len < sizeof hdr) {
                    449:                /* Short message. */
                    450:                rln_rx_end(sc);
                    451:                printf("%s: short msg (%d)\n", sc->sc_dev.dv_xname, len);
                    452:                ifp->if_ierrors++;
                    453:        } else {
                    454:                /* Valid message: read header and process. */
                    455:                rln_rx_data(sc, &hdr, sizeof hdr);
                    456:                rlnread(sc, &hdr, len);
                    457:        }
                    458:
                    459:        /* Ensure that wakeup state is unchanged if transmitting. */
                    460:        if (ifp->if_flags & IFF_OACTIVE)
                    461:                w |= RLN_WAKEUP_NOCHANGE;
                    462:        rln_wakeup(sc, w);
                    463:
                    464:        /* Check for more interrupts. */
                    465:        if ((sc->sc_state & RLN_STATE_NEEDINIT) == 0 &&
                    466:            rln_status_rx_ready(sc)) {
                    467:                if (rln_status_rx_read(sc) == RLN_STATUS_RX_ERROR) {
                    468: #ifdef DIAGNOSTIC
                    469:                        printf("%s: protocol error\n", sc->sc_dev.dv_xname);
                    470: #endif
                    471:                        DELAY(100 * 1000);      /* Woah, baby. */
                    472:                        rln_clear_nak(sc);
                    473:                } else {
                    474: #ifdef DIAGNOSTIC
                    475:                        printf("%s: intr piggyback\n", sc->sc_dev.dv_xname);
                    476: #endif
                    477:                        goto again;
                    478:                }
                    479:        }
                    480:
                    481:        rln_eoi(sc);
                    482:        rln_enable(sc, 1);
                    483:
                    484:        dprintf(")");
                    485:        splx(s);
                    486: }
                    487:
                    488: /* Read and process a message from the card. */
                    489: void
                    490: rlnread(sc, hdr, len)
                    491:        struct rln_softc *sc;
                    492:        struct rln_mm_cmd *hdr;
                    493:        int len;
                    494: {
                    495:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
                    496:        struct mbuf *m;
                    497:        u_int8_t data[1538];
                    498:        u_int8_t  *buf;
                    499:        size_t    buflen;
                    500:        struct rln_pdata pd = RLN_PDATA_INIT;
                    501:        struct rln_mm_synchronised * syncp = (struct rln_mm_synchronised *)data;
                    502:        int s;
                    503:
                    504:        dprintf(" [read]");
                    505:
                    506:        /* Were we waiting for this message? */
                    507:        if (rln_mbox_lock(sc, hdr->cmd_seq, (void **)&buf, &buflen) == 0) {
                    508: #ifdef DIAGNOSTIC
                    509:                if (buflen < sizeof *hdr)
                    510:                        panic("rlnread buflen");
                    511: #endif
                    512:                bcopy(hdr, buf, sizeof *hdr);
                    513:                buf += sizeof *hdr;
                    514:                len -= sizeof *hdr;
                    515:                buflen -= sizeof *hdr;
                    516:                if (len) {
                    517:                        if (len == buflen)              /* Expected size */
                    518:                                rln_rx_pdata(sc, buf, len, &pd);
                    519:                        else if (len < buflen) {        /* Underfill */
                    520: #ifdef DIAGNOSTIC
                    521:                                printf("%s: underfill %d<%d, cmd %c%d\n",
                    522:                                        sc->sc_dev.dv_xname,
                    523:                                        len, buflen,
                    524:                                        hdr->cmd_letter, hdr->cmd_fn);
                    525: #endif
                    526:                                rln_rx_pdata(sc, buf, len, &pd);
                    527:                        } else {                        /* Overflow */
                    528: #ifdef DIAGNOSTIC
                    529:                                printf("%s: overflow %d>%d, cmd %c%d\n",
                    530:                                        sc->sc_dev.dv_xname,
                    531:                                        len, buflen,
                    532:                                        hdr->cmd_letter, hdr->cmd_fn);
                    533: #endif
                    534:                                rln_rx_pdata(sc, buf, buflen, &pd);
                    535:                                /* Drain the rest somewhere. */
                    536:                                rln_rx_pdata(sc, data, len - buflen, &pd);
                    537:                        }
                    538:                }
                    539:                rln_rx_end(sc);
                    540:
                    541:                /* This message can now be handled by the waiter. */
                    542:                rln_mbox_unlock(sc, hdr->cmd_seq, len + sizeof *hdr);
                    543:                return;
                    544:        }
                    545:
                    546:        /* Otherwise, handle the message, right here, right now. */
                    547:
                    548:        /* Check if we can cope with the size of this message. */
                    549:        if (len > sizeof data) {
                    550:                printf("%s: msg too big (%d)\n", sc->sc_dev.dv_xname, len);
                    551:                ifp->if_ierrors++;
                    552:                rln_rx_end(sc);
                    553:                /* rln_need_reset(sc); */
                    554:                return;
                    555:        }
                    556:
                    557:        /* Check for error results. */
                    558:        if (hdr->cmd_error & 0x80) {
                    559:                printf("%s: command error 0x%02x command %c%d len=%d\n",
                    560:                        sc->sc_dev.dv_xname,
                    561:                        hdr->cmd_error & ~0x80,
                    562:                        hdr->cmd_letter, hdr->cmd_fn,
                    563:                        len);
                    564:                ifp->if_ierrors++;
                    565:                rln_rx_end(sc);
                    566:                rln_need_reset(sc);
                    567:                return;
                    568:        }
                    569:
                    570:        /*
                    571:         * "b1": Receiving a packet is a special case.
                    572:         * We wish to read the data with pio straight into an
                    573:         * mbuf to avoid a memory-memory copy.
                    574:         */
                    575:        if (hdr->cmd_letter == 'b' && hdr->cmd_fn == 1) {
                    576:                m = rlnget(sc, hdr, len);
                    577:                rln_rx_end(sc);
                    578:                if (m == NULL)
                    579:                        return;
                    580:                ifp->if_ipackets++;
                    581: #ifdef DIAGNOSTIC
                    582:                if (bcmp(mtod(m, u_int8_t *), "prox", 4) == 0) {
                    583:                        printf("%s: proxim special packet received\n",
                    584:                            sc->sc_dev.dv_xname);
                    585:                }
                    586: #endif
                    587:
                    588: #if NBPFILTER > 0
                    589:                if (ifp->if_bpf)
                    590:                        bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
                    591: #endif
                    592:
                    593:                ether_input_mbuf(ifp, m);
                    594:                return;
                    595:        }
                    596:
                    597:
                    598:        /* Otherwise we read the packet into a buffer on the stack. */
                    599:        bcopy(hdr, data, sizeof *hdr);
                    600:        if (len > sizeof *hdr)
                    601:                rln_rx_pdata(sc, data + sizeof *hdr, len - sizeof *hdr, &pd);
                    602:        rln_rx_end(sc);
                    603:
                    604: #ifdef RLNDUMP
                    605:        printf("%s: recv %c%d seq %d data ", sc->sc_dev.dv_xname,
                    606:            hdr->cmd_letter, hdr->cmd_fn, hdr->cmd_seq);
                    607:        RLNDUMPHEX(hdr, sizeof hdr);
                    608:        printf(":");
                    609:        RLNDUMPHEX(data + sizeof hdr, len - sizeof hdr);
                    610:        printf("\n");
                    611: #endif
                    612:
                    613:        switch (RLN_MM_CMD(hdr->cmd_letter, hdr->cmd_fn)) {
                    614:        case RLN_MM_CMD('b', 0):                        /* b0: Transmit done. */
                    615: #ifdef DIAGNOSTIC
                    616:                if (len != 7)
                    617:                        printf("%s: 'b0' len %d != 7\n",
                    618:                            sc->sc_dev.dv_xname, len);
                    619: #endif
                    620:                ifp->if_flags &= ~IFF_OACTIVE;
                    621:                ifp->if_opackets++;
                    622:                s = splnet();
                    623:                rlnstart(ifp);
                    624:                splx(s);
                    625:                break;
                    626:
                    627:        case RLN_MM_CMD('a', 20):                       /* a20: Card fault. */
                    628:                printf("%s: hardware fault\n", sc->sc_dev.dv_xname);
                    629:                break;
                    630:
                    631:        case RLN_MM_CMD('a', 4):                        /* a4: Sync'd. */
                    632:                if (bcmp(syncp->enaddr, sc->sc_arpcom.ac_enaddr,
                    633:                    ETHER_ADDR_LEN) == 0) {
                    634:                        /* Sync'd to own enaddr. */
                    635:  /*
                    636:   * From http://www.proxim.com/support/faq/7400.shtml
                    637:   * 3. RLNSETUP reports that I'm synchronized to my own MAC address. What
                    638:   *    does that mean?
                    639:   *    You are the acting Master for this network. Either you are
                    640:   *    configured as the Master or as an Alternate Master. If you are an
                    641:   *    Alternate Master, you may be out of range or on a different Domain
                    642:   *    and Security ID from the true Master.
                    643:   */
                    644:
                    645:                        printf("%s: nothing to sync to; now master ",
                    646:                            sc->sc_dev.dv_xname);
                    647:                }
                    648:                else
                    649:                        printf("%s: synchronised to ", sc->sc_dev.dv_xname);
                    650:                printf("%.11s (%s) channel %d/%d\n",
                    651:                    syncp->mastername,
                    652:                    ether_sprintf(syncp->enaddr),
                    653:                    syncp->channel,
                    654:                    syncp->subchannel);
                    655:
                    656:                /* Record the new circumstances. */
                    657:                sc->sc_param.rp_channel = syncp->channel;
                    658:                sc->sc_param.rp_subchannel = syncp->subchannel;
                    659:                sc->sc_state |= RLN_STATE_SYNC;
                    660:
                    661:                /* Resume sending. */
                    662:                s = splnet();
                    663:                rlnstart(ifp);
                    664:                splx(s);
                    665:                break;
                    666:
                    667:        case RLN_MM_CMD('a', 5):                        /* a4: Lost sync. */
                    668:                printf("%s: lost sync\n", sc->sc_dev.dv_xname);
                    669:                sc->sc_state &= ~RLN_STATE_SYNC;
                    670:                break;
                    671:
                    672:        case RLN_MM_CMD('a', 18):                       /* a18: Roaming. */
                    673:                printf("%s: roaming\n", sc->sc_dev.dv_xname);
                    674:                break;
                    675:        default:
                    676: #ifdef DIAGNOSTIC
                    677:                printf("%s: msg `%c%d' seq %d data {",
                    678:                    sc->sc_dev.dv_xname,
                    679:                    hdr->cmd_letter, hdr->cmd_fn, hdr->cmd_seq);
                    680:                RLNDUMPHEX(hdr, sizeof hdr);
                    681:                printf(":");
                    682:                RLNDUMPHEX(data, len);
                    683:                printf("}\n");
                    684: #endif
                    685:                break;
                    686:        }
                    687:
                    688: }
                    689:
                    690: /* Extract a received network packet from the card. */
                    691: struct mbuf *
                    692: rlnget(sc, hdr, totlen)
                    693:        struct rln_softc *sc;
                    694:        struct rln_mm_cmd *hdr;
                    695:        int totlen;
                    696: {
                    697:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
                    698:        int len;
                    699:        int pad;
                    700:        struct mbuf *m, **mp, *top;
                    701:        struct rln_pdata pd = RLN_PDATA_INIT;
                    702:        struct {
                    703:                u_int8_t rssi;
                    704:                u_int8_t xxx1;  /* always 00? */
                    705:                u_int16_t len;  /* payload length */
                    706:                u_int8_t xxx2;  /* always 00? */
                    707:                u_int8_t xxx3;  /* always c0? */
                    708:                u_int8_t seq;
                    709:                u_int8_t xxx4;
                    710:                struct  ether_addr to;   /* destination station addr */
                    711:                struct  ether_addr from; /* sending station addr */
                    712:        } hwhdr;
                    713:
                    714:        dprintf(" [get]");
                    715:
                    716: #ifdef RLNDUMP
                    717:        /* Decode the command header: */
                    718:        printf("%s: recv %c%d seq %d data ", sc->sc_dev.dv_xname,
                    719:            hdr->cmd_letter, hdr->cmd_fn, hdr->cmd_seq);
                    720:        RLNDUMPHEX(hdr, sizeof hdr);
                    721:        printf(":");
                    722: #endif
                    723:        totlen -= sizeof *hdr;
                    724:
                    725: #ifdef DIAGNOSTIC
                    726:        if (totlen <= 0) {
                    727:                printf("%s: empty packet", sc->sc_dev.dv_xname);
                    728:                goto drop;
                    729:        }
                    730: #endif
                    731:
                    732:        /* Decode the hardware header: */
                    733:        rln_rx_pdata(sc, &hwhdr, sizeof hwhdr, &pd);
                    734:        totlen -= sizeof hwhdr;
                    735: #ifdef RLNDUMP
                    736:        RLNDUMPHEX(&hwhdr, sizeof hwhdr);
                    737:        printf("/");
                    738: #endif
                    739:        /* (Most of the following code fleeced from elink3.c.) */
                    740:
                    741:        MGETHDR(m, M_DONTWAIT, MT_DATA);
                    742:        if (m == NULL)
                    743:                goto drop;
                    744:        m->m_pkthdr.rcvif = ifp;
                    745:        m->m_pkthdr.len = totlen;
                    746:        /*
                    747:         * Insert some leading padding in the mbuf, so that payload data is
                    748:         * aligned.
                    749:         */
                    750:        pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header);
                    751:        m->m_data += pad;
                    752:        len = MHLEN - pad;
                    753:        top = 0;
                    754:        mp = &top;
                    755:
                    756:        while (totlen > 0) {
                    757:                if (top) {
                    758:                        MGET(m, M_DONTWAIT, MT_DATA);
                    759:                        if (m == NULL) {
                    760:                                m_freem(top);
                    761:                                goto drop;
                    762:                        }
                    763:                        len = MLEN;
                    764:                }
                    765:                if (totlen >= MINCLSIZE) {
                    766:                        MCLGET(m, M_DONTWAIT);
                    767:                        if (m->m_flags & M_EXT) {
                    768:                                len = MCLBYTES;
                    769:                                if (!top) {
                    770:                                        m->m_data += pad;
                    771:                                        len -= pad;
                    772:                                }
                    773:                        }
                    774:                }
                    775:                len = min(totlen, len);
                    776:                rln_rx_pdata(sc, mtod(m, u_int8_t *), len, &pd);
                    777: #ifdef RLNDUMP
                    778:                RLNDUMPHEX(mtod(m, u_int8_t *), len);
                    779:                if (totlen != len)
                    780:                        printf("|");
                    781: #endif
                    782:                m->m_len = len;
                    783:                totlen -= len;
                    784:                *mp = m;
                    785:                mp = &m->m_next;
                    786:        }
                    787: #ifdef RLNDUMP
                    788:        printf("\n");
                    789: #endif
                    790:        return top;
                    791:
                    792: drop:
                    793: #ifdef RLNDUMP
                    794:        printf(": drop\n");
                    795: #endif
                    796:        ifp->if_iqdrops++;
                    797:        return NULL;
                    798: }
                    799:
                    800: /* Interface control. */
                    801: int
                    802: rlnioctl(ifp, cmd, data)
                    803:        struct ifnet *ifp;
                    804:        u_long cmd;
                    805:        caddr_t data;
                    806: {
                    807:        struct rln_softc *sc = ifp->if_softc;
                    808:        struct ifaddr *ifa = (struct ifaddr *)data;
                    809:        int s, error;
                    810:        int need_init;
                    811:
                    812:        printf("%s: ioctl cmd[%c/%d] data=%x\n", sc->sc_dev.dv_xname,
                    813:                IOCGROUP(cmd), IOCBASECMD(cmd), data);
                    814:
                    815:        s = splnet();
                    816:        if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) != 0) {
                    817:                splx(s);
                    818:                return error;
                    819:        }
                    820:
                    821:        switch (cmd) {
                    822:        case SIOCSIFADDR:
                    823:                /* Set address. */
                    824:                ifp->if_flags |= IFF_UP;
                    825:
                    826:                switch (ifa->ifa_addr->sa_family) {
                    827: #ifdef INET
                    828:                case AF_INET:
                    829:                        rlninit(sc);
                    830:                        arp_ifinit(&sc->sc_arpcom, ifa);
                    831:                        break;
                    832: #endif
                    833:                default:
                    834:                        rlninit(sc);
                    835:                        break;
                    836:                }
                    837:                break;
                    838:
                    839:        case SIOCSIFFLAGS:
                    840:                need_init = 0;
                    841:
                    842:                if ((ifp->if_flags & IFF_UP) == 0 &&
                    843:                    (ifp->if_flags & IFF_RUNNING) != 0) {
                    844:                        /* Was running, want down: stop. */
                    845:                        rlnstop(sc);
                    846:                } else if ((ifp->if_flags & IFF_UP) != 0 &&
                    847:                           (ifp->if_flags & IFF_RUNNING) == 0) {
                    848:                        /* Was not running, want up: start. */
                    849:                        need_init = 1;
                    850:                }
                    851:
                    852:                if (ifp->if_flags & IFF_RUNNING) {
                    853:                        if ((ifp->if_flags & IFF_PROMISC) &&
                    854:                            (sc->sc_state & RLN_STATE_PROMISC) == 0) {
                    855:                                sc->sc_state |= RLN_STATE_PROMISC;
                    856:                                need_init = 1;
                    857:                        }
                    858:                        else if ((ifp->if_flags & IFF_PROMISC) == 0 &&
                    859:                            (sc->sc_state & RLN_STATE_PROMISC)) {
                    860:                                sc->sc_state &= ~RLN_STATE_PROMISC;
                    861:                                need_init = 1;
                    862:                        }
                    863:                }
                    864:
                    865:                if (need_init)
                    866:                        rlninit(sc);
                    867:
                    868:                break;
                    869:
                    870:        case SIOCADDMULTI:
                    871:        case SIOCDELMULTI:
                    872:                error = EOPNOTSUPP;
                    873:                break;
                    874:
                    875: #if notyet
                    876:        case RLNIOSPARAM:
                    877:                error = rln_iosetparam(sc, (struct rln_param *)&data);
                    878:                break;
                    879:
                    880:        case RLNIOGPARAM:
                    881:                bcopy(&sc->sc_param, (struct rln_param *)&data,
                    882:                    sizeof sc->sc_param);
                    883:                break;
                    884: #endif
                    885:
                    886:        default:
                    887:                error = EINVAL;
                    888:                break;
                    889:        }
                    890:
                    891:        splx(s);
                    892:        return (error);
                    893: }
                    894:
                    895: /* Stop output from the card. */
                    896: void
                    897: rlnstop(sc)
                    898:        struct rln_softc *sc;
                    899: {
                    900:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
                    901:
                    902:        dprintf(" [stop]");
                    903:        ifp->if_flags &= ~IFF_RUNNING;
                    904:        rln_enable(sc, 0);
                    905: }
                    906:
                    907: /* Get MAC address from card. */
                    908: int
                    909: rln_getenaddr(sc, enaddr)
                    910:        struct rln_softc *sc;
                    911:        u_int8_t * enaddr;
                    912: {
                    913:        struct rln_mm_cmd query = RLN_MM_GETENADDR;
                    914:        struct rln_mm_gotenaddr response = { RLN_MM_GETENADDR };
                    915:
                    916:        if (rln_msg_txrx(sc, &query, sizeof query,
                    917:            &response, sizeof response))
                    918:                return (-1);
                    919:        bcopy(response.enaddr, enaddr, sizeof response.enaddr);
                    920:        return (0);
                    921: };
                    922:
                    923: /* Get firmware version string from card. */
                    924: int
                    925: rln_getpromvers(sc, ver, verlen)
                    926:        struct rln_softc *sc;
                    927:        char *ver;
                    928:        int verlen;
                    929: {
                    930:        struct rln_mm_cmd query = RLN_MM_GETPROMVERSION;
                    931:        struct rln_mm_gotpromversion response = { RLN_MM_GOTPROMVERSION };
                    932:        int i;
                    933:
                    934: #ifdef DIAGNOSTIC
                    935:        if (verlen != sizeof response.version)
                    936:                panic("rln_getpromvers");
                    937: #endif
                    938:
                    939:        if (rln_msg_txrx(sc, &query, sizeof query,
                    940:            &response, sizeof response))
                    941:                return (-1);
                    942:        bcopy(response.version, ver, verlen);
                    943:        /* Nul trailing spaces. */
                    944:        for (i = verlen - 1; i >= 0 && ver[i] <= ' '; i--)
                    945:                ver[i] = '\0';
                    946:        return (0);
                    947: };
                    948:
                    949: /* Set default operational parameters on card. */
                    950: int
                    951: rln_sendinit(sc)
                    952:        struct rln_softc *sc;
                    953: {
                    954:        struct rln_mm_init init = { RLN_MM_INIT };
                    955:        struct rln_mm_initted iresponse;
                    956: #if 0
                    957:        struct rln_mm_setmagic magic = { RLN_MM_SETMAGIC };
                    958:        struct rln_mm_disablehopping hop = { RLN_MM_DISABLEHOPPING };
                    959:        struct rln_mm_cmd response;
                    960: #endif
                    961:
                    962:        bzero((char *)&init + sizeof init.mm_cmd,
                    963:                sizeof init - sizeof init.mm_cmd);
                    964:
                    965:        dprintf(" [setting parameters]");
                    966:        init.opmode = (sc->sc_state & RLN_STATE_PROMISC ?
                    967:            RLN_MM_INIT_OPMODE_PROMISC : RLN_MM_INIT_OPMODE_NORMAL);
                    968:        init.stationtype = sc->sc_param.rp_station_type;
                    969:
                    970:        /* Spread-spectrum frequency hopping. */
                    971:        init.hop_period = 1;
                    972:        init.bfreq = 2;
                    973:        init.sfreq = 7;
                    974:
                    975:        /* Choose channel. */
                    976:        init.channel = sc->sc_param.rp_channel;
                    977:        init.subchannel = sc->sc_param.rp_subchannel;
                    978:        init.domain = sc->sc_param.rp_domain;
                    979:
                    980:        /* Name of this station when acting as master. */
                    981:        bcopy(sc->sc_param.rp_master, init.mastername, sizeof init.mastername);
                    982:
                    983:        /* Security params. */
                    984:        init.sec1 = (sc->sc_param.rp_security & 0x0000ff) >> 0;
                    985:        init.sec2 = (sc->sc_param.rp_security & 0x00ff00) >> 8;
                    986:        init.sec3 = (sc->sc_param.rp_security & 0xff0000) >> 16;
                    987:
                    988:        init.sync_to = 1;
                    989:        bzero(init.syncname, sizeof init.syncname);
                    990:
                    991:        if (rln_msg_txrx(sc, &init, sizeof init,
                    992:            &iresponse, sizeof iresponse))
                    993:                return (-1);
                    994: #if 0
                    995:        dprintf(" [setting magic]");
                    996:        magic.fairness_slot = 3;        /* lite: 1, norm: 3, off: -1 */
                    997:        magic.deferral_slot = 3;        /* lite: 0, norm: 3, off: -1 */
                    998:        magic.regular_mac_retry = 7;
                    999:        magic.frag_mac_retry = 10;
                   1000:        magic.regular_mac_qfsk = 2;
                   1001:        magic.frag_mac_qfsk = 5;
                   1002:        magic.xxx1 = 0xff;
                   1003:        magic.xxx2 = 0xff;
                   1004:        magic.xxx3 = 0xff;
                   1005:        magic.xxx4 = 0x00;
                   1006:        if (rln_msg_txrx(sc, &magic, sizeof magic,
                   1007:            &response, sizeof response))
                   1008:                return (-1);
                   1009:
                   1010:        dprintf(" [disabling freq hopping]");
                   1011:        hop.hopflag = RLN_MM_DISABLEHOPPING_HOPFLAG_DISABLE;
                   1012:        if (rln_msg_txrx(sc, &hop, sizeof hop,
                   1013:            &response, sizeof response))
                   1014:                return (-1);
                   1015:
                   1016: #endif
                   1017:        return (0);
                   1018: }
                   1019:
                   1020: #if notyet
                   1021: /* Configure the way the card leaves a basestation. */
                   1022: int
                   1023: rln_roamconfig(sc)
                   1024:        struct rln_softc *sc;
                   1025: {
                   1026:        struct rln_mm_setroaming roam = { RLN_MM_SETROAMING };
                   1027:        struct rln_mm_cmd response;
                   1028:        static int retry[3] = { 6, 6, 4 };
                   1029:        static int rssi[3] = { 5, 15, 5 };
                   1030:
                   1031:        dprintf(" [roamconfig]");
                   1032: #ifdef DIAGNOSTIC
                   1033:        if (sc->sc_param.rp_roam_config > 2)
                   1034:                panic("roamconfig");
                   1035: #endif
                   1036:        roam.sync_alarm = 0;
                   1037:        roam.retry_thresh = retry[sc->sc_param.rp_roam_config];
                   1038:        roam.rssi_threshold = rssi[sc->sc_param.rp_roam_config];
                   1039:        roam.xxx1 = 0x5a;
                   1040:        roam.sync_rssi_threshold = 0;
                   1041:        roam.xxx2 = 0x5a;
                   1042:        roam.missed_sync = 0x4;
                   1043:        if (rln_msg_txrx(sc, &roam, sizeof roam,
                   1044:            &response, sizeof response))
                   1045:                return (-1);
                   1046:
                   1047:        return (0);
                   1048: }
                   1049:
                   1050: /* Enable roaming. */
                   1051: int
                   1052: rln_roam(sc)
                   1053:        struct rln_softc *sc;
                   1054: {
                   1055:        struct rln_mm_cmd roam = RLN_MM_ROAM;
                   1056:        struct rln_mm_cmd response;
                   1057:
                   1058:        return (rln_msg_txrx(sc, &roam, sizeof roam,
                   1059:            &response, sizeof response));
                   1060: }
                   1061:
                   1062: /* Enable multicast capability. */
                   1063: int
                   1064: rln_multicast(sc, enable)
                   1065:        struct rln_softc *sc;
                   1066:        int enable;
                   1067: {
                   1068:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
                   1069:        struct rln_mm_multicast mcast = { RLN_MM_MULTICAST };
                   1070:        struct rln_mm_cmd response;
                   1071:        int ret;
                   1072:
                   1073:        mcast.enable = enable;
                   1074:
                   1075:        ret = rln_msg_txrx(sc, &mcast, sizeof mcast,
                   1076:            &response, sizeof response);
                   1077:        if (ret == 0) {
                   1078:                if (enable)
                   1079:                        ifp->if_flags |= IFF_MULTICAST;
                   1080:                else
                   1081:                        ifp->if_flags &= ~IFF_MULTICAST;
                   1082:        }
                   1083:        return (ret);
                   1084: }
                   1085:
                   1086: /* Search for and sync with any master. */
                   1087: int
                   1088: rln_searchsync(sc)
                   1089:        struct rln_softc *sc;
                   1090: {
                   1091:        struct rln_mm_search search = { RLN_MM_SEARCH };
                   1092:        struct rln_mm_searching response;
                   1093:
                   1094:        bzero(search.xxx1, sizeof search.xxx1);
                   1095:        search.domain = sc->sc_param.rp_domain;
                   1096:        search.roaming = 1;
                   1097:        search.xxx3 = 0;
                   1098:        search.xxx4 = 1;
                   1099:        search.xxx5 = 0;
                   1100:        bzero(search.xxx6, sizeof search.xxx6);
                   1101:
                   1102:        return (rln_msg_txrx(sc, &search, sizeof search,
                   1103:                &response, sizeof response));
                   1104: }
                   1105:
                   1106: /* Set values from an external parameter block. */
                   1107: int
                   1108: rln_iosetparam(sc, param)
                   1109:        struct rln_softc *sc;
                   1110:        struct rln_param *param;
                   1111: {
                   1112:        int error = 0;
                   1113:
                   1114:        if (param->rp_roam_config > 2)
                   1115:                error = EINVAL;
                   1116:        if (param->rp_security > 0x00ffffff)
                   1117:                error = EINVAL;
                   1118:        if (param->rp_station_type > 2)
                   1119:                error = EINVAL;
                   1120:        if (param->rp_channel > 15)
                   1121:                error = EINVAL;
                   1122:        if (param->rp_subchannel > 15)
                   1123:                error = EINVAL;
                   1124:        if (error == 0) {
                   1125:                /* Apply immediately. */
                   1126:                bcopy(param, &sc->sc_param, sizeof *param);
                   1127:                if (rln_sendinit(sc))
                   1128:                        error = EIO;
                   1129:        }
                   1130:        return (error);
                   1131: }
                   1132:
                   1133: /* Protect the eeprom from storing a security ID(?) */
                   1134: int
                   1135: rln_lockprom(sc)
                   1136:        struct rln_softc *sc;
                   1137: {
                   1138:        struct rln_mm_cmd lock = RLN_MM_EEPROM_PROTECT;
                   1139:        struct rln_mm_cmd response;
                   1140:
                   1141:        /* XXX Always yields an error? */
                   1142:        return (rln_msg_txrx(sc, &lock, sizeof lock,
                   1143:            &response, sizeof response));
                   1144: }
                   1145:
                   1146: /* Set the h/w Inactivity Time Out timer on the card. */
                   1147: int
                   1148: rln_ito(sc)
                   1149:        struct rln_softc * sc;
                   1150: {
                   1151:        struct rln_mm_setito ito = { RLN_MM_MULTICAST };
                   1152:        struct rln_mm_cmd response;
                   1153:
                   1154:        ito.xxx = 3;
                   1155:        ito.timeout = LLDInactivityTimeOut /* enabler, 0 or 1 */;
                   1156:        ito.bd_wakeup = LLDBDWakeup /* 0 */;
                   1157:        ito.pm_sync = LLDPMSync /* 0 */;
                   1158:        ito.sniff_time = ito.timeout ? LLDSniffTime /* 0 */ : 0;
                   1159:
                   1160:        if (rln_msg_txrx(sc, &ito, sizeof ito,
                   1161:            &response, sizeof response))
                   1162:                return (-1);
                   1163: }
                   1164:
                   1165: /* Put the card into standby mode. */
                   1166: int
                   1167: rln_standby(sc)
                   1168:        struct rln_softc * sc;
                   1169: {
                   1170:        struct rln_mm_standby standby = { RLN_MM_STANDBY };
                   1171:
                   1172:        standby.xxx = 0;
                   1173:        if (rln_msg_txrx(sc, &ito, sizeof ito, NULL, 0))
                   1174:                return (-1);
                   1175: }
                   1176:
                   1177: void
                   1178: rln_crypt(userkey, cardkey)
                   1179:        char *userkey;          /* User's string (max 20 chars). */
                   1180:        u_int8_t *cardkey;      /* 20 bits (3 bytes) */
                   1181: {
                   1182:        /*
                   1183:         * From <http://www.proxim.com/learn/whiteppr/rl2security.shtml>
                   1184:         * "RangeLAN2 Security Features":
                   1185:         *
                   1186:          *  The Security ID is a unique, 20 character alphanumeric
                   1187:          *  string defined and configured by the user. It must be
                   1188:          *  identically configured in every radio intended to
                   1189:          *  communicate with others in the same network. Once
                   1190:          *  configured, the Security ID is reduced to 20 bits by a
                   1191:          *  proprietary algorithm confidential to Proxim. It is
                   1192:          *  merged with the radio MAC address (a 12 character field
                   1193:          *  unique to every radio), scrambled and stored using another
                   1194:          *  proprietary, confidential algorithm.
                   1195:         */
                   1196:         int32_t key;
                   1197:         int8_t ret;
                   1198:         int i;
                   1199:        int len;
                   1200:        int32_t multiplicand = 0x80000181;
                   1201:        int64_t res;
                   1202:
                   1203:        /*
                   1204:         * This algorithm is `compatible' with Proxim's first
                   1205:         * `proprietary confidential algorithm': i.e., it appears
                   1206:         * to be functionally identical.
                   1207:         */
                   1208:        len = strlen(s);
                   1209:         key = 0x030201;
                   1210:         for (i = 0; i < len; i++) {
                   1211:
                   1212:                 key *= userkey[i];
                   1213:                 res = (int64_t)multiplicand * key;
                   1214:                 key = key - 0xfffffd *
                   1215:                    (((key + (int32_t)(res >> 32)) >> 23) - (key >> 31));
                   1216:         }
                   1217:
                   1218:         cardkey[0] = (key >> 16) & 0xff;
                   1219:         cardkey[1] = (key >> 8) & 0xff;
                   1220:         cardkey[2] = key & 0xff;
                   1221:
                   1222:        cardkey[0] |= 0x03;     /* Restrict key space by 2 bits. */
                   1223: }
                   1224: #endif

CVSweb