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