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