windows-nt/Source/XPSP1/NT/base/fs/rdr2/rdbss/minirdr.c
2020-09-26 16:20:57 +08:00

532 lines
14 KiB
C

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
minirdr.c
Abstract:
This module implements minirdr registration functions.
Author:
Joe Linn (JoeLinn) 2-2-95
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, RxRegisterMinirdr)
#pragma alloc_text(PAGE, RxMakeLateDeviceAvailable)
#pragma alloc_text(PAGE, RxpUnregisterMinirdr)
#endif
//
// The debug trace level
//
#define Dbg (0)
#ifdef ALLOC_PRAGMA
#endif
// #define BBT_UPDATE 1
#ifdef BBT_UPDATE
extern VOID RxUpdate(PVOID pContext);
HANDLE RxHandle = INVALID_HANDLE_VALUE;
PETHREAD RxPointer = NULL;
#endif
NTSTATUS
NTAPI
RxRegisterMinirdr(
OUT PRDBSS_DEVICE_OBJECT *DeviceObject,
IN OUT PDRIVER_OBJECT DriverObject, // the minirdr driver object
IN PMINIRDR_DISPATCH MrdrDispatch, // the mini rdr dispatch vector
IN ULONG Controls,
IN PUNICODE_STRING DeviceName,
IN ULONG DeviceExtensionSize,
IN DEVICE_TYPE DeviceType,
IN ULONG DeviceCharacteristics
)
/*++
Routine Description:
The routine adds the registration information to the minirdr registration table. As well, it builds
a device object; the MUP registration is at start time. Also, we fill in the deviceobject so that we are catching
all the calls.
Arguments:
DeviceObject - where the created device object is to be stored
ProtocolMarker - a 4byte marker denoting the FileLevel Protocol
('LCL ', 'SMB ', 'NCP ', and 'NFS ') are used
MrdrDispatch - the dispatch table for finding the server/netroot discovery routines
Context - whatever PVOID the underlying guy wants
MupAction - whether/how the MUP registration is done
DeviceName,DeviceExtensionSize,DeviceType,DeviceCharacteristics
- the params for the device object that is to be built these are adjusted a bit
bfore they're passed to Io
Return Value:
--
--*/
{
NTSTATUS Status;
PRDBSS_DEVICE_OBJECT RxDeviceObject;
PAGED_CODE();
RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), (" RxRegisterMinirdr Name = %wZ", DeviceName));
if (DeviceObject==NULL) {
return STATUS_INVALID_PARAMETER;
}
// Create the device object.
Status = IoCreateDevice(DriverObject,
sizeof(RDBSS_DEVICE_OBJECT) - sizeof(DEVICE_OBJECT) + DeviceExtensionSize,
DeviceName,
DeviceType,
DeviceCharacteristics,
FALSE,
(PDEVICE_OBJECT *)(&RxDeviceObject));
if (Status != STATUS_SUCCESS) {
return(Status);
}
if (RxData.DriverObject == NULL) {
return STATUS_UNSUCCESSFUL;
}
//
// If the Mini-Redir is being built in a monolithic fashion, then the
// device object "RxFileSystemDeviceObject" would not have been created
// in the RxDriverEntry function. Hence we set RxDeviceObject->RDBSSDeviceObject
// to NULL. When the "monolithic" Mini-Redir gets unloaded, a check is done
// to see if RxDeviceObject->RDBSSDeviceObject is NULL. If it is not NULL,
// then the device object is dereferenced. This happens in the function
// RxUnregisterMinirdr.
//
// Don't allow myself to be unloaded.
#ifndef MONOLITHIC_MINIRDR
RxDeviceObject->RDBSSDeviceObject = (PDEVICE_OBJECT)RxFileSystemDeviceObject;
ObReferenceObject((PDEVICE_OBJECT)RxFileSystemDeviceObject);
// Reset the Unload routine. This prevents rdbss from being unloaded individually
RxData.DriverObject->DriverUnload = NULL;
#else
RxDeviceObject->RDBSSDeviceObject = NULL;
RxFileSystemDeviceObject->ReferenceCount++;
#endif
*DeviceObject = RxDeviceObject;
RxDeviceObject->RdbssExports = &RxExports;
RxDeviceObject->Dispatch = MrdrDispatch;
RxDeviceObject->RegistrationControls = Controls;
RxDeviceObject->DeviceName = *DeviceName;
RxDeviceObject->RegisterUncProvider =
!BooleanFlagOn(Controls,RX_REGISTERMINI_FLAG_DONT_PROVIDE_UNCS);
RxDeviceObject->RegisterMailSlotProvider =
!BooleanFlagOn(Controls,RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS);
{
LONG Index;
for (Index = 0; Index < MaximumWorkQueue; Index++) {
InitializeListHead( &RxDeviceObject->OverflowQueue[Index] );
}
}
KeInitializeSpinLock( &RxDeviceObject->OverflowQueueSpinLock );
RxDeviceObject->NetworkProviderPriority = RxGetNetworkProviderPriority(DeviceName);
RxLog(("RegMini %x %wZ\n",RxDeviceObject->NetworkProviderPriority,DeviceName));
RxWmiLog(LOG,
RxRegisterMinirdr,
LOGULONG(RxDeviceObject->NetworkProviderPriority)
LOGUSTR(*DeviceName));
ExAcquireFastMutexUnsafe(&RxData.MinirdrRegistrationMutex);
InsertTailList(&RxData.RegisteredMiniRdrs,&RxDeviceObject->MiniRdrListLinks);
//no need for interlock.....we're inside the mutex
//InterlockedIncrement(&RxData.NumberOfMinirdrsRegistered);
RxData.NumberOfMinirdrsRegistered++;
ExReleaseFastMutexUnsafe(&RxData.MinirdrRegistrationMutex);
if (!FlagOn(Controls,RX_REGISTERMINI_FLAG_DONT_INIT_DRIVER_DISPATCH)) {
RxInitializeMinirdrDispatchTable(DriverObject);
}
if (!FlagOn(Controls,RX_REGISTERMINI_FLAG_DONT_INIT_PREFIX_N_SCAVENGER)) {
// Initialize the netname table
RxDeviceObject->pRxNetNameTable = &RxDeviceObject->RxNetNameTableInDeviceObject;
RxInitializePrefixTable( RxDeviceObject->pRxNetNameTable, 0, FALSE);
RxDeviceObject->RxNetNameTableInDeviceObject.IsNetNameTable = TRUE;
// Initialize the scavenger data structures
RxDeviceObject->pRdbssScavenger = &RxDeviceObject->RdbssScavengerInDeviceObject;
RxInitializeRdbssScavenger(RxDeviceObject->pRdbssScavenger);
}
RxDeviceObject->pAsynchronousRequestsCompletionEvent = NULL;
#ifdef BBT_UPDATE
if (RxHandle == INVALID_HANDLE_VALUE) {
NTSTATUS Status;
Status = PsCreateSystemThread(
&RxHandle,
PROCESS_ALL_ACCESS,
NULL,
NULL,
NULL,
RxUpdate,
NULL);
if (Status == STATUS_SUCCESS) {
Status = ObReferenceObjectByHandle(
RxHandle,
THREAD_ALL_ACCESS,
NULL,
KernelMode,
&RxPointer,
NULL);
if (Status != STATUS_SUCCESS) {
RxPointer = NULL;
}
ZwClose(RxHandle);
} else {
RxHandle = INVALID_HANDLE_VALUE;
}
}
#endif
return((STATUS_SUCCESS));
}
VOID
NTAPI
RxMakeLateDeviceAvailable(
IN PRDBSS_DEVICE_OBJECT RxDeviceObject
)
/*++
Routine Description:
The routine diddles the device object to make a "late device" available.
A late device is one that is not created in the driver's load routine.
Non-late devices are diddled by the driverload code in the io subsystem; but
for late devices we have to do this by hand. This is a routine instead of a
macro in order that other stuff might have to be done here....it's only
executed once per device object.
Arguments:
DeviceObject - where the created device object is to be stored
Return Value:
--
--*/
{
PAGED_CODE();
RxDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
return;
}
VOID
RxpUnregisterMinirdr(
IN PRDBSS_DEVICE_OBJECT RxDeviceObject
)
/*++
Routine Description:
Arguments:
Return Value:
--
--*/
{
PAGED_CODE();
RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), (" RxUnregisterMinirdr Name = %wZ\n",&RxDeviceObject->DeviceName));
ExAcquireFastMutexUnsafe(&RxData.MinirdrRegistrationMutex);
RemoveEntryList(&RxDeviceObject->MiniRdrListLinks);
//no need for interlock.....we're inside the mutex
//InterlockedDecrement(&RxData.NumberOfMinirdrsRegistered);
RxData.NumberOfMinirdrsRegistered--;
if (RxData.NumberOfMinirdrsRegistered == 0) {
// Allow rdbss being unloaded after mini rdr driver is unregistered
RxData.DriverObject->DriverUnload = RxUnload;
}
ExReleaseFastMutexUnsafe(&RxData.MinirdrRegistrationMutex);
if (!FlagOn(RxDeviceObject->RegistrationControls,
RX_REGISTERMINI_FLAG_DONT_INIT_PREFIX_N_SCAVENGER)) {
RxForceNetTableFinalization(RxDeviceObject);
RxFinalizePrefixTable(&RxDeviceObject->RxNetNameTableInDeviceObject);
//no finalization is defined for scavenger structure
}
RxSpinDownOutstandingAsynchronousRequests(RxDeviceObject);
// Spin down any worker threads associated with this minirdr
RxSpinDownMRxDispatcher(RxDeviceObject);
IoDeleteDevice(&RxDeviceObject->DeviceObject);
#ifdef BBT_UPDATE
if (RxPointer != NULL) {
RxHandle = INVALID_HANDLE_VALUE;
KeWaitForSingleObject(
RxPointer,
Executive,
KernelMode,
FALSE,
NULL);
ASSERT(PsIsThreadTerminating(RxPointer));
ObDereferenceObject(RxPointer);
RxPointer = NULL;
}
#endif
}
VOID
RxSpinDownOutstandingAsynchronousRequests(
PRDBSS_DEVICE_OBJECT RxDeviceObject)
/*++
Routine Description:
This routine spins down all the outstanding requests associated with a
mini redirector before it can be unloaded
Arguments:
RxDeviceObject -- the mini redirector's device object
--*/
{
BOOLEAN WaitForSpinDown = FALSE;
KEVENT SpinDownEvent;
KeInitializeEvent(
&SpinDownEvent,
NotificationEvent,
FALSE);
RxAcquireSerializationMutex();
ASSERT(RxDeviceObject->pAsynchronousRequestsCompletionEvent == NULL);
WaitForSpinDown = (RxDeviceObject->AsynchronousRequestsPending != 0);
RxDeviceObject->pAsynchronousRequestsCompletionEvent = &SpinDownEvent;
RxReleaseSerializationMutex();
if (WaitForSpinDown) {
KeWaitForSingleObject(
&SpinDownEvent,
Executive,
KernelMode,
FALSE,
NULL);
}
}
NTSTATUS
RxRegisterAsynchronousRequest(
PRDBSS_DEVICE_OBJECT RxDeviceObject)
/*++
Routine Description:
This routine registers an asynchronous request. On successful completion
the mini redirector cannot be unloaded till the request completes
Arguments:
RxDeviceObject - the mini redirector device object
Return Value:
STATUS_SUCCESS if successful
--*/
{
NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
RxAcquireSerializationMutex();
if (RxDeviceObject->pAsynchronousRequestsCompletionEvent == NULL) {
RxDeviceObject->AsynchronousRequestsPending++;
Status = STATUS_SUCCESS;
}
RxReleaseSerializationMutex();
return Status;
}
VOID
RxDeregisterAsynchronousRequest(
PRDBSS_DEVICE_OBJECT RxDeviceObject)
/*++
Routine Description:
This routine signals the completion of an asynchronous request. It resumes
unloading if required.
Arguments:
RxDeviceObject - the mini redirector device object
--*/
{
PKEVENT pEvent = NULL;
RxAcquireSerializationMutex();
RxDeviceObject->AsynchronousRequestsPending--;
if ((RxDeviceObject->AsynchronousRequestsPending == 0) &&
(RxDeviceObject->pAsynchronousRequestsCompletionEvent != NULL)) {
pEvent = RxDeviceObject->pAsynchronousRequestsCompletionEvent;
}
RxReleaseSerializationMutex();
if (pEvent != NULL) {
KeSetEvent(
pEvent,
IO_NO_INCREMENT,
FALSE);
}
}
#ifdef BBT_UPDATE
WCHAR Request_Name[] = L"\\??\\UNC\\landyw-bear\\bbt\\bbt.txt";
VOID
RxUpdate(PVOID pContext)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
UNICODE_STRING RequestName;
RequestName.Buffer = Request_Name;
RequestName.MaximumLength = wcslen(Request_Name) * sizeof(WCHAR);
RequestName.Length = RequestName.MaximumLength;
InitializeObjectAttributes(
&ObjectAttributes,
&RequestName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
for (;;) {
PHYSICAL_ADDRESS StartAddress;
LARGE_INTEGER NumberOfBytes;
HANDLE FileHandle;
struct {
LIST_ENTRY Link;
SIZE_T Size;
CHAR Data[];
} *Request;
NumberOfBytes.QuadPart = 0x2;
StartAddress.QuadPart = 0;
MmAddPhysicalMemory(
&StartAddress,
&NumberOfBytes);
Request = (PVOID)(StartAddress.QuadPart);
if (Request != NULL) {
Status = ZwCreateFile(
&FileHandle,
(FILE_APPEND_DATA | SYNCHRONIZE),
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
(FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE),
FILE_OPEN,
FILE_NO_INTERMEDIATE_BUFFERING,
NULL,
0);
if (Status == STATUS_SUCCESS) {
LARGE_INTEGER ByteOffset;
ByteOffset.QuadPart = -1;
Status = ZwWriteFile(
FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
Request->Data,
(ULONG)Request->Size,
&ByteOffset,
NULL);
Status = ZwClose(FileHandle);
}
ExFreePool(Request);
}
if (RxHandle == INVALID_HANDLE_VALUE) {
break;
}
}
PsTerminateSystemThread(STATUS_SUCCESS);
}
#endif