a9b5e475705dd9f765510e47b19de25c1d9864a2
[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 = (USHORT)((ULONG_PTR)(ReferenceString.Buffer) - (ULONG_PTR)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 HANDLE InstanceKey, DeviceParametersKey;
228 NTSTATUS Status;
229 OBJECT_ATTRIBUTES ObjectAttributes;
230 UNICODE_STRING DeviceParametersU = RTL_CONSTANT_STRING(L"Device Parameters");
231
232 Status = OpenRegistryHandlesFromSymbolicLink(SymbolicLinkName,
233 KEY_CREATE_SUB_KEY,
234 NULL,
235 NULL,
236 &InstanceKey);
237 if (!NT_SUCCESS(Status))
238 return Status;
239
240 InitializeObjectAttributes(&ObjectAttributes,
241 &DeviceParametersU,
242 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
243 InstanceKey,
244 NULL);
245 Status = ZwCreateKey(&DeviceParametersKey,
246 DesiredAccess,
247 &ObjectAttributes,
248 0,
249 NULL,
250 REG_OPTION_NON_VOLATILE,
251 NULL);
252 ZwClose(InstanceKey);
253
254 if (NT_SUCCESS(Status))
255 *DeviceInterfaceKey = DeviceParametersKey;
256
257 return Status;
258 }
259
260 /*++
261 * @name IoGetDeviceInterfaceAlias
262 * @unimplemented
263 *
264 * Returns the alias device interface of the specified device interface
265 * instance, if the alias exists.
266 * Documented in WDK.
267 *
268 * @param SymbolicLinkName
269 * Pointer to a string which identifies the device interface instance
270 *
271 * @param AliasInterfaceClassGuid
272 * See WDK
273 *
274 * @param AliasSymbolicLinkName
275 * See WDK
276 *
277 * @return Three different NTSTATUS values in case of errors, and STATUS_SUCCESS
278 * otherwise (see WDK for details)
279 *
280 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a system thread
281 *
282 *--*/
283 NTSTATUS
284 NTAPI
285 IoGetDeviceInterfaceAlias(IN PUNICODE_STRING SymbolicLinkName,
286 IN CONST GUID *AliasInterfaceClassGuid,
287 OUT PUNICODE_STRING AliasSymbolicLinkName)
288 {
289 return STATUS_NOT_IMPLEMENTED;
290 }
291
292 /*++
293 * @name IopOpenInterfaceKey
294 *
295 * Returns the alias device interface of the specified device interface
296 *
297 * @param InterfaceClassGuid
298 * FILLME
299 *
300 * @param DesiredAccess
301 * FILLME
302 *
303 * @param pInterfaceKey
304 * FILLME
305 *
306 * @return Usual NTSTATUS
307 *
308 * @remarks None
309 *
310 *--*/
311 static NTSTATUS
312 IopOpenInterfaceKey(IN CONST GUID *InterfaceClassGuid,
313 IN ACCESS_MASK DesiredAccess,
314 OUT HANDLE *pInterfaceKey)
315 {
316 UNICODE_STRING LocalMachine = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\");
317 UNICODE_STRING GuidString;
318 UNICODE_STRING KeyName;
319 OBJECT_ATTRIBUTES ObjectAttributes;
320 HANDLE InterfaceKey = INVALID_HANDLE_VALUE;
321 NTSTATUS Status;
322
323 GuidString.Buffer = KeyName.Buffer = NULL;
324
325 Status = RtlStringFromGUID(InterfaceClassGuid, &GuidString);
326 if (!NT_SUCCESS(Status))
327 {
328 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status);
329 goto cleanup;
330 }
331
332 KeyName.Length = 0;
333 KeyName.MaximumLength = LocalMachine.Length + (wcslen(REGSTR_PATH_DEVICE_CLASSES) + 1) * sizeof(WCHAR) + GuidString.Length;
334 KeyName.Buffer = ExAllocatePool(PagedPool, KeyName.MaximumLength);
335 if (!KeyName.Buffer)
336 {
337 DPRINT("ExAllocatePool() failed\n");
338 Status = STATUS_INSUFFICIENT_RESOURCES;
339 goto cleanup;
340 }
341
342 Status = RtlAppendUnicodeStringToString(&KeyName, &LocalMachine);
343 if (!NT_SUCCESS(Status))
344 {
345 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status);
346 goto cleanup;
347 }
348 Status = RtlAppendUnicodeToString(&KeyName, REGSTR_PATH_DEVICE_CLASSES);
349 if (!NT_SUCCESS(Status))
350 {
351 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status);
352 goto cleanup;
353 }
354 Status = RtlAppendUnicodeToString(&KeyName, L"\\");
355 if (!NT_SUCCESS(Status))
356 {
357 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status);
358 goto cleanup;
359 }
360 Status = RtlAppendUnicodeStringToString(&KeyName, &GuidString);
361 if (!NT_SUCCESS(Status))
362 {
363 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status);
364 goto cleanup;
365 }
366
367 InitializeObjectAttributes(
368 &ObjectAttributes,
369 &KeyName,
370 OBJ_CASE_INSENSITIVE,
371 NULL,
372 NULL);
373 Status = ZwOpenKey(
374 &InterfaceKey,
375 DesiredAccess,
376 &ObjectAttributes);
377 if (!NT_SUCCESS(Status))
378 {
379 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
380 goto cleanup;
381 }
382
383 *pInterfaceKey = InterfaceKey;
384 Status = STATUS_SUCCESS;
385
386 cleanup:
387 if (!NT_SUCCESS(Status))
388 {
389 if (InterfaceKey != INVALID_HANDLE_VALUE)
390 ZwClose(InterfaceKey);
391 }
392 RtlFreeUnicodeString(&GuidString);
393 RtlFreeUnicodeString(&KeyName);
394 return Status;
395 }
396
397 /*++
398 * @name IoGetDeviceInterfaces
399 * @implemented
400 *
401 * Returns a list of device interfaces of a particular device interface class.
402 * Documented in WDK
403 *
404 * @param InterfaceClassGuid
405 * Points to a class GUID specifying the device interface class
406 *
407 * @param PhysicalDeviceObject
408 * Points to an optional PDO that narrows the search to only the
409 * device interfaces of the device represented by the PDO
410 *
411 * @param Flags
412 * Specifies flags that modify the search for device interfaces. The
413 * DEVICE_INTERFACE_INCLUDE_NONACTIVE flag specifies that the list of
414 * returned symbolic links should contain also disabled device
415 * interfaces in addition to the enabled ones.
416 *
417 * @param SymbolicLinkList
418 * Points to a character pointer that is filled in on successful return
419 * with a list of unicode strings identifying the device interfaces
420 * that match the search criteria. The newly allocated buffer contains
421 * a list of symbolic link names. Each unicode string in the list is
422 * null-terminated; the end of the whole list is marked by an additional
423 * NULL. The caller is responsible for freeing the buffer (ExFreePool)
424 * when it is no longer needed.
425 * If no device interfaces match the search criteria, this routine
426 * returns STATUS_SUCCESS and the string contains a single NULL
427 * character.
428 *
429 * @return Usual NTSTATUS
430 *
431 * @remarks None
432 *
433 *--*/
434 NTSTATUS
435 NTAPI
436 IoGetDeviceInterfaces(IN CONST GUID *InterfaceClassGuid,
437 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
438 IN ULONG Flags,
439 OUT PWSTR *SymbolicLinkList)
440 {
441 UNICODE_STRING Control = RTL_CONSTANT_STRING(L"Control");
442 UNICODE_STRING SymbolicLink = RTL_CONSTANT_STRING(L"SymbolicLink");
443 HANDLE InterfaceKey = INVALID_HANDLE_VALUE;
444 HANDLE DeviceKey = INVALID_HANDLE_VALUE;
445 HANDLE ReferenceKey = INVALID_HANDLE_VALUE;
446 HANDLE ControlKey = INVALID_HANDLE_VALUE;
447 PKEY_BASIC_INFORMATION DeviceBi = NULL;
448 PKEY_BASIC_INFORMATION ReferenceBi = NULL;
449 PKEY_VALUE_PARTIAL_INFORMATION bip = NULL;
450 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
451 UNICODE_STRING KeyName;
452 OBJECT_ATTRIBUTES ObjectAttributes;
453 BOOLEAN FoundRightPDO = FALSE;
454 ULONG i = 0, j, Size, NeededLength, ActualLength, LinkedValue;
455 UNICODE_STRING ReturnBuffer = { 0, 0, NULL };
456 NTSTATUS Status;
457
458 PAGED_CODE();
459
460 Status = IopOpenInterfaceKey(InterfaceClassGuid, KEY_ENUMERATE_SUB_KEYS, &InterfaceKey);
461 if (!NT_SUCCESS(Status))
462 {
463 DPRINT("IopOpenInterfaceKey() failed with status 0x%08lx\n", Status);
464 goto cleanup;
465 }
466
467 /* Enumerate subkeys (ie the different device objets) */
468 while (TRUE)
469 {
470 Status = ZwEnumerateKey(
471 InterfaceKey,
472 i,
473 KeyBasicInformation,
474 NULL,
475 0,
476 &Size);
477 if (Status == STATUS_NO_MORE_ENTRIES)
478 {
479 break;
480 }
481 else if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL)
482 {
483 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
484 goto cleanup;
485 }
486
487 DeviceBi = ExAllocatePool(PagedPool, Size);
488 if (!DeviceBi)
489 {
490 DPRINT("ExAllocatePool() failed\n");
491 Status = STATUS_INSUFFICIENT_RESOURCES;
492 goto cleanup;
493 }
494 Status = ZwEnumerateKey(
495 InterfaceKey,
496 i++,
497 KeyBasicInformation,
498 DeviceBi,
499 Size,
500 &Size);
501 if (!NT_SUCCESS(Status))
502 {
503 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
504 goto cleanup;
505 }
506
507 /* Open device key */
508 KeyName.Length = KeyName.MaximumLength = (USHORT)DeviceBi->NameLength;
509 KeyName.Buffer = DeviceBi->Name;
510 InitializeObjectAttributes(
511 &ObjectAttributes,
512 &KeyName,
513 OBJ_CASE_INSENSITIVE,
514 InterfaceKey,
515 NULL);
516 Status = ZwOpenKey(
517 &DeviceKey,
518 KEY_ENUMERATE_SUB_KEYS,
519 &ObjectAttributes);
520 if (!NT_SUCCESS(Status))
521 {
522 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
523 goto cleanup;
524 }
525
526 if (PhysicalDeviceObject)
527 {
528 /* Check if we are on the right physical device object,
529 * by reading the DeviceInstance string
530 */
531 DPRINT1("PhysicalDeviceObject != NULL. Case not implemented.\n");
532 //FoundRightPDO = TRUE;
533 Status = STATUS_NOT_IMPLEMENTED;
534 goto cleanup;
535 }
536
537 /* Enumerate subkeys (ie the different reference strings) */
538 j = 0;
539 while (TRUE)
540 {
541 Status = ZwEnumerateKey(
542 DeviceKey,
543 j,
544 KeyBasicInformation,
545 NULL,
546 0,
547 &Size);
548 if (Status == STATUS_NO_MORE_ENTRIES)
549 {
550 break;
551 }
552 else if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL)
553 {
554 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
555 goto cleanup;
556 }
557
558 ReferenceBi = ExAllocatePool(PagedPool, Size);
559 if (!ReferenceBi)
560 {
561 DPRINT("ExAllocatePool() failed\n");
562 Status = STATUS_INSUFFICIENT_RESOURCES;
563 goto cleanup;
564 }
565 Status = ZwEnumerateKey(
566 DeviceKey,
567 j++,
568 KeyBasicInformation,
569 ReferenceBi,
570 Size,
571 &Size);
572 if (!NT_SUCCESS(Status))
573 {
574 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
575 goto cleanup;
576 }
577
578 KeyName.Length = KeyName.MaximumLength = (USHORT)ReferenceBi->NameLength;
579 KeyName.Buffer = ReferenceBi->Name;
580 if (RtlEqualUnicodeString(&KeyName, &Control, TRUE))
581 {
582 /* Skip Control subkey */
583 goto NextReferenceString;
584 }
585
586 /* Open reference key */
587 InitializeObjectAttributes(
588 &ObjectAttributes,
589 &KeyName,
590 OBJ_CASE_INSENSITIVE,
591 DeviceKey,
592 NULL);
593 Status = ZwOpenKey(
594 &ReferenceKey,
595 KEY_QUERY_VALUE,
596 &ObjectAttributes);
597 if (!NT_SUCCESS(Status))
598 {
599 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
600 goto cleanup;
601 }
602
603 if (!(Flags & DEVICE_INTERFACE_INCLUDE_NONACTIVE))
604 {
605 /* We have to check if the interface is enabled, by
606 * reading the Linked value in the Control subkey
607 */
608 InitializeObjectAttributes(
609 &ObjectAttributes,
610 &Control,
611 OBJ_CASE_INSENSITIVE,
612 ReferenceKey,
613 NULL);
614 Status = ZwOpenKey(
615 &ControlKey,
616 KEY_QUERY_VALUE,
617 &ObjectAttributes);
618 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
619 {
620 /* That's OK. The key doesn't exist (yet) because
621 * the interface is not activated.
622 */
623 goto NextReferenceString;
624 }
625 else if (!NT_SUCCESS(Status))
626 {
627 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
628 goto cleanup;
629 }
630
631 RtlInitUnicodeString(&KeyName, L"Linked");
632 Status = ZwQueryValueKey(ControlKey,
633 &KeyName,
634 KeyValuePartialInformation,
635 NULL,
636 0,
637 &NeededLength);
638 if (Status == STATUS_BUFFER_TOO_SMALL)
639 {
640 ActualLength = NeededLength;
641 PartialInfo = ExAllocatePool(NonPagedPool, ActualLength);
642 if (!PartialInfo)
643 {
644 Status = STATUS_INSUFFICIENT_RESOURCES;
645 goto cleanup;
646 }
647
648 Status = ZwQueryValueKey(ControlKey,
649 &KeyName,
650 KeyValuePartialInformation,
651 PartialInfo,
652 ActualLength,
653 &NeededLength);
654 if (!NT_SUCCESS(Status))
655 {
656 DPRINT1("ZwQueryValueKey #2 failed (%x)\n", Status);
657 ExFreePool(PartialInfo);
658 goto cleanup;
659 }
660
661 if (PartialInfo->Type != REG_DWORD || PartialInfo->DataLength != sizeof(ULONG))
662 {
663 DPRINT1("Bad registry read\n");
664 ExFreePool(PartialInfo);
665 goto cleanup;
666 }
667
668 RtlCopyMemory(&LinkedValue,
669 PartialInfo->Data,
670 PartialInfo->DataLength);
671
672 ExFreePool(PartialInfo);
673 if (LinkedValue == 0)
674 {
675 /* This interface isn't active */
676 goto NextReferenceString;
677 }
678 }
679 else
680 {
681 DPRINT1("ZwQueryValueKey #1 failed (%x)\n", Status);
682 goto cleanup;
683 }
684 }
685
686 /* Read the SymbolicLink string and add it into SymbolicLinkList */
687 Status = ZwQueryValueKey(
688 ReferenceKey,
689 &SymbolicLink,
690 KeyValuePartialInformation,
691 NULL,
692 0,
693 &Size);
694 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL)
695 {
696 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
697 goto cleanup;
698 }
699 bip = ExAllocatePool(PagedPool, Size);
700 if (!bip)
701 {
702 DPRINT("ExAllocatePool() failed\n");
703 Status = STATUS_INSUFFICIENT_RESOURCES;
704 goto cleanup;
705 }
706 Status = ZwQueryValueKey(
707 ReferenceKey,
708 &SymbolicLink,
709 KeyValuePartialInformation,
710 bip,
711 Size,
712 &Size);
713 if (!NT_SUCCESS(Status))
714 {
715 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
716 goto cleanup;
717 }
718 else if (bip->Type != REG_SZ)
719 {
720 DPRINT("Unexpected registry type 0x%lx (expected 0x%lx)\n", bip->Type, REG_SZ);
721 Status = STATUS_UNSUCCESSFUL;
722 goto cleanup;
723 }
724 else if (bip->DataLength < 5 * sizeof(WCHAR))
725 {
726 DPRINT("Registry string too short (length %lu, expected %lu at least)\n", bip->DataLength < 5 * sizeof(WCHAR));
727 Status = STATUS_UNSUCCESSFUL;
728 goto cleanup;
729 }
730 KeyName.Length = KeyName.MaximumLength = (USHORT)bip->DataLength - 4 * sizeof(WCHAR);
731 KeyName.Buffer = &((PWSTR)bip->Data)[4];
732 if (KeyName.Length && KeyName.Buffer[KeyName.Length / sizeof(WCHAR)] == UNICODE_NULL)
733 {
734 /* Remove trailing NULL */
735 KeyName.Length -= sizeof(WCHAR);
736 }
737
738 /* Add new symbolic link to symbolic link list */
739 if (ReturnBuffer.Length + KeyName.Length + sizeof(WCHAR) > ReturnBuffer.MaximumLength)
740 {
741 PWSTR NewBuffer;
742 ReturnBuffer.MaximumLength = max(ReturnBuffer.MaximumLength * 2, ReturnBuffer.Length + KeyName.Length + 2 * sizeof(WCHAR));
743 NewBuffer = ExAllocatePool(PagedPool, ReturnBuffer.MaximumLength);
744 if (!NewBuffer)
745 {
746 DPRINT("ExAllocatePool() failed\n");
747 Status = STATUS_INSUFFICIENT_RESOURCES;
748 goto cleanup;
749 }
750 RtlCopyMemory(NewBuffer, ReturnBuffer.Buffer, ReturnBuffer.Length);
751 if (ReturnBuffer.Buffer)
752 ExFreePool(ReturnBuffer.Buffer);
753 ReturnBuffer.Buffer = NewBuffer;
754 }
755 DPRINT("Adding symbolic link %wZ\n", &KeyName);
756 Status = RtlAppendUnicodeStringToString(&ReturnBuffer, &KeyName);
757 if (!NT_SUCCESS(Status))
758 {
759 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status);
760 goto cleanup;
761 }
762 /* RtlAppendUnicodeStringToString added a NULL at the end of the
763 * destination string, but didn't increase the Length field.
764 * Do it for it.
765 */
766 ReturnBuffer.Length += sizeof(WCHAR);
767
768 NextReferenceString:
769 ExFreePool(ReferenceBi);
770 ReferenceBi = NULL;
771 if (bip)
772 ExFreePool(bip);
773 bip = NULL;
774 if (ReferenceKey != INVALID_HANDLE_VALUE)
775 {
776 ZwClose(ReferenceKey);
777 ReferenceKey = INVALID_HANDLE_VALUE;
778 }
779 if (ControlKey != INVALID_HANDLE_VALUE)
780 {
781 ZwClose(ControlKey);
782 ControlKey = INVALID_HANDLE_VALUE;
783 }
784 }
785 if (FoundRightPDO)
786 {
787 /* No need to go further, as we already have found what we searched */
788 break;
789 }
790
791 ExFreePool(DeviceBi);
792 DeviceBi = NULL;
793 ZwClose(DeviceKey);
794 DeviceKey = INVALID_HANDLE_VALUE;
795 }
796
797 /* Add final NULL to ReturnBuffer */
798 if (ReturnBuffer.Length >= ReturnBuffer.MaximumLength)
799 {
800 PWSTR NewBuffer;
801 ReturnBuffer.MaximumLength += sizeof(WCHAR);
802 NewBuffer = ExAllocatePool(PagedPool, ReturnBuffer.MaximumLength);
803 if (!NewBuffer)
804 {
805 DPRINT("ExAllocatePool() failed\n");
806 Status = STATUS_INSUFFICIENT_RESOURCES;
807 goto cleanup;
808 }
809 if (ReturnBuffer.Buffer)
810 {
811 RtlCopyMemory(NewBuffer, ReturnBuffer.Buffer, ReturnBuffer.Length);
812 ExFreePool(ReturnBuffer.Buffer);
813 }
814 ReturnBuffer.Buffer = NewBuffer;
815 }
816 ReturnBuffer.Buffer[ReturnBuffer.Length / sizeof(WCHAR)] = UNICODE_NULL;
817 *SymbolicLinkList = ReturnBuffer.Buffer;
818 Status = STATUS_SUCCESS;
819
820 cleanup:
821 if (!NT_SUCCESS(Status) && ReturnBuffer.Buffer)
822 ExFreePool(ReturnBuffer.Buffer);
823 if (InterfaceKey != INVALID_HANDLE_VALUE)
824 ZwClose(InterfaceKey);
825 if (DeviceKey != INVALID_HANDLE_VALUE)
826 ZwClose(DeviceKey);
827 if (ReferenceKey != INVALID_HANDLE_VALUE)
828 ZwClose(ReferenceKey);
829 if (ControlKey != INVALID_HANDLE_VALUE)
830 ZwClose(ControlKey);
831 if (DeviceBi)
832 ExFreePool(DeviceBi);
833 if (ReferenceBi)
834 ExFreePool(ReferenceBi);
835 if (bip)
836 ExFreePool(bip);
837 return Status;
838 }
839
840 /*++
841 * @name IoRegisterDeviceInterface
842 * @implemented
843 *
844 * Registers a device interface class, if it has not been previously registered,
845 * and creates a new instance of the interface class, which a driver can
846 * subsequently enable for use by applications or other system components.
847 * Documented in WDK.
848 *
849 * @param PhysicalDeviceObject
850 * Points to an optional PDO that narrows the search to only the
851 * device interfaces of the device represented by the PDO
852 *
853 * @param InterfaceClassGuid
854 * Points to a class GUID specifying the device interface class
855 *
856 * @param ReferenceString
857 * Optional parameter, pointing to a unicode string. For a full
858 * description of this rather rarely used param (usually drivers
859 * pass NULL here) see WDK
860 *
861 * @param SymbolicLinkName
862 * Pointer to the resulting unicode string
863 *
864 * @return Usual NTSTATUS
865 *
866 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a
867 * system thread
868 *
869 *--*/
870 NTSTATUS
871 NTAPI
872 IoRegisterDeviceInterface(IN PDEVICE_OBJECT PhysicalDeviceObject,
873 IN CONST GUID *InterfaceClassGuid,
874 IN PUNICODE_STRING ReferenceString OPTIONAL,
875 OUT PUNICODE_STRING SymbolicLinkName)
876 {
877 PUNICODE_STRING InstancePath;
878 UNICODE_STRING GuidString;
879 UNICODE_STRING SubKeyName;
880 UNICODE_STRING InterfaceKeyName;
881 UNICODE_STRING BaseKeyName;
882 UCHAR PdoNameInfoBuffer[sizeof(OBJECT_NAME_INFORMATION) + (256 * sizeof(WCHAR))];
883 POBJECT_NAME_INFORMATION PdoNameInfo = (POBJECT_NAME_INFORMATION)PdoNameInfoBuffer;
884 UNICODE_STRING DeviceInstance = RTL_CONSTANT_STRING(L"DeviceInstance");
885 UNICODE_STRING SymbolicLink = RTL_CONSTANT_STRING(L"SymbolicLink");
886 HANDLE ClassKey;
887 HANDLE InterfaceKey;
888 HANDLE SubKey;
889 ULONG StartIndex;
890 OBJECT_ATTRIBUTES ObjectAttributes;
891 ULONG i;
892 NTSTATUS Status;
893 PEXTENDED_DEVOBJ_EXTENSION DeviceObjectExtension;
894
895 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
896
897 DPRINT("IoRegisterDeviceInterface(): PDO %p, RefString: %wZ\n",
898 PhysicalDeviceObject, ReferenceString);
899
900 /* Parameters must pass three border of checks */
901 DeviceObjectExtension = (PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension;
902
903 /* 1st level: Presence of a Device Node */
904 if (DeviceObjectExtension->DeviceNode == NULL)
905 {
906 DPRINT("PhysicalDeviceObject 0x%p doesn't have a DeviceNode\n", PhysicalDeviceObject);
907 return STATUS_INVALID_DEVICE_REQUEST;
908 }
909
910 /* 2nd level: Presence of an non-zero length InstancePath */
911 if (DeviceObjectExtension->DeviceNode->InstancePath.Length == 0)
912 {
913 DPRINT("PhysicalDeviceObject 0x%p's DOE has zero-length InstancePath\n", PhysicalDeviceObject);
914 return STATUS_INVALID_DEVICE_REQUEST;
915 }
916
917 /* 3rd level: Optional, based on WDK documentation */
918 if (ReferenceString != NULL)
919 {
920 /* Reference string must not contain path-separator symbols */
921 for (i = 0; i < ReferenceString->Length / sizeof(WCHAR); i++)
922 {
923 if ((ReferenceString->Buffer[i] == '\\') ||
924 (ReferenceString->Buffer[i] == '/'))
925 return STATUS_INVALID_DEVICE_REQUEST;
926 }
927 }
928
929 Status = RtlStringFromGUID(InterfaceClassGuid, &GuidString);
930 if (!NT_SUCCESS(Status))
931 {
932 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status);
933 return Status;
934 }
935
936 /* Create Pdo name: \Device\xxxxxxxx (unnamed device) */
937 Status = ObQueryNameString(
938 PhysicalDeviceObject,
939 PdoNameInfo,
940 sizeof(PdoNameInfoBuffer),
941 &i);
942 if (!NT_SUCCESS(Status))
943 {
944 DPRINT("ObQueryNameString() failed with status 0x%08lx\n", Status);
945 return Status;
946 }
947 ASSERT(PdoNameInfo->Name.Length);
948
949 /* Create base key name for this interface: HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
950 ASSERT(((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode);
951 InstancePath = &((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode->InstancePath;
952 BaseKeyName.Length = wcslen(BaseKeyString) * sizeof(WCHAR);
953 BaseKeyName.MaximumLength = BaseKeyName.Length
954 + GuidString.Length;
955 BaseKeyName.Buffer = ExAllocatePool(
956 PagedPool,
957 BaseKeyName.MaximumLength);
958 if (!BaseKeyName.Buffer)
959 {
960 DPRINT("ExAllocatePool() failed\n");
961 return STATUS_INSUFFICIENT_RESOURCES;
962 }
963 wcscpy(BaseKeyName.Buffer, BaseKeyString);
964 RtlAppendUnicodeStringToString(&BaseKeyName, &GuidString);
965
966 /* Create BaseKeyName key in registry */
967 InitializeObjectAttributes(
968 &ObjectAttributes,
969 &BaseKeyName,
970 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE | OBJ_OPENIF,
971 NULL, /* RootDirectory */
972 NULL); /* SecurityDescriptor */
973
974 Status = ZwCreateKey(
975 &ClassKey,
976 KEY_WRITE,
977 &ObjectAttributes,
978 0, /* TileIndex */
979 NULL, /* Class */
980 REG_OPTION_VOLATILE,
981 NULL); /* Disposition */
982
983 if (!NT_SUCCESS(Status))
984 {
985 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
986 ExFreePool(BaseKeyName.Buffer);
987 return Status;
988 }
989
990 /* Create key name for this interface: ##?#ACPI#PNP0501#1#{GUID} */
991 InterfaceKeyName.Length = 0;
992 InterfaceKeyName.MaximumLength =
993 4 * sizeof(WCHAR) + /* 4 = size of ##?# */
994 InstancePath->Length +
995 sizeof(WCHAR) + /* 1 = size of # */
996 GuidString.Length;
997 InterfaceKeyName.Buffer = ExAllocatePool(
998 PagedPool,
999 InterfaceKeyName.MaximumLength);
1000 if (!InterfaceKeyName.Buffer)
1001 {
1002 DPRINT("ExAllocatePool() failed\n");
1003 return STATUS_INSUFFICIENT_RESOURCES;
1004 }
1005
1006 RtlAppendUnicodeToString(&InterfaceKeyName, L"##?#");
1007 StartIndex = InterfaceKeyName.Length / sizeof(WCHAR);
1008 RtlAppendUnicodeStringToString(&InterfaceKeyName, InstancePath);
1009 for (i = 0; i < InstancePath->Length / sizeof(WCHAR); i++)
1010 {
1011 if (InterfaceKeyName.Buffer[StartIndex + i] == '\\')
1012 InterfaceKeyName.Buffer[StartIndex + i] = '#';
1013 }
1014 RtlAppendUnicodeToString(&InterfaceKeyName, L"#");
1015 RtlAppendUnicodeStringToString(&InterfaceKeyName, &GuidString);
1016
1017 /* Create the interface key in registry */
1018 InitializeObjectAttributes(
1019 &ObjectAttributes,
1020 &InterfaceKeyName,
1021 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE | OBJ_OPENIF,
1022 ClassKey,
1023 NULL); /* SecurityDescriptor */
1024
1025 Status = ZwCreateKey(
1026 &InterfaceKey,
1027 KEY_WRITE,
1028 &ObjectAttributes,
1029 0, /* TileIndex */
1030 NULL, /* Class */
1031 REG_OPTION_VOLATILE,
1032 NULL); /* Disposition */
1033
1034 if (!NT_SUCCESS(Status))
1035 {
1036 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
1037 ZwClose(ClassKey);
1038 ExFreePool(BaseKeyName.Buffer);
1039 return Status;
1040 }
1041
1042 /* Write DeviceInstance entry. Value is InstancePath */
1043 Status = ZwSetValueKey(
1044 InterfaceKey,
1045 &DeviceInstance,
1046 0, /* TileIndex */
1047 REG_SZ,
1048 InstancePath->Buffer,
1049 InstancePath->Length);
1050 if (!NT_SUCCESS(Status))
1051 {
1052 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
1053 ZwClose(InterfaceKey);
1054 ZwClose(ClassKey);
1055 ExFreePool(InterfaceKeyName.Buffer);
1056 ExFreePool(BaseKeyName.Buffer);
1057 return Status;
1058 }
1059
1060 /* Create subkey. Name is #ReferenceString */
1061 SubKeyName.Length = 0;
1062 SubKeyName.MaximumLength = sizeof(WCHAR);
1063 if (ReferenceString && ReferenceString->Length)
1064 SubKeyName.MaximumLength += ReferenceString->Length;
1065 SubKeyName.Buffer = ExAllocatePool(
1066 PagedPool,
1067 SubKeyName.MaximumLength);
1068 if (!SubKeyName.Buffer)
1069 {
1070 DPRINT("ExAllocatePool() failed\n");
1071 ZwClose(InterfaceKey);
1072 ZwClose(ClassKey);
1073 ExFreePool(InterfaceKeyName.Buffer);
1074 ExFreePool(BaseKeyName.Buffer);
1075 return STATUS_INSUFFICIENT_RESOURCES;
1076 }
1077 RtlAppendUnicodeToString(&SubKeyName, L"#");
1078 if (ReferenceString && ReferenceString->Length)
1079 RtlAppendUnicodeStringToString(&SubKeyName, ReferenceString);
1080
1081 /* Create SubKeyName key in registry */
1082 InitializeObjectAttributes(
1083 &ObjectAttributes,
1084 &SubKeyName,
1085 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1086 InterfaceKey, /* RootDirectory */
1087 NULL); /* SecurityDescriptor */
1088
1089 Status = ZwCreateKey(
1090 &SubKey,
1091 KEY_WRITE,
1092 &ObjectAttributes,
1093 0, /* TileIndex */
1094 NULL, /* Class */
1095 REG_OPTION_VOLATILE,
1096 NULL); /* Disposition */
1097
1098 if (!NT_SUCCESS(Status))
1099 {
1100 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
1101 ZwClose(InterfaceKey);
1102 ZwClose(ClassKey);
1103 ExFreePool(InterfaceKeyName.Buffer);
1104 ExFreePool(BaseKeyName.Buffer);
1105 return Status;
1106 }
1107
1108 /* Create symbolic link name: \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
1109 SymbolicLinkName->Length = 0;
1110 SymbolicLinkName->MaximumLength = SymbolicLinkName->Length
1111 + 4 * sizeof(WCHAR) /* 4 = size of \??\ */
1112 + InstancePath->Length
1113 + sizeof(WCHAR) /* 1 = size of # */
1114 + GuidString.Length
1115 + sizeof(WCHAR); /* final NULL */
1116 if (ReferenceString && ReferenceString->Length)
1117 SymbolicLinkName->MaximumLength += sizeof(WCHAR) + ReferenceString->Length;
1118 SymbolicLinkName->Buffer = ExAllocatePool(
1119 PagedPool,
1120 SymbolicLinkName->MaximumLength);
1121 if (!SymbolicLinkName->Buffer)
1122 {
1123 DPRINT("ExAllocatePool() failed\n");
1124 ZwClose(SubKey);
1125 ZwClose(InterfaceKey);
1126 ZwClose(ClassKey);
1127 ExFreePool(InterfaceKeyName.Buffer);
1128 ExFreePool(SubKeyName.Buffer);
1129 ExFreePool(BaseKeyName.Buffer);
1130 return STATUS_INSUFFICIENT_RESOURCES;
1131 }
1132 RtlAppendUnicodeToString(SymbolicLinkName, L"\\??\\");
1133 StartIndex = SymbolicLinkName->Length / sizeof(WCHAR);
1134 RtlAppendUnicodeStringToString(SymbolicLinkName, InstancePath);
1135 for (i = 0; i < InstancePath->Length / sizeof(WCHAR); i++)
1136 {
1137 if (SymbolicLinkName->Buffer[StartIndex + i] == '\\')
1138 SymbolicLinkName->Buffer[StartIndex + i] = '#';
1139 }
1140 RtlAppendUnicodeToString(SymbolicLinkName, L"#");
1141 RtlAppendUnicodeStringToString(SymbolicLinkName, &GuidString);
1142 SymbolicLinkName->Buffer[SymbolicLinkName->Length/sizeof(WCHAR)] = L'\0';
1143
1144 /* Create symbolic link */
1145 DPRINT("IoRegisterDeviceInterface(): creating symbolic link %wZ -> %wZ\n", SymbolicLinkName, &PdoNameInfo->Name);
1146 Status = IoCreateSymbolicLink(SymbolicLinkName, &PdoNameInfo->Name);
1147 if (!NT_SUCCESS(Status) && ReferenceString == NULL)
1148 {
1149 DPRINT1("IoCreateSymbolicLink() failed with status 0x%08lx\n", Status);
1150 ZwClose(SubKey);
1151 ZwClose(InterfaceKey);
1152 ZwClose(ClassKey);
1153 ExFreePool(SubKeyName.Buffer);
1154 ExFreePool(InterfaceKeyName.Buffer);
1155 ExFreePool(BaseKeyName.Buffer);
1156 ExFreePool(SymbolicLinkName->Buffer);
1157 return Status;
1158 }
1159
1160 if (ReferenceString && ReferenceString->Length)
1161 {
1162 RtlAppendUnicodeToString(SymbolicLinkName, L"\\");
1163 RtlAppendUnicodeStringToString(SymbolicLinkName, ReferenceString);
1164 }
1165 SymbolicLinkName->Buffer[SymbolicLinkName->Length/sizeof(WCHAR)] = L'\0';
1166
1167 /* Write symbolic link name in registry */
1168 SymbolicLinkName->Buffer[1] = '\\';
1169 Status = ZwSetValueKey(
1170 SubKey,
1171 &SymbolicLink,
1172 0, /* TileIndex */
1173 REG_SZ,
1174 SymbolicLinkName->Buffer,
1175 SymbolicLinkName->Length);
1176 if (!NT_SUCCESS(Status))
1177 {
1178 DPRINT1("ZwSetValueKey() failed with status 0x%08lx\n", Status);
1179 ExFreePool(SymbolicLinkName->Buffer);
1180 }
1181 else
1182 {
1183 SymbolicLinkName->Buffer[1] = '?';
1184 }
1185
1186 ZwClose(SubKey);
1187 ZwClose(InterfaceKey);
1188 ZwClose(ClassKey);
1189 ExFreePool(SubKeyName.Buffer);
1190 ExFreePool(InterfaceKeyName.Buffer);
1191 ExFreePool(BaseKeyName.Buffer);
1192
1193 return Status;
1194 }
1195
1196 /*++
1197 * @name IoSetDeviceInterfaceState
1198 * @implemented
1199 *
1200 * Enables or disables an instance of a previously registered device
1201 * interface class.
1202 * Documented in WDK.
1203 *
1204 * @param SymbolicLinkName
1205 * Pointer to the string identifying instance to enable or disable
1206 *
1207 * @param Enable
1208 * TRUE = enable, FALSE = disable
1209 *
1210 * @return Usual NTSTATUS
1211 *
1212 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a
1213 * system thread
1214 *
1215 *--*/
1216 NTSTATUS
1217 NTAPI
1218 IoSetDeviceInterfaceState(IN PUNICODE_STRING SymbolicLinkName,
1219 IN BOOLEAN Enable)
1220 {
1221 PDEVICE_OBJECT PhysicalDeviceObject;
1222 PFILE_OBJECT FileObject;
1223 UNICODE_STRING GuidString;
1224 UNICODE_STRING SymLink;
1225 PWCHAR StartPosition;
1226 PWCHAR EndPosition;
1227 NTSTATUS Status;
1228 LPCGUID EventGuid;
1229 HANDLE InstanceHandle, ControlHandle;
1230 UNICODE_STRING KeyName;
1231 OBJECT_ATTRIBUTES ObjectAttributes;
1232 ULONG LinkedValue;
1233
1234 if (SymbolicLinkName == NULL)
1235 return STATUS_INVALID_PARAMETER_1;
1236
1237 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName, Enable);
1238
1239 /* Symbolic link name is \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
1240 /* Get GUID from SymbolicLinkName */
1241 StartPosition = wcschr(SymbolicLinkName->Buffer, L'{');
1242 EndPosition = wcschr(SymbolicLinkName->Buffer, L'}');
1243 if (!StartPosition ||!EndPosition || StartPosition > EndPosition)
1244 {
1245 DPRINT1("IoSetDeviceInterfaceState() returning STATUS_INVALID_PARAMETER_1\n");
1246 return STATUS_INVALID_PARAMETER_1;
1247 }
1248 GuidString.Buffer = StartPosition;
1249 GuidString.MaximumLength = GuidString.Length = (USHORT)((ULONG_PTR)(EndPosition + 1) - (ULONG_PTR)StartPosition);
1250
1251 SymLink.Buffer = SymbolicLinkName->Buffer;
1252 SymLink.MaximumLength = SymLink.Length = (USHORT)((ULONG_PTR)(EndPosition + 1) - (ULONG_PTR)SymLink.Buffer);
1253 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName, Enable);
1254
1255 Status = OpenRegistryHandlesFromSymbolicLink(SymbolicLinkName,
1256 KEY_CREATE_SUB_KEY,
1257 NULL,
1258 NULL,
1259 &InstanceHandle);
1260 if (!NT_SUCCESS(Status))
1261 return Status;
1262
1263 RtlInitUnicodeString(&KeyName, L"Control");
1264 InitializeObjectAttributes(&ObjectAttributes,
1265 &KeyName,
1266 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1267 InstanceHandle,
1268 NULL);
1269 Status = ZwCreateKey(&ControlHandle,
1270 KEY_SET_VALUE,
1271 &ObjectAttributes,
1272 0,
1273 NULL,
1274 REG_OPTION_VOLATILE,
1275 NULL);
1276 ZwClose(InstanceHandle);
1277 if (!NT_SUCCESS(Status))
1278 {
1279 DPRINT1("Failed to create the Control subkey\n");
1280 return Status;
1281 }
1282
1283 LinkedValue = (Enable ? 1 : 0);
1284
1285 RtlInitUnicodeString(&KeyName, L"Linked");
1286 Status = ZwSetValueKey(ControlHandle,
1287 &KeyName,
1288 0,
1289 REG_DWORD,
1290 &LinkedValue,
1291 sizeof(ULONG));
1292 ZwClose(ControlHandle);
1293 if (!NT_SUCCESS(Status))
1294 {
1295 DPRINT1("Failed to write the Linked value\n");
1296 return Status;
1297 }
1298
1299 /* Get pointer to the PDO */
1300 Status = IoGetDeviceObjectPointer(
1301 &SymLink,
1302 0, /* DesiredAccess */
1303 &FileObject,
1304 &PhysicalDeviceObject);
1305 if (!NT_SUCCESS(Status))
1306 {
1307 DPRINT1("IoGetDeviceObjectPointer() failed with status 0x%08lx\n", Status);
1308 return Status;
1309 }
1310
1311 EventGuid = Enable ? &GUID_DEVICE_INTERFACE_ARRIVAL : &GUID_DEVICE_INTERFACE_REMOVAL;
1312 IopNotifyPlugPlayNotification(
1313 PhysicalDeviceObject,
1314 EventCategoryDeviceInterfaceChange,
1315 EventGuid,
1316 &GuidString,
1317 (PVOID)SymbolicLinkName);
1318
1319 ObDereferenceObject(FileObject);
1320 DPRINT("Status %x\n", Status);
1321 return STATUS_SUCCESS;
1322 }
1323
1324 /* EOF */