windows-nt/Source/XPSP1/NT/base/cluster/clusnet/ntemgmt/ntemgmt.c
2020-09-26 16:20:57 +08:00

1268 lines
32 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
ntemgmt.c
Abstract:
Routines for managing IP Network Table Entries.
Author:
Mike Massa (mikemas) April 16, 1997
Revision History:
Who When What
-------- -------- ----------------------------------------------
mikemas 04-16-97 created
Notes:
--*/
#include "clusnet.h"
#include "ntemgmt.tmh"
//
// Types
//
typedef struct {
LIST_ENTRY Linkage;
ULONG Address;
USHORT Context;
ULONG Instance;
} IPA_NTE, *PIPA_NTE;
//
// Data
//
LIST_ENTRY IpaNteList = {NULL,NULL};
KSPIN_LOCK IpaNteListLock = 0;
HANDLE IpaIpHandle = NULL;
PDEVICE_OBJECT IpaIpDeviceObject = NULL;
PFILE_OBJECT IpaIpFileObject = NULL;
//
// Local function prototypes
//
NTSTATUS
IpaIssueDeviceControl (
IN ULONG IoControlCode,
IN PVOID InputBuffer,
IN ULONG InputBufferLength,
IN PVOID OutputBuffer,
IN PULONG OutputBufferLength
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, IpaLoad)
#pragma alloc_text(PAGE, IpaIssueDeviceControl)
#pragma alloc_text(PAGE, IpaInitialize)
#endif // ALLOC_PRAGMA
NTSTATUS
IpaIssueDeviceControl(
IN ULONG IoControlCode,
IN PVOID InputBuffer,
IN ULONG InputBufferLength,
IN PVOID OutputBuffer,
IN PULONG OutputBufferLength
)
/*++
Routine Description:
Arguments:
Return Value:
NTSTATUS -- Indicates the status of the request.
Notes:
Called in the context of the system process.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
IO_STATUS_BLOCK ioStatusBlock;
PIRP irp;
PKEVENT event;
PAGED_CODE();
CnAssert(IpaIpHandle != NULL);
CnAssert(IpaIpFileObject != NULL);
CnAssert(IpaIpDeviceObject != NULL);
CnAssert(CnSystemProcess == (PKPROCESS) IoGetCurrentProcess());
//
// Reference the file object. This reference will be removed by the I/O
// completion code.
//
status = ObReferenceObjectByPointer(
IpaIpFileObject,
0,
NULL,
KernelMode
);
if (!NT_SUCCESS(status)) {
IF_CNDBG(CN_DEBUG_NTE) {
CNPRINT((
"[Clusnet] Failed to reference IP device file handle, status %lx\n",
status
));
}
CnTrace(NTEMGMT_DETAIL, IpaNteObRefFailed,
"[Clusnet] Failed to reference IP device file handle, status %!status!.",
status // LOGSTATUS
);
return(status);
}
event = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
if (event != NULL) {
KeInitializeEvent(event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest(
IoControlCode,
IpaIpDeviceObject,
InputBuffer,
InputBufferLength,
OutputBuffer,
*OutputBufferLength,
FALSE,
event,
&ioStatusBlock
);
if (irp != NULL) {
status = IoCallDriver(IpaIpDeviceObject, irp);
//
// If necessary, wait for the I/O to complete.
//
if (status == STATUS_PENDING) {
KeWaitForSingleObject(
event,
UserRequest,
KernelMode,
FALSE,
NULL
);
}
if (NT_SUCCESS(status)) {
status = ioStatusBlock.Status;
// NOTENOTE: on 64 bit this is a truncation might
// want > check code
*OutputBufferLength = (ULONG)ioStatusBlock.Information;
}
else {
IF_CNDBG(CN_DEBUG_NTE) {
CNPRINT((
"[Clusnet] NTE request failed, status %lx\n",
status
));
}
CnTrace(NTEMGMT_DETAIL, IpaNteRequestFailed,
"[Clusnet] NTE request failed, status %!status!.",
status // LOGSTATUS
);
*OutputBufferLength = 0;
}
ExFreePool(event);
return(status);
}
else {
status = STATUS_INSUFFICIENT_RESOURCES;
IF_CNDBG(CN_DEBUG_NTE) {
CNPRINT((
"[Clusnet] Failed to build NTE request irp, status %lx\n",
status
));
}
CnTrace(NTEMGMT_DETAIL, IpaNteIrpAllocFailed,
"[Clusnet] Failed to build NTE request irp, status %!status!.",
status // LOGSTATUS
);
}
ExFreePool(event);
}
else {
status = STATUS_INSUFFICIENT_RESOURCES;
IF_CNDBG(CN_DEBUG_NTE) {
CNPRINT((
"[Clusnet] Failed to allocate memory for event object.\n"
));
}
CnTrace(NTEMGMT_DETAIL, IpaNteEventAllocFailed,
"[Clusnet] Failed to allocate event object, status %!status!.",
status // LOGSTATUS
);
}
ObDereferenceObject(IpaIpFileObject);
return(status);
} // IpaDeviceControl
PIPA_NTE
IpaFindNTE(
USHORT Context
)
{
PIPA_NTE nte;
PLIST_ENTRY entry;
for ( entry = IpaNteList.Flink;
entry != &IpaNteList;
entry = entry->Flink
)
{
nte = CONTAINING_RECORD(entry, IPA_NTE, Linkage);
if (Context == nte->Context) {
return(nte);
}
}
return(NULL);
} // IpaFindNTE
NTSTATUS
IpaAddNTECompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
IpaAddNTECompletion is the completion routine for an
IOCTL_IP_ADD_NTE IRP. It completes the processing for
an IOCTL_CLUSNET_ADD_NTE request and releases CnResource.
Arguments:
DeviceObject - not used
Irp - completed IRP
Context - local NTE data structure
Return value
Must not be STATUS_MORE_PROCESSING_REQUIRED
--*/
{
PIP_ADD_NTE_RESPONSE response;
PIPA_NTE nte;
NTSTATUS status;
KIRQL irql;
nte = (PIPA_NTE) Context;
status = Irp->IoStatus.Status;
if (status == STATUS_SUCCESS) {
response =
(PIP_ADD_NTE_RESPONSE) Irp->AssociatedIrp.SystemBuffer;
nte->Context = response->Context;
nte->Instance = response->Instance;
CnTrace(NTEMGMT_DETAIL, IpaNteCreatedNte,
"[Clusnet] Created new NTE, context %u, instance %u.",
nte->Context, // LOGUSHORT
nte->Instance // LOGULONG
);
IF_CNDBG(CN_DEBUG_NTE) {
CNPRINT((
"[Clusnet] Created new NTE %lu, instance %u\n",
nte->Context,
nte->Instance
));
}
KeAcquireSpinLock(&IpaNteListLock, &irql);
InsertTailList(&IpaNteList, &(nte->Linkage));
KeReleaseSpinLock(&IpaNteListLock, irql);
}
else {
CnTrace(NTEMGMT_DETAIL, IpaNteCreateNteFailed,
"[Clusnet] Failed to create new NTE, status %!status!.",
status // LOGSTATUS
);
IF_CNDBG(CN_DEBUG_NTE) {
CNPRINT((
"[Clusnet] Failed to create new NTE, status %lx\n",
status
));
}
CnFreePool(nte);
}
//
// Irp was already marked pending in our dispatch routine, but leave
// this code in case the dispatch routine is ever changed.
//
if (Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}
return(status);
} // IpaAddNTECompletion
NTSTATUS
IpaDeleteNTECompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
IpaDeleteNTECompletion is the completion routine for an
IOCTL_IP_DELETE_NTE IRP. It completes the processing for
an IOCTL_CLUSNET_ADD_NTE request and releases CnResource.
Arguments:
DeviceObject - not used
Irp - completed IRP
Context - local NTE data structure
Return value
Must not be STATUS_MORE_PROCESSING_REQUIRED
--*/
{
PIPA_NTE nte;
NTSTATUS status;
nte = (PIPA_NTE) Context;
status = Irp->IoStatus.Status;
if (status != STATUS_SUCCESS) {
CnTrace(NTEMGMT_DETAIL, IpaNteDeleteNteFailed,
"[Clusnet] Failed to delete NTE context %u, status %!status!.",
nte->Context, // LOGUSHORT
status // LOGSTATUS
);
IF_CNDBG(CN_DEBUG_NTE) {
CNPRINT(("[Clusnet] Failed to delete NTE %u, status %lx\n",
nte->Context,
status
));
}
CnAssert(status == STATUS_SUCCESS);
}
else {
CnTrace(NTEMGMT_DETAIL, IpaNteNteDeleted,
"[Clusnet] Deleted NTE %u.",
nte->Context // LOGUSHORT
);
IF_CNDBG(CN_DEBUG_NTE) {
CNPRINT(("[Clusnet] Deleted NTE %u\n", nte->Context));
}
}
CnFreePool(nte);
//
// Irp was already marked pending in our dispatch routine, but leave
// this code in case the dispatch routine is ever changed.
//
if (Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}
return(status);
} // IpaDeleteNTECompletion
NTSTATUS
IpaSetNTEAddressCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description
IpaSetNTEAddressCompletion is the completion routine for an
IOCTL_IP_SET_ADDRESS IRP. It completes the processing for
an IOCTL_CLUSNET_SET_NTE_ADDRESS request and releases
CnResource.
Arguments
DeviceObject - not used
Irp - completed IRP
Context - former IP address of NTE, must be restored in
IpaNteList if IOCTL failed
Return value
Must not be STATUS_MORE_PROCESSING_REQUIRED
--*/
{
PIP_SET_ADDRESS_REQUEST request;
NTSTATUS status;
KIRQL irql;
PIPA_NTE nte;
request = (PIP_SET_ADDRESS_REQUEST) Irp->AssociatedIrp.SystemBuffer;
status = Irp->IoStatus.Status;
if (status != STATUS_SUCCESS) {
CnTrace(NTEMGMT_DETAIL, IpaNteSetNteFailed,
"[Clusnet] Failed to set address for NTE %u, status %!status!.",
request->Context, // LOGUSHORT
status // LOGSTATUS
);
IF_CNDBG(CN_DEBUG_NTE) {
CNPRINT((
"[Clusnet] Failed to set NTE %u, status %lx\n",
request->Context,
status
));
}
KeAcquireSpinLock(&IpaNteListLock, &irql);
nte = IpaFindNTE(request->Context);
if ((nte != NULL) && (nte->Address == request->Address)) {
nte->Address = PtrToUlong(Context);
}
KeReleaseSpinLock(&IpaNteListLock, irql);
}
else {
CnTrace(NTEMGMT_DETAIL, IpaNteSetNteAddress,
"[Clusnet] Set NTE %u to address %x.",
request->Context, // LOGUSHORT
request->Address // LOGXLONG
);
IF_CNDBG(CN_DEBUG_NTE) {
CNPRINT((
"[Clusnet] Set NTE %u to address %lx\n",
request->Context,
request->Address
));
}
}
//
// Irp was already marked pending in our dispatch routine, but leave
// this code in case the dispatch routine is ever changed.
//
if (Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}
return(status);
} // IpaSetNTEAddressCompletion
//
// Public Routines
//
NTSTATUS
IpaLoad(
VOID
)
{
IF_CNDBG(CN_DEBUG_INIT) {
CNPRINT(("[Clusnet] NTE support loading.\n"));
}
KeInitializeSpinLock(&IpaNteListLock);
InitializeListHead(&IpaNteList);
return(STATUS_SUCCESS);
} // IpaLoad
NTSTATUS
IpaInitialize(
VOID
)
{
NTSTATUS status = STATUS_SUCCESS;
OBJECT_ATTRIBUTES objectAttributes;
UNICODE_STRING nameString;
IO_STATUS_BLOCK ioStatusBlock;
PAGED_CODE( );
IF_CNDBG(CN_DEBUG_INIT) {
CNPRINT(("[Clusnet] NTE support initializing.\n"));
}
CnAssert(IsListEmpty(&IpaNteList));
CnAssert(IpaIpHandle == NULL);
CnAssert(CnSystemProcess != NULL);
//
// Open handles in the context of the system process
//
KeAttachProcess(CnSystemProcess);
//
// Open the IP device.
//
RtlInitUnicodeString(&nameString, DD_IP_DEVICE_NAME);
InitializeObjectAttributes(
&objectAttributes,
&nameString,
OBJ_CASE_INSENSITIVE,
(HANDLE) NULL,
(PSECURITY_DESCRIPTOR) NULL
);
status = ZwCreateFile(
&IpaIpHandle,
SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
&objectAttributes,
&ioStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN_IF,
0,
NULL,
0
);
if (!NT_SUCCESS(status)) {
CnTrace(NTEMGMT_DETAIL, IpaNteOpenIpFailed,
"[Clusnet] Failed to open IP device, status %!status!.",
status // LOGSTATUS
);
IF_CNDBG(CN_DEBUG_INIT) {
CNPRINT(("[Clusnet] Failed to open IP device, status %lx\n", status));
}
goto error_exit;
}
status = ObReferenceObjectByHandle(
IpaIpHandle,
0,
NULL,
KernelMode,
&IpaIpFileObject,
NULL
);
if (!NT_SUCCESS(status)) {
CnTrace(NTEMGMT_DETAIL, IpaNteRefIpFailed,
"[Clusnet] Failed to reference IP device, status %!status!.",
status // LOGSTATUS
);
IF_CNDBG(CN_DEBUG_INIT) {
CNPRINT(("[Clusnet] Failed to reference IP device file handle, status %lx\n", status));
}
ZwClose(IpaIpHandle); IpaIpHandle = NULL;
goto error_exit;
}
IpaIpDeviceObject = IoGetRelatedDeviceObject(IpaIpFileObject);
CnAdjustDeviceObjectStackSize(CnDeviceObject, IpaIpDeviceObject);
status = STATUS_SUCCESS;
error_exit:
KeDetachProcess();
return(status);
} // IpaInitialize
VOID
IpaShutdown(
VOID
)
{
NTSTATUS status;
KIRQL irql;
PLIST_ENTRY entry;
PIPA_NTE nte;
IP_DELETE_NTE_REQUEST request;
ULONG responseSize = 0;
IF_CNDBG(CN_DEBUG_INIT) {
CNPRINT(("[Clusnet] Destroying all cluster NTEs...\n"));
}
if (IpaIpHandle != NULL) {
//
// Handles was opened in the context of the system process.
//
CnAssert(CnSystemProcess != NULL);
KeAttachProcess(CnSystemProcess);
KeAcquireSpinLock(&IpaNteListLock, &irql);
while (!IsListEmpty(&IpaNteList)) {
entry = RemoveHeadList(&IpaNteList);
KeReleaseSpinLock(&IpaNteListLock, irql);
nte = CONTAINING_RECORD(entry, IPA_NTE, Linkage);
request.Context = nte->Context;
status = IpaIssueDeviceControl(
IOCTL_IP_DELETE_NTE,
&request,
sizeof(request),
NULL,
&responseSize
);
if (status != STATUS_SUCCESS) {
CnTrace(NTEMGMT_DETAIL, IpaNteShutdownDeleteNteFailed,
"[Clusnet] Shutdown: failed to delete NTE %u, status %!status!.",
nte->Context, // LOGUSHORT
status // LOGSTATUS
);
IF_CNDBG(CN_DEBUG_INIT) {
CNPRINT(("[Clusnet] Failed to delete NTE %u, status %lx\n",
nte->Context,
status
));
}
}
else {
CnTrace(NTEMGMT_DETAIL, IpaNteShutdownDeletedNte,
"[Clusnet] Shutdown: deleted NTE context %u, instance %u.",
nte->Context, // LOGUSHORT
nte->Instance // LOGULONG
);
IF_CNDBG(CN_DEBUG_INIT) {
CNPRINT(("[Clusnet] Deleted NTE %u\n", request.Context));
}
}
CnFreePool(nte);
KeAcquireSpinLock(&IpaNteListLock, &irql);
}
KeReleaseSpinLock(&IpaNteListLock, irql);
CnTrace(NTEMGMT_DETAIL, IpaNteShutdownNtesDeleted,
"[Clusnet] All cluster NTEs destroyed."
);
IF_CNDBG(CN_DEBUG_INIT) {
CNPRINT(("[Clusnet] All cluster NTEs destroyed.\n"));
}
ObDereferenceObject(IpaIpFileObject);
ZwClose(IpaIpHandle);
IpaIpHandle = NULL;
IpaIpFileObject = NULL;
IpaIpDeviceObject = NULL;
KeDetachProcess();
}
return;
} // IpaShutdown
NTSTATUS
IpaAddNTE(
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp
)
/*++
Routine Description
IpaAddNTE issues an IOCTL_IP_ADD_NTE to IP to add an NTE.
Irp is reused. It must be allocated with sufficient stack
locations, as determined when IpaIpDeviceObject was opened
in IpaInitialize.
Arguments
Irp - IRP from I/O manager to clusnet
IrpSp - current IRP stack location
Return Value
STATUS_PENDING, or error status if request is not submitted
to IP.
--*/
{
NTSTATUS status;
PIP_ADD_NTE_REQUEST request;
ULONG requestSize;
ULONG responseSize;
PIPA_NTE nte;
PIO_STACK_LOCATION nextIrpSp;
//
// Verify input parameters
//
requestSize =
IrpSp->Parameters.DeviceIoControl.InputBufferLength;
responseSize =
IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
if (requestSize < sizeof(IP_ADD_NTE_REQUEST)) {
ULONG correctSize = sizeof(IP_ADD_NTE_REQUEST);
CnTrace(NTEMGMT_DETAIL, IpaNteAddInvalidReqSize,
"[Clusnet] Add NTE request size %u invalid, "
"should be %u.",
requestSize, // LOGULONG
correctSize // LOGULONG
);
IF_CNDBG(CN_DEBUG_NTE) {
CNPRINT((
"[Clusnet] Add NTE request size %d invalid, should be %d.\n",
requestSize,
sizeof(IP_ADD_NTE_REQUEST)
));
}
return(STATUS_INVALID_PARAMETER);
} else if (responseSize < sizeof(IP_ADD_NTE_RESPONSE)) {
ULONG correctSize = sizeof(IP_ADD_NTE_RESPONSE);
CnTrace(NTEMGMT_DETAIL, IpaNteAddInvalidResponseSize,
"[Clusnet] Add NTE response size %u invalid, "
"should be %u.",
responseSize, // LOGULONG
correctSize // LOGULONG
);
IF_CNDBG(CN_DEBUG_NTE) {
CNPRINT((
"[Clusnet] Add NTE response size %d invalid, should be %d.\n",
responseSize,
sizeof(IP_ADD_NTE_RESPONSE)
));
}
return(STATUS_INVALID_PARAMETER);
}
//
// Verify that Irp has sufficient stack locations
//
if (Irp->CurrentLocation - IpaIpDeviceObject->StackSize < 1) {
UCHAR correctSize = IpaIpDeviceObject->StackSize+1;
CnTrace(NTEMGMT_DETAIL, IpaNteAddNoIrpStack,
"[Clusnet] Add NTE IRP has %u remaining stack locations, "
"need %u.",
Irp->CurrentLocation, // LOGUCHAR
correctSize // LOGUCHAR
);
IF_CNDBG(CN_DEBUG_NTE) {
CNPRINT((
"[Clusnet] Add NTE IRP has %d stack locations, need %d.\n",
Irp->CurrentLocation,
IpaIpDeviceObject->StackSize
));
}
return(STATUS_INVALID_PARAMETER);
}
request = (PIP_ADD_NTE_REQUEST) Irp->AssociatedIrp.SystemBuffer;
CnTrace(NTEMGMT_DETAIL, IpaNteCreatingNte,
"[Clusnet] Creating new NTE for address %x.",
request->Address // LOGXLONG
);
IF_CNDBG(CN_DEBUG_NTE) {
CNPRINT((
"[Clusnet] Creating new NTE for address %lx...\n",
request->Address
));
}
//
// Allocate a local NTE data structure.
//
nte = CnAllocatePool(sizeof(IPA_NTE));
if (nte == NULL) {
return(STATUS_INSUFFICIENT_RESOURCES);
}
nte->Address = request->Address;
//
// Set up the next IRP stack location for IP.
// IOCTL_CLUSNET_ADD_NTE uses the same request
// and response buffer, so there is no need to
// alter the IRP system buffer.
//
IoCopyCurrentIrpStackLocationToNext(Irp);
nextIrpSp = IoGetNextIrpStackLocation(Irp);
nextIrpSp->Parameters.DeviceIoControl.IoControlCode
= IOCTL_IP_ADD_NTE;
nextIrpSp->FileObject = IpaIpFileObject;
IoSetCompletionRoutine(
Irp,
IpaAddNTECompletion,
(PVOID) nte,
TRUE,
TRUE,
TRUE
);
//
// Mark the IRP pending, since we return STATUS_PENDING
// regardless of the result of IoCallDriver.
//
IoMarkIrpPending(Irp);
//
// Issue the request
//
IoCallDriver(IpaIpDeviceObject, Irp);
//
// At this point we must return STATUS_PENDING so that
// the clusnet dispatch routine will not try to complete
// the IRP. The lower-level driver is required to complete
// the IRP, and errors will be handled in the completion
// routine.
//
return (STATUS_PENDING);
} // IpaAddNTE
NTSTATUS
IpaDeleteNTE(
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp
)
/*++
Routine Description
IpaDeleteNTE issues an IOCTL_IP_DELETE_NTE to IP to delete
an NTE. Irp is reused. It must be allocated with sufficient
stack locations, as determined when IpaIpDeviceObject was
opened in IpaInitialize.
Arguments
Irp - IRP from I/O manager to clusnet
IrpSp - current IRP stack location
Return Value
STATUS_PENDING, or error status if request is not submitted
to IP.
--*/
{
NTSTATUS status;
PIP_DELETE_NTE_REQUEST request;
ULONG requestSize;
PIPA_NTE nte;
KIRQL irql;
PIO_STACK_LOCATION nextIrpSp;
//
// Verify input parameters
//
requestSize =
IrpSp->Parameters.DeviceIoControl.InputBufferLength;
if (requestSize < sizeof(IP_DELETE_NTE_REQUEST)) {
ULONG correctSize = sizeof(IP_DELETE_NTE_REQUEST);
CnTrace(NTEMGMT_DETAIL, IpaNteDelInvalidReqSize,
"[Clusnet] Delete NTE request size %u invalid, "
"should be %u.",
requestSize, // LOGULONG
correctSize // LOGULONG
);
IF_CNDBG(CN_DEBUG_NTE) {
CNPRINT((
"[Clusnet] Delete NTE request size %d invalid, "
"should be %d.\n",
requestSize,
sizeof(IP_DELETE_NTE_REQUEST)
));
}
return(STATUS_INVALID_PARAMETER);
}
//
// Verify that Irp has sufficient stack locations
//
if (Irp->CurrentLocation - IpaIpDeviceObject->StackSize < 1) {
UCHAR correctSize = IpaIpDeviceObject->StackSize+1;
CnTrace(NTEMGMT_DETAIL, IpaNteDeleteNoIrpStack,
"[Clusnet] Delete NTE IRP has %u remaining stack locations, "
"need %u.",
Irp->CurrentLocation, // LOGUCHAR
correctSize // LOGUCHAR
);
IF_CNDBG(CN_DEBUG_NTE) {
CNPRINT((
"[Clusnet] Delete NTE IRP has %d stack locations, "
"need %d.\n",
Irp->CurrentLocation,
IpaIpDeviceObject->StackSize
));
}
return(STATUS_INVALID_PARAMETER);
}
request = (PIP_DELETE_NTE_REQUEST) Irp->AssociatedIrp.SystemBuffer;
//
// Find the NTE in local NTE list and remove.
//
KeAcquireSpinLock(&IpaNteListLock, &irql);
nte = IpaFindNTE(request->Context);
if (nte == NULL) {
KeReleaseSpinLock(&IpaNteListLock, irql);
CnTrace(NTEMGMT_DETAIL, IpaNteDeleteNteUnknown,
"[Clusnet] NTE %u does not exist.",
request->Context // LOGUSHORT
);
IF_CNDBG(CN_DEBUG_NTE) {
CNPRINT((
"[Clusnet] NTE %u does not exist.\n",
request->Context
));
}
return(STATUS_UNSUCCESSFUL);
}
RemoveEntryList(&(nte->Linkage));
KeReleaseSpinLock(&IpaNteListLock, irql);
//
// Set up the next IRP stack location for IP.
// IOCTL_CLUSNET_ADD_NTE uses the same request
// and response buffer, so there is no need to
// alter the IRP system buffer.
//
IoCopyCurrentIrpStackLocationToNext(Irp);
nextIrpSp = IoGetNextIrpStackLocation(Irp);
nextIrpSp->Parameters.DeviceIoControl.IoControlCode
= IOCTL_IP_DELETE_NTE;
nextIrpSp->FileObject = IpaIpFileObject;
IoSetCompletionRoutine(
Irp,
IpaDeleteNTECompletion,
(PVOID) nte,
TRUE,
TRUE,
TRUE
);
//
// Mark the IRP pending, since we return STATUS_PENDING
// regardless of the result of IoCallDriver.
//
IoMarkIrpPending(Irp);
//
// Issue the request
//
IoCallDriver(IpaIpDeviceObject, Irp);
//
// At this point we must return STATUS_PENDING so that
// the clusnet dispatch routine will not try to complete
// the IRP. The lower-level driver is required to complete
// the IRP, and errors will be handled in the completion
// routine.
//
return (STATUS_PENDING);
} // IpaDeleteNTE
NTSTATUS
IpaSetNTEAddress(
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp
)
/*++
Routine Description
IpaSetNTEAddress issues an IOCTL_IP_SET_ADDRESS to IP in order
to set the IP address for an NTE. Irp is reused. It must be
allocated with sufficient stack locations, as determined when
IpaIpDeviceObject was opened in IpaInitialize.
Arguments
Irp - IRP from I/O manager to clusnet
IrpSp - current IRP stack location
Return Value
STATUS_PENDING, or error status if request is not submitted
to IP.
--*/
{
NTSTATUS status;
PIP_SET_ADDRESS_REQUEST request;
ULONG requestSize;
PIPA_NTE nte;
KIRQL irql;
PIO_STACK_LOCATION nextIrpSp;
ULONG oldAddress;
//
// Verify input parameters
//
requestSize =
IrpSp->Parameters.DeviceIoControl.InputBufferLength;
if (requestSize < sizeof(IP_SET_ADDRESS_REQUEST)) {
ULONG correctSize = sizeof(IP_SET_ADDRESS_REQUEST);
CnTrace(NTEMGMT_DETAIL, IpaNteSetInvalidReqSize,
"[Clusnet] Set NTE request size %u invalid, "
"should be %u.",
requestSize, // LOGULONG
correctSize // LOGULONG
);
IF_CNDBG(CN_DEBUG_NTE) {
CNPRINT((
"[Clusnet] Set NTE request size %d invalid, should be %d.\n",
requestSize,
sizeof(IP_SET_ADDRESS_REQUEST)
));
}
return(STATUS_INVALID_PARAMETER);
}
//
// Verify that Irp has sufficient stack locations
//
if (Irp->CurrentLocation - IpaIpDeviceObject->StackSize < 1) {
UCHAR correctSize = IpaIpDeviceObject->StackSize+1;
CnTrace(NTEMGMT_DETAIL, IpaNteSetNoIrpStack,
"[Clusnet] Set NTE IRP has %u remaining stack locations, "
"need %u.",
Irp->CurrentLocation, // LOGUCHAR
correctSize // LOGUCHAR
);
IF_CNDBG(CN_DEBUG_NTE) {
CNPRINT((
"[Clusnet] Set NTE IRP has %d stack locations, need %d.\n",
Irp->CurrentLocation,
IpaIpDeviceObject->StackSize
));
}
return(STATUS_INVALID_PARAMETER);
}
request = (PIP_SET_ADDRESS_REQUEST)
Irp->AssociatedIrp.SystemBuffer;
IF_CNDBG(CN_DEBUG_NTE) {
CNPRINT((
"[Clusnet] Attempting to set NTE %u to address %lx...\n",
request->Context,
request->Address
));
}
KeAcquireSpinLock(&IpaNteListLock, &irql);
nte = IpaFindNTE(request->Context);
if (nte != NULL) {
oldAddress = nte->Address;
nte->Address = request->Address;
KeReleaseSpinLock(&IpaNteListLock, irql);
//
// Set up the next IRP stack location for IP.
// IOCTL_CLUSNET_SET_NTE_ADDRESS uses the same request
// and response buffer, so there is no need to alter the
// IRP system buffer.
//
IoCopyCurrentIrpStackLocationToNext(Irp);
nextIrpSp = IoGetNextIrpStackLocation(Irp);
nextIrpSp->Parameters.DeviceIoControl.IoControlCode
= IOCTL_IP_SET_ADDRESS;
nextIrpSp->FileObject = IpaIpFileObject;
IoSetCompletionRoutine(
Irp,
IpaSetNTEAddressCompletion,
UlongToPtr(oldAddress),
TRUE,
TRUE,
TRUE
);
//
// Mark the IRP pending, since we return STATUS_PENDING
// regardless of the result of IoCallDriver.
//
IoMarkIrpPending(Irp);
//
// Issue the request
//
IoCallDriver(IpaIpDeviceObject, Irp);
//
// At this point we must return STATUS_PENDING so that
// the clusnet dispatch routine will not try to complete
// the IRP. The lower-level driver is required to complete
// the IRP, and errors will be handled in the completion
// routine.
//
status = STATUS_PENDING;
} else {
KeReleaseSpinLock(&IpaNteListLock, irql);
CnTrace(NTEMGMT_DETAIL, IpaNteSetNteUnknown,
"[Clusnet] NTE %u does not exist.",
request->Context // LOGUSHORT
);
IF_CNDBG(CN_DEBUG_NTE) {
CNPRINT(("[Clusnet] NTE %u does not exist.\n",
request->Context
));
}
status = STATUS_UNSUCCESSFUL;
}
return(status);
} // IpaSetNTEAddress
BOOLEAN
IpaIsAddressRegistered(
ULONG Address
)
{
PIPA_NTE nte;
KIRQL irql;
PLIST_ENTRY entry;
BOOLEAN isAddressRegistered = FALSE;
KeAcquireSpinLock(&IpaNteListLock, &irql);
for ( entry = IpaNteList.Flink;
entry != &IpaNteList;
entry = entry->Flink
)
{
nte = CONTAINING_RECORD(entry, IPA_NTE, Linkage);
if (nte->Address == Address) {
isAddressRegistered = TRUE;
break;
}
}
KeReleaseSpinLock(&IpaNteListLock, irql);
return(isAddressRegistered);
} // IpaIsAddressRegistered