if_wi.c revision 93611
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 93611 2002-04-02 02:38:35Z 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 *); 13691693Simpstatic void wi_get_id(struct wi_softc *, device_t); 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 14593611Simpint 14693611Simpwi_generic_detach(dev) 14753702Swpaul device_t dev; 14846492Swpaul{ 14946492Swpaul struct wi_softc *sc; 15046492Swpaul struct ifnet *ifp; 15146492Swpaul 15253702Swpaul sc = device_get_softc(dev); 15367092Swpaul WI_LOCK(sc); 15446492Swpaul ifp = &sc->arpcom.ac_if; 15546492Swpaul 15646492Swpaul if (sc->wi_gone) { 15753702Swpaul device_printf(dev, "already unloaded\n"); 15867092Swpaul WI_UNLOCK(sc); 15953702Swpaul return(ENODEV); 16046492Swpaul } 16146492Swpaul 16253702Swpaul wi_stop(sc); 16358274Srwatson 16477217Sphk /* Delete all remaining media. */ 16577217Sphk ifmedia_removeall(&sc->ifmedia); 16677217Sphk 16763090Sarchie ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); 16854277Swpaul bus_teardown_intr(dev, sc->irq, sc->wi_intrhand); 16953702Swpaul wi_free(dev); 17046492Swpaul sc->wi_gone = 1; 17146492Swpaul 17267092Swpaul WI_UNLOCK(sc); 17367092Swpaul mtx_destroy(&sc->wi_mtx); 17446492Swpaul 17546492Swpaul return(0); 17646492Swpaul} 17746492Swpaul 17893611Simpint 17974906Salfredwi_generic_attach(device_t dev) 18074906Salfred{ 18174906Salfred struct wi_softc *sc; 18274906Salfred struct wi_ltv_macaddr mac; 18374906Salfred struct wi_ltv_gen gen; 18474906Salfred struct ifnet *ifp; 18574906Salfred int error; 18674906Salfred 18774906Salfred sc = device_get_softc(dev); 18874906Salfred ifp = &sc->arpcom.ac_if; 18974906Salfred 19053702Swpaul error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET, 19174998Swpaul wi_intr, sc, &sc->wi_intrhand); 19253702Swpaul 19353702Swpaul if (error) { 19453702Swpaul device_printf(dev, "bus_setup_intr() failed! (%d)\n", error); 19553702Swpaul wi_free(dev); 19653702Swpaul return (error); 19753702Swpaul } 19853702Swpaul 19971228Sbmilekic mtx_init(&sc->wi_mtx, device_get_nameunit(dev), MTX_DEF | MTX_RECURSE); 20067092Swpaul WI_LOCK(sc); 20167092Swpaul 20246492Swpaul /* Reset the NIC. */ 20346492Swpaul wi_reset(sc); 20446492Swpaul 20576438Swpaul /* 20676438Swpaul * Read the station address. 20776438Swpaul * And do it twice. I've seen PRISM-based cards that return 20876438Swpaul * an error when trying to read it the first time, which causes 20976438Swpaul * the probe to fail. 21076438Swpaul */ 21146492Swpaul mac.wi_type = WI_RID_MAC_NODE; 21246492Swpaul mac.wi_len = 4; 21376457Sgrog wi_read_record(sc, (struct wi_ltv_gen *)&mac); 21475150Simp if ((error = wi_read_record(sc, (struct wi_ltv_gen *)&mac)) != 0) { 21575149Simp device_printf(dev, "mac read failed %d\n", error); 21675149Simp wi_free(dev); 21775149Simp return (error); 21875149Simp } 21946492Swpaul bcopy((char *)&mac.wi_mac_addr, 22046492Swpaul (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 22146492Swpaul 22287383Simp device_printf(dev, "802.11 address: %6D\n", sc->arpcom.ac_enaddr, ":"); 22346492Swpaul 22487383Simp wi_get_id(sc, dev); 22587383Simp 22646492Swpaul ifp->if_softc = sc; 22746492Swpaul ifp->if_unit = sc->wi_unit; 22846492Swpaul ifp->if_name = "wi"; 22946492Swpaul ifp->if_mtu = ETHERMTU; 23046492Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 23146492Swpaul ifp->if_ioctl = wi_ioctl; 23246492Swpaul ifp->if_output = ether_output; 23346492Swpaul ifp->if_start = wi_start; 23446492Swpaul ifp->if_watchdog = wi_watchdog; 23546492Swpaul ifp->if_init = wi_init; 23646492Swpaul ifp->if_baudrate = 10000000; 23746492Swpaul ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 23846492Swpaul 23946492Swpaul bzero(sc->wi_node_name, sizeof(sc->wi_node_name)); 24046492Swpaul bcopy(WI_DEFAULT_NODENAME, sc->wi_node_name, 24146492Swpaul sizeof(WI_DEFAULT_NODENAME) - 1); 24246492Swpaul 24346492Swpaul bzero(sc->wi_net_name, sizeof(sc->wi_net_name)); 24446492Swpaul bcopy(WI_DEFAULT_NETNAME, sc->wi_net_name, 24546492Swpaul sizeof(WI_DEFAULT_NETNAME) - 1); 24646492Swpaul 24746492Swpaul bzero(sc->wi_ibss_name, sizeof(sc->wi_ibss_name)); 24846492Swpaul bcopy(WI_DEFAULT_IBSS, sc->wi_ibss_name, 24946492Swpaul sizeof(WI_DEFAULT_IBSS) - 1); 25046492Swpaul 25146492Swpaul sc->wi_portnum = WI_DEFAULT_PORT; 25274139Sassar sc->wi_ptype = WI_PORTTYPE_BSS; 25346492Swpaul sc->wi_ap_density = WI_DEFAULT_AP_DENSITY; 25446492Swpaul sc->wi_rts_thresh = WI_DEFAULT_RTS_THRESH; 25546492Swpaul sc->wi_tx_rate = WI_DEFAULT_TX_RATE; 25646492Swpaul sc->wi_max_data_len = WI_DEFAULT_DATALEN; 25746492Swpaul sc->wi_create_ibss = WI_DEFAULT_CREATE_IBSS; 25846611Swpaul sc->wi_pm_enabled = WI_DEFAULT_PM_ENABLED; 25946611Swpaul sc->wi_max_sleep = WI_DEFAULT_MAX_SLEEP; 26091695Simp sc->wi_roaming = WI_DEFAULT_ROAMING; 26191695Simp sc->wi_authtype = WI_DEFAULT_AUTHTYPE; 26246492Swpaul 26346563Swpaul /* 26446563Swpaul * Read the default channel from the NIC. This may vary 26546563Swpaul * depending on the country where the NIC was purchased, so 26646563Swpaul * we can't hard-code a default and expect it to work for 26746563Swpaul * everyone. 26846563Swpaul */ 26946563Swpaul gen.wi_type = WI_RID_OWN_CHNL; 27046563Swpaul gen.wi_len = 2; 27146563Swpaul wi_read_record(sc, &gen); 27246563Swpaul sc->wi_channel = gen.wi_val; 27346563Swpaul 27456965Swpaul /* 27556965Swpaul * Find out if we support WEP on this card. 27656965Swpaul */ 27756965Swpaul gen.wi_type = WI_RID_WEP_AVAIL; 27856965Swpaul gen.wi_len = 2; 27956965Swpaul wi_read_record(sc, &gen); 28056965Swpaul sc->wi_has_wep = gen.wi_val; 28156965Swpaul 28270073Swpaul if (bootverbose) { 28370073Swpaul device_printf(sc->dev, 28487599Sobrien "%s:wi_has_wep = %d\n", 28587599Sobrien __func__, sc->wi_has_wep); 28670073Swpaul } 28770073Swpaul 28846492Swpaul bzero((char *)&sc->wi_stats, sizeof(sc->wi_stats)); 28946492Swpaul 29046492Swpaul wi_init(sc); 29146492Swpaul wi_stop(sc); 29246492Swpaul 29377217Sphk ifmedia_init(&sc->ifmedia, 0, wi_media_change, wi_media_status); 29477217Sphk /* XXX: Should read from card capabilities */ 29577217Sphk#define ADD(m, c) ifmedia_add(&sc->ifmedia, (m), (c), NULL) 29677217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 29777217Sphk IFM_IEEE80211_ADHOC, 0), 0); 29877217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 0, 0), 0); 29977217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 30077217Sphk IFM_IEEE80211_ADHOC, 0), 0); 30177217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 0, 0), 0); 30277217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 30377217Sphk IFM_IEEE80211_ADHOC, 0), 0); 30477217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 0, 0), 0); 30577217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 30677217Sphk IFM_IEEE80211_ADHOC, 0), 0); 30777217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 0, 0), 0); 30877217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 30977217Sphk IFM_IEEE80211_ADHOC, 0), 0); 31077217Sphk ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0), 0); 31177217Sphk#undef ADD 31277217Sphk ifmedia_set(&sc->ifmedia, IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 31377217Sphk 0, 0)); 31477217Sphk 31577217Sphk 31646492Swpaul /* 31763090Sarchie * Call MI attach routine. 31846492Swpaul */ 31963090Sarchie ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 32053702Swpaul callout_handle_init(&sc->wi_stat_ch); 32167092Swpaul WI_UNLOCK(sc); 32246492Swpaul 32346492Swpaul return(0); 32446492Swpaul} 32546492Swpaul 32687383Simpstatic void 32787383Simpwi_get_id(sc, dev) 32887383Simp struct wi_softc *sc; 32987383Simp device_t dev; 33087383Simp{ 33187383Simp struct wi_ltv_ver ver; 33287383Simp 33387383Simp /* getting chip identity */ 33487383Simp memset(&ver, 0, sizeof(ver)); 33593567Simp ver.wi_type = WI_RID_CARD_ID; 33687383Simp ver.wi_len = 5; 33787383Simp wi_read_record(sc, (struct wi_ltv_gen *)&ver); 33887383Simp device_printf(dev, "using "); 33992457Simp sc->wi_prism2 = 1; 34092457Simp sc->wi_nic_type = le16toh(ver.wi_ver[0]); 34192457Simp switch (sc->wi_nic_type) { 34287383Simp case WI_NIC_EVB2: 34393360Simp printf("RF:PRISM I MAC:HFA3841"); 34487383Simp break; 34587383Simp case WI_NIC_HWB3763: 34693360Simp printf("RF:PRISM II MAC:HFA3841 CARD:HWB3763 rev.B"); 34787383Simp break; 34887383Simp case WI_NIC_HWB3163: 34993360Simp printf("RF:PRISM II MAC:HFA3841 CARD:HWB3163 rev.A"); 35087383Simp break; 35187383Simp case WI_NIC_HWB3163B: 35293360Simp printf("RF:PRISM II MAC:HFA3841 CARD:HWB3163 rev.B"); 35387383Simp break; 35487383Simp case WI_NIC_EVB3: 35593560Simp case WI_NIC_3842: 35693360Simp printf("RF:PRISM II MAC:HFA3842"); 35787383Simp break; 35887383Simp case WI_NIC_HWB1153: 35993360Simp printf("RF:PRISM I MAC:HFA3841 CARD:HWB1153"); 36087383Simp break; 36187383Simp case WI_NIC_P2_SST: 36293560Simp case WI_NIC_EVB2_SST: 36393360Simp printf("RF:PRISM II MAC:HFA3841 CARD:HWB3163-SST-flash"); 36487383Simp break; 36587383Simp case WI_NIC_PRISM2_5: 36687383Simp printf("RF:PRISM2.5 MAC:ISL3873"); 36787383Simp break; 36887383Simp case WI_NIC_3874A: 36987383Simp printf("RF:PRISM2.5 MAC:ISL3874A(PCI)"); 37087383Simp break; 37193360Simp case WI_NIC_37300P: 37293360Simp printf("RF:PRISM2.5 MAC:ISL37300P"); 37393360Simp break; 37493563Simp case WI_NIC_P3_SST: 37593560Simp printf("RF:PRISM3"); 37693560Simp break; 37793563Simp case WI_NIC_P3_PCI: 37893560Simp printf("RF:PRISM3"); 37993560Simp break; 38092457Simp case WI_NIC_LUCENT: 38192457Simp case WI_NIC_LUCENT_ALT: 38292457Simp printf("WaveLan/Lucent/Orinoco chip"); 38392457Simp sc->wi_prism2 = 0; 38492457Simp break; 38587383Simp default: 38692457Simp printf("Lucent chip or unknown chip %04x", ver.wi_ver[0]); 38787383Simp sc->wi_prism2 = 0; 38887383Simp break; 38987383Simp } 39087383Simp 39192457Simp /* get firmware version */ 39292457Simp memset(&ver, 0, sizeof(ver)); 39392457Simp ver.wi_type = WI_RID_STA_IDENTITY; 39492457Simp ver.wi_len = 5; 39592457Simp wi_read_record(sc, (struct wi_ltv_gen *)&ver); 39692457Simp ver.wi_ver[1] = le16toh(ver.wi_ver[1]); 39792457Simp ver.wi_ver[2] = le16toh(ver.wi_ver[2]); 39892457Simp ver.wi_ver[3] = le16toh(ver.wi_ver[3]); 39992457Simp sc->wi_firmware_ver = ver.wi_ver[2] * 100 + ver.wi_ver[3] * 10 + 40092457Simp ver.wi_ver[1]; 40192457Simp printf(", Firmware: %d.%02d variant %d\n", ver.wi_ver[2], 40292457Simp ver.wi_ver[3], ver.wi_ver[1]); 40387383Simp 40487383Simp return; 40587383Simp} 40687383Simp 40788546Salfredstatic void 40888546Salfredwi_rxeof(sc) 40946492Swpaul struct wi_softc *sc; 41046492Swpaul{ 41146492Swpaul struct ifnet *ifp; 41246492Swpaul struct ether_header *eh; 41346492Swpaul struct mbuf *m; 41446492Swpaul int id; 41546492Swpaul 41646492Swpaul ifp = &sc->arpcom.ac_if; 41746492Swpaul 41846492Swpaul id = CSR_READ_2(sc, WI_RX_FID); 41946492Swpaul 42093359Simp /* 42193359Simp * if we have the procframe flag set, disregard all this and just 42293359Simp * read the data from the device. 42393359Simp */ 42493359Simp if (sc->wi_procframe || sc->wi_debug.wi_monitor) { 42593359Simp struct wi_frame *rx_frame; 42693359Simp int datlen, hdrlen; 42746492Swpaul 42893359Simp /* first allocate mbuf for packet storage */ 42993359Simp MGETHDR(m, M_DONTWAIT, MT_DATA); 43093359Simp if (m == NULL) { 43193359Simp ifp->if_ierrors++; 43293359Simp return; 43393359Simp } 43493359Simp MCLGET(m, M_DONTWAIT); 43593359Simp if (!(m->m_flags & M_EXT)) { 43693359Simp m_freem(m); 43793359Simp ifp->if_ierrors++; 43893359Simp return; 43993359Simp } 44046492Swpaul 44193359Simp m->m_pkthdr.rcvif = ifp; 44246492Swpaul 44393359Simp /* now read wi_frame first so we know how much data to read */ 44493359Simp if (wi_read_data(sc, id, 0, mtod(m, caddr_t), 44593359Simp sizeof(struct wi_frame))) { 44693359Simp m_freem(m); 44793359Simp ifp->if_ierrors++; 44893359Simp return; 44993359Simp } 45046492Swpaul 45193359Simp rx_frame = mtod(m, struct wi_frame *); 45293359Simp 45393359Simp switch ((rx_frame->wi_status & WI_STAT_MAC_PORT) >> 8) { 45493359Simp case 7: 45593359Simp switch (rx_frame->wi_frame_ctl & WI_FCTL_FTYPE) { 45693359Simp case WI_FTYPE_DATA: 45793359Simp hdrlen = WI_DATA_HDRLEN; 45893359Simp datlen = rx_frame->wi_dat_len + WI_FCS_LEN; 45993359Simp break; 46093359Simp case WI_FTYPE_MGMT: 46193359Simp hdrlen = WI_MGMT_HDRLEN; 46293359Simp datlen = rx_frame->wi_dat_len + WI_FCS_LEN; 46393359Simp break; 46493359Simp case WI_FTYPE_CTL: 46593359Simp /* 46693359Simp * prism2 cards don't pass control packets 46793359Simp * down properly or consistently, so we'll only 46893359Simp * pass down the header. 46993359Simp */ 47093359Simp hdrlen = WI_CTL_HDRLEN; 47193359Simp datlen = 0; 47293359Simp break; 47393359Simp default: 47493359Simp device_printf(sc->dev, "received packet of " 47593359Simp "unknown type on port 7\n"); 47693359Simp m_freem(m); 47793359Simp ifp->if_ierrors++; 47893359Simp return; 47993359Simp } 48093359Simp break; 48193359Simp case 0: 48293359Simp hdrlen = WI_DATA_HDRLEN; 48393359Simp datlen = rx_frame->wi_dat_len + WI_FCS_LEN; 48493359Simp break; 48593359Simp default: 48693359Simp device_printf(sc->dev, "received packet on invalid " 48793359Simp "port (wi_status=0x%x)\n", rx_frame->wi_status); 48893359Simp m_freem(m); 48993359Simp ifp->if_ierrors++; 49093359Simp return; 49193359Simp } 49293359Simp 49393359Simp if ((hdrlen + datlen + 2) > MCLBYTES) { 49453702Swpaul device_printf(sc->dev, "oversized packet received " 49553702Swpaul "(wi_dat_len=%d, wi_status=0x%x)\n", 49693359Simp datlen, rx_frame->wi_status); 49748553Swpaul m_freem(m); 49848553Swpaul ifp->if_ierrors++; 49948553Swpaul return; 50048553Swpaul } 50146492Swpaul 50293359Simp if (wi_read_data(sc, id, hdrlen, mtod(m, caddr_t) + hdrlen, 50393359Simp datlen + 2)) { 50493359Simp m_freem(m); 50593359Simp ifp->if_ierrors++; 50693359Simp return; 50759328Swpaul } 50875373Salfred 50993359Simp m->m_pkthdr.len = m->m_len = hdrlen + datlen; 51046492Swpaul 51193359Simp ifp->if_ipackets++; 51293359Simp 51393359Simp /* Handle BPF listeners. */ 51493359Simp if (ifp->if_bpf) 51593359Simp bpf_mtap(ifp, m); 51693359Simp 51793359Simp m_freem(m); 51893359Simp } else { 51993359Simp struct wi_frame rx_frame; 52093359Simp 52193359Simp /* First read in the frame header */ 52293359Simp if (wi_read_data(sc, id, 0, (caddr_t)&rx_frame, 52393359Simp sizeof(rx_frame))) { 52446492Swpaul ifp->if_ierrors++; 52546492Swpaul return; 52646492Swpaul } 52793359Simp 52893359Simp if (rx_frame.wi_status & WI_STAT_ERRSTAT) { 52948553Swpaul ifp->if_ierrors++; 53048553Swpaul return; 53148553Swpaul } 53246492Swpaul 53393359Simp MGETHDR(m, M_DONTWAIT, MT_DATA); 53493359Simp if (m == NULL) { 53593359Simp ifp->if_ierrors++; 53693359Simp return; 53793359Simp } 53893359Simp MCLGET(m, M_DONTWAIT); 53993359Simp if (!(m->m_flags & M_EXT)) { 54046492Swpaul m_freem(m); 54146492Swpaul ifp->if_ierrors++; 54246492Swpaul return; 54346492Swpaul } 54446492Swpaul 54593359Simp eh = mtod(m, struct ether_header *); 54693359Simp m->m_pkthdr.rcvif = ifp; 54746492Swpaul 54893359Simp if (rx_frame.wi_status == WI_STAT_1042 || 54993359Simp rx_frame.wi_status == WI_STAT_TUNNEL || 55093359Simp rx_frame.wi_status == WI_STAT_WMP_MSG) { 55193359Simp if((rx_frame.wi_dat_len + WI_SNAPHDR_LEN) > MCLBYTES) { 55293359Simp device_printf(sc->dev, 55393359Simp "oversized packet received " 55493359Simp "(wi_dat_len=%d, wi_status=0x%x)\n", 55593359Simp rx_frame.wi_dat_len, rx_frame.wi_status); 55693359Simp m_freem(m); 55793359Simp ifp->if_ierrors++; 55893359Simp return; 55993359Simp } 56093359Simp m->m_pkthdr.len = m->m_len = 56193359Simp rx_frame.wi_dat_len + WI_SNAPHDR_LEN; 56293359Simp 56393359Simp#if 0 56493359Simp bcopy((char *)&rx_frame.wi_addr1, 56593359Simp (char *)&eh->ether_dhost, ETHER_ADDR_LEN); 56693359Simp if (sc->wi_ptype == WI_PORTTYPE_ADHOC) { 56793359Simp bcopy((char *)&rx_frame.wi_addr2, 56893359Simp (char *)&eh->ether_shost, ETHER_ADDR_LEN); 56993359Simp } else { 57093359Simp bcopy((char *)&rx_frame.wi_addr3, 57193359Simp (char *)&eh->ether_shost, ETHER_ADDR_LEN); 57293359Simp } 57393359Simp#else 57493359Simp bcopy((char *)&rx_frame.wi_dst_addr, 57593359Simp (char *)&eh->ether_dhost, ETHER_ADDR_LEN); 57693359Simp bcopy((char *)&rx_frame.wi_src_addr, 57793359Simp (char *)&eh->ether_shost, ETHER_ADDR_LEN); 57893359Simp#endif 57993359Simp 58093359Simp bcopy((char *)&rx_frame.wi_type, 58193359Simp (char *)&eh->ether_type, ETHER_TYPE_LEN); 58293359Simp 58393359Simp if (wi_read_data(sc, id, WI_802_11_OFFSET, 58493359Simp mtod(m, caddr_t) + sizeof(struct ether_header), 58593359Simp m->m_len + 2)) { 58693359Simp m_freem(m); 58793359Simp ifp->if_ierrors++; 58893359Simp return; 58993359Simp } 59093359Simp } else { 59193359Simp if((rx_frame.wi_dat_len + 59293359Simp sizeof(struct ether_header)) > MCLBYTES) { 59393359Simp device_printf(sc->dev, 59493359Simp "oversized packet received " 59593359Simp "(wi_dat_len=%d, wi_status=0x%x)\n", 59693359Simp rx_frame.wi_dat_len, rx_frame.wi_status); 59793359Simp m_freem(m); 59893359Simp ifp->if_ierrors++; 59993359Simp return; 60093359Simp } 60193359Simp m->m_pkthdr.len = m->m_len = 60293359Simp rx_frame.wi_dat_len + sizeof(struct ether_header); 60393359Simp 60493359Simp if (wi_read_data(sc, id, WI_802_3_OFFSET, 60593359Simp mtod(m, caddr_t), m->m_len + 2)) { 60693359Simp m_freem(m); 60793359Simp ifp->if_ierrors++; 60893359Simp return; 60993359Simp } 61093359Simp } 61193359Simp 61293359Simp ifp->if_ipackets++; 61393359Simp 61493359Simp /* Receive packet. */ 61593359Simp m_adj(m, sizeof(struct ether_header)); 61653702Swpaul#ifdef WICACHE 61793359Simp wi_cache_store(sc, eh, m, rx_frame.wi_q_info); 61853702Swpaul#endif 61993359Simp ether_input(ifp, eh, m); 62093359Simp } 62146492Swpaul} 62246492Swpaul 62388546Salfredstatic void 62488546Salfredwi_txeof(sc, status) 62546492Swpaul struct wi_softc *sc; 62646492Swpaul int status; 62746492Swpaul{ 62846492Swpaul struct ifnet *ifp; 62946492Swpaul 63046492Swpaul ifp = &sc->arpcom.ac_if; 63146492Swpaul 63246492Swpaul ifp->if_timer = 0; 63346492Swpaul ifp->if_flags &= ~IFF_OACTIVE; 63446492Swpaul 63546492Swpaul if (status & WI_EV_TX_EXC) 63646492Swpaul ifp->if_oerrors++; 63746492Swpaul else 63846492Swpaul ifp->if_opackets++; 63946492Swpaul 64046492Swpaul return; 64146492Swpaul} 64246492Swpaul 64388546Salfredvoid 64488546Salfredwi_inquire(xsc) 64546492Swpaul void *xsc; 64646492Swpaul{ 64746492Swpaul struct wi_softc *sc; 64846492Swpaul struct ifnet *ifp; 64946492Swpaul 65046492Swpaul sc = xsc; 65146492Swpaul ifp = &sc->arpcom.ac_if; 65246492Swpaul 65346492Swpaul sc->wi_stat_ch = timeout(wi_inquire, sc, hz * 60); 65446492Swpaul 65546492Swpaul /* Don't do this while we're transmitting */ 65646492Swpaul if (ifp->if_flags & IFF_OACTIVE) 65746492Swpaul return; 65846492Swpaul 65992457Simp wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_COUNTERS, 0, 0); 66046492Swpaul 66146492Swpaul return; 66246492Swpaul} 66346492Swpaul 66488546Salfredvoid 66588546Salfredwi_update_stats(sc) 66646492Swpaul struct wi_softc *sc; 66746492Swpaul{ 66846492Swpaul struct wi_ltv_gen gen; 66946492Swpaul u_int16_t id; 67046492Swpaul struct ifnet *ifp; 67146492Swpaul u_int32_t *ptr; 67275373Salfred int len, i; 67346492Swpaul u_int16_t t; 67446492Swpaul 67546492Swpaul ifp = &sc->arpcom.ac_if; 67646492Swpaul 67746492Swpaul id = CSR_READ_2(sc, WI_INFO_FID); 67846492Swpaul 67946492Swpaul wi_read_data(sc, id, 0, (char *)&gen, 4); 68046492Swpaul 68193359Simp /* 68293359Simp * if we just got our scan results, copy it over into the scan buffer 68393359Simp * so we can return it to anyone that asks for it. (add a little 68493359Simp * compatibility with the prism2 scanning mechanism) 68593359Simp */ 68693359Simp if (gen.wi_type == WI_INFO_SCAN_RESULTS) 68793359Simp { 68893359Simp sc->wi_scanbuf_len = gen.wi_len; 68993359Simp wi_read_data(sc, id, 4, (char *)sc->wi_scanbuf, 69093359Simp sc->wi_scanbuf_len * 2); 69193359Simp 69246492Swpaul return; 69393359Simp } 69493359Simp else if (gen.wi_type != WI_INFO_COUNTERS) 69593359Simp return; 69646492Swpaul 69775373Salfred len = (gen.wi_len - 1 < sizeof(sc->wi_stats) / 4) ? 69875373Salfred gen.wi_len - 1 : sizeof(sc->wi_stats) / 4; 69946492Swpaul ptr = (u_int32_t *)&sc->wi_stats; 70046492Swpaul 70175373Salfred for (i = 0; i < len - 1; i++) { 70246492Swpaul t = CSR_READ_2(sc, WI_DATA1); 70346492Swpaul#ifdef WI_HERMES_STATS_WAR 70446492Swpaul if (t > 0xF000) 70546492Swpaul t = ~t & 0xFFFF; 70646492Swpaul#endif 70746492Swpaul ptr[i] += t; 70846492Swpaul } 70946492Swpaul 71046492Swpaul ifp->if_collisions = sc->wi_stats.wi_tx_single_retries + 71146492Swpaul sc->wi_stats.wi_tx_multi_retries + 71246492Swpaul sc->wi_stats.wi_tx_retry_limit; 71346492Swpaul 71446492Swpaul return; 71546492Swpaul} 71646492Swpaul 71788546Salfredstatic void 71888546Salfredwi_intr(xsc) 71953702Swpaul void *xsc; 72046492Swpaul{ 72153702Swpaul struct wi_softc *sc = xsc; 72246492Swpaul struct ifnet *ifp; 72346492Swpaul u_int16_t status; 72446492Swpaul 72567092Swpaul WI_LOCK(sc); 72667092Swpaul 72746492Swpaul ifp = &sc->arpcom.ac_if; 72846492Swpaul 72975373Salfred if (sc->wi_gone || !(ifp->if_flags & IFF_UP)) { 73046492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); 73146492Swpaul CSR_WRITE_2(sc, WI_INT_EN, 0); 73267092Swpaul WI_UNLOCK(sc); 73346492Swpaul return; 73446492Swpaul } 73546492Swpaul 73646492Swpaul /* Disable interrupts. */ 73746492Swpaul CSR_WRITE_2(sc, WI_INT_EN, 0); 73846492Swpaul 73946492Swpaul status = CSR_READ_2(sc, WI_EVENT_STAT); 74046492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, ~WI_INTRS); 74146492Swpaul 74246492Swpaul if (status & WI_EV_RX) { 74346492Swpaul wi_rxeof(sc); 74446492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX); 74546492Swpaul } 74646492Swpaul 74746492Swpaul if (status & WI_EV_TX) { 74846492Swpaul wi_txeof(sc, status); 74946492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX); 75046492Swpaul } 75146492Swpaul 75246492Swpaul if (status & WI_EV_ALLOC) { 75346492Swpaul int id; 75475373Salfred 75546492Swpaul id = CSR_READ_2(sc, WI_ALLOC_FID); 75646492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC); 75746492Swpaul if (id == sc->wi_tx_data_id) 75846492Swpaul wi_txeof(sc, status); 75946492Swpaul } 76046492Swpaul 76146492Swpaul if (status & WI_EV_INFO) { 76246492Swpaul wi_update_stats(sc); 76346492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO); 76446492Swpaul } 76546492Swpaul 76646492Swpaul if (status & WI_EV_TX_EXC) { 76746492Swpaul wi_txeof(sc, status); 76846492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX_EXC); 76946492Swpaul } 77046492Swpaul 77146492Swpaul if (status & WI_EV_INFO_DROP) { 77246492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO_DROP); 77346492Swpaul } 77446492Swpaul 77546492Swpaul /* Re-enable interrupts. */ 77646492Swpaul CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS); 77746492Swpaul 77875373Salfred if (ifp->if_snd.ifq_head != NULL) { 77946492Swpaul wi_start(ifp); 78075373Salfred } 78146492Swpaul 78267092Swpaul WI_UNLOCK(sc); 78367092Swpaul 78446492Swpaul return; 78546492Swpaul} 78646492Swpaul 78788546Salfredstatic int 78892457Simpwi_cmd(sc, cmd, val0, val1, val2) 78946492Swpaul struct wi_softc *sc; 79046492Swpaul int cmd; 79192457Simp int val0; 79292457Simp int val1; 79392457Simp int val2; 79446492Swpaul{ 79546492Swpaul int i, s = 0; 79646492Swpaul 79770073Swpaul /* wait for the busy bit to clear */ 79875331Simp for (i = 500; i > 0; i--) { /* 5s */ 79970073Swpaul if (!(CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY)) { 80070073Swpaul break; 80170073Swpaul } 80270073Swpaul DELAY(10*1000); /* 10 m sec */ 80370073Swpaul } 80475229Salfred if (i == 0) { 80590580Sbrooks device_printf(sc->dev, "wi_cmd: busy bit won't clear.\n" ); 80670073Swpaul return(ETIMEDOUT); 80770073Swpaul } 80870073Swpaul 80992457Simp CSR_WRITE_2(sc, WI_PARAM0, val0); 81092457Simp CSR_WRITE_2(sc, WI_PARAM1, val1); 81192457Simp CSR_WRITE_2(sc, WI_PARAM2, val2); 81246492Swpaul CSR_WRITE_2(sc, WI_COMMAND, cmd); 81346492Swpaul 81446492Swpaul for (i = 0; i < WI_TIMEOUT; i++) { 81546492Swpaul /* 81646492Swpaul * Wait for 'command complete' bit to be 81746492Swpaul * set in the event status register. 81846492Swpaul */ 81990580Sbrooks s = CSR_READ_2(sc, WI_EVENT_STAT); 82090580Sbrooks if (s & WI_EV_CMD) { 82146492Swpaul /* Ack the event and read result code. */ 82246492Swpaul s = CSR_READ_2(sc, WI_STATUS); 82346492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD); 82446492Swpaul#ifdef foo 82546492Swpaul if ((s & WI_CMD_CODE_MASK) != (cmd & WI_CMD_CODE_MASK)) 82646492Swpaul return(EIO); 82746492Swpaul#endif 82846492Swpaul if (s & WI_STAT_CMD_RESULT) 82946492Swpaul return(EIO); 83046492Swpaul break; 83146492Swpaul } 83290580Sbrooks DELAY(WI_DELAY); 83346492Swpaul } 83446492Swpaul 83590580Sbrooks if (i == WI_TIMEOUT) { 83690580Sbrooks device_printf(sc->dev, 83792457Simp "timeout in wi_cmd 0x%04x; event status 0x%04x\n", cmd, s); 83846492Swpaul return(ETIMEDOUT); 83990580Sbrooks } 84046492Swpaul 84146492Swpaul return(0); 84246492Swpaul} 84346492Swpaul 84488546Salfredstatic void 84588546Salfredwi_reset(sc) 84646492Swpaul struct wi_softc *sc; 84746492Swpaul{ 84875331Simp#define WI_INIT_TRIES 5 84975150Simp int i; 85075149Simp 85175331Simp for (i = 0; i < WI_INIT_TRIES; i++) { 85292457Simp if (wi_cmd(sc, WI_CMD_INI, 0, 0, 0) == 0) 85375149Simp break; 85490580Sbrooks DELAY(WI_DELAY * 1000); 85575149Simp } 85675331Simp if (i == WI_INIT_TRIES) 85753702Swpaul device_printf(sc->dev, "init failed\n"); 85875373Salfred 85946492Swpaul CSR_WRITE_2(sc, WI_INT_EN, 0); 86046492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); 86146492Swpaul 86246492Swpaul /* Calibrate timer. */ 86346492Swpaul WI_SETVAL(WI_RID_TICK_TIME, 8); 86470073Swpaul 86546492Swpaul return; 86646492Swpaul} 86746492Swpaul 86846492Swpaul/* 86946492Swpaul * Read an LTV record from the NIC. 87046492Swpaul */ 87188546Salfredstatic int 87288546Salfredwi_read_record(sc, ltv) 87346492Swpaul struct wi_softc *sc; 87446492Swpaul struct wi_ltv_gen *ltv; 87546492Swpaul{ 87646492Swpaul u_int16_t *ptr; 87746492Swpaul int i, len, code; 87870073Swpaul struct wi_ltv_gen *oltv, p2ltv; 87946492Swpaul 88070073Swpaul oltv = ltv; 88170073Swpaul if (sc->wi_prism2) { 88270073Swpaul switch (ltv->wi_type) { 88370073Swpaul case WI_RID_ENCRYPTION: 88470073Swpaul p2ltv.wi_type = WI_RID_P2_ENCRYPTION; 88570073Swpaul p2ltv.wi_len = 2; 88670073Swpaul ltv = &p2ltv; 88770073Swpaul break; 88870073Swpaul case WI_RID_TX_CRYPT_KEY: 88970073Swpaul p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY; 89070073Swpaul p2ltv.wi_len = 2; 89170073Swpaul ltv = &p2ltv; 89270073Swpaul break; 89370073Swpaul } 89470073Swpaul } 89570073Swpaul 89646492Swpaul /* Tell the NIC to enter record read mode. */ 89792457Simp if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_READ, ltv->wi_type, 0, 0)) 89846492Swpaul return(EIO); 89946492Swpaul 90047789Swpaul /* Seek to the record. */ 90147789Swpaul if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1)) 90247789Swpaul return(EIO); 90346492Swpaul 90446492Swpaul /* 90546492Swpaul * Read the length and record type and make sure they 90646492Swpaul * match what we expect (this verifies that we have enough 90747401Swpaul * room to hold all of the returned data). 90846492Swpaul */ 90946492Swpaul len = CSR_READ_2(sc, WI_DATA1); 91046492Swpaul if (len > ltv->wi_len) 91146492Swpaul return(ENOSPC); 91246492Swpaul code = CSR_READ_2(sc, WI_DATA1); 91346492Swpaul if (code != ltv->wi_type) 91446492Swpaul return(EIO); 91546492Swpaul 91646492Swpaul ltv->wi_len = len; 91746492Swpaul ltv->wi_type = code; 91846492Swpaul 91946492Swpaul /* Now read the data. */ 92046492Swpaul ptr = <v->wi_val; 92146492Swpaul for (i = 0; i < ltv->wi_len - 1; i++) 92246492Swpaul ptr[i] = CSR_READ_2(sc, WI_DATA1); 92346492Swpaul 92470073Swpaul if (sc->wi_prism2) { 92570073Swpaul switch (oltv->wi_type) { 92670073Swpaul case WI_RID_TX_RATE: 92770073Swpaul case WI_RID_CUR_TX_RATE: 92870073Swpaul switch (ltv->wi_val) { 92970073Swpaul case 1: oltv->wi_val = 1; break; 93070073Swpaul case 2: oltv->wi_val = 2; break; 93170073Swpaul case 3: oltv->wi_val = 6; break; 93270073Swpaul case 4: oltv->wi_val = 5; break; 93370073Swpaul case 7: oltv->wi_val = 7; break; 93470073Swpaul case 8: oltv->wi_val = 11; break; 93570073Swpaul case 15: oltv->wi_val = 3; break; 93670073Swpaul default: oltv->wi_val = 0x100 + ltv->wi_val; break; 93770073Swpaul } 93870073Swpaul break; 93970073Swpaul case WI_RID_ENCRYPTION: 94070073Swpaul oltv->wi_len = 2; 94170073Swpaul if (ltv->wi_val & 0x01) 94270073Swpaul oltv->wi_val = 1; 94370073Swpaul else 94470073Swpaul oltv->wi_val = 0; 94570073Swpaul break; 94670073Swpaul case WI_RID_TX_CRYPT_KEY: 94770073Swpaul oltv->wi_len = 2; 94870073Swpaul oltv->wi_val = ltv->wi_val; 94970073Swpaul break; 95091695Simp case WI_RID_AUTH_CNTL: 95191695Simp oltv->wi_len = 2; 95291695Simp if (le16toh(ltv->wi_val) & 0x01) 95391695Simp oltv->wi_val = htole16(1); 95491695Simp else if (le16toh(ltv->wi_val) & 0x02) 95591695Simp oltv->wi_val = htole16(2); 95691695Simp break; 95770073Swpaul } 95870073Swpaul } 95970073Swpaul 96046492Swpaul return(0); 96146492Swpaul} 96246492Swpaul 96346492Swpaul/* 96446492Swpaul * Same as read, except we inject data instead of reading it. 96546492Swpaul */ 96688546Salfredstatic int 96788546Salfredwi_write_record(sc, ltv) 96846492Swpaul struct wi_softc *sc; 96946492Swpaul struct wi_ltv_gen *ltv; 97046492Swpaul{ 97146492Swpaul u_int16_t *ptr; 97246492Swpaul int i; 97370073Swpaul struct wi_ltv_gen p2ltv; 97446492Swpaul 97570073Swpaul if (sc->wi_prism2) { 97670073Swpaul switch (ltv->wi_type) { 97770073Swpaul case WI_RID_TX_RATE: 97870073Swpaul p2ltv.wi_type = WI_RID_TX_RATE; 97970073Swpaul p2ltv.wi_len = 2; 98070073Swpaul switch (ltv->wi_val) { 98170073Swpaul case 1: p2ltv.wi_val = 1; break; 98270073Swpaul case 2: p2ltv.wi_val = 2; break; 98370073Swpaul case 3: p2ltv.wi_val = 15; break; 98470073Swpaul case 5: p2ltv.wi_val = 4; break; 98570073Swpaul case 6: p2ltv.wi_val = 3; break; 98670073Swpaul case 7: p2ltv.wi_val = 7; break; 98770073Swpaul case 11: p2ltv.wi_val = 8; break; 98870073Swpaul default: return EINVAL; 98970073Swpaul } 99070073Swpaul ltv = &p2ltv; 99170073Swpaul break; 99270073Swpaul case WI_RID_ENCRYPTION: 99370073Swpaul p2ltv.wi_type = WI_RID_P2_ENCRYPTION; 99470073Swpaul p2ltv.wi_len = 2; 99570073Swpaul if (ltv->wi_val) 99670073Swpaul p2ltv.wi_val = 0x03; 99770073Swpaul else 99870073Swpaul p2ltv.wi_val = 0x90; 99970073Swpaul ltv = &p2ltv; 100070073Swpaul break; 100170073Swpaul case WI_RID_TX_CRYPT_KEY: 100270073Swpaul p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY; 100370073Swpaul p2ltv.wi_len = 2; 100470073Swpaul p2ltv.wi_val = ltv->wi_val; 100570073Swpaul ltv = &p2ltv; 100670073Swpaul break; 100770073Swpaul case WI_RID_DEFLT_CRYPT_KEYS: 100870073Swpaul { 100970073Swpaul int error; 101091548Sbrooks int keylen; 101170073Swpaul struct wi_ltv_str ws; 101274998Swpaul struct wi_ltv_keys *wk = 101374998Swpaul (struct wi_ltv_keys *)ltv; 101474998Swpaul 101591548Sbrooks keylen = wk->wi_keys[sc->wi_tx_key].wi_keylen; 101691548Sbrooks 101770073Swpaul for (i = 0; i < 4; i++) { 101891548Sbrooks bzero(&ws, sizeof(ws)); 101991548Sbrooks ws.wi_len = (keylen > 5) ? 8 : 4; 102070073Swpaul ws.wi_type = WI_RID_P2_CRYPT_KEY0 + i; 102174998Swpaul memcpy(ws.wi_str, 102291548Sbrooks &wk->wi_keys[i].wi_keydat, keylen); 102370073Swpaul error = wi_write_record(sc, 102470073Swpaul (struct wi_ltv_gen *)&ws); 102570073Swpaul if (error) 102670073Swpaul return error; 102770073Swpaul } 102870073Swpaul return 0; 102970073Swpaul } 103091695Simp case WI_RID_AUTH_CNTL: 103191695Simp p2ltv.wi_type = WI_RID_AUTH_CNTL; 103291695Simp p2ltv.wi_len = 2; 103391695Simp if (le16toh(ltv->wi_val) == 1) 103491695Simp p2ltv.wi_val = htole16(0x01); 103591695Simp else if (le16toh(ltv->wi_val) == 2) 103691695Simp p2ltv.wi_val = htole16(0x02); 103791695Simp ltv = &p2ltv; 103891695Simp break; 103970073Swpaul } 104070073Swpaul } 104170073Swpaul 104247789Swpaul if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1)) 104347789Swpaul return(EIO); 104446492Swpaul 104546492Swpaul CSR_WRITE_2(sc, WI_DATA1, ltv->wi_len); 104646492Swpaul CSR_WRITE_2(sc, WI_DATA1, ltv->wi_type); 104746492Swpaul 104846492Swpaul ptr = <v->wi_val; 104946492Swpaul for (i = 0; i < ltv->wi_len - 1; i++) 105046492Swpaul CSR_WRITE_2(sc, WI_DATA1, ptr[i]); 105146492Swpaul 105292457Simp if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_WRITE, ltv->wi_type, 0, 0)) 105346492Swpaul return(EIO); 105446492Swpaul 105546492Swpaul return(0); 105646492Swpaul} 105746492Swpaul 105888546Salfredstatic int 105988546Salfredwi_seek(sc, id, off, chan) 106046492Swpaul struct wi_softc *sc; 106146492Swpaul int id, off, chan; 106246492Swpaul{ 106346492Swpaul int i; 106446492Swpaul int selreg, offreg; 106575373Salfred int status; 106646492Swpaul 106746492Swpaul switch (chan) { 106846492Swpaul case WI_BAP0: 106946492Swpaul selreg = WI_SEL0; 107046492Swpaul offreg = WI_OFF0; 107146492Swpaul break; 107246492Swpaul case WI_BAP1: 107346492Swpaul selreg = WI_SEL1; 107446492Swpaul offreg = WI_OFF1; 107546492Swpaul break; 107646492Swpaul default: 107753702Swpaul device_printf(sc->dev, "invalid data path: %x\n", chan); 107846492Swpaul return(EIO); 107946492Swpaul } 108046492Swpaul 108146492Swpaul CSR_WRITE_2(sc, selreg, id); 108246492Swpaul CSR_WRITE_2(sc, offreg, off); 108346492Swpaul 108446492Swpaul for (i = 0; i < WI_TIMEOUT; i++) { 108575373Salfred status = CSR_READ_2(sc, offreg); 108675373Salfred if (!(status & (WI_OFF_BUSY|WI_OFF_ERR))) 108746492Swpaul break; 108890580Sbrooks DELAY(WI_DELAY); 108946492Swpaul } 109046492Swpaul 109175373Salfred if (i == WI_TIMEOUT) { 109275373Salfred device_printf(sc->dev, "timeout in wi_seek to %x/%x; last status %x\n", 109375373Salfred id, off, status); 109446492Swpaul return(ETIMEDOUT); 109575373Salfred } 109646492Swpaul 109746492Swpaul return(0); 109846492Swpaul} 109946492Swpaul 110088546Salfredstatic int 110188546Salfredwi_read_data(sc, id, off, buf, len) 110246492Swpaul struct wi_softc *sc; 110346492Swpaul int id, off; 110446492Swpaul caddr_t buf; 110546492Swpaul int len; 110646492Swpaul{ 110746492Swpaul int i; 110846492Swpaul u_int16_t *ptr; 110946492Swpaul 111046492Swpaul if (wi_seek(sc, id, off, WI_BAP1)) 111146492Swpaul return(EIO); 111246492Swpaul 111346492Swpaul ptr = (u_int16_t *)buf; 111446492Swpaul for (i = 0; i < len / 2; i++) 111546492Swpaul ptr[i] = CSR_READ_2(sc, WI_DATA1); 111646492Swpaul 111746492Swpaul return(0); 111846492Swpaul} 111946492Swpaul 112046492Swpaul/* 112146492Swpaul * According to the comments in the HCF Light code, there is a bug in 112246492Swpaul * the Hermes (or possibly in certain Hermes firmware revisions) where 112346492Swpaul * the chip's internal autoincrement counter gets thrown off during 112446492Swpaul * data writes: the autoincrement is missed, causing one data word to 112546492Swpaul * be overwritten and subsequent words to be written to the wrong memory 112646492Swpaul * locations. The end result is that we could end up transmitting bogus 112746492Swpaul * frames without realizing it. The workaround for this is to write a 112846492Swpaul * couple of extra guard words after the end of the transfer, then 112946492Swpaul * attempt to read then back. If we fail to locate the guard words where 113046492Swpaul * we expect them, we preform the transfer over again. 113146492Swpaul */ 113288546Salfredstatic int 113388546Salfredwi_write_data(sc, id, off, buf, len) 113446492Swpaul struct wi_softc *sc; 113546492Swpaul int id, off; 113646492Swpaul caddr_t buf; 113746492Swpaul int len; 113846492Swpaul{ 113946492Swpaul int i; 114046492Swpaul u_int16_t *ptr; 114174838Salfred#ifdef WI_HERMES_AUTOINC_WAR 114274838Salfred int retries; 114346492Swpaul 114475373Salfred retries = 512; 114546492Swpaulagain: 114646492Swpaul#endif 114746492Swpaul 114846492Swpaul if (wi_seek(sc, id, off, WI_BAP0)) 114946492Swpaul return(EIO); 115046492Swpaul 115146492Swpaul ptr = (u_int16_t *)buf; 115246492Swpaul for (i = 0; i < (len / 2); i++) 115346492Swpaul CSR_WRITE_2(sc, WI_DATA0, ptr[i]); 115446492Swpaul 115546492Swpaul#ifdef WI_HERMES_AUTOINC_WAR 115646492Swpaul CSR_WRITE_2(sc, WI_DATA0, 0x1234); 115746492Swpaul CSR_WRITE_2(sc, WI_DATA0, 0x5678); 115846492Swpaul 115946492Swpaul if (wi_seek(sc, id, off + len, WI_BAP0)) 116046492Swpaul return(EIO); 116146492Swpaul 116246492Swpaul if (CSR_READ_2(sc, WI_DATA0) != 0x1234 || 116374998Swpaul CSR_READ_2(sc, WI_DATA0) != 0x5678) { 116474838Salfred if (--retries >= 0) 116574838Salfred goto again; 116674838Salfred device_printf(sc->dev, "wi_write_data device timeout\n"); 116774838Salfred return (EIO); 116874838Salfred } 116946492Swpaul#endif 117046492Swpaul 117146492Swpaul return(0); 117246492Swpaul} 117346492Swpaul 117446492Swpaul/* 117546492Swpaul * Allocate a region of memory inside the NIC and zero 117646492Swpaul * it out. 117746492Swpaul */ 117888546Salfredstatic int 117988546Salfredwi_alloc_nicmem(sc, len, id) 118046492Swpaul struct wi_softc *sc; 118146492Swpaul int len; 118246492Swpaul int *id; 118346492Swpaul{ 118446492Swpaul int i; 118546492Swpaul 118692457Simp if (wi_cmd(sc, WI_CMD_ALLOC_MEM, len, 0, 0)) { 118774998Swpaul device_printf(sc->dev, 118874998Swpaul "failed to allocate %d bytes on NIC\n", len); 118946492Swpaul return(ENOMEM); 119046492Swpaul } 119146492Swpaul 119246492Swpaul for (i = 0; i < WI_TIMEOUT; i++) { 119346492Swpaul if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_ALLOC) 119446492Swpaul break; 119590580Sbrooks DELAY(WI_DELAY); 119646492Swpaul } 119746492Swpaul 119875373Salfred if (i == WI_TIMEOUT) { 119975373Salfred device_printf(sc->dev, "time out allocating memory on card\n"); 120046492Swpaul return(ETIMEDOUT); 120175373Salfred } 120246492Swpaul 120346492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC); 120446492Swpaul *id = CSR_READ_2(sc, WI_ALLOC_FID); 120546492Swpaul 120675373Salfred if (wi_seek(sc, *id, 0, WI_BAP0)) { 120775373Salfred device_printf(sc->dev, "seek failed while allocating memory on card\n"); 120847789Swpaul return(EIO); 120975373Salfred } 121046492Swpaul 121146492Swpaul for (i = 0; i < len / 2; i++) 121246492Swpaul CSR_WRITE_2(sc, WI_DATA0, 0); 121346492Swpaul 121446492Swpaul return(0); 121546492Swpaul} 121646492Swpaul 121788546Salfredstatic void 121888546Salfredwi_setmulti(sc) 121946492Swpaul struct wi_softc *sc; 122046492Swpaul{ 122146492Swpaul struct ifnet *ifp; 122246492Swpaul int i = 0; 122346492Swpaul struct ifmultiaddr *ifma; 122446492Swpaul struct wi_ltv_mcast mcast; 122546492Swpaul 122646492Swpaul ifp = &sc->arpcom.ac_if; 122746492Swpaul 122846492Swpaul bzero((char *)&mcast, sizeof(mcast)); 122946492Swpaul 123046492Swpaul mcast.wi_type = WI_RID_MCAST; 123146492Swpaul mcast.wi_len = (3 * 16) + 1; 123246492Swpaul 123346492Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 123446492Swpaul wi_write_record(sc, (struct wi_ltv_gen *)&mcast); 123546492Swpaul return; 123646492Swpaul } 123746492Swpaul 123872084Sphk TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 123946492Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 124046492Swpaul continue; 124146492Swpaul if (i < 16) { 124246492Swpaul bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 124346492Swpaul (char *)&mcast.wi_mcast[i], ETHER_ADDR_LEN); 124446492Swpaul i++; 124546492Swpaul } else { 124646492Swpaul bzero((char *)&mcast, sizeof(mcast)); 124746492Swpaul break; 124846492Swpaul } 124946492Swpaul } 125046492Swpaul 125146492Swpaul mcast.wi_len = (i * 3) + 1; 125246492Swpaul wi_write_record(sc, (struct wi_ltv_gen *)&mcast); 125346492Swpaul 125446492Swpaul return; 125546492Swpaul} 125646492Swpaul 125788546Salfredstatic void 125888546Salfredwi_setdef(sc, wreq) 125946492Swpaul struct wi_softc *sc; 126046492Swpaul struct wi_req *wreq; 126146492Swpaul{ 126246492Swpaul struct sockaddr_dl *sdl; 126346492Swpaul struct ifaddr *ifa; 126446492Swpaul struct ifnet *ifp; 126546492Swpaul 126646492Swpaul ifp = &sc->arpcom.ac_if; 126746492Swpaul 126846492Swpaul switch(wreq->wi_type) { 126946492Swpaul case WI_RID_MAC_NODE: 127083130Sjlemon ifa = ifaddr_byindex(ifp->if_index); 127146492Swpaul sdl = (struct sockaddr_dl *)ifa->ifa_addr; 127246492Swpaul bcopy((char *)&wreq->wi_val, (char *)&sc->arpcom.ac_enaddr, 127346492Swpaul ETHER_ADDR_LEN); 127446492Swpaul bcopy((char *)&wreq->wi_val, LLADDR(sdl), ETHER_ADDR_LEN); 127546492Swpaul break; 127646492Swpaul case WI_RID_PORTTYPE: 127791695Simp sc->wi_ptype = le16toh(wreq->wi_val[0]); 127846492Swpaul break; 127946492Swpaul case WI_RID_TX_RATE: 128091695Simp sc->wi_tx_rate = le16toh(wreq->wi_val[0]); 128146492Swpaul break; 128246492Swpaul case WI_RID_MAX_DATALEN: 128391695Simp sc->wi_max_data_len = le16toh(wreq->wi_val[0]); 128446492Swpaul break; 128546492Swpaul case WI_RID_RTS_THRESH: 128691695Simp sc->wi_rts_thresh = le16toh(wreq->wi_val[0]); 128746492Swpaul break; 128846492Swpaul case WI_RID_SYSTEM_SCALE: 128991695Simp sc->wi_ap_density = le16toh(wreq->wi_val[0]); 129046492Swpaul break; 129146492Swpaul case WI_RID_CREATE_IBSS: 129291695Simp sc->wi_create_ibss = le16toh(wreq->wi_val[0]); 129346492Swpaul break; 129446563Swpaul case WI_RID_OWN_CHNL: 129591695Simp sc->wi_channel = le16toh(wreq->wi_val[0]); 129646563Swpaul break; 129746492Swpaul case WI_RID_NODENAME: 129846492Swpaul bzero(sc->wi_node_name, sizeof(sc->wi_node_name)); 129946492Swpaul bcopy((char *)&wreq->wi_val[1], sc->wi_node_name, 30); 130046492Swpaul break; 130146492Swpaul case WI_RID_DESIRED_SSID: 130246492Swpaul bzero(sc->wi_net_name, sizeof(sc->wi_net_name)); 130346492Swpaul bcopy((char *)&wreq->wi_val[1], sc->wi_net_name, 30); 130446492Swpaul break; 130546492Swpaul case WI_RID_OWN_SSID: 130646492Swpaul bzero(sc->wi_ibss_name, sizeof(sc->wi_ibss_name)); 130746492Swpaul bcopy((char *)&wreq->wi_val[1], sc->wi_ibss_name, 30); 130846492Swpaul break; 130946611Swpaul case WI_RID_PM_ENABLED: 131091695Simp sc->wi_pm_enabled = le16toh(wreq->wi_val[0]); 131146611Swpaul break; 131291695Simp case WI_RID_MICROWAVE_OVEN: 131391695Simp sc->wi_mor_enabled = le16toh(wreq->wi_val[0]); 131491695Simp break; 131546611Swpaul case WI_RID_MAX_SLEEP: 131691695Simp sc->wi_max_sleep = le16toh(wreq->wi_val[0]); 131746611Swpaul break; 131891695Simp case WI_RID_AUTH_CNTL: 131991695Simp sc->wi_authtype = le16toh(wreq->wi_val[0]); 132091695Simp break; 132191695Simp case WI_RID_ROAMING_MODE: 132291695Simp sc->wi_roaming = le16toh(wreq->wi_val[0]); 132391695Simp break; 132456965Swpaul case WI_RID_ENCRYPTION: 132591695Simp sc->wi_use_wep = le16toh(wreq->wi_val[0]); 132656965Swpaul break; 132756965Swpaul case WI_RID_TX_CRYPT_KEY: 132891695Simp sc->wi_tx_key = le16toh(wreq->wi_val[0]); 132956965Swpaul break; 133056965Swpaul case WI_RID_DEFLT_CRYPT_KEYS: 133156965Swpaul bcopy((char *)wreq, (char *)&sc->wi_keys, 133256965Swpaul sizeof(struct wi_ltv_keys)); 133356965Swpaul break; 133446492Swpaul default: 133546492Swpaul break; 133646492Swpaul } 133746492Swpaul 133846563Swpaul /* Reinitialize WaveLAN. */ 133946563Swpaul wi_init(sc); 134046563Swpaul 134146492Swpaul return; 134246492Swpaul} 134346492Swpaul 134488546Salfredstatic int 134588546Salfredwi_ioctl(ifp, command, data) 134646492Swpaul struct ifnet *ifp; 134746492Swpaul u_long command; 134846492Swpaul caddr_t data; 134946492Swpaul{ 135067092Swpaul int error = 0; 135177217Sphk int len; 135277217Sphk u_int8_t tmpkey[14]; 135377217Sphk char tmpssid[IEEE80211_NWID_LEN]; 135446492Swpaul struct wi_softc *sc; 135546492Swpaul struct wi_req wreq; 135646492Swpaul struct ifreq *ifr; 135777217Sphk struct ieee80211req *ireq; 135893593Sjhb struct thread *td = curthread; 135946492Swpaul 136046492Swpaul sc = ifp->if_softc; 136167092Swpaul WI_LOCK(sc); 136246492Swpaul ifr = (struct ifreq *)data; 136377217Sphk ireq = (struct ieee80211req *)data; 136446492Swpaul 136561818Sroberto if (sc->wi_gone) { 136661818Sroberto error = ENODEV; 136761818Sroberto goto out; 136861818Sroberto } 136946492Swpaul 137046492Swpaul switch(command) { 137146492Swpaul case SIOCSIFADDR: 137246492Swpaul case SIOCGIFADDR: 137346492Swpaul case SIOCSIFMTU: 137446492Swpaul error = ether_ioctl(ifp, command, data); 137546492Swpaul break; 137646492Swpaul case SIOCSIFFLAGS: 137746492Swpaul if (ifp->if_flags & IFF_UP) { 137846492Swpaul if (ifp->if_flags & IFF_RUNNING && 137946492Swpaul ifp->if_flags & IFF_PROMISC && 138046492Swpaul !(sc->wi_if_flags & IFF_PROMISC)) { 138146492Swpaul WI_SETVAL(WI_RID_PROMISC, 1); 138246492Swpaul } else if (ifp->if_flags & IFF_RUNNING && 138346492Swpaul !(ifp->if_flags & IFF_PROMISC) && 138446492Swpaul sc->wi_if_flags & IFF_PROMISC) { 138546492Swpaul WI_SETVAL(WI_RID_PROMISC, 0); 138646492Swpaul } else 138746492Swpaul wi_init(sc); 138846492Swpaul } else { 138946492Swpaul if (ifp->if_flags & IFF_RUNNING) { 139046492Swpaul wi_stop(sc); 139146492Swpaul } 139246492Swpaul } 139346492Swpaul sc->wi_if_flags = ifp->if_flags; 139446492Swpaul error = 0; 139546492Swpaul break; 139677217Sphk case SIOCSIFMEDIA: 139777217Sphk case SIOCGIFMEDIA: 139877217Sphk error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); 139977217Sphk break; 140046492Swpaul case SIOCADDMULTI: 140146492Swpaul case SIOCDELMULTI: 140246492Swpaul wi_setmulti(sc); 140346492Swpaul error = 0; 140446492Swpaul break; 140546492Swpaul case SIOCGWAVELAN: 140646492Swpaul error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); 140746492Swpaul if (error) 140846492Swpaul break; 140965581Swpaul /* Don't show WEP keys to non-root users. */ 141093593Sjhb if (wreq.wi_type == WI_RID_DEFLT_CRYPT_KEYS && suser(td)) 141165581Swpaul break; 141246492Swpaul if (wreq.wi_type == WI_RID_IFACE_STATS) { 141346492Swpaul bcopy((char *)&sc->wi_stats, (char *)&wreq.wi_val, 141446492Swpaul sizeof(sc->wi_stats)); 141546492Swpaul wreq.wi_len = (sizeof(sc->wi_stats) / 2) + 1; 141656965Swpaul } else if (wreq.wi_type == WI_RID_DEFLT_CRYPT_KEYS) { 141756965Swpaul bcopy((char *)&sc->wi_keys, (char *)&wreq, 141856965Swpaul sizeof(struct wi_ltv_keys)); 141953702Swpaul } 142053702Swpaul#ifdef WICACHE 142153702Swpaul else if (wreq.wi_type == WI_RID_ZERO_CACHE) { 142253702Swpaul sc->wi_sigitems = sc->wi_nextitem = 0; 142353702Swpaul } else if (wreq.wi_type == WI_RID_READ_CACHE) { 142453702Swpaul char *pt = (char *)&wreq.wi_val; 142553702Swpaul bcopy((char *)&sc->wi_sigitems, 142653702Swpaul (char *)pt, sizeof(int)); 142753702Swpaul pt += (sizeof (int)); 142853702Swpaul wreq.wi_len = sizeof(int) / 2; 142953702Swpaul bcopy((char *)&sc->wi_sigcache, (char *)pt, 143053702Swpaul sizeof(struct wi_sigcache) * sc->wi_sigitems); 143153702Swpaul wreq.wi_len += ((sizeof(struct wi_sigcache) * 143253702Swpaul sc->wi_sigitems) / 2) + 1; 143353702Swpaul } 143453702Swpaul#endif 143593359Simp else if (wreq.wi_type == WI_RID_PROCFRAME) { 143693359Simp wreq.wi_len = 2; 143793359Simp wreq.wi_val[0] = sc->wi_procframe; 143893359Simp } else if (wreq.wi_type == WI_RID_PRISM2) { 143993359Simp wreq.wi_len = 2; 144093359Simp wreq.wi_val[0] = sc->wi_prism2; 144193359Simp } else if (wreq.wi_type == WI_RID_SCAN_RES && !sc->wi_prism2) { 144293359Simp memcpy((char *)wreq.wi_val, (char *)sc->wi_scanbuf, 144393359Simp sc->wi_scanbuf_len * 2); 144493359Simp wreq.wi_len = sc->wi_scanbuf_len; 144593359Simp } else { 144646492Swpaul if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq)) { 144746492Swpaul error = EINVAL; 144846492Swpaul break; 144946492Swpaul } 145046492Swpaul } 145146492Swpaul error = copyout(&wreq, ifr->ifr_data, sizeof(wreq)); 145246492Swpaul break; 145346492Swpaul case SIOCSWAVELAN: 145493593Sjhb if ((error = suser(td))) 145561818Sroberto goto out; 145646492Swpaul error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); 145746492Swpaul if (error) 145846492Swpaul break; 145946492Swpaul if (wreq.wi_type == WI_RID_IFACE_STATS) { 146046492Swpaul error = EINVAL; 146146492Swpaul break; 146246492Swpaul } else if (wreq.wi_type == WI_RID_MGMT_XMIT) { 146346492Swpaul error = wi_mgmt_xmit(sc, (caddr_t)&wreq.wi_val, 146446492Swpaul wreq.wi_len); 146593359Simp } else if (wreq.wi_type == WI_RID_PROCFRAME) { 146693359Simp sc->wi_procframe = wreq.wi_val[0]; 146793359Simp /* 146893359Simp * if we're getting a scan request from a wavelan card 146993359Simp * (non-prism2), send out a cmd_inquire to the card to scan 147093359Simp * results for the scan will be received through the info 147193359Simp * interrupt handler. otherwise the scan request can be 147293359Simp * directly handled by a prism2 card's rid interface. 147393359Simp */ 147493359Simp } else if (wreq.wi_type == WI_RID_SCAN_REQ && !sc->wi_prism2) { 147593359Simp wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_SCAN_RESULTS, 0, 0); 147646492Swpaul } else { 147746492Swpaul error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq); 147846492Swpaul if (!error) 147946492Swpaul wi_setdef(sc, &wreq); 148046492Swpaul } 148146492Swpaul break; 148293359Simp case SIOCGPRISM2DEBUG: 148393359Simp error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); 148493359Simp if (error) 148593359Simp break; 148693359Simp if (!(ifp->if_flags & IFF_RUNNING) || !sc->wi_prism2) { 148793359Simp error = EIO; 148893359Simp break; 148993359Simp } 149093359Simp error = wi_get_debug(sc, &wreq); 149193359Simp if (error == 0) 149293359Simp error = copyout(&wreq, ifr->ifr_data, sizeof(wreq)); 149393359Simp break; 149493359Simp case SIOCSPRISM2DEBUG: 149593593Sjhb if ((error = suser(td))) 149693359Simp goto out; 149793359Simp error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); 149893359Simp if (error) 149993359Simp break; 150093359Simp error = wi_set_debug(sc, &wreq); 150193359Simp break; 150277217Sphk case SIOCG80211: 150377217Sphk switch(ireq->i_type) { 150477217Sphk case IEEE80211_IOC_SSID: 150577217Sphk if(ireq->i_val == -1) { 150677217Sphk bzero(tmpssid, IEEE80211_NWID_LEN); 150777217Sphk error = wi_get_cur_ssid(sc, tmpssid, &len); 150877217Sphk if (error != 0) 150977217Sphk break; 151077217Sphk error = copyout(tmpssid, ireq->i_data, 151177217Sphk IEEE80211_NWID_LEN); 151277217Sphk ireq->i_len = len; 151377217Sphk } else if (ireq->i_val == 0) { 151477217Sphk error = copyout(sc->wi_net_name, 151577217Sphk ireq->i_data, 151677217Sphk IEEE80211_NWID_LEN); 151777217Sphk ireq->i_len = IEEE80211_NWID_LEN; 151877217Sphk } else 151977217Sphk error = EINVAL; 152077217Sphk break; 152177217Sphk case IEEE80211_IOC_NUMSSIDS: 152277217Sphk ireq->i_val = 1; 152377217Sphk break; 152477217Sphk case IEEE80211_IOC_WEP: 152577217Sphk if(!sc->wi_has_wep) { 152677217Sphk ireq->i_val = IEEE80211_WEP_NOSUP; 152777217Sphk } else { 152877217Sphk if(sc->wi_use_wep) { 152977217Sphk ireq->i_val = 153077217Sphk IEEE80211_WEP_MIXED; 153177217Sphk } else { 153277217Sphk ireq->i_val = 153377217Sphk IEEE80211_WEP_OFF; 153477217Sphk } 153577217Sphk } 153677217Sphk break; 153777217Sphk case IEEE80211_IOC_WEPKEY: 153877217Sphk if(!sc->wi_has_wep || 153977217Sphk ireq->i_val < 0 || ireq->i_val > 3) { 154077217Sphk error = EINVAL; 154177217Sphk break; 154277217Sphk } 154377217Sphk len = sc->wi_keys.wi_keys[ireq->i_val].wi_keylen; 154493593Sjhb if (suser(td)) 154577217Sphk bcopy(sc->wi_keys.wi_keys[ireq->i_val].wi_keydat, 154677217Sphk tmpkey, len); 154777217Sphk else 154877217Sphk bzero(tmpkey, len); 154977217Sphk 155077217Sphk ireq->i_len = len; 155177217Sphk error = copyout(tmpkey, ireq->i_data, len); 155277217Sphk 155377217Sphk break; 155477217Sphk case IEEE80211_IOC_NUMWEPKEYS: 155577217Sphk if(!sc->wi_has_wep) 155677217Sphk error = EINVAL; 155777217Sphk else 155877217Sphk ireq->i_val = 4; 155977217Sphk break; 156077217Sphk case IEEE80211_IOC_WEPTXKEY: 156177217Sphk if(!sc->wi_has_wep) 156277217Sphk error = EINVAL; 156377217Sphk else 156477217Sphk ireq->i_val = sc->wi_tx_key; 156577217Sphk break; 156677217Sphk case IEEE80211_IOC_AUTHMODE: 156777217Sphk ireq->i_val = IEEE80211_AUTH_NONE; 156877217Sphk break; 156977217Sphk case IEEE80211_IOC_STATIONNAME: 157077217Sphk error = copyout(sc->wi_node_name, 157177217Sphk ireq->i_data, IEEE80211_NWID_LEN); 157277217Sphk ireq->i_len = IEEE80211_NWID_LEN; 157377217Sphk break; 157477217Sphk case IEEE80211_IOC_CHANNEL: 157577217Sphk wreq.wi_type = WI_RID_CURRENT_CHAN; 157677217Sphk wreq.wi_len = WI_MAX_DATALEN; 157777217Sphk if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq)) 157877217Sphk error = EINVAL; 157977217Sphk else { 158077217Sphk ireq->i_val = wreq.wi_val[0]; 158177217Sphk } 158277217Sphk break; 158377217Sphk case IEEE80211_IOC_POWERSAVE: 158477217Sphk if(sc->wi_pm_enabled) 158577217Sphk ireq->i_val = IEEE80211_POWERSAVE_ON; 158677217Sphk else 158777217Sphk ireq->i_val = IEEE80211_POWERSAVE_OFF; 158877217Sphk break; 158977217Sphk case IEEE80211_IOC_POWERSAVESLEEP: 159077217Sphk ireq->i_val = sc->wi_max_sleep; 159177217Sphk break; 159277217Sphk default: 159377217Sphk error = EINVAL; 159477217Sphk } 159577217Sphk break; 159677217Sphk case SIOCS80211: 159793593Sjhb if ((error = suser(td))) 159877217Sphk goto out; 159977217Sphk switch(ireq->i_type) { 160077217Sphk case IEEE80211_IOC_SSID: 160177217Sphk if (ireq->i_val != 0 || 160277217Sphk ireq->i_len > IEEE80211_NWID_LEN) { 160377217Sphk error = EINVAL; 160477217Sphk break; 160577217Sphk } 160677217Sphk /* We set both of them */ 160777217Sphk bzero(sc->wi_net_name, IEEE80211_NWID_LEN); 160877217Sphk error = copyin(ireq->i_data, 160977217Sphk sc->wi_net_name, ireq->i_len); 161077217Sphk bcopy(sc->wi_net_name, sc->wi_ibss_name, IEEE80211_NWID_LEN); 161177217Sphk break; 161277217Sphk case IEEE80211_IOC_WEP: 161377217Sphk /* 161477217Sphk * These cards only support one mode so 161577217Sphk * we just turn wep on what ever is 161677217Sphk * passed in if it's not OFF. 161777217Sphk */ 161877217Sphk if (ireq->i_val == IEEE80211_WEP_OFF) { 161977217Sphk sc->wi_use_wep = 0; 162077217Sphk } else { 162177217Sphk sc->wi_use_wep = 1; 162277217Sphk } 162377217Sphk break; 162477217Sphk case IEEE80211_IOC_WEPKEY: 162577217Sphk if (ireq->i_val < 0 || ireq->i_val > 3 || 162677217Sphk ireq->i_len > 13) { 162777217Sphk error = EINVAL; 162877217Sphk break; 162977217Sphk } 163077217Sphk bzero(sc->wi_keys.wi_keys[ireq->i_val].wi_keydat, 13); 163177217Sphk error = copyin(ireq->i_data, 163277217Sphk sc->wi_keys.wi_keys[ireq->i_val].wi_keydat, 163377217Sphk ireq->i_len); 163477217Sphk if(error) 163577217Sphk break; 163677217Sphk sc->wi_keys.wi_keys[ireq->i_val].wi_keylen = 163777217Sphk ireq->i_len; 163877217Sphk break; 163977217Sphk case IEEE80211_IOC_WEPTXKEY: 164077217Sphk if (ireq->i_val < 0 || ireq->i_val > 3) { 164177217Sphk error = EINVAL; 164277217Sphk break; 164377217Sphk } 164477217Sphk sc->wi_tx_key = ireq->i_val; 164577217Sphk break; 164677217Sphk case IEEE80211_IOC_AUTHMODE: 164777217Sphk error = EINVAL; 164877217Sphk break; 164977217Sphk case IEEE80211_IOC_STATIONNAME: 165077217Sphk if (ireq->i_len > 32) { 165177217Sphk error = EINVAL; 165277217Sphk break; 165377217Sphk } 165477217Sphk bzero(sc->wi_node_name, 32); 165577217Sphk error = copyin(ireq->i_data, 165677217Sphk sc->wi_node_name, ireq->i_len); 165777217Sphk break; 165877217Sphk case IEEE80211_IOC_CHANNEL: 165977217Sphk /* 166077217Sphk * The actual range is 1-14, but if you 166177217Sphk * set it to 0 you get the default. So 166277217Sphk * we let that work too. 166377217Sphk */ 166477217Sphk if (ireq->i_val < 0 || ireq->i_val > 14) { 166577217Sphk error = EINVAL; 166677217Sphk break; 166777217Sphk } 166877217Sphk sc->wi_channel = ireq->i_val; 166977217Sphk break; 167077217Sphk case IEEE80211_IOC_POWERSAVE: 167177217Sphk switch (ireq->i_val) { 167277217Sphk case IEEE80211_POWERSAVE_OFF: 167377217Sphk sc->wi_pm_enabled = 0; 167477217Sphk break; 167577217Sphk case IEEE80211_POWERSAVE_ON: 167677217Sphk sc->wi_pm_enabled = 1; 167777217Sphk break; 167877217Sphk default: 167977217Sphk error = EINVAL; 168077217Sphk break; 168177217Sphk } 168277217Sphk break; 168377217Sphk case IEEE80211_IOC_POWERSAVESLEEP: 168477217Sphk if (ireq->i_val < 0) { 168577217Sphk error = EINVAL; 168677217Sphk break; 168777217Sphk } 168877217Sphk sc->wi_max_sleep = ireq->i_val; 168977217Sphk break; 169077217Sphk default: 169177217Sphk error = EINVAL; 169277217Sphk break; 169377217Sphk } 169477217Sphk 169577217Sphk /* Reinitialize WaveLAN. */ 169677217Sphk wi_init(sc); 169777217Sphk 169877217Sphk break; 169946492Swpaul default: 170046492Swpaul error = EINVAL; 170146492Swpaul break; 170246492Swpaul } 170361818Srobertoout: 170467092Swpaul WI_UNLOCK(sc); 170546492Swpaul 170646492Swpaul return(error); 170746492Swpaul} 170846492Swpaul 170988546Salfredstatic void 171088546Salfredwi_init(xsc) 171146492Swpaul void *xsc; 171246492Swpaul{ 171346492Swpaul struct wi_softc *sc = xsc; 171446492Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 171546492Swpaul struct wi_ltv_macaddr mac; 171646492Swpaul int id = 0; 171746492Swpaul 171867092Swpaul WI_LOCK(sc); 171967092Swpaul 172067092Swpaul if (sc->wi_gone) { 172167092Swpaul WI_UNLOCK(sc); 172246492Swpaul return; 172367092Swpaul } 172446492Swpaul 172546492Swpaul if (ifp->if_flags & IFF_RUNNING) 172646492Swpaul wi_stop(sc); 172746492Swpaul 172846492Swpaul wi_reset(sc); 172946492Swpaul 173046492Swpaul /* Program max data length. */ 173146492Swpaul WI_SETVAL(WI_RID_MAX_DATALEN, sc->wi_max_data_len); 173246492Swpaul 173347401Swpaul /* Enable/disable IBSS creation. */ 173446492Swpaul WI_SETVAL(WI_RID_CREATE_IBSS, sc->wi_create_ibss); 173546492Swpaul 173646492Swpaul /* Set the port type. */ 173746492Swpaul WI_SETVAL(WI_RID_PORTTYPE, sc->wi_ptype); 173846492Swpaul 173946492Swpaul /* Program the RTS/CTS threshold. */ 174046492Swpaul WI_SETVAL(WI_RID_RTS_THRESH, sc->wi_rts_thresh); 174146492Swpaul 174246492Swpaul /* Program the TX rate */ 174346492Swpaul WI_SETVAL(WI_RID_TX_RATE, sc->wi_tx_rate); 174446492Swpaul 174546492Swpaul /* Access point density */ 174646492Swpaul WI_SETVAL(WI_RID_SYSTEM_SCALE, sc->wi_ap_density); 174746492Swpaul 174846611Swpaul /* Power Management Enabled */ 174946611Swpaul WI_SETVAL(WI_RID_PM_ENABLED, sc->wi_pm_enabled); 175046611Swpaul 175146611Swpaul /* Power Managment Max Sleep */ 175246611Swpaul WI_SETVAL(WI_RID_MAX_SLEEP, sc->wi_max_sleep); 175346611Swpaul 175491695Simp /* Roaming type */ 175591695Simp WI_SETVAL(WI_RID_ROAMING_MODE, sc->wi_roaming); 175691695Simp 175746492Swpaul /* Specify the IBSS name */ 175846492Swpaul WI_SETSTR(WI_RID_OWN_SSID, sc->wi_ibss_name); 175946492Swpaul 176046492Swpaul /* Specify the network name */ 176146492Swpaul WI_SETSTR(WI_RID_DESIRED_SSID, sc->wi_net_name); 176246492Swpaul 176346563Swpaul /* Specify the frequency to use */ 176446563Swpaul WI_SETVAL(WI_RID_OWN_CHNL, sc->wi_channel); 176546563Swpaul 176646492Swpaul /* Program the nodename. */ 176746492Swpaul WI_SETSTR(WI_RID_NODENAME, sc->wi_node_name); 176846492Swpaul 176946492Swpaul /* Set our MAC address. */ 177046492Swpaul mac.wi_len = 4; 177146492Swpaul mac.wi_type = WI_RID_MAC_NODE; 177246492Swpaul bcopy((char *)&sc->arpcom.ac_enaddr, 177346492Swpaul (char *)&mac.wi_mac_addr, ETHER_ADDR_LEN); 177446492Swpaul wi_write_record(sc, (struct wi_ltv_gen *)&mac); 177546492Swpaul 177656965Swpaul /* Configure WEP. */ 177756965Swpaul if (sc->wi_has_wep) { 177856965Swpaul WI_SETVAL(WI_RID_ENCRYPTION, sc->wi_use_wep); 177956965Swpaul WI_SETVAL(WI_RID_TX_CRYPT_KEY, sc->wi_tx_key); 178056965Swpaul sc->wi_keys.wi_len = (sizeof(struct wi_ltv_keys) / 2) + 1; 178156965Swpaul sc->wi_keys.wi_type = WI_RID_DEFLT_CRYPT_KEYS; 178256965Swpaul wi_write_record(sc, (struct wi_ltv_gen *)&sc->wi_keys); 178391695Simp if (sc->wi_prism2 && sc->wi_use_wep) { 178491695Simp /* 178591695Simp * ONLY HWB3163 EVAL-CARD Firmware version 178691695Simp * less than 0.8 variant3 178791695Simp * 178891695Simp * If promiscuous mode disable, Prism2 chip 178991695Simp * does not work with WEP . 179091695Simp * It is under investigation for details. 179191695Simp * (ichiro@netbsd.org) 179291695Simp */ 179392457Simp if (sc->wi_firmware_ver < 83 ) { 179491695Simp /* firm ver < 0.8 variant 3 */ 179591695Simp WI_SETVAL(WI_RID_PROMISC, 1); 179691695Simp } 179791695Simp WI_SETVAL(WI_RID_AUTH_CNTL, sc->wi_authtype); 179891695Simp } 179956965Swpaul } 180056965Swpaul 180146492Swpaul /* Initialize promisc mode. */ 180246492Swpaul if (ifp->if_flags & IFF_PROMISC) { 180346492Swpaul WI_SETVAL(WI_RID_PROMISC, 1); 180446492Swpaul } else { 180546492Swpaul WI_SETVAL(WI_RID_PROMISC, 0); 180646492Swpaul } 180746492Swpaul 180846492Swpaul /* Set multicast filter. */ 180946492Swpaul wi_setmulti(sc); 181046492Swpaul 181146492Swpaul /* Enable desired port */ 181292457Simp wi_cmd(sc, WI_CMD_ENABLE | sc->wi_portnum, 0, 0, 0); 181346492Swpaul 181475373Salfred if (wi_alloc_nicmem(sc, ETHER_MAX_LEN + sizeof(struct wi_frame) + 8, &id)) 181553702Swpaul device_printf(sc->dev, "tx buffer allocation failed\n"); 181646492Swpaul sc->wi_tx_data_id = id; 181746492Swpaul 181875373Salfred if (wi_alloc_nicmem(sc, ETHER_MAX_LEN + sizeof(struct wi_frame) + 8, &id)) 181953702Swpaul device_printf(sc->dev, "mgmt. buffer allocation failed\n"); 182046492Swpaul sc->wi_tx_mgmt_id = id; 182146492Swpaul 182246492Swpaul /* enable interrupts */ 182346492Swpaul CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS); 182446492Swpaul 182546492Swpaul ifp->if_flags |= IFF_RUNNING; 182646492Swpaul ifp->if_flags &= ~IFF_OACTIVE; 182746492Swpaul 182846492Swpaul sc->wi_stat_ch = timeout(wi_inquire, sc, hz * 60); 182967092Swpaul WI_UNLOCK(sc); 183046492Swpaul 183146492Swpaul return; 183246492Swpaul} 183346492Swpaul 183488546Salfredstatic void 183588546Salfredwi_start(ifp) 183646492Swpaul struct ifnet *ifp; 183746492Swpaul{ 183846492Swpaul struct wi_softc *sc; 183946492Swpaul struct mbuf *m0; 184046492Swpaul struct wi_frame tx_frame; 184146492Swpaul struct ether_header *eh; 184246492Swpaul int id; 184346492Swpaul 184446492Swpaul sc = ifp->if_softc; 184567092Swpaul WI_LOCK(sc); 184646492Swpaul 184767092Swpaul if (sc->wi_gone) { 184867092Swpaul WI_UNLOCK(sc); 184946492Swpaul return; 185067092Swpaul } 185146492Swpaul 185267092Swpaul if (ifp->if_flags & IFF_OACTIVE) { 185367092Swpaul WI_UNLOCK(sc); 185446492Swpaul return; 185567092Swpaul } 185646492Swpaul 185746492Swpaul IF_DEQUEUE(&ifp->if_snd, m0); 185867092Swpaul if (m0 == NULL) { 185967092Swpaul WI_UNLOCK(sc); 186046492Swpaul return; 186167092Swpaul } 186246492Swpaul 186346492Swpaul bzero((char *)&tx_frame, sizeof(tx_frame)); 186446492Swpaul id = sc->wi_tx_data_id; 186546492Swpaul eh = mtod(m0, struct ether_header *); 186646492Swpaul 186746492Swpaul /* 186847401Swpaul * Use RFC1042 encoding for IP and ARP datagrams, 186946492Swpaul * 802.3 for anything else. 187046492Swpaul */ 187175275Salfred if (ntohs(eh->ether_type) > ETHER_MAX_LEN) { 187246492Swpaul bcopy((char *)&eh->ether_dhost, 187346492Swpaul (char *)&tx_frame.wi_addr1, ETHER_ADDR_LEN); 187446492Swpaul bcopy((char *)&eh->ether_shost, 187546492Swpaul (char *)&tx_frame.wi_addr2, ETHER_ADDR_LEN); 187646492Swpaul bcopy((char *)&eh->ether_dhost, 187746492Swpaul (char *)&tx_frame.wi_dst_addr, ETHER_ADDR_LEN); 187846492Swpaul bcopy((char *)&eh->ether_shost, 187946492Swpaul (char *)&tx_frame.wi_src_addr, ETHER_ADDR_LEN); 188046492Swpaul 188146492Swpaul tx_frame.wi_dat_len = m0->m_pkthdr.len - WI_SNAPHDR_LEN; 188246492Swpaul tx_frame.wi_frame_ctl = WI_FTYPE_DATA; 188346492Swpaul tx_frame.wi_dat[0] = htons(WI_SNAP_WORD0); 188446492Swpaul tx_frame.wi_dat[1] = htons(WI_SNAP_WORD1); 188546492Swpaul tx_frame.wi_len = htons(m0->m_pkthdr.len - WI_SNAPHDR_LEN); 188646492Swpaul tx_frame.wi_type = eh->ether_type; 188746492Swpaul 188846492Swpaul m_copydata(m0, sizeof(struct ether_header), 188946492Swpaul m0->m_pkthdr.len - sizeof(struct ether_header), 189046492Swpaul (caddr_t)&sc->wi_txbuf); 189146492Swpaul 189246492Swpaul wi_write_data(sc, id, 0, (caddr_t)&tx_frame, 189346492Swpaul sizeof(struct wi_frame)); 189446492Swpaul wi_write_data(sc, id, WI_802_11_OFFSET, (caddr_t)&sc->wi_txbuf, 189546492Swpaul (m0->m_pkthdr.len - sizeof(struct ether_header)) + 2); 189646492Swpaul } else { 189746492Swpaul tx_frame.wi_dat_len = m0->m_pkthdr.len; 189846492Swpaul 189955831Swpaul eh->ether_type = htons(m0->m_pkthdr.len - WI_SNAPHDR_LEN); 190046492Swpaul m_copydata(m0, 0, m0->m_pkthdr.len, (caddr_t)&sc->wi_txbuf); 190146492Swpaul 190246492Swpaul wi_write_data(sc, id, 0, (caddr_t)&tx_frame, 190346492Swpaul sizeof(struct wi_frame)); 190446492Swpaul wi_write_data(sc, id, WI_802_3_OFFSET, (caddr_t)&sc->wi_txbuf, 190546492Swpaul m0->m_pkthdr.len + 2); 190646492Swpaul } 190746492Swpaul 190846492Swpaul /* 190946492Swpaul * If there's a BPF listner, bounce a copy of 191093359Simp * this frame to him. Also, don't send this to the bpf sniffer 191193359Simp * if we're in procframe or monitor sniffing mode. 191246492Swpaul */ 191393359Simp if (!(sc->wi_procframe || sc->wi_debug.wi_monitor) && ifp->if_bpf) 191446492Swpaul bpf_mtap(ifp, m0); 191546492Swpaul 191646492Swpaul m_freem(m0); 191746492Swpaul 191892457Simp if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0)) 191953702Swpaul device_printf(sc->dev, "xmit failed\n"); 192046492Swpaul 192146492Swpaul ifp->if_flags |= IFF_OACTIVE; 192246492Swpaul 192346492Swpaul /* 192446492Swpaul * Set a timeout in case the chip goes out to lunch. 192546492Swpaul */ 192646492Swpaul ifp->if_timer = 5; 192746492Swpaul 192867092Swpaul WI_UNLOCK(sc); 192946492Swpaul return; 193046492Swpaul} 193146492Swpaul 193288546Salfredstatic int 193388546Salfredwi_mgmt_xmit(sc, data, len) 193446492Swpaul struct wi_softc *sc; 193546492Swpaul caddr_t data; 193646492Swpaul int len; 193746492Swpaul{ 193846492Swpaul struct wi_frame tx_frame; 193946492Swpaul int id; 194046492Swpaul struct wi_80211_hdr *hdr; 194146492Swpaul caddr_t dptr; 194246492Swpaul 194346492Swpaul if (sc->wi_gone) 194446492Swpaul return(ENODEV); 194546492Swpaul 194646492Swpaul hdr = (struct wi_80211_hdr *)data; 194746492Swpaul dptr = data + sizeof(struct wi_80211_hdr); 194846492Swpaul 194946492Swpaul bzero((char *)&tx_frame, sizeof(tx_frame)); 195046492Swpaul id = sc->wi_tx_mgmt_id; 195146492Swpaul 195246492Swpaul bcopy((char *)hdr, (char *)&tx_frame.wi_frame_ctl, 195346492Swpaul sizeof(struct wi_80211_hdr)); 195446492Swpaul 195546492Swpaul tx_frame.wi_dat_len = len - WI_SNAPHDR_LEN; 195646492Swpaul tx_frame.wi_len = htons(len - WI_SNAPHDR_LEN); 195746492Swpaul 195846492Swpaul wi_write_data(sc, id, 0, (caddr_t)&tx_frame, sizeof(struct wi_frame)); 195946492Swpaul wi_write_data(sc, id, WI_802_11_OFFSET_RAW, dptr, 196046492Swpaul (len - sizeof(struct wi_80211_hdr)) + 2); 196146492Swpaul 196292457Simp if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0)) { 196353702Swpaul device_printf(sc->dev, "xmit failed\n"); 196446492Swpaul return(EIO); 196546492Swpaul } 196646492Swpaul 196746492Swpaul return(0); 196846492Swpaul} 196946492Swpaul 197088546Salfredstatic void 197188546Salfredwi_stop(sc) 197246492Swpaul struct wi_softc *sc; 197346492Swpaul{ 197446492Swpaul struct ifnet *ifp; 197546492Swpaul 197667092Swpaul WI_LOCK(sc); 197767092Swpaul 197867092Swpaul if (sc->wi_gone) { 197967092Swpaul WI_UNLOCK(sc); 198046492Swpaul return; 198167092Swpaul } 198246492Swpaul 198346492Swpaul ifp = &sc->arpcom.ac_if; 198446492Swpaul 198570173Sjhb /* 198670173Sjhb * If the card is gone and the memory port isn't mapped, we will 198770173Sjhb * (hopefully) get 0xffff back from the status read, which is not 198870173Sjhb * a valid status value. 198970173Sjhb */ 199070173Sjhb if (CSR_READ_2(sc, WI_STATUS) != 0xffff) { 199170173Sjhb CSR_WRITE_2(sc, WI_INT_EN, 0); 199292457Simp wi_cmd(sc, WI_CMD_DISABLE|sc->wi_portnum, 0, 0, 0); 199370173Sjhb } 199446492Swpaul 199546492Swpaul untimeout(wi_inquire, sc, sc->wi_stat_ch); 199646492Swpaul 199746492Swpaul ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); 199846492Swpaul 199967092Swpaul WI_UNLOCK(sc); 200046492Swpaul return; 200146492Swpaul} 200246492Swpaul 200388546Salfredstatic void 200488546Salfredwi_watchdog(ifp) 200546492Swpaul struct ifnet *ifp; 200646492Swpaul{ 200746492Swpaul struct wi_softc *sc; 200846492Swpaul 200946492Swpaul sc = ifp->if_softc; 201046492Swpaul 201175199Salfred device_printf(sc->dev, "watchdog timeout\n"); 201246492Swpaul 201346492Swpaul wi_init(sc); 201446492Swpaul 201546492Swpaul ifp->if_oerrors++; 201646492Swpaul 201746492Swpaul return; 201846492Swpaul} 201946492Swpaul 202093611Simpint 202190580Sbrookswi_alloc(dev, rid) 202253702Swpaul device_t dev; 202390580Sbrooks int rid; 202446492Swpaul{ 202553702Swpaul struct wi_softc *sc = device_get_softc(dev); 202653702Swpaul 202790580Sbrooks if (sc->wi_bus_type != WI_BUS_PCI_NATIVE) { 202890580Sbrooks sc->iobase_rid = rid; 202990580Sbrooks sc->iobase = bus_alloc_resource(dev, SYS_RES_IOPORT, 203090580Sbrooks &sc->iobase_rid, 0, ~0, (1 << 6), 203190580Sbrooks rman_make_alignment_flags(1 << 6) | RF_ACTIVE); 203290580Sbrooks if (!sc->iobase) { 203390580Sbrooks device_printf(dev, "No I/O space?!\n"); 203490580Sbrooks return (ENXIO); 203590580Sbrooks } 203690580Sbrooks 203790580Sbrooks sc->wi_io_addr = rman_get_start(sc->iobase); 203890580Sbrooks sc->wi_btag = rman_get_bustag(sc->iobase); 203990580Sbrooks sc->wi_bhandle = rman_get_bushandle(sc->iobase); 204090580Sbrooks } else { 204190580Sbrooks sc->mem_rid = rid; 204290580Sbrooks sc->mem = bus_alloc_resource(dev, SYS_RES_MEMORY, 204390580Sbrooks &sc->mem_rid, 0, ~0, 1, RF_ACTIVE); 204490580Sbrooks 204590580Sbrooks if (!sc->mem) { 204690580Sbrooks device_printf(dev, "No Mem space on prism2.5?\n"); 204790580Sbrooks return (ENXIO); 204890580Sbrooks } 204990580Sbrooks 205090580Sbrooks sc->wi_btag = rman_get_bustag(sc->mem); 205190580Sbrooks sc->wi_bhandle = rman_get_bushandle(sc->mem); 205253702Swpaul } 205353702Swpaul 205490580Sbrooks 205574906Salfred sc->irq_rid = 0; 205674906Salfred sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_rid, 205790580Sbrooks 0, ~0, 1, RF_ACTIVE | 205890580Sbrooks ((sc->wi_bus_type == WI_BUS_PCCARD) ? 0 : RF_SHAREABLE)); 205990580Sbrooks 206053702Swpaul if (!sc->irq) { 206175219Salfred wi_free(dev); 206253702Swpaul device_printf(dev, "No irq?!\n"); 206353702Swpaul return (ENXIO); 206453702Swpaul } 206553702Swpaul 206653702Swpaul sc->dev = dev; 206753702Swpaul sc->wi_unit = device_get_unit(dev); 206853702Swpaul 206953702Swpaul return (0); 207053702Swpaul} 207153702Swpaul 207293611Simpvoid 207388546Salfredwi_free(dev) 207453702Swpaul device_t dev; 207553702Swpaul{ 207653702Swpaul struct wi_softc *sc = device_get_softc(dev); 207753702Swpaul 207875219Salfred if (sc->iobase != NULL) { 207975219Salfred bus_release_resource(dev, SYS_RES_IOPORT, sc->iobase_rid, sc->iobase); 208075219Salfred sc->iobase = NULL; 208175219Salfred } 208275219Salfred if (sc->irq != NULL) { 208375219Salfred bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq); 208475219Salfred sc->irq = NULL; 208575219Salfred } 208675219Salfred if (sc->mem != NULL) { 208774906Salfred bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem); 208875219Salfred sc->mem = NULL; 208975219Salfred } 209053702Swpaul 209153702Swpaul return; 209253702Swpaul} 209353702Swpaul 209493611Simpvoid 209588546Salfredwi_shutdown(dev) 209653702Swpaul device_t dev; 209753702Swpaul{ 209846492Swpaul struct wi_softc *sc; 209946492Swpaul 210053702Swpaul sc = device_get_softc(dev); 210146492Swpaul wi_stop(sc); 210246492Swpaul 210346492Swpaul return; 210446492Swpaul} 210553702Swpaul 210653702Swpaul#ifdef WICACHE 210753702Swpaul/* wavelan signal strength cache code. 210853702Swpaul * store signal/noise/quality on per MAC src basis in 210953702Swpaul * a small fixed cache. The cache wraps if > MAX slots 211053702Swpaul * used. The cache may be zeroed out to start over. 211153702Swpaul * Two simple filters exist to reduce computation: 211253702Swpaul * 1. ip only (literally 0x800) which may be used 211353702Swpaul * to ignore some packets. It defaults to ip only. 211453702Swpaul * it could be used to focus on broadcast, non-IP 802.11 beacons. 211553702Swpaul * 2. multicast/broadcast only. This may be used to 211653702Swpaul * ignore unicast packets and only cache signal strength 211753702Swpaul * for multicast/broadcast packets (beacons); e.g., Mobile-IP 211853702Swpaul * beacons and not unicast traffic. 211953702Swpaul * 212053702Swpaul * The cache stores (MAC src(index), IP src (major clue), signal, 212153702Swpaul * quality, noise) 212253702Swpaul * 212353702Swpaul * No apologies for storing IP src here. It's easy and saves much 212453702Swpaul * trouble elsewhere. The cache is assumed to be INET dependent, 212553702Swpaul * although it need not be. 212653702Swpaul */ 212753702Swpaul 212853702Swpaul#ifdef documentation 212953702Swpaul 213053702Swpaulint wi_sigitems; /* number of cached entries */ 213153702Swpaulstruct wi_sigcache wi_sigcache[MAXWICACHE]; /* array of cache entries */ 213253702Swpaulint wi_nextitem; /* index/# of entries */ 213353702Swpaul 213453702Swpaul 213553702Swpaul#endif 213653702Swpaul 213753702Swpaul/* control variables for cache filtering. Basic idea is 213853702Swpaul * to reduce cost (e.g., to only Mobile-IP agent beacons 213953702Swpaul * which are broadcast or multicast). Still you might 214053702Swpaul * want to measure signal strength with unicast ping packets 214153702Swpaul * on a pt. to pt. ant. setup. 214253702Swpaul */ 214353702Swpaul/* set true if you want to limit cache items to broadcast/mcast 214453702Swpaul * only packets (not unicast). Useful for mobile-ip beacons which 214553702Swpaul * are broadcast/multicast at network layer. Default is all packets 214653702Swpaul * so ping/unicast will work say with pt. to pt. antennae setup. 214753702Swpaul */ 214853702Swpaulstatic int wi_cache_mcastonly = 0; 214953702SwpaulSYSCTL_INT(_machdep, OID_AUTO, wi_cache_mcastonly, CTLFLAG_RW, 215053702Swpaul &wi_cache_mcastonly, 0, ""); 215153702Swpaul 215253702Swpaul/* set true if you want to limit cache items to IP packets only 215353702Swpaul*/ 215453702Swpaulstatic int wi_cache_iponly = 1; 215553702SwpaulSYSCTL_INT(_machdep, OID_AUTO, wi_cache_iponly, CTLFLAG_RW, 215653702Swpaul &wi_cache_iponly, 0, ""); 215753702Swpaul 215853702Swpaul/* 215953702Swpaul * Original comments: 216053702Swpaul * ----------------- 216153702Swpaul * wi_cache_store, per rx packet store signal 216253702Swpaul * strength in MAC (src) indexed cache. 216353702Swpaul * 216453702Swpaul * follows linux driver in how signal strength is computed. 216553702Swpaul * In ad hoc mode, we use the rx_quality field. 216653702Swpaul * signal and noise are trimmed to fit in the range from 47..138. 216753702Swpaul * rx_quality field MSB is signal strength. 216853702Swpaul * rx_quality field LSB is noise. 216953702Swpaul * "quality" is (signal - noise) as is log value. 217053702Swpaul * note: quality CAN be negative. 217153702Swpaul * 217253702Swpaul * In BSS mode, we use the RID for communication quality. 217353702Swpaul * TBD: BSS mode is currently untested. 217453702Swpaul * 217553702Swpaul * Bill's comments: 217653702Swpaul * --------------- 217753702Swpaul * Actually, we use the rx_quality field all the time for both "ad-hoc" 217853702Swpaul * and BSS modes. Why? Because reading an RID is really, really expensive: 217953702Swpaul * there's a bunch of PIO operations that have to be done to read a record 218053702Swpaul * from the NIC, and reading the comms quality RID each time a packet is 218153702Swpaul * received can really hurt performance. We don't have to do this anyway: 218253702Swpaul * the comms quality field only reflects the values in the rx_quality field 218353702Swpaul * anyway. The comms quality RID is only meaningful in infrastructure mode, 218453702Swpaul * but the values it contains are updated based on the rx_quality from 218553702Swpaul * frames received from the access point. 218653702Swpaul * 218753702Swpaul * Also, according to Lucent, the signal strength and noise level values 218853702Swpaul * can be converted to dBms by subtracting 149, so I've modified the code 218953702Swpaul * to do that instead of the scaling it did originally. 219053702Swpaul */ 219188546Salfredstatic void 219288546Salfredwi_cache_store(struct wi_softc *sc, struct ether_header *eh, 219353702Swpaul struct mbuf *m, unsigned short rx_quality) 219453702Swpaul{ 219553702Swpaul struct ip *ip = 0; 219653702Swpaul int i; 219753702Swpaul static int cache_slot = 0; /* use this cache entry */ 219853702Swpaul static int wrapindex = 0; /* next "free" cache entry */ 219953702Swpaul int sig, noise; 220053702Swpaul int sawip=0; 220153702Swpaul 220253702Swpaul /* filters: 220353702Swpaul * 1. ip only 220453702Swpaul * 2. configurable filter to throw out unicast packets, 220553702Swpaul * keep multicast only. 220653702Swpaul */ 220753702Swpaul 220875276Salfred if ((ntohs(eh->ether_type) == ETHERTYPE_IP)) { 220953702Swpaul sawip = 1; 221053702Swpaul } 221153702Swpaul 221253702Swpaul /* filter for ip packets only 221353702Swpaul */ 221453702Swpaul if (wi_cache_iponly && !sawip) { 221553702Swpaul return; 221653702Swpaul } 221753702Swpaul 221853702Swpaul /* filter for broadcast/multicast only 221953702Swpaul */ 222053702Swpaul if (wi_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) { 222153702Swpaul return; 222253702Swpaul } 222353702Swpaul 222453702Swpaul#ifdef SIGDEBUG 222553702Swpaul printf("wi%d: q value %x (MSB=0x%x, LSB=0x%x) \n", sc->wi_unit, 222653702Swpaul rx_quality & 0xffff, rx_quality >> 8, rx_quality & 0xff); 222753702Swpaul#endif 222853702Swpaul 222953702Swpaul /* find the ip header. we want to store the ip_src 223053702Swpaul * address. 223153702Swpaul */ 223253702Swpaul if (sawip) { 223353702Swpaul ip = mtod(m, struct ip *); 223453702Swpaul } 223553702Swpaul 223653702Swpaul /* do a linear search for a matching MAC address 223753702Swpaul * in the cache table 223853702Swpaul * . MAC address is 6 bytes, 223953702Swpaul * . var w_nextitem holds total number of entries already cached 224053702Swpaul */ 224153702Swpaul for(i = 0; i < sc->wi_nextitem; i++) { 224253702Swpaul if (! bcmp(eh->ether_shost , sc->wi_sigcache[i].macsrc, 6 )) { 224353702Swpaul /* Match!, 224453702Swpaul * so we already have this entry, 224553702Swpaul * update the data 224653702Swpaul */ 224753702Swpaul break; 224853702Swpaul } 224953702Swpaul } 225053702Swpaul 225153702Swpaul /* did we find a matching mac address? 225253702Swpaul * if yes, then overwrite a previously existing cache entry 225353702Swpaul */ 225453702Swpaul if (i < sc->wi_nextitem ) { 225553702Swpaul cache_slot = i; 225653702Swpaul } 225753702Swpaul /* else, have a new address entry,so 225853702Swpaul * add this new entry, 225953702Swpaul * if table full, then we need to replace LRU entry 226053702Swpaul */ 226153702Swpaul else { 226253702Swpaul 226353702Swpaul /* check for space in cache table 226453702Swpaul * note: wi_nextitem also holds number of entries 226553702Swpaul * added in the cache table 226653702Swpaul */ 226753702Swpaul if ( sc->wi_nextitem < MAXWICACHE ) { 226853702Swpaul cache_slot = sc->wi_nextitem; 226953702Swpaul sc->wi_nextitem++; 227053702Swpaul sc->wi_sigitems = sc->wi_nextitem; 227153702Swpaul } 227253702Swpaul /* no space found, so simply wrap with wrap index 227353702Swpaul * and "zap" the next entry 227453702Swpaul */ 227553702Swpaul else { 227653702Swpaul if (wrapindex == MAXWICACHE) { 227753702Swpaul wrapindex = 0; 227853702Swpaul } 227953702Swpaul cache_slot = wrapindex++; 228053702Swpaul } 228153702Swpaul } 228253702Swpaul 228353702Swpaul /* invariant: cache_slot now points at some slot 228453702Swpaul * in cache. 228553702Swpaul */ 228653702Swpaul if (cache_slot < 0 || cache_slot >= MAXWICACHE) { 228753702Swpaul log(LOG_ERR, "wi_cache_store, bad index: %d of " 228853702Swpaul "[0..%d], gross cache error\n", 228953702Swpaul cache_slot, MAXWICACHE); 229053702Swpaul return; 229153702Swpaul } 229253702Swpaul 229353702Swpaul /* store items in cache 229453702Swpaul * .ip source address 229553702Swpaul * .mac src 229653702Swpaul * .signal, etc. 229753702Swpaul */ 229853702Swpaul if (sawip) { 229953702Swpaul sc->wi_sigcache[cache_slot].ipsrc = ip->ip_src.s_addr; 230053702Swpaul } 230153702Swpaul bcopy( eh->ether_shost, sc->wi_sigcache[cache_slot].macsrc, 6); 230253702Swpaul 230353702Swpaul sig = (rx_quality >> 8) & 0xFF; 230453702Swpaul noise = rx_quality & 0xFF; 230553702Swpaul sc->wi_sigcache[cache_slot].signal = sig - 149; 230653702Swpaul sc->wi_sigcache[cache_slot].noise = noise - 149; 230753702Swpaul sc->wi_sigcache[cache_slot].quality = sig - noise; 230853702Swpaul 230953702Swpaul return; 231053702Swpaul} 231153702Swpaul#endif 231277217Sphk 231388546Salfredstatic int 231488546Salfredwi_get_cur_ssid(sc, ssid, len) 231577217Sphk struct wi_softc *sc; 231677217Sphk char *ssid; 231777217Sphk int *len; 231877217Sphk{ 231977217Sphk int error = 0; 232077217Sphk struct wi_req wreq; 232177217Sphk 232277217Sphk wreq.wi_len = WI_MAX_DATALEN; 232377217Sphk switch (sc->wi_ptype) { 232477217Sphk case WI_PORTTYPE_ADHOC: 232577217Sphk wreq.wi_type = WI_RID_CURRENT_SSID; 232677217Sphk error = wi_read_record(sc, (struct wi_ltv_gen *)&wreq); 232777217Sphk if (error != 0) 232877217Sphk break; 232977217Sphk if (wreq.wi_val[0] > IEEE80211_NWID_LEN) { 233077217Sphk error = EINVAL; 233177217Sphk break; 233277217Sphk } 233377217Sphk *len = wreq.wi_val[0]; 233477217Sphk bcopy(&wreq.wi_val[1], ssid, IEEE80211_NWID_LEN); 233577217Sphk break; 233677217Sphk case WI_PORTTYPE_BSS: 233777217Sphk wreq.wi_type = WI_RID_COMMQUAL; 233877217Sphk error = wi_read_record(sc, (struct wi_ltv_gen *)&wreq); 233977217Sphk if (error != 0) 234077217Sphk break; 234177217Sphk if (wreq.wi_val[0] != 0) /* associated */ { 234277217Sphk wreq.wi_type = WI_RID_CURRENT_SSID; 234377217Sphk wreq.wi_len = WI_MAX_DATALEN; 234477217Sphk error = wi_read_record(sc, (struct wi_ltv_gen *)&wreq); 234577217Sphk if (error != 0) 234677217Sphk break; 234777217Sphk if (wreq.wi_val[0] > IEEE80211_NWID_LEN) { 234877217Sphk error = EINVAL; 234977217Sphk break; 235077217Sphk } 235177217Sphk *len = wreq.wi_val[0]; 235277217Sphk bcopy(&wreq.wi_val[1], ssid, IEEE80211_NWID_LEN); 235377217Sphk } else { 235477217Sphk *len = IEEE80211_NWID_LEN; 235577217Sphk bcopy(sc->wi_net_name, ssid, IEEE80211_NWID_LEN); 235677217Sphk } 235777217Sphk break; 235877217Sphk default: 235977217Sphk error = EINVAL; 236077217Sphk break; 236177217Sphk } 236277217Sphk 236377217Sphk return error; 236477217Sphk} 236577217Sphk 236688546Salfredstatic int 236788546Salfredwi_media_change(ifp) 236877217Sphk struct ifnet *ifp; 236977217Sphk{ 237077217Sphk struct wi_softc *sc = ifp->if_softc; 237177217Sphk int otype = sc->wi_ptype; 237277217Sphk int orate = sc->wi_tx_rate; 237377217Sphk 237477217Sphk if ((sc->ifmedia.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC) != 0) 237577217Sphk sc->wi_ptype = WI_PORTTYPE_ADHOC; 237677217Sphk else 237777217Sphk sc->wi_ptype = WI_PORTTYPE_BSS; 237877217Sphk 237977217Sphk switch (IFM_SUBTYPE(sc->ifmedia.ifm_cur->ifm_media)) { 238077217Sphk case IFM_IEEE80211_DS1: 238177217Sphk sc->wi_tx_rate = 1; 238277217Sphk break; 238377217Sphk case IFM_IEEE80211_DS2: 238477217Sphk sc->wi_tx_rate = 2; 238577217Sphk break; 238677217Sphk case IFM_IEEE80211_DS5: 238777217Sphk sc->wi_tx_rate = 5; 238877217Sphk break; 238977217Sphk case IFM_IEEE80211_DS11: 239077217Sphk sc->wi_tx_rate = 11; 239177217Sphk break; 239277217Sphk case IFM_AUTO: 239377217Sphk sc->wi_tx_rate = 3; 239477217Sphk break; 239577217Sphk } 239677217Sphk 239777217Sphk if (otype != sc->wi_ptype || 239877217Sphk orate != sc->wi_tx_rate) 239977217Sphk wi_init(sc); 240077217Sphk 240177217Sphk return(0); 240277217Sphk} 240377217Sphk 240488546Salfredstatic void 240588546Salfredwi_media_status(ifp, imr) 240677217Sphk struct ifnet *ifp; 240777217Sphk struct ifmediareq *imr; 240877217Sphk{ 240977217Sphk struct wi_req wreq; 241077217Sphk struct wi_softc *sc = ifp->if_softc; 241177217Sphk 241277217Sphk if (sc->wi_tx_rate == 3) { 241377217Sphk imr->ifm_active = IFM_IEEE80211|IFM_AUTO; 241477217Sphk if (sc->wi_ptype == WI_PORTTYPE_ADHOC) 241577217Sphk imr->ifm_active |= IFM_IEEE80211_ADHOC; 241677217Sphk wreq.wi_type = WI_RID_CUR_TX_RATE; 241777217Sphk wreq.wi_len = WI_MAX_DATALEN; 241877217Sphk if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0) { 241977217Sphk switch(wreq.wi_val[0]) { 242077217Sphk case 1: 242177217Sphk imr->ifm_active |= IFM_IEEE80211_DS1; 242277217Sphk break; 242377217Sphk case 2: 242477217Sphk imr->ifm_active |= IFM_IEEE80211_DS2; 242577217Sphk break; 242677217Sphk case 6: 242777217Sphk imr->ifm_active |= IFM_IEEE80211_DS5; 242877217Sphk break; 242977217Sphk case 11: 243077217Sphk imr->ifm_active |= IFM_IEEE80211_DS11; 243177217Sphk break; 243277217Sphk } 243377217Sphk } 243477217Sphk } else { 243577217Sphk imr->ifm_active = sc->ifmedia.ifm_cur->ifm_media; 243677217Sphk } 243777217Sphk 243877217Sphk imr->ifm_status = IFM_AVALID; 243977217Sphk if (sc->wi_ptype == WI_PORTTYPE_ADHOC) 244077217Sphk /* 244177217Sphk * XXX: It would be nice if we could give some actually 244277217Sphk * useful status like whether we joined another IBSS or 244377217Sphk * created one ourselves. 244477217Sphk */ 244577217Sphk imr->ifm_status |= IFM_ACTIVE; 244677217Sphk else { 244777217Sphk wreq.wi_type = WI_RID_COMMQUAL; 244877217Sphk wreq.wi_len = WI_MAX_DATALEN; 244977217Sphk if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0 && 245077217Sphk wreq.wi_val[0] != 0) 245177217Sphk imr->ifm_status |= IFM_ACTIVE; 245277217Sphk } 245377217Sphk} 245493359Simp 245593359Simpstatic int 245693359Simpwi_get_debug(sc, wreq) 245793359Simp struct wi_softc *sc; 245893359Simp struct wi_req *wreq; 245993359Simp{ 246093359Simp int error = 0; 246193359Simp 246293359Simp wreq->wi_len = 1; 246393359Simp 246493359Simp switch (wreq->wi_type) { 246593359Simp case WI_DEBUG_SLEEP: 246693359Simp wreq->wi_len++; 246793359Simp wreq->wi_val[0] = sc->wi_debug.wi_sleep; 246893359Simp break; 246993359Simp case WI_DEBUG_DELAYSUPP: 247093359Simp wreq->wi_len++; 247193359Simp wreq->wi_val[0] = sc->wi_debug.wi_delaysupp; 247293359Simp break; 247393359Simp case WI_DEBUG_TXSUPP: 247493359Simp wreq->wi_len++; 247593359Simp wreq->wi_val[0] = sc->wi_debug.wi_txsupp; 247693359Simp break; 247793359Simp case WI_DEBUG_MONITOR: 247893359Simp wreq->wi_len++; 247993359Simp wreq->wi_val[0] = sc->wi_debug.wi_monitor; 248093359Simp break; 248193359Simp case WI_DEBUG_LEDTEST: 248293359Simp wreq->wi_len += 3; 248393359Simp wreq->wi_val[0] = sc->wi_debug.wi_ledtest; 248493359Simp wreq->wi_val[1] = sc->wi_debug.wi_ledtest_param0; 248593359Simp wreq->wi_val[2] = sc->wi_debug.wi_ledtest_param1; 248693359Simp break; 248793359Simp case WI_DEBUG_CONTTX: 248893359Simp wreq->wi_len += 2; 248993359Simp wreq->wi_val[0] = sc->wi_debug.wi_conttx; 249093359Simp wreq->wi_val[1] = sc->wi_debug.wi_conttx_param0; 249193359Simp break; 249293359Simp case WI_DEBUG_CONTRX: 249393359Simp wreq->wi_len++; 249493359Simp wreq->wi_val[0] = sc->wi_debug.wi_contrx; 249593359Simp break; 249693359Simp case WI_DEBUG_SIGSTATE: 249793359Simp wreq->wi_len += 2; 249893359Simp wreq->wi_val[0] = sc->wi_debug.wi_sigstate; 249993359Simp wreq->wi_val[1] = sc->wi_debug.wi_sigstate_param0; 250093359Simp break; 250193359Simp case WI_DEBUG_CONFBITS: 250293359Simp wreq->wi_len += 2; 250393359Simp wreq->wi_val[0] = sc->wi_debug.wi_confbits; 250493359Simp wreq->wi_val[1] = sc->wi_debug.wi_confbits_param0; 250593359Simp break; 250693359Simp default: 250793359Simp error = EIO; 250893359Simp break; 250993359Simp } 251093359Simp 251193359Simp return (error); 251293359Simp} 251393359Simp 251493359Simpstatic int 251593359Simpwi_set_debug(sc, wreq) 251693359Simp struct wi_softc *sc; 251793359Simp struct wi_req *wreq; 251893359Simp{ 251993359Simp int error = 0; 252093359Simp u_int16_t cmd, param0 = 0, param1 = 0; 252193359Simp 252293359Simp switch (wreq->wi_type) { 252393359Simp case WI_DEBUG_RESET: 252493359Simp case WI_DEBUG_INIT: 252593359Simp case WI_DEBUG_CALENABLE: 252693359Simp break; 252793359Simp case WI_DEBUG_SLEEP: 252893359Simp sc->wi_debug.wi_sleep = 1; 252993359Simp break; 253093359Simp case WI_DEBUG_WAKE: 253193359Simp sc->wi_debug.wi_sleep = 0; 253293359Simp break; 253393359Simp case WI_DEBUG_CHAN: 253493359Simp param0 = wreq->wi_val[0]; 253593359Simp break; 253693359Simp case WI_DEBUG_DELAYSUPP: 253793359Simp sc->wi_debug.wi_delaysupp = 1; 253893359Simp break; 253993359Simp case WI_DEBUG_TXSUPP: 254093359Simp sc->wi_debug.wi_txsupp = 1; 254193359Simp break; 254293359Simp case WI_DEBUG_MONITOR: 254393359Simp sc->wi_debug.wi_monitor = 1; 254493359Simp break; 254593359Simp case WI_DEBUG_LEDTEST: 254693359Simp param0 = wreq->wi_val[0]; 254793359Simp param1 = wreq->wi_val[1]; 254893359Simp sc->wi_debug.wi_ledtest = 1; 254993359Simp sc->wi_debug.wi_ledtest_param0 = param0; 255093359Simp sc->wi_debug.wi_ledtest_param1 = param1; 255193359Simp break; 255293359Simp case WI_DEBUG_CONTTX: 255393359Simp param0 = wreq->wi_val[0]; 255493359Simp sc->wi_debug.wi_conttx = 1; 255593359Simp sc->wi_debug.wi_conttx_param0 = param0; 255693359Simp break; 255793359Simp case WI_DEBUG_STOPTEST: 255893359Simp sc->wi_debug.wi_delaysupp = 0; 255993359Simp sc->wi_debug.wi_txsupp = 0; 256093359Simp sc->wi_debug.wi_monitor = 0; 256193359Simp sc->wi_debug.wi_ledtest = 0; 256293359Simp sc->wi_debug.wi_ledtest_param0 = 0; 256393359Simp sc->wi_debug.wi_ledtest_param1 = 0; 256493359Simp sc->wi_debug.wi_conttx = 0; 256593359Simp sc->wi_debug.wi_conttx_param0 = 0; 256693359Simp sc->wi_debug.wi_contrx = 0; 256793359Simp sc->wi_debug.wi_sigstate = 0; 256893359Simp sc->wi_debug.wi_sigstate_param0 = 0; 256993359Simp break; 257093359Simp case WI_DEBUG_CONTRX: 257193359Simp sc->wi_debug.wi_contrx = 1; 257293359Simp break; 257393359Simp case WI_DEBUG_SIGSTATE: 257493359Simp param0 = wreq->wi_val[0]; 257593359Simp sc->wi_debug.wi_sigstate = 1; 257693359Simp sc->wi_debug.wi_sigstate_param0 = param0; 257793359Simp break; 257893359Simp case WI_DEBUG_CONFBITS: 257993359Simp param0 = wreq->wi_val[0]; 258093359Simp param1 = wreq->wi_val[1]; 258193359Simp sc->wi_debug.wi_confbits = param0; 258293359Simp sc->wi_debug.wi_confbits_param0 = param1; 258393359Simp break; 258493359Simp default: 258593359Simp error = EIO; 258693359Simp break; 258793359Simp } 258893359Simp 258993359Simp if (error) 259093359Simp return (error); 259193359Simp 259293359Simp cmd = WI_CMD_DEBUG | (wreq->wi_type << 8); 259393359Simp error = wi_cmd(sc, cmd, param0, param1, 0); 259493359Simp 259593359Simp return (error); 259693359Simp} 2597