1 /*	$NetBSD: if_ndis.c,v 1.36 2016/06/10 13:27:14 ozaki-r Exp $	*/
2 
3 /*-
4  * Copyright (c) 2003
5  *	Bill Paul <wpaul@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.36 2016/06/10 13:27:14 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
ndisdrv_modevent(module_t mod,int cmd)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
if_ndis_lkmentry(struct lkm_table * lkmtp,int cmd,int ver)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
ndis_setmulti(struct ndis_softc * sc)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
ndis_set_offload(struct ndis_softc * sc)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
ndis_probe_offload(struct ndis_softc * sc)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
ndis_attach(dev)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
ndis_detach(dev,flags)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
ndis_rxeof(ndis_handle adapter,ndis_packet ** packets,uint32_t pktcnt)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
ndis_txeof(adapter,packet,status)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
ndis_linksts(ndis_handle adapter,ndis_status status,void * sbuf,uint32_t slen)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
ndis_linksts_done(ndis_handle adapter)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
ndis_intr(arg)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
ndis_tick(void * xsc)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
ndis_ticktask(void * xsc)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
ndis_map_sclist(arg,segs,nseg,mapsize,error)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
ndis_starttask(void * arg)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
ndis_start(struct ifnet * ifp)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
ndis_init(xsc)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
ndis_ifmedia_upd(struct ifnet * ifp)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
ndis_ifmedia_sts(struct ifnet * ifp,struct ifmediareq * ifmr)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
ndis_setstate_80211(struct ndis_softc * sc)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
ndis_media_status(struct ifnet * ifp,struct ifmediareq * imr)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
ndis_get_assoc(struct ndis_softc * sc,ndis_wlan_bssid_ex ** assoc)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
ndis_getstate_80211(struct ndis_softc * sc)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
ndis_ioctl(struct ifnet * ifp,u_long command,void * data)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
ndis_wi_ioctl_get(struct ifnet * ifp,u_long command,void * data)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
ndis_wi_ioctl_set(struct ifnet * ifp,u_long command,void * data)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
ndis_watchdog(struct ifnet * ifp)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
ndis_stop(struct ndis_softc * sc)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