356 lines
8.1 KiB
C
356 lines
8.1 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1999 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
kmcancel.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains code to verify handling of IRP cancelation requests.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Abolade Gbadegesin (aboladeg) 05-June-2000
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "precomp.h"
|
|||
|
#pragma hdrstop
|
|||
|
|
|||
|
#define THREAD_COUNT 10
|
|||
|
#define REQUEST_COUNT 50
|
|||
|
#define DD_TARGET_DEVICE_NAME DD_IP_DEVICE_NAME
|
|||
|
#define TARGET_IO_CONTROL_CODE IOCTL_IP_RTCHANGE_NOTIFY_REQUEST
|
|||
|
|
|||
|
//
|
|||
|
// Target driver state.
|
|||
|
//
|
|||
|
|
|||
|
PDEVICE_OBJECT TargetDeviceObject = NULL;
|
|||
|
PFILE_OBJECT TargetFileObject = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Thread-management state.
|
|||
|
//
|
|||
|
|
|||
|
ULONG KmcThreadCount;
|
|||
|
KEVENT KmcStopEvent;
|
|||
|
KSEMAPHORE KmcStopSemaphore;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// FUNCTION PROTOTYPES (alphabetically)
|
|||
|
//
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DriverEntry(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PUNICODE_STRING RegistryPath
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
KmcRequestCompletionRoutine(
|
|||
|
PDEVICE_OBJECT DeviceObject,
|
|||
|
PIRP Irp,
|
|||
|
PVOID Context
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
KmcRequestThread(
|
|||
|
PVOID Context
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
KmcUnloadDriver(
|
|||
|
IN PDRIVER_OBJECT DriverObject
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
KmcUpdateThread(
|
|||
|
PVOID Context
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DriverEntry(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PUNICODE_STRING RegistryPath
|
|||
|
)
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
NTSTATUS Status;
|
|||
|
HANDLE ThreadHandle;
|
|||
|
UNICODE_STRING UnicodeString;
|
|||
|
|
|||
|
KdPrint(("DriverEntry\n"));
|
|||
|
DriverObject->DriverUnload = KmcUnloadDriver;
|
|||
|
KmcThreadCount = 0;
|
|||
|
KeInitializeEvent(&KmcStopEvent, NotificationEvent, FALSE);
|
|||
|
KeInitializeSemaphore(&KmcStopSemaphore, 0, MAXLONG);
|
|||
|
|
|||
|
//
|
|||
|
// Obtain the target driver's device-object
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString(&UnicodeString, DD_TARGET_DEVICE_NAME);
|
|||
|
Status =
|
|||
|
IoGetDeviceObjectPointer(
|
|||
|
&UnicodeString,
|
|||
|
SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
|
|||
|
&TargetFileObject,
|
|||
|
&TargetDeviceObject
|
|||
|
);
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
KdPrint(("DriverEntry: error %x getting IP object\n", Status));
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
ObReferenceObject(TargetDeviceObject);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Start the request/update threads.
|
|||
|
// The request threads are responsible for issuing the I/O control
|
|||
|
// whose cancelation is being verified, and the update threads are
|
|||
|
// responsible for triggering completion of those I/O control requests
|
|||
|
// in order to highlight any potential race-conditions.
|
|||
|
//
|
|||
|
|
|||
|
for (i = 0; i < THREAD_COUNT; i++) {
|
|||
|
Status =
|
|||
|
PsCreateSystemThread(
|
|||
|
&ThreadHandle,
|
|||
|
GENERIC_ALL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
KmcUpdateThread,
|
|||
|
NULL
|
|||
|
);
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
ZwClose(ThreadHandle);
|
|||
|
++KmcThreadCount;
|
|||
|
}
|
|||
|
Status =
|
|||
|
PsCreateSystemThread(
|
|||
|
&ThreadHandle,
|
|||
|
GENERIC_ALL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
KmcRequestThread,
|
|||
|
NULL
|
|||
|
);
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
ZwClose(ThreadHandle);
|
|||
|
++KmcThreadCount;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
|
|||
|
} // DriverEntry
|
|||
|
|
|||
|
typedef struct _KMC_REQUEST {
|
|||
|
IO_STATUS_BLOCK IoStatus;
|
|||
|
PIRP Irp;
|
|||
|
ULONG ReferenceCount;
|
|||
|
} KMC_REQUEST, *PKMC_REQUEST;
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
KmcRequestCompletionRoutine(
|
|||
|
PDEVICE_OBJECT DeviceObject,
|
|||
|
PIRP Irp,
|
|||
|
PVOID Context
|
|||
|
)
|
|||
|
{
|
|||
|
PKMC_REQUEST Request = (PKMC_REQUEST)Context;
|
|||
|
if (InterlockedDecrement(&Request->ReferenceCount) == 0) {
|
|||
|
IoFreeIrp(Request->Irp);
|
|||
|
ExFreePool(Request);
|
|||
|
}
|
|||
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|||
|
} // KmcCompletionRoutine
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
KmcRequestThread(
|
|||
|
PVOID Context
|
|||
|
)
|
|||
|
{
|
|||
|
ULONG i, Index;
|
|||
|
LARGE_INTEGER Interval;
|
|||
|
PIRP Irp;
|
|||
|
PIO_STACK_LOCATION IrpSp;
|
|||
|
KIRQL OldIrql;
|
|||
|
PKMC_REQUEST Request, RequestArray[REQUEST_COUNT];
|
|||
|
|
|||
|
for (; !KeReadStateEvent(&KmcStopEvent); ) {
|
|||
|
|
|||
|
//
|
|||
|
// Queue a series of requests to the driver.
|
|||
|
//
|
|||
|
|
|||
|
Index = 0;
|
|||
|
RtlZeroMemory(RequestArray, sizeof(RequestArray));
|
|||
|
for (i = 0; i < REQUEST_COUNT; i++) {
|
|||
|
Request = ExAllocatePool(NonPagedPool, sizeof(*Request));
|
|||
|
if (!Request) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
RtlZeroMemory(Request, sizeof(*Request));
|
|||
|
|
|||
|
Irp = IoAllocateIrp(TargetDeviceObject->StackSize, FALSE);
|
|||
|
if (!Irp) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
Request->Irp = Irp;
|
|||
|
|
|||
|
Irp->RequestorMode = KernelMode;
|
|||
|
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
|
|||
|
Irp->Tail.Overlay.OriginalFileObject = TargetFileObject;
|
|||
|
IoSetCompletionRoutine(
|
|||
|
Irp,
|
|||
|
KmcRequestCompletionRoutine,
|
|||
|
Request,
|
|||
|
TRUE,
|
|||
|
TRUE,
|
|||
|
TRUE
|
|||
|
);
|
|||
|
|
|||
|
IrpSp = IoGetNextIrpStackLocation(Irp);
|
|||
|
IrpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
|
|||
|
IrpSp->Parameters.DeviceIoControl.IoControlCode =
|
|||
|
TARGET_IO_CONTROL_CODE;
|
|||
|
IrpSp->DeviceObject = TargetDeviceObject;
|
|||
|
IrpSp->FileObject = TargetFileObject;
|
|||
|
|
|||
|
Request->ReferenceCount = 2;
|
|||
|
RequestArray[Index++] = Request;
|
|||
|
IoCallDriver(TargetDeviceObject, Request->Irp);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Delay execution for a short interval, and cancel the requests.
|
|||
|
//
|
|||
|
|
|||
|
Interval.QuadPart = -10 * 1000 * 50;
|
|||
|
KeDelayExecutionThread(KernelMode, FALSE, &Interval);
|
|||
|
|
|||
|
for (i = 0; i < REQUEST_COUNT; i++) {
|
|||
|
if (Request = RequestArray[i]) {
|
|||
|
IoCancelIrp(Request->Irp);
|
|||
|
if (InterlockedDecrement(&Request->ReferenceCount) == 0) {
|
|||
|
IoFreeIrp(Request->Irp);
|
|||
|
ExFreePool(Request);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
KeReleaseSemaphore(&KmcStopSemaphore, 0, 1, FALSE);
|
|||
|
|
|||
|
} // KmcRequestThread
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
KmcUnloadDriver(
|
|||
|
IN PDRIVER_OBJECT DriverObject
|
|||
|
)
|
|||
|
{
|
|||
|
KdPrint(("KmcUnloadDriver\n"));
|
|||
|
|
|||
|
//
|
|||
|
// Signal all threads to stop, and wait for them to exit.
|
|||
|
//
|
|||
|
|
|||
|
KeSetEvent(&KmcStopEvent, 0, FALSE);
|
|||
|
while (KmcThreadCount--) {
|
|||
|
KeWaitForSingleObject(
|
|||
|
&KmcStopSemaphore, Executive, KernelMode, FALSE, NULL
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Release references to the IP device object
|
|||
|
//
|
|||
|
|
|||
|
ObDereferenceObject(TargetFileObject);
|
|||
|
ObDereferenceObject(TargetDeviceObject);
|
|||
|
|
|||
|
} // KmcUnloadDriver
|
|||
|
|
|||
|
|
|||
|
extern
|
|||
|
VOID
|
|||
|
LookupRoute(
|
|||
|
IPRouteLookupData* RouteLookupData,
|
|||
|
IPRouteEntry* RouteEntry
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
KmcUpdateThread(
|
|||
|
PVOID Context
|
|||
|
)
|
|||
|
{
|
|||
|
KEVENT Event;
|
|||
|
LARGE_INTEGER Interval;
|
|||
|
IO_STATUS_BLOCK IoStatus;
|
|||
|
PIRP Irp;
|
|||
|
IPRouteEntry RouteEntry;
|
|||
|
IPRouteLookupData RouteLookupData;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
//
|
|||
|
// Retrieve information from IP for use in triggering route-changes.
|
|||
|
//
|
|||
|
|
|||
|
RtlZeroMemory(&RouteEntry, sizeof(RouteEntry));
|
|||
|
RouteLookupData.Version = 0;
|
|||
|
RouteLookupData.SrcAdd = 0;
|
|||
|
RouteLookupData.DestAdd = 0x100000a; // 10.0.0.1
|
|||
|
LookupRoute(&RouteLookupData, &RouteEntry);
|
|||
|
|
|||
|
RouteEntry.ire_dest = 0x100000a; // 10.0.0.1
|
|||
|
RouteEntry.ire_mask = 0xffffffff;
|
|||
|
RouteEntry.ire_proto = IRE_PROTO_NETMGMT;
|
|||
|
|
|||
|
//
|
|||
|
// Repeatedly issue changes to the IP routing table, until told to exit.
|
|||
|
//
|
|||
|
|
|||
|
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
|
|||
|
for (; !KeReadStateEvent(&KmcStopEvent); ) {
|
|||
|
|
|||
|
Interval.QuadPart = -10 * 1000 * 50;
|
|||
|
KeDelayExecutionThread(KernelMode, FALSE, &Interval);
|
|||
|
|
|||
|
Irp =
|
|||
|
IoBuildDeviceIoControlRequest(
|
|||
|
IOCTL_IP_SET_ROUTEWITHREF,
|
|||
|
TargetDeviceObject,
|
|||
|
&RouteEntry,
|
|||
|
sizeof(RouteEntry),
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
FALSE,
|
|||
|
&Event,
|
|||
|
&IoStatus
|
|||
|
);
|
|||
|
if (!Irp) { continue; }
|
|||
|
Status = IoCallDriver(TargetDeviceObject, Irp);
|
|||
|
if (Status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
KeReleaseSemaphore(&KmcStopSemaphore, 0, 1, FALSE);
|
|||
|
|
|||
|
} // KmcUpdateThread
|
|||
|
|