Home | History | Annotate | Line # | Download | only in ic
wi.c revision 1.17.2.14
      1  1.17.2.14  nathanw /*	$NetBSD: wi.c,v 1.17.2.14 2002/06/24 22:10:04 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.14  nathanw __KERNEL_RCSID(0, "$NetBSD: wi.c,v 1.17.2.14 2002/06/24 22:10:04 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/lwp.h>
     89   1.17.2.2  nathanw #include <sys/proc.h>
     90   1.17.2.2  nathanw 
     91   1.17.2.2  nathanw #include <net/if.h>
     92   1.17.2.2  nathanw #include <net/if_dl.h>
     93   1.17.2.2  nathanw #include <net/if_media.h>
     94   1.17.2.2  nathanw #include <net/if_ether.h>
     95   1.17.2.2  nathanw #include <net/if_ieee80211.h>
     96   1.17.2.2  nathanw 
     97   1.17.2.2  nathanw #if NBPFILTER > 0
     98   1.17.2.2  nathanw #include <net/bpf.h>
     99   1.17.2.2  nathanw #include <net/bpfdesc.h>
    100   1.17.2.2  nathanw #endif
    101   1.17.2.2  nathanw 
    102   1.17.2.3  nathanw #include <machine/bus.h>
    103   1.17.2.2  nathanw 
    104   1.17.2.2  nathanw #include <dev/ic/wi_ieee.h>
    105   1.17.2.2  nathanw #include <dev/ic/wireg.h>
    106   1.17.2.2  nathanw #include <dev/ic/wivar.h>
    107   1.17.2.2  nathanw 
    108   1.17.2.2  nathanw static void wi_reset		__P((struct wi_softc *));
    109   1.17.2.2  nathanw static int wi_ioctl		__P((struct ifnet *, u_long, caddr_t));
    110   1.17.2.2  nathanw static void wi_start		__P((struct ifnet *));
    111   1.17.2.2  nathanw static void wi_watchdog		__P((struct ifnet *));
    112   1.17.2.2  nathanw static int wi_init		__P((struct ifnet *));
    113   1.17.2.2  nathanw static void wi_stop		__P((struct ifnet *, int));
    114   1.17.2.2  nathanw static void wi_rxeof		__P((struct wi_softc *));
    115   1.17.2.2  nathanw static void wi_txeof		__P((struct wi_softc *, int));
    116   1.17.2.2  nathanw static void wi_update_stats	__P((struct wi_softc *));
    117   1.17.2.2  nathanw static void wi_setmulti		__P((struct wi_softc *));
    118   1.17.2.2  nathanw 
    119   1.17.2.2  nathanw static int wi_cmd		__P((struct wi_softc *, int, int));
    120   1.17.2.2  nathanw static int wi_read_record	__P((struct wi_softc *, struct wi_ltv_gen *));
    121   1.17.2.2  nathanw static int wi_write_record	__P((struct wi_softc *, struct wi_ltv_gen *));
    122   1.17.2.2  nathanw static int wi_read_data		__P((struct wi_softc *, int,
    123   1.17.2.2  nathanw 					int, caddr_t, int));
    124   1.17.2.2  nathanw static int wi_write_data	__P((struct wi_softc *, int,
    125   1.17.2.2  nathanw 					int, caddr_t, int));
    126   1.17.2.2  nathanw static int wi_seek		__P((struct wi_softc *, int, int, int));
    127   1.17.2.2  nathanw static int wi_alloc_nicmem	__P((struct wi_softc *, int, int *));
    128   1.17.2.7  nathanw static void wi_inquire		__P((void *));
    129  1.17.2.10  nathanw static void wi_wait_scan	__P((void *));
    130   1.17.2.2  nathanw static int wi_setdef		__P((struct wi_softc *, struct wi_req *));
    131   1.17.2.2  nathanw static int wi_getdef		__P((struct wi_softc *, struct wi_req *));
    132   1.17.2.2  nathanw static int wi_mgmt_xmit		__P((struct wi_softc *, caddr_t, int));
    133   1.17.2.2  nathanw 
    134   1.17.2.2  nathanw static int wi_media_change __P((struct ifnet *));
    135   1.17.2.2  nathanw static void wi_media_status __P((struct ifnet *, struct ifmediareq *));
    136   1.17.2.2  nathanw 
    137   1.17.2.2  nathanw static void wi_get_id		__P((struct wi_softc *));
    138   1.17.2.2  nathanw 
    139   1.17.2.2  nathanw static int wi_set_ssid __P((struct ieee80211_nwid *, u_int8_t *, int));
    140   1.17.2.2  nathanw static void wi_request_fill_ssid __P((struct wi_req *,
    141   1.17.2.2  nathanw     struct ieee80211_nwid *));
    142   1.17.2.2  nathanw static int wi_write_ssid __P((struct wi_softc *, int, struct wi_req *,
    143   1.17.2.2  nathanw     struct ieee80211_nwid *));
    144   1.17.2.2  nathanw static int wi_set_nwkey __P((struct wi_softc *, struct ieee80211_nwkey *));
    145   1.17.2.2  nathanw static int wi_get_nwkey __P((struct wi_softc *, struct ieee80211_nwkey *));
    146   1.17.2.2  nathanw static int wi_sync_media __P((struct wi_softc *, int, int));
    147   1.17.2.2  nathanw static int wi_set_pm(struct wi_softc *, struct ieee80211_power *);
    148   1.17.2.2  nathanw static int wi_get_pm(struct wi_softc *, struct ieee80211_power *);
    149   1.17.2.2  nathanw 
    150  1.17.2.12  nathanw struct wi_card_ident wi_card_ident[] = {
    151  1.17.2.12  nathanw 	/* CARD_ID	CARD_NAME	FIRM_TYPE */
    152  1.17.2.12  nathanw 	{ WI_NIC_LUCENT_ID,		WI_NIC_LUCENT_STR,	WI_LUCENT },
    153  1.17.2.12  nathanw 	{ WI_NIC_SONY_ID,		WI_NIC_SONY_STR,	WI_LUCENT },
    154  1.17.2.12  nathanw 	{ WI_NIC_LUCENT_EMB_ID,		WI_NIC_LUCENT_EMB_STR,	WI_LUCENT },
    155  1.17.2.12  nathanw 	{ WI_NIC_EVB2_ID,		WI_NIC_EVB2_STR,	WI_INTERSIL },
    156  1.17.2.12  nathanw 	{ WI_NIC_HWB3763_ID,		WI_NIC_HWB3763_STR,	WI_INTERSIL },
    157  1.17.2.12  nathanw 	{ WI_NIC_HWB3163_ID,		WI_NIC_HWB3163_STR,	WI_INTERSIL },
    158  1.17.2.12  nathanw 	{ WI_NIC_HWB3163B_ID,		WI_NIC_HWB3163B_STR,	WI_INTERSIL },
    159  1.17.2.12  nathanw 	{ WI_NIC_EVB3_ID,		WI_NIC_EVB3_STR,	WI_INTERSIL },
    160  1.17.2.12  nathanw 	{ WI_NIC_HWB1153_ID,		WI_NIC_HWB1153_STR,	WI_INTERSIL },
    161  1.17.2.12  nathanw 	{ WI_NIC_P2_SST_ID,		WI_NIC_P2_SST_STR,	WI_INTERSIL },
    162  1.17.2.12  nathanw 	{ WI_NIC_EVB2_SST_ID,		WI_NIC_EVB2_SST_STR,	WI_INTERSIL },
    163  1.17.2.12  nathanw 	{ WI_NIC_3842_EVA_ID,		WI_NIC_3842_EVA_STR,	WI_INTERSIL },
    164  1.17.2.12  nathanw 	{ WI_NIC_3842_PCMCIA_AMD_ID,	WI_NIC_3842_PCMCIA_STR,	WI_INTERSIL },
    165  1.17.2.12  nathanw 	{ WI_NIC_3842_PCMCIA_SST_ID,	WI_NIC_3842_PCMCIA_STR,	WI_INTERSIL },
    166  1.17.2.12  nathanw 	{ WI_NIC_3842_PCMCIA_ATM_ID,	WI_NIC_3842_PCMCIA_STR,	WI_INTERSIL },
    167  1.17.2.12  nathanw 	{ WI_NIC_3842_MINI_AMD_ID,	WI_NIC_3842_MINI_STR,	WI_INTERSIL },
    168  1.17.2.12  nathanw 	{ WI_NIC_3842_MINI_SST_ID,	WI_NIC_3842_MINI_STR,	WI_INTERSIL },
    169  1.17.2.12  nathanw 	{ WI_NIC_3842_MINI_ATM_ID,	WI_NIC_3842_MINI_STR,	WI_INTERSIL },
    170  1.17.2.12  nathanw 	{ WI_NIC_3842_PCI_AMD_ID,	WI_NIC_3842_PCI_STR,	WI_INTERSIL },
    171  1.17.2.12  nathanw 	{ WI_NIC_3842_PCI_SST_ID,	WI_NIC_3842_PCI_STR,	WI_INTERSIL },
    172  1.17.2.12  nathanw 	{ WI_NIC_3842_PCI_ATM_ID,	WI_NIC_3842_PCI_STR,	WI_INTERSIL },
    173  1.17.2.12  nathanw 	{ WI_NIC_P3_PCMCIA_AMD_ID,	WI_NIC_P3_PCMCIA_STR,	WI_INTERSIL },
    174  1.17.2.12  nathanw 	{ WI_NIC_P3_PCMCIA_SST_ID,	WI_NIC_P3_PCMCIA_STR,	WI_INTERSIL },
    175  1.17.2.12  nathanw 	{ WI_NIC_P3_MINI_AMD_ID,	WI_NIC_P3_MINI_STR,	WI_INTERSIL },
    176  1.17.2.12  nathanw 	{ WI_NIC_P3_MINI_SST_ID,	WI_NIC_P3_MINI_STR,	WI_INTERSIL },
    177  1.17.2.12  nathanw 	{ 0,	NULL,	0 },
    178  1.17.2.12  nathanw };
    179  1.17.2.12  nathanw 
    180   1.17.2.2  nathanw int
    181   1.17.2.2  nathanw wi_attach(sc)
    182   1.17.2.2  nathanw 	struct wi_softc *sc;
    183   1.17.2.2  nathanw {
    184   1.17.2.2  nathanw 	struct ifnet *ifp = sc->sc_ifp;
    185   1.17.2.2  nathanw 	struct wi_ltv_macaddr   mac;
    186   1.17.2.2  nathanw 	struct wi_ltv_gen       gen;
    187   1.17.2.2  nathanw 	static const u_int8_t empty_macaddr[ETHER_ADDR_LEN] = {
    188   1.17.2.2  nathanw 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    189   1.17.2.2  nathanw 	};
    190   1.17.2.2  nathanw 	int s;
    191   1.17.2.2  nathanw 
    192   1.17.2.2  nathanw 	s = splnet();
    193   1.17.2.2  nathanw 
    194   1.17.2.7  nathanw 	callout_init(&sc->wi_inquire_ch);
    195  1.17.2.10  nathanw 	callout_init(&sc->wi_scan_sh);
    196   1.17.2.2  nathanw 
    197   1.17.2.2  nathanw 	/* Make sure interrupts are disabled. */
    198   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_INT_EN, 0);
    199   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
    200   1.17.2.2  nathanw 
    201   1.17.2.2  nathanw 	/* Reset the NIC. */
    202   1.17.2.2  nathanw 	wi_reset(sc);
    203   1.17.2.2  nathanw 
    204   1.17.2.2  nathanw 	memset(&mac, 0, sizeof(mac));
    205   1.17.2.2  nathanw 	/* Read the station address. */
    206   1.17.2.2  nathanw 	mac.wi_type = WI_RID_MAC_NODE;
    207   1.17.2.2  nathanw 	mac.wi_len = 4;
    208   1.17.2.2  nathanw 	wi_read_record(sc, (struct wi_ltv_gen *)&mac);
    209   1.17.2.2  nathanw 	memcpy(sc->sc_macaddr, mac.wi_mac_addr, ETHER_ADDR_LEN);
    210   1.17.2.2  nathanw 
    211   1.17.2.2  nathanw 	/*
    212   1.17.2.2  nathanw 	 * Check if we got anything meaningful.
    213   1.17.2.2  nathanw 	 *
    214   1.17.2.2  nathanw 	 * Is it really enough just checking against null ethernet address?
    215   1.17.2.2  nathanw 	 * Or, check against possible vendor?  XXX.
    216   1.17.2.2  nathanw 	 */
    217   1.17.2.3  nathanw 	if (memcmp(sc->sc_macaddr, empty_macaddr, ETHER_ADDR_LEN) == 0) {
    218  1.17.2.12  nathanw 		printf("could not get mac address, attach failed\n");
    219  1.17.2.10  nathanw 		splx(s);
    220  1.17.2.10  nathanw 		return 1;
    221   1.17.2.2  nathanw 	}
    222   1.17.2.2  nathanw 
    223   1.17.2.2  nathanw 	printf(" 802.11 address %s\n", ether_sprintf(sc->sc_macaddr));
    224   1.17.2.2  nathanw 
    225   1.17.2.2  nathanw 	/* Read NIC identification */
    226   1.17.2.2  nathanw 	wi_get_id(sc);
    227   1.17.2.2  nathanw 
    228   1.17.2.2  nathanw 	memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
    229   1.17.2.2  nathanw 	ifp->if_softc = sc;
    230   1.17.2.2  nathanw 	ifp->if_start = wi_start;
    231   1.17.2.2  nathanw 	ifp->if_ioctl = wi_ioctl;
    232   1.17.2.2  nathanw 	ifp->if_watchdog = wi_watchdog;
    233   1.17.2.2  nathanw 	ifp->if_init = wi_init;
    234   1.17.2.2  nathanw 	ifp->if_stop = wi_stop;
    235   1.17.2.2  nathanw 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
    236   1.17.2.2  nathanw #ifdef IFF_NOTRAILERS
    237   1.17.2.2  nathanw 	ifp->if_flags |= IFF_NOTRAILERS;
    238   1.17.2.2  nathanw #endif
    239   1.17.2.2  nathanw 	IFQ_SET_READY(&ifp->if_snd);
    240   1.17.2.2  nathanw 
    241   1.17.2.2  nathanw 	(void)wi_set_ssid(&sc->wi_nodeid, WI_DEFAULT_NODENAME,
    242   1.17.2.2  nathanw 	    sizeof(WI_DEFAULT_NODENAME) - 1);
    243   1.17.2.2  nathanw 	(void)wi_set_ssid(&sc->wi_netid, WI_DEFAULT_NETNAME,
    244   1.17.2.2  nathanw 	    sizeof(WI_DEFAULT_NETNAME) - 1);
    245   1.17.2.2  nathanw 	(void)wi_set_ssid(&sc->wi_ibssid, WI_DEFAULT_IBSS,
    246   1.17.2.2  nathanw 	    sizeof(WI_DEFAULT_IBSS) - 1);
    247   1.17.2.2  nathanw 
    248   1.17.2.2  nathanw 	sc->wi_portnum = WI_DEFAULT_PORT;
    249   1.17.2.2  nathanw 	sc->wi_ptype = WI_PORTTYPE_BSS;
    250   1.17.2.2  nathanw 	sc->wi_ap_density = WI_DEFAULT_AP_DENSITY;
    251   1.17.2.2  nathanw 	sc->wi_rts_thresh = WI_DEFAULT_RTS_THRESH;
    252   1.17.2.2  nathanw 	sc->wi_tx_rate = WI_DEFAULT_TX_RATE;
    253   1.17.2.2  nathanw 	sc->wi_max_data_len = WI_DEFAULT_DATALEN;
    254   1.17.2.2  nathanw 	sc->wi_create_ibss = WI_DEFAULT_CREATE_IBSS;
    255   1.17.2.2  nathanw 	sc->wi_pm_enabled = WI_DEFAULT_PM_ENABLED;
    256   1.17.2.2  nathanw 	sc->wi_max_sleep = WI_DEFAULT_MAX_SLEEP;
    257   1.17.2.2  nathanw 	sc->wi_roaming = WI_DEFAULT_ROAMING;
    258   1.17.2.2  nathanw 	sc->wi_authtype = WI_DEFAULT_AUTHTYPE;
    259   1.17.2.2  nathanw 
    260   1.17.2.2  nathanw 	/*
    261   1.17.2.2  nathanw 	 * Read the default channel from the NIC. This may vary
    262   1.17.2.2  nathanw 	 * depending on the country where the NIC was purchased, so
    263   1.17.2.2  nathanw 	 * we can't hard-code a default and expect it to work for
    264   1.17.2.2  nathanw 	 * everyone.
    265   1.17.2.2  nathanw 	 */
    266   1.17.2.2  nathanw 	gen.wi_type = WI_RID_OWN_CHNL;
    267   1.17.2.2  nathanw 	gen.wi_len = 2;
    268   1.17.2.2  nathanw 	wi_read_record(sc, &gen);
    269   1.17.2.2  nathanw 	sc->wi_channel = le16toh(gen.wi_val);
    270   1.17.2.2  nathanw 
    271   1.17.2.3  nathanw 	memset((char *)&sc->wi_stats, 0, sizeof(sc->wi_stats));
    272   1.17.2.2  nathanw 
    273  1.17.2.10  nathanw 	/* AP info was filled with 0 */
    274  1.17.2.10  nathanw 	memset((char *)&sc->wi_aps, 0, sizeof(sc->wi_aps));
    275  1.17.2.10  nathanw 	sc->wi_scanning=0;
    276  1.17.2.10  nathanw 	sc->wi_naps=0;
    277  1.17.2.10  nathanw 
    278   1.17.2.2  nathanw 	/*
    279   1.17.2.2  nathanw 	 * Find out if we support WEP on this card.
    280   1.17.2.2  nathanw 	 */
    281   1.17.2.2  nathanw 	gen.wi_type = WI_RID_WEP_AVAIL;
    282   1.17.2.2  nathanw 	gen.wi_len = 2;
    283   1.17.2.2  nathanw 	wi_read_record(sc, &gen);
    284   1.17.2.2  nathanw 	sc->wi_has_wep = le16toh(gen.wi_val);
    285   1.17.2.2  nathanw 
    286   1.17.2.2  nathanw 	ifmedia_init(&sc->sc_media, 0, wi_media_change, wi_media_status);
    287   1.17.2.2  nathanw #define	ADD(m, c)	ifmedia_add(&sc->sc_media, (m), (c), NULL)
    288   1.17.2.2  nathanw 	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0), 0);
    289  1.17.2.11  nathanw 	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, IFM_IEEE80211_ADHOC, 0), 0);
    290   1.17.2.2  nathanw 	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 0, 0), 0);
    291   1.17.2.2  nathanw 	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
    292   1.17.2.2  nathanw 	    IFM_IEEE80211_ADHOC, 0), 0);
    293   1.17.2.2  nathanw 	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 0, 0), 0);
    294   1.17.2.2  nathanw 	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
    295   1.17.2.2  nathanw 	    IFM_IEEE80211_ADHOC, 0), 0);
    296  1.17.2.10  nathanw 	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 0, 0), 0);
    297  1.17.2.10  nathanw 	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
    298  1.17.2.10  nathanw 	    IFM_IEEE80211_ADHOC, 0), 0);
    299   1.17.2.2  nathanw 	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 0, 0), 0);
    300   1.17.2.2  nathanw 	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
    301   1.17.2.2  nathanw 	    IFM_IEEE80211_ADHOC, 0), 0);
    302   1.17.2.2  nathanw 	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_MANUAL, 0, 0), 0);
    303   1.17.2.2  nathanw #undef ADD
    304  1.17.2.11  nathanw 	ifmedia_set(&sc->sc_media, IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0));
    305   1.17.2.2  nathanw 
    306   1.17.2.2  nathanw 	/*
    307   1.17.2.2  nathanw 	 * Call MI attach routines.
    308   1.17.2.2  nathanw 	 */
    309   1.17.2.2  nathanw 	if_attach(ifp);
    310   1.17.2.2  nathanw 	ether_ifattach(ifp, mac.wi_mac_addr);
    311   1.17.2.2  nathanw 
    312   1.17.2.2  nathanw 	ifp->if_baudrate = IF_Mbps(2);
    313   1.17.2.2  nathanw 
    314   1.17.2.2  nathanw 	/* Attach is successful. */
    315   1.17.2.2  nathanw 	sc->sc_attached = 1;
    316   1.17.2.2  nathanw 
    317   1.17.2.2  nathanw 	splx(s);
    318   1.17.2.2  nathanw 	return 0;
    319   1.17.2.2  nathanw }
    320   1.17.2.2  nathanw 
    321   1.17.2.2  nathanw static void wi_rxeof(sc)
    322   1.17.2.2  nathanw 	struct wi_softc		*sc;
    323   1.17.2.2  nathanw {
    324   1.17.2.2  nathanw 	struct ifnet		*ifp;
    325   1.17.2.2  nathanw 	struct ether_header	*eh;
    326   1.17.2.2  nathanw 	struct wi_frame		rx_frame;
    327   1.17.2.2  nathanw 	struct mbuf		*m;
    328   1.17.2.2  nathanw 	int			id;
    329   1.17.2.2  nathanw 
    330   1.17.2.2  nathanw 	ifp = sc->sc_ifp;
    331   1.17.2.2  nathanw 
    332   1.17.2.2  nathanw 	id = CSR_READ_2(sc, WI_RX_FID);
    333   1.17.2.2  nathanw 
    334   1.17.2.2  nathanw 	/* First read in the frame header */
    335   1.17.2.2  nathanw 	if (wi_read_data(sc, id, 0, (caddr_t)&rx_frame, sizeof(rx_frame))) {
    336   1.17.2.2  nathanw 		ifp->if_ierrors++;
    337   1.17.2.2  nathanw 		return;
    338   1.17.2.2  nathanw 	}
    339   1.17.2.2  nathanw 
    340   1.17.2.8  nathanw 	/*
    341   1.17.2.8  nathanw 	 * Drop undecryptable or packets with receive errors here
    342   1.17.2.8  nathanw 	 */
    343   1.17.2.7  nathanw 	if (le16toh(rx_frame.wi_status) & WI_STAT_ERRSTAT) {
    344   1.17.2.2  nathanw 		ifp->if_ierrors++;
    345   1.17.2.2  nathanw 		return;
    346   1.17.2.2  nathanw 	}
    347   1.17.2.2  nathanw 
    348   1.17.2.2  nathanw 	MGETHDR(m, M_DONTWAIT, MT_DATA);
    349   1.17.2.2  nathanw 	if (m == NULL) {
    350   1.17.2.2  nathanw 		ifp->if_ierrors++;
    351   1.17.2.2  nathanw 		return;
    352   1.17.2.2  nathanw 	}
    353   1.17.2.2  nathanw 	MCLGET(m, M_DONTWAIT);
    354   1.17.2.2  nathanw 	if (!(m->m_flags & M_EXT)) {
    355   1.17.2.2  nathanw 		m_freem(m);
    356   1.17.2.2  nathanw 		ifp->if_ierrors++;
    357   1.17.2.2  nathanw 		return;
    358   1.17.2.2  nathanw 	}
    359   1.17.2.2  nathanw 
    360   1.17.2.2  nathanw 	/* Align the data after the ethernet header */
    361   1.17.2.2  nathanw 	m->m_data = (caddr_t) ALIGN(m->m_data + sizeof(struct ether_header))
    362   1.17.2.2  nathanw 	    - sizeof(struct ether_header);
    363   1.17.2.2  nathanw 
    364   1.17.2.2  nathanw 	eh = mtod(m, struct ether_header *);
    365   1.17.2.2  nathanw 	m->m_pkthdr.rcvif = ifp;
    366   1.17.2.2  nathanw 
    367  1.17.2.13  nathanw 	if ((le16toh(rx_frame.wi_status) & WI_RXSTAT_MSG_TYPE) == WI_STAT_1042 ||
    368  1.17.2.13  nathanw 	    (le16toh(rx_frame.wi_status) & WI_RXSTAT_MSG_TYPE) == WI_STAT_TUNNEL ||
    369  1.17.2.13  nathanw 	    (le16toh(rx_frame.wi_status) & WI_RXSTAT_MSG_TYPE) == WI_STAT_WMP_MSG) {
    370   1.17.2.2  nathanw 		if ((le16toh(rx_frame.wi_dat_len) + WI_SNAPHDR_LEN) > MCLBYTES) {
    371   1.17.2.2  nathanw 			printf("%s: oversized packet received "
    372   1.17.2.2  nathanw 			    "(wi_dat_len=%d, wi_status=0x%x)\n",
    373   1.17.2.2  nathanw 			    sc->sc_dev.dv_xname,
    374   1.17.2.2  nathanw 			    le16toh(rx_frame.wi_dat_len), le16toh(rx_frame.wi_status));
    375   1.17.2.2  nathanw 			m_freem(m);
    376   1.17.2.2  nathanw 			ifp->if_ierrors++;
    377   1.17.2.2  nathanw 			return;
    378   1.17.2.2  nathanw 		}
    379   1.17.2.2  nathanw 		m->m_pkthdr.len = m->m_len =
    380   1.17.2.2  nathanw 		    le16toh(rx_frame.wi_dat_len) + WI_SNAPHDR_LEN;
    381   1.17.2.2  nathanw 
    382   1.17.2.3  nathanw 		memcpy((char *)&eh->ether_dhost, (char *)&rx_frame.wi_dst_addr,
    383   1.17.2.3  nathanw 		    ETHER_ADDR_LEN);
    384   1.17.2.3  nathanw 		memcpy((char *)&eh->ether_shost, (char *)&rx_frame.wi_src_addr,
    385   1.17.2.3  nathanw 		    ETHER_ADDR_LEN);
    386   1.17.2.3  nathanw 		memcpy((char *)&eh->ether_type, (char *)&rx_frame.wi_type,
    387   1.17.2.3  nathanw 		    sizeof(u_int16_t));
    388   1.17.2.2  nathanw 
    389   1.17.2.2  nathanw 		if (wi_read_data(sc, id, WI_802_11_OFFSET,
    390   1.17.2.2  nathanw 		    mtod(m, caddr_t) + sizeof(struct ether_header),
    391   1.17.2.2  nathanw 		    m->m_len + 2)) {
    392   1.17.2.2  nathanw 			m_freem(m);
    393   1.17.2.2  nathanw 			ifp->if_ierrors++;
    394   1.17.2.2  nathanw 			return;
    395   1.17.2.2  nathanw 		}
    396   1.17.2.2  nathanw 	} else {
    397   1.17.2.2  nathanw 		if ((le16toh(rx_frame.wi_dat_len) +
    398   1.17.2.2  nathanw 		    sizeof(struct ether_header)) > MCLBYTES) {
    399   1.17.2.2  nathanw 			printf("%s: oversized packet received "
    400   1.17.2.2  nathanw 			    "(wi_dat_len=%d, wi_status=0x%x)\n",
    401   1.17.2.2  nathanw 			    sc->sc_dev.dv_xname,
    402   1.17.2.2  nathanw 			    le16toh(rx_frame.wi_dat_len), le16toh(rx_frame.wi_status));
    403   1.17.2.2  nathanw 			m_freem(m);
    404   1.17.2.2  nathanw 			ifp->if_ierrors++;
    405   1.17.2.2  nathanw 			return;
    406   1.17.2.2  nathanw 		}
    407   1.17.2.2  nathanw 		m->m_pkthdr.len = m->m_len =
    408   1.17.2.2  nathanw 		    le16toh(rx_frame.wi_dat_len) + sizeof(struct ether_header);
    409   1.17.2.2  nathanw 
    410   1.17.2.2  nathanw 		if (wi_read_data(sc, id, WI_802_3_OFFSET,
    411   1.17.2.2  nathanw 		    mtod(m, caddr_t), m->m_len + 2)) {
    412   1.17.2.2  nathanw 			m_freem(m);
    413   1.17.2.2  nathanw 			ifp->if_ierrors++;
    414   1.17.2.2  nathanw 			return;
    415   1.17.2.2  nathanw 		}
    416   1.17.2.2  nathanw 	}
    417   1.17.2.2  nathanw 
    418   1.17.2.2  nathanw 	ifp->if_ipackets++;
    419   1.17.2.2  nathanw 
    420   1.17.2.2  nathanw #if NBPFILTER > 0
    421   1.17.2.2  nathanw 	/* Handle BPF listeners. */
    422   1.17.2.2  nathanw 	if (ifp->if_bpf)
    423   1.17.2.2  nathanw 		bpf_mtap(ifp->if_bpf, m);
    424   1.17.2.2  nathanw #endif
    425   1.17.2.2  nathanw 
    426   1.17.2.2  nathanw 	/* Receive packet. */
    427   1.17.2.2  nathanw 	(*ifp->if_input)(ifp, m);
    428   1.17.2.2  nathanw }
    429   1.17.2.2  nathanw 
    430   1.17.2.2  nathanw static void wi_txeof(sc, status)
    431   1.17.2.2  nathanw 	struct wi_softc	*sc;
    432   1.17.2.2  nathanw 	int		status;
    433   1.17.2.2  nathanw {
    434   1.17.2.2  nathanw 	struct ifnet	*ifp = sc->sc_ifp;
    435   1.17.2.2  nathanw 
    436   1.17.2.2  nathanw 	ifp->if_timer = 0;
    437   1.17.2.2  nathanw 	ifp->if_flags &= ~IFF_OACTIVE;
    438   1.17.2.2  nathanw 
    439   1.17.2.2  nathanw 	if (status & WI_EV_TX_EXC)
    440   1.17.2.2  nathanw 		ifp->if_oerrors++;
    441   1.17.2.2  nathanw 	else
    442   1.17.2.2  nathanw 		ifp->if_opackets++;
    443   1.17.2.2  nathanw 
    444   1.17.2.2  nathanw 	return;
    445   1.17.2.2  nathanw }
    446   1.17.2.2  nathanw 
    447   1.17.2.7  nathanw void wi_inquire(xsc)
    448   1.17.2.2  nathanw 	void			*xsc;
    449   1.17.2.2  nathanw {
    450   1.17.2.2  nathanw 	struct wi_softc		*sc;
    451   1.17.2.2  nathanw 	struct ifnet		*ifp;
    452  1.17.2.10  nathanw 	int			s;
    453   1.17.2.2  nathanw 
    454   1.17.2.2  nathanw 	sc = xsc;
    455   1.17.2.2  nathanw 	ifp = &sc->sc_ethercom.ec_if;
    456   1.17.2.2  nathanw 
    457   1.17.2.2  nathanw 	if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
    458   1.17.2.2  nathanw 		return;
    459   1.17.2.2  nathanw 
    460  1.17.2.11  nathanw 	KASSERT(sc->sc_enabled);
    461  1.17.2.11  nathanw 
    462   1.17.2.7  nathanw 	callout_reset(&sc->wi_inquire_ch, hz * 60, wi_inquire, sc);
    463   1.17.2.2  nathanw 
    464   1.17.2.2  nathanw 	/* Don't do this while we're transmitting */
    465   1.17.2.2  nathanw 	if (ifp->if_flags & IFF_OACTIVE)
    466   1.17.2.2  nathanw 		return;
    467   1.17.2.2  nathanw 
    468  1.17.2.10  nathanw 	s = splnet();
    469   1.17.2.2  nathanw 	wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_COUNTERS);
    470  1.17.2.10  nathanw 	splx(s);
    471  1.17.2.10  nathanw }
    472  1.17.2.10  nathanw 
    473  1.17.2.10  nathanw void wi_wait_scan(xsc)
    474  1.17.2.10  nathanw 	void			*xsc;
    475  1.17.2.10  nathanw {
    476  1.17.2.10  nathanw 	struct wi_softc         *sc;
    477  1.17.2.10  nathanw 	struct ifnet            *ifp;
    478  1.17.2.10  nathanw 	int			s, result;
    479  1.17.2.10  nathanw 
    480  1.17.2.10  nathanw 	sc = xsc;
    481  1.17.2.10  nathanw 	ifp = &sc->sc_ethercom.ec_if;
    482  1.17.2.10  nathanw 
    483  1.17.2.10  nathanw 	/* If not scanning, ignore */
    484  1.17.2.10  nathanw 	if (!sc->wi_scanning)
    485  1.17.2.10  nathanw 		return;
    486  1.17.2.10  nathanw 
    487  1.17.2.10  nathanw 	s = splnet();
    488  1.17.2.10  nathanw 
    489  1.17.2.10  nathanw 	/* Wait for sending complete to make INQUIRE */
    490  1.17.2.10  nathanw 	if (ifp->if_flags & IFF_OACTIVE) {
    491  1.17.2.10  nathanw 		callout_reset(&sc->wi_scan_sh, hz * 1, wi_wait_scan, sc);
    492  1.17.2.10  nathanw 		splx(s);
    493  1.17.2.10  nathanw 		return;
    494  1.17.2.10  nathanw 	}
    495  1.17.2.10  nathanw 
    496  1.17.2.10  nathanw 	/* try INQUIRE */
    497  1.17.2.10  nathanw 	result = wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_SCAN_RESULTS);
    498  1.17.2.10  nathanw 	if (result == ETIMEDOUT)
    499  1.17.2.10  nathanw 		callout_reset(&sc->wi_scan_sh, hz * 1, wi_wait_scan, sc);
    500  1.17.2.10  nathanw 
    501  1.17.2.10  nathanw 	splx(s);
    502   1.17.2.2  nathanw }
    503   1.17.2.2  nathanw 
    504   1.17.2.2  nathanw void wi_update_stats(sc)
    505   1.17.2.2  nathanw 	struct wi_softc		*sc;
    506   1.17.2.2  nathanw {
    507   1.17.2.2  nathanw 	struct wi_ltv_gen	gen;
    508  1.17.2.10  nathanw 	struct wi_scan_header	ap2_header;	/* Prism2 header */
    509  1.17.2.10  nathanw 	struct wi_scan_data_p2	ap2;		/* Prism2 scantable*/
    510  1.17.2.10  nathanw 	struct wi_scan_data	ap;		/* Lucent scantable */
    511  1.17.2.10  nathanw 	struct wi_assoc		assoc;		/* Association Status */
    512   1.17.2.2  nathanw 	u_int16_t		id;
    513   1.17.2.2  nathanw 	struct ifnet		*ifp;
    514   1.17.2.2  nathanw 	u_int32_t		*ptr;
    515  1.17.2.10  nathanw 	int			len, naps, i, j;
    516   1.17.2.2  nathanw 	u_int16_t		t;
    517   1.17.2.2  nathanw 
    518   1.17.2.2  nathanw 	ifp = &sc->sc_ethercom.ec_if;
    519   1.17.2.2  nathanw 
    520   1.17.2.2  nathanw 	id = CSR_READ_2(sc, WI_INFO_FID);
    521   1.17.2.2  nathanw 
    522  1.17.2.11  nathanw 	if (wi_seek(sc, id, 0, WI_BAP1)) {
    523  1.17.2.11  nathanw 		return;
    524  1.17.2.11  nathanw 	}
    525  1.17.2.11  nathanw 
    526  1.17.2.11  nathanw 	gen.wi_len = CSR_READ_2(sc, WI_DATA1);
    527  1.17.2.11  nathanw 	gen.wi_type = CSR_READ_2(sc, WI_DATA1);
    528   1.17.2.2  nathanw 
    529   1.17.2.9  nathanw 	switch (gen.wi_type) {
    530  1.17.2.10  nathanw 	case WI_INFO_SCAN_RESULTS:
    531  1.17.2.12  nathanw 	case WI_INFO_HOST_SCAN_RESULTS:
    532  1.17.2.11  nathanw 		if (gen.wi_len <= 3) {
    533  1.17.2.11  nathanw 			sc->wi_naps = 0;
    534  1.17.2.11  nathanw 			sc->wi_scanning = 0;
    535  1.17.2.10  nathanw 			break;
    536  1.17.2.11  nathanw 		}
    537  1.17.2.11  nathanw 		switch (sc->sc_firmware_type) {
    538  1.17.2.11  nathanw 		case WI_INTERSIL:
    539  1.17.2.12  nathanw 		case WI_SYMBOL:
    540  1.17.2.12  nathanw 			if (sc->sc_firmware_type == WI_INTERSIL) {
    541  1.17.2.12  nathanw 				naps = 2 * (gen.wi_len - 3) / sizeof(ap2);
    542  1.17.2.12  nathanw 				/* Read Header */
    543  1.17.2.12  nathanw 				for(j=0; j < sizeof(ap2_header) / 2; j++)
    544  1.17.2.12  nathanw 					((u_int16_t *)&ap2_header)[j] =
    545  1.17.2.12  nathanw 					    CSR_READ_2(sc, WI_DATA1);
    546  1.17.2.12  nathanw 			} else {	/* WI_SYMBOL */
    547  1.17.2.12  nathanw 				naps = 2 * (gen.wi_len - 1) / (sizeof(ap2) + 6);
    548  1.17.2.12  nathanw 				ap2_header.wi_reason = 0;
    549  1.17.2.12  nathanw 			}
    550  1.17.2.10  nathanw 			naps = naps > MAXAPINFO ? MAXAPINFO : naps;
    551  1.17.2.10  nathanw 			sc->wi_naps = naps;
    552  1.17.2.10  nathanw 			/* Read Data */
    553  1.17.2.10  nathanw 			for (i=0; i < naps; i++) {
    554  1.17.2.10  nathanw 				for(j=0; j < sizeof(ap2) / 2; j++)
    555  1.17.2.10  nathanw 					((u_int16_t *)&ap2)[j] =
    556  1.17.2.10  nathanw 						CSR_READ_2(sc, WI_DATA1);
    557  1.17.2.12  nathanw 				if (sc->sc_firmware_type == WI_SYMBOL) {
    558  1.17.2.12  nathanw 					/* 3 more words */
    559  1.17.2.12  nathanw 					for (j = 0; j < 3; j++)
    560  1.17.2.12  nathanw 						CSR_READ_2(sc, WI_DATA1);
    561  1.17.2.12  nathanw 				}
    562  1.17.2.11  nathanw 				/* unswap 8 bit data fields: */
    563  1.17.2.11  nathanw 				for(j=0;j<sizeof(ap.wi_bssid)/2;j++)
    564  1.17.2.11  nathanw 					LE16TOH(((u_int16_t *)&ap.wi_bssid[0])[j]);
    565  1.17.2.11  nathanw 				for(j=0;j<sizeof(ap.wi_name)/2;j++)
    566  1.17.2.11  nathanw 					LE16TOH(((u_int16_t *)&ap.wi_name[0])[j]);
    567  1.17.2.10  nathanw 				sc->wi_aps[i].scanreason = ap2_header.wi_reason;
    568  1.17.2.10  nathanw 				memcpy(sc->wi_aps[i].bssid, ap2.wi_bssid, 6);
    569  1.17.2.10  nathanw 				sc->wi_aps[i].channel = ap2.wi_chid;
    570  1.17.2.10  nathanw 				sc->wi_aps[i].signal  = ap2.wi_signal;
    571  1.17.2.10  nathanw 				sc->wi_aps[i].noise   = ap2.wi_noise;
    572  1.17.2.10  nathanw 				sc->wi_aps[i].quality = ap2.wi_signal - ap2.wi_noise;
    573  1.17.2.10  nathanw 				sc->wi_aps[i].capinfo = ap2.wi_capinfo;
    574  1.17.2.10  nathanw 				sc->wi_aps[i].interval = ap2.wi_interval;
    575  1.17.2.10  nathanw 				sc->wi_aps[i].rate    = ap2.wi_rate;
    576  1.17.2.10  nathanw 				if (ap2.wi_namelen > 32)
    577  1.17.2.10  nathanw 					ap2.wi_namelen = 32;
    578  1.17.2.10  nathanw 				sc->wi_aps[i].namelen = ap2.wi_namelen;
    579  1.17.2.10  nathanw 				memcpy(sc->wi_aps[i].name, ap2.wi_name,
    580  1.17.2.10  nathanw 				       ap2.wi_namelen);
    581  1.17.2.10  nathanw 			}
    582  1.17.2.11  nathanw 			break;
    583  1.17.2.11  nathanw 
    584  1.17.2.11  nathanw 		case WI_LUCENT:
    585  1.17.2.10  nathanw 			naps = 2 * gen.wi_len / sizeof(ap);
    586  1.17.2.10  nathanw 			naps = naps > MAXAPINFO ? MAXAPINFO : naps;
    587  1.17.2.10  nathanw 			sc->wi_naps = naps;
    588  1.17.2.10  nathanw 			/* Read Data*/
    589  1.17.2.10  nathanw 			for (i=0; i < naps; i++) {
    590  1.17.2.10  nathanw 				for(j=0; j < sizeof(ap) / 2; j++)
    591  1.17.2.10  nathanw 					((u_int16_t *)&ap)[j] =
    592  1.17.2.10  nathanw 						CSR_READ_2(sc, WI_DATA1);
    593  1.17.2.11  nathanw 				/* unswap 8 bit data fields: */
    594  1.17.2.11  nathanw 				for(j=0;j<sizeof(ap.wi_bssid)/2;j++)
    595  1.17.2.11  nathanw 					HTOLE16(((u_int16_t *)&ap.wi_bssid[0])[j]);
    596  1.17.2.11  nathanw 				for(j=0;j<sizeof(ap.wi_name)/2;j++)
    597  1.17.2.11  nathanw 					HTOLE16(((u_int16_t *)&ap.wi_name[0])[j]);
    598  1.17.2.10  nathanw 				memcpy(sc->wi_aps[i].bssid, ap.wi_bssid, 6);
    599  1.17.2.10  nathanw 				sc->wi_aps[i].channel = ap.wi_chid;
    600  1.17.2.10  nathanw 				sc->wi_aps[i].signal  = ap.wi_signal;
    601  1.17.2.10  nathanw 				sc->wi_aps[i].noise   = ap.wi_noise;
    602  1.17.2.10  nathanw 				sc->wi_aps[i].quality = ap.wi_signal - ap.wi_noise;
    603  1.17.2.10  nathanw 				sc->wi_aps[i].capinfo = ap.wi_capinfo;
    604  1.17.2.10  nathanw 				sc->wi_aps[i].interval = ap.wi_interval;
    605  1.17.2.10  nathanw 				if (ap.wi_namelen > 32)
    606  1.17.2.10  nathanw 					ap.wi_namelen = 32;
    607  1.17.2.10  nathanw 				sc->wi_aps[i].namelen = ap.wi_namelen;
    608  1.17.2.10  nathanw 				memcpy(sc->wi_aps[i].name, ap.wi_name,
    609  1.17.2.10  nathanw 				       ap.wi_namelen);
    610  1.17.2.10  nathanw 			}
    611  1.17.2.11  nathanw 			break;
    612  1.17.2.10  nathanw 		}
    613  1.17.2.10  nathanw 		/* Done scanning */
    614  1.17.2.10  nathanw 		sc->wi_scanning = 0;
    615  1.17.2.10  nathanw 		break;
    616  1.17.2.10  nathanw 
    617   1.17.2.9  nathanw 	case WI_INFO_COUNTERS:
    618   1.17.2.9  nathanw 		/* some card versions have a larger stats structure */
    619   1.17.2.9  nathanw 		len = (gen.wi_len - 1 < sizeof(sc->wi_stats) / 4) ?
    620   1.17.2.9  nathanw 			gen.wi_len - 1 : sizeof(sc->wi_stats) / 4;
    621   1.17.2.9  nathanw 		ptr = (u_int32_t *)&sc->wi_stats;
    622   1.17.2.7  nathanw 
    623   1.17.2.9  nathanw 		for (i = 0; i < len; i++) {
    624   1.17.2.9  nathanw 			t = CSR_READ_2(sc, WI_DATA1);
    625   1.17.2.2  nathanw #ifdef WI_HERMES_STATS_WAR
    626   1.17.2.9  nathanw 			if (t > 0xF000)
    627   1.17.2.9  nathanw 				t = ~t & 0xFFFF;
    628   1.17.2.2  nathanw #endif
    629   1.17.2.9  nathanw 			ptr[i] += t;
    630   1.17.2.9  nathanw 		}
    631   1.17.2.4  nathanw 
    632   1.17.2.9  nathanw 		ifp->if_collisions = sc->wi_stats.wi_tx_single_retries +
    633   1.17.2.9  nathanw 			sc->wi_stats.wi_tx_multi_retries +
    634   1.17.2.9  nathanw 			sc->wi_stats.wi_tx_retry_limit;
    635   1.17.2.9  nathanw 		break;
    636   1.17.2.6  thorpej 
    637   1.17.2.9  nathanw 	case WI_INFO_LINK_STAT: {
    638   1.17.2.9  nathanw 		static char *msg[] = {
    639   1.17.2.9  nathanw 			"connected",
    640   1.17.2.9  nathanw 			"disconnected",
    641   1.17.2.9  nathanw 			"AP change",
    642   1.17.2.9  nathanw 			"AP out of range",
    643  1.17.2.10  nathanw 			"AP in range",
    644  1.17.2.11  nathanw 			"Association Failed"
    645   1.17.2.9  nathanw 		};
    646   1.17.2.9  nathanw 
    647   1.17.2.9  nathanw 		if (gen.wi_len != 2) {
    648   1.17.2.9  nathanw #ifdef WI_DEBUG
    649   1.17.2.9  nathanw 			printf("WI_INFO_LINK_STAT: len=%d\n", gen.wi_len);
    650   1.17.2.9  nathanw #endif
    651   1.17.2.9  nathanw 			break;
    652   1.17.2.9  nathanw 		}
    653   1.17.2.9  nathanw 		t = CSR_READ_2(sc, WI_DATA1);
    654  1.17.2.10  nathanw 		if ((t < 1) || (t > 6)) {
    655   1.17.2.9  nathanw #ifdef WI_DEBUG
    656   1.17.2.9  nathanw 			printf("WI_INFO_LINK_STAT: status %d\n", t);
    657   1.17.2.9  nathanw #endif
    658   1.17.2.9  nathanw 			break;
    659   1.17.2.9  nathanw 		}
    660  1.17.2.12  nathanw 		if (sc->sc_firmware_type == WI_SYMBOL && t == 4) {
    661  1.17.2.12  nathanw 			wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_HOST_SCAN_RESULTS);
    662  1.17.2.12  nathanw 			break;
    663  1.17.2.12  nathanw 		}
    664  1.17.2.10  nathanw 		/*
    665  1.17.2.10  nathanw 		 * Some cards issue streams of "connected" messages while
    666  1.17.2.10  nathanw 		 * trying to find a peer. Don't bother the user with this
    667  1.17.2.10  nathanw 		 * unless he is debugging.
    668  1.17.2.10  nathanw 		 */
    669  1.17.2.10  nathanw 		if (ifp->if_flags & IFF_DEBUG)
    670  1.17.2.10  nathanw 			printf("%s: %s\n", sc->sc_dev.dv_xname, msg[t - 1]);
    671   1.17.2.9  nathanw 		break;
    672   1.17.2.9  nathanw 		}
    673   1.17.2.9  nathanw 
    674  1.17.2.10  nathanw 	case WI_INFO_ASSOC_STAT: {
    675  1.17.2.10  nathanw 		static char *msg[] = {
    676  1.17.2.10  nathanw 			"STA Associated",
    677  1.17.2.10  nathanw 			"STA Reassociated",
    678  1.17.2.10  nathanw 			"STA Disassociated",
    679  1.17.2.10  nathanw 			"Association Failure",
    680  1.17.2.11  nathanw 			"Authentication Failed"
    681  1.17.2.10  nathanw 		};
    682  1.17.2.10  nathanw 		if (gen.wi_len != 10)
    683  1.17.2.10  nathanw                         break;
    684  1.17.2.10  nathanw 		for (i=0; i < gen.wi_len - 1; i++)
    685  1.17.2.10  nathanw 			((u_int16_t *)&assoc)[i] = CSR_READ_2(sc, WI_DATA1);
    686  1.17.2.11  nathanw 		/* unswap 8 bit data fields: */
    687  1.17.2.11  nathanw 		for(j=0;j<sizeof(assoc.wi_assoc_sta)/2;j++)
    688  1.17.2.11  nathanw 			HTOLE16(((u_int16_t *)&assoc.wi_assoc_sta[0])[j]);
    689  1.17.2.11  nathanw 		for(j=0;j<sizeof(assoc.wi_assoc_osta)/2;j++)
    690  1.17.2.11  nathanw 			HTOLE16(((u_int16_t *)&assoc.wi_assoc_osta[0])[j]);
    691  1.17.2.10  nathanw 		switch (assoc.wi_assoc_stat) {
    692  1.17.2.10  nathanw 		case ASSOC:
    693  1.17.2.10  nathanw 		case DISASSOC:
    694  1.17.2.10  nathanw 		case ASSOCFAIL:
    695  1.17.2.10  nathanw 		case AUTHFAIL:
    696  1.17.2.11  nathanw 			printf("%s: %s, AP = %02x:%02x:%02x:%02x:%02x:%02x\n",
    697  1.17.2.10  nathanw 				sc->sc_dev.dv_xname,
    698  1.17.2.10  nathanw 				msg[assoc.wi_assoc_stat - 1],
    699  1.17.2.10  nathanw 				assoc.wi_assoc_sta[0]&0xff, assoc.wi_assoc_sta[1]&0xff,
    700  1.17.2.10  nathanw 				assoc.wi_assoc_sta[2]&0xff, assoc.wi_assoc_sta[3]&0xff,
    701  1.17.2.10  nathanw 				assoc.wi_assoc_sta[4]&0xff, assoc.wi_assoc_sta[5]&0xff);
    702  1.17.2.10  nathanw 			break;
    703  1.17.2.10  nathanw 		case REASSOC:
    704  1.17.2.11  nathanw 			printf("%s: %s, AP = %02x:%02x:%02x:%02x:%02x:%02x, "
    705  1.17.2.11  nathanw 				"OldAP = %02x:%02x:%02x:%02x:%02x:%02x\n",
    706  1.17.2.10  nathanw 				sc->sc_dev.dv_xname, msg[assoc.wi_assoc_stat - 1],
    707  1.17.2.10  nathanw 				assoc.wi_assoc_sta[0]&0xff, assoc.wi_assoc_sta[1]&0xff,
    708  1.17.2.10  nathanw 				assoc.wi_assoc_sta[2]&0xff, assoc.wi_assoc_sta[3]&0xff,
    709  1.17.2.10  nathanw 				assoc.wi_assoc_sta[4]&0xff, assoc.wi_assoc_sta[5]&0xff,
    710  1.17.2.10  nathanw 				assoc.wi_assoc_osta[0]&0xff, assoc.wi_assoc_osta[1]&0xff,
    711  1.17.2.10  nathanw 				assoc.wi_assoc_osta[2]&0xff, assoc.wi_assoc_osta[3]&0xff,
    712  1.17.2.10  nathanw 				assoc.wi_assoc_osta[4]&0xff, assoc.wi_assoc_osta[5]&0xff);
    713  1.17.2.10  nathanw 			break;
    714  1.17.2.10  nathanw 		}
    715  1.17.2.10  nathanw 		}
    716  1.17.2.12  nathanw 
    717   1.17.2.9  nathanw 	default:
    718  1.17.2.10  nathanw #ifdef WI_DEBUG
    719  1.17.2.10  nathanw 		printf("%s: got info type: 0x%04x len=0x%04x\n",
    720  1.17.2.10  nathanw       sc->sc_dev.dv_xname, gen.wi_type,gen.wi_len);
    721   1.17.2.9  nathanw #endif
    722  1.17.2.10  nathanw #if 0
    723   1.17.2.9  nathanw 		for (i = 0; i < gen.wi_len; i++) {
    724   1.17.2.9  nathanw 			t = CSR_READ_2(sc, WI_DATA1);
    725   1.17.2.9  nathanw 			printf("[0x%02x] = 0x%04x\n", i, t);
    726   1.17.2.9  nathanw 		}
    727  1.17.2.10  nathanw #endif
    728   1.17.2.9  nathanw 		break;
    729   1.17.2.9  nathanw 	}
    730   1.17.2.2  nathanw }
    731   1.17.2.2  nathanw 
    732   1.17.2.2  nathanw int wi_intr(arg)
    733   1.17.2.2  nathanw 	void *arg;
    734   1.17.2.2  nathanw {
    735   1.17.2.2  nathanw 	struct wi_softc		*sc = arg;
    736   1.17.2.2  nathanw 	struct ifnet		*ifp;
    737   1.17.2.2  nathanw 	u_int16_t		status;
    738   1.17.2.2  nathanw 
    739   1.17.2.2  nathanw 	if (sc->sc_enabled == 0 ||
    740   1.17.2.2  nathanw 	    (sc->sc_dev.dv_flags & DVF_ACTIVE) == 0 ||
    741   1.17.2.2  nathanw 	    (sc->sc_ethercom.ec_if.if_flags & IFF_RUNNING) == 0)
    742   1.17.2.2  nathanw 		return (0);
    743   1.17.2.2  nathanw 
    744   1.17.2.2  nathanw 	ifp = &sc->sc_ethercom.ec_if;
    745   1.17.2.2  nathanw 
    746   1.17.2.2  nathanw 	if (!(ifp->if_flags & IFF_UP)) {
    747   1.17.2.2  nathanw 		CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
    748   1.17.2.2  nathanw 		CSR_WRITE_2(sc, WI_INT_EN, 0);
    749   1.17.2.2  nathanw 		return 1;
    750   1.17.2.2  nathanw 	}
    751   1.17.2.2  nathanw 
    752   1.17.2.2  nathanw 	/* Disable interrupts. */
    753   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_INT_EN, 0);
    754   1.17.2.2  nathanw 
    755   1.17.2.2  nathanw 	status = CSR_READ_2(sc, WI_EVENT_STAT);
    756   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_EVENT_ACK, ~WI_INTRS);
    757   1.17.2.2  nathanw 
    758   1.17.2.2  nathanw 	if (status & WI_EV_RX) {
    759   1.17.2.2  nathanw 		wi_rxeof(sc);
    760   1.17.2.2  nathanw 		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
    761   1.17.2.2  nathanw 	}
    762   1.17.2.2  nathanw 
    763   1.17.2.2  nathanw 	if (status & WI_EV_TX) {
    764   1.17.2.2  nathanw 		wi_txeof(sc, status);
    765   1.17.2.2  nathanw 		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX);
    766   1.17.2.2  nathanw 	}
    767   1.17.2.2  nathanw 
    768   1.17.2.2  nathanw 	if (status & WI_EV_ALLOC) {
    769   1.17.2.2  nathanw 		int			id;
    770   1.17.2.2  nathanw 		id = CSR_READ_2(sc, WI_ALLOC_FID);
    771   1.17.2.2  nathanw 		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
    772   1.17.2.2  nathanw 		if (id == sc->wi_tx_data_id)
    773   1.17.2.2  nathanw 			wi_txeof(sc, status);
    774   1.17.2.2  nathanw 	}
    775   1.17.2.2  nathanw 
    776   1.17.2.2  nathanw 	if (status & WI_EV_INFO) {
    777   1.17.2.2  nathanw 		wi_update_stats(sc);
    778   1.17.2.2  nathanw 		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO);
    779   1.17.2.2  nathanw 	}
    780   1.17.2.2  nathanw 
    781   1.17.2.2  nathanw 	if (status & WI_EV_TX_EXC) {
    782   1.17.2.2  nathanw 		wi_txeof(sc, status);
    783   1.17.2.2  nathanw 		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX_EXC);
    784   1.17.2.2  nathanw 	}
    785   1.17.2.2  nathanw 
    786   1.17.2.2  nathanw 	if (status & WI_EV_INFO_DROP) {
    787   1.17.2.2  nathanw 		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO_DROP);
    788   1.17.2.2  nathanw 	}
    789   1.17.2.2  nathanw 
    790   1.17.2.2  nathanw 	/* Re-enable interrupts. */
    791   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
    792   1.17.2.2  nathanw 
    793   1.17.2.2  nathanw 	if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
    794   1.17.2.2  nathanw 		wi_start(ifp);
    795   1.17.2.2  nathanw 
    796   1.17.2.2  nathanw 	return 1;
    797   1.17.2.2  nathanw }
    798   1.17.2.2  nathanw 
    799  1.17.2.10  nathanw /* Must be called at proper protection level! */
    800   1.17.2.2  nathanw static int
    801   1.17.2.2  nathanw wi_cmd(sc, cmd, val)
    802   1.17.2.2  nathanw 	struct wi_softc		*sc;
    803   1.17.2.2  nathanw 	int			cmd;
    804   1.17.2.2  nathanw 	int			val;
    805   1.17.2.2  nathanw {
    806   1.17.2.2  nathanw 	int			i, s = 0;
    807   1.17.2.2  nathanw 
    808   1.17.2.2  nathanw 	/* wait for the busy bit to clear */
    809   1.17.2.2  nathanw 	for (i = 0; i < WI_TIMEOUT; i++) {
    810   1.17.2.2  nathanw 		if (!(CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY))
    811   1.17.2.2  nathanw 			break;
    812   1.17.2.2  nathanw 	}
    813   1.17.2.2  nathanw 
    814  1.17.2.10  nathanw 	if (i == WI_TIMEOUT) {
    815  1.17.2.10  nathanw 		printf("%s: wi_cmd: BUSY did not clear, cmd=0x%x\n",
    816  1.17.2.10  nathanw 			sc->sc_dev.dv_xname, cmd);
    817  1.17.2.10  nathanw 		return EIO;
    818  1.17.2.10  nathanw 	}
    819  1.17.2.10  nathanw 
    820   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_PARAM0, val);
    821   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_PARAM1, 0);
    822   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_PARAM2, 0);
    823   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_COMMAND, cmd);
    824   1.17.2.2  nathanw 
    825   1.17.2.2  nathanw 	/* wait for the cmd completed bit */
    826   1.17.2.2  nathanw 	for (i = 0; i < WI_TIMEOUT; i++) {
    827   1.17.2.2  nathanw 		if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_CMD)
    828   1.17.2.2  nathanw 			break;
    829   1.17.2.2  nathanw 		DELAY(1);
    830   1.17.2.2  nathanw 	}
    831   1.17.2.2  nathanw 
    832   1.17.2.2  nathanw 	/* Ack the command */
    833   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD);
    834   1.17.2.2  nathanw 
    835   1.17.2.2  nathanw 	s = CSR_READ_2(sc, WI_STATUS);
    836   1.17.2.2  nathanw 	if (s & WI_STAT_CMD_RESULT)
    837   1.17.2.2  nathanw 		return(EIO);
    838   1.17.2.2  nathanw 
    839  1.17.2.10  nathanw 	if (i == WI_TIMEOUT) {
    840  1.17.2.10  nathanw 		if (!sc->wi_scanning)
    841  1.17.2.10  nathanw 		    printf("%s: command timed out, cmd=0x%x\n",
    842  1.17.2.10  nathanw 			sc->sc_dev.dv_xname, cmd);
    843   1.17.2.2  nathanw 		return(ETIMEDOUT);
    844  1.17.2.10  nathanw 	}
    845   1.17.2.2  nathanw 
    846   1.17.2.2  nathanw 	return(0);
    847   1.17.2.2  nathanw }
    848   1.17.2.2  nathanw 
    849   1.17.2.2  nathanw static void
    850   1.17.2.2  nathanw wi_reset(sc)
    851   1.17.2.2  nathanw 	struct wi_softc		*sc;
    852   1.17.2.2  nathanw {
    853  1.17.2.11  nathanw 
    854   1.17.2.2  nathanw 	DELAY(100*1000); /* 100 m sec */
    855   1.17.2.2  nathanw 	if (wi_cmd(sc, WI_CMD_INI, 0))
    856   1.17.2.2  nathanw 		printf("%s: init failed\n", sc->sc_dev.dv_xname);
    857   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_INT_EN, 0);
    858   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
    859   1.17.2.2  nathanw 
    860   1.17.2.2  nathanw 	/* Calibrate timer. */
    861   1.17.2.2  nathanw 	WI_SETVAL(WI_RID_TICK_TIME, 8);
    862   1.17.2.2  nathanw 
    863   1.17.2.2  nathanw 	return;
    864   1.17.2.2  nathanw }
    865   1.17.2.2  nathanw 
    866   1.17.2.2  nathanw /*
    867   1.17.2.2  nathanw  * Read an LTV record from the NIC.
    868   1.17.2.2  nathanw  */
    869   1.17.2.2  nathanw static int wi_read_record(sc, ltv)
    870   1.17.2.2  nathanw 	struct wi_softc		*sc;
    871   1.17.2.2  nathanw 	struct wi_ltv_gen	*ltv;
    872   1.17.2.2  nathanw {
    873   1.17.2.2  nathanw 	u_int16_t		*ptr;
    874   1.17.2.2  nathanw 	int			len, code;
    875   1.17.2.2  nathanw 	struct wi_ltv_gen	*oltv, p2ltv;
    876   1.17.2.2  nathanw 
    877  1.17.2.11  nathanw 	if (sc->sc_firmware_type != WI_LUCENT) {
    878   1.17.2.2  nathanw 		oltv = ltv;
    879   1.17.2.2  nathanw 		switch (ltv->wi_type) {
    880   1.17.2.2  nathanw 		case WI_RID_ENCRYPTION:
    881   1.17.2.2  nathanw 			p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
    882   1.17.2.2  nathanw 			p2ltv.wi_len = 2;
    883   1.17.2.2  nathanw 			ltv = &p2ltv;
    884   1.17.2.2  nathanw 			break;
    885   1.17.2.2  nathanw 		case WI_RID_TX_CRYPT_KEY:
    886   1.17.2.2  nathanw 			p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
    887   1.17.2.2  nathanw 			p2ltv.wi_len = 2;
    888   1.17.2.2  nathanw 			ltv = &p2ltv;
    889   1.17.2.2  nathanw 			break;
    890  1.17.2.12  nathanw 		case WI_RID_ROAMING_MODE:
    891  1.17.2.12  nathanw 			if (sc->sc_firmware_type == WI_INTERSIL)
    892  1.17.2.12  nathanw 				break;
    893  1.17.2.12  nathanw 			/* not supported */
    894  1.17.2.12  nathanw 			ltv->wi_len = 1;
    895  1.17.2.12  nathanw 			return 0;
    896  1.17.2.12  nathanw 		case WI_RID_MICROWAVE_OVEN:
    897  1.17.2.12  nathanw 			/* not supported */
    898  1.17.2.12  nathanw 			ltv->wi_len = 1;
    899  1.17.2.12  nathanw 			return 0;
    900   1.17.2.2  nathanw 		}
    901   1.17.2.2  nathanw 	}
    902   1.17.2.2  nathanw 
    903   1.17.2.2  nathanw 	/* Tell the NIC to enter record read mode. */
    904   1.17.2.2  nathanw 	if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_READ, ltv->wi_type))
    905   1.17.2.2  nathanw 		return(EIO);
    906   1.17.2.2  nathanw 
    907   1.17.2.2  nathanw 	/* Seek to the record. */
    908   1.17.2.2  nathanw 	if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1))
    909   1.17.2.2  nathanw 		return(EIO);
    910   1.17.2.2  nathanw 
    911   1.17.2.2  nathanw 	/*
    912   1.17.2.2  nathanw 	 * Read the length and record type and make sure they
    913   1.17.2.2  nathanw 	 * match what we expect (this verifies that we have enough
    914   1.17.2.2  nathanw 	 * room to hold all of the returned data).
    915   1.17.2.2  nathanw 	 */
    916   1.17.2.2  nathanw 	len = CSR_READ_2(sc, WI_DATA1);
    917   1.17.2.2  nathanw 	if (len > ltv->wi_len)
    918   1.17.2.2  nathanw 		return(ENOSPC);
    919   1.17.2.2  nathanw 	code = CSR_READ_2(sc, WI_DATA1);
    920   1.17.2.2  nathanw 	if (code != ltv->wi_type)
    921   1.17.2.2  nathanw 		return(EIO);
    922   1.17.2.2  nathanw 
    923   1.17.2.2  nathanw 	ltv->wi_len = len;
    924   1.17.2.2  nathanw 	ltv->wi_type = code;
    925   1.17.2.2  nathanw 
    926   1.17.2.2  nathanw 	/* Now read the data. */
    927   1.17.2.2  nathanw 	ptr = &ltv->wi_val;
    928   1.17.2.2  nathanw 	if (ltv->wi_len > 1)
    929   1.17.2.2  nathanw 		CSR_READ_MULTI_STREAM_2(sc, WI_DATA1, ptr, ltv->wi_len - 1);
    930   1.17.2.2  nathanw 
    931  1.17.2.11  nathanw 	if (sc->sc_firmware_type != WI_LUCENT) {
    932   1.17.2.2  nathanw 		int v;
    933   1.17.2.2  nathanw 
    934   1.17.2.2  nathanw 		switch (oltv->wi_type) {
    935   1.17.2.2  nathanw 		case WI_RID_TX_RATE:
    936   1.17.2.2  nathanw 		case WI_RID_CUR_TX_RATE:
    937   1.17.2.2  nathanw 			switch (le16toh(ltv->wi_val)) {
    938   1.17.2.2  nathanw 			case 1: v = 1; break;
    939   1.17.2.2  nathanw 			case 2: v = 2; break;
    940   1.17.2.2  nathanw 			case 3:	v = 6; break;
    941   1.17.2.2  nathanw 			case 4: v = 5; break;
    942   1.17.2.2  nathanw 			case 7: v = 7; break;
    943   1.17.2.2  nathanw 			case 8: v = 11; break;
    944   1.17.2.2  nathanw 			case 15: v = 3; break;
    945   1.17.2.2  nathanw 			default: v = 0x100 + le16toh(ltv->wi_val); break;
    946   1.17.2.2  nathanw 			}
    947   1.17.2.2  nathanw 			oltv->wi_val = htole16(v);
    948   1.17.2.2  nathanw 			break;
    949   1.17.2.2  nathanw 		case WI_RID_ENCRYPTION:
    950   1.17.2.2  nathanw 			oltv->wi_len = 2;
    951   1.17.2.2  nathanw 			if (le16toh(ltv->wi_val) & 0x01)
    952   1.17.2.2  nathanw 				oltv->wi_val = htole16(1);
    953   1.17.2.2  nathanw 			else
    954   1.17.2.2  nathanw 				oltv->wi_val = htole16(0);
    955   1.17.2.2  nathanw 			break;
    956   1.17.2.2  nathanw 		case WI_RID_TX_CRYPT_KEY:
    957   1.17.2.2  nathanw 			oltv->wi_len = 2;
    958   1.17.2.2  nathanw 			oltv->wi_val = ltv->wi_val;
    959   1.17.2.2  nathanw 			break;
    960   1.17.2.2  nathanw 		case WI_RID_AUTH_CNTL:
    961   1.17.2.2  nathanw 			oltv->wi_len = 2;
    962   1.17.2.2  nathanw 			if (le16toh(ltv->wi_val) & 0x01)
    963   1.17.2.2  nathanw 				oltv->wi_val = htole16(1);
    964   1.17.2.2  nathanw 			else if (le16toh(ltv->wi_val) & 0x02)
    965   1.17.2.2  nathanw 				oltv->wi_val = htole16(2);
    966   1.17.2.2  nathanw 			break;
    967   1.17.2.2  nathanw 		}
    968   1.17.2.2  nathanw 	}
    969   1.17.2.2  nathanw 
    970   1.17.2.2  nathanw 	return(0);
    971   1.17.2.2  nathanw }
    972   1.17.2.2  nathanw 
    973   1.17.2.2  nathanw /*
    974   1.17.2.2  nathanw  * Same as read, except we inject data instead of reading it.
    975   1.17.2.2  nathanw  */
    976   1.17.2.2  nathanw static int wi_write_record(sc, ltv)
    977   1.17.2.2  nathanw 	struct wi_softc		*sc;
    978   1.17.2.2  nathanw 	struct wi_ltv_gen	*ltv;
    979   1.17.2.2  nathanw {
    980   1.17.2.2  nathanw 	u_int16_t		*ptr;
    981   1.17.2.2  nathanw 	int			i;
    982   1.17.2.2  nathanw 	struct wi_ltv_gen	p2ltv;
    983   1.17.2.2  nathanw 
    984  1.17.2.11  nathanw 	if (sc->sc_firmware_type != WI_LUCENT) {
    985   1.17.2.2  nathanw 		int v;
    986   1.17.2.2  nathanw 
    987   1.17.2.2  nathanw 		switch (ltv->wi_type) {
    988   1.17.2.2  nathanw 		case WI_RID_TX_RATE:
    989   1.17.2.2  nathanw 			p2ltv.wi_type = WI_RID_TX_RATE;
    990   1.17.2.2  nathanw 			p2ltv.wi_len = 2;
    991   1.17.2.2  nathanw 			switch (le16toh(ltv->wi_val)) {
    992   1.17.2.2  nathanw 			case 1: v = 1; break;
    993   1.17.2.2  nathanw 			case 2: v = 2; break;
    994   1.17.2.2  nathanw 			case 3:	v = 15; break;
    995   1.17.2.2  nathanw 			case 5: v = 4; break;
    996   1.17.2.2  nathanw 			case 6: v = 3; break;
    997   1.17.2.2  nathanw 			case 7: v = 7; break;
    998   1.17.2.2  nathanw 			case 11: v = 8; break;
    999   1.17.2.2  nathanw 			default: return EINVAL;
   1000   1.17.2.2  nathanw 			}
   1001   1.17.2.2  nathanw 			p2ltv.wi_val = htole16(v);
   1002   1.17.2.2  nathanw 			ltv = &p2ltv;
   1003   1.17.2.2  nathanw 			break;
   1004   1.17.2.2  nathanw 		case WI_RID_ENCRYPTION:
   1005   1.17.2.2  nathanw 			p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
   1006   1.17.2.2  nathanw 			p2ltv.wi_len = 2;
   1007   1.17.2.2  nathanw 			if (le16toh(ltv->wi_val))
   1008  1.17.2.12  nathanw 				p2ltv.wi_val = htole16(PRIVACY_INVOKED |
   1009  1.17.2.12  nathanw 						       EXCLUDE_UNENCRYPTED);
   1010   1.17.2.2  nathanw 			else
   1011  1.17.2.12  nathanw 				p2ltv.wi_val =
   1012  1.17.2.12  nathanw 				    htole16(HOST_ENCRYPT | HOST_DECRYPT);
   1013   1.17.2.2  nathanw 			ltv = &p2ltv;
   1014   1.17.2.2  nathanw 			break;
   1015   1.17.2.2  nathanw 		case WI_RID_TX_CRYPT_KEY:
   1016   1.17.2.2  nathanw 			p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
   1017   1.17.2.2  nathanw 			p2ltv.wi_len = 2;
   1018   1.17.2.2  nathanw 			p2ltv.wi_val = ltv->wi_val;
   1019   1.17.2.2  nathanw 			ltv = &p2ltv;
   1020   1.17.2.2  nathanw 			break;
   1021   1.17.2.2  nathanw 		case WI_RID_DEFLT_CRYPT_KEYS:
   1022   1.17.2.2  nathanw 		    {
   1023   1.17.2.2  nathanw 			int error;
   1024  1.17.2.11  nathanw 			int keylen;
   1025   1.17.2.2  nathanw 			struct wi_ltv_str	ws;
   1026   1.17.2.2  nathanw 			struct wi_ltv_keys	*wk = (struct wi_ltv_keys *)ltv;
   1027  1.17.2.11  nathanw 
   1028  1.17.2.11  nathanw 			keylen = wk->wi_keys[sc->wi_tx_key].wi_keylen;
   1029  1.17.2.11  nathanw 
   1030   1.17.2.2  nathanw 			for (i = 0; i < 4; i++) {
   1031  1.17.2.10  nathanw 				memset(&ws, 0, sizeof(ws));
   1032  1.17.2.11  nathanw 				ws.wi_len = (keylen > 5) ? 8 : 4;
   1033   1.17.2.2  nathanw 				ws.wi_type = WI_RID_P2_CRYPT_KEY0 + i;
   1034  1.17.2.11  nathanw 				memcpy(ws.wi_str,
   1035  1.17.2.11  nathanw 					&wk->wi_keys[i].wi_keydat, keylen);
   1036  1.17.2.11  nathanw 				error = wi_write_record(sc,
   1037  1.17.2.11  nathanw 					(struct wi_ltv_gen *)&ws);
   1038  1.17.2.11  nathanw 				if (error)
   1039   1.17.2.2  nathanw 					return error;
   1040   1.17.2.2  nathanw 			}
   1041   1.17.2.2  nathanw 			return 0;
   1042   1.17.2.2  nathanw 		    }
   1043   1.17.2.2  nathanw 		case WI_RID_AUTH_CNTL:
   1044   1.17.2.2  nathanw 			p2ltv.wi_type = WI_RID_AUTH_CNTL;
   1045   1.17.2.2  nathanw 			p2ltv.wi_len = 2;
   1046   1.17.2.2  nathanw 			if (le16toh(ltv->wi_val) == 1)
   1047   1.17.2.2  nathanw 				p2ltv.wi_val = htole16(0x01);
   1048   1.17.2.2  nathanw 			else if (le16toh(ltv->wi_val) == 2)
   1049   1.17.2.2  nathanw 				p2ltv.wi_val = htole16(0x02);
   1050   1.17.2.2  nathanw 			ltv = &p2ltv;
   1051   1.17.2.2  nathanw 			break;
   1052  1.17.2.12  nathanw 
   1053  1.17.2.12  nathanw 		case WI_RID_ROAMING_MODE:
   1054  1.17.2.12  nathanw 			if (sc->sc_firmware_type == WI_INTERSIL)
   1055  1.17.2.12  nathanw 				break;
   1056  1.17.2.12  nathanw 			/* not supported */
   1057  1.17.2.12  nathanw 			return 0;
   1058  1.17.2.12  nathanw 
   1059  1.17.2.12  nathanw 		case WI_RID_MICROWAVE_OVEN:
   1060  1.17.2.12  nathanw 			/* not supported */
   1061  1.17.2.12  nathanw 			return 0;
   1062   1.17.2.2  nathanw 		}
   1063   1.17.2.2  nathanw 	}
   1064   1.17.2.2  nathanw 
   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 	CSR_WRITE_2(sc, WI_DATA1, ltv->wi_len);
   1069   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_DATA1, ltv->wi_type);
   1070   1.17.2.2  nathanw 
   1071   1.17.2.2  nathanw 	/* Write data */
   1072   1.17.2.2  nathanw 	ptr = &ltv->wi_val;
   1073   1.17.2.2  nathanw 	if (ltv->wi_len > 1)
   1074   1.17.2.2  nathanw 		CSR_WRITE_MULTI_STREAM_2(sc, WI_DATA1, ptr, ltv->wi_len - 1);
   1075   1.17.2.2  nathanw 
   1076   1.17.2.2  nathanw 	if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_WRITE, ltv->wi_type))
   1077   1.17.2.2  nathanw 		return(EIO);
   1078   1.17.2.2  nathanw 
   1079   1.17.2.2  nathanw 	return(0);
   1080   1.17.2.2  nathanw }
   1081   1.17.2.2  nathanw 
   1082   1.17.2.2  nathanw static int wi_seek(sc, id, off, chan)
   1083   1.17.2.2  nathanw 	struct wi_softc		*sc;
   1084   1.17.2.2  nathanw 	int			id, off, chan;
   1085   1.17.2.2  nathanw {
   1086   1.17.2.2  nathanw 	int			i;
   1087   1.17.2.2  nathanw 	int			selreg, offreg;
   1088   1.17.2.2  nathanw 	int 			status;
   1089   1.17.2.2  nathanw 
   1090   1.17.2.2  nathanw 	switch (chan) {
   1091   1.17.2.2  nathanw 	case WI_BAP0:
   1092   1.17.2.2  nathanw 		selreg = WI_SEL0;
   1093   1.17.2.2  nathanw 		offreg = WI_OFF0;
   1094   1.17.2.2  nathanw 		break;
   1095   1.17.2.2  nathanw 	case WI_BAP1:
   1096   1.17.2.2  nathanw 		selreg = WI_SEL1;
   1097   1.17.2.2  nathanw 		offreg = WI_OFF1;
   1098   1.17.2.2  nathanw 		break;
   1099   1.17.2.2  nathanw 	default:
   1100   1.17.2.2  nathanw 		printf("%s: invalid data path: %x\n",
   1101   1.17.2.2  nathanw 		    sc->sc_dev.dv_xname, chan);
   1102   1.17.2.2  nathanw 		return(EIO);
   1103   1.17.2.2  nathanw 	}
   1104   1.17.2.2  nathanw 
   1105   1.17.2.2  nathanw 	CSR_WRITE_2(sc, selreg, id);
   1106   1.17.2.2  nathanw 	CSR_WRITE_2(sc, offreg, off);
   1107   1.17.2.2  nathanw 
   1108   1.17.2.2  nathanw 	for (i = 0; i < WI_TIMEOUT; i++) {
   1109   1.17.2.2  nathanw 	  	status = CSR_READ_2(sc, offreg);
   1110   1.17.2.2  nathanw 		if (!(status & (WI_OFF_BUSY|WI_OFF_ERR)))
   1111   1.17.2.2  nathanw 			break;
   1112   1.17.2.2  nathanw 	}
   1113   1.17.2.2  nathanw 
   1114   1.17.2.2  nathanw 	if (i == WI_TIMEOUT) {
   1115   1.17.2.2  nathanw 		printf("%s: timeout in wi_seek to %x/%x; last status %x\n",
   1116   1.17.2.2  nathanw 		       sc->sc_dev.dv_xname, id, off, status);
   1117   1.17.2.2  nathanw 		return(ETIMEDOUT);
   1118   1.17.2.2  nathanw 	}
   1119   1.17.2.2  nathanw 	return(0);
   1120   1.17.2.2  nathanw }
   1121   1.17.2.2  nathanw 
   1122   1.17.2.2  nathanw static int wi_read_data(sc, id, off, buf, len)
   1123   1.17.2.2  nathanw 	struct wi_softc		*sc;
   1124   1.17.2.2  nathanw 	int			id, off;
   1125   1.17.2.2  nathanw 	caddr_t			buf;
   1126   1.17.2.2  nathanw 	int			len;
   1127   1.17.2.2  nathanw {
   1128   1.17.2.2  nathanw 	u_int16_t		*ptr;
   1129   1.17.2.2  nathanw 
   1130   1.17.2.2  nathanw 	if (wi_seek(sc, id, off, WI_BAP1))
   1131   1.17.2.2  nathanw 		return(EIO);
   1132   1.17.2.2  nathanw 
   1133   1.17.2.2  nathanw 	ptr = (u_int16_t *)buf;
   1134   1.17.2.2  nathanw 	CSR_READ_MULTI_STREAM_2(sc, WI_DATA1, ptr, len / 2);
   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  * According to the comments in the HCF Light code, there is a bug in
   1141   1.17.2.2  nathanw  * the Hermes (or possibly in certain Hermes firmware revisions) where
   1142   1.17.2.2  nathanw  * the chip's internal autoincrement counter gets thrown off during
   1143   1.17.2.2  nathanw  * data writes: the autoincrement is missed, causing one data word to
   1144   1.17.2.2  nathanw  * be overwritten and subsequent words to be written to the wrong memory
   1145   1.17.2.2  nathanw  * locations. The end result is that we could end up transmitting bogus
   1146   1.17.2.2  nathanw  * frames without realizing it. The workaround for this is to write a
   1147   1.17.2.2  nathanw  * couple of extra guard words after the end of the transfer, then
   1148   1.17.2.2  nathanw  * attempt to read then back. If we fail to locate the guard words where
   1149   1.17.2.2  nathanw  * we expect them, we preform the transfer over again.
   1150   1.17.2.2  nathanw  */
   1151   1.17.2.2  nathanw static int wi_write_data(sc, id, off, buf, len)
   1152   1.17.2.2  nathanw 	struct wi_softc		*sc;
   1153   1.17.2.2  nathanw 	int			id, off;
   1154   1.17.2.2  nathanw 	caddr_t			buf;
   1155   1.17.2.2  nathanw 	int			len;
   1156   1.17.2.2  nathanw {
   1157   1.17.2.2  nathanw 	u_int16_t		*ptr;
   1158   1.17.2.2  nathanw 
   1159   1.17.2.2  nathanw #ifdef WI_HERMES_AUTOINC_WAR
   1160   1.17.2.2  nathanw again:
   1161   1.17.2.2  nathanw #endif
   1162   1.17.2.2  nathanw 
   1163   1.17.2.2  nathanw 	if (wi_seek(sc, id, off, WI_BAP0))
   1164   1.17.2.2  nathanw 		return(EIO);
   1165   1.17.2.2  nathanw 
   1166   1.17.2.2  nathanw 	ptr = (u_int16_t *)buf;
   1167   1.17.2.2  nathanw 	CSR_WRITE_MULTI_STREAM_2(sc, WI_DATA0, ptr, len / 2);
   1168   1.17.2.2  nathanw 
   1169   1.17.2.2  nathanw #ifdef WI_HERMES_AUTOINC_WAR
   1170   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_DATA0, 0x1234);
   1171   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_DATA0, 0x5678);
   1172   1.17.2.2  nathanw 
   1173   1.17.2.2  nathanw 	if (wi_seek(sc, id, off + len, WI_BAP0))
   1174   1.17.2.2  nathanw 		return(EIO);
   1175   1.17.2.2  nathanw 
   1176   1.17.2.2  nathanw 	if (CSR_READ_2(sc, WI_DATA0) != 0x1234 ||
   1177   1.17.2.2  nathanw 	    CSR_READ_2(sc, WI_DATA0) != 0x5678)
   1178   1.17.2.2  nathanw 		goto again;
   1179   1.17.2.2  nathanw #endif
   1180   1.17.2.2  nathanw 
   1181   1.17.2.2  nathanw 	return(0);
   1182   1.17.2.2  nathanw }
   1183   1.17.2.2  nathanw 
   1184   1.17.2.2  nathanw /*
   1185   1.17.2.2  nathanw  * Allocate a region of memory inside the NIC and zero
   1186   1.17.2.2  nathanw  * it out.
   1187   1.17.2.2  nathanw  */
   1188   1.17.2.2  nathanw static int wi_alloc_nicmem(sc, len, id)
   1189   1.17.2.2  nathanw 	struct wi_softc		*sc;
   1190   1.17.2.2  nathanw 	int			len;
   1191   1.17.2.2  nathanw 	int			*id;
   1192   1.17.2.2  nathanw {
   1193   1.17.2.2  nathanw 	int			i;
   1194   1.17.2.2  nathanw 
   1195   1.17.2.2  nathanw 	if (wi_cmd(sc, WI_CMD_ALLOC_MEM, len)) {
   1196   1.17.2.2  nathanw 		printf("%s: failed to allocate %d bytes on NIC\n",
   1197   1.17.2.2  nathanw 		    sc->sc_dev.dv_xname, len);
   1198   1.17.2.2  nathanw 		return(ENOMEM);
   1199   1.17.2.2  nathanw 	}
   1200   1.17.2.2  nathanw 
   1201   1.17.2.2  nathanw 	for (i = 0; i < WI_TIMEOUT; i++) {
   1202   1.17.2.2  nathanw 		if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_ALLOC)
   1203   1.17.2.2  nathanw 			break;
   1204   1.17.2.2  nathanw 	}
   1205   1.17.2.2  nathanw 
   1206   1.17.2.2  nathanw 	if (i == WI_TIMEOUT) {
   1207   1.17.2.2  nathanw 		printf("%s: TIMED OUT in alloc\n", sc->sc_dev.dv_xname);
   1208   1.17.2.2  nathanw 		return(ETIMEDOUT);
   1209   1.17.2.2  nathanw 	}
   1210   1.17.2.2  nathanw 
   1211   1.17.2.2  nathanw 	*id = CSR_READ_2(sc, WI_ALLOC_FID);
   1212  1.17.2.11  nathanw 	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
   1213   1.17.2.2  nathanw 
   1214   1.17.2.2  nathanw 	if (wi_seek(sc, *id, 0, WI_BAP0)) {
   1215   1.17.2.2  nathanw 		printf("%s: seek failed in alloc\n", sc->sc_dev.dv_xname);
   1216   1.17.2.2  nathanw 		return(EIO);
   1217   1.17.2.2  nathanw 	}
   1218   1.17.2.2  nathanw 
   1219   1.17.2.2  nathanw 	for (i = 0; i < len / 2; i++)
   1220   1.17.2.2  nathanw 		CSR_WRITE_2(sc, WI_DATA0, 0);
   1221   1.17.2.2  nathanw 
   1222   1.17.2.2  nathanw 	return(0);
   1223   1.17.2.2  nathanw }
   1224   1.17.2.2  nathanw 
   1225   1.17.2.2  nathanw static void wi_setmulti(sc)
   1226   1.17.2.2  nathanw 	struct wi_softc		*sc;
   1227   1.17.2.2  nathanw {
   1228   1.17.2.2  nathanw 	struct ifnet		*ifp;
   1229   1.17.2.2  nathanw 	int			i = 0;
   1230   1.17.2.2  nathanw 	struct wi_ltv_mcast	mcast;
   1231   1.17.2.2  nathanw 	struct ether_multi *enm;
   1232   1.17.2.2  nathanw 	struct ether_multistep estep;
   1233   1.17.2.2  nathanw 	struct ethercom *ec = &sc->sc_ethercom;
   1234   1.17.2.2  nathanw 
   1235   1.17.2.2  nathanw 	ifp = &sc->sc_ethercom.ec_if;
   1236   1.17.2.2  nathanw 
   1237   1.17.2.2  nathanw 	if ((ifp->if_flags & IFF_PROMISC) != 0) {
   1238   1.17.2.2  nathanw allmulti:
   1239   1.17.2.2  nathanw 		ifp->if_flags |= IFF_ALLMULTI;
   1240   1.17.2.3  nathanw 		memset((char *)&mcast, 0, sizeof(mcast));
   1241   1.17.2.8  nathanw 		mcast.wi_type = WI_RID_MCAST_LIST;
   1242   1.17.2.2  nathanw 		mcast.wi_len = ((ETHER_ADDR_LEN / 2) * 16) + 1;
   1243   1.17.2.2  nathanw 
   1244   1.17.2.2  nathanw 		wi_write_record(sc, (struct wi_ltv_gen *)&mcast);
   1245   1.17.2.2  nathanw 		return;
   1246   1.17.2.2  nathanw 	}
   1247   1.17.2.2  nathanw 
   1248   1.17.2.2  nathanw 	i = 0;
   1249   1.17.2.2  nathanw 	ETHER_FIRST_MULTI(estep, ec, enm);
   1250   1.17.2.2  nathanw 	while (enm != NULL) {
   1251   1.17.2.2  nathanw 		/* Punt on ranges or too many multicast addresses. */
   1252   1.17.2.3  nathanw 		if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
   1253   1.17.2.2  nathanw 		    ETHER_ADDR_LEN) != 0 ||
   1254   1.17.2.2  nathanw 		    i >= 16)
   1255   1.17.2.2  nathanw 			goto allmulti;
   1256   1.17.2.2  nathanw 
   1257   1.17.2.3  nathanw 		memcpy((char *)&mcast.wi_mcast[i], enm->enm_addrlo,
   1258   1.17.2.3  nathanw 		    ETHER_ADDR_LEN);
   1259   1.17.2.2  nathanw 		i++;
   1260   1.17.2.2  nathanw 		ETHER_NEXT_MULTI(estep, enm);
   1261   1.17.2.2  nathanw 	}
   1262   1.17.2.2  nathanw 
   1263   1.17.2.2  nathanw 	ifp->if_flags &= ~IFF_ALLMULTI;
   1264   1.17.2.8  nathanw 	mcast.wi_type = WI_RID_MCAST_LIST;
   1265   1.17.2.2  nathanw 	mcast.wi_len = ((ETHER_ADDR_LEN / 2) * i) + 1;
   1266   1.17.2.2  nathanw 	wi_write_record(sc, (struct wi_ltv_gen *)&mcast);
   1267   1.17.2.2  nathanw }
   1268   1.17.2.2  nathanw 
   1269   1.17.2.2  nathanw static int
   1270   1.17.2.2  nathanw wi_setdef(sc, wreq)
   1271   1.17.2.2  nathanw 	struct wi_softc		*sc;
   1272   1.17.2.2  nathanw 	struct wi_req		*wreq;
   1273   1.17.2.2  nathanw {
   1274   1.17.2.2  nathanw 	struct sockaddr_dl	*sdl;
   1275   1.17.2.2  nathanw 	struct ifnet		*ifp;
   1276   1.17.2.2  nathanw 	int error = 0;
   1277   1.17.2.2  nathanw 
   1278   1.17.2.2  nathanw 	ifp = &sc->sc_ethercom.ec_if;
   1279   1.17.2.2  nathanw 
   1280   1.17.2.2  nathanw 	switch(wreq->wi_type) {
   1281   1.17.2.2  nathanw 	case WI_RID_MAC_NODE:
   1282   1.17.2.2  nathanw 		sdl = (struct sockaddr_dl *)ifp->if_sadl;
   1283   1.17.2.3  nathanw 		memcpy((char *)&sc->sc_macaddr, (char *)&wreq->wi_val,
   1284   1.17.2.2  nathanw 		    ETHER_ADDR_LEN);
   1285   1.17.2.3  nathanw 		memcpy(LLADDR(sdl), (char *)&wreq->wi_val, ETHER_ADDR_LEN);
   1286   1.17.2.2  nathanw 		break;
   1287   1.17.2.2  nathanw 	case WI_RID_PORTTYPE:
   1288   1.17.2.2  nathanw 		error = wi_sync_media(sc, le16toh(wreq->wi_val[0]), sc->wi_tx_rate);
   1289   1.17.2.2  nathanw 		break;
   1290   1.17.2.2  nathanw 	case WI_RID_TX_RATE:
   1291   1.17.2.2  nathanw 		error = wi_sync_media(sc, sc->wi_ptype, le16toh(wreq->wi_val[0]));
   1292   1.17.2.2  nathanw 		break;
   1293   1.17.2.2  nathanw 	case WI_RID_MAX_DATALEN:
   1294   1.17.2.2  nathanw 		sc->wi_max_data_len = le16toh(wreq->wi_val[0]);
   1295   1.17.2.2  nathanw 		break;
   1296   1.17.2.2  nathanw 	case WI_RID_RTS_THRESH:
   1297   1.17.2.2  nathanw 		sc->wi_rts_thresh = le16toh(wreq->wi_val[0]);
   1298   1.17.2.2  nathanw 		break;
   1299   1.17.2.2  nathanw 	case WI_RID_SYSTEM_SCALE:
   1300   1.17.2.2  nathanw 		sc->wi_ap_density = le16toh(wreq->wi_val[0]);
   1301   1.17.2.2  nathanw 		break;
   1302   1.17.2.2  nathanw 	case WI_RID_CREATE_IBSS:
   1303  1.17.2.12  nathanw 		if (sc->sc_firmware_type != WI_INTERSIL)
   1304  1.17.2.12  nathanw 			sc->wi_create_ibss = le16toh(wreq->wi_val[0]);
   1305   1.17.2.2  nathanw 		break;
   1306   1.17.2.2  nathanw 	case WI_RID_OWN_CHNL:
   1307   1.17.2.2  nathanw 		sc->wi_channel = le16toh(wreq->wi_val[0]);
   1308   1.17.2.2  nathanw 		break;
   1309   1.17.2.2  nathanw 	case WI_RID_NODENAME:
   1310   1.17.2.2  nathanw 		error = wi_set_ssid(&sc->wi_nodeid,
   1311   1.17.2.2  nathanw 		    (u_int8_t *)&wreq->wi_val[1], le16toh(wreq->wi_val[0]));
   1312   1.17.2.2  nathanw 		break;
   1313   1.17.2.2  nathanw 	case WI_RID_DESIRED_SSID:
   1314   1.17.2.2  nathanw 		error = wi_set_ssid(&sc->wi_netid,
   1315   1.17.2.2  nathanw 		    (u_int8_t *)&wreq->wi_val[1], le16toh(wreq->wi_val[0]));
   1316   1.17.2.2  nathanw 		break;
   1317   1.17.2.2  nathanw 	case WI_RID_OWN_SSID:
   1318   1.17.2.2  nathanw 		error = wi_set_ssid(&sc->wi_ibssid,
   1319   1.17.2.2  nathanw 		    (u_int8_t *)&wreq->wi_val[1], le16toh(wreq->wi_val[0]));
   1320   1.17.2.2  nathanw 		break;
   1321   1.17.2.2  nathanw 	case WI_RID_PM_ENABLED:
   1322   1.17.2.2  nathanw 		sc->wi_pm_enabled = le16toh(wreq->wi_val[0]);
   1323   1.17.2.2  nathanw 		break;
   1324   1.17.2.2  nathanw 	case WI_RID_MICROWAVE_OVEN:
   1325   1.17.2.2  nathanw 		sc->wi_mor_enabled = le16toh(wreq->wi_val[0]);
   1326   1.17.2.2  nathanw 		break;
   1327   1.17.2.2  nathanw 	case WI_RID_MAX_SLEEP:
   1328   1.17.2.2  nathanw 		sc->wi_max_sleep = le16toh(wreq->wi_val[0]);
   1329   1.17.2.2  nathanw 		break;
   1330   1.17.2.2  nathanw 	case WI_RID_AUTH_CNTL:
   1331   1.17.2.2  nathanw 		sc->wi_authtype = le16toh(wreq->wi_val[0]);
   1332   1.17.2.2  nathanw 		break;
   1333   1.17.2.2  nathanw 	case WI_RID_ROAMING_MODE:
   1334   1.17.2.2  nathanw 		sc->wi_roaming = le16toh(wreq->wi_val[0]);
   1335   1.17.2.2  nathanw 		break;
   1336   1.17.2.2  nathanw 	case WI_RID_ENCRYPTION:
   1337   1.17.2.2  nathanw 		sc->wi_use_wep = le16toh(wreq->wi_val[0]);
   1338   1.17.2.2  nathanw 		break;
   1339   1.17.2.2  nathanw 	case WI_RID_TX_CRYPT_KEY:
   1340   1.17.2.2  nathanw 		sc->wi_tx_key = le16toh(wreq->wi_val[0]);
   1341   1.17.2.2  nathanw 		break;
   1342   1.17.2.2  nathanw 	case WI_RID_DEFLT_CRYPT_KEYS:
   1343   1.17.2.3  nathanw 		memcpy((char *)&sc->wi_keys, (char *)wreq,
   1344   1.17.2.2  nathanw 		    sizeof(struct wi_ltv_keys));
   1345   1.17.2.2  nathanw 		break;
   1346   1.17.2.2  nathanw 	default:
   1347   1.17.2.2  nathanw 		error = EINVAL;
   1348   1.17.2.2  nathanw 		break;
   1349   1.17.2.2  nathanw 	}
   1350   1.17.2.2  nathanw 
   1351   1.17.2.2  nathanw 	return (error);
   1352   1.17.2.2  nathanw }
   1353   1.17.2.2  nathanw 
   1354   1.17.2.2  nathanw static int
   1355   1.17.2.2  nathanw wi_getdef(sc, wreq)
   1356   1.17.2.2  nathanw 	struct wi_softc		*sc;
   1357   1.17.2.2  nathanw 	struct wi_req		*wreq;
   1358   1.17.2.2  nathanw {
   1359   1.17.2.2  nathanw 	struct sockaddr_dl	*sdl;
   1360   1.17.2.2  nathanw 	struct ifnet		*ifp;
   1361   1.17.2.2  nathanw 	int error = 0;
   1362   1.17.2.2  nathanw 
   1363   1.17.2.2  nathanw 	ifp = &sc->sc_ethercom.ec_if;
   1364   1.17.2.2  nathanw 
   1365   1.17.2.2  nathanw 	wreq->wi_len = 2;			/* XXX */
   1366   1.17.2.2  nathanw 	switch (wreq->wi_type) {
   1367   1.17.2.2  nathanw 	case WI_RID_MAC_NODE:
   1368   1.17.2.2  nathanw 		wreq->wi_len += ETHER_ADDR_LEN / 2 - 1;
   1369   1.17.2.2  nathanw 		sdl = (struct sockaddr_dl *)ifp->if_sadl;
   1370   1.17.2.3  nathanw 		memcpy(&wreq->wi_val, &sc->sc_macaddr, ETHER_ADDR_LEN);
   1371   1.17.2.3  nathanw 		memcpy(&wreq->wi_val, LLADDR(sdl), ETHER_ADDR_LEN);
   1372   1.17.2.2  nathanw 		break;
   1373   1.17.2.2  nathanw 	case WI_RID_PORTTYPE:
   1374   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_ptype);
   1375   1.17.2.2  nathanw 		break;
   1376   1.17.2.2  nathanw 	case WI_RID_TX_RATE:
   1377   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_tx_rate);
   1378   1.17.2.2  nathanw 		break;
   1379   1.17.2.2  nathanw 	case WI_RID_MAX_DATALEN:
   1380   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_max_data_len);
   1381   1.17.2.2  nathanw 		break;
   1382   1.17.2.2  nathanw 	case WI_RID_RTS_THRESH:
   1383   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_rts_thresh);
   1384   1.17.2.2  nathanw 		break;
   1385   1.17.2.2  nathanw 	case WI_RID_SYSTEM_SCALE:
   1386   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_ap_density);
   1387   1.17.2.2  nathanw 		break;
   1388   1.17.2.2  nathanw 	case WI_RID_CREATE_IBSS:
   1389  1.17.2.12  nathanw 		if (sc->sc_firmware_type != WI_INTERSIL)
   1390  1.17.2.12  nathanw 			wreq->wi_val[0] = htole16(sc->wi_create_ibss);
   1391   1.17.2.2  nathanw 		break;
   1392   1.17.2.2  nathanw 	case WI_RID_OWN_CHNL:
   1393   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_channel);
   1394   1.17.2.2  nathanw 		break;
   1395   1.17.2.2  nathanw 	case WI_RID_NODENAME:
   1396   1.17.2.2  nathanw 		wi_request_fill_ssid(wreq, &sc->wi_nodeid);
   1397   1.17.2.2  nathanw 		break;
   1398   1.17.2.2  nathanw 	case WI_RID_DESIRED_SSID:
   1399   1.17.2.2  nathanw 		wi_request_fill_ssid(wreq, &sc->wi_netid);
   1400   1.17.2.2  nathanw 		break;
   1401   1.17.2.2  nathanw 	case WI_RID_OWN_SSID:
   1402   1.17.2.2  nathanw 		wi_request_fill_ssid(wreq, &sc->wi_ibssid);
   1403   1.17.2.2  nathanw 		break;
   1404   1.17.2.2  nathanw 	case WI_RID_PM_ENABLED:
   1405   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_pm_enabled);
   1406   1.17.2.2  nathanw 		break;
   1407   1.17.2.2  nathanw 	case WI_RID_MICROWAVE_OVEN:
   1408   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_mor_enabled);
   1409   1.17.2.2  nathanw 		break;
   1410   1.17.2.2  nathanw 	case WI_RID_MAX_SLEEP:
   1411   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_max_sleep);
   1412   1.17.2.2  nathanw 		break;
   1413   1.17.2.2  nathanw 	case WI_RID_AUTH_CNTL:
   1414   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_authtype);
   1415   1.17.2.2  nathanw 		break;
   1416   1.17.2.2  nathanw 	case WI_RID_ROAMING_MODE:
   1417   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_roaming);
   1418   1.17.2.2  nathanw 		break;
   1419   1.17.2.2  nathanw 	case WI_RID_WEP_AVAIL:
   1420   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_has_wep);
   1421   1.17.2.2  nathanw 		break;
   1422   1.17.2.2  nathanw 	case WI_RID_ENCRYPTION:
   1423   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_use_wep);
   1424   1.17.2.2  nathanw 		break;
   1425   1.17.2.2  nathanw 	case WI_RID_TX_CRYPT_KEY:
   1426   1.17.2.2  nathanw 		wreq->wi_val[0] = htole16(sc->wi_tx_key);
   1427   1.17.2.2  nathanw 		break;
   1428   1.17.2.2  nathanw 	case WI_RID_DEFLT_CRYPT_KEYS:
   1429   1.17.2.2  nathanw 		wreq->wi_len += sizeof(struct wi_ltv_keys) / 2 - 1;
   1430   1.17.2.3  nathanw 		memcpy(wreq, &sc->wi_keys, sizeof(struct wi_ltv_keys));
   1431   1.17.2.2  nathanw 		break;
   1432   1.17.2.2  nathanw 	default:
   1433   1.17.2.2  nathanw #if 0
   1434   1.17.2.2  nathanw 		error = EIO;
   1435   1.17.2.2  nathanw #else
   1436   1.17.2.2  nathanw #ifdef WI_DEBUG
   1437   1.17.2.2  nathanw 		printf("%s: wi_getdef: unknown request %d\n",
   1438   1.17.2.2  nathanw 		    sc->sc_dev.dv_xname, wreq->wi_type);
   1439   1.17.2.2  nathanw #endif
   1440   1.17.2.2  nathanw #endif
   1441   1.17.2.2  nathanw 		break;
   1442   1.17.2.2  nathanw 	}
   1443   1.17.2.2  nathanw 
   1444   1.17.2.2  nathanw 	return (error);
   1445   1.17.2.2  nathanw }
   1446   1.17.2.2  nathanw 
   1447   1.17.2.2  nathanw static int
   1448   1.17.2.2  nathanw wi_ioctl(ifp, command, data)
   1449   1.17.2.2  nathanw 	struct ifnet		*ifp;
   1450   1.17.2.2  nathanw 	u_long			command;
   1451   1.17.2.2  nathanw 	caddr_t			data;
   1452   1.17.2.2  nathanw {
   1453   1.17.2.7  nathanw 	int			s, error = 0;
   1454  1.17.2.10  nathanw 	int			len;
   1455   1.17.2.2  nathanw 	struct wi_softc		*sc = ifp->if_softc;
   1456   1.17.2.2  nathanw 	struct wi_req		wreq;
   1457   1.17.2.2  nathanw 	struct ifreq		*ifr;
   1458  1.17.2.14  nathanw 	struct proc *p = curproc;
   1459   1.17.2.2  nathanw 	struct ieee80211_nwid nwid;
   1460   1.17.2.2  nathanw 
   1461   1.17.2.2  nathanw 	if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
   1462   1.17.2.2  nathanw 		return (ENXIO);
   1463   1.17.2.2  nathanw 
   1464   1.17.2.2  nathanw 	s = splnet();
   1465   1.17.2.2  nathanw 
   1466   1.17.2.2  nathanw 	ifr = (struct ifreq *)data;
   1467   1.17.2.2  nathanw 	switch (command) {
   1468   1.17.2.2  nathanw 	case SIOCSIFADDR:
   1469   1.17.2.2  nathanw 	case SIOCGIFADDR:
   1470   1.17.2.2  nathanw 	case SIOCSIFMTU:
   1471   1.17.2.2  nathanw 		error = ether_ioctl(ifp, command, data);
   1472   1.17.2.2  nathanw 		break;
   1473   1.17.2.2  nathanw 	case SIOCSIFFLAGS:
   1474   1.17.2.2  nathanw 		if (ifp->if_flags & IFF_UP) {
   1475   1.17.2.2  nathanw 			if (ifp->if_flags & IFF_RUNNING &&
   1476   1.17.2.2  nathanw 			    ifp->if_flags & IFF_PROMISC &&
   1477   1.17.2.2  nathanw 			    !(sc->wi_if_flags & IFF_PROMISC)) {
   1478   1.17.2.2  nathanw 				WI_SETVAL(WI_RID_PROMISC, 1);
   1479   1.17.2.2  nathanw 			} else if (ifp->if_flags & IFF_RUNNING &&
   1480   1.17.2.2  nathanw 			    !(ifp->if_flags & IFF_PROMISC) &&
   1481   1.17.2.2  nathanw 			    sc->wi_if_flags & IFF_PROMISC) {
   1482   1.17.2.2  nathanw 				WI_SETVAL(WI_RID_PROMISC, 0);
   1483   1.17.2.2  nathanw 			}
   1484   1.17.2.2  nathanw 			wi_init(ifp);
   1485   1.17.2.2  nathanw 		} else {
   1486   1.17.2.2  nathanw 			if (ifp->if_flags & IFF_RUNNING) {
   1487   1.17.2.2  nathanw 				wi_stop(ifp, 0);
   1488   1.17.2.2  nathanw 			}
   1489   1.17.2.2  nathanw 		}
   1490   1.17.2.2  nathanw 		sc->wi_if_flags = ifp->if_flags;
   1491   1.17.2.2  nathanw 
   1492   1.17.2.2  nathanw 		if (!(ifp->if_flags & IFF_UP)) {
   1493   1.17.2.2  nathanw 			if (sc->sc_enabled) {
   1494   1.17.2.2  nathanw 				if (sc->sc_disable)
   1495   1.17.2.2  nathanw 					(*sc->sc_disable)(sc);
   1496   1.17.2.2  nathanw 				sc->sc_enabled = 0;
   1497   1.17.2.2  nathanw 				ifp->if_flags &= ~IFF_RUNNING;
   1498   1.17.2.2  nathanw 			}
   1499   1.17.2.2  nathanw 		}
   1500   1.17.2.2  nathanw 		error = 0;
   1501   1.17.2.2  nathanw 		break;
   1502   1.17.2.2  nathanw 	case SIOCADDMULTI:
   1503   1.17.2.2  nathanw 	case SIOCDELMULTI:
   1504   1.17.2.2  nathanw 		error = (command == SIOCADDMULTI) ?
   1505   1.17.2.2  nathanw 			ether_addmulti(ifr, &sc->sc_ethercom) :
   1506   1.17.2.2  nathanw 			ether_delmulti(ifr, &sc->sc_ethercom);
   1507   1.17.2.2  nathanw 		if (error == ENETRESET) {
   1508   1.17.2.2  nathanw 			if (sc->sc_enabled != 0) {
   1509   1.17.2.2  nathanw 				/*
   1510   1.17.2.2  nathanw 				 * Multicast list has changed.  Set the
   1511   1.17.2.2  nathanw 				 * hardware filter accordingly.
   1512   1.17.2.2  nathanw 				 */
   1513   1.17.2.2  nathanw 				wi_setmulti(sc);
   1514   1.17.2.2  nathanw 			}
   1515   1.17.2.2  nathanw 			error = 0;
   1516   1.17.2.2  nathanw 		}
   1517   1.17.2.2  nathanw 		break;
   1518   1.17.2.2  nathanw 	case SIOCSIFMEDIA:
   1519   1.17.2.2  nathanw 	case SIOCGIFMEDIA:
   1520   1.17.2.2  nathanw 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command);
   1521   1.17.2.2  nathanw 		break;
   1522   1.17.2.2  nathanw 	case SIOCGWAVELAN:
   1523   1.17.2.2  nathanw 		error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
   1524   1.17.2.2  nathanw 		if (error)
   1525   1.17.2.2  nathanw 			break;
   1526   1.17.2.7  nathanw 		if (wreq.wi_type == WI_RID_IFACE_STATS) {
   1527   1.17.2.3  nathanw 			memcpy((char *)&wreq.wi_val, (char *)&sc->wi_stats,
   1528   1.17.2.7  nathanw 			    sizeof(sc->wi_stats));
   1529   1.17.2.2  nathanw 			wreq.wi_len = (sizeof(sc->wi_stats) / 2) + 1;
   1530  1.17.2.10  nathanw 		} else if (wreq.wi_type == WI_RID_READ_APS) {
   1531  1.17.2.10  nathanw 			if (sc->wi_scanning) {
   1532  1.17.2.11  nathanw 				error = EINPROGRESS;
   1533  1.17.2.10  nathanw 				break;
   1534  1.17.2.10  nathanw 			} else {
   1535  1.17.2.10  nathanw 				len = sc->wi_naps * sizeof(struct wi_apinfo);
   1536  1.17.2.10  nathanw 				len = len > WI_MAX_DATALEN ? WI_MAX_DATALEN : len;
   1537  1.17.2.10  nathanw 				len = len / sizeof(struct wi_apinfo);
   1538  1.17.2.10  nathanw 				memcpy((char *)&wreq.wi_val, (char *)&len, sizeof(len));
   1539  1.17.2.10  nathanw 				memcpy((char *)&wreq.wi_val + sizeof(len),
   1540  1.17.2.10  nathanw 					(char *)&sc->wi_aps,
   1541  1.17.2.10  nathanw 					len * sizeof(struct wi_apinfo));
   1542  1.17.2.10  nathanw 			}
   1543   1.17.2.7  nathanw 		} else if (wreq.wi_type == WI_RID_DEFLT_CRYPT_KEYS) {
   1544   1.17.2.2  nathanw 			/* For non-root user, return all-zeroes keys */
   1545   1.17.2.2  nathanw 			if (suser(p->p_ucred, &p->p_acflag))
   1546   1.17.2.3  nathanw 				memset((char *)&wreq, 0,
   1547   1.17.2.7  nathanw 				    sizeof(struct wi_ltv_keys));
   1548   1.17.2.2  nathanw 			else
   1549   1.17.2.3  nathanw 				memcpy((char *)&wreq, (char *)&sc->wi_keys,
   1550   1.17.2.7  nathanw 				    sizeof(struct wi_ltv_keys));
   1551   1.17.2.7  nathanw 		} else {
   1552   1.17.2.2  nathanw 			if (sc->sc_enabled == 0)
   1553   1.17.2.2  nathanw 				error = wi_getdef(sc, &wreq);
   1554  1.17.2.12  nathanw 			else if (wreq.wi_len > WI_MAX_DATALEN)
   1555  1.17.2.12  nathanw 				error = EINVAL;
   1556   1.17.2.7  nathanw 			else if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq))
   1557   1.17.2.2  nathanw 				error = EINVAL;
   1558   1.17.2.2  nathanw 		}
   1559   1.17.2.2  nathanw 		if (error == 0)
   1560   1.17.2.2  nathanw 			error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
   1561   1.17.2.2  nathanw 		break;
   1562   1.17.2.2  nathanw 	case SIOCSWAVELAN:
   1563   1.17.2.2  nathanw 		error = suser(p->p_ucred, &p->p_acflag);
   1564   1.17.2.2  nathanw 		if (error)
   1565   1.17.2.2  nathanw 			break;
   1566   1.17.2.2  nathanw 		error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
   1567   1.17.2.2  nathanw 		if (error)
   1568   1.17.2.2  nathanw 			break;
   1569   1.17.2.7  nathanw 		if (wreq.wi_type == WI_RID_IFACE_STATS) {
   1570  1.17.2.11  nathanw 			if (sc->sc_enabled)
   1571  1.17.2.11  nathanw 				wi_inquire(sc);
   1572   1.17.2.2  nathanw 			break;
   1573   1.17.2.7  nathanw 		} else if (wreq.wi_type == WI_RID_MGMT_XMIT) {
   1574   1.17.2.2  nathanw 			error = wi_mgmt_xmit(sc, (caddr_t)&wreq.wi_val,
   1575   1.17.2.7  nathanw 			    wreq.wi_len);
   1576  1.17.2.10  nathanw 		} else if (wreq.wi_type == WI_RID_SCAN_APS) {
   1577  1.17.2.10  nathanw 			if (wreq.wi_len != 4) {
   1578  1.17.2.10  nathanw 				error = EINVAL;
   1579  1.17.2.10  nathanw 				break;
   1580  1.17.2.10  nathanw 			}
   1581  1.17.2.10  nathanw 			if (!sc->wi_scanning) {
   1582  1.17.2.12  nathanw 				switch (sc->sc_firmware_type) {
   1583  1.17.2.12  nathanw 				case WI_LUCENT:
   1584  1.17.2.12  nathanw 					break;
   1585  1.17.2.12  nathanw 				case WI_INTERSIL:
   1586  1.17.2.10  nathanw 					wreq.wi_type = WI_RID_SCAN_REQ;
   1587  1.17.2.10  nathanw 					error = wi_write_record(sc,
   1588  1.17.2.10  nathanw 					    (struct wi_ltv_gen *)&wreq);
   1589  1.17.2.12  nathanw 					break;
   1590  1.17.2.12  nathanw 				case WI_SYMBOL:
   1591  1.17.2.12  nathanw 					/*
   1592  1.17.2.12  nathanw 					 * XXX only supported on 3.x ?
   1593  1.17.2.12  nathanw 					 */
   1594  1.17.2.12  nathanw 					wreq.wi_type = WI_RID_BCAST_SCAN_REQ;
   1595  1.17.2.12  nathanw 					wreq.wi_val[0] =
   1596  1.17.2.12  nathanw 					    BSCAN_BCAST | BSCAN_ONETIME;
   1597  1.17.2.12  nathanw 					wreq.wi_len = 2;
   1598  1.17.2.12  nathanw 					error = wi_write_record(sc,
   1599  1.17.2.12  nathanw 					    (struct wi_ltv_gen *)&wreq);
   1600  1.17.2.12  nathanw 					break;
   1601  1.17.2.10  nathanw 				}
   1602  1.17.2.10  nathanw 				if (!error) {
   1603  1.17.2.10  nathanw 					sc->wi_scanning = 1;
   1604  1.17.2.10  nathanw 					callout_reset(&sc->wi_scan_sh, hz * 1,
   1605  1.17.2.10  nathanw 						wi_wait_scan, sc);
   1606  1.17.2.10  nathanw 				}
   1607  1.17.2.10  nathanw 			}
   1608   1.17.2.7  nathanw 		} else {
   1609  1.17.2.12  nathanw 			if (wreq.wi_len > WI_MAX_DATALEN)
   1610  1.17.2.12  nathanw 				error = EINVAL;
   1611  1.17.2.12  nathanw 			else if (sc->sc_enabled != 0)
   1612   1.17.2.2  nathanw 				error = wi_write_record(sc,
   1613   1.17.2.2  nathanw 				    (struct wi_ltv_gen *)&wreq);
   1614   1.17.2.2  nathanw 			if (error == 0)
   1615   1.17.2.2  nathanw 				error = wi_setdef(sc, &wreq);
   1616   1.17.2.2  nathanw 			if (error == 0 && sc->sc_enabled != 0)
   1617   1.17.2.2  nathanw 				/* Reinitialize WaveLAN. */
   1618   1.17.2.2  nathanw 				wi_init(ifp);
   1619   1.17.2.2  nathanw 		}
   1620   1.17.2.2  nathanw 		break;
   1621   1.17.2.2  nathanw 	case SIOCG80211NWID:
   1622   1.17.2.2  nathanw 		if (sc->sc_enabled == 0) {
   1623   1.17.2.2  nathanw 			/* Return the desired ID */
   1624   1.17.2.2  nathanw 			error = copyout(&sc->wi_netid, ifr->ifr_data,
   1625   1.17.2.2  nathanw 			    sizeof(sc->wi_netid));
   1626   1.17.2.2  nathanw 		} else {
   1627   1.17.2.2  nathanw 			wreq.wi_type = WI_RID_CURRENT_SSID;
   1628   1.17.2.2  nathanw 			wreq.wi_len = WI_MAX_DATALEN;
   1629   1.17.2.2  nathanw 			if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) ||
   1630   1.17.2.2  nathanw 			    le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN)
   1631   1.17.2.2  nathanw 				error = EINVAL;
   1632   1.17.2.2  nathanw 			else {
   1633   1.17.2.2  nathanw 				wi_set_ssid(&nwid, (u_int8_t *)&wreq.wi_val[1],
   1634   1.17.2.2  nathanw 				    le16toh(wreq.wi_val[0]));
   1635   1.17.2.2  nathanw 				error = copyout(&nwid, ifr->ifr_data,
   1636   1.17.2.2  nathanw 				    sizeof(nwid));
   1637   1.17.2.2  nathanw 			}
   1638   1.17.2.2  nathanw 		}
   1639   1.17.2.2  nathanw 		break;
   1640   1.17.2.2  nathanw 	case SIOCS80211NWID:
   1641   1.17.2.2  nathanw 		error = copyin(ifr->ifr_data, &nwid, sizeof(nwid));
   1642   1.17.2.2  nathanw 		if (error != 0)
   1643   1.17.2.2  nathanw 			break;
   1644   1.17.2.2  nathanw 		if (nwid.i_len > IEEE80211_NWID_LEN) {
   1645   1.17.2.2  nathanw 			error = EINVAL;
   1646   1.17.2.2  nathanw 			break;
   1647   1.17.2.2  nathanw 		}
   1648   1.17.2.2  nathanw 		if (sc->wi_netid.i_len == nwid.i_len &&
   1649   1.17.2.2  nathanw 		    memcmp(sc->wi_netid.i_nwid, nwid.i_nwid, nwid.i_len) == 0)
   1650   1.17.2.2  nathanw 			break;
   1651   1.17.2.2  nathanw 		wi_set_ssid(&sc->wi_netid, nwid.i_nwid, nwid.i_len);
   1652   1.17.2.2  nathanw 		if (sc->sc_enabled != 0)
   1653   1.17.2.2  nathanw 			/* Reinitialize WaveLAN. */
   1654   1.17.2.2  nathanw 			wi_init(ifp);
   1655   1.17.2.2  nathanw 		break;
   1656   1.17.2.2  nathanw 	case SIOCS80211NWKEY:
   1657   1.17.2.2  nathanw 		error = wi_set_nwkey(sc, (struct ieee80211_nwkey *)data);
   1658   1.17.2.2  nathanw 		break;
   1659   1.17.2.2  nathanw 	case SIOCG80211NWKEY:
   1660   1.17.2.2  nathanw 		error = wi_get_nwkey(sc, (struct ieee80211_nwkey *)data);
   1661   1.17.2.2  nathanw 		break;
   1662   1.17.2.2  nathanw 	case SIOCS80211POWER:
   1663   1.17.2.2  nathanw 		error = wi_set_pm(sc, (struct ieee80211_power *)data);
   1664   1.17.2.2  nathanw 		break;
   1665   1.17.2.2  nathanw 	case SIOCG80211POWER:
   1666   1.17.2.2  nathanw 		error = wi_get_pm(sc, (struct ieee80211_power *)data);
   1667   1.17.2.2  nathanw 		break;
   1668   1.17.2.2  nathanw 
   1669   1.17.2.2  nathanw 	default:
   1670   1.17.2.2  nathanw 		error = EINVAL;
   1671   1.17.2.2  nathanw 		break;
   1672   1.17.2.2  nathanw 	}
   1673   1.17.2.2  nathanw 
   1674   1.17.2.2  nathanw 	splx(s);
   1675   1.17.2.2  nathanw 	return (error);
   1676   1.17.2.2  nathanw }
   1677   1.17.2.2  nathanw 
   1678   1.17.2.2  nathanw static int
   1679   1.17.2.2  nathanw wi_init(ifp)
   1680   1.17.2.2  nathanw 	struct ifnet *ifp;
   1681   1.17.2.2  nathanw {
   1682   1.17.2.2  nathanw 	struct wi_softc *sc = ifp->if_softc;
   1683   1.17.2.2  nathanw 	struct wi_req wreq;
   1684   1.17.2.2  nathanw 	struct wi_ltv_macaddr mac;
   1685  1.17.2.11  nathanw 	int error, id = 0, wasenabled;
   1686   1.17.2.2  nathanw 
   1687  1.17.2.11  nathanw 	wasenabled = sc->sc_enabled;
   1688   1.17.2.2  nathanw 	if (!sc->sc_enabled) {
   1689   1.17.2.2  nathanw 		if ((error = (*sc->sc_enable)(sc)) != 0)
   1690   1.17.2.2  nathanw 			goto out;
   1691   1.17.2.2  nathanw 		sc->sc_enabled = 1;
   1692   1.17.2.2  nathanw 	}
   1693   1.17.2.2  nathanw 
   1694   1.17.2.2  nathanw 	wi_stop(ifp, 0);
   1695  1.17.2.11  nathanw 	/* Symbol firmware cannot be initialized more than once */
   1696  1.17.2.11  nathanw 	if (!(sc->sc_firmware_type == WI_SYMBOL && wasenabled))
   1697  1.17.2.11  nathanw 		wi_reset(sc);
   1698   1.17.2.2  nathanw 
   1699   1.17.2.2  nathanw 	/* Program max data length. */
   1700   1.17.2.2  nathanw 	WI_SETVAL(WI_RID_MAX_DATALEN, sc->wi_max_data_len);
   1701   1.17.2.2  nathanw 
   1702   1.17.2.2  nathanw 	/* Enable/disable IBSS creation. */
   1703  1.17.2.12  nathanw 	if (sc->sc_firmware_type != WI_INTERSIL)
   1704  1.17.2.12  nathanw 		WI_SETVAL(WI_RID_CREATE_IBSS, sc->wi_create_ibss);
   1705   1.17.2.2  nathanw 
   1706   1.17.2.2  nathanw 	/* Set the port type. */
   1707   1.17.2.2  nathanw 	WI_SETVAL(WI_RID_PORTTYPE, sc->wi_ptype);
   1708   1.17.2.2  nathanw 
   1709   1.17.2.2  nathanw 	/* Program the RTS/CTS threshold. */
   1710   1.17.2.2  nathanw 	WI_SETVAL(WI_RID_RTS_THRESH, sc->wi_rts_thresh);
   1711   1.17.2.2  nathanw 
   1712   1.17.2.2  nathanw 	/* Program the TX rate */
   1713   1.17.2.2  nathanw 	WI_SETVAL(WI_RID_TX_RATE, sc->wi_tx_rate);
   1714   1.17.2.2  nathanw 
   1715   1.17.2.2  nathanw 	/* Access point density */
   1716   1.17.2.2  nathanw 	WI_SETVAL(WI_RID_SYSTEM_SCALE, sc->wi_ap_density);
   1717   1.17.2.2  nathanw 
   1718   1.17.2.2  nathanw 	/* Power Management Enabled */
   1719   1.17.2.2  nathanw 	WI_SETVAL(WI_RID_PM_ENABLED, sc->wi_pm_enabled);
   1720   1.17.2.2  nathanw 
   1721   1.17.2.2  nathanw 	/* Power Managment Max Sleep */
   1722   1.17.2.2  nathanw 	WI_SETVAL(WI_RID_MAX_SLEEP, sc->wi_max_sleep);
   1723   1.17.2.2  nathanw 
   1724   1.17.2.2  nathanw 	/* Roaming type */
   1725   1.17.2.2  nathanw 	WI_SETVAL(WI_RID_ROAMING_MODE, sc->wi_roaming);
   1726   1.17.2.2  nathanw 
   1727   1.17.2.2  nathanw 	/* Specify the IBSS name */
   1728   1.17.2.2  nathanw 	wi_write_ssid(sc, WI_RID_OWN_SSID, &wreq, &sc->wi_ibssid);
   1729   1.17.2.2  nathanw 
   1730   1.17.2.2  nathanw 	/* Specify the network name */
   1731   1.17.2.2  nathanw 	wi_write_ssid(sc, WI_RID_DESIRED_SSID, &wreq, &sc->wi_netid);
   1732   1.17.2.2  nathanw 
   1733   1.17.2.2  nathanw 	/* Specify the frequency to use */
   1734   1.17.2.2  nathanw 	WI_SETVAL(WI_RID_OWN_CHNL, sc->wi_channel);
   1735   1.17.2.2  nathanw 
   1736   1.17.2.2  nathanw 	/* Program the nodename. */
   1737   1.17.2.2  nathanw 	wi_write_ssid(sc, WI_RID_NODENAME, &wreq, &sc->wi_nodeid);
   1738   1.17.2.2  nathanw 
   1739   1.17.2.2  nathanw 	/* Set our MAC address. */
   1740   1.17.2.2  nathanw 	mac.wi_len = 4;
   1741   1.17.2.2  nathanw 	mac.wi_type = WI_RID_MAC_NODE;
   1742   1.17.2.2  nathanw 	memcpy(&mac.wi_mac_addr, sc->sc_macaddr, ETHER_ADDR_LEN);
   1743   1.17.2.2  nathanw 	wi_write_record(sc, (struct wi_ltv_gen *)&mac);
   1744   1.17.2.2  nathanw 
   1745   1.17.2.2  nathanw 	/* Initialize promisc mode. */
   1746   1.17.2.2  nathanw 	if (ifp->if_flags & IFF_PROMISC) {
   1747   1.17.2.2  nathanw 		WI_SETVAL(WI_RID_PROMISC, 1);
   1748   1.17.2.2  nathanw 	} else {
   1749   1.17.2.2  nathanw 		WI_SETVAL(WI_RID_PROMISC, 0);
   1750   1.17.2.2  nathanw 	}
   1751   1.17.2.2  nathanw 
   1752   1.17.2.2  nathanw 	/* Configure WEP. */
   1753   1.17.2.2  nathanw 	if (sc->wi_has_wep) {
   1754   1.17.2.2  nathanw 		WI_SETVAL(WI_RID_ENCRYPTION, sc->wi_use_wep);
   1755   1.17.2.2  nathanw 		WI_SETVAL(WI_RID_TX_CRYPT_KEY, sc->wi_tx_key);
   1756   1.17.2.2  nathanw 		sc->wi_keys.wi_len = (sizeof(struct wi_ltv_keys) / 2) + 1;
   1757   1.17.2.2  nathanw 		sc->wi_keys.wi_type = WI_RID_DEFLT_CRYPT_KEYS;
   1758   1.17.2.2  nathanw 		wi_write_record(sc, (struct wi_ltv_gen *)&sc->wi_keys);
   1759  1.17.2.11  nathanw 		if (sc->sc_firmware_type != WI_LUCENT && sc->wi_use_wep) {
   1760   1.17.2.2  nathanw 			/*
   1761   1.17.2.2  nathanw 			 * ONLY HWB3163 EVAL-CARD Firmware version
   1762  1.17.2.11  nathanw 			 * less than 0.8 variant2
   1763   1.17.2.2  nathanw 			 *
   1764   1.17.2.2  nathanw 			 *   If promiscuous mode disable, Prism2 chip
   1765   1.17.2.2  nathanw 			 *  does not work with WEP .
   1766   1.17.2.2  nathanw 			 * It is under investigation for details.
   1767   1.17.2.2  nathanw 			 * (ichiro (at) netbsd.org)
   1768   1.17.2.2  nathanw 			 */
   1769  1.17.2.11  nathanw 			if (sc->sc_firmware_type == WI_INTERSIL &&
   1770  1.17.2.12  nathanw 			    sc->sc_sta_firmware_ver < 802 ) {
   1771  1.17.2.11  nathanw 				/* firm ver < 0.8 variant 2 */
   1772   1.17.2.2  nathanw 				WI_SETVAL(WI_RID_PROMISC, 1);
   1773   1.17.2.2  nathanw 			}
   1774   1.17.2.2  nathanw 			WI_SETVAL(WI_RID_AUTH_CNTL, sc->wi_authtype);
   1775   1.17.2.2  nathanw 		}
   1776   1.17.2.2  nathanw 	}
   1777   1.17.2.2  nathanw 
   1778   1.17.2.2  nathanw 	/* Set multicast filter. */
   1779   1.17.2.2  nathanw 	wi_setmulti(sc);
   1780   1.17.2.2  nathanw 
   1781   1.17.2.2  nathanw 	/* Enable desired port */
   1782   1.17.2.2  nathanw 	wi_cmd(sc, WI_CMD_ENABLE | sc->wi_portnum, 0);
   1783   1.17.2.2  nathanw 
   1784  1.17.2.10  nathanw 	/*  scanning variable is modal, therefore reinit to OFF, in case it was on. */
   1785  1.17.2.10  nathanw 	sc->wi_scanning=0;
   1786  1.17.2.10  nathanw 	sc->wi_naps=0;
   1787  1.17.2.10  nathanw 
   1788   1.17.2.2  nathanw 	if ((error = wi_alloc_nicmem(sc,
   1789   1.17.2.2  nathanw 	    1518 + sizeof(struct wi_frame) + 8, &id)) != 0) {
   1790   1.17.2.2  nathanw 		printf("%s: tx buffer allocation failed\n",
   1791   1.17.2.2  nathanw 		    sc->sc_dev.dv_xname);
   1792   1.17.2.2  nathanw 		goto out;
   1793   1.17.2.2  nathanw 	}
   1794   1.17.2.2  nathanw 	sc->wi_tx_data_id = id;
   1795   1.17.2.2  nathanw 
   1796   1.17.2.2  nathanw 	if ((error = wi_alloc_nicmem(sc,
   1797   1.17.2.2  nathanw 	    1518 + sizeof(struct wi_frame) + 8, &id)) != 0) {
   1798   1.17.2.2  nathanw 		printf("%s: mgmt. buffer allocation failed\n",
   1799   1.17.2.2  nathanw 		    sc->sc_dev.dv_xname);
   1800   1.17.2.2  nathanw 		goto out;
   1801   1.17.2.2  nathanw 	}
   1802   1.17.2.2  nathanw 	sc->wi_tx_mgmt_id = id;
   1803   1.17.2.2  nathanw 
   1804   1.17.2.2  nathanw 	/* Enable interrupts */
   1805   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
   1806   1.17.2.2  nathanw 
   1807   1.17.2.2  nathanw 	ifp->if_flags |= IFF_RUNNING;
   1808   1.17.2.2  nathanw 	ifp->if_flags &= ~IFF_OACTIVE;
   1809   1.17.2.2  nathanw 
   1810   1.17.2.7  nathanw 	callout_reset(&sc->wi_inquire_ch, hz * 60, wi_inquire, sc);
   1811   1.17.2.2  nathanw 
   1812   1.17.2.2  nathanw  out:
   1813   1.17.2.2  nathanw 	if (error) {
   1814   1.17.2.2  nathanw 		ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
   1815   1.17.2.2  nathanw 		ifp->if_timer = 0;
   1816   1.17.2.2  nathanw 		printf("%s: interface not running\n", sc->sc_dev.dv_xname);
   1817   1.17.2.2  nathanw 	}
   1818   1.17.2.2  nathanw 	return (error);
   1819   1.17.2.2  nathanw }
   1820   1.17.2.2  nathanw 
   1821   1.17.2.2  nathanw static void
   1822   1.17.2.2  nathanw wi_start(ifp)
   1823   1.17.2.2  nathanw 	struct ifnet		*ifp;
   1824   1.17.2.2  nathanw {
   1825   1.17.2.2  nathanw 	struct wi_softc		*sc;
   1826   1.17.2.2  nathanw 	struct mbuf		*m0;
   1827   1.17.2.2  nathanw 	struct wi_frame		tx_frame;
   1828   1.17.2.2  nathanw 	struct ether_header	*eh;
   1829   1.17.2.2  nathanw 	int			id;
   1830   1.17.2.2  nathanw 
   1831   1.17.2.2  nathanw 	sc = ifp->if_softc;
   1832   1.17.2.2  nathanw 
   1833   1.17.2.2  nathanw 	if (ifp->if_flags & IFF_OACTIVE)
   1834   1.17.2.2  nathanw 		return;
   1835   1.17.2.2  nathanw 
   1836   1.17.2.2  nathanw 	IFQ_DEQUEUE(&ifp->if_snd, m0);
   1837   1.17.2.2  nathanw 	if (m0 == NULL)
   1838   1.17.2.2  nathanw 		return;
   1839   1.17.2.2  nathanw 
   1840   1.17.2.3  nathanw 	memset((char *)&tx_frame, 0, sizeof(tx_frame));
   1841   1.17.2.2  nathanw 	id = sc->wi_tx_data_id;
   1842   1.17.2.2  nathanw 	eh = mtod(m0, struct ether_header *);
   1843   1.17.2.2  nathanw 
   1844   1.17.2.2  nathanw 	/*
   1845   1.17.2.2  nathanw 	 * Use RFC1042 encoding for IP and ARP datagrams,
   1846   1.17.2.2  nathanw 	 * 802.3 for anything else.
   1847   1.17.2.2  nathanw 	 */
   1848  1.17.2.13  nathanw 	if (eh->ether_type == htons(ETHERTYPE_IP) ||
   1849  1.17.2.13  nathanw 	    eh->ether_type == htons(ETHERTYPE_ARP) ||
   1850  1.17.2.13  nathanw 	    eh->ether_type == htons(ETHERTYPE_REVARP) ||
   1851  1.17.2.13  nathanw 	    eh->ether_type == htons(ETHERTYPE_IPV6)) {
   1852   1.17.2.3  nathanw 		memcpy((char *)&tx_frame.wi_addr1, (char *)&eh->ether_dhost,
   1853   1.17.2.3  nathanw 		    ETHER_ADDR_LEN);
   1854   1.17.2.3  nathanw 		memcpy((char *)&tx_frame.wi_addr2, (char *)&eh->ether_shost,
   1855   1.17.2.3  nathanw 		    ETHER_ADDR_LEN);
   1856   1.17.2.3  nathanw 		memcpy((char *)&tx_frame.wi_dst_addr, (char *)&eh->ether_dhost,
   1857   1.17.2.3  nathanw 		    ETHER_ADDR_LEN);
   1858   1.17.2.3  nathanw 		memcpy((char *)&tx_frame.wi_src_addr, (char *)&eh->ether_shost,
   1859   1.17.2.3  nathanw 		    ETHER_ADDR_LEN);
   1860   1.17.2.2  nathanw 
   1861   1.17.2.2  nathanw 		tx_frame.wi_dat_len = htole16(m0->m_pkthdr.len - WI_SNAPHDR_LEN);
   1862   1.17.2.2  nathanw 		tx_frame.wi_frame_ctl = htole16(WI_FTYPE_DATA);
   1863   1.17.2.2  nathanw 		tx_frame.wi_dat[0] = htons(WI_SNAP_WORD0);
   1864   1.17.2.2  nathanw 		tx_frame.wi_dat[1] = htons(WI_SNAP_WORD1);
   1865   1.17.2.2  nathanw 		tx_frame.wi_len = htons(m0->m_pkthdr.len - WI_SNAPHDR_LEN);
   1866   1.17.2.2  nathanw 		tx_frame.wi_type = eh->ether_type;
   1867   1.17.2.2  nathanw 
   1868   1.17.2.2  nathanw 		m_copydata(m0, sizeof(struct ether_header),
   1869   1.17.2.2  nathanw 		    m0->m_pkthdr.len - sizeof(struct ether_header),
   1870   1.17.2.2  nathanw 		    (caddr_t)&sc->wi_txbuf);
   1871   1.17.2.2  nathanw 
   1872   1.17.2.2  nathanw 		wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
   1873   1.17.2.2  nathanw 		    sizeof(struct wi_frame));
   1874   1.17.2.2  nathanw 		wi_write_data(sc, id, WI_802_11_OFFSET, (caddr_t)&sc->wi_txbuf,
   1875   1.17.2.2  nathanw 		    (m0->m_pkthdr.len - sizeof(struct ether_header)) + 2);
   1876   1.17.2.2  nathanw 	} else {
   1877   1.17.2.2  nathanw 		tx_frame.wi_dat_len = htole16(m0->m_pkthdr.len);
   1878   1.17.2.2  nathanw 
   1879   1.17.2.2  nathanw 		m_copydata(m0, 0, m0->m_pkthdr.len, (caddr_t)&sc->wi_txbuf);
   1880   1.17.2.2  nathanw 
   1881   1.17.2.2  nathanw 		wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
   1882   1.17.2.2  nathanw 		    sizeof(struct wi_frame));
   1883   1.17.2.2  nathanw 		wi_write_data(sc, id, WI_802_3_OFFSET, (caddr_t)&sc->wi_txbuf,
   1884   1.17.2.2  nathanw 		    m0->m_pkthdr.len + 2);
   1885   1.17.2.2  nathanw 	}
   1886   1.17.2.2  nathanw 
   1887   1.17.2.2  nathanw #if NBPFILTER > 0
   1888   1.17.2.2  nathanw 	/*
   1889   1.17.2.2  nathanw 	 * If there's a BPF listener, bounce a copy of
   1890   1.17.2.2  nathanw 	 * this frame to him.
   1891   1.17.2.2  nathanw 	 */
   1892   1.17.2.2  nathanw 	if (ifp->if_bpf)
   1893   1.17.2.2  nathanw 		bpf_mtap(ifp->if_bpf, m0);
   1894   1.17.2.2  nathanw #endif
   1895   1.17.2.2  nathanw 
   1896   1.17.2.2  nathanw 	m_freem(m0);
   1897   1.17.2.2  nathanw 
   1898   1.17.2.2  nathanw 	if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id))
   1899   1.17.2.2  nathanw 		printf("%s: xmit failed\n", sc->sc_dev.dv_xname);
   1900   1.17.2.2  nathanw 
   1901   1.17.2.2  nathanw 	ifp->if_flags |= IFF_OACTIVE;
   1902   1.17.2.2  nathanw 
   1903   1.17.2.2  nathanw 	/*
   1904   1.17.2.2  nathanw 	 * Set a timeout in case the chip goes out to lunch.
   1905   1.17.2.2  nathanw 	 */
   1906   1.17.2.2  nathanw 	ifp->if_timer = 5;
   1907   1.17.2.2  nathanw 
   1908   1.17.2.2  nathanw 	return;
   1909   1.17.2.2  nathanw }
   1910   1.17.2.2  nathanw 
   1911   1.17.2.2  nathanw static int
   1912   1.17.2.2  nathanw wi_mgmt_xmit(sc, data, len)
   1913   1.17.2.2  nathanw 	struct wi_softc		*sc;
   1914   1.17.2.2  nathanw 	caddr_t			data;
   1915   1.17.2.2  nathanw 	int			len;
   1916   1.17.2.2  nathanw {
   1917   1.17.2.2  nathanw 	struct wi_frame		tx_frame;
   1918   1.17.2.2  nathanw 	int			id;
   1919   1.17.2.2  nathanw 	struct wi_80211_hdr	*hdr;
   1920   1.17.2.2  nathanw 	caddr_t			dptr;
   1921   1.17.2.2  nathanw 
   1922   1.17.2.2  nathanw 	hdr = (struct wi_80211_hdr *)data;
   1923   1.17.2.2  nathanw 	dptr = data + sizeof(struct wi_80211_hdr);
   1924   1.17.2.2  nathanw 
   1925   1.17.2.3  nathanw 	memset((char *)&tx_frame, 0, sizeof(tx_frame));
   1926   1.17.2.2  nathanw 	id = sc->wi_tx_mgmt_id;
   1927   1.17.2.2  nathanw 
   1928   1.17.2.3  nathanw 	memcpy((char *)&tx_frame.wi_frame_ctl, (char *)hdr,
   1929   1.17.2.2  nathanw 	   sizeof(struct wi_80211_hdr));
   1930   1.17.2.2  nathanw 
   1931   1.17.2.2  nathanw 	tx_frame.wi_dat_len = htole16(len - WI_SNAPHDR_LEN);
   1932   1.17.2.2  nathanw 	tx_frame.wi_len = htons(len - WI_SNAPHDR_LEN);
   1933   1.17.2.2  nathanw 
   1934   1.17.2.2  nathanw 	wi_write_data(sc, id, 0, (caddr_t)&tx_frame, sizeof(struct wi_frame));
   1935   1.17.2.2  nathanw 	wi_write_data(sc, id, WI_802_11_OFFSET_RAW, dptr,
   1936   1.17.2.2  nathanw 	    (len - sizeof(struct wi_80211_hdr)) + 2);
   1937   1.17.2.2  nathanw 
   1938   1.17.2.2  nathanw 	if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id)) {
   1939   1.17.2.2  nathanw 		printf("%s: xmit failed\n", sc->sc_dev.dv_xname);
   1940   1.17.2.2  nathanw 		return(EIO);
   1941   1.17.2.2  nathanw 	}
   1942   1.17.2.2  nathanw 
   1943   1.17.2.2  nathanw 	return(0);
   1944   1.17.2.2  nathanw }
   1945   1.17.2.2  nathanw 
   1946   1.17.2.2  nathanw static void
   1947   1.17.2.2  nathanw wi_stop(ifp, disable)
   1948   1.17.2.2  nathanw 	struct ifnet *ifp;
   1949   1.17.2.2  nathanw {
   1950   1.17.2.2  nathanw 	struct wi_softc	*sc = ifp->if_softc;
   1951   1.17.2.2  nathanw 
   1952   1.17.2.2  nathanw 	CSR_WRITE_2(sc, WI_INT_EN, 0);
   1953   1.17.2.2  nathanw 	wi_cmd(sc, WI_CMD_DISABLE|sc->wi_portnum, 0);
   1954   1.17.2.2  nathanw 
   1955   1.17.2.7  nathanw 	callout_stop(&sc->wi_inquire_ch);
   1956  1.17.2.10  nathanw 	callout_stop(&sc->wi_scan_sh);
   1957   1.17.2.2  nathanw 
   1958   1.17.2.2  nathanw 	if (disable) {
   1959   1.17.2.2  nathanw 		if (sc->sc_enabled) {
   1960   1.17.2.2  nathanw 			if (sc->sc_disable)
   1961   1.17.2.2  nathanw 				(*sc->sc_disable)(sc);
   1962   1.17.2.2  nathanw 			sc->sc_enabled = 0;
   1963   1.17.2.2  nathanw 		}
   1964   1.17.2.2  nathanw 	}
   1965   1.17.2.2  nathanw 
   1966   1.17.2.2  nathanw 	ifp->if_flags &= ~(IFF_OACTIVE | IFF_RUNNING);
   1967   1.17.2.2  nathanw 	ifp->if_timer = 0;
   1968   1.17.2.2  nathanw }
   1969   1.17.2.2  nathanw 
   1970   1.17.2.2  nathanw static void
   1971   1.17.2.2  nathanw wi_watchdog(ifp)
   1972   1.17.2.2  nathanw 	struct ifnet		*ifp;
   1973   1.17.2.2  nathanw {
   1974   1.17.2.2  nathanw 	struct wi_softc		*sc;
   1975   1.17.2.2  nathanw 
   1976   1.17.2.2  nathanw 	sc = ifp->if_softc;
   1977   1.17.2.2  nathanw 
   1978   1.17.2.2  nathanw 	printf("%s: device timeout\n", sc->sc_dev.dv_xname);
   1979   1.17.2.2  nathanw 
   1980   1.17.2.2  nathanw 	wi_init(ifp);
   1981   1.17.2.2  nathanw 
   1982   1.17.2.2  nathanw 	ifp->if_oerrors++;
   1983   1.17.2.2  nathanw 
   1984   1.17.2.2  nathanw 	return;
   1985   1.17.2.2  nathanw }
   1986   1.17.2.2  nathanw 
   1987   1.17.2.2  nathanw void
   1988   1.17.2.2  nathanw wi_shutdown(sc)
   1989   1.17.2.2  nathanw 	struct wi_softc *sc;
   1990   1.17.2.2  nathanw {
   1991   1.17.2.2  nathanw 	int s;
   1992   1.17.2.2  nathanw 
   1993   1.17.2.2  nathanw 	s = splnet();
   1994   1.17.2.2  nathanw 	if (sc->sc_enabled) {
   1995   1.17.2.2  nathanw 		if (sc->sc_disable)
   1996   1.17.2.2  nathanw 			(*sc->sc_disable)(sc);
   1997   1.17.2.2  nathanw 		sc->sc_enabled = 0;
   1998   1.17.2.2  nathanw 	}
   1999   1.17.2.2  nathanw 	splx(s);
   2000   1.17.2.2  nathanw }
   2001   1.17.2.2  nathanw 
   2002   1.17.2.2  nathanw int
   2003   1.17.2.2  nathanw wi_activate(self, act)
   2004   1.17.2.2  nathanw 	struct device *self;
   2005   1.17.2.2  nathanw 	enum devact act;
   2006   1.17.2.2  nathanw {
   2007   1.17.2.2  nathanw 	struct wi_softc *sc = (struct wi_softc *)self;
   2008   1.17.2.2  nathanw 	int rv = 0, s;
   2009   1.17.2.2  nathanw 
   2010   1.17.2.2  nathanw 	s = splnet();
   2011   1.17.2.2  nathanw 	switch (act) {
   2012   1.17.2.2  nathanw 	case DVACT_ACTIVATE:
   2013   1.17.2.2  nathanw 		rv = EOPNOTSUPP;
   2014   1.17.2.2  nathanw 		break;
   2015   1.17.2.2  nathanw 
   2016   1.17.2.2  nathanw 	case DVACT_DEACTIVATE:
   2017   1.17.2.2  nathanw 		if_deactivate(&sc->sc_ethercom.ec_if);
   2018   1.17.2.2  nathanw 		break;
   2019   1.17.2.2  nathanw 	}
   2020   1.17.2.2  nathanw 	splx(s);
   2021   1.17.2.2  nathanw 	return (rv);
   2022   1.17.2.2  nathanw }
   2023   1.17.2.2  nathanw 
   2024   1.17.2.2  nathanw static void
   2025   1.17.2.2  nathanw wi_get_id(sc)
   2026   1.17.2.2  nathanw 	struct wi_softc *sc;
   2027   1.17.2.2  nathanw {
   2028   1.17.2.2  nathanw 	struct wi_ltv_ver       ver;
   2029  1.17.2.12  nathanw 	struct wi_card_ident	*id;
   2030   1.17.2.2  nathanw 
   2031   1.17.2.2  nathanw 	/* getting chip identity */
   2032   1.17.2.2  nathanw 	memset(&ver, 0, sizeof(ver));
   2033   1.17.2.8  nathanw 	ver.wi_type = WI_RID_CARD_ID;
   2034   1.17.2.2  nathanw 	ver.wi_len = 5;
   2035   1.17.2.2  nathanw 	wi_read_record(sc, (struct wi_ltv_gen *)&ver);
   2036   1.17.2.2  nathanw 	printf("%s: using ", sc->sc_dev.dv_xname);
   2037  1.17.2.12  nathanw 
   2038  1.17.2.12  nathanw 	sc->sc_firmware_type = WI_NOTYPE;
   2039  1.17.2.12  nathanw 	for (id = wi_card_ident; id->card_name != NULL; id++) {
   2040  1.17.2.12  nathanw 		if (le16toh(ver.wi_ver[0]) == id->card_id) {
   2041  1.17.2.12  nathanw 			printf("%s", id->card_name);
   2042  1.17.2.12  nathanw 			sc->sc_firmware_type = id->firm_type;
   2043  1.17.2.12  nathanw 			break;
   2044  1.17.2.12  nathanw 		}
   2045  1.17.2.12  nathanw 	}
   2046  1.17.2.12  nathanw 	if (sc->sc_firmware_type == WI_NOTYPE) {
   2047  1.17.2.11  nathanw 		if (le16toh(ver.wi_ver[0]) & 0x8000) {
   2048  1.17.2.11  nathanw 			printf("Unknown PRISM2 chip");
   2049  1.17.2.11  nathanw 			sc->sc_firmware_type = WI_INTERSIL;
   2050  1.17.2.11  nathanw 		} else {
   2051  1.17.2.11  nathanw 			printf("Unknown Lucent chip");
   2052  1.17.2.11  nathanw 			sc->sc_firmware_type = WI_LUCENT;
   2053  1.17.2.11  nathanw 		}
   2054   1.17.2.2  nathanw 	}
   2055   1.17.2.2  nathanw 
   2056  1.17.2.12  nathanw 	/* get primary firmware version (Only Prism chips) */
   2057  1.17.2.12  nathanw 	if (sc->sc_firmware_type != WI_LUCENT) {
   2058  1.17.2.12  nathanw 		memset(&ver, 0, sizeof(ver));
   2059  1.17.2.12  nathanw 		ver.wi_type = WI_RID_PRI_IDENTITY;
   2060  1.17.2.12  nathanw 		ver.wi_len = 5;
   2061  1.17.2.12  nathanw 		wi_read_record(sc, (struct wi_ltv_gen *)&ver);
   2062  1.17.2.12  nathanw 		LE16TOH(ver.wi_ver[1]);
   2063  1.17.2.12  nathanw 		LE16TOH(ver.wi_ver[2]);
   2064  1.17.2.12  nathanw 		LE16TOH(ver.wi_ver[3]);
   2065  1.17.2.12  nathanw 		sc->sc_pri_firmware_ver = ver.wi_ver[2] * 10000 +
   2066  1.17.2.12  nathanw 		    ver.wi_ver[3] * 100 + ver.wi_ver[1];
   2067  1.17.2.12  nathanw 	}
   2068  1.17.2.12  nathanw 
   2069  1.17.2.12  nathanw 	/* get station firmware version */
   2070  1.17.2.11  nathanw 	memset(&ver, 0, sizeof(ver));
   2071  1.17.2.11  nathanw 	ver.wi_type = WI_RID_STA_IDENTITY;
   2072  1.17.2.11  nathanw 	ver.wi_len = 5;
   2073  1.17.2.11  nathanw 	wi_read_record(sc, (struct wi_ltv_gen *)&ver);
   2074  1.17.2.11  nathanw 	LE16TOH(ver.wi_ver[1]);
   2075  1.17.2.11  nathanw 	LE16TOH(ver.wi_ver[2]);
   2076  1.17.2.11  nathanw 	LE16TOH(ver.wi_ver[3]);
   2077  1.17.2.12  nathanw 	sc->sc_sta_firmware_ver = ver.wi_ver[2] * 10000 +
   2078  1.17.2.11  nathanw 	    ver.wi_ver[3] * 100 + ver.wi_ver[1];
   2079  1.17.2.11  nathanw 	if (sc->sc_firmware_type == WI_INTERSIL &&
   2080  1.17.2.12  nathanw 	    (sc->sc_sta_firmware_ver == 10102 || sc->sc_sta_firmware_ver == 20102)) {
   2081  1.17.2.11  nathanw 		struct wi_ltv_str sver;
   2082  1.17.2.11  nathanw 		char *p;
   2083  1.17.2.11  nathanw 
   2084  1.17.2.11  nathanw 		memset(&sver, 0, sizeof(sver));
   2085  1.17.2.11  nathanw 		sver.wi_type = WI_RID_SYMBOL_IDENTITY;
   2086  1.17.2.11  nathanw 		sver.wi_len = 7;
   2087  1.17.2.12  nathanw 		/* value should be the format like "V2.00-11" */
   2088  1.17.2.11  nathanw 		if (wi_read_record(sc, (struct wi_ltv_gen *)&sver) == 0 &&
   2089  1.17.2.12  nathanw 		    *(p = (char *)sver.wi_str) >= 'A' &&
   2090  1.17.2.11  nathanw 		    p[2] == '.' && p[5] == '-' && p[8] == '\0') {
   2091  1.17.2.11  nathanw 			sc->sc_firmware_type = WI_SYMBOL;
   2092  1.17.2.12  nathanw 			sc->sc_sta_firmware_ver = (p[1] - '0') * 10000 +
   2093  1.17.2.11  nathanw 			    (p[3] - '0') * 1000 + (p[4] - '0') * 100 +
   2094  1.17.2.11  nathanw 			    (p[6] - '0') * 10 + (p[7] - '0');
   2095  1.17.2.11  nathanw 		}
   2096  1.17.2.11  nathanw 	}
   2097  1.17.2.12  nathanw 
   2098  1.17.2.12  nathanw 	printf("\n%s: %s Firmware: ", sc->sc_dev.dv_xname,
   2099  1.17.2.12  nathanw 	     sc->sc_firmware_type == WI_LUCENT ? "Lucent" :
   2100  1.17.2.12  nathanw 	    (sc->sc_firmware_type == WI_SYMBOL ? "Symbol" : "Intersil"));
   2101  1.17.2.12  nathanw 	if (sc->sc_firmware_type != WI_LUCENT)	/* XXX */
   2102  1.17.2.12  nathanw 	    printf("Primary (%u.%u.%u), ", sc->sc_pri_firmware_ver / 10000,
   2103  1.17.2.12  nathanw 		    (sc->sc_pri_firmware_ver % 10000) / 100,
   2104  1.17.2.12  nathanw 		    sc->sc_pri_firmware_ver % 100);
   2105  1.17.2.12  nathanw 	printf("Station (%u.%u.%u)\n",
   2106  1.17.2.12  nathanw 	    sc->sc_sta_firmware_ver / 10000, (sc->sc_sta_firmware_ver % 10000) / 100,
   2107  1.17.2.12  nathanw 	    sc->sc_sta_firmware_ver % 100);
   2108   1.17.2.2  nathanw 
   2109   1.17.2.2  nathanw 	return;
   2110   1.17.2.2  nathanw }
   2111   1.17.2.2  nathanw 
   2112   1.17.2.2  nathanw int
   2113   1.17.2.2  nathanw wi_detach(sc)
   2114   1.17.2.2  nathanw 	struct wi_softc *sc;
   2115   1.17.2.2  nathanw {
   2116   1.17.2.2  nathanw 	struct ifnet *ifp = sc->sc_ifp;
   2117   1.17.2.2  nathanw 	int s;
   2118   1.17.2.2  nathanw 
   2119   1.17.2.2  nathanw 	if (!sc->sc_attached)
   2120   1.17.2.2  nathanw 		return (0);
   2121   1.17.2.2  nathanw 
   2122   1.17.2.2  nathanw 	s = splnet();
   2123   1.17.2.7  nathanw 	callout_stop(&sc->wi_inquire_ch);
   2124   1.17.2.2  nathanw 
   2125   1.17.2.2  nathanw 	/* Delete all remaining media. */
   2126   1.17.2.2  nathanw 	ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
   2127   1.17.2.2  nathanw 
   2128   1.17.2.2  nathanw 	ether_ifdetach(ifp);
   2129   1.17.2.2  nathanw 	if_detach(ifp);
   2130   1.17.2.2  nathanw 	if (sc->sc_enabled) {
   2131   1.17.2.2  nathanw 		if (sc->sc_disable)
   2132   1.17.2.2  nathanw 			(*sc->sc_disable)(sc);
   2133   1.17.2.2  nathanw 		sc->sc_enabled = 0;
   2134   1.17.2.2  nathanw 	}
   2135   1.17.2.2  nathanw 	splx(s);
   2136   1.17.2.2  nathanw 	return (0);
   2137   1.17.2.2  nathanw }
   2138   1.17.2.2  nathanw 
   2139   1.17.2.2  nathanw void
   2140   1.17.2.2  nathanw wi_power(sc, why)
   2141   1.17.2.2  nathanw 	struct wi_softc *sc;
   2142   1.17.2.2  nathanw 	int why;
   2143   1.17.2.2  nathanw {
   2144   1.17.2.2  nathanw 	int s;
   2145   1.17.2.2  nathanw 
   2146   1.17.2.2  nathanw 	if (!sc->sc_enabled)
   2147   1.17.2.2  nathanw 		return;
   2148   1.17.2.2  nathanw 
   2149   1.17.2.2  nathanw 	s = splnet();
   2150   1.17.2.2  nathanw 	switch (why) {
   2151   1.17.2.2  nathanw 	case PWR_SUSPEND:
   2152   1.17.2.2  nathanw 	case PWR_STANDBY:
   2153   1.17.2.2  nathanw 		wi_stop(sc->sc_ifp, 0);
   2154   1.17.2.2  nathanw 		if (sc->sc_enabled) {
   2155   1.17.2.2  nathanw 			if (sc->sc_disable)
   2156   1.17.2.2  nathanw 				(*sc->sc_disable)(sc);
   2157   1.17.2.2  nathanw 		}
   2158   1.17.2.2  nathanw 		break;
   2159   1.17.2.2  nathanw 	case PWR_RESUME:
   2160   1.17.2.2  nathanw 		sc->sc_enabled = 0;
   2161   1.17.2.2  nathanw 		wi_init(sc->sc_ifp);
   2162   1.17.2.2  nathanw 		(void)wi_intr(sc);
   2163   1.17.2.2  nathanw 		break;
   2164   1.17.2.2  nathanw 	case PWR_SOFTSUSPEND:
   2165   1.17.2.2  nathanw 	case PWR_SOFTSTANDBY:
   2166   1.17.2.2  nathanw 	case PWR_SOFTRESUME:
   2167   1.17.2.2  nathanw 		break;
   2168   1.17.2.2  nathanw 	}
   2169   1.17.2.2  nathanw 	splx(s);
   2170   1.17.2.2  nathanw }
   2171   1.17.2.2  nathanw 
   2172   1.17.2.2  nathanw static int
   2173   1.17.2.2  nathanw wi_set_ssid(ws, id, len)
   2174   1.17.2.2  nathanw 	struct ieee80211_nwid *ws;
   2175   1.17.2.2  nathanw 	u_int8_t *id;
   2176   1.17.2.2  nathanw 	int len;
   2177   1.17.2.2  nathanw {
   2178   1.17.2.2  nathanw 
   2179   1.17.2.2  nathanw 	if (len > IEEE80211_NWID_LEN)
   2180   1.17.2.2  nathanw 		return (EINVAL);
   2181   1.17.2.2  nathanw 	ws->i_len = len;
   2182   1.17.2.2  nathanw 	memcpy(ws->i_nwid, id, len);
   2183   1.17.2.2  nathanw 	return (0);
   2184   1.17.2.2  nathanw }
   2185   1.17.2.2  nathanw 
   2186   1.17.2.2  nathanw static void
   2187   1.17.2.2  nathanw wi_request_fill_ssid(wreq, ws)
   2188   1.17.2.2  nathanw 	struct wi_req *wreq;
   2189   1.17.2.2  nathanw 	struct ieee80211_nwid *ws;
   2190   1.17.2.2  nathanw {
   2191   1.17.2.2  nathanw 	int len = ws->i_len;
   2192   1.17.2.2  nathanw 
   2193   1.17.2.2  nathanw 	memset(&wreq->wi_val[0], 0, sizeof(wreq->wi_val));
   2194   1.17.2.2  nathanw 	wreq->wi_val[0] = htole16(len);
   2195   1.17.2.2  nathanw 	wreq->wi_len = roundup(len, 2) / 2 + 2;
   2196   1.17.2.2  nathanw 	memcpy(&wreq->wi_val[1], ws->i_nwid, len);
   2197   1.17.2.2  nathanw }
   2198   1.17.2.2  nathanw 
   2199   1.17.2.2  nathanw static int
   2200   1.17.2.2  nathanw wi_write_ssid(sc, type, wreq, ws)
   2201   1.17.2.2  nathanw 	struct wi_softc *sc;
   2202   1.17.2.2  nathanw 	int type;
   2203   1.17.2.2  nathanw 	struct wi_req *wreq;
   2204   1.17.2.2  nathanw 	struct ieee80211_nwid *ws;
   2205   1.17.2.2  nathanw {
   2206   1.17.2.2  nathanw 
   2207   1.17.2.2  nathanw 	wreq->wi_type = type;
   2208   1.17.2.2  nathanw 	wi_request_fill_ssid(wreq, ws);
   2209   1.17.2.2  nathanw 	return (wi_write_record(sc, (struct wi_ltv_gen *)wreq));
   2210   1.17.2.2  nathanw }
   2211   1.17.2.2  nathanw 
   2212   1.17.2.2  nathanw static int
   2213   1.17.2.2  nathanw wi_sync_media(sc, ptype, txrate)
   2214   1.17.2.2  nathanw 	struct wi_softc *sc;
   2215   1.17.2.2  nathanw 	int ptype;
   2216   1.17.2.2  nathanw 	int txrate;
   2217   1.17.2.2  nathanw {
   2218   1.17.2.2  nathanw 	int media = sc->sc_media.ifm_cur->ifm_media;
   2219   1.17.2.2  nathanw 	int options = IFM_OPTIONS(media);
   2220   1.17.2.2  nathanw 	int subtype;
   2221   1.17.2.2  nathanw 
   2222   1.17.2.2  nathanw 	switch (txrate) {
   2223   1.17.2.2  nathanw 	case 1:
   2224   1.17.2.2  nathanw 		subtype = IFM_IEEE80211_DS1;
   2225   1.17.2.2  nathanw 		break;
   2226   1.17.2.2  nathanw 	case 2:
   2227   1.17.2.2  nathanw 		subtype = IFM_IEEE80211_DS2;
   2228   1.17.2.2  nathanw 		break;
   2229   1.17.2.2  nathanw 	case 3:
   2230   1.17.2.2  nathanw 		subtype = IFM_AUTO;
   2231   1.17.2.2  nathanw 		break;
   2232  1.17.2.10  nathanw 	case 5:
   2233  1.17.2.10  nathanw 		subtype = IFM_IEEE80211_DS5;
   2234  1.17.2.10  nathanw 		break;
   2235   1.17.2.2  nathanw 	case 11:
   2236   1.17.2.2  nathanw 		subtype = IFM_IEEE80211_DS11;
   2237   1.17.2.2  nathanw 		break;
   2238   1.17.2.2  nathanw 	default:
   2239   1.17.2.2  nathanw 		subtype = IFM_MANUAL;		/* Unable to represent */
   2240   1.17.2.2  nathanw 		break;
   2241   1.17.2.2  nathanw 	}
   2242   1.17.2.2  nathanw 	switch (ptype) {
   2243   1.17.2.2  nathanw 	case WI_PORTTYPE_ADHOC:
   2244   1.17.2.2  nathanw 		options |= IFM_IEEE80211_ADHOC;
   2245   1.17.2.2  nathanw 		break;
   2246   1.17.2.2  nathanw 	case WI_PORTTYPE_BSS:
   2247   1.17.2.2  nathanw 		options &= ~IFM_IEEE80211_ADHOC;
   2248   1.17.2.2  nathanw 		break;
   2249   1.17.2.2  nathanw 	default:
   2250   1.17.2.2  nathanw 		subtype = IFM_MANUAL;		/* Unable to represent */
   2251   1.17.2.2  nathanw 		break;
   2252   1.17.2.2  nathanw 	}
   2253   1.17.2.2  nathanw 	media = IFM_MAKEWORD(IFM_TYPE(media), subtype, options,
   2254   1.17.2.2  nathanw 	    IFM_INST(media));
   2255   1.17.2.2  nathanw 	if (ifmedia_match(&sc->sc_media, media, sc->sc_media.ifm_mask) == NULL)
   2256   1.17.2.2  nathanw 		return (EINVAL);
   2257   1.17.2.2  nathanw 	ifmedia_set(&sc->sc_media, media);
   2258   1.17.2.2  nathanw 	sc->wi_ptype = ptype;
   2259   1.17.2.2  nathanw 	sc->wi_tx_rate = txrate;
   2260   1.17.2.2  nathanw 	return (0);
   2261   1.17.2.2  nathanw }
   2262   1.17.2.2  nathanw 
   2263   1.17.2.2  nathanw static int
   2264   1.17.2.2  nathanw wi_media_change(ifp)
   2265   1.17.2.2  nathanw 	struct ifnet *ifp;
   2266   1.17.2.2  nathanw {
   2267   1.17.2.2  nathanw 	struct wi_softc *sc = ifp->if_softc;
   2268   1.17.2.2  nathanw 	int otype = sc->wi_ptype;
   2269   1.17.2.2  nathanw 	int orate = sc->wi_tx_rate;
   2270   1.17.2.2  nathanw 
   2271   1.17.2.2  nathanw 	if ((sc->sc_media.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC) != 0)
   2272   1.17.2.2  nathanw 		sc->wi_ptype = WI_PORTTYPE_ADHOC;
   2273   1.17.2.2  nathanw 	else
   2274   1.17.2.2  nathanw 		sc->wi_ptype = WI_PORTTYPE_BSS;
   2275   1.17.2.2  nathanw 
   2276   1.17.2.2  nathanw 	switch (IFM_SUBTYPE(sc->sc_media.ifm_cur->ifm_media)) {
   2277   1.17.2.2  nathanw 	case IFM_IEEE80211_DS1:
   2278   1.17.2.2  nathanw 		sc->wi_tx_rate = 1;
   2279   1.17.2.2  nathanw 		break;
   2280   1.17.2.2  nathanw 	case IFM_IEEE80211_DS2:
   2281   1.17.2.2  nathanw 		sc->wi_tx_rate = 2;
   2282   1.17.2.2  nathanw 		break;
   2283   1.17.2.2  nathanw 	case IFM_AUTO:
   2284   1.17.2.2  nathanw 		sc->wi_tx_rate = 3;
   2285   1.17.2.2  nathanw 		break;
   2286  1.17.2.10  nathanw 	case IFM_IEEE80211_DS5:
   2287  1.17.2.10  nathanw 		sc->wi_tx_rate = 5;
   2288  1.17.2.10  nathanw 		break;
   2289   1.17.2.2  nathanw 	case IFM_IEEE80211_DS11:
   2290   1.17.2.2  nathanw 		sc->wi_tx_rate = 11;
   2291   1.17.2.2  nathanw 		break;
   2292   1.17.2.2  nathanw 	}
   2293   1.17.2.2  nathanw 
   2294   1.17.2.2  nathanw 	if (sc->sc_enabled != 0) {
   2295   1.17.2.2  nathanw 		if (otype != sc->wi_ptype ||
   2296   1.17.2.2  nathanw 		    orate != sc->wi_tx_rate)
   2297   1.17.2.2  nathanw 			wi_init(ifp);
   2298   1.17.2.2  nathanw 	}
   2299   1.17.2.2  nathanw 
   2300   1.17.2.2  nathanw 	ifp->if_baudrate = ifmedia_baudrate(sc->sc_media.ifm_cur->ifm_media);
   2301   1.17.2.2  nathanw 
   2302   1.17.2.2  nathanw 	return (0);
   2303   1.17.2.2  nathanw }
   2304   1.17.2.2  nathanw 
   2305   1.17.2.2  nathanw static void
   2306   1.17.2.2  nathanw wi_media_status(ifp, imr)
   2307   1.17.2.2  nathanw 	struct ifnet *ifp;
   2308   1.17.2.2  nathanw 	struct ifmediareq *imr;
   2309   1.17.2.2  nathanw {
   2310   1.17.2.2  nathanw 	struct wi_softc *sc = ifp->if_softc;
   2311   1.17.2.2  nathanw 
   2312   1.17.2.2  nathanw 	if (sc->sc_enabled == 0) {
   2313   1.17.2.2  nathanw 		imr->ifm_active = IFM_IEEE80211|IFM_NONE;
   2314   1.17.2.2  nathanw 		imr->ifm_status = 0;
   2315   1.17.2.2  nathanw 		return;
   2316   1.17.2.2  nathanw 	}
   2317   1.17.2.2  nathanw 
   2318   1.17.2.2  nathanw 	imr->ifm_active = sc->sc_media.ifm_cur->ifm_media;
   2319   1.17.2.2  nathanw 	imr->ifm_status = IFM_AVALID|IFM_ACTIVE;
   2320   1.17.2.2  nathanw }
   2321   1.17.2.2  nathanw 
   2322   1.17.2.2  nathanw static int
   2323   1.17.2.2  nathanw wi_set_nwkey(sc, nwkey)
   2324   1.17.2.2  nathanw 	struct wi_softc *sc;
   2325   1.17.2.2  nathanw 	struct ieee80211_nwkey *nwkey;
   2326   1.17.2.2  nathanw {
   2327   1.17.2.3  nathanw 	int i, error;
   2328   1.17.2.3  nathanw 	size_t len;
   2329   1.17.2.2  nathanw 	struct wi_req wreq;
   2330   1.17.2.2  nathanw 	struct wi_ltv_keys *wk = (struct wi_ltv_keys *)&wreq;
   2331   1.17.2.2  nathanw 
   2332   1.17.2.2  nathanw 	if (!sc->wi_has_wep)
   2333   1.17.2.2  nathanw 		return ENODEV;
   2334   1.17.2.2  nathanw 	if (nwkey->i_defkid <= 0 ||
   2335   1.17.2.2  nathanw 	    nwkey->i_defkid > IEEE80211_WEP_NKID)
   2336   1.17.2.2  nathanw 		return EINVAL;
   2337   1.17.2.2  nathanw 	memcpy(wk, &sc->wi_keys, sizeof(*wk));
   2338   1.17.2.2  nathanw 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
   2339   1.17.2.2  nathanw 		if (nwkey->i_key[i].i_keydat == NULL)
   2340   1.17.2.2  nathanw 			continue;
   2341   1.17.2.2  nathanw 		len = nwkey->i_key[i].i_keylen;
   2342   1.17.2.2  nathanw 		if (len > sizeof(wk->wi_keys[i].wi_keydat))
   2343   1.17.2.2  nathanw 			return EINVAL;
   2344   1.17.2.2  nathanw 		error = copyin(nwkey->i_key[i].i_keydat,
   2345   1.17.2.2  nathanw 		    wk->wi_keys[i].wi_keydat, len);
   2346   1.17.2.2  nathanw 		if (error)
   2347   1.17.2.2  nathanw 			return error;
   2348   1.17.2.2  nathanw 		wk->wi_keys[i].wi_keylen = htole16(len);
   2349   1.17.2.2  nathanw 	}
   2350   1.17.2.2  nathanw 
   2351   1.17.2.2  nathanw 	wk->wi_len = (sizeof(*wk) / 2) + 1;
   2352   1.17.2.2  nathanw 	wk->wi_type = WI_RID_DEFLT_CRYPT_KEYS;
   2353   1.17.2.2  nathanw 	if (sc->sc_enabled != 0) {
   2354   1.17.2.2  nathanw 		error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
   2355   1.17.2.2  nathanw 		if (error)
   2356   1.17.2.2  nathanw 			return error;
   2357   1.17.2.2  nathanw 	}
   2358   1.17.2.2  nathanw 	error = wi_setdef(sc, &wreq);
   2359   1.17.2.2  nathanw 	if (error)
   2360   1.17.2.2  nathanw 		return error;
   2361   1.17.2.2  nathanw 
   2362   1.17.2.2  nathanw 	wreq.wi_len = 2;
   2363   1.17.2.2  nathanw 	wreq.wi_type = WI_RID_TX_CRYPT_KEY;
   2364   1.17.2.2  nathanw 	wreq.wi_val[0] = htole16(nwkey->i_defkid - 1);
   2365   1.17.2.2  nathanw 	if (sc->sc_enabled != 0) {
   2366   1.17.2.2  nathanw 		error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
   2367   1.17.2.2  nathanw 		if (error)
   2368   1.17.2.2  nathanw 			return error;
   2369   1.17.2.2  nathanw 	}
   2370   1.17.2.2  nathanw 	error = wi_setdef(sc, &wreq);
   2371   1.17.2.2  nathanw 	if (error)
   2372   1.17.2.2  nathanw 		return error;
   2373   1.17.2.2  nathanw 
   2374   1.17.2.2  nathanw 	wreq.wi_type = WI_RID_ENCRYPTION;
   2375   1.17.2.2  nathanw 	wreq.wi_val[0] = htole16(nwkey->i_wepon);
   2376   1.17.2.2  nathanw 	if (sc->sc_enabled != 0) {
   2377   1.17.2.2  nathanw 		error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
   2378   1.17.2.2  nathanw 		if (error)
   2379   1.17.2.2  nathanw 			return error;
   2380   1.17.2.2  nathanw 	}
   2381   1.17.2.2  nathanw 	error = wi_setdef(sc, &wreq);
   2382   1.17.2.2  nathanw 	if (error)
   2383   1.17.2.2  nathanw 		return error;
   2384   1.17.2.2  nathanw 
   2385   1.17.2.2  nathanw 	if (sc->sc_enabled != 0)
   2386   1.17.2.2  nathanw 		wi_init(&sc->sc_ethercom.ec_if);
   2387   1.17.2.2  nathanw 	return 0;
   2388   1.17.2.2  nathanw }
   2389   1.17.2.2  nathanw 
   2390   1.17.2.2  nathanw static int
   2391   1.17.2.2  nathanw wi_get_nwkey(sc, nwkey)
   2392   1.17.2.2  nathanw 	struct wi_softc *sc;
   2393   1.17.2.2  nathanw 	struct ieee80211_nwkey *nwkey;
   2394   1.17.2.2  nathanw {
   2395   1.17.2.2  nathanw 	int i, len, error;
   2396   1.17.2.2  nathanw 	struct wi_ltv_keys *wk = &sc->wi_keys;
   2397   1.17.2.2  nathanw 
   2398   1.17.2.2  nathanw 	if (!sc->wi_has_wep)
   2399   1.17.2.2  nathanw 		return ENODEV;
   2400   1.17.2.2  nathanw 	nwkey->i_wepon = sc->wi_use_wep;
   2401   1.17.2.2  nathanw 	nwkey->i_defkid = sc->wi_tx_key + 1;
   2402   1.17.2.2  nathanw 
   2403   1.17.2.2  nathanw 	/* do not show any keys to non-root user */
   2404  1.17.2.14  nathanw 	error = suser(curproc->p_ucred, &curproc->p_acflag);
   2405   1.17.2.2  nathanw 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
   2406   1.17.2.2  nathanw 		if (nwkey->i_key[i].i_keydat == NULL)
   2407   1.17.2.2  nathanw 			continue;
   2408   1.17.2.2  nathanw 		/* error holds results of suser() for the first time */
   2409   1.17.2.2  nathanw 		if (error)
   2410   1.17.2.2  nathanw 			return error;
   2411   1.17.2.2  nathanw 		len = le16toh(wk->wi_keys[i].wi_keylen);
   2412   1.17.2.2  nathanw 		if (nwkey->i_key[i].i_keylen < len)
   2413   1.17.2.2  nathanw 			return ENOSPC;
   2414   1.17.2.2  nathanw 		nwkey->i_key[i].i_keylen = len;
   2415   1.17.2.2  nathanw 		error = copyout(wk->wi_keys[i].wi_keydat,
   2416   1.17.2.2  nathanw 		    nwkey->i_key[i].i_keydat, len);
   2417   1.17.2.2  nathanw 		if (error)
   2418   1.17.2.2  nathanw 			return error;
   2419   1.17.2.2  nathanw 	}
   2420   1.17.2.2  nathanw 	return 0;
   2421   1.17.2.2  nathanw }
   2422   1.17.2.2  nathanw 
   2423   1.17.2.2  nathanw static int
   2424   1.17.2.2  nathanw wi_set_pm(struct wi_softc *sc, struct ieee80211_power *power)
   2425   1.17.2.2  nathanw {
   2426   1.17.2.2  nathanw 
   2427   1.17.2.2  nathanw 	sc->wi_pm_enabled = power->i_enabled;
   2428   1.17.2.2  nathanw 	sc->wi_max_sleep = power->i_maxsleep;
   2429   1.17.2.2  nathanw 
   2430   1.17.2.2  nathanw 	if (sc->sc_enabled)
   2431   1.17.2.2  nathanw 		return (wi_init(&sc->sc_ethercom.ec_if));
   2432   1.17.2.2  nathanw 
   2433   1.17.2.2  nathanw 	return (0);
   2434   1.17.2.2  nathanw }
   2435   1.17.2.2  nathanw 
   2436   1.17.2.2  nathanw static int
   2437   1.17.2.2  nathanw wi_get_pm(struct wi_softc *sc, struct ieee80211_power *power)
   2438   1.17.2.2  nathanw {
   2439   1.17.2.2  nathanw 
   2440   1.17.2.2  nathanw 	power->i_enabled = sc->wi_pm_enabled;
   2441   1.17.2.2  nathanw 	power->i_maxsleep = sc->wi_max_sleep;
   2442   1.17.2.2  nathanw 
   2443   1.17.2.2  nathanw 	return (0);
   2444   1.17.2.2  nathanw }
   2445