Leaked source code of windows server 2003
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.
 
 
 
 
 
 

3921 lines
98 KiB

/*++
Copyright (c) 1998-2002 Microsoft Corporation
Module Name:
misc.c
Abstract:
This module contains the miscellaneous UL routines.
Author:
Keith Moore (keithmo) 10-Jun-1998
Revision History:
--*/
#include "precomp.h"
#include "miscp.h"
//
// Binary <--> Base64 Conversion Tables.
//
DECLSPEC_ALIGN(UL_CACHE_LINE) UCHAR BinaryToBase64Table[64] =
{
// 0 1 2 3 4 5 6 7
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/'
};
DECLSPEC_ALIGN(UL_CACHE_LINE) UCHAR Base64ToBinaryTable[256];
const static char hexArray[] = "0123456789ABCDEF";
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, UlOpenRegistry )
#pragma alloc_text( PAGE, UlReadLongParameter )
#pragma alloc_text( PAGE, UlReadLongLongParameter )
#pragma alloc_text( PAGE, UlReadGenericParameter )
#pragma alloc_text( PAGE, UlIssueDeviceControl )
#endif // ALLOC_PRAGMA
#if 0
NOT PAGEABLE -- UlBuildDeviceControlIrp
NOT PAGEABLE -- UlULongLongToAscii
NOT PAGEABLE -- UlpRestartDeviceControl
NOT PAGEABLE -- UlAllocateReceiveBuffer
NOT PAGEABLE -- UlAllocateReceiveBufferPool
NOT PAGEABLE -- UlFreeReceiveBufferPool
NOT PAGEABLE -- UlAllocateIrpContextPool
NOT PAGEABLE -- UlFreeIrpContextPool
NOT PAGEABLE -- UlAllocateRequestBufferPool
NOT PAGEABLE -- UlFreeRequestBufferPool
NOT PAGEABLE -- UlAllocateInternalRequestPool
NOT PAGEABLE -- UlFreeInternalRequestPool
NOT PAGEABLE -- UlAllocateChunkTrackerPool
NOT PAGEABLE -- UlFreeChunkTrackerPool
NOT PAGEABLE -- UlAllocateFullTrackerPool
NOT PAGEABLE -- UlFreeFullTrackerPool
NOT PAGEABLE -- UlAllocateResponseBufferPool
NOT PAGEABLE -- UlFreeResponseBufferPool
NOT PAGEABLE -- UlAllocateLogFileBufferPool
NOT PAGEABLE -- UlFreeLogFileBufferPool
NOT PAGEABLE -- UlAllocateLogDataBufferPool
NOT PAGEABLE -- UlFreeLogDataBufferPool
NOT PAGEABLE -- UlAllocateErrorLogBufferPool
NOT PAGEABLE -- UlFreeErrorLogBufferPool
NOT PAGEABLE -- UlUlInterlockedIncrement64
NOT PAGEABLE -- UlUlInterlockedDecrement64
NOT PAGEABLE -- UlUlInterlockedAdd64
NOT PAGEABLE -- UlUlInterlockedExchange64
NOT PAGEABLE -- TwoDigitsToUnicode
NOT PAGEABLE -- TimeFieldsToHttpDate
NOT PAGEABLE -- AsciiToShort
NOT PAGEABLE -- TwoAsciisToShort
NOT PAGEABLE -- NumericToAsciiMonth
NOT PAGEABLE -- StringTimeToSystemTime
#endif
//
// Public functions.
//
/***************************************************************************++
Routine Description:
Opens a handle to the UL's Parameters registry key.
Arguments:
BaseName - Supplies the name of the parent registry key containing
the Parameters key.
ParametersHandle - Returns a handle to the Parameters key.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlOpenRegistry(
IN PUNICODE_STRING BaseName,
OUT PHANDLE ParametersHandle,
IN PWSTR OptionalParameterString
)
{
HANDLE configHandle;
NTSTATUS status;
PWSTR parametersString = REGISTRY_PARAMETERS;
UNICODE_STRING parametersKeyName;
OBJECT_ATTRIBUTES objectAttributes;
//
// Sanity check.
//
PAGED_CODE();
if (OptionalParameterString)
{
parametersString = OptionalParameterString;
}
//
// Open the registry for the initial string.
//
InitializeObjectAttributes(
&objectAttributes, // ObjectAttributes
BaseName, // ObjectName
OBJ_CASE_INSENSITIVE | // Attributes
OBJ_KERNEL_HANDLE,
NULL, // RootDirectory
NULL // SecurityDescriptor
);
status = ZwOpenKey( &configHandle, KEY_READ, &objectAttributes );
if (!NT_SUCCESS(status))
{
return STATUS_UNSUCCESSFUL;
}
//
// Now open the parameters key.
//
status = UlInitUnicodeStringEx( &parametersKeyName, parametersString );
if ( NT_SUCCESS(status) )
{
InitializeObjectAttributes(
&objectAttributes, // ObjectAttributes
&parametersKeyName, // ObjectName
OBJ_CASE_INSENSITIVE, // Attributes
configHandle, // RootDirectory
NULL // SecurityDescriptor
);
status = ZwOpenKey( ParametersHandle, KEY_READ, &objectAttributes );
}
ZwClose( configHandle );
return status;
} // UlOpenRegistry
/***************************************************************************++
Routine Description:
Reads a single (LONG/ULONG) value from the registry.
Arguments:
ParametersHandle - Supplies an open registry handle.
ValueName - Supplies the name of the value to read.
DefaultValue - Supplies the default value.
Return Value:
LONG - The value read from the registry or the default if the
registry data was unavailable or incorrect.
--***************************************************************************/
LONG
UlReadLongParameter(
IN HANDLE ParametersHandle,
IN PWCHAR ValueName,
IN LONG DefaultValue
)
{
PKEY_VALUE_PARTIAL_INFORMATION information = { 0 };
UNICODE_STRING valueKeyName;
ULONG informationLength;
LONG returnValue;
NTSTATUS status;
UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(LONG)];
//
// Sanity check.
//
PAGED_CODE();
//
// Build the value name, read it from the registry.
//
status = UlInitUnicodeStringEx(
&valueKeyName,
ValueName
);
if ( NT_SUCCESS(status) )
{
information = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
status = ZwQueryValueKey(
ParametersHandle,
&valueKeyName,
KeyValuePartialInformation,
(PVOID)information,
sizeof(buffer),
&informationLength
);
}
//
// If the read succeeded, the type is DWORD and the length is
// sane, use it. Otherwise, use the default.
//
if (status == STATUS_SUCCESS &&
information->Type == REG_DWORD &&
information->DataLength == sizeof(returnValue))
{
RtlMoveMemory( &returnValue, information->Data, sizeof(returnValue) );
}
else
{
returnValue = DefaultValue;
}
return returnValue;
} // UlReadLongParameter
/***************************************************************************++
Routine Description:
Reads a single (LONGLONG/ULONGLONG) value from the registry.
Arguments:
ParametersHandle - Supplies an open registry handle.
ValueName - Supplies the name of the value to read.
DefaultValue - Supplies the default value.
Return Value:
LONGLONG - The value read from the registry or the default if the
registry data was unavailable or incorrect.
--***************************************************************************/
LONGLONG
UlReadLongLongParameter(
IN HANDLE ParametersHandle,
IN PWCHAR ValueName,
IN LONGLONG DefaultValue
)
{
PKEY_VALUE_PARTIAL_INFORMATION information = { 0 };
UNICODE_STRING valueKeyName;
ULONG informationLength;
LONGLONG returnValue;
NTSTATUS status;
UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(LONGLONG)];
//
// Sanity check.
//
PAGED_CODE();
//
// Build the value name, read it from the registry.
//
status = UlInitUnicodeStringEx(
&valueKeyName,
ValueName
);
if ( NT_SUCCESS(status) )
{
information = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
status = ZwQueryValueKey(
ParametersHandle,
&valueKeyName,
KeyValuePartialInformation,
(PVOID)information,
sizeof(buffer),
&informationLength
);
}
//
// If the read succeeded, the type is DWORD and the length is
// sane, use it. Otherwise, use the default.
//
if (status == STATUS_SUCCESS &&
information->Type == REG_QWORD &&
information->DataLength == sizeof(returnValue))
{
RtlMoveMemory( &returnValue, information->Data, sizeof(returnValue) );
}
else
{
returnValue = DefaultValue;
}
return returnValue;
} // UlReadLongLongParameter
/***************************************************************************++
Routine Description:
Reads a single free-form value from the registry.
Arguments:
ParametersHandle - Supplies an open registry handle.
ValueName - Supplies the name of the value to read.
Value - Receives the value read from the registry.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlReadGenericParameter(
IN HANDLE ParametersHandle,
IN PWCHAR ValueName,
OUT PKEY_VALUE_PARTIAL_INFORMATION * Value
)
{
KEY_VALUE_PARTIAL_INFORMATION partialInfo;
UNICODE_STRING valueKeyName;
ULONG informationLength;
NTSTATUS status;
PKEY_VALUE_PARTIAL_INFORMATION newValue;
ULONG dataLength;
//
// Sanity check.
//
PAGED_CODE();
//
// Build the value name, then perform an initial read. The read
// should fail with buffer overflow, but that's OK. We just want
// to get the length of the data.
//
status = UlInitUnicodeStringEx( &valueKeyName, ValueName );
if ( NT_ERROR(status) )
{
return status;
}
status = ZwQueryValueKey(
ParametersHandle,
&valueKeyName,
KeyValuePartialInformation,
(PVOID)&partialInfo,
sizeof(partialInfo),
&informationLength
);
if (NT_ERROR(status))
{
return status;
}
//
// Determine the data length. Ensure that strings and multi-sz get
// properly terminated.
//
dataLength = partialInfo.DataLength - 1;
if (partialInfo.Type == REG_SZ || partialInfo.Type == REG_EXPAND_SZ)
{
dataLength += 1;
}
if (partialInfo.Type == REG_MULTI_SZ)
{
dataLength += 2;
}
//
// Allocate the buffer.
//
newValue = UL_ALLOCATE_STRUCT_WITH_SPACE(
PagedPool,
KEY_VALUE_PARTIAL_INFORMATION,
dataLength,
UL_REGISTRY_DATA_POOL_TAG
);
if (newValue == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// update the actually allocated length for later use
//
dataLength += sizeof(KEY_VALUE_PARTIAL_INFORMATION);
RtlZeroMemory( newValue, dataLength );
//
// Perform the actual read.
//
status = ZwQueryValueKey(
ParametersHandle,
&valueKeyName,
KeyValuePartialInformation,
(PVOID)(newValue),
dataLength,
&informationLength
);
if (NT_SUCCESS(status))
{
*Value = newValue;
}
else
{
UL_FREE_POOL( newValue, UL_REGISTRY_DATA_POOL_TAG );
}
return status;
} // UlReadGenericParameter
/***************************************************************************++
Routine Description:
Builds a properly formatted device control IRP.
Arguments:
Irp - Supplies the IRP to format.
IoControlCode - Supplies the device IO control code.
InputBuffer - Supplies the input buffer.
InputBufferLength - Supplies the length of InputBuffer.
OutputBuffer - Supplies the output buffer.
OutputBufferLength - Supplies the length of OutputBuffer.
MdlAddress - Supplies a MDL to attach to the IRP. This is assumed to
be a non-paged MDL.
FileObject - Supplies the file object for the target driver.
DeviceObject - Supplies the correct device object for the target
driver.
IoStatusBlock - Receives the final completion status of the request.
CompletionRoutine - Supplies a pointer to a completion routine to
call after the request completes. This will only be called if
this routine returns STATUS_PENDING.
CompletionContext - Supplies an uninterpreted context value passed
to the completion routine.
TargetThread - Optionally supplies a target thread for the IRP. If
this value is NULL, then the current thread is used.
--***************************************************************************/
VOID
UlBuildDeviceControlIrp(
IN OUT PIRP Irp,
IN ULONG IoControlCode,
IN PVOID InputBuffer OPTIONAL,
IN ULONG InputBufferLength,
IN PVOID OutputBuffer OPTIONAL,
IN ULONG OutputBufferLength,
IN PMDL MdlAddress,
IN PFILE_OBJECT FileObject,
IN PDEVICE_OBJECT DeviceObject,
IN PIO_STATUS_BLOCK IoStatusBlock,
IN PIO_COMPLETION_ROUTINE CompletionRoutine,
IN PVOID CompletionContext,
IN PETHREAD TargetThread OPTIONAL
)
{
PIO_STACK_LOCATION irpSp;
//
// Sanity check.
//
ASSERT( Irp != NULL );
ASSERT( FileObject != NULL );
ASSERT( DeviceObject != NULL );
//
// Fill in the service independent parameters in the IRP.
//
Irp->Flags = 0;
Irp->RequestorMode = KernelMode;
Irp->PendingReturned = FALSE;
Irp->UserIosb = IoStatusBlock;
Irp->UserEvent = NULL;
Irp->AssociatedIrp.SystemBuffer = InputBuffer ? InputBuffer : OutputBuffer;
Irp->UserBuffer = OutputBuffer;
Irp->MdlAddress = MdlAddress;
Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
Irp->Tail.Overlay.Thread = TargetThread ? TargetThread : PsGetCurrentThread();
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
//
// Put the file object pointer in the stack location.
//
irpSp = IoGetNextIrpStackLocation( Irp );
irpSp->FileObject = FileObject;
irpSp->DeviceObject = DeviceObject;
//
// Fill in the service dependent parameters in the IRP stack.
//
irpSp->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
irpSp->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
irpSp->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength;
irpSp->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer;
irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
irpSp->MinorFunction = 0;
//
// Set the completion routine appropriately.
//
if (CompletionRoutine == NULL)
{
IoSetCompletionRoutine(
Irp,
NULL,
NULL,
FALSE,
FALSE,
FALSE
);
}
else
{
IoSetCompletionRoutine(
Irp,
CompletionRoutine,
CompletionContext,
TRUE,
TRUE,
TRUE
);
}
} // UlBuildDeviceControlIrp
/***************************************************************************++
Routine Description:
Converts the given ULONGLLONG to an ASCII representation and stores it
in the given string.
Arguments:
String - Receives the ASCII representation of the ULONGLONG.
Value - Supplies the ULONGLONG to convert.
Return Value:
PSTR - Pointer to the next character in String *after* the converted
ULONGLONG.
--***************************************************************************/
PSTR
UlULongLongToAscii(
IN PSTR String,
IN ULONGLONG Value
)
{
PSTR p1;
PSTR p2;
CHAR ch;
ULONG digit;
//
// Special case 0 to make the rest of the routine simpler.
//
if (Value == 0)
{
*String++ = '0';
}
else
{
//
// Convert the ULONG. Note that this will result in the string
// being backwards in memory.
//
p1 = String;
p2 = String;
while (Value != 0)
{
digit = (ULONG)( Value % 10 );
Value = Value / 10;
*p1++ = '0' + (CHAR)digit;
}
//
// Reverse the string.
//
String = p1;
p1--;
while (p1 > p2)
{
ch = *p1;
*p1 = *p2;
*p2 = ch;
p2++;
p1--;
}
}
*String = '\0';
return String;
} // UlULongLongToAscii
NTSTATUS
_RtlIntegerToUnicode(
IN ULONG Value,
IN ULONG Base OPTIONAL,
IN LONG BufferLength,
OUT PWSTR String
)
{
PWSTR p1;
PWSTR p2;
WCHAR ch;
ULONG digit;
UNREFERENCED_PARAMETER(Base);
UNREFERENCED_PARAMETER(BufferLength);
//
// Special case 0 to make the rest of the routine simpler.
//
if (Value == 0)
{
*String++ = L'0';
}
else
{
//
// Convert the ULONG. Note that this will result in the string
// being backwards in memory.
//
p1 = String;
p2 = String;
while (Value != 0)
{
digit = (ULONG)( Value % 10 );
Value = Value / 10;
*p1++ = L'0' + (WCHAR)digit;
}
//
// Reverse the string.
//
String = p1;
p1--;
while (p1 > p2)
{
ch = *p1;
*p1 = *p2;
*p2 = ch;
p2++;
p1--;
}
}
*String = L'\0';
return STATUS_SUCCESS;
} // _RtlIntegerToUnicode
/***************************************************************************++
Routine Description:
Synchronously issues a device control request to the TDI provider.
Arguments:
pTdiObject - Supplies a pointer to the TDI object.
pIrpParameters - Supplies a pointer to the IRP parameters.
IrpParametersLength - Supplies the length of pIrpParameters.
pMdlBuffer - Optionally supplies a pointer to a buffer to be mapped
into a MDL and placed in the MdlAddress field of the IRP.
MdlBufferLength - Optionally supplies the length of pMdlBuffer.
MinorFunction - Supplies the minor function code of the request.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlIssueDeviceControl(
IN PUX_TDI_OBJECT pTdiObject,
IN PVOID pIrpParameters,
IN ULONG IrpParametersLength,
IN PVOID pMdlBuffer OPTIONAL,
IN ULONG MdlBufferLength OPTIONAL,
IN UCHAR MinorFunction
)
{
NTSTATUS status;
PIRP pIrp;
PIO_STACK_LOCATION pIrpSp;
UL_STATUS_BLOCK ulStatus;
IO_STATUS_BLOCK UserIosb;
PMDL pMdl;
//
// Sanity check.
//
PAGED_CODE();
//
// Initialize the event that will signal I/O completion.
//
UlInitializeStatusBlock( &ulStatus );
//
// Set the file object event to the non-signaled state.
//
KeResetEvent( &pTdiObject->pFileObject->Event );
//
// Allocate an IRP for the request.
//
pIrp = UlAllocateIrp(
pTdiObject->pDeviceObject->StackSize, // StackSize
FALSE // ChargeQuota
);
if (pIrp == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Initialize the User IO_STATUS_BLOCK
//
UserIosb.Information = 0;
UserIosb.Status = STATUS_SUCCESS;
//
// Establish the service independent parameters.
//
pIrp->Flags = IRP_SYNCHRONOUS_API;
pIrp->RequestorMode = KernelMode;
pIrp->PendingReturned = FALSE;
pIrp->UserIosb = &UserIosb;
pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
pIrp->Tail.Overlay.OriginalFileObject = pTdiObject->pFileObject;
//
// If we have a MDL buffer, allocate a new MDL and map the
// buffer into it.
//
if (pMdlBuffer != NULL)
{
pMdl = UlAllocateMdl(
pMdlBuffer, // VirtualAddress
MdlBufferLength, // Length
FALSE, // SecondaryBuffer
FALSE, // ChargeQuota
pIrp // Irp
);
if (pMdl == NULL)
{
UlFreeIrp( pIrp );
return STATUS_INSUFFICIENT_RESOURCES;
}
MmBuildMdlForNonPagedPool( pMdl );
}
else
{
pIrp->MdlAddress = NULL;
}
//
// Initialize the IRP stack location.
//
pIrpSp = IoGetNextIrpStackLocation( pIrp );
pIrpSp->FileObject = pTdiObject->pFileObject;
pIrpSp->DeviceObject = pTdiObject->pDeviceObject;
ASSERT( IrpParametersLength <= sizeof(pIrpSp->Parameters) );
RtlCopyMemory(
&pIrpSp->Parameters,
pIrpParameters,
IrpParametersLength
);
pIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
pIrpSp->MinorFunction = MinorFunction;
//
// Reference the file object.
//
ObReferenceObject( pTdiObject->pFileObject );
//
// Establish a completion routine to free the MDL and dereference
// the FILE_OBJECT.
//
IoSetCompletionRoutine(
pIrp, // Irp
&UlpRestartDeviceControl, // CompletionRoutine
&ulStatus, // Context
TRUE, // InvokeOnSuccess
TRUE, // InvokeOnError
TRUE // InvokeOnCancel
);
//
// Issue the request.
//
status = UlCallDriver( pTdiObject->pDeviceObject, pIrp );
//
// If necessary, wait for the request to complete and snag the
// final completion status.
//
if (status == STATUS_PENDING)
{
UlWaitForStatusBlockEvent( &ulStatus );
status = ulStatus.IoStatus.Status;
}
return status;
} // UlIssueDeviceControl
/***************************************************************************++
Routine Description:
Allocates the pool necessary for a new UL_RECEIVE_BUFFER structure and
initializes the structure.
Arguments:
IrpStackSize - Supplies the IrpStackSize.
Return Value:
PVOID - Pointer to the newly allocated block if successful, FALSE
otherwise.
--***************************************************************************/
PVOID
UlAllocateReceiveBuffer(
IN CCHAR IrpStackSize
)
{
PUL_RECEIVE_BUFFER pBuffer;
SIZE_T irpLength;
SIZE_T mdlLength;
SIZE_T ExtraLength;
//
// Calculate the required length of the buffer & allocate it.
//
irpLength = IoSizeOfIrp( IrpStackSize );
irpLength = ALIGN_UP( irpLength, PVOID );
mdlLength = MmSizeOfMdl( (PVOID)(PAGE_SIZE - 1), g_UlReceiveBufferSize );
mdlLength = ALIGN_UP( mdlLength, PVOID );
ExtraLength = irpLength + (mdlLength*2) + g_UlReceiveBufferSize;
ASSERT( ( ExtraLength & (sizeof(PVOID) - 1) ) == 0 );
pBuffer = UL_ALLOCATE_STRUCT_WITH_SPACE(
NonPagedPool,
UL_RECEIVE_BUFFER,
ExtraLength,
UL_RCV_BUFFER_POOL_TAG
);
if (pBuffer != NULL)
{
PUCHAR pRawBuffer = (PUCHAR)(pBuffer);
//
// Initialize the IRP, MDL, and data pointers within the buffer.
//
pBuffer->Signature = UL_RECEIVE_BUFFER_SIGNATURE_X;
pRawBuffer += ALIGN_UP( sizeof(UL_RECEIVE_BUFFER), PVOID );
pBuffer->pIrp = (PIRP)pRawBuffer;
pRawBuffer += irpLength;
pBuffer->pMdl = (PMDL)pRawBuffer;
pRawBuffer += mdlLength;
pBuffer->pPartialMdl = (PMDL)pRawBuffer;
pRawBuffer += mdlLength;
pBuffer->pDataArea = (PVOID)pRawBuffer;
pBuffer->UnreadDataLength = 0;
//
// Initialize the IRP.
//
IoInitializeIrp(
pBuffer->pIrp, // Irp
(USHORT)irpLength, // PacketSize
IrpStackSize // StackSize
);
//
// Initialize the primary MDL.
//
MmInitializeMdl(
pBuffer->pMdl, // MemoryDescriptorList
pBuffer->pDataArea, // BaseVa
g_UlReceiveBufferSize // Length
);
MmBuildMdlForNonPagedPool( pBuffer->pMdl );
}
return (PVOID)pBuffer;
} // UlAllocateReceiveBuffer
/***************************************************************************++
Routine Description:
Allocates the pool necessary for a new UL_RECEIVE_BUFFER structure and
initializes the structure.
Arguments:
PoolType - Supplies the type of pool to allocate. This must always
be NonPagedPool.
ByteLength - Supplies the byte length for the allocation request.
This should be sizeof(UL_RECEIVE_BUFFER), but is basically ignored.
Tag - Supplies the tag to use for the pool. This should be
UL_RCV_BUFFER_POOL_TAG, but is basically ignored.
Note: These parameters are required so that this function has a
signature identical to ExAllocatePoolWithTag.
Return Value:
PVOID - Pointer to the newly allocated block if successful, FALSE
otherwise.
--***************************************************************************/
PVOID
UlAllocateReceiveBufferPool(
IN POOL_TYPE PoolType,
IN SIZE_T ByteLength,
IN ULONG Tag
)
{
UNREFERENCED_PARAMETER(PoolType);
UNREFERENCED_PARAMETER(ByteLength);
UNREFERENCED_PARAMETER(Tag);
//
// Sanity check.
//
ASSERT( PoolType == NonPagedPool );
ASSERT( ByteLength == sizeof(UL_RECEIVE_BUFFER) );
ASSERT( Tag == UL_RCV_BUFFER_POOL_TAG );
return UlAllocateReceiveBuffer( DEFAULT_IRP_STACK_SIZE );
} // UlAllocateReceiveBufferPool
/***************************************************************************++
Routine Description:
Frees the pool allocated for a UL_RECEIVE_BUFFER structure.
Arguments:
pBuffer - Supplies the buffer to free.
--***************************************************************************/
VOID
UlFreeReceiveBufferPool(
IN PVOID pBuffer
)
{
PUL_RECEIVE_BUFFER pReceiveBuffer;
pReceiveBuffer = (PUL_RECEIVE_BUFFER)pBuffer;
ASSERT(pReceiveBuffer->Signature == UL_RECEIVE_BUFFER_SIGNATURE_X);
UL_FREE_POOL( pReceiveBuffer, UL_RCV_BUFFER_POOL_TAG );
} // UlFreeReceiveBufferPool
/***************************************************************************++
Routine Description:
Allocates the pool necessary for a new UL_IRP_CONTEXT structure and
initializes the structure.
Arguments:
PoolType - Supplies the type of pool to allocate. This must always
be NonPagedPool.
ByteLength - Supplies the byte length for the allocation request.
This should be sizeof(UL_IRP_CONTEXT), but is basically ignored.
Tag - Supplies the tag to use for the pool. This should be
UL_IRP_CONTEXT_POOL_TAG, but is basically ignored.
Note: These parameters are required so that this function has a
signature identical to ExAllocatePoolWithTag.
Return Value:
PVOID - Pointer to the newly allocated block if successful, FALSE
otherwise.
--***************************************************************************/
PVOID
UlAllocateIrpContextPool(
IN POOL_TYPE PoolType,
IN SIZE_T ByteLength,
IN ULONG Tag
)
{
PUL_IRP_CONTEXT pIrpContext;
UNREFERENCED_PARAMETER(PoolType);
UNREFERENCED_PARAMETER(ByteLength);
UNREFERENCED_PARAMETER(Tag);
//
// Sanity check.
//
ASSERT( PoolType == NonPagedPool );
ASSERT( ByteLength == sizeof(UL_IRP_CONTEXT) );
ASSERT( Tag == UL_IRP_CONTEXT_POOL_TAG );
//
// Allocate the IRP context.
//
pIrpContext = UL_ALLOCATE_STRUCT(
NonPagedPool,
UL_IRP_CONTEXT,
UL_IRP_CONTEXT_POOL_TAG
);
if (pIrpContext != NULL)
{
//
// Initialize it.
//
pIrpContext->Signature = UL_IRP_CONTEXT_SIGNATURE_X;
#if DBG
pIrpContext->pCompletionRoutine = &UlDbgInvalidCompletionRoutine;
#endif
}
return (PVOID)pIrpContext;
} // UlAllocateIrpContextPool
/***************************************************************************++
Routine Description:
Frees the pool allocated for a UL_IRP_CONTEXT structure.
Arguments:
pBuffer - Supplies the buffer to free.
--***************************************************************************/
VOID
UlFreeIrpContextPool(
IN PVOID pBuffer
)
{
PUL_IRP_CONTEXT pIrpContext;
pIrpContext = (PUL_IRP_CONTEXT)pBuffer;
ASSERT(pIrpContext->Signature == UL_IRP_CONTEXT_SIGNATURE_X);
UL_FREE_POOL( pIrpContext, UL_IRP_CONTEXT_POOL_TAG );
} // UlFreeIrpContextPool
/***************************************************************************++
Routine Description:
Allocates the pool necessary for a new UL_REQUEST_BUFFER structure and
initializes the structure.
Arguments:
PoolType - Supplies the type of pool to allocate. This must always
be NonPagedPool.
ByteLength - Supplies the byte length for the allocation request.
This should be DEFAULT_MAX_REQUEST_BUFFER_SIZE but is basically
ignored.
Tag - Supplies the tag to use for the pool. This should be
UL_REQUEST_BUFFER_POOL_TAG, but is basically ignored.
Note: These parameters are required so that this function has a
signature identical to ExAllocatePoolWithTag.
Return Value:
PVOID - Pointer to the newly allocated block if successful, FALSE
otherwise.
--***************************************************************************/
PVOID
UlAllocateRequestBufferPool(
IN POOL_TYPE PoolType,
IN SIZE_T ByteLength,
IN ULONG Tag
)
{
PUL_REQUEST_BUFFER pRequestBuffer;
UNREFERENCED_PARAMETER(PoolType);
UNREFERENCED_PARAMETER(ByteLength);
UNREFERENCED_PARAMETER(Tag);
//
// Sanity check.
//
ASSERT( PoolType == NonPagedPool );
ASSERT( ByteLength == DEFAULT_MAX_REQUEST_BUFFER_SIZE );
ASSERT( Tag == UL_REQUEST_BUFFER_POOL_TAG );
//
// Allocate the request buffer.
//
pRequestBuffer = UL_ALLOCATE_STRUCT_WITH_SPACE(
NonPagedPool,
UL_REQUEST_BUFFER,
DEFAULT_MAX_REQUEST_BUFFER_SIZE,
UL_REQUEST_BUFFER_POOL_TAG
);
if (pRequestBuffer != NULL)
{
//
// Initialize it.
//
pRequestBuffer->Signature = MAKE_FREE_TAG(UL_REQUEST_BUFFER_POOL_TAG);
}
return (PVOID)pRequestBuffer;
} // UlAllocateRequestBufferPool
/***************************************************************************++
Routine Description:
Frees the pool allocated for a UL_REQUEST_BUFFER structure.
Arguments:
pBuffer - Supplies the buffer to free.
--***************************************************************************/
VOID
UlFreeRequestBufferPool(
IN PVOID pBuffer
)
{
PUL_REQUEST_BUFFER pRequestBuffer;
pRequestBuffer = (PUL_REQUEST_BUFFER)pBuffer;
ASSERT(pRequestBuffer->Signature == MAKE_FREE_TAG(UL_REQUEST_BUFFER_POOL_TAG));
UL_FREE_POOL_WITH_SIG(pRequestBuffer, UL_REQUEST_BUFFER_POOL_TAG);
} // UlFreeRequestBufferPool
/***************************************************************************++
Routine Description:
Allocates the pool necessary for a new UL_INTERNAL_REQUEST structure and
initializes the structure.
Arguments:
PoolType - Supplies the type of pool to allocate. This must always
be NonPagedPool.
ByteLength - Supplies the byte length for the allocation request.
This should be sizeof(UL_INTERNAL_REQUEST) but is basically ignored.
Tag - Supplies the tag to use for the pool. This should be
UL_INTERNAL_REQUEST_POOL_TAG, but is basically ignored.
Note: These parameters are required so that this function has a
signature identical to ExAllocatePoolWithTag.
Return Value:
PVOID - Pointer to the newly allocated block if successful, FALSE
otherwise.
--***************************************************************************/
PVOID
UlAllocateInternalRequestPool(
IN POOL_TYPE PoolType,
IN SIZE_T ByteLength,
IN ULONG Tag
)
{
PUL_INTERNAL_REQUEST pRequest;
PUL_FULL_TRACKER pTracker;
ULONG SpaceLength;
ULONG UrlBufferSize;
UNREFERENCED_PARAMETER(PoolType);
UNREFERENCED_PARAMETER(ByteLength);
UNREFERENCED_PARAMETER(Tag);
//
// Sanity check.
//
ASSERT( PoolType == NonPagedPool );
ASSERT( ByteLength == sizeof(UL_INTERNAL_REQUEST) );
ASSERT( Tag == UL_INTERNAL_REQUEST_POOL_TAG );
//
// Allocate the request buffer plus the default cooked URL buffer and
// the full tracker plus the auxiliary buffer.
//
ASSERT( (g_UlMaxInternalUrlLength & (sizeof(WCHAR) - 1)) == 0);
UrlBufferSize = g_UlMaxInternalUrlLength + sizeof(WCHAR);
SpaceLength = g_UlFullTrackerSize + UrlBufferSize +
DEFAULT_MAX_ROUTING_TOKEN_LENGTH;
pRequest = UL_ALLOCATE_STRUCT_WITH_SPACE(
NonPagedPool,
UL_INTERNAL_REQUEST,
SpaceLength,
UL_INTERNAL_REQUEST_POOL_TAG
);
if (pRequest != NULL)
{
pRequest->pTracker =
(PUL_FULL_TRACKER)((PCHAR)pRequest +
ALIGN_UP(sizeof(UL_INTERNAL_REQUEST), PVOID));
pRequest->pUrlBuffer =
(PWSTR)((PCHAR)pRequest->pTracker + g_UlFullTrackerSize);
pRequest->pDefaultRoutingTokenBuffer =
(PWSTR)((PCHAR)pRequest->pUrlBuffer + UrlBufferSize);
//
// Initialize the Request structure
//
INIT_HTTP_REQUEST( pRequest );
pRequest->Signature = MAKE_FREE_TAG(UL_INTERNAL_REQUEST_POOL_TAG);
//
// Initialize the fast/cache tracker.
//
pTracker = pRequest->pTracker;
pTracker->Signature = UL_FULL_TRACKER_POOL_TAG;
pTracker->IrpContext.Signature = UL_IRP_CONTEXT_SIGNATURE;
pTracker->FromLookaside = FALSE;
pTracker->FromRequest = TRUE;
pTracker->ResponseStatusCode = 0;
pTracker->AuxilaryBufferLength =
g_UlMaxFixedHeaderSize +
g_UlMaxVariableHeaderSize +
g_UlMaxCopyThreshold;
UlInitializeFullTrackerPool( pTracker, DEFAULT_MAX_IRP_STACK_SIZE );
}
return (PVOID)pRequest;
} // UlAllocateInternalRequestPool
/***************************************************************************++
Routine Description:
Frees the pool allocated for a UL_INTERNAL_REQUEST structure.
Arguments:
pBuffer - Supplies the buffer to free.
--***************************************************************************/
VOID
UlFreeInternalRequestPool(
IN PVOID pBuffer
)
{
PUL_INTERNAL_REQUEST pRequest;
pRequest = (PUL_INTERNAL_REQUEST)pBuffer;
ASSERT(pRequest->Signature == MAKE_FREE_TAG(UL_INTERNAL_REQUEST_POOL_TAG));
UL_FREE_POOL_WITH_SIG( pRequest, UL_INTERNAL_REQUEST_POOL_TAG );
} // UlFreeInternalRequestPool
/***************************************************************************++
Routine Description:
Allocates the pool necessary for a new UL_CHUNK_TRACKER structure and
initializes the structure.
Arguments:
PoolType - Supplies the type of pool to allocate. This must always
be NonPagedPool.
ByteLength - Supplies the byte length for the allocation request.
This should be g_UlChunkTrackerSize but is basically ignored.
Tag - Supplies the tag to use for the pool. This should be
UL_CHUNK_TRACKER_POOL_TAG, but is basically ignored.
Note: These parameters are required so that this function has a
signature identical to ExAllocatePoolWithTag.
Return Value:
PVOID - Pointer to the newly allocated block if successful, FALSE
otherwise.
--***************************************************************************/
PVOID
UlAllocateChunkTrackerPool(
IN POOL_TYPE PoolType,
IN SIZE_T ByteLength,
IN ULONG Tag
)
{
PUL_CHUNK_TRACKER pTracker;
UNREFERENCED_PARAMETER(PoolType);
UNREFERENCED_PARAMETER(ByteLength);
UNREFERENCED_PARAMETER(Tag);
//
// Sanity check.
//
ASSERT( PoolType == NonPagedPool );
ASSERT( ByteLength == g_UlChunkTrackerSize );
ASSERT( Tag == UL_CHUNK_TRACKER_POOL_TAG );
//
// Allocate the tracker buffer.
//
pTracker = (PUL_CHUNK_TRACKER)UL_ALLOCATE_POOL(
NonPagedPool,
g_UlChunkTrackerSize,
UL_CHUNK_TRACKER_POOL_TAG
);
if (pTracker != NULL)
{
pTracker->Signature = MAKE_FREE_TAG(UL_CHUNK_TRACKER_POOL_TAG);
pTracker->IrpContext.Signature = UL_IRP_CONTEXT_SIGNATURE;
pTracker->FromLookaside = TRUE;
//
// Set up the IRP.
//
pTracker->pIrp =
(PIRP)((PCHAR)pTracker +
ALIGN_UP(sizeof(UL_CHUNK_TRACKER), PVOID));
IoInitializeIrp(
pTracker->pIrp,
IoSizeOfIrp(DEFAULT_MAX_IRP_STACK_SIZE),
DEFAULT_MAX_IRP_STACK_SIZE
);
}
return pTracker;
} // UlAllocateChunkTrackerPool
/***************************************************************************++
Routine Description:
Frees the pool allocated for a UL_CHUNK_TRACKER structure.
Arguments:
pBuffer - Supplies the buffer to free.
--***************************************************************************/
VOID
UlFreeChunkTrackerPool(
IN PVOID pBuffer
)
{
PUL_CHUNK_TRACKER pTracker = (PUL_CHUNK_TRACKER)pBuffer;
ASSERT(pTracker->Signature == MAKE_FREE_TAG(UL_CHUNK_TRACKER_POOL_TAG));
UL_FREE_POOL_WITH_SIG( pTracker, UL_CHUNK_TRACKER_POOL_TAG );
} // UlFreeChunkTrackerPool
/***************************************************************************++
Routine Description:
Allocates the pool necessary for a new UL_FULL_TRACKER structure and
initializes the structure.
Arguments:
PoolType - Supplies the type of pool to allocate. This must always
be NonPagedPool.
ByteLength - Supplies the byte length for the allocation request.
This should be g_UlFullTrackerSize but is basically ignored.
Tag - Supplies the tag to use for the pool. This should be
UL_FULL_TRACKER_POOL_TAG, but is basically ignored.
Note: These parameters are required so that this function has a
signature identical to ExAllocatePoolWithTag.
Return Value:
PVOID - Pointer to the newly allocated block if successful, FALSE
otherwise.
--***************************************************************************/
PVOID
UlAllocateFullTrackerPool(
IN POOL_TYPE PoolType,
IN SIZE_T ByteLength,
IN ULONG Tag
)
{
PUL_FULL_TRACKER pTracker;
UNREFERENCED_PARAMETER(PoolType);
UNREFERENCED_PARAMETER(ByteLength);
UNREFERENCED_PARAMETER(Tag);
//
// Sanity check.
//
ASSERT( PoolType == NonPagedPool );
ASSERT( ByteLength == g_UlFullTrackerSize );
ASSERT( Tag == UL_FULL_TRACKER_POOL_TAG );
//
// Allocate the tracker buffer.
//
pTracker = (PUL_FULL_TRACKER)UL_ALLOCATE_POOL(
NonPagedPool,
g_UlFullTrackerSize,
UL_FULL_TRACKER_POOL_TAG
);
if (pTracker != NULL)
{
pTracker->Signature = MAKE_FREE_TAG(UL_FULL_TRACKER_POOL_TAG);
pTracker->IrpContext.Signature = UL_IRP_CONTEXT_SIGNATURE;
pTracker->FromLookaside = TRUE;
pTracker->FromRequest = FALSE;
pTracker->AuxilaryBufferLength =
g_UlMaxFixedHeaderSize +
g_UlMaxVariableHeaderSize +
g_UlMaxCopyThreshold;
UlInitializeFullTrackerPool( pTracker, DEFAULT_MAX_IRP_STACK_SIZE );
}
return pTracker;
} // UlAllocateFullTrackerPool
/***************************************************************************++
Routine Description:
Frees the pool allocated for a UL_FULL_TRACKER structure.
Arguments:
pBuffer - Supplies the buffer to free.
--***************************************************************************/
VOID
UlFreeFullTrackerPool(
IN PVOID pBuffer
)
{
PUL_FULL_TRACKER pTracker = (PUL_FULL_TRACKER)pBuffer;
ASSERT(pTracker->Signature == MAKE_FREE_TAG(UL_FULL_TRACKER_POOL_TAG));
UL_FREE_POOL_WITH_SIG( pTracker, UL_FULL_TRACKER_POOL_TAG );
} // UlFreeFullTrackerPool
/***************************************************************************++
Routine Description:
Allocates the pool necessary for a new UL_INTERNAL_RESPONSE structure and
initializes the structure.
Arguments:
PoolType - Supplies the type of pool to allocate. This must always
be NonPagedPool.
ByteLength - Supplies the byte length for the allocation request.
This should be g_UlResponseBufferSize but is basically ignored.
Tag - Supplies the tag to use for the pool. This should be
UL_INTERNAL_RESPONSE_POOL_TAG, but is basically ignored.
Note: These parameters are required so that this function has a
signature identical to ExAllocatePoolWithTag.
Return Value:
PVOID - Pointer to the newly allocated block if successful, FALSE
otherwise.
--***************************************************************************/
PVOID
UlAllocateResponseBufferPool(
IN POOL_TYPE PoolType,
IN SIZE_T ByteLength,
IN ULONG Tag
)
{
PUL_INTERNAL_RESPONSE pResponseBuffer;
UNREFERENCED_PARAMETER(PoolType);
UNREFERENCED_PARAMETER(ByteLength);
UNREFERENCED_PARAMETER(Tag);
//
// Sanity check.
//
ASSERT( PoolType == NonPagedPool );
ASSERT( ByteLength == g_UlResponseBufferSize );
ASSERT( Tag == UL_INTERNAL_RESPONSE_POOL_TAG );
//
// Allocate the default internal response buffer.
//
pResponseBuffer = (PUL_INTERNAL_RESPONSE)UL_ALLOCATE_POOL(
NonPagedPool,
g_UlResponseBufferSize,
UL_INTERNAL_RESPONSE_POOL_TAG
);
if (pResponseBuffer != NULL)
{
//
// Initialize it.
//
pResponseBuffer->Signature = MAKE_FREE_TAG(UL_INTERNAL_RESPONSE_POOL_TAG);
}
return (PVOID)pResponseBuffer;
} // UlAllocateResponseBufferPool
/***************************************************************************++
Routine Description:
Frees the pool allocated for a UL_INTERNAL_RESPONSE structure.
Arguments:
pBuffer - Supplies the buffer to free.
--***************************************************************************/
VOID
UlFreeResponseBufferPool(
IN PVOID pBuffer
)
{
PUL_INTERNAL_RESPONSE pResponseBuffer;
pResponseBuffer = (PUL_INTERNAL_RESPONSE)pBuffer;
UL_FREE_POOL_WITH_SIG( pResponseBuffer, UL_INTERNAL_RESPONSE_POOL_TAG );
} // UlFreeResponseBufferPool
/***************************************************************************++
Routine Description:
Allocates the pool necessary for a new UL_FILE_LOG_BUFFER structure and
initializes the structure.
Arguments:
PoolType - Supplies the type of pool to allocate. This must always
be PagedPool.
ByteLength - Supplies the byte length for the allocation request.
This should be sizeof(UL_LOG_FILE_BUFFER) but is basically ignored.
Tag - Supplies the tag to use for the pool. This should be
UL_LOG_FILE_BUFFER_POOL_TAG, but is basically ignored.
Note: These parameters are required so that this function has a
signature identical to ExAllocatePoolWithTag.
Return Value:
PVOID - Pointer to the newly allocated block if successful, FALSE
otherwise.
--***************************************************************************/
PVOID
UlAllocateLogFileBufferPool(
IN POOL_TYPE PoolType,
IN SIZE_T ByteLength,
IN ULONG Tag
)
{
PUL_LOG_FILE_BUFFER pLogBuffer;
UNREFERENCED_PARAMETER(PoolType);
UNREFERENCED_PARAMETER(ByteLength);
UNREFERENCED_PARAMETER(Tag);
//
// Sanity check.
//
ASSERT( PoolType == NonPagedPool );
ASSERT( ByteLength == sizeof(UL_LOG_FILE_BUFFER) );
ASSERT( Tag == UL_LOG_FILE_BUFFER_POOL_TAG );
//
// Allocate the default log buffer.
//
pLogBuffer = UL_ALLOCATE_STRUCT_WITH_SPACE(
PagedPool,
UL_LOG_FILE_BUFFER,
g_UlLogBufferSize,
UL_LOG_FILE_BUFFER_POOL_TAG
);
if ( pLogBuffer != NULL )
{
pLogBuffer->Signature = MAKE_FREE_TAG(UL_LOG_FILE_BUFFER_POOL_TAG);
pLogBuffer->BufferUsed = 0;
pLogBuffer->Buffer = (PUCHAR) (pLogBuffer + 1);
}
return pLogBuffer;
} // UlAllocateLogFileBufferPool
/***************************************************************************++
Routine Description:
Frees the pool allocated for a UL_LOG_FILE_BUFFER structure.
Arguments:
pBuffer - Supplies the buffer to free.
--***************************************************************************/
VOID
UlFreeLogFileBufferPool(
IN PVOID pBuffer
)
{
PUL_LOG_FILE_BUFFER pLogBuffer;
pLogBuffer = (PUL_LOG_FILE_BUFFER) pBuffer;
ASSERT(pLogBuffer->Signature == MAKE_FREE_TAG(UL_LOG_FILE_BUFFER_POOL_TAG));
UL_FREE_POOL_WITH_SIG( pLogBuffer, UL_LOG_FILE_BUFFER_POOL_TAG );
} // UlFreeLogFileBufferPool
/***************************************************************************++
Routine Description:
Allocates the pool necessary for a new UL_FILE_LOG_BUFFER structure and
initializes the structure.
Return Value:
PVOID - Pointer to the newly allocated block if successful, FALSE
otherwise.
--***************************************************************************/
PVOID
UlAllocateLogDataBufferPool(
IN POOL_TYPE PoolType,
IN SIZE_T ByteLength,
IN ULONG Tag
)
{
PUL_LOG_DATA_BUFFER pLogDataBuffer = NULL;
USHORT Size = UL_ANSI_LOG_LINE_BUFFER_SIZE;
BOOLEAN Binary = FALSE;
UNREFERENCED_PARAMETER(PoolType);
UNREFERENCED_PARAMETER(ByteLength);
//
// We understand what type of buffer is asked, by looking at the tag.
//
ASSERT(ByteLength ==
(sizeof(UL_LOG_DATA_BUFFER) + UL_ANSI_LOG_LINE_BUFFER_SIZE) ||
ByteLength ==
(sizeof(UL_LOG_DATA_BUFFER) + UL_BINARY_LOG_LINE_BUFFER_SIZE)
);
ASSERT(PoolType == NonPagedPool );
ASSERT(Tag == UL_BINARY_LOG_DATA_BUFFER_POOL_TAG ||
Tag == UL_ANSI_LOG_DATA_BUFFER_POOL_TAG );
if (Tag == UL_BINARY_LOG_DATA_BUFFER_POOL_TAG)
{
Binary = TRUE;
Size = UL_BINARY_LOG_LINE_BUFFER_SIZE;
}
pLogDataBuffer =
UL_ALLOCATE_STRUCT_WITH_SPACE(
NonPagedPool,
UL_LOG_DATA_BUFFER,
Size,
Tag
);
if ( pLogDataBuffer != NULL )
{
pLogDataBuffer->Signature = MAKE_FREE_TAG(Tag);
pLogDataBuffer->Used = 0;
pLogDataBuffer->Size = Size;
pLogDataBuffer->Line = (PUCHAR) (pLogDataBuffer + 1);
pLogDataBuffer->Flags.Value = 0;
pLogDataBuffer->Flags.IsFromLookaside = 1;
if (Binary)
{
pLogDataBuffer->Flags.Binary = 1;
}
}
return pLogDataBuffer;
} // UlAllocateBinaryLogDataBufferPool
/***************************************************************************++
Routine Description:
Frees the pool allocated for a UL_LOG_DATA_BUFFER structure.
Arguments:
pBuffer - Supplies the buffer to free.
--***************************************************************************/
VOID
UlFreeLogDataBufferPool(
IN PVOID pBuffer
)
{
ULONG Tag;
PUL_LOG_DATA_BUFFER pLogDataBuffer;
pLogDataBuffer = (PUL_LOG_DATA_BUFFER) pBuffer;
if (pLogDataBuffer->Flags.Binary)
{
Tag = UL_BINARY_LOG_DATA_BUFFER_POOL_TAG;
}
else
{
Tag = UL_ANSI_LOG_DATA_BUFFER_POOL_TAG;
}
ASSERT(pLogDataBuffer->Signature == MAKE_FREE_TAG(Tag));
UL_FREE_POOL_WITH_SIG(
pLogDataBuffer,
Tag
);
} // UlFreeLogDataBufferPool
/***************************************************************************++
Routine Description:
Allocates the pool necessary for a new UL_ERROR_LOG_BUFFER structure and
initializes the structure.
Return Value:
PVOID - Pointer to the newly allocated block if successful, FALSE
otherwise.
--***************************************************************************/
PVOID
UlAllocateErrorLogBufferPool(
IN POOL_TYPE PoolType,
IN SIZE_T ByteLength,
IN ULONG Tag
)
{
PUL_ERROR_LOG_BUFFER pErrorLogBuffer = NULL;
UNREFERENCED_PARAMETER(PoolType);
UNREFERENCED_PARAMETER(ByteLength);
//
// We understand what type of buffer is asked, by looking at the tag.
//
ASSERT(ByteLength == UL_ERROR_LOG_BUFFER_SIZE);
ASSERT(PoolType == NonPagedPool );
ASSERT(Tag == UL_ERROR_LOG_BUFFER_POOL_TAG);
pErrorLogBuffer =
UL_ALLOCATE_STRUCT_WITH_SPACE(
NonPagedPool,
UL_ERROR_LOG_BUFFER,
UL_ERROR_LOG_BUFFER_SIZE,
Tag
);
if ( pErrorLogBuffer != NULL )
{
pErrorLogBuffer->Signature = MAKE_FREE_TAG(Tag);
pErrorLogBuffer->Used = 0;
pErrorLogBuffer->pBuffer = (PUCHAR) (pErrorLogBuffer + 1);
pErrorLogBuffer->IsFromLookaside = TRUE;
}
return pErrorLogBuffer;
} // UlAllocateErrorLogBufferPool
/***************************************************************************++
Routine Description:
Frees the pool allocated for a UL_ERROR_LOG_BUFFER structure.
Arguments:
pBuffer - Supplies the buffer to free.
--***************************************************************************/
VOID
UlFreeErrorLogBufferPool(
IN PVOID pBuffer
)
{
PUL_ERROR_LOG_BUFFER pErrorLogBuffer = (PUL_ERROR_LOG_BUFFER) pBuffer;
ASSERT(pErrorLogBuffer->Signature ==
MAKE_FREE_TAG(UL_ERROR_LOG_BUFFER_POOL_TAG));
UL_FREE_POOL_WITH_SIG(
pErrorLogBuffer,
UL_ERROR_LOG_BUFFER_POOL_TAG
);
} // UlFreeErrorLogBufferPool
//
// Private routines.
//
/***************************************************************************++
Routine Description:
Completion handler for device control IRPs.
Arguments:
pDeviceObject - Supplies the device object for the IRP being
completed.
pIrp - Supplies the IRP being completed.
pContext - Supplies the context associated with this request. In
this case, it's a pointer to a UL_STATUS_BLOCK structure.
Return Value:
NTSTATUS - STATUS_SUCCESS if IO should continue processing this
IRP, STATUS_MORE_PROCESSING_REQUIRED if IO should stop processing
this IRP.
--***************************************************************************/
NTSTATUS
UlpRestartDeviceControl(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp,
IN PVOID pContext
)
{
PUL_STATUS_BLOCK pStatus;
UNREFERENCED_PARAMETER(pDeviceObject);
//
// If we attached an MDL to the IRP, then free it here and reset
// the MDL pointer to NULL. IO can't handle a nonpaged MDL in an
// IRP, so we do it here.
//
if (pIrp->MdlAddress != NULL)
{
UlFreeMdl( pIrp->MdlAddress );
pIrp->MdlAddress = NULL;
}
//
// Complete the request.
//
pStatus = (PUL_STATUS_BLOCK)pContext;
UlSignalStatusBlock(
pStatus,
pIrp->IoStatus.Status,
pIrp->IoStatus.Information
);
//
// Tell IO to continue processing this IRP.
//
return STATUS_SUCCESS;
} // UlpRestartDeviceControl
/*++
Routine Description:
Routine to initialize the utilitu code.
Arguments:
Return Value:
--*/
NTSTATUS
InitializeHttpUtil(
VOID
)
{
ULONG i;
HttpCmnInitializeHttpCharsTable(g_UrlC14nConfig.EnableDbcs);
//
// Initialize base64 <--> binary conversion tables.
// N.B. - This initialization must be done at run-time and not
// compile-time.
//
for (i = 0; i < 256; i++)
{
Base64ToBinaryTable[i] = INVALID_BASE64_TO_BINARY_TABLE_ENTRY;
}
for (i = 0; i < 64; i++)
{
ASSERT(BinaryToBase64Table[i] < 256);
Base64ToBinaryTable[BinaryToBase64Table[i]] = (UCHAR)i;
}
return STATUS_SUCCESS;
} // InitializeHttpUtil
//
// constants used by the date formatter
//
const PCWSTR pDays[] =
{
L"Sun", L"Mon", L"Tue", L"Wed", L"Thu", L"Fri", L"Sat"
};
const PCWSTR pMonths[] =
{
L"Jan", L"Feb", L"Mar", L"Apr", L"May", L"Jun", L"Jul",
L"Aug", L"Sep", L"Oct", L"Nov", L"Dec"
};
__inline
VOID
TwoDigitsToUnicode(
PWSTR pBuffer,
ULONG Number
)
{
ASSERT(Number < 100);
pBuffer[0] = L'0' + (WCHAR)(Number / 10);
pBuffer[1] = L'0' + (WCHAR)(Number % 10);
}
/***************************************************************************++
Routine Description:
Converts the given system time to string representation containing
GMT Formatted String.
Arguments:
pTime - System time that needs to be converted.
pBuffer - pointer to string which will contain the GMT time on
successful return.
BufferLength - size of pszBuff in bytes
Return Value:
NTSTATUS
History:
MuraliK 3-Jan-1995
paulmcd 4-Mar-1999 copied to ul
--***************************************************************************/
NTSTATUS
TimeFieldsToHttpDate(
IN PTIME_FIELDS pTime,
OUT PWSTR pBuffer,
IN ULONG BufferLength
)
{
NTSTATUS Status;
ASSERT(pBuffer != NULL);
if (BufferLength < (DATE_HDR_LENGTH + 1) * sizeof(WCHAR))
{
return STATUS_BUFFER_TOO_SMALL;
}
// 0 1 2
// 01234567890123456789012345678
// Formats a string like: "Thu, 14 Jul 1994 15:26:05 GMT"
//
//
// write the constants
//
pBuffer[3] = L',';
pBuffer[4] = pBuffer[7] = pBuffer[11] = L' ';
pBuffer[19] = pBuffer[22] = L':';
//
// now the variants
//
//
// 0-based Weekday
//
RtlCopyMemory(&(pBuffer[0]), pDays[pTime->Weekday], 3*sizeof(WCHAR));
TwoDigitsToUnicode(&(pBuffer[5]), pTime->Day);
//
// 1-based Month
//
RtlCopyMemory(&(pBuffer[8]), pMonths[pTime->Month - 1], 3*sizeof(WCHAR)); // 1-based
Status = _RtlIntegerToUnicode(pTime->Year, 10, 5, &(pBuffer[12]));
ASSERT(NT_SUCCESS(Status));
pBuffer[16] = L' ';
TwoDigitsToUnicode(&(pBuffer[17]), pTime->Hour);
TwoDigitsToUnicode(&(pBuffer[20]), pTime->Minute);
TwoDigitsToUnicode(&(pBuffer[23]), pTime->Second);
RtlCopyMemory(&(pBuffer[25]), L" GMT", sizeof(L" GMT"));
return STATUS_SUCCESS;
} // TimeFieldsToHttpDate
__inline
SHORT
AsciiToShort(
PCHAR pString
)
{
return (SHORT)atoi(pString);
}
__inline
SHORT
TwoAsciisToShort(
PCHAR pString
)
{
SHORT Value;
SHORT Number;
Number = pString[1] - '0';
if (Number <= 9)
{
Value = Number;
Number = pString[0] - '0';
if (Number <= 9)
{
Value += Number * 10;
return Value;
}
}
return 0;
}
/***************************************************************************++
DateTime function ported from user mode W3SVC
--***************************************************************************/
/************************************************************
* Data
************************************************************/
static const PSTR s_rgchMonths[] = {
"Jan", "Feb", "Mar", "Apr",
"May", "Jun", "Jul", "Aug",
"Sep", "Oct", "Nov", "Dec"
};
// Custom hash table for NumericToAsciiMonth() for mapping "Apr" to 4
static const CHAR MonthIndexTable[64] = {
-1,'A', 2, 12, -1, -1, -1, 8, // A to G
-1, -1, -1, -1, 7, -1,'N', -1, // F to O
9, -1,'R', -1, 10, -1, 11, -1, // P to W
-1, 5, -1, -1, -1, -1, -1, -1, // X to Z
-1,'A', 2, 12, -1, -1, -1, 8, // a to g
-1, -1, -1, -1, 7, -1,'N', -1, // f to o
9, -1,'R', -1, 10, -1, 11, -1, // p to w
-1, 5, -1, -1, -1, -1, -1, -1 // x to z
};
/************************************************************
* Functions
************************************************************/
/***************************************************************************++
Converts three letters of a month to numeric month
Arguments:
s String to convert
Returns:
numeric equivalent, 0 on failure.
--***************************************************************************/
__inline
SHORT
NumericToAsciiMonth(
PCHAR s
)
{
UCHAR monthIndex;
UCHAR c;
PSTR monthString;
//
// use the third character as the index
//
c = (s[2] - 0x40) & 0x3F;
monthIndex = MonthIndexTable[c];
if ( monthIndex < 13 ) {
goto verify;
}
//
// ok, we need to look at the second character
//
if ( monthIndex == 'N' ) {
//
// we got an N which we need to resolve further
//
//
// if s[1] is 'u' then Jun, if 'a' then Jan
//
if ( MonthIndexTable[(s[1]-0x40) & 0x3f] == 'A' ) {
monthIndex = 1;
} else {
monthIndex = 6;
}
} else if ( monthIndex == 'R' ) {
//
// if s[1] is 'a' then March, if 'p' then April
//
if ( MonthIndexTable[(s[1]-0x40) & 0x3f] == 'A' ) {
monthIndex = 3;
} else {
monthIndex = 4;
}
} else {
goto error_exit;
}
verify:
monthString = (PSTR) s_rgchMonths[monthIndex-1];
if ( (s[0] == monthString[0]) &&
(s[1] == monthString[1]) &&
(s[2] == monthString[2]) ) {
return(monthIndex);
} else if ( (toupper(s[0]) == monthString[0]) &&
(tolower(s[1]) == monthString[1]) &&
(tolower(s[2]) == monthString[2]) ) {
return monthIndex;
}
error_exit:
return(0);
} // NumericToAsciiMonth
/***************************************************************************++
Converts a string representation of a GMT time (three different
varieties) to an NT representation of a file time.
We handle the following variations:
Sun, 06 Nov 1994 08:49:37 GMT (RFC 822 updated by RFC 1123)
Sunday, 06-Nov-94 08:49:37 GMT (RFC 850)
Sun Nov 6 08:49:37 1994 (ANSI C's asctime() format)
Arguments:
pTimeString String representation of time field
TimeStringLength Length of the string representation of time field
pTime Large integer containing the time in NT format
Returns:
TRUE on success and FALSE on failure.
History:
Johnl 24-Jan-1995 Modified from WWW library
ericsten 30-Nov-2000 Ported from user-mode W3SVC
--***************************************************************************/
BOOLEAN
StringTimeToSystemTime(
IN PCSTR pTimeString,
IN USHORT TimeStringLength,
OUT LARGE_INTEGER *pTime
)
{
PSTR pString;
TIME_FIELDS Fields;
USHORT Length;
if (NULL == pTimeString)
{
return FALSE;
}
Fields.Milliseconds = 0;
Length = 0;
while (Length < TimeStringLength && ',' != pTimeString[Length])
{
Length++;
}
if (Length < TimeStringLength)
{
//
// Thursday, 10-Jun-93 01:29:59 GMT
// or: Thu, 10 Jan 1993 01:29:59 GMT
//
Length++;
pString = (PSTR) &pTimeString[Length];
while (Length < TimeStringLength && ' ' == *pString)
{
Length++;
pString++;
}
if ((TimeStringLength - Length) < 18)
{
return FALSE;
}
if ('-' == *(pString + 2))
{
//
// First format: Thursday, 10-Jun-93 01:29:59 GMT
//
if ('-' == *(pString + 6) &&
' ' == *(pString + 9) &&
':' == *(pString + 12) &&
':' == *(pString + 15))
{
Fields.Day = AsciiToShort(pString);
Fields.Month = NumericToAsciiMonth(pString + 3);
Fields.Year = AsciiToShort(pString + 7);
Fields.Hour = AsciiToShort(pString + 10);
Fields.Minute = AsciiToShort(pString + 13);
Fields.Second = AsciiToShort(pString + 16);
}
else
{
return FALSE;
}
}
else
{
//
// Second format: Thu, 10 Jan 1993 01:29:59 GMT
//
if ((TimeStringLength - Length) < 20)
{
return FALSE;
}
if (' ' == *(pString + 2) &&
' ' == *(pString + 6) &&
' ' == *(pString + 11) &&
':' == *(pString + 14) &&
':' == *(pString + 17))
{
Fields.Day = TwoAsciisToShort(pString);
Fields.Month = NumericToAsciiMonth(pString + 3);
Fields.Year = TwoAsciisToShort(pString + 7) * 100 +
TwoAsciisToShort(pString + 9);
Fields.Hour = TwoAsciisToShort(pString + 12);
Fields.Minute = TwoAsciisToShort(pString + 15);
Fields.Second = TwoAsciisToShort(pString + 18);
}
else
{
return FALSE;
}
}
}
else
{
//
// Thu Jun 9 01:29:59 1993 GMT
//
Length = 0;
pString = (PSTR) pTimeString;
while (Length < TimeStringLength && ' ' == *pString)
{
Length++;
pString++;
}
if ((TimeStringLength - Length) < 24)
{
return FALSE;
}
if (' ' != *(pString + 3) ||
' ' != *(pString + 7) ||
' ' != *(pString + 10) ||
':' != *(pString + 13) ||
':' != *(pString + 16))
{
return FALSE;
}
if (isdigit(*(pString + 8)))
{
Fields.Day = AsciiToShort(pString + 8);
}
else
{
if (' ' != *(pString + 8))
{
return FALSE;
}
Fields.Day = AsciiToShort(pString + 9);
}
Fields.Month = NumericToAsciiMonth(pString + 4);
Fields.Year = AsciiToShort(pString + 20);
Fields.Hour = AsciiToShort(pString + 11);
Fields.Minute = AsciiToShort(pString + 14);
Fields.Second = AsciiToShort(pString + 17);
}
//
// Adjust for dates with only two digits
//
if (Fields.Year < 1000)
{
if (Fields.Year < 50)
{
Fields.Year += 2000;
}
else
{
Fields.Year += 1900;
}
}
return RtlTimeFieldsToTime(&Fields, pTime);
}
/***************************************************************************++
End of DateTime function ported from user mode W3SVC
--***************************************************************************/
/*++
Routine Description:
Search input list of ETags for one that matches our local ETag.
All strings must be NULL terminated (ANSI C strings).
Arguments:
pLocalETag - The local ETag we're using.
pETagList - The ETag list we've received from the client.
bWeakCompare - Whether using Weak Comparison is ok
Returns:
FIND_ETAG_STATUS value:
ETAG_FOUND - pLocalETag was found on the list
ETAG_NOT_FOUND - pLocalETag was NOT found on the list
ETAG_PARSE_ERROR - one (or more) elements on the list were invalid
Author:
Anil Ruia (AnilR) 3-Apr-2000
History:
Eric Stenson (EricSten) 6-Dec-2000 ported from user-mode
--*/
FIND_ETAG_STATUS
FindInETagList(
IN PUCHAR pLocalETag,
IN PUCHAR pETagList,
IN BOOLEAN fWeakCompare
)
{
ULONG QuoteCount;
PUCHAR pFileETag;
BOOLEAN Matched;
// We'll loop through the ETag string, looking for ETag to
// compare, as long as we have an ETag to look at.
do
{
while (IS_HTTP_LWS(*pETagList))
{
pETagList++;
}
if (!*pETagList)
{
// Ran out of ETag.
return ETAG_NOT_FOUND;
}
// If this ETag is *, it's a match.
if (*pETagList == '*')
{
return ETAG_FOUND;
}
// See if this ETag is weak.
if (pETagList[0] == 'W' && pETagList[1] == '/')
{
// This is a weak validator. If we're not doing the weak
// comparison, fail.
if (!fWeakCompare)
{
return ETAG_NOT_FOUND;
}
// Skip over the 'W/', and any intervening whitespace.
pETagList += 2;
while (IS_HTTP_LWS(*pETagList))
{
pETagList++;
}
if (!*pETagList)
{
// Ran out of ETag.
return ETAG_PARSE_ERROR;
}
}
if (*pETagList != '"')
{
// This isn't a quoted string, so fail.
return ETAG_PARSE_ERROR;
}
// OK, right now we should be at the start of a quoted string that
// we can compare against our current ETag.
QuoteCount = 0;
Matched = TRUE;
pFileETag = pLocalETag;
// Do the actual compare. We do this by scanning the current ETag,
// which is a quoted string. We look for two quotation marks, the
// the delimiters of the quoted string. If after we find two quotes
// in the ETag everything has matched, then we've matched this ETag.
// Otherwise we'll try the next one.
do
{
UCHAR Temp;
Temp = *pETagList;
if (IS_HTTP_CTL(Temp))
{
return ETAG_PARSE_ERROR;
}
if (Temp == '"')
{
QuoteCount++;
}
if (*pFileETag != Temp)
{
Matched = FALSE;
// at this point, we can skip the current
// ETag on the list.
break;
}
pETagList++;
if (*pFileETag == '\0')
{
break;
}
pFileETag++;
}
while (QuoteCount != 2);
if (Matched)
{
return ETAG_FOUND;
}
// Otherwise, at this point we need to look at the next ETag.
while (QuoteCount != 2)
{
if (*pETagList == '"')
{
QuoteCount++;
}
else
{
if (IS_HTTP_CTL(*pETagList))
{
return ETAG_PARSE_ERROR;
}
}
pETagList++;
}
while (IS_HTTP_LWS(*pETagList))
{
pETagList++;
}
if (*pETagList == ',')
{
pETagList++;
}
else
{
return ETAG_NOT_FOUND;
}
} while ( *pETagList );
return ETAG_NOT_FOUND;
} // FindInETagList
/*++
Routine Description:
Build a NULL-terminated ANSI string from the IP address
Arguments:
IpAddressString - String buffer to place the ANSI string
(caller allocated)
TdiAddress - TDI address to be converted
TdiAddressType - type of address at TdiAddress
Returns:
Count of bytes written into IpAddressString.
Not including the terminating null.
--*/
USHORT
HostAddressAndPortToString(
OUT PUCHAR IpAddressString,
IN PVOID TdiAddress,
IN USHORT TdiAddressType
)
{
PCHAR psz = (PCHAR) IpAddressString;
if (TdiAddressType == TDI_ADDRESS_TYPE_IP)
{
PTDI_ADDRESS_IP pIPv4Address = ((PTDI_ADDRESS_IP) TdiAddress);
struct in_addr IPv4Addr
= * (struct in_addr UNALIGNED*) &pIPv4Address->in_addr;
USHORT IpPortNum = SWAP_SHORT(pIPv4Address->sin_port);
psz = RtlIpv4AddressToStringA(&IPv4Addr, psz);
*psz++ = ':';
psz = UlStrPrintUlong(psz, IpPortNum, '\0');
}
else if (TdiAddressType == TDI_ADDRESS_TYPE_IP6)
{
PTDI_ADDRESS_IP6 pIPv6Address = ((PTDI_ADDRESS_IP6) TdiAddress);
struct in6_addr IPv6Addr
= * (struct in6_addr UNALIGNED*) &pIPv6Address->sin6_addr[0];
USHORT IpPortNum = SWAP_SHORT(pIPv6Address->sin6_port);
*psz++ = '[';
psz = RtlIpv6AddressToStringA(&IPv6Addr, psz);
*psz++ = ']';
*psz++ = ':';
psz = UlStrPrintUlong(psz, IpPortNum, '\0');
}
else
{
ASSERT(! "Unexpected TdiAddressType");
*psz = '\0';
}
return DIFF_USHORT(psz - (PCHAR) IpAddressString);
} // HostAddressAndPortToString
/****************************************************************************++
Routine Description:
Build a NULL terminated UNICODE string from the IP address & port.
Arguments:
IpAddressStringW - String buffer to place the UNICODE string
(caller allocated)
TdiAddress - TDI address to be converted
TdiAddressType - type of address at TdiAddress
Returns:
Count of bytes written into IpAddressStringW.
Not including the terminating null.
--****************************************************************************/
USHORT
HostAddressAndPortToStringW(
PWCHAR IpAddressStringW,
PVOID TdiAddress,
USHORT TdiAddressType
)
{
PWCHAR pszW = IpAddressStringW;
if (TdiAddressType == TDI_ADDRESS_TYPE_IP)
{
PTDI_ADDRESS_IP pIPv4Address = ((PTDI_ADDRESS_IP) TdiAddress);
struct in_addr IPv4Addr
= * (struct in_addr UNALIGNED*) &pIPv4Address->in_addr;
USHORT IpPortNum = SWAP_SHORT(pIPv4Address->sin_port);
pszW = RtlIpv4AddressToStringW(&IPv4Addr, pszW);
*pszW++ = L':';
pszW = UlStrPrintUlongW(pszW, IpPortNum, 0, L'\0');
}
else if (TdiAddressType == TDI_ADDRESS_TYPE_IP6)
{
PTDI_ADDRESS_IP6 pIPv6Address = ((PTDI_ADDRESS_IP6) TdiAddress);
struct in6_addr IPv6Addr
= * (struct in6_addr UNALIGNED*) &pIPv6Address->sin6_addr[0];
USHORT IpPortNum = SWAP_SHORT(pIPv6Address->sin6_port);
*pszW++ = L'[';
pszW = RtlIpv6AddressToStringW(&IPv6Addr, pszW);
*pszW++ = L']';
*pszW++ = L':';
pszW = UlStrPrintUlongW(pszW, IpPortNum, 0, L'\0');
}
else
{
ASSERT(! "Unexpected TdiAddressType");
*pszW = L'\0';
}
return (DIFF_USHORT(pszW - IpAddressStringW) * sizeof(WCHAR));
} // HostAddressAndPortToString
/*++
Routine Description:
Build a NULL terminated UNICODE string from the IP address
Arguments:
IpAddressStringW - String buffer to place the UNICODE string
(caller allocated)
TdiAddress - TDI address to be converted
TdiAddressType - type of address at TdiAddress
Returns:
Count of bytes written into IpAddressStringW.
Not including the terminating null.
--*/
USHORT
HostAddressToStringW(
OUT PWCHAR IpAddressStringW,
IN PVOID TdiAddress,
IN USHORT TdiAddressType
)
{
PWCHAR pszW = IpAddressStringW;
if (TdiAddressType == TDI_ADDRESS_TYPE_IP)
{
PTDI_ADDRESS_IP pIPv4Address = ((PTDI_ADDRESS_IP) TdiAddress);
struct in_addr IPv4Addr
= * (struct in_addr UNALIGNED*) &pIPv4Address->in_addr;
pszW = RtlIpv4AddressToStringW(&IPv4Addr, pszW);
*pszW = L'\0';
}
else if (TdiAddressType == TDI_ADDRESS_TYPE_IP6)
{
PTDI_ADDRESS_IP6 pIPv6Address = ((PTDI_ADDRESS_IP6) TdiAddress);
struct in6_addr IPv6Addr
= * (struct in6_addr UNALIGNED*) &pIPv6Address->sin6_addr[0];
*pszW++ = L'[';
pszW = RtlIpv6AddressToStringW(&IPv6Addr, pszW);
*pszW++ = L']';
*pszW = L'\0';
}
else
{
ASSERT(! "Unexpected TdiAddressType");
*pszW = L'\0';
}
return (DIFF_USHORT(pszW - IpAddressStringW) * sizeof(WCHAR));
} // HostAddressToStringW
/*++
Routine Description:
Build a NULL terminated routing token UNICODE string from
the IP address and port.
e.g
1.1.1.1:80:1.1.1.1
Arguments:
IpAddressStringW - String buffer to place the UNICODE string
(caller allocated)
TdiAddress - TDI address to be converted
TdiAddressType - type of address at TdiAddress
Returns:
Count of bytes written into IpAddressStringW.
Not including the terminating null.
--*/
USHORT
HostAddressAndPortToRoutingTokenW(
OUT PWCHAR IpAddressStringW,
IN PVOID TdiAddress,
IN USHORT TdiAddressType
)
{
PWCHAR pszW = IpAddressStringW;
//
// WARNING:
// Provided buffer should be at least as big as
// MAX_IP_BASED_ROUTING_TOKEN_LENGTH.
//
if (TdiAddressType == TDI_ADDRESS_TYPE_IP)
{
PTDI_ADDRESS_IP pIPv4Address = ((PTDI_ADDRESS_IP) TdiAddress);
struct in_addr IPv4Addr
= * (struct in_addr UNALIGNED*) &pIPv4Address->in_addr;
USHORT IpPortNum = SWAP_SHORT(pIPv4Address->sin_port);
pszW = RtlIpv4AddressToStringW(&IPv4Addr, pszW);
*pszW++ = L':';
pszW = UlStrPrintUlongW(pszW, IpPortNum, 0, L':');
pszW = RtlIpv4AddressToStringW(&IPv4Addr, pszW);
*pszW = L'\0';
}
else if (TdiAddressType == TDI_ADDRESS_TYPE_IP6)
{
PTDI_ADDRESS_IP6 pIPv6Address = ((PTDI_ADDRESS_IP6) TdiAddress);
struct in6_addr IPv6Addr
= * (struct in6_addr UNALIGNED*) &pIPv6Address->sin6_addr[0];
USHORT IpPortNum = SWAP_SHORT(pIPv6Address->sin6_port);
*pszW++ = L'[';
pszW = RtlIpv6AddressToStringW(&IPv6Addr, pszW);
*pszW++ = L']';
*pszW++ = L':';
pszW = UlStrPrintUlongW(pszW, IpPortNum, 0, L':');
*pszW++ = L'[';
pszW = RtlIpv6AddressToStringW(&IPv6Addr, pszW);
*pszW++ = L']';
*pszW = L'\0';
}
else
{
ASSERT(! "Unexpected TdiAddressType");
*pszW = L'\0';
}
return DIFF_USHORT(pszW - IpAddressStringW) * sizeof(WCHAR);
} // HostAddressAndPortToRoutingTokenW
/*++
Routine Description:
Calculates current bias (daylight time aware) and time zone ID.
Captured from base\client\datetime.c
Until this two functions are exposed in the kernel we have to
keep them here.
Arguments:
IN CONST TIME_ZONE_INFORMATION *ptzi - time zone for which to calculate bias
OUT KSYSTEM_TIME *pBias - current bias
Return Value:
TIME_ZONE_ID_UNKNOWN - daylight saving time is not used in the
current time zone.
TIME_ZONE_ID_STANDARD - The system is operating in the range covered
by StandardDate.
TIME_ZONE_ID_DAYLIGHT - The system is operating in the range covered
by DaylightDate.
TIME_ZONE_ID_INVALID - The operation failed.
--*/
ULONG
UlCalcTimeZoneIdAndBias(
IN RTL_TIME_ZONE_INFORMATION *ptzi,
OUT PLONG pBias
)
{
LARGE_INTEGER TimeZoneBias;
LARGE_INTEGER NewTimeZoneBias;
LARGE_INTEGER LocalCustomBias;
LARGE_INTEGER UtcStandardTime;
LARGE_INTEGER UtcDaylightTime;
LARGE_INTEGER StandardTime;
LARGE_INTEGER DaylightTime;
LARGE_INTEGER CurrentUniversalTime;
ULONG CurrentTimeZoneId = UL_TIME_ZONE_ID_INVALID;
NewTimeZoneBias.QuadPart = Int32x32To64(ptzi->Bias * 60, C_NS_TICKS_PER_SEC);
//
// Now see if we have stored cutover times
//
if (ptzi->StandardStart.Month && ptzi->DaylightStart.Month)
{
KeQuerySystemTime(&CurrentUniversalTime);
//
// We have timezone cutover information. Compute the
// cutover dates and compute what our current bias
// is
//
if((!UlpCutoverTimeToSystemTime(
&ptzi->StandardStart,
&StandardTime,
&CurrentUniversalTime)
) ||
(!UlpCutoverTimeToSystemTime(
&ptzi->DaylightStart,
&DaylightTime,
&CurrentUniversalTime)
)
)
{
return UL_TIME_ZONE_ID_INVALID;
}
//
// Convert standard time and daylight time to utc
//
LocalCustomBias.QuadPart = Int32x32To64(ptzi->StandardBias*60, C_NS_TICKS_PER_SEC);
TimeZoneBias.QuadPart = NewTimeZoneBias.QuadPart + LocalCustomBias.QuadPart;
UtcDaylightTime.QuadPart = DaylightTime.QuadPart + TimeZoneBias.QuadPart;
LocalCustomBias.QuadPart = Int32x32To64(ptzi->DaylightBias*60, C_NS_TICKS_PER_SEC);
TimeZoneBias.QuadPart = NewTimeZoneBias.QuadPart + LocalCustomBias.QuadPart;
UtcStandardTime.QuadPart = StandardTime.QuadPart + TimeZoneBias.QuadPart;
//
// If daylight < standard, then time >= daylight and
// less than standard is daylight
//
if (UtcDaylightTime.QuadPart < UtcStandardTime.QuadPart)
{
//
// If today is >= DaylightTime and < StandardTime, then
// We are in daylight savings time
//
if ((CurrentUniversalTime.QuadPart >= UtcDaylightTime.QuadPart) &&
(CurrentUniversalTime.QuadPart < UtcStandardTime.QuadPart))
{
CurrentTimeZoneId = UL_TIME_ZONE_ID_DAYLIGHT;
}
else
{
CurrentTimeZoneId = UL_TIME_ZONE_ID_STANDARD;
}
}
else
{
//
// If today is >= StandardTime and < DaylightTime, then
// We are in standard time
//
if ((CurrentUniversalTime.QuadPart >= UtcStandardTime.QuadPart) &&
(CurrentUniversalTime.QuadPart < UtcDaylightTime.QuadPart))
{
CurrentTimeZoneId = UL_TIME_ZONE_ID_STANDARD;
}
else
{
CurrentTimeZoneId = UL_TIME_ZONE_ID_DAYLIGHT;
}
}
// Bias in minutes
*pBias = ptzi->Bias + (CurrentTimeZoneId == UL_TIME_ZONE_ID_DAYLIGHT ?
ptzi->DaylightBias : ptzi->StandardBias
);
}
else
{
*pBias = ptzi->Bias;
CurrentTimeZoneId = UL_TIME_ZONE_ID_UNKNOWN;
}
return CurrentTimeZoneId;
} // UlCalcTimeZoneIdAndBias
BOOLEAN
UlpCutoverTimeToSystemTime(
PTIME_FIELDS CutoverTime,
PLARGE_INTEGER SystemTime,
PLARGE_INTEGER CurrentSystemTime
)
{
TIME_FIELDS CurrentTimeFields;
//
// Get the current system time
//
RtlTimeToTimeFields(CurrentSystemTime,&CurrentTimeFields);
//
// check for absolute time field. If the year is specified,
// the the time is an abosulte time
//
if ( CutoverTime->Year )
{
return FALSE;
}
else
{
TIME_FIELDS WorkingTimeField;
TIME_FIELDS ScratchTimeField;
LARGE_INTEGER ScratchTime;
CSHORT BestWeekdayDate;
CSHORT WorkingWeekdayNumber;
CSHORT TargetWeekdayNumber;
CSHORT TargetYear;
CSHORT TargetMonth;
CSHORT TargetWeekday; // range [0..6] == [Sunday..Saturday]
BOOLEAN MonthMatches;
//
// The time is an day in the month style time
//
// the convention is the Day is 1-5 specifying 1st, 2nd... Last
// day within the month. The day is WeekDay.
//
//
// Compute the target month and year
//
TargetWeekdayNumber = CutoverTime->Day;
if ( TargetWeekdayNumber > 5 || TargetWeekdayNumber == 0 ) {
return FALSE;
}
TargetWeekday = CutoverTime->Weekday;
TargetMonth = CutoverTime->Month;
MonthMatches = FALSE;
TargetYear = CurrentTimeFields.Year;
try_next_year:
BestWeekdayDate = 0;
WorkingTimeField.Year = TargetYear;
WorkingTimeField.Month = TargetMonth;
WorkingTimeField.Day = 1;
WorkingTimeField.Hour = CutoverTime->Hour;
WorkingTimeField.Minute = CutoverTime->Minute;
WorkingTimeField.Second = CutoverTime->Second;
WorkingTimeField.Milliseconds = CutoverTime->Milliseconds;
WorkingTimeField.Weekday = 0;
//
// Convert to time and then back to time fields so we can determine
// the weekday of day 1 on the month
//
if ( !RtlTimeFieldsToTime(&WorkingTimeField,&ScratchTime) ) {
return FALSE;
}
RtlTimeToTimeFields(&ScratchTime,&ScratchTimeField);
//
// Compute bias to target weekday
//
if ( ScratchTimeField.Weekday > TargetWeekday ) {
WorkingTimeField.Day += (7-(ScratchTimeField.Weekday - TargetWeekday));
}
else if ( ScratchTimeField.Weekday < TargetWeekday ) {
WorkingTimeField.Day += (TargetWeekday - ScratchTimeField.Weekday);
}
//
// We are now at the first weekday that matches our target weekday
//
BestWeekdayDate = WorkingTimeField.Day;
WorkingWeekdayNumber = 1;
//
// Keep going one week at a time until we either pass the
// target weekday, or we match exactly
//
while ( WorkingWeekdayNumber < TargetWeekdayNumber ) {
WorkingTimeField.Day += 7;
if ( !RtlTimeFieldsToTime(&WorkingTimeField,&ScratchTime) ) {
break;
}
RtlTimeToTimeFields(&ScratchTime,&ScratchTimeField);
WorkingWeekdayNumber++;
BestWeekdayDate = ScratchTimeField.Day;
}
WorkingTimeField.Day = BestWeekdayDate;
//
// If the months match, and the date is less than the current
// date, then be have to go to next year.
//
if ( !RtlTimeFieldsToTime(&WorkingTimeField,&ScratchTime) ) {
return FALSE;
}
if ( MonthMatches ) {
if ( WorkingTimeField.Day < CurrentTimeFields.Day ) {
MonthMatches = FALSE;
TargetYear++;
goto try_next_year;
}
if ( WorkingTimeField.Day == CurrentTimeFields.Day ) {
if (ScratchTime.QuadPart < CurrentSystemTime->QuadPart) {
MonthMatches = FALSE;
TargetYear++;
goto try_next_year;
}
}
}
*SystemTime = ScratchTime;
return TRUE;
}
} // UlpCutoverTimeToSystemTime
/*++
Routine Description:
Predicate for testing if system is close to being out of Non-Paged
Pool memory
Notes:
The Right Thing(tm) would be to query the value of
MmMaximumNonPagedPoolInBytes (%SDXROOT%\base\ntos\mm\miglobal.c).
However, this value is not exposed outside of the memory manager.
(from LandyW) "A crude workaround for now would be for your driver
to periodically allocate a big chunk of pool and if it fails, you
know you are low. If it works, then just return it." (27-Jul-2001)
We check to see if there is 3MB of NPP available. To avoid frag-
mentation issue, we do this in small chunks, tallying up to 3MB.
Returns:
TRUE - System is low on non-paged pool
FALSE - System is NOT low on non-paged pool
--*/
//
// NOTE: (NPP_CHUNK_COUNT * NPP_CHUNK_SIZE) == 3MB
//
#define NPP_CHUNK_SIZE (128 * 1024)
#define NPP_CHUNK_COUNT ((3 * 1024 * 1024) / NPP_CHUNK_SIZE)
BOOLEAN
UlIsLowNPPCondition( VOID )
{
BOOLEAN bRet;
PVOID aPtrs[NPP_CHUNK_COUNT];
int i;
//
// Optimisim is a good thing.
//
bRet = FALSE;
RtlZeroMemory( aPtrs, sizeof(aPtrs) );
//
// To avoid failing an allocation on a fragmentation issue, we
// allocate multiple smaller chunks, which brings us to 3MB of
// NonPagedPool. If we fail on any of the allocs, we know we're
// nearly out of NPP, and are in a Low NPP Condition.
//
for (i = 0 ; i < NPP_CHUNK_COUNT ; i++ )
{
aPtrs[i] = UL_ALLOCATE_POOL(
NonPagedPool,
NPP_CHUNK_SIZE, // 128K
UL_AUXILIARY_BUFFER_POOL_TAG
);
if ( !aPtrs[i] )
{
// Alloc failed! We're in a low-NPP condition!
bRet = TRUE;
goto End;
}
}
End:
//
// Clean up memory
//
for ( i = 0; i < NPP_CHUNK_COUNT; i++ )
{
if ( aPtrs[i] )
{
UL_FREE_POOL(
aPtrs[i],
UL_AUXILIARY_BUFFER_POOL_TAG
);
}
}
return bRet;
} // UlIsLowNPPCondition
/***************************************************************************++
Routine Description:
Generates a hex string from a ULONG. The incoming buffer must be big enough
to hold "12345678" plus the nul terminator.
Arguments:
n - input ULONG
Return Value:
a pointer to the end of the string
--***************************************************************************/
PSTR
UlUlongToHexString(
ULONG n,
PSTR wszHexDword
)
{
const int ULONGHEXDIGITS = sizeof(ULONG) * 2;
PSTR p = wszHexDword;
unsigned shift = (sizeof(ULONG) * 8) - 4;
ULONG mask = 0xFu << shift;
int i;
for (i = 0; i < ULONGHEXDIGITS; ++i, mask >>= 4, shift -= 4)
{
unsigned digit = (unsigned) ((n & mask) >> shift);
p[i] = hexArray[digit];
}
return p+i;
} // UlUlongToHexString
/***************************************************************************++
Routine Description:
This function does what strstr does, but assumes that str1 is not NULL
terminated. str2 is NULL terminated.
Arguments:
str1 - the input string
str2 - the substring
length - length of input string
Return Value:
offset of the substring, NULL if none found.
--***************************************************************************/
char *
UxStrStr(
const char *str1,
const char *str2,
ULONG length
)
{
char *cp = (char *) str1;
char *s1, *s2;
ULONG l1;
if ( !*str2 )
return((char *)str1);
while (length)
{
l1 = length;
s1 = cp;
s2 = (char *) str2;
while ( l1 && *s2 && !(*s1-*s2) )
l1--, s1++, s2++;
if (!*s2)
return(cp);
cp++;
length --;
}
return(NULL);
}
/***************************************************************************++
Routine Description:
This function does what strstr does, but assumes that str1 is not NULL
terminated. str2 is NULL terminated.
Arguments:
str1 - the input string
str2 - the substring
length - length of input string
Return Value:
offset of the substring, NULL if none found.
--***************************************************************************/
char *
UxStriStr(
const char *str1,
const char *str2,
ULONG length1
)
{
ULONG length2;
length2 = (ULONG) strlen(str2);
while (length1 >= length2 )
{
if(_strnicmp(str1, str2, length2) == 0)
return ((char *)str1);
str1 ++;
length1 --;
}
return(NULL);
}
/**************************************************************************++
Routine Description:
This routine encodes binary data in base64 format. It does not spilt
encoded base64 data across lines.
Arguments:
pBinaryData - Supplied pointer to binary data to encode.
BinaryDataLen - Supplies length of binary data in bytes.
pBase64Data - Supplies output buffer where base64 data will be written.
Base64DataLen - Supplies length of output buffer in bytes.
BytesWritten - Returns the number of bytes written in the output buffer.
Return Value:
NTSTATUS.
--**************************************************************************/
NTSTATUS
BinaryToBase64(
IN PUCHAR pBinaryData,
IN ULONG BinaryDataLen,
IN PUCHAR pBase64Data,
IN ULONG Base64DataLen,
OUT PULONG BytesWritten
)
{
NTSTATUS Status;
ULONG RequiredBase64Len;
ULONG i;
UCHAR o0, o1, o2, o3;
UCHAR end24bits[3];
PUCHAR p, pOrig;
//
// N.B. The following macros only work with UCHAR's (because of >> operator.)
//
#define UPPER_6_BITS(c) (((c) & 0xfc) >> 2)
#define UPPER_4_BITS(c) (((c) & 0xf0) >> 4)
#define UPPER_2_BITS(c) (((c) & 0xc0) >> 6)
#define LOWER_2_BITS(c) ((c) & 0x03)
#define LOWER_4_BITS(c) ((c) & 0x0f)
#define LOWER_6_BITS(c) ((c) & 0x3f)
// Sanity Check.
ASSERT(pBinaryData && BinaryDataLen);
ASSERT(pBase64Data && Base64DataLen);
ASSERT(BytesWritten);
// Initialize output argument.
*BytesWritten = 0;
//
// Check if the output buffer can contain base64 encoded data.
//
Status = BinaryToBase64Length(BinaryDataLen, &RequiredBase64Len);
if (!NT_SUCCESS(Status))
{
return Status;
}
if (RequiredBase64Len > Base64DataLen)
{
return STATUS_BUFFER_TOO_SMALL;
}
// Return the number of bytes written.
*BytesWritten = RequiredBase64Len;
p = pBinaryData;
pOrig = pBase64Data;
for (i = 0; i + 3 <= BinaryDataLen; i += 3)
{
//
// Encode 3 bytes at indices i, i+1, i+2.
//
o0 = UPPER_6_BITS(p[i]);
o1 = (LOWER_2_BITS(p[i]) << 4) | UPPER_4_BITS(p[i+1]);
o2 = (LOWER_4_BITS(p[i+1]) << 2) | UPPER_2_BITS(p[i+2]);
o3 = LOWER_6_BITS(p[i+2]);
ASSERT(o0 < 64 && o1 < 64 && o2 < 64 && o3 < 64);
//
// Encode binary bytes and write out the base64 bytes.
//
*pBase64Data++ = BinaryToBase64Table[o0];
*pBase64Data++ = BinaryToBase64Table[o1];
*pBase64Data++ = BinaryToBase64Table[o2];
*pBase64Data++ = BinaryToBase64Table[o3];
}
if (i < BinaryDataLen)
{
//
// Zero pad the remaining bits to get 24 bits.
//
end24bits[0] = p[i];
end24bits[1] = (BinaryDataLen > i+1) ? p[i+1] : '\0';
end24bits[2] = '\0';
o0 = UPPER_6_BITS(end24bits[0]);
o1 = (LOWER_2_BITS(end24bits[0]) << 4) | UPPER_4_BITS(end24bits[1]);
o2 = (LOWER_4_BITS(end24bits[1]) << 2) | UPPER_2_BITS(end24bits[2]);
pBase64Data[0] = BinaryToBase64Table[o0];
pBase64Data[1] = BinaryToBase64Table[o1];
pBase64Data[2] = BinaryToBase64Table[o2];
pBase64Data[3] = '=';
pBase64Data[2] = (BinaryDataLen > i+1) ? pBase64Data[2] : '=';
ASSERT(pBase64Data + 4 == pOrig + RequiredBase64Len);
}
else
{
ASSERT(pBase64Data == pOrig + RequiredBase64Len);
}
return STATUS_SUCCESS;
}
/**************************************************************************++
Routine Description:
This routine decodes Base64 encoded data to binary format.
Arguments:
pBase64Data - Supplies pointer to base64 encoded data.
Base64DataLen - Length of base64 data in bytes.
pBinaryData - Supplies pointer to a buffer where decoded data will
be written.
BinaryDataLen - Supplied the length of output buffer in bytes.
BytesWritten - Returns the number of bytes written in the output buffer.
Return Value:
NTSTATUS.
--**************************************************************************/
NTSTATUS
Base64ToBinary(
IN PUCHAR pBase64Data,
IN ULONG Base64DataLen,
IN PUCHAR pBinaryData,
IN ULONG BinaryDataLen,
OUT PULONG BytesWritten
)
{
ULONG i;
UCHAR b;
NTSTATUS Status;
ULONG RequiredBinaryLen;
ULONG BitsAvail, NumBitsAvail;
PUCHAR pCurr = pBinaryData;
// Sanity check.
ASSERT(pBase64Data && Base64DataLen);
ASSERT(pBinaryData && BinaryDataLen);
ASSERT(BytesWritten);
// Initialize output argument.
*BytesWritten = 0;
//
// Check if output buffer is big enough to hold the data.
//
Status = Base64ToBinaryLength(Base64DataLen, &RequiredBinaryLen);
if (!NT_SUCCESS(Status))
{
return Status;
}
if (RequiredBinaryLen > BinaryDataLen)
{
return STATUS_BUFFER_TOO_SMALL;
}
ASSERT(Base64DataLen % 4 == 0);
BitsAvail = 0;
NumBitsAvail = 0;
for (i = 0; i < Base64DataLen; i ++)
{
//
// See if base64 char is valid. All valid base64 chars are mapped
// to n where 0 <= n <= 63. In adition, '=' is also a valid
// base64 char.
//
b = Base64ToBinaryTable[pBase64Data[i]];
if (b == INVALID_BASE64_TO_BINARY_TABLE_ENTRY)
{
if (pBase64Data[i] != '=')
{
return STATUS_INVALID_PARAMETER;
}
// Handle '=' outside the for loop.
break;
}
ASSERT(NumBitsAvail < 8);
ASSERT(0 <= b && b <= 63);
BitsAvail = (BitsAvail << 6) | b;
NumBitsAvail += 6;
if (NumBitsAvail >= 8)
{
NumBitsAvail -= 8;
*pCurr++ = (UCHAR)(BitsAvail >> NumBitsAvail);
}
ASSERT(NumBitsAvail < 8);
}
if (i < Base64DataLen)
{
ASSERT(pBase64Data[i] == '=');
//
// There can be at most two '=' chars and they must appear at the end
// of the encoded data. A char, if any, that follows '=' char, must
// be a '='.
//
if (i + 2 < Base64DataLen ||
(i + 1 < Base64DataLen && pBase64Data[i+1] != '='))
{
return STATUS_INVALID_PARAMETER;
}
//
// All the remaining bits at this point must be zeros.
//
ASSERT(NumBitsAvail > 0 && NumBitsAvail < 8);
if (BitsAvail & ((1<<NumBitsAvail)-1))
{
return STATUS_INVALID_PARAMETER;
}
}
*BytesWritten = (ULONG)(pCurr - pBinaryData);
ASSERT(*BytesWritten <= BinaryDataLen);
return STATUS_SUCCESS;
}