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
|
||
|