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