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