Windows-Server-2003/net/ndis/sys/common.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;
}