7d97336cc163f1bb167c9529f729b3dce9e1d5bd
[reactos.git] / reactos / ntoskrnl / io / iomgr / deviface.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/deviface.c
5 * PURPOSE: Device interface functions
6 *
7 * PROGRAMMERS: Filip Navara (xnavara@volny.cz)
8 * Matthew Brace (ismarc@austin.rr.com)
9 * Hervé Poussineau (hpoussin@reactos.org)
10 */
11
12 /* INCLUDES ******************************************************************/
13
14 #include <ntoskrnl.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19 /* FUNCTIONS *****************************************************************/
20
21 static PWCHAR BaseKeyString = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\DeviceClasses\\";
22
23 static
24 NTSTATUS
25 OpenRegistryHandlesFromSymbolicLink(IN PUNICODE_STRING SymbolicLinkName,
26 IN ACCESS_MASK DesiredAccess,
27 IN OPTIONAL PHANDLE GuidKey,
28 IN OPTIONAL PHANDLE DeviceKey,
29 IN OPTIONAL PHANDLE InstanceKey)
30 {
31 OBJECT_ATTRIBUTES ObjectAttributes;
32 WCHAR PathBuffer[MAX_PATH];
33 UNICODE_STRING BaseKeyU;
34 UNICODE_STRING GuidString, SubKeyName, ReferenceString;
35 PWCHAR StartPosition, EndPosition;
36 HANDLE ClassesKey;
37 PHANDLE GuidKeyRealP, DeviceKeyRealP, InstanceKeyRealP;
38 HANDLE GuidKeyReal, DeviceKeyReal, InstanceKeyReal;
39 NTSTATUS Status;
40
41 SubKeyName.Buffer = NULL;
42
43 if (GuidKey != NULL)
44 GuidKeyRealP = GuidKey;
45 else
46 GuidKeyRealP = &GuidKeyReal;
47
48 if (DeviceKey != NULL)
49 DeviceKeyRealP = DeviceKey;
50 else
51 DeviceKeyRealP = &DeviceKeyReal;
52
53 if (InstanceKey != NULL)
54 InstanceKeyRealP = InstanceKey;
55 else
56 InstanceKeyRealP = &InstanceKeyReal;
57
58 *GuidKeyRealP = INVALID_HANDLE_VALUE;
59 *DeviceKeyRealP = INVALID_HANDLE_VALUE;
60 *InstanceKeyRealP = INVALID_HANDLE_VALUE;
61
62 BaseKeyU.Buffer = PathBuffer;
63 BaseKeyU.Length = 0;
64 BaseKeyU.MaximumLength = MAX_PATH * sizeof(WCHAR);
65
66 RtlAppendUnicodeToString(&BaseKeyU, BaseKeyString);
67
68 /* Open the DeviceClasses key */
69 InitializeObjectAttributes(&ObjectAttributes,
70 &BaseKeyU,
71 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
72 NULL,
73 NULL);
74 Status = ZwOpenKey(&ClassesKey,
75 DesiredAccess | KEY_ENUMERATE_SUB_KEYS,
76 &ObjectAttributes);
77 if (!NT_SUCCESS(Status))
78 {
79 DPRINT1("Failed to open %wZ\n", &BaseKeyU);
80 goto cleanup;
81 }
82
83 StartPosition = wcschr(SymbolicLinkName->Buffer, L'{');
84 EndPosition = wcschr(SymbolicLinkName->Buffer, L'}');
85 if (!StartPosition || !EndPosition || StartPosition > EndPosition)
86 {
87 DPRINT1("Bad symbolic link: %wZ\n", SymbolicLinkName);
88 return STATUS_INVALID_PARAMETER_1;
89 }
90 GuidString.Buffer = StartPosition;
91 GuidString.MaximumLength = GuidString.Length = (USHORT)((ULONG_PTR)(EndPosition + 1) - (ULONG_PTR)StartPosition);
92
93 InitializeObjectAttributes(&ObjectAttributes,
94 &GuidString,
95 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
96 ClassesKey,
97 NULL);
98 Status = ZwOpenKey(GuidKeyRealP,
99 DesiredAccess | KEY_ENUMERATE_SUB_KEYS,
100 &ObjectAttributes);
101 ZwClose(ClassesKey);
102 if (!NT_SUCCESS(Status))
103 {
104 DPRINT1("Failed to open %wZ%wZ (%x)\n", &BaseKeyU, &GuidString, Status);
105 goto cleanup;
106 }
107
108 SubKeyName.Buffer = ExAllocatePool(PagedPool, SymbolicLinkName->Length);
109 if (!SubKeyName.Buffer)
110 {
111 Status = STATUS_INSUFFICIENT_RESOURCES;
112 goto cleanup;
113 }
114 SubKeyName.MaximumLength = SymbolicLinkName->Length;
115 SubKeyName.Length = 0;
116
117 RtlAppendUnicodeStringToString(&SubKeyName,
118 SymbolicLinkName);
119
120 SubKeyName.Buffer[0] = L'#';
121 SubKeyName.Buffer[1] = L'#';
122 SubKeyName.Buffer[2] = L'?';
123 SubKeyName.Buffer[3] = L'#';
124
125 ReferenceString.Buffer = wcsrchr(SubKeyName.Buffer, '\\');
126 if (ReferenceString.Buffer != NULL)
127 {
128 ReferenceString.Buffer[0] = L'#';
129
130 SubKeyName.Length = ReferenceString.Buffer - SubKeyName.Buffer;
131 ReferenceString.Length = SymbolicLinkName->Length - SubKeyName.Length;
132 }
133 else
134 {
135 RtlInitUnicodeString(&ReferenceString, L"#");
136 }
137
138 InitializeObjectAttributes(&ObjectAttributes,
139 &SubKeyName,
140 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
141 *GuidKeyRealP,
142 NULL);
143 Status = ZwOpenKey(DeviceKeyRealP,
144 DesiredAccess | KEY_ENUMERATE_SUB_KEYS,
145 &ObjectAttributes);
146 if (!NT_SUCCESS(Status))
147 {
148 DPRINT1("Failed to open %wZ%wZ\\%wZ\n", &BaseKeyU, &GuidString, &SubKeyName);
149 goto cleanup;
150 }
151
152 InitializeObjectAttributes(&ObjectAttributes,
153 &ReferenceString,
154 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
155 *DeviceKeyRealP,
156 NULL);
157 Status = ZwOpenKey(InstanceKeyRealP,
158 DesiredAccess,
159 &ObjectAttributes);
160 if (!NT_SUCCESS(Status))
161 {
162 DPRINT1("Failed to open %wZ%wZ\\%wZ%\\%wZ (%x)\n", &BaseKeyU, &GuidString, &SubKeyName, &ReferenceString, Status);
163 goto cleanup;
164 }
165
166 Status = STATUS_SUCCESS;
167
168 cleanup:
169 if (SubKeyName.Buffer != NULL)
170 ExFreePool(SubKeyName.Buffer);
171
172 if (NT_SUCCESS(Status))
173 {
174 if (!GuidKey)
175 ZwClose(*GuidKeyRealP);
176
177 if (!DeviceKey)
178 ZwClose(*DeviceKeyRealP);
179
180 if (!InstanceKey)
181 ZwClose(*InstanceKeyRealP);
182 }
183 else
184 {
185 if (*GuidKeyRealP != INVALID_HANDLE_VALUE)
186 ZwClose(*GuidKeyRealP);
187
188 if (*DeviceKeyRealP != INVALID_HANDLE_VALUE)
189 ZwClose(*DeviceKeyRealP);
190
191 if (*InstanceKeyRealP != INVALID_HANDLE_VALUE)
192 ZwClose(*InstanceKeyRealP);
193 }
194
195 return Status;
196 }
197 /*++
198 * @name IoOpenDeviceInterfaceRegistryKey
199 * @unimplemented
200 *
201 * Provides a handle to the device's interface instance registry key.
202 * Documented in WDK.
203 *
204 * @param SymbolicLinkName
205 * Pointer to a string which identifies the device interface instance
206 *
207 * @param DesiredAccess
208 * Desired ACCESS_MASK used to access the key (like KEY_READ,
209 * KEY_WRITE, etc)
210 *
211 * @param DeviceInterfaceKey
212 * If a call has been succesfull, a handle to the registry key
213 * will be stored there
214 *
215 * @return Three different NTSTATUS values in case of errors, and STATUS_SUCCESS
216 * otherwise (see WDK for details)
217 *
218 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a system thread
219 *
220 *--*/
221 NTSTATUS
222 NTAPI
223 IoOpenDeviceInterfaceRegistryKey(IN PUNICODE_STRING SymbolicLinkName,
224 IN ACCESS_MASK DesiredAccess,
225 OUT PHANDLE DeviceInterfaceKey)
226 {
227 WCHAR StrBuff[MAX_PATH], PathBuff[MAX_PATH];
228 PWCHAR Guid, RefString;
229 UNICODE_STRING DevParamU = RTL_CONSTANT_STRING(L"\\Device Parameters");
230 UNICODE_STRING PrefixU = RTL_CONSTANT_STRING(L"\\??\\");
231 UNICODE_STRING KeyPath, KeyName;
232 UNICODE_STRING MatchableGuid;
233 UNICODE_STRING GuidString;
234 HANDLE GuidKey, hInterfaceKey;
235 ULONG Index = 0;
236 PKEY_BASIC_INFORMATION KeyInformation;
237 ULONG KeyInformationLength;
238 OBJECT_ATTRIBUTES ObjectAttributes;
239 NTSTATUS Status;
240 ULONG RequiredLength;
241
242 swprintf(StrBuff, L"##?#%s", &SymbolicLinkName->Buffer[PrefixU.Length / sizeof(WCHAR)]);
243
244 RefString = wcsstr(StrBuff, L"\\");
245 if (RefString)
246 {
247 RefString[0] = 0;
248 }
249
250 RtlInitUnicodeString(&MatchableGuid, StrBuff);
251
252 Guid = wcsstr(StrBuff, L"{");
253 if (!Guid)
254 return STATUS_OBJECT_NAME_NOT_FOUND;
255
256 KeyPath.Buffer = PathBuff;
257 KeyPath.Length = 0;
258 KeyPath.MaximumLength = MAX_PATH * sizeof(WCHAR);
259
260 GuidString.Buffer = Guid;
261 GuidString.Length = GuidString.MaximumLength = 38 * sizeof(WCHAR);
262
263 RtlAppendUnicodeToString(&KeyPath, BaseKeyString);
264 RtlAppendUnicodeStringToString(&KeyPath, &GuidString);
265
266 InitializeObjectAttributes(&ObjectAttributes,
267 &KeyPath,
268 OBJ_CASE_INSENSITIVE,
269 0,
270 NULL);
271
272 Status = ZwOpenKey(&GuidKey, KEY_CREATE_SUB_KEY, &ObjectAttributes);
273 if (!NT_SUCCESS(Status))
274 return Status;
275
276 while (TRUE)
277 {
278 Status = ZwEnumerateKey(GuidKey,
279 Index,
280 KeyBasicInformation,
281 NULL,
282 0,
283 &RequiredLength);
284 if (Status == STATUS_NO_MORE_ENTRIES)
285 break;
286 else if (Status == STATUS_BUFFER_TOO_SMALL)
287 {
288 KeyInformationLength = RequiredLength;
289 KeyInformation = ExAllocatePool(PagedPool, KeyInformationLength);
290 if (!KeyInformation)
291 {
292 ZwClose(GuidKey);
293 return STATUS_INSUFFICIENT_RESOURCES;
294 }
295
296 Status = ZwEnumerateKey(GuidKey,
297 Index,
298 KeyBasicInformation,
299 KeyInformation,
300 KeyInformationLength,
301 &RequiredLength);
302 }
303 else
304 {
305 ZwClose(GuidKey);
306 return STATUS_OBJECT_PATH_NOT_FOUND;
307 }
308 Index++;
309
310 if (!NT_SUCCESS(Status))
311 {
312 ZwClose(GuidKey);
313 return Status;
314 }
315
316 KeyName.Length = KeyName.MaximumLength = KeyInformation->NameLength;
317 KeyName.Buffer = KeyInformation->Name;
318
319 if (!RtlEqualUnicodeString(&KeyName, &MatchableGuid, TRUE))
320 {
321 ExFreePool(KeyInformation);
322 continue;
323 }
324
325 KeyPath.Length = 0;
326 RtlAppendUnicodeStringToString(&KeyPath, &KeyName);
327 RtlAppendUnicodeToString(&KeyPath, L"\\");
328
329 /* check for presence of a reference string */
330 if (RefString)
331 {
332 /* append reference string */
333 RefString[0] = L'#';
334 RtlInitUnicodeString(&KeyName, RefString);
335 }
336 else
337 {
338 /* no reference string */
339 RtlInitUnicodeString(&KeyName, L"#");
340 }
341 RtlAppendUnicodeStringToString(&KeyPath, &KeyName);
342
343 /* initialize reference string attributes */
344 InitializeObjectAttributes(&ObjectAttributes,
345 &KeyPath,
346 OBJ_CASE_INSENSITIVE,
347 GuidKey,
348 NULL);
349
350 /* now open device interface key */
351 Status = ZwOpenKey(&hInterfaceKey, KEY_CREATE_SUB_KEY, &ObjectAttributes);
352
353 if (NT_SUCCESS(Status))
354 {
355 /* check if it provides a DeviceParameters key */
356 InitializeObjectAttributes(&ObjectAttributes, &DevParamU, OBJ_CASE_INSENSITIVE, hInterfaceKey, NULL);
357
358 Status = ZwCreateKey(DeviceInterfaceKey, DesiredAccess, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
359
360 if (NT_SUCCESS(Status))
361 {
362 /* DeviceParameters key present */
363 ZwClose(hInterfaceKey);
364 }
365 else
366 {
367 /* fall back to device interface */
368 *DeviceInterfaceKey = hInterfaceKey;
369 Status = STATUS_SUCCESS;
370 }
371 }
372
373 /* close class key */
374 ZwClose(GuidKey);
375 ExFreePool(KeyInformation);
376 return Status;
377 }
378
379 return STATUS_OBJECT_PATH_NOT_FOUND;
380 }
381
382 /*++
383 * @name IoGetDeviceInterfaceAlias
384 * @unimplemented
385 *
386 * Returns the alias device interface of the specified device interface
387 * instance, if the alias exists.
388 * Documented in WDK.
389 *
390 * @param SymbolicLinkName
391 * Pointer to a string which identifies the device interface instance
392 *
393 * @param AliasInterfaceClassGuid
394 * See WDK
395 *
396 * @param AliasSymbolicLinkName
397 * See WDK
398 *
399 * @return Three different NTSTATUS values in case of errors, and STATUS_SUCCESS
400 * otherwise (see WDK for details)
401 *
402 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a system thread
403 *
404 *--*/
405 NTSTATUS
406 NTAPI
407 IoGetDeviceInterfaceAlias(IN PUNICODE_STRING SymbolicLinkName,
408 IN CONST GUID *AliasInterfaceClassGuid,
409 OUT PUNICODE_STRING AliasSymbolicLinkName)
410 {
411 return STATUS_NOT_IMPLEMENTED;
412 }
413
414 /*++
415 * @name IopOpenInterfaceKey
416 *
417 * Returns the alias device interface of the specified device interface
418 *
419 * @param InterfaceClassGuid
420 * FILLME
421 *
422 * @param DesiredAccess
423 * FILLME
424 *
425 * @param pInterfaceKey
426 * FILLME
427 *
428 * @return Usual NTSTATUS
429 *
430 * @remarks None
431 *
432 *--*/
433 static NTSTATUS
434 IopOpenInterfaceKey(IN CONST GUID *InterfaceClassGuid,
435 IN ACCESS_MASK DesiredAccess,
436 OUT HANDLE *pInterfaceKey)
437 {
438 UNICODE_STRING LocalMachine = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\");
439 UNICODE_STRING GuidString;
440 UNICODE_STRING KeyName;
441 OBJECT_ATTRIBUTES ObjectAttributes;
442 HANDLE InterfaceKey = INVALID_HANDLE_VALUE;
443 NTSTATUS Status;
444
445 GuidString.Buffer = KeyName.Buffer = NULL;
446
447 Status = RtlStringFromGUID(InterfaceClassGuid, &GuidString);
448 if (!NT_SUCCESS(Status))
449 {
450 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status);
451 goto cleanup;
452 }
453
454 KeyName.Length = 0;
455 KeyName.MaximumLength = LocalMachine.Length + (wcslen(REGSTR_PATH_DEVICE_CLASSES) + 1) * sizeof(WCHAR) + GuidString.Length;
456 KeyName.Buffer = ExAllocatePool(PagedPool, KeyName.MaximumLength);
457 if (!KeyName.Buffer)
458 {
459 DPRINT("ExAllocatePool() failed\n");
460 Status = STATUS_INSUFFICIENT_RESOURCES;
461 goto cleanup;
462 }
463
464 Status = RtlAppendUnicodeStringToString(&KeyName, &LocalMachine);
465 if (!NT_SUCCESS(Status))
466 {
467 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status);
468 goto cleanup;
469 }
470 Status = RtlAppendUnicodeToString(&KeyName, REGSTR_PATH_DEVICE_CLASSES);
471 if (!NT_SUCCESS(Status))
472 {
473 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status);
474 goto cleanup;
475 }
476 Status = RtlAppendUnicodeToString(&KeyName, L"\\");
477 if (!NT_SUCCESS(Status))
478 {
479 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status);
480 goto cleanup;
481 }
482 Status = RtlAppendUnicodeStringToString(&KeyName, &GuidString);
483 if (!NT_SUCCESS(Status))
484 {
485 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status);
486 goto cleanup;
487 }
488
489 InitializeObjectAttributes(
490 &ObjectAttributes,
491 &KeyName,
492 OBJ_CASE_INSENSITIVE,
493 NULL,
494 NULL);
495 Status = ZwOpenKey(
496 &InterfaceKey,
497 DesiredAccess,
498 &ObjectAttributes);
499 if (!NT_SUCCESS(Status))
500 {
501 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
502 goto cleanup;
503 }
504
505 *pInterfaceKey = InterfaceKey;
506 Status = STATUS_SUCCESS;
507
508 cleanup:
509 if (!NT_SUCCESS(Status))
510 {
511 if (InterfaceKey != INVALID_HANDLE_VALUE)
512 ZwClose(InterfaceKey);
513 }
514 RtlFreeUnicodeString(&GuidString);
515 RtlFreeUnicodeString(&KeyName);
516 return Status;
517 }
518
519 /*++
520 * @name IoGetDeviceInterfaces
521 * @implemented
522 *
523 * Returns a list of device interfaces of a particular device interface class.
524 * Documented in WDK
525 *
526 * @param InterfaceClassGuid
527 * Points to a class GUID specifying the device interface class
528 *
529 * @param PhysicalDeviceObject
530 * Points to an optional PDO that narrows the search to only the
531 * device interfaces of the device represented by the PDO
532 *
533 * @param Flags
534 * Specifies flags that modify the search for device interfaces. The
535 * DEVICE_INTERFACE_INCLUDE_NONACTIVE flag specifies that the list of
536 * returned symbolic links should contain also disabled device
537 * interfaces in addition to the enabled ones.
538 *
539 * @param SymbolicLinkList
540 * Points to a character pointer that is filled in on successful return
541 * with a list of unicode strings identifying the device interfaces
542 * that match the search criteria. The newly allocated buffer contains
543 * a list of symbolic link names. Each unicode string in the list is
544 * null-terminated; the end of the whole list is marked by an additional
545 * NULL. The caller is responsible for freeing the buffer (ExFreePool)
546 * when it is no longer needed.
547 * If no device interfaces match the search criteria, this routine
548 * returns STATUS_SUCCESS and the string contains a single NULL
549 * character.
550 *
551 * @return Usual NTSTATUS
552 *
553 * @remarks None
554 *
555 *--*/
556 NTSTATUS
557 NTAPI
558 IoGetDeviceInterfaces(IN CONST GUID *InterfaceClassGuid,
559 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
560 IN ULONG Flags,
561 OUT PWSTR *SymbolicLinkList)
562 {
563 UNICODE_STRING Control = RTL_CONSTANT_STRING(L"Control");
564 UNICODE_STRING SymbolicLink = RTL_CONSTANT_STRING(L"SymbolicLink");
565 HANDLE InterfaceKey = INVALID_HANDLE_VALUE;
566 HANDLE DeviceKey = INVALID_HANDLE_VALUE;
567 HANDLE ReferenceKey = INVALID_HANDLE_VALUE;
568 HANDLE ControlKey = INVALID_HANDLE_VALUE;
569 PKEY_BASIC_INFORMATION DeviceBi = NULL;
570 PKEY_BASIC_INFORMATION ReferenceBi = NULL;
571 PKEY_VALUE_PARTIAL_INFORMATION bip = NULL;
572 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
573 UNICODE_STRING KeyName;
574 OBJECT_ATTRIBUTES ObjectAttributes;
575 BOOLEAN FoundRightPDO = FALSE;
576 ULONG i = 0, j, Size, NeededLength, ActualLength, LinkedValue;
577 UNICODE_STRING ReturnBuffer = { 0, 0, NULL };
578 NTSTATUS Status;
579
580 PAGED_CODE();
581
582 Status = IopOpenInterfaceKey(InterfaceClassGuid, KEY_ENUMERATE_SUB_KEYS, &InterfaceKey);
583 if (!NT_SUCCESS(Status))
584 {
585 DPRINT("IopOpenInterfaceKey() failed with status 0x%08lx\n", Status);
586 goto cleanup;
587 }
588
589 /* Enumerate subkeys (ie the different device objets) */
590 while (TRUE)
591 {
592 Status = ZwEnumerateKey(
593 InterfaceKey,
594 i,
595 KeyBasicInformation,
596 NULL,
597 0,
598 &Size);
599 if (Status == STATUS_NO_MORE_ENTRIES)
600 {
601 break;
602 }
603 else if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL)
604 {
605 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
606 goto cleanup;
607 }
608
609 DeviceBi = ExAllocatePool(PagedPool, Size);
610 if (!DeviceBi)
611 {
612 DPRINT("ExAllocatePool() failed\n");
613 Status = STATUS_INSUFFICIENT_RESOURCES;
614 goto cleanup;
615 }
616 Status = ZwEnumerateKey(
617 InterfaceKey,
618 i++,
619 KeyBasicInformation,
620 DeviceBi,
621 Size,
622 &Size);
623 if (!NT_SUCCESS(Status))
624 {
625 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
626 goto cleanup;
627 }
628
629 /* Open device key */
630 KeyName.Length = KeyName.MaximumLength = (USHORT)DeviceBi->NameLength;
631 KeyName.Buffer = DeviceBi->Name;
632 InitializeObjectAttributes(
633 &ObjectAttributes,
634 &KeyName,
635 OBJ_CASE_INSENSITIVE,
636 InterfaceKey,
637 NULL);
638 Status = ZwOpenKey(
639 &DeviceKey,
640 KEY_ENUMERATE_SUB_KEYS,
641 &ObjectAttributes);
642 if (!NT_SUCCESS(Status))
643 {
644 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
645 goto cleanup;
646 }
647
648 if (PhysicalDeviceObject)
649 {
650 /* Check if we are on the right physical device object,
651 * by reading the DeviceInstance string
652 */
653 DPRINT1("PhysicalDeviceObject != NULL. Case not implemented.\n");
654 //FoundRightPDO = TRUE;
655 Status = STATUS_NOT_IMPLEMENTED;
656 goto cleanup;
657 }
658
659 /* Enumerate subkeys (ie the different reference strings) */
660 j = 0;
661 while (TRUE)
662 {
663 Status = ZwEnumerateKey(
664 DeviceKey,
665 j,
666 KeyBasicInformation,
667 NULL,
668 0,
669 &Size);
670 if (Status == STATUS_NO_MORE_ENTRIES)
671 {
672 break;
673 }
674 else if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL)
675 {
676 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
677 goto cleanup;
678 }
679
680 ReferenceBi = ExAllocatePool(PagedPool, Size);
681 if (!ReferenceBi)
682 {
683 DPRINT("ExAllocatePool() failed\n");
684 Status = STATUS_INSUFFICIENT_RESOURCES;
685 goto cleanup;
686 }
687 Status = ZwEnumerateKey(
688 DeviceKey,
689 j++,
690 KeyBasicInformation,
691 ReferenceBi,
692 Size,
693 &Size);
694 if (!NT_SUCCESS(Status))
695 {
696 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
697 goto cleanup;
698 }
699
700 KeyName.Length = KeyName.MaximumLength = (USHORT)ReferenceBi->NameLength;
701 KeyName.Buffer = ReferenceBi->Name;
702 if (RtlEqualUnicodeString(&KeyName, &Control, TRUE))
703 {
704 /* Skip Control subkey */
705 goto NextReferenceString;
706 }
707
708 /* Open reference key */
709 InitializeObjectAttributes(
710 &ObjectAttributes,
711 &KeyName,
712 OBJ_CASE_INSENSITIVE,
713 DeviceKey,
714 NULL);
715 Status = ZwOpenKey(
716 &ReferenceKey,
717 KEY_QUERY_VALUE,
718 &ObjectAttributes);
719 if (!NT_SUCCESS(Status))
720 {
721 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
722 goto cleanup;
723 }
724
725 if (!(Flags & DEVICE_INTERFACE_INCLUDE_NONACTIVE))
726 {
727 /* We have to check if the interface is enabled, by
728 * reading the Linked value in the Control subkey
729 */
730 InitializeObjectAttributes(
731 &ObjectAttributes,
732 &Control,
733 OBJ_CASE_INSENSITIVE,
734 ReferenceKey,
735 NULL);
736 Status = ZwOpenKey(
737 &ControlKey,
738 KEY_QUERY_VALUE,
739 &ObjectAttributes);
740 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
741 {
742 /* That's OK. The key doesn't exist (yet) because
743 * the interface is not activated.
744 */
745 goto NextReferenceString;
746 }
747 else if (!NT_SUCCESS(Status))
748 {
749 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
750 goto cleanup;
751 }
752
753 RtlInitUnicodeString(&KeyName, L"Linked");
754 Status = ZwQueryValueKey(ControlKey,
755 &KeyName,
756 KeyValuePartialInformation,
757 NULL,
758 0,
759 &NeededLength);
760 if (Status == STATUS_BUFFER_TOO_SMALL)
761 {
762 ActualLength = NeededLength;
763 PartialInfo = ExAllocatePool(NonPagedPool, ActualLength);
764 if (!PartialInfo)
765 {
766 Status = STATUS_INSUFFICIENT_RESOURCES;
767 goto cleanup;
768 }
769
770 Status = ZwQueryValueKey(ControlKey,
771 &KeyName,
772 KeyValuePartialInformation,
773 PartialInfo,
774 ActualLength,
775 &NeededLength);
776 if (!NT_SUCCESS(Status))
777 {
778 DPRINT1("ZwQueryValueKey #2 failed (%x)\n", Status);
779 ExFreePool(PartialInfo);
780 goto cleanup;
781 }
782
783 if (PartialInfo->Type != REG_DWORD || PartialInfo->DataLength != sizeof(ULONG))
784 {
785 DPRINT1("Bad registry read\n");
786 ExFreePool(PartialInfo);
787 goto cleanup;
788 }
789
790 RtlCopyMemory(&LinkedValue,
791 PartialInfo->Data,
792 PartialInfo->DataLength);
793
794 ExFreePool(PartialInfo);
795 if (LinkedValue == 0)
796 {
797 /* This interface isn't active */
798 goto NextReferenceString;
799 }
800 }
801 else
802 {
803 DPRINT1("ZwQueryValueKey #1 failed (%x)\n", Status);
804 goto cleanup;
805 }
806 }
807
808 /* Read the SymbolicLink string and add it into SymbolicLinkList */
809 Status = ZwQueryValueKey(
810 ReferenceKey,
811 &SymbolicLink,
812 KeyValuePartialInformation,
813 NULL,
814 0,
815 &Size);
816 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL)
817 {
818 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
819 goto cleanup;
820 }
821 bip = ExAllocatePool(PagedPool, Size);
822 if (!bip)
823 {
824 DPRINT("ExAllocatePool() failed\n");
825 Status = STATUS_INSUFFICIENT_RESOURCES;
826 goto cleanup;
827 }
828 Status = ZwQueryValueKey(
829 ReferenceKey,
830 &SymbolicLink,
831 KeyValuePartialInformation,
832 bip,
833 Size,
834 &Size);
835 if (!NT_SUCCESS(Status))
836 {
837 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
838 goto cleanup;
839 }
840 else if (bip->Type != REG_SZ)
841 {
842 DPRINT("Unexpected registry type 0x%lx (expected 0x%lx)\n", bip->Type, REG_SZ);
843 Status = STATUS_UNSUCCESSFUL;
844 goto cleanup;
845 }
846 else if (bip->DataLength < 5 * sizeof(WCHAR))
847 {
848 DPRINT("Registry string too short (length %lu, expected %lu at least)\n", bip->DataLength < 5 * sizeof(WCHAR));
849 Status = STATUS_UNSUCCESSFUL;
850 goto cleanup;
851 }
852 KeyName.Length = KeyName.MaximumLength = (USHORT)bip->DataLength - 4 * sizeof(WCHAR);
853 KeyName.Buffer = &((PWSTR)bip->Data)[4];
854 if (KeyName.Length && KeyName.Buffer[KeyName.Length / sizeof(WCHAR)] == UNICODE_NULL)
855 {
856 /* Remove trailing NULL */
857 KeyName.Length -= sizeof(WCHAR);
858 }
859
860 /* Add new symbolic link to symbolic link list */
861 if (ReturnBuffer.Length + KeyName.Length + sizeof(WCHAR) > ReturnBuffer.MaximumLength)
862 {
863 PWSTR NewBuffer;
864 ReturnBuffer.MaximumLength = max(ReturnBuffer.MaximumLength * 2, ReturnBuffer.Length + KeyName.Length + 2 * sizeof(WCHAR));
865 NewBuffer = ExAllocatePool(PagedPool, ReturnBuffer.MaximumLength);
866 if (!NewBuffer)
867 {
868 DPRINT("ExAllocatePool() failed\n");
869 Status = STATUS_INSUFFICIENT_RESOURCES;
870 goto cleanup;
871 }
872 RtlCopyMemory(NewBuffer, ReturnBuffer.Buffer, ReturnBuffer.Length);
873 if (ReturnBuffer.Buffer)
874 ExFreePool(ReturnBuffer.Buffer);
875 ReturnBuffer.Buffer = NewBuffer;
876 }
877 DPRINT("Adding symbolic link %wZ\n", &KeyName);
878 Status = RtlAppendUnicodeStringToString(&ReturnBuffer, &KeyName);
879 if (!NT_SUCCESS(Status))
880 {
881 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status);
882 goto cleanup;
883 }
884 NextReferenceString:
885 ExFreePool(ReferenceBi);
886 ReferenceBi = NULL;
887 if (bip)
888 ExFreePool(bip);
889 bip = NULL;
890 if (ReferenceKey != INVALID_HANDLE_VALUE)
891 {
892 ZwClose(ReferenceKey);
893 ReferenceKey = INVALID_HANDLE_VALUE;
894 }
895 if (ControlKey != INVALID_HANDLE_VALUE)
896 {
897 ZwClose(ControlKey);
898 ControlKey = INVALID_HANDLE_VALUE;
899 }
900 }
901 if (FoundRightPDO)
902 {
903 /* No need to go further, as we already have found what we searched */
904 break;
905 }
906
907 ExFreePool(DeviceBi);
908 DeviceBi = NULL;
909 ZwClose(DeviceKey);
910 DeviceKey = INVALID_HANDLE_VALUE;
911 }
912
913 /* Add final NULL to ReturnBuffer */
914 if (ReturnBuffer.Length >= ReturnBuffer.MaximumLength)
915 {
916 PWSTR NewBuffer;
917 ReturnBuffer.MaximumLength += sizeof(WCHAR);
918 NewBuffer = ExAllocatePool(PagedPool, ReturnBuffer.MaximumLength);
919 if (!NewBuffer)
920 {
921 DPRINT("ExAllocatePool() failed\n");
922 Status = STATUS_INSUFFICIENT_RESOURCES;
923 goto cleanup;
924 }
925 if (ReturnBuffer.Buffer)
926 {
927 RtlCopyMemory(NewBuffer, ReturnBuffer.Buffer, ReturnBuffer.Length);
928 ExFreePool(ReturnBuffer.Buffer);
929 }
930 ReturnBuffer.Buffer = NewBuffer;
931 }
932 ReturnBuffer.Buffer[ReturnBuffer.Length / sizeof(WCHAR)] = UNICODE_NULL;
933 *SymbolicLinkList = ReturnBuffer.Buffer;
934 Status = STATUS_SUCCESS;
935
936 cleanup:
937 if (!NT_SUCCESS(Status) && ReturnBuffer.Buffer)
938 ExFreePool(ReturnBuffer.Buffer);
939 if (InterfaceKey != INVALID_HANDLE_VALUE)
940 ZwClose(InterfaceKey);
941 if (DeviceKey != INVALID_HANDLE_VALUE)
942 ZwClose(DeviceKey);
943 if (ReferenceKey != INVALID_HANDLE_VALUE)
944 ZwClose(ReferenceKey);
945 if (ControlKey != INVALID_HANDLE_VALUE)
946 ZwClose(ControlKey);
947 if (DeviceBi)
948 ExFreePool(DeviceBi);
949 if (ReferenceBi)
950 ExFreePool(ReferenceBi);
951 if (bip)
952 ExFreePool(bip);
953 return Status;
954 }
955
956 /*++
957 * @name IoRegisterDeviceInterface
958 * @implemented
959 *
960 * Registers a device interface class, if it has not been previously registered,
961 * and creates a new instance of the interface class, which a driver can
962 * subsequently enable for use by applications or other system components.
963 * Documented in WDK.
964 *
965 * @param PhysicalDeviceObject
966 * Points to an optional PDO that narrows the search to only the
967 * device interfaces of the device represented by the PDO
968 *
969 * @param InterfaceClassGuid
970 * Points to a class GUID specifying the device interface class
971 *
972 * @param ReferenceString
973 * Optional parameter, pointing to a unicode string. For a full
974 * description of this rather rarely used param (usually drivers
975 * pass NULL here) see WDK
976 *
977 * @param SymbolicLinkName
978 * Pointer to the resulting unicode string
979 *
980 * @return Usual NTSTATUS
981 *
982 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a
983 * system thread
984 *
985 *--*/
986 NTSTATUS
987 NTAPI
988 IoRegisterDeviceInterface(IN PDEVICE_OBJECT PhysicalDeviceObject,
989 IN CONST GUID *InterfaceClassGuid,
990 IN PUNICODE_STRING ReferenceString OPTIONAL,
991 OUT PUNICODE_STRING SymbolicLinkName)
992 {
993 PUNICODE_STRING InstancePath;
994 UNICODE_STRING GuidString;
995 UNICODE_STRING SubKeyName;
996 UNICODE_STRING InterfaceKeyName;
997 UNICODE_STRING BaseKeyName;
998 UCHAR PdoNameInfoBuffer[sizeof(OBJECT_NAME_INFORMATION) + (256 * sizeof(WCHAR))];
999 POBJECT_NAME_INFORMATION PdoNameInfo = (POBJECT_NAME_INFORMATION)PdoNameInfoBuffer;
1000 UNICODE_STRING DeviceInstance = RTL_CONSTANT_STRING(L"DeviceInstance");
1001 UNICODE_STRING SymbolicLink = RTL_CONSTANT_STRING(L"SymbolicLink");
1002 HANDLE ClassKey;
1003 HANDLE InterfaceKey;
1004 HANDLE SubKey;
1005 ULONG StartIndex;
1006 OBJECT_ATTRIBUTES ObjectAttributes;
1007 ULONG i;
1008 NTSTATUS Status;
1009 PEXTENDED_DEVOBJ_EXTENSION DeviceObjectExtension;
1010
1011 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
1012
1013 DPRINT("IoRegisterDeviceInterface(): PDO %p, RefString: %wZ\n",
1014 PhysicalDeviceObject, ReferenceString);
1015
1016 /* Parameters must pass three border of checks */
1017 DeviceObjectExtension = (PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension;
1018
1019 /* 1st level: Presence of a Device Node */
1020 if (DeviceObjectExtension->DeviceNode == NULL)
1021 {
1022 DPRINT("PhysicalDeviceObject 0x%p doesn't have a DeviceNode\n", PhysicalDeviceObject);
1023 return STATUS_INVALID_DEVICE_REQUEST;
1024 }
1025
1026 /* 2nd level: Presence of an non-zero length InstancePath */
1027 if (DeviceObjectExtension->DeviceNode->InstancePath.Length == 0)
1028 {
1029 DPRINT("PhysicalDeviceObject 0x%p's DOE has zero-length InstancePath\n", PhysicalDeviceObject);
1030 return STATUS_INVALID_DEVICE_REQUEST;
1031 }
1032
1033 /* 3rd level: Optional, based on WDK documentation */
1034 if (ReferenceString != NULL)
1035 {
1036 /* Reference string must not contain path-separator symbols */
1037 for (i = 0; i < ReferenceString->Length / sizeof(WCHAR); i++)
1038 {
1039 if ((ReferenceString->Buffer[i] == '\\') ||
1040 (ReferenceString->Buffer[i] == '/'))
1041 return STATUS_INVALID_DEVICE_REQUEST;
1042 }
1043 }
1044
1045 Status = RtlStringFromGUID(InterfaceClassGuid, &GuidString);
1046 if (!NT_SUCCESS(Status))
1047 {
1048 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status);
1049 return Status;
1050 }
1051
1052 /* Create Pdo name: \Device\xxxxxxxx (unnamed device) */
1053 Status = ObQueryNameString(
1054 PhysicalDeviceObject,
1055 PdoNameInfo,
1056 sizeof(PdoNameInfoBuffer),
1057 &i);
1058 if (!NT_SUCCESS(Status))
1059 {
1060 DPRINT("ObQueryNameString() failed with status 0x%08lx\n", Status);
1061 return Status;
1062 }
1063 ASSERT(PdoNameInfo->Name.Length);
1064
1065 /* Create base key name for this interface: HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
1066 ASSERT(((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode);
1067 InstancePath = &((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode->InstancePath;
1068 BaseKeyName.Length = wcslen(BaseKeyString) * sizeof(WCHAR);
1069 BaseKeyName.MaximumLength = BaseKeyName.Length
1070 + GuidString.Length;
1071 BaseKeyName.Buffer = ExAllocatePool(
1072 PagedPool,
1073 BaseKeyName.MaximumLength);
1074 if (!BaseKeyName.Buffer)
1075 {
1076 DPRINT("ExAllocatePool() failed\n");
1077 return STATUS_INSUFFICIENT_RESOURCES;
1078 }
1079 wcscpy(BaseKeyName.Buffer, BaseKeyString);
1080 RtlAppendUnicodeStringToString(&BaseKeyName, &GuidString);
1081
1082 /* Create BaseKeyName key in registry */
1083 InitializeObjectAttributes(
1084 &ObjectAttributes,
1085 &BaseKeyName,
1086 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE | OBJ_OPENIF,
1087 NULL, /* RootDirectory */
1088 NULL); /* SecurityDescriptor */
1089
1090 Status = ZwCreateKey(
1091 &ClassKey,
1092 KEY_WRITE,
1093 &ObjectAttributes,
1094 0, /* TileIndex */
1095 NULL, /* Class */
1096 REG_OPTION_VOLATILE,
1097 NULL); /* Disposition */
1098
1099 if (!NT_SUCCESS(Status))
1100 {
1101 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
1102 ExFreePool(BaseKeyName.Buffer);
1103 return Status;
1104 }
1105
1106 /* Create key name for this interface: ##?#ACPI#PNP0501#1#{GUID} */
1107 InterfaceKeyName.Length = 0;
1108 InterfaceKeyName.MaximumLength =
1109 4 * sizeof(WCHAR) + /* 4 = size of ##?# */
1110 InstancePath->Length +
1111 sizeof(WCHAR) + /* 1 = size of # */
1112 GuidString.Length;
1113 InterfaceKeyName.Buffer = ExAllocatePool(
1114 PagedPool,
1115 InterfaceKeyName.MaximumLength);
1116 if (!InterfaceKeyName.Buffer)
1117 {
1118 DPRINT("ExAllocatePool() failed\n");
1119 return STATUS_INSUFFICIENT_RESOURCES;
1120 }
1121
1122 RtlAppendUnicodeToString(&InterfaceKeyName, L"##?#");
1123 StartIndex = InterfaceKeyName.Length / sizeof(WCHAR);
1124 RtlAppendUnicodeStringToString(&InterfaceKeyName, InstancePath);
1125 for (i = 0; i < InstancePath->Length / sizeof(WCHAR); i++)
1126 {
1127 if (InterfaceKeyName.Buffer[StartIndex + i] == '\\')
1128 InterfaceKeyName.Buffer[StartIndex + i] = '#';
1129 }
1130 RtlAppendUnicodeToString(&InterfaceKeyName, L"#");
1131 RtlAppendUnicodeStringToString(&InterfaceKeyName, &GuidString);
1132
1133 /* Create the interface key in registry */
1134 InitializeObjectAttributes(
1135 &ObjectAttributes,
1136 &InterfaceKeyName,
1137 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE | OBJ_OPENIF,
1138 ClassKey,
1139 NULL); /* SecurityDescriptor */
1140
1141 Status = ZwCreateKey(
1142 &InterfaceKey,
1143 KEY_WRITE,
1144 &ObjectAttributes,
1145 0, /* TileIndex */
1146 NULL, /* Class */
1147 REG_OPTION_VOLATILE,
1148 NULL); /* Disposition */
1149
1150 if (!NT_SUCCESS(Status))
1151 {
1152 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
1153 ZwClose(ClassKey);
1154 ExFreePool(BaseKeyName.Buffer);
1155 return Status;
1156 }
1157
1158 /* Write DeviceInstance entry. Value is InstancePath */
1159 Status = ZwSetValueKey(
1160 InterfaceKey,
1161 &DeviceInstance,
1162 0, /* TileIndex */
1163 REG_SZ,
1164 InstancePath->Buffer,
1165 InstancePath->Length);
1166 if (!NT_SUCCESS(Status))
1167 {
1168 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
1169 ZwClose(InterfaceKey);
1170 ZwClose(ClassKey);
1171 ExFreePool(InterfaceKeyName.Buffer);
1172 ExFreePool(BaseKeyName.Buffer);
1173 return Status;
1174 }
1175
1176 /* Create subkey. Name is #ReferenceString */
1177 SubKeyName.Length = 0;
1178 SubKeyName.MaximumLength = sizeof(WCHAR);
1179 if (ReferenceString && ReferenceString->Length)
1180 SubKeyName.MaximumLength += ReferenceString->Length;
1181 SubKeyName.Buffer = ExAllocatePool(
1182 PagedPool,
1183 SubKeyName.MaximumLength);
1184 if (!SubKeyName.Buffer)
1185 {
1186 DPRINT("ExAllocatePool() failed\n");
1187 ZwClose(InterfaceKey);
1188 ZwClose(ClassKey);
1189 ExFreePool(InterfaceKeyName.Buffer);
1190 ExFreePool(BaseKeyName.Buffer);
1191 return STATUS_INSUFFICIENT_RESOURCES;
1192 }
1193 RtlAppendUnicodeToString(&SubKeyName, L"#");
1194 if (ReferenceString && ReferenceString->Length)
1195 RtlAppendUnicodeStringToString(&SubKeyName, ReferenceString);
1196
1197 /* Create SubKeyName key in registry */
1198 InitializeObjectAttributes(
1199 &ObjectAttributes,
1200 &SubKeyName,
1201 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1202 InterfaceKey, /* RootDirectory */
1203 NULL); /* SecurityDescriptor */
1204
1205 Status = ZwCreateKey(
1206 &SubKey,
1207 KEY_WRITE,
1208 &ObjectAttributes,
1209 0, /* TileIndex */
1210 NULL, /* Class */
1211 REG_OPTION_VOLATILE,
1212 NULL); /* Disposition */
1213
1214 if (!NT_SUCCESS(Status))
1215 {
1216 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
1217 ZwClose(InterfaceKey);
1218 ZwClose(ClassKey);
1219 ExFreePool(InterfaceKeyName.Buffer);
1220 ExFreePool(BaseKeyName.Buffer);
1221 return Status;
1222 }
1223
1224 /* Create symbolic link name: \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
1225 SymbolicLinkName->Length = 0;
1226 SymbolicLinkName->MaximumLength = SymbolicLinkName->Length
1227 + 4 * sizeof(WCHAR) /* 4 = size of \??\ */
1228 + InstancePath->Length
1229 + sizeof(WCHAR) /* 1 = size of # */
1230 + GuidString.Length
1231 + sizeof(WCHAR); /* final NULL */
1232 if (ReferenceString && ReferenceString->Length)
1233 SymbolicLinkName->MaximumLength += sizeof(WCHAR) + ReferenceString->Length;
1234 SymbolicLinkName->Buffer = ExAllocatePool(
1235 PagedPool,
1236 SymbolicLinkName->MaximumLength);
1237 if (!SymbolicLinkName->Buffer)
1238 {
1239 DPRINT("ExAllocatePool() failed\n");
1240 ZwClose(SubKey);
1241 ZwClose(InterfaceKey);
1242 ZwClose(ClassKey);
1243 ExFreePool(InterfaceKeyName.Buffer);
1244 ExFreePool(SubKeyName.Buffer);
1245 ExFreePool(BaseKeyName.Buffer);
1246 return STATUS_INSUFFICIENT_RESOURCES;
1247 }
1248 RtlAppendUnicodeToString(SymbolicLinkName, L"\\??\\");
1249 StartIndex = SymbolicLinkName->Length / sizeof(WCHAR);
1250 RtlAppendUnicodeStringToString(SymbolicLinkName, InstancePath);
1251 for (i = 0; i < InstancePath->Length / sizeof(WCHAR); i++)
1252 {
1253 if (SymbolicLinkName->Buffer[StartIndex + i] == '\\')
1254 SymbolicLinkName->Buffer[StartIndex + i] = '#';
1255 }
1256 RtlAppendUnicodeToString(SymbolicLinkName, L"#");
1257 RtlAppendUnicodeStringToString(SymbolicLinkName, &GuidString);
1258 SymbolicLinkName->Buffer[SymbolicLinkName->Length/sizeof(WCHAR)] = L'\0';
1259
1260 /* Create symbolic link */
1261 DPRINT("IoRegisterDeviceInterface(): creating symbolic link %wZ -> %wZ\n", SymbolicLinkName, &PdoNameInfo->Name);
1262 Status = IoCreateSymbolicLink(SymbolicLinkName, &PdoNameInfo->Name);
1263 if (!NT_SUCCESS(Status) && ReferenceString == NULL)
1264 {
1265 DPRINT1("IoCreateSymbolicLink() failed with status 0x%08lx\n", Status);
1266 ZwClose(SubKey);
1267 ZwClose(InterfaceKey);
1268 ZwClose(ClassKey);
1269 ExFreePool(SubKeyName.Buffer);
1270 ExFreePool(InterfaceKeyName.Buffer);
1271 ExFreePool(BaseKeyName.Buffer);
1272 ExFreePool(SymbolicLinkName->Buffer);
1273 return Status;
1274 }
1275
1276 if (ReferenceString && ReferenceString->Length)
1277 {
1278 RtlAppendUnicodeToString(SymbolicLinkName, L"\\");
1279 RtlAppendUnicodeStringToString(SymbolicLinkName, ReferenceString);
1280 }
1281 SymbolicLinkName->Buffer[SymbolicLinkName->Length/sizeof(WCHAR)] = L'\0';
1282
1283 /* Write symbolic link name in registry */
1284 SymbolicLinkName->Buffer[1] = '\\';
1285 Status = ZwSetValueKey(
1286 SubKey,
1287 &SymbolicLink,
1288 0, /* TileIndex */
1289 REG_SZ,
1290 SymbolicLinkName->Buffer,
1291 SymbolicLinkName->Length);
1292 if (!NT_SUCCESS(Status))
1293 {
1294 DPRINT1("ZwSetValueKey() failed with status 0x%08lx\n", Status);
1295 ExFreePool(SymbolicLinkName->Buffer);
1296 }
1297 else
1298 {
1299 SymbolicLinkName->Buffer[1] = '?';
1300 }
1301
1302 ZwClose(SubKey);
1303 ZwClose(InterfaceKey);
1304 ZwClose(ClassKey);
1305 ExFreePool(SubKeyName.Buffer);
1306 ExFreePool(InterfaceKeyName.Buffer);
1307 ExFreePool(BaseKeyName.Buffer);
1308
1309 return Status;
1310 }
1311
1312 /*++
1313 * @name IoSetDeviceInterfaceState
1314 * @implemented
1315 *
1316 * Enables or disables an instance of a previously registered device
1317 * interface class.
1318 * Documented in WDK.
1319 *
1320 * @param SymbolicLinkName
1321 * Pointer to the string identifying instance to enable or disable
1322 *
1323 * @param Enable
1324 * TRUE = enable, FALSE = disable
1325 *
1326 * @return Usual NTSTATUS
1327 *
1328 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a
1329 * system thread
1330 *
1331 *--*/
1332 NTSTATUS
1333 NTAPI
1334 IoSetDeviceInterfaceState(IN PUNICODE_STRING SymbolicLinkName,
1335 IN BOOLEAN Enable)
1336 {
1337 PDEVICE_OBJECT PhysicalDeviceObject;
1338 PFILE_OBJECT FileObject;
1339 UNICODE_STRING GuidString;
1340 UNICODE_STRING SymLink;
1341 PWCHAR StartPosition;
1342 PWCHAR EndPosition;
1343 NTSTATUS Status;
1344 LPCGUID EventGuid;
1345 HANDLE InstanceHandle, ControlHandle;
1346 UNICODE_STRING KeyName;
1347 OBJECT_ATTRIBUTES ObjectAttributes;
1348 ULONG LinkedValue;
1349
1350 if (SymbolicLinkName == NULL)
1351 return STATUS_INVALID_PARAMETER_1;
1352
1353 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName, Enable);
1354
1355 /* Symbolic link name is \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
1356 /* Get GUID from SymbolicLinkName */
1357 StartPosition = wcschr(SymbolicLinkName->Buffer, L'{');
1358 EndPosition = wcschr(SymbolicLinkName->Buffer, L'}');
1359 if (!StartPosition ||!EndPosition || StartPosition > EndPosition)
1360 {
1361 DPRINT1("IoSetDeviceInterfaceState() returning STATUS_INVALID_PARAMETER_1\n");
1362 return STATUS_INVALID_PARAMETER_1;
1363 }
1364 GuidString.Buffer = StartPosition;
1365 GuidString.MaximumLength = GuidString.Length = (USHORT)((ULONG_PTR)(EndPosition + 1) - (ULONG_PTR)StartPosition);
1366
1367 SymLink.Buffer = SymbolicLinkName->Buffer;
1368 SymLink.MaximumLength = SymLink.Length = (USHORT)((ULONG_PTR)(EndPosition + 1) - (ULONG_PTR)SymLink.Buffer);
1369 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName, Enable);
1370
1371 Status = OpenRegistryHandlesFromSymbolicLink(SymbolicLinkName,
1372 KEY_CREATE_SUB_KEY,
1373 NULL,
1374 NULL,
1375 &InstanceHandle);
1376 if (!NT_SUCCESS(Status))
1377 return Status;
1378
1379 RtlInitUnicodeString(&KeyName, L"Control");
1380 InitializeObjectAttributes(&ObjectAttributes,
1381 &KeyName,
1382 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1383 InstanceHandle,
1384 NULL);
1385 Status = ZwCreateKey(&ControlHandle,
1386 KEY_SET_VALUE,
1387 &ObjectAttributes,
1388 0,
1389 NULL,
1390 REG_OPTION_VOLATILE,
1391 NULL);
1392 ZwClose(InstanceHandle);
1393 if (!NT_SUCCESS(Status))
1394 {
1395 DPRINT1("Failed to create the Control subkey\n");
1396 return Status;
1397 }
1398
1399 LinkedValue = (Enable ? 1 : 0);
1400
1401 RtlInitUnicodeString(&KeyName, L"Linked");
1402 Status = ZwSetValueKey(ControlHandle,
1403 &KeyName,
1404 0,
1405 REG_DWORD,
1406 &LinkedValue,
1407 sizeof(ULONG));
1408 ZwClose(ControlHandle);
1409 if (!NT_SUCCESS(Status))
1410 {
1411 DPRINT1("Failed to write the Linked value\n");
1412 return Status;
1413 }
1414
1415 /* Get pointer to the PDO */
1416 Status = IoGetDeviceObjectPointer(
1417 &SymLink,
1418 0, /* DesiredAccess */
1419 &FileObject,
1420 &PhysicalDeviceObject);
1421 if (!NT_SUCCESS(Status))
1422 {
1423 DPRINT1("IoGetDeviceObjectPointer() failed with status 0x%08lx\n", Status);
1424 return Status;
1425 }
1426
1427 EventGuid = Enable ? &GUID_DEVICE_INTERFACE_ARRIVAL : &GUID_DEVICE_INTERFACE_REMOVAL;
1428 IopNotifyPlugPlayNotification(
1429 PhysicalDeviceObject,
1430 EventCategoryDeviceInterfaceChange,
1431 EventGuid,
1432 &GuidString,
1433 (PVOID)SymbolicLinkName);
1434
1435 ObDereferenceObject(FileObject);
1436 DPRINT("Status %x\n", Status);
1437 return STATUS_SUCCESS;
1438 }
1439
1440 /* EOF */