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