329 lines
7 KiB
C
329 lines
7 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1989 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
misc.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module implemets helper routines not readily available
|
||
|
in kernel or TDI libraries for ws2ifsl.sys driver.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Vadim Eydelman (VadimE) Oct-1997 (Inspired by AFD)
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "precomp.h"
|
||
|
|
||
|
|
||
|
#pragma alloc_text(PAGE, AllocateMdlChain)
|
||
|
#pragma alloc_text(PAGE, CopyBufferToMdlChain)
|
||
|
#pragma alloc_text(PAGE, CopyMdlChainToBuffer)
|
||
|
|
||
|
|
||
|
VOID
|
||
|
AllocateMdlChain(
|
||
|
IN PIRP Irp,
|
||
|
IN LPWSABUF BufferArray,
|
||
|
IN ULONG BufferCount,
|
||
|
OUT PULONG TotalByteCount
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Allocates a MDL chain describing the WSABUF array and attaches
|
||
|
the chain to the specified IRP.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Irp - The IRP that will receive the MDL chain.
|
||
|
|
||
|
BufferArray - Points to an array of WSABUF structures describing
|
||
|
the user's buffers.
|
||
|
|
||
|
BufferCount - Contains the number of WSABUF structures in the
|
||
|
array.
|
||
|
|
||
|
TotalByteCount - Will receive the total number of BYTEs described
|
||
|
by the WSABUF array.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
Note:
|
||
|
Raises appropriate exception if probing/allocation fails
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PMDL currentMdl;
|
||
|
PMDL * chainTarget;
|
||
|
KPROCESSOR_MODE previousMode;
|
||
|
ULONG totalLength;
|
||
|
PVOID bufferPointer;
|
||
|
ULONG bufferLength;
|
||
|
|
||
|
PAGED_CODE ();
|
||
|
//
|
||
|
// Sanity check.
|
||
|
//
|
||
|
|
||
|
ASSERT( Irp != NULL );
|
||
|
ASSERT( Irp->MdlAddress == NULL );
|
||
|
ASSERT( BufferArray != NULL );
|
||
|
ASSERT( BufferCount > 0 );
|
||
|
ASSERT( TotalByteCount != NULL );
|
||
|
|
||
|
//
|
||
|
// Get the previous processor mode.
|
||
|
//
|
||
|
|
||
|
previousMode = Irp->RequestorMode;
|
||
|
|
||
|
if ((BufferArray == NULL)
|
||
|
|| (BufferCount == 0)
|
||
|
// Check for integer overflow (disabled by compiler)
|
||
|
|| (BufferCount>(MAXULONG/sizeof (WSABUF)))) {
|
||
|
ExRaiseStatus (STATUS_INVALID_PARAMETER);
|
||
|
}
|
||
|
|
||
|
if( previousMode != KernelMode ) {
|
||
|
|
||
|
//
|
||
|
// Probe the WSABUF array.
|
||
|
//
|
||
|
|
||
|
ProbeForRead(
|
||
|
BufferArray, // Address
|
||
|
BufferCount * sizeof(WSABUF), // Length
|
||
|
sizeof(ULONG) // Alignment
|
||
|
);
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get into a known state.
|
||
|
//
|
||
|
|
||
|
currentMdl = NULL;
|
||
|
chainTarget = &Irp->MdlAddress;
|
||
|
totalLength = 0;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Scan the array.
|
||
|
//
|
||
|
|
||
|
do {
|
||
|
|
||
|
bufferPointer = BufferArray->buf;
|
||
|
bufferLength = BufferArray->len;
|
||
|
|
||
|
if( bufferPointer != NULL &&
|
||
|
bufferLength > 0 ) {
|
||
|
|
||
|
//
|
||
|
// Update the total byte counter.
|
||
|
//
|
||
|
|
||
|
totalLength += bufferLength;
|
||
|
|
||
|
//
|
||
|
// Create a new MDL.
|
||
|
//
|
||
|
|
||
|
currentMdl = IoAllocateMdl(
|
||
|
bufferPointer, // VirtualAddress
|
||
|
bufferLength, // Length
|
||
|
FALSE, // SecondaryBuffer
|
||
|
TRUE, // ChargeQuota
|
||
|
NULL // Irp
|
||
|
);
|
||
|
|
||
|
if( currentMdl != NULL ) {
|
||
|
|
||
|
//
|
||
|
// Chain the MDL onto the IRP. In theory, we could
|
||
|
// do this by passing the IRP into IoAllocateMdl(),
|
||
|
// but IoAllocateMdl() does a linear scan on the MDL
|
||
|
// chain to find the last one in the chain.
|
||
|
//
|
||
|
// We can do much better.
|
||
|
//
|
||
|
|
||
|
*chainTarget = currentMdl;
|
||
|
chainTarget = ¤tMdl->Next;
|
||
|
|
||
|
//
|
||
|
// Advance to the next WSABUF structure.
|
||
|
//
|
||
|
|
||
|
BufferArray++;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Cannot allocate new MDL, raise exception.
|
||
|
//
|
||
|
|
||
|
ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
} while( --BufferCount );
|
||
|
|
||
|
//
|
||
|
// Ensure the MDL chain is NULL terminated.
|
||
|
//
|
||
|
|
||
|
ASSERT( *chainTarget == NULL );
|
||
|
|
||
|
|
||
|
//
|
||
|
// Return the total buffer count.
|
||
|
//
|
||
|
|
||
|
*TotalByteCount = totalLength;
|
||
|
|
||
|
} // AllocateMdlChain
|
||
|
|
||
|
ULONG
|
||
|
CopyMdlChainToBuffer(
|
||
|
IN PMDL SourceMdlChain,
|
||
|
IN PVOID Destination,
|
||
|
IN ULONG DestinationLength
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Copies data from a MDL chain to a linear buffer.
|
||
|
Assumes that MDL in the right process context
|
||
|
(virtual address is valid but it may not be mapped into system space)
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
SourceMdlChain - chain of MDL to copy buffer from.
|
||
|
|
||
|
Destination - Points to the linear destination of the data.
|
||
|
|
||
|
DestinationLength - The length of Destination.
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
ULONG - The number of bytes copied.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
ULONG SrcBytesLeft = 0;
|
||
|
PUCHAR Dst = Destination, Src;
|
||
|
|
||
|
PAGED_CODE ();
|
||
|
|
||
|
//ASSERT (SourceMdlChain->Process==PsGetCurrentProcess ());
|
||
|
|
||
|
while (DestinationLength != 0) {
|
||
|
do {
|
||
|
if (SourceMdlChain == NULL) {
|
||
|
goto Done;
|
||
|
}
|
||
|
Src = MmGetMdlVirtualAddress (SourceMdlChain);
|
||
|
SrcBytesLeft = MmGetMdlByteCount (SourceMdlChain);
|
||
|
SourceMdlChain = SourceMdlChain->Next;
|
||
|
}
|
||
|
while (SrcBytesLeft == 0);
|
||
|
|
||
|
if (SrcBytesLeft >= DestinationLength) {
|
||
|
RtlCopyMemory (Dst, Src, DestinationLength);
|
||
|
Dst += DestinationLength;
|
||
|
break;
|
||
|
} else {
|
||
|
RtlCopyMemory (Dst, Src, SrcBytesLeft);
|
||
|
DestinationLength -= SrcBytesLeft;
|
||
|
Dst += SrcBytesLeft;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Done:
|
||
|
return (ULONG)(Dst - (PUCHAR)Destination);
|
||
|
|
||
|
} // CopyMdlChainToBuffer
|
||
|
|
||
|
|
||
|
|
||
|
ULONG
|
||
|
CopyBufferToMdlChain(
|
||
|
IN PVOID Source,
|
||
|
IN ULONG SourceLength,
|
||
|
IN PMDL DestinationMdlChain
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Copies data from a linear buffer to a MDL chain.
|
||
|
Assumes that MDL in the right process context
|
||
|
(virtual address is valid but it may not be mapped into system space)
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Source - Points to the linear source of the data.
|
||
|
|
||
|
SourceLength - The length of Source.
|
||
|
|
||
|
DestinationMdlChain - chain of MDL to copy buffer to.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
ULONG - The number of bytes copied.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
ULONG DstBytesLeft = 0;
|
||
|
PUCHAR Dst, Src = Source;
|
||
|
|
||
|
// ASSERT (DestinationMdlChain->Process==PsGetCurrentProcess ());
|
||
|
|
||
|
while (SourceLength != 0) {
|
||
|
do {
|
||
|
if (DestinationMdlChain == NULL) {
|
||
|
goto Done;
|
||
|
}
|
||
|
Dst = MmGetMdlVirtualAddress (DestinationMdlChain);
|
||
|
DstBytesLeft = MmGetMdlByteCount (DestinationMdlChain);
|
||
|
DestinationMdlChain = DestinationMdlChain->Next;
|
||
|
}
|
||
|
while (DstBytesLeft == 0);
|
||
|
|
||
|
if (DstBytesLeft >= SourceLength) {
|
||
|
RtlCopyMemory (Dst, Src, SourceLength);
|
||
|
Src += SourceLength;
|
||
|
break;
|
||
|
} else {
|
||
|
RtlCopyMemory (Dst, Src, DstBytesLeft);
|
||
|
SourceLength -= DstBytesLeft;
|
||
|
Src += DstBytesLeft;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Done:
|
||
|
return (ULONG)(Src - (PUCHAR)Source);
|
||
|
|
||
|
} // CopyBufferToMdlChain
|
||
|
|
||
|
|