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