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