/*++ 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