You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1267 lines
33 KiB
1267 lines
33 KiB
/*++
|
|
|
|
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 = CnAllocatePool(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;
|
|
}
|
|
|
|
CnFreePool(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
|
|
);
|
|
}
|
|
|
|
CnFreePool(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_EX 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_EX)) {
|
|
ULONG correctSize = sizeof(IP_SET_ADDRESS_REQUEST_EX);
|
|
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_EX)
|
|
));
|
|
}
|
|
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_EX)
|
|
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_EX;
|
|
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
|