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