Home | History | Annotate | Line # | Download | only in if_ndis
if_ndis.c revision 1.36
      1 /*	$NetBSD: if_ndis.c,v 1.35 2016/02/09 08:32:10 ozaki-r Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2003
      5  *	Bill Paul <wpaul (at) windriver.com>.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by Bill Paul.
     18  * 4. Neither the name of the author nor the names of any co-contributors
     19  *    may be used to endorse or promote products derived from this software
     20  *    without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
     23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
     26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     32  * THE POSSIBILITY OF SUCH DAMAGE.
     33  */
     34 
     35 #include <sys/cdefs.h>
     36 #ifdef __FreeBSD__
     37 __FBSDID("$FreeBSD: src/sys/dev/if_ndis/if_ndis.c,v 1.69.2.6 2005/03/31 04:24:36 wpaul Exp $");
     38 #endif
     39 #ifdef __NetBSD__
     40 __KERNEL_RCSID(0, "$NetBSD: if_ndis.c,v 1.35 2016/02/09 08:32:10 ozaki-r Exp $");
     41 #endif
     42 
     43 
     44 #include <sys/param.h>
     45 #include <sys/systm.h>
     46 #include <sys/sockio.h>
     47 #include <sys/mbuf.h>
     48 #include <sys/malloc.h>
     49 #include <sys/kernel.h>
     50 #include <sys/socket.h>
     51 #include <sys/queue.h>
     52 
     53 #include <sys/device.h>
     54 #include <sys/kauth.h>
     55 
     56 #include <sys/module.h>
     57 
     58 #include <sys/proc.h>
     59 #include <sys/sysctl.h>
     60 
     61 #include <net/if.h>
     62 #include <net/if_arp.h>
     63 
     64 #include <net/if_ether.h>
     65 
     66 #include <net/if_dl.h>
     67 #include <net/if_media.h>
     68 #include <net/route.h>
     69 
     70 #include <net/bpf.h>
     71 
     72 
     73 #include <sys/bus.h>
     74 
     75 
     76 #include <net80211/ieee80211_var.h>
     77 #include <net80211/ieee80211_ioctl.h>
     78 
     79 #include <dev/ic/wi_ieee.h>
     80 
     81 #include <dev/pci/pcireg.h>
     82 #include <dev/pci/pcivar.h>
     83 #include <dev/pci/pcidevs.h>
     84 
     85 #include <compat/ndis/pe_var.h>
     86 #include <compat/ndis/resource_var.h>
     87 #include <compat/ndis/ntoskrnl_var.h>
     88 #include <compat/ndis/hal_var.h>
     89 #include <compat/ndis/ndis_var.h>
     90 #include <compat/ndis/cfg_var.h>
     91 #include <compat/ndis/nbcompat.h>
     92 #include <dev/if_ndis/if_ndisvar.h>
     93 
     94 #define NDIS_IMAGE
     95 #define NDIS_REGVALS
     96 
     97 #include "ndis_driver_data.h"
     98 
     99 void ndis_attach(void *);
    100 int ndis_detach(device_t, int);
    101 int ndis_suspend(device_t);
    102 int ndis_resume(device_t);
    103 void ndis_shutdown(device_t);
    104 
    105 
    106 /* I moved these to if_ndisvar.h */
    107 /*
    108 static __stdcall void ndis_txeof	(ndis_handle,
    109 	ndis_packet *, ndis_status);
    110 static __stdcall void ndis_rxeof	(ndis_handle,
    111 	ndis_packet **, uint32_t);
    112 static __stdcall void ndis_linksts	(ndis_handle,
    113 	ndis_status, void *, uint32_t);
    114 static __stdcall void ndis_linksts_done	(ndis_handle);
    115 */
    116 
    117 /* We need to wrap these functions for amd64. */
    118 
    119 static funcptr ndis_txeof_wrap;
    120 static funcptr ndis_rxeof_wrap;
    121 static funcptr ndis_linksts_wrap;
    122 static funcptr ndis_linksts_done_wrap;
    123 
    124 int ndis_intr(void *);
    125 static void ndis_tick		(void *);
    126 static void ndis_ticktask	(void *);
    127 static void ndis_start		(struct ifnet *);
    128 static void ndis_starttask	(void *);
    129 static int ndis_ioctl		(struct ifnet *, u_long, void *);
    130 static int ndis_wi_ioctl_get	(struct ifnet *, u_long, void *);
    131 static int ndis_wi_ioctl_set	(struct ifnet *, u_long, void *);
    132 static int ndis_init		(struct ifnet *);
    133 static void ndis_stop		(struct ndis_softc *);
    134 static void ndis_watchdog	(struct ifnet *);
    135 static int ndis_ifmedia_upd	(struct ifnet *);
    136 static void ndis_ifmedia_sts	(struct ifnet *, struct ifmediareq *);
    137 static int ndis_get_assoc	(struct ndis_softc *, ndis_wlan_bssid_ex **);
    138 static int ndis_probe_offload	(struct ndis_softc *);
    139 static int ndis_set_offload	(struct ndis_softc *);
    140 static void ndis_getstate_80211	(struct ndis_softc *);
    141 static void ndis_setstate_80211	(struct ndis_softc *);
    142 static void ndis_media_status	(struct ifnet *, struct ifmediareq *);
    143 
    144 static void ndis_setmulti	(struct ndis_softc *);
    145 static void ndis_map_sclist	(void *, bus_dma_segment_t *,
    146 	int, bus_size_t, int);
    147 
    148 int ndis_in_isr;
    149 
    150 #ifdef _MODULE
    151 
    152 static int ndisdrv_loaded = 0;
    153 int ndisdrv_modevent(module_t,  int);
    154 
    155 MODULE(MODULE_CLASS_DRIVER, ndisdrv_modevent, NULL);
    156 /*
    157  * This routine should call windrv_load() once for each driver
    158  * image. This will do the relocation and dynalinking for the
    159  * image, and create a Windows driver object which will be
    160  * saved in our driver database.
    161  */
    162 int
    163 ndisdrv_modevent(module_t mod, int cmd)
    164 {
    165 	int			error = 0;
    166 
    167 #ifdef NDIS_DBG
    168 	printf("in ndisdrv_modevent\n");
    169 #endif
    170 	switch (cmd) {
    171 	case MODULE_CMD_INIT:
    172 		ndisdrv_loaded++;
    173                 if (ndisdrv_loaded > 1)
    174 			break;
    175 		error = windrv_load(mod, (vm_offset_t)drv_data, 0);
    176 		windrv_wrap((funcptr)ndis_rxeof, &ndis_rxeof_wrap);
    177 		windrv_wrap((funcptr)ndis_txeof, &ndis_txeof_wrap);
    178 		windrv_wrap((funcptr)ndis_linksts, &ndis_linksts_wrap);
    179 		windrv_wrap((funcptr)ndis_linksts_done,
    180 		    &ndis_linksts_done_wrap);
    181 		break;
    182 	case MODULE_CMD_FINI:
    183 		ndisdrv_loaded--;
    184 		if (ndisdrv_loaded > 0)
    185 			break;
    186 		windrv_unload(mod, (vm_offset_t)drv_data, 0);
    187 		windrv_unwrap(ndis_rxeof_wrap);
    188 		windrv_unwrap(ndis_txeof_wrap);
    189 		windrv_unwrap(ndis_linksts_wrap);
    190 		windrv_unwrap(ndis_linksts_done_wrap);
    191 		break;
    192 	case MODULE_CMD_STAT:
    193 		error = ENOTTY;
    194 		break;
    195 	default:
    196 		error = EINVAL;
    197 		break;
    198 	}
    199 
    200 	return error;
    201 }
    202 
    203 int if_ndis_lkmentry(struct lkm_table *lkmtp, int cmd, int ver);
    204 
    205 CFDRIVER_DECL(ndis, DV_DULL, NULL);
    206 extern struct cfattach ndis_ca;
    207 
    208 static int pciloc[] = { -1, -1 }; /* device, function */
    209 static struct cfparent pciparent = {
    210 	"pci", "pci", DVUNIT_ANY
    211 };
    212 static struct cfdata ndis_cfdata[] = {
    213 	{"ndis", "ndis", 0, FSTATE_STAR, pciloc, 0, &pciparent, 0},
    214 	{ 0 }
    215 };
    216 
    217 static struct cfdriver *ndis_cfdrivers[] = {
    218 	&ndis_cd,
    219 	NULL
    220 };
    221 static struct cfattach *ndis_cfattachs[] = {
    222 	&ndis_ca,
    223 	NULL
    224 };
    225 static const struct cfattachlkminit ndis_cfattachinit[] = {
    226 	{ "ndis", ndis_cfattachs },
    227 	{ NULL }
    228 };
    229 
    230 MOD_DRV("ndis", ndis_cfdrivers, ndis_cfattachinit,
    231 	ndis_cfdata);
    232 
    233 int
    234 if_ndis_lkmentry(struct lkm_table *lkmtp, int cmd, int ver)
    235 {
    236 	DISPATCH(lkmtp, cmd, ver, lkm_nofunc, lkm_nofunc, lkm_nofunc);
    237 }
    238 
    239 #endif /* _MODULE */
    240 
    241 /*
    242  * Program the 64-bit multicast hash filter.
    243  */
    244 static void
    245 ndis_setmulti(struct ndis_softc *sc)
    246 {
    247 	struct ifnet		*ifp;
    248 	struct ether_multi	*ifma;
    249 	int			len, mclistsz, error;
    250 	uint8_t			*mclist;
    251 
    252 	ifp = &sc->arpcom.ac_if;
    253 
    254 	if (!NDIS_INITIALIZED(sc))
    255 		return;
    256 
    257 	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
    258 		sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
    259 		len = sizeof(sc->ndis_filter);
    260 		error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER,
    261 		    &sc->ndis_filter, &len);
    262         if (error) {
    263 		aprint_error_dev(sc->ndis_dev, "set filter failed: %d\n",
    264 			     error);
    265         }
    266 		return;
    267 	}
    268 
    269 	if (LIST_EMPTY(&sc->arpcom.ec_multiaddrs))
    270 		return;
    271 
    272 	len = sizeof(mclistsz);
    273 	ndis_get_info(sc, OID_802_3_MAXIMUM_LIST_SIZE, &mclistsz, &len);
    274 
    275 	mclist = malloc(ETHER_ADDR_LEN * mclistsz, M_TEMP, M_NOWAIT|M_ZERO);
    276 
    277 	if (mclist == NULL) {
    278 		sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
    279 		goto out;
    280 	}
    281 
    282 	sc->ndis_filter |= NDIS_PACKET_TYPE_MULTICAST;
    283 
    284 	len = 0;
    285 	LIST_FOREACH(ifma, &sc->arpcom.ec_multiaddrs, enm_list) {
    286 /*
    287  *****************************************************************************
    288  * TODO: The NetBSD ether_multi structure (sys/net/if_ether.h) defines a range
    289  * of addresses TODO: (enm_addrlo to enm_addrhi), but FreeBSD's ifmultiaddr
    290  * structure (in sys/net/if_var.h) defines only a single address.  Do we need
    291  * to add every address in the range to the list?  Seems like it to me.
    292  * But for right now I'm assuming there is only a single address.
    293  *****************************************************************************
    294  */
    295 		memcpy(mclist + (ETHER_ADDR_LEN * len), ifma->enm_addrlo,
    296 			ETHER_ADDR_LEN);
    297 		len++;
    298 		if (len > mclistsz) {
    299 			sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
    300 			sc->ndis_filter &= ~NDIS_PACKET_TYPE_MULTICAST;
    301 			goto out;
    302 		}
    303 	}
    304 
    305 	len = len * ETHER_ADDR_LEN;
    306 	error = ndis_set_info(sc, OID_802_3_MULTICAST_LIST, mclist, &len);
    307 	if (error) {
    308 		aprint_error_dev(sc->ndis_dev, "set mclist failed: %d\n",
    309 			     error);
    310 		sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
    311 		sc->ndis_filter &= ~NDIS_PACKET_TYPE_MULTICAST;
    312 	}
    313 
    314 out:
    315 	free(mclist, M_TEMP);
    316 
    317 	len = sizeof(sc->ndis_filter);
    318 	error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER,
    319 	    &sc->ndis_filter, &len);
    320     if (error) {
    321 		aprint_error_dev(sc->ndis_dev, "set filter failed: %d\n",
    322 			     error);
    323     }
    324 
    325 	return;
    326 }
    327 
    328 static int
    329 ndis_set_offload(struct ndis_softc *sc)
    330 {
    331 	ndis_task_offload	*nto;
    332 	ndis_task_offload_hdr	*ntoh;
    333 	ndis_task_tcpip_csum	*nttc;
    334 	struct ifnet		*ifp;
    335 	int			len, error;
    336 
    337 	ifp = &sc->arpcom.ac_if;
    338 
    339 	if (!NDIS_INITIALIZED(sc))
    340 		return(EINVAL);
    341 
    342 	/* See if there's anything to set. */
    343 
    344 	error = ndis_probe_offload(sc);
    345 	if (error)
    346 		return(error);
    347 
    348 	if (sc->ndis_hwassist == 0 && ifp->if_capabilities == 0)
    349 		return(0);
    350 
    351 	len = sizeof(ndis_task_offload_hdr) + sizeof(ndis_task_offload) +
    352 	    sizeof(ndis_task_tcpip_csum);
    353 
    354 	ntoh = malloc(len, M_TEMP, M_NOWAIT|M_ZERO);
    355 
    356 	if (ntoh == NULL)
    357 		return(ENOMEM);
    358 
    359 	ntoh->ntoh_vers = NDIS_TASK_OFFLOAD_VERSION;
    360 	ntoh->ntoh_len = sizeof(ndis_task_offload_hdr);
    361 	ntoh->ntoh_offset_firsttask = sizeof(ndis_task_offload_hdr);
    362 	ntoh->ntoh_encapfmt.nef_encaphdrlen = sizeof(struct ether_header);
    363 	ntoh->ntoh_encapfmt.nef_encap = NDIS_ENCAP_IEEE802_3;
    364 	ntoh->ntoh_encapfmt.nef_flags = NDIS_ENCAPFLAG_FIXEDHDRLEN;
    365 
    366 	nto = (ndis_task_offload *)((char *)ntoh +
    367 	    ntoh->ntoh_offset_firsttask);
    368 
    369 	nto->nto_vers = NDIS_TASK_OFFLOAD_VERSION;
    370 	nto->nto_len = sizeof(ndis_task_offload);
    371 	nto->nto_task = NDIS_TASK_TCPIP_CSUM;
    372 	nto->nto_offset_nexttask = 0;
    373 	nto->nto_taskbuflen = sizeof(ndis_task_tcpip_csum);
    374 
    375 	nttc = (ndis_task_tcpip_csum *)nto->nto_taskbuf;
    376 
    377 	if (ifp->if_capenable & IFCAP_TXCSUM)
    378 		nttc->nttc_v4tx = sc->ndis_v4tx;
    379 
    380 	if (ifp->if_capenable & IFCAP_RXCSUM)
    381 		nttc->nttc_v4rx = sc->ndis_v4rx;
    382 
    383 	error = ndis_set_info(sc, OID_TCP_TASK_OFFLOAD, ntoh, &len);
    384 	free(ntoh, M_TEMP);
    385 
    386 	return(error);
    387 }
    388 
    389 static int
    390 ndis_probe_offload(struct ndis_softc *sc)
    391 {
    392 	ndis_task_offload	*nto;
    393 	ndis_task_offload_hdr	*ntoh;
    394 	ndis_task_tcpip_csum	*nttc = NULL;
    395 	struct ifnet		*ifp;
    396 	int			len, error, dummy;
    397 
    398 	ifp = &sc->arpcom.ac_if;
    399 
    400 	len = sizeof(dummy);
    401 	error = ndis_get_info(sc, OID_TCP_TASK_OFFLOAD, &dummy, &len);
    402 
    403 	if (error != ENOSPC)
    404 		return(error);
    405 
    406 	ntoh = malloc(len, M_TEMP, M_NOWAIT|M_ZERO);
    407 
    408 	if (ntoh == NULL)
    409 		return(ENOMEM);
    410 
    411 	ntoh->ntoh_vers = NDIS_TASK_OFFLOAD_VERSION;
    412 	ntoh->ntoh_len = sizeof(ndis_task_offload_hdr);
    413 	ntoh->ntoh_encapfmt.nef_encaphdrlen = sizeof(struct ether_header);
    414 	ntoh->ntoh_encapfmt.nef_encap = NDIS_ENCAP_IEEE802_3;
    415 	ntoh->ntoh_encapfmt.nef_flags = NDIS_ENCAPFLAG_FIXEDHDRLEN;
    416 
    417 	error = ndis_get_info(sc, OID_TCP_TASK_OFFLOAD, ntoh, &len);
    418 
    419 	if (error) {
    420 		free(ntoh, M_TEMP);
    421 		return(error);
    422 	}
    423 
    424 	if (ntoh->ntoh_vers != NDIS_TASK_OFFLOAD_VERSION) {
    425 		free(ntoh, M_TEMP);
    426 		return(EINVAL);
    427 	}
    428 
    429 	nto = (ndis_task_offload *)((char *)ntoh +
    430 	    ntoh->ntoh_offset_firsttask);
    431 
    432 	while (1) {
    433 		switch (nto->nto_task) {
    434 		case NDIS_TASK_TCPIP_CSUM:
    435 			nttc = (ndis_task_tcpip_csum *)nto->nto_taskbuf;
    436 			break;
    437 		/* Don't handle these yet. */
    438 		case NDIS_TASK_IPSEC:
    439 		case NDIS_TASK_TCP_LARGESEND:
    440 		default:
    441 			break;
    442 		}
    443 		if (nto->nto_offset_nexttask == 0)
    444 			break;
    445 		nto = (ndis_task_offload *)((char *)nto +
    446 		    nto->nto_offset_nexttask);
    447 	}
    448 
    449 	if (nttc == NULL) {
    450 		free(ntoh, M_TEMP);
    451 		return(ENOENT);
    452 	}
    453 
    454 	sc->ndis_v4tx = nttc->nttc_v4tx;
    455 	sc->ndis_v4rx = nttc->nttc_v4rx;
    456 
    457 	if (nttc->nttc_v4tx & NDIS_TCPSUM_FLAGS_IP_CSUM)
    458 		sc->ndis_hwassist |= CSUM_IP;
    459 	if (nttc->nttc_v4tx & NDIS_TCPSUM_FLAGS_TCP_CSUM)
    460 		sc->ndis_hwassist |= CSUM_TCP;
    461 	if (nttc->nttc_v4tx & NDIS_TCPSUM_FLAGS_UDP_CSUM)
    462 		sc->ndis_hwassist |= CSUM_UDP;
    463 	if (sc->ndis_hwassist)
    464 		ifp->if_capabilities |= IFCAP_TXCSUM;
    465 
    466 	if (nttc->nttc_v4rx & NDIS_TCPSUM_FLAGS_IP_CSUM)
    467 		ifp->if_capabilities |= IFCAP_RXCSUM;
    468 	if (nttc->nttc_v4rx & NDIS_TCPSUM_FLAGS_TCP_CSUM)
    469 		ifp->if_capabilities |= IFCAP_RXCSUM;
    470 	if (nttc->nttc_v4rx & NDIS_TCPSUM_FLAGS_UDP_CSUM)
    471 		ifp->if_capabilities |= IFCAP_RXCSUM;
    472 
    473 	free(ntoh, M_TEMP);
    474 	return(0);
    475 }
    476 
    477 /*
    478  * Attach the interface. Allocate softc structures, do ifmedia
    479  * setup and ethernet/BPF attach.
    480  */
    481 void
    482 ndis_attach(dev)
    483 	void			*dev;
    484 {
    485 	u_char			eaddr[ETHER_ADDR_LEN];
    486 	struct ndis_softc	*sc;
    487 	driver_object		*drv;
    488 	driver_object		*pdrv;
    489 	device_object		*pdo;
    490 	struct ifnet		*ifp = NULL;
    491 	void			*img;
    492 	int			error = 0, len;
    493 	int			j;
    494 
    495 #ifdef NDIS_DBG
    496 	printf("In ndis_attach()\n");
    497 #endif
    498 
    499 	sc = device_get_softc(dev);
    500 
    501 	/* start out at dispatch level */
    502 	win_irql = DISPATCH_LEVEL;
    503 
    504 	mutex_init(&sc->ndis_mtx, MUTEX_DEFAULT, IPL_NET);
    505 
    506 	/*
    507 	 * Hook interrupt early, since calling the driver's
    508 	 * init routine may trigger an interrupt. Note that
    509 	 * we don't need to do any explicit interrupt setup
    510 	 * for USB.
    511 	 */
    512 	/*
    513 	 * For NetBSD, the interrupt is set up in the bus-dependent
    514 	 * code.  For PCI it's done in ndis_attach_pci()
    515 	 */
    516 
    517 /*
    518  * TODO: remove this #ifdef once if_ndis_pcmcia.c compiles
    519  */
    520 
    521 	sc->ndis_regvals = ndis_regvals;
    522 
    523 
    524 	/* Create sysctl registry nodes */
    525 	ndis_create_sysctls(sc);
    526 
    527 	/* Find the PDO for this device instance. */
    528 	if (sc->ndis_iftype == PCIBus)
    529 		pdrv = windrv_lookup(0, "PCI Bus");
    530 	else if (sc->ndis_iftype == PCMCIABus)
    531 		pdrv = windrv_lookup(0, "PCCARD Bus");
    532 	else
    533 		pdrv = windrv_lookup(0, "USB Bus");
    534 	pdo = windrv_find_pdo(pdrv, device_parent(sc->ndis_dev));
    535 
    536 
    537 	/*
    538 	 * Create a new functional device object for this
    539 	 * device. This is what creates the miniport block
    540 	 * for this device instance.
    541 	 */
    542 
    543 	img = drv_data;
    544 	drv = windrv_lookup((vm_offset_t)img, NULL);
    545 	/*
    546 	 * Stash a pointer to the softc in the Windows device_object, since
    547 	 * we can't get it from the NetBSD device structure.
    548 	 */
    549 	pdo->pdo_sc = sc;
    550 	pdo->fdo_sc = sc;
    551 
    552 	if (NdisAddDevice(drv, pdo) != STATUS_SUCCESS) {
    553 		aprint_error_dev(sc->ndis_dev, "failed to create FDO!\n");
    554 		error = ENXIO;
    555 		goto fail;
    556 	}
    557 
    558 	/* Tell the user what version of the API the driver is using. */
    559 	aprint_normal_dev(sc->ndis_dev, "NDIS API version: %d.%d\n",
    560 		      sc->ndis_chars->nmc_version_major,
    561 		      sc->ndis_chars->nmc_version_minor);
    562 
    563 	/*
    564 	 * For NetBSD so far we do the resource conversion directly in
    565 	 * ndis_attach_pci()
    566 	 */
    567 
    568 	/* Install our RX and TX interrupt handlers. */
    569 	sc->ndis_block->nmb_senddone_func = ndis_txeof_wrap;
    570 	sc->ndis_block->nmb_pktind_func = ndis_rxeof_wrap;
    571 
    572 	/* Set up the resource list in the block */
    573 	sc->ndis_block->nmb_rlist = sc->ndis_rl;
    574 	/* sc->ndis_block->nmb_rlist = &sc->ndis_rl; */
    575 
    576 	/* TODO: Free this memory! */
    577 	sc->arpcom.ec_if.if_sadl =
    578 		malloc(sizeof(struct sockaddr_dl), M_DEVBUF, M_NOWAIT|M_ZERO);
    579 
    580 	/* Call driver's init routine. */
    581 	if (ndis_init_nic(sc)) {
    582 		aprint_error_dev(sc->ndis_dev, "init handler failed\n");
    583 		error = ENXIO;
    584 		goto fail;
    585 	}
    586 
    587 	/*
    588 	 * Get station address from the driver.
    589 	 */
    590 	len = sizeof(eaddr);
    591 	ndis_get_info(sc, OID_802_3_CURRENT_ADDRESS, &eaddr, &len);
    592 
    593 	/*
    594 	 * Figure out if we're allowed to use multipacket sends
    595 	 * with this driver, and if so, how many.
    596 	 */
    597 
    598 	if (sc->ndis_chars->nmc_sendsingle_func &&
    599 	    sc->ndis_chars->nmc_sendmulti_func == NULL) {
    600 		sc->ndis_maxpkts = 1;
    601 	} else {
    602 		len = sizeof(sc->ndis_maxpkts);
    603 		ndis_get_info(sc, OID_GEN_MAXIMUM_SEND_PACKETS,
    604 		    &sc->ndis_maxpkts, &len);
    605 	}
    606 
    607 	sc->ndis_txarray = malloc(sizeof(ndis_packet *) *
    608 	    sc->ndis_maxpkts, M_DEVBUF, M_NOWAIT|M_ZERO);
    609 
    610 	/* Allocate a pool of ndis_packets for TX encapsulation. */
    611 
    612 	NdisAllocatePacketPool(&j, &sc->ndis_txpool,
    613 	   sc->ndis_maxpkts, PROTOCOL_RESERVED_SIZE_IN_PACKET);
    614 
    615 	if (j != NDIS_STATUS_SUCCESS) {
    616 		sc->ndis_txpool = NULL;
    617 		aprint_error_dev(sc->ndis_dev, "failed to allocate TX packet pool");
    618 		error = ENOMEM;
    619 		goto fail;
    620 	}
    621 
    622 	sc->ndis_txpending = sc->ndis_maxpkts;
    623 
    624 	sc->ndis_oidcnt = 0;
    625 	/* Get supported oid list. */
    626 	ndis_get_supported_oids(sc, &sc->ndis_oids, &sc->ndis_oidcnt);
    627 
    628 	/* If the NDIS module requested scatter/gather, init maps. */
    629 	if (sc->ndis_sc)
    630 		ndis_init_dma(sc);
    631 
    632 	/*
    633 	 * See if the OID_802_11_CONFIGURATION OID is
    634 	 * supported by this driver. If it is, then this an 802.11
    635 	 * wireless driver, and we should set up media for wireless.
    636 	 */
    637 	for (j = 0; j < sc->ndis_oidcnt; j++) {
    638 		if (sc->ndis_oids[j] == OID_802_11_CONFIGURATION) {
    639 			sc->ndis_80211++;
    640 			break;
    641 		}
    642 	}
    643 
    644 	/* Check for task offload support. */
    645 	ndis_probe_offload(sc);
    646 
    647 	ifp = &sc->arpcom.ac_if;
    648 	ifp->if_softc = sc;
    649 
    650 	sc->ic.ic_ifp = ifp;
    651 
    652 	strlcpy(ifp->if_xname, device_xname(sc->ndis_dev), IFNAMSIZ);
    653 	ifp->if_mtu = ETHERMTU;
    654 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
    655 	ifp->if_ioctl = ndis_ioctl;
    656 	ifp->if_start = ndis_start;
    657 	ifp->if_watchdog = ndis_watchdog;
    658 	ifp->if_init = ndis_init;
    659 	ifp->if_baudrate = 10000000;
    660 	IFQ_SET_MAXLEN(&ifp->if_snd, 50);
    661 	IFQ_SET_READY(&ifp->if_snd);
    662 	ifp->if_capenable = ifp->if_capabilities;
    663 	/*
    664 	 * TODO: I don't think NetBSD has this field describing "HW offload
    665 	 * capabilities" as found in FreeBSD's
    666 	 * if_data structure, but maybe there is something else that
    667 	 * needs to be done here for NetBSD
    668 	 */
    669 
    670 	/* Do media setup */
    671 	if (sc->ndis_80211) {
    672 		struct ieee80211com *ic = &sc->ic;
    673 		ndis_80211_rates_ex	rates;
    674 		struct ndis_80211_nettype_list *ntl;
    675 		uint32_t		arg;
    676 		int			r;
    677 
    678 	    ic->ic_phytype = IEEE80211_T_DS;
    679 		ic->ic_opmode = IEEE80211_M_STA;
    680 		ic->ic_caps = IEEE80211_C_IBSS;
    681 		ic->ic_state = IEEE80211_S_ASSOC;
    682 		ic->ic_modecaps = (1<<IEEE80211_MODE_AUTO);
    683 		len = 0;
    684 		r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED,
    685 		    NULL, &len);
    686 		if (r != ENOSPC)
    687 			goto nonettypes;
    688 		ntl = malloc(len, M_DEVBUF, M_WAITOK|M_ZERO);
    689 		r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED,
    690 		    ntl, &len);
    691 		if (r != 0) {
    692 			free(ntl, M_DEVBUF);
    693 			goto nonettypes;
    694 		}
    695 
    696 		for (j = 0; j < ntl->ntl_items; j++) {
    697 			switch (ntl->ntl_type[j]) {
    698 			case NDIS_80211_NETTYPE_11FH:
    699 			case NDIS_80211_NETTYPE_11DS:
    700 				ic->ic_modecaps |= (1<<IEEE80211_MODE_11B);
    701 				break;
    702 			case NDIS_80211_NETTYPE_11OFDM5:
    703 				ic->ic_modecaps |= (1<<IEEE80211_MODE_11A);
    704 				break;
    705 			case NDIS_80211_NETTYPE_11OFDM24:
    706 				ic->ic_modecaps |= (1<<IEEE80211_MODE_11G);
    707 				break;
    708 			default:
    709 				break;
    710 			}
    711 		}
    712 		free(ntl, M_DEVBUF);
    713 nonettypes:
    714 		len = sizeof(rates);
    715 		memset((char *)&rates, 0, len);
    716 		r = ndis_get_info(sc, OID_802_11_SUPPORTED_RATES,
    717 		    (void *)rates, &len);
    718 		if (r)
    719 			aprint_error_dev(sc->ndis_dev, "get rates failed: 0x%x\n", r);
    720 		/*
    721 		 * Since the supported rates only up to 8 can be supported,
    722 		 * if this is not 802.11b we're just going to be faking it
    723 		 * all up to heck.
    724 		 */
    725 
    726 #define TESTSETRATE(x, y)						\
    727 	do {								\
    728 		int			i;				\
    729 		for (i = 0; i < ic->ic_sup_rates[x].rs_nrates; i++) {	\
    730 			if (ic->ic_sup_rates[x].rs_rates[i] == (y))	\
    731 				break;					\
    732 		}							\
    733 		if (i == ic->ic_sup_rates[x].rs_nrates) {		\
    734 			ic->ic_sup_rates[x].rs_rates[i] = (y);		\
    735 			ic->ic_sup_rates[x].rs_nrates++;		\
    736 		}							\
    737 	} while (0)
    738 
    739 #define SETRATE(x, y)	\
    740 	ic->ic_sup_rates[x].rs_rates[ic->ic_sup_rates[x].rs_nrates] = (y)
    741 #define INCRATE(x)	\
    742 	ic->ic_sup_rates[x].rs_nrates++
    743 
    744 		ic->ic_curmode = IEEE80211_MODE_AUTO;
    745 		if (ic->ic_modecaps & (1<<IEEE80211_MODE_11A))
    746 			ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates = 0;
    747 		if (ic->ic_modecaps & (1<<IEEE80211_MODE_11B))
    748 			ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates = 0;
    749 		if (ic->ic_modecaps & (1<<IEEE80211_MODE_11G))
    750 			ic->ic_sup_rates[IEEE80211_MODE_11G].rs_nrates = 0;
    751 		for (j = 0; j < len; j++) {
    752 			switch (rates[j] & IEEE80211_RATE_VAL) {
    753 			case 2:
    754 			case 4:
    755 			case 11:
    756 			case 10:
    757 			case 22:
    758 				if (!(ic->ic_modecaps &
    759 				    (1<<IEEE80211_MODE_11B))) {
    760 					/* Lazy-init 802.11b. */
    761 					ic->ic_modecaps |=
    762 					    (1<<IEEE80211_MODE_11B);
    763 					ic->ic_sup_rates[IEEE80211_MODE_11B].
    764 					    rs_nrates = 0;
    765 				}
    766 				SETRATE(IEEE80211_MODE_11B, rates[j]);
    767 				INCRATE(IEEE80211_MODE_11B);
    768 				break;
    769 			default:
    770 				if (ic->ic_modecaps & (1<<IEEE80211_MODE_11A)) {
    771 					SETRATE(IEEE80211_MODE_11A, rates[j]);
    772 					INCRATE(IEEE80211_MODE_11A);
    773 				}
    774 				if (ic->ic_modecaps & (1<<IEEE80211_MODE_11G)) {
    775 					SETRATE(IEEE80211_MODE_11G, rates[j]);
    776 					INCRATE(IEEE80211_MODE_11G);
    777 				}
    778 				break;
    779 			}
    780 		}
    781 
    782 		/*
    783 		 * If the hardware supports 802.11g, it most
    784 		 * likely supports 802.11b and all of the
    785 		 * 802.11b and 802.11g speeds, so maybe we can
    786 		 * just cheat here.  Just how in the heck do
    787 		 * we detect turbo modes, though?
    788 		 */
    789 		if (ic->ic_modecaps & (1<<IEEE80211_MODE_11B)) {
    790 			TESTSETRATE(IEEE80211_MODE_11B,
    791 			    IEEE80211_RATE_BASIC|2);
    792 			TESTSETRATE(IEEE80211_MODE_11B,
    793 			    IEEE80211_RATE_BASIC|4);
    794 			TESTSETRATE(IEEE80211_MODE_11B,
    795 			    IEEE80211_RATE_BASIC|11);
    796 			TESTSETRATE(IEEE80211_MODE_11B,
    797 			    IEEE80211_RATE_BASIC|22);
    798 		}
    799 		if (ic->ic_modecaps & (1<<IEEE80211_MODE_11G)) {
    800 			TESTSETRATE(IEEE80211_MODE_11G, 47);
    801 			TESTSETRATE(IEEE80211_MODE_11G, 72);
    802 			TESTSETRATE(IEEE80211_MODE_11G, 96);
    803 			TESTSETRATE(IEEE80211_MODE_11G, 108);
    804 		}
    805 		if (ic->ic_modecaps & (1<<IEEE80211_MODE_11A)) {
    806 			TESTSETRATE(IEEE80211_MODE_11A, 47);
    807 			TESTSETRATE(IEEE80211_MODE_11A, 72);
    808 			TESTSETRATE(IEEE80211_MODE_11A, 96);
    809 			TESTSETRATE(IEEE80211_MODE_11A, 108);
    810 		}
    811 #undef SETRATE
    812 #undef INCRATE
    813 		/*
    814 		 * Taking yet more guesses here.
    815 		 */
    816 		for (j = 1; j < IEEE80211_CHAN_MAX; j++) {
    817 			int chanflag = 0;
    818 
    819 			if (ic->ic_sup_rates[IEEE80211_MODE_11G].rs_nrates)
    820 				chanflag |= IEEE80211_CHAN_G;
    821 			if (j <= 14)
    822 				chanflag |= IEEE80211_CHAN_B;
    823 			if (ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates &&
    824 			    j > 14)
    825 				chanflag = IEEE80211_CHAN_A;
    826 			if (chanflag == 0)
    827 				break;
    828 			ic->ic_channels[j].ic_freq =
    829 			    ieee80211_ieee2mhz(j, chanflag);
    830 			ic->ic_channels[j].ic_flags = chanflag;
    831 		}
    832 
    833 		j = sizeof(arg);
    834 		r = ndis_get_info(sc, OID_802_11_WEP_STATUS, &arg, &j);
    835 		if (arg != NDIS_80211_WEPSTAT_NOTSUPPORTED)
    836 			ic->ic_caps |= IEEE80211_C_WEP;
    837 		j = sizeof(arg);
    838 		r = ndis_get_info(sc, OID_802_11_POWER_MODE, &arg, &j);
    839 		if (r == 0)
    840 			ic->ic_caps |= IEEE80211_C_PMGT;
    841 		memcpy(&ic->ic_myaddr, eaddr, sizeof(eaddr));
    842 		if_attach(ifp);
    843 		ieee80211_ifattach(&sc->ic);
    844 		ieee80211_media_init(&sc->ic, ieee80211_media_change,
    845 		    ndis_media_status);
    846 
    847 		ic->ic_ibss_chan = IEEE80211_CHAN_ANYC;
    848 		ic->ic_bss->ni_chan = ic->ic_ibss_chan;
    849 	} else {
    850 		ifmedia_init(&sc->ifmedia, IFM_IMASK, ndis_ifmedia_upd,
    851 		    ndis_ifmedia_sts);
    852 		ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
    853 		ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
    854 		ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL);
    855 		ifmedia_add(&sc->ifmedia,
    856 		    IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
    857 		ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);
    858 		ifmedia_set(&sc->ifmedia, IFM_ETHER|IFM_AUTO);
    859 		if_attach(ifp);
    860 		ether_ifattach(ifp, eaddr);
    861 	}
    862 
    863 	/* Override the status handler so we can detect link changes. */
    864 	sc->ndis_block->nmb_status_func = ndis_linksts_wrap;
    865 	sc->ndis_block->nmb_statusdone_func = ndis_linksts_done_wrap;
    866 fail:
    867 	if (error)
    868 		ndis_detach(dev, 0);
    869 	else
    870 		/* We're done talking to the NIC for now; halt it. */
    871 		ndis_halt_nic(sc);
    872 
    873 	return;
    874 }
    875 
    876 /*
    877  * Shutdown hardware and free up resources. This can be called any
    878  * time after the mutex has been initialized. It is called in both
    879  * the error case in attach and the normal detach case so it needs
    880  * to be careful about only freeing resources that have actually been
    881  * allocated.
    882  */
    883 int
    884 ndis_detach (dev, flags)
    885 	device_t 		dev;
    886 	int			flags;
    887 {
    888 	struct ndis_softc	*sc;
    889 	struct ifnet		*ifp;
    890 	driver_object		*drv;
    891 	int			s;
    892 
    893 #ifdef NDIS_DBG
    894 	printf("in ndis_detach\n");
    895 #endif
    896 
    897 	sc = device_get_softc(dev);
    898 
    899 	NDIS_LOCK(sc);
    900 
    901 	ifp = &sc->arpcom.ac_if;
    902 	ifp->if_flags &= ~IFF_UP;
    903 
    904 	if (device_is_attached(dev)) {
    905 		NDIS_UNLOCK(sc);
    906 		ndis_stop(sc);
    907 		if (sc->ndis_80211)
    908 			ieee80211_ifdetach(&sc->ic);
    909 		else
    910 			ether_ifdetach(ifp);
    911 	} else {
    912 		NDIS_UNLOCK(sc);
    913 	}
    914 
    915 
    916 /*
    917  * TODO: unmap interrupts when unloading in NetBSD
    918  */
    919 	if (sc->ndis_res_io)
    920 		bus_release_resource(dev, SYS_RES_IOPORT,
    921 		    sc->ndis_io_rid, sc->ndis_res_io);
    922 	if (sc->ndis_res_mem)
    923 		bus_release_resource(dev, SYS_RES_MEMORY,
    924 		    sc->ndis_mem_rid, sc->ndis_res_mem);
    925 	if (sc->ndis_sc)
    926 		ndis_destroy_dma(sc);
    927 
    928 	if (sc->ndis_txarray)
    929 		free(sc->ndis_txarray, M_DEVBUF);
    930 
    931 
    932 	ndis_unload_driver((void *)ifp);
    933 
    934 	if (sc->ndis_txpool != NULL)
    935 		NdisFreePacketPool(sc->ndis_txpool);
    936 
    937 	/* Destroy the PDO for this device. */
    938 
    939 	if (sc->ndis_iftype == PCIBus)
    940 		drv = windrv_lookup(0, "PCI Bus");
    941 	else if (sc->ndis_iftype == PCMCIABus)
    942 		drv = windrv_lookup(0, "PCCARD Bus");
    943 	else
    944 		drv = windrv_lookup(0, "USB Bus");
    945 	if (drv == NULL)
    946 		panic("couldn't find driver object");
    947 	windrv_destroy_pdo(drv, dev);
    948 
    949 /*
    950  * TODO: Unmap dma for NetBSD
    951  */
    952 	mutex_destroy(&sc->ndis_mtx);
    953 
    954 	return(0);
    955 }
    956 
    957 /* TODO: write a NetBSD version of ndis_suspend() */
    958 
    959 /* TODO: write a NetBSD version of ndis_resume() */
    960 
    961 /*
    962  * A frame has been uploaded: pass the resulting mbuf chain up to
    963  * the higher level protocols.
    964  *
    965  * When handling received NDIS packets, the 'status' field in the
    966  * out-of-band portion of the ndis_packet has special meaning. In the
    967  * most common case, the underlying NDIS driver will set this field
    968  * to NDIS_STATUS_SUCCESS, which indicates that it's ok for us to
    969  * take posession of it. We then change the status field to
    970  * NDIS_STATUS_PENDING to tell the driver that we now own the packet,
    971  * and that we will return it at some point in the future via the
    972  * return packet handler.
    973  *
    974  * If the driver hands us a packet with a status of NDIS_STATUS_RESOURCES,
    975  * this means the driver is running out of packet/buffer resources and
    976  * wants to maintain ownership of the packet. In this case, we have to
    977  * copy the packet data into local storage and let the driver keep the
    978  * packet.
    979  */
    980 __stdcall /*static*/ void
    981 ndis_rxeof(ndis_handle adapter, ndis_packet **packets, uint32_t pktcnt)
    982 {
    983 	struct ndis_softc	*sc;
    984 	ndis_miniport_block	*block;
    985 	ndis_packet		*p;
    986 	uint32_t		s;
    987 	ndis_tcpip_csum		*csum;
    988 	struct ifnet		*ifp;
    989 	struct mbuf		*m0, *m;
    990 	int			i;
    991 
    992 	block = (ndis_miniport_block *)adapter;
    993 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
    994 	ifp = &sc->arpcom.ac_if;
    995 
    996 	for (i = 0; i < pktcnt; i++) {
    997 		p = packets[i];
    998 		/* Stash the softc here so ptom can use it. */
    999 		p->np_softc = sc;
   1000 		if (ndis_ptom(&m0, p)) {
   1001 			aprint_error_dev(sc->ndis_dev, "ptom failed\n");
   1002 			if (p->np_oob.npo_status == NDIS_STATUS_SUCCESS)
   1003 				ndis_return_packet(NULL, (void *)sc, 0, p);
   1004 		} else {
   1005 			if (p->np_oob.npo_status == NDIS_STATUS_RESOURCES) {
   1006 				m = m_dup(m0, 0, m0->m_pkthdr.len, FALSE);
   1007 				/*
   1008 				 * NOTE: we want to destroy the mbuf here, but
   1009 				 * we don't actually want to return it to the
   1010 				 * driver via the return packet handler. By
   1011 				 * bumping np_refcnt, we can prevent the
   1012 				 * ndis_return_packet() routine from actually
   1013 				 * doing anything.
   1014 				 */
   1015 				p->np_refcnt++;
   1016 				m_freem(m0);
   1017 				if (m == NULL)
   1018 					ifp->if_ierrors++;
   1019 				else
   1020 					m0 = m;
   1021 			} else
   1022 				p->np_oob.npo_status = NDIS_STATUS_PENDING;
   1023 			m_set_rcvif(m0, ifp);
   1024 			ifp->if_ipackets++;
   1025 
   1026 			/* Deal with checksum offload. */
   1027 /*
   1028  * TODO: deal with checksum offload in NetBSD
   1029  * (see IFCAP_XXX in sys/net/if.h, these differ from the FreeBSD ones)
   1030  */
   1031 			if (ifp->if_capenable & IFCAP_RXCSUM &&
   1032 			    p->np_ext.npe_info[ndis_tcpipcsum_info] != NULL) {
   1033 				s = (uintptr_t)
   1034 			 	    p->np_ext.npe_info[ndis_tcpipcsum_info];
   1035 				csum = (ndis_tcpip_csum *)&s;
   1036 				if (!(csum->u.ntc_rxflags &
   1037 				    NDIS_RXCSUM_IP_PASSED))
   1038 					m0->m_pkthdr.csum_flags |=
   1039 					    M_CSUM_IPv4_BAD;
   1040 				if (csum->u.ntc_rxflags &
   1041 				    (NDIS_RXCSUM_TCP_PASSED |
   1042 				    NDIS_RXCSUM_UDP_PASSED)) {
   1043 					//m0->m_pkthdr.csum_flags |=
   1044 					  //  CSUM_DATA_VALID|CSUM_PSEUDO_HDR;
   1045 					m0->m_pkthdr.csum_data = 0xFFFF;
   1046 				}
   1047 			}
   1048 
   1049 			bpf_mtap(ifp, m0);
   1050 
   1051 			if_percpuq_enqueue(ifp->if_percpuq, m0);
   1052 		}
   1053 	}
   1054 
   1055 	return;
   1056 }
   1057 
   1058 /*
   1059  * A frame was downloaded to the chip. It's safe for us to clean up
   1060  * the list buffers.
   1061  */
   1062 __stdcall /*static*/ void
   1063 ndis_txeof(adapter, packet, status)
   1064 	ndis_handle		adapter;
   1065 	ndis_packet		*packet;
   1066 	ndis_status		status;
   1067 
   1068 {
   1069 	struct ndis_softc	*sc;
   1070 	ndis_miniport_block	*block;
   1071 	struct ifnet		*ifp;
   1072 	int			idx;
   1073 	struct mbuf		*m;
   1074 	int			s;
   1075 
   1076 	block = (ndis_miniport_block *)adapter;
   1077 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
   1078 	ifp = &sc->arpcom.ac_if;
   1079 
   1080 	m = packet->np_m0;
   1081 	idx = packet->np_txidx;
   1082 	if (sc->ndis_sc)
   1083 		bus_dmamap_unload(sc->ndis_ttag, sc->ndis_tmaps[idx]);
   1084 
   1085 	ndis_free_packet(packet);
   1086 	m_freem(m);
   1087 
   1088 	NDIS_LOCK(sc);
   1089 
   1090 	sc->ndis_txarray[idx] = NULL;
   1091 	sc->ndis_txpending++;
   1092 
   1093 	if (status == NDIS_STATUS_SUCCESS)
   1094 		ifp->if_opackets++;
   1095 	else
   1096 		ifp->if_oerrors++;
   1097 	ifp->if_timer = 0;
   1098 	ifp->if_flags &= ~IFF_OACTIVE;
   1099 	NDIS_UNLOCK(sc);
   1100 
   1101 	ndis_sched(ndis_starttask, ifp, NDIS_TASKQUEUE);
   1102 
   1103 	return;
   1104 }
   1105 
   1106 __stdcall /*static*/ void
   1107 ndis_linksts(ndis_handle adapter, ndis_status status, void *sbuf, uint32_t slen)
   1108 {
   1109 	ndis_miniport_block	*block;
   1110 	struct ndis_softc	*sc;
   1111 
   1112 	block = adapter;
   1113 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
   1114 
   1115 
   1116 	block->nmb_getstat = status;
   1117 
   1118 	return;
   1119 }
   1120 
   1121 __stdcall /*static*/ void
   1122 ndis_linksts_done(ndis_handle adapter)
   1123 {
   1124 	ndis_miniport_block	*block;
   1125 	struct ndis_softc	*sc;
   1126 	struct ifnet		*ifp;
   1127 
   1128 	block = adapter;
   1129 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
   1130 	ifp = &sc->arpcom.ac_if;
   1131 
   1132 	if (!NDIS_INITIALIZED(sc))
   1133 		return;
   1134 
   1135 	switch (block->nmb_getstat) {
   1136 	case NDIS_STATUS_MEDIA_CONNECT:
   1137 		ndis_sched(ndis_ticktask, sc, NDIS_TASKQUEUE);
   1138 		ndis_sched(ndis_starttask, ifp, NDIS_TASKQUEUE);
   1139 		break;
   1140 	case NDIS_STATUS_MEDIA_DISCONNECT:
   1141 		if (sc->ndis_link)
   1142 			ndis_sched(ndis_ticktask, sc, NDIS_TASKQUEUE);
   1143 		break;
   1144 	default:
   1145 		break;
   1146 	}
   1147 
   1148 	return;
   1149 }
   1150 
   1151 int
   1152 ndis_intr(arg)
   1153 	void			*arg;
   1154 {
   1155 	struct ndis_softc	*sc;
   1156 	struct ifnet		*ifp;
   1157 	int			is_our_intr = 0;
   1158 	int			call_isr = 0;
   1159 	uint8_t			irql;
   1160 	ndis_miniport_interrupt	*intr;
   1161 
   1162 	sc = arg;
   1163 	ifp = &sc->arpcom.ac_if;
   1164 
   1165 	/*
   1166 	 * I was getting an interrupt before NdisAddDevice was called,
   1167 	 * which sets up the ndis_block, so...
   1168 	 */
   1169 	if(sc->ndis_block == NULL) {
   1170 		return 0;
   1171 	}
   1172 
   1173 	intr = sc->ndis_block->nmb_interrupt;
   1174 
   1175 	if (sc->ndis_block->nmb_miniportadapterctx == NULL) {
   1176 		return 0;
   1177 	}
   1178 
   1179 	KeAcquireSpinLock(&intr->ni_dpccountlock, &irql);
   1180 	if (sc->ndis_block->nmb_interrupt->ni_isrreq == TRUE)
   1181 		ndis_isr(sc, &is_our_intr, &call_isr);
   1182 	else {
   1183 		ndis_disable_intr(sc);
   1184 		call_isr = 1;
   1185 	}
   1186 	KeReleaseSpinLock(&intr->ni_dpccountlock, irql);
   1187 
   1188 	if ((is_our_intr || call_isr)) {
   1189 		ndis_in_isr = TRUE;
   1190 		IoRequestDpc(sc->ndis_block->nmb_deviceobj, NULL, sc);
   1191 		ndis_in_isr = FALSE;
   1192 	}
   1193 
   1194 	return 0;
   1195 }
   1196 
   1197 /*
   1198  * just here so I can wake up the SWI thread
   1199  * in ndis_ticktask
   1200  */
   1201 struct ndisproc {
   1202 	struct ndisqhead	*np_q;
   1203 	struct proc		*np_p;
   1204 	int			np_state;
   1205 	uint8_t			np_stack[PAGE_SIZE*NDIS_KSTACK_PAGES];
   1206 	int			np_needs_wakeup;
   1207 };
   1208 extern struct ndisproc ndis_iproc;
   1209 
   1210 static void
   1211 ndis_tick(void *xsc)
   1212 {
   1213 	struct ndis_softc	*sc;
   1214 
   1215 	/* TODO: do we need the lock for NetBSD? */
   1216 
   1217 	sc = xsc;
   1218 
   1219 	ndis_sched(ndis_ticktask, sc, NDIS_TASKQUEUE);
   1220 
   1221 	callout_reset(&sc->ndis_stat_ch, hz *
   1222 		sc->ndis_block->nmb_checkforhangsecs, ndis_tick, sc);
   1223 
   1224 
   1225 	return;
   1226 }
   1227 
   1228 static void
   1229 ndis_ticktask(void *xsc)
   1230 {
   1231 	struct ndis_softc	*sc;
   1232 	__stdcall ndis_checkforhang_handler hangfunc;
   1233 	uint8_t			rval;
   1234 	ndis_media_state	linkstate;
   1235 	int			error, len;
   1236 	int			s;
   1237 
   1238 	sc = xsc;
   1239 
   1240 	hangfunc = sc->ndis_chars->nmc_checkhang_func;
   1241 
   1242 	if (hangfunc != NULL) {
   1243 		rval = MSCALL1(hangfunc,
   1244 		    sc->ndis_block->nmb_miniportadapterctx);
   1245 		if (rval == TRUE) {
   1246 			ndis_reset_nic(sc);
   1247 			return;
   1248 		}
   1249 	}
   1250 
   1251 	len = sizeof(linkstate);
   1252 	error = ndis_get_info(sc, OID_GEN_MEDIA_CONNECT_STATUS,
   1253 	    (void *)&linkstate, &len);
   1254 
   1255 	NDIS_LOCK(sc);
   1256 
   1257 	if (sc->ndis_link == 0 && linkstate == nmc_connected) {
   1258 		aprint_normal_dev(sc->ndis_dev, "link up\n");
   1259 		sc->ndis_link = 1;
   1260 
   1261 		NDIS_UNLOCK(sc);
   1262 		if (sc->ndis_80211)
   1263 			ndis_getstate_80211(sc);
   1264 		NDIS_LOCK(sc);
   1265 
   1266 #ifdef LINK_STATE_UP
   1267 		sc->arpcom.ac_if.if_link_state = LINK_STATE_UP;
   1268 		rt_ifmsg(&(sc->arpcom.ac_if));
   1269 #endif /* LINK_STATE_UP */
   1270 	}
   1271 
   1272 	if (sc->ndis_link == 1 && linkstate == nmc_disconnected) {
   1273 		aprint_normal_dev(sc->ndis_dev, "link down\n");
   1274 		sc->ndis_link = 0;
   1275 #ifdef LINK_STATE_DOWN
   1276 		sc->arpcom.ac_if.if_link_state = LINK_STATE_DOWN;
   1277 		rt_ifmsg(&(sc->arpcom.ac_if));
   1278 #endif /* LINK_STATE_DOWN */
   1279 	}
   1280 
   1281 	NDIS_UNLOCK(sc);
   1282 
   1283 	return;
   1284 }
   1285 
   1286 static void
   1287 ndis_map_sclist(arg, segs, nseg, mapsize, error)
   1288 	void			*arg;
   1289 	bus_dma_segment_t	*segs;
   1290 	int			nseg;
   1291 	bus_size_t		mapsize;
   1292 	int			error;
   1293 
   1294 {
   1295 	struct ndis_sc_list	*sclist;
   1296 	int			i;
   1297 
   1298 	if (error || arg == NULL)
   1299 		return;
   1300 
   1301 	sclist = arg;
   1302 
   1303 	sclist->nsl_frags = nseg;
   1304 
   1305 	for (i = 0; i < nseg; i++) {
   1306 		sclist->nsl_elements[i].nse_addr.np_quad = segs[i].ds_addr;
   1307 		sclist->nsl_elements[i].nse_len = segs[i].ds_len;
   1308 	}
   1309 
   1310 	return;
   1311 }
   1312 
   1313 static void
   1314 ndis_starttask(void *arg)
   1315 {
   1316 	struct ifnet		*ifp;
   1317 
   1318 	ifp = arg;
   1319 	if (!IFQ_IS_EMPTY(&ifp->if_snd))
   1320 		ndis_start(ifp);
   1321 	return;
   1322 }
   1323 
   1324 /*
   1325  * Main transmit routine. To make NDIS drivers happy, we need to
   1326  * transform mbuf chains into NDIS packets and feed them to the
   1327  * send packet routines. Most drivers allow you to send several
   1328  * packets at once (up to the maxpkts limit). Unfortunately, rather
   1329  * that accepting them in the form of a linked list, they expect
   1330  * a contiguous array of pointers to packets.
   1331  *
   1332  * For those drivers which use the NDIS scatter/gather DMA mechanism,
   1333  * we need to perform busdma work here. Those that use map registers
   1334  * will do the mapping themselves on a buffer by buffer basis.
   1335  */
   1336 static void
   1337 ndis_start(struct ifnet *ifp)
   1338 {
   1339 	struct ndis_softc	*sc;
   1340 	struct mbuf		*m = NULL;
   1341 	ndis_packet		**p0 = NULL, *p = NULL;
   1342     ndis_tcpip_csum		*csum;
   1343 	int			pcnt = 0, status;
   1344 	int			s;
   1345 
   1346 	sc = ifp->if_softc;
   1347 
   1348 	NDIS_LOCK(sc);
   1349 
   1350 	if (!sc->ndis_link || ifp->if_flags & IFF_OACTIVE) {
   1351 		NDIS_UNLOCK(sc);
   1352 		return;
   1353 	}
   1354 
   1355 	p0 = &sc->ndis_txarray[sc->ndis_txidx];
   1356 
   1357 	while(sc->ndis_txpending) {
   1358 		IFQ_DEQUEUE(&ifp->if_snd, m);
   1359 		if (m == NULL)
   1360 			break;
   1361 
   1362 		NdisAllocatePacket(&status,
   1363 		    &sc->ndis_txarray[sc->ndis_txidx], sc->ndis_txpool);
   1364 
   1365 		if (status != NDIS_STATUS_SUCCESS)
   1366 			break;
   1367 
   1368 		if (ndis_mtop(m, &sc->ndis_txarray[sc->ndis_txidx])) {
   1369 #if __FreeBSD_version >= 502114
   1370 			IFQ_DRV_PREPEND(&ifp->if_snd, m);
   1371 #endif
   1372 			NDIS_UNLOCK(sc);
   1373 #if __FreeBSD_version < 502114
   1374 			IF_PREPEND(&ifp->if_snd, m);
   1375 #endif
   1376 			return;
   1377 		}
   1378 
   1379 		/*
   1380 		 * Save pointer to original mbuf
   1381 		 * so we can free it later.
   1382 		 */
   1383 
   1384 		p = sc->ndis_txarray[sc->ndis_txidx];
   1385 		p->np_txidx = sc->ndis_txidx;
   1386 		p->np_m0 = m;
   1387 		p->np_oob.npo_status = NDIS_STATUS_PENDING;
   1388 
   1389 		/*
   1390 		 * Do scatter/gather processing, if driver requested it.
   1391 		 */
   1392 		if (sc->ndis_sc) {
   1393 /*
   1394  * TODO: NetBSD's bus_dmamap_load_mbuf dosen't provide a callback function
   1395  * argumet as FreeBSD's does figure out what to do about this.
   1396  */
   1397 			bus_dmamap_load_mbuf(sc->ndis_ttag,
   1398 			    sc->ndis_tmaps[sc->ndis_txidx], m,
   1399 			    BUS_DMA_WRITE|BUS_DMA_NOWAIT);
   1400 			/* Just call the callback function ? */
   1401 			ndis_map_sclist(&p->np_sclist,
   1402 					sc->ndis_tmaps[sc->ndis_txidx]->dm_segs,
   1403 					sc->ndis_tmaps[sc->ndis_txidx]->dm_nsegs,
   1404 					sc->ndis_tmaps[sc->ndis_txidx]->dm_mapsize, 0);
   1405 /*
   1406  * TODO: Need an offset and length to pass to bus_dmamap_sync() (not needed in
   1407  * FreeBSD), I'm not sure I did this correctly, as man 9 bus_dma says that
   1408  * dm_segs is "an array of segments or a pointer to an array of segments".
   1409  */
   1410 			bus_dmamap_sync(sc->ndis_ttag,
   1411 			    sc->ndis_tmaps[sc->ndis_txidx],
   1412 			    sc->ndis_tmaps[sc->ndis_txidx]->dm_segs->ds_addr,
   1413 			    sc->ndis_tmaps[sc->ndis_txidx]->dm_segs->ds_len,
   1414 			    BUS_DMASYNC_PREREAD);
   1415 			p->np_ext.npe_info[ndis_sclist_info] = &p->np_sclist;
   1416 		}
   1417 
   1418 		/* Handle checksum offload. */
   1419 		if (ifp->if_capenable & IFCAP_TXCSUM &&
   1420 		    m->m_pkthdr.csum_flags) {
   1421 			csum = (ndis_tcpip_csum *)
   1422 				&p->np_ext.npe_info[ndis_tcpipcsum_info];
   1423 			csum->u.ntc_txflags = NDIS_TXCSUM_DO_IPV4;
   1424 			if (m->m_pkthdr.csum_flags & CSUM_IP)
   1425 				csum->u.ntc_txflags |= NDIS_TXCSUM_DO_IP;
   1426 			if (m->m_pkthdr.csum_flags & CSUM_TCP)
   1427 				csum->u.ntc_txflags |= NDIS_TXCSUM_DO_TCP;
   1428 			if (m->m_pkthdr.csum_flags & CSUM_UDP)
   1429 				csum->u.ntc_txflags |= NDIS_TXCSUM_DO_UDP;
   1430 			p->np_private.npp_flags = NDIS_PROTOCOL_ID_TCP_IP;
   1431 		}
   1432 
   1433 		NDIS_INC(sc);
   1434 		sc->ndis_txpending--;
   1435 
   1436 		pcnt++;
   1437 
   1438 		/*
   1439 		 * If there's a BPF listener, bounce a copy of this frame
   1440 		 * to him.
   1441 		 */
   1442 		bpf_mtap(ifp, m);
   1443 		/*
   1444 		 * The array that p0 points to must appear contiguous,
   1445 		 * so we must not wrap past the end of sc->ndis_txarray[].
   1446 		 * If it looks like we're about to wrap, break out here
   1447 		 * so the this batch of packets can be transmitted, then
   1448 		 * wait for txeof to ask us to send the rest.
   1449 		 */
   1450 
   1451 		if (sc->ndis_txidx == 0)
   1452 			break;
   1453 	}
   1454 
   1455 	if (pcnt == 0) {
   1456 		NDIS_UNLOCK(sc);
   1457 		return;
   1458 	}
   1459 
   1460 	if (sc->ndis_txpending == 0)
   1461 		ifp->if_flags |= IFF_OACTIVE;
   1462 
   1463 	/*
   1464 	 * Set a timeout in case the chip goes out to lunch.
   1465 	 */
   1466 	ifp->if_timer = 5;
   1467 
   1468 	NDIS_UNLOCK(sc);
   1469 
   1470 	if (sc->ndis_maxpkts == 1)
   1471 		ndis_send_packet(sc, p);
   1472 	else
   1473 		ndis_send_packets(sc, p0, pcnt);
   1474 
   1475 	return;
   1476 }
   1477 
   1478 static int
   1479 ndis_init(xsc)
   1480 	struct ifnet 		*xsc;
   1481 {
   1482 	struct ndis_softc	*sc  = xsc->if_softc;
   1483 	struct ifnet		*ifp = xsc;
   1484 	int 			s;
   1485 	int			i, error;
   1486 
   1487 	/*
   1488 	 * Avoid reintializing the link unnecessarily.
   1489 	 * This should be dealt with in a better way by
   1490 	 * fixing the upper layer modules so they don't
   1491 	 * call ifp->if_init() quite as often.
   1492 	 */
   1493 	if (sc->ndis_link && sc->ndis_skip)
   1494 		return 0;
   1495 
   1496 	/*
   1497 	 * Cancel pending I/O and free all RX/TX buffers.
   1498 	 */
   1499 	 ndis_stop(sc);
   1500 	 if (ndis_init_nic(sc)) {
   1501 		return 0;
   1502 	}
   1503 
   1504 	/* Init our MAC address */
   1505 
   1506 	/* Program the packet filter */
   1507 
   1508 	sc->ndis_filter = NDIS_PACKET_TYPE_DIRECTED;
   1509 
   1510 	if (ifp->if_flags & IFF_BROADCAST)
   1511 		sc->ndis_filter |= NDIS_PACKET_TYPE_BROADCAST;
   1512 
   1513 	if (ifp->if_flags & IFF_PROMISC)
   1514 		sc->ndis_filter |= NDIS_PACKET_TYPE_PROMISCUOUS;
   1515 
   1516 	i = sizeof(sc->ndis_filter);
   1517 
   1518 	error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER,
   1519 	    &sc->ndis_filter, &i);
   1520 
   1521 	if (error)
   1522 		aprint_error_dev(sc->ndis_dev, "set filter failed: %d\n",
   1523 			     error);
   1524 
   1525 	/*
   1526 	 * Program the multicast filter, if necessary.
   1527 	 */
   1528 	ndis_setmulti(sc);
   1529 
   1530 	/* Setup task offload. */
   1531 	ndis_set_offload(sc);
   1532 
   1533 	/* Enable interrupts. */
   1534 	ndis_enable_intr(sc);
   1535 
   1536 	if (sc->ndis_80211)
   1537 		ndis_setstate_80211(sc);
   1538 
   1539 	NDIS_LOCK(sc);
   1540 
   1541 	sc->ndis_txidx = 0;
   1542 	sc->ndis_txpending = sc->ndis_maxpkts;
   1543 	sc->ndis_link = 0;
   1544 
   1545 	ifp->if_flags |= IFF_RUNNING;
   1546 	ifp->if_flags &= ~IFF_OACTIVE;
   1547 
   1548 	NDIS_UNLOCK(sc);
   1549 
   1550 	/*
   1551 	 * Some drivers don't set this value. The NDIS spec says
   1552 	 * the default checkforhang timeout is "approximately 2
   1553 	 * seconds." We use 3 seconds, because it seems for some
   1554 	 * drivers, exactly 2 seconds is too fast.
   1555 	 */
   1556 
   1557 	if (sc->ndis_block->nmb_checkforhangsecs == 0)
   1558 		sc->ndis_block->nmb_checkforhangsecs = 3;
   1559 
   1560 	callout_reset(&sc->ndis_stat_ch,
   1561 		      hz * sc->ndis_block->nmb_checkforhangsecs,
   1562 		      ndis_tick, sc);
   1563 
   1564 		return 0;
   1565 }
   1566 
   1567 /*
   1568  * Set media options.
   1569  */
   1570 static int
   1571 ndis_ifmedia_upd(struct ifnet *ifp)
   1572 {
   1573 	struct ndis_softc		*sc;
   1574 
   1575 	sc = ifp->if_softc;
   1576 
   1577 	if (NDIS_INITIALIZED(sc))
   1578 		ndis_init(&sc->arpcom.ac_if);
   1579 
   1580 	return(0);
   1581 }
   1582 
   1583 /*
   1584  * Report current media status.
   1585  */
   1586 static void
   1587 ndis_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
   1588 {
   1589 	struct ndis_softc	*sc;
   1590 	uint32_t		media_info;
   1591 	ndis_media_state	linkstate;
   1592 	int			error, len;
   1593 
   1594 	ifmr->ifm_status = IFM_AVALID;
   1595 	ifmr->ifm_active = IFM_ETHER;
   1596 	sc = ifp->if_softc;
   1597 
   1598 	if (!NDIS_INITIALIZED(sc))
   1599 		return;
   1600 
   1601 	len = sizeof(linkstate);
   1602 	error = ndis_get_info(sc, OID_GEN_MEDIA_CONNECT_STATUS,
   1603 	    (void *)&linkstate, &len);
   1604 
   1605 	len = sizeof(media_info);
   1606 	error = ndis_get_info(sc, OID_GEN_LINK_SPEED,
   1607 	    (void *)&media_info, &len);
   1608 
   1609 	if (linkstate == nmc_connected)
   1610 		ifmr->ifm_status |= IFM_ACTIVE;
   1611 
   1612 	switch(media_info) {
   1613 	case 100000:
   1614 		ifmr->ifm_active |= IFM_10_T;
   1615 		break;
   1616 	case 1000000:
   1617 		ifmr->ifm_active |= IFM_100_TX;
   1618 		break;
   1619 	case 10000000:
   1620 		ifmr->ifm_active |= IFM_1000_T;
   1621 		break;
   1622 	default:
   1623 		aprint_error_dev(sc->ndis_dev, "unknown speed: %d\n",
   1624 			     media_info);
   1625 		break;
   1626 	}
   1627 
   1628 	return;
   1629 }
   1630 
   1631 /* TODO: Perhaps raise the IPL while in these wireless functions ? */
   1632 
   1633 static void
   1634 ndis_setstate_80211(struct ndis_softc *sc)
   1635 {
   1636 	struct ieee80211com	*ic;
   1637 	ndis_80211_ssid		ssid;
   1638 	ndis_80211_config	config;
   1639 	ndis_80211_wep		wep;
   1640 	int			i, rval = 0, len;
   1641 	uint32_t		arg;
   1642 	struct ifnet		*ifp;
   1643 
   1644 #define wk_len 		wk_keylen
   1645 #define ic_wep_txkey	ic_def_txkey
   1646 
   1647 ic = &sc->ic;
   1648 
   1649 /* TODO: are these equivelant? */
   1650 	ifp = sc->ic.ic_ifp;
   1651 
   1652 	if (!NDIS_INITIALIZED(sc))
   1653 		return;
   1654 
   1655 	/* Set network infrastructure mode. */
   1656 
   1657 	len = sizeof(arg);
   1658 	if (ic->ic_opmode == IEEE80211_M_IBSS)
   1659 		arg = NDIS_80211_NET_INFRA_IBSS;
   1660 	else
   1661 		arg = NDIS_80211_NET_INFRA_BSS;
   1662 
   1663 	rval = ndis_set_info(sc, OID_802_11_INFRASTRUCTURE_MODE, &arg, &len);
   1664 
   1665 	if (rval)
   1666 		aprint_error_dev(sc->ndis_dev, "set infra failed: %d\n", rval);
   1667 
   1668 	/* Set WEP */
   1669 /* TODO: Clean up these #ifdef's */
   1670 	if (ic->ic_flags & IEEE80211_F_PRIVACY) {
   1671 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
   1672 			if (ic->ic_nw_keys[i].wk_len) {
   1673 				memset((char *)&wep, 0, sizeof(wep));
   1674 				wep.nw_keylen = ic->ic_nw_keys[i].wk_len;
   1675 #ifdef notdef
   1676 				/* 5 and 13 are the only valid key lengths */
   1677 				if (ic->ic_nw_keys[i].wk_len < 5)
   1678 					wep.nw_keylen = 5;
   1679 				else if (ic->ic_nw_keys[i].wk_len > 5 &&
   1680 				     ic->ic_nw_keys[i].wk_len < 13)
   1681 					wep.nw_keylen = 13;
   1682 #endif
   1683 				wep.nw_keyidx = i;
   1684 				wep.nw_length = (sizeof(uint32_t) * 3)
   1685 				    + wep.nw_keylen;
   1686 				if (i == ic->ic_wep_txkey)
   1687 					wep.nw_keyidx |= NDIS_80211_WEPKEY_TX;
   1688 				bcopy(ic->ic_nw_keys[i].wk_key,
   1689 				    wep.nw_keydata, wep.nw_length);
   1690 				len = sizeof(wep);
   1691 				rval = ndis_set_info(sc,
   1692 				    OID_802_11_ADD_WEP, &wep, &len);
   1693 				if (rval)
   1694 					aprint_error_dev(sc->ndis_dev, "set wepkey failed: %d\n", rval);
   1695 			}
   1696 		}
   1697 		arg = NDIS_80211_WEPSTAT_ENABLED;
   1698 		len = sizeof(arg);
   1699 		rval = ndis_set_info(sc, OID_802_11_WEP_STATUS, &arg, &len);
   1700 		if (rval)
   1701 			aprint_error_dev(sc->ndis_dev, "enable WEP failed: %d\n",
   1702 				     rval);
   1703 			arg = NDIS_80211_PRIVFILT_8021XWEP;
   1704 		len = sizeof(arg);
   1705 		rval = ndis_set_info(sc, OID_802_11_PRIVACY_FILTER, &arg, &len);
   1706 #ifdef IEEE80211_WEP_8021X /*IEEE80211_F_WEPON*/
   1707 		/* Accept that we only have "shared" and 802.1x modes. */
   1708 		if (rval == 0) {
   1709 			if (arg == NDIS_80211_PRIVFILT_ACCEPTALL)
   1710 				ic->ic_wep_mode = IEEE80211_WEP_MIXED;
   1711 			else
   1712 				ic->ic_wep_mode = IEEE80211_WEP_8021X;
   1713 		}
   1714 #endif
   1715 		arg = NDIS_80211_AUTHMODE_OPEN;
   1716 	} else {
   1717 		arg = NDIS_80211_WEPSTAT_DISABLED;
   1718 		len = sizeof(arg);
   1719 		ndis_set_info(sc, OID_802_11_WEP_STATUS, &arg, &len);
   1720 		arg = NDIS_80211_AUTHMODE_OPEN;
   1721 	}
   1722 
   1723 	len = sizeof(arg);
   1724 	rval = ndis_set_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &len);
   1725 
   1726 #ifdef notyet
   1727 	if (rval)
   1728 		aprint_error_dev(sc->ndis_dev, "set auth failed: %d\n", rval);
   1729 #endif
   1730 
   1731 #ifdef notyet
   1732 	/* Set network type. */
   1733 
   1734 	arg = 0;
   1735 
   1736 	switch (ic->ic_curmode) {
   1737 	case IEEE80211_MODE_11A:
   1738 		arg = NDIS_80211_NETTYPE_11OFDM5;
   1739 		break;
   1740 	case IEEE80211_MODE_11B:
   1741 		arg = NDIS_80211_NETTYPE_11DS;
   1742 		break;
   1743 	case IEEE80211_MODE_11G:
   1744 		arg = NDIS_80211_NETTYPE_11OFDM24;
   1745 		break;
   1746 	default:
   1747 		aprint_error_dev(sc->ndis_dev, "unknown mode: %d\n",
   1748 			     ic->ic_curmode);
   1749 	}
   1750 
   1751 	if (arg) {
   1752 		len = sizeof(arg);
   1753 		rval = ndis_set_info(sc, OID_802_11_NETWORK_TYPE_IN_USE,
   1754 		    &arg, &len);
   1755 		if (rval)
   1756 			aprint_error_dev(sc->ndis_dev, "set nettype failed: %d\n",
   1757 				     rval);
   1758 	}
   1759 #endif
   1760 
   1761 	len = sizeof(config);
   1762 	memset((char *)&config, 0, len);
   1763 	config.nc_length = len;
   1764 	config.nc_fhconfig.ncf_length = sizeof(ndis_80211_config_fh);
   1765 	rval = ndis_get_info(sc, OID_802_11_CONFIGURATION, &config, &len);
   1766 
   1767 	/*
   1768 	 * Some drivers expect us to initialize these values, so
   1769 	 * provide some defaults.
   1770 	 */
   1771 	if (config.nc_beaconperiod == 0)
   1772 		config.nc_beaconperiod = 100;
   1773 	if (config.nc_atimwin == 0)
   1774 		config.nc_atimwin = 100;
   1775 	if (config.nc_fhconfig.ncf_dwelltime == 0)
   1776 		config.nc_fhconfig.ncf_dwelltime = 200;
   1777 
   1778 	if (rval == 0 && ic->ic_ibss_chan != IEEE80211_CHAN_ANYC) {
   1779 		int chan, chanflag;
   1780 
   1781 		chan = ieee80211_chan2ieee(ic, ic->ic_ibss_chan);
   1782 		chanflag = config.nc_dsconfig > 2500000 ? IEEE80211_CHAN_2GHZ :
   1783 		    IEEE80211_CHAN_5GHZ;
   1784 		if (chan != ieee80211_mhz2ieee(config.nc_dsconfig / 1000, 0)) {
   1785 			config.nc_dsconfig =
   1786 			    ic->ic_ibss_chan->ic_freq * 1000;
   1787 			ic->ic_bss->ni_chan = ic->ic_ibss_chan;
   1788 			len = sizeof(config);
   1789 			config.nc_length = len;
   1790 			config.nc_fhconfig.ncf_length =
   1791 			    sizeof(ndis_80211_config_fh);
   1792 			rval = ndis_set_info(sc, OID_802_11_CONFIGURATION,
   1793 			    &config, &len);
   1794 			if (rval)
   1795 				aprint_error_dev(sc->ndis_dev, "couldn't change "
   1796 					     "DS config to %ukHz: %d\n",
   1797 					     config.nc_dsconfig,
   1798 					     rval);
   1799 		}
   1800 	} else if (rval)
   1801 		aprint_error_dev(sc->ndis_dev, "couldn't retrieve "
   1802 			     "channel info: %d\n", rval);
   1803 
   1804 	/* Set SSID -- always do this last. */
   1805 
   1806 	len = sizeof(ssid);
   1807 	memset((char *)&ssid, 0, len);
   1808 	ssid.ns_ssidlen = ic->ic_des_esslen;
   1809 	if (ssid.ns_ssidlen == 0) {
   1810 		ssid.ns_ssidlen = 1;
   1811 	} else
   1812 		memcpy(ssid.ns_ssid, ic->ic_des_essid, ssid.ns_ssidlen);
   1813 	rval = ndis_set_info(sc, OID_802_11_SSID, &ssid, &len);
   1814 
   1815 	if (rval)
   1816 		aprint_error_dev(sc->ndis_dev, "set ssid failed: %d\n", rval);
   1817 
   1818 	return;
   1819 }
   1820 
   1821 static void
   1822 ndis_media_status(struct ifnet *ifp, struct ifmediareq *imr)
   1823 {
   1824         struct ieee80211com *ic = (void *)ifp;
   1825         struct ieee80211_node *ni = NULL;
   1826 
   1827         imr->ifm_status = IFM_AVALID;
   1828         imr->ifm_active = IFM_IEEE80211;
   1829         if (ic->ic_state == IEEE80211_S_RUN)
   1830                 imr->ifm_status |= IFM_ACTIVE;
   1831         imr->ifm_active |= IFM_AUTO;
   1832         switch (ic->ic_opmode) {
   1833         case IEEE80211_M_STA:
   1834                 ni = ic->ic_bss;
   1835                 /* calculate rate subtype */
   1836                 imr->ifm_active |= ieee80211_rate2media(ic,
   1837                         ni->ni_rates.rs_rates[ni->ni_txrate], ic->ic_curmode);
   1838                 break;
   1839         case IEEE80211_M_IBSS:
   1840                 ni = ic->ic_bss;
   1841                 /* calculate rate subtype */
   1842                 imr->ifm_active |= ieee80211_rate2media(ic,
   1843                         ni->ni_rates.rs_rates[ni->ni_txrate], ic->ic_curmode);
   1844                 imr->ifm_active |= IFM_IEEE80211_ADHOC;
   1845                 break;
   1846         case IEEE80211_M_AHDEMO:
   1847                 /* should not come here */
   1848                 break;
   1849         case IEEE80211_M_HOSTAP:
   1850                 imr->ifm_active |= IFM_IEEE80211_HOSTAP;
   1851                 break;
   1852         case IEEE80211_M_MONITOR:
   1853                 imr->ifm_active |= IFM_IEEE80211_MONITOR;
   1854                 break;
   1855         }
   1856         switch (ic->ic_curmode) {
   1857         case IEEE80211_MODE_11A:
   1858                 imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11A);
   1859                 break;
   1860         case IEEE80211_MODE_11B:
   1861                 imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11B);
   1862                 break;
   1863         case IEEE80211_MODE_11G:
   1864                 imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11G);
   1865                 break;
   1866 /*
   1867  * TODO: is this correct? (IEEE80211_MODE_TURBO_A and IEEE80211_MODE_TURBO_G
   1868  * are defined in _ieee80211.h)
   1869  */
   1870 	case IEEE80211_MODE_TURBO_A:
   1871 	case IEEE80211_MODE_TURBO_G:
   1872                 imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11A)
   1873                                 |  IFM_IEEE80211_TURBO;
   1874                 break;
   1875         }
   1876 }
   1877 
   1878 static int
   1879 ndis_get_assoc(struct ndis_softc *sc, ndis_wlan_bssid_ex **assoc)
   1880 {
   1881 	ndis_80211_bssid_list_ex	*bl;
   1882 	ndis_wlan_bssid_ex	*bs;
   1883 	ndis_80211_macaddr	bssid;
   1884 	int			i, len, error;
   1885 
   1886 	if (!sc->ndis_link)
   1887 		return(ENOENT);
   1888 
   1889 	len = sizeof(bssid);
   1890 	error = ndis_get_info(sc, OID_802_11_BSSID, &bssid, &len);
   1891 	if (error) {
   1892 		aprint_error_dev(sc->ndis_dev, "failed to get bssid\n");
   1893 		return(ENOENT);
   1894 	}
   1895 	len = 0;
   1896 	error = ndis_get_info(sc, OID_802_11_BSSID_LIST, NULL, &len);
   1897 	if (error != ENOSPC) {
   1898 		aprint_error_dev(sc->ndis_dev, "bssid_list failed\n");
   1899 		return (error);
   1900 	}
   1901 
   1902 	bl = malloc(len, M_TEMP, M_NOWAIT|M_ZERO);
   1903 	error = ndis_get_info(sc, OID_802_11_BSSID_LIST, bl, &len);
   1904 	if (error) {
   1905 		free(bl, M_TEMP);
   1906 		aprint_error_dev(sc->ndis_dev, "bssid_list failed\n");
   1907 		return (error);
   1908 	}
   1909 
   1910 	bs = (ndis_wlan_bssid_ex *)&bl->nblx_bssid[0];
   1911 	for (i = 0; i < bl->nblx_items; i++) {
   1912 		if (memcmp(bs->nwbx_macaddr, bssid, sizeof(bssid)) == 0) {
   1913 			*assoc = malloc(bs->nwbx_len, M_TEMP, M_NOWAIT);
   1914 			if (*assoc == NULL) {
   1915 				free(bl, M_TEMP);
   1916 				return(ENOMEM);
   1917 			}
   1918 			memcpy((char *)*assoc, (char *)bs, bs->nwbx_len);
   1919 			free(bl, M_TEMP);
   1920 			return(0);
   1921 		}
   1922 		bs = (ndis_wlan_bssid_ex *)((char *)bs + bs->nwbx_len);
   1923 	}
   1924 
   1925 	free(bl, M_TEMP);
   1926 	return(ENOENT);
   1927 }
   1928 
   1929 static void
   1930 ndis_getstate_80211(struct ndis_softc *sc)
   1931 {
   1932 	struct ieee80211com	*ic;
   1933 	ndis_80211_ssid		ssid;
   1934 	ndis_80211_config	config;
   1935 	ndis_wlan_bssid_ex	*bs = 0;
   1936 	int			rval, len, i = 0;
   1937 	uint32_t		arg;
   1938 	struct ifnet		*ifp;
   1939 
   1940 	ic = &sc->ic;
   1941 /* TODO: are these equivelant? */
   1942 	ifp = sc->ic.ic_ifp;
   1943 
   1944 	if (!NDIS_INITIALIZED(sc))
   1945 		return;
   1946 
   1947 	if (sc->ndis_link)
   1948 		ic->ic_state = IEEE80211_S_RUN;
   1949 	else
   1950 		ic->ic_state = IEEE80211_S_ASSOC;
   1951 
   1952 
   1953 	/*
   1954 	 * If we're associated, retrieve info on the current bssid.
   1955 	 */
   1956 	if ((rval = ndis_get_assoc(sc, &bs)) == 0) {
   1957 		switch(bs->nwbx_nettype) {
   1958 		case NDIS_80211_NETTYPE_11FH:
   1959 		case NDIS_80211_NETTYPE_11DS:
   1960 			ic->ic_curmode = IEEE80211_MODE_11B;
   1961 			break;
   1962 		case NDIS_80211_NETTYPE_11OFDM5:
   1963 			ic->ic_curmode = IEEE80211_MODE_11A;
   1964 			break;
   1965 		case NDIS_80211_NETTYPE_11OFDM24:
   1966 			ic->ic_curmode = IEEE80211_MODE_11G;
   1967 			break;
   1968 		default:
   1969 			aprint_error_dev(sc->ndis_dev, "unknown nettype %d\n",
   1970 				     arg);
   1971 			break;
   1972 		}
   1973 		free(bs, M_TEMP);
   1974 	} else
   1975 		return;
   1976 
   1977 	len = sizeof(ssid);
   1978 	memset((char *)&ssid, 0, len);
   1979 	rval = ndis_get_info(sc, OID_802_11_SSID, &ssid, &len);
   1980 
   1981 	if (rval)
   1982 		aprint_error_dev(sc->ndis_dev, "get ssid failed: %d\n", rval);
   1983 	memcpy(ic->ic_bss->ni_essid, ssid.ns_ssid, ssid.ns_ssidlen);
   1984 	ic->ic_bss->ni_esslen = ssid.ns_ssidlen;
   1985 
   1986 	len = sizeof(arg);
   1987 	rval = ndis_get_info(sc, OID_GEN_LINK_SPEED, &arg, &len);
   1988 	if (rval)
   1989 		aprint_error_dev(sc->ndis_dev, "get link speed failed: %d\n",
   1990 				rval);
   1991 
   1992 	if (ic->ic_modecaps & (1<<IEEE80211_MODE_11B)) {
   1993 		ic->ic_bss->ni_rates = ic->ic_sup_rates[IEEE80211_MODE_11B];
   1994 		for (i = 0; i < ic->ic_bss->ni_rates.rs_nrates; i++) {
   1995 			if ((ic->ic_bss->ni_rates.rs_rates[i] &
   1996 			    IEEE80211_RATE_VAL) == arg / 5000)
   1997 				break;
   1998 		}
   1999 	}
   2000 
   2001 	if (i == ic->ic_bss->ni_rates.rs_nrates &&
   2002 	    ic->ic_modecaps & (1<<IEEE80211_MODE_11G)) {
   2003 		ic->ic_bss->ni_rates = ic->ic_sup_rates[IEEE80211_MODE_11G];
   2004 		for (i = 0; i < ic->ic_bss->ni_rates.rs_nrates; i++) {
   2005 			if ((ic->ic_bss->ni_rates.rs_rates[i] &
   2006 			    IEEE80211_RATE_VAL) == arg / 5000)
   2007 				break;
   2008 		}
   2009 	}
   2010 
   2011 	if (i == ic->ic_bss->ni_rates.rs_nrates)
   2012 		aprint_error_dev(sc->ndis_dev, "no matching rate for: %d\n",
   2013 			     arg / 5000);
   2014 	else
   2015 		ic->ic_bss->ni_txrate = i;
   2016 
   2017 	if (ic->ic_caps & IEEE80211_C_PMGT) {
   2018 		len = sizeof(arg);
   2019 		rval = ndis_get_info(sc, OID_802_11_POWER_MODE, &arg, &len);
   2020 
   2021 		if (rval)
   2022 			aprint_error_dev(sc->ndis_dev, "get power mode failed: %d\n",
   2023 				     rval);
   2024 		if (arg == NDIS_80211_POWERMODE_CAM)
   2025 			ic->ic_flags &= ~IEEE80211_F_PMGTON;
   2026 		else
   2027 			ic->ic_flags |= IEEE80211_F_PMGTON;
   2028 	}
   2029 
   2030 	len = sizeof(config);
   2031 	memset((char *)&config, 0, len);
   2032 	config.nc_length = len;
   2033 	config.nc_fhconfig.ncf_length = sizeof(ndis_80211_config_fh);
   2034 	rval = ndis_get_info(sc, OID_802_11_CONFIGURATION, &config, &len);
   2035 	if (rval == 0) {
   2036 		int chan;
   2037 
   2038 		chan = ieee80211_mhz2ieee(config.nc_dsconfig / 1000, 0);
   2039 		if (chan < 0 || chan >= IEEE80211_CHAN_MAX) {
   2040 			if (ifp->if_flags & IFF_DEBUG)
   2041 				aprint_error_dev(sc->ndis_dev, "current channel "
   2042 					     "(%uMHz) out of bounds\n",
   2043 					     config.nc_dsconfig / 1000);
   2044 			ic->ic_bss->ni_chan = &ic->ic_channels[1];
   2045 		} else
   2046 			ic->ic_bss->ni_chan = &ic->ic_channels[chan];
   2047 	} else
   2048 		aprint_error_dev(sc->ndis_dev, "couldn't retrieve "
   2049 			     "channel info: %d\n", rval);
   2050 
   2051 /*
   2052 	len = sizeof(arg);
   2053 	rval = ndis_get_info(sc, OID_802_11_WEP_STATUS, &arg, &len);
   2054 
   2055 	if (rval)
   2056 		device_printf (sc->ndis_dev,
   2057 		    "get wep status failed: %d\n", rval);
   2058 
   2059 	if (arg == NDIS_80211_WEPSTAT_ENABLED)
   2060 		ic->ic_flags |= IEEE80211_F_WEPON;
   2061 	else
   2062 		ic->ic_flags &= ~IEEE80211_F_WEPON;
   2063 */
   2064 	return;
   2065 }
   2066 
   2067 static int
   2068 ndis_ioctl(struct ifnet *ifp, u_long command, void *data)
   2069 {
   2070 	struct ndis_softc	*sc = ifp->if_softc;
   2071 	struct ifreq		*ifr = (struct ifreq *) data;
   2072 	int			i, error = 0;
   2073 	int			s;
   2074 
   2075 	/*NDIS_LOCK(sc);*/
   2076 	s = splnet();
   2077 
   2078 	switch(command) {
   2079 	case SIOCSIFFLAGS:
   2080 		if ((error = ifioctl_common(ifp, command, data)) != 0)
   2081 			break;
   2082 		if (ifp->if_flags & IFF_UP) {
   2083 			if (ifp->if_flags & IFF_RUNNING &&
   2084 			    ifp->if_flags & IFF_PROMISC &&
   2085 			    !(sc->ndis_if_flags & IFF_PROMISC)) {
   2086 				sc->ndis_filter |=
   2087 				    NDIS_PACKET_TYPE_PROMISCUOUS;
   2088 				i = sizeof(sc->ndis_filter);
   2089 				error = ndis_set_info(sc,
   2090 				    OID_GEN_CURRENT_PACKET_FILTER,
   2091 				    &sc->ndis_filter, &i);
   2092 			} else if (ifp->if_flags & IFF_RUNNING &&
   2093 			    !(ifp->if_flags & IFF_PROMISC) &&
   2094 			    sc->ndis_if_flags & IFF_PROMISC) {
   2095 				sc->ndis_filter &=
   2096 				    ~NDIS_PACKET_TYPE_PROMISCUOUS;
   2097 				i = sizeof(sc->ndis_filter);
   2098 				error = ndis_set_info(sc,
   2099 				    OID_GEN_CURRENT_PACKET_FILTER,
   2100 				    &sc->ndis_filter, &i);
   2101 			} else
   2102 				ndis_init(ifp);
   2103 		} else {
   2104 			if (ifp->if_flags & IFF_RUNNING)
   2105 				ndis_stop(sc);
   2106 		}
   2107 		sc->ndis_if_flags = ifp->if_flags;
   2108 		error = 0;
   2109 		break;
   2110 	case SIOCADDMULTI:
   2111 	case SIOCDELMULTI:
   2112 /*
   2113  * TODO: I'm really not sure this is the correct thing to do here, but multicast
   2114  * address lists weren't getting set in ether_ioctl because they SIOCADDMULTI
   2115  * is routed to ndis_setmulti here.
   2116  */
   2117 		error = ether_ioctl(ifp, command, data);
   2118 		ndis_setmulti(sc);
   2119 		error = 0;
   2120 		break;
   2121 	case SIOCGIFMEDIA:
   2122 	case SIOCSIFMEDIA:
   2123 		if (sc->ndis_80211) {
   2124 			error = ieee80211_ioctl(&sc->ic, command, data);
   2125 			if (error == ENETRESET) {
   2126 				ndis_setstate_80211(sc);
   2127 				/*ndis_init(sc);*/
   2128 				error = 0;
   2129 			}
   2130 		} else
   2131 			error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command);
   2132 		break;
   2133 	case SIOCSIFCAP:
   2134 		if ((error = ether_ioctl(ifp, command, data)) == ENETRESET) {
   2135 			ndis_set_offload(sc);
   2136 			error = 0;
   2137 		}
   2138 		break;
   2139 	case SIOCGIFGENERIC:
   2140 	case SIOCSIFGENERIC:
   2141 		if (sc->ndis_80211 && NDIS_INITIALIZED(sc)) {
   2142 			if (command == SIOCGIFGENERIC)
   2143 				error = ndis_wi_ioctl_get(ifp, command, data);
   2144 			else
   2145 				error = ndis_wi_ioctl_set(ifp, command, data);
   2146 		} else
   2147 			error = ENOTTY;
   2148 		if (error != ENOTTY)
   2149 			break;
   2150 	default:
   2151 		sc->ndis_skip = 1;
   2152 		if (sc->ndis_80211) {
   2153 			error = ieee80211_ioctl(&sc->ic, command, data);
   2154 
   2155 			if (error == ENETRESET) {
   2156 				ndis_setstate_80211(sc);
   2157 				error = 0;
   2158 			}
   2159 		} else {
   2160 			error = ether_ioctl(ifp, command, data);
   2161 		}
   2162 		sc->ndis_skip = 0;
   2163 		break;
   2164 	}
   2165 
   2166 	/*NDIS_UNLOCK(sc);*/
   2167 			splx(s);
   2168 
   2169 	return(error);
   2170 }
   2171 
   2172 static int
   2173 ndis_wi_ioctl_get(struct ifnet *ifp, u_long command, void * data)
   2174 {
   2175 	struct wi_req		wreq;
   2176 	struct ifreq		*ifr;
   2177 	struct ndis_softc	*sc;
   2178 	ndis_80211_bssid_list_ex *bl;
   2179 	ndis_wlan_bssid_ex	*wb;
   2180 	struct wi_apinfo	*api;
   2181 	int			error, i, j, len, maxaps;
   2182 
   2183 	sc = ifp->if_softc;
   2184 	ifr = (struct ifreq *)data;
   2185 	error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
   2186 	if (error)
   2187 		return (error);
   2188 
   2189 	switch (wreq.wi_type) {
   2190 	case WI_RID_READ_APS:
   2191 		len = 0;
   2192 		error = ndis_set_info(sc, OID_802_11_BSSID_LIST_SCAN,
   2193 		    NULL, &len);
   2194 		if (error == 0)
   2195 			tsleep(&error, PPAUSE|PCATCH, "ssidscan", hz * 2);
   2196 		len = 0;
   2197 		error = ndis_get_info(sc, OID_802_11_BSSID_LIST, NULL, &len);
   2198 		if (error != ENOSPC)
   2199 			break;
   2200 		bl = malloc(len, M_DEVBUF, M_WAITOK|M_ZERO);
   2201 		error = ndis_get_info(sc, OID_802_11_BSSID_LIST, bl, &len);
   2202 		if (error) {
   2203 			free(bl, M_DEVBUF);
   2204 			break;
   2205 		}
   2206 		maxaps = (2 * wreq.wi_len - sizeof(int)) / sizeof(*api);
   2207 		maxaps = MIN(maxaps, bl->nblx_items);
   2208 		wreq.wi_len = (maxaps * sizeof(*api) + sizeof(int)) / 2;
   2209 		*(int *)&wreq.wi_val = maxaps;
   2210 		api = (struct wi_apinfo *)&((int *)&wreq.wi_val)[1];
   2211 		wb = bl->nblx_bssid;
   2212 		while (maxaps--) {
   2213 			memset(api, 0, sizeof(*api));
   2214 			memcpy(&api->bssid, &wb->nwbx_macaddr,
   2215 			    sizeof(api->bssid));
   2216 			api->namelen = wb->nwbx_ssid.ns_ssidlen;
   2217 			memcpy(&api->name, &wb->nwbx_ssid.ns_ssid, api->namelen);
   2218 			if (wb->nwbx_privacy)
   2219 				api->capinfo |= IEEE80211_CAPINFO_PRIVACY;
   2220 			/* XXX Where can we get noise information? */
   2221 			api->signal = wb->nwbx_rssi + 149;	/* XXX */
   2222 			api->quality = api->signal;
   2223 			api->channel =
   2224 			    ieee80211_mhz2ieee(wb->nwbx_config.nc_dsconfig /
   2225 			    1000, 0);
   2226 			/* In "auto" infrastructure mode, this is useless. */
   2227 			if (wb->nwbx_netinfra == NDIS_80211_NET_INFRA_IBSS)
   2228 				api->capinfo |= IEEE80211_CAPINFO_IBSS;
   2229 			if (wb->nwbx_len > sizeof(ndis_wlan_bssid)) {
   2230 				j = sizeof(ndis_80211_rates_ex);
   2231 				/* handle other extended things */
   2232 			} else
   2233 				j = sizeof(ndis_80211_rates);
   2234 			for (i = api->rate = 0; i < j; i++)
   2235 				api->rate = MAX(api->rate, 5 *
   2236 				    (wb->nwbx_supportedrates[i] & 0x7f));
   2237 			api++;
   2238 			wb = (ndis_wlan_bssid_ex *)((char *)wb + wb->nwbx_len);
   2239 		}
   2240 		free(bl, M_DEVBUF);
   2241 		error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
   2242 		break;
   2243 	default:
   2244 		error = ENOTTY;
   2245 		break;
   2246 	}
   2247 	return (error);
   2248 }
   2249 
   2250 static int
   2251 ndis_wi_ioctl_set(struct ifnet *ifp, u_long command, void * data)
   2252 {
   2253 	struct wi_req		wreq;
   2254 	struct ifreq		*ifr;
   2255 	struct ndis_softc	*sc;
   2256 	uint32_t		foo;
   2257 	int			error, len;
   2258 
   2259 	error = kauth_authorize_network(kauth_cred_get(),
   2260 	    KAUTH_NETWORK_INTERFACE, KAUTH_REQ_NETWORK_INTERFACE_SETPRIV,
   2261 	    ifp, KAUTH_ARG(command), NULL);
   2262 	if (error)
   2263 		return (error);
   2264 
   2265 	sc = ifp->if_softc;
   2266 	ifr = (struct ifreq *)data;
   2267 	error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
   2268 	if (error)
   2269 		return (error);
   2270 
   2271 	switch (wreq.wi_type) {
   2272 	case WI_RID_SCAN_APS:
   2273 	case WI_RID_SCAN_REQ:			/* arguments ignored */
   2274 		len = sizeof(foo);
   2275 		foo = 0;
   2276 		error = ndis_set_info(sc, OID_802_11_BSSID_LIST_SCAN, &foo,
   2277 		    &len);
   2278 		break;
   2279 	default:
   2280 		error = ENOTTY;
   2281 		break;
   2282 	}
   2283 	return (error);
   2284 }
   2285 
   2286 static void
   2287 ndis_watchdog(struct ifnet *ifp)
   2288 {
   2289 	struct ndis_softc		*sc;
   2290 	int				s;
   2291 
   2292 	sc = ifp->if_softc;
   2293 
   2294 	NDIS_LOCK(sc);
   2295 
   2296 	ifp->if_oerrors++;
   2297 	aprint_error_dev(sc->ndis_dev, "watchdog timeout\n");
   2298 
   2299 	NDIS_UNLOCK(sc);
   2300 
   2301 	ndis_sched((void(*)(void *))ndis_reset_nic, sc, NDIS_TASKQUEUE);
   2302 	ndis_sched(ndis_starttask, ifp, NDIS_TASKQUEUE);
   2303 
   2304 	return;
   2305 }
   2306 
   2307 /*
   2308  * Stop the adapter and free any mbufs allocated to the
   2309  * RX and TX lists.
   2310  */
   2311 static void
   2312 ndis_stop(struct ndis_softc *sc)
   2313 {
   2314 	struct ifnet		*ifp;
   2315 	int 			s;
   2316 
   2317 	ifp = &sc->arpcom.ac_if;
   2318 	callout_stop(&sc->ndis_stat_ch);
   2319 
   2320 	ndis_halt_nic(sc);
   2321 
   2322 	NDIS_LOCK(sc);
   2323 
   2324 	ifp->if_timer = 0;
   2325 	sc->ndis_link = 0;
   2326 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
   2327 
   2328 	NDIS_UNLOCK(sc);
   2329 
   2330 	return;
   2331 }
   2332 
   2333 /*
   2334  * Stop all chip I/O so that the kernel's probe routines don't
   2335  * get confused by errant DMAs when rebooting.
   2336  */
   2337 /* TODO: remove this #ifdef once ndis_shutdown_nic() is working on NetBSD */
   2338