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