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/if_wi.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $OpenBSD: if_wi.c,v 1.177 2022/07/14 13:46:24 bluhm Exp $       */
    2 
    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  *      From: if_wi.c,v 1.7 1999/07/04 14:40:22 wpaul Exp $
   35  */
   36 
   37 /*
   38  * Lucent WaveLAN/IEEE 802.11 driver for OpenBSD.
   39  *
   40  * Originally written by Bill Paul <wpaul@ctr.columbia.edu>
   41  * Electrical Engineering Department
   42  * Columbia University, New York City
   43  */
   44 
   45 /*
   46  * The WaveLAN/IEEE adapter is the second generation of the WaveLAN
   47  * from Lucent. Unlike the older cards, the new ones are programmed
   48  * entirely via a firmware-driven controller called the Hermes.
   49  * Unfortunately, Lucent will not release the Hermes programming manual
   50  * without an NDA (if at all). What they do release is an API library
   51  * called the HCF (Hardware Control Functions) which is supposed to
   52  * do the device-specific operations of a device driver for you. The
   53  * publicly available version of the HCF library (the 'HCF Light') is
   54  * a) extremely gross, b) lacks certain features, particularly support
   55  * for 802.11 frames, and c) is contaminated by the GNU Public License.
   56  *
   57  * This driver does not use the HCF or HCF Light at all. Instead, it
   58  * programs the Hermes controller directly, using information gleaned
   59  * from the HCF Light code and corresponding documentation.
   60  */
   61 
   62 #define WI_HERMES_AUTOINC_WAR   /* Work around data write autoinc bug. */
   63 #define WI_HERMES_STATS_WAR     /* Work around stats counter bug. */
   64 
   65 #include "bpfilter.h"
   66 
   67 #include <sys/param.h>
   68 #include <sys/systm.h>
   69 #include <sys/sockio.h>
   70 #include <sys/mbuf.h>
   71 #include <sys/malloc.h>
   72 #include <sys/kernel.h>
   73 #include <sys/socket.h>
   74 #include <sys/device.h>
   75 
   76 #include <net/if.h>
   77 #include <net/if_dl.h>
   78 #include <net/if_media.h>
   79 
   80 #include <netinet/in.h>
   81 #include <netinet/if_ether.h>
   82 
   83 #include <net80211/ieee80211_var.h>
   84 #include <net80211/ieee80211_ioctl.h>
   85 
   86 #if NBPFILTER > 0
   87 #include <net/bpf.h>
   88 #endif
   89 
   90 #include <machine/bus.h>
   91 
   92 #include <dev/ic/if_wireg.h>
   93 #include <dev/ic/if_wi_ieee.h>
   94 #include <dev/ic/if_wivar.h>
   95 
   96 #include <crypto/arc4.h>
   97 
   98 #define BPFATTACH(if_bpf,if,dlt,sz)
   99 #define STATIC
  100 
  101 #ifdef WIDEBUG
  102 
  103 u_int32_t       widebug = WIDEBUG;
  104 
  105 #define WID_INTR        0x01
  106 #define WID_START       0x02
  107 #define WID_IOCTL       0x04
  108 #define WID_INIT        0x08
  109 #define WID_STOP        0x10
  110 #define WID_RESET       0x20
  111 
  112 #define DPRINTF(mask,args) if (widebug & (mask)) printf args;
  113 
  114 #else   /* !WIDEBUG */
  115 #define DPRINTF(mask,args)
  116 #endif  /* WIDEBUG */
  117 
  118 #ifdef foo
  119 static u_int8_t wi_mcast_addr[6] = { 0x01, 0x60, 0x1D, 0x00, 0x01, 0x00 };
  120 #endif
  121 
  122 STATIC void wi_reset(struct wi_softc *);
  123 STATIC int wi_ioctl(struct ifnet *, u_long, caddr_t);
  124 STATIC void wi_init_io(struct wi_softc *);
  125 STATIC void wi_start(struct ifnet *);
  126 STATIC void wi_watchdog(struct ifnet *);
  127 STATIC void wi_rxeof(struct wi_softc *);
  128 STATIC void wi_txeof(struct wi_softc *, int);
  129 STATIC void wi_update_stats(struct wi_softc *);
  130 STATIC void wi_setmulti(struct wi_softc *);
  131 
  132 STATIC int wi_cmd_io(struct wi_softc *, int, int, int, int);
  133 STATIC int wi_read_record_io(struct wi_softc *, struct wi_ltv_gen *);
  134 STATIC int wi_write_record_io(struct wi_softc *, struct wi_ltv_gen *);
  135 STATIC int wi_read_data_io(struct wi_softc *, int,
  136                                         int, caddr_t, int);
  137 STATIC int wi_write_data_io(struct wi_softc *, int,
  138                                         int, caddr_t, int);
  139 STATIC int wi_seek(struct wi_softc *, int, int, int);
  140 
  141 STATIC void wi_inquire(void *);
  142 STATIC int wi_setdef(struct wi_softc *, struct wi_req *);
  143 STATIC void wi_get_id(struct wi_softc *);
  144 
  145 STATIC int wi_media_change(struct ifnet *);
  146 STATIC void wi_media_status(struct ifnet *, struct ifmediareq *);
  147 
  148 STATIC int wi_set_ssid(struct ieee80211_nwid *, u_int8_t *, int);
  149 STATIC int wi_set_nwkey(struct wi_softc *, struct ieee80211_nwkey *);
  150 STATIC int wi_get_nwkey(struct wi_softc *, struct ieee80211_nwkey *);
  151 STATIC int wi_sync_media(struct wi_softc *, int, int);
  152 STATIC int wi_set_pm(struct wi_softc *, struct ieee80211_power *);
  153 STATIC int wi_get_pm(struct wi_softc *, struct ieee80211_power *);
  154 STATIC int wi_set_txpower(struct wi_softc *, struct ieee80211_txpower *);
  155 STATIC int wi_get_txpower(struct wi_softc *, struct ieee80211_txpower *);
  156 
  157 STATIC int wi_get_debug(struct wi_softc *, struct wi_req *);
  158 STATIC int wi_set_debug(struct wi_softc *, struct wi_req *);
  159 
  160 STATIC void wi_do_hostencrypt(struct wi_softc *, caddr_t, int);                
  161 STATIC int wi_do_hostdecrypt(struct wi_softc *, caddr_t, int);
  162 
  163 STATIC int wi_alloc_nicmem_io(struct wi_softc *, int, int *);
  164 STATIC int wi_get_fid_io(struct wi_softc *sc, int fid);
  165 STATIC void wi_intr_enable(struct wi_softc *sc, int mode);
  166 STATIC void wi_intr_ack(struct wi_softc *sc, int mode);
  167 void     wi_scan_timeout(void *);
  168 
  169 /* Autoconfig definition of driver back-end */
  170 struct cfdriver wi_cd = {
  171         NULL, "wi", DV_IFNET
  172 };
  173 
  174 const struct wi_card_ident wi_card_ident[] = {
  175         WI_CARD_IDS
  176 };
  177 
  178 struct wi_funcs wi_func_io = {
  179         wi_cmd_io,
  180         wi_read_record_io,
  181         wi_write_record_io,
  182         wi_alloc_nicmem_io,
  183         wi_read_data_io,
  184         wi_write_data_io,
  185         wi_get_fid_io,
  186         wi_init_io,
  187 
  188         wi_start,
  189         wi_ioctl,
  190         wi_watchdog,
  191         wi_inquire,
  192 };
  193 
  194 int
  195 wi_attach(struct wi_softc *sc, struct wi_funcs *funcs)
  196 {
  197         struct ieee80211com     *ic;
  198         struct ifnet            *ifp;
  199         struct wi_ltv_macaddr   mac;
  200         struct wi_ltv_rates     rates;
  201         struct wi_ltv_gen       gen;
  202         int                     error;
  203 
  204         ic = &sc->sc_ic;
  205         ifp = &ic->ic_if;
  206 
  207         sc->sc_funcs = funcs;
  208         sc->wi_cmd_count = 500;
  209 
  210         wi_reset(sc);
  211 
  212         /* Read the station address. */
  213         mac.wi_type = WI_RID_MAC_NODE;
  214         mac.wi_len = 4;
  215         error = wi_read_record(sc, (struct wi_ltv_gen *)&mac);
  216         if (error) {
  217                 printf(": unable to read station address\n");
  218                 return (error);
  219         }
  220         bcopy(&mac.wi_mac_addr, &ic->ic_myaddr, IEEE80211_ADDR_LEN);
  221 
  222         wi_get_id(sc);
  223         printf("address %s", ether_sprintf(ic->ic_myaddr));
  224 
  225         bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
  226         ifp->if_softc = sc;
  227         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
  228         ifp->if_ioctl = funcs->f_ioctl;
  229         ifp->if_start = funcs->f_start;
  230         ifp->if_watchdog = funcs->f_watchdog;
  231 
  232         (void)wi_set_ssid(&sc->wi_node_name, WI_DEFAULT_NODENAME,
  233             sizeof(WI_DEFAULT_NODENAME) - 1);
  234         (void)wi_set_ssid(&sc->wi_net_name, WI_DEFAULT_NETNAME,
  235             sizeof(WI_DEFAULT_NETNAME) - 1);
  236         (void)wi_set_ssid(&sc->wi_ibss_name, WI_DEFAULT_IBSS,
  237             sizeof(WI_DEFAULT_IBSS) - 1);
  238 
  239         sc->wi_portnum = WI_DEFAULT_PORT;
  240         sc->wi_ptype = WI_PORTTYPE_BSS;
  241         sc->wi_ap_density = WI_DEFAULT_AP_DENSITY;
  242         sc->wi_rts_thresh = WI_DEFAULT_RTS_THRESH;
  243         sc->wi_tx_rate = WI_DEFAULT_TX_RATE;
  244         sc->wi_max_data_len = WI_DEFAULT_DATALEN;
  245         sc->wi_create_ibss = WI_DEFAULT_CREATE_IBSS;
  246         sc->wi_pm_enabled = WI_DEFAULT_PM_ENABLED;
  247         sc->wi_max_sleep = WI_DEFAULT_MAX_SLEEP;
  248         sc->wi_roaming = WI_DEFAULT_ROAMING;
  249         sc->wi_authtype = WI_DEFAULT_AUTHTYPE;
  250         sc->wi_diversity = WI_DEFAULT_DIVERSITY;
  251         sc->wi_crypto_algorithm = WI_CRYPTO_FIRMWARE_WEP;
  252 
  253         /*
  254          * Read the default channel from the NIC. This may vary
  255          * depending on the country where the NIC was purchased, so
  256          * we can't hard-code a default and expect it to work for
  257          * everyone.
  258          */
  259         gen.wi_type = WI_RID_OWN_CHNL;
  260         gen.wi_len = 2;
  261         if (wi_read_record(sc, &gen) == 0)
  262                 sc->wi_channel = letoh16(gen.wi_val);
  263         else
  264                 sc->wi_channel = 3;
  265 
  266         /*
  267          * Set flags based on firmware version.
  268          */
  269         switch (sc->sc_firmware_type) {
  270         case WI_LUCENT:
  271                 sc->wi_flags |= WI_FLAGS_HAS_ROAMING;
  272                 if (sc->sc_sta_firmware_ver >= 60000)
  273                         sc->wi_flags |= WI_FLAGS_HAS_MOR;
  274                 if (sc->sc_sta_firmware_ver >= 60006) {
  275                         sc->wi_flags |= WI_FLAGS_HAS_IBSS;
  276                         sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS;
  277                 }
  278                 sc->wi_ibss_port = htole16(1);
  279                 break;
  280         case WI_INTERSIL:
  281                 sc->wi_flags |= WI_FLAGS_HAS_ROAMING;
  282                 /* older prism firmware is slow so crank the count */
  283                 if (sc->sc_sta_firmware_ver < 10000)
  284                         sc->wi_cmd_count = 5000;
  285                 else
  286                         sc->wi_cmd_count = 2000;
  287                 if (sc->sc_sta_firmware_ver >= 800) {
  288 #ifndef SMALL_KERNEL
  289                         /*
  290                          * USB hostap is more pain than it is worth
  291                          * for now, things would have to be overhauled
  292                          */
  293                         if ((sc->sc_sta_firmware_ver != 10402) &&
  294                             (!(sc->wi_flags & WI_FLAGS_BUS_USB)))
  295                                 sc->wi_flags |= WI_FLAGS_HAS_HOSTAP;
  296 #endif
  297                         sc->wi_flags |= WI_FLAGS_HAS_IBSS;
  298                         sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS;
  299                 }
  300                 if (sc->sc_sta_firmware_ver >= 10603)
  301                         sc->wi_flags |= WI_FLAGS_HAS_ENH_SECURITY;
  302                 sc->wi_ibss_port = htole16(0);
  303                 break;
  304         case WI_SYMBOL:
  305                 sc->wi_flags |= WI_FLAGS_HAS_DIVERSITY;
  306                 if (sc->sc_sta_firmware_ver >= 20000)
  307                         sc->wi_flags |= WI_FLAGS_HAS_IBSS;
  308                 if (sc->sc_sta_firmware_ver >= 25000)
  309                         sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS;
  310                 sc->wi_ibss_port = htole16(4);
  311                 break;
  312         }
  313 
  314         /*
  315          * Find out if we support WEP on this card.
  316          */
  317         gen.wi_type = WI_RID_WEP_AVAIL;
  318         gen.wi_len = 2;
  319         if (wi_read_record(sc, &gen) == 0 && gen.wi_val != htole16(0))
  320                 sc->wi_flags |= WI_FLAGS_HAS_WEP;
  321         timeout_set(&sc->sc_timo, funcs->f_inquire, sc);
  322 
  323         bzero(&sc->wi_stats, sizeof(sc->wi_stats));
  324 
  325         /* Find supported rates. */
  326         rates.wi_type = WI_RID_DATA_RATES;
  327         rates.wi_len = sizeof(rates.wi_rates);
  328         if (wi_read_record(sc, (struct wi_ltv_gen *)&rates) == 0) {
  329                 int i, nrates;
  330 
  331                 nrates = letoh16(*(u_int16_t *)rates.wi_rates);
  332                 if (nrates > sizeof(rates.wi_rates) - 2)
  333                         nrates = sizeof(rates.wi_rates) - 2;
  334 
  335                 sc->wi_supprates = 0;
  336                 for (i = 0; i < nrates; i++)
  337                         sc->wi_supprates |= rates.wi_rates[2 + i];
  338         } else
  339                 sc->wi_supprates = WI_SUPPRATES_1M | WI_SUPPRATES_2M |
  340                     WI_SUPPRATES_5M | WI_SUPPRATES_11M;
  341 
  342         ifmedia_init(&sc->sc_media, 0, wi_media_change, wi_media_status);
  343 #define ADD(m, c)       ifmedia_add(&sc->sc_media, (m), (c), NULL)
  344         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0), 0);
  345         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, IFM_IEEE80211_ADHOC, 0), 0);
  346         if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
  347                 ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, IFM_IEEE80211_IBSS,
  348                     0), 0);
  349         if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
  350                 ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
  351                     IFM_IEEE80211_IBSSMASTER, 0), 0);
  352         if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
  353                 ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
  354                     IFM_IEEE80211_HOSTAP, 0), 0);
  355         if (sc->wi_supprates & WI_SUPPRATES_1M) {
  356                 ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 0, 0), 0);
  357                 ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
  358                     IFM_IEEE80211_ADHOC, 0), 0);
  359                 if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
  360                         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
  361                             IFM_IEEE80211_IBSS, 0), 0);
  362                 if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
  363                         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
  364                             IFM_IEEE80211_IBSSMASTER, 0), 0);
  365                 if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
  366                         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
  367                             IFM_IEEE80211_HOSTAP, 0), 0);
  368         }
  369         if (sc->wi_supprates & WI_SUPPRATES_2M) {
  370                 ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 0, 0), 0);
  371                 ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
  372                     IFM_IEEE80211_ADHOC, 0), 0);
  373                 if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
  374                         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
  375                             IFM_IEEE80211_IBSS, 0), 0);
  376                 if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
  377                         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
  378                             IFM_IEEE80211_IBSSMASTER, 0), 0);
  379                 if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
  380                         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
  381                             IFM_IEEE80211_HOSTAP, 0), 0);
  382         }
  383         if (sc->wi_supprates & WI_SUPPRATES_5M) {
  384                 ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 0, 0), 0);
  385                 ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
  386                     IFM_IEEE80211_ADHOC, 0), 0);
  387                 if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
  388                         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
  389                             IFM_IEEE80211_IBSS, 0), 0);
  390                 if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
  391                         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
  392                             IFM_IEEE80211_IBSSMASTER, 0), 0);
  393                 if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
  394                         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
  395                             IFM_IEEE80211_HOSTAP, 0), 0);
  396         }
  397         if (sc->wi_supprates & WI_SUPPRATES_11M) {
  398                 ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 0, 0), 0);
  399                 ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
  400                     IFM_IEEE80211_ADHOC, 0), 0);
  401                 if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
  402                         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
  403                             IFM_IEEE80211_IBSS, 0), 0);
  404                 if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
  405                         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
  406                             IFM_IEEE80211_IBSSMASTER, 0), 0);
  407                 if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
  408                         ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
  409                             IFM_IEEE80211_HOSTAP, 0), 0);
  410                 ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_MANUAL, 0, 0), 0);
  411         }
  412 #undef ADD
  413         ifmedia_set(&sc->sc_media,
  414             IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0));
  415 
  416         /*
  417          * Call MI attach routines.
  418          */
  419         if_attach(ifp);
  420         memcpy(((struct arpcom *)ifp)->ac_enaddr, ic->ic_myaddr,
  421             ETHER_ADDR_LEN);
  422         ether_ifattach(ifp);
  423         printf("\n");
  424 
  425         sc->wi_flags |= WI_FLAGS_ATTACHED;
  426 
  427 #if NBPFILTER > 0
  428         BPFATTACH(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
  429 #endif
  430 
  431         if_addgroup(ifp, "wlan");
  432         ifp->if_priority = IF_WIRELESS_DEFAULT_PRIORITY;
  433 
  434         wi_init(sc);
  435         wi_stop(sc);
  436 
  437         return (0);
  438 }
  439 
  440 STATIC void
  441 wi_intr_enable(struct wi_softc *sc, int mode)
  442 {
  443         if (!(sc->wi_flags & WI_FLAGS_BUS_USB))
  444                 CSR_WRITE_2(sc, WI_INT_EN, mode);
  445 }
  446 
  447 STATIC void
  448 wi_intr_ack(struct wi_softc *sc, int mode)
  449 {
  450         if (!(sc->wi_flags & WI_FLAGS_BUS_USB))
  451                 CSR_WRITE_2(sc, WI_EVENT_ACK, mode);
  452 }
  453 
  454 int
  455 wi_intr(void *vsc)
  456 {
  457         struct wi_softc         *sc = vsc;
  458         struct ifnet            *ifp;
  459         u_int16_t               status;
  460 
  461         DPRINTF(WID_INTR, ("wi_intr: sc %p\n", sc));
  462 
  463         ifp = &sc->sc_ic.ic_if;
  464 
  465         if (!(sc->wi_flags & WI_FLAGS_ATTACHED) || !(ifp->if_flags & IFF_UP)) {
  466                 CSR_WRITE_2(sc, WI_INT_EN, 0);
  467                 CSR_WRITE_2(sc, WI_EVENT_ACK, 0xffff);
  468                 return (0);
  469         }
  470 
  471         /* Disable interrupts. */
  472         CSR_WRITE_2(sc, WI_INT_EN, 0);
  473 
  474         status = CSR_READ_2(sc, WI_EVENT_STAT);
  475         CSR_WRITE_2(sc, WI_EVENT_ACK, ~WI_INTRS);
  476 
  477         if (status & WI_EV_RX) {
  478                 wi_rxeof(sc);
  479                 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
  480         }
  481 
  482         if (status & WI_EV_TX) {
  483                 wi_txeof(sc, status);
  484                 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX);
  485         }
  486 
  487         if (status & WI_EV_ALLOC) {
  488                 int                     id;
  489                 id = CSR_READ_2(sc, WI_ALLOC_FID);
  490                 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
  491                 if (id == sc->wi_tx_data_id)
  492                         wi_txeof(sc, status);
  493         }
  494 
  495         if (status & WI_EV_INFO) {
  496                 wi_update_stats(sc);
  497                 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO);
  498         }
  499 
  500         if (status & WI_EV_TX_EXC) {
  501                 wi_txeof(sc, status);
  502                 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX_EXC);
  503         }
  504 
  505         if (status & WI_EV_INFO_DROP) {
  506                 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO_DROP);
  507         }
  508 
  509         /* Re-enable interrupts. */
  510         CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
  511 
  512         if (status == 0)
  513                 return (0);
  514 
  515         if (!ifq_empty(&ifp->if_snd))
  516                 wi_start(ifp);
  517 
  518         return (1);
  519 }
  520 
  521 STATIC int
  522 wi_get_fid_io(struct wi_softc *sc, int fid)
  523 {
  524         return CSR_READ_2(sc, fid);
  525 }
  526 
  527 
  528 void
  529 wi_rxeof(struct wi_softc *sc)
  530 {
  531         struct ifnet            *ifp;
  532         struct ether_header     *eh;
  533         struct mbuf_list        ml = MBUF_LIST_INITIALIZER();
  534         struct mbuf             *m;
  535         caddr_t                 olddata;
  536         u_int16_t               ftype;
  537         int                     maxlen;
  538         int                     id;
  539 
  540         ifp = &sc->sc_ic.ic_if;
  541 
  542         id = wi_get_fid(sc, WI_RX_FID);
  543 
  544         if (sc->wi_procframe || sc->wi_debug.wi_monitor) {
  545                 struct wi_frame *rx_frame;
  546                 int             datlen, hdrlen;
  547 
  548                 MGETHDR(m, M_DONTWAIT, MT_DATA);
  549                 if (m == NULL) {
  550                         ifp->if_ierrors++;
  551                         return;
  552                 }
  553                 MCLGET(m, M_DONTWAIT);
  554                 if (!(m->m_flags & M_EXT)) {
  555                         m_freem(m);
  556                         ifp->if_ierrors++;
  557                         return;
  558                 }
  559 
  560                 if (wi_read_data(sc, id, 0, mtod(m, caddr_t),
  561                     sizeof(struct wi_frame))) {
  562                         m_freem(m);
  563                         ifp->if_ierrors++;
  564                         return;
  565                 }
  566 
  567                 rx_frame = mtod(m, struct wi_frame *);
  568 
  569                 if (rx_frame->wi_status & htole16(WI_STAT_BADCRC)) {
  570                         m_freem(m);
  571                         ifp->if_ierrors++;
  572                         return;
  573                 }
  574 
  575                 switch ((letoh16(rx_frame->wi_status) & WI_STAT_MAC_PORT)
  576                     >> 8) {
  577                 case 7:
  578                         switch (letoh16(rx_frame->wi_frame_ctl) &
  579                             WI_FCTL_FTYPE) {
  580                         case WI_FTYPE_DATA:
  581                                 hdrlen = WI_DATA_HDRLEN;
  582                                 datlen = letoh16(rx_frame->wi_dat_len);
  583                                 break;
  584                         case WI_FTYPE_MGMT:
  585                                 hdrlen = WI_MGMT_HDRLEN;
  586                                 datlen = letoh16(rx_frame->wi_dat_len);
  587                                 break;
  588                         case WI_FTYPE_CTL:
  589                                 hdrlen = WI_CTL_HDRLEN;
  590                                 datlen = 0;
  591                                 break;
  592                         default:
  593                                 printf(WI_PRT_FMT ": received packet of "
  594                                     "unknown type on port 7\n", WI_PRT_ARG(sc));
  595                                 m_freem(m);
  596                                 ifp->if_ierrors++;
  597                                 return;
  598                         }
  599                         break;
  600                 case 0:
  601                         hdrlen = WI_DATA_HDRLEN;
  602                         datlen = letoh16(rx_frame->wi_dat_len);
  603                         break;
  604                 default:
  605                         printf(WI_PRT_FMT ": received packet on invalid port "
  606                             "(wi_status=0x%x)\n", WI_PRT_ARG(sc),
  607                             letoh16(rx_frame->wi_status));
  608                         m_freem(m);
  609                         ifp->if_ierrors++;
  610                         return;
  611                 }
  612 
  613                 if ((hdrlen + datlen + 2) > MCLBYTES) {
  614                         m_freem(m);
  615                         ifp->if_ierrors++;
  616                         return;
  617                 }
  618 
  619                 if (wi_read_data(sc, id, hdrlen, mtod(m, caddr_t) + hdrlen,
  620                     datlen + 2)) {
  621                         m_freem(m);
  622                         ifp->if_ierrors++;
  623                         return;
  624                 }
  625 
  626                 m->m_pkthdr.len = m->m_len = hdrlen + datlen;
  627         } else {
  628                 struct wi_frame rx_frame;
  629 
  630                 /* First read in the frame header */
  631                 if (wi_read_data(sc, id, 0, (caddr_t)&rx_frame,
  632                     sizeof(rx_frame))) {
  633                         ifp->if_ierrors++;
  634                         return;
  635                 }
  636 
  637                 /* Drop undecryptable or packets with receive errors here */
  638                 if (rx_frame.wi_status & htole16(WI_STAT_ERRSTAT)) {
  639                         ifp->if_ierrors++;
  640                         return;
  641                 }
  642 
  643                 /* Stash frame type in host byte order for later use */
  644                 ftype = letoh16(rx_frame.wi_frame_ctl) & WI_FCTL_FTYPE;
  645 
  646                 MGETHDR(m, M_DONTWAIT, MT_DATA);
  647                 if (m == NULL) {
  648                         ifp->if_ierrors++;
  649                         return;
  650                 }
  651                 MCLGET(m, M_DONTWAIT);
  652                 if (!(m->m_flags & M_EXT)) {
  653                         m_freem(m);
  654                         ifp->if_ierrors++;
  655                         return;
  656                 }
  657 
  658                 olddata = m->m_data;
  659                 /* Align the data after the ethernet header */
  660                 m->m_data = (caddr_t)ALIGN(m->m_data +
  661                     sizeof(struct ether_header)) - sizeof(struct ether_header);
  662 
  663                 eh = mtod(m, struct ether_header *);
  664                 maxlen = MCLBYTES - (m->m_data - olddata);
  665 
  666                 if (ftype == WI_FTYPE_MGMT &&
  667                     sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
  668 
  669                         u_int16_t rxlen = letoh16(rx_frame.wi_dat_len);
  670 
  671                         if ((WI_802_11_OFFSET_RAW + rxlen + 2) > maxlen) {
  672                                 printf("%s: oversized mgmt packet received in "
  673                                     "hostap mode (wi_dat_len=%d, "
  674                                     "wi_status=0x%x)\n", sc->sc_dev.dv_xname,
  675                                     rxlen, letoh16(rx_frame.wi_status));
  676                                 m_freem(m);
  677                                 ifp->if_ierrors++;  
  678                                 return;
  679                         }
  680 
  681                         /* Put the whole header in there. */
  682                         bcopy(&rx_frame, mtod(m, void *),
  683                             sizeof(struct wi_frame));
  684                         if (wi_read_data(sc, id, WI_802_11_OFFSET_RAW,
  685                             mtod(m, caddr_t) + WI_802_11_OFFSET_RAW,
  686                             rxlen + 2)) {
  687                                 m_freem(m);
  688                                 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  689                                         printf("wihap: failed to copy header\n");
  690                                 ifp->if_ierrors++;
  691                                 return;
  692                         }
  693 
  694                         m->m_pkthdr.len = m->m_len =
  695                             WI_802_11_OFFSET_RAW + rxlen;
  696 
  697                         /* XXX: consider giving packet to bhp? */
  698 
  699                         wihap_mgmt_input(sc, &rx_frame, m);
  700 
  701                         return;
  702                 }
  703 
  704                 switch (letoh16(rx_frame.wi_status) & WI_RXSTAT_MSG_TYPE) {
  705                 case WI_STAT_1042:
  706                 case WI_STAT_TUNNEL:
  707                 case WI_STAT_WMP_MSG:
  708                         if ((letoh16(rx_frame.wi_dat_len) + WI_SNAPHDR_LEN) >
  709                             maxlen) {
  710                                 printf(WI_PRT_FMT ": oversized packet received "
  711                                     "(wi_dat_len=%d, wi_status=0x%x)\n",
  712                                     WI_PRT_ARG(sc),
  713                                     letoh16(rx_frame.wi_dat_len),
  714                                     letoh16(rx_frame.wi_status));
  715                                 m_freem(m);
  716                                 ifp->if_ierrors++;
  717                                 return;
  718                         }
  719                         m->m_pkthdr.len = m->m_len =
  720                             letoh16(rx_frame.wi_dat_len) + WI_SNAPHDR_LEN;
  721 
  722                         bcopy(&rx_frame.wi_dst_addr,
  723                             &eh->ether_dhost, ETHER_ADDR_LEN);
  724                         bcopy(&rx_frame.wi_src_addr,
  725                             &eh->ether_shost, ETHER_ADDR_LEN);
  726                         bcopy(&rx_frame.wi_type,
  727                             &eh->ether_type, ETHER_TYPE_LEN);
  728 
  729                         if (wi_read_data(sc, id, WI_802_11_OFFSET,
  730                             mtod(m, caddr_t) + sizeof(struct ether_header),
  731                             m->m_len + 2)) {
  732                                 ifp->if_ierrors++;
  733                                 m_freem(m);
  734                                 return;
  735                         }
  736                         break;
  737                 default:
  738                         if ((letoh16(rx_frame.wi_dat_len) +
  739                             sizeof(struct ether_header)) > maxlen) {
  740                                 printf(WI_PRT_FMT ": oversized packet received "
  741                                     "(wi_dat_len=%d, wi_status=0x%x)\n",
  742                                     WI_PRT_ARG(sc),
  743                                     letoh16(rx_frame.wi_dat_len),
  744                                     letoh16(rx_frame.wi_status));
  745                                 m_freem(m);
  746                                 ifp->if_ierrors++;
  747                                 return;
  748                         }
  749                         m->m_pkthdr.len = m->m_len =
  750                             letoh16(rx_frame.wi_dat_len) +
  751                             sizeof(struct ether_header);
  752 
  753                         if (wi_read_data(sc, id, WI_802_3_OFFSET,
  754                             mtod(m, caddr_t), m->m_len + 2)) {
  755                                 m_freem(m);
  756                                 ifp->if_ierrors++;
  757                                 return;
  758                         }
  759                         break;
  760                 }
  761 
  762                 if (sc->wi_use_wep &&
  763                     rx_frame.wi_frame_ctl & htole16(WI_FCTL_WEP)) {
  764                         int len;
  765 
  766                         switch (sc->wi_crypto_algorithm) {
  767                         case WI_CRYPTO_FIRMWARE_WEP:
  768                                 break;
  769                         case WI_CRYPTO_SOFTWARE_WEP:
  770                                 m_copydata(m, 0, m->m_pkthdr.len,
  771                                     sc->wi_rxbuf);
  772                                 len = m->m_pkthdr.len -
  773                                     sizeof(struct ether_header);
  774                                 if (wi_do_hostdecrypt(sc, sc->wi_rxbuf +
  775                                     sizeof(struct ether_header), len)) {
  776                                         if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  777                                                 printf(WI_PRT_FMT ": Error decrypting incoming packet.\n", WI_PRT_ARG(sc));
  778                                         m_freem(m);
  779                                         ifp->if_ierrors++;  
  780                                         return;
  781                                 }
  782                                 len -= IEEE80211_WEP_IVLEN +
  783                                     IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
  784                                 /*
  785                                  * copy data back to mbufs:
  786                                  * we need to ditch the IV & most LLC/SNAP stuff
  787                                  * (except SNAP type, we're going use that to
  788                                  * overwrite the ethertype in the ether_header)
  789                                  */
  790                                 m_copyback(m, sizeof(struct ether_header) -
  791                                     WI_ETHERTYPE_LEN, WI_ETHERTYPE_LEN +
  792                                     (len - WI_SNAPHDR_LEN),
  793                                     sc->wi_rxbuf + sizeof(struct ether_header) +
  794                                     IEEE80211_WEP_IVLEN +
  795                                     IEEE80211_WEP_KIDLEN + WI_SNAPHDR_LEN,
  796                                     M_NOWAIT);
  797                                 m_adj(m, -(WI_ETHERTYPE_LEN +
  798                                     IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
  799                                     WI_SNAPHDR_LEN));
  800                                 break;
  801                         }
  802                 }
  803 
  804                 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
  805                         /*
  806                          * Give host AP code first crack at data packets.
  807                          * If it decides to handle it (or drop it), it will
  808                          * return a non-zero.  Otherwise, it is destined for
  809                          * this host.
  810                          */
  811                         if (wihap_data_input(sc, &rx_frame, m))
  812                                 return;
  813                 }
  814         }
  815 
  816         /* Receive packet unless in procframe or monitor mode. */
  817         if (sc->wi_procframe || sc->wi_debug.wi_monitor)
  818                 m_freem(m);
  819         else {
  820                 ml_enqueue(&ml, m);
  821                 if_input(ifp, &ml);
  822         }
  823 
  824         return;
  825 }
  826 
  827 void
  828 wi_txeof(struct wi_softc *sc, int status)
  829 {
  830         struct ifnet            *ifp;
  831 
  832         ifp = &sc->sc_ic.ic_if;
  833 
  834         ifp->if_timer = 0;
  835         ifq_clr_oactive(&ifp->if_snd);
  836 
  837         if (status & WI_EV_TX_EXC)
  838                 ifp->if_oerrors++;
  839 
  840         return;
  841 }
  842 
  843 void
  844 wi_inquire(void *xsc)
  845 {
  846         struct wi_softc         *sc;
  847         struct ifnet            *ifp;
  848         int s, rv;
  849 
  850         sc = xsc;
  851         ifp = &sc->sc_ic.ic_if;
  852 
  853         timeout_add_sec(&sc->sc_timo, 60);
  854 
  855         /* Don't do this while we're transmitting */
  856         if (ifq_is_oactive(&ifp->if_snd))
  857                 return;
  858 
  859         s = splnet();
  860         rv = wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_COUNTERS, 0, 0);
  861         splx(s);
  862         if (rv)
  863                 printf(WI_PRT_FMT ": wi_cmd failed with %d\n", WI_PRT_ARG(sc),
  864                     rv);
  865 
  866         return;
  867 }
  868 
  869 void
  870 wi_update_stats(struct wi_softc *sc)
  871 {
  872         struct wi_ltv_gen       gen;
  873         u_int16_t               id;
  874         struct ifnet            *ifp;
  875         u_int32_t               *ptr;
  876         int                     len, i;
  877         u_int16_t               t;
  878 
  879         ifp = &sc->sc_ic.ic_if;
  880 
  881         id = wi_get_fid(sc, WI_INFO_FID);
  882 
  883         wi_read_data(sc, id, 0, (char *)&gen, 4);
  884 
  885         if (gen.wi_type == htole16(WI_INFO_SCAN_RESULTS)) {
  886                 sc->wi_scanbuf_len = letoh16(gen.wi_len);
  887                 wi_read_data(sc, id, 4, (caddr_t)sc->wi_scanbuf,
  888                     sc->wi_scanbuf_len * 2);
  889                 return;
  890         } else if (gen.wi_type != htole16(WI_INFO_COUNTERS))
  891                 return;
  892 
  893         /* Some card versions have a larger stats structure */
  894         len = (letoh16(gen.wi_len) - 1 < sizeof(sc->wi_stats) / 4) ?
  895             letoh16(gen.wi_len) - 1 : sizeof(sc->wi_stats) / 4;
  896 
  897         ptr = (u_int32_t *)&sc->wi_stats;
  898 
  899         for (i = 0; i < len; i++) {
  900                 if (sc->wi_flags & WI_FLAGS_BUS_USB) {
  901                         wi_read_data(sc, id, 4 + i*2, (char *)&t, 2);
  902                         t = letoh16(t);
  903                 } else 
  904                         t = CSR_READ_2(sc, WI_DATA1);
  905 #ifdef WI_HERMES_STATS_WAR
  906                 if (t > 0xF000)
  907                         t = ~t & 0xFFFF;
  908 #endif
  909                 ptr[i] += t;
  910         }
  911 
  912         ifp->if_collisions = sc->wi_stats.wi_tx_single_retries +
  913             sc->wi_stats.wi_tx_multi_retries +
  914             sc->wi_stats.wi_tx_retry_limit;
  915 
  916         return;
  917 }
  918 
  919 STATIC int
  920 wi_cmd_io(struct wi_softc *sc, int cmd, int val0, int val1, int val2)
  921 {
  922         int                     i, s = 0;
  923 
  924         /* Wait for the busy bit to clear. */
  925         for (i = sc->wi_cmd_count; i--; DELAY(1000)) {
  926                 if (!(CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY))
  927                         break;
  928         }
  929         if (i < 0) {
  930                 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  931                         printf(WI_PRT_FMT ": wi_cmd_io: busy bit won't clear\n",
  932                             WI_PRT_ARG(sc));
  933                 return(ETIMEDOUT);
  934         }
  935 
  936         CSR_WRITE_2(sc, WI_PARAM0, val0);
  937         CSR_WRITE_2(sc, WI_PARAM1, val1);
  938         CSR_WRITE_2(sc, WI_PARAM2, val2);
  939         CSR_WRITE_2(sc, WI_COMMAND, cmd);
  940 
  941         for (i = WI_TIMEOUT; i--; DELAY(WI_DELAY)) {
  942                 /*
  943                  * Wait for 'command complete' bit to be
  944                  * set in the event status register.
  945                  */
  946                 s = CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_CMD;
  947                 if (s) {
  948                         /* Ack the event and read result code. */
  949                         s = CSR_READ_2(sc, WI_STATUS);
  950                         CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD);
  951                         if (s & WI_STAT_CMD_RESULT)
  952                                 return(EIO);
  953                         break;
  954                 }
  955         }
  956 
  957         if (i < 0) {
  958                 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  959                         printf(WI_PRT_FMT
  960                             ": timeout in wi_cmd 0x%04x; event status 0x%04x\n",
  961                             WI_PRT_ARG(sc), cmd, s);
  962                 return(ETIMEDOUT);
  963         }
  964 
  965         return(0);
  966 }
  967 
  968 STATIC void
  969 wi_reset(struct wi_softc *sc)
  970 {
  971         int error, tries = 3;
  972 
  973         DPRINTF(WID_RESET, ("wi_reset: sc %p\n", sc));
  974 
  975         /* Symbol firmware cannot be initialized more than once. */
  976         if (sc->sc_firmware_type == WI_SYMBOL) {
  977                 if (sc->wi_flags & WI_FLAGS_INITIALIZED)
  978                         return;
  979                 tries = 1;
  980         }
  981 
  982         for (; tries--; DELAY(WI_DELAY * 1000)) {
  983                 if ((error = wi_cmd(sc, WI_CMD_INI, 0, 0, 0)) == 0)
  984                         break;
  985         }
  986         if (tries < 0) {
  987                 printf(WI_PRT_FMT ": init failed\n", WI_PRT_ARG(sc));
  988                 return;
  989         }
  990         sc->wi_flags |= WI_FLAGS_INITIALIZED;
  991 
  992         wi_intr_enable(sc, 0);
  993         wi_intr_ack(sc, 0xffff);
  994 
  995         /* Calibrate timer. */
  996         WI_SETVAL(WI_RID_TICK_TIME, 8);
  997 
  998         return;
  999 }
 1000 
 1001 STATIC void
 1002 wi_cor_reset(struct wi_softc *sc)
 1003 {
 1004         u_int8_t cor_value;
 1005 
 1006         DPRINTF(WID_RESET, ("wi_cor_reset: sc %p\n", sc));
 1007 
 1008         /*
 1009          * Do a soft reset of the card; this is required for Symbol cards.
 1010          * This shouldn't hurt other cards but there have been reports
 1011          * of the COR reset messing up old Lucent firmware revisions so
 1012          * we avoid soft reset on Lucent cards for now.
 1013          */
 1014         if (sc->sc_firmware_type != WI_LUCENT) {
 1015                 cor_value = bus_space_read_1(sc->wi_ltag, sc->wi_lhandle,
 1016                     sc->wi_cor_offset);
 1017                 bus_space_write_1(sc->wi_ltag, sc->wi_lhandle,
 1018                     sc->wi_cor_offset, (cor_value | WI_COR_SOFT_RESET));
 1019                 DELAY(1000);
 1020                 bus_space_write_1(sc->wi_ltag, sc->wi_lhandle,
 1021                     sc->wi_cor_offset, (cor_value & ~WI_COR_SOFT_RESET));
 1022                 DELAY(1000);
 1023         }
 1024 
 1025         return;
 1026 }
 1027 
 1028 /*
 1029  * Read an LTV record from the NIC.
 1030  */
 1031 STATIC int
 1032 wi_read_record_io(struct wi_softc *sc, struct wi_ltv_gen *ltv)
 1033 {
 1034         u_int8_t                *ptr;
 1035         int                     len, code;
 1036         struct wi_ltv_gen       *oltv, p2ltv;
 1037 
 1038         if (sc->sc_firmware_type != WI_LUCENT) {
 1039                 oltv = ltv;
 1040                 switch (ltv->wi_type) {
 1041                 case WI_RID_ENCRYPTION:
 1042                         p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
 1043                         p2ltv.wi_len = 2;
 1044                         ltv = &p2ltv;
 1045                         break;
 1046                 case WI_RID_TX_CRYPT_KEY:
 1047                         if (ltv->wi_val > WI_NLTV_KEYS)
 1048                                 return (EINVAL);
 1049                         p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
 1050                         p2ltv.wi_len = 2;
 1051                         ltv = &p2ltv;
 1052                         break;
 1053                 }
 1054         }
 1055 
 1056         /* Tell the NIC to enter record read mode. */
 1057         if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_READ, ltv->wi_type, 0, 0))
 1058                 return(EIO);
 1059 
 1060         /* Seek to the record. */
 1061         if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1))
 1062                 return(EIO);
 1063 
 1064         /*
 1065          * Read the length and record type and make sure they
 1066          * match what we expect (this verifies that we have enough
 1067          * room to hold all of the returned data).
 1068          */
 1069         len = CSR_READ_2(sc, WI_DATA1);
 1070         if (len > ltv->wi_len)
 1071                 return(ENOSPC);
 1072         code = CSR_READ_2(sc, WI_DATA1);
 1073         if (code != ltv->wi_type)
 1074                 return(EIO);
 1075 
 1076         ltv->wi_len = len;
 1077         ltv->wi_type = code;
 1078 
 1079         /* Now read the data. */
 1080         ptr = (u_int8_t *)&ltv->wi_val;
 1081         if (ltv->wi_len > 1)
 1082                 CSR_READ_RAW_2(sc, WI_DATA1, ptr, (ltv->wi_len-1)*2);
 1083 
 1084         if (ltv->wi_type == WI_RID_PORTTYPE && sc->wi_ptype == WI_PORTTYPE_IBSS
 1085             && ltv->wi_val == sc->wi_ibss_port) {
 1086                 /*
 1087                  * Convert vendor IBSS port type to WI_PORTTYPE_IBSS.
 1088                  * Since Lucent uses port type 1 for BSS *and* IBSS we
 1089                  * have to rely on wi_ptype to distinguish this for us.
 1090                  */
 1091                 ltv->wi_val = htole16(WI_PORTTYPE_IBSS);
 1092         } else if (sc->sc_firmware_type != WI_LUCENT) {
 1093                 int v;
 1094 
 1095                 switch (oltv->wi_type) {
 1096                 case WI_RID_TX_RATE:
 1097                 case WI_RID_CUR_TX_RATE:
 1098                         switch (letoh16(ltv->wi_val)) {
 1099                         case 1: v = 1; break;
 1100                         case 2: v = 2; break;
 1101                         case 3: v = 6; break;
 1102                         case 4: v = 5; break;
 1103                         case 7: v = 7; break;
 1104                         case 8: v = 11; break;
 1105                         case 15: v = 3; break;
 1106                         default: v = 0x100 + letoh16(ltv->wi_val); break;
 1107                         }
 1108                         oltv->wi_val = htole16(v);
 1109                         break;
 1110                 case WI_RID_ENCRYPTION:
 1111                         oltv->wi_len = 2;
 1112                         if (ltv->wi_val & htole16(0x01))
 1113                                 oltv->wi_val = htole16(1);
 1114                         else
 1115                                 oltv->wi_val = htole16(0);
 1116                         break;
 1117                 case WI_RID_TX_CRYPT_KEY:
 1118                 case WI_RID_CNFAUTHMODE:
 1119                         oltv->wi_len = 2;
 1120                         oltv->wi_val = ltv->wi_val;
 1121                         break;
 1122                 }
 1123         }
 1124 
 1125         return(0);
 1126 }
 1127 
 1128 /*
 1129  * Same as read, except we inject data instead of reading it.
 1130  */
 1131 STATIC int
 1132 wi_write_record_io(struct wi_softc *sc, struct wi_ltv_gen *ltv)
 1133 {
 1134         u_int8_t                *ptr;
 1135         u_int16_t               val = 0;
 1136         int                     i;
 1137         struct wi_ltv_gen       p2ltv;
 1138 
 1139         if (ltv->wi_type == WI_RID_PORTTYPE &&
 1140             letoh16(ltv->wi_val) == WI_PORTTYPE_IBSS) {
 1141                 /* Convert WI_PORTTYPE_IBSS to vendor IBSS port type. */
 1142                 p2ltv.wi_type = WI_RID_PORTTYPE;
 1143                 p2ltv.wi_len = 2;
 1144                 p2ltv.wi_val = sc->wi_ibss_port;
 1145                 ltv = &p2ltv;
 1146         } else if (sc->sc_firmware_type != WI_LUCENT) {
 1147                 int v;
 1148 
 1149                 switch (ltv->wi_type) {
 1150                 case WI_RID_TX_RATE:
 1151                         p2ltv.wi_type = WI_RID_TX_RATE;
 1152                         p2ltv.wi_len = 2;
 1153                         switch (letoh16(ltv->wi_val)) {
 1154                         case 1: v = 1; break;
 1155                         case 2: v = 2; break;
 1156                         case 3: v = 15; break;
 1157                         case 5: v = 4; break;
 1158                         case 6: v = 3; break;
 1159                         case 7: v = 7; break;
 1160                         case 11: v = 8; break;
 1161                         default: return EINVAL;
 1162                         }
 1163                         p2ltv.wi_val = htole16(v);
 1164                         ltv = &p2ltv;
 1165                         break;
 1166                 case WI_RID_ENCRYPTION:
 1167                         p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
 1168                         p2ltv.wi_len = 2;
 1169                         if (ltv->wi_val & htole16(0x01)) {
 1170                                 val = PRIVACY_INVOKED;
 1171                                 /*
 1172                                  * If using shared key WEP we must set the
 1173                                  * EXCLUDE_UNENCRYPTED bit.  Symbol cards
 1174                                  * need this bit set even when not using
 1175                                  * shared key. We can't just test for
 1176                                  * IEEE80211_AUTH_SHARED since Symbol cards
 1177                                  * have 2 shared key modes.
 1178                                  */
 1179                                 if (sc->wi_authtype != IEEE80211_AUTH_OPEN ||
 1180                                     sc->sc_firmware_type == WI_SYMBOL)
 1181                                         val |= EXCLUDE_UNENCRYPTED;
 1182 
 1183                                 switch (sc->wi_crypto_algorithm) {
 1184                                 case WI_CRYPTO_FIRMWARE_WEP:
 1185                                         /*
 1186                                          * TX encryption is broken in
 1187                                          * Host AP mode.
 1188                                          */
 1189                                         if (sc->wi_ptype == WI_PORTTYPE_HOSTAP)
 1190                                                 val |= HOST_ENCRYPT;
 1191                                         break;
 1192                                 case WI_CRYPTO_SOFTWARE_WEP:
 1193                                         val |= HOST_ENCRYPT|HOST_DECRYPT;
 1194                                         break;
 1195                                 }
 1196                                 p2ltv.wi_val = htole16(val);
 1197                         } else
 1198                                 p2ltv.wi_val = htole16(HOST_ENCRYPT | HOST_DECRYPT);
 1199                         ltv = &p2ltv;
 1200                         break;
 1201                 case WI_RID_TX_CRYPT_KEY:
 1202                         if (ltv->wi_val > WI_NLTV_KEYS)
 1203                                 return (EINVAL);
 1204                         p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
 1205                         p2ltv.wi_len = 2;
 1206                         p2ltv.wi_val = ltv->wi_val;
 1207                         ltv = &p2ltv;
 1208                         break;
 1209                 case WI_RID_DEFLT_CRYPT_KEYS: {
 1210                                 int error;
 1211                                 int keylen;
 1212                                 struct wi_ltv_str ws;
 1213                                 struct wi_ltv_keys *wk = (struct wi_ltv_keys *)ltv;
 1214 
 1215                                 keylen = wk->wi_keys[sc->wi_tx_key].wi_keylen;
 1216                                 keylen = letoh16(keylen);
 1217 
 1218                                 for (i = 0; i < 4; i++) {
 1219                                         bzero(&ws, sizeof(ws));
 1220                                         ws.wi_len = (keylen > 5) ? 8 : 4;
 1221                                         ws.wi_type = WI_RID_P2_CRYPT_KEY0 + i;
 1222                                         bcopy(&wk->wi_keys[i].wi_keydat,
 1223                                             ws.wi_str, keylen);
 1224                                         error = wi_write_record(sc,
 1225                                             (struct wi_ltv_gen *)&ws);
 1226                                         if (error)
 1227                                                 return (error);
 1228                                 }
 1229                         }
 1230                         return (0);
 1231                 }
 1232         }
 1233 
 1234         if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1))
 1235                 return(EIO);
 1236 
 1237         CSR_WRITE_2(sc, WI_DATA1, ltv->wi_len);
 1238         CSR_WRITE_2(sc, WI_DATA1, ltv->wi_type);
 1239 
 1240         ptr = (u_int8_t *)&ltv->wi_val;
 1241         if (ltv->wi_len > 1)
 1242                 CSR_WRITE_RAW_2(sc, WI_DATA1, ptr, (ltv->wi_len-1) *2);
 1243 
 1244         if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_WRITE, ltv->wi_type, 0, 0))
 1245                 return(EIO);
 1246 
 1247         return(0);
 1248 }
 1249 
 1250 STATIC int
 1251 wi_seek(struct wi_softc *sc, int id, int off, int chan)
 1252 {
 1253         int                     i;
 1254         int                     selreg, offreg;
 1255 
 1256         switch (chan) {
 1257         case WI_BAP0:
 1258                 selreg = WI_SEL0;
 1259                 offreg = WI_OFF0;
 1260                 break;
 1261         case WI_BAP1:
 1262                 selreg = WI_SEL1;
 1263                 offreg = WI_OFF1;
 1264                 break;
 1265         default:
 1266                 printf(WI_PRT_FMT ": invalid data path: %x\n", WI_PRT_ARG(sc),
 1267                     chan);
 1268                 return(EIO);
 1269         }
 1270 
 1271         CSR_WRITE_2(sc, selreg, id);
 1272         CSR_WRITE_2(sc, offreg, off);
 1273 
 1274         for (i = WI_TIMEOUT; i--; DELAY(1))
 1275                 if (!(CSR_READ_2(sc, offreg) & (WI_OFF_BUSY|WI_OFF_ERR)))
 1276                         break;
 1277 
 1278         if (i < 0)
 1279                 return(ETIMEDOUT);
 1280 
 1281         return(0);
 1282 }
 1283 
 1284 STATIC int
 1285 wi_read_data_io(struct wi_softc *sc, int id, int off, caddr_t buf, int len)
 1286 {
 1287         u_int8_t                *ptr;
 1288 
 1289         if (wi_seek(sc, id, off, WI_BAP1))
 1290                 return(EIO);
 1291 
 1292         ptr = (u_int8_t *)buf;
 1293         CSR_READ_RAW_2(sc, WI_DATA1, ptr, len);
 1294 
 1295         return(0);
 1296 }
 1297 
 1298 /*
 1299  * According to the comments in the HCF Light code, there is a bug in
 1300  * the Hermes (or possibly in certain Hermes firmware revisions) where
 1301  * the chip's internal autoincrement counter gets thrown off during
 1302  * data writes: the autoincrement is missed, causing one data word to
 1303  * be overwritten and subsequent words to be written to the wrong memory
 1304  * locations. The end result is that we could end up transmitting bogus
 1305  * frames without realizing it. The workaround for this is to write a
 1306  * couple of extra guard words after the end of the transfer, then
 1307  * attempt to read then back. If we fail to locate the guard words where
 1308  * we expect them, we preform the transfer over again.
 1309  */
 1310 STATIC int
 1311 wi_write_data_io(struct wi_softc *sc, int id, int off, caddr_t buf, int len)
 1312 {
 1313         u_int8_t                *ptr;
 1314 
 1315 #ifdef WI_HERMES_AUTOINC_WAR
 1316 again:
 1317 #endif
 1318 
 1319         if (wi_seek(sc, id, off, WI_BAP0))
 1320                 return(EIO);
 1321 
 1322         ptr = (u_int8_t *)buf;
 1323         CSR_WRITE_RAW_2(sc, WI_DATA0, ptr, len);
 1324 
 1325 #ifdef WI_HERMES_AUTOINC_WAR
 1326         CSR_WRITE_2(sc, WI_DATA0, 0x1234);
 1327         CSR_WRITE_2(sc, WI_DATA0, 0x5678);
 1328 
 1329         if (wi_seek(sc, id, off + len, WI_BAP0))
 1330                 return(EIO);
 1331 
 1332         if (CSR_READ_2(sc, WI_DATA0) != 0x1234 ||
 1333             CSR_READ_2(sc, WI_DATA0) != 0x5678)
 1334                 goto again;
 1335 #endif
 1336 
 1337         return(0);
 1338 }
 1339 
 1340 /*
 1341  * Allocate a region of memory inside the NIC and zero
 1342  * it out.
 1343  */
 1344 STATIC int
 1345 wi_alloc_nicmem_io(struct wi_softc *sc, int len, int *id)
 1346 {
 1347         int                     i;
 1348 
 1349         if (wi_cmd(sc, WI_CMD_ALLOC_MEM, len, 0, 0)) {
 1350                 printf(WI_PRT_FMT ": failed to allocate %d bytes on NIC\n",
 1351                     WI_PRT_ARG(sc), len);
 1352                 return(ENOMEM);
 1353         }
 1354 
 1355         for (i = WI_TIMEOUT; i--; DELAY(1)) {
 1356                 if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_ALLOC)
 1357                         break;
 1358         }
 1359 
 1360         if (i < 0)
 1361                 return(ETIMEDOUT);
 1362 
 1363         *id = CSR_READ_2(sc, WI_ALLOC_FID);
 1364         CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
 1365 
 1366         if (wi_seek(sc, *id, 0, WI_BAP0))
 1367                 return(EIO);
 1368 
 1369         for (i = 0; i < len / 2; i++)
 1370                 CSR_WRITE_2(sc, WI_DATA0, 0);
 1371 
 1372         return(0);
 1373 }
 1374 
 1375 STATIC void
 1376 wi_setmulti(struct wi_softc *sc)
 1377 {
 1378         struct arpcom           *ac = &sc->sc_ic.ic_ac;
 1379         struct ifnet            *ifp;
 1380         int                     i = 0;
 1381         struct wi_ltv_mcast     mcast;
 1382         struct ether_multistep  step;
 1383         struct ether_multi      *enm;
 1384 
 1385         ifp = &sc->sc_ic.ic_if;
 1386 
 1387         bzero(&mcast, sizeof(mcast));
 1388 
 1389         mcast.wi_type = WI_RID_MCAST_LIST;
 1390         mcast.wi_len = ((ETHER_ADDR_LEN / 2) * 16) + 1;
 1391 
 1392         if (ac->ac_multirangecnt > 0)
 1393                 ifp->if_flags |= IFF_ALLMULTI;
 1394 
 1395         if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
 1396                 wi_write_record(sc, (struct wi_ltv_gen *)&mcast);
 1397                 return;
 1398         }
 1399 
 1400         ETHER_FIRST_MULTI(step, &sc->sc_ic.ic_ac, enm);
 1401         while (enm != NULL) {
 1402                 if (i >= 16) {
 1403                         bzero(&mcast, sizeof(mcast));
 1404                         break;
 1405                 }
 1406 
 1407                 bcopy(enm->enm_addrlo, &mcast.wi_mcast[i], ETHER_ADDR_LEN);
 1408                 i++;
 1409                 ETHER_NEXT_MULTI(step, enm);
 1410         }
 1411 
 1412         mcast.wi_len = (i * 3) + 1;
 1413         wi_write_record(sc, (struct wi_ltv_gen *)&mcast);
 1414 
 1415         return;
 1416 }
 1417 
 1418 STATIC int
 1419 wi_setdef(struct wi_softc *sc, struct wi_req *wreq)
 1420 {
 1421         struct ifnet            *ifp;
 1422         int error = 0;
 1423 
 1424         ifp = &sc->sc_ic.ic_if;
 1425 
 1426         switch(wreq->wi_type) {
 1427         case WI_RID_MAC_NODE:
 1428                 bcopy(&wreq->wi_val, LLADDR(ifp->if_sadl), ETHER_ADDR_LEN);
 1429                 bcopy(&wreq->wi_val, &sc->sc_ic.ic_myaddr, ETHER_ADDR_LEN);
 1430                 break;
 1431         case WI_RID_PORTTYPE:
 1432                 error = wi_sync_media(sc, letoh16(wreq->wi_val[0]),
 1433                     sc->wi_tx_rate);
 1434                 break;
 1435         case WI_RID_TX_RATE:
 1436                 error = wi_sync_media(sc, sc->wi_ptype,
 1437                     letoh16(wreq->wi_val[0]));
 1438                 break;
 1439         case WI_RID_MAX_DATALEN:
 1440                 sc->wi_max_data_len = letoh16(wreq->wi_val[0]);
 1441                 break;
 1442         case WI_RID_RTS_THRESH:
 1443                 sc->wi_rts_thresh = letoh16(wreq->wi_val[0]);
 1444                 break;
 1445         case WI_RID_SYSTEM_SCALE:
 1446                 sc->wi_ap_density = letoh16(wreq->wi_val[0]);
 1447                 break;
 1448         case WI_RID_CREATE_IBSS:
 1449                 sc->wi_create_ibss = letoh16(wreq->wi_val[0]);
 1450                 error = wi_sync_media(sc, sc->wi_ptype, sc->wi_tx_rate);
 1451                 break;
 1452         case WI_RID_OWN_CHNL:
 1453                 sc->wi_channel = letoh16(wreq->wi_val[0]);
 1454                 break;
 1455         case WI_RID_NODENAME:
 1456                 error = wi_set_ssid(&sc->wi_node_name,
 1457                     (u_int8_t *)&wreq->wi_val[1], letoh16(wreq->wi_val[0]));
 1458                 break;
 1459         case WI_RID_DESIRED_SSID:
 1460                 error = wi_set_ssid(&sc->wi_net_name,
 1461                     (u_int8_t *)&wreq->wi_val[1], letoh16(wreq->wi_val[0]));
 1462                 break;
 1463         case WI_RID_OWN_SSID:
 1464                 error = wi_set_ssid(&sc->wi_ibss_name,
 1465                     (u_int8_t *)&wreq->wi_val[1], letoh16(wreq->wi_val[0]));
 1466                 break;
 1467         case WI_RID_PM_ENABLED:
 1468                 sc->wi_pm_enabled = letoh16(wreq->wi_val[0]);
 1469                 break;
 1470         case WI_RID_MICROWAVE_OVEN:
 1471                 sc->wi_mor_enabled = letoh16(wreq->wi_val[0]);
 1472                 break;
 1473         case WI_RID_MAX_SLEEP:
 1474                 sc->wi_max_sleep = letoh16(wreq->wi_val[0]);
 1475                 break;
 1476         case WI_RID_CNFAUTHMODE:
 1477                 sc->wi_authtype = letoh16(wreq->wi_val[0]);
 1478                 break;
 1479         case WI_RID_ROAMING_MODE:
 1480                 sc->wi_roaming = letoh16(wreq->wi_val[0]);
 1481                 break;
 1482         case WI_RID_SYMBOL_DIVERSITY:
 1483                 sc->wi_diversity = letoh16(wreq->wi_val[0]);
 1484                 break;
 1485         case WI_RID_ENH_SECURITY:
 1486                 sc->wi_enh_security = letoh16(wreq->wi_val[0]);
 1487                 break;
 1488         case WI_RID_ENCRYPTION:
 1489                 sc->wi_use_wep = letoh16(wreq->wi_val[0]);
 1490                 break;
 1491         case WI_RID_TX_CRYPT_KEY:
 1492                 sc->wi_tx_key = letoh16(wreq->wi_val[0]);
 1493                 break;
 1494         case WI_RID_DEFLT_CRYPT_KEYS:
 1495                 bcopy(wreq, &sc->wi_keys, sizeof(struct wi_ltv_keys));
 1496                 break;
 1497         case WI_FRID_CRYPTO_ALG:
 1498                 switch (letoh16(wreq->wi_val[0])) {
 1499                 case WI_CRYPTO_FIRMWARE_WEP:
 1500                         sc->wi_crypto_algorithm = WI_CRYPTO_FIRMWARE_WEP;
 1501                         break;
 1502                 case WI_CRYPTO_SOFTWARE_WEP:
 1503                         sc->wi_crypto_algorithm = WI_CRYPTO_SOFTWARE_WEP;
 1504                         break;
 1505                 default:
 1506                         printf(WI_PRT_FMT ": unsupported crypto algorithm %d\n",
 1507                             WI_PRT_ARG(sc), letoh16(wreq->wi_val[0]));
 1508                         error = EINVAL;
 1509                 }
 1510                 break;
 1511         default:
 1512                 error = EINVAL;
 1513                 break;
 1514         }
 1515 
 1516         return (error);
 1517 }
 1518 
 1519 STATIC int
 1520 wi_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
 1521 {
 1522         int                     s, error = 0, i, j, len;
 1523         struct wi_softc         *sc = ifp->if_softc;
 1524         struct ifreq            *ifr = (struct ifreq *)data;
 1525         struct proc             *p = curproc;
 1526         struct wi_scan_res      *res;
 1527         struct wi_scan_p2_hdr   *p2;
 1528         struct wi_req           *wreq = NULL;
 1529         u_int32_t               flags;
 1530         struct ieee80211_nwid           *nwidp = NULL;
 1531         struct ieee80211_nodereq_all    *na;
 1532         struct ieee80211_bssid          *bssid;
 1533 
 1534         s = splnet();
 1535         if (!(sc->wi_flags & WI_FLAGS_ATTACHED)) {
 1536                 error = ENODEV;
 1537                 goto fail;
 1538         }
 1539 
 1540         /*
 1541          * Prevent processes from entering this function while another
 1542          * process is tsleep'ing in it.
 1543          */
 1544         while ((sc->wi_flags & WI_FLAGS_BUSY) && error == 0)
 1545                 error = tsleep_nsec(&sc->wi_flags, PCATCH, "wiioc", INFSLP);
 1546         if (error != 0) {
 1547                 splx(s);
 1548                 return error;
 1549         }
 1550         sc->wi_flags |= WI_FLAGS_BUSY;
 1551 
 1552 
 1553         DPRINTF (WID_IOCTL, ("wi_ioctl: command %lu data %p\n",
 1554             command, data));
 1555 
 1556         switch(command) {
 1557         case SIOCSIFADDR:
 1558                 ifp->if_flags |= IFF_UP;
 1559                 wi_init(sc);
 1560                 break;
 1561         case SIOCSIFFLAGS:
 1562                 if (ifp->if_flags & IFF_UP) {
 1563                         if (ifp->if_flags & IFF_RUNNING &&
 1564                             ifp->if_flags & IFF_PROMISC &&
 1565                             !(sc->wi_if_flags & IFF_PROMISC)) {
 1566                                 if (sc->wi_ptype != WI_PORTTYPE_HOSTAP)
 1567                                         WI_SETVAL(WI_RID_PROMISC, 1);
 1568                         } else if (ifp->if_flags & IFF_RUNNING &&
 1569                             !(ifp->if_flags & IFF_PROMISC) &&
 1570                             sc->wi_if_flags & IFF_PROMISC) {
 1571                                 if (sc->wi_ptype != WI_PORTTYPE_HOSTAP)
 1572                                         WI_SETVAL(WI_RID_PROMISC, 0);
 1573                         } else
 1574                                 wi_init(sc);
 1575                 } else if (ifp->if_flags & IFF_RUNNING)
 1576                         wi_stop(sc);
 1577                 sc->wi_if_flags = ifp->if_flags;
 1578                 error = 0;
 1579                 break;
 1580         case SIOCSIFMEDIA:
 1581         case SIOCGIFMEDIA:
 1582                 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command);
 1583                 break;
 1584         case SIOCGWAVELAN:
 1585                 wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK | M_ZERO);
 1586                 error = copyin(ifr->ifr_data, wreq, sizeof(*wreq));
 1587                 if (error)
 1588                         break;
 1589                 if (wreq->wi_len > WI_MAX_DATALEN) {
 1590                         error = EINVAL;
 1591                         break;
 1592                 }
 1593                 switch (wreq->wi_type) {
 1594                 case WI_RID_IFACE_STATS:
 1595                         /* XXX native byte order */
 1596                         bcopy(&sc->wi_stats, &wreq->wi_val,
 1597                             sizeof(sc->wi_stats));
 1598                         wreq->wi_len = (sizeof(sc->wi_stats) / 2) + 1;
 1599                         break;
 1600                 case WI_RID_DEFLT_CRYPT_KEYS:
 1601                         /* For non-root user, return all-zeroes keys */
 1602                         if (suser(p))
 1603                                 bzero(wreq, sizeof(struct wi_ltv_keys));
 1604                         else
 1605                                 bcopy(&sc->wi_keys, wreq,
 1606                                         sizeof(struct wi_ltv_keys));
 1607                         break;
 1608                 case WI_RID_PROCFRAME:
 1609                         wreq->wi_len = 2;
 1610                         wreq->wi_val[0] = htole16(sc->wi_procframe);
 1611                         break;
 1612                 case WI_RID_PRISM2:
 1613                         wreq->wi_len = 2;
 1614                         wreq->wi_val[0] = htole16(sc->sc_firmware_type ==
 1615                             WI_LUCENT ? 0 : 1);
 1616                         break;
 1617                 case WI_FRID_CRYPTO_ALG:
 1618                         wreq->wi_val[0] =
 1619                             htole16((u_int16_t)sc->wi_crypto_algorithm);
 1620                         wreq->wi_len = 1;
 1621                         break;
 1622                 case WI_RID_SCAN_RES:
 1623                         if (sc->sc_firmware_type == WI_LUCENT) {
 1624                                 memcpy((char *)wreq->wi_val,
 1625                                     (char *)sc->wi_scanbuf,
 1626                                     sc->wi_scanbuf_len * 2);
 1627                                 wreq->wi_len = sc->wi_scanbuf_len;
 1628                                 break;
 1629                         }
 1630                         /* FALLTHROUGH */
 1631                 default:
 1632                         if (wi_read_record(sc, (struct wi_ltv_gen *)wreq)) {
 1633                                 error = EINVAL;
 1634                         }
 1635                         break;
 1636                 }
 1637                 error = copyout(wreq, ifr->ifr_data, sizeof(*wreq));
 1638                 break;
 1639         case SIOCSWAVELAN:
 1640                 if ((error = suser(curproc)) != 0)
 1641                         break;
 1642                 wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK | M_ZERO);
 1643                 error = copyin(ifr->ifr_data, wreq, sizeof(*wreq));
 1644                 if (error)
 1645                         break;
 1646                 error = EINVAL;
 1647                 if (wreq->wi_len > WI_MAX_DATALEN)
 1648                         break;
 1649                 switch (wreq->wi_type) {
 1650                 case WI_RID_IFACE_STATS:
 1651                         break;
 1652                 case WI_RID_MGMT_XMIT:
 1653                         error = wi_mgmt_xmit(sc, (caddr_t)&wreq->wi_val,
 1654                             wreq->wi_len);
 1655                         break;
 1656                 case WI_RID_PROCFRAME:
 1657                         sc->wi_procframe = letoh16(wreq->wi_val[0]);
 1658                         error = 0;
 1659                         break;
 1660                 case WI_RID_SCAN_REQ:
 1661                         error = 0;
 1662                         if (sc->sc_firmware_type == WI_LUCENT)
 1663                                 wi_cmd(sc, WI_CMD_INQUIRE,
 1664                                     WI_INFO_SCAN_RESULTS, 0, 0);
 1665                         else
 1666                                 error = wi_write_record(sc,
 1667                                     (struct wi_ltv_gen *)wreq);
 1668                         break;
 1669                 case WI_FRID_CRYPTO_ALG:
 1670                         if (sc->sc_firmware_type != WI_LUCENT) {
 1671                                 error = wi_setdef(sc, wreq);
 1672                                 if (!error && (ifp->if_flags & IFF_UP))
 1673                                         wi_init(sc);
 1674                         }
 1675                         break;
 1676                 case WI_RID_SYMBOL_DIVERSITY:
 1677                 case WI_RID_ROAMING_MODE:
 1678                 case WI_RID_CREATE_IBSS:
 1679                 case WI_RID_MICROWAVE_OVEN:
 1680                 case WI_RID_OWN_SSID:
 1681                 case WI_RID_ENH_SECURITY:
 1682                         /*
 1683                          * Check for features that may not be supported
 1684                          * (must be just before default case).
 1685                          */
 1686                         if ((wreq->wi_type == WI_RID_SYMBOL_DIVERSITY &&
 1687                             !(sc->wi_flags & WI_FLAGS_HAS_DIVERSITY)) ||
 1688                             (wreq->wi_type == WI_RID_ROAMING_MODE &&
 1689                             !(sc->wi_flags & WI_FLAGS_HAS_ROAMING)) ||
 1690                             (wreq->wi_type == WI_RID_CREATE_IBSS &&
 1691                             !(sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)) ||
 1692                             (wreq->wi_type == WI_RID_MICROWAVE_OVEN &&
 1693                             !(sc->wi_flags & WI_FLAGS_HAS_MOR)) ||
 1694                             (wreq->wi_type == WI_RID_ENH_SECURITY &&
 1695                             !(sc->wi_flags & WI_FLAGS_HAS_ENH_SECURITY)) ||
 1696                             (wreq->wi_type == WI_RID_OWN_SSID &&
 1697                             wreq->wi_len != 0))
 1698                                 break;
 1699                         /* FALLTHROUGH */
 1700                 default:
 1701                         error = wi_write_record(sc, (struct wi_ltv_gen *)wreq);
 1702                         if (!error)
 1703                                 error = wi_setdef(sc, wreq);
 1704                         if (!error && (ifp->if_flags & IFF_UP))
 1705                                 wi_init(sc);
 1706                 }
 1707                 break;
 1708         case SIOCGPRISM2DEBUG:
 1709                 wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK | M_ZERO);
 1710                 error = copyin(ifr->ifr_data, wreq, sizeof(*wreq));
 1711                 if (error)
 1712                         break;
 1713                 if (!(ifp->if_flags & IFF_RUNNING) ||
 1714                     sc->sc_firmware_type == WI_LUCENT) {
 1715                         error = EIO;
 1716                         break;
 1717                 }
 1718                 error = wi_get_debug(sc, wreq);
 1719                 if (error == 0)
 1720                         error = copyout(wreq, ifr->ifr_data, sizeof(*wreq));
 1721                 break;
 1722         case SIOCSPRISM2DEBUG:
 1723                 if ((error = suser(curproc)) != 0)
 1724                         break;
 1725                 wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK | M_ZERO);
 1726                 error = copyin(ifr->ifr_data, wreq, sizeof(*wreq));
 1727                 if (error)
 1728                         break;
 1729                 error = wi_set_debug(sc, wreq);
 1730                 break;
 1731         case SIOCG80211NWID:
 1732                 if ((ifp->if_flags & IFF_UP) && sc->wi_net_name.i_len > 0) {
 1733                         /* Return the desired ID */
 1734                         error = copyout(&sc->wi_net_name, ifr->ifr_data,
 1735                             sizeof(sc->wi_net_name));
 1736                 } else {
 1737                         wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK|M_ZERO);
 1738                         wreq->wi_type = WI_RID_CURRENT_SSID;
 1739                         wreq->wi_len = WI_MAX_DATALEN;
 1740                         if (wi_read_record(sc, (struct wi_ltv_gen *)wreq) ||
 1741                             letoh16(wreq->wi_val[0]) > IEEE80211_NWID_LEN)
 1742                                 error = EINVAL;
 1743                         else {
 1744                                 nwidp = malloc(sizeof *nwidp, M_DEVBUF,
 1745                                     M_WAITOK | M_ZERO);
 1746                                 wi_set_ssid(nwidp, (u_int8_t *)&wreq->wi_val[1],
 1747                                     letoh16(wreq->wi_val[0]));
 1748                                 error = copyout(nwidp, ifr->ifr_data,
 1749                                     sizeof(*nwidp));
 1750                         }
 1751                 }
 1752                 break;
 1753         case SIOCS80211NWID:
 1754                 if ((error = suser(curproc)) != 0)
 1755                         break;
 1756                 nwidp = malloc(sizeof *nwidp, M_DEVBUF, M_WAITOK);
 1757                 error = copyin(ifr->ifr_data, nwidp, sizeof(*nwidp));
 1758                 if (error)
 1759                         break;
 1760                 if (nwidp->i_len > IEEE80211_NWID_LEN) {
 1761                         error = EINVAL;
 1762                         break;
 1763                 }
 1764                 if (sc->wi_net_name.i_len == nwidp->i_len &&
 1765                     memcmp(sc->wi_net_name.i_nwid, nwidp->i_nwid, nwidp->i_len) == 0)
 1766                         break;
 1767                 wi_set_ssid(&sc->wi_net_name, nwidp->i_nwid, nwidp->i_len);
 1768                 WI_SETSTR(WI_RID_DESIRED_SSID, sc->wi_net_name);
 1769                 if (ifp->if_flags & IFF_UP)
 1770                         /* Reinitialize WaveLAN. */
 1771                         wi_init(sc);
 1772                 break;
 1773         case SIOCS80211NWKEY:
 1774                 if ((error = suser(curproc)) != 0)
 1775                         break;
 1776                 error = wi_set_nwkey(sc, (struct ieee80211_nwkey *)data);
 1777                 break;
 1778         case SIOCG80211NWKEY:
 1779                 error = wi_get_nwkey(sc, (struct ieee80211_nwkey *)data);
 1780                 break;
 1781         case SIOCS80211POWER:
 1782                 if ((error = suser(curproc)) != 0)
 1783                         break;
 1784                 error = wi_set_pm(sc, (struct ieee80211_power *)data);
 1785                 break;
 1786         case SIOCG80211POWER:
 1787                 error = wi_get_pm(sc, (struct ieee80211_power *)data);
 1788                 break;
 1789         case SIOCS80211TXPOWER:
 1790                 if ((error = suser(curproc)) != 0)
 1791                         break;
 1792                 error = wi_set_txpower(sc, (struct ieee80211_txpower *)data);
 1793                 break;
 1794         case SIOCG80211TXPOWER:
 1795                 error = wi_get_txpower(sc, (struct ieee80211_txpower *)data);
 1796                 break;
 1797         case SIOCS80211CHANNEL:
 1798                 if ((error = suser(curproc)) != 0)
 1799                         break;
 1800                 if (((struct ieee80211chanreq *)data)->i_channel > 14) {
 1801                         error = EINVAL;
 1802                         break;
 1803                 }
 1804                 wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK | M_ZERO);
 1805                 wreq->wi_type = WI_RID_OWN_CHNL;
 1806                 wreq->wi_val[0] =
 1807                     htole16(((struct ieee80211chanreq *)data)->i_channel);
 1808                 error = wi_setdef(sc, wreq);
 1809                 if (!error && (ifp->if_flags & IFF_UP))
 1810                         wi_init(sc);
 1811                 break;
 1812         case SIOCG80211CHANNEL:
 1813                 wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK | M_ZERO);
 1814                 wreq->wi_type = WI_RID_CURRENT_CHAN;
 1815                 wreq->wi_len = WI_MAX_DATALEN;
 1816                 if (wi_read_record(sc, (struct wi_ltv_gen *)wreq)) {
 1817                         error = EINVAL;
 1818                         break;
 1819                 }
 1820                 ((struct ieee80211chanreq *)data)->i_channel =
 1821                     letoh16(wreq->wi_val[0]);
 1822                 break;
 1823         case SIOCG80211BSSID:
 1824                 bssid = (struct ieee80211_bssid *)data;
 1825                 wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK | M_ZERO);
 1826                 wreq->wi_type = WI_RID_CURRENT_BSSID;
 1827                 wreq->wi_len = WI_MAX_DATALEN;
 1828                 if (wi_read_record(sc, (struct wi_ltv_gen *)wreq)) {
 1829                         error = EINVAL;
 1830                         break;
 1831                 }
 1832                 IEEE80211_ADDR_COPY(bssid->i_bssid, wreq->wi_val);
 1833                 break;
 1834         case SIOCS80211SCAN:
 1835                 if ((error = suser(curproc)) != 0)
 1836                         break;
 1837                 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP)
 1838                         break;
 1839                 if ((ifp->if_flags & IFF_UP) == 0) {
 1840                         error = ENETDOWN;
 1841                         break;
 1842                 }
 1843                 if (sc->sc_firmware_type == WI_LUCENT) {
 1844                         wi_cmd(sc, WI_CMD_INQUIRE,
 1845                             WI_INFO_SCAN_RESULTS, 0, 0);
 1846                 } else {
 1847                         wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK|M_ZERO);
 1848                         wreq->wi_len = 3;
 1849                         wreq->wi_type = WI_RID_SCAN_REQ;
 1850                         wreq->wi_val[0] = 0x3FFF;
 1851                         wreq->wi_val[1] = 0x000F;
 1852 
 1853                         error = wi_write_record(sc,
 1854                             (struct wi_ltv_gen *)wreq);
 1855                         if (error)
 1856                                 break;
 1857                 }
 1858                 sc->wi_scan_lock = 0;
 1859                 timeout_set(&sc->wi_scan_timeout, wi_scan_timeout, sc);
 1860                 len = WI_WAVELAN_RES_TIMEOUT;
 1861                 if (sc->wi_flags & WI_FLAGS_BUS_USB) {
 1862                         /* Use a longer timeout for wi@usb */
 1863                         len = WI_WAVELAN_RES_TIMEOUT * 4;
 1864                 }
 1865                 timeout_add(&sc->wi_scan_timeout, len);
 1866 
 1867                 /* Let the userspace process wait for completion */
 1868                 error = tsleep_nsec(&sc->wi_scan_lock, PCATCH, "wiscan",
 1869                     SEC_TO_NSEC(IEEE80211_SCAN_TIMEOUT));
 1870                 break;
 1871         case SIOCG80211ALLNODES:
 1872             {
 1873                 struct ieee80211_nodereq        *nr = NULL;
 1874 
 1875                 if ((error = suser(curproc)) != 0)
 1876                         break;
 1877                 na = (struct ieee80211_nodereq_all *)data;
 1878                 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
 1879                         /* List all associated stations */
 1880                         error = wihap_ioctl(sc, command, data);
 1881                         break;
 1882                 }
 1883                 wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK | M_ZERO);
 1884                 wreq->wi_len = WI_MAX_DATALEN;
 1885                 wreq->wi_type = WI_RID_SCAN_RES;
 1886                 if (sc->sc_firmware_type == WI_LUCENT) {
 1887                         bcopy(sc->wi_scanbuf, wreq->wi_val,
 1888                             sc->wi_scanbuf_len * 2);
 1889                         wreq->wi_len = sc->wi_scanbuf_len;
 1890                         i = 0;
 1891                         len = WI_WAVELAN_RES_SIZE;
 1892                 } else {
 1893                         if (wi_read_record(sc, (struct wi_ltv_gen *)wreq)) {
 1894                                 error = EINVAL;
 1895                                 break;
 1896                         }
 1897                         p2 = (struct wi_scan_p2_hdr *)wreq->wi_val;
 1898                         if (p2->wi_reason == 0)
 1899                                 break;
 1900                         i = sizeof(*p2);
 1901                         len = WI_PRISM2_RES_SIZE;
 1902                 }
 1903 
 1904                 for (na->na_nodes = j = 0; (i < (wreq->wi_len * 2) - len) &&
 1905                     (na->na_size >= j + sizeof(struct ieee80211_nodereq));
 1906                     i += len) {
 1907 
 1908                         if (nr == NULL)
 1909                                 nr = malloc(sizeof *nr, M_DEVBUF, M_WAITOK);
 1910                         res = (struct wi_scan_res *)((char *)wreq->wi_val + i);
 1911                         if (res == NULL)
 1912                                 break;
 1913 
 1914                         bzero(nr, sizeof(*nr));
 1915                         IEEE80211_ADDR_COPY(nr->nr_macaddr, res->wi_bssid);
 1916                         IEEE80211_ADDR_COPY(nr->nr_bssid, res->wi_bssid);
 1917                         nr->nr_channel = letoh16(res->wi_chan);
 1918                         nr->nr_chan_flags = IEEE80211_CHAN_B;
 1919                         nr->nr_rssi = letoh16(res->wi_signal);
 1920                         nr->nr_max_rssi = 0; /* XXX */
 1921                         nr->nr_nwid_len = letoh16(res->wi_ssid_len);
 1922                         bcopy(res->wi_ssid, nr->nr_nwid, nr->nr_nwid_len);
 1923                         nr->nr_intval = letoh16(res->wi_interval);
 1924                         nr->nr_capinfo = letoh16(res->wi_capinfo);
 1925                         nr->nr_txrate = res->wi_rate == WI_WAVELAN_RES_1M ? 2 :
 1926                             (res->wi_rate == WI_WAVELAN_RES_2M ? 4 :
 1927                             (res->wi_rate == WI_WAVELAN_RES_5M ? 11 :
 1928                             (res->wi_rate == WI_WAVELAN_RES_11M ? 22 : 0)));
 1929                         nr->nr_nrates = 0;
 1930                         while (res->wi_srates[nr->nr_nrates] != 0) {
 1931                                 nr->nr_rates[nr->nr_nrates] =
 1932                                     res->wi_srates[nr->nr_nrates] &
 1933                                     WI_VAR_SRATES_MASK;
 1934                                 nr->nr_nrates++;
 1935                         }
 1936                         nr->nr_flags = 0;
 1937                         if (bcmp(nr->nr_macaddr, nr->nr_bssid,
 1938                             IEEE80211_ADDR_LEN) == 0)
 1939                                 nr->nr_flags |= IEEE80211_NODEREQ_AP;
 1940 
 1941                         error = copyout(nr, (caddr_t)na->na_node + j,
 1942                             sizeof(struct ieee80211_nodereq));
 1943                         if (error)
 1944                                 break;
 1945                         j += sizeof(struct ieee80211_nodereq);
 1946                         na->na_nodes++;
 1947                 }
 1948                 if (nr)
 1949                         free(nr, M_DEVBUF, 0);
 1950                 break;
 1951             }
 1952         case SIOCG80211FLAGS:
 1953                 if (sc->wi_ptype != WI_PORTTYPE_HOSTAP)
 1954                         break;
 1955                 ifr->ifr_flags = 0;
 1956                 if (sc->wi_flags & WI_FLAGS_HAS_ENH_SECURITY) {
 1957                         wreq = malloc(sizeof *wreq, M_DEVBUF, M_WAITOK|M_ZERO);
 1958                         wreq->wi_len = WI_MAX_DATALEN;
 1959                         wreq->wi_type = WI_RID_ENH_SECURITY;
 1960                         if (wi_read_record(sc, (struct wi_ltv_gen *)wreq)) {
 1961                                 error = EINVAL;
 1962                                 break;
 1963                         }
 1964                         sc->wi_enh_security = letoh16(wreq->wi_val[0]);
 1965                         if (sc->wi_enh_security == WI_HIDESSID_IGNPROBES)
 1966                                 ifr->ifr_flags |= IEEE80211_F_HIDENWID;
 1967                 }
 1968                 break;
 1969         case SIOCS80211FLAGS:
 1970                 if ((error = suser(curproc)) != 0)
 1971                         break;
 1972                 if (sc->wi_ptype != WI_PORTTYPE_HOSTAP) {
 1973                         error = EINVAL;
 1974                         break;
 1975                 }
 1976                 flags = (u_int32_t)ifr->ifr_flags;
 1977                 if (sc->wi_flags & WI_FLAGS_HAS_ENH_SECURITY) {
 1978                         sc->wi_enh_security = (flags & IEEE80211_F_HIDENWID) ?
 1979                             WI_HIDESSID_IGNPROBES : 0;
 1980                         WI_SETVAL(WI_RID_ENH_SECURITY, sc->wi_enh_security);
 1981                 }
 1982                 break;
 1983         case SIOCHOSTAP_ADD:
 1984         case SIOCHOSTAP_DEL:
 1985         case SIOCHOSTAP_GET:
 1986         case SIOCHOSTAP_GETALL:
 1987         case SIOCHOSTAP_GFLAGS:
 1988         case SIOCHOSTAP_SFLAGS:
 1989                 /* Send all Host AP specific ioctl's to Host AP code. */
 1990                 error = wihap_ioctl(sc, command, data);
 1991                 break;
 1992         default:
 1993                 error = ether_ioctl(ifp, &sc->sc_ic.ic_ac, command, data);
 1994         }
 1995 
 1996         if (error == ENETRESET) {
 1997                 if (ifp->if_flags & IFF_RUNNING)
 1998                         wi_setmulti(sc);
 1999                 error = 0;
 2000         }
 2001 
 2002         if (wreq)
 2003                 free(wreq, M_DEVBUF, 0);
 2004         if (nwidp)
 2005                 free(nwidp, M_DEVBUF, 0);
 2006 
 2007 fail:
 2008         sc->wi_flags &= ~WI_FLAGS_BUSY;
 2009         wakeup(&sc->wi_flags);
 2010         splx(s);
 2011         return(error);
 2012 }
 2013 
 2014 void
 2015 wi_scan_timeout(void *arg)
 2016 {
 2017         struct wi_softc         *sc = (struct wi_softc *)arg;
 2018         struct wi_req           wreq;
 2019 
 2020         if (sc->wi_scan_lock++ < WI_WAVELAN_RES_TRIES &&
 2021             sc->sc_firmware_type != WI_LUCENT &&
 2022             (sc->wi_flags & WI_FLAGS_BUS_USB) == 0) {
 2023                 /*
 2024                  * The Prism2/2.5/3 chipsets will set an extra field in the
 2025                  * scan result if the scan request has been completed by the
 2026                  * firmware. This allows to poll for completion and to
 2027                  * wait for some more time if the scan is still in progress.
 2028                  *
 2029                  * XXX This doesn't work with wi@usb because it isn't safe
 2030                  * to call wi_read_record_usb() while being in the timeout
 2031                  * handler.
 2032                  */
 2033                 wreq.wi_len = WI_MAX_DATALEN;
 2034                 wreq.wi_type = WI_RID_SCAN_RES;
 2035 
 2036                 if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0 &&
 2037                     ((struct wi_scan_p2_hdr *)wreq.wi_val)->wi_reason == 0) {
 2038                         /* Wait some more time for scan completion */
 2039                         timeout_add(&sc->wi_scan_timeout, WI_WAVELAN_RES_TIMEOUT);
 2040                         return;
 2041                 }
 2042         }
 2043 
 2044         if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
 2045                 printf(WI_PRT_FMT ": wi_scan_timeout: %d tries\n",
 2046                     WI_PRT_ARG(sc), sc->wi_scan_lock);
 2047 
 2048         /* Wakeup the userland */
 2049         wakeup(&sc->wi_scan_lock);      
 2050         sc->wi_scan_lock = 0;
 2051 }
 2052 
 2053 STATIC void
 2054 wi_init_io(struct wi_softc *sc)
 2055 {
 2056         struct ifnet            *ifp = &sc->sc_ic.ic_ac.ac_if;
 2057         int                     s;
 2058         struct wi_ltv_macaddr   mac;
 2059         int                     id = 0;
 2060 
 2061         if (!(sc->wi_flags & WI_FLAGS_ATTACHED))
 2062                 return;
 2063 
 2064         DPRINTF(WID_INIT, ("wi_init: sc %p\n", sc));
 2065 
 2066         s = splnet();
 2067 
 2068         if (ifp->if_flags & IFF_RUNNING)
 2069                 wi_stop(sc);
 2070 
 2071         wi_reset(sc);
 2072 
 2073         /* Program max data length. */
 2074         WI_SETVAL(WI_RID_MAX_DATALEN, sc->wi_max_data_len);
 2075 
 2076         /* Set the port type. */
 2077         WI_SETVAL(WI_RID_PORTTYPE, sc->wi_ptype);
 2078 
 2079         /* Enable/disable IBSS creation. */
 2080         WI_SETVAL(WI_RID_CREATE_IBSS, sc->wi_create_ibss);
 2081 
 2082         /* Program the RTS/CTS threshold. */
 2083         WI_SETVAL(WI_RID_RTS_THRESH, sc->wi_rts_thresh);
 2084 
 2085         /* Program the TX rate */
 2086         WI_SETVAL(WI_RID_TX_RATE, sc->wi_tx_rate);
 2087 
 2088         /* Access point density */
 2089         WI_SETVAL(WI_RID_SYSTEM_SCALE, sc->wi_ap_density);
 2090 
 2091         /* Power Management Enabled */
 2092         WI_SETVAL(WI_RID_PM_ENABLED, sc->wi_pm_enabled);
 2093 
 2094         /* Power Management Max Sleep */
 2095         WI_SETVAL(WI_RID_MAX_SLEEP, sc->wi_max_sleep);
 2096 
 2097         /* Set Enhanced Security if supported. */
 2098         if (sc->wi_flags & WI_FLAGS_HAS_ENH_SECURITY)
 2099                 WI_SETVAL(WI_RID_ENH_SECURITY, sc->wi_enh_security);
 2100 
 2101         /* Set Roaming Mode unless this is a Symbol card. */
 2102         if (sc->wi_flags & WI_FLAGS_HAS_ROAMING)
 2103                 WI_SETVAL(WI_RID_ROAMING_MODE, sc->wi_roaming);
 2104 
 2105         /* Set Antenna Diversity if this is a Symbol card. */
 2106         if (sc->wi_flags & WI_FLAGS_HAS_DIVERSITY)
 2107                 WI_SETVAL(WI_RID_SYMBOL_DIVERSITY, sc->wi_diversity);
 2108 
 2109         /* Specify the network name */
 2110         WI_SETSTR(WI_RID_DESIRED_SSID, sc->wi_net_name);
 2111 
 2112         /* Specify the IBSS name */
 2113         if (sc->wi_net_name.i_len != 0 && (sc->wi_ptype == WI_PORTTYPE_HOSTAP ||
 2114             (sc->wi_create_ibss && sc->wi_ptype == WI_PORTTYPE_IBSS)))
 2115                 WI_SETSTR(WI_RID_OWN_SSID, sc->wi_net_name);
 2116         else
 2117                 WI_SETSTR(WI_RID_OWN_SSID, sc->wi_ibss_name);
 2118 
 2119         /* Specify the frequency to use */
 2120         WI_SETVAL(WI_RID_OWN_CHNL, sc->wi_channel);
 2121 
 2122         /* Program the nodename. */
 2123         WI_SETSTR(WI_RID_NODENAME, sc->wi_node_name);
 2124 
 2125         /* Set our MAC address. */
 2126         mac.wi_len = 4;
 2127         mac.wi_type = WI_RID_MAC_NODE;
 2128         bcopy(LLADDR(ifp->if_sadl), &sc->sc_ic.ic_myaddr, ETHER_ADDR_LEN);
 2129         bcopy(&sc->sc_ic.ic_myaddr, &mac.wi_mac_addr, ETHER_ADDR_LEN);
 2130         wi_write_record(sc, (struct wi_ltv_gen *)&mac);
 2131 
 2132         /*
 2133          * Initialize promisc mode.
 2134          *      Being in the Host-AP mode causes
 2135          *      great deal of pain if promisc mode is set.
 2136          *      Therefore we avoid confusing the firmware
 2137          *      and always reset promisc mode in Host-AP regime,
 2138          *      it shows us all the packets anyway.
 2139          */
 2140         if (sc->wi_ptype != WI_PORTTYPE_HOSTAP && ifp->if_flags & IFF_PROMISC)
 2141                 WI_SETVAL(WI_RID_PROMISC, 1);
 2142         else
 2143                 WI_SETVAL(WI_RID_PROMISC, 0);
 2144 
 2145         /* Configure WEP. */
 2146         if (sc->wi_flags & WI_FLAGS_HAS_WEP) {
 2147                 WI_SETVAL(WI_RID_ENCRYPTION, sc->wi_use_wep);
 2148                 WI_SETVAL(WI_RID_TX_CRYPT_KEY, sc->wi_tx_key);
 2149                 sc->wi_keys.wi_len = (sizeof(struct wi_ltv_keys) / 2) + 1;
 2150                 sc->wi_keys.wi_type = WI_RID_DEFLT_CRYPT_KEYS;
 2151                 wi_write_record(sc, (struct wi_ltv_gen *)&sc->wi_keys);
 2152                 if (sc->sc_firmware_type != WI_LUCENT && sc->wi_use_wep) {
 2153                         /*
 2154                          * HWB3163 EVAL-CARD Firmware version less than 0.8.2.
 2155                          *
 2156                          * If promiscuous mode is disabled, the Prism2 chip
 2157                          * does not work with WEP .
 2158                          * I'm currently investigating the details of this.
 2159                          * (ichiro@netbsd.org)
 2160                          */
 2161                          if (sc->sc_firmware_type == WI_INTERSIL &&
 2162                             sc->sc_sta_firmware_ver < 802 ) {
 2163                                 /* firm ver < 0.8.2 */
 2164                                 WI_SETVAL(WI_RID_PROMISC, 1);
 2165                          }
 2166                          WI_SETVAL(WI_RID_CNFAUTHMODE, sc->wi_authtype);
 2167                 }
 2168         }
 2169 
 2170         /* Set multicast filter. */
 2171         wi_setmulti(sc);
 2172 
 2173         /* Enable desired port */
 2174         wi_cmd(sc, WI_CMD_ENABLE | sc->wi_portnum, 0, 0, 0);
 2175 
 2176         if (wi_alloc_nicmem(sc, ETHER_MAX_LEN + sizeof(struct wi_frame) + 8, &id))
 2177                 printf(WI_PRT_FMT ": tx buffer allocation failed\n",
 2178                     WI_PRT_ARG(sc));
 2179         sc->wi_tx_data_id = id;
 2180 
 2181         if (wi_alloc_nicmem(sc, ETHER_MAX_LEN + sizeof(struct wi_frame) + 8, &id))
 2182                 printf(WI_PRT_FMT ": mgmt. buffer allocation failed\n",
 2183                     WI_PRT_ARG(sc));
 2184         sc->wi_tx_mgmt_id = id;
 2185 
 2186         /* Set txpower */
 2187         if (sc->wi_flags & WI_FLAGS_TXPOWER)
 2188                 wi_set_txpower(sc, NULL);
 2189 
 2190         /* enable interrupts */
 2191         wi_intr_enable(sc, WI_INTRS);
 2192 
 2193         wihap_init(sc);
 2194 
 2195         splx(s);
 2196 
 2197         ifp->if_flags |= IFF_RUNNING;
 2198         ifq_clr_oactive(&ifp->if_snd);
 2199 
 2200         timeout_add_sec(&sc->sc_timo, 60);
 2201 
 2202         return;
 2203 }
 2204 
 2205 STATIC void
 2206 wi_do_hostencrypt(struct wi_softc *sc, caddr_t buf, int len)
 2207 {
 2208         u_int32_t crc, klen;
 2209         u_int8_t key[RC4KEYLEN];
 2210         u_int8_t *dat;
 2211         struct rc4_ctx ctx;
 2212 
 2213         if (!sc->wi_icv_flag) {
 2214                 sc->wi_icv = arc4random();
 2215                 sc->wi_icv_flag++;
 2216         } else
 2217                 sc->wi_icv++;
 2218         /*
 2219          * Skip 'bad' IVs from Fluhrer/Mantin/Shamir:
 2220          * (B, 255, N) with 3 <= B < 8
 2221          */
 2222         if (sc->wi_icv >= 0x03ff00 &&
 2223             (sc->wi_icv & 0xf8ff00) == 0x00ff00)
 2224                 sc->wi_icv += 0x000100;
 2225 
 2226         /* prepend 24bit IV to tx key, byte order does not matter */
 2227         bzero(key, sizeof(key));
 2228         key[0] = sc->wi_icv >> 16;
 2229         key[1] = sc->wi_icv >> 8;
 2230         key[2] = sc->wi_icv;
 2231 
 2232         klen = letoh16(sc->wi_keys.wi_keys[sc->wi_tx_key].wi_keylen);
 2233         bcopy(&sc->wi_keys.wi_keys[sc->wi_tx_key].wi_keydat,
 2234             key + IEEE80211_WEP_IVLEN, klen);
 2235         klen = (klen > IEEE80211_WEP_KEYLEN) ? RC4KEYLEN : RC4KEYLEN / 2;
 2236 
 2237         /* rc4 keysetup */
 2238         rc4_keysetup(&ctx, key, klen);
 2239 
 2240         /* output: IV, tx keyid, rc4(data), rc4(crc32(data)) */
 2241         dat = buf;
 2242         dat[0] = key[0];
 2243         dat[1] = key[1];
 2244         dat[2] = key[2];
 2245         dat[3] = sc->wi_tx_key << 6;            /* pad and keyid */
 2246         dat += 4;
 2247 
 2248         /* compute crc32 over data and encrypt */
 2249         crc = ~ether_crc32_le(dat, len);
 2250         rc4_crypt(&ctx, dat, dat, len);
 2251         dat += len;
 2252 
 2253         /* append little-endian crc32 and encrypt */
 2254         dat[0] = crc;
 2255         dat[1] = crc >> 8;
 2256         dat[2] = crc >> 16;
 2257         dat[3] = crc >> 24;
 2258         rc4_crypt(&ctx, dat, dat, IEEE80211_WEP_CRCLEN);
 2259 }
 2260 
 2261 STATIC int
 2262 wi_do_hostdecrypt(struct wi_softc *sc, caddr_t buf, int len)
 2263 {
 2264         u_int32_t crc, klen, kid;
 2265         u_int8_t key[RC4KEYLEN];
 2266         u_int8_t *dat;
 2267         struct rc4_ctx ctx;
 2268 
 2269         if (len < IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
 2270             IEEE80211_WEP_CRCLEN)
 2271                 return -1;
 2272         len -= (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
 2273             IEEE80211_WEP_CRCLEN);
 2274 
 2275         dat = buf;
 2276 
 2277         bzero(key, sizeof(key));
 2278         key[0] = dat[0];
 2279         key[1] = dat[1];
 2280         key[2] = dat[2];
 2281         kid = (dat[3] >> 6) % 4;
 2282         dat += 4;
 2283 
 2284         klen = letoh16(sc->wi_keys.wi_keys[kid].wi_keylen);
 2285         bcopy(&sc->wi_keys.wi_keys[kid].wi_keydat,
 2286             key + IEEE80211_WEP_IVLEN, klen);
 2287         klen = (klen > IEEE80211_WEP_KEYLEN) ? RC4KEYLEN : RC4KEYLEN / 2;
 2288 
 2289         /* rc4 keysetup */
 2290         rc4_keysetup(&ctx, key, klen);
 2291 
 2292         /* decrypt and compute crc32 over data */
 2293         rc4_crypt(&ctx, dat, dat, len);
 2294         crc = ~ether_crc32_le(dat, len);
 2295         dat += len;
 2296 
 2297         /* decrypt little-endian crc32 and verify */
 2298         rc4_crypt(&ctx, dat, dat, IEEE80211_WEP_CRCLEN);
 2299 
 2300         if ((dat[0] != crc) && (dat[1] != crc >> 8) &&
 2301             (dat[2] != crc >> 16) && (dat[3] != crc >> 24)) {
 2302                 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
 2303                         printf(WI_PRT_FMT ": wi_do_hostdecrypt: iv mismatch: "
 2304                             "0x%02x%02x%02x%02x vs. 0x%x\n", WI_PRT_ARG(sc),
 2305                             dat[3], dat[2], dat[1], dat[0], crc);
 2306                 return -1;
 2307         }
 2308 
 2309         return 0;
 2310 }
 2311 
 2312 void
 2313 wi_start(struct ifnet *ifp)
 2314 {
 2315         struct wi_softc         *sc;
 2316         struct mbuf             *m0;
 2317         struct wi_frame         tx_frame;
 2318         struct ether_header     *eh;
 2319         int                     id, hostencrypt = 0;
 2320 
 2321         sc = ifp->if_softc;
 2322 
 2323         DPRINTF(WID_START, ("wi_start: ifp %p sc %p\n", ifp, sc));
 2324 
 2325         if (!(sc->wi_flags & WI_FLAGS_ATTACHED))
 2326                 return;
 2327 
 2328         if (ifq_is_oactive(&ifp->if_snd))
 2329                 return;
 2330 
 2331 nextpkt:
 2332         m0 = ifq_dequeue(&ifp->if_snd);
 2333         if (m0 == NULL)
 2334                 return;
 2335 
 2336         bzero(&tx_frame, sizeof(tx_frame));
 2337         tx_frame.wi_frame_ctl = htole16(WI_FTYPE_DATA | WI_STYPE_DATA);
 2338         id = sc->wi_tx_data_id;
 2339         eh = mtod(m0, struct ether_header *);
 2340 
 2341         if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
 2342                 if (!wihap_check_tx(&sc->wi_hostap_info, eh->ether_dhost,
 2343                     &tx_frame.wi_tx_rate) && !(ifp->if_flags & IFF_PROMISC)) {
 2344                         if (ifp->if_flags & IFF_DEBUG)
 2345                                 printf(WI_PRT_FMT
 2346                                     ": wi_start: dropping unassoc dst %s\n",
 2347                                     WI_PRT_ARG(sc),
 2348                                     ether_sprintf(eh->ether_dhost));
 2349                         m_freem(m0);
 2350                         goto nextpkt;
 2351                 }
 2352         }
 2353 
 2354         /*
 2355          * Use RFC1042 encoding for IP and ARP datagrams,
 2356          * 802.3 for anything else.
 2357          */
 2358         if (eh->ether_type == htons(ETHERTYPE_IP) ||
 2359             eh->ether_type == htons(ETHERTYPE_ARP) ||
 2360             eh->ether_type == htons(ETHERTYPE_REVARP) ||
 2361             eh->ether_type == htons(ETHERTYPE_IPV6)) {
 2362                 bcopy(&eh->ether_dhost,
 2363                     &tx_frame.wi_addr1, ETHER_ADDR_LEN);
 2364                 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
 2365                         tx_frame.wi_tx_ctl = htole16(WI_ENC_TX_MGMT); /* XXX */
 2366                         tx_frame.wi_frame_ctl |= htole16(WI_FCTL_FROMDS);
 2367                         bcopy(&sc->sc_ic.ic_myaddr,
 2368                             &tx_frame.wi_addr2, ETHER_ADDR_LEN);
 2369                         bcopy(&eh->ether_shost,
 2370                             &tx_frame.wi_addr3, ETHER_ADDR_LEN);
 2371                         if (sc->wi_use_wep)
 2372                                 hostencrypt = 1;
 2373                 } else if (sc->wi_ptype == WI_PORTTYPE_BSS && sc->wi_use_wep &&
 2374                     sc->wi_crypto_algorithm != WI_CRYPTO_FIRMWARE_WEP) {
 2375                         tx_frame.wi_tx_ctl = htole16(WI_ENC_TX_MGMT); /* XXX */
 2376                         tx_frame.wi_frame_ctl |= htole16(WI_FCTL_TODS);
 2377                         bcopy(&sc->sc_ic.ic_myaddr,
 2378                             &tx_frame.wi_addr2, ETHER_ADDR_LEN);
 2379                         bcopy(&eh->ether_dhost,
 2380                             &tx_frame.wi_addr3, ETHER_ADDR_LEN);
 2381                         hostencrypt = 1;
 2382                 } else
 2383                         bcopy(&eh->ether_shost,
 2384                             &tx_frame.wi_addr2, ETHER_ADDR_LEN);
 2385                 bcopy(&eh->ether_dhost, &tx_frame.wi_dst_addr, ETHER_ADDR_LEN);
 2386                 bcopy(&eh->ether_shost, &tx_frame.wi_src_addr, ETHER_ADDR_LEN);
 2387 
 2388                 tx_frame.wi_dat_len = m0->m_pkthdr.len - WI_SNAPHDR_LEN;
 2389                 tx_frame.wi_dat[0] = htons(WI_SNAP_WORD0);
 2390                 tx_frame.wi_dat[1] = htons(WI_SNAP_WORD1);
 2391                 tx_frame.wi_len = htons(m0->m_pkthdr.len - WI_SNAPHDR_LEN);
 2392                 tx_frame.wi_type = eh->ether_type;
 2393 
 2394                 if (hostencrypt) {
 2395 
 2396                         /* Do host encryption. */
 2397                         tx_frame.wi_frame_ctl |= htole16(WI_FCTL_WEP);
 2398                         bcopy(&tx_frame.wi_dat[0], &sc->wi_txbuf[4], 6);
 2399                         bcopy(&tx_frame.wi_type, &sc->wi_txbuf[10], 2);
 2400 
 2401                         m_copydata(m0, sizeof(struct ether_header),
 2402                             m0->m_pkthdr.len - sizeof(struct ether_header),
 2403                             &sc->wi_txbuf[12]);
 2404 
 2405                         wi_do_hostencrypt(sc, (caddr_t)&sc->wi_txbuf,
 2406                             tx_frame.wi_dat_len);
 2407 
 2408                         tx_frame.wi_dat_len += IEEE80211_WEP_IVLEN +
 2409                             IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
 2410 
 2411                         tx_frame.wi_dat_len = htole16(tx_frame.wi_dat_len);
 2412                         wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
 2413                             sizeof(struct wi_frame));
 2414                         wi_write_data(sc, id, WI_802_11_OFFSET_RAW,
 2415                             (caddr_t)&sc->wi_txbuf,
 2416                             (m0->m_pkthdr.len -
 2417                              sizeof(struct ether_header)) + 18);
 2418                 } else {
 2419                         m_copydata(m0, sizeof(struct ether_header),
 2420                             m0->m_pkthdr.len - sizeof(struct ether_header),
 2421                             &sc->wi_txbuf);
 2422 
 2423                         tx_frame.wi_dat_len = htole16(tx_frame.wi_dat_len);
 2424                         wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
 2425                             sizeof(struct wi_frame));
 2426                         wi_write_data(sc, id, WI_802_11_OFFSET,
 2427                             (caddr_t)&sc->wi_txbuf,
 2428                             (m0->m_pkthdr.len -
 2429                              sizeof(struct ether_header)) + 2);
 2430                 }
 2431         } else {
 2432                 tx_frame.wi_dat_len = htole16(m0->m_pkthdr.len);
 2433 
 2434                 if (sc->wi_ptype == WI_PORTTYPE_HOSTAP && sc->wi_use_wep) {
 2435 
 2436                         /* Do host encryption. (XXX - not implemented) */
 2437                         printf(WI_PRT_FMT
 2438                             ": host encrypt not implemented for 802.3\n",
 2439                             WI_PRT_ARG(sc));
 2440                 } else {
 2441                         m_copydata(m0, 0, m0->m_pkthdr.len, &sc->wi_txbuf);
 2442 
 2443                         wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
 2444                             sizeof(struct wi_frame));
 2445                         wi_write_data(sc, id, WI_802_3_OFFSET,
 2446                             (caddr_t)&sc->wi_txbuf, m0->m_pkthdr.len + 2);
 2447                 }
 2448         }
 2449 
 2450 #if NBPFILTER > 0
 2451         /*
 2452          * If there's a BPF listener, bounce a copy of
 2453          * this frame to him.
 2454          */
 2455         if (ifp->if_bpf)
 2456                 bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
 2457 #endif
 2458 
 2459         m_freem(m0);
 2460 
 2461         ifq_set_oactive(&ifp->if_snd);
 2462 
 2463         /*
 2464          * Set a timeout in case the chip goes out to lunch.
 2465          */
 2466         ifp->if_timer = 5;
 2467 
 2468         if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0))
 2469                 printf(WI_PRT_FMT ": wi_start: xmit failed\n", WI_PRT_ARG(sc));
 2470 
 2471         return;
 2472 }
 2473 
 2474 STATIC int
 2475 wi_mgmt_xmit(struct wi_softc *sc, caddr_t data, int len)
 2476 {
 2477         struct wi_frame         tx_frame;
 2478         int                     id;
 2479         struct wi_80211_hdr     *hdr;
 2480         caddr_t                 dptr;
 2481 
 2482         if (!(sc->wi_flags & WI_FLAGS_ATTACHED))
 2483                 return(ENODEV);
 2484 
 2485         hdr = (struct wi_80211_hdr *)data;
 2486         dptr = data + sizeof(struct wi_80211_hdr);
 2487 
 2488         bzero(&tx_frame, sizeof(tx_frame));
 2489         id = sc->wi_tx_mgmt_id;
 2490 
 2491         bcopy(hdr, &tx_frame.wi_frame_ctl, sizeof(struct wi_80211_hdr));
 2492 
 2493         tx_frame.wi_tx_ctl = htole16(WI_ENC_TX_MGMT);
 2494         tx_frame.wi_dat_len = len - sizeof(struct wi_80211_hdr);
 2495         tx_frame.wi_len = htole16(tx_frame.wi_dat_len);
 2496 
 2497         tx_frame.wi_dat_len = htole16(tx_frame.wi_dat_len);
 2498         wi_write_data(sc, id, 0, (caddr_t)&tx_frame, sizeof(struct wi_frame));
 2499         wi_write_data(sc, id, WI_802_11_OFFSET_RAW, dptr,
 2500             (len - sizeof(struct wi_80211_hdr)) + 2);
 2501 
 2502         if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0)) {
 2503                 printf(WI_PRT_FMT ": wi_mgmt_xmit: xmit failed\n",
 2504                     WI_PRT_ARG(sc));
 2505                 /*
 2506                  * Hostile stations or corrupt frames may crash the card
 2507                  * and cause the kernel to get stuck printing complaints.
 2508                  * Reset the card and hope the problem goes away.
 2509                  */
 2510                 wi_reset(sc);
 2511                 return(EIO);
 2512         }
 2513 
 2514         return(0);
 2515 }
 2516 
 2517 void
 2518 wi_stop(struct wi_softc *sc)
 2519 {
 2520         struct ifnet            *ifp;
 2521 
 2522         wihap_shutdown(sc);
 2523 
 2524         if (!(sc->wi_flags & WI_FLAGS_ATTACHED))
 2525                 return;
 2526 
 2527         DPRINTF(WID_STOP, ("wi_stop: sc %p\n", sc));
 2528 
 2529         timeout_del(&sc->sc_timo);
 2530 
 2531         ifp = &sc->sc_ic.ic_if;
 2532 
 2533         wi_intr_enable(sc, 0);
 2534         wi_cmd(sc, WI_CMD_DISABLE|sc->wi_portnum, 0, 0, 0);
 2535 
 2536         ifp->if_flags &= ~IFF_RUNNING;
 2537         ifq_clr_oactive(&ifp->if_snd);
 2538         ifp->if_timer = 0;
 2539 
 2540         return;
 2541 }
 2542 
 2543 
 2544 void
 2545 wi_watchdog(struct ifnet *ifp)
 2546 {
 2547         struct wi_softc         *sc;
 2548 
 2549         sc = ifp->if_softc;
 2550 
 2551         printf(WI_PRT_FMT ": device timeout\n", WI_PRT_ARG(sc));
 2552 
 2553         wi_cor_reset(sc);
 2554         wi_init(sc);
 2555 
 2556         ifp->if_oerrors++;
 2557 
 2558         return;
 2559 }
 2560 
 2561 void
 2562 wi_detach(struct wi_softc *sc)
 2563 {
 2564         struct ifnet *ifp;
 2565         ifp = &sc->sc_ic.ic_if;
 2566 
 2567         if (ifp->if_flags & IFF_RUNNING)
 2568                 wi_stop(sc);
 2569         
 2570         if (sc->wi_flags & WI_FLAGS_ATTACHED) {
 2571                 sc->wi_flags &= ~WI_FLAGS_ATTACHED;
 2572         }
 2573 }
 2574 
 2575 STATIC void
 2576 wi_get_id(struct wi_softc *sc)
 2577 {
 2578         struct wi_ltv_ver               ver;
 2579         const struct wi_card_ident      *id;
 2580         u_int16_t                       pri_fw_ver[3];
 2581         const char                      *card_name;
 2582         u_int16_t                       card_id;
 2583 
 2584         /* get chip identity */
 2585         bzero(&ver, sizeof(ver));
 2586         ver.wi_type = WI_RID_CARD_ID;
 2587         ver.wi_len = 5;
 2588         wi_read_record(sc, (struct wi_ltv_gen *)&ver);
 2589         card_id = letoh16(ver.wi_ver[0]);
 2590         for (id = wi_card_ident; id->firm_type != WI_NOTYPE; id++) {
 2591                 if (card_id == id->card_id)
 2592                         break;
 2593         }
 2594         if (id->firm_type != WI_NOTYPE) {
 2595                 sc->sc_firmware_type = id->firm_type;
 2596                 card_name = id->card_name;
 2597         } else if (ver.wi_ver[0] & htole16(0x8000)) {
 2598                 sc->sc_firmware_type = WI_INTERSIL;
 2599                 card_name = "Unknown PRISM2 chip";
 2600         } else {
 2601                 sc->sc_firmware_type = WI_LUCENT;
 2602         }
 2603 
 2604         /* get primary firmware version (XXX - how to do Lucent?) */
 2605         if (sc->sc_firmware_type != WI_LUCENT) {
 2606                 bzero(&ver, sizeof(ver));
 2607                 ver.wi_type = WI_RID_PRI_IDENTITY;
 2608                 ver.wi_len = 5;
 2609                 wi_read_record(sc, (struct wi_ltv_gen *)&ver);
 2610                 pri_fw_ver[0] = letoh16(ver.wi_ver[2]);
 2611                 pri_fw_ver[1] = letoh16(ver.wi_ver[3]);
 2612                 pri_fw_ver[2] = letoh16(ver.wi_ver[1]);
 2613         }
 2614 
 2615         /* get station firmware version */
 2616         bzero(&ver, sizeof(ver));
 2617         ver.wi_type = WI_RID_STA_IDENTITY;
 2618         ver.wi_len = 5;
 2619         wi_read_record(sc, (struct wi_ltv_gen *)&ver);
 2620         ver.wi_ver[1] = letoh16(ver.wi_ver[1]);
 2621         ver.wi_ver[2] = letoh16(ver.wi_ver[2]);
 2622         ver.wi_ver[3] = letoh16(ver.wi_ver[3]);
 2623         sc->sc_sta_firmware_ver = ver.wi_ver[2] * 10000 +
 2624             ver.wi_ver[3] * 100 + ver.wi_ver[1];
 2625 
 2626         if (sc->sc_firmware_type == WI_INTERSIL &&
 2627             (sc->sc_sta_firmware_ver == 10102 || sc->sc_sta_firmware_ver == 20102)) {
 2628                 struct wi_ltv_str sver;
 2629                 char *p;
 2630 
 2631                 bzero(&sver, sizeof(sver));
 2632                 sver.wi_type = WI_RID_SYMBOL_IDENTITY;
 2633                 sver.wi_len = 7;
 2634                 /* value should be something like "V2.00-11" */
 2635                 if (wi_read_record(sc, (struct wi_ltv_gen *)&sver) == 0 &&
 2636                     *(p = (char *)sver.wi_str) >= 'A' &&
 2637                     p[2] == '.' && p[5] == '-' && p[8] == '\0') {
 2638                         sc->sc_firmware_type = WI_SYMBOL;
 2639                         sc->sc_sta_firmware_ver = (p[1] - '') * 10000 +
 2640                             (p[3] - '') * 1000 + (p[4] - '') * 100 +
 2641                             (p[6] - '') * 10 + (p[7] - '');
 2642                 }
 2643         }
 2644 
 2645         if (sc->sc_firmware_type == WI_LUCENT) {
 2646                 printf("%s: Firmware %d.%02d variant %d, ", WI_PRT_ARG(sc),
 2647                     ver.wi_ver[2], ver.wi_ver[3], ver.wi_ver[1]);
 2648         } else {
 2649                 printf("%s: %s%s (0x%04x), Firmware %d.%d.%d (primary), %d.%d.%d (station), ",
 2650                     WI_PRT_ARG(sc),
 2651                     sc->sc_firmware_type == WI_SYMBOL ? "Symbol " : "",
 2652                     card_name, card_id, pri_fw_ver[0], pri_fw_ver[1],
 2653                     pri_fw_ver[2], sc->sc_sta_firmware_ver / 10000,
 2654                     (sc->sc_sta_firmware_ver % 10000) / 100,
 2655                     sc->sc_sta_firmware_ver % 100);
 2656         }
 2657 }
 2658 
 2659 STATIC int
 2660 wi_sync_media(struct wi_softc *sc, int ptype, int txrate)
 2661 {
 2662         uint64_t media = sc->sc_media.ifm_cur->ifm_media;
 2663         uint64_t options = IFM_OPTIONS(media);
 2664         uint64_t subtype;
 2665 
 2666         switch (txrate) {
 2667         case 1:
 2668                 subtype = IFM_IEEE80211_DS1;
 2669                 break;
 2670         case 2:
 2671                 subtype = IFM_IEEE80211_DS2;
 2672                 break;
 2673         case 3:
 2674                 subtype = IFM_AUTO;
 2675                 break;
 2676         case 5:
 2677                 subtype = IFM_IEEE80211_DS5;
 2678                 break;
 2679         case 11:
 2680                 subtype = IFM_IEEE80211_DS11;
 2681                 break;
 2682         default:
 2683                 subtype = IFM_MANUAL;           /* Unable to represent */
 2684                 break;
 2685         }
 2686 
 2687         options &= ~IFM_OMASK;
 2688         switch (ptype) {
 2689         case WI_PORTTYPE_BSS:
 2690                 /* default port type */
 2691                 break;
 2692         case WI_PORTTYPE_ADHOC:
 2693                 options |= IFM_IEEE80211_ADHOC;
 2694                 break;
 2695         case WI_PORTTYPE_HOSTAP:
 2696                 options |= IFM_IEEE80211_HOSTAP;
 2697                 break;
 2698         case WI_PORTTYPE_IBSS:
 2699                 if (sc->wi_create_ibss)
 2700                         options |= IFM_IEEE80211_IBSSMASTER;
 2701                 else
 2702                         options |= IFM_IEEE80211_IBSS;
 2703                 break;
 2704         default:
 2705                 subtype = IFM_MANUAL;           /* Unable to represent */
 2706                 break;
 2707         }
 2708         media = IFM_MAKEWORD(IFM_TYPE(media), subtype, options,
 2709         IFM_INST(media));
 2710         if (!ifmedia_match(&sc->sc_media, media, sc->sc_media.ifm_mask))
 2711                 return (EINVAL);
 2712         ifmedia_set(&sc->sc_media, media);
 2713         sc->wi_ptype = ptype;
 2714         sc->wi_tx_rate = txrate;
 2715         return (0);
 2716 }
 2717 
 2718 STATIC int
 2719 wi_media_change(struct ifnet *ifp)
 2720 {
 2721         struct wi_softc *sc = ifp->if_softc;
 2722         int otype = sc->wi_ptype;
 2723         int orate = sc->wi_tx_rate;
 2724         int ocreate_ibss = sc->wi_create_ibss;
 2725 
 2726         if ((sc->sc_media.ifm_cur->ifm_media & IFM_IEEE80211_HOSTAP) &&
 2727             sc->sc_firmware_type != WI_INTERSIL)
 2728                 return (EINVAL);
 2729 
 2730         sc->wi_create_ibss = 0;
 2731 
 2732         switch (sc->sc_media.ifm_cur->ifm_media & IFM_OMASK) {
 2733         case 0:
 2734                 sc->wi_ptype = WI_PORTTYPE_BSS;
 2735                 break;
 2736         case IFM_IEEE80211_ADHOC:
 2737                 sc->wi_ptype = WI_PORTTYPE_ADHOC;
 2738                 break;
 2739         case IFM_IEEE80211_HOSTAP:
 2740                 sc->wi_ptype = WI_PORTTYPE_HOSTAP;
 2741                 break;
 2742         case IFM_IEEE80211_IBSSMASTER:
 2743         case IFM_IEEE80211_IBSSMASTER|IFM_IEEE80211_IBSS:
 2744                 if (!(sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS))
 2745                         return (EINVAL);
 2746                 sc->wi_create_ibss = 1;
 2747                 /* FALLTHROUGH */
 2748         case IFM_IEEE80211_IBSS:
 2749                 sc->wi_ptype = WI_PORTTYPE_IBSS;
 2750                 break;
 2751         default:
 2752                 /* Invalid combination. */
 2753                 return (EINVAL);
 2754         }
 2755 
 2756         switch (IFM_SUBTYPE(sc->sc_media.ifm_cur->ifm_media)) {
 2757         case IFM_IEEE80211_DS1:
 2758                 sc->wi_tx_rate = 1;
 2759                 break;
 2760         case IFM_IEEE80211_DS2:
 2761                 sc->wi_tx_rate = 2;
 2762                 break;
 2763         case IFM_AUTO:
 2764                 sc->wi_tx_rate = 3;
 2765                 break;
 2766         case IFM_IEEE80211_DS5:
 2767                 sc->wi_tx_rate = 5;
 2768                 break;
 2769         case IFM_IEEE80211_DS11:
 2770                 sc->wi_tx_rate = 11;
 2771                 break;
 2772         }
 2773 
 2774         if (sc->sc_ic.ic_if.if_flags & IFF_UP) {
 2775                 if (otype != sc->wi_ptype || orate != sc->wi_tx_rate ||
 2776                     ocreate_ibss != sc->wi_create_ibss)
 2777                         wi_init(sc);
 2778         }
 2779 
 2780         ifp->if_baudrate = ifmedia_baudrate(sc->sc_media.ifm_cur->ifm_media);
 2781 
 2782         return (0);
 2783 }
 2784 
 2785 STATIC void
 2786 wi_media_status(struct ifnet *ifp, struct ifmediareq *imr)
 2787 {
 2788         struct wi_softc *sc = ifp->if_softc;
 2789         struct wi_req wreq;
 2790 
 2791         if (!(sc->sc_ic.ic_if.if_flags & IFF_UP)) {
 2792                 imr->ifm_active = IFM_IEEE80211|IFM_NONE;
 2793                 imr->ifm_status = 0;
 2794                 return;
 2795         }
 2796 
 2797         if (sc->wi_tx_rate == 3) {
 2798                 imr->ifm_active = IFM_IEEE80211|IFM_AUTO;
 2799 
 2800                 wreq.wi_type = WI_RID_CUR_TX_RATE;
 2801                 wreq.wi_len = WI_MAX_DATALEN;
 2802                 if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0) {
 2803                         switch (letoh16(wreq.wi_val[0])) {
 2804                         case 1:
 2805                                 imr->ifm_active |= IFM_IEEE80211_DS1;
 2806                                 break;
 2807                         case 2:
 2808                                 imr->ifm_active |= IFM_IEEE80211_DS2;
 2809                                 break;
 2810                         case 6:
 2811                                 imr->ifm_active |= IFM_IEEE80211_DS5;
 2812                                 break;
 2813                         case 11:
 2814                                 imr->ifm_active |= IFM_IEEE80211_DS11;
 2815                                 break;
 2816                         }
 2817                 }
 2818         } else {
 2819                 imr->ifm_active = sc->sc_media.ifm_cur->ifm_media;
 2820         }
 2821 
 2822         imr->ifm_status = IFM_AVALID;
 2823         switch (sc->wi_ptype) {
 2824         case WI_PORTTYPE_ADHOC:
 2825         case WI_PORTTYPE_IBSS:
 2826                 /*
 2827                  * XXX: It would be nice if we could give some actually
 2828                  * useful status like whether we joined another IBSS or
 2829                  * created one ourselves.
 2830                  */
 2831                 /* FALLTHROUGH */
 2832         case WI_PORTTYPE_HOSTAP:
 2833                 imr->ifm_status |= IFM_ACTIVE;
 2834                 break;
 2835         default:
 2836                 wreq.wi_type = WI_RID_COMMQUAL;
 2837                 wreq.wi_len = WI_MAX_DATALEN;
 2838                 if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0 &&
 2839                     letoh16(wreq.wi_val[0]) != 0)
 2840                         imr->ifm_status |= IFM_ACTIVE;
 2841         }
 2842 }
 2843 
 2844 STATIC int
 2845 wi_set_nwkey(struct wi_softc *sc, struct ieee80211_nwkey *nwkey)
 2846 {
 2847         int i, len, error;
 2848         struct wi_req wreq;
 2849         struct wi_ltv_keys *wk = (struct wi_ltv_keys *)&wreq;
 2850 
 2851         if (!(sc->wi_flags & WI_FLAGS_HAS_WEP))
 2852                 return ENODEV;
 2853         if (nwkey->i_defkid <= 0 || nwkey->i_defkid > IEEE80211_WEP_NKID)
 2854                 return EINVAL;
 2855         memcpy(wk, &sc->wi_keys, sizeof(*wk));
 2856         for (i = 0; i < IEEE80211_WEP_NKID; i++) {
 2857                 if (nwkey->i_key[i].i_keydat == NULL)
 2858                         continue;
 2859                 len = nwkey->i_key[i].i_keylen;
 2860                 if (len > sizeof(wk->wi_keys[i].wi_keydat))
 2861                         return EINVAL;
 2862                 error = copyin(nwkey->i_key[i].i_keydat,
 2863                     wk->wi_keys[i].wi_keydat, len);
 2864                 if (error)
 2865                         return error;
 2866                 wk->wi_keys[i].wi_keylen = htole16(len);
 2867         }
 2868 
 2869         wk->wi_len = (sizeof(*wk) / 2) + 1;
 2870         wk->wi_type = WI_RID_DEFLT_CRYPT_KEYS;
 2871         if (sc->sc_ic.ic_if.if_flags & IFF_UP) {
 2872                 error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
 2873                 if (error)
 2874                         return error;
 2875         }
 2876         if ((error = wi_setdef(sc, &wreq)))
 2877                 return (error);
 2878 
 2879         wreq.wi_len = 2;
 2880         wreq.wi_type = WI_RID_TX_CRYPT_KEY;
 2881         wreq.wi_val[0] = htole16(nwkey->i_defkid - 1);
 2882         if (sc->sc_ic.ic_if.if_flags & IFF_UP) {
 2883                 error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
 2884                 if (error)
 2885                         return error;
 2886         }
 2887         if ((error = wi_setdef(sc, &wreq)))
 2888                 return (error);
 2889 
 2890         wreq.wi_type = WI_RID_ENCRYPTION;
 2891         wreq.wi_val[0] = htole16(nwkey->i_wepon);
 2892         if (sc->sc_ic.ic_if.if_flags & IFF_UP) {
 2893                 error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
 2894                 if (error)
 2895                         return error;
 2896         }
 2897         if ((error = wi_setdef(sc, &wreq)))
 2898                 return (error);
 2899 
 2900         if (sc->sc_ic.ic_if.if_flags & IFF_UP)
 2901                 wi_init(sc);
 2902         return 0;
 2903 }
 2904 
 2905 STATIC int
 2906 wi_get_nwkey(struct wi_softc *sc, struct ieee80211_nwkey *nwkey)
 2907 {
 2908         int i;
 2909 
 2910         if (!(sc->wi_flags & WI_FLAGS_HAS_WEP))
 2911                 return ENODEV;
 2912         nwkey->i_wepon = sc->wi_use_wep;
 2913         nwkey->i_defkid = sc->wi_tx_key + 1;
 2914 
 2915         for (i = 0; i < IEEE80211_WEP_NKID; i++) {
 2916                 if (nwkey->i_key[i].i_keydat == NULL)
 2917                         continue;
 2918                 /* do not show any keys to userland */
 2919                 return EPERM;
 2920         }
 2921         return 0;
 2922 }
 2923 
 2924 STATIC int
 2925 wi_set_pm(struct wi_softc *sc, struct ieee80211_power *power)
 2926 {
 2927 
 2928         sc->wi_pm_enabled = power->i_enabled;
 2929         sc->wi_max_sleep = power->i_maxsleep;
 2930 
 2931         if (sc->sc_ic.ic_if.if_flags & IFF_UP)
 2932                 wi_init(sc);
 2933 
 2934         return (0);
 2935 }
 2936 
 2937 STATIC int
 2938 wi_get_pm(struct wi_softc *sc, struct ieee80211_power *power)
 2939 {
 2940 
 2941         power->i_enabled = sc->wi_pm_enabled;
 2942         power->i_maxsleep = sc->wi_max_sleep;
 2943 
 2944         return (0);
 2945 }
 2946 
 2947 STATIC int
 2948 wi_set_txpower(struct wi_softc *sc, struct ieee80211_txpower *txpower)
 2949 {
 2950         u_int16_t       cmd;
 2951         u_int16_t       power;
 2952         int8_t          tmp;
 2953         int             error;
 2954         int             alc;
 2955 
 2956         if (txpower == NULL) {
 2957                 if (!(sc->wi_flags & WI_FLAGS_TXPOWER))
 2958                         return (EINVAL);
 2959                 alc = 0;                /* disable ALC */
 2960         } else {
 2961                 if (txpower->i_mode == IEEE80211_TXPOWER_MODE_AUTO) {
 2962                         alc = 1;        /* enable ALC */
 2963                         sc->wi_flags &= ~WI_FLAGS_TXPOWER;
 2964                 } else {
 2965                         alc = 0;        /* disable ALC */
 2966                         sc->wi_flags |= WI_FLAGS_TXPOWER;
 2967                         sc->wi_txpower = txpower->i_val;
 2968                 }
 2969         }       
 2970 
 2971         /* Set ALC */
 2972         cmd = WI_CMD_DEBUG | (WI_DEBUG_CONFBITS << 8);
 2973         if ((error = wi_cmd(sc, cmd, alc, 0x8, 0)) != 0)
 2974                 return (error);
 2975 
 2976         /* No need to set the TX power value if ALC is enabled */
 2977         if (alc)
 2978                 return (0);
 2979 
 2980         /* Convert dBM to internal TX power value */
 2981         if (sc->wi_txpower > 20)
 2982                 power = 128;
 2983         else if (sc->wi_txpower < -43)
 2984                 power = 127;
 2985         else {
 2986                 tmp = sc->wi_txpower;
 2987                 tmp = -12 - tmp;
 2988                 tmp <<= 2;
 2989 
 2990                 power = (u_int16_t)tmp;
 2991         }
 2992 
 2993         /* Set manual TX power */
 2994         cmd = WI_CMD_WRITE_MIF;
 2995         if ((error = wi_cmd(sc, cmd,
 2996                  WI_HFA384X_CR_MANUAL_TX_POWER, power, 0)) != 0)
 2997                 return (error);
 2998 
 2999         if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
 3000                 printf("%s: %u (%d dBm)\n", sc->sc_dev.dv_xname, power,
 3001                     sc->wi_txpower);
 3002 
 3003         return (0);
 3004 }
 3005 
 3006 STATIC int
 3007 wi_get_txpower(struct wi_softc *sc, struct ieee80211_txpower *txpower)
 3008 {
 3009         u_int16_t       cmd;
 3010         u_int16_t       power;
 3011         int8_t          tmp;
 3012         int             error;
 3013 
 3014         if (sc->wi_flags & WI_FLAGS_BUS_USB)
 3015                 return (EOPNOTSUPP);
 3016 
 3017         /* Get manual TX power */
 3018         cmd = WI_CMD_READ_MIF;
 3019         if ((error = wi_cmd(sc, cmd,
 3020                  WI_HFA384X_CR_MANUAL_TX_POWER, 0, 0)) != 0)
 3021                 return (error);
 3022 
 3023         power = CSR_READ_2(sc, WI_RESP0);
 3024 
 3025         /* Convert internal TX power value to dBM */
 3026         if (power > 255)
 3027                 txpower->i_val = 255;
 3028         else {
 3029                 tmp = power;
 3030                 tmp >>= 2;
 3031                 txpower->i_val = (u_int16_t)(-12 - tmp);
 3032         }
 3033 
 3034         if (sc->wi_flags & WI_FLAGS_TXPOWER)
 3035                 txpower->i_mode = IEEE80211_TXPOWER_MODE_FIXED;
 3036         else
 3037                 txpower->i_mode = IEEE80211_TXPOWER_MODE_AUTO;
 3038         
 3039         return (0);
 3040 }
 3041 
 3042 STATIC int
 3043 wi_set_ssid(struct ieee80211_nwid *ws, u_int8_t *id, int len)
 3044 {
 3045 
 3046         if (len > IEEE80211_NWID_LEN)
 3047                 return (EINVAL);
 3048         ws->i_len = len;
 3049         memcpy(ws->i_nwid, id, len);
 3050         return (0);
 3051 }
 3052 
 3053 STATIC int
 3054 wi_get_debug(struct wi_softc *sc, struct wi_req *wreq)
 3055 {
 3056         int                     error = 0;
 3057 
 3058         wreq->wi_len = 1;
 3059 
 3060         switch (wreq->wi_type) {
 3061         case WI_DEBUG_SLEEP:
 3062                 wreq->wi_len++;
 3063                 wreq->wi_val[0] = htole16(sc->wi_debug.wi_sleep);
 3064                 break;
 3065         case WI_DEBUG_DELAYSUPP:
 3066                 wreq->wi_len++;
 3067                 wreq->wi_val[0] = htole16(sc->wi_debug.wi_delaysupp);
 3068                 break;
 3069         case WI_DEBUG_TXSUPP:
 3070                 wreq->wi_len++;
 3071                 wreq->wi_val[0] = htole16(sc->wi_debug.wi_txsupp);
 3072                 break;
 3073         case WI_DEBUG_MONITOR:
 3074                 wreq->wi_len++;
 3075                 wreq->wi_val[0] = htole16(sc->wi_debug.wi_monitor);
 3076                 break;
 3077         case WI_DEBUG_LEDTEST:
 3078                 wreq->wi_len += 3;
 3079                 wreq->wi_val[0] = htole16(sc->wi_debug.wi_ledtest);
 3080                 wreq->wi_val[1] = htole16(sc->wi_debug.wi_ledtest_param0);
 3081                 wreq->wi_val[2] = htole16(sc->wi_debug.wi_ledtest_param1);
 3082                 break;
 3083         case WI_DEBUG_CONTTX:
 3084                 wreq->wi_len += 2;
 3085                 wreq->wi_val[0] = htole16(sc->wi_debug.wi_conttx);
 3086                 wreq->wi_val[1] = htole16(sc->wi_debug.wi_conttx_param0);
 3087                 break;
 3088         case WI_DEBUG_CONTRX:
 3089                 wreq->wi_len++;
 3090                 wreq->wi_val[0] = htole16(sc->wi_debug.wi_contrx);
 3091                 break;
 3092         case WI_DEBUG_SIGSTATE:
 3093                 wreq->wi_len += 2;
 3094                 wreq->wi_val[0] = htole16(sc->wi_debug.wi_sigstate);
 3095                 wreq->wi_val[1] = htole16(sc->wi_debug.wi_sigstate_param0);
 3096                 break;
 3097         case WI_DEBUG_CONFBITS:
 3098                 wreq->wi_len += 2;
 3099                 wreq->wi_val[0] = htole16(sc->wi_debug.wi_confbits);
 3100                 wreq->wi_val[1] = htole16(sc->wi_debug.wi_confbits_param0);
 3101                 break;
 3102         default:
 3103                 error = EIO;
 3104                 break;
 3105         }
 3106 
 3107         return (error);
 3108 }
 3109 
 3110 STATIC int
 3111 wi_set_debug(struct wi_softc *sc, struct wi_req *wreq)
 3112 {
 3113         int                             error = 0;
 3114         u_int16_t                       cmd, param0 = 0, param1 = 0;
 3115 
 3116         switch (wreq->wi_type) {
 3117         case WI_DEBUG_RESET:
 3118         case WI_DEBUG_INIT:
 3119         case WI_DEBUG_CALENABLE:
 3120                 break;
 3121         case WI_DEBUG_SLEEP:
 3122                 sc->wi_debug.wi_sleep = 1;
 3123                 break;
 3124         case WI_DEBUG_WAKE:
 3125                 sc->wi_debug.wi_sleep = 0;
 3126                 break;
 3127         case WI_DEBUG_CHAN:
 3128                 param0 = letoh16(wreq->wi_val[0]);
 3129                 break;
 3130         case WI_DEBUG_DELAYSUPP:
 3131                 sc->wi_debug.wi_delaysupp = 1;
 3132                 break;
 3133         case WI_DEBUG_TXSUPP:
 3134                 sc->wi_debug.wi_txsupp = 1;
 3135                 break;
 3136         case WI_DEBUG_MONITOR:
 3137                 sc->wi_debug.wi_monitor = 1;
 3138                 break;
 3139         case WI_DEBUG_LEDTEST:
 3140                 param0 = letoh16(wreq->wi_val[0]);
 3141                 param1 = letoh16(wreq->wi_val[1]);
 3142                 sc->wi_debug.wi_ledtest = 1;
 3143                 sc->wi_debug.wi_ledtest_param0 = param0;
 3144                 sc->wi_debug.wi_ledtest_param1 = param1;
 3145                 break;
 3146         case WI_DEBUG_CONTTX:
 3147                 param0 = letoh16(wreq->wi_val[0]);
 3148                 sc->wi_debug.wi_conttx = 1;
 3149                 sc->wi_debug.wi_conttx_param0 = param0;
 3150                 break;
 3151         case WI_DEBUG_STOPTEST:
 3152                 sc->wi_debug.wi_delaysupp = 0;
 3153                 sc->wi_debug.wi_txsupp = 0;
 3154                 sc->wi_debug.wi_monitor = 0;
 3155                 sc->wi_debug.wi_ledtest = 0;
 3156                 sc->wi_debug.wi_ledtest_param0 = 0;
 3157                 sc->wi_debug.wi_ledtest_param1 = 0;
 3158                 sc->wi_debug.wi_conttx = 0;
 3159                 sc->wi_debug.wi_conttx_param0 = 0;
 3160                 sc->wi_debug.wi_contrx = 0;
 3161                 sc->wi_debug.wi_sigstate = 0;
 3162                 sc->wi_debug.wi_sigstate_param0 = 0;
 3163                 break;
 3164         case WI_DEBUG_CONTRX:
 3165                 sc->wi_debug.wi_contrx = 1;
 3166                 break;
 3167         case WI_DEBUG_SIGSTATE:
 3168                 param0 = letoh16(wreq->wi_val[0]);
 3169                 sc->wi_debug.wi_sigstate = 1;
 3170                 sc->wi_debug.wi_sigstate_param0 = param0;
 3171                 break;
 3172         case WI_DEBUG_CONFBITS:
 3173                 param0 = letoh16(wreq->wi_val[0]);
 3174                 param1 = letoh16(wreq->wi_val[1]);
 3175                 sc->wi_debug.wi_confbits = param0;
 3176                 sc->wi_debug.wi_confbits_param0 = param1;
 3177                 break;
 3178         default:
 3179                 error = EIO;
 3180                 break;
 3181         }
 3182 
 3183         if (error)
 3184                 return (error);
 3185 
 3186         cmd = WI_CMD_DEBUG | (wreq->wi_type << 8);
 3187         error = wi_cmd(sc, cmd, param0, param1, 0);
 3188 
 3189         return (error);
 3190 }

Cache object: e59b637c127509ebad8fc6973e3a8526


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