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