mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3452 lines
69 KiB
3452 lines
69 KiB
/*++
|
|
|
|
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
|
|
ndisInitializePackage(
|
|
IN PPKG_REF pPkg,
|
|
IN PVOID RoutineName
|
|
)
|
|
{
|
|
//
|
|
// Allocate the spin lock
|
|
//
|
|
INITIALIZE_SPIN_LOCK(&pPkg->ReferenceLock);
|
|
|
|
//
|
|
// Initialize the "in page" event.
|
|
//
|
|
INITIALIZE_EVENT(&pPkg->PagedInEvent);
|
|
|
|
// Lock and unlock the section to obtain the handle. Subsequent locks will be faster
|
|
pPkg->ImageHandle = MmLockPagableCodeSection(RoutineName);
|
|
MmUnlockPagableImageSection(pPkg->ImageHandle);
|
|
}
|
|
|
|
|
|
VOID
|
|
ndisReferencePackage(
|
|
IN PPKG_REF pPkg
|
|
)
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
//
|
|
// Grab the spin lock
|
|
//
|
|
ACQUIRE_SPIN_LOCK(&pPkg->ReferenceLock, &OldIrql);
|
|
|
|
//
|
|
// Increment the reference count
|
|
//
|
|
pPkg->ReferenceCount++;
|
|
|
|
if (pPkg->ReferenceCount == 1)
|
|
{
|
|
//
|
|
// We are the first reference. Page everything in.
|
|
//
|
|
|
|
//
|
|
// Clear the event
|
|
//
|
|
RESET_EVENT(&pPkg->PagedInEvent);
|
|
|
|
//
|
|
// Set the spin lock free
|
|
//
|
|
RELEASE_SPIN_LOCK(&pPkg->ReferenceLock, OldIrql);
|
|
|
|
//
|
|
// Page in all the functions
|
|
//
|
|
MmLockPagableSectionByHandle(pPkg->ImageHandle);
|
|
|
|
//
|
|
// Signal to everyone to go
|
|
//
|
|
SET_EVENT(&pPkg->PagedInEvent);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Set the spin lock free
|
|
//
|
|
RELEASE_SPIN_LOCK(&pPkg->ReferenceLock, OldIrql);
|
|
|
|
//
|
|
// Wait for everything to be paged in
|
|
//
|
|
WAIT_FOR_OBJECT(&pPkg->PagedInEvent, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
ndisDereferencePackage(
|
|
IN PPKG_REF pPkg
|
|
)
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
//
|
|
// Get the spin lock
|
|
//
|
|
ACQUIRE_SPIN_LOCK(&pPkg->ReferenceLock, &OldIrql);
|
|
|
|
pPkg->ReferenceCount--;
|
|
|
|
if (pPkg->ReferenceCount == 0)
|
|
{
|
|
//
|
|
// Let next one in
|
|
//
|
|
RELEASE_SPIN_LOCK(&pPkg->ReferenceLock, OldIrql);
|
|
|
|
//
|
|
// Page out all the functions
|
|
//
|
|
MmUnlockPagableImageSection(pPkg->ImageHandle);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Let next one in
|
|
//
|
|
RELEASE_SPIN_LOCK(&pPkg->ReferenceLock, OldIrql);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Packet and Buffer requests
|
|
//
|
|
|
|
VOID
|
|
NdisAllocatePacketPool(
|
|
OUT PNDIS_STATUS Status,
|
|
OUT PNDIS_HANDLE PoolHandle,
|
|
IN UINT NumberOfDescriptors,
|
|
IN UINT ProtocolReservedLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes a packet pool. All packets are the same
|
|
size for a given pool (as determined by ProtocolReservedLength),
|
|
so a simple linked list of free packets is set up initially.
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNDIS_PACKET_POOL TmpPool;
|
|
PUCHAR FreeEntry;
|
|
UINT PacketLength;
|
|
UINT i;
|
|
|
|
//
|
|
// Set up the size of packets in this pool (rounded
|
|
// up to sizeof(ULONG) for alignment).
|
|
//
|
|
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("==>NdisAllocatePacketPool\n"));
|
|
|
|
PacketLength = FIELD_OFFSET(NDIS_PACKET, ProtocolReserved) +
|
|
sizeof(NDIS_PACKET_OOB_DATA) +
|
|
sizeof(NDIS_PACKET_PRIVATE_EXTENSION) +
|
|
((ProtocolReservedLength + sizeof(ULONGLONG) - 1) & ~(sizeof(ULONGLONG) -1));
|
|
|
|
//
|
|
// Allocate space needed
|
|
//
|
|
TmpPool = (PNDIS_PACKET_POOL)ALLOC_FROM_POOL(sizeof(NDIS_PACKET_POOL) +
|
|
(PacketLength * NumberOfDescriptors),
|
|
NDIS_TAG_PKT_POOL);
|
|
if (TmpPool == NULL)
|
|
{
|
|
*Status = NDIS_STATUS_RESOURCES;
|
|
return;
|
|
}
|
|
|
|
ZeroMemory(TmpPool, PacketLength * NumberOfDescriptors);
|
|
TmpPool->PacketLength = PacketLength;
|
|
|
|
//
|
|
// First entry in free list is at beginning of pool space.
|
|
//
|
|
TmpPool->FreeList = (PNDIS_PACKET)TmpPool->Buffer;
|
|
FreeEntry = TmpPool->Buffer;
|
|
|
|
for (i = 1; i < NumberOfDescriptors; i++)
|
|
{
|
|
//
|
|
// Each entry is linked to the "packet" PacketLength bytes
|
|
// ahead of it, using the Private.Head field.
|
|
//
|
|
((PNDIS_PACKET)FreeEntry)->Private.Head = (PNDIS_BUFFER)(FreeEntry + PacketLength);
|
|
FreeEntry += PacketLength;
|
|
}
|
|
|
|
//
|
|
// Final free list entry.
|
|
//
|
|
((PNDIS_PACKET)FreeEntry)->Private.Head = (PNDIS_BUFFER)NULL;
|
|
|
|
NdisAllocateSpinLock(&TmpPool->SpinLock);
|
|
|
|
*Status = NDIS_STATUS_SUCCESS;
|
|
*PoolHandle = (NDIS_HANDLE)TmpPool;
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("<==NdisAllocatePacketPool\n"));
|
|
}
|
|
|
|
|
|
#undef NdisFreePacketPool
|
|
|
|
VOID
|
|
NdisFreePacketPool(
|
|
IN NDIS_HANDLE PoolHandle
|
|
)
|
|
{
|
|
NdisFreeSpinLock(&((PNDIS_PACKET_POOL)PoolHandle)->SpinLock);
|
|
FREE_POOL(PoolHandle);
|
|
}
|
|
|
|
|
|
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.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// A nop for NT
|
|
//
|
|
UNREFERENCED_PARAMETER(NumberOfDescriptors);
|
|
|
|
*PoolHandle = NULL;
|
|
*Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
#undef NdisAdjustBufferLength
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
#define ndisAllocatePacketFromPool(_Pool, _ppPacket) \
|
|
{ \
|
|
\
|
|
/* \
|
|
* See if any packets are on pool free list. \
|
|
*/ \
|
|
\
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO, \
|
|
("==>NdisAllocatePacket\n")); \
|
|
\
|
|
IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR) \
|
|
{ \
|
|
if (DbgIsNull(PoolHandle)) \
|
|
{ \
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR, \
|
|
("AllocatePacket: NULL Pool address\n")); \
|
|
DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR); \
|
|
} \
|
|
if (!DbgIsNonPaged(PoolHandle)) \
|
|
{ \
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR, \
|
|
("AllocatePacket: Pool not in NonPaged Memory\n")); \
|
|
DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR); \
|
|
} \
|
|
} \
|
|
\
|
|
*(_ppPacket) = Pool->FreeList; \
|
|
if (Pool->FreeList != (PNDIS_PACKET)NULL) \
|
|
{ \
|
|
/* \
|
|
* Take free packet off head of list and return it. \
|
|
*/ \
|
|
\
|
|
Pool->FreeList = (PNDIS_PACKET)(*(_ppPacket))->Private.Head; \
|
|
} \
|
|
}
|
|
|
|
#define ndisInitializePacket(_Pool, _Packet) \
|
|
{ \
|
|
PNDIS_PACKET_PRIVATE_EXTENSION PacketExt; \
|
|
\
|
|
ZeroMemory((_Packet), (_Pool)->PacketLength); \
|
|
(_Packet)->Private.Pool = (PNDIS_PACKET_POOL)(_Pool); \
|
|
(_Packet)->Private.ValidCounts = TRUE; \
|
|
(_Packet)->Private.NdisPacketFlags = fPACKET_ALLOCATED_BY_NDIS; \
|
|
\
|
|
/* \
|
|
* Set the offset to the out of band data. \
|
|
*/ \
|
|
(_Packet)->Private.NdisPacketOobOffset = (USHORT)( \
|
|
(_Pool)->PacketLength - \
|
|
sizeof(NDIS_PACKET_OOB_DATA) - \
|
|
sizeof(NDIS_PACKET_PRIVATE_EXTENSION));\
|
|
\
|
|
/* \
|
|
* Set the pointer to the packet linkage information for ndis. \
|
|
*/ \
|
|
PacketExt = (PNDIS_PACKET_PRIVATE_EXTENSION)((PUCHAR)(_Packet) + \
|
|
(_Packet)->Private.NdisPacketOobOffset + \
|
|
sizeof(NDIS_PACKET_OOB_DATA)); \
|
|
PacketExt->Packet = (_Packet); \
|
|
}
|
|
|
|
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:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNDIS_PACKET_POOL Pool = (PNDIS_PACKET_POOL)PoolHandle;
|
|
KIRQL OldIrql;
|
|
|
|
NDIS_ACQUIRE_SPIN_LOCK(&Pool->SpinLock, &OldIrql);
|
|
|
|
ndisAllocatePacketFromPool(PoolHandle, Packet);
|
|
|
|
NDIS_RELEASE_SPIN_LOCK(&Pool->SpinLock, OldIrql);
|
|
|
|
if (*Packet != (PNDIS_PACKET)NULL)
|
|
{
|
|
//
|
|
// Clear packet elements.
|
|
//
|
|
ndisInitializePacket(Pool, *Packet);
|
|
|
|
*Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// No, cannot satisfy request.
|
|
//
|
|
|
|
*Status = NDIS_STATUS_RESOURCES;
|
|
}
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("<==NdisAllocatePacket\n"));
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisDprAllocatePacket(
|
|
OUT PNDIS_STATUS Status,
|
|
OUT PNDIS_PACKET * Packet,
|
|
IN NDIS_HANDLE PoolHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates a packet out of a packet pool. Similar to NdisAllocatePacket
|
|
but can only be called at raised irql.
|
|
|
|
Arguments:
|
|
|
|
Status - Returns the final status.
|
|
Packet - Return a pointer to the packet.
|
|
PoolHandle - The packet pool to allocate from.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNDIS_PACKET_POOL Pool = (PNDIS_PACKET_POOL)PoolHandle;
|
|
|
|
NDIS_ACQUIRE_SPIN_LOCK_DPC(&Pool->SpinLock);
|
|
|
|
ndisAllocatePacketFromPool(PoolHandle, Packet);
|
|
|
|
NDIS_RELEASE_SPIN_LOCK_DPC(&Pool->SpinLock);
|
|
|
|
if (*Packet != (PNDIS_PACKET)NULL)
|
|
{
|
|
//
|
|
// Clear packet elements.
|
|
//
|
|
ndisInitializePacket(Pool, *Packet);
|
|
|
|
*Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// No, cannot satisfy request.
|
|
//
|
|
|
|
*Status = NDIS_STATUS_RESOURCES;
|
|
}
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("<==NdisDprAllocatePacket\n"));
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisDprAllocatePacketNonInterlocked(
|
|
OUT PNDIS_STATUS Status,
|
|
OUT PNDIS_PACKET * Packet,
|
|
IN NDIS_HANDLE PoolHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates a packet out of a packet pool. Similar to NdisAllocatePacket
|
|
but is not interlocked. Caller guarantees synchronization.
|
|
|
|
Arguments:
|
|
|
|
Status - Returns the final status.
|
|
Packet - Return a pointer to the packet.
|
|
PoolHandle - The packet pool to allocate from.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNDIS_PACKET_POOL Pool = (PNDIS_PACKET_POOL)PoolHandle;
|
|
|
|
ndisAllocatePacketFromPool(PoolHandle, Packet);
|
|
|
|
if (*Packet != (PNDIS_PACKET)NULL)
|
|
{
|
|
//
|
|
// Clear packet elements.
|
|
//
|
|
ndisInitializePacket(Pool, *Packet);
|
|
|
|
*Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// No, cannot satisfy request.
|
|
//
|
|
|
|
*Status = NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("<==NdisDprAllocatePacketNonInterlocked\n"));
|
|
}
|
|
|
|
|
|
#undef NdisFreePacket
|
|
|
|
VOID
|
|
NdisFreePacket(
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
{
|
|
Packet->Private.Head = (PNDIS_BUFFER)(Packet->Private.Pool->FreeList);
|
|
Packet->Private.Pool->FreeList = Packet;
|
|
}
|
|
|
|
#undef NdisDprFreePacket
|
|
|
|
VOID
|
|
NdisDprFreePacket(
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
{
|
|
NdisDprAcquireSpinLock(&Packet->Private.Pool->SpinLock);
|
|
|
|
Packet->Private.Head = (PNDIS_BUFFER)(Packet->Private.Pool->FreeList);
|
|
Packet->Private.Pool->FreeList = Packet;
|
|
|
|
NdisDprReleaseSpinLock(&Packet->Private.Pool->SpinLock);
|
|
}
|
|
|
|
#undef NdisDprFreePacketNonInterlocked
|
|
|
|
VOID
|
|
NdisDprFreePacketNonInterlocked(
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
{
|
|
Packet->Private.Head = (PNDIS_BUFFER)(Packet->Private.Pool->FreeList);
|
|
Packet->Private.Pool->FreeList = Packet;
|
|
}
|
|
|
|
|
|
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(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("==>NdisUnchainBufferAtFront\n"));
|
|
|
|
IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR)
|
|
{
|
|
BOOLEAN f = FALSE;
|
|
if (DbgIsNull(Packet))
|
|
{
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
|
|
("UnchainBufferAtFront: Null Packet Pointer\n"));
|
|
f = TRUE;
|
|
}
|
|
if (!DbgIsNonPaged(Packet))
|
|
{
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
|
|
("UnchainBufferAtFront: Packet not in NonPaged Memory\n"));
|
|
f = TRUE;
|
|
}
|
|
if (!DbgIsPacket(Packet))
|
|
{
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
|
|
("UnchainBufferAtFront: Illegal Packet Size\n"));
|
|
f = TRUE;
|
|
}
|
|
if (f)
|
|
DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
|
|
}
|
|
|
|
if (*Buffer != (PNDIS_BUFFER)NULL)
|
|
{
|
|
Packet->Private.Head = (*Buffer)->Next; // may be NULL
|
|
(*Buffer)->Next = (PNDIS_BUFFER)NULL;
|
|
Packet->Private.ValidCounts = FALSE;
|
|
}
|
|
DBGPRINT(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(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("==>NdisUnchainBufferAtBack\n"));
|
|
|
|
IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR)
|
|
{
|
|
BOOLEAN f = FALSE;
|
|
if (DbgIsNull(Packet))
|
|
{
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
|
|
("UnchainBufferAtBack: Null Packet Pointer\n"));
|
|
f = TRUE;
|
|
}
|
|
if (!DbgIsNonPaged(Packet))
|
|
{
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
|
|
("UnchainBufferAtBack: Packet not in NonPaged Memory\n"));
|
|
f = TRUE;
|
|
}
|
|
if (!DbgIsPacket(Packet))
|
|
{
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
|
|
("UnchainBufferAtBack: Illegal Packet Size\n"));
|
|
f = TRUE;
|
|
}
|
|
if (f)
|
|
DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
|
|
}
|
|
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(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
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Holds the count of the number of ndis buffers comprising the
|
|
// destination packet.
|
|
//
|
|
UINT DestinationBufferCount;
|
|
|
|
//
|
|
// Holds the count of the number of ndis buffers comprising the
|
|
// source packet.
|
|
//
|
|
UINT SourceBufferCount;
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
NdisQueryPacket(Destination,
|
|
NULL,
|
|
&DestinationBufferCount,
|
|
&DestinationCurrentBuffer,
|
|
NULL);
|
|
|
|
//
|
|
// Could have a null packet.
|
|
//
|
|
|
|
if (!DestinationBufferCount)
|
|
return;
|
|
|
|
NdisQueryBuffer(DestinationCurrentBuffer,
|
|
&DestinationVirtualAddress,
|
|
&DestinationCurrentLength);
|
|
|
|
//
|
|
// Get the first buffer of the source.
|
|
//
|
|
|
|
NdisQueryPacket(Source,
|
|
NULL,
|
|
&SourceBufferCount,
|
|
&SourceCurrentBuffer,
|
|
NULL);
|
|
|
|
//
|
|
// Could have a null packet.
|
|
//
|
|
|
|
if (!SourceBufferCount)
|
|
return;
|
|
|
|
NdisQueryBuffer(SourceCurrentBuffer,
|
|
&SourceVirtualAddress,
|
|
&SourceCurrentLength);
|
|
|
|
while (LocalBytesCopied < BytesToCopy)
|
|
{
|
|
//
|
|
// Check to see whether we've exhausted the current destination
|
|
// buffer. If so, move onto the next one.
|
|
//
|
|
|
|
if (!DestinationCurrentLength)
|
|
{
|
|
NdisGetNextBuffer(DestinationCurrentBuffer, &DestinationCurrentBuffer);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
NdisQueryBuffer(DestinationCurrentBuffer,
|
|
&DestinationVirtualAddress,
|
|
&DestinationCurrentLength);
|
|
continue;
|
|
}
|
|
|
|
|
|
//
|
|
// Check to see whether we've exhausted the current source
|
|
// buffer. If so, move onto the next one.
|
|
//
|
|
|
|
if (!SourceCurrentLength)
|
|
{
|
|
NdisGetNextBuffer(SourceCurrentBuffer, &SourceCurrentBuffer);
|
|
|
|
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;
|
|
}
|
|
|
|
NdisQueryBuffer(SourceCurrentBuffer,
|
|
&SourceVirtualAddress,
|
|
&SourceCurrentLength);
|
|
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;
|
|
}
|
|
|
|
VOID
|
|
NdisAllocateSharedMemory(
|
|
IN NDIS_HANDLE NdisAdapterHandle,
|
|
IN ULONG Length,
|
|
IN BOOLEAN Cached,
|
|
OUT PVOID * VirtualAddress,
|
|
OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates memory to be shared between the driver and the adapter.
|
|
|
|
Arguments:
|
|
|
|
NdisAdapterHandle - handle returned by NdisRegisterAdapter.
|
|
Length - Length of the memory to allocate.
|
|
Cached - TRUE if memory is to be cached.
|
|
VirtualAddress - Returns the virtual address of the memory,
|
|
or NULL if the memory cannot be allocated.
|
|
PhysicalAddress - Returns the physical address of the memory.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNDIS_ADAPTER_BLOCK AdaptP = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
|
|
PADAPTER_OBJECT SystemAdapterObject;
|
|
PNDIS_WRAPPER_CONTEXT WrapperContext;
|
|
PULONG Page;
|
|
ULONG Type;
|
|
|
|
//
|
|
// Get interesting information from the adapter/miniport.
|
|
//
|
|
|
|
if (AdaptP->DeviceObject != NULL)
|
|
{
|
|
SystemAdapterObject = AdaptP->SystemAdapterObject;
|
|
WrapperContext = AdaptP->WrapperContext;
|
|
}
|
|
else
|
|
{
|
|
SystemAdapterObject = Miniport->SystemAdapterObject;
|
|
WrapperContext = Miniport->WrapperContext;
|
|
}
|
|
|
|
//
|
|
// Non-busmasters shouldn't call this routine.
|
|
//
|
|
|
|
if (SystemAdapterObject == NULL)
|
|
{
|
|
*VirtualAddress = NULL;
|
|
KdPrint(("You are not a busmaster\n"));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Compute allocation size by aligning to the proper boundary.
|
|
//
|
|
|
|
ASSERT(Length != 0);
|
|
|
|
Length = (Length + ndisDmaAlignment - 1) & ~(ndisDmaAlignment - 1);
|
|
|
|
//
|
|
// Check to determine is there is enough room left in the current page
|
|
// to satisfy the allocation.
|
|
//
|
|
|
|
Type = Cached ? 1 : 0;
|
|
ExAcquireResourceExclusive(&SharedMemoryResource, TRUE);
|
|
|
|
do
|
|
{
|
|
if (WrapperContext->SharedMemoryLeft[Type] < Length)
|
|
{
|
|
if ((Length + sizeof(ULONG)) >= PAGE_SIZE)
|
|
{
|
|
//
|
|
// The allocation is greater than a page.
|
|
//
|
|
|
|
*VirtualAddress = HalAllocateCommonBuffer(SystemAdapterObject,
|
|
Length,
|
|
PhysicalAddress,
|
|
Cached);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Allocate a new page for shared alocation.
|
|
//
|
|
|
|
WrapperContext->SharedMemoryPage[Type] =
|
|
HalAllocateCommonBuffer(SystemAdapterObject,
|
|
PAGE_SIZE,
|
|
&WrapperContext->SharedMemoryAddress[Type],
|
|
Cached);
|
|
|
|
if (WrapperContext->SharedMemoryPage[Type] == NULL)
|
|
{
|
|
WrapperContext->SharedMemoryLeft[Type] = 0;
|
|
*VirtualAddress = NULL;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Initialize the reference count in the last ULONG of the page.
|
|
//
|
|
|
|
Page = (PULONG)WrapperContext->SharedMemoryPage[Type];
|
|
Page[(PAGE_SIZE / sizeof(ULONG)) - 1] = 0;
|
|
WrapperContext->SharedMemoryLeft[Type] = PAGE_SIZE - sizeof(ULONG);
|
|
}
|
|
|
|
//
|
|
// Increment the reference count, set the address of the allocation,
|
|
// compute the physical address, and reduce the space remaining.
|
|
//
|
|
|
|
Page = (PULONG)WrapperContext->SharedMemoryPage[Type];
|
|
Page[(PAGE_SIZE / sizeof(ULONG)) - 1] += 1;
|
|
*VirtualAddress = (PVOID)((PUCHAR)Page +
|
|
(PAGE_SIZE - sizeof(ULONG) - WrapperContext->SharedMemoryLeft[Type]));
|
|
|
|
PhysicalAddress->QuadPart = WrapperContext->SharedMemoryAddress[Type].QuadPart +
|
|
((ULONG)*VirtualAddress & (PAGE_SIZE - 1));
|
|
|
|
WrapperContext->SharedMemoryLeft[Type] -= Length;
|
|
} while (FALSE);
|
|
|
|
ExReleaseResource(&SharedMemoryResource);
|
|
}
|
|
|
|
|
|
#undef NdisUpdateSharedMemory
|
|
|
|
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.
|
|
//
|
|
|
|
NdisAdapterHandle; Length; VirtualAddress; PhysicalAddress;
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisFreeSharedMemory(
|
|
IN NDIS_HANDLE NdisAdapterHandle,
|
|
IN ULONG Length,
|
|
IN BOOLEAN Cached,
|
|
IN PVOID VirtualAddress,
|
|
IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Frees shared memory allocated via NdisAllocateSharedMemory.
|
|
|
|
Arguments:
|
|
|
|
NdisAdapterHandle - handle returned by NdisRegisterAdapter.
|
|
Length - Length of the memory to allocate.
|
|
Cached - TRUE if memory was allocated cached.
|
|
VirtualAddress - Virtual address returned by NdisAllocateSharedMemory.
|
|
PhysicalAddress - The physical address returned by NdisAllocateSharedMemory.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNDIS_ADAPTER_BLOCK AdaptP = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
|
|
PADAPTER_OBJECT SystemAdapterObject;
|
|
PNDIS_WRAPPER_CONTEXT WrapperContext;
|
|
PULONG Page;
|
|
ULONG Type;
|
|
|
|
//
|
|
// Get interesting information from the adapter/miniport.
|
|
//
|
|
|
|
if (AdaptP->DeviceObject != NULL)
|
|
{
|
|
SystemAdapterObject = AdaptP->SystemAdapterObject;
|
|
WrapperContext = AdaptP->WrapperContext;
|
|
}
|
|
else
|
|
{
|
|
SystemAdapterObject = Miniport->SystemAdapterObject;
|
|
WrapperContext = Miniport->WrapperContext;
|
|
}
|
|
|
|
//
|
|
// Non-busmasters shouldn't call this routine.
|
|
//
|
|
|
|
ASSERT(SystemAdapterObject != NULL);
|
|
|
|
//
|
|
// Compute allocation size by aligning to the proper boundary.
|
|
//
|
|
|
|
ASSERT(Length != 0);
|
|
|
|
Length = (Length + ndisDmaAlignment - 1) & ~(ndisDmaAlignment - 1);
|
|
|
|
//
|
|
// Free the specified memory.
|
|
//
|
|
|
|
ExAcquireResourceExclusive(&SharedMemoryResource, TRUE);
|
|
if ((Length + sizeof(ULONG)) >= PAGE_SIZE)
|
|
{
|
|
//
|
|
// The allocation is greater than a page free the page directly.
|
|
//
|
|
|
|
HalFreeCommonBuffer(SystemAdapterObject,
|
|
Length,
|
|
PhysicalAddress,
|
|
VirtualAddress,
|
|
Cached);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Decrement the reference count and if the result is zero, then free
|
|
// the page.
|
|
//
|
|
|
|
Page = (PULONG)((ULONG)VirtualAddress & ~(PAGE_SIZE - 1));
|
|
Page[(PAGE_SIZE / sizeof(ULONG)) - 1] -= 1;
|
|
if (Page[(PAGE_SIZE / sizeof(ULONG)) - 1] == 0)
|
|
{
|
|
//
|
|
// Compute the physical address of the page and free it.
|
|
//
|
|
|
|
PhysicalAddress.LowPart &= ~(PAGE_SIZE - 1);
|
|
HalFreeCommonBuffer(SystemAdapterObject,
|
|
PAGE_SIZE,
|
|
PhysicalAddress,
|
|
Page,
|
|
Cached);
|
|
|
|
Type = Cached ? 1 : 0;
|
|
if ((PVOID)Page == WrapperContext->SharedMemoryPage[Type])
|
|
{
|
|
WrapperContext->SharedMemoryLeft[Type] = 0;
|
|
WrapperContext->SharedMemoryPage[Type] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
ExReleaseResource(&SharedMemoryResource);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
ndisCheckPortUsage(
|
|
IN INTERFACE_TYPE InterfaceType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG PortNumber,
|
|
IN ULONG Length,
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks if a port is currently in use somewhere in the
|
|
system via IoReportUsage -- which fails if there is a conflict.
|
|
|
|
Arguments:
|
|
|
|
InterfaceType - The bus type (ISA, EISA)
|
|
BusNumber - Bus number in the system
|
|
PortNumber - Address of the port to access.
|
|
Length - Number of ports from the base address to access.
|
|
|
|
Return Value:
|
|
|
|
FALSE if there is a conflict, else TRUE
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS NtStatus;
|
|
BOOLEAN Conflict;
|
|
NTSTATUS FirstNtStatus;
|
|
BOOLEAN FirstConflict;
|
|
PCM_RESOURCE_LIST Resources;
|
|
|
|
//
|
|
// Allocate space for resources
|
|
//
|
|
Resources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL(sizeof(CM_RESOURCE_LIST) +
|
|
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
|
|
NDIS_TAG_DEFAULT);
|
|
|
|
if (Resources == NULL)
|
|
{
|
|
//
|
|
// Error out
|
|
//
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
Resources->Count = 1;
|
|
Resources->List[0].InterfaceType = InterfaceType;
|
|
Resources->List[0].BusNumber = BusNumber;
|
|
Resources->List[0].PartialResourceList.Version = 0;
|
|
Resources->List[0].PartialResourceList.Revision = 0;
|
|
Resources->List[0].PartialResourceList.Count = 1;
|
|
|
|
//
|
|
// Setup port
|
|
//
|
|
Resources->List[0].PartialResourceList.PartialDescriptors[0].Type = CmResourceTypePort;
|
|
Resources->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition = CmResourceShareDriverExclusive;
|
|
Resources->List[0].PartialResourceList.PartialDescriptors[0].Flags =
|
|
(InterfaceType == Internal)?
|
|
CM_RESOURCE_PORT_MEMORY :
|
|
CM_RESOURCE_PORT_IO;
|
|
Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start.QuadPart = PortNumber;
|
|
Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Length = Length;
|
|
|
|
//
|
|
// Submit Resources
|
|
//
|
|
FirstNtStatus = IoReportResourceUsage(NULL,
|
|
DriverObject,
|
|
Resources,
|
|
sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
TRUE,
|
|
&FirstConflict);
|
|
|
|
//
|
|
// Now clear it out
|
|
//
|
|
Resources->List[0].PartialResourceList.Count = 0;
|
|
|
|
NtStatus = IoReportResourceUsage(NULL,
|
|
DriverObject,
|
|
Resources,
|
|
sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
TRUE,
|
|
&Conflict);
|
|
|
|
FREE_POOL(Resources);
|
|
|
|
//
|
|
// Check for conflict.
|
|
//
|
|
|
|
if (FirstConflict || (FirstNtStatus != STATUS_SUCCESS))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ndisStartMapping(
|
|
IN INTERFACE_TYPE InterfaceType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG InitialAddress,
|
|
IN ULONG Length,
|
|
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, EISA)
|
|
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 Address;
|
|
PHYSICAL_ADDRESS InitialPhysAddress;
|
|
ULONG addressSpace;
|
|
|
|
//
|
|
// 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;
|
|
|
|
addressSpace = (InterfaceType == Internal) ? 0 : 1;
|
|
|
|
InitialPhysAddress.LowPart = InitialAddress;
|
|
|
|
InitialPhysAddress.HighPart = 0;
|
|
|
|
if (!HalTranslateBusAddress(InterfaceType, // InterfaceType
|
|
BusNumber, // BusNumber
|
|
InitialPhysAddress, // Bus Address
|
|
&addressSpace, // AddressSpace
|
|
&Address)) // 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;
|
|
}
|
|
|
|
if (addressSpace == 0)
|
|
{
|
|
//
|
|
// memory space
|
|
//
|
|
|
|
*InitialMapping = MmMapIoSpace(Address, Length, FALSE);
|
|
|
|
if (*InitialMapping == NULL)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
*Mapped = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// I/O space
|
|
//
|
|
|
|
*InitialMapping = (PVOID)Address.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
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
|
|
(PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
|
|
PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
|
|
BOOLEAN Mapped;
|
|
PVOID PortMapping;
|
|
NDIS_INTERFACE_TYPE BusType;
|
|
ULONG BusNumber;
|
|
NTSTATUS Status;
|
|
|
|
BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
|
|
BusNumber = KeyQueryTable[3].DefaultLength;
|
|
|
|
//
|
|
// Check that the port is available. If so map the space.
|
|
//
|
|
if ((ndisCheckPortUsage(BusType,
|
|
BusNumber,
|
|
Port,
|
|
sizeof(UCHAR),
|
|
DriverObject) == FALSE) ||
|
|
!NT_SUCCESS(Status = ndisStartMapping(BusType,
|
|
BusNumber,
|
|
Port,
|
|
sizeof(UCHAR),
|
|
&PortMapping,
|
|
&Mapped)))
|
|
{
|
|
*Data = (UCHAR)0xFF;
|
|
return;
|
|
}
|
|
//
|
|
// Read from the port
|
|
//
|
|
|
|
*Data = READ_PORT_UCHAR((PUCHAR)PortMapping);
|
|
|
|
//
|
|
// End port mapping
|
|
//
|
|
|
|
ndisEndMapping(PortMapping, sizeof(UCHAR), Mapped);
|
|
}
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
|
|
(PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
|
|
PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
|
|
BOOLEAN Mapped;
|
|
PVOID PortMapping;
|
|
NDIS_INTERFACE_TYPE BusType;
|
|
ULONG BusNumber;
|
|
NTSTATUS Status;
|
|
|
|
BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
|
|
BusNumber = KeyQueryTable[3].DefaultLength;
|
|
|
|
//
|
|
// Check that the port is available. If so map the space.
|
|
//
|
|
if ((ndisCheckPortUsage(BusType,
|
|
BusNumber,
|
|
Port,
|
|
sizeof(USHORT),
|
|
DriverObject) == FALSE) ||
|
|
!NT_SUCCESS(Status = ndisStartMapping(BusType,
|
|
BusNumber,
|
|
Port,
|
|
sizeof(USHORT),
|
|
&PortMapping,
|
|
&Mapped)))
|
|
{
|
|
*Data = (USHORT)0xFFFF;
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Read from the port
|
|
//
|
|
|
|
*Data = READ_PORT_USHORT((PUSHORT)PortMapping);
|
|
|
|
//
|
|
// End port mapping
|
|
//
|
|
|
|
ndisEndMapping(PortMapping, sizeof(USHORT), Mapped);
|
|
}
|
|
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
|
|
(PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
|
|
PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
|
|
BOOLEAN Mapped;
|
|
PVOID PortMapping;
|
|
NDIS_INTERFACE_TYPE BusType;
|
|
ULONG BusNumber;
|
|
NTSTATUS Status;
|
|
|
|
BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
|
|
BusNumber = KeyQueryTable[3].DefaultLength;
|
|
|
|
//
|
|
// Check that the port is available. If so map the space.
|
|
//
|
|
if ((ndisCheckPortUsage(BusType,
|
|
BusNumber,
|
|
Port,
|
|
sizeof(ULONG),
|
|
DriverObject) == FALSE) ||
|
|
!NT_SUCCESS(Status = ndisStartMapping(BusType,
|
|
BusNumber,
|
|
Port,
|
|
sizeof(ULONG),
|
|
&PortMapping,
|
|
&Mapped)))
|
|
{
|
|
*Data = (ULONG)0xFFFFFFFF;
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Read from the port
|
|
//
|
|
|
|
*Data = READ_PORT_ULONG((PULONG)PortMapping);
|
|
|
|
//
|
|
// End port mapping
|
|
//
|
|
|
|
ndisEndMapping(PortMapping, sizeof(ULONG), Mapped);
|
|
}
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
|
|
(PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
|
|
PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
|
|
BOOLEAN Mapped;
|
|
PVOID PortMapping;
|
|
NDIS_INTERFACE_TYPE BusType;
|
|
ULONG BusNumber;
|
|
NTSTATUS Status;
|
|
|
|
BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
|
|
BusNumber = KeyQueryTable[3].DefaultLength;
|
|
|
|
//
|
|
// Check that the port is available. If so map the space.
|
|
//
|
|
if ((ndisCheckPortUsage(BusType,
|
|
BusNumber,
|
|
Port,
|
|
sizeof(UCHAR),
|
|
DriverObject) == FALSE) ||
|
|
!NT_SUCCESS(Status = ndisStartMapping(BusType,
|
|
BusNumber,
|
|
Port,
|
|
sizeof(UCHAR),
|
|
&PortMapping,
|
|
&Mapped)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Read from the port
|
|
//
|
|
|
|
WRITE_PORT_UCHAR((PUCHAR)PortMapping, Data);
|
|
|
|
//
|
|
// End port mapping
|
|
//
|
|
|
|
ndisEndMapping(PortMapping, sizeof(UCHAR), Mapped);
|
|
}
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
|
|
(PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
|
|
PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
|
|
BOOLEAN Mapped;
|
|
PVOID PortMapping;
|
|
NDIS_INTERFACE_TYPE BusType;
|
|
ULONG BusNumber;
|
|
NTSTATUS Status;
|
|
|
|
BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
|
|
BusNumber = KeyQueryTable[3].DefaultLength;
|
|
|
|
//
|
|
// Check that the port is available. If so map the space.
|
|
//
|
|
if ((ndisCheckPortUsage(BusType,
|
|
BusNumber,
|
|
Port,
|
|
sizeof(USHORT),
|
|
DriverObject) == FALSE) ||
|
|
!NT_SUCCESS(Status = ndisStartMapping(BusType,
|
|
BusNumber,
|
|
Port,
|
|
sizeof(USHORT),
|
|
&PortMapping,
|
|
&Mapped)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Read from the port
|
|
//
|
|
|
|
WRITE_PORT_USHORT((PUSHORT)PortMapping, Data);
|
|
|
|
//
|
|
// End port mapping
|
|
//
|
|
|
|
ndisEndMapping(PortMapping, sizeof(USHORT), Mapped);
|
|
}
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
|
|
(PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
|
|
PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
|
|
BOOLEAN Mapped;
|
|
PVOID PortMapping;
|
|
NDIS_INTERFACE_TYPE BusType;
|
|
ULONG BusNumber;
|
|
NTSTATUS Status;
|
|
|
|
BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
|
|
BusNumber = KeyQueryTable[3].DefaultLength;
|
|
|
|
//
|
|
// Check that the port is available. If so map the space.
|
|
//
|
|
if ((ndisCheckPortUsage(BusType,
|
|
BusNumber,
|
|
Port,
|
|
sizeof(ULONG),
|
|
DriverObject) == FALSE) ||
|
|
!NT_SUCCESS(Status = ndisStartMapping(BusType,
|
|
BusNumber,
|
|
Port,
|
|
sizeof(ULONG),
|
|
&PortMapping,
|
|
&Mapped)))
|
|
//
|
|
// Read from the port
|
|
//
|
|
|
|
WRITE_PORT_ULONG((PULONG)PortMapping, Data);
|
|
|
|
//
|
|
// End port mapping
|
|
//
|
|
|
|
ndisEndMapping(PortMapping, sizeof(ULONG), Mapped);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
ndisCheckMemoryUsage(
|
|
IN INTERFACE_TYPE InterfaceType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG Address,
|
|
IN ULONG Length,
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
/*++
|
|
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:
|
|
|
|
InterfaceType - The bus type (ISA, EISA)
|
|
BusNumber - Bus number in the system
|
|
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
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus;
|
|
BOOLEAN Conflict;
|
|
NTSTATUS FirstNtStatus;
|
|
BOOLEAN FirstConflict;
|
|
PCM_RESOURCE_LIST Resources;
|
|
|
|
//
|
|
// Allocate space for resources
|
|
//
|
|
|
|
Resources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL(sizeof(CM_RESOURCE_LIST) +
|
|
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
|
|
NDIS_TAG_DEFAULT);
|
|
|
|
if (Resources == NULL)
|
|
{
|
|
//
|
|
// Error out
|
|
//
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
Resources->Count = 1;
|
|
Resources->List[0].InterfaceType = InterfaceType;
|
|
Resources->List[0].BusNumber = BusNumber;
|
|
Resources->List[0].PartialResourceList.Version = 0;
|
|
Resources->List[0].PartialResourceList.Revision = 0;
|
|
Resources->List[0].PartialResourceList.Count = 1;
|
|
|
|
//
|
|
// Setup memory
|
|
//
|
|
|
|
Resources->List[0].PartialResourceList.PartialDescriptors[0].Type =
|
|
CmResourceTypeMemory;
|
|
Resources->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition =
|
|
CmResourceShareDriverExclusive;
|
|
Resources->List[0].PartialResourceList.PartialDescriptors[0].Flags =
|
|
CM_RESOURCE_MEMORY_READ_WRITE;
|
|
Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Memory.Start.QuadPart = Address;
|
|
Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Memory.Length = Length;
|
|
|
|
|
|
//
|
|
// Submit Resources
|
|
//
|
|
FirstNtStatus = IoReportResourceUsage(NULL,
|
|
DriverObject,
|
|
Resources,
|
|
sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
TRUE,
|
|
&FirstConflict);
|
|
|
|
//
|
|
// Now clear it out
|
|
//
|
|
Resources->List[0].PartialResourceList.Count = 0;
|
|
|
|
NtStatus = IoReportResourceUsage(NULL,
|
|
DriverObject,
|
|
Resources,
|
|
sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
TRUE,
|
|
&Conflict);
|
|
|
|
FREE_POOL(Resources);
|
|
|
|
//
|
|
// Check for conflict.
|
|
//
|
|
|
|
return (FirstConflict || (FirstNtStatus != STATUS_SUCCESS)) ? FALSE : TRUE;
|
|
}
|
|
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
|
|
(PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
|
|
PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
|
|
BOOLEAN Mapped;
|
|
PVOID MemoryMapping;
|
|
NDIS_INTERFACE_TYPE BusType;
|
|
ULONG BusNumber;
|
|
|
|
BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
|
|
BusNumber = KeyQueryTable[3].DefaultLength;
|
|
|
|
//
|
|
// Check that the memory is available. Map the space
|
|
//
|
|
|
|
if ((ndisCheckMemoryUsage(BusType,
|
|
BusNumber,
|
|
SharedMemoryAddress,
|
|
Length,
|
|
DriverObject) == FALSE) ||
|
|
!NT_SUCCESS(ndisStartMapping(BusType,
|
|
BusNumber,
|
|
SharedMemoryAddress,
|
|
Length,
|
|
&MemoryMapping,
|
|
&Mapped)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Read from memory
|
|
//
|
|
|
|
#ifdef _M_IX86
|
|
|
|
memcpy(Buffer, MemoryMapping, Length);
|
|
|
|
#else
|
|
|
|
READ_REGISTER_BUFFER_UCHAR(MemoryMapping,Buffer,Length);
|
|
|
|
#endif
|
|
|
|
//
|
|
// End mapping
|
|
//
|
|
|
|
ndisEndMapping(MemoryMapping,
|
|
Length,
|
|
Mapped);
|
|
}
|
|
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
|
|
(PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
|
|
PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
|
|
BOOLEAN Mapped;
|
|
PVOID MemoryMapping;
|
|
NDIS_INTERFACE_TYPE BusType;
|
|
ULONG BusNumber;
|
|
|
|
BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
|
|
BusNumber = KeyQueryTable[3].DefaultLength;
|
|
|
|
//
|
|
// Check that the memory is available. Map the space
|
|
//
|
|
if ((ndisCheckMemoryUsage(BusType,
|
|
BusNumber,
|
|
SharedMemoryAddress,
|
|
Length,
|
|
DriverObject) == FALSE) ||
|
|
!NT_SUCCESS(ndisStartMapping(BusType,
|
|
BusNumber,
|
|
SharedMemoryAddress,
|
|
Length,
|
|
&MemoryMapping,
|
|
&Mapped)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// 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);
|
|
}
|
|
|
|
|
|
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;
|
|
WCHAR PathPrefix[] = L"\\SystemRoot\\system32\\drivers\\";
|
|
NDIS_STRING FullFileName;
|
|
ULONG FullFileNameLength;
|
|
PNDIS_FILE_DESCRIPTOR FileDescriptor;
|
|
PVOID FileImage;
|
|
|
|
//
|
|
// This structure represents the data from the
|
|
// NtQueryInformationFile API with an information
|
|
// class of FileStandardInformation.
|
|
//
|
|
|
|
FILE_STANDARD_INFORMATION StandardInfo;
|
|
|
|
|
|
//
|
|
// Insert the correct path prefix.
|
|
//
|
|
|
|
FullFileNameLength = sizeof(PathPrefix) + FileName->MaximumLength;
|
|
FullFileName.Buffer = ALLOC_FROM_POOL(FullFileNameLength, NDIS_TAG_DEFAULT);
|
|
|
|
do
|
|
{
|
|
if (FullFileName.Buffer == NULL)
|
|
{
|
|
*Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
FullFileName.Length = sizeof (PathPrefix) - sizeof(WCHAR);
|
|
FullFileName.MaximumLength = (USHORT)FullFileNameLength;
|
|
CopyMemory (FullFileName.Buffer, PathPrefix, sizeof(PathPrefix));
|
|
|
|
RtlAppendUnicodeStringToString (&FullFileName, FileName);
|
|
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("Attempting to open %Z\n", &FullFileName));
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&FullFileName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
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_DEFAULT);
|
|
|
|
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_DEFAULT);
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
FREE_POOL(FileDescriptor->Data);
|
|
FREE_POOL(FileDescriptor);
|
|
}
|
|
|
|
|
|
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.
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle;
|
|
|
|
ACQUIRE_SPIN_LOCK(&FileDescriptor->Lock, &OldIrql);
|
|
|
|
if (FileDescriptor->Mapped == TRUE)
|
|
{
|
|
*Status = NDIS_STATUS_ALREADY_MAPPED;
|
|
RELEASE_SPIN_LOCK (&FileDescriptor->Lock, OldIrql);
|
|
return;
|
|
}
|
|
|
|
FileDescriptor->Mapped = TRUE;
|
|
RELEASE_SPIN_LOCK (&FileDescriptor->Lock, OldIrql);
|
|
|
|
*MappedBuffer = FileDescriptor->Data;
|
|
*Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
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;
|
|
KIRQL OldIrql;
|
|
|
|
ACQUIRE_SPIN_LOCK(&FileDescriptor->Lock, &OldIrql);
|
|
FileDescriptor->Mapped = FALSE;
|
|
RELEASE_SPIN_LOCK (&FileDescriptor->Lock, OldIrql);
|
|
}
|
|
|
|
|
|
CCHAR
|
|
NdisSystemProcessorCount(
|
|
VOID
|
|
)
|
|
{
|
|
return **((PCHAR *)&KeNumberProcessors);
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisGetSystemUpTime(
|
|
OUT PULONG pSystemUpTime
|
|
)
|
|
{
|
|
LARGE_INTEGER TickCount;
|
|
|
|
//
|
|
// Get tick count and convert to hundreds of nanoseconds.
|
|
//
|
|
KeQueryTickCount(&TickCount);
|
|
TickCount = RtlExtendedIntegerMultiply(TickCount,
|
|
KeQueryTimeIncrement());
|
|
TickCount = RtlExtendedIntegerMultiply(TickCount, 10000);
|
|
|
|
ASSERT(TickCount.HighPart == 0);
|
|
*pSystemUpTime = TickCount.LowPart;
|
|
}
|
|
|
|
VOID
|
|
NdisGetCurrentProcessorCpuUsage(
|
|
IN PULONG pCpuUsage
|
|
)
|
|
{
|
|
PKPRCB Prcb;
|
|
|
|
Prcb = KeGetCurrentPrcb();
|
|
*pCpuUsage = 100 - (ULONG)(UInt32x32To64(Prcb->IdleThread->KernelTime, 100) /
|
|
(ULONGLONG)(Prcb->KernelTime + Prcb->UserTime));
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisGetCurrentProcessorCounts(
|
|
OUT PULONG pIdleCount,
|
|
OUT PULONG pKernelAndUser,
|
|
OUT PULONG pIndex
|
|
)
|
|
{
|
|
PKPRCB Prcb;
|
|
|
|
Prcb = KeGetCurrentPrcb();
|
|
*pIdleCount = Prcb->IdleThread->KernelTime;
|
|
*pKernelAndUser = Prcb->KernelTime + Prcb->UserTime;
|
|
*pIndex = (ULONG)Prcb->Number;
|
|
}
|
|
|
|
#undef NdisGetCurrentSystemTime
|
|
VOID
|
|
NdisGetCurrentSystemTime(
|
|
IN PLARGE_INTEGER pCurrentTime
|
|
)
|
|
{
|
|
KeQuerySystemTime(pCurrentTime);
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
NdisQueryMapRegisterCount(
|
|
IN NDIS_INTERFACE_TYPE BusType,
|
|
OUT PUINT MapRegisterCount
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
UINT Count, Tmp;
|
|
|
|
Count = (UINT)BusType;
|
|
Status = HalQuerySystemInformation(HalMapRegisterInformation,
|
|
sizeof(UINT),
|
|
&Count,
|
|
&Tmp);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
*MapRegisterCount = Count;
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
return NDIS_STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
|
|
//
|
|
// NDIS Event support
|
|
//
|
|
|
|
VOID
|
|
NdisInitializeEvent(
|
|
IN PNDIS_EVENT Event
|
|
)
|
|
{
|
|
INITIALIZE_EVENT(&Event->Event);
|
|
}
|
|
|
|
VOID
|
|
NdisSetEvent(
|
|
IN PNDIS_EVENT Event
|
|
)
|
|
{
|
|
SET_EVENT(&Event->Event);
|
|
}
|
|
|
|
VOID
|
|
NdisResetEvent(
|
|
IN PNDIS_EVENT Event
|
|
)
|
|
{
|
|
RESET_EVENT(&Event->Event);
|
|
}
|
|
|
|
BOOLEAN
|
|
NdisWaitEvent(
|
|
IN PNDIS_EVENT Event,
|
|
IN UINT MsToWait
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
TIME Time, *pTime;
|
|
|
|
pTime = NULL;
|
|
if (MsToWait != 0)
|
|
{
|
|
ASSERT(CURRENT_IRQL < DISPATCH_LEVEL);
|
|
Time.QuadPart = Int32x32To64(MsToWait, -10000);
|
|
pTime = &Time;
|
|
}
|
|
|
|
Status = WAIT_FOR_OBJECT(&Event->Event, pTime);
|
|
|
|
return(Status == NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
NdisInitializeString(
|
|
OUT PNDIS_STRING Destination,
|
|
IN PUCHAR Source
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
WCHAR *strptr;
|
|
|
|
Destination->Length = strlen(Source) * sizeof(WCHAR);
|
|
Destination->MaximumLength = Destination->Length + sizeof(WCHAR);
|
|
Destination->Buffer = ALLOC_FROM_POOL(Destination->MaximumLength, NDIS_TAG_STRING);
|
|
|
|
strptr = Destination->Buffer;
|
|
while (*Source != '\0')
|
|
{
|
|
*strptr = (WCHAR)*Source;
|
|
Source++;
|
|
strptr++;
|
|
}
|
|
*strptr = UNICODE_NULL;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
ndisReportResources(
|
|
PCM_RESOURCE_LIST Resources,
|
|
PDRIVER_OBJECT DriverObject,
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PNDIS_STRING AdapterName,
|
|
ULONG NewResourceType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
BOOLEAN Conflict;
|
|
|
|
//
|
|
// When we report the resources we need to subtract 1 from the
|
|
// count. this is because the sizeof(CM_RESOURCE_LIST) already includes
|
|
// one CM_PARTIAL_RESOURCE_DESCRIPTOR and if we multiply by the current
|
|
// Count the size passed to IoReportResourceUsage will be one descriptor
|
|
// too many.
|
|
//
|
|
Status = IoReportResourceUsage(NULL,
|
|
DriverObject,
|
|
NULL,
|
|
0,
|
|
DeviceObject,
|
|
Resources,
|
|
sizeof(CM_RESOURCE_LIST) +
|
|
(sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
|
|
(Resources->List->PartialResourceList.Count - 1)),
|
|
TRUE,
|
|
&Conflict);
|
|
|
|
//
|
|
// Check for conflict.
|
|
//
|
|
if (Conflict || (Status != STATUS_SUCCESS))
|
|
{
|
|
if (Conflict)
|
|
{
|
|
//
|
|
// Log an error
|
|
//
|
|
PIO_ERROR_LOG_PACKET errorLogEntry;
|
|
ULONG i;
|
|
ULONG StringSize;
|
|
PUCHAR Place;
|
|
PWCH baseFileName;
|
|
USHORT logsize;
|
|
|
|
baseFileName = AdapterName->Buffer;
|
|
|
|
//
|
|
// Parse out the path name, leaving only the device name.
|
|
//
|
|
for (i = 0; i < AdapterName->Length / sizeof(WCHAR); i++)
|
|
{
|
|
//
|
|
// If s points to a directory separator, set baseFileName to
|
|
// the character after the separator.
|
|
//
|
|
if (AdapterName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
|
|
{
|
|
baseFileName = &(AdapterName->Buffer[++i]);
|
|
}
|
|
}
|
|
|
|
StringSize = AdapterName->MaximumLength -
|
|
((ULONG)baseFileName - (ULONG)AdapterName->Buffer);
|
|
logsize = sizeof(IO_ERROR_LOG_PACKET) + StringSize + 6;
|
|
if (logsize > 255)
|
|
{
|
|
logsize = 255;
|
|
}
|
|
|
|
errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
|
|
DeviceObject,
|
|
(UCHAR)logsize);
|
|
if (errorLogEntry != NULL)
|
|
{
|
|
switch (NewResourceType)
|
|
{
|
|
case CmResourceTypePort:
|
|
|
|
errorLogEntry->ErrorCode = EVENT_NDIS_IO_PORT_CONFLICT;
|
|
|
|
break;
|
|
|
|
case CmResourceTypeDma:
|
|
|
|
errorLogEntry->ErrorCode = EVENT_NDIS_DMA_CONFLICT;
|
|
|
|
break;
|
|
|
|
case CmResourceTypeMemory:
|
|
|
|
errorLogEntry->ErrorCode = EVENT_NDIS_MEMORY_CONFLICT;
|
|
|
|
break;
|
|
|
|
case CmResourceTypeInterrupt:
|
|
|
|
errorLogEntry->ErrorCode = EVENT_NDIS_INTERRUPT_CONFLICT;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// store the time
|
|
//
|
|
errorLogEntry->MajorFunctionCode = 0;
|
|
errorLogEntry->RetryCount = 0;
|
|
errorLogEntry->UniqueErrorValue = 0;
|
|
errorLogEntry->FinalStatus = 0;
|
|
errorLogEntry->SequenceNumber = 0;
|
|
errorLogEntry->IoControlCode = 0;
|
|
|
|
//
|
|
// Set string information
|
|
//
|
|
if (StringSize != 0)
|
|
{
|
|
errorLogEntry->NumberOfStrings = 1;
|
|
errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
|
|
|
|
MoveMemory(((PUCHAR)errorLogEntry) + sizeof(IO_ERROR_LOG_PACKET),
|
|
baseFileName,
|
|
logsize - (sizeof(IO_ERROR_LOG_PACKET) + 6));
|
|
|
|
Place = ((PUCHAR)errorLogEntry) +
|
|
sizeof(IO_ERROR_LOG_PACKET) +
|
|
StringSize;
|
|
}
|
|
else
|
|
{
|
|
Place = ((PUCHAR)errorLogEntry) +
|
|
sizeof(IO_ERROR_LOG_PACKET);
|
|
|
|
errorLogEntry->NumberOfStrings = 0;
|
|
}
|
|
|
|
//
|
|
// write it out
|
|
//
|
|
IoWriteErrorLogEntry(errorLogEntry);
|
|
}
|
|
|
|
return(NDIS_STATUS_RESOURCE_CONFLICT);
|
|
}
|
|
|
|
return(NDIS_STATUS_FAILURE);
|
|
}
|
|
|
|
return(NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ndisRemoveResource(
|
|
OUT PCM_RESOURCE_LIST *pResources,
|
|
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR DeadResource,
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PNDIS_STRING AdapterName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
this routine will walk the current resource list looking for the
|
|
dead resource. it will construct a new resource list without the
|
|
dead resource and report this new list to the system.
|
|
|
|
Arguments:
|
|
|
|
pResource - On entry this is the current resource list.
|
|
On exit this is the newly constructed resource list.
|
|
DriverObject - Driver object to report the resources for.
|
|
DeviceObject - Device object to report the resources for.
|
|
DeadResource - This is the resource to remove.
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS if the routine succeeded.
|
|
|
|
--*/
|
|
{
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR Dst;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR Partial;
|
|
PCM_RESOURCE_LIST CurrentList = *pResources;
|
|
PCM_RESOURCE_LIST Resources;
|
|
UINT c;
|
|
UINT Remaining;
|
|
BOOLEAN Conflict;
|
|
NDIS_STATUS Status;
|
|
BOOLEAN fFoundResource;
|
|
|
|
//
|
|
// Sanity check!
|
|
//
|
|
if ((NULL == pResources) || (NULL == *pResources))
|
|
{
|
|
return(NDIS_STATUS_FAILURE);
|
|
}
|
|
|
|
//
|
|
// Allocate a new resource map.
|
|
//
|
|
Resources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL(
|
|
sizeof(CM_RESOURCE_LIST) +
|
|
(sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
|
|
(CurrentList->List->PartialResourceList.Count - 1)),
|
|
NDIS_TAG_RSRC_LIST);
|
|
if (NULL == Resources)
|
|
{
|
|
//
|
|
// Leave it there...
|
|
//
|
|
return(NDIS_STATUS_RESOURCES);
|
|
}
|
|
|
|
//
|
|
// Copy the head information.
|
|
//
|
|
MoveMemory(Resources, CurrentList, sizeof(CM_RESOURCE_LIST));
|
|
|
|
Resources->List->PartialResourceList.Count--;
|
|
|
|
//
|
|
// Get our destination pointer.
|
|
//
|
|
Dst = Resources->List->PartialResourceList.PartialDescriptors;
|
|
|
|
//
|
|
// Find the resource in our resource list.
|
|
//
|
|
Partial = CurrentList->List->PartialResourceList.PartialDescriptors;
|
|
for (c = 0, fFoundResource = FALSE;
|
|
(c < CurrentList->List->PartialResourceList.Count) && !fFoundResource;
|
|
c++, Partial++)
|
|
{
|
|
//
|
|
// Is this the resource we are supposed to remove?
|
|
//
|
|
if (RtlEqualMemory(
|
|
Partial,
|
|
DeadResource,
|
|
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)))
|
|
{
|
|
//
|
|
// copy the remaining portion of the list.
|
|
//
|
|
fFoundResource = TRUE;
|
|
|
|
//
|
|
// Copy any remaining resources into the list.
|
|
//
|
|
Remaining = CurrentList->List->PartialResourceList.Count - (c+1);
|
|
if (Remaining > 0)
|
|
{
|
|
MoveMemory(Dst, Partial+1, Remaining * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Copy this resource to our new list!
|
|
//
|
|
MoveMemory(Dst, Partial, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
|
|
Dst++;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Did we find the resource?
|
|
//
|
|
if (!fFoundResource)
|
|
{
|
|
FREE_POOL(Resources);
|
|
return(NDIS_STATUS_FAILURE);
|
|
}
|
|
|
|
//
|
|
// Free the old resource list and save the new one.
|
|
//
|
|
FREE_POOL(*pResources);
|
|
|
|
*pResources = Resources;
|
|
|
|
//
|
|
// Report the resources to the system.
|
|
//
|
|
Status = ndisReportResources(
|
|
Resources,
|
|
DriverObject,
|
|
DeviceObject,
|
|
AdapterName,
|
|
DeadResource->Type);
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
ndisAddResource(
|
|
OUT PCM_RESOURCE_LIST *pResources,
|
|
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR NewResource,
|
|
IN NDIS_INTERFACE_TYPE AdapterType,
|
|
IN ULONG BusNumber,
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PNDIS_STRING AdapterName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PCM_RESOURCE_LIST Resources;
|
|
UINT NumberOfElements;
|
|
BOOLEAN Conflict;
|
|
NDIS_STATUS Status;
|
|
|
|
if (*pResources != NULL)
|
|
{
|
|
NumberOfElements = (*pResources)->List->PartialResourceList.Count;
|
|
}
|
|
else
|
|
{
|
|
NumberOfElements = 0;
|
|
}
|
|
|
|
//
|
|
// Allocate room for the new list. Note that we don't have to add one
|
|
// to the NumberOfElements since a CM_RESOURCE_LIST already contains a
|
|
// single CM_PARTIAL_RESOURCE_DESCRIPTOR.
|
|
//
|
|
Resources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL(
|
|
sizeof(CM_RESOURCE_LIST) +
|
|
(sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * NumberOfElements),
|
|
NDIS_TAG_RSRC_LIST);
|
|
if (NULL == Resources)
|
|
{
|
|
return(NDIS_STATUS_RESOURCES);
|
|
}
|
|
|
|
if (*pResources != NULL)
|
|
{
|
|
//
|
|
// We need to subtract the size of a CM_PARTIAL_RESOURCE_DESCRIPTOR
|
|
// from the size of the CM_RESOURCE_LIST.
|
|
//
|
|
MoveMemory(Resources,
|
|
*pResources,
|
|
(sizeof(CM_RESOURCE_LIST) -
|
|
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)) +
|
|
(sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
|
|
(*pResources)->List->PartialResourceList.Count));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Setup initial resource information.
|
|
//
|
|
Resources->Count = 1;
|
|
Resources->List->InterfaceType = AdapterType;
|
|
Resources->List->BusNumber = BusNumber;
|
|
Resources->List->PartialResourceList.Version = 0;
|
|
Resources->List->PartialResourceList.Revision = 0;
|
|
Resources->List->PartialResourceList.Count = 0;
|
|
}
|
|
|
|
//
|
|
// Add the new resource.
|
|
//
|
|
Resources->List->PartialResourceList.PartialDescriptors[Resources->List->PartialResourceList.Count] = *NewResource;
|
|
Resources->List->PartialResourceList.Count++;
|
|
|
|
if (*pResources != NULL)
|
|
{
|
|
FREE_POOL(*pResources);
|
|
}
|
|
|
|
*pResources = Resources;
|
|
|
|
//
|
|
// Report the resources to the system.
|
|
//
|
|
Status = ndisReportResources(
|
|
Resources,
|
|
DriverObject,
|
|
DeviceObject,
|
|
AdapterName,
|
|
NewResource->Type);
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|