1 /*
2  * PROJECT:         ReactOS kernel-mode tests
3  * LICENSE:         LGPLv2+ - See COPYING.LIB in the top level directory
4  * PURPOSE:         Kernel-Mode Test Suite Device Interface functions test
5  * PROGRAMMER:      Filip Navara <xnavara@volny.cz>
6  */
7 
8 /* TODO: what's with the prototypes at the top, what's with the if-ed out part? Doesn't process most results */
9 
10 #include <kmt_test.h>
11 #include <poclass.h>
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 #if 0
17 NTSTATUS
18 (NTAPI *IoGetDeviceInterfaces_Func)(
19    IN CONST GUID *InterfaceClassGuid,
20    IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
21    IN ULONG Flags,
22    OUT PWSTR *SymbolicLinkList);
23 
24 NTSTATUS NTAPI
25 ReactOS_IoGetDeviceInterfaces(
26    IN CONST GUID *InterfaceClassGuid,
27    IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
28    IN ULONG Flags,
29    OUT PWSTR *SymbolicLinkList);
30 #endif /* 0 */
31 
32 static VOID DeviceInterfaceTest_Func()
33 {
34    NTSTATUS Status;
35    PWSTR SymbolicLinkList;
36    PWSTR SymbolicLinkListPtr;
37    GUID Guid = {0x378de44c, 0x56ef, 0x11d1, {0xbc, 0x8c, 0x00, 0xa0, 0xc9, 0x14, 0x05, 0xdd}};
38 
39    Status = IoGetDeviceInterfaces(
40       &Guid,
41       NULL,
42       0,
43       &SymbolicLinkList);
44 
45    ok(NT_SUCCESS(Status),
46          "IoGetDeviceInterfaces failed with status 0x%X\n",
47          (unsigned int)Status);
48    if (!NT_SUCCESS(Status))
49    {
50       return;
51    }
52 
53    DPRINT("IoGetDeviceInterfaces results:\n");
54    for (SymbolicLinkListPtr = SymbolicLinkList;
55         SymbolicLinkListPtr[0] != 0 && SymbolicLinkListPtr[1] != 0;
56         SymbolicLinkListPtr += wcslen(SymbolicLinkListPtr) + 1)
57    {
58       DPRINT1("Symbolic Link: %S\n", SymbolicLinkListPtr);
59    }
60 
61 #if 0
62    DPRINT("[PnP Test] Trying to get aliases\n");
63 
64    for (SymbolicLinkListPtr = SymbolicLinkList;
65         SymbolicLinkListPtr[0] != 0 && SymbolicLinkListPtr[1] != 0;
66         SymbolicLinkListPtr += wcslen(SymbolicLinkListPtr) + 1)
67    {
68       UNICODE_STRING SymbolicLink;
69       UNICODE_STRING AliasSymbolicLink;
70 
71       SymbolicLink.Buffer = SymbolicLinkListPtr;
72       SymbolicLink.Length = SymbolicLink.MaximumLength = wcslen(SymbolicLinkListPtr);
73       RtlInitUnicodeString(&AliasSymbolicLink, NULL);
74       IoGetDeviceInterfaceAlias(
75          &SymbolicLink,
76          &AliasGuid,
77          &AliasSymbolicLink);
78       if (AliasSymbolicLink.Buffer != NULL)
79       {
80          DPRINT("[PnP Test] Original: %S\n", SymbolicLinkListPtr);
81          DPRINT("[PnP Test] Alias: %S\n", AliasSymbolicLink.Buffer);
82       }
83    }
84 #endif
85 
86    ExFreePool(SymbolicLinkList);
87 }
88 
89 static
90 VOID
91 Test_IoRegisterDeviceInterface(VOID)
92 {
93     GUID Guid = {0x378de44c, 0x56ef, 0x11d1, {0xbc, 0x8c, 0x00, 0xa0, 0xc9, 0x14, 0x05, 0xdd}};
94     DEVICE_OBJECT DeviceObject;
95     EXTENDED_DEVOBJ_EXTENSION DeviceObjectExtension;
96     DEVICE_NODE DeviceNode;
97     UNICODE_STRING SymbolicLinkName;
98     NTSTATUS Status;
99 
100     RtlInitUnicodeString(&SymbolicLinkName, L"");
101 
102     // Prepare our surrogate of a Device Object
103     DeviceObject.DeviceObjectExtension = (PDEVOBJ_EXTENSION)&DeviceObjectExtension;
104 
105     // 1. DeviceNode = NULL
106     DeviceObjectExtension.DeviceNode = NULL;
107     Status = IoRegisterDeviceInterface(&DeviceObject, &Guid, NULL,
108         &SymbolicLinkName);
109 
110     ok(Status == STATUS_INVALID_DEVICE_REQUEST,
111         "IoRegisterDeviceInterface returned 0x%08lX\n", Status);
112 
113     // 2. DeviceNode->InstancePath is of a null length
114     DeviceObjectExtension.DeviceNode = &DeviceNode;
115     DeviceNode.InstancePath.Length = 0;
116     Status = IoRegisterDeviceInterface(&DeviceObject, &Guid, NULL,
117         &SymbolicLinkName);
118 
119     ok(Status == STATUS_INVALID_DEVICE_REQUEST,
120         "IoRegisterDeviceInterface returned 0x%08lX\n", Status);
121 
122     DeviceInterfaceTest_Func();
123 }
124 
125 static UCHAR NotificationContext;
126 
127 static DRIVER_NOTIFICATION_CALLBACK_ROUTINE NotificationCallback;
128 static
129 NTSTATUS
130 NTAPI
131 NotificationCallback(
132     _In_ PVOID NotificationStructure,
133     _Inout_opt_ PVOID Context)
134 {
135     PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification = NotificationStructure;
136     NTSTATUS Status;
137     OBJECT_ATTRIBUTES ObjectAttributes;
138     HANDLE Handle;
139 
140     ok_irql(PASSIVE_LEVEL);
141     ok_eq_pointer(Context, &NotificationContext);
142     ok_eq_uint(Notification->Version, 1);
143     ok_eq_uint(Notification->Size, sizeof(*Notification));
144 
145     /* symbolic link must exist */
146     trace("Interface change: %wZ\n", Notification->SymbolicLinkName);
147     InitializeObjectAttributes(&ObjectAttributes,
148                                Notification->SymbolicLinkName,
149                                OBJ_KERNEL_HANDLE,
150                                NULL,
151                                NULL);
152     Status = ZwOpenSymbolicLinkObject(&Handle, GENERIC_READ, &ObjectAttributes);
153     ok_eq_hex(Status, STATUS_SUCCESS);
154     if (!skip(NT_SUCCESS(Status), "No symbolic link\n"))
155     {
156         Status = ObCloseHandle(Handle, KernelMode);
157         ok_eq_hex(Status, STATUS_SUCCESS);
158     }
159     return STATUS_SUCCESS;
160 }
161 
162 static
163 VOID
164 Test_IoRegisterPlugPlayNotification(VOID)
165 {
166     NTSTATUS Status;
167     PVOID NotificationEntry;
168 
169     Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
170                                             PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
171                                             (PVOID)&GUID_DEVICE_SYS_BUTTON,
172                                             KmtDriverObject,
173                                             NotificationCallback,
174                                             &NotificationContext,
175                                             &NotificationEntry);
176     ok_eq_hex(Status, STATUS_SUCCESS);
177     if (!skip(NT_SUCCESS(Status), "PlugPlayNotification not registered\n"))
178     {
179         Status = IoUnregisterPlugPlayNotification(NotificationEntry);
180         ok_eq_hex(Status, STATUS_SUCCESS);
181     }
182 }
183 
184 static
185 VOID
186 Test_IoSetDeviceInterface(VOID)
187 {
188     NTSTATUS Status;
189     UNICODE_STRING SymbolicLinkName;
190     PWCHAR Buffer;
191     ULONG BufferSize;
192 
193     /* Invalid prefix or GUID */
194     KmtStartSeh()
195         Status = IoSetDeviceInterfaceState(NULL, TRUE);
196     KmtEndSeh(STATUS_SUCCESS)
197     ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
198 
199     RtlInitEmptyUnicodeString(&SymbolicLinkName, NULL, 0);
200     KmtStartSeh()
201         Status = IoSetDeviceInterfaceState(&SymbolicLinkName, TRUE);
202     KmtEndSeh(STATUS_SUCCESS)
203     ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
204 
205     RtlInitUnicodeString(&SymbolicLinkName, L"\\??");
206     KmtStartSeh()
207         Status = IoSetDeviceInterfaceState(&SymbolicLinkName, TRUE);
208     KmtEndSeh(STATUS_SUCCESS)
209     ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
210 
211     RtlInitUnicodeString(&SymbolicLinkName, L"\\??\\");
212     KmtStartSeh()
213         Status = IoSetDeviceInterfaceState(&SymbolicLinkName, TRUE);
214     KmtEndSeh(STATUS_SUCCESS)
215     ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
216 
217     RtlInitUnicodeString(&SymbolicLinkName, L"\\??\\\\");
218     KmtStartSeh()
219         Status = IoSetDeviceInterfaceState(&SymbolicLinkName, TRUE);
220     KmtEndSeh(STATUS_SUCCESS)
221     ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
222 
223     RtlInitUnicodeString(&SymbolicLinkName, L"\\??\\{aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa}");
224     KmtStartSeh()
225         Status = IoSetDeviceInterfaceState(&SymbolicLinkName, TRUE);
226     KmtEndSeh(STATUS_SUCCESS)
227     ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
228 
229     /* Valid prefix & GUID, invalid device node */
230     RtlInitUnicodeString(&SymbolicLinkName, L"\\??\\X{aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa}");
231     KmtStartSeh()
232         Status = IoSetDeviceInterfaceState(&SymbolicLinkName, TRUE);
233     KmtEndSeh(STATUS_SUCCESS)
234     ok_eq_hex(Status, STATUS_OBJECT_NAME_NOT_FOUND);
235 
236     RtlInitUnicodeString(&SymbolicLinkName, L"\\\\?\\X{aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa}");
237     KmtStartSeh()
238         Status = IoSetDeviceInterfaceState(&SymbolicLinkName, TRUE);
239     KmtEndSeh(STATUS_SUCCESS)
240     ok_eq_hex(Status, STATUS_OBJECT_NAME_NOT_FOUND);
241 
242     RtlInitUnicodeString(&SymbolicLinkName, L"\\??\\X{aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa}\\");
243     KmtStartSeh()
244         Status = IoSetDeviceInterfaceState(&SymbolicLinkName, TRUE);
245     KmtEndSeh(STATUS_SUCCESS)
246     ok_eq_hex(Status, STATUS_OBJECT_NAME_NOT_FOUND);
247 
248     RtlInitUnicodeString(&SymbolicLinkName, L"\\??\\#{aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa}");
249     KmtStartSeh()
250         Status = IoSetDeviceInterfaceState(&SymbolicLinkName, TRUE);
251     KmtEndSeh(STATUS_SUCCESS)
252     ok_eq_hex(Status, STATUS_OBJECT_NAME_NOT_FOUND);
253 
254     /* Must not read past the buffer */
255     RtlInitUnicodeString(&SymbolicLinkName, L"\\??\\#{aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa}");
256     BufferSize = SymbolicLinkName.Length;
257     Buffer = KmtAllocateGuarded(BufferSize);
258     if (!skip(Buffer != NULL, "Failed to allocate %lu bytes\n", BufferSize))
259     {
260         RtlCopyMemory(Buffer, SymbolicLinkName.Buffer, BufferSize);
261         SymbolicLinkName.Buffer = Buffer;
262         SymbolicLinkName.MaximumLength = BufferSize;
263         KmtStartSeh()
264             Status = IoSetDeviceInterfaceState(&SymbolicLinkName, TRUE);
265         KmtEndSeh(STATUS_SUCCESS)
266         ok_eq_hex(Status, STATUS_OBJECT_NAME_NOT_FOUND);
267         KmtFreeGuarded(Buffer);
268     }
269 
270     RtlInitUnicodeString(&SymbolicLinkName, L"\\??\\#aaaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa}");
271     BufferSize = SymbolicLinkName.Length;
272     Buffer = KmtAllocateGuarded(BufferSize);
273     if (!skip(Buffer != NULL, "Failed to allocate %lu bytes\n", BufferSize))
274     {
275         RtlCopyMemory(Buffer, SymbolicLinkName.Buffer, BufferSize);
276         SymbolicLinkName.Buffer = Buffer;
277         SymbolicLinkName.MaximumLength = BufferSize;
278         KmtStartSeh()
279             Status = IoSetDeviceInterfaceState(&SymbolicLinkName, TRUE);
280         KmtEndSeh(STATUS_SUCCESS)
281         ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
282         KmtFreeGuarded(Buffer);
283     }
284 }
285 
286 START_TEST(IoDeviceInterface)
287 {
288     // FIXME: This test crashes in Windows
289     (void)Test_IoRegisterDeviceInterface;
290     Test_IoRegisterPlugPlayNotification();
291     Test_IoSetDeviceInterface();
292 }