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