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