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