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