1139749Simp/*- 2123474Swpaul * Copyright (c) 2003 3123474Swpaul * Bill Paul <wpaul@windriver.com>. All rights reserved. 4123474Swpaul * 5123474Swpaul * Redistribution and use in source and binary forms, with or without 6123474Swpaul * modification, are permitted provided that the following conditions 7123474Swpaul * are met: 8123474Swpaul * 1. Redistributions of source code must retain the above copyright 9123474Swpaul * notice, this list of conditions and the following disclaimer. 10123474Swpaul * 2. Redistributions in binary form must reproduce the above copyright 11123474Swpaul * notice, this list of conditions and the following disclaimer in the 12123474Swpaul * documentation and/or other materials provided with the distribution. 13123474Swpaul * 3. All advertising materials mentioning features or use of this software 14123474Swpaul * must display the following acknowledgement: 15123474Swpaul * This product includes software developed by Bill Paul. 16123474Swpaul * 4. Neither the name of the author nor the names of any co-contributors 17123474Swpaul * may be used to endorse or promote products derived from this software 18123474Swpaul * without specific prior written permission. 19123474Swpaul * 20123474Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21123474Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22123474Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23123474Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24123474Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25123474Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26123474Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27123474Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28123474Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29123474Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30123474Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 31145283Swpaul * 32151207Swpaul * WPA support originally contributed by Arvind Srinivasan <arvind@celar.us> 33151207Swpaul * then hacked upon mercilessly by my. 34123474Swpaul */ 35123474Swpaul 36123474Swpaul#include <sys/cdefs.h> 37123474Swpaul__FBSDID("$FreeBSD$"); 38123474Swpaul 39123474Swpaul#include <sys/param.h> 40123474Swpaul#include <sys/systm.h> 41123474Swpaul#include <sys/sockio.h> 42123474Swpaul#include <sys/mbuf.h> 43123474Swpaul#include <sys/malloc.h> 44171390Sthompsa#include <sys/endian.h> 45164033Srwatson#include <sys/priv.h> 46123474Swpaul#include <sys/kernel.h> 47123474Swpaul#include <sys/socket.h> 48123474Swpaul#include <sys/queue.h> 49141524Swpaul#include <sys/module.h> 50143204Swpaul#include <sys/proc.h> 51123474Swpaul#include <sys/sysctl.h> 52171390Sthompsa#include <sys/kthread.h> 53123474Swpaul 54123474Swpaul#include <net/if.h> 55123474Swpaul#include <net/if_arp.h> 56123474Swpaul#include <net/ethernet.h> 57123474Swpaul#include <net/if_dl.h> 58123474Swpaul#include <net/if_media.h> 59147256Sbrooks#include <net/if_types.h> 60129002Sandre#include <net/route.h> 61123474Swpaul 62123474Swpaul#include <net/bpf.h> 63123474Swpaul 64123474Swpaul#include <machine/bus.h> 65123474Swpaul#include <machine/resource.h> 66123474Swpaul#include <sys/bus.h> 67123474Swpaul#include <sys/rman.h> 68123474Swpaul 69123695Swpaul#include <net80211/ieee80211_var.h> 70123695Swpaul#include <net80211/ieee80211_ioctl.h> 71171390Sthompsa#include <net80211/ieee80211_regdomain.h> 72123695Swpaul 73123474Swpaul#include <dev/pci/pcireg.h> 74123474Swpaul#include <dev/pci/pcivar.h> 75189488Sweongyo#include <dev/usb/usb.h> 76194677Sthompsa#include <dev/usb/usbdi.h> 77123474Swpaul 78123474Swpaul#include <compat/ndis/pe_var.h> 79145485Swpaul#include <compat/ndis/cfg_var.h> 80123474Swpaul#include <compat/ndis/resource_var.h> 81132953Swpaul#include <compat/ndis/ntoskrnl_var.h> 82128229Swpaul#include <compat/ndis/hal_var.h> 83123474Swpaul#include <compat/ndis/ndis_var.h> 84186507Sweongyo#include <compat/ndis/usbd_var.h> 85123474Swpaul#include <dev/if_ndis/if_ndisvar.h> 86123474Swpaul 87171602Sthompsa#define NDIS_DEBUG 88171390Sthompsa#ifdef NDIS_DEBUG 89171602Sthompsa#define DPRINTF(x) do { if (ndis_debug > 0) printf x; } while (0) 90171602Sthompsaint ndis_debug = 0; 91171602SthompsaSYSCTL_INT(_debug, OID_AUTO, ndis, CTLFLAG_RW, &ndis_debug, 0, 92171602Sthompsa "if_ndis debug level"); 93171390Sthompsa#else 94171390Sthompsa#define DPRINTF(x) 95171390Sthompsa#endif 96171390Sthompsa 97186507SweongyoSYSCTL_DECL(_hw_ndisusb); 98186507Sweongyoint ndisusb_halt = 1; 99186507SweongyoSYSCTL_INT(_hw_ndisusb, OID_AUTO, halt, CTLFLAG_RW, &ndisusb_halt, 0, 100186507Sweongyo "Halt NDIS USB driver when it's attached"); 101186507Sweongyo 102187104Sthompsa/* 0 - 30 dBm to mW conversion table */ 103189550Ssamstatic const uint16_t dBm2mW[] = { 104187104Sthompsa 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 105187104Sthompsa 3, 4, 4, 4, 5, 6, 6, 7, 8, 9, 106187104Sthompsa 10, 11, 13, 14, 16, 18, 20, 22, 25, 28, 107187104Sthompsa 32, 35, 40, 45, 50, 56, 63, 71, 79, 89, 108187104Sthompsa 100, 112, 126, 141, 158, 178, 200, 224, 251, 282, 109187104Sthompsa 316, 355, 398, 447, 501, 562, 631, 708, 794, 891, 110187104Sthompsa 1000 111187104Sthompsa}; 112187104Sthompsa 113145485SwpaulMODULE_DEPEND(ndis, ether, 1, 1, 1); 114145485SwpaulMODULE_DEPEND(ndis, wlan, 1, 1, 1); 115145485SwpaulMODULE_DEPEND(ndis, ndisapi, 1, 1, 1); 116126706Swpaul 117145485SwpaulMODULE_VERSION(ndis, 1); 118123474Swpaul 119126706Swpaulint ndis_attach (device_t); 120126706Swpaulint ndis_detach (device_t); 121126706Swpaulint ndis_suspend (device_t); 122126706Swpaulint ndis_resume (device_t); 123126706Swpaulvoid ndis_shutdown (device_t); 124123474Swpaul 125141524Swpaulint ndisdrv_modevent (module_t, int, void *); 126141524Swpaul 127144888Swpaulstatic void ndis_txeof (ndis_handle, ndis_packet *, ndis_status); 128144888Swpaulstatic void ndis_rxeof (ndis_handle, ndis_packet **, uint32_t); 129146230Swpaulstatic void ndis_rxeof_eth (ndis_handle, ndis_handle, char *, void *, 130146230Swpaul uint32_t, void *, uint32_t, uint32_t); 131146230Swpaulstatic void ndis_rxeof_done (ndis_handle); 132146230Swpaulstatic void ndis_rxeof_xfr (kdpc *, ndis_handle, void *, void *); 133146230Swpaulstatic void ndis_rxeof_xfr_done (ndis_handle, ndis_packet *, 134146230Swpaul uint32_t, uint32_t); 135144888Swpaulstatic void ndis_linksts (ndis_handle, ndis_status, void *, uint32_t); 136144888Swpaulstatic void ndis_linksts_done (ndis_handle); 137123695Swpaul 138141963Swpaul/* We need to wrap these functions for amd64. */ 139141963Swpaulstatic funcptr ndis_txeof_wrap; 140141963Swpaulstatic funcptr ndis_rxeof_wrap; 141146230Swpaulstatic funcptr ndis_rxeof_eth_wrap; 142146230Swpaulstatic funcptr ndis_rxeof_done_wrap; 143146230Swpaulstatic funcptr ndis_rxeof_xfr_wrap; 144146230Swpaulstatic funcptr ndis_rxeof_xfr_done_wrap; 145141963Swpaulstatic funcptr ndis_linksts_wrap; 146141963Swpaulstatic funcptr ndis_linksts_done_wrap; 147145895Swpaulstatic funcptr ndis_ticktask_wrap; 148145895Swpaulstatic funcptr ndis_starttask_wrap; 149145895Swpaulstatic funcptr ndis_resettask_wrap; 150151451Swpaulstatic funcptr ndis_inputtask_wrap; 151141963Swpaul 152178354Ssamstatic struct ieee80211vap *ndis_vap_create(struct ieee80211com *, 153228621Sbschmidt const char [IFNAMSIZ], int, enum ieee80211_opmode, int, 154228621Sbschmidt const uint8_t [IEEE80211_ADDR_LEN], 155228621Sbschmidt const uint8_t [IEEE80211_ADDR_LEN]); 156178354Ssamstatic void ndis_vap_delete (struct ieee80211vap *); 157123474Swpaulstatic void ndis_tick (void *); 158151207Swpaulstatic void ndis_ticktask (device_object *, void *); 159178354Ssamstatic int ndis_raw_xmit (struct ieee80211_node *, struct mbuf *, 160178354Ssam const struct ieee80211_bpf_params *); 161185485Ssamstatic void ndis_update_mcast (struct ifnet *ifp); 162185485Ssamstatic void ndis_update_promisc (struct ifnet *ifp); 163123474Swpaulstatic void ndis_start (struct ifnet *); 164151207Swpaulstatic void ndis_starttask (device_object *, void *); 165151207Swpaulstatic void ndis_resettask (device_object *, void *); 166151451Swpaulstatic void ndis_inputtask (device_object *, void *); 167123474Swpaulstatic int ndis_ioctl (struct ifnet *, u_long, caddr_t); 168178704Sthompsastatic int ndis_ioctl_80211 (struct ifnet *, u_long, caddr_t); 169178354Ssamstatic int ndis_newstate (struct ieee80211vap *, enum ieee80211_state, 170171390Sthompsa int); 171171602Sthompsastatic int ndis_nettype_chan (uint32_t); 172171602Sthompsastatic int ndis_nettype_mode (uint32_t); 173191746Sthompsastatic void ndis_scan (void *); 174171390Sthompsastatic void ndis_scan_results (struct ndis_softc *); 175171390Sthompsastatic void ndis_scan_start (struct ieee80211com *); 176171390Sthompsastatic void ndis_scan_end (struct ieee80211com *); 177171390Sthompsastatic void ndis_set_channel (struct ieee80211com *); 178178354Ssamstatic void ndis_scan_curchan (struct ieee80211_scan_state *, unsigned long); 179178354Ssamstatic void ndis_scan_mindwell (struct ieee80211_scan_state *); 180123474Swpaulstatic void ndis_init (void *); 181123474Swpaulstatic void ndis_stop (struct ndis_softc *); 182123474Swpaulstatic int ndis_ifmedia_upd (struct ifnet *); 183123474Swpaulstatic void ndis_ifmedia_sts (struct ifnet *, struct ifmediareq *); 184194706Scokanestatic int ndis_get_bssid_list (struct ndis_softc *, 185194706Scokane ndis_80211_bssid_list_ex **); 186127349Swpaulstatic int ndis_get_assoc (struct ndis_softc *, ndis_wlan_bssid_ex **); 187124821Swpaulstatic int ndis_probe_offload (struct ndis_softc *); 188124821Swpaulstatic int ndis_set_offload (struct ndis_softc *); 189123695Swpaulstatic void ndis_getstate_80211 (struct ndis_softc *); 190123695Swpaulstatic void ndis_setstate_80211 (struct ndis_softc *); 191178929Sthompsastatic void ndis_auth_and_assoc (struct ndis_softc *, struct ieee80211vap *); 192201620Srpaulostatic void ndis_media_status (struct ifnet *, struct ifmediareq *); 193151207Swpaulstatic int ndis_set_cipher (struct ndis_softc *, int); 194178354Ssamstatic int ndis_set_wpa (struct ndis_softc *, void *, int); 195178354Ssamstatic int ndis_add_key (struct ieee80211vap *, 196151207Swpaul const struct ieee80211_key *, const u_int8_t []); 197178354Ssamstatic int ndis_del_key (struct ieee80211vap *, 198151207Swpaul const struct ieee80211_key *); 199123474Swpaul 200123474Swpaulstatic void ndis_setmulti (struct ndis_softc *); 201123474Swpaulstatic void ndis_map_sclist (void *, bus_dma_segment_t *, 202123474Swpaul int, bus_size_t, int); 203123474Swpaul 204141524Swpaulstatic int ndisdrv_loaded = 0; 205123474Swpaul 206123474Swpaul/* 207141524Swpaul * This routine should call windrv_load() once for each driver 208141524Swpaul * image. This will do the relocation and dynalinking for the 209141524Swpaul * image, and create a Windows driver object which will be 210141524Swpaul * saved in our driver database. 211141524Swpaul */ 212141524Swpaulint 213141524Swpaulndisdrv_modevent(mod, cmd, arg) 214141524Swpaul module_t mod; 215141524Swpaul int cmd; 216141524Swpaul void *arg; 217141524Swpaul{ 218141524Swpaul int error = 0; 219141524Swpaul 220141524Swpaul switch (cmd) { 221141524Swpaul case MOD_LOAD: 222141524Swpaul ndisdrv_loaded++; 223141524Swpaul if (ndisdrv_loaded > 1) 224141524Swpaul break; 225144888Swpaul windrv_wrap((funcptr)ndis_rxeof, &ndis_rxeof_wrap, 226144888Swpaul 3, WINDRV_WRAP_STDCALL); 227146230Swpaul windrv_wrap((funcptr)ndis_rxeof_eth, &ndis_rxeof_eth_wrap, 228146230Swpaul 8, WINDRV_WRAP_STDCALL); 229146230Swpaul windrv_wrap((funcptr)ndis_rxeof_done, &ndis_rxeof_done_wrap, 230146230Swpaul 1, WINDRV_WRAP_STDCALL); 231146230Swpaul windrv_wrap((funcptr)ndis_rxeof_xfr, &ndis_rxeof_xfr_wrap, 232146230Swpaul 4, WINDRV_WRAP_STDCALL); 233146230Swpaul windrv_wrap((funcptr)ndis_rxeof_xfr_done, 234146230Swpaul &ndis_rxeof_xfr_done_wrap, 4, WINDRV_WRAP_STDCALL); 235144888Swpaul windrv_wrap((funcptr)ndis_txeof, &ndis_txeof_wrap, 236144888Swpaul 3, WINDRV_WRAP_STDCALL); 237144888Swpaul windrv_wrap((funcptr)ndis_linksts, &ndis_linksts_wrap, 238144888Swpaul 4, WINDRV_WRAP_STDCALL); 239141963Swpaul windrv_wrap((funcptr)ndis_linksts_done, 240144888Swpaul &ndis_linksts_done_wrap, 1, WINDRV_WRAP_STDCALL); 241145895Swpaul windrv_wrap((funcptr)ndis_ticktask, &ndis_ticktask_wrap, 242145895Swpaul 2, WINDRV_WRAP_STDCALL); 243145895Swpaul windrv_wrap((funcptr)ndis_starttask, &ndis_starttask_wrap, 244145895Swpaul 2, WINDRV_WRAP_STDCALL); 245145895Swpaul windrv_wrap((funcptr)ndis_resettask, &ndis_resettask_wrap, 246145895Swpaul 2, WINDRV_WRAP_STDCALL); 247151451Swpaul windrv_wrap((funcptr)ndis_inputtask, &ndis_inputtask_wrap, 248151451Swpaul 2, WINDRV_WRAP_STDCALL); 249141524Swpaul break; 250141524Swpaul case MOD_UNLOAD: 251141524Swpaul ndisdrv_loaded--; 252141524Swpaul if (ndisdrv_loaded > 0) 253141524Swpaul break; 254145895Swpaul /* fallthrough */ 255141524Swpaul case MOD_SHUTDOWN: 256141963Swpaul windrv_unwrap(ndis_rxeof_wrap); 257146230Swpaul windrv_unwrap(ndis_rxeof_eth_wrap); 258146230Swpaul windrv_unwrap(ndis_rxeof_done_wrap); 259146230Swpaul windrv_unwrap(ndis_rxeof_xfr_wrap); 260146230Swpaul windrv_unwrap(ndis_rxeof_xfr_done_wrap); 261141963Swpaul windrv_unwrap(ndis_txeof_wrap); 262141963Swpaul windrv_unwrap(ndis_linksts_wrap); 263141963Swpaul windrv_unwrap(ndis_linksts_done_wrap); 264145895Swpaul windrv_unwrap(ndis_ticktask_wrap); 265145895Swpaul windrv_unwrap(ndis_starttask_wrap); 266145895Swpaul windrv_unwrap(ndis_resettask_wrap); 267151451Swpaul windrv_unwrap(ndis_inputtask_wrap); 268141524Swpaul break; 269141524Swpaul default: 270141524Swpaul error = EINVAL; 271141524Swpaul break; 272141524Swpaul } 273141524Swpaul 274141524Swpaul return (error); 275141524Swpaul} 276141524Swpaul 277141524Swpaul/* 278123474Swpaul * Program the 64-bit multicast hash filter. 279123474Swpaul */ 280123474Swpaulstatic void 281123474Swpaulndis_setmulti(sc) 282123474Swpaul struct ndis_softc *sc; 283123474Swpaul{ 284124709Swpaul struct ifnet *ifp; 285124709Swpaul struct ifmultiaddr *ifma; 286124709Swpaul int len, mclistsz, error; 287124709Swpaul uint8_t *mclist; 288124709Swpaul 289147256Sbrooks ifp = sc->ifp; 290124709Swpaul 291131750Swpaul if (!NDIS_INITIALIZED(sc)) 292124709Swpaul return; 293124709Swpaul 294124709Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 295124709Swpaul sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; 296124709Swpaul len = sizeof(sc->ndis_filter); 297124709Swpaul error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER, 298124709Swpaul &sc->ndis_filter, &len); 299124709Swpaul if (error) 300198786Srpaulo device_printf(sc->ndis_dev, 301151207Swpaul "set allmulti failed: %d\n", error); 302124709Swpaul return; 303124709Swpaul } 304124709Swpaul 305127552Swpaul if (TAILQ_EMPTY(&ifp->if_multiaddrs)) 306127552Swpaul return; 307124709Swpaul 308124709Swpaul len = sizeof(mclistsz); 309124709Swpaul ndis_get_info(sc, OID_802_3_MAXIMUM_LIST_SIZE, &mclistsz, &len); 310124709Swpaul 311125061Swpaul mclist = malloc(ETHER_ADDR_LEN * mclistsz, M_TEMP, M_NOWAIT|M_ZERO); 312124709Swpaul 313124709Swpaul if (mclist == NULL) { 314124709Swpaul sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; 315124709Swpaul goto out; 316124709Swpaul } 317124709Swpaul 318124709Swpaul sc->ndis_filter |= NDIS_PACKET_TYPE_MULTICAST; 319124709Swpaul 320124709Swpaul len = 0; 321195049Srwatson if_maddr_rlock(ifp); 322124709Swpaul TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 323124709Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 324124709Swpaul continue; 325124709Swpaul bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 326124709Swpaul mclist + (ETHER_ADDR_LEN * len), ETHER_ADDR_LEN); 327124709Swpaul len++; 328124709Swpaul if (len > mclistsz) { 329195049Srwatson if_maddr_runlock(ifp); 330124709Swpaul sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; 331124709Swpaul sc->ndis_filter &= ~NDIS_PACKET_TYPE_MULTICAST; 332124709Swpaul goto out; 333124709Swpaul } 334124709Swpaul } 335195049Srwatson if_maddr_runlock(ifp); 336124709Swpaul 337124709Swpaul len = len * ETHER_ADDR_LEN; 338124709Swpaul error = ndis_set_info(sc, OID_802_3_MULTICAST_LIST, mclist, &len); 339124709Swpaul if (error) { 340198786Srpaulo device_printf(sc->ndis_dev, "set mclist failed: %d\n", error); 341124709Swpaul sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; 342124709Swpaul sc->ndis_filter &= ~NDIS_PACKET_TYPE_MULTICAST; 343124709Swpaul } 344124709Swpaul 345124709Swpaulout: 346124709Swpaul free(mclist, M_TEMP); 347124709Swpaul 348124709Swpaul len = sizeof(sc->ndis_filter); 349124709Swpaul error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER, 350124709Swpaul &sc->ndis_filter, &len); 351124709Swpaul if (error) 352198786Srpaulo device_printf(sc->ndis_dev, "set multi failed: %d\n", error); 353123474Swpaul} 354123474Swpaul 355123474Swpaulstatic int 356124821Swpaulndis_set_offload(sc) 357124821Swpaul struct ndis_softc *sc; 358124821Swpaul{ 359124821Swpaul ndis_task_offload *nto; 360124821Swpaul ndis_task_offload_hdr *ntoh; 361124821Swpaul ndis_task_tcpip_csum *nttc; 362124821Swpaul struct ifnet *ifp; 363124821Swpaul int len, error; 364124821Swpaul 365147256Sbrooks ifp = sc->ifp; 366124821Swpaul 367131750Swpaul if (!NDIS_INITIALIZED(sc)) 368198786Srpaulo return (EINVAL); 369124821Swpaul 370124821Swpaul /* See if there's anything to set. */ 371124821Swpaul 372124821Swpaul error = ndis_probe_offload(sc); 373124821Swpaul if (error) 374198786Srpaulo return (error); 375124821Swpaul 376124821Swpaul if (sc->ndis_hwassist == 0 && ifp->if_capabilities == 0) 377198786Srpaulo return (0); 378124821Swpaul 379124821Swpaul len = sizeof(ndis_task_offload_hdr) + sizeof(ndis_task_offload) + 380124821Swpaul sizeof(ndis_task_tcpip_csum); 381124821Swpaul 382124821Swpaul ntoh = malloc(len, M_TEMP, M_NOWAIT|M_ZERO); 383124821Swpaul 384124821Swpaul if (ntoh == NULL) 385198786Srpaulo return (ENOMEM); 386124821Swpaul 387124821Swpaul ntoh->ntoh_vers = NDIS_TASK_OFFLOAD_VERSION; 388124821Swpaul ntoh->ntoh_len = sizeof(ndis_task_offload_hdr); 389124821Swpaul ntoh->ntoh_offset_firsttask = sizeof(ndis_task_offload_hdr); 390124821Swpaul ntoh->ntoh_encapfmt.nef_encaphdrlen = sizeof(struct ether_header); 391124821Swpaul ntoh->ntoh_encapfmt.nef_encap = NDIS_ENCAP_IEEE802_3; 392124821Swpaul ntoh->ntoh_encapfmt.nef_flags = NDIS_ENCAPFLAG_FIXEDHDRLEN; 393124821Swpaul 394124821Swpaul nto = (ndis_task_offload *)((char *)ntoh + 395124821Swpaul ntoh->ntoh_offset_firsttask); 396124821Swpaul 397124821Swpaul nto->nto_vers = NDIS_TASK_OFFLOAD_VERSION; 398124821Swpaul nto->nto_len = sizeof(ndis_task_offload); 399124821Swpaul nto->nto_task = NDIS_TASK_TCPIP_CSUM; 400124821Swpaul nto->nto_offset_nexttask = 0; 401124821Swpaul nto->nto_taskbuflen = sizeof(ndis_task_tcpip_csum); 402124821Swpaul 403124821Swpaul nttc = (ndis_task_tcpip_csum *)nto->nto_taskbuf; 404124821Swpaul 405124821Swpaul if (ifp->if_capenable & IFCAP_TXCSUM) 406124821Swpaul nttc->nttc_v4tx = sc->ndis_v4tx; 407124821Swpaul 408124821Swpaul if (ifp->if_capenable & IFCAP_RXCSUM) 409124821Swpaul nttc->nttc_v4rx = sc->ndis_v4rx; 410124821Swpaul 411124821Swpaul error = ndis_set_info(sc, OID_TCP_TASK_OFFLOAD, ntoh, &len); 412124821Swpaul free(ntoh, M_TEMP); 413124821Swpaul 414198786Srpaulo return (error); 415124821Swpaul} 416124821Swpaul 417124821Swpaulstatic int 418124821Swpaulndis_probe_offload(sc) 419124821Swpaul struct ndis_softc *sc; 420124821Swpaul{ 421124821Swpaul ndis_task_offload *nto; 422124821Swpaul ndis_task_offload_hdr *ntoh; 423124821Swpaul ndis_task_tcpip_csum *nttc = NULL; 424124821Swpaul struct ifnet *ifp; 425124821Swpaul int len, error, dummy; 426124821Swpaul 427147256Sbrooks ifp = sc->ifp; 428124821Swpaul 429124821Swpaul len = sizeof(dummy); 430124821Swpaul error = ndis_get_info(sc, OID_TCP_TASK_OFFLOAD, &dummy, &len); 431124821Swpaul 432124821Swpaul if (error != ENOSPC) 433198786Srpaulo return (error); 434124821Swpaul 435124821Swpaul ntoh = malloc(len, M_TEMP, M_NOWAIT|M_ZERO); 436124821Swpaul 437124821Swpaul if (ntoh == NULL) 438198786Srpaulo return (ENOMEM); 439124821Swpaul 440124821Swpaul ntoh->ntoh_vers = NDIS_TASK_OFFLOAD_VERSION; 441124821Swpaul ntoh->ntoh_len = sizeof(ndis_task_offload_hdr); 442124821Swpaul ntoh->ntoh_encapfmt.nef_encaphdrlen = sizeof(struct ether_header); 443124821Swpaul ntoh->ntoh_encapfmt.nef_encap = NDIS_ENCAP_IEEE802_3; 444124821Swpaul ntoh->ntoh_encapfmt.nef_flags = NDIS_ENCAPFLAG_FIXEDHDRLEN; 445124821Swpaul 446124821Swpaul error = ndis_get_info(sc, OID_TCP_TASK_OFFLOAD, ntoh, &len); 447124821Swpaul 448124821Swpaul if (error) { 449124821Swpaul free(ntoh, M_TEMP); 450198786Srpaulo return (error); 451124821Swpaul } 452124821Swpaul 453124821Swpaul if (ntoh->ntoh_vers != NDIS_TASK_OFFLOAD_VERSION) { 454124821Swpaul free(ntoh, M_TEMP); 455198786Srpaulo return (EINVAL); 456124821Swpaul } 457124821Swpaul 458124821Swpaul nto = (ndis_task_offload *)((char *)ntoh + 459124821Swpaul ntoh->ntoh_offset_firsttask); 460124821Swpaul 461124821Swpaul while (1) { 462124821Swpaul switch (nto->nto_task) { 463124821Swpaul case NDIS_TASK_TCPIP_CSUM: 464124821Swpaul nttc = (ndis_task_tcpip_csum *)nto->nto_taskbuf; 465124821Swpaul break; 466124821Swpaul /* Don't handle these yet. */ 467124821Swpaul case NDIS_TASK_IPSEC: 468124821Swpaul case NDIS_TASK_TCP_LARGESEND: 469124821Swpaul default: 470124821Swpaul break; 471124821Swpaul } 472124821Swpaul if (nto->nto_offset_nexttask == 0) 473124821Swpaul break; 474124821Swpaul nto = (ndis_task_offload *)((char *)nto + 475124821Swpaul nto->nto_offset_nexttask); 476124821Swpaul } 477124821Swpaul 478124821Swpaul if (nttc == NULL) { 479124821Swpaul free(ntoh, M_TEMP); 480198786Srpaulo return (ENOENT); 481124821Swpaul } 482124821Swpaul 483124821Swpaul sc->ndis_v4tx = nttc->nttc_v4tx; 484124821Swpaul sc->ndis_v4rx = nttc->nttc_v4rx; 485124821Swpaul 486124821Swpaul if (nttc->nttc_v4tx & NDIS_TCPSUM_FLAGS_IP_CSUM) 487124821Swpaul sc->ndis_hwassist |= CSUM_IP; 488124821Swpaul if (nttc->nttc_v4tx & NDIS_TCPSUM_FLAGS_TCP_CSUM) 489124821Swpaul sc->ndis_hwassist |= CSUM_TCP; 490124821Swpaul if (nttc->nttc_v4tx & NDIS_TCPSUM_FLAGS_UDP_CSUM) 491124821Swpaul sc->ndis_hwassist |= CSUM_UDP; 492124821Swpaul 493124821Swpaul if (sc->ndis_hwassist) 494124821Swpaul ifp->if_capabilities |= IFCAP_TXCSUM; 495124821Swpaul 496124821Swpaul if (nttc->nttc_v4rx & NDIS_TCPSUM_FLAGS_IP_CSUM) 497124821Swpaul ifp->if_capabilities |= IFCAP_RXCSUM; 498124821Swpaul if (nttc->nttc_v4rx & NDIS_TCPSUM_FLAGS_TCP_CSUM) 499124821Swpaul ifp->if_capabilities |= IFCAP_RXCSUM; 500124821Swpaul if (nttc->nttc_v4rx & NDIS_TCPSUM_FLAGS_UDP_CSUM) 501124821Swpaul ifp->if_capabilities |= IFCAP_RXCSUM; 502124821Swpaul 503124821Swpaul free(ntoh, M_TEMP); 504198786Srpaulo return (0); 505124821Swpaul} 506124821Swpaul 507171602Sthompsastatic int 508171602Sthompsandis_nettype_chan(uint32_t type) 509171602Sthompsa{ 510171602Sthompsa switch (type) { 511171602Sthompsa case NDIS_80211_NETTYPE_11FH: return (IEEE80211_CHAN_FHSS); 512171602Sthompsa case NDIS_80211_NETTYPE_11DS: return (IEEE80211_CHAN_B); 513171602Sthompsa case NDIS_80211_NETTYPE_11OFDM5: return (IEEE80211_CHAN_A); 514171602Sthompsa case NDIS_80211_NETTYPE_11OFDM24: return (IEEE80211_CHAN_G); 515171602Sthompsa } 516171602Sthompsa DPRINTF(("unknown channel nettype %d\n", type)); 517171602Sthompsa return (IEEE80211_CHAN_B); /* Default to 11B chan */ 518171602Sthompsa} 519171602Sthompsa 520171602Sthompsastatic int 521171602Sthompsandis_nettype_mode(uint32_t type) 522171602Sthompsa{ 523171602Sthompsa switch (type) { 524171602Sthompsa case NDIS_80211_NETTYPE_11FH: return (IEEE80211_MODE_FH); 525171602Sthompsa case NDIS_80211_NETTYPE_11DS: return (IEEE80211_MODE_11B); 526171602Sthompsa case NDIS_80211_NETTYPE_11OFDM5: return (IEEE80211_MODE_11A); 527171602Sthompsa case NDIS_80211_NETTYPE_11OFDM24: return (IEEE80211_MODE_11G); 528171602Sthompsa } 529171602Sthompsa DPRINTF(("unknown mode nettype %d\n", type)); 530171602Sthompsa return (IEEE80211_MODE_AUTO); 531171602Sthompsa} 532171602Sthompsa 533123474Swpaul/* 534123474Swpaul * Attach the interface. Allocate softc structures, do ifmedia 535123474Swpaul * setup and ethernet/BPF attach. 536123474Swpaul */ 537126706Swpaulint 538123474Swpaulndis_attach(dev) 539123474Swpaul device_t dev; 540123474Swpaul{ 541123474Swpaul u_char eaddr[ETHER_ADDR_LEN]; 542126706Swpaul struct ndis_softc *sc; 543142399Swpaul driver_object *pdrv; 544141524Swpaul device_object *pdo; 545124100Swpaul struct ifnet *ifp = NULL; 546178354Ssam int error = 0, len, mode; 547178354Ssam uint8_t bands = 0; 548171390Sthompsa int i; 549123474Swpaul 550123474Swpaul sc = device_get_softc(dev); 551123474Swpaul 552179723Scokane mtx_init(&sc->ndis_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 553179723Scokane MTX_DEF); 554151451Swpaul KeInitializeSpinLock(&sc->ndis_rxlock); 555189719Sweongyo KeInitializeSpinLock(&sc->ndisusb_tasklock); 556189488Sweongyo KeInitializeSpinLock(&sc->ndisusb_xferdonelock); 557151207Swpaul InitializeListHead(&sc->ndis_shlist); 558189719Sweongyo InitializeListHead(&sc->ndisusb_tasklist); 559189488Sweongyo InitializeListHead(&sc->ndisusb_xferdonelist); 560179498Scokane callout_init(&sc->ndis_stat_callout, CALLOUT_MPSAFE); 561123474Swpaul 562132953Swpaul if (sc->ndis_iftype == PCMCIABus) { 563132953Swpaul error = ndis_alloc_amem(sc); 564132953Swpaul if (error) { 565132953Swpaul device_printf(dev, "failed to allocate " 566132953Swpaul "attribute memory\n"); 567132953Swpaul goto fail; 568132953Swpaul } 569132953Swpaul } 570132953Swpaul 571123474Swpaul /* Create sysctl registry nodes */ 572123474Swpaul ndis_create_sysctls(sc); 573123474Swpaul 574142399Swpaul /* Find the PDO for this device instance. */ 575142399Swpaul 576142399Swpaul if (sc->ndis_iftype == PCIBus) 577142804Swpaul pdrv = windrv_lookup(0, "PCI Bus"); 578142399Swpaul else if (sc->ndis_iftype == PCMCIABus) 579142804Swpaul pdrv = windrv_lookup(0, "PCCARD Bus"); 580142399Swpaul else 581142804Swpaul pdrv = windrv_lookup(0, "USB Bus"); 582142399Swpaul pdo = windrv_find_pdo(pdrv, dev); 583142399Swpaul 584141524Swpaul /* 585141524Swpaul * Create a new functional device object for this 586141524Swpaul * device. This is what creates the miniport block 587141524Swpaul * for this device instance. 588141524Swpaul */ 589141524Swpaul 590145485Swpaul if (NdisAddDevice(sc->ndis_dobj, pdo) != STATUS_SUCCESS) { 591141524Swpaul device_printf(dev, "failed to create FDO!\n"); 592141524Swpaul error = ENXIO; 593141524Swpaul goto fail; 594141524Swpaul } 595123474Swpaul 596124116Swpaul /* Tell the user what version of the API the driver is using. */ 597124116Swpaul device_printf(dev, "NDIS API version: %d.%d\n", 598141524Swpaul sc->ndis_chars->nmc_version_major, 599141524Swpaul sc->ndis_chars->nmc_version_minor); 600124116Swpaul 601123474Swpaul /* Do resource conversion. */ 602142399Swpaul if (sc->ndis_iftype == PCMCIABus || sc->ndis_iftype == PCIBus) 603142399Swpaul ndis_convert_res(sc); 604142408Swpaul else 605142408Swpaul sc->ndis_block->nmb_rlist = NULL; 606123474Swpaul 607123474Swpaul /* Install our RX and TX interrupt handlers. */ 608141963Swpaul sc->ndis_block->nmb_senddone_func = ndis_txeof_wrap; 609141963Swpaul sc->ndis_block->nmb_pktind_func = ndis_rxeof_wrap; 610146230Swpaul sc->ndis_block->nmb_ethrxindicate_func = ndis_rxeof_eth_wrap; 611146230Swpaul sc->ndis_block->nmb_ethrxdone_func = ndis_rxeof_done_wrap; 612146230Swpaul sc->ndis_block->nmb_tdcond_func = ndis_rxeof_xfr_done_wrap; 613123474Swpaul 614155311Swpaul /* Override the status handler so we can detect link changes. */ 615155311Swpaul sc->ndis_block->nmb_status_func = ndis_linksts_wrap; 616155311Swpaul sc->ndis_block->nmb_statusdone_func = ndis_linksts_done_wrap; 617155311Swpaul 618155311Swpaul /* Set up work item handlers. */ 619155311Swpaul sc->ndis_tickitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj); 620155311Swpaul sc->ndis_startitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj); 621155311Swpaul sc->ndis_resetitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj); 622155311Swpaul sc->ndis_inputitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj); 623189488Sweongyo sc->ndisusb_xferdoneitem = 624189488Sweongyo IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj); 625189719Sweongyo sc->ndisusb_taskitem = 626189719Sweongyo IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj); 627155311Swpaul KeInitializeDpc(&sc->ndis_rxdpc, ndis_rxeof_xfr_wrap, sc->ndis_block); 628155311Swpaul 629123474Swpaul /* Call driver's init routine. */ 630123474Swpaul if (ndis_init_nic(sc)) { 631198786Srpaulo device_printf(dev, "init handler failed\n"); 632123474Swpaul error = ENXIO; 633123474Swpaul goto fail; 634123474Swpaul } 635123474Swpaul 636126833Swpaul /* 637123474Swpaul * Get station address from the driver. 638123474Swpaul */ 639123474Swpaul len = sizeof(eaddr); 640123474Swpaul ndis_get_info(sc, OID_802_3_CURRENT_ADDRESS, &eaddr, &len); 641123474Swpaul 642123474Swpaul /* 643151207Swpaul * Figure out how big to make the TX buffer pool. 644123474Swpaul */ 645123474Swpaul 646151207Swpaul len = sizeof(sc->ndis_maxpkts); 647151207Swpaul if (ndis_get_info(sc, OID_GEN_MAXIMUM_SEND_PACKETS, 648151207Swpaul &sc->ndis_maxpkts, &len)) { 649198786Srpaulo device_printf(dev, "failed to get max TX packets\n"); 650151207Swpaul error = ENXIO; 651151207Swpaul goto fail; 652123474Swpaul } 653123474Swpaul 654151451Swpaul /* 655151451Swpaul * If this is a deserialized miniport, we don't have 656151451Swpaul * to honor the OID_GEN_MAXIMUM_SEND_PACKETS result. 657151451Swpaul */ 658151451Swpaul if (!NDIS_SERIALIZED(sc->ndis_block)) 659151451Swpaul sc->ndis_maxpkts = NDIS_TXPKTS; 660151451Swpaul 661151207Swpaul /* Enforce some sanity, just in case. */ 662151207Swpaul 663151207Swpaul if (sc->ndis_maxpkts == 0) 664151207Swpaul sc->ndis_maxpkts = 10; 665151207Swpaul 666125377Swpaul sc->ndis_txarray = malloc(sizeof(ndis_packet *) * 667183587Sweongyo sc->ndis_maxpkts, M_DEVBUF, M_NOWAIT|M_ZERO); 668125377Swpaul 669141963Swpaul /* Allocate a pool of ndis_packets for TX encapsulation. */ 670141963Swpaul 671141963Swpaul NdisAllocatePacketPool(&i, &sc->ndis_txpool, 672183587Sweongyo sc->ndis_maxpkts, PROTOCOL_RESERVED_SIZE_IN_PACKET); 673141963Swpaul 674141963Swpaul if (i != NDIS_STATUS_SUCCESS) { 675141963Swpaul sc->ndis_txpool = NULL; 676141963Swpaul device_printf(dev, "failed to allocate TX packet pool"); 677141963Swpaul error = ENOMEM; 678141963Swpaul goto fail; 679141963Swpaul } 680141963Swpaul 681123474Swpaul sc->ndis_txpending = sc->ndis_maxpkts; 682123474Swpaul 683123474Swpaul sc->ndis_oidcnt = 0; 684123474Swpaul /* Get supported oid list. */ 685123474Swpaul ndis_get_supported_oids(sc, &sc->ndis_oids, &sc->ndis_oidcnt); 686123474Swpaul 687123474Swpaul /* If the NDIS module requested scatter/gather, init maps. */ 688123474Swpaul if (sc->ndis_sc) 689123474Swpaul ndis_init_dma(sc); 690123474Swpaul 691123695Swpaul /* 692125309Swpaul * See if the OID_802_11_CONFIGURATION OID is 693123695Swpaul * supported by this driver. If it is, then this an 802.11 694123695Swpaul * wireless driver, and we should set up media for wireless. 695123695Swpaul */ 696198786Srpaulo for (i = 0; i < sc->ndis_oidcnt; i++) 697125309Swpaul if (sc->ndis_oids[i] == OID_802_11_CONFIGURATION) { 698123695Swpaul sc->ndis_80211++; 699123695Swpaul break; 700123695Swpaul } 701123474Swpaul 702178354Ssam if (sc->ndis_80211) 703178354Ssam ifp = if_alloc(IFT_IEEE80211); 704178354Ssam else 705178354Ssam ifp = if_alloc(IFT_ETHER); 706178354Ssam if (ifp == NULL) { 707178354Ssam error = ENOSPC; 708178354Ssam goto fail; 709178354Ssam } 710178354Ssam sc->ifp = ifp; 711178354Ssam ifp->if_softc = sc; 712178354Ssam 713124821Swpaul /* Check for task offload support. */ 714124821Swpaul ndis_probe_offload(sc); 715124821Swpaul 716123474Swpaul if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 717123474Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 718123474Swpaul ifp->if_ioctl = ndis_ioctl; 719123474Swpaul ifp->if_start = ndis_start; 720123474Swpaul ifp->if_init = ndis_init; 721123474Swpaul ifp->if_baudrate = 10000000; 722132986Smlaier IFQ_SET_MAXLEN(&ifp->if_snd, 50); 723132986Smlaier ifp->if_snd.ifq_drv_maxlen = 25; 724132986Smlaier IFQ_SET_READY(&ifp->if_snd); 725124821Swpaul ifp->if_capenable = ifp->if_capabilities; 726124821Swpaul ifp->if_hwassist = sc->ndis_hwassist; 727123474Swpaul 728123695Swpaul /* Do media setup */ 729123695Swpaul if (sc->ndis_80211) { 730178354Ssam struct ieee80211com *ic = ifp->if_l2com; 731130051Swpaul ndis_80211_rates_ex rates; 732124409Swpaul struct ndis_80211_nettype_list *ntl; 733123695Swpaul uint32_t arg; 734123695Swpaul int r; 735123695Swpaul 736191746Sthompsa callout_init(&sc->ndis_scan_callout, CALLOUT_MPSAFE); 737171390Sthompsa 738178704Sthompsa ifp->if_ioctl = ndis_ioctl_80211; 739138572Ssam ic->ic_ifp = ifp; 740178354Ssam ic->ic_opmode = IEEE80211_M_STA; 741123695Swpaul ic->ic_phytype = IEEE80211_T_DS; 742190850Ssam ic->ic_caps = IEEE80211_C_8023ENCAP | 743190850Ssam IEEE80211_C_STA | IEEE80211_C_IBSS; 744167468Ssam setbit(ic->ic_modecaps, IEEE80211_MODE_AUTO); 745124409Swpaul len = 0; 746124409Swpaul r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED, 747124409Swpaul NULL, &len); 748124409Swpaul if (r != ENOSPC) 749124409Swpaul goto nonettypes; 750151207Swpaul ntl = malloc(len, M_DEVBUF, M_NOWAIT|M_ZERO); 751124409Swpaul r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED, 752124409Swpaul ntl, &len); 753124409Swpaul if (r != 0) { 754124409Swpaul free(ntl, M_DEVBUF); 755124409Swpaul goto nonettypes; 756124409Swpaul } 757124409Swpaul 758124409Swpaul for (i = 0; i < ntl->ntl_items; i++) { 759171602Sthompsa mode = ndis_nettype_mode(ntl->ntl_type[i]); 760171602Sthompsa if (mode) { 761171602Sthompsa setbit(ic->ic_modecaps, mode); 762171602Sthompsa setbit(&bands, mode); 763171602Sthompsa } else 764171602Sthompsa device_printf(dev, "Unknown nettype %d\n", 765171602Sthompsa ntl->ntl_type[i]); 766124409Swpaul } 767124409Swpaul free(ntl, M_DEVBUF); 768124409Swpaulnonettypes: 769171602Sthompsa /* Default to 11b channels if the card did not supply any */ 770171602Sthompsa if (bands == 0) { 771171602Sthompsa setbit(ic->ic_modecaps, IEEE80211_MODE_11B); 772171602Sthompsa setbit(&bands, IEEE80211_MODE_11B); 773171602Sthompsa } 774123695Swpaul len = sizeof(rates); 775123695Swpaul bzero((char *)&rates, len); 776123695Swpaul r = ndis_get_info(sc, OID_802_11_SUPPORTED_RATES, 777123695Swpaul (void *)rates, &len); 778123695Swpaul if (r) 779198786Srpaulo device_printf(dev, "get rates failed: 0x%x\n", r); 780123695Swpaul /* 781124409Swpaul * Since the supported rates only up to 8 can be supported, 782124409Swpaul * if this is not 802.11b we're just going to be faking it 783124409Swpaul * all up to heck. 784123695Swpaul */ 785127887Swpaul 786127887Swpaul#define TESTSETRATE(x, y) \ 787127887Swpaul do { \ 788127887Swpaul int i; \ 789127887Swpaul for (i = 0; i < ic->ic_sup_rates[x].rs_nrates; i++) { \ 790127887Swpaul if (ic->ic_sup_rates[x].rs_rates[i] == (y)) \ 791127887Swpaul break; \ 792127887Swpaul } \ 793127887Swpaul if (i == ic->ic_sup_rates[x].rs_nrates) { \ 794127887Swpaul ic->ic_sup_rates[x].rs_rates[i] = (y); \ 795127887Swpaul ic->ic_sup_rates[x].rs_nrates++; \ 796127887Swpaul } \ 797127887Swpaul } while (0) 798127887Swpaul 799123695Swpaul#define SETRATE(x, y) \ 800124409Swpaul ic->ic_sup_rates[x].rs_rates[ic->ic_sup_rates[x].rs_nrates] = (y) 801123695Swpaul#define INCRATE(x) \ 802124409Swpaul ic->ic_sup_rates[x].rs_nrates++ 803123695Swpaul 804124409Swpaul ic->ic_curmode = IEEE80211_MODE_AUTO; 805167468Ssam if (isset(ic->ic_modecaps, IEEE80211_MODE_11A)) 806124409Swpaul ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates = 0; 807167468Ssam if (isset(ic->ic_modecaps, IEEE80211_MODE_11B)) 808123695Swpaul ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates = 0; 809167468Ssam if (isset(ic->ic_modecaps, IEEE80211_MODE_11G)) 810123695Swpaul ic->ic_sup_rates[IEEE80211_MODE_11G].rs_nrates = 0; 811124409Swpaul for (i = 0; i < len; i++) { 812124409Swpaul switch (rates[i] & IEEE80211_RATE_VAL) { 813124409Swpaul case 2: 814124409Swpaul case 4: 815124409Swpaul case 11: 816124409Swpaul case 10: 817124409Swpaul case 22: 818167468Ssam if (isclr(ic->ic_modecaps, IEEE80211_MODE_11B)) { 819124409Swpaul /* Lazy-init 802.11b. */ 820167468Ssam setbit(ic->ic_modecaps, 821167468Ssam IEEE80211_MODE_11B); 822124409Swpaul ic->ic_sup_rates[IEEE80211_MODE_11B]. 823124409Swpaul rs_nrates = 0; 824124409Swpaul } 825124409Swpaul SETRATE(IEEE80211_MODE_11B, rates[i]); 826124409Swpaul INCRATE(IEEE80211_MODE_11B); 827124409Swpaul break; 828124409Swpaul default: 829167468Ssam if (isset(ic->ic_modecaps, IEEE80211_MODE_11A)) { 830124409Swpaul SETRATE(IEEE80211_MODE_11A, rates[i]); 831124409Swpaul INCRATE(IEEE80211_MODE_11A); 832124409Swpaul } 833167468Ssam if (isset(ic->ic_modecaps, IEEE80211_MODE_11G)) { 834123695Swpaul SETRATE(IEEE80211_MODE_11G, rates[i]); 835123695Swpaul INCRATE(IEEE80211_MODE_11G); 836123695Swpaul } 837124409Swpaul break; 838123695Swpaul } 839124409Swpaul } 840123695Swpaul 841124409Swpaul /* 842124409Swpaul * If the hardware supports 802.11g, it most 843124409Swpaul * likely supports 802.11b and all of the 844124409Swpaul * 802.11b and 802.11g speeds, so maybe we can 845124409Swpaul * just cheat here. Just how in the heck do 846124409Swpaul * we detect turbo modes, though? 847124409Swpaul */ 848167468Ssam if (isset(ic->ic_modecaps, IEEE80211_MODE_11B)) { 849130051Swpaul TESTSETRATE(IEEE80211_MODE_11B, 850130051Swpaul IEEE80211_RATE_BASIC|2); 851130051Swpaul TESTSETRATE(IEEE80211_MODE_11B, 852130051Swpaul IEEE80211_RATE_BASIC|4); 853130051Swpaul TESTSETRATE(IEEE80211_MODE_11B, 854130051Swpaul IEEE80211_RATE_BASIC|11); 855130051Swpaul TESTSETRATE(IEEE80211_MODE_11B, 856130051Swpaul IEEE80211_RATE_BASIC|22); 857129834Swpaul } 858167468Ssam if (isset(ic->ic_modecaps, IEEE80211_MODE_11G)) { 859186919Sweongyo TESTSETRATE(IEEE80211_MODE_11G, 48); 860127887Swpaul TESTSETRATE(IEEE80211_MODE_11G, 72); 861127887Swpaul TESTSETRATE(IEEE80211_MODE_11G, 96); 862127887Swpaul TESTSETRATE(IEEE80211_MODE_11G, 108); 863123695Swpaul } 864167468Ssam if (isset(ic->ic_modecaps, IEEE80211_MODE_11A)) { 865186919Sweongyo TESTSETRATE(IEEE80211_MODE_11A, 48); 866127887Swpaul TESTSETRATE(IEEE80211_MODE_11A, 72); 867127887Swpaul TESTSETRATE(IEEE80211_MODE_11A, 96); 868127887Swpaul TESTSETRATE(IEEE80211_MODE_11A, 108); 869124409Swpaul } 870123695Swpaul#undef SETRATE 871123695Swpaul#undef INCRATE 872178354Ssam ieee80211_init_channels(ic, NULL, &bands); 873124409Swpaul 874151207Swpaul /* 875151207Swpaul * To test for WPA support, we need to see if we can 876151207Swpaul * set AUTHENTICATION_MODE to WPA and read it back 877151207Swpaul * successfully. 878151207Swpaul */ 879123695Swpaul i = sizeof(arg); 880151207Swpaul arg = NDIS_80211_AUTHMODE_WPA; 881151207Swpaul r = ndis_set_info(sc, 882151207Swpaul OID_802_11_AUTHENTICATION_MODE, &arg, &i); 883151207Swpaul if (r == 0) { 884151207Swpaul r = ndis_get_info(sc, 885151207Swpaul OID_802_11_AUTHENTICATION_MODE, &arg, &i); 886151207Swpaul if (r == 0 && arg == NDIS_80211_AUTHMODE_WPA) 887151207Swpaul ic->ic_caps |= IEEE80211_C_WPA; 888151207Swpaul } 889151207Swpaul 890151207Swpaul /* 891151207Swpaul * To test for supported ciphers, we set each 892151207Swpaul * available encryption type in descending order. 893151207Swpaul * If ENC3 works, then we have WEP, TKIP and AES. 894151207Swpaul * If only ENC2 works, then we have WEP and TKIP. 895151207Swpaul * If only ENC1 works, then we have just WEP. 896151207Swpaul */ 897151207Swpaul i = sizeof(arg); 898151207Swpaul arg = NDIS_80211_WEPSTAT_ENC3ENABLED; 899151207Swpaul r = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &i); 900151207Swpaul if (r == 0) { 901178354Ssam ic->ic_cryptocaps |= IEEE80211_CRYPTO_WEP 902178354Ssam | IEEE80211_CRYPTO_TKIP 903178354Ssam | IEEE80211_CRYPTO_AES_CCM; 904151207Swpaul goto got_crypto; 905151207Swpaul } 906151207Swpaul arg = NDIS_80211_WEPSTAT_ENC2ENABLED; 907151207Swpaul r = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &i); 908151207Swpaul if (r == 0) { 909178354Ssam ic->ic_cryptocaps |= IEEE80211_CRYPTO_WEP 910178354Ssam | IEEE80211_CRYPTO_TKIP; 911151207Swpaul goto got_crypto; 912151207Swpaul } 913151207Swpaul arg = NDIS_80211_WEPSTAT_ENC1ENABLED; 914151207Swpaul r = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &i); 915151207Swpaul if (r == 0) 916178354Ssam ic->ic_cryptocaps |= IEEE80211_CRYPTO_WEP; 917151207Swpaulgot_crypto: 918124409Swpaul i = sizeof(arg); 919124409Swpaul r = ndis_get_info(sc, OID_802_11_POWER_MODE, &arg, &i); 920124409Swpaul if (r == 0) 921124409Swpaul ic->ic_caps |= IEEE80211_C_PMGT; 922189550Ssam 923189550Ssam r = ndis_get_info(sc, OID_802_11_TX_POWER_LEVEL, &arg, &i); 924189550Ssam if (r == 0) 925189550Ssam ic->ic_caps |= IEEE80211_C_TXPMGT; 926189550Ssam 927190526Ssam ieee80211_ifattach(ic, eaddr); 928178354Ssam ic->ic_raw_xmit = ndis_raw_xmit; 929171390Sthompsa ic->ic_scan_start = ndis_scan_start; 930171390Sthompsa ic->ic_scan_end = ndis_scan_end; 931171390Sthompsa ic->ic_set_channel = ndis_set_channel; 932171390Sthompsa ic->ic_scan_curchan = ndis_scan_curchan; 933171390Sthompsa ic->ic_scan_mindwell = ndis_scan_mindwell; 934170530Ssam ic->ic_bsschan = IEEE80211_CHAN_ANYC; 935178354Ssam //ic->ic_bss->ni_chan = ic->ic_bsschan; 936178354Ssam ic->ic_vap_create = ndis_vap_create; 937178354Ssam ic->ic_vap_delete = ndis_vap_delete; 938185485Ssam ic->ic_update_mcast = ndis_update_mcast; 939185485Ssam ic->ic_update_promisc = ndis_update_promisc; 940178354Ssam 941194706Scokane if (bootverbose) 942194706Scokane ieee80211_announce(ic); 943194706Scokane 944123695Swpaul } else { 945123695Swpaul ifmedia_init(&sc->ifmedia, IFM_IMASK, ndis_ifmedia_upd, 946123695Swpaul ndis_ifmedia_sts); 947123695Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); 948123695Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); 949123695Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); 950123695Swpaul ifmedia_add(&sc->ifmedia, 951123695Swpaul IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); 952123695Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); 953123695Swpaul ifmedia_set(&sc->ifmedia, IFM_ETHER|IFM_AUTO); 954124409Swpaul ether_ifattach(ifp, eaddr); 955123695Swpaul } 956123695Swpaul 957123474Swpaulfail: 958186507Sweongyo if (error) { 959123474Swpaul ndis_detach(dev); 960186507Sweongyo return (error); 961186507Sweongyo } 962123474Swpaul 963186507Sweongyo if (sc->ndis_iftype == PNPBus && ndisusb_halt == 0) 964186507Sweongyo return (error); 965186507Sweongyo 966189488Sweongyo DPRINTF(("attach done.\n")); 967186507Sweongyo /* We're done talking to the NIC for now; halt it. */ 968186507Sweongyo ndis_halt_nic(sc); 969189488Sweongyo DPRINTF(("halting done.\n")); 970186507Sweongyo 971198786Srpaulo return (error); 972123474Swpaul} 973123474Swpaul 974178354Ssamstatic struct ieee80211vap * 975228621Sbschmidtndis_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, 976228621Sbschmidt enum ieee80211_opmode opmode, int flags, 977228621Sbschmidt const uint8_t bssid[IEEE80211_ADDR_LEN], 978228621Sbschmidt const uint8_t mac[IEEE80211_ADDR_LEN]) 979178354Ssam{ 980178354Ssam struct ndis_vap *nvp; 981178354Ssam struct ieee80211vap *vap; 982178354Ssam 983178354Ssam if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ 984178354Ssam return NULL; 985178354Ssam nvp = (struct ndis_vap *) malloc(sizeof(struct ndis_vap), 986178354Ssam M_80211_VAP, M_NOWAIT | M_ZERO); 987178354Ssam if (nvp == NULL) 988178354Ssam return NULL; 989178354Ssam vap = &nvp->vap; 990178354Ssam ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); 991178354Ssam /* override with driver methods */ 992178354Ssam nvp->newstate = vap->iv_newstate; 993178354Ssam vap->iv_newstate = ndis_newstate; 994178354Ssam 995178354Ssam /* complete setup */ 996201620Srpaulo ieee80211_vap_attach(vap, ieee80211_media_change, ndis_media_status); 997178354Ssam ic->ic_opmode = opmode; 998178354Ssam /* install key handing routines */ 999178354Ssam vap->iv_key_set = ndis_add_key; 1000178354Ssam vap->iv_key_delete = ndis_del_key; 1001178354Ssam return vap; 1002178354Ssam} 1003178354Ssam 1004178354Ssamstatic void 1005178354Ssamndis_vap_delete(struct ieee80211vap *vap) 1006178354Ssam{ 1007178354Ssam struct ndis_vap *nvp = NDIS_VAP(vap); 1008197403Scokane struct ieee80211com *ic = vap->iv_ic; 1009197403Scokane struct ifnet *ifp = ic->ic_ifp; 1010197403Scokane struct ndis_softc *sc = ifp->if_softc; 1011178354Ssam 1012197403Scokane ndis_stop(sc); 1013197403Scokane callout_drain(&sc->ndis_scan_callout); 1014178354Ssam ieee80211_vap_detach(vap); 1015178354Ssam free(nvp, M_80211_VAP); 1016178354Ssam} 1017178354Ssam 1018123474Swpaul/* 1019123474Swpaul * Shutdown hardware and free up resources. This can be called any 1020123474Swpaul * time after the mutex has been initialized. It is called in both 1021123474Swpaul * the error case in attach and the normal detach case so it needs 1022123474Swpaul * to be careful about only freeing resources that have actually been 1023123474Swpaul * allocated. 1024123474Swpaul */ 1025126706Swpaulint 1026123474Swpaulndis_detach(dev) 1027123474Swpaul device_t dev; 1028123474Swpaul{ 1029123757Swpaul struct ndis_softc *sc; 1030123474Swpaul struct ifnet *ifp; 1031141524Swpaul driver_object *drv; 1032123474Swpaul 1033123474Swpaul sc = device_get_softc(dev); 1034123474Swpaul NDIS_LOCK(sc); 1035147256Sbrooks ifp = sc->ifp; 1036179424Sweongyo if (ifp != NULL) 1037179424Sweongyo ifp->if_flags &= ~IFF_UP; 1038123474Swpaul 1039123474Swpaul if (device_is_attached(dev)) { 1040123474Swpaul NDIS_UNLOCK(sc); 1041123474Swpaul ndis_stop(sc); 1042179424Sweongyo if (ifp != NULL) { 1043179424Sweongyo if (sc->ndis_80211) 1044179424Sweongyo ieee80211_ifdetach(ifp->if_l2com); 1045179424Sweongyo else 1046179424Sweongyo ether_ifdetach(ifp); 1047179424Sweongyo } 1048123695Swpaul } else 1049123695Swpaul NDIS_UNLOCK(sc); 1050123474Swpaul 1051151207Swpaul if (sc->ndis_tickitem != NULL) 1052151207Swpaul IoFreeWorkItem(sc->ndis_tickitem); 1053151207Swpaul if (sc->ndis_startitem != NULL) 1054151207Swpaul IoFreeWorkItem(sc->ndis_startitem); 1055151207Swpaul if (sc->ndis_resetitem != NULL) 1056151207Swpaul IoFreeWorkItem(sc->ndis_resetitem); 1057151451Swpaul if (sc->ndis_inputitem != NULL) 1058151451Swpaul IoFreeWorkItem(sc->ndis_inputitem); 1059189488Sweongyo if (sc->ndisusb_xferdoneitem != NULL) 1060189488Sweongyo IoFreeWorkItem(sc->ndisusb_xferdoneitem); 1061189719Sweongyo if (sc->ndisusb_taskitem != NULL) 1062189719Sweongyo IoFreeWorkItem(sc->ndisusb_taskitem); 1063151207Swpaul 1064123474Swpaul bus_generic_detach(dev); 1065171602Sthompsa ndis_unload_driver(sc); 1066123474Swpaul 1067123474Swpaul if (sc->ndis_irq) 1068123474Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ndis_irq); 1069123474Swpaul if (sc->ndis_res_io) 1070123474Swpaul bus_release_resource(dev, SYS_RES_IOPORT, 1071123474Swpaul sc->ndis_io_rid, sc->ndis_res_io); 1072123474Swpaul if (sc->ndis_res_mem) 1073123474Swpaul bus_release_resource(dev, SYS_RES_MEMORY, 1074123474Swpaul sc->ndis_mem_rid, sc->ndis_res_mem); 1075123976Swpaul if (sc->ndis_res_altmem) 1076123976Swpaul bus_release_resource(dev, SYS_RES_MEMORY, 1077123976Swpaul sc->ndis_altmem_rid, sc->ndis_res_altmem); 1078123474Swpaul 1079150306Simp if (ifp != NULL) 1080150306Simp if_free(ifp); 1081150306Simp 1082132953Swpaul if (sc->ndis_iftype == PCMCIABus) 1083132953Swpaul ndis_free_amem(sc); 1084132953Swpaul 1085123474Swpaul if (sc->ndis_sc) 1086123474Swpaul ndis_destroy_dma(sc); 1087123474Swpaul 1088133080Swpaul if (sc->ndis_txarray) 1089133080Swpaul free(sc->ndis_txarray, M_DEVBUF); 1090133080Swpaul 1091133080Swpaul if (!sc->ndis_80211) 1092133080Swpaul ifmedia_removeall(&sc->ifmedia); 1093133080Swpaul 1094141963Swpaul if (sc->ndis_txpool != NULL) 1095141963Swpaul NdisFreePacketPool(sc->ndis_txpool); 1096141963Swpaul 1097141524Swpaul /* Destroy the PDO for this device. */ 1098141524Swpaul 1099142399Swpaul if (sc->ndis_iftype == PCIBus) 1100142804Swpaul drv = windrv_lookup(0, "PCI Bus"); 1101142399Swpaul else if (sc->ndis_iftype == PCMCIABus) 1102142804Swpaul drv = windrv_lookup(0, "PCCARD Bus"); 1103142399Swpaul else 1104142804Swpaul drv = windrv_lookup(0, "USB Bus"); 1105141524Swpaul if (drv == NULL) 1106141524Swpaul panic("couldn't find driver object"); 1107141524Swpaul windrv_destroy_pdo(drv, dev); 1108141524Swpaul 1109126706Swpaul if (sc->ndis_iftype == PCIBus) 1110126706Swpaul bus_dma_tag_destroy(sc->ndis_parent_tag); 1111123474Swpaul 1112198786Srpaulo return (0); 1113123474Swpaul} 1114123474Swpaul 1115126706Swpaulint 1116124822Swpaulndis_suspend(dev) 1117124822Swpaul device_t dev; 1118124822Swpaul{ 1119124822Swpaul struct ndis_softc *sc; 1120124822Swpaul struct ifnet *ifp; 1121124822Swpaul 1122124822Swpaul sc = device_get_softc(dev); 1123147256Sbrooks ifp = sc->ifp; 1124124822Swpaul 1125125309Swpaul#ifdef notdef 1126131750Swpaul if (NDIS_INITIALIZED(sc)) 1127124822Swpaul ndis_stop(sc); 1128125309Swpaul#endif 1129124822Swpaul 1130198786Srpaulo return (0); 1131124822Swpaul} 1132124822Swpaul 1133126706Swpaulint 1134124822Swpaulndis_resume(dev) 1135124822Swpaul device_t dev; 1136124822Swpaul{ 1137124822Swpaul struct ndis_softc *sc; 1138124822Swpaul struct ifnet *ifp; 1139124822Swpaul 1140124822Swpaul sc = device_get_softc(dev); 1141147256Sbrooks ifp = sc->ifp; 1142124822Swpaul 1143131750Swpaul if (NDIS_INITIALIZED(sc)) 1144124822Swpaul ndis_init(sc); 1145124822Swpaul 1146198786Srpaulo return (0); 1147124822Swpaul} 1148124822Swpaul 1149123474Swpaul/* 1150146230Swpaul * The following bunch of routines are here to support drivers that 1151146230Swpaul * use the NdisMEthIndicateReceive()/MiniportTransferData() mechanism. 1152151451Swpaul * The NdisMEthIndicateReceive() handler runs at DISPATCH_LEVEL for 1153151451Swpaul * serialized miniports, or IRQL <= DISPATCH_LEVEL for deserialized 1154151451Swpaul * miniports. 1155146230Swpaul */ 1156146230Swpaulstatic void 1157146230Swpaulndis_rxeof_eth(adapter, ctx, addr, hdr, hdrlen, lookahead, lookaheadlen, pktlen) 1158146230Swpaul ndis_handle adapter; 1159146230Swpaul ndis_handle ctx; 1160146230Swpaul char *addr; 1161146230Swpaul void *hdr; 1162146230Swpaul uint32_t hdrlen; 1163146230Swpaul void *lookahead; 1164146230Swpaul uint32_t lookaheadlen; 1165146230Swpaul uint32_t pktlen; 1166146230Swpaul{ 1167146230Swpaul ndis_miniport_block *block; 1168169800Smjacob uint8_t irql = 0; 1169146230Swpaul uint32_t status; 1170146230Swpaul ndis_buffer *b; 1171146230Swpaul ndis_packet *p; 1172146230Swpaul struct mbuf *m; 1173146230Swpaul ndis_ethpriv *priv; 1174146230Swpaul 1175146230Swpaul block = adapter; 1176146230Swpaul 1177243857Sglebius m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 1178217118Sbschmidt if (m == NULL) 1179146230Swpaul return; 1180146230Swpaul 1181146230Swpaul /* Save the data provided to us so far. */ 1182146230Swpaul 1183146230Swpaul m->m_len = lookaheadlen + hdrlen; 1184146230Swpaul m->m_pkthdr.len = pktlen + hdrlen; 1185146230Swpaul m->m_next = NULL; 1186146230Swpaul m_copyback(m, 0, hdrlen, hdr); 1187146230Swpaul m_copyback(m, hdrlen, lookaheadlen, lookahead); 1188146230Swpaul 1189146230Swpaul /* Now create a fake NDIS_PACKET to hold the data */ 1190146230Swpaul 1191146230Swpaul NdisAllocatePacket(&status, &p, block->nmb_rxpool); 1192146230Swpaul 1193146230Swpaul if (status != NDIS_STATUS_SUCCESS) { 1194146230Swpaul m_freem(m); 1195146230Swpaul return; 1196146230Swpaul } 1197146230Swpaul 1198146230Swpaul p->np_m0 = m; 1199146230Swpaul 1200146230Swpaul b = IoAllocateMdl(m->m_data, m->m_pkthdr.len, FALSE, FALSE, NULL); 1201146230Swpaul 1202146230Swpaul if (b == NULL) { 1203146230Swpaul NdisFreePacket(p); 1204146230Swpaul m_freem(m); 1205146230Swpaul return; 1206146230Swpaul } 1207146230Swpaul 1208146230Swpaul p->np_private.npp_head = p->np_private.npp_tail = b; 1209146230Swpaul p->np_private.npp_totlen = m->m_pkthdr.len; 1210146230Swpaul 1211146230Swpaul /* Save the packet RX context somewhere. */ 1212146230Swpaul priv = (ndis_ethpriv *)&p->np_protocolreserved; 1213146230Swpaul priv->nep_ctx = ctx; 1214146230Swpaul 1215153480Swpaul if (!NDIS_SERIALIZED(block)) 1216153480Swpaul KeAcquireSpinLock(&block->nmb_lock, &irql); 1217146230Swpaul 1218151451Swpaul InsertTailList((&block->nmb_packetlist), (&p->np_list)); 1219146230Swpaul 1220153480Swpaul if (!NDIS_SERIALIZED(block)) 1221153480Swpaul KeReleaseSpinLock(&block->nmb_lock, irql); 1222146230Swpaul} 1223146230Swpaul 1224151451Swpaul/* 1225151451Swpaul * NdisMEthIndicateReceiveComplete() handler, runs at DISPATCH_LEVEL 1226151451Swpaul * for serialized miniports, or IRQL <= DISPATCH_LEVEL for deserialized 1227151451Swpaul * miniports. 1228151451Swpaul */ 1229146230Swpaulstatic void 1230146230Swpaulndis_rxeof_done(adapter) 1231146230Swpaul ndis_handle adapter; 1232146230Swpaul{ 1233146230Swpaul struct ndis_softc *sc; 1234146230Swpaul ndis_miniport_block *block; 1235146230Swpaul 1236146230Swpaul block = adapter; 1237146230Swpaul 1238146230Swpaul /* Schedule transfer/RX of queued packets. */ 1239146230Swpaul 1240146230Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1241146230Swpaul 1242146230Swpaul KeInsertQueueDpc(&sc->ndis_rxdpc, NULL, NULL); 1243146230Swpaul} 1244146230Swpaul 1245146230Swpaul/* 1246151451Swpaul * MiniportTransferData() handler, runs at DISPATCH_LEVEL. 1247146230Swpaul */ 1248146230Swpaulstatic void 1249146230Swpaulndis_rxeof_xfr(dpc, adapter, sysarg1, sysarg2) 1250146230Swpaul kdpc *dpc; 1251146230Swpaul ndis_handle adapter; 1252146230Swpaul void *sysarg1; 1253146230Swpaul void *sysarg2; 1254146230Swpaul{ 1255146230Swpaul ndis_miniport_block *block; 1256146230Swpaul struct ndis_softc *sc; 1257146230Swpaul ndis_packet *p; 1258146230Swpaul list_entry *l; 1259146230Swpaul uint32_t status; 1260146230Swpaul ndis_ethpriv *priv; 1261146230Swpaul struct ifnet *ifp; 1262146230Swpaul struct mbuf *m; 1263146230Swpaul 1264146230Swpaul block = adapter; 1265146230Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1266147256Sbrooks ifp = sc->ifp; 1267146230Swpaul 1268146230Swpaul KeAcquireSpinLockAtDpcLevel(&block->nmb_lock); 1269146230Swpaul 1270146230Swpaul l = block->nmb_packetlist.nle_flink; 1271151207Swpaul while(!IsListEmpty(&block->nmb_packetlist)) { 1272151207Swpaul l = RemoveHeadList((&block->nmb_packetlist)); 1273151451Swpaul p = CONTAINING_RECORD(l, ndis_packet, np_list); 1274151451Swpaul InitializeListHead((&p->np_list)); 1275146230Swpaul 1276146230Swpaul priv = (ndis_ethpriv *)&p->np_protocolreserved; 1277146230Swpaul m = p->np_m0; 1278146230Swpaul p->np_softc = sc; 1279146230Swpaul p->np_m0 = NULL; 1280146230Swpaul 1281146230Swpaul KeReleaseSpinLockFromDpcLevel(&block->nmb_lock); 1282146230Swpaul 1283146230Swpaul status = MSCALL6(sc->ndis_chars->nmc_transferdata_func, 1284146230Swpaul p, &p->np_private.npp_totlen, block, priv->nep_ctx, 1285146230Swpaul m->m_len, m->m_pkthdr.len - m->m_len); 1286146230Swpaul 1287146230Swpaul KeAcquireSpinLockAtDpcLevel(&block->nmb_lock); 1288146230Swpaul 1289146230Swpaul /* 1290146230Swpaul * If status is NDIS_STATUS_PENDING, do nothing and 1291146230Swpaul * wait for a callback to the ndis_rxeof_xfr_done() 1292146230Swpaul * handler. 1293146230Swpaul */ 1294146230Swpaul 1295146230Swpaul m->m_len = m->m_pkthdr.len; 1296146230Swpaul m->m_pkthdr.rcvif = ifp; 1297146230Swpaul 1298146230Swpaul if (status == NDIS_STATUS_SUCCESS) { 1299146230Swpaul IoFreeMdl(p->np_private.npp_head); 1300146230Swpaul NdisFreePacket(p); 1301151451Swpaul KeAcquireSpinLockAtDpcLevel(&sc->ndis_rxlock); 1302151451Swpaul _IF_ENQUEUE(&sc->ndis_rxqueue, m); 1303151451Swpaul KeReleaseSpinLockFromDpcLevel(&sc->ndis_rxlock); 1304151451Swpaul IoQueueWorkItem(sc->ndis_inputitem, 1305151451Swpaul (io_workitem_func)ndis_inputtask_wrap, 1306151451Swpaul WORKQUEUE_CRITICAL, ifp); 1307146230Swpaul } 1308146230Swpaul 1309146230Swpaul if (status == NDIS_STATUS_FAILURE) 1310146230Swpaul m_freem(m); 1311146230Swpaul 1312146230Swpaul /* Advance to next packet */ 1313146230Swpaul l = block->nmb_packetlist.nle_flink; 1314146230Swpaul } 1315146230Swpaul 1316146230Swpaul KeReleaseSpinLockFromDpcLevel(&block->nmb_lock); 1317146230Swpaul} 1318146230Swpaul 1319151451Swpaul/* 1320151451Swpaul * NdisMTransferDataComplete() handler, runs at DISPATCH_LEVEL. 1321151451Swpaul */ 1322146230Swpaulstatic void 1323146230Swpaulndis_rxeof_xfr_done(adapter, packet, status, len) 1324146230Swpaul ndis_handle adapter; 1325146230Swpaul ndis_packet *packet; 1326146230Swpaul uint32_t status; 1327146230Swpaul uint32_t len; 1328146230Swpaul{ 1329146230Swpaul ndis_miniport_block *block; 1330146230Swpaul struct ndis_softc *sc; 1331146230Swpaul struct ifnet *ifp; 1332146230Swpaul struct mbuf *m; 1333146230Swpaul 1334146230Swpaul block = adapter; 1335146230Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1336147256Sbrooks ifp = sc->ifp; 1337146230Swpaul 1338146230Swpaul m = packet->np_m0; 1339146230Swpaul IoFreeMdl(packet->np_private.npp_head); 1340146230Swpaul NdisFreePacket(packet); 1341146230Swpaul 1342146230Swpaul if (status != NDIS_STATUS_SUCCESS) { 1343146230Swpaul m_freem(m); 1344146230Swpaul return; 1345146230Swpaul } 1346146230Swpaul 1347146230Swpaul m->m_len = m->m_pkthdr.len; 1348146230Swpaul m->m_pkthdr.rcvif = ifp; 1349151451Swpaul KeAcquireSpinLockAtDpcLevel(&sc->ndis_rxlock); 1350151451Swpaul _IF_ENQUEUE(&sc->ndis_rxqueue, m); 1351151451Swpaul KeReleaseSpinLockFromDpcLevel(&sc->ndis_rxlock); 1352151451Swpaul IoQueueWorkItem(sc->ndis_inputitem, 1353151451Swpaul (io_workitem_func)ndis_inputtask_wrap, 1354151451Swpaul WORKQUEUE_CRITICAL, ifp); 1355146230Swpaul} 1356146230Swpaul/* 1357123474Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 1358123474Swpaul * the higher level protocols. 1359123858Swpaul * 1360123858Swpaul * When handling received NDIS packets, the 'status' field in the 1361123858Swpaul * out-of-band portion of the ndis_packet has special meaning. In the 1362123858Swpaul * most common case, the underlying NDIS driver will set this field 1363123858Swpaul * to NDIS_STATUS_SUCCESS, which indicates that it's ok for us to 1364123858Swpaul * take posession of it. We then change the status field to 1365123858Swpaul * NDIS_STATUS_PENDING to tell the driver that we now own the packet, 1366123858Swpaul * and that we will return it at some point in the future via the 1367123858Swpaul * return packet handler. 1368123858Swpaul * 1369123858Swpaul * If the driver hands us a packet with a status of NDIS_STATUS_RESOURCES, 1370123858Swpaul * this means the driver is running out of packet/buffer resources and 1371123858Swpaul * wants to maintain ownership of the packet. In this case, we have to 1372123858Swpaul * copy the packet data into local storage and let the driver keep the 1373123858Swpaul * packet. 1374126833Swpaul */ 1375144888Swpaulstatic void 1376128510Swpaulndis_rxeof(adapter, packets, pktcnt) 1377126833Swpaul ndis_handle adapter; 1378126833Swpaul ndis_packet **packets; 1379126833Swpaul uint32_t pktcnt; 1380126833Swpaul{ 1381126833Swpaul struct ndis_softc *sc; 1382126833Swpaul ndis_miniport_block *block; 1383126833Swpaul ndis_packet *p; 1384126833Swpaul uint32_t s; 1385126833Swpaul ndis_tcpip_csum *csum; 1386126833Swpaul struct ifnet *ifp; 1387126833Swpaul struct mbuf *m0, *m; 1388126833Swpaul int i; 1389126833Swpaul 1390126833Swpaul block = (ndis_miniport_block *)adapter; 1391141524Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1392147256Sbrooks ifp = sc->ifp; 1393126833Swpaul 1394155311Swpaul /* 1395155311Swpaul * There's a slim chance the driver may indicate some packets 1396155311Swpaul * before we're completely ready to handle them. If we detect this, 1397155311Swpaul * we need to return them to the miniport and ignore them. 1398155311Swpaul */ 1399155311Swpaul if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1400155311Swpaul for (i = 0; i < pktcnt; i++) { 1401155311Swpaul p = packets[i]; 1402155311Swpaul if (p->np_oob.npo_status == NDIS_STATUS_SUCCESS) { 1403155311Swpaul p->np_refcnt++; 1404254842Sandre (void)ndis_return_packet(NULL ,p, block); 1405155311Swpaul } 1406155311Swpaul } 1407155311Swpaul return; 1408155311Swpaul } 1409155311Swpaul 1410126833Swpaul for (i = 0; i < pktcnt; i++) { 1411126833Swpaul p = packets[i]; 1412126833Swpaul /* Stash the softc here so ptom can use it. */ 1413126833Swpaul p->np_softc = sc; 1414126833Swpaul if (ndis_ptom(&m0, p)) { 1415198786Srpaulo device_printf(sc->ndis_dev, "ptom failed\n"); 1416126833Swpaul if (p->np_oob.npo_status == NDIS_STATUS_SUCCESS) 1417254842Sandre (void)ndis_return_packet(NULL, p, block); 1418126833Swpaul } else { 1419151207Swpaul#ifdef notdef 1420126833Swpaul if (p->np_oob.npo_status == NDIS_STATUS_RESOURCES) { 1421243857Sglebius m = m_dup(m0, M_NOWAIT); 1422126833Swpaul /* 1423126833Swpaul * NOTE: we want to destroy the mbuf here, but 1424126833Swpaul * we don't actually want to return it to the 1425126833Swpaul * driver via the return packet handler. By 1426126833Swpaul * bumping np_refcnt, we can prevent the 1427126833Swpaul * ndis_return_packet() routine from actually 1428126833Swpaul * doing anything. 1429126833Swpaul */ 1430126833Swpaul p->np_refcnt++; 1431126833Swpaul m_freem(m0); 1432126833Swpaul if (m == NULL) 1433126833Swpaul ifp->if_ierrors++; 1434126833Swpaul else 1435126833Swpaul m0 = m; 1436126833Swpaul } else 1437126833Swpaul p->np_oob.npo_status = NDIS_STATUS_PENDING; 1438151207Swpaul#endif 1439243857Sglebius m = m_dup(m0, M_NOWAIT); 1440151207Swpaul if (p->np_oob.npo_status == NDIS_STATUS_RESOURCES) 1441151207Swpaul p->np_refcnt++; 1442151207Swpaul else 1443151207Swpaul p->np_oob.npo_status = NDIS_STATUS_PENDING; 1444151207Swpaul m_freem(m0); 1445151207Swpaul if (m == NULL) { 1446151207Swpaul ifp->if_ierrors++; 1447151207Swpaul continue; 1448151207Swpaul } 1449151207Swpaul m0 = m; 1450126833Swpaul m0->m_pkthdr.rcvif = ifp; 1451126833Swpaul 1452126833Swpaul /* Deal with checksum offload. */ 1453126833Swpaul 1454126833Swpaul if (ifp->if_capenable & IFCAP_RXCSUM && 1455126833Swpaul p->np_ext.npe_info[ndis_tcpipcsum_info] != NULL) { 1456126833Swpaul s = (uintptr_t) 1457126833Swpaul p->np_ext.npe_info[ndis_tcpipcsum_info]; 1458126833Swpaul csum = (ndis_tcpip_csum *)&s; 1459126833Swpaul if (csum->u.ntc_rxflags & 1460126833Swpaul NDIS_RXCSUM_IP_PASSED) 1461126833Swpaul m0->m_pkthdr.csum_flags |= 1462126833Swpaul CSUM_IP_CHECKED|CSUM_IP_VALID; 1463126833Swpaul if (csum->u.ntc_rxflags & 1464126833Swpaul (NDIS_RXCSUM_TCP_PASSED | 1465126833Swpaul NDIS_RXCSUM_UDP_PASSED)) { 1466126833Swpaul m0->m_pkthdr.csum_flags |= 1467126833Swpaul CSUM_DATA_VALID|CSUM_PSEUDO_HDR; 1468126833Swpaul m0->m_pkthdr.csum_data = 0xFFFF; 1469126833Swpaul } 1470126833Swpaul } 1471126833Swpaul 1472151451Swpaul KeAcquireSpinLockAtDpcLevel(&sc->ndis_rxlock); 1473155311Swpaul _IF_ENQUEUE(&sc->ndis_rxqueue, m0); 1474151451Swpaul KeReleaseSpinLockFromDpcLevel(&sc->ndis_rxlock); 1475151451Swpaul IoQueueWorkItem(sc->ndis_inputitem, 1476151451Swpaul (io_workitem_func)ndis_inputtask_wrap, 1477151451Swpaul WORKQUEUE_CRITICAL, ifp); 1478126833Swpaul } 1479126833Swpaul } 1480126833Swpaul} 1481128546Swpaul 1482126833Swpaul/* 1483151451Swpaul * This routine is run at PASSIVE_LEVEL. We use this routine to pass 1484151451Swpaul * packets into the stack in order to avoid calling (*ifp->if_input)() 1485151451Swpaul * with any locks held (at DISPATCH_LEVEL, we'll be holding the 1486151451Swpaul * 'dispatch level' per-cpu sleep lock). 1487151451Swpaul */ 1488151451Swpaulstatic void 1489151451Swpaulndis_inputtask(dobj, arg) 1490151451Swpaul device_object *dobj; 1491151451Swpaul void *arg; 1492151451Swpaul{ 1493151451Swpaul ndis_miniport_block *block; 1494151451Swpaul struct ifnet *ifp; 1495151451Swpaul struct ndis_softc *sc; 1496151451Swpaul struct mbuf *m; 1497178354Ssam struct ieee80211com *ic; 1498178354Ssam struct ieee80211vap *vap; 1499151451Swpaul uint8_t irql; 1500151451Swpaul 1501151451Swpaul ifp = arg; 1502151451Swpaul sc = ifp->if_softc; 1503178354Ssam ic = ifp->if_l2com; 1504178354Ssam vap = TAILQ_FIRST(&ic->ic_vaps); 1505151451Swpaul block = dobj->do_devext; 1506151451Swpaul 1507151451Swpaul KeAcquireSpinLock(&sc->ndis_rxlock, &irql); 1508151451Swpaul while(1) { 1509151451Swpaul _IF_DEQUEUE(&sc->ndis_rxqueue, m); 1510151451Swpaul if (m == NULL) 1511151451Swpaul break; 1512151451Swpaul KeReleaseSpinLock(&sc->ndis_rxlock, irql); 1513197659Scokane if ((sc->ndis_80211 != 0) && (vap != NULL)) 1514178354Ssam vap->iv_deliver_data(vap, vap->iv_bss, m); 1515178354Ssam else 1516178354Ssam (*ifp->if_input)(ifp, m); 1517151451Swpaul KeAcquireSpinLock(&sc->ndis_rxlock, &irql); 1518151451Swpaul } 1519151451Swpaul KeReleaseSpinLock(&sc->ndis_rxlock, irql); 1520151451Swpaul} 1521151451Swpaul 1522151451Swpaul/* 1523123474Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 1524123474Swpaul * the list buffers. 1525123474Swpaul */ 1526144888Swpaulstatic void 1527123474Swpaulndis_txeof(adapter, packet, status) 1528123474Swpaul ndis_handle adapter; 1529123474Swpaul ndis_packet *packet; 1530123474Swpaul ndis_status status; 1531123474Swpaul 1532123474Swpaul{ 1533123474Swpaul struct ndis_softc *sc; 1534123474Swpaul ndis_miniport_block *block; 1535123474Swpaul struct ifnet *ifp; 1536123474Swpaul int idx; 1537123535Swpaul struct mbuf *m; 1538123474Swpaul 1539123474Swpaul block = (ndis_miniport_block *)adapter; 1540141524Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1541147256Sbrooks ifp = sc->ifp; 1542123474Swpaul 1543123826Swpaul m = packet->np_m0; 1544123826Swpaul idx = packet->np_txidx; 1545123535Swpaul if (sc->ndis_sc) 1546123535Swpaul bus_dmamap_unload(sc->ndis_ttag, sc->ndis_tmaps[idx]); 1547123535Swpaul 1548123474Swpaul ndis_free_packet(packet); 1549124697Swpaul m_freem(m); 1550124697Swpaul 1551189488Sweongyo NDIS_LOCK(sc); 1552123535Swpaul sc->ndis_txarray[idx] = NULL; 1553123474Swpaul sc->ndis_txpending++; 1554123474Swpaul 1555124697Swpaul if (status == NDIS_STATUS_SUCCESS) 1556124697Swpaul ifp->if_opackets++; 1557124697Swpaul else 1558124697Swpaul ifp->if_oerrors++; 1559151207Swpaul 1560179498Scokane sc->ndis_tx_timer = 0; 1561148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1562145895Swpaul 1563189488Sweongyo NDIS_UNLOCK(sc); 1564123474Swpaul 1565151207Swpaul IoQueueWorkItem(sc->ndis_startitem, 1566151207Swpaul (io_workitem_func)ndis_starttask_wrap, 1567151207Swpaul WORKQUEUE_CRITICAL, ifp); 1568123474Swpaul} 1569123474Swpaul 1570144888Swpaulstatic void 1571123695Swpaulndis_linksts(adapter, status, sbuf, slen) 1572123695Swpaul ndis_handle adapter; 1573123695Swpaul ndis_status status; 1574123695Swpaul void *sbuf; 1575123695Swpaul uint32_t slen; 1576123695Swpaul{ 1577123695Swpaul ndis_miniport_block *block; 1578143204Swpaul struct ndis_softc *sc; 1579124005Swpaul 1580124005Swpaul block = adapter; 1581143204Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1582151207Swpaul sc->ndis_sts = status; 1583143204Swpaul 1584151207Swpaul /* Event list is all full up, drop this one. */ 1585124005Swpaul 1586189488Sweongyo NDIS_LOCK(sc); 1587151207Swpaul if (sc->ndis_evt[sc->ndis_evtpidx].ne_sts) { 1588189488Sweongyo NDIS_UNLOCK(sc); 1589151207Swpaul return; 1590151207Swpaul } 1591151207Swpaul 1592151207Swpaul /* Cache the event. */ 1593151207Swpaul 1594151207Swpaul if (slen) { 1595151207Swpaul sc->ndis_evt[sc->ndis_evtpidx].ne_buf = malloc(slen, 1596151207Swpaul M_TEMP, M_NOWAIT); 1597151207Swpaul if (sc->ndis_evt[sc->ndis_evtpidx].ne_buf == NULL) { 1598189488Sweongyo NDIS_UNLOCK(sc); 1599151207Swpaul return; 1600151207Swpaul } 1601151207Swpaul bcopy((char *)sbuf, 1602151207Swpaul sc->ndis_evt[sc->ndis_evtpidx].ne_buf, slen); 1603151207Swpaul } 1604151207Swpaul sc->ndis_evt[sc->ndis_evtpidx].ne_sts = status; 1605151207Swpaul sc->ndis_evt[sc->ndis_evtpidx].ne_len = slen; 1606151207Swpaul NDIS_EVTINC(sc->ndis_evtpidx); 1607189488Sweongyo NDIS_UNLOCK(sc); 1608124005Swpaul} 1609124005Swpaul 1610144888Swpaulstatic void 1611124005Swpaulndis_linksts_done(adapter) 1612124005Swpaul ndis_handle adapter; 1613124005Swpaul{ 1614124005Swpaul ndis_miniport_block *block; 1615123695Swpaul struct ndis_softc *sc; 1616123695Swpaul struct ifnet *ifp; 1617123695Swpaul 1618123695Swpaul block = adapter; 1619141524Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1620147256Sbrooks ifp = sc->ifp; 1621123695Swpaul 1622144174Swpaul if (!NDIS_INITIALIZED(sc)) 1623123695Swpaul return; 1624123695Swpaul 1625151207Swpaul switch (sc->ndis_sts) { 1626123695Swpaul case NDIS_STATUS_MEDIA_CONNECT: 1627151207Swpaul IoQueueWorkItem(sc->ndis_tickitem, 1628151207Swpaul (io_workitem_func)ndis_ticktask_wrap, 1629151207Swpaul WORKQUEUE_CRITICAL, sc); 1630151207Swpaul IoQueueWorkItem(sc->ndis_startitem, 1631151207Swpaul (io_workitem_func)ndis_starttask_wrap, 1632151207Swpaul WORKQUEUE_CRITICAL, ifp); 1633123695Swpaul break; 1634123695Swpaul case NDIS_STATUS_MEDIA_DISCONNECT: 1635127249Swpaul if (sc->ndis_link) 1636151207Swpaul IoQueueWorkItem(sc->ndis_tickitem, 1637151207Swpaul (io_workitem_func)ndis_ticktask_wrap, 1638151207Swpaul WORKQUEUE_CRITICAL, sc); 1639123695Swpaul break; 1640123695Swpaul default: 1641123695Swpaul break; 1642123695Swpaul } 1643123474Swpaul} 1644123474Swpaul 1645123474Swpaulstatic void 1646123474Swpaulndis_tick(xsc) 1647123474Swpaul void *xsc; 1648123474Swpaul{ 1649123757Swpaul struct ndis_softc *sc; 1650128780Swpaul 1651124246Swpaul sc = xsc; 1652124697Swpaul 1653179498Scokane if (sc->ndis_hang_timer && --sc->ndis_hang_timer == 0) { 1654179498Scokane IoQueueWorkItem(sc->ndis_tickitem, 1655179498Scokane (io_workitem_func)ndis_ticktask_wrap, 1656179498Scokane WORKQUEUE_CRITICAL, sc); 1657179498Scokane sc->ndis_hang_timer = sc->ndis_block->nmb_checkforhangsecs; 1658179498Scokane } 1659124409Swpaul 1660179498Scokane if (sc->ndis_tx_timer && --sc->ndis_tx_timer == 0) { 1661179498Scokane sc->ifp->if_oerrors++; 1662179498Scokane device_printf(sc->ndis_dev, "watchdog timeout\n"); 1663179498Scokane 1664179498Scokane IoQueueWorkItem(sc->ndis_resetitem, 1665179498Scokane (io_workitem_func)ndis_resettask_wrap, 1666179498Scokane WORKQUEUE_CRITICAL, sc); 1667179498Scokane IoQueueWorkItem(sc->ndis_startitem, 1668179498Scokane (io_workitem_func)ndis_starttask_wrap, 1669179498Scokane WORKQUEUE_CRITICAL, sc->ifp); 1670179498Scokane } 1671179498Scokane 1672179498Scokane callout_reset(&sc->ndis_stat_callout, hz, ndis_tick, sc); 1673124246Swpaul} 1674124246Swpaul 1675124246Swpaulstatic void 1676151207Swpaulndis_ticktask(d, xsc) 1677151207Swpaul device_object *d; 1678124246Swpaul void *xsc; 1679124246Swpaul{ 1680124246Swpaul struct ndis_softc *sc; 1681151207Swpaul struct ieee80211com *ic; 1682178354Ssam struct ieee80211vap *vap; 1683144888Swpaul ndis_checkforhang_handler hangfunc; 1684123474Swpaul uint8_t rval; 1685123474Swpaul 1686123474Swpaul sc = xsc; 1687178354Ssam ic = sc->ifp->if_l2com; 1688178354Ssam vap = TAILQ_FIRST(&ic->ic_vaps); 1689123474Swpaul 1690151625Swpaul NDIS_LOCK(sc); 1691151625Swpaul if (!NDIS_INITIALIZED(sc)) { 1692151625Swpaul NDIS_UNLOCK(sc); 1693151625Swpaul return; 1694151625Swpaul } 1695151625Swpaul NDIS_UNLOCK(sc); 1696151625Swpaul 1697141524Swpaul hangfunc = sc->ndis_chars->nmc_checkhang_func; 1698127887Swpaul 1699127887Swpaul if (hangfunc != NULL) { 1700144174Swpaul rval = MSCALL1(hangfunc, 1701144174Swpaul sc->ndis_block->nmb_miniportadapterctx); 1702127887Swpaul if (rval == TRUE) { 1703127887Swpaul ndis_reset_nic(sc); 1704127887Swpaul return; 1705127887Swpaul } 1706127887Swpaul } 1707127887Swpaul 1708124014Swpaul NDIS_LOCK(sc); 1709151207Swpaul if (sc->ndis_link == 0 && 1710151207Swpaul sc->ndis_sts == NDIS_STATUS_MEDIA_CONNECT) { 1711123695Swpaul sc->ndis_link = 1; 1712125583Swpaul NDIS_UNLOCK(sc); 1713197659Scokane if ((sc->ndis_80211 != 0) && (vap != NULL)) { 1714124409Swpaul ndis_getstate_80211(sc); 1715178354Ssam ieee80211_new_state(vap, IEEE80211_S_RUN, -1); 1716151207Swpaul } 1717125583Swpaul NDIS_LOCK(sc); 1718151207Swpaul if_link_state_change(sc->ifp, LINK_STATE_UP); 1719124409Swpaul } 1720123695Swpaul 1721151207Swpaul if (sc->ndis_link == 1 && 1722151207Swpaul sc->ndis_sts == NDIS_STATUS_MEDIA_DISCONNECT) { 1723124409Swpaul sc->ndis_link = 0; 1724180375Scokane NDIS_UNLOCK(sc); 1725197659Scokane if ((sc->ndis_80211 != 0) && (vap != NULL)) 1726178354Ssam ieee80211_new_state(vap, IEEE80211_S_SCAN, 0); 1727180375Scokane NDIS_LOCK(sc); 1728151207Swpaul if_link_state_change(sc->ifp, LINK_STATE_DOWN); 1729124409Swpaul } 1730124409Swpaul 1731124409Swpaul NDIS_UNLOCK(sc); 1732123474Swpaul} 1733123474Swpaul 1734123474Swpaulstatic void 1735123474Swpaulndis_map_sclist(arg, segs, nseg, mapsize, error) 1736123474Swpaul void *arg; 1737123474Swpaul bus_dma_segment_t *segs; 1738123474Swpaul int nseg; 1739123474Swpaul bus_size_t mapsize; 1740123474Swpaul int error; 1741123474Swpaul 1742123474Swpaul{ 1743123474Swpaul struct ndis_sc_list *sclist; 1744123474Swpaul int i; 1745123474Swpaul 1746123474Swpaul if (error || arg == NULL) 1747123474Swpaul return; 1748123474Swpaul 1749123474Swpaul sclist = arg; 1750123474Swpaul 1751123474Swpaul sclist->nsl_frags = nseg; 1752123474Swpaul 1753123474Swpaul for (i = 0; i < nseg; i++) { 1754123474Swpaul sclist->nsl_elements[i].nse_addr.np_quad = segs[i].ds_addr; 1755123474Swpaul sclist->nsl_elements[i].nse_len = segs[i].ds_len; 1756123474Swpaul } 1757123474Swpaul} 1758123474Swpaul 1759178354Ssamstatic int 1760178354Ssamndis_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 1761178354Ssam const struct ieee80211_bpf_params *params) 1762178354Ssam{ 1763178354Ssam /* no support; just discard */ 1764178354Ssam m_freem(m); 1765178354Ssam ieee80211_free_node(ni); 1766198786Srpaulo return (0); 1767178354Ssam} 1768178354Ssam 1769124246Swpaulstatic void 1770185485Ssamndis_update_mcast(struct ifnet *ifp) 1771185485Ssam{ 1772185485Ssam struct ndis_softc *sc = ifp->if_softc; 1773185485Ssam 1774185485Ssam ndis_setmulti(sc); 1775185485Ssam} 1776185485Ssam 1777185485Ssamstatic void 1778185485Ssamndis_update_promisc(struct ifnet *ifp) 1779185485Ssam{ 1780185485Ssam /* not supported */ 1781185485Ssam} 1782185485Ssam 1783185485Ssamstatic void 1784151207Swpaulndis_starttask(d, arg) 1785151207Swpaul device_object *d; 1786124246Swpaul void *arg; 1787124246Swpaul{ 1788124246Swpaul struct ifnet *ifp; 1789124246Swpaul 1790124246Swpaul ifp = arg; 1791145895Swpaul 1792132986Smlaier if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1793124246Swpaul ndis_start(ifp); 1794124246Swpaul} 1795124246Swpaul 1796123474Swpaul/* 1797123474Swpaul * Main transmit routine. To make NDIS drivers happy, we need to 1798123474Swpaul * transform mbuf chains into NDIS packets and feed them to the 1799123474Swpaul * send packet routines. Most drivers allow you to send several 1800123474Swpaul * packets at once (up to the maxpkts limit). Unfortunately, rather 1801123474Swpaul * that accepting them in the form of a linked list, they expect 1802123474Swpaul * a contiguous array of pointers to packets. 1803123474Swpaul * 1804123474Swpaul * For those drivers which use the NDIS scatter/gather DMA mechanism, 1805123474Swpaul * we need to perform busdma work here. Those that use map registers 1806123474Swpaul * will do the mapping themselves on a buffer by buffer basis. 1807123474Swpaul */ 1808123474Swpaulstatic void 1809123474Swpaulndis_start(ifp) 1810123474Swpaul struct ifnet *ifp; 1811123474Swpaul{ 1812123474Swpaul struct ndis_softc *sc; 1813123474Swpaul struct mbuf *m = NULL; 1814123474Swpaul ndis_packet **p0 = NULL, *p = NULL; 1815124821Swpaul ndis_tcpip_csum *csum; 1816141963Swpaul int pcnt = 0, status; 1817123474Swpaul 1818123474Swpaul sc = ifp->if_softc; 1819123474Swpaul 1820123537Swpaul NDIS_LOCK(sc); 1821148887Srwatson if (!sc->ndis_link || ifp->if_drv_flags & IFF_DRV_OACTIVE) { 1822123695Swpaul NDIS_UNLOCK(sc); 1823123695Swpaul return; 1824123695Swpaul } 1825123695Swpaul 1826123474Swpaul p0 = &sc->ndis_txarray[sc->ndis_txidx]; 1827123474Swpaul 1828123474Swpaul while(sc->ndis_txpending) { 1829132986Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 1830123474Swpaul if (m == NULL) 1831123474Swpaul break; 1832123474Swpaul 1833141963Swpaul NdisAllocatePacket(&status, 1834141963Swpaul &sc->ndis_txarray[sc->ndis_txidx], sc->ndis_txpool); 1835123535Swpaul 1836141963Swpaul if (status != NDIS_STATUS_SUCCESS) 1837141963Swpaul break; 1838141963Swpaul 1839123474Swpaul if (ndis_mtop(m, &sc->ndis_txarray[sc->ndis_txidx])) { 1840132986Smlaier IFQ_DRV_PREPEND(&ifp->if_snd, m); 1841123474Swpaul NDIS_UNLOCK(sc); 1842123474Swpaul return; 1843123474Swpaul } 1844123474Swpaul 1845123474Swpaul /* 1846123474Swpaul * Save pointer to original mbuf 1847123474Swpaul * so we can free it later. 1848123474Swpaul */ 1849123474Swpaul 1850124014Swpaul p = sc->ndis_txarray[sc->ndis_txidx]; 1851124014Swpaul p->np_txidx = sc->ndis_txidx; 1852124014Swpaul p->np_m0 = m; 1853124014Swpaul p->np_oob.npo_status = NDIS_STATUS_PENDING; 1854123474Swpaul 1855123474Swpaul /* 1856123474Swpaul * Do scatter/gather processing, if driver requested it. 1857123474Swpaul */ 1858123474Swpaul if (sc->ndis_sc) { 1859123474Swpaul bus_dmamap_load_mbuf(sc->ndis_ttag, 1860123474Swpaul sc->ndis_tmaps[sc->ndis_txidx], m, 1861123474Swpaul ndis_map_sclist, &p->np_sclist, BUS_DMA_NOWAIT); 1862123474Swpaul bus_dmamap_sync(sc->ndis_ttag, 1863123474Swpaul sc->ndis_tmaps[sc->ndis_txidx], 1864123474Swpaul BUS_DMASYNC_PREREAD); 1865123474Swpaul p->np_ext.npe_info[ndis_sclist_info] = &p->np_sclist; 1866123474Swpaul } 1867123474Swpaul 1868124821Swpaul /* Handle checksum offload. */ 1869124821Swpaul 1870124821Swpaul if (ifp->if_capenable & IFCAP_TXCSUM && 1871124821Swpaul m->m_pkthdr.csum_flags) { 1872124821Swpaul csum = (ndis_tcpip_csum *) 1873124821Swpaul &p->np_ext.npe_info[ndis_tcpipcsum_info]; 1874124821Swpaul csum->u.ntc_txflags = NDIS_TXCSUM_DO_IPV4; 1875124821Swpaul if (m->m_pkthdr.csum_flags & CSUM_IP) 1876124821Swpaul csum->u.ntc_txflags |= NDIS_TXCSUM_DO_IP; 1877124821Swpaul if (m->m_pkthdr.csum_flags & CSUM_TCP) 1878124821Swpaul csum->u.ntc_txflags |= NDIS_TXCSUM_DO_TCP; 1879124821Swpaul if (m->m_pkthdr.csum_flags & CSUM_UDP) 1880124821Swpaul csum->u.ntc_txflags |= NDIS_TXCSUM_DO_UDP; 1881124821Swpaul p->np_private.npp_flags = NDIS_PROTOCOL_ID_TCP_IP; 1882124821Swpaul } 1883124821Swpaul 1884123474Swpaul NDIS_INC(sc); 1885123474Swpaul sc->ndis_txpending--; 1886123474Swpaul 1887123474Swpaul pcnt++; 1888123474Swpaul 1889123474Swpaul /* 1890123474Swpaul * If there's a BPF listener, bounce a copy of this frame 1891123474Swpaul * to him. 1892123474Swpaul */ 1893178354Ssam if (!sc->ndis_80211) /* XXX handle 80211 */ 1894178354Ssam BPF_MTAP(ifp, m); 1895123474Swpaul 1896123474Swpaul /* 1897123474Swpaul * The array that p0 points to must appear contiguous, 1898123474Swpaul * so we must not wrap past the end of sc->ndis_txarray[]. 1899123474Swpaul * If it looks like we're about to wrap, break out here 1900123474Swpaul * so the this batch of packets can be transmitted, then 1901123474Swpaul * wait for txeof to ask us to send the rest. 1902123474Swpaul */ 1903123474Swpaul if (sc->ndis_txidx == 0) 1904123474Swpaul break; 1905123474Swpaul } 1906123474Swpaul 1907136677Sle if (pcnt == 0) { 1908136677Sle NDIS_UNLOCK(sc); 1909136269Smlaier return; 1910136677Sle } 1911136269Smlaier 1912123474Swpaul if (sc->ndis_txpending == 0) 1913148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1914123474Swpaul 1915123474Swpaul /* 1916123474Swpaul * Set a timeout in case the chip goes out to lunch. 1917123474Swpaul */ 1918179498Scokane sc->ndis_tx_timer = 5; 1919123474Swpaul 1920123537Swpaul NDIS_UNLOCK(sc); 1921123537Swpaul 1922151207Swpaul /* 1923151207Swpaul * According to NDIS documentation, if a driver exports 1924151207Swpaul * a MiniportSendPackets() routine, we prefer that over 1925151207Swpaul * a MiniportSend() routine (which sends just a single 1926151207Swpaul * packet). 1927151207Swpaul */ 1928151207Swpaul if (sc->ndis_chars->nmc_sendmulti_func != NULL) 1929151207Swpaul ndis_send_packets(sc, p0, pcnt); 1930151207Swpaul else 1931125377Swpaul ndis_send_packet(sc, p); 1932123537Swpaul 1933123474Swpaul return; 1934123474Swpaul} 1935123474Swpaul 1936123474Swpaulstatic void 1937123474Swpaulndis_init(xsc) 1938123474Swpaul void *xsc; 1939123474Swpaul{ 1940123474Swpaul struct ndis_softc *sc = xsc; 1941147256Sbrooks struct ifnet *ifp = sc->ifp; 1942178354Ssam struct ieee80211com *ic = ifp->if_l2com; 1943151207Swpaul int i, len, error; 1944123474Swpaul 1945123474Swpaul /* 1946125068Swpaul * Avoid reintializing the link unnecessarily. 1947125068Swpaul * This should be dealt with in a better way by 1948125068Swpaul * fixing the upper layer modules so they don't 1949125068Swpaul * call ifp->if_init() quite as often. 1950125068Swpaul */ 1951178354Ssam if (sc->ndis_link) 1952125068Swpaul return; 1953125068Swpaul 1954125068Swpaul /* 1955123474Swpaul * Cancel pending I/O and free all RX/TX buffers. 1956123474Swpaul */ 1957123474Swpaul ndis_stop(sc); 1958151207Swpaul 1959186507Sweongyo if (!(sc->ndis_iftype == PNPBus && ndisusb_halt == 0)) { 1960186507Sweongyo error = ndis_init_nic(sc); 1961186507Sweongyo if (error != 0) { 1962186507Sweongyo device_printf(sc->ndis_dev, 1963186507Sweongyo "failed to initialize the device: %d\n", error); 1964186507Sweongyo return; 1965186507Sweongyo } 1966186507Sweongyo } 1967123474Swpaul 1968123474Swpaul /* Init our MAC address */ 1969123474Swpaul 1970123474Swpaul /* Program the packet filter */ 1971123474Swpaul 1972124709Swpaul sc->ndis_filter = NDIS_PACKET_TYPE_DIRECTED; 1973123474Swpaul 1974123474Swpaul if (ifp->if_flags & IFF_BROADCAST) 1975124709Swpaul sc->ndis_filter |= NDIS_PACKET_TYPE_BROADCAST; 1976123474Swpaul 1977123474Swpaul if (ifp->if_flags & IFF_PROMISC) 1978124709Swpaul sc->ndis_filter |= NDIS_PACKET_TYPE_PROMISCUOUS; 1979123474Swpaul 1980151207Swpaul len = sizeof(sc->ndis_filter); 1981123474Swpaul 1982123474Swpaul error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER, 1983151207Swpaul &sc->ndis_filter, &len); 1984123474Swpaul 1985123474Swpaul if (error) 1986198786Srpaulo device_printf(sc->ndis_dev, "set filter failed: %d\n", error); 1987123474Swpaul 1988124709Swpaul /* 1989151207Swpaul * Set lookahead. 1990151207Swpaul */ 1991151207Swpaul i = ifp->if_mtu; 1992151207Swpaul len = sizeof(i); 1993151207Swpaul ndis_set_info(sc, OID_GEN_CURRENT_LOOKAHEAD, &i, &len); 1994151207Swpaul 1995151207Swpaul /* 1996124709Swpaul * Program the multicast filter, if necessary. 1997124709Swpaul */ 1998124709Swpaul ndis_setmulti(sc); 1999123535Swpaul 2000124821Swpaul /* Setup task offload. */ 2001124821Swpaul ndis_set_offload(sc); 2002178929Sthompsa 2003124709Swpaul NDIS_LOCK(sc); 2004124709Swpaul 2005124709Swpaul sc->ndis_txidx = 0; 2006124709Swpaul sc->ndis_txpending = sc->ndis_maxpkts; 2007124709Swpaul sc->ndis_link = 0; 2008124709Swpaul 2009151207Swpaul if_link_state_change(sc->ifp, LINK_STATE_UNKNOWN); 2010151207Swpaul 2011148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 2012148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2013179498Scokane sc->ndis_tx_timer = 0; 2014123474Swpaul 2015124165Swpaul /* 2016124165Swpaul * Some drivers don't set this value. The NDIS spec says 2017127336Swpaul * the default checkforhang timeout is "approximately 2 2018127336Swpaul * seconds." We use 3 seconds, because it seems for some 2019127336Swpaul * drivers, exactly 2 seconds is too fast. 2020124165Swpaul */ 2021141524Swpaul if (sc->ndis_block->nmb_checkforhangsecs == 0) 2022141524Swpaul sc->ndis_block->nmb_checkforhangsecs = 3; 2023124165Swpaul 2024179498Scokane sc->ndis_hang_timer = sc->ndis_block->nmb_checkforhangsecs; 2025179498Scokane callout_reset(&sc->ndis_stat_callout, hz, ndis_tick, sc); 2026179498Scokane NDIS_UNLOCK(sc); 2027123474Swpaul 2028179498Scokane /* XXX force handling */ 2029191163Sthompsa if (sc->ndis_80211) 2030191163Sthompsa ieee80211_start_all(ic); /* start all vap's */ 2031123474Swpaul} 2032123474Swpaul 2033123474Swpaul/* 2034123474Swpaul * Set media options. 2035123474Swpaul */ 2036123474Swpaulstatic int 2037123474Swpaulndis_ifmedia_upd(ifp) 2038123474Swpaul struct ifnet *ifp; 2039123474Swpaul{ 2040123474Swpaul struct ndis_softc *sc; 2041123474Swpaul 2042123474Swpaul sc = ifp->if_softc; 2043123474Swpaul 2044131750Swpaul if (NDIS_INITIALIZED(sc)) 2045123474Swpaul ndis_init(sc); 2046123474Swpaul 2047198786Srpaulo return (0); 2048123474Swpaul} 2049123474Swpaul 2050123474Swpaul/* 2051123474Swpaul * Report current media status. 2052123474Swpaul */ 2053123474Swpaulstatic void 2054123474Swpaulndis_ifmedia_sts(ifp, ifmr) 2055123474Swpaul struct ifnet *ifp; 2056123474Swpaul struct ifmediareq *ifmr; 2057123474Swpaul{ 2058123474Swpaul struct ndis_softc *sc; 2059123474Swpaul uint32_t media_info; 2060123474Swpaul ndis_media_state linkstate; 2061198786Srpaulo int len; 2062123474Swpaul 2063123848Swpaul ifmr->ifm_status = IFM_AVALID; 2064123848Swpaul ifmr->ifm_active = IFM_ETHER; 2065131750Swpaul sc = ifp->if_softc; 2066123848Swpaul 2067131750Swpaul if (!NDIS_INITIALIZED(sc)) 2068123848Swpaul return; 2069123848Swpaul 2070123474Swpaul len = sizeof(linkstate); 2071198786Srpaulo ndis_get_info(sc, OID_GEN_MEDIA_CONNECT_STATUS, 2072123474Swpaul (void *)&linkstate, &len); 2073123474Swpaul 2074123474Swpaul len = sizeof(media_info); 2075198786Srpaulo ndis_get_info(sc, OID_GEN_LINK_SPEED, 2076123474Swpaul (void *)&media_info, &len); 2077123474Swpaul 2078123474Swpaul if (linkstate == nmc_connected) 2079123474Swpaul ifmr->ifm_status |= IFM_ACTIVE; 2080123474Swpaul 2081198786Srpaulo switch (media_info) { 2082123474Swpaul case 100000: 2083123474Swpaul ifmr->ifm_active |= IFM_10_T; 2084123474Swpaul break; 2085123474Swpaul case 1000000: 2086123474Swpaul ifmr->ifm_active |= IFM_100_TX; 2087123474Swpaul break; 2088123474Swpaul case 10000000: 2089123474Swpaul ifmr->ifm_active |= IFM_1000_T; 2090123474Swpaul break; 2091123474Swpaul default: 2092124060Swpaul device_printf(sc->ndis_dev, "unknown speed: %d\n", media_info); 2093123474Swpaul break; 2094123474Swpaul } 2095123474Swpaul} 2096123474Swpaul 2097151207Swpaulstatic int 2098151207Swpaulndis_set_cipher(sc, cipher) 2099151207Swpaul struct ndis_softc *sc; 2100151207Swpaul int cipher; 2101151207Swpaul{ 2102151207Swpaul struct ieee80211com *ic; 2103151207Swpaul int rval = 0, len; 2104151207Swpaul uint32_t arg, save; 2105151207Swpaul 2106178354Ssam ic = sc->ifp->if_l2com; 2107151207Swpaul 2108151207Swpaul len = sizeof(arg); 2109151207Swpaul 2110213778Srpaulo if (cipher == WPA_CSE_WEP40 || cipher == WPA_CSE_WEP104) { 2111178354Ssam if (!(ic->ic_cryptocaps & IEEE80211_CRYPTO_WEP)) 2112198786Srpaulo return (ENOTSUP); 2113151207Swpaul arg = NDIS_80211_WEPSTAT_ENC1ENABLED; 2114151207Swpaul } 2115151207Swpaul 2116151207Swpaul if (cipher == WPA_CSE_TKIP) { 2117178354Ssam if (!(ic->ic_cryptocaps & IEEE80211_CRYPTO_TKIP)) 2118198786Srpaulo return (ENOTSUP); 2119151207Swpaul arg = NDIS_80211_WEPSTAT_ENC2ENABLED; 2120151207Swpaul } 2121151207Swpaul 2122151207Swpaul if (cipher == WPA_CSE_CCMP) { 2123178354Ssam if (!(ic->ic_cryptocaps & IEEE80211_CRYPTO_AES_CCM)) 2124198786Srpaulo return (ENOTSUP); 2125151207Swpaul arg = NDIS_80211_WEPSTAT_ENC3ENABLED; 2126151207Swpaul } 2127151207Swpaul 2128171390Sthompsa DPRINTF(("Setting cipher to %d\n", arg)); 2129151207Swpaul save = arg; 2130151207Swpaul rval = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &len); 2131151207Swpaul 2132151207Swpaul if (rval) 2133198786Srpaulo return (rval); 2134151207Swpaul 2135151207Swpaul /* Check that the cipher was set correctly. */ 2136151207Swpaul 2137151207Swpaul len = sizeof(save); 2138151207Swpaul rval = ndis_get_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &len); 2139151207Swpaul 2140151207Swpaul if (rval != 0 || arg != save) 2141198786Srpaulo return (ENODEV); 2142151207Swpaul 2143198786Srpaulo return (0); 2144151207Swpaul} 2145151207Swpaul 2146151207Swpaul/* 2147151207Swpaul * WPA is hairy to set up. Do the work in a separate routine 2148151207Swpaul * so we don't clutter the setstate function too much. 2149151207Swpaul * Important yet undocumented fact: first we have to set the 2150151207Swpaul * authentication mode, _then_ we enable the ciphers. If one 2151151207Swpaul * of the WPA authentication modes isn't enabled, the driver 2152151207Swpaul * might not permit the TKIP or AES ciphers to be selected. 2153151207Swpaul */ 2154151207Swpaulstatic int 2155178354Ssamndis_set_wpa(sc, ie, ielen) 2156151207Swpaul struct ndis_softc *sc; 2157178354Ssam void *ie; 2158178354Ssam int ielen; 2159151207Swpaul{ 2160151207Swpaul struct ieee80211_ie_wpa *w; 2161151207Swpaul struct ndis_ie *n; 2162151207Swpaul char *pos; 2163151207Swpaul uint32_t arg; 2164151207Swpaul int i; 2165151207Swpaul 2166151207Swpaul /* 2167151207Swpaul * Apparently, the only way for us to know what ciphers 2168151207Swpaul * and key management/authentication mode to use is for 2169151207Swpaul * us to inspect the optional information element (IE) 2170151207Swpaul * stored in the 802.11 state machine. This IE should be 2171151207Swpaul * supplied by the WPA supplicant. 2172151207Swpaul */ 2173151207Swpaul 2174178354Ssam w = (struct ieee80211_ie_wpa *)ie; 2175151207Swpaul 2176151207Swpaul /* Check for the right kind of IE. */ 2177171390Sthompsa if (w->wpa_id != IEEE80211_ELEMID_VENDOR) { 2178171390Sthompsa DPRINTF(("Incorrect IE type %d\n", w->wpa_id)); 2179198786Srpaulo return (EINVAL); 2180171390Sthompsa } 2181151207Swpaul 2182151207Swpaul /* Skip over the ucast cipher OIDs. */ 2183151207Swpaul pos = (char *)&w->wpa_uciphers[0]; 2184151207Swpaul pos += w->wpa_uciphercnt * sizeof(struct ndis_ie); 2185151207Swpaul 2186151207Swpaul /* Skip over the authmode count. */ 2187151207Swpaul pos += sizeof(u_int16_t); 2188151207Swpaul 2189151207Swpaul /* 2190151207Swpaul * Check for the authentication modes. I'm 2191151207Swpaul * pretty sure there's only supposed to be one. 2192151207Swpaul */ 2193151207Swpaul 2194151207Swpaul n = (struct ndis_ie *)pos; 2195151207Swpaul if (n->ni_val == WPA_ASE_NONE) 2196151207Swpaul arg = NDIS_80211_AUTHMODE_WPANONE; 2197151207Swpaul 2198151207Swpaul if (n->ni_val == WPA_ASE_8021X_UNSPEC) 2199151207Swpaul arg = NDIS_80211_AUTHMODE_WPA; 2200151207Swpaul 2201151207Swpaul if (n->ni_val == WPA_ASE_8021X_PSK) 2202151207Swpaul arg = NDIS_80211_AUTHMODE_WPAPSK; 2203151207Swpaul 2204171390Sthompsa DPRINTF(("Setting WPA auth mode to %d\n", arg)); 2205151207Swpaul i = sizeof(arg); 2206151207Swpaul if (ndis_set_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &i)) 2207198786Srpaulo return (ENOTSUP); 2208151207Swpaul i = sizeof(arg); 2209151207Swpaul ndis_get_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &i); 2210151207Swpaul 2211151207Swpaul /* Now configure the desired ciphers. */ 2212151207Swpaul 2213151207Swpaul /* First, set up the multicast group cipher. */ 2214151207Swpaul n = (struct ndis_ie *)&w->wpa_mcipher[0]; 2215151207Swpaul 2216151207Swpaul if (ndis_set_cipher(sc, n->ni_val)) 2217198786Srpaulo return (ENOTSUP); 2218151207Swpaul 2219151207Swpaul /* Now start looking around for the unicast ciphers. */ 2220151207Swpaul pos = (char *)&w->wpa_uciphers[0]; 2221151207Swpaul n = (struct ndis_ie *)pos; 2222151207Swpaul 2223151207Swpaul for (i = 0; i < w->wpa_uciphercnt; i++) { 2224151207Swpaul if (ndis_set_cipher(sc, n->ni_val)) 2225198786Srpaulo return (ENOTSUP); 2226151207Swpaul n++; 2227151207Swpaul } 2228151207Swpaul 2229198786Srpaulo return (0); 2230151207Swpaul} 2231151207Swpaul 2232123695Swpaulstatic void 2233201620Srpaulondis_media_status(struct ifnet *ifp, struct ifmediareq *imr) 2234201620Srpaulo{ 2235201620Srpaulo struct ieee80211vap *vap = ifp->if_softc; 2236201620Srpaulo struct ndis_softc *sc = vap->iv_ic->ic_ifp->if_softc; 2237201620Srpaulo uint32_t txrate; 2238201644Srpaulo int len; 2239201620Srpaulo 2240201620Srpaulo if (!NDIS_INITIALIZED(sc)) 2241201620Srpaulo return; 2242201620Srpaulo 2243201620Srpaulo len = sizeof(txrate); 2244201620Srpaulo if (ndis_get_info(sc, OID_GEN_LINK_SPEED, &txrate, &len) == 0) 2245201620Srpaulo vap->iv_bss->ni_txrate = txrate / 5000; 2246201620Srpaulo ieee80211_media_status(ifp, imr); 2247201620Srpaulo} 2248201620Srpaulo 2249201620Srpaulostatic void 2250123695Swpaulndis_setstate_80211(sc) 2251123695Swpaul struct ndis_softc *sc; 2252123695Swpaul{ 2253123695Swpaul struct ieee80211com *ic; 2254194432Scokane struct ieee80211vap *vap; 2255151207Swpaul ndis_80211_macaddr bssid; 2256124409Swpaul ndis_80211_config config; 2257178929Sthompsa int rval = 0, len; 2258123695Swpaul uint32_t arg; 2259123695Swpaul struct ifnet *ifp; 2260123695Swpaul 2261147256Sbrooks ifp = sc->ifp; 2262178354Ssam ic = ifp->if_l2com; 2263194432Scokane vap = TAILQ_FIRST(&ic->ic_vaps); 2264123695Swpaul 2265171390Sthompsa if (!NDIS_INITIALIZED(sc)) { 2266171390Sthompsa DPRINTF(("%s: NDIS not initialized\n", __func__)); 2267123695Swpaul return; 2268171390Sthompsa } 2269123695Swpaul 2270151207Swpaul /* Disassociate and turn off radio. */ 2271151207Swpaul len = sizeof(arg); 2272151207Swpaul arg = 1; 2273151207Swpaul ndis_set_info(sc, OID_802_11_DISASSOCIATE, &arg, &len); 2274151207Swpaul 2275123695Swpaul /* Set network infrastructure mode. */ 2276123695Swpaul 2277123695Swpaul len = sizeof(arg); 2278178929Sthompsa if (ic->ic_opmode == IEEE80211_M_IBSS) 2279123695Swpaul arg = NDIS_80211_NET_INFRA_IBSS; 2280123695Swpaul else 2281123695Swpaul arg = NDIS_80211_NET_INFRA_BSS; 2282123695Swpaul 2283123695Swpaul rval = ndis_set_info(sc, OID_802_11_INFRASTRUCTURE_MODE, &arg, &len); 2284123695Swpaul 2285123695Swpaul if (rval) 2286124060Swpaul device_printf (sc->ndis_dev, "set infra failed: %d\n", rval); 2287123695Swpaul 2288151207Swpaul /* Set power management */ 2289151207Swpaul len = sizeof(arg); 2290194432Scokane if (vap->iv_flags & IEEE80211_F_PMGTON) 2291151207Swpaul arg = NDIS_80211_POWERMODE_FAST_PSP; 2292151207Swpaul else 2293151207Swpaul arg = NDIS_80211_POWERMODE_CAM; 2294151207Swpaul ndis_set_info(sc, OID_802_11_POWER_MODE, &arg, &len); 2295151207Swpaul 2296187104Sthompsa /* Set TX power */ 2297189550Ssam if ((ic->ic_caps & IEEE80211_C_TXPMGT) && 2298189550Ssam ic->ic_txpowlimit < (sizeof(dBm2mW) / sizeof(dBm2mW[0]))) { 2299189550Ssam arg = dBm2mW[ic->ic_txpowlimit]; 2300187104Sthompsa len = sizeof(arg); 2301187104Sthompsa ndis_set_info(sc, OID_802_11_TX_POWER_LEVEL, &arg, &len); 2302187104Sthompsa } 2303187104Sthompsa 2304151207Swpaul /* 2305151207Swpaul * Default encryption mode to off, authentication 2306151207Swpaul * to open and privacy to 'accept everything.' 2307151207Swpaul */ 2308151207Swpaul len = sizeof(arg); 2309151207Swpaul arg = NDIS_80211_WEPSTAT_DISABLED; 2310151207Swpaul ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &len); 2311151207Swpaul 2312151207Swpaul len = sizeof(arg); 2313151207Swpaul arg = NDIS_80211_AUTHMODE_OPEN; 2314151207Swpaul ndis_set_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &len); 2315151207Swpaul 2316151207Swpaul /* 2317198786Srpaulo * Note that OID_802_11_PRIVACY_FILTER is optional: 2318151207Swpaul * not all drivers implement it. 2319151207Swpaul */ 2320151207Swpaul len = sizeof(arg); 2321151207Swpaul arg = NDIS_80211_PRIVFILT_8021XWEP; 2322151207Swpaul ndis_set_info(sc, OID_802_11_PRIVACY_FILTER, &arg, &len); 2323151207Swpaul 2324178929Sthompsa len = sizeof(config); 2325178929Sthompsa bzero((char *)&config, len); 2326178929Sthompsa config.nc_length = len; 2327178929Sthompsa config.nc_fhconfig.ncf_length = sizeof(ndis_80211_config_fh); 2328178929Sthompsa rval = ndis_get_info(sc, OID_802_11_CONFIGURATION, &config, &len); 2329178929Sthompsa 2330178929Sthompsa /* 2331178929Sthompsa * Some drivers expect us to initialize these values, so 2332178929Sthompsa * provide some defaults. 2333178929Sthompsa */ 2334178929Sthompsa 2335178929Sthompsa if (config.nc_beaconperiod == 0) 2336178929Sthompsa config.nc_beaconperiod = 100; 2337178929Sthompsa if (config.nc_atimwin == 0) 2338178929Sthompsa config.nc_atimwin = 100; 2339178929Sthompsa if (config.nc_fhconfig.ncf_dwelltime == 0) 2340178929Sthompsa config.nc_fhconfig.ncf_dwelltime = 200; 2341178929Sthompsa if (rval == 0 && ic->ic_bsschan != IEEE80211_CHAN_ANYC) { 2342178929Sthompsa int chan, chanflag; 2343178929Sthompsa 2344178929Sthompsa chan = ieee80211_chan2ieee(ic, ic->ic_bsschan); 2345178929Sthompsa chanflag = config.nc_dsconfig > 2500000 ? IEEE80211_CHAN_2GHZ : 2346178929Sthompsa IEEE80211_CHAN_5GHZ; 2347178929Sthompsa if (chan != ieee80211_mhz2ieee(config.nc_dsconfig / 1000, 0)) { 2348178929Sthompsa config.nc_dsconfig = 2349178929Sthompsa ic->ic_bsschan->ic_freq * 1000; 2350178929Sthompsa len = sizeof(config); 2351178929Sthompsa config.nc_length = len; 2352178929Sthompsa config.nc_fhconfig.ncf_length = 2353178929Sthompsa sizeof(ndis_80211_config_fh); 2354178929Sthompsa DPRINTF(("Setting channel to %ukHz\n", config.nc_dsconfig)); 2355178929Sthompsa rval = ndis_set_info(sc, OID_802_11_CONFIGURATION, 2356178929Sthompsa &config, &len); 2357178929Sthompsa if (rval) 2358178929Sthompsa device_printf(sc->ndis_dev, "couldn't change " 2359178929Sthompsa "DS config to %ukHz: %d\n", 2360178929Sthompsa config.nc_dsconfig, rval); 2361178929Sthompsa } 2362178929Sthompsa } else if (rval) 2363178929Sthompsa device_printf(sc->ndis_dev, "couldn't retrieve " 2364178929Sthompsa "channel info: %d\n", rval); 2365178929Sthompsa 2366178929Sthompsa /* Set the BSSID to our value so the driver doesn't associate */ 2367178929Sthompsa len = IEEE80211_ADDR_LEN; 2368190526Ssam bcopy(IF_LLADDR(ifp), bssid, len); 2369178929Sthompsa DPRINTF(("Setting BSSID to %6D\n", (uint8_t *)&bssid, ":")); 2370178929Sthompsa rval = ndis_set_info(sc, OID_802_11_BSSID, &bssid, &len); 2371178929Sthompsa if (rval) 2372178929Sthompsa device_printf(sc->ndis_dev, 2373178929Sthompsa "setting BSSID failed: %d\n", rval); 2374178929Sthompsa} 2375178929Sthompsa 2376178929Sthompsastatic void 2377178929Sthompsandis_auth_and_assoc(sc, vap) 2378178929Sthompsa struct ndis_softc *sc; 2379178929Sthompsa struct ieee80211vap *vap; 2380178929Sthompsa{ 2381178929Sthompsa struct ieee80211com *ic; 2382178929Sthompsa struct ieee80211_node *ni; 2383178929Sthompsa ndis_80211_ssid ssid; 2384178929Sthompsa ndis_80211_macaddr bssid; 2385178929Sthompsa ndis_80211_wep wep; 2386178929Sthompsa int i, rval = 0, len, error; 2387178929Sthompsa uint32_t arg; 2388178929Sthompsa struct ifnet *ifp; 2389178929Sthompsa 2390178929Sthompsa ifp = sc->ifp; 2391178929Sthompsa ic = ifp->if_l2com; 2392178929Sthompsa ni = vap->iv_bss; 2393178929Sthompsa 2394178929Sthompsa if (!NDIS_INITIALIZED(sc)) { 2395178929Sthompsa DPRINTF(("%s: NDIS not initialized\n", __func__)); 2396178929Sthompsa return; 2397178929Sthompsa } 2398178929Sthompsa 2399178929Sthompsa /* Initial setup */ 2400178929Sthompsa ndis_setstate_80211(sc); 2401178929Sthompsa 2402178929Sthompsa /* Set network infrastructure mode. */ 2403178929Sthompsa 2404178929Sthompsa len = sizeof(arg); 2405178929Sthompsa if (vap->iv_opmode == IEEE80211_M_IBSS) 2406178929Sthompsa arg = NDIS_80211_NET_INFRA_IBSS; 2407178929Sthompsa else 2408178929Sthompsa arg = NDIS_80211_NET_INFRA_BSS; 2409178929Sthompsa 2410178929Sthompsa rval = ndis_set_info(sc, OID_802_11_INFRASTRUCTURE_MODE, &arg, &len); 2411178929Sthompsa 2412178929Sthompsa if (rval) 2413178929Sthompsa device_printf (sc->ndis_dev, "set infra failed: %d\n", rval); 2414178929Sthompsa 2415178929Sthompsa /* Set RTS threshold */ 2416178929Sthompsa 2417178929Sthompsa len = sizeof(arg); 2418178929Sthompsa arg = vap->iv_rtsthreshold; 2419178929Sthompsa ndis_set_info(sc, OID_802_11_RTS_THRESHOLD, &arg, &len); 2420178929Sthompsa 2421178929Sthompsa /* Set fragmentation threshold */ 2422178929Sthompsa 2423178929Sthompsa len = sizeof(arg); 2424178929Sthompsa arg = vap->iv_fragthreshold; 2425178929Sthompsa ndis_set_info(sc, OID_802_11_FRAGMENTATION_THRESHOLD, &arg, &len); 2426178929Sthompsa 2427124005Swpaul /* Set WEP */ 2428124005Swpaul 2429178354Ssam if (vap->iv_flags & IEEE80211_F_PRIVACY && 2430178354Ssam !(vap->iv_flags & IEEE80211_F_WPA)) { 2431198786Srpaulo int keys_set = 0; 2432151207Swpaul 2433178354Ssam if (ni->ni_authmode == IEEE80211_AUTH_SHARED) { 2434165573Sjkim len = sizeof(arg); 2435165573Sjkim arg = NDIS_80211_AUTHMODE_SHARED; 2436171390Sthompsa DPRINTF(("Setting shared auth\n")); 2437165573Sjkim ndis_set_info(sc, OID_802_11_AUTHENTICATION_MODE, 2438165573Sjkim &arg, &len); 2439165573Sjkim } 2440124005Swpaul for (i = 0; i < IEEE80211_WEP_NKID; i++) { 2441178354Ssam if (vap->iv_nw_keys[i].wk_keylen) { 2442178354Ssam if (vap->iv_nw_keys[i].wk_cipher->ic_cipher != 2443151207Swpaul IEEE80211_CIPHER_WEP) 2444151207Swpaul continue; 2445124005Swpaul bzero((char *)&wep, sizeof(wep)); 2446178354Ssam wep.nw_keylen = vap->iv_nw_keys[i].wk_keylen; 2447151207Swpaul 2448151207Swpaul /* 2449151207Swpaul * 5, 13 and 16 are the only valid 2450198786Srpaulo * key lengths. Anything in between 2451198786Srpaulo * will be zero padded out to the 2452198786Srpaulo * next highest boundary. 2453151207Swpaul */ 2454178354Ssam if (vap->iv_nw_keys[i].wk_keylen < 5) 2455124005Swpaul wep.nw_keylen = 5; 2456178354Ssam else if (vap->iv_nw_keys[i].wk_keylen > 5 && 2457178354Ssam vap->iv_nw_keys[i].wk_keylen < 13) 2458124005Swpaul wep.nw_keylen = 13; 2459178354Ssam else if (vap->iv_nw_keys[i].wk_keylen > 13 && 2460178354Ssam vap->iv_nw_keys[i].wk_keylen < 16) 2461151207Swpaul wep.nw_keylen = 16; 2462151207Swpaul 2463124005Swpaul wep.nw_keyidx = i; 2464124005Swpaul wep.nw_length = (sizeof(uint32_t) * 3) 2465124005Swpaul + wep.nw_keylen; 2466178354Ssam if (i == vap->iv_def_txkey) 2467124005Swpaul wep.nw_keyidx |= NDIS_80211_WEPKEY_TX; 2468178354Ssam bcopy(vap->iv_nw_keys[i].wk_key, 2469124005Swpaul wep.nw_keydata, wep.nw_length); 2470124005Swpaul len = sizeof(wep); 2471171390Sthompsa DPRINTF(("Setting WEP key %d\n", i)); 2472124005Swpaul rval = ndis_set_info(sc, 2473124005Swpaul OID_802_11_ADD_WEP, &wep, &len); 2474124005Swpaul if (rval) 2475124060Swpaul device_printf(sc->ndis_dev, 2476124060Swpaul "set wepkey failed: %d\n", rval); 2477151207Swpaul keys_set++; 2478124005Swpaul } 2479124005Swpaul } 2480151207Swpaul if (keys_set) { 2481171390Sthompsa DPRINTF(("Setting WEP on\n")); 2482151207Swpaul arg = NDIS_80211_WEPSTAT_ENABLED; 2483151207Swpaul len = sizeof(arg); 2484151207Swpaul rval = ndis_set_info(sc, 2485151207Swpaul OID_802_11_WEP_STATUS, &arg, &len); 2486151207Swpaul if (rval) 2487151207Swpaul device_printf(sc->ndis_dev, 2488151207Swpaul "enable WEP failed: %d\n", rval); 2489178354Ssam if (vap->iv_flags & IEEE80211_F_DROPUNENC) 2490151207Swpaul arg = NDIS_80211_PRIVFILT_8021XWEP; 2491151207Swpaul else 2492151207Swpaul arg = NDIS_80211_PRIVFILT_ACCEPTALL; 2493151207Swpaul 2494151207Swpaul len = sizeof(arg); 2495151207Swpaul ndis_set_info(sc, 2496151207Swpaul OID_802_11_PRIVACY_FILTER, &arg, &len); 2497124409Swpaul } 2498178354Ssam } 2499124005Swpaul 2500151207Swpaul /* Set up WPA. */ 2501178354Ssam if ((vap->iv_flags & IEEE80211_F_WPA) && 2502178354Ssam vap->iv_appie_assocreq != NULL) { 2503178354Ssam struct ieee80211_appie *ie = vap->iv_appie_assocreq; 2504178354Ssam error = ndis_set_wpa(sc, ie->ie_data, ie->ie_len); 2505178354Ssam if (error != 0) 2506151207Swpaul device_printf(sc->ndis_dev, "WPA setup failed\n"); 2507178354Ssam } 2508125068Swpaul 2509129834Swpaul#ifdef notyet 2510129834Swpaul /* Set network type. */ 2511129834Swpaul 2512129834Swpaul arg = 0; 2513129834Swpaul 2514178354Ssam switch (vap->iv_curmode) { 2515129834Swpaul case IEEE80211_MODE_11A: 2516129834Swpaul arg = NDIS_80211_NETTYPE_11OFDM5; 2517129834Swpaul break; 2518129834Swpaul case IEEE80211_MODE_11B: 2519129834Swpaul arg = NDIS_80211_NETTYPE_11DS; 2520129834Swpaul break; 2521129834Swpaul case IEEE80211_MODE_11G: 2522129834Swpaul arg = NDIS_80211_NETTYPE_11OFDM24; 2523129834Swpaul break; 2524129834Swpaul default: 2525129834Swpaul device_printf(sc->ndis_dev, "unknown mode: %d\n", 2526178354Ssam vap->iv_curmode); 2527129834Swpaul } 2528129834Swpaul 2529129834Swpaul if (arg) { 2530171390Sthompsa DPRINTF(("Setting network type to %d\n", arg)); 2531129834Swpaul len = sizeof(arg); 2532129834Swpaul rval = ndis_set_info(sc, OID_802_11_NETWORK_TYPE_IN_USE, 2533129834Swpaul &arg, &len); 2534129834Swpaul if (rval) 2535198786Srpaulo device_printf(sc->ndis_dev, 2536129834Swpaul "set nettype failed: %d\n", rval); 2537129834Swpaul } 2538130051Swpaul#endif 2539129834Swpaul 2540129834Swpaul /* 2541151207Swpaul * If the user selected a specific BSSID, try 2542151207Swpaul * to use that one. This is useful in the case where 2543151207Swpaul * there are several APs in range with the same network 2544151207Swpaul * name. To delete the BSSID, we use the broadcast 2545151207Swpaul * address as the BSSID. 2546151207Swpaul * Note that some drivers seem to allow setting a BSSID 2547151207Swpaul * in ad-hoc mode, which has the effect of forcing the 2548151207Swpaul * NIC to create an ad-hoc cell with a specific BSSID, 2549151207Swpaul * instead of a randomly chosen one. However, the net80211 2550151207Swpaul * code makes the assumtion that the BSSID setting is invalid 2551151207Swpaul * when you're in ad-hoc mode, so we don't allow that here. 2552151207Swpaul */ 2553151207Swpaul 2554151207Swpaul len = IEEE80211_ADDR_LEN; 2555178354Ssam if (vap->iv_flags & IEEE80211_F_DESBSSID && 2556178354Ssam vap->iv_opmode != IEEE80211_M_IBSS) 2557171390Sthompsa bcopy(ni->ni_bssid, bssid, len); 2558151207Swpaul else 2559151207Swpaul bcopy(ifp->if_broadcastaddr, bssid, len); 2560151207Swpaul 2561174270Swkoszek DPRINTF(("Setting BSSID to %6D\n", (uint8_t *)&bssid, ":")); 2562151207Swpaul rval = ndis_set_info(sc, OID_802_11_BSSID, &bssid, &len); 2563151207Swpaul if (rval) 2564151207Swpaul device_printf(sc->ndis_dev, 2565151207Swpaul "setting BSSID failed: %d\n", rval); 2566151207Swpaul 2567128229Swpaul /* Set SSID -- always do this last. */ 2568128229Swpaul 2569171390Sthompsa#ifdef NDIS_DEBUG 2570174157Sthompsa if (ndis_debug > 0) { 2571174157Sthompsa printf("Setting ESSID to "); 2572174157Sthompsa ieee80211_print_essid(ni->ni_essid, ni->ni_esslen); 2573174157Sthompsa printf("\n"); 2574174157Sthompsa } 2575171390Sthompsa#endif 2576171390Sthompsa 2577128229Swpaul len = sizeof(ssid); 2578128229Swpaul bzero((char *)&ssid, len); 2579171390Sthompsa ssid.ns_ssidlen = ni->ni_esslen; 2580128229Swpaul if (ssid.ns_ssidlen == 0) { 2581128229Swpaul ssid.ns_ssidlen = 1; 2582128229Swpaul } else 2583171390Sthompsa bcopy(ni->ni_essid, ssid.ns_ssid, ssid.ns_ssidlen); 2584151207Swpaul 2585128229Swpaul rval = ndis_set_info(sc, OID_802_11_SSID, &ssid, &len); 2586128229Swpaul 2587128229Swpaul if (rval) 2588128229Swpaul device_printf (sc->ndis_dev, "set ssid failed: %d\n", rval); 2589128229Swpaul 2590123695Swpaul return; 2591123695Swpaul} 2592123695Swpaul 2593124409Swpaulstatic int 2594194706Scokanendis_get_bssid_list(sc, bl) 2595194706Scokane struct ndis_softc *sc; 2596194706Scokane ndis_80211_bssid_list_ex **bl; 2597194706Scokane{ 2598194706Scokane int len, error; 2599194706Scokane 2600194706Scokane len = sizeof(uint32_t) + (sizeof(ndis_wlan_bssid_ex) * 16); 2601194706Scokane *bl = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO); 2602194706Scokane if (*bl == NULL) 2603194706Scokane return (ENOMEM); 2604194706Scokane 2605194706Scokane error = ndis_get_info(sc, OID_802_11_BSSID_LIST, *bl, &len); 2606194706Scokane if (error == ENOSPC) { 2607194706Scokane free(*bl, M_DEVBUF); 2608194706Scokane *bl = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO); 2609194706Scokane if (*bl == NULL) 2610194706Scokane return (ENOMEM); 2611194706Scokane 2612194706Scokane error = ndis_get_info(sc, OID_802_11_BSSID_LIST, *bl, &len); 2613194706Scokane } 2614194706Scokane if (error) { 2615194706Scokane DPRINTF(("%s: failed to read\n", __func__)); 2616194706Scokane free(*bl, M_DEVBUF); 2617194706Scokane return (error); 2618194706Scokane } 2619194706Scokane 2620194706Scokane return (0); 2621194706Scokane} 2622194706Scokane 2623194706Scokanestatic int 2624124409Swpaulndis_get_assoc(sc, assoc) 2625124409Swpaul struct ndis_softc *sc; 2626127349Swpaul ndis_wlan_bssid_ex **assoc; 2627124409Swpaul{ 2628184833Sthompsa struct ifnet *ifp = sc->ifp; 2629184833Sthompsa struct ieee80211com *ic = ifp->if_l2com; 2630184833Sthompsa struct ieee80211vap *vap; 2631184833Sthompsa struct ieee80211_node *ni; 2632124409Swpaul ndis_80211_bssid_list_ex *bl; 2633124409Swpaul ndis_wlan_bssid_ex *bs; 2634124409Swpaul ndis_80211_macaddr bssid; 2635124409Swpaul int i, len, error; 2636124409Swpaul 2637124899Swpaul if (!sc->ndis_link) 2638198786Srpaulo return (ENOENT); 2639124899Swpaul 2640124409Swpaul len = sizeof(bssid); 2641124409Swpaul error = ndis_get_info(sc, OID_802_11_BSSID, &bssid, &len); 2642124409Swpaul if (error) { 2643124899Swpaul device_printf(sc->ndis_dev, "failed to get bssid\n"); 2644198786Srpaulo return (ENOENT); 2645124409Swpaul } 2646152136Swpaul 2647184833Sthompsa vap = TAILQ_FIRST(&ic->ic_vaps); 2648184833Sthompsa ni = vap->iv_bss; 2649184833Sthompsa 2650194706Scokane error = ndis_get_bssid_list(sc, &bl); 2651194706Scokane if (error) 2652124409Swpaul return (error); 2653124409Swpaul 2654124409Swpaul bs = (ndis_wlan_bssid_ex *)&bl->nblx_bssid[0]; 2655124409Swpaul for (i = 0; i < bl->nblx_items; i++) { 2656124409Swpaul if (bcmp(bs->nwbx_macaddr, bssid, sizeof(bssid)) == 0) { 2657127349Swpaul *assoc = malloc(bs->nwbx_len, M_TEMP, M_NOWAIT); 2658127349Swpaul if (*assoc == NULL) { 2659127349Swpaul free(bl, M_TEMP); 2660198786Srpaulo return (ENOMEM); 2661127349Swpaul } 2662127349Swpaul bcopy((char *)bs, (char *)*assoc, bs->nwbx_len); 2663124409Swpaul free(bl, M_TEMP); 2664184833Sthompsa if (ic->ic_opmode == IEEE80211_M_STA) 2665184833Sthompsa ni->ni_associd = 1 | 0xc000; /* fake associd */ 2666198786Srpaulo return (0); 2667184833Sthompsa } 2668124409Swpaul bs = (ndis_wlan_bssid_ex *)((char *)bs + bs->nwbx_len); 2669124409Swpaul } 2670124409Swpaul 2671124409Swpaul free(bl, M_TEMP); 2672198786Srpaulo return (ENOENT); 2673124409Swpaul} 2674124409Swpaul 2675124409Swpaulstatic void 2676123695Swpaulndis_getstate_80211(sc) 2677123695Swpaul struct ndis_softc *sc; 2678123695Swpaul{ 2679123695Swpaul struct ieee80211com *ic; 2680178354Ssam struct ieee80211vap *vap; 2681178354Ssam struct ieee80211_node *ni; 2682127349Swpaul ndis_wlan_bssid_ex *bs; 2683123695Swpaul int rval, len, i = 0; 2684171390Sthompsa int chanflag; 2685123695Swpaul uint32_t arg; 2686123695Swpaul struct ifnet *ifp; 2687123695Swpaul 2688147256Sbrooks ifp = sc->ifp; 2689178354Ssam ic = ifp->if_l2com; 2690178354Ssam vap = TAILQ_FIRST(&ic->ic_vaps); 2691178354Ssam ni = vap->iv_bss; 2692123695Swpaul 2693131750Swpaul if (!NDIS_INITIALIZED(sc)) 2694123695Swpaul return; 2695123695Swpaul 2696171602Sthompsa if ((rval = ndis_get_assoc(sc, &bs)) != 0) 2697125377Swpaul return; 2698124409Swpaul 2699171602Sthompsa /* We're associated, retrieve info on the current bssid. */ 2700171602Sthompsa ic->ic_curmode = ndis_nettype_mode(bs->nwbx_nettype); 2701171602Sthompsa chanflag = ndis_nettype_chan(bs->nwbx_nettype); 2702178354Ssam IEEE80211_ADDR_COPY(ni->ni_bssid, bs->nwbx_macaddr); 2703171602Sthompsa 2704151832Swpaul /* Get SSID from current association info. */ 2705178354Ssam bcopy(bs->nwbx_ssid.ns_ssid, ni->ni_essid, 2706151832Swpaul bs->nwbx_ssid.ns_ssidlen); 2707178354Ssam ni->ni_esslen = bs->nwbx_ssid.ns_ssidlen; 2708123695Swpaul 2709124409Swpaul if (ic->ic_caps & IEEE80211_C_PMGT) { 2710124409Swpaul len = sizeof(arg); 2711124409Swpaul rval = ndis_get_info(sc, OID_802_11_POWER_MODE, &arg, &len); 2712123695Swpaul 2713124409Swpaul if (rval) 2714124409Swpaul device_printf(sc->ndis_dev, 2715124409Swpaul "get power mode failed: %d\n", rval); 2716124409Swpaul if (arg == NDIS_80211_POWERMODE_CAM) 2717194432Scokane vap->iv_flags &= ~IEEE80211_F_PMGTON; 2718124409Swpaul else 2719194432Scokane vap->iv_flags |= IEEE80211_F_PMGTON; 2720124409Swpaul } 2721124409Swpaul 2722187104Sthompsa /* Get TX power */ 2723189550Ssam if (ic->ic_caps & IEEE80211_C_TXPMGT) { 2724189550Ssam len = sizeof(arg); 2725189550Ssam ndis_get_info(sc, OID_802_11_TX_POWER_LEVEL, &arg, &len); 2726189550Ssam for (i = 0; i < (sizeof(dBm2mW) / sizeof(dBm2mW[0])); i++) 2727187104Sthompsa if (dBm2mW[i] >= arg) 2728187104Sthompsa break; 2729187104Sthompsa ic->ic_txpowlimit = i; 2730187104Sthompsa } 2731187104Sthompsa 2732151832Swpaul /* 2733151832Swpaul * Use the current association information to reflect 2734151832Swpaul * what channel we're on. 2735151832Swpaul */ 2736171390Sthompsa ic->ic_curchan = ieee80211_find_channel(ic, 2737171390Sthompsa bs->nwbx_config.nc_dsconfig / 1000, chanflag); 2738171390Sthompsa if (ic->ic_curchan == NULL) 2739171390Sthompsa ic->ic_curchan = &ic->ic_channels[0]; 2740178354Ssam ni->ni_chan = ic->ic_curchan; 2741171390Sthompsa ic->ic_bsschan = ic->ic_curchan; 2742124409Swpaul 2743151832Swpaul free(bs, M_TEMP); 2744151832Swpaul 2745151832Swpaul /* 2746198786Srpaulo * Determine current authentication mode. 2747151832Swpaul */ 2748123695Swpaul len = sizeof(arg); 2749151832Swpaul rval = ndis_get_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &len); 2750151832Swpaul if (rval) 2751198786Srpaulo device_printf(sc->ndis_dev, 2752151832Swpaul "get authmode status failed: %d\n", rval); 2753151832Swpaul else { 2754194432Scokane vap->iv_flags &= ~IEEE80211_F_WPA; 2755198786Srpaulo switch (arg) { 2756151832Swpaul case NDIS_80211_AUTHMODE_OPEN: 2757178354Ssam ni->ni_authmode = IEEE80211_AUTH_OPEN; 2758151832Swpaul break; 2759151832Swpaul case NDIS_80211_AUTHMODE_SHARED: 2760178354Ssam ni->ni_authmode = IEEE80211_AUTH_SHARED; 2761151832Swpaul break; 2762151832Swpaul case NDIS_80211_AUTHMODE_AUTO: 2763178354Ssam ni->ni_authmode = IEEE80211_AUTH_AUTO; 2764151832Swpaul break; 2765151832Swpaul case NDIS_80211_AUTHMODE_WPA: 2766151832Swpaul case NDIS_80211_AUTHMODE_WPAPSK: 2767151832Swpaul case NDIS_80211_AUTHMODE_WPANONE: 2768178354Ssam ni->ni_authmode = IEEE80211_AUTH_WPA; 2769194432Scokane vap->iv_flags |= IEEE80211_F_WPA1; 2770151832Swpaul break; 2771151832Swpaul case NDIS_80211_AUTHMODE_WPA2: 2772151832Swpaul case NDIS_80211_AUTHMODE_WPA2PSK: 2773178354Ssam ni->ni_authmode = IEEE80211_AUTH_WPA; 2774194432Scokane vap->iv_flags |= IEEE80211_F_WPA2; 2775151832Swpaul break; 2776151832Swpaul default: 2777178354Ssam ni->ni_authmode = IEEE80211_AUTH_NONE; 2778151832Swpaul break; 2779151832Swpaul } 2780151832Swpaul } 2781151832Swpaul 2782151832Swpaul len = sizeof(arg); 2783123695Swpaul rval = ndis_get_info(sc, OID_802_11_WEP_STATUS, &arg, &len); 2784123695Swpaul 2785123695Swpaul if (rval) 2786198786Srpaulo device_printf(sc->ndis_dev, 2787124060Swpaul "get wep status failed: %d\n", rval); 2788123695Swpaul 2789123695Swpaul if (arg == NDIS_80211_WEPSTAT_ENABLED) 2790194432Scokane vap->iv_flags |= IEEE80211_F_PRIVACY|IEEE80211_F_DROPUNENC; 2791151832Swpaul else 2792194432Scokane vap->iv_flags &= ~(IEEE80211_F_PRIVACY|IEEE80211_F_DROPUNENC); 2793123695Swpaul} 2794123695Swpaul 2795123474Swpaulstatic int 2796123474Swpaulndis_ioctl(ifp, command, data) 2797123474Swpaul struct ifnet *ifp; 2798123474Swpaul u_long command; 2799123474Swpaul caddr_t data; 2800123474Swpaul{ 2801123474Swpaul struct ndis_softc *sc = ifp->if_softc; 2802123474Swpaul struct ifreq *ifr = (struct ifreq *) data; 2803123695Swpaul int i, error = 0; 2804123474Swpaul 2805123474Swpaul /*NDIS_LOCK(sc);*/ 2806123474Swpaul 2807198786Srpaulo switch (command) { 2808123474Swpaul case SIOCSIFFLAGS: 2809123474Swpaul if (ifp->if_flags & IFF_UP) { 2810148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING && 2811123695Swpaul ifp->if_flags & IFF_PROMISC && 2812123695Swpaul !(sc->ndis_if_flags & IFF_PROMISC)) { 2813123695Swpaul sc->ndis_filter |= 2814123695Swpaul NDIS_PACKET_TYPE_PROMISCUOUS; 2815124709Swpaul i = sizeof(sc->ndis_filter); 2816124709Swpaul error = ndis_set_info(sc, 2817123695Swpaul OID_GEN_CURRENT_PACKET_FILTER, 2818123695Swpaul &sc->ndis_filter, &i); 2819148887Srwatson } else if (ifp->if_drv_flags & IFF_DRV_RUNNING && 2820123695Swpaul !(ifp->if_flags & IFF_PROMISC) && 2821123695Swpaul sc->ndis_if_flags & IFF_PROMISC) { 2822123695Swpaul sc->ndis_filter &= 2823123695Swpaul ~NDIS_PACKET_TYPE_PROMISCUOUS; 2824124709Swpaul i = sizeof(sc->ndis_filter); 2825124709Swpaul error = ndis_set_info(sc, 2826123695Swpaul OID_GEN_CURRENT_PACKET_FILTER, 2827123695Swpaul &sc->ndis_filter, &i); 2828123695Swpaul } else 2829123695Swpaul ndis_init(sc); 2830123474Swpaul } else { 2831148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2832123474Swpaul ndis_stop(sc); 2833123474Swpaul } 2834123695Swpaul sc->ndis_if_flags = ifp->if_flags; 2835123474Swpaul error = 0; 2836123474Swpaul break; 2837123474Swpaul case SIOCADDMULTI: 2838123474Swpaul case SIOCDELMULTI: 2839123474Swpaul ndis_setmulti(sc); 2840123474Swpaul error = 0; 2841123474Swpaul break; 2842123474Swpaul case SIOCGIFMEDIA: 2843123474Swpaul case SIOCSIFMEDIA: 2844178704Sthompsa error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); 2845123474Swpaul break; 2846124821Swpaul case SIOCSIFCAP: 2847124821Swpaul ifp->if_capenable = ifr->ifr_reqcap; 2848124821Swpaul if (ifp->if_capenable & IFCAP_TXCSUM) 2849124821Swpaul ifp->if_hwassist = sc->ndis_hwassist; 2850124821Swpaul else 2851124821Swpaul ifp->if_hwassist = 0; 2852124821Swpaul ndis_set_offload(sc); 2853124821Swpaul break; 2854178704Sthompsa default: 2855178704Sthompsa error = ether_ioctl(ifp, command, data); 2856178704Sthompsa break; 2857178704Sthompsa } 2858178704Sthompsa 2859178704Sthompsa /*NDIS_UNLOCK(sc);*/ 2860178704Sthompsa 2861178704Sthompsa return(error); 2862178704Sthompsa} 2863178704Sthompsa 2864178704Sthompsastatic int 2865178704Sthompsandis_ioctl_80211(ifp, command, data) 2866178704Sthompsa struct ifnet *ifp; 2867178704Sthompsa u_long command; 2868178704Sthompsa caddr_t data; 2869178704Sthompsa{ 2870178704Sthompsa struct ndis_softc *sc = ifp->if_softc; 2871178704Sthompsa struct ieee80211com *ic = ifp->if_l2com; 2872178704Sthompsa struct ifreq *ifr = (struct ifreq *) data; 2873178704Sthompsa struct ndis_oid_data oid; 2874178704Sthompsa struct ndis_evt evt; 2875178704Sthompsa void *oidbuf; 2876178704Sthompsa int error = 0; 2877178704Sthompsa 2878198786Srpaulo switch (command) { 2879178704Sthompsa case SIOCSIFFLAGS: 2880178704Sthompsa /*NDIS_LOCK(sc);*/ 2881178704Sthompsa if (ifp->if_flags & IFF_UP) { 2882178930Sthompsa if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 2883178704Sthompsa ndis_init(sc); 2884178704Sthompsa } else { 2885178704Sthompsa if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2886178704Sthompsa ndis_stop(sc); 2887178704Sthompsa } 2888178704Sthompsa sc->ndis_if_flags = ifp->if_flags; 2889178704Sthompsa error = 0; 2890178704Sthompsa /*NDIS_UNLOCK(sc);*/ 2891178704Sthompsa break; 2892151207Swpaul case SIOCGDRVSPEC: 2893164033Srwatson if ((error = priv_check(curthread, PRIV_DRIVER))) 2894151207Swpaul break; 2895151207Swpaul error = copyin(ifr->ifr_data, &oid, sizeof(oid)); 2896151207Swpaul if (error) 2897151207Swpaul break; 2898151207Swpaul oidbuf = malloc(oid.len, M_TEMP, M_NOWAIT|M_ZERO); 2899151207Swpaul if (oidbuf == NULL) { 2900151207Swpaul error = ENOMEM; 2901151207Swpaul break; 2902151207Swpaul } 2903151207Swpaul error = copyin(ifr->ifr_data + sizeof(oid), oidbuf, oid.len); 2904151207Swpaul if (error) { 2905151207Swpaul free(oidbuf, M_TEMP); 2906151207Swpaul break; 2907151207Swpaul } 2908151207Swpaul error = ndis_get_info(sc, oid.oid, oidbuf, &oid.len); 2909151207Swpaul if (error) { 2910151207Swpaul free(oidbuf, M_TEMP); 2911151207Swpaul break; 2912151207Swpaul } 2913151207Swpaul error = copyout(&oid, ifr->ifr_data, sizeof(oid)); 2914151207Swpaul if (error) { 2915151207Swpaul free(oidbuf, M_TEMP); 2916151207Swpaul break; 2917151207Swpaul } 2918151207Swpaul error = copyout(oidbuf, ifr->ifr_data + sizeof(oid), oid.len); 2919151207Swpaul free(oidbuf, M_TEMP); 2920151207Swpaul break; 2921151207Swpaul case SIOCSDRVSPEC: 2922164033Srwatson if ((error = priv_check(curthread, PRIV_DRIVER))) 2923151207Swpaul break; 2924151207Swpaul error = copyin(ifr->ifr_data, &oid, sizeof(oid)); 2925151207Swpaul if (error) 2926151207Swpaul break; 2927151207Swpaul oidbuf = malloc(oid.len, M_TEMP, M_NOWAIT|M_ZERO); 2928151207Swpaul if (oidbuf == NULL) { 2929151207Swpaul error = ENOMEM; 2930151207Swpaul break; 2931151207Swpaul } 2932151207Swpaul error = copyin(ifr->ifr_data + sizeof(oid), oidbuf, oid.len); 2933151207Swpaul if (error) { 2934151207Swpaul free(oidbuf, M_TEMP); 2935151207Swpaul break; 2936151207Swpaul } 2937151207Swpaul error = ndis_set_info(sc, oid.oid, oidbuf, &oid.len); 2938151207Swpaul if (error) { 2939151207Swpaul free(oidbuf, M_TEMP); 2940151207Swpaul break; 2941151207Swpaul } 2942151207Swpaul error = copyout(&oid, ifr->ifr_data, sizeof(oid)); 2943151207Swpaul if (error) { 2944151207Swpaul free(oidbuf, M_TEMP); 2945151207Swpaul break; 2946151207Swpaul } 2947151207Swpaul error = copyout(oidbuf, ifr->ifr_data + sizeof(oid), oid.len); 2948151207Swpaul free(oidbuf, M_TEMP); 2949151207Swpaul break; 2950151207Swpaul case SIOCGPRIVATE_0: 2951164033Srwatson if ((error = priv_check(curthread, PRIV_DRIVER))) 2952151207Swpaul break; 2953151207Swpaul NDIS_LOCK(sc); 2954151207Swpaul if (sc->ndis_evt[sc->ndis_evtcidx].ne_sts == 0) { 2955151207Swpaul error = ENOENT; 2956151207Swpaul NDIS_UNLOCK(sc); 2957151207Swpaul break; 2958151207Swpaul } 2959151207Swpaul error = copyin(ifr->ifr_data, &evt, sizeof(evt)); 2960151217Swpaul if (error) { 2961151217Swpaul NDIS_UNLOCK(sc); 2962151207Swpaul break; 2963151217Swpaul } 2964151207Swpaul if (evt.ne_len < sc->ndis_evt[sc->ndis_evtcidx].ne_len) { 2965151207Swpaul error = ENOSPC; 2966151207Swpaul NDIS_UNLOCK(sc); 2967151207Swpaul break; 2968151207Swpaul } 2969151207Swpaul error = copyout(&sc->ndis_evt[sc->ndis_evtcidx], 2970151207Swpaul ifr->ifr_data, sizeof(uint32_t) * 2); 2971151207Swpaul if (error) { 2972151207Swpaul NDIS_UNLOCK(sc); 2973151207Swpaul break; 2974151207Swpaul } 2975151207Swpaul if (sc->ndis_evt[sc->ndis_evtcidx].ne_len) { 2976151207Swpaul error = copyout(sc->ndis_evt[sc->ndis_evtcidx].ne_buf, 2977151207Swpaul ifr->ifr_data + (sizeof(uint32_t) * 2), 2978151207Swpaul sc->ndis_evt[sc->ndis_evtcidx].ne_len); 2979151216Swpaul if (error) { 2980151216Swpaul NDIS_UNLOCK(sc); 2981151207Swpaul break; 2982151216Swpaul } 2983151207Swpaul free(sc->ndis_evt[sc->ndis_evtcidx].ne_buf, M_TEMP); 2984151207Swpaul sc->ndis_evt[sc->ndis_evtcidx].ne_buf = NULL; 2985151207Swpaul } 2986151207Swpaul sc->ndis_evt[sc->ndis_evtcidx].ne_len = 0; 2987151207Swpaul sc->ndis_evt[sc->ndis_evtcidx].ne_sts = 0; 2988151207Swpaul NDIS_EVTINC(sc->ndis_evtcidx); 2989151207Swpaul NDIS_UNLOCK(sc); 2990151207Swpaul break; 2991178704Sthompsa case SIOCGIFMEDIA: 2992178704Sthompsa error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, command); 2993178704Sthompsa break; 2994178704Sthompsa case SIOCGIFADDR: 2995178354Ssam error = ether_ioctl(ifp, command, data); 2996123474Swpaul break; 2997178704Sthompsa default: 2998178704Sthompsa error = EINVAL; 2999178704Sthompsa break; 3000123474Swpaul } 3001198786Srpaulo return (error); 3002123474Swpaul} 3003123474Swpaul 3004151207Swpaulint 3005178354Ssamndis_del_key(vap, key) 3006178354Ssam struct ieee80211vap *vap; 3007151207Swpaul const struct ieee80211_key *key; 3008151207Swpaul{ 3009145283Swpaul struct ndis_softc *sc; 3010151207Swpaul ndis_80211_key rkey; 3011151207Swpaul int len, error = 0; 3012145283Swpaul 3013178354Ssam sc = vap->iv_ic->ic_ifp->if_softc; 3014145283Swpaul 3015151207Swpaul bzero((char *)&rkey, sizeof(rkey)); 3016151207Swpaul len = sizeof(rkey); 3017145283Swpaul 3018151207Swpaul rkey.nk_len = len; 3019151207Swpaul rkey.nk_keyidx = key->wk_keyix; 3020145283Swpaul 3021178354Ssam bcopy(vap->iv_ifp->if_broadcastaddr, 3022151207Swpaul rkey.nk_bssid, IEEE80211_ADDR_LEN); 3023145283Swpaul 3024151207Swpaul error = ndis_set_info(sc, OID_802_11_REMOVE_KEY, &rkey, &len); 3025145283Swpaul 3026151207Swpaul if (error) 3027198786Srpaulo return (0); 3028151207Swpaul 3029198786Srpaulo return (1); 3030151207Swpaul} 3031151207Swpaul 3032151207Swpaul/* 3033151207Swpaul * In theory this could be called for any key, but we'll 3034151207Swpaul * only use it for WPA TKIP or AES keys. These need to be 3035151207Swpaul * set after initial authentication with the AP. 3036151207Swpaul */ 3037151207Swpaulstatic int 3038178354Ssamndis_add_key(vap, key, mac) 3039178354Ssam struct ieee80211vap *vap; 3040151207Swpaul const struct ieee80211_key *key; 3041151207Swpaul const uint8_t mac[IEEE80211_ADDR_LEN]; 3042151207Swpaul{ 3043151207Swpaul struct ndis_softc *sc; 3044178354Ssam struct ifnet *ifp; 3045151207Swpaul ndis_80211_key rkey; 3046151207Swpaul int len, error = 0; 3047151207Swpaul 3048178354Ssam ifp = vap->iv_ic->ic_ifp; 3049178354Ssam sc = ifp->if_softc; 3050151207Swpaul 3051151207Swpaul switch (key->wk_cipher->ic_cipher) { 3052145283Swpaul case IEEE80211_CIPHER_TKIP: 3053145283Swpaul 3054151207Swpaul len = sizeof(ndis_80211_key); 3055151207Swpaul bzero((char *)&rkey, sizeof(rkey)); 3056145283Swpaul 3057151207Swpaul rkey.nk_len = len; 3058151207Swpaul rkey.nk_keylen = key->wk_keylen; 3059151207Swpaul 3060151207Swpaul if (key->wk_flags & IEEE80211_KEY_SWMIC) 3061151207Swpaul rkey.nk_keylen += 16; 3062151207Swpaul 3063145283Swpaul /* key index - gets weird in NDIS */ 3064145283Swpaul 3065151207Swpaul if (key->wk_keyix != IEEE80211_KEYIX_NONE) 3066151207Swpaul rkey.nk_keyidx = key->wk_keyix; 3067151207Swpaul else 3068151207Swpaul rkey.nk_keyidx = 0; 3069151207Swpaul 3070151207Swpaul if (key->wk_flags & IEEE80211_KEY_XMIT) 3071151207Swpaul rkey.nk_keyidx |= 1 << 31; 3072151207Swpaul 3073151207Swpaul if (key->wk_flags & IEEE80211_KEY_GROUP) { 3074178354Ssam bcopy(ifp->if_broadcastaddr, 3075151207Swpaul rkey.nk_bssid, IEEE80211_ADDR_LEN); 3076145283Swpaul } else { 3077178354Ssam bcopy(vap->iv_bss->ni_bssid, 3078151207Swpaul rkey.nk_bssid, IEEE80211_ADDR_LEN); 3079145283Swpaul /* pairwise key */ 3080151207Swpaul rkey.nk_keyidx |= 1 << 30; 3081145283Swpaul } 3082145283Swpaul 3083145283Swpaul /* need to set bit 29 based on keyrsc */ 3084178354Ssam rkey.nk_keyrsc = key->wk_keyrsc[0]; /* XXX need tid */ 3085145283Swpaul 3086151207Swpaul if (rkey.nk_keyrsc) 3087151207Swpaul rkey.nk_keyidx |= 1 << 29; 3088151207Swpaul 3089151207Swpaul if (key->wk_flags & IEEE80211_KEY_SWMIC) { 3090151207Swpaul bcopy(key->wk_key, rkey.nk_keydata, 16); 3091151207Swpaul bcopy(key->wk_key + 24, rkey.nk_keydata + 16, 8); 3092151207Swpaul bcopy(key->wk_key + 16, rkey.nk_keydata + 24, 8); 3093151207Swpaul } else 3094151207Swpaul bcopy(key->wk_key, rkey.nk_keydata, key->wk_keylen); 3095151207Swpaul 3096151207Swpaul error = ndis_set_info(sc, OID_802_11_ADD_KEY, &rkey, &len); 3097145283Swpaul break; 3098151207Swpaul case IEEE80211_CIPHER_WEP: 3099151207Swpaul error = 0; 3100151207Swpaul break; 3101151207Swpaul /* 3102151207Swpaul * I don't know how to set up keys for the AES 3103151207Swpaul * cipher yet. Is it the same as TKIP? 3104151207Swpaul */ 3105145283Swpaul case IEEE80211_CIPHER_AES_CCM: 3106145283Swpaul default: 3107151207Swpaul error = ENOTTY; 3108151207Swpaul break; 3109145283Swpaul } 3110151207Swpaul 3111151207Swpaul /* We need to return 1 for success, 0 for failure. */ 3112151207Swpaul 3113151207Swpaul if (error) 3114198786Srpaulo return (0); 3115151207Swpaul 3116151207Swpaul return (1); 3117145283Swpaul} 3118145283Swpaul 3119123474Swpaulstatic void 3120151207Swpaulndis_resettask(d, arg) 3121151207Swpaul device_object *d; 3122145895Swpaul void *arg; 3123145895Swpaul{ 3124145895Swpaul struct ndis_softc *sc; 3125145895Swpaul 3126145895Swpaul sc = arg; 3127145895Swpaul ndis_reset_nic(sc); 3128145895Swpaul} 3129145895Swpaul 3130123474Swpaul/* 3131123474Swpaul * Stop the adapter and free any mbufs allocated to the 3132123474Swpaul * RX and TX lists. 3133123474Swpaul */ 3134123474Swpaulstatic void 3135123474Swpaulndis_stop(sc) 3136123474Swpaul struct ndis_softc *sc; 3137123474Swpaul{ 3138123474Swpaul struct ifnet *ifp; 3139151207Swpaul int i; 3140123474Swpaul 3141147256Sbrooks ifp = sc->ifp; 3142178286Scokane callout_drain(&sc->ndis_stat_callout); 3143123474Swpaul 3144124697Swpaul NDIS_LOCK(sc); 3145179498Scokane sc->ndis_tx_timer = 0; 3146124697Swpaul sc->ndis_link = 0; 3147148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 3148124697Swpaul NDIS_UNLOCK(sc); 3149123474Swpaul 3150189719Sweongyo if (sc->ndis_iftype != PNPBus || 3151189719Sweongyo (sc->ndis_iftype == PNPBus && 3152189719Sweongyo !(sc->ndisusb_status & NDISUSB_STATUS_DETACH) && 3153189719Sweongyo ndisusb_halt != 0)) 3154186507Sweongyo ndis_halt_nic(sc); 3155145898Swpaul 3156151207Swpaul NDIS_LOCK(sc); 3157151207Swpaul for (i = 0; i < NDIS_EVENTS; i++) { 3158190367Sweongyo if (sc->ndis_evt[i].ne_sts && sc->ndis_evt[i].ne_buf != NULL) { 3159151207Swpaul free(sc->ndis_evt[i].ne_buf, M_TEMP); 3160190367Sweongyo sc->ndis_evt[i].ne_buf = NULL; 3161190367Sweongyo } 3162151207Swpaul sc->ndis_evt[i].ne_sts = 0; 3163151207Swpaul sc->ndis_evt[i].ne_len = 0; 3164151207Swpaul } 3165151207Swpaul sc->ndis_evtcidx = 0; 3166151207Swpaul sc->ndis_evtpidx = 0; 3167151207Swpaul NDIS_UNLOCK(sc); 3168123474Swpaul} 3169123474Swpaul 3170123474Swpaul/* 3171123474Swpaul * Stop all chip I/O so that the kernel's probe routines don't 3172123474Swpaul * get confused by errant DMAs when rebooting. 3173123474Swpaul */ 3174126706Swpaulvoid 3175123474Swpaulndis_shutdown(dev) 3176123474Swpaul device_t dev; 3177123474Swpaul{ 3178123474Swpaul struct ndis_softc *sc; 3179125068Swpaul 3180123474Swpaul sc = device_get_softc(dev); 3181146427Swpaul ndis_stop(sc); 3182123474Swpaul} 3183171390Sthompsa 3184171390Sthompsastatic int 3185178354Ssamndis_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 3186171390Sthompsa{ 3187178354Ssam struct ndis_vap *nvp = NDIS_VAP(vap); 3188178354Ssam struct ieee80211com *ic = vap->iv_ic; 3189171390Sthompsa struct ifnet *ifp = ic->ic_ifp; 3190171390Sthompsa struct ndis_softc *sc = ifp->if_softc; 3191178354Ssam enum ieee80211_state ostate; 3192171390Sthompsa 3193171390Sthompsa DPRINTF(("%s: %s -> %s\n", __func__, 3194178354Ssam ieee80211_state_name[vap->iv_state], 3195171390Sthompsa ieee80211_state_name[nstate])); 3196171390Sthompsa 3197178354Ssam ostate = vap->iv_state; 3198178354Ssam vap->iv_state = nstate; 3199171390Sthompsa 3200171390Sthompsa switch (nstate) { 3201171390Sthompsa /* pass on to net80211 */ 3202171390Sthompsa case IEEE80211_S_INIT: 3203171390Sthompsa case IEEE80211_S_SCAN: 3204178354Ssam return nvp->newstate(vap, nstate, arg); 3205171390Sthompsa case IEEE80211_S_ASSOC: 3206178930Sthompsa if (ostate != IEEE80211_S_AUTH) { 3207191746Sthompsa IEEE80211_UNLOCK(ic); 3208191746Sthompsa ndis_auth_and_assoc(sc, vap); 3209191746Sthompsa IEEE80211_LOCK(ic); 3210178930Sthompsa } 3211171390Sthompsa break; 3212171390Sthompsa case IEEE80211_S_AUTH: 3213191746Sthompsa IEEE80211_UNLOCK(ic); 3214191746Sthompsa ndis_auth_and_assoc(sc, vap); 3215191746Sthompsa if (vap->iv_state == IEEE80211_S_AUTH) /* XXX */ 3216191746Sthompsa ieee80211_new_state(vap, IEEE80211_S_ASSOC, 0); 3217191746Sthompsa IEEE80211_LOCK(ic); 3218191746Sthompsa break; 3219171390Sthompsa default: 3220171390Sthompsa break; 3221171390Sthompsa } 3222171390Sthompsa return (0); 3223171390Sthompsa} 3224171390Sthompsa 3225171390Sthompsastatic void 3226191746Sthompsandis_scan(void *arg) 3227171390Sthompsa{ 3228200037Sjhb struct ieee80211vap *vap = arg; 3229171390Sthompsa 3230178354Ssam ieee80211_scan_done(vap); 3231171390Sthompsa} 3232171390Sthompsa 3233171390Sthompsastatic void 3234171390Sthompsandis_scan_results(struct ndis_softc *sc) 3235171390Sthompsa{ 3236178354Ssam struct ieee80211com *ic; 3237178354Ssam struct ieee80211vap *vap; 3238171390Sthompsa ndis_80211_bssid_list_ex *bl; 3239171390Sthompsa ndis_wlan_bssid_ex *wb; 3240171390Sthompsa struct ieee80211_scanparams sp; 3241171390Sthompsa struct ieee80211_frame wh; 3242178930Sthompsa struct ieee80211_channel *saved_chan; 3243171390Sthompsa int i, j; 3244194706Scokane int rssi, noise, freq, chanflag; 3245171390Sthompsa uint8_t ssid[2+IEEE80211_NWID_LEN]; 3246171390Sthompsa uint8_t rates[2+IEEE80211_RATE_MAXSIZE]; 3247171390Sthompsa uint8_t *frm, *efrm; 3248171390Sthompsa 3249178354Ssam ic = sc->ifp->if_l2com; 3250178354Ssam vap = TAILQ_FIRST(&ic->ic_vaps); 3251178930Sthompsa saved_chan = ic->ic_curchan; 3252171390Sthompsa noise = -96; 3253174401Sthompsa 3254194706Scokane if (ndis_get_bssid_list(sc, &bl)) 3255174401Sthompsa return; 3256174401Sthompsa 3257171602Sthompsa DPRINTF(("%s: %d results\n", __func__, bl->nblx_items)); 3258171390Sthompsa wb = &bl->nblx_bssid[0]; 3259171390Sthompsa for (i = 0; i < bl->nblx_items; i++) { 3260171390Sthompsa memset(&sp, 0, sizeof(sp)); 3261171390Sthompsa 3262171390Sthompsa memcpy(wh.i_addr2, wb->nwbx_macaddr, sizeof(wh.i_addr2)); 3263171390Sthompsa memcpy(wh.i_addr3, wb->nwbx_macaddr, sizeof(wh.i_addr3)); 3264171602Sthompsa rssi = 100 * (wb->nwbx_rssi - noise) / (-32 - noise); 3265171390Sthompsa rssi = max(0, min(rssi, 100)); /* limit 0 <= rssi <= 100 */ 3266171390Sthompsa if (wb->nwbx_privacy) 3267171390Sthompsa sp.capinfo |= IEEE80211_CAPINFO_PRIVACY; 3268171390Sthompsa sp.bintval = wb->nwbx_config.nc_beaconperiod; 3269171390Sthompsa switch (wb->nwbx_netinfra) { 3270171390Sthompsa case NDIS_80211_NET_INFRA_IBSS: 3271171390Sthompsa sp.capinfo |= IEEE80211_CAPINFO_IBSS; 3272171390Sthompsa break; 3273171390Sthompsa case NDIS_80211_NET_INFRA_BSS: 3274171390Sthompsa sp.capinfo |= IEEE80211_CAPINFO_ESS; 3275171390Sthompsa break; 3276171390Sthompsa } 3277171390Sthompsa sp.rates = &rates[0]; 3278171390Sthompsa for (j = 0; j < IEEE80211_RATE_MAXSIZE; j++) { 3279171390Sthompsa /* XXX - check units */ 3280171390Sthompsa if (wb->nwbx_supportedrates[j] == 0) 3281171390Sthompsa break; 3282171390Sthompsa rates[2 + j] = 3283171390Sthompsa wb->nwbx_supportedrates[j] & 0x7f; 3284171390Sthompsa } 3285171390Sthompsa rates[1] = j; 3286171390Sthompsa sp.ssid = (uint8_t *)&ssid[0]; 3287171390Sthompsa memcpy(sp.ssid + 2, &wb->nwbx_ssid.ns_ssid, 3288171390Sthompsa wb->nwbx_ssid.ns_ssidlen); 3289171390Sthompsa sp.ssid[1] = wb->nwbx_ssid.ns_ssidlen; 3290171390Sthompsa 3291171602Sthompsa chanflag = ndis_nettype_chan(wb->nwbx_nettype); 3292171602Sthompsa freq = wb->nwbx_config.nc_dsconfig / 1000; 3293178354Ssam sp.chan = sp.bchan = ieee80211_mhz2ieee(freq, chanflag); 3294178930Sthompsa /* Hack ic->ic_curchan to be in sync with the scan result */ 3295178930Sthompsa ic->ic_curchan = ieee80211_find_channel(ic, freq, chanflag); 3296178930Sthompsa if (ic->ic_curchan == NULL) 3297178930Sthompsa ic->ic_curchan = &ic->ic_channels[0]; 3298171390Sthompsa 3299171390Sthompsa /* Process extended info from AP */ 3300171390Sthompsa if (wb->nwbx_len > sizeof(ndis_wlan_bssid)) { 3301171390Sthompsa frm = (uint8_t *)&wb->nwbx_ies; 3302171390Sthompsa efrm = frm + wb->nwbx_ielen; 3303171390Sthompsa if (efrm - frm < 12) 3304171390Sthompsa goto done; 3305200524Srpaulo sp.tstamp = frm; frm += 8; 3306200524Srpaulo sp.bintval = le16toh(*(uint16_t *)frm); frm += 2; 3307200524Srpaulo sp.capinfo = le16toh(*(uint16_t *)frm); frm += 2; 3308200524Srpaulo sp.ies = frm; 3309200524Srpaulo sp.ies_len = efrm - frm; 3310171390Sthompsa } 3311171390Sthompsadone: 3312171602Sthompsa DPRINTF(("scan: bssid %s chan %dMHz (%d/%d) rssi %d\n", 3313171602Sthompsa ether_sprintf(wb->nwbx_macaddr), freq, sp.bchan, chanflag, 3314171602Sthompsa rssi)); 3315192497Ssam ieee80211_add_scan(vap, &sp, &wh, 0, rssi, noise); 3316171390Sthompsa wb = (ndis_wlan_bssid_ex *)((char *)wb + wb->nwbx_len); 3317171390Sthompsa } 3318171602Sthompsa free(bl, M_DEVBUF); 3319178930Sthompsa /* Restore the channel after messing with it */ 3320178930Sthompsa ic->ic_curchan = saved_chan; 3321171390Sthompsa} 3322171390Sthompsa 3323171390Sthompsastatic void 3324171390Sthompsandis_scan_start(struct ieee80211com *ic) 3325171390Sthompsa{ 3326171390Sthompsa struct ifnet *ifp = ic->ic_ifp; 3327171390Sthompsa struct ndis_softc *sc = ifp->if_softc; 3328191746Sthompsa struct ieee80211vap *vap; 3329191746Sthompsa struct ieee80211_scan_state *ss; 3330191746Sthompsa ndis_80211_ssid ssid; 3331191746Sthompsa int error, len; 3332171390Sthompsa 3333191746Sthompsa ss = ic->ic_scan; 3334191746Sthompsa vap = TAILQ_FIRST(&ic->ic_vaps); 3335191746Sthompsa 3336191746Sthompsa if (!NDIS_INITIALIZED(sc)) { 3337191746Sthompsa DPRINTF(("%s: scan aborted\n", __func__)); 3338191746Sthompsa ieee80211_cancel_scan(vap); 3339191746Sthompsa return; 3340191746Sthompsa } 3341191746Sthompsa 3342191746Sthompsa len = sizeof(ssid); 3343191746Sthompsa bzero((char *)&ssid, len); 3344191746Sthompsa if (ss->ss_nssid == 0) 3345191746Sthompsa ssid.ns_ssidlen = 1; 3346191746Sthompsa else { 3347191746Sthompsa /* Perform a directed scan */ 3348191746Sthompsa ssid.ns_ssidlen = ss->ss_ssid[0].len; 3349191746Sthompsa bcopy(ss->ss_ssid[0].ssid, ssid.ns_ssid, ssid.ns_ssidlen); 3350191746Sthompsa } 3351191746Sthompsa 3352191746Sthompsa error = ndis_set_info(sc, OID_802_11_SSID, &ssid, &len); 3353191746Sthompsa if (error) 3354191746Sthompsa DPRINTF(("%s: set ESSID failed\n", __func__)); 3355191746Sthompsa 3356191746Sthompsa len = 0; 3357198786Srpaulo error = ndis_set_info(sc, OID_802_11_BSSID_LIST_SCAN, NULL, &len); 3358191746Sthompsa if (error) { 3359191746Sthompsa DPRINTF(("%s: scan command failed\n", __func__)); 3360191746Sthompsa ieee80211_cancel_scan(vap); 3361191746Sthompsa return; 3362191746Sthompsa } 3363191746Sthompsa /* Set a timer to collect the results */ 3364200037Sjhb callout_reset(&sc->ndis_scan_callout, hz * 3, ndis_scan, vap); 3365171390Sthompsa} 3366171390Sthompsa 3367171390Sthompsastatic void 3368171390Sthompsandis_set_channel(struct ieee80211com *ic) 3369171390Sthompsa{ 3370171390Sthompsa /* ignore */ 3371171390Sthompsa} 3372171390Sthompsa 3373171390Sthompsastatic void 3374178354Ssamndis_scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell) 3375171390Sthompsa{ 3376171390Sthompsa /* ignore */ 3377171390Sthompsa} 3378171390Sthompsa 3379171390Sthompsastatic void 3380178354Ssamndis_scan_mindwell(struct ieee80211_scan_state *ss) 3381171390Sthompsa{ 3382171390Sthompsa /* NB: don't try to abort scan; wait for firmware to finish */ 3383171390Sthompsa} 3384171390Sthompsa 3385171390Sthompsastatic void 3386171390Sthompsandis_scan_end(struct ieee80211com *ic) 3387171390Sthompsa{ 3388200037Sjhb struct ndis_softc *sc = ic->ic_ifp->if_softc; 3389200037Sjhb 3390200037Sjhb ndis_scan_results(sc); 3391171390Sthompsa} 3392