if_wi.c revision 75149
146492Swpaul/* 246492Swpaul * Copyright (c) 1997, 1998, 1999 346492Swpaul * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 446492Swpaul * 546492Swpaul * Redistribution and use in source and binary forms, with or without 646492Swpaul * modification, are permitted provided that the following conditions 746492Swpaul * are met: 846492Swpaul * 1. Redistributions of source code must retain the above copyright 946492Swpaul * notice, this list of conditions and the following disclaimer. 1046492Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1146492Swpaul * notice, this list of conditions and the following disclaimer in the 1246492Swpaul * documentation and/or other materials provided with the distribution. 1346492Swpaul * 3. All advertising materials mentioning features or use of this software 1446492Swpaul * must display the following acknowledgement: 1546492Swpaul * This product includes software developed by Bill Paul. 1646492Swpaul * 4. Neither the name of the author nor the names of any co-contributors 1746492Swpaul * may be used to endorse or promote products derived from this software 1846492Swpaul * without specific prior written permission. 1946492Swpaul * 2046492Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 2146492Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2246492Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2346492Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 2446492Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2546492Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2646492Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2746492Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2846492Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2946492Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3046492Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 3146492Swpaul */ 3246492Swpaul 3346492Swpaul/* 3446492Swpaul * Lucent WaveLAN/IEEE 802.11 PCMCIA driver for FreeBSD. 3546492Swpaul * 3646492Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu> 3746492Swpaul * Electrical Engineering Department 3846492Swpaul * Columbia University, New York City 3946492Swpaul */ 4046492Swpaul 4146492Swpaul/* 4247401Swpaul * The WaveLAN/IEEE adapter is the second generation of the WaveLAN 4346492Swpaul * from Lucent. Unlike the older cards, the new ones are programmed 4446492Swpaul * entirely via a firmware-driven controller called the Hermes. 4546492Swpaul * Unfortunately, Lucent will not release the Hermes programming manual 4646492Swpaul * without an NDA (if at all). What they do release is an API library 4746492Swpaul * called the HCF (Hardware Control Functions) which is supposed to 4846492Swpaul * do the device-specific operations of a device driver for you. The 4946492Swpaul * publically available version of the HCF library (the 'HCF Light') is 5047401Swpaul * a) extremely gross, b) lacks certain features, particularly support 5146492Swpaul * for 802.11 frames, and c) is contaminated by the GNU Public License. 5246492Swpaul * 5346492Swpaul * This driver does not use the HCF or HCF Light at all. Instead, it 5446492Swpaul * programs the Hermes controller directly, using information gleaned 5546492Swpaul * from the HCF Light code and corresponding documentation. 5646492Swpaul * 5746492Swpaul * This driver supports both the PCMCIA and ISA versions of the 5846492Swpaul * WaveLAN/IEEE cards. Note however that the ISA card isn't really 5946492Swpaul * anything of the sort: it's actually a PCMCIA bridge adapter 6046492Swpaul * that fits into an ISA slot, into which a PCMCIA WaveLAN card is 6146492Swpaul * inserted. Consequently, you need to use the pccard support for 6246492Swpaul * both the ISA and PCMCIA adapters. 6346492Swpaul */ 6446492Swpaul 6546492Swpaul#define WI_HERMES_AUTOINC_WAR /* Work around data write autoinc bug. */ 6646492Swpaul#define WI_HERMES_STATS_WAR /* Work around stats counter bug. */ 6753702Swpaul#define WICACHE /* turn on signal strength cache code */ 6846492Swpaul 6946492Swpaul#include <sys/param.h> 7046492Swpaul#include <sys/systm.h> 7146492Swpaul#include <sys/sockio.h> 7246492Swpaul#include <sys/mbuf.h> 7346492Swpaul#include <sys/kernel.h> 7446492Swpaul#include <sys/socket.h> 7553702Swpaul#include <sys/module.h> 7653702Swpaul#include <sys/bus.h> 7753702Swpaul#include <sys/syslog.h> 7853702Swpaul#include <sys/sysctl.h> 7946492Swpaul 8053702Swpaul#include <machine/bus.h> 8153702Swpaul#include <machine/resource.h> 8253702Swpaul#include <machine/md_var.h> 8353702Swpaul#include <machine/bus_pio.h> 8453702Swpaul#include <sys/rman.h> 8553702Swpaul 8674906Salfred#include <pci/pcireg.h> 8774906Salfred#include <pci/pcivar.h> 8874906Salfred 8946492Swpaul#include <net/if.h> 9046492Swpaul#include <net/if_arp.h> 9146492Swpaul#include <net/ethernet.h> 9246492Swpaul#include <net/if_dl.h> 9346492Swpaul#include <net/if_media.h> 9446492Swpaul#include <net/if_types.h> 9546492Swpaul 9646492Swpaul#include <netinet/in.h> 9746492Swpaul#include <netinet/in_systm.h> 9846492Swpaul#include <netinet/in_var.h> 9946492Swpaul#include <netinet/ip.h> 10046492Swpaul#include <netinet/if_ether.h> 10146492Swpaul 10246492Swpaul#include <net/bpf.h> 10346492Swpaul 10471161Speter#include <dev/pccard/pccardvar.h> 10571161Speter#include <dev/pccard/pccarddevs.h> 10671161Speter 10770808Speter#include <dev/wi/if_wavelan_ieee.h> 10870808Speter#include <dev/wi/if_wireg.h> 10946492Swpaul 11071161Speter#include "card_if.h" 11171161Speter 11246492Swpaul#if !defined(lint) 11346492Swpaulstatic const char rcsid[] = 11450477Speter "$FreeBSD: head/sys/dev/wi/if_wi.c 75149 2001-04-04 06:03:39Z imp $"; 11546492Swpaul#endif 11646492Swpaul 11746492Swpaul#ifdef foo 11847401Swpaulstatic u_int8_t wi_mcast_addr[6] = { 0x01, 0x60, 0x1D, 0x00, 0x01, 0x00 }; 11946492Swpaul#endif 12046492Swpaul 12153702Swpaulstatic void wi_intr __P((void *)); 12246492Swpaulstatic void wi_reset __P((struct wi_softc *)); 12346492Swpaulstatic int wi_ioctl __P((struct ifnet *, u_long, caddr_t)); 12446492Swpaulstatic void wi_init __P((void *)); 12546492Swpaulstatic void wi_start __P((struct ifnet *)); 12646492Swpaulstatic void wi_stop __P((struct wi_softc *)); 12746492Swpaulstatic void wi_watchdog __P((struct ifnet *)); 12846492Swpaulstatic void wi_rxeof __P((struct wi_softc *)); 12946492Swpaulstatic void wi_txeof __P((struct wi_softc *, int)); 13046492Swpaulstatic void wi_update_stats __P((struct wi_softc *)); 13146492Swpaulstatic void wi_setmulti __P((struct wi_softc *)); 13246492Swpaul 13346492Swpaulstatic int wi_cmd __P((struct wi_softc *, int, int)); 13446492Swpaulstatic int wi_read_record __P((struct wi_softc *, struct wi_ltv_gen *)); 13546492Swpaulstatic int wi_write_record __P((struct wi_softc *, struct wi_ltv_gen *)); 13646492Swpaulstatic int wi_read_data __P((struct wi_softc *, int, 13746492Swpaul int, caddr_t, int)); 13846492Swpaulstatic int wi_write_data __P((struct wi_softc *, int, 13946492Swpaul int, caddr_t, int)); 14046492Swpaulstatic int wi_seek __P((struct wi_softc *, int, int, int)); 14146492Swpaulstatic int wi_alloc_nicmem __P((struct wi_softc *, int, int *)); 14246492Swpaulstatic void wi_inquire __P((void *)); 14346492Swpaulstatic void wi_setdef __P((struct wi_softc *, struct wi_req *)); 14446492Swpaulstatic int wi_mgmt_xmit __P((struct wi_softc *, caddr_t, int)); 14546492Swpaul 14653702Swpaul#ifdef WICACHE 14753702Swpaulstatic 14853702Swpaulvoid wi_cache_store __P((struct wi_softc *, struct ether_header *, 14953702Swpaul struct mbuf *, unsigned short)); 15053702Swpaul#endif 15153702Swpaul 15274906Salfredstatic int wi_generic_attach __P((device_t)); 15371161Speterstatic int wi_pccard_match __P((device_t)); 15453702Swpaulstatic int wi_pccard_probe __P((device_t)); 15574906Salfredstatic int wi_pci_probe __P((device_t)); 15653702Swpaulstatic int wi_pccard_attach __P((device_t)); 15774906Salfredstatic int wi_pci_attach __P((device_t)); 15853702Swpaulstatic int wi_pccard_detach __P((device_t)); 15953702Swpaulstatic void wi_shutdown __P((device_t)); 16053702Swpaul 16174906Salfredstatic int wi_alloc __P((device_t, int)); 16253702Swpaulstatic void wi_free __P((device_t)); 16353702Swpaul 16453702Swpaulstatic device_method_t wi_pccard_methods[] = { 16553702Swpaul /* Device interface */ 16671161Speter DEVMETHOD(device_probe, pccard_compat_probe), 16771161Speter DEVMETHOD(device_attach, pccard_compat_attach), 16853702Swpaul DEVMETHOD(device_detach, wi_pccard_detach), 16953702Swpaul DEVMETHOD(device_shutdown, wi_shutdown), 17053702Swpaul 17171161Speter /* Card interface */ 17271161Speter DEVMETHOD(card_compat_match, wi_pccard_match), 17371161Speter DEVMETHOD(card_compat_probe, wi_pccard_probe), 17471161Speter DEVMETHOD(card_compat_attach, wi_pccard_attach), 17571161Speter 17653702Swpaul { 0, 0 } 17746492Swpaul}; 17846492Swpaul 17974906Salfredstatic device_method_t wi_pci_methods[] = { 18074906Salfred /* Device interface */ 18174906Salfred DEVMETHOD(device_probe, wi_pci_probe), 18274906Salfred DEVMETHOD(device_attach, wi_pci_attach), 18374906Salfred DEVMETHOD(device_detach, wi_pccard_detach), 18474906Salfred DEVMETHOD(device_shutdown, wi_shutdown), 18574906Salfred 18674906Salfred { 0, 0 } 18774906Salfred}; 18874906Salfred 18953702Swpaulstatic driver_t wi_pccard_driver = { 19046492Swpaul "wi", 19153702Swpaul wi_pccard_methods, 19253702Swpaul sizeof(struct wi_softc) 19346492Swpaul}; 19446492Swpaul 19574906Salfredstatic driver_t wi_pci_driver = { 19674906Salfred "wi", 19774906Salfred wi_pci_methods, 19874906Salfred sizeof(struct wi_softc) 19974906Salfred}; 20074906Salfred 20153702Swpaulstatic devclass_t wi_pccard_devclass; 20274906Salfredstatic devclass_t wi_pci_devclass; 20346492Swpaul 20453702SwpaulDRIVER_MODULE(if_wi, pccard, wi_pccard_driver, wi_pccard_devclass, 0, 0); 20574906SalfredDRIVER_MODULE(if_wi, pci, wi_pci_driver, wi_pci_devclass, 0, 0); 20653702Swpaul 20771161Speterstatic const struct pccard_product wi_pccard_products[] = { 20871161Speter { PCCARD_STR_LUCENT_WAVELAN_IEEE, PCCARD_VENDOR_LUCENT, 20971336Simp PCCARD_PRODUCT_LUCENT_WAVELAN_IEEE, 0, 21071336Simp PCCARD_CIS_LUCENT_WAVELAN_IEEE }, 21171161Speter}; 21271161Speter 21374906Salfredstatic char wi_device_desc[] = "WaveLAN/IEEE 802.11"; 21474906Salfred 21571161Speterstatic int wi_pccard_match(dev) 21671161Speter device_t dev; 21771161Speter{ 21871161Speter const struct pccard_product *pp; 21971161Speter 22071161Speter if ((pp = pccard_product_lookup(dev, wi_pccard_products, 22171161Speter sizeof(wi_pccard_products[0]), NULL)) != NULL) { 22271161Speter device_set_desc(dev, pp->pp_name); 22371161Speter return 0; 22471161Speter } 22571161Speter return ENXIO; 22671161Speter} 22771161Speter 22853702Swpaulstatic int wi_pccard_probe(dev) 22953702Swpaul device_t dev; 23046492Swpaul{ 23153702Swpaul struct wi_softc *sc; 23253702Swpaul int error; 23346492Swpaul 23453702Swpaul sc = device_get_softc(dev); 23546492Swpaul sc->wi_gone = 0; 23646492Swpaul 23774906Salfred error = wi_alloc(dev, 0); 23853702Swpaul if (error) 23953702Swpaul return (error); 24053702Swpaul 24153702Swpaul wi_free(dev); 24253702Swpaul 24346492Swpaul /* Make sure interrupts are disabled. */ 24446492Swpaul CSR_WRITE_2(sc, WI_INT_EN, 0); 24546492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); 24646492Swpaul 24753702Swpaul return (0); 24846492Swpaul} 24946492Swpaul 25074906Salfredstatic int 25174906Salfredwi_pci_probe(dev) 25274906Salfred device_t dev; 25374906Salfred{ 25474906Salfred struct wi_softc *sc; 25574906Salfred 25674906Salfred sc = device_get_softc(dev); 25774998Swpaul if ((pci_get_vendor(dev) == WI_PCI_VENDOR_EUMITCOM) && 25874906Salfred (pci_get_device(dev) == WI_PCI_DEVICE_PRISM2STA)) { 25974906Salfred sc->wi_prism2 = 1; 26074998Swpaul device_set_desc(dev, 26174998Swpaul "PRISM2STA PCI WaveLAN/IEEE 802.11"); 26274906Salfred return (0); 26374906Salfred } 26474906Salfred return(ENXIO); 26574906Salfred} 26674906Salfred 26753702Swpaulstatic int wi_pccard_detach(dev) 26853702Swpaul device_t dev; 26946492Swpaul{ 27046492Swpaul struct wi_softc *sc; 27146492Swpaul struct ifnet *ifp; 27246492Swpaul 27353702Swpaul sc = device_get_softc(dev); 27467092Swpaul WI_LOCK(sc); 27546492Swpaul ifp = &sc->arpcom.ac_if; 27646492Swpaul 27746492Swpaul if (sc->wi_gone) { 27853702Swpaul device_printf(dev, "already unloaded\n"); 27967092Swpaul WI_UNLOCK(sc); 28053702Swpaul return(ENODEV); 28146492Swpaul } 28246492Swpaul 28353702Swpaul wi_stop(sc); 28458274Srwatson 28563090Sarchie ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); 28654277Swpaul bus_teardown_intr(dev, sc->irq, sc->wi_intrhand); 28753702Swpaul wi_free(dev); 28846492Swpaul sc->wi_gone = 1; 28946492Swpaul 29067092Swpaul WI_UNLOCK(sc); 29167092Swpaul mtx_destroy(&sc->wi_mtx); 29246492Swpaul 29346492Swpaul return(0); 29446492Swpaul} 29546492Swpaul 29653702Swpaulstatic int wi_pccard_attach(device_t dev) 29746492Swpaul{ 29846492Swpaul struct wi_softc *sc; 29953702Swpaul int error; 30070073Swpaul u_int32_t flags; 30146492Swpaul 30253702Swpaul sc = device_get_softc(dev); 30346492Swpaul 30470073Swpaul /* 30570073Swpaul * XXX: quick hack to support Prism II chip. 30670073Swpaul * Currently, we need to set a flags in pccard.conf to specify 30770073Swpaul * which type chip is used. 30870073Swpaul * 30970073Swpaul * We need to replace this code in a future. 31070073Swpaul * It is better to use CIS than using a flag. 31170073Swpaul */ 31270073Swpaul flags = device_get_flags(dev); 31370073Swpaul#define WI_FLAGS_PRISM2 0x10000 31470073Swpaul if (flags & WI_FLAGS_PRISM2) { 31570073Swpaul sc->wi_prism2 = 1; 31670073Swpaul if (bootverbose) { 31770073Swpaul device_printf(dev, "found PrismII chip\n"); 31870073Swpaul } 31970073Swpaul } 32070073Swpaul else { 32170073Swpaul sc->wi_prism2 = 0; 32270073Swpaul if (bootverbose) { 32370073Swpaul device_printf(dev, "found Lucent chip\n"); 32470073Swpaul } 32570073Swpaul } 32670073Swpaul 32774906Salfred error = wi_alloc(dev, 0); 32853702Swpaul if (error) { 32953702Swpaul device_printf(dev, "wi_alloc() failed! (%d)\n", error); 33053702Swpaul return (error); 33153702Swpaul } 33274906Salfred return (wi_generic_attach(dev)); 33374906Salfred} 33453702Swpaul 33574906Salfredstatic int 33674906Salfredwi_pci_attach(device_t dev) 33774906Salfred{ 33874906Salfred struct wi_softc *sc; 33974906Salfred u_int32_t command, wanted; 34074906Salfred u_int16_t reg; 34174906Salfred int error; 34274906Salfred 34374906Salfred sc = device_get_softc(dev); 34474906Salfred 34574906Salfred command = pci_read_config(dev, PCIR_COMMAND, 4); 34674906Salfred wanted = PCIM_CMD_PORTEN|PCIM_CMD_MEMEN; 34774906Salfred command |= wanted; 34874906Salfred pci_write_config(dev, PCIR_COMMAND, command, 4); 34974906Salfred command = pci_read_config(dev, PCIR_COMMAND, 4); 35074906Salfred if ((command & wanted) != wanted) { 35174906Salfred device_printf(dev, "wi_pci_attach() failed to enable pci!\n"); 35274906Salfred return (ENXIO); 35374906Salfred } 35474906Salfred 35574906Salfred error = wi_alloc(dev, WI_PCI_IORES); 35674906Salfred if (error) 35774906Salfred return (error); 35874906Salfred 35974906Salfred device_set_desc(dev, wi_device_desc); 36074906Salfred 36174906Salfred /* Make sure interrupts are disabled. */ 36274906Salfred CSR_WRITE_2(sc, WI_INT_EN, 0); 36374906Salfred CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); 36474906Salfred 36574998Swpaul sc->mem_rid = WI_PCI_MEMRES; 36674906Salfred sc->mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mem_rid, 36774906Salfred 0, ~0, 1, RF_ACTIVE); 36874906Salfred if (sc->mem == NULL) { 36974906Salfred device_printf(dev, "couldn't allocate memory\n"); 37074906Salfred wi_free(dev); 37174906Salfred return (ENXIO); 37274906Salfred } 37374906Salfred sc->wi_bmemtag = rman_get_bustag(sc->mem); 37474906Salfred sc->wi_bmemhandle = rman_get_bushandle(sc->mem); 37574906Salfred 37674906Salfred /* 37774906Salfred * From Linux driver: 37874906Salfred * Write COR to enable PC card 37975149Simp * This is a subset of the protocol that the pccard bus code 38075149Simp * would do. 38174906Salfred */ 38274906Salfred CSM_WRITE_1(sc, WI_COR_OFFSET, WI_COR_VALUE); 38374906Salfred reg = CSM_READ_1(sc, WI_COR_OFFSET); 38474906Salfred 38574998Swpaul CSR_WRITE_2(sc, WI_HFA384X_SWSUPPORT0_OFF, WI_PRISM2STA_MAGIC); 38674998Swpaul reg = CSR_READ_2(sc, WI_HFA384X_SWSUPPORT0_OFF); 38774906Salfred if (reg != WI_PRISM2STA_MAGIC) { 38874906Salfred device_printf(dev, 38974998Swpaul "CSR_READ_2(WI_HFA384X_SWSUPPORT0_OFF) " 39074998Swpaul "wanted %d, got %d\n", WI_PRISM2STA_MAGIC, reg); 39174906Salfred wi_free(dev); 39274906Salfred return (ENXIO); 39374906Salfred } 39474906Salfred 39574906Salfred error = wi_generic_attach(dev); 39674906Salfred if (error != 0) 39774906Salfred return (error); 39874906Salfred 39974906Salfred return (0); 40074906Salfred} 40174906Salfred 40274906Salfredstatic int 40374906Salfredwi_generic_attach(device_t dev) 40474906Salfred{ 40574906Salfred struct wi_softc *sc; 40674906Salfred struct wi_ltv_macaddr mac; 40774906Salfred struct wi_ltv_gen gen; 40874906Salfred struct ifnet *ifp; 40974906Salfred int error; 41074906Salfred 41174906Salfred sc = device_get_softc(dev); 41274906Salfred ifp = &sc->arpcom.ac_if; 41374906Salfred 41453702Swpaul error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET, 41574998Swpaul wi_intr, sc, &sc->wi_intrhand); 41653702Swpaul 41753702Swpaul if (error) { 41853702Swpaul device_printf(dev, "bus_setup_intr() failed! (%d)\n", error); 41953702Swpaul wi_free(dev); 42053702Swpaul return (error); 42153702Swpaul } 42253702Swpaul 42371228Sbmilekic mtx_init(&sc->wi_mtx, device_get_nameunit(dev), MTX_DEF | MTX_RECURSE); 42467092Swpaul WI_LOCK(sc); 42567092Swpaul 42646492Swpaul /* Reset the NIC. */ 42746492Swpaul wi_reset(sc); 42846492Swpaul 42946492Swpaul /* Read the station address. */ 43046492Swpaul mac.wi_type = WI_RID_MAC_NODE; 43146492Swpaul mac.wi_len = 4; 43275149Simp if (error = wi_read_record(sc, (struct wi_ltv_gen *)&mac)) { 43375149Simp device_printf(dev, "mac read failed %d\n", error); 43475149Simp wi_free(dev); 43575149Simp return (error); 43675149Simp } 43746492Swpaul bcopy((char *)&mac.wi_mac_addr, 43846492Swpaul (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 43946492Swpaul 44053702Swpaul device_printf(dev, "Ethernet address: %6D\n", 44146492Swpaul sc->arpcom.ac_enaddr, ":"); 44246492Swpaul 44346492Swpaul ifp->if_softc = sc; 44446492Swpaul ifp->if_unit = sc->wi_unit; 44546492Swpaul ifp->if_name = "wi"; 44646492Swpaul ifp->if_mtu = ETHERMTU; 44746492Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 44846492Swpaul ifp->if_ioctl = wi_ioctl; 44946492Swpaul ifp->if_output = ether_output; 45046492Swpaul ifp->if_start = wi_start; 45146492Swpaul ifp->if_watchdog = wi_watchdog; 45246492Swpaul ifp->if_init = wi_init; 45346492Swpaul ifp->if_baudrate = 10000000; 45446492Swpaul ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 45546492Swpaul 45646492Swpaul bzero(sc->wi_node_name, sizeof(sc->wi_node_name)); 45746492Swpaul bcopy(WI_DEFAULT_NODENAME, sc->wi_node_name, 45846492Swpaul sizeof(WI_DEFAULT_NODENAME) - 1); 45946492Swpaul 46046492Swpaul bzero(sc->wi_net_name, sizeof(sc->wi_net_name)); 46146492Swpaul bcopy(WI_DEFAULT_NETNAME, sc->wi_net_name, 46246492Swpaul sizeof(WI_DEFAULT_NETNAME) - 1); 46346492Swpaul 46446492Swpaul bzero(sc->wi_ibss_name, sizeof(sc->wi_ibss_name)); 46546492Swpaul bcopy(WI_DEFAULT_IBSS, sc->wi_ibss_name, 46646492Swpaul sizeof(WI_DEFAULT_IBSS) - 1); 46746492Swpaul 46846492Swpaul sc->wi_portnum = WI_DEFAULT_PORT; 46974139Sassar sc->wi_ptype = WI_PORTTYPE_BSS; 47046492Swpaul sc->wi_ap_density = WI_DEFAULT_AP_DENSITY; 47146492Swpaul sc->wi_rts_thresh = WI_DEFAULT_RTS_THRESH; 47246492Swpaul sc->wi_tx_rate = WI_DEFAULT_TX_RATE; 47346492Swpaul sc->wi_max_data_len = WI_DEFAULT_DATALEN; 47446492Swpaul sc->wi_create_ibss = WI_DEFAULT_CREATE_IBSS; 47546611Swpaul sc->wi_pm_enabled = WI_DEFAULT_PM_ENABLED; 47646611Swpaul sc->wi_max_sleep = WI_DEFAULT_MAX_SLEEP; 47746492Swpaul 47846563Swpaul /* 47946563Swpaul * Read the default channel from the NIC. This may vary 48046563Swpaul * depending on the country where the NIC was purchased, so 48146563Swpaul * we can't hard-code a default and expect it to work for 48246563Swpaul * everyone. 48346563Swpaul */ 48446563Swpaul gen.wi_type = WI_RID_OWN_CHNL; 48546563Swpaul gen.wi_len = 2; 48646563Swpaul wi_read_record(sc, &gen); 48746563Swpaul sc->wi_channel = gen.wi_val; 48846563Swpaul 48956965Swpaul /* 49056965Swpaul * Find out if we support WEP on this card. 49156965Swpaul */ 49256965Swpaul gen.wi_type = WI_RID_WEP_AVAIL; 49356965Swpaul gen.wi_len = 2; 49456965Swpaul wi_read_record(sc, &gen); 49556965Swpaul sc->wi_has_wep = gen.wi_val; 49656965Swpaul 49770073Swpaul if (bootverbose) { 49870073Swpaul device_printf(sc->dev, 49970073Swpaul __FUNCTION__ ":wi_has_wep = %d\n", 50070073Swpaul sc->wi_has_wep); 50170073Swpaul } 50270073Swpaul 50346492Swpaul bzero((char *)&sc->wi_stats, sizeof(sc->wi_stats)); 50446492Swpaul 50546492Swpaul wi_init(sc); 50646492Swpaul wi_stop(sc); 50746492Swpaul 50846492Swpaul /* 50963090Sarchie * Call MI attach routine. 51046492Swpaul */ 51163090Sarchie ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 51253702Swpaul callout_handle_init(&sc->wi_stat_ch); 51367092Swpaul WI_UNLOCK(sc); 51446492Swpaul 51546492Swpaul return(0); 51646492Swpaul} 51746492Swpaul 51846492Swpaulstatic void wi_rxeof(sc) 51946492Swpaul struct wi_softc *sc; 52046492Swpaul{ 52146492Swpaul struct ifnet *ifp; 52246492Swpaul struct ether_header *eh; 52346492Swpaul struct wi_frame rx_frame; 52446492Swpaul struct mbuf *m; 52546492Swpaul int id; 52646492Swpaul 52746492Swpaul ifp = &sc->arpcom.ac_if; 52846492Swpaul 52946492Swpaul id = CSR_READ_2(sc, WI_RX_FID); 53046492Swpaul 53146492Swpaul /* First read in the frame header */ 53246492Swpaul if (wi_read_data(sc, id, 0, (caddr_t)&rx_frame, sizeof(rx_frame))) { 53346492Swpaul ifp->if_ierrors++; 53446492Swpaul return; 53546492Swpaul } 53646492Swpaul 53746492Swpaul if (rx_frame.wi_status & WI_STAT_ERRSTAT) { 53846492Swpaul ifp->if_ierrors++; 53946492Swpaul return; 54046492Swpaul } 54146492Swpaul 54246492Swpaul MGETHDR(m, M_DONTWAIT, MT_DATA); 54346492Swpaul if (m == NULL) { 54446492Swpaul ifp->if_ierrors++; 54546492Swpaul return; 54646492Swpaul } 54746492Swpaul MCLGET(m, M_DONTWAIT); 54846492Swpaul if (!(m->m_flags & M_EXT)) { 54946492Swpaul m_freem(m); 55046492Swpaul ifp->if_ierrors++; 55146492Swpaul return; 55246492Swpaul } 55346492Swpaul 55446492Swpaul eh = mtod(m, struct ether_header *); 55546492Swpaul m->m_pkthdr.rcvif = ifp; 55646492Swpaul 55746492Swpaul if (rx_frame.wi_status == WI_STAT_1042 || 55846492Swpaul rx_frame.wi_status == WI_STAT_TUNNEL || 55946492Swpaul rx_frame.wi_status == WI_STAT_WMP_MSG) { 56048553Swpaul if((rx_frame.wi_dat_len + WI_SNAPHDR_LEN) > MCLBYTES) { 56153702Swpaul device_printf(sc->dev, "oversized packet received " 56253702Swpaul "(wi_dat_len=%d, wi_status=0x%x)\n", 56348553Swpaul rx_frame.wi_dat_len, rx_frame.wi_status); 56448553Swpaul m_freem(m); 56548553Swpaul ifp->if_ierrors++; 56648553Swpaul return; 56748553Swpaul } 56846492Swpaul m->m_pkthdr.len = m->m_len = 56946492Swpaul rx_frame.wi_dat_len + WI_SNAPHDR_LEN; 57046492Swpaul 57146492Swpaul bcopy((char *)&rx_frame.wi_addr1, 57246492Swpaul (char *)&eh->ether_dhost, ETHER_ADDR_LEN); 57359328Swpaul if (sc->wi_ptype == WI_PORTTYPE_ADHOC) { 57459328Swpaul bcopy((char *)&rx_frame.wi_addr2, 57559328Swpaul (char *)&eh->ether_shost, ETHER_ADDR_LEN); 57659328Swpaul } else { 57759328Swpaul bcopy((char *)&rx_frame.wi_addr3, 57859328Swpaul (char *)&eh->ether_shost, ETHER_ADDR_LEN); 57959328Swpaul } 58046492Swpaul bcopy((char *)&rx_frame.wi_type, 58146492Swpaul (char *)&eh->ether_type, sizeof(u_int16_t)); 58246492Swpaul 58346492Swpaul if (wi_read_data(sc, id, WI_802_11_OFFSET, 58446492Swpaul mtod(m, caddr_t) + sizeof(struct ether_header), 58546492Swpaul m->m_len + 2)) { 58646492Swpaul m_freem(m); 58746492Swpaul ifp->if_ierrors++; 58846492Swpaul return; 58946492Swpaul } 59046492Swpaul } else { 59148553Swpaul if((rx_frame.wi_dat_len + 59248553Swpaul sizeof(struct ether_header)) > MCLBYTES) { 59353702Swpaul device_printf(sc->dev, "oversized packet received " 59453702Swpaul "(wi_dat_len=%d, wi_status=0x%x)\n", 59548553Swpaul rx_frame.wi_dat_len, rx_frame.wi_status); 59648553Swpaul m_freem(m); 59748553Swpaul ifp->if_ierrors++; 59848553Swpaul return; 59948553Swpaul } 60046492Swpaul m->m_pkthdr.len = m->m_len = 60146492Swpaul rx_frame.wi_dat_len + sizeof(struct ether_header); 60246492Swpaul 60346492Swpaul if (wi_read_data(sc, id, WI_802_3_OFFSET, 60446492Swpaul mtod(m, caddr_t), m->m_len + 2)) { 60546492Swpaul m_freem(m); 60646492Swpaul ifp->if_ierrors++; 60746492Swpaul return; 60846492Swpaul } 60946492Swpaul } 61046492Swpaul 61146492Swpaul ifp->if_ipackets++; 61246492Swpaul 61346492Swpaul /* Receive packet. */ 61446492Swpaul m_adj(m, sizeof(struct ether_header)); 61553702Swpaul#ifdef WICACHE 61653702Swpaul wi_cache_store(sc, eh, m, rx_frame.wi_q_info); 61753702Swpaul#endif 61846492Swpaul ether_input(ifp, eh, m); 61946492Swpaul} 62046492Swpaul 62146492Swpaulstatic void wi_txeof(sc, status) 62246492Swpaul struct wi_softc *sc; 62346492Swpaul int status; 62446492Swpaul{ 62546492Swpaul struct ifnet *ifp; 62646492Swpaul 62746492Swpaul ifp = &sc->arpcom.ac_if; 62846492Swpaul 62946492Swpaul ifp->if_timer = 0; 63046492Swpaul ifp->if_flags &= ~IFF_OACTIVE; 63146492Swpaul 63246492Swpaul if (status & WI_EV_TX_EXC) 63346492Swpaul ifp->if_oerrors++; 63446492Swpaul else 63546492Swpaul ifp->if_opackets++; 63646492Swpaul 63746492Swpaul return; 63846492Swpaul} 63946492Swpaul 64046492Swpaulvoid wi_inquire(xsc) 64146492Swpaul void *xsc; 64246492Swpaul{ 64346492Swpaul struct wi_softc *sc; 64446492Swpaul struct ifnet *ifp; 64546492Swpaul 64646492Swpaul sc = xsc; 64746492Swpaul ifp = &sc->arpcom.ac_if; 64846492Swpaul 64946492Swpaul sc->wi_stat_ch = timeout(wi_inquire, sc, hz * 60); 65046492Swpaul 65146492Swpaul /* Don't do this while we're transmitting */ 65246492Swpaul if (ifp->if_flags & IFF_OACTIVE) 65346492Swpaul return; 65446492Swpaul 65546492Swpaul wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_COUNTERS); 65646492Swpaul 65746492Swpaul return; 65846492Swpaul} 65946492Swpaul 66046492Swpaulvoid wi_update_stats(sc) 66146492Swpaul struct wi_softc *sc; 66246492Swpaul{ 66346492Swpaul struct wi_ltv_gen gen; 66446492Swpaul u_int16_t id; 66546492Swpaul struct ifnet *ifp; 66646492Swpaul u_int32_t *ptr; 66746492Swpaul int i; 66846492Swpaul u_int16_t t; 66946492Swpaul 67046492Swpaul ifp = &sc->arpcom.ac_if; 67146492Swpaul 67246492Swpaul id = CSR_READ_2(sc, WI_INFO_FID); 67346492Swpaul 67446492Swpaul wi_read_data(sc, id, 0, (char *)&gen, 4); 67546492Swpaul 67646492Swpaul if (gen.wi_type != WI_INFO_COUNTERS || 67746492Swpaul gen.wi_len > (sizeof(sc->wi_stats) / 4) + 1) 67846492Swpaul return; 67946492Swpaul 68046492Swpaul ptr = (u_int32_t *)&sc->wi_stats; 68146492Swpaul 68246492Swpaul for (i = 0; i < gen.wi_len - 1; i++) { 68346492Swpaul t = CSR_READ_2(sc, WI_DATA1); 68446492Swpaul#ifdef WI_HERMES_STATS_WAR 68546492Swpaul if (t > 0xF000) 68646492Swpaul t = ~t & 0xFFFF; 68746492Swpaul#endif 68846492Swpaul ptr[i] += t; 68946492Swpaul } 69046492Swpaul 69146492Swpaul ifp->if_collisions = sc->wi_stats.wi_tx_single_retries + 69246492Swpaul sc->wi_stats.wi_tx_multi_retries + 69346492Swpaul sc->wi_stats.wi_tx_retry_limit; 69446492Swpaul 69546492Swpaul return; 69646492Swpaul} 69746492Swpaul 69853702Swpaulstatic void wi_intr(xsc) 69953702Swpaul void *xsc; 70046492Swpaul{ 70153702Swpaul struct wi_softc *sc = xsc; 70246492Swpaul struct ifnet *ifp; 70346492Swpaul u_int16_t status; 70446492Swpaul 70567092Swpaul WI_LOCK(sc); 70667092Swpaul 70746492Swpaul ifp = &sc->arpcom.ac_if; 70846492Swpaul 70946492Swpaul if (!(ifp->if_flags & IFF_UP)) { 71046492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); 71146492Swpaul CSR_WRITE_2(sc, WI_INT_EN, 0); 71267092Swpaul WI_UNLOCK(sc); 71346492Swpaul return; 71446492Swpaul } 71546492Swpaul 71646492Swpaul /* Disable interrupts. */ 71746492Swpaul CSR_WRITE_2(sc, WI_INT_EN, 0); 71846492Swpaul 71946492Swpaul status = CSR_READ_2(sc, WI_EVENT_STAT); 72046492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, ~WI_INTRS); 72146492Swpaul 72246492Swpaul if (status & WI_EV_RX) { 72346492Swpaul wi_rxeof(sc); 72446492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX); 72546492Swpaul } 72646492Swpaul 72746492Swpaul if (status & WI_EV_TX) { 72846492Swpaul wi_txeof(sc, status); 72946492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX); 73046492Swpaul } 73146492Swpaul 73246492Swpaul if (status & WI_EV_ALLOC) { 73346492Swpaul int id; 73446492Swpaul id = CSR_READ_2(sc, WI_ALLOC_FID); 73546492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC); 73646492Swpaul if (id == sc->wi_tx_data_id) 73746492Swpaul wi_txeof(sc, status); 73846492Swpaul } 73946492Swpaul 74046492Swpaul if (status & WI_EV_INFO) { 74146492Swpaul wi_update_stats(sc); 74246492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO); 74346492Swpaul } 74446492Swpaul 74546492Swpaul if (status & WI_EV_TX_EXC) { 74646492Swpaul wi_txeof(sc, status); 74746492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX_EXC); 74846492Swpaul } 74946492Swpaul 75046492Swpaul if (status & WI_EV_INFO_DROP) { 75146492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO_DROP); 75246492Swpaul } 75346492Swpaul 75446492Swpaul /* Re-enable interrupts. */ 75546492Swpaul CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS); 75646492Swpaul 75746492Swpaul if (ifp->if_snd.ifq_head != NULL) 75846492Swpaul wi_start(ifp); 75946492Swpaul 76067092Swpaul WI_UNLOCK(sc); 76167092Swpaul 76246492Swpaul return; 76346492Swpaul} 76446492Swpaul 76546492Swpaulstatic int wi_cmd(sc, cmd, val) 76646492Swpaul struct wi_softc *sc; 76746492Swpaul int cmd; 76846492Swpaul int val; 76946492Swpaul{ 77046492Swpaul int i, s = 0; 77146492Swpaul 77270073Swpaul /* wait for the busy bit to clear */ 77370073Swpaul for (i = 0; i < WI_TIMEOUT; i++) { 77470073Swpaul if (!(CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY)) { 77570073Swpaul break; 77670073Swpaul } 77770073Swpaul DELAY(10*1000); /* 10 m sec */ 77870073Swpaul } 77970073Swpaul 78070073Swpaul if (i == WI_TIMEOUT) { 78170073Swpaul return(ETIMEDOUT); 78270073Swpaul } 78370073Swpaul 78446492Swpaul CSR_WRITE_2(sc, WI_PARAM0, val); 78570073Swpaul CSR_WRITE_2(sc, WI_PARAM1, 0); 78670073Swpaul CSR_WRITE_2(sc, WI_PARAM2, 0); 78746492Swpaul CSR_WRITE_2(sc, WI_COMMAND, cmd); 78846492Swpaul 78946492Swpaul for (i = 0; i < WI_TIMEOUT; i++) { 79046492Swpaul /* 79146492Swpaul * Wait for 'command complete' bit to be 79246492Swpaul * set in the event status register. 79346492Swpaul */ 79446492Swpaul s = CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_CMD; 79546492Swpaul if (s) { 79646492Swpaul /* Ack the event and read result code. */ 79746492Swpaul s = CSR_READ_2(sc, WI_STATUS); 79846492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD); 79946492Swpaul#ifdef foo 80046492Swpaul if ((s & WI_CMD_CODE_MASK) != (cmd & WI_CMD_CODE_MASK)) 80146492Swpaul return(EIO); 80246492Swpaul#endif 80346492Swpaul if (s & WI_STAT_CMD_RESULT) 80446492Swpaul return(EIO); 80546492Swpaul break; 80646492Swpaul } 80746492Swpaul } 80846492Swpaul 80946492Swpaul if (i == WI_TIMEOUT) 81046492Swpaul return(ETIMEDOUT); 81146492Swpaul 81246492Swpaul return(0); 81346492Swpaul} 81446492Swpaul 81546492Swpaulstatic void wi_reset(sc) 81646492Swpaul struct wi_softc *sc; 81746492Swpaul{ 81875149Simp int i, err; 81975149Simp 82075149Simp for (i = 0; i < 5; i++) { 82175149Simp if (wi_cmd(sc, WI_CMD_INI, 0) == 0) 82275149Simp break; 82375149Simp DELAY(100000); 82475149Simp } 82575149Simp if (i == 5) 82653702Swpaul device_printf(sc->dev, "init failed\n"); 82746492Swpaul CSR_WRITE_2(sc, WI_INT_EN, 0); 82846492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); 82946492Swpaul 83046492Swpaul /* Calibrate timer. */ 83146492Swpaul WI_SETVAL(WI_RID_TICK_TIME, 8); 83270073Swpaul 83346492Swpaul return; 83446492Swpaul} 83546492Swpaul 83646492Swpaul/* 83746492Swpaul * Read an LTV record from the NIC. 83846492Swpaul */ 83946492Swpaulstatic int wi_read_record(sc, ltv) 84046492Swpaul struct wi_softc *sc; 84146492Swpaul struct wi_ltv_gen *ltv; 84246492Swpaul{ 84346492Swpaul u_int16_t *ptr; 84446492Swpaul int i, len, code; 84570073Swpaul struct wi_ltv_gen *oltv, p2ltv; 84646492Swpaul 84770073Swpaul oltv = ltv; 84870073Swpaul if (sc->wi_prism2) { 84970073Swpaul switch (ltv->wi_type) { 85070073Swpaul case WI_RID_ENCRYPTION: 85170073Swpaul p2ltv.wi_type = WI_RID_P2_ENCRYPTION; 85270073Swpaul p2ltv.wi_len = 2; 85370073Swpaul ltv = &p2ltv; 85470073Swpaul break; 85570073Swpaul case WI_RID_TX_CRYPT_KEY: 85670073Swpaul p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY; 85770073Swpaul p2ltv.wi_len = 2; 85870073Swpaul ltv = &p2ltv; 85970073Swpaul break; 86070073Swpaul } 86170073Swpaul } 86270073Swpaul 86346492Swpaul /* Tell the NIC to enter record read mode. */ 86446492Swpaul if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_READ, ltv->wi_type)) 86546492Swpaul return(EIO); 86646492Swpaul 86747789Swpaul /* Seek to the record. */ 86847789Swpaul if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1)) 86947789Swpaul return(EIO); 87046492Swpaul 87146492Swpaul /* 87246492Swpaul * Read the length and record type and make sure they 87346492Swpaul * match what we expect (this verifies that we have enough 87447401Swpaul * room to hold all of the returned data). 87546492Swpaul */ 87646492Swpaul len = CSR_READ_2(sc, WI_DATA1); 87746492Swpaul if (len > ltv->wi_len) 87846492Swpaul return(ENOSPC); 87946492Swpaul code = CSR_READ_2(sc, WI_DATA1); 88046492Swpaul if (code != ltv->wi_type) 88146492Swpaul return(EIO); 88246492Swpaul 88346492Swpaul ltv->wi_len = len; 88446492Swpaul ltv->wi_type = code; 88546492Swpaul 88646492Swpaul /* Now read the data. */ 88746492Swpaul ptr = <v->wi_val; 88846492Swpaul for (i = 0; i < ltv->wi_len - 1; i++) 88946492Swpaul ptr[i] = CSR_READ_2(sc, WI_DATA1); 89046492Swpaul 89170073Swpaul if (sc->wi_prism2) { 89270073Swpaul switch (oltv->wi_type) { 89370073Swpaul case WI_RID_TX_RATE: 89470073Swpaul case WI_RID_CUR_TX_RATE: 89570073Swpaul switch (ltv->wi_val) { 89670073Swpaul case 1: oltv->wi_val = 1; break; 89770073Swpaul case 2: oltv->wi_val = 2; break; 89870073Swpaul case 3: oltv->wi_val = 6; break; 89970073Swpaul case 4: oltv->wi_val = 5; break; 90070073Swpaul case 7: oltv->wi_val = 7; break; 90170073Swpaul case 8: oltv->wi_val = 11; break; 90270073Swpaul case 15: oltv->wi_val = 3; break; 90370073Swpaul default: oltv->wi_val = 0x100 + ltv->wi_val; break; 90470073Swpaul } 90570073Swpaul break; 90670073Swpaul case WI_RID_ENCRYPTION: 90770073Swpaul oltv->wi_len = 2; 90870073Swpaul if (ltv->wi_val & 0x01) 90970073Swpaul oltv->wi_val = 1; 91070073Swpaul else 91170073Swpaul oltv->wi_val = 0; 91270073Swpaul break; 91370073Swpaul case WI_RID_TX_CRYPT_KEY: 91470073Swpaul oltv->wi_len = 2; 91570073Swpaul oltv->wi_val = ltv->wi_val; 91670073Swpaul break; 91770073Swpaul } 91870073Swpaul } 91970073Swpaul 92046492Swpaul return(0); 92146492Swpaul} 92246492Swpaul 92346492Swpaul/* 92446492Swpaul * Same as read, except we inject data instead of reading it. 92546492Swpaul */ 92646492Swpaulstatic int wi_write_record(sc, ltv) 92746492Swpaul struct wi_softc *sc; 92846492Swpaul struct wi_ltv_gen *ltv; 92946492Swpaul{ 93046492Swpaul u_int16_t *ptr; 93146492Swpaul int i; 93270073Swpaul struct wi_ltv_gen p2ltv; 93346492Swpaul 93470073Swpaul if (sc->wi_prism2) { 93570073Swpaul switch (ltv->wi_type) { 93670073Swpaul case WI_RID_TX_RATE: 93770073Swpaul p2ltv.wi_type = WI_RID_TX_RATE; 93870073Swpaul p2ltv.wi_len = 2; 93970073Swpaul switch (ltv->wi_val) { 94070073Swpaul case 1: p2ltv.wi_val = 1; break; 94170073Swpaul case 2: p2ltv.wi_val = 2; break; 94270073Swpaul case 3: p2ltv.wi_val = 15; break; 94370073Swpaul case 5: p2ltv.wi_val = 4; break; 94470073Swpaul case 6: p2ltv.wi_val = 3; break; 94570073Swpaul case 7: p2ltv.wi_val = 7; break; 94670073Swpaul case 11: p2ltv.wi_val = 8; break; 94770073Swpaul default: return EINVAL; 94870073Swpaul } 94970073Swpaul ltv = &p2ltv; 95070073Swpaul break; 95170073Swpaul case WI_RID_ENCRYPTION: 95270073Swpaul p2ltv.wi_type = WI_RID_P2_ENCRYPTION; 95370073Swpaul p2ltv.wi_len = 2; 95470073Swpaul if (ltv->wi_val) 95570073Swpaul p2ltv.wi_val = 0x03; 95670073Swpaul else 95770073Swpaul p2ltv.wi_val = 0x90; 95870073Swpaul ltv = &p2ltv; 95970073Swpaul break; 96070073Swpaul case WI_RID_TX_CRYPT_KEY: 96170073Swpaul p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY; 96270073Swpaul p2ltv.wi_len = 2; 96370073Swpaul p2ltv.wi_val = ltv->wi_val; 96470073Swpaul ltv = &p2ltv; 96570073Swpaul break; 96670073Swpaul case WI_RID_DEFLT_CRYPT_KEYS: 96770073Swpaul { 96870073Swpaul int error; 96970073Swpaul struct wi_ltv_str ws; 97074998Swpaul struct wi_ltv_keys *wk = 97174998Swpaul (struct wi_ltv_keys *)ltv; 97274998Swpaul 97370073Swpaul for (i = 0; i < 4; i++) { 97470073Swpaul ws.wi_len = 4; 97570073Swpaul ws.wi_type = WI_RID_P2_CRYPT_KEY0 + i; 97674998Swpaul memcpy(ws.wi_str, 97774998Swpaul &wk->wi_keys[i].wi_keydat, 5); 97870073Swpaul ws.wi_str[5] = '\0'; 97970073Swpaul error = wi_write_record(sc, 98070073Swpaul (struct wi_ltv_gen *)&ws); 98170073Swpaul if (error) 98270073Swpaul return error; 98370073Swpaul } 98470073Swpaul return 0; 98570073Swpaul } 98670073Swpaul } 98770073Swpaul } 98870073Swpaul 98947789Swpaul if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1)) 99047789Swpaul return(EIO); 99146492Swpaul 99246492Swpaul CSR_WRITE_2(sc, WI_DATA1, ltv->wi_len); 99346492Swpaul CSR_WRITE_2(sc, WI_DATA1, ltv->wi_type); 99446492Swpaul 99546492Swpaul ptr = <v->wi_val; 99646492Swpaul for (i = 0; i < ltv->wi_len - 1; i++) 99746492Swpaul CSR_WRITE_2(sc, WI_DATA1, ptr[i]); 99846492Swpaul 99946492Swpaul if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_WRITE, ltv->wi_type)) 100046492Swpaul return(EIO); 100146492Swpaul 100246492Swpaul return(0); 100346492Swpaul} 100446492Swpaul 100546492Swpaulstatic int wi_seek(sc, id, off, chan) 100646492Swpaul struct wi_softc *sc; 100746492Swpaul int id, off, chan; 100846492Swpaul{ 100946492Swpaul int i; 101046492Swpaul int selreg, offreg; 101146492Swpaul 101246492Swpaul switch (chan) { 101346492Swpaul case WI_BAP0: 101446492Swpaul selreg = WI_SEL0; 101546492Swpaul offreg = WI_OFF0; 101646492Swpaul break; 101746492Swpaul case WI_BAP1: 101846492Swpaul selreg = WI_SEL1; 101946492Swpaul offreg = WI_OFF1; 102046492Swpaul break; 102146492Swpaul default: 102253702Swpaul device_printf(sc->dev, "invalid data path: %x\n", chan); 102346492Swpaul return(EIO); 102446492Swpaul } 102546492Swpaul 102646492Swpaul CSR_WRITE_2(sc, selreg, id); 102746492Swpaul CSR_WRITE_2(sc, offreg, off); 102846492Swpaul 102946492Swpaul for (i = 0; i < WI_TIMEOUT; i++) { 103046492Swpaul if (!(CSR_READ_2(sc, offreg) & (WI_OFF_BUSY|WI_OFF_ERR))) 103146492Swpaul break; 103246492Swpaul } 103346492Swpaul 103446492Swpaul if (i == WI_TIMEOUT) 103546492Swpaul return(ETIMEDOUT); 103646492Swpaul 103746492Swpaul return(0); 103846492Swpaul} 103946492Swpaul 104046492Swpaulstatic int wi_read_data(sc, id, off, buf, len) 104146492Swpaul struct wi_softc *sc; 104246492Swpaul int id, off; 104346492Swpaul caddr_t buf; 104446492Swpaul int len; 104546492Swpaul{ 104646492Swpaul int i; 104746492Swpaul u_int16_t *ptr; 104846492Swpaul 104946492Swpaul if (wi_seek(sc, id, off, WI_BAP1)) 105046492Swpaul return(EIO); 105146492Swpaul 105246492Swpaul ptr = (u_int16_t *)buf; 105346492Swpaul for (i = 0; i < len / 2; i++) 105446492Swpaul ptr[i] = CSR_READ_2(sc, WI_DATA1); 105546492Swpaul 105646492Swpaul return(0); 105746492Swpaul} 105846492Swpaul 105946492Swpaul/* 106046492Swpaul * According to the comments in the HCF Light code, there is a bug in 106146492Swpaul * the Hermes (or possibly in certain Hermes firmware revisions) where 106246492Swpaul * the chip's internal autoincrement counter gets thrown off during 106346492Swpaul * data writes: the autoincrement is missed, causing one data word to 106446492Swpaul * be overwritten and subsequent words to be written to the wrong memory 106546492Swpaul * locations. The end result is that we could end up transmitting bogus 106646492Swpaul * frames without realizing it. The workaround for this is to write a 106746492Swpaul * couple of extra guard words after the end of the transfer, then 106846492Swpaul * attempt to read then back. If we fail to locate the guard words where 106946492Swpaul * we expect them, we preform the transfer over again. 107046492Swpaul */ 107146492Swpaulstatic int wi_write_data(sc, id, off, buf, len) 107246492Swpaul struct wi_softc *sc; 107346492Swpaul int id, off; 107446492Swpaul caddr_t buf; 107546492Swpaul int len; 107646492Swpaul{ 107746492Swpaul int i; 107846492Swpaul u_int16_t *ptr; 107974838Salfred#ifdef WI_HERMES_AUTOINC_WAR 108074838Salfred int retries; 108146492Swpaul 108274838Salfred retries = WI_TIMEOUT >> 4; 108346492Swpaulagain: 108446492Swpaul#endif 108546492Swpaul 108646492Swpaul if (wi_seek(sc, id, off, WI_BAP0)) 108746492Swpaul return(EIO); 108846492Swpaul 108946492Swpaul ptr = (u_int16_t *)buf; 109046492Swpaul for (i = 0; i < (len / 2); i++) 109146492Swpaul CSR_WRITE_2(sc, WI_DATA0, ptr[i]); 109246492Swpaul 109346492Swpaul#ifdef WI_HERMES_AUTOINC_WAR 109446492Swpaul CSR_WRITE_2(sc, WI_DATA0, 0x1234); 109546492Swpaul CSR_WRITE_2(sc, WI_DATA0, 0x5678); 109646492Swpaul 109746492Swpaul if (wi_seek(sc, id, off + len, WI_BAP0)) 109846492Swpaul return(EIO); 109946492Swpaul 110046492Swpaul if (CSR_READ_2(sc, WI_DATA0) != 0x1234 || 110174998Swpaul CSR_READ_2(sc, WI_DATA0) != 0x5678) { 110274838Salfred if (--retries >= 0) 110374838Salfred goto again; 110474838Salfred device_printf(sc->dev, "wi_write_data device timeout\n"); 110574838Salfred return (EIO); 110674838Salfred } 110746492Swpaul#endif 110846492Swpaul 110946492Swpaul return(0); 111046492Swpaul} 111146492Swpaul 111246492Swpaul/* 111346492Swpaul * Allocate a region of memory inside the NIC and zero 111446492Swpaul * it out. 111546492Swpaul */ 111646492Swpaulstatic int wi_alloc_nicmem(sc, len, id) 111746492Swpaul struct wi_softc *sc; 111846492Swpaul int len; 111946492Swpaul int *id; 112046492Swpaul{ 112146492Swpaul int i; 112246492Swpaul 112346492Swpaul if (wi_cmd(sc, WI_CMD_ALLOC_MEM, len)) { 112474998Swpaul device_printf(sc->dev, 112574998Swpaul "failed to allocate %d bytes on NIC\n", len); 112646492Swpaul return(ENOMEM); 112746492Swpaul } 112846492Swpaul 112946492Swpaul for (i = 0; i < WI_TIMEOUT; i++) { 113046492Swpaul if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_ALLOC) 113146492Swpaul break; 113246492Swpaul } 113346492Swpaul 113446492Swpaul if (i == WI_TIMEOUT) 113546492Swpaul return(ETIMEDOUT); 113646492Swpaul 113746492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC); 113846492Swpaul *id = CSR_READ_2(sc, WI_ALLOC_FID); 113946492Swpaul 114047789Swpaul if (wi_seek(sc, *id, 0, WI_BAP0)) 114147789Swpaul return(EIO); 114246492Swpaul 114346492Swpaul for (i = 0; i < len / 2; i++) 114446492Swpaul CSR_WRITE_2(sc, WI_DATA0, 0); 114546492Swpaul 114646492Swpaul return(0); 114746492Swpaul} 114846492Swpaul 114946492Swpaulstatic void wi_setmulti(sc) 115046492Swpaul struct wi_softc *sc; 115146492Swpaul{ 115246492Swpaul struct ifnet *ifp; 115346492Swpaul int i = 0; 115446492Swpaul struct ifmultiaddr *ifma; 115546492Swpaul struct wi_ltv_mcast mcast; 115646492Swpaul 115746492Swpaul ifp = &sc->arpcom.ac_if; 115846492Swpaul 115946492Swpaul bzero((char *)&mcast, sizeof(mcast)); 116046492Swpaul 116146492Swpaul mcast.wi_type = WI_RID_MCAST; 116246492Swpaul mcast.wi_len = (3 * 16) + 1; 116346492Swpaul 116446492Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 116546492Swpaul wi_write_record(sc, (struct wi_ltv_gen *)&mcast); 116646492Swpaul return; 116746492Swpaul } 116846492Swpaul 116972084Sphk TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 117046492Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 117146492Swpaul continue; 117246492Swpaul if (i < 16) { 117346492Swpaul bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 117446492Swpaul (char *)&mcast.wi_mcast[i], ETHER_ADDR_LEN); 117546492Swpaul i++; 117646492Swpaul } else { 117746492Swpaul bzero((char *)&mcast, sizeof(mcast)); 117846492Swpaul break; 117946492Swpaul } 118046492Swpaul } 118146492Swpaul 118246492Swpaul mcast.wi_len = (i * 3) + 1; 118346492Swpaul wi_write_record(sc, (struct wi_ltv_gen *)&mcast); 118446492Swpaul 118546492Swpaul return; 118646492Swpaul} 118746492Swpaul 118846492Swpaulstatic void wi_setdef(sc, wreq) 118946492Swpaul struct wi_softc *sc; 119046492Swpaul struct wi_req *wreq; 119146492Swpaul{ 119246492Swpaul struct sockaddr_dl *sdl; 119346492Swpaul struct ifaddr *ifa; 119446492Swpaul struct ifnet *ifp; 119546492Swpaul 119646492Swpaul ifp = &sc->arpcom.ac_if; 119746492Swpaul 119846492Swpaul switch(wreq->wi_type) { 119946492Swpaul case WI_RID_MAC_NODE: 120046492Swpaul ifa = ifnet_addrs[ifp->if_index - 1]; 120146492Swpaul sdl = (struct sockaddr_dl *)ifa->ifa_addr; 120246492Swpaul bcopy((char *)&wreq->wi_val, (char *)&sc->arpcom.ac_enaddr, 120346492Swpaul ETHER_ADDR_LEN); 120446492Swpaul bcopy((char *)&wreq->wi_val, LLADDR(sdl), ETHER_ADDR_LEN); 120546492Swpaul break; 120646492Swpaul case WI_RID_PORTTYPE: 120746492Swpaul sc->wi_ptype = wreq->wi_val[0]; 120846492Swpaul break; 120946492Swpaul case WI_RID_TX_RATE: 121046492Swpaul sc->wi_tx_rate = wreq->wi_val[0]; 121146492Swpaul break; 121246492Swpaul case WI_RID_MAX_DATALEN: 121346492Swpaul sc->wi_max_data_len = wreq->wi_val[0]; 121446492Swpaul break; 121546492Swpaul case WI_RID_RTS_THRESH: 121646492Swpaul sc->wi_rts_thresh = wreq->wi_val[0]; 121746492Swpaul break; 121846492Swpaul case WI_RID_SYSTEM_SCALE: 121946492Swpaul sc->wi_ap_density = wreq->wi_val[0]; 122046492Swpaul break; 122146492Swpaul case WI_RID_CREATE_IBSS: 122246492Swpaul sc->wi_create_ibss = wreq->wi_val[0]; 122346492Swpaul break; 122446563Swpaul case WI_RID_OWN_CHNL: 122546563Swpaul sc->wi_channel = wreq->wi_val[0]; 122646563Swpaul break; 122746492Swpaul case WI_RID_NODENAME: 122846492Swpaul bzero(sc->wi_node_name, sizeof(sc->wi_node_name)); 122946492Swpaul bcopy((char *)&wreq->wi_val[1], sc->wi_node_name, 30); 123046492Swpaul break; 123146492Swpaul case WI_RID_DESIRED_SSID: 123246492Swpaul bzero(sc->wi_net_name, sizeof(sc->wi_net_name)); 123346492Swpaul bcopy((char *)&wreq->wi_val[1], sc->wi_net_name, 30); 123446492Swpaul break; 123546492Swpaul case WI_RID_OWN_SSID: 123646492Swpaul bzero(sc->wi_ibss_name, sizeof(sc->wi_ibss_name)); 123746492Swpaul bcopy((char *)&wreq->wi_val[1], sc->wi_ibss_name, 30); 123846492Swpaul break; 123946611Swpaul case WI_RID_PM_ENABLED: 124046611Swpaul sc->wi_pm_enabled = wreq->wi_val[0]; 124146611Swpaul break; 124246611Swpaul case WI_RID_MAX_SLEEP: 124346611Swpaul sc->wi_max_sleep = wreq->wi_val[0]; 124446611Swpaul break; 124556965Swpaul case WI_RID_ENCRYPTION: 124656965Swpaul sc->wi_use_wep = wreq->wi_val[0]; 124756965Swpaul break; 124856965Swpaul case WI_RID_TX_CRYPT_KEY: 124956965Swpaul sc->wi_tx_key = wreq->wi_val[0]; 125056965Swpaul break; 125156965Swpaul case WI_RID_DEFLT_CRYPT_KEYS: 125256965Swpaul bcopy((char *)wreq, (char *)&sc->wi_keys, 125356965Swpaul sizeof(struct wi_ltv_keys)); 125456965Swpaul break; 125546492Swpaul default: 125646492Swpaul break; 125746492Swpaul } 125846492Swpaul 125946563Swpaul /* Reinitialize WaveLAN. */ 126046563Swpaul wi_init(sc); 126146563Swpaul 126246492Swpaul return; 126346492Swpaul} 126446492Swpaul 126546492Swpaulstatic int wi_ioctl(ifp, command, data) 126646492Swpaul struct ifnet *ifp; 126746492Swpaul u_long command; 126846492Swpaul caddr_t data; 126946492Swpaul{ 127067092Swpaul int error = 0; 127146492Swpaul struct wi_softc *sc; 127246492Swpaul struct wi_req wreq; 127346492Swpaul struct ifreq *ifr; 127461818Sroberto struct proc *p = curproc; 127546492Swpaul 127646492Swpaul sc = ifp->if_softc; 127767092Swpaul WI_LOCK(sc); 127846492Swpaul ifr = (struct ifreq *)data; 127946492Swpaul 128061818Sroberto if (sc->wi_gone) { 128161818Sroberto error = ENODEV; 128261818Sroberto goto out; 128361818Sroberto } 128446492Swpaul 128546492Swpaul switch(command) { 128646492Swpaul case SIOCSIFADDR: 128746492Swpaul case SIOCGIFADDR: 128846492Swpaul case SIOCSIFMTU: 128946492Swpaul error = ether_ioctl(ifp, command, data); 129046492Swpaul break; 129146492Swpaul case SIOCSIFFLAGS: 129246492Swpaul if (ifp->if_flags & IFF_UP) { 129346492Swpaul if (ifp->if_flags & IFF_RUNNING && 129446492Swpaul ifp->if_flags & IFF_PROMISC && 129546492Swpaul !(sc->wi_if_flags & IFF_PROMISC)) { 129646492Swpaul WI_SETVAL(WI_RID_PROMISC, 1); 129746492Swpaul } else if (ifp->if_flags & IFF_RUNNING && 129846492Swpaul !(ifp->if_flags & IFF_PROMISC) && 129946492Swpaul sc->wi_if_flags & IFF_PROMISC) { 130046492Swpaul WI_SETVAL(WI_RID_PROMISC, 0); 130146492Swpaul } else 130246492Swpaul wi_init(sc); 130346492Swpaul } else { 130446492Swpaul if (ifp->if_flags & IFF_RUNNING) { 130546492Swpaul wi_stop(sc); 130646492Swpaul } 130746492Swpaul } 130846492Swpaul sc->wi_if_flags = ifp->if_flags; 130946492Swpaul error = 0; 131046492Swpaul break; 131146492Swpaul case SIOCADDMULTI: 131246492Swpaul case SIOCDELMULTI: 131346492Swpaul wi_setmulti(sc); 131446492Swpaul error = 0; 131546492Swpaul break; 131646492Swpaul case SIOCGWAVELAN: 131746492Swpaul error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); 131846492Swpaul if (error) 131946492Swpaul break; 132065581Swpaul /* Don't show WEP keys to non-root users. */ 132165581Swpaul if (wreq.wi_type == WI_RID_DEFLT_CRYPT_KEYS && suser(p)) 132265581Swpaul break; 132346492Swpaul if (wreq.wi_type == WI_RID_IFACE_STATS) { 132446492Swpaul bcopy((char *)&sc->wi_stats, (char *)&wreq.wi_val, 132546492Swpaul sizeof(sc->wi_stats)); 132646492Swpaul wreq.wi_len = (sizeof(sc->wi_stats) / 2) + 1; 132756965Swpaul } else if (wreq.wi_type == WI_RID_DEFLT_CRYPT_KEYS) { 132856965Swpaul bcopy((char *)&sc->wi_keys, (char *)&wreq, 132956965Swpaul sizeof(struct wi_ltv_keys)); 133053702Swpaul } 133153702Swpaul#ifdef WICACHE 133253702Swpaul else if (wreq.wi_type == WI_RID_ZERO_CACHE) { 133353702Swpaul sc->wi_sigitems = sc->wi_nextitem = 0; 133453702Swpaul } else if (wreq.wi_type == WI_RID_READ_CACHE) { 133553702Swpaul char *pt = (char *)&wreq.wi_val; 133653702Swpaul bcopy((char *)&sc->wi_sigitems, 133753702Swpaul (char *)pt, sizeof(int)); 133853702Swpaul pt += (sizeof (int)); 133953702Swpaul wreq.wi_len = sizeof(int) / 2; 134053702Swpaul bcopy((char *)&sc->wi_sigcache, (char *)pt, 134153702Swpaul sizeof(struct wi_sigcache) * sc->wi_sigitems); 134253702Swpaul wreq.wi_len += ((sizeof(struct wi_sigcache) * 134353702Swpaul sc->wi_sigitems) / 2) + 1; 134453702Swpaul } 134553702Swpaul#endif 134653702Swpaul else { 134746492Swpaul if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq)) { 134846492Swpaul error = EINVAL; 134946492Swpaul break; 135046492Swpaul } 135146492Swpaul } 135246492Swpaul error = copyout(&wreq, ifr->ifr_data, sizeof(wreq)); 135346492Swpaul break; 135446492Swpaul case SIOCSWAVELAN: 135561818Sroberto if ((error = suser(p))) 135661818Sroberto goto out; 135746492Swpaul error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); 135846492Swpaul if (error) 135946492Swpaul break; 136046492Swpaul if (wreq.wi_type == WI_RID_IFACE_STATS) { 136146492Swpaul error = EINVAL; 136246492Swpaul break; 136346492Swpaul } else if (wreq.wi_type == WI_RID_MGMT_XMIT) { 136446492Swpaul error = wi_mgmt_xmit(sc, (caddr_t)&wreq.wi_val, 136546492Swpaul wreq.wi_len); 136646492Swpaul } else { 136746492Swpaul error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq); 136846492Swpaul if (!error) 136946492Swpaul wi_setdef(sc, &wreq); 137046492Swpaul } 137146492Swpaul break; 137246492Swpaul default: 137346492Swpaul error = EINVAL; 137446492Swpaul break; 137546492Swpaul } 137661818Srobertoout: 137767092Swpaul WI_UNLOCK(sc); 137846492Swpaul 137946492Swpaul return(error); 138046492Swpaul} 138146492Swpaul 138246492Swpaulstatic void wi_init(xsc) 138346492Swpaul void *xsc; 138446492Swpaul{ 138546492Swpaul struct wi_softc *sc = xsc; 138646492Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 138746492Swpaul struct wi_ltv_macaddr mac; 138846492Swpaul int id = 0; 138946492Swpaul 139067092Swpaul WI_LOCK(sc); 139167092Swpaul 139267092Swpaul if (sc->wi_gone) { 139367092Swpaul WI_UNLOCK(sc); 139446492Swpaul return; 139567092Swpaul } 139646492Swpaul 139746492Swpaul if (ifp->if_flags & IFF_RUNNING) 139846492Swpaul wi_stop(sc); 139946492Swpaul 140046492Swpaul wi_reset(sc); 140146492Swpaul 140246492Swpaul /* Program max data length. */ 140346492Swpaul WI_SETVAL(WI_RID_MAX_DATALEN, sc->wi_max_data_len); 140446492Swpaul 140547401Swpaul /* Enable/disable IBSS creation. */ 140646492Swpaul WI_SETVAL(WI_RID_CREATE_IBSS, sc->wi_create_ibss); 140746492Swpaul 140846492Swpaul /* Set the port type. */ 140946492Swpaul WI_SETVAL(WI_RID_PORTTYPE, sc->wi_ptype); 141046492Swpaul 141146492Swpaul /* Program the RTS/CTS threshold. */ 141246492Swpaul WI_SETVAL(WI_RID_RTS_THRESH, sc->wi_rts_thresh); 141346492Swpaul 141446492Swpaul /* Program the TX rate */ 141546492Swpaul WI_SETVAL(WI_RID_TX_RATE, sc->wi_tx_rate); 141646492Swpaul 141746492Swpaul /* Access point density */ 141846492Swpaul WI_SETVAL(WI_RID_SYSTEM_SCALE, sc->wi_ap_density); 141946492Swpaul 142046611Swpaul /* Power Management Enabled */ 142146611Swpaul WI_SETVAL(WI_RID_PM_ENABLED, sc->wi_pm_enabled); 142246611Swpaul 142346611Swpaul /* Power Managment Max Sleep */ 142446611Swpaul WI_SETVAL(WI_RID_MAX_SLEEP, sc->wi_max_sleep); 142546611Swpaul 142646492Swpaul /* Specify the IBSS name */ 142746492Swpaul WI_SETSTR(WI_RID_OWN_SSID, sc->wi_ibss_name); 142846492Swpaul 142946492Swpaul /* Specify the network name */ 143046492Swpaul WI_SETSTR(WI_RID_DESIRED_SSID, sc->wi_net_name); 143146492Swpaul 143246563Swpaul /* Specify the frequency to use */ 143346563Swpaul WI_SETVAL(WI_RID_OWN_CHNL, sc->wi_channel); 143446563Swpaul 143546492Swpaul /* Program the nodename. */ 143646492Swpaul WI_SETSTR(WI_RID_NODENAME, sc->wi_node_name); 143746492Swpaul 143846492Swpaul /* Set our MAC address. */ 143946492Swpaul mac.wi_len = 4; 144046492Swpaul mac.wi_type = WI_RID_MAC_NODE; 144146492Swpaul bcopy((char *)&sc->arpcom.ac_enaddr, 144246492Swpaul (char *)&mac.wi_mac_addr, ETHER_ADDR_LEN); 144346492Swpaul wi_write_record(sc, (struct wi_ltv_gen *)&mac); 144446492Swpaul 144556965Swpaul /* Configure WEP. */ 144656965Swpaul if (sc->wi_has_wep) { 144756965Swpaul WI_SETVAL(WI_RID_ENCRYPTION, sc->wi_use_wep); 144856965Swpaul WI_SETVAL(WI_RID_TX_CRYPT_KEY, sc->wi_tx_key); 144956965Swpaul sc->wi_keys.wi_len = (sizeof(struct wi_ltv_keys) / 2) + 1; 145056965Swpaul sc->wi_keys.wi_type = WI_RID_DEFLT_CRYPT_KEYS; 145156965Swpaul wi_write_record(sc, (struct wi_ltv_gen *)&sc->wi_keys); 145256965Swpaul } 145356965Swpaul 145446492Swpaul /* Initialize promisc mode. */ 145546492Swpaul if (ifp->if_flags & IFF_PROMISC) { 145646492Swpaul WI_SETVAL(WI_RID_PROMISC, 1); 145746492Swpaul } else { 145846492Swpaul WI_SETVAL(WI_RID_PROMISC, 0); 145946492Swpaul } 146046492Swpaul 146146492Swpaul /* Set multicast filter. */ 146246492Swpaul wi_setmulti(sc); 146346492Swpaul 146446492Swpaul /* Enable desired port */ 146546492Swpaul wi_cmd(sc, WI_CMD_ENABLE|sc->wi_portnum, 0); 146646492Swpaul 146746492Swpaul if (wi_alloc_nicmem(sc, 1518 + sizeof(struct wi_frame) + 8, &id)) 146853702Swpaul device_printf(sc->dev, "tx buffer allocation failed\n"); 146946492Swpaul sc->wi_tx_data_id = id; 147046492Swpaul 147146492Swpaul if (wi_alloc_nicmem(sc, 1518 + sizeof(struct wi_frame) + 8, &id)) 147253702Swpaul device_printf(sc->dev, "mgmt. buffer allocation failed\n"); 147346492Swpaul sc->wi_tx_mgmt_id = id; 147446492Swpaul 147546492Swpaul /* enable interrupts */ 147646492Swpaul CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS); 147746492Swpaul 147846492Swpaul ifp->if_flags |= IFF_RUNNING; 147946492Swpaul ifp->if_flags &= ~IFF_OACTIVE; 148046492Swpaul 148146492Swpaul sc->wi_stat_ch = timeout(wi_inquire, sc, hz * 60); 148267092Swpaul WI_UNLOCK(sc); 148346492Swpaul 148446492Swpaul return; 148546492Swpaul} 148646492Swpaul 148746492Swpaulstatic void wi_start(ifp) 148846492Swpaul struct ifnet *ifp; 148946492Swpaul{ 149046492Swpaul struct wi_softc *sc; 149146492Swpaul struct mbuf *m0; 149246492Swpaul struct wi_frame tx_frame; 149346492Swpaul struct ether_header *eh; 149446492Swpaul int id; 149546492Swpaul 149646492Swpaul sc = ifp->if_softc; 149767092Swpaul WI_LOCK(sc); 149846492Swpaul 149967092Swpaul if (sc->wi_gone) { 150067092Swpaul WI_UNLOCK(sc); 150146492Swpaul return; 150267092Swpaul } 150346492Swpaul 150467092Swpaul if (ifp->if_flags & IFF_OACTIVE) { 150567092Swpaul WI_UNLOCK(sc); 150646492Swpaul return; 150767092Swpaul } 150846492Swpaul 150946492Swpaul IF_DEQUEUE(&ifp->if_snd, m0); 151067092Swpaul if (m0 == NULL) { 151167092Swpaul WI_UNLOCK(sc); 151246492Swpaul return; 151367092Swpaul } 151446492Swpaul 151546492Swpaul bzero((char *)&tx_frame, sizeof(tx_frame)); 151646492Swpaul id = sc->wi_tx_data_id; 151746492Swpaul eh = mtod(m0, struct ether_header *); 151846492Swpaul 151946492Swpaul /* 152047401Swpaul * Use RFC1042 encoding for IP and ARP datagrams, 152146492Swpaul * 802.3 for anything else. 152246492Swpaul */ 152355831Swpaul if (ntohs(eh->ether_type) > 1518) { 152446492Swpaul bcopy((char *)&eh->ether_dhost, 152546492Swpaul (char *)&tx_frame.wi_addr1, ETHER_ADDR_LEN); 152646492Swpaul bcopy((char *)&eh->ether_shost, 152746492Swpaul (char *)&tx_frame.wi_addr2, ETHER_ADDR_LEN); 152846492Swpaul bcopy((char *)&eh->ether_dhost, 152946492Swpaul (char *)&tx_frame.wi_dst_addr, ETHER_ADDR_LEN); 153046492Swpaul bcopy((char *)&eh->ether_shost, 153146492Swpaul (char *)&tx_frame.wi_src_addr, ETHER_ADDR_LEN); 153246492Swpaul 153346492Swpaul tx_frame.wi_dat_len = m0->m_pkthdr.len - WI_SNAPHDR_LEN; 153446492Swpaul tx_frame.wi_frame_ctl = WI_FTYPE_DATA; 153546492Swpaul tx_frame.wi_dat[0] = htons(WI_SNAP_WORD0); 153646492Swpaul tx_frame.wi_dat[1] = htons(WI_SNAP_WORD1); 153746492Swpaul tx_frame.wi_len = htons(m0->m_pkthdr.len - WI_SNAPHDR_LEN); 153846492Swpaul tx_frame.wi_type = eh->ether_type; 153946492Swpaul 154046492Swpaul m_copydata(m0, sizeof(struct ether_header), 154146492Swpaul m0->m_pkthdr.len - sizeof(struct ether_header), 154246492Swpaul (caddr_t)&sc->wi_txbuf); 154346492Swpaul 154446492Swpaul wi_write_data(sc, id, 0, (caddr_t)&tx_frame, 154546492Swpaul sizeof(struct wi_frame)); 154646492Swpaul wi_write_data(sc, id, WI_802_11_OFFSET, (caddr_t)&sc->wi_txbuf, 154746492Swpaul (m0->m_pkthdr.len - sizeof(struct ether_header)) + 2); 154846492Swpaul } else { 154946492Swpaul tx_frame.wi_dat_len = m0->m_pkthdr.len; 155046492Swpaul 155155831Swpaul eh->ether_type = htons(m0->m_pkthdr.len - WI_SNAPHDR_LEN); 155246492Swpaul m_copydata(m0, 0, m0->m_pkthdr.len, (caddr_t)&sc->wi_txbuf); 155346492Swpaul 155446492Swpaul wi_write_data(sc, id, 0, (caddr_t)&tx_frame, 155546492Swpaul sizeof(struct wi_frame)); 155646492Swpaul wi_write_data(sc, id, WI_802_3_OFFSET, (caddr_t)&sc->wi_txbuf, 155746492Swpaul m0->m_pkthdr.len + 2); 155846492Swpaul } 155946492Swpaul 156046492Swpaul /* 156146492Swpaul * If there's a BPF listner, bounce a copy of 156246492Swpaul * this frame to him. 156346492Swpaul */ 156446492Swpaul if (ifp->if_bpf) 156546492Swpaul bpf_mtap(ifp, m0); 156646492Swpaul 156746492Swpaul m_freem(m0); 156846492Swpaul 156946492Swpaul if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id)) 157053702Swpaul device_printf(sc->dev, "xmit failed\n"); 157146492Swpaul 157246492Swpaul ifp->if_flags |= IFF_OACTIVE; 157346492Swpaul 157446492Swpaul /* 157546492Swpaul * Set a timeout in case the chip goes out to lunch. 157646492Swpaul */ 157746492Swpaul ifp->if_timer = 5; 157846492Swpaul 157967092Swpaul WI_UNLOCK(sc); 158046492Swpaul return; 158146492Swpaul} 158246492Swpaul 158346492Swpaulstatic int wi_mgmt_xmit(sc, data, len) 158446492Swpaul struct wi_softc *sc; 158546492Swpaul caddr_t data; 158646492Swpaul int len; 158746492Swpaul{ 158846492Swpaul struct wi_frame tx_frame; 158946492Swpaul int id; 159046492Swpaul struct wi_80211_hdr *hdr; 159146492Swpaul caddr_t dptr; 159246492Swpaul 159346492Swpaul if (sc->wi_gone) 159446492Swpaul return(ENODEV); 159546492Swpaul 159646492Swpaul hdr = (struct wi_80211_hdr *)data; 159746492Swpaul dptr = data + sizeof(struct wi_80211_hdr); 159846492Swpaul 159946492Swpaul bzero((char *)&tx_frame, sizeof(tx_frame)); 160046492Swpaul id = sc->wi_tx_mgmt_id; 160146492Swpaul 160246492Swpaul bcopy((char *)hdr, (char *)&tx_frame.wi_frame_ctl, 160346492Swpaul sizeof(struct wi_80211_hdr)); 160446492Swpaul 160546492Swpaul tx_frame.wi_dat_len = len - WI_SNAPHDR_LEN; 160646492Swpaul tx_frame.wi_len = htons(len - WI_SNAPHDR_LEN); 160746492Swpaul 160846492Swpaul wi_write_data(sc, id, 0, (caddr_t)&tx_frame, sizeof(struct wi_frame)); 160946492Swpaul wi_write_data(sc, id, WI_802_11_OFFSET_RAW, dptr, 161046492Swpaul (len - sizeof(struct wi_80211_hdr)) + 2); 161146492Swpaul 161246492Swpaul if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id)) { 161353702Swpaul device_printf(sc->dev, "xmit failed\n"); 161446492Swpaul return(EIO); 161546492Swpaul } 161646492Swpaul 161746492Swpaul return(0); 161846492Swpaul} 161946492Swpaul 162046492Swpaulstatic void wi_stop(sc) 162146492Swpaul struct wi_softc *sc; 162246492Swpaul{ 162346492Swpaul struct ifnet *ifp; 162446492Swpaul 162567092Swpaul WI_LOCK(sc); 162667092Swpaul 162767092Swpaul if (sc->wi_gone) { 162867092Swpaul WI_UNLOCK(sc); 162946492Swpaul return; 163067092Swpaul } 163146492Swpaul 163246492Swpaul ifp = &sc->arpcom.ac_if; 163346492Swpaul 163470173Sjhb /* 163570173Sjhb * If the card is gone and the memory port isn't mapped, we will 163670173Sjhb * (hopefully) get 0xffff back from the status read, which is not 163770173Sjhb * a valid status value. 163870173Sjhb */ 163970173Sjhb if (CSR_READ_2(sc, WI_STATUS) != 0xffff) { 164070173Sjhb CSR_WRITE_2(sc, WI_INT_EN, 0); 164170173Sjhb wi_cmd(sc, WI_CMD_DISABLE|sc->wi_portnum, 0); 164270173Sjhb } 164346492Swpaul 164446492Swpaul untimeout(wi_inquire, sc, sc->wi_stat_ch); 164546492Swpaul 164646492Swpaul ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); 164746492Swpaul 164867092Swpaul WI_UNLOCK(sc); 164946492Swpaul return; 165046492Swpaul} 165146492Swpaul 165246492Swpaulstatic void wi_watchdog(ifp) 165346492Swpaul struct ifnet *ifp; 165446492Swpaul{ 165546492Swpaul struct wi_softc *sc; 165646492Swpaul 165746492Swpaul sc = ifp->if_softc; 165846492Swpaul 165953702Swpaul device_printf(sc->dev,"device timeout\n"); 166046492Swpaul 166146492Swpaul wi_init(sc); 166246492Swpaul 166346492Swpaul ifp->if_oerrors++; 166446492Swpaul 166546492Swpaul return; 166646492Swpaul} 166746492Swpaul 166874906Salfredstatic int 166974906Salfredwi_alloc(dev, io_rid) 167053702Swpaul device_t dev; 167174906Salfred int io_rid; 167246492Swpaul{ 167353702Swpaul struct wi_softc *sc = device_get_softc(dev); 167453702Swpaul 167574906Salfred sc->iobase_rid = io_rid; 167674906Salfred sc->iobase = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iobase_rid, 167770073Swpaul 0, ~0, (1 << 6), 167870073Swpaul rman_make_alignment_flags(1 << 6) | RF_ACTIVE); 167953702Swpaul if (!sc->iobase) { 168053702Swpaul device_printf(dev, "No I/O space?!\n"); 168153702Swpaul return (ENXIO); 168253702Swpaul } 168353702Swpaul 168474906Salfred sc->irq_rid = 0; 168574906Salfred sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_rid, 168653702Swpaul 0, ~0, 1, RF_ACTIVE); 168753702Swpaul if (!sc->irq) { 168853702Swpaul device_printf(dev, "No irq?!\n"); 168953702Swpaul return (ENXIO); 169053702Swpaul } 169153702Swpaul 169253702Swpaul sc->dev = dev; 169353702Swpaul sc->wi_unit = device_get_unit(dev); 169453702Swpaul sc->wi_io_addr = rman_get_start(sc->iobase); 169553702Swpaul sc->wi_btag = rman_get_bustag(sc->iobase); 169653702Swpaul sc->wi_bhandle = rman_get_bushandle(sc->iobase); 169753702Swpaul 169853702Swpaul return (0); 169953702Swpaul} 170053702Swpaul 170153702Swpaulstatic void wi_free(dev) 170253702Swpaul device_t dev; 170353702Swpaul{ 170453702Swpaul struct wi_softc *sc = device_get_softc(dev); 170553702Swpaul 170653702Swpaul if (sc->iobase != NULL) 170753702Swpaul bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->iobase); 170853702Swpaul if (sc->irq != NULL) 170953702Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); 171074906Salfred if (sc->mem != NULL) 171174906Salfred bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem); 171253702Swpaul 171353702Swpaul return; 171453702Swpaul} 171553702Swpaul 171653702Swpaulstatic void wi_shutdown(dev) 171753702Swpaul device_t dev; 171853702Swpaul{ 171946492Swpaul struct wi_softc *sc; 172046492Swpaul 172153702Swpaul sc = device_get_softc(dev); 172246492Swpaul wi_stop(sc); 172346492Swpaul 172446492Swpaul return; 172546492Swpaul} 172653702Swpaul 172753702Swpaul#ifdef WICACHE 172853702Swpaul/* wavelan signal strength cache code. 172953702Swpaul * store signal/noise/quality on per MAC src basis in 173053702Swpaul * a small fixed cache. The cache wraps if > MAX slots 173153702Swpaul * used. The cache may be zeroed out to start over. 173253702Swpaul * Two simple filters exist to reduce computation: 173353702Swpaul * 1. ip only (literally 0x800) which may be used 173453702Swpaul * to ignore some packets. It defaults to ip only. 173553702Swpaul * it could be used to focus on broadcast, non-IP 802.11 beacons. 173653702Swpaul * 2. multicast/broadcast only. This may be used to 173753702Swpaul * ignore unicast packets and only cache signal strength 173853702Swpaul * for multicast/broadcast packets (beacons); e.g., Mobile-IP 173953702Swpaul * beacons and not unicast traffic. 174053702Swpaul * 174153702Swpaul * The cache stores (MAC src(index), IP src (major clue), signal, 174253702Swpaul * quality, noise) 174353702Swpaul * 174453702Swpaul * No apologies for storing IP src here. It's easy and saves much 174553702Swpaul * trouble elsewhere. The cache is assumed to be INET dependent, 174653702Swpaul * although it need not be. 174753702Swpaul */ 174853702Swpaul 174953702Swpaul#ifdef documentation 175053702Swpaul 175153702Swpaulint wi_sigitems; /* number of cached entries */ 175253702Swpaulstruct wi_sigcache wi_sigcache[MAXWICACHE]; /* array of cache entries */ 175353702Swpaulint wi_nextitem; /* index/# of entries */ 175453702Swpaul 175553702Swpaul 175653702Swpaul#endif 175753702Swpaul 175853702Swpaul/* control variables for cache filtering. Basic idea is 175953702Swpaul * to reduce cost (e.g., to only Mobile-IP agent beacons 176053702Swpaul * which are broadcast or multicast). Still you might 176153702Swpaul * want to measure signal strength with unicast ping packets 176253702Swpaul * on a pt. to pt. ant. setup. 176353702Swpaul */ 176453702Swpaul/* set true if you want to limit cache items to broadcast/mcast 176553702Swpaul * only packets (not unicast). Useful for mobile-ip beacons which 176653702Swpaul * are broadcast/multicast at network layer. Default is all packets 176753702Swpaul * so ping/unicast will work say with pt. to pt. antennae setup. 176853702Swpaul */ 176953702Swpaulstatic int wi_cache_mcastonly = 0; 177053702SwpaulSYSCTL_INT(_machdep, OID_AUTO, wi_cache_mcastonly, CTLFLAG_RW, 177153702Swpaul &wi_cache_mcastonly, 0, ""); 177253702Swpaul 177353702Swpaul/* set true if you want to limit cache items to IP packets only 177453702Swpaul*/ 177553702Swpaulstatic int wi_cache_iponly = 1; 177653702SwpaulSYSCTL_INT(_machdep, OID_AUTO, wi_cache_iponly, CTLFLAG_RW, 177753702Swpaul &wi_cache_iponly, 0, ""); 177853702Swpaul 177953702Swpaul/* 178053702Swpaul * Original comments: 178153702Swpaul * ----------------- 178253702Swpaul * wi_cache_store, per rx packet store signal 178353702Swpaul * strength in MAC (src) indexed cache. 178453702Swpaul * 178553702Swpaul * follows linux driver in how signal strength is computed. 178653702Swpaul * In ad hoc mode, we use the rx_quality field. 178753702Swpaul * signal and noise are trimmed to fit in the range from 47..138. 178853702Swpaul * rx_quality field MSB is signal strength. 178953702Swpaul * rx_quality field LSB is noise. 179053702Swpaul * "quality" is (signal - noise) as is log value. 179153702Swpaul * note: quality CAN be negative. 179253702Swpaul * 179353702Swpaul * In BSS mode, we use the RID for communication quality. 179453702Swpaul * TBD: BSS mode is currently untested. 179553702Swpaul * 179653702Swpaul * Bill's comments: 179753702Swpaul * --------------- 179853702Swpaul * Actually, we use the rx_quality field all the time for both "ad-hoc" 179953702Swpaul * and BSS modes. Why? Because reading an RID is really, really expensive: 180053702Swpaul * there's a bunch of PIO operations that have to be done to read a record 180153702Swpaul * from the NIC, and reading the comms quality RID each time a packet is 180253702Swpaul * received can really hurt performance. We don't have to do this anyway: 180353702Swpaul * the comms quality field only reflects the values in the rx_quality field 180453702Swpaul * anyway. The comms quality RID is only meaningful in infrastructure mode, 180553702Swpaul * but the values it contains are updated based on the rx_quality from 180653702Swpaul * frames received from the access point. 180753702Swpaul * 180853702Swpaul * Also, according to Lucent, the signal strength and noise level values 180953702Swpaul * can be converted to dBms by subtracting 149, so I've modified the code 181053702Swpaul * to do that instead of the scaling it did originally. 181153702Swpaul */ 181253702Swpaulstatic 181353702Swpaulvoid wi_cache_store (struct wi_softc *sc, struct ether_header *eh, 181453702Swpaul struct mbuf *m, unsigned short rx_quality) 181553702Swpaul{ 181653702Swpaul struct ip *ip = 0; 181753702Swpaul int i; 181853702Swpaul static int cache_slot = 0; /* use this cache entry */ 181953702Swpaul static int wrapindex = 0; /* next "free" cache entry */ 182053702Swpaul int sig, noise; 182153702Swpaul int sawip=0; 182253702Swpaul 182353702Swpaul /* filters: 182453702Swpaul * 1. ip only 182553702Swpaul * 2. configurable filter to throw out unicast packets, 182653702Swpaul * keep multicast only. 182753702Swpaul */ 182853702Swpaul 182953702Swpaul if ((ntohs(eh->ether_type) == 0x800)) { 183053702Swpaul sawip = 1; 183153702Swpaul } 183253702Swpaul 183353702Swpaul /* filter for ip packets only 183453702Swpaul */ 183553702Swpaul if (wi_cache_iponly && !sawip) { 183653702Swpaul return; 183753702Swpaul } 183853702Swpaul 183953702Swpaul /* filter for broadcast/multicast only 184053702Swpaul */ 184153702Swpaul if (wi_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) { 184253702Swpaul return; 184353702Swpaul } 184453702Swpaul 184553702Swpaul#ifdef SIGDEBUG 184653702Swpaul printf("wi%d: q value %x (MSB=0x%x, LSB=0x%x) \n", sc->wi_unit, 184753702Swpaul rx_quality & 0xffff, rx_quality >> 8, rx_quality & 0xff); 184853702Swpaul#endif 184953702Swpaul 185053702Swpaul /* find the ip header. we want to store the ip_src 185153702Swpaul * address. 185253702Swpaul */ 185353702Swpaul if (sawip) { 185453702Swpaul ip = mtod(m, struct ip *); 185553702Swpaul } 185653702Swpaul 185753702Swpaul /* do a linear search for a matching MAC address 185853702Swpaul * in the cache table 185953702Swpaul * . MAC address is 6 bytes, 186053702Swpaul * . var w_nextitem holds total number of entries already cached 186153702Swpaul */ 186253702Swpaul for(i = 0; i < sc->wi_nextitem; i++) { 186353702Swpaul if (! bcmp(eh->ether_shost , sc->wi_sigcache[i].macsrc, 6 )) { 186453702Swpaul /* Match!, 186553702Swpaul * so we already have this entry, 186653702Swpaul * update the data 186753702Swpaul */ 186853702Swpaul break; 186953702Swpaul } 187053702Swpaul } 187153702Swpaul 187253702Swpaul /* did we find a matching mac address? 187353702Swpaul * if yes, then overwrite a previously existing cache entry 187453702Swpaul */ 187553702Swpaul if (i < sc->wi_nextitem ) { 187653702Swpaul cache_slot = i; 187753702Swpaul } 187853702Swpaul /* else, have a new address entry,so 187953702Swpaul * add this new entry, 188053702Swpaul * if table full, then we need to replace LRU entry 188153702Swpaul */ 188253702Swpaul else { 188353702Swpaul 188453702Swpaul /* check for space in cache table 188553702Swpaul * note: wi_nextitem also holds number of entries 188653702Swpaul * added in the cache table 188753702Swpaul */ 188853702Swpaul if ( sc->wi_nextitem < MAXWICACHE ) { 188953702Swpaul cache_slot = sc->wi_nextitem; 189053702Swpaul sc->wi_nextitem++; 189153702Swpaul sc->wi_sigitems = sc->wi_nextitem; 189253702Swpaul } 189353702Swpaul /* no space found, so simply wrap with wrap index 189453702Swpaul * and "zap" the next entry 189553702Swpaul */ 189653702Swpaul else { 189753702Swpaul if (wrapindex == MAXWICACHE) { 189853702Swpaul wrapindex = 0; 189953702Swpaul } 190053702Swpaul cache_slot = wrapindex++; 190153702Swpaul } 190253702Swpaul } 190353702Swpaul 190453702Swpaul /* invariant: cache_slot now points at some slot 190553702Swpaul * in cache. 190653702Swpaul */ 190753702Swpaul if (cache_slot < 0 || cache_slot >= MAXWICACHE) { 190853702Swpaul log(LOG_ERR, "wi_cache_store, bad index: %d of " 190953702Swpaul "[0..%d], gross cache error\n", 191053702Swpaul cache_slot, MAXWICACHE); 191153702Swpaul return; 191253702Swpaul } 191353702Swpaul 191453702Swpaul /* store items in cache 191553702Swpaul * .ip source address 191653702Swpaul * .mac src 191753702Swpaul * .signal, etc. 191853702Swpaul */ 191953702Swpaul if (sawip) { 192053702Swpaul sc->wi_sigcache[cache_slot].ipsrc = ip->ip_src.s_addr; 192153702Swpaul } 192253702Swpaul bcopy( eh->ether_shost, sc->wi_sigcache[cache_slot].macsrc, 6); 192353702Swpaul 192453702Swpaul sig = (rx_quality >> 8) & 0xFF; 192553702Swpaul noise = rx_quality & 0xFF; 192653702Swpaul sc->wi_sigcache[cache_slot].signal = sig - 149; 192753702Swpaul sc->wi_sigcache[cache_slot].noise = noise - 149; 192853702Swpaul sc->wi_sigcache[cache_slot].quality = sig - noise; 192953702Swpaul 193053702Swpaul return; 193153702Swpaul} 193253702Swpaul#endif 1933