3535 lines
90 KiB
C
3535 lines
90 KiB
C
/*++
|
|
|
|
Copyright (c) 1990-1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
common.c
|
|
|
|
Abstract:
|
|
|
|
NDIS wrapper functions common to miniports and full mac drivers
|
|
|
|
Author:
|
|
|
|
Adam Barr (adamba) 11-Jul-1990
|
|
|
|
Environment:
|
|
|
|
Kernel mode, FSD
|
|
|
|
Revision History:
|
|
|
|
26-Feb-1991 JohnsonA Added Debugging Code
|
|
10-Jul-1991 JohnsonA Implement revised Ndis Specs
|
|
01-Jun-1995 JameelH Re-organization/optimization
|
|
09-Apr-1996 KyleB Added resource remove and acquisition routines.
|
|
|
|
--*/
|
|
|
|
|
|
#include <precomp.h>
|
|
#pragma hdrstop
|
|
|
|
#include <stdarg.h>
|
|
|
|
//
|
|
// Define the module number for debug code.
|
|
//
|
|
#define MODULE_NUMBER MODULE_COMMON
|
|
|
|
//
|
|
// Routines for dealing with making the PKG specific routines pagable
|
|
//
|
|
|
|
VOID FASTCALL
|
|
ndisInitializePackage(
|
|
IN PPKG_REF pPkg
|
|
)
|
|
{
|
|
//
|
|
// Lock and unlock the section to obtain the handle. Subsequent locks will be faster
|
|
//
|
|
pPkg->ImageHandle = MmLockPagableCodeSection(pPkg->Address);
|
|
MmUnlockPagableImageSection(pPkg->ImageHandle);
|
|
}
|
|
|
|
|
|
VOID FASTCALL
|
|
ndisReferencePackage(
|
|
IN PPKG_REF pPkg
|
|
)
|
|
{
|
|
ASSERT(CURRENT_IRQL < DISPATCH_LEVEL);
|
|
MmLockPagableSectionByHandle(pPkg->ImageHandle);
|
|
InterlockedIncrement(&pPkg->ReferenceCount);
|
|
}
|
|
|
|
|
|
VOID FASTCALL
|
|
ndisDereferencePackage(
|
|
IN PPKG_REF pPkg
|
|
)
|
|
{
|
|
ASSERT(CURRENT_IRQL < DISPATCH_LEVEL);
|
|
MmUnlockPagableImageSection(pPkg->ImageHandle);
|
|
InterlockedDecrement(&pPkg->ReferenceCount);
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
NdisAllocateMemory(
|
|
OUT PVOID * VirtualAddress,
|
|
IN UINT Length,
|
|
IN UINT MemoryFlags,
|
|
IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate memory for use by a protocol or a MAC driver
|
|
|
|
Arguments:
|
|
|
|
VirtualAddress - Returns a pointer to the allocated memory.
|
|
Length - Size of requested allocation in bytes.
|
|
MaximumPhysicalAddress - Highest addressable address of the allocated
|
|
memory.. 0 means highest system memory possible.
|
|
MemoryFlags - Bit mask that allows the caller to specify attributes
|
|
of the allocated memory. 0 means standard memory.
|
|
|
|
other options:
|
|
|
|
NDIS_MEMORY_CONTIGUOUS
|
|
NDIS_MEMORY_NONCACHED
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS if successful.
|
|
NDIS_STATUS_FAILURE if not successful. *VirtualAddress will be NULL.
|
|
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Depending on the value of MemoryFlags, we allocate three different
|
|
// types of memory.
|
|
//
|
|
|
|
if (MemoryFlags == 0)
|
|
{
|
|
*VirtualAddress = ALLOC_FROM_POOL(Length, NDIS_TAG_ALLOC_MEM);
|
|
}
|
|
else if (MemoryFlags & NDIS_MEMORY_NONCACHED)
|
|
{
|
|
*VirtualAddress = MmAllocateNonCachedMemory(Length);
|
|
}
|
|
else if (MemoryFlags & NDIS_MEMORY_CONTIGUOUS)
|
|
{
|
|
*VirtualAddress = MmAllocateContiguousMemory(Length, HighestAcceptableAddress);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// invalid flags
|
|
//
|
|
*VirtualAddress = NULL;
|
|
}
|
|
|
|
return (*VirtualAddress == NULL) ? NDIS_STATUS_FAILURE : NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
NdisAllocateMemoryWithTag(
|
|
OUT PVOID * VirtualAddress,
|
|
IN UINT Length,
|
|
IN ULONG Tag
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate memory for use by a protocol or a MAC driver
|
|
|
|
Arguments:
|
|
|
|
VirtualAddress - Returns a pointer to the allocated memory.
|
|
Length - Size of requested allocation in bytes.
|
|
Tag - tag to associate with this memory.
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS if successful.
|
|
NDIS_STATUS_FAILURE if not successful. *VirtualAddress will be NULL.
|
|
|
|
--*/
|
|
{
|
|
*VirtualAddress = ALLOC_FROM_POOL(Length, Tag);
|
|
return (*VirtualAddress == NULL) ? NDIS_STATUS_FAILURE : NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisFreeMemory(
|
|
IN PVOID VirtualAddress,
|
|
IN UINT Length,
|
|
IN UINT MemoryFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Releases memory allocated using NdisAllocateMemory.
|
|
|
|
Arguments:
|
|
|
|
VirtualAddress - Pointer to the memory to be freed.
|
|
Length - Size of allocation in bytes.
|
|
MemoryFlags - Bit mask that allows the caller to specify attributes
|
|
of the allocated memory. 0 means standard memory.
|
|
|
|
other options:
|
|
|
|
NDIS_MEMORY_CONTIGUOUS
|
|
NDIS_MEMORY_NONCACHED
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Depending on the value of MemoryFlags, we allocate three free 3
|
|
// types of memory.
|
|
//
|
|
|
|
if (MemoryFlags == 0)
|
|
{
|
|
FREE_POOL(VirtualAddress);
|
|
}
|
|
else if (MemoryFlags & NDIS_MEMORY_NONCACHED)
|
|
{
|
|
MmFreeNonCachedMemory(VirtualAddress, Length);
|
|
}
|
|
else if (MemoryFlags & NDIS_MEMORY_CONTIGUOUS)
|
|
{
|
|
MmFreeContiguousMemory(VirtualAddress);
|
|
}
|
|
}
|
|
|
|
//1 With the new packet pool allocation, there is no need to export this any more
|
|
UINT
|
|
NdisPacketSize(
|
|
IN UINT ProtocolReservedSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the size of the packet given the amount of protocolreserved. This lets the caller
|
|
do a better job with # of packets it allocates in a single pool.
|
|
|
|
Arguments:
|
|
|
|
ProtocolReservedSize - Size of protocol reserved in bytes
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
UINT PacketLength;
|
|
|
|
PacketLength = SIZE_PACKET_STACKS + sizeof(NDIS_PACKET_OOB_DATA) + sizeof(NDIS_PACKET_EXTENSION);
|
|
PacketLength += ((FIELD_OFFSET(NDIS_PACKET, ProtocolReserved) + ProtocolReservedSize + sizeof(ULONGLONG) - 1) & ~(sizeof(ULONGLONG) -1));
|
|
|
|
//
|
|
// Round the entire length up to a memory allocation alignment.
|
|
//
|
|
|
|
PacketLength = (PacketLength + MEMORY_ALLOCATION_ALIGNMENT - 1) & ~(MEMORY_ALLOCATION_ALIGNMENT - 1);
|
|
|
|
return(PacketLength);
|
|
}
|
|
|
|
|
|
NDIS_HANDLE
|
|
NdisGetPoolFromPacket(
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
Packet - Packet in question
|
|
|
|
Return Value:
|
|
|
|
Pool handle corresponding to the packet
|
|
|
|
--*/
|
|
{
|
|
PNDIS_PKT_POOL Pool = (PNDIS_PKT_POOL)Packet->Private.Pool;
|
|
|
|
return(Pool);
|
|
}
|
|
|
|
PNDIS_PACKET_STACK
|
|
NdisIMGetCurrentPacketStack(
|
|
IN PNDIS_PACKET Packet,
|
|
OUT BOOLEAN * StacksRemaining
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
Packet - Packet in question
|
|
|
|
Return Value:
|
|
|
|
Pointer to the new stack location or NULL if we are out of stacks
|
|
|
|
--*/
|
|
{
|
|
PNDIS_PACKET_STACK pStack;
|
|
|
|
GET_CURRENT_PACKET_STACK_X(Packet, &pStack, StacksRemaining);
|
|
|
|
return(pStack);
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisAllocatePacketPool(
|
|
OUT PNDIS_STATUS Status,
|
|
OUT PNDIS_HANDLE PoolHandle,
|
|
IN UINT NumberOfDescriptors,
|
|
IN UINT ProtocolReservedLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
See ndisAllocPacketPool.
|
|
|
|
Arguments:
|
|
|
|
Status - Returns the final status (always NDIS_STATUS_SUCCESS).
|
|
PoolHandle - Returns a pointer to the pool.
|
|
NumberOfDescriptors - Number of packet descriptors needed.
|
|
ProtocolReservedLength - How long the ProtocolReserved field
|
|
should be for packets in this pool.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PVOID Caller, CallersCaller;
|
|
|
|
//
|
|
// We save the address of the caller in the pool header, for debugging.
|
|
//
|
|
RtlGetCallersAddress(&Caller, &CallersCaller);
|
|
|
|
NdisAllocatePacketPoolEx(Status,
|
|
PoolHandle,
|
|
NumberOfDescriptors,
|
|
0,
|
|
ProtocolReservedLength);
|
|
|
|
if (*Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
PNDIS_PKT_POOL Pool = *PoolHandle;
|
|
|
|
Pool->Allocator = Caller;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisAllocatePacketPoolEx(
|
|
OUT PNDIS_STATUS Status,
|
|
OUT PNDIS_HANDLE PoolHandle,
|
|
IN UINT NumberOfDescriptors,
|
|
IN UINT NumberOfOverflowDescriptors,
|
|
IN UINT ProtocolReservedLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes a packet pool. All packets are the same size for a given pool
|
|
(as determined by ProtocolReservedLength).
|
|
|
|
Pool is organized as a pool-header and a number of page-size blocks
|
|
|
|
Arguments:
|
|
|
|
Status - Returns the final status (always NDIS_STATUS_SUCCESS).
|
|
PoolHandle - Returns a pointer to the pool.
|
|
NumberOfDescriptors - Number of packet descriptors needed.
|
|
NumberOfOverflowDescriptors - Number of packet descriptors needed.
|
|
ProtocolReservedLength - How long the ProtocolReserved field should be for packets in this pool.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_PKT_POOL Pool;
|
|
PNDIS_PACKET Packet;
|
|
UINT NumPkts = (NumberOfDescriptors + NumberOfOverflowDescriptors);
|
|
ULONG Tag = NDIS_TAG_PKT_POOL;
|
|
NDIS_HANDLE tag = *PoolHandle;
|
|
ULONG_PTR TmpTag;
|
|
PVOID Caller, CallersCaller;
|
|
KIRQL OldIrql;
|
|
|
|
//
|
|
// We save the address of the caller in the pool header, for debugging.
|
|
//
|
|
RtlGetCallersAddress(&Caller, &CallersCaller);
|
|
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("==>NdisAllocatePacketPoolEx\n"));
|
|
|
|
do
|
|
{
|
|
*PoolHandle = NULL;
|
|
TmpTag = (ULONG_PTR)tag & 0xffffff;
|
|
|
|
if ((TmpTag == '\0PDN') ||
|
|
(TmpTag == '\0pDN'))
|
|
{
|
|
//
|
|
// zero out the high order bit otherwise the verifier gets confused
|
|
//
|
|
Tag = (ULONG)((ULONG_PTR)tag & 0x7fffffff);
|
|
}
|
|
|
|
Pool = (PNDIS_PKT_POOL)ALLOC_FROM_POOL(sizeof(NDIS_PKT_POOL), Tag);
|
|
if (Pool == NULL)
|
|
{
|
|
*Status = NDIS_STATUS_RESOURCES;
|
|
return;
|
|
}
|
|
|
|
ZeroMemory(Pool, sizeof(NDIS_PKT_POOL));
|
|
|
|
Pool->Tag = Tag;
|
|
Pool->PacketLength = (USHORT)NdisPacketSize(ProtocolReservedLength);
|
|
Pool->PktsPerBlock = (USHORT)((PAGE_SIZE - sizeof(NDIS_PKT_POOL_HDR))/Pool->PacketLength);
|
|
if (Pool->PktsPerBlock != 0)
|
|
{
|
|
Pool->MaxBlocks = (NumPkts + Pool->PktsPerBlock - 1)/Pool->PktsPerBlock;
|
|
Pool->BlockSize = PAGE_SIZE;
|
|
}
|
|
|
|
INITIALIZE_SPIN_LOCK(&Pool->Lock);
|
|
|
|
if ((Pool->PktsPerBlock > NumPkts) || (Pool->PktsPerBlock == 0))
|
|
{
|
|
//
|
|
// This is a pool which does not warrant a full-page or packet is too big to fit in
|
|
// one page.
|
|
//
|
|
Pool->BlockSize = (ULONG)(sizeof(NDIS_PKT_POOL_HDR) + (NumPkts*Pool->PacketLength));
|
|
Pool->PktsPerBlock = (USHORT)NumPkts;
|
|
Pool->MaxBlocks = 1;
|
|
}
|
|
|
|
Pool->ProtocolId = NDIS_PROTOCOL_ID_DEFAULT;
|
|
InitializeListHead(&Pool->AgingBlocks);
|
|
InitializeListHead(&Pool->FreeBlocks);
|
|
InitializeListHead(&Pool->UsedBlocks);
|
|
|
|
ACQUIRE_SPIN_LOCK(&ndisGlobalPacketPoolListLock, &OldIrql);
|
|
InsertHeadList(&ndisGlobalPacketPoolList, &Pool->GlobalPacketPoolList);
|
|
RELEASE_SPIN_LOCK(&ndisGlobalPacketPoolListLock, OldIrql);
|
|
|
|
|
|
//
|
|
// Prime the pool by allocating a packet and freeing it.
|
|
// Aging will ensure it is not immediately freed
|
|
//
|
|
NdisAllocatePacket(Status, &Packet, Pool);
|
|
if (*Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
ACQUIRE_SPIN_LOCK(&ndisGlobalPacketPoolListLock, &OldIrql);
|
|
RemoveEntryList(&Pool->GlobalPacketPoolList);
|
|
RELEASE_SPIN_LOCK(&ndisGlobalPacketPoolListLock, OldIrql);
|
|
FREE_POOL(Pool);
|
|
break;
|
|
}
|
|
NdisFreePacket(Packet);
|
|
*PoolHandle = Pool;
|
|
Pool->Allocator = Caller;
|
|
} while (FALSE);
|
|
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("<==NdisAllocatePacketPoolEx, Status %.8x\n", *Status));
|
|
}
|
|
|
|
VOID
|
|
NdisFreePacketPool(
|
|
IN NDIS_HANDLE PoolHandle
|
|
)
|
|
{
|
|
ndisFreePacketPool(PoolHandle, FALSE);
|
|
}
|
|
|
|
VOID
|
|
ndisFreePacketPool(
|
|
IN NDIS_HANDLE PoolHandle,
|
|
IN BOOLEAN Verify
|
|
)
|
|
{
|
|
PNDIS_PKT_POOL Pool = (PNDIS_PKT_POOL)PoolHandle;
|
|
PNDIS_PKT_POOL_HDR Hdr;
|
|
PLIST_ENTRY List;
|
|
KIRQL OldIrql;
|
|
|
|
ACQUIRE_SPIN_LOCK(&Pool->Lock, &OldIrql);
|
|
|
|
if (Verify)
|
|
ASSERTMSG("NdisFreePacketPool: Freeing non-empty pool\n", IsListEmpty(&Pool->UsedBlocks));
|
|
|
|
while (!IsListEmpty(&Pool->AgingBlocks))
|
|
{
|
|
List = RemoveHeadList(&Pool->AgingBlocks);
|
|
ASSERT(List != NULL);
|
|
Hdr = CONTAINING_RECORD(List, NDIS_PKT_POOL_HDR, List);
|
|
if (Verify)
|
|
ASSERT(ExQueryDepthSList(&Hdr->FreeList) == Pool->PktsPerBlock);
|
|
Pool->BlocksAllocated --;
|
|
FREE_POOL(Hdr);
|
|
}
|
|
|
|
while (!IsListEmpty(&Pool->FreeBlocks))
|
|
{
|
|
List = RemoveHeadList(&Pool->FreeBlocks);
|
|
ASSERT(List != NULL);
|
|
Hdr = CONTAINING_RECORD(List, NDIS_PKT_POOL_HDR, List);
|
|
if (Verify)
|
|
ASSERT(ExQueryDepthSList(&Hdr->FreeList) == Pool->PktsPerBlock);
|
|
Pool->BlocksAllocated --;
|
|
FREE_POOL(Hdr);
|
|
}
|
|
|
|
//
|
|
// We should never be executing the code below (see assertmsg() above). This should perhaps
|
|
// be turned into a KeBugCheckEx()
|
|
//
|
|
while (!IsListEmpty(&Pool->UsedBlocks))
|
|
{
|
|
List = RemoveHeadList(&Pool->UsedBlocks);
|
|
ASSERT(List != NULL);
|
|
Hdr = CONTAINING_RECORD(List, NDIS_PKT_POOL_HDR, List);
|
|
FREE_POOL(Hdr);
|
|
Pool->BlocksAllocated --;
|
|
}
|
|
|
|
ASSERT(Pool->BlocksAllocated == 0);
|
|
|
|
ACQUIRE_SPIN_LOCK_DPC(&ndisGlobalPacketPoolListLock);
|
|
RemoveEntryList(&Pool->GlobalPacketPoolList);
|
|
RELEASE_SPIN_LOCK_DPC(&ndisGlobalPacketPoolListLock);
|
|
|
|
RELEASE_SPIN_LOCK(&Pool->Lock, OldIrql);
|
|
|
|
FREE_POOL(Pool);
|
|
}
|
|
|
|
|
|
#define ndisInitializePacket(_Packet) \
|
|
{ \
|
|
/* \
|
|
* Set the current stack pointer to -1 \
|
|
*/ \
|
|
CURR_STACK_LOCATION(_Packet) = (ULONG)-1; \
|
|
CURR_XFER_DATA_STACK_LOCATION(_Packet) = (ULONG)-1; \
|
|
NDIS_SET_ORIGINAL_PACKET(_Packet, _Packet); \
|
|
(_Packet)->Private.Head = NULL; \
|
|
(_Packet)->Private.ValidCounts = FALSE; \
|
|
(_Packet)->Private.NdisPacketFlags = fPACKET_ALLOCATED_BY_NDIS; \
|
|
}
|
|
|
|
VOID
|
|
NdisAllocatePacket(
|
|
OUT PNDIS_STATUS Status,
|
|
OUT PNDIS_PACKET * Packet,
|
|
IN NDIS_HANDLE PoolHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates a packet out of a packet pool.
|
|
|
|
Arguments:
|
|
|
|
Status - Returns the final status.
|
|
Packet - Return a pointer to the packet.
|
|
PoolHandle - The packet pool to allocate from.
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS If we succeeded.
|
|
NDIS_STATUS_RESOURCES On a failure to allocate or exceeded limit
|
|
|
|
--*/
|
|
{
|
|
PNDIS_PKT_POOL Pool = (PNDIS_PKT_POOL)PoolHandle;
|
|
PNDIS_PKT_POOL_HDR Hdr;
|
|
PLIST_ENTRY List;
|
|
PSLIST_ENTRY SList;
|
|
KIRQL OldIrql;
|
|
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("==> NdisAllocatePacket\n"));
|
|
|
|
IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR)
|
|
{
|
|
if (DbgIsNull(Pool))
|
|
{
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
|
|
("NdisAllocatePacket: NULL Pool address\n"));
|
|
DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
|
|
}
|
|
}
|
|
|
|
do
|
|
{
|
|
SList = NULL;
|
|
|
|
//
|
|
// First check if we have any free packets readily available
|
|
// but get a pointer to Flink before doing the check. this will save us aginst
|
|
// the situations that List can become empty right after the check below.
|
|
//
|
|
List = Pool->FreeBlocks.Flink;
|
|
|
|
if (List != &Pool->FreeBlocks)
|
|
{
|
|
Hdr = CONTAINING_RECORD(List, NDIS_PKT_POOL_HDR, List);
|
|
SList = InterlockedPopEntrySList(&Hdr->FreeList);
|
|
|
|
//
|
|
// Another processor can exhaust the block between the check for non-empty and the pop
|
|
//
|
|
if (SList == NULL)
|
|
{
|
|
goto try_aging_block;
|
|
}
|
|
|
|
#ifdef NDIS_PKT_POOL_STATISTICS
|
|
InterlockedIncrement(&Pool->cAllocatedFromFreeBlocks);
|
|
#endif
|
|
//
|
|
// We got the packet, now see if some book-keeping is in order
|
|
//
|
|
if ((Pool->MaxBlocks > 1) &&
|
|
ExQueryDepthSList(&Hdr->FreeList) == 0)
|
|
{
|
|
//
|
|
// This block is now completely used up. Move it to the UsedBlocks list.
|
|
// The sequence below guarantees that there is no race condition
|
|
//
|
|
ACQUIRE_SPIN_LOCK(&Pool->Lock, &OldIrql);
|
|
|
|
RemoveEntryList(&Hdr->List);
|
|
if (ExQueryDepthSList(&Hdr->FreeList) == 0)
|
|
{
|
|
InsertTailList(&Pool->UsedBlocks, List);
|
|
Hdr->State = NDIS_PACKET_POOL_BLOCK_USED;
|
|
|
|
#ifdef NDIS_PKT_POOL_STATISTICS
|
|
InterlockedIncrement(&Pool->cMovedFreeBlocksToUsed);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
InsertHeadList(&Pool->FreeBlocks, &Hdr->List);
|
|
Hdr->State = NDIS_PACKET_POOL_BLOCK_FREE;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&Pool->Lock, OldIrql);
|
|
}
|
|
break;
|
|
}
|
|
|
|
try_aging_block:
|
|
//
|
|
// Try taking an aging block and move it into the free block
|
|
//
|
|
ACQUIRE_SPIN_LOCK(&Pool->Lock, &OldIrql);
|
|
|
|
if (!IsListEmpty(&Pool->AgingBlocks))
|
|
{
|
|
List = RemoveHeadList(&Pool->AgingBlocks);
|
|
ASSERT (List != NULL);
|
|
|
|
Hdr = CONTAINING_RECORD(List, NDIS_PKT_POOL_HDR, List);
|
|
SList = InterlockedPopEntrySList(&Hdr->FreeList);
|
|
ASSERT(SList != NULL);
|
|
InsertHeadList(&Pool->FreeBlocks, List);
|
|
Hdr->State = NDIS_PACKET_POOL_BLOCK_FREE;
|
|
|
|
#ifdef NDIS_PKT_POOL_STATISTICS
|
|
InterlockedIncrement(&Pool->cMovedAgedBlocksToFree);
|
|
#endif
|
|
|
|
if (!IsListEmpty(&Pool->AgingBlocks))
|
|
{
|
|
List = Pool->AgingBlocks.Flink;
|
|
Hdr = CONTAINING_RECORD(List, NDIS_PKT_POOL_HDR, List);
|
|
Pool->NextScavengeTick.QuadPart = Hdr->TimeStamp.QuadPart + PoolAgingTicks.QuadPart;
|
|
}
|
|
else
|
|
{
|
|
Pool->NextScavengeTick.QuadPart = 0;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&Pool->Lock, OldIrql);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// See if have any head room to allocate more blocks
|
|
//
|
|
if (Pool->BlocksAllocated < Pool->MaxBlocks)
|
|
{
|
|
PUCHAR pTmp;
|
|
ULONG i, j;
|
|
|
|
Hdr = (PNDIS_PKT_POOL_HDR)ALLOC_FROM_POOL(Pool->BlockSize, Pool->Tag);
|
|
if (Hdr == NULL)
|
|
{
|
|
RELEASE_SPIN_LOCK(&Pool->Lock, OldIrql);
|
|
break;
|
|
}
|
|
NdisZeroMemory(Hdr, Pool->BlockSize);
|
|
|
|
Pool->BlocksAllocated ++;
|
|
InitializeListHead(&Hdr->List);
|
|
ExInitializeSListHead(&Hdr->FreeList);
|
|
pTmp = (PUCHAR)Hdr + sizeof(NDIS_PKT_POOL_HDR);
|
|
for (i = Pool->PktsPerBlock; i > 0; i --)
|
|
{
|
|
PNDIS_PACKET p;
|
|
PNDIS_STACK_RESERVED NSR;
|
|
|
|
p = (PNDIS_PACKET)(pTmp + SIZE_PACKET_STACKS);
|
|
p->Private.NdisPacketFlags = 0;
|
|
pTmp += Pool->PacketLength;
|
|
#ifdef _WIN64
|
|
InterlockedPushEntrySList(&Hdr->FreeList,
|
|
(PSLIST_ENTRY)p);
|
|
#else
|
|
|
|
InterlockedPushEntrySList(&Hdr->FreeList,
|
|
(PSLIST_ENTRY)(&p->Private.Head));
|
|
#endif
|
|
|
|
p->Private.Pool = Pool;
|
|
p->Private.Flags = Pool->ProtocolId;
|
|
|
|
//
|
|
// Set the offset to the out of band data.
|
|
//
|
|
p->Private.NdisPacketOobOffset = (USHORT)(Pool->PacketLength -
|
|
(SIZE_PACKET_STACKS +
|
|
sizeof(NDIS_PACKET_OOB_DATA) +
|
|
sizeof(NDIS_PACKET_EXTENSION)));
|
|
NDIS_SET_ORIGINAL_PACKET(p, p);
|
|
|
|
//
|
|
// initialize the spinlocks on packet stack
|
|
//
|
|
for (j = 0; j < ndisPacketStackSize; j++)
|
|
{
|
|
CURR_STACK_LOCATION(p) = j;
|
|
NDIS_STACK_RESERVED_FROM_PACKET(p, &NSR);
|
|
INITIALIZE_SPIN_LOCK(&NSR->Lock);
|
|
}
|
|
}
|
|
|
|
SList = InterlockedPopEntrySList(&Hdr->FreeList);
|
|
|
|
InsertHeadList(&Pool->FreeBlocks, &Hdr->List);
|
|
Hdr->State = NDIS_PACKET_POOL_BLOCK_FREE;
|
|
|
|
#ifdef NDIS_PKT_POOL_STATISTICS
|
|
InterlockedIncrement(&Pool->cAllocatedNewBlocks);
|
|
#endif
|
|
|
|
RELEASE_SPIN_LOCK(&Pool->Lock, OldIrql);
|
|
break;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&Pool->Lock, OldIrql);
|
|
|
|
} while (FALSE);
|
|
|
|
if (SList != NULL)
|
|
{
|
|
|
|
#ifdef _WIN64
|
|
*Packet = (PNDIS_PACKET)SList;
|
|
#else
|
|
*Packet = CONTAINING_RECORD(SList, NDIS_PACKET, Private.Head);
|
|
#endif
|
|
*Status = NDIS_STATUS_SUCCESS;
|
|
ndisInitializePacket(*Packet);
|
|
}
|
|
else
|
|
{
|
|
*Packet = NULL;
|
|
*Status = NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("<==NdisAllocatePacket, Status %.8x\n", *Status));
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisFreePacket(
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
{
|
|
PNDIS_PKT_POOL_HDR Hdr;
|
|
PNDIS_PKT_POOL Pool;
|
|
LARGE_INTEGER CurrTick;
|
|
KIRQL OldIrql;
|
|
LARGE_INTEGER HdrDeadTicks;
|
|
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("==>NdisFreePacket\n"));
|
|
|
|
ASSERT(Packet->Private.NdisPacketFlags & fPACKET_ALLOCATED_BY_NDIS);
|
|
Packet->Private.NdisPacketFlags =0;
|
|
|
|
Pool = Packet->Private.Pool;
|
|
|
|
Hdr = (PNDIS_PKT_POOL_HDR)((ULONG_PTR)Packet & ~(PAGE_SIZE - 1));
|
|
if (Pool->BlockSize != PAGE_SIZE)
|
|
{
|
|
PLIST_ENTRY List;
|
|
|
|
//
|
|
// This pool is not a page-sized pool and so the hdr is not page-aligned.
|
|
// However we know that for such as pool, the Hdr is part of the FreeBlocks
|
|
// list and is never moved to either Used or Aging blocks.
|
|
//
|
|
List = Pool->FreeBlocks.Flink;
|
|
Hdr = CONTAINING_RECORD(List, NDIS_PKT_POOL_HDR, List);
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
ExInterlockedPushEntrySList(&Hdr->FreeList, (PSLIST_ENTRY)Packet, &Pool->Lock);
|
|
#else
|
|
|
|
ExInterlockedPushEntrySList(&Hdr->FreeList,
|
|
CONTAINING_RECORD(&Packet->Private.Head, SLIST_ENTRY, Next),
|
|
&Pool->Lock);
|
|
#endif
|
|
|
|
//
|
|
// If this pool is a pool > 1 block and more than one has been allocated then ...
|
|
//
|
|
// If this hdr is completely free , then move it from the FreeBlocks list to the AgingBlocks and time-stamp it.
|
|
// Add it at the tail since this makes it sorted in time.
|
|
// While we are at it, check the head of the list and age out an entry if it needs to be.
|
|
//
|
|
if (Pool->MaxBlocks > 1)
|
|
{
|
|
|
|
if (((Pool->BlocksAllocated > 1) && (ExQueryDepthSList(&Hdr->FreeList) == Pool->PktsPerBlock))||
|
|
(Hdr->State == NDIS_PACKET_POOL_BLOCK_USED))
|
|
{
|
|
ACQUIRE_SPIN_LOCK(&Pool->Lock, &OldIrql);
|
|
if (ExQueryDepthSList(&Hdr->FreeList) == Pool->PktsPerBlock)
|
|
{
|
|
//
|
|
// This block is completely free. Move it to the aged blocks list.
|
|
//
|
|
GET_CURRENT_TICK(&CurrTick);
|
|
Hdr->TimeStamp = CurrTick;
|
|
RemoveEntryList(&Hdr->List);
|
|
InsertTailList(&Pool->AgingBlocks, &Hdr->List);
|
|
Hdr->State = NDIS_PACKET_POOL_BLOCK_AGING;
|
|
|
|
#ifdef NDIS_PKT_POOL_STATISTICS
|
|
InterlockedIncrement(&Pool->cMovedFreeBlocksToAged);
|
|
#endif
|
|
}
|
|
else if (Hdr->State == NDIS_PACKET_POOL_BLOCK_USED)
|
|
{
|
|
//
|
|
// This block was completely used up but now has one or more
|
|
// free packet. Move it to the tail of the free blocks list.
|
|
//
|
|
RemoveEntryList(&Hdr->List);
|
|
InsertTailList(&Pool->FreeBlocks, &Hdr->List);
|
|
Hdr->State = NDIS_PACKET_POOL_BLOCK_FREE;
|
|
|
|
#ifdef NDIS_PKT_POOL_STATISTICS
|
|
InterlockedIncrement(&Pool->cMovedUsedBlocksToFree);
|
|
#endif
|
|
}
|
|
RELEASE_SPIN_LOCK(&Pool->Lock, OldIrql);
|
|
}
|
|
|
|
if (!IsListEmpty(&Pool->AgingBlocks))
|
|
{
|
|
GET_CURRENT_TICK(&CurrTick);
|
|
if (CurrTick.QuadPart > Pool->NextScavengeTick.QuadPart)
|
|
{
|
|
ACQUIRE_SPIN_LOCK(&Pool->Lock, &OldIrql);
|
|
|
|
while (!IsListEmpty(&Pool->AgingBlocks))
|
|
{
|
|
PLIST_ENTRY List = Pool->AgingBlocks.Flink;
|
|
|
|
Hdr = CONTAINING_RECORD(List, NDIS_PKT_POOL_HDR, List);
|
|
|
|
HdrDeadTicks.QuadPart = Hdr->TimeStamp.QuadPart + PoolAgingTicks.QuadPart;
|
|
if (CurrTick.QuadPart > HdrDeadTicks.QuadPart)
|
|
{
|
|
RemoveHeadList(&Pool->AgingBlocks);
|
|
|
|
if (ExQueryDepthSList(&Hdr->FreeList) != Pool->PktsPerBlock)
|
|
{
|
|
//
|
|
// somehow we ended up allocating a packet from an aged block
|
|
// put the block back on free list. this can happen if during
|
|
// NdisAllocatePacket, right after getting a packet from a free
|
|
// block list, the block moves to aging list.
|
|
//
|
|
#if DBG
|
|
DbgPrint("Ndis: pool %p: aged packet pool block at %p contains allocated packets!\n", Pool, Hdr);
|
|
#endif
|
|
InsertHeadList(&Pool->FreeBlocks, &Hdr->List);
|
|
Hdr->State = NDIS_PACKET_POOL_BLOCK_FREE;
|
|
}
|
|
else
|
|
{
|
|
FREE_POOL(Hdr);
|
|
Pool->BlocksAllocated --;
|
|
|
|
#ifdef NDIS_PKT_POOL_STATISTICS
|
|
InterlockedIncrement(&Pool->cFreedAgedBlocks);
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Compute the next tick value which represents the earliest time
|
|
// that we will scavenge this pool again.
|
|
//
|
|
Pool->NextScavengeTick.QuadPart = HdrDeadTicks.QuadPart;
|
|
break;
|
|
}
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&Pool->Lock, OldIrql);
|
|
}
|
|
}
|
|
}
|
|
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("<==NdisFreePacket\n"));
|
|
}
|
|
|
|
UINT
|
|
NdisPacketPoolUsage(
|
|
IN PNDIS_HANDLE PoolHandle
|
|
)
|
|
{
|
|
PNDIS_PKT_POOL Pool = (PNDIS_PKT_POOL)PoolHandle;
|
|
PNDIS_PKT_POOL_HDR Hdr;
|
|
PLIST_ENTRY List;
|
|
UINT NumUsed = 0;
|
|
KIRQL OldIrql;
|
|
|
|
ACQUIRE_SPIN_LOCK(&Pool->Lock, &OldIrql);
|
|
|
|
for (List = Pool->UsedBlocks.Flink; List != &Pool->UsedBlocks; List = List->Flink)
|
|
{
|
|
NumUsed += Pool->PktsPerBlock;
|
|
}
|
|
|
|
for (List = Pool->FreeBlocks.Flink; List != &Pool->FreeBlocks; List = List->Flink)
|
|
{
|
|
Hdr = CONTAINING_RECORD(List, NDIS_PKT_POOL_HDR, List);
|
|
|
|
NumUsed += (Pool->PktsPerBlock - ExQueryDepthSList(&Hdr->FreeList));
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&Pool->Lock, OldIrql);
|
|
|
|
return NumUsed;
|
|
}
|
|
|
|
//1 we probably don't need this API any more.
|
|
VOID
|
|
NdisSetPacketPoolProtocolId(
|
|
IN NDIS_HANDLE PacketPoolHandle,
|
|
IN UINT ProtocolId
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the protocol id in the pool and all the packets allocated to the pool. This api has to be called
|
|
prior to any packets that are allocated out of the pool. The code below is linked to the NdisAllocatePacket
|
|
code in that the first empty pool (Pool->BlocksAllocated == 1) is left at the FreeBlocks list and not
|
|
moved to the AgingList.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_PKT_POOL Pool = (PNDIS_PKT_POOL)PacketPoolHandle;
|
|
PNDIS_PKT_POOL_HDR Hdr;
|
|
PLIST_ENTRY List;
|
|
PNDIS_PACKET Packet;
|
|
PUCHAR p;
|
|
UINT j;
|
|
|
|
Pool->ProtocolId = ProtocolId;
|
|
|
|
ASSERT(IsListEmpty(&Pool->AgingBlocks));
|
|
ASSERT(IsListEmpty(&Pool->UsedBlocks));
|
|
|
|
for (List = Pool->FreeBlocks.Flink; List != &Pool->FreeBlocks; List = List->Flink)
|
|
{
|
|
Hdr = CONTAINING_RECORD(List, NDIS_PKT_POOL_HDR, List);
|
|
p = (PUCHAR)Hdr + sizeof(NDIS_PKT_POOL_HDR);
|
|
|
|
for (j = Pool->PktsPerBlock; j > 0; j--, p += Pool->PacketLength)
|
|
{
|
|
Packet = (PNDIS_PACKET)(p + SIZE_PACKET_STACKS);
|
|
Packet->Private.Flags |= ProtocolId;
|
|
}
|
|
}
|
|
}
|
|
|
|
//1 Deprecate this function for non-binary compatible drivers.
|
|
VOID
|
|
NdisAllocateBufferPool(
|
|
OUT PNDIS_STATUS Status,
|
|
OUT PNDIS_HANDLE PoolHandle,
|
|
IN UINT NumberOfDescriptors
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes a block of storage so that buffer descriptors can be
|
|
allocated.
|
|
|
|
Arguments:
|
|
|
|
Status - status of the request.
|
|
PoolHandle - handle that is used to specify the pool
|
|
NumberOfDescriptors - Number of buffer descriptors in the pool.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
UNREFERENCED_PARAMETER(NumberOfDescriptors);
|
|
|
|
*PoolHandle = NULL;
|
|
*Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
//1 Deprecate this function for non-binary compatible drivers.
|
|
VOID
|
|
NdisFreeBufferPool(
|
|
IN NDIS_HANDLE PoolHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Terminates usage of a buffer descriptor pool.
|
|
|
|
Arguments:
|
|
|
|
PoolHandle - handle that is used to specify the pool
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
UNREFERENCED_PARAMETER(PoolHandle);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisAllocateBuffer(
|
|
OUT PNDIS_STATUS Status,
|
|
OUT PNDIS_BUFFER * Buffer,
|
|
IN NDIS_HANDLE PoolHandle,
|
|
IN PVOID VirtualAddress,
|
|
IN UINT Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a buffer descriptor to describe a segment of virtual memory
|
|
allocated via NdisAllocateMemory (which always allocates nonpaged).
|
|
|
|
Arguments:
|
|
|
|
Status - Status of the request.
|
|
Buffer - Pointer to the allocated buffer descriptor.
|
|
PoolHandle - Handle that is used to specify the pool.
|
|
VirtualAddress - The virtual address of the buffer.
|
|
Length - The Length of the buffer.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
UNREFERENCED_PARAMETER(PoolHandle);
|
|
|
|
*Status = NDIS_STATUS_FAILURE;
|
|
if ((*Buffer = IoAllocateMdl(VirtualAddress,
|
|
Length,
|
|
FALSE,
|
|
FALSE,
|
|
NULL)) != NULL)
|
|
{
|
|
MmBuildMdlForNonPagedPool(*Buffer);
|
|
(*Buffer)->Next = NULL;
|
|
*Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisAdjustBufferLength(
|
|
IN PNDIS_BUFFER Buffer,
|
|
IN UINT Length
|
|
)
|
|
{
|
|
Buffer->ByteCount = Length;
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisCopyBuffer(
|
|
OUT PNDIS_STATUS Status,
|
|
OUT PNDIS_BUFFER * Buffer,
|
|
IN NDIS_HANDLE PoolHandle,
|
|
IN PVOID MemoryDescriptor,
|
|
IN UINT Offset,
|
|
IN UINT Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Used to create a buffer descriptor given a memory descriptor.
|
|
|
|
Arguments:
|
|
|
|
Status - Status of the request.
|
|
Buffer - Pointer to the allocated buffer descriptor.
|
|
PoolHandle - Handle that is used to specify the pool.
|
|
MemoryDescriptor - Pointer to the descriptor of the source memory.
|
|
Offset - The Offset in the sources memory from which the copy is to begin
|
|
Length - Number of Bytes to copy.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_BUFFER SourceDescriptor = (PNDIS_BUFFER)MemoryDescriptor;
|
|
PVOID BaseVa = (((PUCHAR)MDL_VA(SourceDescriptor)) + Offset);
|
|
|
|
UNREFERENCED_PARAMETER(PoolHandle);
|
|
|
|
|
|
*Status = NDIS_STATUS_FAILURE;
|
|
if ((*Buffer = IoAllocateMdl(BaseVa,
|
|
Length,
|
|
FALSE,
|
|
FALSE,
|
|
NULL)) != NULL)
|
|
{
|
|
IoBuildPartialMdl(SourceDescriptor,
|
|
*Buffer,
|
|
BaseVa,
|
|
Length);
|
|
|
|
(*Buffer)->Next = NULL;
|
|
*Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisUnchainBufferAtFront(
|
|
IN OUT PNDIS_PACKET Packet,
|
|
OUT PNDIS_BUFFER * Buffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Takes a buffer off the front of a packet.
|
|
|
|
Arguments:
|
|
|
|
Packet - The packet to be modified.
|
|
Buffer - Returns the packet on the front, or NULL.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
*Buffer = Packet->Private.Head;
|
|
|
|
//
|
|
// If packet is not empty, remove head buffer.
|
|
//
|
|
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("==>NdisUnchainBufferAtFront\n"));
|
|
|
|
if (*Buffer != (PNDIS_BUFFER)NULL)
|
|
{
|
|
Packet->Private.Head = (*Buffer)->Next; // may be NULL
|
|
(*Buffer)->Next = (PNDIS_BUFFER)NULL;
|
|
Packet->Private.ValidCounts = FALSE;
|
|
}
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("<==NdisUnchainBufferAtFront\n"));
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisUnchainBufferAtBack(
|
|
IN OUT PNDIS_PACKET Packet,
|
|
OUT PNDIS_BUFFER * Buffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Takes a buffer off the end of a packet.
|
|
|
|
Arguments:
|
|
|
|
Packet - The packet to be modified.
|
|
Buffer - Returns the packet on the end, or NULL.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNDIS_BUFFER BufP = Packet->Private.Head;
|
|
PNDIS_BUFFER Result;
|
|
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("==>NdisUnchainBufferAtBack\n"));
|
|
|
|
if (BufP != (PNDIS_BUFFER)NULL)
|
|
{
|
|
//
|
|
// The packet is not empty, return the tail buffer.
|
|
//
|
|
|
|
Result = Packet->Private.Tail;
|
|
if (BufP == Result)
|
|
{
|
|
//
|
|
// There was only one buffer on the queue.
|
|
//
|
|
|
|
Packet->Private.Head = (PNDIS_BUFFER)NULL;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Determine the new tail buffer.
|
|
//
|
|
|
|
while (BufP->Next != Result)
|
|
{
|
|
BufP = BufP->Next;
|
|
}
|
|
Packet->Private.Tail = BufP;
|
|
BufP->Next = NULL;
|
|
}
|
|
|
|
Result->Next = (PNDIS_BUFFER)NULL;
|
|
Packet->Private.ValidCounts = FALSE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Packet is empty.
|
|
//
|
|
|
|
Result = (PNDIS_BUFFER)NULL;
|
|
}
|
|
|
|
*Buffer = Result;
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("<==NdisUnchainBufferAtBack\n"));
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
NdisCopyFromPacketToPacket(
|
|
IN PNDIS_PACKET Destination,
|
|
IN UINT DestinationOffset,
|
|
IN UINT BytesToCopy,
|
|
IN PNDIS_PACKET Source,
|
|
IN UINT SourceOffset,
|
|
OUT PUINT BytesCopied
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copy from an ndis packet to an ndis packet.
|
|
|
|
Arguments:
|
|
|
|
Destination - The packet should be copied in to.
|
|
|
|
DestinationOffset - The offset from the beginning of the packet
|
|
into which the data should start being placed.
|
|
|
|
BytesToCopy - The number of bytes to copy from the source packet.
|
|
|
|
Source - The ndis packet from which to copy data.
|
|
|
|
SourceOffset - The offset from the start of the packet from which
|
|
to start copying data.
|
|
|
|
BytesCopied - The number of bytes actually copied from the source
|
|
packet. This can be less than BytesToCopy if the source or destination
|
|
packet is too short.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Points to the buffer into which we are putting data.
|
|
//
|
|
PNDIS_BUFFER DestinationCurrentBuffer;
|
|
|
|
//
|
|
// Points to the buffer from which we are extracting data.
|
|
//
|
|
PNDIS_BUFFER SourceCurrentBuffer;
|
|
|
|
//
|
|
// Holds the virtual address of the current destination buffer.
|
|
//
|
|
PVOID DestinationVirtualAddress;
|
|
|
|
//
|
|
// Holds the virtual address of the current source buffer.
|
|
//
|
|
PVOID SourceVirtualAddress;
|
|
|
|
//
|
|
// Holds the length of the current destination buffer.
|
|
//
|
|
UINT DestinationCurrentLength;
|
|
|
|
//
|
|
// Holds the length of the current source buffer.
|
|
//
|
|
UINT SourceCurrentLength;
|
|
|
|
//
|
|
// Keep a local variable of BytesCopied so we aren't referencing
|
|
// through a pointer.
|
|
//
|
|
UINT LocalBytesCopied = 0;
|
|
|
|
//
|
|
// Take care of boundary condition of zero length copy.
|
|
//
|
|
|
|
*BytesCopied = 0;
|
|
if (!BytesToCopy)
|
|
return;
|
|
|
|
//
|
|
// Get the first buffer of the destination.
|
|
//
|
|
|
|
DestinationCurrentBuffer = Destination->Private.Head;
|
|
//
|
|
// Could have a null packet.
|
|
//
|
|
if (DestinationCurrentBuffer == NULL)
|
|
return;
|
|
|
|
DestinationVirtualAddress = MDL_ADDRESS(DestinationCurrentBuffer);
|
|
DestinationCurrentLength = MDL_SIZE(DestinationCurrentBuffer);
|
|
|
|
|
|
//
|
|
// Get the first buffer of the source.
|
|
//
|
|
|
|
SourceCurrentBuffer = Source->Private.Head;
|
|
|
|
//
|
|
// Could have a null packet.
|
|
//
|
|
|
|
if (SourceCurrentBuffer == NULL)
|
|
return;
|
|
|
|
|
|
SourceVirtualAddress = MDL_ADDRESS(SourceCurrentBuffer);
|
|
SourceCurrentLength = MDL_SIZE(SourceCurrentBuffer);
|
|
|
|
while (LocalBytesCopied < BytesToCopy)
|
|
{
|
|
//
|
|
// Check to see whether we've exhausted the current destination
|
|
// buffer. If so, move onto the next one.
|
|
//
|
|
|
|
if (!DestinationCurrentLength)
|
|
{
|
|
DestinationCurrentBuffer = DestinationCurrentBuffer->Next;
|
|
|
|
if (!DestinationCurrentBuffer)
|
|
{
|
|
//
|
|
// We've reached the end of the packet. We return
|
|
// with what we've done so far. (Which must be shorter
|
|
// than requested.)
|
|
//
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
DestinationVirtualAddress = MDL_ADDRESS(DestinationCurrentBuffer);
|
|
DestinationCurrentLength = MDL_SIZE(DestinationCurrentBuffer);
|
|
|
|
continue;
|
|
}
|
|
|
|
|
|
//
|
|
// Check to see whether we've exhausted the current source
|
|
// buffer. If so, move onto the next one.
|
|
//
|
|
|
|
if (!SourceCurrentLength)
|
|
{
|
|
SourceCurrentBuffer = SourceCurrentBuffer->Next;
|
|
|
|
if (!SourceCurrentBuffer)
|
|
{
|
|
//
|
|
// We've reached the end of the packet. We return
|
|
// with what we've done so far. (Which must be shorter
|
|
// than requested.)
|
|
//
|
|
|
|
break;
|
|
}
|
|
|
|
SourceVirtualAddress = MDL_ADDRESS(SourceCurrentBuffer);
|
|
SourceCurrentLength = MDL_SIZE(SourceCurrentBuffer);
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Try to get us up to the point to start the copy.
|
|
//
|
|
|
|
if (DestinationOffset)
|
|
{
|
|
if (DestinationOffset > DestinationCurrentLength)
|
|
{
|
|
//
|
|
// What we want isn't in this buffer.
|
|
//
|
|
|
|
DestinationOffset -= DestinationCurrentLength;
|
|
DestinationCurrentLength = 0;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
DestinationVirtualAddress = (PCHAR)DestinationVirtualAddress
|
|
+ DestinationOffset;
|
|
DestinationCurrentLength -= DestinationOffset;
|
|
DestinationOffset = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Try to get us up to the point to start the copy.
|
|
//
|
|
|
|
if (SourceOffset)
|
|
{
|
|
if (SourceOffset > SourceCurrentLength)
|
|
{
|
|
//
|
|
// What we want isn't in this buffer.
|
|
//
|
|
|
|
SourceOffset -= SourceCurrentLength;
|
|
SourceCurrentLength = 0;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
SourceVirtualAddress = (PCHAR)SourceVirtualAddress
|
|
+ SourceOffset;
|
|
SourceCurrentLength -= SourceOffset;
|
|
SourceOffset = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Copy the data.
|
|
//
|
|
|
|
{
|
|
//
|
|
// Holds the amount of data to move.
|
|
//
|
|
UINT AmountToMove;
|
|
|
|
//
|
|
// Holds the amount desired remaining.
|
|
//
|
|
UINT Remaining = BytesToCopy - LocalBytesCopied;
|
|
|
|
AmountToMove = ((SourceCurrentLength <= DestinationCurrentLength) ?
|
|
(SourceCurrentLength) : (DestinationCurrentLength));
|
|
|
|
AmountToMove = ((Remaining < AmountToMove)?
|
|
(Remaining):(AmountToMove));
|
|
|
|
CopyMemory(DestinationVirtualAddress, SourceVirtualAddress, AmountToMove);
|
|
|
|
DestinationVirtualAddress =
|
|
(PCHAR)DestinationVirtualAddress + AmountToMove;
|
|
SourceVirtualAddress =
|
|
(PCHAR)SourceVirtualAddress + AmountToMove;
|
|
|
|
LocalBytesCopied += AmountToMove;
|
|
SourceCurrentLength -= AmountToMove;
|
|
DestinationCurrentLength -= AmountToMove;
|
|
}
|
|
}
|
|
|
|
*BytesCopied = LocalBytesCopied;
|
|
}
|
|
|
|
//1 Deprecate this function
|
|
VOID
|
|
NdisUpdateSharedMemory(
|
|
IN NDIS_HANDLE NdisAdapterHandle,
|
|
IN ULONG Length,
|
|
IN PVOID VirtualAddress,
|
|
IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Ensures that the data to be read from a shared memory region is
|
|
fully up-to-date.
|
|
|
|
Arguments:
|
|
|
|
NdisAdapterHandle - handle returned by NdisRegisterAdapter.
|
|
Length - The length of the shared memory.
|
|
VirtualAddress - Virtual address returned by NdisAllocateSharedMemory.
|
|
PhysicalAddress - The physical address returned by NdisAllocateSharedMemory.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// There is no underlying HAL routine for this anymore,
|
|
// it is not needed.
|
|
//
|
|
UNREFERENCED_PARAMETER(NdisAdapterHandle);
|
|
UNREFERENCED_PARAMETER(Length);
|
|
UNREFERENCED_PARAMETER(VirtualAddress);
|
|
UNREFERENCED_PARAMETER(PhysicalAddress);
|
|
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
ndisCheckPortUsage(
|
|
IN ULONG u32PortNumber,
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
OUT PULONG pTranslatedPort,
|
|
OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR * pResourceDescriptor
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks if a port is assigned to this miniport.
|
|
|
|
Arguments:
|
|
|
|
BusNumber - Bus number in the system
|
|
PortNumber - Address of the port to access.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the port is assigned to this miniport, FALSE otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
PHYSICAL_ADDRESS Port;
|
|
PHYSICAL_ADDRESS u64Port;
|
|
|
|
Port.QuadPart = u32PortNumber;
|
|
|
|
if (NDIS_STATUS_SUCCESS == ndisTranslateResources(Miniport,
|
|
CmResourceTypePort,
|
|
Port,
|
|
&u64Port,
|
|
pResourceDescriptor))
|
|
{
|
|
*pTranslatedPort = u64Port.LowPart;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
*pTranslatedPort = 0;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ndisStartMapping(
|
|
IN INTERFACE_TYPE InterfaceType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG InitialAddress,
|
|
IN ULONG Length,
|
|
IN ULONG AddressSpace,
|
|
OUT PVOID * InitialMapping,
|
|
OUT PBOOLEAN Mapped
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initialize the mapping of a address into virtual
|
|
space dependent on the bus number, etc.
|
|
|
|
Arguments:
|
|
|
|
InterfaceType - The bus type (ISA)
|
|
BusNumber - Bus number in the system
|
|
InitialAddress - Address to access.
|
|
Length - Number of bytes from the base address to access.
|
|
InitialMapping - The virtual address space to use when accessing the
|
|
address.
|
|
Mapped - Did an MmMapIoSpace() take place.
|
|
|
|
Return Value:
|
|
|
|
The function value is the status of the operation.
|
|
|
|
--*/
|
|
{
|
|
PHYSICAL_ADDRESS TranslatedAddress;
|
|
PHYSICAL_ADDRESS InitialPhysAddress;
|
|
|
|
//
|
|
// Get the system physical address for this card. The card uses
|
|
// I/O space, except for "internal" Jazz devices which use
|
|
// memory space.
|
|
//
|
|
|
|
*Mapped = FALSE;
|
|
|
|
InitialPhysAddress.LowPart = InitialAddress;
|
|
|
|
InitialPhysAddress.HighPart = 0;
|
|
|
|
if (InterfaceType != -1)
|
|
{
|
|
if ((InterfaceType != Isa) &&
|
|
(InterfaceType != PCIBus))
|
|
{
|
|
InterfaceType = Isa;
|
|
}
|
|
|
|
if (!HalTranslateBusAddress(InterfaceType, // InterfaceType
|
|
BusNumber, // BusNumber
|
|
InitialPhysAddress, // Bus Address
|
|
&AddressSpace, // AddressSpace
|
|
&TranslatedAddress)) // Translated address
|
|
{
|
|
//
|
|
// It would be nice to return a better status here, but we only get
|
|
// TRUE/FALSE back from HalTranslateBusAddress.
|
|
//
|
|
|
|
return NDIS_STATUS_FAILURE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TranslatedAddress = InitialPhysAddress;
|
|
}
|
|
|
|
if (AddressSpace == 0)
|
|
{
|
|
//
|
|
// memory space
|
|
//
|
|
|
|
*InitialMapping = MmMapIoSpace(TranslatedAddress, Length, FALSE);
|
|
|
|
if (*InitialMapping == NULL)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
*Mapped = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// I/O space
|
|
//
|
|
|
|
*(ULONG_PTR *)InitialMapping = TranslatedAddress.LowPart;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ndisEndMapping(
|
|
IN PVOID InitialMapping,
|
|
IN ULONG Length,
|
|
IN BOOLEAN Mapped
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine undoes the mapping of an address into virtual
|
|
space dependent on the bus number, etc.
|
|
|
|
Arguments:
|
|
|
|
InitialMapping - The virtual address space to use when accessing the
|
|
address.
|
|
Length - Number of bytes from the base address to access.
|
|
Mapped - Do we need to call MmUnmapIoSpace.
|
|
|
|
Return Value:
|
|
|
|
The function value is the status of the operation.
|
|
|
|
--*/
|
|
{
|
|
|
|
if (Mapped)
|
|
{
|
|
//
|
|
// memory space
|
|
//
|
|
|
|
MmUnmapIoSpace(InitialMapping, Length);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
ndisImmediateReadWritePort(
|
|
IN NDIS_HANDLE WrapperConfigurationContext,
|
|
IN ULONG Port,
|
|
IN OUT PVOID Data,
|
|
IN ULONG Size,
|
|
IN BOOLEAN Read
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine reads from a port a UCHAR. It does all the mapping,
|
|
etc, to do the read here.
|
|
|
|
Arguments:
|
|
|
|
WrapperConfigurationContext - The handle used to call NdisOpenConfig.
|
|
|
|
Port - Port number to read from.
|
|
|
|
Data - Pointer to place to store the result.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
|
|
PNDIS_MINIPORT_BLOCK Miniport;
|
|
BOOLEAN Mapped = FALSE;
|
|
PVOID PortMapping;
|
|
NDIS_INTERFACE_TYPE BusType;
|
|
ULONG BusNumber;
|
|
NTSTATUS Status;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR pResourceDescriptor = NULL;
|
|
|
|
Miniport = (PNDIS_MINIPORT_BLOCK)KeyQueryTable[3].QueryRoutine;
|
|
BusType = Miniport->BusType;
|
|
BusNumber = Miniport->BusNumber;
|
|
|
|
ASSERT(Miniport != NULL);
|
|
|
|
do
|
|
{
|
|
if (Read)
|
|
{
|
|
switch (Size)
|
|
{
|
|
case sizeof (UCHAR):
|
|
*((PUCHAR)Data) = (UCHAR)0xFF;
|
|
break;
|
|
|
|
case sizeof (USHORT):
|
|
*((PUSHORT)Data) = (USHORT)0xFFFF;
|
|
break;
|
|
|
|
case sizeof (ULONG):
|
|
*((PULONG)Data) = (ULONG)0xFFFFFFFF;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check that the port is available. If so map the space.
|
|
//
|
|
if (ndisCheckPortUsage(Port,
|
|
Miniport,
|
|
(PULONG)&PortMapping,
|
|
&pResourceDescriptor) == FALSE)
|
|
{
|
|
//
|
|
// the resource was not part of already allocated resources,
|
|
// nor could we allocate the resource
|
|
//
|
|
break;
|
|
}
|
|
|
|
if (pResourceDescriptor == NULL)
|
|
{
|
|
//
|
|
// the port is not part of allocated resources, try to
|
|
// temporray allocate the resource
|
|
//
|
|
if (!NT_SUCCESS(Status = ndisStartMapping(BusType,
|
|
BusNumber,
|
|
Port,
|
|
Size,
|
|
(BusType == Internal) ? 0 : 1,
|
|
&PortMapping,
|
|
&Mapped)))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Mapped = FALSE;
|
|
}
|
|
|
|
if (Read)
|
|
{
|
|
//
|
|
// Read from the port
|
|
//
|
|
switch (Size)
|
|
{
|
|
case sizeof (UCHAR):
|
|
*((PUCHAR)Data) = READ_PORT_UCHAR((PUCHAR)PortMapping);
|
|
break;
|
|
|
|
case sizeof (USHORT):
|
|
*((PUSHORT)Data) = READ_PORT_USHORT((PUSHORT)PortMapping);
|
|
break;
|
|
|
|
case sizeof (ULONG):
|
|
*((PULONG)Data) = READ_PORT_ULONG((PULONG)PortMapping);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// write to the port
|
|
//
|
|
switch (Size)
|
|
{
|
|
case sizeof (UCHAR):
|
|
WRITE_PORT_UCHAR((PUCHAR)PortMapping, *((PUCHAR)Data));
|
|
break;
|
|
|
|
case sizeof (USHORT):
|
|
WRITE_PORT_USHORT((PUSHORT)PortMapping, *((PUSHORT)Data));
|
|
break;
|
|
|
|
case sizeof (ULONG):
|
|
WRITE_PORT_ULONG((PULONG)PortMapping, *((PULONG)Data));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Mapped)
|
|
{
|
|
//
|
|
// End port mapping
|
|
//
|
|
|
|
ndisEndMapping(PortMapping, Size, Mapped);
|
|
}
|
|
} while (FALSE);
|
|
}
|
|
|
|
|
|
|
|
//1 Deprecated function
|
|
VOID
|
|
NdisImmediateReadPortUchar(
|
|
IN NDIS_HANDLE WrapperConfigurationContext,
|
|
IN ULONG Port,
|
|
OUT PUCHAR Data
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine reads from a port a UCHAR. It does all the mapping,
|
|
etc, to do the read here.
|
|
|
|
Arguments:
|
|
|
|
WrapperConfigurationContext - The handle used to call NdisOpenConfig.
|
|
|
|
Port - Port number to read from.
|
|
|
|
Data - Pointer to place to store the result.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
#if DBG
|
|
PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)KeyQueryTable[3].QueryRoutine;
|
|
|
|
NDIS_WARN(TRUE, Miniport, NDIS_GFLAG_WARN_LEVEL_1,
|
|
("NdisImmediateReadPortUchar: this API is going away. use non-Immediate version\n", Miniport));
|
|
#endif
|
|
|
|
ndisImmediateReadWritePort(WrapperConfigurationContext,
|
|
Port,
|
|
(PVOID)Data,
|
|
sizeof (UCHAR),
|
|
TRUE);
|
|
}
|
|
|
|
//1 Deprecated function
|
|
VOID
|
|
NdisImmediateReadPortUshort(
|
|
IN NDIS_HANDLE WrapperConfigurationContext,
|
|
IN ULONG Port,
|
|
OUT PUSHORT Data
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine reads from a port a USHORT. It does all the mapping,
|
|
etc, to do the read here.
|
|
|
|
Arguments:
|
|
|
|
WrapperConfigurationContext - The handle used to call NdisOpenConfig.
|
|
|
|
Port - Port number to read from.
|
|
|
|
Data - Pointer to place to store the result.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
#if DBG
|
|
PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)KeyQueryTable[3].QueryRoutine;
|
|
|
|
NDIS_WARN(TRUE, Miniport, NDIS_GFLAG_WARN_LEVEL_1,
|
|
("NdisImmediateReadPortUshort: this API is going away. use non-Immediate version\n", Miniport));
|
|
#endif
|
|
|
|
ndisImmediateReadWritePort(WrapperConfigurationContext,
|
|
Port,
|
|
(PVOID)Data,
|
|
sizeof (USHORT),
|
|
TRUE);
|
|
|
|
}
|
|
|
|
//1 Deprecated function
|
|
VOID
|
|
NdisImmediateReadPortUlong(
|
|
IN NDIS_HANDLE WrapperConfigurationContext,
|
|
IN ULONG Port,
|
|
OUT PULONG Data
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine reads from a port a ULONG. It does all the mapping,
|
|
etc, to do the read here.
|
|
|
|
Arguments:
|
|
|
|
WrapperConfigurationContext - The handle used to call NdisOpenConfig.
|
|
|
|
Port - Port number to read from.
|
|
|
|
Data - Pointer to place to store the result.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
#if DBG
|
|
PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)KeyQueryTable[3].QueryRoutine;
|
|
|
|
NDIS_WARN(TRUE, Miniport, NDIS_GFLAG_WARN_LEVEL_1,
|
|
("NdisImmediateReadPortUlong: this API is going away. use non-Immediate version\n", Miniport));
|
|
#endif
|
|
|
|
ndisImmediateReadWritePort(WrapperConfigurationContext,
|
|
Port,
|
|
(PVOID)Data,
|
|
sizeof (ULONG),
|
|
TRUE);
|
|
|
|
}
|
|
|
|
//1 Deprecated function
|
|
VOID
|
|
NdisImmediateWritePortUchar(
|
|
IN NDIS_HANDLE WrapperConfigurationContext,
|
|
IN ULONG Port,
|
|
IN UCHAR Data
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine writes to a port a UCHAR. It does all the mapping,
|
|
etc, to do the write here.
|
|
|
|
Arguments:
|
|
|
|
WrapperConfigurationContext - The handle used to call NdisOpenConfig.
|
|
|
|
Port - Port number to read from.
|
|
|
|
Data - Pointer to place to store the result.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
#if DBG
|
|
PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)KeyQueryTable[3].QueryRoutine;
|
|
|
|
NDIS_WARN(TRUE, Miniport, NDIS_GFLAG_WARN_LEVEL_1,
|
|
("NdisImmediateWritePortUchar: this API is going away. use non-Immediate version\n", Miniport));
|
|
#endif
|
|
|
|
ndisImmediateReadWritePort(WrapperConfigurationContext,
|
|
Port,
|
|
(PVOID)&Data,
|
|
sizeof (UCHAR),
|
|
FALSE);
|
|
|
|
}
|
|
|
|
//1 Deprecated function
|
|
VOID
|
|
NdisImmediateWritePortUshort(
|
|
IN NDIS_HANDLE WrapperConfigurationContext,
|
|
IN ULONG Port,
|
|
IN USHORT Data
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine writes to a port a USHORT. It does all the mapping,
|
|
etc, to do the write here.
|
|
|
|
Arguments:
|
|
|
|
WrapperConfigurationContext - The handle used to call NdisOpenConfig.
|
|
|
|
Port - Port number to read from.
|
|
|
|
Data - Pointer to place to store the result.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
#if DBG
|
|
PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)KeyQueryTable[3].QueryRoutine;
|
|
|
|
NDIS_WARN(TRUE, Miniport, NDIS_GFLAG_WARN_LEVEL_1,
|
|
("NdisImmediateWritePortUshort: this API is going away. use non-Immediate version\n", Miniport));
|
|
#endif
|
|
|
|
ndisImmediateReadWritePort(WrapperConfigurationContext,
|
|
Port,
|
|
(PVOID)&Data,
|
|
sizeof (USHORT),
|
|
FALSE);
|
|
|
|
}
|
|
|
|
//1 Deprecated function
|
|
VOID
|
|
NdisImmediateWritePortUlong(
|
|
IN NDIS_HANDLE WrapperConfigurationContext,
|
|
IN ULONG Port,
|
|
IN ULONG Data
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine writes to a port a ULONG. It does all the mapping,
|
|
etc, to do the write here.
|
|
|
|
Arguments:
|
|
|
|
WrapperConfigurationContext - The handle used to call NdisOpenConfig.
|
|
|
|
Port - Port number to read from.
|
|
|
|
Data - Pointer to place to store the result.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
#if DBG
|
|
PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)KeyQueryTable[3].QueryRoutine;
|
|
|
|
NDIS_WARN(TRUE, Miniport, NDIS_GFLAG_WARN_LEVEL_1,
|
|
("NdisImmediateWritePortUlong: this API is going away. use non-Immediate version\n", Miniport));
|
|
#endif
|
|
|
|
ndisImmediateReadWritePort(WrapperConfigurationContext,
|
|
Port,
|
|
(PVOID)&Data,
|
|
sizeof (ULONG),
|
|
FALSE);
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
ndisCheckMemoryUsage(
|
|
IN ULONG u32Address,
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
OUT PULONG pTranslatedAddress,
|
|
OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR * pResourceDescriptor
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
This routine checks if a range of memory is currently in use somewhere
|
|
in the system via IoReportUsage -- which fails if there is a conflict.
|
|
|
|
Arguments:
|
|
|
|
Address - Starting Address of the memory to access.
|
|
Length - Length of memory from the base address to access.
|
|
|
|
Return Value:
|
|
|
|
FALSE if there is a conflict, else TRUE
|
|
|
|
--*/
|
|
{
|
|
PHYSICAL_ADDRESS Address;
|
|
PHYSICAL_ADDRESS u64Address;
|
|
|
|
Address.QuadPart = u32Address;
|
|
|
|
if (NDIS_STATUS_SUCCESS == ndisTranslateResources(Miniport,
|
|
CmResourceTypeMemory,
|
|
Address,
|
|
&u64Address,
|
|
pResourceDescriptor))
|
|
{
|
|
*pTranslatedAddress = u64Address.LowPart;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
*pTranslatedAddress = 0;
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
ndisImmediateReadWriteSharedMemory(
|
|
IN NDIS_HANDLE WrapperConfigurationContext,
|
|
IN ULONG SharedMemoryAddress,
|
|
OUT PUCHAR Buffer,
|
|
IN ULONG Length,
|
|
IN BOOLEAN Read
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine read into a buffer from shared ram. It does all the mapping,
|
|
etc, to do the read here.
|
|
|
|
Arguments:
|
|
|
|
WrapperConfigurationContext - The handle used to call NdisOpenConfig.
|
|
|
|
SharedMemoryAddress - The physical address to read from.
|
|
|
|
Buffer - The buffer to read into.
|
|
|
|
Length - Length of the buffer in bytes.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR pResourceDescriptor = NULL;
|
|
NDIS_INTERFACE_TYPE BusType;
|
|
PNDIS_MINIPORT_BLOCK Miniport;
|
|
BOOLEAN Mapped;
|
|
PVOID MemoryMapping;
|
|
ULONG BusNumber;
|
|
|
|
Miniport = (PNDIS_MINIPORT_BLOCK)KeyQueryTable[3].QueryRoutine;
|
|
BusType = Miniport->BusType;
|
|
BusNumber = Miniport->BusNumber;
|
|
|
|
ASSERT(Miniport != NULL);
|
|
|
|
do
|
|
{
|
|
//
|
|
// Check that the memory is available. Map the space
|
|
//
|
|
|
|
if (ndisCheckMemoryUsage(SharedMemoryAddress,
|
|
Miniport,
|
|
(PULONG)&MemoryMapping,
|
|
&pResourceDescriptor
|
|
) == FALSE)
|
|
{
|
|
//
|
|
// the resource was not part of already allocated resources,
|
|
// nor could we allocate the resource
|
|
//
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// the port is not part of allocated resources, try to
|
|
// temporray allocate the resource
|
|
//
|
|
if (!NT_SUCCESS(ndisStartMapping((pResourceDescriptor == NULL) ? BusType : -1,
|
|
BusNumber,
|
|
SharedMemoryAddress,
|
|
Length,
|
|
0,
|
|
&MemoryMapping,
|
|
&Mapped)))
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (Read)
|
|
{
|
|
//
|
|
// Read from memory
|
|
//
|
|
|
|
#ifdef _M_IX86
|
|
|
|
memcpy(Buffer, MemoryMapping, Length);
|
|
|
|
#else
|
|
|
|
READ_REGISTER_BUFFER_UCHAR(MemoryMapping,Buffer,Length);
|
|
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Write to memory
|
|
//
|
|
|
|
#ifdef _M_IX86
|
|
|
|
memcpy(MemoryMapping, Buffer, Length);
|
|
|
|
#else
|
|
|
|
WRITE_REGISTER_BUFFER_UCHAR(MemoryMapping,Buffer,Length);
|
|
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// End mapping
|
|
//
|
|
|
|
ndisEndMapping(MemoryMapping,
|
|
Length,
|
|
Mapped);
|
|
|
|
} while (FALSE);
|
|
}
|
|
|
|
//1 Deprecated function
|
|
VOID
|
|
NdisImmediateReadSharedMemory(
|
|
IN NDIS_HANDLE WrapperConfigurationContext,
|
|
IN ULONG SharedMemoryAddress,
|
|
OUT PUCHAR Buffer,
|
|
IN ULONG Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine read into a buffer from shared ram. It does all the mapping,
|
|
etc, to do the read here.
|
|
|
|
Arguments:
|
|
|
|
WrapperConfigurationContext - The handle used to call NdisOpenConfig.
|
|
|
|
SharedMemoryAddress - The physical address to read from.
|
|
|
|
Buffer - The buffer to read into.
|
|
|
|
Length - Length of the buffer in bytes.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
#if DBG
|
|
PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)KeyQueryTable[3].QueryRoutine;
|
|
|
|
NDIS_WARN(TRUE, Miniport, NDIS_GFLAG_WARN_LEVEL_1,
|
|
("NdisImmediateReadSharedMemory: this API is going away. use non-Immediate version\n", Miniport));
|
|
#endif
|
|
|
|
ndisImmediateReadWriteSharedMemory(
|
|
WrapperConfigurationContext,
|
|
SharedMemoryAddress,
|
|
Buffer,
|
|
Length,
|
|
TRUE
|
|
);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
NdisImmediateWriteSharedMemory(
|
|
IN NDIS_HANDLE WrapperConfigurationContext,
|
|
IN ULONG SharedMemoryAddress,
|
|
IN PUCHAR Buffer,
|
|
IN ULONG Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine writes a buffer to shared ram. It does all the mapping,
|
|
etc, to do the write here.
|
|
|
|
Arguments:
|
|
|
|
WrapperConfigurationContext - The handle used to call NdisOpenConfig.
|
|
|
|
SharedMemoryAddress - The physical address to write to.
|
|
|
|
Buffer - The buffer to write.
|
|
|
|
Length - Length of the buffer in bytes.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
#if DBG
|
|
PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)KeyQueryTable[3].QueryRoutine;
|
|
|
|
NDIS_WARN(TRUE, Miniport, NDIS_GFLAG_WARN_LEVEL_1,
|
|
("NdisImmediateWriteSharedMemory: this API is going away. use non-Immediate version\n", Miniport));
|
|
#endif
|
|
|
|
ndisImmediateReadWriteSharedMemory(
|
|
WrapperConfigurationContext,
|
|
SharedMemoryAddress,
|
|
Buffer,
|
|
Length,
|
|
FALSE
|
|
);
|
|
}
|
|
|
|
//1 Should we check for path?
|
|
VOID
|
|
NdisOpenFile(
|
|
OUT PNDIS_STATUS Status,
|
|
OUT PNDIS_HANDLE FileHandle,
|
|
OUT PUINT FileLength,
|
|
IN PNDIS_STRING FileName,
|
|
IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine opens a file for future mapping and reads its contents
|
|
into allocated memory.
|
|
|
|
Arguments:
|
|
|
|
Status - The status of the operation
|
|
|
|
FileHandle - A handle to be associated with this open
|
|
|
|
FileLength - Returns the length of the file
|
|
|
|
FileName - The name of the file
|
|
|
|
HighestAcceptableAddress - The highest physical address at which
|
|
the memory for the file can be allocated.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
HANDLE NtFileHandle;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
ULONG LengthOfFile;
|
|
#define PathPrefix L"\\SystemRoot\\system32\\drivers\\"
|
|
NDIS_STRING FullFileName;
|
|
PNDIS_FILE_DESCRIPTOR FileDescriptor;
|
|
PVOID FileImage;
|
|
FILE_STANDARD_INFORMATION StandardInfo;
|
|
|
|
UNREFERENCED_PARAMETER(HighestAcceptableAddress);
|
|
|
|
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
|
|
("==>NdisOpenFile\n"));
|
|
|
|
do
|
|
{
|
|
//
|
|
// Insert the correct path prefix.
|
|
//
|
|
FullFileName.MaximumLength = sizeof(PathPrefix) + FileName->MaximumLength;
|
|
FullFileName.Buffer = ALLOC_FROM_POOL(FullFileName.MaximumLength, NDIS_TAG_FILE_NAME);
|
|
|
|
if (FullFileName.Buffer == NULL)
|
|
{
|
|
*Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
FullFileName.Length = sizeof (PathPrefix) - sizeof(WCHAR);
|
|
CopyMemory(FullFileName.Buffer, PathPrefix, sizeof(PathPrefix));
|
|
RtlAppendUnicodeStringToString (&FullFileName, FileName);
|
|
|
|
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
|
|
(" Attempting to open %Z\n", &FullFileName));
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&FullFileName,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
NULL,
|
|
NULL);
|
|
|
|
NtStatus = ZwCreateFile(&NtFileHandle,
|
|
SYNCHRONIZE | FILE_READ_DATA,
|
|
&ObjectAttributes,
|
|
&IoStatus,
|
|
NULL,
|
|
0,
|
|
FILE_SHARE_READ,
|
|
FILE_OPEN,
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
0);
|
|
|
|
FREE_POOL(FullFileName.Buffer);
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
|
|
("Error opening file %x\n", NtStatus));
|
|
*Status = NDIS_STATUS_FILE_NOT_FOUND;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Query the object to determine its length.
|
|
//
|
|
|
|
NtStatus = ZwQueryInformationFile(NtFileHandle,
|
|
&IoStatus,
|
|
&StandardInfo,
|
|
sizeof(FILE_STANDARD_INFORMATION),
|
|
FileStandardInformation);
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
|
|
("Error querying info on file %x\n", NtStatus));
|
|
ZwClose(NtFileHandle);
|
|
*Status = NDIS_STATUS_ERROR_READING_FILE;
|
|
break;
|
|
}
|
|
|
|
LengthOfFile = StandardInfo.EndOfFile.LowPart;
|
|
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("File length is %d\n", LengthOfFile));
|
|
|
|
//
|
|
// Might be corrupted.
|
|
//
|
|
if (LengthOfFile < 1)
|
|
{
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
|
|
("Bad file length %d\n", LengthOfFile));
|
|
ZwClose(NtFileHandle);
|
|
*Status = NDIS_STATUS_ERROR_READING_FILE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Allocate buffer for this file
|
|
//
|
|
|
|
FileImage = ALLOC_FROM_POOL(LengthOfFile, NDIS_TAG_FILE_IMAGE);
|
|
|
|
if (FileImage == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
|
|
("Could not allocate buffer\n"));
|
|
ZwClose(NtFileHandle);
|
|
*Status = NDIS_STATUS_ERROR_READING_FILE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Read the file into our buffer.
|
|
//
|
|
|
|
NtStatus = ZwReadFile(NtFileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
FileImage,
|
|
LengthOfFile,
|
|
NULL,
|
|
NULL);
|
|
|
|
ZwClose(NtFileHandle);
|
|
|
|
if ((!NT_SUCCESS(NtStatus)) || (IoStatus.Information != LengthOfFile))
|
|
{
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
|
|
("error reading file %x\n", NtStatus));
|
|
*Status = NDIS_STATUS_ERROR_READING_FILE;
|
|
FREE_POOL(FileImage);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Allocate a structure to describe the file.
|
|
//
|
|
|
|
FileDescriptor = ALLOC_FROM_POOL(sizeof(NDIS_FILE_DESCRIPTOR), NDIS_TAG_FILE_DESCRIPTOR);
|
|
|
|
if (FileDescriptor == NULL)
|
|
{
|
|
*Status = NDIS_STATUS_RESOURCES;
|
|
FREE_POOL(FileImage);
|
|
break;
|
|
}
|
|
|
|
FileDescriptor->Data = FileImage;
|
|
INITIALIZE_SPIN_LOCK (&FileDescriptor->Lock);
|
|
FileDescriptor->Mapped = FALSE;
|
|
|
|
*FileHandle = (NDIS_HANDLE)FileDescriptor;
|
|
*FileLength = LengthOfFile;
|
|
*Status = STATUS_SUCCESS;
|
|
} while (FALSE);
|
|
|
|
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
|
|
("<==NdisOpenFile, Status %.8x\n", *Status));
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisCloseFile(
|
|
IN NDIS_HANDLE FileHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine closes a file previously opened with NdisOpenFile.
|
|
The file is unmapped if needed and the memory is freed.
|
|
|
|
Arguments:
|
|
|
|
FileHandle - The handle returned by NdisOpenFile
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle;
|
|
|
|
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
|
|
("==>NdisCloseFile\n"));
|
|
|
|
FREE_POOL(FileDescriptor->Data);
|
|
FREE_POOL(FileDescriptor);
|
|
|
|
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
|
|
("<==NdisCloseFile\n"));
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisMapFile(
|
|
OUT PNDIS_STATUS Status,
|
|
OUT PVOID * MappedBuffer,
|
|
IN NDIS_HANDLE FileHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine maps an open file, so that the contents can be accessed.
|
|
Files can only have one active mapping at any time.
|
|
|
|
Arguments:
|
|
|
|
Status - The status of the operation
|
|
|
|
MappedBuffer - Returns the virtual address of the mapping.
|
|
|
|
FileHandle - The handle returned by NdisOpenFile.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle;
|
|
|
|
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
|
|
("==>NdisMapFile\n"));
|
|
|
|
if (FileDescriptor->Mapped == TRUE)
|
|
{
|
|
*Status = NDIS_STATUS_ALREADY_MAPPED;
|
|
}
|
|
else
|
|
{
|
|
FileDescriptor->Mapped = TRUE;
|
|
|
|
*MappedBuffer = FileDescriptor->Data;
|
|
*Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
|
|
("<==NdisMapFile, Status %.8x \n", *Status));
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisUnmapFile(
|
|
IN NDIS_HANDLE FileHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine unmaps a file previously mapped with NdisOpenFile.
|
|
The file is unmapped if needed and the memory is freed.
|
|
|
|
Arguments:
|
|
FileHandle - The handle returned by NdisOpenFile
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle;
|
|
|
|
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
|
|
("==>NdisUnmapFile\n"));
|
|
|
|
FileDescriptor->Mapped = FALSE;
|
|
|
|
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
|
|
("<==NdisUnmapFile\n"));
|
|
}
|
|
|
|
|
|
CCHAR
|
|
NdisSystemProcessorCount(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function returns the number of processors in the machine
|
|
|
|
Arguments:
|
|
None.
|
|
|
|
Return Value:
|
|
NdisSystemProcessorCount returns the number of processors in the machine
|
|
|
|
Callers of NdisSystemProcessorCount can be running at IRQL == PASSIVE
|
|
|
|
--*/
|
|
|
|
{
|
|
return KeNumberProcessors;
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisGetSystemUpTime(
|
|
OUT PULONG pSystemUpTime
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
NdisGetSystemUpTime returns the number of milliseconds that have elapsed since the
|
|
system was booted.
|
|
|
|
Arguments:
|
|
pSystemUpTime: Pointer to a caller-supplied variable in which this function returns the
|
|
system uptime.
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
Callers of NdisGetSystemUpTime can be running at any IRQL.
|
|
|
|
--*/
|
|
{
|
|
LARGE_INTEGER TickCount;
|
|
|
|
//
|
|
// Get tick count and convert to hundreds of nanoseconds.
|
|
//
|
|
KeQueryTickCount(&TickCount);
|
|
|
|
TickCount = RtlExtendedIntegerMultiply(TickCount, (LONG)ndisTimeIncrement);
|
|
|
|
TickCount.QuadPart /= 10000;
|
|
|
|
ASSERT(TickCount.HighPart == 0);
|
|
|
|
*pSystemUpTime = TickCount.LowPart;
|
|
}
|
|
|
|
VOID
|
|
NdisGetCurrentProcessorCpuUsage(
|
|
IN PULONG pCpuUsage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
NdisGetCurrentProcessorCpuUsage returns how busy the current processor is as a percentage.
|
|
|
|
Arguments:
|
|
pCpuUsage: Pointer to a caller-supplied variable in which this function returns the percentage
|
|
of CPU, on which the caller is running, that is currently in use.
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
Callers of NdisGetCurrentProcessorCpuUsage can be running at any IRQL.
|
|
|
|
--*/
|
|
|
|
{
|
|
ExGetCurrentProcessorCpuUsage(pCpuUsage);
|
|
}
|
|
|
|
VOID
|
|
NdisGetCurrentProcessorCounts(
|
|
OUT PULONG pIdleCount,
|
|
OUT PULONG pKernelAndUser,
|
|
OUT PULONG pIndex
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
NdisGetCurrentProcessorCounts returns counts for the current processor that a
|
|
driver can use to determine CPU utilization for a particular time interval.
|
|
|
|
|
|
Arguments:
|
|
pIdleCount: Pointer to a caller-supplied variable in which this function
|
|
returns the cumulative idle time for the processor since the system was booted.
|
|
|
|
pKernelAndUser: Pointer to a caller-supplied variable in which this function
|
|
returns the cumulative processing time (kernel-mode time plus user-mode time)
|
|
for the processor since the system was booted.
|
|
|
|
pIndex: Pointer to a caller-supplied variable in which this function returns
|
|
a zero-based index that identifies the processor within the machine
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
Callers of NdisGetCurrentProcessorCounts must be running at IRQL <= DISPATCH_LEVEL.
|
|
|
|
--*/
|
|
{
|
|
ExGetCurrentProcessorCounts(pIdleCount, pKernelAndUser, pIndex);
|
|
}
|
|
|
|
VOID
|
|
NdisGetCurrentSystemTime(
|
|
IN PLARGE_INTEGER pCurrentTime
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
NdisGetCurrentSystemTime returns the current system time,
|
|
suitable for setting timestamps.
|
|
|
|
Arguments:
|
|
pSystemTime: Pointer to a caller-supplied variable in which this function returns
|
|
a count of 100-nanosecond intervals since January 1, 1601.
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
Callers of NdisGetCurrentSystemTime can be running at any IRQL.
|
|
|
|
--*/
|
|
{
|
|
KeQuerySystemTime(pCurrentTime);
|
|
}
|
|
|
|
//1 deprecated function
|
|
NDIS_STATUS
|
|
NdisQueryMapRegisterCount(
|
|
IN NDIS_INTERFACE_TYPE BusType,
|
|
OUT PUINT MapRegisterCount
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
UNREFERENCED_PARAMETER(BusType);
|
|
|
|
*MapRegisterCount = 0;
|
|
return NDIS_STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
|
|
//
|
|
// NDIS Event support
|
|
//
|
|
|
|
VOID
|
|
NdisInitializeEvent(
|
|
IN PNDIS_EVENT Event
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
NdisInitializeEvent sets up an event object during driver initialization to be
|
|
used subsequently as a synchronization mechanism.
|
|
|
|
Arguments:
|
|
Event: Pointer to caller-supplied storage for the event object, which is opaque to drivers.
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
Callers of NdisInitializeEvent run at IRQL = PASSIVE_LEVEL.
|
|
|
|
--*/
|
|
{
|
|
INITIALIZE_EVENT(&Event->Event);
|
|
}
|
|
|
|
VOID
|
|
NdisSetEvent(
|
|
IN PNDIS_EVENT Event
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
NdisSetEvent sets a given event to the signaled state if it was not already Signaled.
|
|
|
|
Arguments:
|
|
Event: Pointer to an initialized event object for which the caller provides the storage.
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
Callers of NdisSetEvent run at IRQL <= DISPATCH_LEVEL.
|
|
|
|
--*/
|
|
{
|
|
SET_EVENT(&Event->Event);
|
|
}
|
|
|
|
VOID
|
|
NdisResetEvent(
|
|
IN PNDIS_EVENT Event
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
NdisResetEvent clears the Signaled state of a given event.
|
|
|
|
Arguments:
|
|
Event: Pointer to an initialized event object for which the caller provided the storage.
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
Callers of NdisResetEvent run at IRQL <= DISPATCH_LEVEL.
|
|
|
|
--*/
|
|
{
|
|
RESET_EVENT(&Event->Event);
|
|
}
|
|
|
|
BOOLEAN
|
|
NdisWaitEvent(
|
|
IN PNDIS_EVENT Event,
|
|
IN UINT MsToWait
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
NdisWaitEvent puts the caller into a wait state until the given event is set
|
|
to the Signaled state or the wait times out.
|
|
|
|
Arguments:
|
|
Event: Pointer to an initialized event object for which the caller provides the storage.
|
|
|
|
MsToWait: Specifies the number of milliseconds the caller will wait if the event is not
|
|
set to the Signaled state within that interval. A value of zero specifies that the caller
|
|
will wait for the event indefinitely.
|
|
|
|
Return Value:
|
|
NdisWaitEvent returns TRUE if the event is in the Signaled state when the wait is satisfied.
|
|
|
|
Callers of NdisWaitEvent must be running at IRQL = PASSIVE_LEVEL.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
TIME Time, *pTime;
|
|
|
|
ASSERT(CURRENT_IRQL < DISPATCH_LEVEL);
|
|
|
|
pTime = NULL;
|
|
if (MsToWait != 0)
|
|
{
|
|
Time.QuadPart = Int32x32To64(MsToWait, -10000);
|
|
pTime = &Time;
|
|
}
|
|
|
|
Status = WAIT_FOR_OBJECT(&Event->Event, pTime);
|
|
|
|
return(Status == NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
NdisScheduleWorkItem(
|
|
IN PNDIS_WORK_ITEM WorkItem
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
NdisScheduleWorkItem inserts a given work item into a queue from which
|
|
a system worker thread removes the item and gives control to the callback
|
|
function that the driver previously supplied to NdisInitializeWorkItem.
|
|
|
|
Arguments:
|
|
WorkItem: Pointer to the work item that was set up by a preceding call
|
|
to NdisInitializeWorkItem.
|
|
|
|
Return Value:
|
|
This function always return NDIS_STATUS_SUCCESS.
|
|
|
|
Callers of NdisScheduleWorkItem must be running at IRQL <= DISPATCH_LEVEL.
|
|
--*/
|
|
{
|
|
INITIALIZE_WORK_ITEM((WORK_QUEUE_ITEM *)WorkItem->WrapperReserved,
|
|
ndisWorkItemHandler,
|
|
WorkItem);
|
|
XQUEUE_WORK_ITEM((WORK_QUEUE_ITEM *)WorkItem->WrapperReserved, CriticalWorkQueue);
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
ndisWorkItemHandler(
|
|
IN PNDIS_WORK_ITEM WorkItem
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
ndisWorkItemHandler is the common callback routine for all the workitems
|
|
scheduled by a call to NdisScheduleWorkItem INITIALIZE_WORK_ITEM.
|
|
This routine will call the real callback function from the workitem.
|
|
|
|
Arguments:
|
|
WorkItem: a pointer to workitem.
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
ndisWorkItemHandler is called at PASSIVE level.
|
|
--*/
|
|
{
|
|
ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
(*WorkItem->Routine)(WorkItem, WorkItem->Context);
|
|
ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
}
|
|
|
|
//1 deprectae this function
|
|
VOID
|
|
NdisInitializeString(
|
|
OUT PNDIS_STRING Destination,
|
|
IN PUCHAR Source
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
NdisInitializeString allocates storage for and initializes a counted string
|
|
in the system-default character set.
|
|
|
|
Arguments:
|
|
DestinationString: Specifies NULL when NdisInitializeString is called;
|
|
on return from this function, points to an NDIS_STRING type that describes
|
|
an initialized counted string. For Windows 2000 and later, NDIS defines the
|
|
NDIS_STRING type as a UNICODE_STRING type.
|
|
|
|
SourceString: Pointer to a zero-terminated string with which to initialize
|
|
the counted string.
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
Callers of NdisInitializeString run at IRQL = PASSIVE_LEVEL.
|
|
|
|
--*/
|
|
{
|
|
WCHAR *strptr;
|
|
|
|
//1 don't use strlen, set an upper limit on length
|
|
Destination->Length = (USHORT)(strlen((CONST char *)Source) * sizeof(WCHAR));
|
|
Destination->MaximumLength = Destination->Length + sizeof(WCHAR);
|
|
Destination->Buffer = ALLOC_FROM_POOL(Destination->MaximumLength, NDIS_TAG_STRING);
|
|
|
|
if (Destination->Buffer != NULL)
|
|
{
|
|
strptr = Destination->Buffer;
|
|
//1 this loop should put a limit on how far it goes.
|
|
while (*Source != '\0')
|
|
{
|
|
*strptr = (WCHAR)*Source;
|
|
Source++;
|
|
strptr++;
|
|
}
|
|
*strptr = UNICODE_NULL;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NdisSetPacketStatus(
|
|
IN PNDIS_PACKET Packet,
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE Handle,
|
|
IN ULONG Code
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
NdisSetPacketStatus sets the Status value in the out-of-band data block associated with
|
|
a given packet descriptor just before a driver calls NdisMIndicateReceivePacket or
|
|
before a driver's MiniportSendPackets function returns control.
|
|
|
|
|
|
Arguments:
|
|
Packet: Pointer to a packet descriptor either allocated by the caller for a receive
|
|
indication or by a protocol for a send.
|
|
|
|
Status: Specifies the status to be set.
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
Callers of NDIS_SET_PACKET_STATUS run at IRQL <= DISPATCH_LEVEL.
|
|
|
|
--*/
|
|
{
|
|
#ifdef TRACK_RECEIVED_PACKETS
|
|
NDIS_STATUS OldStatus = NDIS_GET_PACKET_STATUS(Packet);
|
|
|
|
ndisRcvLogfile[ndisRcvLogfileIndex++] = (ULONG_PTR)Packet;
|
|
ndisRcvLogfile[ndisRcvLogfileIndex++] = (ULONG_PTR)Handle;
|
|
ndisRcvLogfile[ndisRcvLogfileIndex++] = (ULONG_PTR)PsGetCurrentThread();
|
|
ndisRcvLogfile[ndisRcvLogfileIndex++] = (ULONG_PTR)((Status<<24) |
|
|
((OldStatus&0xff)<<16) |
|
|
(Code&0xffff)
|
|
);
|
|
#else
|
|
UNREFERENCED_PARAMETER(Handle);
|
|
UNREFERENCED_PARAMETER(Code);
|
|
#endif
|
|
|
|
NDIS_SET_PACKET_STATUS(Packet, Status);
|
|
|
|
}
|
|
|
|
VOID
|
|
NdisCopyFromPacketToPacketSafe(
|
|
IN PNDIS_PACKET Destination,
|
|
IN UINT DestinationOffset,
|
|
IN UINT BytesToCopy,
|
|
IN PNDIS_PACKET Source,
|
|
IN UINT SourceOffset,
|
|
OUT PUINT BytesCopied,
|
|
IN MM_PAGE_PRIORITY Priority
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
safe version of Copy from NdisCopyFromPacketToPacket
|
|
|
|
Arguments:
|
|
|
|
Destination - The packet should be copied in to.
|
|
|
|
DestinationOffset - The offset from the beginning of the packet
|
|
into which the data should start being placed.
|
|
|
|
BytesToCopy - The number of bytes to copy from the source packet.
|
|
|
|
Source - The ndis packet from which to copy data.
|
|
|
|
SourceOffset - The offset from the start of the packet from which
|
|
to start copying data.
|
|
|
|
BytesCopied - The number of bytes actually copied from the source
|
|
packet. This can be less than BytesToCopy if the source or destination
|
|
packet is too short.
|
|
|
|
Priority: Indicates the priority of the request.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Callers of NdisCopyFromPacketToPacketSafe run at IRQL <= DISPATCH_LEVEL.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Points to the buffer into which we are putting data.
|
|
//
|
|
PNDIS_BUFFER DestinationCurrentBuffer;
|
|
|
|
//
|
|
// Points to the buffer from which we are extracting data.
|
|
//
|
|
PNDIS_BUFFER SourceCurrentBuffer;
|
|
|
|
//
|
|
// Holds the virtual address of the current destination buffer.
|
|
//
|
|
PVOID DestinationVirtualAddress;
|
|
|
|
//
|
|
// Holds the virtual address of the current source buffer.
|
|
//
|
|
PVOID SourceVirtualAddress;
|
|
|
|
//
|
|
// Holds the length of the current destination buffer.
|
|
//
|
|
UINT DestinationCurrentLength;
|
|
|
|
//
|
|
// Holds the length of the current source buffer.
|
|
//
|
|
UINT SourceCurrentLength;
|
|
|
|
//
|
|
// Keep a local variable of BytesCopied so we aren't referencing
|
|
// through a pointer.
|
|
//
|
|
UINT LocalBytesCopied = 0;
|
|
|
|
//
|
|
// Take care of boundary condition of zero length copy.
|
|
//
|
|
|
|
*BytesCopied = 0;
|
|
if (!BytesToCopy)
|
|
return;
|
|
|
|
//
|
|
// Get the first buffer of the destination.
|
|
//
|
|
|
|
DestinationCurrentBuffer = Destination->Private.Head;
|
|
if (DestinationCurrentBuffer == NULL)
|
|
return;
|
|
|
|
DestinationVirtualAddress = MmGetSystemAddressForMdlSafe(DestinationCurrentBuffer, Priority);
|
|
if (DestinationVirtualAddress == NULL)
|
|
return;
|
|
|
|
DestinationCurrentLength = MmGetMdlByteCount(DestinationCurrentBuffer);
|
|
|
|
//
|
|
// Get the first buffer of the source.
|
|
//
|
|
|
|
SourceCurrentBuffer = Source->Private.Head;
|
|
if (SourceCurrentBuffer == NULL)
|
|
return;
|
|
|
|
SourceVirtualAddress = MmGetSystemAddressForMdlSafe(SourceCurrentBuffer, Priority);
|
|
if (SourceVirtualAddress == NULL)
|
|
return;
|
|
|
|
SourceCurrentLength = MmGetMdlByteCount(SourceCurrentBuffer);
|
|
|
|
while (LocalBytesCopied < BytesToCopy)
|
|
{
|
|
//
|
|
// Check to see whether we've exhausted the current destination
|
|
// buffer. If so, move onto the next one.
|
|
//
|
|
|
|
if (!DestinationCurrentLength)
|
|
{
|
|
DestinationCurrentBuffer = DestinationCurrentBuffer->Next;
|
|
|
|
if (!DestinationCurrentBuffer)
|
|
{
|
|
//
|
|
// We've reached the end of the packet. We return
|
|
// with what we've done so far. (Which must be shorter
|
|
// than requested.)
|
|
//
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
DestinationVirtualAddress = MmGetSystemAddressForMdlSafe(DestinationCurrentBuffer, Priority);
|
|
if (DestinationVirtualAddress == NULL)
|
|
break;
|
|
|
|
DestinationCurrentLength = MmGetMdlByteCount(DestinationCurrentBuffer);
|
|
|
|
continue;
|
|
}
|
|
|
|
|
|
//
|
|
// Check to see whether we've exhausted the current source
|
|
// buffer. If so, move onto the next one.
|
|
//
|
|
|
|
if (!SourceCurrentLength)
|
|
{
|
|
SourceCurrentBuffer = SourceCurrentBuffer->Next;
|
|
|
|
if (!SourceCurrentBuffer)
|
|
{
|
|
//
|
|
// We've reached the end of the packet. We return
|
|
// with what we've done so far. (Which must be shorter
|
|
// than requested.)
|
|
//
|
|
|
|
break;
|
|
}
|
|
|
|
SourceVirtualAddress = MmGetSystemAddressForMdlSafe(SourceCurrentBuffer, Priority);
|
|
if (SourceVirtualAddress == NULL)
|
|
break;
|
|
|
|
SourceCurrentLength = MmGetMdlByteCount(SourceCurrentBuffer);
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Try to get us up to the point to start the copy.
|
|
//
|
|
|
|
if (DestinationOffset)
|
|
{
|
|
if (DestinationOffset > DestinationCurrentLength)
|
|
{
|
|
//
|
|
// What we want isn't in this buffer.
|
|
//
|
|
|
|
DestinationOffset -= DestinationCurrentLength;
|
|
DestinationCurrentLength = 0;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
DestinationVirtualAddress = (PCHAR)DestinationVirtualAddress
|
|
+ DestinationOffset;
|
|
DestinationCurrentLength -= DestinationOffset;
|
|
DestinationOffset = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Try to get us up to the point to start the copy.
|
|
//
|
|
|
|
if (SourceOffset)
|
|
{
|
|
if (SourceOffset > SourceCurrentLength)
|
|
{
|
|
//
|
|
// What we want isn't in this buffer.
|
|
//
|
|
|
|
SourceOffset -= SourceCurrentLength;
|
|
SourceCurrentLength = 0;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
SourceVirtualAddress = (PCHAR)SourceVirtualAddress
|
|
+ SourceOffset;
|
|
SourceCurrentLength -= SourceOffset;
|
|
SourceOffset = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Copy the data.
|
|
//
|
|
|
|
{
|
|
//
|
|
// Holds the amount of data to move.
|
|
//
|
|
UINT AmountToMove;
|
|
|
|
//
|
|
// Holds the amount desired remaining.
|
|
//
|
|
UINT Remaining = BytesToCopy - LocalBytesCopied;
|
|
|
|
AmountToMove = ((SourceCurrentLength <= DestinationCurrentLength) ?
|
|
(SourceCurrentLength) : (DestinationCurrentLength));
|
|
|
|
AmountToMove = ((Remaining < AmountToMove)?
|
|
(Remaining):(AmountToMove));
|
|
|
|
CopyMemory(DestinationVirtualAddress, SourceVirtualAddress, AmountToMove);
|
|
|
|
DestinationVirtualAddress =
|
|
(PCHAR)DestinationVirtualAddress + AmountToMove;
|
|
SourceVirtualAddress =
|
|
(PCHAR)SourceVirtualAddress + AmountToMove;
|
|
|
|
LocalBytesCopied += AmountToMove;
|
|
SourceCurrentLength -= AmountToMove;
|
|
DestinationCurrentLength -= AmountToMove;
|
|
}
|
|
}
|
|
|
|
*BytesCopied = LocalBytesCopied;
|
|
}
|
|
|