if_an.c revision 171775
1139749Simp/*- 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/* 3355992Swpaul * Aironet 4500/4800 802.11 PCMCIA/ISA/PCI driver for FreeBSD. 3455992Swpaul * 3555992Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu> 3655992Swpaul * Electrical Engineering Department 3755992Swpaul * Columbia University, New York City 3855992Swpaul */ 3955992Swpaul 40119418Sobrien#include <sys/cdefs.h> 41119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/an/if_an.c 171775 2007-08-07 12:26:19Z avatar $"); 42119418Sobrien 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 46100770Sfenner * through an extra PCI shim: /sys/dev/an/if_an_pci.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> 91154866Snjl#include <sys/ctype.h> 9255992Swpaul#include <sys/systm.h> 9355992Swpaul#include <sys/sockio.h> 9455992Swpaul#include <sys/mbuf.h> 95164033Srwatson#include <sys/priv.h> 9683366Sjulian#include <sys/proc.h> 9755992Swpaul#include <sys/kernel.h> 9855992Swpaul#include <sys/socket.h> 9955992Swpaul#ifdef ANCACHE 10055992Swpaul#include <sys/syslog.h> 101108401Sambrisko#endif 10255992Swpaul#include <sys/sysctl.h> 10355992Swpaul 10455992Swpaul#include <sys/module.h> 10583269Sbrooks#include <sys/sysctl.h> 10655992Swpaul#include <sys/bus.h> 10755992Swpaul#include <machine/bus.h> 10855992Swpaul#include <sys/rman.h> 10984811Sjhb#include <sys/lock.h> 11067365Sjhb#include <sys/mutex.h> 11155992Swpaul#include <machine/resource.h> 112108401Sambrisko#include <sys/malloc.h> 11355992Swpaul 11455992Swpaul#include <net/if.h> 11555992Swpaul#include <net/if_arp.h> 116152315Sru#include <net/if_dl.h> 11755992Swpaul#include <net/ethernet.h> 11855992Swpaul#include <net/if_types.h> 11977217Sphk#include <net/if_media.h> 12055992Swpaul 121116951Ssam#include <net80211/ieee80211_var.h> 122116951Ssam#include <net80211/ieee80211_ioctl.h> 123116951Ssam 12455992Swpaul#ifdef INET 12555992Swpaul#include <netinet/in.h> 12655992Swpaul#include <netinet/in_systm.h> 12755992Swpaul#include <netinet/in_var.h> 12855992Swpaul#include <netinet/ip.h> 12955992Swpaul#endif 13055992Swpaul 13155992Swpaul#include <net/bpf.h> 13255992Swpaul 13355992Swpaul#include <machine/md_var.h> 13455992Swpaul 13555992Swpaul#include <dev/an/if_aironet_ieee.h> 13655992Swpaul#include <dev/an/if_anreg.h> 13755992Swpaul 13855992Swpaul/* These are global because we need them in sys/pci/if_an_p.c. */ 139150446Simpstatic void an_reset(struct an_softc *); 140150446Simpstatic int an_init_mpi350_desc(struct an_softc *); 141150446Simpstatic int an_ioctl(struct ifnet *, u_long, caddr_t); 142150446Simpstatic void an_init(void *); 143150446Simpstatic int an_init_tx_ring(struct an_softc *); 144150446Simpstatic void an_start(struct ifnet *); 145150446Simpstatic void an_watchdog(struct ifnet *); 146150446Simpstatic void an_rxeof(struct an_softc *); 147150446Simpstatic void an_txeof(struct an_softc *, int); 14855992Swpaul 149150446Simpstatic void an_promisc(struct an_softc *, int); 150150446Simpstatic int an_cmd(struct an_softc *, int, int); 151150446Simpstatic int an_cmd_struct(struct an_softc *, struct an_command *, 152150446Simp struct an_reply *); 153150446Simpstatic int an_read_record(struct an_softc *, struct an_ltv_gen *); 154150446Simpstatic int an_write_record(struct an_softc *, struct an_ltv_gen *); 155150446Simpstatic int an_read_data(struct an_softc *, int, int, caddr_t, int); 156150446Simpstatic int an_write_data(struct an_softc *, int, int, caddr_t, int); 157150446Simpstatic int an_seek(struct an_softc *, int, int, int); 158150446Simpstatic int an_alloc_nicmem(struct an_softc *, int, int *); 159150446Simpstatic int an_dma_malloc(struct an_softc *, bus_size_t, struct an_dma_alloc *, 160150446Simp int); 161150446Simpstatic void an_dma_free(struct an_softc *, struct an_dma_alloc *); 162150446Simpstatic void an_dma_malloc_cb(void *, bus_dma_segment_t *, int, int); 163150446Simpstatic void an_stats_update(void *); 164150446Simpstatic void an_setdef(struct an_softc *, struct an_req *); 16555992Swpaul#ifdef ANCACHE 166150446Simpstatic void an_cache_store(struct an_softc *, struct ether_header *, 167150446Simp struct mbuf *, u_int8_t, u_int8_t); 16855992Swpaul#endif 16955992Swpaul 17088748Sambrisko/* function definitions for use with the Cisco's Linux configuration 17188748Sambrisko utilities 17288748Sambrisko*/ 17388748Sambrisko 17492739Salfredstatic int readrids(struct ifnet*, struct aironet_ioctl*); 17592739Salfredstatic int writerids(struct ifnet*, struct aironet_ioctl*); 17692739Salfredstatic int flashcard(struct ifnet*, struct aironet_ioctl*); 17788748Sambrisko 17892739Salfredstatic int cmdreset(struct ifnet *); 17992739Salfredstatic int setflashmode(struct ifnet *); 18092739Salfredstatic int flashgchar(struct ifnet *,int,int); 18192739Salfredstatic int flashpchar(struct ifnet *,int,int); 18292739Salfredstatic int flashputbuf(struct ifnet *); 18392739Salfredstatic int flashrestart(struct ifnet *); 18492739Salfredstatic int WaitBusy(struct ifnet *, int); 18592739Salfredstatic int unstickbusy(struct ifnet *); 18688748Sambrisko 18792739Salfredstatic void an_dump_record (struct an_softc *,struct an_ltv_gen *, 18892739Salfred char *); 18978639Sbrooks 19092739Salfredstatic int an_media_change (struct ifnet *); 19192739Salfredstatic void an_media_status (struct ifnet *, struct ifmediareq *); 19277217Sphk 19378639Sbrooksstatic int an_dump = 0; 194108401Sambriskostatic int an_cache_mode = 0; 19588748Sambrisko 196108401Sambrisko#define DBM 0 197108401Sambrisko#define PERCENT 1 198108401Sambrisko#define RAW 2 199108401Sambrisko 20083269Sbrooksstatic char an_conf[256]; 201108401Sambriskostatic char an_conf_cache[256]; 20283269Sbrooks 20383269Sbrooks/* sysctl vars */ 204108401Sambrisko 205110531SambriskoSYSCTL_NODE(_hw, OID_AUTO, an, CTLFLAG_RD, 0, "Wireless driver parameters"); 20683269Sbrooks 207106937Ssam/* XXX violate ethernet/netgraph callback hooks */ 208106937Ssamextern void (*ng_ether_attach_p)(struct ifnet *ifp); 209106937Ssamextern void (*ng_ether_detach_p)(struct ifnet *ifp); 210106937Ssam 21183269Sbrooksstatic int 21283269Sbrookssysctl_an_dump(SYSCTL_HANDLER_ARGS) 21383269Sbrooks{ 21483269Sbrooks int error, r, last; 21583269Sbrooks char *s = an_conf; 21683270Sbrooks 21783269Sbrooks last = an_dump; 21883269Sbrooks 21983270Sbrooks switch (an_dump) { 22083269Sbrooks case 0: 221108401Sambrisko strcpy(an_conf, "off"); 22283269Sbrooks break; 22383269Sbrooks case 1: 224108401Sambrisko strcpy(an_conf, "type"); 22583269Sbrooks break; 22683269Sbrooks case 2: 227108401Sambrisko strcpy(an_conf, "dump"); 22883269Sbrooks break; 22983269Sbrooks default: 23083269Sbrooks snprintf(an_conf, 5, "%x", an_dump); 23183269Sbrooks break; 23283269Sbrooks } 23383269Sbrooks 23483269Sbrooks error = sysctl_handle_string(oidp, an_conf, sizeof(an_conf), req); 23583269Sbrooks 236108401Sambrisko if (strncmp(an_conf,"off", 3) == 0) { 23783269Sbrooks an_dump = 0; 23883269Sbrooks } 23983270Sbrooks if (strncmp(an_conf,"dump", 4) == 0) { 24083269Sbrooks an_dump = 1; 24183269Sbrooks } 24283270Sbrooks if (strncmp(an_conf,"type", 4) == 0) { 24383269Sbrooks an_dump = 2; 24483269Sbrooks } 24583270Sbrooks if (*s == 'f') { 24683269Sbrooks r = 0; 24783270Sbrooks for (;;s++) { 24883270Sbrooks if ((*s >= '0') && (*s <= '9')) { 24983269Sbrooks r = r * 16 + (*s - '0'); 25083270Sbrooks } else if ((*s >= 'a') && (*s <= 'f')) { 25183269Sbrooks r = r * 16 + (*s - 'a' + 10); 25283270Sbrooks } else { 25383270Sbrooks break; 25483269Sbrooks } 25583269Sbrooks } 25683269Sbrooks an_dump = r; 25783269Sbrooks } 25883269Sbrooks if (an_dump != last) 25983269Sbrooks printf("Sysctl changed for Aironet driver\n"); 26083269Sbrooks 26183269Sbrooks return error; 26283269Sbrooks} 26383269Sbrooks 264110531SambriskoSYSCTL_PROC(_hw_an, OID_AUTO, an_dump, CTLTYPE_STRING | CTLFLAG_RW, 26583269Sbrooks 0, sizeof(an_conf), sysctl_an_dump, "A", ""); 26683269Sbrooks 267108401Sambriskostatic int 268108401Sambriskosysctl_an_cache_mode(SYSCTL_HANDLER_ARGS) 269108401Sambrisko{ 270108401Sambrisko int error, last; 271108401Sambrisko 272108401Sambrisko last = an_cache_mode; 273108401Sambrisko 274108401Sambrisko switch (an_cache_mode) { 275108401Sambrisko case 1: 276108401Sambrisko strcpy(an_conf_cache, "per"); 277108401Sambrisko break; 278108401Sambrisko case 2: 279108401Sambrisko strcpy(an_conf_cache, "raw"); 280108401Sambrisko break; 281108401Sambrisko default: 282108401Sambrisko strcpy(an_conf_cache, "dbm"); 283108401Sambrisko break; 284108401Sambrisko } 285108401Sambrisko 286108401Sambrisko error = sysctl_handle_string(oidp, an_conf_cache, 287108401Sambrisko sizeof(an_conf_cache), req); 288108401Sambrisko 289108401Sambrisko if (strncmp(an_conf_cache,"dbm", 3) == 0) { 290108401Sambrisko an_cache_mode = 0; 291108401Sambrisko } 292108401Sambrisko if (strncmp(an_conf_cache,"per", 3) == 0) { 293108401Sambrisko an_cache_mode = 1; 294108401Sambrisko } 295108401Sambrisko if (strncmp(an_conf_cache,"raw", 3) == 0) { 296108401Sambrisko an_cache_mode = 2; 297108401Sambrisko } 298108401Sambrisko 299108401Sambrisko return error; 300108401Sambrisko} 301108401Sambrisko 302110531SambriskoSYSCTL_PROC(_hw_an, OID_AUTO, an_cache_mode, CTLTYPE_STRING | CTLFLAG_RW, 303108401Sambrisko 0, sizeof(an_conf_cache), sysctl_an_cache_mode, "A", ""); 304108401Sambrisko 30583270Sbrooks/* 30655992Swpaul * We probe for an Aironet 4500/4800 card by attempting to 30755992Swpaul * read the default SSID list. On reset, the first entry in 30855992Swpaul * the SSID list will contain the name "tsunami." If we don't 30955992Swpaul * find this, then there's no card present. 31055992Swpaul */ 31183270Sbrooksint 312150446Simpan_probe(device_t dev) 31355992Swpaul{ 31455992Swpaul struct an_softc *sc = device_get_softc(dev); 315119156Sambrisko struct an_ltv_ssidlist_new ssid; 31655992Swpaul int error; 31755992Swpaul 31855992Swpaul bzero((char *)&ssid, sizeof(ssid)); 31955992Swpaul 32055992Swpaul error = an_alloc_port(dev, 0, AN_IOSIZ); 32178639Sbrooks if (error != 0) 32255992Swpaul return (0); 32355992Swpaul 32455992Swpaul /* can't do autoprobing */ 32555992Swpaul if (rman_get_start(sc->port_res) == -1) 32655992Swpaul return(0); 32755992Swpaul 32855992Swpaul /* 32955992Swpaul * We need to fake up a softc structure long enough 33055992Swpaul * to be able to issue commands and call some of the 33155992Swpaul * other routines. 33255992Swpaul */ 33356094Swpaul sc->an_bhandle = rman_get_bushandle(sc->port_res); 33455992Swpaul sc->an_btag = rman_get_bustag(sc->port_res); 33555992Swpaul sc->an_unit = device_get_unit(dev); 33655992Swpaul 33755992Swpaul ssid.an_len = sizeof(ssid); 33855992Swpaul ssid.an_type = AN_RID_SSIDLIST; 33955992Swpaul 34055992Swpaul /* Make sure interrupts are disabled. */ 341119156Sambrisko sc->mpi350 = 0; 342108401Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0); 343108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), 0xFFFF); 34455992Swpaul 34555992Swpaul an_reset(sc); 34655992Swpaul 34755992Swpaul if (an_cmd(sc, AN_CMD_READCFG, 0)) 34855992Swpaul return(0); 34955992Swpaul 35055992Swpaul if (an_read_record(sc, (struct an_ltv_gen *)&ssid)) 35155992Swpaul return(0); 35255992Swpaul 35368692Swpaul /* See if the ssid matches what we expect ... but doesn't have to */ 354119156Sambrisko if (strcmp(ssid.an_entry[0].an_ssid, AN_DEF_SSID)) 35555992Swpaul return(0); 35683270Sbrooks 35755992Swpaul return(AN_IOSIZ); 35855992Swpaul} 35955992Swpaul 36055992Swpaul/* 36155992Swpaul * Allocate a port resource with the given resource id. 36255992Swpaul */ 36355992Swpaulint 364150446Simpan_alloc_port(device_t dev, int rid, int size) 36555992Swpaul{ 36655992Swpaul struct an_softc *sc = device_get_softc(dev); 36755992Swpaul struct resource *res; 36855992Swpaul 36955992Swpaul res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 37055992Swpaul 0ul, ~0ul, size, RF_ACTIVE); 37155992Swpaul if (res) { 37255992Swpaul sc->port_rid = rid; 37355992Swpaul sc->port_res = res; 37455992Swpaul return (0); 37555992Swpaul } else { 37655992Swpaul return (ENOENT); 37755992Swpaul } 37855992Swpaul} 37955992Swpaul 38055992Swpaul/* 381108401Sambrisko * Allocate a memory resource with the given resource id. 382108401Sambrisko */ 383108401Sambriskoint an_alloc_memory(device_t dev, int rid, int size) 384108401Sambrisko{ 385108401Sambrisko struct an_softc *sc = device_get_softc(dev); 386108401Sambrisko struct resource *res; 387108401Sambrisko 388108401Sambrisko res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 389108401Sambrisko 0ul, ~0ul, size, RF_ACTIVE); 390108401Sambrisko if (res) { 391108401Sambrisko sc->mem_rid = rid; 392108401Sambrisko sc->mem_res = res; 393108401Sambrisko sc->mem_used = size; 394108401Sambrisko return (0); 395108401Sambrisko } else { 396108401Sambrisko return (ENOENT); 397108401Sambrisko } 398108401Sambrisko} 399108401Sambrisko 400108401Sambrisko/* 401108401Sambrisko * Allocate a auxilary memory resource with the given resource id. 402108401Sambrisko */ 403108401Sambriskoint an_alloc_aux_memory(device_t dev, int rid, int size) 404108401Sambrisko{ 405108401Sambrisko struct an_softc *sc = device_get_softc(dev); 406108401Sambrisko struct resource *res; 407108401Sambrisko 408108401Sambrisko res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 409108401Sambrisko 0ul, ~0ul, size, RF_ACTIVE); 410108401Sambrisko if (res) { 411108401Sambrisko sc->mem_aux_rid = rid; 412108401Sambrisko sc->mem_aux_res = res; 413108401Sambrisko sc->mem_aux_used = size; 414108401Sambrisko return (0); 415108401Sambrisko } else { 416108401Sambrisko return (ENOENT); 417108401Sambrisko } 418108401Sambrisko} 419108401Sambrisko 420108401Sambrisko/* 42155992Swpaul * Allocate an irq resource with the given resource id. 42255992Swpaul */ 42355992Swpaulint 424150446Simpan_alloc_irq(device_t dev, int rid, int flags) 42555992Swpaul{ 42655992Swpaul struct an_softc *sc = device_get_softc(dev); 42755992Swpaul struct resource *res; 42855992Swpaul 429127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 430127135Snjl (RF_ACTIVE | flags)); 43155992Swpaul if (res) { 43255992Swpaul sc->irq_rid = rid; 43355992Swpaul sc->irq_res = res; 43455992Swpaul return (0); 43555992Swpaul } else { 43655992Swpaul return (ENOENT); 43755992Swpaul } 43855992Swpaul} 43955992Swpaul 440108401Sambriskostatic void 441150446Simpan_dma_malloc_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 442108401Sambrisko{ 443108401Sambrisko bus_addr_t *paddr = (bus_addr_t*) arg; 444108401Sambrisko *paddr = segs->ds_addr; 445108401Sambrisko} 446108401Sambrisko 44755992Swpaul/* 448108401Sambrisko * Alloc DMA memory and set the pointer to it 449108401Sambrisko */ 450108401Sambriskostatic int 451150446Simpan_dma_malloc(struct an_softc *sc, bus_size_t size, struct an_dma_alloc *dma, 452150446Simp int mapflags) 453108401Sambrisko{ 454108401Sambrisko int r; 455108401Sambrisko 456108401Sambrisko r = bus_dmamap_create(sc->an_dtag, BUS_DMA_NOWAIT, &dma->an_dma_map); 457108401Sambrisko if (r != 0) 458108401Sambrisko goto fail_0; 459108401Sambrisko 460108401Sambrisko r = bus_dmamem_alloc(sc->an_dtag, (void**) &dma->an_dma_vaddr, 461108401Sambrisko BUS_DMA_NOWAIT, &dma->an_dma_map); 462108401Sambrisko if (r != 0) 463108401Sambrisko goto fail_1; 464108401Sambrisko 465108401Sambrisko r = bus_dmamap_load(sc->an_dtag, dma->an_dma_map, dma->an_dma_vaddr, 466108401Sambrisko size, 467108401Sambrisko an_dma_malloc_cb, 468108401Sambrisko &dma->an_dma_paddr, 469108401Sambrisko mapflags | BUS_DMA_NOWAIT); 470108401Sambrisko if (r != 0) 471108401Sambrisko goto fail_2; 472108401Sambrisko 473108401Sambrisko dma->an_dma_size = size; 474108401Sambrisko return (0); 475108401Sambrisko 476108401Sambriskofail_2: 477108401Sambrisko bus_dmamap_unload(sc->an_dtag, dma->an_dma_map); 478108401Sambriskofail_1: 479108401Sambrisko bus_dmamem_free(sc->an_dtag, dma->an_dma_vaddr, dma->an_dma_map); 480108401Sambriskofail_0: 481108401Sambrisko bus_dmamap_destroy(sc->an_dtag, dma->an_dma_map); 482108401Sambrisko dma->an_dma_map = NULL; 483108401Sambrisko return (r); 484108401Sambrisko} 485108401Sambrisko 486108401Sambriskostatic void 487150446Simpan_dma_free(struct an_softc *sc, struct an_dma_alloc *dma) 488108401Sambrisko{ 489108401Sambrisko bus_dmamap_unload(sc->an_dtag, dma->an_dma_map); 490108401Sambrisko bus_dmamem_free(sc->an_dtag, dma->an_dma_vaddr, dma->an_dma_map); 491123978Sambrisko dma->an_dma_vaddr = 0; 492108401Sambrisko bus_dmamap_destroy(sc->an_dtag, dma->an_dma_map); 493108401Sambrisko} 494108401Sambrisko 495108401Sambrisko/* 49655992Swpaul * Release all resources 49755992Swpaul */ 49855992Swpaulvoid 499150446Simpan_release_resources(device_t dev) 50055992Swpaul{ 50155992Swpaul struct an_softc *sc = device_get_softc(dev); 502108401Sambrisko int i; 50355992Swpaul 50455992Swpaul if (sc->port_res) { 50555992Swpaul bus_release_resource(dev, SYS_RES_IOPORT, 50655992Swpaul sc->port_rid, sc->port_res); 50755992Swpaul sc->port_res = 0; 50855992Swpaul } 509108401Sambrisko if (sc->mem_res) { 510108401Sambrisko bus_release_resource(dev, SYS_RES_MEMORY, 511108401Sambrisko sc->mem_rid, sc->mem_res); 512108401Sambrisko sc->mem_res = 0; 513108401Sambrisko } 514108401Sambrisko if (sc->mem_aux_res) { 515108401Sambrisko bus_release_resource(dev, SYS_RES_MEMORY, 516108401Sambrisko sc->mem_aux_rid, sc->mem_aux_res); 517108401Sambrisko sc->mem_aux_res = 0; 518108401Sambrisko } 51955992Swpaul if (sc->irq_res) { 52055992Swpaul bus_release_resource(dev, SYS_RES_IRQ, 52155992Swpaul sc->irq_rid, sc->irq_res); 52255992Swpaul sc->irq_res = 0; 52355992Swpaul } 524108401Sambrisko if (sc->an_rid_buffer.an_dma_paddr) { 525108401Sambrisko an_dma_free(sc, &sc->an_rid_buffer); 526108401Sambrisko } 527108401Sambrisko for (i = 0; i < AN_MAX_RX_DESC; i++) 528108401Sambrisko if (sc->an_rx_buffer[i].an_dma_paddr) { 529108401Sambrisko an_dma_free(sc, &sc->an_rx_buffer[i]); 530108401Sambrisko } 531108401Sambrisko for (i = 0; i < AN_MAX_TX_DESC; i++) 532108401Sambrisko if (sc->an_tx_buffer[i].an_dma_paddr) { 533108401Sambrisko an_dma_free(sc, &sc->an_tx_buffer[i]); 534108401Sambrisko } 535108401Sambrisko if (sc->an_dtag) { 536108401Sambrisko bus_dma_tag_destroy(sc->an_dtag); 537108401Sambrisko } 538108401Sambrisko 53955992Swpaul} 54055992Swpaul 54183270Sbrooksint 542150446Simpan_init_mpi350_desc(struct an_softc *sc) 543108401Sambrisko{ 544108401Sambrisko struct an_command cmd_struct; 545108401Sambrisko struct an_reply reply; 546108401Sambrisko struct an_card_rid_desc an_rid_desc; 547108401Sambrisko struct an_card_rx_desc an_rx_desc; 548108401Sambrisko struct an_card_tx_desc an_tx_desc; 549108401Sambrisko int i, desc; 550108401Sambrisko 551108401Sambrisko if(!sc->an_rid_buffer.an_dma_paddr) 552108401Sambrisko an_dma_malloc(sc, AN_RID_BUFFER_SIZE, 553108401Sambrisko &sc->an_rid_buffer, 0); 554108401Sambrisko for (i = 0; i < AN_MAX_RX_DESC; i++) 555108401Sambrisko if(!sc->an_rx_buffer[i].an_dma_paddr) 556108401Sambrisko an_dma_malloc(sc, AN_RX_BUFFER_SIZE, 557108401Sambrisko &sc->an_rx_buffer[i], 0); 558108401Sambrisko for (i = 0; i < AN_MAX_TX_DESC; i++) 559108401Sambrisko if(!sc->an_tx_buffer[i].an_dma_paddr) 560108401Sambrisko an_dma_malloc(sc, AN_TX_BUFFER_SIZE, 561108401Sambrisko &sc->an_tx_buffer[i], 0); 562108401Sambrisko 563108401Sambrisko /* 564108401Sambrisko * Allocate RX descriptor 565108401Sambrisko */ 566108401Sambrisko bzero(&reply,sizeof(reply)); 567108401Sambrisko cmd_struct.an_cmd = AN_CMD_ALLOC_DESC; 568108401Sambrisko cmd_struct.an_parm0 = AN_DESCRIPTOR_RX; 569108401Sambrisko cmd_struct.an_parm1 = AN_RX_DESC_OFFSET; 570108401Sambrisko cmd_struct.an_parm2 = AN_MAX_RX_DESC; 571108401Sambrisko if (an_cmd_struct(sc, &cmd_struct, &reply)) { 572108401Sambrisko printf("an%d: failed to allocate RX descriptor\n", 573108401Sambrisko sc->an_unit); 574108401Sambrisko return(EIO); 575108401Sambrisko } 576108401Sambrisko 577108401Sambrisko for (desc = 0; desc < AN_MAX_RX_DESC; desc++) { 578108401Sambrisko bzero(&an_rx_desc, sizeof(an_rx_desc)); 579108401Sambrisko an_rx_desc.an_valid = 1; 580108401Sambrisko an_rx_desc.an_len = AN_RX_BUFFER_SIZE; 581108401Sambrisko an_rx_desc.an_done = 0; 582108401Sambrisko an_rx_desc.an_phys = sc->an_rx_buffer[desc].an_dma_paddr; 583108401Sambrisko 584108401Sambrisko for (i = 0; i < sizeof(an_rx_desc) / 4; i++) 585155321Simp CSR_MEM_AUX_WRITE_4(sc, AN_RX_DESC_OFFSET 586155321Simp + (desc * sizeof(an_rx_desc)) 587155321Simp + (i * 4), 588155321Simp ((u_int32_t *)(void *)&an_rx_desc)[i]); 589108401Sambrisko } 590108401Sambrisko 591108401Sambrisko /* 592108401Sambrisko * Allocate TX descriptor 593108401Sambrisko */ 594108401Sambrisko 595108401Sambrisko bzero(&reply,sizeof(reply)); 596108401Sambrisko cmd_struct.an_cmd = AN_CMD_ALLOC_DESC; 597108401Sambrisko cmd_struct.an_parm0 = AN_DESCRIPTOR_TX; 598108401Sambrisko cmd_struct.an_parm1 = AN_TX_DESC_OFFSET; 599108401Sambrisko cmd_struct.an_parm2 = AN_MAX_TX_DESC; 600108401Sambrisko if (an_cmd_struct(sc, &cmd_struct, &reply)) { 601108401Sambrisko printf("an%d: failed to allocate TX descriptor\n", 602108401Sambrisko sc->an_unit); 603108401Sambrisko return(EIO); 604108401Sambrisko } 605108401Sambrisko 606108401Sambrisko for (desc = 0; desc < AN_MAX_TX_DESC; desc++) { 607108401Sambrisko bzero(&an_tx_desc, sizeof(an_tx_desc)); 608108401Sambrisko an_tx_desc.an_offset = 0; 609108401Sambrisko an_tx_desc.an_eoc = 0; 610108401Sambrisko an_tx_desc.an_valid = 0; 611108401Sambrisko an_tx_desc.an_len = 0; 612108401Sambrisko an_tx_desc.an_phys = sc->an_tx_buffer[desc].an_dma_paddr; 613108401Sambrisko 614108401Sambrisko for (i = 0; i < sizeof(an_tx_desc) / 4; i++) 615108401Sambrisko CSR_MEM_AUX_WRITE_4(sc, AN_TX_DESC_OFFSET 616155321Simp + (desc * sizeof(an_tx_desc)) 617155321Simp + (i * 4), 618155321Simp ((u_int32_t *)(void *)&an_tx_desc)[i]); 619108401Sambrisko } 620108401Sambrisko 621108401Sambrisko /* 622108401Sambrisko * Allocate RID descriptor 623108401Sambrisko */ 624108401Sambrisko 625108401Sambrisko bzero(&reply,sizeof(reply)); 626108401Sambrisko cmd_struct.an_cmd = AN_CMD_ALLOC_DESC; 627108401Sambrisko cmd_struct.an_parm0 = AN_DESCRIPTOR_HOSTRW; 628108401Sambrisko cmd_struct.an_parm1 = AN_HOST_DESC_OFFSET; 629108401Sambrisko cmd_struct.an_parm2 = 1; 630108401Sambrisko if (an_cmd_struct(sc, &cmd_struct, &reply)) { 631108401Sambrisko printf("an%d: failed to allocate host descriptor\n", 632108401Sambrisko sc->an_unit); 633108401Sambrisko return(EIO); 634108401Sambrisko } 635108401Sambrisko 636108401Sambrisko bzero(&an_rid_desc, sizeof(an_rid_desc)); 637108401Sambrisko an_rid_desc.an_valid = 1; 638108401Sambrisko an_rid_desc.an_len = AN_RID_BUFFER_SIZE; 639108401Sambrisko an_rid_desc.an_rid = 0; 640108401Sambrisko an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr; 641108401Sambrisko 642108401Sambrisko for (i = 0; i < sizeof(an_rid_desc) / 4; i++) 643108401Sambrisko CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4, 644155321Simp ((u_int32_t *)(void *)&an_rid_desc)[i]); 645108401Sambrisko 646108401Sambrisko return(0); 647108401Sambrisko} 648108401Sambrisko 649108401Sambriskoint 650150446Simpan_attach(struct an_softc *sc, int unit, int flags) 65155992Swpaul{ 652147256Sbrooks struct ifnet *ifp; 653113316Simp int error = EIO; 654110253Sambrisko int i, nrate, mword; 655110253Sambrisko u_int8_t r; 65655992Swpaul 65793818Sjhb mtx_init(&sc->an_mtx, device_get_nameunit(sc->an_dev), MTX_NETWORK_LOCK, 65893818Sjhb MTX_DEF | MTX_RECURSE); 659147380Sdelphij ifp = sc->an_ifp = if_alloc(IFT_ETHER); 660147256Sbrooks if (ifp == NULL) { 661147256Sbrooks printf("an%d: can not if_alloc()\n", sc->an_unit); 662147256Sbrooks goto fail; 663147256Sbrooks } 664147256Sbrooks 66555992Swpaul sc->an_gone = 0; 66655992Swpaul sc->an_associated = 0; 66783269Sbrooks sc->an_monitor = 0; 66883269Sbrooks sc->an_was_monitor = 0; 669108401Sambrisko sc->an_flash_buffer = NULL; 67055992Swpaul 67155992Swpaul /* Reset the NIC. */ 67255992Swpaul an_reset(sc); 673110104Sambrisko if (sc->mpi350) { 674108401Sambrisko error = an_init_mpi350_desc(sc); 675108401Sambrisko if (error) 676113316Simp goto fail; 677108401Sambrisko } 67855992Swpaul 67955992Swpaul /* Load factory config */ 68055992Swpaul if (an_cmd(sc, AN_CMD_READCFG, 0)) { 68155992Swpaul printf("an%d: failed to load config data\n", sc->an_unit); 682113316Simp goto fail; 68355992Swpaul } 68455992Swpaul 68555992Swpaul /* Read the current configuration */ 68655992Swpaul sc->an_config.an_type = AN_RID_GENCONFIG; 68755992Swpaul sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 68855992Swpaul if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_config)) { 68955992Swpaul printf("an%d: read record failed\n", sc->an_unit); 690113316Simp goto fail; 69155992Swpaul } 69255992Swpaul 69355992Swpaul /* Read the card capabilities */ 69455992Swpaul sc->an_caps.an_type = AN_RID_CAPABILITIES; 69555992Swpaul sc->an_caps.an_len = sizeof(struct an_ltv_caps); 69655992Swpaul if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_caps)) { 69755992Swpaul printf("an%d: read record failed\n", sc->an_unit); 698113316Simp goto fail; 69955992Swpaul } 70055992Swpaul 70155992Swpaul /* Read ssid list */ 70255992Swpaul sc->an_ssidlist.an_type = AN_RID_SSIDLIST; 703119156Sambrisko sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist_new); 70455992Swpaul if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) { 70555992Swpaul printf("an%d: read record failed\n", sc->an_unit); 706113316Simp goto fail; 70755992Swpaul } 70855992Swpaul 70955992Swpaul /* Read AP list */ 71055992Swpaul sc->an_aplist.an_type = AN_RID_APLIST; 71155992Swpaul sc->an_aplist.an_len = sizeof(struct an_ltv_aplist); 71255992Swpaul if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) { 71355992Swpaul printf("an%d: read record failed\n", sc->an_unit); 714113316Simp goto fail; 71555992Swpaul } 71655992Swpaul 717108401Sambrisko#ifdef ANCACHE 718108401Sambrisko /* Read the RSSI <-> dBm map */ 719108401Sambrisko sc->an_have_rssimap = 0; 720108401Sambrisko if (sc->an_caps.an_softcaps & 8) { 721108401Sambrisko sc->an_rssimap.an_type = AN_RID_RSSI_MAP; 722108401Sambrisko sc->an_rssimap.an_len = sizeof(struct an_ltv_rssi_map); 723108401Sambrisko if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_rssimap)) { 724108401Sambrisko printf("an%d: unable to get RSSI <-> dBM map\n", sc->an_unit); 725108401Sambrisko } else { 726108401Sambrisko printf("an%d: got RSSI <-> dBM map\n", sc->an_unit); 727108401Sambrisko sc->an_have_rssimap = 1; 728108401Sambrisko } 729108401Sambrisko } else { 730108401Sambrisko printf("an%d: no RSSI <-> dBM map\n", sc->an_unit); 731108401Sambrisko } 732108401Sambrisko#endif 733108401Sambrisko 73455992Swpaul ifp->if_softc = sc; 735121816Sbrooks sc->an_unit = unit; 736121816Sbrooks if_initname(ifp, device_get_name(sc->an_dev), 737121816Sbrooks device_get_unit(sc->an_dev)); 73855992Swpaul ifp->if_mtu = ETHERMTU; 73955992Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 74055992Swpaul ifp->if_ioctl = an_ioctl; 74155992Swpaul ifp->if_start = an_start; 74255992Swpaul ifp->if_watchdog = an_watchdog; 74355992Swpaul ifp->if_init = an_init; 74455992Swpaul ifp->if_baudrate = 10000000; 745132986Smlaier IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 746132986Smlaier ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; 747132986Smlaier IFQ_SET_READY(&ifp->if_snd); 74855992Swpaul 74955992Swpaul bzero(sc->an_config.an_nodename, sizeof(sc->an_config.an_nodename)); 75055992Swpaul bcopy(AN_DEFAULT_NODENAME, sc->an_config.an_nodename, 75155992Swpaul sizeof(AN_DEFAULT_NODENAME) - 1); 75255992Swpaul 753119156Sambrisko bzero(sc->an_ssidlist.an_entry[0].an_ssid, 754119156Sambrisko sizeof(sc->an_ssidlist.an_entry[0].an_ssid)); 755119156Sambrisko bcopy(AN_DEFAULT_NETNAME, sc->an_ssidlist.an_entry[0].an_ssid, 75655992Swpaul sizeof(AN_DEFAULT_NETNAME) - 1); 757119156Sambrisko sc->an_ssidlist.an_entry[0].an_len = strlen(AN_DEFAULT_NETNAME); 75855992Swpaul 75955992Swpaul sc->an_config.an_opmode = 76074144Sassar AN_OPMODE_INFRASTRUCTURE_STATION; 76155992Swpaul 76255992Swpaul sc->an_tx_rate = 0; 76355992Swpaul bzero((char *)&sc->an_stats, sizeof(sc->an_stats)); 76455992Swpaul 765110253Sambrisko nrate = 8; 766110253Sambrisko 76777217Sphk ifmedia_init(&sc->an_ifmedia, 0, an_media_change, an_media_status); 768110253Sambrisko if_printf(ifp, "supported rates: "); 769110253Sambrisko#define ADD(s, o) ifmedia_add(&sc->an_ifmedia, \ 770110253Sambrisko IFM_MAKEWORD(IFM_IEEE80211, (s), (o), 0), 0, NULL) 771110253Sambrisko ADD(IFM_AUTO, 0); 772110253Sambrisko ADD(IFM_AUTO, IFM_IEEE80211_ADHOC); 773110253Sambrisko for (i = 0; i < nrate; i++) { 774110253Sambrisko r = sc->an_caps.an_rates[i]; 775116951Ssam mword = ieee80211_rate2media(NULL, r, IEEE80211_T_DS); 776110253Sambrisko if (mword == 0) 777110253Sambrisko continue; 778110253Sambrisko printf("%s%d%sMbps", (i != 0 ? " " : ""), 779110253Sambrisko (r & IEEE80211_RATE_VAL) / 2, ((r & 0x1) != 0 ? ".5" : "")); 780110253Sambrisko ADD(mword, 0); 781110253Sambrisko ADD(mword, IFM_IEEE80211_ADHOC); 78277217Sphk } 783110253Sambrisko printf("\n"); 784110253Sambrisko ifmedia_set(&sc->an_ifmedia, IFM_MAKEWORD(IFM_IEEE80211, 785110253Sambrisko IFM_AUTO, 0, 0)); 786110253Sambrisko#undef ADD 78777217Sphk 78855992Swpaul /* 78963090Sarchie * Call MI attach routine. 79055992Swpaul */ 791147256Sbrooks 792147256Sbrooks ether_ifattach(ifp, sc->an_caps.an_oemaddr); 79355992Swpaul callout_handle_init(&sc->an_stat_ch); 79455992Swpaul 79555992Swpaul return(0); 796113316Simpfail:; 797113316Simp mtx_destroy(&sc->an_mtx); 798147256Sbrooks if (ifp != NULL) 799147256Sbrooks if_free(ifp); 800113316Simp return(error); 80155992Swpaul} 80255992Swpaul 803123978Sambriskoint 804123978Sambriskoan_detach(device_t dev) 805123978Sambrisko{ 806123978Sambrisko struct an_softc *sc = device_get_softc(dev); 807147256Sbrooks struct ifnet *ifp = sc->an_ifp; 808123978Sambrisko 809123978Sambrisko if (sc->an_gone) { 810123978Sambrisko device_printf(dev,"already unloaded\n"); 811123978Sambrisko return(0); 812123978Sambrisko } 813148639Semax AN_LOCK(sc); 814123978Sambrisko an_stop(sc); 815148454Semax sc->an_gone = 1; 816123978Sambrisko ifmedia_removeall(&sc->an_ifmedia); 817148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 818148454Semax AN_UNLOCK(sc); 819123978Sambrisko ether_ifdetach(ifp); 820150306Simp bus_teardown_intr(dev, sc->irq_res, sc->irq_handle); 821147256Sbrooks if_free(ifp); 822123978Sambrisko an_release_resources(dev); 823123978Sambrisko mtx_destroy(&sc->an_mtx); 824123978Sambrisko return (0); 825123978Sambrisko} 826123978Sambrisko 82783270Sbrooksstatic void 828150446Simpan_rxeof(struct an_softc *sc) 82955992Swpaul{ 83083269Sbrooks struct ifnet *ifp; 83183269Sbrooks struct ether_header *eh; 83283269Sbrooks struct ieee80211_frame *ih; 83383269Sbrooks struct an_rxframe rx_frame; 83483269Sbrooks struct an_rxframe_802_3 rx_frame_802_3; 83583269Sbrooks struct mbuf *m; 836108401Sambrisko int len, id, error = 0, i, count = 0; 837108401Sambrisko int ieee80211_header_len; 838108401Sambrisko u_char *bpf_buf; 839108401Sambrisko u_short fc1; 840108401Sambrisko struct an_card_rx_desc an_rx_desc; 841108401Sambrisko u_int8_t *buf; 84255992Swpaul 843122689Ssam AN_LOCK_ASSERT(sc); 844122689Ssam 845147256Sbrooks ifp = sc->an_ifp; 84655992Swpaul 847108401Sambrisko if (!sc->mpi350) { 848108401Sambrisko id = CSR_READ_2(sc, AN_RX_FID); 84955992Swpaul 850108401Sambrisko if (sc->an_monitor && (ifp->if_flags & IFF_PROMISC)) { 851108401Sambrisko /* read raw 802.11 packet */ 852108401Sambrisko bpf_buf = sc->buf_802_11; 85355992Swpaul 854108401Sambrisko /* read header */ 855108401Sambrisko if (an_read_data(sc, id, 0x0, (caddr_t)&rx_frame, 856108401Sambrisko sizeof(rx_frame))) { 857108401Sambrisko ifp->if_ierrors++; 858108401Sambrisko return; 859108401Sambrisko } 86055992Swpaul 861108401Sambrisko /* 862108401Sambrisko * skip beacon by default since this increases the 863108401Sambrisko * system load a lot 864108401Sambrisko */ 86583270Sbrooks 866108401Sambrisko if (!(sc->an_monitor & AN_MONITOR_INCLUDE_BEACON) && 867108401Sambrisko (rx_frame.an_frame_ctl & 868108401Sambrisko IEEE80211_FC0_SUBTYPE_BEACON)) { 86983269Sbrooks return; 87083269Sbrooks } 87155992Swpaul 872108401Sambrisko if (sc->an_monitor & AN_MONITOR_AIRONET_HEADER) { 873108401Sambrisko len = rx_frame.an_rx_payload_len 874108401Sambrisko + sizeof(rx_frame); 875108401Sambrisko /* Check for insane frame length */ 876108401Sambrisko if (len > sizeof(sc->buf_802_11)) { 877108401Sambrisko printf("an%d: oversized packet " 878108401Sambrisko "received (%d, %d)\n", 879108401Sambrisko sc->an_unit, len, MCLBYTES); 880108401Sambrisko ifp->if_ierrors++; 881108401Sambrisko return; 882108401Sambrisko } 88355992Swpaul 884108401Sambrisko bcopy((char *)&rx_frame, 885108401Sambrisko bpf_buf, sizeof(rx_frame)); 886108401Sambrisko 887108401Sambrisko error = an_read_data(sc, id, sizeof(rx_frame), 888108401Sambrisko (caddr_t)bpf_buf+sizeof(rx_frame), 889108401Sambrisko rx_frame.an_rx_payload_len); 890108401Sambrisko } else { 891108401Sambrisko fc1=rx_frame.an_frame_ctl >> 8; 892108401Sambrisko ieee80211_header_len = 893108401Sambrisko sizeof(struct ieee80211_frame); 894108401Sambrisko if ((fc1 & IEEE80211_FC1_DIR_TODS) && 895108401Sambrisko (fc1 & IEEE80211_FC1_DIR_FROMDS)) { 896108401Sambrisko ieee80211_header_len += ETHER_ADDR_LEN; 897108401Sambrisko } 898108401Sambrisko 899108401Sambrisko len = rx_frame.an_rx_payload_len 900108401Sambrisko + ieee80211_header_len; 901108401Sambrisko /* Check for insane frame length */ 902108401Sambrisko if (len > sizeof(sc->buf_802_11)) { 903108401Sambrisko printf("an%d: oversized packet " 904108401Sambrisko "received (%d, %d)\n", 905108401Sambrisko sc->an_unit, len, MCLBYTES); 906108401Sambrisko ifp->if_ierrors++; 907108401Sambrisko return; 908108401Sambrisko } 909108401Sambrisko 910108401Sambrisko ih = (struct ieee80211_frame *)bpf_buf; 911108401Sambrisko 912108401Sambrisko bcopy((char *)&rx_frame.an_frame_ctl, 913108401Sambrisko (char *)ih, ieee80211_header_len); 914108401Sambrisko 915108401Sambrisko error = an_read_data(sc, id, sizeof(rx_frame) + 916108401Sambrisko rx_frame.an_gaplen, 917108401Sambrisko (caddr_t)ih +ieee80211_header_len, 918108401Sambrisko rx_frame.an_rx_payload_len); 919108401Sambrisko } 920108401Sambrisko /* dump raw 802.11 packet to bpf and skip ip stack */ 921108401Sambrisko BPF_TAP(ifp, bpf_buf, len); 92283270Sbrooks } else { 923111119Simp MGETHDR(m, M_DONTWAIT, MT_DATA); 924108401Sambrisko if (m == NULL) { 925108401Sambrisko ifp->if_ierrors++; 926108401Sambrisko return; 92783269Sbrooks } 928111119Simp MCLGET(m, M_DONTWAIT); 929108401Sambrisko if (!(m->m_flags & M_EXT)) { 930108401Sambrisko m_freem(m); 931108401Sambrisko ifp->if_ierrors++; 932108401Sambrisko return; 933108401Sambrisko } 934108401Sambrisko m->m_pkthdr.rcvif = ifp; 935108401Sambrisko /* Read Ethernet encapsulated packet */ 93655992Swpaul 937108401Sambrisko#ifdef ANCACHE 938108401Sambrisko /* Read NIC frame header */ 939108401Sambrisko if (an_read_data(sc, id, 0, (caddr_t)&rx_frame, 940108401Sambrisko sizeof(rx_frame))) { 941154394Srwatson m_freem(m); 942108401Sambrisko ifp->if_ierrors++; 943108401Sambrisko return; 944108401Sambrisko } 945108401Sambrisko#endif 946108401Sambrisko /* Read in the 802_3 frame header */ 947108401Sambrisko if (an_read_data(sc, id, 0x34, 948108401Sambrisko (caddr_t)&rx_frame_802_3, 949108401Sambrisko sizeof(rx_frame_802_3))) { 950154394Srwatson m_freem(m); 951108401Sambrisko ifp->if_ierrors++; 952108401Sambrisko return; 953108401Sambrisko } 954108401Sambrisko if (rx_frame_802_3.an_rx_802_3_status != 0) { 955154394Srwatson m_freem(m); 956108401Sambrisko ifp->if_ierrors++; 957108401Sambrisko return; 958108401Sambrisko } 95983269Sbrooks /* Check for insane frame length */ 960108401Sambrisko len = rx_frame_802_3.an_rx_802_3_payload_len; 96183269Sbrooks if (len > sizeof(sc->buf_802_11)) { 962154394Srwatson m_freem(m); 963108401Sambrisko printf("an%d: oversized packet " 964108401Sambrisko "received (%d, %d)\n", 96583269Sbrooks sc->an_unit, len, MCLBYTES); 96683269Sbrooks ifp->if_ierrors++; 96783269Sbrooks return; 96883269Sbrooks } 969108401Sambrisko m->m_pkthdr.len = m->m_len = 970108401Sambrisko rx_frame_802_3.an_rx_802_3_payload_len + 12; 97155992Swpaul 972108401Sambrisko eh = mtod(m, struct ether_header *); 97355992Swpaul 974108401Sambrisko bcopy((char *)&rx_frame_802_3.an_rx_dst_addr, 975108401Sambrisko (char *)&eh->ether_dhost, ETHER_ADDR_LEN); 976108401Sambrisko bcopy((char *)&rx_frame_802_3.an_rx_src_addr, 977108401Sambrisko (char *)&eh->ether_shost, ETHER_ADDR_LEN); 97855992Swpaul 979108401Sambrisko /* in mbuf header type is just before payload */ 980108401Sambrisko error = an_read_data(sc, id, 0x44, 981108401Sambrisko (caddr_t)&(eh->ether_type), 982108401Sambrisko rx_frame_802_3.an_rx_802_3_payload_len); 98355992Swpaul 984108401Sambrisko if (error) { 985108401Sambrisko m_freem(m); 986108401Sambrisko ifp->if_ierrors++; 987108401Sambrisko return; 988108401Sambrisko } 989108401Sambrisko ifp->if_ipackets++; 990108401Sambrisko 991108401Sambrisko /* Receive packet. */ 99283269Sbrooks#ifdef ANCACHE 993108401Sambrisko an_cache_store(sc, eh, m, 994110253Sambrisko rx_frame.an_rx_signal_strength, 995110253Sambrisko rx_frame.an_rsvd0); 99683269Sbrooks#endif 997122689Ssam AN_UNLOCK(sc); 998108401Sambrisko (*ifp->if_input)(ifp, m); 999122689Ssam AN_LOCK(sc); 100083269Sbrooks } 100155992Swpaul 1002108401Sambrisko } else { /* MPI-350 */ 1003108401Sambrisko for (count = 0; count < AN_MAX_RX_DESC; count++){ 1004108401Sambrisko for (i = 0; i < sizeof(an_rx_desc) / 4; i++) 1005155321Simp ((u_int32_t *)(void *)&an_rx_desc)[i] 1006108401Sambrisko = CSR_MEM_AUX_READ_4(sc, 1007108401Sambrisko AN_RX_DESC_OFFSET 1008108401Sambrisko + (count * sizeof(an_rx_desc)) 1009108401Sambrisko + (i * 4)); 101083269Sbrooks 1011108401Sambrisko if (an_rx_desc.an_done && !an_rx_desc.an_valid) { 1012108401Sambrisko buf = sc->an_rx_buffer[count].an_dma_vaddr; 101383269Sbrooks 1014111119Simp MGETHDR(m, M_DONTWAIT, MT_DATA); 1015108401Sambrisko if (m == NULL) { 1016108401Sambrisko ifp->if_ierrors++; 1017108401Sambrisko return; 1018108401Sambrisko } 1019111119Simp MCLGET(m, M_DONTWAIT); 1020108401Sambrisko if (!(m->m_flags & M_EXT)) { 1021108401Sambrisko m_freem(m); 1022108401Sambrisko ifp->if_ierrors++; 1023108401Sambrisko return; 1024108401Sambrisko } 1025108401Sambrisko m->m_pkthdr.rcvif = ifp; 1026108401Sambrisko /* Read Ethernet encapsulated packet */ 102783269Sbrooks 1028108401Sambrisko /* 1029108401Sambrisko * No ANCACHE support since we just get back 1030108401Sambrisko * an Ethernet packet no 802.11 info 1031108401Sambrisko */ 1032108401Sambrisko#if 0 1033108401Sambrisko#ifdef ANCACHE 1034108401Sambrisko /* Read NIC frame header */ 1035108401Sambrisko bcopy(buf, (caddr_t)&rx_frame, 1036108401Sambrisko sizeof(rx_frame)); 1037108401Sambrisko#endif 1038108401Sambrisko#endif 1039108401Sambrisko /* Check for insane frame length */ 1040108401Sambrisko len = an_rx_desc.an_len + 12; 1041108401Sambrisko if (len > MCLBYTES) { 1042154393Srwatson m_freem(m); 1043108401Sambrisko printf("an%d: oversized packet " 1044108401Sambrisko "received (%d, %d)\n", 1045108401Sambrisko sc->an_unit, len, MCLBYTES); 1046108401Sambrisko ifp->if_ierrors++; 1047108401Sambrisko return; 1048108401Sambrisko } 104983269Sbrooks 1050108401Sambrisko m->m_pkthdr.len = m->m_len = 1051108401Sambrisko an_rx_desc.an_len + 12; 1052108401Sambrisko 1053108401Sambrisko eh = mtod(m, struct ether_header *); 1054108401Sambrisko 1055108401Sambrisko bcopy(buf, (char *)eh, 1056108401Sambrisko m->m_pkthdr.len); 1057108401Sambrisko 1058108401Sambrisko ifp->if_ipackets++; 1059108401Sambrisko 1060108401Sambrisko /* Receive packet. */ 1061108401Sambrisko#if 0 106255992Swpaul#ifdef ANCACHE 1063108401Sambrisko an_cache_store(sc, eh, m, 1064110253Sambrisko rx_frame.an_rx_signal_strength, 1065110253Sambrisko rx_frame.an_rsvd0); 106655992Swpaul#endif 1067108401Sambrisko#endif 1068171775Savatar AN_UNLOCK(sc); 1069108401Sambrisko (*ifp->if_input)(ifp, m); 1070171775Savatar AN_LOCK(sc); 1071171775Savatar 1072108401Sambrisko an_rx_desc.an_valid = 1; 1073108401Sambrisko an_rx_desc.an_len = AN_RX_BUFFER_SIZE; 1074108401Sambrisko an_rx_desc.an_done = 0; 1075108401Sambrisko an_rx_desc.an_phys = 1076108401Sambrisko sc->an_rx_buffer[count].an_dma_paddr; 1077108401Sambrisko 1078108401Sambrisko for (i = 0; i < sizeof(an_rx_desc) / 4; i++) 1079108401Sambrisko CSR_MEM_AUX_WRITE_4(sc, 1080155321Simp AN_RX_DESC_OFFSET 1081155321Simp + (count * sizeof(an_rx_desc)) 1082155321Simp + (i * 4), 1083155321Simp ((u_int32_t *)(void *)&an_rx_desc)[i]); 1084108401Sambrisko 1085108401Sambrisko } else { 1086108401Sambrisko printf("an%d: Didn't get valid RX packet " 1087108401Sambrisko "%x %x %d\n", 1088108401Sambrisko sc->an_unit, 1089108401Sambrisko an_rx_desc.an_done, 1090108401Sambrisko an_rx_desc.an_valid, an_rx_desc.an_len); 1091108401Sambrisko } 1092108401Sambrisko } 109383269Sbrooks } 109455992Swpaul} 109555992Swpaul 109683270Sbrooksstatic void 1097150446Simpan_txeof(struct an_softc *sc, int status) 109855992Swpaul{ 109955992Swpaul struct ifnet *ifp; 110078639Sbrooks int id, i; 110155992Swpaul 1102147256Sbrooks ifp = sc->an_ifp; 110355992Swpaul 110455992Swpaul ifp->if_timer = 0; 1105148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 110655992Swpaul 1107108401Sambrisko if (!sc->mpi350) { 1108119156Sambrisko id = CSR_READ_2(sc, AN_TX_CMP_FID(sc->mpi350)); 110955992Swpaul 1110108401Sambrisko if (status & AN_EV_TX_EXC) { 1111108401Sambrisko ifp->if_oerrors++; 1112108401Sambrisko } else 1113108401Sambrisko ifp->if_opackets++; 111455992Swpaul 1115108401Sambrisko for (i = 0; i < AN_TX_RING_CNT; i++) { 1116108401Sambrisko if (id == sc->an_rdata.an_tx_ring[i]) { 1117108401Sambrisko sc->an_rdata.an_tx_ring[i] = 0; 1118108401Sambrisko break; 1119108401Sambrisko } 112078639Sbrooks } 1121108401Sambrisko 1122108401Sambrisko AN_INC(sc->an_rdata.an_tx_cons, AN_TX_RING_CNT); 1123108401Sambrisko } else { /* MPI 350 */ 1124119156Sambrisko id = CSR_READ_2(sc, AN_TX_CMP_FID(sc->mpi350)); 1125119156Sambrisko if (!sc->an_rdata.an_tx_empty){ 1126119156Sambrisko if (status & AN_EV_TX_EXC) { 1127119156Sambrisko ifp->if_oerrors++; 1128119156Sambrisko } else 1129119156Sambrisko ifp->if_opackets++; 1130119156Sambrisko AN_INC(sc->an_rdata.an_tx_cons, AN_MAX_TX_DESC); 1131119156Sambrisko if (sc->an_rdata.an_tx_prod == 1132119156Sambrisko sc->an_rdata.an_tx_cons) 1133119156Sambrisko sc->an_rdata.an_tx_empty = 1; 1134119156Sambrisko } 113578639Sbrooks } 113655992Swpaul 113755992Swpaul return; 113855992Swpaul} 113955992Swpaul 114055992Swpaul/* 114155992Swpaul * We abuse the stats updater to check the current NIC status. This 114255992Swpaul * is important because we don't want to allow transmissions until 114355992Swpaul * the NIC has synchronized to the current cell (either as the master 114455992Swpaul * in an ad-hoc group, or as a station connected to an access point). 114555992Swpaul */ 1146104094Sphkstatic void 1147150446Simpan_stats_update(void *xsc) 114855992Swpaul{ 114955992Swpaul struct an_softc *sc; 115055992Swpaul struct ifnet *ifp; 115155992Swpaul 115255992Swpaul sc = xsc; 115367094Swpaul AN_LOCK(sc); 1154147256Sbrooks ifp = sc->an_ifp; 115555992Swpaul 115655992Swpaul sc->an_status.an_type = AN_RID_STATUS; 115755992Swpaul sc->an_status.an_len = sizeof(struct an_ltv_status); 115855992Swpaul an_read_record(sc, (struct an_ltv_gen *)&sc->an_status); 115955992Swpaul 116055992Swpaul if (sc->an_status.an_opmode & AN_STATUS_OPMODE_IN_SYNC) 116155992Swpaul sc->an_associated = 1; 116255992Swpaul else 116355992Swpaul sc->an_associated = 0; 116455992Swpaul 116555992Swpaul /* Don't do this while we're transmitting */ 1166148887Srwatson if (ifp->if_drv_flags & IFF_DRV_OACTIVE) { 116755992Swpaul sc->an_stat_ch = timeout(an_stats_update, sc, hz); 116867094Swpaul AN_UNLOCK(sc); 116955992Swpaul return; 117055992Swpaul } 117155992Swpaul 117255992Swpaul sc->an_stats.an_len = sizeof(struct an_ltv_stats); 117355992Swpaul sc->an_stats.an_type = AN_RID_32BITS_CUM; 117455992Swpaul an_read_record(sc, (struct an_ltv_gen *)&sc->an_stats.an_len); 117555992Swpaul 117655992Swpaul sc->an_stat_ch = timeout(an_stats_update, sc, hz); 117767094Swpaul AN_UNLOCK(sc); 117855992Swpaul 117955992Swpaul return; 118055992Swpaul} 118155992Swpaul 118283270Sbrooksvoid 1183150446Simpan_intr(void *xsc) 118455992Swpaul{ 118555992Swpaul struct an_softc *sc; 118655992Swpaul struct ifnet *ifp; 118755992Swpaul u_int16_t status; 118855992Swpaul 118955992Swpaul sc = (struct an_softc*)xsc; 119055992Swpaul 119167094Swpaul AN_LOCK(sc); 119267094Swpaul 119367094Swpaul if (sc->an_gone) { 119467094Swpaul AN_UNLOCK(sc); 119555992Swpaul return; 119667094Swpaul } 119755992Swpaul 1198147256Sbrooks ifp = sc->an_ifp; 119955992Swpaul 120055992Swpaul /* Disable interrupts. */ 1201108401Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0); 120255992Swpaul 1203108401Sambrisko status = CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)); 1204119156Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), ~AN_INTRS(sc->mpi350)); 120555992Swpaul 1206119156Sambrisko if (status & AN_EV_MIC) { 1207119156Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_MIC); 120855992Swpaul } 120955992Swpaul 121055992Swpaul if (status & AN_EV_LINKSTAT) { 1211108401Sambrisko if (CSR_READ_2(sc, AN_LINKSTAT(sc->mpi350)) 1212108401Sambrisko == AN_LINKSTAT_ASSOCIATED) 121355992Swpaul sc->an_associated = 1; 121455992Swpaul else 121555992Swpaul sc->an_associated = 0; 1216108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_LINKSTAT); 121755992Swpaul } 121855992Swpaul 121955992Swpaul if (status & AN_EV_RX) { 122055992Swpaul an_rxeof(sc); 1221108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_RX); 122255992Swpaul } 122355992Swpaul 1224119156Sambrisko if (sc->mpi350 && status & AN_EV_TX_CPY) { 1225119156Sambrisko an_txeof(sc, status); 1226150446Simp CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX_CPY); 1227119156Sambrisko } 1228119156Sambrisko 122955992Swpaul if (status & AN_EV_TX) { 123055992Swpaul an_txeof(sc, status); 1231150446Simp CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX); 123255992Swpaul } 123355992Swpaul 123455992Swpaul if (status & AN_EV_TX_EXC) { 123555992Swpaul an_txeof(sc, status); 1236108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX_EXC); 123755992Swpaul } 123855992Swpaul 123955992Swpaul if (status & AN_EV_ALLOC) 1240108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC); 124155992Swpaul 124255992Swpaul /* Re-enable interrupts. */ 1243119156Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350)); 124455992Swpaul 1245132986Smlaier if ((ifp->if_flags & IFF_UP) && !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 124655992Swpaul an_start(ifp); 124755992Swpaul 124867094Swpaul AN_UNLOCK(sc); 124967094Swpaul 125055992Swpaul return; 125155992Swpaul} 125255992Swpaul 1253108401Sambrisko 125483270Sbrooksstatic int 1255150446Simpan_cmd_struct(struct an_softc *sc, struct an_command *cmd, 1256150446Simp struct an_reply *reply) 1257108401Sambrisko{ 1258108401Sambrisko int i; 1259108401Sambrisko 1260108401Sambrisko for (i = 0; i != AN_TIMEOUT; i++) { 1261108401Sambrisko if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) { 1262110531Sambrisko DELAY(1000); 1263110104Sambrisko } else 1264108401Sambrisko break; 1265108401Sambrisko } 1266119156Sambrisko 1267108401Sambrisko if( i == AN_TIMEOUT) { 1268108401Sambrisko printf("BUSY\n"); 1269108401Sambrisko return(ETIMEDOUT); 1270108401Sambrisko } 1271108401Sambrisko 1272108401Sambrisko CSR_WRITE_2(sc, AN_PARAM0(sc->mpi350), cmd->an_parm0); 1273108401Sambrisko CSR_WRITE_2(sc, AN_PARAM1(sc->mpi350), cmd->an_parm1); 1274108401Sambrisko CSR_WRITE_2(sc, AN_PARAM2(sc->mpi350), cmd->an_parm2); 1275108401Sambrisko CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd->an_cmd); 1276108401Sambrisko 1277108401Sambrisko for (i = 0; i < AN_TIMEOUT; i++) { 1278108401Sambrisko if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_CMD) 1279108401Sambrisko break; 1280110531Sambrisko DELAY(1000); 1281108401Sambrisko } 1282108401Sambrisko 1283108401Sambrisko reply->an_resp0 = CSR_READ_2(sc, AN_RESP0(sc->mpi350)); 1284108401Sambrisko reply->an_resp1 = CSR_READ_2(sc, AN_RESP1(sc->mpi350)); 1285108401Sambrisko reply->an_resp2 = CSR_READ_2(sc, AN_RESP2(sc->mpi350)); 1286108401Sambrisko reply->an_status = CSR_READ_2(sc, AN_STATUS(sc->mpi350)); 1287108401Sambrisko 1288108401Sambrisko if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) 1289119156Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), 1290119156Sambrisko AN_EV_CLR_STUCK_BUSY); 1291108401Sambrisko 1292108401Sambrisko /* Ack the command */ 1293108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CMD); 1294108401Sambrisko 1295108401Sambrisko if (i == AN_TIMEOUT) 1296108401Sambrisko return(ETIMEDOUT); 1297108401Sambrisko 1298108401Sambrisko return(0); 1299108401Sambrisko} 1300108401Sambrisko 1301108401Sambriskostatic int 1302150446Simpan_cmd(struct an_softc *sc, int cmd, int val) 130355992Swpaul{ 130455992Swpaul int i, s = 0; 130555992Swpaul 1306108401Sambrisko CSR_WRITE_2(sc, AN_PARAM0(sc->mpi350), val); 1307108401Sambrisko CSR_WRITE_2(sc, AN_PARAM1(sc->mpi350), 0); 1308108401Sambrisko CSR_WRITE_2(sc, AN_PARAM2(sc->mpi350), 0); 1309108401Sambrisko CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd); 131055992Swpaul 131155992Swpaul for (i = 0; i < AN_TIMEOUT; i++) { 1312108401Sambrisko if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_CMD) 131355992Swpaul break; 131455992Swpaul else { 1315108401Sambrisko if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) == cmd) 1316108401Sambrisko CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd); 131755992Swpaul } 131855992Swpaul } 131955992Swpaul 132055992Swpaul for (i = 0; i < AN_TIMEOUT; i++) { 1321108401Sambrisko CSR_READ_2(sc, AN_RESP0(sc->mpi350)); 1322108401Sambrisko CSR_READ_2(sc, AN_RESP1(sc->mpi350)); 1323108401Sambrisko CSR_READ_2(sc, AN_RESP2(sc->mpi350)); 1324108401Sambrisko s = CSR_READ_2(sc, AN_STATUS(sc->mpi350)); 132555992Swpaul if ((s & AN_STAT_CMD_CODE) == (cmd & AN_STAT_CMD_CODE)) 132655992Swpaul break; 132755992Swpaul } 132855992Swpaul 132955992Swpaul /* Ack the command */ 1330108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CMD); 133155992Swpaul 1332108401Sambrisko if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) 1333108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CLR_STUCK_BUSY); 133455992Swpaul 133555992Swpaul if (i == AN_TIMEOUT) 133655992Swpaul return(ETIMEDOUT); 133755992Swpaul 133855992Swpaul return(0); 133955992Swpaul} 134055992Swpaul 134155992Swpaul/* 134255992Swpaul * This reset sequence may look a little strange, but this is the 134355992Swpaul * most reliable method I've found to really kick the NIC in the 134455992Swpaul * head and force it to reboot correctly. 134555992Swpaul */ 134683270Sbrooksstatic void 1347150446Simpan_reset(struct an_softc *sc) 134855992Swpaul{ 134955992Swpaul if (sc->an_gone) 135055992Swpaul return; 135183270Sbrooks 135255992Swpaul an_cmd(sc, AN_CMD_ENABLE, 0); 135355992Swpaul an_cmd(sc, AN_CMD_FW_RESTART, 0); 135455992Swpaul an_cmd(sc, AN_CMD_NOOP2, 0); 135555992Swpaul 135655992Swpaul if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0) == ETIMEDOUT) 135755992Swpaul printf("an%d: reset failed\n", sc->an_unit); 135855992Swpaul 135955992Swpaul an_cmd(sc, AN_CMD_DISABLE, 0); 136055992Swpaul 136155992Swpaul return; 136255992Swpaul} 136355992Swpaul 136455992Swpaul/* 136555992Swpaul * Read an LTV record from the NIC. 136655992Swpaul */ 136783270Sbrooksstatic int 1368150446Simpan_read_record(struct an_softc *sc, struct an_ltv_gen *ltv) 136955992Swpaul{ 1370108401Sambrisko struct an_ltv_gen *an_ltv; 1371108401Sambrisko struct an_card_rid_desc an_rid_desc; 1372108401Sambrisko struct an_command cmd; 1373108401Sambrisko struct an_reply reply; 137455992Swpaul u_int16_t *ptr; 137578639Sbrooks u_int8_t *ptr2; 137655992Swpaul int i, len; 137755992Swpaul 137878639Sbrooks if (ltv->an_len < 4 || ltv->an_type == 0) 137955992Swpaul return(EINVAL); 138055992Swpaul 1381108401Sambrisko if (!sc->mpi350){ 1382108401Sambrisko /* Tell the NIC to enter record read mode. */ 1383108401Sambrisko if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) { 1384108401Sambrisko printf("an%d: RID access failed\n", sc->an_unit); 1385108401Sambrisko return(EIO); 1386108401Sambrisko } 138755992Swpaul 1388108401Sambrisko /* Seek to the record. */ 1389108401Sambrisko if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) { 1390108401Sambrisko printf("an%d: seek to record failed\n", sc->an_unit); 1391108401Sambrisko return(EIO); 1392108401Sambrisko } 139355992Swpaul 1394108401Sambrisko /* 1395108401Sambrisko * Read the length and record type and make sure they 1396108401Sambrisko * match what we expect (this verifies that we have enough 1397108401Sambrisko * room to hold all of the returned data). 1398108401Sambrisko * Length includes type but not length. 1399108401Sambrisko */ 1400108401Sambrisko len = CSR_READ_2(sc, AN_DATA1); 1401108401Sambrisko if (len > (ltv->an_len - 2)) { 1402108401Sambrisko printf("an%d: record length mismatch -- expected %d, " 1403108401Sambrisko "got %d for Rid %x\n", sc->an_unit, 1404108401Sambrisko ltv->an_len - 2, len, ltv->an_type); 1405108401Sambrisko len = ltv->an_len - 2; 1406108401Sambrisko } else { 1407108401Sambrisko ltv->an_len = len + 2; 1408108401Sambrisko } 1409108401Sambrisko 1410108401Sambrisko /* Now read the data. */ 1411108401Sambrisko len -= 2; /* skip the type */ 1412108401Sambrisko ptr = <v->an_val; 1413108401Sambrisko for (i = len; i > 1; i -= 2) 1414108401Sambrisko *ptr++ = CSR_READ_2(sc, AN_DATA1); 1415108401Sambrisko if (i) { 1416108401Sambrisko ptr2 = (u_int8_t *)ptr; 1417108401Sambrisko *ptr2 = CSR_READ_1(sc, AN_DATA1); 1418108401Sambrisko } 1419108401Sambrisko } else { /* MPI-350 */ 1420123978Sambrisko if (!sc->an_rid_buffer.an_dma_vaddr) 1421123978Sambrisko return(EIO); 1422108401Sambrisko an_rid_desc.an_valid = 1; 1423108401Sambrisko an_rid_desc.an_len = AN_RID_BUFFER_SIZE; 1424108401Sambrisko an_rid_desc.an_rid = 0; 1425108401Sambrisko an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr; 1426108401Sambrisko bzero(sc->an_rid_buffer.an_dma_vaddr, AN_RID_BUFFER_SIZE); 1427108401Sambrisko 1428108401Sambrisko bzero(&cmd, sizeof(cmd)); 1429108401Sambrisko bzero(&reply, sizeof(reply)); 1430108401Sambrisko cmd.an_cmd = AN_CMD_ACCESS|AN_ACCESS_READ; 1431108401Sambrisko cmd.an_parm0 = ltv->an_type; 1432108401Sambrisko 1433108401Sambrisko for (i = 0; i < sizeof(an_rid_desc) / 4; i++) 1434108401Sambrisko CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4, 1435155321Simp ((u_int32_t *)(void *)&an_rid_desc)[i]); 1436108401Sambrisko 1437108401Sambrisko if (an_cmd_struct(sc, &cmd, &reply) 1438108401Sambrisko || reply.an_status & AN_CMD_QUAL_MASK) { 1439108401Sambrisko printf("an%d: failed to read RID %x %x %x %x %x, %d\n", 1440108401Sambrisko sc->an_unit, ltv->an_type, 1441108401Sambrisko reply.an_status, 1442108401Sambrisko reply.an_resp0, 1443108401Sambrisko reply.an_resp1, 1444108401Sambrisko reply.an_resp2, 1445108401Sambrisko i); 1446108401Sambrisko return(EIO); 1447108401Sambrisko } 1448108401Sambrisko 1449108401Sambrisko an_ltv = (struct an_ltv_gen *)sc->an_rid_buffer.an_dma_vaddr; 1450108401Sambrisko if (an_ltv->an_len + 2 < an_rid_desc.an_len) { 1451108401Sambrisko an_rid_desc.an_len = an_ltv->an_len; 1452108401Sambrisko } 1453108401Sambrisko 1454123978Sambrisko len = an_rid_desc.an_len; 1455123978Sambrisko if (len > (ltv->an_len - 2)) { 1456123978Sambrisko printf("an%d: record length mismatch -- expected %d, " 1457123978Sambrisko "got %d for Rid %x\n", sc->an_unit, 1458123978Sambrisko ltv->an_len - 2, len, ltv->an_type); 1459123978Sambrisko len = ltv->an_len - 2; 1460123978Sambrisko } else { 1461123978Sambrisko ltv->an_len = len + 2; 1462123978Sambrisko } 1463123978Sambrisko bcopy(&an_ltv->an_type, 1464123978Sambrisko <v->an_val, 1465123978Sambrisko len); 146655992Swpaul } 146755992Swpaul 146878639Sbrooks if (an_dump) 146978639Sbrooks an_dump_record(sc, ltv, "Read"); 147055992Swpaul 147155992Swpaul return(0); 147255992Swpaul} 147355992Swpaul 147455992Swpaul/* 147555992Swpaul * Same as read, except we inject data instead of reading it. 147655992Swpaul */ 147783270Sbrooksstatic int 1478150446Simpan_write_record(struct an_softc *sc, struct an_ltv_gen *ltv) 147955992Swpaul{ 1480108401Sambrisko struct an_card_rid_desc an_rid_desc; 1481108401Sambrisko struct an_command cmd; 1482108401Sambrisko struct an_reply reply; 148355992Swpaul u_int16_t *ptr; 148478639Sbrooks u_int8_t *ptr2; 148578639Sbrooks int i, len; 148655992Swpaul 148778639Sbrooks if (an_dump) 148878639Sbrooks an_dump_record(sc, ltv, "Write"); 148978639Sbrooks 1490108401Sambrisko if (!sc->mpi350){ 1491108401Sambrisko if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) 1492108401Sambrisko return(EIO); 149383270Sbrooks 1494108401Sambrisko if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) 1495108401Sambrisko return(EIO); 1496108401Sambrisko 1497108401Sambrisko /* 1498108401Sambrisko * Length includes type but not length. 1499108401Sambrisko */ 1500108401Sambrisko len = ltv->an_len - 2; 1501108401Sambrisko CSR_WRITE_2(sc, AN_DATA1, len); 1502108401Sambrisko 1503108401Sambrisko len -= 2; /* skip the type */ 1504108401Sambrisko ptr = <v->an_val; 1505108401Sambrisko for (i = len; i > 1; i -= 2) 1506108401Sambrisko CSR_WRITE_2(sc, AN_DATA1, *ptr++); 1507108401Sambrisko if (i) { 1508108401Sambrisko ptr2 = (u_int8_t *)ptr; 1509108401Sambrisko CSR_WRITE_1(sc, AN_DATA0, *ptr2); 1510108401Sambrisko } 1511108401Sambrisko 1512108401Sambrisko if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_WRITE, ltv->an_type)) 1513108401Sambrisko return(EIO); 1514110104Sambrisko } else { 1515110104Sambrisko /* MPI-350 */ 1516108401Sambrisko 1517108401Sambrisko for (i = 0; i != AN_TIMEOUT; i++) { 1518110104Sambrisko if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) 1519110104Sambrisko & AN_CMD_BUSY) { 1520108401Sambrisko DELAY(10); 1521110104Sambrisko } else 1522108401Sambrisko break; 1523108401Sambrisko } 1524108401Sambrisko if (i == AN_TIMEOUT) { 1525108401Sambrisko printf("BUSY\n"); 1526108401Sambrisko } 1527108401Sambrisko 1528108401Sambrisko an_rid_desc.an_valid = 1; 1529108401Sambrisko an_rid_desc.an_len = ltv->an_len - 2; 1530108401Sambrisko an_rid_desc.an_rid = ltv->an_type; 1531108401Sambrisko an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr; 1532108401Sambrisko 1533108401Sambrisko bcopy(<v->an_type, sc->an_rid_buffer.an_dma_vaddr, 1534108401Sambrisko an_rid_desc.an_len); 1535108401Sambrisko 1536108401Sambrisko bzero(&cmd,sizeof(cmd)); 1537108401Sambrisko bzero(&reply,sizeof(reply)); 1538108401Sambrisko cmd.an_cmd = AN_CMD_ACCESS|AN_ACCESS_WRITE; 1539108401Sambrisko cmd.an_parm0 = ltv->an_type; 1540108401Sambrisko 1541108401Sambrisko for (i = 0; i < sizeof(an_rid_desc) / 4; i++) 1542108401Sambrisko CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4, 1543155321Simp ((u_int32_t *)(void *)&an_rid_desc)[i]); 1544108401Sambrisko 1545110531Sambrisko DELAY(100000); 1546110531Sambrisko 1547108401Sambrisko if ((i = an_cmd_struct(sc, &cmd, &reply))) { 1548110531Sambrisko printf("an%d: failed to write RID 1 %x %x %x %x %x, %d\n", 1549110104Sambrisko sc->an_unit, ltv->an_type, 1550110104Sambrisko reply.an_status, 1551110104Sambrisko reply.an_resp0, 1552110104Sambrisko reply.an_resp1, 1553110104Sambrisko reply.an_resp2, 1554110104Sambrisko i); 1555110104Sambrisko return(EIO); 1556108401Sambrisko } 155755992Swpaul 155883270Sbrooks 1559108401Sambrisko if (reply.an_status & AN_CMD_QUAL_MASK) { 1560110531Sambrisko printf("an%d: failed to write RID 2 %x %x %x %x %x, %d\n", 1561110104Sambrisko sc->an_unit, ltv->an_type, 1562110104Sambrisko reply.an_status, 1563110104Sambrisko reply.an_resp0, 1564110104Sambrisko reply.an_resp1, 1565110104Sambrisko reply.an_resp2, 1566110104Sambrisko i); 1567108401Sambrisko return(EIO); 1568108401Sambrisko } 1569110531Sambrisko DELAY(100000); 157078639Sbrooks } 157155992Swpaul 157255992Swpaul return(0); 157355992Swpaul} 157455992Swpaul 157583270Sbrooksstatic void 1576150446Simpan_dump_record(struct an_softc *sc, struct an_ltv_gen *ltv, char *string) 157778639Sbrooks{ 157878639Sbrooks u_int8_t *ptr2; 157978639Sbrooks int len; 158078639Sbrooks int i; 158178639Sbrooks int count = 0; 158278639Sbrooks char buf[17], temp; 158378639Sbrooks 158478639Sbrooks len = ltv->an_len - 4; 158583270Sbrooks printf("an%d: RID %4x, Length %4d, Mode %s\n", 158678639Sbrooks sc->an_unit, ltv->an_type, ltv->an_len - 4, string); 158778639Sbrooks 158878639Sbrooks if (an_dump == 1 || (an_dump == ltv->an_type)) { 158978639Sbrooks printf("an%d:\t", sc->an_unit); 159078639Sbrooks bzero(buf,sizeof(buf)); 159178639Sbrooks 159278639Sbrooks ptr2 = (u_int8_t *)<v->an_val; 159378639Sbrooks for (i = len; i > 0; i--) { 159478639Sbrooks printf("%02x ", *ptr2); 159578639Sbrooks 159678639Sbrooks temp = *ptr2++; 1597154866Snjl if (isprint(temp)) 159878639Sbrooks buf[count] = temp; 159978639Sbrooks else 160078639Sbrooks buf[count] = '.'; 160178639Sbrooks if (++count == 16) { 160278639Sbrooks count = 0; 160378639Sbrooks printf("%s\n",buf); 160478639Sbrooks printf("an%d:\t", sc->an_unit); 160578639Sbrooks bzero(buf,sizeof(buf)); 160678639Sbrooks } 160778639Sbrooks } 160878639Sbrooks for (; count != 16; count++) { 160978639Sbrooks printf(" "); 161078639Sbrooks } 161178639Sbrooks printf(" %s\n",buf); 161278639Sbrooks } 161378639Sbrooks} 161478639Sbrooks 161583270Sbrooksstatic int 1616150446Simpan_seek(struct an_softc *sc, int id, int off, int chan) 161755992Swpaul{ 161855992Swpaul int i; 161955992Swpaul int selreg, offreg; 162055992Swpaul 162155992Swpaul switch (chan) { 162255992Swpaul case AN_BAP0: 162355992Swpaul selreg = AN_SEL0; 162455992Swpaul offreg = AN_OFF0; 162555992Swpaul break; 162655992Swpaul case AN_BAP1: 162755992Swpaul selreg = AN_SEL1; 162855992Swpaul offreg = AN_OFF1; 162955992Swpaul break; 163055992Swpaul default: 163155992Swpaul printf("an%d: invalid data path: %x\n", sc->an_unit, chan); 163255992Swpaul return(EIO); 163355992Swpaul } 163455992Swpaul 163555992Swpaul CSR_WRITE_2(sc, selreg, id); 163655992Swpaul CSR_WRITE_2(sc, offreg, off); 163755992Swpaul 163855992Swpaul for (i = 0; i < AN_TIMEOUT; i++) { 163955992Swpaul if (!(CSR_READ_2(sc, offreg) & (AN_OFF_BUSY|AN_OFF_ERR))) 164055992Swpaul break; 164155992Swpaul } 164255992Swpaul 164355992Swpaul if (i == AN_TIMEOUT) 164455992Swpaul return(ETIMEDOUT); 164555992Swpaul 164655992Swpaul return(0); 164755992Swpaul} 164855992Swpaul 164983270Sbrooksstatic int 1650150446Simpan_read_data(struct an_softc *sc, int id, int off, caddr_t buf, int len) 165155992Swpaul{ 165255992Swpaul int i; 165355992Swpaul u_int16_t *ptr; 165455992Swpaul u_int8_t *ptr2; 165555992Swpaul 165655992Swpaul if (off != -1) { 165755992Swpaul if (an_seek(sc, id, off, AN_BAP1)) 165855992Swpaul return(EIO); 165955992Swpaul } 166055992Swpaul 166155992Swpaul ptr = (u_int16_t *)buf; 166278639Sbrooks for (i = len; i > 1; i -= 2) 166378639Sbrooks *ptr++ = CSR_READ_2(sc, AN_DATA1); 166478639Sbrooks if (i) { 166578639Sbrooks ptr2 = (u_int8_t *)ptr; 166678639Sbrooks *ptr2 = CSR_READ_1(sc, AN_DATA1); 166755992Swpaul } 166855992Swpaul 166955992Swpaul return(0); 167055992Swpaul} 167155992Swpaul 167283270Sbrooksstatic int 1673150446Simpan_write_data(struct an_softc *sc, int id, int off, caddr_t buf, int len) 167455992Swpaul{ 167555992Swpaul int i; 167655992Swpaul u_int16_t *ptr; 167755992Swpaul u_int8_t *ptr2; 167855992Swpaul 167955992Swpaul if (off != -1) { 168055992Swpaul if (an_seek(sc, id, off, AN_BAP0)) 168155992Swpaul return(EIO); 168255992Swpaul } 168355992Swpaul 168455992Swpaul ptr = (u_int16_t *)buf; 168578639Sbrooks for (i = len; i > 1; i -= 2) 168678639Sbrooks CSR_WRITE_2(sc, AN_DATA0, *ptr++); 168778639Sbrooks if (i) { 168878639Sbrooks ptr2 = (u_int8_t *)ptr; 168978639Sbrooks CSR_WRITE_1(sc, AN_DATA0, *ptr2); 169055992Swpaul } 169155992Swpaul 169255992Swpaul return(0); 169355992Swpaul} 169455992Swpaul 169555992Swpaul/* 169655992Swpaul * Allocate a region of memory inside the NIC and zero 169755992Swpaul * it out. 169855992Swpaul */ 169983270Sbrooksstatic int 1700150446Simpan_alloc_nicmem(struct an_softc *sc, int len, int *id) 170155992Swpaul{ 170255992Swpaul int i; 170355992Swpaul 170455992Swpaul if (an_cmd(sc, AN_CMD_ALLOC_MEM, len)) { 170555992Swpaul printf("an%d: failed to allocate %d bytes on NIC\n", 170655992Swpaul sc->an_unit, len); 170755992Swpaul return(ENOMEM); 170855992Swpaul } 170955992Swpaul 171055992Swpaul for (i = 0; i < AN_TIMEOUT; i++) { 1711108401Sambrisko if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_ALLOC) 171255992Swpaul break; 171355992Swpaul } 171455992Swpaul 171555992Swpaul if (i == AN_TIMEOUT) 171655992Swpaul return(ETIMEDOUT); 171755992Swpaul 1718108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC); 171955992Swpaul *id = CSR_READ_2(sc, AN_ALLOC_FID); 172055992Swpaul 172155992Swpaul if (an_seek(sc, *id, 0, AN_BAP0)) 172255992Swpaul return(EIO); 172355992Swpaul 172455992Swpaul for (i = 0; i < len / 2; i++) 172555992Swpaul CSR_WRITE_2(sc, AN_DATA0, 0); 172655992Swpaul 172755992Swpaul return(0); 172855992Swpaul} 172955992Swpaul 173083270Sbrooksstatic void 1731150446Simpan_setdef(struct an_softc *sc, struct an_req *areq) 173255992Swpaul{ 173355992Swpaul struct ifnet *ifp; 173455992Swpaul struct an_ltv_genconfig *cfg; 1735119156Sambrisko struct an_ltv_ssidlist_new *ssid; 173655992Swpaul struct an_ltv_aplist *ap; 173755992Swpaul struct an_ltv_gen *sp; 173855992Swpaul 1739147256Sbrooks ifp = sc->an_ifp; 174055992Swpaul 174155992Swpaul switch (areq->an_type) { 174255992Swpaul case AN_RID_GENCONFIG: 174355992Swpaul cfg = (struct an_ltv_genconfig *)areq; 174455992Swpaul 1745152315Sru bcopy((char *)&cfg->an_macaddr, IF_LLADDR(sc->an_ifp), 174655992Swpaul ETHER_ADDR_LEN); 174755992Swpaul 174855992Swpaul bcopy((char *)cfg, (char *)&sc->an_config, 174955992Swpaul sizeof(struct an_ltv_genconfig)); 175055992Swpaul break; 175155992Swpaul case AN_RID_SSIDLIST: 1752119156Sambrisko ssid = (struct an_ltv_ssidlist_new *)areq; 175355992Swpaul bcopy((char *)ssid, (char *)&sc->an_ssidlist, 1754119156Sambrisko sizeof(struct an_ltv_ssidlist_new)); 175555992Swpaul break; 175655992Swpaul case AN_RID_APLIST: 175755992Swpaul ap = (struct an_ltv_aplist *)areq; 175855992Swpaul bcopy((char *)ap, (char *)&sc->an_aplist, 175955992Swpaul sizeof(struct an_ltv_aplist)); 176055992Swpaul break; 176155992Swpaul case AN_RID_TX_SPEED: 176255992Swpaul sp = (struct an_ltv_gen *)areq; 176355992Swpaul sc->an_tx_rate = sp->an_val; 1764110253Sambrisko 1765110253Sambrisko /* Read the current configuration */ 1766110253Sambrisko sc->an_config.an_type = AN_RID_GENCONFIG; 1767110253Sambrisko sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 1768110253Sambrisko an_read_record(sc, (struct an_ltv_gen *)&sc->an_config); 1769110253Sambrisko cfg = &sc->an_config; 1770110253Sambrisko 1771110253Sambrisko /* clear other rates and set the only one we want */ 1772110253Sambrisko bzero(cfg->an_rates, sizeof(cfg->an_rates)); 1773110253Sambrisko cfg->an_rates[0] = sc->an_tx_rate; 1774110253Sambrisko 1775110253Sambrisko /* Save the new rate */ 1776110253Sambrisko sc->an_config.an_type = AN_RID_GENCONFIG; 1777110253Sambrisko sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 177855992Swpaul break; 177968692Swpaul case AN_RID_WEP_TEMP: 1780110531Sambrisko /* Cache the temp keys */ 1781110531Sambrisko bcopy(areq, 1782110531Sambrisko &sc->an_temp_keys[((struct an_ltv_key *)areq)->kindex], 1783110531Sambrisko sizeof(struct an_ltv_key)); 178468692Swpaul case AN_RID_WEP_PERM: 178588748Sambrisko case AN_RID_LEAPUSERNAME: 178688748Sambrisko case AN_RID_LEAPPASSWORD: 1787119156Sambrisko an_init(sc); 1788119156Sambrisko 178968692Swpaul /* Disable the MAC. */ 179068692Swpaul an_cmd(sc, AN_CMD_DISABLE, 0); 179183270Sbrooks 179283269Sbrooks /* Write the key */ 179368692Swpaul an_write_record(sc, (struct an_ltv_gen *)areq); 179483270Sbrooks 179583270Sbrooks /* Turn the MAC back on. */ 179668692Swpaul an_cmd(sc, AN_CMD_ENABLE, 0); 179783270Sbrooks 179868692Swpaul break; 179983269Sbrooks case AN_RID_MONITOR_MODE: 180083269Sbrooks cfg = (struct an_ltv_genconfig *)areq; 180183269Sbrooks bpfdetach(ifp); 180283269Sbrooks if (ng_ether_detach_p != NULL) 180383269Sbrooks (*ng_ether_detach_p) (ifp); 180483269Sbrooks sc->an_monitor = cfg->an_len; 180583269Sbrooks 180683270Sbrooks if (sc->an_monitor & AN_MONITOR) { 180783270Sbrooks if (sc->an_monitor & AN_MONITOR_AIRONET_HEADER) { 180883270Sbrooks bpfattach(ifp, DLT_AIRONET_HEADER, 180983269Sbrooks sizeof(struct ether_header)); 181083269Sbrooks } else { 181183270Sbrooks bpfattach(ifp, DLT_IEEE802_11, 181283269Sbrooks sizeof(struct ether_header)); 181383269Sbrooks } 181483269Sbrooks } else { 181583270Sbrooks bpfattach(ifp, DLT_EN10MB, 181683269Sbrooks sizeof(struct ether_header)); 181783269Sbrooks if (ng_ether_attach_p != NULL) 181883269Sbrooks (*ng_ether_attach_p) (ifp); 181983269Sbrooks } 182083269Sbrooks break; 182155992Swpaul default: 182255992Swpaul printf("an%d: unknown RID: %x\n", sc->an_unit, areq->an_type); 182355992Swpaul return; 182455992Swpaul } 182555992Swpaul 182655992Swpaul 182755992Swpaul /* Reinitialize the card. */ 182874698Sarchie if (ifp->if_flags) 182955992Swpaul an_init(sc); 183055992Swpaul 183155992Swpaul return; 183255992Swpaul} 183355992Swpaul 183455992Swpaul/* 183583269Sbrooks * Derived from Linux driver to enable promiscious mode. 183655992Swpaul */ 183783269Sbrooks 183883270Sbrooksstatic void 1839150446Simpan_promisc(struct an_softc *sc, int promisc) 184055992Swpaul{ 1841150446Simp if (sc->an_was_monitor) { 184283269Sbrooks an_reset(sc); 1843108401Sambrisko if (sc->mpi350) 1844108401Sambrisko an_init_mpi350_desc(sc); 1845150446Simp } 184683270Sbrooks if (sc->an_monitor || sc->an_was_monitor) 184783269Sbrooks an_init(sc); 184883269Sbrooks 184983269Sbrooks sc->an_was_monitor = sc->an_monitor; 185074698Sarchie an_cmd(sc, AN_CMD_SET_MODE, promisc ? 0xffff : 0); 185183270Sbrooks 185255992Swpaul return; 185355992Swpaul} 185455992Swpaul 185583270Sbrooksstatic int 1856150446Simpan_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 185755992Swpaul{ 185867094Swpaul int error = 0; 185977217Sphk int len; 1860119156Sambrisko int i, max; 186155992Swpaul struct an_softc *sc; 186255992Swpaul struct ifreq *ifr; 186393593Sjhb struct thread *td = curthread; 186477217Sphk struct ieee80211req *ireq; 186577217Sphk u_int8_t tmpstr[IEEE80211_NWID_LEN*2]; 186677217Sphk u_int8_t *tmpptr; 186777217Sphk struct an_ltv_genconfig *config; 186877217Sphk struct an_ltv_key *key; 186977217Sphk struct an_ltv_status *status; 1870119156Sambrisko struct an_ltv_ssidlist_new *ssids; 187188748Sambrisko int mode; 187288748Sambrisko struct aironet_ioctl l_ioctl; 187355992Swpaul 187455992Swpaul sc = ifp->if_softc; 187567094Swpaul AN_LOCK(sc); 187655992Swpaul ifr = (struct ifreq *)data; 187777217Sphk ireq = (struct ieee80211req *)data; 187855992Swpaul 187988749Sambrisko config = (struct an_ltv_genconfig *)&sc->areq; 188088749Sambrisko key = (struct an_ltv_key *)&sc->areq; 188188749Sambrisko status = (struct an_ltv_status *)&sc->areq; 1882119156Sambrisko ssids = (struct an_ltv_ssidlist_new *)&sc->areq; 188377217Sphk 188464429Speter if (sc->an_gone) { 188561816Sroberto error = ENODEV; 188661816Sroberto goto out; 188761816Sroberto } 188855992Swpaul 188983270Sbrooks switch (command) { 189055992Swpaul case SIOCSIFFLAGS: 189155992Swpaul if (ifp->if_flags & IFF_UP) { 1892148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING && 189355992Swpaul ifp->if_flags & IFF_PROMISC && 189455992Swpaul !(sc->an_if_flags & IFF_PROMISC)) { 189555992Swpaul an_promisc(sc, 1); 1896148887Srwatson } else if (ifp->if_drv_flags & IFF_DRV_RUNNING && 189755992Swpaul !(ifp->if_flags & IFF_PROMISC) && 189855992Swpaul sc->an_if_flags & IFF_PROMISC) { 189955992Swpaul an_promisc(sc, 0); 190055992Swpaul } else 190155992Swpaul an_init(sc); 190255992Swpaul } else { 1903148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 190455992Swpaul an_stop(sc); 190555992Swpaul } 190655992Swpaul sc->an_if_flags = ifp->if_flags; 190755992Swpaul error = 0; 190855992Swpaul break; 190977217Sphk case SIOCSIFMEDIA: 191077217Sphk case SIOCGIFMEDIA: 191177217Sphk error = ifmedia_ioctl(ifp, ifr, &sc->an_ifmedia, command); 191277217Sphk break; 191355992Swpaul case SIOCADDMULTI: 191455992Swpaul case SIOCDELMULTI: 191555992Swpaul /* The Aironet has no multicast filter. */ 191655992Swpaul error = 0; 191755992Swpaul break; 191855992Swpaul case SIOCGAIRONET: 1919171692Savatar AN_UNLOCK(sc); 192088749Sambrisko error = copyin(ifr->ifr_data, &sc->areq, sizeof(sc->areq)); 1921171692Savatar AN_LOCK(sc); 192278639Sbrooks if (error != 0) 192355992Swpaul break; 192455992Swpaul#ifdef ANCACHE 192588749Sambrisko if (sc->areq.an_type == AN_RID_ZERO_CACHE) { 1926164033Srwatson error = priv_check(td, PRIV_DRIVER); 1927108259Srwatson if (error) 1928108259Srwatson break; 192955992Swpaul sc->an_sigitems = sc->an_nextitem = 0; 193055992Swpaul break; 193188749Sambrisko } else if (sc->areq.an_type == AN_RID_READ_CACHE) { 193288749Sambrisko char *pt = (char *)&sc->areq.an_val; 193355992Swpaul bcopy((char *)&sc->an_sigitems, (char *)pt, 193455992Swpaul sizeof(int)); 193555992Swpaul pt += sizeof(int); 193688749Sambrisko sc->areq.an_len = sizeof(int) / 2; 193755992Swpaul bcopy((char *)&sc->an_sigcache, (char *)pt, 193855992Swpaul sizeof(struct an_sigcache) * sc->an_sigitems); 193988749Sambrisko sc->areq.an_len += ((sizeof(struct an_sigcache) * 194055992Swpaul sc->an_sigitems) / 2) + 1; 194155992Swpaul } else 194255992Swpaul#endif 194388749Sambrisko if (an_read_record(sc, (struct an_ltv_gen *)&sc->areq)) { 194455992Swpaul error = EINVAL; 194555992Swpaul break; 194655992Swpaul } 1947171692Savatar AN_UNLOCK(sc); 194888749Sambrisko error = copyout(&sc->areq, ifr->ifr_data, sizeof(sc->areq)); 1949171692Savatar AN_LOCK(sc); 195055992Swpaul break; 195155992Swpaul case SIOCSAIRONET: 1952164033Srwatson if ((error = priv_check(td, PRIV_DRIVER))) 195364429Speter goto out; 1954171692Savatar AN_UNLOCK(sc); 195588749Sambrisko error = copyin(ifr->ifr_data, &sc->areq, sizeof(sc->areq)); 1956171692Savatar AN_LOCK(sc); 195778639Sbrooks if (error != 0) 195855992Swpaul break; 195988749Sambrisko an_setdef(sc, &sc->areq); 196055992Swpaul break; 196188748Sambrisko case SIOCGPRIVATE_0: /* used by Cisco client utility */ 1962164033Srwatson if ((error = priv_check(td, PRIV_DRIVER))) 196392292Sambrisko goto out; 1964171692Savatar AN_UNLOCK(sc); 1965144242Ssam error = copyin(ifr->ifr_data, &l_ioctl, sizeof(l_ioctl)); 1966171692Savatar AN_LOCK(sc); 1967144242Ssam if (error) 1968144242Ssam goto out; 196988748Sambrisko mode = l_ioctl.command; 197088748Sambrisko 197188748Sambrisko if (mode >= AIROGCAP && mode <= AIROGSTATSD32) { 197288748Sambrisko error = readrids(ifp, &l_ioctl); 1973110104Sambrisko } else if (mode >= AIROPCAP && mode <= AIROPLEAPUSR) { 197488748Sambrisko error = writerids(ifp, &l_ioctl); 1975110104Sambrisko } else if (mode >= AIROFLSHRST && mode <= AIRORESTART) { 197688748Sambrisko error = flashcard(ifp, &l_ioctl); 1977110104Sambrisko } else { 197888748Sambrisko error =-1; 197988748Sambrisko } 1980144242Ssam if (!error) { 1981144242Ssam /* copy out the updated command info */ 1982171692Savatar AN_UNLOCK(sc); 1983144242Ssam error = copyout(&l_ioctl, ifr->ifr_data, sizeof(l_ioctl)); 1984171692Savatar AN_LOCK(sc); 1985144242Ssam } 198688748Sambrisko break; 198788748Sambrisko case SIOCGPRIVATE_1: /* used by Cisco client utility */ 1988164033Srwatson if ((error = priv_check(td, PRIV_DRIVER))) 198992292Sambrisko goto out; 1990171692Savatar AN_UNLOCK(sc); 1991144242Ssam error = copyin(ifr->ifr_data, &l_ioctl, sizeof(l_ioctl)); 1992171692Savatar AN_LOCK(sc); 1993144242Ssam if (error) 1994144242Ssam goto out; 199588748Sambrisko l_ioctl.command = 0; 199688748Sambrisko error = AIROMAGIC; 1997171692Savatar AN_UNLOCK(sc); 1998144242Ssam (void) copyout(&error, l_ioctl.data, sizeof(error)); 1999171692Savatar AN_LOCK(sc); 200088748Sambrisko error = 0; 200188748Sambrisko break; 200277217Sphk case SIOCG80211: 200388749Sambrisko sc->areq.an_len = sizeof(sc->areq); 200488748Sambrisko /* was that a good idea DJA we are doing a short-cut */ 200583270Sbrooks switch (ireq->i_type) { 200677217Sphk case IEEE80211_IOC_SSID: 200778639Sbrooks if (ireq->i_val == -1) { 200888749Sambrisko sc->areq.an_type = AN_RID_STATUS; 200977217Sphk if (an_read_record(sc, 201088749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 201177217Sphk error = EINVAL; 201277217Sphk break; 201377217Sphk } 201477217Sphk len = status->an_ssidlen; 201577217Sphk tmpptr = status->an_ssid; 201678639Sbrooks } else if (ireq->i_val >= 0) { 201788749Sambrisko sc->areq.an_type = AN_RID_SSIDLIST; 201877217Sphk if (an_read_record(sc, 201988749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 202077217Sphk error = EINVAL; 202177217Sphk break; 202277217Sphk } 2023119156Sambrisko max = (sc->areq.an_len - 4) 2024119156Sambrisko / sizeof(struct an_ltv_ssid_entry); 2025119156Sambrisko if ( max > MAX_SSIDS ) { 2026119156Sambrisko printf("To many SSIDs only using " 2027119156Sambrisko "%d of %d\n", 2028119156Sambrisko MAX_SSIDS, max); 2029119156Sambrisko max = MAX_SSIDS; 2030119156Sambrisko } 2031119156Sambrisko if (ireq->i_val > max) { 203277217Sphk error = EINVAL; 203377217Sphk break; 2034119156Sambrisko } else { 2035119156Sambrisko len = ssids->an_entry[ireq->i_val].an_len; 2036119156Sambrisko tmpptr = ssids->an_entry[ireq->i_val].an_ssid; 203777217Sphk } 203877217Sphk } else { 203977217Sphk error = EINVAL; 204077217Sphk break; 204177217Sphk } 204278639Sbrooks if (len > IEEE80211_NWID_LEN) { 204377217Sphk error = EINVAL; 204477217Sphk break; 204577217Sphk } 204677217Sphk ireq->i_len = len; 204777217Sphk bzero(tmpstr, IEEE80211_NWID_LEN); 204877217Sphk bcopy(tmpptr, tmpstr, len); 2049171692Savatar AN_UNLOCK(sc); 205077217Sphk error = copyout(tmpstr, ireq->i_data, 205177217Sphk IEEE80211_NWID_LEN); 2052171692Savatar AN_LOCK(sc); 205377217Sphk break; 205477217Sphk case IEEE80211_IOC_NUMSSIDS: 2055119156Sambrisko sc->areq.an_len = sizeof(sc->areq); 2056119156Sambrisko sc->areq.an_type = AN_RID_SSIDLIST; 2057119156Sambrisko if (an_read_record(sc, 2058119156Sambrisko (struct an_ltv_gen *)&sc->areq)) { 2059119156Sambrisko error = EINVAL; 2060119156Sambrisko break; 2061119156Sambrisko } 2062119156Sambrisko max = (sc->areq.an_len - 4) 2063119156Sambrisko / sizeof(struct an_ltv_ssid_entry); 2064119156Sambrisko if ( max > MAX_SSIDS ) { 2065119156Sambrisko printf("To many SSIDs only using " 2066119156Sambrisko "%d of %d\n", 2067119156Sambrisko MAX_SSIDS, max); 2068119156Sambrisko max = MAX_SSIDS; 2069119156Sambrisko } 2070119156Sambrisko ireq->i_val = max; 207177217Sphk break; 207277217Sphk case IEEE80211_IOC_WEP: 207388749Sambrisko sc->areq.an_type = AN_RID_ACTUALCFG; 207477217Sphk if (an_read_record(sc, 207588749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 207677217Sphk error = EINVAL; 207777217Sphk break; 207877217Sphk } 207978639Sbrooks if (config->an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE) { 208078639Sbrooks if (config->an_authtype & 208177217Sphk AN_AUTHTYPE_ALLOW_UNENCRYPTED) 208277217Sphk ireq->i_val = IEEE80211_WEP_MIXED; 208377217Sphk else 208477217Sphk ireq->i_val = IEEE80211_WEP_ON; 208577217Sphk } else { 208677217Sphk ireq->i_val = IEEE80211_WEP_OFF; 208777217Sphk } 208877217Sphk break; 208977217Sphk case IEEE80211_IOC_WEPKEY: 209077217Sphk /* 209177217Sphk * XXX: I'm not entierly convinced this is 209277217Sphk * correct, but it's what is implemented in 209377217Sphk * ancontrol so it will have to do until we get 209477217Sphk * access to actual Cisco code. 209577217Sphk */ 209688748Sambrisko if (ireq->i_val < 0 || ireq->i_val > 8) { 209777217Sphk error = EINVAL; 209877217Sphk break; 209977217Sphk } 210077217Sphk len = 0; 210188748Sambrisko if (ireq->i_val < 5) { 210288749Sambrisko sc->areq.an_type = AN_RID_WEP_TEMP; 210378639Sbrooks for (i = 0; i < 5; i++) { 210477217Sphk if (an_read_record(sc, 210588749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 210677217Sphk error = EINVAL; 210777217Sphk break; 210877217Sphk } 210978639Sbrooks if (key->kindex == 0xffff) 211077217Sphk break; 211178639Sbrooks if (key->kindex == ireq->i_val) 211278639Sbrooks len = key->klen; 211377217Sphk /* Required to get next entry */ 211488749Sambrisko sc->areq.an_type = AN_RID_WEP_PERM; 211577217Sphk } 211678639Sbrooks if (error != 0) 211777217Sphk break; 211877217Sphk } 211977217Sphk /* We aren't allowed to read the value of the 212077217Sphk * key from the card so we just output zeros 212177217Sphk * like we would if we could read the card, but 212277217Sphk * denied the user access. 212377217Sphk */ 212477217Sphk bzero(tmpstr, len); 212577217Sphk ireq->i_len = len; 2126171692Savatar AN_UNLOCK(sc); 212777217Sphk error = copyout(tmpstr, ireq->i_data, len); 2128171692Savatar AN_LOCK(sc); 212977217Sphk break; 213077217Sphk case IEEE80211_IOC_NUMWEPKEYS: 213188748Sambrisko ireq->i_val = 9; /* include home key */ 213277217Sphk break; 213377217Sphk case IEEE80211_IOC_WEPTXKEY: 213478639Sbrooks /* 213578639Sbrooks * For some strange reason, you have to read all 213678639Sbrooks * keys before you can read the txkey. 213778639Sbrooks */ 213888749Sambrisko sc->areq.an_type = AN_RID_WEP_TEMP; 213978639Sbrooks for (i = 0; i < 5; i++) { 214078639Sbrooks if (an_read_record(sc, 214188749Sambrisko (struct an_ltv_gen *) &sc->areq)) { 214278639Sbrooks error = EINVAL; 214378639Sbrooks break; 214478639Sbrooks } 214578639Sbrooks if (key->kindex == 0xffff) 214678639Sbrooks break; 214778639Sbrooks /* Required to get next entry */ 214888749Sambrisko sc->areq.an_type = AN_RID_WEP_PERM; 214978639Sbrooks } 215078639Sbrooks if (error != 0) 215178639Sbrooks break; 215278639Sbrooks 215388749Sambrisko sc->areq.an_type = AN_RID_WEP_PERM; 215477217Sphk key->kindex = 0xffff; 215577217Sphk if (an_read_record(sc, 215688749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 215777217Sphk error = EINVAL; 215877217Sphk break; 215977217Sphk } 216077217Sphk ireq->i_val = key->mac[0]; 216188748Sambrisko /* 216288748Sambrisko * Check for home mode. Map home mode into 216388748Sambrisko * 5th key since that is how it is stored on 216488748Sambrisko * the card 216588748Sambrisko */ 216688749Sambrisko sc->areq.an_len = sizeof(struct an_ltv_genconfig); 216788749Sambrisko sc->areq.an_type = AN_RID_GENCONFIG; 216888748Sambrisko if (an_read_record(sc, 216988749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 217088748Sambrisko error = EINVAL; 217188748Sambrisko break; 217288748Sambrisko } 217388748Sambrisko if (config->an_home_product & AN_HOME_NETWORK) 217488748Sambrisko ireq->i_val = 4; 217577217Sphk break; 217677217Sphk case IEEE80211_IOC_AUTHMODE: 217788749Sambrisko sc->areq.an_type = AN_RID_ACTUALCFG; 217877217Sphk if (an_read_record(sc, 217988749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 218077217Sphk error = EINVAL; 218177217Sphk break; 218277217Sphk } 218377217Sphk if ((config->an_authtype & AN_AUTHTYPE_MASK) == 218477217Sphk AN_AUTHTYPE_NONE) { 218577217Sphk ireq->i_val = IEEE80211_AUTH_NONE; 218677217Sphk } else if ((config->an_authtype & AN_AUTHTYPE_MASK) == 218777217Sphk AN_AUTHTYPE_OPEN) { 218877217Sphk ireq->i_val = IEEE80211_AUTH_OPEN; 218977217Sphk } else if ((config->an_authtype & AN_AUTHTYPE_MASK) == 219077217Sphk AN_AUTHTYPE_SHAREDKEY) { 219177217Sphk ireq->i_val = IEEE80211_AUTH_SHARED; 219277217Sphk } else 219377217Sphk error = EINVAL; 219477217Sphk break; 219577217Sphk case IEEE80211_IOC_STATIONNAME: 219688749Sambrisko sc->areq.an_type = AN_RID_ACTUALCFG; 219777217Sphk if (an_read_record(sc, 219888749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 219977217Sphk error = EINVAL; 220077217Sphk break; 220177217Sphk } 220277217Sphk ireq->i_len = sizeof(config->an_nodename); 220377217Sphk tmpptr = config->an_nodename; 220477217Sphk bzero(tmpstr, IEEE80211_NWID_LEN); 220577217Sphk bcopy(tmpptr, tmpstr, ireq->i_len); 2206171692Savatar AN_UNLOCK(sc); 220777217Sphk error = copyout(tmpstr, ireq->i_data, 220877217Sphk IEEE80211_NWID_LEN); 2209171692Savatar AN_LOCK(sc); 221077217Sphk break; 221177217Sphk case IEEE80211_IOC_CHANNEL: 221288749Sambrisko sc->areq.an_type = AN_RID_STATUS; 221377217Sphk if (an_read_record(sc, 221488749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 221577217Sphk error = EINVAL; 221677217Sphk break; 221777217Sphk } 221877217Sphk ireq->i_val = status->an_cur_channel; 221977217Sphk break; 222077217Sphk case IEEE80211_IOC_POWERSAVE: 222188749Sambrisko sc->areq.an_type = AN_RID_ACTUALCFG; 222277217Sphk if (an_read_record(sc, 222388749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 222477217Sphk error = EINVAL; 222577217Sphk break; 222677217Sphk } 222778639Sbrooks if (config->an_psave_mode == AN_PSAVE_NONE) { 222877217Sphk ireq->i_val = IEEE80211_POWERSAVE_OFF; 222978639Sbrooks } else if (config->an_psave_mode == AN_PSAVE_CAM) { 223077217Sphk ireq->i_val = IEEE80211_POWERSAVE_CAM; 223178639Sbrooks } else if (config->an_psave_mode == AN_PSAVE_PSP) { 223277217Sphk ireq->i_val = IEEE80211_POWERSAVE_PSP; 223378639Sbrooks } else if (config->an_psave_mode == AN_PSAVE_PSP_CAM) { 223477217Sphk ireq->i_val = IEEE80211_POWERSAVE_PSP_CAM; 223577217Sphk } else 223677217Sphk error = EINVAL; 223777217Sphk break; 223877217Sphk case IEEE80211_IOC_POWERSAVESLEEP: 223988749Sambrisko sc->areq.an_type = AN_RID_ACTUALCFG; 224077217Sphk if (an_read_record(sc, 224188749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 224277217Sphk error = EINVAL; 224377217Sphk break; 224477217Sphk } 224577217Sphk ireq->i_val = config->an_listen_interval; 224677217Sphk break; 224783270Sbrooks } 224877217Sphk break; 224977217Sphk case SIOCS80211: 2250164033Srwatson if ((error = priv_check(td, PRIV_NET80211_MANAGE))) 225177217Sphk goto out; 225288749Sambrisko sc->areq.an_len = sizeof(sc->areq); 225377217Sphk /* 225477217Sphk * We need a config structure for everything but the WEP 225577217Sphk * key management and SSIDs so we get it now so avoid 225677217Sphk * duplicating this code every time. 225777217Sphk */ 225877217Sphk if (ireq->i_type != IEEE80211_IOC_SSID && 225977217Sphk ireq->i_type != IEEE80211_IOC_WEPKEY && 226077217Sphk ireq->i_type != IEEE80211_IOC_WEPTXKEY) { 226188749Sambrisko sc->areq.an_type = AN_RID_GENCONFIG; 226277217Sphk if (an_read_record(sc, 226388749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 226477217Sphk error = EINVAL; 226577217Sphk break; 226677217Sphk } 226777217Sphk } 226883270Sbrooks switch (ireq->i_type) { 226977217Sphk case IEEE80211_IOC_SSID: 2270119156Sambrisko sc->areq.an_len = sizeof(sc->areq); 227188749Sambrisko sc->areq.an_type = AN_RID_SSIDLIST; 227277217Sphk if (an_read_record(sc, 227388749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 227477217Sphk error = EINVAL; 227577217Sphk break; 227677217Sphk } 227778639Sbrooks if (ireq->i_len > IEEE80211_NWID_LEN) { 227877217Sphk error = EINVAL; 227977217Sphk break; 228077217Sphk } 2281119156Sambrisko max = (sc->areq.an_len - 4) 2282119156Sambrisko / sizeof(struct an_ltv_ssid_entry); 2283119156Sambrisko if ( max > MAX_SSIDS ) { 2284119156Sambrisko printf("To many SSIDs only using " 2285119156Sambrisko "%d of %d\n", 2286119156Sambrisko MAX_SSIDS, max); 2287119156Sambrisko max = MAX_SSIDS; 2288119156Sambrisko } 2289119156Sambrisko if (ireq->i_val > max) { 2290119156Sambrisko error = EINVAL; 229177217Sphk break; 2292119156Sambrisko } else { 2293171692Savatar AN_UNLOCK(sc); 229477217Sphk error = copyin(ireq->i_data, 2295119156Sambrisko ssids->an_entry[ireq->i_val].an_ssid, 2296119156Sambrisko ireq->i_len); 2297171692Savatar AN_LOCK(sc); 2298119156Sambrisko ssids->an_entry[ireq->i_val].an_len 2299119156Sambrisko = ireq->i_len; 230077217Sphk break; 230177217Sphk } 230277217Sphk break; 230377217Sphk case IEEE80211_IOC_WEP: 230477217Sphk switch (ireq->i_val) { 230577217Sphk case IEEE80211_WEP_OFF: 230677217Sphk config->an_authtype &= 230777217Sphk ~(AN_AUTHTYPE_PRIVACY_IN_USE | 230877217Sphk AN_AUTHTYPE_ALLOW_UNENCRYPTED); 230977217Sphk break; 231077217Sphk case IEEE80211_WEP_ON: 231177217Sphk config->an_authtype |= 231277217Sphk AN_AUTHTYPE_PRIVACY_IN_USE; 231377217Sphk config->an_authtype &= 231477217Sphk ~AN_AUTHTYPE_ALLOW_UNENCRYPTED; 231577217Sphk break; 231677217Sphk case IEEE80211_WEP_MIXED: 231777217Sphk config->an_authtype |= 231877217Sphk AN_AUTHTYPE_PRIVACY_IN_USE | 231977217Sphk AN_AUTHTYPE_ALLOW_UNENCRYPTED; 232077217Sphk break; 232177217Sphk default: 232277217Sphk error = EINVAL; 232377217Sphk break; 232477217Sphk } 232577217Sphk break; 232677217Sphk case IEEE80211_IOC_WEPKEY: 2327110531Sambrisko if (ireq->i_val < 0 || ireq->i_val > 8 || 232877217Sphk ireq->i_len > 13) { 232977217Sphk error = EINVAL; 233077217Sphk break; 233177217Sphk } 2332171692Savatar AN_UNLOCK(sc); 233377217Sphk error = copyin(ireq->i_data, tmpstr, 13); 2334171692Savatar AN_LOCK(sc); 233578639Sbrooks if (error != 0) 233677217Sphk break; 2337110531Sambrisko /* 2338110531Sambrisko * Map the 9th key into the home mode 2339110531Sambrisko * since that is how it is stored on 2340110531Sambrisko * the card 2341110531Sambrisko */ 234288749Sambrisko bzero(&sc->areq, sizeof(struct an_ltv_key)); 234388749Sambrisko sc->areq.an_len = sizeof(struct an_ltv_key); 234477217Sphk key->mac[0] = 1; /* The others are 0. */ 2345110531Sambrisko if (ireq->i_val < 4) { 234688749Sambrisko sc->areq.an_type = AN_RID_WEP_TEMP; 2347110531Sambrisko key->kindex = ireq->i_val; 2348110531Sambrisko } else { 234988749Sambrisko sc->areq.an_type = AN_RID_WEP_PERM; 2350110531Sambrisko key->kindex = ireq->i_val - 4; 2351110531Sambrisko } 235277217Sphk key->klen = ireq->i_len; 235377217Sphk bcopy(tmpstr, key->key, key->klen); 235477217Sphk break; 235577217Sphk case IEEE80211_IOC_WEPTXKEY: 2356110531Sambrisko if (ireq->i_val < 0 || ireq->i_val > 4) { 2357110531Sambrisko error = EINVAL; 2358110531Sambrisko break; 2359110531Sambrisko } 2360110531Sambrisko 236188748Sambrisko /* 236288748Sambrisko * Map the 5th key into the home mode 236388748Sambrisko * since that is how it is stored on 236488748Sambrisko * the card 236588748Sambrisko */ 236688749Sambrisko sc->areq.an_len = sizeof(struct an_ltv_genconfig); 236788749Sambrisko sc->areq.an_type = AN_RID_ACTUALCFG; 236888748Sambrisko if (an_read_record(sc, 236988749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 237088748Sambrisko error = EINVAL; 237188748Sambrisko break; 237288748Sambrisko } 237388748Sambrisko if (ireq->i_val == 4) { 237488748Sambrisko config->an_home_product |= AN_HOME_NETWORK; 237588748Sambrisko ireq->i_val = 0; 237688748Sambrisko } else { 237788748Sambrisko config->an_home_product &= ~AN_HOME_NETWORK; 237888748Sambrisko } 237988748Sambrisko 238088748Sambrisko sc->an_config.an_home_product 238188748Sambrisko = config->an_home_product; 238288748Sambrisko 2383110531Sambrisko /* update configuration */ 2384110531Sambrisko an_init(sc); 2385110531Sambrisko 238688749Sambrisko bzero(&sc->areq, sizeof(struct an_ltv_key)); 238788749Sambrisko sc->areq.an_len = sizeof(struct an_ltv_key); 238888749Sambrisko sc->areq.an_type = AN_RID_WEP_PERM; 238977217Sphk key->kindex = 0xffff; 239077217Sphk key->mac[0] = ireq->i_val; 239177217Sphk break; 239277217Sphk case IEEE80211_IOC_AUTHMODE: 239377217Sphk switch (ireq->i_val) { 239477217Sphk case IEEE80211_AUTH_NONE: 239577217Sphk config->an_authtype = AN_AUTHTYPE_NONE | 239677217Sphk (config->an_authtype & ~AN_AUTHTYPE_MASK); 239777217Sphk break; 239877217Sphk case IEEE80211_AUTH_OPEN: 239977217Sphk config->an_authtype = AN_AUTHTYPE_OPEN | 240077217Sphk (config->an_authtype & ~AN_AUTHTYPE_MASK); 240177217Sphk break; 240277217Sphk case IEEE80211_AUTH_SHARED: 240377217Sphk config->an_authtype = AN_AUTHTYPE_SHAREDKEY | 240477217Sphk (config->an_authtype & ~AN_AUTHTYPE_MASK); 240577217Sphk break; 240677217Sphk default: 240777217Sphk error = EINVAL; 240877217Sphk } 240977217Sphk break; 241077217Sphk case IEEE80211_IOC_STATIONNAME: 241178639Sbrooks if (ireq->i_len > 16) { 241277217Sphk error = EINVAL; 241377217Sphk break; 241477217Sphk } 241577217Sphk bzero(config->an_nodename, 16); 2416171692Savatar AN_UNLOCK(sc); 241777217Sphk error = copyin(ireq->i_data, 241877217Sphk config->an_nodename, ireq->i_len); 2419171692Savatar AN_LOCK(sc); 242077217Sphk break; 242177217Sphk case IEEE80211_IOC_CHANNEL: 242277217Sphk /* 242377217Sphk * The actual range is 1-14, but if you set it 242477217Sphk * to 0 you get the default so we let that work 242577217Sphk * too. 242677217Sphk */ 242777217Sphk if (ireq->i_val < 0 || ireq->i_val >14) { 242877217Sphk error = EINVAL; 242977217Sphk break; 243077217Sphk } 243177217Sphk config->an_ds_channel = ireq->i_val; 243277217Sphk break; 243377217Sphk case IEEE80211_IOC_POWERSAVE: 243477217Sphk switch (ireq->i_val) { 243577217Sphk case IEEE80211_POWERSAVE_OFF: 243677217Sphk config->an_psave_mode = AN_PSAVE_NONE; 243777217Sphk break; 243877217Sphk case IEEE80211_POWERSAVE_CAM: 243977217Sphk config->an_psave_mode = AN_PSAVE_CAM; 244077217Sphk break; 244177217Sphk case IEEE80211_POWERSAVE_PSP: 244277217Sphk config->an_psave_mode = AN_PSAVE_PSP; 244377217Sphk break; 244477217Sphk case IEEE80211_POWERSAVE_PSP_CAM: 244577217Sphk config->an_psave_mode = AN_PSAVE_PSP_CAM; 244677217Sphk break; 244777217Sphk default: 244877217Sphk error = EINVAL; 244977217Sphk break; 245077217Sphk } 245177217Sphk break; 245277217Sphk case IEEE80211_IOC_POWERSAVESLEEP: 245377217Sphk config->an_listen_interval = ireq->i_val; 245477217Sphk break; 245577217Sphk } 245677217Sphk 245777217Sphk if (!error) 245888749Sambrisko an_setdef(sc, &sc->areq); 245977217Sphk break; 246055992Swpaul default: 2461171692Savatar AN_UNLOCK(sc); 2462106937Ssam error = ether_ioctl(ifp, command, data); 2463171692Savatar AN_LOCK(sc); 246455992Swpaul break; 246555992Swpaul } 246661816Srobertoout: 246767094Swpaul AN_UNLOCK(sc); 246855992Swpaul 246978639Sbrooks return(error != 0); 247055992Swpaul} 247155992Swpaul 247283270Sbrooksstatic int 2473150446Simpan_init_tx_ring(struct an_softc *sc) 247455992Swpaul{ 247555992Swpaul int i; 247655992Swpaul int id; 247755992Swpaul 247855992Swpaul if (sc->an_gone) 247955992Swpaul return (0); 248055992Swpaul 2481108401Sambrisko if (!sc->mpi350) { 2482108401Sambrisko for (i = 0; i < AN_TX_RING_CNT; i++) { 2483108401Sambrisko if (an_alloc_nicmem(sc, 1518 + 2484108401Sambrisko 0x44, &id)) 2485108401Sambrisko return(ENOMEM); 2486108401Sambrisko sc->an_rdata.an_tx_fids[i] = id; 2487108401Sambrisko sc->an_rdata.an_tx_ring[i] = 0; 2488108401Sambrisko } 248955992Swpaul } 249055992Swpaul 249155992Swpaul sc->an_rdata.an_tx_prod = 0; 249255992Swpaul sc->an_rdata.an_tx_cons = 0; 2493108401Sambrisko sc->an_rdata.an_tx_empty = 1; 249455992Swpaul 249555992Swpaul return(0); 249655992Swpaul} 249755992Swpaul 249883270Sbrooksstatic void 2499150446Simpan_init(void *xsc) 250055992Swpaul{ 250155992Swpaul struct an_softc *sc = xsc; 2502147256Sbrooks struct ifnet *ifp = sc->an_ifp; 250355992Swpaul 250467094Swpaul AN_LOCK(sc); 250567094Swpaul 250667094Swpaul if (sc->an_gone) { 250767094Swpaul AN_UNLOCK(sc); 250855992Swpaul return; 250967094Swpaul } 251055992Swpaul 2511148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 251255992Swpaul an_stop(sc); 251355992Swpaul 251455992Swpaul sc->an_associated = 0; 251555992Swpaul 251655992Swpaul /* Allocate the TX buffers */ 251755992Swpaul if (an_init_tx_ring(sc)) { 251855992Swpaul an_reset(sc); 2519108401Sambrisko if (sc->mpi350) 2520108401Sambrisko an_init_mpi350_desc(sc); 252155992Swpaul if (an_init_tx_ring(sc)) { 252255992Swpaul printf("an%d: tx buffer allocation " 252355992Swpaul "failed\n", sc->an_unit); 252467094Swpaul AN_UNLOCK(sc); 252555992Swpaul return; 252655992Swpaul } 252755992Swpaul } 252855992Swpaul 252955992Swpaul /* Set our MAC address. */ 2530152315Sru bcopy((char *)IF_LLADDR(sc->an_ifp), 253155992Swpaul (char *)&sc->an_config.an_macaddr, ETHER_ADDR_LEN); 253255992Swpaul 253355992Swpaul if (ifp->if_flags & IFF_BROADCAST) 253455992Swpaul sc->an_config.an_rxmode = AN_RXMODE_BC_ADDR; 253555992Swpaul else 253655992Swpaul sc->an_config.an_rxmode = AN_RXMODE_ADDR; 253755992Swpaul 253855992Swpaul if (ifp->if_flags & IFF_MULTICAST) 253955992Swpaul sc->an_config.an_rxmode = AN_RXMODE_BC_MC_ADDR; 254055992Swpaul 254183269Sbrooks if (ifp->if_flags & IFF_PROMISC) { 254283269Sbrooks if (sc->an_monitor & AN_MONITOR) { 254383269Sbrooks if (sc->an_monitor & AN_MONITOR_ANY_BSS) { 254483269Sbrooks sc->an_config.an_rxmode |= 254583269Sbrooks AN_RXMODE_80211_MONITOR_ANYBSS | 254683269Sbrooks AN_RXMODE_NO_8023_HEADER; 254783269Sbrooks } else { 254883269Sbrooks sc->an_config.an_rxmode |= 254983269Sbrooks AN_RXMODE_80211_MONITOR_CURBSS | 255083269Sbrooks AN_RXMODE_NO_8023_HEADER; 255183269Sbrooks } 255283269Sbrooks } 255383269Sbrooks } 255455992Swpaul 2555108401Sambrisko if (sc->an_have_rssimap) 2556108401Sambrisko sc->an_config.an_rxmode |= AN_RXMODE_NORMALIZED_RSSI; 2557108401Sambrisko 255855992Swpaul /* Set the ssid list */ 255955992Swpaul sc->an_ssidlist.an_type = AN_RID_SSIDLIST; 2560119156Sambrisko sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist_new); 256155992Swpaul if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) { 256255992Swpaul printf("an%d: failed to set ssid list\n", sc->an_unit); 256367094Swpaul AN_UNLOCK(sc); 256455992Swpaul return; 256555992Swpaul } 256655992Swpaul 256755992Swpaul /* Set the AP list */ 256855992Swpaul sc->an_aplist.an_type = AN_RID_APLIST; 256955992Swpaul sc->an_aplist.an_len = sizeof(struct an_ltv_aplist); 257055992Swpaul if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) { 257155992Swpaul printf("an%d: failed to set AP list\n", sc->an_unit); 257267094Swpaul AN_UNLOCK(sc); 257355992Swpaul return; 257455992Swpaul } 257555992Swpaul 257655992Swpaul /* Set the configuration in the NIC */ 257755992Swpaul sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 257855992Swpaul sc->an_config.an_type = AN_RID_GENCONFIG; 257955992Swpaul if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_config)) { 258055992Swpaul printf("an%d: failed to set configuration\n", sc->an_unit); 258167094Swpaul AN_UNLOCK(sc); 258255992Swpaul return; 258355992Swpaul } 258455992Swpaul 258555992Swpaul /* Enable the MAC */ 258655992Swpaul if (an_cmd(sc, AN_CMD_ENABLE, 0)) { 258755992Swpaul printf("an%d: failed to enable MAC\n", sc->an_unit); 258867094Swpaul AN_UNLOCK(sc); 258955992Swpaul return; 259055992Swpaul } 259155992Swpaul 259274698Sarchie if (ifp->if_flags & IFF_PROMISC) 259374698Sarchie an_cmd(sc, AN_CMD_SET_MODE, 0xffff); 259474698Sarchie 259555992Swpaul /* enable interrupts */ 2596119156Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350)); 259755992Swpaul 2598148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 2599148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 260055992Swpaul 260155992Swpaul sc->an_stat_ch = timeout(an_stats_update, sc, hz); 260267094Swpaul AN_UNLOCK(sc); 260355992Swpaul 260455992Swpaul return; 260555992Swpaul} 260655992Swpaul 260783270Sbrooksstatic void 2608150446Simpan_start(struct ifnet *ifp) 260955992Swpaul{ 261055992Swpaul struct an_softc *sc; 261155992Swpaul struct mbuf *m0 = NULL; 261255992Swpaul struct an_txframe_802_3 tx_frame_802_3; 261355992Swpaul struct ether_header *eh; 2614108401Sambrisko int id, idx, i; 261555992Swpaul unsigned char txcontrol; 2616108401Sambrisko struct an_card_tx_desc an_tx_desc; 2617108401Sambrisko u_int8_t *buf; 261855992Swpaul 261955992Swpaul sc = ifp->if_softc; 262055992Swpaul 262155992Swpaul if (sc->an_gone) 262255992Swpaul return; 262355992Swpaul 2624148887Srwatson if (ifp->if_drv_flags & IFF_DRV_OACTIVE) 262555992Swpaul return; 262655992Swpaul 262755992Swpaul if (!sc->an_associated) 262855992Swpaul return; 262955992Swpaul 263090990Sbrooks /* We can't send in monitor mode so toss any attempts. */ 263183269Sbrooks if (sc->an_monitor && (ifp->if_flags & IFF_PROMISC)) { 263283270Sbrooks for (;;) { 2633132986Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); 263483269Sbrooks if (m0 == NULL) 263583269Sbrooks break; 263690990Sbrooks m_freem(m0); 263783269Sbrooks } 263883269Sbrooks return; 263983269Sbrooks } 264083269Sbrooks 264155992Swpaul idx = sc->an_rdata.an_tx_prod; 264255992Swpaul 2643108401Sambrisko if (!sc->mpi350) { 2644108401Sambrisko bzero((char *)&tx_frame_802_3, sizeof(tx_frame_802_3)); 264555992Swpaul 2646108401Sambrisko while (sc->an_rdata.an_tx_ring[idx] == 0) { 2647132986Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); 2648108401Sambrisko if (m0 == NULL) 2649108401Sambrisko break; 265055992Swpaul 2651108401Sambrisko id = sc->an_rdata.an_tx_fids[idx]; 2652108401Sambrisko eh = mtod(m0, struct ether_header *); 265383270Sbrooks 2654108401Sambrisko bcopy((char *)&eh->ether_dhost, 2655108401Sambrisko (char *)&tx_frame_802_3.an_tx_dst_addr, 2656108401Sambrisko ETHER_ADDR_LEN); 2657108401Sambrisko bcopy((char *)&eh->ether_shost, 2658108401Sambrisko (char *)&tx_frame_802_3.an_tx_src_addr, 2659108401Sambrisko ETHER_ADDR_LEN); 266055992Swpaul 2661108401Sambrisko /* minus src/dest mac & type */ 2662108401Sambrisko tx_frame_802_3.an_tx_802_3_payload_len = 2663108401Sambrisko m0->m_pkthdr.len - 12; 266455992Swpaul 2665108401Sambrisko m_copydata(m0, sizeof(struct ether_header) - 2 , 2666108401Sambrisko tx_frame_802_3.an_tx_802_3_payload_len, 2667108401Sambrisko (caddr_t)&sc->an_txbuf); 2668108401Sambrisko 2669108401Sambrisko txcontrol = AN_TXCTL_8023; 2670108401Sambrisko /* write the txcontrol only */ 2671108401Sambrisko an_write_data(sc, id, 0x08, (caddr_t)&txcontrol, 2672108401Sambrisko sizeof(txcontrol)); 2673108401Sambrisko 2674108401Sambrisko /* 802_3 header */ 2675108401Sambrisko an_write_data(sc, id, 0x34, (caddr_t)&tx_frame_802_3, 2676108401Sambrisko sizeof(struct an_txframe_802_3)); 2677108401Sambrisko 2678108401Sambrisko /* in mbuf header type is just before payload */ 2679108401Sambrisko an_write_data(sc, id, 0x44, (caddr_t)&sc->an_txbuf, 2680108401Sambrisko tx_frame_802_3.an_tx_802_3_payload_len); 2681108401Sambrisko 2682108401Sambrisko /* 2683108401Sambrisko * If there's a BPF listner, bounce a copy of 2684108401Sambrisko * this frame to him. 2685108401Sambrisko */ 2686108401Sambrisko BPF_MTAP(ifp, m0); 2687108401Sambrisko 2688108401Sambrisko m_freem(m0); 2689108401Sambrisko m0 = NULL; 2690108401Sambrisko 2691108401Sambrisko sc->an_rdata.an_tx_ring[idx] = id; 2692108401Sambrisko if (an_cmd(sc, AN_CMD_TX, id)) 2693108401Sambrisko printf("an%d: xmit failed\n", sc->an_unit); 2694108401Sambrisko 2695108401Sambrisko AN_INC(idx, AN_TX_RING_CNT); 2696119156Sambrisko 2697119156Sambrisko /* 2698119156Sambrisko * Set a timeout in case the chip goes out to lunch. 2699119156Sambrisko */ 2700119156Sambrisko ifp->if_timer = 5; 2701108401Sambrisko } 2702108401Sambrisko } else { /* MPI-350 */ 2703130620Sambrisko /* Disable interrupts. */ 2704130620Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0); 2705130620Sambrisko 2706108401Sambrisko while (sc->an_rdata.an_tx_empty || 2707108401Sambrisko idx != sc->an_rdata.an_tx_cons) { 2708132986Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); 2709108401Sambrisko if (m0 == NULL) { 2710108401Sambrisko break; 2711108401Sambrisko } 2712108401Sambrisko buf = sc->an_tx_buffer[idx].an_dma_vaddr; 2713108401Sambrisko 2714108401Sambrisko eh = mtod(m0, struct ether_header *); 2715108401Sambrisko 2716108401Sambrisko /* DJA optimize this to limit bcopy */ 2717108401Sambrisko bcopy((char *)&eh->ether_dhost, 2718108401Sambrisko (char *)&tx_frame_802_3.an_tx_dst_addr, 2719108401Sambrisko ETHER_ADDR_LEN); 2720108401Sambrisko bcopy((char *)&eh->ether_shost, 2721108401Sambrisko (char *)&tx_frame_802_3.an_tx_src_addr, 2722108401Sambrisko ETHER_ADDR_LEN); 2723108401Sambrisko 2724108401Sambrisko /* minus src/dest mac & type */ 2725108401Sambrisko tx_frame_802_3.an_tx_802_3_payload_len = 2726108401Sambrisko m0->m_pkthdr.len - 12; 2727108401Sambrisko 2728108401Sambrisko m_copydata(m0, sizeof(struct ether_header) - 2 , 2729108401Sambrisko tx_frame_802_3.an_tx_802_3_payload_len, 2730108401Sambrisko (caddr_t)&sc->an_txbuf); 2731108401Sambrisko 2732108401Sambrisko txcontrol = AN_TXCTL_8023; 2733108401Sambrisko /* write the txcontrol only */ 2734108401Sambrisko bcopy((caddr_t)&txcontrol, &buf[0x08], 273555992Swpaul sizeof(txcontrol)); 273683270Sbrooks 2737108401Sambrisko /* 802_3 header */ 2738108401Sambrisko bcopy((caddr_t)&tx_frame_802_3, &buf[0x34], 273955992Swpaul sizeof(struct an_txframe_802_3)); 274083270Sbrooks 2741108401Sambrisko /* in mbuf header type is just before payload */ 2742108401Sambrisko bcopy((caddr_t)&sc->an_txbuf, &buf[0x44], 2743108401Sambrisko tx_frame_802_3.an_tx_802_3_payload_len); 274483270Sbrooks 274555992Swpaul 2746108401Sambrisko bzero(&an_tx_desc, sizeof(an_tx_desc)); 2747108401Sambrisko an_tx_desc.an_offset = 0; 2748108401Sambrisko an_tx_desc.an_eoc = 1; 2749108401Sambrisko an_tx_desc.an_valid = 1; 2750108401Sambrisko an_tx_desc.an_len = 0x44 + 2751119156Sambrisko tx_frame_802_3.an_tx_802_3_payload_len; 2752119156Sambrisko an_tx_desc.an_phys 2753119156Sambrisko = sc->an_tx_buffer[idx].an_dma_paddr; 2754119156Sambrisko for (i = 0; i < sizeof(an_tx_desc) / 4 ; i++) { 2755119156Sambrisko CSR_MEM_AUX_WRITE_4(sc, AN_TX_DESC_OFFSET 2756119156Sambrisko /* zero for now */ 2757119156Sambrisko + (0 * sizeof(an_tx_desc)) 2758119156Sambrisko + (i * 4), 2759155321Simp ((u_int32_t *)(void *)&an_tx_desc)[i]); 2760108401Sambrisko } 276155992Swpaul 2762108401Sambrisko /* 2763108401Sambrisko * If there's a BPF listner, bounce a copy of 2764108401Sambrisko * this frame to him. 2765108401Sambrisko */ 2766108401Sambrisko BPF_MTAP(ifp, m0); 276755992Swpaul 2768108401Sambrisko m_freem(m0); 2769108401Sambrisko m0 = NULL; 2770119156Sambrisko AN_INC(idx, AN_MAX_TX_DESC); 2771119156Sambrisko sc->an_rdata.an_tx_empty = 0; 2772108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC); 2773108401Sambrisko 2774119156Sambrisko /* 2775119156Sambrisko * Set a timeout in case the chip goes out to lunch. 2776119156Sambrisko */ 2777119156Sambrisko ifp->if_timer = 5; 2778108401Sambrisko } 2779130620Sambrisko 2780130620Sambrisko /* Re-enable interrupts. */ 2781130620Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350)); 278255992Swpaul } 278355992Swpaul 278455992Swpaul if (m0 != NULL) 2785148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 278655992Swpaul 278755992Swpaul sc->an_rdata.an_tx_prod = idx; 278855992Swpaul 278955992Swpaul return; 279055992Swpaul} 279155992Swpaul 279283270Sbrooksvoid 2793150446Simpan_stop(struct an_softc *sc) 279455992Swpaul{ 279555992Swpaul struct ifnet *ifp; 279655992Swpaul int i; 279755992Swpaul 279867094Swpaul AN_LOCK(sc); 279967094Swpaul 280067094Swpaul if (sc->an_gone) { 280167094Swpaul AN_UNLOCK(sc); 280255992Swpaul return; 280367094Swpaul } 280455992Swpaul 2805147256Sbrooks ifp = sc->an_ifp; 280655992Swpaul 280755992Swpaul an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0); 2808108401Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0); 280955992Swpaul an_cmd(sc, AN_CMD_DISABLE, 0); 281055992Swpaul 281155992Swpaul for (i = 0; i < AN_TX_RING_CNT; i++) 281255992Swpaul an_cmd(sc, AN_CMD_DEALLOC_MEM, sc->an_rdata.an_tx_fids[i]); 281355992Swpaul 281455992Swpaul untimeout(an_stats_update, sc, sc->an_stat_ch); 281555992Swpaul 2816148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_RUNNING|IFF_DRV_OACTIVE); 281755992Swpaul 2818108401Sambrisko if (sc->an_flash_buffer) { 2819108401Sambrisko free(sc->an_flash_buffer, M_DEVBUF); 2820108401Sambrisko sc->an_flash_buffer = NULL; 2821108401Sambrisko } 2822108401Sambrisko 282367094Swpaul AN_UNLOCK(sc); 282467094Swpaul 282555992Swpaul return; 282655992Swpaul} 282755992Swpaul 282883270Sbrooksstatic void 2829150446Simpan_watchdog(struct ifnet *ifp) 283055992Swpaul{ 283155992Swpaul struct an_softc *sc; 283255992Swpaul 283355992Swpaul sc = ifp->if_softc; 283467094Swpaul AN_LOCK(sc); 283555992Swpaul 283667094Swpaul if (sc->an_gone) { 283767094Swpaul AN_UNLOCK(sc); 283855992Swpaul return; 283967094Swpaul } 284055992Swpaul 284155992Swpaul printf("an%d: device timeout\n", sc->an_unit); 284255992Swpaul 284355992Swpaul an_reset(sc); 2844108401Sambrisko if (sc->mpi350) 2845108401Sambrisko an_init_mpi350_desc(sc); 284655992Swpaul an_init(sc); 284755992Swpaul 284855992Swpaul ifp->if_oerrors++; 284967094Swpaul AN_UNLOCK(sc); 285055992Swpaul 285155992Swpaul return; 285255992Swpaul} 285355992Swpaul 285483270Sbrooksvoid 2855150446Simpan_shutdown(device_t dev) 285655992Swpaul{ 285755992Swpaul struct an_softc *sc; 285855992Swpaul 285955992Swpaul sc = device_get_softc(dev); 286055992Swpaul an_stop(sc); 2861110531Sambrisko sc->an_gone = 1; 286255992Swpaul 286355992Swpaul return; 286455992Swpaul} 286555992Swpaul 2866110362Sambriskovoid 2867150446Simpan_resume(device_t dev) 2868110362Sambrisko{ 2869110362Sambrisko struct an_softc *sc; 2870110362Sambrisko struct ifnet *ifp; 2871110531Sambrisko int i; 2872110531Sambrisko 2873110362Sambrisko sc = device_get_softc(dev); 2874110531Sambrisko AN_LOCK(sc); 2875147256Sbrooks ifp = sc->an_ifp; 2876110362Sambrisko 2877110531Sambrisko sc->an_gone = 0; 2878110362Sambrisko an_reset(sc); 2879110362Sambrisko if (sc->mpi350) 2880110362Sambrisko an_init_mpi350_desc(sc); 2881110362Sambrisko an_init(sc); 2882110362Sambrisko 2883110531Sambrisko /* Recovery temporary keys */ 2884110531Sambrisko for (i = 0; i < 4; i++) { 2885110531Sambrisko sc->areq.an_type = AN_RID_WEP_TEMP; 2886110531Sambrisko sc->areq.an_len = sizeof(struct an_ltv_key); 2887110531Sambrisko bcopy(&sc->an_temp_keys[i], 2888110531Sambrisko &sc->areq, sizeof(struct an_ltv_key)); 2889110531Sambrisko an_setdef(sc, &sc->areq); 2890110531Sambrisko } 2891110531Sambrisko 2892110362Sambrisko if (ifp->if_flags & IFF_UP) 2893110362Sambrisko an_start(ifp); 2894110531Sambrisko AN_UNLOCK(sc); 2895110362Sambrisko 2896110362Sambrisko return; 2897110362Sambrisko} 2898110362Sambrisko 289955992Swpaul#ifdef ANCACHE 290055992Swpaul/* Aironet signal strength cache code. 290155992Swpaul * store signal/noise/quality on per MAC src basis in 290255992Swpaul * a small fixed cache. The cache wraps if > MAX slots 290355992Swpaul * used. The cache may be zeroed out to start over. 290455992Swpaul * Two simple filters exist to reduce computation: 290588748Sambrisko * 1. ip only (literally 0x800, ETHERTYPE_IP) which may be used 290655992Swpaul * to ignore some packets. It defaults to ip only. 290755992Swpaul * it could be used to focus on broadcast, non-IP 802.11 beacons. 290855992Swpaul * 2. multicast/broadcast only. This may be used to 290955992Swpaul * ignore unicast packets and only cache signal strength 291055992Swpaul * for multicast/broadcast packets (beacons); e.g., Mobile-IP 291155992Swpaul * beacons and not unicast traffic. 291255992Swpaul * 291355992Swpaul * The cache stores (MAC src(index), IP src (major clue), signal, 291455992Swpaul * quality, noise) 291555992Swpaul * 291655992Swpaul * No apologies for storing IP src here. It's easy and saves much 291783270Sbrooks * trouble elsewhere. The cache is assumed to be INET dependent, 291855992Swpaul * although it need not be. 291955992Swpaul * 292055992Swpaul * Note: the Aironet only has a single byte of signal strength value 292155992Swpaul * in the rx frame header, and it's not scaled to anything sensible. 292255992Swpaul * This is kind of lame, but it's all we've got. 292355992Swpaul */ 292455992Swpaul 292555992Swpaul#ifdef documentation 292655992Swpaul 292755992Swpaulint an_sigitems; /* number of cached entries */ 292855992Swpaulstruct an_sigcache an_sigcache[MAXANCACHE]; /* array of cache entries */ 292955992Swpaulint an_nextitem; /* index/# of entries */ 293055992Swpaul 293155992Swpaul 293255992Swpaul#endif 293355992Swpaul 293455992Swpaul/* control variables for cache filtering. Basic idea is 293555992Swpaul * to reduce cost (e.g., to only Mobile-IP agent beacons 293655992Swpaul * which are broadcast or multicast). Still you might 293755992Swpaul * want to measure signal strength anth unicast ping packets 293855992Swpaul * on a pt. to pt. ant. setup. 293955992Swpaul */ 294083270Sbrooks/* set true if you want to limit cache items to broadcast/mcast 294155992Swpaul * only packets (not unicast). Useful for mobile-ip beacons which 294255992Swpaul * are broadcast/multicast at network layer. Default is all packets 294355992Swpaul * so ping/unicast anll work say anth pt. to pt. antennae setup. 294455992Swpaul */ 294555992Swpaulstatic int an_cache_mcastonly = 0; 2946110531SambriskoSYSCTL_INT(_hw_an, OID_AUTO, an_cache_mcastonly, CTLFLAG_RW, 294755992Swpaul &an_cache_mcastonly, 0, ""); 294855992Swpaul 294955992Swpaul/* set true if you want to limit cache items to IP packets only 295055992Swpaul*/ 295155992Swpaulstatic int an_cache_iponly = 1; 2952110531SambriskoSYSCTL_INT(_hw_an, OID_AUTO, an_cache_iponly, CTLFLAG_RW, 295355992Swpaul &an_cache_iponly, 0, ""); 295455992Swpaul 295555992Swpaul/* 295655992Swpaul * an_cache_store, per rx packet store signal 295755992Swpaul * strength in MAC (src) indexed cache. 295855992Swpaul */ 295983270Sbrooksstatic void 2960150446Simpan_cache_store(struct an_softc *sc, struct ether_header *eh, struct mbuf *m, 2961150446Simp u_int8_t rx_rssi, u_int8_t rx_quality) 296255992Swpaul{ 296383270Sbrooks struct ip *ip = 0; 296455992Swpaul int i; 296555992Swpaul static int cache_slot = 0; /* use this cache entry */ 296655992Swpaul static int wrapindex = 0; /* next "free" cache entry */ 296788748Sambrisko int type_ipv4 = 0; 296855992Swpaul 296955992Swpaul /* filters: 297055992Swpaul * 1. ip only 297155992Swpaul * 2. configurable filter to throw out unicast packets, 297255992Swpaul * keep multicast only. 297355992Swpaul */ 297483270Sbrooks 297588748Sambrisko if ((ntohs(eh->ether_type) == ETHERTYPE_IP)) { 297688748Sambrisko type_ipv4 = 1; 297755992Swpaul } 297855992Swpaul 297983270Sbrooks /* filter for ip packets only 298055992Swpaul */ 298188748Sambrisko if ( an_cache_iponly && !type_ipv4) { 298255992Swpaul return; 298355992Swpaul } 298455992Swpaul 298555992Swpaul /* filter for broadcast/multicast only 298655992Swpaul */ 298755992Swpaul if (an_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) { 298855992Swpaul return; 298955992Swpaul } 299055992Swpaul 299155992Swpaul#ifdef SIGDEBUG 299255992Swpaul printf("an: q value %x (MSB=0x%x, LSB=0x%x) \n", 2993108401Sambrisko rx_rssi & 0xffff, rx_rssi >> 8, rx_rssi & 0xff); 299455992Swpaul#endif 299555992Swpaul 299655992Swpaul /* find the ip header. we want to store the ip_src 299783270Sbrooks * address. 299855992Swpaul */ 299988748Sambrisko if (type_ipv4) { 300055992Swpaul ip = mtod(m, struct ip *); 300155992Swpaul } 300283270Sbrooks 300383270Sbrooks /* do a linear search for a matching MAC address 300455992Swpaul * in the cache table 300555992Swpaul * . MAC address is 6 bytes, 300655992Swpaul * . var w_nextitem holds total number of entries already cached 300755992Swpaul */ 300878639Sbrooks for (i = 0; i < sc->an_nextitem; i++) { 300955992Swpaul if (! bcmp(eh->ether_shost , sc->an_sigcache[i].macsrc, 6 )) { 301055992Swpaul /* Match!, 301155992Swpaul * so we already have this entry, 301255992Swpaul * update the data 301355992Swpaul */ 301483270Sbrooks break; 301555992Swpaul } 301655992Swpaul } 301755992Swpaul 301855992Swpaul /* did we find a matching mac address? 301955992Swpaul * if yes, then overwrite a previously existing cache entry 302055992Swpaul */ 302155992Swpaul if (i < sc->an_nextitem ) { 302283270Sbrooks cache_slot = i; 302355992Swpaul } 302455992Swpaul /* else, have a new address entry,so 302555992Swpaul * add this new entry, 302655992Swpaul * if table full, then we need to replace LRU entry 302755992Swpaul */ 302883270Sbrooks else { 302955992Swpaul 303083270Sbrooks /* check for space in cache table 303155992Swpaul * note: an_nextitem also holds number of entries 303283270Sbrooks * added in the cache table 303355992Swpaul */ 303455992Swpaul if ( sc->an_nextitem < MAXANCACHE ) { 303555992Swpaul cache_slot = sc->an_nextitem; 303683270Sbrooks sc->an_nextitem++; 303755992Swpaul sc->an_sigitems = sc->an_nextitem; 303855992Swpaul } 303955992Swpaul /* no space found, so simply wrap anth wrap index 304055992Swpaul * and "zap" the next entry 304155992Swpaul */ 304255992Swpaul else { 304355992Swpaul if (wrapindex == MAXANCACHE) { 304455992Swpaul wrapindex = 0; 304555992Swpaul } 304655992Swpaul cache_slot = wrapindex++; 304755992Swpaul } 304855992Swpaul } 304955992Swpaul 305055992Swpaul /* invariant: cache_slot now points at some slot 305155992Swpaul * in cache. 305255992Swpaul */ 305355992Swpaul if (cache_slot < 0 || cache_slot >= MAXANCACHE) { 305455992Swpaul log(LOG_ERR, "an_cache_store, bad index: %d of " 305555992Swpaul "[0..%d], gross cache error\n", 305655992Swpaul cache_slot, MAXANCACHE); 305755992Swpaul return; 305855992Swpaul } 305955992Swpaul 306055992Swpaul /* store items in cache 306155992Swpaul * .ip source address 306255992Swpaul * .mac src 306355992Swpaul * .signal, etc. 306455992Swpaul */ 306588748Sambrisko if (type_ipv4) { 306655992Swpaul sc->an_sigcache[cache_slot].ipsrc = ip->ip_src.s_addr; 306755992Swpaul } 306855992Swpaul bcopy( eh->ether_shost, sc->an_sigcache[cache_slot].macsrc, 6); 306955992Swpaul 307055992Swpaul 3071108401Sambrisko switch (an_cache_mode) { 3072108401Sambrisko case DBM: 3073108401Sambrisko if (sc->an_have_rssimap) { 3074108401Sambrisko sc->an_sigcache[cache_slot].signal = 3075108401Sambrisko - sc->an_rssimap.an_entries[rx_rssi].an_rss_dbm; 3076108401Sambrisko sc->an_sigcache[cache_slot].quality = 3077108401Sambrisko - sc->an_rssimap.an_entries[rx_quality].an_rss_dbm; 3078108401Sambrisko } else { 3079108401Sambrisko sc->an_sigcache[cache_slot].signal = rx_rssi - 100; 3080108401Sambrisko sc->an_sigcache[cache_slot].quality = rx_quality - 100; 3081108401Sambrisko } 3082108401Sambrisko break; 3083108401Sambrisko case PERCENT: 3084108401Sambrisko if (sc->an_have_rssimap) { 3085108401Sambrisko sc->an_sigcache[cache_slot].signal = 3086108401Sambrisko sc->an_rssimap.an_entries[rx_rssi].an_rss_pct; 3087108401Sambrisko sc->an_sigcache[cache_slot].quality = 3088108401Sambrisko sc->an_rssimap.an_entries[rx_quality].an_rss_pct; 3089108401Sambrisko } else { 3090108401Sambrisko if (rx_rssi > 100) 3091108401Sambrisko rx_rssi = 100; 3092108401Sambrisko if (rx_quality > 100) 3093108401Sambrisko rx_quality = 100; 3094108401Sambrisko sc->an_sigcache[cache_slot].signal = rx_rssi; 3095108401Sambrisko sc->an_sigcache[cache_slot].quality = rx_quality; 3096108401Sambrisko } 3097108401Sambrisko break; 3098108401Sambrisko case RAW: 3099108401Sambrisko sc->an_sigcache[cache_slot].signal = rx_rssi; 3100108401Sambrisko sc->an_sigcache[cache_slot].quality = rx_quality; 3101108401Sambrisko break; 3102108401Sambrisko } 3103108401Sambrisko 3104108401Sambrisko sc->an_sigcache[cache_slot].noise = 0; 3105108401Sambrisko 310655992Swpaul return; 310755992Swpaul} 310855992Swpaul#endif 310977217Sphk 311083270Sbrooksstatic int 3111150446Simpan_media_change(struct ifnet *ifp) 311277217Sphk{ 311377217Sphk struct an_softc *sc = ifp->if_softc; 3114110253Sambrisko struct an_ltv_genconfig *cfg; 311577217Sphk int otype = sc->an_config.an_opmode; 311677217Sphk int orate = sc->an_tx_rate; 311777217Sphk 3118116951Ssam sc->an_tx_rate = ieee80211_media2rate( 3119116951Ssam IFM_SUBTYPE(sc->an_ifmedia.ifm_cur->ifm_media)); 3120119156Sambrisko if (sc->an_tx_rate < 0) 3121119156Sambrisko sc->an_tx_rate = 0; 3122110253Sambrisko 3123110253Sambrisko if (orate != sc->an_tx_rate) { 3124110253Sambrisko /* Read the current configuration */ 3125110253Sambrisko sc->an_config.an_type = AN_RID_GENCONFIG; 3126110253Sambrisko sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 3127110253Sambrisko an_read_record(sc, (struct an_ltv_gen *)&sc->an_config); 3128110253Sambrisko cfg = &sc->an_config; 3129110253Sambrisko 3130110253Sambrisko /* clear other rates and set the only one we want */ 3131110253Sambrisko bzero(cfg->an_rates, sizeof(cfg->an_rates)); 3132110253Sambrisko cfg->an_rates[0] = sc->an_tx_rate; 3133110253Sambrisko 3134110253Sambrisko /* Save the new rate */ 3135110253Sambrisko sc->an_config.an_type = AN_RID_GENCONFIG; 3136110253Sambrisko sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 313777217Sphk } 313877217Sphk 3139119156Sambrisko if ((sc->an_ifmedia.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC) != 0) 3140119156Sambrisko sc->an_config.an_opmode &= ~AN_OPMODE_INFRASTRUCTURE_STATION; 3141119156Sambrisko else 3142119156Sambrisko sc->an_config.an_opmode |= AN_OPMODE_INFRASTRUCTURE_STATION; 3143119156Sambrisko 3144110531Sambrisko if (otype != sc->an_config.an_opmode || 3145110531Sambrisko orate != sc->an_tx_rate) 314677217Sphk an_init(sc); 314777217Sphk 314877217Sphk return(0); 314977217Sphk} 315077217Sphk 315183270Sbrooksstatic void 3152150446Simpan_media_status(struct ifnet *ifp, struct ifmediareq *imr) 315377217Sphk{ 315477217Sphk struct an_ltv_status status; 315577217Sphk struct an_softc *sc = ifp->if_softc; 315677217Sphk 3157110253Sambrisko imr->ifm_active = IFM_IEEE80211; 3158110253Sambrisko 315977217Sphk status.an_len = sizeof(status); 316077217Sphk status.an_type = AN_RID_STATUS; 316177217Sphk if (an_read_record(sc, (struct an_ltv_gen *)&status)) { 316277217Sphk /* If the status read fails, just lie. */ 316377217Sphk imr->ifm_active = sc->an_ifmedia.ifm_cur->ifm_media; 316477217Sphk imr->ifm_status = IFM_AVALID|IFM_ACTIVE; 316577217Sphk } 316677217Sphk 316778639Sbrooks if (sc->an_tx_rate == 0) { 316877217Sphk imr->ifm_active = IFM_IEEE80211|IFM_AUTO; 316977217Sphk } 317077217Sphk 3171110253Sambrisko if (sc->an_config.an_opmode == AN_OPMODE_IBSS_ADHOC) 3172110253Sambrisko imr->ifm_active |= IFM_IEEE80211_ADHOC; 3173116951Ssam imr->ifm_active |= ieee80211_rate2media(NULL, 3174116951Ssam status.an_current_tx_rate, IEEE80211_T_DS); 317577217Sphk imr->ifm_status = IFM_AVALID; 317691283Sambrisko if (status.an_opmode & AN_STATUS_OPMODE_ASSOCIATED) 317777217Sphk imr->ifm_status |= IFM_ACTIVE; 317877217Sphk} 317988748Sambrisko 318088748Sambrisko/********************** Cisco utility support routines *************/ 318188748Sambrisko 318288748Sambrisko/* 318388748Sambrisko * ReadRids & WriteRids derived from Cisco driver additions to Ben Reed's 318488748Sambrisko * Linux driver 318588748Sambrisko */ 318688748Sambrisko 318788748Sambriskostatic int 3188150446Simpreadrids(struct ifnet *ifp, struct aironet_ioctl *l_ioctl) 318988748Sambrisko{ 319088749Sambrisko unsigned short rid; 319188748Sambrisko struct an_softc *sc; 3192171692Savatar int error; 319388748Sambrisko 319488748Sambrisko switch (l_ioctl->command) { 319588748Sambrisko case AIROGCAP: 319688748Sambrisko rid = AN_RID_CAPABILITIES; 319788748Sambrisko break; 319888748Sambrisko case AIROGCFG: 319988748Sambrisko rid = AN_RID_GENCONFIG; 320088748Sambrisko break; 320188748Sambrisko case AIROGSLIST: 320288748Sambrisko rid = AN_RID_SSIDLIST; 320388748Sambrisko break; 320488748Sambrisko case AIROGVLIST: 320588748Sambrisko rid = AN_RID_APLIST; 320688748Sambrisko break; 320788748Sambrisko case AIROGDRVNAM: 320888748Sambrisko rid = AN_RID_DRVNAME; 320988748Sambrisko break; 321088748Sambrisko case AIROGEHTENC: 321188748Sambrisko rid = AN_RID_ENCAPPROTO; 321288748Sambrisko break; 321388748Sambrisko case AIROGWEPKTMP: 321488748Sambrisko rid = AN_RID_WEP_TEMP; 321588748Sambrisko break; 321688748Sambrisko case AIROGWEPKNV: 321788748Sambrisko rid = AN_RID_WEP_PERM; 321888748Sambrisko break; 321988748Sambrisko case AIROGSTAT: 322088748Sambrisko rid = AN_RID_STATUS; 322188748Sambrisko break; 322288748Sambrisko case AIROGSTATSD32: 322388748Sambrisko rid = AN_RID_32BITS_DELTA; 322488748Sambrisko break; 322588748Sambrisko case AIROGSTATSC32: 322688748Sambrisko rid = AN_RID_32BITS_CUM; 322788748Sambrisko break; 322888748Sambrisko default: 322988748Sambrisko rid = 999; 323088748Sambrisko break; 323188748Sambrisko } 323288748Sambrisko 323388748Sambrisko if (rid == 999) /* Is bad command */ 323488748Sambrisko return -EINVAL; 323588748Sambrisko 323688748Sambrisko sc = ifp->if_softc; 323788749Sambrisko sc->areq.an_len = AN_MAX_DATALEN; 323888749Sambrisko sc->areq.an_type = rid; 323988748Sambrisko 324088749Sambrisko an_read_record(sc, (struct an_ltv_gen *)&sc->areq); 324188748Sambrisko 324288749Sambrisko l_ioctl->len = sc->areq.an_len - 4; /* just data */ 324388748Sambrisko 3244171692Savatar AN_UNLOCK(sc); 324588748Sambrisko /* the data contains the length at first */ 324688749Sambrisko if (copyout(&(sc->areq.an_len), l_ioctl->data, 324788749Sambrisko sizeof(sc->areq.an_len))) { 3248171692Savatar error = -EFAULT; 3249171692Savatar goto lock_exit; 325088748Sambrisko } 325188748Sambrisko /* Just copy the data back */ 325288749Sambrisko if (copyout(&(sc->areq.an_val), l_ioctl->data + 2, 325388748Sambrisko l_ioctl->len)) { 3254171692Savatar error = -EFAULT; 3255171692Savatar goto lock_exit; 325688748Sambrisko } 3257171692Savatar error = 0; 3258171692Savatarlock_exit: 3259171692Savatar AN_LOCK(sc); 3260171692Savatar return (error); 326188748Sambrisko} 326288748Sambrisko 326388748Sambriskostatic int 3264150446Simpwriterids(struct ifnet *ifp, struct aironet_ioctl *l_ioctl) 326588748Sambrisko{ 326688748Sambrisko struct an_softc *sc; 3267171692Savatar int rid, command, error; 326888748Sambrisko 326988748Sambrisko sc = ifp->if_softc; 327088748Sambrisko rid = 0; 327188748Sambrisko command = l_ioctl->command; 327288748Sambrisko 327388748Sambrisko switch (command) { 327488748Sambrisko case AIROPSIDS: 327588748Sambrisko rid = AN_RID_SSIDLIST; 327688748Sambrisko break; 327788748Sambrisko case AIROPCAP: 327888748Sambrisko rid = AN_RID_CAPABILITIES; 327988748Sambrisko break; 328088748Sambrisko case AIROPAPLIST: 328188748Sambrisko rid = AN_RID_APLIST; 328288748Sambrisko break; 328388748Sambrisko case AIROPCFG: 328488748Sambrisko rid = AN_RID_GENCONFIG; 328588748Sambrisko break; 328688748Sambrisko case AIROPMACON: 328788748Sambrisko an_cmd(sc, AN_CMD_ENABLE, 0); 328888748Sambrisko return 0; 328988748Sambrisko break; 329088748Sambrisko case AIROPMACOFF: 329188748Sambrisko an_cmd(sc, AN_CMD_DISABLE, 0); 329288748Sambrisko return 0; 329388748Sambrisko break; 329488748Sambrisko case AIROPSTCLR: 329588748Sambrisko /* 329688748Sambrisko * This command merely clears the counts does not actually 329788748Sambrisko * store any data only reads rid. But as it changes the cards 329888748Sambrisko * state, I put it in the writerid routines. 329988748Sambrisko */ 330088748Sambrisko 330188748Sambrisko rid = AN_RID_32BITS_DELTACLR; 330288748Sambrisko sc = ifp->if_softc; 330388749Sambrisko sc->areq.an_len = AN_MAX_DATALEN; 330488749Sambrisko sc->areq.an_type = rid; 330588748Sambrisko 330688749Sambrisko an_read_record(sc, (struct an_ltv_gen *)&sc->areq); 330788749Sambrisko l_ioctl->len = sc->areq.an_len - 4; /* just data */ 330888748Sambrisko 3309171692Savatar AN_UNLOCK(sc); 331088748Sambrisko /* the data contains the length at first */ 3311171692Savatar error = copyout(&(sc->areq.an_len), l_ioctl->data, 3312171692Savatar sizeof(sc->areq.an_len)); 3313171692Savatar if (error) { 3314171692Savatar AN_LOCK(sc); 331588748Sambrisko return -EFAULT; 331688748Sambrisko } 331788748Sambrisko /* Just copy the data */ 3318171692Savatar error = copyout(&(sc->areq.an_val), l_ioctl->data + 2, 3319171692Savatar l_ioctl->len); 3320171692Savatar AN_LOCK(sc); 3321171692Savatar if (error) 332288748Sambrisko return -EFAULT; 332388748Sambrisko return 0; 332488748Sambrisko break; 332588748Sambrisko case AIROPWEPKEY: 332688748Sambrisko rid = AN_RID_WEP_TEMP; 332788748Sambrisko break; 332888748Sambrisko case AIROPWEPKEYNV: 332988748Sambrisko rid = AN_RID_WEP_PERM; 333088748Sambrisko break; 333188748Sambrisko case AIROPLEAPUSR: 333288748Sambrisko rid = AN_RID_LEAPUSERNAME; 333388748Sambrisko break; 333488748Sambrisko case AIROPLEAPPWD: 333588748Sambrisko rid = AN_RID_LEAPPASSWORD; 333688748Sambrisko break; 333788748Sambrisko default: 333888748Sambrisko return -EOPNOTSUPP; 333988748Sambrisko } 334088748Sambrisko 334188748Sambrisko if (rid) { 334288749Sambrisko if (l_ioctl->len > sizeof(sc->areq.an_val) + 4) 334388748Sambrisko return -EINVAL; 334488749Sambrisko sc->areq.an_len = l_ioctl->len + 4; /* add type & length */ 334588749Sambrisko sc->areq.an_type = rid; 334688748Sambrisko 334788748Sambrisko /* Just copy the data back */ 3348171692Savatar AN_UNLOCK(sc); 3349171692Savatar error = copyin((l_ioctl->data) + 2, &sc->areq.an_val, 3350171692Savatar l_ioctl->len); 3351171692Savatar AN_LOCK(sc); 3352171692Savatar if (error) 3353144242Ssam return -EFAULT; 3354171692Savatar 335588748Sambrisko an_cmd(sc, AN_CMD_DISABLE, 0); 335688749Sambrisko an_write_record(sc, (struct an_ltv_gen *)&sc->areq); 335788748Sambrisko an_cmd(sc, AN_CMD_ENABLE, 0); 335888748Sambrisko return 0; 335988748Sambrisko } 336088748Sambrisko return -EOPNOTSUPP; 336188748Sambrisko} 336288748Sambrisko 336388748Sambrisko/* 336488748Sambrisko * General Flash utilities derived from Cisco driver additions to Ben Reed's 336588748Sambrisko * Linux driver 336688748Sambrisko */ 336788748Sambrisko 3368123978Sambrisko#define FLASH_DELAY(_sc, x) msleep(ifp, &(_sc)->an_mtx, PZERO, \ 3369123978Sambrisko "flash", ((x) / hz) + 1); 3370108401Sambrisko#define FLASH_COMMAND 0x7e7e 3371108401Sambrisko#define FLASH_SIZE 32 * 1024 337288748Sambrisko 337388748Sambriskostatic int 3374150446Simpunstickbusy(struct ifnet *ifp) 337588748Sambrisko{ 337688748Sambrisko struct an_softc *sc = ifp->if_softc; 337788748Sambrisko 3378108401Sambrisko if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) { 3379108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), 3380108401Sambrisko AN_EV_CLR_STUCK_BUSY); 338188748Sambrisko return 1; 338288748Sambrisko } 338388748Sambrisko return 0; 338488748Sambrisko} 338588748Sambrisko 338688748Sambrisko/* 338788748Sambrisko * Wait for busy completion from card wait for delay uSec's Return true for 338888748Sambrisko * success meaning command reg is clear 338988748Sambrisko */ 339088748Sambrisko 339188748Sambriskostatic int 3392150446SimpWaitBusy(struct ifnet *ifp, int uSec) 339388748Sambrisko{ 339488748Sambrisko int statword = 0xffff; 339588748Sambrisko int delay = 0; 339688748Sambrisko struct an_softc *sc = ifp->if_softc; 339788748Sambrisko 339888748Sambrisko while ((statword & AN_CMD_BUSY) && delay <= (1000 * 100)) { 3399119163Sambrisko FLASH_DELAY(sc, 10); 340088748Sambrisko delay += 10; 3401108401Sambrisko statword = CSR_READ_2(sc, AN_COMMAND(sc->mpi350)); 340288748Sambrisko 340388748Sambrisko if ((AN_CMD_BUSY & statword) && (delay % 200)) { 340488748Sambrisko unstickbusy(ifp); 340588748Sambrisko } 340688748Sambrisko } 340788748Sambrisko 340888748Sambrisko return 0 == (AN_CMD_BUSY & statword); 340988748Sambrisko} 341088748Sambrisko 341188748Sambrisko/* 341288748Sambrisko * STEP 1) Disable MAC and do soft reset on card. 341388748Sambrisko */ 341488748Sambrisko 341588748Sambriskostatic int 3416150446Simpcmdreset(struct ifnet *ifp) 341788748Sambrisko{ 341888748Sambrisko int status; 341988748Sambrisko struct an_softc *sc = ifp->if_softc; 342088748Sambrisko 342188748Sambrisko an_stop(sc); 342288748Sambrisko 342388748Sambrisko an_cmd(sc, AN_CMD_DISABLE, 0); 342488748Sambrisko 3425108401Sambrisko if (!(status = WaitBusy(ifp, AN_TIMEOUT))) { 342688748Sambrisko printf("an%d: Waitbusy hang b4 RESET =%d\n", 342788748Sambrisko sc->an_unit, status); 342888748Sambrisko return -EBUSY; 342988748Sambrisko } 3430108401Sambrisko CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), AN_CMD_FW_RESTART); 343188748Sambrisko 3432119163Sambrisko FLASH_DELAY(sc, 1000); /* WAS 600 12/7/00 */ 343388748Sambrisko 343488748Sambrisko 343588748Sambrisko if (!(status = WaitBusy(ifp, 100))) { 343688748Sambrisko printf("an%d: Waitbusy hang AFTER RESET =%d\n", 343788748Sambrisko sc->an_unit, status); 343888748Sambrisko return -EBUSY; 343988748Sambrisko } 344088748Sambrisko return 0; 344188748Sambrisko} 344288748Sambrisko 344388748Sambrisko/* 344488748Sambrisko * STEP 2) Put the card in legendary flash mode 344588748Sambrisko */ 344688748Sambrisko 344788748Sambriskostatic int 3448150446Simpsetflashmode(struct ifnet *ifp) 344988748Sambrisko{ 345088748Sambrisko int status; 345188748Sambrisko struct an_softc *sc = ifp->if_softc; 345288748Sambrisko 3453108401Sambrisko CSR_WRITE_2(sc, AN_SW0(sc->mpi350), FLASH_COMMAND); 3454108401Sambrisko CSR_WRITE_2(sc, AN_SW1(sc->mpi350), FLASH_COMMAND); 3455108401Sambrisko CSR_WRITE_2(sc, AN_SW0(sc->mpi350), FLASH_COMMAND); 3456108401Sambrisko CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), FLASH_COMMAND); 345788748Sambrisko 345888748Sambrisko /* 345988748Sambrisko * mdelay(500); // 500ms delay 346088748Sambrisko */ 346188748Sambrisko 3462119163Sambrisko FLASH_DELAY(sc, 500); 346388748Sambrisko 3464108401Sambrisko if (!(status = WaitBusy(ifp, AN_TIMEOUT))) { 346588748Sambrisko printf("Waitbusy hang after setflash mode\n"); 346688748Sambrisko return -EIO; 346788748Sambrisko } 346888748Sambrisko return 0; 346988748Sambrisko} 347088748Sambrisko 347188748Sambrisko/* 347288748Sambrisko * Get a character from the card matching matchbyte Step 3) 347388748Sambrisko */ 347488748Sambrisko 347588748Sambriskostatic int 3476150446Simpflashgchar(struct ifnet *ifp, int matchbyte, int dwelltime) 347788748Sambrisko{ 347888748Sambrisko int rchar; 347988748Sambrisko unsigned char rbyte = 0; 348088748Sambrisko int success = -1; 348188748Sambrisko struct an_softc *sc = ifp->if_softc; 348288748Sambrisko 348388748Sambrisko 348488748Sambrisko do { 3485108401Sambrisko rchar = CSR_READ_2(sc, AN_SW1(sc->mpi350)); 348688748Sambrisko 348788748Sambrisko if (dwelltime && !(0x8000 & rchar)) { 348888748Sambrisko dwelltime -= 10; 3489119163Sambrisko FLASH_DELAY(sc, 10); 349088748Sambrisko continue; 349188748Sambrisko } 349288748Sambrisko rbyte = 0xff & rchar; 349388748Sambrisko 349488748Sambrisko if ((rbyte == matchbyte) && (0x8000 & rchar)) { 3495108401Sambrisko CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0); 349688748Sambrisko success = 1; 349788748Sambrisko break; 349888748Sambrisko } 349988748Sambrisko if (rbyte == 0x81 || rbyte == 0x82 || rbyte == 0x83 || rbyte == 0x1a || 0xffff == rchar) 350088748Sambrisko break; 3501108401Sambrisko CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0); 350288748Sambrisko 350388748Sambrisko } while (dwelltime > 0); 350488748Sambrisko return success; 350588748Sambrisko} 350688748Sambrisko 350788748Sambrisko/* 350888748Sambrisko * Put character to SWS0 wait for dwelltime x 50us for echo . 350988748Sambrisko */ 351088748Sambrisko 351188748Sambriskostatic int 3512150446Simpflashpchar(struct ifnet *ifp, int byte, int dwelltime) 351388748Sambrisko{ 351488748Sambrisko int echo; 351588748Sambrisko int pollbusy, waittime; 351688748Sambrisko struct an_softc *sc = ifp->if_softc; 351788748Sambrisko 351888748Sambrisko byte |= 0x8000; 351988748Sambrisko 352088748Sambrisko if (dwelltime == 0) 352188748Sambrisko dwelltime = 200; 352288748Sambrisko 352388748Sambrisko waittime = dwelltime; 352488748Sambrisko 352588748Sambrisko /* 352688748Sambrisko * Wait for busy bit d15 to go false indicating buffer empty 352788748Sambrisko */ 352888748Sambrisko do { 3529108401Sambrisko pollbusy = CSR_READ_2(sc, AN_SW0(sc->mpi350)); 353088748Sambrisko 353188748Sambrisko if (pollbusy & 0x8000) { 3532119163Sambrisko FLASH_DELAY(sc, 50); 353388748Sambrisko waittime -= 50; 353488748Sambrisko continue; 353588748Sambrisko } else 353688748Sambrisko break; 353788748Sambrisko } 353888748Sambrisko while (waittime >= 0); 353988748Sambrisko 354088748Sambrisko /* timeout for busy clear wait */ 354188748Sambrisko 354288748Sambrisko if (waittime <= 0) { 354388748Sambrisko printf("an%d: flash putchar busywait timeout! \n", 354488748Sambrisko sc->an_unit); 354588748Sambrisko return -1; 354688748Sambrisko } 354788748Sambrisko /* 354888748Sambrisko * Port is clear now write byte and wait for it to echo back 354988748Sambrisko */ 355088748Sambrisko do { 3551108401Sambrisko CSR_WRITE_2(sc, AN_SW0(sc->mpi350), byte); 3552119163Sambrisko FLASH_DELAY(sc, 50); 355388748Sambrisko dwelltime -= 50; 3554108401Sambrisko echo = CSR_READ_2(sc, AN_SW1(sc->mpi350)); 355588748Sambrisko } while (dwelltime >= 0 && echo != byte); 355688748Sambrisko 355788748Sambrisko 3558108401Sambrisko CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0); 355988748Sambrisko 356088748Sambrisko return echo == byte; 356188748Sambrisko} 356288748Sambrisko 356388748Sambrisko/* 356488748Sambrisko * Transfer 32k of firmware data from user buffer to our buffer and send to 356588748Sambrisko * the card 356688748Sambrisko */ 356788748Sambrisko 356888748Sambriskostatic int 3569150446Simpflashputbuf(struct ifnet *ifp) 357088748Sambrisko{ 357188748Sambrisko unsigned short *bufp; 357288748Sambrisko int nwords; 357388748Sambrisko struct an_softc *sc = ifp->if_softc; 357488748Sambrisko 357588748Sambrisko /* Write stuff */ 357688748Sambrisko 3577108401Sambrisko bufp = sc->an_flash_buffer; 357888748Sambrisko 3579108401Sambrisko if (!sc->mpi350) { 3580108401Sambrisko CSR_WRITE_2(sc, AN_AUX_PAGE, 0x100); 3581108401Sambrisko CSR_WRITE_2(sc, AN_AUX_OFFSET, 0); 358288748Sambrisko 3583108401Sambrisko for (nwords = 0; nwords != FLASH_SIZE / 2; nwords++) { 3584108401Sambrisko CSR_WRITE_2(sc, AN_AUX_DATA, bufp[nwords] & 0xffff); 3585108401Sambrisko } 3586108401Sambrisko } else { 3587108401Sambrisko for (nwords = 0; nwords != FLASH_SIZE / 4; nwords++) { 3588108401Sambrisko CSR_MEM_AUX_WRITE_4(sc, 0x8000, 3589108401Sambrisko ((u_int32_t *)bufp)[nwords] & 0xffff); 3590108401Sambrisko } 359188748Sambrisko } 359288748Sambrisko 3593108401Sambrisko CSR_WRITE_2(sc, AN_SW0(sc->mpi350), 0x8000); 359488748Sambrisko 359588748Sambrisko return 0; 359688748Sambrisko} 359788748Sambrisko 359888748Sambrisko/* 359988748Sambrisko * After flashing restart the card. 360088748Sambrisko */ 360188748Sambrisko 360288748Sambriskostatic int 3603150446Simpflashrestart(struct ifnet *ifp) 360488748Sambrisko{ 360588748Sambrisko int status = 0; 360688748Sambrisko struct an_softc *sc = ifp->if_softc; 360788748Sambrisko 3608119163Sambrisko FLASH_DELAY(sc, 1024); /* Added 12/7/00 */ 360988748Sambrisko 361088748Sambrisko an_init(sc); 361188748Sambrisko 3612119163Sambrisko FLASH_DELAY(sc, 1024); /* Added 12/7/00 */ 361388748Sambrisko return status; 361488748Sambrisko} 361588748Sambrisko 361688748Sambrisko/* 361788748Sambrisko * Entry point for flash ioclt. 361888748Sambrisko */ 361988748Sambrisko 362088748Sambriskostatic int 3621150446Simpflashcard(struct ifnet *ifp, struct aironet_ioctl *l_ioctl) 362288748Sambrisko{ 362388749Sambrisko int z = 0, status; 362488748Sambrisko struct an_softc *sc; 362588748Sambrisko 362688748Sambrisko sc = ifp->if_softc; 3627108401Sambrisko if (sc->mpi350) { 3628108401Sambrisko printf("an%d: flashing not supported on MPI 350 yet\n", 3629108401Sambrisko sc->an_unit); 3630108401Sambrisko return(-1); 3631108401Sambrisko } 363288748Sambrisko status = l_ioctl->command; 363388748Sambrisko 363488748Sambrisko switch (l_ioctl->command) { 363588748Sambrisko case AIROFLSHRST: 363688748Sambrisko return cmdreset(ifp); 363788748Sambrisko break; 363888748Sambrisko case AIROFLSHSTFL: 3639108401Sambrisko if (sc->an_flash_buffer) { 3640108401Sambrisko free(sc->an_flash_buffer, M_DEVBUF); 3641108401Sambrisko sc->an_flash_buffer = NULL; 3642108401Sambrisko } 3643111119Simp sc->an_flash_buffer = malloc(FLASH_SIZE, M_DEVBUF, M_WAITOK); 3644108401Sambrisko if (sc->an_flash_buffer) 3645108401Sambrisko return setflashmode(ifp); 3646108401Sambrisko else 3647108401Sambrisko return ENOBUFS; 364888748Sambrisko break; 364988748Sambrisko case AIROFLSHGCHR: /* Get char from aux */ 3650171692Savatar AN_UNLOCK(sc); 3651144242Ssam status = copyin(l_ioctl->data, &sc->areq, l_ioctl->len); 3652171692Savatar AN_LOCK(sc); 3653144242Ssam if (status) 3654144242Ssam return status; 365588749Sambrisko z = *(int *)&sc->areq; 365688748Sambrisko if ((status = flashgchar(ifp, z, 8000)) == 1) 365788748Sambrisko return 0; 365888748Sambrisko else 365988748Sambrisko return -1; 366088748Sambrisko case AIROFLSHPCHR: /* Send char to card. */ 3661171692Savatar AN_UNLOCK(sc); 3662144242Ssam status = copyin(l_ioctl->data, &sc->areq, l_ioctl->len); 3663171692Savatar AN_LOCK(sc); 3664144242Ssam if (status) 3665144242Ssam return status; 366688749Sambrisko z = *(int *)&sc->areq; 366788748Sambrisko if ((status = flashpchar(ifp, z, 8000)) == -1) 366888748Sambrisko return -EIO; 366988748Sambrisko else 367088748Sambrisko return 0; 367188748Sambrisko break; 367288748Sambrisko case AIROFLPUTBUF: /* Send 32k to card */ 3673108401Sambrisko if (l_ioctl->len > FLASH_SIZE) { 3674108401Sambrisko printf("an%d: Buffer to big, %x %x\n", sc->an_unit, 3675108401Sambrisko l_ioctl->len, FLASH_SIZE); 367688748Sambrisko return -EINVAL; 367788748Sambrisko } 3678171692Savatar AN_UNLOCK(sc); 3679144242Ssam status = copyin(l_ioctl->data, sc->an_flash_buffer, l_ioctl->len); 3680171692Savatar AN_LOCK(sc); 3681144242Ssam if (status) 3682144242Ssam return status; 368388748Sambrisko 368488748Sambrisko if ((status = flashputbuf(ifp)) != 0) 368588748Sambrisko return -EIO; 368688748Sambrisko else 368788748Sambrisko return 0; 368888748Sambrisko break; 368988748Sambrisko case AIRORESTART: 369088748Sambrisko if ((status = flashrestart(ifp)) != 0) { 369188748Sambrisko printf("an%d: FLASHRESTART returned %d\n", 369288748Sambrisko sc->an_unit, status); 369388748Sambrisko return -EIO; 369488748Sambrisko } else 369588748Sambrisko return 0; 369688748Sambrisko 369788748Sambrisko break; 369888748Sambrisko default: 369988748Sambrisko return -EINVAL; 370088748Sambrisko } 370188748Sambrisko 370288748Sambrisko return -EINVAL; 370388748Sambrisko} 3704