Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1954 lines
49 KiB

/*++
Copyright (c) 1998-2001 Microsoft Corporation
Module Name:
init.cxx
Abstract:
This module performs initialization for the UL device driver.
Author:
Keith Moore (keithmo) 10-Jun-1998
Revision History:
--*/
#include "precomp.h"
//
// Private constants.
//
#define DEFAULT_THREAD_AFFINITY_MASK ((1ui64 << KeNumberProcessors) - 1)
//
// Private types.
//
typedef struct _SID_MASK_PAIR
{
PSID pSid;
ACCESS_MASK AccessMask;
} SID_MASK_PAIR, *PSID_MASK_PAIR;
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
//
// Private prototypes.
//
NTSTATUS
UlpApplySecurityToDeviceObjects(
VOID
);
NTSTATUS
UlpCreateSecurityDescriptor(
OUT PSECURITY_DESCRIPTOR pSecurityDescriptor,
IN PSID_MASK_PAIR pSidMaskPairs,
IN ULONG NumSidMaskPairs
);
VOID
UlpCleanupSecurityDescriptor(
IN PSECURITY_DESCRIPTOR pSecurityDescriptor
);
NTSTATUS
UlpSetDeviceObjectSecurity(
IN PDEVICE_OBJECT pDeviceObject,
IN SECURITY_INFORMATION SecurityInformation,
IN PSECURITY_DESCRIPTOR pSecurityDescriptor
);
VOID
UlpReadRegistry (
IN PUL_CONFIG pConfig
);
VOID
UlpTerminateModules(
VOID
);
#if ALLOW_UNLOAD
VOID
UlpUnload (
IN PDRIVER_OBJECT DriverObject
);
#endif // ALLOW_UNLOAD
#ifdef __cplusplus
}; // extern "C"
#endif // __cplusplus
//
// Private globals.
//
#if DBG
ULONG g_UlpForceInitFailure = 0;
#endif // DBG
#ifdef ALLOC_PRAGMA
#pragma alloc_text( INIT, DriverEntry )
#pragma alloc_text( INIT, UlpApplySecurityToDeviceObjects )
#pragma alloc_text( INIT, UlpCreateSecurityDescriptor )
#pragma alloc_text( INIT, UlpCleanupSecurityDescriptor )
#pragma alloc_text( INIT, UlpSetDeviceObjectSecurity )
#pragma alloc_text( INIT, UlpReadRegistry )
#if ALLOW_UNLOAD
#pragma alloc_text( PAGE, UlpUnload )
#pragma alloc_text( PAGE, UlpTerminateModules )
#endif // ALLOW_UNLOAD
//
// Note that UlpTerminateModules() must be "page" if driver unloading
// is enabled (it's called from UlpUnload), but can be "init" otherwise
// (it's only called after initialization failure).
//
#if ALLOW_UNLOAD
#pragma alloc_text( PAGE, UlpTerminateModules )
#else
#pragma alloc_text( INIT, UlpTerminateModules )
#endif // ALLOW_UNLOAD
#endif // ALLOC_PRAGMA
//
// Public functions.
//
/***************************************************************************++
Routine Description:
This is the initialization routine for the UL device driver.
Arguments:
DriverObject - Supplies a pointer to driver object created by the
system.
RegistryPath - Supplies the name of the driver's configuration
registry tree.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
NTSTATUS status;
UNICODE_STRING deviceName;
OBJECT_ATTRIBUTES objectAttributes;
CLONG i;
UL_CONFIG config;
//
// Sanity check.
//
PAGED_CODE();
//
// Grab the number of processors in the system.
//
g_UlNumberOfProcessors = KeNumberProcessors;
g_UlThreadAffinityMask = DEFAULT_THREAD_AFFINITY_MASK;
//
// Grab the largest cache line size in the system
//
g_UlCacheLineSize = KeGetRecommendedSharedDataAlignment();
for (g_UlCacheLineBits = 0;
(1U << g_UlCacheLineBits) < g_UlCacheLineSize;
++g_UlCacheLineBits)
{}
ASSERT(g_UlCacheLineSize <= (1U << g_UlCacheLineBits));
//
// Snag a pointer to the system process.
//
g_pUlSystemProcess = (PKPROCESS)IoGetCurrentProcess();
//
// Read registry information.
//
UlpReadRegistry( &config );
#if DBG
//
// Give anyone using the kernel debugger a chance to abort
// initialization.
//
if (g_UlpForceInitFailure != 0)
{
status = STATUS_UNSUCCESSFUL;
goto fatal;
}
#endif // DBG
//
// Initialize the global trace logs.
//
UlInitializeOwnerRefTraceLog();
CREATE_REF_TRACE_LOG( g_pMondoGlobalTraceLog, 16384 - REF_TRACE_OVERHEAD, 0 );
CREATE_REF_TRACE_LOG( g_pTdiTraceLog, 32768 - REF_TRACE_OVERHEAD, 0 );
CREATE_REF_TRACE_LOG( g_pHttpRequestTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 );
CREATE_REF_TRACE_LOG( g_pHttpConnectionTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 );
CREATE_REF_TRACE_LOG( g_pHttpResponseTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 );
CREATE_REF_TRACE_LOG( g_pAppPoolTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 );
CREATE_REF_TRACE_LOG( g_pConfigGroupTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 );
CREATE_REF_TRACE_LOG( g_pThreadTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 );
CREATE_REF_TRACE_LOG( g_pMdlTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 );
CREATE_REF_TRACE_LOG( g_pFilterTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 );
CREATE_IRP_TRACE_LOG( g_pIrpTraceLog, 32768 - REF_TRACE_OVERHEAD, 0 );
CREATE_TIME_TRACE_LOG( g_pTimeTraceLog, 32768 - REF_TRACE_OVERHEAD, 0 );
CREATE_REPLENISH_TRACE_LOG( g_pReplenishTraceLog, 32768 - REF_TRACE_OVERHEAD, 0 );
CREATE_FILTQ_TRACE_LOG( g_pFilterQueueTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 );
CREATE_REF_TRACE_LOG( g_pSiteCounterTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 );
CREATE_REF_TRACE_LOG( g_pConnectionCountTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 );
CREATE_REF_TRACE_LOG( g_pConfigGroupInfoTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 );
CREATE_REF_TRACE_LOG( g_pChunkTrackerTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 );
CREATE_REF_TRACE_LOG( g_pWorkItemTraceLog, 32768 - REF_TRACE_OVERHEAD, 0 );
//
// Create an object directory to contain our device objects.
//
RtlInitUnicodeString( &deviceName, HTTP_DIRECTORY_NAME );
InitializeObjectAttributes(
&objectAttributes, // ObjectAttributes
&deviceName, // ObjectName
OBJ_CASE_INSENSITIVE | // Attributes
UL_KERNEL_HANDLE,
NULL, // RootDirectory
NULL // SecurityDescriptor
);
UlAttachToSystemProcess();
status = ZwCreateDirectoryObject(
&g_UlDirectoryObject, // DirectoryHandle
DIRECTORY_ALL_ACCESS, // AccessMask
&objectAttributes // ObjectAttributes
);
UlDetachFromSystemProcess();
if (!NT_SUCCESS(status))
{
goto fatal;
}
//
// Create the control channel device object.
//
RtlInitUnicodeString( &deviceName, HTTP_CONTROL_DEVICE_NAME );
status = IoCreateDevice(
DriverObject, // DriverObject
0, // DeviceExtension
&deviceName, // DeviceName
FILE_DEVICE_NETWORK, // DeviceType
0, // DeviceCharacteristics
TRUE, // Exclusive
&g_pUlControlDeviceObject // DeviceObject
);
if (!NT_SUCCESS(status))
{
goto fatal;
}
//
// Create the filter device object.
//
RtlInitUnicodeString( &deviceName, HTTP_FILTER_DEVICE_NAME );
status = IoCreateDevice(
DriverObject, // DriverObject
0, // DeviceExtension
&deviceName, // DeviceName
FILE_DEVICE_NETWORK, // DeviceType
0, // DeviceCharacteristics
FALSE, // Exclusive
&g_pUlFilterDeviceObject // DeviceObject
);
if (!NT_SUCCESS(status))
{
goto fatal;
}
g_pUlFilterDeviceObject->StackSize = g_UlIrpStackSize;
//
// Create the app pool device object.
//
RtlInitUnicodeString( &deviceName, HTTP_APP_POOL_DEVICE_NAME );
status = IoCreateDevice(
DriverObject, // DriverObject
0, // DeviceExtension
&deviceName, // DeviceName
FILE_DEVICE_NETWORK, // DeviceType
0, // DeviceCharacteristics
FALSE, // Exclusive
&g_pUlAppPoolDeviceObject // DeviceObject
);
if (!NT_SUCCESS(status))
{
goto fatal;
}
g_pUlAppPoolDeviceObject->StackSize = g_UlIrpStackSize;
//
// If so requested, apply security to the device objects.
//
// CODEWORK: REMOVE THIS CONFIGURATION PARAMETER!
//
if (config.EnableSecurity)
{
status = UlpApplySecurityToDeviceObjects();
if (!NT_SUCCESS(status))
{
goto fatal;
}
}
else
{
KdPrint(( "UL: security disabled\n" ));
}
//
// Initialize the driver object with this driver's entrypoints.
//
DriverObject->MajorFunction[IRP_MJ_CREATE] = &UlCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = &UlClose;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = &UlCleanup;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = &UlDeviceControl;
DriverObject->FastIoDispatch = &UlFastIoDispatch;
DriverObject->DriverUnload = NULL;
#if ALLOW_UNLOAD
if( config.EnableUnload )
{
KdPrint(( "UL: DriverUnload enabled\n" ));
DriverObject->DriverUnload = &UlpUnload;
}
#endif // ALLOW_UNLOAD
//
// Initialize global data.
//
status = UlInitializeData(&config);
if (!NT_SUCCESS(status))
{
goto fatal;
}
//
// Create the thread pool.
//
status = UlInitializeThreadPool(config.ThreadsPerCpu);
if (!NT_SUCCESS(status))
{
goto fatal;
}
//
// Initialize common TDI.
//
status = UxInitializeTdi();
if (!NT_SUCCESS(status))
{
goto fatal;
}
//
// Initialize server connection code.
//
status = UlInitializeTdi();
if (!NT_SUCCESS(status))
{
goto fatal;
}
//
// Initialize temporary test code.
//
// status = UlInitializeTdiTest();
// if (!NT_SUCCESS(status))
// {
// goto fatal;
// }
//
// Initialize George.
//
status = UlLargeMemInitialize(&config);
ASSERT( NT_SUCCESS(status) );
//
// Initialize Keith.
//
status = UlInitializeControlChannel();
ASSERT( NT_SUCCESS(status) );
//
// Initialize Henry.
//
status = InitializeHttpUtil();
ASSERT( NT_SUCCESS(status) );
status = InitializeParser();
ASSERT( NT_SUCCESS(status) );
status = UlInitializeOpaqueIdTable();
ASSERT( NT_SUCCESS(status) );
status = InitializeFileCache();
ASSERT( NT_SUCCESS(status) );
//
// Initialize Michael.
//
status = UlInitializeFilterChannel();
ASSERT( NT_SUCCESS(status) );
//
// Initialize Alex.
//
status = UlInitializeUriCache(&config);
if ( !NT_SUCCESS(status) )
{
goto fatal;
}
status = UlInitializeDateCache();
ASSERT( NT_SUCCESS(status) );
//
// Initialize Paul.
//
status = UlInitializeCG();
ASSERT( NT_SUCCESS(status) );
status = UlInitializeAP();
ASSERT( NT_SUCCESS(status) );
//
// Initialize Ali
//
status = UlInitializeLogs();
ASSERT( NT_SUCCESS(status) );
// TC Init may fail if PSched
// is not installed.
UlTcInitialize();
#if 0
status = UlTcInitialize();
ASSERT( NT_SUCCESS(status));
#endif
status = UlInitGlobalConnectionLimits();
ASSERT( NT_SUCCESS(status) );
//
// Initialize Eric.
//
status = UlInitializeHttpRcv();
ASSERT( NT_SUCCESS(status) );
status = UlInitializeCounters();
ASSERT( NT_SUCCESS(status) );
UlInitializeTimeoutMonitor();
#if DBG
//
// Give anyone using the kernel debugger one final chance to abort
// initialization.
//
if (g_UlpForceInitFailure != 0)
{
status = STATUS_UNSUCCESSFUL;
goto fatal;
}
#endif // DBG
return STATUS_SUCCESS;
//
// Fatal error handlers.
//
fatal:
UlpTerminateModules();
ASSERT( !NT_SUCCESS(status) );
return status;
} // DriverEntry
//
// Private functions.
//
/***************************************************************************++
Routine Description:
Applies the appropriate security descriptors to the global device
objects created at initialization time.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlpApplySecurityToDeviceObjects(
VOID
)
{
NTSTATUS status;
SECURITY_DESCRIPTOR securityDescriptor;
PGENERIC_MAPPING pFileObjectGenericMapping;
ACCESS_MASK fileRead;
ACCESS_MASK fileAll;
HANDLE handle;
SID_MASK_PAIR sidMaskPairs[3];
//
// Sanity check.
//
PAGED_CODE();
ASSERT( IS_VALID_DEVICE_OBJECT( g_pUlControlDeviceObject ) );
ASSERT( IS_VALID_DEVICE_OBJECT( g_pUlFilterDeviceObject ) );
ASSERT( IS_VALID_DEVICE_OBJECT( g_pUlAppPoolDeviceObject ) );
//
// Gain access to the predefined SIDs and other security-related
// goodies exported by the kernel.
//
//SeEnableAccessToExports();
//
// Map a couple of generic file access types to their corresponding
// object-specific rights.
//
pFileObjectGenericMapping = IoGetFileObjectGenericMapping();
ASSERT( pFileObjectGenericMapping != NULL );
fileRead = GENERIC_READ;
RtlMapGenericMask(
&fileRead,
pFileObjectGenericMapping
);
fileAll = GENERIC_ALL;
RtlMapGenericMask(
&fileAll,
pFileObjectGenericMapping
);
//
// Build a restrictive security descriptor for the control device
// object:
//
// Full access for NT AUTHORITY\SYSTEM
// Full access for BUILTIN\Administrators
//
sidMaskPairs[0].pSid = SeExports->SeLocalSystemSid;
sidMaskPairs[0].AccessMask = fileAll;
sidMaskPairs[1].pSid = SeExports->SeAliasAdminsSid;
sidMaskPairs[1].AccessMask = fileAll;
status = UlpCreateSecurityDescriptor(
&securityDescriptor, // pSecurityDescriptor
&sidMaskPairs[0], // pSidMaskPairs
2 // NumSidMaskPairs
);
if (!NT_SUCCESS(status))
{
goto complete;
}
status = UlpSetDeviceObjectSecurity(
g_pUlControlDeviceObject,
DACL_SECURITY_INFORMATION,
&securityDescriptor
);
UlpCleanupSecurityDescriptor( &securityDescriptor );
if (!NT_SUCCESS(status))
{
goto complete;
}
//
// Build a restrictive security descriptor for the filter device
// object:
//
// Full access for NT AUTHORITY\SYSTEM
// Full access for BUILTIN\Administrators
//
sidMaskPairs[0].pSid = SeExports->SeLocalSystemSid;
sidMaskPairs[0].AccessMask = fileAll;
sidMaskPairs[1].pSid = SeExports->SeAliasAdminsSid;
sidMaskPairs[1].AccessMask = fileAll;
status = UlpCreateSecurityDescriptor(
&securityDescriptor, // pSecurityDescriptor
&sidMaskPairs[0], // pSidMaskPairs
2 // NumSidMaskPairs
);
if (!NT_SUCCESS(status))
{
goto complete;
}
status = UlpSetDeviceObjectSecurity(
g_pUlFilterDeviceObject,
DACL_SECURITY_INFORMATION,
&securityDescriptor
);
UlpCleanupSecurityDescriptor( &securityDescriptor );
if (!NT_SUCCESS(status))
{
goto complete;
}
//
// Build a slightly less restrictive security descriptor for the
// app pool device object:
//
// Full access for NT AUTHORITY\SYSTEM
// Full access for BUILTIN\Administrators
// Read access for Everyone
//
sidMaskPairs[0].pSid = SeExports->SeLocalSystemSid;
sidMaskPairs[0].AccessMask = fileAll;
sidMaskPairs[1].pSid = SeExports->SeAliasAdminsSid;
sidMaskPairs[1].AccessMask = fileAll;
sidMaskPairs[2].pSid = SeExports->SeWorldSid;
sidMaskPairs[2].AccessMask = fileRead;
status = UlpCreateSecurityDescriptor(
&securityDescriptor, // pSecurityDescriptor
&sidMaskPairs[0], // pSidMaskPairs
3 // NumSidMaskPairs
);
if (!NT_SUCCESS(status))
{
goto complete;
}
status = UlpSetDeviceObjectSecurity(
g_pUlAppPoolDeviceObject,
DACL_SECURITY_INFORMATION,
&securityDescriptor
);
UlpCleanupSecurityDescriptor( &securityDescriptor );
if (!NT_SUCCESS(status))
{
goto complete;
}
complete:
return status;
} // UlpApplySecurityToDeviceObjects
/***************************************************************************++
Routine Description:
Allocates and initializes a security descriptor with the specified
attributes.
Arguments:
pSecurityDescriptor - Supplies a pointer to the security descriptor
to initialize.
pSidMaskPairs - Supplies an array of SID/ACCESS_MASK pairs.
NumSidMaskPairs - Supplies the number of SID/ACESS_MASK pairs.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlpCreateSecurityDescriptor(
OUT PSECURITY_DESCRIPTOR pSecurityDescriptor,
IN PSID_MASK_PAIR pSidMaskPairs,
IN ULONG NumSidMaskPairs
)
{
NTSTATUS status;
PACL pDacl;
ULONG daclLength;
ULONG i;
//
// Sanity check.
//
PAGED_CODE();
ASSERT( pSecurityDescriptor != NULL );
ASSERT( pSidMaskPairs != NULL );
ASSERT( NumSidMaskPairs > 0 );
//
// Setup locals so we know how to cleanup on exit.
//
pDacl = NULL;
//
// Initialize the security descriptor.
//
status = RtlCreateSecurityDescriptor(
pSecurityDescriptor, // SecurityDescriptor
SECURITY_DESCRIPTOR_REVISION // Revision
);
if (!NT_SUCCESS(status))
{
goto cleanup;
}
//
// Calculate the DACL length.
//
daclLength = sizeof(ACL);
for (i = 0 ; i < NumSidMaskPairs ; i++)
{
daclLength += sizeof(ACCESS_ALLOWED_ACE);
daclLength += RtlLengthSid( pSidMaskPairs[i].pSid );
}
//
// Allocate & initialize the DACL.
//
pDacl = (PACL) UL_ALLOCATE_POOL(
PagedPool,
daclLength,
UL_SECURITY_DATA_POOL_TAG
);
if (pDacl == NULL)
{
status = STATUS_INSUFFICIENT_RESOURCES;
goto cleanup;
}
status = RtlCreateAcl(
pDacl, // Acl
daclLength, // AclLength
ACL_REVISION // AclRevision
);
if (!NT_SUCCESS(status))
{
goto cleanup;
}
//
// Add the necessary access-allowed ACEs to the DACL.
//
for (i = 0 ; i < NumSidMaskPairs ; i++)
{
status = RtlAddAccessAllowedAce(
pDacl, // Acl
ACL_REVISION, // AceRevision
pSidMaskPairs[i].AccessMask, // AccessMask
pSidMaskPairs[i].pSid // Sid
);
if (!NT_SUCCESS(status))
{
goto cleanup;
}
}
//
// Attach the DACL to the security descriptor.
//
status = RtlSetDaclSecurityDescriptor(
pSecurityDescriptor, // SecurityDescriptor
TRUE, // DaclPresent
pDacl, // Dacl
FALSE // DaclDefaulted
);
if (!NT_SUCCESS(status))
{
goto cleanup;
}
//
// Success!
//
ASSERT( NT_SUCCESS(status) );
return STATUS_SUCCESS;
cleanup:
ASSERT( !NT_SUCCESS(status) );
if (pDacl != NULL)
{
UL_FREE_POOL(
pDacl,
UL_SECURITY_DATA_POOL_TAG
);
}
return status;
} // UlpCreateSecurityDescriptor
/***************************************************************************++
Routine Description:
Frees any resources associated with the security descriptor created
by UlpCreateSecurityDescriptor().
Arguments:
pSecurityDescriptor - Supplies the security descriptor to cleanup.
--***************************************************************************/
VOID
UlpCleanupSecurityDescriptor(
IN PSECURITY_DESCRIPTOR pSecurityDescriptor
)
{
NTSTATUS status;
PACL pDacl;
BOOLEAN daclPresent;
BOOLEAN daclDefaulted;
//
// Sanity check.
//
PAGED_CODE();
ASSERT( RtlValidSecurityDescriptor( pSecurityDescriptor ) );
//
// Try to retrieve the DACL from the security descriptor.
//
status = RtlGetDaclSecurityDescriptor(
pSecurityDescriptor, // SecurityDescriptor
&daclPresent, // DaclPresent
&pDacl, // Dacl
&daclDefaulted // DaclDefaulted
);
if (NT_SUCCESS(status))
{
if (daclPresent && (pDacl != NULL))
{
UL_FREE_POOL(
pDacl,
UL_SECURITY_DATA_POOL_TAG
);
}
}
} // UlpCleanupSecurityDescriptor
/***************************************************************************++
Routine Description:
Applies the specified security descriptor to the specified device
object.
Arguments:
pDeviceObject - Supplies the device object to manipulate.
SecurityInformation - Supplies the level of information to change.
pSecurityDescriptor - Supplies the new security descriptor for the
device object.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlpSetDeviceObjectSecurity(
IN PDEVICE_OBJECT pDeviceObject,
IN SECURITY_INFORMATION SecurityInformation,
IN PSECURITY_DESCRIPTOR pSecurityDescriptor
)
{
NTSTATUS status;
HANDLE handle;
//
// Sanity check.
//
PAGED_CODE();
ASSERT( IS_VALID_DEVICE_OBJECT( pDeviceObject ) );
ASSERT( RtlValidSecurityDescriptor( pSecurityDescriptor ) );
//
// Open a handle to the device object.
//
UlAttachToSystemProcess();
status = ObOpenObjectByPointer(
pDeviceObject, // Object
OBJ_CASE_INSENSITIVE | // HandleAttributes
UL_KERNEL_HANDLE,
NULL, // PassedAccessState
MAXIMUM_ALLOWED, // DesiredAccess
NULL, // ObjectType
KernelMode, // AccessMode
&handle // Handle
);
if (NT_SUCCESS(status))
{
status = NtSetSecurityObject(
handle, // Handle
SecurityInformation, // SecurityInformation
pSecurityDescriptor // SecurityDescriptor
);
ZwClose( handle );
}
UlDetachFromSystemProcess();
return status;
} // UlpSetDeviceObjectSecurity
/***************************************************************************++
Routine Description:
Reads the UL section of the registry. Any values contained in the
registry override defaults.
Arguments:
pConfig - Supplies a pointer to a UL_CONFIG structure that receives
init-time configuration parameters. These are basically
parameters that do not need to persist in the driver once
initialization is complete.
--***************************************************************************/
VOID
UlpReadRegistry(
IN PUL_CONFIG pConfig
)
{
HANDLE parametersHandle;
NTSTATUS status;
LONG tmp;
LONGLONG tmp64;
UNICODE_STRING registryPath;
//
// Sanity check.
//
PAGED_CODE();
//
// Establish defaults.
//
pConfig->ThreadsPerCpu = DEFAULT_THREADS_PER_CPU;
pConfig->IrpContextLookasideDepth = DEFAULT_IRP_CONTEXT_LOOKASIDE_DEPTH;
pConfig->ReceiveBufferLookasideDepth = DEFAULT_RCV_BUFFER_LOOKASIDE_DEPTH;
pConfig->ResourceLookasideDepth = DEFAULT_RESOURCE_LOOKASIDE_DEPTH;
pConfig->RequestBufferLookasideDepth = DEFAULT_REQ_BUFFER_LOOKASIDE_DEPTH;
pConfig->InternalRequestLookasideDepth = DEFAULT_INT_REQUEST_LOOKASIDE_DEPTH;
pConfig->ResponseBufferLookasideDepth = DEFAULT_RESP_BUFFER_LOOKASIDE_DEPTH;
pConfig->SendTrackerLookasideDepth = DEFAULT_SEND_TRACKER_LOOKASIDE_DEPTH;
pConfig->LogBufferLookasideDepth = DEFAULT_LOG_BUFFER_LOOKASIDE_DEPTH;
pConfig->EnableUnload = DEFAULT_ENABLE_UNLOAD;
pConfig->EnableSecurity = DEFAULT_ENABLE_SECURITY;
pConfig->UriConfig.EnableCache = DEFAULT_CACHE_ENABLED;
pConfig->UriConfig.MaxCacheUriCount = DEFAULT_MAX_CACHE_URI_COUNT;
pConfig->UriConfig.MaxCacheMegabyteCount = DEFAULT_MAX_CACHE_MEGABYTE_COUNT;
pConfig->UriConfig.MaxUriBytes = DEFAULT_MAX_URI_BYTES;
pConfig->UriConfig.ScavengerPeriod = DEFAULT_CACHE_SCAVENGER_PERIOD;
pConfig->LargeMemMegabytes = DEFAULT_LARGE_MEM_MEGABYTES;
//
// Open the registry.
//
RtlInitUnicodeString( &registryPath, REGISTRY_UL_INFORMATION );
status = UlOpenRegistry( &registryPath, &parametersHandle );
if (status != STATUS_SUCCESS)
{
return;
}
#if DBG
//
// Read the debug flags.
//
g_UlDebug = (ULONG)UlReadLongParameter(
parametersHandle,
REGISTRY_DEBUG_FLAGS,
g_UlDebug
);
//
// Force a breakpoint if so requested.
//
if (UlReadLongParameter(
parametersHandle,
REGISTRY_BREAK_ON_STARTUP,
DEFAULT_BREAK_ON_STARTUP) != 0 )
{
DbgBreakPoint();
}
//
// Read the break-on-error flags.
//
g_UlBreakOnError = (ULONG)UlReadLongParameter(
parametersHandle,
REGISTRY_BREAK_ON_ERROR,
g_UlBreakOnError
);
g_UlVerboseErrors = (ULONG)UlReadLongParameter(
parametersHandle,
REGISTRY_VERBOSE_ERRORS,
g_UlVerboseErrors
);
//
// Break-on-error implies verbose-errors.
//
if (g_UlBreakOnError)
{
g_UlVerboseErrors = TRUE;
}
#endif // DBG
#if ALLOW_UNLOAD
//
// Enable driver unload if requested.
//
pConfig->EnableUnload = UlReadLongParameter(
parametersHandle,
REGISTRY_ENABLE_UNLOAD,
(LONG)pConfig->EnableUnload
) != 0;
#endif // ALLOW_UNLOAD
//
// Enable driver security if requested.
//
pConfig->EnableSecurity = UlReadLongParameter(
parametersHandle,
REGISTRY_ENABLE_SECURITY,
(LONG)pConfig->EnableSecurity
) != 0;
//
// Read the stack size and priority boost values from the registry.
//
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_IRP_STACK_SIZE,
(LONG)g_UlIrpStackSize
);
//
// Enforce reasonable minimum/maximum values for the IRP stack size.
//
if (tmp < 2)
{
tmp = 2;
}
else if (tmp > 64)
{
tmp = 64;
}
g_UlIrpStackSize = (CCHAR)tmp;
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_PRIORITY_BOOST,
(LONG)g_UlPriorityBoost
);
if (tmp > 16 || tmp <= 0)
{
tmp = DEFAULT_PRIORITY_BOOST;
}
g_UlPriorityBoost = (CCHAR)tmp;
//
// Read the thread pool parameters.
//
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_THREADS_PER_CPU,
(LONG)pConfig->ThreadsPerCpu
);
if (tmp > 0xFFFF || tmp <= 0)
{
tmp = DEFAULT_THREADS_PER_CPU;
}
pConfig->ThreadsPerCpu = (USHORT)tmp;
//
// Other configuration parameters.
//
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_MIN_IDLE_CONNECTIONS,
(LONG)g_UlMinIdleConnections
);
if (tmp > 0xFFFF || tmp <= 1)
{
tmp = DEFAULT_MIN_IDLE_CONNECTIONS;
}
g_UlMinIdleConnections = (USHORT)tmp;
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_MAX_IDLE_CONNECTIONS,
(LONG)g_UlMaxIdleConnections
);
if (tmp > 0xFFFF || tmp <= 0)
{
tmp = DEFAULT_MAX_IDLE_CONNECTIONS;
}
g_UlMaxIdleConnections = (USHORT)tmp;
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_IRP_CONTEXT_LOOKASIDE_DEPTH,
(LONG)pConfig->IrpContextLookasideDepth
);
if (tmp > 0xFFFF || tmp <= 0)
{
tmp = DEFAULT_IRP_CONTEXT_LOOKASIDE_DEPTH;
}
pConfig->IrpContextLookasideDepth = (USHORT)tmp;
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_RCV_BUFFER_LOOKASIDE_DEPTH,
(LONG)pConfig->ReceiveBufferLookasideDepth
);
if (tmp > 0xFFFF || tmp <= 0)
{
tmp = DEFAULT_RCV_BUFFER_LOOKASIDE_DEPTH;
}
pConfig->ReceiveBufferLookasideDepth = (USHORT)tmp;
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_REQ_BUFFER_LOOKASIDE_DEPTH,
(LONG)pConfig->RequestBufferLookasideDepth
);
if (tmp > 0xFFFF || tmp <= 0)
{
tmp = DEFAULT_REQ_BUFFER_LOOKASIDE_DEPTH;
}
pConfig->RequestBufferLookasideDepth = (USHORT)tmp;
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_INT_REQUEST_LOOKASIDE_DEPTH,
(LONG)pConfig->InternalRequestLookasideDepth
);
if (tmp > 0xFFFF || tmp <= 0)
{
tmp = DEFAULT_INT_REQUEST_LOOKASIDE_DEPTH;
}
pConfig->InternalRequestLookasideDepth = (USHORT)tmp;
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_RESP_BUFFER_LOOKASIDE_DEPTH,
(LONG)pConfig->ResponseBufferLookasideDepth
);
if (tmp > 0xFFFF || tmp <= 0)
{
tmp = DEFAULT_RESP_BUFFER_LOOKASIDE_DEPTH;
}
pConfig->ResponseBufferLookasideDepth = (USHORT)tmp;
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_SEND_TRACKER_LOOKASIDE_DEPTH,
(LONG)pConfig->SendTrackerLookasideDepth
);
if (tmp > 0xFFFF || tmp <= 0)
{
tmp = DEFAULT_SEND_TRACKER_LOOKASIDE_DEPTH;
}
pConfig->SendTrackerLookasideDepth = (USHORT)tmp;
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_LOG_BUFFER_LOOKASIDE_DEPTH,
(LONG)pConfig->LogBufferLookasideDepth
);
if (tmp > 0xFFFF || tmp <= 0)
{
tmp = DEFAULT_LOG_BUFFER_LOOKASIDE_DEPTH;
}
pConfig->LogBufferLookasideDepth = (USHORT)tmp;
g_UlEnableConnectionReuse = UlReadLongParameter(
parametersHandle,
REGISTRY_ENABLE_CONNECTION_REUSE,
(LONG)g_UlEnableConnectionReuse
) != 0;
g_UlEnableNagling = UlReadLongParameter(
parametersHandle,
REGISTRY_ENABLE_NAGLING,
(LONG)g_UlEnableNagling
) != 0;
g_UlEnableThreadAffinity = UlReadLongParameter(
parametersHandle,
REGISTRY_ENABLE_THREAD_AFFINITY,
(LONG)g_UlEnableThreadAffinity
) != 0;
tmp64 = UlReadLongLongParameter(
parametersHandle,
REGISTRY_THREAD_AFFINITY_MASK,
g_UlThreadAffinityMask
);
if ((ULONGLONG)tmp64 > DEFAULT_THREAD_AFFINITY_MASK
|| (ULONGLONG)tmp64 == 0)
{
tmp64 = DEFAULT_THREAD_AFFINITY_MASK;
}
g_UlThreadAffinityMask = (ULONGLONG)tmp64;
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_MAX_WORK_QUEUE_DEPTH,
(LONG)g_UlMaxWorkQueueDepth
);
if (tmp > 0xFFFF || tmp < 0)
{
tmp = DEFAULT_MAX_WORK_QUEUE_DEPTH;
}
g_UlMaxWorkQueueDepth = (USHORT)tmp;
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_MIN_WORK_DEQUEUE_DEPTH,
(LONG)g_UlMinWorkDequeueDepth
);
if (tmp > 0xFFFF || tmp < 0)
{
tmp = DEFAULT_MIN_WORK_DEQUEUE_DEPTH;
}
g_UlMinWorkDequeueDepth = (USHORT)tmp;
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_OPAQUE_ID_TABLE_SIZE,
(LONG)g_UlOpaqueIdTableSize
);
if (tmp > 0xFFFF || tmp <= 0)
{
tmp = DEFAULT_OPAQUE_ID_TABLE_SIZE;
}
g_UlOpaqueIdTableSize = tmp;
//
// MAX url setting
//
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_MAX_URL_LENGTH,
(LONG)g_UlMaxUrlLength
);
if (tmp > 0xFFFF || tmp <= 0)
{
tmp = DEFAULT_MAX_URL_LENGTH;
}
g_UlMaxUrlLength = (USHORT)tmp;
//
// MAX allowed field length in HTTP requests
//
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_MAX_FIELD_LENGTH,
(LONG)g_UlMaxFieldLength
);
if (tmp > 0xFFFFFF || tmp <= 0)
{
tmp = DEFAULT_MAX_FIELD_LENGTH;
}
g_UlMaxFieldLength = tmp;
//
// If defined this will overwrite the default
// log timer cycle period of 1 hour and make
// the testing of the log recycling easier.
// The value is interpreted in seconds.
//
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_DEBUG_LOGTIMER_CYCLE,
(LONG)g_UlDebugLogTimerCycle
);
if (tmp > 0xFFFF || tmp <= 0)
{
tmp = DEFAULT_DEBUG_LOGTIMER_CYCLE;
}
g_UlDebugLogTimerCycle = (USHORT)tmp;
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_DEBUG_LOG_BUFFER_PERIOD,
(LONG)g_UlDebugLogBufferPeriod
);
if (tmp > 0xFFFF || tmp <= 0)
{
tmp = DEFAULT_DEBUG_LOG_BUFFER_PERIOD;
}
g_UlDebugLogBufferPeriod = (USHORT)tmp;
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_LOG_BUFFER_SIZE,
(LONG)g_UlLogBufferSize
);
if (tmp > MAXIMUM_ALLOWED_LOG_BUFFER_SIZE
|| tmp < MINIMUM_ALLOWED_LOG_BUFFER_SIZE )
{
// Basically this value will be discarted by the logging code
// instead systems granularity size (64K) will be used.
tmp = DEFAULT_LOG_BUFFER_SIZE;
}
tmp -= tmp % 4096; // Align down to 4k
g_UlLogBufferSize = (ULONG) tmp;
//
// read the resource lookaside config
//
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_RESOURCE_LOOKASIDE_DEPTH,
(LONG)pConfig->ResourceLookasideDepth
);
if (tmp > 0xFFFF || tmp <= 0)
{
tmp = DEFAULT_RESOURCE_LOOKASIDE_DEPTH;
}
pConfig->ResourceLookasideDepth = (USHORT)tmp;
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_MAX_REQUEST_BYTES,
g_UlMaxRequestBytes
);
if (tmp > 0xFFFFFF || tmp <= 0)
{
tmp = DEFAULT_MAX_REQUEST_BYTES;
}
g_UlMaxRequestBytes = ALIGN_DOWN( tmp, PVOID );
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_RCV_BUFFER_SIZE,
g_UlReceiveBufferSize
);
if (tmp > 0xFFFFFF || tmp <= 0)
{
tmp = DEFAULT_RCV_BUFFER_SIZE;
}
g_UlReceiveBufferSize = ALIGN_DOWN( tmp, PVOID );
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_RESP_BUFFER_SIZE,
g_UlResponseBufferSize
);
if (tmp > 0xFFFFFF || tmp <= 0)
{
tmp = DEFAULT_RESP_BUFFER_SIZE;
}
g_UlResponseBufferSize = ALIGN_DOWN( tmp, PVOID );
//
// Read URL processing parameters.
// BUGBUG: read legacy IIS value?
//
g_UlEnableNonUTF8 = UlReadLongParameter(
parametersHandle,
REGISTRY_ENABLE_NON_UTF8_URL,
DEFAULT_ENABLE_NON_UTF8_URL
) != 0;
if (g_UlEnableNonUTF8)
{
g_UlEnableDBCS = UlReadLongParameter(
parametersHandle,
REGISTRY_ENABLE_DBCS_URL,
DEFAULT_ENABLE_DBCS_URL
) != 0;
}
else
{
//
// We can't do DBCS if we only accept UTF-8.
//
g_UlEnableDBCS = FALSE;
}
if (g_UlEnableDBCS)
{
g_UlFavorDBCS = UlReadLongParameter(
parametersHandle,
REGISTRY_FAVOR_DBCS_URL,
DEFAULT_FAVOR_DBCS_URL
) != 0;
}
else
{
//
// We can't favor DBCS if we don't allow DBCS.
//
g_UlFavorDBCS = FALSE;
}
tmp = UlReadLongParameter(
parametersHandle,
REGISTRY_MAX_INTERNAL_URL_LENGTH,
g_UlMaxInternalUrlLength
);
if (tmp > 0xFFFFFF || tmp <= 0)
{
tmp = DEFAULT_MAX_INTERNAL_URL_LENGTH;
}
g_UlMaxInternalUrlLength = (USHORT)tmp;
//
// Read URI Cache parameters
//
pConfig->UriConfig.EnableCache = UlReadLongParameter(
parametersHandle,
REGISTRY_CACHE_ENABLED,
DEFAULT_CACHE_ENABLED
) != 0;
pConfig->UriConfig.MaxCacheUriCount = UlReadLongParameter(
parametersHandle,
REGISTRY_MAX_CACHE_URI_COUNT,
DEFAULT_MAX_CACHE_URI_COUNT
);
pConfig->UriConfig.MaxCacheMegabyteCount = UlReadLongParameter(
parametersHandle,
REGISTRY_MAX_CACHE_MEGABYTE_COUNT,
DEFAULT_MAX_CACHE_MEGABYTE_COUNT
);
pConfig->UriConfig.MaxUriBytes = UlReadLongParameter(
parametersHandle,
REGISTRY_MAX_URI_BYTES,
DEFAULT_MAX_URI_BYTES
);
pConfig->UriConfig.ScavengerPeriod = UlReadLongParameter(
parametersHandle,
REGISTRY_CACHE_SCAVENGER_PERIOD,
DEFAULT_CACHE_SCAVENGER_PERIOD
);
pConfig->UriConfig.HashTableBits = UlReadLongParameter(
parametersHandle,
REGISTRY_HASH_TABLE_BITS,
DEFAULT_HASH_TABLE_BITS
);
pConfig->LargeMemMegabytes = UlReadLongParameter(
parametersHandle,
REGISTRY_LARGE_MEM_MEGABYTES,
DEFAULT_LARGE_MEM_MEGABYTES
);
//
// Make sure we can always buffer enough bytes for an entire request
// header.
//
g_UlMaxBufferedBytes = MAX(g_UlMaxBufferedBytes, g_UlMaxRequestBytes);
//
// Dump configuration on checked builds.
//
#if DBG
DbgPrint( "UL Configuration:\n" );
#if DBG
DbgPrint( " g_UlDebug = %08lx\n", g_UlDebug );
DbgPrint( " g_UlBreakOnError = %lu\n", g_UlBreakOnError );
DbgPrint( " g_UlVerboseErrors = %lu\n", g_UlVerboseErrors );
#endif // DBG
DbgPrint( " g_UlIrpStackSize = %lu\n", g_UlIrpStackSize );
DbgPrint( " g_UlPriorityBoost = %lu\n", g_UlPriorityBoost );
DbgPrint( " g_UlMinIdleConnections = %lu\n", g_UlMinIdleConnections );
DbgPrint( " g_UlMaxIdleConnections = %lu\n", g_UlMaxIdleConnections );
DbgPrint( " g_UlEnableConnectionReuse = %lu\n", g_UlEnableConnectionReuse );
DbgPrint( " g_UlEnableNagling = %lu\n", g_UlEnableNagling );
DbgPrint( " g_UlEnableThreadAffinity = %lu\n", g_UlEnableThreadAffinity );
DbgPrint( " g_UlThreadAffinityMask = %I64x\n", g_UlThreadAffinityMask );
DbgPrint( " g_UlMaxWorkQueueDepth = %lu\n", g_UlMaxWorkQueueDepth );
DbgPrint( " g_UlMinWorkDequeueDepth = %lu\n", g_UlMinWorkDequeueDepth );
DbgPrint( " g_UlOpaqueIdTableSize = %lu\n", g_UlOpaqueIdTableSize );
DbgPrint( " g_UlMaxRequestBytes = %lu\n", g_UlMaxRequestBytes );
DbgPrint( " g_UlReceiveBufferSize = %lu\n", g_UlReceiveBufferSize );
DbgPrint( " g_UlResponseBufferSize = %lu\n", g_UlResponseBufferSize );
DbgPrint( " g_UlMaxUrlLength = %lu\n", g_UlMaxUrlLength );
DbgPrint( " g_UlMaxFieldLength = %lu\n", g_UlMaxFieldLength );
DbgPrint( " g_UlDebugLogTimerCycle = %lu\n", g_UlDebugLogTimerCycle );
DbgPrint( " g_UlDebugLogBufferPeriod = %lu\n", g_UlDebugLogBufferPeriod );
DbgPrint( " g_UlLogBufferSize = %lu\n", g_UlLogBufferSize );
DbgPrint( " g_UlEnableNonUTF8 = %lu\n", g_UlEnableNonUTF8 );
DbgPrint( " g_UlEnableDBCS = %lu\n", g_UlEnableDBCS );
DbgPrint( " g_UlFavorDBCS = %lu\n", g_UlFavorDBCS );
DbgPrint( " g_UlMaxInternalUrlLength = %lu\n", g_UlMaxInternalUrlLength );
#if ALLOW_UNLOAD
DbgPrint( " EnableUnload = %lu\n", pConfig->EnableUnload );
#endif // ALLOW_UNLOAD
DbgPrint( " EnableSecurity = %lu\n", pConfig->EnableSecurity );
DbgPrint( " ThreadsPerCpu = %lx\n", pConfig->ThreadsPerCpu );
DbgPrint( " IrpContextLookasideDepth = %lu\n", pConfig->IrpContextLookasideDepth );
DbgPrint( " ReceiveBufferLookasideDepth = %lu\n", pConfig->ReceiveBufferLookasideDepth );
DbgPrint( " ResourceLookasideDepth = %lu\n", pConfig->ResourceLookasideDepth );
DbgPrint( " RequestBufferLookasideDepth = %lu\n", pConfig->RequestBufferLookasideDepth );
DbgPrint( " IntlRequestLookasideDepth = %lu\n", pConfig->InternalRequestLookasideDepth );
DbgPrint( " ResponseBufferLookasideDepth = %lu\n", pConfig->ResponseBufferLookasideDepth );
DbgPrint( " SendTrackerLookasideDepth = %lu\n", pConfig->SendTrackerLookasideDepth );
DbgPrint( " LogBufferLookasideDepth = %lu\n", pConfig->LogBufferLookasideDepth );
DbgPrint( " EnableCache = %lu\n", pConfig->UriConfig.EnableCache );
DbgPrint( " MaxCacheUriCount = %lu\n", pConfig->UriConfig.MaxCacheUriCount );
DbgPrint( " MaxCacheMegabyteCount = %lu\n", pConfig->UriConfig.MaxCacheMegabyteCount );
DbgPrint( " ScavengerPeriod = %lu\n", pConfig->UriConfig.ScavengerPeriod );
DbgPrint( " HashTableBits = %ld\n", pConfig->UriConfig.HashTableBits);
DbgPrint( " MaxUriBytes = %lu\n", pConfig->UriConfig.MaxUriBytes );
DbgPrint( " LargeMemMegabytes = %ld\n", pConfig->LargeMemMegabytes );
#endif // DBG
//
// Cleanup.
//
UlCloseSystemHandle( parametersHandle );
} // UlpReadRegistry
#if ALLOW_UNLOAD
/***************************************************************************++
Routine Description:
Unload routine called by the IO subsystem when UL is getting
unloaded.
--***************************************************************************/
VOID
UlpUnload(
IN PDRIVER_OBJECT DriverObject
)
{
//
// Sanity check.
//
PAGED_CODE();
UL_ENTER_DRIVER("UlpUnload", NULL);
#if DBG
KdPrint(( "UlpUnload called.\n" ));
#endif // DBG
//
// Terminate the UL modules.
//
UlpTerminateModules();
UL_LEAVE_DRIVER("UlpUnload");
#if DBG
//
// Terminate any debug-specific data after UL_LEAVE_DRIVER
//
UlDbgTerminateDebugData( );
#endif // DBG
} // UlpUnload
#endif // ALLOW_UNLOAD
/***************************************************************************++
Routine Description:
Terminates the various UL modules in the correct order.
--***************************************************************************/
VOID
UlpTerminateModules(
VOID
)
{
//
// Sanity check.
//
PAGED_CODE();
//
// Wait for endpoints to go away, so we're sure all I/O is done.
//
UlWaitForEndpointDrain();
//
// Kill Michael.
//
UlTerminateDateCache();
UlTerminateUriCache();
UlTerminateFilterChannel();
//
// Kill Henry.
//
TerminateFileCache();
//
// Kill Paul.
//
UlTerminateCG();
UlTerminateAP();
//
// Kill Keith.
//
UlTerminateControlChannel();
//
// TerminateLogs Blocks until all Io To Be Complete
//
// Note:CG should be terminated before Logs.
// Otherwise we won't stop issuing the buffer writes.
// ThreadPool should be terminated after Logs.
// Otherwise our Completion APCs won't be completed back.
//
//
// Kill Ali
//
UlTerminateLogs();
UlTcTerminate();
//
// Kill Eric.
//
UlTerminateHttpRcv();
UlTerminateCounters();
UlTerminateTimeoutMonitor();
//
// Kill George.
//
UlLargeMemTerminate();
//
// Kill TDI.
//
UxTerminateTdi();
UlTerminateTdi();
//
// Kill the thread pool.
//
UlTerminateThreadPool();
//
// Kill the opaque Ids
//
UlTerminateOpaqueIdTable();
//
// Kill any global data.
//
UlTerminateData();
//
// Delete our device objects.
//
if (g_pUlAppPoolDeviceObject != NULL)
{
IoDeleteDevice( g_pUlAppPoolDeviceObject );
}
if (g_pUlFilterDeviceObject != NULL)
{
IoDeleteDevice( g_pUlFilterDeviceObject );
}
if (g_pUlControlDeviceObject != NULL)
{
IoDeleteDevice( g_pUlControlDeviceObject );
}
//
// Delete the directory container.
//
if (g_UlDirectoryObject != NULL)
{
UlCloseSystemHandle( g_UlDirectoryObject );
}
//
// Delete the global trace logs.
//
DESTROY_REF_TRACE_LOG( g_pTdiTraceLog );
DESTROY_REF_TRACE_LOG( g_pHttpRequestTraceLog );
DESTROY_REF_TRACE_LOG( g_pHttpConnectionTraceLog );
DESTROY_REF_TRACE_LOG( g_pHttpResponseTraceLog );
DESTROY_REF_TRACE_LOG( g_pAppPoolTraceLog );
DESTROY_REF_TRACE_LOG( g_pConfigGroupTraceLog );
DESTROY_REF_TRACE_LOG( g_pThreadTraceLog );
DESTROY_REF_TRACE_LOG( g_pMdlTraceLog );
DESTROY_REF_TRACE_LOG( g_pFilterTraceLog );
DESTROY_REF_TRACE_LOG( g_pMondoGlobalTraceLog );
DESTROY_IRP_TRACE_LOG( g_pIrpTraceLog );
DESTROY_TIME_TRACE_LOG( g_pTimeTraceLog );
DESTROY_REPLENISH_TRACE_LOG( g_pReplenishTraceLog );
DESTROY_FILTQ_TRACE_LOG( g_pFilterQueueTraceLog );
DESTROY_REF_TRACE_LOG( g_pSiteCounterTraceLog );
DESTROY_REF_TRACE_LOG( g_pConnectionCountTraceLog );
DESTROY_REF_TRACE_LOG( g_pConfigGroupInfoTraceLog );
DESTROY_REF_TRACE_LOG( g_pChunkTrackerTraceLog );
DESTROY_REF_TRACE_LOG( g_pWorkItemTraceLog );
UlTerminateOwnerRefTraceLog();
} // UlpTerminateModules