subr_ndis.c revision 144239
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 144239 2005-03-28 17:06: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 while (sh) { 1590 if (sh->ndis_saddr == vaddr) 1591 break; 1592 prev = sh; 1593 sh = sh->ndis_next; 1594 } 1595 1596 bus_dmamap_unload(sh->ndis_stag, sh->ndis_smap); 1597 bus_dmamem_free(sh->ndis_stag, vaddr, sh->ndis_smap); 1598 bus_dma_tag_destroy(sh->ndis_stag); 1599 1600 if (sh == sc->ndis_shlist) 1601 sc->ndis_shlist = sh->ndis_next; 1602 else 1603 prev->ndis_next = sh->ndis_next; 1604 1605 free(sh, M_DEVBUF); 1606 1607 return; 1608} 1609 1610__stdcall static ndis_status 1611NdisMMapIoSpace(vaddr, adapter, paddr, len) 1612 void **vaddr; 1613 ndis_handle adapter; 1614 ndis_physaddr paddr; 1615 uint32_t len; 1616{ 1617 ndis_miniport_block *block; 1618 struct ndis_softc *sc; 1619 1620 if (adapter == NULL) 1621 return(NDIS_STATUS_FAILURE); 1622 1623 block = (ndis_miniport_block *)adapter; 1624 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1625 1626 if (sc->ndis_res_mem != NULL && 1627 paddr.np_quad == rman_get_start(sc->ndis_res_mem)) 1628 *vaddr = (void *)rman_get_virtual(sc->ndis_res_mem); 1629 else if (sc->ndis_res_altmem != NULL && 1630 paddr.np_quad == rman_get_start(sc->ndis_res_altmem)) 1631 *vaddr = (void *)rman_get_virtual(sc->ndis_res_altmem); 1632 else if (sc->ndis_res_am != NULL && 1633 paddr.np_quad == rman_get_start(sc->ndis_res_am)) 1634 *vaddr = (void *)rman_get_virtual(sc->ndis_res_am); 1635 else 1636 return(NDIS_STATUS_FAILURE); 1637 1638 return(NDIS_STATUS_SUCCESS); 1639} 1640 1641__stdcall static void 1642NdisMUnmapIoSpace(adapter, vaddr, len) 1643 ndis_handle adapter; 1644 void *vaddr; 1645 uint32_t len; 1646{ 1647 return; 1648} 1649 1650__stdcall static uint32_t 1651NdisGetCacheFillSize(void) 1652{ 1653 return(128); 1654} 1655 1656__stdcall static uint32_t 1657NdisMGetDmaAlignment(handle) 1658 ndis_handle handle; 1659{ 1660 return(128); 1661} 1662 1663/* 1664 * NDIS has two methods for dealing with NICs that support DMA. 1665 * One is to just pass packets to the driver and let it call 1666 * NdisMStartBufferPhysicalMapping() to map each buffer in the packet 1667 * all by itself, and the other is to let the NDIS library handle the 1668 * buffer mapping internally, and hand the driver an already populated 1669 * scatter/gather fragment list. If the driver calls 1670 * NdisMInitializeScatterGatherDma(), it wants to use the latter 1671 * method. 1672 */ 1673 1674__stdcall static ndis_status 1675NdisMInitializeScatterGatherDma(adapter, is64, maxphysmap) 1676 ndis_handle adapter; 1677 uint8_t is64; 1678 uint32_t maxphysmap; 1679{ 1680 struct ndis_softc *sc; 1681 ndis_miniport_block *block; 1682 int error; 1683 1684 if (adapter == NULL) 1685 return(NDIS_STATUS_FAILURE); 1686 block = (ndis_miniport_block *)adapter; 1687 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1688 1689 /* Don't do this twice. */ 1690 if (sc->ndis_sc == 1) 1691 return(NDIS_STATUS_SUCCESS); 1692 1693 error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0, 1694 BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 1695 MCLBYTES * NDIS_MAXSEG, NDIS_MAXSEG, MCLBYTES, BUS_DMA_ALLOCNOW, 1696 NULL, NULL, &sc->ndis_ttag); 1697 1698 sc->ndis_sc = 1; 1699 1700 return(NDIS_STATUS_SUCCESS); 1701} 1702 1703__stdcall void 1704NdisAllocatePacketPool(status, pool, descnum, protrsvdlen) 1705 ndis_status *status; 1706 ndis_handle *pool; 1707 uint32_t descnum; 1708 uint32_t protrsvdlen; 1709{ 1710 ndis_packet *cur; 1711 int i; 1712 1713 *pool = malloc((sizeof(ndis_packet) + protrsvdlen) * 1714 ((descnum + NDIS_POOL_EXTRA) + 1), 1715 M_DEVBUF, M_NOWAIT|M_ZERO); 1716 1717 if (*pool == NULL) { 1718 *status = NDIS_STATUS_RESOURCES; 1719 return; 1720 } 1721 1722 cur = (ndis_packet *)*pool; 1723 KeInitializeSpinLock(&cur->np_lock); 1724 cur->np_private.npp_flags = 0x1; /* mark the head of the list */ 1725 cur->np_private.npp_totlen = 0; /* init deletetion flag */ 1726 for (i = 0; i < (descnum + NDIS_POOL_EXTRA); i++) { 1727 cur->np_private.npp_head = (ndis_handle)(cur + 1); 1728 cur++; 1729 } 1730 1731 *status = NDIS_STATUS_SUCCESS; 1732 return; 1733} 1734 1735__stdcall void 1736NdisAllocatePacketPoolEx(status, pool, descnum, oflowdescnum, protrsvdlen) 1737 ndis_status *status; 1738 ndis_handle *pool; 1739 uint32_t descnum; 1740 uint32_t oflowdescnum; 1741 uint32_t protrsvdlen; 1742{ 1743 return(NdisAllocatePacketPool(status, pool, 1744 descnum + oflowdescnum, protrsvdlen)); 1745} 1746 1747__stdcall uint32_t 1748NdisPacketPoolUsage(pool) 1749 ndis_handle pool; 1750{ 1751 ndis_packet *head; 1752 uint8_t irql; 1753 uint32_t cnt; 1754 1755 head = (ndis_packet *)pool; 1756 KeAcquireSpinLock(&head->np_lock, &irql); 1757 cnt = head->np_private.npp_count; 1758 KeReleaseSpinLock(&head->np_lock, irql); 1759 1760 return(cnt); 1761} 1762 1763__stdcall void 1764NdisFreePacketPool(pool) 1765 ndis_handle pool; 1766{ 1767 ndis_packet *head; 1768 uint8_t irql; 1769 1770 head = pool; 1771 1772 /* Mark this pool as 'going away.' */ 1773 1774 KeAcquireSpinLock(&head->np_lock, &irql); 1775 head->np_private.npp_totlen = 1; 1776 1777 /* If there are no buffers loaned out, destroy the pool. */ 1778 1779 if (head->np_private.npp_count == 0) { 1780 KeReleaseSpinLock(&head->np_lock, irql); 1781 free(pool, M_DEVBUF); 1782 } else { 1783 printf("NDIS: buggy driver deleting active packet pool!\n"); 1784 KeReleaseSpinLock(&head->np_lock, irql); 1785 } 1786 1787 return; 1788} 1789 1790__stdcall void 1791NdisAllocatePacket(status, packet, pool) 1792 ndis_status *status; 1793 ndis_packet **packet; 1794 ndis_handle pool; 1795{ 1796 ndis_packet *head, *pkt; 1797 uint8_t irql; 1798 1799 head = (ndis_packet *)pool; 1800 KeAcquireSpinLock(&head->np_lock, &irql); 1801 1802 if (head->np_private.npp_flags != 0x1) { 1803 *status = NDIS_STATUS_FAILURE; 1804 KeReleaseSpinLock(&head->np_lock, irql); 1805 return; 1806 } 1807 1808 /* 1809 * If this pool is marked as 'going away' don't allocate any 1810 * more packets out of it. 1811 */ 1812 1813 if (head->np_private.npp_totlen) { 1814 *status = NDIS_STATUS_FAILURE; 1815 KeReleaseSpinLock(&head->np_lock, irql); 1816 return; 1817 } 1818 1819 pkt = (ndis_packet *)head->np_private.npp_head; 1820 1821 if (pkt == NULL) { 1822 *status = NDIS_STATUS_RESOURCES; 1823 KeReleaseSpinLock(&head->np_lock, irql); 1824 return; 1825 } 1826 1827 head->np_private.npp_head = pkt->np_private.npp_head; 1828 1829 pkt->np_private.npp_head = pkt->np_private.npp_tail = NULL; 1830 /* Save pointer to the pool. */ 1831 pkt->np_private.npp_pool = head; 1832 1833 /* Set the oob offset pointer. Lots of things expect this. */ 1834 pkt->np_private.npp_packetooboffset = 1835 offsetof(ndis_packet, np_oob); 1836 1837 /* 1838 * We must initialize the packet flags correctly in order 1839 * for the NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO() and 1840 * NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO() macros to work 1841 * correctly. 1842 */ 1843 pkt->np_private.npp_ndispktflags = NDIS_PACKET_ALLOCATED_BY_NDIS; 1844 pkt->np_private.npp_validcounts = FALSE; 1845 1846 *packet = pkt; 1847 1848 head->np_private.npp_count++; 1849 *status = NDIS_STATUS_SUCCESS; 1850 1851 KeReleaseSpinLock(&head->np_lock, irql); 1852 1853 return; 1854} 1855 1856__stdcall void 1857NdisFreePacket(packet) 1858 ndis_packet *packet; 1859{ 1860 ndis_packet *head; 1861 uint8_t irql; 1862 1863 if (packet == NULL || packet->np_private.npp_pool == NULL) 1864 return; 1865 1866 head = packet->np_private.npp_pool; 1867 KeAcquireSpinLock(&head->np_lock, &irql); 1868 1869 if (head->np_private.npp_flags != 0x1) { 1870 KeReleaseSpinLock(&head->np_lock, irql); 1871 return; 1872 } 1873 1874 packet->np_private.npp_head = head->np_private.npp_head; 1875 head->np_private.npp_head = (ndis_buffer *)packet; 1876 head->np_private.npp_count--; 1877 1878 /* 1879 * If the pool has been marked for deletion and there are 1880 * no more packets outstanding, nuke the pool. 1881 */ 1882 1883 if (head->np_private.npp_totlen && head->np_private.npp_count == 0) { 1884 KeReleaseSpinLock(&head->np_lock, irql); 1885 free(head, M_DEVBUF); 1886 } else 1887 KeReleaseSpinLock(&head->np_lock, irql); 1888 1889 return; 1890} 1891 1892__stdcall static void 1893NdisUnchainBufferAtFront(packet, buf) 1894 ndis_packet *packet; 1895 ndis_buffer **buf; 1896{ 1897 ndis_packet_private *priv; 1898 1899 if (packet == NULL || buf == NULL) 1900 return; 1901 1902 priv = &packet->np_private; 1903 1904 priv->npp_validcounts = FALSE; 1905 1906 if (priv->npp_head == priv->npp_tail) { 1907 *buf = priv->npp_head; 1908 priv->npp_head = priv->npp_tail = NULL; 1909 } else { 1910 *buf = priv->npp_head; 1911 priv->npp_head = (*buf)->mdl_next; 1912 } 1913 1914 return; 1915} 1916 1917__stdcall static void 1918NdisUnchainBufferAtBack(packet, buf) 1919 ndis_packet *packet; 1920 ndis_buffer **buf; 1921{ 1922 ndis_packet_private *priv; 1923 ndis_buffer *tmp; 1924 1925 if (packet == NULL || buf == NULL) 1926 return; 1927 1928 priv = &packet->np_private; 1929 1930 priv->npp_validcounts = FALSE; 1931 1932 if (priv->npp_head == priv->npp_tail) { 1933 *buf = priv->npp_head; 1934 priv->npp_head = priv->npp_tail = NULL; 1935 } else { 1936 *buf = priv->npp_tail; 1937 tmp = priv->npp_head; 1938 while (tmp->mdl_next != priv->npp_tail) 1939 tmp = tmp->mdl_next; 1940 priv->npp_tail = tmp; 1941 tmp->mdl_next = NULL; 1942 } 1943 1944 return; 1945} 1946 1947/* 1948 * The NDIS "buffer" is really an MDL (memory descriptor list) 1949 * which is used to describe a buffer in a way that allows it 1950 * to mapped into different contexts. We have to be careful how 1951 * we handle them: in some versions of Windows, the NdisFreeBuffer() 1952 * routine is an actual function in the NDIS API, but in others 1953 * it's just a macro wrapper around IoFreeMdl(). There's really 1954 * no way to use the 'descnum' parameter to count how many 1955 * "buffers" are allocated since in order to use IoFreeMdl() to 1956 * dispose of a buffer, we have to use IoAllocateMdl() to allocate 1957 * them, and IoAllocateMdl() just grabs them out of the heap. 1958 */ 1959 1960__stdcall static void 1961NdisAllocateBufferPool(status, pool, descnum) 1962 ndis_status *status; 1963 ndis_handle *pool; 1964 uint32_t descnum; 1965{ 1966 /* 1967 * The only thing we can really do here is verify that descnum 1968 * is a reasonable value, but I really don't know what to check 1969 * it against. 1970 */ 1971 1972 *pool = NonPagedPool; 1973 *status = NDIS_STATUS_SUCCESS; 1974 return; 1975} 1976 1977__stdcall static void 1978NdisFreeBufferPool(pool) 1979 ndis_handle pool; 1980{ 1981 return; 1982} 1983 1984__stdcall static void 1985NdisAllocateBuffer(status, buffer, pool, vaddr, len) 1986 ndis_status *status; 1987 ndis_buffer **buffer; 1988 ndis_handle pool; 1989 void *vaddr; 1990 uint32_t len; 1991{ 1992 ndis_buffer *buf; 1993 1994 buf = IoAllocateMdl(vaddr, len, FALSE, FALSE, NULL); 1995 if (buf == NULL) { 1996 *status = NDIS_STATUS_RESOURCES; 1997 return; 1998 } 1999 2000 *buffer = buf; 2001 *status = NDIS_STATUS_SUCCESS; 2002 2003 return; 2004} 2005 2006__stdcall static void 2007NdisFreeBuffer(buf) 2008 ndis_buffer *buf; 2009{ 2010 IoFreeMdl(buf); 2011 return; 2012} 2013 2014/* Aw c'mon. */ 2015 2016__stdcall static uint32_t 2017NdisBufferLength(buf) 2018 ndis_buffer *buf; 2019{ 2020 return(MmGetMdlByteCount(buf)); 2021} 2022 2023/* 2024 * Get the virtual address and length of a buffer. 2025 * Note: the vaddr argument is optional. 2026 */ 2027 2028__stdcall static void 2029NdisQueryBuffer(buf, vaddr, len) 2030 ndis_buffer *buf; 2031 void **vaddr; 2032 uint32_t *len; 2033{ 2034 if (vaddr != NULL) 2035 *vaddr = MmGetMdlVirtualAddress(buf); 2036 *len = MmGetMdlByteCount(buf); 2037 2038 return; 2039} 2040 2041/* Same as above -- we don't care about the priority. */ 2042 2043__stdcall static void 2044NdisQueryBufferSafe(buf, vaddr, len, prio) 2045 ndis_buffer *buf; 2046 void **vaddr; 2047 uint32_t *len; 2048 uint32_t prio; 2049{ 2050 if (vaddr != NULL) 2051 *vaddr = MmGetMdlVirtualAddress(buf); 2052 *len = MmGetMdlByteCount(buf); 2053 2054 return; 2055} 2056 2057/* Damnit Microsoft!! How many ways can you do the same thing?! */ 2058 2059__stdcall static void * 2060NdisBufferVirtualAddress(buf) 2061 ndis_buffer *buf; 2062{ 2063 return(MmGetMdlVirtualAddress(buf)); 2064} 2065 2066__stdcall static void * 2067NdisBufferVirtualAddressSafe(buf, prio) 2068 ndis_buffer *buf; 2069 uint32_t prio; 2070{ 2071 return(MmGetMdlVirtualAddress(buf)); 2072} 2073 2074__stdcall static void 2075NdisAdjustBufferLength(buf, len) 2076 ndis_buffer *buf; 2077 int len; 2078{ 2079 MmGetMdlByteCount(buf) = len; 2080 2081 return; 2082} 2083 2084__stdcall static uint32_t 2085NdisInterlockedIncrement(addend) 2086 uint32_t *addend; 2087{ 2088 atomic_add_long((u_long *)addend, 1); 2089 return(*addend); 2090} 2091 2092__stdcall static uint32_t 2093NdisInterlockedDecrement(addend) 2094 uint32_t *addend; 2095{ 2096 atomic_subtract_long((u_long *)addend, 1); 2097 return(*addend); 2098} 2099 2100__stdcall static void 2101NdisInitializeEvent(event) 2102 ndis_event *event; 2103{ 2104 /* 2105 * NDIS events are always notification 2106 * events, and should be initialized to the 2107 * not signaled state. 2108 */ 2109 2110 KeInitializeEvent(&event->ne_event, EVENT_TYPE_NOTIFY, FALSE); 2111 return; 2112} 2113 2114__stdcall static void 2115NdisSetEvent(event) 2116 ndis_event *event; 2117{ 2118 KeSetEvent(&event->ne_event, 0, 0); 2119 return; 2120} 2121 2122__stdcall static void 2123NdisResetEvent(event) 2124 ndis_event *event; 2125{ 2126 KeResetEvent(&event->ne_event); 2127 return; 2128} 2129 2130__stdcall static uint8_t 2131NdisWaitEvent(event, msecs) 2132 ndis_event *event; 2133 uint32_t msecs; 2134{ 2135 int64_t duetime; 2136 uint32_t rval; 2137 2138 duetime = ((int64_t)msecs * -10000); 2139 2140 rval = KeWaitForSingleObject((nt_dispatch_header *)event, 2141 0, 0, TRUE, msecs ? &duetime : NULL); 2142 2143 if (rval == STATUS_TIMEOUT) 2144 return(FALSE); 2145 2146 return(TRUE); 2147} 2148 2149__stdcall static ndis_status 2150NdisUnicodeStringToAnsiString(dstr, sstr) 2151 ndis_ansi_string *dstr; 2152 ndis_unicode_string *sstr; 2153{ 2154 if (dstr == NULL || sstr == NULL) 2155 return(NDIS_STATUS_FAILURE); 2156 if (ndis_unicode_to_ascii(sstr->us_buf, 2157 sstr->us_len, &dstr->nas_buf)) 2158 return(NDIS_STATUS_FAILURE); 2159 dstr->nas_len = dstr->nas_maxlen = strlen(dstr->nas_buf); 2160 return (NDIS_STATUS_SUCCESS); 2161} 2162 2163__stdcall static ndis_status 2164NdisAnsiStringToUnicodeString(dstr, sstr) 2165 ndis_unicode_string *dstr; 2166 ndis_ansi_string *sstr; 2167{ 2168 char *str; 2169 if (dstr == NULL || sstr == NULL) 2170 return(NDIS_STATUS_FAILURE); 2171 str = malloc(sstr->nas_len + 1, M_DEVBUF, M_NOWAIT); 2172 if (str == NULL) 2173 return(NDIS_STATUS_FAILURE); 2174 strncpy(str, sstr->nas_buf, sstr->nas_len); 2175 *(str + sstr->nas_len) = '\0'; 2176 if (ndis_ascii_to_unicode(str, &dstr->us_buf)) { 2177 free(str, M_DEVBUF); 2178 return(NDIS_STATUS_FAILURE); 2179 } 2180 dstr->us_len = dstr->us_maxlen = sstr->nas_len * 2; 2181 free(str, M_DEVBUF); 2182 return (NDIS_STATUS_SUCCESS); 2183} 2184 2185__stdcall static ndis_status 2186NdisMPciAssignResources(adapter, slot, list) 2187 ndis_handle adapter; 2188 uint32_t slot; 2189 ndis_resource_list **list; 2190{ 2191 ndis_miniport_block *block; 2192 2193 if (adapter == NULL || list == NULL) 2194 return (NDIS_STATUS_FAILURE); 2195 2196 block = (ndis_miniport_block *)adapter; 2197 *list = block->nmb_rlist; 2198 2199 return (NDIS_STATUS_SUCCESS); 2200} 2201 2202__stdcall static ndis_status 2203NdisMRegisterInterrupt(intr, adapter, ivec, ilevel, reqisr, shared, imode) 2204 ndis_miniport_interrupt *intr; 2205 ndis_handle adapter; 2206 uint32_t ivec; 2207 uint32_t ilevel; 2208 uint8_t reqisr; 2209 uint8_t shared; 2210 ndis_interrupt_mode imode; 2211{ 2212 ndis_miniport_block *block; 2213 2214 block = adapter; 2215 2216 intr->ni_block = adapter; 2217 intr->ni_isrreq = reqisr; 2218 intr->ni_shared = shared; 2219 block->nmb_interrupt = intr; 2220 2221 KeInitializeSpinLock(&intr->ni_dpccountlock); 2222 2223 return(NDIS_STATUS_SUCCESS); 2224} 2225 2226__stdcall static void 2227NdisMDeregisterInterrupt(intr) 2228 ndis_miniport_interrupt *intr; 2229{ 2230 return; 2231} 2232 2233__stdcall static void 2234NdisMRegisterAdapterShutdownHandler(adapter, shutdownctx, shutdownfunc) 2235 ndis_handle adapter; 2236 void *shutdownctx; 2237 ndis_shutdown_handler shutdownfunc; 2238{ 2239 ndis_miniport_block *block; 2240 ndis_miniport_characteristics *chars; 2241 struct ndis_softc *sc; 2242 2243 if (adapter == NULL) 2244 return; 2245 2246 block = (ndis_miniport_block *)adapter; 2247 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 2248 chars = sc->ndis_chars; 2249 2250 chars->nmc_shutdown_handler = shutdownfunc; 2251 chars->nmc_rsvd0 = shutdownctx; 2252 2253 return; 2254} 2255 2256__stdcall static void 2257NdisMDeregisterAdapterShutdownHandler(adapter) 2258 ndis_handle adapter; 2259{ 2260 ndis_miniport_block *block; 2261 ndis_miniport_characteristics *chars; 2262 struct ndis_softc *sc; 2263 2264 if (adapter == NULL) 2265 return; 2266 2267 block = (ndis_miniport_block *)adapter; 2268 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 2269 chars = sc->ndis_chars; 2270 2271 chars->nmc_shutdown_handler = NULL; 2272 chars->nmc_rsvd0 = NULL; 2273 2274 return; 2275} 2276 2277__stdcall static uint32_t 2278NDIS_BUFFER_TO_SPAN_PAGES(buf) 2279 ndis_buffer *buf; 2280{ 2281 if (buf == NULL) 2282 return(0); 2283 if (MmGetMdlByteCount(buf) == 0) 2284 return(1); 2285 return(SPAN_PAGES(MmGetMdlVirtualAddress(buf), 2286 MmGetMdlByteCount(buf))); 2287} 2288 2289__stdcall static void 2290NdisGetBufferPhysicalArraySize(buf, pages) 2291 ndis_buffer *buf; 2292 uint32_t *pages; 2293{ 2294 if (buf == NULL) 2295 return; 2296 2297 *pages = NDIS_BUFFER_TO_SPAN_PAGES(buf); 2298 return; 2299} 2300 2301__stdcall static void 2302NdisQueryBufferOffset(buf, off, len) 2303 ndis_buffer *buf; 2304 uint32_t *off; 2305 uint32_t *len; 2306{ 2307 if (buf == NULL) 2308 return; 2309 2310 *off = MmGetMdlByteOffset(buf); 2311 *len = MmGetMdlByteCount(buf); 2312 2313 return; 2314} 2315 2316__stdcall static void 2317NdisMSleep(usecs) 2318 uint32_t usecs; 2319{ 2320 struct timeval tv; 2321 2322 tv.tv_sec = 0; 2323 tv.tv_usec = usecs; 2324 2325 ndis_thsuspend(curthread->td_proc, NULL, tvtohz(&tv)); 2326 2327 return; 2328} 2329 2330__stdcall static uint32_t 2331NdisReadPcmciaAttributeMemory(handle, offset, buf, len) 2332 ndis_handle handle; 2333 uint32_t offset; 2334 void *buf; 2335 uint32_t len; 2336{ 2337 struct ndis_softc *sc; 2338 ndis_miniport_block *block; 2339 bus_space_handle_t bh; 2340 bus_space_tag_t bt; 2341 char *dest; 2342 int i; 2343 2344 if (handle == NULL) 2345 return(0); 2346 2347 block = (ndis_miniport_block *)handle; 2348 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 2349 dest = buf; 2350 2351 bh = rman_get_bushandle(sc->ndis_res_am); 2352 bt = rman_get_bustag(sc->ndis_res_am); 2353 2354 for (i = 0; i < len; i++) 2355 dest[i] = bus_space_read_1(bt, bh, (offset + i) * 2); 2356 2357 return(i); 2358} 2359 2360__stdcall static uint32_t 2361NdisWritePcmciaAttributeMemory(handle, offset, buf, len) 2362 ndis_handle handle; 2363 uint32_t offset; 2364 void *buf; 2365 uint32_t len; 2366{ 2367 struct ndis_softc *sc; 2368 ndis_miniport_block *block; 2369 bus_space_handle_t bh; 2370 bus_space_tag_t bt; 2371 char *src; 2372 int i; 2373 2374 if (handle == NULL) 2375 return(0); 2376 2377 block = (ndis_miniport_block *)handle; 2378 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 2379 src = buf; 2380 2381 bh = rman_get_bushandle(sc->ndis_res_am); 2382 bt = rman_get_bustag(sc->ndis_res_am); 2383 2384 for (i = 0; i < len; i++) 2385 bus_space_write_1(bt, bh, (offset + i) * 2, src[i]); 2386 2387 return(i); 2388} 2389 2390__stdcall static list_entry * 2391NdisInterlockedInsertHeadList(head, entry, lock) 2392 list_entry *head; 2393 list_entry *entry; 2394 ndis_spin_lock *lock; 2395{ 2396 list_entry *flink; 2397 2398 KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql); 2399 flink = head->nle_flink; 2400 entry->nle_flink = flink; 2401 entry->nle_blink = head; 2402 flink->nle_blink = entry; 2403 head->nle_flink = entry; 2404 KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql); 2405 2406 return(flink); 2407} 2408 2409__stdcall static list_entry * 2410NdisInterlockedRemoveHeadList(head, lock) 2411 list_entry *head; 2412 ndis_spin_lock *lock; 2413{ 2414 list_entry *flink; 2415 list_entry *entry; 2416 2417 KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql); 2418 entry = head->nle_flink; 2419 flink = entry->nle_flink; 2420 head->nle_flink = flink; 2421 flink->nle_blink = head; 2422 KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql); 2423 2424 return(entry); 2425} 2426 2427__stdcall static list_entry * 2428NdisInterlockedInsertTailList(head, entry, lock) 2429 list_entry *head; 2430 list_entry *entry; 2431 ndis_spin_lock *lock; 2432{ 2433 list_entry *blink; 2434 2435 KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql); 2436 blink = head->nle_blink; 2437 entry->nle_flink = head; 2438 entry->nle_blink = blink; 2439 blink->nle_flink = entry; 2440 head->nle_blink = entry; 2441 KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql); 2442 2443 return(blink); 2444} 2445 2446__stdcall static uint8_t 2447NdisMSynchronizeWithInterrupt(intr, syncfunc, syncctx) 2448 ndis_miniport_interrupt *intr; 2449 void *syncfunc; 2450 void *syncctx; 2451{ 2452 __stdcall uint8_t (*sync)(void *); 2453 uint8_t rval; 2454 uint8_t irql; 2455 2456 if (syncfunc == NULL || syncctx == NULL) 2457 return(0); 2458 2459 sync = syncfunc; 2460 KeAcquireSpinLock(&intr->ni_dpccountlock, &irql); 2461 rval = MSCALL1(sync, syncctx); 2462 KeReleaseSpinLock(&intr->ni_dpccountlock, irql); 2463 2464 return(rval); 2465} 2466 2467/* 2468 * Return the number of 100 nanosecond intervals since 2469 * January 1, 1601. (?!?!) 2470 */ 2471__stdcall static void 2472NdisGetCurrentSystemTime(tval) 2473 uint64_t *tval; 2474{ 2475 struct timespec ts; 2476 2477 nanotime(&ts); 2478 *tval = (uint64_t)ts.tv_nsec / 100 + (uint64_t)ts.tv_sec * 10000000 + 2479 11644473600; 2480 2481 return; 2482} 2483 2484/* 2485 * Return the number of milliseconds since the system booted. 2486 */ 2487__stdcall static void 2488NdisGetSystemUpTime(tval) 2489 uint32_t *tval; 2490{ 2491 *tval = (ticks * hz) / 1000; 2492 2493 return; 2494} 2495 2496__stdcall static void 2497NdisInitializeString(dst, src) 2498 ndis_unicode_string *dst; 2499 char *src; 2500{ 2501 ndis_unicode_string *u; 2502 2503 u = dst; 2504 u->us_buf = NULL; 2505 if (ndis_ascii_to_unicode(src, &u->us_buf)) 2506 return; 2507 u->us_len = u->us_maxlen = strlen(src) * 2; 2508 return; 2509} 2510 2511__stdcall static void 2512NdisFreeString(str) 2513 ndis_unicode_string *str; 2514{ 2515 if (str == NULL) 2516 return; 2517 if (str->us_buf != NULL) 2518 free(str->us_buf, M_DEVBUF); 2519 free(str, M_DEVBUF); 2520 return; 2521} 2522 2523__stdcall static ndis_status 2524NdisMRemoveMiniport(adapter) 2525 ndis_handle *adapter; 2526{ 2527 return(NDIS_STATUS_SUCCESS); 2528} 2529 2530__stdcall static void 2531NdisInitAnsiString(dst, src) 2532 ndis_ansi_string *dst; 2533 char *src; 2534{ 2535 ndis_ansi_string *a; 2536 2537 a = dst; 2538 if (a == NULL) 2539 return; 2540 if (src == NULL) { 2541 a->nas_len = a->nas_maxlen = 0; 2542 a->nas_buf = NULL; 2543 } else { 2544 a->nas_buf = src; 2545 a->nas_len = a->nas_maxlen = strlen(src); 2546 } 2547 2548 return; 2549} 2550 2551__stdcall static void 2552NdisInitUnicodeString(dst, src) 2553 ndis_unicode_string *dst; 2554 uint16_t *src; 2555{ 2556 ndis_unicode_string *u; 2557 int i; 2558 2559 u = dst; 2560 if (u == NULL) 2561 return; 2562 if (src == NULL) { 2563 u->us_len = u->us_maxlen = 0; 2564 u->us_buf = NULL; 2565 } else { 2566 i = 0; 2567 while(src[i] != 0) 2568 i++; 2569 u->us_buf = src; 2570 u->us_len = u->us_maxlen = i * 2; 2571 } 2572 2573 return; 2574} 2575 2576__stdcall static void NdisMGetDeviceProperty(adapter, phydevobj, 2577 funcdevobj, nextdevobj, resources, transresources) 2578 ndis_handle adapter; 2579 device_object **phydevobj; 2580 device_object **funcdevobj; 2581 device_object **nextdevobj; 2582 cm_resource_list *resources; 2583 cm_resource_list *transresources; 2584{ 2585 ndis_miniport_block *block; 2586 2587 block = (ndis_miniport_block *)adapter; 2588 2589 if (phydevobj != NULL) 2590 *phydevobj = block->nmb_physdeviceobj; 2591 if (funcdevobj != NULL) 2592 *funcdevobj = block->nmb_deviceobj; 2593 if (nextdevobj != NULL) 2594 *nextdevobj = block->nmb_nextdeviceobj; 2595 2596 return; 2597} 2598 2599__stdcall static void 2600NdisGetFirstBufferFromPacket(packet, buf, firstva, firstlen, totlen) 2601 ndis_packet *packet; 2602 ndis_buffer **buf; 2603 void **firstva; 2604 uint32_t *firstlen; 2605 uint32_t *totlen; 2606{ 2607 ndis_buffer *tmp; 2608 2609 tmp = packet->np_private.npp_head; 2610 *buf = tmp; 2611 if (tmp == NULL) { 2612 *firstva = NULL; 2613 *firstlen = *totlen = 0; 2614 } else { 2615 *firstva = MmGetMdlVirtualAddress(tmp); 2616 *firstlen = *totlen = MmGetMdlByteCount(tmp); 2617 for (tmp = tmp->mdl_next; tmp != NULL; tmp = tmp->mdl_next) 2618 *totlen += MmGetMdlByteCount(tmp); 2619 } 2620 2621 return; 2622} 2623 2624__stdcall static void 2625NdisGetFirstBufferFromPacketSafe(packet, buf, firstva, firstlen, totlen, prio) 2626 ndis_packet *packet; 2627 ndis_buffer **buf; 2628 void **firstva; 2629 uint32_t *firstlen; 2630 uint32_t *totlen; 2631 uint32_t prio; 2632{ 2633 NdisGetFirstBufferFromPacket(packet, buf, firstva, firstlen, totlen); 2634} 2635 2636static int 2637ndis_find_sym(lf, filename, suffix, sym) 2638 linker_file_t lf; 2639 char *filename; 2640 char *suffix; 2641 caddr_t *sym; 2642{ 2643 char *fullsym; 2644 char *suf; 2645 int i; 2646 2647 fullsym = ExAllocatePoolWithTag(NonPagedPool, MAXPATHLEN, 0); 2648 if (fullsym == NULL) 2649 return(ENOMEM); 2650 2651 bzero(fullsym, MAXPATHLEN); 2652 strncpy(fullsym, filename, MAXPATHLEN); 2653 if (strlen(filename) < 4) { 2654 ExFreePool(fullsym); 2655 return(EINVAL); 2656 } 2657 2658 /* If the filename has a .ko suffix, strip if off. */ 2659 suf = fullsym + (strlen(filename) - 3); 2660 if (strcmp(suf, ".ko") == 0) 2661 *suf = '\0'; 2662 2663 for (i = 0; i < strlen(fullsym); i++) { 2664 if (fullsym[i] == '.') 2665 fullsym[i] = '_'; 2666 else 2667 fullsym[i] = tolower(fullsym[i]); 2668 } 2669 strcat(fullsym, suffix); 2670 *sym = linker_file_lookup_symbol(lf, fullsym, 0); 2671 ExFreePool(fullsym); 2672 if (*sym == 0) 2673 return(ENOENT); 2674 2675 return(0); 2676} 2677 2678/* can also return NDIS_STATUS_RESOURCES/NDIS_STATUS_ERROR_READING_FILE */ 2679__stdcall static void 2680NdisOpenFile(status, filehandle, filelength, filename, highestaddr) 2681 ndis_status *status; 2682 ndis_handle *filehandle; 2683 uint32_t *filelength; 2684 ndis_unicode_string *filename; 2685 ndis_physaddr highestaddr; 2686{ 2687 char *afilename = NULL; 2688 struct thread *td = curthread; 2689 struct nameidata nd; 2690 int flags, error; 2691 struct vattr vat; 2692 struct vattr *vap = &vat; 2693 ndis_fh *fh; 2694 char *path; 2695 linker_file_t head, lf; 2696 caddr_t kldstart, kldend; 2697 2698 ndis_unicode_to_ascii(filename->us_buf, 2699 filename->us_len, &afilename); 2700 2701 fh = ExAllocatePoolWithTag(NonPagedPool, sizeof(ndis_fh), 0); 2702 if (fh == NULL) { 2703 *status = NDIS_STATUS_RESOURCES; 2704 return; 2705 } 2706 2707 /* 2708 * During system bootstrap, it's impossible to load files 2709 * from the rootfs since it's not mounted yet. We therefore 2710 * offer the possibility of opening files that have been 2711 * preloaded as modules instead. Both choices will work 2712 * when kldloading a module from multiuser, but only the 2713 * module option will work during bootstrap. The module 2714 * loading option works by using the ndiscvt(8) utility 2715 * to convert the arbitrary file into a .ko using objcopy(1). 2716 * This file will contain two special symbols: filename_start 2717 * and filename_end. All we have to do is traverse the KLD 2718 * list in search of those symbols and we've found the file 2719 * data. As an added bonus, ndiscvt(8) will also generate 2720 * a normal .o file which can be linked statically with 2721 * the kernel. This means that the symbols will actual reside 2722 * in the kernel's symbol table, but that doesn't matter to 2723 * us since the kernel appears to us as just another module. 2724 */ 2725 2726 /* 2727 * This is an evil trick for getting the head of the linked 2728 * file list, which is not exported from kern_linker.o. It 2729 * happens that linker file #1 is always the kernel, and is 2730 * always the first element in the list. 2731 */ 2732 2733 head = linker_find_file_by_id(1); 2734 for (lf = head; lf != NULL; lf = TAILQ_NEXT(lf, link)) { 2735 if (ndis_find_sym(lf, afilename, "_start", &kldstart)) 2736 continue; 2737 if (ndis_find_sym(lf, afilename, "_end", &kldend)) 2738 continue; 2739 fh->nf_vp = lf; 2740 fh->nf_map = NULL; 2741 fh->nf_type = NDIS_FH_TYPE_MODULE; 2742 *filelength = fh->nf_maplen = (kldend - kldstart) & 0xFFFFFFFF; 2743 *filehandle = fh; 2744 free(afilename, M_DEVBUF); 2745 *status = NDIS_STATUS_SUCCESS; 2746 return; 2747 } 2748 2749 if (TAILQ_EMPTY(&mountlist)) { 2750 free(fh, M_TEMP); 2751 *status = NDIS_STATUS_FILE_NOT_FOUND; 2752 printf("NDIS: could not find file %s in linker list\n", 2753 afilename); 2754 printf("NDIS: and no filesystems mounted yet, " 2755 "aborting NdisOpenFile()\n"); 2756 free(afilename, M_DEVBUF); 2757 return; 2758 } 2759 2760 path = ExAllocatePoolWithTag(NonPagedPool, MAXPATHLEN, 0); 2761 if (path == NULL) { 2762 *status = NDIS_STATUS_RESOURCES; 2763 return; 2764 } 2765 2766 snprintf(path, MAXPATHLEN, "%s/%s", ndis_filepath, afilename); 2767 free(afilename, M_DEVBUF); 2768 2769 mtx_lock(&Giant); 2770 2771 /* Some threads don't have a current working directory. */ 2772 2773 if (td->td_proc->p_fd->fd_rdir == NULL) 2774 td->td_proc->p_fd->fd_rdir = rootvnode; 2775 if (td->td_proc->p_fd->fd_cdir == NULL) 2776 td->td_proc->p_fd->fd_cdir = rootvnode; 2777 2778 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, td); 2779 2780 flags = FREAD; 2781 error = vn_open(&nd, &flags, 0, -1); 2782 if (error) { 2783 mtx_unlock(&Giant); 2784 *status = NDIS_STATUS_FILE_NOT_FOUND; 2785 ExFreePool(fh); 2786 printf("NDIS: open file %s failed: %d\n", path, error); 2787 ExFreePool(path); 2788 return; 2789 } 2790 2791 ExFreePool(path); 2792 2793 NDFREE(&nd, NDF_ONLY_PNBUF); 2794 2795 /* Get the file size. */ 2796 VOP_GETATTR(nd.ni_vp, vap, td->td_ucred, td); 2797 VOP_UNLOCK(nd.ni_vp, 0, td); 2798 mtx_unlock(&Giant); 2799 2800 fh->nf_vp = nd.ni_vp; 2801 fh->nf_map = NULL; 2802 fh->nf_type = NDIS_FH_TYPE_VFS; 2803 *filehandle = fh; 2804 *filelength = fh->nf_maplen = vap->va_size & 0xFFFFFFFF; 2805 *status = NDIS_STATUS_SUCCESS; 2806 2807 return; 2808} 2809 2810__stdcall static void 2811NdisMapFile(status, mappedbuffer, filehandle) 2812 ndis_status *status; 2813 void **mappedbuffer; 2814 ndis_handle filehandle; 2815{ 2816 ndis_fh *fh; 2817 struct thread *td = curthread; 2818 linker_file_t lf; 2819 caddr_t kldstart; 2820 int error, resid; 2821 2822 if (filehandle == NULL) { 2823 *status = NDIS_STATUS_FAILURE; 2824 return; 2825 } 2826 2827 fh = (ndis_fh *)filehandle; 2828 2829 if (fh->nf_vp == NULL) { 2830 *status = NDIS_STATUS_FAILURE; 2831 return; 2832 } 2833 2834 if (fh->nf_map != NULL) { 2835 *status = NDIS_STATUS_ALREADY_MAPPED; 2836 return; 2837 } 2838 2839 if (fh->nf_type == NDIS_FH_TYPE_MODULE) { 2840 lf = fh->nf_vp; 2841 if (ndis_find_sym(lf, lf->filename, "_start", &kldstart)) { 2842 *status = NDIS_STATUS_FAILURE; 2843 return; 2844 } 2845 fh->nf_map = kldstart; 2846 *status = NDIS_STATUS_SUCCESS; 2847 *mappedbuffer = fh->nf_map; 2848 return; 2849 } 2850 2851 fh->nf_map = ExAllocatePoolWithTag(NonPagedPool, fh->nf_maplen, 0); 2852 2853 if (fh->nf_map == NULL) { 2854 *status = NDIS_STATUS_RESOURCES; 2855 return; 2856 } 2857 2858 mtx_lock(&Giant); 2859 error = vn_rdwr(UIO_READ, fh->nf_vp, fh->nf_map, fh->nf_maplen, 0, 2860 UIO_SYSSPACE, 0, td->td_ucred, NOCRED, &resid, td); 2861 mtx_unlock(&Giant); 2862 2863 if (error) 2864 *status = NDIS_STATUS_FAILURE; 2865 else { 2866 *status = NDIS_STATUS_SUCCESS; 2867 *mappedbuffer = fh->nf_map; 2868 } 2869 2870 return; 2871} 2872 2873__stdcall static void 2874NdisUnmapFile(filehandle) 2875 ndis_handle filehandle; 2876{ 2877 ndis_fh *fh; 2878 fh = (ndis_fh *)filehandle; 2879 2880 if (fh->nf_map == NULL) 2881 return; 2882 2883 if (fh->nf_type == NDIS_FH_TYPE_VFS) 2884 ExFreePool(fh->nf_map); 2885 fh->nf_map = NULL; 2886 2887 return; 2888} 2889 2890__stdcall static void 2891NdisCloseFile(filehandle) 2892 ndis_handle filehandle; 2893{ 2894 struct thread *td = curthread; 2895 ndis_fh *fh; 2896 2897 if (filehandle == NULL) 2898 return; 2899 2900 fh = (ndis_fh *)filehandle; 2901 if (fh->nf_map != NULL) { 2902 if (fh->nf_type == NDIS_FH_TYPE_VFS) 2903 ExFreePool(fh->nf_map); 2904 fh->nf_map = NULL; 2905 } 2906 2907 if (fh->nf_vp == NULL) 2908 return; 2909 2910 if (fh->nf_type == NDIS_FH_TYPE_VFS) { 2911 mtx_lock(&Giant); 2912 vn_close(fh->nf_vp, FREAD, td->td_ucred, td); 2913 mtx_unlock(&Giant); 2914 } 2915 2916 fh->nf_vp = NULL; 2917 ExFreePool(fh); 2918 2919 return; 2920} 2921 2922__stdcall static uint8_t 2923NdisSystemProcessorCount() 2924{ 2925 return(mp_ncpus); 2926} 2927 2928typedef void (*ndis_statusdone_handler)(ndis_handle); 2929typedef void (*ndis_status_handler)(ndis_handle, ndis_status, 2930 void *, uint32_t); 2931 2932__stdcall static void 2933NdisMIndicateStatusComplete(adapter) 2934 ndis_handle adapter; 2935{ 2936 ndis_miniport_block *block; 2937 __stdcall ndis_statusdone_handler statusdonefunc; 2938 2939 block = (ndis_miniport_block *)adapter; 2940 statusdonefunc = block->nmb_statusdone_func; 2941 2942 MSCALL1(statusdonefunc, adapter); 2943 return; 2944} 2945 2946__stdcall static void 2947NdisMIndicateStatus(adapter, status, sbuf, slen) 2948 ndis_handle adapter; 2949 ndis_status status; 2950 void *sbuf; 2951 uint32_t slen; 2952{ 2953 ndis_miniport_block *block; 2954 __stdcall ndis_status_handler statusfunc; 2955 2956 block = (ndis_miniport_block *)adapter; 2957 statusfunc = block->nmb_status_func; 2958 2959 MSCALL4(statusfunc, adapter, status, sbuf, slen); 2960 return; 2961} 2962 2963static void 2964ndis_workfunc(ctx) 2965 void *ctx; 2966{ 2967 ndis_work_item *work; 2968 __stdcall ndis_proc workfunc; 2969 2970 work = ctx; 2971 workfunc = work->nwi_func; 2972 MSCALL2(workfunc, work, work->nwi_ctx); 2973 return; 2974} 2975 2976__stdcall static ndis_status 2977NdisScheduleWorkItem(work) 2978 ndis_work_item *work; 2979{ 2980 ndis_sched(ndis_workfunc, work, NDIS_TASKQUEUE); 2981 return(NDIS_STATUS_SUCCESS); 2982} 2983 2984__stdcall static void 2985NdisCopyFromPacketToPacket(dpkt, doff, reqlen, spkt, soff, cpylen) 2986 ndis_packet *dpkt; 2987 uint32_t doff; 2988 uint32_t reqlen; 2989 ndis_packet *spkt; 2990 uint32_t soff; 2991 uint32_t *cpylen; 2992{ 2993 ndis_buffer *src, *dst; 2994 char *sptr, *dptr; 2995 int resid, copied, len, scnt, dcnt; 2996 2997 *cpylen = 0; 2998 2999 src = spkt->np_private.npp_head; 3000 dst = dpkt->np_private.npp_head; 3001 3002 sptr = MmGetMdlVirtualAddress(src); 3003 dptr = MmGetMdlVirtualAddress(dst); 3004 scnt = MmGetMdlByteCount(src); 3005 dcnt = MmGetMdlByteCount(dst); 3006 3007 while (soff) { 3008 if (MmGetMdlByteCount(src) > soff) { 3009 sptr += soff; 3010 scnt = MmGetMdlByteCount(src)- soff; 3011 break; 3012 } 3013 soff -= MmGetMdlByteCount(src); 3014 src = src->mdl_next; 3015 if (src == NULL) 3016 return; 3017 sptr = MmGetMdlVirtualAddress(src); 3018 } 3019 3020 while (doff) { 3021 if (MmGetMdlByteCount(dst) > doff) { 3022 dptr += doff; 3023 dcnt = MmGetMdlByteCount(dst) - doff; 3024 break; 3025 } 3026 doff -= MmGetMdlByteCount(dst); 3027 dst = dst->mdl_next; 3028 if (dst == NULL) 3029 return; 3030 dptr = MmGetMdlVirtualAddress(dst); 3031 } 3032 3033 resid = reqlen; 3034 copied = 0; 3035 3036 while(1) { 3037 if (resid < scnt) 3038 len = resid; 3039 else 3040 len = scnt; 3041 if (dcnt < len) 3042 len = dcnt; 3043 3044 bcopy(sptr, dptr, len); 3045 3046 copied += len; 3047 resid -= len; 3048 if (resid == 0) 3049 break; 3050 3051 dcnt -= len; 3052 if (dcnt == 0) { 3053 dst = dst->mdl_next; 3054 if (dst == NULL) 3055 break; 3056 dptr = MmGetMdlVirtualAddress(dst); 3057 dcnt = MmGetMdlByteCount(dst); 3058 } 3059 3060 scnt -= len; 3061 if (scnt == 0) { 3062 src = src->mdl_next; 3063 if (src == NULL) 3064 break; 3065 sptr = MmGetMdlVirtualAddress(src); 3066 scnt = MmGetMdlByteCount(src); 3067 } 3068 } 3069 3070 *cpylen = copied; 3071 return; 3072} 3073 3074__stdcall static void 3075NdisCopyFromPacketToPacketSafe(dpkt, doff, reqlen, spkt, soff, cpylen, prio) 3076 ndis_packet *dpkt; 3077 uint32_t doff; 3078 uint32_t reqlen; 3079 ndis_packet *spkt; 3080 uint32_t soff; 3081 uint32_t *cpylen; 3082 uint32_t prio; 3083{ 3084 NdisCopyFromPacketToPacket(dpkt, doff, reqlen, spkt, soff, cpylen); 3085 return; 3086} 3087 3088__stdcall static ndis_status 3089NdisMRegisterDevice(handle, devname, symname, majorfuncs, devobj, devhandle) 3090 ndis_handle handle; 3091 ndis_unicode_string *devname; 3092 ndis_unicode_string *symname; 3093 driver_dispatch *majorfuncs[]; 3094 void **devobj; 3095 ndis_handle *devhandle; 3096{ 3097 ndis_miniport_block *block; 3098 3099 block = (ndis_miniport_block *)handle; 3100 *devobj = block->nmb_deviceobj; 3101 *devhandle = handle; 3102 3103 return(NDIS_STATUS_SUCCESS); 3104} 3105 3106__stdcall static ndis_status 3107NdisMDeregisterDevice(handle) 3108 ndis_handle handle; 3109{ 3110 return(NDIS_STATUS_SUCCESS); 3111} 3112 3113__stdcall static ndis_status 3114NdisMQueryAdapterInstanceName(name, handle) 3115 ndis_unicode_string *name; 3116 ndis_handle handle; 3117{ 3118 ndis_miniport_block *block; 3119 device_t dev; 3120 3121 block = (ndis_miniport_block *)handle; 3122 dev = block->nmb_physdeviceobj->do_devext; 3123 3124 ndis_ascii_to_unicode(__DECONST(char *, 3125 device_get_nameunit(dev)), &name->us_buf); 3126 name->us_len = strlen(device_get_nameunit(dev)) * 2; 3127 3128 return(NDIS_STATUS_SUCCESS); 3129} 3130 3131__stdcall static void 3132NdisMRegisterUnloadHandler(handle, func) 3133 ndis_handle handle; 3134 void *func; 3135{ 3136 return; 3137} 3138 3139__stdcall static void 3140dummy() 3141{ 3142 printf ("NDIS dummy called...\n"); 3143 return; 3144} 3145 3146image_patch_table ndis_functbl[] = { 3147 IMPORT_FUNC(NdisCopyFromPacketToPacket), 3148 IMPORT_FUNC(NdisCopyFromPacketToPacketSafe), 3149 IMPORT_FUNC(NdisScheduleWorkItem), 3150 IMPORT_FUNC(NdisMIndicateStatusComplete), 3151 IMPORT_FUNC(NdisMIndicateStatus), 3152 IMPORT_FUNC(NdisSystemProcessorCount), 3153 IMPORT_FUNC(NdisUnchainBufferAtBack), 3154 IMPORT_FUNC(NdisGetFirstBufferFromPacket), 3155 IMPORT_FUNC(NdisGetFirstBufferFromPacketSafe), 3156 IMPORT_FUNC(NdisGetBufferPhysicalArraySize), 3157 IMPORT_FUNC(NdisMGetDeviceProperty), 3158 IMPORT_FUNC(NdisInitAnsiString), 3159 IMPORT_FUNC(NdisInitUnicodeString), 3160 IMPORT_FUNC(NdisWriteConfiguration), 3161 IMPORT_FUNC(NdisAnsiStringToUnicodeString), 3162 IMPORT_FUNC(NdisTerminateWrapper), 3163 IMPORT_FUNC(NdisOpenConfigurationKeyByName), 3164 IMPORT_FUNC(NdisOpenConfigurationKeyByIndex), 3165 IMPORT_FUNC(NdisMRemoveMiniport), 3166 IMPORT_FUNC(NdisInitializeString), 3167 IMPORT_FUNC(NdisFreeString), 3168 IMPORT_FUNC(NdisGetCurrentSystemTime), 3169 IMPORT_FUNC(NdisGetSystemUpTime), 3170 IMPORT_FUNC(NdisMSynchronizeWithInterrupt), 3171 IMPORT_FUNC(NdisMAllocateSharedMemoryAsync), 3172 IMPORT_FUNC(NdisInterlockedInsertHeadList), 3173 IMPORT_FUNC(NdisInterlockedInsertTailList), 3174 IMPORT_FUNC(NdisInterlockedRemoveHeadList), 3175 IMPORT_FUNC(NdisInitializeWrapper), 3176 IMPORT_FUNC(NdisMRegisterMiniport), 3177 IMPORT_FUNC(NdisAllocateMemoryWithTag), 3178 IMPORT_FUNC(NdisAllocateMemory), 3179 IMPORT_FUNC(NdisMSetAttributesEx), 3180 IMPORT_FUNC(NdisCloseConfiguration), 3181 IMPORT_FUNC(NdisReadConfiguration), 3182 IMPORT_FUNC(NdisOpenConfiguration), 3183 IMPORT_FUNC(NdisAcquireSpinLock), 3184 IMPORT_FUNC(NdisReleaseSpinLock), 3185 IMPORT_FUNC(NdisDprAcquireSpinLock), 3186 IMPORT_FUNC(NdisDprReleaseSpinLock), 3187 IMPORT_FUNC(NdisAllocateSpinLock), 3188 IMPORT_FUNC(NdisFreeSpinLock), 3189 IMPORT_FUNC(NdisFreeMemory), 3190 IMPORT_FUNC(NdisReadPciSlotInformation), 3191 IMPORT_FUNC(NdisWritePciSlotInformation), 3192 IMPORT_FUNC_MAP(NdisImmediateReadPciSlotInformation, 3193 NdisReadPciSlotInformation), 3194 IMPORT_FUNC_MAP(NdisImmediateWritePciSlotInformation, 3195 NdisWritePciSlotInformation), 3196 IMPORT_FUNC(NdisWriteErrorLogEntry), 3197 IMPORT_FUNC(NdisMStartBufferPhysicalMapping), 3198 IMPORT_FUNC(NdisMCompleteBufferPhysicalMapping), 3199 IMPORT_FUNC(NdisMInitializeTimer), 3200 IMPORT_FUNC(NdisInitializeTimer), 3201 IMPORT_FUNC(NdisSetTimer), 3202 IMPORT_FUNC(NdisMCancelTimer), 3203 IMPORT_FUNC_MAP(NdisCancelTimer, NdisMCancelTimer), 3204 IMPORT_FUNC(NdisMSetPeriodicTimer), 3205 IMPORT_FUNC(NdisMQueryAdapterResources), 3206 IMPORT_FUNC(NdisMRegisterIoPortRange), 3207 IMPORT_FUNC(NdisMDeregisterIoPortRange), 3208 IMPORT_FUNC(NdisReadNetworkAddress), 3209 IMPORT_FUNC(NdisQueryMapRegisterCount), 3210 IMPORT_FUNC(NdisMAllocateMapRegisters), 3211 IMPORT_FUNC(NdisMFreeMapRegisters), 3212 IMPORT_FUNC(NdisMAllocateSharedMemory), 3213 IMPORT_FUNC(NdisMMapIoSpace), 3214 IMPORT_FUNC(NdisMUnmapIoSpace), 3215 IMPORT_FUNC(NdisGetCacheFillSize), 3216 IMPORT_FUNC(NdisMGetDmaAlignment), 3217 IMPORT_FUNC(NdisMInitializeScatterGatherDma), 3218 IMPORT_FUNC(NdisAllocatePacketPool), 3219 IMPORT_FUNC(NdisAllocatePacketPoolEx), 3220 IMPORT_FUNC(NdisAllocatePacket), 3221 IMPORT_FUNC(NdisFreePacket), 3222 IMPORT_FUNC(NdisFreePacketPool), 3223 IMPORT_FUNC_MAP(NdisDprAllocatePacket, NdisAllocatePacket), 3224 IMPORT_FUNC_MAP(NdisDprFreePacket, NdisFreePacket), 3225 IMPORT_FUNC(NdisAllocateBufferPool), 3226 IMPORT_FUNC(NdisAllocateBuffer), 3227 IMPORT_FUNC(NdisQueryBuffer), 3228 IMPORT_FUNC(NdisQueryBufferSafe), 3229 IMPORT_FUNC(NdisBufferVirtualAddress), 3230 IMPORT_FUNC(NdisBufferVirtualAddressSafe), 3231 IMPORT_FUNC(NdisBufferLength), 3232 IMPORT_FUNC(NdisFreeBuffer), 3233 IMPORT_FUNC(NdisFreeBufferPool), 3234 IMPORT_FUNC(NdisInterlockedIncrement), 3235 IMPORT_FUNC(NdisInterlockedDecrement), 3236 IMPORT_FUNC(NdisInitializeEvent), 3237 IMPORT_FUNC(NdisSetEvent), 3238 IMPORT_FUNC(NdisResetEvent), 3239 IMPORT_FUNC(NdisWaitEvent), 3240 IMPORT_FUNC(NdisUnicodeStringToAnsiString), 3241 IMPORT_FUNC(NdisMPciAssignResources), 3242 IMPORT_FUNC(NdisMFreeSharedMemory), 3243 IMPORT_FUNC(NdisMRegisterInterrupt), 3244 IMPORT_FUNC(NdisMDeregisterInterrupt), 3245 IMPORT_FUNC(NdisMRegisterAdapterShutdownHandler), 3246 IMPORT_FUNC(NdisMDeregisterAdapterShutdownHandler), 3247 IMPORT_FUNC(NDIS_BUFFER_TO_SPAN_PAGES), 3248 IMPORT_FUNC(NdisQueryBufferOffset), 3249 IMPORT_FUNC(NdisAdjustBufferLength), 3250 IMPORT_FUNC(NdisPacketPoolUsage), 3251 IMPORT_FUNC(NdisMSleep), 3252 IMPORT_FUNC(NdisUnchainBufferAtFront), 3253 IMPORT_FUNC(NdisReadPcmciaAttributeMemory), 3254 IMPORT_FUNC(NdisWritePcmciaAttributeMemory), 3255 IMPORT_FUNC(NdisOpenFile), 3256 IMPORT_FUNC(NdisMapFile), 3257 IMPORT_FUNC(NdisUnmapFile), 3258 IMPORT_FUNC(NdisCloseFile), 3259 IMPORT_FUNC(NdisMRegisterDevice), 3260 IMPORT_FUNC(NdisMDeregisterDevice), 3261 IMPORT_FUNC(NdisMQueryAdapterInstanceName), 3262 IMPORT_FUNC(NdisMRegisterUnloadHandler), 3263 3264 /* 3265 * This last entry is a catch-all for any function we haven't 3266 * implemented yet. The PE import list patching routine will 3267 * use it for any function that doesn't have an explicit match 3268 * in this table. 3269 */ 3270 3271 { NULL, (FUNC)dummy, NULL }, 3272 3273 /* End of list. */ 3274 3275 { NULL, NULL, NULL } 3276}; 3277