if_an.c revision 78639
155992Swpaul/* 255992Swpaul * Copyright (c) 1997, 1998, 1999 355992Swpaul * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 455992Swpaul * 555992Swpaul * Redistribution and use in source and binary forms, with or without 655992Swpaul * modification, are permitted provided that the following conditions 755992Swpaul * are met: 855992Swpaul * 1. Redistributions of source code must retain the above copyright 955992Swpaul * notice, this list of conditions and the following disclaimer. 1055992Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1155992Swpaul * notice, this list of conditions and the following disclaimer in the 1255992Swpaul * documentation and/or other materials provided with the distribution. 1355992Swpaul * 3. All advertising materials mentioning features or use of this software 1455992Swpaul * must display the following acknowledgement: 1555992Swpaul * This product includes software developed by Bill Paul. 1655992Swpaul * 4. Neither the name of the author nor the names of any co-contributors 1755992Swpaul * may be used to endorse or promote products derived from this software 1855992Swpaul * without specific prior written permission. 1955992Swpaul * 2055992Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 2155992Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2255992Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2355992Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 2455992Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2555992Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2655992Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2755992Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2855992Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2955992Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3055992Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 3155992Swpaul * 3255992Swpaul * $FreeBSD: head/sys/dev/an/if_an.c 78639 2001-06-22 23:35:24Z brooks $ 3355992Swpaul */ 3455992Swpaul 3555992Swpaul/* 3655992Swpaul * Aironet 4500/4800 802.11 PCMCIA/ISA/PCI driver for FreeBSD. 3755992Swpaul * 3855992Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu> 3955992Swpaul * Electrical Engineering Department 4055992Swpaul * Columbia University, New York City 4155992Swpaul */ 4255992Swpaul 4355992Swpaul/* 4455992Swpaul * The Aironet 4500/4800 series cards some in PCMCIA, ISA and PCI form. 4555992Swpaul * This driver supports all three device types (PCI devices are supported 4655992Swpaul * through an extra PCI shim: /sys/pci/if_an_p.c). ISA devices can be 4755992Swpaul * supported either using hard-coded IO port/IRQ settings or via Plug 4855992Swpaul * and Play. The 4500 series devices support 1Mbps and 2Mbps data rates. 4955992Swpaul * The 4800 devices support 1, 2, 5.5 and 11Mbps rates. 5055992Swpaul * 5155992Swpaul * Like the WaveLAN/IEEE cards, the Aironet NICs are all essentially 5255992Swpaul * PCMCIA devices. The ISA and PCI cards are a combination of a PCMCIA 5355992Swpaul * device and a PCMCIA to ISA or PCMCIA to PCI adapter card. There are 5455992Swpaul * a couple of important differences though: 5555992Swpaul * 5655992Swpaul * - Lucent doesn't currently offer a PCI card, however Aironet does 5755992Swpaul * - Lucent ISA card looks to the host like a PCMCIA controller with 5855992Swpaul * a PCMCIA WaveLAN card inserted. This means that even desktop 5955992Swpaul * machines need to be configured with PCMCIA support in order to 6055992Swpaul * use WaveLAN/IEEE ISA cards. The Aironet cards on the other hand 6155992Swpaul * actually look like normal ISA and PCI devices to the host, so 6255992Swpaul * no PCMCIA controller support is needed 6355992Swpaul * 6455992Swpaul * The latter point results in a small gotcha. The Aironet PCMCIA 6555992Swpaul * cards can be configured for one of two operating modes depending 6655992Swpaul * on how the Vpp1 and Vpp2 programming voltages are set when the 6755992Swpaul * card is activated. In order to put the card in proper PCMCIA 6855992Swpaul * operation (where the CIS table is visible and the interface is 6955992Swpaul * programmed for PCMCIA operation), both Vpp1 and Vpp2 have to be 7055992Swpaul * set to 5 volts. FreeBSD by default doesn't set the Vpp voltages, 7155992Swpaul * which leaves the card in ISA/PCI mode, which prevents it from 7255992Swpaul * being activated as an PCMCIA device. Consequently, /sys/pccard/pccard.c 7355992Swpaul * has to be patched slightly in order to enable the Vpp voltages in 7455992Swpaul * order to make the Aironet PCMCIA cards work. 7555992Swpaul * 7655992Swpaul * Note that some PCMCIA controller software packages for Windows NT 7755992Swpaul * fail to set the voltages as well. 7855992Swpaul * 7955992Swpaul * The Aironet devices can operate in both station mode and access point 8055992Swpaul * mode. Typically, when programmed for station mode, the card can be set 8155992Swpaul * to automatically perform encapsulation/decapsulation of Ethernet II 8255992Swpaul * and 802.3 frames within 802.11 frames so that the host doesn't have 8355992Swpaul * to do it itself. This driver doesn't program the card that way: the 8455992Swpaul * driver handles all of the encapsulation/decapsulation itself. 8555992Swpaul */ 8655992Swpaul 8755992Swpaul#include "opt_inet.h" 8855992Swpaul 8955992Swpaul#ifdef INET 9055992Swpaul#define ANCACHE /* enable signal strength cache */ 9155992Swpaul#endif 9255992Swpaul 9355992Swpaul#include <sys/param.h> 9455992Swpaul#include <sys/systm.h> 9555992Swpaul#include <sys/sockio.h> 9655992Swpaul#include <sys/mbuf.h> 9755992Swpaul#include <sys/kernel.h> 9855992Swpaul#include <sys/socket.h> 9955992Swpaul#ifdef ANCACHE 10055992Swpaul#include <sys/syslog.h> 10155992Swpaul#include <sys/sysctl.h> 10255992Swpaul#endif 10355992Swpaul 10455992Swpaul#include <sys/module.h> 10555992Swpaul#include <sys/bus.h> 10655992Swpaul#include <machine/bus.h> 10755992Swpaul#include <sys/rman.h> 10867365Sjhb#include <sys/mutex.h> 10955992Swpaul#include <machine/resource.h> 11055992Swpaul 11155992Swpaul#include <net/if.h> 11255992Swpaul#include <net/if_arp.h> 11355992Swpaul#include <net/ethernet.h> 11455992Swpaul#include <net/if_dl.h> 11555992Swpaul#include <net/if_types.h> 11677217Sphk#include <net/if_ieee80211.h> 11777217Sphk#include <net/if_media.h> 11855992Swpaul 11955992Swpaul#ifdef INET 12055992Swpaul#include <netinet/in.h> 12155992Swpaul#include <netinet/in_systm.h> 12255992Swpaul#include <netinet/in_var.h> 12355992Swpaul#include <netinet/ip.h> 12455992Swpaul#endif 12555992Swpaul 12655992Swpaul#include <net/bpf.h> 12755992Swpaul 12855992Swpaul#include <machine/md_var.h> 12955992Swpaul 13055992Swpaul#include <dev/an/if_aironet_ieee.h> 13155992Swpaul#include <dev/an/if_anreg.h> 13255992Swpaul 13355992Swpaul#if !defined(lint) 13455992Swpaulstatic const char rcsid[] = 13555992Swpaul "$FreeBSD: head/sys/dev/an/if_an.c 78639 2001-06-22 23:35:24Z brooks $"; 13655992Swpaul#endif 13755992Swpaul 13855992Swpaul/* These are global because we need them in sys/pci/if_an_p.c. */ 13955992Swpaulstatic void an_reset __P((struct an_softc *)); 14055992Swpaulstatic int an_ioctl __P((struct ifnet *, u_long, caddr_t)); 14155992Swpaulstatic void an_init __P((void *)); 14255992Swpaulstatic int an_init_tx_ring __P((struct an_softc *)); 14355992Swpaulstatic void an_start __P((struct ifnet *)); 14455992Swpaulstatic void an_watchdog __P((struct ifnet *)); 14555992Swpaulstatic void an_rxeof __P((struct an_softc *)); 14655992Swpaulstatic void an_txeof __P((struct an_softc *, int)); 14755992Swpaul 14855992Swpaulstatic void an_promisc __P((struct an_softc *, int)); 14955992Swpaulstatic int an_cmd __P((struct an_softc *, int, int)); 15055992Swpaulstatic int an_read_record __P((struct an_softc *, struct an_ltv_gen *)); 15155992Swpaulstatic int an_write_record __P((struct an_softc *, struct an_ltv_gen *)); 15255992Swpaulstatic int an_read_data __P((struct an_softc *, int, 15355992Swpaul int, caddr_t, int)); 15455992Swpaulstatic int an_write_data __P((struct an_softc *, int, 15555992Swpaul int, caddr_t, int)); 15655992Swpaulstatic int an_seek __P((struct an_softc *, int, int, int)); 15755992Swpaulstatic int an_alloc_nicmem __P((struct an_softc *, int, int *)); 15855992Swpaulstatic void an_stats_update __P((void *)); 15955992Swpaulstatic void an_setdef __P((struct an_softc *, struct an_req *)); 16055992Swpaul#ifdef ANCACHE 16155992Swpaulstatic void an_cache_store __P((struct an_softc *, struct ether_header *, 16255992Swpaul struct mbuf *, unsigned short)); 16355992Swpaul#endif 16455992Swpaul 16578639Sbrooksstatic void an_dump_record __P((struct an_softc *,struct an_ltv_gen *, 16678639Sbrooks char *)); 16778639Sbrooks 16877217Sphkstatic int an_media_change __P((struct ifnet *)); 16977217Sphkstatic void an_media_status __P((struct ifnet *, struct ifmediareq *)); 17077217Sphk 17178639Sbrooksstatic int an_dump = 0; 17255992Swpaul/* 17355992Swpaul * We probe for an Aironet 4500/4800 card by attempting to 17455992Swpaul * read the default SSID list. On reset, the first entry in 17555992Swpaul * the SSID list will contain the name "tsunami." If we don't 17655992Swpaul * find this, then there's no card present. 17755992Swpaul */ 17855992Swpaulint an_probe(dev) 17955992Swpaul device_t dev; 18055992Swpaul{ 18155992Swpaul struct an_softc *sc = device_get_softc(dev); 18255992Swpaul struct an_ltv_ssidlist ssid; 18355992Swpaul int error; 18455992Swpaul 18555992Swpaul bzero((char *)&ssid, sizeof(ssid)); 18655992Swpaul 18755992Swpaul error = an_alloc_port(dev, 0, AN_IOSIZ); 18878639Sbrooks if (error != 0) 18955992Swpaul return (0); 19055992Swpaul 19155992Swpaul /* can't do autoprobing */ 19255992Swpaul if (rman_get_start(sc->port_res) == -1) 19355992Swpaul return(0); 19455992Swpaul 19555992Swpaul /* 19655992Swpaul * We need to fake up a softc structure long enough 19755992Swpaul * to be able to issue commands and call some of the 19855992Swpaul * other routines. 19955992Swpaul */ 20056094Swpaul sc->an_bhandle = rman_get_bushandle(sc->port_res); 20155992Swpaul sc->an_btag = rman_get_bustag(sc->port_res); 20255992Swpaul sc->an_unit = device_get_unit(dev); 20355992Swpaul 20455992Swpaul ssid.an_len = sizeof(ssid); 20555992Swpaul ssid.an_type = AN_RID_SSIDLIST; 20655992Swpaul 20755992Swpaul /* Make sure interrupts are disabled. */ 20855992Swpaul CSR_WRITE_2(sc, AN_INT_EN, 0); 20955992Swpaul CSR_WRITE_2(sc, AN_EVENT_ACK, 0xFFFF); 21055992Swpaul 21155992Swpaul an_reset(sc); 21255992Swpaul 21355992Swpaul if (an_cmd(sc, AN_CMD_READCFG, 0)) 21455992Swpaul return(0); 21555992Swpaul 21655992Swpaul if (an_read_record(sc, (struct an_ltv_gen *)&ssid)) 21755992Swpaul return(0); 21855992Swpaul 21968692Swpaul /* See if the ssid matches what we expect ... but doesn't have to */ 22055992Swpaul if (strcmp(ssid.an_ssid1, AN_DEF_SSID)) 22155992Swpaul return(0); 22255992Swpaul 22355992Swpaul return(AN_IOSIZ); 22455992Swpaul} 22555992Swpaul 22655992Swpaul/* 22755992Swpaul * Allocate a port resource with the given resource id. 22855992Swpaul */ 22955992Swpaulint 23055992Swpaulan_alloc_port(dev, rid, size) 23155992Swpaul device_t dev; 23255992Swpaul int rid; 23355992Swpaul int size; 23455992Swpaul{ 23555992Swpaul struct an_softc *sc = device_get_softc(dev); 23655992Swpaul struct resource *res; 23755992Swpaul 23855992Swpaul res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 23955992Swpaul 0ul, ~0ul, size, RF_ACTIVE); 24055992Swpaul if (res) { 24155992Swpaul sc->port_rid = rid; 24255992Swpaul sc->port_res = res; 24355992Swpaul return (0); 24455992Swpaul } else { 24555992Swpaul return (ENOENT); 24655992Swpaul } 24755992Swpaul} 24855992Swpaul 24955992Swpaul/* 25055992Swpaul * Allocate an irq resource with the given resource id. 25155992Swpaul */ 25255992Swpaulint 25355992Swpaulan_alloc_irq(dev, rid, flags) 25455992Swpaul device_t dev; 25555992Swpaul int rid; 25655992Swpaul int flags; 25755992Swpaul{ 25855992Swpaul struct an_softc *sc = device_get_softc(dev); 25955992Swpaul struct resource *res; 26055992Swpaul 26155992Swpaul res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 26255992Swpaul 0ul, ~0ul, 1, (RF_ACTIVE | flags)); 26355992Swpaul if (res) { 26455992Swpaul sc->irq_rid = rid; 26555992Swpaul sc->irq_res = res; 26655992Swpaul return (0); 26755992Swpaul } else { 26855992Swpaul return (ENOENT); 26955992Swpaul } 27055992Swpaul} 27155992Swpaul 27255992Swpaul/* 27355992Swpaul * Release all resources 27455992Swpaul */ 27555992Swpaulvoid 27655992Swpaulan_release_resources(dev) 27755992Swpaul device_t dev; 27855992Swpaul{ 27955992Swpaul struct an_softc *sc = device_get_softc(dev); 28055992Swpaul 28155992Swpaul if (sc->port_res) { 28255992Swpaul bus_release_resource(dev, SYS_RES_IOPORT, 28355992Swpaul sc->port_rid, sc->port_res); 28455992Swpaul sc->port_res = 0; 28555992Swpaul } 28655992Swpaul if (sc->irq_res) { 28755992Swpaul bus_release_resource(dev, SYS_RES_IRQ, 28855992Swpaul sc->irq_rid, sc->irq_res); 28955992Swpaul sc->irq_res = 0; 29055992Swpaul } 29155992Swpaul} 29255992Swpaul 29355992Swpaulint an_attach(sc, unit, flags) 29455992Swpaul struct an_softc *sc; 29555992Swpaul int unit; 29655992Swpaul int flags; 29755992Swpaul{ 29855992Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 29955992Swpaul 30071228Sbmilekic mtx_init(&sc->an_mtx, device_get_nameunit(sc->an_dev), MTX_DEF | 30171228Sbmilekic MTX_RECURSE); 30267094Swpaul AN_LOCK(sc); 30367094Swpaul 30455992Swpaul sc->an_gone = 0; 30555992Swpaul sc->an_associated = 0; 30655992Swpaul 30755992Swpaul /* Reset the NIC. */ 30855992Swpaul an_reset(sc); 30955992Swpaul 31055992Swpaul /* Load factory config */ 31155992Swpaul if (an_cmd(sc, AN_CMD_READCFG, 0)) { 31255992Swpaul printf("an%d: failed to load config data\n", sc->an_unit); 31367094Swpaul AN_UNLOCK(sc); 31467094Swpaul mtx_destroy(&sc->an_mtx); 31555992Swpaul return(EIO); 31655992Swpaul } 31755992Swpaul 31855992Swpaul /* Read the current configuration */ 31955992Swpaul sc->an_config.an_type = AN_RID_GENCONFIG; 32055992Swpaul sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 32155992Swpaul if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_config)) { 32255992Swpaul printf("an%d: read record failed\n", sc->an_unit); 32367094Swpaul AN_UNLOCK(sc); 32467094Swpaul mtx_destroy(&sc->an_mtx); 32555992Swpaul return(EIO); 32655992Swpaul } 32755992Swpaul 32855992Swpaul /* Read the card capabilities */ 32955992Swpaul sc->an_caps.an_type = AN_RID_CAPABILITIES; 33055992Swpaul sc->an_caps.an_len = sizeof(struct an_ltv_caps); 33155992Swpaul if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_caps)) { 33255992Swpaul printf("an%d: read record failed\n", sc->an_unit); 33367094Swpaul AN_UNLOCK(sc); 33467094Swpaul mtx_destroy(&sc->an_mtx); 33555992Swpaul return(EIO); 33655992Swpaul } 33755992Swpaul 33855992Swpaul /* Read ssid list */ 33955992Swpaul sc->an_ssidlist.an_type = AN_RID_SSIDLIST; 34055992Swpaul sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist); 34155992Swpaul if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) { 34255992Swpaul printf("an%d: read record failed\n", sc->an_unit); 34367094Swpaul AN_UNLOCK(sc); 34467094Swpaul mtx_destroy(&sc->an_mtx); 34555992Swpaul return(EIO); 34655992Swpaul } 34755992Swpaul 34855992Swpaul /* Read AP list */ 34955992Swpaul sc->an_aplist.an_type = AN_RID_APLIST; 35055992Swpaul sc->an_aplist.an_len = sizeof(struct an_ltv_aplist); 35155992Swpaul if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) { 35255992Swpaul printf("an%d: read record failed\n", sc->an_unit); 35367094Swpaul AN_UNLOCK(sc); 35467094Swpaul mtx_destroy(&sc->an_mtx); 35555992Swpaul return(EIO); 35655992Swpaul } 35755992Swpaul 35855992Swpaul bcopy((char *)&sc->an_caps.an_oemaddr, 35955992Swpaul (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 36055992Swpaul 36155992Swpaul printf("an%d: Ethernet address: %6D\n", sc->an_unit, 36255992Swpaul sc->arpcom.ac_enaddr, ":"); 36355992Swpaul 36455992Swpaul ifp->if_softc = sc; 36555992Swpaul ifp->if_unit = sc->an_unit = unit; 36655992Swpaul ifp->if_name = "an"; 36755992Swpaul ifp->if_mtu = ETHERMTU; 36855992Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 36955992Swpaul ifp->if_ioctl = an_ioctl; 37055992Swpaul ifp->if_output = ether_output; 37155992Swpaul ifp->if_start = an_start; 37255992Swpaul ifp->if_watchdog = an_watchdog; 37355992Swpaul ifp->if_init = an_init; 37455992Swpaul ifp->if_baudrate = 10000000; 37555992Swpaul ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 37655992Swpaul 37755992Swpaul bzero(sc->an_config.an_nodename, sizeof(sc->an_config.an_nodename)); 37855992Swpaul bcopy(AN_DEFAULT_NODENAME, sc->an_config.an_nodename, 37955992Swpaul sizeof(AN_DEFAULT_NODENAME) - 1); 38055992Swpaul 38155992Swpaul bzero(sc->an_ssidlist.an_ssid1, sizeof(sc->an_ssidlist.an_ssid1)); 38255992Swpaul bcopy(AN_DEFAULT_NETNAME, sc->an_ssidlist.an_ssid1, 38355992Swpaul sizeof(AN_DEFAULT_NETNAME) - 1); 38455992Swpaul sc->an_ssidlist.an_ssid1_len = strlen(AN_DEFAULT_NETNAME); 38555992Swpaul 38655992Swpaul sc->an_config.an_opmode = 38774144Sassar AN_OPMODE_INFRASTRUCTURE_STATION; 38855992Swpaul 38955992Swpaul sc->an_tx_rate = 0; 39055992Swpaul bzero((char *)&sc->an_stats, sizeof(sc->an_stats)); 39155992Swpaul 39277217Sphk ifmedia_init(&sc->an_ifmedia, 0, an_media_change, an_media_status); 39377217Sphk#define ADD(m, c) ifmedia_add(&sc->an_ifmedia, (m), (c), NULL) 39477217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 39577217Sphk IFM_IEEE80211_ADHOC, 0), 0); 39677217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 0, 0), 0); 39777217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 39877217Sphk IFM_IEEE80211_ADHOC, 0), 0); 39977217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 0, 0), 0); 40078639Sbrooks if (sc->an_caps.an_rates[2] == AN_RATE_5_5MBPS) { 40177217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 40277217Sphk IFM_IEEE80211_ADHOC, 0), 0); 40377217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 0, 0), 0); 40477217Sphk } 40578639Sbrooks if (sc->an_caps.an_rates[3] == AN_RATE_11MBPS) { 40677217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 40777217Sphk IFM_IEEE80211_ADHOC, 0), 0); 40877217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 0, 0), 0); 40977217Sphk } 41077217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 41177217Sphk IFM_IEEE80211_ADHOC, 0), 0); 41277217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0), 0); 41377217Sphk#undef ADD 41477217Sphk ifmedia_set(&sc->an_ifmedia, IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 41577217Sphk 0, 0)); 41677217Sphk 41755992Swpaul /* 41863090Sarchie * Call MI attach routine. 41955992Swpaul */ 42063090Sarchie ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 42155992Swpaul callout_handle_init(&sc->an_stat_ch); 42267094Swpaul AN_UNLOCK(sc); 42355992Swpaul 42455992Swpaul return(0); 42555992Swpaul} 42655992Swpaul 42755992Swpaulstatic void an_rxeof(sc) 42855992Swpaul struct an_softc *sc; 42955992Swpaul{ 43055992Swpaul struct ifnet *ifp; 43155992Swpaul struct ether_header *eh; 43255992Swpaul#ifdef ANCACHE 43355992Swpaul struct an_rxframe rx_frame; 43455992Swpaul#endif 43555992Swpaul struct an_rxframe_802_3 rx_frame_802_3; 43655992Swpaul struct mbuf *m; 43755992Swpaul int id, error = 0; 43855992Swpaul 43955992Swpaul ifp = &sc->arpcom.ac_if; 44055992Swpaul 44155992Swpaul id = CSR_READ_2(sc, AN_RX_FID); 44255992Swpaul 44355992Swpaul MGETHDR(m, M_DONTWAIT, MT_DATA); 44455992Swpaul if (m == NULL) { 44555992Swpaul ifp->if_ierrors++; 44655992Swpaul return; 44755992Swpaul } 44855992Swpaul MCLGET(m, M_DONTWAIT); 44955992Swpaul if (!(m->m_flags & M_EXT)) { 45055992Swpaul m_freem(m); 45155992Swpaul ifp->if_ierrors++; 45255992Swpaul return; 45355992Swpaul } 45455992Swpaul 45555992Swpaul m->m_pkthdr.rcvif = ifp; 45655992Swpaul 45755992Swpaul eh = mtod(m, struct ether_header *); 45855992Swpaul 45955992Swpaul#ifdef ANCACHE 46055992Swpaul /* Read NIC frame header */ 46155992Swpaul if (an_read_data(sc, id, 0, (caddr_t)&rx_frame, sizeof(rx_frame))) { 46255992Swpaul ifp->if_ierrors++; 46355992Swpaul return; 46455992Swpaul } 46555992Swpaul#endif 46655992Swpaul /* Read in the 802_3 frame header */ 46755992Swpaul if (an_read_data(sc, id, 0x34, (caddr_t)&rx_frame_802_3, 46855992Swpaul sizeof(rx_frame_802_3))) { 46955992Swpaul ifp->if_ierrors++; 47055992Swpaul return; 47155992Swpaul } 47255992Swpaul 47355992Swpaul if (rx_frame_802_3.an_rx_802_3_status != 0) { 47455992Swpaul ifp->if_ierrors++; 47555992Swpaul return; 47655992Swpaul } 47755992Swpaul 47855992Swpaul /* Check for insane frame length */ 47955992Swpaul if (rx_frame_802_3.an_rx_802_3_payload_len > MCLBYTES) { 48055992Swpaul ifp->if_ierrors++; 48155992Swpaul return; 48255992Swpaul } 48355992Swpaul 48455992Swpaul m->m_pkthdr.len = m->m_len = 48555992Swpaul rx_frame_802_3.an_rx_802_3_payload_len + 12; 48655992Swpaul 48755992Swpaul 48855992Swpaul bcopy((char *)&rx_frame_802_3.an_rx_dst_addr, 48955992Swpaul (char *)&eh->ether_dhost, ETHER_ADDR_LEN); 49055992Swpaul bcopy((char *)&rx_frame_802_3.an_rx_src_addr, 49155992Swpaul (char *)&eh->ether_shost, ETHER_ADDR_LEN); 49255992Swpaul 49355992Swpaul /* in mbuf header type is just before payload */ 49455992Swpaul error = an_read_data(sc, id, 0x44, (caddr_t)&(eh->ether_type), 49555992Swpaul rx_frame_802_3.an_rx_802_3_payload_len); 49655992Swpaul 49778639Sbrooks if (error != 0) { 49855992Swpaul m_freem(m); 49955992Swpaul ifp->if_ierrors++; 50055992Swpaul return; 50155992Swpaul } 50255992Swpaul 50355992Swpaul ifp->if_ipackets++; 50455992Swpaul 50555992Swpaul /* Receive packet. */ 50655992Swpaul m_adj(m, sizeof(struct ether_header)); 50755992Swpaul#ifdef ANCACHE 50855992Swpaul an_cache_store(sc, eh, m, rx_frame.an_rx_signal_strength); 50955992Swpaul#endif 51055992Swpaul ether_input(ifp, eh, m); 51155992Swpaul} 51255992Swpaul 51355992Swpaulstatic void an_txeof(sc, status) 51455992Swpaul struct an_softc *sc; 51555992Swpaul int status; 51655992Swpaul{ 51755992Swpaul struct ifnet *ifp; 51878639Sbrooks int id, i; 51955992Swpaul 52068692Swpaul /* TX DONE enable lan monitor DJA 52168692Swpaul an_enable_sniff(); 52268692Swpaul */ 52368692Swpaul 52455992Swpaul ifp = &sc->arpcom.ac_if; 52555992Swpaul 52655992Swpaul ifp->if_timer = 0; 52755992Swpaul ifp->if_flags &= ~IFF_OACTIVE; 52855992Swpaul 52955992Swpaul id = CSR_READ_2(sc, AN_TX_CMP_FID); 53055992Swpaul 53155992Swpaul if (status & AN_EV_TX_EXC) { 53255992Swpaul ifp->if_oerrors++; 53355992Swpaul } else 53455992Swpaul ifp->if_opackets++; 53555992Swpaul 53678639Sbrooks for (i = 0; i < AN_TX_RING_CNT; i++) { 53778639Sbrooks if (id == sc->an_rdata.an_tx_ring[i]) { 53878639Sbrooks sc->an_rdata.an_tx_ring[i] = 0; 53978639Sbrooks break; 54078639Sbrooks } 54178639Sbrooks } 54255992Swpaul 54355992Swpaul AN_INC(sc->an_rdata.an_tx_cons, AN_TX_RING_CNT); 54455992Swpaul 54555992Swpaul return; 54655992Swpaul} 54755992Swpaul 54855992Swpaul/* 54955992Swpaul * We abuse the stats updater to check the current NIC status. This 55055992Swpaul * is important because we don't want to allow transmissions until 55155992Swpaul * the NIC has synchronized to the current cell (either as the master 55255992Swpaul * in an ad-hoc group, or as a station connected to an access point). 55355992Swpaul */ 55455992Swpaulvoid an_stats_update(xsc) 55555992Swpaul void *xsc; 55655992Swpaul{ 55755992Swpaul struct an_softc *sc; 55855992Swpaul struct ifnet *ifp; 55955992Swpaul 56055992Swpaul sc = xsc; 56167094Swpaul AN_LOCK(sc); 56255992Swpaul ifp = &sc->arpcom.ac_if; 56355992Swpaul 56455992Swpaul sc->an_status.an_type = AN_RID_STATUS; 56555992Swpaul sc->an_status.an_len = sizeof(struct an_ltv_status); 56655992Swpaul an_read_record(sc, (struct an_ltv_gen *)&sc->an_status); 56755992Swpaul 56855992Swpaul if (sc->an_status.an_opmode & AN_STATUS_OPMODE_IN_SYNC) 56955992Swpaul sc->an_associated = 1; 57055992Swpaul else 57155992Swpaul sc->an_associated = 0; 57255992Swpaul 57355992Swpaul /* Don't do this while we're transmitting */ 57455992Swpaul if (ifp->if_flags & IFF_OACTIVE) { 57555992Swpaul sc->an_stat_ch = timeout(an_stats_update, sc, hz); 57667094Swpaul AN_UNLOCK(sc); 57755992Swpaul return; 57855992Swpaul } 57955992Swpaul 58055992Swpaul sc->an_stats.an_len = sizeof(struct an_ltv_stats); 58155992Swpaul sc->an_stats.an_type = AN_RID_32BITS_CUM; 58255992Swpaul an_read_record(sc, (struct an_ltv_gen *)&sc->an_stats.an_len); 58355992Swpaul 58455992Swpaul sc->an_stat_ch = timeout(an_stats_update, sc, hz); 58567094Swpaul AN_UNLOCK(sc); 58655992Swpaul 58755992Swpaul return; 58855992Swpaul} 58955992Swpaul 59055992Swpaulvoid an_intr(xsc) 59155992Swpaul void *xsc; 59255992Swpaul{ 59355992Swpaul struct an_softc *sc; 59455992Swpaul struct ifnet *ifp; 59555992Swpaul u_int16_t status; 59655992Swpaul 59755992Swpaul sc = (struct an_softc*)xsc; 59855992Swpaul 59967094Swpaul AN_LOCK(sc); 60067094Swpaul 60167094Swpaul if (sc->an_gone) { 60267094Swpaul AN_UNLOCK(sc); 60355992Swpaul return; 60467094Swpaul } 60555992Swpaul 60655992Swpaul ifp = &sc->arpcom.ac_if; 60755992Swpaul 60855992Swpaul /* Disable interrupts. */ 60955992Swpaul CSR_WRITE_2(sc, AN_INT_EN, 0); 61055992Swpaul 61155992Swpaul status = CSR_READ_2(sc, AN_EVENT_STAT); 61255992Swpaul CSR_WRITE_2(sc, AN_EVENT_ACK, ~AN_INTRS); 61355992Swpaul 61455992Swpaul if (status & AN_EV_AWAKE) { 61555992Swpaul CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_AWAKE); 61655992Swpaul } 61755992Swpaul 61855992Swpaul if (status & AN_EV_LINKSTAT) { 61955992Swpaul if (CSR_READ_2(sc, AN_LINKSTAT) == AN_LINKSTAT_ASSOCIATED) 62055992Swpaul sc->an_associated = 1; 62155992Swpaul else 62255992Swpaul sc->an_associated = 0; 62355992Swpaul CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_LINKSTAT); 62455992Swpaul } 62555992Swpaul 62655992Swpaul if (status & AN_EV_RX) { 62755992Swpaul an_rxeof(sc); 62855992Swpaul CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX); 62955992Swpaul } 63055992Swpaul 63155992Swpaul if (status & AN_EV_TX) { 63255992Swpaul an_txeof(sc, status); 63355992Swpaul CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_TX); 63455992Swpaul } 63555992Swpaul 63655992Swpaul if (status & AN_EV_TX_EXC) { 63755992Swpaul an_txeof(sc, status); 63855992Swpaul CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_TX_EXC); 63955992Swpaul } 64055992Swpaul 64155992Swpaul if (status & AN_EV_ALLOC) 64255992Swpaul CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_ALLOC); 64355992Swpaul 64455992Swpaul /* Re-enable interrupts. */ 64555992Swpaul CSR_WRITE_2(sc, AN_INT_EN, AN_INTRS); 64655992Swpaul 64774698Sarchie if ((ifp->if_flags & IFF_UP) && (ifp->if_snd.ifq_head != NULL)) 64855992Swpaul an_start(ifp); 64955992Swpaul 65067094Swpaul AN_UNLOCK(sc); 65167094Swpaul 65255992Swpaul return; 65355992Swpaul} 65455992Swpaul 65555992Swpaulstatic int an_cmd(sc, cmd, val) 65655992Swpaul struct an_softc *sc; 65755992Swpaul int cmd; 65855992Swpaul int val; 65955992Swpaul{ 66055992Swpaul int i, s = 0; 66155992Swpaul 66255992Swpaul CSR_WRITE_2(sc, AN_PARAM0, val); 66355992Swpaul CSR_WRITE_2(sc, AN_PARAM1, 0); 66455992Swpaul CSR_WRITE_2(sc, AN_PARAM2, 0); 66555992Swpaul CSR_WRITE_2(sc, AN_COMMAND, cmd); 66655992Swpaul 66755992Swpaul for (i = 0; i < AN_TIMEOUT; i++) { 66855992Swpaul if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_CMD) 66955992Swpaul break; 67055992Swpaul else { 67155992Swpaul if (CSR_READ_2(sc, AN_COMMAND) == cmd) 67255992Swpaul CSR_WRITE_2(sc, AN_COMMAND, cmd); 67355992Swpaul } 67455992Swpaul } 67555992Swpaul 67655992Swpaul for (i = 0; i < AN_TIMEOUT; i++) { 67755992Swpaul CSR_READ_2(sc, AN_RESP0); 67855992Swpaul CSR_READ_2(sc, AN_RESP1); 67955992Swpaul CSR_READ_2(sc, AN_RESP2); 68055992Swpaul s = CSR_READ_2(sc, AN_STATUS); 68155992Swpaul if ((s & AN_STAT_CMD_CODE) == (cmd & AN_STAT_CMD_CODE)) 68255992Swpaul break; 68355992Swpaul } 68455992Swpaul 68555992Swpaul /* Ack the command */ 68655992Swpaul CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD); 68755992Swpaul 68855992Swpaul if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY) 68955992Swpaul CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY); 69055992Swpaul 69155992Swpaul if (i == AN_TIMEOUT) 69255992Swpaul return(ETIMEDOUT); 69355992Swpaul 69455992Swpaul return(0); 69555992Swpaul} 69655992Swpaul 69755992Swpaul/* 69855992Swpaul * This reset sequence may look a little strange, but this is the 69955992Swpaul * most reliable method I've found to really kick the NIC in the 70055992Swpaul * head and force it to reboot correctly. 70155992Swpaul */ 70255992Swpaulstatic void an_reset(sc) 70355992Swpaul struct an_softc *sc; 70455992Swpaul{ 70555992Swpaul if (sc->an_gone) 70655992Swpaul return; 70755992Swpaul 70855992Swpaul an_cmd(sc, AN_CMD_ENABLE, 0); 70955992Swpaul an_cmd(sc, AN_CMD_FW_RESTART, 0); 71055992Swpaul an_cmd(sc, AN_CMD_NOOP2, 0); 71155992Swpaul 71255992Swpaul if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0) == ETIMEDOUT) 71355992Swpaul printf("an%d: reset failed\n", sc->an_unit); 71455992Swpaul 71555992Swpaul an_cmd(sc, AN_CMD_DISABLE, 0); 71655992Swpaul 71755992Swpaul return; 71855992Swpaul} 71955992Swpaul 72055992Swpaul/* 72155992Swpaul * Read an LTV record from the NIC. 72255992Swpaul */ 72355992Swpaulstatic int an_read_record(sc, ltv) 72455992Swpaul struct an_softc *sc; 72555992Swpaul struct an_ltv_gen *ltv; 72655992Swpaul{ 72755992Swpaul u_int16_t *ptr; 72878639Sbrooks u_int8_t *ptr2; 72955992Swpaul int i, len; 73055992Swpaul 73178639Sbrooks if (ltv->an_len < 4 || ltv->an_type == 0) 73255992Swpaul return(EINVAL); 73355992Swpaul 73455992Swpaul /* Tell the NIC to enter record read mode. */ 73555992Swpaul if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) { 73655992Swpaul printf("an%d: RID access failed\n", sc->an_unit); 73755992Swpaul return(EIO); 73855992Swpaul } 73955992Swpaul 74055992Swpaul /* Seek to the record. */ 74155992Swpaul if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) { 74255992Swpaul printf("an%d: seek to record failed\n", sc->an_unit); 74355992Swpaul return(EIO); 74455992Swpaul } 74555992Swpaul 74655992Swpaul /* 74755992Swpaul * Read the length and record type and make sure they 74855992Swpaul * match what we expect (this verifies that we have enough 74955992Swpaul * room to hold all of the returned data). 75078639Sbrooks * Length includes type but not length. 75155992Swpaul */ 75255992Swpaul len = CSR_READ_2(sc, AN_DATA1); 75377217Sphk if (len > (ltv->an_len - 2)) { 75455992Swpaul printf("an%d: record length mismatch -- expected %d, " 75578639Sbrooks "got %d for Rid %x\n", sc->an_unit, 75678639Sbrooks ltv->an_len - 2, len, ltv->an_type); 75778639Sbrooks len = ltv->an_len - 2; 75878639Sbrooks } else { 75978639Sbrooks ltv->an_len = len + 2; 76055992Swpaul } 76155992Swpaul 76255992Swpaul /* Now read the data. */ 76378639Sbrooks len -= 2; /* skip the type */ 76455992Swpaul ptr = <v->an_val; 76578639Sbrooks for (i = len; i > 1; i -= 2) 76678639Sbrooks *ptr++ = CSR_READ_2(sc, AN_DATA1); 76778639Sbrooks if (i) { 76878639Sbrooks ptr2 = (u_int8_t *)ptr; 76978639Sbrooks *ptr2 = CSR_READ_1(sc, AN_DATA1); 77078639Sbrooks } 77178639Sbrooks if (an_dump) 77278639Sbrooks an_dump_record(sc, ltv, "Read"); 77355992Swpaul 77455992Swpaul return(0); 77555992Swpaul} 77655992Swpaul 77755992Swpaul/* 77855992Swpaul * Same as read, except we inject data instead of reading it. 77955992Swpaul */ 78055992Swpaulstatic int an_write_record(sc, ltv) 78155992Swpaul struct an_softc *sc; 78255992Swpaul struct an_ltv_gen *ltv; 78355992Swpaul{ 78455992Swpaul u_int16_t *ptr; 78578639Sbrooks u_int8_t *ptr2; 78678639Sbrooks int i, len; 78755992Swpaul 78878639Sbrooks if (an_dump) 78978639Sbrooks an_dump_record(sc, ltv, "Write"); 79078639Sbrooks 79155992Swpaul if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) 79255992Swpaul return(EIO); 79378639Sbrooks 79455992Swpaul if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) 79555992Swpaul return(EIO); 79655992Swpaul 79778639Sbrooks /* 79878639Sbrooks * Length includes type but not length. 79978639Sbrooks */ 80078639Sbrooks len = ltv->an_len - 2; 80178639Sbrooks CSR_WRITE_2(sc, AN_DATA1, len); 80268692Swpaul 80378639Sbrooks len -= 2; /* skip the type */ 80455992Swpaul ptr = <v->an_val; 80578639Sbrooks for (i = len; i > 1; i -= 2) 80678639Sbrooks CSR_WRITE_2(sc, AN_DATA1, *ptr++); 80778639Sbrooks if (i) { 80878639Sbrooks ptr2 = (u_int8_t *)ptr; 80978639Sbrooks CSR_WRITE_1(sc, AN_DATA0, *ptr2); 81078639Sbrooks } 81155992Swpaul 81255992Swpaul if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_WRITE, ltv->an_type)) 81355992Swpaul return(EIO); 81455992Swpaul 81555992Swpaul return(0); 81655992Swpaul} 81755992Swpaul 81878639Sbrooksstatic void an_dump_record(sc, ltv, string) 81978639Sbrooks struct an_softc *sc; 82078639Sbrooks struct an_ltv_gen *ltv; 82178639Sbrooks char *string; 82278639Sbrooks{ 82378639Sbrooks u_int8_t *ptr2; 82478639Sbrooks int len; 82578639Sbrooks int i; 82678639Sbrooks int count = 0; 82778639Sbrooks char buf[17], temp; 82878639Sbrooks 82978639Sbrooks len = ltv->an_len - 4; 83078639Sbrooks printf("an%d: RID %4x, Length %4d, Mode %s\n", 83178639Sbrooks sc->an_unit, ltv->an_type, ltv->an_len - 4, string); 83278639Sbrooks 83378639Sbrooks if (an_dump == 1 || (an_dump == ltv->an_type)) { 83478639Sbrooks printf("an%d:\t", sc->an_unit); 83578639Sbrooks bzero(buf,sizeof(buf)); 83678639Sbrooks 83778639Sbrooks ptr2 = (u_int8_t *)<v->an_val; 83878639Sbrooks for (i = len; i > 0; i--) { 83978639Sbrooks printf("%02x ", *ptr2); 84078639Sbrooks 84178639Sbrooks temp = *ptr2++; 84278639Sbrooks if (temp >= ' ' && temp <= '~') 84378639Sbrooks buf[count] = temp; 84478639Sbrooks else if (temp >= 'A' && temp <= 'Z') 84578639Sbrooks buf[count] = temp; 84678639Sbrooks else 84778639Sbrooks buf[count] = '.'; 84878639Sbrooks if (++count == 16) { 84978639Sbrooks count = 0; 85078639Sbrooks printf("%s\n",buf); 85178639Sbrooks printf("an%d:\t", sc->an_unit); 85278639Sbrooks bzero(buf,sizeof(buf)); 85378639Sbrooks } 85478639Sbrooks } 85578639Sbrooks for (; count != 16; count++) { 85678639Sbrooks printf(" "); 85778639Sbrooks } 85878639Sbrooks printf(" %s\n",buf); 85978639Sbrooks } 86078639Sbrooks} 86178639Sbrooks 86255992Swpaulstatic int an_seek(sc, id, off, chan) 86355992Swpaul struct an_softc *sc; 86455992Swpaul int id, off, chan; 86555992Swpaul{ 86655992Swpaul int i; 86755992Swpaul int selreg, offreg; 86855992Swpaul 86955992Swpaul switch (chan) { 87055992Swpaul case AN_BAP0: 87155992Swpaul selreg = AN_SEL0; 87255992Swpaul offreg = AN_OFF0; 87355992Swpaul break; 87455992Swpaul case AN_BAP1: 87555992Swpaul selreg = AN_SEL1; 87655992Swpaul offreg = AN_OFF1; 87755992Swpaul break; 87855992Swpaul default: 87955992Swpaul printf("an%d: invalid data path: %x\n", sc->an_unit, chan); 88055992Swpaul return(EIO); 88155992Swpaul } 88255992Swpaul 88355992Swpaul CSR_WRITE_2(sc, selreg, id); 88455992Swpaul CSR_WRITE_2(sc, offreg, off); 88555992Swpaul 88655992Swpaul for (i = 0; i < AN_TIMEOUT; i++) { 88755992Swpaul if (!(CSR_READ_2(sc, offreg) & (AN_OFF_BUSY|AN_OFF_ERR))) 88855992Swpaul break; 88955992Swpaul } 89055992Swpaul 89155992Swpaul if (i == AN_TIMEOUT) 89255992Swpaul return(ETIMEDOUT); 89355992Swpaul 89455992Swpaul return(0); 89555992Swpaul} 89655992Swpaul 89755992Swpaulstatic int an_read_data(sc, id, off, buf, len) 89855992Swpaul struct an_softc *sc; 89955992Swpaul int id, off; 90055992Swpaul caddr_t buf; 90155992Swpaul int len; 90255992Swpaul{ 90355992Swpaul int i; 90455992Swpaul u_int16_t *ptr; 90555992Swpaul u_int8_t *ptr2; 90655992Swpaul 90755992Swpaul if (off != -1) { 90855992Swpaul if (an_seek(sc, id, off, AN_BAP1)) 90955992Swpaul return(EIO); 91055992Swpaul } 91155992Swpaul 91255992Swpaul ptr = (u_int16_t *)buf; 91378639Sbrooks for (i = len; i > 1; i -= 2) 91478639Sbrooks *ptr++ = CSR_READ_2(sc, AN_DATA1); 91578639Sbrooks if (i) { 91678639Sbrooks ptr2 = (u_int8_t *)ptr; 91778639Sbrooks *ptr2 = CSR_READ_1(sc, AN_DATA1); 91855992Swpaul } 91955992Swpaul 92055992Swpaul return(0); 92155992Swpaul} 92255992Swpaul 92355992Swpaulstatic int an_write_data(sc, id, off, buf, len) 92455992Swpaul struct an_softc *sc; 92555992Swpaul int id, off; 92655992Swpaul caddr_t buf; 92755992Swpaul int len; 92855992Swpaul{ 92955992Swpaul int i; 93055992Swpaul u_int16_t *ptr; 93155992Swpaul u_int8_t *ptr2; 93255992Swpaul 93355992Swpaul if (off != -1) { 93455992Swpaul if (an_seek(sc, id, off, AN_BAP0)) 93555992Swpaul return(EIO); 93655992Swpaul } 93755992Swpaul 93855992Swpaul ptr = (u_int16_t *)buf; 93978639Sbrooks for (i = len; i > 1; i -= 2) 94078639Sbrooks CSR_WRITE_2(sc, AN_DATA0, *ptr++); 94178639Sbrooks if (i) { 94278639Sbrooks ptr2 = (u_int8_t *)ptr; 94378639Sbrooks CSR_WRITE_1(sc, AN_DATA0, *ptr2); 94455992Swpaul } 94555992Swpaul 94655992Swpaul return(0); 94755992Swpaul} 94855992Swpaul 94955992Swpaul/* 95055992Swpaul * Allocate a region of memory inside the NIC and zero 95155992Swpaul * it out. 95255992Swpaul */ 95355992Swpaulstatic int an_alloc_nicmem(sc, len, id) 95455992Swpaul struct an_softc *sc; 95555992Swpaul int len; 95655992Swpaul int *id; 95755992Swpaul{ 95855992Swpaul int i; 95955992Swpaul 96055992Swpaul if (an_cmd(sc, AN_CMD_ALLOC_MEM, len)) { 96155992Swpaul printf("an%d: failed to allocate %d bytes on NIC\n", 96255992Swpaul sc->an_unit, len); 96355992Swpaul return(ENOMEM); 96455992Swpaul } 96555992Swpaul 96655992Swpaul for (i = 0; i < AN_TIMEOUT; i++) { 96755992Swpaul if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_ALLOC) 96855992Swpaul break; 96955992Swpaul } 97055992Swpaul 97155992Swpaul if (i == AN_TIMEOUT) 97255992Swpaul return(ETIMEDOUT); 97355992Swpaul 97455992Swpaul CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_ALLOC); 97555992Swpaul *id = CSR_READ_2(sc, AN_ALLOC_FID); 97655992Swpaul 97755992Swpaul if (an_seek(sc, *id, 0, AN_BAP0)) 97855992Swpaul return(EIO); 97955992Swpaul 98055992Swpaul for (i = 0; i < len / 2; i++) 98155992Swpaul CSR_WRITE_2(sc, AN_DATA0, 0); 98255992Swpaul 98355992Swpaul return(0); 98455992Swpaul} 98555992Swpaul 98655992Swpaulstatic void an_setdef(sc, areq) 98755992Swpaul struct an_softc *sc; 98855992Swpaul struct an_req *areq; 98955992Swpaul{ 99055992Swpaul struct sockaddr_dl *sdl; 99155992Swpaul struct ifaddr *ifa; 99255992Swpaul struct ifnet *ifp; 99355992Swpaul struct an_ltv_genconfig *cfg; 99455992Swpaul struct an_ltv_ssidlist *ssid; 99555992Swpaul struct an_ltv_aplist *ap; 99655992Swpaul struct an_ltv_gen *sp; 99755992Swpaul 99855992Swpaul ifp = &sc->arpcom.ac_if; 99955992Swpaul 100055992Swpaul switch (areq->an_type) { 100155992Swpaul case AN_RID_GENCONFIG: 100255992Swpaul cfg = (struct an_ltv_genconfig *)areq; 100355992Swpaul 100455992Swpaul ifa = ifnet_addrs[ifp->if_index - 1]; 100555992Swpaul sdl = (struct sockaddr_dl *)ifa->ifa_addr; 100655992Swpaul bcopy((char *)&cfg->an_macaddr, (char *)&sc->arpcom.ac_enaddr, 100755992Swpaul ETHER_ADDR_LEN); 100855992Swpaul bcopy((char *)&cfg->an_macaddr, LLADDR(sdl), ETHER_ADDR_LEN); 100955992Swpaul 101055992Swpaul bcopy((char *)cfg, (char *)&sc->an_config, 101155992Swpaul sizeof(struct an_ltv_genconfig)); 101255992Swpaul break; 101355992Swpaul case AN_RID_SSIDLIST: 101455992Swpaul ssid = (struct an_ltv_ssidlist *)areq; 101555992Swpaul bcopy((char *)ssid, (char *)&sc->an_ssidlist, 101655992Swpaul sizeof(struct an_ltv_ssidlist)); 101755992Swpaul break; 101855992Swpaul case AN_RID_APLIST: 101955992Swpaul ap = (struct an_ltv_aplist *)areq; 102055992Swpaul bcopy((char *)ap, (char *)&sc->an_aplist, 102155992Swpaul sizeof(struct an_ltv_aplist)); 102255992Swpaul break; 102355992Swpaul case AN_RID_TX_SPEED: 102455992Swpaul sp = (struct an_ltv_gen *)areq; 102555992Swpaul sc->an_tx_rate = sp->an_val; 102655992Swpaul break; 102768692Swpaul case AN_RID_WEP_TEMP: 102868692Swpaul /* Disable the MAC. */ 102968692Swpaul an_cmd(sc, AN_CMD_DISABLE, 0); 103068692Swpaul 103168692Swpaul /* Just write the Key, we don't want to save it */ 103268692Swpaul an_write_record(sc, (struct an_ltv_gen *)areq); 103368692Swpaul 103468692Swpaul /* Turn the MAC back on. */ 103568692Swpaul an_cmd(sc, AN_CMD_ENABLE, 0); 103668692Swpaul 103768692Swpaul break; 103868692Swpaul case AN_RID_WEP_PERM: 103968692Swpaul 104068692Swpaul /* Disable the MAC. */ 104168692Swpaul an_cmd(sc, AN_CMD_DISABLE, 0); 104268692Swpaul 104368692Swpaul /* Just write the Key, the card will save it in this mode */ 104468692Swpaul an_write_record(sc, (struct an_ltv_gen *)areq); 104568692Swpaul 104668692Swpaul /* Turn the MAC back on. */ 104768692Swpaul an_cmd(sc, AN_CMD_ENABLE, 0); 104868692Swpaul 104968692Swpaul break; 105055992Swpaul default: 105155992Swpaul printf("an%d: unknown RID: %x\n", sc->an_unit, areq->an_type); 105255992Swpaul return; 105355992Swpaul break; 105455992Swpaul } 105555992Swpaul 105655992Swpaul 105755992Swpaul /* Reinitialize the card. */ 105874698Sarchie if (ifp->if_flags) 105955992Swpaul an_init(sc); 106055992Swpaul 106155992Swpaul return; 106255992Swpaul} 106355992Swpaul 106455992Swpaul/* 106555992Swpaul * We can't change the NIC configuration while the MAC is enabled, 106655992Swpaul * so in order to turn on RX monitor mode, we have to turn the MAC 106755992Swpaul * off first. 106855992Swpaul */ 106955992Swpaulstatic void an_promisc(sc, promisc) 107055992Swpaul struct an_softc *sc; 107155992Swpaul int promisc; 107255992Swpaul{ 107374698Sarchie an_cmd(sc, AN_CMD_SET_MODE, promisc ? 0xffff : 0); 107455992Swpaul 107555992Swpaul return; 107655992Swpaul} 107755992Swpaul 107855992Swpaulstatic int an_ioctl(ifp, command, data) 107955992Swpaul struct ifnet *ifp; 108055992Swpaul u_long command; 108155992Swpaul caddr_t data; 108255992Swpaul{ 108367094Swpaul int error = 0; 108477217Sphk int len; 108577217Sphk int i; 108655992Swpaul struct an_softc *sc; 108755992Swpaul struct an_req areq; 108855992Swpaul struct ifreq *ifr; 108961816Sroberto struct proc *p = curproc; 109077217Sphk struct ieee80211req *ireq; 109177217Sphk u_int8_t tmpstr[IEEE80211_NWID_LEN*2]; 109277217Sphk u_int8_t *tmpptr; 109377217Sphk struct an_ltv_genconfig *config; 109477217Sphk struct an_ltv_key *key; 109577217Sphk struct an_ltv_status *status; 109677217Sphk struct an_ltv_ssidlist *ssids; 109755992Swpaul 109855992Swpaul sc = ifp->if_softc; 109967094Swpaul AN_LOCK(sc); 110055992Swpaul ifr = (struct ifreq *)data; 110177217Sphk ireq = (struct ieee80211req *)data; 110255992Swpaul 110377217Sphk config = (struct an_ltv_genconfig *)&areq; 110477217Sphk key = (struct an_ltv_key *)&areq; 110577217Sphk status = (struct an_ltv_status *)&areq; 110677217Sphk ssids = (struct an_ltv_ssidlist *)&areq; 110777217Sphk 110864429Speter if (sc->an_gone) { 110961816Sroberto error = ENODEV; 111061816Sroberto goto out; 111161816Sroberto } 111255992Swpaul 111355992Swpaul switch(command) { 111455992Swpaul case SIOCSIFADDR: 111555992Swpaul case SIOCGIFADDR: 111655992Swpaul case SIOCSIFMTU: 111755992Swpaul error = ether_ioctl(ifp, command, data); 111855992Swpaul break; 111955992Swpaul case SIOCSIFFLAGS: 112055992Swpaul if (ifp->if_flags & IFF_UP) { 112155992Swpaul if (ifp->if_flags & IFF_RUNNING && 112255992Swpaul ifp->if_flags & IFF_PROMISC && 112355992Swpaul !(sc->an_if_flags & IFF_PROMISC)) { 112455992Swpaul an_promisc(sc, 1); 112555992Swpaul } else if (ifp->if_flags & IFF_RUNNING && 112655992Swpaul !(ifp->if_flags & IFF_PROMISC) && 112755992Swpaul sc->an_if_flags & IFF_PROMISC) { 112855992Swpaul an_promisc(sc, 0); 112955992Swpaul } else 113055992Swpaul an_init(sc); 113155992Swpaul } else { 113255992Swpaul if (ifp->if_flags & IFF_RUNNING) 113355992Swpaul an_stop(sc); 113455992Swpaul } 113555992Swpaul sc->an_if_flags = ifp->if_flags; 113655992Swpaul error = 0; 113755992Swpaul break; 113877217Sphk case SIOCSIFMEDIA: 113977217Sphk case SIOCGIFMEDIA: 114077217Sphk error = ifmedia_ioctl(ifp, ifr, &sc->an_ifmedia, command); 114177217Sphk break; 114255992Swpaul case SIOCADDMULTI: 114355992Swpaul case SIOCDELMULTI: 114455992Swpaul /* The Aironet has no multicast filter. */ 114555992Swpaul error = 0; 114655992Swpaul break; 114755992Swpaul case SIOCGAIRONET: 114855992Swpaul error = copyin(ifr->ifr_data, &areq, sizeof(areq)); 114978639Sbrooks if (error != 0) 115055992Swpaul break; 115155992Swpaul#ifdef ANCACHE 115255992Swpaul if (areq.an_type == AN_RID_ZERO_CACHE) { 115355992Swpaul sc->an_sigitems = sc->an_nextitem = 0; 115455992Swpaul break; 115555992Swpaul } else if (areq.an_type == AN_RID_READ_CACHE) { 115655992Swpaul char *pt = (char *)&areq.an_val; 115755992Swpaul bcopy((char *)&sc->an_sigitems, (char *)pt, 115855992Swpaul sizeof(int)); 115955992Swpaul pt += sizeof(int); 116055992Swpaul areq.an_len = sizeof(int) / 2; 116155992Swpaul bcopy((char *)&sc->an_sigcache, (char *)pt, 116255992Swpaul sizeof(struct an_sigcache) * sc->an_sigitems); 116355992Swpaul areq.an_len += ((sizeof(struct an_sigcache) * 116455992Swpaul sc->an_sigitems) / 2) + 1; 116555992Swpaul } else 116655992Swpaul#endif 116755992Swpaul if (an_read_record(sc, (struct an_ltv_gen *)&areq)) { 116855992Swpaul error = EINVAL; 116955992Swpaul break; 117055992Swpaul } 117155992Swpaul error = copyout(&areq, ifr->ifr_data, sizeof(areq)); 117255992Swpaul break; 117355992Swpaul case SIOCSAIRONET: 117464429Speter if ((error = suser(p))) 117564429Speter goto out; 117655992Swpaul error = copyin(ifr->ifr_data, &areq, sizeof(areq)); 117778639Sbrooks if (error != 0) 117855992Swpaul break; 117955992Swpaul an_setdef(sc, &areq); 118055992Swpaul break; 118177217Sphk case SIOCG80211: 118277217Sphk areq.an_len = sizeof(areq); 118377217Sphk switch(ireq->i_type) { 118477217Sphk case IEEE80211_IOC_SSID: 118578639Sbrooks if (ireq->i_val == -1) { 118677217Sphk areq.an_type = AN_RID_STATUS; 118777217Sphk if (an_read_record(sc, 118877217Sphk (struct an_ltv_gen *)&areq)) { 118977217Sphk error = EINVAL; 119077217Sphk break; 119177217Sphk } 119277217Sphk len = status->an_ssidlen; 119377217Sphk tmpptr = status->an_ssid; 119478639Sbrooks } else if (ireq->i_val >= 0) { 119577217Sphk areq.an_type = AN_RID_SSIDLIST; 119677217Sphk if (an_read_record(sc, 119777217Sphk (struct an_ltv_gen *)&areq)) { 119877217Sphk error = EINVAL; 119977217Sphk break; 120077217Sphk } 120178639Sbrooks if (ireq->i_val == 0) { 120277217Sphk len = ssids->an_ssid1_len; 120377217Sphk tmpptr = ssids->an_ssid1; 120478639Sbrooks } else if (ireq->i_val == 1) { 120577217Sphk len = ssids->an_ssid2_len; 120677217Sphk tmpptr = ssids->an_ssid3; 120778639Sbrooks } else if (ireq->i_val == 1) { 120877217Sphk len = ssids->an_ssid3_len; 120977217Sphk tmpptr = ssids->an_ssid3; 121077217Sphk } else { 121177217Sphk error = EINVAL; 121277217Sphk break; 121377217Sphk } 121477217Sphk } else { 121577217Sphk error = EINVAL; 121677217Sphk break; 121777217Sphk } 121878639Sbrooks if (len > IEEE80211_NWID_LEN) { 121977217Sphk error = EINVAL; 122077217Sphk break; 122177217Sphk } 122277217Sphk ireq->i_len = len; 122377217Sphk bzero(tmpstr, IEEE80211_NWID_LEN); 122477217Sphk bcopy(tmpptr, tmpstr, len); 122577217Sphk error = copyout(tmpstr, ireq->i_data, 122677217Sphk IEEE80211_NWID_LEN); 122777217Sphk break; 122877217Sphk case IEEE80211_IOC_NUMSSIDS: 122977217Sphk ireq->i_val = 3; 123077217Sphk break; 123177217Sphk case IEEE80211_IOC_WEP: 123277217Sphk areq.an_type = AN_RID_ACTUALCFG; 123377217Sphk if (an_read_record(sc, 123477217Sphk (struct an_ltv_gen *)&areq)) { 123577217Sphk error = EINVAL; 123677217Sphk break; 123777217Sphk } 123878639Sbrooks if (config->an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE) { 123978639Sbrooks if (config->an_authtype & 124077217Sphk AN_AUTHTYPE_ALLOW_UNENCRYPTED) 124177217Sphk ireq->i_val = IEEE80211_WEP_MIXED; 124277217Sphk else 124377217Sphk ireq->i_val = IEEE80211_WEP_ON; 124477217Sphk 124577217Sphk } else { 124677217Sphk ireq->i_val = IEEE80211_WEP_OFF; 124777217Sphk } 124877217Sphk break; 124977217Sphk case IEEE80211_IOC_WEPKEY: 125077217Sphk /* 125177217Sphk * XXX: I'm not entierly convinced this is 125277217Sphk * correct, but it's what is implemented in 125377217Sphk * ancontrol so it will have to do until we get 125477217Sphk * access to actual Cisco code. 125577217Sphk */ 125678639Sbrooks if (ireq->i_val < 0 || ireq->i_val > 7) { 125777217Sphk error = EINVAL; 125877217Sphk break; 125977217Sphk } 126077217Sphk len = 0; 126178639Sbrooks if (ireq->i_val < 4) { 126277217Sphk areq.an_type = AN_RID_WEP_TEMP; 126378639Sbrooks for (i = 0; i < 5; i++) { 126477217Sphk if (an_read_record(sc, 126577217Sphk (struct an_ltv_gen *)&areq)) { 126677217Sphk error = EINVAL; 126777217Sphk break; 126877217Sphk } 126978639Sbrooks if (key->kindex == 0xffff) 127077217Sphk break; 127178639Sbrooks if (key->kindex == ireq->i_val) 127278639Sbrooks len = key->klen; 127377217Sphk /* Required to get next entry */ 127477217Sphk areq.an_type = AN_RID_WEP_PERM; 127577217Sphk } 127678639Sbrooks if (error != 0) 127777217Sphk break; 127877217Sphk } 127977217Sphk /* We aren't allowed to read the value of the 128077217Sphk * key from the card so we just output zeros 128177217Sphk * like we would if we could read the card, but 128277217Sphk * denied the user access. 128377217Sphk */ 128477217Sphk bzero(tmpstr, len); 128577217Sphk ireq->i_len = len; 128677217Sphk error = copyout(tmpstr, ireq->i_data, len); 128777217Sphk break; 128877217Sphk case IEEE80211_IOC_NUMWEPKEYS: 128977217Sphk ireq->i_val = 8; 129077217Sphk break; 129177217Sphk case IEEE80211_IOC_WEPTXKEY: 129278639Sbrooks /* 129378639Sbrooks * For some strange reason, you have to read all 129478639Sbrooks * keys before you can read the txkey. 129578639Sbrooks */ 129678639Sbrooks areq.an_type = AN_RID_WEP_TEMP; 129778639Sbrooks for (i = 0; i < 5; i++) { 129878639Sbrooks if (an_read_record(sc, 129978639Sbrooks (struct an_ltv_gen *)&areq)) { 130078639Sbrooks error = EINVAL; 130178639Sbrooks break; 130278639Sbrooks } 130378639Sbrooks if (key->kindex == 0xffff) 130478639Sbrooks break; 130578639Sbrooks /* Required to get next entry */ 130678639Sbrooks areq.an_type = AN_RID_WEP_PERM; 130778639Sbrooks } 130878639Sbrooks if (error != 0) 130978639Sbrooks break; 131078639Sbrooks 131177217Sphk areq.an_type = AN_RID_WEP_PERM; 131277217Sphk key->kindex = 0xffff; 131377217Sphk if (an_read_record(sc, 131477217Sphk (struct an_ltv_gen *)&areq)) { 131577217Sphk error = EINVAL; 131677217Sphk break; 131777217Sphk } 131877217Sphk ireq->i_val = key->mac[0]; 131977217Sphk break; 132077217Sphk case IEEE80211_IOC_AUTHMODE: 132177217Sphk areq.an_type = AN_RID_ACTUALCFG; 132277217Sphk if (an_read_record(sc, 132377217Sphk (struct an_ltv_gen *)&areq)) { 132477217Sphk error = EINVAL; 132577217Sphk break; 132677217Sphk } 132777217Sphk if ((config->an_authtype & AN_AUTHTYPE_MASK) == 132877217Sphk AN_AUTHTYPE_NONE) { 132977217Sphk ireq->i_val = IEEE80211_AUTH_NONE; 133077217Sphk } else if ((config->an_authtype & AN_AUTHTYPE_MASK) == 133177217Sphk AN_AUTHTYPE_OPEN) { 133277217Sphk ireq->i_val = IEEE80211_AUTH_OPEN; 133377217Sphk } else if ((config->an_authtype & AN_AUTHTYPE_MASK) == 133477217Sphk AN_AUTHTYPE_SHAREDKEY) { 133577217Sphk ireq->i_val = IEEE80211_AUTH_SHARED; 133677217Sphk } else 133777217Sphk error = EINVAL; 133877217Sphk break; 133977217Sphk case IEEE80211_IOC_STATIONNAME: 134077217Sphk areq.an_type = AN_RID_ACTUALCFG; 134177217Sphk if (an_read_record(sc, 134277217Sphk (struct an_ltv_gen *)&areq)) { 134377217Sphk error = EINVAL; 134477217Sphk break; 134577217Sphk } 134677217Sphk ireq->i_len = sizeof(config->an_nodename); 134777217Sphk tmpptr = config->an_nodename; 134877217Sphk bzero(tmpstr, IEEE80211_NWID_LEN); 134977217Sphk bcopy(tmpptr, tmpstr, ireq->i_len); 135077217Sphk error = copyout(tmpstr, ireq->i_data, 135177217Sphk IEEE80211_NWID_LEN); 135277217Sphk break; 135377217Sphk case IEEE80211_IOC_CHANNEL: 135477217Sphk areq.an_type = AN_RID_STATUS; 135577217Sphk if (an_read_record(sc, 135677217Sphk (struct an_ltv_gen *)&areq)) { 135777217Sphk error = EINVAL; 135877217Sphk break; 135977217Sphk } 136077217Sphk ireq->i_val = status->an_cur_channel; 136177217Sphk break; 136277217Sphk case IEEE80211_IOC_POWERSAVE: 136377217Sphk areq.an_type = AN_RID_ACTUALCFG; 136477217Sphk if (an_read_record(sc, 136577217Sphk (struct an_ltv_gen *)&areq)) { 136677217Sphk error = EINVAL; 136777217Sphk break; 136877217Sphk } 136978639Sbrooks if (config->an_psave_mode == AN_PSAVE_NONE) { 137077217Sphk ireq->i_val = IEEE80211_POWERSAVE_OFF; 137178639Sbrooks } else if (config->an_psave_mode == AN_PSAVE_CAM) { 137277217Sphk ireq->i_val = IEEE80211_POWERSAVE_CAM; 137378639Sbrooks } else if (config->an_psave_mode == AN_PSAVE_PSP) { 137477217Sphk ireq->i_val = IEEE80211_POWERSAVE_PSP; 137578639Sbrooks } else if (config->an_psave_mode == AN_PSAVE_PSP_CAM) { 137677217Sphk ireq->i_val = IEEE80211_POWERSAVE_PSP_CAM; 137777217Sphk } else 137877217Sphk error = EINVAL; 137977217Sphk break; 138077217Sphk case IEEE80211_IOC_POWERSAVESLEEP: 138177217Sphk areq.an_type = AN_RID_ACTUALCFG; 138277217Sphk if (an_read_record(sc, 138377217Sphk (struct an_ltv_gen *)&areq)) { 138477217Sphk error = EINVAL; 138577217Sphk break; 138677217Sphk } 138777217Sphk ireq->i_val = config->an_listen_interval; 138877217Sphk break; 138977217Sphk } 139077217Sphk break; 139177217Sphk case SIOCS80211: 139277217Sphk if ((error = suser(p))) 139377217Sphk goto out; 139477217Sphk areq.an_len = sizeof(areq); 139577217Sphk /* 139677217Sphk * We need a config structure for everything but the WEP 139777217Sphk * key management and SSIDs so we get it now so avoid 139877217Sphk * duplicating this code every time. 139977217Sphk */ 140077217Sphk if (ireq->i_type != IEEE80211_IOC_SSID && 140177217Sphk ireq->i_type != IEEE80211_IOC_WEPKEY && 140277217Sphk ireq->i_type != IEEE80211_IOC_WEPTXKEY) { 140377217Sphk areq.an_type = AN_RID_GENCONFIG; 140477217Sphk if (an_read_record(sc, 140577217Sphk (struct an_ltv_gen *)&areq)) { 140677217Sphk error = EINVAL; 140777217Sphk break; 140877217Sphk } 140977217Sphk } 141077217Sphk switch(ireq->i_type) { 141177217Sphk case IEEE80211_IOC_SSID: 141277217Sphk areq.an_type = AN_RID_SSIDLIST; 141377217Sphk if (an_read_record(sc, 141477217Sphk (struct an_ltv_gen *)&areq)) { 141577217Sphk error = EINVAL; 141677217Sphk break; 141777217Sphk } 141878639Sbrooks if (ireq->i_len > IEEE80211_NWID_LEN) { 141977217Sphk error = EINVAL; 142077217Sphk break; 142177217Sphk } 142277217Sphk switch (ireq->i_val) { 142377217Sphk case 0: 142477217Sphk error = copyin(ireq->i_data, 142577217Sphk ssids->an_ssid1, ireq->i_len); 142677217Sphk ssids->an_ssid1_len = ireq->i_len; 142777217Sphk break; 142877217Sphk case 1: 142977217Sphk error = copyin(ireq->i_data, 143077217Sphk ssids->an_ssid2, ireq->i_len); 143177217Sphk ssids->an_ssid2_len = ireq->i_len; 143277217Sphk break; 143377217Sphk case 2: 143477217Sphk error = copyin(ireq->i_data, 143577217Sphk ssids->an_ssid3, ireq->i_len); 143677217Sphk ssids->an_ssid3_len = ireq->i_len; 143777217Sphk break; 143877217Sphk default: 143977217Sphk error = EINVAL; 144077217Sphk break; 144177217Sphk } 144277217Sphk break; 144377217Sphk case IEEE80211_IOC_WEP: 144477217Sphk switch (ireq->i_val) { 144577217Sphk case IEEE80211_WEP_OFF: 144677217Sphk config->an_authtype &= 144777217Sphk ~(AN_AUTHTYPE_PRIVACY_IN_USE | 144877217Sphk AN_AUTHTYPE_ALLOW_UNENCRYPTED); 144977217Sphk break; 145077217Sphk case IEEE80211_WEP_ON: 145177217Sphk config->an_authtype |= 145277217Sphk AN_AUTHTYPE_PRIVACY_IN_USE; 145377217Sphk config->an_authtype &= 145477217Sphk ~AN_AUTHTYPE_ALLOW_UNENCRYPTED; 145577217Sphk break; 145677217Sphk case IEEE80211_WEP_MIXED: 145777217Sphk config->an_authtype |= 145877217Sphk AN_AUTHTYPE_PRIVACY_IN_USE | 145977217Sphk AN_AUTHTYPE_ALLOW_UNENCRYPTED; 146077217Sphk break; 146177217Sphk default: 146277217Sphk error = EINVAL; 146377217Sphk break; 146477217Sphk } 146577217Sphk break; 146677217Sphk case IEEE80211_IOC_WEPKEY: 146777217Sphk if (ireq->i_val < 0 || ireq->i_val > 7 || 146877217Sphk ireq->i_len > 13) { 146977217Sphk error = EINVAL; 147077217Sphk break; 147177217Sphk } 147277217Sphk error = copyin(ireq->i_data, tmpstr, 13); 147378639Sbrooks if (error != 0) 147477217Sphk break; 147577217Sphk bzero(&areq, sizeof(struct an_ltv_key)); 147677217Sphk areq.an_len = sizeof(struct an_ltv_key); 147777217Sphk key->mac[0] = 1; /* The others are 0. */ 147877217Sphk key->kindex = ireq->i_val % 4; 147978639Sbrooks if (ireq->i_val < 4) 148077217Sphk areq.an_type = AN_RID_WEP_TEMP; 148177217Sphk else 148277217Sphk areq.an_type = AN_RID_WEP_PERM; 148377217Sphk key->klen = ireq->i_len; 148477217Sphk bcopy(tmpstr, key->key, key->klen); 148577217Sphk break; 148677217Sphk case IEEE80211_IOC_WEPTXKEY: 148778639Sbrooks if (ireq->i_val < 0 || ireq->i_val > 3) { 148877217Sphk error = EINVAL; 148977217Sphk break; 149077217Sphk } 149177217Sphk bzero(&areq, sizeof(struct an_ltv_key)); 149277217Sphk areq.an_len = sizeof(struct an_ltv_key); 149377217Sphk areq.an_type = AN_RID_WEP_PERM; 149477217Sphk key->kindex = 0xffff; 149577217Sphk key->mac[0] = ireq->i_val; 149677217Sphk break; 149777217Sphk case IEEE80211_IOC_AUTHMODE: 149877217Sphk switch (ireq->i_val) { 149977217Sphk case IEEE80211_AUTH_NONE: 150077217Sphk config->an_authtype = AN_AUTHTYPE_NONE | 150177217Sphk (config->an_authtype & ~AN_AUTHTYPE_MASK); 150277217Sphk break; 150377217Sphk case IEEE80211_AUTH_OPEN: 150477217Sphk config->an_authtype = AN_AUTHTYPE_OPEN | 150577217Sphk (config->an_authtype & ~AN_AUTHTYPE_MASK); 150677217Sphk break; 150777217Sphk case IEEE80211_AUTH_SHARED: 150877217Sphk config->an_authtype = AN_AUTHTYPE_SHAREDKEY | 150977217Sphk (config->an_authtype & ~AN_AUTHTYPE_MASK); 151077217Sphk break; 151177217Sphk default: 151277217Sphk error = EINVAL; 151377217Sphk } 151477217Sphk break; 151577217Sphk case IEEE80211_IOC_STATIONNAME: 151678639Sbrooks if (ireq->i_len > 16) { 151777217Sphk error = EINVAL; 151877217Sphk break; 151977217Sphk } 152077217Sphk bzero(config->an_nodename, 16); 152177217Sphk error = copyin(ireq->i_data, 152277217Sphk config->an_nodename, ireq->i_len); 152377217Sphk break; 152477217Sphk case IEEE80211_IOC_CHANNEL: 152577217Sphk /* 152677217Sphk * The actual range is 1-14, but if you set it 152777217Sphk * to 0 you get the default so we let that work 152877217Sphk * too. 152977217Sphk */ 153077217Sphk if (ireq->i_val < 0 || ireq->i_val >14) { 153177217Sphk error = EINVAL; 153277217Sphk break; 153377217Sphk } 153477217Sphk config->an_ds_channel = ireq->i_val; 153577217Sphk break; 153677217Sphk case IEEE80211_IOC_POWERSAVE: 153777217Sphk switch (ireq->i_val) { 153877217Sphk case IEEE80211_POWERSAVE_OFF: 153977217Sphk config->an_psave_mode = AN_PSAVE_NONE; 154077217Sphk break; 154177217Sphk case IEEE80211_POWERSAVE_CAM: 154277217Sphk config->an_psave_mode = AN_PSAVE_CAM; 154377217Sphk break; 154477217Sphk case IEEE80211_POWERSAVE_PSP: 154577217Sphk config->an_psave_mode = AN_PSAVE_PSP; 154677217Sphk break; 154777217Sphk case IEEE80211_POWERSAVE_PSP_CAM: 154877217Sphk config->an_psave_mode = AN_PSAVE_PSP_CAM; 154977217Sphk break; 155077217Sphk default: 155177217Sphk error = EINVAL; 155277217Sphk break; 155377217Sphk } 155477217Sphk break; 155577217Sphk case IEEE80211_IOC_POWERSAVESLEEP: 155677217Sphk config->an_listen_interval = ireq->i_val; 155777217Sphk break; 155877217Sphk } 155977217Sphk 156077217Sphk if (!error) 156177217Sphk an_setdef(sc, &areq); 156277217Sphk break; 156355992Swpaul default: 156455992Swpaul error = EINVAL; 156555992Swpaul break; 156655992Swpaul } 156761816Srobertoout: 156867094Swpaul AN_UNLOCK(sc); 156955992Swpaul 157078639Sbrooks return(error != 0); 157155992Swpaul} 157255992Swpaul 157355992Swpaulstatic int an_init_tx_ring(sc) 157455992Swpaul struct an_softc *sc; 157555992Swpaul{ 157655992Swpaul int i; 157755992Swpaul int id; 157855992Swpaul 157955992Swpaul if (sc->an_gone) 158055992Swpaul return (0); 158155992Swpaul 158255992Swpaul for (i = 0; i < AN_TX_RING_CNT; i++) { 158355992Swpaul if (an_alloc_nicmem(sc, 1518 + 158455992Swpaul 0x44, &id)) 158555992Swpaul return(ENOMEM); 158655992Swpaul sc->an_rdata.an_tx_fids[i] = id; 158755992Swpaul sc->an_rdata.an_tx_ring[i] = 0; 158855992Swpaul } 158955992Swpaul 159055992Swpaul sc->an_rdata.an_tx_prod = 0; 159155992Swpaul sc->an_rdata.an_tx_cons = 0; 159255992Swpaul 159355992Swpaul return(0); 159455992Swpaul} 159555992Swpaul 159655992Swpaulstatic void an_init(xsc) 159755992Swpaul void *xsc; 159855992Swpaul{ 159955992Swpaul struct an_softc *sc = xsc; 160055992Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 160155992Swpaul 160267094Swpaul AN_LOCK(sc); 160367094Swpaul 160467094Swpaul if (sc->an_gone) { 160567094Swpaul AN_UNLOCK(sc); 160655992Swpaul return; 160767094Swpaul } 160855992Swpaul 160955992Swpaul if (ifp->if_flags & IFF_RUNNING) 161055992Swpaul an_stop(sc); 161155992Swpaul 161255992Swpaul sc->an_associated = 0; 161355992Swpaul 161455992Swpaul /* Allocate the TX buffers */ 161555992Swpaul if (an_init_tx_ring(sc)) { 161655992Swpaul an_reset(sc); 161755992Swpaul if (an_init_tx_ring(sc)) { 161855992Swpaul printf("an%d: tx buffer allocation " 161955992Swpaul "failed\n", sc->an_unit); 162067094Swpaul AN_UNLOCK(sc); 162155992Swpaul return; 162255992Swpaul } 162355992Swpaul } 162455992Swpaul 162555992Swpaul /* Set our MAC address. */ 162655992Swpaul bcopy((char *)&sc->arpcom.ac_enaddr, 162755992Swpaul (char *)&sc->an_config.an_macaddr, ETHER_ADDR_LEN); 162855992Swpaul 162955992Swpaul if (ifp->if_flags & IFF_BROADCAST) 163055992Swpaul sc->an_config.an_rxmode = AN_RXMODE_BC_ADDR; 163155992Swpaul else 163255992Swpaul sc->an_config.an_rxmode = AN_RXMODE_ADDR; 163355992Swpaul 163455992Swpaul if (ifp->if_flags & IFF_MULTICAST) 163555992Swpaul sc->an_config.an_rxmode = AN_RXMODE_BC_MC_ADDR; 163655992Swpaul 163755992Swpaul /* Initialize promisc mode. */ 163868692Swpaul /* Kills card DJA can't TX packet in sniff mode 163968692Swpaul if (ifp->if_flags & IFF_PROMISC) 164055992Swpaul sc->an_config.an_rxmode |= AN_RXMODE_LAN_MONITOR_CURBSS; 164168692Swpaul */ 164255992Swpaul 164355992Swpaul sc->an_rxmode = sc->an_config.an_rxmode; 164455992Swpaul 164555992Swpaul /* Set the ssid list */ 164655992Swpaul sc->an_ssidlist.an_type = AN_RID_SSIDLIST; 164755992Swpaul sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist); 164855992Swpaul if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) { 164955992Swpaul printf("an%d: failed to set ssid list\n", sc->an_unit); 165067094Swpaul AN_UNLOCK(sc); 165155992Swpaul return; 165255992Swpaul } 165355992Swpaul 165455992Swpaul /* Set the AP list */ 165555992Swpaul sc->an_aplist.an_type = AN_RID_APLIST; 165655992Swpaul sc->an_aplist.an_len = sizeof(struct an_ltv_aplist); 165755992Swpaul if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) { 165855992Swpaul printf("an%d: failed to set AP list\n", sc->an_unit); 165967094Swpaul AN_UNLOCK(sc); 166055992Swpaul return; 166155992Swpaul } 166255992Swpaul 166355992Swpaul /* Set the configuration in the NIC */ 166455992Swpaul sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 166555992Swpaul sc->an_config.an_type = AN_RID_GENCONFIG; 166655992Swpaul if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_config)) { 166755992Swpaul printf("an%d: failed to set configuration\n", sc->an_unit); 166867094Swpaul AN_UNLOCK(sc); 166955992Swpaul return; 167055992Swpaul } 167155992Swpaul 167255992Swpaul /* Enable the MAC */ 167355992Swpaul if (an_cmd(sc, AN_CMD_ENABLE, 0)) { 167455992Swpaul printf("an%d: failed to enable MAC\n", sc->an_unit); 167567094Swpaul AN_UNLOCK(sc); 167655992Swpaul return; 167755992Swpaul } 167855992Swpaul 167974698Sarchie if (ifp->if_flags & IFF_PROMISC) 168074698Sarchie an_cmd(sc, AN_CMD_SET_MODE, 0xffff); 168174698Sarchie 168255992Swpaul /* enable interrupts */ 168355992Swpaul CSR_WRITE_2(sc, AN_INT_EN, AN_INTRS); 168455992Swpaul 168555992Swpaul ifp->if_flags |= IFF_RUNNING; 168655992Swpaul ifp->if_flags &= ~IFF_OACTIVE; 168755992Swpaul 168855992Swpaul sc->an_stat_ch = timeout(an_stats_update, sc, hz); 168967094Swpaul AN_UNLOCK(sc); 169055992Swpaul 169155992Swpaul return; 169255992Swpaul} 169355992Swpaul 169455992Swpaulstatic void an_start(ifp) 169555992Swpaul struct ifnet *ifp; 169655992Swpaul{ 169755992Swpaul struct an_softc *sc; 169855992Swpaul struct mbuf *m0 = NULL; 169955992Swpaul struct an_txframe_802_3 tx_frame_802_3; 170055992Swpaul struct ether_header *eh; 170155992Swpaul int id; 170255992Swpaul int idx; 170355992Swpaul unsigned char txcontrol; 170455992Swpaul 170555992Swpaul sc = ifp->if_softc; 170655992Swpaul 170755992Swpaul if (sc->an_gone) 170855992Swpaul return; 170955992Swpaul 171055992Swpaul if (ifp->if_flags & IFF_OACTIVE) 171155992Swpaul return; 171255992Swpaul 171355992Swpaul if (!sc->an_associated) 171455992Swpaul return; 171555992Swpaul 171655992Swpaul idx = sc->an_rdata.an_tx_prod; 171755992Swpaul bzero((char *)&tx_frame_802_3, sizeof(tx_frame_802_3)); 171855992Swpaul 171955992Swpaul while(sc->an_rdata.an_tx_ring[idx] == 0) { 172055992Swpaul IF_DEQUEUE(&ifp->if_snd, m0); 172155992Swpaul if (m0 == NULL) 172255992Swpaul break; 172355992Swpaul 172455992Swpaul id = sc->an_rdata.an_tx_fids[idx]; 172555992Swpaul eh = mtod(m0, struct ether_header *); 172655992Swpaul 172755992Swpaul bcopy((char *)&eh->ether_dhost, 172855992Swpaul (char *)&tx_frame_802_3.an_tx_dst_addr, ETHER_ADDR_LEN); 172955992Swpaul bcopy((char *)&eh->ether_shost, 173055992Swpaul (char *)&tx_frame_802_3.an_tx_src_addr, ETHER_ADDR_LEN); 173155992Swpaul 173255992Swpaul tx_frame_802_3.an_tx_802_3_payload_len = 173355992Swpaul m0->m_pkthdr.len - 12; /* minus src/dest mac & type */ 173455992Swpaul 173555992Swpaul m_copydata(m0, sizeof(struct ether_header) - 2 , 173655992Swpaul tx_frame_802_3.an_tx_802_3_payload_len, 173755992Swpaul (caddr_t)&sc->an_txbuf); 173855992Swpaul 173978639Sbrooks txcontrol = AN_TXCTL_8023; 174055992Swpaul /* write the txcontrol only */ 174155992Swpaul an_write_data(sc, id, 0x08, (caddr_t)&txcontrol, 174255992Swpaul sizeof(txcontrol)); 174355992Swpaul 174455992Swpaul /* 802_3 header */ 174555992Swpaul an_write_data(sc, id, 0x34, (caddr_t)&tx_frame_802_3, 174655992Swpaul sizeof(struct an_txframe_802_3)); 174755992Swpaul 174855992Swpaul /* in mbuf header type is just before payload */ 174955992Swpaul an_write_data(sc, id, 0x44, (caddr_t)&sc->an_txbuf, 175055992Swpaul tx_frame_802_3.an_tx_802_3_payload_len); 175155992Swpaul 175255992Swpaul /* 175355992Swpaul * If there's a BPF listner, bounce a copy of 175455992Swpaul * this frame to him. 175555992Swpaul */ 175655992Swpaul if (ifp->if_bpf) 175755992Swpaul bpf_mtap(ifp, m0); 175855992Swpaul 175955992Swpaul m_freem(m0); 176055992Swpaul m0 = NULL; 176155992Swpaul 176255992Swpaul sc->an_rdata.an_tx_ring[idx] = id; 176355992Swpaul if (an_cmd(sc, AN_CMD_TX, id)) 176455992Swpaul printf("an%d: xmit failed\n", sc->an_unit); 176555992Swpaul 176655992Swpaul AN_INC(idx, AN_TX_RING_CNT); 176755992Swpaul } 176855992Swpaul 176955992Swpaul if (m0 != NULL) 177055992Swpaul ifp->if_flags |= IFF_OACTIVE; 177155992Swpaul 177255992Swpaul sc->an_rdata.an_tx_prod = idx; 177355992Swpaul 177455992Swpaul /* 177555992Swpaul * Set a timeout in case the chip goes out to lunch. 177655992Swpaul */ 177755992Swpaul ifp->if_timer = 5; 177855992Swpaul 177955992Swpaul return; 178055992Swpaul} 178155992Swpaul 178255992Swpaulvoid an_stop(sc) 178355992Swpaul struct an_softc *sc; 178455992Swpaul{ 178555992Swpaul struct ifnet *ifp; 178655992Swpaul int i; 178755992Swpaul 178867094Swpaul AN_LOCK(sc); 178967094Swpaul 179067094Swpaul if (sc->an_gone) { 179167094Swpaul AN_UNLOCK(sc); 179255992Swpaul return; 179367094Swpaul } 179455992Swpaul 179555992Swpaul ifp = &sc->arpcom.ac_if; 179655992Swpaul 179755992Swpaul an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0); 179855992Swpaul CSR_WRITE_2(sc, AN_INT_EN, 0); 179955992Swpaul an_cmd(sc, AN_CMD_DISABLE, 0); 180055992Swpaul 180155992Swpaul for (i = 0; i < AN_TX_RING_CNT; i++) 180255992Swpaul an_cmd(sc, AN_CMD_DEALLOC_MEM, sc->an_rdata.an_tx_fids[i]); 180355992Swpaul 180455992Swpaul untimeout(an_stats_update, sc, sc->an_stat_ch); 180555992Swpaul 180655992Swpaul ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); 180755992Swpaul 180867094Swpaul AN_UNLOCK(sc); 180967094Swpaul 181055992Swpaul return; 181155992Swpaul} 181255992Swpaul 181355992Swpaulstatic void an_watchdog(ifp) 181455992Swpaul struct ifnet *ifp; 181555992Swpaul{ 181655992Swpaul struct an_softc *sc; 181755992Swpaul 181855992Swpaul sc = ifp->if_softc; 181967094Swpaul AN_LOCK(sc); 182055992Swpaul 182167094Swpaul if (sc->an_gone) { 182267094Swpaul AN_UNLOCK(sc); 182355992Swpaul return; 182467094Swpaul } 182555992Swpaul 182655992Swpaul printf("an%d: device timeout\n", sc->an_unit); 182755992Swpaul 182855992Swpaul an_reset(sc); 182955992Swpaul an_init(sc); 183055992Swpaul 183155992Swpaul ifp->if_oerrors++; 183267094Swpaul AN_UNLOCK(sc); 183355992Swpaul 183455992Swpaul return; 183555992Swpaul} 183655992Swpaul 183755992Swpaulvoid an_shutdown(dev) 183855992Swpaul device_t dev; 183955992Swpaul{ 184055992Swpaul struct an_softc *sc; 184155992Swpaul 184255992Swpaul sc = device_get_softc(dev); 184355992Swpaul an_stop(sc); 184455992Swpaul 184555992Swpaul return; 184655992Swpaul} 184755992Swpaul 184855992Swpaul#ifdef ANCACHE 184955992Swpaul/* Aironet signal strength cache code. 185055992Swpaul * store signal/noise/quality on per MAC src basis in 185155992Swpaul * a small fixed cache. The cache wraps if > MAX slots 185255992Swpaul * used. The cache may be zeroed out to start over. 185355992Swpaul * Two simple filters exist to reduce computation: 185455992Swpaul * 1. ip only (literally 0x800) which may be used 185555992Swpaul * to ignore some packets. It defaults to ip only. 185655992Swpaul * it could be used to focus on broadcast, non-IP 802.11 beacons. 185755992Swpaul * 2. multicast/broadcast only. This may be used to 185855992Swpaul * ignore unicast packets and only cache signal strength 185955992Swpaul * for multicast/broadcast packets (beacons); e.g., Mobile-IP 186055992Swpaul * beacons and not unicast traffic. 186155992Swpaul * 186255992Swpaul * The cache stores (MAC src(index), IP src (major clue), signal, 186355992Swpaul * quality, noise) 186455992Swpaul * 186555992Swpaul * No apologies for storing IP src here. It's easy and saves much 186655992Swpaul * trouble elsewhere. The cache is assumed to be INET dependent, 186755992Swpaul * although it need not be. 186855992Swpaul * 186955992Swpaul * Note: the Aironet only has a single byte of signal strength value 187055992Swpaul * in the rx frame header, and it's not scaled to anything sensible. 187155992Swpaul * This is kind of lame, but it's all we've got. 187255992Swpaul */ 187355992Swpaul 187455992Swpaul#ifdef documentation 187555992Swpaul 187655992Swpaulint an_sigitems; /* number of cached entries */ 187755992Swpaulstruct an_sigcache an_sigcache[MAXANCACHE]; /* array of cache entries */ 187855992Swpaulint an_nextitem; /* index/# of entries */ 187955992Swpaul 188055992Swpaul 188155992Swpaul#endif 188255992Swpaul 188355992Swpaul/* control variables for cache filtering. Basic idea is 188455992Swpaul * to reduce cost (e.g., to only Mobile-IP agent beacons 188555992Swpaul * which are broadcast or multicast). Still you might 188655992Swpaul * want to measure signal strength anth unicast ping packets 188755992Swpaul * on a pt. to pt. ant. setup. 188855992Swpaul */ 188955992Swpaul/* set true if you want to limit cache items to broadcast/mcast 189055992Swpaul * only packets (not unicast). Useful for mobile-ip beacons which 189155992Swpaul * are broadcast/multicast at network layer. Default is all packets 189255992Swpaul * so ping/unicast anll work say anth pt. to pt. antennae setup. 189355992Swpaul */ 189455992Swpaulstatic int an_cache_mcastonly = 0; 189555992SwpaulSYSCTL_INT(_machdep, OID_AUTO, an_cache_mcastonly, CTLFLAG_RW, 189655992Swpaul &an_cache_mcastonly, 0, ""); 189755992Swpaul 189855992Swpaul/* set true if you want to limit cache items to IP packets only 189955992Swpaul*/ 190055992Swpaulstatic int an_cache_iponly = 1; 190155992SwpaulSYSCTL_INT(_machdep, OID_AUTO, an_cache_iponly, CTLFLAG_RW, 190255992Swpaul &an_cache_iponly, 0, ""); 190355992Swpaul 190455992Swpaul/* 190555992Swpaul * an_cache_store, per rx packet store signal 190655992Swpaul * strength in MAC (src) indexed cache. 190755992Swpaul */ 190855992Swpaulstatic 190955992Swpaulvoid an_cache_store (sc, eh, m, rx_quality) 191055992Swpaul struct an_softc *sc; 191155992Swpaul struct ether_header *eh; 191255992Swpaul struct mbuf *m; 191355992Swpaul unsigned short rx_quality; 191455992Swpaul{ 191555992Swpaul struct ip *ip = 0; 191655992Swpaul int i; 191755992Swpaul static int cache_slot = 0; /* use this cache entry */ 191855992Swpaul static int wrapindex = 0; /* next "free" cache entry */ 191978639Sbrooks int saanp = 0; 192055992Swpaul 192155992Swpaul /* filters: 192255992Swpaul * 1. ip only 192355992Swpaul * 2. configurable filter to throw out unicast packets, 192455992Swpaul * keep multicast only. 192555992Swpaul */ 192655992Swpaul 192755992Swpaul if ((ntohs(eh->ether_type) == 0x800)) { 192855992Swpaul saanp = 1; 192955992Swpaul } 193055992Swpaul 193155992Swpaul /* filter for ip packets only 193255992Swpaul */ 193355992Swpaul if ( an_cache_iponly && !saanp) { 193455992Swpaul return; 193555992Swpaul } 193655992Swpaul 193755992Swpaul /* filter for broadcast/multicast only 193855992Swpaul */ 193955992Swpaul if (an_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) { 194055992Swpaul return; 194155992Swpaul } 194255992Swpaul 194355992Swpaul#ifdef SIGDEBUG 194455992Swpaul printf("an: q value %x (MSB=0x%x, LSB=0x%x) \n", 194555992Swpaul rx_quality & 0xffff, rx_quality >> 8, rx_quality & 0xff); 194655992Swpaul#endif 194755992Swpaul 194855992Swpaul /* find the ip header. we want to store the ip_src 194955992Swpaul * address. 195055992Swpaul */ 195155992Swpaul if (saanp) { 195255992Swpaul ip = mtod(m, struct ip *); 195355992Swpaul } 195455992Swpaul 195555992Swpaul /* do a linear search for a matching MAC address 195655992Swpaul * in the cache table 195755992Swpaul * . MAC address is 6 bytes, 195855992Swpaul * . var w_nextitem holds total number of entries already cached 195955992Swpaul */ 196078639Sbrooks for (i = 0; i < sc->an_nextitem; i++) { 196155992Swpaul if (! bcmp(eh->ether_shost , sc->an_sigcache[i].macsrc, 6 )) { 196255992Swpaul /* Match!, 196355992Swpaul * so we already have this entry, 196455992Swpaul * update the data 196555992Swpaul */ 196655992Swpaul break; 196755992Swpaul } 196855992Swpaul } 196955992Swpaul 197055992Swpaul /* did we find a matching mac address? 197155992Swpaul * if yes, then overwrite a previously existing cache entry 197255992Swpaul */ 197355992Swpaul if (i < sc->an_nextitem ) { 197455992Swpaul cache_slot = i; 197555992Swpaul } 197655992Swpaul /* else, have a new address entry,so 197755992Swpaul * add this new entry, 197855992Swpaul * if table full, then we need to replace LRU entry 197955992Swpaul */ 198055992Swpaul else { 198155992Swpaul 198255992Swpaul /* check for space in cache table 198355992Swpaul * note: an_nextitem also holds number of entries 198455992Swpaul * added in the cache table 198555992Swpaul */ 198655992Swpaul if ( sc->an_nextitem < MAXANCACHE ) { 198755992Swpaul cache_slot = sc->an_nextitem; 198855992Swpaul sc->an_nextitem++; 198955992Swpaul sc->an_sigitems = sc->an_nextitem; 199055992Swpaul } 199155992Swpaul /* no space found, so simply wrap anth wrap index 199255992Swpaul * and "zap" the next entry 199355992Swpaul */ 199455992Swpaul else { 199555992Swpaul if (wrapindex == MAXANCACHE) { 199655992Swpaul wrapindex = 0; 199755992Swpaul } 199855992Swpaul cache_slot = wrapindex++; 199955992Swpaul } 200055992Swpaul } 200155992Swpaul 200255992Swpaul /* invariant: cache_slot now points at some slot 200355992Swpaul * in cache. 200455992Swpaul */ 200555992Swpaul if (cache_slot < 0 || cache_slot >= MAXANCACHE) { 200655992Swpaul log(LOG_ERR, "an_cache_store, bad index: %d of " 200755992Swpaul "[0..%d], gross cache error\n", 200855992Swpaul cache_slot, MAXANCACHE); 200955992Swpaul return; 201055992Swpaul } 201155992Swpaul 201255992Swpaul /* store items in cache 201355992Swpaul * .ip source address 201455992Swpaul * .mac src 201555992Swpaul * .signal, etc. 201655992Swpaul */ 201755992Swpaul if (saanp) { 201855992Swpaul sc->an_sigcache[cache_slot].ipsrc = ip->ip_src.s_addr; 201955992Swpaul } 202055992Swpaul bcopy( eh->ether_shost, sc->an_sigcache[cache_slot].macsrc, 6); 202155992Swpaul 202255992Swpaul sc->an_sigcache[cache_slot].signal = rx_quality; 202355992Swpaul 202455992Swpaul return; 202555992Swpaul} 202655992Swpaul#endif 202777217Sphk 202877217Sphkstatic int an_media_change(ifp) 202977217Sphk struct ifnet *ifp; 203077217Sphk{ 203177217Sphk struct an_softc *sc = ifp->if_softc; 203277217Sphk int otype = sc->an_config.an_opmode; 203377217Sphk int orate = sc->an_tx_rate; 203477217Sphk 203577217Sphk if ((sc->an_ifmedia.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC) != 0) 203677217Sphk sc->an_config.an_opmode = AN_OPMODE_IBSS_ADHOC; 203777217Sphk else 203877217Sphk sc->an_config.an_opmode = AN_OPMODE_INFRASTRUCTURE_STATION; 203977217Sphk 204077217Sphk switch (IFM_SUBTYPE(sc->an_ifmedia.ifm_cur->ifm_media)) { 204177217Sphk case IFM_IEEE80211_DS1: 204277217Sphk sc->an_tx_rate = AN_RATE_1MBPS; 204377217Sphk break; 204477217Sphk case IFM_IEEE80211_DS2: 204577217Sphk sc->an_tx_rate = AN_RATE_2MBPS; 204677217Sphk break; 204777217Sphk case IFM_IEEE80211_DS5: 204877217Sphk sc->an_tx_rate = AN_RATE_5_5MBPS; 204977217Sphk break; 205077217Sphk case IFM_IEEE80211_DS11: 205177217Sphk sc->an_tx_rate = AN_RATE_11MBPS; 205277217Sphk break; 205377217Sphk case IFM_AUTO: 205477217Sphk sc->an_tx_rate = 0; 205577217Sphk break; 205677217Sphk } 205777217Sphk 205877217Sphk if (otype != sc->an_config.an_opmode || 205977217Sphk orate != sc->an_tx_rate) 206077217Sphk an_init(sc); 206177217Sphk 206277217Sphk return(0); 206377217Sphk} 206477217Sphk 206577217Sphkstatic void an_media_status(ifp, imr) 206677217Sphk struct ifnet *ifp; 206777217Sphk struct ifmediareq *imr; 206877217Sphk{ 206977217Sphk struct an_ltv_status status; 207077217Sphk struct an_softc *sc = ifp->if_softc; 207177217Sphk 207277217Sphk status.an_len = sizeof(status); 207377217Sphk status.an_type = AN_RID_STATUS; 207477217Sphk if (an_read_record(sc, (struct an_ltv_gen *)&status)) { 207577217Sphk /* If the status read fails, just lie. */ 207677217Sphk imr->ifm_active = sc->an_ifmedia.ifm_cur->ifm_media; 207777217Sphk imr->ifm_status = IFM_AVALID|IFM_ACTIVE; 207877217Sphk } 207977217Sphk 208078639Sbrooks if (sc->an_tx_rate == 0) { 208177217Sphk imr->ifm_active = IFM_IEEE80211|IFM_AUTO; 208277217Sphk if (sc->an_config.an_opmode == AN_OPMODE_IBSS_ADHOC) 208377217Sphk imr->ifm_active |= IFM_IEEE80211_ADHOC; 208477217Sphk switch(status.an_current_tx_rate) { 208577217Sphk case AN_RATE_1MBPS: 208677217Sphk imr->ifm_active |= IFM_IEEE80211_DS1; 208777217Sphk break; 208877217Sphk case AN_RATE_2MBPS: 208977217Sphk imr->ifm_active |= IFM_IEEE80211_DS2; 209077217Sphk break; 209177217Sphk case AN_RATE_5_5MBPS: 209277217Sphk imr->ifm_active |= IFM_IEEE80211_DS5; 209377217Sphk break; 209477217Sphk case AN_RATE_11MBPS: 209577217Sphk imr->ifm_active |= IFM_IEEE80211_DS11; 209677217Sphk break; 209777217Sphk } 209877217Sphk } else { 209977217Sphk imr->ifm_active = sc->an_ifmedia.ifm_cur->ifm_media; 210077217Sphk } 210177217Sphk 210277217Sphk imr->ifm_status = IFM_AVALID; 210377217Sphk if (sc->an_config.an_opmode == AN_OPMODE_IBSS_ADHOC) 210477217Sphk imr->ifm_status |= IFM_ACTIVE; 210577217Sphk else if (status.an_opmode & AN_STATUS_OPMODE_ASSOCIATED) 210677217Sphk imr->ifm_status |= IFM_ACTIVE; 210777217Sphk} 2108