xref: /netbsd-src/sys/dev/ic/an.c (revision 1ffa7b76c40339c17a0fb2a09fac93f287cfc046)
1 /*	$NetBSD: an.c,v 1.24 2003/01/31 00:26:27 thorpej 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  * The Aironet 4500/4800 series cards some in PCMCIA, ISA and PCI form.
46  * This driver supports all three device types (PCI devices are supported
47  * through an extra PCI shim: /sys/pci/if_an_p.c). ISA devices can be
48  * supported either using hard-coded IO port/IRQ settings or via Plug
49  * and Play. The 4500 series devices support 1Mbps and 2Mbps data rates.
50  * The 4800 devices support 1, 2, 5.5 and 11Mbps rates.
51  *
52  * Like the WaveLAN/IEEE cards, the Aironet NICs are all essentially
53  * PCMCIA devices. The ISA and PCI cards are a combination of a PCMCIA
54  * device and a PCMCIA to ISA or PCMCIA to PCI adapter card. There are
55  * a couple of important differences though:
56  *
57  * - Lucent doesn't currently offer a PCI card, however Aironet does
58  * - Lucent ISA card looks to the host like a PCMCIA controller with
59  *   a PCMCIA WaveLAN card inserted. This means that even desktop
60  *   machines need to be configured with PCMCIA support in order to
61  *   use WaveLAN/IEEE ISA cards. The Aironet cards on the other hand
62  *   actually look like normal ISA and PCI devices to the host, so
63  *   no PCMCIA controller support is needed
64  *
65  * The latter point results in a small gotcha. The Aironet PCMCIA
66  * cards can be configured for one of two operating modes depending
67  * on how the Vpp1 and Vpp2 programming voltages are set when the
68  * card is activated. In order to put the card in proper PCMCIA
69  * operation (where the CIS table is visible and the interface is
70  * programmed for PCMCIA operation), both Vpp1 and Vpp2 have to be
71  * set to 5 volts. FreeBSD by default doesn't set the Vpp voltages,
72  * which leaves the card in ISA/PCI mode, which prevents it from
73  * being activated as an PCMCIA device. Consequently, /sys/pccard/pccard.c
74  * has to be patched slightly in order to enable the Vpp voltages in
75  * order to make the Aironet PCMCIA cards work.
76  *
77  * Note that some PCMCIA controller software packages for Windows NT
78  * fail to set the voltages as well.
79  *
80  * The Aironet devices can operate in both station mode and access point
81  * mode. Typically, when programmed for station mode, the card can be set
82  * to automatically perform encapsulation/decapsulation of Ethernet II
83  * and 802.3 frames within 802.11 frames so that the host doesn't have
84  * to do it itself. This driver doesn't program the card that way: the
85  * driver handles all of the encapsulation/decapsulation itself.
86  */
87 
88 /*
89  * Ported to NetBSD from FreeBSD by Atsushi Onoe at the San Diego
90  * IETF meeting.
91  */
92 
93 #include <sys/cdefs.h>
94 __KERNEL_RCSID(0, "$NetBSD: an.c,v 1.24 2003/01/31 00:26:27 thorpej Exp $");
95 
96 #include "opt_inet.h"
97 #include "bpfilter.h"
98 
99 #ifdef INET
100 /*
101  * It is designed for IPv4 only.
102  * no one use it and disabled for now. -- onoe
103  */
104 #undef ANCACHE			/* enable signal strength cache */
105 #endif
106 
107 #include <sys/param.h>
108 #include <sys/callout.h>
109 #include <sys/systm.h>
110 #include <sys/sockio.h>
111 #include <sys/mbuf.h>
112 #include <sys/kernel.h>
113 #include <sys/ucred.h>
114 #include <sys/socket.h>
115 #include <sys/device.h>
116 #include <sys/proc.h>
117 #include <sys/md4.h>
118 #ifdef ANCACHE
119 #include <sys/syslog.h>
120 #include <sys/sysctl.h>
121 #endif
122 
123 #include <machine/bus.h>
124 
125 #include <net/if.h>
126 #include <net/if_arp.h>
127 #include <net/if_dl.h>
128 #include <net/if_ether.h>
129 #include <net/if_ieee80211.h>
130 #include <net/if_types.h>
131 #include <net/if_media.h>
132 
133 #ifdef INET
134 #include <netinet/in.h>
135 #include <netinet/in_systm.h>
136 #include <netinet/in_var.h>
137 #include <netinet/ip.h>
138 #endif
139 
140 #if NBPFILTER > 0
141 #include <net/bpf.h>
142 #endif
143 
144 #include <dev/ic/anreg.h>
145 #include <dev/ic/anvar.h>
146 
147 /* These are global because we need them in sys/pci/if_an_p.c. */
148 static void an_reset		__P((struct an_softc *));
149 static void an_wait		__P((struct an_softc *));
150 static int an_ioctl		__P((struct ifnet *, u_long, caddr_t));
151 static int an_set_nwkey		__P((struct an_softc *,
152 					struct ieee80211_nwkey *));
153 static int an_set_nwkey_wep	__P((struct an_softc *,
154 					struct ieee80211_nwkey *));
155 static int an_set_nwkey_eap	__P((struct an_softc *,
156 					struct ieee80211_nwkey *));
157 static int an_get_nwkey		__P((struct an_softc *,
158 					struct ieee80211_nwkey *));
159 static int an_write_wepkey	__P((struct an_softc *sc, int type,
160 					struct an_wepkey *keys, int kid));
161 static int an_init		__P((struct ifnet *));
162 static void an_stop		__P((struct ifnet *, int));
163 static int an_init_tx_ring	__P((struct an_softc *));
164 static void an_start		__P((struct ifnet *));
165 static void an_watchdog		__P((struct ifnet *));
166 static void an_rxeof		__P((struct an_softc *));
167 static void an_txeof		__P((struct an_softc *, int));
168 
169 static int an_cmd		__P((struct an_softc *, int, int));
170 static int an_read_record	__P((struct an_softc *, struct an_ltv_gen *));
171 static int an_write_record	__P((struct an_softc *, struct an_ltv_gen *));
172 static int an_read_data		__P((struct an_softc *, int,
173 					int, caddr_t, int));
174 static int an_write_data	__P((struct an_softc *, int,
175 					int, caddr_t, int));
176 static int an_seek		__P((struct an_softc *, int, int, int));
177 static int an_alloc_nicmem	__P((struct an_softc *, int, int *));
178 static void an_stats_update	__P((void *));
179 static int an_setdef		__P((struct an_softc *, struct an_req *));
180 #ifdef ANCACHE
181 static void an_cache_store	__P((struct an_softc *, struct ether_header *,
182 					struct mbuf *, unsigned short));
183 #endif
184 #ifdef IFM_IEEE80211
185 static int an_media_change __P((struct ifnet *ifp));
186 static void an_media_status __P((struct ifnet *ifp, struct ifmediareq *imr));
187 #endif
188 
189 int
190 an_attach(struct an_softc *sc)
191 {
192 	struct ifnet *ifp = &sc->arpcom.ec_if;
193 	int i, s;
194 	struct an_ltv_wepkey *akey;
195 #ifdef IFM_IEEE80211
196 	int mtype;
197 	struct ifmediareq imr;
198 #endif
199 
200 	s = splnet();
201 	sc->an_associated = 0;
202 	an_wait(sc);
203 
204 	/* Load factory config */
205 	if (an_cmd(sc, AN_CMD_READCFG, 0)) {
206 		splx(s);
207 		aprint_error("%s: failed to load config data\n",
208 		    sc->an_dev.dv_xname);
209 		return(EIO);
210 	}
211 
212 	/* Read the current configuration */
213 	sc->an_config.an_type = AN_RID_GENCONFIG;
214 	sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
215 	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_config)) {
216 		splx(s);
217 		aprint_error("%s: read record failed\n", sc->an_dev.dv_xname);
218 		return(EIO);
219 	}
220 
221 	/* Read the card capabilities */
222 	sc->an_caps.an_type = AN_RID_CAPABILITIES;
223 	sc->an_caps.an_len = sizeof(struct an_ltv_caps);
224 	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_caps)) {
225 		splx(s);
226 		aprint_error("%s: read record failed\n", sc->an_dev.dv_xname);
227 		return(EIO);
228 	}
229 
230 	/* Read ssid list */
231 	sc->an_ssidlist.an_type = AN_RID_SSIDLIST;
232 	sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist);
233 	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) {
234 		splx(s);
235 		aprint_error("%s: read record failed\n", sc->an_dev.dv_xname);
236 		return(EIO);
237 	}
238 
239 	/* Read AP list */
240 	sc->an_aplist.an_type = AN_RID_APLIST;
241 	sc->an_aplist.an_len = sizeof(struct an_ltv_aplist);
242 	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) {
243 		splx(s);
244 		aprint_error("%s: read record failed\n", sc->an_dev.dv_xname);
245 		return(EIO);
246 	}
247 
248 	/* Read WEP settings from persistent memory */
249 	akey = (struct an_ltv_wepkey *)&sc->an_reqbuf;
250 	akey->an_type = AN_RID_WEP_VOLATILE;
251 	akey->an_len = sizeof(struct an_ltv_wepkey);
252 	while (an_read_record(sc, (struct an_ltv_gen *)akey) == 0) {
253 		if (akey->an_key_index == 0xffff) {
254 			sc->an_tx_perskey = akey->an_mac_addr[0];
255 			sc->an_tx_key = -1;
256 			break;
257 		}
258 		if (akey->an_key_index >= IEEE80211_WEP_NKID)
259 			break;
260 		sc->an_perskeylen[akey->an_key_index] = akey->an_key_len;
261 		sc->an_wepkeys[akey->an_key_index].an_wep_keylen = -1;
262 		akey->an_type = AN_RID_WEP_PERSISTENT;	/* for next key */
263 		akey->an_len = sizeof(*akey);
264 	}
265 	/* XXX not sure if persistent key settings should be printed here */
266 
267 	aprint_normal("%s: 802.11 address: %s\n", sc->an_dev.dv_xname,
268 	    ether_sprintf(sc->an_caps.an_oemaddr));
269 
270 	ifp->if_softc = sc;
271 	ifp->if_flags = IFF_BROADCAST | IFF_NOTRAILERS | IFF_SIMPLEX |
272 	    IFF_MULTICAST | IFF_ALLMULTI;
273 	ifp->if_ioctl = an_ioctl;
274 	ifp->if_start = an_start;
275 	ifp->if_init = an_init;
276 	ifp->if_stop = an_stop;
277 	ifp->if_watchdog = an_watchdog;
278 	IFQ_SET_READY(&ifp->if_snd);
279 
280 	memcpy(ifp->if_xname, sc->an_dev.dv_xname, IFNAMSIZ);
281 
282 	memset(sc->an_config.an_nodename, 0, sizeof(sc->an_config.an_nodename));
283 	memcpy(sc->an_config.an_nodename, AN_DEFAULT_NODENAME,
284 	    sizeof(AN_DEFAULT_NODENAME) - 1);
285 
286 	memset(sc->an_ssidlist.an_ssid1, 0, sizeof(sc->an_ssidlist.an_ssid1));
287 	memcpy(sc->an_ssidlist.an_ssid1, AN_DEFAULT_NETNAME,
288 	    sizeof(AN_DEFAULT_NETNAME) - 1);
289 	sc->an_ssidlist.an_ssid1_len = strlen(AN_DEFAULT_NETNAME);
290 
291 	sc->an_config.an_opmode = AN_OPMODE_INFRASTRUCTURE_STATION;
292 
293 	sc->an_tx_rate = 0;
294 #if 0
295 	memset(&sc->an_stats, 0, sizeof(sc->an_stats));
296 #endif
297 
298 	/*
299 	 * Call MI attach routine.
300 	 */
301 	if_attach(ifp);
302 	ether_ifattach(ifp, sc->an_caps.an_oemaddr);
303 
304 #ifdef IFM_IEEE80211
305 	ifmedia_init(&sc->sc_media, 0, an_media_change, an_media_status);
306 	ifmedia_add(&sc->sc_media, IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
307 	    0, 0), 0, NULL);
308 	ifmedia_add(&sc->sc_media, IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
309 	    IFM_IEEE80211_ADHOC, 0), 0, NULL);
310 	for (i = 0; i < sizeof(sc->an_caps.an_rates); i++) {
311 		switch (sc->an_caps.an_rates[i]) {
312 		case AN_RATE_1MBPS:
313 			mtype = IFM_IEEE80211_DS1;
314 			break;
315 		case AN_RATE_2MBPS:
316 			mtype = IFM_IEEE80211_DS2;
317 			break;
318 		case AN_RATE_5_5MBPS:
319 			mtype = IFM_IEEE80211_DS5;
320 			break;
321 		case AN_RATE_11MBPS:
322 			mtype = IFM_IEEE80211_DS11;
323 			break;
324 		default:
325 			continue;
326 		}
327 		ifmedia_add(&sc->sc_media, IFM_MAKEWORD(IFM_IEEE80211, mtype,
328 		    0, 0), 0, NULL);
329 		ifmedia_add(&sc->sc_media, IFM_MAKEWORD(IFM_IEEE80211, mtype,
330 		    IFM_IEEE80211_ADHOC, 0), 0, NULL);
331 	}
332 	an_media_status(ifp, &imr);
333 	ifmedia_set(&sc->sc_media, imr.ifm_active);
334 #endif
335 	callout_init(&sc->an_stat_ch);
336 	splx(s);
337 
338 	return(0);
339 }
340 
341 int
342 an_detach(struct an_softc *sc)
343 {
344 	struct ifnet *ifp = &sc->arpcom.ec_if;
345 	int s;
346 
347 	s = splnet();
348 	an_stop(ifp, 1);
349 	ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
350 	ether_ifdetach(ifp);
351 	if_detach(ifp);
352 	splx(s);
353 	return 0;
354 }
355 
356 int
357 an_activate(struct device *self, enum devact act)
358 {
359 	struct an_softc *sc = (struct an_softc *)self;
360 	int s, error = 0;
361 
362 	s = splnet();
363 	switch (act) {
364 	case DVACT_ACTIVATE:
365 		error = EOPNOTSUPP;
366 		break;
367 
368 	case DVACT_DEACTIVATE:
369 		if_deactivate(&sc->arpcom.ec_if);
370 		break;
371 	}
372 	splx(s);
373 
374 	return error;
375 }
376 
377 void
378 an_power(int why, void *arg)
379 {
380 	int s;
381 	struct an_softc *sc = arg;
382 	struct ifnet *ifp = &sc->arpcom.ec_if;
383 
384 	s = splnet();
385 	switch (why) {
386 	case PWR_SUSPEND:
387 	case PWR_STANDBY:
388 		an_stop(ifp, 1);
389 		break;
390 	case PWR_RESUME:
391 		if (ifp->if_flags & IFF_UP)
392 			an_init(ifp);
393 		break;
394 	case PWR_SOFTSUSPEND:
395 	case PWR_SOFTSTANDBY:
396 	case PWR_SOFTRESUME:
397 		break;
398 	}
399 	splx(s);
400 }
401 
402 void
403 an_shutdown(void *arg)
404 {
405 	struct an_softc *sc = arg;
406 
407 	an_stop(&sc->arpcom.ec_if, 1);
408 	return;
409 }
410 
411 static int
412 an_setdef(struct an_softc *sc, struct an_req *areq)
413 {
414 	int error;
415 	struct ifnet *ifp = &sc->arpcom.ec_if;
416 	struct an_ltv_genconfig	*cfg;
417 	struct an_ltv_gen *sp;
418 
419 	error = 0;
420 
421 	switch (areq->an_type) {
422 	case AN_RID_GENCONFIG:
423 		cfg = (struct an_ltv_genconfig *)areq;
424 		memcpy(sc->an_caps.an_oemaddr, cfg->an_macaddr, ETHER_ADDR_LEN);
425 		memcpy(LLADDR(ifp->if_sadl), cfg->an_macaddr, ETHER_ADDR_LEN);
426 		memcpy(&sc->an_config, areq, sizeof(struct an_ltv_genconfig));
427 		error = ENETRESET;
428 		break;
429 	case AN_RID_SSIDLIST:
430 		memcpy(&sc->an_ssidlist, areq, sizeof(struct an_ltv_ssidlist));
431 		error = ENETRESET;
432 		break;
433 	case AN_RID_APLIST:
434 		memcpy(&sc->an_aplist, areq, sizeof(struct an_ltv_aplist));
435 		error = ENETRESET;
436 		break;
437 	case AN_RID_TX_SPEED:
438 		sp = (struct an_ltv_gen *)areq;
439 		sc->an_tx_rate = sp->an_val;
440 		break;
441 	case AN_RID_WEP_VOLATILE:
442 	case AN_RID_WEP_PERSISTENT:
443 	case AN_RID_LEAP_USER:
444 	case AN_RID_LEAP_PASS:
445 		if (!sc->sc_enabled) {
446 			error = ENXIO;
447 			break;
448 		}
449 		an_cmd(sc, AN_CMD_DISABLE, 0);
450 		an_write_record(sc, (struct an_ltv_gen *)areq);
451 		if (an_cmd(sc, AN_CMD_ENABLE, 0))
452 			error = EIO;
453 		break;
454 	default:
455 		if (ifp->if_flags & IFF_DEBUG)
456 			printf("%s: unknown RID: %x\n", sc->an_dev.dv_xname,
457 			    areq->an_type);
458 		error = EINVAL;
459 		break;
460 	}
461 	return error;
462 }
463 
464 static int
465 an_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
466 {
467 	int s;
468 	int error = 0;
469 	struct an_softc *sc;
470 	struct an_req *areq;
471 	struct ifreq *ifr;
472 	struct ieee80211_nwid nwid;
473 	struct ieee80211_power *power;
474 
475 	sc = ifp->if_softc;
476 	ifr = (struct ifreq *)data;
477 	s = splnet();
478 
479 	switch (command) {
480 	case SIOCSIFFLAGS:
481 		if (ifp->if_flags & IFF_UP) {
482 			if (sc->sc_enabled) {
483 				/*
484 				 * To avoid rescanning another access point,
485 				 * do not call an_init() here.  Instead, only
486 				 * reflect promisc mode settings.
487 				 */
488 				error = an_cmd(sc, AN_CMD_SET_MODE,
489 				    (ifp->if_flags & IFF_PROMISC) ? 0xffff : 0);
490 			} else
491 				error = an_init(ifp);
492 		} else if (sc->sc_enabled)
493 			an_stop(ifp, 1);
494 		break;
495 	case SIOCGAIRONET:
496 		areq = &sc->an_reqbuf;
497 		error = copyin(ifr->ifr_data, areq, sizeof(struct an_req));
498 		if (error)
499 			break;
500 		switch (areq->an_type) {
501 #ifdef ANCACHE
502 		case AN_RID_ZERO_CACHE:
503 			/* XXX suser()? -- should belong to SIOCSAIRONET */
504 			sc->an_sigitems = sc->an_nextitem = 0;
505 			goto out;
506 		case AN_RID_READ_CACHE:
507 			caddr_t pt = (char *)&areq->an_val;
508 			memcpy(pt, &sc->an_sigitems, sizeof(int));
509 			pt += sizeof(int);
510 			areq->an_len = sizeof(int) / 2;
511 			memcpy(pt, &sc->an_sigcache,
512 			    sizeof(struct an_sigcache) * sc->an_sigitems);
513 			areq->an_len += ((sizeof(struct an_sigcache) *
514 			    sc->an_sigitems) / 2) + 1;
515 			break;
516 #endif
517 		default:
518 			if (an_read_record(sc, (struct an_ltv_gen *)areq)) {
519 				error = EINVAL;
520 				break;
521 			}
522 			break;
523 		}
524 		error = copyout(areq, ifr->ifr_data, sizeof(struct an_req));
525 		break;
526 	case SIOCSAIRONET:
527 		if ((error = suser(curproc->p_ucred, &curproc->p_acflag)))
528 			break;
529 		areq = &sc->an_reqbuf;
530 		error = copyin(ifr->ifr_data, areq, sizeof(struct an_req));
531 		if (error)
532 			break;
533 		error = an_setdef(sc, areq);
534 		break;
535 	case SIOCS80211NWID:
536 		error = copyin(ifr->ifr_data, &nwid, sizeof(nwid));
537 		if (error)
538 			break;
539 		if (nwid.i_len > IEEE80211_NWID_LEN) {
540 			error = EINVAL;
541 			break;
542 		}
543 		if (sc->an_ssidlist.an_ssid1_len == nwid.i_len &&
544 		    memcmp(sc->an_ssidlist.an_ssid1, nwid.i_nwid, nwid.i_len)
545 		    == 0)
546 			break;
547 		memset(sc->an_ssidlist.an_ssid1, 0, IEEE80211_NWID_LEN);
548 		sc->an_ssidlist.an_ssid1_len = nwid.i_len;
549 		memcpy(sc->an_ssidlist.an_ssid1, nwid.i_nwid, nwid.i_len);
550 		error = ENETRESET;
551 		break;
552 	case SIOCG80211NWID:
553 		memset(&nwid, 0, sizeof(nwid));
554 		if (sc->sc_enabled && sc->an_associated) {
555 			nwid.i_len = sc->an_status.an_ssidlen;
556 			memcpy(nwid.i_nwid, sc->an_status.an_ssid, nwid.i_len);
557 		} else {
558 			nwid.i_len = sc->an_ssidlist.an_ssid1_len;
559 			memcpy(nwid.i_nwid, sc->an_ssidlist.an_ssid1,
560 			    nwid.i_len);
561 		}
562 		error = copyout(&nwid, ifr->ifr_data, sizeof(nwid));
563 		break;
564 	case SIOCS80211NWKEY:
565 		error = an_set_nwkey(sc, (struct ieee80211_nwkey *)data);
566 		break;
567 	case SIOCG80211NWKEY:
568 		error = an_get_nwkey(sc, (struct ieee80211_nwkey *)data);
569 		break;
570 	case SIOCS80211POWER:
571 		power = (struct ieee80211_power *)data;
572 		sc->an_config.an_psave_mode = power->i_enabled ?
573 		    AN_PSAVE_PSP : AN_PSAVE_NONE;
574 		sc->an_config.an_listen_interval = power->i_maxsleep;
575 		error = ENETRESET;
576 		break;
577 	case SIOCG80211POWER:
578 		power = (struct ieee80211_power *)data;
579 		power->i_enabled =
580 		    sc->an_config.an_psave_mode != AN_PSAVE_NONE ? 1 : 0;
581 		power->i_maxsleep = sc->an_config.an_listen_interval;
582 		break;
583 #ifdef IFM_IEEE80211
584 	case SIOCSIFMEDIA:
585 	case SIOCGIFMEDIA:
586 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command);
587 		break;
588 #endif
589 	case SIOCADDMULTI:
590 	case SIOCDELMULTI:
591 		error = ether_ioctl(ifp, command, data);
592 		if (error == ENETRESET) {
593 			/* we don't have multicast filter. */
594 			error = 0;
595 		}
596 		break;
597 	default:
598 		error = ether_ioctl(ifp, command, data);
599 		break;
600 	}
601 	if (error == ENETRESET) {
602 		if (sc->sc_enabled)
603 			error = an_init(ifp);
604 		else
605 			error = 0;
606 	}
607 #ifdef ANCACHE
608 out:
609 #endif
610 	splx(s);
611 	return error;
612 }
613 
614 static int
615 an_set_nwkey(struct an_softc *sc, struct ieee80211_nwkey *nwkey)
616 {
617 	int error;
618 	u_int16_t prevauth;
619 
620 	error = 0;
621 	prevauth = sc->an_config.an_authtype;
622 
623 	switch (nwkey->i_wepon) {
624 	case IEEE80211_NWKEY_OPEN:
625 		sc->an_config.an_authtype = AN_AUTHTYPE_OPEN;
626 		break;
627 
628 	case IEEE80211_NWKEY_WEP:
629 	case IEEE80211_NWKEY_WEP | IEEE80211_NWKEY_PERSIST:
630 		error = an_set_nwkey_wep(sc, nwkey);
631 		if (error == 0 || error == ENETRESET)
632 			sc->an_config.an_authtype =
633 			    AN_AUTHTYPE_OPEN | AN_AUTHTYPE_PRIVACY_IN_USE;
634 		break;
635 
636 	case IEEE80211_NWKEY_EAP:
637 		error = an_set_nwkey_eap(sc, nwkey);
638 		if (error == 0 || error == ENETRESET)
639 			sc->an_config.an_authtype = AN_AUTHTYPE_OPEN |
640 			    AN_AUTHTYPE_PRIVACY_IN_USE | AN_AUTHTYPE_LEAP;
641 		break;
642 	default:
643 		error = EINVAL;
644 		break;
645 	}
646 	if (error == 0 && prevauth != sc->an_config.an_authtype)
647 		error = ENETRESET;
648 	return error;
649 }
650 
651 static int
652 an_set_nwkey_wep(struct an_softc *sc, struct ieee80211_nwkey *nwkey)
653 {
654 	int i, txkey, anysetkey, needreset, error;
655 	struct an_wepkey keys[IEEE80211_WEP_NKID];
656 
657 	error = 0;
658 	memset(keys, 0, sizeof(keys));
659 	anysetkey = needreset = 0;
660 
661 	/* load argument and sanity check */
662 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
663 		keys[i].an_wep_keylen = nwkey->i_key[i].i_keylen;
664 		if (keys[i].an_wep_keylen < 0)
665 			continue;
666 		if (keys[i].an_wep_keylen != 0 &&
667 		    keys[i].an_wep_keylen < IEEE80211_WEP_KEYLEN)
668 			return EINVAL;
669 		if (keys[i].an_wep_keylen > sizeof(keys[i].an_wep_key))
670 			return EINVAL;
671 		if ((error = copyin(nwkey->i_key[i].i_keydat,
672 		    keys[i].an_wep_key, keys[i].an_wep_keylen)) != 0)
673 			return error;
674 		anysetkey++;
675 	}
676 	txkey = nwkey->i_defkid - 1;
677 	if (txkey >= 0) {
678 		if (txkey >= IEEE80211_WEP_NKID)
679 			return EINVAL;
680 		/* default key must have a valid value */
681 		if (keys[txkey].an_wep_keylen == 0 ||
682 		    (keys[txkey].an_wep_keylen < 0 &&
683 		    sc->an_perskeylen[txkey] == 0))
684 			return EINVAL;
685 		anysetkey++;
686 	}
687 	if (!(nwkey->i_wepon & IEEE80211_NWKEY_PERSIST)) {
688 		/* set temporary keys */
689 		sc->an_tx_key = txkey;
690 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
691 			if (keys[i].an_wep_keylen < 0)
692 				continue;
693 			memcpy(&sc->an_wepkeys[i], &keys[i], sizeof(keys[i]));
694 		}
695 	} else {
696 		/* set persist keys */
697 		if (anysetkey) {
698 			/* prepare to write nvram */
699 			if (!sc->sc_enabled) {
700 				if (sc->sc_enable)
701 					(*sc->sc_enable)(sc);
702 				an_wait(sc);
703 				sc->sc_enabled = 1;
704 				error = an_write_wepkey(sc,
705 				    AN_RID_WEP_PERSISTENT, keys, txkey);
706 				if (sc->sc_disable)
707 					(*sc->sc_disable)(sc);
708 				sc->sc_enabled = 0;
709 			} else {
710 				an_cmd(sc, AN_CMD_DISABLE, 0);
711 				error = an_write_wepkey(sc,
712 				    AN_RID_WEP_PERSISTENT, keys, txkey);
713 				an_cmd(sc, AN_CMD_ENABLE, 0);
714 			}
715 			if (error)
716 				return error;
717 		}
718 		if (txkey >= 0)
719 			sc->an_tx_perskey = txkey;
720 		if (sc->an_tx_key >= 0) {
721 			sc->an_tx_key = -1;
722 			needreset++;
723 		}
724 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
725 			if (sc->an_wepkeys[i].an_wep_keylen >= 0) {
726 				memset(&sc->an_wepkeys[i].an_wep_key, 0,
727 				    sizeof(sc->an_wepkeys[i].an_wep_key));
728 				sc->an_wepkeys[i].an_wep_keylen = -1;
729 				needreset++;
730 			}
731 			if (keys[i].an_wep_keylen >= 0)
732 				sc->an_perskeylen[i] = keys[i].an_wep_keylen;
733 		}
734 	}
735 	if (needreset) {
736 		/* firmware restart to reload persistent key */
737 		an_reset(sc);
738 	}
739 	if (anysetkey || needreset)
740 		error = ENETRESET;
741 	return error;
742 }
743 
744 static int
745 an_set_nwkey_eap(struct an_softc *sc, struct ieee80211_nwkey *nwkey)
746 {
747 	int i, error;
748 	struct an_ltv_leapkey *key;
749 	u_int16_t unibuf[sizeof(key->an_key)];
750 	MD4_CTX ctx;
751 
752 	error = 0;
753 
754 	if (nwkey->i_key[0].i_keydat == NULL &&
755 	    nwkey->i_key[1].i_keydat == NULL)
756 		return 0;
757 	if (!sc->sc_enabled)
758 		return ENXIO;
759 	an_cmd(sc, AN_CMD_DISABLE, 0);
760 	key = (struct an_ltv_leapkey *)&sc->an_reqbuf;
761 	if (nwkey->i_key[0].i_keydat != NULL) {
762 		memset(key, 0, sizeof(*key));
763 		key->an_type = AN_RID_LEAP_USER;
764 		key->an_len = sizeof(*key);
765 		key->an_key_len = nwkey->i_key[0].i_keylen;
766 		if (key->an_key_len > sizeof(key->an_key))
767 			return EINVAL;
768 		if ((error = copyin(nwkey->i_key[0].i_keydat, key->an_key,
769 		    key->an_key_len)) != 0)
770 			return error;
771 		an_write_record(sc, (struct an_ltv_gen *)key);
772 	}
773 	if (nwkey->i_key[1].i_keydat != NULL) {
774 		memset(key, 0, sizeof(*key));
775 		key->an_type = AN_RID_LEAP_PASS;
776 		key->an_len = sizeof(*key);
777 		key->an_key_len = nwkey->i_key[1].i_keylen;
778 		if (key->an_key_len > sizeof(key->an_key))
779 			return EINVAL;
780 		if ((error = copyin(nwkey->i_key[1].i_keydat, key->an_key,
781 		    key->an_key_len)) != 0)
782 			return error;
783 		/*
784 		 * Cisco seems to use PasswordHash and PasswordHashHash
785 		 * in RFC-2759 (MS-CHAP-V2).
786 		 */
787 		memset(unibuf, 0, sizeof(unibuf));
788 		/* XXX: convert password to unicode */
789 		for (i = 0; i < key->an_key_len; i++)
790 			unibuf[i] = key->an_key[i];
791 		/* set PasswordHash */
792 		MD4Init(&ctx);
793 		MD4Update(&ctx, (u_int8_t *)unibuf, key->an_key_len * 2);
794 		MD4Final(key->an_key, &ctx);
795 		/* set PasswordHashHash */
796 		MD4Init(&ctx);
797 		MD4Update(&ctx, key->an_key, 16);
798 		MD4Final(key->an_key + 16, &ctx);
799 		key->an_key_len = 32;
800 		an_write_record(sc, (struct an_ltv_gen *)key);
801 	}
802 	error = an_cmd(sc, AN_CMD_ENABLE, 0);
803 	if (error)
804 		printf("%s: an_set_nwkey: failed to enable MAC\n",
805 		    sc->an_dev.dv_xname);
806 	else
807 		error = ENETRESET;
808 	return error;
809 }
810 
811 static int
812 an_get_nwkey(struct an_softc *sc, struct ieee80211_nwkey *nwkey)
813 {
814 	int i, error;
815 
816 	error = 0;
817 	if (sc->an_config.an_authtype & AN_AUTHTYPE_LEAP)
818 		nwkey->i_wepon = IEEE80211_NWKEY_EAP;
819 	else if (sc->an_config.an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE)
820 		nwkey->i_wepon = IEEE80211_NWKEY_WEP;
821 	else
822 		nwkey->i_wepon = IEEE80211_NWKEY_OPEN;
823 	if (sc->an_tx_key == -1)
824 		nwkey->i_defkid = sc->an_tx_perskey + 1;
825 	else
826 		nwkey->i_defkid = sc->an_tx_key + 1;
827 	if (nwkey->i_key[0].i_keydat == NULL)
828 		return 0;
829 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
830 		if (nwkey->i_key[i].i_keydat == NULL)
831 			continue;
832 		/* do not show any keys to non-root user */
833 		if ((error = suser(curproc->p_ucred, &curproc->p_acflag)) != 0)
834 			break;
835 		nwkey->i_key[i].i_keylen = sc->an_wepkeys[i].an_wep_keylen;
836 		if (nwkey->i_key[i].i_keylen < 0) {
837 			if (sc->an_perskeylen[i] == 0)
838 				nwkey->i_key[i].i_keylen = 0;
839 			continue;
840 		}
841 		if ((error = copyout(sc->an_wepkeys[i].an_wep_key,
842 		    nwkey->i_key[i].i_keydat,
843 		    sc->an_wepkeys[i].an_wep_keylen)) != 0)
844 			break;
845 	}
846 	return error;
847 }
848 
849 static int
850 an_write_wepkey(struct an_softc *sc, int type, struct an_wepkey *keys, int kid)
851 {
852 	int i, error;
853 	struct an_ltv_wepkey	*akey;
854 
855 	error = 0;
856 	akey = (struct an_ltv_wepkey *)&sc->an_reqbuf;
857 	memset(akey, 0, sizeof(struct an_ltv_wepkey));
858 	akey->an_type = type;
859 	akey->an_len = sizeof(struct an_ltv_wepkey);
860 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
861 		if (keys[i].an_wep_keylen < 0 ||
862 		    keys[i].an_wep_keylen > sizeof(akey->an_key))
863 			continue;
864 		akey->an_key_len = keys[i].an_wep_keylen;
865 		akey->an_key_index = i;
866 		akey->an_mac_addr[0] = 1;	/* default mac */
867 		memcpy(akey->an_key, keys[i].an_wep_key, akey->an_key_len);
868 		error = an_write_record(sc, (struct an_ltv_gen *)akey);
869 		if (error)
870 			return error;
871 	}
872 	if (kid >= 0) {
873 		akey->an_key_index = 0xffff;
874 		akey->an_mac_addr[0] = kid;
875 		akey->an_key_len = 0;
876 		memset(akey->an_key, 0, sizeof(akey->an_key));
877 		error = an_write_record(sc, (struct an_ltv_gen *)akey);
878 	}
879 	return error;
880 }
881 
882 #ifdef IFM_IEEE80211
883 static int
884 an_media_change(struct ifnet *ifp)
885 {
886 	struct an_softc *sc = ifp->if_softc;
887 	struct ifmedia_entry *ime;
888 	int error;
889 
890 	error = 0;
891 	ime = sc->sc_media.ifm_cur;
892 	switch (IFM_SUBTYPE(ime->ifm_media)) {
893 	case IFM_AUTO:
894 		sc->an_tx_rate = 0;
895 		break;
896 	case IFM_IEEE80211_DS1:
897 		sc->an_tx_rate = AN_RATE_1MBPS;
898 		break;
899 	case IFM_IEEE80211_DS2:
900 		sc->an_tx_rate = AN_RATE_2MBPS;
901 		break;
902 	case IFM_IEEE80211_DS5:
903 		sc->an_tx_rate = AN_RATE_5_5MBPS;
904 		break;
905 	case IFM_IEEE80211_DS11:
906 		sc->an_tx_rate = AN_RATE_11MBPS;
907 		break;
908 	}
909 	if (ime->ifm_media & IFM_IEEE80211_ADHOC)
910 		sc->an_config.an_opmode = AN_OPMODE_IBSS_ADHOC;
911 	else
912 		sc->an_config.an_opmode = AN_OPMODE_INFRASTRUCTURE_STATION;
913 	/*
914 	 * XXX: how to set txrate for the firmware?
915 	 * There is a struct defined as an_txframe, which is used nowhere.
916 	 * Perhaps we need to change the transmit mode from 802.3 to native.
917 	 */
918 
919 	/* we cannot return ENETRESET here */
920 	if (sc->sc_enabled)
921 		error = an_init(ifp);
922 	return error;
923 }
924 
925 static void
926 an_media_status(ifp, imr)
927 	struct ifnet *ifp;
928 	struct ifmediareq *imr;
929 {
930 	struct an_softc *sc = ifp->if_softc;
931 
932 	imr->ifm_status = IFM_AVALID;
933 	imr->ifm_active = IFM_IEEE80211;
934 	if (sc->sc_enabled && sc->an_associated) {
935 		imr->ifm_status |= IFM_ACTIVE;
936 		switch (sc->an_status.an_current_tx_rate) {
937 		case 0:
938 			imr->ifm_active |= IFM_AUTO;
939 			break;
940 		case AN_RATE_1MBPS:
941 			imr->ifm_active |= IFM_IEEE80211_DS1;
942 			break;
943 		case AN_RATE_2MBPS:
944 			imr->ifm_active |= IFM_IEEE80211_DS2;
945 			break;
946 		case AN_RATE_5_5MBPS:
947 			imr->ifm_active |= IFM_IEEE80211_DS5;
948 			break;
949 		case AN_RATE_11MBPS:
950 			imr->ifm_active |= IFM_IEEE80211_DS11;
951 			break;
952 		}
953 	}
954 	if ((sc->an_config.an_opmode & 0x0f) == AN_OPMODE_IBSS_ADHOC)
955 		imr->ifm_active |= IFM_IEEE80211_ADHOC;
956 }
957 #endif /* IFM_IEEE80211 */
958 
959 static int
960 an_init_tx_ring(struct an_softc *sc)
961 {
962 	int i, id;
963 
964 	for (i = 0; i < AN_TX_RING_CNT; i++) {
965 		if (an_alloc_nicmem(sc,
966 		    ETHER_MAX_LEN + ETHER_TYPE_LEN + AN_802_11_OFFSET, &id))
967 			return ENOMEM;
968 		sc->an_rdata.an_tx_fids[i] = id;
969 		sc->an_rdata.an_tx_ring[i] = 0;
970 	}
971 
972 	sc->an_rdata.an_tx_prod = 0;
973 	sc->an_rdata.an_tx_cons = 0;
974 	return 0;
975 }
976 
977 static int
978 an_init(struct ifnet *ifp)
979 {
980 	struct an_softc *sc = (struct an_softc *)ifp->if_softc;
981 
982 	if (sc->sc_enabled) {
983 		an_stop(ifp, 0);
984 	} else {
985 		if (sc->sc_enable)
986 			(*sc->sc_enable)(sc);
987 		sc->sc_enabled = 1;
988 		an_wait(sc);
989 	}
990 
991 	sc->an_associated = 0;
992 
993 	/* Allocate the TX buffers */
994 	if (an_init_tx_ring(sc)) {
995 		an_reset(sc);
996 		if (an_init_tx_ring(sc)) {
997 			printf("%s: tx buffer allocation failed\n",
998 			    sc->an_dev.dv_xname);
999 			an_stop(ifp, 1);
1000 			return ENOMEM;
1001 		}
1002 	}
1003 
1004 	/* Set our MAC address. */
1005 	memcpy(sc->an_config.an_macaddr, sc->an_caps.an_oemaddr,
1006 	    ETHER_ADDR_LEN);
1007 
1008 	if (ifp->if_flags & IFF_MULTICAST)
1009 		sc->an_config.an_rxmode = AN_RXMODE_BC_MC_ADDR;
1010 	else if (ifp->if_flags & IFF_BROADCAST)
1011 		sc->an_config.an_rxmode = AN_RXMODE_BC_ADDR;
1012 	else
1013 		sc->an_config.an_rxmode = AN_RXMODE_ADDR;
1014 
1015 	/* Set the ssid list */
1016 	sc->an_ssidlist.an_type = AN_RID_SSIDLIST;
1017 	sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist);
1018 	if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) {
1019 		printf("%s: failed to set ssid list\n", sc->an_dev.dv_xname);
1020 		an_stop(ifp, 1);
1021 		return ENXIO;
1022 	}
1023 
1024 	/* Set the AP list */
1025 	sc->an_aplist.an_type = AN_RID_APLIST;
1026 	sc->an_aplist.an_len = sizeof(struct an_ltv_aplist);
1027 	if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) {
1028 		printf("%s: failed to set AP list\n", sc->an_dev.dv_xname);
1029 		an_stop(ifp, 1);
1030 		return ENXIO;
1031 	}
1032 
1033 	/* Set the configuration in the NIC */
1034 	sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
1035 	sc->an_config.an_type = AN_RID_GENCONFIG;
1036 	if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_config)) {
1037 		printf("%s: failed to set configuration\n", sc->an_dev.dv_xname);
1038 		an_stop(ifp, 1);
1039 		return ENXIO;
1040 	}
1041 
1042 	/* Set the WEP Keys */
1043 	if ((sc->an_config.an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE) != 0)
1044 		an_write_wepkey(sc, AN_RID_WEP_VOLATILE, sc->an_wepkeys,
1045 		    sc->an_tx_key);
1046 
1047 	/* Enable the MAC */
1048 	if (an_cmd(sc, AN_CMD_ENABLE, 0)) {
1049 		printf("%s: failed to enable MAC\n", sc->an_dev.dv_xname);
1050 		an_stop(ifp, 1);
1051 		return ENXIO;
1052 	}
1053 
1054 	an_cmd(sc, AN_CMD_SET_MODE, (ifp->if_flags & IFF_PROMISC) ? 0xffff : 0);
1055 
1056 	/* enable interrupts */
1057 	CSR_WRITE_2(sc, AN_INT_EN, AN_INTRS);
1058 
1059 	ifp->if_flags |= IFF_RUNNING;
1060 	ifp->if_flags &= ~IFF_OACTIVE;
1061 
1062 	callout_reset(&sc->an_stat_ch, hz, an_stats_update, sc);
1063 	return 0;
1064 }
1065 
1066 static void
1067 an_start(struct ifnet *ifp)
1068 {
1069 	struct an_softc *sc = (struct an_softc *)ifp->if_softc;
1070 	struct mbuf *m0 = NULL, *m;
1071 	struct an_txframe_802_3 tx_frame_802_3;
1072 	struct ether_header *eh;
1073 	int id, idx;
1074 	u_int16_t txctl;
1075 
1076 	if (!sc->sc_enabled)
1077 		return;
1078 
1079 	if (ifp->if_flags & IFF_OACTIVE)
1080 		return;
1081 
1082 	if (!sc->an_associated)
1083 		return;
1084 
1085 	idx = sc->an_rdata.an_tx_prod;
1086 	memset(&tx_frame_802_3, 0, sizeof(tx_frame_802_3));
1087 
1088 	for (;;) {
1089 		IFQ_POLL(&ifp->if_snd, m0);
1090 		if (m0 == NULL)
1091 			break;
1092 		if (sc->an_rdata.an_tx_ring[idx] != 0)
1093 			break;
1094 		id = sc->an_rdata.an_tx_fids[idx];
1095 		IFQ_DEQUEUE(&ifp->if_snd, m0);
1096 #if NBPFILTER > 0
1097 		/*
1098 		 * If there's a BPF listner, bounce a copy of
1099 		 * this frame to him.
1100 		 */
1101 		if (ifp->if_bpf)
1102 			bpf_mtap(ifp->if_bpf, m0);
1103 #endif
1104 
1105 		txctl = AN_TXCTL_8023;
1106 		/* write the txctl only */
1107 		an_write_data(sc, id, 0x08, (caddr_t)&txctl, sizeof(txctl));
1108 
1109 		eh = mtod(m0, struct ether_header *);
1110 		memcpy(tx_frame_802_3.an_tx_dst_addr, eh->ether_dhost,
1111 		    ETHER_ADDR_LEN);
1112 		memcpy(tx_frame_802_3.an_tx_src_addr, eh->ether_shost,
1113 		    ETHER_ADDR_LEN);
1114 		tx_frame_802_3.an_tx_802_3_payload_len =
1115 		    m0->m_pkthdr.len - ETHER_ADDR_LEN * 2;
1116 		m_adj(m0, ETHER_ADDR_LEN * 2);
1117 
1118 		/* 802_3 header */
1119 		an_write_data(sc, id, AN_802_3_OFFSET,
1120 		    (caddr_t)&tx_frame_802_3, sizeof(struct an_txframe_802_3));
1121 		for (m = m0; m != NULL; m = m->m_next)
1122 			an_write_data(sc, id, -1, mtod(m, caddr_t), m->m_len);
1123 		m_freem(m0);
1124 		m0 = NULL;
1125 
1126 		sc->an_rdata.an_tx_ring[idx] = id;
1127 		if (an_cmd(sc, AN_CMD_TX, id))
1128 			printf("%s: xmit failed\n", sc->an_dev.dv_xname);
1129 
1130 		AN_INC(idx, AN_TX_RING_CNT);
1131 	}
1132 
1133 	if (m0 != NULL)
1134 		ifp->if_flags |= IFF_OACTIVE;
1135 
1136 	sc->an_rdata.an_tx_prod = idx;
1137 
1138 	/*
1139 	 * Set a timeout in case the chip goes out to lunch.
1140 	 */
1141 	ifp->if_timer = 5;
1142 }
1143 
1144 void
1145 an_stop(struct ifnet *ifp, int disable)
1146 {
1147 	struct an_softc *sc = (struct an_softc *)ifp->if_softc;
1148 	int i;
1149 
1150 	callout_stop(&sc->an_stat_ch);
1151 
1152 	ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
1153 	ifp->if_timer = 0;
1154 
1155 	if (!sc->sc_enabled)
1156 		return;
1157 
1158 	an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0);
1159 	CSR_WRITE_2(sc, AN_INT_EN, 0);
1160 	an_cmd(sc, AN_CMD_DISABLE, 0);
1161 
1162 	for (i = 0; i < AN_TX_RING_CNT; i++)
1163 		an_cmd(sc, AN_CMD_DEALLOC_MEM, sc->an_rdata.an_tx_fids[i]);
1164 
1165 	if (disable) {
1166 		if (sc->sc_disable)
1167 			(*sc->sc_disable)(sc);
1168 		sc->sc_enabled = 0;
1169 	}
1170 }
1171 
1172 static void
1173 an_watchdog(struct ifnet *ifp)
1174 {
1175 	struct an_softc *sc;
1176 
1177 	sc = ifp->if_softc;
1178 	if (!sc->sc_enabled)
1179 		return;
1180 
1181 	printf("%s: device timeout\n", sc->an_dev.dv_xname);
1182 
1183 	an_reset(sc);
1184 	an_init(ifp);
1185 
1186 	ifp->if_oerrors++;
1187 	return;
1188 }
1189 
1190 /*
1191  * Low level functions
1192  */
1193 
1194 static void
1195 an_rxeof(struct an_softc *sc)
1196 {
1197 	struct ifnet *ifp = &sc->arpcom.ec_if;
1198 	struct ether_header *eh;
1199 #ifdef ANCACHE
1200 	struct an_rxframe rx_frame;
1201 #endif
1202 	struct an_rxframe_802_3	rx_frame_802_3;
1203 	struct mbuf *m;
1204 	int id, error = 0;
1205 
1206 
1207 	id = CSR_READ_2(sc, AN_RX_FID);
1208 
1209 	MGETHDR(m, M_DONTWAIT, MT_DATA);
1210 	if (m == NULL) {
1211 		ifp->if_ierrors++;
1212 		return;
1213 	}
1214 	MCLGET(m, M_DONTWAIT);
1215 	if (!(m->m_flags & M_EXT)) {
1216 		m_freem(m);
1217 		ifp->if_ierrors++;
1218 		return;
1219 	}
1220 
1221 	m->m_pkthdr.rcvif = ifp;
1222 
1223 	/* Align the data after the ethernet header */
1224 	m->m_data = (caddr_t) ALIGN(m->m_data + sizeof(struct ether_header)) -
1225 	    sizeof(struct ether_header);
1226 
1227 	eh = mtod(m, struct ether_header *);
1228 
1229 #ifdef ANCACHE
1230 	/* Read NIC frame header */
1231 	if (an_read_data(sc, id, 0, (caddr_t)&rx_frame, sizeof(rx_frame))) {
1232 		ifp->if_ierrors++;
1233 		return;
1234 	}
1235 #endif
1236 	/* Read in the 802_3 frame header */
1237 	if (an_read_data(sc, id, AN_802_3_OFFSET, (caddr_t)&rx_frame_802_3,
1238 	    sizeof(rx_frame_802_3))) {
1239 		ifp->if_ierrors++;
1240 		return;
1241 	}
1242 
1243 	if (rx_frame_802_3.an_rx_802_3_status != 0) {
1244 		ifp->if_ierrors++;
1245 		return;
1246 	}
1247 
1248 	/* Check for insane frame length */
1249 	if (rx_frame_802_3.an_rx_802_3_payload_len > MCLBYTES) {
1250 		ifp->if_ierrors++;
1251 		return;
1252 	}
1253 
1254 	m->m_pkthdr.len = m->m_len =
1255 	    rx_frame_802_3.an_rx_802_3_payload_len + ETHER_ADDR_LEN * 2;
1256 
1257 	memcpy(&eh->ether_dhost, &rx_frame_802_3.an_rx_dst_addr,
1258 	    ETHER_ADDR_LEN);
1259 	memcpy(&eh->ether_shost, &rx_frame_802_3.an_rx_src_addr,
1260 	    ETHER_ADDR_LEN);
1261 
1262 	/* in mbuf header type is just before payload */
1263 	error = an_read_data(sc, id, -1, (caddr_t)&(eh->ether_type),
1264 	     rx_frame_802_3.an_rx_802_3_payload_len);
1265 
1266 	if (error) {
1267 		m_freem(m);
1268 		ifp->if_ierrors++;
1269 		return;
1270 	}
1271 
1272 	ifp->if_ipackets++;
1273 
1274 	/* Receive packet. */
1275 #ifdef ANCACHE
1276 	an_cache_store(sc, eh, m, rx_frame.an_rx_signal_strength);
1277 #endif
1278 #if NBPFILTER > 0
1279 	if (ifp->if_bpf)
1280 		bpf_mtap(ifp->if_bpf, m);
1281 #endif
1282 	(*ifp->if_input)(ifp, m);
1283 }
1284 
1285 static void
1286 an_txeof(struct an_softc *sc, int status)
1287 {
1288 	struct ifnet *ifp = &sc->arpcom.ec_if;
1289 	int i, id;
1290 
1291 	ifp->if_timer = 0;
1292 	ifp->if_flags &= ~IFF_OACTIVE;
1293 
1294 	id = CSR_READ_2(sc, AN_TX_CMP_FID);
1295 
1296 	if (status & AN_EV_TX_EXC)
1297 		ifp->if_oerrors++;
1298 	else
1299 		ifp->if_opackets++;
1300 
1301 	/* fix from Doug Ambrisko -wsr */
1302 	for (i = 0; i < AN_TX_RING_CNT; i++) {
1303 		if (id == sc->an_rdata.an_tx_ring[i]) {
1304 			sc->an_rdata.an_tx_ring[i] = 0;
1305 			break;
1306 		}
1307 	}
1308 	if (i != sc->an_rdata.an_tx_cons) {
1309 		if (ifp->if_flags & IFF_DEBUG)
1310 			printf("%s: id mismatch: id %x, "
1311 			    "expected %x(%d), actual %x(%d)\n",
1312 			    sc->an_dev.dv_xname, id,
1313 			    sc->an_rdata.an_tx_ring[sc->an_rdata.an_tx_cons],
1314 			    sc->an_rdata.an_tx_cons, id, i);
1315 	}
1316 
1317 	AN_INC(sc->an_rdata.an_tx_cons, AN_TX_RING_CNT);
1318 
1319 	return;
1320 }
1321 
1322 /*
1323  * We abuse the stats updater to check the current NIC status. This
1324  * is important because we don't want to allow transmissions until
1325  * the NIC has synchronized to the current cell (either as the master
1326  * in an ad-hoc group, or as a station connected to an access point).
1327  */
1328 void
1329 an_stats_update(void *xsc)
1330 {
1331 	struct an_softc *sc = xsc;
1332 
1333 	if (sc->sc_enabled) {
1334 		sc->an_status.an_type = AN_RID_STATUS;
1335 		sc->an_status.an_len = sizeof(struct an_ltv_status);
1336 		if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_status)
1337 		    == 0) {
1338 			if (sc->an_status.an_opmode & AN_STATUS_OPMODE_IN_SYNC)
1339 				sc->an_associated = 1;
1340 			else
1341 				sc->an_associated = 0;
1342 #if 0
1343 			/* Don't do this while we're transmitting */
1344 			if (sc->arpcom.ec_if.if_flags & IFF_OACTIVE) {
1345 				sc->an_stats.an_len =
1346 				    sizeof(struct an_ltv_stats);
1347 				sc->an_stats.an_type = AN_RID_32BITS_CUM;
1348 				an_read_record(sc,
1349 				    (struct an_ltv_gen *)&sc->an_stats.an_len);
1350 			}
1351 #endif
1352 		}
1353 	}
1354 	callout_reset(&sc->an_stat_ch, hz, an_stats_update, sc);
1355 }
1356 
1357 int
1358 an_intr(void *arg)
1359 {
1360 	struct an_softc *sc = arg;
1361 	struct ifnet *ifp = &sc->arpcom.ec_if;
1362 	u_int16_t status;
1363 
1364 	if (!sc->sc_enabled)
1365 		return 0;
1366 
1367 	if (!(ifp->if_flags & IFF_UP)) {
1368 		CSR_WRITE_2(sc, AN_EVENT_ACK, 0xFFFF);
1369 		CSR_WRITE_2(sc, AN_INT_EN, 0);
1370 		return 0;
1371 	}
1372 
1373 	/* Disable interrupts. */
1374 	CSR_WRITE_2(sc, AN_INT_EN, 0);
1375 
1376 	while ((status = (CSR_READ_2(sc, AN_EVENT_STAT) & AN_INTRS)) != 0) {
1377 		if (status & AN_EV_RX) {
1378 			an_rxeof(sc);
1379 			CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
1380 			status &= ~AN_EV_RX;
1381 		}
1382 		if (status & (AN_EV_TX | AN_EV_TX_EXC)) {
1383 			an_txeof(sc, status);
1384 			CSR_WRITE_2(sc, AN_EVENT_ACK,
1385 			    status & (AN_EV_TX | AN_EV_TX_EXC));
1386 			status &= ~(AN_EV_TX | AN_EV_TX_EXC);
1387 		}
1388 		if (status & AN_EV_LINKSTAT) {
1389 			if (CSR_READ_2(sc, AN_LINKSTAT) ==
1390 			    AN_LINKSTAT_ASSOCIATED)
1391 				sc->an_associated = 1;
1392 			else
1393 				sc->an_associated = 0;
1394 			CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_LINKSTAT);
1395 			status &= ~AN_EV_LINKSTAT;
1396 		}
1397 #if 0
1398 		if (status & AN_EV_CMD) {
1399 			wakeup(sc);
1400 			CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD);
1401 			status &= ~AN_EV_CMD;
1402 		}
1403 #endif
1404 		if (status)
1405 			CSR_WRITE_2(sc, AN_EVENT_ACK, status);
1406 	}
1407 
1408 	/* Re-enable interrupts. */
1409 	CSR_WRITE_2(sc, AN_INT_EN, AN_INTRS);
1410 
1411 	if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
1412 		an_start(ifp);
1413 
1414 	return 1;
1415 }
1416 
1417 static int
1418 an_cmd(struct an_softc *sc, int cmd, int val)
1419 {
1420 	int i, stat;
1421 
1422 	/* make sure that previous command completed */
1423 	if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY) {
1424 		if (sc->arpcom.ec_if.if_flags & IFF_DEBUG)
1425 			printf("%s: command 0x%x busy\n", sc->an_dev.dv_xname,
1426 			    CSR_READ_2(sc, AN_COMMAND));
1427 		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY);
1428 	}
1429 
1430 	CSR_WRITE_2(sc, AN_PARAM0, val);
1431 	CSR_WRITE_2(sc, AN_PARAM1, 0);
1432 	CSR_WRITE_2(sc, AN_PARAM2, 0);
1433 	CSR_WRITE_2(sc, AN_COMMAND, cmd);
1434 
1435 	for (i = 0; i < AN_TIMEOUT; i++) {
1436 		if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_CMD)
1437 			break;
1438 		/* make sure the command is accepted */
1439 		if (CSR_READ_2(sc, AN_COMMAND) == cmd)
1440 			CSR_WRITE_2(sc, AN_COMMAND, cmd);
1441 		DELAY(10);
1442 	}
1443 
1444 	stat = CSR_READ_2(sc, AN_STATUS);
1445 
1446 	/* clear stuck command busy if necessary */
1447 	if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY)
1448 		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY);
1449 
1450 	/* Ack the command */
1451 	CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD);
1452 
1453 	if (i == AN_TIMEOUT) {
1454 		if (sc->arpcom.ec_if.if_flags & IFF_DEBUG)
1455 			printf("%s: command 0x%x param 0x%x timeout\n",
1456 			    sc->an_dev.dv_xname, cmd, val);
1457 		return ETIMEDOUT;
1458 	}
1459 	if (stat & AN_STAT_CMD_RESULT) {
1460 		if (sc->arpcom.ec_if.if_flags & IFF_DEBUG)
1461 			printf("%s: command 0x%x param 0x%x stat 0x%x\n",
1462 			    sc->an_dev.dv_xname, cmd, val, stat);
1463 		return EIO;
1464 	}
1465 
1466 	return 0;
1467 }
1468 
1469 /*
1470  * This reset sequence may look a little strange, but this is the
1471  * most reliable method I've found to really kick the NIC in the
1472  * head and force it to reboot correctly.
1473  */
1474 static void
1475 an_reset(struct an_softc *sc)
1476 {
1477 
1478 	if (!sc->sc_enabled)
1479 		return;
1480 
1481 	an_cmd(sc, AN_CMD_ENABLE, 0);
1482 	an_cmd(sc, AN_CMD_FW_RESTART, 0);
1483 	an_cmd(sc, AN_CMD_NOOP2, 0);
1484 
1485 	if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0) == ETIMEDOUT)
1486 		printf("%s: reset failed\n", sc->an_dev.dv_xname);
1487 
1488 	an_cmd(sc, AN_CMD_DISABLE, 0);
1489 }
1490 
1491 /*
1492  * Wait for firmware come up after power enabled.
1493  */
1494 static void
1495 an_wait(struct an_softc *sc)
1496 {
1497 	int i;
1498 
1499 	CSR_WRITE_2(sc, AN_COMMAND, AN_CMD_NOOP2);
1500 	for (i = 0; i < 3*hz; i++) {
1501 		if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_CMD)
1502 			break;
1503 		(void)tsleep(sc, PWAIT, "anatch", 1);
1504 	}
1505 	CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD);
1506 }
1507 
1508 /*
1509  * Read an LTV record from the NIC.
1510  */
1511 static int
1512 an_read_record(struct an_softc *sc, struct an_ltv_gen *ltv)
1513 {
1514 	u_int16_t *ptr;
1515 	int i, len;
1516 
1517 	if (ltv->an_len == 0 || ltv->an_type == 0)
1518 		return EINVAL;
1519 
1520 	/* Tell the NIC to enter record read mode. */
1521 	if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type))
1522 		return EIO;
1523 
1524 	/* Seek to the record. */
1525 	if (an_seek(sc, ltv->an_type, 0, AN_BAP1))
1526 		return EIO;
1527 
1528 	/*
1529 	 * Read the length and record type and make sure they
1530 	 * match what we expect (this verifies that we have enough
1531 	 * room to hold all of the returned data).
1532 	 */
1533 	len = CSR_READ_2(sc, AN_DATA1);
1534 	if (len > ltv->an_len) {
1535 		if (sc->arpcom.ec_if.if_flags & IFF_DEBUG)
1536 			printf("%s: RID 0x%04x record length mismatch"
1537 			    "-- expected %d, got %d\n", sc->an_dev.dv_xname,
1538 			    ltv->an_type, ltv->an_len, len);
1539 		return ENOSPC;
1540 	}
1541 
1542 	ltv->an_len = len;
1543 
1544 	/* Now read the data. */
1545 	ptr = &ltv->an_val;
1546 	for (i = 0; i < (ltv->an_len - 2) >> 1; i++)
1547 		ptr[i] = CSR_READ_2(sc, AN_DATA1);
1548 
1549 	return 0;
1550 }
1551 
1552 /*
1553  * Same as read, except we inject data instead of reading it.
1554  */
1555 static int
1556 an_write_record(struct an_softc *sc, struct an_ltv_gen *ltv)
1557 {
1558 	u_int16_t *ptr;
1559 	int i;
1560 
1561 	if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type))
1562 		return EIO;
1563 
1564 	if (an_seek(sc, ltv->an_type, 0, AN_BAP1))
1565 		return EIO;
1566 
1567 	CSR_WRITE_2(sc, AN_DATA1, ltv->an_len-2);
1568 
1569 	ptr = &ltv->an_val;
1570 	for (i = 0; i < (ltv->an_len - 4) >> 1; i++)
1571 		CSR_WRITE_2(sc, AN_DATA1, ptr[i]);
1572 
1573 	if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_WRITE, ltv->an_type))
1574 		return EIO;
1575 
1576 	return 0;
1577 }
1578 
1579 static int
1580 an_seek(struct an_softc *sc, int id, int off, int chan)
1581 {
1582 	int i, selreg, offreg;
1583 
1584 	switch (chan) {
1585 	case AN_BAP0:
1586 		selreg = AN_SEL0;
1587 		offreg = AN_OFF0;
1588 		break;
1589 	case AN_BAP1:
1590 		selreg = AN_SEL1;
1591 		offreg = AN_OFF1;
1592 		break;
1593 	default:
1594 		panic("%s: invalid chan: %x", sc->an_dev.dv_xname, chan);
1595 	}
1596 
1597 	CSR_WRITE_2(sc, selreg, id);
1598 	CSR_WRITE_2(sc, offreg, off);
1599 
1600 	for (i = 0; i < AN_TIMEOUT; i++) {
1601 		if (!(CSR_READ_2(sc, offreg) & (AN_OFF_BUSY|AN_OFF_ERR)))
1602 			break;
1603 		DELAY(10);
1604 	}
1605 	if (i == AN_TIMEOUT) {
1606 		if (sc->arpcom.ec_if.if_flags & IFF_DEBUG)
1607 			printf("%s: seek(0x%x, 0x%x, 0x%x) timeout\n",
1608 			    sc->an_dev.dv_xname, id, off, chan);
1609 		return ETIMEDOUT;
1610 	}
1611 
1612 	return 0;
1613 }
1614 
1615 static int
1616 an_read_data(struct an_softc *sc, int id, int off, caddr_t buf, int len)
1617 {
1618 	int i;
1619 	u_int16_t *ptr;
1620 	u_int8_t *ptr2;
1621 
1622 	if (off != -1) {
1623 		if (an_seek(sc, id, off, AN_BAP1))
1624 			return EIO;
1625 	}
1626 
1627 	ptr = (u_int16_t *)buf;
1628 	for (i = 0; i < len / 2; i++)
1629 		ptr[i] = CSR_READ_2(sc, AN_DATA1);
1630 	i *= 2;
1631 	if (i < len){
1632 	        ptr2 = (u_int8_t *)buf;
1633 	        ptr2[i] = CSR_READ_1(sc, AN_DATA1);
1634 	}
1635 
1636 	return 0;
1637 }
1638 
1639 static int
1640 an_write_data(struct an_softc *sc, int id, int off, caddr_t buf, int len)
1641 {
1642 	int i;
1643 	u_int16_t *ptr;
1644 	u_int8_t *ptr2;
1645 
1646 	if (off != -1) {
1647 		if (an_seek(sc, id, off, AN_BAP0))
1648 			return EIO;
1649 	}
1650 
1651 	ptr = (u_int16_t *)buf;
1652 	for (i = 0; i < (len / 2); i++)
1653 		CSR_WRITE_2(sc, AN_DATA0, ptr[i]);
1654 	i *= 2;
1655 	if (i < len){
1656 	        ptr2 = (u_int8_t *)buf;
1657 	        CSR_WRITE_1(sc, AN_DATA0, ptr2[i]);
1658 	}
1659 
1660 	return 0;
1661 }
1662 
1663 /*
1664  * Allocate a region of memory inside the NIC and zero
1665  * it out.
1666  */
1667 static int
1668 an_alloc_nicmem(struct an_softc *sc, int len, int *id)
1669 {
1670 	int			i;
1671 
1672 	if (an_cmd(sc, AN_CMD_ALLOC_MEM, len)) {
1673 		printf("%s: failed to allocate %d bytes on NIC\n",
1674 		    sc->an_dev.dv_xname, len);
1675 		return ENOMEM;
1676 	}
1677 
1678 	for (i = 0; i < AN_TIMEOUT; i++) {
1679 		if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_ALLOC)
1680 			break;
1681 		DELAY(10);
1682 	}
1683 
1684 	if (i == AN_TIMEOUT)
1685 		return(ETIMEDOUT);
1686 
1687 	CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_ALLOC);
1688 	*id = CSR_READ_2(sc, AN_ALLOC_FID);
1689 
1690 	if (an_seek(sc, *id, 0, AN_BAP0))
1691 		return EIO;
1692 
1693 	for (i = 0; i < len / 2; i++)
1694 		CSR_WRITE_2(sc, AN_DATA0, 0);
1695 
1696 	return 0;
1697 }
1698 
1699 #ifdef ANCACHE
1700 /* Aironet signal strength cache code.
1701  * store signal/noise/quality on per MAC src basis in
1702  * a small fixed cache.  The cache wraps if > MAX slots
1703  * used.  The cache may be zeroed out to start over.
1704  * Two simple filters exist to reduce computation:
1705  * 1. ip only (literally 0x800) which may be used
1706  * to ignore some packets.  It defaults to ip only.
1707  * it could be used to focus on broadcast, non-IP 802.11 beacons.
1708  * 2. multicast/broadcast only.  This may be used to
1709  * ignore unicast packets and only cache signal strength
1710  * for multicast/broadcast packets (beacons); e.g., Mobile-IP
1711  * beacons and not unicast traffic.
1712  *
1713  * The cache stores (MAC src(index), IP src (major clue), signal,
1714  *	quality, noise)
1715  *
1716  * No apologies for storing IP src here.  It's easy and saves much
1717  * trouble elsewhere.  The cache is assumed to be INET dependent,
1718  * although it need not be.
1719  *
1720  * Note: the Aironet only has a single byte of signal strength value
1721  * in the rx frame header, and it's not scaled to anything sensible.
1722  * This is kind of lame, but it's all we've got.
1723  */
1724 
1725 #ifdef documentation
1726 
1727 int an_sigitems;                                /* number of cached entries */
1728 struct an_sigcache an_sigcache[MAXANCACHE];  /*  array of cache entries */
1729 int an_nextitem;                                /*  index/# of entries */
1730 
1731 
1732 #endif
1733 
1734 /* control variables for cache filtering.  Basic idea is
1735  * to reduce cost (e.g., to only Mobile-IP agent beacons
1736  * which are broadcast or multicast).  Still you might
1737  * want to measure signal strength anth unicast ping packets
1738  * on a pt. to pt. ant. setup.
1739  */
1740 /* set true if you want to limit cache items to broadcast/mcast
1741  * only packets (not unicast).  Useful for mobile-ip beacons which
1742  * are broadcast/multicast at network layer.  Default is all packets
1743  * so ping/unicast anll work say anth pt. to pt. antennae setup.
1744  */
1745 static int an_cache_mcastonly = 0;
1746 #if 0
1747 SYSCTL_INT(_machdep, OID_AUTO, an_cache_mcastonly, CTLFLAG_RW,
1748 	&an_cache_mcastonly, 0, "");
1749 #endif
1750 
1751 /* set true if you want to limit cache items to IP packets only
1752 */
1753 static int an_cache_iponly = 1;
1754 #if 0
1755 SYSCTL_INT(_machdep, OID_AUTO, an_cache_iponly, CTLFLAG_RW,
1756 	&an_cache_iponly, 0, "");
1757 #endif
1758 
1759 /*
1760  * an_cache_store, per rx packet store signal
1761  * strength in MAC (src) indexed cache.
1762  */
1763 static
1764 void an_cache_store (sc, eh, m, rx_quality)
1765 	struct an_softc *sc;
1766 	struct ether_header *eh;
1767 	struct mbuf *m;
1768 	unsigned short rx_quality;
1769 {
1770 	struct ip *ip = 0;
1771 	int i;
1772 	static int cache_slot = 0; 	/* use this cache entry */
1773 	static int wrapindex = 0;       /* next "free" cache entry */
1774 	int saanp=0;
1775 
1776 	/* filters:
1777 	 * 1. ip only
1778 	 * 2. configurable filter to throw out unicast packets,
1779 	 * keep multicast only.
1780 	 */
1781 
1782 	if ((ntohs(eh->ether_type) == 0x800)) {
1783 		saanp = 1;
1784 	}
1785 
1786 	/* filter for ip packets only
1787 	*/
1788 	if (an_cache_iponly && !saanp) {
1789 		return;
1790 	}
1791 
1792 	/* filter for broadcast/multicast only
1793 	 */
1794 	if (an_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
1795 		return;
1796 	}
1797 
1798 #ifdef SIGDEBUG
1799 	printf("an: q value %x (MSB=0x%x, LSB=0x%x) \n",
1800 	    rx_quality & 0xffff, rx_quality >> 8, rx_quality & 0xff);
1801 #endif
1802 
1803 	/* find the ip header.  we want to store the ip_src
1804 	 * address.
1805 	 */
1806 	if (saanp) {
1807 		ip = (struct ip *)(mtod(m, caddr_t) + 14);
1808 	}
1809 
1810 	/* do a linear search for a matching MAC address
1811 	 * in the cache table
1812 	 * . MAC address is 6 bytes,
1813 	 * . var w_nextitem holds total number of entries already cached
1814 	 */
1815 	for(i = 0; i < sc->an_nextitem; i++) {
1816 		if (!memcmp(eh->ether_shost , sc->an_sigcache[i].macsrc,  6 )) {
1817 			/* Match!,
1818 			 * so we already have this entry,
1819 			 * update the data
1820 			 */
1821 			break;
1822 		}
1823 	}
1824 
1825 	/* did we find a matching mac address?
1826 	 * if yes, then overwrite a previously existing cache entry
1827 	 */
1828 	if (i < sc->an_nextitem )   {
1829 		cache_slot = i;
1830 	}
1831 	/* else, have a new address entry,so
1832 	 * add this new entry,
1833 	 * if table full, then we need to replace LRU entry
1834 	 */
1835 	else    {
1836 
1837 		/* check for space in cache table
1838 		 * note: an_nextitem also holds number of entries
1839 		 * added in the cache table
1840 		 */
1841 		if (sc->an_nextitem < MAXANCACHE ) {
1842 			cache_slot = sc->an_nextitem;
1843 			sc->an_nextitem++;
1844 			sc->an_sigitems = sc->an_nextitem;
1845 		}
1846         	/* no space found, so simply wrap anth wrap index
1847 		 * and "zap" the next entry
1848 		 */
1849 		else {
1850 			if (wrapindex == MAXANCACHE) {
1851 				wrapindex = 0;
1852 			}
1853 			cache_slot = wrapindex++;
1854 		}
1855 	}
1856 
1857 	/* invariant: cache_slot now points at some slot
1858 	 * in cache.
1859 	 */
1860 	if (cache_slot < 0 || cache_slot >= MAXANCACHE) {
1861 		log(LOG_ERR, "an_cache_store, bad index: %d of "
1862 		    "[0..%d], gross cache error\n",
1863 		    cache_slot, MAXANCACHE);
1864 		return;
1865 	}
1866 
1867 	/*  store items in cache
1868 	 *  .ip source address
1869 	 *  .mac src
1870 	 *  .signal, etc.
1871 	 */
1872 	if (saanp) {
1873 		sc->an_sigcache[cache_slot].ipsrc = ip->ip_src.s_addr;
1874 	}
1875 	memcpy(sc->an_sigcache[cache_slot].macsrc, eh->ether_shost, 6);
1876 
1877 	sc->an_sigcache[cache_slot].signal = rx_quality;
1878 
1879 	return;
1880 }
1881 #endif
1882