1268 lines
32 KiB
C
1268 lines
32 KiB
C
/*++
|
||
|
||
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
|