/*++ Copyright (c) 1990-1995 Microsoft Corporation Module Name: miniport.c Abstract: NDIS wrapper functions Author: Sean Selitrennikoff (SeanSe) 05-Oct-93 Jameel Hyder (JameelH) Re-organization 01-Jun-95 Environment: Kernel mode, FSD Revision History: --*/ #include "precomp.h" #pragma hdrstop // // Define the module number for debug code. // #define MODULE_NUMBER MODULE_MINISUB VOID NdisAllocateSpinLock( IN PNDIS_SPIN_LOCK SpinLock ) { INITIALIZE_SPIN_LOCK(&SpinLock->SpinLock); } VOID NdisFreeSpinLock( IN PNDIS_SPIN_LOCK SpinLock ) { UNREFERENCED_PARAMETER(SpinLock); } VOID NdisAcquireSpinLock( IN PNDIS_SPIN_LOCK SpinLock ) { NDIS_ACQUIRE_SPIN_LOCK(SpinLock, &SpinLock->OldIrql); } VOID NdisReleaseSpinLock( IN PNDIS_SPIN_LOCK SpinLock ) { NDIS_RELEASE_SPIN_LOCK(SpinLock, SpinLock->OldIrql); } VOID NdisDprAcquireSpinLock( IN PNDIS_SPIN_LOCK SpinLock ) { NDIS_ACQUIRE_SPIN_LOCK_DPC(SpinLock); SpinLock->OldIrql = DISPATCH_LEVEL; } VOID NdisDprReleaseSpinLock( IN PNDIS_SPIN_LOCK SpinLock ) { NDIS_RELEASE_SPIN_LOCK_DPC(SpinLock); } #undef NdisFreeBuffer VOID NdisFreeBuffer( IN PNDIS_BUFFER Buffer ) { IoFreeMdl(Buffer); } #undef NdisQueryBuffer VOID NdisQueryBuffer( IN PNDIS_BUFFER Buffer, OUT PVOID * VirtualAddress OPTIONAL, OUT PUINT Length ) { if (ARGUMENT_PRESENT(VirtualAddress)) { *VirtualAddress = MDL_ADDRESS(Buffer); } *Length = MDL_SIZE(Buffer); } VOID NdisQueryBufferSafe( IN PNDIS_BUFFER Buffer, OUT PVOID * VirtualAddress OPTIONAL, OUT PUINT Length, IN MM_PAGE_PRIORITY Priority ) { if (ARGUMENT_PRESENT(VirtualAddress)) { *VirtualAddress = MDL_ADDRESS_SAFE(Buffer, Priority); } *Length = MDL_SIZE(Buffer); } VOID NdisQueryBufferOffset( IN PNDIS_BUFFER Buffer, OUT PUINT Offset, OUT PUINT Length ) { *Offset = MDL_OFFSET(Buffer); *Length = MDL_SIZE(Buffer); } VOID NdisGetFirstBufferFromPacket( IN PNDIS_PACKET Packet, OUT PNDIS_BUFFER * FirstBuffer, OUT PVOID * FirstBufferVA, OUT PUINT FirstBufferLength, OUT PUINT TotalBufferLength ) { PNDIS_BUFFER pBuf; pBuf = Packet->Private.Head; *FirstBuffer = pBuf; if (pBuf) { *FirstBufferVA = MmGetSystemAddressForMdl(pBuf); *FirstBufferLength = *TotalBufferLength = MmGetMdlByteCount(pBuf); for (pBuf = pBuf->Next; pBuf != NULL; pBuf = pBuf->Next) { *TotalBufferLength += MmGetMdlByteCount(pBuf); } } else { *FirstBufferVA = 0; *FirstBufferLength = 0; *TotalBufferLength = 0; } } // // safe version of NdisGetFirstBufferFromPacket // if the memory described by the first buffer can not be mapped // this function will return NULL for FirstBuferVA // VOID NdisGetFirstBufferFromPacketSafe( IN PNDIS_PACKET Packet, OUT PNDIS_BUFFER * FirstBuffer, OUT PVOID * FirstBufferVA, OUT PUINT FirstBufferLength, OUT PUINT TotalBufferLength, IN MM_PAGE_PRIORITY Priority ) { PNDIS_BUFFER pBuf; pBuf = Packet->Private.Head; *FirstBuffer = pBuf; if (pBuf) { *FirstBufferVA = MmGetSystemAddressForMdlSafe(pBuf, Priority); *FirstBufferLength = *TotalBufferLength = MmGetMdlByteCount(pBuf); for (pBuf = pBuf->Next; pBuf != NULL; pBuf = pBuf->Next) { *TotalBufferLength += MmGetMdlByteCount(pBuf); } } else { *FirstBufferVA = 0; *FirstBufferLength = 0; *TotalBufferLength = 0; } } ULONG NdisBufferLength( IN PNDIS_BUFFER Buffer ) { return (MmGetMdlByteCount(Buffer)); } PVOID NdisBufferVirtualAddress( IN PNDIS_BUFFER Buffer ) { return (MDL_ADDRESS_SAFE(Buffer, HighPagePriority)); } ULONG NDIS_BUFFER_TO_SPAN_PAGES( IN PNDIS_BUFFER Buffer ) { if (MDL_SIZE(Buffer) == 0) { return 1; } return ADDRESS_AND_SIZE_TO_SPAN_PAGES(MDL_VA(Buffer), MDL_SIZE(Buffer)); } VOID NdisGetBufferPhysicalArraySize( IN PNDIS_BUFFER Buffer, OUT PUINT ArraySize ) { if (MDL_SIZE(Buffer) == 0) { *ArraySize = 1; } else { *ArraySize = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MDL_VA(Buffer), MDL_SIZE(Buffer)); } } NDIS_STATUS NdisAnsiStringToUnicodeString( IN OUT PUNICODE_STRING DestinationString, IN PANSI_STRING SourceString ) { NDIS_STATUS Status; Status = RtlAnsiStringToUnicodeString(DestinationString, SourceString, FALSE); return Status; } NDIS_STATUS NdisUnicodeStringToAnsiString( IN OUT PANSI_STRING DestinationString, IN PUNICODE_STRING SourceString ) { NDIS_STATUS Status; Status = RtlUnicodeStringToAnsiString(DestinationString, SourceString, FALSE); return Status; } NDIS_STATUS NdisUpcaseUnicodeString( OUT PUNICODE_STRING DestinationString, IN PUNICODE_STRING SourceString ) { return(RtlUpcaseUnicodeString(DestinationString, SourceString, FALSE)); } VOID NdisMStartBufferPhysicalMapping( IN NDIS_HANDLE MiniportAdapterHandle, IN PNDIS_BUFFER Buffer, IN ULONG PhysicalMapRegister, IN BOOLEAN WriteToDevice, OUT PNDIS_PHYSICAL_ADDRESS_UNIT PhysicalAddressArray, OUT PUINT ArraySize ) { NdisMStartBufferPhysicalMappingMacro(MiniportAdapterHandle, Buffer, PhysicalMapRegister, WriteToDevice, PhysicalAddressArray, ArraySize); } VOID NdisMCompleteBufferPhysicalMapping( IN NDIS_HANDLE MiniportAdapterHandle, IN PNDIS_BUFFER Buffer, IN ULONG PhysicalMapRegister ) { NdisMCompleteBufferPhysicalMappingMacro(MiniportAdapterHandle, Buffer, PhysicalMapRegister); } #undef NdisInterlockedIncrement ULONG NdisInterlockedIncrement( IN PULONG Addend ) /*++ Return Value: (eax) < 0 (but not necessarily -1) if result of add < 0 (eax) == 0 if result of add == 0 (eax) > 0 (but not necessarily +1) if result of add > 0 --*/ { return(InterlockedIncrement(Addend)); } #undef NdisInterlockedDecrement ULONG NdisInterlockedDecrement( IN PULONG Addend ) /*++ Return Value: (eax) < 0 (but not necessarily -1) if result of add < 0 (eax) == 0 if result of add == 0 (eax) > 0 (but not necessarily +1) if result of add > 0 --*/ { return(InterlockedDecrement(Addend)); } #undef NdisInterlockedAddUlong ULONG NdisInterlockedAddUlong( IN PULONG Addend, IN ULONG Increment, IN PNDIS_SPIN_LOCK SpinLock ) { return(ExInterlockedAddUlong(Addend,Increment, &SpinLock->SpinLock)); } #undef NdisInterlockedInsertHeadList PLIST_ENTRY NdisInterlockedInsertHeadList( IN PLIST_ENTRY ListHead, IN PLIST_ENTRY ListEntry, IN PNDIS_SPIN_LOCK SpinLock ) { return(ExInterlockedInsertHeadList(ListHead,ListEntry,&SpinLock->SpinLock)); } #undef NdisInterlockedInsertTailList PLIST_ENTRY NdisInterlockedInsertTailList( IN PLIST_ENTRY ListHead, IN PLIST_ENTRY ListEntry, IN PNDIS_SPIN_LOCK SpinLock ) { return(ExInterlockedInsertTailList(ListHead,ListEntry,&SpinLock->SpinLock)); } #undef NdisInterlockedRemoveHeadList PLIST_ENTRY NdisInterlockedRemoveHeadList( IN PLIST_ENTRY ListHead, IN PNDIS_SPIN_LOCK SpinLock ) { return(ExInterlockedRemoveHeadList(ListHead, &SpinLock->SpinLock)); } #undef NdisInterlockedPushEntryList PSINGLE_LIST_ENTRY NdisInterlockedPushEntryList( IN PSINGLE_LIST_ENTRY ListHead, IN PSINGLE_LIST_ENTRY ListEntry, IN PNDIS_SPIN_LOCK Lock ) { return(ExInterlockedPushEntryList(ListHead, ListEntry, &Lock->SpinLock)); } #undef NdisInterlockedPopEntryList PSINGLE_LIST_ENTRY NdisInterlockedPopEntryList( IN PSINGLE_LIST_ENTRY ListHead, IN PNDIS_SPIN_LOCK Lock ) { return(ExInterlockedPopEntryList(ListHead, &Lock->SpinLock)); } // // Logging support for miniports // NDIS_STATUS NdisMCreateLog( IN NDIS_HANDLE MiniportAdapterHandle, IN UINT Size, OUT PNDIS_HANDLE LogHandle ) { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; PNDIS_LOG Log = NULL; NDIS_STATUS Status; KIRQL OldIrql; NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql); if (Miniport->Log != NULL) { Status = NDIS_STATUS_FAILURE; } else { Log = ALLOC_FROM_POOL(sizeof(NDIS_LOG) + Size, NDIS_TAG_DBG_LOG); if (Log != NULL) { Status = NDIS_STATUS_SUCCESS; Miniport->Log = Log; INITIALIZE_SPIN_LOCK(&Log->LogLock); Log->Miniport = Miniport; Log->Irp = NULL; Log->TotalSize = Size; Log->CurrentSize = 0; Log->InPtr = 0; Log->OutPtr = 0; } else { Status = NDIS_STATUS_RESOURCES; } } *LogHandle = Log; NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql); return Status; } VOID NdisMCloseLog( IN NDIS_HANDLE LogHandle ) { PNDIS_LOG Log = (PNDIS_LOG)LogHandle; PNDIS_MINIPORT_BLOCK Miniport; KIRQL OldIrql; Miniport = Log->Miniport; NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql); Miniport->Log = NULL; NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql); FREE_POOL(Log); } NDIS_STATUS NdisMWriteLogData( IN NDIS_HANDLE LogHandle, IN PVOID LogBuffer, IN UINT LogBufferSize ) { PNDIS_LOG Log = (PNDIS_LOG)LogHandle; NDIS_STATUS Status = NDIS_STATUS_SUCCESS; KIRQL OldIrql; UINT AmtToCopy; IoAcquireCancelSpinLock(&OldIrql); ACQUIRE_SPIN_LOCK_DPC(&Log->LogLock); if (LogBufferSize <= Log->TotalSize) { if (LogBufferSize <= (Log->TotalSize - Log->InPtr)) { // // Can copy the entire buffer // CopyMemory(Log->LogBuf+Log->InPtr, LogBuffer, LogBufferSize); } else { // // We are going to wrap around. Copy it in two chunks. // AmtToCopy = Log->TotalSize - Log->InPtr; CopyMemory(Log->LogBuf+Log->InPtr, LogBuffer, AmtToCopy); CopyMemory(Log->LogBuf + 0, (PUCHAR)LogBuffer+AmtToCopy, LogBufferSize - AmtToCopy); } // // Update the current size // Log->CurrentSize += LogBufferSize; if (Log->CurrentSize > Log->TotalSize) Log->CurrentSize = Log->TotalSize; // // Update the InPtr and possibly the outptr // Log->InPtr += LogBufferSize; if (Log->InPtr >= Log->TotalSize) { Log->InPtr -= Log->TotalSize; } if (Log->CurrentSize == Log->TotalSize) { Log->OutPtr = Log->InPtr; } // // Check if there is a pending Irp to complete // if (Log->Irp != NULL) { PIRP Irp = Log->Irp; PUCHAR Buffer; Log->Irp = NULL; // // If the InPtr is lagging the OutPtr. then we can simply // copy the data over in one shot. // AmtToCopy = MDL_SIZE(Irp->MdlAddress); if (AmtToCopy > Log->CurrentSize) AmtToCopy = Log->CurrentSize; if ((Log->TotalSize - Log->OutPtr) >= AmtToCopy) { Buffer = MDL_ADDRESS_SAFE(Irp->MdlAddress, LowPagePriority); if (Buffer != NULL) { CopyMemory(Buffer, Log->LogBuf+Log->OutPtr, AmtToCopy); } else Status = NDIS_STATUS_RESOURCES; } else { Buffer = MDL_ADDRESS_SAFE(Irp->MdlAddress, LowPagePriority); if (Buffer != NULL) { CopyMemory(Buffer, Log->LogBuf+Log->OutPtr, Log->TotalSize-Log->OutPtr); CopyMemory(Buffer+Log->TotalSize-Log->OutPtr, Log->LogBuf, AmtToCopy - (Log->TotalSize-Log->OutPtr)); } else Status = NDIS_STATUS_RESOURCES; } Log->CurrentSize -= AmtToCopy; Log->OutPtr += AmtToCopy; if (Log->OutPtr >= Log->TotalSize) Log->OutPtr -= Log->TotalSize; Irp->IoStatus.Information = AmtToCopy; IoSetCancelRoutine(Irp, NULL); Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); } } else { Status = NDIS_STATUS_BUFFER_OVERFLOW; } RELEASE_SPIN_LOCK_DPC(&Log->LogLock); IoReleaseCancelSpinLock(OldIrql); return Status; } NDIS_STATUS FASTCALL ndisMGetLogData( IN PNDIS_MINIPORT_BLOCK Miniport, IN PIRP Irp ) { NTSTATUS Status = STATUS_SUCCESS; KIRQL OldIrql; PNDIS_LOG Log; UINT AmtToCopy; IoAcquireCancelSpinLock(&OldIrql); NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport); if ((Log = Miniport->Log) != NULL) { ACQUIRE_SPIN_LOCK_DPC(&Log->LogLock); if (Log->CurrentSize != 0) { PUCHAR Buffer; // // If the InPtr is lagging the OutPtr. then we can simply // copy the data over in one shot. // AmtToCopy = MDL_SIZE(Irp->MdlAddress); if (AmtToCopy > Log->CurrentSize) AmtToCopy = Log->CurrentSize; Buffer = MDL_ADDRESS_SAFE(Irp->MdlAddress, LowPagePriority); if (Buffer != NULL) { if ((Log->TotalSize - Log->OutPtr) >= AmtToCopy) { CopyMemory(Buffer, Log->LogBuf+Log->OutPtr, AmtToCopy); } else { CopyMemory(Buffer, Log->LogBuf+Log->OutPtr, Log->TotalSize-Log->OutPtr); CopyMemory(Buffer+Log->TotalSize-Log->OutPtr, Log->LogBuf, AmtToCopy - (Log->TotalSize-Log->OutPtr)); } Log->CurrentSize -= AmtToCopy; Log->OutPtr += AmtToCopy; if (Log->OutPtr >= Log->TotalSize) Log->OutPtr -= Log->TotalSize; Irp->IoStatus.Information = AmtToCopy; Status = STATUS_SUCCESS; } else { Status = STATUS_INSUFFICIENT_RESOURCES; } } else if (Log->Irp != NULL) { Status = STATUS_UNSUCCESSFUL; } else { IoSetCancelRoutine(Irp, ndisCancelLogIrp); Log->Irp = Irp; Status = STATUS_PENDING; } RELEASE_SPIN_LOCK_DPC(&Log->LogLock); } else { Status = STATUS_UNSUCCESSFUL; } NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport); IoReleaseCancelSpinLock(OldIrql); return Status; } VOID NdisMFlushLog( IN NDIS_HANDLE LogHandle ) { PNDIS_LOG Log = (PNDIS_LOG)LogHandle; KIRQL OldIrql; ACQUIRE_SPIN_LOCK(&Log->LogLock, &OldIrql); Log->InPtr = 0; Log->OutPtr = 0; Log->CurrentSize = 0; RELEASE_SPIN_LOCK(&Log->LogLock, OldIrql); } NDIS_STATUS NdisMQueryAdapterInstanceName( OUT PNDIS_STRING pAdapterInstanceName, IN NDIS_HANDLE NdisAdapterHandle ) { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle; USHORT cbSize; PVOID ptmp = NULL; NDIS_STATUS Status = NDIS_STATUS_FAILURE; NTSTATUS NtStatus; DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("==>NdisMQueryAdapterInstanceName\n")); // // If we failed to create the adapter instance name then fail this call. // if (NULL != Miniport->pAdapterInstanceName) { // // Allocate storage for the copy of the adapter instance name. // cbSize = Miniport->pAdapterInstanceName->MaximumLength; // // Allocate storage for the new string. // ptmp = ALLOC_FROM_POOL(cbSize, NDIS_TAG_NAME_BUF); if (NULL != ptmp) { RtlZeroMemory(ptmp, cbSize); pAdapterInstanceName->Buffer = ptmp; pAdapterInstanceName->Length = 0; pAdapterInstanceName->MaximumLength = cbSize; NtStatus = RtlAppendUnicodeStringToString( pAdapterInstanceName, Miniport->pAdapterInstanceName); if (NT_SUCCESS(NtStatus)) { Status = NDIS_STATUS_SUCCESS; } } else { Status = NDIS_STATUS_RESOURCES; } } if (NDIS_STATUS_SUCCESS != Status) { if (NULL != ptmp) { FREE_POOL(ptmp); } } DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("<==NdisMQueryAdapterInstanceName: 0x%x\n", Status)); return(Status); } EXPORT VOID NdisInitializeReadWriteLock( IN PNDIS_RW_LOCK Lock ) { NdisZeroMemory(Lock, sizeof(NDIS_RW_LOCK)); } VOID NdisAcquireReadWriteLock( IN PNDIS_RW_LOCK Lock, IN BOOLEAN fWrite, IN PLOCK_STATE LockState ) { if (fWrite) { LockState->LockState = WRITE_LOCK_STATE_UNKNOWN; { UINT i, refcount; ULONG Prc; /* * This means we need to attempt to acquire the lock, * if we do not already own it. * Set the state accordingly. */ if ((Lock)->Context == CURRENT_THREAD) { (LockState)->LockState = LOCK_STATE_ALREADY_ACQUIRED; } else { ACQUIRE_SPIN_LOCK(&(Lock)->SpinLock, &(LockState)->OldIrql); Prc = KeGetCurrentProcessorNumber(); refcount = (Lock)->RefCount[Prc].RefCount; (Lock)->RefCount[Prc].RefCount = 0; /* wait for all readers to exit */ for (i=0; i < ndisNumberOfProcessors; i++) { volatile UINT *_p = &(Lock)->RefCount[i].RefCount; while (*_p != 0) NDIS_INTERNAL_STALL(50); } (Lock)->RefCount[Prc].RefCount = refcount; (Lock)->Context = CURRENT_THREAD; (LockState)->LockState = WRITE_LOCK_STATE_FREE; } } } else { LockState->LockState = READ_LOCK; { UINT refcount; ULONG Prc; RAISE_IRQL_TO_DISPATCH(&(LockState)->OldIrql); /* go ahead and bump up the ref count IF no writes are underway */ Prc = CURRENT_PROCESSOR; refcount = InterlockedIncrement(&Lock->RefCount[Prc].RefCount); /* Test if spin lock is held, i.e., write is underway */ /* if (KeTestSpinLock(&(_L)->SpinLock) == TRUE) */ /* This processor already is holding the lock, just */ /* allow him to take it again or else we run into a */ /* dead-lock situation with the writer */ if (TEST_SPIN_LOCK((Lock)->SpinLock) && (refcount == 1) && ((Lock)->Context != CURRENT_THREAD)) { (Lock)->RefCount[Prc].RefCount--; ACQUIRE_SPIN_LOCK_DPC(&(Lock)->SpinLock); (Lock)->RefCount[Prc].RefCount++; RELEASE_SPIN_LOCK_DPC(&(Lock)->SpinLock); } (LockState)->LockState = READ_LOCK_STATE_FREE; } } // LockState->LockState = fWrite ? WRITE_LOCK_STATE_UNKNOWN : READ_LOCK; // xLockHandler(Lock, LockState); } VOID NdisReleaseReadWriteLock( IN PNDIS_RW_LOCK Lock, IN PLOCK_STATE LockState ) { xLockHandler(Lock, LockState); }