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