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