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.
651 lines
14 KiB
651 lines
14 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
buffer.c
|
|
|
|
Abstract:
|
|
|
|
This module contains routines for handling non-bufferring TDI
|
|
providers. The AFD interface assumes that bufferring will be done
|
|
below AFD; if the TDI provider doesn't buffer, then AFD must.
|
|
|
|
Author:
|
|
|
|
David Treadwell (davidtr) 21-Feb-1992
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "afdp.h"
|
|
|
|
VOID
|
|
AfdInitializeBuffer (
|
|
IN PAFD_BUFFER AfdBuffer,
|
|
IN CLONG BufferDataSize,
|
|
IN CLONG AddressSize
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGEAFD, AfdAllocateBuffer )
|
|
#pragma alloc_text( PAGEAFD, AfdCalculateBufferSize )
|
|
#pragma alloc_text( PAGEAFD, AfdInitializeBuffer )
|
|
#pragma alloc_text( PAGEAFD, AfdGetBuffer )
|
|
#pragma alloc_text( PAGEAFD, AfdGetBufferChain )
|
|
#pragma alloc_text( PAGEAFD, AfdReturnBuffer )
|
|
#pragma alloc_text( PAGEAFD, AfdReturnBufferChain )
|
|
#if DBG
|
|
#pragma alloc_text( PAGEAFD, AfdFreeBufferPool )
|
|
#endif
|
|
#endif
|
|
|
|
|
|
PVOID
|
|
AfdAllocateBuffer (
|
|
IN POOL_TYPE PoolType,
|
|
IN ULONG NumberOfBytes,
|
|
IN ULONG Tag
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Used by the lookaside list allocation function to allocate a new
|
|
AFD buffer structure. The returned structure will be fully
|
|
initialized.
|
|
|
|
Arguments:
|
|
|
|
PoolType - passed to ExAllocatePoolWithTag.
|
|
|
|
NumberOfBytes - the number of bytes required for the data buffer
|
|
portion of the AFD buffer.
|
|
|
|
Tag - passed to ExAllocatePoolWithTag.
|
|
|
|
Return Value:
|
|
|
|
PVOID - a fully initialized PAFD_BUFFER, or NULL if the allocation
|
|
attempt fails.
|
|
|
|
--*/
|
|
|
|
{
|
|
PAFD_BUFFER afdBuffer;
|
|
ULONG bytesRequired;
|
|
|
|
//
|
|
// The requested length must be the same as one of the standard
|
|
// AFD buffer sizes.
|
|
//
|
|
|
|
ASSERT( NumberOfBytes == AfdSmallBufferSize ||
|
|
NumberOfBytes == AfdMediumBufferSize ||
|
|
NumberOfBytes == AfdLargeBufferSize );
|
|
|
|
//
|
|
// Determine how much data we'll actually need for the buffer.
|
|
//
|
|
|
|
bytesRequired = AfdCalculateBufferSize(
|
|
NumberOfBytes,
|
|
AfdStandardAddressLength
|
|
);
|
|
|
|
//
|
|
// Get nonpaged pool for the buffer.
|
|
//
|
|
|
|
afdBuffer = AFD_ALLOCATE_POOL( PoolType, bytesRequired, Tag );
|
|
if ( afdBuffer == NULL ) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Initialize the buffer and return a pointer to it.
|
|
//
|
|
|
|
AfdInitializeBuffer( afdBuffer, NumberOfBytes, AfdStandardAddressLength );
|
|
|
|
return afdBuffer;
|
|
|
|
|
|
} // AfdAllocateBuffer
|
|
|
|
|
|
CLONG
|
|
AfdCalculateBufferSize (
|
|
IN CLONG BufferDataSize,
|
|
IN CLONG AddressSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determines the size of an AFD buffer structure given the amount of
|
|
data that the buffer contains.
|
|
|
|
Arguments:
|
|
|
|
BufferDataSize - data length of the buffer.
|
|
|
|
AddressSize - length of address structure for the buffer.
|
|
|
|
Return Value:
|
|
|
|
Number of bytes needed for an AFD_BUFFER structure for data of
|
|
this size.
|
|
|
|
--*/
|
|
|
|
{
|
|
CLONG irpSize;
|
|
CLONG mdlSize;
|
|
CLONG bufferSize;
|
|
|
|
ASSERT( BufferDataSize != 0 );
|
|
ASSERT( AfdCacheLineSize < 100 );
|
|
|
|
//
|
|
// Determine the sizes of the various components of an AFD_BUFFER
|
|
// structure. Note that these are all worst-case calculations--
|
|
// actual sizes of the MDL and the buffer may be smaller.
|
|
//
|
|
|
|
irpSize = IoSizeOfIrp( AfdIrpStackSize ) + 8;
|
|
bufferSize = BufferDataSize + AfdCacheLineSize;
|
|
mdlSize = MmSizeOfMdl( (PVOID)(PAGE_SIZE-1), bufferSize );
|
|
|
|
return ( (sizeof(AFD_BUFFER) + irpSize + mdlSize +
|
|
AddressSize + bufferSize + 3) & ~3);
|
|
|
|
} // AfdCalculateBufferSize
|
|
|
|
|
|
PAFD_BUFFER
|
|
AfdGetBuffer (
|
|
IN CLONG BufferDataSize,
|
|
IN CLONG AddressSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Obtains a buffer of the appropriate size for the caller. Uses
|
|
the preallocated buffers if possible, or else allocates a new buffer
|
|
structure if required.
|
|
|
|
Arguments:
|
|
|
|
BufferDataSize - the size of the data buffer that goes along with the
|
|
buffer structure.
|
|
|
|
AddressSize - size of the address field required for the buffer.
|
|
|
|
Return Value:
|
|
|
|
PAFD_BUFFER - a pointer to an AFD_BUFFER structure, or NULL if one
|
|
was not available or could not be allocated.
|
|
|
|
--*/
|
|
|
|
{
|
|
PAFD_BUFFER afdBuffer;
|
|
CLONG bufferSize;
|
|
PLIST_ENTRY listEntry;
|
|
PNPAGED_LOOKASIDE_LIST lookasideList;
|
|
|
|
//
|
|
// If possible, allocate the buffer from one of the lookaside lists.
|
|
//
|
|
|
|
if ( AddressSize <= AfdStandardAddressLength &&
|
|
BufferDataSize <= AfdLargeBufferSize ) {
|
|
|
|
if ( BufferDataSize <= AfdSmallBufferSize ) {
|
|
|
|
lookasideList = &AfdLookasideLists->SmallBufferList;
|
|
BufferDataSize = AfdSmallBufferSize;
|
|
|
|
} else if ( BufferDataSize <= AfdMediumBufferSize ) {
|
|
|
|
lookasideList = &AfdLookasideLists->MediumBufferList;
|
|
BufferDataSize = AfdMediumBufferSize;
|
|
|
|
} else {
|
|
|
|
lookasideList = &AfdLookasideLists->LargeBufferList;
|
|
BufferDataSize = AfdLargeBufferSize;
|
|
}
|
|
|
|
afdBuffer = ExAllocateFromNPagedLookasideList( lookasideList );
|
|
#if DBG
|
|
if ( afdBuffer != NULL ) {
|
|
|
|
RtlGetCallersAddress(
|
|
&afdBuffer->Caller,
|
|
&afdBuffer->CallersCaller
|
|
);
|
|
}
|
|
#endif
|
|
|
|
return afdBuffer;
|
|
|
|
}
|
|
|
|
//
|
|
// Couldn't find an appropriate buffer that was preallocated.
|
|
// Allocate one manually. If the buffer size requested was
|
|
// zero bytes, give them four bytes. This is because some of
|
|
// the routines like MmSizeOfMdl() cannot handle getting passed
|
|
// in a length of zero.
|
|
//
|
|
// !!! It would be good to ROUND_TO_PAGES for this allocation
|
|
// if appropriate, then use entire buffer size.
|
|
//
|
|
|
|
if ( BufferDataSize == 0 ) {
|
|
BufferDataSize = sizeof(ULONG);
|
|
}
|
|
|
|
bufferSize = AfdCalculateBufferSize( BufferDataSize, AddressSize );
|
|
|
|
afdBuffer = AFD_ALLOCATE_POOL(
|
|
NonPagedPool,
|
|
bufferSize,
|
|
AFD_DATA_BUFFER_POOL_TAG
|
|
);
|
|
|
|
if ( afdBuffer == NULL ) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Initialize the AFD buffer structure and return it.
|
|
//
|
|
|
|
AfdInitializeBuffer( afdBuffer, BufferDataSize, AddressSize );
|
|
|
|
return afdBuffer;
|
|
|
|
} // AfdGetBuffer
|
|
|
|
|
|
PAFD_BUFFER
|
|
AfdGetBufferChain (
|
|
IN CLONG BufferDataSize
|
|
)
|
|
{
|
|
PAFD_BUFFER afdBuffer;
|
|
PAFD_BUFFER bufferChain;
|
|
PAFD_BUFFER *bufferChainTarget;
|
|
PMDL mdlChain;
|
|
PMDL *mdlChainTarget;
|
|
CLONG currentBufferSize;
|
|
#if DBG
|
|
CLONG totalChainLength = BufferDataSize;
|
|
#endif
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
ASSERT( BufferDataSize > AfdBufferLengthForOnePage );
|
|
|
|
//
|
|
// Setup so we know how to cleanup.
|
|
//
|
|
|
|
bufferChain = NULL;
|
|
mdlChain = NULL;
|
|
bufferChainTarget = &bufferChain;
|
|
mdlChainTarget = &mdlChain;
|
|
|
|
//
|
|
// Loop, acquiring & chaining the buffers.
|
|
//
|
|
|
|
while ( BufferDataSize > 0 ) {
|
|
|
|
//
|
|
// Acquire a new buffer. If this fails, we're toast.
|
|
//
|
|
|
|
currentBufferSize = max( BufferDataSize, AfdBufferLengthForOnePage );
|
|
|
|
afdBuffer = AfdGetBuffer( currentBufferSize, 0 );
|
|
|
|
if ( afdBuffer == NULL ) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Chain it on.
|
|
//
|
|
|
|
*bufferChainTarget = afdBuffer;
|
|
bufferChainTarget = &afdBuffer->NextBuffer;
|
|
|
|
*mdlChainTarget = afdBuffer->Mdl;
|
|
mdlChainTarget = &afdBuffer->Mdl->Next;
|
|
|
|
BufferDataSize -= currentBufferSize;
|
|
|
|
}
|
|
|
|
if ( BufferDataSize == 0 ) {
|
|
|
|
ASSERT( bufferChain != NULL );
|
|
ASSERT( afdBuffer != NULL );
|
|
ASSERT( currentBufferSize > 0 );
|
|
ASSERT( currentBufferSize <= AfdBufferLengthForOnePage );
|
|
|
|
//
|
|
// Set the byte count in the final MDL in the chain.
|
|
//
|
|
|
|
afdBuffer->Mdl->ByteCount = currentBufferSize;
|
|
SET_CHAIN_LENGTH( afdBuffer, totalChainLength );
|
|
|
|
return bufferChain;
|
|
|
|
}
|
|
|
|
//
|
|
// Error, time to cleanup.
|
|
//
|
|
|
|
while( bufferChain != NULL ) {
|
|
|
|
afdBuffer = bufferChain->NextBuffer;
|
|
|
|
bufferChain->Mdl->Next = NULL;
|
|
bufferChain->NextBuffer = NULL;
|
|
RESET_CHAIN_LENGTH( bufferChain );
|
|
AfdReturnBuffer( bufferChain );
|
|
|
|
bufferChain = afdBuffer;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
} // AfdGetBufferChain
|
|
|
|
|
|
VOID
|
|
AfdReturnBuffer (
|
|
IN PAFD_BUFFER AfdBuffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns an AFD buffer to the appropriate global list, or frees
|
|
it if necessary.
|
|
|
|
Arguments:
|
|
|
|
AfdBuffer - points to the AFD_BUFFER structure to return or free.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNPAGED_LOOKASIDE_LIST lookasideList;
|
|
|
|
//
|
|
// Most of the AFD buffer must be zeroed when returning the buffer.
|
|
//
|
|
|
|
ASSERT( AfdBuffer->DataOffset == 0 );
|
|
ASSERT( !AfdBuffer->ExpeditedData );
|
|
ASSERT( AfdBuffer->TdiInputInfo.UserDataLength == 0 );
|
|
ASSERT( AfdBuffer->TdiInputInfo.UserData == NULL );
|
|
ASSERT( AfdBuffer->TdiInputInfo.OptionsLength == 0 );
|
|
ASSERT( AfdBuffer->TdiInputInfo.Options == NULL );
|
|
ASSERT( AfdBuffer->TdiInputInfo.RemoteAddressLength == 0 );
|
|
ASSERT( AfdBuffer->TdiInputInfo.RemoteAddress == NULL );
|
|
ASSERT( AfdBuffer->TdiOutputInfo.UserDataLength == 0 );
|
|
ASSERT( AfdBuffer->TdiOutputInfo.UserData == NULL );
|
|
ASSERT( AfdBuffer->TdiOutputInfo.OptionsLength == 0 );
|
|
ASSERT( AfdBuffer->TdiOutputInfo.Options == NULL );
|
|
ASSERT( AfdBuffer->TdiOutputInfo.RemoteAddressLength == 0 );
|
|
ASSERT( AfdBuffer->TdiOutputInfo.RemoteAddress == NULL );
|
|
|
|
ASSERT( AfdBuffer->Mdl->ByteCount == AfdBuffer->BufferLength );
|
|
ASSERT( AfdBuffer->Mdl->Next == NULL );
|
|
ASSERT( AfdBuffer->FileObject == NULL );
|
|
ASSERT( AfdBuffer->NextBuffer == NULL );
|
|
ASSERT( AfdBuffer->TotalChainLength == AfdBuffer->BufferLength );
|
|
|
|
#if DBG
|
|
AfdBuffer->Caller = NULL;
|
|
AfdBuffer->CallersCaller = NULL;
|
|
#endif
|
|
|
|
//
|
|
// If appropriate, return the buffer to one of the AFD buffer
|
|
// lookaside lists.
|
|
//
|
|
|
|
if ( AfdBuffer->AllocatedAddressLength == AfdStandardAddressLength &&
|
|
AfdBuffer->BufferLength <= AfdLargeBufferSize ) {
|
|
|
|
if ( AfdBuffer->BufferLength == AfdSmallBufferSize ) {
|
|
|
|
lookasideList = &AfdLookasideLists->SmallBufferList;
|
|
|
|
} else if ( AfdBuffer->BufferLength == AfdMediumBufferSize ) {
|
|
|
|
lookasideList = &AfdLookasideLists->MediumBufferList;
|
|
|
|
} else {
|
|
|
|
ASSERT( AfdBuffer->BufferLength == AfdLargeBufferSize );
|
|
lookasideList = &AfdLookasideLists->LargeBufferList;
|
|
}
|
|
|
|
ExFreeToNPagedLookasideList( lookasideList, AfdBuffer );
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// The buffer was not from a lookaside list allocation, so just free
|
|
// the pool we used for it.
|
|
//
|
|
|
|
AFD_FREE_POOL(
|
|
AfdBuffer,
|
|
AFD_DATA_BUFFER_POOL_TAG
|
|
);
|
|
|
|
return;
|
|
|
|
} // AfdReturnBuffer
|
|
|
|
VOID
|
|
AfdReturnBufferChain (
|
|
IN PAFD_BUFFER AfdBuffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns an AFD buffer chain to the appropriate global list, or frees
|
|
it if necessary.
|
|
|
|
Arguments:
|
|
|
|
AfdBuffer - points to the AFD_BUFFER structure to return or free.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PAFD_BUFFER nextBuffer;
|
|
|
|
while ( AfdBuffer != NULL ) {
|
|
|
|
nextBuffer = AfdBuffer->NextBuffer;
|
|
|
|
AfdBuffer->NextBuffer = NULL;
|
|
AfdBuffer->Mdl->Next = NULL;
|
|
AfdBuffer->Mdl->ByteCount = AfdBuffer->BufferLength;
|
|
RESET_CHAIN_LENGTH( AfdBuffer );
|
|
AfdReturnBuffer( AfdBuffer );
|
|
|
|
AfdBuffer = nextBuffer;
|
|
|
|
}
|
|
|
|
} // AfdReturnBufferChain
|
|
|
|
|
|
VOID
|
|
AfdInitializeBuffer (
|
|
IN PAFD_BUFFER AfdBuffer,
|
|
IN CLONG BufferDataSize,
|
|
IN CLONG AddressSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes an AFD buffer. Sets up fields in the actual AFD_BUFFER
|
|
structure and initializes the IRP and MDL associated with the
|
|
buffer. This routine assumes that the caller has properly allocated
|
|
sufficient space for all this.
|
|
|
|
Arguments:
|
|
|
|
AfdBuffer - points to the AFD_BUFFER structure to initialize.
|
|
|
|
BufferDataSize - the size of the data buffer that goes along with the
|
|
buffer structure.
|
|
|
|
AddressSize - the size of data allocated for the address buffer.
|
|
|
|
ListHead - the global list this buffer belongs to, or NULL if it
|
|
doesn't belong on any list. This routine does NOT place the
|
|
buffer structure on the list.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
CLONG irpSize;
|
|
CLONG mdlSize;
|
|
|
|
//
|
|
// Initialize the IRP pointer and the IRP itself.
|
|
//
|
|
|
|
AfdBuffer->Irp = (PIRP)(( ((ULONG)(AfdBuffer + 1)) + 7) & ~7);
|
|
irpSize = IoSizeOfIrp( AfdIrpStackSize );
|
|
|
|
IoInitializeIrp( AfdBuffer->Irp, (USHORT)irpSize, AfdIrpStackSize );
|
|
|
|
//
|
|
// Set up the MDL pointer but don't build it yet. We have to wait
|
|
// until after the data buffer is built to build the MDL.
|
|
//
|
|
|
|
mdlSize = MmSizeOfMdl( (PVOID)(PAGE_SIZE-1), BufferDataSize );
|
|
|
|
AfdBuffer->Mdl = (PMDL)( (PCHAR)AfdBuffer->Irp + irpSize );
|
|
|
|
//
|
|
// Set up the address buffer pointer.
|
|
//
|
|
|
|
AfdBuffer->SourceAddress = (PCHAR)AfdBuffer->Mdl + mdlSize;
|
|
AfdBuffer->AllocatedAddressLength = (USHORT)AddressSize;
|
|
|
|
//
|
|
// Initialize the TDI information structures.
|
|
//
|
|
|
|
RtlZeroMemory( &AfdBuffer->TdiInputInfo, sizeof(AfdBuffer->TdiInputInfo) );
|
|
RtlZeroMemory( &AfdBuffer->TdiOutputInfo, sizeof(AfdBuffer->TdiOutputInfo) );
|
|
|
|
//
|
|
// Set up the data buffer pointer and length. Note that the buffer
|
|
// MUST begin on a cache line boundary so that we can use the fast
|
|
// copy routines like RtlCopyMemory on the buffer.
|
|
//
|
|
|
|
AfdBuffer->Buffer = (PVOID)
|
|
( ( (ULONG)AfdBuffer->SourceAddress + AddressSize +
|
|
AfdCacheLineSize - 1 ) & ~(AfdCacheLineSize - 1) );
|
|
|
|
AfdBuffer->BufferLength = BufferDataSize;
|
|
RESET_CHAIN_LENGTH( AfdBuffer );
|
|
|
|
//
|
|
// Now build the MDL and set up a pointer to the MDL in the IRP.
|
|
//
|
|
|
|
MmInitializeMdl( AfdBuffer->Mdl, AfdBuffer->Buffer, BufferDataSize );
|
|
MmBuildMdlForNonPagedPool( AfdBuffer->Mdl );
|
|
|
|
AfdBuffer->Irp->MdlAddress = AfdBuffer->Mdl;
|
|
AfdBuffer->DataOffset = 0;
|
|
AfdBuffer->ExpeditedData = FALSE;
|
|
AfdBuffer->PartialMessage = FALSE;
|
|
AfdBuffer->FileObject = NULL;
|
|
|
|
//
|
|
// By default, buffers are not part of a chain.
|
|
//
|
|
|
|
AfdBuffer->NextBuffer = NULL;
|
|
|
|
|
|
#if DBG
|
|
AfdBuffer->BufferListEntry.Flink = (PVOID)0xE0E1E2E3;
|
|
AfdBuffer->BufferListEntry.Blink = (PVOID)0xE4E5E6E7;
|
|
AfdBuffer->Caller = NULL;
|
|
AfdBuffer->CallersCaller = NULL;
|
|
#endif
|
|
|
|
} // AfdInitializeBuffer
|
|
|
|
|
|
#if DBG
|
|
VOID
|
|
NTAPI
|
|
AfdFreeBufferPool(
|
|
IN PVOID Block
|
|
)
|
|
{
|
|
|
|
AFD_FREE_POOL(
|
|
Block,
|
|
AFD_DATA_BUFFER_POOL_TAG
|
|
);
|
|
|
|
} // AfdFreeBufferPool
|
|
#endif
|
|
|