Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

882 lines
23 KiB

/*++
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);
}