3 * Bill Paul <wpaul@windriver.com>. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
33 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD: src/sys/compat/ndis/subr_ndis.c,v 1.67.2.7 2005/03/31 21:50:11 wpaul Exp $");
38 __KERNEL_RCSID(0, "$NetBSD: subr_ndis.c,v 1.21 2009/05/11 21:34:55 cegger Exp $");
42 * This file implements a translation layer between the BSD networking
43 * infrasturcture and Windows(R) NDIS network driver modules. A Windows
44 * NDIS driver calls into several functions in the NDIS.SYS Windows
45 * kernel module and exports a table of functions designed to be called
46 * by the NDIS subsystem. Using the PE loader, we can patch our own
47 * versions of the NDIS routines into a given Windows driver module and
48 * convince the driver that it is in fact running on Windows.
50 * We provide a table of all our implemented NDIS routines which is patched
51 * into the driver object code. All our exported routines must use the
52 * _stdcall calling convention, since that's what the Windows object code
57 #include <sys/ctype.h>
59 #include <sys/param.h>
60 #include <sys/types.h>
61 #include <sys/errno.h>
63 #include <sys/callout.h>
64 #include <sys/kernel.h>
65 #include <sys/systm.h>
66 #include <sys/malloc.h>
69 #include <sys/mutex.h>
71 #include <sys/socket.h>
72 #include <sys/sysctl.h>
74 #include <sys/timespec.h>
77 #include <sys/queue.h>
79 #include <sys/filedesc.h>
80 #include <sys/namei.h>
81 #include <sys/fcntl.h>
82 #include <sys/vnode.h>
83 #include <sys/kthread.h>
85 #include <sys/linker.h>
86 #include <sys/sysproto.h>
88 #include <sys/mount.h>
91 #include <net/if_arp.h>
93 #include <net/ethernet.h>
95 #include <net/if_ether.h>
97 #include <net/if_dl.h>
98 #include <net/if_media.h>
100 #include <sys/atomic.h>
102 #include <machine/bus_memio.h>
103 #include <machine/bus_pio.h>
104 #include <machine/resource.h>
106 #include <sys/rman.h>
110 #include <machine/stdarg.h>
112 #include <net80211/ieee80211_var.h>
113 #include <net80211/ieee80211_ioctl.h>
115 #include <dev/pci/pcireg.h>
116 #include <dev/pci/pcivar.h>
118 #include <compat/ndis/pe_var.h>
119 #include <compat/ndis/resource_var.h>
120 #include <compat/ndis/ntoskrnl_var.h>
121 #include <compat/ndis/hal_var.h>
122 #include <compat/ndis/ndis_var.h>
123 #include <compat/ndis/cfg_var.h>
124 #include <dev/if_ndis/if_ndisvar.h>
127 #include "nbcompat.h"
131 #define PN(name) /* printf(#name "\n"); */
134 static char ndis_filepath
[MAXPATHLEN
];
135 extern struct nd_head ndis_devhead
;
138 SYSCTL_STRING(_hw
, OID_AUTO
, ndis_filepath
, CTLFLAG_RW
, ndis_filepath
,
139 MAXPATHLEN
, "Path used by NdisOpenFile() to search for files");
142 __stdcall
static void NdisInitializeWrapper(ndis_handle
*,
143 driver_object
*, void *, void *);
144 __stdcall
static ndis_status
NdisMRegisterMiniport(ndis_handle
,
145 ndis_miniport_characteristics
*, int);
146 __stdcall
static ndis_status
NdisAllocateMemoryWithTag(void **,
148 __stdcall
static ndis_status
NdisAllocateMemory(void **,
149 uint32_t, uint32_t, ndis_physaddr
);
150 __stdcall
static void NdisFreeMemory(void *, uint32_t, uint32_t);
151 __stdcall
static ndis_status
NdisMSetAttributesEx(ndis_handle
, ndis_handle
,
152 uint32_t, uint32_t, ndis_interface_type
);
153 __stdcall
static void NdisOpenConfiguration(ndis_status
*,
154 ndis_handle
*, ndis_handle
);
155 __stdcall
static void NdisOpenConfigurationKeyByIndex(ndis_status
*,
156 ndis_handle
, uint32_t, ndis_unicode_string
*, ndis_handle
*);
157 __stdcall
static void NdisOpenConfigurationKeyByName(ndis_status
*,
158 ndis_handle
, ndis_unicode_string
*, ndis_handle
*);
160 static ndis_status
ndis_encode_parm(ndis_miniport_block
*,
161 struct sysctl_oid
*, ndis_parm_type
, ndis_config_parm
**);
162 static ndis_status
ndis_decode_parm(ndis_miniport_block
*,
163 ndis_config_parm
*, char *);
164 #else /* __NetBSD__ */
165 static ndis_status
ndis_encode_parm(ndis_miniport_block
*,
166 void *, ndis_parm_type
, ndis_config_parm
**);
168 __stdcall
static void NdisReadConfiguration(ndis_status
*, ndis_config_parm
**,
169 ndis_handle
, ndis_unicode_string
*, ndis_parm_type
);
170 __stdcall
static void NdisWriteConfiguration(ndis_status
*, ndis_handle
,
171 ndis_unicode_string
*, ndis_config_parm
*);
172 __stdcall
static void NdisCloseConfiguration(ndis_handle
);
173 __stdcall
static void NdisAllocateSpinLock(ndis_spin_lock
*);
174 __stdcall
static void NdisFreeSpinLock(ndis_spin_lock
*);
175 __stdcall
static void NdisAcquireSpinLock(ndis_spin_lock
*);
176 __stdcall
static void NdisReleaseSpinLock(ndis_spin_lock
*);
177 __stdcall
static void NdisDprAcquireSpinLock(ndis_spin_lock
*);
178 __stdcall
static void NdisDprReleaseSpinLock(ndis_spin_lock
*);
179 __stdcall
static uint32_t NdisReadPciSlotInformation(ndis_handle
, uint32_t,
180 uint32_t, void *, uint32_t);
181 __stdcall
static uint32_t NdisWritePciSlotInformation(ndis_handle
, uint32_t,
182 uint32_t, void *, uint32_t);
183 static void NdisWriteErrorLogEntry(ndis_handle
, ndis_error_code
, uint32_t, ...);
184 static void ndis_map_cb(void *, bus_dma_segment_t
*, int, int);
185 __stdcall
static void NdisMStartBufferPhysicalMapping(ndis_handle
,
186 ndis_buffer
*, uint32_t, uint8_t, ndis_paddr_unit
*, uint32_t *);
187 __stdcall
static void NdisMCompleteBufferPhysicalMapping(ndis_handle
,
188 ndis_buffer
*, uint32_t);
189 __stdcall
static void NdisMInitializeTimer(ndis_miniport_timer
*, ndis_handle
,
190 ndis_timer_function
, void *);
191 __stdcall
static void NdisInitializeTimer(ndis_timer
*,
192 ndis_timer_function
, void *);
193 __stdcall
static void NdisSetTimer(ndis_timer
*, uint32_t);
194 __stdcall
static void NdisMSetPeriodicTimer(ndis_miniport_timer
*, uint32_t);
195 __stdcall
static void NdisMCancelTimer(ndis_timer
*, uint8_t *);
196 __stdcall
static void ndis_timercall(kdpc
*, ndis_miniport_timer
*,
198 __stdcall
static void NdisMQueryAdapterResources(ndis_status
*, ndis_handle
,
199 ndis_resource_list
*, uint32_t *);
200 __stdcall
static ndis_status
NdisMRegisterIoPortRange(void **,
201 ndis_handle
, uint32_t, uint32_t);
202 __stdcall
static void NdisMDeregisterIoPortRange(ndis_handle
,
203 uint32_t, uint32_t, void *);
204 __stdcall
static void NdisReadNetworkAddress(ndis_status
*, void **,
205 uint32_t *, ndis_handle
);
206 __stdcall
static ndis_status
NdisQueryMapRegisterCount(uint32_t, uint32_t *);
207 __stdcall
static ndis_status
NdisMAllocateMapRegisters(ndis_handle
,
208 uint32_t, uint8_t, uint32_t, uint32_t);
209 __stdcall
static void NdisMFreeMapRegisters(ndis_handle
);
210 static void ndis_mapshared_cb(void *, bus_dma_segment_t
*, int, int);
211 __stdcall
static void NdisMAllocateSharedMemory(ndis_handle
, uint32_t,
212 uint8_t, void **, ndis_physaddr
*);
213 static void ndis_asyncmem_complete(void *);
214 __stdcall
static ndis_status
NdisMAllocateSharedMemoryAsync(ndis_handle
,
215 uint32_t, uint8_t, void *);
216 __stdcall
static void NdisMFreeSharedMemory(ndis_handle
, uint32_t,
217 uint8_t, void *, ndis_physaddr
);
218 __stdcall
static ndis_status
NdisMMapIoSpace(void **, ndis_handle
,
219 ndis_physaddr
, uint32_t);
220 __stdcall
static void NdisMUnmapIoSpace(ndis_handle
, void *, uint32_t);
221 __stdcall
static uint32_t NdisGetCacheFillSize(void);
222 __stdcall
static uint32_t NdisMGetDmaAlignment(ndis_handle
);
223 __stdcall
static ndis_status
NdisMInitializeScatterGatherDma(ndis_handle
,
225 __stdcall
static void NdisUnchainBufferAtFront(ndis_packet
*, ndis_buffer
**);
226 __stdcall
static void NdisUnchainBufferAtBack(ndis_packet
*, ndis_buffer
**);
227 __stdcall
static void NdisAllocateBufferPool(ndis_status
*,
228 ndis_handle
*, uint32_t);
229 __stdcall
static void NdisFreeBufferPool(ndis_handle
);
230 __stdcall
static void NdisAllocateBuffer(ndis_status
*, ndis_buffer
**,
231 ndis_handle
, void *, uint32_t);
232 __stdcall
static void NdisFreeBuffer(ndis_buffer
*);
233 __stdcall
static uint32_t NdisBufferLength(ndis_buffer
*);
234 __stdcall
static void NdisQueryBuffer(ndis_buffer
*, void **, uint32_t *);
235 __stdcall
static void NdisQueryBufferSafe(ndis_buffer
*, void **,
236 uint32_t *, uint32_t);
237 __stdcall
static void *NdisBufferVirtualAddress(ndis_buffer
*);
238 __stdcall
static void *NdisBufferVirtualAddressSafe(ndis_buffer
*, uint32_t);
239 __stdcall
static void NdisAdjustBufferLength(ndis_buffer
*, int);
240 __stdcall
static uint32_t NdisInterlockedIncrement(uint32_t *);
241 __stdcall
static uint32_t NdisInterlockedDecrement(uint32_t *);
242 __stdcall
static void NdisInitializeEvent(ndis_event
*);
243 __stdcall
static void NdisSetEvent(ndis_event
*);
244 __stdcall
static void NdisResetEvent(ndis_event
*);
245 __stdcall
static uint8_t NdisWaitEvent(ndis_event
*, uint32_t);
246 __stdcall
static ndis_status
NdisUnicodeStringToAnsiString(ndis_ansi_string
*,
247 ndis_unicode_string
*);
248 __stdcall
static ndis_status
249 NdisAnsiStringToUnicodeString(ndis_unicode_string
*,
251 __stdcall
static ndis_status
NdisMPciAssignResources(ndis_handle
,
252 uint32_t, ndis_resource_list
**);
253 __stdcall
static ndis_status
NdisMRegisterInterrupt(ndis_miniport_interrupt
*,
254 ndis_handle
, uint32_t, uint32_t, uint8_t,
255 uint8_t, ndis_interrupt_mode
);
256 __stdcall
static void NdisMDeregisterInterrupt(ndis_miniport_interrupt
*);
257 __stdcall
static void NdisMRegisterAdapterShutdownHandler(ndis_handle
, void *,
258 ndis_shutdown_handler
);
259 __stdcall
static void NdisMDeregisterAdapterShutdownHandler(ndis_handle
);
260 __stdcall
static uint32_t NDIS_BUFFER_TO_SPAN_PAGES(ndis_buffer
*);
261 __stdcall
static void NdisGetBufferPhysicalArraySize(ndis_buffer
*,
263 __stdcall
static void NdisQueryBufferOffset(ndis_buffer
*,
264 uint32_t *, uint32_t *);
265 __stdcall
static void NdisMSleep(uint32_t);
266 __stdcall
static uint32_t NdisReadPcmciaAttributeMemory(ndis_handle
,
267 uint32_t, void *, uint32_t);
268 __stdcall
static uint32_t NdisWritePcmciaAttributeMemory(ndis_handle
,
269 uint32_t, void *, uint32_t);
270 __stdcall
static list_entry
*NdisInterlockedInsertHeadList(list_entry
*,
271 list_entry
*, ndis_spin_lock
*);
272 __stdcall
static list_entry
*NdisInterlockedRemoveHeadList(list_entry
*,
274 __stdcall
static list_entry
*NdisInterlockedInsertTailList(list_entry
*,
275 list_entry
*, ndis_spin_lock
*);
276 __stdcall
static uint8_t
277 NdisMSynchronizeWithInterrupt(ndis_miniport_interrupt
*,
279 __stdcall
static void NdisGetCurrentSystemTime(uint64_t *);
280 __stdcall
static void NdisGetSystemUpTime(uint32_t *);
281 __stdcall
static void NdisInitializeString(ndis_unicode_string
*, char *);
282 __stdcall
static void NdisInitAnsiString(ndis_ansi_string
*, char *);
283 __stdcall
static void NdisInitUnicodeString(ndis_unicode_string
*,
285 __stdcall
static void NdisFreeString(ndis_unicode_string
*);
286 __stdcall
static ndis_status
NdisMRemoveMiniport(ndis_handle
*);
287 __stdcall
static void NdisTerminateWrapper(ndis_handle
, void *);
288 __stdcall
static void NdisMGetDeviceProperty(ndis_handle
, device_object
**,
289 device_object
**, device_object
**, cm_resource_list
*,
291 __stdcall
static void NdisGetFirstBufferFromPacket(ndis_packet
*,
292 ndis_buffer
**, void **, uint32_t *, uint32_t *);
293 __stdcall
static void NdisGetFirstBufferFromPacketSafe(ndis_packet
*,
294 ndis_buffer
**, void **, uint32_t *, uint32_t *, uint32_t);
296 static int ndis_find_sym(linker_file_t
, char *, char *, void **);
297 __stdcall
static void NdisOpenFile(ndis_status
*, ndis_handle
*, uint32_t *,
298 ndis_unicode_string
*, ndis_physaddr
);
299 __stdcall
static void NdisMapFile(ndis_status
*, void **, ndis_handle
);
300 __stdcall
static void NdisUnmapFile(ndis_handle
);
301 __stdcall
static void NdisCloseFile(ndis_handle
);
303 __stdcall
static uint8_t NdisSystemProcessorCount(void);
304 __stdcall
static void NdisMIndicateStatusComplete(ndis_handle
);
305 __stdcall
static void NdisMIndicateStatus(ndis_handle
, ndis_status
,
307 static void ndis_workfunc(void *);
308 static funcptr
ndis_findwrap(funcptr
);
309 __stdcall
static ndis_status
NdisScheduleWorkItem(ndis_work_item
*);
310 __stdcall
static void NdisCopyFromPacketToPacket(ndis_packet
*,
311 uint32_t, uint32_t, ndis_packet
*, uint32_t, uint32_t *);
312 __stdcall
static void NdisCopyFromPacketToPacketSafe(ndis_packet
*,
313 uint32_t, uint32_t, ndis_packet
*, uint32_t, uint32_t *, uint32_t);
314 __stdcall
static ndis_status
NdisMRegisterDevice(ndis_handle
,
315 ndis_unicode_string
*, ndis_unicode_string
*, driver_dispatch
**,
316 void **, ndis_handle
*);
317 __stdcall
static ndis_status
NdisMDeregisterDevice(ndis_handle
);
318 __stdcall
static ndis_status
319 NdisMQueryAdapterInstanceName(ndis_unicode_string
*,
321 __stdcall
static void NdisMRegisterUnloadHandler(ndis_handle
, void *);
322 __stdcall
static void dummy(void);
325 * Some really old drivers do not properly check the return value
326 * from NdisAllocatePacket() and NdisAllocateBuffer() and will
327 * sometimes allocate few more buffers/packets that they originally
328 * requested when they created the pool. To prevent this from being
329 * a problem, we allocate a few extra buffers/packets beyond what
330 * the driver asks for. This #define controls how many.
332 #define NDIS_POOL_EXTRA 16
337 image_patch_table
*patch
;
339 strcpy(ndis_filepath
, "/compat/ndis");
341 patch
= ndis_functbl
;
342 while (patch
->ipt_func
!= NULL
) {
343 windrv_wrap((funcptr
)patch
->ipt_func
,
344 (funcptr
*)&patch
->ipt_wrap
);
354 image_patch_table
*patch
;
356 patch
= ndis_functbl
;
357 while (patch
->ipt_func
!= NULL
) {
358 windrv_unwrap(patch
->ipt_wrap
);
366 ndis_findwrap(funcptr func
)
368 image_patch_table
*patch
;
370 patch
= ndis_functbl
;
371 while (patch
->ipt_func
!= NULL
) {
372 if ((funcptr
)patch
->ipt_func
== func
)
373 return((funcptr
)patch
->ipt_wrap
);
381 * NDIS deals with strings in unicode format, so we have
382 * do deal with them that way too. For now, we only handle
383 * conversion between unicode and ASCII since that's all
384 * that device drivers care about.
388 ndis_ascii_to_unicode(const char *ascii
, uint16_t **unicode
)
393 if (*unicode
== NULL
)
394 *unicode
= malloc(strlen(ascii
) * 2, M_DEVBUF
, M_NOWAIT
);
396 if (*unicode
== NULL
)
399 for (i
= 0; i
< strlen(ascii
); i
++) {
400 *ustr
= (uint16_t)ascii
[i
];
408 ndis_unicode_to_ascii(uint16_t *unicode
, int ulen
, char **ascii
)
414 *ascii
= malloc((ulen
/ 2) + 1, M_DEVBUF
, M_NOWAIT
|M_ZERO
);
418 for (i
= 0; i
< ulen
/ 2; i
++) {
419 *astr
= (uint8_t)unicode
[i
];
427 * This routine does the messy Windows Driver Model device attachment
428 * stuff on behalf of NDIS drivers. We register our own AddDevice
431 __stdcall
static void
432 NdisInitializeWrapper(
433 ndis_handle
*wrapper
,
438 PN(NdisInitializeWrapper
)
440 * As of yet, I haven't come up with a compelling
441 * reason to define a private NDIS wrapper structure,
442 * so we use a pointer to the driver object as the
443 * wrapper handle. The driver object has the miniport
444 * characteristics struct for this driver hung off it
445 * via IoAllocateDriverObjectExtension(), and that's
446 * really all the private data we need.
452 * If this was really Windows, we'd be registering dispatch
453 * routines for the NDIS miniport module here, but we're
454 * not Windows so all we really need to do is set up an
455 * AddDevice function that'll be invoked when a new device
459 drv
->dro_driverext
->dre_adddevicefunc
= NdisAddDevice
;
464 __stdcall
static void
465 NdisTerminateWrapper(
469 /* Nothing to see here, move along. */
473 __stdcall
static ndis_status
474 NdisMRegisterMiniport(ndis_handle handle
, ndis_miniport_characteristics
*characteristics
, int len
)
476 ndis_miniport_characteristics
*pch
= NULL
;
480 PN(NdisMRegisterMiniport
);
482 drv
= (driver_object
*)handle
;
485 * We need to save the NDIS miniport characteristics
486 * somewhere. This data is per-driver, not per-device
487 * (all devices handled by the same driver have the
488 * same characteristics) so we hook it onto the driver
489 * object using IoAllocateDriverObjectExtension().
490 * The extra extension info is automagically deleted when
491 * the driver is unloaded (see windrv_unload()).
493 if (IoAllocateDriverObjectExtension(drv
, (void *)1,
494 sizeof(ndis_miniport_characteristics
), /*(void **)*/&ch
) !=
496 return(NDIS_STATUS_RESOURCES
);
497 pch
= (ndis_miniport_characteristics
*)ch
;
499 memset((char *)pch
, 0, sizeof(ndis_miniport_characteristics
));
502 memcpy( (char *)pch
, (char *)characteristics
, len
);
503 #else /* __NetBSD__ */
504 memcpy(pch
, characteristics
, len
);
507 if (pch
->nmc_version_major
< 5 || pch
->nmc_version_minor
< 1) {
508 pch
->nmc_shutdown_handler
= NULL
;
509 pch
->nmc_canceltxpkts_handler
= NULL
;
510 pch
->nmc_pnpevent_handler
= NULL
;
513 return(NDIS_STATUS_SUCCESS
);
516 __stdcall
static ndis_status
517 NdisAllocateMemoryWithTag(void **vaddr
, uint32_t len
, uint32_t tag
)
522 mem
= ExAllocatePoolWithTag(NonPagedPool
, len
, tag
);
524 return(NDIS_STATUS_RESOURCES
);
527 return(NDIS_STATUS_SUCCESS
);
530 __stdcall
static ndis_status
535 ndis_physaddr highaddr
)
539 mem
= ExAllocatePoolWithTag(NonPagedPool
, len
, 0);
541 return(NDIS_STATUS_RESOURCES
);
544 return(NDIS_STATUS_SUCCESS
);
547 __stdcall
static void
561 __stdcall
static ndis_status
562 NdisMSetAttributesEx(
563 ndis_handle adapter_handle
,
564 ndis_handle adapter_ctx
,
567 ndis_interface_type iftype
)
569 ndis_miniport_block
*block
;
571 PN(NdisMSetAttributesEx
)
573 * Save the adapter context, we need it for calling
574 * the driver's internal functions.
576 block
= (ndis_miniport_block
*)adapter_handle
;
577 block
->nmb_miniportadapterctx
= adapter_ctx
;
578 block
->nmb_checkforhangsecs
= hangsecs
;
579 block
->nmb_flags
= flags
;
581 return(NDIS_STATUS_SUCCESS
);
584 __stdcall
static void
585 NdisOpenConfiguration(ndis_status
*status
, ndis_handle
*cfg
, ndis_handle wrapctx
)
587 PN(NdisOpenConfiguration
)
589 *status
= NDIS_STATUS_SUCCESS
;
594 __stdcall
static void
595 NdisOpenConfigurationKeyByName(
598 ndis_unicode_string
*subkey
,
599 ndis_handle
*subhandle
)
601 PN(NdisOpenConfiguration
)
603 *status
= NDIS_STATUS_SUCCESS
;
607 __stdcall
static void
608 NdisOpenConfigurationKeyByIndex(
612 ndis_unicode_string
*subkey
,
613 ndis_handle
*subhandle
)
615 *status
= NDIS_STATUS_FAILURE
;
621 ndis_encode_parm(block
, oid
, type
, parm
)
622 ndis_miniport_block
*block
;
623 struct sysctl_oid
*oid
;
625 ndis_config_parm
**parm
;
626 #else /* __NetBSD__ */
627 ndis_encode_parm(block
, data
, type
, parm
)
628 ndis_miniport_block
*block
;
631 ndis_config_parm
**parm
;
635 ndis_unicode_string
*ustr
;
640 unicode
= (uint16_t *)&block
->nmb_dummybuf
;
643 case ndis_parm_string
:
645 ndis_ascii_to_unicode((char *)oid
->oid_arg1
, &unicode
);
646 #else /* __NetBSD__ */
647 ndis_ascii_to_unicode((char *)data
, &unicode
);
649 (*parm
)->ncp_type
= ndis_parm_string
;
650 ustr
= &(*parm
)->ncp_parmdata
.ncp_stringdata
;
652 ustr
->us_len
= strlen((char *)oid
->oid_arg1
) * 2;
653 #else /* __NetBSD__ */
654 ustr
->us_len
= strlen((char *)data
) * 2;
656 ustr
->us_buf
= unicode
;
660 if (strncmp((char *)oid
->oid_arg1
, "0x", 2) == 0) {
661 #else /* __NetBSD__ */
662 if (strncmp((char *)data
, "0x", 2) == 0) {
668 (*parm
)->ncp_type
= ndis_parm_int
;
669 (*parm
)->ncp_parmdata
.ncp_intdata
=
671 strtol((char *)oid
->oid_arg1
, NULL
, base
);
672 #else /* __NetBSD__ */
673 /* TODO: NetBSD dosen't seem to have a strtol in sys/lib/libkern I hope strtoul is OK */
674 strtoul((char *)data
, NULL
, base
);
677 case ndis_parm_hexint
:
679 if (strncmp((char *)oid
->oid_arg1
, "0x", 2) == 0) {
680 #else /* __NetBSD__ */
681 if (strncmp((char *)data
, "0x", 2) == 0) {
687 (*parm
)->ncp_type
= ndis_parm_hexint
;
688 (*parm
)->ncp_parmdata
.ncp_intdata
=
690 strtoul((char *)oid
->oid_arg1
, NULL
, base
);
691 #else /* __NetBSD__ */
692 strtoul((char *)data
, NULL
, base
);
696 return(NDIS_STATUS_FAILURE
);
700 return(NDIS_STATUS_SUCCESS
);
704 ndis_strcasecmp(const char *s1
, const char *s2
)
709 * In the kernel, toupper() is a macro. Have to be careful
710 * not to use pointer arithmetic when passing it arguments.
716 if (toupper(a
) != toupper(b
))
722 return (*(const unsigned char *)s1
- *(const unsigned char *)(s2
- 1));
726 ndis_strncasecmp(const char *s1
, const char *s2
, size_t n
)
734 if (toupper(a
) != toupper(b
))
735 return (*(const unsigned char *)s1
-
736 *(const unsigned char *)(s2
- 1));
745 __stdcall
static void
746 NdisReadConfiguration(ndis_status
*status
, ndis_config_parm
**parm
, ndis_handle cfg
, ndis_unicode_string
*key
, ndis_parm_type type
)
750 ndis_miniport_block
*block
;
751 struct ndis_softc
*sc
;
753 struct sysctl_oid
*oidp
;
754 struct sysctl_ctx_entry
*e
;
758 const struct sysctlnode
*pnode
= NULL
;
759 struct sysctlnode
*ndiscld
= NULL
;
764 char new_keystr
[MAX_SYSCTL_LEN
+1];
768 block
= (ndis_miniport_block
*)cfg
;
770 sc
= device_get_softc(block
->nmb_physdeviceobj
->do_devext
);
771 #else /* __NetBSD__ */
772 sc
= block
->nmb_physdeviceobj
->pdo_sc
;
774 PN(NdisReadConfiguration
)
776 if (key
->us_len
== 0 || key
->us_buf
== NULL
) {
777 *status
= NDIS_STATUS_FAILURE
;
781 ndis_unicode_to_ascii(key
->us_buf
, key
->us_len
, &keystr
);
782 *parm
= &block
->nmb_replyparm
;
783 memset((char *)&block
->nmb_replyparm
, 0, sizeof(ndis_config_parm
));
784 unicode
= (uint16_t *)&block
->nmb_dummybuf
;
787 if(strlen(keystr
) + strlen("ndis_") > MAX_SYSCTL_LEN
) {
788 panic("sysctl name too long: %s\n", keystr
);
790 strcpy(new_keystr
, "ndis_");
791 strcpy(new_keystr
+ strlen("ndis_"), keystr
);
797 * See if registry key is already in a list of known keys
798 * included with the driver.
801 #if __FreeBSD_version < 502113
802 TAILQ_FOREACH(e
, &sc
->ndis_ctx
, link
) {
804 TAILQ_FOREACH(e
, device_get_sysctl_ctx(sc
->ndis_dev
), link
) {
808 if (ndis_strcasecmp(oidp
->oid_name
, keystr
) == 0) {
809 #else /* __NetBSD__ */
810 if (ndis_strcasecmp(oidp
->ctl_name
, keystr
) == 0) {
812 if (strcmp((char *)oidp
->oid_arg1
, "UNSET") == 0) {
813 free(keystr
, M_DEVBUF
);
814 *status
= NDIS_STATUS_FAILURE
;
817 *status
= ndis_encode_parm(block
, oidp
, type
, parm
);
819 free(keystr
, M_DEVBUF
);
823 #else /* __NetBSD__ */
824 mib
[0] = sc
->ndis_sysctl_mib
;
827 error
= sysctl_locate(curlwp
, &mib
[0], 1, &pnode
, NULL
);
829 numcld
= pnode
->sysctl_csize
;
830 ndiscld
= pnode
->sysctl_child
;
832 /* find the node whose name is keystr */
833 for(i
=0; i
< numcld
; i
++) {
834 if(strcmp(keystr
, ndiscld
->sysctl_name
) == 0) {
844 if(strcmp(ndiscld
->sysctl_data
, "UNSET") == 0) {
845 free(keystr
, M_DEVBUF
);
846 *status
= NDIS_STATUS_FAILURE
;
850 *status
= ndis_encode_parm(block
, ndiscld
->sysctl_data
, type
, parm
);
851 free(keystr
, M_DEVBUF
);
858 free(keystr
, M_DEVBUF
);
863 * If the key didn't match, add it to the list of dynamically
864 * created ones. Sometimes, drivers refer to registry keys
865 * that aren't documented in their .INF files. These keys
866 * are supposed to be created by some sort of utility or
867 * control panel snap-in that comes with the driver software.
868 * Sometimes it's useful to be able to manipulate these.
869 * If the driver requests the key in the form of a string,
870 * make its default value an empty string, otherwise default
873 if (type
== ndis_parm_int
|| type
== ndis_parm_hexint
)
874 ndis_add_sysctl(sc
, keystr
, "(dynamic integer key)",
875 "UNSET", CTLFLAG_RW
);
877 ndis_add_sysctl(sc
, keystr
, "(dynamic string key)",
878 "UNSET", CTLFLAG_RW
);
880 free(keystr
, M_DEVBUF
);
881 *status
= NDIS_STATUS_FAILURE
;
887 ndis_decode_parm(ndis_miniport_block
*block
, ndis_config_parm
*parm
, char *val
)
889 ndis_unicode_string
*ustr
;
894 switch(parm
->ncp_type
) {
895 case ndis_parm_string
:
896 ustr
= &parm
->ncp_parmdata
.ncp_stringdata
;
897 ndis_unicode_to_ascii(ustr
->us_buf
, ustr
->us_len
, &astr
);
898 memcpy( val
, astr
, 254);
899 free(astr
, M_DEVBUF
);
902 sprintf(val
, "%d", parm
->ncp_parmdata
.ncp_intdata
);
904 case ndis_parm_hexint
:
905 sprintf(val
, "%xu", parm
->ncp_parmdata
.ncp_intdata
);
908 return(NDIS_STATUS_FAILURE
);
911 return(NDIS_STATUS_SUCCESS
);
915 __stdcall
static void
916 NdisWriteConfiguration(
919 ndis_unicode_string
*key
,
920 ndis_config_parm
*parm
)
924 ndis_miniport_block
*block
;
925 struct ndis_softc
*sc
;
926 struct sysctl_oid
*oidp
;
927 struct sysctl_ctx_entry
*e
;
930 block
= (ndis_miniport_block
*)cfg
;
932 PN(NdisWriteConfiguration
)
935 sc
= device_get_softc(block
->nmb_physdeviceobj
->do_devext
);
936 #else /* __NetBSD__ */
937 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
940 ndis_unicode_to_ascii(key
->us_buf
, key
->us_len
, &keystr
);
942 /* Decode the parameter into a string. */
943 memset(val
, 0, sizeof(val
));
944 *status
= ndis_decode_parm(block
, parm
, val
);
945 if (*status
!= NDIS_STATUS_SUCCESS
) {
946 free(keystr
, M_DEVBUF
);
950 /* See if the key already exists. */
952 #if __FreeBSD_version < 502113 || !defined(__FreeBSD__)
953 TAILQ_FOREACH(e
, &sc
->ndis_ctx
, link
) {
955 TAILQ_FOREACH(e
, device_get_sysctl_ctx(sc
->ndis_dev
), link
) {
958 if (ndis_strcasecmp(oidp
->oid_name
, keystr
) == 0) {
959 /* Found it, set the value. */
960 strcpy((char *)oidp
->oid_arg1
, val
);
961 free(keystr
, M_DEVBUF
);
966 /* Not found, add a new key with the specified value. */
967 ndis_add_sysctl(sc
, keystr
, "(dynamically set key)",
970 free(keystr
, M_DEVBUF
);
971 *status
= NDIS_STATUS_SUCCESS
;
973 #else /* __FreeBSD__ */
974 *status
= NDIS_STATUS_SUCCESS
;
979 __stdcall
static void
980 NdisCloseConfiguration(ndis_handle cfg
)
986 * Initialize a Windows spinlock.
988 __stdcall
static void
989 NdisAllocateSpinLock(ndis_spin_lock
*lock
)
991 KeInitializeSpinLock(&lock
->nsl_spinlock
);
998 * Destroy a Windows spinlock. This is a no-op for now. There are two reasons
999 * for this. One is that it's sort of superfluous: we don't have to do anything
1000 * special to deallocate the spinlock. The other is that there are some buggy
1001 * drivers which call NdisFreeSpinLock() _after_ calling NdisFreeMemory() on
1002 * the block of memory in which the spinlock resides. (Yes, ADMtek, I'm
1005 __stdcall
static void
1006 NdisFreeSpinLock(ndis_spin_lock
*lock
)
1009 KeInitializeSpinLock(&lock
->nsl_spinlock
);
1010 lock
->nsl_kirql
= 0;
1016 * Acquire a spinlock from IRQL <= DISPATCH_LEVEL.
1019 __stdcall
static void
1020 NdisAcquireSpinLock(ndis_spin_lock
*lock
)
1022 KeAcquireSpinLock(&lock
->nsl_spinlock
, &lock
->nsl_kirql
);
1027 * Release a spinlock from IRQL == DISPATCH_LEVEL.
1030 __stdcall
static void
1031 NdisReleaseSpinLock(ndis_spin_lock
*lock
)
1033 KeReleaseSpinLock(&lock
->nsl_spinlock
, lock
->nsl_kirql
);
1038 * Acquire a spinlock when already running at IRQL == DISPATCH_LEVEL.
1040 __stdcall
static void
1041 NdisDprAcquireSpinLock(ndis_spin_lock
*lock
)
1043 KeAcquireSpinLockAtDpcLevel(&lock
->nsl_spinlock
);
1048 * Release a spinlock without leaving IRQL == DISPATCH_LEVEL.
1050 __stdcall
static void
1051 NdisDprReleaseSpinLock(ndis_spin_lock
*lock
)
1053 KeReleaseSpinLockFromDpcLevel(&lock
->nsl_spinlock
);
1057 __stdcall
static uint32_t
1058 NdisReadPciSlotInformation(
1059 ndis_handle adapter
,
1065 ndis_miniport_block
*block
;
1073 /* PN(NdisReadPciSlotInformation) */
1075 struct ndis_softc
*sc
;
1077 block
= (ndis_miniport_block
*)adapter
;
1082 dev
= (device_t
)block
->nmb_physdeviceobj
->do_devext
;
1084 sc
= device_get_softc(dev
);
1085 #else /* __NetBSD__ */
1086 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
1090 * I have a test system consisting of a Sun w2100z
1091 * dual 2.4Ghz Opteron machine and an Atheros 802.11a/b/g
1092 * "Aries" miniPCI NIC. (The NIC is installed in the
1093 * machine using a miniPCI to PCI bus adapter card.)
1094 * When running in SMP mode, I found that
1095 * performing a large number of consecutive calls to
1096 * NdisReadPciSlotInformation() would result in a
1097 * sudden system reset (or in some cases a freeze).
1098 * My suspicion is that the multiple reads are somehow
1099 * triggering a fatal PCI bus error that leads to a
1100 * machine check. The 1us delay in the loop below
1101 * seems to prevent this problem.
1105 for (i
= 0; i
< len
; i
++) {
1106 #else /* __NetBSD__ */
1107 for (i
= 0; i
< len
/4; i
+= 4) {
1111 dest
[i
] = pci_read_config(dev
, i
+ offset
, 1);
1113 dest
[i
/4] = pci_conf_read(sc
->ndis_res_pc
,sc
->ndis_res_pctag
, (i
+ offset
));
1121 __stdcall
static uint32_t
1122 NdisWritePciSlotInformation(
1123 ndis_handle adapter
,
1129 ndis_miniport_block
*block
;
1139 /* PN(NdisWritePciSlotInformation) */
1141 block
= (ndis_miniport_block
*)adapter
;
1143 struct ndis_softc
*sc
;
1149 dev
= block
->nmb_physdeviceobj
->do_devext
;
1151 sc
= device_get_softc(dev
);
1152 #else /* __NetBSD__ */
1153 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
1157 for (i
= 0; i
< len
; i
++) {
1158 #else /* __NetBSD__ */
1159 for (i
= 0; i
< len
/4; i
++) {
1163 pci_write_config(dev
, i
+ offset
, dest
[i
], 1);
1165 pci_conf_write(sc
->ndis_res_pc
,sc
->ndis_res_pctag
,
1166 (i
+ offset
), dest
[i
/4]);
1175 * The errorlog routine uses a variable argument list, so we
1176 * have to declare it this way.
1178 #define ERRMSGLEN 512
1180 NdisWriteErrorLogEntry(ndis_handle adapter
, ndis_error_code code
,
1181 uint32_t numerrors
, ...)
1183 ndis_miniport_block
*block
;
1186 char *str
= NULL
, *ustr
= NULL
;
1188 char msgbuf
[ERRMSGLEN
];
1192 PN(NdisWriteErrorLogEntry
)
1194 block
= (ndis_miniport_block
*)adapter
;
1195 dev
= block
->nmb_physdeviceobj
->do_devext
;
1196 drv
= block
->nmb_physdeviceobj
->do_drvobj
;
1198 error
= pe_get_message((vm_offset_t
)drv
->dro_driverstart
,
1199 code
, &str
, &i
, &flags
);
1200 if (error
== 0 && flags
& MESSAGE_RESOURCE_UNICODE
) {
1202 ndis_unicode_to_ascii((uint16_t *)str
,
1203 ((i
/ 2)) > (ERRMSGLEN
- 1) ? ERRMSGLEN
: i
, &ustr
);
1207 printf ("%s: NDIS ERROR: %x (%s)\n", device_xname(dev
), code
,
1208 str
== NULL
? "unknown error" : str
);
1209 printf ("%s: NDIS NUMERRORS: %x\n", device_xname(dev
), numerrors
);
1211 va_start(ap
, numerrors
);
1212 for (i
= 0; i
< numerrors
; i
++)
1213 printf ("%s: argptr: %p\n",
1215 va_arg(ap
, void *));
1223 ndis_map_cb(void *arg
, bus_dma_segment_t
*segs
, int nseg
, int error
)
1225 struct ndis_map_arg
*ctx
;
1235 for (i
= 0; i
< nseg
; i
++) {
1236 ctx
->nma_fraglist
[i
].npu_physaddr
.np_quad
= segs
[i
].ds_addr
;
1237 ctx
->nma_fraglist
[i
].npu_len
= segs
[i
].ds_len
;
1240 ctx
->nma_cnt
= nseg
;
1245 __stdcall
static void
1246 NdisMStartBufferPhysicalMapping(ndis_handle adapter
, ndis_buffer
*buf
, uint32_t mapreg
, uint8_t writedev
, ndis_paddr_unit
*addrarray
, uint32_t *arraysize
)
1248 ndis_miniport_block
*block
;
1249 struct ndis_softc
*sc
;
1250 struct ndis_map_arg nma
;
1254 PN(NdisMStartBufferPhysicalMapping
)
1256 if (adapter
== NULL
)
1259 block
= (ndis_miniport_block
*)adapter
;
1261 sc
= device_get_softc(block
->nmb_physdeviceobj
->do_devext
);
1262 #else /* __NetBSD__ */
1263 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
1266 if (mapreg
> sc
->ndis_mmapcnt
)
1269 map
= sc
->ndis_mmaps
[mapreg
];
1270 nma
.nma_fraglist
= addrarray
;
1273 error
= bus_dmamap_load(sc
->ndis_mtag
, map
,
1274 MmGetMdlVirtualAddress(buf
), MmGetMdlByteCount(buf
), ndis_map_cb
,
1275 (void *)&nma
, BUS_DMA_NOWAIT
);
1277 error
= bus_dmamap_load(sc
->ndis_mtag
, map
,
1278 MmGetMdlVirtualAddress(buf
), MmGetMdlByteCount(buf
),
1279 NULL
/* kernel space */, BUS_DMA_NOWAIT
);
1280 /* callback function called "by hand" */
1281 ndis_map_cb((void *)&nma
, map
->dm_segs
, map
->dm_nsegs
, error
);
1287 bus_dmamap_sync(sc
->ndis_mtag
, map
,
1288 writedev
? BUS_DMASYNC_PREWRITE
: BUS_DMASYNC_PREREAD
);
1290 bus_dmamap_sync(sc
->ndis_mtag
, map
, 0, map
->dm_mapsize
,
1291 writedev
? BUS_DMASYNC_PREWRITE
: BUS_DMASYNC_PREREAD
);
1293 *arraysize
= nma
.nma_cnt
;
1298 __stdcall
static void
1299 NdisMCompleteBufferPhysicalMapping(
1300 ndis_handle adapter
,
1304 ndis_miniport_block
*block
;
1305 struct ndis_softc
*sc
;
1308 PN(NdisMCompleteBufferPhysicalMapping
)
1310 if (adapter
== NULL
)
1313 block
= (ndis_miniport_block
*)adapter
;
1315 sc
= device_get_softc(block
->nmb_physdeviceobj
->do_devext
);
1316 #else /* __NetBSD__ */
1317 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
1320 if (mapreg
> sc
->ndis_mmapcnt
)
1323 map
= sc
->ndis_mmaps
[mapreg
];
1326 bus_dmamap_sync(sc
->ndis_mtag
, map
,
1327 BUS_DMASYNC_POSTREAD
|BUS_DMASYNC_POSTWRITE
);
1329 bus_dmamap_sync(sc
->ndis_mtag
, map
, 0, map
->dm_mapsize
,
1330 BUS_DMASYNC_POSTREAD
|BUS_DMASYNC_POSTWRITE
);
1332 bus_dmamap_unload(sc
->ndis_mtag
, map
);
1338 * This is an older (?) timer init routine which doesn't
1339 * accept a miniport context handle. Serialized miniports should
1340 * never call this function.
1343 __stdcall
static void
1344 NdisInitializeTimer(ndis_timer
*timer
, ndis_timer_function func
, void *ctx
)
1346 KeInitializeTimer(&timer
->nt_ktimer
);
1347 KeInitializeDpc(&timer
->nt_kdpc
, func
, ctx
);
1352 __stdcall
static void
1353 ndis_timercall(kdpc
*dpc
, ndis_miniport_timer
*timer
, void *sysarg1
, void *sysarg2
)
1355 //PN(ndis_timercall)
1358 * Since we're called as a DPC, we should be running
1359 * at DISPATCH_LEVEL here. This means to acquire the
1360 * spinlock, we can use KeAcquireSpinLockAtDpcLevel()
1361 * rather than KeAcquireSpinLock().
1363 if (NDIS_SERIALIZED(timer
->nmt_block
))
1364 KeAcquireSpinLockAtDpcLevel(&timer
->nmt_block
->nmb_lock
);
1366 MSCALL4(timer
->nmt_timerfunc
, dpc
, timer
->nmt_timerctx
,
1369 if (NDIS_SERIALIZED(timer
->nmt_block
))
1370 KeReleaseSpinLockFromDpcLevel(&timer
->nmt_block
->nmb_lock
);
1376 * For a long time I wondered why there were two NDIS timer initialization
1377 * routines, and why this one needed an NDIS_MINIPORT_TIMER and the
1378 * MiniportAdapterHandle. The NDIS_MINIPORT_TIMER has its own callout
1379 * function and context pointers separate from those in the DPC, which
1380 * allows for another level of indirection: when the timer fires, we
1381 * can have our own timer function invoked, and from there we can call
1382 * the driver's function. But why go to all that trouble? Then it hit
1383 * me: for serialized miniports, the timer callouts are not re-entrant.
1384 * By trapping the callouts and having access to the MiniportAdapterHandle,
1385 * we can protect the driver callouts by acquiring the NDIS serialization
1386 * lock. This is essential for allowing serialized miniports to work
1387 * correctly on SMP systems. On UP hosts, setting IRQL to DISPATCH_LEVEL
1388 * is enough to prevent other threads from pre-empting you, but with
1389 * SMP, you must acquire a lock as well, otherwise the other CPU is
1390 * free to clobber you.
1393 /* Just to test out how much memory is wasted*/
1394 int ndis_num_timers_allocated
= 0;
1396 __stdcall
static void
1397 NdisMInitializeTimer(ndis_miniport_timer
*timer
, ndis_handle handle
, ndis_timer_function func
, void *ctx
)
1399 /* Save the driver's funcptr and context */
1401 PN(NdisMInitializeTimer
)
1403 timer
->nmt_timerfunc
= func
;
1404 timer
->nmt_timerctx
= ctx
;
1405 timer
->nmt_block
= handle
;
1408 /* TODO: free this memory somewhere! */
1409 printf("Allocating callout struct\n");
1410 if(timer
->nmt_ktimer
.k_handle
== NULL
) {
1411 timer
->nmt_ktimer
.k_handle
=
1412 malloc(sizeof(struct callout
), M_DEVBUF
, M_NOWAIT
|M_ZERO
);
1413 ndis_num_timers_allocated
++;
1418 * Set up the timer so it will call our intermediate DPC.
1419 * Be sure to use the wrapped entry point, since
1420 * ntoskrnl_run_dpc() expects to invoke a function with
1421 * Microsoft calling conventions.
1423 KeInitializeTimer(&timer
->nmt_ktimer
);
1424 KeInitializeDpc(&timer
->nmt_kdpc
,
1425 ndis_findwrap((funcptr
)ndis_timercall
), timer
);
1431 * In Windows, there's both an NdisMSetTimer() and an NdisSetTimer(),
1432 * but the former is just a macro wrapper around the latter.
1434 __stdcall
static void
1435 NdisSetTimer(ndis_timer
*timer
, uint32_t msecs
)
1439 * KeSetTimer() wants the period in
1440 * hundred nanosecond intervals.
1442 KeSetTimer(&timer
->nt_ktimer
,
1443 ((int64_t)msecs
* -10000), &timer
->nt_kdpc
);
1448 __stdcall
static void
1449 NdisMSetPeriodicTimer(ndis_miniport_timer
*timer
, uint32_t msecs
)
1451 PN(NdisMSetPeriodicTimer
)
1453 KeSetTimerEx(&timer
->nmt_ktimer
,
1454 ((int64_t)msecs
* -10000), msecs
, &timer
->nmt_kdpc
);
1460 * Technically, this is really NdisCancelTimer(), but we also
1461 * (ab)use it for NdisMCancelTimer(), since in our implementation
1462 * we don't need the extra info in the ndis_miniport_timer
1463 * structure just to cancel a timer.
1466 __stdcall
static void
1467 NdisMCancelTimer(ndis_timer
*timer
, uint8_t *cancelled
)
1469 PN(NdisMCancelTimer
)
1470 *cancelled
= KeCancelTimer(&timer
->nt_ktimer
);
1475 __stdcall
static void
1476 NdisMQueryAdapterResources(ndis_status
*status
, ndis_handle adapter
, ndis_resource_list
*list
, uint32_t *buflen
)
1478 ndis_miniport_block
*block
;
1479 struct ndis_softc
*sc
;
1482 PN(NdisMQueryAdapterResources
)
1484 block
= (ndis_miniport_block
*)adapter
;
1487 sc
= device_get_softc(block
->nmb_physdeviceobj
->do_devext
);
1488 #else /* __NetBSD__ */
1489 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
1492 rsclen
= sizeof(ndis_resource_list
) +
1493 (sizeof(cm_partial_resource_desc
) * (sc
->ndis_rescnt
- 1));
1494 if (*buflen
< rsclen
) {
1496 *status
= NDIS_STATUS_INVALID_LENGTH
;
1501 memcpy( (char *)list
, (char *)block
->nmb_rlist
, rsclen
);
1502 #else /* __NetBSD__ */
1503 memcpy(list
, block
->nmb_rlist
, rsclen
);
1506 *status
= NDIS_STATUS_SUCCESS
;
1511 __stdcall
static ndis_status
1512 NdisMRegisterIoPortRange(
1514 ndis_handle adapter
,
1518 struct ndis_miniport_block
*block
;
1519 struct ndis_softc
*sc
;
1521 PN(NdisMRegisterIoPortRange
)
1523 if (adapter
== NULL
)
1524 return(NDIS_STATUS_FAILURE
);
1526 block
= (ndis_miniport_block
*)adapter
;
1528 sc
= device_get_softc(block
->nmb_physdeviceobj
->do_devext
);
1529 #else /* __NetBSD__ */
1530 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
1534 if (sc
->ndis_res_io
== NULL
)
1536 if (sc
->ndis_res_io
== NULL
&& sc
->ndis_iftype
!= PCMCIABus
)
1538 return(NDIS_STATUS_FAILURE
);
1540 /* Don't let the device map more ports than we have. */
1542 if (rman_get_size(sc
->ndis_res_io
) < numports
)
1543 #else /* __NetBSD__ */
1544 if ( (sc
->ndis_iftype
!= PCMCIABus
&& sc
->ndis_res_io
->res_size
< numports
)
1545 || (sc
->ndis_iftype
== PCMCIABus
&& sc
->ndis_res_pcioh
.size
< numports
) )
1547 return(NDIS_STATUS_INVALID_LENGTH
);
1550 *offset
= (void *)rman_get_start(sc
->ndis_res_io
);
1551 #else /* __NetBSD__ */
1552 switch (sc
->ndis_iftype
){
1554 case CBus
: /* CardBus */
1555 *offset
= (void*)sc
->ndis_res_io
->res_base
;
1558 *offset
= (void*)sc
->ndis_res_pcioh
.addr
;
1561 return(NDIS_STATUS_FAILURE
);
1563 #endif /* __NetBSD__ */
1565 return(NDIS_STATUS_SUCCESS
);
1568 __stdcall
static void
1569 NdisMDeregisterIoPortRange(
1570 ndis_handle adapter
,
1578 __stdcall
static void
1579 NdisReadNetworkAddress(ndis_status
*status
, void **addr
, uint32_t *addrlen
, ndis_handle adapter
)
1581 struct ndis_softc
*sc
;
1582 ndis_miniport_block
*block
;
1583 uint8_t empty
[] = { 0, 0, 0, 0, 0, 0 };
1585 PN(NdisReadNetworkAddress
)
1587 block
= (ndis_miniport_block
*)adapter
;
1589 sc
= device_get_softc(block
->nmb_physdeviceobj
->do_devext
);
1590 #else /* __NetBSD__ */
1591 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
1595 if (memcmp(sc
->arpcom
.ac_enaddr
, empty
, ETHER_ADDR_LEN
) == 0)
1597 if (memcmp(CLLADDR(sc
->arpcom
.ec_if
.if_sadl
),
1598 empty
, ETHER_ADDR_LEN
) == 0)
1601 *status
= NDIS_STATUS_FAILURE
;
1604 *addr
= sc
->arpcom
.ac_enaddr
;
1606 memcpy(sc
->ndis_mac
, CLLADDR(sc
->arpcom
.ec_if
.if_sadl
),
1608 *addr
= sc
->ndis_mac
;
1610 *addrlen
= ETHER_ADDR_LEN
;
1611 *status
= NDIS_STATUS_SUCCESS
;
1617 __stdcall
static ndis_status
1618 NdisQueryMapRegisterCount(
1622 PN(NdisQueryMapRegisterCount
)
1625 return(NDIS_STATUS_SUCCESS
);
1628 __stdcall
static ndis_status
1629 NdisMAllocateMapRegisters(
1630 ndis_handle adapter
,
1631 uint32_t dmachannel
,
1633 uint32_t physmapneeded
,
1636 struct ndis_softc
*sc
;
1637 ndis_miniport_block
*block
;
1641 int i
, nseg
= NDIS_MAXSEG
;
1643 PN(NdisMAllocateMapRegisters
)
1645 block
= (ndis_miniport_block
*)adapter
;
1647 sc
= device_get_softc(block
->nmb_physdeviceobj
->do_devext
);
1648 #else /* __NetBSD__ */
1649 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
1652 sc
->ndis_mmaps
= malloc(sizeof(bus_dmamap_t
) * physmapneeded
,
1653 M_DEVBUF
, M_NOWAIT
|M_ZERO
);
1655 if (sc
->ndis_mmaps
== NULL
)
1656 return(NDIS_STATUS_RESOURCES
);
1659 error
= bus_dma_tag_create(sc
->ndis_parent_tag
, ETHER_ALIGN
, 0,
1660 BUS_SPACE_MAXADDR_32BIT
, BUS_SPACE_MAXADDR
, NULL
,
1661 NULL
, maxmap
* nseg
, nseg
, maxmap
, BUS_DMA_ALLOCNOW
,
1662 NULL
, NULL
, &sc
->ndis_mtag
);
1665 free(sc
->ndis_mmaps
, M_DEVBUF
);
1666 return(NDIS_STATUS_RESOURCES
);
1669 sc
->ndis_mtag
= sc
->ndis_parent_tag
;
1672 for (i
= 0; i
< physmapneeded
; i
++) {
1674 bus_dmamap_create(sc
->ndis_mtag
, 0, &sc
->ndis_mmaps
[i
]);
1676 bus_dmamap_create(sc
->ndis_mtag
, maxmap
* nseg
,
1677 nseg
, maxmap
, BUS_DMA_NOWAIT
,
1678 0, &sc
->ndis_mmaps
[i
]);
1682 sc
->ndis_mmapcnt
= physmapneeded
;
1684 return(NDIS_STATUS_SUCCESS
);
1687 __stdcall
static void
1688 NdisMFreeMapRegisters(ndis_handle adapter
)
1690 struct ndis_softc
*sc
;
1691 ndis_miniport_block
*block
;
1694 PN(NdisMFreeMapRegisters
)
1696 block
= (ndis_miniport_block
*)adapter
;
1698 sc
= device_get_softc(block
->nmb_physdeviceobj
->do_devext
);
1699 #else /* __NetBSD__ */
1700 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
1703 for (i
= 0; i
< sc
->ndis_mmapcnt
; i
++)
1704 bus_dmamap_destroy(sc
->ndis_mtag
, sc
->ndis_mmaps
[i
]);
1706 free(sc
->ndis_mmaps
, M_DEVBUF
);
1709 bus_dma_tag_destroy(sc
->ndis_mtag
);
1716 ndis_mapshared_cb(void *arg
, bus_dma_segment_t
*segs
, int nseg
, int error
)
1720 /* PN(ndis_mapshared_cb) */
1722 if (error
|| nseg
> 1)
1727 p
->np_quad
= segs
[0].ds_addr
;
1733 * This maps to bus_dmamem_alloc().
1735 __stdcall
static void
1736 NdisMAllocateSharedMemory(
1737 ndis_handle adapter
,
1741 ndis_physaddr
*paddr
)
1743 ndis_miniport_block
*block
;
1744 struct ndis_softc
*sc
;
1745 struct ndis_shmem
*sh
;
1748 bus_dma_segment_t segs
;
1752 /* PN(NdisMAllocateSharedMemory) */
1754 if (adapter
== NULL
)
1757 block
= (ndis_miniport_block
*)adapter
;
1759 sc
= device_get_softc(block
->nmb_physdeviceobj
->do_devext
);
1760 #else /* __NetBSD__ */
1761 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
1764 sh
= malloc(sizeof(struct ndis_shmem
), M_DEVBUF
, M_NOWAIT
|M_ZERO
);
1769 * When performing shared memory allocations, create a tag
1770 * with a lowaddr limit that restricts physical memory mappings
1771 * so that they all fall within the first 1GB of memory.
1772 * At least one device/driver combination (Linksys Instant
1773 * Wireless PCI Card V2.7, Broadcom 802.11b) seems to have
1774 * problems with performing DMA operations with physical
1775 * addresses that lie above the 1GB mark. I don't know if this
1776 * is a hardware limitation or if the addresses are being
1777 * truncated within the driver, but this seems to be the only
1778 * way to make these cards work reliably in systems with more
1779 * than 1GB of physical memory.
1783 error
= bus_dma_tag_create(sc
->ndis_parent_tag
, 64,
1784 0, NDIS_BUS_SPACE_SHARED_MAXADDR
, BUS_SPACE_MAXADDR
, NULL
,
1785 NULL
, len
, 1, len
, BUS_DMA_ALLOCNOW
, NULL
, NULL
,
1793 error
= bus_dmamem_alloc(sh
->ndis_stag
, vaddr
,
1794 BUS_DMA_NOWAIT
| BUS_DMA_ZERO
, &sh
->ndis_smap
);
1797 bus_dma_tag_destroy(sh
->ndis_stag
);
1802 error
= bus_dmamap_load(sh
->ndis_stag
, sh
->ndis_smap
, *vaddr
,
1803 len
, ndis_mapshared_cb
, (void *)paddr
, BUS_DMA_NOWAIT
);
1806 bus_dmamem_free(sh
->ndis_stag
, *vaddr
, sh
->ndis_smap
);
1807 bus_dma_tag_destroy(sh
->ndis_stag
);
1812 sh
->ndis_stag
= sc
->ndis_parent_tag
;
1814 error
= bus_dmamem_alloc(sh
->ndis_stag
, len
, 64, 0,
1815 &segs
, 1, &nsegs
, BUS_DMA_NOWAIT
);
1818 printf("bus_dmamem_alloc failed(1)\n");
1822 error
= bus_dmamem_map(sh
->ndis_stag
, &segs
, nsegs
,
1823 len
, /*(void **)&vaddr*/ (void **)vaddr
, BUS_DMA_NOWAIT
);
1825 /* printf("*vaddr = %x\n", (unsigned int)*vaddr); */
1828 printf("bus_dmamem_alloc failed(2)\n");
1833 error
= bus_dmamap_create(sh
->ndis_stag
, len
, nsegs
,
1834 BUS_SPACE_MAXSIZE_32BIT
, 0,
1835 BUS_DMA_ALLOCNOW
, &sh
->ndis_smap
);
1838 printf("bus_dmamem_alloc failed(3)\n");
1839 /* XXX free, unmap */
1843 error
= bus_dmamap_load(sh
->ndis_stag
, sh
->ndis_smap
, /*vaddr*/ *vaddr
,
1844 len
, NULL
, BUS_DMA_NOWAIT
);
1845 ndis_mapshared_cb((void *)paddr
,
1846 sh
->ndis_smap
->dm_segs
,
1847 sh
->ndis_smap
->dm_nsegs
, error
);
1850 printf("bus_dmamem_alloc failed(3)\n");
1851 /* XXX free, unmap, destroy */
1856 sh
->ndis_saddr
= *vaddr
;
1857 sh
->ndis_next
= sc
->ndis_shlist
;
1858 sc
->ndis_shlist
= sh
;
1863 struct ndis_allocwork
{
1864 ndis_handle na_adapter
;
1871 ndis_asyncmem_complete(void *arg
)
1873 ndis_miniport_block
*block
;
1874 struct ndis_softc
*sc
;
1875 struct ndis_allocwork
*w
;
1877 ndis_physaddr paddr
;
1878 __stdcall ndis_allocdone_handler donefunc
;
1881 block
= (ndis_miniport_block
*)w
->na_adapter
;
1883 sc
= device_get_softc(block
->nmb_physdeviceobj
->do_devext
);
1884 #else /* __NetBSD__ */
1885 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
1888 PN(ndis_asyncmem_complete
)
1893 donefunc
= sc
->ndis_chars
->nmc_allocate_complete_func
;
1894 NdisMAllocateSharedMemory(w
->na_adapter
, w
->na_len
,
1895 w
->na_cached
, &vaddr
, &paddr
);
1896 MSCALL5(donefunc
, w
->na_adapter
, vaddr
, &paddr
, w
->na_len
, w
->na_ctx
);
1898 free(arg
, M_DEVBUF
);
1903 __stdcall
static ndis_status
1904 NdisMAllocateSharedMemoryAsync(ndis_handle adapter
, uint32_t len
, uint8_t cached
, void *ctx
)
1906 struct ndis_allocwork
*w
;
1908 PN(NdisMAllocateSharedMemoryAsync
)
1910 if (adapter
== NULL
)
1911 return(NDIS_STATUS_FAILURE
);
1913 w
= malloc(sizeof(struct ndis_allocwork
), M_TEMP
, M_NOWAIT
);
1916 return(NDIS_STATUS_FAILURE
);
1918 w
->na_adapter
= adapter
;
1919 w
->na_cached
= cached
;
1924 * Pawn this work off on the SWI thread instead of the
1925 * taskqueue thread, because sometimes drivers will queue
1926 * up work items on the taskqueue thread that will block,
1927 * which would prevent the memory allocation from completing
1930 ndis_sched(ndis_asyncmem_complete
, w
, NDIS_SWI
);
1932 return(NDIS_STATUS_PENDING
);
1935 __stdcall
static void
1936 NdisMFreeSharedMemory(
1937 ndis_handle adapter
,
1941 ndis_physaddr paddr
)
1943 ndis_miniport_block
*block
;
1944 struct ndis_softc
*sc
;
1945 struct ndis_shmem
*sh
, *prev
;
1947 PN(NdisMFreeSharedMemory
)
1949 if (vaddr
== NULL
|| adapter
== NULL
)
1952 block
= (ndis_miniport_block
*)adapter
;
1954 sc
= device_get_softc(block
->nmb_physdeviceobj
->do_devext
);
1955 #else /* __NetBSD__ */
1956 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
1958 sh
= prev
= sc
->ndis_shlist
;
1960 /* Sanity check: is list empty? */
1966 if (sh
->ndis_saddr
== vaddr
)
1972 bus_dmamap_unload(sh
->ndis_stag
, sh
->ndis_smap
);
1974 bus_dmamem_free(sh
->ndis_stag
, vaddr
, sh
->ndis_smap
);
1975 bus_dma_tag_destroy(sh
->ndis_stag
);
1977 bus_dmamem_unmap(sh
->ndis_stag
, vaddr
, sh
->ndis_smap
->dm_mapsize
);
1978 bus_dmamem_free(sh
->ndis_stag
,
1979 sh
->ndis_smap
->dm_segs
, sh
->ndis_smap
->dm_nsegs
);
1981 if (sh
== sc
->ndis_shlist
)
1982 sc
->ndis_shlist
= sh
->ndis_next
;
1984 prev
->ndis_next
= sh
->ndis_next
;
1991 __stdcall
static ndis_status
1994 ndis_handle adapter
,
1995 ndis_physaddr paddr
,
1998 ndis_miniport_block
*block
;
1999 struct ndis_softc
*sc
;
2003 if (adapter
== NULL
)
2004 return(NDIS_STATUS_FAILURE
);
2006 block
= (ndis_miniport_block
*)adapter
;
2008 sc
= device_get_softc(block
->nmb_physdeviceobj
->do_devext
);
2009 #else /* __NetBSD__ */
2010 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
2015 if (sc
->ndis_res_mem
!= NULL
&&
2016 paddr
.np_quad
== rman_get_start(sc
->ndis_res_mem
))
2017 *vaddr
= (void *)rman_get_virtual(sc
->ndis_res_mem
);
2018 else if (sc
->ndis_res_altmem
!= NULL
&&
2019 paddr
.np_quad
== rman_get_start(sc
->ndis_res_altmem
))
2020 *vaddr
= (void *)rman_get_virtual(sc
->ndis_res_altmem
);
2021 else if (sc
->ndis_res_am
!= NULL
&&
2022 paddr
.np_quad
== rman_get_start(sc
->ndis_res_am
))
2023 *vaddr
= (void *)rman_get_virtual(sc
->ndis_res_am
);
2025 return(NDIS_STATUS_FAILURE
);
2027 /* TODO: add one for sc->ndis_res_am once PCMCIA is going */
2028 if (sc
->ndis_res_mem
!= NULL
&&
2029 paddr
.np_quad
== sc
->ndis_res_mem
->res_base
)
2030 *vaddr
= bus_space_vaddr(sc
->ndis_res_mem
->res_tag
,
2031 sc
->ndis_res_mem
->res_handle
);
2032 else if (sc
->ndis_res_altmem
!= NULL
&&
2033 paddr
.np_quad
== sc
->ndis_res_altmem
->res_base
)
2034 *vaddr
= bus_space_vaddr(sc
->ndis_res_altmem
->res_tag
,
2035 sc
->ndis_res_altmem
->res_handle
);
2037 return(NDIS_STATUS_FAILURE
);
2039 *vaddr = bus_space_vaddr(sc->ndis_res_mem->res_tag,
2040 sc->ndis_res_mem->res_handle);
2044 return(NDIS_STATUS_SUCCESS
);
2047 __stdcall
static void
2049 ndis_handle adapter
,
2056 __stdcall
static uint32_t
2057 NdisGetCacheFillSize(void)
2062 __stdcall
static uint32_t
2063 NdisMGetDmaAlignment(ndis_handle handle
)
2069 * NDIS has two methods for dealing with NICs that support DMA.
2070 * One is to just pass packets to the driver and let it call
2071 * NdisMStartBufferPhysicalMapping() to map each buffer in the packet
2072 * all by itself, and the other is to let the NDIS library handle the
2073 * buffer mapping internally, and hand the driver an already populated
2074 * scatter/gather fragment list. If the driver calls
2075 * NdisMInitializeScatterGatherDma(), it wants to use the latter
2079 __stdcall
static ndis_status
2080 NdisMInitializeScatterGatherDma(
2081 ndis_handle adapter
,
2083 uint32_t maxphysmap
)
2085 struct ndis_softc
*sc
;
2086 ndis_miniport_block
*block
;
2091 PN(NdisMInitializeScatterGatherDma
)
2093 if (adapter
== NULL
)
2094 return(NDIS_STATUS_FAILURE
);
2095 block
= (ndis_miniport_block
*)adapter
;
2097 sc
= device_get_softc(block
->nmb_physdeviceobj
->do_devext
);
2098 #else /* __NetBSD__ */
2099 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
2102 /* Don't do this twice. */
2103 if (sc
->ndis_sc
== 1)
2104 return(NDIS_STATUS_SUCCESS
);
2107 error
= bus_dma_tag_create(sc
->ndis_parent_tag
, ETHER_ALIGN
, 0,
2108 BUS_SPACE_MAXADDR_32BIT
, BUS_SPACE_MAXADDR
, NULL
, NULL
,
2109 MCLBYTES
* NDIS_MAXSEG
, NDIS_MAXSEG
, MCLBYTES
, BUS_DMA_ALLOCNOW
,
2110 NULL
, NULL
, &sc
->ndis_ttag
);
2111 #else /* __NetBSD__ */
2112 /* TODO: Is this correct to just use the parent tag? */
2113 sc
->ndis_ttag
= sc
->ndis_parent_tag
;
2118 return(NDIS_STATUS_SUCCESS
);
2122 NdisAllocatePacketPool(ndis_status
*status
, ndis_handle
*pool
, uint32_t descnum
, uint32_t protrsvdlen
)
2127 PN(NdisAllocatePacketPool
)
2129 *pool
= malloc((sizeof(ndis_packet
) + protrsvdlen
) *
2130 ((descnum
+ NDIS_POOL_EXTRA
) + 1),
2131 M_DEVBUF
, M_NOWAIT
|M_ZERO
);
2133 if (*pool
== NULL
) {
2134 *status
= NDIS_STATUS_RESOURCES
;
2138 cur
= (ndis_packet
*)*pool
;
2139 KeInitializeSpinLock(&cur
->np_lock
);
2140 cur
->np_private
.npp_flags
= 0x1; /* mark the head of the list */
2141 cur
->np_private
.npp_totlen
= 0; /* init deletetion flag */
2142 for (i
= 0; i
< (descnum
+ NDIS_POOL_EXTRA
); i
++) {
2143 cur
->np_private
.npp_head
= (ndis_handle
)(cur
+ 1);
2147 *status
= NDIS_STATUS_SUCCESS
;
2152 NdisAllocatePacketPoolEx(ndis_status
*status
, ndis_handle
*pool
, uint32_t descnum
, uint32_t oflowdescnum
, uint32_t protrsvdlen
)
2154 return(NdisAllocatePacketPool(status
, pool
,
2155 descnum
+ oflowdescnum
, protrsvdlen
));
2159 NdisPacketPoolUsage(ndis_handle pool
)
2165 head
= (ndis_packet
*)pool
;
2166 KeAcquireSpinLock(&head
->np_lock
, &irql
);
2167 cnt
= head
->np_private
.npp_count
;
2168 KeReleaseSpinLock(&head
->np_lock
, irql
);
2174 NdisFreePacketPool(ndis_handle pool
)
2181 /* Mark this pool as 'going away.' */
2183 KeAcquireSpinLock(&head
->np_lock
, &irql
);
2184 head
->np_private
.npp_totlen
= 1;
2186 /* If there are no buffers loaned out, destroy the pool. */
2188 if (head
->np_private
.npp_count
== 0) {
2189 KeReleaseSpinLock(&head
->np_lock
, irql
);
2190 free(pool
, M_DEVBUF
);
2192 printf("NDIS: buggy driver deleting active packet pool!\n");
2193 KeReleaseSpinLock(&head
->np_lock
, irql
);
2200 NdisAllocatePacket(ndis_status
*status
, ndis_packet
**packet
, ndis_handle pool
)
2202 ndis_packet
*head
, *pkt
;
2206 /*TODO: For some reason NdisAllocatePacket was getting called once with pool being NULL
2207 *TODO: and this was causing a seg-fault. This seems to solve the problem, but I'm not
2208 *TODO: should happen at all in the first place.
2211 *status
= NDIS_STATUS_FAILURE
;
2216 head
= (ndis_packet
*)pool
;
2217 KeAcquireSpinLock(&head
->np_lock
, &irql
);
2219 if (head
->np_private
.npp_flags
!= 0x1) {
2220 *status
= NDIS_STATUS_FAILURE
;
2221 KeReleaseSpinLock(&head
->np_lock
, irql
);
2226 * If this pool is marked as 'going away' don't allocate any
2227 * more packets out of it.
2230 if (head
->np_private
.npp_totlen
) {
2231 *status
= NDIS_STATUS_FAILURE
;
2232 KeReleaseSpinLock(&head
->np_lock
, irql
);
2236 pkt
= (ndis_packet
*)head
->np_private
.npp_head
;
2239 *status
= NDIS_STATUS_RESOURCES
;
2240 KeReleaseSpinLock(&head
->np_lock
, irql
);
2244 head
->np_private
.npp_head
= pkt
->np_private
.npp_head
;
2246 pkt
->np_private
.npp_head
= pkt
->np_private
.npp_tail
= NULL
;
2247 /* Save pointer to the pool. */
2248 pkt
->np_private
.npp_pool
= head
;
2250 /* Set the oob offset pointer. Lots of things expect this. */
2251 pkt
->np_private
.npp_packetooboffset
=
2252 offsetof(ndis_packet
, np_oob
);
2255 * We must initialize the packet flags correctly in order
2256 * for the NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO() and
2257 * NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO() macros to work
2260 pkt
->np_private
.npp_ndispktflags
= NDIS_PACKET_ALLOCATED_BY_NDIS
;
2261 pkt
->np_private
.npp_validcounts
= FALSE
;
2265 head
->np_private
.npp_count
++;
2266 *status
= NDIS_STATUS_SUCCESS
;
2268 KeReleaseSpinLock(&head
->np_lock
, irql
);
2274 NdisFreePacket(ndis_packet
*packet
)
2279 if (packet
== NULL
|| packet
->np_private
.npp_pool
== NULL
)
2282 head
= packet
->np_private
.npp_pool
;
2283 KeAcquireSpinLock(&head
->np_lock
, &irql
);
2285 if (head
->np_private
.npp_flags
!= 0x1) {
2286 KeReleaseSpinLock(&head
->np_lock
, irql
);
2290 packet
->np_private
.npp_head
= head
->np_private
.npp_head
;
2291 head
->np_private
.npp_head
= (ndis_buffer
*)packet
;
2292 head
->np_private
.npp_count
--;
2295 * If the pool has been marked for deletion and there are
2296 * no more packets outstanding, nuke the pool.
2299 if (head
->np_private
.npp_totlen
&& head
->np_private
.npp_count
== 0) {
2300 KeReleaseSpinLock(&head
->np_lock
, irql
);
2301 free(head
, M_DEVBUF
);
2303 KeReleaseSpinLock(&head
->np_lock
, irql
);
2308 __stdcall
static void
2309 NdisUnchainBufferAtFront(ndis_packet
*packet
, ndis_buffer
**buf
)
2311 ndis_packet_private
*priv
;
2313 if (packet
== NULL
|| buf
== NULL
)
2316 priv
= &packet
->np_private
;
2318 priv
->npp_validcounts
= FALSE
;
2320 if (priv
->npp_head
== priv
->npp_tail
) {
2321 *buf
= priv
->npp_head
;
2322 priv
->npp_head
= priv
->npp_tail
= NULL
;
2324 *buf
= priv
->npp_head
;
2325 priv
->npp_head
= (*buf
)->mdl_next
;
2331 __stdcall
static void
2332 NdisUnchainBufferAtBack(ndis_packet
*packet
, ndis_buffer
**buf
)
2334 ndis_packet_private
*priv
;
2337 if (packet
== NULL
|| buf
== NULL
)
2340 priv
= &packet
->np_private
;
2342 priv
->npp_validcounts
= FALSE
;
2344 if (priv
->npp_head
== priv
->npp_tail
) {
2345 *buf
= priv
->npp_head
;
2346 priv
->npp_head
= priv
->npp_tail
= NULL
;
2348 *buf
= priv
->npp_tail
;
2349 tmp
= priv
->npp_head
;
2350 while (tmp
->mdl_next
!= priv
->npp_tail
)
2351 tmp
= tmp
->mdl_next
;
2352 priv
->npp_tail
= tmp
;
2353 tmp
->mdl_next
= NULL
;
2360 * The NDIS "buffer" is really an MDL (memory descriptor list)
2361 * which is used to describe a buffer in a way that allows it
2362 * to mapped into different contexts. We have to be careful how
2363 * we handle them: in some versions of Windows, the NdisFreeBuffer()
2364 * routine is an actual function in the NDIS API, but in others
2365 * it's just a macro wrapper around IoFreeMdl(). There's really
2366 * no way to use the 'descnum' parameter to count how many
2367 * "buffers" are allocated since in order to use IoFreeMdl() to
2368 * dispose of a buffer, we have to use IoAllocateMdl() to allocate
2369 * them, and IoAllocateMdl() just grabs them out of the heap.
2372 __stdcall
static void
2373 NdisAllocateBufferPool(
2374 ndis_status
*status
,
2379 * The only thing we can really do here is verify that descnum
2380 * is a reasonable value, but I really don't know what to check
2384 *pool
= NonPagedPool
;
2385 *status
= NDIS_STATUS_SUCCESS
;
2389 __stdcall
static void
2390 NdisFreeBufferPool(ndis_handle pool
)
2395 __stdcall
static void
2397 ndis_status
*status
,
2398 ndis_buffer
**buffer
,
2405 buf
= IoAllocateMdl(vaddr
, len
, FALSE
, FALSE
, NULL
);
2407 *status
= NDIS_STATUS_RESOURCES
;
2412 *status
= NDIS_STATUS_SUCCESS
;
2417 __stdcall
static void
2418 NdisFreeBuffer(ndis_buffer
*buf
)
2426 __stdcall
static uint32_t
2427 NdisBufferLength(ndis_buffer
*buf
)
2429 return(MmGetMdlByteCount(buf
));
2433 * Get the virtual address and length of a buffer.
2434 * Note: the vaddr argument is optional.
2437 __stdcall
static void
2438 NdisQueryBuffer(ndis_buffer
*buf
, void **vaddr
, uint32_t *len
)
2441 *vaddr
= MmGetMdlVirtualAddress(buf
);
2442 *len
= MmGetMdlByteCount(buf
);
2447 /* Same as above -- we don't care about the priority. */
2449 __stdcall
static void
2450 NdisQueryBufferSafe(
2457 *vaddr
= MmGetMdlVirtualAddress(buf
);
2458 *len
= MmGetMdlByteCount(buf
);
2463 /* Damnit Microsoft!! How many ways can you do the same thing?! */
2465 __stdcall
static void *
2466 NdisBufferVirtualAddress(ndis_buffer
*buf
)
2468 return(MmGetMdlVirtualAddress(buf
));
2471 __stdcall
static void *
2472 NdisBufferVirtualAddressSafe(
2476 return(MmGetMdlVirtualAddress(buf
));
2479 __stdcall
static void
2480 NdisAdjustBufferLength(ndis_buffer
*buf
, int len
)
2482 MmGetMdlByteCount(buf
) = len
;
2487 __stdcall
static uint32_t
2488 NdisInterlockedIncrement(uint32_t *addend
)
2490 atomic_inc_32(addend
);
2494 __stdcall
static uint32_t
2495 NdisInterlockedDecrement(uint32_t *addend
)
2497 atomic_dec_32(addend
);
2501 __stdcall
static void
2502 NdisInitializeEvent(ndis_event
*event
)
2505 * NDIS events are always notification
2506 * events, and should be initialized to the
2507 * not signaled state.
2510 KeInitializeEvent(&event
->ne_event
, EVENT_TYPE_NOTIFY
, FALSE
);
2514 __stdcall
static void
2515 NdisSetEvent(ndis_event
*event
)
2517 KeSetEvent(&event
->ne_event
, 0, 0);
2521 __stdcall
static void
2522 NdisResetEvent(ndis_event
*event
)
2524 KeResetEvent(&event
->ne_event
);
2528 __stdcall
static uint8_t
2529 NdisWaitEvent(ndis_event
*event
, uint32_t msecs
)
2534 duetime
= ((int64_t)msecs
* -10000);
2536 rval
= KeWaitForSingleObject((nt_dispatch_header
*)event
,
2537 0, 0, TRUE
, msecs
? &duetime
: NULL
);
2539 if (rval
== STATUS_TIMEOUT
)
2545 __stdcall
static ndis_status
2546 NdisUnicodeStringToAnsiString(ndis_ansi_string
*dstr
, ndis_unicode_string
*sstr
)
2548 if (dstr
== NULL
|| sstr
== NULL
)
2549 return(NDIS_STATUS_FAILURE
);
2550 if (ndis_unicode_to_ascii(sstr
->us_buf
,
2551 sstr
->us_len
, &dstr
->nas_buf
))
2552 return(NDIS_STATUS_FAILURE
);
2553 dstr
->nas_len
= dstr
->nas_maxlen
= strlen(dstr
->nas_buf
);
2554 return (NDIS_STATUS_SUCCESS
);
2557 __stdcall
static ndis_status
2558 NdisAnsiStringToUnicodeString(ndis_unicode_string
*dstr
, ndis_ansi_string
*sstr
)
2561 if (dstr
== NULL
|| sstr
== NULL
)
2562 return(NDIS_STATUS_FAILURE
);
2563 str
= malloc(sstr
->nas_len
+ 1, M_DEVBUF
, M_NOWAIT
);
2565 return(NDIS_STATUS_FAILURE
);
2566 strncpy(str
, sstr
->nas_buf
, sstr
->nas_len
);
2567 *(str
+ sstr
->nas_len
) = '\0';
2568 if (ndis_ascii_to_unicode(str
, &dstr
->us_buf
)) {
2569 free(str
, M_DEVBUF
);
2570 return(NDIS_STATUS_FAILURE
);
2572 dstr
->us_len
= dstr
->us_maxlen
= sstr
->nas_len
* 2;
2573 free(str
, M_DEVBUF
);
2574 return (NDIS_STATUS_SUCCESS
);
2577 __stdcall
static ndis_status
2578 NdisMPciAssignResources(
2579 ndis_handle adapter
,
2581 ndis_resource_list
**list
)
2583 ndis_miniport_block
*block
;
2585 if (adapter
== NULL
|| list
== NULL
)
2586 return (NDIS_STATUS_FAILURE
);
2588 block
= (ndis_miniport_block
*)adapter
;
2589 *list
= block
->nmb_rlist
;
2591 return (NDIS_STATUS_SUCCESS
);
2594 __stdcall
static ndis_status
2595 NdisMRegisterInterrupt(
2596 ndis_miniport_interrupt
*intr
,
2597 ndis_handle adapter
,
2602 ndis_interrupt_mode imode
)
2604 ndis_miniport_block
*block
;
2608 intr
->ni_block
= adapter
;
2609 intr
->ni_isrreq
= reqisr
;
2610 intr
->ni_shared
= shared
;
2611 block
->nmb_interrupt
= intr
;
2613 KeInitializeSpinLock(&intr
->ni_dpccountlock
);
2615 return(NDIS_STATUS_SUCCESS
);
2618 __stdcall
static void
2619 NdisMDeregisterInterrupt(ndis_miniport_interrupt
*intr
)
2624 __stdcall
static void
2625 NdisMRegisterAdapterShutdownHandler(ndis_handle adapter
, void *shutdownctx
, ndis_shutdown_handler shutdownfunc
)
2627 ndis_miniport_block
*block
;
2628 ndis_miniport_characteristics
*chars
;
2629 struct ndis_softc
*sc
;
2631 if (adapter
== NULL
)
2634 block
= (ndis_miniport_block
*)adapter
;
2636 sc
= device_get_softc(block
->nmb_physdeviceobj
->do_devext
);
2637 #else /* __NetBSD__ */
2638 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
2640 chars
= sc
->ndis_chars
;
2642 chars
->nmc_shutdown_handler
= shutdownfunc
;
2643 chars
->nmc_rsvd0
= shutdownctx
;
2648 __stdcall
static void
2649 NdisMDeregisterAdapterShutdownHandler(ndis_handle adapter
)
2651 ndis_miniport_block
*block
;
2652 ndis_miniport_characteristics
*chars
;
2653 struct ndis_softc
*sc
;
2655 if (adapter
== NULL
)
2658 block
= (ndis_miniport_block
*)adapter
;
2660 sc
= device_get_softc(block
->nmb_physdeviceobj
->do_devext
);
2661 #else /* __NetBSD__ */
2662 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
2664 chars
= sc
->ndis_chars
;
2666 chars
->nmc_shutdown_handler
= NULL
;
2667 chars
->nmc_rsvd0
= NULL
;
2672 __stdcall
static uint32_t
2673 NDIS_BUFFER_TO_SPAN_PAGES(ndis_buffer
*buf
)
2677 if (MmGetMdlByteCount(buf
) == 0)
2679 return(SPAN_PAGES(MmGetMdlVirtualAddress(buf
),
2680 MmGetMdlByteCount(buf
)));
2683 __stdcall
static void
2684 NdisGetBufferPhysicalArraySize(ndis_buffer
*buf
, uint32_t *pages
)
2689 *pages
= NDIS_BUFFER_TO_SPAN_PAGES(buf
);
2693 __stdcall
static void
2694 NdisQueryBufferOffset(ndis_buffer
*buf
, uint32_t *off
, uint32_t *len
)
2699 *off
= MmGetMdlByteOffset(buf
);
2700 *len
= MmGetMdlByteCount(buf
);
2705 __stdcall
static void
2706 NdisMSleep(uint32_t usecs
)
2714 ndis_thsuspend(curthread
->td_proc
, NULL
, tvtohz(&tv
));
2716 ndis_thsuspend(curproc
, NULL
, tvtohz(&tv
));
2722 __stdcall
static uint32_t
2723 NdisReadPcmciaAttributeMemory(ndis_handle handle
, uint32_t offset
, void *buf
, uint32_t len
)
2725 struct ndis_softc
*sc
;
2726 ndis_miniport_block
*block
;
2727 bus_space_handle_t bh
;
2735 block
= (ndis_miniport_block
*)handle
;
2737 sc
= device_get_softc(block
->nmb_physdeviceobj
->do_devext
);
2738 #else /* __NetBSD__ */
2739 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
2744 bh
= rman_get_bushandle(sc
->ndis_res_am
);
2745 bt
= rman_get_bustag(sc
->ndis_res_am
);
2748 if ( sc
->ndis_iftype
== PCMCIABus
){
2749 bt
= sc
->ndis_res_pcmem
.memt
;
2750 bh
= sc
->ndis_res_pcmem
.memh
;
2751 } else { /* cardbus case */
2752 /* TODO what does it really wait for ? */
2753 bt
= sc
->ndis_res_mem
->res_tag
;
2754 bh
= sc
->ndis_res_mem
->res_handle
;
2758 for (i
= 0; i
< len
; i
++)
2759 dest
[i
] = bus_space_read_1(bt
, bh
, (offset
+ i
) * 2);
2764 __stdcall
static uint32_t
2765 NdisWritePcmciaAttributeMemory(ndis_handle handle
, uint32_t offset
, void *buf
, uint32_t len
)
2767 struct ndis_softc
*sc
;
2768 ndis_miniport_block
*block
;
2769 bus_space_handle_t bh
;
2777 block
= (ndis_miniport_block
*)handle
;
2779 sc
= device_get_softc(block
->nmb_physdeviceobj
->do_devext
);
2780 #else /* __NetBSD__ */
2781 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
2785 bh
= rman_get_bushandle(sc
->ndis_res_am
);
2786 bt
= rman_get_bustag(sc
->ndis_res_am
);
2788 if ( sc
->ndis_iftype
== PCMCIABus
){
2789 bt
= sc
->ndis_res_pcmem
.memt
;
2790 bh
= sc
->ndis_res_pcmem
.memh
;
2791 } else { /* cardbus case */
2792 /* TODO what does it really wait for ? */
2793 bt
= sc
->ndis_res_mem
->res_tag
;
2794 bh
= sc
->ndis_res_mem
->res_handle
;
2798 for (i
= 0; i
< len
; i
++)
2799 bus_space_write_1(bt
, bh
, (offset
+ i
) * 2, src
[i
]);
2804 __stdcall
static list_entry
*
2805 NdisInterlockedInsertHeadList(list_entry
*head
, list_entry
*entry
, ndis_spin_lock
*lock
)
2809 KeAcquireSpinLock(&lock
->nsl_spinlock
, &lock
->nsl_kirql
);
2810 flink
= head
->nle_flink
;
2811 entry
->nle_flink
= flink
;
2812 entry
->nle_blink
= head
;
2813 flink
->nle_blink
= entry
;
2814 head
->nle_flink
= entry
;
2815 KeReleaseSpinLock(&lock
->nsl_spinlock
, lock
->nsl_kirql
);
2820 __stdcall
static list_entry
*
2821 NdisInterlockedRemoveHeadList(list_entry
*head
, ndis_spin_lock
*lock
)
2826 KeAcquireSpinLock(&lock
->nsl_spinlock
, &lock
->nsl_kirql
);
2827 entry
= head
->nle_flink
;
2828 flink
= entry
->nle_flink
;
2829 head
->nle_flink
= flink
;
2830 flink
->nle_blink
= head
;
2831 KeReleaseSpinLock(&lock
->nsl_spinlock
, lock
->nsl_kirql
);
2836 __stdcall
static list_entry
*
2837 NdisInterlockedInsertTailList(list_entry
*head
, list_entry
*entry
, ndis_spin_lock
*lock
)
2841 KeAcquireSpinLock(&lock
->nsl_spinlock
, &lock
->nsl_kirql
);
2842 blink
= head
->nle_blink
;
2843 entry
->nle_flink
= head
;
2844 entry
->nle_blink
= blink
;
2845 blink
->nle_flink
= entry
;
2846 head
->nle_blink
= entry
;
2847 KeReleaseSpinLock(&lock
->nsl_spinlock
, lock
->nsl_kirql
);
2852 __stdcall
static uint8_t
2853 NdisMSynchronizeWithInterrupt(ndis_miniport_interrupt
*intr
, void *syncfunc
, void *syncctx
)
2855 __stdcall
uint8_t (*sync
)(void *);
2859 if (syncfunc
== NULL
|| syncctx
== NULL
)
2863 KeAcquireSpinLock(&intr
->ni_dpccountlock
, &irql
);
2864 rval
= MSCALL1(sync
, syncctx
);
2865 KeReleaseSpinLock(&intr
->ni_dpccountlock
, irql
);
2871 * Return the number of 100 nanosecond intervals since
2872 * January 1, 1601. (?!?!)
2874 __stdcall
static void
2875 NdisGetCurrentSystemTime(uint64_t *tval
)
2882 TIMEVAL_TO_TIMESPEC(&tv
,&ts
);
2887 *tval
= (uint64_t)ts
.tv_nsec
/ 100 + (uint64_t)ts
.tv_sec
* 10000000 +
2888 (uint64_t)11644473600ULL;
2894 * Return the number of milliseconds since the system booted.
2896 __stdcall
static void
2897 NdisGetSystemUpTime(uint32_t *tval
)
2899 *tval
= (ticks
* hz
) / 1000;
2904 __stdcall
static void
2905 NdisInitializeString(ndis_unicode_string
*dst
, char *src
)
2907 ndis_unicode_string
*u
;
2911 if (ndis_ascii_to_unicode(src
, &u
->us_buf
))
2913 u
->us_len
= u
->us_maxlen
= strlen(src
) * 2;
2917 __stdcall
static void
2918 NdisFreeString(ndis_unicode_string
*str
)
2922 if (str
->us_buf
!= NULL
)
2923 free(str
->us_buf
, M_DEVBUF
);
2924 free(str
, M_DEVBUF
);
2928 __stdcall
static ndis_status
2929 NdisMRemoveMiniport(ndis_handle
*adapter
)
2931 return(NDIS_STATUS_SUCCESS
);
2934 __stdcall
static void
2935 NdisInitAnsiString(ndis_ansi_string
*dst
, char *src
)
2937 ndis_ansi_string
*a
;
2943 a
->nas_len
= a
->nas_maxlen
= 0;
2947 a
->nas_len
= a
->nas_maxlen
= strlen(src
);
2953 __stdcall
static void
2954 NdisInitUnicodeString(ndis_unicode_string
*dst
, uint16_t *src
)
2956 ndis_unicode_string
*u
;
2963 u
->us_len
= u
->us_maxlen
= 0;
2970 u
->us_len
= u
->us_maxlen
= i
* 2;
2976 __stdcall
static void NdisMGetDeviceProperty(
2977 ndis_handle adapter
,
2978 device_object
**phydevobj
,
2979 device_object
**funcdevobj
,
2980 device_object
**nextdevobj
,
2981 cm_resource_list
*resources
,
2982 cm_resource_list
*transresources
)
2984 ndis_miniport_block
*block
;
2986 block
= (ndis_miniport_block
*)adapter
;
2988 if (phydevobj
!= NULL
)
2989 *phydevobj
= block
->nmb_physdeviceobj
;
2990 if (funcdevobj
!= NULL
)
2991 *funcdevobj
= block
->nmb_deviceobj
;
2992 if (nextdevobj
!= NULL
)
2993 *nextdevobj
= block
->nmb_nextdeviceobj
;
2998 __stdcall
static void
2999 NdisGetFirstBufferFromPacket(ndis_packet
*packet
, ndis_buffer
**buf
, void **firstva
, uint32_t *firstlen
, uint32_t *totlen
)
3003 tmp
= packet
->np_private
.npp_head
;
3007 *firstlen
= *totlen
= 0;
3009 *firstva
= MmGetMdlVirtualAddress(tmp
);
3010 *firstlen
= *totlen
= MmGetMdlByteCount(tmp
);
3011 for (tmp
= tmp
->mdl_next
; tmp
!= NULL
; tmp
= tmp
->mdl_next
)
3012 *totlen
+= MmGetMdlByteCount(tmp
);
3018 __stdcall
static void
3019 NdisGetFirstBufferFromPacketSafe(
3020 ndis_packet
*packet
,
3027 NdisGetFirstBufferFromPacket(packet
, buf
, firstva
, firstlen
, totlen
);
3032 ndis_find_sym(linker_file_t lf
, char *filename
, char *suffix
, void * *sym
)
3038 fullsym
= ExAllocatePoolWithTag(NonPagedPool
, MAXPATHLEN
, 0);
3039 if (fullsym
== NULL
)
3042 memset(fullsym
, 0, MAXPATHLEN
);
3043 strncpy(fullsym
, filename
, MAXPATHLEN
);
3044 if (strlen(filename
) < 4) {
3045 ExFreePool(fullsym
);
3049 /* If the filename has a .ko suffix, strip if off. */
3050 suf
= fullsym
+ (strlen(filename
) - 3);
3051 if (strcmp(suf
, ".ko") == 0)
3054 for (i
= 0; i
< strlen(fullsym
); i
++) {
3055 if (fullsym
[i
] == '.')
3058 fullsym
[i
] = tolower(fullsym
[i
]);
3060 strcat(fullsym
, suffix
);
3061 *sym
= linker_file_lookup_symbol(lf
, fullsym
, 0);
3062 ExFreePool(fullsym
);
3069 /* can also return NDIS_STATUS_RESOURCES/NDIS_STATUS_ERROR_READING_FILE */
3070 __stdcall
static void
3071 NdisOpenFile(ndis_status
*status
, ndis_handle
*filehandle
, uint32_t *filelength
, ndis_unicode_string
*filename
, ndis_physaddr highestaddr
)
3073 char *afilename
= NULL
;
3074 struct thread
*td
= curthread
;
3075 struct nameidata nd
;
3078 struct vattr
*vap
= &vat
;
3081 linker_file_t head
, lf
;
3082 void *kldstart
, *kldend
;
3084 ndis_unicode_to_ascii(filename
->us_buf
,
3085 filename
->us_len
, &afilename
);
3087 fh
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(ndis_fh
), 0);
3089 *status
= NDIS_STATUS_RESOURCES
;
3094 * During system bootstrap, it's impossible to load files
3095 * from the rootfs since it's not mounted yet. We therefore
3096 * offer the possibility of opening files that have been
3097 * preloaded as modules instead. Both choices will work
3098 * when kldloading a module from multiuser, but only the
3099 * module option will work during bootstrap. The module
3100 * loading option works by using the ndiscvt(8) utility
3101 * to convert the arbitrary file into a .ko using objcopy(1).
3102 * This file will contain two special symbols: filename_start
3103 * and filename_end. All we have to do is traverse the KLD
3104 * list in search of those symbols and we've found the file
3105 * data. As an added bonus, ndiscvt(8) will also generate
3106 * a normal .o file which can be linked statically with
3107 * the kernel. This means that the symbols will actual reside
3108 * in the kernel's symbol table, but that doesn't matter to
3109 * us since the kernel appears to us as just another module.
3113 * This is an evil trick for getting the head of the linked
3114 * file list, which is not exported from kern_linker.o. It
3115 * happens that linker file #1 is always the kernel, and is
3116 * always the first element in the list.
3119 head
= linker_find_file_by_id(1);
3120 for (lf
= head
; lf
!= NULL
; lf
= TAILQ_NEXT(lf
, link
)) {
3121 if (ndis_find_sym(lf
, afilename
, "_start", &kldstart
))
3123 if (ndis_find_sym(lf
, afilename
, "_end", &kldend
))
3127 fh
->nf_type
= NDIS_FH_TYPE_MODULE
;
3128 *filelength
= fh
->nf_maplen
= (kldend
- kldstart
) & 0xFFFFFFFF;
3130 free(afilename
, M_DEVBUF
);
3131 *status
= NDIS_STATUS_SUCCESS
;
3135 if (TAILQ_EMPTY(&mountlist
)) {
3137 *status
= NDIS_STATUS_FILE_NOT_FOUND
;
3138 printf("NDIS: could not find file %s in linker list\n",
3140 printf("NDIS: and no filesystems mounted yet, "
3141 "aborting NdisOpenFile()\n");
3142 free(afilename
, M_DEVBUF
);
3146 path
= ExAllocatePoolWithTag(NonPagedPool
, MAXPATHLEN
, 0);
3149 *status
= NDIS_STATUS_RESOURCES
;
3153 snprintf(path
, MAXPATHLEN
, "%s/%s", ndis_filepath
, afilename
);
3154 free(afilename
, M_DEVBUF
);
3158 /* Some threads don't have a current working directory. */
3160 if (td
->td_proc
->p_fd
->fd_rdir
== NULL
)
3161 td
->td_proc
->p_fd
->fd_rdir
= rootvnode
;
3162 if (td
->td_proc
->p_fd
->fd_cdir
== NULL
)
3163 td
->td_proc
->p_fd
->fd_cdir
= rootvnode
;
3165 /* freebsd-only code; don't modernize this - dholland */
3166 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE
, path
, td
);
3169 error
= vn_open(&nd
, &flags
, 0, -1);
3172 *status
= NDIS_STATUS_FILE_NOT_FOUND
;
3174 printf("NDIS: open file %s failed: %d\n", path
, error
);
3181 NDFREE(&nd
, NDF_ONLY_PNBUF
);
3183 /* Get the file size. */
3184 VOP_GETATTR(nd
.ni_vp
, vap
, td
->td_ucred
, td
);
3185 VOP_UNLOCK(nd
.ni_vp
, 0, td
);
3188 fh
->nf_vp
= nd
.ni_vp
;
3190 fh
->nf_type
= NDIS_FH_TYPE_VFS
;
3192 *filelength
= fh
->nf_maplen
= vap
->va_size
& 0xFFFFFFFF;
3193 *status
= NDIS_STATUS_SUCCESS
;
3198 __stdcall
static void
3199 NdisMapFile(ndis_status
*status
, void **mappedbuffer
, ndis_handle filehandle
)
3202 struct thread
*td
= curthread
;
3207 if (filehandle
== NULL
) {
3208 *status
= NDIS_STATUS_FAILURE
;
3212 fh
= (ndis_fh
*)filehandle
;
3214 if (fh
->nf_vp
== NULL
) {
3215 *status
= NDIS_STATUS_FAILURE
;
3219 if (fh
->nf_map
!= NULL
) {
3220 *status
= NDIS_STATUS_ALREADY_MAPPED
;
3224 if (fh
->nf_type
== NDIS_FH_TYPE_MODULE
) {
3226 if (ndis_find_sym(lf
, lf
->filename
, "_start", &kldstart
)) {
3227 *status
= NDIS_STATUS_FAILURE
;
3230 fh
->nf_map
= kldstart
;
3231 *status
= NDIS_STATUS_SUCCESS
;
3232 *mappedbuffer
= fh
->nf_map
;
3236 fh
->nf_map
= ExAllocatePoolWithTag(NonPagedPool
, fh
->nf_maplen
, 0);
3238 if (fh
->nf_map
== NULL
) {
3239 *status
= NDIS_STATUS_RESOURCES
;
3244 error
= vn_rdwr(UIO_READ
, fh
->nf_vp
, fh
->nf_map
, fh
->nf_maplen
, 0,
3245 UIO_SYSSPACE
, 0, td
->td_ucred
, NOCRED
, &resid
, td
);
3249 *status
= NDIS_STATUS_FAILURE
;
3251 *status
= NDIS_STATUS_SUCCESS
;
3252 *mappedbuffer
= fh
->nf_map
;
3258 __stdcall
static void
3259 NdisUnmapFile(ndis_handle filehandle
)
3262 fh
= (ndis_fh
*)filehandle
;
3264 if (fh
->nf_map
== NULL
)
3267 if (fh
->nf_type
== NDIS_FH_TYPE_VFS
)
3268 ExFreePool(fh
->nf_map
);
3274 __stdcall
static void
3275 NdisCloseFile(ndis_handle filehandle
)
3277 struct thread
*td
= curthread
;
3280 if (filehandle
== NULL
)
3283 fh
= (ndis_fh
*)filehandle
;
3284 if (fh
->nf_map
!= NULL
) {
3285 if (fh
->nf_type
== NDIS_FH_TYPE_VFS
)
3286 ExFreePool(fh
->nf_map
);
3290 if (fh
->nf_vp
== NULL
)
3293 if (fh
->nf_type
== NDIS_FH_TYPE_VFS
) {
3295 vn_close(fh
->nf_vp
, FREAD
, td
->td_ucred
, td
);
3304 #endif /* __FreeBSD__ */
3305 __stdcall
static uint8_t
3306 NdisSystemProcessorCount(void)
3315 typedef void (*ndis_statusdone_handler
)(ndis_handle
);
3316 typedef void (*ndis_status_handler
)(ndis_handle
, ndis_status
,
3319 __stdcall
static void
3320 NdisMIndicateStatusComplete(ndis_handle adapter
)
3322 ndis_miniport_block
*block
;
3323 __stdcall ndis_statusdone_handler statusdonefunc
;
3325 block
= (ndis_miniport_block
*)adapter
;
3326 statusdonefunc
= block
->nmb_statusdone_func
;
3328 MSCALL1(statusdonefunc
, adapter
);
3332 __stdcall
static void
3333 NdisMIndicateStatus(ndis_handle adapter
, ndis_status status
, void *sbuf
, uint32_t slen
)
3335 ndis_miniport_block
*block
;
3336 __stdcall ndis_status_handler statusfunc
;
3338 block
= (ndis_miniport_block
*)adapter
;
3339 statusfunc
= block
->nmb_status_func
;
3341 MSCALL4(statusfunc
, adapter
, status
, sbuf
, slen
);
3346 ndis_workfunc(void *ctx
)
3348 ndis_work_item
*work
;
3349 __stdcall ndis_proc workfunc
;
3352 workfunc
= work
->nwi_func
;
3353 MSCALL2(workfunc
, work
, work
->nwi_ctx
);
3357 __stdcall
static ndis_status
3358 NdisScheduleWorkItem(ndis_work_item
*work
)
3360 ndis_sched(ndis_workfunc
, work
, NDIS_TASKQUEUE
);
3361 return(NDIS_STATUS_SUCCESS
);
3364 __stdcall
static void
3365 NdisCopyFromPacketToPacket(ndis_packet
*dpkt
, uint32_t doff
, uint32_t reqlen
, ndis_packet
*spkt
, uint32_t soff
, uint32_t *cpylen
)
3367 ndis_buffer
*src
, *dst
;
3369 int resid
, copied
, len
, scnt
, dcnt
;
3373 src
= spkt
->np_private
.npp_head
;
3374 dst
= dpkt
->np_private
.npp_head
;
3376 sptr
= MmGetMdlVirtualAddress(src
);
3377 dptr
= MmGetMdlVirtualAddress(dst
);
3378 scnt
= MmGetMdlByteCount(src
);
3379 dcnt
= MmGetMdlByteCount(dst
);
3382 if (MmGetMdlByteCount(src
) > soff
) {
3384 scnt
= MmGetMdlByteCount(src
)- soff
;
3387 soff
-= MmGetMdlByteCount(src
);
3388 src
= src
->mdl_next
;
3391 sptr
= MmGetMdlVirtualAddress(src
);
3395 if (MmGetMdlByteCount(dst
) > doff
) {
3397 dcnt
= MmGetMdlByteCount(dst
) - doff
;
3400 doff
-= MmGetMdlByteCount(dst
);
3401 dst
= dst
->mdl_next
;
3404 dptr
= MmGetMdlVirtualAddress(dst
);
3418 memcpy( dptr
, sptr
, len
);
3427 dst
= dst
->mdl_next
;
3430 dptr
= MmGetMdlVirtualAddress(dst
);
3431 dcnt
= MmGetMdlByteCount(dst
);
3436 src
= src
->mdl_next
;
3439 sptr
= MmGetMdlVirtualAddress(src
);
3440 scnt
= MmGetMdlByteCount(src
);
3448 __stdcall
static void
3449 NdisCopyFromPacketToPacketSafe(
3458 NdisCopyFromPacketToPacket(dpkt
, doff
, reqlen
, spkt
, soff
, cpylen
);
3462 __stdcall
static ndis_status
3463 NdisMRegisterDevice(
3465 ndis_unicode_string
*devname
,
3466 ndis_unicode_string
*symname
,
3467 driver_dispatch
*majorfuncs
[],
3469 ndis_handle
*devhandle
)
3471 ndis_miniport_block
*block
;
3473 block
= (ndis_miniport_block
*)handle
;
3474 *devobj
= block
->nmb_deviceobj
;
3475 *devhandle
= handle
;
3477 return(NDIS_STATUS_SUCCESS
);
3480 __stdcall
static ndis_status
3481 NdisMDeregisterDevice(ndis_handle handle
)
3483 return(NDIS_STATUS_SUCCESS
);
3486 __stdcall
static ndis_status
3487 NdisMQueryAdapterInstanceName(ndis_unicode_string
*name
, ndis_handle handle
)
3489 ndis_miniport_block
*block
;
3492 block
= (ndis_miniport_block
*)handle
;
3493 dev
= block
->nmb_physdeviceobj
->do_devext
;
3495 ndis_ascii_to_unicode(__DECONST(char *,
3496 device_get_nameunit(dev
)), &name
->us_buf
);
3497 name
->us_len
= strlen(device_get_nameunit(dev
)) * 2;
3499 return(NDIS_STATUS_SUCCESS
);
3502 __stdcall
static void
3503 NdisMRegisterUnloadHandler(
3510 __stdcall
static void
3513 printf ("NDIS dummy called...\n");
3517 image_patch_table ndis_functbl
[] = {
3518 IMPORT_FUNC(NdisCopyFromPacketToPacket
),
3519 IMPORT_FUNC(NdisCopyFromPacketToPacketSafe
),
3520 IMPORT_FUNC(NdisScheduleWorkItem
),
3521 IMPORT_FUNC(NdisMIndicateStatusComplete
),
3522 IMPORT_FUNC(NdisMIndicateStatus
),
3523 IMPORT_FUNC(NdisSystemProcessorCount
),
3524 IMPORT_FUNC(NdisUnchainBufferAtBack
),
3525 IMPORT_FUNC(NdisGetFirstBufferFromPacket
),
3526 IMPORT_FUNC(NdisGetFirstBufferFromPacketSafe
),
3527 IMPORT_FUNC(NdisGetBufferPhysicalArraySize
),
3528 IMPORT_FUNC(NdisMGetDeviceProperty
),
3529 IMPORT_FUNC(NdisInitAnsiString
),
3530 IMPORT_FUNC(NdisInitUnicodeString
),
3531 IMPORT_FUNC(NdisWriteConfiguration
),
3532 IMPORT_FUNC(NdisAnsiStringToUnicodeString
),
3533 IMPORT_FUNC(NdisTerminateWrapper
),
3534 IMPORT_FUNC(NdisOpenConfigurationKeyByName
),
3535 IMPORT_FUNC(NdisOpenConfigurationKeyByIndex
),
3536 IMPORT_FUNC(NdisMRemoveMiniport
),
3537 IMPORT_FUNC(NdisInitializeString
),
3538 IMPORT_FUNC(NdisFreeString
),
3539 IMPORT_FUNC(NdisGetCurrentSystemTime
),
3540 IMPORT_FUNC(NdisGetSystemUpTime
),
3541 IMPORT_FUNC(NdisMSynchronizeWithInterrupt
),
3542 IMPORT_FUNC(NdisMAllocateSharedMemoryAsync
),
3543 IMPORT_FUNC(NdisInterlockedInsertHeadList
),
3544 IMPORT_FUNC(NdisInterlockedInsertTailList
),
3545 IMPORT_FUNC(NdisInterlockedRemoveHeadList
),
3546 IMPORT_FUNC(NdisInitializeWrapper
),
3547 IMPORT_FUNC(NdisMRegisterMiniport
),
3548 IMPORT_FUNC(NdisAllocateMemoryWithTag
),
3549 IMPORT_FUNC(NdisAllocateMemory
),
3550 IMPORT_FUNC(NdisMSetAttributesEx
),
3551 IMPORT_FUNC(NdisCloseConfiguration
),
3552 IMPORT_FUNC(NdisReadConfiguration
),
3553 IMPORT_FUNC(NdisOpenConfiguration
),
3554 IMPORT_FUNC(NdisAcquireSpinLock
),
3555 IMPORT_FUNC(NdisReleaseSpinLock
),
3556 IMPORT_FUNC(NdisDprAcquireSpinLock
),
3557 IMPORT_FUNC(NdisDprReleaseSpinLock
),
3558 IMPORT_FUNC(NdisAllocateSpinLock
),
3559 IMPORT_FUNC(NdisFreeSpinLock
),
3560 IMPORT_FUNC(NdisFreeMemory
),
3561 IMPORT_FUNC(NdisReadPciSlotInformation
),
3562 IMPORT_FUNC(NdisWritePciSlotInformation
),
3563 IMPORT_FUNC_MAP(NdisImmediateReadPciSlotInformation
,
3564 NdisReadPciSlotInformation
),
3565 IMPORT_FUNC_MAP(NdisImmediateWritePciSlotInformation
,
3566 NdisWritePciSlotInformation
),
3567 IMPORT_FUNC(NdisWriteErrorLogEntry
),
3568 IMPORT_FUNC(NdisMStartBufferPhysicalMapping
),
3569 IMPORT_FUNC(NdisMCompleteBufferPhysicalMapping
),
3570 IMPORT_FUNC(NdisMInitializeTimer
),
3571 IMPORT_FUNC(NdisInitializeTimer
),
3572 IMPORT_FUNC(NdisSetTimer
),
3573 IMPORT_FUNC(NdisMCancelTimer
),
3574 IMPORT_FUNC_MAP(NdisCancelTimer
, NdisMCancelTimer
),
3575 IMPORT_FUNC(NdisMSetPeriodicTimer
),
3576 IMPORT_FUNC(NdisMQueryAdapterResources
),
3577 IMPORT_FUNC(NdisMRegisterIoPortRange
),
3578 IMPORT_FUNC(NdisMDeregisterIoPortRange
),
3579 IMPORT_FUNC(NdisReadNetworkAddress
),
3580 IMPORT_FUNC(NdisQueryMapRegisterCount
),
3581 IMPORT_FUNC(NdisMAllocateMapRegisters
),
3582 IMPORT_FUNC(NdisMFreeMapRegisters
),
3583 IMPORT_FUNC(NdisMAllocateSharedMemory
),
3584 IMPORT_FUNC(NdisMMapIoSpace
),
3585 IMPORT_FUNC(NdisMUnmapIoSpace
),
3586 IMPORT_FUNC(NdisGetCacheFillSize
),
3587 IMPORT_FUNC(NdisMGetDmaAlignment
),
3588 IMPORT_FUNC(NdisMInitializeScatterGatherDma
),
3589 IMPORT_FUNC(NdisAllocatePacketPool
),
3590 IMPORT_FUNC(NdisAllocatePacketPoolEx
),
3591 IMPORT_FUNC(NdisAllocatePacket
),
3592 IMPORT_FUNC(NdisFreePacket
),
3593 IMPORT_FUNC(NdisFreePacketPool
),
3594 IMPORT_FUNC_MAP(NdisDprAllocatePacket
, NdisAllocatePacket
),
3595 IMPORT_FUNC_MAP(NdisDprFreePacket
, NdisFreePacket
),
3596 IMPORT_FUNC(NdisAllocateBufferPool
),
3597 IMPORT_FUNC(NdisAllocateBuffer
),
3598 IMPORT_FUNC(NdisQueryBuffer
),
3599 IMPORT_FUNC(NdisQueryBufferSafe
),
3600 IMPORT_FUNC(NdisBufferVirtualAddress
),
3601 IMPORT_FUNC(NdisBufferVirtualAddressSafe
),
3602 IMPORT_FUNC(NdisBufferLength
),
3603 IMPORT_FUNC(NdisFreeBuffer
),
3604 IMPORT_FUNC(NdisFreeBufferPool
),
3605 IMPORT_FUNC(NdisInterlockedIncrement
),
3606 IMPORT_FUNC(NdisInterlockedDecrement
),
3607 IMPORT_FUNC(NdisInitializeEvent
),
3608 IMPORT_FUNC(NdisSetEvent
),
3609 IMPORT_FUNC(NdisResetEvent
),
3610 IMPORT_FUNC(NdisWaitEvent
),
3611 IMPORT_FUNC(NdisUnicodeStringToAnsiString
),
3612 IMPORT_FUNC(NdisMPciAssignResources
),
3613 IMPORT_FUNC(NdisMFreeSharedMemory
),
3614 IMPORT_FUNC(NdisMRegisterInterrupt
),
3615 IMPORT_FUNC(NdisMDeregisterInterrupt
),
3616 IMPORT_FUNC(NdisMRegisterAdapterShutdownHandler
),
3617 IMPORT_FUNC(NdisMDeregisterAdapterShutdownHandler
),
3618 IMPORT_FUNC(NDIS_BUFFER_TO_SPAN_PAGES
),
3619 IMPORT_FUNC(NdisQueryBufferOffset
),
3620 IMPORT_FUNC(NdisAdjustBufferLength
),
3621 IMPORT_FUNC(NdisPacketPoolUsage
),
3622 IMPORT_FUNC(NdisMSleep
),
3623 IMPORT_FUNC(NdisUnchainBufferAtFront
),
3624 IMPORT_FUNC(NdisReadPcmciaAttributeMemory
),
3625 IMPORT_FUNC(NdisWritePcmciaAttributeMemory
),
3627 IMPORT_FUNC(NdisOpenFile
),
3628 IMPORT_FUNC(NdisMapFile
),
3629 IMPORT_FUNC(NdisUnmapFile
),
3630 IMPORT_FUNC(NdisCloseFile
),
3632 IMPORT_FUNC(NdisMRegisterDevice
),
3633 IMPORT_FUNC(NdisMDeregisterDevice
),
3634 IMPORT_FUNC(NdisMQueryAdapterInstanceName
),
3635 IMPORT_FUNC(NdisMRegisterUnloadHandler
),
3636 IMPORT_FUNC(ndis_timercall
),
3639 * This last entry is a catch-all for any function we haven't
3640 * implemented yet. The PE import list patching routine will
3641 * use it for any function that doesn't have an explicit match
3645 { NULL
, (FUNC
)dummy
, NULL
},
3649 { NULL
, NULL
, NULL
}