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