xref: /openbsd-src/sys/dev/ic/if_wi.c (revision 8500990981f885cbe5e6a4958549cacc238b5ae6)
1 /*	$OpenBSD: if_wi.c,v 1.101 2003/10/26 15:34:15 drahn Exp $	*/
2 
3 /*
4  * Copyright (c) 1997, 1998, 1999
5  *	Bill Paul <wpaul@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  *	From: if_wi.c,v 1.7 1999/07/04 14:40:22 wpaul Exp $
35  */
36 
37 /*
38  * Lucent WaveLAN/IEEE 802.11 driver for OpenBSD.
39  *
40  * Originally written by Bill Paul <wpaul@ctr.columbia.edu>
41  * Electrical Engineering Department
42  * Columbia University, New York City
43  */
44 
45 /*
46  * The WaveLAN/IEEE adapter is the second generation of the WaveLAN
47  * from Lucent. Unlike the older cards, the new ones are programmed
48  * entirely via a firmware-driven controller called the Hermes.
49  * Unfortunately, Lucent will not release the Hermes programming manual
50  * without an NDA (if at all). What they do release is an API library
51  * called the HCF (Hardware Control Functions) which is supposed to
52  * do the device-specific operations of a device driver for you. The
53  * publicly available version of the HCF library (the 'HCF Light') is
54  * a) extremely gross, b) lacks certain features, particularly support
55  * for 802.11 frames, and c) is contaminated by the GNU Public License.
56  *
57  * This driver does not use the HCF or HCF Light at all. Instead, it
58  * programs the Hermes controller directly, using information gleaned
59  * from the HCF Light code and corresponding documentation.
60  */
61 
62 #define WI_HERMES_AUTOINC_WAR	/* Work around data write autoinc bug. */
63 #define WI_HERMES_STATS_WAR	/* Work around stats counter bug. */
64 
65 #include "bpfilter.h"
66 
67 #include <sys/param.h>
68 #include <sys/systm.h>
69 #include <sys/sockio.h>
70 #include <sys/mbuf.h>
71 #include <sys/malloc.h>
72 #include <sys/kernel.h>
73 #include <sys/proc.h>
74 #include <sys/socket.h>
75 #include <sys/device.h>
76 
77 #include <net/if.h>
78 #include <net/if_dl.h>
79 #include <net/if_media.h>
80 #include <net/if_types.h>
81 
82 #ifdef INET
83 #include <netinet/in.h>
84 #include <netinet/in_systm.h>
85 #include <netinet/in_var.h>
86 #include <netinet/ip.h>
87 #include <netinet/if_ether.h>
88 #endif
89 
90 #include <net/if_ieee80211.h>
91 
92 #if NBPFILTER > 0
93 #include <net/bpf.h>
94 #endif
95 
96 #include <machine/bus.h>
97 
98 #include <dev/rndvar.h>
99 
100 #include <dev/ic/if_wireg.h>
101 #include <dev/ic/if_wi_ieee.h>
102 #include <dev/ic/if_wivar.h>
103 
104 #include <crypto/arc4.h>
105 
106 #define BPF_MTAP(if,mbuf) bpf_mtap((if)->if_bpf, (mbuf))
107 #define BPFATTACH(if_bpf,if,dlt,sz)
108 #define STATIC
109 
110 #ifdef WIDEBUG
111 
112 u_int32_t	widebug = WIDEBUG;
113 
114 #define WID_INTR	0x01
115 #define WID_START	0x02
116 #define WID_IOCTL	0x04
117 #define WID_INIT	0x08
118 #define WID_STOP	0x10
119 #define WID_RESET	0x20
120 
121 #define DPRINTF(mask,args) if (widebug & (mask)) printf args;
122 
123 #else	/* !WIDEBUG */
124 #define DPRINTF(mask,args)
125 #endif	/* WIDEBUG */
126 
127 #if !defined(lint) && !defined(__OpenBSD__)
128 static const char rcsid[] =
129 	"$OpenBSD: if_wi.c,v 1.101 2003/10/26 15:34:15 drahn Exp $";
130 #endif	/* lint */
131 
132 #ifdef foo
133 static u_int8_t	wi_mcast_addr[6] = { 0x01, 0x60, 0x1D, 0x00, 0x01, 0x00 };
134 #endif
135 
136 STATIC void wi_reset(struct wi_softc *);
137 STATIC int wi_ioctl(struct ifnet *, u_long, caddr_t);
138 STATIC void wi_init_io(struct wi_softc *);
139 STATIC void wi_start(struct ifnet *);
140 STATIC void wi_watchdog(struct ifnet *);
141 STATIC void wi_shutdown(void *);
142 STATIC void wi_rxeof(struct wi_softc *);
143 STATIC void wi_txeof(struct wi_softc *, int);
144 STATIC void wi_update_stats(struct wi_softc *);
145 STATIC void wi_setmulti(struct wi_softc *);
146 
147 STATIC int wi_cmd_io(struct wi_softc *, int, int, int, int);
148 STATIC int wi_read_record_io(struct wi_softc *, struct wi_ltv_gen *);
149 STATIC int wi_write_record_io(struct wi_softc *, struct wi_ltv_gen *);
150 STATIC int wi_read_data_io(struct wi_softc *, int,
151 					int, caddr_t, int);
152 STATIC int wi_write_data_io(struct wi_softc *, int,
153 					int, caddr_t, int);
154 STATIC int wi_seek(struct wi_softc *, int, int, int);
155 
156 STATIC void wi_inquire(void *);
157 STATIC int wi_setdef(struct wi_softc *, struct wi_req *);
158 STATIC void wi_get_id(struct wi_softc *);
159 
160 STATIC int wi_media_change(struct ifnet *);
161 STATIC void wi_media_status(struct ifnet *, struct ifmediareq *);
162 
163 STATIC int wi_set_ssid(struct ieee80211_nwid *, u_int8_t *, int);
164 STATIC int wi_set_nwkey(struct wi_softc *, struct ieee80211_nwkey *);
165 STATIC int wi_get_nwkey(struct wi_softc *, struct ieee80211_nwkey *);
166 STATIC int wi_sync_media(struct wi_softc *, int, int);
167 STATIC int wi_set_pm(struct wi_softc *, struct ieee80211_power *);
168 STATIC int wi_get_pm(struct wi_softc *, struct ieee80211_power *);
169 
170 STATIC int wi_get_debug(struct wi_softc *, struct wi_req *);
171 STATIC int wi_set_debug(struct wi_softc *, struct wi_req *);
172 
173 STATIC void wi_do_hostencrypt(struct wi_softc *, caddr_t, int);
174 STATIC int wi_do_hostdecrypt(struct wi_softc *, caddr_t, int);
175 
176 STATIC int wi_alloc_nicmem_io(struct wi_softc *, int, int *);
177 STATIC int wi_get_fid_io(struct wi_softc *sc, int fid);
178 STATIC void wi_intr_enable(struct wi_softc *sc, int mode);
179 STATIC void wi_intr_ack(struct wi_softc *sc, int mode);
180 
181 /* Autoconfig definition of driver back-end */
182 struct cfdriver wi_cd = {
183 	NULL, "wi", DV_IFNET
184 };
185 
186 const struct wi_card_ident wi_card_ident[] = {
187 	WI_CARD_IDS
188 };
189 
190 struct wi_funcs wi_func_io = {
191         wi_cmd_io,
192         wi_read_record_io,
193         wi_write_record_io,
194         wi_alloc_nicmem_io,
195         wi_read_data_io,
196         wi_write_data_io,
197         wi_get_fid_io,
198         wi_init_io,
199 
200         wi_start,
201         wi_ioctl,
202         wi_watchdog,
203         wi_inquire,
204 };
205 
206 int
207 wi_attach(struct wi_softc *sc, struct wi_funcs *funcs)
208 {
209 	struct wi_ltv_macaddr	mac;
210 	struct wi_ltv_gen	gen;
211 	struct ifnet		*ifp;
212 	int			error;
213 
214 	sc->sc_funcs = funcs;
215 
216 	wi_reset(sc);
217 
218 	/* Read the station address. */
219 	mac.wi_type = WI_RID_MAC_NODE;
220 	mac.wi_len = 4;
221 	error = wi_read_record(sc, (struct wi_ltv_gen *)&mac);
222 	if (error) {
223 		printf(": unable to read station address\n");
224 		return (error);
225 	}
226 	bcopy((char *)&mac.wi_mac_addr, (char *)&sc->sc_arpcom.ac_enaddr,
227 	    ETHER_ADDR_LEN);
228 
229 	wi_get_id(sc);
230 	printf("address %s", ether_sprintf(sc->sc_arpcom.ac_enaddr));
231 
232 	ifp = &sc->sc_arpcom.ac_if;
233 	bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
234 	ifp->if_softc = sc;
235 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
236 	ifp->if_ioctl = funcs->f_ioctl;
237 	ifp->if_start = funcs->f_start;
238 	ifp->if_watchdog = funcs->f_watchdog;
239 	ifp->if_baudrate = 10000000;
240 	IFQ_SET_READY(&ifp->if_snd);
241 
242 	(void)wi_set_ssid(&sc->wi_node_name, WI_DEFAULT_NODENAME,
243 	    sizeof(WI_DEFAULT_NODENAME) - 1);
244 	(void)wi_set_ssid(&sc->wi_net_name, WI_DEFAULT_NETNAME,
245 	    sizeof(WI_DEFAULT_NETNAME) - 1);
246 	(void)wi_set_ssid(&sc->wi_ibss_name, WI_DEFAULT_IBSS,
247 	    sizeof(WI_DEFAULT_IBSS) - 1);
248 
249 	sc->wi_portnum = WI_DEFAULT_PORT;
250 	sc->wi_ptype = WI_PORTTYPE_BSS;
251 	sc->wi_ap_density = WI_DEFAULT_AP_DENSITY;
252 	sc->wi_rts_thresh = WI_DEFAULT_RTS_THRESH;
253 	sc->wi_tx_rate = WI_DEFAULT_TX_RATE;
254 	sc->wi_max_data_len = WI_DEFAULT_DATALEN;
255 	sc->wi_create_ibss = WI_DEFAULT_CREATE_IBSS;
256 	sc->wi_pm_enabled = WI_DEFAULT_PM_ENABLED;
257 	sc->wi_max_sleep = WI_DEFAULT_MAX_SLEEP;
258 	sc->wi_roaming = WI_DEFAULT_ROAMING;
259 	sc->wi_authtype = WI_DEFAULT_AUTHTYPE;
260 	sc->wi_diversity = WI_DEFAULT_DIVERSITY;
261 	sc->wi_crypto_algorithm = WI_CRYPTO_FIRMWARE_WEP;
262 
263 	/*
264 	 * Read the default channel from the NIC. This may vary
265 	 * depending on the country where the NIC was purchased, so
266 	 * we can't hard-code a default and expect it to work for
267 	 * everyone.
268 	 */
269 	gen.wi_type = WI_RID_OWN_CHNL;
270 	gen.wi_len = 2;
271 	if (wi_read_record(sc, &gen) == 0)
272 		sc->wi_channel = letoh16(gen.wi_val);
273 	else
274 		sc->wi_channel = 3;
275 
276 	/*
277 	 * Set flags based on firmware version.
278 	 */
279 	switch (sc->sc_firmware_type) {
280 	case WI_LUCENT:
281 		sc->wi_flags |= WI_FLAGS_HAS_ROAMING;
282 		if (sc->sc_sta_firmware_ver >= 60000)
283 			sc->wi_flags |= WI_FLAGS_HAS_MOR;
284 		if (sc->sc_sta_firmware_ver >= 60006) {
285 			sc->wi_flags |= WI_FLAGS_HAS_IBSS;
286 			sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS;
287 		}
288 		sc->wi_ibss_port = htole16(1);
289 		break;
290 	case WI_INTERSIL:
291 		sc->wi_flags |= WI_FLAGS_HAS_ROAMING;
292 		if (sc->sc_sta_firmware_ver >= 800) {
293 #ifndef SMALL_KERNEL
294 			sc->wi_flags |= WI_FLAGS_HAS_HOSTAP;
295 #endif
296 			sc->wi_flags |= WI_FLAGS_HAS_IBSS;
297 			sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS;
298 		}
299 		sc->wi_ibss_port = htole16(0);
300 		break;
301 	case WI_SYMBOL:
302 		sc->wi_flags |= WI_FLAGS_HAS_DIVERSITY;
303 		if (sc->sc_sta_firmware_ver >= 20000)
304 			sc->wi_flags |= WI_FLAGS_HAS_IBSS;
305 		if (sc->sc_sta_firmware_ver >= 25000)
306 			sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS;
307 		sc->wi_ibss_port = htole16(4);
308 		break;
309 	}
310 
311 	/*
312 	 * Find out if we support WEP on this card.
313 	 */
314 	gen.wi_type = WI_RID_WEP_AVAIL;
315 	gen.wi_len = 2;
316 	if (wi_read_record(sc, &gen) == 0 && gen.wi_val != htole16(0))
317 		sc->wi_flags |= WI_FLAGS_HAS_WEP;
318 	timeout_set(&sc->sc_timo, funcs->f_inquire, sc);
319 
320 	bzero((char *)&sc->wi_stats, sizeof(sc->wi_stats));
321 
322 	/* Find supported rates. */
323 	gen.wi_type = WI_RID_DATA_RATES;
324 	gen.wi_len = 2;
325 	if (wi_read_record(sc, &gen))
326 		sc->wi_supprates = WI_SUPPRATES_1M | WI_SUPPRATES_2M |
327 		    WI_SUPPRATES_5M | WI_SUPPRATES_11M;
328 	else
329 		sc->wi_supprates = gen.wi_val;
330 
331 	ifmedia_init(&sc->sc_media, 0, wi_media_change, wi_media_status);
332 #define	ADD(m, c)	ifmedia_add(&sc->sc_media, (m), (c), NULL)
333 	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0), 0);
334 	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, IFM_IEEE80211_ADHOC, 0), 0);
335 	if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
336 		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, IFM_IEEE80211_IBSS,
337 		    0), 0);
338 	if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
339 		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
340 		    IFM_IEEE80211_IBSSMASTER, 0), 0);
341 	if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
342 		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
343 		    IFM_IEEE80211_HOSTAP, 0), 0);
344 	if (sc->wi_supprates & WI_SUPPRATES_1M) {
345 		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 0, 0), 0);
346 		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
347 		    IFM_IEEE80211_ADHOC, 0), 0);
348 		if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
349 			ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
350 			    IFM_IEEE80211_IBSS, 0), 0);
351 		if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
352 			ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
353 			    IFM_IEEE80211_IBSSMASTER, 0), 0);
354 		if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
355 			ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
356 			    IFM_IEEE80211_HOSTAP, 0), 0);
357 	}
358 	if (sc->wi_supprates & WI_SUPPRATES_2M) {
359 		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 0, 0), 0);
360 		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
361 		    IFM_IEEE80211_ADHOC, 0), 0);
362 		if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
363 			ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
364 			    IFM_IEEE80211_IBSS, 0), 0);
365 		if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
366 			ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
367 			    IFM_IEEE80211_IBSSMASTER, 0), 0);
368 		if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
369 			ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
370 			    IFM_IEEE80211_HOSTAP, 0), 0);
371 	}
372 	if (sc->wi_supprates & WI_SUPPRATES_5M) {
373 		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 0, 0), 0);
374 		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
375 		    IFM_IEEE80211_ADHOC, 0), 0);
376 		if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
377 			ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
378 			    IFM_IEEE80211_IBSS, 0), 0);
379 		if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
380 			ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
381 			    IFM_IEEE80211_IBSSMASTER, 0), 0);
382 		if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
383 			ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
384 			    IFM_IEEE80211_HOSTAP, 0), 0);
385 	}
386 	if (sc->wi_supprates & WI_SUPPRATES_11M) {
387 		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 0, 0), 0);
388 		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
389 		    IFM_IEEE80211_ADHOC, 0), 0);
390 		if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
391 			ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
392 			    IFM_IEEE80211_IBSS, 0), 0);
393 		if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
394 			ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
395 			    IFM_IEEE80211_IBSSMASTER, 0), 0);
396 		if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP)
397 			ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
398 			    IFM_IEEE80211_HOSTAP, 0), 0);
399 		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_MANUAL, 0, 0), 0);
400 	}
401 #undef ADD
402 	ifmedia_set(&sc->sc_media,
403 	    IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0));
404 
405 	/*
406 	 * Call MI attach routines.
407 	 */
408 	if_attach(ifp);
409 	ether_ifattach(ifp);
410 	printf("\n");
411 
412 	sc->wi_flags |= WI_FLAGS_ATTACHED;
413 
414 #if NBPFILTER > 0
415 	BPFATTACH(&sc->sc_arpcom.ac_if.if_bpf, ifp, DLT_EN10MB,
416 	    sizeof(struct ether_header));
417 #endif
418 
419 	sc->sc_sdhook = shutdownhook_establish(wi_shutdown, sc);
420 
421 	wi_init(sc);
422 	wi_stop(sc);
423 
424 	return (0);
425 }
426 
427 STATIC void
428 wi_intr_enable(struct wi_softc *sc, int mode)
429 {
430 	if (!(sc->wi_flags & WI_FLAGS_BUS_USB))
431 		CSR_WRITE_2(sc, WI_INT_EN, mode);
432 }
433 
434 STATIC void
435 wi_intr_ack(struct wi_softc *sc, int mode)
436 {
437 	if (!(sc->wi_flags & WI_FLAGS_BUS_USB))
438 		CSR_WRITE_2(sc, WI_EVENT_ACK, mode);
439 }
440 
441 int
442 wi_intr(vsc)
443 	void			*vsc;
444 {
445 	struct wi_softc		*sc = vsc;
446 	struct ifnet		*ifp;
447 	u_int16_t		status;
448 
449 	DPRINTF(WID_INTR, ("wi_intr: sc %p\n", sc));
450 
451 	ifp = &sc->sc_arpcom.ac_if;
452 
453 	if (!(sc->wi_flags & WI_FLAGS_ATTACHED) || !(ifp->if_flags & IFF_UP)) {
454 		CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
455 		CSR_WRITE_2(sc, WI_INT_EN, 0);
456 		return (0);
457 	}
458 
459 	/* Disable interrupts. */
460 	CSR_WRITE_2(sc, WI_INT_EN, 0);
461 
462 	status = CSR_READ_2(sc, WI_EVENT_STAT);
463 	CSR_WRITE_2(sc, WI_EVENT_ACK, ~WI_INTRS);
464 
465 	if (status & WI_EV_RX) {
466 		wi_rxeof(sc);
467 		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
468 	}
469 
470 	if (status & WI_EV_TX) {
471 		wi_txeof(sc, status);
472 		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX);
473 	}
474 
475 	if (status & WI_EV_ALLOC) {
476 		int			id;
477 		id = CSR_READ_2(sc, WI_ALLOC_FID);
478 		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
479 		if (id == sc->wi_tx_data_id)
480 			wi_txeof(sc, status);
481 	}
482 
483 	if (status & WI_EV_INFO) {
484 		wi_update_stats(sc);
485 		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO);
486 	}
487 
488 	if (status & WI_EV_TX_EXC) {
489 		wi_txeof(sc, status);
490 		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX_EXC);
491 	}
492 
493 	if (status & WI_EV_INFO_DROP) {
494 		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO_DROP);
495 	}
496 
497 	/* Re-enable interrupts. */
498 	CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
499 
500 	if (!IFQ_IS_EMPTY(&ifp->if_snd))
501 		wi_start(ifp);
502 
503 	return (1);
504 }
505 
506 STATIC int
507 wi_get_fid_io(struct wi_softc *sc, int fid)
508 {
509 	return CSR_READ_2(sc, fid);
510 }
511 
512 
513 void
514 wi_rxeof(sc)
515 	struct wi_softc		*sc;
516 {
517 	struct ifnet		*ifp;
518 	struct ether_header	*eh;
519 	struct mbuf		*m;
520 	caddr_t			olddata;
521 	u_int16_t		msg_type;
522 	int			maxlen;
523 	int			id;
524 
525 	ifp = &sc->sc_arpcom.ac_if;
526 
527 	id = wi_get_fid(sc, WI_RX_FID);
528 
529 	if (sc->wi_procframe || sc->wi_debug.wi_monitor) {
530 		struct wi_frame	*rx_frame;
531 		int		datlen, hdrlen;
532 
533 		MGETHDR(m, M_DONTWAIT, MT_DATA);
534 		if (m == NULL) {
535 			ifp->if_ierrors++;
536 			return;
537 		}
538 		MCLGET(m, M_DONTWAIT);
539 		if (!(m->m_flags & M_EXT)) {
540 			m_freem(m);
541 			ifp->if_ierrors++;
542 			return;
543 		}
544 
545 		m->m_pkthdr.rcvif = ifp;
546 
547 		if (wi_read_data(sc, id, 0, mtod(m, caddr_t),
548 		    sizeof(struct wi_frame))) {
549 			m_freem(m);
550 			ifp->if_ierrors++;
551 			return;
552 		}
553 
554 		rx_frame = mtod(m, struct wi_frame *);
555 
556 		if (rx_frame->wi_status & htole16(WI_STAT_BADCRC)) {
557 			m_freem(m);
558 			ifp->if_ierrors++;
559 			return;
560 		}
561 
562 		switch ((letoh16(rx_frame->wi_status) & WI_STAT_MAC_PORT)
563 		    >> 8) {
564 		case 7:
565 			switch (letoh16(rx_frame->wi_frame_ctl) &
566 			    WI_FCTL_FTYPE) {
567 			case WI_FTYPE_DATA:
568 				hdrlen = WI_DATA_HDRLEN;
569 				datlen = letoh16(rx_frame->wi_dat_len);
570 				break;
571 			case WI_FTYPE_MGMT:
572 				hdrlen = WI_MGMT_HDRLEN;
573 				datlen = letoh16(rx_frame->wi_dat_len);
574 				break;
575 			case WI_FTYPE_CTL:
576 				hdrlen = WI_CTL_HDRLEN;
577 				datlen = 0;
578 				break;
579 			default:
580 				printf(WI_PRT_FMT ": received packet of "
581 				    "unknown type on port 7\n", WI_PRT_ARG(sc));
582 				m_freem(m);
583 				ifp->if_ierrors++;
584 				return;
585 			}
586 			break;
587 		case 0:
588 			hdrlen = WI_DATA_HDRLEN;
589 			datlen = letoh16(rx_frame->wi_dat_len);
590 			break;
591 		default:
592 			printf(WI_PRT_FMT ": received packet on invalid port "
593 			    "(wi_status=0x%x)\n", WI_PRT_ARG(sc),
594 			    letoh16(rx_frame->wi_status));
595 			m_freem(m);
596 			ifp->if_ierrors++;
597 			return;
598 		}
599 
600 		if ((hdrlen + datlen + 2) > MCLBYTES) {
601 			m_freem(m);
602 			ifp->if_ierrors++;
603 			return;
604 		}
605 
606 		if (wi_read_data(sc, id, hdrlen, mtod(m, caddr_t) + hdrlen,
607 		    datlen + 2)) {
608 			m_freem(m);
609 			ifp->if_ierrors++;
610 			return;
611 		}
612 
613 		m->m_pkthdr.len = m->m_len = hdrlen + datlen;
614 	} else {
615 		struct wi_frame rx_frame;
616 
617 		/* First read in the frame header */
618 		if (wi_read_data(sc, id, 0, (caddr_t)&rx_frame,
619 		    sizeof(rx_frame))) {
620 			ifp->if_ierrors++;
621 			return;
622 		}
623 
624 		/* Drop undecryptable or packets with receive errors here */
625 		if (rx_frame.wi_status & htole16(WI_STAT_ERRSTAT)) {
626 			ifp->if_ierrors++;
627 			return;
628 		}
629 
630 		/* Stash message type in host byte order for later use */
631 		msg_type = letoh16(rx_frame.wi_status) & WI_RXSTAT_MSG_TYPE;
632 
633 		MGETHDR(m, M_DONTWAIT, MT_DATA);
634 		if (m == NULL) {
635 			ifp->if_ierrors++;
636 			return;
637 		}
638 		MCLGET(m, M_DONTWAIT);
639 		if (!(m->m_flags & M_EXT)) {
640 			m_freem(m);
641 			ifp->if_ierrors++;
642 			return;
643 		}
644 
645 		olddata = m->m_data;
646 		/* Align the data after the ethernet header */
647 		m->m_data = (caddr_t)ALIGN(m->m_data +
648 		    sizeof(struct ether_header)) - sizeof(struct ether_header);
649 
650 		eh = mtod(m, struct ether_header *);
651 		maxlen = MCLBYTES - (m->m_data - olddata);
652 		m->m_pkthdr.rcvif = ifp;
653 
654 		if (msg_type == WI_STAT_MGMT &&
655 		    sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
656 
657 			u_int16_t rxlen = letoh16(rx_frame.wi_dat_len);
658 
659 			if ((WI_802_11_OFFSET_RAW + rxlen + 2) > maxlen) {
660 				printf("%s: oversized mgmt packet received in "
661 				    "hostap mode (wi_dat_len=%d, "
662 				    "wi_status=0x%x)\n", sc->sc_dev.dv_xname,
663 				    rxlen, letoh16(rx_frame.wi_status));
664 				m_freem(m);
665 				ifp->if_ierrors++;
666 				return;
667 			}
668 
669 			/* Put the whole header in there. */
670 			bcopy(&rx_frame, mtod(m, void *),
671 			    sizeof(struct wi_frame));
672 			if (wi_read_data(sc, id, WI_802_11_OFFSET_RAW,
673 			    mtod(m, caddr_t) + WI_802_11_OFFSET_RAW,
674 			    rxlen + 2)) {
675 				m_freem(m);
676 				if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
677 					printf("wihap: failed to copy header\n");
678 				ifp->if_ierrors++;
679 				return;
680 			}
681 
682 			m->m_pkthdr.len = m->m_len =
683 			    WI_802_11_OFFSET_RAW + rxlen;
684 
685 			/* XXX: consider giving packet to bhp? */
686 
687 			wihap_mgmt_input(sc, &rx_frame, m);
688 
689 			return;
690 		}
691 
692 		switch (msg_type) {
693 		case WI_STAT_1042:
694 		case WI_STAT_TUNNEL:
695 		case WI_STAT_WMP_MSG:
696 			if ((letoh16(rx_frame.wi_dat_len) + WI_SNAPHDR_LEN) >
697 			    maxlen) {
698 				printf(WI_PRT_FMT ": oversized packet received "
699 				    "(wi_dat_len=%d, wi_status=0x%x)\n",
700 				    WI_PRT_ARG(sc),
701 				    letoh16(rx_frame.wi_dat_len),
702 				    letoh16(rx_frame.wi_status));
703 				m_freem(m);
704 				ifp->if_ierrors++;
705 				return;
706 			}
707 			m->m_pkthdr.len = m->m_len =
708 			    letoh16(rx_frame.wi_dat_len) + WI_SNAPHDR_LEN;
709 
710 			bcopy((char *)&rx_frame.wi_dst_addr,
711 			    (char *)&eh->ether_dhost, ETHER_ADDR_LEN);
712 			bcopy((char *)&rx_frame.wi_src_addr,
713 			    (char *)&eh->ether_shost, ETHER_ADDR_LEN);
714 			bcopy((char *)&rx_frame.wi_type,
715 			    (char *)&eh->ether_type, ETHER_TYPE_LEN);
716 
717 			if (wi_read_data(sc, id, WI_802_11_OFFSET,
718 			    mtod(m, caddr_t) + sizeof(struct ether_header),
719 			    m->m_len + 2)) {
720 				ifp->if_ierrors++;
721 				m_freem(m);
722 				return;
723 			}
724 			break;
725 		default:
726 			if ((letoh16(rx_frame.wi_dat_len) +
727 			    sizeof(struct ether_header)) > maxlen) {
728 				printf(WI_PRT_FMT ": oversized packet received "
729 				    "(wi_dat_len=%d, wi_status=0x%x)\n",
730 				    WI_PRT_ARG(sc),
731 				    letoh16(rx_frame.wi_dat_len),
732 				    letoh16(rx_frame.wi_status));
733 				m_freem(m);
734 				ifp->if_ierrors++;
735 				return;
736 			}
737 			m->m_pkthdr.len = m->m_len =
738 			    letoh16(rx_frame.wi_dat_len) +
739 			    sizeof(struct ether_header);
740 
741 			if (wi_read_data(sc, id, WI_802_3_OFFSET,
742 			    mtod(m, caddr_t), m->m_len + 2)) {
743 				m_freem(m);
744 				ifp->if_ierrors++;
745 				return;
746 			}
747 			break;
748 		}
749 
750 		ifp->if_ipackets++;
751 
752 		if (sc->wi_use_wep &&
753 		    rx_frame.wi_frame_ctl & WI_FCTL_WEP) {
754 			int len;
755 			u_int8_t rx_buf[1596];
756 
757 			switch (sc->wi_crypto_algorithm) {
758 			case WI_CRYPTO_FIRMWARE_WEP:
759 				break;
760 			case WI_CRYPTO_SOFTWARE_WEP:
761 				m_copydata(m, 0, m->m_pkthdr.len,
762 				    (caddr_t)rx_buf);
763 				len = m->m_pkthdr.len -
764 				    sizeof(struct ether_header);
765 				if (wi_do_hostdecrypt(sc, rx_buf +
766 				    sizeof(struct ether_header), len)) {
767 					if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
768 						printf(WI_PRT_FMT ": Error decrypting incoming packet.\n", WI_PRT_ARG(sc));
769 					m_freem(m);
770 					ifp->if_ierrors++;
771 					return;
772 				}
773 				len -= IEEE80211_WEP_IVLEN +
774 				    IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
775 				/*
776 				 * copy data back to mbufs:
777 				 * we need to ditch the IV & most LLC/SNAP stuff
778 				 * (except SNAP type, we're going use that to
779 				 * overwrite the ethertype in the ether_header)
780 				 */
781 				m_copyback(m, sizeof(struct ether_header) -
782 				    WI_ETHERTYPE_LEN, WI_ETHERTYPE_LEN +
783 				    (len - WI_SNAPHDR_LEN),
784 				    rx_buf + sizeof(struct ether_header) +
785 				    IEEE80211_WEP_IVLEN +
786 				    IEEE80211_WEP_KIDLEN + WI_SNAPHDR_LEN);
787 				m_adj(m, -(WI_ETHERTYPE_LEN +
788 				    IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
789 				    WI_SNAPHDR_LEN));
790 				break;
791 			}
792 		}
793 
794 		if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
795 			/*
796 			 * Give host AP code first crack at data packets.
797 			 * If it decides to handle it (or drop it), it will
798 			 * return a non-zero.  Otherwise, it is destined for
799 			 * this host.
800 			 */
801 			if (wihap_data_input(sc, &rx_frame, m))
802 				return;
803 		}
804 	}
805 
806 #if NBPFILTER > 0
807 	/* Handle BPF listeners. */
808 	if (ifp->if_bpf)
809 		BPF_MTAP(ifp, m);
810 #endif
811 
812 	/* Receive packet unless in procframe or monitor mode. */
813 	if (sc->wi_procframe || sc->wi_debug.wi_monitor)
814 		m_freem(m);
815 	else
816 		ether_input_mbuf(ifp, m);
817 
818 	return;
819 }
820 
821 void
822 wi_txeof(sc, status)
823 	struct wi_softc		*sc;
824 	int			status;
825 {
826 	struct ifnet		*ifp;
827 
828 	ifp = &sc->sc_arpcom.ac_if;
829 
830 	ifp->if_timer = 0;
831 	ifp->if_flags &= ~IFF_OACTIVE;
832 
833 	if (status & WI_EV_TX_EXC)
834 		ifp->if_oerrors++;
835 	else
836 		ifp->if_opackets++;
837 
838 	return;
839 }
840 
841 void
842 wi_inquire(xsc)
843 	void			*xsc;
844 {
845 	struct wi_softc		*sc;
846 	struct ifnet		*ifp;
847 	int s, rv;
848 
849 	sc = xsc;
850 	ifp = &sc->sc_arpcom.ac_if;
851 
852 	timeout_add(&sc->sc_timo, hz * 60);
853 
854 	/* Don't do this while we're transmitting */
855 	if (ifp->if_flags & IFF_OACTIVE)
856 		return;
857 
858 	s = splimp();
859 	rv = wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_COUNTERS, 0, 0);
860 	splx(s);
861 	if (rv)
862 		printf(WI_PRT_FMT ": wi_cmd failed with %d\n", WI_PRT_ARG(sc),
863 		    rv);
864 
865 	return;
866 }
867 
868 void
869 wi_update_stats(sc)
870 	struct wi_softc		*sc;
871 {
872 	struct wi_ltv_gen	gen;
873 	u_int16_t		id;
874 	struct ifnet		*ifp;
875 	u_int32_t		*ptr;
876 	int			len, i;
877 	u_int16_t		t;
878 
879 	ifp = &sc->sc_arpcom.ac_if;
880 
881 	id = wi_get_fid(sc, WI_INFO_FID);
882 
883 	wi_read_data(sc, id, 0, (char *)&gen, 4);
884 
885 	if (gen.wi_type == htole16(WI_INFO_SCAN_RESULTS)) {
886 		sc->wi_scanbuf_len = letoh16(gen.wi_len);
887 		wi_read_data(sc, id, 4, (caddr_t)sc->wi_scanbuf,
888 		    sc->wi_scanbuf_len * 2);
889 		return;
890 	} else if (gen.wi_type != htole16(WI_INFO_COUNTERS))
891 		return;
892 
893 	/* Some card versions have a larger stats structure */
894 	len = (letoh16(gen.wi_len) - 1 < sizeof(sc->wi_stats) / 4) ?
895 	    letoh16(gen.wi_len) - 1 : sizeof(sc->wi_stats) / 4;
896 
897 	ptr = (u_int32_t *)&sc->wi_stats;
898 
899 	for (i = 0; i < len; i++) {
900 		if (sc->wi_flags & WI_FLAGS_BUS_USB) {
901 			wi_read_data(sc, id, 4 + i*2, (char *)&t, 2);
902 			t = letoh16(t);
903 		} else
904 			t = CSR_READ_2(sc, WI_DATA1);
905 #ifdef WI_HERMES_STATS_WAR
906 		if (t > 0xF000)
907 			t = ~t & 0xFFFF;
908 #endif
909 		ptr[i] += t;
910 	}
911 
912 	ifp->if_collisions = sc->wi_stats.wi_tx_single_retries +
913 	    sc->wi_stats.wi_tx_multi_retries +
914 	    sc->wi_stats.wi_tx_retry_limit;
915 
916 	return;
917 }
918 
919 STATIC int
920 wi_cmd_io(sc, cmd, val0, val1, val2)
921 	struct wi_softc		*sc;
922 	int			cmd;
923 	int			val0;
924 	int			val1;
925 	int			val2;
926 {
927 	int			i, s = 0;
928 
929 	/* Wait for the busy bit to clear. */
930 	for (i = 0; i < WI_TIMEOUT; i++) {
931 		if (!(CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY))
932 			break;
933 		DELAY(10);
934 	}
935 
936 	CSR_WRITE_2(sc, WI_PARAM0, val0);
937 	CSR_WRITE_2(sc, WI_PARAM1, val1);
938 	CSR_WRITE_2(sc, WI_PARAM2, val2);
939 	CSR_WRITE_2(sc, WI_COMMAND, cmd);
940 
941 	for (i = WI_TIMEOUT; i--; DELAY(10)) {
942 		/*
943 		 * Wait for 'command complete' bit to be
944 		 * set in the event status register.
945 		 */
946 		s = CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_CMD;
947 		if (s) {
948 			/* Ack the event and read result code. */
949 			s = CSR_READ_2(sc, WI_STATUS);
950 			CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD);
951 #ifdef foo
952 			if ((s & WI_CMD_CODE_MASK) != (cmd & WI_CMD_CODE_MASK))
953 				return(EIO);
954 #endif
955 			if (s & WI_STAT_CMD_RESULT)
956 				return(EIO);
957 			break;
958 		}
959 	}
960 
961 	if (i < 0)
962 		return(ETIMEDOUT);
963 
964 	return(0);
965 }
966 
967 STATIC void
968 wi_reset(sc)
969 	struct wi_softc		*sc;
970 {
971 	DPRINTF(WID_RESET, ("wi_reset: sc %p\n", sc));
972 
973 	/* Symbol firmware cannot be initialized more than once. */
974 	if (sc->sc_firmware_type == WI_SYMBOL &&
975 	    (sc->wi_flags & WI_FLAGS_INITIALIZED))
976 		return;
977 
978 	if (wi_cmd(sc, WI_CMD_INI, 0, 0, 0))
979 		printf(WI_PRT_FMT ": init failed\n", WI_PRT_ARG(sc));
980 	else
981 		sc->wi_flags |= WI_FLAGS_INITIALIZED;
982 
983 	wi_intr_enable(sc, 0);
984 	wi_intr_ack(sc, 0xffff);
985 
986 	/* Calibrate timer. */
987 	WI_SETVAL(WI_RID_TICK_TIME, 8);
988 
989 	return;
990 }
991 
992 STATIC void
993 wi_cor_reset(sc)
994 	struct wi_softc		*sc;
995 {
996 	u_int8_t cor_value;
997 
998 	DPRINTF(WID_RESET, ("wi_cor_reset: sc %p\n", sc));
999 
1000 	/*
1001 	 * Do a soft reset of the card; this is required for Symbol cards.
1002 	 * This shouldn't hurt other cards but there have been reports
1003 	 * of the COR reset messing up old Lucent firmware revisions so
1004 	 * we only soft reset Symbol cards for now.
1005 	 */
1006 	if (sc->sc_firmware_type == WI_SYMBOL) {
1007 		cor_value = bus_space_read_1(sc->wi_ltag, sc->wi_lhandle,
1008 		    sc->wi_cor_offset);
1009 		bus_space_write_1(sc->wi_ltag, sc->wi_lhandle,
1010 		    sc->wi_cor_offset, (cor_value | WI_COR_SOFT_RESET));
1011 		DELAY(1000);
1012 		bus_space_write_1(sc->wi_ltag, sc->wi_lhandle,
1013 		    sc->wi_cor_offset, (cor_value & ~WI_COR_SOFT_RESET));
1014 		DELAY(1000);
1015 	}
1016 
1017 	return;
1018 }
1019 
1020 /*
1021  * Read an LTV record from the NIC.
1022  */
1023 STATIC int
1024 wi_read_record_io(sc, ltv)
1025 	struct wi_softc		*sc;
1026 	struct wi_ltv_gen	*ltv;
1027 {
1028 	u_int8_t		*ptr;
1029 	int			len, code;
1030 	struct wi_ltv_gen	*oltv, p2ltv;
1031 
1032 	if (sc->sc_firmware_type != WI_LUCENT) {
1033 		oltv = ltv;
1034 		switch (ltv->wi_type) {
1035 		case WI_RID_ENCRYPTION:
1036 			p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
1037 			p2ltv.wi_len = 2;
1038 			ltv = &p2ltv;
1039 			break;
1040 		case WI_RID_TX_CRYPT_KEY:
1041 			if (ltv->wi_val > WI_NLTV_KEYS)
1042 				return (EINVAL);
1043 			p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
1044 			p2ltv.wi_len = 2;
1045 			ltv = &p2ltv;
1046 			break;
1047 		}
1048 	}
1049 
1050 	/* Tell the NIC to enter record read mode. */
1051 	if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_READ, ltv->wi_type, 0, 0))
1052 		return(EIO);
1053 
1054 	/* Seek to the record. */
1055 	if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1))
1056 		return(EIO);
1057 
1058 	/*
1059 	 * Read the length and record type and make sure they
1060 	 * match what we expect (this verifies that we have enough
1061 	 * room to hold all of the returned data).
1062 	 */
1063 	len = CSR_READ_2(sc, WI_DATA1);
1064 	if (len > ltv->wi_len)
1065 		return(ENOSPC);
1066 	code = CSR_READ_2(sc, WI_DATA1);
1067 	if (code != ltv->wi_type)
1068 		return(EIO);
1069 
1070 	ltv->wi_len = len;
1071 	ltv->wi_type = code;
1072 
1073 	/* Now read the data. */
1074 	ptr = (u_int8_t *)&ltv->wi_val;
1075 	if (ltv->wi_len > 1)
1076 		CSR_READ_RAW_2(sc, WI_DATA1, ptr, (ltv->wi_len-1)*2);
1077 
1078 	if (ltv->wi_type == WI_RID_PORTTYPE && sc->wi_ptype == WI_PORTTYPE_IBSS
1079 	    && ltv->wi_val == sc->wi_ibss_port) {
1080 		/*
1081 		 * Convert vendor IBSS port type to WI_PORTTYPE_IBSS.
1082 		 * Since Lucent uses port type 1 for BSS *and* IBSS we
1083 		 * have to rely on wi_ptype to distinguish this for us.
1084 		 */
1085 		ltv->wi_val = htole16(WI_PORTTYPE_IBSS);
1086 	} else if (sc->sc_firmware_type != WI_LUCENT) {
1087 		int v;
1088 
1089 		switch (oltv->wi_type) {
1090 		case WI_RID_TX_RATE:
1091 		case WI_RID_CUR_TX_RATE:
1092 			switch (letoh16(ltv->wi_val)) {
1093 			case 1: v = 1; break;
1094 			case 2: v = 2; break;
1095 			case 3:	v = 6; break;
1096 			case 4: v = 5; break;
1097 			case 7: v = 7; break;
1098 			case 8: v = 11; break;
1099 			case 15: v = 3; break;
1100 			default: v = 0x100 + letoh16(ltv->wi_val); break;
1101 			}
1102 			oltv->wi_val = htole16(v);
1103 			break;
1104 		case WI_RID_ENCRYPTION:
1105 			oltv->wi_len = 2;
1106 			if (ltv->wi_val & htole16(0x01))
1107 				oltv->wi_val = htole16(1);
1108 			else
1109 				oltv->wi_val = htole16(0);
1110 			break;
1111 		case WI_RID_TX_CRYPT_KEY:
1112 		case WI_RID_CNFAUTHMODE:
1113 			oltv->wi_len = 2;
1114 			oltv->wi_val = ltv->wi_val;
1115 			break;
1116 		}
1117 	}
1118 
1119 	return(0);
1120 }
1121 
1122 /*
1123  * Same as read, except we inject data instead of reading it.
1124  */
1125 STATIC int
1126 wi_write_record_io(sc, ltv)
1127 	struct wi_softc		*sc;
1128 	struct wi_ltv_gen	*ltv;
1129 {
1130 	u_int8_t		*ptr;
1131 	u_int16_t		val = 0;
1132 	int			i;
1133 	struct wi_ltv_gen	p2ltv;
1134 
1135 	if (ltv->wi_type == WI_RID_PORTTYPE &&
1136 	    letoh16(ltv->wi_val) == WI_PORTTYPE_IBSS) {
1137 		/* Convert WI_PORTTYPE_IBSS to vendor IBSS port type. */
1138 		p2ltv.wi_type = WI_RID_PORTTYPE;
1139 		p2ltv.wi_len = 2;
1140 		p2ltv.wi_val = sc->wi_ibss_port;
1141 		ltv = &p2ltv;
1142 	} else if (sc->sc_firmware_type != WI_LUCENT) {
1143 		int v;
1144 
1145 		switch (ltv->wi_type) {
1146 		case WI_RID_TX_RATE:
1147 			p2ltv.wi_type = WI_RID_TX_RATE;
1148 			p2ltv.wi_len = 2;
1149 			switch (letoh16(ltv->wi_val)) {
1150 			case 1: v = 1; break;
1151 			case 2: v = 2; break;
1152 			case 3:	v = 15; break;
1153 			case 5: v = 4; break;
1154 			case 6: v = 3; break;
1155 			case 7: v = 7; break;
1156 			case 11: v = 8; break;
1157 			default: return EINVAL;
1158 			}
1159 			p2ltv.wi_val = htole16(v);
1160 			ltv = &p2ltv;
1161 			break;
1162 		case WI_RID_ENCRYPTION:
1163 			p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
1164 			p2ltv.wi_len = 2;
1165 			if (ltv->wi_val & htole16(0x01)) {
1166 				val = PRIVACY_INVOKED;
1167 				/*
1168 				 * If using shared key WEP we must set the
1169 				 * EXCLUDE_UNENCRYPTED bit.  Symbol cards
1170 				 * need this bit set even when not using
1171 				 * shared key. We can't just test for
1172 				 * IEEE80211_AUTH_SHARED since Symbol cards
1173 				 * have 2 shared key modes.
1174 				 */
1175 				if (sc->wi_authtype != IEEE80211_AUTH_OPEN ||
1176 				    sc->sc_firmware_type == WI_SYMBOL)
1177 					val |= EXCLUDE_UNENCRYPTED;
1178 
1179 				switch (sc->wi_crypto_algorithm) {
1180 				case WI_CRYPTO_FIRMWARE_WEP:
1181 					/*
1182 					 * TX encryption is broken in
1183 					 * Host AP mode.
1184 					 */
1185 					if (sc->wi_ptype == WI_PORTTYPE_HOSTAP)
1186 						val |= HOST_ENCRYPT;
1187 					break;
1188 				case WI_CRYPTO_SOFTWARE_WEP:
1189 					val |= HOST_ENCRYPT|HOST_DECRYPT;
1190 					break;
1191 				}
1192 				p2ltv.wi_val = htole16(val);
1193 			} else
1194 				p2ltv.wi_val = htole16(HOST_ENCRYPT | HOST_DECRYPT);
1195 			ltv = &p2ltv;
1196 			break;
1197 		case WI_RID_TX_CRYPT_KEY:
1198 			if (ltv->wi_val > WI_NLTV_KEYS)
1199 				return (EINVAL);
1200 			p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
1201 			p2ltv.wi_len = 2;
1202 			p2ltv.wi_val = ltv->wi_val;
1203 			ltv = &p2ltv;
1204 			break;
1205 		case WI_RID_DEFLT_CRYPT_KEYS: {
1206 				int error;
1207 				int keylen;
1208 				struct wi_ltv_str ws;
1209 				struct wi_ltv_keys *wk = (struct wi_ltv_keys *)ltv;
1210 				keylen = wk->wi_keys[sc->wi_tx_key].wi_keylen;
1211 
1212 				for (i = 0; i < 4; i++) {
1213 					bzero(&ws, sizeof(ws));
1214 					ws.wi_len = (keylen > 5) ? 8 : 4;
1215 					ws.wi_type = WI_RID_P2_CRYPT_KEY0 + i;
1216 					bcopy(&wk->wi_keys[i].wi_keydat,
1217 					    ws.wi_str, keylen);
1218 					error = wi_write_record(sc,
1219 					    (struct wi_ltv_gen *)&ws);
1220 					if (error)
1221 						return (error);
1222 				}
1223 			}
1224 			return (0);
1225 		}
1226 	}
1227 
1228 	if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1))
1229 		return(EIO);
1230 
1231 	CSR_WRITE_2(sc, WI_DATA1, ltv->wi_len);
1232 	CSR_WRITE_2(sc, WI_DATA1, ltv->wi_type);
1233 
1234 	ptr = (u_int8_t *)&ltv->wi_val;
1235 	if (ltv->wi_len > 1)
1236 		CSR_WRITE_RAW_2(sc, WI_DATA1, ptr, (ltv->wi_len-1) *2);
1237 
1238 	if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_WRITE, ltv->wi_type, 0, 0))
1239 		return(EIO);
1240 
1241 	return(0);
1242 }
1243 
1244 STATIC int
1245 wi_seek(sc, id, off, chan)
1246 	struct wi_softc		*sc;
1247 	int			id, off, chan;
1248 {
1249 	int			i;
1250 	int			selreg, offreg;
1251 
1252 	switch (chan) {
1253 	case WI_BAP0:
1254 		selreg = WI_SEL0;
1255 		offreg = WI_OFF0;
1256 		break;
1257 	case WI_BAP1:
1258 		selreg = WI_SEL1;
1259 		offreg = WI_OFF1;
1260 		break;
1261 	default:
1262 		printf(WI_PRT_FMT ": invalid data path: %x\n", WI_PRT_ARG(sc),
1263 		    chan);
1264 		return(EIO);
1265 	}
1266 
1267 	CSR_WRITE_2(sc, selreg, id);
1268 	CSR_WRITE_2(sc, offreg, off);
1269 
1270 	for (i = WI_TIMEOUT; i--; DELAY(10))
1271 		if (!(CSR_READ_2(sc, offreg) & (WI_OFF_BUSY|WI_OFF_ERR)))
1272 			break;
1273 
1274 	if (i < 0)
1275 		return(ETIMEDOUT);
1276 
1277 	return(0);
1278 }
1279 
1280 STATIC int
1281 wi_read_data_io(sc, id, off, buf, len)
1282 	struct wi_softc		*sc;
1283 	int			id, off;
1284 	caddr_t			buf;
1285 	int			len;
1286 {
1287 	u_int8_t		*ptr;
1288 
1289 	if (wi_seek(sc, id, off, WI_BAP1))
1290 		return(EIO);
1291 
1292 	ptr = (u_int8_t *)buf;
1293 	CSR_READ_RAW_2(sc, WI_DATA1, ptr, len);
1294 
1295 	return(0);
1296 }
1297 
1298 /*
1299  * According to the comments in the HCF Light code, there is a bug in
1300  * the Hermes (or possibly in certain Hermes firmware revisions) where
1301  * the chip's internal autoincrement counter gets thrown off during
1302  * data writes: the autoincrement is missed, causing one data word to
1303  * be overwritten and subsequent words to be written to the wrong memory
1304  * locations. The end result is that we could end up transmitting bogus
1305  * frames without realizing it. The workaround for this is to write a
1306  * couple of extra guard words after the end of the transfer, then
1307  * attempt to read then back. If we fail to locate the guard words where
1308  * we expect them, we preform the transfer over again.
1309  */
1310 STATIC int
1311 wi_write_data_io(sc, id, off, buf, len)
1312 	struct wi_softc		*sc;
1313 	int			id, off;
1314 	caddr_t			buf;
1315 	int			len;
1316 {
1317 	u_int8_t		*ptr;
1318 
1319 #ifdef WI_HERMES_AUTOINC_WAR
1320 again:
1321 #endif
1322 
1323 	if (wi_seek(sc, id, off, WI_BAP0))
1324 		return(EIO);
1325 
1326 	ptr = (u_int8_t *)buf;
1327 	CSR_WRITE_RAW_2(sc, WI_DATA0, ptr, len);
1328 
1329 #ifdef WI_HERMES_AUTOINC_WAR
1330 	CSR_WRITE_2(sc, WI_DATA0, 0x1234);
1331 	CSR_WRITE_2(sc, WI_DATA0, 0x5678);
1332 
1333 	if (wi_seek(sc, id, off + len, WI_BAP0))
1334 		return(EIO);
1335 
1336 	if (CSR_READ_2(sc, WI_DATA0) != 0x1234 ||
1337 	    CSR_READ_2(sc, WI_DATA0) != 0x5678)
1338 		goto again;
1339 #endif
1340 
1341 	return(0);
1342 }
1343 
1344 /*
1345  * Allocate a region of memory inside the NIC and zero
1346  * it out.
1347  */
1348 STATIC int
1349 wi_alloc_nicmem_io(sc, len, id)
1350 	struct wi_softc		*sc;
1351 	int			len;
1352 	int			*id;
1353 {
1354 	int			i;
1355 
1356 	if (wi_cmd(sc, WI_CMD_ALLOC_MEM, len, 0, 0)) {
1357 		printf(WI_PRT_FMT ": failed to allocate %d bytes on NIC\n",
1358 		    WI_PRT_ARG(sc), len);
1359 		return(ENOMEM);
1360 	}
1361 
1362 	for (i = WI_TIMEOUT; i--; DELAY(10)) {
1363 		if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_ALLOC)
1364 			break;
1365 	}
1366 
1367 	if (i < 0)
1368 		return(ETIMEDOUT);
1369 
1370 	*id = CSR_READ_2(sc, WI_ALLOC_FID);
1371 	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
1372 
1373 	if (wi_seek(sc, *id, 0, WI_BAP0))
1374 		return(EIO);
1375 
1376 	for (i = 0; i < len / 2; i++)
1377 		CSR_WRITE_2(sc, WI_DATA0, 0);
1378 
1379 	return(0);
1380 }
1381 
1382 STATIC void
1383 wi_setmulti(sc)
1384 	struct wi_softc		*sc;
1385 {
1386 	struct ifnet		*ifp;
1387 	int			i = 0;
1388 	struct wi_ltv_mcast	mcast;
1389 	struct ether_multistep	step;
1390 	struct ether_multi	*enm;
1391 
1392 	ifp = &sc->sc_arpcom.ac_if;
1393 
1394 	bzero((char *)&mcast, sizeof(mcast));
1395 
1396 	mcast.wi_type = WI_RID_MCAST_LIST;
1397 	mcast.wi_len = ((ETHER_ADDR_LEN / 2) * 16) + 1;
1398 
1399 	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
1400 		wi_write_record(sc, (struct wi_ltv_gen *)&mcast);
1401 		return;
1402 	}
1403 
1404 	ETHER_FIRST_MULTI(step, &sc->sc_arpcom, enm);
1405 	while (enm != NULL) {
1406 		if (i >= 16) {
1407 			bzero((char *)&mcast, sizeof(mcast));
1408 			break;
1409 		}
1410 
1411 		/* Punt on ranges. */
1412 		if (bcmp(enm->enm_addrlo, enm->enm_addrhi,
1413 		    sizeof(enm->enm_addrlo)) != 0)
1414 			break;
1415 		bcopy(enm->enm_addrlo, (char *)&mcast.wi_mcast[i],
1416 		    ETHER_ADDR_LEN);
1417 		i++;
1418 		ETHER_NEXT_MULTI(step, enm);
1419 	}
1420 
1421 	mcast.wi_len = (i * 3) + 1;
1422 	wi_write_record(sc, (struct wi_ltv_gen *)&mcast);
1423 
1424 	return;
1425 }
1426 
1427 STATIC int
1428 wi_setdef(sc, wreq)
1429 	struct wi_softc		*sc;
1430 	struct wi_req		*wreq;
1431 {
1432 	struct ifnet		*ifp;
1433 	int error = 0;
1434 
1435 	ifp = &sc->sc_arpcom.ac_if;
1436 
1437 	switch(wreq->wi_type) {
1438 	case WI_RID_MAC_NODE:
1439 		bcopy((char *)&wreq->wi_val, LLADDR(ifp->if_sadl),
1440 		    ETHER_ADDR_LEN);
1441 		bcopy((char *)&wreq->wi_val, (char *)&sc->sc_arpcom.ac_enaddr,
1442 		    ETHER_ADDR_LEN);
1443 		break;
1444 	case WI_RID_PORTTYPE:
1445 		error = wi_sync_media(sc, letoh16(wreq->wi_val[0]),
1446 		    sc->wi_tx_rate);
1447 		break;
1448 	case WI_RID_TX_RATE:
1449 		error = wi_sync_media(sc, sc->wi_ptype,
1450 		    letoh16(wreq->wi_val[0]));
1451 		break;
1452 	case WI_RID_MAX_DATALEN:
1453 		sc->wi_max_data_len = letoh16(wreq->wi_val[0]);
1454 		break;
1455 	case WI_RID_RTS_THRESH:
1456 		sc->wi_rts_thresh = letoh16(wreq->wi_val[0]);
1457 		break;
1458 	case WI_RID_SYSTEM_SCALE:
1459 		sc->wi_ap_density = letoh16(wreq->wi_val[0]);
1460 		break;
1461 	case WI_RID_CREATE_IBSS:
1462 		sc->wi_create_ibss = letoh16(wreq->wi_val[0]);
1463 		error = wi_sync_media(sc, sc->wi_ptype, sc->wi_tx_rate);
1464 		break;
1465 	case WI_RID_OWN_CHNL:
1466 		sc->wi_channel = letoh16(wreq->wi_val[0]);
1467 		break;
1468 	case WI_RID_NODENAME:
1469 		error = wi_set_ssid(&sc->wi_node_name,
1470 		    (u_int8_t *)&wreq->wi_val[1], letoh16(wreq->wi_val[0]));
1471 		break;
1472 	case WI_RID_DESIRED_SSID:
1473 		error = wi_set_ssid(&sc->wi_net_name,
1474 		    (u_int8_t *)&wreq->wi_val[1], letoh16(wreq->wi_val[0]));
1475 		break;
1476 	case WI_RID_OWN_SSID:
1477 		error = wi_set_ssid(&sc->wi_ibss_name,
1478 		    (u_int8_t *)&wreq->wi_val[1], letoh16(wreq->wi_val[0]));
1479 		break;
1480 	case WI_RID_PM_ENABLED:
1481 		sc->wi_pm_enabled = letoh16(wreq->wi_val[0]);
1482 		break;
1483 	case WI_RID_MICROWAVE_OVEN:
1484 		sc->wi_mor_enabled = letoh16(wreq->wi_val[0]);
1485 		break;
1486 	case WI_RID_MAX_SLEEP:
1487 		sc->wi_max_sleep = letoh16(wreq->wi_val[0]);
1488 		break;
1489 	case WI_RID_CNFAUTHMODE:
1490 		sc->wi_authtype = letoh16(wreq->wi_val[0]);
1491 		break;
1492 	case WI_RID_ROAMING_MODE:
1493 		sc->wi_roaming = letoh16(wreq->wi_val[0]);
1494 		break;
1495 	case WI_RID_SYMBOL_DIVERSITY:
1496 		sc->wi_diversity = letoh16(wreq->wi_val[0]);
1497 		break;
1498 	case WI_RID_ENCRYPTION:
1499 		sc->wi_use_wep = letoh16(wreq->wi_val[0]);
1500 		break;
1501 	case WI_RID_TX_CRYPT_KEY:
1502 		sc->wi_tx_key = letoh16(wreq->wi_val[0]);
1503 		break;
1504 	case WI_RID_DEFLT_CRYPT_KEYS:
1505 		bcopy((char *)wreq, (char *)&sc->wi_keys,
1506 		    sizeof(struct wi_ltv_keys));
1507 		break;
1508 	case WI_FRID_CRYPTO_ALG:
1509 		switch (letoh16(wreq->wi_val[0])) {
1510 		case WI_CRYPTO_FIRMWARE_WEP:
1511 			sc->wi_crypto_algorithm = WI_CRYPTO_FIRMWARE_WEP;
1512 			break;
1513 		case WI_CRYPTO_SOFTWARE_WEP:
1514 			sc->wi_crypto_algorithm = WI_CRYPTO_SOFTWARE_WEP;
1515 			break;
1516 		default:
1517 			printf(WI_PRT_FMT ": unsupported crypto algorithm %d\n",
1518 			    WI_PRT_ARG(sc), letoh16(wreq->wi_val[0]));
1519 			error = EINVAL;
1520 		}
1521 		break;
1522 	default:
1523 		error = EINVAL;
1524 		break;
1525 	}
1526 
1527 	return (error);
1528 }
1529 
1530 STATIC int
1531 wi_ioctl(ifp, command, data)
1532 	struct ifnet		*ifp;
1533 	u_long			command;
1534 	caddr_t			data;
1535 {
1536 	int			s, error = 0;
1537 	struct wi_softc		*sc;
1538 	struct wi_req		wreq;
1539 	struct ifreq		*ifr;
1540 	struct proc		*p = curproc;
1541 	struct ifaddr		*ifa = (struct ifaddr *)data;
1542 	struct ieee80211_nwid	nwid;
1543 
1544 	s = splimp();
1545 
1546 	sc = ifp->if_softc;
1547 	ifr = (struct ifreq *)data;
1548 
1549 	if (!(sc->wi_flags & WI_FLAGS_ATTACHED)) {
1550 		splx(s);
1551 		return(ENODEV);
1552 	}
1553 
1554 	DPRINTF (WID_IOCTL, ("wi_ioctl: command %lu data %p\n",
1555 	    command, data));
1556 
1557 	if ((error = ether_ioctl(ifp, &sc->sc_arpcom, command, data)) > 0) {
1558 		splx(s);
1559 		return error;
1560 	}
1561 
1562 	switch(command) {
1563 	case SIOCSWAVELAN:
1564 	case SIOCSPRISM2DEBUG:
1565 	case SIOCS80211NWID:
1566 	case SIOCS80211NWKEY:
1567 	case SIOCS80211POWER:
1568 		error = suser(p, 0);
1569 		if (error) {
1570 			splx(s);
1571 			return (error);
1572 		}
1573 	default:
1574 		break;
1575 	}
1576 
1577 	switch(command) {
1578 	case SIOCSIFADDR:
1579 		ifp->if_flags |= IFF_UP;
1580 		switch (ifa->ifa_addr->sa_family) {
1581 #ifdef INET
1582 		case AF_INET:
1583 			wi_init(sc);
1584 			arp_ifinit(&sc->sc_arpcom, ifa);
1585 			break;
1586 #endif	/* INET */
1587 		default:
1588 			wi_init(sc);
1589 			break;
1590 		}
1591 		break;
1592 
1593 	case SIOCSIFMTU:
1594 		if (ifr->ifr_mtu > ETHERMTU || ifr->ifr_mtu < ETHERMIN) {
1595 			error = EINVAL;
1596 		} else if (ifp->if_mtu != ifr->ifr_mtu) {
1597 			ifp->if_mtu = ifr->ifr_mtu;
1598 		}
1599 		break;
1600 
1601 	case SIOCSIFFLAGS:
1602 		if (ifp->if_flags & IFF_UP) {
1603 			if (ifp->if_flags & IFF_RUNNING &&
1604 			    ifp->if_flags & IFF_PROMISC &&
1605 			    !(sc->wi_if_flags & IFF_PROMISC)) {
1606 				if (sc->wi_ptype != WI_PORTTYPE_HOSTAP)
1607 					WI_SETVAL(WI_RID_PROMISC, 1);
1608 			} else if (ifp->if_flags & IFF_RUNNING &&
1609 			    !(ifp->if_flags & IFF_PROMISC) &&
1610 			    sc->wi_if_flags & IFF_PROMISC) {
1611 				if (sc->wi_ptype != WI_PORTTYPE_HOSTAP)
1612 					WI_SETVAL(WI_RID_PROMISC, 0);
1613 			} else
1614 				wi_init(sc);
1615 		} else if (ifp->if_flags & IFF_RUNNING)
1616 			wi_stop(sc);
1617 		sc->wi_if_flags = ifp->if_flags;
1618 		error = 0;
1619 		break;
1620 	case SIOCADDMULTI:
1621 	case SIOCDELMULTI:
1622 		/* Update our multicast list. */
1623 		error = (command == SIOCADDMULTI) ?
1624 		    ether_addmulti(ifr, &sc->sc_arpcom) :
1625 		    ether_delmulti(ifr, &sc->sc_arpcom);
1626 		if (error == ENETRESET) {
1627 			/*
1628 			 * Multicast list has changed; set the hardware filter
1629 			 * accordingly.
1630 			 */
1631 			wi_setmulti(sc);
1632 			error = 0;
1633 		}
1634 		break;
1635 	case SIOCSIFMEDIA:
1636 	case SIOCGIFMEDIA:
1637 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command);
1638 		break;
1639 	case SIOCGWAVELAN:
1640 		error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
1641 		if (error)
1642 			break;
1643 		if (wreq.wi_len > WI_MAX_DATALEN) {
1644 			error = EINVAL;
1645 			break;
1646 		}
1647 		switch (wreq.wi_type) {
1648 		case WI_RID_IFACE_STATS:
1649 			/* XXX native byte order */
1650 			bcopy((char *)&sc->wi_stats, (char *)&wreq.wi_val,
1651 			    sizeof(sc->wi_stats));
1652 			wreq.wi_len = (sizeof(sc->wi_stats) / 2) + 1;
1653 			break;
1654 		case WI_RID_DEFLT_CRYPT_KEYS:
1655 			/* For non-root user, return all-zeroes keys */
1656 			if (suser(p, 0))
1657 				bzero((char *)&wreq,
1658 					sizeof(struct wi_ltv_keys));
1659 			else
1660 				bcopy((char *)&sc->wi_keys, (char *)&wreq,
1661 					sizeof(struct wi_ltv_keys));
1662 			break;
1663 		case WI_RID_PROCFRAME:
1664 			wreq.wi_len = 2;
1665 			wreq.wi_val[0] = htole16(sc->wi_procframe);
1666 			break;
1667 		case WI_RID_PRISM2:
1668 			wreq.wi_len = 2;
1669 			wreq.wi_val[0] = htole16(sc->sc_firmware_type ==
1670 			    WI_LUCENT ? 0 : 1);
1671 			break;
1672 		case WI_FRID_CRYPTO_ALG:
1673 			wreq.wi_val[0] =
1674 			    htole16((u_int16_t)sc->wi_crypto_algorithm);
1675 			wreq.wi_len = 1;
1676 			break;
1677 		case WI_RID_SCAN_RES:
1678 			if (sc->sc_firmware_type == WI_LUCENT) {
1679 				memcpy((char *)wreq.wi_val,
1680 				    (char *)sc->wi_scanbuf,
1681 				    sc->wi_scanbuf_len * 2);
1682 				wreq.wi_len = sc->wi_scanbuf_len;
1683 				break;
1684 			}
1685 			/* FALLTHROUGH */
1686 		default:
1687 			if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq)) {
1688 				error = EINVAL;
1689 			}
1690 			break;
1691 		}
1692 		error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
1693 		break;
1694 	case SIOCSWAVELAN:
1695 		error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
1696 		if (error)
1697 			break;
1698 		error = EINVAL;
1699 		if (wreq.wi_len > WI_MAX_DATALEN)
1700 			break;
1701 		switch (wreq.wi_type) {
1702 		case WI_RID_IFACE_STATS:
1703 			break;
1704 		case WI_RID_MGMT_XMIT:
1705 			error = wi_mgmt_xmit(sc, (caddr_t)&wreq.wi_val,
1706 			    wreq.wi_len);
1707 			break;
1708 		case WI_RID_PROCFRAME:
1709 			sc->wi_procframe = letoh16(wreq.wi_val[0]);
1710 			error = 0;
1711 			break;
1712 		case WI_RID_SCAN_REQ:
1713 			error = 0;
1714 			if (sc->sc_firmware_type == WI_LUCENT)
1715 				wi_cmd(sc, WI_CMD_INQUIRE,
1716 				    WI_INFO_SCAN_RESULTS, 0, 0);
1717 			else
1718 				error = wi_write_record(sc,
1719 				    (struct wi_ltv_gen *)&wreq);
1720 			break;
1721 		case WI_FRID_CRYPTO_ALG:
1722 			if (sc->sc_firmware_type != WI_LUCENT) {
1723 				error = wi_setdef(sc, &wreq);
1724 				if (!error && (ifp->if_flags & IFF_UP))
1725 					wi_init(sc);
1726 			}
1727 			break;
1728 		case WI_RID_SYMBOL_DIVERSITY:
1729 		case WI_RID_ROAMING_MODE:
1730 		case WI_RID_CREATE_IBSS:
1731 		case WI_RID_MICROWAVE_OVEN:
1732 		case WI_RID_OWN_SSID:
1733 			/*
1734 			 * Check for features that may not be supported
1735 			 * (must be just before default case).
1736 			 */
1737 			if ((wreq.wi_type == WI_RID_SYMBOL_DIVERSITY &&
1738 			    !(sc->wi_flags & WI_FLAGS_HAS_DIVERSITY)) ||
1739 			    (wreq.wi_type == WI_RID_ROAMING_MODE &&
1740 			    !(sc->wi_flags & WI_FLAGS_HAS_ROAMING)) ||
1741 			    (wreq.wi_type == WI_RID_CREATE_IBSS &&
1742 			    !(sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)) ||
1743 			    (wreq.wi_type == WI_RID_MICROWAVE_OVEN &&
1744 			    !(sc->wi_flags & WI_FLAGS_HAS_MOR)) ||
1745 			    (wreq.wi_type == WI_RID_OWN_SSID &&
1746 			    wreq.wi_len != 0))
1747 				break;
1748 			/* FALLTHROUGH */
1749 		default:
1750 			error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
1751 			if (!error)
1752 				error = wi_setdef(sc, &wreq);
1753 			if (!error && (ifp->if_flags & IFF_UP))
1754 				wi_init(sc);
1755 		}
1756 		break;
1757 	case SIOCGPRISM2DEBUG:
1758 		error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
1759 		if (error)
1760 			break;
1761 		if (!(ifp->if_flags & IFF_RUNNING) ||
1762 		    sc->sc_firmware_type == WI_LUCENT) {
1763 			error = EIO;
1764 			break;
1765 		}
1766 		error = wi_get_debug(sc, &wreq);
1767 		if (error == 0)
1768 			error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
1769 		break;
1770 	case SIOCSPRISM2DEBUG:
1771 		error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
1772 		if (error)
1773 			break;
1774 		error = wi_set_debug(sc, &wreq);
1775 		break;
1776 	case SIOCG80211NWID:
1777 		if ((ifp->if_flags & IFF_UP) && sc->wi_net_name.i_len > 0) {
1778 			/* Return the desired ID */
1779 			error = copyout(&sc->wi_net_name, ifr->ifr_data,
1780 			    sizeof(sc->wi_net_name));
1781 		} else {
1782 			wreq.wi_type = WI_RID_CURRENT_SSID;
1783 			wreq.wi_len = WI_MAX_DATALEN;
1784 			if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) ||
1785 			    letoh16(wreq.wi_val[0]) > IEEE80211_NWID_LEN)
1786 				error = EINVAL;
1787 			else {
1788 				wi_set_ssid(&nwid, (u_int8_t *)&wreq.wi_val[1],
1789 				    letoh16(wreq.wi_val[0]));
1790 				error = copyout(&nwid, ifr->ifr_data,
1791 				    sizeof(nwid));
1792 			}
1793 		}
1794 		break;
1795 	case SIOCS80211NWID:
1796 		error = copyin(ifr->ifr_data, &nwid, sizeof(nwid));
1797 		if (error)
1798 			break;
1799 		if (nwid.i_len > IEEE80211_NWID_LEN) {
1800 			error = EINVAL;
1801 			break;
1802 		}
1803 		if (sc->wi_net_name.i_len == nwid.i_len &&
1804 		    memcmp(sc->wi_net_name.i_nwid, nwid.i_nwid, nwid.i_len) == 0)
1805 			break;
1806 		wi_set_ssid(&sc->wi_net_name, nwid.i_nwid, nwid.i_len);
1807 		WI_SETSTR(WI_RID_DESIRED_SSID, sc->wi_net_name);
1808 		if (ifp->if_flags & IFF_UP)
1809 			/* Reinitialize WaveLAN. */
1810 			wi_init(sc);
1811 		break;
1812 	case SIOCS80211NWKEY:
1813 		error = wi_set_nwkey(sc, (struct ieee80211_nwkey *)data);
1814 		break;
1815 	case SIOCG80211NWKEY:
1816 		error = wi_get_nwkey(sc, (struct ieee80211_nwkey *)data);
1817 		break;
1818 	case SIOCS80211POWER:
1819 		error = wi_set_pm(sc, (struct ieee80211_power *)data);
1820 		break;
1821 	case SIOCG80211POWER:
1822 		error = wi_get_pm(sc, (struct ieee80211_power *)data);
1823 		break;
1824 	case SIOCHOSTAP_ADD:
1825 	case SIOCHOSTAP_DEL:
1826 	case SIOCHOSTAP_GET:
1827 	case SIOCHOSTAP_GETALL:
1828 	case SIOCHOSTAP_GFLAGS:
1829 	case SIOCHOSTAP_SFLAGS:
1830 		/* Send all Host AP specific ioctl's to Host AP code. */
1831 		error = wihap_ioctl(sc, command, data);
1832 		break;
1833 	default:
1834 		error = EINVAL;
1835 		break;
1836 	}
1837 
1838 	splx(s);
1839 	return(error);
1840 }
1841 
1842 STATIC void
1843 wi_init_io(sc)
1844 	struct wi_softc		*sc;
1845 {
1846 	struct ifnet		*ifp = &sc->sc_arpcom.ac_if;
1847 	int			s;
1848 	struct wi_ltv_macaddr	mac;
1849 	int			id = 0;
1850 
1851 	if (!(sc->wi_flags & WI_FLAGS_ATTACHED))
1852 		return;
1853 
1854 	DPRINTF(WID_INIT, ("wi_init: sc %p\n", sc));
1855 
1856 	s = splimp();
1857 
1858 	if (ifp->if_flags & IFF_RUNNING)
1859 		wi_stop(sc);
1860 
1861 	wi_reset(sc);
1862 
1863 	/* Program max data length. */
1864 	WI_SETVAL(WI_RID_MAX_DATALEN, sc->wi_max_data_len);
1865 
1866 	/* Set the port type. */
1867 	WI_SETVAL(WI_RID_PORTTYPE, sc->wi_ptype);
1868 
1869 	/* Enable/disable IBSS creation. */
1870 	WI_SETVAL(WI_RID_CREATE_IBSS, sc->wi_create_ibss);
1871 
1872 	/* Program the RTS/CTS threshold. */
1873 	WI_SETVAL(WI_RID_RTS_THRESH, sc->wi_rts_thresh);
1874 
1875 	/* Program the TX rate */
1876 	WI_SETVAL(WI_RID_TX_RATE, sc->wi_tx_rate);
1877 
1878 	/* Access point density */
1879 	WI_SETVAL(WI_RID_SYSTEM_SCALE, sc->wi_ap_density);
1880 
1881 	/* Power Management Enabled */
1882 	WI_SETVAL(WI_RID_PM_ENABLED, sc->wi_pm_enabled);
1883 
1884 	/* Power Management Max Sleep */
1885 	WI_SETVAL(WI_RID_MAX_SLEEP, sc->wi_max_sleep);
1886 
1887 	/* Set Roaming Mode unless this is a Symbol card. */
1888 	if (sc->wi_flags & WI_FLAGS_HAS_ROAMING)
1889 		WI_SETVAL(WI_RID_ROAMING_MODE, sc->wi_roaming);
1890 
1891 	/* Set Antenna Diversity if this is a Symbol card. */
1892 	if (sc->wi_flags & WI_FLAGS_HAS_DIVERSITY)
1893 		WI_SETVAL(WI_RID_SYMBOL_DIVERSITY, sc->wi_diversity);
1894 
1895 	/* Specify the network name */
1896 	WI_SETSTR(WI_RID_DESIRED_SSID, sc->wi_net_name);
1897 
1898 	/* Specify the IBSS name */
1899 	if (sc->wi_net_name.i_len != 0 && (sc->wi_ptype == WI_PORTTYPE_HOSTAP ||
1900 	    (sc->wi_create_ibss && sc->wi_ptype == WI_PORTTYPE_IBSS)))
1901 		WI_SETSTR(WI_RID_OWN_SSID, sc->wi_net_name);
1902 	else
1903 		WI_SETSTR(WI_RID_OWN_SSID, sc->wi_ibss_name);
1904 
1905 	/* Specify the frequency to use */
1906 	WI_SETVAL(WI_RID_OWN_CHNL, sc->wi_channel);
1907 
1908 	/* Program the nodename. */
1909 	WI_SETSTR(WI_RID_NODENAME, sc->wi_node_name);
1910 
1911 	/* Set our MAC address. */
1912 	mac.wi_len = 4;
1913 	mac.wi_type = WI_RID_MAC_NODE;
1914 	bcopy((char *)&sc->sc_arpcom.ac_enaddr,
1915 	   (char *)&mac.wi_mac_addr, ETHER_ADDR_LEN);
1916 	wi_write_record(sc, (struct wi_ltv_gen *)&mac);
1917 
1918 	/*
1919 	 * Initialize promisc mode.
1920 	 *	Being in the Host-AP mode causes
1921 	 *	great deal of pain if promisc mode is set.
1922 	 *	Therefore we avoid confusing the firmware
1923 	 *	and always reset promisc mode in Host-AP regime,
1924 	 *	it shows us all the packets anyway.
1925 	 */
1926 	if (sc->wi_ptype != WI_PORTTYPE_HOSTAP && ifp->if_flags & IFF_PROMISC)
1927 		WI_SETVAL(WI_RID_PROMISC, 1);
1928 	else
1929 		WI_SETVAL(WI_RID_PROMISC, 0);
1930 
1931 	/* Configure WEP. */
1932 	if (sc->wi_flags & WI_FLAGS_HAS_WEP) {
1933 		WI_SETVAL(WI_RID_ENCRYPTION, sc->wi_use_wep);
1934 		WI_SETVAL(WI_RID_TX_CRYPT_KEY, sc->wi_tx_key);
1935 		sc->wi_keys.wi_len = (sizeof(struct wi_ltv_keys) / 2) + 1;
1936 		sc->wi_keys.wi_type = WI_RID_DEFLT_CRYPT_KEYS;
1937 		wi_write_record(sc, (struct wi_ltv_gen *)&sc->wi_keys);
1938 		if (sc->sc_firmware_type != WI_LUCENT && sc->wi_use_wep) {
1939 			/*
1940 			 * HWB3163 EVAL-CARD Firmware version less than 0.8.2.
1941 			 *
1942 			 * If promiscuous mode is disabled, the Prism2 chip
1943 			 * does not work with WEP .
1944 			 * I'm currently investigating the details of this.
1945 			 * (ichiro@netbsd.org)
1946 			 */
1947 			 if (sc->sc_firmware_type == WI_INTERSIL &&
1948 			    sc->sc_sta_firmware_ver < 802 ) {
1949 				/* firm ver < 0.8.2 */
1950 				WI_SETVAL(WI_RID_PROMISC, 1);
1951 			 }
1952 			 WI_SETVAL(WI_RID_CNFAUTHMODE, sc->wi_authtype);
1953 		}
1954 	}
1955 
1956 	/* Set multicast filter. */
1957 	wi_setmulti(sc);
1958 
1959 	/* Enable desired port */
1960 	wi_cmd(sc, WI_CMD_ENABLE | sc->wi_portnum, 0, 0, 0);
1961 
1962 	if (wi_alloc_nicmem(sc, ETHER_MAX_LEN + sizeof(struct wi_frame) + 8, &id))
1963 		printf(WI_PRT_FMT ": tx buffer allocation failed\n",
1964 		    WI_PRT_ARG(sc));
1965 	sc->wi_tx_data_id = id;
1966 
1967 	if (wi_alloc_nicmem(sc, ETHER_MAX_LEN + sizeof(struct wi_frame) + 8, &id))
1968 		printf(WI_PRT_FMT ": mgmt. buffer allocation failed\n",
1969 		    WI_PRT_ARG(sc));
1970 	sc->wi_tx_mgmt_id = id;
1971 
1972 	/* enable interrupts */
1973 	wi_intr_enable(sc, WI_INTRS);
1974 
1975         wihap_init(sc);
1976 
1977 	splx(s);
1978 
1979 	ifp->if_flags |= IFF_RUNNING;
1980 	ifp->if_flags &= ~IFF_OACTIVE;
1981 
1982 	timeout_add(&sc->sc_timo, hz * 60);
1983 
1984 	return;
1985 }
1986 
1987 static const u_int32_t crc32tab[] = {
1988 	0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL,
1989 	0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
1990 	0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L,
1991 	0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
1992 	0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
1993 	0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
1994 	0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL,
1995 	0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,
1996 	0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L,
1997 	0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
1998 	0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L,
1999 	0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
2000 	0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L,
2001 	0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,
2002 	0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
2003 	0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,
2004 	0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL,
2005 	0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
2006 	0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L,
2007 	0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
2008 	0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL,
2009 	0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
2010 	0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL,
2011 	0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
2012 	0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
2013 	0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,
2014 	0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L,
2015 	0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
2016 	0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L,
2017 	0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
2018 	0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L,
2019 	0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
2020 	0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL,
2021 	0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
2022 	0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
2023 	0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
2024 	0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL,
2025 	0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
2026 	0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL,
2027 	0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
2028 	0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L,
2029 	0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
2030 	0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L,
2031 	0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,
2032 	0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
2033 	0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,
2034 	0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L,
2035 	0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
2036 	0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL,
2037 	0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
2038 	0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L,
2039 	0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
2040 	0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL,
2041 	0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
2042 	0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
2043 	0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,
2044 	0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L,
2045 	0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,
2046 	0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L,
2047 	0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
2048 	0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L,
2049 	0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
2050 	0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L,
2051 	0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
2052 };
2053 
2054 STATIC void
2055 wi_do_hostencrypt(struct wi_softc *sc, caddr_t buf, int len)
2056 {
2057 	u_int32_t i, crc, klen;
2058 	u_int8_t key[RC4KEYLEN];
2059 	u_int8_t *dat;
2060 	struct rc4_ctx ctx;
2061 
2062 	if (!sc->wi_icv_flag) {
2063 		sc->wi_icv = arc4random();
2064 		sc->wi_icv_flag++;
2065         } else
2066 		sc->wi_icv++;
2067 	/*
2068 	 * Skip 'bad' IVs from Fluhrer/Mantin/Shamir:
2069 	 * (B, 255, N) with 3 <= B < 8
2070 	 */
2071 	if (sc->wi_icv >= 0x03ff00 &&
2072             (sc->wi_icv & 0xf8ff00) == 0x00ff00)
2073                 sc->wi_icv += 0x000100;
2074 
2075 	/* prepend 24bit IV to tx key, byte order does not matter */
2076 	bzero(key, sizeof(key));
2077 	key[0] = sc->wi_icv >> 16;
2078 	key[1] = sc->wi_icv >> 8;
2079 	key[2] = sc->wi_icv;
2080 
2081 	klen = sc->wi_keys.wi_keys[sc->wi_tx_key].wi_keylen;
2082 	bcopy((char *)&sc->wi_keys.wi_keys[sc->wi_tx_key].wi_keydat,
2083 	    (char *)key + IEEE80211_WEP_IVLEN, klen);
2084 	klen = (klen > IEEE80211_WEP_KEYLEN) ? RC4KEYLEN : RC4KEYLEN / 2;
2085 
2086 	/* rc4 keysetup */
2087 	rc4_keysetup(&ctx, key, klen);
2088 
2089 	/* output: IV, tx keyid, rc4(data), rc4(crc32(data)) */
2090 	dat = buf;
2091 	dat[0] = key[0];
2092 	dat[1] = key[1];
2093 	dat[2] = key[2];
2094 	dat[3] = sc->wi_tx_key << 6;		/* pad and keyid */
2095 	dat += 4;
2096 
2097 	/* compute crc32 over data and encrypt */
2098 	crc = ~0;
2099 	for (i = 0; i < len; i++)
2100 		crc = crc32tab[(crc ^ dat[i]) & 0xff] ^ (crc >> 8);
2101 	crc = ~crc;
2102 	rc4_crypt(&ctx, dat, dat, len);
2103 	dat += len;
2104 
2105 	/* append little-endian crc32 and encrypt */
2106 	dat[0] = crc;
2107 	dat[1] = crc >> 8;
2108 	dat[2] = crc >> 16;
2109 	dat[3] = crc >> 24;
2110 	rc4_crypt(&ctx, dat, dat, IEEE80211_WEP_CRCLEN);
2111 }
2112 
2113 STATIC int
2114 wi_do_hostdecrypt(struct wi_softc *sc, caddr_t buf, int len)
2115 {
2116 	u_int32_t i, crc, klen, kid;
2117 	u_int8_t key[RC4KEYLEN];
2118 	u_int8_t *dat;
2119 	struct rc4_ctx ctx;
2120 
2121 	if (len < IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
2122 	    IEEE80211_WEP_CRCLEN)
2123 		return -1;
2124 	len -= (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
2125 	    IEEE80211_WEP_CRCLEN);
2126 
2127 	dat = buf;
2128 
2129 	bzero(key, sizeof(key));
2130 	key[0] = dat[0];
2131 	key[1] = dat[1];
2132 	key[2] = dat[2];
2133 	kid = (dat[3] >> 6) % 4;
2134 	dat += 4;
2135 
2136 	klen = sc->wi_keys.wi_keys[kid].wi_keylen;
2137 	bcopy((char *)&sc->wi_keys.wi_keys[kid].wi_keydat,
2138 	    (char *)key + IEEE80211_WEP_IVLEN, klen);
2139 	klen = (klen > IEEE80211_WEP_KEYLEN) ? RC4KEYLEN : RC4KEYLEN / 2;
2140 
2141 	/* rc4 keysetup */
2142 	rc4_keysetup(&ctx, key, klen);
2143 
2144 	/* decrypt and compute crc32 over data */
2145 	rc4_crypt(&ctx, dat, dat, len);
2146 	crc = ~0;
2147 	for (i = 0; i < len; i++)
2148 		crc = crc32tab[(crc ^ dat[i]) & 0xff] ^ (crc >> 8);
2149 	crc = ~crc;
2150 	dat += len;
2151 
2152 	/* decrypt little-endian crc32 and verify */
2153 	rc4_crypt(&ctx, dat, dat, IEEE80211_WEP_CRCLEN);
2154 
2155 	if ((dat[0] != crc) && (dat[1] != crc >> 8) &&
2156 	    (dat[2] != crc >> 16) && (dat[3] != crc >> 24)) {
2157 		if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
2158 			printf(WI_PRT_FMT ": wi_do_hostdecrypt: iv mismatch: "
2159 			    "0x%02x%02x%02x%02x vs. 0x%x\n", WI_PRT_ARG(sc),
2160 			    dat[3], dat[2], dat[1], dat[0], crc);
2161 		return -1;
2162 	}
2163 
2164 	return 0;
2165 }
2166 
2167 void
2168 wi_start(ifp)
2169 	struct ifnet		*ifp;
2170 {
2171 	struct wi_softc		*sc;
2172 	struct mbuf		*m0;
2173 	struct wi_frame		tx_frame;
2174 	struct ether_header	*eh;
2175 	int			id;
2176 
2177 	sc = ifp->if_softc;
2178 
2179 	DPRINTF(WID_START, ("wi_start: ifp %p sc %p\n", ifp, sc));
2180 
2181 	if (!(sc->wi_flags & WI_FLAGS_ATTACHED))
2182 		return;
2183 
2184 	if (ifp->if_flags & IFF_OACTIVE)
2185 		return;
2186 
2187 nextpkt:
2188 	IFQ_DEQUEUE(&ifp->if_snd, m0);
2189 	if (m0 == NULL)
2190 		return;
2191 
2192 	bzero((char *)&tx_frame, sizeof(tx_frame));
2193 	tx_frame.wi_frame_ctl = htole16(WI_FTYPE_DATA);
2194 	id = sc->wi_tx_data_id;
2195 	eh = mtod(m0, struct ether_header *);
2196 
2197 	if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
2198 		if (!wihap_check_tx(&sc->wi_hostap_info, eh->ether_dhost,
2199 		    &tx_frame.wi_tx_rate) && !(ifp->if_flags & IFF_PROMISC)) {
2200 			if (ifp->if_flags & IFF_DEBUG)
2201 				printf(WI_PRT_FMT
2202 				    ": wi_start: dropping unassoc dst %s\n",
2203 				    WI_PRT_ARG(sc),
2204 				    ether_sprintf(eh->ether_dhost));
2205 			m_freem(m0);
2206 			goto nextpkt;
2207 		}
2208 	}
2209 
2210 	/*
2211 	 * Use RFC1042 encoding for IP and ARP datagrams,
2212 	 * 802.3 for anything else.
2213 	 */
2214 	if (eh->ether_type == htons(ETHERTYPE_IP) ||
2215 	    eh->ether_type == htons(ETHERTYPE_ARP) ||
2216 	    eh->ether_type == htons(ETHERTYPE_REVARP) ||
2217 	    eh->ether_type == htons(ETHERTYPE_IPV6)) {
2218 		bcopy((char *)&eh->ether_dhost,
2219 		    (char *)&tx_frame.wi_addr1, ETHER_ADDR_LEN);
2220 		if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
2221 			tx_frame.wi_tx_ctl = htole16(WI_ENC_TX_MGMT); /* XXX */
2222 			tx_frame.wi_frame_ctl |= htole16(WI_FCTL_FROMDS);
2223 			if (sc->wi_use_wep)
2224 				tx_frame.wi_frame_ctl |= htole16(WI_FCTL_WEP);
2225 			bcopy((char *)&sc->sc_arpcom.ac_enaddr,
2226 			    (char *)&tx_frame.wi_addr2, ETHER_ADDR_LEN);
2227 			bcopy((char *)&eh->ether_shost,
2228 			    (char *)&tx_frame.wi_addr3, ETHER_ADDR_LEN);
2229 		} else
2230 			bcopy((char *)&eh->ether_shost,
2231 			    (char *)&tx_frame.wi_addr2, ETHER_ADDR_LEN);
2232 		bcopy((char *)&eh->ether_dhost,
2233 		    (char *)&tx_frame.wi_dst_addr, ETHER_ADDR_LEN);
2234 		bcopy((char *)&eh->ether_shost,
2235 		    (char *)&tx_frame.wi_src_addr, ETHER_ADDR_LEN);
2236 
2237 		tx_frame.wi_dat_len = m0->m_pkthdr.len - WI_SNAPHDR_LEN;
2238 		tx_frame.wi_dat[0] = htons(WI_SNAP_WORD0);
2239 		tx_frame.wi_dat[1] = htons(WI_SNAP_WORD1);
2240 		tx_frame.wi_len = htons(m0->m_pkthdr.len - WI_SNAPHDR_LEN);
2241 		tx_frame.wi_type = eh->ether_type;
2242 
2243 		if (sc->wi_ptype == WI_PORTTYPE_HOSTAP && sc->wi_use_wep) {
2244 
2245 			/* Do host encryption. */
2246 			bcopy(&tx_frame.wi_dat[0], &sc->wi_txbuf[4], 8);
2247 
2248 			m_copydata(m0, sizeof(struct ether_header),
2249 			    m0->m_pkthdr.len - sizeof(struct ether_header),
2250 			    (caddr_t)&sc->wi_txbuf[12]);
2251 
2252 			wi_do_hostencrypt(sc, (caddr_t)&sc->wi_txbuf,
2253 			    tx_frame.wi_dat_len);
2254 
2255 			tx_frame.wi_dat_len += IEEE80211_WEP_IVLEN +
2256 			    IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
2257 
2258 			tx_frame.wi_dat_len = htole16(tx_frame.wi_dat_len);
2259 			wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
2260 			    sizeof(struct wi_frame));
2261 			wi_write_data(sc, id, WI_802_11_OFFSET_RAW,
2262 			    (caddr_t)&sc->wi_txbuf,
2263 			    (m0->m_pkthdr.len -
2264 			     sizeof(struct ether_header)) + 18);
2265 		} else {
2266 			m_copydata(m0, sizeof(struct ether_header),
2267 			    m0->m_pkthdr.len - sizeof(struct ether_header),
2268 			    (caddr_t)&sc->wi_txbuf);
2269 
2270 			tx_frame.wi_dat_len = htole16(tx_frame.wi_dat_len);
2271 			wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
2272 			    sizeof(struct wi_frame));
2273 			wi_write_data(sc, id, WI_802_11_OFFSET,
2274 			    (caddr_t)&sc->wi_txbuf,
2275 			    (m0->m_pkthdr.len -
2276 			     sizeof(struct ether_header)) + 2);
2277 		}
2278 	} else {
2279 		tx_frame.wi_dat_len = htole16(m0->m_pkthdr.len);
2280 
2281 		if (sc->wi_ptype == WI_PORTTYPE_HOSTAP && sc->wi_use_wep) {
2282 
2283 			/* Do host encryption. (XXX - not implemented) */
2284 			printf(WI_PRT_FMT
2285 			    ": host encrypt not implemented for 802.3\n",
2286 			    WI_PRT_ARG(sc));
2287 		} else {
2288 			m_copydata(m0, 0, m0->m_pkthdr.len,
2289 			    (caddr_t)&sc->wi_txbuf);
2290 
2291 			wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
2292 			    sizeof(struct wi_frame));
2293 			wi_write_data(sc, id, WI_802_3_OFFSET,
2294 			    (caddr_t)&sc->wi_txbuf, m0->m_pkthdr.len + 2);
2295 		}
2296 	}
2297 
2298 #if NBPFILTER > 0
2299 	/*
2300 	 * If there's a BPF listener, bounce a copy of
2301 	 * this frame to him.
2302 	 */
2303 	if (ifp->if_bpf)
2304 		BPF_MTAP(ifp, m0);
2305 #endif
2306 
2307 	m_freem(m0);
2308 
2309 	ifp->if_flags |= IFF_OACTIVE;
2310 
2311 	/*
2312 	 * Set a timeout in case the chip goes out to lunch.
2313 	 */
2314 	ifp->if_timer = 5;
2315 
2316 	if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0))
2317 		printf(WI_PRT_FMT ": wi_start: xmit failed\n", WI_PRT_ARG(sc));
2318 
2319 	return;
2320 }
2321 
2322 STATIC int
2323 wi_mgmt_xmit(sc, data, len)
2324 	struct wi_softc		*sc;
2325 	caddr_t			data;
2326 	int			len;
2327 {
2328 	struct wi_frame		tx_frame;
2329 	int			id;
2330 	struct wi_80211_hdr	*hdr;
2331 	caddr_t			dptr;
2332 
2333 	if (!(sc->wi_flags & WI_FLAGS_ATTACHED))
2334 		return(ENODEV);
2335 
2336 	hdr = (struct wi_80211_hdr *)data;
2337 	dptr = data + sizeof(struct wi_80211_hdr);
2338 
2339 	bzero((char *)&tx_frame, sizeof(tx_frame));
2340 	id = sc->wi_tx_mgmt_id;
2341 
2342 	bcopy((char *)hdr, (char *)&tx_frame.wi_frame_ctl,
2343 	   sizeof(struct wi_80211_hdr));
2344 
2345 	tx_frame.wi_tx_ctl = htole16(WI_ENC_TX_MGMT);
2346 	tx_frame.wi_dat_len = len - sizeof(struct wi_80211_hdr);
2347 	tx_frame.wi_len = htole16(tx_frame.wi_dat_len);
2348 
2349 	tx_frame.wi_dat_len = htole16(tx_frame.wi_dat_len);
2350 	wi_write_data(sc, id, 0, (caddr_t)&tx_frame, sizeof(struct wi_frame));
2351 	wi_write_data(sc, id, WI_802_11_OFFSET_RAW, dptr,
2352 	    (len - sizeof(struct wi_80211_hdr)) + 2);
2353 
2354 	if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0)) {
2355 		printf(WI_PRT_FMT ": wi_mgmt_xmit: xmit failed\n",
2356 		    WI_PRT_ARG(sc));
2357 		return(EIO);
2358 	}
2359 
2360 	return(0);
2361 }
2362 
2363 void
2364 wi_stop(sc)
2365 	struct wi_softc		*sc;
2366 {
2367 	struct ifnet		*ifp;
2368 
2369 	wihap_shutdown(sc);
2370 
2371 	if (!(sc->wi_flags & WI_FLAGS_ATTACHED))
2372 		return;
2373 
2374 	DPRINTF(WID_STOP, ("wi_stop: sc %p\n", sc));
2375 
2376 	timeout_del(&sc->sc_timo);
2377 
2378 	ifp = &sc->sc_arpcom.ac_if;
2379 
2380 	wi_intr_enable(sc, 0);
2381 	wi_cmd(sc, WI_CMD_DISABLE|sc->wi_portnum, 0, 0, 0);
2382 
2383 	ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
2384 	ifp->if_timer = 0;
2385 
2386 	return;
2387 }
2388 
2389 
2390 void
2391 wi_watchdog(ifp)
2392 	struct ifnet		*ifp;
2393 {
2394 	struct wi_softc		*sc;
2395 
2396 	sc = ifp->if_softc;
2397 
2398 	printf(WI_PRT_FMT ": device timeout\n", WI_PRT_ARG(sc));
2399 
2400 	wi_cor_reset(sc);
2401 	wi_init(sc);
2402 
2403 	ifp->if_oerrors++;
2404 
2405 	return;
2406 }
2407 
2408 void
2409 wi_detach(sc)
2410 	struct wi_softc *sc;
2411 {
2412 	struct ifnet *ifp;
2413 	ifp = &sc->sc_arpcom.ac_if;
2414 
2415 	if (ifp->if_flags & IFF_RUNNING)
2416 		wi_stop(sc);
2417 
2418 	if (sc->wi_flags & WI_FLAGS_ATTACHED) {
2419 		sc->wi_flags &= ~WI_FLAGS_ATTACHED;
2420 		shutdownhook_disestablish(sc->sc_sdhook);
2421 	}
2422 }
2423 
2424 STATIC void
2425 wi_shutdown(arg)
2426 	void			*arg;
2427 {
2428 	struct wi_softc		*sc;
2429 
2430 	sc = arg;
2431 	wi_stop(sc);
2432 
2433 	return;
2434 }
2435 
2436 STATIC void
2437 wi_get_id(sc)
2438 	struct wi_softc *sc;
2439 {
2440 	struct wi_ltv_ver		ver;
2441 	const struct wi_card_ident	*id;
2442 	u_int16_t			pri_fw_ver[3];
2443 	const char			*card_name;
2444 	u_int16_t			card_id;
2445 
2446 	/* get chip identity */
2447 	bzero(&ver, sizeof(ver));
2448 	ver.wi_type = WI_RID_CARD_ID;
2449 	ver.wi_len = 5;
2450 	wi_read_record(sc, (struct wi_ltv_gen *)&ver);
2451 	card_id = letoh16(ver.wi_ver[0]);
2452 	for (id = wi_card_ident; id->firm_type != WI_NOTYPE; id++) {
2453 		if (card_id == id->card_id)
2454 			break;
2455 	}
2456 	if (id->firm_type != WI_NOTYPE) {
2457 		sc->sc_firmware_type = id->firm_type;
2458 		card_name = id->card_name;
2459 	} else if (ver.wi_ver[0] & htole16(0x8000)) {
2460 		sc->sc_firmware_type = WI_INTERSIL;
2461 		card_name = "Unknown PRISM2 chip";
2462 	} else {
2463 		sc->sc_firmware_type = WI_LUCENT;
2464 	}
2465 
2466 	/* get primary firmware version (XXX - how to do Lucent?) */
2467 	if (sc->sc_firmware_type != WI_LUCENT) {
2468 		bzero(&ver, sizeof(ver));
2469 		ver.wi_type = WI_RID_PRI_IDENTITY;
2470 		ver.wi_len = 5;
2471 		wi_read_record(sc, (struct wi_ltv_gen *)&ver);
2472 		pri_fw_ver[0] = letoh16(ver.wi_ver[2]);
2473 		pri_fw_ver[1] = letoh16(ver.wi_ver[3]);
2474 		pri_fw_ver[2] = letoh16(ver.wi_ver[1]);
2475 	}
2476 
2477 	/* get station firmware version */
2478 	bzero(&ver, sizeof(ver));
2479 	ver.wi_type = WI_RID_STA_IDENTITY;
2480 	ver.wi_len = 5;
2481 	wi_read_record(sc, (struct wi_ltv_gen *)&ver);
2482 	ver.wi_ver[1] = letoh16(ver.wi_ver[1]);
2483 	ver.wi_ver[2] = letoh16(ver.wi_ver[2]);
2484 	ver.wi_ver[3] = letoh16(ver.wi_ver[3]);
2485 	sc->sc_sta_firmware_ver = ver.wi_ver[2] * 10000 +
2486 	    ver.wi_ver[3] * 100 + ver.wi_ver[1];
2487 
2488 	if (sc->sc_firmware_type == WI_INTERSIL &&
2489 	    (sc->sc_sta_firmware_ver == 10102 || sc->sc_sta_firmware_ver == 20102)) {
2490 		struct wi_ltv_str sver;
2491 		char *p;
2492 
2493 		bzero(&sver, sizeof(sver));
2494 		sver.wi_type = WI_RID_SYMBOL_IDENTITY;
2495 		sver.wi_len = 7;
2496 		/* value should be something like "V2.00-11" */
2497 		if (wi_read_record(sc, (struct wi_ltv_gen *)&sver) == 0 &&
2498 		    *(p = (char *)sver.wi_str) >= 'A' &&
2499 		    p[2] == '.' && p[5] == '-' && p[8] == '\0') {
2500 			sc->sc_firmware_type = WI_SYMBOL;
2501 			sc->sc_sta_firmware_ver = (p[1] - '0') * 10000 +
2502 			    (p[3] - '0') * 1000 + (p[4] - '0') * 100 +
2503 			    (p[6] - '0') * 10 + (p[7] - '0');
2504 		}
2505 	}
2506 
2507 	if (sc->sc_firmware_type == WI_LUCENT) {
2508 		printf("\n%s: Firmware %d.%02d variant %d, ", WI_PRT_ARG(sc),
2509 		    ver.wi_ver[2], ver.wi_ver[3], ver.wi_ver[1]);
2510 	} else {
2511 		printf("\n%s: %s%s, Firmware %d.%d.%d (primary), %d.%d.%d (station), ",
2512 		    WI_PRT_ARG(sc),
2513 		    sc->sc_firmware_type == WI_SYMBOL ? "Symbol " : "",
2514 		    card_name, pri_fw_ver[0], pri_fw_ver[1], pri_fw_ver[2],
2515 		    sc->sc_sta_firmware_ver / 10000,
2516 		    (sc->sc_sta_firmware_ver % 10000) / 100,
2517 		    sc->sc_sta_firmware_ver % 100);
2518 	}
2519 }
2520 
2521 STATIC int
2522 wi_sync_media(sc, ptype, txrate)
2523 	struct wi_softc *sc;
2524 	int ptype;
2525 	int txrate;
2526 {
2527 	int media = sc->sc_media.ifm_cur->ifm_media;
2528 	int options = IFM_OPTIONS(media);
2529 	int subtype;
2530 
2531 	switch (txrate) {
2532 	case 1:
2533 		subtype = IFM_IEEE80211_DS1;
2534 		break;
2535 	case 2:
2536 		subtype = IFM_IEEE80211_DS2;
2537 		break;
2538 	case 3:
2539 		subtype = IFM_AUTO;
2540 		break;
2541 	case 5:
2542 		subtype = IFM_IEEE80211_DS5;
2543 		break;
2544 	case 11:
2545 		subtype = IFM_IEEE80211_DS11;
2546 		break;
2547 	default:
2548 		subtype = IFM_MANUAL;		/* Unable to represent */
2549 		break;
2550 	}
2551 
2552 	options &= ~IFM_OMASK;
2553 	switch (ptype) {
2554 	case WI_PORTTYPE_BSS:
2555 		/* default port type */
2556 		break;
2557 	case WI_PORTTYPE_ADHOC:
2558 		options |= IFM_IEEE80211_ADHOC;
2559 		break;
2560 	case WI_PORTTYPE_HOSTAP:
2561 		options |= IFM_IEEE80211_HOSTAP;
2562 		break;
2563 	case WI_PORTTYPE_IBSS:
2564 		if (sc->wi_create_ibss)
2565 			options |= IFM_IEEE80211_IBSSMASTER;
2566 		else
2567 			options |= IFM_IEEE80211_IBSS;
2568 		break;
2569 	default:
2570 		subtype = IFM_MANUAL;		/* Unable to represent */
2571 		break;
2572 	}
2573 	media = IFM_MAKEWORD(IFM_TYPE(media), subtype, options,
2574 	IFM_INST(media));
2575 	if (ifmedia_match(&sc->sc_media, media, sc->sc_media.ifm_mask) == NULL)
2576 		return (EINVAL);
2577 	ifmedia_set(&sc->sc_media, media);
2578 	sc->wi_ptype = ptype;
2579 	sc->wi_tx_rate = txrate;
2580 	return (0);
2581 }
2582 
2583 STATIC int
2584 wi_media_change(ifp)
2585 	struct ifnet *ifp;
2586 {
2587 	struct wi_softc *sc = ifp->if_softc;
2588 	int otype = sc->wi_ptype;
2589 	int orate = sc->wi_tx_rate;
2590 	int ocreate_ibss = sc->wi_create_ibss;
2591 
2592 	if ((sc->sc_media.ifm_cur->ifm_media & IFM_IEEE80211_HOSTAP) &&
2593 	    sc->sc_firmware_type != WI_INTERSIL)
2594 		return (EINVAL);
2595 
2596 	sc->wi_create_ibss = 0;
2597 
2598 	switch (sc->sc_media.ifm_cur->ifm_media & IFM_OMASK) {
2599 	case 0:
2600 		sc->wi_ptype = WI_PORTTYPE_BSS;
2601 		break;
2602 	case IFM_IEEE80211_ADHOC:
2603 		sc->wi_ptype = WI_PORTTYPE_ADHOC;
2604 		break;
2605 	case IFM_IEEE80211_HOSTAP:
2606 		sc->wi_ptype = WI_PORTTYPE_HOSTAP;
2607 		break;
2608 	case IFM_IEEE80211_IBSSMASTER:
2609 	case IFM_IEEE80211_IBSSMASTER|IFM_IEEE80211_IBSS:
2610 		if (!(sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS))
2611 			return (EINVAL);
2612 		sc->wi_create_ibss = 1;
2613 		/* FALLTHROUGH */
2614 	case IFM_IEEE80211_IBSS:
2615 		sc->wi_ptype = WI_PORTTYPE_IBSS;
2616 		break;
2617 	default:
2618 		/* Invalid combination. */
2619 		return (EINVAL);
2620 	}
2621 
2622 	switch (IFM_SUBTYPE(sc->sc_media.ifm_cur->ifm_media)) {
2623 	case IFM_IEEE80211_DS1:
2624 		sc->wi_tx_rate = 1;
2625 		break;
2626 	case IFM_IEEE80211_DS2:
2627 		sc->wi_tx_rate = 2;
2628 		break;
2629 	case IFM_AUTO:
2630 		sc->wi_tx_rate = 3;
2631 		break;
2632 	case IFM_IEEE80211_DS5:
2633 		sc->wi_tx_rate = 5;
2634 		break;
2635 	case IFM_IEEE80211_DS11:
2636 		sc->wi_tx_rate = 11;
2637 		break;
2638 	}
2639 
2640 	if (sc->sc_arpcom.ac_if.if_flags & IFF_UP) {
2641 		if (otype != sc->wi_ptype || orate != sc->wi_tx_rate ||
2642 		    ocreate_ibss != sc->wi_create_ibss)
2643 			wi_init(sc);
2644 	}
2645 
2646 	ifp->if_baudrate = ifmedia_baudrate(sc->sc_media.ifm_cur->ifm_media);
2647 
2648 	return (0);
2649 }
2650 
2651 STATIC void
2652 wi_media_status(ifp, imr)
2653 	struct ifnet *ifp;
2654 	struct ifmediareq *imr;
2655 {
2656 	struct wi_softc *sc = ifp->if_softc;
2657 	struct wi_req wreq;
2658 
2659 	if (!(sc->sc_arpcom.ac_if.if_flags & IFF_UP)) {
2660 		imr->ifm_active = IFM_IEEE80211|IFM_NONE;
2661 		imr->ifm_status = 0;
2662 		return;
2663 	}
2664 
2665 	if (sc->wi_tx_rate == 3) {
2666 		imr->ifm_active = IFM_IEEE80211|IFM_AUTO;
2667 
2668 		wreq.wi_type = WI_RID_CUR_TX_RATE;
2669 		wreq.wi_len = WI_MAX_DATALEN;
2670 		if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0) {
2671 			switch (letoh16(wreq.wi_val[0])) {
2672 			case 1:
2673 				imr->ifm_active |= IFM_IEEE80211_DS1;
2674 				break;
2675 			case 2:
2676 				imr->ifm_active |= IFM_IEEE80211_DS2;
2677 				break;
2678 			case 6:
2679 				imr->ifm_active |= IFM_IEEE80211_DS5;
2680 				break;
2681 			case 11:
2682 				imr->ifm_active |= IFM_IEEE80211_DS11;
2683 				break;
2684 			}
2685 		}
2686 	} else {
2687 		imr->ifm_active = sc->sc_media.ifm_cur->ifm_media;
2688 	}
2689 
2690 	imr->ifm_status = IFM_AVALID;
2691 	switch (sc->wi_ptype) {
2692 	case WI_PORTTYPE_ADHOC:
2693 	case WI_PORTTYPE_IBSS:
2694 		/*
2695 		 * XXX: It would be nice if we could give some actually
2696 		 * useful status like whether we joined another IBSS or
2697 		 * created one ourselves.
2698 		 */
2699 		/* FALLTHROUGH */
2700 	case WI_PORTTYPE_HOSTAP:
2701 		imr->ifm_status |= IFM_ACTIVE;
2702 		break;
2703 	default:
2704 		wreq.wi_type = WI_RID_COMMQUAL;
2705 		wreq.wi_len = WI_MAX_DATALEN;
2706 		if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0 &&
2707 		    letoh16(wreq.wi_val[0]) != 0)
2708 			imr->ifm_status |= IFM_ACTIVE;
2709 	}
2710 }
2711 
2712 STATIC int
2713 wi_set_nwkey(sc, nwkey)
2714 	struct wi_softc *sc;
2715 	struct ieee80211_nwkey *nwkey;
2716 {
2717 	int i, len, error;
2718 	struct wi_req wreq;
2719 	struct wi_ltv_keys *wk = (struct wi_ltv_keys *)&wreq;
2720 
2721 	if (!(sc->wi_flags & WI_FLAGS_HAS_WEP))
2722 		return ENODEV;
2723 	if (nwkey->i_defkid <= 0 || nwkey->i_defkid > IEEE80211_WEP_NKID)
2724 		return EINVAL;
2725 	memcpy(wk, &sc->wi_keys, sizeof(*wk));
2726 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
2727 		if (nwkey->i_key[i].i_keydat == NULL)
2728 			continue;
2729 		len = nwkey->i_key[i].i_keylen;
2730 		if (len > sizeof(wk->wi_keys[i].wi_keydat))
2731 			return EINVAL;
2732 		error = copyin(nwkey->i_key[i].i_keydat,
2733 		    wk->wi_keys[i].wi_keydat, len);
2734 		if (error)
2735 			return error;
2736 		wk->wi_keys[i].wi_keylen = htole16(len);
2737 	}
2738 
2739 	wk->wi_len = (sizeof(*wk) / 2) + 1;
2740 	wk->wi_type = WI_RID_DEFLT_CRYPT_KEYS;
2741 	if (sc->sc_arpcom.ac_if.if_flags & IFF_UP) {
2742 		error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
2743 		if (error)
2744 			return error;
2745 	}
2746 	if ((error = wi_setdef(sc, &wreq)))
2747 		return (error);
2748 
2749 	wreq.wi_len = 2;
2750 	wreq.wi_type = WI_RID_TX_CRYPT_KEY;
2751 	wreq.wi_val[0] = htole16(nwkey->i_defkid - 1);
2752 	if (sc->sc_arpcom.ac_if.if_flags & IFF_UP) {
2753 		error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
2754 		if (error)
2755 			return error;
2756 	}
2757 	if ((error = wi_setdef(sc, &wreq)))
2758 		return (error);
2759 
2760 	wreq.wi_type = WI_RID_ENCRYPTION;
2761 	wreq.wi_val[0] = htole16(nwkey->i_wepon);
2762 	if (sc->sc_arpcom.ac_if.if_flags & IFF_UP) {
2763 		error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
2764 		if (error)
2765 			return error;
2766 	}
2767 	if ((error = wi_setdef(sc, &wreq)))
2768 		return (error);
2769 
2770 	if (sc->sc_arpcom.ac_if.if_flags & IFF_UP)
2771 		wi_init(sc);
2772 	return 0;
2773 }
2774 
2775 STATIC int
2776 wi_get_nwkey(sc, nwkey)
2777 	struct wi_softc *sc;
2778 	struct ieee80211_nwkey *nwkey;
2779 {
2780 	int i, len, error;
2781 	struct wi_ltv_keys *wk = &sc->wi_keys;
2782 
2783 	if (!(sc->wi_flags & WI_FLAGS_HAS_WEP))
2784 		return ENODEV;
2785 	nwkey->i_wepon = sc->wi_use_wep;
2786 	nwkey->i_defkid = sc->wi_tx_key + 1;
2787 
2788 	/* do not show any keys to non-root user */
2789 	error = suser(curproc, 0);
2790 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
2791 		if (nwkey->i_key[i].i_keydat == NULL)
2792 			continue;
2793 		/* error holds results of suser() for the first time */
2794 		if (error)
2795 			return error;
2796 		len = letoh16(wk->wi_keys[i].wi_keylen);
2797 		if (nwkey->i_key[i].i_keylen < len)
2798 			return ENOSPC;
2799 		nwkey->i_key[i].i_keylen = len;
2800 		error = copyout(wk->wi_keys[i].wi_keydat,
2801 		    nwkey->i_key[i].i_keydat, len);
2802 		if (error)
2803 			return error;
2804 	}
2805 	return 0;
2806 }
2807 
2808 STATIC int
2809 wi_set_pm(struct wi_softc *sc, struct ieee80211_power *power)
2810 {
2811 
2812 	sc->wi_pm_enabled = power->i_enabled;
2813 	sc->wi_max_sleep = power->i_maxsleep;
2814 
2815 	if (sc->sc_arpcom.ac_if.if_flags & IFF_UP)
2816 		wi_init(sc);
2817 
2818 	return (0);
2819 }
2820 
2821 STATIC int
2822 wi_get_pm(struct wi_softc *sc, struct ieee80211_power *power)
2823 {
2824 
2825 	power->i_enabled = sc->wi_pm_enabled;
2826 	power->i_maxsleep = sc->wi_max_sleep;
2827 
2828 	return (0);
2829 }
2830 
2831 STATIC int
2832 wi_set_ssid(ws, id, len)
2833 	struct ieee80211_nwid *ws;
2834 	u_int8_t *id;
2835 	int len;
2836 {
2837 
2838 	if (len > IEEE80211_NWID_LEN)
2839 		return (EINVAL);
2840 	ws->i_len = len;
2841 	memcpy(ws->i_nwid, id, len);
2842 	return (0);
2843 }
2844 
2845 STATIC int
2846 wi_get_debug(sc, wreq)
2847 	struct wi_softc		*sc;
2848 	struct wi_req		*wreq;
2849 {
2850 	int			error = 0;
2851 
2852 	wreq->wi_len = 1;
2853 
2854 	switch (wreq->wi_type) {
2855 	case WI_DEBUG_SLEEP:
2856 		wreq->wi_len++;
2857 		wreq->wi_val[0] = htole16(sc->wi_debug.wi_sleep);
2858 		break;
2859 	case WI_DEBUG_DELAYSUPP:
2860 		wreq->wi_len++;
2861 		wreq->wi_val[0] = htole16(sc->wi_debug.wi_delaysupp);
2862 		break;
2863 	case WI_DEBUG_TXSUPP:
2864 		wreq->wi_len++;
2865 		wreq->wi_val[0] = htole16(sc->wi_debug.wi_txsupp);
2866 		break;
2867 	case WI_DEBUG_MONITOR:
2868 		wreq->wi_len++;
2869 		wreq->wi_val[0] = htole16(sc->wi_debug.wi_monitor);
2870 		break;
2871 	case WI_DEBUG_LEDTEST:
2872 		wreq->wi_len += 3;
2873 		wreq->wi_val[0] = htole16(sc->wi_debug.wi_ledtest);
2874 		wreq->wi_val[1] = htole16(sc->wi_debug.wi_ledtest_param0);
2875 		wreq->wi_val[2] = htole16(sc->wi_debug.wi_ledtest_param1);
2876 		break;
2877 	case WI_DEBUG_CONTTX:
2878 		wreq->wi_len += 2;
2879 		wreq->wi_val[0] = htole16(sc->wi_debug.wi_conttx);
2880 		wreq->wi_val[1] = htole16(sc->wi_debug.wi_conttx_param0);
2881 		break;
2882 	case WI_DEBUG_CONTRX:
2883 		wreq->wi_len++;
2884 		wreq->wi_val[0] = htole16(sc->wi_debug.wi_contrx);
2885 		break;
2886 	case WI_DEBUG_SIGSTATE:
2887 		wreq->wi_len += 2;
2888 		wreq->wi_val[0] = htole16(sc->wi_debug.wi_sigstate);
2889 		wreq->wi_val[1] = htole16(sc->wi_debug.wi_sigstate_param0);
2890 		break;
2891 	case WI_DEBUG_CONFBITS:
2892 		wreq->wi_len += 2;
2893 		wreq->wi_val[0] = htole16(sc->wi_debug.wi_confbits);
2894 		wreq->wi_val[1] = htole16(sc->wi_debug.wi_confbits_param0);
2895 		break;
2896 	default:
2897 		error = EIO;
2898 		break;
2899 	}
2900 
2901 	return (error);
2902 }
2903 
2904 STATIC int
2905 wi_set_debug(sc, wreq)
2906 	struct wi_softc		*sc;
2907 	struct wi_req		*wreq;
2908 {
2909 	int				error = 0;
2910 	u_int16_t			cmd, param0 = 0, param1 = 0;
2911 
2912 	switch (wreq->wi_type) {
2913 	case WI_DEBUG_RESET:
2914 	case WI_DEBUG_INIT:
2915 	case WI_DEBUG_CALENABLE:
2916 		break;
2917 	case WI_DEBUG_SLEEP:
2918 		sc->wi_debug.wi_sleep = 1;
2919 		break;
2920 	case WI_DEBUG_WAKE:
2921 		sc->wi_debug.wi_sleep = 0;
2922 		break;
2923 	case WI_DEBUG_CHAN:
2924 		param0 = letoh16(wreq->wi_val[0]);
2925 		break;
2926 	case WI_DEBUG_DELAYSUPP:
2927 		sc->wi_debug.wi_delaysupp = 1;
2928 		break;
2929 	case WI_DEBUG_TXSUPP:
2930 		sc->wi_debug.wi_txsupp = 1;
2931 		break;
2932 	case WI_DEBUG_MONITOR:
2933 		sc->wi_debug.wi_monitor = 1;
2934 		break;
2935 	case WI_DEBUG_LEDTEST:
2936 		param0 = letoh16(wreq->wi_val[0]);
2937 		param1 = letoh16(wreq->wi_val[1]);
2938 		sc->wi_debug.wi_ledtest = 1;
2939 		sc->wi_debug.wi_ledtest_param0 = param0;
2940 		sc->wi_debug.wi_ledtest_param1 = param1;
2941 		break;
2942 	case WI_DEBUG_CONTTX:
2943 		param0 = letoh16(wreq->wi_val[0]);
2944 		sc->wi_debug.wi_conttx = 1;
2945 		sc->wi_debug.wi_conttx_param0 = param0;
2946 		break;
2947 	case WI_DEBUG_STOPTEST:
2948 		sc->wi_debug.wi_delaysupp = 0;
2949 		sc->wi_debug.wi_txsupp = 0;
2950 		sc->wi_debug.wi_monitor = 0;
2951 		sc->wi_debug.wi_ledtest = 0;
2952 		sc->wi_debug.wi_ledtest_param0 = 0;
2953 		sc->wi_debug.wi_ledtest_param1 = 0;
2954 		sc->wi_debug.wi_conttx = 0;
2955 		sc->wi_debug.wi_conttx_param0 = 0;
2956 		sc->wi_debug.wi_contrx = 0;
2957 		sc->wi_debug.wi_sigstate = 0;
2958 		sc->wi_debug.wi_sigstate_param0 = 0;
2959 		break;
2960 	case WI_DEBUG_CONTRX:
2961 		sc->wi_debug.wi_contrx = 1;
2962 		break;
2963 	case WI_DEBUG_SIGSTATE:
2964 		param0 = letoh16(wreq->wi_val[0]);
2965 		sc->wi_debug.wi_sigstate = 1;
2966 		sc->wi_debug.wi_sigstate_param0 = param0;
2967 		break;
2968 	case WI_DEBUG_CONFBITS:
2969 		param0 = letoh16(wreq->wi_val[0]);
2970 		param1 = letoh16(wreq->wi_val[1]);
2971 		sc->wi_debug.wi_confbits = param0;
2972 		sc->wi_debug.wi_confbits_param0 = param1;
2973 		break;
2974 	default:
2975 		error = EIO;
2976 		break;
2977 	}
2978 
2979 	if (error)
2980 		return (error);
2981 
2982 	cmd = WI_CMD_DEBUG | (wreq->wi_type << 8);
2983 	error = wi_cmd(sc, cmd, param0, param1, 0);
2984 
2985 	return (error);
2986 }
2987