Windows NT 4.0 source code leak
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

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