xref: /openbsd-src/sys/dev/ic/an.c (revision 0b7734b3d77bb9b21afec6f4621cae6c805dbd45)
1 /*	$OpenBSD: an.c,v 1.71 2016/04/13 10:49:26 mpi Exp $	*/
2 /*	$NetBSD: an.c,v 1.34 2005/06/20 02:49:18 atatat Exp $	*/
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  * $FreeBSD: src/sys/dev/an/if_an.c,v 1.12 2000/11/13 23:04:12 wpaul Exp $
35  */
36 /*
37  * Copyright (c) 2004, 2005 David Young.  All rights reserved.
38  * Copyright (c) 2004, 2005 OJC Technologies.  All rights reserved.
39  * Copyright (c) 2004, 2005 Dayton Data Center Services, LLC.  All
40  *     rights reserved.
41  *
42  * Redistribution and use in source and binary forms, with or without
43  * modification, are permitted provided that the following conditions
44  * are met:
45  * 1. Redistributions of source code must retain the above copyright
46  *    notice, this list of conditions and the following disclaimer.
47  * 2. Redistributions in binary form must reproduce the above copyright
48  *    notice, this list of conditions and the following disclaimer in the
49  *    documentation and/or other materials provided with the distribution.
50  * 3. Neither the name of the author nor the names of any co-contributors
51  *    may be used to endorse or promote products derived from this software
52  *    without specific prior written permission.
53  *
54  * THIS SOFTWARE IS PROVIDED BY David Young AND CONTRIBUTORS ``AS IS'' AND
55  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57  * ARE DISCLAIMED.  IN NO EVENT SHALL David Young AND CONTRIBUTORS
58  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
59  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
60  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
61  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
62  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
63  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
64  * THE POSSIBILITY OF SUCH DAMAGE.
65  */
66 
67 /*
68  * Aironet 4500/4800 802.11 PCMCIA/ISA/PCI driver for FreeBSD.
69  *
70  * Written by Bill Paul <wpaul@ctr.columbia.edu>
71  * Electrical Engineering Department
72  * Columbia University, New York City
73  */
74 
75 /*
76  * Ported to NetBSD from FreeBSD by Atsushi Onoe at the San Diego
77  * IETF meeting.
78  */
79 
80 #include "bpfilter.h"
81 
82 #include <sys/param.h>
83 #include <sys/systm.h>
84 #include <sys/sockio.h>
85 #include <sys/mbuf.h>
86 #include <sys/kernel.h>
87 #include <sys/ucred.h>
88 #include <sys/socket.h>
89 #include <sys/timeout.h>
90 #include <sys/device.h>
91 #include <sys/endian.h>
92 #include <sys/tree.h>
93 
94 #include <machine/bus.h>
95 
96 #include <net/if.h>
97 #include <net/if_llc.h>
98 #include <net/if_media.h>
99 
100 #include <netinet/in.h>
101 #include <netinet/if_ether.h>
102 
103 #include <net80211/ieee80211_radiotap.h>
104 #include <net80211/ieee80211_var.h>
105 
106 #if NBPFILTER > 0
107 #include <net/bpf.h>
108 #endif
109 
110 #include <dev/ic/anreg.h>
111 #include <dev/ic/anvar.h>
112 
113 struct cfdriver an_cd = {
114 	NULL, "an", DV_IFNET
115 };
116 
117 int	an_reset(struct an_softc *);
118 void	an_wait(struct an_softc *);
119 int	an_init(struct ifnet *);
120 void	an_stop(struct ifnet *, int);
121 void	an_start(struct ifnet *);
122 void	an_watchdog(struct ifnet *);
123 int	an_ioctl(struct ifnet *, u_long, caddr_t);
124 int	an_media_change(struct ifnet *);
125 void	an_media_status(struct ifnet *, struct ifmediareq *);
126 
127 int	an_set_nwkey(struct an_softc *, struct ieee80211_nwkey *);
128 int	an_set_nwkey_wep(struct an_softc *, struct ieee80211_nwkey *);
129 int	an_get_nwkey(struct an_softc *, struct ieee80211_nwkey *);
130 int	an_write_wepkey(struct an_softc *, int, struct an_wepkey *,
131 				int);
132 
133 void	an_rxeof(struct an_softc *);
134 void	an_txeof(struct an_softc *, u_int16_t);
135 void	an_linkstat_intr(struct an_softc *);
136 
137 int	an_cmd(struct an_softc *, int, int);
138 int	an_seek_bap(struct an_softc *, int, int);
139 int	an_read_bap(struct an_softc *, int, int, void *, int, int);
140 int	an_write_bap(struct an_softc *, int, int, void *, int);
141 int	an_mwrite_bap(struct an_softc *, int, int, struct mbuf *, int);
142 int	an_read_rid(struct an_softc *, int, void *, int *);
143 int	an_write_rid(struct an_softc *, int, void *, int);
144 
145 int	an_alloc_nicmem(struct an_softc *, int, int *);
146 
147 int	an_newstate(struct ieee80211com *, enum ieee80211_state, int);
148 
149 #ifdef AN_DEBUG
150 int an_debug = 0;
151 
152 #define	DPRINTF(X)	if (an_debug) printf X
153 #define	DPRINTF2(X)	if (an_debug > 1) printf X
154 #else
155 #define	DPRINTF(X)
156 #define	DPRINTF2(X)
157 #endif
158 
159 #if BYTE_ORDER == BIG_ENDIAN
160 static __inline void
161 an_swap16(u_int16_t *p, int cnt)
162 {
163         for (; cnt--; p++)
164                 *p = swap16(*p);
165 }
166 #define an_switch32(val)	(val >> 16 | (val & 0xFFFF) << 16)
167 #else
168 #define an_swap16(p, cnt)
169 #define an_switch32(val)	val
170 #endif
171 
172 int
173 an_attach(struct an_softc *sc)
174 {
175 	struct ieee80211com *ic = &sc->sc_ic;
176 	struct ifnet *ifp = &ic->ic_if;
177 	int i;
178 	struct an_rid_wepkey *akey;
179 	int buflen, kid, rid;
180 	int chan, chan_min, chan_max;
181 
182 	sc->sc_invalid = 0;
183 
184 	/* disable interrupts */
185 	CSR_WRITE_2(sc, AN_INT_EN, 0);
186 	CSR_WRITE_2(sc, AN_EVENT_ACK, 0xffff);
187 
188 //	an_wait(sc);
189 	if (an_reset(sc) != 0) {
190 		sc->sc_invalid = 1;
191 		return 1;
192 	}
193 
194 	/* Load factory config */
195 	if (an_cmd(sc, AN_CMD_READCFG, 0) != 0) {
196 		printf("%s: failed to load config data\n",
197 		    sc->sc_dev.dv_xname);
198 		return (EIO);
199 	}
200 
201 	/* Read the current configuration */
202 	buflen = sizeof(sc->sc_config);
203 	if (an_read_rid(sc, AN_RID_GENCONFIG, &sc->sc_config, &buflen) != 0) {
204 		printf("%s: read config failed\n", sc->sc_dev.dv_xname);
205 		return(EIO);
206 	}
207 
208 	an_swap16((u_int16_t *)&sc->sc_config.an_macaddr, 3);
209 
210 	/* Read the card capabilities */
211 	buflen = sizeof(sc->sc_caps);
212 	if (an_read_rid(sc, AN_RID_CAPABILITIES, &sc->sc_caps, &buflen) != 0) {
213 		printf("%s: read caps failed\n", sc->sc_dev.dv_xname);
214 		return(EIO);
215 	}
216 
217 	an_swap16((u_int16_t *)&sc->sc_caps.an_oemaddr, 3);
218 	an_swap16((u_int16_t *)&sc->sc_caps.an_rates, 4);
219 
220 	/* Read WEP settings from persistent memory */
221 	akey = &sc->sc_buf.sc_wepkey;
222 	buflen = sizeof(struct an_rid_wepkey);
223 	rid = AN_RID_WEP_VOLATILE;	/* first persistent key */
224 	while (an_read_rid(sc, rid, akey, &buflen) == 0) {
225 		an_swap16((u_int16_t *)&akey->an_mac_addr, 3);
226 		an_swap16((u_int16_t *)&akey->an_key, 8);
227 		kid = akey->an_key_index;
228 		DPRINTF(("an_attach: wep rid=0x%x len=%d(%d) index=0x%04x "
229 		    "mac[0]=%02x keylen=%d\n",
230 		    rid, buflen, sizeof(*akey), kid,
231 		    akey->an_mac_addr[0], akey->an_key_len));
232 		if (kid == 0xffff) {
233 			sc->sc_tx_perskey = akey->an_mac_addr[0];
234 			sc->sc_tx_key = -1;
235 			break;
236 		}
237 		if (kid >= IEEE80211_WEP_NKID)
238 			break;
239 		sc->sc_perskeylen[kid] = akey->an_key_len;
240 		sc->sc_wepkeys[kid].an_wep_keylen = -1;
241 		rid = AN_RID_WEP_PERSISTENT;	/* for next key */
242 		buflen = sizeof(struct an_rid_wepkey);
243 	}
244 
245 	IEEE80211_ADDR_COPY(ic->ic_myaddr, sc->sc_caps.an_oemaddr);
246 	bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
247 
248 	printf("%s: Firmware %x.%02x.%02x, Radio: ", ifp->if_xname,
249 	    sc->sc_caps.an_fwrev >> 8,
250 	    sc->sc_caps.an_fwrev & 0xff,
251 	    sc->sc_caps.an_fwsubrev);
252 
253 	if (sc->sc_config.an_radiotype & AN_RADIOTYPE_80211_FH)
254 		printf("802.11 FH");
255 	else if (sc->sc_config.an_radiotype & AN_RADIOTYPE_80211_DS)
256 		printf("802.11 DS");
257 	else if (sc->sc_config.an_radiotype & AN_RADIOTYPE_LM2000_DS)
258 		printf("LM2000 DS");
259 	else
260 		printf("unknown (%x)", sc->sc_config.an_radiotype);
261 
262 	printf(", address %s\n", ether_sprintf(ic->ic_myaddr));
263 
264 	ifp->if_softc = sc;
265 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
266 	ifp->if_ioctl = an_ioctl;
267 	ifp->if_start = an_start;
268 	ifp->if_watchdog = an_watchdog;
269 
270 	ic->ic_phytype = IEEE80211_T_DS;
271 	ic->ic_opmode = IEEE80211_M_STA;
272 	ic->ic_caps = IEEE80211_C_WEP | IEEE80211_C_PMGT | IEEE80211_C_MONITOR;
273 #ifndef IEEE80211_STA_ONLY
274 	ic->ic_caps |= IEEE80211_C_IBSS;
275 #endif
276 	ic->ic_state = IEEE80211_S_INIT;
277 	IEEE80211_ADDR_COPY(ic->ic_myaddr, sc->sc_caps.an_oemaddr);
278 
279 	switch (sc->sc_caps.an_regdomain) {
280 	default:
281 	case AN_REGDOMAIN_USA:
282 	case AN_REGDOMAIN_CANADA:
283 		chan_min = 1; chan_max = 11; break;
284 	case AN_REGDOMAIN_EUROPE:
285 	case AN_REGDOMAIN_AUSTRALIA:
286 		chan_min = 1; chan_max = 13; break;
287 	case AN_REGDOMAIN_JAPAN:
288 		chan_min = 14; chan_max = 14; break;
289 	case AN_REGDOMAIN_SPAIN:
290 		chan_min = 10; chan_max = 11; break;
291 	case AN_REGDOMAIN_FRANCE:
292 		chan_min = 10; chan_max = 13; break;
293 	case AN_REGDOMAIN_JAPANWIDE:
294 		chan_min = 1; chan_max = 14; break;
295 	}
296 
297 	for (chan = chan_min; chan <= chan_max; chan++) {
298 		ic->ic_channels[chan].ic_freq =
299 		    ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ);
300 		ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_B;
301 	}
302 	ic->ic_ibss_chan = &ic->ic_channels[chan_min];
303 
304 	/* Find supported rate */
305 	for (i = 0; i < sizeof(sc->sc_caps.an_rates); i++) {
306 		if (sc->sc_caps.an_rates[i] == 0)
307 			continue;
308 		ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[
309 		    ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates++] =
310 		    sc->sc_caps.an_rates[i];
311 	}
312 
313 	/*
314 	 * Call MI attach routine.
315 	 */
316 	if_attach(ifp);
317 	ieee80211_ifattach(ifp);
318 
319 	sc->sc_newstate = ic->ic_newstate;
320 	ic->ic_newstate = an_newstate;
321 
322 	ieee80211_media_init(ifp, an_media_change, an_media_status);
323 
324 #if NBPFILTER > 0
325 	bzero(&sc->sc_rxtapu, sizeof(sc->sc_rxtapu));
326 	sc->sc_rxtap.ar_ihdr.it_len = sizeof(sc->sc_rxtapu);
327 	sc->sc_rxtap.ar_ihdr.it_present = AN_RX_RADIOTAP_PRESENT;
328 
329 	bzero(&sc->sc_txtapu, sizeof(sc->sc_txtapu));
330 	sc->sc_txtap.at_ihdr.it_len = sizeof(sc->sc_txtapu);
331 	sc->sc_txtap.at_ihdr.it_present = AN_TX_RADIOTAP_PRESENT;
332 
333 	bpfattach(&sc->sc_drvbpf, ifp, DLT_IEEE802_11_RADIO,
334 	    sizeof(struct ieee80211_frame) + 64);
335 #endif
336 
337 	sc->sc_attached = 1;
338 
339 	return(0);
340 }
341 
342 void
343 an_rxeof(struct an_softc *sc)
344 {
345 	struct ieee80211com *ic = &sc->sc_ic;
346 	struct ifnet *ifp = &ic->ic_if;
347 	struct ieee80211_frame *wh;
348 	struct ieee80211_rxinfo rxi;
349 	struct ieee80211_node *ni;
350 	struct an_rxframe frmhdr;
351 	struct mbuf *m;
352 	u_int16_t status;
353 	int fid, gaplen, len, off;
354 	uint8_t *gap;
355 
356 	fid = CSR_READ_2(sc, AN_RX_FID);
357 
358 	/* First read in the frame header */
359 	if (an_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr), sizeof(frmhdr)) != 0) {
360 		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
361 		ifp->if_ierrors++;
362 		DPRINTF(("an_rxeof: read fid %x failed\n", fid));
363 		return;
364 	}
365 	an_swap16((u_int16_t *)&frmhdr.an_whdr, sizeof(struct ieee80211_frame)/2);
366 
367 	status = frmhdr.an_rx_status;
368 	if ((status & AN_STAT_ERRSTAT) != 0 &&
369 	    ic->ic_opmode != IEEE80211_M_MONITOR) {
370 		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
371 		ifp->if_ierrors++;
372 		DPRINTF(("an_rxeof: fid %x status %x\n", fid, status));
373 		return;
374 	}
375 
376 	/* the payload length field includes a 16-bit "mystery field" */
377 	len = frmhdr.an_rx_payload_len - sizeof(uint16_t);
378 	off = ALIGN(sizeof(struct ieee80211_frame));
379 
380 	if (off + len > MCLBYTES) {
381 		if (ic->ic_opmode != IEEE80211_M_MONITOR) {
382 			CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
383 			ifp->if_ierrors++;
384 			DPRINTF(("an_rxeof: oversized packet %d\n", len));
385 			return;
386 		}
387 		len = 0;
388 	}
389 
390 	MGETHDR(m, M_DONTWAIT, MT_DATA);
391 	if (m == NULL) {
392 		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
393 		ifp->if_ierrors++;
394 		DPRINTF(("an_rxeof: MGET failed\n"));
395 		return;
396 	}
397 	if (off + len + AN_GAPLEN_MAX > MHLEN) {
398 		MCLGET(m, M_DONTWAIT);
399 		if ((m->m_flags & M_EXT) == 0) {
400 			CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
401 			m_freem(m);
402 			ifp->if_ierrors++;
403 			DPRINTF(("an_rxeof: MCLGET failed\n"));
404 			return;
405 		}
406 	}
407 	m->m_data += off - sizeof(struct ieee80211_frame);
408 
409 	if (ic->ic_opmode != IEEE80211_M_MONITOR) {
410 		gaplen = frmhdr.an_gaplen;
411 		if (gaplen > AN_GAPLEN_MAX) {
412 			CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
413 			m_freem(m);
414 			ifp->if_ierrors++;
415 			DPRINTF(("%s: gap too long\n", __func__));
416 			return;
417 		}
418 		/*
419 		 * We don't need the 16-bit mystery field (payload length?),
420 		 * so read it into the region reserved for the 802.11 header.
421 		 *
422 		 * When Cisco Aironet 350 cards w/ firmware version 5 or
423 		 * greater operate with certain Cisco 350 APs,
424 		 * the "gap" is filled with the SNAP header.  Read
425 		 * it in after the 802.11 header.
426 		 */
427 		gap = m->m_data + sizeof(struct ieee80211_frame) -
428 		    sizeof(uint16_t);
429 		an_read_bap(sc, fid, -1, gap, gaplen + sizeof(u_int16_t),
430 		    gaplen + sizeof(u_int16_t));
431 	} else
432 		gaplen = 0;
433 
434 	an_read_bap(sc, fid, -1,
435 	    m->m_data + sizeof(struct ieee80211_frame) + gaplen, len, len);
436 	an_swap16((u_int16_t *)(m->m_data + sizeof(struct ieee80211_frame) + gaplen), (len+1)/2);
437 	m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame) + gaplen +
438 	    len;
439 
440 	memcpy(m->m_data, &frmhdr.an_whdr, sizeof(struct ieee80211_frame));
441 	CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
442 
443 #if NBPFILTER > 0
444 	if (sc->sc_drvbpf) {
445 		struct mbuf mb;
446 		struct an_rx_radiotap_header *tap = &sc->sc_rxtap;
447 
448 		tap->ar_rate = frmhdr.an_rx_rate;
449 		tap->ar_antsignal = frmhdr.an_rx_signal_strength;
450 		tap->ar_chan_freq = ic->ic_bss->ni_chan->ic_freq;
451 		tap->ar_chan_flags = ic->ic_bss->ni_chan->ic_flags;
452 
453 
454 		mb.m_data = (caddr_t)tap;
455 		mb.m_len = sizeof(sc->sc_rxtapu);
456 		mb.m_next = m;
457 		mb.m_nextpkt = NULL;
458 		mb.m_type = 0;
459 		mb.m_flags = 0;
460 		bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN);
461 	}
462 #endif /* NBPFILTER > 0 */
463 
464 	wh = mtod(m, struct ieee80211_frame *);
465 	rxi.rxi_flags = 0;
466 	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
467 		/*
468 		 * WEP is decrypted by hardware. Clear WEP bit
469 		 * header for ieee80211_input().
470 		 */
471 		wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
472 
473 		rxi.rxi_flags |= IEEE80211_RXI_HWDEC;
474 	}
475 
476 	ni = ieee80211_find_rxnode(ic, wh);
477 	rxi.rxi_rssi = frmhdr.an_rx_signal_strength;
478 	rxi.rxi_tstamp = an_switch32(frmhdr.an_rx_time);
479 	ieee80211_input(ifp, m, ni, &rxi);
480 	ieee80211_release_node(ic, ni);
481 }
482 
483 void
484 an_txeof(struct an_softc *sc, u_int16_t status)
485 {
486 	struct ifnet *ifp = &sc->sc_ic.ic_if;
487 	int cur, id;
488 
489 	sc->sc_tx_timer = 0;
490 	ifq_clr_oactive(&ifp->if_snd);
491 
492 	id = CSR_READ_2(sc, AN_TX_CMP_FID);
493 	CSR_WRITE_2(sc, AN_EVENT_ACK, status & (AN_EV_TX | AN_EV_TX_EXC));
494 
495 	if (status & AN_EV_TX_EXC)
496 		ifp->if_oerrors++;
497 	else
498 		ifp->if_opackets++;
499 
500 	cur = sc->sc_txcur;
501 	if (sc->sc_txd[cur].d_fid == id) {
502 		sc->sc_txd[cur].d_inuse = 0;
503 		DPRINTF2(("an_txeof: sent %x/%d\n", id, cur));
504 		AN_INC(cur, AN_TX_RING_CNT);
505 		sc->sc_txcur = cur;
506 	} else {
507 		for (cur = 0; cur < AN_TX_RING_CNT; cur++) {
508 			if (id == sc->sc_txd[cur].d_fid) {
509 				sc->sc_txd[cur].d_inuse = 0;
510 				break;
511 			}
512 		}
513 		if (ifp->if_flags & IFF_DEBUG)
514 			printf("%s: tx mismatch: "
515 			    "expected %x(%d), actual %x(%d)\n",
516 			    sc->sc_dev.dv_xname,
517 			    sc->sc_txd[sc->sc_txcur].d_fid, sc->sc_txcur,
518 			    id, cur);
519 	}
520 }
521 
522 int
523 an_intr(void *arg)
524 {
525 	struct an_softc *sc = arg;
526 	struct ifnet *ifp = &sc->sc_ic.ic_if;
527 	int i;
528 	u_int16_t status;
529 
530 	if (!sc->sc_enabled || sc->sc_invalid ||
531 	    (sc->sc_dev.dv_flags & DVF_ACTIVE) == 0 ||
532 	    (ifp->if_flags & IFF_RUNNING) == 0)
533 		return 0;
534 
535 	if ((ifp->if_flags & IFF_UP) == 0) {
536 		CSR_WRITE_2(sc, AN_INT_EN, 0);
537 		CSR_WRITE_2(sc, AN_EVENT_ACK, ~0);
538 		return 1;
539 	}
540 
541 	/* maximum 10 loops per interrupt */
542 	for (i = 0; i < 10; i++) {
543 		if (!sc->sc_enabled || sc->sc_invalid)
544 			return 1;
545 		if (CSR_READ_2(sc, AN_SW0) != AN_MAGIC) {
546 			DPRINTF(("an_intr: magic number changed: %x\n",
547 			    CSR_READ_2(sc, AN_SW0)));
548 			sc->sc_invalid = 1;
549 			return 1;
550 		}
551 		status = CSR_READ_2(sc, AN_EVENT_STAT);
552 		CSR_WRITE_2(sc, AN_EVENT_ACK, status & ~(AN_INTRS));
553 		if ((status & AN_INTRS) == 0)
554 			break;
555 
556 		if (status & AN_EV_RX)
557 			an_rxeof(sc);
558 
559 		if (status & (AN_EV_TX | AN_EV_TX_EXC))
560 			an_txeof(sc, status);
561 
562 		if (status & AN_EV_LINKSTAT)
563 			an_linkstat_intr(sc);
564 
565 		if (ifq_is_oactive(&ifp->if_snd) == 0 &&
566 		    sc->sc_ic.ic_state == IEEE80211_S_RUN &&
567 		    !IFQ_IS_EMPTY(&ifp->if_snd))
568 			an_start(ifp);
569 	}
570 
571 	return 1;
572 }
573 
574 /* Must be called at proper protection level! */
575 int
576 an_cmd(struct an_softc *sc, int cmd, int val)
577 {
578 	int i, stat;
579 
580 	/* make sure previous command completed */
581 	if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY) {
582 		if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
583 			printf("%s: command 0x%x busy\n", sc->sc_dev.dv_xname,
584 			    CSR_READ_2(sc, AN_COMMAND));
585 		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY);
586 	}
587 
588 	CSR_WRITE_2(sc, AN_PARAM0, val);
589 	CSR_WRITE_2(sc, AN_PARAM1, 0);
590 	CSR_WRITE_2(sc, AN_PARAM2, 0);
591 	CSR_WRITE_2(sc, AN_COMMAND, cmd);
592 
593 	if (cmd == AN_CMD_FW_RESTART) {
594 		/* XXX: should sleep here */
595 		DELAY(100*1000);
596 	}
597 
598 	for (i = 0; i < AN_TIMEOUT; i++) {
599 		if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_CMD)
600 			break;
601 		DELAY(10);
602 	}
603 
604 	stat = CSR_READ_2(sc, AN_STATUS);
605 
606 	/* clear stuck command busy if necessary */
607 	if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY)
608 		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY);
609 
610 	/* Ack the command */
611 	CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD);
612 
613 	if (i == AN_TIMEOUT) {
614 		if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
615 			printf("%s: command 0x%x param 0x%x timeout\n",
616 			    sc->sc_dev.dv_xname, cmd, val);
617 		return ETIMEDOUT;
618 	}
619 	if (stat & AN_STAT_CMD_RESULT) {
620 		if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
621 			printf("%s: command 0x%x param 0x%x status 0x%x "
622 			    "resp 0x%x 0x%x 0x%x\n",
623 			    sc->sc_dev.dv_xname, cmd, val, stat,
624 			    CSR_READ_2(sc, AN_RESP0), CSR_READ_2(sc, AN_RESP1),
625 			    CSR_READ_2(sc, AN_RESP2));
626 		return EIO;
627 	}
628 
629 	return 0;
630 }
631 
632 int
633 an_reset(struct an_softc *sc)
634 {
635 
636 	DPRINTF(("an_reset\n"));
637 
638 	if (!sc->sc_enabled)
639 		return ENXIO;
640 
641 	an_cmd(sc, AN_CMD_ENABLE, 0);
642 	an_cmd(sc, AN_CMD_FW_RESTART, 0);
643 	an_cmd(sc, AN_CMD_NOOP2, 0);
644 
645 	if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0) == ETIMEDOUT) {
646 		printf("%s: reset failed\n", sc->sc_dev.dv_xname);
647 		return ETIMEDOUT;
648 	}
649 
650 	an_cmd(sc, AN_CMD_DISABLE, 0);
651 	return 0;
652 }
653 
654 void
655 an_linkstat_intr(struct an_softc *sc)
656 {
657 	struct ieee80211com *ic = &sc->sc_ic;
658 	u_int16_t status;
659 
660 	status = CSR_READ_2(sc, AN_LINKSTAT);
661 	CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_LINKSTAT);
662 	DPRINTF(("an_linkstat_intr: status 0x%x\n", status));
663 
664 	if (status == AN_LINKSTAT_ASSOCIATED) {
665 		if (ic->ic_state != IEEE80211_S_RUN
666 #ifndef IEEE80211_STA_ONLY
667 		    || ic->ic_opmode == IEEE80211_M_IBSS
668 #endif
669 		    )
670 			ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
671 	} else {
672 		if (ic->ic_opmode == IEEE80211_M_STA)
673 			ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
674 	}
675 }
676 
677 /*
678  * Wait for firmware come up after power enabled.
679  */
680 void
681 an_wait(struct an_softc *sc)
682 {
683 	int i;
684 
685 	CSR_WRITE_2(sc, AN_COMMAND, AN_CMD_NOOP2);
686 	for (i = 0; i < 3*hz; i++) {
687 		if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_CMD)
688 			break;
689 		(void)tsleep(sc, PWAIT, "anatch", 1);
690 	}
691 	CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD);
692 }
693 
694 int
695 an_read_bap(struct an_softc *sc, int id, int off, void *buf, int len, int blen)
696 {
697 	int error, cnt, cnt2;
698 
699 	if (len == 0 || blen == 0)
700 		return 0;
701 	if (off == -1)
702 		off = sc->sc_bap_off;
703 	if (id != sc->sc_bap_id || off != sc->sc_bap_off) {
704 		if ((error = an_seek_bap(sc, id, off)) != 0)
705 			return EIO;
706 	}
707 
708 	cnt = (blen + 1) / 2;
709 	CSR_READ_MULTI_STREAM_2(sc, AN_DATA0, (u_int16_t *)buf, cnt);
710 	for (cnt2 = (len + 1) / 2; cnt < cnt2; cnt++)
711 		(void) CSR_READ_2(sc, AN_DATA0);
712 	sc->sc_bap_off += cnt * 2;
713 
714 	return 0;
715 }
716 
717 int
718 an_write_bap(struct an_softc *sc, int id, int off, void *buf, int buflen)
719 {
720 	int error, cnt;
721 
722 	if (buflen == 0)
723 		return 0;
724 	if (off == -1)
725 		off = sc->sc_bap_off;
726 	if (id != sc->sc_bap_id || off != sc->sc_bap_off) {
727 		if ((error = an_seek_bap(sc, id, off)) != 0)
728 			return EIO;
729 	}
730 
731 	cnt = (buflen + 1) / 2;
732 	CSR_WRITE_MULTI_STREAM_2(sc, AN_DATA0, (u_int16_t *)buf, cnt);
733 	sc->sc_bap_off += cnt * 2;
734 	return 0;
735 }
736 
737 int
738 an_seek_bap(struct an_softc *sc, int id, int off)
739 {
740 	int i, status;
741 
742 	CSR_WRITE_2(sc, AN_SEL0, id);
743 	CSR_WRITE_2(sc, AN_OFF0, off);
744 
745 	for (i = 0; ; i++) {
746 		status = CSR_READ_2(sc, AN_OFF0);
747 		if ((status & AN_OFF_BUSY) == 0)
748 			break;
749 		if (i == AN_TIMEOUT) {
750 			printf("%s: timeout in an_seek_bap to 0x%x/0x%x\n",
751 			    sc->sc_dev.dv_xname, id, off);
752 			sc->sc_bap_off = AN_OFF_ERR;	/* invalidate */
753 			return ETIMEDOUT;
754 		}
755 		DELAY(10);
756 	}
757 	if (status & AN_OFF_ERR) {
758 		printf("%s: failed in an_seek_bap to 0x%x/0x%x\n",
759 		    sc->sc_dev.dv_xname, id, off);
760 		sc->sc_bap_off = AN_OFF_ERR;	/* invalidate */
761 		return EIO;
762 	}
763 	sc->sc_bap_id = id;
764 	sc->sc_bap_off = off;
765 	return 0;
766 }
767 
768 int
769 an_mwrite_bap(struct an_softc *sc, int id, int off, struct mbuf *m, int totlen)
770 {
771 	int error, len, cnt;
772 
773 	if (off == -1)
774 		off = sc->sc_bap_off;
775 	if (id != sc->sc_bap_id || off != sc->sc_bap_off) {
776 		if ((error = an_seek_bap(sc, id, off)) != 0)
777 			return EIO;
778 	}
779 
780 	for (len = 0; m != NULL; m = m->m_next) {
781 		if (m->m_len == 0)
782 			continue;
783 		len = min(m->m_len, totlen);
784 
785 		if ((mtod(m, u_long) & 0x1) || (len & 0x1)) {
786 			m_copydata(m, 0, totlen, (caddr_t)&sc->sc_buf.sc_txbuf);
787 			cnt = (totlen + 1) / 2;
788 			an_swap16((u_int16_t *)&sc->sc_buf.sc_txbuf, cnt);
789 			CSR_WRITE_MULTI_STREAM_2(sc, AN_DATA0,
790 			    sc->sc_buf.sc_val, cnt);
791 			off += cnt * 2;
792 			break;
793 		}
794 		cnt = len / 2;
795 		an_swap16((u_int16_t *)mtod(m, u_int16_t *), cnt);
796 		CSR_WRITE_MULTI_STREAM_2(sc, AN_DATA0, mtod(m, u_int16_t *),
797 		    cnt);
798 		off += len;
799 		totlen -= len;
800 	}
801 	sc->sc_bap_off = off;
802 	return 0;
803 }
804 
805 int
806 an_alloc_nicmem(struct an_softc *sc, int len, int *idp)
807 {
808 	int i;
809 
810 	if (an_cmd(sc, AN_CMD_ALLOC_MEM, len)) {
811 		printf("%s: failed to allocate %d bytes on NIC\n",
812 		    sc->sc_dev.dv_xname, len);
813 		return(ENOMEM);
814 	}
815 
816 	for (i = 0; i < AN_TIMEOUT; i++) {
817 		if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_ALLOC)
818 			break;
819 		if (i == AN_TIMEOUT) {
820 			printf("%s: timeout in alloc\n", sc->sc_dev.dv_xname);
821 			return ETIMEDOUT;
822 		}
823 		DELAY(10);
824 	}
825 
826 	*idp = CSR_READ_2(sc, AN_ALLOC_FID);
827 	CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_ALLOC);
828 	return 0;
829 }
830 
831 int
832 an_read_rid(struct an_softc *sc, int rid, void *buf, int *buflenp)
833 {
834 	int error;
835 	u_int16_t len;
836 
837 	/* Tell the NIC to enter record read mode. */
838 	error = an_cmd(sc, AN_CMD_ACCESS | AN_ACCESS_READ, rid);
839 	if (error)
840 		return error;
841 
842 	/* length in byte, including length itself */
843 	error = an_read_bap(sc, rid, 0, &len, sizeof(len), sizeof(len));
844 	if (error)
845 		return error;
846 
847 	len -= 2;
848 	return an_read_bap(sc, rid, sizeof(len), buf, len, *buflenp);
849 }
850 
851 int
852 an_write_rid(struct an_softc *sc, int rid, void *buf, int buflen)
853 {
854 	int error;
855 	u_int16_t len;
856 
857 	/* length in byte, including length itself */
858 	len = buflen + 2;
859 
860 	error = an_write_bap(sc, rid, 0, &len, sizeof(len));
861 	if (error)
862 		return error;
863 	error = an_write_bap(sc, rid, sizeof(len), buf, buflen);
864 	if (error)
865 		return error;
866 
867 	return an_cmd(sc, AN_CMD_ACCESS | AN_ACCESS_WRITE, rid);
868 }
869 
870 int
871 an_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
872 {
873 	struct an_softc *sc = ifp->if_softc;
874 	int s, error = 0;
875 
876 	if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
877 		return ENXIO;
878 
879 	s = splnet();
880 
881 	switch(command) {
882 	case SIOCSIFADDR:
883 		ifp->if_flags |= IFF_UP;
884 		error = an_init(ifp);
885 		break;
886 	case SIOCSIFFLAGS:
887 		if (ifp->if_flags & IFF_UP) {
888 			if (sc->sc_enabled) {
889 				/*
890 				 * To avoid rescanning another access point,
891 				 * do not call an_init() here.  Instead, only
892 				 * reflect promisc mode settings.
893 				 */
894 				error = an_cmd(sc, AN_CMD_SET_MODE,
895 				    (ifp->if_flags & IFF_PROMISC) ? 0xffff : 0);
896 			} else
897 				error = an_init(ifp);
898 		} else if (sc->sc_enabled)
899 			an_stop(ifp, 1);
900 		break;
901 	case SIOCADDMULTI:
902 	case SIOCDELMULTI:
903 		/* The Aironet has no multicast filter. */
904 		error = 0;
905 		break;
906 	case SIOCS80211NWKEY:
907 		error = an_set_nwkey(sc, (struct ieee80211_nwkey *)data);
908 			break;
909 	case SIOCG80211NWKEY:
910 		error = an_get_nwkey(sc, (struct ieee80211_nwkey *)data);
911 		break;
912 	default:
913 		error = ieee80211_ioctl(ifp, command, data);
914 		break;
915 	}
916 	if (error == ENETRESET) {
917 		if (sc->sc_enabled)
918 			error = an_init(ifp);
919 		else
920 			error = 0;
921 	}
922 	splx(s);
923 	return(error);
924 }
925 
926 int
927 an_init(struct ifnet *ifp)
928 {
929 	struct an_softc *sc = ifp->if_softc;
930 	struct ieee80211com *ic = &sc->sc_ic;
931 	int i, error, fid;
932 
933 	DPRINTF(("an_init: enabled %d\n", sc->sc_enabled));
934 	if (!sc->sc_enabled) {
935 		if (sc->sc_enable)
936 			(*sc->sc_enable)(sc);
937 		an_wait(sc);
938 		sc->sc_enabled = 1;
939 	} else {
940 		an_stop(ifp, 0);
941 		if ((error = an_reset(sc)) != 0) {
942 			printf("%s: failed to reset\n", ifp->if_xname);
943 			an_stop(ifp, 1);
944 			return error;
945 		}
946 	}
947 	CSR_WRITE_2(sc, AN_SW0, AN_MAGIC);
948 
949 	/* Allocate the TX buffers */
950 	for (i = 0; i < AN_TX_RING_CNT; i++) {
951 		if ((error = an_alloc_nicmem(sc, AN_TX_MAX_LEN, &fid)) != 0) {
952 			printf("%s: failed to allocate nic memory\n",
953 			    ifp->if_xname);
954 			an_stop(ifp, 1);
955 			return error;
956 		}
957 		DPRINTF2(("an_init: txbuf %d allocated %x\n", i, fid));
958 		sc->sc_txd[i].d_fid = fid;
959 		sc->sc_txd[i].d_inuse = 0;
960 	}
961 	sc->sc_txcur = sc->sc_txnext = 0;
962 
963 	IEEE80211_ADDR_COPY(sc->sc_config.an_macaddr, ic->ic_myaddr);
964 	an_swap16((u_int16_t *)&sc->sc_config.an_macaddr, 3);
965 	sc->sc_config.an_scanmode = AN_SCANMODE_ACTIVE;
966 	sc->sc_config.an_authtype = AN_AUTHTYPE_OPEN;	/*XXX*/
967 	if (ic->ic_flags & IEEE80211_F_WEPON) {
968 		sc->sc_config.an_authtype |=
969 		    AN_AUTHTYPE_PRIVACY_IN_USE;
970 	}
971 	sc->sc_config.an_listen_interval = ic->ic_lintval;
972 	sc->sc_config.an_beacon_period = ic->ic_lintval;
973 	if (ic->ic_flags & IEEE80211_F_PMGTON)
974 		sc->sc_config.an_psave_mode = AN_PSAVE_PSP;
975 	else
976 		sc->sc_config.an_psave_mode = AN_PSAVE_CAM;
977 	sc->sc_config.an_ds_channel =
978 	    ieee80211_chan2ieee(ic, ic->ic_ibss_chan);
979 
980 	switch (ic->ic_opmode) {
981 	case IEEE80211_M_STA:
982 		sc->sc_config.an_opmode =
983 		    AN_OPMODE_INFRASTRUCTURE_STATION;
984 		sc->sc_config.an_rxmode = AN_RXMODE_BC_MC_ADDR;
985 		break;
986 #ifndef IEEE80211_STA_ONLY
987 	case IEEE80211_M_IBSS:
988 		sc->sc_config.an_opmode = AN_OPMODE_IBSS_ADHOC;
989 		sc->sc_config.an_rxmode = AN_RXMODE_BC_MC_ADDR;
990 		break;
991 #endif
992 	case IEEE80211_M_MONITOR:
993 		sc->sc_config.an_opmode =
994 		    AN_OPMODE_INFRASTRUCTURE_STATION;
995 		sc->sc_config.an_rxmode =
996 		    AN_RXMODE_80211_MONITOR_ANYBSS;
997 		sc->sc_config.an_authtype = AN_AUTHTYPE_NONE;
998 		if (ic->ic_flags & IEEE80211_F_WEPON)
999 			sc->sc_config.an_authtype |=
1000 			    AN_AUTHTYPE_PRIVACY_IN_USE |
1001 		            AN_AUTHTYPE_ALLOW_UNENCRYPTED;
1002 		break;
1003 	default:
1004 		printf("%s: bad opmode %d\n", ifp->if_xname, ic->ic_opmode);
1005 		an_stop(ifp, 1);
1006 		return EIO;
1007 	}
1008 	sc->sc_config.an_rxmode |= AN_RXMODE_NO_8023_HEADER;
1009 
1010 	/* Set the ssid list */
1011 	memset(&sc->sc_buf, 0, sizeof(sc->sc_buf.sc_ssidlist));
1012 	sc->sc_buf.sc_ssidlist.an_entry[0].an_ssid_len =
1013 	    ic->ic_des_esslen;
1014 	if (ic->ic_des_esslen)
1015 		memcpy(sc->sc_buf.sc_ssidlist.an_entry[0].an_ssid,
1016 		    ic->ic_des_essid, ic->ic_des_esslen);
1017 	an_swap16((u_int16_t *)&sc->sc_buf.sc_ssidlist.an_entry[0].an_ssid, 16);
1018 	if ((error = an_write_rid(sc, AN_RID_SSIDLIST, &sc->sc_buf,
1019 	    sizeof(sc->sc_buf.sc_ssidlist)))) {
1020 		printf("%s: failed to write ssid list\n", ifp->if_xname);
1021 		an_stop(ifp, 1);
1022 		return error;
1023 	}
1024 
1025 	/* Set the AP list */
1026 	memset(&sc->sc_buf, 0, sizeof(sc->sc_buf.sc_aplist));
1027 	(void)an_write_rid(sc, AN_RID_APLIST, &sc->sc_buf,
1028 	    sizeof(sc->sc_buf.sc_aplist));
1029 
1030 	/* Set the encapsulation */
1031 	for (i = 0; i < AN_ENCAP_NENTS; i++) {
1032 		sc->sc_buf.sc_encap.an_entry[i].an_ethertype = 0;
1033 		sc->sc_buf.sc_encap.an_entry[i].an_action =
1034 		    AN_RXENCAP_RFC1024 | AN_TXENCAP_RFC1024;
1035 	}
1036 	(void)an_write_rid(sc, AN_RID_ENCAP, &sc->sc_buf,
1037 	    sizeof(sc->sc_buf.sc_encap));
1038 
1039 	/* Set the WEP Keys */
1040 	if (ic->ic_flags & IEEE80211_F_WEPON)
1041 		an_write_wepkey(sc, AN_RID_WEP_VOLATILE, sc->sc_wepkeys,
1042 		    sc->sc_tx_key);
1043 
1044 	/* Set the configuration */
1045 	if ((error = an_write_rid(sc, AN_RID_GENCONFIG, &sc->sc_config,
1046 	    sizeof(sc->sc_config)))) {
1047 		printf("%s: failed to write config\n", ifp->if_xname);
1048 		an_stop(ifp, 1);
1049 		return error;
1050 	}
1051 
1052 	/* Enable the MAC */
1053 	if (an_cmd(sc, AN_CMD_ENABLE, 0)) {
1054 		printf("%s: failed to enable MAC\n", sc->sc_dev.dv_xname);
1055 		an_stop(ifp, 1);
1056 		return ENXIO;
1057 	}
1058 	if (ifp->if_flags & IFF_PROMISC)
1059 		an_cmd(sc, AN_CMD_SET_MODE, 0xffff);
1060 
1061 	ifp->if_flags |= IFF_RUNNING;
1062 	ifq_clr_oactive(&ifp->if_snd);
1063 	ic->ic_state = IEEE80211_S_INIT;
1064 	if (ic->ic_opmode == IEEE80211_M_MONITOR)
1065 		ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
1066 
1067 	/* enable interrupts */
1068 	CSR_WRITE_2(sc, AN_INT_EN, AN_INTRS);
1069 	return 0;
1070 }
1071 
1072 void
1073 an_start(struct ifnet *ifp)
1074 {
1075 	struct an_softc *sc = (struct an_softc *)ifp->if_softc;
1076 	struct ieee80211com *ic = &sc->sc_ic;
1077 	struct ieee80211_node *ni;
1078 	struct ieee80211_frame *wh;
1079 	struct an_txframe frmhdr;
1080 	struct mbuf *m;
1081 	u_int16_t len;
1082 	int cur, fid;
1083 
1084 	if (!sc->sc_enabled || sc->sc_invalid) {
1085 		DPRINTF(("an_start: noop: enabled %d invalid %d\n",
1086 		    sc->sc_enabled, sc->sc_invalid));
1087 		return;
1088 	}
1089 
1090 	memset(&frmhdr, 0, sizeof(frmhdr));
1091 	cur = sc->sc_txnext;
1092 	for (;;) {
1093 		if (ic->ic_state != IEEE80211_S_RUN) {
1094 			DPRINTF(("an_start: not running %d\n", ic->ic_state));
1095 			break;
1096 		}
1097 		m = ifq_deq_begin(&ifp->if_snd);
1098 		if (m == NULL) {
1099 			DPRINTF2(("an_start: no pending mbuf\n"));
1100 			break;
1101 		}
1102 		if (sc->sc_txd[cur].d_inuse) {
1103 			ifq_deq_rollback(&ifp->if_snd, m);
1104 			DPRINTF2(("an_start: %x/%d busy\n",
1105 			    sc->sc_txd[cur].d_fid, cur));
1106 			ifq_set_oactive(&ifp->if_snd);
1107 			break;
1108 		}
1109 		ifq_deq_commit(&ifp->if_snd, m);
1110 		ifp->if_opackets++;
1111 #if NBPFILTER > 0
1112 		if (ifp->if_bpf)
1113 			bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
1114 #endif
1115 		if ((m = ieee80211_encap(ifp, m, &ni)) == NULL) {
1116 			ifp->if_oerrors++;
1117 			continue;
1118 		}
1119 		if (ni != NULL)
1120 			ieee80211_release_node(ic, ni);
1121 #if NBPFILTER > 0
1122 		if (ic->ic_rawbpf)
1123 			bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT);
1124 #endif
1125 
1126 		wh = mtod(m, struct ieee80211_frame *);
1127 		if (ic->ic_flags & IEEE80211_F_WEPON)
1128 			wh->i_fc[1] |= IEEE80211_FC1_WEP;
1129 		m_copydata(m, 0, sizeof(struct ieee80211_frame),
1130 		    (caddr_t)&frmhdr.an_whdr);
1131 		an_swap16((u_int16_t *)&frmhdr.an_whdr, sizeof(struct ieee80211_frame)/2);
1132 
1133 		/* insert payload length in front of llc/snap */
1134 		len = htons(m->m_pkthdr.len - sizeof(struct ieee80211_frame));
1135 		m_adj(m, sizeof(struct ieee80211_frame) - sizeof(len));
1136 		if (mtod(m, u_long) & 0x01)
1137 			memcpy(mtod(m, caddr_t), &len, sizeof(len));
1138 		else
1139 			*mtod(m, u_int16_t *) = len;
1140 
1141 		/*
1142 		 * XXX Aironet firmware apparently convert the packet
1143 		 * with longer than 1500 bytes in length into LLC/SNAP.
1144 		 * If we have 1500 bytes in ethernet payload, it is
1145 		 * 1508 bytes including LLC/SNAP and will be inserted
1146 		 * additional LLC/SNAP header with 1501-1508 in its
1147 		 * ethertype !!
1148 		 * So we skip LLC/SNAP header and force firmware to
1149 		 * convert it to LLC/SNAP again.
1150 		 */
1151 		m_adj(m, sizeof(struct llc));
1152 
1153 		frmhdr.an_tx_ctl = AN_TXCTL_80211;
1154 		frmhdr.an_tx_payload_len = m->m_pkthdr.len;
1155 		frmhdr.an_gaplen = AN_TXGAP_802_11;
1156 
1157 		if (ic->ic_fixed_rate != -1)
1158 			frmhdr.an_tx_rate =
1159 			    ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[
1160 			    ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
1161 		else
1162 			frmhdr.an_tx_rate = 0;
1163 
1164 		if (sizeof(frmhdr) + AN_TXGAP_802_11 + sizeof(len) +
1165 		    m->m_pkthdr.len > AN_TX_MAX_LEN) {
1166 			ifp->if_oerrors++;
1167 			m_freem(m);
1168 			continue;
1169 		}
1170 
1171 #if NBPFILTER > 0
1172 		if (sc->sc_drvbpf) {
1173 			struct mbuf mb;
1174 			struct an_tx_radiotap_header *tap = &sc->sc_txtap;
1175 
1176 			tap->at_rate =
1177 			    ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate];
1178 			tap->at_chan_freq =
1179 			    ic->ic_bss->ni_chan->ic_freq;
1180 			tap->at_chan_flags =
1181 			    ic->ic_bss->ni_chan->ic_flags;
1182 
1183 			mb.m_data = (caddr_t)tap;
1184 			mb.m_len = sizeof(sc->sc_txtapu);
1185 			mb.m_next = m;
1186 			mb.m_nextpkt = NULL;
1187 			mb.m_type = 0;
1188 			mb.m_flags = 0;
1189 			bpf_mtap(sc->sc_drvbpf, m, BPF_DIRECTION_OUT);
1190 		}
1191 #endif
1192 
1193 		fid = sc->sc_txd[cur].d_fid;
1194 		if (an_write_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) != 0) {
1195 			ifp->if_oerrors++;
1196 			m_freem(m);
1197 			continue;
1198 		}
1199 		/* dummy write to avoid seek. */
1200 		an_write_bap(sc, fid, -1, &frmhdr, AN_TXGAP_802_11);
1201 		an_mwrite_bap(sc, fid, -1, m, m->m_pkthdr.len);
1202 		m_freem(m);
1203 
1204 		DPRINTF2(("an_start: send %d byte via %x/%d\n",
1205 		    ntohs(len) + sizeof(struct ieee80211_frame),
1206 		    fid, cur));
1207 		sc->sc_txd[cur].d_inuse = 1;
1208 		if (an_cmd(sc, AN_CMD_TX, fid)) {
1209 			printf("%s: xmit failed\n", ifp->if_xname);
1210 			sc->sc_txd[cur].d_inuse = 0;
1211 			continue;
1212 		}
1213 		sc->sc_tx_timer = 5;
1214 		ifp->if_timer = 1;
1215 		AN_INC(cur, AN_TX_RING_CNT);
1216 		sc->sc_txnext = cur;
1217 	}
1218 }
1219 
1220 void
1221 an_stop(struct ifnet *ifp, int disable)
1222 {
1223 	struct an_softc *sc = ifp->if_softc;
1224 	int i, s;
1225 
1226 	if (!sc->sc_enabled)
1227 		return;
1228 
1229 	DPRINTF(("an_stop: disable %d\n", disable));
1230 
1231 	s = splnet();
1232 	ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
1233 	if (!sc->sc_invalid) {
1234 		an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0);
1235 		CSR_WRITE_2(sc, AN_INT_EN, 0);
1236 		an_cmd(sc, AN_CMD_DISABLE, 0);
1237 
1238 		for (i = 0; i < AN_TX_RING_CNT; i++)
1239 			an_cmd(sc, AN_CMD_DEALLOC_MEM, sc->sc_txd[i].d_fid);
1240 	}
1241 
1242 	sc->sc_tx_timer = 0;
1243 	ifp->if_timer = 0;
1244 	ifp->if_flags &= ~IFF_RUNNING;
1245 	ifq_clr_oactive(&ifp->if_snd);
1246 
1247 	if (disable) {
1248 		if (sc->sc_disable)
1249 			(*sc->sc_disable)(sc);
1250 		sc->sc_enabled = 0;
1251 	}
1252 	splx(s);
1253 }
1254 
1255 void
1256 an_watchdog(struct ifnet *ifp)
1257 {
1258 	struct an_softc *sc = ifp->if_softc;
1259 
1260 	if (!sc->sc_enabled)
1261 		return;
1262 
1263 	if (sc->sc_tx_timer) {
1264 		if (--sc->sc_tx_timer == 0) {
1265 			printf("%s: device timeout\n", ifp->if_xname);
1266 			ifp->if_oerrors++;
1267 			an_init(ifp);
1268 			return;
1269 		}
1270 		ifp->if_timer = 1;
1271 	}
1272 	ieee80211_watchdog(ifp);
1273 }
1274 
1275 /* TBD factor with ieee80211_media_change */
1276 int
1277 an_media_change(struct ifnet *ifp)
1278 {
1279 	struct an_softc *sc = ifp->if_softc;
1280 	struct ieee80211com *ic = &sc->sc_ic;
1281 	struct ifmedia_entry *ime;
1282 	enum ieee80211_opmode newmode;
1283 	int i, rate, error = 0;
1284 
1285 	ime = ic->ic_media.ifm_cur;
1286 	if (IFM_SUBTYPE(ime->ifm_media) == IFM_AUTO) {
1287 		i = -1;
1288 	} else {
1289 		struct ieee80211_rateset *rs =
1290 		    &ic->ic_sup_rates[IEEE80211_MODE_11B];
1291 		rate = ieee80211_media2rate(ime->ifm_media);
1292 		if (rate == 0)
1293 			return EINVAL;
1294 		for (i = 0; i < rs->rs_nrates; i++) {
1295 			if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == rate)
1296 				break;
1297 		}
1298 		if (i == rs->rs_nrates)
1299 			return EINVAL;
1300 	}
1301 	if (ic->ic_fixed_rate != i) {
1302 		ic->ic_fixed_rate = i;
1303 		error = ENETRESET;
1304 	}
1305 
1306 #ifndef IEEE80211_STA_ONLY
1307 	if (ime->ifm_media & IFM_IEEE80211_ADHOC)
1308 		newmode = IEEE80211_M_IBSS;
1309 	else if (ime->ifm_media & IFM_IEEE80211_HOSTAP)
1310 		newmode = IEEE80211_M_HOSTAP;
1311 	else
1312 #endif
1313 	if (ime->ifm_media & IFM_IEEE80211_MONITOR)
1314 		newmode = IEEE80211_M_MONITOR;
1315 	else
1316 		newmode = IEEE80211_M_STA;
1317 	if (ic->ic_opmode != newmode) {
1318 		ic->ic_opmode = newmode;
1319 		error = ENETRESET;
1320 	}
1321 	if (error == ENETRESET) {
1322 		if (sc->sc_enabled)
1323 			error = an_init(ifp);
1324 		else
1325 			error = 0;
1326 	}
1327 	ifp->if_baudrate = ifmedia_baudrate(ic->ic_media.ifm_cur->ifm_media);
1328 
1329 	return error;
1330 }
1331 
1332 void
1333 an_media_status(struct ifnet *ifp, struct ifmediareq *imr)
1334 {
1335 	struct an_softc *sc = ifp->if_softc;
1336 	struct ieee80211com *ic = &sc->sc_ic;
1337 	int rate, buflen;
1338 
1339 	if (sc->sc_enabled == 0) {
1340 		imr->ifm_active = IFM_IEEE80211 | IFM_NONE;
1341 		imr->ifm_status = 0;
1342 		return;
1343 	}
1344 
1345 	imr->ifm_status = IFM_AVALID;
1346 	imr->ifm_active = IFM_IEEE80211;
1347 	if (ic->ic_state == IEEE80211_S_RUN)
1348 		imr->ifm_status |= IFM_ACTIVE;
1349 	buflen = sizeof(sc->sc_buf);
1350 	if (ic->ic_fixed_rate != -1)
1351 		rate = ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[
1352 		    ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
1353 	else if (an_read_rid(sc, AN_RID_STATUS, &sc->sc_buf, &buflen) != 0)
1354 		rate = 0;
1355 	else
1356 		rate = sc->sc_buf.sc_status.an_current_tx_rate;
1357 	imr->ifm_active |= ieee80211_rate2media(ic, rate, IEEE80211_MODE_11B);
1358 	switch (ic->ic_opmode) {
1359 	case IEEE80211_M_STA:
1360 		break;
1361 #ifndef IEEE80211_STA_ONLY
1362 	case IEEE80211_M_IBSS:
1363 		imr->ifm_active |= IFM_IEEE80211_ADHOC;
1364 		break;
1365 	case IEEE80211_M_HOSTAP:
1366 		imr->ifm_active |= IFM_IEEE80211_HOSTAP;
1367 		break;
1368 #endif
1369 	case IEEE80211_M_MONITOR:
1370 		imr->ifm_active |= IFM_IEEE80211_MONITOR;
1371 		break;
1372 	default:
1373 		break;
1374 	}
1375 }
1376 
1377 int
1378 an_set_nwkey(struct an_softc *sc, struct ieee80211_nwkey *nwkey)
1379 {
1380 	int error;
1381 	struct ieee80211com *ic = &sc->sc_ic;
1382 	u_int16_t prevauth;
1383 
1384 	error = 0;
1385 	prevauth = sc->sc_config.an_authtype;
1386 
1387 	switch (nwkey->i_wepon) {
1388 	case IEEE80211_NWKEY_OPEN:
1389 		sc->sc_config.an_authtype = AN_AUTHTYPE_OPEN;
1390 		ic->ic_flags &= ~IEEE80211_F_WEPON;
1391 		break;
1392 
1393 	case IEEE80211_NWKEY_WEP:
1394 	case IEEE80211_NWKEY_WEP | IEEE80211_NWKEY_PERSIST:
1395 		error = an_set_nwkey_wep(sc, nwkey);
1396 		if (error == 0 || error == ENETRESET) {
1397 			sc->sc_config.an_authtype =
1398 			    AN_AUTHTYPE_OPEN | AN_AUTHTYPE_PRIVACY_IN_USE;
1399 			ic->ic_flags |= IEEE80211_F_WEPON;
1400 		}
1401 		break;
1402 
1403 	default:
1404 		error = EINVAL;
1405 		break;
1406 	}
1407 	if (error == 0 && prevauth != sc->sc_config.an_authtype)
1408 		error = ENETRESET;
1409 	return error;
1410 }
1411 
1412 int
1413 an_set_nwkey_wep(struct an_softc *sc, struct ieee80211_nwkey *nwkey)
1414 {
1415 	int i, txkey, anysetkey, needreset, error;
1416 	struct an_wepkey keys[IEEE80211_WEP_NKID];
1417 
1418 	error = 0;
1419 	memset(keys, 0, sizeof(keys));
1420 	anysetkey = needreset = 0;
1421 
1422 	/* load argument and sanity check */
1423 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1424 		keys[i].an_wep_keylen = nwkey->i_key[i].i_keylen;
1425 		if (keys[i].an_wep_keylen < 0)
1426 			continue;
1427 		if (keys[i].an_wep_keylen != 0 &&
1428 		    keys[i].an_wep_keylen < IEEE80211_WEP_KEYLEN)
1429 			return EINVAL;
1430 		if (keys[i].an_wep_keylen > sizeof(keys[i].an_wep_key))
1431 			return EINVAL;
1432 		if ((error = copyin(nwkey->i_key[i].i_keydat,
1433 		    keys[i].an_wep_key, keys[i].an_wep_keylen)) != 0)
1434 			return error;
1435 		anysetkey++;
1436 	}
1437 	txkey = nwkey->i_defkid - 1;
1438 	if (txkey >= 0) {
1439 		if (txkey >= IEEE80211_WEP_NKID)
1440 			return EINVAL;
1441 		/* default key must have a valid value */
1442 		if (keys[txkey].an_wep_keylen == 0 ||
1443 		    (keys[txkey].an_wep_keylen < 0 &&
1444 		    sc->sc_perskeylen[txkey] == 0))
1445 			return EINVAL;
1446 		anysetkey++;
1447 	}
1448 	DPRINTF(("an_set_nwkey_wep: %s: %sold(%d:%d,%d,%d,%d) "
1449 	    "pers(%d:%d,%d,%d,%d) new(%d:%d,%d,%d,%d)\n",
1450 	    sc->sc_dev.dv_xname,
1451 	    ((nwkey->i_wepon & IEEE80211_NWKEY_PERSIST) ? "persist: " : ""),
1452 	    sc->sc_tx_key,
1453 	    sc->sc_wepkeys[0].an_wep_keylen, sc->sc_wepkeys[1].an_wep_keylen,
1454 	    sc->sc_wepkeys[2].an_wep_keylen, sc->sc_wepkeys[3].an_wep_keylen,
1455 	    sc->sc_tx_perskey,
1456 	    sc->sc_perskeylen[0], sc->sc_perskeylen[1],
1457 	    sc->sc_perskeylen[2], sc->sc_perskeylen[3],
1458 	    txkey,
1459 	    keys[0].an_wep_keylen, keys[1].an_wep_keylen,
1460 	    keys[2].an_wep_keylen, keys[3].an_wep_keylen));
1461 	if (!(nwkey->i_wepon & IEEE80211_NWKEY_PERSIST)) {
1462 		/* set temporary keys */
1463 		sc->sc_tx_key = txkey;
1464 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1465 			if (keys[i].an_wep_keylen < 0)
1466 				continue;
1467 			memcpy(&sc->sc_wepkeys[i], &keys[i], sizeof(keys[i]));
1468 		}
1469 	} else {
1470 		/* set persist keys */
1471 		if (anysetkey) {
1472 			/* prepare to write nvram */
1473 			if (!sc->sc_enabled) {
1474 				if (sc->sc_enable)
1475 					(*sc->sc_enable)(sc);
1476 				an_wait(sc);
1477 				sc->sc_enabled = 1;
1478 				error = an_write_wepkey(sc,
1479 				    AN_RID_WEP_PERSISTENT, keys, txkey);
1480 				if (sc->sc_disable)
1481 					(*sc->sc_disable)(sc);
1482 				sc->sc_enabled = 0;
1483 			} else {
1484 				an_cmd(sc, AN_CMD_DISABLE, 0);
1485 				error = an_write_wepkey(sc,
1486 				    AN_RID_WEP_PERSISTENT, keys, txkey);
1487 				an_cmd(sc, AN_CMD_ENABLE, 0);
1488 			}
1489 			if (error)
1490 				return error;
1491 		}
1492 		if (txkey >= 0)
1493 			sc->sc_tx_perskey = txkey;
1494 		if (sc->sc_tx_key >= 0) {
1495 			sc->sc_tx_key = -1;
1496 			needreset++;
1497 		}
1498 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1499 			if (sc->sc_wepkeys[i].an_wep_keylen >= 0) {
1500 				memset(&sc->sc_wepkeys[i].an_wep_key, 0,
1501 				    sizeof(sc->sc_wepkeys[i].an_wep_key));
1502 				sc->sc_wepkeys[i].an_wep_keylen = -1;
1503 				needreset++;
1504 			}
1505 			if (keys[i].an_wep_keylen >= 0)
1506 				sc->sc_perskeylen[i] = keys[i].an_wep_keylen;
1507 		}
1508 	}
1509 	if (needreset) {
1510 		/* firmware restart to reload persistent key */
1511 		an_reset(sc);
1512 	}
1513 	if (anysetkey || needreset)
1514 		error = ENETRESET;
1515 	return error;
1516 }
1517 
1518 int
1519 an_get_nwkey(struct an_softc *sc, struct ieee80211_nwkey *nwkey)
1520 {
1521 	int i, error;
1522 
1523 	error = 0;
1524 	if (sc->sc_config.an_authtype & AN_AUTHTYPE_LEAP)
1525 		nwkey->i_wepon = IEEE80211_NWKEY_EAP;
1526 	else if (sc->sc_config.an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE)
1527 		nwkey->i_wepon = IEEE80211_NWKEY_WEP;
1528 	else
1529 		nwkey->i_wepon = IEEE80211_NWKEY_OPEN;
1530 	if (sc->sc_tx_key == -1)
1531 		nwkey->i_defkid = sc->sc_tx_perskey + 1;
1532 	else
1533 		nwkey->i_defkid = sc->sc_tx_key + 1;
1534 	if (nwkey->i_key[0].i_keydat == NULL)
1535 		return 0;
1536 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1537 		if (nwkey->i_key[i].i_keydat == NULL)
1538 			continue;
1539 		/* do not show any keys to non-root user */
1540 		if ((error = suser(curproc, 0)) != 0)
1541 			break;
1542 		nwkey->i_key[i].i_keylen = sc->sc_wepkeys[i].an_wep_keylen;
1543 		if (nwkey->i_key[i].i_keylen < 0) {
1544 			if (sc->sc_perskeylen[i] == 0)
1545 				nwkey->i_key[i].i_keylen = 0;
1546 			continue;
1547 		}
1548 		if ((error = copyout(sc->sc_wepkeys[i].an_wep_key,
1549 		    nwkey->i_key[i].i_keydat,
1550 		    sc->sc_wepkeys[i].an_wep_keylen)) != 0)
1551 			break;
1552 	}
1553 	return error;
1554 }
1555 
1556 int
1557 an_write_wepkey(struct an_softc *sc, int type, struct an_wepkey *keys, int kid)
1558 {
1559 	int i, error;
1560 	struct an_rid_wepkey *akey;
1561 
1562 	error = 0;
1563 	akey = &sc->sc_buf.sc_wepkey;
1564 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1565 		memset(akey, 0, sizeof(struct an_rid_wepkey));
1566 		if (keys[i].an_wep_keylen < 0 ||
1567 		    keys[i].an_wep_keylen > sizeof(akey->an_key))
1568 			continue;
1569 		akey->an_key_len = keys[i].an_wep_keylen;
1570 		akey->an_key_index = i;
1571 		akey->an_mac_addr[0] = 1;	/* default mac */
1572 		an_swap16((u_int16_t *)&akey->an_mac_addr, 3);
1573 		memcpy(akey->an_key, keys[i].an_wep_key, keys[i].an_wep_keylen);
1574 		an_swap16((u_int16_t *)&akey->an_key, 8);
1575 		if ((error = an_write_rid(sc, type, akey, sizeof(*akey))) != 0)
1576 			return error;
1577 	}
1578 	if (kid >= 0) {
1579 		memset(akey, 0, sizeof(struct an_rid_wepkey));
1580 		akey->an_key_index = 0xffff;
1581 		akey->an_mac_addr[0] = kid;
1582 		an_swap16((u_int16_t *)&akey->an_mac_addr, 3);
1583 		akey->an_key_len = 0;
1584 		memset(akey->an_key, 0, sizeof(akey->an_key));
1585 		error = an_write_rid(sc, type, akey, sizeof(*akey));
1586 	}
1587 	return error;
1588 }
1589 
1590 int
1591 an_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
1592 {
1593 	struct an_softc *sc = ic->ic_softc;
1594 	struct ieee80211_node *ni = ic->ic_bss;
1595 	enum ieee80211_state ostate;
1596 	int buflen;
1597 
1598 	ostate = ic->ic_state;
1599 	DPRINTF(("an_newstate: %s -> %s\n", ieee80211_state_name[ostate],
1600 	    ieee80211_state_name[nstate]));
1601 
1602 	switch (nstate) {
1603 	case IEEE80211_S_INIT:
1604 		ic->ic_flags &= ~IEEE80211_F_IBSSON;
1605 		return (*sc->sc_newstate)(ic, nstate, arg);
1606 
1607 	case IEEE80211_S_RUN:
1608 		buflen = sizeof(sc->sc_buf);
1609 		an_read_rid(sc, AN_RID_STATUS, &sc->sc_buf, &buflen);
1610 		an_swap16((u_int16_t *)&sc->sc_buf.sc_status.an_cur_bssid, 3);
1611 		an_swap16((u_int16_t *)&sc->sc_buf.sc_status.an_ssid, 16);
1612 		IEEE80211_ADDR_COPY(ni->ni_bssid,
1613 		    sc->sc_buf.sc_status.an_cur_bssid);
1614 		IEEE80211_ADDR_COPY(ni->ni_macaddr, ni->ni_bssid);
1615 		ni->ni_chan = &ic->ic_channels[
1616 		    sc->sc_buf.sc_status.an_cur_channel];
1617 		ni->ni_esslen = sc->sc_buf.sc_status.an_ssidlen;
1618 		if (ni->ni_esslen > IEEE80211_NWID_LEN)
1619 			ni->ni_esslen = IEEE80211_NWID_LEN;	/*XXX*/
1620 		memcpy(ni->ni_essid, sc->sc_buf.sc_status.an_ssid,
1621 		    ni->ni_esslen);
1622 		ni->ni_rates = ic->ic_sup_rates[IEEE80211_MODE_11B];	/*XXX*/
1623 		if (ic->ic_if.if_flags & IFF_DEBUG) {
1624 			printf("%s: ", sc->sc_dev.dv_xname);
1625 			if (ic->ic_opmode == IEEE80211_M_STA)
1626 				printf("associated ");
1627 			else
1628 				printf("synchronized ");
1629 			printf("with %s ssid ", ether_sprintf(ni->ni_bssid));
1630 			ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
1631 			printf(" channel %u start %uMb\n",
1632 			    sc->sc_buf.sc_status.an_cur_channel,
1633 			    sc->sc_buf.sc_status.an_current_tx_rate/2);
1634 		}
1635 		break;
1636 
1637 	default:
1638 		break;
1639 	}
1640 	ic->ic_state = nstate;
1641 	/* skip standard ieee80211 handling */
1642 	return 0;
1643 }
1644 
1645 int
1646 an_detach(struct an_softc *sc)
1647 {
1648 	struct ifnet *ifp = &sc->sc_ic.ic_if;
1649 	int s;
1650 
1651 	if (!sc->sc_attached)
1652 		return 0;
1653 
1654 	s = splnet();
1655 	sc->sc_invalid = 1;
1656 	an_stop(ifp, 1);
1657 	ifmedia_delete_instance(&sc->sc_ic.ic_media, IFM_INST_ANY);
1658 	ieee80211_ifdetach(ifp);
1659 	if_detach(ifp);
1660 	splx(s);
1661 	return 0;
1662 }
1663 
1664