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