if_an.c revision 91283
155992Swpaul/*
255992Swpaul * Copyright (c) 1997, 1998, 1999
355992Swpaul *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
455992Swpaul *
555992Swpaul * Redistribution and use in source and binary forms, with or without
655992Swpaul * modification, are permitted provided that the following conditions
755992Swpaul * are met:
855992Swpaul * 1. Redistributions of source code must retain the above copyright
955992Swpaul *    notice, this list of conditions and the following disclaimer.
1055992Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1155992Swpaul *    notice, this list of conditions and the following disclaimer in the
1255992Swpaul *    documentation and/or other materials provided with the distribution.
1355992Swpaul * 3. All advertising materials mentioning features or use of this software
1455992Swpaul *    must display the following acknowledgement:
1555992Swpaul *	This product includes software developed by Bill Paul.
1655992Swpaul * 4. Neither the name of the author nor the names of any co-contributors
1755992Swpaul *    may be used to endorse or promote products derived from this software
1855992Swpaul *    without specific prior written permission.
1955992Swpaul *
2055992Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2155992Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2255992Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2355992Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
2455992Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2555992Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2655992Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2755992Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2855992Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2955992Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
3055992Swpaul * THE POSSIBILITY OF SUCH DAMAGE.
3155992Swpaul *
3255992Swpaul * $FreeBSD: head/sys/dev/an/if_an.c 91283 2002-02-26 05:43:05Z ambrisko $
3355992Swpaul */
3455992Swpaul
3555992Swpaul/*
3655992Swpaul * Aironet 4500/4800 802.11 PCMCIA/ISA/PCI driver for FreeBSD.
3755992Swpaul *
3855992Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu>
3955992Swpaul * Electrical Engineering Department
4055992Swpaul * Columbia University, New York City
4155992Swpaul */
4255992Swpaul
4355992Swpaul/*
4486259Sphk * The Aironet 4500/4800 series cards come in PCMCIA, ISA and PCI form.
4555992Swpaul * This driver supports all three device types (PCI devices are supported
4655992Swpaul * through an extra PCI shim: /sys/pci/if_an_p.c). ISA devices can be
4755992Swpaul * supported either using hard-coded IO port/IRQ settings or via Plug
4855992Swpaul * and Play. The 4500 series devices support 1Mbps and 2Mbps data rates.
4955992Swpaul * The 4800 devices support 1, 2, 5.5 and 11Mbps rates.
5055992Swpaul *
5155992Swpaul * Like the WaveLAN/IEEE cards, the Aironet NICs are all essentially
5255992Swpaul * PCMCIA devices. The ISA and PCI cards are a combination of a PCMCIA
5355992Swpaul * device and a PCMCIA to ISA or PCMCIA to PCI adapter card. There are
5455992Swpaul * a couple of important differences though:
5555992Swpaul *
5655992Swpaul * - Lucent ISA card looks to the host like a PCMCIA controller with
5755992Swpaul *   a PCMCIA WaveLAN card inserted. This means that even desktop
5855992Swpaul *   machines need to be configured with PCMCIA support in order to
5955992Swpaul *   use WaveLAN/IEEE ISA cards. The Aironet cards on the other hand
6055992Swpaul *   actually look like normal ISA and PCI devices to the host, so
6155992Swpaul *   no PCMCIA controller support is needed
6255992Swpaul *
6355992Swpaul * The latter point results in a small gotcha. The Aironet PCMCIA
6455992Swpaul * cards can be configured for one of two operating modes depending
6555992Swpaul * on how the Vpp1 and Vpp2 programming voltages are set when the
6655992Swpaul * card is activated. In order to put the card in proper PCMCIA
6755992Swpaul * operation (where the CIS table is visible and the interface is
6855992Swpaul * programmed for PCMCIA operation), both Vpp1 and Vpp2 have to be
6955992Swpaul * set to 5 volts. FreeBSD by default doesn't set the Vpp voltages,
7055992Swpaul * which leaves the card in ISA/PCI mode, which prevents it from
7186381Simp * being activated as an PCMCIA device.
7255992Swpaul *
7355992Swpaul * Note that some PCMCIA controller software packages for Windows NT
7455992Swpaul * fail to set the voltages as well.
7583270Sbrooks *
7655992Swpaul * The Aironet devices can operate in both station mode and access point
7755992Swpaul * mode. Typically, when programmed for station mode, the card can be set
7855992Swpaul * to automatically perform encapsulation/decapsulation of Ethernet II
7955992Swpaul * and 802.3 frames within 802.11 frames so that the host doesn't have
8055992Swpaul * to do it itself. This driver doesn't program the card that way: the
8155992Swpaul * driver handles all of the encapsulation/decapsulation itself.
8255992Swpaul */
8355992Swpaul
8455992Swpaul#include "opt_inet.h"
8555992Swpaul
8655992Swpaul#ifdef INET
8755992Swpaul#define ANCACHE			/* enable signal strength cache */
8855992Swpaul#endif
8955992Swpaul
9055992Swpaul#include <sys/param.h>
9155992Swpaul#include <sys/systm.h>
9255992Swpaul#include <sys/sockio.h>
9355992Swpaul#include <sys/mbuf.h>
9483366Sjulian#include <sys/proc.h>
9555992Swpaul#include <sys/kernel.h>
9655992Swpaul#include <sys/socket.h>
9755992Swpaul#ifdef ANCACHE
9855992Swpaul#include <sys/syslog.h>
9955992Swpaul#include <sys/sysctl.h>
10055992Swpaul#endif
10155992Swpaul
10255992Swpaul#include <sys/module.h>
10383269Sbrooks#include <sys/sysctl.h>
10455992Swpaul#include <sys/bus.h>
10555992Swpaul#include <machine/bus.h>
10655992Swpaul#include <sys/rman.h>
10784811Sjhb#include <sys/lock.h>
10867365Sjhb#include <sys/mutex.h>
10955992Swpaul#include <machine/resource.h>
11055992Swpaul
11155992Swpaul#include <net/if.h>
11255992Swpaul#include <net/if_arp.h>
11355992Swpaul#include <net/ethernet.h>
11455992Swpaul#include <net/if_dl.h>
11555992Swpaul#include <net/if_types.h>
11677217Sphk#include <net/if_ieee80211.h>
11777217Sphk#include <net/if_media.h>
11855992Swpaul
11955992Swpaul#ifdef INET
12055992Swpaul#include <netinet/in.h>
12155992Swpaul#include <netinet/in_systm.h>
12255992Swpaul#include <netinet/in_var.h>
12355992Swpaul#include <netinet/ip.h>
12455992Swpaul#endif
12555992Swpaul
12655992Swpaul#include <net/bpf.h>
12755992Swpaul
12855992Swpaul#include <machine/md_var.h>
12955992Swpaul
13055992Swpaul#include <dev/an/if_aironet_ieee.h>
13155992Swpaul#include <dev/an/if_anreg.h>
13255992Swpaul
13355992Swpaul#if !defined(lint)
13455992Swpaulstatic const char rcsid[] =
13555992Swpaul  "$FreeBSD: head/sys/dev/an/if_an.c 91283 2002-02-26 05:43:05Z ambrisko $";
13655992Swpaul#endif
13755992Swpaul
13855992Swpaul/* These are global because we need them in sys/pci/if_an_p.c. */
13955992Swpaulstatic void an_reset		__P((struct an_softc *));
14055992Swpaulstatic int an_ioctl		__P((struct ifnet *, u_long, caddr_t));
14155992Swpaulstatic void an_init		__P((void *));
14255992Swpaulstatic int an_init_tx_ring	__P((struct an_softc *));
14355992Swpaulstatic void an_start		__P((struct ifnet *));
14455992Swpaulstatic void an_watchdog		__P((struct ifnet *));
14555992Swpaulstatic void an_rxeof		__P((struct an_softc *));
14655992Swpaulstatic void an_txeof		__P((struct an_softc *, int));
14755992Swpaul
14855992Swpaulstatic void an_promisc		__P((struct an_softc *, int));
14955992Swpaulstatic int an_cmd		__P((struct an_softc *, int, int));
15055992Swpaulstatic int an_read_record	__P((struct an_softc *, struct an_ltv_gen *));
15155992Swpaulstatic int an_write_record	__P((struct an_softc *, struct an_ltv_gen *));
15255992Swpaulstatic int an_read_data		__P((struct an_softc *, int,
15355992Swpaul					int, caddr_t, int));
15455992Swpaulstatic int an_write_data	__P((struct an_softc *, int,
15555992Swpaul					int, caddr_t, int));
15655992Swpaulstatic int an_seek		__P((struct an_softc *, int, int, int));
15755992Swpaulstatic int an_alloc_nicmem	__P((struct an_softc *, int, int *));
15855992Swpaulstatic void an_stats_update	__P((void *));
15955992Swpaulstatic void an_setdef		__P((struct an_softc *, struct an_req *));
16055992Swpaul#ifdef ANCACHE
16155992Swpaulstatic void an_cache_store	__P((struct an_softc *, struct ether_header *,
16255992Swpaul					struct mbuf *, unsigned short));
16355992Swpaul#endif
16455992Swpaul
16588748Sambrisko/* function definitions for use with the Cisco's Linux configuration
16688748Sambrisko   utilities
16788748Sambrisko*/
16888748Sambrisko
16988748Sambriskostatic int readrids             __P((struct ifnet*, struct aironet_ioctl*));
17088748Sambriskostatic int writerids            __P((struct ifnet*, struct aironet_ioctl*));
17188748Sambriskostatic int flashcard            __P((struct ifnet*, struct aironet_ioctl*));
17288748Sambrisko
17388748Sambriskostatic int cmdreset             __P((struct ifnet *));
17488748Sambriskostatic int setflashmode         __P((struct ifnet *));
17588748Sambriskostatic int flashgchar           __P((struct ifnet *,int,int));
17688748Sambriskostatic int flashpchar           __P((struct ifnet *,int,int));
17788748Sambriskostatic int flashputbuf          __P((struct ifnet *));
17888748Sambriskostatic int flashrestart         __P((struct ifnet *));
17988748Sambriskostatic int WaitBusy             __P((struct ifnet *, int));
18088748Sambriskostatic int unstickbusy          __P((struct ifnet *));
18188748Sambrisko
18278639Sbrooksstatic void an_dump_record	__P((struct an_softc *,struct an_ltv_gen *,
18378639Sbrooks				    char *));
18478639Sbrooks
18577217Sphkstatic int an_media_change	__P((struct ifnet *));
18677217Sphkstatic void an_media_status	__P((struct ifnet *, struct ifmediareq *));
18777217Sphk
18878639Sbrooksstatic int	an_dump = 0;
18988748Sambrisko
19083269Sbrooksstatic char an_conf[256];
19183269Sbrooks
19283269Sbrooks/* sysctl vars */
19383269SbrooksSYSCTL_NODE(_machdep, OID_AUTO, an, CTLFLAG_RD, 0, "dump RID");
19483269Sbrooks
19583269Sbrooksstatic int
19683269Sbrookssysctl_an_dump(SYSCTL_HANDLER_ARGS)
19783269Sbrooks{
19883269Sbrooks	int	error, r, last;
19983269Sbrooks	char 	*s = an_conf;
20083270Sbrooks
20183269Sbrooks	last = an_dump;
20283269Sbrooks	bzero(an_conf, sizeof(an_conf));
20383269Sbrooks
20483270Sbrooks	switch (an_dump) {
20583269Sbrooks	case 0:
20683269Sbrooks		strcat(an_conf, "off");
20783269Sbrooks		break;
20883269Sbrooks	case 1:
20983269Sbrooks		strcat(an_conf, "type");
21083269Sbrooks		break;
21183269Sbrooks	case 2:
21283269Sbrooks		strcat(an_conf, "dump");
21383269Sbrooks		break;
21483269Sbrooks	default:
21583269Sbrooks		snprintf(an_conf, 5, "%x", an_dump);
21683269Sbrooks		break;
21783269Sbrooks	}
21883269Sbrooks
21983269Sbrooks	error = sysctl_handle_string(oidp, an_conf, sizeof(an_conf), req);
22083269Sbrooks
22183270Sbrooks	if (strncmp(an_conf,"off", 4) == 0) {
22283269Sbrooks		an_dump = 0;
22383269Sbrooks 	}
22483270Sbrooks	if (strncmp(an_conf,"dump", 4) == 0) {
22583269Sbrooks		an_dump = 1;
22683269Sbrooks	}
22783270Sbrooks	if (strncmp(an_conf,"type", 4) == 0) {
22883269Sbrooks		an_dump = 2;
22983269Sbrooks	}
23083270Sbrooks	if (*s == 'f') {
23183269Sbrooks		r = 0;
23283270Sbrooks		for (;;s++) {
23383270Sbrooks			if ((*s >= '0') && (*s <= '9')) {
23483269Sbrooks				r = r * 16 + (*s - '0');
23583270Sbrooks			} else if ((*s >= 'a') && (*s <= 'f')) {
23683269Sbrooks				r = r * 16 + (*s - 'a' + 10);
23783270Sbrooks			} else {
23883270Sbrooks				break;
23983269Sbrooks			}
24083269Sbrooks		}
24183269Sbrooks		an_dump = r;
24283269Sbrooks	}
24383269Sbrooks	if (an_dump != last)
24483269Sbrooks		printf("Sysctl changed for Aironet driver\n");
24583269Sbrooks
24683269Sbrooks	return error;
24783269Sbrooks}
24883269Sbrooks
24983269SbrooksSYSCTL_PROC(_machdep, OID_AUTO, an_dump, CTLTYPE_STRING | CTLFLAG_RW,
25083269Sbrooks            0, sizeof(an_conf), sysctl_an_dump, "A", "");
25183269Sbrooks
25283270Sbrooks/*
25355992Swpaul * We probe for an Aironet 4500/4800 card by attempting to
25455992Swpaul * read the default SSID list. On reset, the first entry in
25555992Swpaul * the SSID list will contain the name "tsunami." If we don't
25655992Swpaul * find this, then there's no card present.
25755992Swpaul */
25883270Sbrooksint
25983270Sbrooksan_probe(dev)
26055992Swpaul	device_t		dev;
26155992Swpaul{
26255992Swpaul        struct an_softc *sc = device_get_softc(dev);
26355992Swpaul	struct an_ltv_ssidlist	ssid;
26455992Swpaul	int	error;
26555992Swpaul
26655992Swpaul	bzero((char *)&ssid, sizeof(ssid));
26755992Swpaul
26855992Swpaul	error = an_alloc_port(dev, 0, AN_IOSIZ);
26978639Sbrooks	if (error != 0)
27055992Swpaul		return (0);
27155992Swpaul
27255992Swpaul	/* can't do autoprobing */
27355992Swpaul	if (rman_get_start(sc->port_res) == -1)
27455992Swpaul		return(0);
27555992Swpaul
27655992Swpaul	/*
27755992Swpaul	 * We need to fake up a softc structure long enough
27855992Swpaul	 * to be able to issue commands and call some of the
27955992Swpaul	 * other routines.
28055992Swpaul	 */
28156094Swpaul	sc->an_bhandle = rman_get_bushandle(sc->port_res);
28255992Swpaul	sc->an_btag = rman_get_bustag(sc->port_res);
28355992Swpaul	sc->an_unit = device_get_unit(dev);
28455992Swpaul
28555992Swpaul	ssid.an_len = sizeof(ssid);
28655992Swpaul	ssid.an_type = AN_RID_SSIDLIST;
28755992Swpaul
28855992Swpaul        /* Make sure interrupts are disabled. */
28955992Swpaul        CSR_WRITE_2(sc, AN_INT_EN, 0);
29055992Swpaul        CSR_WRITE_2(sc, AN_EVENT_ACK, 0xFFFF);
29155992Swpaul
29255992Swpaul	an_reset(sc);
29355992Swpaul
29455992Swpaul	if (an_cmd(sc, AN_CMD_READCFG, 0))
29555992Swpaul		return(0);
29655992Swpaul
29755992Swpaul	if (an_read_record(sc, (struct an_ltv_gen *)&ssid))
29855992Swpaul		return(0);
29955992Swpaul
30068692Swpaul	/* See if the ssid matches what we expect ... but doesn't have to */
30155992Swpaul	if (strcmp(ssid.an_ssid1, AN_DEF_SSID))
30255992Swpaul		return(0);
30383270Sbrooks
30455992Swpaul	return(AN_IOSIZ);
30555992Swpaul}
30655992Swpaul
30755992Swpaul/*
30855992Swpaul * Allocate a port resource with the given resource id.
30955992Swpaul */
31055992Swpaulint
31155992Swpaulan_alloc_port(dev, rid, size)
31255992Swpaul	device_t dev;
31355992Swpaul	int rid;
31455992Swpaul	int size;
31555992Swpaul{
31655992Swpaul	struct an_softc *sc = device_get_softc(dev);
31755992Swpaul	struct resource *res;
31855992Swpaul
31955992Swpaul	res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
32055992Swpaul				 0ul, ~0ul, size, RF_ACTIVE);
32155992Swpaul	if (res) {
32255992Swpaul		sc->port_rid = rid;
32355992Swpaul		sc->port_res = res;
32455992Swpaul		return (0);
32555992Swpaul	} else {
32655992Swpaul		return (ENOENT);
32755992Swpaul	}
32855992Swpaul}
32955992Swpaul
33055992Swpaul/*
33155992Swpaul * Allocate an irq resource with the given resource id.
33255992Swpaul */
33355992Swpaulint
33455992Swpaulan_alloc_irq(dev, rid, flags)
33555992Swpaul	device_t dev;
33655992Swpaul	int rid;
33755992Swpaul	int flags;
33855992Swpaul{
33955992Swpaul	struct an_softc *sc = device_get_softc(dev);
34055992Swpaul	struct resource *res;
34155992Swpaul
34255992Swpaul	res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
34355992Swpaul				 0ul, ~0ul, 1, (RF_ACTIVE | flags));
34455992Swpaul	if (res) {
34555992Swpaul		sc->irq_rid = rid;
34655992Swpaul		sc->irq_res = res;
34755992Swpaul		return (0);
34855992Swpaul	} else {
34955992Swpaul		return (ENOENT);
35055992Swpaul	}
35155992Swpaul}
35255992Swpaul
35355992Swpaul/*
35455992Swpaul * Release all resources
35555992Swpaul */
35655992Swpaulvoid
35755992Swpaulan_release_resources(dev)
35855992Swpaul	device_t dev;
35955992Swpaul{
36055992Swpaul	struct an_softc *sc = device_get_softc(dev);
36155992Swpaul
36255992Swpaul	if (sc->port_res) {
36355992Swpaul		bus_release_resource(dev, SYS_RES_IOPORT,
36455992Swpaul				     sc->port_rid, sc->port_res);
36555992Swpaul		sc->port_res = 0;
36655992Swpaul	}
36755992Swpaul	if (sc->irq_res) {
36855992Swpaul		bus_release_resource(dev, SYS_RES_IRQ,
36955992Swpaul				     sc->irq_rid, sc->irq_res);
37055992Swpaul		sc->irq_res = 0;
37155992Swpaul	}
37255992Swpaul}
37355992Swpaul
37483270Sbrooksint
37583270Sbrooksan_attach(sc, unit, flags)
37655992Swpaul	struct an_softc *sc;
37755992Swpaul	int unit;
37855992Swpaul	int flags;
37955992Swpaul{
38055992Swpaul	struct ifnet		*ifp = &sc->arpcom.ac_if;
38155992Swpaul
38271228Sbmilekic	mtx_init(&sc->an_mtx, device_get_nameunit(sc->an_dev), MTX_DEF |
38371228Sbmilekic	    MTX_RECURSE);
38467094Swpaul	AN_LOCK(sc);
38567094Swpaul
38655992Swpaul	sc->an_gone = 0;
38755992Swpaul	sc->an_associated = 0;
38883269Sbrooks	sc->an_monitor = 0;
38983269Sbrooks	sc->an_was_monitor = 0;
39055992Swpaul
39155992Swpaul	/* Reset the NIC. */
39255992Swpaul	an_reset(sc);
39355992Swpaul
39455992Swpaul	/* Load factory config */
39555992Swpaul	if (an_cmd(sc, AN_CMD_READCFG, 0)) {
39655992Swpaul		printf("an%d: failed to load config data\n", sc->an_unit);
39767094Swpaul		AN_UNLOCK(sc);
39867094Swpaul		mtx_destroy(&sc->an_mtx);
39955992Swpaul		return(EIO);
40055992Swpaul	}
40155992Swpaul
40255992Swpaul	/* Read the current configuration */
40355992Swpaul	sc->an_config.an_type = AN_RID_GENCONFIG;
40455992Swpaul	sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
40555992Swpaul	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_config)) {
40655992Swpaul		printf("an%d: read record failed\n", sc->an_unit);
40767094Swpaul		AN_UNLOCK(sc);
40867094Swpaul		mtx_destroy(&sc->an_mtx);
40955992Swpaul		return(EIO);
41055992Swpaul	}
41155992Swpaul
41255992Swpaul	/* Read the card capabilities */
41355992Swpaul	sc->an_caps.an_type = AN_RID_CAPABILITIES;
41455992Swpaul	sc->an_caps.an_len = sizeof(struct an_ltv_caps);
41555992Swpaul	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_caps)) {
41655992Swpaul		printf("an%d: read record failed\n", sc->an_unit);
41767094Swpaul		AN_UNLOCK(sc);
41867094Swpaul		mtx_destroy(&sc->an_mtx);
41955992Swpaul		return(EIO);
42055992Swpaul	}
42155992Swpaul
42255992Swpaul	/* Read ssid list */
42355992Swpaul	sc->an_ssidlist.an_type = AN_RID_SSIDLIST;
42455992Swpaul	sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist);
42555992Swpaul	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) {
42655992Swpaul		printf("an%d: read record failed\n", sc->an_unit);
42767094Swpaul		AN_UNLOCK(sc);
42867094Swpaul		mtx_destroy(&sc->an_mtx);
42955992Swpaul		return(EIO);
43055992Swpaul	}
43155992Swpaul
43255992Swpaul	/* Read AP list */
43355992Swpaul	sc->an_aplist.an_type = AN_RID_APLIST;
43455992Swpaul	sc->an_aplist.an_len = sizeof(struct an_ltv_aplist);
43555992Swpaul	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) {
43655992Swpaul		printf("an%d: read record failed\n", sc->an_unit);
43767094Swpaul		AN_UNLOCK(sc);
43867094Swpaul		mtx_destroy(&sc->an_mtx);
43955992Swpaul		return(EIO);
44055992Swpaul	}
44155992Swpaul
44255992Swpaul	bcopy((char *)&sc->an_caps.an_oemaddr,
44355992Swpaul	   (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
44455992Swpaul
44555992Swpaul	printf("an%d: Ethernet address: %6D\n", sc->an_unit,
44655992Swpaul	    sc->arpcom.ac_enaddr, ":");
44755992Swpaul
44855992Swpaul	ifp->if_softc = sc;
44955992Swpaul	ifp->if_unit = sc->an_unit = unit;
45055992Swpaul	ifp->if_name = "an";
45155992Swpaul	ifp->if_mtu = ETHERMTU;
45255992Swpaul	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
45355992Swpaul	ifp->if_ioctl = an_ioctl;
45455992Swpaul	ifp->if_output = ether_output;
45555992Swpaul	ifp->if_start = an_start;
45655992Swpaul	ifp->if_watchdog = an_watchdog;
45755992Swpaul	ifp->if_init = an_init;
45855992Swpaul	ifp->if_baudrate = 10000000;
45955992Swpaul	ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
46055992Swpaul
46155992Swpaul	bzero(sc->an_config.an_nodename, sizeof(sc->an_config.an_nodename));
46255992Swpaul	bcopy(AN_DEFAULT_NODENAME, sc->an_config.an_nodename,
46355992Swpaul	    sizeof(AN_DEFAULT_NODENAME) - 1);
46455992Swpaul
46555992Swpaul	bzero(sc->an_ssidlist.an_ssid1, sizeof(sc->an_ssidlist.an_ssid1));
46655992Swpaul	bcopy(AN_DEFAULT_NETNAME, sc->an_ssidlist.an_ssid1,
46755992Swpaul	    sizeof(AN_DEFAULT_NETNAME) - 1);
46855992Swpaul	sc->an_ssidlist.an_ssid1_len = strlen(AN_DEFAULT_NETNAME);
46955992Swpaul
47055992Swpaul	sc->an_config.an_opmode =
47174144Sassar	    AN_OPMODE_INFRASTRUCTURE_STATION;
47255992Swpaul
47355992Swpaul	sc->an_tx_rate = 0;
47455992Swpaul	bzero((char *)&sc->an_stats, sizeof(sc->an_stats));
47555992Swpaul
47677217Sphk	ifmedia_init(&sc->an_ifmedia, 0, an_media_change, an_media_status);
47777217Sphk#define	ADD(m, c)	ifmedia_add(&sc->an_ifmedia, (m), (c), NULL)
47877217Sphk	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
47977217Sphk	    IFM_IEEE80211_ADHOC, 0), 0);
48077217Sphk	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 0, 0), 0);
48177217Sphk	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
48277217Sphk	    IFM_IEEE80211_ADHOC, 0), 0);
48377217Sphk	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 0, 0), 0);
48478639Sbrooks	if (sc->an_caps.an_rates[2] == AN_RATE_5_5MBPS) {
48577217Sphk		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
48677217Sphk		    IFM_IEEE80211_ADHOC, 0), 0);
48777217Sphk		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 0, 0), 0);
48877217Sphk	}
48978639Sbrooks	if (sc->an_caps.an_rates[3] == AN_RATE_11MBPS) {
49077217Sphk		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
49177217Sphk		    IFM_IEEE80211_ADHOC, 0), 0);
49277217Sphk		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 0, 0), 0);
49377217Sphk	}
49477217Sphk	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
49577217Sphk	    IFM_IEEE80211_ADHOC, 0), 0);
49677217Sphk	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0), 0);
49777217Sphk#undef	ADD
49877217Sphk	ifmedia_set(&sc->an_ifmedia, IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
49977217Sphk	    0, 0));
50077217Sphk
50155992Swpaul	/*
50263090Sarchie	 * Call MI attach routine.
50355992Swpaul	 */
50463090Sarchie	ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
50555992Swpaul	callout_handle_init(&sc->an_stat_ch);
50667094Swpaul	AN_UNLOCK(sc);
50755992Swpaul
50855992Swpaul	return(0);
50955992Swpaul}
51055992Swpaul
51183270Sbrooksstatic void
51283269Sbrooksan_rxeof(sc)
51383269Sbrooks	struct an_softc *sc;
51455992Swpaul{
51583269Sbrooks	struct ifnet   *ifp;
51683269Sbrooks	struct ether_header *eh;
51783269Sbrooks	struct ieee80211_frame *ih;
51883269Sbrooks	struct an_rxframe rx_frame;
51983269Sbrooks	struct an_rxframe_802_3 rx_frame_802_3;
52083269Sbrooks	struct mbuf    *m;
52183269Sbrooks	int             len, id, error = 0;
52283269Sbrooks	int             ieee80211_header_len;
52383269Sbrooks	u_char          *bpf_buf;
52483269Sbrooks	u_short         fc1;
52555992Swpaul
52655992Swpaul	ifp = &sc->arpcom.ac_if;
52755992Swpaul
52855992Swpaul	id = CSR_READ_2(sc, AN_RX_FID);
52955992Swpaul
53083269Sbrooks	if (sc->an_monitor && (ifp->if_flags & IFF_PROMISC)) {
53183269Sbrooks		/* read raw 802.11 packet */
53283269Sbrooks	        bpf_buf = sc->buf_802_11;
53355992Swpaul
53483269Sbrooks		/* read header */
53583269Sbrooks		if (an_read_data(sc, id, 0x0, (caddr_t)&rx_frame,
53683269Sbrooks				 sizeof(rx_frame))) {
53783269Sbrooks			ifp->if_ierrors++;
53883269Sbrooks			return;
53983269Sbrooks		}
54055992Swpaul
54183270Sbrooks		/*
54283270Sbrooks		 * skip beacon by default since this increases the
54383269Sbrooks		 * system load a lot
54483269Sbrooks		 */
54583270Sbrooks
54683270Sbrooks		if (!(sc->an_monitor & AN_MONITOR_INCLUDE_BEACON) &&
54783270Sbrooks		    (rx_frame.an_frame_ctl & IEEE80211_FC0_SUBTYPE_BEACON)) {
54883269Sbrooks			return;
54983269Sbrooks		}
55055992Swpaul
55183270Sbrooks		if (sc->an_monitor & AN_MONITOR_AIRONET_HEADER) {
55283270Sbrooks			len = rx_frame.an_rx_payload_len
55383269Sbrooks				+ sizeof(rx_frame);
55483269Sbrooks			/* Check for insane frame length */
55583269Sbrooks			if (len > sizeof(sc->buf_802_11)) {
55683269Sbrooks				printf("an%d: oversized packet received (%d, %d)\n",
55783269Sbrooks				       sc->an_unit, len, MCLBYTES);
55883269Sbrooks				ifp->if_ierrors++;
55983269Sbrooks				return;
56083269Sbrooks			}
56155992Swpaul
56283269Sbrooks			bcopy((char *)&rx_frame,
56383269Sbrooks			      bpf_buf, sizeof(rx_frame));
56455992Swpaul
56583269Sbrooks			error = an_read_data(sc, id, sizeof(rx_frame),
56683269Sbrooks					     (caddr_t)bpf_buf+sizeof(rx_frame),
56783269Sbrooks					     rx_frame.an_rx_payload_len);
56883270Sbrooks		} else {
56983269Sbrooks			fc1=rx_frame.an_frame_ctl >> 8;
57083269Sbrooks			ieee80211_header_len = sizeof(struct ieee80211_frame);
57183269Sbrooks			if ((fc1 & IEEE80211_FC1_DIR_TODS) &&
57283269Sbrooks			    (fc1 & IEEE80211_FC1_DIR_FROMDS)) {
57383269Sbrooks				ieee80211_header_len += ETHER_ADDR_LEN;
57483269Sbrooks			}
57555992Swpaul
57683270Sbrooks			len = rx_frame.an_rx_payload_len
57783269Sbrooks				+ ieee80211_header_len;
57883269Sbrooks			/* Check for insane frame length */
57983269Sbrooks			if (len > sizeof(sc->buf_802_11)) {
58083269Sbrooks				printf("an%d: oversized packet received (%d, %d)\n",
58183269Sbrooks				       sc->an_unit, len, MCLBYTES);
58283269Sbrooks				ifp->if_ierrors++;
58383269Sbrooks				return;
58483269Sbrooks			}
58555992Swpaul
58683269Sbrooks			ih = (struct ieee80211_frame *)bpf_buf;
58755992Swpaul
58883269Sbrooks			bcopy((char *)&rx_frame.an_frame_ctl,
58983269Sbrooks			      (char *)ih, ieee80211_header_len);
59055992Swpaul
59183270Sbrooks			error = an_read_data(sc, id, sizeof(rx_frame) +
59283269Sbrooks					     rx_frame.an_gaplen,
59383269Sbrooks					     (caddr_t)ih +ieee80211_header_len,
59483269Sbrooks					     rx_frame.an_rx_payload_len);
59583269Sbrooks		}
59683269Sbrooks		/* dump raw 802.11 packet to bpf and skip ip stack */
59783269Sbrooks		if (ifp->if_bpf != NULL) {
59883269Sbrooks			bpf_tap(ifp, bpf_buf, len);
59983269Sbrooks		}
60083269Sbrooks	} else {
60183269Sbrooks		MGETHDR(m, M_DONTWAIT, MT_DATA);
60283269Sbrooks		if (m == NULL) {
60383269Sbrooks			ifp->if_ierrors++;
60483269Sbrooks			return;
60583269Sbrooks		}
60683269Sbrooks		MCLGET(m, M_DONTWAIT);
60783269Sbrooks		if (!(m->m_flags & M_EXT)) {
60883269Sbrooks			m_freem(m);
60983269Sbrooks			ifp->if_ierrors++;
61083269Sbrooks			return;
61183269Sbrooks		}
61283269Sbrooks		m->m_pkthdr.rcvif = ifp;
61388748Sambrisko		/* Read Ethernet encapsulated packet */
61455992Swpaul
61583269Sbrooks#ifdef ANCACHE
61683269Sbrooks		/* Read NIC frame header */
61783269Sbrooks		if (an_read_data(sc, id, 0, (caddr_t) & rx_frame, sizeof(rx_frame))) {
61883269Sbrooks			ifp->if_ierrors++;
61983269Sbrooks			return;
62083269Sbrooks		}
62183269Sbrooks#endif
62283269Sbrooks		/* Read in the 802_3 frame header */
62383269Sbrooks		if (an_read_data(sc, id, 0x34, (caddr_t) & rx_frame_802_3,
62483269Sbrooks				 sizeof(rx_frame_802_3))) {
62583269Sbrooks			ifp->if_ierrors++;
62683269Sbrooks			return;
62783269Sbrooks		}
62883269Sbrooks		if (rx_frame_802_3.an_rx_802_3_status != 0) {
62983269Sbrooks			ifp->if_ierrors++;
63083269Sbrooks			return;
63183269Sbrooks		}
63283269Sbrooks		/* Check for insane frame length */
63383269Sbrooks		if (rx_frame_802_3.an_rx_802_3_payload_len > MCLBYTES) {
63483269Sbrooks			ifp->if_ierrors++;
63583269Sbrooks			return;
63683269Sbrooks		}
63783269Sbrooks		m->m_pkthdr.len = m->m_len =
63883269Sbrooks			rx_frame_802_3.an_rx_802_3_payload_len + 12;
63955992Swpaul
64083269Sbrooks		eh = mtod(m, struct ether_header *);
64183269Sbrooks
64283269Sbrooks		bcopy((char *)&rx_frame_802_3.an_rx_dst_addr,
64383269Sbrooks		      (char *)&eh->ether_dhost, ETHER_ADDR_LEN);
64483269Sbrooks		bcopy((char *)&rx_frame_802_3.an_rx_src_addr,
64583269Sbrooks		      (char *)&eh->ether_shost, ETHER_ADDR_LEN);
64683269Sbrooks
64783269Sbrooks		/* in mbuf header type is just before payload */
64883269Sbrooks		error = an_read_data(sc, id, 0x44, (caddr_t)&(eh->ether_type),
64983269Sbrooks				     rx_frame_802_3.an_rx_802_3_payload_len);
65083269Sbrooks
65183269Sbrooks		if (error) {
65283269Sbrooks			m_freem(m);
65383269Sbrooks			ifp->if_ierrors++;
65483269Sbrooks			return;
65583269Sbrooks		}
65683269Sbrooks		ifp->if_ipackets++;
65783269Sbrooks
65883269Sbrooks		/* Receive packet. */
65983269Sbrooks		m_adj(m, sizeof(struct ether_header));
66055992Swpaul#ifdef ANCACHE
66183269Sbrooks		an_cache_store(sc, eh, m, rx_frame.an_rx_signal_strength);
66255992Swpaul#endif
66383269Sbrooks		ether_input(ifp, eh, m);
66483269Sbrooks	}
66555992Swpaul}
66655992Swpaul
66783270Sbrooksstatic void
66883270Sbrooksan_txeof(sc, status)
66955992Swpaul	struct an_softc		*sc;
67055992Swpaul	int			status;
67155992Swpaul{
67255992Swpaul	struct ifnet		*ifp;
67378639Sbrooks	int			id, i;
67455992Swpaul
67555992Swpaul	ifp = &sc->arpcom.ac_if;
67655992Swpaul
67755992Swpaul	ifp->if_timer = 0;
67855992Swpaul	ifp->if_flags &= ~IFF_OACTIVE;
67955992Swpaul
68055992Swpaul	id = CSR_READ_2(sc, AN_TX_CMP_FID);
68155992Swpaul
68255992Swpaul	if (status & AN_EV_TX_EXC) {
68355992Swpaul		ifp->if_oerrors++;
68455992Swpaul	} else
68555992Swpaul		ifp->if_opackets++;
68655992Swpaul
68778639Sbrooks	for (i = 0; i < AN_TX_RING_CNT; i++) {
68878639Sbrooks		if (id == sc->an_rdata.an_tx_ring[i]) {
68978639Sbrooks			sc->an_rdata.an_tx_ring[i] = 0;
69078639Sbrooks			break;
69178639Sbrooks		}
69278639Sbrooks	}
69355992Swpaul
69455992Swpaul	AN_INC(sc->an_rdata.an_tx_cons, AN_TX_RING_CNT);
69555992Swpaul
69655992Swpaul	return;
69755992Swpaul}
69855992Swpaul
69955992Swpaul/*
70055992Swpaul * We abuse the stats updater to check the current NIC status. This
70155992Swpaul * is important because we don't want to allow transmissions until
70255992Swpaul * the NIC has synchronized to the current cell (either as the master
70355992Swpaul * in an ad-hoc group, or as a station connected to an access point).
70455992Swpaul */
70583270Sbrooksvoid
70683270Sbrooksan_stats_update(xsc)
70755992Swpaul	void			*xsc;
70855992Swpaul{
70955992Swpaul	struct an_softc		*sc;
71055992Swpaul	struct ifnet		*ifp;
71155992Swpaul
71255992Swpaul	sc = xsc;
71367094Swpaul	AN_LOCK(sc);
71455992Swpaul	ifp = &sc->arpcom.ac_if;
71555992Swpaul
71655992Swpaul	sc->an_status.an_type = AN_RID_STATUS;
71755992Swpaul	sc->an_status.an_len = sizeof(struct an_ltv_status);
71855992Swpaul	an_read_record(sc, (struct an_ltv_gen *)&sc->an_status);
71955992Swpaul
72055992Swpaul	if (sc->an_status.an_opmode & AN_STATUS_OPMODE_IN_SYNC)
72155992Swpaul		sc->an_associated = 1;
72255992Swpaul	else
72355992Swpaul		sc->an_associated = 0;
72455992Swpaul
72555992Swpaul	/* Don't do this while we're transmitting */
72655992Swpaul	if (ifp->if_flags & IFF_OACTIVE) {
72755992Swpaul		sc->an_stat_ch = timeout(an_stats_update, sc, hz);
72867094Swpaul		AN_UNLOCK(sc);
72955992Swpaul		return;
73055992Swpaul	}
73155992Swpaul
73255992Swpaul	sc->an_stats.an_len = sizeof(struct an_ltv_stats);
73355992Swpaul	sc->an_stats.an_type = AN_RID_32BITS_CUM;
73455992Swpaul	an_read_record(sc, (struct an_ltv_gen *)&sc->an_stats.an_len);
73555992Swpaul
73655992Swpaul	sc->an_stat_ch = timeout(an_stats_update, sc, hz);
73767094Swpaul	AN_UNLOCK(sc);
73855992Swpaul
73955992Swpaul	return;
74055992Swpaul}
74155992Swpaul
74283270Sbrooksvoid
74383270Sbrooksan_intr(xsc)
74455992Swpaul	void			*xsc;
74555992Swpaul{
74655992Swpaul	struct an_softc		*sc;
74755992Swpaul	struct ifnet		*ifp;
74855992Swpaul	u_int16_t		status;
74955992Swpaul
75055992Swpaul	sc = (struct an_softc*)xsc;
75155992Swpaul
75267094Swpaul	AN_LOCK(sc);
75367094Swpaul
75467094Swpaul	if (sc->an_gone) {
75567094Swpaul		AN_UNLOCK(sc);
75655992Swpaul		return;
75767094Swpaul	}
75855992Swpaul
75955992Swpaul	ifp = &sc->arpcom.ac_if;
76055992Swpaul
76155992Swpaul	/* Disable interrupts. */
76255992Swpaul	CSR_WRITE_2(sc, AN_INT_EN, 0);
76355992Swpaul
76455992Swpaul	status = CSR_READ_2(sc, AN_EVENT_STAT);
76555992Swpaul	CSR_WRITE_2(sc, AN_EVENT_ACK, ~AN_INTRS);
76655992Swpaul
76755992Swpaul	if (status & AN_EV_AWAKE) {
76855992Swpaul		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_AWAKE);
76955992Swpaul	}
77055992Swpaul
77155992Swpaul	if (status & AN_EV_LINKSTAT) {
77255992Swpaul		if (CSR_READ_2(sc, AN_LINKSTAT) == AN_LINKSTAT_ASSOCIATED)
77355992Swpaul			sc->an_associated = 1;
77455992Swpaul		else
77555992Swpaul			sc->an_associated = 0;
77655992Swpaul		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_LINKSTAT);
77755992Swpaul	}
77855992Swpaul
77955992Swpaul	if (status & AN_EV_RX) {
78055992Swpaul		an_rxeof(sc);
78155992Swpaul		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
78255992Swpaul	}
78355992Swpaul
78455992Swpaul	if (status & AN_EV_TX) {
78555992Swpaul		an_txeof(sc, status);
78655992Swpaul		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_TX);
78755992Swpaul	}
78855992Swpaul
78955992Swpaul	if (status & AN_EV_TX_EXC) {
79055992Swpaul		an_txeof(sc, status);
79155992Swpaul		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_TX_EXC);
79255992Swpaul	}
79355992Swpaul
79455992Swpaul	if (status & AN_EV_ALLOC)
79555992Swpaul		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_ALLOC);
79655992Swpaul
79755992Swpaul	/* Re-enable interrupts. */
79855992Swpaul	CSR_WRITE_2(sc, AN_INT_EN, AN_INTRS);
79955992Swpaul
80074698Sarchie	if ((ifp->if_flags & IFF_UP) && (ifp->if_snd.ifq_head != NULL))
80155992Swpaul		an_start(ifp);
80255992Swpaul
80367094Swpaul	AN_UNLOCK(sc);
80467094Swpaul
80555992Swpaul	return;
80655992Swpaul}
80755992Swpaul
80883270Sbrooksstatic int
80983270Sbrooksan_cmd(sc, cmd, val)
81055992Swpaul	struct an_softc		*sc;
81155992Swpaul	int			cmd;
81255992Swpaul	int			val;
81355992Swpaul{
81455992Swpaul	int			i, s = 0;
81555992Swpaul
81655992Swpaul	CSR_WRITE_2(sc, AN_PARAM0, val);
81755992Swpaul	CSR_WRITE_2(sc, AN_PARAM1, 0);
81855992Swpaul	CSR_WRITE_2(sc, AN_PARAM2, 0);
81955992Swpaul	CSR_WRITE_2(sc, AN_COMMAND, cmd);
82055992Swpaul
82155992Swpaul	for (i = 0; i < AN_TIMEOUT; i++) {
82255992Swpaul		if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_CMD)
82355992Swpaul			break;
82455992Swpaul		else {
82555992Swpaul			if (CSR_READ_2(sc, AN_COMMAND) == cmd)
82655992Swpaul				CSR_WRITE_2(sc, AN_COMMAND, cmd);
82755992Swpaul		}
82855992Swpaul	}
82955992Swpaul
83055992Swpaul	for (i = 0; i < AN_TIMEOUT; i++) {
83155992Swpaul		CSR_READ_2(sc, AN_RESP0);
83255992Swpaul		CSR_READ_2(sc, AN_RESP1);
83355992Swpaul		CSR_READ_2(sc, AN_RESP2);
83455992Swpaul		s = CSR_READ_2(sc, AN_STATUS);
83555992Swpaul		if ((s & AN_STAT_CMD_CODE) == (cmd & AN_STAT_CMD_CODE))
83655992Swpaul			break;
83755992Swpaul	}
83855992Swpaul
83955992Swpaul	/* Ack the command */
84055992Swpaul	CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD);
84155992Swpaul
84255992Swpaul	if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY)
84355992Swpaul		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY);
84455992Swpaul
84555992Swpaul	if (i == AN_TIMEOUT)
84655992Swpaul		return(ETIMEDOUT);
84755992Swpaul
84855992Swpaul	return(0);
84955992Swpaul}
85055992Swpaul
85155992Swpaul/*
85255992Swpaul * This reset sequence may look a little strange, but this is the
85355992Swpaul * most reliable method I've found to really kick the NIC in the
85455992Swpaul * head and force it to reboot correctly.
85555992Swpaul */
85683270Sbrooksstatic void
85783270Sbrooksan_reset(sc)
85855992Swpaul	struct an_softc		*sc;
85955992Swpaul{
86055992Swpaul	if (sc->an_gone)
86155992Swpaul		return;
86283270Sbrooks
86355992Swpaul	an_cmd(sc, AN_CMD_ENABLE, 0);
86455992Swpaul	an_cmd(sc, AN_CMD_FW_RESTART, 0);
86555992Swpaul	an_cmd(sc, AN_CMD_NOOP2, 0);
86655992Swpaul
86755992Swpaul	if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0) == ETIMEDOUT)
86855992Swpaul		printf("an%d: reset failed\n", sc->an_unit);
86955992Swpaul
87055992Swpaul	an_cmd(sc, AN_CMD_DISABLE, 0);
87155992Swpaul
87255992Swpaul	return;
87355992Swpaul}
87455992Swpaul
87555992Swpaul/*
87655992Swpaul * Read an LTV record from the NIC.
87755992Swpaul */
87883270Sbrooksstatic int
87983270Sbrooksan_read_record(sc, ltv)
88055992Swpaul	struct an_softc		*sc;
88155992Swpaul	struct an_ltv_gen	*ltv;
88255992Swpaul{
88355992Swpaul	u_int16_t		*ptr;
88478639Sbrooks	u_int8_t		*ptr2;
88555992Swpaul	int			i, len;
88655992Swpaul
88778639Sbrooks	if (ltv->an_len < 4 || ltv->an_type == 0)
88855992Swpaul		return(EINVAL);
88955992Swpaul
89055992Swpaul	/* Tell the NIC to enter record read mode. */
89155992Swpaul	if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) {
89255992Swpaul		printf("an%d: RID access failed\n", sc->an_unit);
89355992Swpaul		return(EIO);
89455992Swpaul	}
89555992Swpaul
89655992Swpaul	/* Seek to the record. */
89755992Swpaul	if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) {
89855992Swpaul		printf("an%d: seek to record failed\n", sc->an_unit);
89955992Swpaul		return(EIO);
90055992Swpaul	}
90155992Swpaul
90255992Swpaul	/*
90355992Swpaul	 * Read the length and record type and make sure they
90455992Swpaul	 * match what we expect (this verifies that we have enough
90555992Swpaul	 * room to hold all of the returned data).
90678639Sbrooks	 * Length includes type but not length.
90755992Swpaul	 */
90855992Swpaul	len = CSR_READ_2(sc, AN_DATA1);
90977217Sphk	if (len > (ltv->an_len - 2)) {
91055992Swpaul		printf("an%d: record length mismatch -- expected %d, "
91178639Sbrooks		    "got %d for Rid %x\n", sc->an_unit,
91278639Sbrooks		    ltv->an_len - 2, len, ltv->an_type);
91378639Sbrooks		len = ltv->an_len - 2;
91478639Sbrooks	} else {
91578639Sbrooks		ltv->an_len = len + 2;
91655992Swpaul	}
91755992Swpaul
91855992Swpaul	/* Now read the data. */
91978639Sbrooks	len -= 2;	/* skip the type */
92055992Swpaul	ptr = &ltv->an_val;
92178639Sbrooks	for (i = len; i > 1; i -= 2)
92278639Sbrooks		*ptr++ = CSR_READ_2(sc, AN_DATA1);
92378639Sbrooks	if (i) {
92478639Sbrooks		ptr2 = (u_int8_t *)ptr;
92578639Sbrooks		*ptr2 = CSR_READ_1(sc, AN_DATA1);
92678639Sbrooks	}
92778639Sbrooks	if (an_dump)
92878639Sbrooks		an_dump_record(sc, ltv, "Read");
92955992Swpaul
93055992Swpaul	return(0);
93155992Swpaul}
93255992Swpaul
93355992Swpaul/*
93455992Swpaul * Same as read, except we inject data instead of reading it.
93555992Swpaul */
93683270Sbrooksstatic int
93783270Sbrooksan_write_record(sc, ltv)
93855992Swpaul	struct an_softc		*sc;
93955992Swpaul	struct an_ltv_gen	*ltv;
94055992Swpaul{
94155992Swpaul	u_int16_t		*ptr;
94278639Sbrooks	u_int8_t		*ptr2;
94378639Sbrooks	int			i, len;
94455992Swpaul
94578639Sbrooks	if (an_dump)
94678639Sbrooks		an_dump_record(sc, ltv, "Write");
94778639Sbrooks
94855992Swpaul	if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type))
94955992Swpaul		return(EIO);
95083270Sbrooks
95155992Swpaul	if (an_seek(sc, ltv->an_type, 0, AN_BAP1))
95255992Swpaul		return(EIO);
95355992Swpaul
95478639Sbrooks	/*
95578639Sbrooks	 * Length includes type but not length.
95678639Sbrooks	 */
95778639Sbrooks	len = ltv->an_len - 2;
95878639Sbrooks	CSR_WRITE_2(sc, AN_DATA1, len);
95983270Sbrooks
96078639Sbrooks	len -= 2;	/* skip the type */
96155992Swpaul	ptr = &ltv->an_val;
96278639Sbrooks	for (i = len; i > 1; i -= 2)
96378639Sbrooks		CSR_WRITE_2(sc, AN_DATA1, *ptr++);
96478639Sbrooks	if (i) {
96578639Sbrooks		ptr2 = (u_int8_t *)ptr;
96678639Sbrooks		CSR_WRITE_1(sc, AN_DATA0, *ptr2);
96778639Sbrooks	}
96855992Swpaul
96955992Swpaul	if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_WRITE, ltv->an_type))
97055992Swpaul		return(EIO);
97155992Swpaul
97255992Swpaul	return(0);
97355992Swpaul}
97455992Swpaul
97583270Sbrooksstatic void
97683270Sbrooksan_dump_record(sc, ltv, string)
97778639Sbrooks	struct an_softc		*sc;
97878639Sbrooks	struct an_ltv_gen	*ltv;
97978639Sbrooks	char			*string;
98078639Sbrooks{
98178639Sbrooks	u_int8_t		*ptr2;
98278639Sbrooks	int			len;
98378639Sbrooks	int			i;
98478639Sbrooks	int			count = 0;
98578639Sbrooks	char			buf[17], temp;
98678639Sbrooks
98778639Sbrooks	len = ltv->an_len - 4;
98883270Sbrooks	printf("an%d: RID %4x, Length %4d, Mode %s\n",
98978639Sbrooks		sc->an_unit, ltv->an_type, ltv->an_len - 4, string);
99078639Sbrooks
99178639Sbrooks	if (an_dump == 1 || (an_dump == ltv->an_type)) {
99278639Sbrooks		printf("an%d:\t", sc->an_unit);
99378639Sbrooks		bzero(buf,sizeof(buf));
99478639Sbrooks
99578639Sbrooks		ptr2 = (u_int8_t *)&ltv->an_val;
99678639Sbrooks		for (i = len; i > 0; i--) {
99778639Sbrooks			printf("%02x ", *ptr2);
99878639Sbrooks
99978639Sbrooks			temp = *ptr2++;
100078639Sbrooks			if (temp >= ' ' && temp <= '~')
100178639Sbrooks				buf[count] = temp;
100278639Sbrooks			else if (temp >= 'A' && temp <= 'Z')
100378639Sbrooks				buf[count] = temp;
100478639Sbrooks			else
100578639Sbrooks				buf[count] = '.';
100678639Sbrooks			if (++count == 16) {
100778639Sbrooks				count = 0;
100878639Sbrooks				printf("%s\n",buf);
100978639Sbrooks				printf("an%d:\t", sc->an_unit);
101078639Sbrooks				bzero(buf,sizeof(buf));
101178639Sbrooks			}
101278639Sbrooks		}
101378639Sbrooks		for (; count != 16; count++) {
101478639Sbrooks			printf("   ");
101578639Sbrooks		}
101678639Sbrooks		printf(" %s\n",buf);
101778639Sbrooks	}
101878639Sbrooks}
101978639Sbrooks
102083270Sbrooksstatic int
102183270Sbrooksan_seek(sc, id, off, chan)
102255992Swpaul	struct an_softc		*sc;
102355992Swpaul	int			id, off, chan;
102455992Swpaul{
102555992Swpaul	int			i;
102655992Swpaul	int			selreg, offreg;
102755992Swpaul
102855992Swpaul	switch (chan) {
102955992Swpaul	case AN_BAP0:
103055992Swpaul		selreg = AN_SEL0;
103155992Swpaul		offreg = AN_OFF0;
103255992Swpaul		break;
103355992Swpaul	case AN_BAP1:
103455992Swpaul		selreg = AN_SEL1;
103555992Swpaul		offreg = AN_OFF1;
103655992Swpaul		break;
103755992Swpaul	default:
103855992Swpaul		printf("an%d: invalid data path: %x\n", sc->an_unit, chan);
103955992Swpaul		return(EIO);
104055992Swpaul	}
104155992Swpaul
104255992Swpaul	CSR_WRITE_2(sc, selreg, id);
104355992Swpaul	CSR_WRITE_2(sc, offreg, off);
104455992Swpaul
104555992Swpaul	for (i = 0; i < AN_TIMEOUT; i++) {
104655992Swpaul		if (!(CSR_READ_2(sc, offreg) & (AN_OFF_BUSY|AN_OFF_ERR)))
104755992Swpaul			break;
104855992Swpaul	}
104955992Swpaul
105055992Swpaul	if (i == AN_TIMEOUT)
105155992Swpaul		return(ETIMEDOUT);
105255992Swpaul
105355992Swpaul	return(0);
105455992Swpaul}
105555992Swpaul
105683270Sbrooksstatic int
105783270Sbrooksan_read_data(sc, id, off, buf, len)
105855992Swpaul	struct an_softc		*sc;
105955992Swpaul	int			id, off;
106055992Swpaul	caddr_t			buf;
106155992Swpaul	int			len;
106255992Swpaul{
106355992Swpaul	int			i;
106455992Swpaul	u_int16_t		*ptr;
106555992Swpaul	u_int8_t		*ptr2;
106655992Swpaul
106755992Swpaul	if (off != -1) {
106855992Swpaul		if (an_seek(sc, id, off, AN_BAP1))
106955992Swpaul			return(EIO);
107055992Swpaul	}
107155992Swpaul
107255992Swpaul	ptr = (u_int16_t *)buf;
107378639Sbrooks	for (i = len; i > 1; i -= 2)
107478639Sbrooks		*ptr++ = CSR_READ_2(sc, AN_DATA1);
107578639Sbrooks	if (i) {
107678639Sbrooks		ptr2 = (u_int8_t *)ptr;
107778639Sbrooks		*ptr2 = CSR_READ_1(sc, AN_DATA1);
107855992Swpaul	}
107955992Swpaul
108055992Swpaul	return(0);
108155992Swpaul}
108255992Swpaul
108383270Sbrooksstatic int
108483270Sbrooksan_write_data(sc, id, off, buf, len)
108555992Swpaul	struct an_softc		*sc;
108655992Swpaul	int			id, off;
108755992Swpaul	caddr_t			buf;
108855992Swpaul	int			len;
108955992Swpaul{
109055992Swpaul	int			i;
109155992Swpaul	u_int16_t		*ptr;
109255992Swpaul	u_int8_t		*ptr2;
109355992Swpaul
109455992Swpaul	if (off != -1) {
109555992Swpaul		if (an_seek(sc, id, off, AN_BAP0))
109655992Swpaul			return(EIO);
109755992Swpaul	}
109855992Swpaul
109955992Swpaul	ptr = (u_int16_t *)buf;
110078639Sbrooks	for (i = len; i > 1; i -= 2)
110178639Sbrooks		CSR_WRITE_2(sc, AN_DATA0, *ptr++);
110278639Sbrooks	if (i) {
110378639Sbrooks	        ptr2 = (u_int8_t *)ptr;
110478639Sbrooks	        CSR_WRITE_1(sc, AN_DATA0, *ptr2);
110555992Swpaul	}
110655992Swpaul
110755992Swpaul	return(0);
110855992Swpaul}
110955992Swpaul
111055992Swpaul/*
111155992Swpaul * Allocate a region of memory inside the NIC and zero
111255992Swpaul * it out.
111355992Swpaul */
111483270Sbrooksstatic int
111583270Sbrooksan_alloc_nicmem(sc, len, id)
111655992Swpaul	struct an_softc		*sc;
111755992Swpaul	int			len;
111855992Swpaul	int			*id;
111955992Swpaul{
112055992Swpaul	int			i;
112155992Swpaul
112255992Swpaul	if (an_cmd(sc, AN_CMD_ALLOC_MEM, len)) {
112355992Swpaul		printf("an%d: failed to allocate %d bytes on NIC\n",
112455992Swpaul		    sc->an_unit, len);
112555992Swpaul		return(ENOMEM);
112655992Swpaul	}
112755992Swpaul
112855992Swpaul	for (i = 0; i < AN_TIMEOUT; i++) {
112955992Swpaul		if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_ALLOC)
113055992Swpaul			break;
113155992Swpaul	}
113255992Swpaul
113355992Swpaul	if (i == AN_TIMEOUT)
113455992Swpaul		return(ETIMEDOUT);
113555992Swpaul
113655992Swpaul	CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_ALLOC);
113755992Swpaul	*id = CSR_READ_2(sc, AN_ALLOC_FID);
113855992Swpaul
113955992Swpaul	if (an_seek(sc, *id, 0, AN_BAP0))
114055992Swpaul		return(EIO);
114155992Swpaul
114255992Swpaul	for (i = 0; i < len / 2; i++)
114355992Swpaul		CSR_WRITE_2(sc, AN_DATA0, 0);
114455992Swpaul
114555992Swpaul	return(0);
114655992Swpaul}
114755992Swpaul
114883270Sbrooksstatic void
114983270Sbrooksan_setdef(sc, areq)
115055992Swpaul	struct an_softc		*sc;
115155992Swpaul	struct an_req		*areq;
115255992Swpaul{
115355992Swpaul	struct sockaddr_dl	*sdl;
115455992Swpaul	struct ifaddr		*ifa;
115555992Swpaul	struct ifnet		*ifp;
115655992Swpaul	struct an_ltv_genconfig	*cfg;
115755992Swpaul	struct an_ltv_ssidlist	*ssid;
115855992Swpaul	struct an_ltv_aplist	*ap;
115955992Swpaul	struct an_ltv_gen	*sp;
116055992Swpaul
116155992Swpaul	ifp = &sc->arpcom.ac_if;
116255992Swpaul
116355992Swpaul	switch (areq->an_type) {
116455992Swpaul	case AN_RID_GENCONFIG:
116555992Swpaul		cfg = (struct an_ltv_genconfig *)areq;
116655992Swpaul
116783130Sjlemon		ifa = ifaddr_byindex(ifp->if_index);
116855992Swpaul		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
116955992Swpaul		bcopy((char *)&cfg->an_macaddr, (char *)&sc->arpcom.ac_enaddr,
117055992Swpaul		    ETHER_ADDR_LEN);
117155992Swpaul		bcopy((char *)&cfg->an_macaddr, LLADDR(sdl), ETHER_ADDR_LEN);
117255992Swpaul
117355992Swpaul		bcopy((char *)cfg, (char *)&sc->an_config,
117455992Swpaul			sizeof(struct an_ltv_genconfig));
117555992Swpaul		break;
117655992Swpaul	case AN_RID_SSIDLIST:
117755992Swpaul		ssid = (struct an_ltv_ssidlist *)areq;
117855992Swpaul		bcopy((char *)ssid, (char *)&sc->an_ssidlist,
117955992Swpaul			sizeof(struct an_ltv_ssidlist));
118055992Swpaul		break;
118155992Swpaul	case AN_RID_APLIST:
118255992Swpaul		ap = (struct an_ltv_aplist *)areq;
118355992Swpaul		bcopy((char *)ap, (char *)&sc->an_aplist,
118455992Swpaul			sizeof(struct an_ltv_aplist));
118555992Swpaul		break;
118655992Swpaul	case AN_RID_TX_SPEED:
118755992Swpaul		sp = (struct an_ltv_gen *)areq;
118855992Swpaul		sc->an_tx_rate = sp->an_val;
118955992Swpaul		break;
119068692Swpaul	case AN_RID_WEP_TEMP:
119168692Swpaul	case AN_RID_WEP_PERM:
119288748Sambrisko	case AN_RID_LEAPUSERNAME:
119388748Sambrisko	case AN_RID_LEAPPASSWORD:
119468692Swpaul		/* Disable the MAC. */
119568692Swpaul		an_cmd(sc, AN_CMD_DISABLE, 0);
119683270Sbrooks
119783269Sbrooks		/* Write the key */
119868692Swpaul		an_write_record(sc, (struct an_ltv_gen *)areq);
119983270Sbrooks
120083270Sbrooks		/* Turn the MAC back on. */
120168692Swpaul		an_cmd(sc, AN_CMD_ENABLE, 0);
120283270Sbrooks
120368692Swpaul		break;
120483269Sbrooks	case AN_RID_MONITOR_MODE:
120583269Sbrooks		cfg = (struct an_ltv_genconfig *)areq;
120683269Sbrooks		bpfdetach(ifp);
120783269Sbrooks		if (ng_ether_detach_p != NULL)
120883269Sbrooks			(*ng_ether_detach_p) (ifp);
120983269Sbrooks		sc->an_monitor = cfg->an_len;
121083269Sbrooks
121183270Sbrooks		if (sc->an_monitor & AN_MONITOR) {
121283270Sbrooks			if (sc->an_monitor & AN_MONITOR_AIRONET_HEADER) {
121383270Sbrooks				bpfattach(ifp, DLT_AIRONET_HEADER,
121483269Sbrooks					sizeof(struct ether_header));
121583269Sbrooks			} else {
121683270Sbrooks				bpfattach(ifp, DLT_IEEE802_11,
121783269Sbrooks					sizeof(struct ether_header));
121883269Sbrooks			}
121983269Sbrooks		} else {
122083270Sbrooks			bpfattach(ifp, DLT_EN10MB,
122183269Sbrooks				  sizeof(struct ether_header));
122283269Sbrooks			if (ng_ether_attach_p != NULL)
122383269Sbrooks				(*ng_ether_attach_p) (ifp);
122483269Sbrooks		}
122583269Sbrooks		break;
122655992Swpaul	default:
122755992Swpaul		printf("an%d: unknown RID: %x\n", sc->an_unit, areq->an_type);
122855992Swpaul		return;
122955992Swpaul		break;
123055992Swpaul	}
123155992Swpaul
123255992Swpaul
123355992Swpaul	/* Reinitialize the card. */
123474698Sarchie	if (ifp->if_flags)
123555992Swpaul		an_init(sc);
123655992Swpaul
123755992Swpaul	return;
123855992Swpaul}
123955992Swpaul
124055992Swpaul/*
124183269Sbrooks * Derived from Linux driver to enable promiscious mode.
124255992Swpaul */
124383269Sbrooks
124483270Sbrooksstatic void
124583270Sbrooksan_promisc(sc, promisc)
124655992Swpaul	struct an_softc		*sc;
124755992Swpaul	int			promisc;
124855992Swpaul{
124983270Sbrooks	if (sc->an_was_monitor)
125083269Sbrooks		an_reset(sc);
125183270Sbrooks	if (sc->an_monitor || sc->an_was_monitor)
125283269Sbrooks		an_init(sc);
125383269Sbrooks
125483269Sbrooks	sc->an_was_monitor = sc->an_monitor;
125574698Sarchie	an_cmd(sc, AN_CMD_SET_MODE, promisc ? 0xffff : 0);
125683270Sbrooks
125755992Swpaul	return;
125855992Swpaul}
125955992Swpaul
126083270Sbrooksstatic int
126183270Sbrooksan_ioctl(ifp, command, data)
126255992Swpaul	struct ifnet		*ifp;
126355992Swpaul	u_long			command;
126455992Swpaul	caddr_t			data;
126555992Swpaul{
126667094Swpaul	int			error = 0;
126777217Sphk	int			len;
126877217Sphk	int			i;
126955992Swpaul	struct an_softc		*sc;
127055992Swpaul	struct ifreq		*ifr;
127161816Sroberto	struct proc		*p = curproc;
127277217Sphk	struct ieee80211req	*ireq;
127377217Sphk	u_int8_t		tmpstr[IEEE80211_NWID_LEN*2];
127477217Sphk	u_int8_t		*tmpptr;
127577217Sphk	struct an_ltv_genconfig	*config;
127677217Sphk	struct an_ltv_key	*key;
127777217Sphk	struct an_ltv_status	*status;
127877217Sphk	struct an_ltv_ssidlist	*ssids;
127988748Sambrisko	int			mode;
128088748Sambrisko	struct aironet_ioctl	l_ioctl;
128155992Swpaul
128255992Swpaul	sc = ifp->if_softc;
128367094Swpaul	AN_LOCK(sc);
128455992Swpaul	ifr = (struct ifreq *)data;
128577217Sphk	ireq = (struct ieee80211req *)data;
128655992Swpaul
128788749Sambrisko	config = (struct an_ltv_genconfig *)&sc->areq;
128888749Sambrisko	key = (struct an_ltv_key *)&sc->areq;
128988749Sambrisko	status = (struct an_ltv_status *)&sc->areq;
129088749Sambrisko	ssids = (struct an_ltv_ssidlist *)&sc->areq;
129177217Sphk
129264429Speter	if (sc->an_gone) {
129361816Sroberto		error = ENODEV;
129461816Sroberto		goto out;
129561816Sroberto	}
129655992Swpaul
129783270Sbrooks	switch (command) {
129855992Swpaul	case SIOCSIFADDR:
129955992Swpaul	case SIOCGIFADDR:
130055992Swpaul	case SIOCSIFMTU:
130155992Swpaul		error = ether_ioctl(ifp, command, data);
130255992Swpaul		break;
130355992Swpaul	case SIOCSIFFLAGS:
130455992Swpaul		if (ifp->if_flags & IFF_UP) {
130555992Swpaul			if (ifp->if_flags & IFF_RUNNING &&
130655992Swpaul			    ifp->if_flags & IFF_PROMISC &&
130755992Swpaul			    !(sc->an_if_flags & IFF_PROMISC)) {
130855992Swpaul				an_promisc(sc, 1);
130955992Swpaul			} else if (ifp->if_flags & IFF_RUNNING &&
131055992Swpaul			    !(ifp->if_flags & IFF_PROMISC) &&
131155992Swpaul			    sc->an_if_flags & IFF_PROMISC) {
131255992Swpaul				an_promisc(sc, 0);
131355992Swpaul			} else
131455992Swpaul				an_init(sc);
131555992Swpaul		} else {
131655992Swpaul			if (ifp->if_flags & IFF_RUNNING)
131755992Swpaul				an_stop(sc);
131855992Swpaul		}
131955992Swpaul		sc->an_if_flags = ifp->if_flags;
132055992Swpaul		error = 0;
132155992Swpaul		break;
132277217Sphk	case SIOCSIFMEDIA:
132377217Sphk	case SIOCGIFMEDIA:
132477217Sphk		error = ifmedia_ioctl(ifp, ifr, &sc->an_ifmedia, command);
132577217Sphk		break;
132655992Swpaul	case SIOCADDMULTI:
132755992Swpaul	case SIOCDELMULTI:
132855992Swpaul		/* The Aironet has no multicast filter. */
132955992Swpaul		error = 0;
133055992Swpaul		break;
133155992Swpaul	case SIOCGAIRONET:
133288749Sambrisko		error = copyin(ifr->ifr_data, &sc->areq, sizeof(sc->areq));
133378639Sbrooks		if (error != 0)
133455992Swpaul			break;
133555992Swpaul#ifdef ANCACHE
133688749Sambrisko		if (sc->areq.an_type == AN_RID_ZERO_CACHE) {
133755992Swpaul			sc->an_sigitems = sc->an_nextitem = 0;
133855992Swpaul			break;
133988749Sambrisko		} else if (sc->areq.an_type == AN_RID_READ_CACHE) {
134088749Sambrisko			char *pt = (char *)&sc->areq.an_val;
134155992Swpaul			bcopy((char *)&sc->an_sigitems, (char *)pt,
134255992Swpaul			    sizeof(int));
134355992Swpaul			pt += sizeof(int);
134488749Sambrisko			sc->areq.an_len = sizeof(int) / 2;
134555992Swpaul			bcopy((char *)&sc->an_sigcache, (char *)pt,
134655992Swpaul			    sizeof(struct an_sigcache) * sc->an_sigitems);
134788749Sambrisko			sc->areq.an_len += ((sizeof(struct an_sigcache) *
134855992Swpaul			    sc->an_sigitems) / 2) + 1;
134955992Swpaul		} else
135055992Swpaul#endif
135188749Sambrisko		if (an_read_record(sc, (struct an_ltv_gen *)&sc->areq)) {
135255992Swpaul			error = EINVAL;
135355992Swpaul			break;
135455992Swpaul		}
135588749Sambrisko		error = copyout(&sc->areq, ifr->ifr_data, sizeof(sc->areq));
135655992Swpaul		break;
135755992Swpaul	case SIOCSAIRONET:
135864429Speter		if ((error = suser(p)))
135964429Speter			goto out;
136088749Sambrisko		error = copyin(ifr->ifr_data, &sc->areq, sizeof(sc->areq));
136178639Sbrooks		if (error != 0)
136255992Swpaul			break;
136388749Sambrisko		an_setdef(sc, &sc->areq);
136455992Swpaul		break;
136588748Sambrisko	case SIOCGPRIVATE_0:              /* used by Cisco client utility */
136688748Sambrisko		copyin(ifr->ifr_data, &l_ioctl, sizeof(l_ioctl));
136788748Sambrisko		mode = l_ioctl.command;
136888748Sambrisko
136988748Sambrisko		if (mode >= AIROGCAP && mode <= AIROGSTATSD32) {
137088748Sambrisko			error = readrids(ifp, &l_ioctl);
137188748Sambrisko		}else if (mode >= AIROPCAP && mode <= AIROPLEAPUSR) {
137288748Sambrisko			error = writerids(ifp, &l_ioctl);
137388748Sambrisko		}else if (mode >= AIROFLSHRST && mode <= AIRORESTART) {
137488748Sambrisko			error = flashcard(ifp, &l_ioctl);
137588748Sambrisko		}else{
137688748Sambrisko			error =-1;
137788748Sambrisko		}
137888748Sambrisko
137988748Sambrisko		/* copy out the updated command info */
138088748Sambrisko		copyout(&l_ioctl, ifr->ifr_data, sizeof(l_ioctl));
138188748Sambrisko
138288748Sambrisko		break;
138388748Sambrisko	case SIOCGPRIVATE_1:              /* used by Cisco client utility */
138488748Sambrisko		copyin(ifr->ifr_data, &l_ioctl, sizeof(l_ioctl));
138588748Sambrisko		l_ioctl.command = 0;
138688748Sambrisko		error = AIROMAGIC;
138788748Sambrisko		copyout(&error, l_ioctl.data, sizeof(error));
138888748Sambrisko	        error = 0;
138988748Sambrisko		break;
139077217Sphk	case SIOCG80211:
139188749Sambrisko		sc->areq.an_len = sizeof(sc->areq);
139288748Sambrisko		/* was that a good idea DJA we are doing a short-cut */
139383270Sbrooks		switch (ireq->i_type) {
139477217Sphk		case IEEE80211_IOC_SSID:
139578639Sbrooks			if (ireq->i_val == -1) {
139688749Sambrisko				sc->areq.an_type = AN_RID_STATUS;
139777217Sphk				if (an_read_record(sc,
139888749Sambrisko				    (struct an_ltv_gen *)&sc->areq)) {
139977217Sphk					error = EINVAL;
140077217Sphk					break;
140177217Sphk				}
140277217Sphk				len = status->an_ssidlen;
140377217Sphk				tmpptr = status->an_ssid;
140478639Sbrooks			} else if (ireq->i_val >= 0) {
140588749Sambrisko				sc->areq.an_type = AN_RID_SSIDLIST;
140677217Sphk				if (an_read_record(sc,
140788749Sambrisko				    (struct an_ltv_gen *)&sc->areq)) {
140877217Sphk					error = EINVAL;
140977217Sphk					break;
141077217Sphk				}
141178639Sbrooks				if (ireq->i_val == 0) {
141277217Sphk					len = ssids->an_ssid1_len;
141377217Sphk					tmpptr = ssids->an_ssid1;
141478639Sbrooks				} else if (ireq->i_val == 1) {
141577217Sphk					len = ssids->an_ssid2_len;
141688748Sambrisko					tmpptr = ssids->an_ssid2;
141788748Sambrisko				} else if (ireq->i_val == 2) {
141877217Sphk					len = ssids->an_ssid3_len;
141977217Sphk					tmpptr = ssids->an_ssid3;
142077217Sphk				} else {
142177217Sphk					error = EINVAL;
142277217Sphk					break;
142377217Sphk				}
142477217Sphk			} else {
142577217Sphk				error = EINVAL;
142677217Sphk				break;
142777217Sphk			}
142878639Sbrooks			if (len > IEEE80211_NWID_LEN) {
142977217Sphk				error = EINVAL;
143077217Sphk				break;
143177217Sphk			}
143277217Sphk			ireq->i_len = len;
143377217Sphk			bzero(tmpstr, IEEE80211_NWID_LEN);
143477217Sphk			bcopy(tmpptr, tmpstr, len);
143577217Sphk			error = copyout(tmpstr, ireq->i_data,
143677217Sphk			    IEEE80211_NWID_LEN);
143777217Sphk			break;
143877217Sphk		case IEEE80211_IOC_NUMSSIDS:
143977217Sphk			ireq->i_val = 3;
144077217Sphk			break;
144177217Sphk		case IEEE80211_IOC_WEP:
144288749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
144377217Sphk			if (an_read_record(sc,
144488749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
144577217Sphk				error = EINVAL;
144677217Sphk				break;
144777217Sphk			}
144878639Sbrooks			if (config->an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE) {
144978639Sbrooks				if (config->an_authtype &
145077217Sphk				    AN_AUTHTYPE_ALLOW_UNENCRYPTED)
145177217Sphk					ireq->i_val = IEEE80211_WEP_MIXED;
145277217Sphk				else
145377217Sphk					ireq->i_val = IEEE80211_WEP_ON;
145477217Sphk			} else {
145577217Sphk				ireq->i_val = IEEE80211_WEP_OFF;
145677217Sphk			}
145777217Sphk			break;
145877217Sphk		case IEEE80211_IOC_WEPKEY:
145977217Sphk			/*
146077217Sphk			 * XXX: I'm not entierly convinced this is
146177217Sphk			 * correct, but it's what is implemented in
146277217Sphk			 * ancontrol so it will have to do until we get
146377217Sphk			 * access to actual Cisco code.
146477217Sphk			 */
146588748Sambrisko			if (ireq->i_val < 0 || ireq->i_val > 8) {
146677217Sphk				error = EINVAL;
146777217Sphk				break;
146877217Sphk			}
146977217Sphk			len = 0;
147088748Sambrisko			if (ireq->i_val < 5) {
147188749Sambrisko				sc->areq.an_type = AN_RID_WEP_TEMP;
147278639Sbrooks				for (i = 0; i < 5; i++) {
147377217Sphk					if (an_read_record(sc,
147488749Sambrisko					    (struct an_ltv_gen *)&sc->areq)) {
147577217Sphk						error = EINVAL;
147677217Sphk						break;
147777217Sphk					}
147878639Sbrooks					if (key->kindex == 0xffff)
147977217Sphk						break;
148078639Sbrooks					if (key->kindex == ireq->i_val)
148178639Sbrooks						len = key->klen;
148277217Sphk					/* Required to get next entry */
148388749Sambrisko					sc->areq.an_type = AN_RID_WEP_PERM;
148477217Sphk				}
148578639Sbrooks				if (error != 0)
148677217Sphk					break;
148777217Sphk			}
148877217Sphk			/* We aren't allowed to read the value of the
148977217Sphk			 * key from the card so we just output zeros
149077217Sphk			 * like we would if we could read the card, but
149177217Sphk			 * denied the user access.
149277217Sphk			 */
149377217Sphk			bzero(tmpstr, len);
149477217Sphk			ireq->i_len = len;
149577217Sphk			error = copyout(tmpstr, ireq->i_data, len);
149677217Sphk			break;
149777217Sphk		case IEEE80211_IOC_NUMWEPKEYS:
149888748Sambrisko			ireq->i_val = 9; /* include home key */
149977217Sphk			break;
150077217Sphk		case IEEE80211_IOC_WEPTXKEY:
150178639Sbrooks			/*
150278639Sbrooks			 * For some strange reason, you have to read all
150378639Sbrooks			 * keys before you can read the txkey.
150478639Sbrooks			 */
150588749Sambrisko			sc->areq.an_type = AN_RID_WEP_TEMP;
150678639Sbrooks			for (i = 0; i < 5; i++) {
150778639Sbrooks				if (an_read_record(sc,
150888749Sambrisko				    (struct an_ltv_gen *) &sc->areq)) {
150978639Sbrooks					error = EINVAL;
151078639Sbrooks					break;
151178639Sbrooks				}
151278639Sbrooks				if (key->kindex == 0xffff)
151378639Sbrooks					break;
151478639Sbrooks				/* Required to get next entry */
151588749Sambrisko				sc->areq.an_type = AN_RID_WEP_PERM;
151678639Sbrooks			}
151778639Sbrooks			if (error != 0)
151878639Sbrooks				break;
151978639Sbrooks
152088749Sambrisko			sc->areq.an_type = AN_RID_WEP_PERM;
152177217Sphk			key->kindex = 0xffff;
152277217Sphk			if (an_read_record(sc,
152388749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
152477217Sphk				error = EINVAL;
152577217Sphk				break;
152677217Sphk			}
152777217Sphk			ireq->i_val = key->mac[0];
152888748Sambrisko			/*
152988748Sambrisko			 * Check for home mode.  Map home mode into
153088748Sambrisko			 * 5th key since that is how it is stored on
153188748Sambrisko			 * the card
153288748Sambrisko			 */
153388749Sambrisko			sc->areq.an_len  = sizeof(struct an_ltv_genconfig);
153488749Sambrisko			sc->areq.an_type = AN_RID_GENCONFIG;
153588748Sambrisko			if (an_read_record(sc,
153688749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
153788748Sambrisko				error = EINVAL;
153888748Sambrisko				break;
153988748Sambrisko			}
154088748Sambrisko			if (config->an_home_product & AN_HOME_NETWORK)
154188748Sambrisko				ireq->i_val = 4;
154277217Sphk			break;
154377217Sphk		case IEEE80211_IOC_AUTHMODE:
154488749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
154577217Sphk			if (an_read_record(sc,
154688749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
154777217Sphk				error = EINVAL;
154877217Sphk				break;
154977217Sphk			}
155077217Sphk			if ((config->an_authtype & AN_AUTHTYPE_MASK) ==
155177217Sphk			    AN_AUTHTYPE_NONE) {
155277217Sphk			    ireq->i_val = IEEE80211_AUTH_NONE;
155377217Sphk			} else if ((config->an_authtype & AN_AUTHTYPE_MASK) ==
155477217Sphk			    AN_AUTHTYPE_OPEN) {
155577217Sphk			    ireq->i_val = IEEE80211_AUTH_OPEN;
155677217Sphk			} else if ((config->an_authtype & AN_AUTHTYPE_MASK) ==
155777217Sphk			    AN_AUTHTYPE_SHAREDKEY) {
155877217Sphk			    ireq->i_val = IEEE80211_AUTH_SHARED;
155977217Sphk			} else
156077217Sphk				error = EINVAL;
156177217Sphk			break;
156277217Sphk		case IEEE80211_IOC_STATIONNAME:
156388749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
156477217Sphk			if (an_read_record(sc,
156588749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
156677217Sphk				error = EINVAL;
156777217Sphk				break;
156877217Sphk			}
156977217Sphk			ireq->i_len = sizeof(config->an_nodename);
157077217Sphk			tmpptr = config->an_nodename;
157177217Sphk			bzero(tmpstr, IEEE80211_NWID_LEN);
157277217Sphk			bcopy(tmpptr, tmpstr, ireq->i_len);
157377217Sphk			error = copyout(tmpstr, ireq->i_data,
157477217Sphk			    IEEE80211_NWID_LEN);
157577217Sphk			break;
157677217Sphk		case IEEE80211_IOC_CHANNEL:
157788749Sambrisko			sc->areq.an_type = AN_RID_STATUS;
157877217Sphk			if (an_read_record(sc,
157988749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
158077217Sphk				error = EINVAL;
158177217Sphk				break;
158277217Sphk			}
158377217Sphk			ireq->i_val = status->an_cur_channel;
158477217Sphk			break;
158577217Sphk		case IEEE80211_IOC_POWERSAVE:
158688749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
158777217Sphk			if (an_read_record(sc,
158888749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
158977217Sphk				error = EINVAL;
159077217Sphk				break;
159177217Sphk			}
159278639Sbrooks			if (config->an_psave_mode == AN_PSAVE_NONE) {
159377217Sphk				ireq->i_val = IEEE80211_POWERSAVE_OFF;
159478639Sbrooks			} else if (config->an_psave_mode == AN_PSAVE_CAM) {
159577217Sphk				ireq->i_val = IEEE80211_POWERSAVE_CAM;
159678639Sbrooks			} else if (config->an_psave_mode == AN_PSAVE_PSP) {
159777217Sphk				ireq->i_val = IEEE80211_POWERSAVE_PSP;
159878639Sbrooks			} else if (config->an_psave_mode == AN_PSAVE_PSP_CAM) {
159977217Sphk				ireq->i_val = IEEE80211_POWERSAVE_PSP_CAM;
160077217Sphk			} else
160177217Sphk				error = EINVAL;
160277217Sphk			break;
160377217Sphk		case IEEE80211_IOC_POWERSAVESLEEP:
160488749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
160577217Sphk			if (an_read_record(sc,
160688749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
160777217Sphk				error = EINVAL;
160877217Sphk				break;
160977217Sphk			}
161077217Sphk			ireq->i_val = config->an_listen_interval;
161177217Sphk			break;
161283270Sbrooks		}
161377217Sphk		break;
161477217Sphk	case SIOCS80211:
161577217Sphk		if ((error = suser(p)))
161677217Sphk			goto out;
161788749Sambrisko		sc->areq.an_len = sizeof(sc->areq);
161877217Sphk		/*
161977217Sphk		 * We need a config structure for everything but the WEP
162077217Sphk		 * key management and SSIDs so we get it now so avoid
162177217Sphk		 * duplicating this code every time.
162277217Sphk		 */
162377217Sphk		if (ireq->i_type != IEEE80211_IOC_SSID &&
162477217Sphk		    ireq->i_type != IEEE80211_IOC_WEPKEY &&
162577217Sphk		    ireq->i_type != IEEE80211_IOC_WEPTXKEY) {
162688749Sambrisko			sc->areq.an_type = AN_RID_GENCONFIG;
162777217Sphk			if (an_read_record(sc,
162888749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
162977217Sphk				error = EINVAL;
163077217Sphk				break;
163177217Sphk			}
163277217Sphk		}
163383270Sbrooks		switch (ireq->i_type) {
163477217Sphk		case IEEE80211_IOC_SSID:
163588749Sambrisko			sc->areq.an_type = AN_RID_SSIDLIST;
163677217Sphk			if (an_read_record(sc,
163788749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
163877217Sphk				error = EINVAL;
163977217Sphk				break;
164077217Sphk			}
164178639Sbrooks			if (ireq->i_len > IEEE80211_NWID_LEN) {
164277217Sphk				error = EINVAL;
164377217Sphk				break;
164477217Sphk			}
164577217Sphk			switch (ireq->i_val) {
164677217Sphk			case 0:
164777217Sphk				error = copyin(ireq->i_data,
164877217Sphk				    ssids->an_ssid1, ireq->i_len);
164977217Sphk				ssids->an_ssid1_len = ireq->i_len;
165077217Sphk				break;
165177217Sphk			case 1:
165277217Sphk				error = copyin(ireq->i_data,
165377217Sphk				    ssids->an_ssid2, ireq->i_len);
165477217Sphk				ssids->an_ssid2_len = ireq->i_len;
165577217Sphk				break;
165677217Sphk			case 2:
165777217Sphk				error = copyin(ireq->i_data,
165877217Sphk				    ssids->an_ssid3, ireq->i_len);
165977217Sphk				ssids->an_ssid3_len = ireq->i_len;
166077217Sphk				break;
166177217Sphk			default:
166277217Sphk				error = EINVAL;
166377217Sphk				break;
166477217Sphk			}
166577217Sphk			break;
166677217Sphk		case IEEE80211_IOC_WEP:
166777217Sphk			switch (ireq->i_val) {
166877217Sphk			case IEEE80211_WEP_OFF:
166977217Sphk				config->an_authtype &=
167077217Sphk				    ~(AN_AUTHTYPE_PRIVACY_IN_USE |
167177217Sphk				    AN_AUTHTYPE_ALLOW_UNENCRYPTED);
167277217Sphk				break;
167377217Sphk			case IEEE80211_WEP_ON:
167477217Sphk				config->an_authtype |=
167577217Sphk				    AN_AUTHTYPE_PRIVACY_IN_USE;
167677217Sphk				config->an_authtype &=
167777217Sphk				    ~AN_AUTHTYPE_ALLOW_UNENCRYPTED;
167877217Sphk				break;
167977217Sphk			case IEEE80211_WEP_MIXED:
168077217Sphk				config->an_authtype |=
168177217Sphk				    AN_AUTHTYPE_PRIVACY_IN_USE |
168277217Sphk				    AN_AUTHTYPE_ALLOW_UNENCRYPTED;
168377217Sphk				break;
168477217Sphk			default:
168577217Sphk				error = EINVAL;
168677217Sphk				break;
168777217Sphk			}
168877217Sphk			break;
168977217Sphk		case IEEE80211_IOC_WEPKEY:
169077217Sphk			if (ireq->i_val < 0 || ireq->i_val > 7 ||
169177217Sphk			    ireq->i_len > 13) {
169277217Sphk				error = EINVAL;
169377217Sphk				break;
169477217Sphk			}
169577217Sphk			error = copyin(ireq->i_data, tmpstr, 13);
169678639Sbrooks			if (error != 0)
169777217Sphk				break;
169888749Sambrisko			bzero(&sc->areq, sizeof(struct an_ltv_key));
169988749Sambrisko			sc->areq.an_len = sizeof(struct an_ltv_key);
170077217Sphk			key->mac[0] = 1;	/* The others are 0. */
170177217Sphk			key->kindex = ireq->i_val % 4;
170278639Sbrooks			if (ireq->i_val < 4)
170388749Sambrisko				sc->areq.an_type = AN_RID_WEP_TEMP;
170477217Sphk			else
170588749Sambrisko				sc->areq.an_type = AN_RID_WEP_PERM;
170677217Sphk			key->klen = ireq->i_len;
170777217Sphk			bcopy(tmpstr, key->key, key->klen);
170877217Sphk			break;
170977217Sphk		case IEEE80211_IOC_WEPTXKEY:
171088748Sambrisko			/*
171188748Sambrisko			 * Map the 5th key into the home mode
171288748Sambrisko			 * since that is how it is stored on
171388748Sambrisko			 * the card
171488748Sambrisko			 */
171588748Sambrisko			if (ireq->i_val < 0 || ireq->i_val > 4) {
171677217Sphk				error = EINVAL;
171777217Sphk				break;
171877217Sphk			}
171988749Sambrisko			sc->areq.an_len  = sizeof(struct an_ltv_genconfig);
172088749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
172188748Sambrisko			if (an_read_record(sc,
172288749Sambrisko	       		    (struct an_ltv_gen *)&sc->areq)) {
172388748Sambrisko	       			error = EINVAL;
172488748Sambrisko				break;
172588748Sambrisko			}
172688748Sambrisko			if (ireq->i_val ==  4) {
172788748Sambrisko				config->an_home_product |= AN_HOME_NETWORK;
172888748Sambrisko				ireq->i_val = 0;
172988748Sambrisko			} else {
173088748Sambrisko				config->an_home_product &= ~AN_HOME_NETWORK;
173188748Sambrisko			}
173288748Sambrisko
173388748Sambrisko			sc->an_config.an_home_product
173488748Sambrisko				= config->an_home_product;
173588749Sambrisko			an_write_record(sc, (struct an_ltv_gen *)&sc->areq);
173688748Sambrisko
173788749Sambrisko			bzero(&sc->areq, sizeof(struct an_ltv_key));
173888749Sambrisko			sc->areq.an_len = sizeof(struct an_ltv_key);
173988749Sambrisko			sc->areq.an_type = AN_RID_WEP_PERM;
174077217Sphk			key->kindex = 0xffff;
174177217Sphk			key->mac[0] = ireq->i_val;
174277217Sphk			break;
174377217Sphk		case IEEE80211_IOC_AUTHMODE:
174477217Sphk			switch (ireq->i_val) {
174577217Sphk			case IEEE80211_AUTH_NONE:
174677217Sphk				config->an_authtype = AN_AUTHTYPE_NONE |
174777217Sphk				    (config->an_authtype & ~AN_AUTHTYPE_MASK);
174877217Sphk				break;
174977217Sphk			case IEEE80211_AUTH_OPEN:
175077217Sphk				config->an_authtype = AN_AUTHTYPE_OPEN |
175177217Sphk				    (config->an_authtype & ~AN_AUTHTYPE_MASK);
175277217Sphk				break;
175377217Sphk			case IEEE80211_AUTH_SHARED:
175477217Sphk				config->an_authtype = AN_AUTHTYPE_SHAREDKEY |
175577217Sphk				    (config->an_authtype & ~AN_AUTHTYPE_MASK);
175677217Sphk				break;
175777217Sphk			default:
175877217Sphk				error = EINVAL;
175977217Sphk			}
176077217Sphk			break;
176177217Sphk		case IEEE80211_IOC_STATIONNAME:
176278639Sbrooks			if (ireq->i_len > 16) {
176377217Sphk				error = EINVAL;
176477217Sphk				break;
176577217Sphk			}
176677217Sphk			bzero(config->an_nodename, 16);
176777217Sphk			error = copyin(ireq->i_data,
176877217Sphk			    config->an_nodename, ireq->i_len);
176977217Sphk			break;
177077217Sphk		case IEEE80211_IOC_CHANNEL:
177177217Sphk			/*
177277217Sphk			 * The actual range is 1-14, but if you set it
177377217Sphk			 * to 0 you get the default so we let that work
177477217Sphk			 * too.
177577217Sphk			 */
177677217Sphk			if (ireq->i_val < 0 || ireq->i_val >14) {
177777217Sphk				error = EINVAL;
177877217Sphk				break;
177977217Sphk			}
178077217Sphk			config->an_ds_channel = ireq->i_val;
178177217Sphk			break;
178277217Sphk		case IEEE80211_IOC_POWERSAVE:
178377217Sphk			switch (ireq->i_val) {
178477217Sphk			case IEEE80211_POWERSAVE_OFF:
178577217Sphk				config->an_psave_mode = AN_PSAVE_NONE;
178677217Sphk				break;
178777217Sphk			case IEEE80211_POWERSAVE_CAM:
178877217Sphk				config->an_psave_mode = AN_PSAVE_CAM;
178977217Sphk				break;
179077217Sphk			case IEEE80211_POWERSAVE_PSP:
179177217Sphk				config->an_psave_mode = AN_PSAVE_PSP;
179277217Sphk				break;
179377217Sphk			case IEEE80211_POWERSAVE_PSP_CAM:
179477217Sphk				config->an_psave_mode = AN_PSAVE_PSP_CAM;
179577217Sphk				break;
179677217Sphk			default:
179777217Sphk				error = EINVAL;
179877217Sphk				break;
179977217Sphk			}
180077217Sphk			break;
180177217Sphk		case IEEE80211_IOC_POWERSAVESLEEP:
180277217Sphk			config->an_listen_interval = ireq->i_val;
180377217Sphk			break;
180477217Sphk		}
180577217Sphk
180677217Sphk		if (!error)
180788749Sambrisko			an_setdef(sc, &sc->areq);
180877217Sphk		break;
180955992Swpaul	default:
181055992Swpaul		error = EINVAL;
181155992Swpaul		break;
181255992Swpaul	}
181361816Srobertoout:
181467094Swpaul	AN_UNLOCK(sc);
181555992Swpaul
181678639Sbrooks	return(error != 0);
181755992Swpaul}
181855992Swpaul
181983270Sbrooksstatic int
182083270Sbrooksan_init_tx_ring(sc)
182155992Swpaul	struct an_softc		*sc;
182255992Swpaul{
182355992Swpaul	int			i;
182455992Swpaul	int			id;
182555992Swpaul
182655992Swpaul	if (sc->an_gone)
182755992Swpaul		return (0);
182855992Swpaul
182955992Swpaul	for (i = 0; i < AN_TX_RING_CNT; i++) {
183055992Swpaul		if (an_alloc_nicmem(sc, 1518 +
183155992Swpaul		    0x44, &id))
183255992Swpaul			return(ENOMEM);
183355992Swpaul		sc->an_rdata.an_tx_fids[i] = id;
183455992Swpaul		sc->an_rdata.an_tx_ring[i] = 0;
183555992Swpaul	}
183655992Swpaul
183755992Swpaul	sc->an_rdata.an_tx_prod = 0;
183855992Swpaul	sc->an_rdata.an_tx_cons = 0;
183955992Swpaul
184055992Swpaul	return(0);
184155992Swpaul}
184255992Swpaul
184383270Sbrooksstatic void
184483270Sbrooksan_init(xsc)
184555992Swpaul	void			*xsc;
184655992Swpaul{
184755992Swpaul	struct an_softc		*sc = xsc;
184855992Swpaul	struct ifnet		*ifp = &sc->arpcom.ac_if;
184955992Swpaul
185067094Swpaul	AN_LOCK(sc);
185167094Swpaul
185267094Swpaul	if (sc->an_gone) {
185367094Swpaul		AN_UNLOCK(sc);
185455992Swpaul		return;
185567094Swpaul	}
185655992Swpaul
185755992Swpaul	if (ifp->if_flags & IFF_RUNNING)
185855992Swpaul		an_stop(sc);
185955992Swpaul
186055992Swpaul	sc->an_associated = 0;
186155992Swpaul
186255992Swpaul	/* Allocate the TX buffers */
186355992Swpaul	if (an_init_tx_ring(sc)) {
186455992Swpaul		an_reset(sc);
186555992Swpaul		if (an_init_tx_ring(sc)) {
186655992Swpaul			printf("an%d: tx buffer allocation "
186755992Swpaul			    "failed\n", sc->an_unit);
186867094Swpaul			AN_UNLOCK(sc);
186955992Swpaul			return;
187055992Swpaul		}
187155992Swpaul	}
187255992Swpaul
187355992Swpaul	/* Set our MAC address. */
187455992Swpaul	bcopy((char *)&sc->arpcom.ac_enaddr,
187555992Swpaul	    (char *)&sc->an_config.an_macaddr, ETHER_ADDR_LEN);
187655992Swpaul
187755992Swpaul	if (ifp->if_flags & IFF_BROADCAST)
187855992Swpaul		sc->an_config.an_rxmode = AN_RXMODE_BC_ADDR;
187955992Swpaul	else
188055992Swpaul		sc->an_config.an_rxmode = AN_RXMODE_ADDR;
188155992Swpaul
188255992Swpaul	if (ifp->if_flags & IFF_MULTICAST)
188355992Swpaul		sc->an_config.an_rxmode = AN_RXMODE_BC_MC_ADDR;
188455992Swpaul
188583269Sbrooks	if (ifp->if_flags & IFF_PROMISC) {
188683269Sbrooks		if (sc->an_monitor & AN_MONITOR) {
188783269Sbrooks			if (sc->an_monitor & AN_MONITOR_ANY_BSS) {
188883269Sbrooks				sc->an_config.an_rxmode |=
188983269Sbrooks				    AN_RXMODE_80211_MONITOR_ANYBSS |
189083269Sbrooks				    AN_RXMODE_NO_8023_HEADER;
189183269Sbrooks			} else {
189283269Sbrooks				sc->an_config.an_rxmode |=
189383269Sbrooks				    AN_RXMODE_80211_MONITOR_CURBSS |
189483269Sbrooks				    AN_RXMODE_NO_8023_HEADER;
189583269Sbrooks			}
189683269Sbrooks		}
189783269Sbrooks	}
189855992Swpaul
189955992Swpaul	/* Set the ssid list */
190055992Swpaul	sc->an_ssidlist.an_type = AN_RID_SSIDLIST;
190155992Swpaul	sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist);
190255992Swpaul	if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) {
190355992Swpaul		printf("an%d: failed to set ssid list\n", sc->an_unit);
190467094Swpaul		AN_UNLOCK(sc);
190555992Swpaul		return;
190655992Swpaul	}
190755992Swpaul
190855992Swpaul	/* Set the AP list */
190955992Swpaul	sc->an_aplist.an_type = AN_RID_APLIST;
191055992Swpaul	sc->an_aplist.an_len = sizeof(struct an_ltv_aplist);
191155992Swpaul	if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) {
191255992Swpaul		printf("an%d: failed to set AP list\n", sc->an_unit);
191367094Swpaul		AN_UNLOCK(sc);
191455992Swpaul		return;
191555992Swpaul	}
191655992Swpaul
191755992Swpaul	/* Set the configuration in the NIC */
191855992Swpaul	sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
191955992Swpaul	sc->an_config.an_type = AN_RID_GENCONFIG;
192055992Swpaul	if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_config)) {
192155992Swpaul		printf("an%d: failed to set configuration\n", sc->an_unit);
192267094Swpaul		AN_UNLOCK(sc);
192355992Swpaul		return;
192455992Swpaul	}
192555992Swpaul
192655992Swpaul	/* Enable the MAC */
192755992Swpaul	if (an_cmd(sc, AN_CMD_ENABLE, 0)) {
192855992Swpaul		printf("an%d: failed to enable MAC\n", sc->an_unit);
192967094Swpaul		AN_UNLOCK(sc);
193055992Swpaul		return;
193155992Swpaul	}
193255992Swpaul
193374698Sarchie	if (ifp->if_flags & IFF_PROMISC)
193474698Sarchie		an_cmd(sc, AN_CMD_SET_MODE, 0xffff);
193574698Sarchie
193655992Swpaul	/* enable interrupts */
193755992Swpaul	CSR_WRITE_2(sc, AN_INT_EN, AN_INTRS);
193855992Swpaul
193955992Swpaul	ifp->if_flags |= IFF_RUNNING;
194055992Swpaul	ifp->if_flags &= ~IFF_OACTIVE;
194155992Swpaul
194255992Swpaul	sc->an_stat_ch = timeout(an_stats_update, sc, hz);
194367094Swpaul	AN_UNLOCK(sc);
194455992Swpaul
194555992Swpaul	return;
194655992Swpaul}
194755992Swpaul
194883270Sbrooksstatic void
194983270Sbrooksan_start(ifp)
195055992Swpaul	struct ifnet		*ifp;
195155992Swpaul{
195255992Swpaul	struct an_softc		*sc;
195355992Swpaul	struct mbuf		*m0 = NULL;
195455992Swpaul	struct an_txframe_802_3	tx_frame_802_3;
195555992Swpaul	struct ether_header	*eh;
195655992Swpaul	int			id;
195755992Swpaul	int			idx;
195855992Swpaul	unsigned char           txcontrol;
195955992Swpaul
196055992Swpaul	sc = ifp->if_softc;
196155992Swpaul
196255992Swpaul	if (sc->an_gone)
196355992Swpaul		return;
196455992Swpaul
196555992Swpaul	if (ifp->if_flags & IFF_OACTIVE)
196655992Swpaul		return;
196755992Swpaul
196855992Swpaul	if (!sc->an_associated)
196955992Swpaul		return;
197055992Swpaul
197190990Sbrooks	/* We can't send in monitor mode so toss any attempts. */
197283269Sbrooks	if (sc->an_monitor && (ifp->if_flags & IFF_PROMISC)) {
197383270Sbrooks		for (;;) {
197483269Sbrooks			IF_DEQUEUE(&ifp->if_snd, m0);
197583269Sbrooks			if (m0 == NULL)
197683269Sbrooks				break;
197790990Sbrooks			m_freem(m0);
197883269Sbrooks		}
197983269Sbrooks		return;
198083269Sbrooks	}
198183269Sbrooks
198255992Swpaul	idx = sc->an_rdata.an_tx_prod;
198355992Swpaul	bzero((char *)&tx_frame_802_3, sizeof(tx_frame_802_3));
198455992Swpaul
198583270Sbrooks	while (sc->an_rdata.an_tx_ring[idx] == 0) {
198655992Swpaul		IF_DEQUEUE(&ifp->if_snd, m0);
198755992Swpaul		if (m0 == NULL)
198855992Swpaul			break;
198955992Swpaul
199055992Swpaul		id = sc->an_rdata.an_tx_fids[idx];
199155992Swpaul		eh = mtod(m0, struct ether_header *);
199255992Swpaul
199355992Swpaul		bcopy((char *)&eh->ether_dhost,
199455992Swpaul		    (char *)&tx_frame_802_3.an_tx_dst_addr, ETHER_ADDR_LEN);
199555992Swpaul		bcopy((char *)&eh->ether_shost,
199655992Swpaul		    (char *)&tx_frame_802_3.an_tx_src_addr, ETHER_ADDR_LEN);
199783270Sbrooks
199855992Swpaul		tx_frame_802_3.an_tx_802_3_payload_len =
199955992Swpaul		  m0->m_pkthdr.len - 12;  /* minus src/dest mac & type */
200055992Swpaul
200155992Swpaul                m_copydata(m0, sizeof(struct ether_header) - 2 ,
200255992Swpaul                    tx_frame_802_3.an_tx_802_3_payload_len,
200355992Swpaul                    (caddr_t)&sc->an_txbuf);
200455992Swpaul
200578639Sbrooks		txcontrol = AN_TXCTL_8023;
200655992Swpaul		/* write the txcontrol only */
200755992Swpaul		an_write_data(sc, id, 0x08, (caddr_t)&txcontrol,
200855992Swpaul			      sizeof(txcontrol));
200983270Sbrooks
201055992Swpaul		/* 802_3 header */
201155992Swpaul		an_write_data(sc, id, 0x34, (caddr_t)&tx_frame_802_3,
201255992Swpaul			      sizeof(struct an_txframe_802_3));
201383270Sbrooks
201455992Swpaul		/* in mbuf header type is just before payload */
201555992Swpaul		an_write_data(sc, id, 0x44, (caddr_t)&sc->an_txbuf,
201655992Swpaul			    tx_frame_802_3.an_tx_802_3_payload_len);
201783270Sbrooks
201855992Swpaul		/*
201955992Swpaul		 * If there's a BPF listner, bounce a copy of
202055992Swpaul		 * this frame to him.
202155992Swpaul		 */
202255992Swpaul		if (ifp->if_bpf)
202355992Swpaul			bpf_mtap(ifp, m0);
202455992Swpaul
202555992Swpaul		m_freem(m0);
202655992Swpaul		m0 = NULL;
202755992Swpaul
202855992Swpaul		sc->an_rdata.an_tx_ring[idx] = id;
202955992Swpaul		if (an_cmd(sc, AN_CMD_TX, id))
203055992Swpaul			printf("an%d: xmit failed\n", sc->an_unit);
203155992Swpaul
203255992Swpaul		AN_INC(idx, AN_TX_RING_CNT);
203355992Swpaul	}
203455992Swpaul
203555992Swpaul	if (m0 != NULL)
203655992Swpaul		ifp->if_flags |= IFF_OACTIVE;
203755992Swpaul
203855992Swpaul	sc->an_rdata.an_tx_prod = idx;
203955992Swpaul
204055992Swpaul	/*
204155992Swpaul	 * Set a timeout in case the chip goes out to lunch.
204255992Swpaul	 */
204355992Swpaul	ifp->if_timer = 5;
204455992Swpaul
204555992Swpaul	return;
204655992Swpaul}
204755992Swpaul
204883270Sbrooksvoid
204983270Sbrooksan_stop(sc)
205055992Swpaul	struct an_softc		*sc;
205155992Swpaul{
205255992Swpaul	struct ifnet		*ifp;
205355992Swpaul	int			i;
205455992Swpaul
205567094Swpaul	AN_LOCK(sc);
205667094Swpaul
205767094Swpaul	if (sc->an_gone) {
205867094Swpaul		AN_UNLOCK(sc);
205955992Swpaul		return;
206067094Swpaul	}
206155992Swpaul
206255992Swpaul	ifp = &sc->arpcom.ac_if;
206355992Swpaul
206455992Swpaul	an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0);
206555992Swpaul	CSR_WRITE_2(sc, AN_INT_EN, 0);
206655992Swpaul	an_cmd(sc, AN_CMD_DISABLE, 0);
206755992Swpaul
206855992Swpaul	for (i = 0; i < AN_TX_RING_CNT; i++)
206955992Swpaul		an_cmd(sc, AN_CMD_DEALLOC_MEM, sc->an_rdata.an_tx_fids[i]);
207055992Swpaul
207155992Swpaul	untimeout(an_stats_update, sc, sc->an_stat_ch);
207255992Swpaul
207355992Swpaul	ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
207455992Swpaul
207567094Swpaul	AN_UNLOCK(sc);
207667094Swpaul
207755992Swpaul	return;
207855992Swpaul}
207955992Swpaul
208083270Sbrooksstatic void
208183270Sbrooksan_watchdog(ifp)
208255992Swpaul	struct ifnet		*ifp;
208355992Swpaul{
208455992Swpaul	struct an_softc		*sc;
208555992Swpaul
208655992Swpaul	sc = ifp->if_softc;
208767094Swpaul	AN_LOCK(sc);
208855992Swpaul
208967094Swpaul	if (sc->an_gone) {
209067094Swpaul		AN_UNLOCK(sc);
209155992Swpaul		return;
209267094Swpaul	}
209355992Swpaul
209455992Swpaul	printf("an%d: device timeout\n", sc->an_unit);
209555992Swpaul
209655992Swpaul	an_reset(sc);
209755992Swpaul	an_init(sc);
209855992Swpaul
209955992Swpaul	ifp->if_oerrors++;
210067094Swpaul	AN_UNLOCK(sc);
210155992Swpaul
210255992Swpaul	return;
210355992Swpaul}
210455992Swpaul
210583270Sbrooksvoid
210683270Sbrooksan_shutdown(dev)
210755992Swpaul	device_t		dev;
210855992Swpaul{
210955992Swpaul	struct an_softc		*sc;
211055992Swpaul
211155992Swpaul	sc = device_get_softc(dev);
211255992Swpaul	an_stop(sc);
211355992Swpaul
211455992Swpaul	return;
211555992Swpaul}
211655992Swpaul
211755992Swpaul#ifdef ANCACHE
211855992Swpaul/* Aironet signal strength cache code.
211955992Swpaul * store signal/noise/quality on per MAC src basis in
212055992Swpaul * a small fixed cache.  The cache wraps if > MAX slots
212155992Swpaul * used.  The cache may be zeroed out to start over.
212255992Swpaul * Two simple filters exist to reduce computation:
212388748Sambrisko * 1. ip only (literally 0x800, ETHERTYPE_IP) which may be used
212455992Swpaul * to ignore some packets.  It defaults to ip only.
212555992Swpaul * it could be used to focus on broadcast, non-IP 802.11 beacons.
212655992Swpaul * 2. multicast/broadcast only.  This may be used to
212755992Swpaul * ignore unicast packets and only cache signal strength
212855992Swpaul * for multicast/broadcast packets (beacons); e.g., Mobile-IP
212955992Swpaul * beacons and not unicast traffic.
213055992Swpaul *
213155992Swpaul * The cache stores (MAC src(index), IP src (major clue), signal,
213255992Swpaul *	quality, noise)
213355992Swpaul *
213455992Swpaul * No apologies for storing IP src here.  It's easy and saves much
213583270Sbrooks * trouble elsewhere.  The cache is assumed to be INET dependent,
213655992Swpaul * although it need not be.
213755992Swpaul *
213855992Swpaul * Note: the Aironet only has a single byte of signal strength value
213955992Swpaul * in the rx frame header, and it's not scaled to anything sensible.
214055992Swpaul * This is kind of lame, but it's all we've got.
214155992Swpaul */
214255992Swpaul
214355992Swpaul#ifdef documentation
214455992Swpaul
214555992Swpaulint an_sigitems;                                /* number of cached entries */
214655992Swpaulstruct an_sigcache an_sigcache[MAXANCACHE];  /*  array of cache entries */
214755992Swpaulint an_nextitem;                                /*  index/# of entries */
214855992Swpaul
214955992Swpaul
215055992Swpaul#endif
215155992Swpaul
215255992Swpaul/* control variables for cache filtering.  Basic idea is
215355992Swpaul * to reduce cost (e.g., to only Mobile-IP agent beacons
215455992Swpaul * which are broadcast or multicast).  Still you might
215555992Swpaul * want to measure signal strength anth unicast ping packets
215655992Swpaul * on a pt. to pt. ant. setup.
215755992Swpaul */
215883270Sbrooks/* set true if you want to limit cache items to broadcast/mcast
215955992Swpaul * only packets (not unicast).  Useful for mobile-ip beacons which
216055992Swpaul * are broadcast/multicast at network layer.  Default is all packets
216155992Swpaul * so ping/unicast anll work say anth pt. to pt. antennae setup.
216255992Swpaul */
216355992Swpaulstatic int an_cache_mcastonly = 0;
216483270SbrooksSYSCTL_INT(_machdep, OID_AUTO, an_cache_mcastonly, CTLFLAG_RW,
216555992Swpaul	&an_cache_mcastonly, 0, "");
216655992Swpaul
216755992Swpaul/* set true if you want to limit cache items to IP packets only
216855992Swpaul*/
216955992Swpaulstatic int an_cache_iponly = 1;
217083270SbrooksSYSCTL_INT(_machdep, OID_AUTO, an_cache_iponly, CTLFLAG_RW,
217155992Swpaul	&an_cache_iponly, 0, "");
217255992Swpaul
217355992Swpaul/*
217455992Swpaul * an_cache_store, per rx packet store signal
217555992Swpaul * strength in MAC (src) indexed cache.
217655992Swpaul */
217783270Sbrooksstatic void
217883270Sbrooksan_cache_store (sc, eh, m, rx_quality)
217955992Swpaul	struct an_softc *sc;
218055992Swpaul	struct ether_header *eh;
218155992Swpaul	struct mbuf *m;
218255992Swpaul	unsigned short rx_quality;
218355992Swpaul{
218483270Sbrooks	struct ip *ip = 0;
218555992Swpaul	int i;
218655992Swpaul	static int cache_slot = 0; 	/* use this cache entry */
218755992Swpaul	static int wrapindex = 0;       /* next "free" cache entry */
218888748Sambrisko	int type_ipv4 = 0;
218955992Swpaul
219055992Swpaul	/* filters:
219155992Swpaul	 * 1. ip only
219255992Swpaul	 * 2. configurable filter to throw out unicast packets,
219355992Swpaul	 * keep multicast only.
219455992Swpaul	 */
219583270Sbrooks
219688748Sambrisko	if ((ntohs(eh->ether_type) == ETHERTYPE_IP)) {
219788748Sambrisko		type_ipv4 = 1;
219855992Swpaul	}
219955992Swpaul
220083270Sbrooks	/* filter for ip packets only
220155992Swpaul	*/
220288748Sambrisko	if ( an_cache_iponly && !type_ipv4) {
220355992Swpaul		return;
220455992Swpaul	}
220555992Swpaul
220655992Swpaul	/* filter for broadcast/multicast only
220755992Swpaul	 */
220855992Swpaul	if (an_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
220955992Swpaul		return;
221055992Swpaul	}
221155992Swpaul
221255992Swpaul#ifdef SIGDEBUG
221355992Swpaul	printf("an: q value %x (MSB=0x%x, LSB=0x%x) \n",
221455992Swpaul	    rx_quality & 0xffff, rx_quality >> 8, rx_quality & 0xff);
221555992Swpaul#endif
221655992Swpaul
221755992Swpaul	/* find the ip header.  we want to store the ip_src
221883270Sbrooks	 * address.
221955992Swpaul	 */
222088748Sambrisko	if (type_ipv4) {
222155992Swpaul		ip = mtod(m, struct ip *);
222255992Swpaul	}
222383270Sbrooks
222483270Sbrooks	/* do a linear search for a matching MAC address
222555992Swpaul	 * in the cache table
222655992Swpaul	 * . MAC address is 6 bytes,
222755992Swpaul	 * . var w_nextitem holds total number of entries already cached
222855992Swpaul	 */
222978639Sbrooks	for (i = 0; i < sc->an_nextitem; i++) {
223055992Swpaul		if (! bcmp(eh->ether_shost , sc->an_sigcache[i].macsrc,  6 )) {
223155992Swpaul			/* Match!,
223255992Swpaul			 * so we already have this entry,
223355992Swpaul			 * update the data
223455992Swpaul			 */
223583270Sbrooks			break;
223655992Swpaul		}
223755992Swpaul	}
223855992Swpaul
223955992Swpaul	/* did we find a matching mac address?
224055992Swpaul	 * if yes, then overwrite a previously existing cache entry
224155992Swpaul	 */
224255992Swpaul	if (i < sc->an_nextitem )   {
224383270Sbrooks		cache_slot = i;
224455992Swpaul	}
224555992Swpaul	/* else, have a new address entry,so
224655992Swpaul	 * add this new entry,
224755992Swpaul	 * if table full, then we need to replace LRU entry
224855992Swpaul	 */
224983270Sbrooks	else    {
225055992Swpaul
225183270Sbrooks		/* check for space in cache table
225255992Swpaul		 * note: an_nextitem also holds number of entries
225383270Sbrooks		 * added in the cache table
225455992Swpaul		 */
225555992Swpaul		if ( sc->an_nextitem < MAXANCACHE ) {
225655992Swpaul			cache_slot = sc->an_nextitem;
225783270Sbrooks			sc->an_nextitem++;
225855992Swpaul			sc->an_sigitems = sc->an_nextitem;
225955992Swpaul		}
226055992Swpaul        	/* no space found, so simply wrap anth wrap index
226155992Swpaul		 * and "zap" the next entry
226255992Swpaul		 */
226355992Swpaul		else {
226455992Swpaul			if (wrapindex == MAXANCACHE) {
226555992Swpaul				wrapindex = 0;
226655992Swpaul			}
226755992Swpaul			cache_slot = wrapindex++;
226855992Swpaul		}
226955992Swpaul	}
227055992Swpaul
227155992Swpaul	/* invariant: cache_slot now points at some slot
227255992Swpaul	 * in cache.
227355992Swpaul	 */
227455992Swpaul	if (cache_slot < 0 || cache_slot >= MAXANCACHE) {
227555992Swpaul		log(LOG_ERR, "an_cache_store, bad index: %d of "
227655992Swpaul		    "[0..%d], gross cache error\n",
227755992Swpaul		    cache_slot, MAXANCACHE);
227855992Swpaul		return;
227955992Swpaul	}
228055992Swpaul
228155992Swpaul	/*  store items in cache
228255992Swpaul	 *  .ip source address
228355992Swpaul	 *  .mac src
228455992Swpaul	 *  .signal, etc.
228555992Swpaul	 */
228688748Sambrisko	if (type_ipv4) {
228755992Swpaul		sc->an_sigcache[cache_slot].ipsrc = ip->ip_src.s_addr;
228855992Swpaul	}
228955992Swpaul	bcopy( eh->ether_shost, sc->an_sigcache[cache_slot].macsrc,  6);
229055992Swpaul
229155992Swpaul	sc->an_sigcache[cache_slot].signal = rx_quality;
229255992Swpaul
229355992Swpaul	return;
229455992Swpaul}
229555992Swpaul#endif
229677217Sphk
229783270Sbrooksstatic int
229883270Sbrooksan_media_change(ifp)
229977217Sphk	struct ifnet		*ifp;
230077217Sphk{
230177217Sphk	struct an_softc *sc = ifp->if_softc;
230277217Sphk	int otype = sc->an_config.an_opmode;
230377217Sphk	int orate = sc->an_tx_rate;
230477217Sphk
230577217Sphk	if ((sc->an_ifmedia.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC) != 0)
230677217Sphk		sc->an_config.an_opmode = AN_OPMODE_IBSS_ADHOC;
230777217Sphk	else
230877217Sphk		sc->an_config.an_opmode = AN_OPMODE_INFRASTRUCTURE_STATION;
230977217Sphk
231077217Sphk	switch (IFM_SUBTYPE(sc->an_ifmedia.ifm_cur->ifm_media)) {
231177217Sphk	case IFM_IEEE80211_DS1:
231277217Sphk		sc->an_tx_rate = AN_RATE_1MBPS;
231377217Sphk		break;
231477217Sphk	case IFM_IEEE80211_DS2:
231577217Sphk		sc->an_tx_rate = AN_RATE_2MBPS;
231677217Sphk		break;
231777217Sphk	case IFM_IEEE80211_DS5:
231877217Sphk		sc->an_tx_rate = AN_RATE_5_5MBPS;
231977217Sphk		break;
232077217Sphk	case IFM_IEEE80211_DS11:
232177217Sphk		sc->an_tx_rate = AN_RATE_11MBPS;
232277217Sphk		break;
232377217Sphk	case IFM_AUTO:
232477217Sphk		sc->an_tx_rate = 0;
232577217Sphk		break;
232677217Sphk	}
232777217Sphk
232877217Sphk	if (otype != sc->an_config.an_opmode ||
232977217Sphk	    orate != sc->an_tx_rate)
233077217Sphk		an_init(sc);
233177217Sphk
233277217Sphk	return(0);
233377217Sphk}
233477217Sphk
233583270Sbrooksstatic void
233683270Sbrooksan_media_status(ifp, imr)
233777217Sphk	struct ifnet		*ifp;
233877217Sphk	struct ifmediareq	*imr;
233977217Sphk{
234077217Sphk	struct an_ltv_status	status;
234177217Sphk	struct an_softc		*sc = ifp->if_softc;
234277217Sphk
234377217Sphk	status.an_len = sizeof(status);
234477217Sphk	status.an_type = AN_RID_STATUS;
234577217Sphk	if (an_read_record(sc, (struct an_ltv_gen *)&status)) {
234677217Sphk		/* If the status read fails, just lie. */
234777217Sphk		imr->ifm_active = sc->an_ifmedia.ifm_cur->ifm_media;
234877217Sphk		imr->ifm_status = IFM_AVALID|IFM_ACTIVE;
234977217Sphk	}
235077217Sphk
235178639Sbrooks	if (sc->an_tx_rate == 0) {
235277217Sphk		imr->ifm_active = IFM_IEEE80211|IFM_AUTO;
235377217Sphk		if (sc->an_config.an_opmode == AN_OPMODE_IBSS_ADHOC)
235477217Sphk			imr->ifm_active |= IFM_IEEE80211_ADHOC;
235583270Sbrooks		switch (status.an_current_tx_rate) {
235677217Sphk		case AN_RATE_1MBPS:
235777217Sphk			imr->ifm_active |= IFM_IEEE80211_DS1;
235877217Sphk			break;
235977217Sphk		case AN_RATE_2MBPS:
236077217Sphk			imr->ifm_active |= IFM_IEEE80211_DS2;
236177217Sphk			break;
236277217Sphk		case AN_RATE_5_5MBPS:
236377217Sphk			imr->ifm_active |= IFM_IEEE80211_DS5;
236477217Sphk			break;
236577217Sphk		case AN_RATE_11MBPS:
236677217Sphk			imr->ifm_active |= IFM_IEEE80211_DS11;
236777217Sphk			break;
236877217Sphk		}
236977217Sphk	} else {
237077217Sphk		imr->ifm_active = sc->an_ifmedia.ifm_cur->ifm_media;
237177217Sphk	}
237277217Sphk
237377217Sphk	imr->ifm_status = IFM_AVALID;
237491283Sambrisko	if (status.an_opmode & AN_STATUS_OPMODE_ASSOCIATED)
237577217Sphk		imr->ifm_status |= IFM_ACTIVE;
237677217Sphk}
237788748Sambrisko
237888748Sambrisko/********************** Cisco utility support routines *************/
237988748Sambrisko
238088748Sambrisko/*
238188748Sambrisko * ReadRids & WriteRids derived from Cisco driver additions to Ben Reed's
238288748Sambrisko * Linux driver
238388748Sambrisko */
238488748Sambrisko
238588748Sambriskostatic int
238688748Sambriskoreadrids(ifp, l_ioctl)
238788748Sambrisko	struct ifnet   *ifp;
238888748Sambrisko	struct aironet_ioctl *l_ioctl;
238988748Sambrisko{
239088749Sambrisko	unsigned short  rid;
239188748Sambrisko	struct an_softc *sc;
239288748Sambrisko
239388748Sambrisko	switch (l_ioctl->command) {
239488748Sambrisko	case AIROGCAP:
239588748Sambrisko		rid = AN_RID_CAPABILITIES;
239688748Sambrisko		break;
239788748Sambrisko	case AIROGCFG:
239888748Sambrisko		rid = AN_RID_GENCONFIG;
239988748Sambrisko		break;
240088748Sambrisko	case AIROGSLIST:
240188748Sambrisko		rid = AN_RID_SSIDLIST;
240288748Sambrisko		break;
240388748Sambrisko	case AIROGVLIST:
240488748Sambrisko		rid = AN_RID_APLIST;
240588748Sambrisko		break;
240688748Sambrisko	case AIROGDRVNAM:
240788748Sambrisko		rid = AN_RID_DRVNAME;
240888748Sambrisko		break;
240988748Sambrisko	case AIROGEHTENC:
241088748Sambrisko		rid = AN_RID_ENCAPPROTO;
241188748Sambrisko		break;
241288748Sambrisko	case AIROGWEPKTMP:
241388748Sambrisko		rid = AN_RID_WEP_TEMP;
241488748Sambrisko		break;
241588748Sambrisko	case AIROGWEPKNV:
241688748Sambrisko		rid = AN_RID_WEP_PERM;
241788748Sambrisko		break;
241888748Sambrisko	case AIROGSTAT:
241988748Sambrisko		rid = AN_RID_STATUS;
242088748Sambrisko		break;
242188748Sambrisko	case AIROGSTATSD32:
242288748Sambrisko		rid = AN_RID_32BITS_DELTA;
242388748Sambrisko		break;
242488748Sambrisko	case AIROGSTATSC32:
242588748Sambrisko		rid = AN_RID_32BITS_CUM;
242688748Sambrisko		break;
242788748Sambrisko	default:
242888748Sambrisko		rid = 999;
242988748Sambrisko		break;
243088748Sambrisko	}
243188748Sambrisko
243288748Sambrisko	if (rid == 999)	/* Is bad command */
243388748Sambrisko		return -EINVAL;
243488748Sambrisko
243588748Sambrisko	sc = ifp->if_softc;
243688749Sambrisko	sc->areq.an_len  = AN_MAX_DATALEN;
243788749Sambrisko	sc->areq.an_type = rid;
243888748Sambrisko
243988749Sambrisko	an_read_record(sc, (struct an_ltv_gen *)&sc->areq);
244088748Sambrisko
244188749Sambrisko	l_ioctl->len = sc->areq.an_len - 4;	/* just data */
244288748Sambrisko
244388748Sambrisko	/* the data contains the length at first */
244488749Sambrisko	if (copyout(&(sc->areq.an_len), l_ioctl->data,
244588749Sambrisko		    sizeof(sc->areq.an_len))) {
244688748Sambrisko		return -EFAULT;
244788748Sambrisko	}
244888748Sambrisko	/* Just copy the data back */
244988749Sambrisko	if (copyout(&(sc->areq.an_val), l_ioctl->data + 2,
245088748Sambrisko		    l_ioctl->len)) {
245188748Sambrisko		return -EFAULT;
245288748Sambrisko	}
245388748Sambrisko	return 0;
245488748Sambrisko}
245588748Sambrisko
245688748Sambriskostatic int
245788748Sambriskowriterids(ifp, l_ioctl)
245888748Sambrisko	struct ifnet   *ifp;
245988748Sambrisko	struct aironet_ioctl *l_ioctl;
246088748Sambrisko{
246188748Sambrisko	struct an_softc *sc;
246288748Sambrisko	int             rid, command;
246388748Sambrisko
246488748Sambrisko	sc = ifp->if_softc;
246588748Sambrisko	rid = 0;
246688748Sambrisko	command = l_ioctl->command;
246788748Sambrisko
246888748Sambrisko	switch (command) {
246988748Sambrisko	case AIROPSIDS:
247088748Sambrisko		rid = AN_RID_SSIDLIST;
247188748Sambrisko		break;
247288748Sambrisko	case AIROPCAP:
247388748Sambrisko		rid = AN_RID_CAPABILITIES;
247488748Sambrisko		break;
247588748Sambrisko	case AIROPAPLIST:
247688748Sambrisko		rid = AN_RID_APLIST;
247788748Sambrisko		break;
247888748Sambrisko	case AIROPCFG:
247988748Sambrisko		rid = AN_RID_GENCONFIG;
248088748Sambrisko		break;
248188748Sambrisko	case AIROPMACON:
248288748Sambrisko		an_cmd(sc, AN_CMD_ENABLE, 0);
248388748Sambrisko		return 0;
248488748Sambrisko		break;
248588748Sambrisko	case AIROPMACOFF:
248688748Sambrisko		an_cmd(sc, AN_CMD_DISABLE, 0);
248788748Sambrisko		return 0;
248888748Sambrisko		break;
248988748Sambrisko	case AIROPSTCLR:
249088748Sambrisko		/*
249188748Sambrisko		 * This command merely clears the counts does not actually
249288748Sambrisko		 * store any data only reads rid. But as it changes the cards
249388748Sambrisko		 * state, I put it in the writerid routines.
249488748Sambrisko		 */
249588748Sambrisko
249688748Sambrisko		rid = AN_RID_32BITS_DELTACLR;
249788748Sambrisko		sc = ifp->if_softc;
249888749Sambrisko		sc->areq.an_len = AN_MAX_DATALEN;
249988749Sambrisko		sc->areq.an_type = rid;
250088748Sambrisko
250188749Sambrisko		an_read_record(sc, (struct an_ltv_gen *)&sc->areq);
250288749Sambrisko		l_ioctl->len = sc->areq.an_len - 4;	/* just data */
250388748Sambrisko
250488748Sambrisko		/* the data contains the length at first */
250588749Sambrisko		if (copyout(&(sc->areq.an_len), l_ioctl->data,
250688749Sambrisko			    sizeof(sc->areq.an_len))) {
250788748Sambrisko			return -EFAULT;
250888748Sambrisko		}
250988748Sambrisko		/* Just copy the data */
251088749Sambrisko		if (copyout(&(sc->areq.an_val), l_ioctl->data + 2,
251188748Sambrisko			    l_ioctl->len)) {
251288748Sambrisko			return -EFAULT;
251388748Sambrisko		}
251488748Sambrisko		return 0;
251588748Sambrisko		break;
251688748Sambrisko	case AIROPWEPKEY:
251788748Sambrisko		rid = AN_RID_WEP_TEMP;
251888748Sambrisko		break;
251988748Sambrisko	case AIROPWEPKEYNV:
252088748Sambrisko		rid = AN_RID_WEP_PERM;
252188748Sambrisko		break;
252288748Sambrisko	case AIROPLEAPUSR:
252388748Sambrisko		rid = AN_RID_LEAPUSERNAME;
252488748Sambrisko		break;
252588748Sambrisko	case AIROPLEAPPWD:
252688748Sambrisko		rid = AN_RID_LEAPPASSWORD;
252788748Sambrisko		break;
252888748Sambrisko	default:
252988748Sambrisko		return -EOPNOTSUPP;
253088748Sambrisko	}
253188748Sambrisko
253288748Sambrisko	if (rid) {
253388749Sambrisko		if (l_ioctl->len > sizeof(sc->areq.an_val) + 4)
253488748Sambrisko			return -EINVAL;
253588749Sambrisko		sc->areq.an_len = l_ioctl->len + 4;	/* add type & length */
253688749Sambrisko		sc->areq.an_type = rid;
253788748Sambrisko
253888748Sambrisko		/* Just copy the data back */
253988749Sambrisko		copyin((l_ioctl->data) + 2, &sc->areq.an_val,
254088748Sambrisko		       l_ioctl->len);
254188748Sambrisko
254288748Sambrisko		an_cmd(sc, AN_CMD_DISABLE, 0);
254388749Sambrisko		an_write_record(sc, (struct an_ltv_gen *)&sc->areq);
254488748Sambrisko		an_cmd(sc, AN_CMD_ENABLE, 0);
254588748Sambrisko		return 0;
254688748Sambrisko	}
254788748Sambrisko	return -EOPNOTSUPP;
254888748Sambrisko}
254988748Sambrisko
255088748Sambrisko/*
255188748Sambrisko * General Flash utilities derived from Cisco driver additions to Ben Reed's
255288748Sambrisko * Linux driver
255388748Sambrisko */
255488748Sambrisko
255588748Sambrisko#define FLASH_DELAY(x) tsleep(ifp, PZERO, "flash", ((x) / hz) + 1);
255688748Sambrisko
255788748Sambriskostatic int
255888748Sambriskounstickbusy(ifp)
255988748Sambrisko	struct ifnet   *ifp;
256088748Sambrisko{
256188748Sambrisko	struct an_softc *sc = ifp->if_softc;
256288748Sambrisko
256388748Sambrisko	if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY) {
256488748Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY);
256588748Sambrisko		return 1;
256688748Sambrisko	}
256788748Sambrisko	return 0;
256888748Sambrisko}
256988748Sambrisko
257088748Sambrisko/*
257188748Sambrisko * Wait for busy completion from card wait for delay uSec's Return true for
257288748Sambrisko * success meaning command reg is clear
257388748Sambrisko */
257488748Sambrisko
257588748Sambriskostatic int
257688748SambriskoWaitBusy(ifp, uSec)
257788748Sambrisko	struct ifnet   *ifp;
257888748Sambrisko	int             uSec;
257988748Sambrisko{
258088748Sambrisko	int             statword = 0xffff;
258188748Sambrisko	int             delay = 0;
258288748Sambrisko	struct an_softc *sc = ifp->if_softc;
258388748Sambrisko
258488748Sambrisko	while ((statword & AN_CMD_BUSY) && delay <= (1000 * 100)) {
258588748Sambrisko		FLASH_DELAY(10);
258688748Sambrisko		delay += 10;
258788748Sambrisko		statword = CSR_READ_2(sc, AN_COMMAND);
258888748Sambrisko
258988748Sambrisko		if ((AN_CMD_BUSY & statword) && (delay % 200)) {
259088748Sambrisko			unstickbusy(ifp);
259188748Sambrisko		}
259288748Sambrisko	}
259388748Sambrisko
259488748Sambrisko	return 0 == (AN_CMD_BUSY & statword);
259588748Sambrisko}
259688748Sambrisko
259788748Sambrisko/*
259888748Sambrisko * STEP 1) Disable MAC and do soft reset on card.
259988748Sambrisko */
260088748Sambrisko
260188748Sambriskostatic int
260288748Sambriskocmdreset(ifp)
260388748Sambrisko	struct ifnet   *ifp;
260488748Sambrisko{
260588748Sambrisko	int             status;
260688748Sambrisko	struct an_softc *sc = ifp->if_softc;
260788748Sambrisko
260888748Sambrisko	an_stop(sc);
260988748Sambrisko
261088748Sambrisko	an_cmd(sc, AN_CMD_DISABLE, 0);
261188748Sambrisko
261288748Sambrisko	if (!(status = WaitBusy(ifp, 600))) {
261388748Sambrisko		printf("an%d: Waitbusy hang b4 RESET =%d\n",
261488748Sambrisko		       sc->an_unit, status);
261588748Sambrisko		return -EBUSY;
261688748Sambrisko	}
261788748Sambrisko	CSR_WRITE_2(sc, AN_COMMAND, AN_CMD_FW_RESTART);
261888748Sambrisko
261988748Sambrisko	FLASH_DELAY(1000);	/* WAS 600 12/7/00 */
262088748Sambrisko
262188748Sambrisko
262288748Sambrisko	if (!(status = WaitBusy(ifp, 100))) {
262388748Sambrisko		printf("an%d: Waitbusy hang AFTER RESET =%d\n",
262488748Sambrisko		       sc->an_unit, status);
262588748Sambrisko		return -EBUSY;
262688748Sambrisko	}
262788748Sambrisko	return 0;
262888748Sambrisko}
262988748Sambrisko
263088748Sambrisko/*
263188748Sambrisko * STEP 2) Put the card in legendary flash mode
263288748Sambrisko */
263388748Sambrisko#define FLASH_COMMAND  0x7e7e
263488748Sambrisko
263588748Sambriskostatic int
263688748Sambriskosetflashmode(ifp)
263788748Sambrisko	struct ifnet   *ifp;
263888748Sambrisko{
263988748Sambrisko	int             status;
264088748Sambrisko	struct an_softc *sc = ifp->if_softc;
264188748Sambrisko
264288748Sambrisko	CSR_WRITE_2(sc, AN_SW0, FLASH_COMMAND);
264388748Sambrisko	CSR_WRITE_2(sc, AN_SW1, FLASH_COMMAND);
264488748Sambrisko	CSR_WRITE_2(sc, AN_SW0, FLASH_COMMAND);
264588748Sambrisko	CSR_WRITE_2(sc, AN_COMMAND, FLASH_COMMAND);
264688748Sambrisko
264788748Sambrisko	/*
264888748Sambrisko	 * mdelay(500); // 500ms delay
264988748Sambrisko	 */
265088748Sambrisko
265188748Sambrisko	FLASH_DELAY(500);
265288748Sambrisko
265388748Sambrisko	if (!(status = WaitBusy(ifp, 600))) {
265488748Sambrisko		printf("Waitbusy hang after setflash mode\n");
265588748Sambrisko		return -EIO;
265688748Sambrisko	}
265788748Sambrisko	return 0;
265888748Sambrisko}
265988748Sambrisko
266088748Sambrisko/*
266188748Sambrisko * Get a character from the card matching matchbyte Step 3)
266288748Sambrisko */
266388748Sambrisko
266488748Sambriskostatic int
266588748Sambriskoflashgchar(ifp, matchbyte, dwelltime)
266688748Sambrisko	struct ifnet   *ifp;
266788748Sambrisko	int             matchbyte;
266888748Sambrisko	int             dwelltime;
266988748Sambrisko{
267088748Sambrisko	int             rchar;
267188748Sambrisko	unsigned char   rbyte = 0;
267288748Sambrisko	int             success = -1;
267388748Sambrisko	struct an_softc *sc = ifp->if_softc;
267488748Sambrisko
267588748Sambrisko
267688748Sambrisko	do {
267788748Sambrisko		rchar = CSR_READ_2(sc, AN_SW1);
267888748Sambrisko
267988748Sambrisko		if (dwelltime && !(0x8000 & rchar)) {
268088748Sambrisko			dwelltime -= 10;
268188748Sambrisko			FLASH_DELAY(10);
268288748Sambrisko			continue;
268388748Sambrisko		}
268488748Sambrisko		rbyte = 0xff & rchar;
268588748Sambrisko
268688748Sambrisko		if ((rbyte == matchbyte) && (0x8000 & rchar)) {
268788748Sambrisko			CSR_WRITE_2(sc, AN_SW1, 0);
268888748Sambrisko			success = 1;
268988748Sambrisko			break;
269088748Sambrisko		}
269188748Sambrisko		if (rbyte == 0x81 || rbyte == 0x82 || rbyte == 0x83 || rbyte == 0x1a || 0xffff == rchar)
269288748Sambrisko			break;
269388748Sambrisko		CSR_WRITE_2(sc, AN_SW1, 0);
269488748Sambrisko
269588748Sambrisko	} while (dwelltime > 0);
269688748Sambrisko	return success;
269788748Sambrisko}
269888748Sambrisko
269988748Sambrisko/*
270088748Sambrisko * Put character to SWS0 wait for dwelltime x 50us for  echo .
270188748Sambrisko */
270288748Sambrisko
270388748Sambriskostatic int
270488748Sambriskoflashpchar(ifp, byte, dwelltime)
270588748Sambrisko	struct ifnet   *ifp;
270688748Sambrisko	int             byte;
270788748Sambrisko	int             dwelltime;
270888748Sambrisko{
270988748Sambrisko	int             echo;
271088748Sambrisko	int             pollbusy, waittime;
271188748Sambrisko	struct an_softc *sc = ifp->if_softc;
271288748Sambrisko
271388748Sambrisko	byte |= 0x8000;
271488748Sambrisko
271588748Sambrisko	if (dwelltime == 0)
271688748Sambrisko		dwelltime = 200;
271788748Sambrisko
271888748Sambrisko	waittime = dwelltime;
271988748Sambrisko
272088748Sambrisko	/*
272188748Sambrisko	 * Wait for busy bit d15 to go false indicating buffer empty
272288748Sambrisko	 */
272388748Sambrisko	do {
272488748Sambrisko		pollbusy = CSR_READ_2(sc, AN_SW0);
272588748Sambrisko
272688748Sambrisko		if (pollbusy & 0x8000) {
272788748Sambrisko			FLASH_DELAY(50);
272888748Sambrisko			waittime -= 50;
272988748Sambrisko			continue;
273088748Sambrisko		} else
273188748Sambrisko			break;
273288748Sambrisko	}
273388748Sambrisko	while (waittime >= 0);
273488748Sambrisko
273588748Sambrisko	/* timeout for busy clear wait */
273688748Sambrisko
273788748Sambrisko	if (waittime <= 0) {
273888748Sambrisko		printf("an%d: flash putchar busywait timeout! \n",
273988748Sambrisko		       sc->an_unit);
274088748Sambrisko		return -1;
274188748Sambrisko	}
274288748Sambrisko	/*
274388748Sambrisko	 * Port is clear now write byte and wait for it to echo back
274488748Sambrisko	 */
274588748Sambrisko	do {
274688748Sambrisko		CSR_WRITE_2(sc, AN_SW0, byte);
274788748Sambrisko		FLASH_DELAY(50);
274888748Sambrisko		dwelltime -= 50;
274988748Sambrisko		echo = CSR_READ_2(sc, AN_SW1);
275088748Sambrisko	} while (dwelltime >= 0 && echo != byte);
275188748Sambrisko
275288748Sambrisko
275388748Sambrisko	CSR_WRITE_2(sc, AN_SW1, 0);
275488748Sambrisko
275588748Sambrisko	return echo == byte;
275688748Sambrisko}
275788748Sambrisko
275888748Sambrisko/*
275988748Sambrisko * Transfer 32k of firmware data from user buffer to our buffer and send to
276088748Sambrisko * the card
276188748Sambrisko */
276288748Sambrisko
276389063Smsmithstatic char     flashbuffer[1024 * 38];	/* RAW Buffer for flash will be
276488748Sambrisko					 * dynamic next */
276588748Sambrisko
276688748Sambriskostatic int
276788748Sambriskoflashputbuf(ifp)
276888748Sambrisko	struct ifnet   *ifp;
276988748Sambrisko{
277088748Sambrisko	unsigned short *bufp;
277188748Sambrisko	int             nwords;
277288748Sambrisko	struct an_softc *sc = ifp->if_softc;
277388748Sambrisko
277488748Sambrisko	/* Write stuff */
277588748Sambrisko
277688748Sambrisko	bufp = (unsigned short *)flashbuffer;
277788748Sambrisko
277888748Sambrisko	CSR_WRITE_2(sc, AN_AUX_PAGE, 0x100);
277988748Sambrisko	CSR_WRITE_2(sc, AN_AUX_OFFSET, 0);
278088748Sambrisko
278188748Sambrisko	for (nwords = 0; nwords != 16384; nwords++) {
278288748Sambrisko		CSR_WRITE_2(sc, AN_AUX_DATA, bufp[nwords] & 0xffff);
278388748Sambrisko	}
278488748Sambrisko
278588748Sambrisko	CSR_WRITE_2(sc, AN_SW0, 0x8000);
278688748Sambrisko
278788748Sambrisko	return 0;
278888748Sambrisko}
278988748Sambrisko
279088748Sambrisko/*
279188748Sambrisko * After flashing restart the card.
279288748Sambrisko */
279388748Sambrisko
279488748Sambriskostatic int
279588748Sambriskoflashrestart(ifp)
279688748Sambrisko	struct ifnet   *ifp;
279788748Sambrisko{
279888748Sambrisko	int             status = 0;
279988748Sambrisko	struct an_softc *sc = ifp->if_softc;
280088748Sambrisko
280188748Sambrisko	FLASH_DELAY(1024);		/* Added 12/7/00 */
280288748Sambrisko
280388748Sambrisko	an_init(sc);
280488748Sambrisko
280588748Sambrisko	FLASH_DELAY(1024);		/* Added 12/7/00 */
280688748Sambrisko	return status;
280788748Sambrisko}
280888748Sambrisko
280988748Sambrisko/*
281088748Sambrisko * Entry point for flash ioclt.
281188748Sambrisko */
281288748Sambrisko
281388748Sambriskostatic int
281488748Sambriskoflashcard(ifp, l_ioctl)
281588748Sambrisko	struct ifnet   *ifp;
281688748Sambrisko	struct aironet_ioctl *l_ioctl;
281788748Sambrisko{
281888749Sambrisko	int             z = 0, status;
281988748Sambrisko	struct an_softc	*sc;
282088748Sambrisko
282188748Sambrisko	sc = ifp->if_softc;
282288748Sambrisko	status = l_ioctl->command;
282388748Sambrisko
282488748Sambrisko	switch (l_ioctl->command) {
282588748Sambrisko	case AIROFLSHRST:
282688748Sambrisko		return cmdreset(ifp);
282788748Sambrisko		break;
282888748Sambrisko	case AIROFLSHSTFL:
282988748Sambrisko		return setflashmode(ifp);
283088748Sambrisko		break;
283188748Sambrisko	case AIROFLSHGCHR:	/* Get char from aux */
283288749Sambrisko		copyin(l_ioctl->data, &sc->areq, l_ioctl->len);
283388749Sambrisko		z = *(int *)&sc->areq;
283488748Sambrisko		if ((status = flashgchar(ifp, z, 8000)) == 1)
283588748Sambrisko			return 0;
283688748Sambrisko		else
283788748Sambrisko			return -1;
283888748Sambrisko		break;
283988748Sambrisko	case AIROFLSHPCHR:	/* Send char to card. */
284088749Sambrisko		copyin(l_ioctl->data, &sc->areq, l_ioctl->len);
284188749Sambrisko		z = *(int *)&sc->areq;
284288748Sambrisko		if ((status = flashpchar(ifp, z, 8000)) == -1)
284388748Sambrisko			return -EIO;
284488748Sambrisko		else
284588748Sambrisko			return 0;
284688748Sambrisko		break;
284788748Sambrisko	case AIROFLPUTBUF:	/* Send 32k to card */
284888748Sambrisko		if (l_ioctl->len > sizeof(flashbuffer)) {
284988748Sambrisko			printf("an%d: Buffer to big, %x %x\n", sc->an_unit,
285088748Sambrisko			       l_ioctl->len, sizeof(flashbuffer));
285188748Sambrisko			return -EINVAL;
285288748Sambrisko		}
285388748Sambrisko		copyin(l_ioctl->data, &flashbuffer, l_ioctl->len);
285488748Sambrisko
285588748Sambrisko		if ((status = flashputbuf(ifp)) != 0)
285688748Sambrisko			return -EIO;
285788748Sambrisko		else
285888748Sambrisko			return 0;
285988748Sambrisko		break;
286088748Sambrisko	case AIRORESTART:
286188748Sambrisko		if ((status = flashrestart(ifp)) != 0) {
286288748Sambrisko			printf("an%d: FLASHRESTART returned %d\n",
286388748Sambrisko			       sc->an_unit, status);
286488748Sambrisko			return -EIO;
286588748Sambrisko		} else
286688748Sambrisko			return 0;
286788748Sambrisko
286888748Sambrisko		break;
286988748Sambrisko	default:
287088748Sambrisko		return -EINVAL;
287188748Sambrisko	}
287288748Sambrisko
287388748Sambrisko	return -EINVAL;
287488748Sambrisko}
287588748Sambrisko
2876