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

Annotation of sys/dev/ic/an.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: an.c,v 1.53 2007/01/03 18:16:43 claudio Exp $ */
        !             2: /*     $NetBSD: an.c,v 1.34 2005/06/20 02:49:18 atatat Exp $   */
        !             3: /*
        !             4:  * Copyright (c) 1997, 1998, 1999
        !             5:  *     Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
        !             6:  *
        !             7:  * Redistribution and use in source and binary forms, with or without
        !             8:  * modification, are permitted provided that the following conditions
        !             9:  * are met:
        !            10:  * 1. Redistributions of source code must retain the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer.
        !            12:  * 2. Redistributions in binary form must reproduce the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer in the
        !            14:  *    documentation and/or other materials provided with the distribution.
        !            15:  * 3. All advertising materials mentioning features or use of this software
        !            16:  *    must display the following acknowledgement:
        !            17:  *     This product includes software developed by Bill Paul.
        !            18:  * 4. Neither the name of the author nor the names of any co-contributors
        !            19:  *    may be used to endorse or promote products derived from this software
        !            20:  *    without specific prior written permission.
        !            21:  *
        !            22:  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
        !            23:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            24:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            25:  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
        !            26:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            27:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            28:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            29:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            30:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            31:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
        !            32:  * THE POSSIBILITY OF SUCH DAMAGE.
        !            33:  *
        !            34:  * $FreeBSD: src/sys/dev/an/if_an.c,v 1.12 2000/11/13 23:04:12 wpaul Exp $
        !            35:  */
        !            36: /*
        !            37:  * Copyright (c) 2004, 2005 David Young.  All rights reserved.
        !            38:  * Copyright (c) 2004, 2005 OJC Technologies.  All rights reserved.
        !            39:  * Copyright (c) 2004, 2005 Dayton Data Center Services, LLC.  All
        !            40:  *     rights reserved.
        !            41:  *
        !            42:  * Redistribution and use in source and binary forms, with or without
        !            43:  * modification, are permitted provided that the following conditions
        !            44:  * are met:
        !            45:  * 1. Redistributions of source code must retain the above copyright
        !            46:  *    notice, this list of conditions and the following disclaimer.
        !            47:  * 2. Redistributions in binary form must reproduce the above copyright
        !            48:  *    notice, this list of conditions and the following disclaimer in the
        !            49:  *    documentation and/or other materials provided with the distribution.
        !            50:  * 3. Neither the name of the author nor the names of any co-contributors
        !            51:  *    may be used to endorse or promote products derived from this software
        !            52:  *    without specific prior written permission.
        !            53:  *
        !            54:  * THIS SOFTWARE IS PROVIDED BY David Young AND CONTRIBUTORS ``AS IS'' AND
        !            55:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            56:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            57:  * ARE DISCLAIMED.  IN NO EVENT SHALL David Young AND CONTRIBUTORS
        !            58:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            59:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            60:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            61:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            62:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            63:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
        !            64:  * THE POSSIBILITY OF SUCH DAMAGE.
        !            65:  */
        !            66:
        !            67: /*
        !            68:  * Aironet 4500/4800 802.11 PCMCIA/ISA/PCI driver for FreeBSD.
        !            69:  *
        !            70:  * Written by Bill Paul <wpaul@ctr.columbia.edu>
        !            71:  * Electrical Engineering Department
        !            72:  * Columbia University, New York City
        !            73:  */
        !            74:
        !            75: /*
        !            76:  * Ported to NetBSD from FreeBSD by Atsushi Onoe at the San Diego
        !            77:  * IETF meeting.
        !            78:  */
        !            79:
        !            80: #include <sys/cdefs.h>
        !            81:
        !            82: #include "bpfilter.h"
        !            83:
        !            84: #include <sys/param.h>
        !            85: #include <sys/systm.h>
        !            86: #include <sys/sockio.h>
        !            87: #include <sys/mbuf.h>
        !            88: #include <sys/kernel.h>
        !            89: #include <sys/ucred.h>
        !            90: #include <sys/socket.h>
        !            91: #include <sys/timeout.h>
        !            92: #include <sys/device.h>
        !            93: #include <sys/proc.h>
        !            94: #include <sys/endian.h>
        !            95: #include <sys/tree.h>
        !            96:
        !            97: #include <machine/bus.h>
        !            98:
        !            99: #include <net/if.h>
        !           100: #include <net/if_dl.h>
        !           101: #include <net/if_llc.h>
        !           102: #include <net/if_media.h>
        !           103: #include <net/if_types.h>
        !           104:
        !           105: #ifdef INET
        !           106: #include <netinet/in.h>
        !           107: #include <netinet/in_systm.h>
        !           108: #include <netinet/in_var.h>
        !           109: #include <netinet/ip.h>
        !           110: #include <netinet/if_ether.h>
        !           111: #endif
        !           112:
        !           113: #include <net80211/ieee80211_radiotap.h>
        !           114: #include <net80211/ieee80211_var.h>
        !           115:
        !           116: #if NBPFILTER > 0
        !           117: #include <net/bpf.h>
        !           118: #endif
        !           119:
        !           120: #include <dev/ic/anreg.h>
        !           121: #include <dev/ic/anvar.h>
        !           122:
        !           123: struct cfdriver an_cd = {
        !           124:        NULL, "an", DV_IFNET
        !           125: };
        !           126:
        !           127: int    an_reset(struct an_softc *);
        !           128: void   an_wait(struct an_softc *);
        !           129: int    an_init(struct ifnet *);
        !           130: void   an_stop(struct ifnet *, int);
        !           131: void   an_start(struct ifnet *);
        !           132: void   an_watchdog(struct ifnet *);
        !           133: int    an_ioctl(struct ifnet *, u_long, caddr_t);
        !           134: int    an_media_change(struct ifnet *);
        !           135: void   an_media_status(struct ifnet *, struct ifmediareq *);
        !           136:
        !           137: int    an_set_nwkey(struct an_softc *, struct ieee80211_nwkey *);
        !           138: int    an_set_nwkey_wep(struct an_softc *, struct ieee80211_nwkey *);
        !           139: int    an_get_nwkey(struct an_softc *, struct ieee80211_nwkey *);
        !           140: int    an_write_wepkey(struct an_softc *, int, struct an_wepkey *,
        !           141:                                int);
        !           142:
        !           143: void   an_rxeof(struct an_softc *);
        !           144: void   an_txeof(struct an_softc *, u_int16_t);
        !           145: void   an_linkstat_intr(struct an_softc *);
        !           146:
        !           147: int    an_cmd(struct an_softc *, int, int);
        !           148: int    an_seek_bap(struct an_softc *, int, int);
        !           149: int    an_read_bap(struct an_softc *, int, int, void *, int, int);
        !           150: int    an_write_bap(struct an_softc *, int, int, void *, int);
        !           151: int    an_mwrite_bap(struct an_softc *, int, int, struct mbuf *, int);
        !           152: int    an_read_rid(struct an_softc *, int, void *, int *);
        !           153: int    an_write_rid(struct an_softc *, int, void *, int);
        !           154:
        !           155: int    an_alloc_nicmem(struct an_softc *, int, int *);
        !           156:
        !           157: int    an_newstate(struct ieee80211com *, enum ieee80211_state, int);
        !           158:
        !           159: #ifdef AN_DEBUG
        !           160: int an_debug = 0;
        !           161:
        !           162: #define        DPRINTF(X)      if (an_debug) printf X
        !           163: #define        DPRINTF2(X)     if (an_debug > 1) printf X
        !           164: #else
        !           165: #define        DPRINTF(X)
        !           166: #define        DPRINTF2(X)
        !           167: #endif
        !           168:
        !           169: #if BYTE_ORDER == BIG_ENDIAN
        !           170: static __inline void
        !           171: an_swap16(u_int16_t *p, int cnt)
        !           172: {
        !           173:         for (; cnt--; p++)
        !           174:                 *p = swap16(*p);
        !           175: }
        !           176: #define an_switch32(val)       (val >> 16 | (val & 0xFFFF) << 16)
        !           177: #else
        !           178: #define an_swap16(p, cnt)
        !           179: #define an_switch32(val)       val
        !           180: #endif
        !           181:
        !           182: int
        !           183: an_attach(struct an_softc *sc)
        !           184: {
        !           185:        struct ieee80211com *ic = &sc->sc_ic;
        !           186:        struct ifnet *ifp = &ic->ic_if;
        !           187:        int i;
        !           188:        struct an_rid_wepkey *akey;
        !           189:        int buflen, kid, rid;
        !           190:        int chan, chan_min, chan_max;
        !           191:
        !           192:        sc->sc_invalid = 0;
        !           193:
        !           194:        /* disable interrupts */
        !           195:        CSR_WRITE_2(sc, AN_INT_EN, 0);
        !           196:        CSR_WRITE_2(sc, AN_EVENT_ACK, 0xffff);
        !           197:
        !           198: //     an_wait(sc);
        !           199:        if (an_reset(sc) != 0) {
        !           200:                sc->sc_invalid = 1;
        !           201:                return 1;
        !           202:        }
        !           203:
        !           204:        /* Load factory config */
        !           205:        if (an_cmd(sc, AN_CMD_READCFG, 0) != 0) {
        !           206:                printf("%s: failed to load config data\n",
        !           207:                    sc->sc_dev.dv_xname);
        !           208:                return (EIO);
        !           209:        }
        !           210:
        !           211:        /* Read the current configuration */
        !           212:        buflen = sizeof(sc->sc_config);
        !           213:        if (an_read_rid(sc, AN_RID_GENCONFIG, &sc->sc_config, &buflen) != 0) {
        !           214:                printf("%s: read config failed\n", sc->sc_dev.dv_xname);
        !           215:                return(EIO);
        !           216:        }
        !           217:
        !           218:        an_swap16((u_int16_t *)&sc->sc_config.an_macaddr, 3);
        !           219:
        !           220:        /* Read the card capabilities */
        !           221:        buflen = sizeof(sc->sc_caps);
        !           222:        if (an_read_rid(sc, AN_RID_CAPABILITIES, &sc->sc_caps, &buflen) != 0) {
        !           223:                printf("%s: read caps failed\n", sc->sc_dev.dv_xname);
        !           224:                return(EIO);
        !           225:        }
        !           226:
        !           227:        an_swap16((u_int16_t *)&sc->sc_caps.an_oemaddr, 3);
        !           228:        an_swap16((u_int16_t *)&sc->sc_caps.an_rates, 4);
        !           229:
        !           230:        /* Read WEP settings from persistent memory */
        !           231:        akey = &sc->sc_buf.sc_wepkey;
        !           232:        buflen = sizeof(struct an_rid_wepkey);
        !           233:        rid = AN_RID_WEP_VOLATILE;      /* first persistent key */
        !           234:        while (an_read_rid(sc, rid, akey, &buflen) == 0) {
        !           235:                an_swap16((u_int16_t *)&akey->an_mac_addr, 3);
        !           236:                an_swap16((u_int16_t *)&akey->an_key, 8);
        !           237:                kid = akey->an_key_index;
        !           238:                DPRINTF(("an_attach: wep rid=0x%x len=%d(%d) index=0x%04x "
        !           239:                    "mac[0]=%02x keylen=%d\n",
        !           240:                    rid, buflen, sizeof(*akey), kid,
        !           241:                    akey->an_mac_addr[0], akey->an_key_len));
        !           242:                if (kid == 0xffff) {
        !           243:                        sc->sc_tx_perskey = akey->an_mac_addr[0];
        !           244:                        sc->sc_tx_key = -1;
        !           245:                        break;
        !           246:                }
        !           247:                if (kid >= IEEE80211_WEP_NKID)
        !           248:                        break;
        !           249:                sc->sc_perskeylen[kid] = akey->an_key_len;
        !           250:                sc->sc_wepkeys[kid].an_wep_keylen = -1;
        !           251:                rid = AN_RID_WEP_PERSISTENT;    /* for next key */
        !           252:                buflen = sizeof(struct an_rid_wepkey);
        !           253:        }
        !           254:
        !           255:        IEEE80211_ADDR_COPY(ic->ic_myaddr, sc->sc_caps.an_oemaddr);
        !           256:        bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
        !           257:
        !           258:        printf("%s: Firmware %x.%02x.%02x, Radio: ", ifp->if_xname,
        !           259:            sc->sc_caps.an_fwrev >> 8,
        !           260:            sc->sc_caps.an_fwrev & 0xff,
        !           261:            sc->sc_caps.an_fwsubrev);
        !           262:
        !           263:        if (sc->sc_config.an_radiotype & AN_RADIOTYPE_80211_FH)
        !           264:                printf("802.11 FH");
        !           265:        else if (sc->sc_config.an_radiotype & AN_RADIOTYPE_80211_DS)
        !           266:                printf("802.11 DS");
        !           267:        else if (sc->sc_config.an_radiotype & AN_RADIOTYPE_LM2000_DS)
        !           268:                printf("LM2000 DS");
        !           269:        else
        !           270:                printf("unknown (%x)", sc->sc_config.an_radiotype);
        !           271:
        !           272:        printf(", address %s\n", ether_sprintf(ic->ic_myaddr));
        !           273:
        !           274:        ifp->if_softc = sc;
        !           275:        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
        !           276:        ifp->if_ioctl = an_ioctl;
        !           277:        ifp->if_start = an_start;
        !           278:        ifp->if_init = an_init;
        !           279:        ifp->if_watchdog = an_watchdog;
        !           280:        IFQ_SET_READY(&ifp->if_snd);
        !           281:
        !           282:        ic->ic_phytype = IEEE80211_T_DS;
        !           283:        ic->ic_opmode = IEEE80211_M_STA;
        !           284:        ic->ic_caps = IEEE80211_C_WEP | IEEE80211_C_PMGT | IEEE80211_C_IBSS |
        !           285:            IEEE80211_C_MONITOR;
        !           286:        ic->ic_state = IEEE80211_S_INIT;
        !           287:        IEEE80211_ADDR_COPY(ic->ic_myaddr, sc->sc_caps.an_oemaddr);
        !           288:
        !           289:        switch (sc->sc_caps.an_regdomain) {
        !           290:        default:
        !           291:        case AN_REGDOMAIN_USA:
        !           292:        case AN_REGDOMAIN_CANADA:
        !           293:                chan_min = 1; chan_max = 11; break;
        !           294:        case AN_REGDOMAIN_EUROPE:
        !           295:        case AN_REGDOMAIN_AUSTRALIA:
        !           296:                chan_min = 1; chan_max = 13; break;
        !           297:        case AN_REGDOMAIN_JAPAN:
        !           298:                chan_min = 14; chan_max = 14; break;
        !           299:        case AN_REGDOMAIN_SPAIN:
        !           300:                chan_min = 10; chan_max = 11; break;
        !           301:        case AN_REGDOMAIN_FRANCE:
        !           302:                chan_min = 10; chan_max = 13; break;
        !           303:        case AN_REGDOMAIN_JAPANWIDE:
        !           304:                chan_min = 1; chan_max = 14; break;
        !           305:        }
        !           306:
        !           307:        for (chan = chan_min; chan <= chan_max; chan++) {
        !           308:                ic->ic_channels[chan].ic_freq =
        !           309:                    ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ);
        !           310:                ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_B;
        !           311:        }
        !           312:        ic->ic_ibss_chan = &ic->ic_channels[chan_min];
        !           313:
        !           314:        /* Find supported rate */
        !           315:        for (i = 0; i < sizeof(sc->sc_caps.an_rates); i++) {
        !           316:                if (sc->sc_caps.an_rates[i] == 0)
        !           317:                        continue;
        !           318:                ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[
        !           319:                    ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates++] =
        !           320:                    sc->sc_caps.an_rates[i];
        !           321:        }
        !           322:
        !           323:        /*
        !           324:         * Call MI attach routine.
        !           325:         */
        !           326:        if_attach(ifp);
        !           327:        ieee80211_ifattach(ifp);
        !           328:
        !           329:        sc->sc_newstate = ic->ic_newstate;
        !           330:        ic->ic_newstate = an_newstate;
        !           331:
        !           332:        ieee80211_media_init(ifp, an_media_change, an_media_status);
        !           333:
        !           334: #if NBPFILTER > 0
        !           335:        bzero(&sc->sc_rxtapu, sizeof(sc->sc_rxtapu));
        !           336:        sc->sc_rxtap.ar_ihdr.it_len = sizeof(sc->sc_rxtapu);
        !           337:        sc->sc_rxtap.ar_ihdr.it_present = AN_RX_RADIOTAP_PRESENT;
        !           338:
        !           339:        bzero(&sc->sc_txtapu, sizeof(sc->sc_txtapu));
        !           340:        sc->sc_txtap.at_ihdr.it_len = sizeof(sc->sc_txtapu);
        !           341:        sc->sc_txtap.at_ihdr.it_present = AN_TX_RADIOTAP_PRESENT;
        !           342:
        !           343:        bpfattach(&sc->sc_drvbpf, ifp, DLT_IEEE802_11_RADIO,
        !           344:            sizeof(struct ieee80211_frame) + 64);
        !           345: #endif
        !           346:
        !           347:        sc->sc_sdhook = shutdownhook_establish(an_shutdown, sc);
        !           348:
        !           349:        sc->sc_attached = 1;
        !           350:
        !           351:        return(0);
        !           352: }
        !           353:
        !           354: void
        !           355: an_rxeof(struct an_softc *sc)
        !           356: {
        !           357:        struct ieee80211com *ic = &sc->sc_ic;
        !           358:        struct ifnet *ifp = &ic->ic_if;
        !           359:        struct ieee80211_frame *wh;
        !           360:        struct ieee80211_node *ni;
        !           361:        struct an_rxframe frmhdr;
        !           362:        struct mbuf *m;
        !           363:        u_int16_t status;
        !           364:        int fid, gaplen, len, off;
        !           365:        uint8_t *gap;
        !           366:
        !           367:        fid = CSR_READ_2(sc, AN_RX_FID);
        !           368:
        !           369:        /* First read in the frame header */
        !           370:        if (an_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr), sizeof(frmhdr)) != 0) {
        !           371:                CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
        !           372:                ifp->if_ierrors++;
        !           373:                DPRINTF(("an_rxeof: read fid %x failed\n", fid));
        !           374:                return;
        !           375:        }
        !           376:        an_swap16((u_int16_t *)&frmhdr.an_whdr, sizeof(struct ieee80211_frame)/2);
        !           377:
        !           378:        status = frmhdr.an_rx_status;
        !           379:        if ((status & AN_STAT_ERRSTAT) != 0 &&
        !           380:            ic->ic_opmode != IEEE80211_M_MONITOR) {
        !           381:                CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
        !           382:                ifp->if_ierrors++;
        !           383:                DPRINTF(("an_rxeof: fid %x status %x\n", fid, status));
        !           384:                return;
        !           385:        }
        !           386:
        !           387:        /* the payload length field includes a 16-bit "mystery field" */
        !           388:        len = frmhdr.an_rx_payload_len - sizeof(uint16_t);
        !           389:        off = ALIGN(sizeof(struct ieee80211_frame));
        !           390:
        !           391:        if (off + len > MCLBYTES) {
        !           392:                if (ic->ic_opmode != IEEE80211_M_MONITOR) {
        !           393:                        CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
        !           394:                        ifp->if_ierrors++;
        !           395:                        DPRINTF(("an_rxeof: oversized packet %d\n", len));
        !           396:                        return;
        !           397:                }
        !           398:                len = 0;
        !           399:        }
        !           400:
        !           401:        MGETHDR(m, M_DONTWAIT, MT_DATA);
        !           402:        if (m == NULL) {
        !           403:                CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
        !           404:                ifp->if_ierrors++;
        !           405:                DPRINTF(("an_rxeof: MGET failed\n"));
        !           406:                return;
        !           407:        }
        !           408:        if (off + len + AN_GAPLEN_MAX > MHLEN) {
        !           409:                MCLGET(m, M_DONTWAIT);
        !           410:                if ((m->m_flags & M_EXT) == 0) {
        !           411:                        CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
        !           412:                        m_freem(m);
        !           413:                        ifp->if_ierrors++;
        !           414:                        DPRINTF(("an_rxeof: MCLGET failed\n"));
        !           415:                        return;
        !           416:                }
        !           417:        }
        !           418:        m->m_data += off - sizeof(struct ieee80211_frame);
        !           419:
        !           420:        if (ic->ic_opmode != IEEE80211_M_MONITOR) {
        !           421:                gaplen = frmhdr.an_gaplen;
        !           422:                if (gaplen > AN_GAPLEN_MAX) {
        !           423:                        CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
        !           424:                        m_freem(m);
        !           425:                        ifp->if_ierrors++;
        !           426:                        DPRINTF(("%s: gap too long\n", __func__));
        !           427:                        return;
        !           428:                }
        !           429:                /*
        !           430:                 * We don't need the 16-bit mystery field (payload length?),
        !           431:                 * so read it into the region reserved for the 802.11 header.
        !           432:                 *
        !           433:                 * When Cisco Aironet 350 cards w/ firmware version 5 or
        !           434:                 * greater operate with certain Cisco 350 APs,
        !           435:                 * the "gap" is filled with the SNAP header.  Read
        !           436:                 * it in after the 802.11 header.
        !           437:                 */
        !           438:                gap = m->m_data + sizeof(struct ieee80211_frame) -
        !           439:                    sizeof(uint16_t);
        !           440:                an_read_bap(sc, fid, -1, gap, gaplen + sizeof(u_int16_t),
        !           441:                    gaplen + sizeof(u_int16_t));
        !           442:        } else
        !           443:                gaplen = 0;
        !           444:
        !           445:        an_read_bap(sc, fid, -1,
        !           446:            m->m_data + sizeof(struct ieee80211_frame) + gaplen, len, len);
        !           447:        an_swap16((u_int16_t *)(m->m_data + sizeof(struct ieee80211_frame) + gaplen), (len+1)/2);
        !           448:        m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame) + gaplen +
        !           449:            len;
        !           450:
        !           451:        memcpy(m->m_data, &frmhdr.an_whdr, sizeof(struct ieee80211_frame));
        !           452:        m->m_pkthdr.rcvif = ifp;
        !           453:        CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
        !           454:
        !           455: #if NBPFILTER > 0
        !           456:        if (sc->sc_drvbpf) {
        !           457:                struct mbuf mb;
        !           458:                struct an_rx_radiotap_header *tap = &sc->sc_rxtap;
        !           459:
        !           460:                tap->ar_rate = frmhdr.an_rx_rate;
        !           461:                tap->ar_antsignal = frmhdr.an_rx_signal_strength;
        !           462:                tap->ar_chan_freq = ic->ic_bss->ni_chan->ic_freq;
        !           463:                tap->ar_chan_flags = ic->ic_bss->ni_chan->ic_flags;
        !           464:
        !           465:
        !           466:                mb.m_data = (caddr_t)tap;
        !           467:                mb.m_len = sizeof(sc->sc_rxtapu);
        !           468:                mb.m_next = m;
        !           469:                mb.m_nextpkt = NULL;
        !           470:                mb.m_type = 0;
        !           471:                mb.m_flags = 0;
        !           472:                bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN);
        !           473:        }
        !           474: #endif /* NPBFILTER > 0 */
        !           475:
        !           476:        wh = mtod(m, struct ieee80211_frame *);
        !           477:        if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
        !           478:                /*
        !           479:                 * WEP is decrypted by hardware. Clear WEP bit
        !           480:                 * header for ieee80211_input().
        !           481:                 */
        !           482:                wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
        !           483:        }
        !           484:
        !           485:        ni = ieee80211_find_rxnode(ic, wh);
        !           486:        ieee80211_input(ifp, m, ni, frmhdr.an_rx_signal_strength,
        !           487:            an_switch32(frmhdr.an_rx_time));
        !           488:        ieee80211_release_node(ic, ni);
        !           489: }
        !           490:
        !           491: void
        !           492: an_txeof(struct an_softc *sc, u_int16_t status)
        !           493: {
        !           494:        struct ifnet *ifp = &sc->sc_ic.ic_if;
        !           495:        int cur, id;
        !           496:
        !           497:        sc->sc_tx_timer = 0;
        !           498:        ifp->if_flags &= ~IFF_OACTIVE;
        !           499:
        !           500:        id = CSR_READ_2(sc, AN_TX_CMP_FID);
        !           501:        CSR_WRITE_2(sc, AN_EVENT_ACK, status & (AN_EV_TX | AN_EV_TX_EXC));
        !           502:
        !           503:        if (status & AN_EV_TX_EXC)
        !           504:                ifp->if_oerrors++;
        !           505:        else
        !           506:                ifp->if_opackets++;
        !           507:
        !           508:        cur = sc->sc_txcur;
        !           509:        if (sc->sc_txd[cur].d_fid == id) {
        !           510:                sc->sc_txd[cur].d_inuse = 0;
        !           511:                DPRINTF2(("an_txeof: sent %x/%d\n", id, cur));
        !           512:                AN_INC(cur, AN_TX_RING_CNT);
        !           513:                sc->sc_txcur = cur;
        !           514:        } else {
        !           515:                for (cur = 0; cur < AN_TX_RING_CNT; cur++) {
        !           516:                        if (id == sc->sc_txd[cur].d_fid) {
        !           517:                                sc->sc_txd[cur].d_inuse = 0;
        !           518:                                break;
        !           519:                        }
        !           520:                }
        !           521:                if (ifp->if_flags & IFF_DEBUG)
        !           522:                        printf("%s: tx mismatch: "
        !           523:                            "expected %x(%d), actual %x(%d)\n",
        !           524:                            sc->sc_dev.dv_xname,
        !           525:                            sc->sc_txd[sc->sc_txcur].d_fid, sc->sc_txcur,
        !           526:                            id, cur);
        !           527:        }
        !           528: }
        !           529:
        !           530: int
        !           531: an_intr(void *arg)
        !           532: {
        !           533:        struct an_softc *sc = arg;
        !           534:        struct ifnet *ifp = &sc->sc_ic.ic_if;
        !           535:        int i;
        !           536:        u_int16_t status;
        !           537:
        !           538:        if (!sc->sc_enabled || sc->sc_invalid ||
        !           539:            (sc->sc_dev.dv_flags & DVF_ACTIVE) == 0 ||
        !           540:            (ifp->if_flags & IFF_RUNNING) == 0)
        !           541:                return 0;
        !           542:
        !           543:        if ((ifp->if_flags & IFF_UP) == 0) {
        !           544:                CSR_WRITE_2(sc, AN_INT_EN, 0);
        !           545:                CSR_WRITE_2(sc, AN_EVENT_ACK, ~0);
        !           546:                return 1;
        !           547:        }
        !           548:
        !           549:        /* maximum 10 loops per interrupt */
        !           550:        for (i = 0; i < 10; i++) {
        !           551:                if (!sc->sc_enabled || sc->sc_invalid)
        !           552:                        return 1;
        !           553:                if (CSR_READ_2(sc, AN_SW0) != AN_MAGIC) {
        !           554:                        DPRINTF(("an_intr: magic number changed: %x\n",
        !           555:                            CSR_READ_2(sc, AN_SW0)));
        !           556:                        sc->sc_invalid = 1;
        !           557:                        return 1;
        !           558:                }
        !           559:                status = CSR_READ_2(sc, AN_EVENT_STAT);
        !           560:                CSR_WRITE_2(sc, AN_EVENT_ACK, status & ~(AN_INTRS));
        !           561:                if ((status & AN_INTRS) == 0)
        !           562:                        break;
        !           563:
        !           564:                if (status & AN_EV_RX)
        !           565:                        an_rxeof(sc);
        !           566:
        !           567:                if (status & (AN_EV_TX | AN_EV_TX_EXC))
        !           568:                        an_txeof(sc, status);
        !           569:
        !           570:                if (status & AN_EV_LINKSTAT)
        !           571:                        an_linkstat_intr(sc);
        !           572:
        !           573:                if ((ifp->if_flags & IFF_OACTIVE) == 0 &&
        !           574:                    sc->sc_ic.ic_state == IEEE80211_S_RUN &&
        !           575:                    !IFQ_IS_EMPTY(&ifp->if_snd))
        !           576:                        an_start(ifp);
        !           577:        }
        !           578:
        !           579:        return 1;
        !           580: }
        !           581:
        !           582: /* Must be called at proper protection level! */
        !           583: int
        !           584: an_cmd(struct an_softc *sc, int cmd, int val)
        !           585: {
        !           586:        int i, stat;
        !           587:
        !           588:        /* make sure previous command completed */
        !           589:        if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY) {
        !           590:                if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           591:                        printf("%s: command 0x%x busy\n", sc->sc_dev.dv_xname,
        !           592:                            CSR_READ_2(sc, AN_COMMAND));
        !           593:                CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY);
        !           594:        }
        !           595:
        !           596:        CSR_WRITE_2(sc, AN_PARAM0, val);
        !           597:        CSR_WRITE_2(sc, AN_PARAM1, 0);
        !           598:        CSR_WRITE_2(sc, AN_PARAM2, 0);
        !           599:        CSR_WRITE_2(sc, AN_COMMAND, cmd);
        !           600:
        !           601:        if (cmd == AN_CMD_FW_RESTART) {
        !           602:                /* XXX: should sleep here */
        !           603:                DELAY(100*1000);
        !           604:        }
        !           605:
        !           606:        for (i = 0; i < AN_TIMEOUT; i++) {
        !           607:                if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_CMD)
        !           608:                        break;
        !           609:                DELAY(10);
        !           610:        }
        !           611:
        !           612:        stat = CSR_READ_2(sc, AN_STATUS);
        !           613:
        !           614:        /* clear stuck command busy if necessary */
        !           615:        if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY)
        !           616:                CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY);
        !           617:
        !           618:        /* Ack the command */
        !           619:        CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD);
        !           620:
        !           621:        if (i == AN_TIMEOUT) {
        !           622:                if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           623:                        printf("%s: command 0x%x param 0x%x timeout\n",
        !           624:                            sc->sc_dev.dv_xname, cmd, val);
        !           625:                return ETIMEDOUT;
        !           626:        }
        !           627:        if (stat & AN_STAT_CMD_RESULT) {
        !           628:                if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           629:                        printf("%s: command 0x%x param 0x%x status 0x%x "
        !           630:                            "resp 0x%x 0x%x 0x%x\n",
        !           631:                            sc->sc_dev.dv_xname, cmd, val, stat,
        !           632:                            CSR_READ_2(sc, AN_RESP0), CSR_READ_2(sc, AN_RESP1),
        !           633:                            CSR_READ_2(sc, AN_RESP2));
        !           634:                return EIO;
        !           635:        }
        !           636:
        !           637:        return 0;
        !           638: }
        !           639:
        !           640: int
        !           641: an_reset(struct an_softc *sc)
        !           642: {
        !           643:
        !           644:        DPRINTF(("an_reset\n"));
        !           645:
        !           646:        if (!sc->sc_enabled)
        !           647:                return ENXIO;
        !           648:
        !           649:        an_cmd(sc, AN_CMD_ENABLE, 0);
        !           650:        an_cmd(sc, AN_CMD_FW_RESTART, 0);
        !           651:        an_cmd(sc, AN_CMD_NOOP2, 0);
        !           652:
        !           653:        if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0) == ETIMEDOUT) {
        !           654:                printf("%s: reset failed\n", sc->sc_dev.dv_xname);
        !           655:                return ETIMEDOUT;
        !           656:        }
        !           657:
        !           658:        an_cmd(sc, AN_CMD_DISABLE, 0);
        !           659:        return 0;
        !           660: }
        !           661:
        !           662: void
        !           663: an_linkstat_intr(struct an_softc *sc)
        !           664: {
        !           665:        struct ieee80211com *ic = &sc->sc_ic;
        !           666:        u_int16_t status;
        !           667:
        !           668:        status = CSR_READ_2(sc, AN_LINKSTAT);
        !           669:        CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_LINKSTAT);
        !           670:        DPRINTF(("an_linkstat_intr: status 0x%x\n", status));
        !           671:
        !           672:        if (status == AN_LINKSTAT_ASSOCIATED) {
        !           673:                if (ic->ic_state != IEEE80211_S_RUN ||
        !           674:                    ic->ic_opmode == IEEE80211_M_IBSS)
        !           675:                        ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
        !           676:        } else {
        !           677:                if (ic->ic_opmode == IEEE80211_M_STA)
        !           678:                        ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
        !           679:        }
        !           680: }
        !           681:
        !           682: /*
        !           683:  * Wait for firmware come up after power enabled.
        !           684:  */
        !           685: void
        !           686: an_wait(struct an_softc *sc)
        !           687: {
        !           688:        int i;
        !           689:
        !           690:        CSR_WRITE_2(sc, AN_COMMAND, AN_CMD_NOOP2);
        !           691:        for (i = 0; i < 3*hz; i++) {
        !           692:                if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_CMD)
        !           693:                        break;
        !           694:                (void)tsleep(sc, PWAIT, "anatch", 1);
        !           695:        }
        !           696:        CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD);
        !           697: }
        !           698:
        !           699: int
        !           700: an_read_bap(struct an_softc *sc, int id, int off, void *buf, int len, int blen)
        !           701: {
        !           702:        int error, cnt, cnt2;
        !           703:
        !           704:        if (len == 0 || blen == 0)
        !           705:                return 0;
        !           706:        if (off == -1)
        !           707:                off = sc->sc_bap_off;
        !           708:        if (id != sc->sc_bap_id || off != sc->sc_bap_off) {
        !           709:                if ((error = an_seek_bap(sc, id, off)) != 0)
        !           710:                        return EIO;
        !           711:        }
        !           712:
        !           713:        cnt = (blen + 1) / 2;
        !           714:        CSR_READ_MULTI_STREAM_2(sc, AN_DATA0, (u_int16_t *)buf, cnt);
        !           715:        for (cnt2 = (len + 1) / 2; cnt < cnt2; cnt++)
        !           716:                (void) CSR_READ_2(sc, AN_DATA0);
        !           717:        sc->sc_bap_off += cnt * 2;
        !           718:
        !           719:        return 0;
        !           720: }
        !           721:
        !           722: int
        !           723: an_write_bap(struct an_softc *sc, int id, int off, void *buf, int buflen)
        !           724: {
        !           725:        int error, cnt;
        !           726:
        !           727:        if (buflen == 0)
        !           728:                return 0;
        !           729:        if (off == -1)
        !           730:                off = sc->sc_bap_off;
        !           731:        if (id != sc->sc_bap_id || off != sc->sc_bap_off) {
        !           732:                if ((error = an_seek_bap(sc, id, off)) != 0)
        !           733:                        return EIO;
        !           734:        }
        !           735:
        !           736:        cnt = (buflen + 1) / 2;
        !           737:        CSR_WRITE_MULTI_STREAM_2(sc, AN_DATA0, (u_int16_t *)buf, cnt);
        !           738:        sc->sc_bap_off += cnt * 2;
        !           739:        return 0;
        !           740: }
        !           741:
        !           742: int
        !           743: an_seek_bap(struct an_softc *sc, int id, int off)
        !           744: {
        !           745:        int i, status;
        !           746:
        !           747:        CSR_WRITE_2(sc, AN_SEL0, id);
        !           748:        CSR_WRITE_2(sc, AN_OFF0, off);
        !           749:
        !           750:        for (i = 0; ; i++) {
        !           751:                status = CSR_READ_2(sc, AN_OFF0);
        !           752:                if ((status & AN_OFF_BUSY) == 0)
        !           753:                        break;
        !           754:                if (i == AN_TIMEOUT) {
        !           755:                        printf("%s: timeout in an_seek_bap to 0x%x/0x%x\n",
        !           756:                            sc->sc_dev.dv_xname, id, off);
        !           757:                        sc->sc_bap_off = AN_OFF_ERR;    /* invalidate */
        !           758:                        return ETIMEDOUT;
        !           759:                }
        !           760:                DELAY(10);
        !           761:        }
        !           762:        if (status & AN_OFF_ERR) {
        !           763:                printf("%s: failed in an_seek_bap to 0x%x/0x%x\n",
        !           764:                    sc->sc_dev.dv_xname, id, off);
        !           765:                sc->sc_bap_off = AN_OFF_ERR;    /* invalidate */
        !           766:                return EIO;
        !           767:        }
        !           768:        sc->sc_bap_id = id;
        !           769:        sc->sc_bap_off = off;
        !           770:        return 0;
        !           771: }
        !           772:
        !           773: int
        !           774: an_mwrite_bap(struct an_softc *sc, int id, int off, struct mbuf *m, int totlen)
        !           775: {
        !           776:        int error, len, cnt;
        !           777:
        !           778:        if (off == -1)
        !           779:                off = sc->sc_bap_off;
        !           780:        if (id != sc->sc_bap_id || off != sc->sc_bap_off) {
        !           781:                if ((error = an_seek_bap(sc, id, off)) != 0)
        !           782:                        return EIO;
        !           783:        }
        !           784:
        !           785:        for (len = 0; m != NULL; m = m->m_next) {
        !           786:                if (m->m_len == 0)
        !           787:                        continue;
        !           788:                len = min(m->m_len, totlen);
        !           789:
        !           790:                if ((mtod(m, u_long) & 0x1) || (len & 0x1)) {
        !           791:                        m_copydata(m, 0, totlen, (caddr_t)&sc->sc_buf.sc_txbuf);
        !           792:                        cnt = (totlen + 1) / 2;
        !           793:                        an_swap16((u_int16_t *)&sc->sc_buf.sc_txbuf, cnt);
        !           794:                        CSR_WRITE_MULTI_STREAM_2(sc, AN_DATA0,
        !           795:                            sc->sc_buf.sc_val, cnt);
        !           796:                        off += cnt * 2;
        !           797:                        break;
        !           798:                }
        !           799:                cnt = len / 2;
        !           800:                an_swap16((u_int16_t *)mtod(m, u_int16_t *), cnt);
        !           801:                CSR_WRITE_MULTI_STREAM_2(sc, AN_DATA0, mtod(m, u_int16_t *),
        !           802:                    cnt);
        !           803:                off += len;
        !           804:                totlen -= len;
        !           805:        }
        !           806:        sc->sc_bap_off = off;
        !           807:        return 0;
        !           808: }
        !           809:
        !           810: int
        !           811: an_alloc_nicmem(struct an_softc *sc, int len, int *idp)
        !           812: {
        !           813:        int i;
        !           814:
        !           815:        if (an_cmd(sc, AN_CMD_ALLOC_MEM, len)) {
        !           816:                printf("%s: failed to allocate %d bytes on NIC\n",
        !           817:                    sc->sc_dev.dv_xname, len);
        !           818:                return(ENOMEM);
        !           819:        }
        !           820:
        !           821:        for (i = 0; i < AN_TIMEOUT; i++) {
        !           822:                if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_ALLOC)
        !           823:                        break;
        !           824:                if (i == AN_TIMEOUT) {
        !           825:                        printf("%s: timeout in alloc\n", sc->sc_dev.dv_xname);
        !           826:                        return ETIMEDOUT;
        !           827:                }
        !           828:                DELAY(10);
        !           829:        }
        !           830:
        !           831:        *idp = CSR_READ_2(sc, AN_ALLOC_FID);
        !           832:        CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_ALLOC);
        !           833:        return 0;
        !           834: }
        !           835:
        !           836: int
        !           837: an_read_rid(struct an_softc *sc, int rid, void *buf, int *buflenp)
        !           838: {
        !           839:        int error;
        !           840:        u_int16_t len;
        !           841:
        !           842:        /* Tell the NIC to enter record read mode. */
        !           843:        error = an_cmd(sc, AN_CMD_ACCESS | AN_ACCESS_READ, rid);
        !           844:        if (error)
        !           845:                return error;
        !           846:
        !           847:        /* length in byte, including length itself */
        !           848:        error = an_read_bap(sc, rid, 0, &len, sizeof(len), sizeof(len));
        !           849:        if (error)
        !           850:                return error;
        !           851:
        !           852:        len -= 2;
        !           853:        return an_read_bap(sc, rid, sizeof(len), buf, len, *buflenp);
        !           854: }
        !           855:
        !           856: int
        !           857: an_write_rid(struct an_softc *sc, int rid, void *buf, int buflen)
        !           858: {
        !           859:        int error;
        !           860:        u_int16_t len;
        !           861:
        !           862:        /* length in byte, including length itself */
        !           863:        len = buflen + 2;
        !           864:
        !           865:        error = an_write_bap(sc, rid, 0, &len, sizeof(len));
        !           866:        if (error)
        !           867:                return error;
        !           868:        error = an_write_bap(sc, rid, sizeof(len), buf, buflen);
        !           869:        if (error)
        !           870:                return error;
        !           871:
        !           872:        return an_cmd(sc, AN_CMD_ACCESS | AN_ACCESS_WRITE, rid);
        !           873: }
        !           874:
        !           875: int
        !           876: an_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
        !           877: {
        !           878:        struct an_softc *sc = ifp->if_softc;
        !           879:        struct ifaddr *ifa = (struct ifaddr *)data;
        !           880:        int s, error = 0;
        !           881:
        !           882:        if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
        !           883:                return ENXIO;
        !           884:
        !           885:        s = splnet();
        !           886:
        !           887:        switch(command) {
        !           888:        case SIOCSIFADDR:
        !           889:                ifp->if_flags |= IFF_UP;
        !           890:                switch (ifa->ifa_addr->sa_family) {
        !           891: #ifdef INET
        !           892:                case AF_INET:
        !           893:                        error = an_init(ifp);
        !           894:                        arp_ifinit(&sc->sc_ic.ic_ac, ifa);
        !           895:                        break;
        !           896: #endif
        !           897:                default:
        !           898:                        error = an_init(ifp);
        !           899:                        break;
        !           900:                }
        !           901:                break;
        !           902:        case SIOCSIFFLAGS:
        !           903:                if (ifp->if_flags & IFF_UP) {
        !           904:                        if (sc->sc_enabled) {
        !           905:                                /*
        !           906:                                 * To avoid rescanning another access point,
        !           907:                                 * do not call an_init() here.  Instead, only
        !           908:                                 * reflect promisc mode settings.
        !           909:                                 */
        !           910:                                error = an_cmd(sc, AN_CMD_SET_MODE,
        !           911:                                    (ifp->if_flags & IFF_PROMISC) ? 0xffff : 0);
        !           912:                        } else
        !           913:                                error = an_init(ifp);
        !           914:                } else if (sc->sc_enabled)
        !           915:                        an_stop(ifp, 1);
        !           916:                break;
        !           917:        case SIOCADDMULTI:
        !           918:        case SIOCDELMULTI:
        !           919:                /* The Aironet has no multicast filter. */
        !           920:                error = 0;
        !           921:                break;
        !           922:        case SIOCS80211NWKEY:
        !           923:                error = an_set_nwkey(sc, (struct ieee80211_nwkey *)data);
        !           924:                        break;
        !           925:        case SIOCG80211NWKEY:
        !           926:                error = an_get_nwkey(sc, (struct ieee80211_nwkey *)data);
        !           927:                break;
        !           928:        default:
        !           929:                error = ieee80211_ioctl(ifp, command, data);
        !           930:                break;
        !           931:        }
        !           932:        if (error == ENETRESET) {
        !           933:                if (sc->sc_enabled)
        !           934:                        error = an_init(ifp);
        !           935:                else
        !           936:                        error = 0;
        !           937:        }
        !           938:        splx(s);
        !           939:        return(error);
        !           940: }
        !           941:
        !           942: int
        !           943: an_init(struct ifnet *ifp)
        !           944: {
        !           945:        struct an_softc *sc = ifp->if_softc;
        !           946:        struct ieee80211com *ic = &sc->sc_ic;
        !           947:        int i, error, fid;
        !           948:
        !           949:        DPRINTF(("an_init: enabled %d\n", sc->sc_enabled));
        !           950:        if (!sc->sc_enabled) {
        !           951:                if (sc->sc_enable)
        !           952:                        (*sc->sc_enable)(sc);
        !           953:                an_wait(sc);
        !           954:                sc->sc_enabled = 1;
        !           955:        } else {
        !           956:                an_stop(ifp, 0);
        !           957:                if ((error = an_reset(sc)) != 0) {
        !           958:                        printf("%s: failed to reset\n", ifp->if_xname);
        !           959:                        an_stop(ifp, 1);
        !           960:                        return error;
        !           961:                }
        !           962:        }
        !           963:        CSR_WRITE_2(sc, AN_SW0, AN_MAGIC);
        !           964:
        !           965:        /* Allocate the TX buffers */
        !           966:        for (i = 0; i < AN_TX_RING_CNT; i++) {
        !           967:                if ((error = an_alloc_nicmem(sc, AN_TX_MAX_LEN, &fid)) != 0) {
        !           968:                        printf("%s: failed to allocate nic memory\n",
        !           969:                            ifp->if_xname);
        !           970:                        an_stop(ifp, 1);
        !           971:                        return error;
        !           972:                }
        !           973:                DPRINTF2(("an_init: txbuf %d allocated %x\n", i, fid));
        !           974:                sc->sc_txd[i].d_fid = fid;
        !           975:                sc->sc_txd[i].d_inuse = 0;
        !           976:        }
        !           977:        sc->sc_txcur = sc->sc_txnext = 0;
        !           978:
        !           979:        IEEE80211_ADDR_COPY(sc->sc_config.an_macaddr, ic->ic_myaddr);
        !           980:        an_swap16((u_int16_t *)&sc->sc_config.an_macaddr, 3);
        !           981:        sc->sc_config.an_scanmode = AN_SCANMODE_ACTIVE;
        !           982:        sc->sc_config.an_authtype = AN_AUTHTYPE_OPEN;   /*XXX*/
        !           983:        if (ic->ic_flags & IEEE80211_F_WEPON) {
        !           984:                sc->sc_config.an_authtype |=
        !           985:                    AN_AUTHTYPE_PRIVACY_IN_USE;
        !           986:        }
        !           987:        sc->sc_config.an_listen_interval = ic->ic_lintval;
        !           988:        sc->sc_config.an_beacon_period = ic->ic_lintval;
        !           989:        if (ic->ic_flags & IEEE80211_F_PMGTON)
        !           990:                sc->sc_config.an_psave_mode = AN_PSAVE_PSP;
        !           991:        else
        !           992:                sc->sc_config.an_psave_mode = AN_PSAVE_CAM;
        !           993:        sc->sc_config.an_ds_channel =
        !           994:            ieee80211_chan2ieee(ic, ic->ic_ibss_chan);
        !           995:
        !           996:        switch (ic->ic_opmode) {
        !           997:        case IEEE80211_M_STA:
        !           998:                sc->sc_config.an_opmode =
        !           999:                    AN_OPMODE_INFRASTRUCTURE_STATION;
        !          1000:                sc->sc_config.an_rxmode = AN_RXMODE_BC_MC_ADDR;
        !          1001:                break;
        !          1002:        case IEEE80211_M_IBSS:
        !          1003:                sc->sc_config.an_opmode = AN_OPMODE_IBSS_ADHOC;
        !          1004:                sc->sc_config.an_rxmode = AN_RXMODE_BC_MC_ADDR;
        !          1005:                break;
        !          1006:        case IEEE80211_M_MONITOR:
        !          1007:                sc->sc_config.an_opmode =
        !          1008:                    AN_OPMODE_INFRASTRUCTURE_STATION;
        !          1009:                sc->sc_config.an_rxmode =
        !          1010:                    AN_RXMODE_80211_MONITOR_ANYBSS;
        !          1011:                sc->sc_config.an_authtype = AN_AUTHTYPE_NONE;
        !          1012:                if (ic->ic_flags & IEEE80211_F_WEPON)
        !          1013:                        sc->sc_config.an_authtype |=
        !          1014:                            AN_AUTHTYPE_PRIVACY_IN_USE |
        !          1015:                            AN_AUTHTYPE_ALLOW_UNENCRYPTED;
        !          1016:                break;
        !          1017:        default:
        !          1018:                printf("%s: bad opmode %d\n", ifp->if_xname, ic->ic_opmode);
        !          1019:                an_stop(ifp, 1);
        !          1020:                return EIO;
        !          1021:        }
        !          1022:        sc->sc_config.an_rxmode |= AN_RXMODE_NO_8023_HEADER;
        !          1023:
        !          1024:        /* Set the ssid list */
        !          1025:        memset(&sc->sc_buf, 0, sizeof(sc->sc_buf.sc_ssidlist));
        !          1026:        sc->sc_buf.sc_ssidlist.an_entry[0].an_ssid_len =
        !          1027:            ic->ic_des_esslen;
        !          1028:        if (ic->ic_des_esslen)
        !          1029:                memcpy(sc->sc_buf.sc_ssidlist.an_entry[0].an_ssid,
        !          1030:                    ic->ic_des_essid, ic->ic_des_esslen);
        !          1031:        an_swap16((u_int16_t *)&sc->sc_buf.sc_ssidlist.an_entry[0].an_ssid, 16);
        !          1032:        if (an_write_rid(sc, AN_RID_SSIDLIST, &sc->sc_buf,
        !          1033:            sizeof(sc->sc_buf.sc_ssidlist)) != 0) {
        !          1034:                printf("%s: failed to write ssid list\n", ifp->if_xname);
        !          1035:                an_stop(ifp, 1);
        !          1036:                return error;
        !          1037:        }
        !          1038:
        !          1039:        /* Set the AP list */
        !          1040:        memset(&sc->sc_buf, 0, sizeof(sc->sc_buf.sc_aplist));
        !          1041:        (void)an_write_rid(sc, AN_RID_APLIST, &sc->sc_buf,
        !          1042:            sizeof(sc->sc_buf.sc_aplist));
        !          1043:
        !          1044:        /* Set the encapsulation */
        !          1045:        for (i = 0; i < AN_ENCAP_NENTS; i++) {
        !          1046:                sc->sc_buf.sc_encap.an_entry[i].an_ethertype = 0;
        !          1047:                sc->sc_buf.sc_encap.an_entry[i].an_action =
        !          1048:                    AN_RXENCAP_RFC1024 | AN_TXENCAP_RFC1024;
        !          1049:        }
        !          1050:        (void)an_write_rid(sc, AN_RID_ENCAP, &sc->sc_buf,
        !          1051:            sizeof(sc->sc_buf.sc_encap));
        !          1052:
        !          1053:        /* Set the WEP Keys */
        !          1054:        if (ic->ic_flags & IEEE80211_F_WEPON)
        !          1055:                an_write_wepkey(sc, AN_RID_WEP_VOLATILE, sc->sc_wepkeys,
        !          1056:                    sc->sc_tx_key);
        !          1057:
        !          1058:        /* Set the configuration */
        !          1059:        if (an_write_rid(sc, AN_RID_GENCONFIG, &sc->sc_config,
        !          1060:            sizeof(sc->sc_config)) != 0) {
        !          1061:                printf("%s: failed to write config\n", ifp->if_xname);
        !          1062:                an_stop(ifp, 1);
        !          1063:                return error;
        !          1064:        }
        !          1065:
        !          1066:        /* Enable the MAC */
        !          1067:        if (an_cmd(sc, AN_CMD_ENABLE, 0)) {
        !          1068:                printf("%s: failed to enable MAC\n", sc->sc_dev.dv_xname);
        !          1069:                an_stop(ifp, 1);
        !          1070:                return ENXIO;
        !          1071:        }
        !          1072:        if (ifp->if_flags & IFF_PROMISC)
        !          1073:                an_cmd(sc, AN_CMD_SET_MODE, 0xffff);
        !          1074:
        !          1075:        ifp->if_flags |= IFF_RUNNING;
        !          1076:        ifp->if_flags &= ~IFF_OACTIVE;
        !          1077:        ic->ic_state = IEEE80211_S_INIT;
        !          1078:        if (ic->ic_opmode == IEEE80211_M_MONITOR)
        !          1079:                ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
        !          1080:
        !          1081:        /* enable interrupts */
        !          1082:        CSR_WRITE_2(sc, AN_INT_EN, AN_INTRS);
        !          1083:        return 0;
        !          1084: }
        !          1085:
        !          1086: void
        !          1087: an_start(struct ifnet *ifp)
        !          1088: {
        !          1089:        struct an_softc *sc = (struct an_softc *)ifp->if_softc;
        !          1090:        struct ieee80211com *ic = &sc->sc_ic;
        !          1091:        struct ieee80211_node *ni;
        !          1092:        struct ieee80211_frame *wh;
        !          1093:        struct an_txframe frmhdr;
        !          1094:        struct mbuf *m;
        !          1095:        u_int16_t len;
        !          1096:        int cur, fid;
        !          1097:
        !          1098:        if (!sc->sc_enabled || sc->sc_invalid) {
        !          1099:                DPRINTF(("an_start: noop: enabled %d invalid %d\n",
        !          1100:                    sc->sc_enabled, sc->sc_invalid));
        !          1101:                return;
        !          1102:        }
        !          1103:
        !          1104:        memset(&frmhdr, 0, sizeof(frmhdr));
        !          1105:        cur = sc->sc_txnext;
        !          1106:        for (;;) {
        !          1107:                if (ic->ic_state != IEEE80211_S_RUN) {
        !          1108:                        DPRINTF(("an_start: not running %d\n", ic->ic_state));
        !          1109:                        break;
        !          1110:                }
        !          1111:                IFQ_POLL(&ifp->if_snd, m);
        !          1112:                if (m == NULL) {
        !          1113:                        DPRINTF2(("an_start: no pending mbuf\n"));
        !          1114:                        break;
        !          1115:                }
        !          1116:                if (sc->sc_txd[cur].d_inuse) {
        !          1117:                        DPRINTF2(("an_start: %x/%d busy\n",
        !          1118:                            sc->sc_txd[cur].d_fid, cur));
        !          1119:                        ifp->if_flags |= IFF_OACTIVE;
        !          1120:                        break;
        !          1121:                }
        !          1122:                IFQ_DEQUEUE(&ifp->if_snd, m);
        !          1123:                ifp->if_opackets++;
        !          1124: #if NBPFILTER > 0
        !          1125:                if (ifp->if_bpf)
        !          1126:                        bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
        !          1127: #endif
        !          1128:                if ((m = ieee80211_encap(ifp, m, &ni)) == NULL) {
        !          1129:                        ifp->if_oerrors++;
        !          1130:                        continue;
        !          1131:                }
        !          1132:                if (ni != NULL)
        !          1133:                        ieee80211_release_node(ic, ni);
        !          1134: #if NBPFILTER > 0
        !          1135:                if (ic->ic_rawbpf)
        !          1136:                        bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT);
        !          1137: #endif
        !          1138:
        !          1139:                wh = mtod(m, struct ieee80211_frame *);
        !          1140:                if (ic->ic_flags & IEEE80211_F_WEPON)
        !          1141:                        wh->i_fc[1] |= IEEE80211_FC1_WEP;
        !          1142:                m_copydata(m, 0, sizeof(struct ieee80211_frame),
        !          1143:                    (caddr_t)&frmhdr.an_whdr);
        !          1144:                an_swap16((u_int16_t *)&frmhdr.an_whdr, sizeof(struct ieee80211_frame)/2);
        !          1145:
        !          1146:                /* insert payload length in front of llc/snap */
        !          1147:                len = htons(m->m_pkthdr.len - sizeof(struct ieee80211_frame));
        !          1148:                m_adj(m, sizeof(struct ieee80211_frame) - sizeof(len));
        !          1149:                if (mtod(m, u_long) & 0x01)
        !          1150:                        memcpy(mtod(m, caddr_t), &len, sizeof(len));
        !          1151:                else
        !          1152:                        *mtod(m, u_int16_t *) = len;
        !          1153:
        !          1154:                /*
        !          1155:                 * XXX Aironet firmware apparently convert the packet
        !          1156:                 * with longer than 1500 bytes in length into LLC/SNAP.
        !          1157:                 * If we have 1500 bytes in ethernet payload, it is
        !          1158:                 * 1508 bytes including LLC/SNAP and will be inserted
        !          1159:                 * additional LLC/SNAP header with 1501-1508 in its
        !          1160:                 * ethertype !!
        !          1161:                 * So we skip LLC/SNAP header and force firmware to
        !          1162:                 * convert it to LLC/SNAP again.
        !          1163:                 */
        !          1164:                m_adj(m, sizeof(struct llc));
        !          1165:
        !          1166:                frmhdr.an_tx_ctl = AN_TXCTL_80211;
        !          1167:                frmhdr.an_tx_payload_len = m->m_pkthdr.len;
        !          1168:                frmhdr.an_gaplen = AN_TXGAP_802_11;
        !          1169:
        !          1170:                if (ic->ic_fixed_rate != -1)
        !          1171:                        frmhdr.an_tx_rate =
        !          1172:                            ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[
        !          1173:                            ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
        !          1174:                else
        !          1175:                        frmhdr.an_tx_rate = 0;
        !          1176:
        !          1177:                if (sizeof(frmhdr) + AN_TXGAP_802_11 + sizeof(len) +
        !          1178:                    m->m_pkthdr.len > AN_TX_MAX_LEN) {
        !          1179:                        ifp->if_oerrors++;
        !          1180:                        m_freem(m);
        !          1181:                        continue;
        !          1182:                }
        !          1183:
        !          1184: #if NBPFILTER > 0
        !          1185:                if (sc->sc_drvbpf) {
        !          1186:                        struct mbuf mb;
        !          1187:                        struct an_tx_radiotap_header *tap = &sc->sc_txtap;
        !          1188:
        !          1189:                        tap->at_rate =
        !          1190:                            ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate];
        !          1191:                        tap->at_chan_freq =
        !          1192:                            ic->ic_bss->ni_chan->ic_freq;
        !          1193:                        tap->at_chan_flags =
        !          1194:                            ic->ic_bss->ni_chan->ic_flags;
        !          1195:
        !          1196:                        mb.m_data = (caddr_t)tap;
        !          1197:                        mb.m_len = sizeof(sc->sc_txtapu);
        !          1198:                        mb.m_next = m;
        !          1199:                        mb.m_nextpkt = NULL;
        !          1200:                        mb.m_type = 0;
        !          1201:                        mb.m_flags = 0;
        !          1202:                        bpf_mtap(sc->sc_drvbpf, m, BPF_DIRECTION_OUT);
        !          1203:                }
        !          1204: #endif
        !          1205:
        !          1206:                fid = sc->sc_txd[cur].d_fid;
        !          1207:                if (an_write_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) != 0) {
        !          1208:                        ifp->if_oerrors++;
        !          1209:                        m_freem(m);
        !          1210:                        continue;
        !          1211:                }
        !          1212:                /* dummy write to avoid seek. */
        !          1213:                an_write_bap(sc, fid, -1, &frmhdr, AN_TXGAP_802_11);
        !          1214:                an_mwrite_bap(sc, fid, -1, m, m->m_pkthdr.len);
        !          1215:                m_freem(m);
        !          1216:
        !          1217:                DPRINTF2(("an_start: send %d byte via %x/%d\n",
        !          1218:                    ntohs(len) + sizeof(struct ieee80211_frame),
        !          1219:                    fid, cur));
        !          1220:                sc->sc_txd[cur].d_inuse = 1;
        !          1221:                if (an_cmd(sc, AN_CMD_TX, fid)) {
        !          1222:                        printf("%s: xmit failed\n", ifp->if_xname);
        !          1223:                        sc->sc_txd[cur].d_inuse = 0;
        !          1224:                        continue;
        !          1225:                }
        !          1226:                sc->sc_tx_timer = 5;
        !          1227:                ifp->if_timer = 1;
        !          1228:                AN_INC(cur, AN_TX_RING_CNT);
        !          1229:                sc->sc_txnext = cur;
        !          1230:        }
        !          1231: }
        !          1232:
        !          1233: void
        !          1234: an_stop(struct ifnet *ifp, int disable)
        !          1235: {
        !          1236:        struct an_softc *sc = ifp->if_softc;
        !          1237:        int i, s;
        !          1238:
        !          1239:        if (!sc->sc_enabled)
        !          1240:                return;
        !          1241:
        !          1242:        DPRINTF(("an_stop: disable %d\n", disable));
        !          1243:
        !          1244:        s = splnet();
        !          1245:        ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
        !          1246:        if (!sc->sc_invalid) {
        !          1247:                an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0);
        !          1248:                CSR_WRITE_2(sc, AN_INT_EN, 0);
        !          1249:                an_cmd(sc, AN_CMD_DISABLE, 0);
        !          1250:
        !          1251:                for (i = 0; i < AN_TX_RING_CNT; i++)
        !          1252:                        an_cmd(sc, AN_CMD_DEALLOC_MEM, sc->sc_txd[i].d_fid);
        !          1253:        }
        !          1254:
        !          1255:        sc->sc_tx_timer = 0;
        !          1256:        ifp->if_timer = 0;
        !          1257:        ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
        !          1258:
        !          1259:        if (disable) {
        !          1260:                if (sc->sc_disable)
        !          1261:                        (*sc->sc_disable)(sc);
        !          1262:                sc->sc_enabled = 0;
        !          1263:        }
        !          1264:        splx(s);
        !          1265: }
        !          1266:
        !          1267: void
        !          1268: an_watchdog(struct ifnet *ifp)
        !          1269: {
        !          1270:        struct an_softc *sc = ifp->if_softc;
        !          1271:
        !          1272:        if (!sc->sc_enabled)
        !          1273:                return;
        !          1274:
        !          1275:        if (sc->sc_tx_timer) {
        !          1276:                if (--sc->sc_tx_timer == 0) {
        !          1277:                        printf("%s: device timeout\n", ifp->if_xname);
        !          1278:                        ifp->if_oerrors++;
        !          1279:                        an_init(ifp);
        !          1280:                        return;
        !          1281:                }
        !          1282:                ifp->if_timer = 1;
        !          1283:        }
        !          1284:        ieee80211_watchdog(ifp);
        !          1285: }
        !          1286:
        !          1287: void
        !          1288: an_shutdown(void *self)
        !          1289: {
        !          1290:        struct an_softc *sc = (struct an_softc *)self;
        !          1291:
        !          1292:        if (sc->sc_attached)
        !          1293:                an_stop(&sc->sc_ic.ic_if, 1);
        !          1294: }
        !          1295:
        !          1296: /* TBD factor with ieee80211_media_change */
        !          1297: int
        !          1298: an_media_change(struct ifnet *ifp)
        !          1299: {
        !          1300:        struct an_softc *sc = ifp->if_softc;
        !          1301:        struct ieee80211com *ic = &sc->sc_ic;
        !          1302:        struct ifmedia_entry *ime;
        !          1303:        enum ieee80211_opmode newmode;
        !          1304:        int i, rate, error = 0;
        !          1305:
        !          1306:        ime = ic->ic_media.ifm_cur;
        !          1307:        if (IFM_SUBTYPE(ime->ifm_media) == IFM_AUTO) {
        !          1308:                i = -1;
        !          1309:        } else {
        !          1310:                struct ieee80211_rateset *rs =
        !          1311:                    &ic->ic_sup_rates[IEEE80211_MODE_11B];
        !          1312:                rate = ieee80211_media2rate(ime->ifm_media);
        !          1313:                if (rate == 0)
        !          1314:                        return EINVAL;
        !          1315:                for (i = 0; i < rs->rs_nrates; i++) {
        !          1316:                        if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == rate)
        !          1317:                                break;
        !          1318:                }
        !          1319:                if (i == rs->rs_nrates)
        !          1320:                        return EINVAL;
        !          1321:        }
        !          1322:        if (ic->ic_fixed_rate != i) {
        !          1323:                ic->ic_fixed_rate = i;
        !          1324:                error = ENETRESET;
        !          1325:        }
        !          1326:
        !          1327:        if (ime->ifm_media & IFM_IEEE80211_ADHOC)
        !          1328:                newmode = IEEE80211_M_IBSS;
        !          1329:        else if (ime->ifm_media & IFM_IEEE80211_HOSTAP)
        !          1330:                newmode = IEEE80211_M_HOSTAP;
        !          1331:        else if (ime->ifm_media & IFM_IEEE80211_MONITOR)
        !          1332:                newmode = IEEE80211_M_MONITOR;
        !          1333:        else
        !          1334:                newmode = IEEE80211_M_STA;
        !          1335:        if (ic->ic_opmode != newmode) {
        !          1336:                ic->ic_opmode = newmode;
        !          1337:                error = ENETRESET;
        !          1338:        }
        !          1339:        if (error == ENETRESET) {
        !          1340:                if (sc->sc_enabled)
        !          1341:                        error = an_init(ifp);
        !          1342:                else
        !          1343:                        error = 0;
        !          1344:        }
        !          1345:        ifp->if_baudrate = ifmedia_baudrate(ic->ic_media.ifm_cur->ifm_media);
        !          1346:
        !          1347:        return error;
        !          1348: }
        !          1349:
        !          1350: void
        !          1351: an_media_status(struct ifnet *ifp, struct ifmediareq *imr)
        !          1352: {
        !          1353:        struct an_softc *sc = ifp->if_softc;
        !          1354:        struct ieee80211com *ic = &sc->sc_ic;
        !          1355:        int rate, buflen;
        !          1356:
        !          1357:        if (sc->sc_enabled == 0) {
        !          1358:                imr->ifm_active = IFM_IEEE80211 | IFM_NONE;
        !          1359:                imr->ifm_status = 0;
        !          1360:                return;
        !          1361:        }
        !          1362:
        !          1363:        imr->ifm_status = IFM_AVALID;
        !          1364:        imr->ifm_active = IFM_IEEE80211;
        !          1365:        if (ic->ic_state == IEEE80211_S_RUN)
        !          1366:                imr->ifm_status |= IFM_ACTIVE;
        !          1367:        buflen = sizeof(sc->sc_buf);
        !          1368:        if (ic->ic_fixed_rate != -1)
        !          1369:                rate = ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[
        !          1370:                    ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
        !          1371:        else if (an_read_rid(sc, AN_RID_STATUS, &sc->sc_buf, &buflen) != 0)
        !          1372:                rate = 0;
        !          1373:        else
        !          1374:                rate = sc->sc_buf.sc_status.an_current_tx_rate;
        !          1375:        imr->ifm_active |= ieee80211_rate2media(ic, rate, IEEE80211_MODE_11B);
        !          1376:        switch (ic->ic_opmode) {
        !          1377:        case IEEE80211_M_STA:
        !          1378:                break;
        !          1379:        case IEEE80211_M_IBSS:
        !          1380:                imr->ifm_active |= IFM_IEEE80211_ADHOC;
        !          1381:                break;
        !          1382:        case IEEE80211_M_HOSTAP:
        !          1383:                imr->ifm_active |= IFM_IEEE80211_HOSTAP;
        !          1384:                break;
        !          1385:        case IEEE80211_M_MONITOR:
        !          1386:                imr->ifm_active |= IFM_IEEE80211_MONITOR;
        !          1387:                break;
        !          1388:        default:
        !          1389:                break;
        !          1390:        }
        !          1391: }
        !          1392:
        !          1393: int
        !          1394: an_set_nwkey(struct an_softc *sc, struct ieee80211_nwkey *nwkey)
        !          1395: {
        !          1396:        int error;
        !          1397:        struct ieee80211com *ic = &sc->sc_ic;
        !          1398:        u_int16_t prevauth;
        !          1399:
        !          1400:        error = 0;
        !          1401:        prevauth = sc->sc_config.an_authtype;
        !          1402:
        !          1403:        switch (nwkey->i_wepon) {
        !          1404:        case IEEE80211_NWKEY_OPEN:
        !          1405:                sc->sc_config.an_authtype = AN_AUTHTYPE_OPEN;
        !          1406:                ic->ic_flags &= ~IEEE80211_F_WEPON;
        !          1407:                break;
        !          1408:
        !          1409:        case IEEE80211_NWKEY_WEP:
        !          1410:        case IEEE80211_NWKEY_WEP | IEEE80211_NWKEY_PERSIST:
        !          1411:                error = an_set_nwkey_wep(sc, nwkey);
        !          1412:                if (error == 0 || error == ENETRESET) {
        !          1413:                        sc->sc_config.an_authtype =
        !          1414:                            AN_AUTHTYPE_OPEN | AN_AUTHTYPE_PRIVACY_IN_USE;
        !          1415:                        ic->ic_flags |= IEEE80211_F_WEPON;
        !          1416:                }
        !          1417:                break;
        !          1418:
        !          1419:        default:
        !          1420:                error = EINVAL;
        !          1421:                break;
        !          1422:        }
        !          1423:        if (error == 0 && prevauth != sc->sc_config.an_authtype)
        !          1424:                error = ENETRESET;
        !          1425:        return error;
        !          1426: }
        !          1427:
        !          1428: int
        !          1429: an_set_nwkey_wep(struct an_softc *sc, struct ieee80211_nwkey *nwkey)
        !          1430: {
        !          1431:        int i, txkey, anysetkey, needreset, error;
        !          1432:        struct an_wepkey keys[IEEE80211_WEP_NKID];
        !          1433:
        !          1434:        error = 0;
        !          1435:        memset(keys, 0, sizeof(keys));
        !          1436:        anysetkey = needreset = 0;
        !          1437:
        !          1438:        /* load argument and sanity check */
        !          1439:        for (i = 0; i < IEEE80211_WEP_NKID; i++) {
        !          1440:                keys[i].an_wep_keylen = nwkey->i_key[i].i_keylen;
        !          1441:                if (keys[i].an_wep_keylen < 0)
        !          1442:                        continue;
        !          1443:                if (keys[i].an_wep_keylen != 0 &&
        !          1444:                    keys[i].an_wep_keylen < IEEE80211_WEP_KEYLEN)
        !          1445:                        return EINVAL;
        !          1446:                if (keys[i].an_wep_keylen > sizeof(keys[i].an_wep_key))
        !          1447:                        return EINVAL;
        !          1448:                if ((error = copyin(nwkey->i_key[i].i_keydat,
        !          1449:                    keys[i].an_wep_key, keys[i].an_wep_keylen)) != 0)
        !          1450:                        return error;
        !          1451:                anysetkey++;
        !          1452:        }
        !          1453:        txkey = nwkey->i_defkid - 1;
        !          1454:        if (txkey >= 0) {
        !          1455:                if (txkey >= IEEE80211_WEP_NKID)
        !          1456:                        return EINVAL;
        !          1457:                /* default key must have a valid value */
        !          1458:                if (keys[txkey].an_wep_keylen == 0 ||
        !          1459:                    (keys[txkey].an_wep_keylen < 0 &&
        !          1460:                    sc->sc_perskeylen[txkey] == 0))
        !          1461:                        return EINVAL;
        !          1462:                anysetkey++;
        !          1463:        }
        !          1464:        DPRINTF(("an_set_nwkey_wep: %s: %sold(%d:%d,%d,%d,%d) "
        !          1465:            "pers(%d:%d,%d,%d,%d) new(%d:%d,%d,%d,%d)\n",
        !          1466:            sc->sc_dev.dv_xname,
        !          1467:            ((nwkey->i_wepon & IEEE80211_NWKEY_PERSIST) ? "persist: " : ""),
        !          1468:            sc->sc_tx_key,
        !          1469:            sc->sc_wepkeys[0].an_wep_keylen, sc->sc_wepkeys[1].an_wep_keylen,
        !          1470:            sc->sc_wepkeys[2].an_wep_keylen, sc->sc_wepkeys[3].an_wep_keylen,
        !          1471:            sc->sc_tx_perskey,
        !          1472:            sc->sc_perskeylen[0], sc->sc_perskeylen[1],
        !          1473:            sc->sc_perskeylen[2], sc->sc_perskeylen[3],
        !          1474:            txkey,
        !          1475:            keys[0].an_wep_keylen, keys[1].an_wep_keylen,
        !          1476:            keys[2].an_wep_keylen, keys[3].an_wep_keylen));
        !          1477:        if (!(nwkey->i_wepon & IEEE80211_NWKEY_PERSIST)) {
        !          1478:                /* set temporary keys */
        !          1479:                sc->sc_tx_key = txkey;
        !          1480:                for (i = 0; i < IEEE80211_WEP_NKID; i++) {
        !          1481:                        if (keys[i].an_wep_keylen < 0)
        !          1482:                                continue;
        !          1483:                        memcpy(&sc->sc_wepkeys[i], &keys[i], sizeof(keys[i]));
        !          1484:                }
        !          1485:        } else {
        !          1486:                /* set persist keys */
        !          1487:                if (anysetkey) {
        !          1488:                        /* prepare to write nvram */
        !          1489:                        if (!sc->sc_enabled) {
        !          1490:                                if (sc->sc_enable)
        !          1491:                                        (*sc->sc_enable)(sc);
        !          1492:                                an_wait(sc);
        !          1493:                                sc->sc_enabled = 1;
        !          1494:                                error = an_write_wepkey(sc,
        !          1495:                                    AN_RID_WEP_PERSISTENT, keys, txkey);
        !          1496:                                if (sc->sc_disable)
        !          1497:                                        (*sc->sc_disable)(sc);
        !          1498:                                sc->sc_enabled = 0;
        !          1499:                        } else {
        !          1500:                                an_cmd(sc, AN_CMD_DISABLE, 0);
        !          1501:                                error = an_write_wepkey(sc,
        !          1502:                                    AN_RID_WEP_PERSISTENT, keys, txkey);
        !          1503:                                an_cmd(sc, AN_CMD_ENABLE, 0);
        !          1504:                        }
        !          1505:                        if (error)
        !          1506:                                return error;
        !          1507:                }
        !          1508:                if (txkey >= 0)
        !          1509:                        sc->sc_tx_perskey = txkey;
        !          1510:                if (sc->sc_tx_key >= 0) {
        !          1511:                        sc->sc_tx_key = -1;
        !          1512:                        needreset++;
        !          1513:                }
        !          1514:                for (i = 0; i < IEEE80211_WEP_NKID; i++) {
        !          1515:                        if (sc->sc_wepkeys[i].an_wep_keylen >= 0) {
        !          1516:                                memset(&sc->sc_wepkeys[i].an_wep_key, 0,
        !          1517:                                    sizeof(sc->sc_wepkeys[i].an_wep_key));
        !          1518:                                sc->sc_wepkeys[i].an_wep_keylen = -1;
        !          1519:                                needreset++;
        !          1520:                        }
        !          1521:                        if (keys[i].an_wep_keylen >= 0)
        !          1522:                                sc->sc_perskeylen[i] = keys[i].an_wep_keylen;
        !          1523:                }
        !          1524:        }
        !          1525:        if (needreset) {
        !          1526:                /* firmware restart to reload persistent key */
        !          1527:                an_reset(sc);
        !          1528:        }
        !          1529:        if (anysetkey || needreset)
        !          1530:                error = ENETRESET;
        !          1531:        return error;
        !          1532: }
        !          1533:
        !          1534: int
        !          1535: an_get_nwkey(struct an_softc *sc, struct ieee80211_nwkey *nwkey)
        !          1536: {
        !          1537:        int i, error;
        !          1538:
        !          1539:        error = 0;
        !          1540:        if (sc->sc_config.an_authtype & AN_AUTHTYPE_LEAP)
        !          1541:                nwkey->i_wepon = IEEE80211_NWKEY_EAP;
        !          1542:        else if (sc->sc_config.an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE)
        !          1543:                nwkey->i_wepon = IEEE80211_NWKEY_WEP;
        !          1544:        else
        !          1545:                nwkey->i_wepon = IEEE80211_NWKEY_OPEN;
        !          1546:        if (sc->sc_tx_key == -1)
        !          1547:                nwkey->i_defkid = sc->sc_tx_perskey + 1;
        !          1548:        else
        !          1549:                nwkey->i_defkid = sc->sc_tx_key + 1;
        !          1550:        if (nwkey->i_key[0].i_keydat == NULL)
        !          1551:                return 0;
        !          1552:        for (i = 0; i < IEEE80211_WEP_NKID; i++) {
        !          1553:                if (nwkey->i_key[i].i_keydat == NULL)
        !          1554:                        continue;
        !          1555:                /* do not show any keys to non-root user */
        !          1556:                if ((error = suser(curproc, 0)) != 0)
        !          1557:                        break;
        !          1558:                nwkey->i_key[i].i_keylen = sc->sc_wepkeys[i].an_wep_keylen;
        !          1559:                if (nwkey->i_key[i].i_keylen < 0) {
        !          1560:                        if (sc->sc_perskeylen[i] == 0)
        !          1561:                                nwkey->i_key[i].i_keylen = 0;
        !          1562:                        continue;
        !          1563:                }
        !          1564:                if ((error = copyout(sc->sc_wepkeys[i].an_wep_key,
        !          1565:                    nwkey->i_key[i].i_keydat,
        !          1566:                    sc->sc_wepkeys[i].an_wep_keylen)) != 0)
        !          1567:                        break;
        !          1568:        }
        !          1569:        return error;
        !          1570: }
        !          1571:
        !          1572: int
        !          1573: an_write_wepkey(struct an_softc *sc, int type, struct an_wepkey *keys, int kid)
        !          1574: {
        !          1575:        int i, error;
        !          1576:        struct an_rid_wepkey *akey;
        !          1577:
        !          1578:        error = 0;
        !          1579:        akey = &sc->sc_buf.sc_wepkey;
        !          1580:        for (i = 0; i < IEEE80211_WEP_NKID; i++) {
        !          1581:                memset(akey, 0, sizeof(struct an_rid_wepkey));
        !          1582:                if (keys[i].an_wep_keylen < 0 ||
        !          1583:                    keys[i].an_wep_keylen > sizeof(akey->an_key))
        !          1584:                        continue;
        !          1585:                akey->an_key_len = keys[i].an_wep_keylen;
        !          1586:                akey->an_key_index = i;
        !          1587:                akey->an_mac_addr[0] = 1;       /* default mac */
        !          1588:                an_swap16((u_int16_t *)&akey->an_mac_addr, 3);
        !          1589:                memcpy(akey->an_key, keys[i].an_wep_key, keys[i].an_wep_keylen);
        !          1590:                an_swap16((u_int16_t *)&akey->an_key, 8);
        !          1591:                if ((error = an_write_rid(sc, type, akey, sizeof(*akey))) != 0)
        !          1592:                        return error;
        !          1593:        }
        !          1594:        if (kid >= 0) {
        !          1595:                memset(akey, 0, sizeof(struct an_rid_wepkey));
        !          1596:                akey->an_key_index = 0xffff;
        !          1597:                akey->an_mac_addr[0] = kid;
        !          1598:                an_swap16((u_int16_t *)&akey->an_mac_addr, 3);
        !          1599:                akey->an_key_len = 0;
        !          1600:                memset(akey->an_key, 0, sizeof(akey->an_key));
        !          1601:                error = an_write_rid(sc, type, akey, sizeof(*akey));
        !          1602:        }
        !          1603:        return error;
        !          1604: }
        !          1605:
        !          1606: int
        !          1607: an_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
        !          1608: {
        !          1609:        struct an_softc *sc = ic->ic_softc;
        !          1610:        struct ieee80211_node *ni = ic->ic_bss;
        !          1611:        enum ieee80211_state ostate;
        !          1612:        int buflen;
        !          1613:
        !          1614:        ostate = ic->ic_state;
        !          1615:        DPRINTF(("an_newstate: %s -> %s\n", ieee80211_state_name[ostate],
        !          1616:            ieee80211_state_name[nstate]));
        !          1617:
        !          1618:        switch (nstate) {
        !          1619:        case IEEE80211_S_INIT:
        !          1620:                ic->ic_flags &= ~IEEE80211_F_IBSSON;
        !          1621:                return (*sc->sc_newstate)(ic, nstate, arg);
        !          1622:
        !          1623:        case IEEE80211_S_RUN:
        !          1624:                buflen = sizeof(sc->sc_buf);
        !          1625:                an_read_rid(sc, AN_RID_STATUS, &sc->sc_buf, &buflen);
        !          1626:                an_swap16((u_int16_t *)&sc->sc_buf.sc_status.an_cur_bssid, 3);
        !          1627:                an_swap16((u_int16_t *)&sc->sc_buf.sc_status.an_ssid, 16);
        !          1628:                IEEE80211_ADDR_COPY(ni->ni_bssid,
        !          1629:                    sc->sc_buf.sc_status.an_cur_bssid);
        !          1630:                IEEE80211_ADDR_COPY(ni->ni_macaddr, ni->ni_bssid);
        !          1631:                ni->ni_chan = &ic->ic_channels[
        !          1632:                    sc->sc_buf.sc_status.an_cur_channel];
        !          1633:                ni->ni_esslen = sc->sc_buf.sc_status.an_ssidlen;
        !          1634:                if (ni->ni_esslen > IEEE80211_NWID_LEN)
        !          1635:                        ni->ni_esslen = IEEE80211_NWID_LEN;     /*XXX*/
        !          1636:                memcpy(ni->ni_essid, sc->sc_buf.sc_status.an_ssid,
        !          1637:                    ni->ni_esslen);
        !          1638:                ni->ni_rates = ic->ic_sup_rates[IEEE80211_MODE_11B];    /*XXX*/
        !          1639:                if (ic->ic_if.if_flags & IFF_DEBUG) {
        !          1640:                        printf("%s: ", sc->sc_dev.dv_xname);
        !          1641:                        if (ic->ic_opmode == IEEE80211_M_STA)
        !          1642:                                printf("associated ");
        !          1643:                        else
        !          1644:                                printf("synchronized ");
        !          1645:                        printf("with %s ssid ", ether_sprintf(ni->ni_bssid));
        !          1646:                        ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
        !          1647:                        printf(" channel %u start %uMb\n",
        !          1648:                            sc->sc_buf.sc_status.an_cur_channel,
        !          1649:                            sc->sc_buf.sc_status.an_current_tx_rate/2);
        !          1650:                }
        !          1651:                break;
        !          1652:
        !          1653:        default:
        !          1654:                break;
        !          1655:        }
        !          1656:        ic->ic_state = nstate;
        !          1657:        /* skip standard ieee80211 handling */
        !          1658:        return 0;
        !          1659: }
        !          1660:
        !          1661: int
        !          1662: an_detach(struct an_softc *sc)
        !          1663: {
        !          1664:        struct ifnet *ifp = &sc->sc_ic.ic_if;
        !          1665:        int s;
        !          1666:
        !          1667:        if (!sc->sc_attached)
        !          1668:                return 0;
        !          1669:
        !          1670:        s = splnet();
        !          1671:        sc->sc_invalid = 1;
        !          1672:        an_stop(ifp, 1);
        !          1673:        ifmedia_delete_instance(&sc->sc_ic.ic_media, IFM_INST_ANY);
        !          1674:        ieee80211_ifdetach(ifp);
        !          1675:        if_detach(ifp);
        !          1676:        if (sc->sc_sdhook != NULL)
        !          1677:                shutdownhook_disestablish(sc->sc_sdhook);
        !          1678:        splx(s);
        !          1679:        return 0;
        !          1680: }
        !          1681:

CVSweb