|
|
/*++
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
|