if_wi.c revision 93825
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#include <sys/param.h> 6646492Swpaul#include <sys/systm.h> 6746492Swpaul#include <sys/sockio.h> 6846492Swpaul#include <sys/mbuf.h> 6983366Sjulian#include <sys/proc.h> 7046492Swpaul#include <sys/kernel.h> 7146492Swpaul#include <sys/socket.h> 7253702Swpaul#include <sys/module.h> 7353702Swpaul#include <sys/bus.h> 7453702Swpaul#include <sys/syslog.h> 7553702Swpaul#include <sys/sysctl.h> 7646492Swpaul 7753702Swpaul#include <machine/bus.h> 7853702Swpaul#include <machine/resource.h> 7953702Swpaul#include <sys/rman.h> 8053702Swpaul 8146492Swpaul#include <net/if.h> 8246492Swpaul#include <net/if_arp.h> 8346492Swpaul#include <net/ethernet.h> 8446492Swpaul#include <net/if_dl.h> 8546492Swpaul#include <net/if_media.h> 8646492Swpaul#include <net/if_types.h> 8777217Sphk#include <net/if_ieee80211.h> 8846492Swpaul 8946492Swpaul#include <netinet/in.h> 9046492Swpaul#include <netinet/in_systm.h> 9146492Swpaul#include <netinet/in_var.h> 9246492Swpaul#include <netinet/ip.h> 9346492Swpaul#include <netinet/if_ether.h> 9446492Swpaul 9546492Swpaul#include <net/bpf.h> 9646492Swpaul 9770808Speter#include <dev/wi/if_wavelan_ieee.h> 9893611Simp#include <dev/wi/if_wivar.h> 9970808Speter#include <dev/wi/if_wireg.h> 10046492Swpaul 10146492Swpaul#if !defined(lint) 10246492Swpaulstatic const char rcsid[] = 10350477Speter "$FreeBSD: head/sys/dev/wi/if_wi.c 93825 2002-04-04 21:40:37Z imp $"; 10446492Swpaul#endif 10546492Swpaul 10691693Simpstatic void wi_intr(void *); 10791693Simpstatic void wi_reset(struct wi_softc *); 10891693Simpstatic int wi_ioctl(struct ifnet *, u_long, caddr_t); 10991693Simpstatic void wi_init(void *); 11091693Simpstatic void wi_start(struct ifnet *); 11191693Simpstatic void wi_stop(struct wi_softc *); 11291693Simpstatic void wi_watchdog(struct ifnet *); 11391693Simpstatic void wi_rxeof(struct wi_softc *); 11491693Simpstatic void wi_txeof(struct wi_softc *, int); 11591693Simpstatic void wi_update_stats(struct wi_softc *); 11691693Simpstatic void wi_setmulti(struct wi_softc *); 11746492Swpaul 11892457Simpstatic int wi_cmd(struct wi_softc *, int, int, int, int); 11991693Simpstatic int wi_read_record(struct wi_softc *, struct wi_ltv_gen *); 12091693Simpstatic int wi_write_record(struct wi_softc *, struct wi_ltv_gen *); 12191693Simpstatic int wi_read_data(struct wi_softc *, int, int, caddr_t, int); 12291693Simpstatic int wi_write_data(struct wi_softc *, int, int, caddr_t, int); 12391693Simpstatic int wi_seek(struct wi_softc *, int, int, int); 12491693Simpstatic int wi_alloc_nicmem(struct wi_softc *, int, int *); 12591693Simpstatic void wi_inquire(void *); 12691693Simpstatic void wi_setdef(struct wi_softc *, struct wi_req *); 12791693Simpstatic int wi_mgmt_xmit(struct wi_softc *, caddr_t, int); 12846492Swpaul 12953702Swpaul#ifdef WICACHE 13053702Swpaulstatic 13191693Simpvoid wi_cache_store(struct wi_softc *, struct ether_header *, 13291693Simp struct mbuf *, unsigned short); 13353702Swpaul#endif 13453702Swpaul 13591693Simpstatic int wi_get_cur_ssid(struct wi_softc *, char *, int *); 13693825Simpstatic void wi_get_id(struct wi_softc *); 13791693Simpstatic int wi_media_change(struct ifnet *); 13891693Simpstatic void wi_media_status(struct ifnet *, struct ifmediareq *); 13977217Sphk 14093359Simpstatic int wi_get_debug(struct wi_softc *, struct wi_req *); 14193359Simpstatic int wi_set_debug(struct wi_softc *, struct wi_req *); 14293359Simp 14393611Simpdevclass_t wi_devclass; 14453702Swpaul 14593825Simpstruct wi_card_ident wi_card_ident[] = { 14693825Simp /* CARD_ID CARD_NAME FIRM_TYPE */ 14793825Simp { WI_NIC_LUCENT_ID, WI_NIC_LUCENT_STR, WI_LUCENT }, 14893825Simp { WI_NIC_SONY_ID, WI_NIC_SONY_STR, WI_LUCENT }, 14993825Simp { WI_NIC_LUCENT_EMB_ID, WI_NIC_LUCENT_EMB_STR, WI_LUCENT }, 15093825Simp { WI_NIC_EVB2_ID, WI_NIC_EVB2_STR, WI_INTERSIL }, 15193825Simp { WI_NIC_HWB3763_ID, WI_NIC_HWB3763_STR, WI_INTERSIL }, 15293825Simp { WI_NIC_HWB3163_ID, WI_NIC_HWB3163_STR, WI_INTERSIL }, 15393825Simp { WI_NIC_HWB3163B_ID, WI_NIC_HWB3163B_STR, WI_INTERSIL }, 15493825Simp { WI_NIC_EVB3_ID, WI_NIC_EVB3_STR, WI_INTERSIL }, 15593825Simp { WI_NIC_HWB1153_ID, WI_NIC_HWB1153_STR, WI_INTERSIL }, 15693825Simp { WI_NIC_P2_SST_ID, WI_NIC_P2_SST_STR, WI_INTERSIL }, 15793825Simp { WI_NIC_EVB2_SST_ID, WI_NIC_EVB2_SST_STR, WI_INTERSIL }, 15893825Simp { WI_NIC_3842_EVA_ID, WI_NIC_3842_EVA_STR, WI_INTERSIL }, 15993825Simp { WI_NIC_3842_PCMCIA_AMD_ID, WI_NIC_3842_PCMCIA_STR, WI_INTERSIL }, 16093825Simp { WI_NIC_3842_PCMCIA_SST_ID, WI_NIC_3842_PCMCIA_STR, WI_INTERSIL }, 16193825Simp { WI_NIC_3842_PCMCIA_ATM_ID, WI_NIC_3842_PCMCIA_STR, WI_INTERSIL }, 16293825Simp { WI_NIC_3842_MINI_AMD_ID, WI_NIC_3842_MINI_STR, WI_INTERSIL }, 16393825Simp { WI_NIC_3842_MINI_SST_ID, WI_NIC_3842_MINI_STR, WI_INTERSIL }, 16493825Simp { WI_NIC_3842_MINI_ATM_ID, WI_NIC_3842_MINI_STR, WI_INTERSIL }, 16593825Simp { WI_NIC_3842_PCI_AMD_ID, WI_NIC_3842_PCI_STR, WI_INTERSIL }, 16693825Simp { WI_NIC_3842_PCI_SST_ID, WI_NIC_3842_PCI_STR, WI_INTERSIL }, 16793825Simp { WI_NIC_3842_PCI_ATM_ID, WI_NIC_3842_PCI_STR, WI_INTERSIL }, 16893825Simp { WI_NIC_P3_PCMCIA_AMD_ID, WI_NIC_P3_PCMCIA_STR, WI_INTERSIL }, 16993825Simp { WI_NIC_P3_PCMCIA_SST_ID, WI_NIC_P3_PCMCIA_STR, WI_INTERSIL }, 17093825Simp { WI_NIC_P3_MINI_AMD_ID, WI_NIC_P3_MINI_STR, WI_INTERSIL }, 17193825Simp { WI_NIC_P3_MINI_SST_ID, WI_NIC_P3_MINI_STR, WI_INTERSIL }, 17293825Simp { 0, NULL, 0 }, 17393825Simp}; 17493825Simp 17593611Simpint 17693611Simpwi_generic_detach(dev) 17753702Swpaul device_t dev; 17846492Swpaul{ 17946492Swpaul struct wi_softc *sc; 18046492Swpaul struct ifnet *ifp; 18146492Swpaul 18253702Swpaul sc = device_get_softc(dev); 18367092Swpaul WI_LOCK(sc); 18446492Swpaul ifp = &sc->arpcom.ac_if; 18546492Swpaul 18646492Swpaul if (sc->wi_gone) { 18753702Swpaul device_printf(dev, "already unloaded\n"); 18867092Swpaul WI_UNLOCK(sc); 18953702Swpaul return(ENODEV); 19046492Swpaul } 19146492Swpaul 19253702Swpaul wi_stop(sc); 19358274Srwatson 19477217Sphk /* Delete all remaining media. */ 19577217Sphk ifmedia_removeall(&sc->ifmedia); 19677217Sphk 19763090Sarchie ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); 19854277Swpaul bus_teardown_intr(dev, sc->irq, sc->wi_intrhand); 19953702Swpaul wi_free(dev); 20046492Swpaul sc->wi_gone = 1; 20146492Swpaul 20267092Swpaul WI_UNLOCK(sc); 20367092Swpaul mtx_destroy(&sc->wi_mtx); 20446492Swpaul 20546492Swpaul return(0); 20646492Swpaul} 20746492Swpaul 20893611Simpint 20974906Salfredwi_generic_attach(device_t dev) 21074906Salfred{ 21174906Salfred struct wi_softc *sc; 21274906Salfred struct wi_ltv_macaddr mac; 21374906Salfred struct wi_ltv_gen gen; 21474906Salfred struct ifnet *ifp; 21574906Salfred int error; 21674906Salfred 21774906Salfred sc = device_get_softc(dev); 21874906Salfred ifp = &sc->arpcom.ac_if; 21974906Salfred 22053702Swpaul error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET, 22174998Swpaul wi_intr, sc, &sc->wi_intrhand); 22253702Swpaul 22353702Swpaul if (error) { 22453702Swpaul device_printf(dev, "bus_setup_intr() failed! (%d)\n", error); 22553702Swpaul wi_free(dev); 22653702Swpaul return (error); 22753702Swpaul } 22853702Swpaul 22993818Sjhb mtx_init(&sc->wi_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 23093818Sjhb MTX_DEF | MTX_RECURSE); 23167092Swpaul WI_LOCK(sc); 23267092Swpaul 23346492Swpaul /* Reset the NIC. */ 23446492Swpaul wi_reset(sc); 23546492Swpaul 23676438Swpaul /* 23776438Swpaul * Read the station address. 23876438Swpaul * And do it twice. I've seen PRISM-based cards that return 23976438Swpaul * an error when trying to read it the first time, which causes 24076438Swpaul * the probe to fail. 24176438Swpaul */ 24246492Swpaul mac.wi_type = WI_RID_MAC_NODE; 24346492Swpaul mac.wi_len = 4; 24476457Sgrog wi_read_record(sc, (struct wi_ltv_gen *)&mac); 24575150Simp if ((error = wi_read_record(sc, (struct wi_ltv_gen *)&mac)) != 0) { 24675149Simp device_printf(dev, "mac read failed %d\n", error); 24775149Simp wi_free(dev); 24875149Simp return (error); 24975149Simp } 25046492Swpaul bcopy((char *)&mac.wi_mac_addr, 25146492Swpaul (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 25246492Swpaul 25387383Simp device_printf(dev, "802.11 address: %6D\n", sc->arpcom.ac_enaddr, ":"); 25446492Swpaul 25593825Simp wi_get_id(sc); 25687383Simp 25746492Swpaul ifp->if_softc = sc; 25846492Swpaul ifp->if_unit = sc->wi_unit; 25946492Swpaul ifp->if_name = "wi"; 26046492Swpaul ifp->if_mtu = ETHERMTU; 26146492Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 26246492Swpaul ifp->if_ioctl = wi_ioctl; 26346492Swpaul ifp->if_output = ether_output; 26446492Swpaul ifp->if_start = wi_start; 26546492Swpaul ifp->if_watchdog = wi_watchdog; 26646492Swpaul ifp->if_init = wi_init; 26746492Swpaul ifp->if_baudrate = 10000000; 26846492Swpaul ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 26946492Swpaul 27046492Swpaul bzero(sc->wi_node_name, sizeof(sc->wi_node_name)); 27146492Swpaul bcopy(WI_DEFAULT_NODENAME, sc->wi_node_name, 27246492Swpaul sizeof(WI_DEFAULT_NODENAME) - 1); 27346492Swpaul 27446492Swpaul bzero(sc->wi_net_name, sizeof(sc->wi_net_name)); 27546492Swpaul bcopy(WI_DEFAULT_NETNAME, sc->wi_net_name, 27646492Swpaul sizeof(WI_DEFAULT_NETNAME) - 1); 27746492Swpaul 27846492Swpaul bzero(sc->wi_ibss_name, sizeof(sc->wi_ibss_name)); 27946492Swpaul bcopy(WI_DEFAULT_IBSS, sc->wi_ibss_name, 28046492Swpaul sizeof(WI_DEFAULT_IBSS) - 1); 28146492Swpaul 28246492Swpaul sc->wi_portnum = WI_DEFAULT_PORT; 28374139Sassar sc->wi_ptype = WI_PORTTYPE_BSS; 28446492Swpaul sc->wi_ap_density = WI_DEFAULT_AP_DENSITY; 28546492Swpaul sc->wi_rts_thresh = WI_DEFAULT_RTS_THRESH; 28646492Swpaul sc->wi_tx_rate = WI_DEFAULT_TX_RATE; 28746492Swpaul sc->wi_max_data_len = WI_DEFAULT_DATALEN; 28846492Swpaul sc->wi_create_ibss = WI_DEFAULT_CREATE_IBSS; 28946611Swpaul sc->wi_pm_enabled = WI_DEFAULT_PM_ENABLED; 29046611Swpaul sc->wi_max_sleep = WI_DEFAULT_MAX_SLEEP; 29191695Simp sc->wi_roaming = WI_DEFAULT_ROAMING; 29291695Simp sc->wi_authtype = WI_DEFAULT_AUTHTYPE; 29346492Swpaul 29446563Swpaul /* 29546563Swpaul * Read the default channel from the NIC. This may vary 29646563Swpaul * depending on the country where the NIC was purchased, so 29746563Swpaul * we can't hard-code a default and expect it to work for 29846563Swpaul * everyone. 29946563Swpaul */ 30046563Swpaul gen.wi_type = WI_RID_OWN_CHNL; 30146563Swpaul gen.wi_len = 2; 30246563Swpaul wi_read_record(sc, &gen); 30346563Swpaul sc->wi_channel = gen.wi_val; 30446563Swpaul 30556965Swpaul /* 30656965Swpaul * Find out if we support WEP on this card. 30756965Swpaul */ 30856965Swpaul gen.wi_type = WI_RID_WEP_AVAIL; 30956965Swpaul gen.wi_len = 2; 31056965Swpaul wi_read_record(sc, &gen); 31156965Swpaul sc->wi_has_wep = gen.wi_val; 31256965Swpaul 31370073Swpaul if (bootverbose) { 31470073Swpaul device_printf(sc->dev, 31587599Sobrien "%s:wi_has_wep = %d\n", 31687599Sobrien __func__, sc->wi_has_wep); 31770073Swpaul } 31870073Swpaul 31946492Swpaul bzero((char *)&sc->wi_stats, sizeof(sc->wi_stats)); 32046492Swpaul 32146492Swpaul wi_init(sc); 32246492Swpaul wi_stop(sc); 32346492Swpaul 32477217Sphk ifmedia_init(&sc->ifmedia, 0, wi_media_change, wi_media_status); 32577217Sphk /* XXX: Should read from card capabilities */ 32677217Sphk#define ADD(m, c) ifmedia_add(&sc->ifmedia, (m), (c), NULL) 32777217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 32877217Sphk IFM_IEEE80211_ADHOC, 0), 0); 32977217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 0, 0), 0); 33077217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 33177217Sphk IFM_IEEE80211_ADHOC, 0), 0); 33277217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 0, 0), 0); 33377217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 33477217Sphk IFM_IEEE80211_ADHOC, 0), 0); 33577217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 0, 0), 0); 33677217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 33777217Sphk IFM_IEEE80211_ADHOC, 0), 0); 33877217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 0, 0), 0); 33977217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 34077217Sphk IFM_IEEE80211_ADHOC, 0), 0); 34177217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0), 0); 34277217Sphk#undef ADD 34377217Sphk ifmedia_set(&sc->ifmedia, IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 34477217Sphk 0, 0)); 34577217Sphk 34677217Sphk 34746492Swpaul /* 34863090Sarchie * Call MI attach routine. 34946492Swpaul */ 35063090Sarchie ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 35153702Swpaul callout_handle_init(&sc->wi_stat_ch); 35267092Swpaul WI_UNLOCK(sc); 35346492Swpaul 35446492Swpaul return(0); 35546492Swpaul} 35646492Swpaul 35787383Simpstatic void 35893825Simpwi_get_id(sc) 35987383Simp struct wi_softc *sc; 36087383Simp{ 36187383Simp struct wi_ltv_ver ver; 36293825Simp struct wi_card_ident *id; 36387383Simp 36487383Simp /* getting chip identity */ 36587383Simp memset(&ver, 0, sizeof(ver)); 36693567Simp ver.wi_type = WI_RID_CARD_ID; 36787383Simp ver.wi_len = 5; 36887383Simp wi_read_record(sc, (struct wi_ltv_gen *)&ver); 36993733Simp device_printf(sc->dev, "using "); 37093825Simp sc->sc_firmware_type = WI_NOTYPE; 37193825Simp for (id = wi_card_ident; id->card_name != NULL; id++) { 37293825Simp if (le16toh(ver.wi_ver[0]) == id->card_id) { 37393825Simp printf("%s", id->card_name); 37493825Simp sc->sc_firmware_type = id->firm_type; 37593825Simp break; 37693825Simp } 37793825Simp } 37893825Simp if (sc->sc_firmware_type == WI_NOTYPE) { 37993825Simp if (le16toh(ver.wi_ver[0]) & 0x8000) { 38093733Simp printf("Unknown PRISM2 chip"); 38193825Simp sc->sc_firmware_type = WI_INTERSIL; 38293825Simp } else { 38393733Simp printf("Unknown Lucent chip"); 38493825Simp sc->sc_firmware_type = WI_LUCENT; 38593825Simp } 38687383Simp } 38787383Simp 38893733Simp if (sc->sc_firmware_type != WI_LUCENT) { 38993733Simp /* get primary firmware version */ 39093733Simp memset(&ver, 0, sizeof(ver)); 39193733Simp ver.wi_type = WI_RID_PRI_IDENTITY; 39293733Simp ver.wi_len = 5; 39393733Simp wi_read_record(sc, (struct wi_ltv_gen *)&ver); 39493733Simp ver.wi_ver[1] = le16toh(ver.wi_ver[1]); 39593733Simp ver.wi_ver[2] = le16toh(ver.wi_ver[2]); 39693733Simp ver.wi_ver[3] = le16toh(ver.wi_ver[3]); 39793733Simp sc->sc_pri_firmware_ver = ver.wi_ver[2] * 10000 + 39893733Simp ver.wi_ver[3] * 100 + ver.wi_ver[1]; 39993733Simp } 40093733Simp 40193733Simp /* get station firmware version */ 40292457Simp memset(&ver, 0, sizeof(ver)); 40392457Simp ver.wi_type = WI_RID_STA_IDENTITY; 40492457Simp ver.wi_len = 5; 40592457Simp wi_read_record(sc, (struct wi_ltv_gen *)&ver); 40692457Simp ver.wi_ver[1] = le16toh(ver.wi_ver[1]); 40792457Simp ver.wi_ver[2] = le16toh(ver.wi_ver[2]); 40892457Simp ver.wi_ver[3] = le16toh(ver.wi_ver[3]); 40993733Simp sc->sc_sta_firmware_ver = ver.wi_ver[2] * 10000 + 41093733Simp ver.wi_ver[3] * 100 + ver.wi_ver[1]; 41193733Simp if (sc->sc_firmware_type == WI_INTERSIL && 41293733Simp (sc->sc_sta_firmware_ver == 10102 || 41393733Simp sc->sc_sta_firmware_ver == 20102)) { 41493733Simp struct wi_ltv_str sver; 41593733Simp char *p; 41687383Simp 41793733Simp memset(&sver, 0, sizeof(sver)); 41893733Simp sver.wi_type = WI_RID_SYMBOL_IDENTITY; 41993733Simp sver.wi_len = 7; 42093733Simp /* value should be "V2.00-11" */ 42193733Simp if (wi_read_record(sc, (struct wi_ltv_gen *)&sver) == 0 && 42293733Simp *(p = (char *)sver.wi_str) == 'V' && 42393733Simp p[2] == '.' && p[5] == '-' && p[8] == '\0') { 42493733Simp sc->sc_firmware_type = WI_SYMBOL; 42593733Simp sc->sc_sta_firmware_ver = (p[1] - '0') * 10000 + 42693733Simp (p[3] - '0') * 1000 + (p[4] - '0') * 100 + 42793733Simp (p[6] - '0') * 10 + (p[7] - '0'); 42893733Simp } 42993733Simp } 43093733Simp printf("\n"); 43193733Simp device_printf(sc->dev, "%s Firmware: ", 43293733Simp sc->sc_firmware_type == WI_LUCENT ? "Lucent" : 43393733Simp (sc->sc_firmware_type == WI_SYMBOL ? "Symbol" : "Intersil")); 43493733Simp 43593733Simp /* 43693733Simp * The primary firmware is only valid on Prism based chipsets 43793733Simp * (INTERSIL or SYMBOL). 43893733Simp */ 43993733Simp if (sc->sc_firmware_type != WI_LUCENT) 44093733Simp printf("Primary %u.%02u.%02u, ", sc->sc_pri_firmware_ver / 10000, 44193733Simp (sc->sc_pri_firmware_ver % 10000) / 100, 44293733Simp sc->sc_pri_firmware_ver % 100); 44393733Simp printf("Station %u.%02u.%02u\n", 44493733Simp sc->sc_sta_firmware_ver / 10000, (sc->sc_sta_firmware_ver % 10000) / 100, 44593733Simp sc->sc_sta_firmware_ver % 100); 44687383Simp return; 44787383Simp} 44887383Simp 44988546Salfredstatic void 45088546Salfredwi_rxeof(sc) 45146492Swpaul struct wi_softc *sc; 45246492Swpaul{ 45346492Swpaul struct ifnet *ifp; 45446492Swpaul struct ether_header *eh; 45546492Swpaul struct mbuf *m; 45646492Swpaul int id; 45746492Swpaul 45846492Swpaul ifp = &sc->arpcom.ac_if; 45946492Swpaul 46046492Swpaul id = CSR_READ_2(sc, WI_RX_FID); 46146492Swpaul 46293359Simp /* 46393359Simp * if we have the procframe flag set, disregard all this and just 46493359Simp * read the data from the device. 46593359Simp */ 46693359Simp if (sc->wi_procframe || sc->wi_debug.wi_monitor) { 46793359Simp struct wi_frame *rx_frame; 46893359Simp int datlen, hdrlen; 46946492Swpaul 47093359Simp /* first allocate mbuf for packet storage */ 47193359Simp MGETHDR(m, M_DONTWAIT, MT_DATA); 47293359Simp if (m == NULL) { 47393359Simp ifp->if_ierrors++; 47493359Simp return; 47593359Simp } 47693359Simp MCLGET(m, M_DONTWAIT); 47793359Simp if (!(m->m_flags & M_EXT)) { 47893359Simp m_freem(m); 47993359Simp ifp->if_ierrors++; 48093359Simp return; 48193359Simp } 48246492Swpaul 48393359Simp m->m_pkthdr.rcvif = ifp; 48446492Swpaul 48593359Simp /* now read wi_frame first so we know how much data to read */ 48693359Simp if (wi_read_data(sc, id, 0, mtod(m, caddr_t), 48793359Simp sizeof(struct wi_frame))) { 48893359Simp m_freem(m); 48993359Simp ifp->if_ierrors++; 49093359Simp return; 49193359Simp } 49246492Swpaul 49393359Simp rx_frame = mtod(m, struct wi_frame *); 49493359Simp 49593359Simp switch ((rx_frame->wi_status & WI_STAT_MAC_PORT) >> 8) { 49693359Simp case 7: 49793359Simp switch (rx_frame->wi_frame_ctl & WI_FCTL_FTYPE) { 49893359Simp case WI_FTYPE_DATA: 49993359Simp hdrlen = WI_DATA_HDRLEN; 50093359Simp datlen = rx_frame->wi_dat_len + WI_FCS_LEN; 50193359Simp break; 50293359Simp case WI_FTYPE_MGMT: 50393359Simp hdrlen = WI_MGMT_HDRLEN; 50493359Simp datlen = rx_frame->wi_dat_len + WI_FCS_LEN; 50593359Simp break; 50693359Simp case WI_FTYPE_CTL: 50793359Simp /* 50893359Simp * prism2 cards don't pass control packets 50993359Simp * down properly or consistently, so we'll only 51093359Simp * pass down the header. 51193359Simp */ 51293359Simp hdrlen = WI_CTL_HDRLEN; 51393359Simp datlen = 0; 51493359Simp break; 51593359Simp default: 51693359Simp device_printf(sc->dev, "received packet of " 51793359Simp "unknown type on port 7\n"); 51893359Simp m_freem(m); 51993359Simp ifp->if_ierrors++; 52093359Simp return; 52193359Simp } 52293359Simp break; 52393359Simp case 0: 52493359Simp hdrlen = WI_DATA_HDRLEN; 52593359Simp datlen = rx_frame->wi_dat_len + WI_FCS_LEN; 52693359Simp break; 52793359Simp default: 52893359Simp device_printf(sc->dev, "received packet on invalid " 52993359Simp "port (wi_status=0x%x)\n", rx_frame->wi_status); 53093359Simp m_freem(m); 53193359Simp ifp->if_ierrors++; 53293359Simp return; 53393359Simp } 53493359Simp 53593359Simp if ((hdrlen + datlen + 2) > MCLBYTES) { 53653702Swpaul device_printf(sc->dev, "oversized packet received " 53753702Swpaul "(wi_dat_len=%d, wi_status=0x%x)\n", 53893359Simp datlen, rx_frame->wi_status); 53948553Swpaul m_freem(m); 54048553Swpaul ifp->if_ierrors++; 54148553Swpaul return; 54248553Swpaul } 54346492Swpaul 54493359Simp if (wi_read_data(sc, id, hdrlen, mtod(m, caddr_t) + hdrlen, 54593359Simp datlen + 2)) { 54693359Simp m_freem(m); 54793359Simp ifp->if_ierrors++; 54893359Simp return; 54959328Swpaul } 55075373Salfred 55193359Simp m->m_pkthdr.len = m->m_len = hdrlen + datlen; 55246492Swpaul 55393359Simp ifp->if_ipackets++; 55493359Simp 55593359Simp /* Handle BPF listeners. */ 55693359Simp if (ifp->if_bpf) 55793359Simp bpf_mtap(ifp, m); 55893359Simp 55993359Simp m_freem(m); 56093359Simp } else { 56193359Simp struct wi_frame rx_frame; 56293359Simp 56393359Simp /* First read in the frame header */ 56493359Simp if (wi_read_data(sc, id, 0, (caddr_t)&rx_frame, 56593359Simp sizeof(rx_frame))) { 56646492Swpaul ifp->if_ierrors++; 56746492Swpaul return; 56846492Swpaul } 56993359Simp 57093359Simp if (rx_frame.wi_status & WI_STAT_ERRSTAT) { 57148553Swpaul ifp->if_ierrors++; 57248553Swpaul return; 57348553Swpaul } 57446492Swpaul 57593359Simp MGETHDR(m, M_DONTWAIT, MT_DATA); 57693359Simp if (m == NULL) { 57793359Simp ifp->if_ierrors++; 57893359Simp return; 57993359Simp } 58093359Simp MCLGET(m, M_DONTWAIT); 58193359Simp if (!(m->m_flags & M_EXT)) { 58246492Swpaul m_freem(m); 58346492Swpaul ifp->if_ierrors++; 58446492Swpaul return; 58546492Swpaul } 58646492Swpaul 58793359Simp eh = mtod(m, struct ether_header *); 58893359Simp m->m_pkthdr.rcvif = ifp; 58946492Swpaul 59093359Simp if (rx_frame.wi_status == WI_STAT_1042 || 59193359Simp rx_frame.wi_status == WI_STAT_TUNNEL || 59293359Simp rx_frame.wi_status == WI_STAT_WMP_MSG) { 59393359Simp if((rx_frame.wi_dat_len + WI_SNAPHDR_LEN) > MCLBYTES) { 59493359Simp device_printf(sc->dev, 59593359Simp "oversized packet received " 59693359Simp "(wi_dat_len=%d, wi_status=0x%x)\n", 59793359Simp rx_frame.wi_dat_len, rx_frame.wi_status); 59893359Simp m_freem(m); 59993359Simp ifp->if_ierrors++; 60093359Simp return; 60193359Simp } 60293359Simp m->m_pkthdr.len = m->m_len = 60393359Simp rx_frame.wi_dat_len + WI_SNAPHDR_LEN; 60493359Simp 60593359Simp#if 0 60693359Simp bcopy((char *)&rx_frame.wi_addr1, 60793359Simp (char *)&eh->ether_dhost, ETHER_ADDR_LEN); 60893359Simp if (sc->wi_ptype == WI_PORTTYPE_ADHOC) { 60993359Simp bcopy((char *)&rx_frame.wi_addr2, 61093359Simp (char *)&eh->ether_shost, ETHER_ADDR_LEN); 61193359Simp } else { 61293359Simp bcopy((char *)&rx_frame.wi_addr3, 61393359Simp (char *)&eh->ether_shost, ETHER_ADDR_LEN); 61493359Simp } 61593359Simp#else 61693359Simp bcopy((char *)&rx_frame.wi_dst_addr, 61793359Simp (char *)&eh->ether_dhost, ETHER_ADDR_LEN); 61893359Simp bcopy((char *)&rx_frame.wi_src_addr, 61993359Simp (char *)&eh->ether_shost, ETHER_ADDR_LEN); 62093359Simp#endif 62193359Simp 62293359Simp bcopy((char *)&rx_frame.wi_type, 62393359Simp (char *)&eh->ether_type, ETHER_TYPE_LEN); 62493359Simp 62593359Simp if (wi_read_data(sc, id, WI_802_11_OFFSET, 62693359Simp mtod(m, caddr_t) + sizeof(struct ether_header), 62793359Simp m->m_len + 2)) { 62893359Simp m_freem(m); 62993359Simp ifp->if_ierrors++; 63093359Simp return; 63193359Simp } 63293359Simp } else { 63393359Simp if((rx_frame.wi_dat_len + 63493359Simp sizeof(struct ether_header)) > MCLBYTES) { 63593359Simp device_printf(sc->dev, 63693359Simp "oversized packet received " 63793359Simp "(wi_dat_len=%d, wi_status=0x%x)\n", 63893359Simp rx_frame.wi_dat_len, rx_frame.wi_status); 63993359Simp m_freem(m); 64093359Simp ifp->if_ierrors++; 64193359Simp return; 64293359Simp } 64393359Simp m->m_pkthdr.len = m->m_len = 64493359Simp rx_frame.wi_dat_len + sizeof(struct ether_header); 64593359Simp 64693359Simp if (wi_read_data(sc, id, WI_802_3_OFFSET, 64793359Simp mtod(m, caddr_t), m->m_len + 2)) { 64893359Simp m_freem(m); 64993359Simp ifp->if_ierrors++; 65093359Simp return; 65193359Simp } 65293359Simp } 65393359Simp 65493359Simp ifp->if_ipackets++; 65593359Simp 65693359Simp /* Receive packet. */ 65793359Simp m_adj(m, sizeof(struct ether_header)); 65853702Swpaul#ifdef WICACHE 65993359Simp wi_cache_store(sc, eh, m, rx_frame.wi_q_info); 66053702Swpaul#endif 66193359Simp ether_input(ifp, eh, m); 66293359Simp } 66346492Swpaul} 66446492Swpaul 66588546Salfredstatic void 66688546Salfredwi_txeof(sc, status) 66746492Swpaul struct wi_softc *sc; 66846492Swpaul int status; 66946492Swpaul{ 67046492Swpaul struct ifnet *ifp; 67146492Swpaul 67246492Swpaul ifp = &sc->arpcom.ac_if; 67346492Swpaul 67446492Swpaul ifp->if_timer = 0; 67546492Swpaul ifp->if_flags &= ~IFF_OACTIVE; 67646492Swpaul 67746492Swpaul if (status & WI_EV_TX_EXC) 67846492Swpaul ifp->if_oerrors++; 67946492Swpaul else 68046492Swpaul ifp->if_opackets++; 68146492Swpaul 68246492Swpaul return; 68346492Swpaul} 68446492Swpaul 68588546Salfredvoid 68688546Salfredwi_inquire(xsc) 68746492Swpaul void *xsc; 68846492Swpaul{ 68946492Swpaul struct wi_softc *sc; 69046492Swpaul struct ifnet *ifp; 69146492Swpaul 69246492Swpaul sc = xsc; 69346492Swpaul ifp = &sc->arpcom.ac_if; 69446492Swpaul 69546492Swpaul sc->wi_stat_ch = timeout(wi_inquire, sc, hz * 60); 69646492Swpaul 69746492Swpaul /* Don't do this while we're transmitting */ 69846492Swpaul if (ifp->if_flags & IFF_OACTIVE) 69946492Swpaul return; 70046492Swpaul 70192457Simp wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_COUNTERS, 0, 0); 70246492Swpaul 70346492Swpaul return; 70446492Swpaul} 70546492Swpaul 70688546Salfredvoid 70788546Salfredwi_update_stats(sc) 70846492Swpaul struct wi_softc *sc; 70946492Swpaul{ 71046492Swpaul struct wi_ltv_gen gen; 71146492Swpaul u_int16_t id; 71246492Swpaul struct ifnet *ifp; 71346492Swpaul u_int32_t *ptr; 71475373Salfred int len, i; 71546492Swpaul u_int16_t t; 71646492Swpaul 71746492Swpaul ifp = &sc->arpcom.ac_if; 71846492Swpaul 71946492Swpaul id = CSR_READ_2(sc, WI_INFO_FID); 72046492Swpaul 72146492Swpaul wi_read_data(sc, id, 0, (char *)&gen, 4); 72246492Swpaul 72393359Simp /* 72493359Simp * if we just got our scan results, copy it over into the scan buffer 72593359Simp * so we can return it to anyone that asks for it. (add a little 72693359Simp * compatibility with the prism2 scanning mechanism) 72793359Simp */ 72893359Simp if (gen.wi_type == WI_INFO_SCAN_RESULTS) 72993359Simp { 73093359Simp sc->wi_scanbuf_len = gen.wi_len; 73193359Simp wi_read_data(sc, id, 4, (char *)sc->wi_scanbuf, 73293359Simp sc->wi_scanbuf_len * 2); 73393359Simp 73446492Swpaul return; 73593359Simp } 73693359Simp else if (gen.wi_type != WI_INFO_COUNTERS) 73793359Simp return; 73846492Swpaul 73975373Salfred len = (gen.wi_len - 1 < sizeof(sc->wi_stats) / 4) ? 74075373Salfred gen.wi_len - 1 : sizeof(sc->wi_stats) / 4; 74146492Swpaul ptr = (u_int32_t *)&sc->wi_stats; 74246492Swpaul 74375373Salfred for (i = 0; i < len - 1; i++) { 74446492Swpaul t = CSR_READ_2(sc, WI_DATA1); 74546492Swpaul#ifdef WI_HERMES_STATS_WAR 74646492Swpaul if (t > 0xF000) 74746492Swpaul t = ~t & 0xFFFF; 74846492Swpaul#endif 74946492Swpaul ptr[i] += t; 75046492Swpaul } 75146492Swpaul 75246492Swpaul ifp->if_collisions = sc->wi_stats.wi_tx_single_retries + 75346492Swpaul sc->wi_stats.wi_tx_multi_retries + 75446492Swpaul sc->wi_stats.wi_tx_retry_limit; 75546492Swpaul 75646492Swpaul return; 75746492Swpaul} 75846492Swpaul 75988546Salfredstatic void 76088546Salfredwi_intr(xsc) 76153702Swpaul void *xsc; 76246492Swpaul{ 76353702Swpaul struct wi_softc *sc = xsc; 76446492Swpaul struct ifnet *ifp; 76546492Swpaul u_int16_t status; 76646492Swpaul 76767092Swpaul WI_LOCK(sc); 76867092Swpaul 76946492Swpaul ifp = &sc->arpcom.ac_if; 77046492Swpaul 77175373Salfred if (sc->wi_gone || !(ifp->if_flags & IFF_UP)) { 77246492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); 77346492Swpaul CSR_WRITE_2(sc, WI_INT_EN, 0); 77467092Swpaul WI_UNLOCK(sc); 77546492Swpaul return; 77646492Swpaul } 77746492Swpaul 77846492Swpaul /* Disable interrupts. */ 77946492Swpaul CSR_WRITE_2(sc, WI_INT_EN, 0); 78046492Swpaul 78146492Swpaul status = CSR_READ_2(sc, WI_EVENT_STAT); 78246492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, ~WI_INTRS); 78346492Swpaul 78446492Swpaul if (status & WI_EV_RX) { 78546492Swpaul wi_rxeof(sc); 78646492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX); 78746492Swpaul } 78846492Swpaul 78946492Swpaul if (status & WI_EV_TX) { 79046492Swpaul wi_txeof(sc, status); 79146492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX); 79246492Swpaul } 79346492Swpaul 79446492Swpaul if (status & WI_EV_ALLOC) { 79546492Swpaul int id; 79675373Salfred 79746492Swpaul id = CSR_READ_2(sc, WI_ALLOC_FID); 79846492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC); 79946492Swpaul if (id == sc->wi_tx_data_id) 80046492Swpaul wi_txeof(sc, status); 80146492Swpaul } 80246492Swpaul 80346492Swpaul if (status & WI_EV_INFO) { 80446492Swpaul wi_update_stats(sc); 80546492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO); 80646492Swpaul } 80746492Swpaul 80846492Swpaul if (status & WI_EV_TX_EXC) { 80946492Swpaul wi_txeof(sc, status); 81046492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX_EXC); 81146492Swpaul } 81246492Swpaul 81346492Swpaul if (status & WI_EV_INFO_DROP) { 81446492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO_DROP); 81546492Swpaul } 81646492Swpaul 81746492Swpaul /* Re-enable interrupts. */ 81846492Swpaul CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS); 81946492Swpaul 82075373Salfred if (ifp->if_snd.ifq_head != NULL) { 82146492Swpaul wi_start(ifp); 82275373Salfred } 82346492Swpaul 82467092Swpaul WI_UNLOCK(sc); 82567092Swpaul 82646492Swpaul return; 82746492Swpaul} 82846492Swpaul 82988546Salfredstatic int 83092457Simpwi_cmd(sc, cmd, val0, val1, val2) 83146492Swpaul struct wi_softc *sc; 83246492Swpaul int cmd; 83392457Simp int val0; 83492457Simp int val1; 83592457Simp int val2; 83646492Swpaul{ 83746492Swpaul int i, s = 0; 83846492Swpaul 83970073Swpaul /* wait for the busy bit to clear */ 84075331Simp for (i = 500; i > 0; i--) { /* 5s */ 84170073Swpaul if (!(CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY)) { 84270073Swpaul break; 84370073Swpaul } 84470073Swpaul DELAY(10*1000); /* 10 m sec */ 84570073Swpaul } 84675229Salfred if (i == 0) { 84790580Sbrooks device_printf(sc->dev, "wi_cmd: busy bit won't clear.\n" ); 84870073Swpaul return(ETIMEDOUT); 84970073Swpaul } 85070073Swpaul 85192457Simp CSR_WRITE_2(sc, WI_PARAM0, val0); 85292457Simp CSR_WRITE_2(sc, WI_PARAM1, val1); 85392457Simp CSR_WRITE_2(sc, WI_PARAM2, val2); 85446492Swpaul CSR_WRITE_2(sc, WI_COMMAND, cmd); 85546492Swpaul 85646492Swpaul for (i = 0; i < WI_TIMEOUT; i++) { 85746492Swpaul /* 85846492Swpaul * Wait for 'command complete' bit to be 85946492Swpaul * set in the event status register. 86046492Swpaul */ 86190580Sbrooks s = CSR_READ_2(sc, WI_EVENT_STAT); 86290580Sbrooks if (s & WI_EV_CMD) { 86346492Swpaul /* Ack the event and read result code. */ 86446492Swpaul s = CSR_READ_2(sc, WI_STATUS); 86546492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD); 86646492Swpaul#ifdef foo 86746492Swpaul if ((s & WI_CMD_CODE_MASK) != (cmd & WI_CMD_CODE_MASK)) 86846492Swpaul return(EIO); 86946492Swpaul#endif 87046492Swpaul if (s & WI_STAT_CMD_RESULT) 87146492Swpaul return(EIO); 87246492Swpaul break; 87346492Swpaul } 87490580Sbrooks DELAY(WI_DELAY); 87546492Swpaul } 87646492Swpaul 87790580Sbrooks if (i == WI_TIMEOUT) { 87890580Sbrooks device_printf(sc->dev, 87992457Simp "timeout in wi_cmd 0x%04x; event status 0x%04x\n", cmd, s); 88046492Swpaul return(ETIMEDOUT); 88190580Sbrooks } 88246492Swpaul 88346492Swpaul return(0); 88446492Swpaul} 88546492Swpaul 88688546Salfredstatic void 88788546Salfredwi_reset(sc) 88846492Swpaul struct wi_softc *sc; 88946492Swpaul{ 89075331Simp#define WI_INIT_TRIES 5 89175150Simp int i; 89293733Simp int tries; 89375149Simp 89493733Simp /* Symbol firmware cannot be initialized more than once */ 89593733Simp if (sc->sc_firmware_type == WI_SYMBOL && sc->sc_enabled) 89693733Simp return; 89793733Simp if (sc->sc_firmware_type == WI_SYMBOL) 89893733Simp tries = 1; 89993733Simp else 90093733Simp tries = WI_INIT_TRIES; 90193733Simp 90293733Simp for (i = 0; i < tries; i++) { 90392457Simp if (wi_cmd(sc, WI_CMD_INI, 0, 0, 0) == 0) 90475149Simp break; 90590580Sbrooks DELAY(WI_DELAY * 1000); 90675149Simp } 90775331Simp if (i == WI_INIT_TRIES) 90853702Swpaul device_printf(sc->dev, "init failed\n"); 90975373Salfred 91046492Swpaul CSR_WRITE_2(sc, WI_INT_EN, 0); 91146492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); 91246492Swpaul 91346492Swpaul /* Calibrate timer. */ 91446492Swpaul WI_SETVAL(WI_RID_TICK_TIME, 8); 91570073Swpaul 91693733Simp sc->sc_enabled = 1; 91793733Simp 91846492Swpaul return; 91946492Swpaul} 92046492Swpaul 92146492Swpaul/* 92246492Swpaul * Read an LTV record from the NIC. 92346492Swpaul */ 92488546Salfredstatic int 92588546Salfredwi_read_record(sc, ltv) 92646492Swpaul struct wi_softc *sc; 92746492Swpaul struct wi_ltv_gen *ltv; 92846492Swpaul{ 92946492Swpaul u_int16_t *ptr; 93046492Swpaul int i, len, code; 93170073Swpaul struct wi_ltv_gen *oltv, p2ltv; 93246492Swpaul 93370073Swpaul oltv = ltv; 93493733Simp if (sc->sc_firmware_type != WI_LUCENT) { 93570073Swpaul switch (ltv->wi_type) { 93670073Swpaul case WI_RID_ENCRYPTION: 93770073Swpaul p2ltv.wi_type = WI_RID_P2_ENCRYPTION; 93870073Swpaul p2ltv.wi_len = 2; 93970073Swpaul ltv = &p2ltv; 94070073Swpaul break; 94170073Swpaul case WI_RID_TX_CRYPT_KEY: 94270073Swpaul p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY; 94370073Swpaul p2ltv.wi_len = 2; 94470073Swpaul ltv = &p2ltv; 94570073Swpaul break; 94670073Swpaul } 94770073Swpaul } 94870073Swpaul 94946492Swpaul /* Tell the NIC to enter record read mode. */ 95092457Simp if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_READ, ltv->wi_type, 0, 0)) 95146492Swpaul return(EIO); 95246492Swpaul 95347789Swpaul /* Seek to the record. */ 95447789Swpaul if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1)) 95547789Swpaul return(EIO); 95646492Swpaul 95746492Swpaul /* 95846492Swpaul * Read the length and record type and make sure they 95946492Swpaul * match what we expect (this verifies that we have enough 96047401Swpaul * room to hold all of the returned data). 96146492Swpaul */ 96246492Swpaul len = CSR_READ_2(sc, WI_DATA1); 96346492Swpaul if (len > ltv->wi_len) 96446492Swpaul return(ENOSPC); 96546492Swpaul code = CSR_READ_2(sc, WI_DATA1); 96646492Swpaul if (code != ltv->wi_type) 96746492Swpaul return(EIO); 96846492Swpaul 96946492Swpaul ltv->wi_len = len; 97046492Swpaul ltv->wi_type = code; 97146492Swpaul 97246492Swpaul /* Now read the data. */ 97346492Swpaul ptr = <v->wi_val; 97446492Swpaul for (i = 0; i < ltv->wi_len - 1; i++) 97546492Swpaul ptr[i] = CSR_READ_2(sc, WI_DATA1); 97646492Swpaul 97793733Simp if (sc->sc_firmware_type != WI_LUCENT) { 97870073Swpaul switch (oltv->wi_type) { 97970073Swpaul case WI_RID_TX_RATE: 98070073Swpaul case WI_RID_CUR_TX_RATE: 98170073Swpaul switch (ltv->wi_val) { 98270073Swpaul case 1: oltv->wi_val = 1; break; 98370073Swpaul case 2: oltv->wi_val = 2; break; 98470073Swpaul case 3: oltv->wi_val = 6; break; 98570073Swpaul case 4: oltv->wi_val = 5; break; 98670073Swpaul case 7: oltv->wi_val = 7; break; 98770073Swpaul case 8: oltv->wi_val = 11; break; 98870073Swpaul case 15: oltv->wi_val = 3; break; 98970073Swpaul default: oltv->wi_val = 0x100 + ltv->wi_val; break; 99070073Swpaul } 99170073Swpaul break; 99270073Swpaul case WI_RID_ENCRYPTION: 99370073Swpaul oltv->wi_len = 2; 99470073Swpaul if (ltv->wi_val & 0x01) 99570073Swpaul oltv->wi_val = 1; 99670073Swpaul else 99770073Swpaul oltv->wi_val = 0; 99870073Swpaul break; 99970073Swpaul case WI_RID_TX_CRYPT_KEY: 100070073Swpaul oltv->wi_len = 2; 100170073Swpaul oltv->wi_val = ltv->wi_val; 100270073Swpaul break; 100391695Simp case WI_RID_AUTH_CNTL: 100491695Simp oltv->wi_len = 2; 100591695Simp if (le16toh(ltv->wi_val) & 0x01) 100691695Simp oltv->wi_val = htole16(1); 100791695Simp else if (le16toh(ltv->wi_val) & 0x02) 100891695Simp oltv->wi_val = htole16(2); 100991695Simp break; 101070073Swpaul } 101170073Swpaul } 101270073Swpaul 101346492Swpaul return(0); 101446492Swpaul} 101546492Swpaul 101646492Swpaul/* 101746492Swpaul * Same as read, except we inject data instead of reading it. 101846492Swpaul */ 101988546Salfredstatic int 102088546Salfredwi_write_record(sc, ltv) 102146492Swpaul struct wi_softc *sc; 102246492Swpaul struct wi_ltv_gen *ltv; 102346492Swpaul{ 102446492Swpaul u_int16_t *ptr; 102546492Swpaul int i; 102670073Swpaul struct wi_ltv_gen p2ltv; 102746492Swpaul 102893733Simp if (sc->sc_firmware_type != WI_LUCENT) { 102970073Swpaul switch (ltv->wi_type) { 103070073Swpaul case WI_RID_TX_RATE: 103170073Swpaul p2ltv.wi_type = WI_RID_TX_RATE; 103270073Swpaul p2ltv.wi_len = 2; 103370073Swpaul switch (ltv->wi_val) { 103470073Swpaul case 1: p2ltv.wi_val = 1; break; 103570073Swpaul case 2: p2ltv.wi_val = 2; break; 103670073Swpaul case 3: p2ltv.wi_val = 15; break; 103770073Swpaul case 5: p2ltv.wi_val = 4; break; 103870073Swpaul case 6: p2ltv.wi_val = 3; break; 103970073Swpaul case 7: p2ltv.wi_val = 7; break; 104070073Swpaul case 11: p2ltv.wi_val = 8; break; 104170073Swpaul default: return EINVAL; 104270073Swpaul } 104370073Swpaul ltv = &p2ltv; 104470073Swpaul break; 104570073Swpaul case WI_RID_ENCRYPTION: 104670073Swpaul p2ltv.wi_type = WI_RID_P2_ENCRYPTION; 104770073Swpaul p2ltv.wi_len = 2; 104893825Simp if (le16toh(ltv->wi_val)) 104993825Simp p2ltv.wi_val =htole16(PRIVACY_INVOKED | 105093825Simp EXCLUDE_UNENCRYPTED); 105170073Swpaul else 105293825Simp p2ltv.wi_val = 105393825Simp htole16(HOST_ENCRYPT | HOST_DECRYPT); 105470073Swpaul ltv = &p2ltv; 105570073Swpaul break; 105670073Swpaul case WI_RID_TX_CRYPT_KEY: 105770073Swpaul p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY; 105870073Swpaul p2ltv.wi_len = 2; 105970073Swpaul p2ltv.wi_val = ltv->wi_val; 106070073Swpaul ltv = &p2ltv; 106170073Swpaul break; 106270073Swpaul case WI_RID_DEFLT_CRYPT_KEYS: 106370073Swpaul { 106470073Swpaul int error; 106591548Sbrooks int keylen; 106670073Swpaul struct wi_ltv_str ws; 106774998Swpaul struct wi_ltv_keys *wk = 106874998Swpaul (struct wi_ltv_keys *)ltv; 106974998Swpaul 107091548Sbrooks keylen = wk->wi_keys[sc->wi_tx_key].wi_keylen; 107191548Sbrooks 107270073Swpaul for (i = 0; i < 4; i++) { 107391548Sbrooks bzero(&ws, sizeof(ws)); 107491548Sbrooks ws.wi_len = (keylen > 5) ? 8 : 4; 107570073Swpaul ws.wi_type = WI_RID_P2_CRYPT_KEY0 + i; 107674998Swpaul memcpy(ws.wi_str, 107791548Sbrooks &wk->wi_keys[i].wi_keydat, keylen); 107870073Swpaul error = wi_write_record(sc, 107970073Swpaul (struct wi_ltv_gen *)&ws); 108070073Swpaul if (error) 108170073Swpaul return error; 108270073Swpaul } 108370073Swpaul return 0; 108470073Swpaul } 108591695Simp case WI_RID_AUTH_CNTL: 108691695Simp p2ltv.wi_type = WI_RID_AUTH_CNTL; 108791695Simp p2ltv.wi_len = 2; 108891695Simp if (le16toh(ltv->wi_val) == 1) 108991695Simp p2ltv.wi_val = htole16(0x01); 109091695Simp else if (le16toh(ltv->wi_val) == 2) 109191695Simp p2ltv.wi_val = htole16(0x02); 109291695Simp ltv = &p2ltv; 109391695Simp break; 109470073Swpaul } 109570073Swpaul } 109670073Swpaul 109747789Swpaul if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1)) 109847789Swpaul return(EIO); 109946492Swpaul 110046492Swpaul CSR_WRITE_2(sc, WI_DATA1, ltv->wi_len); 110146492Swpaul CSR_WRITE_2(sc, WI_DATA1, ltv->wi_type); 110246492Swpaul 110346492Swpaul ptr = <v->wi_val; 110446492Swpaul for (i = 0; i < ltv->wi_len - 1; i++) 110546492Swpaul CSR_WRITE_2(sc, WI_DATA1, ptr[i]); 110646492Swpaul 110792457Simp if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_WRITE, ltv->wi_type, 0, 0)) 110846492Swpaul return(EIO); 110946492Swpaul 111046492Swpaul return(0); 111146492Swpaul} 111246492Swpaul 111388546Salfredstatic int 111488546Salfredwi_seek(sc, id, off, chan) 111546492Swpaul struct wi_softc *sc; 111646492Swpaul int id, off, chan; 111746492Swpaul{ 111846492Swpaul int i; 111946492Swpaul int selreg, offreg; 112075373Salfred int status; 112146492Swpaul 112246492Swpaul switch (chan) { 112346492Swpaul case WI_BAP0: 112446492Swpaul selreg = WI_SEL0; 112546492Swpaul offreg = WI_OFF0; 112646492Swpaul break; 112746492Swpaul case WI_BAP1: 112846492Swpaul selreg = WI_SEL1; 112946492Swpaul offreg = WI_OFF1; 113046492Swpaul break; 113146492Swpaul default: 113253702Swpaul device_printf(sc->dev, "invalid data path: %x\n", chan); 113346492Swpaul return(EIO); 113446492Swpaul } 113546492Swpaul 113646492Swpaul CSR_WRITE_2(sc, selreg, id); 113746492Swpaul CSR_WRITE_2(sc, offreg, off); 113846492Swpaul 113946492Swpaul for (i = 0; i < WI_TIMEOUT; i++) { 114075373Salfred status = CSR_READ_2(sc, offreg); 114175373Salfred if (!(status & (WI_OFF_BUSY|WI_OFF_ERR))) 114246492Swpaul break; 114390580Sbrooks DELAY(WI_DELAY); 114446492Swpaul } 114546492Swpaul 114675373Salfred if (i == WI_TIMEOUT) { 114775373Salfred device_printf(sc->dev, "timeout in wi_seek to %x/%x; last status %x\n", 114875373Salfred id, off, status); 114946492Swpaul return(ETIMEDOUT); 115075373Salfred } 115146492Swpaul 115246492Swpaul return(0); 115346492Swpaul} 115446492Swpaul 115588546Salfredstatic int 115688546Salfredwi_read_data(sc, id, off, buf, len) 115746492Swpaul struct wi_softc *sc; 115846492Swpaul int id, off; 115946492Swpaul caddr_t buf; 116046492Swpaul int len; 116146492Swpaul{ 116246492Swpaul int i; 116346492Swpaul u_int16_t *ptr; 116446492Swpaul 116546492Swpaul if (wi_seek(sc, id, off, WI_BAP1)) 116646492Swpaul return(EIO); 116746492Swpaul 116846492Swpaul ptr = (u_int16_t *)buf; 116946492Swpaul for (i = 0; i < len / 2; i++) 117046492Swpaul ptr[i] = CSR_READ_2(sc, WI_DATA1); 117146492Swpaul 117246492Swpaul return(0); 117346492Swpaul} 117446492Swpaul 117546492Swpaul/* 117646492Swpaul * According to the comments in the HCF Light code, there is a bug in 117746492Swpaul * the Hermes (or possibly in certain Hermes firmware revisions) where 117846492Swpaul * the chip's internal autoincrement counter gets thrown off during 117946492Swpaul * data writes: the autoincrement is missed, causing one data word to 118046492Swpaul * be overwritten and subsequent words to be written to the wrong memory 118146492Swpaul * locations. The end result is that we could end up transmitting bogus 118246492Swpaul * frames without realizing it. The workaround for this is to write a 118346492Swpaul * couple of extra guard words after the end of the transfer, then 118446492Swpaul * attempt to read then back. If we fail to locate the guard words where 118546492Swpaul * we expect them, we preform the transfer over again. 118646492Swpaul */ 118788546Salfredstatic int 118888546Salfredwi_write_data(sc, id, off, buf, len) 118946492Swpaul struct wi_softc *sc; 119046492Swpaul int id, off; 119146492Swpaul caddr_t buf; 119246492Swpaul int len; 119346492Swpaul{ 119446492Swpaul int i; 119546492Swpaul u_int16_t *ptr; 119674838Salfred#ifdef WI_HERMES_AUTOINC_WAR 119774838Salfred int retries; 119846492Swpaul 119975373Salfred retries = 512; 120046492Swpaulagain: 120146492Swpaul#endif 120246492Swpaul 120346492Swpaul if (wi_seek(sc, id, off, WI_BAP0)) 120446492Swpaul return(EIO); 120546492Swpaul 120646492Swpaul ptr = (u_int16_t *)buf; 120746492Swpaul for (i = 0; i < (len / 2); i++) 120846492Swpaul CSR_WRITE_2(sc, WI_DATA0, ptr[i]); 120946492Swpaul 121046492Swpaul#ifdef WI_HERMES_AUTOINC_WAR 121146492Swpaul CSR_WRITE_2(sc, WI_DATA0, 0x1234); 121246492Swpaul CSR_WRITE_2(sc, WI_DATA0, 0x5678); 121346492Swpaul 121446492Swpaul if (wi_seek(sc, id, off + len, WI_BAP0)) 121546492Swpaul return(EIO); 121646492Swpaul 121746492Swpaul if (CSR_READ_2(sc, WI_DATA0) != 0x1234 || 121874998Swpaul CSR_READ_2(sc, WI_DATA0) != 0x5678) { 121974838Salfred if (--retries >= 0) 122074838Salfred goto again; 122174838Salfred device_printf(sc->dev, "wi_write_data device timeout\n"); 122274838Salfred return (EIO); 122374838Salfred } 122446492Swpaul#endif 122546492Swpaul 122646492Swpaul return(0); 122746492Swpaul} 122846492Swpaul 122946492Swpaul/* 123046492Swpaul * Allocate a region of memory inside the NIC and zero 123146492Swpaul * it out. 123246492Swpaul */ 123388546Salfredstatic int 123488546Salfredwi_alloc_nicmem(sc, len, id) 123546492Swpaul struct wi_softc *sc; 123646492Swpaul int len; 123746492Swpaul int *id; 123846492Swpaul{ 123946492Swpaul int i; 124046492Swpaul 124192457Simp if (wi_cmd(sc, WI_CMD_ALLOC_MEM, len, 0, 0)) { 124274998Swpaul device_printf(sc->dev, 124374998Swpaul "failed to allocate %d bytes on NIC\n", len); 124446492Swpaul return(ENOMEM); 124546492Swpaul } 124646492Swpaul 124746492Swpaul for (i = 0; i < WI_TIMEOUT; i++) { 124846492Swpaul if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_ALLOC) 124946492Swpaul break; 125090580Sbrooks DELAY(WI_DELAY); 125146492Swpaul } 125246492Swpaul 125375373Salfred if (i == WI_TIMEOUT) { 125475373Salfred device_printf(sc->dev, "time out allocating memory on card\n"); 125546492Swpaul return(ETIMEDOUT); 125675373Salfred } 125746492Swpaul 125846492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC); 125946492Swpaul *id = CSR_READ_2(sc, WI_ALLOC_FID); 126046492Swpaul 126175373Salfred if (wi_seek(sc, *id, 0, WI_BAP0)) { 126275373Salfred device_printf(sc->dev, "seek failed while allocating memory on card\n"); 126347789Swpaul return(EIO); 126475373Salfred } 126546492Swpaul 126646492Swpaul for (i = 0; i < len / 2; i++) 126746492Swpaul CSR_WRITE_2(sc, WI_DATA0, 0); 126846492Swpaul 126946492Swpaul return(0); 127046492Swpaul} 127146492Swpaul 127288546Salfredstatic void 127388546Salfredwi_setmulti(sc) 127446492Swpaul struct wi_softc *sc; 127546492Swpaul{ 127646492Swpaul struct ifnet *ifp; 127746492Swpaul int i = 0; 127846492Swpaul struct ifmultiaddr *ifma; 127946492Swpaul struct wi_ltv_mcast mcast; 128046492Swpaul 128146492Swpaul ifp = &sc->arpcom.ac_if; 128246492Swpaul 128346492Swpaul bzero((char *)&mcast, sizeof(mcast)); 128446492Swpaul 128593756Simp mcast.wi_type = WI_RID_MCAST_LIST; 128646492Swpaul mcast.wi_len = (3 * 16) + 1; 128746492Swpaul 128846492Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 128946492Swpaul wi_write_record(sc, (struct wi_ltv_gen *)&mcast); 129046492Swpaul return; 129146492Swpaul } 129246492Swpaul 129372084Sphk TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 129446492Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 129546492Swpaul continue; 129646492Swpaul if (i < 16) { 129746492Swpaul bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 129846492Swpaul (char *)&mcast.wi_mcast[i], ETHER_ADDR_LEN); 129946492Swpaul i++; 130046492Swpaul } else { 130146492Swpaul bzero((char *)&mcast, sizeof(mcast)); 130246492Swpaul break; 130346492Swpaul } 130446492Swpaul } 130546492Swpaul 130646492Swpaul mcast.wi_len = (i * 3) + 1; 130746492Swpaul wi_write_record(sc, (struct wi_ltv_gen *)&mcast); 130846492Swpaul 130946492Swpaul return; 131046492Swpaul} 131146492Swpaul 131288546Salfredstatic void 131388546Salfredwi_setdef(sc, wreq) 131446492Swpaul struct wi_softc *sc; 131546492Swpaul struct wi_req *wreq; 131646492Swpaul{ 131746492Swpaul struct sockaddr_dl *sdl; 131846492Swpaul struct ifaddr *ifa; 131946492Swpaul struct ifnet *ifp; 132046492Swpaul 132146492Swpaul ifp = &sc->arpcom.ac_if; 132246492Swpaul 132346492Swpaul switch(wreq->wi_type) { 132446492Swpaul case WI_RID_MAC_NODE: 132583130Sjlemon ifa = ifaddr_byindex(ifp->if_index); 132646492Swpaul sdl = (struct sockaddr_dl *)ifa->ifa_addr; 132746492Swpaul bcopy((char *)&wreq->wi_val, (char *)&sc->arpcom.ac_enaddr, 132846492Swpaul ETHER_ADDR_LEN); 132946492Swpaul bcopy((char *)&wreq->wi_val, LLADDR(sdl), ETHER_ADDR_LEN); 133046492Swpaul break; 133146492Swpaul case WI_RID_PORTTYPE: 133291695Simp sc->wi_ptype = le16toh(wreq->wi_val[0]); 133346492Swpaul break; 133446492Swpaul case WI_RID_TX_RATE: 133591695Simp sc->wi_tx_rate = le16toh(wreq->wi_val[0]); 133646492Swpaul break; 133746492Swpaul case WI_RID_MAX_DATALEN: 133891695Simp sc->wi_max_data_len = le16toh(wreq->wi_val[0]); 133946492Swpaul break; 134046492Swpaul case WI_RID_RTS_THRESH: 134191695Simp sc->wi_rts_thresh = le16toh(wreq->wi_val[0]); 134246492Swpaul break; 134346492Swpaul case WI_RID_SYSTEM_SCALE: 134491695Simp sc->wi_ap_density = le16toh(wreq->wi_val[0]); 134546492Swpaul break; 134646492Swpaul case WI_RID_CREATE_IBSS: 134791695Simp sc->wi_create_ibss = le16toh(wreq->wi_val[0]); 134846492Swpaul break; 134946563Swpaul case WI_RID_OWN_CHNL: 135091695Simp sc->wi_channel = le16toh(wreq->wi_val[0]); 135146563Swpaul break; 135246492Swpaul case WI_RID_NODENAME: 135346492Swpaul bzero(sc->wi_node_name, sizeof(sc->wi_node_name)); 135446492Swpaul bcopy((char *)&wreq->wi_val[1], sc->wi_node_name, 30); 135546492Swpaul break; 135646492Swpaul case WI_RID_DESIRED_SSID: 135746492Swpaul bzero(sc->wi_net_name, sizeof(sc->wi_net_name)); 135846492Swpaul bcopy((char *)&wreq->wi_val[1], sc->wi_net_name, 30); 135946492Swpaul break; 136046492Swpaul case WI_RID_OWN_SSID: 136146492Swpaul bzero(sc->wi_ibss_name, sizeof(sc->wi_ibss_name)); 136246492Swpaul bcopy((char *)&wreq->wi_val[1], sc->wi_ibss_name, 30); 136346492Swpaul break; 136446611Swpaul case WI_RID_PM_ENABLED: 136591695Simp sc->wi_pm_enabled = le16toh(wreq->wi_val[0]); 136646611Swpaul break; 136791695Simp case WI_RID_MICROWAVE_OVEN: 136891695Simp sc->wi_mor_enabled = le16toh(wreq->wi_val[0]); 136991695Simp break; 137046611Swpaul case WI_RID_MAX_SLEEP: 137191695Simp sc->wi_max_sleep = le16toh(wreq->wi_val[0]); 137246611Swpaul break; 137391695Simp case WI_RID_AUTH_CNTL: 137491695Simp sc->wi_authtype = le16toh(wreq->wi_val[0]); 137591695Simp break; 137691695Simp case WI_RID_ROAMING_MODE: 137791695Simp sc->wi_roaming = le16toh(wreq->wi_val[0]); 137891695Simp break; 137956965Swpaul case WI_RID_ENCRYPTION: 138091695Simp sc->wi_use_wep = le16toh(wreq->wi_val[0]); 138156965Swpaul break; 138256965Swpaul case WI_RID_TX_CRYPT_KEY: 138391695Simp sc->wi_tx_key = le16toh(wreq->wi_val[0]); 138456965Swpaul break; 138556965Swpaul case WI_RID_DEFLT_CRYPT_KEYS: 138656965Swpaul bcopy((char *)wreq, (char *)&sc->wi_keys, 138756965Swpaul sizeof(struct wi_ltv_keys)); 138856965Swpaul break; 138946492Swpaul default: 139046492Swpaul break; 139146492Swpaul } 139246492Swpaul 139346563Swpaul /* Reinitialize WaveLAN. */ 139446563Swpaul wi_init(sc); 139546563Swpaul 139646492Swpaul return; 139746492Swpaul} 139846492Swpaul 139988546Salfredstatic int 140088546Salfredwi_ioctl(ifp, command, data) 140146492Swpaul struct ifnet *ifp; 140246492Swpaul u_long command; 140346492Swpaul caddr_t data; 140446492Swpaul{ 140567092Swpaul int error = 0; 140677217Sphk int len; 140777217Sphk u_int8_t tmpkey[14]; 140877217Sphk char tmpssid[IEEE80211_NWID_LEN]; 140946492Swpaul struct wi_softc *sc; 141046492Swpaul struct wi_req wreq; 141146492Swpaul struct ifreq *ifr; 141277217Sphk struct ieee80211req *ireq; 141393593Sjhb struct thread *td = curthread; 141446492Swpaul 141546492Swpaul sc = ifp->if_softc; 141667092Swpaul WI_LOCK(sc); 141746492Swpaul ifr = (struct ifreq *)data; 141877217Sphk ireq = (struct ieee80211req *)data; 141946492Swpaul 142061818Sroberto if (sc->wi_gone) { 142161818Sroberto error = ENODEV; 142261818Sroberto goto out; 142361818Sroberto } 142446492Swpaul 142546492Swpaul switch(command) { 142646492Swpaul case SIOCSIFADDR: 142746492Swpaul case SIOCGIFADDR: 142846492Swpaul case SIOCSIFMTU: 142946492Swpaul error = ether_ioctl(ifp, command, data); 143046492Swpaul break; 143146492Swpaul case SIOCSIFFLAGS: 143246492Swpaul if (ifp->if_flags & IFF_UP) { 143346492Swpaul if (ifp->if_flags & IFF_RUNNING && 143446492Swpaul ifp->if_flags & IFF_PROMISC && 143546492Swpaul !(sc->wi_if_flags & IFF_PROMISC)) { 143646492Swpaul WI_SETVAL(WI_RID_PROMISC, 1); 143746492Swpaul } else if (ifp->if_flags & IFF_RUNNING && 143846492Swpaul !(ifp->if_flags & IFF_PROMISC) && 143946492Swpaul sc->wi_if_flags & IFF_PROMISC) { 144046492Swpaul WI_SETVAL(WI_RID_PROMISC, 0); 144146492Swpaul } else 144246492Swpaul wi_init(sc); 144346492Swpaul } else { 144446492Swpaul if (ifp->if_flags & IFF_RUNNING) { 144546492Swpaul wi_stop(sc); 144646492Swpaul } 144746492Swpaul } 144846492Swpaul sc->wi_if_flags = ifp->if_flags; 144946492Swpaul error = 0; 145046492Swpaul break; 145177217Sphk case SIOCSIFMEDIA: 145277217Sphk case SIOCGIFMEDIA: 145377217Sphk error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); 145477217Sphk break; 145546492Swpaul case SIOCADDMULTI: 145646492Swpaul case SIOCDELMULTI: 145746492Swpaul wi_setmulti(sc); 145846492Swpaul error = 0; 145946492Swpaul break; 146046492Swpaul case SIOCGWAVELAN: 146146492Swpaul error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); 146246492Swpaul if (error) 146346492Swpaul break; 146465581Swpaul /* Don't show WEP keys to non-root users. */ 146593593Sjhb if (wreq.wi_type == WI_RID_DEFLT_CRYPT_KEYS && suser(td)) 146665581Swpaul break; 146746492Swpaul if (wreq.wi_type == WI_RID_IFACE_STATS) { 146846492Swpaul bcopy((char *)&sc->wi_stats, (char *)&wreq.wi_val, 146946492Swpaul sizeof(sc->wi_stats)); 147046492Swpaul wreq.wi_len = (sizeof(sc->wi_stats) / 2) + 1; 147156965Swpaul } else if (wreq.wi_type == WI_RID_DEFLT_CRYPT_KEYS) { 147256965Swpaul bcopy((char *)&sc->wi_keys, (char *)&wreq, 147356965Swpaul sizeof(struct wi_ltv_keys)); 147453702Swpaul } 147553702Swpaul#ifdef WICACHE 147653702Swpaul else if (wreq.wi_type == WI_RID_ZERO_CACHE) { 147753702Swpaul sc->wi_sigitems = sc->wi_nextitem = 0; 147853702Swpaul } else if (wreq.wi_type == WI_RID_READ_CACHE) { 147953702Swpaul char *pt = (char *)&wreq.wi_val; 148053702Swpaul bcopy((char *)&sc->wi_sigitems, 148153702Swpaul (char *)pt, sizeof(int)); 148253702Swpaul pt += (sizeof (int)); 148353702Swpaul wreq.wi_len = sizeof(int) / 2; 148453702Swpaul bcopy((char *)&sc->wi_sigcache, (char *)pt, 148553702Swpaul sizeof(struct wi_sigcache) * sc->wi_sigitems); 148653702Swpaul wreq.wi_len += ((sizeof(struct wi_sigcache) * 148753702Swpaul sc->wi_sigitems) / 2) + 1; 148853702Swpaul } 148953702Swpaul#endif 149093359Simp else if (wreq.wi_type == WI_RID_PROCFRAME) { 149193359Simp wreq.wi_len = 2; 149293359Simp wreq.wi_val[0] = sc->wi_procframe; 149393359Simp } else if (wreq.wi_type == WI_RID_PRISM2) { 149493359Simp wreq.wi_len = 2; 149593733Simp wreq.wi_val[0] = sc->sc_firmware_type != WI_LUCENT; 149693733Simp } else if (wreq.wi_type == WI_RID_SCAN_RES && 149793733Simp sc->sc_firmware_type == WI_LUCENT) { 149893359Simp memcpy((char *)wreq.wi_val, (char *)sc->wi_scanbuf, 149993359Simp sc->wi_scanbuf_len * 2); 150093359Simp wreq.wi_len = sc->wi_scanbuf_len; 150193359Simp } else { 150246492Swpaul if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq)) { 150346492Swpaul error = EINVAL; 150446492Swpaul break; 150546492Swpaul } 150646492Swpaul } 150746492Swpaul error = copyout(&wreq, ifr->ifr_data, sizeof(wreq)); 150846492Swpaul break; 150946492Swpaul case SIOCSWAVELAN: 151093593Sjhb if ((error = suser(td))) 151161818Sroberto goto out; 151246492Swpaul error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); 151346492Swpaul if (error) 151446492Swpaul break; 151546492Swpaul if (wreq.wi_type == WI_RID_IFACE_STATS) { 151646492Swpaul error = EINVAL; 151746492Swpaul break; 151846492Swpaul } else if (wreq.wi_type == WI_RID_MGMT_XMIT) { 151946492Swpaul error = wi_mgmt_xmit(sc, (caddr_t)&wreq.wi_val, 152046492Swpaul wreq.wi_len); 152193359Simp } else if (wreq.wi_type == WI_RID_PROCFRAME) { 152293359Simp sc->wi_procframe = wreq.wi_val[0]; 152393359Simp /* 152493359Simp * if we're getting a scan request from a wavelan card 152593359Simp * (non-prism2), send out a cmd_inquire to the card to scan 152693359Simp * results for the scan will be received through the info 152793359Simp * interrupt handler. otherwise the scan request can be 152893359Simp * directly handled by a prism2 card's rid interface. 152993359Simp */ 153093733Simp } else if (wreq.wi_type == WI_RID_SCAN_REQ && 153193733Simp sc->sc_firmware_type == WI_LUCENT) { 153293359Simp wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_SCAN_RESULTS, 0, 0); 153346492Swpaul } else { 153446492Swpaul error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq); 153546492Swpaul if (!error) 153646492Swpaul wi_setdef(sc, &wreq); 153746492Swpaul } 153846492Swpaul break; 153993359Simp case SIOCGPRISM2DEBUG: 154093359Simp error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); 154193359Simp if (error) 154293359Simp break; 154393733Simp if (!(ifp->if_flags & IFF_RUNNING) || 154493733Simp sc->sc_firmware_type == WI_LUCENT) { 154593359Simp error = EIO; 154693359Simp break; 154793359Simp } 154893359Simp error = wi_get_debug(sc, &wreq); 154993359Simp if (error == 0) 155093359Simp error = copyout(&wreq, ifr->ifr_data, sizeof(wreq)); 155193359Simp break; 155293359Simp case SIOCSPRISM2DEBUG: 155393593Sjhb if ((error = suser(td))) 155493359Simp goto out; 155593359Simp error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); 155693359Simp if (error) 155793359Simp break; 155893359Simp error = wi_set_debug(sc, &wreq); 155993359Simp break; 156077217Sphk case SIOCG80211: 156177217Sphk switch(ireq->i_type) { 156277217Sphk case IEEE80211_IOC_SSID: 156377217Sphk if(ireq->i_val == -1) { 156477217Sphk bzero(tmpssid, IEEE80211_NWID_LEN); 156577217Sphk error = wi_get_cur_ssid(sc, tmpssid, &len); 156677217Sphk if (error != 0) 156777217Sphk break; 156877217Sphk error = copyout(tmpssid, ireq->i_data, 156977217Sphk IEEE80211_NWID_LEN); 157077217Sphk ireq->i_len = len; 157177217Sphk } else if (ireq->i_val == 0) { 157277217Sphk error = copyout(sc->wi_net_name, 157377217Sphk ireq->i_data, 157477217Sphk IEEE80211_NWID_LEN); 157577217Sphk ireq->i_len = IEEE80211_NWID_LEN; 157677217Sphk } else 157777217Sphk error = EINVAL; 157877217Sphk break; 157977217Sphk case IEEE80211_IOC_NUMSSIDS: 158077217Sphk ireq->i_val = 1; 158177217Sphk break; 158277217Sphk case IEEE80211_IOC_WEP: 158377217Sphk if(!sc->wi_has_wep) { 158477217Sphk ireq->i_val = IEEE80211_WEP_NOSUP; 158577217Sphk } else { 158677217Sphk if(sc->wi_use_wep) { 158777217Sphk ireq->i_val = 158877217Sphk IEEE80211_WEP_MIXED; 158977217Sphk } else { 159077217Sphk ireq->i_val = 159177217Sphk IEEE80211_WEP_OFF; 159277217Sphk } 159377217Sphk } 159477217Sphk break; 159577217Sphk case IEEE80211_IOC_WEPKEY: 159677217Sphk if(!sc->wi_has_wep || 159777217Sphk ireq->i_val < 0 || ireq->i_val > 3) { 159877217Sphk error = EINVAL; 159977217Sphk break; 160077217Sphk } 160177217Sphk len = sc->wi_keys.wi_keys[ireq->i_val].wi_keylen; 160293593Sjhb if (suser(td)) 160377217Sphk bcopy(sc->wi_keys.wi_keys[ireq->i_val].wi_keydat, 160477217Sphk tmpkey, len); 160577217Sphk else 160677217Sphk bzero(tmpkey, len); 160777217Sphk 160877217Sphk ireq->i_len = len; 160977217Sphk error = copyout(tmpkey, ireq->i_data, len); 161077217Sphk 161177217Sphk break; 161277217Sphk case IEEE80211_IOC_NUMWEPKEYS: 161377217Sphk if(!sc->wi_has_wep) 161477217Sphk error = EINVAL; 161577217Sphk else 161677217Sphk ireq->i_val = 4; 161777217Sphk break; 161877217Sphk case IEEE80211_IOC_WEPTXKEY: 161977217Sphk if(!sc->wi_has_wep) 162077217Sphk error = EINVAL; 162177217Sphk else 162277217Sphk ireq->i_val = sc->wi_tx_key; 162377217Sphk break; 162477217Sphk case IEEE80211_IOC_AUTHMODE: 162577217Sphk ireq->i_val = IEEE80211_AUTH_NONE; 162677217Sphk break; 162777217Sphk case IEEE80211_IOC_STATIONNAME: 162877217Sphk error = copyout(sc->wi_node_name, 162977217Sphk ireq->i_data, IEEE80211_NWID_LEN); 163077217Sphk ireq->i_len = IEEE80211_NWID_LEN; 163177217Sphk break; 163277217Sphk case IEEE80211_IOC_CHANNEL: 163377217Sphk wreq.wi_type = WI_RID_CURRENT_CHAN; 163477217Sphk wreq.wi_len = WI_MAX_DATALEN; 163577217Sphk if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq)) 163677217Sphk error = EINVAL; 163777217Sphk else { 163877217Sphk ireq->i_val = wreq.wi_val[0]; 163977217Sphk } 164077217Sphk break; 164177217Sphk case IEEE80211_IOC_POWERSAVE: 164277217Sphk if(sc->wi_pm_enabled) 164377217Sphk ireq->i_val = IEEE80211_POWERSAVE_ON; 164477217Sphk else 164577217Sphk ireq->i_val = IEEE80211_POWERSAVE_OFF; 164677217Sphk break; 164777217Sphk case IEEE80211_IOC_POWERSAVESLEEP: 164877217Sphk ireq->i_val = sc->wi_max_sleep; 164977217Sphk break; 165077217Sphk default: 165177217Sphk error = EINVAL; 165277217Sphk } 165377217Sphk break; 165477217Sphk case SIOCS80211: 165593593Sjhb if ((error = suser(td))) 165677217Sphk goto out; 165777217Sphk switch(ireq->i_type) { 165877217Sphk case IEEE80211_IOC_SSID: 165977217Sphk if (ireq->i_val != 0 || 166077217Sphk ireq->i_len > IEEE80211_NWID_LEN) { 166177217Sphk error = EINVAL; 166277217Sphk break; 166377217Sphk } 166477217Sphk /* We set both of them */ 166577217Sphk bzero(sc->wi_net_name, IEEE80211_NWID_LEN); 166677217Sphk error = copyin(ireq->i_data, 166777217Sphk sc->wi_net_name, ireq->i_len); 166877217Sphk bcopy(sc->wi_net_name, sc->wi_ibss_name, IEEE80211_NWID_LEN); 166977217Sphk break; 167077217Sphk case IEEE80211_IOC_WEP: 167177217Sphk /* 167277217Sphk * These cards only support one mode so 167377217Sphk * we just turn wep on what ever is 167477217Sphk * passed in if it's not OFF. 167577217Sphk */ 167677217Sphk if (ireq->i_val == IEEE80211_WEP_OFF) { 167777217Sphk sc->wi_use_wep = 0; 167877217Sphk } else { 167977217Sphk sc->wi_use_wep = 1; 168077217Sphk } 168177217Sphk break; 168277217Sphk case IEEE80211_IOC_WEPKEY: 168377217Sphk if (ireq->i_val < 0 || ireq->i_val > 3 || 168477217Sphk ireq->i_len > 13) { 168577217Sphk error = EINVAL; 168677217Sphk break; 168777217Sphk } 168877217Sphk bzero(sc->wi_keys.wi_keys[ireq->i_val].wi_keydat, 13); 168977217Sphk error = copyin(ireq->i_data, 169077217Sphk sc->wi_keys.wi_keys[ireq->i_val].wi_keydat, 169177217Sphk ireq->i_len); 169277217Sphk if(error) 169377217Sphk break; 169477217Sphk sc->wi_keys.wi_keys[ireq->i_val].wi_keylen = 169577217Sphk ireq->i_len; 169677217Sphk break; 169777217Sphk case IEEE80211_IOC_WEPTXKEY: 169877217Sphk if (ireq->i_val < 0 || ireq->i_val > 3) { 169977217Sphk error = EINVAL; 170077217Sphk break; 170177217Sphk } 170277217Sphk sc->wi_tx_key = ireq->i_val; 170377217Sphk break; 170477217Sphk case IEEE80211_IOC_AUTHMODE: 170577217Sphk error = EINVAL; 170677217Sphk break; 170777217Sphk case IEEE80211_IOC_STATIONNAME: 170877217Sphk if (ireq->i_len > 32) { 170977217Sphk error = EINVAL; 171077217Sphk break; 171177217Sphk } 171277217Sphk bzero(sc->wi_node_name, 32); 171377217Sphk error = copyin(ireq->i_data, 171477217Sphk sc->wi_node_name, ireq->i_len); 171577217Sphk break; 171677217Sphk case IEEE80211_IOC_CHANNEL: 171777217Sphk /* 171877217Sphk * The actual range is 1-14, but if you 171977217Sphk * set it to 0 you get the default. So 172077217Sphk * we let that work too. 172177217Sphk */ 172277217Sphk if (ireq->i_val < 0 || ireq->i_val > 14) { 172377217Sphk error = EINVAL; 172477217Sphk break; 172577217Sphk } 172677217Sphk sc->wi_channel = ireq->i_val; 172777217Sphk break; 172877217Sphk case IEEE80211_IOC_POWERSAVE: 172977217Sphk switch (ireq->i_val) { 173077217Sphk case IEEE80211_POWERSAVE_OFF: 173177217Sphk sc->wi_pm_enabled = 0; 173277217Sphk break; 173377217Sphk case IEEE80211_POWERSAVE_ON: 173477217Sphk sc->wi_pm_enabled = 1; 173577217Sphk break; 173677217Sphk default: 173777217Sphk error = EINVAL; 173877217Sphk break; 173977217Sphk } 174077217Sphk break; 174177217Sphk case IEEE80211_IOC_POWERSAVESLEEP: 174277217Sphk if (ireq->i_val < 0) { 174377217Sphk error = EINVAL; 174477217Sphk break; 174577217Sphk } 174677217Sphk sc->wi_max_sleep = ireq->i_val; 174777217Sphk break; 174877217Sphk default: 174977217Sphk error = EINVAL; 175077217Sphk break; 175177217Sphk } 175277217Sphk 175377217Sphk /* Reinitialize WaveLAN. */ 175477217Sphk wi_init(sc); 175577217Sphk 175677217Sphk break; 175746492Swpaul default: 175846492Swpaul error = EINVAL; 175946492Swpaul break; 176046492Swpaul } 176161818Srobertoout: 176267092Swpaul WI_UNLOCK(sc); 176346492Swpaul 176446492Swpaul return(error); 176546492Swpaul} 176646492Swpaul 176788546Salfredstatic void 176888546Salfredwi_init(xsc) 176946492Swpaul void *xsc; 177046492Swpaul{ 177146492Swpaul struct wi_softc *sc = xsc; 177246492Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 177346492Swpaul struct wi_ltv_macaddr mac; 177446492Swpaul int id = 0; 177546492Swpaul 177667092Swpaul WI_LOCK(sc); 177767092Swpaul 177867092Swpaul if (sc->wi_gone) { 177967092Swpaul WI_UNLOCK(sc); 178046492Swpaul return; 178167092Swpaul } 178246492Swpaul 178346492Swpaul if (ifp->if_flags & IFF_RUNNING) 178446492Swpaul wi_stop(sc); 178546492Swpaul 178646492Swpaul wi_reset(sc); 178746492Swpaul 178846492Swpaul /* Program max data length. */ 178946492Swpaul WI_SETVAL(WI_RID_MAX_DATALEN, sc->wi_max_data_len); 179046492Swpaul 179147401Swpaul /* Enable/disable IBSS creation. */ 179246492Swpaul WI_SETVAL(WI_RID_CREATE_IBSS, sc->wi_create_ibss); 179346492Swpaul 179446492Swpaul /* Set the port type. */ 179546492Swpaul WI_SETVAL(WI_RID_PORTTYPE, sc->wi_ptype); 179646492Swpaul 179746492Swpaul /* Program the RTS/CTS threshold. */ 179846492Swpaul WI_SETVAL(WI_RID_RTS_THRESH, sc->wi_rts_thresh); 179946492Swpaul 180046492Swpaul /* Program the TX rate */ 180146492Swpaul WI_SETVAL(WI_RID_TX_RATE, sc->wi_tx_rate); 180246492Swpaul 180346492Swpaul /* Access point density */ 180446492Swpaul WI_SETVAL(WI_RID_SYSTEM_SCALE, sc->wi_ap_density); 180546492Swpaul 180646611Swpaul /* Power Management Enabled */ 180746611Swpaul WI_SETVAL(WI_RID_PM_ENABLED, sc->wi_pm_enabled); 180846611Swpaul 180946611Swpaul /* Power Managment Max Sleep */ 181046611Swpaul WI_SETVAL(WI_RID_MAX_SLEEP, sc->wi_max_sleep); 181146611Swpaul 181291695Simp /* Roaming type */ 181391695Simp WI_SETVAL(WI_RID_ROAMING_MODE, sc->wi_roaming); 181491695Simp 181546492Swpaul /* Specify the IBSS name */ 181646492Swpaul WI_SETSTR(WI_RID_OWN_SSID, sc->wi_ibss_name); 181746492Swpaul 181846492Swpaul /* Specify the network name */ 181946492Swpaul WI_SETSTR(WI_RID_DESIRED_SSID, sc->wi_net_name); 182046492Swpaul 182146563Swpaul /* Specify the frequency to use */ 182246563Swpaul WI_SETVAL(WI_RID_OWN_CHNL, sc->wi_channel); 182346563Swpaul 182446492Swpaul /* Program the nodename. */ 182546492Swpaul WI_SETSTR(WI_RID_NODENAME, sc->wi_node_name); 182646492Swpaul 182746492Swpaul /* Set our MAC address. */ 182846492Swpaul mac.wi_len = 4; 182946492Swpaul mac.wi_type = WI_RID_MAC_NODE; 183046492Swpaul bcopy((char *)&sc->arpcom.ac_enaddr, 183146492Swpaul (char *)&mac.wi_mac_addr, ETHER_ADDR_LEN); 183246492Swpaul wi_write_record(sc, (struct wi_ltv_gen *)&mac); 183346492Swpaul 183456965Swpaul /* Configure WEP. */ 183556965Swpaul if (sc->wi_has_wep) { 183656965Swpaul WI_SETVAL(WI_RID_ENCRYPTION, sc->wi_use_wep); 183756965Swpaul WI_SETVAL(WI_RID_TX_CRYPT_KEY, sc->wi_tx_key); 183856965Swpaul sc->wi_keys.wi_len = (sizeof(struct wi_ltv_keys) / 2) + 1; 183956965Swpaul sc->wi_keys.wi_type = WI_RID_DEFLT_CRYPT_KEYS; 184056965Swpaul wi_write_record(sc, (struct wi_ltv_gen *)&sc->wi_keys); 184193733Simp if (sc->sc_firmware_type != WI_LUCENT && sc->wi_use_wep) { 184291695Simp /* 184391695Simp * ONLY HWB3163 EVAL-CARD Firmware version 184493733Simp * less than 0.8 variant2 184591695Simp * 184691695Simp * If promiscuous mode disable, Prism2 chip 184791695Simp * does not work with WEP . 184891695Simp * It is under investigation for details. 184991695Simp * (ichiro@netbsd.org) 185091695Simp */ 185193733Simp if (sc->sc_firmware_type == WI_INTERSIL && 185293733Simp sc->sc_sta_firmware_ver < 802 ) { 185393733Simp /* firm ver < 0.8 variant 2 */ 185491695Simp WI_SETVAL(WI_RID_PROMISC, 1); 185591695Simp } 185691695Simp WI_SETVAL(WI_RID_AUTH_CNTL, sc->wi_authtype); 185791695Simp } 185856965Swpaul } 185956965Swpaul 186046492Swpaul /* Initialize promisc mode. */ 186146492Swpaul if (ifp->if_flags & IFF_PROMISC) { 186246492Swpaul WI_SETVAL(WI_RID_PROMISC, 1); 186346492Swpaul } else { 186446492Swpaul WI_SETVAL(WI_RID_PROMISC, 0); 186546492Swpaul } 186646492Swpaul 186746492Swpaul /* Set multicast filter. */ 186846492Swpaul wi_setmulti(sc); 186946492Swpaul 187046492Swpaul /* Enable desired port */ 187192457Simp wi_cmd(sc, WI_CMD_ENABLE | sc->wi_portnum, 0, 0, 0); 187246492Swpaul 187375373Salfred if (wi_alloc_nicmem(sc, ETHER_MAX_LEN + sizeof(struct wi_frame) + 8, &id)) 187453702Swpaul device_printf(sc->dev, "tx buffer allocation failed\n"); 187546492Swpaul sc->wi_tx_data_id = id; 187646492Swpaul 187775373Salfred if (wi_alloc_nicmem(sc, ETHER_MAX_LEN + sizeof(struct wi_frame) + 8, &id)) 187853702Swpaul device_printf(sc->dev, "mgmt. buffer allocation failed\n"); 187946492Swpaul sc->wi_tx_mgmt_id = id; 188046492Swpaul 188146492Swpaul /* enable interrupts */ 188246492Swpaul CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS); 188346492Swpaul 188446492Swpaul ifp->if_flags |= IFF_RUNNING; 188546492Swpaul ifp->if_flags &= ~IFF_OACTIVE; 188646492Swpaul 188746492Swpaul sc->wi_stat_ch = timeout(wi_inquire, sc, hz * 60); 188867092Swpaul WI_UNLOCK(sc); 188946492Swpaul 189046492Swpaul return; 189146492Swpaul} 189246492Swpaul 189388546Salfredstatic void 189488546Salfredwi_start(ifp) 189546492Swpaul struct ifnet *ifp; 189646492Swpaul{ 189746492Swpaul struct wi_softc *sc; 189846492Swpaul struct mbuf *m0; 189946492Swpaul struct wi_frame tx_frame; 190046492Swpaul struct ether_header *eh; 190146492Swpaul int id; 190246492Swpaul 190346492Swpaul sc = ifp->if_softc; 190467092Swpaul WI_LOCK(sc); 190546492Swpaul 190667092Swpaul if (sc->wi_gone) { 190767092Swpaul WI_UNLOCK(sc); 190846492Swpaul return; 190967092Swpaul } 191046492Swpaul 191167092Swpaul if (ifp->if_flags & IFF_OACTIVE) { 191267092Swpaul WI_UNLOCK(sc); 191346492Swpaul return; 191467092Swpaul } 191546492Swpaul 191646492Swpaul IF_DEQUEUE(&ifp->if_snd, m0); 191767092Swpaul if (m0 == NULL) { 191867092Swpaul WI_UNLOCK(sc); 191946492Swpaul return; 192067092Swpaul } 192146492Swpaul 192246492Swpaul bzero((char *)&tx_frame, sizeof(tx_frame)); 192346492Swpaul id = sc->wi_tx_data_id; 192446492Swpaul eh = mtod(m0, struct ether_header *); 192546492Swpaul 192646492Swpaul /* 192747401Swpaul * Use RFC1042 encoding for IP and ARP datagrams, 192846492Swpaul * 802.3 for anything else. 192946492Swpaul */ 193075275Salfred if (ntohs(eh->ether_type) > ETHER_MAX_LEN) { 193146492Swpaul bcopy((char *)&eh->ether_dhost, 193246492Swpaul (char *)&tx_frame.wi_addr1, ETHER_ADDR_LEN); 193346492Swpaul bcopy((char *)&eh->ether_shost, 193446492Swpaul (char *)&tx_frame.wi_addr2, ETHER_ADDR_LEN); 193546492Swpaul bcopy((char *)&eh->ether_dhost, 193646492Swpaul (char *)&tx_frame.wi_dst_addr, ETHER_ADDR_LEN); 193746492Swpaul bcopy((char *)&eh->ether_shost, 193846492Swpaul (char *)&tx_frame.wi_src_addr, ETHER_ADDR_LEN); 193946492Swpaul 194046492Swpaul tx_frame.wi_dat_len = m0->m_pkthdr.len - WI_SNAPHDR_LEN; 194146492Swpaul tx_frame.wi_frame_ctl = WI_FTYPE_DATA; 194246492Swpaul tx_frame.wi_dat[0] = htons(WI_SNAP_WORD0); 194346492Swpaul tx_frame.wi_dat[1] = htons(WI_SNAP_WORD1); 194446492Swpaul tx_frame.wi_len = htons(m0->m_pkthdr.len - WI_SNAPHDR_LEN); 194546492Swpaul tx_frame.wi_type = eh->ether_type; 194646492Swpaul 194746492Swpaul m_copydata(m0, sizeof(struct ether_header), 194846492Swpaul m0->m_pkthdr.len - sizeof(struct ether_header), 194946492Swpaul (caddr_t)&sc->wi_txbuf); 195046492Swpaul 195146492Swpaul wi_write_data(sc, id, 0, (caddr_t)&tx_frame, 195246492Swpaul sizeof(struct wi_frame)); 195346492Swpaul wi_write_data(sc, id, WI_802_11_OFFSET, (caddr_t)&sc->wi_txbuf, 195446492Swpaul (m0->m_pkthdr.len - sizeof(struct ether_header)) + 2); 195546492Swpaul } else { 195646492Swpaul tx_frame.wi_dat_len = m0->m_pkthdr.len; 195746492Swpaul 195855831Swpaul eh->ether_type = htons(m0->m_pkthdr.len - WI_SNAPHDR_LEN); 195946492Swpaul m_copydata(m0, 0, m0->m_pkthdr.len, (caddr_t)&sc->wi_txbuf); 196046492Swpaul 196146492Swpaul wi_write_data(sc, id, 0, (caddr_t)&tx_frame, 196246492Swpaul sizeof(struct wi_frame)); 196346492Swpaul wi_write_data(sc, id, WI_802_3_OFFSET, (caddr_t)&sc->wi_txbuf, 196446492Swpaul m0->m_pkthdr.len + 2); 196546492Swpaul } 196646492Swpaul 196746492Swpaul /* 196846492Swpaul * If there's a BPF listner, bounce a copy of 196993359Simp * this frame to him. Also, don't send this to the bpf sniffer 197093359Simp * if we're in procframe or monitor sniffing mode. 197146492Swpaul */ 197293359Simp if (!(sc->wi_procframe || sc->wi_debug.wi_monitor) && ifp->if_bpf) 197346492Swpaul bpf_mtap(ifp, m0); 197446492Swpaul 197546492Swpaul m_freem(m0); 197646492Swpaul 197792457Simp if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0)) 197853702Swpaul device_printf(sc->dev, "xmit failed\n"); 197946492Swpaul 198046492Swpaul ifp->if_flags |= IFF_OACTIVE; 198146492Swpaul 198246492Swpaul /* 198346492Swpaul * Set a timeout in case the chip goes out to lunch. 198446492Swpaul */ 198546492Swpaul ifp->if_timer = 5; 198646492Swpaul 198767092Swpaul WI_UNLOCK(sc); 198846492Swpaul return; 198946492Swpaul} 199046492Swpaul 199188546Salfredstatic int 199288546Salfredwi_mgmt_xmit(sc, data, len) 199346492Swpaul struct wi_softc *sc; 199446492Swpaul caddr_t data; 199546492Swpaul int len; 199646492Swpaul{ 199746492Swpaul struct wi_frame tx_frame; 199846492Swpaul int id; 199946492Swpaul struct wi_80211_hdr *hdr; 200046492Swpaul caddr_t dptr; 200146492Swpaul 200246492Swpaul if (sc->wi_gone) 200346492Swpaul return(ENODEV); 200446492Swpaul 200546492Swpaul hdr = (struct wi_80211_hdr *)data; 200646492Swpaul dptr = data + sizeof(struct wi_80211_hdr); 200746492Swpaul 200846492Swpaul bzero((char *)&tx_frame, sizeof(tx_frame)); 200946492Swpaul id = sc->wi_tx_mgmt_id; 201046492Swpaul 201146492Swpaul bcopy((char *)hdr, (char *)&tx_frame.wi_frame_ctl, 201246492Swpaul sizeof(struct wi_80211_hdr)); 201346492Swpaul 201446492Swpaul tx_frame.wi_dat_len = len - WI_SNAPHDR_LEN; 201546492Swpaul tx_frame.wi_len = htons(len - WI_SNAPHDR_LEN); 201646492Swpaul 201746492Swpaul wi_write_data(sc, id, 0, (caddr_t)&tx_frame, sizeof(struct wi_frame)); 201846492Swpaul wi_write_data(sc, id, WI_802_11_OFFSET_RAW, dptr, 201946492Swpaul (len - sizeof(struct wi_80211_hdr)) + 2); 202046492Swpaul 202192457Simp if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0)) { 202253702Swpaul device_printf(sc->dev, "xmit failed\n"); 202346492Swpaul return(EIO); 202446492Swpaul } 202546492Swpaul 202646492Swpaul return(0); 202746492Swpaul} 202846492Swpaul 202988546Salfredstatic void 203088546Salfredwi_stop(sc) 203146492Swpaul struct wi_softc *sc; 203246492Swpaul{ 203346492Swpaul struct ifnet *ifp; 203446492Swpaul 203567092Swpaul WI_LOCK(sc); 203667092Swpaul 203767092Swpaul if (sc->wi_gone) { 203867092Swpaul WI_UNLOCK(sc); 203946492Swpaul return; 204067092Swpaul } 204146492Swpaul 204246492Swpaul ifp = &sc->arpcom.ac_if; 204346492Swpaul 204470173Sjhb /* 204570173Sjhb * If the card is gone and the memory port isn't mapped, we will 204670173Sjhb * (hopefully) get 0xffff back from the status read, which is not 204770173Sjhb * a valid status value. 204870173Sjhb */ 204970173Sjhb if (CSR_READ_2(sc, WI_STATUS) != 0xffff) { 205070173Sjhb CSR_WRITE_2(sc, WI_INT_EN, 0); 205192457Simp wi_cmd(sc, WI_CMD_DISABLE|sc->wi_portnum, 0, 0, 0); 205270173Sjhb } 205346492Swpaul 205446492Swpaul untimeout(wi_inquire, sc, sc->wi_stat_ch); 205546492Swpaul 205646492Swpaul ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); 205746492Swpaul 205867092Swpaul WI_UNLOCK(sc); 205946492Swpaul return; 206046492Swpaul} 206146492Swpaul 206288546Salfredstatic void 206388546Salfredwi_watchdog(ifp) 206446492Swpaul struct ifnet *ifp; 206546492Swpaul{ 206646492Swpaul struct wi_softc *sc; 206746492Swpaul 206846492Swpaul sc = ifp->if_softc; 206946492Swpaul 207075199Salfred device_printf(sc->dev, "watchdog timeout\n"); 207146492Swpaul 207246492Swpaul wi_init(sc); 207346492Swpaul 207446492Swpaul ifp->if_oerrors++; 207546492Swpaul 207646492Swpaul return; 207746492Swpaul} 207846492Swpaul 207993611Simpint 208090580Sbrookswi_alloc(dev, rid) 208153702Swpaul device_t dev; 208290580Sbrooks int rid; 208346492Swpaul{ 208453702Swpaul struct wi_softc *sc = device_get_softc(dev); 208553702Swpaul 208690580Sbrooks if (sc->wi_bus_type != WI_BUS_PCI_NATIVE) { 208790580Sbrooks sc->iobase_rid = rid; 208890580Sbrooks sc->iobase = bus_alloc_resource(dev, SYS_RES_IOPORT, 208990580Sbrooks &sc->iobase_rid, 0, ~0, (1 << 6), 209090580Sbrooks rman_make_alignment_flags(1 << 6) | RF_ACTIVE); 209190580Sbrooks if (!sc->iobase) { 209290580Sbrooks device_printf(dev, "No I/O space?!\n"); 209390580Sbrooks return (ENXIO); 209490580Sbrooks } 209590580Sbrooks 209690580Sbrooks sc->wi_io_addr = rman_get_start(sc->iobase); 209790580Sbrooks sc->wi_btag = rman_get_bustag(sc->iobase); 209890580Sbrooks sc->wi_bhandle = rman_get_bushandle(sc->iobase); 209990580Sbrooks } else { 210090580Sbrooks sc->mem_rid = rid; 210190580Sbrooks sc->mem = bus_alloc_resource(dev, SYS_RES_MEMORY, 210290580Sbrooks &sc->mem_rid, 0, ~0, 1, RF_ACTIVE); 210390580Sbrooks 210490580Sbrooks if (!sc->mem) { 210590580Sbrooks device_printf(dev, "No Mem space on prism2.5?\n"); 210690580Sbrooks return (ENXIO); 210790580Sbrooks } 210890580Sbrooks 210990580Sbrooks sc->wi_btag = rman_get_bustag(sc->mem); 211090580Sbrooks sc->wi_bhandle = rman_get_bushandle(sc->mem); 211153702Swpaul } 211253702Swpaul 211390580Sbrooks 211474906Salfred sc->irq_rid = 0; 211574906Salfred sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_rid, 211690580Sbrooks 0, ~0, 1, RF_ACTIVE | 211790580Sbrooks ((sc->wi_bus_type == WI_BUS_PCCARD) ? 0 : RF_SHAREABLE)); 211890580Sbrooks 211953702Swpaul if (!sc->irq) { 212075219Salfred wi_free(dev); 212153702Swpaul device_printf(dev, "No irq?!\n"); 212253702Swpaul return (ENXIO); 212353702Swpaul } 212453702Swpaul 212553702Swpaul sc->dev = dev; 212653702Swpaul sc->wi_unit = device_get_unit(dev); 212753702Swpaul 212853702Swpaul return (0); 212953702Swpaul} 213053702Swpaul 213193611Simpvoid 213288546Salfredwi_free(dev) 213353702Swpaul device_t dev; 213453702Swpaul{ 213553702Swpaul struct wi_softc *sc = device_get_softc(dev); 213653702Swpaul 213775219Salfred if (sc->iobase != NULL) { 213875219Salfred bus_release_resource(dev, SYS_RES_IOPORT, sc->iobase_rid, sc->iobase); 213975219Salfred sc->iobase = NULL; 214075219Salfred } 214175219Salfred if (sc->irq != NULL) { 214275219Salfred bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq); 214375219Salfred sc->irq = NULL; 214475219Salfred } 214575219Salfred if (sc->mem != NULL) { 214674906Salfred bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem); 214775219Salfred sc->mem = NULL; 214875219Salfred } 214953702Swpaul 215053702Swpaul return; 215153702Swpaul} 215253702Swpaul 215393611Simpvoid 215488546Salfredwi_shutdown(dev) 215553702Swpaul device_t dev; 215653702Swpaul{ 215746492Swpaul struct wi_softc *sc; 215846492Swpaul 215953702Swpaul sc = device_get_softc(dev); 216046492Swpaul wi_stop(sc); 216146492Swpaul 216246492Swpaul return; 216346492Swpaul} 216453702Swpaul 216553702Swpaul#ifdef WICACHE 216653702Swpaul/* wavelan signal strength cache code. 216753702Swpaul * store signal/noise/quality on per MAC src basis in 216853702Swpaul * a small fixed cache. The cache wraps if > MAX slots 216953702Swpaul * used. The cache may be zeroed out to start over. 217053702Swpaul * Two simple filters exist to reduce computation: 217153702Swpaul * 1. ip only (literally 0x800) which may be used 217253702Swpaul * to ignore some packets. It defaults to ip only. 217353702Swpaul * it could be used to focus on broadcast, non-IP 802.11 beacons. 217453702Swpaul * 2. multicast/broadcast only. This may be used to 217553702Swpaul * ignore unicast packets and only cache signal strength 217653702Swpaul * for multicast/broadcast packets (beacons); e.g., Mobile-IP 217753702Swpaul * beacons and not unicast traffic. 217853702Swpaul * 217953702Swpaul * The cache stores (MAC src(index), IP src (major clue), signal, 218053702Swpaul * quality, noise) 218153702Swpaul * 218253702Swpaul * No apologies for storing IP src here. It's easy and saves much 218353702Swpaul * trouble elsewhere. The cache is assumed to be INET dependent, 218453702Swpaul * although it need not be. 218553702Swpaul */ 218653702Swpaul 218753702Swpaul#ifdef documentation 218853702Swpaul 218953702Swpaulint wi_sigitems; /* number of cached entries */ 219053702Swpaulstruct wi_sigcache wi_sigcache[MAXWICACHE]; /* array of cache entries */ 219153702Swpaulint wi_nextitem; /* index/# of entries */ 219253702Swpaul 219353702Swpaul 219453702Swpaul#endif 219553702Swpaul 219653702Swpaul/* control variables for cache filtering. Basic idea is 219753702Swpaul * to reduce cost (e.g., to only Mobile-IP agent beacons 219853702Swpaul * which are broadcast or multicast). Still you might 219953702Swpaul * want to measure signal strength with unicast ping packets 220053702Swpaul * on a pt. to pt. ant. setup. 220153702Swpaul */ 220253702Swpaul/* set true if you want to limit cache items to broadcast/mcast 220353702Swpaul * only packets (not unicast). Useful for mobile-ip beacons which 220453702Swpaul * are broadcast/multicast at network layer. Default is all packets 220553702Swpaul * so ping/unicast will work say with pt. to pt. antennae setup. 220653702Swpaul */ 220753702Swpaulstatic int wi_cache_mcastonly = 0; 220853702SwpaulSYSCTL_INT(_machdep, OID_AUTO, wi_cache_mcastonly, CTLFLAG_RW, 220953702Swpaul &wi_cache_mcastonly, 0, ""); 221053702Swpaul 221153702Swpaul/* set true if you want to limit cache items to IP packets only 221253702Swpaul*/ 221353702Swpaulstatic int wi_cache_iponly = 1; 221453702SwpaulSYSCTL_INT(_machdep, OID_AUTO, wi_cache_iponly, CTLFLAG_RW, 221553702Swpaul &wi_cache_iponly, 0, ""); 221653702Swpaul 221753702Swpaul/* 221853702Swpaul * Original comments: 221953702Swpaul * ----------------- 222053702Swpaul * wi_cache_store, per rx packet store signal 222153702Swpaul * strength in MAC (src) indexed cache. 222253702Swpaul * 222353702Swpaul * follows linux driver in how signal strength is computed. 222453702Swpaul * In ad hoc mode, we use the rx_quality field. 222553702Swpaul * signal and noise are trimmed to fit in the range from 47..138. 222653702Swpaul * rx_quality field MSB is signal strength. 222753702Swpaul * rx_quality field LSB is noise. 222853702Swpaul * "quality" is (signal - noise) as is log value. 222953702Swpaul * note: quality CAN be negative. 223053702Swpaul * 223153702Swpaul * In BSS mode, we use the RID for communication quality. 223253702Swpaul * TBD: BSS mode is currently untested. 223353702Swpaul * 223453702Swpaul * Bill's comments: 223553702Swpaul * --------------- 223653702Swpaul * Actually, we use the rx_quality field all the time for both "ad-hoc" 223753702Swpaul * and BSS modes. Why? Because reading an RID is really, really expensive: 223853702Swpaul * there's a bunch of PIO operations that have to be done to read a record 223953702Swpaul * from the NIC, and reading the comms quality RID each time a packet is 224053702Swpaul * received can really hurt performance. We don't have to do this anyway: 224153702Swpaul * the comms quality field only reflects the values in the rx_quality field 224253702Swpaul * anyway. The comms quality RID is only meaningful in infrastructure mode, 224353702Swpaul * but the values it contains are updated based on the rx_quality from 224453702Swpaul * frames received from the access point. 224553702Swpaul * 224653702Swpaul * Also, according to Lucent, the signal strength and noise level values 224753702Swpaul * can be converted to dBms by subtracting 149, so I've modified the code 224853702Swpaul * to do that instead of the scaling it did originally. 224953702Swpaul */ 225088546Salfredstatic void 225188546Salfredwi_cache_store(struct wi_softc *sc, struct ether_header *eh, 225253702Swpaul struct mbuf *m, unsigned short rx_quality) 225353702Swpaul{ 225453702Swpaul struct ip *ip = 0; 225553702Swpaul int i; 225653702Swpaul static int cache_slot = 0; /* use this cache entry */ 225753702Swpaul static int wrapindex = 0; /* next "free" cache entry */ 225853702Swpaul int sig, noise; 225953702Swpaul int sawip=0; 226053702Swpaul 226153702Swpaul /* filters: 226253702Swpaul * 1. ip only 226353702Swpaul * 2. configurable filter to throw out unicast packets, 226453702Swpaul * keep multicast only. 226553702Swpaul */ 226653702Swpaul 226775276Salfred if ((ntohs(eh->ether_type) == ETHERTYPE_IP)) { 226853702Swpaul sawip = 1; 226953702Swpaul } 227053702Swpaul 227153702Swpaul /* filter for ip packets only 227253702Swpaul */ 227353702Swpaul if (wi_cache_iponly && !sawip) { 227453702Swpaul return; 227553702Swpaul } 227653702Swpaul 227753702Swpaul /* filter for broadcast/multicast only 227853702Swpaul */ 227953702Swpaul if (wi_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) { 228053702Swpaul return; 228153702Swpaul } 228253702Swpaul 228353702Swpaul#ifdef SIGDEBUG 228453702Swpaul printf("wi%d: q value %x (MSB=0x%x, LSB=0x%x) \n", sc->wi_unit, 228553702Swpaul rx_quality & 0xffff, rx_quality >> 8, rx_quality & 0xff); 228653702Swpaul#endif 228753702Swpaul 228853702Swpaul /* find the ip header. we want to store the ip_src 228953702Swpaul * address. 229053702Swpaul */ 229153702Swpaul if (sawip) { 229253702Swpaul ip = mtod(m, struct ip *); 229353702Swpaul } 229453702Swpaul 229553702Swpaul /* do a linear search for a matching MAC address 229653702Swpaul * in the cache table 229753702Swpaul * . MAC address is 6 bytes, 229853702Swpaul * . var w_nextitem holds total number of entries already cached 229953702Swpaul */ 230053702Swpaul for(i = 0; i < sc->wi_nextitem; i++) { 230153702Swpaul if (! bcmp(eh->ether_shost , sc->wi_sigcache[i].macsrc, 6 )) { 230253702Swpaul /* Match!, 230353702Swpaul * so we already have this entry, 230453702Swpaul * update the data 230553702Swpaul */ 230653702Swpaul break; 230753702Swpaul } 230853702Swpaul } 230953702Swpaul 231053702Swpaul /* did we find a matching mac address? 231153702Swpaul * if yes, then overwrite a previously existing cache entry 231253702Swpaul */ 231353702Swpaul if (i < sc->wi_nextitem ) { 231453702Swpaul cache_slot = i; 231553702Swpaul } 231653702Swpaul /* else, have a new address entry,so 231753702Swpaul * add this new entry, 231853702Swpaul * if table full, then we need to replace LRU entry 231953702Swpaul */ 232053702Swpaul else { 232153702Swpaul 232253702Swpaul /* check for space in cache table 232353702Swpaul * note: wi_nextitem also holds number of entries 232453702Swpaul * added in the cache table 232553702Swpaul */ 232653702Swpaul if ( sc->wi_nextitem < MAXWICACHE ) { 232753702Swpaul cache_slot = sc->wi_nextitem; 232853702Swpaul sc->wi_nextitem++; 232953702Swpaul sc->wi_sigitems = sc->wi_nextitem; 233053702Swpaul } 233153702Swpaul /* no space found, so simply wrap with wrap index 233253702Swpaul * and "zap" the next entry 233353702Swpaul */ 233453702Swpaul else { 233553702Swpaul if (wrapindex == MAXWICACHE) { 233653702Swpaul wrapindex = 0; 233753702Swpaul } 233853702Swpaul cache_slot = wrapindex++; 233953702Swpaul } 234053702Swpaul } 234153702Swpaul 234253702Swpaul /* invariant: cache_slot now points at some slot 234353702Swpaul * in cache. 234453702Swpaul */ 234553702Swpaul if (cache_slot < 0 || cache_slot >= MAXWICACHE) { 234653702Swpaul log(LOG_ERR, "wi_cache_store, bad index: %d of " 234753702Swpaul "[0..%d], gross cache error\n", 234853702Swpaul cache_slot, MAXWICACHE); 234953702Swpaul return; 235053702Swpaul } 235153702Swpaul 235253702Swpaul /* store items in cache 235353702Swpaul * .ip source address 235453702Swpaul * .mac src 235553702Swpaul * .signal, etc. 235653702Swpaul */ 235753702Swpaul if (sawip) { 235853702Swpaul sc->wi_sigcache[cache_slot].ipsrc = ip->ip_src.s_addr; 235953702Swpaul } 236053702Swpaul bcopy( eh->ether_shost, sc->wi_sigcache[cache_slot].macsrc, 6); 236153702Swpaul 236253702Swpaul sig = (rx_quality >> 8) & 0xFF; 236353702Swpaul noise = rx_quality & 0xFF; 236453702Swpaul sc->wi_sigcache[cache_slot].signal = sig - 149; 236553702Swpaul sc->wi_sigcache[cache_slot].noise = noise - 149; 236653702Swpaul sc->wi_sigcache[cache_slot].quality = sig - noise; 236753702Swpaul 236853702Swpaul return; 236953702Swpaul} 237053702Swpaul#endif 237177217Sphk 237288546Salfredstatic int 237388546Salfredwi_get_cur_ssid(sc, ssid, len) 237477217Sphk struct wi_softc *sc; 237577217Sphk char *ssid; 237677217Sphk int *len; 237777217Sphk{ 237877217Sphk int error = 0; 237977217Sphk struct wi_req wreq; 238077217Sphk 238177217Sphk wreq.wi_len = WI_MAX_DATALEN; 238277217Sphk switch (sc->wi_ptype) { 238377217Sphk case WI_PORTTYPE_ADHOC: 238477217Sphk wreq.wi_type = WI_RID_CURRENT_SSID; 238577217Sphk error = wi_read_record(sc, (struct wi_ltv_gen *)&wreq); 238677217Sphk if (error != 0) 238777217Sphk break; 238877217Sphk if (wreq.wi_val[0] > IEEE80211_NWID_LEN) { 238977217Sphk error = EINVAL; 239077217Sphk break; 239177217Sphk } 239277217Sphk *len = wreq.wi_val[0]; 239377217Sphk bcopy(&wreq.wi_val[1], ssid, IEEE80211_NWID_LEN); 239477217Sphk break; 239577217Sphk case WI_PORTTYPE_BSS: 239677217Sphk wreq.wi_type = WI_RID_COMMQUAL; 239777217Sphk error = wi_read_record(sc, (struct wi_ltv_gen *)&wreq); 239877217Sphk if (error != 0) 239977217Sphk break; 240077217Sphk if (wreq.wi_val[0] != 0) /* associated */ { 240177217Sphk wreq.wi_type = WI_RID_CURRENT_SSID; 240277217Sphk wreq.wi_len = WI_MAX_DATALEN; 240377217Sphk error = wi_read_record(sc, (struct wi_ltv_gen *)&wreq); 240477217Sphk if (error != 0) 240577217Sphk break; 240677217Sphk if (wreq.wi_val[0] > IEEE80211_NWID_LEN) { 240777217Sphk error = EINVAL; 240877217Sphk break; 240977217Sphk } 241077217Sphk *len = wreq.wi_val[0]; 241177217Sphk bcopy(&wreq.wi_val[1], ssid, IEEE80211_NWID_LEN); 241277217Sphk } else { 241377217Sphk *len = IEEE80211_NWID_LEN; 241477217Sphk bcopy(sc->wi_net_name, ssid, IEEE80211_NWID_LEN); 241577217Sphk } 241677217Sphk break; 241777217Sphk default: 241877217Sphk error = EINVAL; 241977217Sphk break; 242077217Sphk } 242177217Sphk 242277217Sphk return error; 242377217Sphk} 242477217Sphk 242588546Salfredstatic int 242688546Salfredwi_media_change(ifp) 242777217Sphk struct ifnet *ifp; 242877217Sphk{ 242977217Sphk struct wi_softc *sc = ifp->if_softc; 243077217Sphk int otype = sc->wi_ptype; 243177217Sphk int orate = sc->wi_tx_rate; 243277217Sphk 243377217Sphk if ((sc->ifmedia.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC) != 0) 243477217Sphk sc->wi_ptype = WI_PORTTYPE_ADHOC; 243577217Sphk else 243677217Sphk sc->wi_ptype = WI_PORTTYPE_BSS; 243777217Sphk 243877217Sphk switch (IFM_SUBTYPE(sc->ifmedia.ifm_cur->ifm_media)) { 243977217Sphk case IFM_IEEE80211_DS1: 244077217Sphk sc->wi_tx_rate = 1; 244177217Sphk break; 244277217Sphk case IFM_IEEE80211_DS2: 244377217Sphk sc->wi_tx_rate = 2; 244477217Sphk break; 244577217Sphk case IFM_IEEE80211_DS5: 244677217Sphk sc->wi_tx_rate = 5; 244777217Sphk break; 244877217Sphk case IFM_IEEE80211_DS11: 244977217Sphk sc->wi_tx_rate = 11; 245077217Sphk break; 245177217Sphk case IFM_AUTO: 245277217Sphk sc->wi_tx_rate = 3; 245377217Sphk break; 245477217Sphk } 245577217Sphk 245677217Sphk if (otype != sc->wi_ptype || 245777217Sphk orate != sc->wi_tx_rate) 245877217Sphk wi_init(sc); 245977217Sphk 246077217Sphk return(0); 246177217Sphk} 246277217Sphk 246388546Salfredstatic void 246488546Salfredwi_media_status(ifp, imr) 246577217Sphk struct ifnet *ifp; 246677217Sphk struct ifmediareq *imr; 246777217Sphk{ 246877217Sphk struct wi_req wreq; 246977217Sphk struct wi_softc *sc = ifp->if_softc; 247077217Sphk 247177217Sphk if (sc->wi_tx_rate == 3) { 247277217Sphk imr->ifm_active = IFM_IEEE80211|IFM_AUTO; 247377217Sphk if (sc->wi_ptype == WI_PORTTYPE_ADHOC) 247477217Sphk imr->ifm_active |= IFM_IEEE80211_ADHOC; 247577217Sphk wreq.wi_type = WI_RID_CUR_TX_RATE; 247677217Sphk wreq.wi_len = WI_MAX_DATALEN; 247777217Sphk if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0) { 247877217Sphk switch(wreq.wi_val[0]) { 247977217Sphk case 1: 248077217Sphk imr->ifm_active |= IFM_IEEE80211_DS1; 248177217Sphk break; 248277217Sphk case 2: 248377217Sphk imr->ifm_active |= IFM_IEEE80211_DS2; 248477217Sphk break; 248577217Sphk case 6: 248677217Sphk imr->ifm_active |= IFM_IEEE80211_DS5; 248777217Sphk break; 248877217Sphk case 11: 248977217Sphk imr->ifm_active |= IFM_IEEE80211_DS11; 249077217Sphk break; 249177217Sphk } 249277217Sphk } 249377217Sphk } else { 249477217Sphk imr->ifm_active = sc->ifmedia.ifm_cur->ifm_media; 249577217Sphk } 249677217Sphk 249777217Sphk imr->ifm_status = IFM_AVALID; 249877217Sphk if (sc->wi_ptype == WI_PORTTYPE_ADHOC) 249977217Sphk /* 250077217Sphk * XXX: It would be nice if we could give some actually 250177217Sphk * useful status like whether we joined another IBSS or 250277217Sphk * created one ourselves. 250377217Sphk */ 250477217Sphk imr->ifm_status |= IFM_ACTIVE; 250577217Sphk else { 250677217Sphk wreq.wi_type = WI_RID_COMMQUAL; 250777217Sphk wreq.wi_len = WI_MAX_DATALEN; 250877217Sphk if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0 && 250977217Sphk wreq.wi_val[0] != 0) 251077217Sphk imr->ifm_status |= IFM_ACTIVE; 251177217Sphk } 251277217Sphk} 251393359Simp 251493359Simpstatic int 251593359Simpwi_get_debug(sc, wreq) 251693359Simp struct wi_softc *sc; 251793359Simp struct wi_req *wreq; 251893359Simp{ 251993359Simp int error = 0; 252093359Simp 252193359Simp wreq->wi_len = 1; 252293359Simp 252393359Simp switch (wreq->wi_type) { 252493359Simp case WI_DEBUG_SLEEP: 252593359Simp wreq->wi_len++; 252693359Simp wreq->wi_val[0] = sc->wi_debug.wi_sleep; 252793359Simp break; 252893359Simp case WI_DEBUG_DELAYSUPP: 252993359Simp wreq->wi_len++; 253093359Simp wreq->wi_val[0] = sc->wi_debug.wi_delaysupp; 253193359Simp break; 253293359Simp case WI_DEBUG_TXSUPP: 253393359Simp wreq->wi_len++; 253493359Simp wreq->wi_val[0] = sc->wi_debug.wi_txsupp; 253593359Simp break; 253693359Simp case WI_DEBUG_MONITOR: 253793359Simp wreq->wi_len++; 253893359Simp wreq->wi_val[0] = sc->wi_debug.wi_monitor; 253993359Simp break; 254093359Simp case WI_DEBUG_LEDTEST: 254193359Simp wreq->wi_len += 3; 254293359Simp wreq->wi_val[0] = sc->wi_debug.wi_ledtest; 254393359Simp wreq->wi_val[1] = sc->wi_debug.wi_ledtest_param0; 254493359Simp wreq->wi_val[2] = sc->wi_debug.wi_ledtest_param1; 254593359Simp break; 254693359Simp case WI_DEBUG_CONTTX: 254793359Simp wreq->wi_len += 2; 254893359Simp wreq->wi_val[0] = sc->wi_debug.wi_conttx; 254993359Simp wreq->wi_val[1] = sc->wi_debug.wi_conttx_param0; 255093359Simp break; 255193359Simp case WI_DEBUG_CONTRX: 255293359Simp wreq->wi_len++; 255393359Simp wreq->wi_val[0] = sc->wi_debug.wi_contrx; 255493359Simp break; 255593359Simp case WI_DEBUG_SIGSTATE: 255693359Simp wreq->wi_len += 2; 255793359Simp wreq->wi_val[0] = sc->wi_debug.wi_sigstate; 255893359Simp wreq->wi_val[1] = sc->wi_debug.wi_sigstate_param0; 255993359Simp break; 256093359Simp case WI_DEBUG_CONFBITS: 256193359Simp wreq->wi_len += 2; 256293359Simp wreq->wi_val[0] = sc->wi_debug.wi_confbits; 256393359Simp wreq->wi_val[1] = sc->wi_debug.wi_confbits_param0; 256493359Simp break; 256593359Simp default: 256693359Simp error = EIO; 256793359Simp break; 256893359Simp } 256993359Simp 257093359Simp return (error); 257193359Simp} 257293359Simp 257393359Simpstatic int 257493359Simpwi_set_debug(sc, wreq) 257593359Simp struct wi_softc *sc; 257693359Simp struct wi_req *wreq; 257793359Simp{ 257893359Simp int error = 0; 257993359Simp u_int16_t cmd, param0 = 0, param1 = 0; 258093359Simp 258193359Simp switch (wreq->wi_type) { 258293359Simp case WI_DEBUG_RESET: 258393359Simp case WI_DEBUG_INIT: 258493359Simp case WI_DEBUG_CALENABLE: 258593359Simp break; 258693359Simp case WI_DEBUG_SLEEP: 258793359Simp sc->wi_debug.wi_sleep = 1; 258893359Simp break; 258993359Simp case WI_DEBUG_WAKE: 259093359Simp sc->wi_debug.wi_sleep = 0; 259193359Simp break; 259293359Simp case WI_DEBUG_CHAN: 259393359Simp param0 = wreq->wi_val[0]; 259493359Simp break; 259593359Simp case WI_DEBUG_DELAYSUPP: 259693359Simp sc->wi_debug.wi_delaysupp = 1; 259793359Simp break; 259893359Simp case WI_DEBUG_TXSUPP: 259993359Simp sc->wi_debug.wi_txsupp = 1; 260093359Simp break; 260193359Simp case WI_DEBUG_MONITOR: 260293359Simp sc->wi_debug.wi_monitor = 1; 260393359Simp break; 260493359Simp case WI_DEBUG_LEDTEST: 260593359Simp param0 = wreq->wi_val[0]; 260693359Simp param1 = wreq->wi_val[1]; 260793359Simp sc->wi_debug.wi_ledtest = 1; 260893359Simp sc->wi_debug.wi_ledtest_param0 = param0; 260993359Simp sc->wi_debug.wi_ledtest_param1 = param1; 261093359Simp break; 261193359Simp case WI_DEBUG_CONTTX: 261293359Simp param0 = wreq->wi_val[0]; 261393359Simp sc->wi_debug.wi_conttx = 1; 261493359Simp sc->wi_debug.wi_conttx_param0 = param0; 261593359Simp break; 261693359Simp case WI_DEBUG_STOPTEST: 261793359Simp sc->wi_debug.wi_delaysupp = 0; 261893359Simp sc->wi_debug.wi_txsupp = 0; 261993359Simp sc->wi_debug.wi_monitor = 0; 262093359Simp sc->wi_debug.wi_ledtest = 0; 262193359Simp sc->wi_debug.wi_ledtest_param0 = 0; 262293359Simp sc->wi_debug.wi_ledtest_param1 = 0; 262393359Simp sc->wi_debug.wi_conttx = 0; 262493359Simp sc->wi_debug.wi_conttx_param0 = 0; 262593359Simp sc->wi_debug.wi_contrx = 0; 262693359Simp sc->wi_debug.wi_sigstate = 0; 262793359Simp sc->wi_debug.wi_sigstate_param0 = 0; 262893359Simp break; 262993359Simp case WI_DEBUG_CONTRX: 263093359Simp sc->wi_debug.wi_contrx = 1; 263193359Simp break; 263293359Simp case WI_DEBUG_SIGSTATE: 263393359Simp param0 = wreq->wi_val[0]; 263493359Simp sc->wi_debug.wi_sigstate = 1; 263593359Simp sc->wi_debug.wi_sigstate_param0 = param0; 263693359Simp break; 263793359Simp case WI_DEBUG_CONFBITS: 263893359Simp param0 = wreq->wi_val[0]; 263993359Simp param1 = wreq->wi_val[1]; 264093359Simp sc->wi_debug.wi_confbits = param0; 264193359Simp sc->wi_debug.wi_confbits_param0 = param1; 264293359Simp break; 264393359Simp default: 264493359Simp error = EIO; 264593359Simp break; 264693359Simp } 264793359Simp 264893359Simp if (error) 264993359Simp return (error); 265093359Simp 265193359Simp cmd = WI_CMD_DEBUG | (wreq->wi_type << 8); 265293359Simp error = wi_cmd(sc, cmd, param0, param1, 0); 265393359Simp 265493359Simp return (error); 265593359Simp} 2656