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 = <v->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 = <v->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 *)<v->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