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