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