1633 lines
40 KiB
C
1633 lines
40 KiB
C
/*++
|
||
|
||
Copyright (c) 1997 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
dispatch.c
|
||
|
||
Abstract:
|
||
|
||
Dispatch routines for the Cluster Network Driver.
|
||
|
||
Author:
|
||
|
||
Mike Massa (mikemas) January 3, 1997
|
||
|
||
Revision History:
|
||
|
||
Who When What
|
||
-------- -------- ----------------------------------------------
|
||
mikemas 01-03-97 created
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
|
||
//
|
||
// Data
|
||
//
|
||
PCN_FSCONTEXT CnExclusiveChannel = NULL;
|
||
|
||
//
|
||
// Un-exported Prototypes
|
||
//
|
||
NTSYSAPI
|
||
NTSTATUS
|
||
NTAPI
|
||
ZwOpenProcess (
|
||
OUT PHANDLE ProcessHandle,
|
||
IN ACCESS_MASK DesiredAccess,
|
||
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||
IN PCLIENT_ID ClientId OPTIONAL
|
||
);
|
||
|
||
//
|
||
// Local Prototypes
|
||
//
|
||
FILE_FULL_EA_INFORMATION UNALIGNED *
|
||
CnFindEA(
|
||
PFILE_FULL_EA_INFORMATION StartEA,
|
||
CHAR *TargetName,
|
||
USHORT TargetNameLength
|
||
);
|
||
|
||
NTSTATUS
|
||
CnCreate(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
);
|
||
|
||
NTSTATUS
|
||
CnCleanup(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
);
|
||
|
||
NTSTATUS
|
||
CnClose(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
);
|
||
|
||
NTSTATUS
|
||
CnEnableShutdownOnClose(
|
||
PIRP Irp
|
||
);
|
||
|
||
//
|
||
// Mark pageable code.
|
||
//
|
||
#ifdef ALLOC_PRAGMA
|
||
|
||
#pragma alloc_text(PAGE, CnDispatchDeviceControl)
|
||
#pragma alloc_text(PAGE, CnFindEA)
|
||
#pragma alloc_text(PAGE, CnCreate)
|
||
#pragma alloc_text(PAGE, CnEnableShutdownOnClose)
|
||
|
||
#endif // ALLOC_PRAGMA
|
||
|
||
|
||
|
||
//
|
||
// Function definitions
|
||
//
|
||
VOID
|
||
CnDereferenceFsContext(
|
||
PCN_FSCONTEXT FsContext
|
||
)
|
||
{
|
||
LONG newValue = InterlockedDecrement(&(FsContext->ReferenceCount));
|
||
|
||
|
||
CnAssert(newValue >= 0);
|
||
|
||
if (newValue != 0) {
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Set the cleanup event.
|
||
//
|
||
KeSetEvent(&(FsContext->CleanupEvent), 0, FALSE);
|
||
|
||
return;
|
||
|
||
} // CnDereferenceFsContext
|
||
|
||
|
||
NTSTATUS
|
||
CnMarkRequestPending(
|
||
PIRP Irp,
|
||
PIO_STACK_LOCATION IrpSp,
|
||
PDRIVER_CANCEL CancelRoutine
|
||
)
|
||
/*++
|
||
|
||
Notes:
|
||
|
||
Called with IoCancelSpinLock held.
|
||
|
||
--*/
|
||
{
|
||
PCN_FSCONTEXT fsContext = (PCN_FSCONTEXT) IrpSp->FileObject->FsContext;
|
||
CN_IRQL oldIrql;
|
||
|
||
//
|
||
// Set up for cancellation
|
||
//
|
||
CnAssert(Irp->CancelRoutine == NULL);
|
||
|
||
if (!Irp->Cancel) {
|
||
|
||
IoMarkIrpPending(Irp);
|
||
IoSetCancelRoutine(Irp, CancelRoutine);
|
||
|
||
CnReferenceFsContext(fsContext);
|
||
|
||
IF_CNDBG(CN_DEBUG_IRP) {
|
||
CNPRINT((
|
||
"[Clusnet] Pending irp %p fileobj %p.\n",
|
||
Irp,
|
||
IrpSp->FileObject
|
||
));
|
||
}
|
||
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
//
|
||
// The IRP has already been cancelled.
|
||
//
|
||
|
||
IF_CNDBG(CN_DEBUG_IRP) {
|
||
CNPRINT(("[Clusnet] irp %p already cancelled.\n", Irp));
|
||
}
|
||
|
||
return(STATUS_CANCELLED);
|
||
|
||
} // CnPrepareIrpForCancel
|
||
|
||
|
||
|
||
VOID
|
||
CnCompletePendingRequest(
|
||
IN PIRP Irp,
|
||
IN NTSTATUS Status,
|
||
IN ULONG BytesReturned
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Completes a pending request.
|
||
|
||
Arguments:
|
||
|
||
Irp - A pointer to the IRP for this request.
|
||
Status - The final status of the request.
|
||
BytesReturned - Bytes sent/received information.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
Notes:
|
||
|
||
Called with IoCancelSpinLock held. Lock Irql is stored in Irp->CancelIrql.
|
||
Releases IoCancelSpinLock before returning.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIO_STACK_LOCATION irpSp;
|
||
PCN_FSCONTEXT fsContext;
|
||
|
||
|
||
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
fsContext = (PCN_FSCONTEXT) irpSp->FileObject->FsContext;
|
||
|
||
|
||
IoSetCancelRoutine(Irp, NULL);
|
||
|
||
CnDereferenceFsContext(fsContext);
|
||
|
||
IF_CNDBG(CN_DEBUG_IRP) {
|
||
CNPRINT((
|
||
"[Clusnet] Completing irp %p fileobj %p, status %lx\n",
|
||
Irp,
|
||
irpSp->FileObject,
|
||
Status
|
||
));
|
||
}
|
||
|
||
if (Irp->Cancel || fsContext->CancelIrps) {
|
||
|
||
IF_CNDBG(CN_DEBUG_IRP) {
|
||
CNPRINT(("[Clusnet] Completed irp %p was cancelled\n", Irp));
|
||
}
|
||
|
||
Status = (NTSTATUS) STATUS_CANCELLED;
|
||
BytesReturned = 0;
|
||
}
|
||
|
||
CnReleaseCancelSpinLock(Irp->CancelIrql);
|
||
|
||
Irp->IoStatus.Status = (NTSTATUS) Status;
|
||
Irp->IoStatus.Information = BytesReturned;
|
||
|
||
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
||
|
||
return;
|
||
|
||
} // CnCompletePendingRequest
|
||
|
||
|
||
|
||
PFILE_OBJECT
|
||
CnBeginCancelRoutine(
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Performs common bookkeeping for irp cancellation.
|
||
|
||
Arguments:
|
||
|
||
Irp - Pointer to I/O request packet
|
||
|
||
Return Value:
|
||
|
||
A pointer to the file object on which the irp was submitted.
|
||
This value must be passed to CnEndCancelRequest().
|
||
|
||
Notes:
|
||
|
||
Called with cancel spinlock held.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIO_STACK_LOCATION irpSp;
|
||
PCN_FSCONTEXT fsContext;
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
PFILE_OBJECT fileObject;
|
||
|
||
|
||
CnAssert(Irp->Cancel);
|
||
|
||
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
fileObject = irpSp->FileObject;
|
||
fsContext = (PCN_FSCONTEXT) fileObject->FsContext;
|
||
|
||
IoSetCancelRoutine(Irp, NULL);
|
||
|
||
//
|
||
// Add a reference so the object can't be closed while the cancel routine
|
||
// is executing.
|
||
//
|
||
CnReferenceFsContext(fsContext);
|
||
|
||
IF_CNDBG(CN_DEBUG_IRP) {
|
||
CNPRINT((
|
||
"[Clusnet] Cancelling irp %p fileobj %p\n",
|
||
Irp,
|
||
fileObject
|
||
));
|
||
}
|
||
|
||
return(fileObject);
|
||
|
||
} // CnBeginCancelRoutine
|
||
|
||
|
||
|
||
VOID
|
||
CnEndCancelRoutine(
|
||
PFILE_OBJECT FileObject
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Performs common bookkeeping for irp cancellation.
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
Notes:
|
||
|
||
Called with cancel spinlock held.
|
||
|
||
--*/
|
||
{
|
||
|
||
PCN_FSCONTEXT fsContext = (PCN_FSCONTEXT) FileObject->FsContext;
|
||
|
||
|
||
//
|
||
// Remove the reference placed on the endpoint by the cancel routine.
|
||
//
|
||
CnDereferenceFsContext(fsContext);
|
||
|
||
IF_CNDBG(CN_DEBUG_IRP) {
|
||
CNPRINT((
|
||
"[Clusnet] Finished cancelling, fileobj %p\n",
|
||
FileObject
|
||
));
|
||
}
|
||
|
||
return;
|
||
|
||
} // CnEndCancelRoutine
|
||
|
||
|
||
|
||
NTSTATUS
|
||
CnDispatchInternalDeviceControl(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the dispatch routine for Internal Device Control IRPs.
|
||
This is the hot path for kernel-mode TDI clients.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to device object for target device
|
||
Irp - Pointer to I/O request packet
|
||
|
||
Return Value:
|
||
|
||
An NT status code.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
ULONG fileType = (ULONG)((ULONG_PTR)irpSp->FileObject->FsContext2);
|
||
#if DBG
|
||
KIRQL entryIrql = KeGetCurrentIrql();
|
||
#endif // DBG
|
||
|
||
|
||
Irp->IoStatus.Information = 0;
|
||
|
||
if (DeviceObject == CdpDeviceObject) {
|
||
if (fileType == TDI_TRANSPORT_ADDRESS_FILE) {
|
||
if (irpSp->MinorFunction == TDI_SEND_DATAGRAM) {
|
||
status = CxSendDatagram(Irp, irpSp);
|
||
|
||
#if DBG
|
||
CnAssert(entryIrql == KeGetCurrentIrql());
|
||
#endif // DBG
|
||
return(status);
|
||
}
|
||
else if (irpSp->MinorFunction == TDI_RECEIVE_DATAGRAM) {
|
||
status = CxReceiveDatagram(Irp, irpSp);
|
||
#if DBG
|
||
CnAssert(entryIrql == KeGetCurrentIrql());
|
||
#endif // DBG
|
||
return(status);
|
||
}
|
||
else if (irpSp->MinorFunction == TDI_SET_EVENT_HANDLER) {
|
||
status = CxSetEventHandler(Irp, irpSp);
|
||
|
||
#if DBG
|
||
CnAssert(entryIrql == KeGetCurrentIrql());
|
||
#endif // DBG
|
||
|
||
return(status);
|
||
}
|
||
|
||
//
|
||
// Fall through to common code.
|
||
//
|
||
}
|
||
|
||
//
|
||
// These functions are common to all endpoint types.
|
||
//
|
||
switch(irpSp->MinorFunction) {
|
||
|
||
case TDI_QUERY_INFORMATION:
|
||
status = CxQueryInformation(Irp, irpSp);
|
||
break;
|
||
|
||
case TDI_SET_INFORMATION:
|
||
case TDI_ACTION:
|
||
CNPRINT((
|
||
"[Clusnet] Call to unimplemented TDI function 0x%x\n",
|
||
irpSp->MinorFunction
|
||
));
|
||
status = STATUS_NOT_IMPLEMENTED;
|
||
break;
|
||
|
||
default:
|
||
CNPRINT((
|
||
"[Clusnet] Call to invalid TDI function 0x%x\n",
|
||
irpSp->MinorFunction
|
||
));
|
||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
}
|
||
else {
|
||
CNPRINT((
|
||
"[Clusnet] Invalid internal device control function 0x%x on device %ws\n",
|
||
irpSp->MinorFunction,
|
||
DD_CLUSNET_DEVICE_NAME
|
||
));
|
||
|
||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
||
|
||
#if DBG
|
||
CnAssert(entryIrql == KeGetCurrentIrql());
|
||
#endif // DBG
|
||
|
||
return(status);
|
||
|
||
} // CnDispatchInternalDeviceControl
|
||
|
||
|
||
|
||
NTSTATUS
|
||
CnDispatchDeviceControl(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the top-level dispatch routine for Device Control IRPs.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to device object for target device
|
||
Irp - Pointer to I/O request packet
|
||
|
||
Return Value:
|
||
|
||
An NT status code.
|
||
|
||
Notes:
|
||
|
||
This routine completes any IRPs for which the return code is not
|
||
STATUS_PENDING.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
CCHAR ioIncrement = IO_NO_INCREMENT;
|
||
BOOLEAN resourceAcquired = FALSE;
|
||
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
ULONG ioControlCode =
|
||
irpSp->Parameters.DeviceIoControl.IoControlCode;
|
||
ULONG fileType =
|
||
(ULONG) ((ULONG_PTR) irpSp->FileObject->FsContext2);
|
||
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Set this in advance. Any subsequent dispatch routine that cares
|
||
// about it will modify it itself.
|
||
//
|
||
Irp->IoStatus.Information = 0;
|
||
|
||
//
|
||
// The following commands are valid on only TDI address objects.
|
||
//
|
||
if (fileType == TDI_TRANSPORT_ADDRESS_FILE) {
|
||
if (ioControlCode == IOCTL_CX_IGNORE_NODE_STATE) {
|
||
status = CxDispatchDeviceControl(Irp, irpSp);
|
||
}
|
||
else {
|
||
//
|
||
// Not handled. Return an error.
|
||
//
|
||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
|
||
goto complete_request;
|
||
}
|
||
|
||
//
|
||
// The remaining commands are valid for control channels.
|
||
//
|
||
CnAssert(fileType == TDI_CONTROL_CHANNEL_FILE);
|
||
|
||
//
|
||
// The following set of commands affect only this file object and
|
||
// can be issued at any time. We do not need to hold the CnResource
|
||
// in order to process them. Nor do we need to be in the initialized.
|
||
// state.
|
||
//
|
||
switch(ioControlCode) {
|
||
|
||
case IOCTL_CLUSNET_SET_EVENT_MASK:
|
||
{
|
||
PCN_FSCONTEXT fsContext = irpSp->FileObject->FsContext;
|
||
PCLUSNET_SET_EVENT_MASK_REQUEST request;
|
||
ULONG requestSize;
|
||
|
||
|
||
request = (PCLUSNET_SET_EVENT_MASK_REQUEST)
|
||
Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
requestSize =
|
||
irpSp->Parameters.DeviceIoControl.InputBufferLength;
|
||
|
||
if (requestSize >= sizeof(CLUSNET_SET_EVENT_MASK_REQUEST))
|
||
{
|
||
//
|
||
// Kernel mode callers must supply a callback.
|
||
// User mode callers must not.
|
||
//
|
||
if ( !( (Irp->RequestorMode == KernelMode) &&
|
||
(request->KmodeEventCallback == NULL)
|
||
)
|
||
&&
|
||
!( (Irp->RequestorMode == UserMode) &&
|
||
(request->KmodeEventCallback != NULL)
|
||
)
|
||
)
|
||
{
|
||
status = CnSetEventMask( fsContext, request );
|
||
}
|
||
else {
|
||
status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
}
|
||
else {
|
||
status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
}
|
||
goto complete_request;
|
||
|
||
case IOCTL_CLUSNET_GET_NEXT_EVENT:
|
||
{
|
||
PCLUSNET_EVENT_RESPONSE response;
|
||
ULONG responseSize;
|
||
|
||
|
||
responseSize =
|
||
irpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
||
|
||
if ( (responseSize < sizeof(CLUSNET_EVENT_RESPONSE))) {
|
||
|
||
status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
else {
|
||
status = CnGetNextEvent( Irp, irpSp );
|
||
ioIncrement = IO_NETWORK_INCREMENT;
|
||
}
|
||
}
|
||
goto complete_request;
|
||
|
||
} // end of switch
|
||
|
||
//
|
||
// Not handled yet. Fall through.
|
||
//
|
||
|
||
if (ClusnetIsGeneralIoctl(ioControlCode)) {
|
||
|
||
if (!ClusnetIsNTEIoctl(ioControlCode)) {
|
||
|
||
//
|
||
// The following commands require exclusive access to CnResource.
|
||
//
|
||
resourceAcquired = CnAcquireResourceExclusive(
|
||
CnResource,
|
||
TRUE
|
||
);
|
||
|
||
if (!resourceAcquired) {
|
||
CnAssert(resourceAcquired == TRUE);
|
||
status = STATUS_UNSUCCESSFUL;
|
||
goto complete_request;
|
||
}
|
||
|
||
switch(ioControlCode) {
|
||
|
||
case IOCTL_CLUSNET_INITIALIZE:
|
||
|
||
if (CnState == CnStateShutdown) {
|
||
PCLUSNET_INITIALIZE_REQUEST request;
|
||
ULONG requestSize;
|
||
|
||
request = (PCLUSNET_INITIALIZE_REQUEST)
|
||
Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
requestSize =
|
||
irpSp->Parameters.DeviceIoControl.InputBufferLength;
|
||
|
||
if (requestSize < sizeof(CLUSNET_INITIALIZE_REQUEST)) {
|
||
status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
else {
|
||
status = CnInitialize(
|
||
request->LocalNodeId,
|
||
request->MaxNodes
|
||
);
|
||
}
|
||
}
|
||
else {
|
||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
|
||
goto complete_request;
|
||
|
||
case IOCTL_CLUSNET_ENABLE_SHUTDOWN_ON_CLOSE:
|
||
status = CnEnableShutdownOnClose(Irp);
|
||
goto complete_request;
|
||
|
||
case IOCTL_CLUSNET_DISABLE_SHUTDOWN_ON_CLOSE:
|
||
{
|
||
PCN_FSCONTEXT fsContext = irpSp->FileObject->FsContext;
|
||
|
||
fsContext->ShutdownOnClose = FALSE;
|
||
|
||
if ( ClussvcProcessHandle ) {
|
||
|
||
CnCloseProcessHandle( &ClussvcProcessHandle );
|
||
ClussvcProcessHandle = NULL;
|
||
}
|
||
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
goto complete_request;
|
||
|
||
case IOCTL_CLUSNET_HALT:
|
||
status = CnShutdown();
|
||
|
||
CnReleaseResourceForThread(
|
||
CnResource,
|
||
(ERESOURCE_THREAD) PsGetCurrentThread()
|
||
);
|
||
|
||
resourceAcquired = FALSE;
|
||
|
||
//
|
||
// Issue a Halt event. If clusdisk still has a handle
|
||
// to clusnet, then it will release its reservations.
|
||
//
|
||
CnIssueEvent( ClusnetEventHalt, 0, 0 );
|
||
|
||
goto complete_request;
|
||
|
||
case IOCTL_CLUSNET_SHUTDOWN:
|
||
status = CnShutdown();
|
||
goto complete_request;
|
||
|
||
case IOCTL_CLUSNET_SET_MEMORY_LOGGING:
|
||
{
|
||
PCLUSNET_SET_MEM_LOGGING_REQUEST request;
|
||
ULONG requestSize;
|
||
|
||
request = (PCLUSNET_SET_MEM_LOGGING_REQUEST)
|
||
Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
requestSize =
|
||
irpSp->Parameters.DeviceIoControl.InputBufferLength;
|
||
|
||
if ( (requestSize < sizeof(CLUSNET_SET_MEM_LOGGING_REQUEST))) {
|
||
|
||
status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
else {
|
||
|
||
status = CnSetMemLogging( request );
|
||
}
|
||
}
|
||
goto complete_request;
|
||
#if DBG
|
||
case IOCTL_CLUSNET_SET_DEBUG_MASK:
|
||
{
|
||
PCLUSNET_SET_DEBUG_MASK_REQUEST request;
|
||
ULONG requestSize;
|
||
|
||
request = (PCLUSNET_SET_DEBUG_MASK_REQUEST)
|
||
Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
requestSize =
|
||
irpSp->Parameters.DeviceIoControl.InputBufferLength;
|
||
|
||
if (requestSize < sizeof(CLUSNET_SET_DEBUG_MASK_REQUEST)) {
|
||
status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
else {
|
||
CnDebug = request->DebugMask;
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
}
|
||
goto complete_request;
|
||
#endif // DBG
|
||
|
||
} // end switch
|
||
|
||
} else {
|
||
|
||
//
|
||
// The following commands are only valid if we are
|
||
// in the initialized state. The resource is
|
||
// acquired to start the operation in the proper
|
||
// state; however, the dispatched routines are
|
||
// reentrant, so the resource can be released before
|
||
// the IRPs complete.
|
||
//
|
||
|
||
resourceAcquired = CnAcquireResourceShared(
|
||
CnResource,
|
||
TRUE
|
||
);
|
||
|
||
if (!resourceAcquired) {
|
||
CnAssert(resourceAcquired == TRUE);
|
||
status = STATUS_UNSUCCESSFUL;
|
||
goto complete_request;
|
||
}
|
||
|
||
if (CnState != CnStateInitialized) {
|
||
status = STATUS_DEVICE_NOT_READY;
|
||
goto complete_request;
|
||
}
|
||
|
||
switch(ioControlCode) {
|
||
|
||
case IOCTL_CLUSNET_ADD_NTE:
|
||
|
||
status = IpaAddNTE(Irp, irpSp);
|
||
|
||
goto complete_request;
|
||
|
||
case IOCTL_CLUSNET_DELETE_NTE:
|
||
|
||
status = IpaDeleteNTE(Irp, irpSp);
|
||
|
||
goto complete_request;
|
||
|
||
case IOCTL_CLUSNET_SET_NTE_ADDRESS:
|
||
|
||
status = IpaSetNTEAddress(Irp, irpSp);
|
||
|
||
goto complete_request;
|
||
|
||
case IOCTL_CLUSNET_ADD_NBT_INTERFACE:
|
||
{
|
||
PNETBT_ADD_DEL_IF request;
|
||
ULONG requestSize;
|
||
PNETBT_ADD_DEL_IF response;
|
||
ULONG responseSize;
|
||
|
||
|
||
request = (PNETBT_ADD_DEL_IF)
|
||
Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
requestSize =
|
||
irpSp->Parameters.DeviceIoControl.InputBufferLength;
|
||
|
||
responseSize =
|
||
irpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
||
|
||
response = (PNETBT_ADD_DEL_IF) request;
|
||
|
||
if ( (requestSize < sizeof(NETBT_ADD_DEL_IF)) ||
|
||
(responseSize < sizeof(NETBT_ADD_DEL_IF))
|
||
)
|
||
{
|
||
status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
else {
|
||
status = NbtAddIf(
|
||
request,
|
||
requestSize,
|
||
response,
|
||
&responseSize
|
||
);
|
||
|
||
CnAssert(status != STATUS_PENDING);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
Irp->IoStatus.Information = responseSize;
|
||
}
|
||
}
|
||
}
|
||
goto complete_request;
|
||
|
||
case IOCTL_CLUSNET_DEL_NBT_INTERFACE:
|
||
{
|
||
PNETBT_ADD_DEL_IF request;
|
||
ULONG requestSize;
|
||
|
||
|
||
request = (PNETBT_ADD_DEL_IF)
|
||
Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
requestSize =
|
||
irpSp->Parameters.DeviceIoControl.InputBufferLength;
|
||
|
||
if (requestSize < sizeof(NETBT_ADD_DEL_IF)) {
|
||
status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
else {
|
||
status = NbtDeleteIf(request, requestSize);
|
||
|
||
CnAssert(status != STATUS_PENDING);
|
||
}
|
||
}
|
||
goto complete_request;
|
||
|
||
} // end switch
|
||
}
|
||
|
||
//
|
||
// Not handled. Return an error.
|
||
//
|
||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||
goto complete_request;
|
||
}
|
||
else {
|
||
//
|
||
// The following commands require shared access to CnResource.
|
||
// They are only valid in the initialized state.
|
||
//
|
||
resourceAcquired = CnAcquireResourceShared(CnResource, TRUE);
|
||
|
||
if (!resourceAcquired) {
|
||
CnAssert(resourceAcquired == TRUE);
|
||
status = STATUS_UNSUCCESSFUL;
|
||
goto complete_request;
|
||
}
|
||
|
||
if (CnState == CnStateInitialized) {
|
||
if (ClusnetIsTransportIoctl(ioControlCode)) {
|
||
status = CxDispatchDeviceControl(Irp, irpSp);
|
||
}
|
||
else {
|
||
//
|
||
// Not handled. Return an error.
|
||
//
|
||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
}
|
||
else {
|
||
//
|
||
// We haven't been initialized yet. Return an error.
|
||
//
|
||
status = STATUS_DEVICE_NOT_READY;
|
||
}
|
||
}
|
||
|
||
complete_request:
|
||
|
||
if (resourceAcquired) {
|
||
CnReleaseResourceForThread(
|
||
CnResource,
|
||
(ERESOURCE_THREAD) PsGetCurrentThread()
|
||
);
|
||
}
|
||
|
||
if (status != STATUS_PENDING) {
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest(Irp, ioIncrement);
|
||
}
|
||
|
||
return(status);
|
||
|
||
} // CnDispatchDeviceControl
|
||
|
||
|
||
|
||
NTSTATUS
|
||
CnDispatch(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the generic dispatch routine for the driver.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to device object for target device
|
||
Irp - Pointer to I/O request packet
|
||
|
||
Return Value:
|
||
|
||
An NT status code.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
#if DBG
|
||
KIRQL entryIrql = KeGetCurrentIrql();
|
||
#endif // DBG
|
||
|
||
|
||
PAGED_CODE();
|
||
|
||
CnAssert(irpSp->MajorFunction != IRP_MJ_INTERNAL_DEVICE_CONTROL);
|
||
|
||
switch (irpSp->MajorFunction) {
|
||
|
||
case IRP_MJ_CREATE:
|
||
status = CnCreate(DeviceObject, Irp, irpSp);
|
||
break;
|
||
|
||
case IRP_MJ_CLEANUP:
|
||
status = CnCleanup(DeviceObject, Irp, irpSp);
|
||
break;
|
||
|
||
case IRP_MJ_CLOSE:
|
||
status = CnClose(DeviceObject, Irp, irpSp);
|
||
break;
|
||
|
||
case IRP_MJ_SHUTDOWN:
|
||
IF_CNDBG(CN_DEBUG_INIT) {
|
||
CNPRINT(("[ClusNet] Processing shutdown notification...\n"));
|
||
}
|
||
|
||
{
|
||
BOOLEAN acquired = CnAcquireResourceExclusive(
|
||
CnResource,
|
||
TRUE
|
||
);
|
||
|
||
CnAssert(acquired == TRUE);
|
||
|
||
(VOID) CnShutdown();
|
||
|
||
if (acquired) {
|
||
CnReleaseResourceForThread(
|
||
CnResource,
|
||
(ERESOURCE_THREAD) PsGetCurrentThread()
|
||
);
|
||
}
|
||
|
||
//
|
||
// Issue a Halt event. If clusdisk still has a handle
|
||
// to clusnet, then it will release its reservations
|
||
//
|
||
CnIssueEvent( ClusnetEventHalt, 0, 0 );
|
||
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
|
||
IF_CNDBG(CN_DEBUG_INIT) {
|
||
CNPRINT(("[ClusNet] Shutdown processing complete.\n"));
|
||
}
|
||
|
||
break;
|
||
|
||
default:
|
||
IF_CNDBG(CN_DEBUG_IRP) {
|
||
CNPRINT((
|
||
"[ClusNet] Received IRP with unsupported "
|
||
"major function 0x%lx\n",
|
||
irpSp->MajorFunction
|
||
));
|
||
}
|
||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||
break;
|
||
}
|
||
|
||
CnAssert(status != STATUS_PENDING);
|
||
|
||
Irp->IoStatus.Status = status;
|
||
Irp->IoStatus.Information = 0;
|
||
|
||
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
||
|
||
#if DBG
|
||
CnAssert(entryIrql == KeGetCurrentIrql());
|
||
#endif // DBG
|
||
|
||
return(status);
|
||
|
||
} // CnDispatch
|
||
|
||
|
||
|
||
NTSTATUS
|
||
CnCreate(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Handler for create IRPs.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to the device object for this request.
|
||
Irp - Pointer to I/O request packet
|
||
|
||
Return Value:
|
||
|
||
An NT status code.
|
||
|
||
Notes:
|
||
|
||
This routine never returns STATUS_PENDING.
|
||
The calling routine must complete the IRP.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCN_FSCONTEXT fsContext;
|
||
FILE_FULL_EA_INFORMATION *ea;
|
||
FILE_FULL_EA_INFORMATION UNALIGNED *targetEA;
|
||
NTSTATUS status;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Reject unathorized opens
|
||
//
|
||
if ( (IrpSp->FileObject->RelatedFileObject != NULL) ||
|
||
(IrpSp->FileObject->FileName.Length != 0)
|
||
)
|
||
{
|
||
return(STATUS_ACCESS_DENIED);
|
||
}
|
||
|
||
ea = (PFILE_FULL_EA_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
if ((DeviceObject == CdpDeviceObject) && (ea != NULL)) {
|
||
|
||
IF_CNDBG(CN_DEBUG_OPEN) {
|
||
CNPRINT((
|
||
"[ClusNet] Opening address object, file object %p\n",
|
||
IrpSp->FileObject
|
||
));
|
||
}
|
||
|
||
//
|
||
// This is the CDP device. This should be an address object open.
|
||
//
|
||
targetEA = CnFindEA(
|
||
ea,
|
||
TdiTransportAddress,
|
||
TDI_TRANSPORT_ADDRESS_LENGTH
|
||
);
|
||
|
||
if (targetEA != NULL) {
|
||
IrpSp->FileObject->FsContext2 = (PVOID)
|
||
TDI_TRANSPORT_ADDRESS_FILE;
|
||
|
||
//
|
||
// Open an address object. This will also allocate the common
|
||
// file object context structure.
|
||
//
|
||
status = CxOpenAddress(
|
||
&fsContext,
|
||
(TRANSPORT_ADDRESS UNALIGNED *)
|
||
&(targetEA->EaName[targetEA->EaNameLength + 1]),
|
||
targetEA->EaValueLength
|
||
);
|
||
}
|
||
else {
|
||
IF_CNDBG(CN_DEBUG_OPEN) {
|
||
CNPRINT((
|
||
"[ClusNet] No transport address in EA!\n"
|
||
));
|
||
}
|
||
status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
}
|
||
else {
|
||
//
|
||
// This is a control channel open.
|
||
//
|
||
IF_CNDBG(CN_DEBUG_OPEN) {
|
||
IF_CNDBG(CN_DEBUG_OPEN) {
|
||
CNPRINT((
|
||
"[ClusNet] Opening control channel, file object %p\n",
|
||
IrpSp->FileObject
|
||
));
|
||
}
|
||
}
|
||
|
||
//
|
||
// Allocate our common file object context structure.
|
||
//
|
||
fsContext = CnAllocatePool(sizeof(CN_FSCONTEXT));
|
||
|
||
if (fsContext != NULL) {
|
||
IrpSp->FileObject->FsContext2 = (PVOID) TDI_CONTROL_CHANNEL_FILE;
|
||
CN_INIT_SIGNATURE(fsContext, CN_CONTROL_CHANNEL_SIG);
|
||
|
||
//
|
||
// Check the sharing flags. If this is an exclusive open, check
|
||
// to make sure there isn't already an exclusive open outstanding.
|
||
//
|
||
if (IrpSp->Parameters.Create.ShareAccess == 0) {
|
||
BOOLEAN acquired = CnAcquireResourceExclusive(
|
||
CnResource,
|
||
TRUE
|
||
);
|
||
|
||
CnAssert(acquired == TRUE);
|
||
|
||
if (CnExclusiveChannel == NULL) {
|
||
CnExclusiveChannel = fsContext;
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
else {
|
||
CnFreePool(fsContext);
|
||
status = STATUS_SHARING_VIOLATION;
|
||
}
|
||
|
||
if (acquired) {
|
||
CnReleaseResourceForThread(
|
||
CnResource,
|
||
(ERESOURCE_THREAD) PsGetCurrentThread()
|
||
);
|
||
}
|
||
}
|
||
else {
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
}
|
||
else {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
}
|
||
|
||
if (status == STATUS_SUCCESS) {
|
||
IrpSp->FileObject->FsContext = fsContext;
|
||
|
||
fsContext->FileObject = IrpSp->FileObject;
|
||
fsContext->ReferenceCount = 1;
|
||
fsContext->CancelIrps = FALSE;
|
||
fsContext->ShutdownOnClose = FALSE;
|
||
|
||
KeInitializeEvent(
|
||
&(fsContext->CleanupEvent),
|
||
SynchronizationEvent,
|
||
FALSE
|
||
);
|
||
|
||
//
|
||
// init the Event list stuff. We use the empty list test on the
|
||
// Linkage field to see if this context block is already been linked
|
||
// to the event file object list
|
||
//
|
||
fsContext->EventMask = 0;
|
||
InitializeListHead( &fsContext->EventList );
|
||
InitializeListHead( &fsContext->Linkage );
|
||
fsContext->EventIrp = NULL;
|
||
}
|
||
|
||
return(status);
|
||
|
||
} // CnCreate
|
||
|
||
|
||
|
||
NTSTATUS
|
||
CnCleanup(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Cancels all outstanding Irps on a device object and waits for them to be
|
||
completed before returning.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to the device object on which the Irp was received.
|
||
Irp - Pointer to I/O request packet
|
||
IrpSp - Pointer to the current stack location in the Irp.
|
||
|
||
Return Value:
|
||
|
||
An NT status code.
|
||
|
||
Notes:
|
||
|
||
This routine may block.
|
||
This routine never returns STATUS_PENDING.
|
||
The calling routine must complete the IRP.
|
||
|
||
--*/
|
||
|
||
{
|
||
CN_IRQL oldIrql;
|
||
NTSTATUS status;
|
||
ULONG fileType =
|
||
(ULONG)((ULONG_PTR)IrpSp->FileObject->FsContext2);
|
||
PCN_FSCONTEXT fsContext = (PCN_FSCONTEXT) IrpSp->FileObject->FsContext;
|
||
PLIST_ENTRY EventEntry;
|
||
PIRP eventIrp;
|
||
|
||
|
||
if (fileType == TDI_TRANSPORT_ADDRESS_FILE) {
|
||
//
|
||
// This is an address object.
|
||
//
|
||
CnAssert(DeviceObject == CdpDeviceObject);
|
||
|
||
status = CxCloseAddress(fsContext);
|
||
}
|
||
else {
|
||
//
|
||
// This is a control channel.
|
||
//
|
||
CnAssert(fileType == TDI_CONTROL_CHANNEL_FILE);
|
||
|
||
//
|
||
// If this channel has a shutdown trigger enabled,
|
||
// shutdown the driver.
|
||
//
|
||
if (fsContext->ShutdownOnClose) {
|
||
|
||
BOOLEAN shutdownScheduled;
|
||
|
||
//
|
||
// Bug 303422: CnShutdown closes handles that were opened
|
||
// in the context of the system process. However, attaching
|
||
// to the system process during shutdown can cause a
|
||
// bugcheck under certain conditions. The only alternative
|
||
// is to defer executing of CnShutdown to a system worker
|
||
// thread.
|
||
//
|
||
// Rather than creating a new event object, leverage the
|
||
// cleanup event in the fscontext. It is reset before use
|
||
// below.
|
||
//
|
||
KeClearEvent(&(fsContext->CleanupEvent));
|
||
|
||
shutdownScheduled = CnHaltOperation(&(fsContext->CleanupEvent));
|
||
|
||
if (shutdownScheduled) {
|
||
status = KeWaitForSingleObject(
|
||
&(fsContext->CleanupEvent),
|
||
(Irp->RequestorMode == KernelMode
|
||
? Executive : UserRequest),
|
||
KernelMode,
|
||
FALSE,
|
||
NULL
|
||
);
|
||
|
||
CnAssert(NT_SUCCESS(status));
|
||
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// issue a Halt event. If clusdisk still has a handle
|
||
// to clusnet, then it will release its reservations
|
||
//
|
||
CnIssueEvent( ClusnetEventHalt, 0, 0 );
|
||
}
|
||
|
||
//
|
||
// if this guy forgot to clear the event mask before
|
||
// closing the handle, do the appropriate cleanup
|
||
// now.
|
||
//
|
||
|
||
if ( fsContext->EventMask ) {
|
||
CLUSNET_SET_EVENT_MASK_REQUEST EventRequest;
|
||
|
||
EventRequest.EventMask = 0;
|
||
|
||
//
|
||
// cannot proceed if CnSetEventMask returns a timeout
|
||
// error. this indicates that the fsContext has not
|
||
// been removed from the EventFileHandles list because
|
||
// of lock starvation.
|
||
do {
|
||
status = CnSetEventMask( fsContext, &EventRequest );
|
||
} while ( status == STATUS_TIMEOUT );
|
||
CnAssert( status == STATUS_SUCCESS );
|
||
}
|
||
|
||
CnAcquireCancelSpinLock( &oldIrql );
|
||
CnAcquireLockAtDpc( &EventLock );
|
||
|
||
if ( fsContext->EventIrp != NULL ) {
|
||
|
||
eventIrp = fsContext->EventIrp;
|
||
fsContext->EventIrp = NULL;
|
||
|
||
CnReleaseLockFromDpc( &EventLock );
|
||
eventIrp->CancelIrql = oldIrql;
|
||
CnCompletePendingRequest(eventIrp, STATUS_CANCELLED, 0);
|
||
} else {
|
||
CnReleaseLockFromDpc( &EventLock );
|
||
CnReleaseCancelSpinLock( oldIrql );
|
||
}
|
||
}
|
||
|
||
//
|
||
// Remove the initial reference and wait for all pending work
|
||
// to complete.
|
||
//
|
||
fsContext->CancelIrps = TRUE;
|
||
KeResetEvent(&(fsContext->CleanupEvent));
|
||
|
||
CnDereferenceFsContext(fsContext);
|
||
|
||
IF_CNDBG(CN_DEBUG_CLEANUP) {
|
||
CNPRINT((
|
||
"[ClusNet] Waiting for completion of Irps on file object %p\n",
|
||
IrpSp->FileObject
|
||
));
|
||
}
|
||
|
||
status = KeWaitForSingleObject(
|
||
&(fsContext->CleanupEvent),
|
||
(Irp->RequestorMode == KernelMode ? Executive : UserRequest),
|
||
KernelMode,
|
||
FALSE,
|
||
NULL
|
||
);
|
||
|
||
CnAssert(NT_SUCCESS(status));
|
||
|
||
status = STATUS_SUCCESS;
|
||
|
||
IF_CNDBG(CN_DEBUG_CLEANUP) {
|
||
CNPRINT((
|
||
"[Clusnet] Wait on file object %p finished\n",
|
||
IrpSp->FileObject
|
||
));
|
||
}
|
||
|
||
return(status);
|
||
|
||
} // CnCleanup
|
||
|
||
|
||
|
||
NTSTATUS
|
||
CnClose(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Dispatch routine for MJ_CLOSE IRPs. Performs final cleanup of the
|
||
open file object.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to the device object on which the Irp was received.
|
||
Irp - Pointer to I/O request packet
|
||
IrpSp - Pointer to the current stack location in the Irp.
|
||
|
||
Return Value:
|
||
|
||
An NT status code.
|
||
|
||
Notes:
|
||
|
||
This routine never returns STATUS_PENDING.
|
||
The calling routine must complete the IRP.
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOLEAN acquired;
|
||
PCN_FSCONTEXT fsContext = (PCN_FSCONTEXT) IrpSp->FileObject->FsContext;
|
||
ULONG fileType =
|
||
(ULONG)((ULONG_PTR)IrpSp->FileObject->FsContext2);
|
||
|
||
|
||
CnAssert(fsContext->ReferenceCount == 0);
|
||
CnAssert(IsListEmpty(&(fsContext->EventList)));
|
||
|
||
if (fileType == TDI_CONTROL_CHANNEL_FILE) {
|
||
acquired = CnAcquireResourceExclusive(
|
||
CnResource,
|
||
TRUE
|
||
);
|
||
|
||
CnAssert(acquired == TRUE);
|
||
|
||
if (CnExclusiveChannel == fsContext) {
|
||
CnExclusiveChannel = NULL;
|
||
}
|
||
|
||
if (acquired) {
|
||
CnReleaseResourceForThread(
|
||
CnResource,
|
||
(ERESOURCE_THREAD) PsGetCurrentThread()
|
||
);
|
||
}
|
||
}
|
||
|
||
IF_CNDBG(CN_DEBUG_CLOSE) {
|
||
CNPRINT((
|
||
"[ClusNet] Close on file object %p\n",
|
||
IrpSp->FileObject
|
||
));
|
||
}
|
||
|
||
CnFreePool(fsContext);
|
||
|
||
return(STATUS_SUCCESS);
|
||
|
||
} // CnClose
|
||
|
||
|
||
|
||
FILE_FULL_EA_INFORMATION UNALIGNED *
|
||
CnFindEA(
|
||
PFILE_FULL_EA_INFORMATION StartEA,
|
||
CHAR *TargetName,
|
||
USHORT TargetNameLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Parses and extended attribute list for a given target attribute.
|
||
|
||
Arguments:
|
||
|
||
StartEA - the first extended attribute in the list.
|
||
TargetName - the name of the target attribute.
|
||
TargetNameLength - the length of the name of the target attribute.
|
||
|
||
Return Value:
|
||
|
||
A pointer to the requested attribute or NULL if the target wasn't found.
|
||
|
||
--*/
|
||
{
|
||
USHORT i;
|
||
BOOLEAN found;
|
||
FILE_FULL_EA_INFORMATION UNALIGNED * CurrentEA;
|
||
FILE_FULL_EA_INFORMATION UNALIGNED * NextEA;
|
||
|
||
|
||
PAGED_CODE();
|
||
|
||
NextEA = (FILE_FULL_EA_INFORMATION UNALIGNED *) StartEA;
|
||
|
||
do {
|
||
found = TRUE;
|
||
|
||
CurrentEA = NextEA;
|
||
NextEA = (FILE_FULL_EA_INFORMATION UNALIGNED *)
|
||
( ((PUCHAR) StartEA) + CurrentEA->NextEntryOffset);
|
||
|
||
if (CurrentEA->EaNameLength != TargetNameLength) {
|
||
continue;
|
||
}
|
||
|
||
for (i=0; i < CurrentEA->EaNameLength; i++) {
|
||
if (CurrentEA->EaName[i] == TargetName[i]) {
|
||
continue;
|
||
}
|
||
found = FALSE;
|
||
break;
|
||
}
|
||
|
||
if (found) {
|
||
return(CurrentEA);
|
||
}
|
||
|
||
} while(CurrentEA->NextEntryOffset != 0);
|
||
|
||
return(NULL);
|
||
|
||
} // CnFindEA
|
||
|
||
|
||
NTSTATUS
|
||
CnEnableShutdownOnClose(
|
||
PIRP Irp
|
||
)
|
||
{
|
||
NTSTATUS status;
|
||
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
PCN_FSCONTEXT fsContext = irpSp->FileObject->FsContext;
|
||
ULONG requestSize;
|
||
CLIENT_ID ClientId;
|
||
OBJECT_ATTRIBUTES ObjAttributes;
|
||
PCLUSNET_SHUTDOWN_ON_CLOSE_REQUEST request;
|
||
|
||
|
||
PAGED_CODE();
|
||
|
||
request = (PCLUSNET_SHUTDOWN_ON_CLOSE_REQUEST)
|
||
Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
requestSize = irpSp->Parameters.DeviceIoControl.InputBufferLength;
|
||
|
||
if ( requestSize >= sizeof(CLUSNET_SHUTDOWN_ON_CLOSE_REQUEST)
|
||
)
|
||
{
|
||
//
|
||
// illegal for kernel mode
|
||
//
|
||
if ( Irp->RequestorMode != KernelMode ) {
|
||
//
|
||
// Get a handle to the cluster service process.
|
||
// This is used to kill the service if a poison
|
||
// pkt is received. Since a kernel worker thread
|
||
// is used to kill the cluster service, we need
|
||
// to acquire the handle in the system process.
|
||
//
|
||
IF_CNDBG(CN_DEBUG_INIT) {
|
||
CNPRINT(("[Clusnet] Acquiring process handle\n"));
|
||
}
|
||
|
||
if (ClussvcProcessHandle == NULL) {
|
||
KeAttachProcess( CnSystemProcess );
|
||
|
||
ClientId.UniqueThread = (HANDLE)NULL;
|
||
ClientId.UniqueProcess = UlongToHandle(request->ProcessId);
|
||
|
||
InitializeObjectAttributes(
|
||
&ObjAttributes,
|
||
NULL,
|
||
0,
|
||
(HANDLE) NULL,
|
||
(PSECURITY_DESCRIPTOR) NULL
|
||
);
|
||
|
||
status = ZwOpenProcess(
|
||
&ClussvcProcessHandle,
|
||
0,
|
||
&ObjAttributes,
|
||
&ClientId
|
||
);
|
||
|
||
KeDetachProcess();
|
||
|
||
if ( NT_SUCCESS( status )) {
|
||
fsContext->ShutdownOnClose = TRUE;
|
||
} else {
|
||
IF_CNDBG(CN_DEBUG_INIT) {
|
||
CNPRINT((
|
||
"[Clusnet] ZwOpenProcess failed. status = %08X\n",
|
||
status
|
||
));
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
}
|
||
else {
|
||
status = STATUS_INVALID_PARAMETER_MIX;
|
||
}
|
||
}
|
||
else {
|
||
status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
return(status);
|
||
|
||
} // CnEnableShutdownOnClose
|
||
|