1 /*++
2 
3 Copyright (C) Microsoft Corporation, 1991 - 1999
4 
5 Module Name:
6 
7     classwmi.c
8 
9 Abstract:
10 
11     SCSI class driver routines
12 
13 Environment:
14 
15     kernel mode only
16 
17 Notes:
18 
19 
20 Revision History:
21 
22 --*/
23 
24 #ifndef __REACTOS__
25 #include "stddef.h"
26 #include "ntddk.h"
27 #include "scsi.h"
28 
29 #include "classpnp.h"
30 
31 #include "mountdev.h"
32 
33 #include <stdarg.h>
34 #endif
35 
36 #include "classp.h"
37 #include <wmistr.h>
38 #include <wmidata.h>
39 // #include <classlog.h> __REACTOS__
40 
41 #ifdef DEBUG_USE_WPP
42 #include "classwmi.tmh"
43 #endif
44 
45 #define TIME_STRING_LENGTH      25
46 
47 BOOLEAN
48 ClassFindGuid(
49     PGUIDREGINFO GuidList,
50     ULONG GuidCount,
51     LPGUID Guid,
52     PULONG GuidIndex
53     );
54 
55 NTSTATUS
56 ClassQueryInternalDataBlock(
57     IN PDEVICE_OBJECT DeviceObject,
58     IN PIRP Irp,
59     IN ULONG GuidIndex,
60     IN ULONG BufferAvail,
61     OUT PUCHAR Buffer
62     );
63 
64 PWCHAR
65 ConvertTickToDateTime(
66     IN LARGE_INTEGER Tick,
67     _Out_writes_(TIME_STRING_LENGTH) PWCHAR String
68     );
69 
70 BOOLEAN
71 ClassFindInternalGuid(
72     LPGUID Guid,
73     PULONG GuidIndex
74     );
75 
76 
77 //
78 // This is the name for the MOF resource that must be part of all drivers that
79 // register via this interface.
80 #define MOFRESOURCENAME L"MofResourceName"
81 
82 //
83 // What can be paged ???
84 #ifdef ALLOC_PRAGMA
85 #pragma alloc_text(PAGE, ClassSystemControl)
86 #pragma alloc_text(PAGE, ClassFindGuid)
87 #pragma alloc_text(PAGE, ClassFindInternalGuid)
88 #endif
89 
90 #ifdef __REACTOS__
91 #define MSStorageDriver_ClassErrorLogGuid {0xD5A9A51E, 0x03F9, 0x404d, {0x97, 0x22, 0x15, 0xF9, 0x0E, 0xB0, 0x70, 0x38}}
92 #endif
93 
94 //
95 // Define WMI interface to all class drivers
96 //
97 GUIDREGINFO wmiClassGuids[] =
98 {
99     {
100         MSStorageDriver_ClassErrorLogGuid, 1, 0
101     }
102 };
103 
104 #define MSStorageDriver_ClassErrorLogGuid_Index     0
105 #define NUM_CLASS_WMI_GUIDS     (sizeof(wmiClassGuids) / sizeof(GUIDREGINFO))
106 
107 
108 /*++////////////////////////////////////////////////////////////////////////////
109 
110 ClassFindGuid()
111 
112 Routine Description:
113 
114     This routine will search the list of guids registered and return
115     the index for the one that was registered.
116 
117 Arguments:
118 
119     GuidList is the list of guids to search
120 
121     GuidCount is the count of guids in the list
122 
123     Guid is the guid being searched for
124 
125     *GuidIndex returns the index to the guid
126 
127 Return Value:
128 
129     TRUE if guid is found else FALSE
130 
131 --*/
132 BOOLEAN
133 ClassFindGuid(
134     PGUIDREGINFO GuidList,
135     ULONG GuidCount,
136     LPGUID Guid,
137     PULONG GuidIndex
138     )
139 {
140     ULONG i;
141 
142     PAGED_CODE();
143 
144     for (i = 0; i < GuidCount; i++)
145     {
146         if (IsEqualGUID(Guid, &GuidList[i].Guid))
147         {
148             *GuidIndex = i;
149             return(TRUE);
150         }
151     }
152     return(FALSE);
153 } // end ClassFindGuid()
154 
155 /*++////////////////////////////////////////////////////////////////////////////
156 
157 ClassFindInternalGuid()
158 
159 Routine Description:
160 
161     This routine will search the list of internal guids registered and return
162     the index for the one that was registered.
163 
164 Arguments:
165 
166     Guid is the guid being searched for
167 
168     *GuidIndex returns the index to the guid
169 
170 Return Value:
171 
172     TRUE if guid is found else FALSE
173 
174 --*/
175 BOOLEAN
176 ClassFindInternalGuid(
177     LPGUID Guid,
178     PULONG GuidIndex
179     )
180 {
181     ULONG i;
182 
183     PAGED_CODE();
184 
185     for (i = 0; i < NUM_CLASS_WMI_GUIDS; i++)
186     {
187         if (IsEqualGUID(Guid, &wmiClassGuids[i].Guid))
188         {
189             *GuidIndex = i;
190             return(TRUE);
191         }
192     }
193 
194     return(FALSE);
195 } // end ClassFindGuid()
196 
197 /*++////////////////////////////////////////////////////////////////////////////
198 
199 ClassSystemControl()
200 
201 Routine Description:
202 
203     Dispatch routine for IRP_MJ_SYSTEM_CONTROL. This routine will process
204     all wmi requests received, forwarding them if they are not for this
205     driver or determining if the guid is valid and if so passing it to
206     the driver specific function for handing wmi requests.
207 
208 Arguments:
209 
210     DeviceObject - Supplies a pointer to the device object for this request.
211 
212     Irp - Supplies the Irp making the request.
213 
214 Return Value:
215 
216     status
217 
218 --*/
219 NTSTATUS
220 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
221 ClassSystemControl(
222     IN PDEVICE_OBJECT DeviceObject,
223     IN PIRP Irp
224     )
225 {
226     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
227     PCLASS_DRIVER_EXTENSION driverExtension;
228     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
229     ULONG isRemoved;
230     ULONG bufferSize;
231     PUCHAR buffer;
232     NTSTATUS status;
233     UCHAR minorFunction;
234     ULONG guidIndex = (ULONG)-1;
235     PCLASS_WMI_INFO classWmiInfo;
236     BOOLEAN isInternalGuid = FALSE;
237 
238     PAGED_CODE();
239 
240     //
241     // Make sure device has not been removed
242     isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
243     if(isRemoved)
244     {
245         Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
246         ClassReleaseRemoveLock(DeviceObject, Irp);
247         ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
248         return STATUS_DEVICE_DOES_NOT_EXIST;
249     }
250 
251     //
252     // If the irp is not a WMI irp or it is not targetted at this device
253     // or this device has not regstered with WMI then just forward it on.
254     minorFunction = irpStack->MinorFunction;
255     if ((minorFunction > IRP_MN_EXECUTE_METHOD) ||
256         (irpStack->Parameters.WMI.ProviderId != (ULONG_PTR)DeviceObject) ||
257         ((minorFunction != IRP_MN_REGINFO) &&
258          (commonExtension->GuidCount == 0)))
259     {
260         //
261         // CONSIDER: Do I need to hang onto lock until IoCallDriver returns ?
262         IoSkipCurrentIrpStackLocation(Irp);
263         ClassReleaseRemoveLock(DeviceObject, Irp);
264         return(IoCallDriver(commonExtension->LowerDeviceObject, Irp));
265     }
266 
267     buffer = (PUCHAR)irpStack->Parameters.WMI.Buffer;
268     bufferSize = irpStack->Parameters.WMI.BufferSize;
269 
270     if (minorFunction != IRP_MN_REGINFO)
271     {
272         //
273         // For all requests other than query registration info we are passed
274         // a guid. Determine if the guid is one that is supported by the
275         // device.
276         if (commonExtension->GuidRegInfo != NULL &&
277             ClassFindGuid(commonExtension->GuidRegInfo,
278                             commonExtension->GuidCount,
279                             (LPGUID)irpStack->Parameters.WMI.DataPath,
280                             &guidIndex))
281         {
282             isInternalGuid = FALSE;
283             status = STATUS_SUCCESS;
284         } else if (ClassFindInternalGuid((LPGUID)irpStack->Parameters.WMI.DataPath,
285                             &guidIndex)) {
286             isInternalGuid = TRUE;
287             status = STATUS_SUCCESS;
288         } else {
289             status = STATUS_WMI_GUID_NOT_FOUND;
290             TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "WMI GUID not found!"));
291         }
292 
293         TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_WMI, "WMI Find Guid = %x, isInternalGuid = %x", status, isInternalGuid));
294         if (NT_SUCCESS(status) &&
295             ((minorFunction == IRP_MN_QUERY_SINGLE_INSTANCE) ||
296              (minorFunction == IRP_MN_CHANGE_SINGLE_INSTANCE) ||
297              (minorFunction == IRP_MN_CHANGE_SINGLE_ITEM) ||
298              (minorFunction == IRP_MN_EXECUTE_METHOD)))
299         {
300             if ( (((PWNODE_HEADER)buffer)->Flags) &
301                                           WNODE_FLAG_STATIC_INSTANCE_NAMES)
302             {
303                 if ( ((PWNODE_SINGLE_INSTANCE)buffer)->InstanceIndex != 0 )
304                 {
305                     status = STATUS_WMI_INSTANCE_NOT_FOUND;
306                 }
307             } else {
308                 status = STATUS_WMI_INSTANCE_NOT_FOUND;
309                 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "WMI Instance not found!"));
310             }
311         }
312 
313         if (! NT_SUCCESS(status))
314         {
315             Irp->IoStatus.Status = status;
316             ClassReleaseRemoveLock(DeviceObject, Irp);
317             ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
318             return(status);
319         }
320     }
321 
322     driverExtension = commonExtension->DriverExtension;
323 
324     classWmiInfo = commonExtension->IsFdo ?
325                            &driverExtension->InitData.FdoData.ClassWmiInfo :
326                            &driverExtension->InitData.PdoData.ClassWmiInfo;
327     switch(minorFunction)
328     {
329         case IRP_MN_REGINFO:
330         {
331             ULONG guidCount;
332             PGUIDREGINFO guidList;
333             PWMIREGINFOW wmiRegInfo;
334             PWMIREGGUIDW wmiRegGuid;
335             PUNICODE_STRING regPath;
336             PWCHAR stringPtr;
337             ULONG retSize;
338             ULONG registryPathOffset;
339             ULONG mofResourceOffset;
340             ULONG bufferNeeded;
341             ULONG i;
342             ULONG_PTR nameInfo;
343             ULONG nameSize, nameOffset, nameFlags;
344             UNICODE_STRING name, mofName;
345             PCLASS_QUERY_WMI_REGINFO_EX ClassQueryWmiRegInfoEx;
346 
347             name.Buffer = NULL;
348             name.Length = 0;
349             name.MaximumLength = 0;
350             nameFlags = 0;
351 
352             ClassQueryWmiRegInfoEx = commonExtension->IsFdo ?
353                                driverExtension->ClassFdoQueryWmiRegInfoEx :
354                                driverExtension->ClassPdoQueryWmiRegInfoEx;
355 
356             if ((classWmiInfo->GuidRegInfo != NULL) &&
357                 (classWmiInfo->ClassQueryWmiRegInfo != NULL) &&
358                 (ClassQueryWmiRegInfoEx == NULL))
359             {
360                 status = classWmiInfo->ClassQueryWmiRegInfo(
361                                                         DeviceObject,
362                                                         &nameFlags,
363                                                         &name);
364 
365                 RtlInitUnicodeString(&mofName, MOFRESOURCENAME);
366 
367             } else if ((classWmiInfo->GuidRegInfo != NULL) && (ClassQueryWmiRegInfoEx != NULL)) {
368                 RtlInitUnicodeString(&mofName, L"");
369 
370                 status = (*ClassQueryWmiRegInfoEx)(
371                                                     DeviceObject,
372                                                     &nameFlags,
373                                                     &name,
374                                                     &mofName);
375             } else {
376                 RtlInitUnicodeString(&mofName, L"");
377                 nameFlags = WMIREG_FLAG_INSTANCE_PDO;
378                 status = STATUS_SUCCESS;
379             }
380 
381             if (NT_SUCCESS(status) &&
382                 (! (nameFlags &  WMIREG_FLAG_INSTANCE_PDO) &&
383                 (name.Buffer == NULL)))
384             {
385                 //
386                 // if PDO flag not specified then an instance name must be
387                 status = STATUS_INVALID_DEVICE_REQUEST;
388                 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "Invalid Device Request!"));
389             }
390 
391             if (NT_SUCCESS(status))
392             {
393                 guidList = classWmiInfo->GuidRegInfo;
394                 guidCount = (classWmiInfo->GuidRegInfo == NULL ? 0 : classWmiInfo->GuidCount) + NUM_CLASS_WMI_GUIDS;
395 
396                 nameOffset = sizeof(WMIREGINFO) +
397                                       guidCount * sizeof(WMIREGGUIDW);
398 
399                 if (nameFlags & WMIREG_FLAG_INSTANCE_PDO)
400                 {
401                     nameSize = 0;
402                     nameInfo = commonExtension->IsFdo ?
403                                    (ULONG_PTR)((PFUNCTIONAL_DEVICE_EXTENSION)commonExtension)->LowerPdo :
404                                    (ULONG_PTR)DeviceObject;
405                 } else {
406                     nameFlags |= WMIREG_FLAG_INSTANCE_LIST;
407                     nameSize = name.Length + sizeof(USHORT);
408                     nameInfo = nameOffset;
409                 }
410 
411                 mofResourceOffset = nameOffset + nameSize;
412 
413                 registryPathOffset = mofResourceOffset +
414                                   mofName.Length + sizeof(USHORT);
415 
416                 regPath = &driverExtension->RegistryPath;
417 
418                 bufferNeeded = registryPathOffset + regPath->Length;
419                 bufferNeeded += sizeof(USHORT);
420 
421                 if (bufferNeeded <= bufferSize)
422                 {
423                     retSize = bufferNeeded;
424 
425                     commonExtension->GuidCount = guidCount;
426                     commonExtension->GuidRegInfo = guidList;
427 
428                     wmiRegInfo = (PWMIREGINFO)buffer;
429                     wmiRegInfo->BufferSize = bufferNeeded;
430                     wmiRegInfo->NextWmiRegInfo = 0;
431                     wmiRegInfo->MofResourceName = mofResourceOffset;
432                     wmiRegInfo->RegistryPath = registryPathOffset;
433                     wmiRegInfo->GuidCount = guidCount;
434 
435                     for (i = 0; i < classWmiInfo->GuidCount; i++)
436                     {
437                         wmiRegGuid = &wmiRegInfo->WmiRegGuid[i];
438                         wmiRegGuid->Guid = guidList[i].Guid;
439                         wmiRegGuid->Flags = guidList[i].Flags | nameFlags;
440                         wmiRegGuid->InstanceInfo = nameInfo;
441                         wmiRegGuid->InstanceCount = 1;
442                     }
443                     for (i = 0; i < NUM_CLASS_WMI_GUIDS; i++)
444                     {
445                         wmiRegGuid = &wmiRegInfo->WmiRegGuid[i + classWmiInfo->GuidCount];
446                         wmiRegGuid->Guid = wmiClassGuids[i].Guid;
447                         wmiRegGuid->Flags = wmiClassGuids[i].Flags | nameFlags;
448                         wmiRegGuid->InstanceInfo = nameInfo;
449                         wmiRegGuid->InstanceCount = 1;
450                     }
451 
452                     if ( nameFlags &  WMIREG_FLAG_INSTANCE_LIST)
453                     {
454                         bufferNeeded = nameOffset + sizeof(WCHAR);
455                         bufferNeeded += name.Length;
456 
457                         if (bufferSize >= bufferNeeded){
458                             stringPtr = (PWCHAR)((PUCHAR)buffer + nameOffset);
459                             *stringPtr++ = name.Length;
460                             RtlCopyMemory(stringPtr, name.Buffer, name.Length);
461                         }
462                         else {
463                             NT_ASSERT(bufferSize >= bufferNeeded);
464                             status = STATUS_INVALID_BUFFER_SIZE;
465                         }
466                     }
467 
468                     bufferNeeded = mofResourceOffset + sizeof(WCHAR);
469                     bufferNeeded += mofName.Length;
470 
471                     if (bufferSize >= bufferNeeded){
472                         stringPtr = (PWCHAR)((PUCHAR)buffer + mofResourceOffset);
473                         *stringPtr++ = mofName.Length;
474                         RtlCopyMemory(stringPtr, mofName.Buffer, mofName.Length);
475                     }
476                     else {
477                         NT_ASSERT(bufferSize >= bufferNeeded);
478                         status = STATUS_INVALID_BUFFER_SIZE;
479                     }
480 
481                     bufferNeeded = registryPathOffset + sizeof(WCHAR);
482                     bufferNeeded += regPath->Length;
483 
484                     if (bufferSize >= bufferNeeded){
485                         stringPtr = (PWCHAR)((PUCHAR)buffer + registryPathOffset);
486                         *stringPtr++ = regPath->Length;
487                         RtlCopyMemory(stringPtr,
488                                   regPath->Buffer,
489                                   regPath->Length);
490                     }
491                     else {
492 
493                         NT_ASSERT(bufferSize >= bufferNeeded);
494                         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_WMI, "Invalid Buffer Size!"));
495                         status = STATUS_INVALID_BUFFER_SIZE;
496                     }
497 
498                 } else {
499                     *((PULONG)buffer) = bufferNeeded;
500                     retSize = sizeof(ULONG);
501                 }
502             } else {
503                 retSize = 0;
504             }
505 
506             FREE_POOL(name.Buffer);
507 
508             Irp->IoStatus.Status = status;
509             Irp->IoStatus.Information = retSize;
510             ClassReleaseRemoveLock(DeviceObject, Irp);
511             ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
512             return(status);
513         }
514 
515         case IRP_MN_QUERY_ALL_DATA:
516         {
517             PWNODE_ALL_DATA wnode;
518             ULONG bufferAvail;
519 
520             wnode = (PWNODE_ALL_DATA)buffer;
521 
522             if (bufferSize < sizeof(WNODE_ALL_DATA))
523             {
524                 bufferAvail = 0;
525             } else {
526                 bufferAvail = bufferSize - sizeof(WNODE_ALL_DATA);
527             }
528 
529             wnode->DataBlockOffset = sizeof(WNODE_ALL_DATA);
530 
531             NT_ASSERT(guidIndex != (ULONG)-1);
532             _Analysis_assume_(isInternalGuid);
533             if (isInternalGuid)
534             {
535                 status = ClassQueryInternalDataBlock(
536                                                 DeviceObject,
537                                                 Irp,
538                                                 guidIndex,
539                                                 bufferAvail,
540                                                 buffer + sizeof(WNODE_ALL_DATA));
541             } else {
542                 status = classWmiInfo->ClassQueryWmiDataBlock(
543                                                  DeviceObject,
544                                                  Irp,
545                                                  guidIndex,
546                                                  bufferAvail,
547                                                  buffer + sizeof(WNODE_ALL_DATA));
548             }
549             break;
550         }
551 
552         case IRP_MN_QUERY_SINGLE_INSTANCE:
553         {
554             PWNODE_SINGLE_INSTANCE wnode;
555             ULONG dataBlockOffset;
556 
557             wnode = (PWNODE_SINGLE_INSTANCE)buffer;
558 
559             dataBlockOffset = wnode->DataBlockOffset;
560 
561             NT_ASSERT(guidIndex != (ULONG)-1);
562             _Analysis_assume_(isInternalGuid);
563             if (isInternalGuid)
564             {
565                 status = ClassQueryInternalDataBlock(
566                                             DeviceObject,
567                                             Irp,
568                                             guidIndex,
569                                             bufferSize - dataBlockOffset,
570                                             (PUCHAR)wnode + dataBlockOffset);
571             } else {
572                 status = classWmiInfo->ClassQueryWmiDataBlock(
573                                               DeviceObject,
574                                               Irp,
575                                               guidIndex,
576                                               bufferSize - dataBlockOffset,
577                                               (PUCHAR)wnode + dataBlockOffset);
578             }
579             break;
580         }
581 
582         case IRP_MN_CHANGE_SINGLE_INSTANCE:
583         {
584             PWNODE_SINGLE_INSTANCE wnode;
585 
586             wnode = (PWNODE_SINGLE_INSTANCE)buffer;
587             _Analysis_assume_(isInternalGuid);
588             if (isInternalGuid)
589             {
590                 status = ClassWmiCompleteRequest(DeviceObject,
591                                                 Irp,
592                                                 STATUS_WMI_GUID_NOT_FOUND,
593                                                 0,
594                                                 IO_NO_INCREMENT);
595             } else {
596 
597                 NT_ASSERT(guidIndex != (ULONG)-1);
598 
599                 status = classWmiInfo->ClassSetWmiDataBlock(
600                                          DeviceObject,
601                                          Irp,
602                                          guidIndex,
603                                          wnode->SizeDataBlock,
604                                          (PUCHAR)wnode + wnode->DataBlockOffset);
605             }
606 
607             break;
608         }
609 
610         case IRP_MN_CHANGE_SINGLE_ITEM:
611         {
612             PWNODE_SINGLE_ITEM wnode;
613 
614             wnode = (PWNODE_SINGLE_ITEM)buffer;
615 
616             NT_ASSERT(guidIndex != (ULONG)-1);
617             _Analysis_assume_(isInternalGuid);
618             if (isInternalGuid)
619             {
620                 status = ClassWmiCompleteRequest(DeviceObject,
621                                                 Irp,
622                                                 STATUS_WMI_GUID_NOT_FOUND,
623                                                 0,
624                                                 IO_NO_INCREMENT);
625             } else {
626 
627                 NT_ASSERT(guidIndex != (ULONG)-1);
628 
629                 status = classWmiInfo->ClassSetWmiDataItem(
630                                          DeviceObject,
631                                          Irp,
632                                          guidIndex,
633                                          wnode->ItemId,
634                                          wnode->SizeDataItem,
635                                          (PUCHAR)wnode + wnode->DataBlockOffset);
636 
637             }
638 
639             break;
640         }
641 
642         case IRP_MN_EXECUTE_METHOD:
643         {
644             PWNODE_METHOD_ITEM wnode;
645 
646             wnode = (PWNODE_METHOD_ITEM)buffer;
647             _Analysis_assume_(isInternalGuid);
648             if (isInternalGuid)
649             {
650                 status = ClassWmiCompleteRequest(DeviceObject,
651                                                 Irp,
652                                                 STATUS_WMI_GUID_NOT_FOUND,
653                                                 0,
654                                                 IO_NO_INCREMENT);
655             } else {
656 
657                 NT_ASSERT(guidIndex != (ULONG)-1);
658 
659                 status = classWmiInfo->ClassExecuteWmiMethod(
660                                              DeviceObject,
661                                              Irp,
662                                              guidIndex,
663                                              wnode->MethodId,
664                                              wnode->SizeDataBlock,
665                                              bufferSize - wnode->DataBlockOffset,
666                                              buffer + wnode->DataBlockOffset);
667             }
668 
669             break;
670         }
671 
672         case IRP_MN_ENABLE_EVENTS:
673         {
674             _Analysis_assume_(isInternalGuid);
675             if (isInternalGuid)
676             {
677                 status = ClassWmiCompleteRequest(DeviceObject,
678                                                 Irp,
679                                                 STATUS_WMI_GUID_NOT_FOUND,
680                                                 0,
681                                                 IO_NO_INCREMENT);
682             } else {
683 
684                 NT_ASSERT(guidIndex != (ULONG)-1);
685 
686                 status = classWmiInfo->ClassWmiFunctionControl(
687                                                                DeviceObject,
688                                                                Irp,
689                                                                guidIndex,
690                                                                EventGeneration,
691                                                                TRUE);
692             }
693             break;
694         }
695 
696         case IRP_MN_DISABLE_EVENTS:
697         {
698             _Analysis_assume_(isInternalGuid);
699             if (isInternalGuid)
700             {
701                 status = ClassWmiCompleteRequest(DeviceObject,
702                                                 Irp,
703                                                 STATUS_WMI_GUID_NOT_FOUND,
704                                                 0,
705                                                 IO_NO_INCREMENT);
706             } else {
707 
708                 NT_ASSERT(guidIndex != (ULONG)-1);
709 
710                 status = classWmiInfo->ClassWmiFunctionControl(
711                                                                DeviceObject,
712                                                                Irp,
713                                                                guidIndex,
714                                                                EventGeneration,
715                                                                FALSE);
716             }
717             break;
718         }
719 
720         case IRP_MN_ENABLE_COLLECTION:
721         {
722             _Analysis_assume_(isInternalGuid);
723             if (isInternalGuid)
724             {
725                 status = ClassWmiCompleteRequest(DeviceObject,
726                                                 Irp,
727                                                 STATUS_WMI_GUID_NOT_FOUND,
728                                                 0,
729                                                 IO_NO_INCREMENT);
730             } else {
731 
732                 NT_ASSERT(guidIndex != (ULONG)-1);
733 
734                 status = classWmiInfo->ClassWmiFunctionControl(
735                                                              DeviceObject,
736                                                              Irp,
737                                                              guidIndex,
738                                                              DataBlockCollection,
739                                                              TRUE);
740             }
741             break;
742         }
743 
744         case IRP_MN_DISABLE_COLLECTION:
745         {
746             _Analysis_assume_(isInternalGuid);
747             if (isInternalGuid)
748             {
749                 status = ClassWmiCompleteRequest(DeviceObject,
750                                                 Irp,
751                                                 STATUS_WMI_GUID_NOT_FOUND,
752                                                 0,
753                                                 IO_NO_INCREMENT);
754             } else {
755 
756                 NT_ASSERT(guidIndex != (ULONG)-1);
757 
758                 status = classWmiInfo->ClassWmiFunctionControl(
759                                                              DeviceObject,
760                                                              Irp,
761                                                              guidIndex,
762                                                              DataBlockCollection,
763                                                              FALSE);
764             }
765 
766             break;
767         }
768 
769         default:
770         {
771             status = STATUS_INVALID_DEVICE_REQUEST;
772             break;
773         }
774 
775     }
776 
777     return(status);
778 } // end ClassSystemControl()
779 
780 
781 NTSTATUS
782 ClassQueryInternalDataBlock(
783     IN PDEVICE_OBJECT DeviceObject,
784     IN PIRP Irp,
785     IN ULONG GuidIndex,
786     IN ULONG BufferAvail,
787     OUT PUCHAR Buffer
788     )
789 /*++
790 
791 Routine Description:
792 
793     This routine allows querying for the contents of an internal WMI
794     data block. When the driver has finished filling the data block it
795     must call ClassWmiCompleteRequest to complete the irp.
796 
797 Arguments:
798 
799     DeviceObject is the device whose data block is being queried
800 
801     Irp is the Irp that makes this request
802 
803     GuidIndex is the index into the list of guids provided when the
804         device registered
805 
806     BufferAvail on has the maximum size available to write the data
807         block.
808 
809     Buffer on return is filled with the returned data block
810 
811 
812 Return Value:
813 
814     status
815 
816 --*/
817 {
818     NTSTATUS status;
819 #ifndef __REACTOS__ // WMI in not a thing on ReactOS yet
820     ULONG sizeNeeded = 0, i;
821     PFUNCTIONAL_DEVICE_EXTENSION fdoExt = DeviceObject->DeviceExtension;
822     if (GuidIndex == MSStorageDriver_ClassErrorLogGuid_Index) {
823 
824         //
825         // NOTE - ClassErrorLog is still using SCSI_REQUEST_BLOCK and will not be
826         // updated to support extended SRB until classpnp is updated to send >16
827         // byte CDBs. Extended SRBs will be translated to SCSI_REQUEST_BLOCK.
828         //
829         sizeNeeded = MSStorageDriver_ClassErrorLog_SIZE;
830         if (BufferAvail >= sizeNeeded) {
831             PMSStorageDriver_ClassErrorLog errorLog = (PMSStorageDriver_ClassErrorLog) Buffer;
832             PMSStorageDriver_ClassErrorLogEntry logEntry;
833             PMSStorageDriver_ScsiRequestBlock srbBlock;
834             PMSStorageDriver_SenseData senseData;
835             PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
836             PCLASS_ERROR_LOG_DATA fdoLogEntry;
837             PSCSI_REQUEST_BLOCK fdoSRBBlock;
838             PSENSE_DATA fdoSenseData;
839             errorLog->numEntries = NUM_ERROR_LOG_ENTRIES;
840             for (i = 0; i < NUM_ERROR_LOG_ENTRIES; i++) {
841                 fdoLogEntry = &fdoData->ErrorLogs[i];
842                 fdoSRBBlock = &fdoLogEntry->Srb;
843                 fdoSenseData = &fdoLogEntry->SenseData;
844                 logEntry = &errorLog->logEntries[i];
845                 srbBlock = &logEntry->srb;
846                 senseData = &logEntry->senseData;
847                 logEntry->tickCount = fdoLogEntry->TickCount.QuadPart;
848                 logEntry->portNumber = fdoLogEntry->PortNumber;
849                 logEntry->errorPaging = (fdoLogEntry->ErrorPaging == 0 ? FALSE : TRUE);
850                 logEntry->errorRetried = (fdoLogEntry->ErrorRetried == 0 ? FALSE : TRUE);
851                 logEntry->errorUnhandled = (fdoLogEntry->ErrorUnhandled == 0 ? FALSE : TRUE);
852                 logEntry->errorReserved = fdoLogEntry->ErrorReserved;
853                 RtlMoveMemory(logEntry->reserved, fdoLogEntry->Reserved, sizeof(logEntry->reserved));
854                 ConvertTickToDateTime(fdoLogEntry->TickCount, logEntry->eventTime);
855 
856                 srbBlock->length = fdoSRBBlock->Length;
857                 srbBlock->function = fdoSRBBlock->Function;
858                 srbBlock->srbStatus = fdoSRBBlock->SrbStatus;
859                 srbBlock->scsiStatus = fdoSRBBlock->ScsiStatus;
860                 srbBlock->pathID = fdoSRBBlock->PathId;
861                 srbBlock->targetID = fdoSRBBlock->TargetId;
862                 srbBlock->lun = fdoSRBBlock->Lun;
863                 srbBlock->queueTag = fdoSRBBlock->QueueTag;
864                 srbBlock->queueAction = fdoSRBBlock->QueueAction;
865                 srbBlock->cdbLength = fdoSRBBlock->CdbLength;
866                 srbBlock->senseInfoBufferLength = fdoSRBBlock->SenseInfoBufferLength;
867                 srbBlock->srbFlags = fdoSRBBlock->SrbFlags;
868                 srbBlock->dataTransferLength = fdoSRBBlock->DataTransferLength;
869                 srbBlock->timeOutValue = fdoSRBBlock->TimeOutValue;
870                 srbBlock->dataBuffer = (ULONGLONG) fdoSRBBlock->DataBuffer;
871                 srbBlock->senseInfoBuffer = (ULONGLONG) fdoSRBBlock->SenseInfoBuffer;
872                 srbBlock->nextSRB = (ULONGLONG) fdoSRBBlock->NextSrb;
873                 srbBlock->originalRequest = (ULONGLONG) fdoSRBBlock->OriginalRequest;
874                 srbBlock->srbExtension = (ULONGLONG) fdoSRBBlock->SrbExtension;
875                 srbBlock->internalStatus = fdoSRBBlock->InternalStatus;
876 #if defined(_WIN64)
877                 srbBlock->reserved = fdoSRBBlock->Reserved;
878 #else
879                 srbBlock->reserved = 0;
880 #endif
881                 RtlMoveMemory(srbBlock->cdb, fdoSRBBlock->Cdb, sizeof(srbBlock->cdb));
882 
883                 //
884                 // Note: Sense data has been converted into Fixed format before it was
885                 //       put in the log.  Therefore, no conversion is needed here.
886                 //
887                 senseData->errorCode = fdoSenseData->ErrorCode;
888                 senseData->valid = (fdoSenseData->Valid == 0 ? FALSE : TRUE);
889                 senseData->segmentNumber = fdoSenseData->SegmentNumber;
890                 senseData->senseKey = fdoSenseData->SenseKey;
891                 senseData->reserved = (fdoSenseData->Reserved == 0 ? FALSE : TRUE);
892                 senseData->incorrectLength = (fdoSenseData->IncorrectLength == 0 ? FALSE : TRUE);
893                 senseData->endOfMedia = (fdoSenseData->EndOfMedia == 0 ? FALSE : TRUE);
894                 senseData->fileMark = (fdoSenseData->FileMark == 0 ? FALSE : TRUE);
895                 RtlMoveMemory(senseData->information, fdoSenseData->Information, sizeof(senseData->information));
896                 senseData->additionalSenseLength = fdoSenseData->AdditionalSenseLength;
897                 RtlMoveMemory(senseData->commandSpecificInformation, fdoSenseData->CommandSpecificInformation, sizeof(senseData->commandSpecificInformation));
898                 senseData->additionalSenseCode = fdoSenseData->AdditionalSenseCode;
899                 senseData->additionalSenseCodeQualifier = fdoSenseData->AdditionalSenseCodeQualifier;
900                 senseData->fieldReplaceableUnitCode = fdoSenseData->FieldReplaceableUnitCode;
901                 RtlMoveMemory(senseData->senseKeySpecific, fdoSenseData->SenseKeySpecific, sizeof(senseData->senseKeySpecific));
902             }
903             status = STATUS_SUCCESS;
904         } else {
905             status = STATUS_BUFFER_TOO_SMALL;
906         }
907     } else if (GuidIndex > 0 && GuidIndex < NUM_CLASS_WMI_GUIDS) {
908         status = STATUS_WMI_INSTANCE_NOT_FOUND;
909     } else {
910         status = STATUS_WMI_GUID_NOT_FOUND;
911     }
912 #else
913     ULONG sizeNeeded = 0;
914     status = STATUS_WMI_GUID_NOT_FOUND;
915 #endif
916     status = ClassWmiCompleteRequest(DeviceObject,
917                                     Irp,
918                                     status,
919                                     sizeNeeded,
920                                     IO_NO_INCREMENT);
921     return status;
922 }
923 
924 PWCHAR
925 ConvertTickToDateTime(
926     IN LARGE_INTEGER Tick,
927     _Out_writes_(TIME_STRING_LENGTH) PWCHAR String
928     )
929 
930 /*++
931 
932 Routine Description:
933 
934     This routine converts a tick count to a datetime (MOF) data type
935 
936 Arguments:
937 
938     Tick - The tick count that needs to be converted
939     String - The buffer to hold the time string, must be able to hold WCHAR[25]
940 
941 Return Value:
942 
943     The time string
944 
945 --*/
946 
947 {
948     LARGE_INTEGER nowTick, nowTime, time;
949     ULONG maxInc = 0;
950     TIME_FIELDS timeFields = {0};
951     WCHAR outDateTime[TIME_STRING_LENGTH + 1];
952 
953     nowTick.QuadPart = 0;
954     nowTime.QuadPart = 0;
955     //
956     // Translate the tick count to a system time
957     //
958     KeQueryTickCount(&nowTick);
959     maxInc = KeQueryTimeIncrement();
960     KeQuerySystemTime(&nowTime);
961     time.QuadPart = nowTime.QuadPart - ((nowTick.QuadPart - Tick.QuadPart) * maxInc);
962 
963     RtlTimeToTimeFields(&time, &timeFields);
964 
965     //
966     // The buffer String is of size MAX_PATH. Use that to specify the buffer size.
967     //
968     //yyyymmddhhmmss.mmmmmmsutc
969     RtlStringCbPrintfW(outDateTime, sizeof(outDateTime), L"%04d%02d%02d%02d%02d%02d.%03d***+000", timeFields.Year, timeFields.Month, timeFields.Day, timeFields.Hour, timeFields.Minute, timeFields.Second, timeFields.Milliseconds);
970     RtlMoveMemory(String, outDateTime, sizeof(WCHAR) * TIME_STRING_LENGTH);
971     return  String;
972 }
973 
974 /*++////////////////////////////////////////////////////////////////////////////
975 
976 ClassWmiCompleteRequest()
977 
978 Routine Description:
979 
980 
981     This routine will do the work of completing a WMI irp. Depending upon the
982     the WMI request this routine will fixup the returned WNODE appropriately.
983 
984     NOTE: This routine assumes that the ClassRemoveLock is held and it will
985           release it.
986 
987 Arguments:
988 
989     DeviceObject - Supplies a pointer to the device object for this request.
990 
991     Irp - Supplies the Irp making the request.
992 
993     Status - Status to complete the irp with.  STATUS_BUFFER_TOO_SMALL is used
994         to indicate that more buffer is required for the data requested.
995 
996     BufferUsed - number of bytes of actual data to return (not including WMI
997         specific structures)
998 
999     PriorityBoost - priority boost to pass to ClassCompleteRequest
1000 
1001 Return Value:
1002 
1003     status
1004 
1005 --*/
1006 SCSIPORT_API
1007 NTSTATUS
1008 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
1009 ClassWmiCompleteRequest(
1010     _In_ PDEVICE_OBJECT DeviceObject,
1011     _Inout_ PIRP Irp,
1012     _In_ NTSTATUS Status,
1013     _In_ ULONG BufferUsed,
1014     _In_ CCHAR PriorityBoost
1015     )
1016 {
1017     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
1018     PUCHAR buffer;
1019     ULONG retSize;
1020     UCHAR minorFunction;
1021 
1022     minorFunction = irpStack->MinorFunction;
1023     buffer = (PUCHAR)irpStack->Parameters.WMI.Buffer;
1024 
1025     switch(minorFunction)
1026     {
1027         case IRP_MN_QUERY_ALL_DATA:
1028         {
1029             PWNODE_ALL_DATA wnode;
1030             PWNODE_TOO_SMALL wnodeTooSmall;
1031             ULONG bufferNeeded;
1032 
1033             wnode = (PWNODE_ALL_DATA)buffer;
1034 
1035             bufferNeeded = sizeof(WNODE_ALL_DATA) + BufferUsed;
1036 
1037             if (NT_SUCCESS(Status))
1038             {
1039                 retSize = bufferNeeded;
1040                 wnode->WnodeHeader.BufferSize = bufferNeeded;
1041                 KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
1042                 wnode->WnodeHeader.Flags |= WNODE_FLAG_FIXED_INSTANCE_SIZE;
1043                 wnode->FixedInstanceSize = BufferUsed;
1044                 wnode->InstanceCount = 1;
1045 
1046             } else if (Status == STATUS_BUFFER_TOO_SMALL) {
1047                 wnodeTooSmall = (PWNODE_TOO_SMALL)wnode;
1048 
1049                 wnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
1050                 wnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
1051                 wnodeTooSmall->SizeNeeded = sizeof(WNODE_ALL_DATA) + BufferUsed;
1052                 retSize = sizeof(WNODE_TOO_SMALL);
1053                 Status = STATUS_SUCCESS;
1054             } else {
1055                 retSize = 0;
1056             }
1057             break;
1058         }
1059 
1060         case IRP_MN_QUERY_SINGLE_INSTANCE:
1061         {
1062             PWNODE_SINGLE_INSTANCE wnode;
1063             PWNODE_TOO_SMALL wnodeTooSmall;
1064             ULONG bufferNeeded;
1065 
1066             wnode = (PWNODE_SINGLE_INSTANCE)buffer;
1067 
1068             bufferNeeded = wnode->DataBlockOffset + BufferUsed;
1069 
1070             if (NT_SUCCESS(Status))
1071             {
1072                 retSize = bufferNeeded;
1073                 wnode->WnodeHeader.BufferSize = bufferNeeded;
1074                 KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
1075                 wnode->SizeDataBlock = BufferUsed;
1076 
1077             } else if (Status == STATUS_BUFFER_TOO_SMALL) {
1078                 wnodeTooSmall = (PWNODE_TOO_SMALL)wnode;
1079 
1080                 wnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
1081                 wnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
1082                 wnodeTooSmall->SizeNeeded = bufferNeeded;
1083                 retSize = sizeof(WNODE_TOO_SMALL);
1084                 Status = STATUS_SUCCESS;
1085             } else {
1086                 retSize = 0;
1087             }
1088             break;
1089         }
1090 
1091         case IRP_MN_EXECUTE_METHOD:
1092         {
1093             PWNODE_METHOD_ITEM wnode;
1094             PWNODE_TOO_SMALL wnodeTooSmall;
1095             ULONG bufferNeeded;
1096 
1097             wnode = (PWNODE_METHOD_ITEM)buffer;
1098 
1099             bufferNeeded = wnode->DataBlockOffset + BufferUsed;
1100 
1101             if (NT_SUCCESS(Status))
1102             {
1103                 retSize = bufferNeeded;
1104                 wnode->WnodeHeader.BufferSize = bufferNeeded;
1105                 KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
1106                 wnode->SizeDataBlock = BufferUsed;
1107 
1108             } else if (Status == STATUS_BUFFER_TOO_SMALL) {
1109                 wnodeTooSmall = (PWNODE_TOO_SMALL)wnode;
1110 
1111                 wnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
1112                 wnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
1113                 wnodeTooSmall->SizeNeeded = bufferNeeded;
1114                 retSize = sizeof(WNODE_TOO_SMALL);
1115                 Status = STATUS_SUCCESS;
1116             } else {
1117                 retSize = 0;
1118             }
1119             break;
1120         }
1121 
1122         default:
1123         {
1124             //
1125             // All other requests don't return any data
1126             retSize = 0;
1127             break;
1128         }
1129 
1130     }
1131 
1132     Irp->IoStatus.Status = Status;
1133     Irp->IoStatus.Information = retSize;
1134     ClassReleaseRemoveLock(DeviceObject, Irp);
1135     ClassCompleteRequest(DeviceObject, Irp, PriorityBoost);
1136     return(Status);
1137 } // end ClassWmiCompleteRequest()
1138 
1139 /*++////////////////////////////////////////////////////////////////////////////
1140 
1141 ClassWmiFireEvent()
1142 
1143 Routine Description:
1144 
1145     This routine will fire a WMI event using the data buffer passed. This
1146     routine may be called at or below DPC level
1147 
1148 Arguments:
1149 
1150     DeviceObject - Supplies a pointer to the device object for this event
1151 
1152     Guid is pointer to the GUID that represents the event
1153 
1154     InstanceIndex is the index of the instance of the event
1155 
1156     EventDataSize is the number of bytes of data that is being fired with
1157        with the event
1158 
1159     EventData is the data that is fired with the events. This may be NULL
1160         if there is no data associated with the event
1161 
1162 
1163 Return Value:
1164 
1165     status
1166 
1167 --*/
1168 _IRQL_requires_max_(DISPATCH_LEVEL)
1169 NTSTATUS
1170 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
1171 ClassWmiFireEvent(
1172     _In_ PDEVICE_OBJECT DeviceObject,
1173     _In_ LPGUID Guid,
1174     _In_ ULONG InstanceIndex,
1175     _In_ ULONG EventDataSize,
1176     _In_reads_bytes_(EventDataSize) PVOID EventData
1177     )
1178 {
1179 
1180     ULONG sizeNeeded;
1181     PWNODE_SINGLE_INSTANCE event;
1182     NTSTATUS status;
1183 
1184     if (EventData == NULL)
1185     {
1186         EventDataSize = 0;
1187     }
1188 
1189     sizeNeeded = sizeof(WNODE_SINGLE_INSTANCE) + EventDataSize;
1190 
1191     event = ExAllocatePoolWithTag(NonPagedPoolNx, sizeNeeded, CLASS_TAG_WMI);
1192     if (event != NULL)
1193     {
1194         RtlZeroMemory(event, sizeNeeded);
1195         event->WnodeHeader.Guid = *Guid;
1196         event->WnodeHeader.ProviderId = IoWMIDeviceObjectToProviderId(DeviceObject);
1197         event->WnodeHeader.BufferSize = sizeNeeded;
1198         event->WnodeHeader.Flags =  WNODE_FLAG_SINGLE_INSTANCE |
1199                                     WNODE_FLAG_EVENT_ITEM |
1200                                     WNODE_FLAG_STATIC_INSTANCE_NAMES;
1201         KeQuerySystemTime(&event->WnodeHeader.TimeStamp);
1202 
1203         event->InstanceIndex = InstanceIndex;
1204         event->SizeDataBlock = EventDataSize;
1205         event->DataBlockOffset = sizeof(WNODE_SINGLE_INSTANCE);
1206         if (EventData != NULL)
1207         {
1208             RtlCopyMemory( &event->VariableData, EventData, EventDataSize);
1209         }
1210 
1211         status = IoWMIWriteEvent(event);
1212         if (! NT_SUCCESS(status))
1213         {
1214             FREE_POOL(event);
1215         }
1216     } else {
1217         status = STATUS_INSUFFICIENT_RESOURCES;
1218     }
1219 
1220     return(status);
1221 } // end ClassWmiFireEvent()
1222