1c2c66affSColin Finck /*
2c2c66affSColin Finck * PROJECT: ReactOS kernel-mode tests
3*a9ba7a3fSThomas Faber * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
4*a9ba7a3fSThomas Faber * PURPOSE: Kernel-Mode Test Suite Example test driver
5*a9ba7a3fSThomas Faber * COPYRIGHT: Copyright 2011-2018 Thomas Faber <thomas.faber@reactos.org>
6c2c66affSColin Finck */
7c2c66affSColin Finck
8c2c66affSColin Finck #include <kmt_test.h>
9c2c66affSColin Finck
10c2c66affSColin Finck //#define NDEBUG
11c2c66affSColin Finck #include <debug.h>
12c2c66affSColin Finck
13c2c66affSColin Finck #include "Example.h"
14c2c66affSColin Finck
15c2c66affSColin Finck /* prototypes */
16c2c66affSColin Finck static KMT_MESSAGE_HANDLER TestMessageHandler;
17c2c66affSColin Finck static KMT_IRP_HANDLER TestIrpHandler;
18c2c66affSColin Finck
19c2c66affSColin Finck /* globals */
20c2c66affSColin Finck static PDRIVER_OBJECT TestDriverObject;
21c2c66affSColin Finck
22c2c66affSColin Finck /**
23c2c66affSColin Finck * @name TestEntry
24c2c66affSColin Finck *
25c2c66affSColin Finck * Test entry point.
26c2c66affSColin Finck * This is called by DriverEntry as early as possible, but with ResultBuffer
27c2c66affSColin Finck * initialized, so that test macros work correctly
28c2c66affSColin Finck *
29c2c66affSColin Finck * @param DriverObject
30c2c66affSColin Finck * Driver Object.
31c2c66affSColin Finck * This is guaranteed not to have been touched by DriverEntry before
32c2c66affSColin Finck * the call to TestEntry
33c2c66affSColin Finck * @param RegistryPath
34c2c66affSColin Finck * Driver Registry Path
35c2c66affSColin Finck * This is guaranteed not to have been touched by DriverEntry before
36c2c66affSColin Finck * the call to TestEntry
37c2c66affSColin Finck * @param DeviceName
38c2c66affSColin Finck * Pointer to receive a test-specific name for the device to create
39c2c66affSColin Finck * @param Flags
40c2c66affSColin Finck * Pointer to a flags variable instructing DriverEntry how to proceed.
41c2c66affSColin Finck * See the KMT_TESTENTRY_FLAGS enumeration for possible values
42c2c66affSColin Finck * Initialized to zero on entry
43c2c66affSColin Finck *
44c2c66affSColin Finck * @return Status.
45c2c66affSColin Finck * DriverEntry will fail if this is a failure status
46c2c66affSColin Finck */
47c2c66affSColin Finck NTSTATUS
TestEntry(IN PDRIVER_OBJECT DriverObject,IN PCUNICODE_STRING RegistryPath,OUT PCWSTR * DeviceName,IN OUT INT * Flags)48c2c66affSColin Finck TestEntry(
49c2c66affSColin Finck IN PDRIVER_OBJECT DriverObject,
50c2c66affSColin Finck IN PCUNICODE_STRING RegistryPath,
51c2c66affSColin Finck OUT PCWSTR *DeviceName,
52c2c66affSColin Finck IN OUT INT *Flags)
53c2c66affSColin Finck {
54c2c66affSColin Finck NTSTATUS Status = STATUS_SUCCESS;
55c2c66affSColin Finck
56c2c66affSColin Finck PAGED_CODE();
57c2c66affSColin Finck
58c2c66affSColin Finck UNREFERENCED_PARAMETER(RegistryPath);
59c2c66affSColin Finck UNREFERENCED_PARAMETER(Flags);
60c2c66affSColin Finck
61c2c66affSColin Finck DPRINT("Entry!\n");
62c2c66affSColin Finck
63c2c66affSColin Finck ok_irql(PASSIVE_LEVEL);
64c2c66affSColin Finck TestDriverObject = DriverObject;
65c2c66affSColin Finck
66c2c66affSColin Finck *DeviceName = L"Example";
67c2c66affSColin Finck
68c2c66affSColin Finck trace("Hi, this is the example driver\n");
69c2c66affSColin Finck
70c2c66affSColin Finck KmtRegisterIrpHandler(IRP_MJ_CREATE, NULL, TestIrpHandler);
71c2c66affSColin Finck KmtRegisterIrpHandler(IRP_MJ_CLOSE, NULL, TestIrpHandler);
72c2c66affSColin Finck KmtRegisterMessageHandler(0, NULL, TestMessageHandler);
73c2c66affSColin Finck
74c2c66affSColin Finck return Status;
75c2c66affSColin Finck }
76c2c66affSColin Finck
77c2c66affSColin Finck /**
78c2c66affSColin Finck * @name TestUnload
79c2c66affSColin Finck *
80c2c66affSColin Finck * Test unload routine.
81c2c66affSColin Finck * This is called by the driver's Unload routine as early as possible, with
82c2c66affSColin Finck * ResultBuffer and the test device object still valid, so that test macros
83c2c66affSColin Finck * work correctly
84c2c66affSColin Finck *
85c2c66affSColin Finck * @param DriverObject
86c2c66affSColin Finck * Driver Object.
87c2c66affSColin Finck * This is guaranteed not to have been touched by Unload before the call
88c2c66affSColin Finck * to TestEntry
89c2c66affSColin Finck *
90c2c66affSColin Finck * @return Status
91c2c66affSColin Finck */
92c2c66affSColin Finck VOID
TestUnload(IN PDRIVER_OBJECT DriverObject)93c2c66affSColin Finck TestUnload(
94c2c66affSColin Finck IN PDRIVER_OBJECT DriverObject)
95c2c66affSColin Finck {
96c2c66affSColin Finck PAGED_CODE();
97c2c66affSColin Finck
98c2c66affSColin Finck DPRINT("Unload!\n");
99c2c66affSColin Finck
100c2c66affSColin Finck ok_irql(PASSIVE_LEVEL);
101c2c66affSColin Finck ok_eq_pointer(DriverObject, TestDriverObject);
102c2c66affSColin Finck
103c2c66affSColin Finck trace("Unloading example driver\n");
104c2c66affSColin Finck }
105c2c66affSColin Finck
106c2c66affSColin Finck /**
107c2c66affSColin Finck * @name TestMessageHandler
108c2c66affSColin Finck *
109c2c66affSColin Finck * Test message handler routine
110c2c66affSColin Finck *
111c2c66affSColin Finck * @param DeviceObject
112c2c66affSColin Finck * Device Object.
113c2c66affSColin Finck * This is guaranteed not to have been touched by the dispatch function
114c2c66affSColin Finck * before the call to the IRP handler
115c2c66affSColin Finck * @param Irp
116c2c66affSColin Finck * Device Object.
117c2c66affSColin Finck * This is guaranteed not to have been touched by the dispatch function
118c2c66affSColin Finck * before the call to the IRP handler, except for passing it to
119c2c66affSColin Finck * IoGetCurrentStackLocation
120c2c66affSColin Finck * @param IoStackLocation
121c2c66affSColin Finck * Device Object.
122c2c66affSColin Finck * This is guaranteed not to have been touched by the dispatch function
123c2c66affSColin Finck * before the call to the IRP handler
124c2c66affSColin Finck *
125c2c66affSColin Finck * @return Status
126c2c66affSColin Finck */
127c2c66affSColin Finck static
128c2c66affSColin Finck NTSTATUS
TestMessageHandler(IN PDEVICE_OBJECT DeviceObject,IN ULONG ControlCode,IN PVOID Buffer OPTIONAL,IN SIZE_T InLength,IN OUT PSIZE_T OutLength)129c2c66affSColin Finck TestMessageHandler(
130c2c66affSColin Finck IN PDEVICE_OBJECT DeviceObject,
131c2c66affSColin Finck IN ULONG ControlCode,
132c2c66affSColin Finck IN PVOID Buffer OPTIONAL,
133c2c66affSColin Finck IN SIZE_T InLength,
134c2c66affSColin Finck IN OUT PSIZE_T OutLength)
135c2c66affSColin Finck {
136c2c66affSColin Finck NTSTATUS Status = STATUS_SUCCESS;
137c2c66affSColin Finck
138c2c66affSColin Finck switch (ControlCode)
139c2c66affSColin Finck {
140c2c66affSColin Finck case IOCTL_NOTIFY:
141c2c66affSColin Finck {
142c2c66affSColin Finck static int TimesReceived = 0;
143c2c66affSColin Finck
144c2c66affSColin Finck ++TimesReceived;
145c2c66affSColin Finck ok(TimesReceived == 1, "Received control code 1 %d times\n", TimesReceived);
146c2c66affSColin Finck ok_eq_pointer(Buffer, NULL);
147c2c66affSColin Finck ok_eq_ulong((ULONG)InLength, 0LU);
148c2c66affSColin Finck ok_eq_ulong((ULONG)*OutLength, 0LU);
149c2c66affSColin Finck break;
150c2c66affSColin Finck }
151c2c66affSColin Finck case IOCTL_SEND_STRING:
152c2c66affSColin Finck {
153c2c66affSColin Finck static int TimesReceived = 0;
154c2c66affSColin Finck ANSI_STRING ExpectedString = RTL_CONSTANT_STRING("yay");
155c2c66affSColin Finck ANSI_STRING ReceivedString;
156c2c66affSColin Finck
157c2c66affSColin Finck ++TimesReceived;
158c2c66affSColin Finck ok(TimesReceived == 1, "Received control code 2 %d times\n", TimesReceived);
159c2c66affSColin Finck ok(Buffer != NULL, "Buffer is NULL\n");
160c2c66affSColin Finck ok_eq_ulong((ULONG)InLength, (ULONG)ExpectedString.Length);
161c2c66affSColin Finck ok_eq_ulong((ULONG)*OutLength, 0LU);
162c2c66affSColin Finck ReceivedString.MaximumLength = ReceivedString.Length = (USHORT)InLength;
163c2c66affSColin Finck ReceivedString.Buffer = Buffer;
164c2c66affSColin Finck ok(RtlCompareString(&ExpectedString, &ReceivedString, FALSE) == 0, "Received string: %Z\n", &ReceivedString);
165c2c66affSColin Finck break;
166c2c66affSColin Finck }
167c2c66affSColin Finck case IOCTL_SEND_MYSTRUCT:
168c2c66affSColin Finck {
169c2c66affSColin Finck static int TimesReceived = 0;
170c2c66affSColin Finck MY_STRUCT ExpectedStruct = { 123, ":D" };
171c2c66affSColin Finck MY_STRUCT ResultStruct = { 456, "!!!" };
172c2c66affSColin Finck
173c2c66affSColin Finck ++TimesReceived;
174c2c66affSColin Finck ok(TimesReceived == 1, "Received control code 3 %d times\n", TimesReceived);
175c2c66affSColin Finck ok(Buffer != NULL, "Buffer is NULL\n");
176c2c66affSColin Finck ok_eq_ulong((ULONG)InLength, (ULONG)sizeof ExpectedStruct);
177c2c66affSColin Finck ok_eq_ulong((ULONG)*OutLength, 2LU * sizeof ExpectedStruct);
178c2c66affSColin Finck if (!skip(Buffer && InLength >= sizeof ExpectedStruct, "Cannot read from buffer!\n"))
179c2c66affSColin Finck ok(RtlCompareMemory(&ExpectedStruct, Buffer, sizeof ExpectedStruct) == sizeof ExpectedStruct, "Buffer does not contain expected values\n");
180c2c66affSColin Finck
181c2c66affSColin Finck if (!skip(Buffer && *OutLength >= 2 * sizeof ExpectedStruct, "Cannot write to buffer!\n"))
182c2c66affSColin Finck {
183c2c66affSColin Finck RtlCopyMemory((PCHAR)Buffer + sizeof ExpectedStruct, &ResultStruct, sizeof ResultStruct);
184c2c66affSColin Finck *OutLength = 2 * sizeof ExpectedStruct;
185c2c66affSColin Finck }
186c2c66affSColin Finck break;
187c2c66affSColin Finck }
188c2c66affSColin Finck default:
189c2c66affSColin Finck ok(0, "Got an unknown message! DeviceObject=%p, ControlCode=%lu, Buffer=%p, In=%lu, Out=%lu bytes\n",
190c2c66affSColin Finck DeviceObject, ControlCode, Buffer, InLength, *OutLength);
191c2c66affSColin Finck break;
192c2c66affSColin Finck }
193c2c66affSColin Finck
194c2c66affSColin Finck return Status;
195c2c66affSColin Finck }
196c2c66affSColin Finck
197c2c66affSColin Finck /**
198c2c66affSColin Finck * @name TestIrpHandler
199c2c66affSColin Finck *
200c2c66affSColin Finck * Test IRP handler routine
201c2c66affSColin Finck *
202c2c66affSColin Finck * @param DeviceObject
203c2c66affSColin Finck * Device Object.
204c2c66affSColin Finck * This is guaranteed not to have been touched by the dispatch function
205c2c66affSColin Finck * before the call to the IRP handler
206c2c66affSColin Finck * @param Irp
207c2c66affSColin Finck * Device Object.
208c2c66affSColin Finck * This is guaranteed not to have been touched by the dispatch function
209c2c66affSColin Finck * before the call to the IRP handler, except for passing it to
210c2c66affSColin Finck * IoGetCurrentStackLocation
211c2c66affSColin Finck * @param IoStackLocation
212c2c66affSColin Finck * Device Object.
213c2c66affSColin Finck * This is guaranteed not to have been touched by the dispatch function
214c2c66affSColin Finck * before the call to the IRP handler
215c2c66affSColin Finck *
216c2c66affSColin Finck * @return Status
217c2c66affSColin Finck */
218c2c66affSColin Finck static
219c2c66affSColin Finck NTSTATUS
TestIrpHandler(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PIO_STACK_LOCATION IoStackLocation)220c2c66affSColin Finck TestIrpHandler(
221c2c66affSColin Finck IN PDEVICE_OBJECT DeviceObject,
222c2c66affSColin Finck IN PIRP Irp,
223c2c66affSColin Finck IN PIO_STACK_LOCATION IoStackLocation)
224c2c66affSColin Finck {
225c2c66affSColin Finck NTSTATUS Status = STATUS_SUCCESS;
226c2c66affSColin Finck
227c2c66affSColin Finck DPRINT("IRP!\n");
228c2c66affSColin Finck
229c2c66affSColin Finck ok_irql(PASSIVE_LEVEL);
230c2c66affSColin Finck ok_eq_pointer(DeviceObject->DriverObject, TestDriverObject);
231c2c66affSColin Finck
232c2c66affSColin Finck if (IoStackLocation->MajorFunction == IRP_MJ_CREATE)
233c2c66affSColin Finck trace("Got IRP_MJ_CREATE!\n");
234c2c66affSColin Finck else if (IoStackLocation->MajorFunction == IRP_MJ_CLOSE)
235c2c66affSColin Finck trace("Got IRP_MJ_CLOSE!\n");
236c2c66affSColin Finck else
237c2c66affSColin Finck trace("Got an IRP!\n");
238c2c66affSColin Finck
239c2c66affSColin Finck Irp->IoStatus.Status = Status;
240c2c66affSColin Finck Irp->IoStatus.Information = 0;
241c2c66affSColin Finck
242c2c66affSColin Finck IoCompleteRequest(Irp, IO_NO_INCREMENT);
243c2c66affSColin Finck
244c2c66affSColin Finck return Status;
245c2c66affSColin Finck }
246