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