if_wi.c revision 100876
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 * 5795534Simp * This driver supports the ISA, PCMCIA and PCI versions of the Lucent 5895534Simp * WaveLan cards (based on the Hermes chipset), as well as the newer 5995534Simp * Prism 2 chipsets with firmware from Intersil and Symbol. 6046492Swpaul */ 6146492Swpaul 6246492Swpaul#include <sys/param.h> 6346492Swpaul#include <sys/systm.h> 6495706Simp#if __FreeBSD_version >= 500033 6595533Smike#include <sys/endian.h> 6695706Simp#endif 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> 7494486Simp#include <sys/random.h> 7553702Swpaul#include <sys/syslog.h> 7653702Swpaul#include <sys/sysctl.h> 7746492Swpaul 7853702Swpaul#include <machine/bus.h> 7953702Swpaul#include <machine/resource.h> 8095534Simp#include <machine/clock.h> 8153702Swpaul#include <sys/rman.h> 8253702Swpaul 8346492Swpaul#include <net/if.h> 8446492Swpaul#include <net/if_arp.h> 8546492Swpaul#include <net/ethernet.h> 8646492Swpaul#include <net/if_dl.h> 8746492Swpaul#include <net/if_media.h> 8846492Swpaul#include <net/if_types.h> 8977217Sphk#include <net/if_ieee80211.h> 9046492Swpaul 9146492Swpaul#include <netinet/in.h> 9246492Swpaul#include <netinet/in_systm.h> 9346492Swpaul#include <netinet/in_var.h> 9446492Swpaul#include <netinet/ip.h> 9546492Swpaul#include <netinet/if_ether.h> 9646492Swpaul 9746492Swpaul#include <net/bpf.h> 9846492Swpaul 9970808Speter#include <dev/wi/if_wavelan_ieee.h> 10094405Simp#include <dev/wi/wi_hostap.h> 10193611Simp#include <dev/wi/if_wivar.h> 10270808Speter#include <dev/wi/if_wireg.h> 10346492Swpaul 10446492Swpaul#if !defined(lint) 10546492Swpaulstatic const char rcsid[] = 10650477Speter "$FreeBSD: head/sys/dev/wi/if_wi.c 100876 2002-07-29 15:36:22Z imp $"; 10746492Swpaul#endif 10846492Swpaul 10991693Simpstatic void wi_intr(void *); 11091693Simpstatic void wi_reset(struct wi_softc *); 11191693Simpstatic int wi_ioctl(struct ifnet *, u_long, caddr_t); 11291693Simpstatic void wi_init(void *); 11391693Simpstatic void wi_start(struct ifnet *); 11491693Simpstatic void wi_stop(struct wi_softc *); 11591693Simpstatic void wi_watchdog(struct ifnet *); 11691693Simpstatic void wi_rxeof(struct wi_softc *); 11791693Simpstatic void wi_txeof(struct wi_softc *, int); 11891693Simpstatic void wi_update_stats(struct wi_softc *); 11991693Simpstatic void wi_setmulti(struct wi_softc *); 12046492Swpaul 12192457Simpstatic int wi_cmd(struct wi_softc *, int, int, int, int); 12291693Simpstatic int wi_read_record(struct wi_softc *, struct wi_ltv_gen *); 12391693Simpstatic int wi_write_record(struct wi_softc *, struct wi_ltv_gen *); 12491693Simpstatic int wi_read_data(struct wi_softc *, int, int, caddr_t, int); 12591693Simpstatic int wi_write_data(struct wi_softc *, int, int, caddr_t, int); 12691693Simpstatic int wi_seek(struct wi_softc *, int, int, int); 12791693Simpstatic int wi_alloc_nicmem(struct wi_softc *, int, int *); 12891693Simpstatic void wi_inquire(void *); 12991693Simpstatic void wi_setdef(struct wi_softc *, struct wi_req *); 13046492Swpaul 13153702Swpaul#ifdef WICACHE 13253702Swpaulstatic 13391693Simpvoid wi_cache_store(struct wi_softc *, struct ether_header *, 13491693Simp struct mbuf *, unsigned short); 13553702Swpaul#endif 13653702Swpaul 13791693Simpstatic int wi_get_cur_ssid(struct wi_softc *, char *, int *); 13893825Simpstatic void wi_get_id(struct wi_softc *); 13991693Simpstatic int wi_media_change(struct ifnet *); 14091693Simpstatic void wi_media_status(struct ifnet *, struct ifmediareq *); 14177217Sphk 14293359Simpstatic int wi_get_debug(struct wi_softc *, struct wi_req *); 14393359Simpstatic int wi_set_debug(struct wi_softc *, struct wi_req *); 14493359Simp 14593611Simpdevclass_t wi_devclass; 14653702Swpaul 14793825Simpstruct wi_card_ident wi_card_ident[] = { 14893825Simp /* CARD_ID CARD_NAME FIRM_TYPE */ 14993825Simp { WI_NIC_LUCENT_ID, WI_NIC_LUCENT_STR, WI_LUCENT }, 15093825Simp { WI_NIC_SONY_ID, WI_NIC_SONY_STR, WI_LUCENT }, 15193825Simp { WI_NIC_LUCENT_EMB_ID, WI_NIC_LUCENT_EMB_STR, WI_LUCENT }, 15293825Simp { WI_NIC_EVB2_ID, WI_NIC_EVB2_STR, WI_INTERSIL }, 15393825Simp { WI_NIC_HWB3763_ID, WI_NIC_HWB3763_STR, WI_INTERSIL }, 15493825Simp { WI_NIC_HWB3163_ID, WI_NIC_HWB3163_STR, WI_INTERSIL }, 15593825Simp { WI_NIC_HWB3163B_ID, WI_NIC_HWB3163B_STR, WI_INTERSIL }, 15693825Simp { WI_NIC_EVB3_ID, WI_NIC_EVB3_STR, WI_INTERSIL }, 15793825Simp { WI_NIC_HWB1153_ID, WI_NIC_HWB1153_STR, WI_INTERSIL }, 15893825Simp { WI_NIC_P2_SST_ID, WI_NIC_P2_SST_STR, WI_INTERSIL }, 15993825Simp { WI_NIC_EVB2_SST_ID, WI_NIC_EVB2_SST_STR, WI_INTERSIL }, 16093825Simp { WI_NIC_3842_EVA_ID, WI_NIC_3842_EVA_STR, WI_INTERSIL }, 16193825Simp { WI_NIC_3842_PCMCIA_AMD_ID, WI_NIC_3842_PCMCIA_STR, WI_INTERSIL }, 16293825Simp { WI_NIC_3842_PCMCIA_SST_ID, WI_NIC_3842_PCMCIA_STR, WI_INTERSIL }, 16393825Simp { WI_NIC_3842_PCMCIA_ATM_ID, WI_NIC_3842_PCMCIA_STR, WI_INTERSIL }, 16493825Simp { WI_NIC_3842_MINI_AMD_ID, WI_NIC_3842_MINI_STR, WI_INTERSIL }, 16593825Simp { WI_NIC_3842_MINI_SST_ID, WI_NIC_3842_MINI_STR, WI_INTERSIL }, 16693825Simp { WI_NIC_3842_MINI_ATM_ID, WI_NIC_3842_MINI_STR, WI_INTERSIL }, 16793825Simp { WI_NIC_3842_PCI_AMD_ID, WI_NIC_3842_PCI_STR, WI_INTERSIL }, 16893825Simp { WI_NIC_3842_PCI_SST_ID, WI_NIC_3842_PCI_STR, WI_INTERSIL }, 16993825Simp { WI_NIC_3842_PCI_ATM_ID, WI_NIC_3842_PCI_STR, WI_INTERSIL }, 17093825Simp { WI_NIC_P3_PCMCIA_AMD_ID, WI_NIC_P3_PCMCIA_STR, WI_INTERSIL }, 17193825Simp { WI_NIC_P3_PCMCIA_SST_ID, WI_NIC_P3_PCMCIA_STR, WI_INTERSIL }, 17293825Simp { WI_NIC_P3_MINI_AMD_ID, WI_NIC_P3_MINI_STR, WI_INTERSIL }, 17393825Simp { WI_NIC_P3_MINI_SST_ID, WI_NIC_P3_MINI_STR, WI_INTERSIL }, 17493825Simp { 0, NULL, 0 }, 17593825Simp}; 17693825Simp 17793611Simpint 17893611Simpwi_generic_detach(dev) 17953702Swpaul device_t dev; 18046492Swpaul{ 18146492Swpaul struct wi_softc *sc; 18246492Swpaul struct ifnet *ifp; 18395534Simp int s; 18446492Swpaul 18553702Swpaul sc = device_get_softc(dev); 18695534Simp WI_LOCK(sc, s); 18746492Swpaul ifp = &sc->arpcom.ac_if; 18846492Swpaul 18946492Swpaul if (sc->wi_gone) { 19053702Swpaul device_printf(dev, "already unloaded\n"); 19195534Simp WI_UNLOCK(sc, s); 19253702Swpaul return(ENODEV); 19346492Swpaul } 19446492Swpaul 19553702Swpaul wi_stop(sc); 19658274Srwatson 19777217Sphk /* Delete all remaining media. */ 19877217Sphk ifmedia_removeall(&sc->ifmedia); 19977217Sphk 20063090Sarchie ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); 20154277Swpaul bus_teardown_intr(dev, sc->irq, sc->wi_intrhand); 20253702Swpaul wi_free(dev); 20346492Swpaul sc->wi_gone = 1; 20446492Swpaul 20595534Simp WI_UNLOCK(sc, s); 20695534Simp#if __FreeBSD_version >= 500000 20767092Swpaul mtx_destroy(&sc->wi_mtx); 20895534Simp#endif 20946492Swpaul 21046492Swpaul return(0); 21146492Swpaul} 21246492Swpaul 21393611Simpint 21474906Salfredwi_generic_attach(device_t dev) 21574906Salfred{ 21674906Salfred struct wi_softc *sc; 21774906Salfred struct wi_ltv_macaddr mac; 21874906Salfred struct wi_ltv_gen gen; 21974906Salfred struct ifnet *ifp; 22074906Salfred int error; 22195534Simp int s; 22274906Salfred 22394405Simp /* XXX maybe we need the splimp stuff here XXX */ 22474906Salfred sc = device_get_softc(dev); 22574906Salfred ifp = &sc->arpcom.ac_if; 22674906Salfred 22753702Swpaul error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET, 22874998Swpaul wi_intr, sc, &sc->wi_intrhand); 22953702Swpaul 23053702Swpaul if (error) { 23153702Swpaul device_printf(dev, "bus_setup_intr() failed! (%d)\n", error); 23253702Swpaul wi_free(dev); 23353702Swpaul return (error); 23453702Swpaul } 23553702Swpaul 23695534Simp#if __FreeBSD_version >= 500000 23793818Sjhb mtx_init(&sc->wi_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 23893818Sjhb MTX_DEF | MTX_RECURSE); 23995534Simp#endif 24095534Simp WI_LOCK(sc, s); 24167092Swpaul 24246492Swpaul /* Reset the NIC. */ 24346492Swpaul wi_reset(sc); 24446492Swpaul 24576438Swpaul /* 24676438Swpaul * Read the station address. 24776438Swpaul * And do it twice. I've seen PRISM-based cards that return 24876438Swpaul * an error when trying to read it the first time, which causes 24976438Swpaul * the probe to fail. 25076438Swpaul */ 25146492Swpaul mac.wi_type = WI_RID_MAC_NODE; 25246492Swpaul mac.wi_len = 4; 25376457Sgrog wi_read_record(sc, (struct wi_ltv_gen *)&mac); 25475150Simp if ((error = wi_read_record(sc, (struct wi_ltv_gen *)&mac)) != 0) { 25575149Simp device_printf(dev, "mac read failed %d\n", error); 25675149Simp wi_free(dev); 25775149Simp return (error); 25875149Simp } 25946492Swpaul bcopy((char *)&mac.wi_mac_addr, 26046492Swpaul (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 26146492Swpaul 26287383Simp device_printf(dev, "802.11 address: %6D\n", sc->arpcom.ac_enaddr, ":"); 26346492Swpaul 26493825Simp wi_get_id(sc); 26587383Simp 26646492Swpaul ifp->if_softc = sc; 26746492Swpaul ifp->if_unit = sc->wi_unit; 26846492Swpaul ifp->if_name = "wi"; 26946492Swpaul ifp->if_mtu = ETHERMTU; 27046492Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 27146492Swpaul ifp->if_ioctl = wi_ioctl; 27246492Swpaul ifp->if_output = ether_output; 27346492Swpaul ifp->if_start = wi_start; 27446492Swpaul ifp->if_watchdog = wi_watchdog; 27546492Swpaul ifp->if_init = wi_init; 27646492Swpaul ifp->if_baudrate = 10000000; 27746492Swpaul ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 27846492Swpaul 27946492Swpaul bzero(sc->wi_node_name, sizeof(sc->wi_node_name)); 28046492Swpaul bcopy(WI_DEFAULT_NODENAME, sc->wi_node_name, 28146492Swpaul sizeof(WI_DEFAULT_NODENAME) - 1); 28246492Swpaul 28346492Swpaul bzero(sc->wi_net_name, sizeof(sc->wi_net_name)); 28446492Swpaul bcopy(WI_DEFAULT_NETNAME, sc->wi_net_name, 28546492Swpaul sizeof(WI_DEFAULT_NETNAME) - 1); 28646492Swpaul 28746492Swpaul bzero(sc->wi_ibss_name, sizeof(sc->wi_ibss_name)); 28846492Swpaul bcopy(WI_DEFAULT_IBSS, sc->wi_ibss_name, 28946492Swpaul sizeof(WI_DEFAULT_IBSS) - 1); 29046492Swpaul 29146492Swpaul sc->wi_portnum = WI_DEFAULT_PORT; 29274139Sassar sc->wi_ptype = WI_PORTTYPE_BSS; 29346492Swpaul sc->wi_ap_density = WI_DEFAULT_AP_DENSITY; 29446492Swpaul sc->wi_rts_thresh = WI_DEFAULT_RTS_THRESH; 29546492Swpaul sc->wi_tx_rate = WI_DEFAULT_TX_RATE; 29646492Swpaul sc->wi_max_data_len = WI_DEFAULT_DATALEN; 29746492Swpaul sc->wi_create_ibss = WI_DEFAULT_CREATE_IBSS; 29846611Swpaul sc->wi_pm_enabled = WI_DEFAULT_PM_ENABLED; 29946611Swpaul sc->wi_max_sleep = WI_DEFAULT_MAX_SLEEP; 30091695Simp sc->wi_roaming = WI_DEFAULT_ROAMING; 30191695Simp sc->wi_authtype = WI_DEFAULT_AUTHTYPE; 30294405Simp sc->wi_authmode = IEEE80211_AUTH_OPEN; 30346492Swpaul 30446563Swpaul /* 30546563Swpaul * Read the default channel from the NIC. This may vary 30646563Swpaul * depending on the country where the NIC was purchased, so 30746563Swpaul * we can't hard-code a default and expect it to work for 30846563Swpaul * everyone. 30946563Swpaul */ 31046563Swpaul gen.wi_type = WI_RID_OWN_CHNL; 31146563Swpaul gen.wi_len = 2; 31246563Swpaul wi_read_record(sc, &gen); 31346563Swpaul sc->wi_channel = gen.wi_val; 31446563Swpaul 31556965Swpaul /* 31698440Simp * Set flags based on firmware version. 31798440Simp */ 31898440Simp switch (sc->sc_firmware_type) { 31998440Simp case WI_LUCENT: 32098440Simp sc->wi_flags |= WI_FLAGS_HAS_ROAMING; 32198440Simp if (sc->sc_sta_firmware_ver >= 60000) 32298440Simp sc->wi_flags |= WI_FLAGS_HAS_MOR; 32398440Simp if (sc->sc_sta_firmware_ver >= 60006) { 32498440Simp sc->wi_flags |= WI_FLAGS_HAS_IBSS; 32598440Simp sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS; 32698440Simp } 32798440Simp sc->wi_ibss_port = htole16(1); 32898440Simp break; 32998440Simp case WI_INTERSIL: 33098440Simp sc->wi_flags |= WI_FLAGS_HAS_ROAMING; 33198440Simp if (sc->sc_sta_firmware_ver >= 800) { 33298440Simp sc->wi_flags |= WI_FLAGS_HAS_IBSS; 33398440Simp sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS; 33498440Simp } 335100734Simp /* 336100734Simp * version 0.8.3 and newer are the only ones that are known 337100734Simp * to currently work. Earlier versions can be made to work, 338100734Simp * at least according to the Linux driver. 339100734Simp */ 340100734Simp if (sc->sc_sta_firmware_ver >= 803) 341100734Simp sc->wi_flags |= WI_FLAGS_HAS_HOSTAP; 34298440Simp sc->wi_ibss_port = htole16(0); 34398440Simp break; 34498440Simp case WI_SYMBOL: 34598440Simp sc->wi_flags |= WI_FLAGS_HAS_DIVERSITY; 34698440Simp if (sc->sc_sta_firmware_ver >= 20000) 34798440Simp sc->wi_flags |= WI_FLAGS_HAS_IBSS; 34898440Simp /* Older Symbol firmware does not support IBSS creation. */ 34998440Simp if (sc->sc_sta_firmware_ver >= 25000) 35098440Simp sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS; 35198440Simp sc->wi_ibss_port = htole16(4); 35298440Simp break; 35398440Simp } 35498440Simp 35598440Simp /* 35656965Swpaul * Find out if we support WEP on this card. 35756965Swpaul */ 35856965Swpaul gen.wi_type = WI_RID_WEP_AVAIL; 35956965Swpaul gen.wi_len = 2; 36056965Swpaul wi_read_record(sc, &gen); 36156965Swpaul sc->wi_has_wep = gen.wi_val; 36256965Swpaul 36394490Simp if (bootverbose) 36494490Simp device_printf(sc->dev, "wi_has_wep = %d\n", sc->wi_has_wep); 36570073Swpaul 36694405Simp /* 36794405Simp * Find supported rates. 36894405Simp */ 36998440Simp gen.wi_type = WI_RID_DATA_RATES; 37094405Simp gen.wi_len = 2; 37198440Simp if (wi_read_record(sc, &gen)) 37298440Simp sc->wi_supprates = WI_SUPPRATES_1M | WI_SUPPRATES_2M | 37398440Simp WI_SUPPRATES_5M | WI_SUPPRATES_11M; 37498440Simp else 37598440Simp sc->wi_supprates = gen.wi_val; 37694405Simp 37746492Swpaul bzero((char *)&sc->wi_stats, sizeof(sc->wi_stats)); 37846492Swpaul 37946492Swpaul wi_init(sc); 38046492Swpaul wi_stop(sc); 38146492Swpaul 38277217Sphk ifmedia_init(&sc->ifmedia, 0, wi_media_change, wi_media_status); 38377217Sphk#define ADD(m, c) ifmedia_add(&sc->ifmedia, (m), (c), NULL) 38498440Simp if (sc->wi_supprates & WI_SUPPRATES_1M) { 38598440Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 0, 0), 0); 38694405Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 38798440Simp IFM_IEEE80211_ADHOC, 0), 0); 38898440Simp if (sc->wi_flags & WI_FLAGS_HAS_IBSS) 38998440Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 39098440Simp IFM_IEEE80211_IBSS, 0), 0); 39198440Simp if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS) 39298440Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 39398440Simp IFM_IEEE80211_IBSSMASTER, 0), 0); 394100734Simp if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP) 39598440Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 39698440Simp IFM_IEEE80211_HOSTAP, 0), 0); 39798440Simp } 39898440Simp if (sc->wi_supprates & WI_SUPPRATES_2M) { 39998440Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 0, 0), 0); 40094405Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 40198440Simp IFM_IEEE80211_ADHOC, 0), 0); 40298440Simp if (sc->wi_flags & WI_FLAGS_HAS_IBSS) 40398440Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 40498440Simp IFM_IEEE80211_IBSS, 0), 0); 40598440Simp if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS) 40698440Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 40798440Simp IFM_IEEE80211_IBSSMASTER, 0), 0); 408100734Simp if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP) 40998440Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 41098440Simp IFM_IEEE80211_HOSTAP, 0), 0); 41198440Simp } 41298440Simp if (sc->wi_supprates & WI_SUPPRATES_5M) { 41398440Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 0, 0), 0); 41494405Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 41598440Simp IFM_IEEE80211_ADHOC, 0), 0); 41698440Simp if (sc->wi_flags & WI_FLAGS_HAS_IBSS) 41798440Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 41898440Simp IFM_IEEE80211_IBSS, 0), 0); 41998440Simp if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS) 42098440Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 42198440Simp IFM_IEEE80211_IBSSMASTER, 0), 0); 422100734Simp if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP) 42398440Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 42498440Simp IFM_IEEE80211_HOSTAP, 0), 0); 42598440Simp } 42698440Simp if (sc->wi_supprates & WI_SUPPRATES_11M) { 42798440Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 0, 0), 0); 42894405Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 42998440Simp IFM_IEEE80211_ADHOC, 0), 0); 43098440Simp if (sc->wi_flags & WI_FLAGS_HAS_IBSS) 43198440Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 43298440Simp IFM_IEEE80211_IBSS, 0), 0); 43398440Simp if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS) 43498440Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 43598440Simp IFM_IEEE80211_IBSSMASTER, 0), 0); 436100734Simp if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP) 43798440Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 43898440Simp IFM_IEEE80211_HOSTAP, 0), 0); 43998440Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_MANUAL, 0, 0), 0); 44098440Simp } 44198440Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, IFM_IEEE80211_ADHOC, 0), 0); 44298440Simp if (sc->wi_flags & WI_FLAGS_HAS_IBSS) 44398440Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, IFM_IEEE80211_IBSS, 44498440Simp 0), 0); 44598440Simp if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS) 44698440Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 44798440Simp IFM_IEEE80211_IBSSMASTER, 0), 0); 448100734Simp if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP) 44998440Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 45094405Simp IFM_IEEE80211_HOSTAP, 0), 0); 45198440Simp ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0), 0); 45298440Simp#undef ADD 453100734Simp ifmedia_set(&sc->ifmedia, IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0)); 45477217Sphk 45546492Swpaul /* 45663090Sarchie * Call MI attach routine. 45746492Swpaul */ 45863090Sarchie ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 45953702Swpaul callout_handle_init(&sc->wi_stat_ch); 46095534Simp WI_UNLOCK(sc, s); 46146492Swpaul 46246492Swpaul return(0); 46346492Swpaul} 46446492Swpaul 46587383Simpstatic void 46693825Simpwi_get_id(sc) 46787383Simp struct wi_softc *sc; 46887383Simp{ 46987383Simp struct wi_ltv_ver ver; 47093825Simp struct wi_card_ident *id; 47187383Simp 47287383Simp /* getting chip identity */ 47387383Simp memset(&ver, 0, sizeof(ver)); 47493567Simp ver.wi_type = WI_RID_CARD_ID; 47587383Simp ver.wi_len = 5; 47687383Simp wi_read_record(sc, (struct wi_ltv_gen *)&ver); 47793733Simp device_printf(sc->dev, "using "); 47893825Simp sc->sc_firmware_type = WI_NOTYPE; 47993825Simp for (id = wi_card_ident; id->card_name != NULL; id++) { 48093825Simp if (le16toh(ver.wi_ver[0]) == id->card_id) { 48193825Simp printf("%s", id->card_name); 48293825Simp sc->sc_firmware_type = id->firm_type; 48393825Simp break; 48493825Simp } 48593825Simp } 48693825Simp if (sc->sc_firmware_type == WI_NOTYPE) { 48793825Simp if (le16toh(ver.wi_ver[0]) & 0x8000) { 48893733Simp printf("Unknown PRISM2 chip"); 48993825Simp sc->sc_firmware_type = WI_INTERSIL; 49093825Simp } else { 49193733Simp printf("Unknown Lucent chip"); 49293825Simp sc->sc_firmware_type = WI_LUCENT; 49393825Simp } 49487383Simp } 49587383Simp 49693733Simp if (sc->sc_firmware_type != WI_LUCENT) { 49793733Simp /* get primary firmware version */ 49893733Simp memset(&ver, 0, sizeof(ver)); 49993733Simp ver.wi_type = WI_RID_PRI_IDENTITY; 50093733Simp ver.wi_len = 5; 50193733Simp wi_read_record(sc, (struct wi_ltv_gen *)&ver); 50293733Simp ver.wi_ver[1] = le16toh(ver.wi_ver[1]); 50393733Simp ver.wi_ver[2] = le16toh(ver.wi_ver[2]); 50493733Simp ver.wi_ver[3] = le16toh(ver.wi_ver[3]); 50593733Simp sc->sc_pri_firmware_ver = ver.wi_ver[2] * 10000 + 50693733Simp ver.wi_ver[3] * 100 + ver.wi_ver[1]; 50793733Simp } 50893733Simp 50993733Simp /* get station firmware version */ 51092457Simp memset(&ver, 0, sizeof(ver)); 51192457Simp ver.wi_type = WI_RID_STA_IDENTITY; 51292457Simp ver.wi_len = 5; 51392457Simp wi_read_record(sc, (struct wi_ltv_gen *)&ver); 51492457Simp ver.wi_ver[1] = le16toh(ver.wi_ver[1]); 51592457Simp ver.wi_ver[2] = le16toh(ver.wi_ver[2]); 51692457Simp ver.wi_ver[3] = le16toh(ver.wi_ver[3]); 51793733Simp sc->sc_sta_firmware_ver = ver.wi_ver[2] * 10000 + 51893733Simp ver.wi_ver[3] * 100 + ver.wi_ver[1]; 51993733Simp if (sc->sc_firmware_type == WI_INTERSIL && 52093733Simp (sc->sc_sta_firmware_ver == 10102 || 52193733Simp sc->sc_sta_firmware_ver == 20102)) { 52293733Simp struct wi_ltv_str sver; 52393733Simp char *p; 52487383Simp 52593733Simp memset(&sver, 0, sizeof(sver)); 52693733Simp sver.wi_type = WI_RID_SYMBOL_IDENTITY; 52793733Simp sver.wi_len = 7; 52895031Sonoe /* value should be the format like "V2.00-11" */ 52993733Simp if (wi_read_record(sc, (struct wi_ltv_gen *)&sver) == 0 && 53095031Sonoe *(p = (char *)sver.wi_str) >= 'A' && 53193733Simp p[2] == '.' && p[5] == '-' && p[8] == '\0') { 53293733Simp sc->sc_firmware_type = WI_SYMBOL; 53393733Simp sc->sc_sta_firmware_ver = (p[1] - '0') * 10000 + 53493733Simp (p[3] - '0') * 1000 + (p[4] - '0') * 100 + 53593733Simp (p[6] - '0') * 10 + (p[7] - '0'); 53693733Simp } 53793733Simp } 53893733Simp printf("\n"); 53993733Simp device_printf(sc->dev, "%s Firmware: ", 54093733Simp sc->sc_firmware_type == WI_LUCENT ? "Lucent" : 54193733Simp (sc->sc_firmware_type == WI_SYMBOL ? "Symbol" : "Intersil")); 54293733Simp 54393733Simp /* 54493733Simp * The primary firmware is only valid on Prism based chipsets 54593733Simp * (INTERSIL or SYMBOL). 54693733Simp */ 54793733Simp if (sc->sc_firmware_type != WI_LUCENT) 54893733Simp printf("Primary %u.%02u.%02u, ", sc->sc_pri_firmware_ver / 10000, 54993733Simp (sc->sc_pri_firmware_ver % 10000) / 100, 55093733Simp sc->sc_pri_firmware_ver % 100); 55193733Simp printf("Station %u.%02u.%02u\n", 55293733Simp sc->sc_sta_firmware_ver / 10000, (sc->sc_sta_firmware_ver % 10000) / 100, 55393733Simp sc->sc_sta_firmware_ver % 100); 55487383Simp return; 55587383Simp} 55687383Simp 55788546Salfredstatic void 55888546Salfredwi_rxeof(sc) 55946492Swpaul struct wi_softc *sc; 56046492Swpaul{ 56146492Swpaul struct ifnet *ifp; 56246492Swpaul struct ether_header *eh; 56346492Swpaul struct mbuf *m; 56446492Swpaul int id; 56546492Swpaul 56646492Swpaul ifp = &sc->arpcom.ac_if; 56746492Swpaul 56846492Swpaul id = CSR_READ_2(sc, WI_RX_FID); 56946492Swpaul 57093359Simp /* 57193359Simp * if we have the procframe flag set, disregard all this and just 57293359Simp * read the data from the device. 57393359Simp */ 57493359Simp if (sc->wi_procframe || sc->wi_debug.wi_monitor) { 57593359Simp struct wi_frame *rx_frame; 57693359Simp int datlen, hdrlen; 57746492Swpaul 57893359Simp /* first allocate mbuf for packet storage */ 57993359Simp MGETHDR(m, M_DONTWAIT, MT_DATA); 58093359Simp if (m == NULL) { 58193359Simp ifp->if_ierrors++; 58293359Simp return; 58393359Simp } 58493359Simp MCLGET(m, M_DONTWAIT); 58593359Simp if (!(m->m_flags & M_EXT)) { 58693359Simp m_freem(m); 58793359Simp ifp->if_ierrors++; 58893359Simp return; 58993359Simp } 59046492Swpaul 59193359Simp m->m_pkthdr.rcvif = ifp; 59246492Swpaul 59393359Simp /* now read wi_frame first so we know how much data to read */ 59493359Simp if (wi_read_data(sc, id, 0, mtod(m, caddr_t), 59593359Simp sizeof(struct wi_frame))) { 59693359Simp m_freem(m); 59793359Simp ifp->if_ierrors++; 59893359Simp return; 59993359Simp } 60046492Swpaul 60193359Simp rx_frame = mtod(m, struct wi_frame *); 60293359Simp 60393359Simp switch ((rx_frame->wi_status & WI_STAT_MAC_PORT) >> 8) { 60493359Simp case 7: 60593359Simp switch (rx_frame->wi_frame_ctl & WI_FCTL_FTYPE) { 60693359Simp case WI_FTYPE_DATA: 60793359Simp hdrlen = WI_DATA_HDRLEN; 60893359Simp datlen = rx_frame->wi_dat_len + WI_FCS_LEN; 60993359Simp break; 61093359Simp case WI_FTYPE_MGMT: 61193359Simp hdrlen = WI_MGMT_HDRLEN; 61293359Simp datlen = rx_frame->wi_dat_len + WI_FCS_LEN; 61393359Simp break; 61493359Simp case WI_FTYPE_CTL: 61593359Simp /* 61693359Simp * prism2 cards don't pass control packets 61793359Simp * down properly or consistently, so we'll only 61893359Simp * pass down the header. 61993359Simp */ 62093359Simp hdrlen = WI_CTL_HDRLEN; 62193359Simp datlen = 0; 62293359Simp break; 62393359Simp default: 62493359Simp device_printf(sc->dev, "received packet of " 62593359Simp "unknown type on port 7\n"); 62693359Simp m_freem(m); 62793359Simp ifp->if_ierrors++; 62893359Simp return; 62993359Simp } 63093359Simp break; 63193359Simp case 0: 63293359Simp hdrlen = WI_DATA_HDRLEN; 63393359Simp datlen = rx_frame->wi_dat_len + WI_FCS_LEN; 63493359Simp break; 63593359Simp default: 63693359Simp device_printf(sc->dev, "received packet on invalid " 63793359Simp "port (wi_status=0x%x)\n", rx_frame->wi_status); 63893359Simp m_freem(m); 63993359Simp ifp->if_ierrors++; 64093359Simp return; 64193359Simp } 64293359Simp 64393359Simp if ((hdrlen + datlen + 2) > MCLBYTES) { 64453702Swpaul device_printf(sc->dev, "oversized packet received " 64553702Swpaul "(wi_dat_len=%d, wi_status=0x%x)\n", 64693359Simp datlen, rx_frame->wi_status); 64748553Swpaul m_freem(m); 64848553Swpaul ifp->if_ierrors++; 64948553Swpaul return; 65048553Swpaul } 65146492Swpaul 65293359Simp if (wi_read_data(sc, id, hdrlen, mtod(m, caddr_t) + hdrlen, 65393359Simp datlen + 2)) { 65493359Simp m_freem(m); 65593359Simp ifp->if_ierrors++; 65693359Simp return; 65759328Swpaul } 65875373Salfred 65993359Simp m->m_pkthdr.len = m->m_len = hdrlen + datlen; 66046492Swpaul 66193359Simp ifp->if_ipackets++; 66293359Simp 66393359Simp /* Handle BPF listeners. */ 66493359Simp if (ifp->if_bpf) 66593359Simp bpf_mtap(ifp, m); 66693359Simp 66793359Simp m_freem(m); 66893359Simp } else { 66993359Simp struct wi_frame rx_frame; 67093359Simp 67193359Simp /* First read in the frame header */ 67293359Simp if (wi_read_data(sc, id, 0, (caddr_t)&rx_frame, 67393359Simp sizeof(rx_frame))) { 67446492Swpaul ifp->if_ierrors++; 67546492Swpaul return; 67646492Swpaul } 67793359Simp 67893359Simp if (rx_frame.wi_status & WI_STAT_ERRSTAT) { 67948553Swpaul ifp->if_ierrors++; 68048553Swpaul return; 68148553Swpaul } 68246492Swpaul 68393359Simp MGETHDR(m, M_DONTWAIT, MT_DATA); 68493359Simp if (m == NULL) { 68593359Simp ifp->if_ierrors++; 68693359Simp return; 68793359Simp } 68893359Simp MCLGET(m, M_DONTWAIT); 68993359Simp if (!(m->m_flags & M_EXT)) { 69046492Swpaul m_freem(m); 69146492Swpaul ifp->if_ierrors++; 69246492Swpaul return; 69346492Swpaul } 69446492Swpaul 69593359Simp eh = mtod(m, struct ether_header *); 69693359Simp m->m_pkthdr.rcvif = ifp; 69746492Swpaul 69894405Simp if (rx_frame.wi_status == WI_STAT_MGMT && 69994405Simp sc->wi_ptype == WI_PORTTYPE_AP) { 70094405Simp if ((WI_802_11_OFFSET_RAW + rx_frame.wi_dat_len + 2) > 70194405Simp MCLBYTES) { 70294405Simp device_printf(sc->dev, "oversized mgmt packet " 70394405Simp "received in hostap mode " 70494405Simp "(wi_dat_len=%d, wi_status=0x%x)\n", 70594405Simp rx_frame.wi_dat_len, rx_frame.wi_status); 70694405Simp m_freem(m); 70794405Simp ifp->if_ierrors++; 70894405Simp return; 70994405Simp } 71094405Simp 71194405Simp /* Put the whole header in there. */ 71294405Simp bcopy(&rx_frame, mtod(m, void *), 71394405Simp sizeof(struct wi_frame)); 71494405Simp if (wi_read_data(sc, id, WI_802_11_OFFSET_RAW, 71594405Simp mtod(m, caddr_t) + WI_802_11_OFFSET_RAW, 71694405Simp rx_frame.wi_dat_len + 2)) { 71794405Simp m_freem(m); 71894405Simp ifp->if_ierrors++; 71994405Simp return; 72094405Simp } 72194405Simp m->m_pkthdr.len = m->m_len = 72294405Simp WI_802_11_OFFSET_RAW + rx_frame.wi_dat_len; 72394405Simp /* XXX: consider giving packet to bhp? */ 72494405Simp wihap_mgmt_input(sc, &rx_frame, m); 72594405Simp return; 72694405Simp } 72794405Simp 72893359Simp if (rx_frame.wi_status == WI_STAT_1042 || 72993359Simp rx_frame.wi_status == WI_STAT_TUNNEL || 73093359Simp rx_frame.wi_status == WI_STAT_WMP_MSG) { 73193359Simp if((rx_frame.wi_dat_len + WI_SNAPHDR_LEN) > MCLBYTES) { 73293359Simp device_printf(sc->dev, 73393359Simp "oversized packet received " 73493359Simp "(wi_dat_len=%d, wi_status=0x%x)\n", 73593359Simp rx_frame.wi_dat_len, rx_frame.wi_status); 73693359Simp m_freem(m); 73793359Simp ifp->if_ierrors++; 73893359Simp return; 73993359Simp } 74093359Simp m->m_pkthdr.len = m->m_len = 74193359Simp rx_frame.wi_dat_len + WI_SNAPHDR_LEN; 74293359Simp 74393359Simp#if 0 74493359Simp bcopy((char *)&rx_frame.wi_addr1, 74593359Simp (char *)&eh->ether_dhost, ETHER_ADDR_LEN); 74693359Simp if (sc->wi_ptype == WI_PORTTYPE_ADHOC) { 74793359Simp bcopy((char *)&rx_frame.wi_addr2, 74893359Simp (char *)&eh->ether_shost, ETHER_ADDR_LEN); 74993359Simp } else { 75093359Simp bcopy((char *)&rx_frame.wi_addr3, 75193359Simp (char *)&eh->ether_shost, ETHER_ADDR_LEN); 75293359Simp } 75393359Simp#else 75493359Simp bcopy((char *)&rx_frame.wi_dst_addr, 75593359Simp (char *)&eh->ether_dhost, ETHER_ADDR_LEN); 75693359Simp bcopy((char *)&rx_frame.wi_src_addr, 75793359Simp (char *)&eh->ether_shost, ETHER_ADDR_LEN); 75893359Simp#endif 75993359Simp 76093359Simp bcopy((char *)&rx_frame.wi_type, 76193359Simp (char *)&eh->ether_type, ETHER_TYPE_LEN); 76293359Simp 76393359Simp if (wi_read_data(sc, id, WI_802_11_OFFSET, 76493359Simp mtod(m, caddr_t) + sizeof(struct ether_header), 76593359Simp m->m_len + 2)) { 76693359Simp m_freem(m); 76793359Simp ifp->if_ierrors++; 76893359Simp return; 76993359Simp } 77093359Simp } else { 77193359Simp if((rx_frame.wi_dat_len + 77293359Simp sizeof(struct ether_header)) > MCLBYTES) { 77393359Simp device_printf(sc->dev, 77493359Simp "oversized packet received " 77593359Simp "(wi_dat_len=%d, wi_status=0x%x)\n", 77693359Simp rx_frame.wi_dat_len, rx_frame.wi_status); 77793359Simp m_freem(m); 77893359Simp ifp->if_ierrors++; 77993359Simp return; 78093359Simp } 78193359Simp m->m_pkthdr.len = m->m_len = 78293359Simp rx_frame.wi_dat_len + sizeof(struct ether_header); 78393359Simp 78493359Simp if (wi_read_data(sc, id, WI_802_3_OFFSET, 78593359Simp mtod(m, caddr_t), m->m_len + 2)) { 78693359Simp m_freem(m); 78793359Simp ifp->if_ierrors++; 78893359Simp return; 78993359Simp } 79093359Simp } 79193359Simp 79293359Simp ifp->if_ipackets++; 79393359Simp 79494405Simp if (sc->wi_ptype == WI_PORTTYPE_AP) { 79594405Simp /* 79694405Simp * Give host AP code first crack at data 79794405Simp * packets. If it decides to handle it (or 79894405Simp * drop it), it will return a non-zero. 79994405Simp * Otherwise, it is destined for this host. 80094405Simp */ 80194405Simp if (wihap_data_input(sc, &rx_frame, m)) 80294405Simp return; 80394405Simp } 80493359Simp /* Receive packet. */ 80593359Simp m_adj(m, sizeof(struct ether_header)); 80653702Swpaul#ifdef WICACHE 80793359Simp wi_cache_store(sc, eh, m, rx_frame.wi_q_info); 80853702Swpaul#endif 80993359Simp ether_input(ifp, eh, m); 81093359Simp } 81146492Swpaul} 81246492Swpaul 81388546Salfredstatic void 81488546Salfredwi_txeof(sc, status) 81546492Swpaul struct wi_softc *sc; 81646492Swpaul int status; 81746492Swpaul{ 81846492Swpaul struct ifnet *ifp; 81946492Swpaul 82046492Swpaul ifp = &sc->arpcom.ac_if; 82146492Swpaul 82246492Swpaul ifp->if_timer = 0; 82346492Swpaul ifp->if_flags &= ~IFF_OACTIVE; 82446492Swpaul 82546492Swpaul if (status & WI_EV_TX_EXC) 82646492Swpaul ifp->if_oerrors++; 82746492Swpaul else 82846492Swpaul ifp->if_opackets++; 82946492Swpaul 83046492Swpaul return; 83146492Swpaul} 83246492Swpaul 83388546Salfredvoid 83488546Salfredwi_inquire(xsc) 83546492Swpaul void *xsc; 83646492Swpaul{ 83746492Swpaul struct wi_softc *sc; 83846492Swpaul struct ifnet *ifp; 83995534Simp int s; 84046492Swpaul 84146492Swpaul sc = xsc; 84246492Swpaul ifp = &sc->arpcom.ac_if; 84346492Swpaul 84446492Swpaul sc->wi_stat_ch = timeout(wi_inquire, sc, hz * 60); 84546492Swpaul 84646492Swpaul /* Don't do this while we're transmitting */ 84746492Swpaul if (ifp->if_flags & IFF_OACTIVE) 84846492Swpaul return; 84946492Swpaul 85095534Simp WI_LOCK(sc, s); 85192457Simp wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_COUNTERS, 0, 0); 85295534Simp WI_UNLOCK(sc, s); 85346492Swpaul 85446492Swpaul return; 85546492Swpaul} 85646492Swpaul 85788546Salfredvoid 85888546Salfredwi_update_stats(sc) 85946492Swpaul struct wi_softc *sc; 86046492Swpaul{ 86146492Swpaul struct wi_ltv_gen gen; 86246492Swpaul u_int16_t id; 86346492Swpaul struct ifnet *ifp; 86446492Swpaul u_int32_t *ptr; 86575373Salfred int len, i; 86646492Swpaul u_int16_t t; 86746492Swpaul 86846492Swpaul ifp = &sc->arpcom.ac_if; 86946492Swpaul 87046492Swpaul id = CSR_READ_2(sc, WI_INFO_FID); 87146492Swpaul 87246492Swpaul wi_read_data(sc, id, 0, (char *)&gen, 4); 87346492Swpaul 87493359Simp /* 87593359Simp * if we just got our scan results, copy it over into the scan buffer 87693359Simp * so we can return it to anyone that asks for it. (add a little 87793359Simp * compatibility with the prism2 scanning mechanism) 87893359Simp */ 87993359Simp if (gen.wi_type == WI_INFO_SCAN_RESULTS) 88093359Simp { 88193359Simp sc->wi_scanbuf_len = gen.wi_len; 88293359Simp wi_read_data(sc, id, 4, (char *)sc->wi_scanbuf, 88393359Simp sc->wi_scanbuf_len * 2); 88493359Simp 88546492Swpaul return; 88693359Simp } 88793359Simp else if (gen.wi_type != WI_INFO_COUNTERS) 88893359Simp return; 88946492Swpaul 89075373Salfred len = (gen.wi_len - 1 < sizeof(sc->wi_stats) / 4) ? 89175373Salfred gen.wi_len - 1 : sizeof(sc->wi_stats) / 4; 89246492Swpaul ptr = (u_int32_t *)&sc->wi_stats; 89346492Swpaul 89475373Salfred for (i = 0; i < len - 1; i++) { 89546492Swpaul t = CSR_READ_2(sc, WI_DATA1); 89646492Swpaul#ifdef WI_HERMES_STATS_WAR 89746492Swpaul if (t > 0xF000) 89846492Swpaul t = ~t & 0xFFFF; 89946492Swpaul#endif 90046492Swpaul ptr[i] += t; 90146492Swpaul } 90246492Swpaul 90346492Swpaul ifp->if_collisions = sc->wi_stats.wi_tx_single_retries + 90446492Swpaul sc->wi_stats.wi_tx_multi_retries + 90546492Swpaul sc->wi_stats.wi_tx_retry_limit; 90646492Swpaul 90746492Swpaul return; 90846492Swpaul} 90946492Swpaul 91088546Salfredstatic void 91188546Salfredwi_intr(xsc) 91253702Swpaul void *xsc; 91346492Swpaul{ 91453702Swpaul struct wi_softc *sc = xsc; 91546492Swpaul struct ifnet *ifp; 91646492Swpaul u_int16_t status; 91795534Simp int s; 91846492Swpaul 91995534Simp WI_LOCK(sc, s); 92067092Swpaul 92146492Swpaul ifp = &sc->arpcom.ac_if; 92246492Swpaul 92375373Salfred if (sc->wi_gone || !(ifp->if_flags & IFF_UP)) { 92446492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); 92546492Swpaul CSR_WRITE_2(sc, WI_INT_EN, 0); 92695534Simp WI_UNLOCK(sc, s); 92746492Swpaul return; 92846492Swpaul } 92946492Swpaul 93046492Swpaul /* Disable interrupts. */ 93146492Swpaul CSR_WRITE_2(sc, WI_INT_EN, 0); 93246492Swpaul 93346492Swpaul status = CSR_READ_2(sc, WI_EVENT_STAT); 93446492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, ~WI_INTRS); 93546492Swpaul 93646492Swpaul if (status & WI_EV_RX) { 93746492Swpaul wi_rxeof(sc); 93846492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX); 93946492Swpaul } 94046492Swpaul 94146492Swpaul if (status & WI_EV_TX) { 94246492Swpaul wi_txeof(sc, status); 94346492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX); 94446492Swpaul } 94546492Swpaul 94646492Swpaul if (status & WI_EV_ALLOC) { 94746492Swpaul int id; 94875373Salfred 94946492Swpaul id = CSR_READ_2(sc, WI_ALLOC_FID); 95046492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC); 95146492Swpaul if (id == sc->wi_tx_data_id) 95246492Swpaul wi_txeof(sc, status); 95346492Swpaul } 95446492Swpaul 95546492Swpaul if (status & WI_EV_INFO) { 95646492Swpaul wi_update_stats(sc); 95746492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO); 95846492Swpaul } 95946492Swpaul 96046492Swpaul if (status & WI_EV_TX_EXC) { 96146492Swpaul wi_txeof(sc, status); 96246492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX_EXC); 96346492Swpaul } 96446492Swpaul 96546492Swpaul if (status & WI_EV_INFO_DROP) { 96646492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO_DROP); 96746492Swpaul } 96846492Swpaul 96946492Swpaul /* Re-enable interrupts. */ 97046492Swpaul CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS); 97146492Swpaul 97275373Salfred if (ifp->if_snd.ifq_head != NULL) { 97346492Swpaul wi_start(ifp); 97475373Salfred } 97546492Swpaul 97695534Simp WI_UNLOCK(sc, s); 97767092Swpaul 97846492Swpaul return; 97946492Swpaul} 98046492Swpaul 98188546Salfredstatic int 98292457Simpwi_cmd(sc, cmd, val0, val1, val2) 98346492Swpaul struct wi_softc *sc; 98446492Swpaul int cmd; 98592457Simp int val0; 98692457Simp int val1; 98792457Simp int val2; 98846492Swpaul{ 98946492Swpaul int i, s = 0; 99095534Simp static volatile int count = 0; 99195534Simp 99295534Simp if (count > 1) 99395534Simp panic("Hey partner, hold on there!"); 99495534Simp count++; 99546492Swpaul 99670073Swpaul /* wait for the busy bit to clear */ 99775331Simp for (i = 500; i > 0; i--) { /* 5s */ 99870073Swpaul if (!(CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY)) { 99970073Swpaul break; 100070073Swpaul } 100170073Swpaul DELAY(10*1000); /* 10 m sec */ 100270073Swpaul } 100375229Salfred if (i == 0) { 100490580Sbrooks device_printf(sc->dev, "wi_cmd: busy bit won't clear.\n" ); 100595534Simp count--; 100670073Swpaul return(ETIMEDOUT); 100770073Swpaul } 100870073Swpaul 100992457Simp CSR_WRITE_2(sc, WI_PARAM0, val0); 101092457Simp CSR_WRITE_2(sc, WI_PARAM1, val1); 101192457Simp CSR_WRITE_2(sc, WI_PARAM2, val2); 101246492Swpaul CSR_WRITE_2(sc, WI_COMMAND, cmd); 101346492Swpaul 101446492Swpaul for (i = 0; i < WI_TIMEOUT; i++) { 101546492Swpaul /* 101646492Swpaul * Wait for 'command complete' bit to be 101746492Swpaul * set in the event status register. 101846492Swpaul */ 101990580Sbrooks s = CSR_READ_2(sc, WI_EVENT_STAT); 102090580Sbrooks if (s & WI_EV_CMD) { 102146492Swpaul /* Ack the event and read result code. */ 102246492Swpaul s = CSR_READ_2(sc, WI_STATUS); 102346492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD); 102446492Swpaul#ifdef foo 102546492Swpaul if ((s & WI_CMD_CODE_MASK) != (cmd & WI_CMD_CODE_MASK)) 102646492Swpaul return(EIO); 102746492Swpaul#endif 102895534Simp if (s & WI_STAT_CMD_RESULT) { 102995534Simp count--; 103046492Swpaul return(EIO); 103195534Simp } 103246492Swpaul break; 103346492Swpaul } 103490580Sbrooks DELAY(WI_DELAY); 103546492Swpaul } 103646492Swpaul 103795534Simp count--; 103890580Sbrooks if (i == WI_TIMEOUT) { 103990580Sbrooks device_printf(sc->dev, 104092457Simp "timeout in wi_cmd 0x%04x; event status 0x%04x\n", cmd, s); 104146492Swpaul return(ETIMEDOUT); 104290580Sbrooks } 104346492Swpaul return(0); 104446492Swpaul} 104546492Swpaul 104688546Salfredstatic void 104788546Salfredwi_reset(sc) 104846492Swpaul struct wi_softc *sc; 104946492Swpaul{ 105094397Simp#define WI_INIT_TRIES 3 105175150Simp int i; 105293733Simp int tries; 105375149Simp 105493733Simp /* Symbol firmware cannot be initialized more than once */ 105593733Simp if (sc->sc_firmware_type == WI_SYMBOL && sc->sc_enabled) 105693733Simp return; 105793733Simp if (sc->sc_firmware_type == WI_SYMBOL) 105893733Simp tries = 1; 105993733Simp else 106093733Simp tries = WI_INIT_TRIES; 106193733Simp 106293733Simp for (i = 0; i < tries; i++) { 106392457Simp if (wi_cmd(sc, WI_CMD_INI, 0, 0, 0) == 0) 106475149Simp break; 106590580Sbrooks DELAY(WI_DELAY * 1000); 106675149Simp } 106794397Simp sc->sc_enabled = 1; 106894397Simp 106994397Simp if (i == tries) { 107053702Swpaul device_printf(sc->dev, "init failed\n"); 107194397Simp return; 107294397Simp } 107375373Salfred 107446492Swpaul CSR_WRITE_2(sc, WI_INT_EN, 0); 107546492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); 107646492Swpaul 107746492Swpaul /* Calibrate timer. */ 107846492Swpaul WI_SETVAL(WI_RID_TICK_TIME, 8); 107970073Swpaul 108046492Swpaul return; 108146492Swpaul} 108246492Swpaul 108346492Swpaul/* 108446492Swpaul * Read an LTV record from the NIC. 108546492Swpaul */ 108688546Salfredstatic int 108788546Salfredwi_read_record(sc, ltv) 108846492Swpaul struct wi_softc *sc; 108946492Swpaul struct wi_ltv_gen *ltv; 109046492Swpaul{ 109146492Swpaul u_int16_t *ptr; 109246492Swpaul int i, len, code; 109370073Swpaul struct wi_ltv_gen *oltv, p2ltv; 109446492Swpaul 109570073Swpaul oltv = ltv; 109693733Simp if (sc->sc_firmware_type != WI_LUCENT) { 109770073Swpaul switch (ltv->wi_type) { 109870073Swpaul case WI_RID_ENCRYPTION: 109970073Swpaul p2ltv.wi_type = WI_RID_P2_ENCRYPTION; 110070073Swpaul p2ltv.wi_len = 2; 110170073Swpaul ltv = &p2ltv; 110270073Swpaul break; 110370073Swpaul case WI_RID_TX_CRYPT_KEY: 110470073Swpaul p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY; 110570073Swpaul p2ltv.wi_len = 2; 110670073Swpaul ltv = &p2ltv; 110770073Swpaul break; 110895031Sonoe case WI_RID_ROAMING_MODE: 110995031Sonoe if (sc->sc_firmware_type == WI_INTERSIL) 111095031Sonoe break; 111195031Sonoe /* not supported */ 111295031Sonoe ltv->wi_len = 1; 111395031Sonoe return 0; 111495031Sonoe case WI_RID_MICROWAVE_OVEN: 111595031Sonoe /* not supported */ 111695031Sonoe ltv->wi_len = 1; 111795031Sonoe return 0; 111870073Swpaul } 111970073Swpaul } 112070073Swpaul 112146492Swpaul /* Tell the NIC to enter record read mode. */ 112292457Simp if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_READ, ltv->wi_type, 0, 0)) 112346492Swpaul return(EIO); 112446492Swpaul 112547789Swpaul /* Seek to the record. */ 112647789Swpaul if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1)) 112747789Swpaul return(EIO); 112846492Swpaul 112946492Swpaul /* 113046492Swpaul * Read the length and record type and make sure they 113146492Swpaul * match what we expect (this verifies that we have enough 113247401Swpaul * room to hold all of the returned data). 113346492Swpaul */ 113446492Swpaul len = CSR_READ_2(sc, WI_DATA1); 113546492Swpaul if (len > ltv->wi_len) 113646492Swpaul return(ENOSPC); 113746492Swpaul code = CSR_READ_2(sc, WI_DATA1); 113846492Swpaul if (code != ltv->wi_type) 113946492Swpaul return(EIO); 114046492Swpaul 114146492Swpaul ltv->wi_len = len; 114246492Swpaul ltv->wi_type = code; 114346492Swpaul 114446492Swpaul /* Now read the data. */ 114546492Swpaul ptr = <v->wi_val; 114646492Swpaul for (i = 0; i < ltv->wi_len - 1; i++) 114746492Swpaul ptr[i] = CSR_READ_2(sc, WI_DATA1); 114846492Swpaul 114998440Simp if (ltv->wi_type == WI_RID_PORTTYPE && sc->wi_ptype == WI_PORTTYPE_IBSS 115098440Simp && ltv->wi_val == sc->wi_ibss_port) { 115198440Simp /* 115298440Simp * Convert vendor IBSS port type to WI_PORTTYPE_IBSS. 115398440Simp * Since Lucent uses port type 1 for BSS *and* IBSS we 115498440Simp * have to rely on wi_ptype to distinguish this for us. 115598440Simp */ 115698440Simp ltv->wi_val = htole16(WI_PORTTYPE_IBSS); 115798440Simp } else if (sc->sc_firmware_type != WI_LUCENT) { 115870073Swpaul switch (oltv->wi_type) { 115970073Swpaul case WI_RID_TX_RATE: 116070073Swpaul case WI_RID_CUR_TX_RATE: 116170073Swpaul switch (ltv->wi_val) { 116270073Swpaul case 1: oltv->wi_val = 1; break; 116370073Swpaul case 2: oltv->wi_val = 2; break; 116470073Swpaul case 3: oltv->wi_val = 6; break; 116570073Swpaul case 4: oltv->wi_val = 5; break; 116670073Swpaul case 7: oltv->wi_val = 7; break; 116770073Swpaul case 8: oltv->wi_val = 11; break; 116870073Swpaul case 15: oltv->wi_val = 3; break; 116970073Swpaul default: oltv->wi_val = 0x100 + ltv->wi_val; break; 117070073Swpaul } 117170073Swpaul break; 117270073Swpaul case WI_RID_ENCRYPTION: 117370073Swpaul oltv->wi_len = 2; 117470073Swpaul if (ltv->wi_val & 0x01) 117570073Swpaul oltv->wi_val = 1; 117670073Swpaul else 117770073Swpaul oltv->wi_val = 0; 117870073Swpaul break; 117970073Swpaul case WI_RID_TX_CRYPT_KEY: 118070073Swpaul oltv->wi_len = 2; 118170073Swpaul oltv->wi_val = ltv->wi_val; 118270073Swpaul break; 118394405Simp case WI_RID_CNFAUTHMODE: 118491695Simp oltv->wi_len = 2; 118591695Simp if (le16toh(ltv->wi_val) & 0x01) 118691695Simp oltv->wi_val = htole16(1); 118791695Simp else if (le16toh(ltv->wi_val) & 0x02) 118891695Simp oltv->wi_val = htole16(2); 118991695Simp break; 119070073Swpaul } 119170073Swpaul } 119270073Swpaul 119346492Swpaul return(0); 119446492Swpaul} 119546492Swpaul 119646492Swpaul/* 119746492Swpaul * Same as read, except we inject data instead of reading it. 119846492Swpaul */ 119988546Salfredstatic int 120088546Salfredwi_write_record(sc, ltv) 120146492Swpaul struct wi_softc *sc; 120246492Swpaul struct wi_ltv_gen *ltv; 120346492Swpaul{ 120446492Swpaul u_int16_t *ptr; 120546492Swpaul int i; 120670073Swpaul struct wi_ltv_gen p2ltv; 120746492Swpaul 120898440Simp if (ltv->wi_type == WI_RID_PORTTYPE && 120998440Simp le16toh(ltv->wi_val) == WI_PORTTYPE_IBSS) { 121098440Simp /* Convert WI_PORTTYPE_IBSS to vendor IBSS port type. */ 121198440Simp p2ltv.wi_type = WI_RID_PORTTYPE; 121298440Simp p2ltv.wi_len = 2; 121398440Simp p2ltv.wi_val = sc->wi_ibss_port; 121498440Simp ltv = &p2ltv; 121598440Simp } else if (sc->sc_firmware_type != WI_LUCENT) { 121670073Swpaul switch (ltv->wi_type) { 121770073Swpaul case WI_RID_TX_RATE: 121870073Swpaul p2ltv.wi_type = WI_RID_TX_RATE; 121970073Swpaul p2ltv.wi_len = 2; 122070073Swpaul switch (ltv->wi_val) { 122170073Swpaul case 1: p2ltv.wi_val = 1; break; 122270073Swpaul case 2: p2ltv.wi_val = 2; break; 122370073Swpaul case 3: p2ltv.wi_val = 15; break; 122470073Swpaul case 5: p2ltv.wi_val = 4; break; 122570073Swpaul case 6: p2ltv.wi_val = 3; break; 122670073Swpaul case 7: p2ltv.wi_val = 7; break; 122770073Swpaul case 11: p2ltv.wi_val = 8; break; 122870073Swpaul default: return EINVAL; 122970073Swpaul } 123070073Swpaul ltv = &p2ltv; 123170073Swpaul break; 123270073Swpaul case WI_RID_ENCRYPTION: 123370073Swpaul p2ltv.wi_type = WI_RID_P2_ENCRYPTION; 123470073Swpaul p2ltv.wi_len = 2; 123594405Simp if (le16toh(ltv->wi_val)) { 123693825Simp p2ltv.wi_val =htole16(PRIVACY_INVOKED | 123793825Simp EXCLUDE_UNENCRYPTED); 123894405Simp if (sc->wi_ptype == WI_PORTTYPE_AP) 123994405Simp /* 124094405Simp * Disable tx encryption... 124194405Simp * it's broken. 124294405Simp */ 124394405Simp p2ltv.wi_val |= htole16(HOST_ENCRYPT); 124494405Simp } else 124593825Simp p2ltv.wi_val = 124693825Simp htole16(HOST_ENCRYPT | HOST_DECRYPT); 124770073Swpaul ltv = &p2ltv; 124870073Swpaul break; 124970073Swpaul case WI_RID_TX_CRYPT_KEY: 125070073Swpaul p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY; 125170073Swpaul p2ltv.wi_len = 2; 125270073Swpaul p2ltv.wi_val = ltv->wi_val; 125370073Swpaul ltv = &p2ltv; 125470073Swpaul break; 125570073Swpaul case WI_RID_DEFLT_CRYPT_KEYS: 125670073Swpaul { 125770073Swpaul int error; 125891548Sbrooks int keylen; 125970073Swpaul struct wi_ltv_str ws; 126074998Swpaul struct wi_ltv_keys *wk = 126174998Swpaul (struct wi_ltv_keys *)ltv; 126274998Swpaul 126391548Sbrooks keylen = wk->wi_keys[sc->wi_tx_key].wi_keylen; 126491548Sbrooks 126570073Swpaul for (i = 0; i < 4; i++) { 126691548Sbrooks bzero(&ws, sizeof(ws)); 126791548Sbrooks ws.wi_len = (keylen > 5) ? 8 : 4; 126870073Swpaul ws.wi_type = WI_RID_P2_CRYPT_KEY0 + i; 126974998Swpaul memcpy(ws.wi_str, 127091548Sbrooks &wk->wi_keys[i].wi_keydat, keylen); 127170073Swpaul error = wi_write_record(sc, 127270073Swpaul (struct wi_ltv_gen *)&ws); 127370073Swpaul if (error) 127470073Swpaul return error; 127570073Swpaul } 127670073Swpaul return 0; 127770073Swpaul } 127894405Simp case WI_RID_CNFAUTHMODE: 127994405Simp p2ltv.wi_type = WI_RID_CNFAUTHMODE; 128091695Simp p2ltv.wi_len = 2; 128191695Simp if (le16toh(ltv->wi_val) == 1) 128291695Simp p2ltv.wi_val = htole16(0x01); 128391695Simp else if (le16toh(ltv->wi_val) == 2) 128491695Simp p2ltv.wi_val = htole16(0x02); 128591695Simp ltv = &p2ltv; 128691695Simp break; 128795031Sonoe case WI_RID_ROAMING_MODE: 128895031Sonoe if (sc->sc_firmware_type == WI_INTERSIL) 128995031Sonoe break; 129095031Sonoe /* not supported */ 129195031Sonoe return 0; 129295031Sonoe case WI_RID_MICROWAVE_OVEN: 129395031Sonoe /* not supported */ 129495031Sonoe return 0; 129570073Swpaul } 129694695Sbrooks } else { 129794695Sbrooks /* LUCENT */ 129894695Sbrooks switch (ltv->wi_type) { 129994695Sbrooks case WI_RID_TX_RATE: 130094695Sbrooks switch (ltv->wi_val) { 130194695Sbrooks case 1: ltv->wi_val = 1; break; /* 1Mb/s fixed */ 130294695Sbrooks case 2: ltv->wi_val = 2; break; /* 2Mb/s fixed */ 130394695Sbrooks case 3: ltv->wi_val = 3; break; /* 11Mb/s auto */ 130494695Sbrooks case 5: ltv->wi_val = 4; break; /* 5.5Mb/s fixed */ 130594695Sbrooks case 6: ltv->wi_val = 6; break; /* 2Mb/s auto */ 130694695Sbrooks case 7: ltv->wi_val = 7; break; /* 5.5Mb/s auto */ 130794695Sbrooks case 11: ltv->wi_val = 5; break; /* 11Mb/s fixed */ 130894695Sbrooks default: return EINVAL; 130994695Sbrooks } 131094695Sbrooks } 131170073Swpaul } 131270073Swpaul 131347789Swpaul if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1)) 131447789Swpaul return(EIO); 131546492Swpaul 131646492Swpaul CSR_WRITE_2(sc, WI_DATA1, ltv->wi_len); 131746492Swpaul CSR_WRITE_2(sc, WI_DATA1, ltv->wi_type); 131846492Swpaul 131946492Swpaul ptr = <v->wi_val; 132046492Swpaul for (i = 0; i < ltv->wi_len - 1; i++) 132146492Swpaul CSR_WRITE_2(sc, WI_DATA1, ptr[i]); 132246492Swpaul 132392457Simp if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_WRITE, ltv->wi_type, 0, 0)) 132446492Swpaul return(EIO); 132546492Swpaul 132646492Swpaul return(0); 132746492Swpaul} 132846492Swpaul 132988546Salfredstatic int 133088546Salfredwi_seek(sc, id, off, chan) 133146492Swpaul struct wi_softc *sc; 133246492Swpaul int id, off, chan; 133346492Swpaul{ 133446492Swpaul int i; 133546492Swpaul int selreg, offreg; 133675373Salfred int status; 133746492Swpaul 133846492Swpaul switch (chan) { 133946492Swpaul case WI_BAP0: 134046492Swpaul selreg = WI_SEL0; 134146492Swpaul offreg = WI_OFF0; 134246492Swpaul break; 134346492Swpaul case WI_BAP1: 134446492Swpaul selreg = WI_SEL1; 134546492Swpaul offreg = WI_OFF1; 134646492Swpaul break; 134746492Swpaul default: 134853702Swpaul device_printf(sc->dev, "invalid data path: %x\n", chan); 134946492Swpaul return(EIO); 135046492Swpaul } 135146492Swpaul 135246492Swpaul CSR_WRITE_2(sc, selreg, id); 135346492Swpaul CSR_WRITE_2(sc, offreg, off); 135446492Swpaul 135546492Swpaul for (i = 0; i < WI_TIMEOUT; i++) { 135675373Salfred status = CSR_READ_2(sc, offreg); 135775373Salfred if (!(status & (WI_OFF_BUSY|WI_OFF_ERR))) 135846492Swpaul break; 135990580Sbrooks DELAY(WI_DELAY); 136046492Swpaul } 136146492Swpaul 136275373Salfred if (i == WI_TIMEOUT) { 136375373Salfred device_printf(sc->dev, "timeout in wi_seek to %x/%x; last status %x\n", 136475373Salfred id, off, status); 136546492Swpaul return(ETIMEDOUT); 136675373Salfred } 136746492Swpaul 136846492Swpaul return(0); 136946492Swpaul} 137046492Swpaul 137188546Salfredstatic int 137288546Salfredwi_read_data(sc, id, off, buf, len) 137346492Swpaul struct wi_softc *sc; 137446492Swpaul int id, off; 137546492Swpaul caddr_t buf; 137646492Swpaul int len; 137746492Swpaul{ 137846492Swpaul int i; 137946492Swpaul u_int16_t *ptr; 138046492Swpaul 138146492Swpaul if (wi_seek(sc, id, off, WI_BAP1)) 138246492Swpaul return(EIO); 138346492Swpaul 138446492Swpaul ptr = (u_int16_t *)buf; 138546492Swpaul for (i = 0; i < len / 2; i++) 138646492Swpaul ptr[i] = CSR_READ_2(sc, WI_DATA1); 138746492Swpaul 138846492Swpaul return(0); 138946492Swpaul} 139046492Swpaul 139146492Swpaul/* 139246492Swpaul * According to the comments in the HCF Light code, there is a bug in 139346492Swpaul * the Hermes (or possibly in certain Hermes firmware revisions) where 139446492Swpaul * the chip's internal autoincrement counter gets thrown off during 139546492Swpaul * data writes: the autoincrement is missed, causing one data word to 139646492Swpaul * be overwritten and subsequent words to be written to the wrong memory 139746492Swpaul * locations. The end result is that we could end up transmitting bogus 139846492Swpaul * frames without realizing it. The workaround for this is to write a 139946492Swpaul * couple of extra guard words after the end of the transfer, then 140046492Swpaul * attempt to read then back. If we fail to locate the guard words where 140146492Swpaul * we expect them, we preform the transfer over again. 140246492Swpaul */ 140388546Salfredstatic int 140488546Salfredwi_write_data(sc, id, off, buf, len) 140546492Swpaul struct wi_softc *sc; 140646492Swpaul int id, off; 140746492Swpaul caddr_t buf; 140846492Swpaul int len; 140946492Swpaul{ 141046492Swpaul int i; 141146492Swpaul u_int16_t *ptr; 141274838Salfred#ifdef WI_HERMES_AUTOINC_WAR 141374838Salfred int retries; 141446492Swpaul 141575373Salfred retries = 512; 141646492Swpaulagain: 141746492Swpaul#endif 141846492Swpaul 141946492Swpaul if (wi_seek(sc, id, off, WI_BAP0)) 142046492Swpaul return(EIO); 142146492Swpaul 142246492Swpaul ptr = (u_int16_t *)buf; 142346492Swpaul for (i = 0; i < (len / 2); i++) 142446492Swpaul CSR_WRITE_2(sc, WI_DATA0, ptr[i]); 142546492Swpaul 142646492Swpaul#ifdef WI_HERMES_AUTOINC_WAR 142746492Swpaul CSR_WRITE_2(sc, WI_DATA0, 0x1234); 142846492Swpaul CSR_WRITE_2(sc, WI_DATA0, 0x5678); 142946492Swpaul 143046492Swpaul if (wi_seek(sc, id, off + len, WI_BAP0)) 143146492Swpaul return(EIO); 143246492Swpaul 143346492Swpaul if (CSR_READ_2(sc, WI_DATA0) != 0x1234 || 143474998Swpaul CSR_READ_2(sc, WI_DATA0) != 0x5678) { 143574838Salfred if (--retries >= 0) 143674838Salfred goto again; 143774838Salfred device_printf(sc->dev, "wi_write_data device timeout\n"); 143874838Salfred return (EIO); 143974838Salfred } 144046492Swpaul#endif 144146492Swpaul 144246492Swpaul return(0); 144346492Swpaul} 144446492Swpaul 144546492Swpaul/* 144646492Swpaul * Allocate a region of memory inside the NIC and zero 144746492Swpaul * it out. 144846492Swpaul */ 144988546Salfredstatic int 145088546Salfredwi_alloc_nicmem(sc, len, id) 145146492Swpaul struct wi_softc *sc; 145246492Swpaul int len; 145346492Swpaul int *id; 145446492Swpaul{ 145546492Swpaul int i; 145646492Swpaul 145792457Simp if (wi_cmd(sc, WI_CMD_ALLOC_MEM, len, 0, 0)) { 145874998Swpaul device_printf(sc->dev, 145974998Swpaul "failed to allocate %d bytes on NIC\n", len); 146046492Swpaul return(ENOMEM); 146146492Swpaul } 146246492Swpaul 146346492Swpaul for (i = 0; i < WI_TIMEOUT; i++) { 146446492Swpaul if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_ALLOC) 146546492Swpaul break; 146690580Sbrooks DELAY(WI_DELAY); 146746492Swpaul } 146846492Swpaul 146975373Salfred if (i == WI_TIMEOUT) { 147075373Salfred device_printf(sc->dev, "time out allocating memory on card\n"); 147146492Swpaul return(ETIMEDOUT); 147275373Salfred } 147346492Swpaul 147446492Swpaul CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC); 147546492Swpaul *id = CSR_READ_2(sc, WI_ALLOC_FID); 147646492Swpaul 147775373Salfred if (wi_seek(sc, *id, 0, WI_BAP0)) { 147875373Salfred device_printf(sc->dev, "seek failed while allocating memory on card\n"); 147947789Swpaul return(EIO); 148075373Salfred } 148146492Swpaul 148246492Swpaul for (i = 0; i < len / 2; i++) 148346492Swpaul CSR_WRITE_2(sc, WI_DATA0, 0); 148446492Swpaul 148546492Swpaul return(0); 148646492Swpaul} 148746492Swpaul 148888546Salfredstatic void 148988546Salfredwi_setmulti(sc) 149046492Swpaul struct wi_softc *sc; 149146492Swpaul{ 149246492Swpaul struct ifnet *ifp; 149346492Swpaul int i = 0; 149446492Swpaul struct ifmultiaddr *ifma; 149546492Swpaul struct wi_ltv_mcast mcast; 149646492Swpaul 149746492Swpaul ifp = &sc->arpcom.ac_if; 149846492Swpaul 149946492Swpaul bzero((char *)&mcast, sizeof(mcast)); 150046492Swpaul 150193756Simp mcast.wi_type = WI_RID_MCAST_LIST; 150246492Swpaul mcast.wi_len = (3 * 16) + 1; 150346492Swpaul 150446492Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 150546492Swpaul wi_write_record(sc, (struct wi_ltv_gen *)&mcast); 150646492Swpaul return; 150746492Swpaul } 150846492Swpaul 150995534Simp#if __FreeBSD_version < 500000 151095534Simp LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 151195534Simp#else 151272084Sphk TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 151395534Simp#endif 151446492Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 151546492Swpaul continue; 151646492Swpaul if (i < 16) { 151746492Swpaul bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 151846492Swpaul (char *)&mcast.wi_mcast[i], ETHER_ADDR_LEN); 151946492Swpaul i++; 152046492Swpaul } else { 152146492Swpaul bzero((char *)&mcast, sizeof(mcast)); 152246492Swpaul break; 152346492Swpaul } 152446492Swpaul } 152546492Swpaul 152646492Swpaul mcast.wi_len = (i * 3) + 1; 152746492Swpaul wi_write_record(sc, (struct wi_ltv_gen *)&mcast); 152846492Swpaul 152946492Swpaul return; 153046492Swpaul} 153146492Swpaul 153288546Salfredstatic void 153388546Salfredwi_setdef(sc, wreq) 153446492Swpaul struct wi_softc *sc; 153546492Swpaul struct wi_req *wreq; 153646492Swpaul{ 153746492Swpaul struct sockaddr_dl *sdl; 153846492Swpaul struct ifaddr *ifa; 153946492Swpaul struct ifnet *ifp; 154046492Swpaul 154146492Swpaul ifp = &sc->arpcom.ac_if; 154246492Swpaul 154346492Swpaul switch(wreq->wi_type) { 154446492Swpaul case WI_RID_MAC_NODE: 154583130Sjlemon ifa = ifaddr_byindex(ifp->if_index); 154646492Swpaul sdl = (struct sockaddr_dl *)ifa->ifa_addr; 154746492Swpaul bcopy((char *)&wreq->wi_val, (char *)&sc->arpcom.ac_enaddr, 154846492Swpaul ETHER_ADDR_LEN); 154946492Swpaul bcopy((char *)&wreq->wi_val, LLADDR(sdl), ETHER_ADDR_LEN); 155046492Swpaul break; 155146492Swpaul case WI_RID_PORTTYPE: 155291695Simp sc->wi_ptype = le16toh(wreq->wi_val[0]); 155346492Swpaul break; 155446492Swpaul case WI_RID_TX_RATE: 155591695Simp sc->wi_tx_rate = le16toh(wreq->wi_val[0]); 155646492Swpaul break; 155746492Swpaul case WI_RID_MAX_DATALEN: 155891695Simp sc->wi_max_data_len = le16toh(wreq->wi_val[0]); 155946492Swpaul break; 156046492Swpaul case WI_RID_RTS_THRESH: 156191695Simp sc->wi_rts_thresh = le16toh(wreq->wi_val[0]); 156246492Swpaul break; 156346492Swpaul case WI_RID_SYSTEM_SCALE: 156491695Simp sc->wi_ap_density = le16toh(wreq->wi_val[0]); 156546492Swpaul break; 156646492Swpaul case WI_RID_CREATE_IBSS: 156791695Simp sc->wi_create_ibss = le16toh(wreq->wi_val[0]); 156846492Swpaul break; 156946563Swpaul case WI_RID_OWN_CHNL: 157091695Simp sc->wi_channel = le16toh(wreq->wi_val[0]); 157146563Swpaul break; 157246492Swpaul case WI_RID_NODENAME: 157346492Swpaul bzero(sc->wi_node_name, sizeof(sc->wi_node_name)); 157446492Swpaul bcopy((char *)&wreq->wi_val[1], sc->wi_node_name, 30); 157546492Swpaul break; 157646492Swpaul case WI_RID_DESIRED_SSID: 157746492Swpaul bzero(sc->wi_net_name, sizeof(sc->wi_net_name)); 157846492Swpaul bcopy((char *)&wreq->wi_val[1], sc->wi_net_name, 30); 157946492Swpaul break; 158046492Swpaul case WI_RID_OWN_SSID: 158146492Swpaul bzero(sc->wi_ibss_name, sizeof(sc->wi_ibss_name)); 158246492Swpaul bcopy((char *)&wreq->wi_val[1], sc->wi_ibss_name, 30); 158346492Swpaul break; 158446611Swpaul case WI_RID_PM_ENABLED: 158591695Simp sc->wi_pm_enabled = le16toh(wreq->wi_val[0]); 158646611Swpaul break; 158791695Simp case WI_RID_MICROWAVE_OVEN: 158891695Simp sc->wi_mor_enabled = le16toh(wreq->wi_val[0]); 158991695Simp break; 159046611Swpaul case WI_RID_MAX_SLEEP: 159191695Simp sc->wi_max_sleep = le16toh(wreq->wi_val[0]); 159246611Swpaul break; 159394405Simp case WI_RID_CNFAUTHMODE: 159491695Simp sc->wi_authtype = le16toh(wreq->wi_val[0]); 159591695Simp break; 159691695Simp case WI_RID_ROAMING_MODE: 159791695Simp sc->wi_roaming = le16toh(wreq->wi_val[0]); 159891695Simp break; 159956965Swpaul case WI_RID_ENCRYPTION: 160091695Simp sc->wi_use_wep = le16toh(wreq->wi_val[0]); 160156965Swpaul break; 160256965Swpaul case WI_RID_TX_CRYPT_KEY: 160391695Simp sc->wi_tx_key = le16toh(wreq->wi_val[0]); 160456965Swpaul break; 160556965Swpaul case WI_RID_DEFLT_CRYPT_KEYS: 160656965Swpaul bcopy((char *)wreq, (char *)&sc->wi_keys, 160756965Swpaul sizeof(struct wi_ltv_keys)); 160856965Swpaul break; 160946492Swpaul default: 161046492Swpaul break; 161146492Swpaul } 161246492Swpaul 161346563Swpaul /* Reinitialize WaveLAN. */ 161446563Swpaul wi_init(sc); 161546563Swpaul 161646492Swpaul return; 161746492Swpaul} 161846492Swpaul 161988546Salfredstatic int 162088546Salfredwi_ioctl(ifp, command, data) 162146492Swpaul struct ifnet *ifp; 162246492Swpaul u_long command; 162346492Swpaul caddr_t data; 162446492Swpaul{ 162567092Swpaul int error = 0; 162677217Sphk int len; 162777217Sphk u_int8_t tmpkey[14]; 162877217Sphk char tmpssid[IEEE80211_NWID_LEN]; 162946492Swpaul struct wi_softc *sc; 163046492Swpaul struct wi_req wreq; 163146492Swpaul struct ifreq *ifr; 163277217Sphk struct ieee80211req *ireq; 163395534Simp#if __FreeBSD_version >= 500000 163493593Sjhb struct thread *td = curthread; 163595534Simp#else 163695534Simp struct proc *td = curproc; /* Little white lie */ 163795534Simp#endif 163895534Simp int s; 163946492Swpaul 164046492Swpaul sc = ifp->if_softc; 164195534Simp WI_LOCK(sc, s); 164246492Swpaul ifr = (struct ifreq *)data; 164377217Sphk ireq = (struct ieee80211req *)data; 164446492Swpaul 164561818Sroberto if (sc->wi_gone) { 164661818Sroberto error = ENODEV; 164761818Sroberto goto out; 164861818Sroberto } 164946492Swpaul 165046492Swpaul switch(command) { 165146492Swpaul case SIOCSIFADDR: 165246492Swpaul case SIOCGIFADDR: 165346492Swpaul case SIOCSIFMTU: 165446492Swpaul error = ether_ioctl(ifp, command, data); 165546492Swpaul break; 165646492Swpaul case SIOCSIFFLAGS: 1657100876Simp /* 1658100876Simp * Can't do promisc and hostap at the same time. 1659100876Simp */ 1660100876Simp if (sc->wi_ptype == WI_PORTTYPE_AP) 1661100876Simp ifp->if_flags &= ~IFF_PROMISC; 166246492Swpaul if (ifp->if_flags & IFF_UP) { 166346492Swpaul if (ifp->if_flags & IFF_RUNNING && 166446492Swpaul ifp->if_flags & IFF_PROMISC && 166546492Swpaul !(sc->wi_if_flags & IFF_PROMISC)) { 166646492Swpaul WI_SETVAL(WI_RID_PROMISC, 1); 166746492Swpaul } else if (ifp->if_flags & IFF_RUNNING && 166846492Swpaul !(ifp->if_flags & IFF_PROMISC) && 166946492Swpaul sc->wi_if_flags & IFF_PROMISC) { 167046492Swpaul WI_SETVAL(WI_RID_PROMISC, 0); 1671100876Simp } else { 167246492Swpaul wi_init(sc); 1673100876Simp } 167446492Swpaul } else { 167546492Swpaul if (ifp->if_flags & IFF_RUNNING) { 167646492Swpaul wi_stop(sc); 167746492Swpaul } 167846492Swpaul } 167946492Swpaul sc->wi_if_flags = ifp->if_flags; 168046492Swpaul error = 0; 168146492Swpaul break; 168277217Sphk case SIOCSIFMEDIA: 168377217Sphk case SIOCGIFMEDIA: 168477217Sphk error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); 168577217Sphk break; 168646492Swpaul case SIOCADDMULTI: 168746492Swpaul case SIOCDELMULTI: 168846492Swpaul wi_setmulti(sc); 168946492Swpaul error = 0; 169046492Swpaul break; 169146492Swpaul case SIOCGWAVELAN: 169246492Swpaul error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); 169346492Swpaul if (error) 169446492Swpaul break; 169593833Simp if (wreq.wi_len > WI_MAX_DATALEN) { 169693833Simp error = EINVAL; 169793833Simp break; 169893833Simp } 169965581Swpaul /* Don't show WEP keys to non-root users. */ 170093593Sjhb if (wreq.wi_type == WI_RID_DEFLT_CRYPT_KEYS && suser(td)) 170165581Swpaul break; 170246492Swpaul if (wreq.wi_type == WI_RID_IFACE_STATS) { 170346492Swpaul bcopy((char *)&sc->wi_stats, (char *)&wreq.wi_val, 170446492Swpaul sizeof(sc->wi_stats)); 170546492Swpaul wreq.wi_len = (sizeof(sc->wi_stats) / 2) + 1; 170656965Swpaul } else if (wreq.wi_type == WI_RID_DEFLT_CRYPT_KEYS) { 170756965Swpaul bcopy((char *)&sc->wi_keys, (char *)&wreq, 170856965Swpaul sizeof(struct wi_ltv_keys)); 170953702Swpaul } 171053702Swpaul#ifdef WICACHE 171153702Swpaul else if (wreq.wi_type == WI_RID_ZERO_CACHE) { 171253702Swpaul sc->wi_sigitems = sc->wi_nextitem = 0; 171353702Swpaul } else if (wreq.wi_type == WI_RID_READ_CACHE) { 171453702Swpaul char *pt = (char *)&wreq.wi_val; 171553702Swpaul bcopy((char *)&sc->wi_sigitems, 171653702Swpaul (char *)pt, sizeof(int)); 171753702Swpaul pt += (sizeof (int)); 171853702Swpaul wreq.wi_len = sizeof(int) / 2; 171953702Swpaul bcopy((char *)&sc->wi_sigcache, (char *)pt, 172053702Swpaul sizeof(struct wi_sigcache) * sc->wi_sigitems); 172153702Swpaul wreq.wi_len += ((sizeof(struct wi_sigcache) * 172253702Swpaul sc->wi_sigitems) / 2) + 1; 172353702Swpaul } 172453702Swpaul#endif 172593359Simp else if (wreq.wi_type == WI_RID_PROCFRAME) { 172693359Simp wreq.wi_len = 2; 172793359Simp wreq.wi_val[0] = sc->wi_procframe; 172893359Simp } else if (wreq.wi_type == WI_RID_PRISM2) { 172993359Simp wreq.wi_len = 2; 173093733Simp wreq.wi_val[0] = sc->sc_firmware_type != WI_LUCENT; 173193733Simp } else if (wreq.wi_type == WI_RID_SCAN_RES && 173293733Simp sc->sc_firmware_type == WI_LUCENT) { 173393359Simp memcpy((char *)wreq.wi_val, (char *)sc->wi_scanbuf, 173493359Simp sc->wi_scanbuf_len * 2); 173593359Simp wreq.wi_len = sc->wi_scanbuf_len; 173693359Simp } else { 173746492Swpaul if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq)) { 173846492Swpaul error = EINVAL; 173946492Swpaul break; 174046492Swpaul } 174146492Swpaul } 174246492Swpaul error = copyout(&wreq, ifr->ifr_data, sizeof(wreq)); 174346492Swpaul break; 174446492Swpaul case SIOCSWAVELAN: 174593593Sjhb if ((error = suser(td))) 174661818Sroberto goto out; 174746492Swpaul error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); 174846492Swpaul if (error) 174946492Swpaul break; 175093833Simp if (wreq.wi_len > WI_MAX_DATALEN) { 175193833Simp error = EINVAL; 175293833Simp break; 175393833Simp } 175446492Swpaul if (wreq.wi_type == WI_RID_IFACE_STATS) { 175546492Swpaul error = EINVAL; 175646492Swpaul break; 175746492Swpaul } else if (wreq.wi_type == WI_RID_MGMT_XMIT) { 175846492Swpaul error = wi_mgmt_xmit(sc, (caddr_t)&wreq.wi_val, 175946492Swpaul wreq.wi_len); 176093359Simp } else if (wreq.wi_type == WI_RID_PROCFRAME) { 176193359Simp sc->wi_procframe = wreq.wi_val[0]; 176293359Simp /* 176393359Simp * if we're getting a scan request from a wavelan card 176493359Simp * (non-prism2), send out a cmd_inquire to the card to scan 176593359Simp * results for the scan will be received through the info 176693359Simp * interrupt handler. otherwise the scan request can be 176793359Simp * directly handled by a prism2 card's rid interface. 176893359Simp */ 176993733Simp } else if (wreq.wi_type == WI_RID_SCAN_REQ && 177093733Simp sc->sc_firmware_type == WI_LUCENT) { 177193359Simp wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_SCAN_RESULTS, 0, 0); 177246492Swpaul } else { 177346492Swpaul error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq); 177446492Swpaul if (!error) 177546492Swpaul wi_setdef(sc, &wreq); 177646492Swpaul } 177746492Swpaul break; 177893359Simp case SIOCGPRISM2DEBUG: 177993359Simp error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); 178093359Simp if (error) 178193359Simp break; 178293733Simp if (!(ifp->if_flags & IFF_RUNNING) || 178393733Simp sc->sc_firmware_type == WI_LUCENT) { 178493359Simp error = EIO; 178593359Simp break; 178693359Simp } 178793359Simp error = wi_get_debug(sc, &wreq); 178893359Simp if (error == 0) 178993359Simp error = copyout(&wreq, ifr->ifr_data, sizeof(wreq)); 179093359Simp break; 179193359Simp case SIOCSPRISM2DEBUG: 179293593Sjhb if ((error = suser(td))) 179393359Simp goto out; 179493359Simp error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); 179593359Simp if (error) 179693359Simp break; 179793359Simp error = wi_set_debug(sc, &wreq); 179893359Simp break; 179977217Sphk case SIOCG80211: 180077217Sphk switch(ireq->i_type) { 180177217Sphk case IEEE80211_IOC_SSID: 180277217Sphk if(ireq->i_val == -1) { 180377217Sphk bzero(tmpssid, IEEE80211_NWID_LEN); 180477217Sphk error = wi_get_cur_ssid(sc, tmpssid, &len); 180577217Sphk if (error != 0) 180677217Sphk break; 180777217Sphk error = copyout(tmpssid, ireq->i_data, 180877217Sphk IEEE80211_NWID_LEN); 180977217Sphk ireq->i_len = len; 181077217Sphk } else if (ireq->i_val == 0) { 181177217Sphk error = copyout(sc->wi_net_name, 181277217Sphk ireq->i_data, 181377217Sphk IEEE80211_NWID_LEN); 181477217Sphk ireq->i_len = IEEE80211_NWID_LEN; 181577217Sphk } else 181677217Sphk error = EINVAL; 181777217Sphk break; 181877217Sphk case IEEE80211_IOC_NUMSSIDS: 181977217Sphk ireq->i_val = 1; 182077217Sphk break; 182177217Sphk case IEEE80211_IOC_WEP: 182277217Sphk if(!sc->wi_has_wep) { 182377217Sphk ireq->i_val = IEEE80211_WEP_NOSUP; 182477217Sphk } else { 182577217Sphk if(sc->wi_use_wep) { 182677217Sphk ireq->i_val = 182777217Sphk IEEE80211_WEP_MIXED; 182877217Sphk } else { 182977217Sphk ireq->i_val = 183077217Sphk IEEE80211_WEP_OFF; 183177217Sphk } 183277217Sphk } 183377217Sphk break; 183477217Sphk case IEEE80211_IOC_WEPKEY: 183577217Sphk if(!sc->wi_has_wep || 183677217Sphk ireq->i_val < 0 || ireq->i_val > 3) { 183777217Sphk error = EINVAL; 183877217Sphk break; 183977217Sphk } 184077217Sphk len = sc->wi_keys.wi_keys[ireq->i_val].wi_keylen; 184193593Sjhb if (suser(td)) 184277217Sphk bcopy(sc->wi_keys.wi_keys[ireq->i_val].wi_keydat, 184377217Sphk tmpkey, len); 184477217Sphk else 184577217Sphk bzero(tmpkey, len); 184677217Sphk 184777217Sphk ireq->i_len = len; 184877217Sphk error = copyout(tmpkey, ireq->i_data, len); 184977217Sphk 185077217Sphk break; 185177217Sphk case IEEE80211_IOC_NUMWEPKEYS: 185277217Sphk if(!sc->wi_has_wep) 185377217Sphk error = EINVAL; 185477217Sphk else 185577217Sphk ireq->i_val = 4; 185677217Sphk break; 185777217Sphk case IEEE80211_IOC_WEPTXKEY: 185877217Sphk if(!sc->wi_has_wep) 185977217Sphk error = EINVAL; 186077217Sphk else 186177217Sphk ireq->i_val = sc->wi_tx_key; 186277217Sphk break; 186377217Sphk case IEEE80211_IOC_AUTHMODE: 186494405Simp ireq->i_val = sc->wi_authmode; 186577217Sphk break; 186677217Sphk case IEEE80211_IOC_STATIONNAME: 186777217Sphk error = copyout(sc->wi_node_name, 186877217Sphk ireq->i_data, IEEE80211_NWID_LEN); 186977217Sphk ireq->i_len = IEEE80211_NWID_LEN; 187077217Sphk break; 187177217Sphk case IEEE80211_IOC_CHANNEL: 187277217Sphk wreq.wi_type = WI_RID_CURRENT_CHAN; 187377217Sphk wreq.wi_len = WI_MAX_DATALEN; 187477217Sphk if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq)) 187577217Sphk error = EINVAL; 187677217Sphk else { 187777217Sphk ireq->i_val = wreq.wi_val[0]; 187877217Sphk } 187977217Sphk break; 188077217Sphk case IEEE80211_IOC_POWERSAVE: 188177217Sphk if(sc->wi_pm_enabled) 188277217Sphk ireq->i_val = IEEE80211_POWERSAVE_ON; 188377217Sphk else 188477217Sphk ireq->i_val = IEEE80211_POWERSAVE_OFF; 188577217Sphk break; 188677217Sphk case IEEE80211_IOC_POWERSAVESLEEP: 188777217Sphk ireq->i_val = sc->wi_max_sleep; 188877217Sphk break; 188977217Sphk default: 189077217Sphk error = EINVAL; 189177217Sphk } 189277217Sphk break; 189377217Sphk case SIOCS80211: 189493593Sjhb if ((error = suser(td))) 189577217Sphk goto out; 189677217Sphk switch(ireq->i_type) { 189777217Sphk case IEEE80211_IOC_SSID: 189877217Sphk if (ireq->i_val != 0 || 189977217Sphk ireq->i_len > IEEE80211_NWID_LEN) { 190077217Sphk error = EINVAL; 190177217Sphk break; 190277217Sphk } 190377217Sphk /* We set both of them */ 190477217Sphk bzero(sc->wi_net_name, IEEE80211_NWID_LEN); 190577217Sphk error = copyin(ireq->i_data, 190677217Sphk sc->wi_net_name, ireq->i_len); 190777217Sphk bcopy(sc->wi_net_name, sc->wi_ibss_name, IEEE80211_NWID_LEN); 190877217Sphk break; 190977217Sphk case IEEE80211_IOC_WEP: 191077217Sphk /* 191177217Sphk * These cards only support one mode so 191277217Sphk * we just turn wep on what ever is 191377217Sphk * passed in if it's not OFF. 191477217Sphk */ 191577217Sphk if (ireq->i_val == IEEE80211_WEP_OFF) { 191677217Sphk sc->wi_use_wep = 0; 191777217Sphk } else { 191877217Sphk sc->wi_use_wep = 1; 191977217Sphk } 192077217Sphk break; 192177217Sphk case IEEE80211_IOC_WEPKEY: 192277217Sphk if (ireq->i_val < 0 || ireq->i_val > 3 || 192377217Sphk ireq->i_len > 13) { 192477217Sphk error = EINVAL; 192577217Sphk break; 192677217Sphk } 192777217Sphk bzero(sc->wi_keys.wi_keys[ireq->i_val].wi_keydat, 13); 192877217Sphk error = copyin(ireq->i_data, 192977217Sphk sc->wi_keys.wi_keys[ireq->i_val].wi_keydat, 193077217Sphk ireq->i_len); 193177217Sphk if(error) 193277217Sphk break; 193377217Sphk sc->wi_keys.wi_keys[ireq->i_val].wi_keylen = 193477217Sphk ireq->i_len; 193577217Sphk break; 193677217Sphk case IEEE80211_IOC_WEPTXKEY: 193777217Sphk if (ireq->i_val < 0 || ireq->i_val > 3) { 193877217Sphk error = EINVAL; 193977217Sphk break; 194077217Sphk } 194177217Sphk sc->wi_tx_key = ireq->i_val; 194277217Sphk break; 194377217Sphk case IEEE80211_IOC_AUTHMODE: 194494405Simp sc->wi_authmode = ireq->i_val; 194577217Sphk break; 194677217Sphk case IEEE80211_IOC_STATIONNAME: 194777217Sphk if (ireq->i_len > 32) { 194877217Sphk error = EINVAL; 194977217Sphk break; 195077217Sphk } 195177217Sphk bzero(sc->wi_node_name, 32); 195277217Sphk error = copyin(ireq->i_data, 195377217Sphk sc->wi_node_name, ireq->i_len); 195477217Sphk break; 195577217Sphk case IEEE80211_IOC_CHANNEL: 195677217Sphk /* 195777217Sphk * The actual range is 1-14, but if you 195877217Sphk * set it to 0 you get the default. So 195977217Sphk * we let that work too. 196077217Sphk */ 196177217Sphk if (ireq->i_val < 0 || ireq->i_val > 14) { 196277217Sphk error = EINVAL; 196377217Sphk break; 196477217Sphk } 196577217Sphk sc->wi_channel = ireq->i_val; 196677217Sphk break; 196777217Sphk case IEEE80211_IOC_POWERSAVE: 196877217Sphk switch (ireq->i_val) { 196977217Sphk case IEEE80211_POWERSAVE_OFF: 197077217Sphk sc->wi_pm_enabled = 0; 197177217Sphk break; 197277217Sphk case IEEE80211_POWERSAVE_ON: 197377217Sphk sc->wi_pm_enabled = 1; 197477217Sphk break; 197577217Sphk default: 197677217Sphk error = EINVAL; 197777217Sphk break; 197877217Sphk } 197977217Sphk break; 198077217Sphk case IEEE80211_IOC_POWERSAVESLEEP: 198177217Sphk if (ireq->i_val < 0) { 198277217Sphk error = EINVAL; 198377217Sphk break; 198477217Sphk } 198577217Sphk sc->wi_max_sleep = ireq->i_val; 198677217Sphk break; 198777217Sphk default: 198877217Sphk error = EINVAL; 198977217Sphk break; 199077217Sphk } 199177217Sphk 199277217Sphk /* Reinitialize WaveLAN. */ 199377217Sphk wi_init(sc); 199477217Sphk 199594405Simp break; 199694405Simp case SIOCHOSTAP_ADD: 199794405Simp case SIOCHOSTAP_DEL: 199894405Simp case SIOCHOSTAP_GET: 199994405Simp case SIOCHOSTAP_GETALL: 200094405Simp case SIOCHOSTAP_GFLAGS: 200194405Simp case SIOCHOSTAP_SFLAGS: 200294405Simp /* Send all Host AP specific ioctl's to Host AP code. */ 200394405Simp error = wihap_ioctl(sc, command, data); 200477217Sphk break; 200546492Swpaul default: 200646492Swpaul error = EINVAL; 200746492Swpaul break; 200846492Swpaul } 200961818Srobertoout: 201095534Simp WI_UNLOCK(sc, s); 201146492Swpaul 201246492Swpaul return(error); 201346492Swpaul} 201446492Swpaul 201588546Salfredstatic void 201688546Salfredwi_init(xsc) 201746492Swpaul void *xsc; 201846492Swpaul{ 201946492Swpaul struct wi_softc *sc = xsc; 202046492Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 202146492Swpaul struct wi_ltv_macaddr mac; 202246492Swpaul int id = 0; 202395534Simp int s; 202446492Swpaul 202595534Simp WI_LOCK(sc, s); 202667092Swpaul 202767092Swpaul if (sc->wi_gone) { 202895534Simp WI_UNLOCK(sc, s); 202946492Swpaul return; 203067092Swpaul } 203146492Swpaul 203246492Swpaul if (ifp->if_flags & IFF_RUNNING) 203346492Swpaul wi_stop(sc); 203446492Swpaul 203546492Swpaul wi_reset(sc); 203646492Swpaul 203746492Swpaul /* Program max data length. */ 203846492Swpaul WI_SETVAL(WI_RID_MAX_DATALEN, sc->wi_max_data_len); 203946492Swpaul 204098440Simp /* Set the port type. */ 204198440Simp WI_SETVAL(WI_RID_PORTTYPE, sc->wi_ptype); 204298440Simp 204347401Swpaul /* Enable/disable IBSS creation. */ 204446492Swpaul WI_SETVAL(WI_RID_CREATE_IBSS, sc->wi_create_ibss); 204546492Swpaul 204646492Swpaul /* Program the RTS/CTS threshold. */ 204746492Swpaul WI_SETVAL(WI_RID_RTS_THRESH, sc->wi_rts_thresh); 204846492Swpaul 204946492Swpaul /* Program the TX rate */ 205046492Swpaul WI_SETVAL(WI_RID_TX_RATE, sc->wi_tx_rate); 205146492Swpaul 205246492Swpaul /* Access point density */ 205346492Swpaul WI_SETVAL(WI_RID_SYSTEM_SCALE, sc->wi_ap_density); 205446492Swpaul 205546611Swpaul /* Power Management Enabled */ 205646611Swpaul WI_SETVAL(WI_RID_PM_ENABLED, sc->wi_pm_enabled); 205746611Swpaul 205846611Swpaul /* Power Managment Max Sleep */ 205946611Swpaul WI_SETVAL(WI_RID_MAX_SLEEP, sc->wi_max_sleep); 206046611Swpaul 206191695Simp /* Roaming type */ 206291695Simp WI_SETVAL(WI_RID_ROAMING_MODE, sc->wi_roaming); 206391695Simp 206446492Swpaul /* Specify the IBSS name */ 206546492Swpaul WI_SETSTR(WI_RID_OWN_SSID, sc->wi_ibss_name); 206646492Swpaul 206746492Swpaul /* Specify the network name */ 206846492Swpaul WI_SETSTR(WI_RID_DESIRED_SSID, sc->wi_net_name); 206946492Swpaul 207046563Swpaul /* Specify the frequency to use */ 207146563Swpaul WI_SETVAL(WI_RID_OWN_CHNL, sc->wi_channel); 207246563Swpaul 207346492Swpaul /* Program the nodename. */ 207446492Swpaul WI_SETSTR(WI_RID_NODENAME, sc->wi_node_name); 207546492Swpaul 207694405Simp /* Specify the authentication mode. */ 207794405Simp WI_SETVAL(WI_RID_CNFAUTHMODE, sc->wi_authmode); 207894405Simp 207946492Swpaul /* Set our MAC address. */ 208046492Swpaul mac.wi_len = 4; 208146492Swpaul mac.wi_type = WI_RID_MAC_NODE; 208246492Swpaul bcopy((char *)&sc->arpcom.ac_enaddr, 208346492Swpaul (char *)&mac.wi_mac_addr, ETHER_ADDR_LEN); 208446492Swpaul wi_write_record(sc, (struct wi_ltv_gen *)&mac); 208546492Swpaul 2086100876Simp /* 2087100876Simp * Initialize promisc mode. 2088100876Simp * Being in the Host-AP mode causes 2089100876Simp * great deal of pain if promisc mode is set. 2090100876Simp * Therefore we avoid confusing the firmware 2091100876Simp * and always reset promisc mode in Host-AP regime, 2092100876Simp * it shows us all the packets anyway. 2093100876Simp */ 2094100876Simp /* 2095100876Simp * Can't do promisc and hostap at the same time. 2096100876Simp */ 2097100876Simp if (sc->wi_ptype == WI_PORTTYPE_AP) 2098100876Simp ifp->if_flags &= ~IFF_PROMISC; 2099100876Simp if (ifp->if_flags & IFF_PROMISC) 2100100876Simp WI_SETVAL(WI_RID_PROMISC, 1); 2101100876Simp else 2102100876Simp WI_SETVAL(WI_RID_PROMISC, 0); 2103100876Simp 210456965Swpaul /* Configure WEP. */ 210556965Swpaul if (sc->wi_has_wep) { 210656965Swpaul WI_SETVAL(WI_RID_ENCRYPTION, sc->wi_use_wep); 210756965Swpaul WI_SETVAL(WI_RID_TX_CRYPT_KEY, sc->wi_tx_key); 210856965Swpaul sc->wi_keys.wi_len = (sizeof(struct wi_ltv_keys) / 2) + 1; 210956965Swpaul sc->wi_keys.wi_type = WI_RID_DEFLT_CRYPT_KEYS; 211056965Swpaul wi_write_record(sc, (struct wi_ltv_gen *)&sc->wi_keys); 211193733Simp if (sc->sc_firmware_type != WI_LUCENT && sc->wi_use_wep) { 211291695Simp /* 211391695Simp * ONLY HWB3163 EVAL-CARD Firmware version 211493733Simp * less than 0.8 variant2 211591695Simp * 2116100876Simp * If promiscuous mode disable, Prism2 chip 2117100876Simp * does not work with WEP. 211891695Simp * It is under investigation for details. 211991695Simp * (ichiro@netbsd.org) 2120100876Simp * 2121100876Simp * And make sure that we don't need to do it 2122100876Simp * in hostap mode, since it interferes with 2123100876Simp * the above hostap workaround. 212491695Simp */ 2125100876Simp if (sc->wi_ptype != WI_PORTTYPE_AP && 2126100876Simp sc->sc_firmware_type == WI_INTERSIL && 212793733Simp sc->sc_sta_firmware_ver < 802 ) { 212893733Simp /* firm ver < 0.8 variant 2 */ 212991695Simp WI_SETVAL(WI_RID_PROMISC, 1); 213091695Simp } 213194405Simp WI_SETVAL(WI_RID_CNFAUTHMODE, sc->wi_authtype); 213291695Simp } 213356965Swpaul } 213456965Swpaul 213546492Swpaul /* Set multicast filter. */ 213646492Swpaul wi_setmulti(sc); 213746492Swpaul 213846492Swpaul /* Enable desired port */ 213992457Simp wi_cmd(sc, WI_CMD_ENABLE | sc->wi_portnum, 0, 0, 0); 214046492Swpaul 214175373Salfred if (wi_alloc_nicmem(sc, ETHER_MAX_LEN + sizeof(struct wi_frame) + 8, &id)) 214253702Swpaul device_printf(sc->dev, "tx buffer allocation failed\n"); 214346492Swpaul sc->wi_tx_data_id = id; 214446492Swpaul 214575373Salfred if (wi_alloc_nicmem(sc, ETHER_MAX_LEN + sizeof(struct wi_frame) + 8, &id)) 214653702Swpaul device_printf(sc->dev, "mgmt. buffer allocation failed\n"); 214746492Swpaul sc->wi_tx_mgmt_id = id; 214846492Swpaul 214946492Swpaul /* enable interrupts */ 215046492Swpaul CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS); 215146492Swpaul 215294405Simp wihap_init(sc); 215394405Simp 215446492Swpaul ifp->if_flags |= IFF_RUNNING; 215546492Swpaul ifp->if_flags &= ~IFF_OACTIVE; 215646492Swpaul 215746492Swpaul sc->wi_stat_ch = timeout(wi_inquire, sc, hz * 60); 215895534Simp WI_UNLOCK(sc, s); 215946492Swpaul 216046492Swpaul return; 216146492Swpaul} 216246492Swpaul 216394472Simp#define RC4STATE 256 216494472Simp#define RC4KEYLEN 16 216594472Simp#define RC4SWAP(x,y) \ 216694472Simp do { u_int8_t t = state[x]; state[x] = state[y]; state[y] = t; } while(0) 216794405Simp 216888546Salfredstatic void 216994405Simpwi_do_hostencrypt(struct wi_softc *sc, caddr_t buf, int len) 217094405Simp{ 217194472Simp u_int32_t i, crc, klen; 217294472Simp u_int8_t state[RC4STATE], key[RC4KEYLEN]; 217394472Simp u_int8_t x, y, *dat; 217494405Simp 217594472Simp if (!sc->wi_icv_flag) { 217694472Simp sc->wi_icv = arc4random(); 217794472Simp sc->wi_icv_flag++; 217894472Simp } else 217994472Simp sc->wi_icv++; 218094472Simp /* 218194472Simp * Skip 'bad' IVs from Fluhrer/Mantin/Shamir: 218294472Simp * (B, 255, N) with 3 <= B < 8 218394472Simp */ 218494472Simp if (sc->wi_icv >= 0x03ff00 && 218594472Simp (sc->wi_icv & 0xf8ff00) == 0x00ff00) 218694472Simp sc->wi_icv += 0x000100; 218794405Simp 218894472Simp /* prepend 24bit IV to tx key, byte order does not matter */ 218994472Simp key[0] = sc->wi_icv >> 16; 219094472Simp key[1] = sc->wi_icv >> 8; 219194472Simp key[2] = sc->wi_icv; 219294405Simp 219394472Simp klen = sc->wi_keys.wi_keys[sc->wi_tx_key].wi_keylen + 219494472Simp IEEE80211_WEP_IVLEN; 219594472Simp klen = (klen >= RC4KEYLEN) ? RC4KEYLEN : RC4KEYLEN/2; 219694472Simp bcopy((char *)&sc->wi_keys.wi_keys[sc->wi_tx_key].wi_keydat, 219794472Simp (char *)key + IEEE80211_WEP_IVLEN, klen - IEEE80211_WEP_IVLEN); 219894405Simp 219994472Simp /* rc4 keysetup */ 220094472Simp x = y = 0; 220194472Simp for (i = 0; i < RC4STATE; i++) 220294472Simp state[i] = i; 220394472Simp for (i = 0; i < RC4STATE; i++) { 220494472Simp y = (key[x] + state[i] + y) % RC4STATE; 220594472Simp RC4SWAP(i, y); 220694472Simp x = (x + 1) % klen; 220794405Simp } 220894405Simp 220994472Simp /* output: IV, tx keyid, rc4(data), rc4(crc32(data)) */ 221094472Simp dat = buf; 221194472Simp dat[0] = key[0]; 221294472Simp dat[1] = key[1]; 221394472Simp dat[2] = key[2]; 221494472Simp dat[3] = sc->wi_tx_key << 6; /* pad and keyid */ 221594472Simp dat += 4; 221694472Simp 221794472Simp /* compute rc4 over data, crc32 over data */ 221894472Simp crc = ~0; 221994472Simp x = y = 0; 222094472Simp for (i = 0; i < len; i++) { 222194472Simp x = (x + 1) % RC4STATE; 222294472Simp y = (state[x] + y) % RC4STATE; 222394472Simp RC4SWAP(x, y); 222494472Simp crc = crc32_tab[(crc ^ dat[i]) & 0xff] ^ (crc >> 8); 222594472Simp dat[i] ^= state[(state[x] + state[y]) % RC4STATE]; 222694405Simp } 222794472Simp crc = ~crc; 222894472Simp dat += len; 222994405Simp 223094472Simp /* append little-endian crc32 and encrypt */ 223194472Simp dat[0] = crc; 223294472Simp dat[1] = crc >> 8; 223394472Simp dat[2] = crc >> 16; 223494472Simp dat[3] = crc >> 24; 223594472Simp for (i = 0; i < IEEE80211_WEP_CRCLEN; i++) { 223694472Simp x = (x + 1) % RC4STATE; 223794472Simp y = (state[x] + y) % RC4STATE; 223894472Simp RC4SWAP(x, y); 223994472Simp dat[i] ^= state[(state[x] + state[y]) % RC4STATE]; 224094405Simp } 224194405Simp} 224294405Simp 224394405Simpstatic void 224488546Salfredwi_start(ifp) 224546492Swpaul struct ifnet *ifp; 224646492Swpaul{ 224746492Swpaul struct wi_softc *sc; 224846492Swpaul struct mbuf *m0; 224946492Swpaul struct wi_frame tx_frame; 225046492Swpaul struct ether_header *eh; 225146492Swpaul int id; 225295534Simp int s; 225346492Swpaul 225446492Swpaul sc = ifp->if_softc; 225595534Simp WI_LOCK(sc, s); 225646492Swpaul 225767092Swpaul if (sc->wi_gone) { 225895534Simp WI_UNLOCK(sc, s); 225946492Swpaul return; 226067092Swpaul } 226146492Swpaul 226267092Swpaul if (ifp->if_flags & IFF_OACTIVE) { 226395534Simp WI_UNLOCK(sc, s); 226446492Swpaul return; 226567092Swpaul } 226646492Swpaul 226794405Simpnextpkt: 226846492Swpaul IF_DEQUEUE(&ifp->if_snd, m0); 226967092Swpaul if (m0 == NULL) { 227095534Simp WI_UNLOCK(sc, s); 227146492Swpaul return; 227267092Swpaul } 227346492Swpaul 227446492Swpaul bzero((char *)&tx_frame, sizeof(tx_frame)); 227594405Simp tx_frame.wi_frame_ctl = htole16(WI_FTYPE_DATA); 227646492Swpaul id = sc->wi_tx_data_id; 227746492Swpaul eh = mtod(m0, struct ether_header *); 227846492Swpaul 227994405Simp if (sc->wi_ptype == WI_PORTTYPE_AP) { 228094405Simp if (!wihap_check_tx(&sc->wi_hostap_info, 228194405Simp eh->ether_dhost, &tx_frame.wi_tx_rate)) { 228294405Simp if (ifp->if_flags & IFF_DEBUG) 228394405Simp printf("wi_start: dropping unassoc " 228494405Simp "dst %6D\n", eh->ether_dhost, ":"); 228594405Simp m_freem(m0); 228694405Simp goto nextpkt; 228794405Simp } 228894405Simp } 228946492Swpaul /* 229047401Swpaul * Use RFC1042 encoding for IP and ARP datagrams, 229146492Swpaul * 802.3 for anything else. 229246492Swpaul */ 229375275Salfred if (ntohs(eh->ether_type) > ETHER_MAX_LEN) { 229446492Swpaul bcopy((char *)&eh->ether_dhost, 229546492Swpaul (char *)&tx_frame.wi_addr1, ETHER_ADDR_LEN); 229694405Simp if (sc->wi_ptype == WI_PORTTYPE_AP) { 229794405Simp tx_frame.wi_tx_ctl = WI_ENC_TX_MGMT; /* XXX */ 229894405Simp tx_frame.wi_frame_ctl |= WI_FCTL_FROMDS; 229994405Simp if (sc->wi_use_wep) 230094405Simp tx_frame.wi_frame_ctl |= WI_FCTL_WEP; 230194405Simp bcopy((char *)&sc->arpcom.ac_enaddr, 230294405Simp (char *)&tx_frame.wi_addr2, ETHER_ADDR_LEN); 230394405Simp bcopy((char *)&eh->ether_shost, 230494405Simp (char *)&tx_frame.wi_addr3, ETHER_ADDR_LEN); 230594405Simp } 230694405Simp else 230794405Simp bcopy((char *)&eh->ether_shost, 230894405Simp (char *)&tx_frame.wi_addr2, ETHER_ADDR_LEN); 230946492Swpaul bcopy((char *)&eh->ether_dhost, 231046492Swpaul (char *)&tx_frame.wi_dst_addr, ETHER_ADDR_LEN); 231146492Swpaul bcopy((char *)&eh->ether_shost, 231246492Swpaul (char *)&tx_frame.wi_src_addr, ETHER_ADDR_LEN); 231346492Swpaul 231446492Swpaul tx_frame.wi_dat_len = m0->m_pkthdr.len - WI_SNAPHDR_LEN; 231546492Swpaul tx_frame.wi_dat[0] = htons(WI_SNAP_WORD0); 231646492Swpaul tx_frame.wi_dat[1] = htons(WI_SNAP_WORD1); 231746492Swpaul tx_frame.wi_len = htons(m0->m_pkthdr.len - WI_SNAPHDR_LEN); 231846492Swpaul tx_frame.wi_type = eh->ether_type; 231946492Swpaul 232094405Simp if (sc->wi_ptype == WI_PORTTYPE_AP && sc->wi_use_wep) { 232194405Simp /* Do host encryption. */ 232294405Simp bcopy(&tx_frame.wi_dat[0], &sc->wi_txbuf[4], 8); 232394405Simp m_copydata(m0, sizeof(struct ether_header), 232494405Simp m0->m_pkthdr.len - sizeof(struct ether_header), 232594405Simp (caddr_t)&sc->wi_txbuf[12]); 232694405Simp wi_do_hostencrypt(sc, &sc->wi_txbuf[0], 232794405Simp tx_frame.wi_dat_len); 232894472Simp tx_frame.wi_dat_len += IEEE80211_WEP_IVLEN + 232994472Simp IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN; 233094405Simp wi_write_data(sc, id, 0, (caddr_t)&tx_frame, 233194405Simp sizeof(struct wi_frame)); 233294405Simp wi_write_data(sc, id, WI_802_11_OFFSET_RAW, 233394405Simp (caddr_t)&sc->wi_txbuf, (m0->m_pkthdr.len - 233494405Simp sizeof(struct ether_header)) + 18); 233594486Simp } else { 233694405Simp m_copydata(m0, sizeof(struct ether_header), 233794405Simp m0->m_pkthdr.len - sizeof(struct ether_header), 233894405Simp (caddr_t)&sc->wi_txbuf); 233994405Simp wi_write_data(sc, id, 0, (caddr_t)&tx_frame, 234094405Simp sizeof(struct wi_frame)); 234194405Simp wi_write_data(sc, id, WI_802_11_OFFSET, 234294405Simp (caddr_t)&sc->wi_txbuf, (m0->m_pkthdr.len - 234394405Simp sizeof(struct ether_header)) + 2); 234494405Simp } 234546492Swpaul } else { 234646492Swpaul tx_frame.wi_dat_len = m0->m_pkthdr.len; 234746492Swpaul 234894405Simp if (sc->wi_ptype == WI_PORTTYPE_AP && sc->wi_use_wep) { 234994405Simp /* Do host encryption. */ 235094405Simp printf( "XXX: host encrypt not implemented for 802.3\n" ); 235194486Simp } else { 235294405Simp eh->ether_type = htons(m0->m_pkthdr.len - 235394405Simp WI_SNAPHDR_LEN); 235494405Simp m_copydata(m0, 0, m0->m_pkthdr.len, 235594405Simp (caddr_t)&sc->wi_txbuf); 235646492Swpaul 235794405Simp wi_write_data(sc, id, 0, (caddr_t)&tx_frame, 235894405Simp sizeof(struct wi_frame)); 235994405Simp wi_write_data(sc, id, WI_802_3_OFFSET, 236094405Simp (caddr_t)&sc->wi_txbuf, m0->m_pkthdr.len + 2); 236194405Simp } 236246492Swpaul } 236346492Swpaul 236446492Swpaul /* 236546492Swpaul * If there's a BPF listner, bounce a copy of 236693359Simp * this frame to him. Also, don't send this to the bpf sniffer 236793359Simp * if we're in procframe or monitor sniffing mode. 236846492Swpaul */ 236993359Simp if (!(sc->wi_procframe || sc->wi_debug.wi_monitor) && ifp->if_bpf) 237046492Swpaul bpf_mtap(ifp, m0); 237146492Swpaul 237246492Swpaul m_freem(m0); 237346492Swpaul 237492457Simp if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0)) 237553702Swpaul device_printf(sc->dev, "xmit failed\n"); 237646492Swpaul 237746492Swpaul ifp->if_flags |= IFF_OACTIVE; 237846492Swpaul 237946492Swpaul /* 238046492Swpaul * Set a timeout in case the chip goes out to lunch. 238146492Swpaul */ 238246492Swpaul ifp->if_timer = 5; 238346492Swpaul 238495534Simp WI_UNLOCK(sc, s); 238546492Swpaul return; 238646492Swpaul} 238746492Swpaul 238894405Simpint 238988546Salfredwi_mgmt_xmit(sc, data, len) 239046492Swpaul struct wi_softc *sc; 239146492Swpaul caddr_t data; 239246492Swpaul int len; 239346492Swpaul{ 239446492Swpaul struct wi_frame tx_frame; 239546492Swpaul int id; 239646492Swpaul struct wi_80211_hdr *hdr; 239746492Swpaul caddr_t dptr; 239846492Swpaul 239946492Swpaul if (sc->wi_gone) 240046492Swpaul return(ENODEV); 240146492Swpaul 240246492Swpaul hdr = (struct wi_80211_hdr *)data; 240346492Swpaul dptr = data + sizeof(struct wi_80211_hdr); 240446492Swpaul 240546492Swpaul bzero((char *)&tx_frame, sizeof(tx_frame)); 240646492Swpaul id = sc->wi_tx_mgmt_id; 240746492Swpaul 240846492Swpaul bcopy((char *)hdr, (char *)&tx_frame.wi_frame_ctl, 240946492Swpaul sizeof(struct wi_80211_hdr)); 241046492Swpaul 241194405Simp tx_frame.wi_tx_ctl = WI_ENC_TX_MGMT; 241294405Simp tx_frame.wi_dat_len = len - sizeof(struct wi_80211_hdr); 241394405Simp tx_frame.wi_len = htons(tx_frame.wi_dat_len); 241446492Swpaul 241546492Swpaul wi_write_data(sc, id, 0, (caddr_t)&tx_frame, sizeof(struct wi_frame)); 241646492Swpaul wi_write_data(sc, id, WI_802_11_OFFSET_RAW, dptr, 241794405Simp len - sizeof(struct wi_80211_hdr) + 2); 241846492Swpaul 241992457Simp if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0)) { 242053702Swpaul device_printf(sc->dev, "xmit failed\n"); 242146492Swpaul return(EIO); 242246492Swpaul } 242346492Swpaul 242446492Swpaul return(0); 242546492Swpaul} 242646492Swpaul 242788546Salfredstatic void 242888546Salfredwi_stop(sc) 242946492Swpaul struct wi_softc *sc; 243046492Swpaul{ 243146492Swpaul struct ifnet *ifp; 243295534Simp int s; 243346492Swpaul 243495534Simp WI_LOCK(sc, s); 243567092Swpaul 243667092Swpaul if (sc->wi_gone) { 243795534Simp WI_UNLOCK(sc, s); 243846492Swpaul return; 243967092Swpaul } 244046492Swpaul 244194405Simp wihap_shutdown(sc); 244294405Simp 244346492Swpaul ifp = &sc->arpcom.ac_if; 244446492Swpaul 244570173Sjhb /* 244670173Sjhb * If the card is gone and the memory port isn't mapped, we will 244770173Sjhb * (hopefully) get 0xffff back from the status read, which is not 244870173Sjhb * a valid status value. 244970173Sjhb */ 245070173Sjhb if (CSR_READ_2(sc, WI_STATUS) != 0xffff) { 245170173Sjhb CSR_WRITE_2(sc, WI_INT_EN, 0); 245292457Simp wi_cmd(sc, WI_CMD_DISABLE|sc->wi_portnum, 0, 0, 0); 245370173Sjhb } 245446492Swpaul 245546492Swpaul untimeout(wi_inquire, sc, sc->wi_stat_ch); 245646492Swpaul 245746492Swpaul ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); 245846492Swpaul 245995534Simp WI_UNLOCK(sc, s); 246046492Swpaul return; 246146492Swpaul} 246246492Swpaul 246388546Salfredstatic void 246488546Salfredwi_watchdog(ifp) 246546492Swpaul struct ifnet *ifp; 246646492Swpaul{ 246746492Swpaul struct wi_softc *sc; 246846492Swpaul 246946492Swpaul sc = ifp->if_softc; 247046492Swpaul 247175199Salfred device_printf(sc->dev, "watchdog timeout\n"); 247246492Swpaul 247346492Swpaul wi_init(sc); 247446492Swpaul 247546492Swpaul ifp->if_oerrors++; 247646492Swpaul 247746492Swpaul return; 247846492Swpaul} 247946492Swpaul 248093611Simpint 248190580Sbrookswi_alloc(dev, rid) 248253702Swpaul device_t dev; 248390580Sbrooks int rid; 248446492Swpaul{ 248553702Swpaul struct wi_softc *sc = device_get_softc(dev); 248653702Swpaul 248790580Sbrooks if (sc->wi_bus_type != WI_BUS_PCI_NATIVE) { 248890580Sbrooks sc->iobase_rid = rid; 248990580Sbrooks sc->iobase = bus_alloc_resource(dev, SYS_RES_IOPORT, 249090580Sbrooks &sc->iobase_rid, 0, ~0, (1 << 6), 249190580Sbrooks rman_make_alignment_flags(1 << 6) | RF_ACTIVE); 249290580Sbrooks if (!sc->iobase) { 249390580Sbrooks device_printf(dev, "No I/O space?!\n"); 249490580Sbrooks return (ENXIO); 249590580Sbrooks } 249690580Sbrooks 249790580Sbrooks sc->wi_io_addr = rman_get_start(sc->iobase); 249890580Sbrooks sc->wi_btag = rman_get_bustag(sc->iobase); 249990580Sbrooks sc->wi_bhandle = rman_get_bushandle(sc->iobase); 250090580Sbrooks } else { 250190580Sbrooks sc->mem_rid = rid; 250290580Sbrooks sc->mem = bus_alloc_resource(dev, SYS_RES_MEMORY, 250390580Sbrooks &sc->mem_rid, 0, ~0, 1, RF_ACTIVE); 250490580Sbrooks 250590580Sbrooks if (!sc->mem) { 250690580Sbrooks device_printf(dev, "No Mem space on prism2.5?\n"); 250790580Sbrooks return (ENXIO); 250890580Sbrooks } 250990580Sbrooks 251090580Sbrooks sc->wi_btag = rman_get_bustag(sc->mem); 251190580Sbrooks sc->wi_bhandle = rman_get_bushandle(sc->mem); 251253702Swpaul } 251353702Swpaul 251490580Sbrooks 251574906Salfred sc->irq_rid = 0; 251674906Salfred sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_rid, 251790580Sbrooks 0, ~0, 1, RF_ACTIVE | 251890580Sbrooks ((sc->wi_bus_type == WI_BUS_PCCARD) ? 0 : RF_SHAREABLE)); 251990580Sbrooks 252053702Swpaul if (!sc->irq) { 252175219Salfred wi_free(dev); 252253702Swpaul device_printf(dev, "No irq?!\n"); 252353702Swpaul return (ENXIO); 252453702Swpaul } 252553702Swpaul 252653702Swpaul sc->dev = dev; 252753702Swpaul sc->wi_unit = device_get_unit(dev); 252853702Swpaul 252953702Swpaul return (0); 253053702Swpaul} 253153702Swpaul 253293611Simpvoid 253388546Salfredwi_free(dev) 253453702Swpaul device_t dev; 253553702Swpaul{ 253653702Swpaul struct wi_softc *sc = device_get_softc(dev); 253753702Swpaul 253875219Salfred if (sc->iobase != NULL) { 253975219Salfred bus_release_resource(dev, SYS_RES_IOPORT, sc->iobase_rid, sc->iobase); 254075219Salfred sc->iobase = NULL; 254175219Salfred } 254275219Salfred if (sc->irq != NULL) { 254375219Salfred bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq); 254475219Salfred sc->irq = NULL; 254575219Salfred } 254675219Salfred if (sc->mem != NULL) { 254774906Salfred bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem); 254875219Salfred sc->mem = NULL; 254975219Salfred } 255053702Swpaul 255153702Swpaul return; 255253702Swpaul} 255353702Swpaul 255493611Simpvoid 255588546Salfredwi_shutdown(dev) 255653702Swpaul device_t dev; 255753702Swpaul{ 255846492Swpaul struct wi_softc *sc; 255946492Swpaul 256053702Swpaul sc = device_get_softc(dev); 256146492Swpaul wi_stop(sc); 256246492Swpaul 256346492Swpaul return; 256446492Swpaul} 256553702Swpaul 256653702Swpaul#ifdef WICACHE 256753702Swpaul/* wavelan signal strength cache code. 256853702Swpaul * store signal/noise/quality on per MAC src basis in 256953702Swpaul * a small fixed cache. The cache wraps if > MAX slots 257053702Swpaul * used. The cache may be zeroed out to start over. 257153702Swpaul * Two simple filters exist to reduce computation: 257253702Swpaul * 1. ip only (literally 0x800) which may be used 257353702Swpaul * to ignore some packets. It defaults to ip only. 257453702Swpaul * it could be used to focus on broadcast, non-IP 802.11 beacons. 257553702Swpaul * 2. multicast/broadcast only. This may be used to 257653702Swpaul * ignore unicast packets and only cache signal strength 257753702Swpaul * for multicast/broadcast packets (beacons); e.g., Mobile-IP 257853702Swpaul * beacons and not unicast traffic. 257953702Swpaul * 258053702Swpaul * The cache stores (MAC src(index), IP src (major clue), signal, 258153702Swpaul * quality, noise) 258253702Swpaul * 258353702Swpaul * No apologies for storing IP src here. It's easy and saves much 258453702Swpaul * trouble elsewhere. The cache is assumed to be INET dependent, 258553702Swpaul * although it need not be. 258653702Swpaul */ 258753702Swpaul 258853702Swpaul#ifdef documentation 258953702Swpaul 259053702Swpaulint wi_sigitems; /* number of cached entries */ 259153702Swpaulstruct wi_sigcache wi_sigcache[MAXWICACHE]; /* array of cache entries */ 259253702Swpaulint wi_nextitem; /* index/# of entries */ 259353702Swpaul 259453702Swpaul 259553702Swpaul#endif 259653702Swpaul 259753702Swpaul/* control variables for cache filtering. Basic idea is 259853702Swpaul * to reduce cost (e.g., to only Mobile-IP agent beacons 259953702Swpaul * which are broadcast or multicast). Still you might 260053702Swpaul * want to measure signal strength with unicast ping packets 260153702Swpaul * on a pt. to pt. ant. setup. 260253702Swpaul */ 260353702Swpaul/* set true if you want to limit cache items to broadcast/mcast 260453702Swpaul * only packets (not unicast). Useful for mobile-ip beacons which 260553702Swpaul * are broadcast/multicast at network layer. Default is all packets 260653702Swpaul * so ping/unicast will work say with pt. to pt. antennae setup. 260753702Swpaul */ 260853702Swpaulstatic int wi_cache_mcastonly = 0; 260953702SwpaulSYSCTL_INT(_machdep, OID_AUTO, wi_cache_mcastonly, CTLFLAG_RW, 261053702Swpaul &wi_cache_mcastonly, 0, ""); 261153702Swpaul 261253702Swpaul/* set true if you want to limit cache items to IP packets only 261353702Swpaul*/ 261453702Swpaulstatic int wi_cache_iponly = 1; 261553702SwpaulSYSCTL_INT(_machdep, OID_AUTO, wi_cache_iponly, CTLFLAG_RW, 261653702Swpaul &wi_cache_iponly, 0, ""); 261753702Swpaul 261853702Swpaul/* 261953702Swpaul * Original comments: 262053702Swpaul * ----------------- 262153702Swpaul * wi_cache_store, per rx packet store signal 262253702Swpaul * strength in MAC (src) indexed cache. 262353702Swpaul * 262453702Swpaul * follows linux driver in how signal strength is computed. 262553702Swpaul * In ad hoc mode, we use the rx_quality field. 262653702Swpaul * signal and noise are trimmed to fit in the range from 47..138. 262753702Swpaul * rx_quality field MSB is signal strength. 262853702Swpaul * rx_quality field LSB is noise. 262953702Swpaul * "quality" is (signal - noise) as is log value. 263053702Swpaul * note: quality CAN be negative. 263153702Swpaul * 263253702Swpaul * In BSS mode, we use the RID for communication quality. 263353702Swpaul * TBD: BSS mode is currently untested. 263453702Swpaul * 263553702Swpaul * Bill's comments: 263653702Swpaul * --------------- 263753702Swpaul * Actually, we use the rx_quality field all the time for both "ad-hoc" 263853702Swpaul * and BSS modes. Why? Because reading an RID is really, really expensive: 263953702Swpaul * there's a bunch of PIO operations that have to be done to read a record 264053702Swpaul * from the NIC, and reading the comms quality RID each time a packet is 264153702Swpaul * received can really hurt performance. We don't have to do this anyway: 264253702Swpaul * the comms quality field only reflects the values in the rx_quality field 264353702Swpaul * anyway. The comms quality RID is only meaningful in infrastructure mode, 264453702Swpaul * but the values it contains are updated based on the rx_quality from 264553702Swpaul * frames received from the access point. 264653702Swpaul * 264753702Swpaul * Also, according to Lucent, the signal strength and noise level values 264853702Swpaul * can be converted to dBms by subtracting 149, so I've modified the code 264953702Swpaul * to do that instead of the scaling it did originally. 265053702Swpaul */ 265188546Salfredstatic void 265288546Salfredwi_cache_store(struct wi_softc *sc, struct ether_header *eh, 265353702Swpaul struct mbuf *m, unsigned short rx_quality) 265453702Swpaul{ 265553702Swpaul struct ip *ip = 0; 265653702Swpaul int i; 265753702Swpaul static int cache_slot = 0; /* use this cache entry */ 265853702Swpaul static int wrapindex = 0; /* next "free" cache entry */ 265953702Swpaul int sig, noise; 266053702Swpaul int sawip=0; 266153702Swpaul 266294405Simp /* 266394405Simp * filters: 266453702Swpaul * 1. ip only 266553702Swpaul * 2. configurable filter to throw out unicast packets, 266653702Swpaul * keep multicast only. 266753702Swpaul */ 266853702Swpaul 266975276Salfred if ((ntohs(eh->ether_type) == ETHERTYPE_IP)) { 267053702Swpaul sawip = 1; 267153702Swpaul } 267253702Swpaul 267394405Simp /* 267494405Simp * filter for ip packets only 267553702Swpaul */ 267653702Swpaul if (wi_cache_iponly && !sawip) { 267753702Swpaul return; 267853702Swpaul } 267953702Swpaul 268094405Simp /* 268194405Simp * filter for broadcast/multicast only 268253702Swpaul */ 268353702Swpaul if (wi_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) { 268453702Swpaul return; 268553702Swpaul } 268653702Swpaul 268753702Swpaul#ifdef SIGDEBUG 268853702Swpaul printf("wi%d: q value %x (MSB=0x%x, LSB=0x%x) \n", sc->wi_unit, 268953702Swpaul rx_quality & 0xffff, rx_quality >> 8, rx_quality & 0xff); 269053702Swpaul#endif 269153702Swpaul 269294405Simp /* 269394405Simp * find the ip header. we want to store the ip_src 269453702Swpaul * address. 269553702Swpaul */ 269694405Simp if (sawip) 269753702Swpaul ip = mtod(m, struct ip *); 269853702Swpaul 269994405Simp /* 270094405Simp * do a linear search for a matching MAC address 270153702Swpaul * in the cache table 270253702Swpaul * . MAC address is 6 bytes, 270353702Swpaul * . var w_nextitem holds total number of entries already cached 270453702Swpaul */ 270553702Swpaul for(i = 0; i < sc->wi_nextitem; i++) { 270653702Swpaul if (! bcmp(eh->ether_shost , sc->wi_sigcache[i].macsrc, 6 )) { 270794405Simp /* 270894405Simp * Match!, 270953702Swpaul * so we already have this entry, 271053702Swpaul * update the data 271153702Swpaul */ 271253702Swpaul break; 271353702Swpaul } 271453702Swpaul } 271553702Swpaul 271694405Simp /* 271794405Simp * did we find a matching mac address? 271853702Swpaul * if yes, then overwrite a previously existing cache entry 271953702Swpaul */ 272053702Swpaul if (i < sc->wi_nextitem ) { 272153702Swpaul cache_slot = i; 272253702Swpaul } 272394405Simp /* 272494405Simp * else, have a new address entry,so 272553702Swpaul * add this new entry, 272653702Swpaul * if table full, then we need to replace LRU entry 272753702Swpaul */ 272853702Swpaul else { 272953702Swpaul 273094405Simp /* 273194405Simp * check for space in cache table 273253702Swpaul * note: wi_nextitem also holds number of entries 273353702Swpaul * added in the cache table 273453702Swpaul */ 273553702Swpaul if ( sc->wi_nextitem < MAXWICACHE ) { 273653702Swpaul cache_slot = sc->wi_nextitem; 273753702Swpaul sc->wi_nextitem++; 273853702Swpaul sc->wi_sigitems = sc->wi_nextitem; 273953702Swpaul } 274053702Swpaul /* no space found, so simply wrap with wrap index 274153702Swpaul * and "zap" the next entry 274253702Swpaul */ 274353702Swpaul else { 274453702Swpaul if (wrapindex == MAXWICACHE) { 274553702Swpaul wrapindex = 0; 274653702Swpaul } 274753702Swpaul cache_slot = wrapindex++; 274853702Swpaul } 274953702Swpaul } 275053702Swpaul 275194405Simp /* 275294405Simp * invariant: cache_slot now points at some slot 275353702Swpaul * in cache. 275453702Swpaul */ 275553702Swpaul if (cache_slot < 0 || cache_slot >= MAXWICACHE) { 275653702Swpaul log(LOG_ERR, "wi_cache_store, bad index: %d of " 275753702Swpaul "[0..%d], gross cache error\n", 275853702Swpaul cache_slot, MAXWICACHE); 275953702Swpaul return; 276053702Swpaul } 276153702Swpaul 276294405Simp /* 276394405Simp * store items in cache 276453702Swpaul * .ip source address 276553702Swpaul * .mac src 276653702Swpaul * .signal, etc. 276753702Swpaul */ 276894405Simp if (sawip) 276953702Swpaul sc->wi_sigcache[cache_slot].ipsrc = ip->ip_src.s_addr; 277053702Swpaul bcopy( eh->ether_shost, sc->wi_sigcache[cache_slot].macsrc, 6); 277153702Swpaul 277253702Swpaul sig = (rx_quality >> 8) & 0xFF; 277353702Swpaul noise = rx_quality & 0xFF; 277453702Swpaul sc->wi_sigcache[cache_slot].signal = sig - 149; 277553702Swpaul sc->wi_sigcache[cache_slot].noise = noise - 149; 277653702Swpaul sc->wi_sigcache[cache_slot].quality = sig - noise; 277753702Swpaul 277853702Swpaul return; 277953702Swpaul} 278053702Swpaul#endif 278177217Sphk 278288546Salfredstatic int 278388546Salfredwi_get_cur_ssid(sc, ssid, len) 278477217Sphk struct wi_softc *sc; 278577217Sphk char *ssid; 278677217Sphk int *len; 278777217Sphk{ 278877217Sphk int error = 0; 278977217Sphk struct wi_req wreq; 279077217Sphk 279177217Sphk wreq.wi_len = WI_MAX_DATALEN; 279277217Sphk switch (sc->wi_ptype) { 279394405Simp case WI_PORTTYPE_AP: 279494405Simp *len = IEEE80211_NWID_LEN; 279594405Simp bcopy(sc->wi_net_name, ssid, IEEE80211_NWID_LEN); 279694405Simp break; 279777217Sphk case WI_PORTTYPE_ADHOC: 279877217Sphk wreq.wi_type = WI_RID_CURRENT_SSID; 279977217Sphk error = wi_read_record(sc, (struct wi_ltv_gen *)&wreq); 280077217Sphk if (error != 0) 280177217Sphk break; 280277217Sphk if (wreq.wi_val[0] > IEEE80211_NWID_LEN) { 280377217Sphk error = EINVAL; 280477217Sphk break; 280577217Sphk } 280677217Sphk *len = wreq.wi_val[0]; 280777217Sphk bcopy(&wreq.wi_val[1], ssid, IEEE80211_NWID_LEN); 280877217Sphk break; 280977217Sphk case WI_PORTTYPE_BSS: 281077217Sphk wreq.wi_type = WI_RID_COMMQUAL; 281177217Sphk error = wi_read_record(sc, (struct wi_ltv_gen *)&wreq); 281277217Sphk if (error != 0) 281377217Sphk break; 281477217Sphk if (wreq.wi_val[0] != 0) /* associated */ { 281577217Sphk wreq.wi_type = WI_RID_CURRENT_SSID; 281677217Sphk wreq.wi_len = WI_MAX_DATALEN; 281777217Sphk error = wi_read_record(sc, (struct wi_ltv_gen *)&wreq); 281877217Sphk if (error != 0) 281977217Sphk break; 282077217Sphk if (wreq.wi_val[0] > IEEE80211_NWID_LEN) { 282177217Sphk error = EINVAL; 282277217Sphk break; 282377217Sphk } 282477217Sphk *len = wreq.wi_val[0]; 282577217Sphk bcopy(&wreq.wi_val[1], ssid, IEEE80211_NWID_LEN); 282677217Sphk } else { 282777217Sphk *len = IEEE80211_NWID_LEN; 282877217Sphk bcopy(sc->wi_net_name, ssid, IEEE80211_NWID_LEN); 282977217Sphk } 283077217Sphk break; 283177217Sphk default: 283277217Sphk error = EINVAL; 283377217Sphk break; 283477217Sphk } 283577217Sphk 283677217Sphk return error; 283777217Sphk} 283877217Sphk 283988546Salfredstatic int 284088546Salfredwi_media_change(ifp) 284177217Sphk struct ifnet *ifp; 284277217Sphk{ 284377217Sphk struct wi_softc *sc = ifp->if_softc; 284477217Sphk int otype = sc->wi_ptype; 284577217Sphk int orate = sc->wi_tx_rate; 284698440Simp int ocreate_ibss = sc->wi_create_ibss; 284777217Sphk 284898440Simp if ((sc->ifmedia.ifm_cur->ifm_media & IFM_IEEE80211_HOSTAP) && 284998440Simp sc->sc_firmware_type != WI_INTERSIL) 285098440Simp return (EINVAL); 285198440Simp 285298440Simp sc->wi_create_ibss = 0; 285398440Simp 285498440Simp switch (sc->ifmedia.ifm_cur->ifm_media & IFM_OMASK) { 285598440Simp case 0: 285698440Simp sc->wi_ptype = WI_PORTTYPE_BSS; 285798440Simp break; 285898440Simp case IFM_IEEE80211_ADHOC: 285977217Sphk sc->wi_ptype = WI_PORTTYPE_ADHOC; 286098440Simp break; 286198440Simp case IFM_IEEE80211_HOSTAP: 286294405Simp sc->wi_ptype = WI_PORTTYPE_AP; 286398440Simp break; 286498440Simp case IFM_IEEE80211_IBSSMASTER: 286598440Simp case IFM_IEEE80211_IBSSMASTER|IFM_IEEE80211_IBSS: 286698440Simp if (!(sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)) 286798440Simp return (EINVAL); 286898440Simp sc->wi_create_ibss = 1; 286998440Simp /* FALLTHROUGH */ 287098440Simp case IFM_IEEE80211_IBSS: 287198440Simp sc->wi_ptype = WI_PORTTYPE_IBSS; 287298440Simp break; 287398440Simp default: 287498440Simp /* Invalid combination. */ 287598440Simp return (EINVAL); 287698440Simp } 287777217Sphk 287877217Sphk switch (IFM_SUBTYPE(sc->ifmedia.ifm_cur->ifm_media)) { 287977217Sphk case IFM_IEEE80211_DS1: 288077217Sphk sc->wi_tx_rate = 1; 288177217Sphk break; 288277217Sphk case IFM_IEEE80211_DS2: 288377217Sphk sc->wi_tx_rate = 2; 288477217Sphk break; 288577217Sphk case IFM_IEEE80211_DS5: 288677217Sphk sc->wi_tx_rate = 5; 288777217Sphk break; 288877217Sphk case IFM_IEEE80211_DS11: 288977217Sphk sc->wi_tx_rate = 11; 289077217Sphk break; 289177217Sphk case IFM_AUTO: 289277217Sphk sc->wi_tx_rate = 3; 289377217Sphk break; 289477217Sphk } 289577217Sphk 289698440Simp if (ocreate_ibss != sc->wi_create_ibss || otype != sc->wi_ptype || 289777217Sphk orate != sc->wi_tx_rate) 289877217Sphk wi_init(sc); 289977217Sphk 290077217Sphk return(0); 290177217Sphk} 290277217Sphk 290388546Salfredstatic void 290488546Salfredwi_media_status(ifp, imr) 290577217Sphk struct ifnet *ifp; 290677217Sphk struct ifmediareq *imr; 290777217Sphk{ 290877217Sphk struct wi_req wreq; 290977217Sphk struct wi_softc *sc = ifp->if_softc; 291077217Sphk 291177217Sphk if (sc->wi_tx_rate == 3) { 291277217Sphk imr->ifm_active = IFM_IEEE80211|IFM_AUTO; 291377217Sphk if (sc->wi_ptype == WI_PORTTYPE_ADHOC) 291477217Sphk imr->ifm_active |= IFM_IEEE80211_ADHOC; 291594405Simp else if (sc->wi_ptype == WI_PORTTYPE_AP) 291694405Simp imr->ifm_active |= IFM_IEEE80211_HOSTAP; 291798440Simp else if (sc->wi_ptype == WI_PORTTYPE_IBSS) { 291898440Simp if (sc->wi_create_ibss) 291998440Simp imr->ifm_active |= IFM_IEEE80211_IBSSMASTER; 292098440Simp else 292198440Simp imr->ifm_active |= IFM_IEEE80211_IBSS; 292298440Simp } 292377217Sphk wreq.wi_type = WI_RID_CUR_TX_RATE; 292477217Sphk wreq.wi_len = WI_MAX_DATALEN; 292577217Sphk if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0) { 292677217Sphk switch(wreq.wi_val[0]) { 292777217Sphk case 1: 292877217Sphk imr->ifm_active |= IFM_IEEE80211_DS1; 292977217Sphk break; 293077217Sphk case 2: 293177217Sphk imr->ifm_active |= IFM_IEEE80211_DS2; 293277217Sphk break; 293377217Sphk case 6: 293477217Sphk imr->ifm_active |= IFM_IEEE80211_DS5; 293577217Sphk break; 293677217Sphk case 11: 293777217Sphk imr->ifm_active |= IFM_IEEE80211_DS11; 293877217Sphk break; 293977217Sphk } 294077217Sphk } 294177217Sphk } else { 294277217Sphk imr->ifm_active = sc->ifmedia.ifm_cur->ifm_media; 294377217Sphk } 294477217Sphk 294577217Sphk imr->ifm_status = IFM_AVALID; 294698440Simp if (sc->wi_ptype == WI_PORTTYPE_ADHOC || 294798440Simp sc->wi_ptype == WI_PORTTYPE_IBSS) 294877217Sphk /* 294977217Sphk * XXX: It would be nice if we could give some actually 295077217Sphk * useful status like whether we joined another IBSS or 295177217Sphk * created one ourselves. 295277217Sphk */ 295377217Sphk imr->ifm_status |= IFM_ACTIVE; 295494405Simp else if (sc->wi_ptype == WI_PORTTYPE_AP) 295594405Simp imr->ifm_status |= IFM_ACTIVE; 295677217Sphk else { 295777217Sphk wreq.wi_type = WI_RID_COMMQUAL; 295877217Sphk wreq.wi_len = WI_MAX_DATALEN; 295977217Sphk if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0 && 296077217Sphk wreq.wi_val[0] != 0) 296177217Sphk imr->ifm_status |= IFM_ACTIVE; 296277217Sphk } 296377217Sphk} 296493359Simp 296593359Simpstatic int 296693359Simpwi_get_debug(sc, wreq) 296793359Simp struct wi_softc *sc; 296893359Simp struct wi_req *wreq; 296993359Simp{ 297093359Simp int error = 0; 297193359Simp 297293359Simp wreq->wi_len = 1; 297393359Simp 297493359Simp switch (wreq->wi_type) { 297593359Simp case WI_DEBUG_SLEEP: 297693359Simp wreq->wi_len++; 297793359Simp wreq->wi_val[0] = sc->wi_debug.wi_sleep; 297893359Simp break; 297993359Simp case WI_DEBUG_DELAYSUPP: 298093359Simp wreq->wi_len++; 298193359Simp wreq->wi_val[0] = sc->wi_debug.wi_delaysupp; 298293359Simp break; 298393359Simp case WI_DEBUG_TXSUPP: 298493359Simp wreq->wi_len++; 298593359Simp wreq->wi_val[0] = sc->wi_debug.wi_txsupp; 298693359Simp break; 298793359Simp case WI_DEBUG_MONITOR: 298893359Simp wreq->wi_len++; 298993359Simp wreq->wi_val[0] = sc->wi_debug.wi_monitor; 299093359Simp break; 299193359Simp case WI_DEBUG_LEDTEST: 299293359Simp wreq->wi_len += 3; 299393359Simp wreq->wi_val[0] = sc->wi_debug.wi_ledtest; 299493359Simp wreq->wi_val[1] = sc->wi_debug.wi_ledtest_param0; 299593359Simp wreq->wi_val[2] = sc->wi_debug.wi_ledtest_param1; 299693359Simp break; 299793359Simp case WI_DEBUG_CONTTX: 299893359Simp wreq->wi_len += 2; 299993359Simp wreq->wi_val[0] = sc->wi_debug.wi_conttx; 300093359Simp wreq->wi_val[1] = sc->wi_debug.wi_conttx_param0; 300193359Simp break; 300293359Simp case WI_DEBUG_CONTRX: 300393359Simp wreq->wi_len++; 300493359Simp wreq->wi_val[0] = sc->wi_debug.wi_contrx; 300593359Simp break; 300693359Simp case WI_DEBUG_SIGSTATE: 300793359Simp wreq->wi_len += 2; 300893359Simp wreq->wi_val[0] = sc->wi_debug.wi_sigstate; 300993359Simp wreq->wi_val[1] = sc->wi_debug.wi_sigstate_param0; 301093359Simp break; 301193359Simp case WI_DEBUG_CONFBITS: 301293359Simp wreq->wi_len += 2; 301393359Simp wreq->wi_val[0] = sc->wi_debug.wi_confbits; 301493359Simp wreq->wi_val[1] = sc->wi_debug.wi_confbits_param0; 301593359Simp break; 301693359Simp default: 301793359Simp error = EIO; 301893359Simp break; 301993359Simp } 302093359Simp 302193359Simp return (error); 302293359Simp} 302393359Simp 302493359Simpstatic int 302593359Simpwi_set_debug(sc, wreq) 302693359Simp struct wi_softc *sc; 302793359Simp struct wi_req *wreq; 302893359Simp{ 302993359Simp int error = 0; 303093359Simp u_int16_t cmd, param0 = 0, param1 = 0; 303193359Simp 303293359Simp switch (wreq->wi_type) { 303393359Simp case WI_DEBUG_RESET: 303493359Simp case WI_DEBUG_INIT: 303593359Simp case WI_DEBUG_CALENABLE: 303693359Simp break; 303793359Simp case WI_DEBUG_SLEEP: 303893359Simp sc->wi_debug.wi_sleep = 1; 303993359Simp break; 304093359Simp case WI_DEBUG_WAKE: 304193359Simp sc->wi_debug.wi_sleep = 0; 304293359Simp break; 304393359Simp case WI_DEBUG_CHAN: 304493359Simp param0 = wreq->wi_val[0]; 304593359Simp break; 304693359Simp case WI_DEBUG_DELAYSUPP: 304793359Simp sc->wi_debug.wi_delaysupp = 1; 304893359Simp break; 304993359Simp case WI_DEBUG_TXSUPP: 305093359Simp sc->wi_debug.wi_txsupp = 1; 305193359Simp break; 305293359Simp case WI_DEBUG_MONITOR: 305393359Simp sc->wi_debug.wi_monitor = 1; 305493359Simp break; 305593359Simp case WI_DEBUG_LEDTEST: 305693359Simp param0 = wreq->wi_val[0]; 305793359Simp param1 = wreq->wi_val[1]; 305893359Simp sc->wi_debug.wi_ledtest = 1; 305993359Simp sc->wi_debug.wi_ledtest_param0 = param0; 306093359Simp sc->wi_debug.wi_ledtest_param1 = param1; 306193359Simp break; 306293359Simp case WI_DEBUG_CONTTX: 306393359Simp param0 = wreq->wi_val[0]; 306493359Simp sc->wi_debug.wi_conttx = 1; 306593359Simp sc->wi_debug.wi_conttx_param0 = param0; 306693359Simp break; 306793359Simp case WI_DEBUG_STOPTEST: 306893359Simp sc->wi_debug.wi_delaysupp = 0; 306993359Simp sc->wi_debug.wi_txsupp = 0; 307093359Simp sc->wi_debug.wi_monitor = 0; 307193359Simp sc->wi_debug.wi_ledtest = 0; 307293359Simp sc->wi_debug.wi_ledtest_param0 = 0; 307393359Simp sc->wi_debug.wi_ledtest_param1 = 0; 307493359Simp sc->wi_debug.wi_conttx = 0; 307593359Simp sc->wi_debug.wi_conttx_param0 = 0; 307693359Simp sc->wi_debug.wi_contrx = 0; 307793359Simp sc->wi_debug.wi_sigstate = 0; 307893359Simp sc->wi_debug.wi_sigstate_param0 = 0; 307993359Simp break; 308093359Simp case WI_DEBUG_CONTRX: 308193359Simp sc->wi_debug.wi_contrx = 1; 308293359Simp break; 308393359Simp case WI_DEBUG_SIGSTATE: 308493359Simp param0 = wreq->wi_val[0]; 308593359Simp sc->wi_debug.wi_sigstate = 1; 308693359Simp sc->wi_debug.wi_sigstate_param0 = param0; 308793359Simp break; 308893359Simp case WI_DEBUG_CONFBITS: 308993359Simp param0 = wreq->wi_val[0]; 309093359Simp param1 = wreq->wi_val[1]; 309193359Simp sc->wi_debug.wi_confbits = param0; 309293359Simp sc->wi_debug.wi_confbits_param0 = param1; 309393359Simp break; 309493359Simp default: 309593359Simp error = EIO; 309693359Simp break; 309793359Simp } 309893359Simp 309993359Simp if (error) 310093359Simp return (error); 310193359Simp 310293359Simp cmd = WI_CMD_DEBUG | (wreq->wi_type << 8); 310393359Simp error = wi_cmd(sc, cmd, param0, param1, 0); 310493359Simp 310593359Simp return (error); 310693359Simp} 3107