The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ic/an.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

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

Cache object: 119416344bf6cdc0db2db9b42034b0cf


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.