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