Home | History | Annotate | Line # | Download | only in ic
wi.c revision 1.86
      1 /*	$NetBSD: wi.c,v 1.86 2002/09/26 23:47:57 martin 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.86 2002/09/26 23:47:57 martin 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 			error = 0;
   2299 			if (wreq.wi_len != 4) {
   2300 				error = EINVAL;
   2301 				break;
   2302 			}
   2303 			if (!sc->wi_scanning) {
   2304 				switch (sc->sc_firmware_type) {
   2305 				case WI_LUCENT:
   2306 					break;
   2307 				case WI_INTERSIL:
   2308 					wreq.wi_type = WI_RID_SCAN_REQ;
   2309 					error = wi_write_record(sc,
   2310 					    (struct wi_ltv_gen *)&wreq);
   2311 					break;
   2312 				case WI_SYMBOL:
   2313 					/*
   2314 					 * XXX only supported on 3.x ?
   2315 					 */
   2316 					wreq.wi_type = WI_RID_BCAST_SCAN_REQ;
   2317 					wreq.wi_val[0] =
   2318 					    BSCAN_BCAST | BSCAN_ONETIME;
   2319 					wreq.wi_len = 2;
   2320 					error = wi_write_record(sc,
   2321 					    (struct wi_ltv_gen *)&wreq);
   2322 					break;
   2323 				}
   2324 				if (!error) {
   2325 					sc->wi_scanning = 1;
   2326 					callout_reset(&sc->wi_scan_sh, hz * 1,
   2327 						wi_wait_scan, sc);
   2328 				}
   2329 			}
   2330 			break;
   2331 		default:
   2332 			error = 0;
   2333 			/*
   2334 			 * Filter stuff out based on what the
   2335 			 * card can do.
   2336 			 */
   2337 			if ((wreq.wi_type == WI_RID_ROAMING_MODE &&
   2338 			     (sc->wi_flags & WI_FLAGS_HAS_ROAMING) == 0) ||
   2339 			    (wreq.wi_type == WI_RID_CREATE_IBSS &&
   2340 			     (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS) == 0) ||
   2341 			    (wreq.wi_type == WI_RID_MICROWAVE_OVEN &&
   2342 			     (sc->wi_flags & WI_FLAGS_HAS_MOR) == 0))
   2343 				break;
   2344 
   2345 			if (wreq.wi_len > WI_MAX_DATALEN)
   2346 				error = EINVAL;
   2347 			else if (sc->sc_enabled != 0)
   2348 				error = wi_write_record(sc,
   2349 				    (struct wi_ltv_gen *)&wreq);
   2350 			if (error == 0)
   2351 				error = wi_setdef(sc, &wreq);
   2352 			if (error == 0 && sc->sc_enabled != 0)
   2353 				/* Reinitialize WaveLAN. */
   2354 				wi_init(ifp);
   2355 		}
   2356 		break;
   2357 	case SIOCS80211BSSID:
   2358 
   2359 		if (sc->wi_ptype != WI_PORTTYPE_IBSS &&
   2360 		    sc->wi_ptype != WI_PORTTYPE_BSS) {
   2361 			error = EINVAL;
   2362 			break;
   2363 		}
   2364 		/* don't join twice. */
   2365 		if (sc->wi_flags & WI_FLAGS_JOINING) {
   2366 			error = EAGAIN;
   2367 			break;
   2368 		}
   2369 
   2370 		(void)memcpy(&sc->wi_join_bssid,
   2371 		       &((struct ieee80211_bssid *)data)->i_bssid,
   2372 		       sizeof(sc->wi_join_bssid));
   2373 
   2374 		error = wi_join_bss(sc);
   2375 		break;
   2376 	case SIOCG80211BSSID:
   2377 		if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
   2378 			(void)memcpy(&((struct ieee80211_bssid *)data)->i_bssid,
   2379 			    LLADDR(ifp->if_sadl), IEEE80211_ADDR_LEN);
   2380 		} else {
   2381 			(void)memcpy(
   2382 			    &((struct ieee80211_bssid *)data)->i_bssid,
   2383 			    &sc->wi_current_bssid,
   2384 			    sizeof(sc->wi_current_bssid));
   2385 		}
   2386 		break;
   2387 	case SIOCS80211CHANNEL:
   2388 		error = wi_set_channel(sc, ((struct ieee80211_channel *)data));
   2389 		break;
   2390 	case SIOCG80211CHANNEL:
   2391 		error = wi_get_channel(sc, ((struct ieee80211_channel *)data));
   2392 		break;
   2393 	case SIOCG80211NWID:
   2394 		if (sc->sc_enabled == 0) {
   2395 			/* Return the desired ID */
   2396 			error = copyout(&sc->wi_netid, ifr->ifr_data,
   2397 			    sizeof(sc->wi_netid));
   2398 		} else {
   2399 			wreq.wi_type = WI_RID_CURRENT_SSID;
   2400 			wreq.wi_len = WI_MAX_DATALEN;
   2401 			if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) ||
   2402 			    le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN)
   2403 				error = EINVAL;
   2404 			else {
   2405 				wi_set_ssid(&nwid, (u_int8_t *)&wreq.wi_val[1],
   2406 				    le16toh(wreq.wi_val[0]));
   2407 				error = copyout(&nwid, ifr->ifr_data,
   2408 				    sizeof(nwid));
   2409 			}
   2410 		}
   2411 		break;
   2412 	case SIOCS80211NWID:
   2413 		error = copyin(ifr->ifr_data, &nwid, sizeof(nwid));
   2414 		if (error != 0)
   2415 			break;
   2416 		if (nwid.i_len > IEEE80211_NWID_LEN) {
   2417 			error = EINVAL;
   2418 			break;
   2419 		}
   2420 		if (sc->wi_netid.i_len == nwid.i_len &&
   2421 		    memcmp(sc->wi_netid.i_nwid, nwid.i_nwid, nwid.i_len) == 0)
   2422 			break;
   2423 		wi_set_ssid(&sc->wi_netid, nwid.i_nwid, nwid.i_len);
   2424 		if (sc->sc_enabled != 0)
   2425 			/* Reinitialize WaveLAN. */
   2426 			wi_init(ifp);
   2427 		break;
   2428 	case SIOCS80211NWKEY:
   2429 		error = wi_set_nwkey(sc, (struct ieee80211_nwkey *)data);
   2430 		break;
   2431 	case SIOCG80211NWKEY:
   2432 		error = wi_get_nwkey(sc, (struct ieee80211_nwkey *)data);
   2433 		break;
   2434 	case SIOCS80211POWER:
   2435 		error = wi_set_pm(sc, (struct ieee80211_power *)data);
   2436 		break;
   2437 	case SIOCG80211POWER:
   2438 		error = wi_get_pm(sc, (struct ieee80211_power *)data);
   2439 		break;
   2440 	case SIOCHOSTAP_ADD:
   2441 	case SIOCHOSTAP_DEL:
   2442 	case SIOCHOSTAP_GET:
   2443 	case SIOCHOSTAP_GETALL:
   2444 	case SIOCHOSTAP_GFLAGS:
   2445 	case SIOCHOSTAP_SFLAGS:
   2446 		/* Send all Host-AP specific ioctls to the Host-AP code. */
   2447 		error = wihap_ioctl(sc, command, data);
   2448 		break;
   2449 
   2450 	default:
   2451 		error = EINVAL;
   2452 		break;
   2453 	}
   2454 
   2455 	splx(s);
   2456 	return (error);
   2457 }
   2458 
   2459 static int
   2460 wi_init(ifp)
   2461 	struct ifnet *ifp;
   2462 {
   2463 	struct wi_softc *sc = ifp->if_softc;
   2464 	struct wi_req wreq;
   2465 	struct wi_ltv_macaddr mac;
   2466 	int s, error, id = 0, wasenabled;
   2467 
   2468 	if (!sc->sc_attached)
   2469 		return(ENODEV);
   2470 
   2471 	s = splnet();
   2472 	wasenabled = sc->sc_enabled;
   2473 	if (!sc->sc_enabled) {
   2474 		if ((error = (*sc->sc_enable)(sc)) != 0)
   2475 			goto out;
   2476 		sc->sc_enabled = 1;
   2477 	}
   2478 
   2479 	wi_stop(ifp, 0);
   2480 	/* Symbol firmware cannot be initialized more than once */
   2481 	if (!(sc->sc_firmware_type == WI_SYMBOL && wasenabled))
   2482 		wi_reset(sc);
   2483 
   2484 	/* Program max data length. */
   2485 	WI_SETVAL(WI_RID_MAX_DATALEN, sc->wi_max_data_len);
   2486 
   2487 	/* Enable/disable IBSS creation. */
   2488 	WI_SETVAL(WI_RID_CREATE_IBSS, sc->wi_create_ibss);
   2489 
   2490 	/* Set the port type. */
   2491 	WI_SETVAL(WI_RID_PORTTYPE, sc->wi_ptype);
   2492 
   2493 	/* Program the RTS/CTS threshold. */
   2494 	WI_SETVAL(WI_RID_RTS_THRESH, sc->wi_rts_thresh);
   2495 
   2496 	/* Program the TX rate */
   2497 	WI_SETVAL(WI_RID_TX_RATE, sc->wi_tx_rate);
   2498 
   2499 	/* Access point density */
   2500 	WI_SETVAL(WI_RID_SYSTEM_SCALE, sc->wi_ap_density);
   2501 
   2502 	/* Power Management Enabled */
   2503 	WI_SETVAL(WI_RID_PM_ENABLED, sc->wi_pm_enabled);
   2504 
   2505 	/* Power Managment Max Sleep */
   2506 	WI_SETVAL(WI_RID_MAX_SLEEP, sc->wi_max_sleep);
   2507 
   2508 	/* Roaming type */
   2509 	if (sc->wi_flags & WI_FLAGS_HAS_ROAMING)
   2510 		WI_SETVAL(WI_RID_ROAMING_MODE, sc->wi_roaming);
   2511 
   2512 	/* Specify the network name */
   2513 	wi_write_ssid(sc, WI_RID_DESIRED_SSID, &wreq, &sc->wi_netid);
   2514 
   2515 	/* Specify the IBSS name */
   2516 	if (sc->wi_netid.i_len != 0 &&
   2517 	    (sc->wi_ptype == WI_PORTTYPE_HOSTAP ||
   2518 	     (sc->wi_create_ibss && sc->wi_ptype == WI_PORTTYPE_IBSS)))
   2519 		wi_write_ssid(sc, WI_RID_OWN_SSID, &wreq, &sc->wi_netid);
   2520 	else
   2521 		wi_write_ssid(sc, WI_RID_OWN_SSID, &wreq, &sc->wi_ibssid);
   2522 
   2523 	/* Specify the frequency to use */
   2524 	WI_SETVAL(WI_RID_OWN_CHNL, sc->wi_create_channel);
   2525 
   2526 	/* Program the nodename. */
   2527 	wi_write_ssid(sc, WI_RID_NODENAME, &wreq, &sc->wi_nodeid);
   2528 
   2529 	/* Set our MAC address. */
   2530 	mac.wi_len = 4;
   2531 	mac.wi_type = WI_RID_MAC_NODE;
   2532 	memcpy(&mac.wi_mac_addr, sc->sc_macaddr, ETHER_ADDR_LEN);
   2533 	wi_write_record(sc, (struct wi_ltv_gen *)&mac);
   2534 
   2535 	/*
   2536 	 * Initialize promiscuous mode.
   2537 	 *	Being in the Host-AP mode causes a great
   2538 	 *	deal of pain if promiscuous mode is set.
   2539 	 *	Therefore we avoid confusing the firmware
   2540 	 *	and always reset promiscuous mode in Host-AP
   2541 	 *	mode.  Host-AP sees all the packets anyway.
   2542 	 */
   2543 	if (sc->wi_ptype != WI_PORTTYPE_HOSTAP &&
   2544 	    (ifp->if_flags & IFF_PROMISC) != 0) {
   2545 		WI_SETVAL(WI_RID_PROMISC, 1);
   2546 	} else {
   2547 		WI_SETVAL(WI_RID_PROMISC, 0);
   2548 	}
   2549 
   2550 	/* Configure WEP. */
   2551 	if (sc->wi_flags & WI_FLAGS_HAS_WEP) {
   2552 		WI_SETVAL(WI_RID_ENCRYPTION, sc->wi_use_wep);
   2553 		WI_SETVAL(WI_RID_TX_CRYPT_KEY, sc->wi_tx_key);
   2554 		sc->wi_keys.wi_len = (sizeof(struct wi_ltv_keys) / 2) + 1;
   2555 		sc->wi_keys.wi_type = WI_RID_DEFLT_CRYPT_KEYS;
   2556 		wi_write_record(sc, (struct wi_ltv_gen *)&sc->wi_keys);
   2557 		if (sc->sc_firmware_type != WI_LUCENT && sc->wi_use_wep) {
   2558 			/*
   2559 			 * ONLY HWB3163 EVAL-CARD Firmware version
   2560 			 * less than 0.8 variant2
   2561 			 *
   2562 			 *   If promiscuous mode disable, Prism2 chip
   2563 			 *  does not work with WEP .
   2564 			 * It is under investigation for details.
   2565 			 * (ichiro (at) netbsd.org)
   2566 			 */
   2567 			if (sc->sc_firmware_type == WI_INTERSIL &&
   2568 			    sc->sc_sta_firmware_ver < 802 ) {
   2569 				/* firm ver < 0.8 variant 2 */
   2570 				WI_SETVAL(WI_RID_PROMISC, 1);
   2571 			}
   2572 			WI_SETVAL(WI_RID_CNFAUTHMODE, sc->wi_authtype);
   2573 		}
   2574 	}
   2575 
   2576 	/* Set multicast filter. */
   2577 	wi_setmulti(sc);
   2578 
   2579 	sc->wi_flags &= ~(WI_FLAGS_JOINING | WI_FLAGS_CONNECTED |
   2580 	                  WI_FLAGS_AP_IN_RANGE);
   2581 
   2582 	/* Enable desired port */
   2583 	wi_cmd(sc, WI_CMD_ENABLE | sc->wi_portnum, 0, 0, 0);
   2584 
   2585 	/*  scanning variable is modal, therefore reinit to OFF, in case it was on. */
   2586 	sc->wi_scanning=0;
   2587 	sc->wi_naps=0;
   2588 
   2589 	if ((error = wi_alloc_nicmem(sc, WI_TX_BUFSIZE, &id)) != 0) {
   2590 		printf("%s: tx buffer allocation failed\n",
   2591 		    sc->sc_dev.dv_xname);
   2592 		goto out;
   2593 	}
   2594 	sc->wi_tx_data_id = id;
   2595 
   2596 	if ((error = wi_alloc_nicmem(sc, WI_TX_BUFSIZE, &id)) != 0) {
   2597 		printf("%s: mgmt. buffer allocation failed\n",
   2598 		    sc->sc_dev.dv_xname);
   2599 		goto out;
   2600 	}
   2601 	sc->wi_tx_mgmt_id = id;
   2602 
   2603 	/* Enable interrupts */
   2604 	CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
   2605 
   2606 	wihap_init(sc);
   2607 
   2608  out:
   2609 	if (error) {
   2610 		ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
   2611 		ifp->if_timer = 0;
   2612 		printf("%s: interface not running\n", sc->sc_dev.dv_xname);
   2613 		splx(s);
   2614 		return error;
   2615 	}
   2616 
   2617 	ifp->if_flags |= IFF_RUNNING;
   2618 	ifp->if_flags &= ~IFF_OACTIVE;
   2619 
   2620 	callout_reset(&sc->wi_inquire_ch, hz * 60, wi_inquire, sc);
   2621 
   2622 	splx(s);
   2623 	return 0;
   2624 }
   2625 
   2626 static const u_int32_t crc32_tab[] = {
   2627 	0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
   2628 	0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
   2629 	0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
   2630 	0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
   2631 	0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
   2632 	0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
   2633 	0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
   2634 	0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
   2635 	0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
   2636 	0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
   2637 	0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
   2638 	0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
   2639 	0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
   2640 	0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
   2641 	0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
   2642 	0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
   2643 	0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
   2644 	0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
   2645 	0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
   2646 	0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
   2647 	0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
   2648 	0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
   2649 	0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
   2650 	0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
   2651 	0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
   2652 	0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
   2653 	0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
   2654 	0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
   2655 	0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
   2656 	0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
   2657 	0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
   2658 	0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
   2659 	0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
   2660 	0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
   2661 	0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
   2662 	0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
   2663 	0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
   2664 	0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
   2665 	0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
   2666 	0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
   2667 	0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
   2668 	0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
   2669 	0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
   2670 	0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
   2671 	0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
   2672 	0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
   2673 	0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
   2674 	0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
   2675 	0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
   2676 	0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
   2677 	0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
   2678 	0x2d02ef8dL
   2679 };
   2680 
   2681 #define RC4STATE 256
   2682 #define RC4KEYLEN 16
   2683 #define RC4SWAP(x,y) \
   2684     do { u_int8_t t = state[x]; state[x] = state[y]; state[y] = t; } while(0)
   2685 
   2686 static void
   2687 wi_do_hostencrypt(struct wi_softc *sc, caddr_t buf, int len)
   2688 {
   2689 	u_int32_t i, crc, klen;
   2690 	u_int8_t state[RC4STATE], key[RC4KEYLEN];
   2691 	u_int8_t x, y, *dat;
   2692 
   2693 	if (!sc->wi_icv_flag) {
   2694 		sc->wi_icv = arc4random();
   2695 		sc->wi_icv_flag++;
   2696 	} else
   2697 		sc->wi_icv++;
   2698 	/*
   2699 	 * Skip 'bad' IVs from Fluhrer/Mantin/Shamir:
   2700 	 * (B, 255, N) with 3 <= B < 8
   2701 	 */
   2702 	if (sc->wi_icv >= 0x03ff00 &&
   2703             (sc->wi_icv & 0xf8ff00) == 0x00ff00)
   2704                 sc->wi_icv += 0x000100;
   2705 
   2706 	/* prepend 24bit IV to tx key, byte order does not matter */
   2707 	key[0] = sc->wi_icv >> 16;
   2708 	key[1] = sc->wi_icv >> 8;
   2709 	key[2] = sc->wi_icv;
   2710 
   2711 	klen = le16toh(sc->wi_keys.wi_keys[sc->wi_tx_key].wi_keylen) +
   2712 	    IEEE80211_WEP_IVLEN;
   2713 	klen = (klen >= RC4KEYLEN) ? RC4KEYLEN : RC4KEYLEN/2;
   2714 	bcopy((char *)&sc->wi_keys.wi_keys[sc->wi_tx_key].wi_keydat,
   2715 	    (char *)key + IEEE80211_WEP_IVLEN, klen - IEEE80211_WEP_IVLEN);
   2716 
   2717 	/* rc4 keysetup */
   2718 	x = y = 0;
   2719 	for (i = 0; i < RC4STATE; i++)
   2720 		state[i] = i;
   2721 	for (i = 0; i < RC4STATE; i++) {
   2722 		y = (key[x] + state[i] + y) % RC4STATE;
   2723 		RC4SWAP(i, y);
   2724 		x = (x + 1) % klen;
   2725 	}
   2726 
   2727 	/* output: IV, tx keyid, rc4(data), rc4(crc32(data)) */
   2728 	dat = buf;
   2729 	dat[0] = key[0];
   2730 	dat[1] = key[1];
   2731 	dat[2] = key[2];
   2732 	dat[3] = sc->wi_tx_key << 6;		/* pad and keyid */
   2733 	dat += 4;
   2734 
   2735 	/* compute rc4 over data, crc32 over data */
   2736 	crc = ~0;
   2737 	x = y = 0;
   2738 	for (i = 0; i < len; i++) {
   2739 		x = (x + 1) % RC4STATE;
   2740 		y = (state[x] + y) % RC4STATE;
   2741 		RC4SWAP(x, y);
   2742 		crc = crc32_tab[(crc ^ dat[i]) & 0xff] ^ (crc >> 8);
   2743 		dat[i] ^= state[(state[x] + state[y]) % RC4STATE];
   2744 	}
   2745 	crc = ~crc;
   2746 	dat += len;
   2747 
   2748 	/* append little-endian crc32 and encrypt */
   2749 	dat[0] = crc;
   2750 	dat[1] = crc >> 8;
   2751 	dat[2] = crc >> 16;
   2752 	dat[3] = crc >> 24;
   2753 	for (i = 0; i < IEEE80211_WEP_CRCLEN; i++) {
   2754 		x = (x + 1) % RC4STATE;
   2755 		y = (state[x] + y) % RC4STATE;
   2756 		RC4SWAP(x, y);
   2757 		dat[i] ^= state[(state[x] + state[y]) % RC4STATE];
   2758 	}
   2759 }
   2760 
   2761 static void
   2762 wi_start(ifp)
   2763 	struct ifnet		*ifp;
   2764 {
   2765 	struct wi_softc		*sc;
   2766 	struct mbuf		*m0;
   2767 	struct ether_header	*eh;
   2768 	int			id;
   2769 	int			len;
   2770 	struct wi_frame		*hdr;
   2771 	struct llc		*llc;
   2772 	u_int8_t		*body, *payload;
   2773 #if defined(WI_HOSTAP_POWERSAVE)
   2774 	int			more_data = 0;
   2775 #endif
   2776 
   2777 	sc = ifp->if_softc;
   2778 
   2779 	if (!sc->sc_attached)
   2780 		return;
   2781 
   2782 	if (ifp->if_flags & IFF_OACTIVE)
   2783 		return;
   2784 
   2785 	/* discard packets when disconnected. postpone sending packets when
   2786 	 * connected but out of range.
   2787 	 */
   2788 	if (!(sc->wi_flags & WI_FLAGS_AP_IN_RANGE) &&
   2789 	    (sc->wi_flags & WI_FLAGS_CONNECTED)) {
   2790 		return;
   2791 	}
   2792 	hdr = (struct wi_frame *)&sc->wi_txbuf;
   2793 
   2794 	body = (u_int8_t *)(hdr + 1);
   2795 
   2796 	if (sc->wi_ptype == WI_PORTTYPE_HOSTAP && sc->wi_use_wep) {
   2797 		llc = (struct llc *)(body + IEEE80211_WEP_IVLEN +
   2798 		    IEEE80211_WEP_KIDLEN);
   2799 	} else {
   2800 		llc = (struct llc *)body;
   2801 	}
   2802 
   2803 	payload = (u_int8_t *)(llc + 1);
   2804 
   2805  nextpkt:
   2806 #if defined(WI_HOSTAP_POWERSAVE)
   2807 	/* power-save queue, first. */
   2808 	if (sc->wi_ptype == WI_PORTTYPE_HOSTAP)
   2809 		m0 = wihap_dequeue(&sc->wi_hostap_info, &more_data);
   2810 
   2811 	if (m0 == NULL)
   2812 #endif /* WI_HOSTAP_POWERSAVE */
   2813 		IFQ_DEQUEUE(&ifp->if_snd, m0);
   2814 
   2815 	if (m0 == NULL)
   2816 		return;
   2817 
   2818 	bzero(hdr, sizeof(*hdr));
   2819 	hdr->wi_frame_ctl = htole16(WI_FTYPE_DATA);
   2820 	id = sc->wi_tx_data_id;
   2821 	eh = mtod(m0, struct ether_header *);
   2822 
   2823 #if defined(OPTIMIZE_RW_DATA)
   2824 	wi_rewind(sc);
   2825 #endif
   2826 
   2827 	if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
   2828 		if (wihap_check_tx(sc, m0, &hdr->wi_tx_rate) == 0)
   2829 			goto nextpkt;
   2830 #if defined(WI_HOSTAP_POWERSAVE)
   2831 		if (more_data)
   2832 			hdr->wi_frame_ctl |= htole16(WI_FCTL_PM);
   2833 #endif /* WI_HOSTAP_POWERSAVE */
   2834 	}
   2835 
   2836 	/*
   2837 	 * Use RFC1042 encoding for everything.
   2838 	 */
   2839 
   2840 	hdr->wi_tx_ctl |= htole16(WI_ENC_TX_802_11);
   2841 
   2842 	if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
   2843 		hdr->wi_frame_ctl |= htole16(WI_FCTL_FROMDS);
   2844 		memcpy(&hdr->wi_addr1, &eh->ether_dhost,
   2845 		    IEEE80211_ADDR_LEN);
   2846 		memcpy(&hdr->wi_addr2, LLADDR(ifp->if_sadl),
   2847 		    IEEE80211_ADDR_LEN);
   2848 		memcpy((char *)&hdr->wi_addr3,
   2849 		    (char *)&eh->ether_shost, IEEE80211_ADDR_LEN);
   2850 	} else {
   2851 		if (sc->wi_ptype == WI_PORTTYPE_BSS) {
   2852 			hdr->wi_frame_ctl |= htole16(WI_FCTL_TODS);
   2853 			memcpy(&hdr->wi_addr1, &sc->wi_current_bssid,
   2854 			    IEEE80211_ADDR_LEN);
   2855 			memcpy(&hdr->wi_addr3, &eh->ether_dhost,
   2856 			    IEEE80211_ADDR_LEN);
   2857 		} else {
   2858 			memcpy(&hdr->wi_addr1, &eh->ether_dhost,
   2859 			    IEEE80211_ADDR_LEN);
   2860 			memcpy(&hdr->wi_addr3, &sc->wi_current_bssid,
   2861 			    IEEE80211_ADDR_LEN);
   2862 		}
   2863 		memcpy(&hdr->wi_addr2, &eh->ether_shost,
   2864 		    IEEE80211_ADDR_LEN);
   2865 	}
   2866 
   2867 	len = sizeof(struct llc) - sizeof(struct ether_header) +
   2868 	    m0->m_pkthdr.len;
   2869 
   2870 	llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
   2871 	llc->llc_control = LLC_UI;
   2872 	llc->llc_snap.org_code[0] = 0;
   2873 	llc->llc_snap.org_code[1] = 0;
   2874 	llc->llc_snap.org_code[2] = 0;
   2875 	llc->llc_snap.ether_type = eh->ether_type;
   2876 
   2877 	m_copydata(m0, sizeof(struct ether_header),
   2878 	    m0->m_pkthdr.len - sizeof(struct ether_header),
   2879 	    payload);
   2880 
   2881 	if (sc->wi_ptype == WI_PORTTYPE_HOSTAP && sc->wi_use_wep) {
   2882 
   2883 		hdr->wi_frame_ctl |= htole16(WI_FCTL_WEP);
   2884 
   2885 		wi_do_hostencrypt(sc, body, len);
   2886 
   2887 		len += IEEE80211_WEP_IVLEN +
   2888 		    IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
   2889 	}
   2890 
   2891 	hdr->wi_dat_len = htole16(len);
   2892 
   2893 	wi_write_data(sc, id, 0, (caddr_t)&sc->wi_txbuf,
   2894 	    sizeof(struct wi_frame) + len);
   2895 
   2896 #if NBPFILTER > 0
   2897 	/*
   2898 	 * If there's a BPF listener, bounce a copy of
   2899 	 * this frame to him.
   2900 	 */
   2901 	wi_tap_802_3(sc, m0, hdr);
   2902 #endif
   2903 
   2904 	m_freem(m0);
   2905 
   2906 	if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0))
   2907 		printf("%s: xmit failed\n", sc->sc_dev.dv_xname);
   2908 
   2909 	ifp->if_flags |= IFF_OACTIVE;
   2910 
   2911 	/*
   2912 	 * Set a timeout in case the chip goes out to lunch.
   2913 	 */
   2914 	ifp->if_timer = 5;
   2915 
   2916 	return;
   2917 }
   2918 
   2919 int
   2920 wi_mgmt_xmit(sc, data, len)
   2921 	struct wi_softc		*sc;
   2922 	caddr_t			data;
   2923 	int			len;
   2924 {
   2925 	struct wi_frame		*tx_frame;
   2926 	int			id;
   2927 	struct wi_80211_hdr	*hdr;
   2928 	caddr_t			dptr;
   2929 	struct mbuf		*m0, *m1;
   2930 
   2931 #if defined(OPTIMIZE_RW_DATA)
   2932 	wi_rewind(sc);
   2933 #endif
   2934 
   2935 	if (!sc->sc_attached)
   2936 		return(ENODEV);
   2937 
   2938 	KASSERT(MHLEN >= sizeof(*tx_frame));
   2939 
   2940 	MGETHDR(m0, M_DONTWAIT, MT_DATA);
   2941 	if (m0 == NULL)
   2942 		return (ENOMEM);
   2943 	MGET(m1, M_DONTWAIT, MT_DATA);
   2944 	if (m1 == NULL) {
   2945 		m_free(m0);
   2946 		return (ENOMEM);
   2947 	}
   2948 
   2949 	tx_frame = mtod(m0, struct wi_frame *);
   2950 	memset(tx_frame, 0, sizeof(*tx_frame));
   2951 
   2952 	hdr = (struct wi_80211_hdr *)data;
   2953 	dptr = data + sizeof(struct wi_80211_hdr);
   2954 
   2955 	id = sc->wi_tx_mgmt_id;
   2956 
   2957 	memcpy(&tx_frame->wi_frame_ctl, hdr, sizeof(struct wi_80211_hdr));
   2958 
   2959 	tx_frame->wi_tx_ctl |= htole16(WI_ENC_TX_802_11);
   2960 	tx_frame->wi_dat_len = len - sizeof(struct wi_80211_hdr);
   2961 	tx_frame->wi_len = htole16(tx_frame->wi_dat_len);
   2962 
   2963 	tx_frame->wi_dat_len = htole16(tx_frame->wi_dat_len);
   2964 
   2965 	wi_write_data(sc, id, 0, (caddr_t)tx_frame, sizeof(*tx_frame));
   2966 	wi_write_data(sc, id, sizeof(*tx_frame), dptr,
   2967 	    (len - sizeof(struct wi_80211_hdr)));
   2968 
   2969 	m0->m_len = WI_SHORT_802_11_END; /* XXX */
   2970 	m0->m_next = m1;
   2971 	m1->m_data = dptr;	/* XXX */
   2972 	m1->m_len = len - sizeof(struct wi_80211_hdr);
   2973 	m1->m_next = 0;
   2974 
   2975 	m0->m_pkthdr.len = m0->m_len + m1->m_len;
   2976 
   2977 	wi_tap_802_11_plus(sc, m0);
   2978 
   2979 	m_freem(m0);
   2980 
   2981 	if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0)) {
   2982 		printf("%s: xmit failed\n", sc->sc_dev.dv_xname);
   2983 		return(EIO);
   2984 	}
   2985 
   2986 	return(0);
   2987 }
   2988 
   2989 static void
   2990 wi_stop(ifp, disable)
   2991 	struct ifnet *ifp;
   2992 {
   2993 	struct wi_softc	*sc = ifp->if_softc;
   2994 
   2995 	wihap_shutdown(sc);
   2996 
   2997 	if (!sc->sc_attached)
   2998 		return;
   2999 
   3000 	CSR_WRITE_2(sc, WI_INT_EN, 0);
   3001 	wi_cmd(sc, WI_CMD_DISABLE|sc->wi_portnum, 0, 0, 0);
   3002 
   3003 	callout_stop(&sc->wi_inquire_ch);
   3004 	callout_stop(&sc->wi_scan_sh);
   3005 
   3006 	if (disable) {
   3007 		if (sc->sc_enabled) {
   3008 			if (sc->sc_disable)
   3009 				(*sc->sc_disable)(sc);
   3010 			sc->sc_enabled = 0;
   3011 		}
   3012 	}
   3013 
   3014 	ifp->if_flags &= ~(IFF_OACTIVE | IFF_RUNNING);
   3015 	ifp->if_timer = 0;
   3016 }
   3017 
   3018 static void
   3019 wi_watchdog(ifp)
   3020 	struct ifnet		*ifp;
   3021 {
   3022 	struct wi_softc		*sc;
   3023 
   3024 	sc = ifp->if_softc;
   3025 
   3026 	printf("%s: device timeout\n", sc->sc_dev.dv_xname);
   3027 
   3028 	wi_init(ifp);
   3029 
   3030 	ifp->if_oerrors++;
   3031 
   3032 	return;
   3033 }
   3034 
   3035 void
   3036 wi_shutdown(sc)
   3037 	struct wi_softc *sc;
   3038 {
   3039 	int s;
   3040 
   3041 	s = splnet();
   3042 	if (sc->sc_enabled) {
   3043 		if (sc->sc_disable)
   3044 			(*sc->sc_disable)(sc);
   3045 		sc->sc_enabled = 0;
   3046 		wi_stop(&sc->sc_ethercom.ec_if, 0);
   3047 	}
   3048 
   3049 	splx(s);
   3050 }
   3051 
   3052 int
   3053 wi_activate(self, act)
   3054 	struct device *self;
   3055 	enum devact act;
   3056 {
   3057 	struct wi_softc *sc = (struct wi_softc *)self;
   3058 	int rv = 0, s;
   3059 
   3060 	s = splnet();
   3061 	switch (act) {
   3062 	case DVACT_ACTIVATE:
   3063 		rv = EOPNOTSUPP;
   3064 		break;
   3065 
   3066 	case DVACT_DEACTIVATE:
   3067 		if_deactivate(&sc->sc_ethercom.ec_if);
   3068 		break;
   3069 	}
   3070 	splx(s);
   3071 	return (rv);
   3072 }
   3073 
   3074 static void
   3075 wi_get_id(sc)
   3076 	struct wi_softc *sc;
   3077 {
   3078 	struct wi_ltv_ver       ver;
   3079 	struct wi_card_ident	*id;
   3080 
   3081 	/* getting chip identity */
   3082 	memset(&ver, 0, sizeof(ver));
   3083 	ver.wi_type = WI_RID_CARD_ID;
   3084 	ver.wi_len = 5;
   3085 	wi_read_record(sc, (struct wi_ltv_gen *)&ver);
   3086 	printf("%s: using ", sc->sc_dev.dv_xname);
   3087 
   3088 	sc->sc_firmware_type = WI_NOTYPE;
   3089 	for (id = wi_card_ident; id->card_name != NULL; id++) {
   3090 		if (le16toh(ver.wi_ver[0]) == id->card_id) {
   3091 			printf("%s", id->card_name);
   3092 			sc->sc_firmware_type = id->firm_type;
   3093 			break;
   3094 		}
   3095 	}
   3096 	if (sc->sc_firmware_type == WI_NOTYPE) {
   3097 		if (le16toh(ver.wi_ver[0]) & 0x8000) {
   3098 			printf("Unknown PRISM2 chip");
   3099 			sc->sc_firmware_type = WI_INTERSIL;
   3100 		} else {
   3101 			printf("Unknown Lucent chip");
   3102 			sc->sc_firmware_type = WI_LUCENT;
   3103 		}
   3104 	}
   3105 
   3106 	/* get primary firmware version (Only Prism chips) */
   3107 	if (sc->sc_firmware_type != WI_LUCENT) {
   3108 		memset(&ver, 0, sizeof(ver));
   3109 		ver.wi_type = WI_RID_PRI_IDENTITY;
   3110 		ver.wi_len = 5;
   3111 		wi_read_record(sc, (struct wi_ltv_gen *)&ver);
   3112 		LE16TOH(ver.wi_ver[1]);
   3113 		LE16TOH(ver.wi_ver[2]);
   3114 		LE16TOH(ver.wi_ver[3]);
   3115 		sc->sc_pri_firmware_ver = ver.wi_ver[2] * 10000 +
   3116 		    ver.wi_ver[3] * 100 + ver.wi_ver[1];
   3117 	}
   3118 
   3119 	/* get station firmware version */
   3120 	memset(&ver, 0, sizeof(ver));
   3121 	ver.wi_type = WI_RID_STA_IDENTITY;
   3122 	ver.wi_len = 5;
   3123 	wi_read_record(sc, (struct wi_ltv_gen *)&ver);
   3124 	LE16TOH(ver.wi_ver[1]);
   3125 	LE16TOH(ver.wi_ver[2]);
   3126 	LE16TOH(ver.wi_ver[3]);
   3127 	sc->sc_sta_firmware_ver = ver.wi_ver[2] * 10000 +
   3128 	    ver.wi_ver[3] * 100 + ver.wi_ver[1];
   3129 	if (sc->sc_firmware_type == WI_INTERSIL &&
   3130 	    (sc->sc_sta_firmware_ver == 10102 || sc->sc_sta_firmware_ver == 20102)) {
   3131 		struct wi_ltv_str sver;
   3132 		char *p;
   3133 
   3134 		memset(&sver, 0, sizeof(sver));
   3135 		sver.wi_type = WI_RID_SYMBOL_IDENTITY;
   3136 		sver.wi_len = 7;
   3137 		/* value should be the format like "V2.00-11" */
   3138 		if (wi_read_record(sc, (struct wi_ltv_gen *)&sver) == 0 &&
   3139 		    *(p = (char *)sver.wi_str) >= 'A' &&
   3140 		    p[2] == '.' && p[5] == '-' && p[8] == '\0') {
   3141 			sc->sc_firmware_type = WI_SYMBOL;
   3142 			sc->sc_sta_firmware_ver = (p[1] - '0') * 10000 +
   3143 			    (p[3] - '0') * 1000 + (p[4] - '0') * 100 +
   3144 			    (p[6] - '0') * 10 + (p[7] - '0');
   3145 		}
   3146 	}
   3147 
   3148 	printf("\n%s: %s Firmware: ", sc->sc_dev.dv_xname,
   3149 	     sc->sc_firmware_type == WI_LUCENT ? "Lucent" :
   3150 	    (sc->sc_firmware_type == WI_SYMBOL ? "Symbol" : "Intersil"));
   3151 	if (sc->sc_firmware_type != WI_LUCENT)	/* XXX */
   3152 	    printf("Primary (%u.%u.%u), ", sc->sc_pri_firmware_ver / 10000,
   3153 		    (sc->sc_pri_firmware_ver % 10000) / 100,
   3154 		    sc->sc_pri_firmware_ver % 100);
   3155 	printf("Station (%u.%u.%u)\n",
   3156 	    sc->sc_sta_firmware_ver / 10000, (sc->sc_sta_firmware_ver % 10000) / 100,
   3157 	    sc->sc_sta_firmware_ver % 100);
   3158 
   3159 	return;
   3160 }
   3161 
   3162 int
   3163 wi_detach(sc)
   3164 	struct wi_softc *sc;
   3165 {
   3166 	struct ifnet *ifp = sc->sc_ifp;
   3167 	int s;
   3168 
   3169 	if (!sc->sc_attached)
   3170 		return (0);
   3171 
   3172 	s = splnet();
   3173 	callout_stop(&sc->wi_inquire_ch);
   3174 
   3175 	/* Delete all remaining media. */
   3176 	ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
   3177 
   3178 	/* TBD detach all BPF listeners. */
   3179 	ether_ifdetach(ifp);
   3180 	if_detach(ifp);
   3181 	if (sc->sc_enabled) {
   3182 		if (sc->sc_disable)
   3183 			(*sc->sc_disable)(sc);
   3184 		sc->sc_enabled = 0;
   3185 	}
   3186 	splx(s);
   3187 	return (0);
   3188 }
   3189 
   3190 void
   3191 wi_power(sc, why)
   3192 	struct wi_softc *sc;
   3193 	int why;
   3194 {
   3195 	int s;
   3196 
   3197 	if (!sc->sc_enabled)
   3198 		return;
   3199 
   3200 	s = splnet();
   3201 	switch (why) {
   3202 	case PWR_SUSPEND:
   3203 	case PWR_STANDBY:
   3204 		wi_stop(sc->sc_ifp, 0);
   3205 		if (sc->sc_enabled) {
   3206 			if (sc->sc_disable)
   3207 				(*sc->sc_disable)(sc);
   3208 		}
   3209 		break;
   3210 	case PWR_RESUME:
   3211 		sc->sc_enabled = 0;
   3212 		wi_init(sc->sc_ifp);
   3213 		(void)wi_intr(sc);
   3214 		break;
   3215 	case PWR_SOFTSUSPEND:
   3216 	case PWR_SOFTSTANDBY:
   3217 	case PWR_SOFTRESUME:
   3218 		break;
   3219 	}
   3220 	splx(s);
   3221 }
   3222 
   3223 static int
   3224 wi_set_ssid(ws, id, len)
   3225 	struct ieee80211_nwid *ws;
   3226 	u_int8_t *id;
   3227 	int len;
   3228 {
   3229 
   3230 	if (len > IEEE80211_NWID_LEN)
   3231 		return (EINVAL);
   3232 	ws->i_len = len;
   3233 	memcpy(ws->i_nwid, id, len);
   3234 	return (0);
   3235 }
   3236 
   3237 static void
   3238 wi_request_fill_ssid(wreq, ws)
   3239 	struct wi_req *wreq;
   3240 	struct ieee80211_nwid *ws;
   3241 {
   3242 	int len = ws->i_len;
   3243 
   3244 	memset(&wreq->wi_val[0], 0, sizeof(wreq->wi_val));
   3245 	wreq->wi_val[0] = htole16(len);
   3246 	wreq->wi_len = roundup(len, 2) / 2 + 2;
   3247 	memcpy(&wreq->wi_val[1], ws->i_nwid, len);
   3248 }
   3249 
   3250 static int
   3251 wi_write_ssid(sc, type, wreq, ws)
   3252 	struct wi_softc *sc;
   3253 	int type;
   3254 	struct wi_req *wreq;
   3255 	struct ieee80211_nwid *ws;
   3256 {
   3257 
   3258 	wreq->wi_type = type;
   3259 	wi_request_fill_ssid(wreq, ws);
   3260 	return (wi_write_record(sc, (struct wi_ltv_gen *)wreq));
   3261 }
   3262 
   3263 static int
   3264 wi_sync_media(sc, ptype, txrate)
   3265 	struct wi_softc *sc;
   3266 	int ptype;
   3267 	int txrate;
   3268 {
   3269 	int media = sc->sc_media.ifm_cur->ifm_media;
   3270 	int options = IFM_OPTIONS(media);
   3271 	int subtype;
   3272 
   3273 	switch (txrate) {
   3274 	case 1:
   3275 		subtype = IFM_IEEE80211_DS1;
   3276 		break;
   3277 	case 2:
   3278 		subtype = IFM_IEEE80211_DS2;
   3279 		break;
   3280 	case 3:
   3281 		subtype = IFM_AUTO;
   3282 		break;
   3283 	case 5:
   3284 		subtype = IFM_IEEE80211_DS5;
   3285 		break;
   3286 	case 11:
   3287 		subtype = IFM_IEEE80211_DS11;
   3288 		break;
   3289 	default:
   3290 		subtype = IFM_MANUAL;		/* Unable to represent */
   3291 		break;
   3292 	}
   3293 
   3294 	options &= ~IFM_OMASK;
   3295 	switch (ptype) {
   3296 	case WI_PORTTYPE_BSS:
   3297 		/* default port type */
   3298 		break;
   3299 	case WI_PORTTYPE_ADHOC:
   3300 		options |= IFM_IEEE80211_ADHOC | IFM_FLAG0;
   3301 		break;
   3302 	case WI_PORTTYPE_HOSTAP:
   3303 		options |= IFM_IEEE80211_HOSTAP;
   3304 		break;
   3305 	case WI_PORTTYPE_IBSS:
   3306 		options |= IFM_IEEE80211_ADHOC;
   3307 		break;
   3308 	default:
   3309 		subtype = IFM_MANUAL;		/* Unable to represent */
   3310 		break;
   3311 	}
   3312 	media = IFM_MAKEWORD(IFM_TYPE(media), subtype, options,
   3313 	    IFM_INST(media));
   3314 	if (ifmedia_match(&sc->sc_media, media, sc->sc_media.ifm_mask) == NULL)
   3315 		return (EINVAL);
   3316 	ifmedia_set(&sc->sc_media, media);
   3317 	sc->wi_ptype = ptype;
   3318 	sc->wi_tx_rate = txrate;
   3319 	return (0);
   3320 }
   3321 
   3322 static int
   3323 wi_media_change(ifp)
   3324 	struct ifnet *ifp;
   3325 {
   3326 	struct wi_softc *sc = ifp->if_softc;
   3327 	int otype = sc->wi_ptype;
   3328 	int orate = sc->wi_tx_rate;
   3329 	int ocreate_ibss = sc->wi_create_ibss;
   3330 
   3331 	sc->wi_create_ibss = 0;
   3332 
   3333 	switch (sc->sc_media.ifm_cur->ifm_media & IFM_OMASK) {
   3334 	case 0:
   3335 		sc->wi_ptype = WI_PORTTYPE_BSS;
   3336 		break;
   3337 	case IFM_IEEE80211_HOSTAP:
   3338 		sc->wi_ptype = WI_PORTTYPE_HOSTAP;
   3339 		break;
   3340 	case IFM_IEEE80211_ADHOC:
   3341 		sc->wi_ptype = WI_PORTTYPE_IBSS;
   3342 		if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
   3343 			sc->wi_create_ibss = 1;
   3344 		break;
   3345 	case IFM_IEEE80211_ADHOC | IFM_FLAG0:
   3346 		sc->wi_ptype = WI_PORTTYPE_ADHOC;
   3347 		break;
   3348 	default:
   3349 		/* Invalid combination. */
   3350 		sc->wi_create_ibss = ocreate_ibss;
   3351 		return (EINVAL);
   3352 	}
   3353 
   3354 	switch (IFM_SUBTYPE(sc->sc_media.ifm_cur->ifm_media)) {
   3355 	case IFM_IEEE80211_DS1:
   3356 		sc->wi_tx_rate = 1;
   3357 		break;
   3358 	case IFM_IEEE80211_DS2:
   3359 		sc->wi_tx_rate = 2;
   3360 		break;
   3361 	case IFM_AUTO:
   3362 		sc->wi_tx_rate = 3;
   3363 		break;
   3364 	case IFM_IEEE80211_DS5:
   3365 		sc->wi_tx_rate = 5;
   3366 		break;
   3367 	case IFM_IEEE80211_DS11:
   3368 		sc->wi_tx_rate = 11;
   3369 		break;
   3370 	}
   3371 
   3372 	if (sc->sc_enabled != 0) {
   3373 		if (otype != sc->wi_ptype ||
   3374 		    orate != sc->wi_tx_rate ||
   3375 		    ocreate_ibss != sc->wi_create_ibss)
   3376 			wi_init(ifp);
   3377 	}
   3378 
   3379 	ifp->if_baudrate = ifmedia_baudrate(sc->sc_media.ifm_cur->ifm_media);
   3380 
   3381 	return (0);
   3382 }
   3383 
   3384 static void
   3385 wi_media_status(ifp, imr)
   3386 	struct ifnet *ifp;
   3387 	struct ifmediareq *imr;
   3388 {
   3389 	struct wi_req	wreq;
   3390 	struct wi_softc *sc = ifp->if_softc;
   3391 
   3392 	if (sc->sc_enabled == 0) {
   3393 		imr->ifm_active = IFM_IEEE80211|IFM_NONE;
   3394 		imr->ifm_status = 0;
   3395 		return;
   3396 	}
   3397 
   3398 	if (sc->wi_tx_rate == 3) {
   3399 		imr->ifm_active = IFM_IEEE80211|IFM_AUTO;
   3400 		switch (sc->wi_ptype) {
   3401 		case WI_PORTTYPE_ADHOC:
   3402 			imr->ifm_active |= IFM_FLAG0;
   3403 			/* fall through */
   3404 		case WI_PORTTYPE_IBSS:
   3405 			imr->ifm_active |= IFM_IEEE80211_ADHOC;
   3406 			break;
   3407 		case WI_PORTTYPE_HOSTAP:
   3408 			imr->ifm_active |= IFM_IEEE80211_HOSTAP;
   3409 			break;
   3410 		default:
   3411 			/* do nothing for BSS, WDS, or unknown. */
   3412 			break;
   3413 		}
   3414 		wreq.wi_type = WI_RID_CUR_TX_RATE;
   3415 		wreq.wi_len = WI_MAX_DATALEN;
   3416 		if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0) {
   3417 			switch(wreq.wi_val[0]) {
   3418 			case 1:
   3419 				imr->ifm_active |= IFM_IEEE80211_DS1;
   3420 				break;
   3421 			case 2:
   3422 				imr->ifm_active |= IFM_IEEE80211_DS2;
   3423 				break;
   3424 			case 6:
   3425 				imr->ifm_active |= IFM_IEEE80211_DS5;
   3426 				break;
   3427 			case 11:
   3428 				imr->ifm_active |= IFM_IEEE80211_DS11;
   3429 				break;
   3430 			}
   3431 		}
   3432 	} else {
   3433 		imr->ifm_active = sc->sc_media.ifm_cur->ifm_media;
   3434 	}
   3435 
   3436 	imr->ifm_status = IFM_AVALID;
   3437 	switch (sc->wi_ptype) {
   3438 	case WI_PORTTYPE_IBSS:
   3439 		/*
   3440 		 * XXX: It would be nice if we could give some actually
   3441 		 * useful status like whether we joined another IBSS or
   3442 		 * created one ourselves.
   3443 		 */
   3444 		/* fall through */
   3445 	case WI_PORTTYPE_HOSTAP:
   3446 		imr->ifm_status |= IFM_ACTIVE;
   3447 		break;
   3448 	case WI_PORTTYPE_BSS:
   3449 	default:
   3450 #if 0
   3451 		wreq.wi_type = WI_RID_COMMQUAL;
   3452 		wreq.wi_len = WI_MAX_DATALEN;
   3453 		if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0 &&
   3454 		    wreq.wi_val[0] != 0)
   3455 #else
   3456 		if (sc->wi_flags & WI_FLAGS_CONNECTED)
   3457 #endif
   3458 			imr->ifm_status |= IFM_ACTIVE;
   3459 	}
   3460 }
   3461 
   3462 static int
   3463 wi_set_nwkey(sc, nwkey)
   3464 	struct wi_softc *sc;
   3465 	struct ieee80211_nwkey *nwkey;
   3466 {
   3467 	int i, error;
   3468 	size_t len;
   3469 	struct wi_req wreq;
   3470 	struct wi_ltv_keys *wk = (struct wi_ltv_keys *)&wreq;
   3471 
   3472 	if ((sc->wi_flags & WI_FLAGS_HAS_WEP) == 0)
   3473 		return ENODEV;
   3474 	if (nwkey->i_defkid <= 0 ||
   3475 	    nwkey->i_defkid > IEEE80211_WEP_NKID)
   3476 		return EINVAL;
   3477 	memcpy(wk, &sc->wi_keys, sizeof(*wk));
   3478 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
   3479 		if (nwkey->i_key[i].i_keydat == NULL)
   3480 			continue;
   3481 		len = nwkey->i_key[i].i_keylen;
   3482 		if (len > sizeof(wk->wi_keys[i].wi_keydat))
   3483 			return EINVAL;
   3484 		error = copyin(nwkey->i_key[i].i_keydat,
   3485 		    wk->wi_keys[i].wi_keydat, len);
   3486 		if (error)
   3487 			return error;
   3488 		wk->wi_keys[i].wi_keylen = htole16(len);
   3489 	}
   3490 
   3491 	wk->wi_len = (sizeof(*wk) / 2) + 1;
   3492 	wk->wi_type = WI_RID_DEFLT_CRYPT_KEYS;
   3493 	if (sc->sc_enabled != 0) {
   3494 		error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
   3495 		if (error)
   3496 			return error;
   3497 	}
   3498 	error = wi_setdef(sc, &wreq);
   3499 	if (error)
   3500 		return error;
   3501 
   3502 	wreq.wi_len = 2;
   3503 	wreq.wi_type = WI_RID_TX_CRYPT_KEY;
   3504 	wreq.wi_val[0] = htole16(nwkey->i_defkid - 1);
   3505 	if (sc->sc_enabled != 0) {
   3506 		error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
   3507 		if (error)
   3508 			return error;
   3509 	}
   3510 	error = wi_setdef(sc, &wreq);
   3511 	if (error)
   3512 		return error;
   3513 
   3514 	wreq.wi_type = WI_RID_ENCRYPTION;
   3515 	wreq.wi_val[0] = htole16(nwkey->i_wepon);
   3516 	if (sc->sc_enabled != 0) {
   3517 		error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
   3518 		if (error)
   3519 			return error;
   3520 	}
   3521 	error = wi_setdef(sc, &wreq);
   3522 	if (error)
   3523 		return error;
   3524 
   3525 	if (sc->sc_enabled != 0)
   3526 		wi_init(&sc->sc_ethercom.ec_if);
   3527 	return 0;
   3528 }
   3529 
   3530 static int
   3531 wi_get_nwkey(sc, nwkey)
   3532 	struct wi_softc *sc;
   3533 	struct ieee80211_nwkey *nwkey;
   3534 {
   3535 	int i, len, error;
   3536 	struct wi_ltv_keys *wk = &sc->wi_keys;
   3537 
   3538 	if ((sc->wi_flags & WI_FLAGS_HAS_WEP) == 0)
   3539 		return ENODEV;
   3540 	nwkey->i_wepon = sc->wi_use_wep;
   3541 	nwkey->i_defkid = sc->wi_tx_key + 1;
   3542 
   3543 	/* do not show any keys to non-root user */
   3544 	error = suser(curproc->p_ucred, &curproc->p_acflag);
   3545 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
   3546 		if (nwkey->i_key[i].i_keydat == NULL)
   3547 			continue;
   3548 		/* error holds results of suser() for the first time */
   3549 		if (error)
   3550 			return error;
   3551 		len = le16toh(wk->wi_keys[i].wi_keylen);
   3552 		if (nwkey->i_key[i].i_keylen < len)
   3553 			return ENOSPC;
   3554 		nwkey->i_key[i].i_keylen = len;
   3555 		error = copyout(wk->wi_keys[i].wi_keydat,
   3556 		    nwkey->i_key[i].i_keydat, len);
   3557 		if (error)
   3558 			return error;
   3559 	}
   3560 	return 0;
   3561 }
   3562 
   3563 static int
   3564 wi_set_pm(struct wi_softc *sc, struct ieee80211_power *power)
   3565 {
   3566 
   3567 	sc->wi_pm_enabled = power->i_enabled;
   3568 	sc->wi_max_sleep = power->i_maxsleep;
   3569 
   3570 	if (sc->sc_enabled)
   3571 		return (wi_init(&sc->sc_ethercom.ec_if));
   3572 
   3573 	return (0);
   3574 }
   3575 
   3576 static int
   3577 wi_get_pm(struct wi_softc *sc, struct ieee80211_power *power)
   3578 {
   3579 
   3580 	power->i_enabled = sc->wi_pm_enabled;
   3581 	power->i_maxsleep = sc->wi_max_sleep;
   3582 
   3583 	return (0);
   3584 }
   3585 
   3586 static int
   3587 wi_set_channel(struct wi_softc *sc, struct ieee80211_channel *channel)
   3588 {
   3589 	int do_init = 0, error = 0;
   3590 	if (channel->i_channel != 0 &&
   3591 	    !(sc->wi_channels & (1 << (channel->i_channel - 1)))) {
   3592 		return EINVAL;
   3593 	}
   3594 	switch (sc->wi_ptype) {
   3595 	default:
   3596 	case WI_PORTTYPE_IBSS:
   3597 	case WI_PORTTYPE_ADHOC: /* set channel of BSS to join/create */
   3598 
   3599 		if (channel->i_channel != 0 &&
   3600 		    channel->i_channel != sc->wi_create_channel) {
   3601 			sc->wi_create_channel = channel->i_channel;
   3602 			if (sc->sc_enabled)
   3603 				do_init = 1;
   3604 		}
   3605 		/* fall through */
   3606 	case WI_PORTTYPE_BSS: /* set channel of BSS to join */
   3607 
   3608 		/* We are warned not to join while a join is pending.
   3609 		 * Our next opportunity comes after a LinkStatus notification.
   3610 		 */
   3611 		if (sc->wi_flags & WI_FLAGS_JOINING) {
   3612 			error = EAGAIN;
   3613 			break;
   3614 		}
   3615 		sc->wi_join_channel = channel->i_channel;
   3616 		error = wi_join_bss(sc);
   3617 		break;
   3618 	case WI_PORTTYPE_HOSTAP: /* set channel of BSS to create */
   3619 		if (channel->i_channel == 0) {
   3620 			error = EINVAL;
   3621 			break;
   3622 		}
   3623 		if (channel->i_channel == sc->wi_create_channel)
   3624 			break;
   3625 		sc->wi_create_channel = channel->i_channel;
   3626 		if (sc->sc_enabled)
   3627 			do_init = 1;
   3628 		break;
   3629 	}
   3630 	if (!error && do_init)
   3631 		error = wi_init(sc->sc_ifp);
   3632 	return error;
   3633 }
   3634 
   3635 static int
   3636 wi_get_channel(struct wi_softc *sc, struct ieee80211_channel *channel)
   3637 {
   3638 	switch (sc->wi_ptype) {
   3639 	default:
   3640 	case WI_PORTTYPE_IBSS:
   3641 	case WI_PORTTYPE_ADHOC:
   3642 		if (!(sc->wi_flags & WI_FLAGS_CONNECTED)) {
   3643 			/* return channel of BSS to create */
   3644 			channel->i_channel = sc->wi_create_channel;
   3645 			break;
   3646 		}
   3647 		/* fall through */
   3648 	case WI_PORTTYPE_BSS:
   3649 		if (sc->wi_flags & WI_FLAGS_CONNECTED) {
   3650 			/* return channel of connected BSS */
   3651 			channel->i_channel = sc->wi_current_channel;
   3652 			break;
   3653 		}
   3654 		/* return channel of BSS to join */
   3655 		channel->i_channel = sc->wi_join_channel;
   3656 		break;
   3657 	case WI_PORTTYPE_HOSTAP:
   3658 		/* return channel of BSS to create */
   3659 		channel->i_channel = sc->wi_create_channel;
   3660 		break;
   3661 	}
   3662 	return 0;
   3663 }
   3664