Home | History | Annotate | Line # | Download | only in ic
wi.c revision 1.17.2.16
      1  1.17.2.16  nathanw /*	$NetBSD: wi.c,v 1.17.2.16 2002/08/13 02:19:30 nathanw Exp $	*/
      2   1.17.2.2  nathanw 
      3   1.17.2.2  nathanw /*
      4   1.17.2.2  nathanw  * Copyright (c) 1997, 1998, 1999
      5   1.17.2.2  nathanw  *	Bill Paul <wpaul (at) ctr.columbia.edu>.  All rights reserved.
      6   1.17.2.2  nathanw  *
      7   1.17.2.2  nathanw  * Redistribution and use in source and binary forms, with or without
      8   1.17.2.2  nathanw  * modification, are permitted provided that the following conditions
      9   1.17.2.2  nathanw  * are met:
     10   1.17.2.2  nathanw  * 1. Redistributions of source code must retain the above copyright
     11   1.17.2.2  nathanw  *    notice, this list of conditions and the following disclaimer.
     12   1.17.2.2  nathanw  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.17.2.2  nathanw  *    notice, this list of conditions and the following disclaimer in the
     14   1.17.2.2  nathanw  *    documentation and/or other materials provided with the distribution.
     15   1.17.2.2  nathanw  * 3. All advertising materials mentioning features or use of this software
     16   1.17.2.2  nathanw  *    must display the following acknowledgement:
     17   1.17.2.2  nathanw  *	This product includes software developed by Bill Paul.
     18   1.17.2.2  nathanw  * 4. Neither the name of the author nor the names of any co-contributors
     19   1.17.2.2  nathanw  *    may be used to endorse or promote products derived from this software
     20   1.17.2.2  nathanw  *    without specific prior written permission.
     21   1.17.2.2  nathanw  *
     22   1.17.2.2  nathanw  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
     23   1.17.2.2  nathanw  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24   1.17.2.2  nathanw  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25   1.17.2.2  nathanw  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
     26   1.17.2.2  nathanw  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     27   1.17.2.2  nathanw  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     28   1.17.2.2  nathanw  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     29   1.17.2.2  nathanw  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     30   1.17.2.2  nathanw  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     31   1.17.2.2  nathanw  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     32   1.17.2.2  nathanw  * THE POSSIBILITY OF SUCH DAMAGE.
     33   1.17.2.2  nathanw  */
     34   1.17.2.2  nathanw 
     35   1.17.2.2  nathanw /*
     36   1.17.2.2  nathanw  * Lucent WaveLAN/IEEE 802.11 PCMCIA driver for NetBSD.
     37   1.17.2.2  nathanw  *
     38   1.17.2.2  nathanw  * Original FreeBSD driver written by Bill Paul <wpaul (at) ctr.columbia.edu>
     39   1.17.2.2  nathanw  * Electrical Engineering Department
     40   1.17.2.2  nathanw  * Columbia University, New York City
     41   1.17.2.2  nathanw  */
     42   1.17.2.2  nathanw 
     43   1.17.2.2  nathanw /*
     44   1.17.2.2  nathanw  * The WaveLAN/IEEE adapter is the second generation of the WaveLAN
     45   1.17.2.2  nathanw  * from Lucent. Unlike the older cards, the new ones are programmed
     46   1.17.2.2  nathanw  * entirely via a firmware-driven controller called the Hermes.
     47   1.17.2.2  nathanw  * Unfortunately, Lucent will not release the Hermes programming manual
     48   1.17.2.2  nathanw  * without an NDA (if at all). What they do release is an API library
     49   1.17.2.2  nathanw  * called the HCF (Hardware Control Functions) which is supposed to
     50   1.17.2.2  nathanw  * do the device-specific operations of a device driver for you. The
     51   1.17.2.2  nathanw  * publically available version of the HCF library (the 'HCF Light') is
     52   1.17.2.2  nathanw  * a) extremely gross, b) lacks certain features, particularly support
     53   1.17.2.2  nathanw  * for 802.11 frames, and c) is contaminated by the GNU Public License.
     54   1.17.2.2  nathanw  *
     55   1.17.2.2  nathanw  * This driver does not use the HCF or HCF Light at all. Instead, it
     56   1.17.2.2  nathanw  * programs the Hermes controller directly, using information gleaned
     57   1.17.2.2  nathanw  * from the HCF Light code and corresponding documentation.
     58   1.17.2.2  nathanw  *
     59   1.17.2.2  nathanw  * This driver supports both the PCMCIA and ISA versions of the
     60   1.17.2.2  nathanw  * WaveLAN/IEEE cards. Note however that the ISA card isn't really
     61   1.17.2.2  nathanw  * anything of the sort: it's actually a PCMCIA bridge adapter
     62   1.17.2.2  nathanw  * that fits into an ISA slot, into which a PCMCIA WaveLAN card is
     63   1.17.2.2  nathanw  * inserted. Consequently, you need to use the pccard support for
     64   1.17.2.2  nathanw  * both the ISA and PCMCIA adapters.
     65   1.17.2.2  nathanw  */
     66   1.17.2.2  nathanw 
     67   1.17.2.2  nathanw /*
     68   1.17.2.2  nathanw  * FreeBSD driver ported to NetBSD by Bill Sommerfeld in the back of the
     69   1.17.2.2  nathanw  * Oslo IETF plenary meeting.
     70   1.17.2.2  nathanw  */
     71   1.17.2.2  nathanw 
     72   1.17.2.8  nathanw #include <sys/cdefs.h>
     73  1.17.2.16  nathanw __KERNEL_RCSID(0, "$NetBSD: wi.c,v 1.17.2.16 2002/08/13 02:19:30 nathanw Exp $");
     74   1.17.2.8  nathanw 
     75   1.17.2.2  nathanw #define WI_HERMES_AUTOINC_WAR	/* Work around data write autoinc bug. */
     76   1.17.2.2  nathanw #define WI_HERMES_STATS_WAR	/* Work around stats counter bug. */
     77   1.17.2.2  nathanw 
     78   1.17.2.2  nathanw #include "bpfilter.h"
     79   1.17.2.2  nathanw 
     80   1.17.2.2  nathanw #include <sys/param.h>
     81   1.17.2.2  nathanw #include <sys/systm.h>
     82   1.17.2.2  nathanw #include <sys/callout.h>
     83   1.17.2.2  nathanw #include <sys/device.h>
     84   1.17.2.2  nathanw #include <sys/socket.h>
     85   1.17.2.2  nathanw #include <sys/mbuf.h>
     86   1.17.2.2  nathanw #include <sys/ioctl.h>
     87   1.17.2.2  nathanw #include <sys/kernel.h>		/* for hz */
     88   1.17.2.2  nathanw #include <sys/proc.h>
     89   1.17.2.2  nathanw 
     90   1.17.2.2  nathanw #include <net/if.h>
     91   1.17.2.2  nathanw #include <net/if_dl.h>
     92   1.17.2.2  nathanw #include <net/if_media.h>
     93   1.17.2.2  nathanw #include <net/if_ether.h>
     94   1.17.2.2  nathanw #include <net/if_ieee80211.h>
     95   1.17.2.2  nathanw 
     96   1.17.2.2  nathanw #if NBPFILTER > 0
     97   1.17.2.2  nathanw #include <net/bpf.h>
     98   1.17.2.2  nathanw #include <net/bpfdesc.h>
     99   1.17.2.2  nathanw #endif
    100   1.17.2.2  nathanw 
    101   1.17.2.3  nathanw #include <machine/bus.h>
    102   1.17.2.2  nathanw 
    103   1.17.2.2  nathanw #include <dev/ic/wi_ieee.h>
    104   1.17.2.2  nathanw #include <dev/ic/wireg.h>
    105   1.17.2.2  nathanw #include <dev/ic/wivar.h>
    106   1.17.2.2  nathanw 
    107   1.17.2.2  nathanw static void wi_reset		__P((struct wi_softc *));
    108   1.17.2.2  nathanw static int wi_ioctl		__P((struct ifnet *, u_long, caddr_t));
    109   1.17.2.2  nathanw static void wi_start		__P((struct ifnet *));
    110   1.17.2.2  nathanw static void wi_watchdog		__P((struct ifnet *));
    111   1.17.2.2  nathanw static int wi_init		__P((struct ifnet *));
    112   1.17.2.2  nathanw static void wi_stop		__P((struct ifnet *, int));
    113   1.17.2.2  nathanw static void wi_rxeof		__P((struct wi_softc *));
    114   1.17.2.2  nathanw static void wi_txeof		__P((struct wi_softc *, int));
    115   1.17.2.2  nathanw static void wi_update_stats	__P((struct wi_softc *));
    116   1.17.2.2  nathanw static void wi_setmulti		__P((struct wi_softc *));
    117   1.17.2.2  nathanw 
    118  1.17.2.16  nathanw static int wi_cmd		__P((struct wi_softc *, int, int, int, int));
    119   1.17.2.2  nathanw static int wi_read_record	__P((struct wi_softc *, struct wi_ltv_gen *));
    120   1.17.2.2  nathanw static int wi_write_record	__P((struct wi_softc *, struct wi_ltv_gen *));
    121   1.17.2.2  nathanw static int wi_read_data		__P((struct wi_softc *, int,
    122   1.17.2.2  nathanw 					int, caddr_t, int));
    123   1.17.2.2  nathanw static int wi_write_data	__P((struct wi_softc *, int,
    124   1.17.2.2  nathanw 					int, caddr_t, int));
    125   1.17.2.2  nathanw static int wi_seek		__P((struct wi_softc *, int, int, int));
    126   1.17.2.2  nathanw static int wi_alloc_nicmem	__P((struct wi_softc *, int, int *));
    127   1.17.2.7  nathanw static void wi_inquire		__P((void *));
    128  1.17.2.10  nathanw static void wi_wait_scan	__P((void *));
    129   1.17.2.2  nathanw static int wi_setdef		__P((struct wi_softc *, struct wi_req *));
    130   1.17.2.2  nathanw static int wi_getdef		__P((struct wi_softc *, struct wi_req *));
    131   1.17.2.2  nathanw 
    132   1.17.2.2  nathanw static int wi_media_change __P((struct ifnet *));
    133   1.17.2.2  nathanw static void wi_media_status __P((struct ifnet *, struct ifmediareq *));
    134   1.17.2.2  nathanw 
    135   1.17.2.2  nathanw static void wi_get_id		__P((struct wi_softc *));
    136   1.17.2.2  nathanw 
    137   1.17.2.2  nathanw static int wi_set_ssid __P((struct ieee80211_nwid *, u_int8_t *, int));
    138   1.17.2.2  nathanw static void wi_request_fill_ssid __P((struct wi_req *,
    139   1.17.2.2  nathanw     struct ieee80211_nwid *));
    140   1.17.2.2  nathanw static int wi_write_ssid __P((struct wi_softc *, int, struct wi_req *,
    141   1.17.2.2  nathanw     struct ieee80211_nwid *));
    142   1.17.2.2  nathanw static int wi_set_nwkey __P((struct wi_softc *, struct ieee80211_nwkey *));
    143   1.17.2.2  nathanw static int wi_get_nwkey __P((struct wi_softc *, struct ieee80211_nwkey *));
    144   1.17.2.2  nathanw static int wi_sync_media __P((struct wi_softc *, int, int));
    145   1.17.2.2  nathanw static int wi_set_pm(struct wi_softc *, struct ieee80211_power *);
    146   1.17.2.2  nathanw static int wi_get_pm(struct wi_softc *, struct ieee80211_power *);
    147   1.17.2.2  nathanw 
    148  1.17.2.12  nathanw struct wi_card_ident wi_card_ident[] = {
    149  1.17.2.16  nathanw 	/* CARD_ID			CARD_NAME		FIRM_TYPE */
    150  1.17.2.12  nathanw 	{ WI_NIC_LUCENT_ID,		WI_NIC_LUCENT_STR,	WI_LUCENT },
    151  1.17.2.12  nathanw 	{ WI_NIC_SONY_ID,		WI_NIC_SONY_STR,	WI_LUCENT },
    152  1.17.2.12  nathanw 	{ WI_NIC_LUCENT_EMB_ID,		WI_NIC_LUCENT_EMB_STR,	WI_LUCENT },
    153  1.17.2.12  nathanw 	{ WI_NIC_EVB2_ID,		WI_NIC_EVB2_STR,	WI_INTERSIL },
    154  1.17.2.12  nathanw 	{ WI_NIC_HWB3763_ID,		WI_NIC_HWB3763_STR,	WI_INTERSIL },
    155  1.17.2.12  nathanw 	{ WI_NIC_HWB3163_ID,		WI_NIC_HWB3163_STR,	WI_INTERSIL },
    156  1.17.2.12  nathanw 	{ WI_NIC_HWB3163B_ID,		WI_NIC_HWB3163B_STR,	WI_INTERSIL },
    157  1.17.2.12  nathanw 	{ WI_NIC_EVB3_ID,		WI_NIC_EVB3_STR,	WI_INTERSIL },
    158  1.17.2.12  nathanw 	{ WI_NIC_HWB1153_ID,		WI_NIC_HWB1153_STR,	WI_INTERSIL },
    159  1.17.2.12  nathanw 	{ WI_NIC_P2_SST_ID,		WI_NIC_P2_SST_STR,	WI_INTERSIL },
    160  1.17.2.12  nathanw 	{ WI_NIC_EVB2_SST_ID,		WI_NIC_EVB2_SST_STR,	WI_INTERSIL },
    161  1.17.2.12  nathanw 	{ WI_NIC_3842_EVA_ID,		WI_NIC_3842_EVA_STR,	WI_INTERSIL },
    162  1.17.2.12  nathanw 	{ WI_NIC_3842_PCMCIA_AMD_ID,	WI_NIC_3842_PCMCIA_STR,	WI_INTERSIL },
    163  1.17.2.12  nathanw 	{ WI_NIC_3842_PCMCIA_SST_ID,	WI_NIC_3842_PCMCIA_STR,	WI_INTERSIL },
    164  1.17.2.12  nathanw 	{ WI_NIC_3842_PCMCIA_ATM_ID,	WI_NIC_3842_PCMCIA_STR,	WI_INTERSIL },
    165  1.17.2.12  nathanw 	{ WI_NIC_3842_MINI_AMD_ID,	WI_NIC_3842_MINI_STR,	WI_INTERSIL },
    166  1.17.2.12  nathanw 	{ WI_NIC_3842_MINI_SST_ID,	WI_NIC_3842_MINI_STR,	WI_INTERSIL },
    167  1.17.2.12  nathanw 	{ WI_NIC_3842_MINI_ATM_ID,	WI_NIC_3842_MINI_STR,	WI_INTERSIL },
    168  1.17.2.12  nathanw 	{ WI_NIC_3842_PCI_AMD_ID,	WI_NIC_3842_PCI_STR,	WI_INTERSIL },
    169  1.17.2.12  nathanw 	{ WI_NIC_3842_PCI_SST_ID,	WI_NIC_3842_PCI_STR,	WI_INTERSIL },
    170  1.17.2.12  nathanw 	{ WI_NIC_3842_PCI_ATM_ID,	WI_NIC_3842_PCI_STR,	WI_INTERSIL },
    171  1.17.2.12  nathanw 	{ WI_NIC_P3_PCMCIA_AMD_ID,	WI_NIC_P3_PCMCIA_STR,	WI_INTERSIL },
    172  1.17.2.12  nathanw 	{ WI_NIC_P3_PCMCIA_SST_ID,	WI_NIC_P3_PCMCIA_STR,	WI_INTERSIL },
    173  1.17.2.12  nathanw 	{ WI_NIC_P3_MINI_AMD_ID,	WI_NIC_P3_MINI_STR,	WI_INTERSIL },
    174  1.17.2.12  nathanw 	{ WI_NIC_P3_MINI_SST_ID,	WI_NIC_P3_MINI_STR,	WI_INTERSIL },
    175  1.17.2.12  nathanw 	{ 0,	NULL,	0 },
    176  1.17.2.12  nathanw };
    177  1.17.2.12  nathanw 
    178   1.17.2.2  nathanw int
    179   1.17.2.2  nathanw wi_attach(sc)
    180   1.17.2.2  nathanw 	struct wi_softc *sc;
    181   1.17.2.2  nathanw {
    182   1.17.2.2  nathanw 	struct ifnet *ifp = sc->sc_ifp;
    183  1.17.2.16  nathanw 	const char *sep = "";
    184   1.17.2.2  nathanw 	struct wi_ltv_macaddr   mac;
    185   1.17.2.2  nathanw 	struct wi_ltv_gen       gen;
    186   1.17.2.2  nathanw 	static const u_int8_t empty_macaddr[ETHER_ADDR_LEN] = {
    187   1.17.2.2  nathanw 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    188   1.17.2.2  nathanw 	};
    189   1.17.2.2  nathanw 	int s;
    190   1.17.2.2  nathanw 
    191   1.17.2.2  nathanw 	s = splnet();
    192   1.17.2.2  nathanw 
    193   1.17.2.7  nathanw 	callout_init(&sc->wi_inquire_ch);
    194  1.17.2.10  nathanw 	callout_init(&sc->wi_scan_sh);
    195   1.17.2.2  nathanw 
    196   1.17.2.2  nathanw 	/* Make sure interrupts are disabled. */
    197   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_INT_EN, 0);
    198   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
    199   1.17.2.2  nathanw 
    200   1.17.2.2  nathanw 	/* Reset the NIC. */
    201   1.17.2.2  nathanw 	wi_reset(sc);
    202   1.17.2.2  nathanw 
    203   1.17.2.2  nathanw 	memset(&mac, 0, sizeof(mac));
    204   1.17.2.2  nathanw 	/* Read the station address. */
    205   1.17.2.2  nathanw 	mac.wi_type = WI_RID_MAC_NODE;
    206   1.17.2.2  nathanw 	mac.wi_len = 4;
    207   1.17.2.2  nathanw 	wi_read_record(sc, (struct wi_ltv_gen *)&mac);
    208   1.17.2.2  nathanw 	memcpy(sc->sc_macaddr, mac.wi_mac_addr, ETHER_ADDR_LEN);
    209   1.17.2.2  nathanw 
    210   1.17.2.2  nathanw 	/*
    211   1.17.2.2  nathanw 	 * Check if we got anything meaningful.
    212   1.17.2.2  nathanw 	 *
    213   1.17.2.2  nathanw 	 * Is it really enough just checking against null ethernet address?
    214   1.17.2.2  nathanw 	 * Or, check against possible vendor?  XXX.
    215   1.17.2.2  nathanw 	 */
    216   1.17.2.3  nathanw 	if (memcmp(sc->sc_macaddr, empty_macaddr, ETHER_ADDR_LEN) == 0) {
    217  1.17.2.12  nathanw 		printf("could not get mac address, attach failed\n");
    218  1.17.2.10  nathanw 		splx(s);
    219  1.17.2.10  nathanw 		return 1;
    220   1.17.2.2  nathanw 	}
    221   1.17.2.2  nathanw 
    222   1.17.2.2  nathanw 	printf(" 802.11 address %s\n", ether_sprintf(sc->sc_macaddr));
    223   1.17.2.2  nathanw 
    224   1.17.2.2  nathanw 	/* Read NIC identification */
    225   1.17.2.2  nathanw 	wi_get_id(sc);
    226   1.17.2.2  nathanw 
    227   1.17.2.2  nathanw 	memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
    228   1.17.2.2  nathanw 	ifp->if_softc = sc;
    229   1.17.2.2  nathanw 	ifp->if_start = wi_start;
    230   1.17.2.2  nathanw 	ifp->if_ioctl = wi_ioctl;
    231   1.17.2.2  nathanw 	ifp->if_watchdog = wi_watchdog;
    232   1.17.2.2  nathanw 	ifp->if_init = wi_init;
    233   1.17.2.2  nathanw 	ifp->if_stop = wi_stop;
    234   1.17.2.2  nathanw 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
    235   1.17.2.2  nathanw #ifdef IFF_NOTRAILERS
    236   1.17.2.2  nathanw 	ifp->if_flags |= IFF_NOTRAILERS;
    237   1.17.2.2  nathanw #endif
    238   1.17.2.2  nathanw 	IFQ_SET_READY(&ifp->if_snd);
    239   1.17.2.2  nathanw 
    240   1.17.2.2  nathanw 	(void)wi_set_ssid(&sc->wi_nodeid, WI_DEFAULT_NODENAME,
    241   1.17.2.2  nathanw 	    sizeof(WI_DEFAULT_NODENAME) - 1);
    242   1.17.2.2  nathanw 	(void)wi_set_ssid(&sc->wi_netid, WI_DEFAULT_NETNAME,
    243   1.17.2.2  nathanw 	    sizeof(WI_DEFAULT_NETNAME) - 1);
    244   1.17.2.2  nathanw 	(void)wi_set_ssid(&sc->wi_ibssid, WI_DEFAULT_IBSS,
    245   1.17.2.2  nathanw 	    sizeof(WI_DEFAULT_IBSS) - 1);
    246   1.17.2.2  nathanw 
    247   1.17.2.2  nathanw 	sc->wi_portnum = WI_DEFAULT_PORT;
    248   1.17.2.2  nathanw 	sc->wi_ptype = WI_PORTTYPE_BSS;
    249   1.17.2.2  nathanw 	sc->wi_ap_density = WI_DEFAULT_AP_DENSITY;
    250   1.17.2.2  nathanw 	sc->wi_rts_thresh = WI_DEFAULT_RTS_THRESH;
    251   1.17.2.2  nathanw 	sc->wi_tx_rate = WI_DEFAULT_TX_RATE;
    252   1.17.2.2  nathanw 	sc->wi_max_data_len = WI_DEFAULT_DATALEN;
    253   1.17.2.2  nathanw 	sc->wi_create_ibss = WI_DEFAULT_CREATE_IBSS;
    254   1.17.2.2  nathanw 	sc->wi_pm_enabled = WI_DEFAULT_PM_ENABLED;
    255   1.17.2.2  nathanw 	sc->wi_max_sleep = WI_DEFAULT_MAX_SLEEP;
    256   1.17.2.2  nathanw 	sc->wi_roaming = WI_DEFAULT_ROAMING;
    257   1.17.2.2  nathanw 	sc->wi_authtype = WI_DEFAULT_AUTHTYPE;
    258   1.17.2.2  nathanw 
    259   1.17.2.2  nathanw 	/*
    260   1.17.2.2  nathanw 	 * Read the default channel from the NIC. This may vary
    261   1.17.2.2  nathanw 	 * depending on the country where the NIC was purchased, so
    262   1.17.2.2  nathanw 	 * we can't hard-code a default and expect it to work for
    263   1.17.2.2  nathanw 	 * everyone.
    264   1.17.2.2  nathanw 	 */
    265   1.17.2.2  nathanw 	gen.wi_type = WI_RID_OWN_CHNL;
    266   1.17.2.2  nathanw 	gen.wi_len = 2;
    267   1.17.2.2  nathanw 	wi_read_record(sc, &gen);
    268   1.17.2.2  nathanw 	sc->wi_channel = le16toh(gen.wi_val);
    269   1.17.2.2  nathanw 
    270   1.17.2.3  nathanw 	memset((char *)&sc->wi_stats, 0, sizeof(sc->wi_stats));
    271   1.17.2.2  nathanw 
    272  1.17.2.10  nathanw 	/* AP info was filled with 0 */
    273  1.17.2.10  nathanw 	memset((char *)&sc->wi_aps, 0, sizeof(sc->wi_aps));
    274  1.17.2.16  nathanw 	sc->wi_scanning = 0;
    275  1.17.2.16  nathanw 	sc->wi_naps = 0;
    276  1.17.2.16  nathanw 
    277  1.17.2.16  nathanw 	/*
    278  1.17.2.16  nathanw 	 * Set flags based on firmware version.
    279  1.17.2.16  nathanw 	 */
    280  1.17.2.16  nathanw 	switch (sc->sc_firmware_type) {
    281  1.17.2.16  nathanw 	case WI_LUCENT:
    282  1.17.2.16  nathanw 		sc->wi_flags |= WI_FLAGS_HAS_ROAMING;
    283  1.17.2.16  nathanw 		if (sc->sc_sta_firmware_ver >= 60000)
    284  1.17.2.16  nathanw 			sc->wi_flags |= WI_FLAGS_HAS_MOR;
    285  1.17.2.16  nathanw 		if (sc->sc_sta_firmware_ver >= 60006) {
    286  1.17.2.16  nathanw 			sc->wi_flags |= WI_FLAGS_HAS_IBSS;
    287  1.17.2.16  nathanw 			sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS;
    288  1.17.2.16  nathanw 		}
    289  1.17.2.16  nathanw 		sc->wi_ibss_port = htole16(1);
    290  1.17.2.16  nathanw 		break;
    291  1.17.2.16  nathanw 
    292  1.17.2.16  nathanw 	case WI_INTERSIL:
    293  1.17.2.16  nathanw 		sc->wi_flags |= WI_FLAGS_HAS_ROAMING;
    294  1.17.2.16  nathanw 		if (sc->sc_sta_firmware_ver >= 800) {
    295  1.17.2.16  nathanw 			sc->wi_flags |= WI_FLAGS_HAS_HOSTAP;
    296  1.17.2.16  nathanw 			sc->wi_flags |= WI_FLAGS_HAS_IBSS;
    297  1.17.2.16  nathanw 			sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS;
    298  1.17.2.16  nathanw 		}
    299  1.17.2.16  nathanw 		sc->wi_ibss_port = htole16(0);
    300  1.17.2.16  nathanw 		break;
    301  1.17.2.16  nathanw 
    302  1.17.2.16  nathanw 	case WI_SYMBOL:
    303  1.17.2.16  nathanw 		sc->wi_flags |= WI_FLAGS_HAS_DIVERSITY;
    304  1.17.2.16  nathanw 		if (sc->sc_sta_firmware_ver >= 20000)
    305  1.17.2.16  nathanw 			sc->wi_flags |= WI_FLAGS_HAS_IBSS;
    306  1.17.2.16  nathanw 		if (sc->sc_sta_firmware_ver >= 25000)
    307  1.17.2.16  nathanw 			sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS;
    308  1.17.2.16  nathanw 		sc->wi_ibss_port = htole16(4);
    309  1.17.2.16  nathanw 		break;
    310  1.17.2.16  nathanw 	}
    311  1.17.2.10  nathanw 
    312   1.17.2.2  nathanw 	/*
    313   1.17.2.2  nathanw 	 * Find out if we support WEP on this card.
    314   1.17.2.2  nathanw 	 */
    315   1.17.2.2  nathanw 	gen.wi_type = WI_RID_WEP_AVAIL;
    316   1.17.2.2  nathanw 	gen.wi_len = 2;
    317  1.17.2.16  nathanw 	if (wi_read_record(sc, &gen) == 0 &&
    318  1.17.2.16  nathanw 	    gen.wi_val != le16toh(0))
    319  1.17.2.16  nathanw 		sc->wi_flags |= WI_FLAGS_HAS_WEP;
    320  1.17.2.16  nathanw 
    321  1.17.2.16  nathanw 	/* Find supported rates. */
    322  1.17.2.16  nathanw 	gen.wi_type = WI_RID_DATA_RATES;
    323  1.17.2.16  nathanw 	gen.wi_len = 2;
    324  1.17.2.16  nathanw 	if (wi_read_record(sc, &gen))
    325  1.17.2.16  nathanw 		sc->wi_supprates = WI_SUPPRATES_1M | WI_SUPPRATES_2M |
    326  1.17.2.16  nathanw 		    WI_SUPPRATES_5M | WI_SUPPRATES_11M;
    327  1.17.2.16  nathanw 	else
    328  1.17.2.16  nathanw 		sc->wi_supprates = le16toh(gen.wi_val);
    329   1.17.2.2  nathanw 
    330   1.17.2.2  nathanw 	ifmedia_init(&sc->sc_media, 0, wi_media_change, wi_media_status);
    331  1.17.2.16  nathanw 	if (sc->wi_supprates != 0)
    332  1.17.2.16  nathanw 		printf("%s: supported rates: ", sc->sc_dev.dv_xname);
    333   1.17.2.2  nathanw #define	ADD(m, c)	ifmedia_add(&sc->sc_media, (m), (c), NULL)
    334  1.17.2.16  nathanw #define	PRINT(n)	printf("%s%s", sep, (n)); sep = ", "
    335   1.17.2.2  nathanw 	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0), 0);
    336  1.17.2.11  nathanw 	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, IFM_IEEE80211_ADHOC, 0), 0);
    337  1.17.2.16  nathanw 	if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
    338  1.17.2.16  nathanw 		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, IFM_IEEE80211_IBSS,
    339  1.17.2.16  nathanw 		    0), 0);
    340  1.17.2.16  nathanw 	if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
    341  1.17.2.16  nathanw 		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
    342  1.17.2.16  nathanw 		    IFM_IEEE80211_IBSSMASTER, 0), 0);
    343  1.17.2.16  nathanw 	if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
    344  1.17.2.16  nathanw 		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
    345  1.17.2.16  nathanw 		    IFM_IEEE80211_HOSTAP, 0), 0);
    346  1.17.2.16  nathanw 	if (sc->wi_supprates & WI_SUPPRATES_1M) {
    347  1.17.2.16  nathanw 		PRINT("1Mbps");
    348  1.17.2.16  nathanw 		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 0, 0), 0);
    349  1.17.2.16  nathanw 		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
    350  1.17.2.16  nathanw 		    IFM_IEEE80211_ADHOC, 0), 0);
    351  1.17.2.16  nathanw 		if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
    352  1.17.2.16  nathanw 			ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
    353  1.17.2.16  nathanw 			    IFM_IEEE80211_IBSS, 0), 0);
    354  1.17.2.16  nathanw 		if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
    355  1.17.2.16  nathanw 			ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
    356  1.17.2.16  nathanw 			    IFM_IEEE80211_IBSSMASTER, 0), 0);
    357  1.17.2.16  nathanw 		if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
    358  1.17.2.16  nathanw 			ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
    359  1.17.2.16  nathanw 			    IFM_IEEE80211_HOSTAP, 0), 0);
    360  1.17.2.16  nathanw 	}
    361  1.17.2.16  nathanw 	if (sc->wi_supprates & WI_SUPPRATES_2M) {
    362  1.17.2.16  nathanw 		PRINT("2Mbps");
    363  1.17.2.16  nathanw 		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 0, 0), 0);
    364  1.17.2.16  nathanw 		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
    365  1.17.2.16  nathanw 		    IFM_IEEE80211_ADHOC, 0), 0);
    366  1.17.2.16  nathanw 		if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
    367  1.17.2.16  nathanw 			ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
    368  1.17.2.16  nathanw 			    IFM_IEEE80211_IBSS, 0), 0);
    369  1.17.2.16  nathanw 		if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
    370  1.17.2.16  nathanw 			ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
    371  1.17.2.16  nathanw 			    IFM_IEEE80211_IBSSMASTER, 0), 0);
    372  1.17.2.16  nathanw 		if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
    373  1.17.2.16  nathanw 			ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
    374  1.17.2.16  nathanw 			    IFM_IEEE80211_HOSTAP, 0), 0);
    375  1.17.2.16  nathanw 	}
    376  1.17.2.16  nathanw 	if (sc->wi_supprates & WI_SUPPRATES_5M) {
    377  1.17.2.16  nathanw 		PRINT("5.5Mbps");
    378  1.17.2.16  nathanw 		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 0, 0), 0);
    379  1.17.2.16  nathanw 		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
    380  1.17.2.16  nathanw 		    IFM_IEEE80211_ADHOC, 0), 0);
    381  1.17.2.16  nathanw 		if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
    382  1.17.2.16  nathanw 			ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
    383  1.17.2.16  nathanw 			    IFM_IEEE80211_IBSS, 0), 0);
    384  1.17.2.16  nathanw 		if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
    385  1.17.2.16  nathanw 			ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
    386  1.17.2.16  nathanw 			    IFM_IEEE80211_IBSSMASTER, 0), 0);
    387  1.17.2.16  nathanw 		if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
    388  1.17.2.16  nathanw 			ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
    389  1.17.2.16  nathanw 			    IFM_IEEE80211_HOSTAP, 0), 0);
    390  1.17.2.16  nathanw 	}
    391  1.17.2.16  nathanw 	if (sc->wi_supprates & WI_SUPPRATES_11M) {
    392  1.17.2.16  nathanw 		PRINT("11Mbps");
    393  1.17.2.16  nathanw 		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 0, 0), 0);
    394  1.17.2.16  nathanw 		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
    395  1.17.2.16  nathanw 		    IFM_IEEE80211_ADHOC, 0), 0);
    396  1.17.2.16  nathanw 		if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
    397  1.17.2.16  nathanw 			ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
    398  1.17.2.16  nathanw 			    IFM_IEEE80211_IBSS, 0), 0);
    399  1.17.2.16  nathanw 		if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
    400  1.17.2.16  nathanw 			ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
    401  1.17.2.16  nathanw 			    IFM_IEEE80211_IBSSMASTER, 0), 0);
    402  1.17.2.16  nathanw 		if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
    403  1.17.2.16  nathanw 			ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
    404  1.17.2.16  nathanw 			    IFM_IEEE80211_HOSTAP, 0), 0);
    405  1.17.2.16  nathanw 		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_MANUAL, 0, 0), 0);
    406  1.17.2.16  nathanw 	}
    407  1.17.2.16  nathanw 	if (sc->wi_supprates != 0)
    408  1.17.2.16  nathanw 		printf("\n");
    409  1.17.2.16  nathanw 	ifmedia_set(&sc->sc_media,
    410  1.17.2.16  nathanw 	    IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0));
    411   1.17.2.2  nathanw #undef ADD
    412  1.17.2.16  nathanw #undef PRINT
    413   1.17.2.2  nathanw 
    414   1.17.2.2  nathanw 	/*
    415   1.17.2.2  nathanw 	 * Call MI attach routines.
    416   1.17.2.2  nathanw 	 */
    417   1.17.2.2  nathanw 	if_attach(ifp);
    418   1.17.2.2  nathanw 	ether_ifattach(ifp, mac.wi_mac_addr);
    419   1.17.2.2  nathanw 
    420   1.17.2.2  nathanw 	ifp->if_baudrate = IF_Mbps(2);
    421   1.17.2.2  nathanw 
    422   1.17.2.2  nathanw 	/* Attach is successful. */
    423   1.17.2.2  nathanw 	sc->sc_attached = 1;
    424   1.17.2.2  nathanw 
    425   1.17.2.2  nathanw 	splx(s);
    426   1.17.2.2  nathanw 	return 0;
    427   1.17.2.2  nathanw }
    428   1.17.2.2  nathanw 
    429   1.17.2.2  nathanw static void wi_rxeof(sc)
    430   1.17.2.2  nathanw 	struct wi_softc		*sc;
    431   1.17.2.2  nathanw {
    432   1.17.2.2  nathanw 	struct ifnet		*ifp;
    433   1.17.2.2  nathanw 	struct ether_header	*eh;
    434   1.17.2.2  nathanw 	struct wi_frame		rx_frame;
    435   1.17.2.2  nathanw 	struct mbuf		*m;
    436   1.17.2.2  nathanw 	int			id;
    437   1.17.2.2  nathanw 
    438   1.17.2.2  nathanw 	ifp = sc->sc_ifp;
    439   1.17.2.2  nathanw 
    440   1.17.2.2  nathanw 	id = CSR_READ_2(sc, WI_RX_FID);
    441   1.17.2.2  nathanw 
    442   1.17.2.2  nathanw 	/* First read in the frame header */
    443   1.17.2.2  nathanw 	if (wi_read_data(sc, id, 0, (caddr_t)&rx_frame, sizeof(rx_frame))) {
    444   1.17.2.2  nathanw 		ifp->if_ierrors++;
    445   1.17.2.2  nathanw 		return;
    446   1.17.2.2  nathanw 	}
    447   1.17.2.2  nathanw 
    448   1.17.2.8  nathanw 	/*
    449   1.17.2.8  nathanw 	 * Drop undecryptable or packets with receive errors here
    450   1.17.2.8  nathanw 	 */
    451   1.17.2.7  nathanw 	if (le16toh(rx_frame.wi_status) & WI_STAT_ERRSTAT) {
    452   1.17.2.2  nathanw 		ifp->if_ierrors++;
    453   1.17.2.2  nathanw 		return;
    454   1.17.2.2  nathanw 	}
    455   1.17.2.2  nathanw 
    456   1.17.2.2  nathanw 	MGETHDR(m, M_DONTWAIT, MT_DATA);
    457   1.17.2.2  nathanw 	if (m == NULL) {
    458   1.17.2.2  nathanw 		ifp->if_ierrors++;
    459   1.17.2.2  nathanw 		return;
    460   1.17.2.2  nathanw 	}
    461   1.17.2.2  nathanw 	MCLGET(m, M_DONTWAIT);
    462   1.17.2.2  nathanw 	if (!(m->m_flags & M_EXT)) {
    463   1.17.2.2  nathanw 		m_freem(m);
    464   1.17.2.2  nathanw 		ifp->if_ierrors++;
    465   1.17.2.2  nathanw 		return;
    466   1.17.2.2  nathanw 	}
    467   1.17.2.2  nathanw 
    468   1.17.2.2  nathanw 	/* Align the data after the ethernet header */
    469   1.17.2.2  nathanw 	m->m_data = (caddr_t) ALIGN(m->m_data + sizeof(struct ether_header))
    470   1.17.2.2  nathanw 	    - sizeof(struct ether_header);
    471   1.17.2.2  nathanw 
    472   1.17.2.2  nathanw 	eh = mtod(m, struct ether_header *);
    473   1.17.2.2  nathanw 	m->m_pkthdr.rcvif = ifp;
    474   1.17.2.2  nathanw 
    475  1.17.2.16  nathanw 	if ((le16toh(rx_frame.wi_status) & WI_RXSTAT_MSG_TYPE) == WI_STAT_MGMT &&
    476  1.17.2.16  nathanw 	    sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
    477  1.17.2.16  nathanw 		if ((le16toh(rx_frame.wi_dat_len) + WI_802_11_OFFSET_RAW + 2) >
    478  1.17.2.16  nathanw 		    MCLBYTES) {
    479  1.17.2.16  nathanw 			printf("%s: oversized packet received in "
    480  1.17.2.16  nathanw 			    "Host-AP mode (wi_dat_len=%d, wi_status=0x%x)\n",
    481  1.17.2.16  nathanw 			    sc->sc_dev.dv_xname,
    482  1.17.2.16  nathanw 			    le16toh(rx_frame.wi_dat_len),
    483  1.17.2.16  nathanw 			    le16toh(rx_frame.wi_status));
    484  1.17.2.16  nathanw 			m_freem(m);
    485  1.17.2.16  nathanw 			ifp->if_ierrors++;
    486  1.17.2.16  nathanw 			return;
    487  1.17.2.16  nathanw 		}
    488  1.17.2.16  nathanw 
    489  1.17.2.16  nathanw 		/* Put the whole header in there. */
    490  1.17.2.16  nathanw 		memcpy(mtod(m, void *), &rx_frame, sizeof(rx_frame));
    491  1.17.2.16  nathanw 		if (wi_read_data(sc, id, WI_802_11_OFFSET_RAW,
    492  1.17.2.16  nathanw 		    mtod(m, caddr_t) + WI_802_11_OFFSET_RAW,
    493  1.17.2.16  nathanw 		    le16toh(rx_frame.wi_dat_len) + 2)) {
    494  1.17.2.16  nathanw 			m_freem(m);
    495  1.17.2.16  nathanw 			if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
    496  1.17.2.16  nathanw 				printf("%s: Host-AP: failed to copy header\n",
    497  1.17.2.16  nathanw 				    sc->sc_dev.dv_xname);
    498  1.17.2.16  nathanw 			ifp->if_ierrors++;
    499  1.17.2.16  nathanw 			return;
    500  1.17.2.16  nathanw 		}
    501  1.17.2.16  nathanw 
    502  1.17.2.16  nathanw 		m->m_pkthdr.len = m->m_len =
    503  1.17.2.16  nathanw 		    WI_802_11_OFFSET_RAW + le16toh(rx_frame.wi_dat_len);
    504  1.17.2.16  nathanw 
    505  1.17.2.16  nathanw 		/* XXX Consider giving packet to bhp? */
    506  1.17.2.16  nathanw 
    507  1.17.2.16  nathanw 		wihap_mgmt_input(sc, &rx_frame, m);
    508  1.17.2.16  nathanw 		return;
    509  1.17.2.16  nathanw 	}
    510  1.17.2.16  nathanw 
    511  1.17.2.13  nathanw 	if ((le16toh(rx_frame.wi_status) & WI_RXSTAT_MSG_TYPE) == WI_STAT_1042 ||
    512  1.17.2.13  nathanw 	    (le16toh(rx_frame.wi_status) & WI_RXSTAT_MSG_TYPE) == WI_STAT_TUNNEL ||
    513  1.17.2.13  nathanw 	    (le16toh(rx_frame.wi_status) & WI_RXSTAT_MSG_TYPE) == WI_STAT_WMP_MSG) {
    514   1.17.2.2  nathanw 		if ((le16toh(rx_frame.wi_dat_len) + WI_SNAPHDR_LEN) > MCLBYTES) {
    515   1.17.2.2  nathanw 			printf("%s: oversized packet received "
    516   1.17.2.2  nathanw 			    "(wi_dat_len=%d, wi_status=0x%x)\n",
    517   1.17.2.2  nathanw 			    sc->sc_dev.dv_xname,
    518   1.17.2.2  nathanw 			    le16toh(rx_frame.wi_dat_len), le16toh(rx_frame.wi_status));
    519   1.17.2.2  nathanw 			m_freem(m);
    520   1.17.2.2  nathanw 			ifp->if_ierrors++;
    521   1.17.2.2  nathanw 			return;
    522   1.17.2.2  nathanw 		}
    523   1.17.2.2  nathanw 		m->m_pkthdr.len = m->m_len =
    524   1.17.2.2  nathanw 		    le16toh(rx_frame.wi_dat_len) + WI_SNAPHDR_LEN;
    525   1.17.2.2  nathanw 
    526   1.17.2.3  nathanw 		memcpy((char *)&eh->ether_dhost, (char *)&rx_frame.wi_dst_addr,
    527   1.17.2.3  nathanw 		    ETHER_ADDR_LEN);
    528   1.17.2.3  nathanw 		memcpy((char *)&eh->ether_shost, (char *)&rx_frame.wi_src_addr,
    529   1.17.2.3  nathanw 		    ETHER_ADDR_LEN);
    530   1.17.2.3  nathanw 		memcpy((char *)&eh->ether_type, (char *)&rx_frame.wi_type,
    531   1.17.2.3  nathanw 		    sizeof(u_int16_t));
    532   1.17.2.2  nathanw 
    533   1.17.2.2  nathanw 		if (wi_read_data(sc, id, WI_802_11_OFFSET,
    534   1.17.2.2  nathanw 		    mtod(m, caddr_t) + sizeof(struct ether_header),
    535   1.17.2.2  nathanw 		    m->m_len + 2)) {
    536   1.17.2.2  nathanw 			m_freem(m);
    537   1.17.2.2  nathanw 			ifp->if_ierrors++;
    538   1.17.2.2  nathanw 			return;
    539   1.17.2.2  nathanw 		}
    540   1.17.2.2  nathanw 	} else {
    541   1.17.2.2  nathanw 		if ((le16toh(rx_frame.wi_dat_len) +
    542   1.17.2.2  nathanw 		    sizeof(struct ether_header)) > MCLBYTES) {
    543   1.17.2.2  nathanw 			printf("%s: oversized packet received "
    544   1.17.2.2  nathanw 			    "(wi_dat_len=%d, wi_status=0x%x)\n",
    545   1.17.2.2  nathanw 			    sc->sc_dev.dv_xname,
    546   1.17.2.2  nathanw 			    le16toh(rx_frame.wi_dat_len), le16toh(rx_frame.wi_status));
    547   1.17.2.2  nathanw 			m_freem(m);
    548   1.17.2.2  nathanw 			ifp->if_ierrors++;
    549   1.17.2.2  nathanw 			return;
    550   1.17.2.2  nathanw 		}
    551   1.17.2.2  nathanw 		m->m_pkthdr.len = m->m_len =
    552   1.17.2.2  nathanw 		    le16toh(rx_frame.wi_dat_len) + sizeof(struct ether_header);
    553   1.17.2.2  nathanw 
    554   1.17.2.2  nathanw 		if (wi_read_data(sc, id, WI_802_3_OFFSET,
    555   1.17.2.2  nathanw 		    mtod(m, caddr_t), m->m_len + 2)) {
    556   1.17.2.2  nathanw 			m_freem(m);
    557   1.17.2.2  nathanw 			ifp->if_ierrors++;
    558   1.17.2.2  nathanw 			return;
    559   1.17.2.2  nathanw 		}
    560   1.17.2.2  nathanw 	}
    561   1.17.2.2  nathanw 
    562   1.17.2.2  nathanw 	ifp->if_ipackets++;
    563   1.17.2.2  nathanw 
    564  1.17.2.16  nathanw 	if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
    565  1.17.2.16  nathanw 		/*
    566  1.17.2.16  nathanw 		 * Give Host-AP first crack at data packets.  If it
    567  1.17.2.16  nathanw 		 * decides to handle it (or drop it), it will return
    568  1.17.2.16  nathanw 		 * non-zero.  Otherwise, it is destined for this host.
    569  1.17.2.16  nathanw 		 */
    570  1.17.2.16  nathanw 		if (wihap_data_input(sc, &rx_frame, m))
    571  1.17.2.16  nathanw 			return;
    572  1.17.2.16  nathanw 	}
    573  1.17.2.16  nathanw 
    574   1.17.2.2  nathanw #if NBPFILTER > 0
    575   1.17.2.2  nathanw 	/* Handle BPF listeners. */
    576   1.17.2.2  nathanw 	if (ifp->if_bpf)
    577   1.17.2.2  nathanw 		bpf_mtap(ifp->if_bpf, m);
    578   1.17.2.2  nathanw #endif
    579   1.17.2.2  nathanw 
    580   1.17.2.2  nathanw 	/* Receive packet. */
    581   1.17.2.2  nathanw 	(*ifp->if_input)(ifp, m);
    582   1.17.2.2  nathanw }
    583   1.17.2.2  nathanw 
    584   1.17.2.2  nathanw static void wi_txeof(sc, status)
    585   1.17.2.2  nathanw 	struct wi_softc	*sc;
    586   1.17.2.2  nathanw 	int		status;
    587   1.17.2.2  nathanw {
    588   1.17.2.2  nathanw 	struct ifnet	*ifp = sc->sc_ifp;
    589   1.17.2.2  nathanw 
    590   1.17.2.2  nathanw 	ifp->if_timer = 0;
    591   1.17.2.2  nathanw 	ifp->if_flags &= ~IFF_OACTIVE;
    592   1.17.2.2  nathanw 
    593   1.17.2.2  nathanw 	if (status & WI_EV_TX_EXC)
    594   1.17.2.2  nathanw 		ifp->if_oerrors++;
    595   1.17.2.2  nathanw 	else
    596   1.17.2.2  nathanw 		ifp->if_opackets++;
    597   1.17.2.2  nathanw 
    598   1.17.2.2  nathanw 	return;
    599   1.17.2.2  nathanw }
    600   1.17.2.2  nathanw 
    601   1.17.2.7  nathanw void wi_inquire(xsc)
    602   1.17.2.2  nathanw 	void			*xsc;
    603   1.17.2.2  nathanw {
    604   1.17.2.2  nathanw 	struct wi_softc		*sc;
    605   1.17.2.2  nathanw 	struct ifnet		*ifp;
    606  1.17.2.10  nathanw 	int			s;
    607   1.17.2.2  nathanw 
    608   1.17.2.2  nathanw 	sc = xsc;
    609   1.17.2.2  nathanw 	ifp = &sc->sc_ethercom.ec_if;
    610   1.17.2.2  nathanw 
    611   1.17.2.2  nathanw 	if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
    612   1.17.2.2  nathanw 		return;
    613   1.17.2.2  nathanw 
    614  1.17.2.11  nathanw 	KASSERT(sc->sc_enabled);
    615  1.17.2.11  nathanw 
    616   1.17.2.7  nathanw 	callout_reset(&sc->wi_inquire_ch, hz * 60, wi_inquire, sc);
    617   1.17.2.2  nathanw 
    618   1.17.2.2  nathanw 	/* Don't do this while we're transmitting */
    619   1.17.2.2  nathanw 	if (ifp->if_flags & IFF_OACTIVE)
    620   1.17.2.2  nathanw 		return;
    621   1.17.2.2  nathanw 
    622  1.17.2.10  nathanw 	s = splnet();
    623  1.17.2.16  nathanw 	wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_COUNTERS, 0, 0);
    624  1.17.2.10  nathanw 	splx(s);
    625  1.17.2.10  nathanw }
    626  1.17.2.10  nathanw 
    627  1.17.2.10  nathanw void wi_wait_scan(xsc)
    628  1.17.2.10  nathanw 	void			*xsc;
    629  1.17.2.10  nathanw {
    630  1.17.2.10  nathanw 	struct wi_softc         *sc;
    631  1.17.2.10  nathanw 	struct ifnet            *ifp;
    632  1.17.2.10  nathanw 	int			s, result;
    633  1.17.2.10  nathanw 
    634  1.17.2.10  nathanw 	sc = xsc;
    635  1.17.2.10  nathanw 	ifp = &sc->sc_ethercom.ec_if;
    636  1.17.2.10  nathanw 
    637  1.17.2.10  nathanw 	/* If not scanning, ignore */
    638  1.17.2.10  nathanw 	if (!sc->wi_scanning)
    639  1.17.2.10  nathanw 		return;
    640  1.17.2.10  nathanw 
    641  1.17.2.10  nathanw 	s = splnet();
    642  1.17.2.10  nathanw 
    643  1.17.2.10  nathanw 	/* Wait for sending complete to make INQUIRE */
    644  1.17.2.10  nathanw 	if (ifp->if_flags & IFF_OACTIVE) {
    645  1.17.2.10  nathanw 		callout_reset(&sc->wi_scan_sh, hz * 1, wi_wait_scan, sc);
    646  1.17.2.10  nathanw 		splx(s);
    647  1.17.2.10  nathanw 		return;
    648  1.17.2.10  nathanw 	}
    649  1.17.2.10  nathanw 
    650  1.17.2.10  nathanw 	/* try INQUIRE */
    651  1.17.2.16  nathanw 	result = wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_SCAN_RESULTS, 0, 0);
    652  1.17.2.10  nathanw 	if (result == ETIMEDOUT)
    653  1.17.2.10  nathanw 		callout_reset(&sc->wi_scan_sh, hz * 1, wi_wait_scan, sc);
    654  1.17.2.10  nathanw 
    655  1.17.2.10  nathanw 	splx(s);
    656   1.17.2.2  nathanw }
    657   1.17.2.2  nathanw 
    658   1.17.2.2  nathanw void wi_update_stats(sc)
    659   1.17.2.2  nathanw 	struct wi_softc		*sc;
    660   1.17.2.2  nathanw {
    661   1.17.2.2  nathanw 	struct wi_ltv_gen	gen;
    662  1.17.2.10  nathanw 	struct wi_scan_header	ap2_header;	/* Prism2 header */
    663  1.17.2.10  nathanw 	struct wi_scan_data_p2	ap2;		/* Prism2 scantable*/
    664  1.17.2.10  nathanw 	struct wi_scan_data	ap;		/* Lucent scantable */
    665  1.17.2.10  nathanw 	struct wi_assoc		assoc;		/* Association Status */
    666   1.17.2.2  nathanw 	u_int16_t		id;
    667   1.17.2.2  nathanw 	struct ifnet		*ifp;
    668   1.17.2.2  nathanw 	u_int32_t		*ptr;
    669  1.17.2.10  nathanw 	int			len, naps, i, j;
    670   1.17.2.2  nathanw 	u_int16_t		t;
    671   1.17.2.2  nathanw 
    672   1.17.2.2  nathanw 	ifp = &sc->sc_ethercom.ec_if;
    673   1.17.2.2  nathanw 
    674   1.17.2.2  nathanw 	id = CSR_READ_2(sc, WI_INFO_FID);
    675   1.17.2.2  nathanw 
    676  1.17.2.11  nathanw 	if (wi_seek(sc, id, 0, WI_BAP1)) {
    677  1.17.2.11  nathanw 		return;
    678  1.17.2.11  nathanw 	}
    679  1.17.2.11  nathanw 
    680  1.17.2.11  nathanw 	gen.wi_len = CSR_READ_2(sc, WI_DATA1);
    681  1.17.2.11  nathanw 	gen.wi_type = CSR_READ_2(sc, WI_DATA1);
    682   1.17.2.2  nathanw 
    683   1.17.2.9  nathanw 	switch (gen.wi_type) {
    684  1.17.2.10  nathanw 	case WI_INFO_SCAN_RESULTS:
    685  1.17.2.12  nathanw 	case WI_INFO_HOST_SCAN_RESULTS:
    686  1.17.2.11  nathanw 		if (gen.wi_len <= 3) {
    687  1.17.2.11  nathanw 			sc->wi_naps = 0;
    688  1.17.2.11  nathanw 			sc->wi_scanning = 0;
    689  1.17.2.10  nathanw 			break;
    690  1.17.2.11  nathanw 		}
    691  1.17.2.11  nathanw 		switch (sc->sc_firmware_type) {
    692  1.17.2.11  nathanw 		case WI_INTERSIL:
    693  1.17.2.12  nathanw 		case WI_SYMBOL:
    694  1.17.2.12  nathanw 			if (sc->sc_firmware_type == WI_INTERSIL) {
    695  1.17.2.12  nathanw 				naps = 2 * (gen.wi_len - 3) / sizeof(ap2);
    696  1.17.2.12  nathanw 				/* Read Header */
    697  1.17.2.12  nathanw 				for(j=0; j < sizeof(ap2_header) / 2; j++)
    698  1.17.2.12  nathanw 					((u_int16_t *)&ap2_header)[j] =
    699  1.17.2.12  nathanw 					    CSR_READ_2(sc, WI_DATA1);
    700  1.17.2.12  nathanw 			} else {	/* WI_SYMBOL */
    701  1.17.2.12  nathanw 				naps = 2 * (gen.wi_len - 1) / (sizeof(ap2) + 6);
    702  1.17.2.12  nathanw 				ap2_header.wi_reason = 0;
    703  1.17.2.12  nathanw 			}
    704  1.17.2.10  nathanw 			naps = naps > MAXAPINFO ? MAXAPINFO : naps;
    705  1.17.2.10  nathanw 			sc->wi_naps = naps;
    706  1.17.2.10  nathanw 			/* Read Data */
    707  1.17.2.10  nathanw 			for (i=0; i < naps; i++) {
    708  1.17.2.10  nathanw 				for(j=0; j < sizeof(ap2) / 2; j++)
    709  1.17.2.10  nathanw 					((u_int16_t *)&ap2)[j] =
    710  1.17.2.10  nathanw 						CSR_READ_2(sc, WI_DATA1);
    711  1.17.2.12  nathanw 				if (sc->sc_firmware_type == WI_SYMBOL) {
    712  1.17.2.12  nathanw 					/* 3 more words */
    713  1.17.2.12  nathanw 					for (j = 0; j < 3; j++)
    714  1.17.2.12  nathanw 						CSR_READ_2(sc, WI_DATA1);
    715  1.17.2.12  nathanw 				}
    716  1.17.2.11  nathanw 				/* unswap 8 bit data fields: */
    717  1.17.2.11  nathanw 				for(j=0;j<sizeof(ap.wi_bssid)/2;j++)
    718  1.17.2.11  nathanw 					LE16TOH(((u_int16_t *)&ap.wi_bssid[0])[j]);
    719  1.17.2.11  nathanw 				for(j=0;j<sizeof(ap.wi_name)/2;j++)
    720  1.17.2.11  nathanw 					LE16TOH(((u_int16_t *)&ap.wi_name[0])[j]);
    721  1.17.2.10  nathanw 				sc->wi_aps[i].scanreason = ap2_header.wi_reason;
    722  1.17.2.10  nathanw 				memcpy(sc->wi_aps[i].bssid, ap2.wi_bssid, 6);
    723  1.17.2.10  nathanw 				sc->wi_aps[i].channel = ap2.wi_chid;
    724  1.17.2.10  nathanw 				sc->wi_aps[i].signal  = ap2.wi_signal;
    725  1.17.2.10  nathanw 				sc->wi_aps[i].noise   = ap2.wi_noise;
    726  1.17.2.10  nathanw 				sc->wi_aps[i].quality = ap2.wi_signal - ap2.wi_noise;
    727  1.17.2.10  nathanw 				sc->wi_aps[i].capinfo = ap2.wi_capinfo;
    728  1.17.2.10  nathanw 				sc->wi_aps[i].interval = ap2.wi_interval;
    729  1.17.2.10  nathanw 				sc->wi_aps[i].rate    = ap2.wi_rate;
    730  1.17.2.10  nathanw 				if (ap2.wi_namelen > 32)
    731  1.17.2.10  nathanw 					ap2.wi_namelen = 32;
    732  1.17.2.10  nathanw 				sc->wi_aps[i].namelen = ap2.wi_namelen;
    733  1.17.2.10  nathanw 				memcpy(sc->wi_aps[i].name, ap2.wi_name,
    734  1.17.2.10  nathanw 				       ap2.wi_namelen);
    735  1.17.2.10  nathanw 			}
    736  1.17.2.11  nathanw 			break;
    737  1.17.2.11  nathanw 
    738  1.17.2.11  nathanw 		case WI_LUCENT:
    739  1.17.2.10  nathanw 			naps = 2 * gen.wi_len / sizeof(ap);
    740  1.17.2.10  nathanw 			naps = naps > MAXAPINFO ? MAXAPINFO : naps;
    741  1.17.2.10  nathanw 			sc->wi_naps = naps;
    742  1.17.2.10  nathanw 			/* Read Data*/
    743  1.17.2.10  nathanw 			for (i=0; i < naps; i++) {
    744  1.17.2.10  nathanw 				for(j=0; j < sizeof(ap) / 2; j++)
    745  1.17.2.10  nathanw 					((u_int16_t *)&ap)[j] =
    746  1.17.2.10  nathanw 						CSR_READ_2(sc, WI_DATA1);
    747  1.17.2.11  nathanw 				/* unswap 8 bit data fields: */
    748  1.17.2.11  nathanw 				for(j=0;j<sizeof(ap.wi_bssid)/2;j++)
    749  1.17.2.11  nathanw 					HTOLE16(((u_int16_t *)&ap.wi_bssid[0])[j]);
    750  1.17.2.11  nathanw 				for(j=0;j<sizeof(ap.wi_name)/2;j++)
    751  1.17.2.11  nathanw 					HTOLE16(((u_int16_t *)&ap.wi_name[0])[j]);
    752  1.17.2.10  nathanw 				memcpy(sc->wi_aps[i].bssid, ap.wi_bssid, 6);
    753  1.17.2.10  nathanw 				sc->wi_aps[i].channel = ap.wi_chid;
    754  1.17.2.10  nathanw 				sc->wi_aps[i].signal  = ap.wi_signal;
    755  1.17.2.10  nathanw 				sc->wi_aps[i].noise   = ap.wi_noise;
    756  1.17.2.10  nathanw 				sc->wi_aps[i].quality = ap.wi_signal - ap.wi_noise;
    757  1.17.2.10  nathanw 				sc->wi_aps[i].capinfo = ap.wi_capinfo;
    758  1.17.2.10  nathanw 				sc->wi_aps[i].interval = ap.wi_interval;
    759  1.17.2.10  nathanw 				if (ap.wi_namelen > 32)
    760  1.17.2.10  nathanw 					ap.wi_namelen = 32;
    761  1.17.2.10  nathanw 				sc->wi_aps[i].namelen = ap.wi_namelen;
    762  1.17.2.10  nathanw 				memcpy(sc->wi_aps[i].name, ap.wi_name,
    763  1.17.2.10  nathanw 				       ap.wi_namelen);
    764  1.17.2.10  nathanw 			}
    765  1.17.2.11  nathanw 			break;
    766  1.17.2.10  nathanw 		}
    767  1.17.2.10  nathanw 		/* Done scanning */
    768  1.17.2.10  nathanw 		sc->wi_scanning = 0;
    769  1.17.2.10  nathanw 		break;
    770  1.17.2.10  nathanw 
    771   1.17.2.9  nathanw 	case WI_INFO_COUNTERS:
    772   1.17.2.9  nathanw 		/* some card versions have a larger stats structure */
    773   1.17.2.9  nathanw 		len = (gen.wi_len - 1 < sizeof(sc->wi_stats) / 4) ?
    774   1.17.2.9  nathanw 			gen.wi_len - 1 : sizeof(sc->wi_stats) / 4;
    775   1.17.2.9  nathanw 		ptr = (u_int32_t *)&sc->wi_stats;
    776   1.17.2.7  nathanw 
    777   1.17.2.9  nathanw 		for (i = 0; i < len; i++) {
    778   1.17.2.9  nathanw 			t = CSR_READ_2(sc, WI_DATA1);
    779   1.17.2.2  nathanw #ifdef WI_HERMES_STATS_WAR
    780   1.17.2.9  nathanw 			if (t > 0xF000)
    781   1.17.2.9  nathanw 				t = ~t & 0xFFFF;
    782   1.17.2.2  nathanw #endif
    783   1.17.2.9  nathanw 			ptr[i] += t;
    784   1.17.2.9  nathanw 		}
    785   1.17.2.4  nathanw 
    786   1.17.2.9  nathanw 		ifp->if_collisions = sc->wi_stats.wi_tx_single_retries +
    787   1.17.2.9  nathanw 			sc->wi_stats.wi_tx_multi_retries +
    788   1.17.2.9  nathanw 			sc->wi_stats.wi_tx_retry_limit;
    789   1.17.2.9  nathanw 		break;
    790   1.17.2.6  thorpej 
    791   1.17.2.9  nathanw 	case WI_INFO_LINK_STAT: {
    792   1.17.2.9  nathanw 		static char *msg[] = {
    793   1.17.2.9  nathanw 			"connected",
    794   1.17.2.9  nathanw 			"disconnected",
    795   1.17.2.9  nathanw 			"AP change",
    796   1.17.2.9  nathanw 			"AP out of range",
    797  1.17.2.10  nathanw 			"AP in range",
    798  1.17.2.11  nathanw 			"Association Failed"
    799   1.17.2.9  nathanw 		};
    800   1.17.2.9  nathanw 
    801   1.17.2.9  nathanw 		if (gen.wi_len != 2) {
    802   1.17.2.9  nathanw #ifdef WI_DEBUG
    803   1.17.2.9  nathanw 			printf("WI_INFO_LINK_STAT: len=%d\n", gen.wi_len);
    804   1.17.2.9  nathanw #endif
    805   1.17.2.9  nathanw 			break;
    806   1.17.2.9  nathanw 		}
    807   1.17.2.9  nathanw 		t = CSR_READ_2(sc, WI_DATA1);
    808  1.17.2.10  nathanw 		if ((t < 1) || (t > 6)) {
    809   1.17.2.9  nathanw #ifdef WI_DEBUG
    810   1.17.2.9  nathanw 			printf("WI_INFO_LINK_STAT: status %d\n", t);
    811   1.17.2.9  nathanw #endif
    812   1.17.2.9  nathanw 			break;
    813   1.17.2.9  nathanw 		}
    814  1.17.2.12  nathanw 		if (sc->sc_firmware_type == WI_SYMBOL && t == 4) {
    815  1.17.2.16  nathanw 			wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_HOST_SCAN_RESULTS,
    816  1.17.2.16  nathanw 			    0, 0);
    817  1.17.2.12  nathanw 			break;
    818  1.17.2.12  nathanw 		}
    819  1.17.2.10  nathanw 		/*
    820  1.17.2.10  nathanw 		 * Some cards issue streams of "connected" messages while
    821  1.17.2.10  nathanw 		 * trying to find a peer. Don't bother the user with this
    822  1.17.2.10  nathanw 		 * unless he is debugging.
    823  1.17.2.10  nathanw 		 */
    824  1.17.2.10  nathanw 		if (ifp->if_flags & IFF_DEBUG)
    825  1.17.2.10  nathanw 			printf("%s: %s\n", sc->sc_dev.dv_xname, msg[t - 1]);
    826   1.17.2.9  nathanw 		break;
    827   1.17.2.9  nathanw 		}
    828   1.17.2.9  nathanw 
    829  1.17.2.10  nathanw 	case WI_INFO_ASSOC_STAT: {
    830  1.17.2.10  nathanw 		static char *msg[] = {
    831  1.17.2.10  nathanw 			"STA Associated",
    832  1.17.2.10  nathanw 			"STA Reassociated",
    833  1.17.2.10  nathanw 			"STA Disassociated",
    834  1.17.2.10  nathanw 			"Association Failure",
    835  1.17.2.11  nathanw 			"Authentication Failed"
    836  1.17.2.10  nathanw 		};
    837  1.17.2.10  nathanw 		if (gen.wi_len != 10)
    838  1.17.2.10  nathanw                         break;
    839  1.17.2.10  nathanw 		for (i=0; i < gen.wi_len - 1; i++)
    840  1.17.2.10  nathanw 			((u_int16_t *)&assoc)[i] = CSR_READ_2(sc, WI_DATA1);
    841  1.17.2.11  nathanw 		/* unswap 8 bit data fields: */
    842  1.17.2.11  nathanw 		for(j=0;j<sizeof(assoc.wi_assoc_sta)/2;j++)
    843  1.17.2.11  nathanw 			HTOLE16(((u_int16_t *)&assoc.wi_assoc_sta[0])[j]);
    844  1.17.2.11  nathanw 		for(j=0;j<sizeof(assoc.wi_assoc_osta)/2;j++)
    845  1.17.2.11  nathanw 			HTOLE16(((u_int16_t *)&assoc.wi_assoc_osta[0])[j]);
    846  1.17.2.10  nathanw 		switch (assoc.wi_assoc_stat) {
    847  1.17.2.10  nathanw 		case ASSOC:
    848  1.17.2.10  nathanw 		case DISASSOC:
    849  1.17.2.10  nathanw 		case ASSOCFAIL:
    850  1.17.2.10  nathanw 		case AUTHFAIL:
    851  1.17.2.11  nathanw 			printf("%s: %s, AP = %02x:%02x:%02x:%02x:%02x:%02x\n",
    852  1.17.2.10  nathanw 				sc->sc_dev.dv_xname,
    853  1.17.2.10  nathanw 				msg[assoc.wi_assoc_stat - 1],
    854  1.17.2.10  nathanw 				assoc.wi_assoc_sta[0]&0xff, assoc.wi_assoc_sta[1]&0xff,
    855  1.17.2.10  nathanw 				assoc.wi_assoc_sta[2]&0xff, assoc.wi_assoc_sta[3]&0xff,
    856  1.17.2.10  nathanw 				assoc.wi_assoc_sta[4]&0xff, assoc.wi_assoc_sta[5]&0xff);
    857  1.17.2.10  nathanw 			break;
    858  1.17.2.10  nathanw 		case REASSOC:
    859  1.17.2.11  nathanw 			printf("%s: %s, AP = %02x:%02x:%02x:%02x:%02x:%02x, "
    860  1.17.2.11  nathanw 				"OldAP = %02x:%02x:%02x:%02x:%02x:%02x\n",
    861  1.17.2.10  nathanw 				sc->sc_dev.dv_xname, msg[assoc.wi_assoc_stat - 1],
    862  1.17.2.10  nathanw 				assoc.wi_assoc_sta[0]&0xff, assoc.wi_assoc_sta[1]&0xff,
    863  1.17.2.10  nathanw 				assoc.wi_assoc_sta[2]&0xff, assoc.wi_assoc_sta[3]&0xff,
    864  1.17.2.10  nathanw 				assoc.wi_assoc_sta[4]&0xff, assoc.wi_assoc_sta[5]&0xff,
    865  1.17.2.10  nathanw 				assoc.wi_assoc_osta[0]&0xff, assoc.wi_assoc_osta[1]&0xff,
    866  1.17.2.10  nathanw 				assoc.wi_assoc_osta[2]&0xff, assoc.wi_assoc_osta[3]&0xff,
    867  1.17.2.10  nathanw 				assoc.wi_assoc_osta[4]&0xff, assoc.wi_assoc_osta[5]&0xff);
    868  1.17.2.10  nathanw 			break;
    869  1.17.2.10  nathanw 		}
    870  1.17.2.10  nathanw 		}
    871  1.17.2.12  nathanw 
    872   1.17.2.9  nathanw 	default:
    873  1.17.2.10  nathanw #ifdef WI_DEBUG
    874  1.17.2.10  nathanw 		printf("%s: got info type: 0x%04x len=0x%04x\n",
    875  1.17.2.10  nathanw       sc->sc_dev.dv_xname, gen.wi_type,gen.wi_len);
    876   1.17.2.9  nathanw #endif
    877  1.17.2.10  nathanw #if 0
    878   1.17.2.9  nathanw 		for (i = 0; i < gen.wi_len; i++) {
    879   1.17.2.9  nathanw 			t = CSR_READ_2(sc, WI_DATA1);
    880   1.17.2.9  nathanw 			printf("[0x%02x] = 0x%04x\n", i, t);
    881   1.17.2.9  nathanw 		}
    882  1.17.2.10  nathanw #endif
    883   1.17.2.9  nathanw 		break;
    884   1.17.2.9  nathanw 	}
    885   1.17.2.2  nathanw }
    886   1.17.2.2  nathanw 
    887   1.17.2.2  nathanw int wi_intr(arg)
    888   1.17.2.2  nathanw 	void *arg;
    889   1.17.2.2  nathanw {
    890   1.17.2.2  nathanw 	struct wi_softc		*sc = arg;
    891   1.17.2.2  nathanw 	struct ifnet		*ifp;
    892   1.17.2.2  nathanw 	u_int16_t		status;
    893   1.17.2.2  nathanw 
    894   1.17.2.2  nathanw 	if (sc->sc_enabled == 0 ||
    895   1.17.2.2  nathanw 	    (sc->sc_dev.dv_flags & DVF_ACTIVE) == 0 ||
    896   1.17.2.2  nathanw 	    (sc->sc_ethercom.ec_if.if_flags & IFF_RUNNING) == 0)
    897   1.17.2.2  nathanw 		return (0);
    898   1.17.2.2  nathanw 
    899   1.17.2.2  nathanw 	ifp = &sc->sc_ethercom.ec_if;
    900   1.17.2.2  nathanw 
    901   1.17.2.2  nathanw 	if (!(ifp->if_flags & IFF_UP)) {
    902   1.17.2.2  nathanw 		CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
    903   1.17.2.2  nathanw 		CSR_WRITE_2(sc, WI_INT_EN, 0);
    904   1.17.2.2  nathanw 		return 1;
    905   1.17.2.2  nathanw 	}
    906   1.17.2.2  nathanw 
    907   1.17.2.2  nathanw 	/* Disable interrupts. */
    908   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_INT_EN, 0);
    909   1.17.2.2  nathanw 
    910   1.17.2.2  nathanw 	status = CSR_READ_2(sc, WI_EVENT_STAT);
    911   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_EVENT_ACK, ~WI_INTRS);
    912   1.17.2.2  nathanw 
    913   1.17.2.2  nathanw 	if (status & WI_EV_RX) {
    914   1.17.2.2  nathanw 		wi_rxeof(sc);
    915   1.17.2.2  nathanw 		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
    916   1.17.2.2  nathanw 	}
    917   1.17.2.2  nathanw 
    918   1.17.2.2  nathanw 	if (status & WI_EV_TX) {
    919   1.17.2.2  nathanw 		wi_txeof(sc, status);
    920   1.17.2.2  nathanw 		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX);
    921   1.17.2.2  nathanw 	}
    922   1.17.2.2  nathanw 
    923   1.17.2.2  nathanw 	if (status & WI_EV_ALLOC) {
    924   1.17.2.2  nathanw 		int			id;
    925   1.17.2.2  nathanw 		id = CSR_READ_2(sc, WI_ALLOC_FID);
    926   1.17.2.2  nathanw 		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
    927   1.17.2.2  nathanw 		if (id == sc->wi_tx_data_id)
    928   1.17.2.2  nathanw 			wi_txeof(sc, status);
    929   1.17.2.2  nathanw 	}
    930   1.17.2.2  nathanw 
    931   1.17.2.2  nathanw 	if (status & WI_EV_INFO) {
    932   1.17.2.2  nathanw 		wi_update_stats(sc);
    933   1.17.2.2  nathanw 		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO);
    934   1.17.2.2  nathanw 	}
    935   1.17.2.2  nathanw 
    936   1.17.2.2  nathanw 	if (status & WI_EV_TX_EXC) {
    937   1.17.2.2  nathanw 		wi_txeof(sc, status);
    938   1.17.2.2  nathanw 		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX_EXC);
    939   1.17.2.2  nathanw 	}
    940   1.17.2.2  nathanw 
    941   1.17.2.2  nathanw 	if (status & WI_EV_INFO_DROP) {
    942   1.17.2.2  nathanw 		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO_DROP);
    943   1.17.2.2  nathanw 	}
    944   1.17.2.2  nathanw 
    945   1.17.2.2  nathanw 	/* Re-enable interrupts. */
    946   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
    947   1.17.2.2  nathanw 
    948   1.17.2.2  nathanw 	if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
    949   1.17.2.2  nathanw 		wi_start(ifp);
    950   1.17.2.2  nathanw 
    951   1.17.2.2  nathanw 	return 1;
    952   1.17.2.2  nathanw }
    953   1.17.2.2  nathanw 
    954  1.17.2.10  nathanw /* Must be called at proper protection level! */
    955   1.17.2.2  nathanw static int
    956  1.17.2.16  nathanw wi_cmd(sc, cmd, val0, val1, val2)
    957   1.17.2.2  nathanw 	struct wi_softc		*sc;
    958   1.17.2.2  nathanw 	int			cmd;
    959  1.17.2.16  nathanw 	int			val0;
    960  1.17.2.16  nathanw 	int			val1;
    961  1.17.2.16  nathanw 	int			val2;
    962   1.17.2.2  nathanw {
    963   1.17.2.2  nathanw 	int			i, s = 0;
    964   1.17.2.2  nathanw 
    965   1.17.2.2  nathanw 	/* wait for the busy bit to clear */
    966   1.17.2.2  nathanw 	for (i = 0; i < WI_TIMEOUT; i++) {
    967   1.17.2.2  nathanw 		if (!(CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY))
    968   1.17.2.2  nathanw 			break;
    969   1.17.2.2  nathanw 	}
    970   1.17.2.2  nathanw 
    971  1.17.2.10  nathanw 	if (i == WI_TIMEOUT) {
    972  1.17.2.10  nathanw 		printf("%s: wi_cmd: BUSY did not clear, cmd=0x%x\n",
    973  1.17.2.10  nathanw 			sc->sc_dev.dv_xname, cmd);
    974  1.17.2.10  nathanw 		return EIO;
    975  1.17.2.10  nathanw 	}
    976  1.17.2.10  nathanw 
    977  1.17.2.16  nathanw 	CSR_WRITE_2(sc, WI_PARAM0, val0);
    978  1.17.2.16  nathanw 	CSR_WRITE_2(sc, WI_PARAM1, val1);
    979  1.17.2.16  nathanw 	CSR_WRITE_2(sc, WI_PARAM2, val2);
    980   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_COMMAND, cmd);
    981   1.17.2.2  nathanw 
    982   1.17.2.2  nathanw 	/* wait for the cmd completed bit */
    983   1.17.2.2  nathanw 	for (i = 0; i < WI_TIMEOUT; i++) {
    984   1.17.2.2  nathanw 		if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_CMD)
    985   1.17.2.2  nathanw 			break;
    986   1.17.2.2  nathanw 		DELAY(1);
    987   1.17.2.2  nathanw 	}
    988   1.17.2.2  nathanw 
    989   1.17.2.2  nathanw 	/* Ack the command */
    990   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD);
    991   1.17.2.2  nathanw 
    992   1.17.2.2  nathanw 	s = CSR_READ_2(sc, WI_STATUS);
    993   1.17.2.2  nathanw 	if (s & WI_STAT_CMD_RESULT)
    994   1.17.2.2  nathanw 		return(EIO);
    995   1.17.2.2  nathanw 
    996  1.17.2.10  nathanw 	if (i == WI_TIMEOUT) {
    997  1.17.2.10  nathanw 		if (!sc->wi_scanning)
    998  1.17.2.10  nathanw 		    printf("%s: command timed out, cmd=0x%x\n",
    999  1.17.2.10  nathanw 			sc->sc_dev.dv_xname, cmd);
   1000   1.17.2.2  nathanw 		return(ETIMEDOUT);
   1001  1.17.2.10  nathanw 	}
   1002   1.17.2.2  nathanw 
   1003   1.17.2.2  nathanw 	return(0);
   1004   1.17.2.2  nathanw }
   1005   1.17.2.2  nathanw 
   1006   1.17.2.2  nathanw static void
   1007   1.17.2.2  nathanw wi_reset(sc)
   1008   1.17.2.2  nathanw 	struct wi_softc		*sc;
   1009   1.17.2.2  nathanw {
   1010  1.17.2.11  nathanw 
   1011   1.17.2.2  nathanw 	DELAY(100*1000); /* 100 m sec */
   1012  1.17.2.16  nathanw 	if (wi_cmd(sc, WI_CMD_INI, 0, 0, 0))
   1013   1.17.2.2  nathanw 		printf("%s: init failed\n", sc->sc_dev.dv_xname);
   1014   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_INT_EN, 0);
   1015   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
   1016   1.17.2.2  nathanw 
   1017   1.17.2.2  nathanw 	/* Calibrate timer. */
   1018   1.17.2.2  nathanw 	WI_SETVAL(WI_RID_TICK_TIME, 8);
   1019   1.17.2.2  nathanw 
   1020   1.17.2.2  nathanw 	return;
   1021   1.17.2.2  nathanw }
   1022   1.17.2.2  nathanw 
   1023   1.17.2.2  nathanw /*
   1024   1.17.2.2  nathanw  * Read an LTV record from the NIC.
   1025   1.17.2.2  nathanw  */
   1026   1.17.2.2  nathanw static int wi_read_record(sc, ltv)
   1027   1.17.2.2  nathanw 	struct wi_softc		*sc;
   1028   1.17.2.2  nathanw 	struct wi_ltv_gen	*ltv;
   1029   1.17.2.2  nathanw {
   1030   1.17.2.2  nathanw 	u_int16_t		*ptr;
   1031   1.17.2.2  nathanw 	int			len, code;
   1032   1.17.2.2  nathanw 	struct wi_ltv_gen	*oltv, p2ltv;
   1033   1.17.2.2  nathanw 
   1034  1.17.2.11  nathanw 	if (sc->sc_firmware_type != WI_LUCENT) {
   1035   1.17.2.2  nathanw 		oltv = ltv;
   1036   1.17.2.2  nathanw 		switch (ltv->wi_type) {
   1037   1.17.2.2  nathanw 		case WI_RID_ENCRYPTION:
   1038   1.17.2.2  nathanw 			p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
   1039   1.17.2.2  nathanw 			p2ltv.wi_len = 2;
   1040   1.17.2.2  nathanw 			ltv = &p2ltv;
   1041   1.17.2.2  nathanw 			break;
   1042   1.17.2.2  nathanw 		case WI_RID_TX_CRYPT_KEY:
   1043   1.17.2.2  nathanw 			p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
   1044   1.17.2.2  nathanw 			p2ltv.wi_len = 2;
   1045   1.17.2.2  nathanw 			ltv = &p2ltv;
   1046   1.17.2.2  nathanw 			break;
   1047  1.17.2.12  nathanw 		case WI_RID_ROAMING_MODE:
   1048  1.17.2.12  nathanw 			if (sc->sc_firmware_type == WI_INTERSIL)
   1049  1.17.2.12  nathanw 				break;
   1050  1.17.2.12  nathanw 			/* not supported */
   1051  1.17.2.12  nathanw 			ltv->wi_len = 1;
   1052  1.17.2.12  nathanw 			return 0;
   1053  1.17.2.12  nathanw 		case WI_RID_MICROWAVE_OVEN:
   1054  1.17.2.12  nathanw 			/* not supported */
   1055  1.17.2.12  nathanw 			ltv->wi_len = 1;
   1056  1.17.2.12  nathanw 			return 0;
   1057   1.17.2.2  nathanw 		}
   1058   1.17.2.2  nathanw 	}
   1059   1.17.2.2  nathanw 
   1060   1.17.2.2  nathanw 	/* Tell the NIC to enter record read mode. */
   1061  1.17.2.16  nathanw 	if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_READ, ltv->wi_type, 0, 0))
   1062   1.17.2.2  nathanw 		return(EIO);
   1063   1.17.2.2  nathanw 
   1064   1.17.2.2  nathanw 	/* Seek to the record. */
   1065   1.17.2.2  nathanw 	if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1))
   1066   1.17.2.2  nathanw 		return(EIO);
   1067   1.17.2.2  nathanw 
   1068   1.17.2.2  nathanw 	/*
   1069   1.17.2.2  nathanw 	 * Read the length and record type and make sure they
   1070   1.17.2.2  nathanw 	 * match what we expect (this verifies that we have enough
   1071   1.17.2.2  nathanw 	 * room to hold all of the returned data).
   1072   1.17.2.2  nathanw 	 */
   1073   1.17.2.2  nathanw 	len = CSR_READ_2(sc, WI_DATA1);
   1074   1.17.2.2  nathanw 	if (len > ltv->wi_len)
   1075   1.17.2.2  nathanw 		return(ENOSPC);
   1076   1.17.2.2  nathanw 	code = CSR_READ_2(sc, WI_DATA1);
   1077   1.17.2.2  nathanw 	if (code != ltv->wi_type)
   1078   1.17.2.2  nathanw 		return(EIO);
   1079   1.17.2.2  nathanw 
   1080   1.17.2.2  nathanw 	ltv->wi_len = len;
   1081   1.17.2.2  nathanw 	ltv->wi_type = code;
   1082   1.17.2.2  nathanw 
   1083   1.17.2.2  nathanw 	/* Now read the data. */
   1084   1.17.2.2  nathanw 	ptr = &ltv->wi_val;
   1085   1.17.2.2  nathanw 	if (ltv->wi_len > 1)
   1086   1.17.2.2  nathanw 		CSR_READ_MULTI_STREAM_2(sc, WI_DATA1, ptr, ltv->wi_len - 1);
   1087   1.17.2.2  nathanw 
   1088  1.17.2.16  nathanw 	if (ltv->wi_type == WI_RID_PORTTYPE &&
   1089  1.17.2.16  nathanw 	    sc->wi_ptype == WI_PORTTYPE_IBSS &&
   1090  1.17.2.16  nathanw 	    ltv->wi_val == sc->wi_ibss_port) {
   1091  1.17.2.16  nathanw 		/*
   1092  1.17.2.16  nathanw 		 * Convert vendor IBSS port type to WI_PORTTYPE_IBSS.
   1093  1.17.2.16  nathanw 		 * Since Lucent uses port type 1 for BSS *and* IBSS we
   1094  1.17.2.16  nathanw 		 * have to rely on wi_ptype to distinguish this for us.
   1095  1.17.2.16  nathanw 		 */
   1096  1.17.2.16  nathanw 		ltv->wi_val = htole16(WI_PORTTYPE_IBSS);
   1097  1.17.2.16  nathanw 	} else if (sc->sc_firmware_type != WI_LUCENT) {
   1098   1.17.2.2  nathanw 		int v;
   1099   1.17.2.2  nathanw 
   1100   1.17.2.2  nathanw 		switch (oltv->wi_type) {
   1101   1.17.2.2  nathanw 		case WI_RID_TX_RATE:
   1102   1.17.2.2  nathanw 		case WI_RID_CUR_TX_RATE:
   1103   1.17.2.2  nathanw 			switch (le16toh(ltv->wi_val)) {
   1104   1.17.2.2  nathanw 			case 1: v = 1; break;
   1105   1.17.2.2  nathanw 			case 2: v = 2; break;
   1106   1.17.2.2  nathanw 			case 3:	v = 6; break;
   1107   1.17.2.2  nathanw 			case 4: v = 5; break;
   1108   1.17.2.2  nathanw 			case 7: v = 7; break;
   1109   1.17.2.2  nathanw 			case 8: v = 11; break;
   1110   1.17.2.2  nathanw 			case 15: v = 3; break;
   1111   1.17.2.2  nathanw 			default: v = 0x100 + le16toh(ltv->wi_val); break;
   1112   1.17.2.2  nathanw 			}
   1113   1.17.2.2  nathanw 			oltv->wi_val = htole16(v);
   1114   1.17.2.2  nathanw 			break;
   1115   1.17.2.2  nathanw 		case WI_RID_ENCRYPTION:
   1116   1.17.2.2  nathanw 			oltv->wi_len = 2;
   1117   1.17.2.2  nathanw 			if (le16toh(ltv->wi_val) & 0x01)
   1118   1.17.2.2  nathanw 				oltv->wi_val = htole16(1);
   1119   1.17.2.2  nathanw 			else
   1120   1.17.2.2  nathanw 				oltv->wi_val = htole16(0);
   1121   1.17.2.2  nathanw 			break;
   1122   1.17.2.2  nathanw 		case WI_RID_TX_CRYPT_KEY:
   1123   1.17.2.2  nathanw 			oltv->wi_len = 2;
   1124   1.17.2.2  nathanw 			oltv->wi_val = ltv->wi_val;
   1125   1.17.2.2  nathanw 			break;
   1126  1.17.2.16  nathanw 		case WI_RID_CNFAUTHMODE:
   1127   1.17.2.2  nathanw 			oltv->wi_len = 2;
   1128   1.17.2.2  nathanw 			if (le16toh(ltv->wi_val) & 0x01)
   1129   1.17.2.2  nathanw 				oltv->wi_val = htole16(1);
   1130   1.17.2.2  nathanw 			else if (le16toh(ltv->wi_val) & 0x02)
   1131   1.17.2.2  nathanw 				oltv->wi_val = htole16(2);
   1132   1.17.2.2  nathanw 			break;
   1133   1.17.2.2  nathanw 		}
   1134   1.17.2.2  nathanw 	}
   1135   1.17.2.2  nathanw 
   1136   1.17.2.2  nathanw 	return(0);
   1137   1.17.2.2  nathanw }
   1138   1.17.2.2  nathanw 
   1139   1.17.2.2  nathanw /*
   1140   1.17.2.2  nathanw  * Same as read, except we inject data instead of reading it.
   1141   1.17.2.2  nathanw  */
   1142   1.17.2.2  nathanw static int wi_write_record(sc, ltv)
   1143   1.17.2.2  nathanw 	struct wi_softc		*sc;
   1144   1.17.2.2  nathanw 	struct wi_ltv_gen	*ltv;
   1145   1.17.2.2  nathanw {
   1146   1.17.2.2  nathanw 	u_int16_t		*ptr;
   1147   1.17.2.2  nathanw 	int			i;
   1148   1.17.2.2  nathanw 	struct wi_ltv_gen	p2ltv;
   1149   1.17.2.2  nathanw 
   1150  1.17.2.16  nathanw 	if (ltv->wi_type == WI_RID_PORTTYPE &&
   1151  1.17.2.16  nathanw 	    ltv->wi_val == le16toh(WI_PORTTYPE_IBSS)) {
   1152  1.17.2.16  nathanw 		/* Convert WI_PORTTYPE_IBSS to vendor IBSS port type. */
   1153  1.17.2.16  nathanw 		p2ltv.wi_type = WI_RID_PORTTYPE;
   1154  1.17.2.16  nathanw 		p2ltv.wi_len = 2;
   1155  1.17.2.16  nathanw 		p2ltv.wi_val = sc->wi_ibss_port;
   1156  1.17.2.16  nathanw 		ltv = &p2ltv;
   1157  1.17.2.16  nathanw 	} else if (sc->sc_firmware_type != WI_LUCENT) {
   1158   1.17.2.2  nathanw 		int v;
   1159   1.17.2.2  nathanw 
   1160   1.17.2.2  nathanw 		switch (ltv->wi_type) {
   1161   1.17.2.2  nathanw 		case WI_RID_TX_RATE:
   1162   1.17.2.2  nathanw 			p2ltv.wi_type = WI_RID_TX_RATE;
   1163   1.17.2.2  nathanw 			p2ltv.wi_len = 2;
   1164   1.17.2.2  nathanw 			switch (le16toh(ltv->wi_val)) {
   1165   1.17.2.2  nathanw 			case 1: v = 1; break;
   1166   1.17.2.2  nathanw 			case 2: v = 2; break;
   1167   1.17.2.2  nathanw 			case 3:	v = 15; break;
   1168   1.17.2.2  nathanw 			case 5: v = 4; break;
   1169   1.17.2.2  nathanw 			case 6: v = 3; break;
   1170   1.17.2.2  nathanw 			case 7: v = 7; break;
   1171   1.17.2.2  nathanw 			case 11: v = 8; break;
   1172   1.17.2.2  nathanw 			default: return EINVAL;
   1173   1.17.2.2  nathanw 			}
   1174   1.17.2.2  nathanw 			p2ltv.wi_val = htole16(v);
   1175   1.17.2.2  nathanw 			ltv = &p2ltv;
   1176   1.17.2.2  nathanw 			break;
   1177   1.17.2.2  nathanw 		case WI_RID_ENCRYPTION:
   1178   1.17.2.2  nathanw 			p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
   1179   1.17.2.2  nathanw 			p2ltv.wi_len = 2;
   1180  1.17.2.16  nathanw 			if (le16toh(ltv->wi_val)) {
   1181  1.17.2.16  nathanw 				uint16_t val = PRIVACY_INVOKED;
   1182  1.17.2.16  nathanw 				/*
   1183  1.17.2.16  nathanw 				 * If using shared key WEP we must set the
   1184  1.17.2.16  nathanw 				 * EXCLUDE_UNENCRYPTED bit.  Symbol cards
   1185  1.17.2.16  nathanw 				 * need this bit even when not using shared
   1186  1.17.2.16  nathanw 				 * key.  We can't just test for
   1187  1.17.2.16  nathanw 				 * IEEE80211_AUTH_SHARED since Symbol cards
   1188  1.17.2.16  nathanw 				 * have 2 shared key modes.
   1189  1.17.2.16  nathanw 				 */
   1190  1.17.2.16  nathanw 				if (sc->wi_authtype != IEEE80211_AUTH_OPEN ||
   1191  1.17.2.16  nathanw 				    sc->sc_firmware_type == WI_SYMBOL)
   1192  1.17.2.16  nathanw 					val |= EXCLUDE_UNENCRYPTED;
   1193  1.17.2.16  nathanw 				/* Tx encryption is broken in Host-AP mode. */
   1194  1.17.2.16  nathanw 				if (sc->wi_ptype == WI_PORTTYPE_HOSTAP)
   1195  1.17.2.16  nathanw 					val |= HOST_ENCRYPT;
   1196  1.17.2.16  nathanw 				p2ltv.wi_val = htole16(val);
   1197  1.17.2.16  nathanw 			} else
   1198  1.17.2.12  nathanw 				p2ltv.wi_val =
   1199  1.17.2.12  nathanw 				    htole16(HOST_ENCRYPT | HOST_DECRYPT);
   1200   1.17.2.2  nathanw 			ltv = &p2ltv;
   1201   1.17.2.2  nathanw 			break;
   1202   1.17.2.2  nathanw 		case WI_RID_TX_CRYPT_KEY:
   1203   1.17.2.2  nathanw 			p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
   1204   1.17.2.2  nathanw 			p2ltv.wi_len = 2;
   1205   1.17.2.2  nathanw 			p2ltv.wi_val = ltv->wi_val;
   1206   1.17.2.2  nathanw 			ltv = &p2ltv;
   1207   1.17.2.2  nathanw 			break;
   1208   1.17.2.2  nathanw 		case WI_RID_DEFLT_CRYPT_KEYS:
   1209   1.17.2.2  nathanw 		    {
   1210   1.17.2.2  nathanw 			int error;
   1211  1.17.2.11  nathanw 			int keylen;
   1212   1.17.2.2  nathanw 			struct wi_ltv_str	ws;
   1213   1.17.2.2  nathanw 			struct wi_ltv_keys	*wk = (struct wi_ltv_keys *)ltv;
   1214  1.17.2.11  nathanw 
   1215  1.17.2.16  nathanw 			keylen = le16toh(wk->wi_keys[sc->wi_tx_key].wi_keylen);
   1216  1.17.2.11  nathanw 
   1217   1.17.2.2  nathanw 			for (i = 0; i < 4; i++) {
   1218  1.17.2.10  nathanw 				memset(&ws, 0, sizeof(ws));
   1219  1.17.2.11  nathanw 				ws.wi_len = (keylen > 5) ? 8 : 4;
   1220   1.17.2.2  nathanw 				ws.wi_type = WI_RID_P2_CRYPT_KEY0 + i;
   1221  1.17.2.11  nathanw 				memcpy(ws.wi_str,
   1222  1.17.2.11  nathanw 					&wk->wi_keys[i].wi_keydat, keylen);
   1223  1.17.2.11  nathanw 				error = wi_write_record(sc,
   1224  1.17.2.11  nathanw 					(struct wi_ltv_gen *)&ws);
   1225  1.17.2.11  nathanw 				if (error)
   1226   1.17.2.2  nathanw 					return error;
   1227   1.17.2.2  nathanw 			}
   1228   1.17.2.2  nathanw 			return 0;
   1229   1.17.2.2  nathanw 		    }
   1230  1.17.2.16  nathanw 		case WI_RID_CNFAUTHMODE:
   1231  1.17.2.16  nathanw 			p2ltv.wi_type = WI_RID_CNFAUTHMODE;
   1232   1.17.2.2  nathanw 			p2ltv.wi_len = 2;
   1233   1.17.2.2  nathanw 			if (le16toh(ltv->wi_val) == 1)
   1234   1.17.2.2  nathanw 				p2ltv.wi_val = htole16(0x01);
   1235   1.17.2.2  nathanw 			else if (le16toh(ltv->wi_val) == 2)
   1236   1.17.2.2  nathanw 				p2ltv.wi_val = htole16(0x02);
   1237   1.17.2.2  nathanw 			ltv = &p2ltv;
   1238   1.17.2.2  nathanw 			break;
   1239  1.17.2.12  nathanw 
   1240  1.17.2.12  nathanw 		case WI_RID_ROAMING_MODE:
   1241  1.17.2.12  nathanw 			if (sc->sc_firmware_type == WI_INTERSIL)
   1242  1.17.2.12  nathanw 				break;
   1243  1.17.2.12  nathanw 			/* not supported */
   1244  1.17.2.12  nathanw 			return 0;
   1245  1.17.2.12  nathanw 
   1246  1.17.2.12  nathanw 		case WI_RID_MICROWAVE_OVEN:
   1247  1.17.2.12  nathanw 			/* not supported */
   1248  1.17.2.12  nathanw 			return 0;
   1249   1.17.2.2  nathanw 		}
   1250   1.17.2.2  nathanw 	}
   1251   1.17.2.2  nathanw 
   1252   1.17.2.2  nathanw 	if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1))
   1253   1.17.2.2  nathanw 		return(EIO);
   1254   1.17.2.2  nathanw 
   1255   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_DATA1, ltv->wi_len);
   1256   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_DATA1, ltv->wi_type);
   1257   1.17.2.2  nathanw 
   1258   1.17.2.2  nathanw 	/* Write data */
   1259   1.17.2.2  nathanw 	ptr = &ltv->wi_val;
   1260   1.17.2.2  nathanw 	if (ltv->wi_len > 1)
   1261   1.17.2.2  nathanw 		CSR_WRITE_MULTI_STREAM_2(sc, WI_DATA1, ptr, ltv->wi_len - 1);
   1262   1.17.2.2  nathanw 
   1263  1.17.2.16  nathanw 	if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_WRITE, ltv->wi_type, 0, 0))
   1264   1.17.2.2  nathanw 		return(EIO);
   1265   1.17.2.2  nathanw 
   1266   1.17.2.2  nathanw 	return(0);
   1267   1.17.2.2  nathanw }
   1268   1.17.2.2  nathanw 
   1269   1.17.2.2  nathanw static int wi_seek(sc, id, off, chan)
   1270   1.17.2.2  nathanw 	struct wi_softc		*sc;
   1271   1.17.2.2  nathanw 	int			id, off, chan;
   1272   1.17.2.2  nathanw {
   1273   1.17.2.2  nathanw 	int			i;
   1274   1.17.2.2  nathanw 	int			selreg, offreg;
   1275   1.17.2.2  nathanw 	int 			status;
   1276   1.17.2.2  nathanw 
   1277   1.17.2.2  nathanw 	switch (chan) {
   1278   1.17.2.2  nathanw 	case WI_BAP0:
   1279   1.17.2.2  nathanw 		selreg = WI_SEL0;
   1280   1.17.2.2  nathanw 		offreg = WI_OFF0;
   1281   1.17.2.2  nathanw 		break;
   1282   1.17.2.2  nathanw 	case WI_BAP1:
   1283   1.17.2.2  nathanw 		selreg = WI_SEL1;
   1284   1.17.2.2  nathanw 		offreg = WI_OFF1;
   1285   1.17.2.2  nathanw 		break;
   1286   1.17.2.2  nathanw 	default:
   1287   1.17.2.2  nathanw 		printf("%s: invalid data path: %x\n",
   1288   1.17.2.2  nathanw 		    sc->sc_dev.dv_xname, chan);
   1289   1.17.2.2  nathanw 		return(EIO);
   1290   1.17.2.2  nathanw 	}
   1291   1.17.2.2  nathanw 
   1292   1.17.2.2  nathanw 	CSR_WRITE_2(sc, selreg, id);
   1293   1.17.2.2  nathanw 	CSR_WRITE_2(sc, offreg, off);
   1294   1.17.2.2  nathanw 
   1295   1.17.2.2  nathanw 	for (i = 0; i < WI_TIMEOUT; i++) {
   1296   1.17.2.2  nathanw 	  	status = CSR_READ_2(sc, offreg);
   1297   1.17.2.2  nathanw 		if (!(status & (WI_OFF_BUSY|WI_OFF_ERR)))
   1298   1.17.2.2  nathanw 			break;
   1299   1.17.2.2  nathanw 	}
   1300   1.17.2.2  nathanw 
   1301   1.17.2.2  nathanw 	if (i == WI_TIMEOUT) {
   1302   1.17.2.2  nathanw 		printf("%s: timeout in wi_seek to %x/%x; last status %x\n",
   1303   1.17.2.2  nathanw 		       sc->sc_dev.dv_xname, id, off, status);
   1304   1.17.2.2  nathanw 		return(ETIMEDOUT);
   1305   1.17.2.2  nathanw 	}
   1306   1.17.2.2  nathanw 	return(0);
   1307   1.17.2.2  nathanw }
   1308   1.17.2.2  nathanw 
   1309   1.17.2.2  nathanw static int wi_read_data(sc, id, off, buf, len)
   1310   1.17.2.2  nathanw 	struct wi_softc		*sc;
   1311   1.17.2.2  nathanw 	int			id, off;
   1312   1.17.2.2  nathanw 	caddr_t			buf;
   1313   1.17.2.2  nathanw 	int			len;
   1314   1.17.2.2  nathanw {
   1315   1.17.2.2  nathanw 	u_int16_t		*ptr;
   1316   1.17.2.2  nathanw 
   1317   1.17.2.2  nathanw 	if (wi_seek(sc, id, off, WI_BAP1))
   1318   1.17.2.2  nathanw 		return(EIO);
   1319   1.17.2.2  nathanw 
   1320   1.17.2.2  nathanw 	ptr = (u_int16_t *)buf;
   1321   1.17.2.2  nathanw 	CSR_READ_MULTI_STREAM_2(sc, WI_DATA1, ptr, len / 2);
   1322   1.17.2.2  nathanw 
   1323   1.17.2.2  nathanw 	return(0);
   1324   1.17.2.2  nathanw }
   1325   1.17.2.2  nathanw 
   1326   1.17.2.2  nathanw /*
   1327   1.17.2.2  nathanw  * According to the comments in the HCF Light code, there is a bug in
   1328   1.17.2.2  nathanw  * the Hermes (or possibly in certain Hermes firmware revisions) where
   1329   1.17.2.2  nathanw  * the chip's internal autoincrement counter gets thrown off during
   1330   1.17.2.2  nathanw  * data writes: the autoincrement is missed, causing one data word to
   1331   1.17.2.2  nathanw  * be overwritten and subsequent words to be written to the wrong memory
   1332   1.17.2.2  nathanw  * locations. The end result is that we could end up transmitting bogus
   1333   1.17.2.2  nathanw  * frames without realizing it. The workaround for this is to write a
   1334   1.17.2.2  nathanw  * couple of extra guard words after the end of the transfer, then
   1335   1.17.2.2  nathanw  * attempt to read then back. If we fail to locate the guard words where
   1336   1.17.2.2  nathanw  * we expect them, we preform the transfer over again.
   1337   1.17.2.2  nathanw  */
   1338   1.17.2.2  nathanw static int wi_write_data(sc, id, off, buf, len)
   1339   1.17.2.2  nathanw 	struct wi_softc		*sc;
   1340   1.17.2.2  nathanw 	int			id, off;
   1341   1.17.2.2  nathanw 	caddr_t			buf;
   1342   1.17.2.2  nathanw 	int			len;
   1343   1.17.2.2  nathanw {
   1344   1.17.2.2  nathanw 	u_int16_t		*ptr;
   1345   1.17.2.2  nathanw 
   1346   1.17.2.2  nathanw #ifdef WI_HERMES_AUTOINC_WAR
   1347   1.17.2.2  nathanw again:
   1348   1.17.2.2  nathanw #endif
   1349   1.17.2.2  nathanw 
   1350   1.17.2.2  nathanw 	if (wi_seek(sc, id, off, WI_BAP0))
   1351   1.17.2.2  nathanw 		return(EIO);
   1352   1.17.2.2  nathanw 
   1353   1.17.2.2  nathanw 	ptr = (u_int16_t *)buf;
   1354   1.17.2.2  nathanw 	CSR_WRITE_MULTI_STREAM_2(sc, WI_DATA0, ptr, len / 2);
   1355   1.17.2.2  nathanw 
   1356   1.17.2.2  nathanw #ifdef WI_HERMES_AUTOINC_WAR
   1357   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_DATA0, 0x1234);
   1358   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_DATA0, 0x5678);
   1359   1.17.2.2  nathanw 
   1360   1.17.2.2  nathanw 	if (wi_seek(sc, id, off + len, WI_BAP0))
   1361   1.17.2.2  nathanw 		return(EIO);
   1362   1.17.2.2  nathanw 
   1363   1.17.2.2  nathanw 	if (CSR_READ_2(sc, WI_DATA0) != 0x1234 ||
   1364   1.17.2.2  nathanw 	    CSR_READ_2(sc, WI_DATA0) != 0x5678)
   1365   1.17.2.2  nathanw 		goto again;
   1366   1.17.2.2  nathanw #endif
   1367   1.17.2.2  nathanw 
   1368   1.17.2.2  nathanw 	return(0);
   1369   1.17.2.2  nathanw }
   1370   1.17.2.2  nathanw 
   1371   1.17.2.2  nathanw /*
   1372   1.17.2.2  nathanw  * Allocate a region of memory inside the NIC and zero
   1373   1.17.2.2  nathanw  * it out.
   1374   1.17.2.2  nathanw  */
   1375   1.17.2.2  nathanw static int wi_alloc_nicmem(sc, len, id)
   1376   1.17.2.2  nathanw 	struct wi_softc		*sc;
   1377   1.17.2.2  nathanw 	int			len;
   1378   1.17.2.2  nathanw 	int			*id;
   1379   1.17.2.2  nathanw {
   1380   1.17.2.2  nathanw 	int			i;
   1381   1.17.2.2  nathanw 
   1382  1.17.2.16  nathanw 	if (wi_cmd(sc, WI_CMD_ALLOC_MEM, len, 0, 0)) {
   1383   1.17.2.2  nathanw 		printf("%s: failed to allocate %d bytes on NIC\n",
   1384   1.17.2.2  nathanw 		    sc->sc_dev.dv_xname, len);
   1385   1.17.2.2  nathanw 		return(ENOMEM);
   1386   1.17.2.2  nathanw 	}
   1387   1.17.2.2  nathanw 
   1388   1.17.2.2  nathanw 	for (i = 0; i < WI_TIMEOUT; i++) {
   1389   1.17.2.2  nathanw 		if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_ALLOC)
   1390   1.17.2.2  nathanw 			break;
   1391   1.17.2.2  nathanw 	}
   1392   1.17.2.2  nathanw 
   1393   1.17.2.2  nathanw 	if (i == WI_TIMEOUT) {
   1394   1.17.2.2  nathanw 		printf("%s: TIMED OUT in alloc\n", sc->sc_dev.dv_xname);
   1395   1.17.2.2  nathanw 		return(ETIMEDOUT);
   1396   1.17.2.2  nathanw 	}
   1397   1.17.2.2  nathanw 
   1398   1.17.2.2  nathanw 	*id = CSR_READ_2(sc, WI_ALLOC_FID);
   1399  1.17.2.11  nathanw 	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
   1400   1.17.2.2  nathanw 
   1401   1.17.2.2  nathanw 	if (wi_seek(sc, *id, 0, WI_BAP0)) {
   1402   1.17.2.2  nathanw 		printf("%s: seek failed in alloc\n", sc->sc_dev.dv_xname);
   1403   1.17.2.2  nathanw 		return(EIO);
   1404   1.17.2.2  nathanw 	}
   1405   1.17.2.2  nathanw 
   1406   1.17.2.2  nathanw 	for (i = 0; i < len / 2; i++)
   1407   1.17.2.2  nathanw 		CSR_WRITE_2(sc, WI_DATA0, 0);
   1408   1.17.2.2  nathanw 
   1409   1.17.2.2  nathanw 	return(0);
   1410   1.17.2.2  nathanw }
   1411   1.17.2.2  nathanw 
   1412   1.17.2.2  nathanw static void wi_setmulti(sc)
   1413   1.17.2.2  nathanw 	struct wi_softc		*sc;
   1414   1.17.2.2  nathanw {
   1415   1.17.2.2  nathanw 	struct ifnet		*ifp;
   1416   1.17.2.2  nathanw 	int			i = 0;
   1417   1.17.2.2  nathanw 	struct wi_ltv_mcast	mcast;
   1418   1.17.2.2  nathanw 	struct ether_multi *enm;
   1419   1.17.2.2  nathanw 	struct ether_multistep estep;
   1420   1.17.2.2  nathanw 	struct ethercom *ec = &sc->sc_ethercom;
   1421   1.17.2.2  nathanw 
   1422   1.17.2.2  nathanw 	ifp = &sc->sc_ethercom.ec_if;
   1423   1.17.2.2  nathanw 
   1424   1.17.2.2  nathanw 	if ((ifp->if_flags & IFF_PROMISC) != 0) {
   1425   1.17.2.2  nathanw allmulti:
   1426   1.17.2.2  nathanw 		ifp->if_flags |= IFF_ALLMULTI;
   1427   1.17.2.3  nathanw 		memset((char *)&mcast, 0, sizeof(mcast));
   1428   1.17.2.8  nathanw 		mcast.wi_type = WI_RID_MCAST_LIST;
   1429   1.17.2.2  nathanw 		mcast.wi_len = ((ETHER_ADDR_LEN / 2) * 16) + 1;
   1430   1.17.2.2  nathanw 
   1431   1.17.2.2  nathanw 		wi_write_record(sc, (struct wi_ltv_gen *)&mcast);
   1432   1.17.2.2  nathanw 		return;
   1433   1.17.2.2  nathanw 	}
   1434   1.17.2.2  nathanw 
   1435   1.17.2.2  nathanw 	i = 0;
   1436   1.17.2.2  nathanw 	ETHER_FIRST_MULTI(estep, ec, enm);
   1437   1.17.2.2  nathanw 	while (enm != NULL) {
   1438   1.17.2.2  nathanw 		/* Punt on ranges or too many multicast addresses. */
   1439   1.17.2.3  nathanw 		if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
   1440   1.17.2.2  nathanw 		    ETHER_ADDR_LEN) != 0 ||
   1441   1.17.2.2  nathanw 		    i >= 16)
   1442   1.17.2.2  nathanw 			goto allmulti;
   1443   1.17.2.2  nathanw 
   1444   1.17.2.3  nathanw 		memcpy((char *)&mcast.wi_mcast[i], enm->enm_addrlo,
   1445   1.17.2.3  nathanw 		    ETHER_ADDR_LEN);
   1446   1.17.2.2  nathanw 		i++;
   1447   1.17.2.2  nathanw 		ETHER_NEXT_MULTI(estep, enm);
   1448   1.17.2.2  nathanw 	}
   1449   1.17.2.2  nathanw 
   1450   1.17.2.2  nathanw 	ifp->if_flags &= ~IFF_ALLMULTI;
   1451   1.17.2.8  nathanw 	mcast.wi_type = WI_RID_MCAST_LIST;
   1452   1.17.2.2  nathanw 	mcast.wi_len = ((ETHER_ADDR_LEN / 2) * i) + 1;
   1453   1.17.2.2  nathanw 	wi_write_record(sc, (struct wi_ltv_gen *)&mcast);
   1454   1.17.2.2  nathanw }
   1455   1.17.2.2  nathanw 
   1456   1.17.2.2  nathanw static int
   1457   1.17.2.2  nathanw wi_setdef(sc, wreq)
   1458   1.17.2.2  nathanw 	struct wi_softc		*sc;
   1459   1.17.2.2  nathanw 	struct wi_req		*wreq;
   1460   1.17.2.2  nathanw {
   1461   1.17.2.2  nathanw 	struct sockaddr_dl	*sdl;
   1462   1.17.2.2  nathanw 	struct ifnet		*ifp;
   1463   1.17.2.2  nathanw 	int error = 0;
   1464   1.17.2.2  nathanw 
   1465   1.17.2.2  nathanw 	ifp = &sc->sc_ethercom.ec_if;
   1466   1.17.2.2  nathanw 
   1467   1.17.2.2  nathanw 	switch(wreq->wi_type) {
   1468   1.17.2.2  nathanw 	case WI_RID_MAC_NODE:
   1469   1.17.2.2  nathanw 		sdl = (struct sockaddr_dl *)ifp->if_sadl;
   1470   1.17.2.3  nathanw 		memcpy((char *)&sc->sc_macaddr, (char *)&wreq->wi_val,
   1471   1.17.2.2  nathanw 		    ETHER_ADDR_LEN);
   1472   1.17.2.3  nathanw 		memcpy(LLADDR(sdl), (char *)&wreq->wi_val, ETHER_ADDR_LEN);
   1473   1.17.2.2  nathanw 		break;
   1474   1.17.2.2  nathanw 	case WI_RID_PORTTYPE:
   1475  1.17.2.16  nathanw 		error = wi_sync_media(sc, le16toh(wreq->wi_val[0]),
   1476  1.17.2.16  nathanw 		    sc->wi_tx_rate);
   1477   1.17.2.2  nathanw 		break;
   1478   1.17.2.2  nathanw 	case WI_RID_TX_RATE:
   1479  1.17.2.16  nathanw 		error = wi_sync_media(sc, sc->wi_ptype,
   1480  1.17.2.16  nathanw 		    le16toh(wreq->wi_val[0]));
   1481   1.17.2.2  nathanw 		break;
   1482   1.17.2.2  nathanw 	case WI_RID_MAX_DATALEN:
   1483   1.17.2.2  nathanw 		sc->wi_max_data_len = le16toh(wreq->wi_val[0]);
   1484   1.17.2.2  nathanw 		break;
   1485   1.17.2.2  nathanw 	case WI_RID_RTS_THRESH:
   1486   1.17.2.2  nathanw 		sc->wi_rts_thresh = le16toh(wreq->wi_val[0]);
   1487   1.17.2.2  nathanw 		break;
   1488   1.17.2.2  nathanw 	case WI_RID_SYSTEM_SCALE:
   1489   1.17.2.2  nathanw 		sc->wi_ap_density = le16toh(wreq->wi_val[0]);
   1490   1.17.2.2  nathanw 		break;
   1491   1.17.2.2  nathanw 	case WI_RID_CREATE_IBSS:
   1492  1.17.2.16  nathanw 		sc->wi_create_ibss = le16toh(wreq->wi_val[0]);
   1493  1.17.2.16  nathanw 		error = wi_sync_media(sc, sc->wi_ptype, sc->wi_tx_rate);
   1494   1.17.2.2  nathanw 		break;
   1495   1.17.2.2  nathanw 	case WI_RID_OWN_CHNL:
   1496   1.17.2.2  nathanw 		sc->wi_channel = le16toh(wreq->wi_val[0]);
   1497   1.17.2.2  nathanw 		break;
   1498   1.17.2.2  nathanw 	case WI_RID_NODENAME:
   1499   1.17.2.2  nathanw 		error = wi_set_ssid(&sc->wi_nodeid,
   1500   1.17.2.2  nathanw 		    (u_int8_t *)&wreq->wi_val[1], le16toh(wreq->wi_val[0]));
   1501   1.17.2.2  nathanw 		break;
   1502   1.17.2.2  nathanw 	case WI_RID_DESIRED_SSID:
   1503   1.17.2.2  nathanw 		error = wi_set_ssid(&sc->wi_netid,
   1504   1.17.2.2  nathanw 		    (u_int8_t *)&wreq->wi_val[1], le16toh(wreq->wi_val[0]));
   1505   1.17.2.2  nathanw 		break;
   1506   1.17.2.2  nathanw 	case WI_RID_OWN_SSID:
   1507   1.17.2.2  nathanw 		error = wi_set_ssid(&sc->wi_ibssid,
   1508   1.17.2.2  nathanw 		    (u_int8_t *)&wreq->wi_val[1], le16toh(wreq->wi_val[0]));
   1509   1.17.2.2  nathanw 		break;
   1510   1.17.2.2  nathanw 	case WI_RID_PM_ENABLED:
   1511   1.17.2.2  nathanw 		sc->wi_pm_enabled = le16toh(wreq->wi_val[0]);
   1512   1.17.2.2  nathanw 		break;
   1513   1.17.2.2  nathanw 	case WI_RID_MICROWAVE_OVEN:
   1514   1.17.2.2  nathanw 		sc->wi_mor_enabled = le16toh(wreq->wi_val[0]);
   1515   1.17.2.2  nathanw 		break;
   1516   1.17.2.2  nathanw 	case WI_RID_MAX_SLEEP:
   1517   1.17.2.2  nathanw 		sc->wi_max_sleep = le16toh(wreq->wi_val[0]);
   1518   1.17.2.2  nathanw 		break;
   1519  1.17.2.16  nathanw 	case WI_RID_CNFAUTHMODE:
   1520   1.17.2.2  nathanw 		sc->wi_authtype = le16toh(wreq->wi_val[0]);
   1521   1.17.2.2  nathanw 		break;
   1522   1.17.2.2  nathanw 	case WI_RID_ROAMING_MODE:
   1523   1.17.2.2  nathanw 		sc->wi_roaming = le16toh(wreq->wi_val[0]);
   1524   1.17.2.2  nathanw 		break;
   1525   1.17.2.2  nathanw 	case WI_RID_ENCRYPTION:
   1526   1.17.2.2  nathanw 		sc->wi_use_wep = le16toh(wreq->wi_val[0]);
   1527   1.17.2.2  nathanw 		break;
   1528   1.17.2.2  nathanw 	case WI_RID_TX_CRYPT_KEY:
   1529   1.17.2.2  nathanw 		sc->wi_tx_key = le16toh(wreq->wi_val[0]);
   1530   1.17.2.2  nathanw 		break;
   1531   1.17.2.2  nathanw 	case WI_RID_DEFLT_CRYPT_KEYS:
   1532   1.17.2.3  nathanw 		memcpy((char *)&sc->wi_keys, (char *)wreq,
   1533   1.17.2.2  nathanw 		    sizeof(struct wi_ltv_keys));
   1534   1.17.2.2  nathanw 		break;
   1535   1.17.2.2  nathanw 	default:
   1536   1.17.2.2  nathanw 		error = EINVAL;
   1537   1.17.2.2  nathanw 		break;
   1538   1.17.2.2  nathanw 	}
   1539   1.17.2.2  nathanw 
   1540   1.17.2.2  nathanw 	return (error);
   1541   1.17.2.2  nathanw }
   1542   1.17.2.2  nathanw 
   1543   1.17.2.2  nathanw static int
   1544   1.17.2.2  nathanw wi_getdef(sc, wreq)
   1545   1.17.2.2  nathanw 	struct wi_softc		*sc;
   1546   1.17.2.2  nathanw 	struct wi_req		*wreq;
   1547   1.17.2.2  nathanw {
   1548   1.17.2.2  nathanw 	struct sockaddr_dl	*sdl;
   1549   1.17.2.2  nathanw 	struct ifnet		*ifp;
   1550   1.17.2.2  nathanw 	int error = 0;
   1551   1.17.2.2  nathanw 
   1552   1.17.2.2  nathanw 	ifp = &sc->sc_ethercom.ec_if;
   1553   1.17.2.2  nathanw 
   1554   1.17.2.2  nathanw 	wreq->wi_len = 2;			/* XXX */
   1555   1.17.2.2  nathanw 	switch (wreq->wi_type) {
   1556   1.17.2.2  nathanw 	case WI_RID_MAC_NODE:
   1557   1.17.2.2  nathanw 		wreq->wi_len += ETHER_ADDR_LEN / 2 - 1;
   1558   1.17.2.2  nathanw 		sdl = (struct sockaddr_dl *)ifp->if_sadl;
   1559   1.17.2.3  nathanw 		memcpy(&wreq->wi_val, &sc->sc_macaddr, ETHER_ADDR_LEN);
   1560   1.17.2.3  nathanw 		memcpy(&wreq->wi_val, LLADDR(sdl), ETHER_ADDR_LEN);
   1561   1.17.2.2  nathanw 		break;
   1562   1.17.2.2  nathanw 	case WI_RID_PORTTYPE:
   1563   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_ptype);
   1564   1.17.2.2  nathanw 		break;
   1565   1.17.2.2  nathanw 	case WI_RID_TX_RATE:
   1566   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_tx_rate);
   1567   1.17.2.2  nathanw 		break;
   1568   1.17.2.2  nathanw 	case WI_RID_MAX_DATALEN:
   1569   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_max_data_len);
   1570   1.17.2.2  nathanw 		break;
   1571   1.17.2.2  nathanw 	case WI_RID_RTS_THRESH:
   1572   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_rts_thresh);
   1573   1.17.2.2  nathanw 		break;
   1574   1.17.2.2  nathanw 	case WI_RID_SYSTEM_SCALE:
   1575   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_ap_density);
   1576   1.17.2.2  nathanw 		break;
   1577   1.17.2.2  nathanw 	case WI_RID_CREATE_IBSS:
   1578  1.17.2.16  nathanw 		wreq->wi_val[0] = htole16(sc->wi_create_ibss);
   1579   1.17.2.2  nathanw 		break;
   1580   1.17.2.2  nathanw 	case WI_RID_OWN_CHNL:
   1581   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_channel);
   1582   1.17.2.2  nathanw 		break;
   1583   1.17.2.2  nathanw 	case WI_RID_NODENAME:
   1584   1.17.2.2  nathanw 		wi_request_fill_ssid(wreq, &sc->wi_nodeid);
   1585   1.17.2.2  nathanw 		break;
   1586   1.17.2.2  nathanw 	case WI_RID_DESIRED_SSID:
   1587   1.17.2.2  nathanw 		wi_request_fill_ssid(wreq, &sc->wi_netid);
   1588   1.17.2.2  nathanw 		break;
   1589   1.17.2.2  nathanw 	case WI_RID_OWN_SSID:
   1590   1.17.2.2  nathanw 		wi_request_fill_ssid(wreq, &sc->wi_ibssid);
   1591   1.17.2.2  nathanw 		break;
   1592   1.17.2.2  nathanw 	case WI_RID_PM_ENABLED:
   1593   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_pm_enabled);
   1594   1.17.2.2  nathanw 		break;
   1595   1.17.2.2  nathanw 	case WI_RID_MICROWAVE_OVEN:
   1596   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_mor_enabled);
   1597   1.17.2.2  nathanw 		break;
   1598   1.17.2.2  nathanw 	case WI_RID_MAX_SLEEP:
   1599   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_max_sleep);
   1600   1.17.2.2  nathanw 		break;
   1601  1.17.2.16  nathanw 	case WI_RID_CNFAUTHMODE:
   1602   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_authtype);
   1603   1.17.2.2  nathanw 		break;
   1604   1.17.2.2  nathanw 	case WI_RID_ROAMING_MODE:
   1605   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_roaming);
   1606   1.17.2.2  nathanw 		break;
   1607   1.17.2.2  nathanw 	case WI_RID_WEP_AVAIL:
   1608  1.17.2.16  nathanw 		wreq->wi_val[0] = (sc->wi_flags & WI_FLAGS_HAS_WEP) ?
   1609  1.17.2.16  nathanw 		    htole16(1) : htole16(0);
   1610   1.17.2.2  nathanw 		break;
   1611   1.17.2.2  nathanw 	case WI_RID_ENCRYPTION:
   1612   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_use_wep);
   1613   1.17.2.2  nathanw 		break;
   1614   1.17.2.2  nathanw 	case WI_RID_TX_CRYPT_KEY:
   1615   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_tx_key);
   1616   1.17.2.2  nathanw 		break;
   1617   1.17.2.2  nathanw 	case WI_RID_DEFLT_CRYPT_KEYS:
   1618   1.17.2.2  nathanw 		wreq->wi_len += sizeof(struct wi_ltv_keys) / 2 - 1;
   1619   1.17.2.3  nathanw 		memcpy(wreq, &sc->wi_keys, sizeof(struct wi_ltv_keys));
   1620   1.17.2.2  nathanw 		break;
   1621   1.17.2.2  nathanw 	default:
   1622   1.17.2.2  nathanw #if 0
   1623   1.17.2.2  nathanw 		error = EIO;
   1624   1.17.2.2  nathanw #else
   1625   1.17.2.2  nathanw #ifdef WI_DEBUG
   1626   1.17.2.2  nathanw 		printf("%s: wi_getdef: unknown request %d\n",
   1627   1.17.2.2  nathanw 		    sc->sc_dev.dv_xname, wreq->wi_type);
   1628   1.17.2.2  nathanw #endif
   1629   1.17.2.2  nathanw #endif
   1630   1.17.2.2  nathanw 		break;
   1631   1.17.2.2  nathanw 	}
   1632   1.17.2.2  nathanw 
   1633   1.17.2.2  nathanw 	return (error);
   1634   1.17.2.2  nathanw }
   1635   1.17.2.2  nathanw 
   1636   1.17.2.2  nathanw static int
   1637   1.17.2.2  nathanw wi_ioctl(ifp, command, data)
   1638   1.17.2.2  nathanw 	struct ifnet		*ifp;
   1639   1.17.2.2  nathanw 	u_long			command;
   1640   1.17.2.2  nathanw 	caddr_t			data;
   1641   1.17.2.2  nathanw {
   1642   1.17.2.7  nathanw 	int			s, error = 0;
   1643  1.17.2.10  nathanw 	int			len;
   1644   1.17.2.2  nathanw 	struct wi_softc		*sc = ifp->if_softc;
   1645   1.17.2.2  nathanw 	struct wi_req		wreq;
   1646   1.17.2.2  nathanw 	struct ifreq		*ifr;
   1647  1.17.2.14  nathanw 	struct proc *p = curproc;
   1648   1.17.2.2  nathanw 	struct ieee80211_nwid nwid;
   1649   1.17.2.2  nathanw 
   1650   1.17.2.2  nathanw 	if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
   1651   1.17.2.2  nathanw 		return (ENXIO);
   1652   1.17.2.2  nathanw 
   1653   1.17.2.2  nathanw 	s = splnet();
   1654   1.17.2.2  nathanw 
   1655   1.17.2.2  nathanw 	ifr = (struct ifreq *)data;
   1656   1.17.2.2  nathanw 	switch (command) {
   1657   1.17.2.2  nathanw 	case SIOCSIFADDR:
   1658   1.17.2.2  nathanw 	case SIOCGIFADDR:
   1659   1.17.2.2  nathanw 	case SIOCSIFMTU:
   1660   1.17.2.2  nathanw 		error = ether_ioctl(ifp, command, data);
   1661   1.17.2.2  nathanw 		break;
   1662   1.17.2.2  nathanw 	case SIOCSIFFLAGS:
   1663   1.17.2.2  nathanw 		if (ifp->if_flags & IFF_UP) {
   1664   1.17.2.2  nathanw 			if (ifp->if_flags & IFF_RUNNING &&
   1665   1.17.2.2  nathanw 			    ifp->if_flags & IFF_PROMISC &&
   1666   1.17.2.2  nathanw 			    !(sc->wi_if_flags & IFF_PROMISC)) {
   1667  1.17.2.16  nathanw 				if (sc->wi_ptype != WI_PORTTYPE_HOSTAP)
   1668  1.17.2.16  nathanw 					WI_SETVAL(WI_RID_PROMISC, 1);
   1669   1.17.2.2  nathanw 			} else if (ifp->if_flags & IFF_RUNNING &&
   1670   1.17.2.2  nathanw 			    !(ifp->if_flags & IFF_PROMISC) &&
   1671   1.17.2.2  nathanw 			    sc->wi_if_flags & IFF_PROMISC) {
   1672  1.17.2.16  nathanw 				if (sc->wi_ptype != WI_PORTTYPE_HOSTAP)
   1673  1.17.2.16  nathanw 					WI_SETVAL(WI_RID_PROMISC, 0);
   1674  1.17.2.16  nathanw 			} else
   1675  1.17.2.16  nathanw 				wi_init(ifp);
   1676  1.17.2.16  nathanw 		} else if (ifp->if_flags & IFF_RUNNING)
   1677  1.17.2.16  nathanw 			wi_stop(ifp, 0);
   1678   1.17.2.2  nathanw 		sc->wi_if_flags = ifp->if_flags;
   1679   1.17.2.2  nathanw 
   1680   1.17.2.2  nathanw 		if (!(ifp->if_flags & IFF_UP)) {
   1681   1.17.2.2  nathanw 			if (sc->sc_enabled) {
   1682   1.17.2.2  nathanw 				if (sc->sc_disable)
   1683   1.17.2.2  nathanw 					(*sc->sc_disable)(sc);
   1684   1.17.2.2  nathanw 				sc->sc_enabled = 0;
   1685   1.17.2.2  nathanw 				ifp->if_flags &= ~IFF_RUNNING;
   1686   1.17.2.2  nathanw 			}
   1687   1.17.2.2  nathanw 		}
   1688   1.17.2.2  nathanw 		error = 0;
   1689   1.17.2.2  nathanw 		break;
   1690   1.17.2.2  nathanw 	case SIOCADDMULTI:
   1691   1.17.2.2  nathanw 	case SIOCDELMULTI:
   1692   1.17.2.2  nathanw 		error = (command == SIOCADDMULTI) ?
   1693   1.17.2.2  nathanw 			ether_addmulti(ifr, &sc->sc_ethercom) :
   1694   1.17.2.2  nathanw 			ether_delmulti(ifr, &sc->sc_ethercom);
   1695   1.17.2.2  nathanw 		if (error == ENETRESET) {
   1696   1.17.2.2  nathanw 			if (sc->sc_enabled != 0) {
   1697   1.17.2.2  nathanw 				/*
   1698   1.17.2.2  nathanw 				 * Multicast list has changed.  Set the
   1699   1.17.2.2  nathanw 				 * hardware filter accordingly.
   1700   1.17.2.2  nathanw 				 */
   1701   1.17.2.2  nathanw 				wi_setmulti(sc);
   1702   1.17.2.2  nathanw 			}
   1703   1.17.2.2  nathanw 			error = 0;
   1704   1.17.2.2  nathanw 		}
   1705   1.17.2.2  nathanw 		break;
   1706   1.17.2.2  nathanw 	case SIOCSIFMEDIA:
   1707   1.17.2.2  nathanw 	case SIOCGIFMEDIA:
   1708   1.17.2.2  nathanw 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command);
   1709   1.17.2.2  nathanw 		break;
   1710   1.17.2.2  nathanw 	case SIOCGWAVELAN:
   1711   1.17.2.2  nathanw 		error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
   1712   1.17.2.2  nathanw 		if (error)
   1713   1.17.2.2  nathanw 			break;
   1714   1.17.2.7  nathanw 		if (wreq.wi_type == WI_RID_IFACE_STATS) {
   1715   1.17.2.3  nathanw 			memcpy((char *)&wreq.wi_val, (char *)&sc->wi_stats,
   1716   1.17.2.7  nathanw 			    sizeof(sc->wi_stats));
   1717   1.17.2.2  nathanw 			wreq.wi_len = (sizeof(sc->wi_stats) / 2) + 1;
   1718  1.17.2.10  nathanw 		} else if (wreq.wi_type == WI_RID_READ_APS) {
   1719  1.17.2.10  nathanw 			if (sc->wi_scanning) {
   1720  1.17.2.11  nathanw 				error = EINPROGRESS;
   1721  1.17.2.10  nathanw 				break;
   1722  1.17.2.10  nathanw 			} else {
   1723  1.17.2.10  nathanw 				len = sc->wi_naps * sizeof(struct wi_apinfo);
   1724  1.17.2.10  nathanw 				len = len > WI_MAX_DATALEN ? WI_MAX_DATALEN : len;
   1725  1.17.2.10  nathanw 				len = len / sizeof(struct wi_apinfo);
   1726  1.17.2.10  nathanw 				memcpy((char *)&wreq.wi_val, (char *)&len, sizeof(len));
   1727  1.17.2.10  nathanw 				memcpy((char *)&wreq.wi_val + sizeof(len),
   1728  1.17.2.10  nathanw 					(char *)&sc->wi_aps,
   1729  1.17.2.10  nathanw 					len * sizeof(struct wi_apinfo));
   1730  1.17.2.10  nathanw 			}
   1731   1.17.2.7  nathanw 		} else if (wreq.wi_type == WI_RID_DEFLT_CRYPT_KEYS) {
   1732   1.17.2.2  nathanw 			/* For non-root user, return all-zeroes keys */
   1733   1.17.2.2  nathanw 			if (suser(p->p_ucred, &p->p_acflag))
   1734   1.17.2.3  nathanw 				memset((char *)&wreq, 0,
   1735   1.17.2.7  nathanw 				    sizeof(struct wi_ltv_keys));
   1736   1.17.2.2  nathanw 			else
   1737   1.17.2.3  nathanw 				memcpy((char *)&wreq, (char *)&sc->wi_keys,
   1738   1.17.2.7  nathanw 				    sizeof(struct wi_ltv_keys));
   1739   1.17.2.7  nathanw 		} else {
   1740   1.17.2.2  nathanw 			if (sc->sc_enabled == 0)
   1741   1.17.2.2  nathanw 				error = wi_getdef(sc, &wreq);
   1742  1.17.2.12  nathanw 			else if (wreq.wi_len > WI_MAX_DATALEN)
   1743  1.17.2.12  nathanw 				error = EINVAL;
   1744   1.17.2.7  nathanw 			else if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq))
   1745   1.17.2.2  nathanw 				error = EINVAL;
   1746   1.17.2.2  nathanw 		}
   1747   1.17.2.2  nathanw 		if (error == 0)
   1748   1.17.2.2  nathanw 			error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
   1749   1.17.2.2  nathanw 		break;
   1750   1.17.2.2  nathanw 	case SIOCSWAVELAN:
   1751   1.17.2.2  nathanw 		error = suser(p->p_ucred, &p->p_acflag);
   1752   1.17.2.2  nathanw 		if (error)
   1753   1.17.2.2  nathanw 			break;
   1754   1.17.2.2  nathanw 		error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
   1755   1.17.2.2  nathanw 		if (error)
   1756   1.17.2.2  nathanw 			break;
   1757   1.17.2.7  nathanw 		if (wreq.wi_type == WI_RID_IFACE_STATS) {
   1758  1.17.2.11  nathanw 			if (sc->sc_enabled)
   1759  1.17.2.11  nathanw 				wi_inquire(sc);
   1760   1.17.2.2  nathanw 			break;
   1761   1.17.2.7  nathanw 		} else if (wreq.wi_type == WI_RID_MGMT_XMIT) {
   1762   1.17.2.2  nathanw 			error = wi_mgmt_xmit(sc, (caddr_t)&wreq.wi_val,
   1763   1.17.2.7  nathanw 			    wreq.wi_len);
   1764  1.17.2.10  nathanw 		} else if (wreq.wi_type == WI_RID_SCAN_APS) {
   1765  1.17.2.10  nathanw 			if (wreq.wi_len != 4) {
   1766  1.17.2.10  nathanw 				error = EINVAL;
   1767  1.17.2.10  nathanw 				break;
   1768  1.17.2.10  nathanw 			}
   1769  1.17.2.10  nathanw 			if (!sc->wi_scanning) {
   1770  1.17.2.12  nathanw 				switch (sc->sc_firmware_type) {
   1771  1.17.2.12  nathanw 				case WI_LUCENT:
   1772  1.17.2.12  nathanw 					break;
   1773  1.17.2.12  nathanw 				case WI_INTERSIL:
   1774  1.17.2.10  nathanw 					wreq.wi_type = WI_RID_SCAN_REQ;
   1775  1.17.2.10  nathanw 					error = wi_write_record(sc,
   1776  1.17.2.10  nathanw 					    (struct wi_ltv_gen *)&wreq);
   1777  1.17.2.12  nathanw 					break;
   1778  1.17.2.12  nathanw 				case WI_SYMBOL:
   1779  1.17.2.12  nathanw 					/*
   1780  1.17.2.12  nathanw 					 * XXX only supported on 3.x ?
   1781  1.17.2.12  nathanw 					 */
   1782  1.17.2.12  nathanw 					wreq.wi_type = WI_RID_BCAST_SCAN_REQ;
   1783  1.17.2.12  nathanw 					wreq.wi_val[0] =
   1784  1.17.2.12  nathanw 					    BSCAN_BCAST | BSCAN_ONETIME;
   1785  1.17.2.12  nathanw 					wreq.wi_len = 2;
   1786  1.17.2.12  nathanw 					error = wi_write_record(sc,
   1787  1.17.2.12  nathanw 					    (struct wi_ltv_gen *)&wreq);
   1788  1.17.2.12  nathanw 					break;
   1789  1.17.2.10  nathanw 				}
   1790  1.17.2.10  nathanw 				if (!error) {
   1791  1.17.2.10  nathanw 					sc->wi_scanning = 1;
   1792  1.17.2.10  nathanw 					callout_reset(&sc->wi_scan_sh, hz * 1,
   1793  1.17.2.10  nathanw 						wi_wait_scan, sc);
   1794  1.17.2.10  nathanw 				}
   1795  1.17.2.10  nathanw 			}
   1796   1.17.2.7  nathanw 		} else {
   1797  1.17.2.16  nathanw 			/*
   1798  1.17.2.16  nathanw 			 * Filter stuff out based on what the
   1799  1.17.2.16  nathanw 			 * card can do.
   1800  1.17.2.16  nathanw 			 */
   1801  1.17.2.16  nathanw 			if ((wreq.wi_type == WI_RID_ROAMING_MODE &&
   1802  1.17.2.16  nathanw 			     (sc->wi_flags & WI_FLAGS_HAS_ROAMING) == 0) ||
   1803  1.17.2.16  nathanw 			    (wreq.wi_type == WI_RID_CREATE_IBSS &&
   1804  1.17.2.16  nathanw 			     (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS) == 0) ||
   1805  1.17.2.16  nathanw 			    (wreq.wi_type == WI_RID_MICROWAVE_OVEN &&
   1806  1.17.2.16  nathanw 			     (sc->wi_flags & WI_FLAGS_HAS_MOR) == 0))
   1807  1.17.2.16  nathanw 				break;
   1808  1.17.2.16  nathanw 
   1809  1.17.2.12  nathanw 			if (wreq.wi_len > WI_MAX_DATALEN)
   1810  1.17.2.12  nathanw 				error = EINVAL;
   1811  1.17.2.12  nathanw 			else if (sc->sc_enabled != 0)
   1812   1.17.2.2  nathanw 				error = wi_write_record(sc,
   1813   1.17.2.2  nathanw 				    (struct wi_ltv_gen *)&wreq);
   1814   1.17.2.2  nathanw 			if (error == 0)
   1815   1.17.2.2  nathanw 				error = wi_setdef(sc, &wreq);
   1816   1.17.2.2  nathanw 			if (error == 0 && sc->sc_enabled != 0)
   1817   1.17.2.2  nathanw 				/* Reinitialize WaveLAN. */
   1818   1.17.2.2  nathanw 				wi_init(ifp);
   1819   1.17.2.2  nathanw 		}
   1820   1.17.2.2  nathanw 		break;
   1821   1.17.2.2  nathanw 	case SIOCG80211NWID:
   1822   1.17.2.2  nathanw 		if (sc->sc_enabled == 0) {
   1823   1.17.2.2  nathanw 			/* Return the desired ID */
   1824   1.17.2.2  nathanw 			error = copyout(&sc->wi_netid, ifr->ifr_data,
   1825   1.17.2.2  nathanw 			    sizeof(sc->wi_netid));
   1826   1.17.2.2  nathanw 		} else {
   1827   1.17.2.2  nathanw 			wreq.wi_type = WI_RID_CURRENT_SSID;
   1828   1.17.2.2  nathanw 			wreq.wi_len = WI_MAX_DATALEN;
   1829   1.17.2.2  nathanw 			if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) ||
   1830   1.17.2.2  nathanw 			    le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN)
   1831   1.17.2.2  nathanw 				error = EINVAL;
   1832   1.17.2.2  nathanw 			else {
   1833   1.17.2.2  nathanw 				wi_set_ssid(&nwid, (u_int8_t *)&wreq.wi_val[1],
   1834   1.17.2.2  nathanw 				    le16toh(wreq.wi_val[0]));
   1835   1.17.2.2  nathanw 				error = copyout(&nwid, ifr->ifr_data,
   1836   1.17.2.2  nathanw 				    sizeof(nwid));
   1837   1.17.2.2  nathanw 			}
   1838   1.17.2.2  nathanw 		}
   1839   1.17.2.2  nathanw 		break;
   1840   1.17.2.2  nathanw 	case SIOCS80211NWID:
   1841   1.17.2.2  nathanw 		error = copyin(ifr->ifr_data, &nwid, sizeof(nwid));
   1842   1.17.2.2  nathanw 		if (error != 0)
   1843   1.17.2.2  nathanw 			break;
   1844   1.17.2.2  nathanw 		if (nwid.i_len > IEEE80211_NWID_LEN) {
   1845   1.17.2.2  nathanw 			error = EINVAL;
   1846   1.17.2.2  nathanw 			break;
   1847   1.17.2.2  nathanw 		}
   1848   1.17.2.2  nathanw 		if (sc->wi_netid.i_len == nwid.i_len &&
   1849   1.17.2.2  nathanw 		    memcmp(sc->wi_netid.i_nwid, nwid.i_nwid, nwid.i_len) == 0)
   1850   1.17.2.2  nathanw 			break;
   1851   1.17.2.2  nathanw 		wi_set_ssid(&sc->wi_netid, nwid.i_nwid, nwid.i_len);
   1852   1.17.2.2  nathanw 		if (sc->sc_enabled != 0)
   1853   1.17.2.2  nathanw 			/* Reinitialize WaveLAN. */
   1854   1.17.2.2  nathanw 			wi_init(ifp);
   1855   1.17.2.2  nathanw 		break;
   1856   1.17.2.2  nathanw 	case SIOCS80211NWKEY:
   1857   1.17.2.2  nathanw 		error = wi_set_nwkey(sc, (struct ieee80211_nwkey *)data);
   1858   1.17.2.2  nathanw 		break;
   1859   1.17.2.2  nathanw 	case SIOCG80211NWKEY:
   1860   1.17.2.2  nathanw 		error = wi_get_nwkey(sc, (struct ieee80211_nwkey *)data);
   1861   1.17.2.2  nathanw 		break;
   1862   1.17.2.2  nathanw 	case SIOCS80211POWER:
   1863   1.17.2.2  nathanw 		error = wi_set_pm(sc, (struct ieee80211_power *)data);
   1864   1.17.2.2  nathanw 		break;
   1865   1.17.2.2  nathanw 	case SIOCG80211POWER:
   1866   1.17.2.2  nathanw 		error = wi_get_pm(sc, (struct ieee80211_power *)data);
   1867   1.17.2.2  nathanw 		break;
   1868  1.17.2.16  nathanw 	case SIOCHOSTAP_ADD:
   1869  1.17.2.16  nathanw 	case SIOCHOSTAP_DEL:
   1870  1.17.2.16  nathanw 	case SIOCHOSTAP_GET:
   1871  1.17.2.16  nathanw 	case SIOCHOSTAP_GETALL:
   1872  1.17.2.16  nathanw 	case SIOCHOSTAP_GFLAGS:
   1873  1.17.2.16  nathanw 	case SIOCHOSTAP_SFLAGS:
   1874  1.17.2.16  nathanw 		/* Send all Host-AP specific ioctls to the Host-AP code. */
   1875  1.17.2.16  nathanw 		error = wihap_ioctl(sc, command, data);
   1876  1.17.2.16  nathanw 		break;
   1877   1.17.2.2  nathanw 
   1878   1.17.2.2  nathanw 	default:
   1879   1.17.2.2  nathanw 		error = EINVAL;
   1880   1.17.2.2  nathanw 		break;
   1881   1.17.2.2  nathanw 	}
   1882   1.17.2.2  nathanw 
   1883   1.17.2.2  nathanw 	splx(s);
   1884   1.17.2.2  nathanw 	return (error);
   1885   1.17.2.2  nathanw }
   1886   1.17.2.2  nathanw 
   1887   1.17.2.2  nathanw static int
   1888   1.17.2.2  nathanw wi_init(ifp)
   1889   1.17.2.2  nathanw 	struct ifnet *ifp;
   1890   1.17.2.2  nathanw {
   1891   1.17.2.2  nathanw 	struct wi_softc *sc = ifp->if_softc;
   1892   1.17.2.2  nathanw 	struct wi_req wreq;
   1893   1.17.2.2  nathanw 	struct wi_ltv_macaddr mac;
   1894  1.17.2.11  nathanw 	int error, id = 0, wasenabled;
   1895   1.17.2.2  nathanw 
   1896  1.17.2.11  nathanw 	wasenabled = sc->sc_enabled;
   1897   1.17.2.2  nathanw 	if (!sc->sc_enabled) {
   1898   1.17.2.2  nathanw 		if ((error = (*sc->sc_enable)(sc)) != 0)
   1899   1.17.2.2  nathanw 			goto out;
   1900   1.17.2.2  nathanw 		sc->sc_enabled = 1;
   1901   1.17.2.2  nathanw 	}
   1902   1.17.2.2  nathanw 
   1903   1.17.2.2  nathanw 	wi_stop(ifp, 0);
   1904  1.17.2.11  nathanw 	/* Symbol firmware cannot be initialized more than once */
   1905  1.17.2.11  nathanw 	if (!(sc->sc_firmware_type == WI_SYMBOL && wasenabled))
   1906  1.17.2.11  nathanw 		wi_reset(sc);
   1907   1.17.2.2  nathanw 
   1908   1.17.2.2  nathanw 	/* Program max data length. */
   1909   1.17.2.2  nathanw 	WI_SETVAL(WI_RID_MAX_DATALEN, sc->wi_max_data_len);
   1910   1.17.2.2  nathanw 
   1911   1.17.2.2  nathanw 	/* Enable/disable IBSS creation. */
   1912  1.17.2.16  nathanw 	WI_SETVAL(WI_RID_CREATE_IBSS, sc->wi_create_ibss);
   1913   1.17.2.2  nathanw 
   1914   1.17.2.2  nathanw 	/* Set the port type. */
   1915   1.17.2.2  nathanw 	WI_SETVAL(WI_RID_PORTTYPE, sc->wi_ptype);
   1916   1.17.2.2  nathanw 
   1917   1.17.2.2  nathanw 	/* Program the RTS/CTS threshold. */
   1918   1.17.2.2  nathanw 	WI_SETVAL(WI_RID_RTS_THRESH, sc->wi_rts_thresh);
   1919   1.17.2.2  nathanw 
   1920   1.17.2.2  nathanw 	/* Program the TX rate */
   1921   1.17.2.2  nathanw 	WI_SETVAL(WI_RID_TX_RATE, sc->wi_tx_rate);
   1922   1.17.2.2  nathanw 
   1923   1.17.2.2  nathanw 	/* Access point density */
   1924   1.17.2.2  nathanw 	WI_SETVAL(WI_RID_SYSTEM_SCALE, sc->wi_ap_density);
   1925   1.17.2.2  nathanw 
   1926   1.17.2.2  nathanw 	/* Power Management Enabled */
   1927   1.17.2.2  nathanw 	WI_SETVAL(WI_RID_PM_ENABLED, sc->wi_pm_enabled);
   1928   1.17.2.2  nathanw 
   1929   1.17.2.2  nathanw 	/* Power Managment Max Sleep */
   1930   1.17.2.2  nathanw 	WI_SETVAL(WI_RID_MAX_SLEEP, sc->wi_max_sleep);
   1931   1.17.2.2  nathanw 
   1932   1.17.2.2  nathanw 	/* Roaming type */
   1933  1.17.2.16  nathanw 	if (sc->wi_flags & WI_FLAGS_HAS_ROAMING)
   1934  1.17.2.16  nathanw 		WI_SETVAL(WI_RID_ROAMING_MODE, sc->wi_roaming);
   1935   1.17.2.2  nathanw 
   1936   1.17.2.2  nathanw 	/* Specify the network name */
   1937   1.17.2.2  nathanw 	wi_write_ssid(sc, WI_RID_DESIRED_SSID, &wreq, &sc->wi_netid);
   1938   1.17.2.2  nathanw 
   1939  1.17.2.16  nathanw 	/* Specify the IBSS name */
   1940  1.17.2.16  nathanw 	if (sc->wi_netid.i_len != 0 &&
   1941  1.17.2.16  nathanw 	    (sc->wi_ptype == WI_PORTTYPE_HOSTAP ||
   1942  1.17.2.16  nathanw 	     (sc->wi_create_ibss && sc->wi_ptype == WI_PORTTYPE_IBSS)))
   1943  1.17.2.16  nathanw 		wi_write_ssid(sc, WI_RID_OWN_SSID, &wreq, &sc->wi_netid);
   1944  1.17.2.16  nathanw 	else
   1945  1.17.2.16  nathanw 		wi_write_ssid(sc, WI_RID_OWN_SSID, &wreq, &sc->wi_ibssid);
   1946  1.17.2.16  nathanw 
   1947   1.17.2.2  nathanw 	/* Specify the frequency to use */
   1948   1.17.2.2  nathanw 	WI_SETVAL(WI_RID_OWN_CHNL, sc->wi_channel);
   1949   1.17.2.2  nathanw 
   1950   1.17.2.2  nathanw 	/* Program the nodename. */
   1951   1.17.2.2  nathanw 	wi_write_ssid(sc, WI_RID_NODENAME, &wreq, &sc->wi_nodeid);
   1952   1.17.2.2  nathanw 
   1953   1.17.2.2  nathanw 	/* Set our MAC address. */
   1954   1.17.2.2  nathanw 	mac.wi_len = 4;
   1955   1.17.2.2  nathanw 	mac.wi_type = WI_RID_MAC_NODE;
   1956   1.17.2.2  nathanw 	memcpy(&mac.wi_mac_addr, sc->sc_macaddr, ETHER_ADDR_LEN);
   1957   1.17.2.2  nathanw 	wi_write_record(sc, (struct wi_ltv_gen *)&mac);
   1958   1.17.2.2  nathanw 
   1959  1.17.2.16  nathanw 	/*
   1960  1.17.2.16  nathanw 	 * Initialize promisc mode.
   1961  1.17.2.16  nathanw 	 *	Being in the Host-AP mode causes a great
   1962  1.17.2.16  nathanw 	 *	deal of pain if primisc mode is set.
   1963  1.17.2.16  nathanw 	 *	Therefore we avoid confusing the firmware
   1964  1.17.2.16  nathanw 	 *	and always reset promisc mode in Host-AP
   1965  1.17.2.16  nathanw 	 *	mode.  Host-AP sees all the packets anyway.
   1966  1.17.2.16  nathanw 	 */
   1967  1.17.2.16  nathanw 	if (sc->wi_ptype != WI_PORTTYPE_HOSTAP &&
   1968  1.17.2.16  nathanw 	    (ifp->if_flags & IFF_PROMISC) != 0) {
   1969   1.17.2.2  nathanw 		WI_SETVAL(WI_RID_PROMISC, 1);
   1970   1.17.2.2  nathanw 	} else {
   1971   1.17.2.2  nathanw 		WI_SETVAL(WI_RID_PROMISC, 0);
   1972   1.17.2.2  nathanw 	}
   1973   1.17.2.2  nathanw 
   1974   1.17.2.2  nathanw 	/* Configure WEP. */
   1975  1.17.2.16  nathanw 	if (sc->wi_flags & WI_FLAGS_HAS_WEP) {
   1976   1.17.2.2  nathanw 		WI_SETVAL(WI_RID_ENCRYPTION, sc->wi_use_wep);
   1977   1.17.2.2  nathanw 		WI_SETVAL(WI_RID_TX_CRYPT_KEY, sc->wi_tx_key);
   1978   1.17.2.2  nathanw 		sc->wi_keys.wi_len = (sizeof(struct wi_ltv_keys) / 2) + 1;
   1979   1.17.2.2  nathanw 		sc->wi_keys.wi_type = WI_RID_DEFLT_CRYPT_KEYS;
   1980   1.17.2.2  nathanw 		wi_write_record(sc, (struct wi_ltv_gen *)&sc->wi_keys);
   1981  1.17.2.11  nathanw 		if (sc->sc_firmware_type != WI_LUCENT && sc->wi_use_wep) {
   1982   1.17.2.2  nathanw 			/*
   1983   1.17.2.2  nathanw 			 * ONLY HWB3163 EVAL-CARD Firmware version
   1984  1.17.2.11  nathanw 			 * less than 0.8 variant2
   1985   1.17.2.2  nathanw 			 *
   1986   1.17.2.2  nathanw 			 *   If promiscuous mode disable, Prism2 chip
   1987   1.17.2.2  nathanw 			 *  does not work with WEP .
   1988   1.17.2.2  nathanw 			 * It is under investigation for details.
   1989   1.17.2.2  nathanw 			 * (ichiro (at) netbsd.org)
   1990   1.17.2.2  nathanw 			 */
   1991  1.17.2.11  nathanw 			if (sc->sc_firmware_type == WI_INTERSIL &&
   1992  1.17.2.12  nathanw 			    sc->sc_sta_firmware_ver < 802 ) {
   1993  1.17.2.11  nathanw 				/* firm ver < 0.8 variant 2 */
   1994   1.17.2.2  nathanw 				WI_SETVAL(WI_RID_PROMISC, 1);
   1995   1.17.2.2  nathanw 			}
   1996  1.17.2.16  nathanw 			WI_SETVAL(WI_RID_CNFAUTHMODE, sc->wi_authtype);
   1997   1.17.2.2  nathanw 		}
   1998   1.17.2.2  nathanw 	}
   1999   1.17.2.2  nathanw 
   2000   1.17.2.2  nathanw 	/* Set multicast filter. */
   2001   1.17.2.2  nathanw 	wi_setmulti(sc);
   2002   1.17.2.2  nathanw 
   2003   1.17.2.2  nathanw 	/* Enable desired port */
   2004  1.17.2.16  nathanw 	wi_cmd(sc, WI_CMD_ENABLE | sc->wi_portnum, 0, 0, 0);
   2005   1.17.2.2  nathanw 
   2006  1.17.2.10  nathanw 	/*  scanning variable is modal, therefore reinit to OFF, in case it was on. */
   2007  1.17.2.10  nathanw 	sc->wi_scanning=0;
   2008  1.17.2.10  nathanw 	sc->wi_naps=0;
   2009  1.17.2.10  nathanw 
   2010   1.17.2.2  nathanw 	if ((error = wi_alloc_nicmem(sc,
   2011   1.17.2.2  nathanw 	    1518 + sizeof(struct wi_frame) + 8, &id)) != 0) {
   2012   1.17.2.2  nathanw 		printf("%s: tx buffer allocation failed\n",
   2013   1.17.2.2  nathanw 		    sc->sc_dev.dv_xname);
   2014   1.17.2.2  nathanw 		goto out;
   2015   1.17.2.2  nathanw 	}
   2016   1.17.2.2  nathanw 	sc->wi_tx_data_id = id;
   2017   1.17.2.2  nathanw 
   2018   1.17.2.2  nathanw 	if ((error = wi_alloc_nicmem(sc,
   2019   1.17.2.2  nathanw 	    1518 + sizeof(struct wi_frame) + 8, &id)) != 0) {
   2020   1.17.2.2  nathanw 		printf("%s: mgmt. buffer allocation failed\n",
   2021   1.17.2.2  nathanw 		    sc->sc_dev.dv_xname);
   2022   1.17.2.2  nathanw 		goto out;
   2023   1.17.2.2  nathanw 	}
   2024   1.17.2.2  nathanw 	sc->wi_tx_mgmt_id = id;
   2025   1.17.2.2  nathanw 
   2026   1.17.2.2  nathanw 	/* Enable interrupts */
   2027   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
   2028   1.17.2.2  nathanw 
   2029  1.17.2.16  nathanw 	wihap_init(sc);
   2030  1.17.2.16  nathanw 
   2031   1.17.2.2  nathanw 	ifp->if_flags |= IFF_RUNNING;
   2032   1.17.2.2  nathanw 	ifp->if_flags &= ~IFF_OACTIVE;
   2033   1.17.2.2  nathanw 
   2034   1.17.2.7  nathanw 	callout_reset(&sc->wi_inquire_ch, hz * 60, wi_inquire, sc);
   2035   1.17.2.2  nathanw 
   2036   1.17.2.2  nathanw  out:
   2037   1.17.2.2  nathanw 	if (error) {
   2038   1.17.2.2  nathanw 		ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
   2039   1.17.2.2  nathanw 		ifp->if_timer = 0;
   2040   1.17.2.2  nathanw 		printf("%s: interface not running\n", sc->sc_dev.dv_xname);
   2041   1.17.2.2  nathanw 	}
   2042   1.17.2.2  nathanw 	return (error);
   2043   1.17.2.2  nathanw }
   2044   1.17.2.2  nathanw 
   2045  1.17.2.16  nathanw static const u_int32_t crc32_tab[] = {
   2046  1.17.2.16  nathanw 	0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
   2047  1.17.2.16  nathanw 	0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
   2048  1.17.2.16  nathanw 	0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
   2049  1.17.2.16  nathanw 	0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
   2050  1.17.2.16  nathanw 	0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
   2051  1.17.2.16  nathanw 	0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
   2052  1.17.2.16  nathanw 	0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
   2053  1.17.2.16  nathanw 	0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
   2054  1.17.2.16  nathanw 	0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
   2055  1.17.2.16  nathanw 	0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
   2056  1.17.2.16  nathanw 	0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
   2057  1.17.2.16  nathanw 	0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
   2058  1.17.2.16  nathanw 	0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
   2059  1.17.2.16  nathanw 	0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
   2060  1.17.2.16  nathanw 	0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
   2061  1.17.2.16  nathanw 	0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
   2062  1.17.2.16  nathanw 	0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
   2063  1.17.2.16  nathanw 	0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
   2064  1.17.2.16  nathanw 	0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
   2065  1.17.2.16  nathanw 	0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
   2066  1.17.2.16  nathanw 	0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
   2067  1.17.2.16  nathanw 	0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
   2068  1.17.2.16  nathanw 	0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
   2069  1.17.2.16  nathanw 	0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
   2070  1.17.2.16  nathanw 	0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
   2071  1.17.2.16  nathanw 	0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
   2072  1.17.2.16  nathanw 	0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
   2073  1.17.2.16  nathanw 	0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
   2074  1.17.2.16  nathanw 	0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
   2075  1.17.2.16  nathanw 	0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
   2076  1.17.2.16  nathanw 	0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
   2077  1.17.2.16  nathanw 	0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
   2078  1.17.2.16  nathanw 	0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
   2079  1.17.2.16  nathanw 	0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
   2080  1.17.2.16  nathanw 	0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
   2081  1.17.2.16  nathanw 	0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
   2082  1.17.2.16  nathanw 	0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
   2083  1.17.2.16  nathanw 	0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
   2084  1.17.2.16  nathanw 	0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
   2085  1.17.2.16  nathanw 	0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
   2086  1.17.2.16  nathanw 	0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
   2087  1.17.2.16  nathanw 	0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
   2088  1.17.2.16  nathanw 	0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
   2089  1.17.2.16  nathanw 	0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
   2090  1.17.2.16  nathanw 	0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
   2091  1.17.2.16  nathanw 	0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
   2092  1.17.2.16  nathanw 	0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
   2093  1.17.2.16  nathanw 	0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
   2094  1.17.2.16  nathanw 	0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
   2095  1.17.2.16  nathanw 	0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
   2096  1.17.2.16  nathanw 	0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
   2097  1.17.2.16  nathanw 	0x2d02ef8dL
   2098  1.17.2.16  nathanw };
   2099  1.17.2.16  nathanw 
   2100  1.17.2.16  nathanw #define RC4STATE 256
   2101  1.17.2.16  nathanw #define RC4KEYLEN 16
   2102  1.17.2.16  nathanw #define RC4SWAP(x,y) \
   2103  1.17.2.16  nathanw     do { u_int8_t t = state[x]; state[x] = state[y]; state[y] = t; } while(0)
   2104  1.17.2.16  nathanw 
   2105  1.17.2.16  nathanw static void
   2106  1.17.2.16  nathanw wi_do_hostencrypt(struct wi_softc *sc, caddr_t buf, int len)
   2107  1.17.2.16  nathanw {
   2108  1.17.2.16  nathanw 	u_int32_t i, crc, klen;
   2109  1.17.2.16  nathanw 	u_int8_t state[RC4STATE], key[RC4KEYLEN];
   2110  1.17.2.16  nathanw 	u_int8_t x, y, *dat;
   2111  1.17.2.16  nathanw 
   2112  1.17.2.16  nathanw 	if (!sc->wi_icv_flag) {
   2113  1.17.2.16  nathanw 		sc->wi_icv = arc4random();
   2114  1.17.2.16  nathanw 		sc->wi_icv_flag++;
   2115  1.17.2.16  nathanw 	} else
   2116  1.17.2.16  nathanw 		sc->wi_icv++;
   2117  1.17.2.16  nathanw 	/*
   2118  1.17.2.16  nathanw 	 * Skip 'bad' IVs from Fluhrer/Mantin/Shamir:
   2119  1.17.2.16  nathanw 	 * (B, 255, N) with 3 <= B < 8
   2120  1.17.2.16  nathanw 	 */
   2121  1.17.2.16  nathanw 	if (sc->wi_icv >= 0x03ff00 &&
   2122  1.17.2.16  nathanw             (sc->wi_icv & 0xf8ff00) == 0x00ff00)
   2123  1.17.2.16  nathanw                 sc->wi_icv += 0x000100;
   2124  1.17.2.16  nathanw 
   2125  1.17.2.16  nathanw 	/* prepend 24bit IV to tx key, byte order does not matter */
   2126  1.17.2.16  nathanw 	key[0] = sc->wi_icv >> 16;
   2127  1.17.2.16  nathanw 	key[1] = sc->wi_icv >> 8;
   2128  1.17.2.16  nathanw 	key[2] = sc->wi_icv;
   2129  1.17.2.16  nathanw 
   2130  1.17.2.16  nathanw 	klen = le16toh(sc->wi_keys.wi_keys[sc->wi_tx_key].wi_keylen) +
   2131  1.17.2.16  nathanw 	    IEEE80211_WEP_IVLEN;
   2132  1.17.2.16  nathanw 	klen = (klen >= RC4KEYLEN) ? RC4KEYLEN : RC4KEYLEN/2;
   2133  1.17.2.16  nathanw 	bcopy((char *)&sc->wi_keys.wi_keys[sc->wi_tx_key].wi_keydat,
   2134  1.17.2.16  nathanw 	    (char *)key + IEEE80211_WEP_IVLEN, klen - IEEE80211_WEP_IVLEN);
   2135  1.17.2.16  nathanw 
   2136  1.17.2.16  nathanw 	/* rc4 keysetup */
   2137  1.17.2.16  nathanw 	x = y = 0;
   2138  1.17.2.16  nathanw 	for (i = 0; i < RC4STATE; i++)
   2139  1.17.2.16  nathanw 		state[i] = i;
   2140  1.17.2.16  nathanw 	for (i = 0; i < RC4STATE; i++) {
   2141  1.17.2.16  nathanw 		y = (key[x] + state[i] + y) % RC4STATE;
   2142  1.17.2.16  nathanw 		RC4SWAP(i, y);
   2143  1.17.2.16  nathanw 		x = (x + 1) % klen;
   2144  1.17.2.16  nathanw 	}
   2145  1.17.2.16  nathanw 
   2146  1.17.2.16  nathanw 	/* output: IV, tx keyid, rc4(data), rc4(crc32(data)) */
   2147  1.17.2.16  nathanw 	dat = buf;
   2148  1.17.2.16  nathanw 	dat[0] = key[0];
   2149  1.17.2.16  nathanw 	dat[1] = key[1];
   2150  1.17.2.16  nathanw 	dat[2] = key[2];
   2151  1.17.2.16  nathanw 	dat[3] = sc->wi_tx_key << 6;		/* pad and keyid */
   2152  1.17.2.16  nathanw 	dat += 4;
   2153  1.17.2.16  nathanw 
   2154  1.17.2.16  nathanw 	/* compute rc4 over data, crc32 over data */
   2155  1.17.2.16  nathanw 	crc = ~0;
   2156  1.17.2.16  nathanw 	x = y = 0;
   2157  1.17.2.16  nathanw 	for (i = 0; i < len; i++) {
   2158  1.17.2.16  nathanw 		x = (x + 1) % RC4STATE;
   2159  1.17.2.16  nathanw 		y = (state[x] + y) % RC4STATE;
   2160  1.17.2.16  nathanw 		RC4SWAP(x, y);
   2161  1.17.2.16  nathanw 		crc = crc32_tab[(crc ^ dat[i]) & 0xff] ^ (crc >> 8);
   2162  1.17.2.16  nathanw 		dat[i] ^= state[(state[x] + state[y]) % RC4STATE];
   2163  1.17.2.16  nathanw 	}
   2164  1.17.2.16  nathanw 	crc = ~crc;
   2165  1.17.2.16  nathanw 	dat += len;
   2166  1.17.2.16  nathanw 
   2167  1.17.2.16  nathanw 	/* append little-endian crc32 and encrypt */
   2168  1.17.2.16  nathanw 	dat[0] = crc;
   2169  1.17.2.16  nathanw 	dat[1] = crc >> 8;
   2170  1.17.2.16  nathanw 	dat[2] = crc >> 16;
   2171  1.17.2.16  nathanw 	dat[3] = crc >> 24;
   2172  1.17.2.16  nathanw 	for (i = 0; i < IEEE80211_WEP_CRCLEN; i++) {
   2173  1.17.2.16  nathanw 		x = (x + 1) % RC4STATE;
   2174  1.17.2.16  nathanw 		y = (state[x] + y) % RC4STATE;
   2175  1.17.2.16  nathanw 		RC4SWAP(x, y);
   2176  1.17.2.16  nathanw 		dat[i] ^= state[(state[x] + state[y]) % RC4STATE];
   2177  1.17.2.16  nathanw 	}
   2178  1.17.2.16  nathanw }
   2179  1.17.2.16  nathanw 
   2180   1.17.2.2  nathanw static void
   2181   1.17.2.2  nathanw wi_start(ifp)
   2182   1.17.2.2  nathanw 	struct ifnet		*ifp;
   2183   1.17.2.2  nathanw {
   2184   1.17.2.2  nathanw 	struct wi_softc		*sc;
   2185   1.17.2.2  nathanw 	struct mbuf		*m0;
   2186   1.17.2.2  nathanw 	struct wi_frame		tx_frame;
   2187   1.17.2.2  nathanw 	struct ether_header	*eh;
   2188   1.17.2.2  nathanw 	int			id;
   2189   1.17.2.2  nathanw 
   2190   1.17.2.2  nathanw 	sc = ifp->if_softc;
   2191   1.17.2.2  nathanw 
   2192   1.17.2.2  nathanw 	if (ifp->if_flags & IFF_OACTIVE)
   2193   1.17.2.2  nathanw 		return;
   2194   1.17.2.2  nathanw 
   2195  1.17.2.16  nathanw  nextpkt:
   2196   1.17.2.2  nathanw 	IFQ_DEQUEUE(&ifp->if_snd, m0);
   2197   1.17.2.2  nathanw 	if (m0 == NULL)
   2198   1.17.2.2  nathanw 		return;
   2199   1.17.2.2  nathanw 
   2200   1.17.2.3  nathanw 	memset((char *)&tx_frame, 0, sizeof(tx_frame));
   2201  1.17.2.16  nathanw 	tx_frame.wi_frame_ctl = htole16(WI_FTYPE_DATA);
   2202   1.17.2.2  nathanw 	id = sc->wi_tx_data_id;
   2203   1.17.2.2  nathanw 	eh = mtod(m0, struct ether_header *);
   2204   1.17.2.2  nathanw 
   2205  1.17.2.16  nathanw 	if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
   2206  1.17.2.16  nathanw 		if (wihap_check_tx(&sc->wi_hostap_info, eh->ether_dhost,
   2207  1.17.2.16  nathanw 				   &tx_frame.wi_tx_rate) == 0 &&
   2208  1.17.2.16  nathanw 		    (ifp->if_flags & IFF_PROMISC) == 0) {
   2209  1.17.2.16  nathanw 			if (ifp->if_flags & IFF_DEBUG)
   2210  1.17.2.16  nathanw 				printf("%s: Host-AP: dropping unassoc "
   2211  1.17.2.16  nathanw 				    "dst %s\n", sc->sc_dev.dv_xname,
   2212  1.17.2.16  nathanw 				    ether_sprintf(eh->ether_dhost));
   2213  1.17.2.16  nathanw 			m_freem(m0);
   2214  1.17.2.16  nathanw 			goto nextpkt;
   2215  1.17.2.16  nathanw 		}
   2216  1.17.2.16  nathanw 	}
   2217  1.17.2.16  nathanw 
   2218   1.17.2.2  nathanw 	/*
   2219   1.17.2.2  nathanw 	 * Use RFC1042 encoding for IP and ARP datagrams,
   2220   1.17.2.2  nathanw 	 * 802.3 for anything else.
   2221   1.17.2.2  nathanw 	 */
   2222  1.17.2.13  nathanw 	if (eh->ether_type == htons(ETHERTYPE_IP) ||
   2223  1.17.2.13  nathanw 	    eh->ether_type == htons(ETHERTYPE_ARP) ||
   2224  1.17.2.13  nathanw 	    eh->ether_type == htons(ETHERTYPE_REVARP) ||
   2225  1.17.2.13  nathanw 	    eh->ether_type == htons(ETHERTYPE_IPV6)) {
   2226   1.17.2.3  nathanw 		memcpy((char *)&tx_frame.wi_addr1, (char *)&eh->ether_dhost,
   2227   1.17.2.3  nathanw 		    ETHER_ADDR_LEN);
   2228  1.17.2.16  nathanw 		if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
   2229  1.17.2.16  nathanw 			tx_frame.wi_tx_ctl |= htole16(WI_ENC_TX_MGMT);/* XXX */
   2230  1.17.2.16  nathanw 			tx_frame.wi_frame_ctl |= htole16(WI_FCTL_FROMDS);
   2231  1.17.2.16  nathanw 			if (sc->wi_use_wep)
   2232  1.17.2.16  nathanw 				tx_frame.wi_frame_ctl |= htole16(WI_FCTL_WEP);
   2233  1.17.2.16  nathanw 			memcpy((char *)&tx_frame.wi_addr2,
   2234  1.17.2.16  nathanw 			    (char *)LLADDR(ifp->if_sadl), ETHER_ADDR_LEN);
   2235  1.17.2.16  nathanw 			memcpy((char *)&tx_frame.wi_addr3,
   2236  1.17.2.16  nathanw 			    (char *)&eh->ether_shost, ETHER_ADDR_LEN);
   2237  1.17.2.16  nathanw 		} else
   2238  1.17.2.16  nathanw 			memcpy((char *)&tx_frame.wi_addr2,
   2239  1.17.2.16  nathanw 			    (char *)&eh->ether_shost, ETHER_ADDR_LEN);
   2240   1.17.2.3  nathanw 		memcpy((char *)&tx_frame.wi_dst_addr, (char *)&eh->ether_dhost,
   2241   1.17.2.3  nathanw 		    ETHER_ADDR_LEN);
   2242   1.17.2.3  nathanw 		memcpy((char *)&tx_frame.wi_src_addr, (char *)&eh->ether_shost,
   2243   1.17.2.3  nathanw 		    ETHER_ADDR_LEN);
   2244   1.17.2.2  nathanw 
   2245  1.17.2.16  nathanw 		tx_frame.wi_dat_len = m0->m_pkthdr.len - WI_SNAPHDR_LEN;
   2246   1.17.2.2  nathanw 		tx_frame.wi_dat[0] = htons(WI_SNAP_WORD0);
   2247   1.17.2.2  nathanw 		tx_frame.wi_dat[1] = htons(WI_SNAP_WORD1);
   2248   1.17.2.2  nathanw 		tx_frame.wi_len = htons(m0->m_pkthdr.len - WI_SNAPHDR_LEN);
   2249   1.17.2.2  nathanw 		tx_frame.wi_type = eh->ether_type;
   2250   1.17.2.2  nathanw 
   2251  1.17.2.16  nathanw 		if (sc->wi_ptype == WI_PORTTYPE_HOSTAP && sc->wi_use_wep) {
   2252  1.17.2.16  nathanw 			/* Do host encryption. */
   2253  1.17.2.16  nathanw 			memcpy(&sc->wi_txbuf[4], &tx_frame.wi_dat[0], 8);
   2254  1.17.2.16  nathanw 
   2255  1.17.2.16  nathanw 			m_copydata(m0, sizeof(struct ether_header),
   2256  1.17.2.16  nathanw 			    m0->m_pkthdr.len - sizeof(struct ether_header),
   2257  1.17.2.16  nathanw 			    (caddr_t)&sc->wi_txbuf[12]);
   2258  1.17.2.16  nathanw 
   2259  1.17.2.16  nathanw 			wi_do_hostencrypt(sc, (caddr_t)&sc->wi_txbuf,
   2260  1.17.2.16  nathanw 			    tx_frame.wi_dat_len);
   2261  1.17.2.16  nathanw 
   2262  1.17.2.16  nathanw 			tx_frame.wi_dat_len += IEEE80211_WEP_IVLEN +
   2263  1.17.2.16  nathanw 			    IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
   2264  1.17.2.16  nathanw 
   2265  1.17.2.16  nathanw 			tx_frame.wi_dat_len = htole16(tx_frame.wi_dat_len);
   2266  1.17.2.16  nathanw 
   2267  1.17.2.16  nathanw 			wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
   2268  1.17.2.16  nathanw 			    sizeof(struct wi_frame));
   2269  1.17.2.16  nathanw 			wi_write_data(sc, id, WI_802_11_OFFSET_RAW,
   2270  1.17.2.16  nathanw 			    (caddr_t)&sc->wi_txbuf,
   2271  1.17.2.16  nathanw 			    (m0->m_pkthdr.len -
   2272  1.17.2.16  nathanw 			     sizeof(struct ether_header)) + 18);
   2273  1.17.2.16  nathanw 		} else {
   2274  1.17.2.16  nathanw 			m_copydata(m0, sizeof(struct ether_header),
   2275  1.17.2.16  nathanw 			    m0->m_pkthdr.len - sizeof(struct ether_header),
   2276  1.17.2.16  nathanw 			    (caddr_t)&sc->wi_txbuf);
   2277  1.17.2.16  nathanw 
   2278  1.17.2.16  nathanw 			tx_frame.wi_dat_len = htole16(tx_frame.wi_dat_len);
   2279  1.17.2.16  nathanw 
   2280  1.17.2.16  nathanw 			wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
   2281  1.17.2.16  nathanw 			    sizeof(struct wi_frame));
   2282  1.17.2.16  nathanw 			wi_write_data(sc, id, WI_802_11_OFFSET,
   2283  1.17.2.16  nathanw 			    (caddr_t)&sc->wi_txbuf,
   2284  1.17.2.16  nathanw 			    (m0->m_pkthdr.len -
   2285  1.17.2.16  nathanw 			     sizeof(struct ether_header)) + 2);
   2286  1.17.2.16  nathanw 		}
   2287   1.17.2.2  nathanw 	} else {
   2288   1.17.2.2  nathanw 		tx_frame.wi_dat_len = htole16(m0->m_pkthdr.len);
   2289   1.17.2.2  nathanw 
   2290  1.17.2.16  nathanw 		if (sc->wi_ptype == WI_PORTTYPE_HOSTAP && sc->wi_use_wep) {
   2291  1.17.2.16  nathanw 			/* Do host encryption.  (XXX - not implemented) */
   2292  1.17.2.16  nathanw 			printf("%s: host encryption not implemented "
   2293  1.17.2.16  nathanw 			    "for 802.3\n", sc->sc_dev.dv_xname);
   2294  1.17.2.16  nathanw 		} else {
   2295  1.17.2.16  nathanw 			m_copydata(m0, 0, m0->m_pkthdr.len,
   2296  1.17.2.16  nathanw 			    (caddr_t)&sc->wi_txbuf);
   2297   1.17.2.2  nathanw 
   2298  1.17.2.16  nathanw 			wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
   2299  1.17.2.16  nathanw 			    sizeof(struct wi_frame));
   2300  1.17.2.16  nathanw 			wi_write_data(sc, id, WI_802_3_OFFSET,
   2301  1.17.2.16  nathanw 			    (caddr_t)&sc->wi_txbuf, m0->m_pkthdr.len + 2);
   2302  1.17.2.16  nathanw 		}
   2303   1.17.2.2  nathanw 	}
   2304   1.17.2.2  nathanw 
   2305   1.17.2.2  nathanw #if NBPFILTER > 0
   2306   1.17.2.2  nathanw 	/*
   2307   1.17.2.2  nathanw 	 * If there's a BPF listener, bounce a copy of
   2308   1.17.2.2  nathanw 	 * this frame to him.
   2309   1.17.2.2  nathanw 	 */
   2310   1.17.2.2  nathanw 	if (ifp->if_bpf)
   2311   1.17.2.2  nathanw 		bpf_mtap(ifp->if_bpf, m0);
   2312   1.17.2.2  nathanw #endif
   2313   1.17.2.2  nathanw 
   2314   1.17.2.2  nathanw 	m_freem(m0);
   2315   1.17.2.2  nathanw 
   2316  1.17.2.16  nathanw 	if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0))
   2317   1.17.2.2  nathanw 		printf("%s: xmit failed\n", sc->sc_dev.dv_xname);
   2318   1.17.2.2  nathanw 
   2319   1.17.2.2  nathanw 	ifp->if_flags |= IFF_OACTIVE;
   2320   1.17.2.2  nathanw 
   2321   1.17.2.2  nathanw 	/*
   2322   1.17.2.2  nathanw 	 * Set a timeout in case the chip goes out to lunch.
   2323   1.17.2.2  nathanw 	 */
   2324   1.17.2.2  nathanw 	ifp->if_timer = 5;
   2325   1.17.2.2  nathanw 
   2326   1.17.2.2  nathanw 	return;
   2327   1.17.2.2  nathanw }
   2328   1.17.2.2  nathanw 
   2329  1.17.2.16  nathanw int
   2330   1.17.2.2  nathanw wi_mgmt_xmit(sc, data, len)
   2331   1.17.2.2  nathanw 	struct wi_softc		*sc;
   2332   1.17.2.2  nathanw 	caddr_t			data;
   2333   1.17.2.2  nathanw 	int			len;
   2334   1.17.2.2  nathanw {
   2335   1.17.2.2  nathanw 	struct wi_frame		tx_frame;
   2336   1.17.2.2  nathanw 	int			id;
   2337   1.17.2.2  nathanw 	struct wi_80211_hdr	*hdr;
   2338   1.17.2.2  nathanw 	caddr_t			dptr;
   2339   1.17.2.2  nathanw 
   2340   1.17.2.2  nathanw 	hdr = (struct wi_80211_hdr *)data;
   2341   1.17.2.2  nathanw 	dptr = data + sizeof(struct wi_80211_hdr);
   2342   1.17.2.2  nathanw 
   2343   1.17.2.3  nathanw 	memset((char *)&tx_frame, 0, sizeof(tx_frame));
   2344   1.17.2.2  nathanw 	id = sc->wi_tx_mgmt_id;
   2345   1.17.2.2  nathanw 
   2346   1.17.2.3  nathanw 	memcpy((char *)&tx_frame.wi_frame_ctl, (char *)hdr,
   2347   1.17.2.2  nathanw 	   sizeof(struct wi_80211_hdr));
   2348   1.17.2.2  nathanw 
   2349  1.17.2.16  nathanw 	tx_frame.wi_tx_ctl = htole16(WI_ENC_TX_MGMT);
   2350  1.17.2.16  nathanw 	tx_frame.wi_dat_len = len - sizeof(struct wi_80211_hdr);
   2351  1.17.2.16  nathanw 	tx_frame.wi_len = htole16(tx_frame.wi_dat_len);
   2352  1.17.2.16  nathanw 
   2353  1.17.2.16  nathanw 	tx_frame.wi_dat_len = htole16(tx_frame.wi_dat_len);
   2354   1.17.2.2  nathanw 
   2355   1.17.2.2  nathanw 	wi_write_data(sc, id, 0, (caddr_t)&tx_frame, sizeof(struct wi_frame));
   2356   1.17.2.2  nathanw 	wi_write_data(sc, id, WI_802_11_OFFSET_RAW, dptr,
   2357   1.17.2.2  nathanw 	    (len - sizeof(struct wi_80211_hdr)) + 2);
   2358   1.17.2.2  nathanw 
   2359  1.17.2.16  nathanw 	if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0)) {
   2360   1.17.2.2  nathanw 		printf("%s: xmit failed\n", sc->sc_dev.dv_xname);
   2361   1.17.2.2  nathanw 		return(EIO);
   2362   1.17.2.2  nathanw 	}
   2363   1.17.2.2  nathanw 
   2364   1.17.2.2  nathanw 	return(0);
   2365   1.17.2.2  nathanw }
   2366   1.17.2.2  nathanw 
   2367   1.17.2.2  nathanw static void
   2368   1.17.2.2  nathanw wi_stop(ifp, disable)
   2369   1.17.2.2  nathanw 	struct ifnet *ifp;
   2370   1.17.2.2  nathanw {
   2371   1.17.2.2  nathanw 	struct wi_softc	*sc = ifp->if_softc;
   2372   1.17.2.2  nathanw 
   2373  1.17.2.16  nathanw 	wihap_shutdown(sc);
   2374  1.17.2.16  nathanw 
   2375   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_INT_EN, 0);
   2376  1.17.2.16  nathanw 	wi_cmd(sc, WI_CMD_DISABLE|sc->wi_portnum, 0, 0, 0);
   2377   1.17.2.2  nathanw 
   2378   1.17.2.7  nathanw 	callout_stop(&sc->wi_inquire_ch);
   2379  1.17.2.10  nathanw 	callout_stop(&sc->wi_scan_sh);
   2380   1.17.2.2  nathanw 
   2381   1.17.2.2  nathanw 	if (disable) {
   2382   1.17.2.2  nathanw 		if (sc->sc_enabled) {
   2383   1.17.2.2  nathanw 			if (sc->sc_disable)
   2384   1.17.2.2  nathanw 				(*sc->sc_disable)(sc);
   2385   1.17.2.2  nathanw 			sc->sc_enabled = 0;
   2386   1.17.2.2  nathanw 		}
   2387   1.17.2.2  nathanw 	}
   2388   1.17.2.2  nathanw 
   2389   1.17.2.2  nathanw 	ifp->if_flags &= ~(IFF_OACTIVE | IFF_RUNNING);
   2390   1.17.2.2  nathanw 	ifp->if_timer = 0;
   2391   1.17.2.2  nathanw }
   2392   1.17.2.2  nathanw 
   2393   1.17.2.2  nathanw static void
   2394   1.17.2.2  nathanw wi_watchdog(ifp)
   2395   1.17.2.2  nathanw 	struct ifnet		*ifp;
   2396   1.17.2.2  nathanw {
   2397   1.17.2.2  nathanw 	struct wi_softc		*sc;
   2398   1.17.2.2  nathanw 
   2399   1.17.2.2  nathanw 	sc = ifp->if_softc;
   2400   1.17.2.2  nathanw 
   2401   1.17.2.2  nathanw 	printf("%s: device timeout\n", sc->sc_dev.dv_xname);
   2402   1.17.2.2  nathanw 
   2403   1.17.2.2  nathanw 	wi_init(ifp);
   2404   1.17.2.2  nathanw 
   2405   1.17.2.2  nathanw 	ifp->if_oerrors++;
   2406   1.17.2.2  nathanw 
   2407   1.17.2.2  nathanw 	return;
   2408   1.17.2.2  nathanw }
   2409   1.17.2.2  nathanw 
   2410   1.17.2.2  nathanw void
   2411   1.17.2.2  nathanw wi_shutdown(sc)
   2412   1.17.2.2  nathanw 	struct wi_softc *sc;
   2413   1.17.2.2  nathanw {
   2414   1.17.2.2  nathanw 	int s;
   2415   1.17.2.2  nathanw 
   2416   1.17.2.2  nathanw 	s = splnet();
   2417   1.17.2.2  nathanw 	if (sc->sc_enabled) {
   2418   1.17.2.2  nathanw 		if (sc->sc_disable)
   2419   1.17.2.2  nathanw 			(*sc->sc_disable)(sc);
   2420   1.17.2.2  nathanw 		sc->sc_enabled = 0;
   2421   1.17.2.2  nathanw 	}
   2422   1.17.2.2  nathanw 	splx(s);
   2423   1.17.2.2  nathanw }
   2424   1.17.2.2  nathanw 
   2425   1.17.2.2  nathanw int
   2426   1.17.2.2  nathanw wi_activate(self, act)
   2427   1.17.2.2  nathanw 	struct device *self;
   2428   1.17.2.2  nathanw 	enum devact act;
   2429   1.17.2.2  nathanw {
   2430   1.17.2.2  nathanw 	struct wi_softc *sc = (struct wi_softc *)self;
   2431   1.17.2.2  nathanw 	int rv = 0, s;
   2432   1.17.2.2  nathanw 
   2433   1.17.2.2  nathanw 	s = splnet();
   2434   1.17.2.2  nathanw 	switch (act) {
   2435   1.17.2.2  nathanw 	case DVACT_ACTIVATE:
   2436   1.17.2.2  nathanw 		rv = EOPNOTSUPP;
   2437   1.17.2.2  nathanw 		break;
   2438   1.17.2.2  nathanw 
   2439   1.17.2.2  nathanw 	case DVACT_DEACTIVATE:
   2440   1.17.2.2  nathanw 		if_deactivate(&sc->sc_ethercom.ec_if);
   2441   1.17.2.2  nathanw 		break;
   2442   1.17.2.2  nathanw 	}
   2443   1.17.2.2  nathanw 	splx(s);
   2444   1.17.2.2  nathanw 	return (rv);
   2445   1.17.2.2  nathanw }
   2446   1.17.2.2  nathanw 
   2447   1.17.2.2  nathanw static void
   2448   1.17.2.2  nathanw wi_get_id(sc)
   2449   1.17.2.2  nathanw 	struct wi_softc *sc;
   2450   1.17.2.2  nathanw {
   2451   1.17.2.2  nathanw 	struct wi_ltv_ver       ver;
   2452  1.17.2.12  nathanw 	struct wi_card_ident	*id;
   2453   1.17.2.2  nathanw 
   2454   1.17.2.2  nathanw 	/* getting chip identity */
   2455   1.17.2.2  nathanw 	memset(&ver, 0, sizeof(ver));
   2456   1.17.2.8  nathanw 	ver.wi_type = WI_RID_CARD_ID;
   2457   1.17.2.2  nathanw 	ver.wi_len = 5;
   2458   1.17.2.2  nathanw 	wi_read_record(sc, (struct wi_ltv_gen *)&ver);
   2459   1.17.2.2  nathanw 	printf("%s: using ", sc->sc_dev.dv_xname);
   2460  1.17.2.12  nathanw 
   2461  1.17.2.12  nathanw 	sc->sc_firmware_type = WI_NOTYPE;
   2462  1.17.2.12  nathanw 	for (id = wi_card_ident; id->card_name != NULL; id++) {
   2463  1.17.2.12  nathanw 		if (le16toh(ver.wi_ver[0]) == id->card_id) {
   2464  1.17.2.12  nathanw 			printf("%s", id->card_name);
   2465  1.17.2.12  nathanw 			sc->sc_firmware_type = id->firm_type;
   2466  1.17.2.12  nathanw 			break;
   2467  1.17.2.12  nathanw 		}
   2468  1.17.2.12  nathanw 	}
   2469  1.17.2.12  nathanw 	if (sc->sc_firmware_type == WI_NOTYPE) {
   2470  1.17.2.11  nathanw 		if (le16toh(ver.wi_ver[0]) & 0x8000) {
   2471  1.17.2.11  nathanw 			printf("Unknown PRISM2 chip");
   2472  1.17.2.11  nathanw 			sc->sc_firmware_type = WI_INTERSIL;
   2473  1.17.2.11  nathanw 		} else {
   2474  1.17.2.11  nathanw 			printf("Unknown Lucent chip");
   2475  1.17.2.11  nathanw 			sc->sc_firmware_type = WI_LUCENT;
   2476  1.17.2.11  nathanw 		}
   2477   1.17.2.2  nathanw 	}
   2478   1.17.2.2  nathanw 
   2479  1.17.2.12  nathanw 	/* get primary firmware version (Only Prism chips) */
   2480  1.17.2.12  nathanw 	if (sc->sc_firmware_type != WI_LUCENT) {
   2481  1.17.2.12  nathanw 		memset(&ver, 0, sizeof(ver));
   2482  1.17.2.12  nathanw 		ver.wi_type = WI_RID_PRI_IDENTITY;
   2483  1.17.2.12  nathanw 		ver.wi_len = 5;
   2484  1.17.2.12  nathanw 		wi_read_record(sc, (struct wi_ltv_gen *)&ver);
   2485  1.17.2.12  nathanw 		LE16TOH(ver.wi_ver[1]);
   2486  1.17.2.12  nathanw 		LE16TOH(ver.wi_ver[2]);
   2487  1.17.2.12  nathanw 		LE16TOH(ver.wi_ver[3]);
   2488  1.17.2.12  nathanw 		sc->sc_pri_firmware_ver = ver.wi_ver[2] * 10000 +
   2489  1.17.2.12  nathanw 		    ver.wi_ver[3] * 100 + ver.wi_ver[1];
   2490  1.17.2.12  nathanw 	}
   2491  1.17.2.12  nathanw 
   2492  1.17.2.12  nathanw 	/* get station firmware version */
   2493  1.17.2.11  nathanw 	memset(&ver, 0, sizeof(ver));
   2494  1.17.2.11  nathanw 	ver.wi_type = WI_RID_STA_IDENTITY;
   2495  1.17.2.11  nathanw 	ver.wi_len = 5;
   2496  1.17.2.11  nathanw 	wi_read_record(sc, (struct wi_ltv_gen *)&ver);
   2497  1.17.2.11  nathanw 	LE16TOH(ver.wi_ver[1]);
   2498  1.17.2.11  nathanw 	LE16TOH(ver.wi_ver[2]);
   2499  1.17.2.11  nathanw 	LE16TOH(ver.wi_ver[3]);
   2500  1.17.2.12  nathanw 	sc->sc_sta_firmware_ver = ver.wi_ver[2] * 10000 +
   2501  1.17.2.11  nathanw 	    ver.wi_ver[3] * 100 + ver.wi_ver[1];
   2502  1.17.2.11  nathanw 	if (sc->sc_firmware_type == WI_INTERSIL &&
   2503  1.17.2.12  nathanw 	    (sc->sc_sta_firmware_ver == 10102 || sc->sc_sta_firmware_ver == 20102)) {
   2504  1.17.2.11  nathanw 		struct wi_ltv_str sver;
   2505  1.17.2.11  nathanw 		char *p;
   2506  1.17.2.11  nathanw 
   2507  1.17.2.11  nathanw 		memset(&sver, 0, sizeof(sver));
   2508  1.17.2.11  nathanw 		sver.wi_type = WI_RID_SYMBOL_IDENTITY;
   2509  1.17.2.11  nathanw 		sver.wi_len = 7;
   2510  1.17.2.12  nathanw 		/* value should be the format like "V2.00-11" */
   2511  1.17.2.11  nathanw 		if (wi_read_record(sc, (struct wi_ltv_gen *)&sver) == 0 &&
   2512  1.17.2.12  nathanw 		    *(p = (char *)sver.wi_str) >= 'A' &&
   2513  1.17.2.11  nathanw 		    p[2] == '.' && p[5] == '-' && p[8] == '\0') {
   2514  1.17.2.11  nathanw 			sc->sc_firmware_type = WI_SYMBOL;
   2515  1.17.2.12  nathanw 			sc->sc_sta_firmware_ver = (p[1] - '0') * 10000 +
   2516  1.17.2.11  nathanw 			    (p[3] - '0') * 1000 + (p[4] - '0') * 100 +
   2517  1.17.2.11  nathanw 			    (p[6] - '0') * 10 + (p[7] - '0');
   2518  1.17.2.11  nathanw 		}
   2519  1.17.2.11  nathanw 	}
   2520  1.17.2.12  nathanw 
   2521  1.17.2.12  nathanw 	printf("\n%s: %s Firmware: ", sc->sc_dev.dv_xname,
   2522  1.17.2.12  nathanw 	     sc->sc_firmware_type == WI_LUCENT ? "Lucent" :
   2523  1.17.2.12  nathanw 	    (sc->sc_firmware_type == WI_SYMBOL ? "Symbol" : "Intersil"));
   2524  1.17.2.12  nathanw 	if (sc->sc_firmware_type != WI_LUCENT)	/* XXX */
   2525  1.17.2.12  nathanw 	    printf("Primary (%u.%u.%u), ", sc->sc_pri_firmware_ver / 10000,
   2526  1.17.2.12  nathanw 		    (sc->sc_pri_firmware_ver % 10000) / 100,
   2527  1.17.2.12  nathanw 		    sc->sc_pri_firmware_ver % 100);
   2528  1.17.2.12  nathanw 	printf("Station (%u.%u.%u)\n",
   2529  1.17.2.12  nathanw 	    sc->sc_sta_firmware_ver / 10000, (sc->sc_sta_firmware_ver % 10000) / 100,
   2530  1.17.2.12  nathanw 	    sc->sc_sta_firmware_ver % 100);
   2531   1.17.2.2  nathanw 
   2532   1.17.2.2  nathanw 	return;
   2533   1.17.2.2  nathanw }
   2534   1.17.2.2  nathanw 
   2535   1.17.2.2  nathanw int
   2536   1.17.2.2  nathanw wi_detach(sc)
   2537   1.17.2.2  nathanw 	struct wi_softc *sc;
   2538   1.17.2.2  nathanw {
   2539   1.17.2.2  nathanw 	struct ifnet *ifp = sc->sc_ifp;
   2540   1.17.2.2  nathanw 	int s;
   2541   1.17.2.2  nathanw 
   2542   1.17.2.2  nathanw 	if (!sc->sc_attached)
   2543   1.17.2.2  nathanw 		return (0);
   2544   1.17.2.2  nathanw 
   2545   1.17.2.2  nathanw 	s = splnet();
   2546   1.17.2.7  nathanw 	callout_stop(&sc->wi_inquire_ch);
   2547   1.17.2.2  nathanw 
   2548   1.17.2.2  nathanw 	/* Delete all remaining media. */
   2549   1.17.2.2  nathanw 	ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
   2550   1.17.2.2  nathanw 
   2551   1.17.2.2  nathanw 	ether_ifdetach(ifp);
   2552   1.17.2.2  nathanw 	if_detach(ifp);
   2553   1.17.2.2  nathanw 	if (sc->sc_enabled) {
   2554   1.17.2.2  nathanw 		if (sc->sc_disable)
   2555   1.17.2.2  nathanw 			(*sc->sc_disable)(sc);
   2556   1.17.2.2  nathanw 		sc->sc_enabled = 0;
   2557   1.17.2.2  nathanw 	}
   2558   1.17.2.2  nathanw 	splx(s);
   2559   1.17.2.2  nathanw 	return (0);
   2560   1.17.2.2  nathanw }
   2561   1.17.2.2  nathanw 
   2562   1.17.2.2  nathanw void
   2563   1.17.2.2  nathanw wi_power(sc, why)
   2564   1.17.2.2  nathanw 	struct wi_softc *sc;
   2565   1.17.2.2  nathanw 	int why;
   2566   1.17.2.2  nathanw {
   2567   1.17.2.2  nathanw 	int s;
   2568   1.17.2.2  nathanw 
   2569   1.17.2.2  nathanw 	if (!sc->sc_enabled)
   2570   1.17.2.2  nathanw 		return;
   2571   1.17.2.2  nathanw 
   2572   1.17.2.2  nathanw 	s = splnet();
   2573   1.17.2.2  nathanw 	switch (why) {
   2574   1.17.2.2  nathanw 	case PWR_SUSPEND:
   2575   1.17.2.2  nathanw 	case PWR_STANDBY:
   2576   1.17.2.2  nathanw 		wi_stop(sc->sc_ifp, 0);
   2577   1.17.2.2  nathanw 		if (sc->sc_enabled) {
   2578   1.17.2.2  nathanw 			if (sc->sc_disable)
   2579   1.17.2.2  nathanw 				(*sc->sc_disable)(sc);
   2580   1.17.2.2  nathanw 		}
   2581   1.17.2.2  nathanw 		break;
   2582   1.17.2.2  nathanw 	case PWR_RESUME:
   2583   1.17.2.2  nathanw 		sc->sc_enabled = 0;
   2584   1.17.2.2  nathanw 		wi_init(sc->sc_ifp);
   2585   1.17.2.2  nathanw 		(void)wi_intr(sc);
   2586   1.17.2.2  nathanw 		break;
   2587   1.17.2.2  nathanw 	case PWR_SOFTSUSPEND:
   2588   1.17.2.2  nathanw 	case PWR_SOFTSTANDBY:
   2589   1.17.2.2  nathanw 	case PWR_SOFTRESUME:
   2590   1.17.2.2  nathanw 		break;
   2591   1.17.2.2  nathanw 	}
   2592   1.17.2.2  nathanw 	splx(s);
   2593   1.17.2.2  nathanw }
   2594   1.17.2.2  nathanw 
   2595   1.17.2.2  nathanw static int
   2596   1.17.2.2  nathanw wi_set_ssid(ws, id, len)
   2597   1.17.2.2  nathanw 	struct ieee80211_nwid *ws;
   2598   1.17.2.2  nathanw 	u_int8_t *id;
   2599   1.17.2.2  nathanw 	int len;
   2600   1.17.2.2  nathanw {
   2601   1.17.2.2  nathanw 
   2602   1.17.2.2  nathanw 	if (len > IEEE80211_NWID_LEN)
   2603   1.17.2.2  nathanw 		return (EINVAL);
   2604   1.17.2.2  nathanw 	ws->i_len = len;
   2605   1.17.2.2  nathanw 	memcpy(ws->i_nwid, id, len);
   2606   1.17.2.2  nathanw 	return (0);
   2607   1.17.2.2  nathanw }
   2608   1.17.2.2  nathanw 
   2609   1.17.2.2  nathanw static void
   2610   1.17.2.2  nathanw wi_request_fill_ssid(wreq, ws)
   2611   1.17.2.2  nathanw 	struct wi_req *wreq;
   2612   1.17.2.2  nathanw 	struct ieee80211_nwid *ws;
   2613   1.17.2.2  nathanw {
   2614   1.17.2.2  nathanw 	int len = ws->i_len;
   2615   1.17.2.2  nathanw 
   2616   1.17.2.2  nathanw 	memset(&wreq->wi_val[0], 0, sizeof(wreq->wi_val));
   2617   1.17.2.2  nathanw 	wreq->wi_val[0] = htole16(len);
   2618   1.17.2.2  nathanw 	wreq->wi_len = roundup(len, 2) / 2 + 2;
   2619   1.17.2.2  nathanw 	memcpy(&wreq->wi_val[1], ws->i_nwid, len);
   2620   1.17.2.2  nathanw }
   2621   1.17.2.2  nathanw 
   2622   1.17.2.2  nathanw static int
   2623   1.17.2.2  nathanw wi_write_ssid(sc, type, wreq, ws)
   2624   1.17.2.2  nathanw 	struct wi_softc *sc;
   2625   1.17.2.2  nathanw 	int type;
   2626   1.17.2.2  nathanw 	struct wi_req *wreq;
   2627   1.17.2.2  nathanw 	struct ieee80211_nwid *ws;
   2628   1.17.2.2  nathanw {
   2629   1.17.2.2  nathanw 
   2630   1.17.2.2  nathanw 	wreq->wi_type = type;
   2631   1.17.2.2  nathanw 	wi_request_fill_ssid(wreq, ws);
   2632   1.17.2.2  nathanw 	return (wi_write_record(sc, (struct wi_ltv_gen *)wreq));
   2633   1.17.2.2  nathanw }
   2634   1.17.2.2  nathanw 
   2635   1.17.2.2  nathanw static int
   2636   1.17.2.2  nathanw wi_sync_media(sc, ptype, txrate)
   2637   1.17.2.2  nathanw 	struct wi_softc *sc;
   2638   1.17.2.2  nathanw 	int ptype;
   2639   1.17.2.2  nathanw 	int txrate;
   2640   1.17.2.2  nathanw {
   2641   1.17.2.2  nathanw 	int media = sc->sc_media.ifm_cur->ifm_media;
   2642   1.17.2.2  nathanw 	int options = IFM_OPTIONS(media);
   2643   1.17.2.2  nathanw 	int subtype;
   2644   1.17.2.2  nathanw 
   2645   1.17.2.2  nathanw 	switch (txrate) {
   2646   1.17.2.2  nathanw 	case 1:
   2647   1.17.2.2  nathanw 		subtype = IFM_IEEE80211_DS1;
   2648   1.17.2.2  nathanw 		break;
   2649   1.17.2.2  nathanw 	case 2:
   2650   1.17.2.2  nathanw 		subtype = IFM_IEEE80211_DS2;
   2651   1.17.2.2  nathanw 		break;
   2652   1.17.2.2  nathanw 	case 3:
   2653   1.17.2.2  nathanw 		subtype = IFM_AUTO;
   2654   1.17.2.2  nathanw 		break;
   2655  1.17.2.10  nathanw 	case 5:
   2656  1.17.2.10  nathanw 		subtype = IFM_IEEE80211_DS5;
   2657  1.17.2.10  nathanw 		break;
   2658   1.17.2.2  nathanw 	case 11:
   2659   1.17.2.2  nathanw 		subtype = IFM_IEEE80211_DS11;
   2660   1.17.2.2  nathanw 		break;
   2661   1.17.2.2  nathanw 	default:
   2662   1.17.2.2  nathanw 		subtype = IFM_MANUAL;		/* Unable to represent */
   2663   1.17.2.2  nathanw 		break;
   2664   1.17.2.2  nathanw 	}
   2665  1.17.2.16  nathanw 
   2666  1.17.2.16  nathanw 	options &= ~IFM_OMASK;
   2667   1.17.2.2  nathanw 	switch (ptype) {
   2668  1.17.2.16  nathanw 	case WI_PORTTYPE_BSS:
   2669  1.17.2.16  nathanw 		/* default port type */
   2670  1.17.2.16  nathanw 		break;
   2671   1.17.2.2  nathanw 	case WI_PORTTYPE_ADHOC:
   2672   1.17.2.2  nathanw 		options |= IFM_IEEE80211_ADHOC;
   2673   1.17.2.2  nathanw 		break;
   2674  1.17.2.16  nathanw 	case WI_PORTTYPE_IBSS:
   2675  1.17.2.16  nathanw 		if (sc->wi_create_ibss)
   2676  1.17.2.16  nathanw 			options |= IFM_IEEE80211_IBSSMASTER;
   2677  1.17.2.16  nathanw 		else
   2678  1.17.2.16  nathanw 			options |= IFM_IEEE80211_IBSS;
   2679   1.17.2.2  nathanw 		break;
   2680   1.17.2.2  nathanw 	default:
   2681   1.17.2.2  nathanw 		subtype = IFM_MANUAL;		/* Unable to represent */
   2682   1.17.2.2  nathanw 		break;
   2683   1.17.2.2  nathanw 	}
   2684   1.17.2.2  nathanw 	media = IFM_MAKEWORD(IFM_TYPE(media), subtype, options,
   2685   1.17.2.2  nathanw 	    IFM_INST(media));
   2686   1.17.2.2  nathanw 	if (ifmedia_match(&sc->sc_media, media, sc->sc_media.ifm_mask) == NULL)
   2687   1.17.2.2  nathanw 		return (EINVAL);
   2688   1.17.2.2  nathanw 	ifmedia_set(&sc->sc_media, media);
   2689   1.17.2.2  nathanw 	sc->wi_ptype = ptype;
   2690   1.17.2.2  nathanw 	sc->wi_tx_rate = txrate;
   2691   1.17.2.2  nathanw 	return (0);
   2692   1.17.2.2  nathanw }
   2693   1.17.2.2  nathanw 
   2694   1.17.2.2  nathanw static int
   2695   1.17.2.2  nathanw wi_media_change(ifp)
   2696   1.17.2.2  nathanw 	struct ifnet *ifp;
   2697   1.17.2.2  nathanw {
   2698   1.17.2.2  nathanw 	struct wi_softc *sc = ifp->if_softc;
   2699   1.17.2.2  nathanw 	int otype = sc->wi_ptype;
   2700   1.17.2.2  nathanw 	int orate = sc->wi_tx_rate;
   2701  1.17.2.16  nathanw 	int ocreate_ibss = sc->wi_create_ibss;
   2702   1.17.2.2  nathanw 
   2703  1.17.2.16  nathanw 	sc->wi_create_ibss = 0;
   2704  1.17.2.16  nathanw 
   2705  1.17.2.16  nathanw 	switch (sc->sc_media.ifm_cur->ifm_media & IFM_OMASK) {
   2706  1.17.2.16  nathanw 	case 0:
   2707   1.17.2.2  nathanw 		sc->wi_ptype = WI_PORTTYPE_BSS;
   2708  1.17.2.16  nathanw 		break;
   2709  1.17.2.16  nathanw 	case IFM_IEEE80211_ADHOC:
   2710  1.17.2.16  nathanw 		sc->wi_ptype = WI_PORTTYPE_ADHOC;
   2711  1.17.2.16  nathanw 		break;
   2712  1.17.2.16  nathanw 	case IFM_IEEE80211_HOSTAP:
   2713  1.17.2.16  nathanw 		sc->wi_ptype = WI_PORTTYPE_HOSTAP;
   2714  1.17.2.16  nathanw 		break;
   2715  1.17.2.16  nathanw 	case IFM_IEEE80211_IBSSMASTER:
   2716  1.17.2.16  nathanw 	case IFM_IEEE80211_IBSSMASTER|IFM_IEEE80211_IBSS:
   2717  1.17.2.16  nathanw 		if ((sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS) == 0)
   2718  1.17.2.16  nathanw 			return (EINVAL);
   2719  1.17.2.16  nathanw 		sc->wi_create_ibss = 1;
   2720  1.17.2.16  nathanw 		/* FALLTHROUGH */
   2721  1.17.2.16  nathanw 	case IFM_IEEE80211_IBSS:
   2722  1.17.2.16  nathanw 		sc->wi_ptype = WI_PORTTYPE_IBSS;
   2723  1.17.2.16  nathanw 		break;
   2724  1.17.2.16  nathanw 	default:
   2725  1.17.2.16  nathanw 		/* Invalid combination. */
   2726  1.17.2.16  nathanw 		sc->wi_create_ibss = ocreate_ibss;
   2727  1.17.2.16  nathanw 		return (EINVAL);
   2728  1.17.2.16  nathanw 	}
   2729   1.17.2.2  nathanw 
   2730   1.17.2.2  nathanw 	switch (IFM_SUBTYPE(sc->sc_media.ifm_cur->ifm_media)) {
   2731   1.17.2.2  nathanw 	case IFM_IEEE80211_DS1:
   2732   1.17.2.2  nathanw 		sc->wi_tx_rate = 1;
   2733   1.17.2.2  nathanw 		break;
   2734   1.17.2.2  nathanw 	case IFM_IEEE80211_DS2:
   2735   1.17.2.2  nathanw 		sc->wi_tx_rate = 2;
   2736   1.17.2.2  nathanw 		break;
   2737   1.17.2.2  nathanw 	case IFM_AUTO:
   2738   1.17.2.2  nathanw 		sc->wi_tx_rate = 3;
   2739   1.17.2.2  nathanw 		break;
   2740  1.17.2.10  nathanw 	case IFM_IEEE80211_DS5:
   2741  1.17.2.10  nathanw 		sc->wi_tx_rate = 5;
   2742  1.17.2.10  nathanw 		break;
   2743   1.17.2.2  nathanw 	case IFM_IEEE80211_DS11:
   2744   1.17.2.2  nathanw 		sc->wi_tx_rate = 11;
   2745   1.17.2.2  nathanw 		break;
   2746   1.17.2.2  nathanw 	}
   2747   1.17.2.2  nathanw 
   2748   1.17.2.2  nathanw 	if (sc->sc_enabled != 0) {
   2749   1.17.2.2  nathanw 		if (otype != sc->wi_ptype ||
   2750  1.17.2.16  nathanw 		    orate != sc->wi_tx_rate ||
   2751  1.17.2.16  nathanw 		    ocreate_ibss != sc->wi_create_ibss)
   2752   1.17.2.2  nathanw 			wi_init(ifp);
   2753   1.17.2.2  nathanw 	}
   2754   1.17.2.2  nathanw 
   2755   1.17.2.2  nathanw 	ifp->if_baudrate = ifmedia_baudrate(sc->sc_media.ifm_cur->ifm_media);
   2756   1.17.2.2  nathanw 
   2757   1.17.2.2  nathanw 	return (0);
   2758   1.17.2.2  nathanw }
   2759   1.17.2.2  nathanw 
   2760   1.17.2.2  nathanw static void
   2761   1.17.2.2  nathanw wi_media_status(ifp, imr)
   2762   1.17.2.2  nathanw 	struct ifnet *ifp;
   2763   1.17.2.2  nathanw 	struct ifmediareq *imr;
   2764   1.17.2.2  nathanw {
   2765   1.17.2.2  nathanw 	struct wi_softc *sc = ifp->if_softc;
   2766   1.17.2.2  nathanw 
   2767   1.17.2.2  nathanw 	if (sc->sc_enabled == 0) {
   2768   1.17.2.2  nathanw 		imr->ifm_active = IFM_IEEE80211|IFM_NONE;
   2769   1.17.2.2  nathanw 		imr->ifm_status = 0;
   2770   1.17.2.2  nathanw 		return;
   2771   1.17.2.2  nathanw 	}
   2772   1.17.2.2  nathanw 
   2773   1.17.2.2  nathanw 	imr->ifm_active = sc->sc_media.ifm_cur->ifm_media;
   2774   1.17.2.2  nathanw 	imr->ifm_status = IFM_AVALID|IFM_ACTIVE;
   2775   1.17.2.2  nathanw }
   2776   1.17.2.2  nathanw 
   2777   1.17.2.2  nathanw static int
   2778   1.17.2.2  nathanw wi_set_nwkey(sc, nwkey)
   2779   1.17.2.2  nathanw 	struct wi_softc *sc;
   2780   1.17.2.2  nathanw 	struct ieee80211_nwkey *nwkey;
   2781   1.17.2.2  nathanw {
   2782   1.17.2.3  nathanw 	int i, error;
   2783   1.17.2.3  nathanw 	size_t len;
   2784   1.17.2.2  nathanw 	struct wi_req wreq;
   2785   1.17.2.2  nathanw 	struct wi_ltv_keys *wk = (struct wi_ltv_keys *)&wreq;
   2786   1.17.2.2  nathanw 
   2787  1.17.2.16  nathanw 	if ((sc->wi_flags & WI_FLAGS_HAS_WEP) == 0)
   2788   1.17.2.2  nathanw 		return ENODEV;
   2789   1.17.2.2  nathanw 	if (nwkey->i_defkid <= 0 ||
   2790   1.17.2.2  nathanw 	    nwkey->i_defkid > IEEE80211_WEP_NKID)
   2791   1.17.2.2  nathanw 		return EINVAL;
   2792   1.17.2.2  nathanw 	memcpy(wk, &sc->wi_keys, sizeof(*wk));
   2793   1.17.2.2  nathanw 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
   2794   1.17.2.2  nathanw 		if (nwkey->i_key[i].i_keydat == NULL)
   2795   1.17.2.2  nathanw 			continue;
   2796   1.17.2.2  nathanw 		len = nwkey->i_key[i].i_keylen;
   2797   1.17.2.2  nathanw 		if (len > sizeof(wk->wi_keys[i].wi_keydat))
   2798   1.17.2.2  nathanw 			return EINVAL;
   2799   1.17.2.2  nathanw 		error = copyin(nwkey->i_key[i].i_keydat,
   2800   1.17.2.2  nathanw 		    wk->wi_keys[i].wi_keydat, len);
   2801   1.17.2.2  nathanw 		if (error)
   2802   1.17.2.2  nathanw 			return error;
   2803   1.17.2.2  nathanw 		wk->wi_keys[i].wi_keylen = htole16(len);
   2804   1.17.2.2  nathanw 	}
   2805   1.17.2.2  nathanw 
   2806   1.17.2.2  nathanw 	wk->wi_len = (sizeof(*wk) / 2) + 1;
   2807   1.17.2.2  nathanw 	wk->wi_type = WI_RID_DEFLT_CRYPT_KEYS;
   2808   1.17.2.2  nathanw 	if (sc->sc_enabled != 0) {
   2809   1.17.2.2  nathanw 		error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
   2810   1.17.2.2  nathanw 		if (error)
   2811   1.17.2.2  nathanw 			return error;
   2812   1.17.2.2  nathanw 	}
   2813   1.17.2.2  nathanw 	error = wi_setdef(sc, &wreq);
   2814   1.17.2.2  nathanw 	if (error)
   2815   1.17.2.2  nathanw 		return error;
   2816   1.17.2.2  nathanw 
   2817   1.17.2.2  nathanw 	wreq.wi_len = 2;
   2818   1.17.2.2  nathanw 	wreq.wi_type = WI_RID_TX_CRYPT_KEY;
   2819   1.17.2.2  nathanw 	wreq.wi_val[0] = htole16(nwkey->i_defkid - 1);
   2820   1.17.2.2  nathanw 	if (sc->sc_enabled != 0) {
   2821   1.17.2.2  nathanw 		error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
   2822   1.17.2.2  nathanw 		if (error)
   2823   1.17.2.2  nathanw 			return error;
   2824   1.17.2.2  nathanw 	}
   2825   1.17.2.2  nathanw 	error = wi_setdef(sc, &wreq);
   2826   1.17.2.2  nathanw 	if (error)
   2827   1.17.2.2  nathanw 		return error;
   2828   1.17.2.2  nathanw 
   2829   1.17.2.2  nathanw 	wreq.wi_type = WI_RID_ENCRYPTION;
   2830   1.17.2.2  nathanw 	wreq.wi_val[0] = htole16(nwkey->i_wepon);
   2831   1.17.2.2  nathanw 	if (sc->sc_enabled != 0) {
   2832   1.17.2.2  nathanw 		error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
   2833   1.17.2.2  nathanw 		if (error)
   2834   1.17.2.2  nathanw 			return error;
   2835   1.17.2.2  nathanw 	}
   2836   1.17.2.2  nathanw 	error = wi_setdef(sc, &wreq);
   2837   1.17.2.2  nathanw 	if (error)
   2838   1.17.2.2  nathanw 		return error;
   2839   1.17.2.2  nathanw 
   2840   1.17.2.2  nathanw 	if (sc->sc_enabled != 0)
   2841   1.17.2.2  nathanw 		wi_init(&sc->sc_ethercom.ec_if);
   2842   1.17.2.2  nathanw 	return 0;
   2843   1.17.2.2  nathanw }
   2844   1.17.2.2  nathanw 
   2845   1.17.2.2  nathanw static int
   2846   1.17.2.2  nathanw wi_get_nwkey(sc, nwkey)
   2847   1.17.2.2  nathanw 	struct wi_softc *sc;
   2848   1.17.2.2  nathanw 	struct ieee80211_nwkey *nwkey;
   2849   1.17.2.2  nathanw {
   2850   1.17.2.2  nathanw 	int i, len, error;
   2851   1.17.2.2  nathanw 	struct wi_ltv_keys *wk = &sc->wi_keys;
   2852   1.17.2.2  nathanw 
   2853  1.17.2.16  nathanw 	if ((sc->wi_flags & WI_FLAGS_HAS_WEP) == 0)
   2854   1.17.2.2  nathanw 		return ENODEV;
   2855   1.17.2.2  nathanw 	nwkey->i_wepon = sc->wi_use_wep;
   2856   1.17.2.2  nathanw 	nwkey->i_defkid = sc->wi_tx_key + 1;
   2857   1.17.2.2  nathanw 
   2858   1.17.2.2  nathanw 	/* do not show any keys to non-root user */
   2859  1.17.2.14  nathanw 	error = suser(curproc->p_ucred, &curproc->p_acflag);
   2860   1.17.2.2  nathanw 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
   2861   1.17.2.2  nathanw 		if (nwkey->i_key[i].i_keydat == NULL)
   2862   1.17.2.2  nathanw 			continue;
   2863   1.17.2.2  nathanw 		/* error holds results of suser() for the first time */
   2864   1.17.2.2  nathanw 		if (error)
   2865   1.17.2.2  nathanw 			return error;
   2866   1.17.2.2  nathanw 		len = le16toh(wk->wi_keys[i].wi_keylen);
   2867   1.17.2.2  nathanw 		if (nwkey->i_key[i].i_keylen < len)
   2868   1.17.2.2  nathanw 			return ENOSPC;
   2869   1.17.2.2  nathanw 		nwkey->i_key[i].i_keylen = len;
   2870   1.17.2.2  nathanw 		error = copyout(wk->wi_keys[i].wi_keydat,
   2871   1.17.2.2  nathanw 		    nwkey->i_key[i].i_keydat, len);
   2872   1.17.2.2  nathanw 		if (error)
   2873   1.17.2.2  nathanw 			return error;
   2874   1.17.2.2  nathanw 	}
   2875   1.17.2.2  nathanw 	return 0;
   2876   1.17.2.2  nathanw }
   2877   1.17.2.2  nathanw 
   2878   1.17.2.2  nathanw static int
   2879   1.17.2.2  nathanw wi_set_pm(struct wi_softc *sc, struct ieee80211_power *power)
   2880   1.17.2.2  nathanw {
   2881   1.17.2.2  nathanw 
   2882   1.17.2.2  nathanw 	sc->wi_pm_enabled = power->i_enabled;
   2883   1.17.2.2  nathanw 	sc->wi_max_sleep = power->i_maxsleep;
   2884   1.17.2.2  nathanw 
   2885   1.17.2.2  nathanw 	if (sc->sc_enabled)
   2886   1.17.2.2  nathanw 		return (wi_init(&sc->sc_ethercom.ec_if));
   2887   1.17.2.2  nathanw 
   2888   1.17.2.2  nathanw 	return (0);
   2889   1.17.2.2  nathanw }
   2890   1.17.2.2  nathanw 
   2891   1.17.2.2  nathanw static int
   2892   1.17.2.2  nathanw wi_get_pm(struct wi_softc *sc, struct ieee80211_power *power)
   2893   1.17.2.2  nathanw {
   2894   1.17.2.2  nathanw 
   2895   1.17.2.2  nathanw 	power->i_enabled = sc->wi_pm_enabled;
   2896   1.17.2.2  nathanw 	power->i_maxsleep = sc->wi_max_sleep;
   2897   1.17.2.2  nathanw 
   2898   1.17.2.2  nathanw 	return (0);
   2899   1.17.2.2  nathanw }
   2900