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