4d42858241a79f91a0831eafb756ea6ea9cdd189
[reactos.git] / reactos / ntoskrnl / io / deviface.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/io/pnpmgr/devintrf.c
5 * PURPOSE: Device interface functions
6 * PROGRAMMER: Filip Navara (xnavara@volny.cz)
7 * Matthew Brace (ismarc@austin.rr.com)
8 * UPDATE HISTORY:
9 * 22/09/2003 FiN Created
10 */
11
12 /* INCLUDES ******************************************************************/
13
14 #include <ntoskrnl.h>
15
16 #define NDEBUG
17 #include <internal/debug.h>
18
19 DEFINE_GUID(GUID_SERENUM_BUS_ENUMERATOR,
20 0x4D36E978L, 0xE325, 0x11CE, 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18);
21
22 /* FUNCTIONS *****************************************************************/
23
24 /*
25 * @unimplemented
26 */
27
28 NTSTATUS STDCALL
29 IoOpenDeviceInterfaceRegistryKey(
30 IN PUNICODE_STRING SymbolicLinkName,
31 IN ACCESS_MASK DesiredAccess,
32 OUT PHANDLE DeviceInterfaceKey)
33 {
34 return STATUS_NOT_IMPLEMENTED;
35 }
36
37 /*
38 * @unimplemented
39 */
40
41 NTSTATUS STDCALL
42 IoGetDeviceInterfaceAlias(
43 IN PUNICODE_STRING SymbolicLinkName,
44 IN CONST GUID *AliasInterfaceClassGuid,
45 OUT PUNICODE_STRING AliasSymbolicLinkName)
46 {
47 return STATUS_NOT_IMPLEMENTED;
48 }
49
50 /*
51 * IoGetDeviceInterfaces
52 *
53 * Returns a list of device interfaces of a particular device interface class.
54 *
55 * Parameters
56 * InterfaceClassGuid
57 * Points to a class GUID specifying the device interface class.
58 *
59 * PhysicalDeviceObject
60 * Points to an optional PDO that narrows the search to only the
61 * device interfaces of the device represented by the PDO.
62 *
63 * Flags
64 * Specifies flags that modify the search for device interfaces. The
65 * DEVICE_INTERFACE_INCLUDE_NONACTIVE flag specifies that the list of
66 * returned symbolic links should contain also disabled device
67 * interfaces in addition to the enabled ones.
68 *
69 * SymbolicLinkList
70 * Points to a character pointer that is filled in on successful return
71 * with a list of unicode strings identifying the device interfaces
72 * that match the search criteria. The newly allocated buffer contains
73 * a list of symbolic link names. Each unicode string in the list is
74 * null-terminated; the end of the whole list is marked by an additional
75 * NULL. The caller is responsible for freeing the buffer (ExFreePool)
76 * when it is no longer needed.
77 * If no device interfaces match the search criteria, this routine
78 * returns STATUS_SUCCESS and the string contains a single NULL
79 * character.
80 *
81 * Status
82 * @implemented
83 *
84 * The parameters PhysicalDeviceObject and Flags aren't correctly
85 * processed. Rest of the cases was tested under Windows(R) XP and
86 * the function worked correctly.
87 */
88
89 NTSTATUS STDCALL
90 IoGetDeviceInterfaces(
91 IN CONST GUID *InterfaceClassGuid,
92 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
93 IN ULONG Flags,
94 OUT PWSTR *SymbolicLinkList)
95 {
96 PWCHAR BaseKeyString = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\DeviceClasses\\";
97 PWCHAR BaseInterfaceString = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
98 UNICODE_STRING GuidString;
99 UNICODE_STRING BaseKeyName;
100 UNICODE_STRING AliasKeyName;
101 UNICODE_STRING SymbolicLink;
102 UNICODE_STRING Control;
103 UNICODE_STRING SubKeyName;
104 UNICODE_STRING SymbolicLinkKeyName;
105 UNICODE_STRING ControlKeyName;
106 UNICODE_STRING TempString;
107 HANDLE InterfaceKey;
108 HANDLE SubKey;
109 HANDLE SymbolicLinkKey;
110 PKEY_FULL_INFORMATION fip;
111 PKEY_FULL_INFORMATION bfip = NULL;
112 PKEY_BASIC_INFORMATION bip;
113 PKEY_VALUE_PARTIAL_INFORMATION vpip = NULL;
114 PWCHAR SymLinkList = NULL;
115 ULONG SymLinkListSize = 0;
116 NTSTATUS Status;
117 ULONG Size = 0;
118 ULONG i = 0;
119 ULONG j = 0;
120 OBJECT_ATTRIBUTES ObjectAttributes;
121
122 Status = RtlStringFromGUID(InterfaceClassGuid, &GuidString);
123 if (!NT_SUCCESS(Status))
124 {
125 DPRINT("RtlStringFromGUID() Failed.\n");
126 return STATUS_INVALID_HANDLE;
127 }
128
129 RtlInitUnicodeString(&AliasKeyName, BaseInterfaceString);
130 RtlInitUnicodeString(&SymbolicLink, L"SymbolicLink");
131 RtlInitUnicodeString(&Control, L"\\Control");
132 BaseKeyName.Length = wcslen(BaseKeyString) * sizeof(WCHAR);
133 BaseKeyName.MaximumLength = BaseKeyName.Length + (38 * sizeof(WCHAR));
134 BaseKeyName.Buffer = ExAllocatePool(
135 NonPagedPool,
136 BaseKeyName.MaximumLength);
137 ASSERT(BaseKeyName.Buffer != NULL);
138 wcscpy(BaseKeyName.Buffer, BaseKeyString);
139 RtlAppendUnicodeStringToString(&BaseKeyName, &GuidString);
140
141 if (PhysicalDeviceObject)
142 {
143 WCHAR GuidBuffer[40];
144 UNICODE_STRING PdoGuidString;
145
146 RtlFreeUnicodeString(&BaseKeyName);
147
148 IoGetDeviceProperty(
149 PhysicalDeviceObject,
150 DevicePropertyClassGuid,
151 sizeof(GuidBuffer),
152 GuidBuffer,
153 &Size);
154
155 RtlInitUnicodeString(&PdoGuidString, GuidBuffer);
156 if (RtlCompareUnicodeString(&GuidString, &PdoGuidString, TRUE))
157 {
158 DPRINT("Inconsistent Guid's asked for in IoGetDeviceInterfaces()\n");
159 return STATUS_INVALID_HANDLE;
160 }
161
162 DPRINT("IoGetDeviceInterfaces() called with PDO, not implemented.\n");
163 return STATUS_NOT_IMPLEMENTED;
164 }
165 else
166 {
167 InitializeObjectAttributes(
168 &ObjectAttributes,
169 &BaseKeyName,
170 OBJ_CASE_INSENSITIVE,
171 NULL,
172 NULL);
173
174 Status = ZwOpenKey(
175 &InterfaceKey,
176 KEY_READ,
177 &ObjectAttributes);
178
179 if (!NT_SUCCESS(Status))
180 {
181 DPRINT("ZwOpenKey() Failed. (0x%X)\n", Status);
182 RtlFreeUnicodeString(&BaseKeyName);
183 return Status;
184 }
185
186 Status = ZwQueryKey(
187 InterfaceKey,
188 KeyFullInformation,
189 NULL,
190 0,
191 &Size);
192
193 if (Status != STATUS_BUFFER_TOO_SMALL)
194 {
195 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status);
196 RtlFreeUnicodeString(&BaseKeyName);
197 ZwClose(InterfaceKey);
198 return Status;
199 }
200
201 fip = (PKEY_FULL_INFORMATION)ExAllocatePool(NonPagedPool, Size);
202 ASSERT(fip != NULL);
203
204 Status = ZwQueryKey(
205 InterfaceKey,
206 KeyFullInformation,
207 fip,
208 Size,
209 &Size);
210
211 if (!NT_SUCCESS(Status))
212 {
213 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status);
214 ExFreePool(fip);
215 RtlFreeUnicodeString(&BaseKeyName);
216 ZwClose(InterfaceKey);
217 return Status;
218 }
219
220 for (; i < fip->SubKeys; i++)
221 {
222 Status = ZwEnumerateKey(
223 InterfaceKey,
224 i,
225 KeyBasicInformation,
226 NULL,
227 0,
228 &Size);
229
230 if (Status != STATUS_BUFFER_TOO_SMALL)
231 {
232 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status);
233 ExFreePool(fip);
234 if (SymLinkList != NULL)
235 ExFreePool(SymLinkList);
236 RtlFreeUnicodeString(&BaseKeyName);
237 ZwClose(InterfaceKey);
238 return Status;
239 }
240
241 bip = (PKEY_BASIC_INFORMATION)ExAllocatePool(NonPagedPool, Size);
242 ASSERT(bip != NULL);
243
244 Status = ZwEnumerateKey(
245 InterfaceKey,
246 i,
247 KeyBasicInformation,
248 bip,
249 Size,
250 &Size);
251
252 if (!NT_SUCCESS(Status))
253 {
254 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status);
255 ExFreePool(fip);
256 ExFreePool(bip);
257 if (SymLinkList != NULL)
258 ExFreePool(SymLinkList);
259 RtlFreeUnicodeString(&BaseKeyName);
260 ZwClose(InterfaceKey);
261 return Status;
262 }
263
264 SubKeyName.Length = 0;
265 SubKeyName.MaximumLength = BaseKeyName.Length + bip->NameLength + sizeof(WCHAR);
266 SubKeyName.Buffer = ExAllocatePool(NonPagedPool, SubKeyName.MaximumLength);
267 ASSERT(SubKeyName.Buffer != NULL);
268 TempString.Length = TempString.MaximumLength = bip->NameLength;
269 TempString.Buffer = bip->Name;
270 RtlCopyUnicodeString(&SubKeyName, &BaseKeyName);
271 RtlAppendUnicodeToString(&SubKeyName, L"\\");
272 RtlAppendUnicodeStringToString(&SubKeyName, &TempString);
273
274 ExFreePool(bip);
275
276 InitializeObjectAttributes(
277 &ObjectAttributes,
278 &SubKeyName,
279 OBJ_CASE_INSENSITIVE,
280 NULL,
281 NULL);
282
283 Status = ZwOpenKey(
284 &SubKey,
285 KEY_READ,
286 &ObjectAttributes);
287
288 if (!NT_SUCCESS(Status))
289 {
290 DPRINT("ZwOpenKey() Failed. (0x%X)\n", Status);
291 ExFreePool(fip);
292 if (SymLinkList != NULL)
293 ExFreePool(SymLinkList);
294 RtlFreeUnicodeString(&SubKeyName);
295 RtlFreeUnicodeString(&BaseKeyName);
296 ZwClose(InterfaceKey);
297 return Status;
298 }
299
300 Status = ZwQueryKey(
301 SubKey,
302 KeyFullInformation,
303 NULL,
304 0,
305 &Size);
306
307 if (Status != STATUS_BUFFER_TOO_SMALL)
308 {
309 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status);
310 ExFreePool(fip);
311 RtlFreeUnicodeString(&BaseKeyName);
312 RtlFreeUnicodeString(&SubKeyName);
313 ZwClose(SubKey);
314 ZwClose(InterfaceKey);
315 return Status;
316 }
317
318 bfip = (PKEY_FULL_INFORMATION)ExAllocatePool(NonPagedPool, Size);
319 ASSERT(bfip != NULL);
320
321 Status = ZwQueryKey(
322 SubKey,
323 KeyFullInformation,
324 bfip,
325 Size,
326 &Size);
327
328 if (!NT_SUCCESS(Status))
329 {
330 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status);
331 ExFreePool(fip);
332 RtlFreeUnicodeString(&SubKeyName);
333 RtlFreeUnicodeString(&BaseKeyName);
334 ZwClose(SubKey);
335 ZwClose(InterfaceKey);
336 return Status;
337 }
338
339 for(j = 0; j < bfip->SubKeys; j++)
340 {
341 Status = ZwEnumerateKey(
342 SubKey,
343 j,
344 KeyBasicInformation,
345 NULL,
346 0,
347 &Size);
348
349 if (Status == STATUS_NO_MORE_ENTRIES)
350 continue;
351
352 if (Status != STATUS_BUFFER_TOO_SMALL)
353 {
354 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status);
355 ExFreePool(bfip);
356 ExFreePool(fip);
357 if (SymLinkList != NULL)
358 ExFreePool(SymLinkList);
359 RtlFreeUnicodeString(&SubKeyName);
360 RtlFreeUnicodeString(&BaseKeyName);
361 ZwClose(SubKey);
362 ZwClose(InterfaceKey);
363 return Status;
364 }
365
366 bip = (PKEY_BASIC_INFORMATION)ExAllocatePool(NonPagedPool, Size);
367 ASSERT(bip != NULL);
368
369 Status = ZwEnumerateKey(
370 SubKey,
371 j,
372 KeyBasicInformation,
373 bip,
374 Size,
375 &Size);
376
377 if (!NT_SUCCESS(Status))
378 {
379 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status);
380 ExFreePool(fip);
381 ExFreePool(bfip);
382 ExFreePool(bip);
383 if (SymLinkList != NULL)
384 ExFreePool(SymLinkList);
385 RtlFreeUnicodeString(&SubKeyName);
386 RtlFreeUnicodeString(&BaseKeyName);
387 ZwClose(SubKey);
388 ZwClose(InterfaceKey);
389 return Status;
390 }
391
392 if (!wcsncmp(bip->Name, L"Control", bip->NameLength))
393 {
394 continue;
395 }
396
397 SymbolicLinkKeyName.Length = 0;
398 SymbolicLinkKeyName.MaximumLength = SubKeyName.Length + bip->NameLength + sizeof(WCHAR);
399 SymbolicLinkKeyName.Buffer = ExAllocatePool(NonPagedPool, SymbolicLinkKeyName.MaximumLength);
400 ASSERT(SymbolicLinkKeyName.Buffer != NULL);
401 TempString.Length = TempString.MaximumLength = bip->NameLength;
402 TempString.Buffer = bip->Name;
403 RtlCopyUnicodeString(&SymbolicLinkKeyName, &SubKeyName);
404 RtlAppendUnicodeToString(&SymbolicLinkKeyName, L"\\");
405 RtlAppendUnicodeStringToString(&SymbolicLinkKeyName, &TempString);
406
407 ControlKeyName.Length = 0;
408 ControlKeyName.MaximumLength = SymbolicLinkKeyName.Length + Control.Length + sizeof(WCHAR);
409 ControlKeyName.Buffer = ExAllocatePool(NonPagedPool, ControlKeyName.MaximumLength);
410 ASSERT(ControlKeyName.Buffer != NULL);
411 RtlCopyUnicodeString(&ControlKeyName, &SymbolicLinkKeyName);
412 RtlAppendUnicodeStringToString(&ControlKeyName, &Control);
413
414 ExFreePool(bip);
415
416 InitializeObjectAttributes(
417 &ObjectAttributes,
418 &SymbolicLinkKeyName,
419 OBJ_CASE_INSENSITIVE,
420 NULL,
421 NULL);
422
423 Status = ZwOpenKey(
424 &SymbolicLinkKey,
425 KEY_READ,
426 &ObjectAttributes);
427
428 if (!NT_SUCCESS(Status))
429 {
430 DPRINT("ZwOpenKey() Failed. (0x%X)\n", Status);
431 ExFreePool(fip);
432 ExFreePool(bfip);
433 if (SymLinkList != NULL)
434 ExFreePool(SymLinkList);
435 RtlFreeUnicodeString(&SymbolicLinkKeyName);
436 RtlFreeUnicodeString(&SubKeyName);
437 RtlFreeUnicodeString(&BaseKeyName);
438 ZwClose(SubKey);
439 ZwClose(InterfaceKey);
440 return Status;
441 }
442
443 Status = ZwQueryValueKey(
444 SymbolicLinkKey,
445 &SymbolicLink,
446 KeyValuePartialInformation,
447 NULL,
448 0,
449 &Size);
450
451 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
452 continue;
453
454 if (Status != STATUS_BUFFER_TOO_SMALL)
455 {
456 DPRINT("ZwQueryValueKey() Failed.(0x%X)\n", Status);
457 ExFreePool(fip);
458 ExFreePool(bfip);
459 if (SymLinkList != NULL)
460 ExFreePool(SymLinkList);
461 RtlFreeUnicodeString(&SymbolicLinkKeyName);
462 RtlFreeUnicodeString(&SubKeyName);
463 RtlFreeUnicodeString(&BaseKeyName);
464 ZwClose(SymbolicLinkKey);
465 ZwClose(SubKey);
466 ZwClose(InterfaceKey);
467 return Status;
468 }
469
470 vpip = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool(NonPagedPool, Size);
471 ASSERT(vpip != NULL);
472
473 Status = ZwQueryValueKey(
474 SymbolicLinkKey,
475 &SymbolicLink,
476 KeyValuePartialInformation,
477 vpip,
478 Size,
479 &Size);
480
481 if (!NT_SUCCESS(Status))
482 {
483 DPRINT("ZwQueryValueKey() Failed.(0x%X)\n", Status);
484 ExFreePool(fip);
485 ExFreePool(bfip);
486 ExFreePool(vpip);
487 if (SymLinkList != NULL)
488 ExFreePool(SymLinkList);
489 RtlFreeUnicodeString(&SymbolicLinkKeyName);
490 RtlFreeUnicodeString(&SubKeyName);
491 RtlFreeUnicodeString(&BaseKeyName);
492 ZwClose(SymbolicLinkKey);
493 ZwClose(SubKey);
494 ZwClose(InterfaceKey);
495 return Status;
496 }
497
498 Status = RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, ControlKeyName.Buffer);
499
500 if (NT_SUCCESS(Status))
501 {
502 /* Put the name in the string here */
503 if (SymLinkList == NULL)
504 {
505 SymLinkListSize = vpip->DataLength;
506 SymLinkList = ExAllocatePool(NonPagedPool, SymLinkListSize + sizeof(WCHAR));
507 ASSERT(SymLinkList != NULL);
508 RtlCopyMemory(SymLinkList, vpip->Data, vpip->DataLength);
509 SymLinkList[vpip->DataLength / sizeof(WCHAR)] = 0;
510 SymLinkList[1] = '?';
511 }
512 else
513 {
514 PWCHAR OldSymLinkList;
515 ULONG OldSymLinkListSize;
516 PWCHAR SymLinkListPtr;
517
518 OldSymLinkList = SymLinkList;
519 OldSymLinkListSize = SymLinkListSize;
520 SymLinkListSize += vpip->DataLength;
521 SymLinkList = ExAllocatePool(NonPagedPool, SymLinkListSize + sizeof(WCHAR));
522 ASSERT(SymLinkList != NULL);
523 RtlCopyMemory(SymLinkList, OldSymLinkList, OldSymLinkListSize);
524 ExFreePool(OldSymLinkList);
525 SymLinkListPtr = SymLinkList + (OldSymLinkListSize / sizeof(WCHAR));
526 RtlCopyMemory(SymLinkListPtr, vpip->Data, vpip->DataLength);
527 SymLinkListPtr[vpip->DataLength / sizeof(WCHAR)] = 0;
528 SymLinkListPtr[1] = '?';
529 }
530 }
531
532 RtlFreeUnicodeString(&SymbolicLinkKeyName);
533 RtlFreeUnicodeString(&ControlKeyName);
534 ZwClose(SymbolicLinkKey);
535 }
536
537 ExFreePool(vpip);
538 RtlFreeUnicodeString(&SubKeyName);
539 ZwClose(SubKey);
540 }
541
542 if (SymLinkList != NULL)
543 {
544 SymLinkList[SymLinkListSize / sizeof(WCHAR)] = 0;
545 }
546 else
547 {
548 SymLinkList = ExAllocatePool(NonPagedPool, 2 * sizeof(WCHAR));
549 SymLinkList[0] = 0;
550 }
551
552 *SymbolicLinkList = SymLinkList;
553
554 RtlFreeUnicodeString(&BaseKeyName);
555 ZwClose(InterfaceKey);
556 ExFreePool(bfip);
557 ExFreePool(fip);
558 }
559
560 return STATUS_SUCCESS;
561 }
562
563 /*
564 * @unimplemented
565 */
566
567 NTSTATUS STDCALL
568 IoRegisterDeviceInterface(
569 IN PDEVICE_OBJECT PhysicalDeviceObject,
570 IN CONST GUID *InterfaceClassGuid,
571 IN PUNICODE_STRING ReferenceString OPTIONAL,
572 OUT PUNICODE_STRING SymbolicLinkName)
573 {
574 PWCHAR KeyNameString = L"\\Device\\Serenum";
575
576 DPRINT("IoRegisterDeviceInterface called (UNIMPLEMENTED)\n");
577 if (!memcmp(InterfaceClassGuid, (LPGUID)&GUID_SERENUM_BUS_ENUMERATOR, sizeof(GUID)))
578 {
579 RtlInitUnicodeString(SymbolicLinkName, KeyNameString);
580 return STATUS_SUCCESS;
581 }
582
583 return STATUS_INVALID_DEVICE_REQUEST;
584 }
585
586 /*
587 * @unimplemented
588 */
589
590 NTSTATUS STDCALL
591 IoSetDeviceInterfaceState(
592 IN PUNICODE_STRING SymbolicLinkName,
593 IN BOOLEAN Enable)
594 {
595 return STATUS_NOT_IMPLEMENTED;
596 }
597
598 /* EOF */