LCOV - code coverage report
Current view: top level - dev/ic - if_wi.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 1716 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 43 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13