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