1 /*	$NetBSD: subr_ndis.c,v 1.28 2014/03/25 16:23:58 christos 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/compat/ndis/subr_ndis.c,v 1.67.2.7 2005/03/31 21:50:11 wpaul Exp $");
38 #endif
39 #ifdef __NetBSD__
40 __KERNEL_RCSID(0, "$NetBSD: subr_ndis.c,v 1.28 2014/03/25 16:23:58 christos Exp $");
41 #endif
42 
43 /*
44  * This file implements a translation layer between the BSD networking
45  * infrasturcture and Windows(R) NDIS network driver modules. A Windows
46  * NDIS driver calls into several functions in the NDIS.SYS Windows
47  * kernel module and exports a table of functions designed to be called
48  * by the NDIS subsystem. Using the PE loader, we can patch our own
49  * versions of the NDIS routines into a given Windows driver module and
50  * convince the driver that it is in fact running on Windows.
51  *
52  * We provide a table of all our implemented NDIS routines which is patched
53  * into the driver object code. All our exported routines must use the
54  * _stdcall calling convention, since that's what the Windows object code
55  * expects.
56  */
57 
58 #ifdef __FreeBSD__
59 #include <sys/ctype.h>
60 #endif
61 #include <sys/param.h>
62 #include <sys/types.h>
63 #include <sys/errno.h>
64 
65 #include <sys/callout.h>
66 #include <sys/kernel.h>
67 #include <sys/systm.h>
68 #include <sys/malloc.h>
69 #include <sys/lock.h>
70 #ifdef __FreeBSD__
71 #include <sys/mutex.h>
72 #endif
73 #include <sys/socket.h>
74 #include <sys/sysctl.h>
75 #ifdef __FreeBSD__
76 #include <sys/timespec.h>
77 #include <sys/smp.h>
78 #endif
79 #include <sys/queue.h>
80 #include <sys/proc.h>
81 #include <sys/filedesc.h>
82 #include <sys/namei.h>
83 #include <sys/fcntl.h>
84 #include <sys/vnode.h>
85 #include <sys/kthread.h>
86 #ifdef __FreeBSD__
87 #include <sys/linker.h>
88 #include <sys/sysproto.h>
89 #endif
90 #include <sys/mount.h>
91 
92 #include <net/if.h>
93 #include <net/if_arp.h>
94 #ifdef __FreeBSD__
95 #include <net/ethernet.h>
96 #else
97 #include <net/if_ether.h>
98 #endif
99 #include <net/if_dl.h>
100 #include <net/if_media.h>
101 
102 #include <sys/atomic.h>
103 #ifdef __FreeBSD__
104 #include <machine/bus_memio.h>
105 #include <machine/bus_pio.h>
106 #include <machine/resource.h>
107 #include <sys/bus.h>
108 #include <sys/rman.h>
109 #endif
110 #include <sys/bus.h>
111 
112 #include <net80211/ieee80211_var.h>
113 #include <net80211/ieee80211_ioctl.h>
114 
115 #include <dev/pci/pcireg.h>
116 #include <dev/pci/pcivar.h>
117 
118 #include <compat/ndis/pe_var.h>
119 #include <compat/ndis/resource_var.h>
120 #include <compat/ndis/ntoskrnl_var.h>
121 #include <compat/ndis/hal_var.h>
122 #include <compat/ndis/ndis_var.h>
123 #include <compat/ndis/cfg_var.h>
124 #include <dev/if_ndis/if_ndisvar.h>
125 
126 #ifdef __NetBSD__
127 #include "nbcompat.h"
128 #endif
129 
130 #ifdef __NetBSD__
131 #define PN(name) /* printf(#name "\n"); */
132 #endif
133 
134 static char ndis_filepath[MAXPATHLEN];
135 extern struct nd_head ndis_devhead;
136 
137 #ifdef __FreeBSD__
138 SYSCTL_STRING(_hw, OID_AUTO, ndis_filepath, CTLFLAG_RW, ndis_filepath,
139         MAXPATHLEN, "Path used by NdisOpenFile() to search for files");
140 #endif
141 
142 __stdcall static void NdisInitializeWrapper(ndis_handle *,
143 	driver_object *, void *, void *);
144 __stdcall static ndis_status NdisMRegisterMiniport(ndis_handle,
145 	ndis_miniport_characteristics *, int);
146 __stdcall static ndis_status NdisAllocateMemoryWithTag(void **,
147 	uint32_t, uint32_t);
148 __stdcall static ndis_status NdisAllocateMemory(void **,
149 	uint32_t, uint32_t, ndis_physaddr);
150 __stdcall static void NdisFreeMemory(void *, uint32_t, uint32_t);
151 __stdcall static ndis_status NdisMSetAttributesEx(ndis_handle, ndis_handle,
152 	uint32_t, uint32_t, ndis_interface_type);
153 __stdcall static void NdisOpenConfiguration(ndis_status *,
154 	ndis_handle *, ndis_handle);
155 __stdcall static void NdisOpenConfigurationKeyByIndex(ndis_status *,
156 	ndis_handle, uint32_t, ndis_unicode_string *, ndis_handle *);
157 __stdcall static void NdisOpenConfigurationKeyByName(ndis_status *,
158 	ndis_handle, ndis_unicode_string *, ndis_handle *);
159 #ifdef __FreeBSD__
160 static ndis_status ndis_encode_parm(ndis_miniport_block *,
161 	struct sysctl_oid *, ndis_parm_type, ndis_config_parm **);
162 static ndis_status ndis_decode_parm(ndis_miniport_block *,
163 	ndis_config_parm *, char *, size_t);
164 #else /* __NetBSD__ */
165 static ndis_status ndis_encode_parm(ndis_miniport_block *,
166 	void *, ndis_parm_type, ndis_config_parm **);
167 #endif
168 __stdcall static void NdisReadConfiguration(ndis_status *, ndis_config_parm **,
169 	ndis_handle, ndis_unicode_string *, ndis_parm_type);
170 __stdcall static void NdisWriteConfiguration(ndis_status *, ndis_handle,
171 	ndis_unicode_string *, ndis_config_parm *);
172 __stdcall static void NdisCloseConfiguration(ndis_handle);
173 __stdcall static void NdisAllocateSpinLock(ndis_spin_lock *);
174 __stdcall static void NdisFreeSpinLock(ndis_spin_lock *);
175 __stdcall static void NdisAcquireSpinLock(ndis_spin_lock *);
176 __stdcall static void NdisReleaseSpinLock(ndis_spin_lock *);
177 __stdcall static void NdisDprAcquireSpinLock(ndis_spin_lock *);
178 __stdcall static void NdisDprReleaseSpinLock(ndis_spin_lock *);
179 __stdcall static uint32_t NdisReadPciSlotInformation(ndis_handle, uint32_t,
180 	uint32_t, void *, uint32_t);
181 __stdcall static uint32_t NdisWritePciSlotInformation(ndis_handle, uint32_t,
182 	uint32_t, void *, uint32_t);
183 static void NdisWriteErrorLogEntry(ndis_handle, ndis_error_code, uint32_t, ...);
184 static void ndis_map_cb(void *, bus_dma_segment_t *, int, int);
185 __stdcall static void NdisMStartBufferPhysicalMapping(ndis_handle,
186 	ndis_buffer *, uint32_t, uint8_t, ndis_paddr_unit *, uint32_t *);
187 __stdcall static void NdisMCompleteBufferPhysicalMapping(ndis_handle,
188 	ndis_buffer *, uint32_t);
189 __stdcall static void NdisMInitializeTimer(ndis_miniport_timer *, ndis_handle,
190 	ndis_timer_function, void *);
191 __stdcall static void NdisInitializeTimer(ndis_timer *,
192 	ndis_timer_function, void *);
193 __stdcall static void NdisSetTimer(ndis_timer *, uint32_t);
194 __stdcall static void NdisMSetPeriodicTimer(ndis_miniport_timer *, uint32_t);
195 __stdcall static void NdisMCancelTimer(ndis_timer *, uint8_t *);
196 __stdcall static void ndis_timercall(kdpc *, ndis_miniport_timer *,
197 	void *, void *);
198 __stdcall static void NdisMQueryAdapterResources(ndis_status *, ndis_handle,
199 	ndis_resource_list *, uint32_t *);
200 __stdcall static ndis_status NdisMRegisterIoPortRange(void **,
201 	ndis_handle, uint32_t, uint32_t);
202 __stdcall static void NdisMDeregisterIoPortRange(ndis_handle,
203 	uint32_t, uint32_t, void *);
204 __stdcall static void NdisReadNetworkAddress(ndis_status *, void **,
205 	uint32_t *, ndis_handle);
206 __stdcall static ndis_status NdisQueryMapRegisterCount(uint32_t, uint32_t *);
207 __stdcall static ndis_status NdisMAllocateMapRegisters(ndis_handle,
208 	uint32_t, uint8_t, uint32_t, uint32_t);
209 __stdcall static void NdisMFreeMapRegisters(ndis_handle);
210 static void ndis_mapshared_cb(void *, bus_dma_segment_t *, int, int);
211 __stdcall static void NdisMAllocateSharedMemory(ndis_handle, uint32_t,
212 	uint8_t, void **, ndis_physaddr *);
213 static void ndis_asyncmem_complete(void *);
214 __stdcall static ndis_status NdisMAllocateSharedMemoryAsync(ndis_handle,
215 	uint32_t, uint8_t, void *);
216 __stdcall static void NdisMFreeSharedMemory(ndis_handle, uint32_t,
217 	uint8_t, void *, ndis_physaddr);
218 __stdcall static ndis_status NdisMMapIoSpace(void **, ndis_handle,
219 	ndis_physaddr, uint32_t);
220 __stdcall static void NdisMUnmapIoSpace(ndis_handle, void *, uint32_t);
221 __stdcall static uint32_t NdisGetCacheFillSize(void);
222 __stdcall static uint32_t NdisMGetDmaAlignment(ndis_handle);
223 __stdcall static ndis_status NdisMInitializeScatterGatherDma(ndis_handle,
224 	uint8_t, uint32_t);
225 __stdcall static void NdisUnchainBufferAtFront(ndis_packet *, ndis_buffer **);
226 __stdcall static void NdisUnchainBufferAtBack(ndis_packet *, ndis_buffer **);
227 __stdcall static void NdisAllocateBufferPool(ndis_status *,
228 	ndis_handle *, uint32_t);
229 __stdcall static void NdisFreeBufferPool(ndis_handle);
230 __stdcall static void NdisAllocateBuffer(ndis_status *, ndis_buffer **,
231 	ndis_handle, void *, uint32_t);
232 __stdcall static void NdisFreeBuffer(ndis_buffer *);
233 __stdcall static uint32_t NdisBufferLength(ndis_buffer *);
234 __stdcall static void NdisQueryBuffer(ndis_buffer *, void **, uint32_t *);
235 __stdcall static void NdisQueryBufferSafe(ndis_buffer *, void **,
236 	uint32_t *, uint32_t);
237 __stdcall static void *NdisBufferVirtualAddress(ndis_buffer *);
238 __stdcall static void *NdisBufferVirtualAddressSafe(ndis_buffer *, uint32_t);
239 __stdcall static void NdisAdjustBufferLength(ndis_buffer *, int);
240 __stdcall static uint32_t NdisInterlockedIncrement(uint32_t *);
241 __stdcall static uint32_t NdisInterlockedDecrement(uint32_t *);
242 __stdcall static void NdisInitializeEvent(ndis_event *);
243 __stdcall static void NdisSetEvent(ndis_event *);
244 __stdcall static void NdisResetEvent(ndis_event *);
245 __stdcall static uint8_t NdisWaitEvent(ndis_event *, uint32_t);
246 __stdcall static ndis_status NdisUnicodeStringToAnsiString(ndis_ansi_string *,
247 	ndis_unicode_string *);
248 __stdcall static ndis_status
249 	NdisAnsiStringToUnicodeString(ndis_unicode_string *,
250 	ndis_ansi_string *);
251 __stdcall static ndis_status NdisMPciAssignResources(ndis_handle,
252 	uint32_t, ndis_resource_list **);
253 __stdcall static ndis_status NdisMRegisterInterrupt(ndis_miniport_interrupt *,
254 	ndis_handle, uint32_t, uint32_t, uint8_t,
255 	uint8_t, ndis_interrupt_mode);
256 __stdcall static void NdisMDeregisterInterrupt(ndis_miniport_interrupt *);
257 __stdcall static void NdisMRegisterAdapterShutdownHandler(ndis_handle, void *,
258 	ndis_shutdown_handler);
259 __stdcall static void NdisMDeregisterAdapterShutdownHandler(ndis_handle);
260 __stdcall static uint32_t NDIS_BUFFER_TO_SPAN_PAGES(ndis_buffer *);
261 __stdcall static void NdisGetBufferPhysicalArraySize(ndis_buffer *,
262 	uint32_t *);
263 __stdcall static void NdisQueryBufferOffset(ndis_buffer *,
264 	uint32_t *, uint32_t *);
265 __stdcall static void NdisMSleep(uint32_t);
266 __stdcall static uint32_t NdisReadPcmciaAttributeMemory(ndis_handle,
267 	uint32_t, void *, uint32_t);
268 __stdcall static uint32_t NdisWritePcmciaAttributeMemory(ndis_handle,
269 	uint32_t, void *, uint32_t);
270 __stdcall static list_entry *NdisInterlockedInsertHeadList(list_entry *,
271 	list_entry *, ndis_spin_lock *);
272 __stdcall static list_entry *NdisInterlockedRemoveHeadList(list_entry *,
273 	ndis_spin_lock *);
274 __stdcall static list_entry *NdisInterlockedInsertTailList(list_entry *,
275 	list_entry *, ndis_spin_lock *);
276 __stdcall static uint8_t
277 	NdisMSynchronizeWithInterrupt(ndis_miniport_interrupt *,
278 	void *, void *);
279 __stdcall static void NdisGetCurrentSystemTime(uint64_t *);
280 __stdcall static void NdisGetSystemUpTime(uint32_t *);
281 __stdcall static void NdisInitializeString(ndis_unicode_string *, char *);
282 __stdcall static void NdisInitAnsiString(ndis_ansi_string *, char *);
283 __stdcall static void NdisInitUnicodeString(ndis_unicode_string *,
284 	uint16_t *);
285 __stdcall static void NdisFreeString(ndis_unicode_string *);
286 __stdcall static ndis_status NdisMRemoveMiniport(ndis_handle *);
287 __stdcall static void NdisTerminateWrapper(ndis_handle, void *);
288 __stdcall static void NdisMGetDeviceProperty(ndis_handle, device_object **,
289 	device_object **, device_object **, cm_resource_list *,
290 	cm_resource_list *);
291 __stdcall static void NdisGetFirstBufferFromPacket(ndis_packet *,
292 	ndis_buffer **, void **, uint32_t *, uint32_t *);
293 __stdcall static void NdisGetFirstBufferFromPacketSafe(ndis_packet *,
294 	ndis_buffer **, void **, uint32_t *, uint32_t *, uint32_t);
295 #ifdef __FreeBSD__
296 static int ndis_find_sym(linker_file_t, char *, char *, void **);
297 __stdcall static void NdisOpenFile(ndis_status *, ndis_handle *, uint32_t *,
298 	ndis_unicode_string *, ndis_physaddr);
299 __stdcall static void NdisMapFile(ndis_status *, void **, ndis_handle);
300 __stdcall static void NdisUnmapFile(ndis_handle);
301 __stdcall static void NdisCloseFile(ndis_handle);
302 #endif
303 __stdcall static uint8_t NdisSystemProcessorCount(void);
304 __stdcall static void NdisMIndicateStatusComplete(ndis_handle);
305 __stdcall static void NdisMIndicateStatus(ndis_handle, ndis_status,
306         void *, uint32_t);
307 static void ndis_workfunc(void *);
308 static funcptr ndis_findwrap(funcptr);
309 __stdcall static ndis_status NdisScheduleWorkItem(ndis_work_item *);
310 __stdcall static void NdisCopyFromPacketToPacket(ndis_packet *,
311 	uint32_t, uint32_t, ndis_packet *, uint32_t, uint32_t *);
312 __stdcall static void NdisCopyFromPacketToPacketSafe(ndis_packet *,
313 	uint32_t, uint32_t, ndis_packet *, uint32_t, uint32_t *, uint32_t);
314 __stdcall static ndis_status NdisMRegisterDevice(ndis_handle,
315 	ndis_unicode_string *, ndis_unicode_string *, driver_dispatch **,
316 	void **, ndis_handle *);
317 __stdcall static ndis_status NdisMDeregisterDevice(ndis_handle);
318 __stdcall static ndis_status
319 	NdisMQueryAdapterInstanceName(ndis_unicode_string *,
320 	ndis_handle);
321 __stdcall static void NdisMRegisterUnloadHandler(ndis_handle, void *);
322 __stdcall static void dummy(void);
323 
324 /*
325  * Some really old drivers do not properly check the return value
326  * from NdisAllocatePacket() and NdisAllocateBuffer() and will
327  * sometimes allocate few more buffers/packets that they originally
328  * requested when they created the pool. To prevent this from being
329  * a problem, we allocate a few extra buffers/packets beyond what
330  * the driver asks for. This #define controls how many.
331  */
332 #define NDIS_POOL_EXTRA		16
333 
334 int
ndis_libinit(void)335 ndis_libinit(void)
336 {
337 	image_patch_table	*patch;
338 
339 	strcpy(ndis_filepath, "/compat/ndis");
340 
341 	patch = ndis_functbl;
342 	while (patch->ipt_func != NULL) {
343 		windrv_wrap((funcptr)patch->ipt_func,
344 		    (funcptr *)&patch->ipt_wrap);
345 		patch++;
346 	}
347 
348 	return(0);
349 }
350 
351 int
ndis_libfini(void)352 ndis_libfini(void)
353 {
354 	image_patch_table	*patch;
355 
356 	patch = ndis_functbl;
357 	while (patch->ipt_func != NULL) {
358 		windrv_unwrap(patch->ipt_wrap);
359 		patch++;
360 	}
361 
362 	return(0);
363 }
364 
365 static funcptr
ndis_findwrap(funcptr func)366 ndis_findwrap(funcptr func)
367 {
368 	image_patch_table	*patch;
369 
370 	patch = ndis_functbl;
371 	while (patch->ipt_func != NULL) {
372 		if ((funcptr)patch->ipt_func == func)
373 			return((funcptr)patch->ipt_wrap);
374 		patch++;
375 	}
376 
377 	return(NULL);
378 }
379 
380 /*
381  * NDIS deals with strings in unicode format, so we have
382  * do deal with them that way too. For now, we only handle
383  * conversion between unicode and ASCII since that's all
384  * that device drivers care about.
385  */
386 
387 int
ndis_ascii_to_unicode(const char * ascii,uint16_t ** unicode)388 ndis_ascii_to_unicode(const char *ascii, uint16_t **unicode)
389 {
390 	uint16_t		*ustr;
391 	int			i;
392 
393 	if (*unicode == NULL)
394 		*unicode = malloc(strlen(ascii) * 2, M_DEVBUF, M_NOWAIT);
395 
396 	if (*unicode == NULL)
397 		return(ENOMEM);
398 	ustr = *unicode;
399 	for (i = 0; i < strlen(ascii); i++) {
400 		*ustr = (uint16_t)ascii[i];
401 		ustr++;
402 	}
403 
404 	return(0);
405 }
406 
407 int
ndis_unicode_to_ascii(uint16_t * unicode,int ulen,char ** ascii)408 ndis_unicode_to_ascii(uint16_t *unicode, int ulen, char **ascii)
409 {
410 	uint8_t			*astr;
411 	int			i;
412 
413 	if (*ascii == NULL)
414 		*ascii = malloc((ulen / 2) + 1, M_DEVBUF, M_NOWAIT|M_ZERO);
415 	if (*ascii == NULL)
416 		return(ENOMEM);
417 	astr = *ascii;
418 	for (i = 0; i < ulen / 2; i++) {
419 		*astr = (uint8_t)unicode[i];
420 		astr++;
421 	}
422 
423 	return(0);
424 }
425 
426 /*
427  * This routine does the messy Windows Driver Model device attachment
428  * stuff on behalf of NDIS drivers. We register our own AddDevice
429  * routine here
430  */
431 __stdcall static void
NdisInitializeWrapper(ndis_handle * wrapper,driver_object * drv,void * path,void * unused)432 NdisInitializeWrapper(
433 	ndis_handle		*wrapper,
434 	driver_object		*drv,
435 	void			*path,
436 	void			*unused)
437 {
438 	PN(NdisInitializeWrapper)
439 	/*
440 	 * As of yet, I haven't come up with a compelling
441 	 * reason to define a private NDIS wrapper structure,
442 	 * so we use a pointer to the driver object as the
443 	 * wrapper handle. The driver object has the miniport
444 	 * characteristics struct for this driver hung off it
445 	 * via IoAllocateDriverObjectExtension(), and that's
446 	 * really all the private data we need.
447 	 */
448 
449 	*wrapper = drv;
450 
451 	/*
452 	 * If this was really Windows, we'd be registering dispatch
453 	 * routines for the NDIS miniport module here, but we're
454 	 * not Windows so all we really need to do is set up an
455 	 * AddDevice function that'll be invoked when a new device
456 	 * instance appears.
457 	 */
458 
459 	drv->dro_driverext->dre_adddevicefunc = NdisAddDevice;
460 
461 	return;
462 }
463 
464 __stdcall static void
NdisTerminateWrapper(ndis_handle handle,void * syspec)465 NdisTerminateWrapper(
466 	ndis_handle		handle,
467 	void			*syspec)
468 {
469 	/* Nothing to see here, move along. */
470 	return;
471 }
472 
473 __stdcall static ndis_status
NdisMRegisterMiniport(ndis_handle handle,ndis_miniport_characteristics * characteristics,int len)474 NdisMRegisterMiniport(ndis_handle handle, ndis_miniport_characteristics *characteristics, int len)
475 {
476 	ndis_miniport_characteristics	*pch = NULL;
477 	void *ch = NULL;
478 	driver_object		*drv;
479 
480 	PN(NdisMRegisterMiniport);
481 
482 	drv = (driver_object *)handle;
483 
484 	/*
485 	 * We need to save the NDIS miniport characteristics
486 	 * somewhere. This data is per-driver, not per-device
487 	 * (all devices handled by the same driver have the
488 	 * same characteristics) so we hook it onto the driver
489 	 * object using IoAllocateDriverObjectExtension().
490 	 * The extra extension info is automagically deleted when
491 	 * the driver is unloaded (see windrv_unload()).
492 	 */
493 	if (IoAllocateDriverObjectExtension(drv, (void *)1,
494 		sizeof(ndis_miniport_characteristics), /*(void **)*/&ch) !=
495 	    STATUS_SUCCESS)
496 		return(NDIS_STATUS_RESOURCES);
497    pch = (ndis_miniport_characteristics *)ch;
498 
499 	memset((char *)pch, 0, sizeof(ndis_miniport_characteristics));
500 
501 #ifdef __FreeBSD__
502 	memcpy( (char *)pch, (char *)characteristics, len);
503 #else /* __NetBSD__ */
504 	memcpy(pch, characteristics, len);
505 #endif
506 
507 	if (pch->nmc_version_major < 5 || pch->nmc_version_minor < 1) {
508 		pch->nmc_shutdown_handler = NULL;
509 		pch->nmc_canceltxpkts_handler = NULL;
510 		pch->nmc_pnpevent_handler = NULL;
511 	}
512 
513 	return(NDIS_STATUS_SUCCESS);
514 }
515 
516 __stdcall static ndis_status
NdisAllocateMemoryWithTag(void ** vaddr,uint32_t len,uint32_t tag)517 NdisAllocateMemoryWithTag(void **vaddr, uint32_t len, uint32_t tag)
518 {
519 	void			*mem;
520 
521 
522 	mem = ExAllocatePoolWithTag(NonPagedPool, len, tag);
523 	if (mem == NULL)
524 		return(NDIS_STATUS_RESOURCES);
525 	*vaddr = mem;
526 
527 	return(NDIS_STATUS_SUCCESS);
528 }
529 
530 __stdcall static ndis_status
NdisAllocateMemory(void ** vaddr,uint32_t len,uint32_t flags,ndis_physaddr highaddr)531 NdisAllocateMemory(
532 	void			**vaddr,
533 	uint32_t		len,
534 	uint32_t		flags,
535 	ndis_physaddr		highaddr)
536 {
537 	void			*mem;
538 
539 	mem = ExAllocatePoolWithTag(NonPagedPool, len, 0);
540 	if (mem == NULL)
541 		return(NDIS_STATUS_RESOURCES);
542 	*vaddr = mem;
543 
544 	return(NDIS_STATUS_SUCCESS);
545 }
546 
547 __stdcall static void
NdisFreeMemory(void * vaddr,uint32_t len,uint32_t flags)548 NdisFreeMemory(
549 	void			*vaddr,
550 	uint32_t		len,
551 	uint32_t		flags)
552 {
553 	if (len == 0)
554 		return;
555 
556 	ExFreePool(vaddr);
557 
558 	return;
559 }
560 
561 __stdcall static ndis_status
NdisMSetAttributesEx(ndis_handle adapter_handle,ndis_handle adapter_ctx,uint32_t hangsecs,uint32_t flags,ndis_interface_type iftype)562 NdisMSetAttributesEx(
563 	ndis_handle			adapter_handle,
564 	ndis_handle			adapter_ctx,
565 	uint32_t			hangsecs,
566 	uint32_t			flags,
567 	ndis_interface_type		iftype)
568 {
569 	ndis_miniport_block		*block;
570 
571 	PN(NdisMSetAttributesEx)
572 	/*
573 	 * Save the adapter context, we need it for calling
574 	 * the driver's internal functions.
575 	 */
576 	block = (ndis_miniport_block *)adapter_handle;
577 	block->nmb_miniportadapterctx = adapter_ctx;
578 	block->nmb_checkforhangsecs = hangsecs;
579 	block->nmb_flags = flags;
580 
581 	return(NDIS_STATUS_SUCCESS);
582 }
583 
584 __stdcall static void
NdisOpenConfiguration(ndis_status * status,ndis_handle * cfg,ndis_handle wrapctx)585 NdisOpenConfiguration(ndis_status *status, ndis_handle *cfg, ndis_handle wrapctx)
586 {
587 	PN(NdisOpenConfiguration)
588 	*cfg = wrapctx;
589 	*status = NDIS_STATUS_SUCCESS;
590 
591 	return;
592 }
593 
594 __stdcall static void
NdisOpenConfigurationKeyByName(ndis_status * status,ndis_handle cfg,ndis_unicode_string * subkey,ndis_handle * subhandle)595 NdisOpenConfigurationKeyByName(
596 	ndis_status		*status,
597 	ndis_handle		cfg,
598 	ndis_unicode_string	*subkey,
599 	ndis_handle		*subhandle)
600 {
601 	PN(NdisOpenConfiguration)
602 	*subhandle = cfg;
603 	*status = NDIS_STATUS_SUCCESS;
604 	return;
605 }
606 
607 __stdcall static void
NdisOpenConfigurationKeyByIndex(ndis_status * status,ndis_handle cfg,uint32_t idx,ndis_unicode_string * subkey,ndis_handle * subhandle)608 NdisOpenConfigurationKeyByIndex(
609 	ndis_status		*status,
610 	ndis_handle		cfg,
611 	uint32_t		idx,
612 	ndis_unicode_string	*subkey,
613 	ndis_handle		*subhandle)
614 {
615 	*status = NDIS_STATUS_FAILURE;
616 	return;
617 }
618 
619 static ndis_status
ndis_encode_parm(ndis_miniport_block * block,struct sysctl_oid * oid,ndis_parm_type type,ndis_config_parm ** parm)620 ndis_encode_parm(
621     ndis_miniport_block	*block,
622 #ifdef __FreeBSD__
623     struct sysctl_oid	*oid,
624 #define oiddata	oid->iod_arg1
625 #else
626     void 		*oiddata,
627 #endif
628     ndis_parm_type	type,
629     ndis_config_parm	**parm)
630 {
631 	uint16_t		*unicode;
632 	ndis_unicode_string	*ustr;
633 	int			base = 0;
634 
635 	PN(ndis_encode_parm)
636 
637 	unicode = (uint16_t *)&block->nmb_dummybuf;
638 
639 	switch(type) {
640 	case ndis_parm_string:
641 		ndis_ascii_to_unicode((char *)oiddata, &unicode);
642 		(*parm)->ncp_type = ndis_parm_string;
643 		ustr = &(*parm)->ncp_parmdata.ncp_stringdata;
644 		ustr->us_len = strlen((char *)oiddata) * 2;
645 		ustr->us_buf = unicode;
646 		break;
647 	case ndis_parm_int:
648 		if (strncmp(oiddata, "0x", 2) == 0) {
649 			base = 16;
650 		}
651 		else
652 			base = 10;
653 		(*parm)->ncp_type = ndis_parm_int;
654 		(*parm)->ncp_parmdata.ncp_intdata =
655 		    strtoul((char *)oiddata, NULL, base);
656 		break;
657 	case ndis_parm_hexint:
658 		if (strncmp((char *)oiddata, "0x", 2) == 0) {
659 			base = 16;
660 		}
661 		else
662 			base = 10;
663 		(*parm)->ncp_type = ndis_parm_hexint;
664 		(*parm)->ncp_parmdata.ncp_intdata =
665 		    strtoul((char *)oiddata, NULL, base);
666 		break;
667 	default:
668 		return(NDIS_STATUS_FAILURE);
669 		break;
670 	}
671 
672 	return(NDIS_STATUS_SUCCESS);
673 }
674 
675 int
ndis_strcasecmp(const char * s1,const char * s2)676 ndis_strcasecmp(const char *s1, const char *s2)
677 {
678 	char			a, b;
679 
680 	/*
681 	 * In the kernel, toupper() is a macro. Have to be careful
682 	 * not to use pointer arithmetic when passing it arguments.
683 	 */
684 
685 	while(1) {
686 		a = *s1;
687 		b = *s2++;
688 		if (toupper(a) != toupper(b))
689 			break;
690 		if (*s1++ == '\0')
691 			return(0);
692 	}
693 
694 	return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1));
695 }
696 
697 int
ndis_strncasecmp(const char * s1,const char * s2,size_t n)698 ndis_strncasecmp(const char *s1, const char *s2, size_t n)
699 {
700 	char			a, b;
701 
702 	if (n != 0) {
703 		do {
704 			a = *s1;
705 			b = *s2++;
706 			if (toupper(a) != toupper(b))
707 				return (*(const unsigned char *)s1 -
708 				    *(const unsigned char *)(s2 - 1));
709 			if (*s1++ == '\0')
710 				break;
711 		} while (--n != 0);
712 	}
713 
714 	return(0);
715 }
716 
717 __stdcall static void
NdisReadConfiguration(ndis_status * status,ndis_config_parm ** parm,ndis_handle cfg,ndis_unicode_string * key,ndis_parm_type type)718 NdisReadConfiguration(ndis_status *status, ndis_config_parm **parm, ndis_handle cfg, ndis_unicode_string *key, ndis_parm_type type)
719 {
720 	char			*keystr = NULL;
721 	ndis_miniport_block	*block;
722 	struct ndis_softc	*sc;
723 #ifdef __FreeBSD__
724     struct sysctl_oid	*oidp;
725 	struct sysctl_ctx_entry	*e;
726 #endif
727 
728 #ifdef __NetBSD__
729 	const struct sysctlnode *pnode = NULL;
730 	struct sysctlnode *ndiscld = NULL;
731 	int numcld;
732 	int mib[1];
733 	int i;
734 	char new_keystr[MAX_SYSCTL_LEN+1];
735 	char *old_keystr;
736 #endif
737 
738 	block = (ndis_miniport_block *)cfg;
739 #ifdef __FreeBSD__
740 	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
741 #else /* __NetBSD__ */
742 	sc = block->nmb_physdeviceobj->pdo_sc;
743 #endif
744 	PN(NdisReadConfiguration)
745 
746 	if (key->us_len == 0 || key->us_buf == NULL) {
747 		*status = NDIS_STATUS_FAILURE;
748 		return;
749 	}
750 
751 	ndis_unicode_to_ascii(key->us_buf, key->us_len, &keystr);
752 	*parm = &block->nmb_replyparm;
753 	memset((char *)&block->nmb_replyparm, 0, sizeof(ndis_config_parm));
754 
755 #ifdef __NetBSD__
756 	if(strlen(keystr) + strlen("ndis_") > MAX_SYSCTL_LEN) {
757 		panic("sysctl name too long: %s\n", keystr);
758 	}
759 	strcpy(new_keystr, "ndis_");
760 	strcpy(new_keystr + strlen("ndis_"), keystr);
761 	old_keystr = keystr;
762 	keystr = new_keystr;
763 #endif
764 
765 	/*
766 	 * See if registry key is already in a list of known keys
767 	 * included with the driver.
768 	 */
769 #ifdef __FreeBSD__
770 #if __FreeBSD_version < 502113
771 	TAILQ_FOREACH(e, &sc->ndis_ctx, link) {
772 #else
773 	TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) {
774 #endif
775 		oidp = e->entry;
776 #ifdef __FreeBSD__
777 		if (ndis_strcasecmp(oidp->oid_name, keystr) == 0) {
778 #else /* __NetBSD__ */
779 		if (ndis_strcasecmp(oidp->ctl_name, keystr) == 0) {
780 #endif
781 			if (strcmp((char *)oidp->oid_arg1, "UNSET") == 0) {
782 				free(keystr, M_DEVBUF);
783 				*status = NDIS_STATUS_FAILURE;
784 				return;
785 			}
786 			*status = ndis_encode_parm(block, oidp, type, parm);
787 
788 			free(keystr, M_DEVBUF);
789 			return;
790 		}
791 	}
792 #else /* __NetBSD__ */
793 	mib[0] = sc->ndis_sysctl_mib;
794 
795 	sysctl_lock(false);
796 		sysctl_locate(curlwp, &mib[0], 1, &pnode, NULL);
797 
798 		numcld  = pnode->sysctl_csize;
799 		ndiscld = pnode->sysctl_child;
800 
801 		/* find the node whose name is keystr */
802 		for(i=0; i < numcld; i++) {
803 			if(strcmp(keystr, ndiscld->sysctl_name) == 0) {
804 				/* Found it */
805 				break;
806 			}
807 			ndiscld++;
808 		}
809 	sysctl_unlock();
810 
811 	if(i < numcld) {
812 		/* Found it */
813 		if(strcmp(ndiscld->sysctl_data, "UNSET") == 0) {
814 			free(keystr, M_DEVBUF);
815 			*status = NDIS_STATUS_FAILURE;
816 			return;
817 		}
818 
819 		*status = ndis_encode_parm(block, ndiscld->sysctl_data, type,  parm);
820 		free(keystr, M_DEVBUF);
821 		return;
822 	}
823 
824 #endif
825 
826 #ifdef __NetBSD__
827 	free(keystr, M_DEVBUF);
828 	keystr = old_keystr;
829 #endif
830 
831 	/*
832 	 * If the key didn't match, add it to the list of dynamically
833 	 * created ones. Sometimes, drivers refer to registry keys
834 	 * that aren't documented in their .INF files. These keys
835 	 * are supposed to be created by some sort of utility or
836 	 * control panel snap-in that comes with the driver software.
837 	 * Sometimes it's useful to be able to manipulate these.
838 	 * If the driver requests the key in the form of a string,
839 	 * make its default value an empty string, otherwise default
840 	 * it to "0".
841 	 */
842 	if (type == ndis_parm_int || type == ndis_parm_hexint)
843 		ndis_add_sysctl(sc, keystr, "(dynamic integer key)",
844 		    "UNSET", CTLFLAG_RW);
845 	else
846 		ndis_add_sysctl(sc, keystr, "(dynamic string key)",
847 		    "UNSET", CTLFLAG_RW);
848 
849 	free(keystr, M_DEVBUF);
850 	*status = NDIS_STATUS_FAILURE;
851 	return;
852 }
853 
854 #ifdef __FreeBSD__
855 static ndis_status
856 ndis_decode_parm(ndis_miniport_block *block, ndis_config_parm *parm, char *val,
857     size_t len)
858 {
859 	ndis_unicode_string	*ustr;
860 	char			*astr = NULL;
861 
862 	PN(ndis_decode_parm)
863 
864 	switch(parm->ncp_type) {
865 	case ndis_parm_string:
866 		ustr = &parm->ncp_parmdata.ncp_stringdata;
867 		ndis_unicode_to_ascii(ustr->us_buf, ustr->us_len, &astr);
868 		memcpy( val, astr, 254);
869 		free(astr, M_DEVBUF);
870 		break;
871 	case ndis_parm_int:
872 		snprintf(val, len, "%d", parm->ncp_parmdata.ncp_intdata);
873 		break;
874 	case ndis_parm_hexint:
875 		snprintf(val, len, "%xu", parm->ncp_parmdata.ncp_intdata);
876 		break;
877 	default:
878 		return(NDIS_STATUS_FAILURE);
879 		break;
880 	}
881 	return(NDIS_STATUS_SUCCESS);
882 }
883 #endif
884 
885 __stdcall static void
886 NdisWriteConfiguration(
887 	ndis_status		*status,
888 	ndis_handle		cfg,
889 	ndis_unicode_string	*key,
890 	ndis_config_parm	*parm)
891 {
892 #ifdef __FreeBSD__
893 	char			*keystr = NULL;
894 	ndis_miniport_block	*block;
895 	struct ndis_softc	*sc;
896         struct sysctl_oid	*oidp;
897 	struct sysctl_ctx_entry	*e;
898 	char			val[256];
899 
900 	block = (ndis_miniport_block *)cfg;
901 
902 	PN(NdisWriteConfiguration)
903 
904 #ifdef __FreeBSD__
905 	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
906 #else /* __NetBSD__ */
907 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
908 #endif
909 
910 	ndis_unicode_to_ascii(key->us_buf, key->us_len, &keystr);
911 
912 	/* Decode the parameter into a string. */
913 	memset(val, 0, sizeof(val));
914 	*status = ndis_decode_parm(block, parm, val, sizeof(val));
915 	if (*status != NDIS_STATUS_SUCCESS) {
916 		free(keystr, M_DEVBUF);
917 		return;
918 	}
919 
920 	/* See if the key already exists. */
921 
922 #if __FreeBSD_version < 502113 || !defined(__FreeBSD__)
923 	TAILQ_FOREACH(e, &sc->ndis_ctx, link) {
924 #else
925 	TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) {
926 #endif
927 		oidp = e->entry;
928 		if (ndis_strcasecmp(oidp->oid_name, keystr) == 0) {
929 			/* Found it, set the value. */
930 			strcpy((char *)oidp->oid_arg1, val);
931 			free(keystr, M_DEVBUF);
932 			return;
933 		}
934 	}
935 
936 	/* Not found, add a new key with the specified value. */
937 	ndis_add_sysctl(sc, keystr, "(dynamically set key)",
938 		    val, CTLFLAG_RW);
939 
940 	free(keystr, M_DEVBUF);
941 	*status = NDIS_STATUS_SUCCESS;
942 	return;
943 #else /* __FreeBSD__ */
944 	*status = NDIS_STATUS_SUCCESS;
945 	return;
946 #endif
947 }
948 
949 __stdcall static void
950 NdisCloseConfiguration(ndis_handle cfg)
951 {
952 	return;
953 }
954 
955 /*
956  * Initialize a Windows spinlock.
957  */
958 __stdcall static void
959 NdisAllocateSpinLock(ndis_spin_lock *lock)
960 {
961 	KeInitializeSpinLock(&lock->nsl_spinlock);
962 	lock->nsl_kirql = 0;
963 
964 	return;
965 }
966 
967 /*
968  * Destroy a Windows spinlock. This is a no-op for now. There are two reasons
969  * for this. One is that it's sort of superfluous: we don't have to do anything
970  * special to deallocate the spinlock. The other is that there are some buggy
971  * drivers which call NdisFreeSpinLock() _after_ calling NdisFreeMemory() on
972  * the block of memory in which the spinlock resides. (Yes, ADMtek, I'm
973  * talking to you.)
974  */
975 __stdcall static void
976 NdisFreeSpinLock(ndis_spin_lock *lock)
977 {
978 #ifdef notdef
979 	KeInitializeSpinLock(&lock->nsl_spinlock);
980 	lock->nsl_kirql = 0;
981 #endif
982 	return;
983 }
984 
985 /*
986  * Acquire a spinlock from IRQL <= DISPATCH_LEVEL.
987  */
988 
989 __stdcall static void
990 NdisAcquireSpinLock(ndis_spin_lock *lock)
991 {
992 	KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql);
993 	return;
994 }
995 
996 /*
997  * Release a spinlock from IRQL == DISPATCH_LEVEL.
998  */
999 
1000 __stdcall static void
1001 NdisReleaseSpinLock(ndis_spin_lock *lock)
1002 {
1003 	KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql);
1004 	return;
1005 }
1006 
1007 /*
1008  * Acquire a spinlock when already running at IRQL == DISPATCH_LEVEL.
1009  */
1010 __stdcall static void
1011 NdisDprAcquireSpinLock(ndis_spin_lock *lock)
1012 {
1013 	KeAcquireSpinLockAtDpcLevel(&lock->nsl_spinlock);
1014 	return;
1015 }
1016 
1017 /*
1018  * Release a spinlock without leaving IRQL == DISPATCH_LEVEL.
1019  */
1020 __stdcall static void
1021 NdisDprReleaseSpinLock(ndis_spin_lock *lock)
1022 {
1023 	KeReleaseSpinLockFromDpcLevel(&lock->nsl_spinlock);
1024 	return;
1025 }
1026 
1027 __stdcall static uint32_t
1028 NdisReadPciSlotInformation(
1029 	ndis_handle		adapter,
1030 	uint32_t		slot,
1031 	uint32_t		offset,
1032 	void			*buf,
1033 	uint32_t		len)
1034 {
1035 	ndis_miniport_block	*block;
1036 	int			i;
1037 #ifdef __FreeBSD__
1038      char                    *dest;
1039 #else
1040    pcireg_t    *dest;
1041 #endif
1042 
1043 	/* PN(NdisReadPciSlotInformation) */
1044     struct ndis_softc  *sc;
1045 
1046 	block = (ndis_miniport_block *)adapter;
1047 	dest = buf;
1048 	if (block == NULL)
1049 		return(0);
1050 
1051 #ifdef __FreeBSD__
1052 	device_t dev = (device_t)block->nmb_physdeviceobj->do_devext;
1053     sc = device_get_softc(dev);
1054 #else /* __NetBSD__ */
1055 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
1056 #endif
1057 
1058 	/*
1059 	 * I have a test system consisting of a Sun w2100z
1060 	 * dual 2.4Ghz Opteron machine and an Atheros 802.11a/b/g
1061 	 * "Aries" miniPCI NIC. (The NIC is installed in the
1062 	 * machine using a miniPCI to PCI bus adapter card.)
1063 	 * When running in SMP mode, I found that
1064 	 * performing a large number of consecutive calls to
1065 	 * NdisReadPciSlotInformation() would result in a
1066 	 * sudden system reset (or in some cases a freeze).
1067 	 * My suspicion is that the multiple reads are somehow
1068 	 * triggering a fatal PCI bus error that leads to a
1069 	 * machine check. The 1us delay in the loop below
1070 	 * seems to prevent this problem.
1071 	 */
1072 
1073 #ifdef __FreeBSD__
1074 	for (i = 0; i < len; i++) {
1075 #else /* __NetBSD__ */
1076 	for (i = 0; i < len/4; i += 4) {
1077 #endif
1078 		DELAY(1);
1079 #ifdef __FreeBSD__
1080       dest[i] = pci_read_config(dev, i + offset, 1);
1081 #else
1082       dest[i/4] = pci_conf_read(sc->ndis_res_pc,sc->ndis_res_pctag, (i + offset));
1083 #endif
1084 
1085 	}
1086 
1087 	return(len);
1088 }
1089 
1090 __stdcall static uint32_t
1091 NdisWritePciSlotInformation(
1092 	ndis_handle		adapter,
1093 	uint32_t		slot,
1094 	uint32_t		offset,
1095 	void			*buf,
1096 	uint32_t		len)
1097 {
1098 	ndis_miniport_block	*block;
1099 	int			i;
1100 #ifdef __FreeBSD__
1101     char                    *dest;
1102 #else
1103     pcireg_t    *dest;
1104 #endif
1105 
1106 
1107 	/* PN(NdisWritePciSlotInformation) */
1108 
1109 	block = (ndis_miniport_block *)adapter;
1110 	dest = buf;
1111     struct ndis_softc      *sc;
1112 
1113 
1114 	if (block == NULL)
1115 		return(0);
1116 
1117 #ifdef __FreeBSD__
1118     device_t dev = block->nmb_physdeviceobj->do_devext;
1119     sc = device_get_softc(dev);
1120 #else /* __NetBSD__ */
1121 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
1122 #endif
1123 
1124 #ifdef __FreeBSD__
1125 	for (i = 0; i < len; i++) {
1126 #else /* __NetBSD__ */
1127 	for (i = 0; i < len/4; i++) {
1128 #endif
1129 		DELAY(1);
1130 #ifdef __FreeBSD__
1131         pci_write_config(dev, i + offset, dest[i], 1);
1132 #else
1133         pci_conf_write(sc->ndis_res_pc,sc->ndis_res_pctag,
1134 					   (i + offset), dest[i/4]);
1135 #endif
1136 
1137 	}
1138 
1139 	return(len);
1140 }
1141 
1142 /*
1143  * The errorlog routine uses a variable argument list, so we
1144  * have to declare it this way.
1145  */
1146 #define ERRMSGLEN 512
1147 static void
1148 NdisWriteErrorLogEntry(ndis_handle adapter, ndis_error_code code,
1149 	uint32_t numerrors, ...)
1150 {
1151 	ndis_miniport_block	*block;
1152 	va_list			ap;
1153 	int			i, error;
1154 	char			*str = NULL, *ustr = NULL;
1155 	uint16_t		flags;
1156 	char			msgbuf[ERRMSGLEN];
1157 	device_t		dev;
1158 	driver_object		*drv;
1159 
1160 	PN(NdisWriteErrorLogEntry)
1161 
1162 	block = (ndis_miniport_block *)adapter;
1163 	dev = block->nmb_physdeviceobj->do_devext;
1164 	drv = block->nmb_physdeviceobj->do_drvobj;
1165 
1166 	error = pe_get_message((vm_offset_t)drv->dro_driverstart,
1167 	    code, &str, &i, &flags);
1168 	if (error == 0 && flags & MESSAGE_RESOURCE_UNICODE) {
1169 		ustr = msgbuf;
1170 		ndis_unicode_to_ascii((uint16_t *)str,
1171 		    ((i / 2)) > (ERRMSGLEN - 1) ? ERRMSGLEN : i, &ustr);
1172 		str = ustr;
1173 	}
1174 
1175 	printf ("%s: NDIS ERROR: %x (%s)\n", device_xname(dev), code,
1176 		str == NULL ? "unknown error" : str);
1177 	printf ("%s: NDIS NUMERRORS: %x\n",  device_xname(dev), numerrors);
1178 
1179 	va_start(ap, numerrors);
1180 	for (i = 0; i < numerrors; i++)
1181 		printf ("%s: argptr: %p\n",
1182 			device_xname(dev),
1183 			va_arg(ap, void *));
1184 
1185 	va_end(ap);
1186 
1187 	return;
1188 }
1189 
1190 static void
1191 ndis_map_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1192 {
1193 	struct ndis_map_arg	*ctx;
1194 	int			i;
1195 
1196 	PN(ndis_map_cb)
1197 
1198 	if (error)
1199 		return;
1200 
1201 	ctx = arg;
1202 
1203 	for (i = 0; i < nseg; i++) {
1204 		ctx->nma_fraglist[i].npu_physaddr.np_quad = segs[i].ds_addr;
1205 		ctx->nma_fraglist[i].npu_len = segs[i].ds_len;
1206 	}
1207 
1208 	ctx->nma_cnt = nseg;
1209 
1210 	return;
1211 }
1212 
1213 __stdcall static void
1214 NdisMStartBufferPhysicalMapping(ndis_handle adapter, ndis_buffer *buf, uint32_t mapreg, uint8_t writedev, ndis_paddr_unit *addrarray, uint32_t *arraysize)
1215 {
1216 	ndis_miniport_block	*block;
1217 	struct ndis_softc	*sc;
1218 	struct ndis_map_arg	nma;
1219 	bus_dmamap_t		map;
1220 	int			error;
1221 
1222 	PN(NdisMStartBufferPhysicalMapping)
1223 
1224 	if (adapter == NULL)
1225 		return;
1226 
1227 	block = (ndis_miniport_block *)adapter;
1228 #ifdef __FreeBSD__
1229 	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1230 #else /* __NetBSD__ */
1231 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
1232 #endif
1233 
1234 	if (mapreg > sc->ndis_mmapcnt)
1235 		return;
1236 
1237 	map = sc->ndis_mmaps[mapreg];
1238 	nma.nma_fraglist = addrarray;
1239 
1240 #ifdef __FreeBSD__
1241 	error = bus_dmamap_load(sc->ndis_mtag, map,
1242 	    MmGetMdlVirtualAddress(buf), MmGetMdlByteCount(buf), ndis_map_cb,
1243 	    (void *)&nma, BUS_DMA_NOWAIT);
1244 #else
1245 	error = bus_dmamap_load(sc->ndis_mtag, map,
1246 	    MmGetMdlVirtualAddress(buf), MmGetMdlByteCount(buf),
1247 				NULL /* kernel space */, BUS_DMA_NOWAIT);
1248 	/* callback function called "by hand" */
1249 	ndis_map_cb((void *)&nma, map->dm_segs, map->dm_nsegs, error);
1250 #endif
1251 	if (error)
1252 		return;
1253 
1254 #ifdef __FreeBSD__
1255 	bus_dmamap_sync(sc->ndis_mtag, map,
1256 	    writedev ? BUS_DMASYNC_PREWRITE : BUS_DMASYNC_PREREAD);
1257 #else
1258 	bus_dmamap_sync(sc->ndis_mtag, map, 0, map->dm_mapsize,
1259 		writedev ? BUS_DMASYNC_PREWRITE : BUS_DMASYNC_PREREAD);
1260 #endif
1261 	*arraysize = nma.nma_cnt;
1262 
1263 	return;
1264 }
1265 
1266 __stdcall static void
1267 NdisMCompleteBufferPhysicalMapping(
1268 	ndis_handle		adapter,
1269 	ndis_buffer		*buf,
1270 	uint32_t		mapreg)
1271 {
1272 	ndis_miniport_block	*block;
1273 	struct ndis_softc	*sc;
1274 	bus_dmamap_t		map;
1275 
1276 	PN(NdisMCompleteBufferPhysicalMapping)
1277 
1278 	if (adapter == NULL)
1279 		return;
1280 
1281 	block = (ndis_miniport_block *)adapter;
1282 #ifdef __FreeBSD__
1283 	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1284 #else /* __NetBSD__ */
1285 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
1286 #endif
1287 
1288 	if (mapreg > sc->ndis_mmapcnt)
1289 		return;
1290 
1291 	map = sc->ndis_mmaps[mapreg];
1292 
1293 #ifdef __FreeBSD__
1294 	bus_dmamap_sync(sc->ndis_mtag, map,
1295 	    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
1296 #else
1297 	bus_dmamap_sync(sc->ndis_mtag, map, 0, map->dm_mapsize,
1298 	    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
1299 #endif
1300 	bus_dmamap_unload(sc->ndis_mtag, map);
1301 
1302 	return;
1303 }
1304 
1305 /*
1306  * This is an older (?) timer init routine which doesn't
1307  * accept a miniport context handle. Serialized miniports should
1308  * never call this function.
1309  */
1310 
1311 __stdcall static void
1312 NdisInitializeTimer(ndis_timer *timer, ndis_timer_function func, void *ctx)
1313 {
1314 	KeInitializeTimer(&timer->nt_ktimer);
1315 	KeInitializeDpc(&timer->nt_kdpc, func, ctx);
1316 
1317 	return;
1318 }
1319 
1320 __stdcall static void
1321 ndis_timercall(kdpc *dpc, ndis_miniport_timer *timer, void *sysarg1, void *sysarg2)
1322 {
1323 	//PN(ndis_timercall)
1324 
1325 	/*
1326 	 * Since we're called as a DPC, we should be running
1327 	 * at DISPATCH_LEVEL here. This means to acquire the
1328 	 * spinlock, we can use KeAcquireSpinLockAtDpcLevel()
1329 	 * rather than KeAcquireSpinLock().
1330 	 */
1331 	if (NDIS_SERIALIZED(timer->nmt_block))
1332 		KeAcquireSpinLockAtDpcLevel(&timer->nmt_block->nmb_lock);
1333 
1334 	MSCALL4(timer->nmt_timerfunc, dpc, timer->nmt_timerctx,
1335 	    sysarg1, sysarg2);
1336 
1337 	if (NDIS_SERIALIZED(timer->nmt_block))
1338 		KeReleaseSpinLockFromDpcLevel(&timer->nmt_block->nmb_lock);
1339 
1340 	return;
1341 }
1342 
1343 /*
1344  * For a long time I wondered why there were two NDIS timer initialization
1345  * routines, and why this one needed an NDIS_MINIPORT_TIMER and the
1346  * MiniportAdapterHandle. The NDIS_MINIPORT_TIMER has its own callout
1347  * function and context pointers separate from those in the DPC, which
1348  * allows for another level of indirection: when the timer fires, we
1349  * can have our own timer function invoked, and from there we can call
1350  * the driver's function. But why go to all that trouble? Then it hit
1351  * me: for serialized miniports, the timer callouts are not re-entrant.
1352  * By trapping the callouts and having access to the MiniportAdapterHandle,
1353  * we can protect the driver callouts by acquiring the NDIS serialization
1354  * lock. This is essential for allowing serialized miniports to work
1355  * correctly on SMP systems. On UP hosts, setting IRQL to DISPATCH_LEVEL
1356  * is enough to prevent other threads from pre-empting you, but with
1357  * SMP, you must acquire a lock as well, otherwise the other CPU is
1358  * free to clobber you.
1359  */
1360 
1361  /* Just to test out how much memory is wasted*/
1362  int ndis_num_timers_allocated = 0;
1363 
1364 __stdcall static void
1365 NdisMInitializeTimer(ndis_miniport_timer *timer, ndis_handle handle, ndis_timer_function func, void *ctx)
1366 {
1367 	/* Save the driver's funcptr and context */
1368 
1369 	PN(NdisMInitializeTimer)
1370 
1371 	timer->nmt_timerfunc = func;
1372 	timer->nmt_timerctx = ctx;
1373 	timer->nmt_block = handle;
1374 
1375 #ifdef __NetBSD__
1376 /* TODO: free this memory somewhere! */
1377 	printf("Allocating callout struct\n");
1378 	if(timer->nmt_ktimer.k_handle == NULL) {
1379 		timer->nmt_ktimer.k_handle =
1380 				malloc(sizeof(struct callout), M_DEVBUF, M_NOWAIT|M_ZERO);
1381 		ndis_num_timers_allocated++;
1382 	}
1383 #endif
1384 
1385 	/*
1386 	 * Set up the timer so it will call our intermediate DPC.
1387 	 * Be sure to use the wrapped entry point, since
1388 	 * ntoskrnl_run_dpc() expects to invoke a function with
1389 	 * Microsoft calling conventions.
1390 	 */
1391 	KeInitializeTimer(&timer->nmt_ktimer);
1392 	KeInitializeDpc(&timer->nmt_kdpc,
1393 	    ndis_findwrap((funcptr)ndis_timercall), timer);
1394 
1395 	return;
1396 }
1397 
1398 /*
1399  * In Windows, there's both an NdisMSetTimer() and an NdisSetTimer(),
1400  * but the former is just a macro wrapper around the latter.
1401  */
1402 __stdcall static void
1403 NdisSetTimer(ndis_timer *timer, uint32_t msecs)
1404 {
1405 	PN(NdisSetTimer)
1406 	/*
1407 	 * KeSetTimer() wants the period in
1408 	 * hundred nanosecond intervals.
1409 	 */
1410 	KeSetTimer(&timer->nt_ktimer,
1411 	    ((int64_t)msecs * -10000), &timer->nt_kdpc);
1412 
1413 	return;
1414 }
1415 
1416 __stdcall static void
1417 NdisMSetPeriodicTimer(ndis_miniport_timer *timer, uint32_t msecs)
1418 {
1419 	PN(NdisMSetPeriodicTimer)
1420 
1421 	KeSetTimerEx(&timer->nmt_ktimer,
1422 	    ((int64_t)msecs * -10000), msecs, &timer->nmt_kdpc);
1423 
1424 	return;
1425 }
1426 
1427 /*
1428  * Technically, this is really NdisCancelTimer(), but we also
1429  * (ab)use it for NdisMCancelTimer(), since in our implementation
1430  * we don't need the extra info in the ndis_miniport_timer
1431  * structure just to cancel a timer.
1432  */
1433 
1434 __stdcall static void
1435 NdisMCancelTimer(ndis_timer *timer, uint8_t *cancelled)
1436 {
1437 	PN(NdisMCancelTimer)
1438 	*cancelled = KeCancelTimer(&timer->nt_ktimer);
1439 
1440 	return;
1441 }
1442 
1443 __stdcall static void
1444 NdisMQueryAdapterResources(ndis_status *status, ndis_handle adapter, ndis_resource_list *list, uint32_t *buflen)
1445 {
1446 	ndis_miniport_block	*block;
1447 	struct ndis_softc	*sc;
1448 	int			rsclen;
1449 
1450 	PN(NdisMQueryAdapterResources)
1451 
1452 	block = (ndis_miniport_block *)adapter;
1453 
1454 #ifdef __FreeBSD__
1455 	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1456 #else /* __NetBSD__ */
1457 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
1458 #endif
1459 
1460 	rsclen = sizeof(ndis_resource_list) +
1461 	    (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1));
1462 	if (*buflen < rsclen) {
1463 		*buflen = rsclen;
1464 		*status = NDIS_STATUS_INVALID_LENGTH;
1465 		return;
1466 	}
1467 
1468 #ifdef __FreeBSD__
1469 	memcpy( (char *)list, (char *)block->nmb_rlist, rsclen);
1470 #else /* __NetBSD__ */
1471 	memcpy(list, block->nmb_rlist, rsclen);
1472 #endif
1473 
1474 	*status = NDIS_STATUS_SUCCESS;
1475 
1476 	return;
1477 }
1478 
1479 __stdcall static ndis_status
1480 NdisMRegisterIoPortRange(
1481 	void			**offset,
1482 	ndis_handle		adapter,
1483 	uint32_t		port,
1484 	uint32_t		numports)
1485 {
1486 	struct ndis_miniport_block	*block;
1487 	struct ndis_softc	*sc;
1488 
1489 	PN(NdisMRegisterIoPortRange)
1490 
1491 	if (adapter == NULL)
1492 		return(NDIS_STATUS_FAILURE);
1493 
1494 	block = (ndis_miniport_block *)adapter;
1495 #ifdef __FreeBSD__
1496 	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1497 #else /* __NetBSD__ */
1498 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
1499 #endif
1500 
1501 #ifdef __FreeBSD__
1502 	if (sc->ndis_res_io == NULL)
1503 #else
1504     if (sc->ndis_res_io == NULL && sc->ndis_iftype != PCMCIABus)
1505 #endif
1506 		return(NDIS_STATUS_FAILURE);
1507 
1508 	/* Don't let the device map more ports than we have. */
1509 #ifdef __FreeBSD__
1510 	if (rman_get_size(sc->ndis_res_io) < numports)
1511 #else /* __NetBSD__ */
1512     if ( (sc->ndis_iftype != PCMCIABus && sc->ndis_res_io->res_size < numports)
1513             || (sc->ndis_iftype == PCMCIABus && sc->ndis_res_pcioh.size < numports) )
1514 #endif
1515 		return(NDIS_STATUS_INVALID_LENGTH);
1516 
1517 #ifdef __FreeBSD__
1518         *offset = (void *)rman_get_start(sc->ndis_res_io);
1519 #else /* __NetBSD__ */
1520     switch (sc->ndis_iftype){
1521         case PCIBus:
1522         case CBus:	/* CardBus */
1523             *offset = (void*)(u_long)sc->ndis_res_io->res_base;
1524             break;
1525         case PCMCIABus:
1526             *offset = (void*)(u_long)sc->ndis_res_pcioh.addr;
1527             break;
1528         default:
1529             return(NDIS_STATUS_FAILURE);
1530    }
1531 #endif /* __NetBSD__ */
1532 
1533 	return(NDIS_STATUS_SUCCESS);
1534 }
1535 
1536 __stdcall static void
1537 NdisMDeregisterIoPortRange(
1538 	ndis_handle		adapter,
1539 	uint32_t		port,
1540 	uint32_t		numports,
1541 	void			*offset)
1542 {
1543 	return;
1544 }
1545 
1546 __stdcall static void
1547 NdisReadNetworkAddress(ndis_status *status, void **addr, uint32_t *addrlen, ndis_handle adapter)
1548 {
1549 	struct ndis_softc	*sc;
1550 	ndis_miniport_block	*block;
1551 	uint8_t			empty[] = { 0, 0, 0, 0, 0, 0 };
1552 
1553 	PN(NdisReadNetworkAddress)
1554 
1555 	block = (ndis_miniport_block *)adapter;
1556 #ifdef __FreeBSD__
1557 	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1558 #else /* __NetBSD__ */
1559 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
1560 #endif
1561 
1562 #ifdef __FreeBSD__
1563 	if (memcmp(sc->arpcom.ac_enaddr, empty, ETHER_ADDR_LEN) == 0)
1564 #else
1565 	if (memcmp(CLLADDR(sc->arpcom.ec_if.if_sadl),
1566 		 empty, ETHER_ADDR_LEN) == 0)
1567 #endif
1568 
1569 		*status = NDIS_STATUS_FAILURE;
1570 	else {
1571 #ifdef __FreeBSD__
1572 		*addr = sc->arpcom.ac_enaddr;
1573 #else
1574 		memcpy(sc->ndis_mac, CLLADDR(sc->arpcom.ec_if.if_sadl),
1575 		    ETHER_ADDR_LEN);
1576                 *addr = sc->ndis_mac;
1577 #endif
1578 		*addrlen = ETHER_ADDR_LEN;
1579 		*status = NDIS_STATUS_SUCCESS;
1580 	}
1581 
1582 	return;
1583 }
1584 
1585 __stdcall static ndis_status
1586 NdisQueryMapRegisterCount(
1587 	uint32_t		bustype,
1588 	uint32_t		*cnt)
1589 {
1590 	PN(NdisQueryMapRegisterCount)
1591 
1592 	*cnt = 8192;
1593 	return(NDIS_STATUS_SUCCESS);
1594 }
1595 
1596 __stdcall static ndis_status
1597 NdisMAllocateMapRegisters(
1598 	ndis_handle		adapter,
1599 	uint32_t		dmachannel,
1600 	uint8_t			dmasize,
1601 	uint32_t		physmapneeded,
1602 	uint32_t		maxmap)
1603 {
1604 	struct ndis_softc	*sc;
1605 	ndis_miniport_block	*block;
1606 #ifdef __FreeBSD__
1607 	int error;
1608 #endif
1609 	int			i, nseg = NDIS_MAXSEG;
1610 
1611 	PN(NdisMAllocateMapRegisters)
1612 
1613 	block = (ndis_miniport_block *)adapter;
1614 #ifdef __FreeBSD__
1615 	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1616 #else /* __NetBSD__ */
1617 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
1618 #endif
1619 
1620 	sc->ndis_mmaps = malloc(sizeof(bus_dmamap_t) * physmapneeded,
1621 	    M_DEVBUF, M_NOWAIT|M_ZERO);
1622 
1623 	if (sc->ndis_mmaps == NULL)
1624 		return(NDIS_STATUS_RESOURCES);
1625 
1626 #ifdef __FreeBSD__
1627 	error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0,
1628 	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL,
1629 	    NULL, maxmap * nseg, nseg, maxmap, BUS_DMA_ALLOCNOW,
1630 	    NULL, NULL, &sc->ndis_mtag);
1631 
1632 	if (error) {
1633 		free(sc->ndis_mmaps, M_DEVBUF);
1634 		return(NDIS_STATUS_RESOURCES);
1635 	}
1636 #else
1637 	sc->ndis_mtag = sc->ndis_parent_tag;
1638 #endif
1639 
1640 	for (i = 0; i < physmapneeded; i++) {
1641 #ifdef __FreeBSD__
1642 		bus_dmamap_create(sc->ndis_mtag, 0, &sc->ndis_mmaps[i]);
1643 #else
1644 		bus_dmamap_create(sc->ndis_mtag, maxmap * nseg,
1645 				  nseg, maxmap, BUS_DMA_NOWAIT,
1646 				  0, &sc->ndis_mmaps[i]);
1647 #endif
1648 	}
1649 
1650 	sc->ndis_mmapcnt = physmapneeded;
1651 
1652 	return(NDIS_STATUS_SUCCESS);
1653 }
1654 
1655 __stdcall static void
1656 NdisMFreeMapRegisters(ndis_handle adapter)
1657 {
1658 	struct ndis_softc	*sc;
1659 	ndis_miniport_block	*block;
1660 	int			i;
1661 
1662 	PN(NdisMFreeMapRegisters)
1663 
1664 	block = (ndis_miniport_block *)adapter;
1665 #ifdef __FreeBSD__
1666 	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1667 #else /* __NetBSD__ */
1668 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
1669 #endif
1670 
1671 	for (i = 0; i < sc->ndis_mmapcnt; i++)
1672 		bus_dmamap_destroy(sc->ndis_mtag, sc->ndis_mmaps[i]);
1673 
1674 	free(sc->ndis_mmaps, M_DEVBUF);
1675 
1676 #ifdef __FreeBSD__
1677 	bus_dma_tag_destroy(sc->ndis_mtag);
1678 #endif
1679 
1680 	return;
1681 }
1682 
1683 static void
1684 ndis_mapshared_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1685 {
1686 	ndis_physaddr		*p;
1687 
1688 	/* PN(ndis_mapshared_cb) */
1689 
1690 	if (error || nseg > 1)
1691 		return;
1692 
1693 	p = arg;
1694 
1695 	p->np_quad = segs[0].ds_addr;
1696 
1697 	return;
1698 }
1699 
1700 /*
1701  * This maps to bus_dmamem_alloc().
1702  */
1703 __stdcall static void
1704 NdisMAllocateSharedMemory(
1705 	ndis_handle		adapter,
1706 	uint32_t		len,
1707 	uint8_t			cached,
1708 	void			**vaddr,
1709 	ndis_physaddr		*paddr)
1710 {
1711 	ndis_miniport_block	*block;
1712 	struct ndis_softc	*sc;
1713 	struct ndis_shmem	*sh;
1714 	int			error;
1715 #ifdef __NetBSD__
1716 	bus_dma_segment_t	segs;
1717 	int					nsegs;
1718 #endif
1719 
1720 	/* PN(NdisMAllocateSharedMemory) */
1721 
1722 	if (adapter == NULL)
1723 		return;
1724 
1725 	block = (ndis_miniport_block *)adapter;
1726 #ifdef __FreeBSD__
1727 	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1728 #else /* __NetBSD__ */
1729 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
1730 #endif
1731 
1732 	sh = malloc(sizeof(struct ndis_shmem), M_DEVBUF, M_NOWAIT|M_ZERO);
1733 	if (sh == NULL)
1734 		return;
1735 
1736 	/*
1737 	 * When performing shared memory allocations, create a tag
1738 	 * with a lowaddr limit that restricts physical memory mappings
1739 	 * so that they all fall within the first 1GB of memory.
1740 	 * At least one device/driver combination (Linksys Instant
1741 	 * Wireless PCI Card V2.7, Broadcom 802.11b) seems to have
1742 	 * problems with performing DMA operations with physical
1743 	 * addresses that lie above the 1GB mark. I don't know if this
1744 	 * is a hardware limitation or if the addresses are being
1745 	 * truncated within the driver, but this seems to be the only
1746 	 * way to make these cards work reliably in systems with more
1747 	 * than 1GB of physical memory.
1748 	 */
1749 
1750 #ifdef __FreeBSD__
1751 	error = bus_dma_tag_create(sc->ndis_parent_tag, 64,
1752 	    0, NDIS_BUS_SPACE_SHARED_MAXADDR, BUS_SPACE_MAXADDR, NULL,
1753 	    NULL, len, 1, len, BUS_DMA_ALLOCNOW, NULL, NULL,
1754 	    &sh->ndis_stag);
1755 
1756 	if (error) {
1757 		free(sh, M_DEVBUF);
1758 		return;
1759 	}
1760 
1761 	error = bus_dmamem_alloc(sh->ndis_stag, vaddr,
1762 	    BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sh->ndis_smap);
1763 
1764 	if (error) {
1765 		bus_dma_tag_destroy(sh->ndis_stag);
1766 		free(sh, M_DEVBUF);
1767 		return;
1768 	}
1769 
1770 	error = bus_dmamap_load(sh->ndis_stag, sh->ndis_smap, *vaddr,
1771 	    len, ndis_mapshared_cb, (void *)paddr, BUS_DMA_NOWAIT);
1772 
1773 	if (error) {
1774 		bus_dmamem_free(sh->ndis_stag, *vaddr, sh->ndis_smap);
1775 		bus_dma_tag_destroy(sh->ndis_stag);
1776 		free(sh, M_DEVBUF);
1777 		return;
1778 	}
1779 #else
1780 	sh->ndis_stag = sc->ndis_parent_tag;
1781 
1782 	error = bus_dmamem_alloc(sh->ndis_stag, len, 64, 0,
1783 				 &segs, 1, &nsegs, BUS_DMA_NOWAIT);
1784 
1785 	if (error) {
1786 		printf("bus_dmamem_alloc failed(1)\n");
1787 		return;
1788 	}
1789 
1790 	error = bus_dmamem_map(sh->ndis_stag, &segs, nsegs,
1791 				len, /*(void **)&vaddr*/ (void **)vaddr, BUS_DMA_NOWAIT);
1792 
1793 	/* printf("*vaddr = %x\n", (unsigned int)*vaddr); */
1794 
1795 	if (error) {
1796 		printf("bus_dmamem_alloc failed(2)\n");
1797 		/* XXX free */
1798 		return;
1799 	}
1800 
1801 	error = bus_dmamap_create(sh->ndis_stag, len, nsegs,
1802 				  BUS_SPACE_MAXSIZE_32BIT, 0,
1803 				  BUS_DMA_ALLOCNOW, &sh->ndis_smap);
1804 
1805 	if (error) {
1806 		printf("bus_dmamem_alloc failed(3)\n");
1807 		/* XXX free, unmap */
1808 		return;
1809 	}
1810 
1811 	error = bus_dmamap_load(sh->ndis_stag, sh->ndis_smap, /*vaddr*/ *vaddr,
1812 				len, NULL, BUS_DMA_NOWAIT);
1813 	ndis_mapshared_cb((void *)paddr,
1814 			  sh->ndis_smap->dm_segs,
1815 			  sh->ndis_smap->dm_nsegs, error);
1816 
1817 	if (error) {
1818 		printf("bus_dmamem_alloc failed(3)\n");
1819 		/* XXX free, unmap, destroy */
1820 		return;
1821 	}
1822 #endif
1823 
1824 	sh->ndis_saddr = *vaddr;
1825 	sh->ndis_next = sc->ndis_shlist;
1826 	sc->ndis_shlist = sh;
1827 
1828 	return;
1829 }
1830 
1831 struct ndis_allocwork {
1832 	ndis_handle		na_adapter;
1833 	uint32_t		na_len;
1834 	uint8_t			na_cached;
1835 	void			*na_ctx;
1836 };
1837 
1838 static void
1839 ndis_asyncmem_complete(void *arg)
1840 {
1841 	ndis_miniport_block	*block;
1842 	struct ndis_softc	*sc;
1843 	struct ndis_allocwork	*w;
1844 	void			*vaddr;
1845 	ndis_physaddr		paddr;
1846 	__stdcall ndis_allocdone_handler	donefunc;
1847 
1848 	w = arg;
1849 	block = (ndis_miniport_block *)w->na_adapter;
1850 #ifdef __FreeBSD__
1851 	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1852 #else /* __NetBSD__ */
1853 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
1854 #endif
1855 
1856 	PN(ndis_asyncmem_complete)
1857 
1858 	vaddr = NULL;
1859 	paddr.np_quad = 0;
1860 
1861 	donefunc = sc->ndis_chars->nmc_allocate_complete_func;
1862 	NdisMAllocateSharedMemory(w->na_adapter, w->na_len,
1863 	    w->na_cached, &vaddr, &paddr);
1864 	MSCALL5(donefunc, w->na_adapter, vaddr, &paddr, w->na_len, w->na_ctx);
1865 
1866 	free(arg, M_DEVBUF);
1867 
1868 	return;
1869 }
1870 
1871 __stdcall static ndis_status
1872 NdisMAllocateSharedMemoryAsync(ndis_handle adapter, uint32_t len, uint8_t cached, void *ctx)
1873 {
1874 	struct ndis_allocwork	*w;
1875 
1876 	PN(NdisMAllocateSharedMemoryAsync)
1877 
1878 	if (adapter == NULL)
1879 		return(NDIS_STATUS_FAILURE);
1880 
1881 	w = malloc(sizeof(struct ndis_allocwork), M_TEMP, M_NOWAIT);
1882 
1883 	if (w == NULL)
1884 		return(NDIS_STATUS_FAILURE);
1885 
1886 	w->na_adapter = adapter;
1887 	w->na_cached = cached;
1888 	w->na_len = len;
1889 	w->na_ctx = ctx;
1890 
1891 	/*
1892 	 * Pawn this work off on the SWI thread instead of the
1893 	 * taskqueue thread, because sometimes drivers will queue
1894 	 * up work items on the taskqueue thread that will block,
1895 	 * which would prevent the memory allocation from completing
1896 	 * when we need it.
1897 	 */
1898 	ndis_sched(ndis_asyncmem_complete, w, NDIS_SWI);
1899 
1900 	return(NDIS_STATUS_PENDING);
1901 }
1902 
1903 __stdcall static void
1904 NdisMFreeSharedMemory(
1905 	ndis_handle		adapter,
1906 	uint32_t		len,
1907 	uint8_t			cached,
1908 	void			*vaddr,
1909 	ndis_physaddr		paddr)
1910 {
1911 	ndis_miniport_block	*block;
1912 	struct ndis_softc	*sc;
1913 	struct ndis_shmem	*sh, *prev;
1914 
1915 	PN(NdisMFreeSharedMemory)
1916 
1917 	if (vaddr == NULL || adapter == NULL)
1918 		return;
1919 
1920 	block = (ndis_miniport_block *)adapter;
1921 #ifdef __FreeBSD__
1922 	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1923 #else /* __NetBSD__ */
1924 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
1925 #endif
1926 	sh = prev = sc->ndis_shlist;
1927 
1928 	/* Sanity check: is list empty? */
1929 
1930 	if (sh == NULL)
1931 		return;
1932 
1933 	while (sh) {
1934 		if (sh->ndis_saddr == vaddr)
1935 			break;
1936 		prev = sh;
1937 		sh = sh->ndis_next;
1938 	}
1939 
1940 	bus_dmamap_unload(sh->ndis_stag, sh->ndis_smap);
1941 #ifdef __FreeBSD__
1942 	bus_dmamem_free(sh->ndis_stag, vaddr, sh->ndis_smap);
1943 	bus_dma_tag_destroy(sh->ndis_stag);
1944 #else
1945 	bus_dmamem_unmap(sh->ndis_stag, vaddr, sh->ndis_smap->dm_mapsize);
1946 	bus_dmamem_free(sh->ndis_stag,
1947 			sh->ndis_smap->dm_segs, sh->ndis_smap->dm_nsegs );
1948 #endif
1949 	if (sh == sc->ndis_shlist)
1950 		sc->ndis_shlist = sh->ndis_next;
1951 	else
1952 		prev->ndis_next = sh->ndis_next;
1953 
1954 	free(sh, M_DEVBUF);
1955 
1956 	return;
1957 }
1958 
1959 __stdcall static ndis_status
1960 NdisMMapIoSpace(
1961 	void			**vaddr,
1962 	ndis_handle		adapter,
1963 	ndis_physaddr		paddr,
1964 	uint32_t		len)
1965 {
1966 	ndis_miniport_block	*block;
1967 	struct ndis_softc	*sc;
1968 
1969 	PN(NdisMMapIoSpace)
1970 
1971 	if (adapter == NULL)
1972 		return(NDIS_STATUS_FAILURE);
1973 
1974 	block = (ndis_miniport_block *)adapter;
1975 #ifdef __FreeBSD__
1976 	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1977 #else /* __NetBSD__ */
1978 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
1979 #endif
1980 
1981 
1982 #ifdef __FreeBSD__
1983 	if (sc->ndis_res_mem != NULL &&
1984 	    paddr.np_quad == rman_get_start(sc->ndis_res_mem))
1985 		*vaddr = (void *)rman_get_virtual(sc->ndis_res_mem);
1986 	else if (sc->ndis_res_altmem != NULL &&
1987 	     paddr.np_quad == rman_get_start(sc->ndis_res_altmem))
1988 		*vaddr = (void *)rman_get_virtual(sc->ndis_res_altmem);
1989 	else if (sc->ndis_res_am != NULL &&
1990 	     paddr.np_quad == rman_get_start(sc->ndis_res_am))
1991 		*vaddr = (void *)rman_get_virtual(sc->ndis_res_am);
1992 	else
1993 		return(NDIS_STATUS_FAILURE);
1994 #else
1995 /* TODO: add one for sc->ndis_res_am once PCMCIA is going */
1996 	if (sc->ndis_res_mem != NULL &&
1997 	    paddr.np_quad == sc->ndis_res_mem->res_base)
1998 		*vaddr = bus_space_vaddr(sc->ndis_res_mem->res_tag,
1999 					sc->ndis_res_mem->res_handle);
2000 	else if (sc->ndis_res_altmem != NULL &&
2001 	     paddr.np_quad == sc->ndis_res_altmem->res_base)
2002 		*vaddr = bus_space_vaddr(sc->ndis_res_altmem->res_tag,
2003 					sc->ndis_res_altmem->res_handle);
2004 	else
2005 		return(NDIS_STATUS_FAILURE);
2006 /*
2007 	*vaddr = bus_space_vaddr(sc->ndis_res_mem->res_tag,
2008 				sc->ndis_res_mem->res_handle);
2009 */
2010 #endif
2011 
2012 	return(NDIS_STATUS_SUCCESS);
2013 }
2014 
2015 __stdcall static void
2016 NdisMUnmapIoSpace(
2017 	ndis_handle		adapter,
2018 	void			*vaddr,
2019 	uint32_t		len)
2020 {
2021 	return;
2022 }
2023 
2024 __stdcall static uint32_t
2025 NdisGetCacheFillSize(void)
2026 {
2027 	return(128);
2028 }
2029 
2030 __stdcall static uint32_t
2031 NdisMGetDmaAlignment(ndis_handle handle)
2032 {
2033 	return(128);
2034 }
2035 
2036 /*
2037  * NDIS has two methods for dealing with NICs that support DMA.
2038  * One is to just pass packets to the driver and let it call
2039  * NdisMStartBufferPhysicalMapping() to map each buffer in the packet
2040  * all by itself, and the other is to let the NDIS library handle the
2041  * buffer mapping internally, and hand the driver an already populated
2042  * scatter/gather fragment list. If the driver calls
2043  * NdisMInitializeScatterGatherDma(), it wants to use the latter
2044  * method.
2045  */
2046 
2047 __stdcall static ndis_status
2048 NdisMInitializeScatterGatherDma(
2049 	ndis_handle		adapter,
2050 	uint8_t			is64,
2051 	uint32_t		maxphysmap)
2052 {
2053 	struct ndis_softc	*sc;
2054 	ndis_miniport_block	*block;
2055 #ifdef __FreeBSD__
2056 	int			error;
2057 #endif
2058 
2059 	PN(NdisMInitializeScatterGatherDma)
2060 
2061 	if (adapter == NULL)
2062 		return(NDIS_STATUS_FAILURE);
2063 	block = (ndis_miniport_block *)adapter;
2064 #ifdef __FreeBSD__
2065 	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2066 #else /* __NetBSD__ */
2067 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
2068 #endif
2069 
2070 	/* Don't do this twice. */
2071 	if (sc->ndis_sc == 1)
2072 		return(NDIS_STATUS_SUCCESS);
2073 
2074 #ifdef __FreeBSD__
2075 	error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0,
2076 	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
2077 	    MCLBYTES * NDIS_MAXSEG, NDIS_MAXSEG, MCLBYTES, BUS_DMA_ALLOCNOW,
2078 	    NULL, NULL, &sc->ndis_ttag);
2079 #else /* __NetBSD__ */
2080 /* TODO: Is this correct to just use the parent tag? */
2081 	sc->ndis_ttag = sc->ndis_parent_tag;
2082 #endif
2083 
2084 	sc->ndis_sc = 1;
2085 
2086 	return(NDIS_STATUS_SUCCESS);
2087 }
2088 
2089 __stdcall void
2090 NdisAllocatePacketPool(ndis_status *status, ndis_handle *pool, uint32_t descnum, uint32_t protrsvdlen)
2091 {
2092 	ndis_packet		*cur;
2093 	int			i;
2094 
2095 	PN(NdisAllocatePacketPool)
2096 
2097 	*pool = malloc((sizeof(ndis_packet) + protrsvdlen) *
2098 	    ((descnum + NDIS_POOL_EXTRA) + 1),
2099 	    M_DEVBUF, M_NOWAIT|M_ZERO);
2100 
2101 	if (*pool == NULL) {
2102 		*status = NDIS_STATUS_RESOURCES;
2103 		return;
2104 	}
2105 
2106 	cur = (ndis_packet *)*pool;
2107 	KeInitializeSpinLock(&cur->np_lock);
2108 	cur->np_private.npp_flags = 0x1; /* mark the head of the list */
2109 	cur->np_private.npp_totlen = 0; /* init deletetion flag */
2110 	for (i = 0; i < (descnum + NDIS_POOL_EXTRA); i++) {
2111 		cur->np_private.npp_head = (ndis_handle)(cur + 1);
2112 		cur++;
2113 	}
2114 
2115 	*status = NDIS_STATUS_SUCCESS;
2116 	return;
2117 }
2118 
2119 __stdcall void
2120 NdisAllocatePacketPoolEx(ndis_status *status, ndis_handle *pool, uint32_t descnum, uint32_t oflowdescnum, uint32_t protrsvdlen)
2121 {
2122 	return(NdisAllocatePacketPool(status, pool,
2123 	    descnum + oflowdescnum, protrsvdlen));
2124 }
2125 
2126 __stdcall uint32_t
2127 NdisPacketPoolUsage(ndis_handle pool)
2128 {
2129 	ndis_packet		*head;
2130 	uint8_t			irql;
2131 	uint32_t		cnt;
2132 
2133 	head = (ndis_packet *)pool;
2134 	KeAcquireSpinLock(&head->np_lock, &irql);
2135 	cnt = head->np_private.npp_count;
2136 	KeReleaseSpinLock(&head->np_lock, irql);
2137 
2138 	return(cnt);
2139 }
2140 
2141 __stdcall void
2142 NdisFreePacketPool(ndis_handle pool)
2143 {
2144 	ndis_packet		*head;
2145 	uint8_t			irql;
2146 
2147 	head = pool;
2148 
2149 	/* Mark this pool as 'going away.' */
2150 
2151 	KeAcquireSpinLock(&head->np_lock, &irql);
2152 	head->np_private.npp_totlen = 1;
2153 
2154 	/* If there are no buffers loaned out, destroy the pool. */
2155 
2156 	if (head->np_private.npp_count == 0) {
2157 		KeReleaseSpinLock(&head->np_lock, irql);
2158 		free(pool, M_DEVBUF);
2159 	} else {
2160 		printf("NDIS: buggy driver deleting active packet pool!\n");
2161 		KeReleaseSpinLock(&head->np_lock, irql);
2162 	}
2163 
2164 	return;
2165 }
2166 
2167 __stdcall void
2168 NdisAllocatePacket(ndis_status *status, ndis_packet **packet, ndis_handle pool)
2169 {
2170 	ndis_packet		*head, *pkt;
2171 	uint8_t			irql;
2172 
2173 #ifdef __NetBSD__
2174 /*TODO: For some reason NdisAllocatePacket was getting called once with pool being NULL
2175  *TODO: and this was causing a seg-fault.  This seems to solve the problem, but I'm not
2176  *TODO: should happen at all in the first place.
2177  */
2178 	if(pool == NULL) {
2179 		*status = NDIS_STATUS_FAILURE;
2180 		return;
2181 	}
2182 #endif
2183 
2184 	head = (ndis_packet *)pool;
2185 	KeAcquireSpinLock(&head->np_lock, &irql);
2186 
2187 	if (head->np_private.npp_flags != 0x1) {
2188 		*status = NDIS_STATUS_FAILURE;
2189 		KeReleaseSpinLock(&head->np_lock, irql);
2190 		return;
2191 	}
2192 
2193 	/*
2194 	 * If this pool is marked as 'going away' don't allocate any
2195 	 * more packets out of it.
2196 	 */
2197 
2198 	if (head->np_private.npp_totlen) {
2199 		*status = NDIS_STATUS_FAILURE;
2200 		KeReleaseSpinLock(&head->np_lock, irql);
2201 		return;
2202 	}
2203 
2204 	pkt = (ndis_packet *)head->np_private.npp_head;
2205 
2206 	if (pkt == NULL) {
2207 		*status = NDIS_STATUS_RESOURCES;
2208 		KeReleaseSpinLock(&head->np_lock, irql);
2209 		return;
2210 	}
2211 
2212 	head->np_private.npp_head = pkt->np_private.npp_head;
2213 
2214 	pkt->np_private.npp_head = pkt->np_private.npp_tail = NULL;
2215 	/* Save pointer to the pool. */
2216 	pkt->np_private.npp_pool = head;
2217 
2218 	/* Set the oob offset pointer. Lots of things expect this. */
2219 	pkt->np_private.npp_packetooboffset =
2220 	    offsetof(ndis_packet, np_oob);
2221 
2222 	/*
2223 	 * We must initialize the packet flags correctly in order
2224 	 * for the NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO() and
2225 	 * NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO() macros to work
2226          * correctly.
2227 	 */
2228 	pkt->np_private.npp_ndispktflags = NDIS_PACKET_ALLOCATED_BY_NDIS;
2229 	pkt->np_private.npp_validcounts = FALSE;
2230 
2231 	*packet = pkt;
2232 
2233 	head->np_private.npp_count++;
2234 	*status = NDIS_STATUS_SUCCESS;
2235 
2236 	KeReleaseSpinLock(&head->np_lock, irql);
2237 
2238 	return;
2239 }
2240 
2241 __stdcall void
2242 NdisFreePacket(ndis_packet *packet)
2243 {
2244 	ndis_packet		*head;
2245 	uint8_t			irql;
2246 
2247 	if (packet == NULL || packet->np_private.npp_pool == NULL)
2248 		return;
2249 
2250 	head = packet->np_private.npp_pool;
2251 	KeAcquireSpinLock(&head->np_lock, &irql);
2252 
2253 	if (head->np_private.npp_flags != 0x1) {
2254 		KeReleaseSpinLock(&head->np_lock, irql);
2255 		return;
2256 	}
2257 
2258 	packet->np_private.npp_head = head->np_private.npp_head;
2259 	head->np_private.npp_head = (ndis_buffer *)packet;
2260 	head->np_private.npp_count--;
2261 
2262 	/*
2263 	 * If the pool has been marked for deletion and there are
2264 	 * no more packets outstanding, nuke the pool.
2265 	 */
2266 
2267 	if (head->np_private.npp_totlen && head->np_private.npp_count == 0) {
2268 		KeReleaseSpinLock(&head->np_lock, irql);
2269 		free(head, M_DEVBUF);
2270 	} else
2271 		KeReleaseSpinLock(&head->np_lock, irql);
2272 
2273 	return;
2274 }
2275 
2276 __stdcall static void
2277 NdisUnchainBufferAtFront(ndis_packet *packet, ndis_buffer **buf)
2278 {
2279 	ndis_packet_private	*priv;
2280 
2281 	if (packet == NULL || buf == NULL)
2282 		return;
2283 
2284 	priv = &packet->np_private;
2285 
2286 	priv->npp_validcounts = FALSE;
2287 
2288 	if (priv->npp_head == priv->npp_tail) {
2289 		*buf = priv->npp_head;
2290 		priv->npp_head = priv->npp_tail = NULL;
2291 	} else {
2292 		*buf = priv->npp_head;
2293 		priv->npp_head = (*buf)->mdl_next;
2294 	}
2295 
2296 	return;
2297 }
2298 
2299 __stdcall static void
2300 NdisUnchainBufferAtBack(ndis_packet *packet, ndis_buffer **buf)
2301 {
2302 	ndis_packet_private	*priv;
2303 	ndis_buffer		*tmp;
2304 
2305 	if (packet == NULL || buf == NULL)
2306 		return;
2307 
2308 	priv = &packet->np_private;
2309 
2310 	priv->npp_validcounts = FALSE;
2311 
2312 	if (priv->npp_head == priv->npp_tail) {
2313 		*buf = priv->npp_head;
2314 		priv->npp_head = priv->npp_tail = NULL;
2315 	} else {
2316 		*buf = priv->npp_tail;
2317 		tmp = priv->npp_head;
2318 		while (tmp->mdl_next != priv->npp_tail)
2319 			tmp = tmp->mdl_next;
2320 		priv->npp_tail = tmp;
2321 		tmp->mdl_next = NULL;
2322 	}
2323 
2324 	return;
2325 }
2326 
2327 /*
2328  * The NDIS "buffer" is really an MDL (memory descriptor list)
2329  * which is used to describe a buffer in a way that allows it
2330  * to mapped into different contexts. We have to be careful how
2331  * we handle them: in some versions of Windows, the NdisFreeBuffer()
2332  * routine is an actual function in the NDIS API, but in others
2333  * it's just a macro wrapper around IoFreeMdl(). There's really
2334  * no way to use the 'descnum' parameter to count how many
2335  * "buffers" are allocated since in order to use IoFreeMdl() to
2336  * dispose of a buffer, we have to use IoAllocateMdl() to allocate
2337  * them, and IoAllocateMdl() just grabs them out of the heap.
2338  */
2339 
2340 __stdcall static void
2341 NdisAllocateBufferPool(
2342 	ndis_status		*status,
2343 	ndis_handle		*pool,
2344 	uint32_t		descnum)
2345 {
2346 	/*
2347 	 * The only thing we can really do here is verify that descnum
2348 	 * is a reasonable value, but I really don't know what to check
2349 	 * it against.
2350 	 */
2351 
2352 	*pool = NonPagedPool;
2353 	*status = NDIS_STATUS_SUCCESS;
2354 	return;
2355 }
2356 
2357 __stdcall static void
2358 NdisFreeBufferPool(ndis_handle pool)
2359 {
2360 	return;
2361 }
2362 
2363 __stdcall static void
2364 NdisAllocateBuffer(
2365 	ndis_status		*status,
2366 	ndis_buffer		**buffer,
2367 	ndis_handle		pool,
2368 	void			*vaddr,
2369 	uint32_t		len)
2370 {
2371 	ndis_buffer		*buf;
2372 
2373 	buf = IoAllocateMdl(vaddr, len, FALSE, FALSE, NULL);
2374 	if (buf == NULL) {
2375 		*status = NDIS_STATUS_RESOURCES;
2376 		return;
2377 	}
2378 
2379 	*buffer = buf;
2380 	*status = NDIS_STATUS_SUCCESS;
2381 
2382 	return;
2383 }
2384 
2385 __stdcall static void
2386 NdisFreeBuffer(ndis_buffer *buf)
2387 {
2388 	IoFreeMdl(buf);
2389 	return;
2390 }
2391 
2392 /* Aw c'mon. */
2393 
2394 __stdcall static uint32_t
2395 NdisBufferLength(ndis_buffer *buf)
2396 {
2397 	return(MmGetMdlByteCount(buf));
2398 }
2399 
2400 /*
2401  * Get the virtual address and length of a buffer.
2402  * Note: the vaddr argument is optional.
2403  */
2404 
2405 __stdcall static void
2406 NdisQueryBuffer(ndis_buffer *buf, void **vaddr, uint32_t *len)
2407 {
2408 	if (vaddr != NULL)
2409 		*vaddr = MmGetMdlVirtualAddress(buf);
2410 	*len = MmGetMdlByteCount(buf);
2411 
2412 	return;
2413 }
2414 
2415 /* Same as above -- we don't care about the priority. */
2416 
2417 __stdcall static void
2418 NdisQueryBufferSafe(
2419 	ndis_buffer		*buf,
2420 	void			**vaddr,
2421 	uint32_t		*len,
2422 	uint32_t		prio)
2423 {
2424 	if (vaddr != NULL)
2425 		*vaddr = MmGetMdlVirtualAddress(buf);
2426 	*len = MmGetMdlByteCount(buf);
2427 
2428 	return;
2429 }
2430 
2431 /* Damnit Microsoft!! How many ways can you do the same thing?! */
2432 
2433 __stdcall static void *
2434 NdisBufferVirtualAddress(ndis_buffer *buf)
2435 {
2436 	return(MmGetMdlVirtualAddress(buf));
2437 }
2438 
2439 __stdcall static void *
2440 NdisBufferVirtualAddressSafe(
2441 	ndis_buffer		*buf,
2442 	uint32_t		prio)
2443 {
2444 	return(MmGetMdlVirtualAddress(buf));
2445 }
2446 
2447 __stdcall static void
2448 NdisAdjustBufferLength(ndis_buffer *buf, int len)
2449 {
2450 	MmGetMdlByteCount(buf) = len;
2451 
2452 	return;
2453 }
2454 
2455 __stdcall static uint32_t
2456 NdisInterlockedIncrement(uint32_t *addend)
2457 {
2458 	atomic_inc_32(addend);
2459 	return(*addend);
2460 }
2461 
2462 __stdcall static uint32_t
2463 NdisInterlockedDecrement(uint32_t *addend)
2464 {
2465 	atomic_dec_32(addend);
2466 	return(*addend);
2467 }
2468 
2469 __stdcall static void
2470 NdisInitializeEvent(ndis_event *event)
2471 {
2472 	/*
2473 	 * NDIS events are always notification
2474 	 * events, and should be initialized to the
2475 	 * not signaled state.
2476 	 */
2477 
2478 	KeInitializeEvent(&event->ne_event, EVENT_TYPE_NOTIFY, FALSE);
2479 	return;
2480 }
2481 
2482 __stdcall static void
2483 NdisSetEvent(ndis_event *event)
2484 {
2485 	KeSetEvent(&event->ne_event, 0, 0);
2486 	return;
2487 }
2488 
2489 __stdcall static void
2490 NdisResetEvent(ndis_event *event)
2491 {
2492 	KeResetEvent(&event->ne_event);
2493 	return;
2494 }
2495 
2496 __stdcall static uint8_t
2497 NdisWaitEvent(ndis_event *event, uint32_t msecs)
2498 {
2499 	int64_t			duetime;
2500 	uint32_t		rval;
2501 
2502 	duetime = ((int64_t)msecs * -10000);
2503 
2504 	rval = KeWaitForSingleObject((nt_dispatch_header *)event,
2505 	    0, 0, TRUE, msecs ? &duetime : NULL);
2506 
2507 	if (rval == STATUS_TIMEOUT)
2508 		return(FALSE);
2509 
2510 	return(TRUE);
2511 }
2512 
2513 __stdcall static ndis_status
2514 NdisUnicodeStringToAnsiString(ndis_ansi_string *dstr, ndis_unicode_string *sstr)
2515 {
2516 	if (dstr == NULL || sstr == NULL)
2517 		return(NDIS_STATUS_FAILURE);
2518 	if (ndis_unicode_to_ascii(sstr->us_buf,
2519 	    sstr->us_len, &dstr->nas_buf))
2520 		return(NDIS_STATUS_FAILURE);
2521 	dstr->nas_len = dstr->nas_maxlen = strlen(dstr->nas_buf);
2522 	return (NDIS_STATUS_SUCCESS);
2523 }
2524 
2525 __stdcall static ndis_status
2526 NdisAnsiStringToUnicodeString(ndis_unicode_string *dstr, ndis_ansi_string *sstr)
2527 {
2528 	char			*str;
2529 	if (dstr == NULL || sstr == NULL)
2530 		return(NDIS_STATUS_FAILURE);
2531 	str = malloc(sstr->nas_len + 1, M_DEVBUF, M_NOWAIT);
2532 	if (str == NULL)
2533 		return(NDIS_STATUS_FAILURE);
2534 	strncpy(str, sstr->nas_buf, sstr->nas_len);
2535 	*(str + sstr->nas_len) = '\0';
2536 	if (ndis_ascii_to_unicode(str, &dstr->us_buf)) {
2537 		free(str, M_DEVBUF);
2538 		return(NDIS_STATUS_FAILURE);
2539 	}
2540 	dstr->us_len = dstr->us_maxlen = sstr->nas_len * 2;
2541 	free(str, M_DEVBUF);
2542 	return (NDIS_STATUS_SUCCESS);
2543 }
2544 
2545 __stdcall static ndis_status
2546 NdisMPciAssignResources(
2547 	ndis_handle		adapter,
2548 	uint32_t		slot,
2549 	ndis_resource_list	**list)
2550 {
2551 	ndis_miniport_block	*block;
2552 
2553 	if (adapter == NULL || list == NULL)
2554 		return (NDIS_STATUS_FAILURE);
2555 
2556 	block = (ndis_miniport_block *)adapter;
2557 	*list = block->nmb_rlist;
2558 
2559 	return (NDIS_STATUS_SUCCESS);
2560 }
2561 
2562 __stdcall static ndis_status
2563 NdisMRegisterInterrupt(
2564 	ndis_miniport_interrupt	*intr,
2565 	ndis_handle		adapter,
2566 	uint32_t		ivec,
2567 	uint32_t		ilevel,
2568 	uint8_t			reqisr,
2569 	uint8_t			shared,
2570 	ndis_interrupt_mode	imode)
2571 {
2572 	ndis_miniport_block	*block;
2573 
2574 	block = adapter;
2575 
2576 	intr->ni_block = adapter;
2577 	intr->ni_isrreq = reqisr;
2578 	intr->ni_shared = shared;
2579 	block->nmb_interrupt = intr;
2580 
2581 	KeInitializeSpinLock(&intr->ni_dpccountlock);
2582 
2583 	return(NDIS_STATUS_SUCCESS);
2584 }
2585 
2586 __stdcall static void
2587 NdisMDeregisterInterrupt(ndis_miniport_interrupt *intr)
2588 {
2589 	return;
2590 }
2591 
2592 __stdcall static void
2593 NdisMRegisterAdapterShutdownHandler(ndis_handle adapter, void *shutdownctx, ndis_shutdown_handler shutdownfunc)
2594 {
2595 	ndis_miniport_block	*block;
2596 	ndis_miniport_characteristics *chars;
2597 	struct ndis_softc	*sc;
2598 
2599 	if (adapter == NULL)
2600 		return;
2601 
2602 	block = (ndis_miniport_block *)adapter;
2603 #ifdef __FreeBSD__
2604 	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2605 #else /* __NetBSD__ */
2606 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
2607 #endif
2608 	chars = sc->ndis_chars;
2609 
2610 	chars->nmc_shutdown_handler = shutdownfunc;
2611 	chars->nmc_rsvd0 = shutdownctx;
2612 
2613 	return;
2614 }
2615 
2616 __stdcall static void
2617 NdisMDeregisterAdapterShutdownHandler(ndis_handle adapter)
2618 {
2619 	ndis_miniport_block	*block;
2620 	ndis_miniport_characteristics *chars;
2621 	struct ndis_softc	*sc;
2622 
2623 	if (adapter == NULL)
2624 		return;
2625 
2626 	block = (ndis_miniport_block *)adapter;
2627 #ifdef __FreeBSD__
2628 	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2629 #else /* __NetBSD__ */
2630 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
2631 #endif
2632 	chars = sc->ndis_chars;
2633 
2634 	chars->nmc_shutdown_handler = NULL;
2635 	chars->nmc_rsvd0 = NULL;
2636 
2637 	return;
2638 }
2639 
2640 __stdcall static uint32_t
2641 NDIS_BUFFER_TO_SPAN_PAGES(ndis_buffer *buf)
2642 {
2643 	if (buf == NULL)
2644 		return(0);
2645 	if (MmGetMdlByteCount(buf) == 0)
2646 		return(1);
2647 	return(SPAN_PAGES(MmGetMdlVirtualAddress(buf),
2648 	    MmGetMdlByteCount(buf)));
2649 }
2650 
2651 __stdcall static void
2652 NdisGetBufferPhysicalArraySize(ndis_buffer *buf, uint32_t *pages)
2653 {
2654 	if (buf == NULL)
2655 		return;
2656 
2657 	*pages = NDIS_BUFFER_TO_SPAN_PAGES(buf);
2658 	return;
2659 }
2660 
2661 __stdcall static void
2662 NdisQueryBufferOffset(ndis_buffer *buf, uint32_t *off, uint32_t *len)
2663 {
2664 	if (buf == NULL)
2665 		return;
2666 
2667 	*off = MmGetMdlByteOffset(buf);
2668 	*len = MmGetMdlByteCount(buf);
2669 
2670 	return;
2671 }
2672 
2673 __stdcall static void
2674 NdisMSleep(uint32_t usecs)
2675 {
2676 	struct timeval		tv;
2677 
2678 	tv.tv_sec = 0;
2679 	tv.tv_usec = usecs;
2680 
2681 	ndis_thsuspend(curproc, NULL, tvtohz(&tv));
2682 }
2683 
2684 __stdcall static uint32_t
2685 NdisReadPcmciaAttributeMemory(ndis_handle handle, uint32_t offset, void *buf, uint32_t len)
2686 {
2687 	struct ndis_softc	*sc;
2688 	ndis_miniport_block	*block;
2689 	bus_space_handle_t	bh;
2690 	bus_space_tag_t		bt;
2691 	char			*dest;
2692 	int			i;
2693 
2694 	if (handle == NULL)
2695 		return(0);
2696 
2697 	block = (ndis_miniport_block *)handle;
2698 #ifdef __FreeBSD__
2699 	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2700 #else /* __NetBSD__ */
2701 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
2702 #endif
2703 	dest = buf;
2704 
2705 #ifdef __FreeBSD__
2706     bh = rman_get_bushandle(sc->ndis_res_am);
2707     bt = rman_get_bustag(sc->ndis_res_am);
2708 
2709 #else
2710     if ( sc->ndis_iftype == PCMCIABus  ){
2711         bt = sc->ndis_res_pcmem.memt;
2712         bh = sc->ndis_res_pcmem.memh;
2713    } else { /* cardbus case */
2714             /* TODO  what does it really wait for ? */
2715         bt = sc->ndis_res_mem->res_tag;
2716         bh = sc->ndis_res_mem->res_handle;
2717    }
2718 #endif
2719 
2720 	for (i = 0; i < len; i++)
2721 		dest[i] = bus_space_read_1(bt, bh, (offset + i) * 2);
2722 
2723 	return(i);
2724 }
2725 
2726 __stdcall static uint32_t
2727 NdisWritePcmciaAttributeMemory(ndis_handle handle, uint32_t offset, void *buf, uint32_t len)
2728 {
2729 	struct ndis_softc	*sc;
2730 	ndis_miniport_block	*block;
2731 	bus_space_handle_t	bh;
2732 	bus_space_tag_t		bt;
2733 	char			*src;
2734 	int			i;
2735 
2736 	if (handle == NULL)
2737 		return(0);
2738 
2739 	block = (ndis_miniport_block *)handle;
2740 #ifdef __FreeBSD__
2741 	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2742 #else /* __NetBSD__ */
2743 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
2744 #endif
2745 	src = buf;
2746 #ifdef __FreeBSD__
2747     bh = rman_get_bushandle(sc->ndis_res_am);
2748     bt = rman_get_bustag(sc->ndis_res_am);
2749 #else
2750     if ( sc->ndis_iftype == PCMCIABus  ){
2751         bt = sc->ndis_res_pcmem.memt;
2752         bh = sc->ndis_res_pcmem.memh;
2753    } else { /* cardbus case */
2754             /* TODO  what does it really wait for ? */
2755         bt = sc->ndis_res_mem->res_tag;
2756         bh = sc->ndis_res_mem->res_handle;
2757    }
2758 #endif
2759 
2760 	for (i = 0; i < len; i++)
2761 		bus_space_write_1(bt, bh, (offset + i) * 2, src[i]);
2762 
2763 	return(i);
2764 }
2765 
2766 __stdcall static list_entry *
2767 NdisInterlockedInsertHeadList(list_entry *head, list_entry *entry, ndis_spin_lock *lock)
2768 {
2769 	list_entry		*flink;
2770 
2771 	KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql);
2772 	flink = head->nle_flink;
2773 	entry->nle_flink = flink;
2774 	entry->nle_blink = head;
2775 	flink->nle_blink = entry;
2776 	head->nle_flink = entry;
2777 	KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql);
2778 
2779 	return(flink);
2780 }
2781 
2782 __stdcall static list_entry *
2783 NdisInterlockedRemoveHeadList(list_entry *head, ndis_spin_lock *lock)
2784 {
2785 	list_entry		*flink;
2786 	list_entry		*entry;
2787 
2788 	KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql);
2789 	entry = head->nle_flink;
2790 	flink = entry->nle_flink;
2791 	head->nle_flink = flink;
2792 	flink->nle_blink = head;
2793 	KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql);
2794 
2795 	return(entry);
2796 }
2797 
2798 __stdcall static list_entry *
2799 NdisInterlockedInsertTailList(list_entry *head, list_entry *entry, ndis_spin_lock *lock)
2800 {
2801 	list_entry		*blink;
2802 
2803 	KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql);
2804 	blink = head->nle_blink;
2805 	entry->nle_flink = head;
2806 	entry->nle_blink = blink;
2807 	blink->nle_flink = entry;
2808 	head->nle_blink = entry;
2809 	KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql);
2810 
2811 	return(blink);
2812 }
2813 
2814 __stdcall static uint8_t
2815 NdisMSynchronizeWithInterrupt(ndis_miniport_interrupt *intr, void *syncfunc, void *syncctx)
2816 {
2817 	__stdcall uint8_t (*sync)(void *);
2818 	uint8_t			rval;
2819 	uint8_t			irql;
2820 
2821 	if (syncfunc == NULL || syncctx == NULL)
2822 		return(0);
2823 
2824 	sync = syncfunc;
2825 	KeAcquireSpinLock(&intr->ni_dpccountlock, &irql);
2826 	rval = MSCALL1(sync, syncctx);
2827 	KeReleaseSpinLock(&intr->ni_dpccountlock, irql);
2828 
2829 	return(rval);
2830 }
2831 
2832 /*
2833  * Return the number of 100 nanosecond intervals since
2834  * January 1, 1601. (?!?!)
2835  */
2836 __stdcall static void
2837 NdisGetCurrentSystemTime(uint64_t *tval)
2838 {
2839 	struct timespec		ts;
2840 #ifdef __NetBSD__
2841     struct timeval      tv;
2842 
2843     microtime(&tv);
2844     TIMEVAL_TO_TIMESPEC(&tv,&ts);
2845 #else
2846     nanotime(&ts);
2847 #endif
2848 
2849 	*tval = (uint64_t)ts.tv_nsec / 100 + (uint64_t)ts.tv_sec * 10000000 +
2850 	    (uint64_t)11644473600ULL;
2851 
2852 	return;
2853 }
2854 
2855 /*
2856  * Return the number of milliseconds since the system booted.
2857  */
2858 __stdcall static void
2859 NdisGetSystemUpTime(uint32_t *tval)
2860 {
2861 	*tval = (ticks * hz) / 1000;
2862 
2863 	return;
2864 }
2865 
2866 __stdcall static void
2867 NdisInitializeString(ndis_unicode_string *dst, char *src)
2868 {
2869 	ndis_unicode_string	*u;
2870 
2871 	u = dst;
2872 	u->us_buf = NULL;
2873 	if (ndis_ascii_to_unicode(src, &u->us_buf))
2874 		return;
2875 	u->us_len = u->us_maxlen = strlen(src) * 2;
2876 	return;
2877 }
2878 
2879 __stdcall static void
2880 NdisFreeString(ndis_unicode_string *str)
2881 {
2882 	if (str == NULL)
2883 		return;
2884 	if (str->us_buf != NULL)
2885 		free(str->us_buf, M_DEVBUF);
2886 	free(str, M_DEVBUF);
2887 	return;
2888 }
2889 
2890 __stdcall static ndis_status
2891 NdisMRemoveMiniport(ndis_handle	*adapter)
2892 {
2893 	return(NDIS_STATUS_SUCCESS);
2894 }
2895 
2896 __stdcall static void
2897 NdisInitAnsiString(ndis_ansi_string *dst, char *src)
2898 {
2899 	ndis_ansi_string	*a;
2900 
2901 	a = dst;
2902 	if (a == NULL)
2903 		return;
2904 	if (src == NULL) {
2905 		a->nas_len = a->nas_maxlen = 0;
2906 		a->nas_buf = NULL;
2907 	} else {
2908 		a->nas_buf = src;
2909 		a->nas_len = a->nas_maxlen = strlen(src);
2910 	}
2911 
2912 	return;
2913 }
2914 
2915 __stdcall static void
2916 NdisInitUnicodeString(ndis_unicode_string *dst, uint16_t *src)
2917 {
2918 	ndis_unicode_string	*u;
2919 	int			i;
2920 
2921 	u = dst;
2922 	if (u == NULL)
2923 		return;
2924 	if (src == NULL) {
2925 		u->us_len = u->us_maxlen = 0;
2926 		u->us_buf = NULL;
2927 	} else {
2928 		i = 0;
2929 		while(src[i] != 0)
2930 			i++;
2931 		u->us_buf = src;
2932 		u->us_len = u->us_maxlen = i * 2;
2933 	}
2934 
2935 	return;
2936 }
2937 
2938 __stdcall static void NdisMGetDeviceProperty(
2939 	ndis_handle		adapter,
2940 	device_object		**phydevobj,
2941 	device_object		**funcdevobj,
2942 	device_object		**nextdevobj,
2943 	cm_resource_list	*resources,
2944 	cm_resource_list	*transresources)
2945 {
2946 	ndis_miniport_block	*block;
2947 
2948 	block = (ndis_miniport_block *)adapter;
2949 
2950 	if (phydevobj != NULL)
2951 		*phydevobj = block->nmb_physdeviceobj;
2952 	if (funcdevobj != NULL)
2953 		*funcdevobj = block->nmb_deviceobj;
2954 	if (nextdevobj != NULL)
2955 		*nextdevobj = block->nmb_nextdeviceobj;
2956 
2957 	return;
2958 }
2959 
2960 __stdcall static void
2961 NdisGetFirstBufferFromPacket(ndis_packet *packet, ndis_buffer **buf, void **firstva, uint32_t *firstlen, uint32_t *totlen)
2962 {
2963 	ndis_buffer		*tmp;
2964 
2965 	tmp = packet->np_private.npp_head;
2966 	*buf = tmp;
2967 	if (tmp == NULL) {
2968 		*firstva = NULL;
2969 		*firstlen = *totlen = 0;
2970 	} else {
2971 		*firstva = MmGetMdlVirtualAddress(tmp);
2972 		*firstlen = *totlen = MmGetMdlByteCount(tmp);
2973 		for (tmp = tmp->mdl_next; tmp != NULL; tmp = tmp->mdl_next)
2974 			*totlen += MmGetMdlByteCount(tmp);
2975 	}
2976 
2977 	return;
2978 }
2979 
2980 __stdcall static void
2981 NdisGetFirstBufferFromPacketSafe(
2982 	ndis_packet		*packet,
2983 	ndis_buffer		**buf,
2984 	void			**firstva,
2985 	uint32_t		*firstlen,
2986 	uint32_t		*totlen,
2987 	uint32_t		prio)
2988 {
2989 	NdisGetFirstBufferFromPacket(packet, buf, firstva, firstlen, totlen);
2990 }
2991 
2992 #ifdef __FreeBSD__
2993 static int
2994 ndis_find_sym(linker_file_t lf, char *filename, char *suffix, void * *sym)
2995 {
2996 	char			*fullsym;
2997 	char			*suf;
2998 	int			i;
2999 
3000 	fullsym = ExAllocatePoolWithTag(NonPagedPool, MAXPATHLEN, 0);
3001 	if (fullsym == NULL)
3002 		return(ENOMEM);
3003 
3004 	memset(fullsym, 0, MAXPATHLEN);
3005 	strncpy(fullsym, filename, MAXPATHLEN);
3006 	if (strlen(filename) < 4) {
3007 		ExFreePool(fullsym);
3008 		return(EINVAL);
3009 	}
3010 
3011 	/* If the filename has a .ko suffix, strip if off. */
3012 	suf = fullsym + (strlen(filename) - 3);
3013 	if (strcmp(suf, ".ko") == 0)
3014 		*suf = '\0';
3015 
3016 	for (i = 0; i < strlen(fullsym); i++) {
3017 		if (fullsym[i] == '.')
3018 			fullsym[i] = '_';
3019 		else
3020 			fullsym[i] = tolower(fullsym[i]);
3021 	}
3022 	strcat(fullsym, suffix);
3023 	*sym = linker_file_lookup_symbol(lf, fullsym, 0);
3024 	ExFreePool(fullsym);
3025 	if (*sym == 0)
3026 		return(ENOENT);
3027 
3028 	return(0);
3029 }
3030 
3031 /* can also return NDIS_STATUS_RESOURCES/NDIS_STATUS_ERROR_READING_FILE */
3032 __stdcall static void
3033 NdisOpenFile(ndis_status *status, ndis_handle *filehandle, uint32_t *filelength, ndis_unicode_string *filename, ndis_physaddr highestaddr)
3034 {
3035 	char			*afilename = NULL;
3036 	struct thread		*td = curthread;
3037 	struct nameidata	nd;
3038 	int			flags, error;
3039 	struct vattr		vat;
3040 	struct vattr		*vap = &vat;
3041 	ndis_fh			*fh;
3042 	char			*path;
3043 	linker_file_t		head, lf;
3044 	void			*kldstart, *kldend;
3045 
3046 	ndis_unicode_to_ascii(filename->us_buf,
3047 	    filename->us_len, &afilename);
3048 
3049 	fh = ExAllocatePoolWithTag(NonPagedPool, sizeof(ndis_fh), 0);
3050 	if (fh == NULL) {
3051 		*status = NDIS_STATUS_RESOURCES;
3052 		return;
3053 	}
3054 
3055 	/*
3056 	 * During system bootstrap, it's impossible to load files
3057 	 * from the rootfs since it's not mounted yet. We therefore
3058 	 * offer the possibility of opening files that have been
3059 	 * preloaded as modules instead. Both choices will work
3060 	 * when kldloading a module from multiuser, but only the
3061 	 * module option will work during bootstrap. The module
3062 	 * loading option works by using the ndiscvt(8) utility
3063 	 * to convert the arbitrary file into a .ko using objcopy(1).
3064 	 * This file will contain two special symbols: filename_start
3065 	 * and filename_end. All we have to do is traverse the KLD
3066 	 * list in search of those symbols and we've found the file
3067 	 * data. As an added bonus, ndiscvt(8) will also generate
3068 	 * a normal .o file which can be linked statically with
3069 	 * the kernel. This means that the symbols will actual reside
3070 	 * in the kernel's symbol table, but that doesn't matter to
3071 	 * us since the kernel appears to us as just another module.
3072 	 */
3073 
3074 	/*
3075 	 * This is an evil trick for getting the head of the linked
3076 	 * file list, which is not exported from kern_linker.o. It
3077 	 * happens that linker file #1 is always the kernel, and is
3078 	 * always the first element in the list.
3079 	 */
3080 
3081 	head = linker_find_file_by_id(1);
3082 	for (lf = head; lf != NULL; lf = TAILQ_NEXT(lf, link)) {
3083 		if (ndis_find_sym(lf, afilename, "_start", &kldstart))
3084 			continue;
3085 		if (ndis_find_sym(lf, afilename, "_end", &kldend))
3086 			continue;
3087 		fh->nf_vp = lf;
3088 		fh->nf_map = NULL;
3089 		fh->nf_type = NDIS_FH_TYPE_MODULE;
3090 		*filelength = fh->nf_maplen = (kldend - kldstart) & 0xFFFFFFFF;
3091 		*filehandle = fh;
3092 		free(afilename, M_DEVBUF);
3093 		*status = NDIS_STATUS_SUCCESS;
3094 		return;
3095 	}
3096 
3097 	if (TAILQ_EMPTY(&mountlist)) {
3098 		ExFreePool(fh);
3099 		*status = NDIS_STATUS_FILE_NOT_FOUND;
3100 		printf("NDIS: could not find file %s in linker list\n",
3101 		    afilename);
3102 		printf("NDIS: and no filesystems mounted yet, "
3103 		    "aborting NdisOpenFile()\n");
3104 		free(afilename, M_DEVBUF);
3105 		return;
3106 	}
3107 
3108 	path = ExAllocatePoolWithTag(NonPagedPool, MAXPATHLEN, 0);
3109 	if (path == NULL) {
3110 		ExFreePool(fh);
3111 		*status = NDIS_STATUS_RESOURCES;
3112 		return;
3113 	}
3114 
3115 	snprintf(path, MAXPATHLEN, "%s/%s", ndis_filepath, afilename);
3116 	free(afilename, M_DEVBUF);
3117 
3118 	mtx_lock(&Giant);
3119 
3120 	/* Some threads don't have a current working directory. */
3121 
3122 	if (td->td_proc->p_fd->fd_rdir == NULL)
3123 		td->td_proc->p_fd->fd_rdir = rootvnode;
3124 	if (td->td_proc->p_fd->fd_cdir == NULL)
3125 		td->td_proc->p_fd->fd_cdir = rootvnode;
3126 
3127 	/* freebsd-only code; don't modernize this - dholland */
3128 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, td);
3129 
3130 	flags = FREAD;
3131 	error = vn_open(&nd, &flags, 0, -1);
3132 	if (error) {
3133 		mtx_unlock(&Giant);
3134 		*status = NDIS_STATUS_FILE_NOT_FOUND;
3135 		ExFreePool(fh);
3136 		printf("NDIS: open file %s failed: %d\n", path, error);
3137 		ExFreePool(path);
3138 		return;
3139 	}
3140 
3141 	ExFreePool(path);
3142 
3143 	NDFREE(&nd, NDF_ONLY_PNBUF);
3144 
3145 	/* Get the file size. */
3146 	VOP_GETATTR(nd.ni_vp, vap, td->td_ucred, td);
3147 	VOP_UNLOCK(nd.ni_vp, 0, td);
3148 	mtx_unlock(&Giant);
3149 
3150 	fh->nf_vp = nd.ni_vp;
3151 	fh->nf_map = NULL;
3152 	fh->nf_type = NDIS_FH_TYPE_VFS;
3153 	*filehandle = fh;
3154 	*filelength = fh->nf_maplen = vap->va_size & 0xFFFFFFFF;
3155 	*status = NDIS_STATUS_SUCCESS;
3156 
3157 	return;
3158 }
3159 
3160 __stdcall static void
3161 NdisMapFile(ndis_status *status, void **mappedbuffer, ndis_handle filehandle)
3162 {
3163 	ndis_fh			*fh;
3164 	struct thread		*td = curthread;
3165 	linker_file_t		lf;
3166 	void *			kldstart;
3167 	int			error, resid;
3168 
3169 	if (filehandle == NULL) {
3170 		*status = NDIS_STATUS_FAILURE;
3171 		return;
3172 	}
3173 
3174 	fh = (ndis_fh *)filehandle;
3175 
3176 	if (fh->nf_vp == NULL) {
3177 		*status = NDIS_STATUS_FAILURE;
3178 		return;
3179 	}
3180 
3181 	if (fh->nf_map != NULL) {
3182 		*status = NDIS_STATUS_ALREADY_MAPPED;
3183 		return;
3184 	}
3185 
3186 	if (fh->nf_type == NDIS_FH_TYPE_MODULE) {
3187 		lf = fh->nf_vp;
3188 		if (ndis_find_sym(lf, lf->filename, "_start", &kldstart)) {
3189 			*status = NDIS_STATUS_FAILURE;
3190 			return;
3191 		}
3192 		fh->nf_map = kldstart;
3193 		*status = NDIS_STATUS_SUCCESS;
3194 		*mappedbuffer = fh->nf_map;
3195 		return;
3196 	}
3197 
3198 	fh->nf_map = ExAllocatePoolWithTag(NonPagedPool, fh->nf_maplen, 0);
3199 
3200 	if (fh->nf_map == NULL) {
3201 		*status = NDIS_STATUS_RESOURCES;
3202 		return;
3203 	}
3204 
3205 	mtx_lock(&Giant);
3206 	error = vn_rdwr(UIO_READ, fh->nf_vp, fh->nf_map, fh->nf_maplen, 0,
3207 	    UIO_SYSSPACE, 0, td->td_ucred, NOCRED, &resid, td);
3208 	mtx_unlock(&Giant);
3209 
3210 	if (error)
3211 		*status = NDIS_STATUS_FAILURE;
3212 	else {
3213 		*status = NDIS_STATUS_SUCCESS;
3214 		*mappedbuffer = fh->nf_map;
3215 	}
3216 
3217 	return;
3218 }
3219 
3220 __stdcall static void
3221 NdisUnmapFile(ndis_handle filehandle)
3222 {
3223 	ndis_fh			*fh;
3224 	fh = (ndis_fh *)filehandle;
3225 
3226 	if (fh->nf_map == NULL)
3227 		return;
3228 
3229 	if (fh->nf_type == NDIS_FH_TYPE_VFS)
3230 		ExFreePool(fh->nf_map);
3231 	fh->nf_map = NULL;
3232 
3233 	return;
3234 }
3235 
3236 __stdcall static void
3237 NdisCloseFile(ndis_handle filehandle)
3238 {
3239 	struct thread		*td = curthread;
3240 	ndis_fh			*fh;
3241 
3242 	if (filehandle == NULL)
3243 		return;
3244 
3245 	fh = (ndis_fh *)filehandle;
3246 	if (fh->nf_map != NULL) {
3247 		if (fh->nf_type == NDIS_FH_TYPE_VFS)
3248 			ExFreePool(fh->nf_map);
3249 		fh->nf_map = NULL;
3250 	}
3251 
3252 	if (fh->nf_vp == NULL)
3253 		return;
3254 
3255 	if (fh->nf_type == NDIS_FH_TYPE_VFS) {
3256 		mtx_lock(&Giant);
3257 		vn_close(fh->nf_vp, FREAD, td->td_ucred, td);
3258 		mtx_unlock(&Giant);
3259 	}
3260 
3261 	fh->nf_vp = NULL;
3262 	ExFreePool(fh);
3263 
3264 	return;
3265 }
3266 #endif /* __FreeBSD__ */
3267 __stdcall static uint8_t
3268 NdisSystemProcessorCount(void)
3269 {
3270 #ifdef __FreeBSD__
3271 	return(mp_ncpus);
3272 #else
3273 	return(nprocs);
3274 #endif
3275 }
3276 
3277 typedef void (*ndis_statusdone_handler)(ndis_handle);
3278 typedef void (*ndis_status_handler)(ndis_handle, ndis_status,
3279         void *, uint32_t);
3280 
3281 __stdcall static void
3282 NdisMIndicateStatusComplete(ndis_handle adapter)
3283 {
3284 	ndis_miniport_block	*block;
3285 	__stdcall ndis_statusdone_handler	statusdonefunc;
3286 
3287 	block = (ndis_miniport_block *)adapter;
3288 	statusdonefunc = block->nmb_statusdone_func;
3289 
3290 	MSCALL1(statusdonefunc, adapter);
3291 	return;
3292 }
3293 
3294 __stdcall static void
3295 NdisMIndicateStatus(ndis_handle adapter, ndis_status status, void *sbuf, uint32_t slen)
3296 {
3297 	ndis_miniport_block	*block;
3298 	__stdcall ndis_status_handler	statusfunc;
3299 
3300 	block = (ndis_miniport_block *)adapter;
3301 	statusfunc = block->nmb_status_func;
3302 
3303 	MSCALL4(statusfunc, adapter, status, sbuf, slen);
3304 	return;
3305 }
3306 
3307 static void
3308 ndis_workfunc(void *ctx)
3309 {
3310 	ndis_work_item		*work;
3311 	__stdcall ndis_proc	workfunc;
3312 
3313 	work = ctx;
3314 	workfunc = work->nwi_func;
3315 	MSCALL2(workfunc, work, work->nwi_ctx);
3316 	return;
3317 }
3318 
3319 __stdcall static ndis_status
3320 NdisScheduleWorkItem(ndis_work_item *work)
3321 {
3322 	ndis_sched(ndis_workfunc, work, NDIS_TASKQUEUE);
3323 	return(NDIS_STATUS_SUCCESS);
3324 }
3325 
3326 __stdcall static void
3327 NdisCopyFromPacketToPacket(ndis_packet *dpkt, uint32_t doff, uint32_t reqlen, ndis_packet *spkt, uint32_t soff, uint32_t *cpylen)
3328 {
3329 	ndis_buffer		*src, *dst;
3330 	char			*sptr, *dptr;
3331 	int			resid, copied, len, scnt, dcnt;
3332 
3333 	*cpylen = 0;
3334 
3335 	src = spkt->np_private.npp_head;
3336 	dst = dpkt->np_private.npp_head;
3337 
3338 	sptr = MmGetMdlVirtualAddress(src);
3339 	dptr = MmGetMdlVirtualAddress(dst);
3340 	scnt = MmGetMdlByteCount(src);
3341 	dcnt = MmGetMdlByteCount(dst);
3342 
3343 	while (soff) {
3344 		if (MmGetMdlByteCount(src) > soff) {
3345 			sptr += soff;
3346 			scnt = MmGetMdlByteCount(src)- soff;
3347 			break;
3348 		}
3349 		soff -= MmGetMdlByteCount(src);
3350 		src = src->mdl_next;
3351 		if (src == NULL)
3352 			return;
3353 		sptr = MmGetMdlVirtualAddress(src);
3354 	}
3355 
3356 	while (doff) {
3357 		if (MmGetMdlByteCount(dst) > doff) {
3358 			dptr += doff;
3359 			dcnt = MmGetMdlByteCount(dst) - doff;
3360 			break;
3361 		}
3362 		doff -= MmGetMdlByteCount(dst);
3363 		dst = dst->mdl_next;
3364 		if (dst == NULL)
3365 			return;
3366 		dptr = MmGetMdlVirtualAddress(dst);
3367 	}
3368 
3369 	resid = reqlen;
3370 	copied = 0;
3371 
3372 	while(1) {
3373 		if (resid < scnt)
3374 			len = resid;
3375 		else
3376 			len = scnt;
3377 		if (dcnt < len)
3378 			len = dcnt;
3379 
3380 		memcpy( dptr, sptr, len);
3381 
3382 		copied += len;
3383 		resid -= len;
3384 		if (resid == 0)
3385 			break;
3386 
3387 		dcnt -= len;
3388 		if (dcnt == 0) {
3389 			dst = dst->mdl_next;
3390 			if (dst == NULL)
3391 				break;
3392 			dptr = MmGetMdlVirtualAddress(dst);
3393 			dcnt = MmGetMdlByteCount(dst);
3394 		}
3395 
3396 		scnt -= len;
3397 		if (scnt == 0) {
3398 			src = src->mdl_next;
3399 			if (src == NULL)
3400 				break;
3401 			sptr = MmGetMdlVirtualAddress(src);
3402 			scnt = MmGetMdlByteCount(src);
3403 		}
3404 	}
3405 
3406 	*cpylen = copied;
3407 	return;
3408 }
3409 
3410 __stdcall static void
3411 NdisCopyFromPacketToPacketSafe(
3412 	ndis_packet		*dpkt,
3413 	uint32_t		doff,
3414 	uint32_t		reqlen,
3415 	ndis_packet		*spkt,
3416 	uint32_t		soff,
3417 	uint32_t		*cpylen,
3418 	uint32_t		prio)
3419 {
3420 	NdisCopyFromPacketToPacket(dpkt, doff, reqlen, spkt, soff, cpylen);
3421 	return;
3422 }
3423 
3424 __stdcall static ndis_status
3425 NdisMRegisterDevice(
3426 	ndis_handle		handle,
3427 	ndis_unicode_string	*devname,
3428 	ndis_unicode_string	*symname,
3429 	driver_dispatch		*majorfuncs[],
3430 	void			**devobj,
3431 	ndis_handle		*devhandle)
3432 {
3433 	ndis_miniport_block	*block;
3434 
3435 	block = (ndis_miniport_block *)handle;
3436 	*devobj = block->nmb_deviceobj;
3437 	*devhandle = handle;
3438 
3439 	return(NDIS_STATUS_SUCCESS);
3440 }
3441 
3442 __stdcall static ndis_status
3443 NdisMDeregisterDevice(ndis_handle handle)
3444 {
3445 	return(NDIS_STATUS_SUCCESS);
3446 }
3447 
3448 __stdcall static ndis_status
3449 NdisMQueryAdapterInstanceName(ndis_unicode_string *name, ndis_handle handle)
3450 {
3451 	ndis_miniport_block	*block;
3452 	device_t		dev;
3453 
3454 	block = (ndis_miniport_block *)handle;
3455 	dev = block->nmb_physdeviceobj->do_devext;
3456 
3457 	ndis_ascii_to_unicode(__DECONST(char *,
3458 	    device_get_nameunit(dev)), &name->us_buf);
3459 	name->us_len = strlen(device_get_nameunit(dev)) * 2;
3460 
3461 	return(NDIS_STATUS_SUCCESS);
3462 }
3463 
3464 __stdcall static void
3465 NdisMRegisterUnloadHandler(
3466 	ndis_handle		handle,
3467 	void			*func)
3468 {
3469 	return;
3470 }
3471 
3472 __stdcall static void
3473 dummy(void)
3474 {
3475 	printf ("NDIS dummy called...\n");
3476 	return;
3477 }
3478 
3479 image_patch_table ndis_functbl[] = {
3480 	IMPORT_FUNC(NdisCopyFromPacketToPacket),
3481 	IMPORT_FUNC(NdisCopyFromPacketToPacketSafe),
3482 	IMPORT_FUNC(NdisScheduleWorkItem),
3483 	IMPORT_FUNC(NdisMIndicateStatusComplete),
3484 	IMPORT_FUNC(NdisMIndicateStatus),
3485 	IMPORT_FUNC(NdisSystemProcessorCount),
3486 	IMPORT_FUNC(NdisUnchainBufferAtBack),
3487 	IMPORT_FUNC(NdisGetFirstBufferFromPacket),
3488 	IMPORT_FUNC(NdisGetFirstBufferFromPacketSafe),
3489 	IMPORT_FUNC(NdisGetBufferPhysicalArraySize),
3490 	IMPORT_FUNC(NdisMGetDeviceProperty),
3491 	IMPORT_FUNC(NdisInitAnsiString),
3492 	IMPORT_FUNC(NdisInitUnicodeString),
3493 	IMPORT_FUNC(NdisWriteConfiguration),
3494 	IMPORT_FUNC(NdisAnsiStringToUnicodeString),
3495 	IMPORT_FUNC(NdisTerminateWrapper),
3496 	IMPORT_FUNC(NdisOpenConfigurationKeyByName),
3497 	IMPORT_FUNC(NdisOpenConfigurationKeyByIndex),
3498 	IMPORT_FUNC(NdisMRemoveMiniport),
3499 	IMPORT_FUNC(NdisInitializeString),
3500 	IMPORT_FUNC(NdisFreeString),
3501 	IMPORT_FUNC(NdisGetCurrentSystemTime),
3502 	IMPORT_FUNC(NdisGetSystemUpTime),
3503 	IMPORT_FUNC(NdisMSynchronizeWithInterrupt),
3504 	IMPORT_FUNC(NdisMAllocateSharedMemoryAsync),
3505 	IMPORT_FUNC(NdisInterlockedInsertHeadList),
3506 	IMPORT_FUNC(NdisInterlockedInsertTailList),
3507 	IMPORT_FUNC(NdisInterlockedRemoveHeadList),
3508 	IMPORT_FUNC(NdisInitializeWrapper),
3509 	IMPORT_FUNC(NdisMRegisterMiniport),
3510 	IMPORT_FUNC(NdisAllocateMemoryWithTag),
3511 	IMPORT_FUNC(NdisAllocateMemory),
3512 	IMPORT_FUNC(NdisMSetAttributesEx),
3513 	IMPORT_FUNC(NdisCloseConfiguration),
3514 	IMPORT_FUNC(NdisReadConfiguration),
3515 	IMPORT_FUNC(NdisOpenConfiguration),
3516 	IMPORT_FUNC(NdisAcquireSpinLock),
3517 	IMPORT_FUNC(NdisReleaseSpinLock),
3518 	IMPORT_FUNC(NdisDprAcquireSpinLock),
3519 	IMPORT_FUNC(NdisDprReleaseSpinLock),
3520 	IMPORT_FUNC(NdisAllocateSpinLock),
3521 	IMPORT_FUNC(NdisFreeSpinLock),
3522 	IMPORT_FUNC(NdisFreeMemory),
3523 	IMPORT_FUNC(NdisReadPciSlotInformation),
3524 	IMPORT_FUNC(NdisWritePciSlotInformation),
3525 	IMPORT_FUNC_MAP(NdisImmediateReadPciSlotInformation,
3526 	    NdisReadPciSlotInformation),
3527 	IMPORT_FUNC_MAP(NdisImmediateWritePciSlotInformation,
3528 	    NdisWritePciSlotInformation),
3529 	IMPORT_FUNC(NdisWriteErrorLogEntry),
3530 	IMPORT_FUNC(NdisMStartBufferPhysicalMapping),
3531 	IMPORT_FUNC(NdisMCompleteBufferPhysicalMapping),
3532 	IMPORT_FUNC(NdisMInitializeTimer),
3533 	IMPORT_FUNC(NdisInitializeTimer),
3534 	IMPORT_FUNC(NdisSetTimer),
3535 	IMPORT_FUNC(NdisMCancelTimer),
3536 	IMPORT_FUNC_MAP(NdisCancelTimer, NdisMCancelTimer),
3537 	IMPORT_FUNC(NdisMSetPeriodicTimer),
3538 	IMPORT_FUNC(NdisMQueryAdapterResources),
3539 	IMPORT_FUNC(NdisMRegisterIoPortRange),
3540 	IMPORT_FUNC(NdisMDeregisterIoPortRange),
3541 	IMPORT_FUNC(NdisReadNetworkAddress),
3542 	IMPORT_FUNC(NdisQueryMapRegisterCount),
3543 	IMPORT_FUNC(NdisMAllocateMapRegisters),
3544 	IMPORT_FUNC(NdisMFreeMapRegisters),
3545 	IMPORT_FUNC(NdisMAllocateSharedMemory),
3546 	IMPORT_FUNC(NdisMMapIoSpace),
3547 	IMPORT_FUNC(NdisMUnmapIoSpace),
3548 	IMPORT_FUNC(NdisGetCacheFillSize),
3549 	IMPORT_FUNC(NdisMGetDmaAlignment),
3550 	IMPORT_FUNC(NdisMInitializeScatterGatherDma),
3551 	IMPORT_FUNC(NdisAllocatePacketPool),
3552 	IMPORT_FUNC(NdisAllocatePacketPoolEx),
3553 	IMPORT_FUNC(NdisAllocatePacket),
3554 	IMPORT_FUNC(NdisFreePacket),
3555 	IMPORT_FUNC(NdisFreePacketPool),
3556 	IMPORT_FUNC_MAP(NdisDprAllocatePacket, NdisAllocatePacket),
3557 	IMPORT_FUNC_MAP(NdisDprFreePacket, NdisFreePacket),
3558 	IMPORT_FUNC(NdisAllocateBufferPool),
3559 	IMPORT_FUNC(NdisAllocateBuffer),
3560 	IMPORT_FUNC(NdisQueryBuffer),
3561 	IMPORT_FUNC(NdisQueryBufferSafe),
3562 	IMPORT_FUNC(NdisBufferVirtualAddress),
3563 	IMPORT_FUNC(NdisBufferVirtualAddressSafe),
3564 	IMPORT_FUNC(NdisBufferLength),
3565 	IMPORT_FUNC(NdisFreeBuffer),
3566 	IMPORT_FUNC(NdisFreeBufferPool),
3567 	IMPORT_FUNC(NdisInterlockedIncrement),
3568 	IMPORT_FUNC(NdisInterlockedDecrement),
3569 	IMPORT_FUNC(NdisInitializeEvent),
3570 	IMPORT_FUNC(NdisSetEvent),
3571 	IMPORT_FUNC(NdisResetEvent),
3572 	IMPORT_FUNC(NdisWaitEvent),
3573 	IMPORT_FUNC(NdisUnicodeStringToAnsiString),
3574 	IMPORT_FUNC(NdisMPciAssignResources),
3575 	IMPORT_FUNC(NdisMFreeSharedMemory),
3576 	IMPORT_FUNC(NdisMRegisterInterrupt),
3577 	IMPORT_FUNC(NdisMDeregisterInterrupt),
3578 	IMPORT_FUNC(NdisMRegisterAdapterShutdownHandler),
3579 	IMPORT_FUNC(NdisMDeregisterAdapterShutdownHandler),
3580 	IMPORT_FUNC(NDIS_BUFFER_TO_SPAN_PAGES),
3581 	IMPORT_FUNC(NdisQueryBufferOffset),
3582 	IMPORT_FUNC(NdisAdjustBufferLength),
3583 	IMPORT_FUNC(NdisPacketPoolUsage),
3584 	IMPORT_FUNC(NdisMSleep),
3585 	IMPORT_FUNC(NdisUnchainBufferAtFront),
3586 	IMPORT_FUNC(NdisReadPcmciaAttributeMemory),
3587 	IMPORT_FUNC(NdisWritePcmciaAttributeMemory),
3588 #ifdef __FreeBSD__
3589 	IMPORT_FUNC(NdisOpenFile),
3590 	IMPORT_FUNC(NdisMapFile),
3591 	IMPORT_FUNC(NdisUnmapFile),
3592 	IMPORT_FUNC(NdisCloseFile),
3593 #endif
3594 	IMPORT_FUNC(NdisMRegisterDevice),
3595 	IMPORT_FUNC(NdisMDeregisterDevice),
3596 	IMPORT_FUNC(NdisMQueryAdapterInstanceName),
3597 	IMPORT_FUNC(NdisMRegisterUnloadHandler),
3598 	IMPORT_FUNC(ndis_timercall),
3599 
3600 	/*
3601 	 * This last entry is a catch-all for any function we haven't
3602 	 * implemented yet. The PE import list patching routine will
3603 	 * use it for any function that doesn't have an explicit match
3604 	 * in this table.
3605 	 */
3606 
3607 	{ NULL, (FUNC)dummy, NULL },
3608 
3609 	/* End of list. */
3610 
3611 	{ NULL, NULL, NULL }
3612 };
3613