[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     ! 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