reactos/rostests/kmtests/example/Example_drv.c

246 lines
7.2 KiB
C
Raw Normal View History

/*
* PROJECT: ReactOS kernel-mode tests
* LICENSE: GPLv2+ - See COPYING in the top level directory
* PURPOSE: Kernel-Mode Test Suite Example Test Driver
* PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
*/
#include <kmt_test.h>
//#define NDEBUG
#include <debug.h>
#include "Example.h"
/* prototypes */
static KMT_MESSAGE_HANDLER TestMessageHandler;
static KMT_IRP_HANDLER TestIrpHandler;
/* globals */
static PDRIVER_OBJECT TestDriverObject;
/**
* @name TestEntry
*
* Test entry point.
* This is called by DriverEntry as early as possible, but with ResultBuffer
* initialized, so that test macros work correctly
*
* @param DriverObject
* Driver Object.
* This is guaranteed not to have been touched by DriverEntry before
* the call to TestEntry
* @param RegistryPath
* Driver Registry Path
* This is guaranteed not to have been touched by DriverEntry before
* the call to TestEntry
* @param DeviceName
* Pointer to receive a test-specific name for the device to create
* @param Flags
* Pointer to a flags variable instructing DriverEntry how to proceed.
* See the KMT_TESTENTRY_FLAGS enumeration for possible values
* Initialized to zero on entry
*
* @return Status.
* DriverEntry will fail if this is a failure status
*/
NTSTATUS
TestEntry(
IN PDRIVER_OBJECT DriverObject,
IN PCUNICODE_STRING RegistryPath,
OUT PCWSTR *DeviceName,
IN OUT INT *Flags)
{
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
UNREFERENCED_PARAMETER(RegistryPath);
UNREFERENCED_PARAMETER(Flags);
DPRINT("Entry!\n");
ok_irql(PASSIVE_LEVEL);
TestDriverObject = DriverObject;
*DeviceName = L"Example";
trace("Hi, this is the example driver\n");
KmtRegisterIrpHandler(IRP_MJ_CREATE, NULL, TestIrpHandler);
KmtRegisterIrpHandler(IRP_MJ_CLOSE, NULL, TestIrpHandler);
KmtRegisterMessageHandler(0, NULL, TestMessageHandler);
return Status;
}
/**
* @name TestUnload
*
* Test unload routine.
* This is called by the driver's Unload routine as early as possible, with
* ResultBuffer and the test device object still valid, so that test macros
* work correctly
*
* @param DriverObject
* Driver Object.
* This is guaranteed not to have been touched by Unload before the call
* to TestEntry
*
* @return Status
*/
VOID
TestUnload(
IN PDRIVER_OBJECT DriverObject)
{
PAGED_CODE();
DPRINT("Unload!\n");
ok_irql(PASSIVE_LEVEL);
ok_eq_pointer(DriverObject, TestDriverObject);
trace("Unloading example driver\n");
}
/**
* @name TestMessageHandler
*
* Test message handler routine
*
* @param DeviceObject
* Device Object.
* This is guaranteed not to have been touched by the dispatch function
* before the call to the IRP handler
* @param Irp
* Device Object.
* This is guaranteed not to have been touched by the dispatch function
* before the call to the IRP handler, except for passing it to
* IoGetCurrentStackLocation
* @param IoStackLocation
* Device Object.
* This is guaranteed not to have been touched by the dispatch function
* before the call to the IRP handler
*
* @return Status
*/
static
NTSTATUS
TestMessageHandler(
IN PDEVICE_OBJECT DeviceObject,
IN ULONG ControlCode,
IN PVOID Buffer OPTIONAL,
IN SIZE_T InLength,
IN OUT PSIZE_T OutLength)
{
NTSTATUS Status = STATUS_SUCCESS;
switch (ControlCode)
{
case IOCTL_NOTIFY:
{
static int TimesReceived = 0;
++TimesReceived;
ok(TimesReceived == 1, "Received control code 1 %d times\n", TimesReceived);
ok_eq_pointer(Buffer, NULL);
ok_eq_ulong((ULONG)InLength, 0LU);
ok_eq_ulong((ULONG)*OutLength, 0LU);
break;
}
case IOCTL_SEND_STRING:
{
static int TimesReceived = 0;
ANSI_STRING ExpectedString = RTL_CONSTANT_STRING("yay");
ANSI_STRING ReceivedString;
++TimesReceived;
ok(TimesReceived == 1, "Received control code 2 %d times\n", TimesReceived);
ok(Buffer != NULL, "Buffer is NULL\n");
ok_eq_ulong((ULONG)InLength, (ULONG)ExpectedString.Length);
ok_eq_ulong((ULONG)*OutLength, 0LU);
ReceivedString.MaximumLength = ReceivedString.Length = (USHORT)InLength;
ReceivedString.Buffer = Buffer;
ok(RtlCompareString(&ExpectedString, &ReceivedString, FALSE) == 0, "Received string: %Z\n", &ReceivedString);
break;
}
case IOCTL_SEND_MYSTRUCT:
{
static int TimesReceived = 0;
MY_STRUCT ExpectedStruct = { 123, ":D" };
MY_STRUCT ResultStruct = { 456, "!!!" };
++TimesReceived;
ok(TimesReceived == 1, "Received control code 3 %d times\n", TimesReceived);
ok(Buffer != NULL, "Buffer is NULL\n");
ok_eq_ulong((ULONG)InLength, (ULONG)sizeof ExpectedStruct);
ok_eq_ulong((ULONG)*OutLength, 2LU * sizeof ExpectedStruct);
if (!skip(Buffer && InLength >= sizeof ExpectedStruct, "Cannot read from buffer!\n"))
ok(RtlCompareMemory(&ExpectedStruct, Buffer, sizeof ExpectedStruct) == sizeof ExpectedStruct, "Buffer does not contain expected values\n");
if (!skip(Buffer && *OutLength >= 2 * sizeof ExpectedStruct, "Cannot write to buffer!\n"))
{
RtlCopyMemory((PCHAR)Buffer + sizeof ExpectedStruct, &ResultStruct, sizeof ResultStruct);
*OutLength = 2 * sizeof ExpectedStruct;
}
break;
}
default:
ok(0, "Got an unknown message! DeviceObject=%p, ControlCode=%lu, Buffer=%p, In=%lu, Out=%lu bytes\n",
DeviceObject, ControlCode, Buffer, InLength, *OutLength);
break;
}
return Status;
}
/**
* @name TestIrpHandler
*
* Test IRP handler routine
*
* @param DeviceObject
* Device Object.
* This is guaranteed not to have been touched by the dispatch function
* before the call to the IRP handler
* @param Irp
* Device Object.
* This is guaranteed not to have been touched by the dispatch function
* before the call to the IRP handler, except for passing it to
* IoGetCurrentStackLocation
* @param IoStackLocation
* Device Object.
* This is guaranteed not to have been touched by the dispatch function
* before the call to the IRP handler
*
* @return Status
*/
static
NTSTATUS
TestIrpHandler(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PIO_STACK_LOCATION IoStackLocation)
{
NTSTATUS Status = STATUS_SUCCESS;
DPRINT("IRP!\n");
ok_irql(PASSIVE_LEVEL);
ok_eq_pointer(DeviceObject->DriverObject, TestDriverObject);
if (IoStackLocation->MajorFunction == IRP_MJ_CREATE)
trace("Got IRP_MJ_CREATE!\n");
else if (IoStackLocation->MajorFunction == IRP_MJ_CLOSE)
trace("Got IRP_MJ_CLOSE!\n");
else
trace("Got an IRP!\n");
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}