windows-nt/Source/XPSP1/NT/net/tcpip/samples/kmcancel/kmcancel.c

356 lines
8.1 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
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