4a624f2eb30916558c01b7c584b5ce8d530fc7ec
[reactos.git] / reactos / ntoskrnl / io / deviface.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/deviface.c
6 * PURPOSE: Device interface functions
7 *
8 * PROGRAMMERS: Filip Navara (xnavara@volny.cz)
9 * Matthew Brace (ismarc@austin.rr.com)
10 * Hervé Poussineau (hpoussin@reactos.com)
11 */
12
13 /* INCLUDES ******************************************************************/
14
15 #include <ntoskrnl.h>
16
17 #define NDEBUG
18 #include <internal/debug.h>
19
20 /* FUNCTIONS *****************************************************************/
21
22 static PWCHAR BaseKeyString = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\DeviceClasses\\";
23
24 /*
25 * @unimplemented
26 */
27
28 NTSTATUS STDCALL
29 IoOpenDeviceInterfaceRegistryKey(
30 IN PUNICODE_STRING SymbolicLinkName,
31 IN ACCESS_MASK DesiredAccess,
32 OUT PHANDLE DeviceInterfaceKey)
33 {
34 return STATUS_NOT_IMPLEMENTED;
35 }
36
37 /*
38 * @unimplemented
39 */
40
41 NTSTATUS STDCALL
42 IoGetDeviceInterfaceAlias(
43 IN PUNICODE_STRING SymbolicLinkName,
44 IN CONST GUID *AliasInterfaceClassGuid,
45 OUT PUNICODE_STRING AliasSymbolicLinkName)
46 {
47 return STATUS_NOT_IMPLEMENTED;
48 }
49
50 /*
51 * IoGetDeviceInterfaces
52 *
53 * Returns a list of device interfaces of a particular device interface class.
54 *
55 * Parameters
56 * InterfaceClassGuid
57 * Points to a class GUID specifying the device interface class.
58 *
59 * PhysicalDeviceObject
60 * Points to an optional PDO that narrows the search to only the
61 * device interfaces of the device represented by the PDO.
62 *
63 * Flags
64 * Specifies flags that modify the search for device interfaces. The
65 * DEVICE_INTERFACE_INCLUDE_NONACTIVE flag specifies that the list of
66 * returned symbolic links should contain also disabled device
67 * interfaces in addition to the enabled ones.
68 *
69 * SymbolicLinkList
70 * Points to a character pointer that is filled in on successful return
71 * with a list of unicode strings identifying the device interfaces
72 * that match the search criteria. The newly allocated buffer contains
73 * a list of symbolic link names. Each unicode string in the list is
74 * null-terminated; the end of the whole list is marked by an additional
75 * NULL. The caller is responsible for freeing the buffer (ExFreePool)
76 * when it is no longer needed.
77 * If no device interfaces match the search criteria, this routine
78 * returns STATUS_SUCCESS and the string contains a single NULL
79 * character.
80 *
81 * Status
82 * @implemented
83 *
84 * The parameters PhysicalDeviceObject and Flags aren't correctly
85 * processed. Rest of the cases was tested under Windows(R) XP and
86 * the function worked correctly.
87 */
88
89 NTSTATUS STDCALL
90 IoGetDeviceInterfaces(
91 IN CONST GUID *InterfaceClassGuid,
92 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
93 IN ULONG Flags,
94 OUT PWSTR *SymbolicLinkList)
95 {
96 PWCHAR BaseInterfaceString = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
97 UNICODE_STRING GuidString;
98 UNICODE_STRING BaseKeyName;
99 UNICODE_STRING AliasKeyName;
100 UNICODE_STRING SymbolicLink;
101 UNICODE_STRING Control;
102 UNICODE_STRING SubKeyName;
103 UNICODE_STRING SymbolicLinkKeyName;
104 UNICODE_STRING ControlKeyName;
105 UNICODE_STRING TempString;
106 HANDLE InterfaceKey;
107 HANDLE SubKey;
108 HANDLE SymbolicLinkKey;
109 PKEY_FULL_INFORMATION fip;
110 PKEY_FULL_INFORMATION bfip = NULL;
111 PKEY_BASIC_INFORMATION bip;
112 PKEY_VALUE_PARTIAL_INFORMATION vpip = NULL;
113 PWCHAR SymLinkList = NULL;
114 ULONG SymLinkListSize = 0;
115 NTSTATUS Status;
116 ULONG Size = 0;
117 ULONG i = 0;
118 ULONG j = 0;
119 OBJECT_ATTRIBUTES ObjectAttributes;
120
121 ASSERT_IRQL(PASSIVE_LEVEL);
122
123 Status = RtlStringFromGUID(InterfaceClassGuid, &GuidString);
124 if (!NT_SUCCESS(Status))
125 {
126 DPRINT("RtlStringFromGUID() Failed.\n");
127 return STATUS_INVALID_HANDLE;
128 }
129
130 RtlInitUnicodeString(&AliasKeyName, BaseInterfaceString);
131 RtlInitUnicodeString(&SymbolicLink, L"SymbolicLink");
132 RtlInitUnicodeString(&Control, L"\\Control");
133 BaseKeyName.Length = wcslen(BaseKeyString) * sizeof(WCHAR);
134 BaseKeyName.MaximumLength = BaseKeyName.Length + (38 * sizeof(WCHAR));
135 BaseKeyName.Buffer = ExAllocatePool(
136 PagedPool,
137 BaseKeyName.MaximumLength);
138 ASSERT(BaseKeyName.Buffer != NULL);
139 wcscpy(BaseKeyName.Buffer, BaseKeyString);
140 RtlAppendUnicodeStringToString(&BaseKeyName, &GuidString);
141
142 if (PhysicalDeviceObject)
143 {
144 WCHAR GuidBuffer[40];
145 UNICODE_STRING PdoGuidString;
146
147 RtlFreeUnicodeString(&BaseKeyName);
148
149 IoGetDeviceProperty(
150 PhysicalDeviceObject,
151 DevicePropertyClassGuid,
152 sizeof(GuidBuffer),
153 GuidBuffer,
154 &Size);
155
156 RtlInitUnicodeString(&PdoGuidString, GuidBuffer);
157 if (RtlCompareUnicodeString(&GuidString, &PdoGuidString, TRUE))
158 {
159 DPRINT("Inconsistent Guid's asked for in IoGetDeviceInterfaces()\n");
160 return STATUS_INVALID_HANDLE;
161 }
162
163 DPRINT("IoGetDeviceInterfaces() called with PDO, not implemented.\n");
164 return STATUS_NOT_IMPLEMENTED;
165 }
166 else
167 {
168 InitializeObjectAttributes(
169 &ObjectAttributes,
170 &BaseKeyName,
171 OBJ_CASE_INSENSITIVE,
172 NULL,
173 NULL);
174
175 Status = ZwOpenKey(
176 &InterfaceKey,
177 KEY_READ,
178 &ObjectAttributes);
179
180 if (!NT_SUCCESS(Status))
181 {
182 DPRINT("ZwOpenKey() Failed. (0x%X)\n", Status);
183 RtlFreeUnicodeString(&BaseKeyName);
184 return Status;
185 }
186
187 Status = ZwQueryKey(
188 InterfaceKey,
189 KeyFullInformation,
190 NULL,
191 0,
192 &Size);
193
194 if (Status != STATUS_BUFFER_TOO_SMALL)
195 {
196 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status);
197 RtlFreeUnicodeString(&BaseKeyName);
198 ZwClose(InterfaceKey);
199 return Status;
200 }
201
202 fip = (PKEY_FULL_INFORMATION)ExAllocatePool(PagedPool, Size);
203 ASSERT(fip != NULL);
204
205 Status = ZwQueryKey(
206 InterfaceKey,
207 KeyFullInformation,
208 fip,
209 Size,
210 &Size);
211
212 if (!NT_SUCCESS(Status))
213 {
214 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status);
215 ExFreePool(fip);
216 RtlFreeUnicodeString(&BaseKeyName);
217 ZwClose(InterfaceKey);
218 return Status;
219 }
220
221 for (; i < fip->SubKeys; i++)
222 {
223 Status = ZwEnumerateKey(
224 InterfaceKey,
225 i,
226 KeyBasicInformation,
227 NULL,
228 0,
229 &Size);
230
231 if (Status != STATUS_BUFFER_TOO_SMALL)
232 {
233 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status);
234 ExFreePool(fip);
235 if (SymLinkList != NULL)
236 ExFreePool(SymLinkList);
237 RtlFreeUnicodeString(&BaseKeyName);
238 ZwClose(InterfaceKey);
239 return Status;
240 }
241
242 bip = (PKEY_BASIC_INFORMATION)ExAllocatePool(PagedPool, Size);
243 ASSERT(bip != NULL);
244
245 Status = ZwEnumerateKey(
246 InterfaceKey,
247 i,
248 KeyBasicInformation,
249 bip,
250 Size,
251 &Size);
252
253 if (!NT_SUCCESS(Status))
254 {
255 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status);
256 ExFreePool(fip);
257 ExFreePool(bip);
258 if (SymLinkList != NULL)
259 ExFreePool(SymLinkList);
260 RtlFreeUnicodeString(&BaseKeyName);
261 ZwClose(InterfaceKey);
262 return Status;
263 }
264
265 SubKeyName.Length = 0;
266 SubKeyName.MaximumLength = BaseKeyName.Length + bip->NameLength + sizeof(WCHAR);
267 SubKeyName.Buffer = ExAllocatePool(PagedPool, SubKeyName.MaximumLength);
268 ASSERT(SubKeyName.Buffer != NULL);
269 TempString.Length = TempString.MaximumLength = bip->NameLength;
270 TempString.Buffer = bip->Name;
271 RtlCopyUnicodeString(&SubKeyName, &BaseKeyName);
272 RtlAppendUnicodeToString(&SubKeyName, L"\\");
273 RtlAppendUnicodeStringToString(&SubKeyName, &TempString);
274
275 ExFreePool(bip);
276
277 InitializeObjectAttributes(
278 &ObjectAttributes,
279 &SubKeyName,
280 OBJ_CASE_INSENSITIVE,
281 NULL,
282 NULL);
283
284 Status = ZwOpenKey(
285 &SubKey,
286 KEY_READ,
287 &ObjectAttributes);
288
289 if (!NT_SUCCESS(Status))
290 {
291 DPRINT("ZwOpenKey() Failed. (0x%X)\n", Status);
292 ExFreePool(fip);
293 if (SymLinkList != NULL)
294 ExFreePool(SymLinkList);
295 RtlFreeUnicodeString(&SubKeyName);
296 RtlFreeUnicodeString(&BaseKeyName);
297 ZwClose(InterfaceKey);
298 return Status;
299 }
300
301 Status = ZwQueryKey(
302 SubKey,
303 KeyFullInformation,
304 NULL,
305 0,
306 &Size);
307
308 if (Status != STATUS_BUFFER_TOO_SMALL)
309 {
310 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status);
311 ExFreePool(fip);
312 RtlFreeUnicodeString(&BaseKeyName);
313 RtlFreeUnicodeString(&SubKeyName);
314 ZwClose(SubKey);
315 ZwClose(InterfaceKey);
316 return Status;
317 }
318
319 bfip = (PKEY_FULL_INFORMATION)ExAllocatePool(PagedPool, Size);
320 ASSERT(bfip != NULL);
321
322 Status = ZwQueryKey(
323 SubKey,
324 KeyFullInformation,
325 bfip,
326 Size,
327 &Size);
328
329 if (!NT_SUCCESS(Status))
330 {
331 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status);
332 ExFreePool(fip);
333 RtlFreeUnicodeString(&SubKeyName);
334 RtlFreeUnicodeString(&BaseKeyName);
335 ZwClose(SubKey);
336 ZwClose(InterfaceKey);
337 return Status;
338 }
339
340 for(j = 0; j < bfip->SubKeys; j++)
341 {
342 Status = ZwEnumerateKey(
343 SubKey,
344 j,
345 KeyBasicInformation,
346 NULL,
347 0,
348 &Size);
349
350 if (Status == STATUS_NO_MORE_ENTRIES)
351 continue;
352
353 if (Status != STATUS_BUFFER_TOO_SMALL)
354 {
355 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status);
356 ExFreePool(bfip);
357 ExFreePool(fip);
358 if (SymLinkList != NULL)
359 ExFreePool(SymLinkList);
360 RtlFreeUnicodeString(&SubKeyName);
361 RtlFreeUnicodeString(&BaseKeyName);
362 ZwClose(SubKey);
363 ZwClose(InterfaceKey);
364 return Status;
365 }
366
367 bip = (PKEY_BASIC_INFORMATION)ExAllocatePool(PagedPool, Size);
368 ASSERT(bip != NULL);
369
370 Status = ZwEnumerateKey(
371 SubKey,
372 j,
373 KeyBasicInformation,
374 bip,
375 Size,
376 &Size);
377
378 if (!NT_SUCCESS(Status))
379 {
380 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status);
381 ExFreePool(fip);
382 ExFreePool(bfip);
383 ExFreePool(bip);
384 if (SymLinkList != NULL)
385 ExFreePool(SymLinkList);
386 RtlFreeUnicodeString(&SubKeyName);
387 RtlFreeUnicodeString(&BaseKeyName);
388 ZwClose(SubKey);
389 ZwClose(InterfaceKey);
390 return Status;
391 }
392
393 if (!wcsncmp(bip->Name, L"Control", bip->NameLength))
394 {
395 continue;
396 }
397
398 SymbolicLinkKeyName.Length = 0;
399 SymbolicLinkKeyName.MaximumLength = SubKeyName.Length + bip->NameLength + sizeof(WCHAR);
400 SymbolicLinkKeyName.Buffer = ExAllocatePool(PagedPool, SymbolicLinkKeyName.MaximumLength);
401 ASSERT(SymbolicLinkKeyName.Buffer != NULL);
402 TempString.Length = TempString.MaximumLength = bip->NameLength;
403 TempString.Buffer = bip->Name;
404 RtlCopyUnicodeString(&SymbolicLinkKeyName, &SubKeyName);
405 RtlAppendUnicodeToString(&SymbolicLinkKeyName, L"\\");
406 RtlAppendUnicodeStringToString(&SymbolicLinkKeyName, &TempString);
407
408 ControlKeyName.Length = 0;
409 ControlKeyName.MaximumLength = SymbolicLinkKeyName.Length + Control.Length + sizeof(WCHAR);
410 ControlKeyName.Buffer = ExAllocatePool(PagedPool, ControlKeyName.MaximumLength);
411 ASSERT(ControlKeyName.Buffer != NULL);
412 RtlCopyUnicodeString(&ControlKeyName, &SymbolicLinkKeyName);
413 RtlAppendUnicodeStringToString(&ControlKeyName, &Control);
414
415 ExFreePool(bip);
416
417 InitializeObjectAttributes(
418 &ObjectAttributes,
419 &SymbolicLinkKeyName,
420 OBJ_CASE_INSENSITIVE,
421 NULL,
422 NULL);
423
424 Status = ZwOpenKey(
425 &SymbolicLinkKey,
426 KEY_READ,
427 &ObjectAttributes);
428
429 if (!NT_SUCCESS(Status))
430 {
431 DPRINT("ZwOpenKey() Failed. (0x%X)\n", Status);
432 ExFreePool(fip);
433 ExFreePool(bfip);
434 if (SymLinkList != NULL)
435 ExFreePool(SymLinkList);
436 RtlFreeUnicodeString(&SymbolicLinkKeyName);
437 RtlFreeUnicodeString(&SubKeyName);
438 RtlFreeUnicodeString(&BaseKeyName);
439 ZwClose(SubKey);
440 ZwClose(InterfaceKey);
441 return Status;
442 }
443
444 Status = ZwQueryValueKey(
445 SymbolicLinkKey,
446 &SymbolicLink,
447 KeyValuePartialInformation,
448 NULL,
449 0,
450 &Size);
451
452 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
453 continue;
454
455 if (Status != STATUS_BUFFER_TOO_SMALL)
456 {
457 DPRINT("ZwQueryValueKey() Failed.(0x%X)\n", Status);
458 ExFreePool(fip);
459 ExFreePool(bfip);
460 if (SymLinkList != NULL)
461 ExFreePool(SymLinkList);
462 RtlFreeUnicodeString(&SymbolicLinkKeyName);
463 RtlFreeUnicodeString(&SubKeyName);
464 RtlFreeUnicodeString(&BaseKeyName);
465 ZwClose(SymbolicLinkKey);
466 ZwClose(SubKey);
467 ZwClose(InterfaceKey);
468 return Status;
469 }
470
471 vpip = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool(PagedPool, Size);
472 ASSERT(vpip != NULL);
473
474 Status = ZwQueryValueKey(
475 SymbolicLinkKey,
476 &SymbolicLink,
477 KeyValuePartialInformation,
478 vpip,
479 Size,
480 &Size);
481
482 if (!NT_SUCCESS(Status))
483 {
484 DPRINT("ZwQueryValueKey() Failed.(0x%X)\n", Status);
485 ExFreePool(fip);
486 ExFreePool(bfip);
487 ExFreePool(vpip);
488 if (SymLinkList != NULL)
489 ExFreePool(SymLinkList);
490 RtlFreeUnicodeString(&SymbolicLinkKeyName);
491 RtlFreeUnicodeString(&SubKeyName);
492 RtlFreeUnicodeString(&BaseKeyName);
493 ZwClose(SymbolicLinkKey);
494 ZwClose(SubKey);
495 ZwClose(InterfaceKey);
496 return Status;
497 }
498
499 Status = RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, ControlKeyName.Buffer);
500
501 if (NT_SUCCESS(Status))
502 {
503 /* Put the name in the string here */
504 if (SymLinkList == NULL)
505 {
506 SymLinkListSize = vpip->DataLength;
507 SymLinkList = ExAllocatePool(PagedPool, SymLinkListSize + sizeof(WCHAR));
508 ASSERT(SymLinkList != NULL);
509 RtlCopyMemory(SymLinkList, vpip->Data, vpip->DataLength);
510 SymLinkList[vpip->DataLength / sizeof(WCHAR)] = 0;
511 SymLinkList[1] = '?';
512 }
513 else
514 {
515 PWCHAR OldSymLinkList;
516 ULONG OldSymLinkListSize;
517 PWCHAR SymLinkListPtr;
518
519 OldSymLinkList = SymLinkList;
520 OldSymLinkListSize = SymLinkListSize;
521 SymLinkListSize += vpip->DataLength;
522 SymLinkList = ExAllocatePool(PagedPool, SymLinkListSize + sizeof(WCHAR));
523 ASSERT(SymLinkList != NULL);
524 RtlCopyMemory(SymLinkList, OldSymLinkList, OldSymLinkListSize);
525 ExFreePool(OldSymLinkList);
526 SymLinkListPtr = SymLinkList + (OldSymLinkListSize / sizeof(WCHAR));
527 RtlCopyMemory(SymLinkListPtr, vpip->Data, vpip->DataLength);
528 SymLinkListPtr[vpip->DataLength / sizeof(WCHAR)] = 0;
529 SymLinkListPtr[1] = '?';
530 }
531 }
532
533 RtlFreeUnicodeString(&SymbolicLinkKeyName);
534 RtlFreeUnicodeString(&ControlKeyName);
535 ZwClose(SymbolicLinkKey);
536 }
537
538 ExFreePool(vpip);
539 RtlFreeUnicodeString(&SubKeyName);
540 ZwClose(SubKey);
541 }
542
543 if (SymLinkList != NULL)
544 {
545 SymLinkList[SymLinkListSize / sizeof(WCHAR)] = 0;
546 }
547 else
548 {
549 SymLinkList = ExAllocatePool(PagedPool, 2 * sizeof(WCHAR));
550 SymLinkList[0] = 0;
551 }
552
553 *SymbolicLinkList = SymLinkList;
554
555 RtlFreeUnicodeString(&BaseKeyName);
556 ZwClose(InterfaceKey);
557 ExFreePool(bfip);
558 ExFreePool(fip);
559 }
560
561 return STATUS_SUCCESS;
562 }
563
564 /*
565 * @implemented
566 */
567
568 NTSTATUS STDCALL
569 IoRegisterDeviceInterface(
570 IN PDEVICE_OBJECT PhysicalDeviceObject,
571 IN CONST GUID *InterfaceClassGuid,
572 IN PUNICODE_STRING ReferenceString OPTIONAL,
573 OUT PUNICODE_STRING SymbolicLinkName)
574 {
575 PUNICODE_STRING InstancePath;
576 UNICODE_STRING GuidString;
577 UNICODE_STRING SubKeyName;
578 UNICODE_STRING InterfaceKeyName;
579 UNICODE_STRING BaseKeyName;
580 UCHAR PdoNameInfoBuffer[sizeof(OBJECT_NAME_INFORMATION) + (256 * sizeof(WCHAR))];
581 POBJECT_NAME_INFORMATION PdoNameInfo = (POBJECT_NAME_INFORMATION)PdoNameInfoBuffer;
582 UNICODE_STRING DeviceInstance = RTL_CONSTANT_STRING(L"DeviceInstance");
583 UNICODE_STRING SymbolicLink = RTL_CONSTANT_STRING(L"SymbolicLink");
584 HANDLE ClassKey;
585 HANDLE InterfaceKey;
586 HANDLE SubKey;
587 ULONG StartIndex;
588 OBJECT_ATTRIBUTES ObjectAttributes;
589 ULONG i;
590 NTSTATUS Status;
591
592 ASSERT_IRQL(PASSIVE_LEVEL);
593
594 if (!(PhysicalDeviceObject->Flags & DO_BUS_ENUMERATED_DEVICE))
595 {
596 DPRINT("PhysicalDeviceObject 0x%p is not a valid Pdo\n", PhysicalDeviceObject);
597 return STATUS_INVALID_PARAMETER_1;
598 }
599
600 Status = RtlStringFromGUID(InterfaceClassGuid, &GuidString);
601 if (!NT_SUCCESS(Status))
602 {
603 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status);
604 return Status;
605 }
606
607 /* Create Pdo name: \Device\xxxxxxxx (unnamed device) */
608 Status = ObQueryNameString(
609 PhysicalDeviceObject,
610 PdoNameInfo,
611 sizeof(PdoNameInfoBuffer),
612 &i);
613 if (!NT_SUCCESS(Status))
614 {
615 DPRINT("ObQueryNameString() failed with status 0x%08lx\n", Status);
616 return Status;
617 }
618 ASSERT(PdoNameInfo->Name.Length);
619
620 /* Create base key name for this interface: HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
621 ASSERT(PhysicalDeviceObject->DeviceObjectExtension->DeviceNode);
622 InstancePath = &PhysicalDeviceObject->DeviceObjectExtension->DeviceNode->InstancePath;
623 BaseKeyName.Length = wcslen(BaseKeyString) * sizeof(WCHAR);
624 BaseKeyName.MaximumLength = BaseKeyName.Length
625 + GuidString.Length;
626 BaseKeyName.Buffer = ExAllocatePool(
627 PagedPool,
628 BaseKeyName.MaximumLength);
629 if (!BaseKeyName.Buffer)
630 {
631 DPRINT("ExAllocatePool() failed\n");
632 return STATUS_INSUFFICIENT_RESOURCES;
633 }
634 wcscpy(BaseKeyName.Buffer, BaseKeyString);
635 RtlAppendUnicodeStringToString(&BaseKeyName, &GuidString);
636
637 /* Create BaseKeyName key in registry */
638 InitializeObjectAttributes(
639 &ObjectAttributes,
640 &BaseKeyName,
641 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE | OBJ_OPENIF,
642 NULL, /* RootDirectory */
643 NULL); /* SecurityDescriptor */
644
645 Status = ZwCreateKey(
646 &ClassKey,
647 KEY_WRITE,
648 &ObjectAttributes,
649 0, /* TileIndex */
650 NULL, /* Class */
651 REG_OPTION_VOLATILE,
652 NULL); /* Disposition */
653
654 if (!NT_SUCCESS(Status))
655 {
656 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
657 ExFreePool(BaseKeyName.Buffer);
658 return Status;
659 }
660
661 /* Create key name for this interface: ##?#ACPI#PNP0501#1#{GUID} */
662 InterfaceKeyName.Length = 0;
663 InterfaceKeyName.MaximumLength =
664 4 * sizeof(WCHAR) + /* 4 = size of ##?# */
665 InstancePath->Length +
666 sizeof(WCHAR) + /* 1 = size of # */
667 GuidString.Length;
668 InterfaceKeyName.Buffer = ExAllocatePool(
669 PagedPool,
670 InterfaceKeyName.MaximumLength);
671 if (!InterfaceKeyName.Buffer)
672 {
673 DPRINT("ExAllocatePool() failed\n");
674 return STATUS_INSUFFICIENT_RESOURCES;
675 }
676
677 RtlAppendUnicodeToString(&InterfaceKeyName, L"##?#");
678 StartIndex = InterfaceKeyName.Length / sizeof(WCHAR);
679 RtlAppendUnicodeStringToString(&InterfaceKeyName, InstancePath);
680 for (i = 0; i < InstancePath->Length / sizeof(WCHAR); i++)
681 {
682 if (InterfaceKeyName.Buffer[StartIndex + i] == '\\')
683 InterfaceKeyName.Buffer[StartIndex + i] = '#';
684 }
685 RtlAppendUnicodeToString(&InterfaceKeyName, L"#");
686 RtlAppendUnicodeStringToString(&InterfaceKeyName, &GuidString);
687
688 /* Create the interface key in registry */
689 InitializeObjectAttributes(
690 &ObjectAttributes,
691 &InterfaceKeyName,
692 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE | OBJ_OPENIF,
693 ClassKey,
694 NULL); /* SecurityDescriptor */
695
696 Status = ZwCreateKey(
697 &InterfaceKey,
698 KEY_WRITE,
699 &ObjectAttributes,
700 0, /* TileIndex */
701 NULL, /* Class */
702 REG_OPTION_VOLATILE,
703 NULL); /* Disposition */
704
705 if (!NT_SUCCESS(Status))
706 {
707 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
708 ZwClose(ClassKey);
709 ExFreePool(BaseKeyName.Buffer);
710 return Status;
711 }
712
713 /* Write DeviceInstance entry. Value is InstancePath */
714 Status = ZwSetValueKey(
715 InterfaceKey,
716 &DeviceInstance,
717 0, /* TileIndex */
718 REG_SZ,
719 InstancePath->Buffer,
720 InstancePath->Length);
721 if (!NT_SUCCESS(Status))
722 {
723 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
724 ZwClose(InterfaceKey);
725 ZwClose(ClassKey);
726 ExFreePool(InterfaceKeyName.Buffer);
727 ExFreePool(BaseKeyName.Buffer);
728 return Status;
729 }
730
731 /* Create subkey. Name is #ReferenceString */
732 SubKeyName.Length = 0;
733 SubKeyName.MaximumLength = sizeof(WCHAR);
734 if (ReferenceString && ReferenceString->Length)
735 SubKeyName.MaximumLength += ReferenceString->Length;
736 SubKeyName.Buffer = ExAllocatePool(
737 PagedPool,
738 SubKeyName.MaximumLength);
739 if (!SubKeyName.Buffer)
740 {
741 DPRINT("ExAllocatePool() failed\n");
742 ZwClose(InterfaceKey);
743 ZwClose(ClassKey);
744 ExFreePool(InterfaceKeyName.Buffer);
745 ExFreePool(BaseKeyName.Buffer);
746 return STATUS_INSUFFICIENT_RESOURCES;
747 }
748 RtlAppendUnicodeToString(&SubKeyName, L"#");
749 if (ReferenceString && ReferenceString->Length)
750 RtlAppendUnicodeStringToString(&SubKeyName, ReferenceString);
751
752 /* Create SubKeyName key in registry */
753 InitializeObjectAttributes(
754 &ObjectAttributes,
755 &SubKeyName,
756 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
757 InterfaceKey, /* RootDirectory */
758 NULL); /* SecurityDescriptor */
759
760 Status = ZwCreateKey(
761 &SubKey,
762 KEY_WRITE,
763 &ObjectAttributes,
764 0, /* TileIndex */
765 NULL, /* Class */
766 REG_OPTION_VOLATILE,
767 NULL); /* Disposition */
768
769 if (!NT_SUCCESS(Status))
770 {
771 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
772 ZwClose(InterfaceKey);
773 ZwClose(ClassKey);
774 ExFreePool(InterfaceKeyName.Buffer);
775 ExFreePool(BaseKeyName.Buffer);
776 return Status;
777 }
778
779 /* Create symbolic link name: \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
780 SymbolicLinkName->Length = 0;
781 SymbolicLinkName->MaximumLength = SymbolicLinkName->Length
782 + 4 * sizeof(WCHAR) /* 4 = size of \??\ */
783 + InstancePath->Length
784 + sizeof(WCHAR) /* 1 = size of # */
785 + GuidString.Length
786 + sizeof(WCHAR); /* final NULL */
787 if (ReferenceString && ReferenceString->Length)
788 SymbolicLinkName->MaximumLength += sizeof(WCHAR) + ReferenceString->Length;
789 SymbolicLinkName->Buffer = ExAllocatePool(
790 PagedPool,
791 SymbolicLinkName->MaximumLength);
792 if (!SymbolicLinkName->Buffer)
793 {
794 DPRINT("ExAllocatePool() failed\n");
795 ZwClose(SubKey);
796 ZwClose(InterfaceKey);
797 ZwClose(ClassKey);
798 ExFreePool(InterfaceKeyName.Buffer);
799 ExFreePool(SubKeyName.Buffer);
800 ExFreePool(BaseKeyName.Buffer);
801 return STATUS_INSUFFICIENT_RESOURCES;
802 }
803 RtlAppendUnicodeToString(SymbolicLinkName, L"\\??\\");
804 StartIndex = SymbolicLinkName->Length / sizeof(WCHAR);
805 RtlAppendUnicodeStringToString(SymbolicLinkName, InstancePath);
806 for (i = 0; i < InstancePath->Length / sizeof(WCHAR); i++)
807 {
808 if (SymbolicLinkName->Buffer[StartIndex + i] == '\\')
809 SymbolicLinkName->Buffer[StartIndex + i] = '#';
810 }
811 RtlAppendUnicodeToString(SymbolicLinkName, L"#");
812 RtlAppendUnicodeStringToString(SymbolicLinkName, &GuidString);
813 if (ReferenceString && ReferenceString->Length)
814 {
815 RtlAppendUnicodeToString(SymbolicLinkName, L"\\");
816 RtlAppendUnicodeStringToString(SymbolicLinkName, ReferenceString);
817 }
818 SymbolicLinkName->Buffer[SymbolicLinkName->Length] = '\0';
819
820 /* Create symbolic link */
821 DPRINT("IoRegisterDeviceInterface(): creating symbolic link %wZ -> %wZ\n", SymbolicLinkName, &PdoNameInfo->Name);
822 Status = IoCreateSymbolicLink(SymbolicLinkName, &PdoNameInfo->Name);
823 if (!NT_SUCCESS(Status))
824 {
825 DPRINT("IoCreateSymbolicLink() failed with status 0x%08lx\n", Status);
826 ZwClose(SubKey);
827 ZwClose(InterfaceKey);
828 ZwClose(ClassKey);
829 ExFreePool(SubKeyName.Buffer);
830 ExFreePool(InterfaceKeyName.Buffer);
831 ExFreePool(BaseKeyName.Buffer);
832 ExFreePool(SymbolicLinkName->Buffer);
833 return Status;
834 }
835
836 /* Write symbolic link name in registry */
837 SymbolicLinkName->Buffer[1] = '\\';
838 Status = ZwSetValueKey(
839 SubKey,
840 &SymbolicLink,
841 0, /* TileIndex */
842 REG_SZ,
843 SymbolicLinkName->Buffer,
844 SymbolicLinkName->Length);
845 if (!NT_SUCCESS(Status))
846 {
847 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
848 ExFreePool(SymbolicLinkName->Buffer);
849 }
850
851 /* Remove \\?\ at the start of symbolic link name */
852 SymbolicLinkName->Length -= 4 * sizeof(WCHAR);
853 SymbolicLinkName->MaximumLength -= 4 * sizeof(WCHAR);
854 RtlMoveMemory(
855 SymbolicLinkName->Buffer,
856 &SymbolicLinkName->Buffer[4],
857 SymbolicLinkName->Length);
858
859 ZwClose(SubKey);
860 ZwClose(InterfaceKey);
861 ZwClose(ClassKey);
862 ExFreePool(SubKeyName.Buffer);
863 ExFreePool(InterfaceKeyName.Buffer);
864 ExFreePool(BaseKeyName.Buffer);
865
866 return Status;
867 }
868
869 /*
870 * @implemented
871 */
872
873 NTSTATUS STDCALL
874 IoSetDeviceInterfaceState(
875 IN PUNICODE_STRING SymbolicLinkName,
876 IN BOOLEAN Enable)
877 {
878 PDEVICE_OBJECT PhysicalDeviceObject;
879 PFILE_OBJECT FileObject;
880 UNICODE_STRING ObjectName;
881 UNICODE_STRING GuidString;
882 PWCHAR StartPosition;
883 PWCHAR EndPosition;
884 NTSTATUS Status;
885
886 if (SymbolicLinkName == NULL)
887 return STATUS_INVALID_PARAMETER_1;
888
889 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName, Enable);
890
891 /* Symbolic link name is ACPI#PNP0501#1#{GUID}\ReferenceString */
892 /* Get GUID from SymbolicLinkName */
893 StartPosition = wcschr(SymbolicLinkName->Buffer, L'{');
894 EndPosition = wcschr(SymbolicLinkName->Buffer, L'}');
895 if (!StartPosition ||!EndPosition || StartPosition > EndPosition)
896 return STATUS_INVALID_PARAMETER_1;
897 GuidString.Buffer = StartPosition;
898 GuidString.MaximumLength = GuidString.Length = (ULONG_PTR)(EndPosition + 1) - (ULONG_PTR)StartPosition;
899
900 /* Create \??\SymbolicLinkName string */
901 ObjectName.Length = 0;
902 ObjectName.MaximumLength = SymbolicLinkName->Length + 4 * sizeof(WCHAR);
903 ObjectName.Buffer = ExAllocatePool(PagedPool, ObjectName.MaximumLength);
904 if (!ObjectName.Buffer)
905 return STATUS_INSUFFICIENT_RESOURCES;
906 RtlAppendUnicodeToString(&ObjectName, L"\\??\\");
907 RtlAppendUnicodeStringToString(&ObjectName, SymbolicLinkName);
908
909 /* Get pointer to the PDO */
910 Status = IoGetDeviceObjectPointer(&ObjectName,
911 0, /* DesiredAccess */
912 &FileObject,
913 &PhysicalDeviceObject);
914 if (!NT_SUCCESS(Status))
915 {
916 ExFreePool(ObjectName.Buffer);
917 return Status;
918 }
919
920 IopNotifyPlugPlayNotification(
921 PhysicalDeviceObject,
922 EventCategoryDeviceInterfaceChange,
923 Enable ? (LPGUID)&GUID_DEVICE_INTERFACE_ARRIVAL : (LPGUID)&GUID_DEVICE_INTERFACE_REMOVAL,
924 &GuidString,
925 (PVOID)SymbolicLinkName);
926
927 ObDereferenceObject(FileObject);
928 ExFreePool(ObjectName.Buffer);
929
930 return STATUS_SUCCESS;
931 }
932
933 /* EOF */