Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1865 lines
53 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. wmisamp.c
  5. Abstract:
  6. Sample device driver whose purpose is to show various mechanisms for
  7. using WMI in a kernel mode driver. Specific things shown are
  8. Events
  9. Event references
  10. Queries, Sets
  11. Methods
  12. Updating guid registration
  13. Environment:
  14. WDM, NT and Windows 98
  15. Revision History:
  16. --*/
  17. #include <WDM.H>
  18. #include "filter.h"
  19. #include <wmistr.h>
  20. #include <wmiguid.h>
  21. //
  22. // default Date/Time structure
  23. #define FilterDateTime L"19940525133015.000000-300"
  24. NTSTATUS
  25. FilterFunctionControl(
  26. IN PDEVICE_OBJECT DeviceObject,
  27. IN PIRP Irp,
  28. IN ULONG GuidIndex,
  29. IN WMIENABLEDISABLECONTROL Function,
  30. IN BOOLEAN Enable
  31. );
  32. NTSTATUS
  33. FilterExecuteWmiMethod(
  34. IN PDEVICE_OBJECT DeviceObject,
  35. IN PIRP Irp,
  36. IN ULONG GuidIndex,
  37. IN ULONG InstanceIndex,
  38. IN ULONG MethodId,
  39. IN ULONG InBufferSize,
  40. IN ULONG OutBufferSize,
  41. IN PUCHAR Buffer
  42. );
  43. NTSTATUS
  44. FilterSetWmiDataItem(
  45. IN PDEVICE_OBJECT DeviceObject,
  46. IN PIRP Irp,
  47. IN ULONG InstanceIndex,
  48. IN ULONG GuidIndex,
  49. IN ULONG DataItemId,
  50. IN ULONG BufferSize,
  51. IN PUCHAR Buffer
  52. );
  53. NTSTATUS
  54. FilterSetWmiDataBlock(
  55. IN PDEVICE_OBJECT DeviceObject,
  56. IN PIRP Irp,
  57. IN ULONG GuidIndex,
  58. IN ULONG InstanceIndex,
  59. IN ULONG BufferSize,
  60. IN PUCHAR Buffer
  61. );
  62. NTSTATUS
  63. FilterQueryWmiDataBlock(
  64. IN PDEVICE_OBJECT DeviceObject,
  65. IN PIRP Irp,
  66. IN ULONG GuidIndex,
  67. IN ULONG InstanceIndex,
  68. IN ULONG InstanceCount,
  69. IN OUT PULONG InstanceLengthArray,
  70. IN ULONG BufferAvail,
  71. OUT PUCHAR Buffer
  72. );
  73. NTSTATUS
  74. FilterQueryWmiRegInfo(
  75. IN PDEVICE_OBJECT DeviceObject,
  76. OUT ULONG *RegFlags,
  77. OUT PUNICODE_STRING InstanceName,
  78. OUT PUNICODE_STRING *RegistryPath,
  79. OUT PUNICODE_STRING MofResourceName,
  80. OUT PDEVICE_OBJECT *Pdo
  81. );
  82. void FilterSetEc1(
  83. struct DEVICE_EXTENSION * devExt,
  84. PUCHAR Buffer,
  85. ULONG Length,
  86. ULONG Index
  87. );
  88. void FilterSetEc2(
  89. struct DEVICE_EXTENSION * devExt,
  90. PUCHAR Buffer,
  91. ULONG Length,
  92. ULONG Index
  93. );
  94. #ifdef ALLOC_PRAGMA
  95. #pragma alloc_text(PAGE,FilterQueryWmiRegInfo)
  96. #pragma alloc_text(PAGE,FilterQueryWmiDataBlock)
  97. #pragma alloc_text(PAGE,FilterSetWmiDataBlock)
  98. #pragma alloc_text(PAGE,FilterSetWmiDataItem)
  99. #pragma alloc_text(PAGE,FilterExecuteWmiMethod)
  100. #pragma alloc_text(PAGE,FilterFunctionControl)
  101. #endif
  102. #ifdef USE_BINARY_MOF_QUERY
  103. //
  104. // MOF data can be reported by a device driver via a resource attached to
  105. // the device drivers image file or in response to a query on the binary
  106. // mof data guid. Here we define global variables containing the binary mof
  107. // data to return in response to a binary mof guid query. Note that this
  108. // data is defined to be in a PAGED data segment since it does not need to
  109. // be in nonpaged memory. Note that instead of a single large mof file
  110. // we could have broken it into multiple individual files. Each file would
  111. // have its own binary mof data buffer and get reported via a different
  112. // instance of the binary mof guid. By mixing and matching the different
  113. // sets of binary mof data buffers a "dynamic" composite mof would be created.
  114. #ifdef ALLOC_DATA_PRAGMA
  115. #pragma data_seg("PAGED")
  116. #endif
  117. UCHAR FilterBinaryMofData[] =
  118. {
  119. #include "filter.x"
  120. };
  121. #ifdef ALLOC_DATA_PRAGMA
  122. #pragma data_seg()
  123. #endif
  124. #endif
  125. //
  126. // Create data structures for identifying the guids and reporting them to
  127. // WMI. Since the WMILIB callbacks pass an index into the guid list we make
  128. // definitions for the various guids indicies.
  129. //
  130. #define FilterClass1 0
  131. #define FilterClass2 1
  132. #define FilterClass3 2
  133. #define FilterClass4 3
  134. #define FilterClass5 4
  135. #define FilterClass6 5
  136. #define FilterClass7 6
  137. #define FilterGetSetData 7
  138. #define FilterFireEvent 8
  139. #define FilterEventClass1 9
  140. #define FilterEventClass2 10
  141. #define FilterEventClass3 11
  142. #define FilterEventClass4 12
  143. #define FilterEventClass5 13
  144. #define FilterEventClass6 14
  145. #define FilterEventClass7 15
  146. #define FilterEventReferenceClass 16
  147. #define FilterIrpCount 17
  148. #define BinaryMofGuid 18
  149. GUID FilterClass1Guid = Vendor_SampleClass1Guid;
  150. GUID FilterClass2Guid = Vendor_SampleClass2Guid;
  151. GUID FilterClass3Guid = Vendor_SampleClass3Guid;
  152. GUID FilterClass4Guid = Vendor_SampleClass4Guid;
  153. GUID FilterClass5Guid = Vendor_SampleClass5Guid;
  154. GUID FilterClass6Guid = Vendor_SampleClass6Guid;
  155. GUID FilterClass7Guid = Vendor_SampleClass7Guid;
  156. GUID FilterGetSetDataGuid = Vendor_GetSetDataGuid;
  157. GUID FilterFireEventGuid = Vendor_FireEventGuid;
  158. GUID FilterEventClass1Guid = Vendor_EventClass1Guid;
  159. GUID FilterEventClass2Guid = Vendor_EventClass2Guid;
  160. GUID FilterEventClass3Guid = Vendor_EventClass3Guid;
  161. GUID FilterEventClass4Guid = Vendor_EventClass4Guid;
  162. GUID FilterEventClass5Guid = Vendor_EventClass5Guid;
  163. GUID FilterEventClass6Guid = Vendor_EventClass6Guid;
  164. GUID FilterEventClass7Guid = Vendor_EventClass7Guid;
  165. GUID FilterEventReferenceClassGuid = Vendor_EventReferenceClassGuid;
  166. GUID FilterIrpCountGuid = Vendor_IrpCounterGuid;
  167. GUID FilterBinaryMofGuid = BINARY_MOF_GUID;
  168. WMIGUIDREGINFO FilterGuidList[] =
  169. {
  170. {
  171. &FilterClass1Guid, // Guid
  172. 1, // # of instances in each device
  173. WMIREG_FLAG_EXPENSIVE // Flag as expensive to collect
  174. },
  175. {
  176. &FilterClass2Guid,
  177. 1,
  178. 0
  179. },
  180. {
  181. &FilterClass3Guid,
  182. 1,
  183. 0
  184. },
  185. {
  186. &FilterClass4Guid,
  187. 1,
  188. 0
  189. },
  190. {
  191. &FilterClass5Guid,
  192. 1,
  193. 0
  194. },
  195. {
  196. &FilterClass6Guid,
  197. 1,
  198. 0
  199. },
  200. {
  201. &FilterClass7Guid,
  202. 1,
  203. 0
  204. },
  205. {
  206. &FilterGetSetDataGuid,
  207. 1,
  208. 0
  209. },
  210. {
  211. &FilterFireEventGuid,
  212. 1,
  213. 0
  214. },
  215. {
  216. &FilterEventClass1Guid,
  217. 1,
  218. WMIREG_FLAG_EVENT_ONLY_GUID // Flag as an event
  219. },
  220. {
  221. &FilterEventClass2Guid,
  222. 1,
  223. WMIREG_FLAG_EVENT_ONLY_GUID
  224. },
  225. {
  226. &FilterEventClass3Guid,
  227. 1,
  228. WMIREG_FLAG_EVENT_ONLY_GUID
  229. },
  230. {
  231. &FilterEventClass4Guid,
  232. 1,
  233. WMIREG_FLAG_EVENT_ONLY_GUID
  234. },
  235. {
  236. &FilterEventClass5Guid,
  237. 1,
  238. WMIREG_FLAG_EVENT_ONLY_GUID
  239. },
  240. {
  241. &FilterEventClass6Guid,
  242. 1,
  243. WMIREG_FLAG_EVENT_ONLY_GUID
  244. },
  245. {
  246. &FilterEventClass7Guid,
  247. 1,
  248. WMIREG_FLAG_EVENT_ONLY_GUID
  249. },
  250. {
  251. &FilterEventReferenceClassGuid,
  252. 1,
  253. WMIREG_FLAG_EVENT_ONLY_GUID
  254. },
  255. {
  256. &FilterIrpCountGuid,
  257. 1,
  258. 0
  259. },
  260. {
  261. &FilterBinaryMofGuid,
  262. 1,
  263. #ifdef USE_BINARY_MOF_QUERY
  264. 0
  265. #else
  266. WMIREG_FLAG_REMOVE_GUID
  267. #endif
  268. }
  269. };
  270. #define FilterGuidCount (sizeof(FilterGuidList) / sizeof(WMIGUIDREGINFO))
  271. //
  272. // We need to hang onto the registry path passed to our driver entry so that
  273. // we can return it in the QueryWmiRegInfo callback.
  274. //
  275. UNICODE_STRING FilterRegistryPath;
  276. NTSTATUS VA_SystemControl(
  277. struct DEVICE_EXTENSION *devExt,
  278. PIRP irp,
  279. PBOOLEAN passIrpDown
  280. )
  281. /*++
  282. Routine Description:
  283. Dispatch routine for System Control IRPs (MajorFunction == IRP_MJ_SYSTEM_CONTROL)
  284. Arguments:
  285. devExt - device extension for targetted device object
  286. irp - Io Request Packet
  287. *passIrpDown - returns with whether to pass irp down stack
  288. Return Value:
  289. NT status code
  290. --*/
  291. {
  292. PWMILIB_CONTEXT wmilibContext;
  293. NTSTATUS status;
  294. SYSCTL_IRP_DISPOSITION disposition;
  295. InterlockedIncrement(&devExt->WmiIrpCount);
  296. wmilibContext = &devExt->WmiLib;
  297. //
  298. // Call Wmilib helper function to crack the irp. If this is a wmi irp
  299. // that is targetted for this device then WmiSystemControl will callback
  300. // at the appropriate callback routine.
  301. //
  302. status = WmiSystemControl(wmilibContext,
  303. devExt->filterDevObj,
  304. irp,
  305. &disposition);
  306. switch(disposition)
  307. {
  308. case IrpProcessed:
  309. {
  310. //
  311. // This irp has been processed and may be completed or pending.
  312. *passIrpDown = FALSE;
  313. break;
  314. }
  315. case IrpNotCompleted:
  316. {
  317. //
  318. // This irp has not been completed, but has been fully processed.
  319. // we will complete it now.
  320. *passIrpDown = FALSE;
  321. IoCompleteRequest(irp, IO_NO_INCREMENT);
  322. break;
  323. }
  324. case IrpForward:
  325. case IrpNotWmi:
  326. {
  327. //
  328. // This irp is either not a WMI irp or is a WMI irp targetted
  329. // at a device lower in the stack.
  330. *passIrpDown = TRUE;
  331. break;
  332. }
  333. default:
  334. {
  335. //
  336. // We really should never get here, but if we do just forward....
  337. ASSERT(FALSE);
  338. *passIrpDown = TRUE;
  339. break;
  340. }
  341. }
  342. return(status);
  343. }
  344. NTSTATUS
  345. FilterInitializeWmiDataBlocks(
  346. IN struct DEVICE_EXTENSION *devExt
  347. )
  348. /*++
  349. Routine Description:
  350. This routine is called to create a new instance of the device
  351. Arguments:
  352. devExt is device extension
  353. Return Value:
  354. --*/
  355. {
  356. PWMILIB_CONTEXT wmilibInfo;
  357. ULONG i;
  358. PEC1 Ec1;
  359. PEC2 Ec2;
  360. UCHAR Ec[sizeof(EC2)];
  361. //
  362. // Fill in the WMILIB_CONTEXT structure with a pointer to the
  363. // callback routines and a pointer to the list of guids
  364. // supported by the driver
  365. //
  366. wmilibInfo = &devExt->WmiLib;
  367. wmilibInfo->GuidCount = FilterGuidCount;
  368. wmilibInfo->GuidList = FilterGuidList;
  369. wmilibInfo->QueryWmiRegInfo = FilterQueryWmiRegInfo;
  370. wmilibInfo->QueryWmiDataBlock = FilterQueryWmiDataBlock;
  371. wmilibInfo->SetWmiDataBlock = FilterSetWmiDataBlock;
  372. wmilibInfo->SetWmiDataItem = FilterSetWmiDataItem;
  373. wmilibInfo->ExecuteWmiMethod = FilterExecuteWmiMethod;
  374. wmilibInfo->WmiFunctionControl = FilterFunctionControl;
  375. //
  376. // Initialize the wmi data blocks with specific data
  377. //
  378. devExt->Ec1Count = 3;
  379. devExt->Ec2Count = 3;
  380. for (i = 0; i < 4; i++)
  381. {
  382. Ec1 = (PEC1)Ec;
  383. memset(Ec1, i, sizeof(EC1));
  384. memcpy(Ec1->Xdatetime, FilterDateTime, 25*sizeof(WCHAR));
  385. ASSERT(devExt->Ec1[i] == NULL);
  386. FilterSetEc1(devExt,
  387. (PUCHAR)Ec1,
  388. sizeof(EC1),
  389. i);
  390. Ec2 = (PEC2)Ec;
  391. memset(Ec2, i, sizeof(EC2));
  392. memcpy(Ec2->Xdatetime, FilterDateTime, 25*sizeof(WCHAR));
  393. ASSERT(devExt->Ec2[i] == NULL);
  394. FilterSetEc2(devExt,
  395. (PUCHAR)Ec2,
  396. sizeof(EC2),
  397. i);
  398. }
  399. return(STATUS_SUCCESS);
  400. }
  401. void FilterWmiCleanup(
  402. struct DEVICE_EXTENSION *devExt
  403. )
  404. {
  405. ULONG i;
  406. for (i = 0; i < 4; i++)
  407. {
  408. if (devExt->Ec1[i] != NULL)
  409. {
  410. ExFreePool(devExt->Ec1[i]);
  411. devExt->Ec1[i] = NULL;
  412. }
  413. if (devExt->Ec2[i] != NULL)
  414. {
  415. ExFreePool(devExt->Ec2[i]);
  416. devExt->Ec2[i] = NULL;
  417. }
  418. }
  419. }
  420. NTSTATUS
  421. FilterQueryWmiRegInfo(
  422. IN PDEVICE_OBJECT DeviceObject,
  423. OUT ULONG *RegFlags,
  424. OUT PUNICODE_STRING InstanceName,
  425. OUT PUNICODE_STRING *RegistryPath,
  426. OUT PUNICODE_STRING MofResourceName,
  427. OUT PDEVICE_OBJECT *Pdo
  428. )
  429. /*++
  430. Routine Description:
  431. This routine is a callback into the driver to retrieve the list of
  432. guids or data blocks that the driver wants to register with WMI. This
  433. routine may not pend or block. Driver should NOT call
  434. WmiCompleteRequest.
  435. Arguments:
  436. DeviceObject is the device whose registration info is being queried
  437. *RegFlags returns with a set of flags that describe the guids being
  438. registered for this device. If the device wants enable and disable
  439. collection callbacks before receiving queries for the registered
  440. guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the
  441. returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case
  442. the instance name is determined from the PDO associated with the
  443. device object. Note that the PDO must have an associated devnode. If
  444. WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique
  445. name for the device.
  446. InstanceName returns with the instance name for the guids if
  447. WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The
  448. caller will call ExFreePool with the buffer returned.
  449. *RegistryPath returns with the registry path of the driver. The caller
  450. does NOT free this buffer.
  451. *MofResourceName returns with the name of the MOF resource attached to
  452. the binary file. If the driver does not have a mof resource attached
  453. then this can be returned as NULL. The caller does NOT free this
  454. buffer.
  455. *Pdo returns with the device object for the PDO associated with this
  456. device if the WMIREG_FLAG_INSTANCE_PDO flag is retured in
  457. *RegFlags.
  458. Return Value:
  459. status
  460. --*/
  461. {
  462. struct DEVICE_EXTENSION * devExt = DeviceObject->DeviceExtension;
  463. //
  464. // Return the registry path for this driver. This is required so WMI
  465. // can find your driver image and can attribute any eventlog messages to
  466. // your driver.
  467. *RegistryPath = &FilterRegistryPath;
  468. #ifndef USE_BINARY_MOF_QUERY
  469. //
  470. // Return the name specified in the .rc file of the resource which
  471. // contains the bianry mof data. By default WMI will look for this
  472. // resource in the driver image (.sys) file, however if the value
  473. // MofImagePath is specified in the driver's registry key
  474. // then WMI will look for the resource in the file specified there.
  475. RtlInitUnicodeString(MofResourceName, L"MofResourceName");
  476. #endif
  477. //
  478. // Specify that the driver wants WMI to automatically generate instance
  479. // names for all of the data blocks based upon the device stack's
  480. // device instance id. Doing this is STRONGLY recommended since additional
  481. // information about the device would then be available to callers.
  482. *RegFlags = WMIREG_FLAG_INSTANCE_PDO;
  483. *Pdo = devExt->physicalDevObj;
  484. return(STATUS_SUCCESS);
  485. }
  486. ULONG FilterGetEc1(
  487. struct DEVICE_EXTENSION * devExt,
  488. PUCHAR Buffer,
  489. ULONG Index
  490. )
  491. {
  492. RtlCopyMemory(Buffer,
  493. devExt->Ec1[Index],
  494. devExt->Ec1Length[Index]);
  495. return(devExt->Ec1Length[Index]);
  496. }
  497. ULONG FilterGetActualEc1(
  498. struct DEVICE_EXTENSION * devExt,
  499. PUCHAR Buffer,
  500. ULONG Index
  501. )
  502. {
  503. RtlCopyMemory(Buffer,
  504. devExt->Ec1[Index],
  505. devExt->Ec1ActualLength[Index]);
  506. return(devExt->Ec1ActualLength[Index]);
  507. }
  508. void FilterSetEc1(
  509. struct DEVICE_EXTENSION * devExt,
  510. PUCHAR Buffer,
  511. ULONG Length,
  512. ULONG Index
  513. )
  514. {
  515. PEC1 New;
  516. ULONG NewLength;
  517. NewLength = (Length + 7) & ~7;
  518. New = ExAllocatePoolWithTag(PagedPool, NewLength, FILTER_TAG);
  519. if (New != NULL)
  520. {
  521. if (devExt->Ec1[Index] != NULL)
  522. {
  523. ExFreePool(devExt->Ec1[Index]);
  524. }
  525. devExt->Ec1[Index] = New;
  526. devExt->Ec1Length[Index] = NewLength;
  527. devExt->Ec1ActualLength[Index] = Length;
  528. RtlCopyMemory(New,
  529. Buffer,
  530. Length);
  531. }
  532. }
  533. ULONG FilterGetEc2(
  534. struct DEVICE_EXTENSION * devExt,
  535. PUCHAR Buffer,
  536. ULONG Index
  537. )
  538. {
  539. RtlCopyMemory(Buffer,
  540. devExt->Ec2[Index],
  541. devExt->Ec2Length[Index]);
  542. return(devExt->Ec2Length[Index]);
  543. }
  544. ULONG FilterGetActualEc2(
  545. struct DEVICE_EXTENSION * devExt,
  546. PUCHAR Buffer,
  547. ULONG Index
  548. )
  549. {
  550. RtlCopyMemory(Buffer,
  551. devExt->Ec2[Index],
  552. devExt->Ec2ActualLength[Index]);
  553. return(devExt->Ec2ActualLength[Index]);
  554. }
  555. void FilterSetEc2(
  556. struct DEVICE_EXTENSION * devExt,
  557. PUCHAR Buffer,
  558. ULONG Length,
  559. ULONG Index
  560. )
  561. {
  562. PEC2 New;
  563. ULONG NewLength;
  564. NewLength = (Length + 7) & ~7;
  565. New = ExAllocatePoolWithTag(PagedPool, NewLength, FILTER_TAG);
  566. if (New != NULL)
  567. {
  568. if (devExt->Ec2[Index] != NULL)
  569. {
  570. ExFreePool(devExt->Ec2[Index]);
  571. }
  572. devExt->Ec2[Index] = New;
  573. devExt->Ec2Length[Index] = NewLength;
  574. devExt->Ec2ActualLength[Index] = Length;
  575. RtlCopyMemory(New,
  576. Buffer,
  577. Length);
  578. }
  579. }
  580. NTSTATUS
  581. FilterQueryWmiDataBlock(
  582. IN PDEVICE_OBJECT DeviceObject,
  583. IN PIRP Irp,
  584. IN ULONG GuidIndex,
  585. IN ULONG InstanceIndex,
  586. IN ULONG InstanceCount,
  587. IN OUT PULONG InstanceLengthArray,
  588. IN ULONG BufferAvail,
  589. OUT PUCHAR Buffer
  590. )
  591. /*++
  592. Routine Description:
  593. This routine is a callback into the driver to query for the contents of
  594. all instances of a data block. If the driver can satisfy the query within
  595. the callback it should call WmiCompleteRequest to complete the irp before
  596. returning to the caller. Or the driver can return STATUS_PENDING if the
  597. irp cannot be completed immediately and must then call WmiCompleteRequest
  598. once the query is satisfied.
  599. Arguments:
  600. DeviceObject is the device whose data block is being queried
  601. Irp is the Irp that makes this request
  602. GuidIndex is the index into the list of guids provided when the
  603. device registered
  604. InstanceCount is the number of instnaces expected to be returned for
  605. the data block.
  606. InstanceLengthArray is a pointer to an array of ULONG that returns the
  607. lengths of each instance of the data block. If this is NULL then
  608. there was not enough space in the output buffer to fufill the request
  609. so the irp should be completed with the buffer needed.
  610. BufferAvail on entry has the maximum size available to write the data
  611. blocks.
  612. Buffer on return is filled with the returned data blocks. Note that each
  613. instance of the data block must be aligned on a 8 byte boundry.
  614. Return Value:
  615. status
  616. --*/
  617. {
  618. NTSTATUS status = STATUS_UNSUCCESSFUL;
  619. struct DEVICE_EXTENSION * devExt = DeviceObject->DeviceExtension;
  620. ULONG sizeNeeded;
  621. ULONG i;
  622. ULONG LastInstanceIndex;
  623. ULONG sizeUsed, vlSize;
  624. switch(GuidIndex)
  625. {
  626. case FilterEventReferenceClass:
  627. case FilterClass1:
  628. case FilterClass2:
  629. {
  630. // plain EC1
  631. sizeNeeded = devExt->Ec1Length[0];
  632. if (BufferAvail < sizeNeeded)
  633. {
  634. status = STATUS_BUFFER_TOO_SMALL;
  635. } else {
  636. *InstanceLengthArray = sizeNeeded;
  637. FilterGetEc1(devExt, Buffer, 0);
  638. status = STATUS_SUCCESS;
  639. }
  640. break;
  641. }
  642. case FilterClass3:
  643. {
  644. // fixed array of EC1
  645. sizeNeeded = 0;
  646. for (i = 0; i < 4; i++)
  647. {
  648. //
  649. // Each embedded class in an array of embedded classes
  650. // must be naturally aligned, and any padding between
  651. // the embedded classes must be included in the calculation
  652. // of the size of buffer needed to fufill the request.
  653. // Since the largest element in the embedded structure is
  654. // 8 bytes we pad the structure size out to 8 bytes.
  655. sizeNeeded += (devExt->Ec1Length[i] + 7) & ~7;
  656. }
  657. if (BufferAvail < sizeNeeded)
  658. {
  659. status = STATUS_BUFFER_TOO_SMALL;
  660. } else {
  661. *InstanceLengthArray = sizeNeeded;
  662. for (i = 0; i < 4; i++)
  663. {
  664. //
  665. // Copy each embedded class from storage into the
  666. // output buffer. Note that we make sure that each
  667. // embedded class begins on a natural alignment, in
  668. // this case an 8 byte boundry
  669. sizeUsed = FilterGetEc1(devExt, Buffer, i);
  670. Buffer += (sizeUsed+7) & ~7;
  671. }
  672. status = STATUS_SUCCESS;
  673. }
  674. break;
  675. }
  676. case FilterClass4:
  677. {
  678. // variable array of EC1
  679. //
  680. // Account for the size of the ULONG plus padding so that the
  681. // embedded classes start on an 8 byte boundry
  682. sizeNeeded = (sizeof(ULONG) + 7) & ~7;
  683. vlSize = devExt->Ec1Count;
  684. for (i = 0; i < vlSize; i++)
  685. {
  686. sizeNeeded += (devExt->Ec1Length[i] + 7) &~7;
  687. }
  688. if (BufferAvail < sizeNeeded)
  689. {
  690. status = STATUS_BUFFER_TOO_SMALL;
  691. } else {
  692. *InstanceLengthArray = sizeNeeded;
  693. *((PULONG)Buffer) = vlSize;
  694. Buffer += (sizeof(ULONG) + 7) & ~7;
  695. for (i = 0; i < vlSize; i++)
  696. {
  697. sizeUsed = FilterGetEc1(devExt, Buffer, i);
  698. Buffer += (sizeUsed+7) & ~7;
  699. }
  700. status = STATUS_SUCCESS;
  701. }
  702. break;
  703. }
  704. case FilterClass5:
  705. {
  706. // plain EC2
  707. sizeNeeded = devExt->Ec2Length[0];
  708. if (BufferAvail < sizeNeeded)
  709. {
  710. status = STATUS_BUFFER_TOO_SMALL;
  711. } else {
  712. *InstanceLengthArray = sizeNeeded;
  713. FilterGetEc2(devExt, Buffer, 0);
  714. status = STATUS_SUCCESS;
  715. }
  716. break;
  717. }
  718. case FilterClass6:
  719. {
  720. // fixed array EC2
  721. sizeNeeded = 0;
  722. for (i = 0; i < 4; i++)
  723. {
  724. sizeNeeded += (devExt->Ec2Length[i] + 7) & ~7;
  725. }
  726. if (BufferAvail < sizeNeeded)
  727. {
  728. status = STATUS_BUFFER_TOO_SMALL;
  729. } else {
  730. *InstanceLengthArray = sizeNeeded;
  731. for (i = 0; i < 4; i++)
  732. {
  733. sizeUsed = FilterGetEc2(devExt, Buffer, i);
  734. Buffer += (sizeUsed + 7) & ~7;
  735. }
  736. status = STATUS_SUCCESS;
  737. }
  738. break;
  739. }
  740. case FilterClass7:
  741. {
  742. // VL array EC2
  743. sizeNeeded = (sizeof(ULONG) + 7) & ~7;
  744. vlSize = devExt->Ec2Count;
  745. for (i = 0; i < vlSize; i++)
  746. {
  747. sizeNeeded += devExt->Ec2Length[i];
  748. }
  749. if (BufferAvail < sizeNeeded)
  750. {
  751. status = STATUS_BUFFER_TOO_SMALL;
  752. } else {
  753. *InstanceLengthArray = sizeNeeded;
  754. *((PULONG)Buffer) = vlSize;
  755. Buffer += (sizeof(ULONG)+7) & ~7;
  756. for (i = 0; i < vlSize; i++)
  757. {
  758. sizeUsed = FilterGetEc2(devExt, Buffer, i);
  759. Buffer += (sizeUsed + 7) & ~7;
  760. }
  761. status = STATUS_SUCCESS;
  762. }
  763. break;
  764. }
  765. case FilterIrpCount:
  766. {
  767. sizeNeeded = sizeof(Vendor_IrpCounter);
  768. if (BufferAvail >= sizeNeeded)
  769. {
  770. PVendor_IrpCounter IrpCounter = (PVendor_IrpCounter)Buffer;
  771. IrpCounter->TotalIrpCount = devExt->TotalIrpCount;
  772. IrpCounter->TotalIrpRate = devExt->TotalIrpCount;
  773. IrpCounter->WmiIrpCount = devExt->WmiIrpCount;
  774. *InstanceLengthArray = sizeNeeded;
  775. status = STATUS_SUCCESS;
  776. } else {
  777. status = STATUS_BUFFER_TOO_SMALL;
  778. }
  779. break;
  780. }
  781. case FilterFireEvent:
  782. case FilterGetSetData:
  783. {
  784. //
  785. // Method classes do not have any data within them, but must
  786. // repond successfully to queries so that WMI method operation
  787. // work successfully.
  788. sizeNeeded = sizeof(USHORT);
  789. if (BufferAvail < sizeNeeded)
  790. {
  791. status = STATUS_BUFFER_TOO_SMALL;
  792. } else {
  793. *InstanceLengthArray = sizeNeeded;
  794. status = STATUS_SUCCESS;
  795. }
  796. break;
  797. }
  798. #ifdef USE_BINARY_MOF_QUERY
  799. case BinaryMofGuid:
  800. {
  801. sizeNeeded = sizeof(FilterBinaryMofData);
  802. if (BufferAvail < sizeNeeded)
  803. {
  804. status = STATUS_BUFFER_TOO_SMALL;
  805. } else {
  806. RtlCopyMemory(Buffer, FilterBinaryMofData, sizeNeeded);
  807. *InstanceLengthArray = sizeNeeded;
  808. status = STATUS_SUCCESS;
  809. }
  810. break;
  811. }
  812. #endif
  813. default:
  814. {
  815. status = STATUS_WMI_GUID_NOT_FOUND;
  816. break;
  817. }
  818. }
  819. //
  820. // Complete the irp. If there was not enough room in the output buffer
  821. // then status is STATUS_BUFFER_TOO_SMALL and sizeNeeded has the size
  822. // needed to return all of the data. If there was enough room then
  823. // status is STATUS_SUCCESS and sizeNeeded is the actual number of bytes
  824. // being returned.
  825. status = WmiCompleteRequest(
  826. DeviceObject,
  827. Irp,
  828. status,
  829. sizeNeeded,
  830. IO_NO_INCREMENT);
  831. return(status);
  832. }
  833. //
  834. // Use this size when checking that the input data block is the correct
  835. // size. The compiler will add padding to the end of the structure if
  836. // you use sizeof(EC1), but WMI may pass a data block that is the exact
  837. // size of the data without padding.
  838. //
  839. #define EC1Size (FIELD_OFFSET(EC1, Xdatetime) + 25*sizeof(WCHAR))
  840. NTSTATUS FilterSetEc1Worker(
  841. struct DEVICE_EXTENSION * devExt,
  842. ULONG BufferSize,
  843. ULONG Index,
  844. PUCHAR Buffer,
  845. PULONG BufferUsed
  846. )
  847. {
  848. ULONG blockLen;
  849. NTSTATUS status;
  850. PEC1 Ec1;
  851. Ec1 = (PEC1)Buffer;
  852. if (BufferSize >= EC1Size)
  853. {
  854. blockLen = sizeof(EC1);
  855. FilterSetEc1(devExt,
  856. Buffer,
  857. blockLen,
  858. Index);
  859. *BufferUsed = (blockLen+7) & ~7;
  860. status = STATUS_SUCCESS;
  861. } else {
  862. status = STATUS_INVALID_PARAMETER_MIX;
  863. }
  864. return(status);
  865. }
  866. //
  867. // Use this size when checking that the input data block is the correct
  868. // size. The compiler will add padding to the end of the structure if
  869. // you use sizeof(EC2), but WMI may pass a data block that is the exact
  870. // size of the data without padding.
  871. //
  872. #define EC2Size (FIELD_OFFSET(EC2, Xdatetime) + 25*sizeof(WCHAR))
  873. NTSTATUS FilterSetEc2Worker(
  874. struct DEVICE_EXTENSION * devExt,
  875. ULONG BufferSize,
  876. ULONG Index,
  877. PUCHAR Buffer,
  878. PULONG BufferUsed
  879. )
  880. {
  881. ULONG blockLen;
  882. NTSTATUS status;
  883. PUSHORT wPtr;
  884. PEC2 Ec2;
  885. Ec2 = (PEC2)Buffer;
  886. if (BufferSize >= EC2Size)
  887. {
  888. blockLen = sizeof(EC2);
  889. FilterSetEc2(devExt,
  890. Buffer,
  891. blockLen,
  892. Index);
  893. *BufferUsed = (blockLen+7) & ~7;
  894. status = STATUS_SUCCESS;
  895. } else {
  896. status = STATUS_INVALID_PARAMETER_MIX;
  897. }
  898. return(status);
  899. }
  900. NTSTATUS
  901. FilterSetWmiDataBlock(
  902. IN PDEVICE_OBJECT DeviceObject,
  903. IN PIRP Irp,
  904. IN ULONG GuidIndex,
  905. IN ULONG InstanceIndex,
  906. IN ULONG BufferSize,
  907. IN PUCHAR Buffer
  908. )
  909. /*++
  910. Routine Description:
  911. This routine is a callback into the driver to change the contents of
  912. a data block. If the driver can change the data block within
  913. the callback it should call WmiCompleteRequest to complete the irp before
  914. returning to the caller. Or the driver can return STATUS_PENDING if the
  915. irp cannot be completed immediately and must then call WmiCompleteRequest
  916. once the data is changed.
  917. Arguments:
  918. DeviceObject is the device whose data block is being queried
  919. Irp is the Irp that makes this request
  920. GuidIndex is the index into the list of guids provided when the
  921. device registered
  922. BufferSize has the size of the data block passed
  923. Buffer has the new values for the data block
  924. Return Value:
  925. status
  926. --*/
  927. {
  928. NTSTATUS status;
  929. ULONG bufferUsed;
  930. struct DEVICE_EXTENSION * devExt = DeviceObject->DeviceExtension;
  931. ULONG i;
  932. ULONG vlSize;
  933. switch(GuidIndex)
  934. {
  935. case FilterClass1:
  936. case FilterClass2:
  937. {
  938. // plain EC1
  939. status = FilterSetEc1Worker(devExt,
  940. BufferSize,
  941. 0,
  942. Buffer,
  943. &bufferUsed);
  944. break;
  945. }
  946. case FilterClass3:
  947. {
  948. // fixed array of EC1
  949. for (i = 0, status = STATUS_SUCCESS;
  950. (i < 4) && NT_SUCCESS(status); i++)
  951. {
  952. status = FilterSetEc1Worker(devExt,
  953. BufferSize,
  954. i,
  955. Buffer,
  956. &bufferUsed);
  957. Buffer += bufferUsed;
  958. BufferSize -= bufferUsed;
  959. }
  960. break;
  961. }
  962. case FilterClass4:
  963. {
  964. // variable array of EC1
  965. if (BufferSize >= ((sizeof(ULONG) +7) & ~7))
  966. {
  967. vlSize = *((PULONG)Buffer);
  968. Buffer += ((sizeof(ULONG) +7) & ~7);
  969. if ((vlSize >= 1) && (vlSize <= 4))
  970. {
  971. for (i = 0, status = STATUS_SUCCESS;
  972. (i < vlSize) && NT_SUCCESS(status); i++)
  973. {
  974. status = FilterSetEc1Worker(devExt,
  975. BufferSize,
  976. i,
  977. Buffer,
  978. &bufferUsed);
  979. Buffer += bufferUsed;
  980. BufferSize -= bufferUsed;
  981. }
  982. if (NT_SUCCESS(status))
  983. {
  984. devExt->Ec1Count = vlSize;
  985. }
  986. } else {
  987. KdPrint(("SetEc1 only up to [4] allowed, not %d\n",
  988. vlSize));
  989. status = STATUS_INVALID_PARAMETER_MIX;
  990. }
  991. } else {
  992. KdPrint(("SetEc1 size too small\n"));
  993. status = STATUS_INVALID_PARAMETER_MIX;
  994. }
  995. break;
  996. }
  997. case FilterClass5:
  998. {
  999. // plain EC2
  1000. status = FilterSetEc2Worker(devExt,
  1001. BufferSize,
  1002. 0,
  1003. Buffer,
  1004. &bufferUsed);
  1005. break;
  1006. }
  1007. case FilterClass6:
  1008. {
  1009. // fixed array EC2
  1010. for (i = 0, status = STATUS_SUCCESS;
  1011. (i < 4) && NT_SUCCESS(status); i++)
  1012. {
  1013. status = FilterSetEc2Worker(devExt,
  1014. BufferSize,
  1015. i,
  1016. Buffer,
  1017. &bufferUsed);
  1018. Buffer += bufferUsed;
  1019. BufferSize -= bufferUsed;
  1020. }
  1021. break;
  1022. }
  1023. case FilterClass7:
  1024. {
  1025. // VL array EC2
  1026. if (BufferSize >= sizeof(ULONG))
  1027. {
  1028. vlSize = *((PULONG)Buffer);
  1029. Buffer += (sizeof(ULONG) +7) & ~7;
  1030. if ((vlSize >= 1) && (vlSize <= 4))
  1031. {
  1032. for (i = 0, status = STATUS_SUCCESS;
  1033. (i < vlSize) && NT_SUCCESS(status); i++)
  1034. {
  1035. status = FilterSetEc2Worker(devExt,
  1036. BufferSize,
  1037. i,
  1038. Buffer,
  1039. &bufferUsed);
  1040. Buffer += bufferUsed;
  1041. BufferSize -= bufferUsed;
  1042. }
  1043. if (NT_SUCCESS(status))
  1044. {
  1045. devExt->Ec1Count = vlSize;
  1046. }
  1047. } else {
  1048. KdPrint(("SetEc2 only up to [4] allowed, not %d\n",
  1049. vlSize));
  1050. status = STATUS_INVALID_PARAMETER_MIX;
  1051. }
  1052. } else {
  1053. KdPrint(("SetEc2 size too small\n"));
  1054. status = STATUS_INVALID_PARAMETER_MIX;
  1055. }
  1056. break;
  1057. }
  1058. default:
  1059. {
  1060. status = STATUS_WMI_GUID_NOT_FOUND;
  1061. break;
  1062. }
  1063. }
  1064. status = WmiCompleteRequest(
  1065. DeviceObject,
  1066. Irp,
  1067. status,
  1068. 0,
  1069. IO_NO_INCREMENT);
  1070. return(status);
  1071. }
  1072. NTSTATUS
  1073. FilterSetWmiDataItem(
  1074. IN PDEVICE_OBJECT DeviceObject,
  1075. IN PIRP Irp,
  1076. IN ULONG GuidIndex,
  1077. IN ULONG InstanceIndex,
  1078. IN ULONG DataItemId,
  1079. IN ULONG BufferSize,
  1080. IN PUCHAR Buffer
  1081. )
  1082. /*++
  1083. Routine Description:
  1084. This routine is a callback into the driver to change the contents of
  1085. a data block. If the driver can change the data block within
  1086. the callback it should call WmiCompleteRequest to complete the irp before
  1087. returning to the caller. Or the driver can return STATUS_PENDING if the
  1088. irp cannot be completed immediately and must then call WmiCompleteRequest
  1089. once the data is changed.
  1090. Arguments:
  1091. DeviceObject is the device whose data block is being changed
  1092. Irp is the Irp that makes this request
  1093. GuidIndex is the index into the list of guids provided when the
  1094. device registered
  1095. DataItemId has the id of the data item being set
  1096. BufferSize has the size of the data item passed
  1097. Buffer has the new values for the data item
  1098. Return Value:
  1099. status
  1100. --*/
  1101. {
  1102. NTSTATUS status;
  1103. struct DEVICE_EXTENSION * devExt = DeviceObject->DeviceExtension;
  1104. ULONG sizeNeeded = 0;
  1105. switch(GuidIndex)
  1106. {
  1107. case FilterClass1:
  1108. case FilterClass2:
  1109. case FilterClass3:
  1110. case FilterClass4:
  1111. case FilterClass5:
  1112. case FilterClass6:
  1113. case FilterClass7:
  1114. {
  1115. status = STATUS_INVALID_DEVICE_REQUEST;
  1116. break;
  1117. }
  1118. case FilterFireEvent:
  1119. case FilterGetSetData:
  1120. {
  1121. status = STATUS_WMI_READ_ONLY;
  1122. break;
  1123. }
  1124. default:
  1125. {
  1126. status = STATUS_WMI_GUID_NOT_FOUND;
  1127. break;
  1128. }
  1129. }
  1130. status = WmiCompleteRequest(
  1131. DeviceObject,
  1132. Irp,
  1133. status,
  1134. sizeNeeded,
  1135. IO_NO_INCREMENT);
  1136. return(status);
  1137. }
  1138. NTSTATUS FilterDoFireEvent(
  1139. struct DEVICE_EXTENSION * devExt,
  1140. ULONG WnodeType, // 0 - AllData, 1 - Single Instance
  1141. ULONG DataType, // 1,2,5,8 is guid id
  1142. ULONG BlockIndex // 0 - 3 is block index containing data
  1143. )
  1144. {
  1145. PWNODE_HEADER Wnode;
  1146. PWNODE_ALL_DATA WnodeAD;
  1147. PWNODE_SINGLE_INSTANCE WnodeSI;
  1148. PUCHAR dataPtr;
  1149. PUCHAR WnodeDataPtr;
  1150. ULONG dataSize;
  1151. LPGUID Guid;
  1152. NTSTATUS status;
  1153. ULONG sizeNeeded;
  1154. BOOLEAN isEventRef = FALSE;
  1155. if (BlockIndex > 3)
  1156. {
  1157. return(STATUS_INVALID_PARAMETER_MIX);
  1158. }
  1159. switch(DataType)
  1160. {
  1161. case 1:
  1162. {
  1163. // EC1
  1164. dataSize = devExt->Ec1Length[BlockIndex];
  1165. dataPtr = (PUCHAR)devExt->Ec1[BlockIndex];
  1166. Guid = &FilterEventClass1Guid;
  1167. break;
  1168. }
  1169. case 2:
  1170. {
  1171. // EC1 (embedded)
  1172. dataSize = devExt->Ec1Length[BlockIndex];
  1173. dataPtr = (PUCHAR)devExt->Ec1[BlockIndex];
  1174. Guid = &FilterEventClass2Guid;
  1175. break;
  1176. }
  1177. case 5:
  1178. {
  1179. // EC2 (embedded)
  1180. dataSize = devExt->Ec2Length[BlockIndex];
  1181. dataPtr = (PUCHAR)devExt->Ec2[BlockIndex];
  1182. Guid = &FilterEventClass5Guid;
  1183. break;
  1184. }
  1185. case 8:
  1186. {
  1187. isEventRef = TRUE;
  1188. Guid = &FilterEventReferenceClassGuid;
  1189. break;
  1190. }
  1191. default:
  1192. {
  1193. return(STATUS_INVALID_PARAMETER_MIX);
  1194. }
  1195. }
  1196. if (isEventRef) {
  1197. Wnode = ExAllocatePoolWithTag(NonPagedPool,
  1198. sizeof(WNODE_EVENT_REFERENCE),
  1199. FILTER_TAG);
  1200. if (Wnode != NULL)
  1201. {
  1202. PWNODE_EVENT_REFERENCE WnodeER;
  1203. sizeNeeded = sizeof(WNODE_EVENT_REFERENCE);
  1204. //
  1205. // Create a WNODE_EVENT_REFERENCE. First set the flags in the
  1206. // header to specify an event reference with static instance
  1207. // names.
  1208. //
  1209. Wnode->Flags = WNODE_FLAG_EVENT_REFERENCE |
  1210. WNODE_FLAG_STATIC_INSTANCE_NAMES;
  1211. WnodeER = (PWNODE_EVENT_REFERENCE)Wnode;
  1212. //
  1213. // The target guid is almose always the same guid as the event
  1214. // guid. To be most efficient we can set the size of the target
  1215. // data block, but in any case if it is too small then WMI will
  1216. // retry with a larger buffer.
  1217. //
  1218. WnodeER->TargetGuid = *Guid;
  1219. WnodeER->TargetDataBlockSize = 0;
  1220. //
  1221. // Since the target guid is a static instance name guid we fill
  1222. // in the instance index. If the target guid was dynamic instance
  1223. // names we would have to setup the instance name as text.
  1224. WnodeER->TargetInstanceIndex = 0;
  1225. dataPtr = NULL;
  1226. } else {
  1227. return(STATUS_INSUFFICIENT_RESOURCES);
  1228. }
  1229. } else if (WnodeType == 0)
  1230. {
  1231. sizeNeeded = FIELD_OFFSET(WNODE_ALL_DATA,
  1232. OffsetInstanceDataAndLength) + dataSize;
  1233. Wnode = ExAllocatePoolWithTag(NonPagedPool,
  1234. sizeNeeded,
  1235. FILTER_TAG);
  1236. if (Wnode == NULL)
  1237. {
  1238. return(STATUS_INSUFFICIENT_RESOURCES);
  1239. }
  1240. Wnode->Flags = WNODE_FLAG_ALL_DATA |
  1241. WNODE_FLAG_FIXED_INSTANCE_SIZE |
  1242. WNODE_FLAG_EVENT_ITEM |
  1243. WNODE_FLAG_STATIC_INSTANCE_NAMES;
  1244. WnodeAD = (PWNODE_ALL_DATA)Wnode;
  1245. WnodeAD->DataBlockOffset = FIELD_OFFSET(WNODE_ALL_DATA,
  1246. OffsetInstanceDataAndLength);
  1247. WnodeAD->InstanceCount = 1;
  1248. WnodeAD->FixedInstanceSize = dataSize;
  1249. WnodeDataPtr = (PUCHAR)Wnode + WnodeAD->DataBlockOffset;
  1250. } else if (WnodeType == 1) {
  1251. sizeNeeded = FIELD_OFFSET(WNODE_SINGLE_INSTANCE,
  1252. VariableData) + dataSize;
  1253. Wnode = ExAllocatePoolWithTag(NonPagedPool,
  1254. sizeNeeded,
  1255. FILTER_TAG);
  1256. if (Wnode == NULL)
  1257. {
  1258. return(STATUS_INSUFFICIENT_RESOURCES);
  1259. }
  1260. Wnode->Flags = WNODE_FLAG_SINGLE_INSTANCE |
  1261. WNODE_FLAG_EVENT_ITEM |
  1262. WNODE_FLAG_STATIC_INSTANCE_NAMES;
  1263. WnodeSI = (PWNODE_SINGLE_INSTANCE)Wnode;
  1264. WnodeSI->DataBlockOffset = FIELD_OFFSET(WNODE_SINGLE_INSTANCE,
  1265. VariableData);
  1266. WnodeSI->InstanceIndex = 0;
  1267. WnodeSI->SizeDataBlock = dataSize;
  1268. WnodeDataPtr = (PUCHAR)Wnode + WnodeSI->DataBlockOffset;
  1269. } else {
  1270. return(STATUS_INVALID_PARAMETER_MIX);
  1271. }
  1272. Wnode->Guid = *Guid;
  1273. Wnode->ProviderId = IoWMIDeviceObjectToProviderId(devExt->filterDevObj);
  1274. Wnode->BufferSize = sizeNeeded;
  1275. KeQuerySystemTime(&Wnode->TimeStamp);
  1276. if (dataPtr != NULL)
  1277. {
  1278. RtlCopyMemory(WnodeDataPtr, dataPtr, dataSize);
  1279. }
  1280. status = IoWMIWriteEvent(Wnode);
  1281. //
  1282. // If IoWMIWriteEvent succeeds then WMI will free the event buffer. If
  1283. // it fails then the caller frees the event buffer.
  1284. //
  1285. if (! NT_SUCCESS(status))
  1286. {
  1287. ExFreePool(Wnode);
  1288. }
  1289. return(status);
  1290. }
  1291. NTSTATUS
  1292. FilterExecuteWmiMethod(
  1293. IN PDEVICE_OBJECT DeviceObject,
  1294. IN PIRP Irp,
  1295. IN ULONG GuidIndex,
  1296. IN ULONG InstanceIndex,
  1297. IN ULONG MethodId,
  1298. IN ULONG InBufferSize,
  1299. IN ULONG OutBufferSize,
  1300. IN PUCHAR Buffer
  1301. )
  1302. /*++
  1303. Routine Description:
  1304. This routine is a callback into the driver to execute a method. If
  1305. the driver can complete the method within the callback it should
  1306. call WmiCompleteRequest to complete the irp before returning to the
  1307. caller. Or the driver can return STATUS_PENDING if the irp cannot be
  1308. completed immediately and must then call WmiCompleteRequest once the
  1309. data is changed.
  1310. Arguments:
  1311. DeviceObject is the device whose method is being executed
  1312. Irp is the Irp that makes this request
  1313. GuidIndex is the index into the list of guids provided when the
  1314. device registered
  1315. MethodId has the id of the method being called
  1316. InBufferSize has the size of the data block passed in as the input to
  1317. the method.
  1318. OutBufferSize on entry has the maximum size available to write the
  1319. returned data block.
  1320. Buffer is filled with the input buffer on entry and returns with
  1321. the output data block
  1322. Return Value:
  1323. status
  1324. --*/
  1325. {
  1326. ULONG sizeNeeded = 0;
  1327. NTSTATUS status;
  1328. struct DEVICE_EXTENSION * devExt = DeviceObject->DeviceExtension;
  1329. ULONG bufferUsed;
  1330. ULONG blockIndex;
  1331. ULONG UlongPadSize = (sizeof(ULONG) + 7) & ~7;
  1332. if (GuidIndex == FilterGetSetData)
  1333. {
  1334. switch(MethodId)
  1335. {
  1336. case SetEC1:
  1337. case SetEC1AsEc:
  1338. {
  1339. // SetEc1
  1340. if (InBufferSize < UlongPadSize)
  1341. {
  1342. status = STATUS_INVALID_PARAMETER_MIX;
  1343. sizeNeeded = 0;
  1344. break;
  1345. } else {
  1346. blockIndex = *((PULONG)Buffer);
  1347. if (blockIndex > 3)
  1348. {
  1349. status = STATUS_INVALID_PARAMETER_MIX;
  1350. break;
  1351. }
  1352. Buffer += UlongPadSize;
  1353. InBufferSize -= UlongPadSize;
  1354. }
  1355. status = FilterSetEc1Worker(devExt,
  1356. InBufferSize,
  1357. blockIndex,
  1358. Buffer,
  1359. &bufferUsed);
  1360. sizeNeeded = 0;
  1361. break;
  1362. }
  1363. case SetEC2:
  1364. case SetEC2AsEc:
  1365. {
  1366. // SetEc2
  1367. if (InBufferSize < UlongPadSize)
  1368. {
  1369. status = STATUS_INVALID_PARAMETER_MIX;
  1370. sizeNeeded = 0;
  1371. break;
  1372. } else {
  1373. blockIndex = *((PULONG)Buffer);
  1374. if (blockIndex > 3)
  1375. {
  1376. status = STATUS_INVALID_PARAMETER_MIX;
  1377. break;
  1378. }
  1379. Buffer += UlongPadSize;
  1380. InBufferSize -= UlongPadSize;
  1381. }
  1382. status = FilterSetEc2Worker(devExt,
  1383. InBufferSize,
  1384. blockIndex,
  1385. Buffer,
  1386. &bufferUsed);
  1387. sizeNeeded = 0;
  1388. break;
  1389. }
  1390. case GetEC1:
  1391. case GetEC1AsEc:
  1392. {
  1393. // GetEc1
  1394. if (InBufferSize != sizeof(ULONG))
  1395. {
  1396. status = STATUS_INVALID_PARAMETER_MIX;
  1397. sizeNeeded = 0;
  1398. break;
  1399. } else {
  1400. blockIndex = *((PULONG)Buffer);
  1401. if (blockIndex > 3)
  1402. {
  1403. status = STATUS_INVALID_PARAMETER_MIX;
  1404. break;
  1405. }
  1406. }
  1407. sizeNeeded = devExt->Ec1ActualLength[blockIndex];
  1408. if (OutBufferSize < sizeNeeded)
  1409. {
  1410. status = STATUS_BUFFER_TOO_SMALL;
  1411. } else {
  1412. FilterGetActualEc1(devExt, Buffer, blockIndex);
  1413. status = STATUS_SUCCESS;
  1414. }
  1415. break;
  1416. }
  1417. case GetEC2:
  1418. case GetEC2AsEc:
  1419. {
  1420. // GetEc2
  1421. if (InBufferSize != sizeof(ULONG))
  1422. {
  1423. status = STATUS_INVALID_PARAMETER_MIX;
  1424. sizeNeeded = 0;
  1425. break;
  1426. } else {
  1427. blockIndex = *((PULONG)Buffer);
  1428. if (blockIndex > 3)
  1429. {
  1430. status = STATUS_INVALID_PARAMETER_MIX;
  1431. break;
  1432. }
  1433. }
  1434. sizeNeeded = devExt->Ec2ActualLength[blockIndex];
  1435. if (OutBufferSize < sizeNeeded)
  1436. {
  1437. status = STATUS_BUFFER_TOO_SMALL;
  1438. } else {
  1439. FilterGetActualEc2(devExt, Buffer, blockIndex);
  1440. status = STATUS_SUCCESS;
  1441. }
  1442. break;
  1443. }
  1444. case DisableSampleClass7:
  1445. {
  1446. //
  1447. // Mark the guid for FilterClass7 as not available and then
  1448. // call WMI to inform it that the guid list has changed. WMI
  1449. // will send a new IRP_MN_REGINFO which would cause the
  1450. // QueryWmiRegInfo callback to be called and the new
  1451. // guid list would be returned and the registration updated.
  1452. FilterGuidList[FilterClass7].Flags |= WMIREG_FLAG_REMOVE_GUID;
  1453. status = IoWMIRegistrationControl(devExt->filterDevObj,
  1454. WMIREG_ACTION_UPDATE_GUIDS);
  1455. sizeNeeded = 0;
  1456. break;
  1457. }
  1458. case UnregisterFromWmi:
  1459. {
  1460. //
  1461. // We must wait until AFTER the irp is completed before
  1462. // calling IoWMIRegistrationControl to unregister. Since
  1463. // that api will block until all WMI irps sent to the
  1464. // device are completed we would become deadlocked.
  1465. IoWMIRegistrationControl(devExt->filterDevObj,
  1466. WMIREG_ACTION_BLOCK_IRPS);
  1467. status = WmiCompleteRequest(
  1468. DeviceObject,
  1469. Irp,
  1470. STATUS_SUCCESS,
  1471. 0,
  1472. IO_NO_INCREMENT);
  1473. IoWMIRegistrationControl(devExt->filterDevObj,
  1474. WMIREG_ACTION_DEREGISTER);
  1475. return(status);
  1476. }
  1477. case EnableSampleClass7:
  1478. {
  1479. //
  1480. // Mark the guid for FilterClass7 as available and then
  1481. // call WMI to inform it that the guid list has changed. WMI
  1482. // will send a new IRP_MN_REGINFO which would cause the
  1483. // QueryWmiRegInfo callback to be called and the new
  1484. // guid list would be returned and the registration updated.
  1485. FilterGuidList[FilterClass7].Flags &= ~WMIREG_FLAG_REMOVE_GUID;
  1486. status = IoWMIRegistrationControl(devExt->filterDevObj,
  1487. WMIREG_ACTION_UPDATE_GUIDS);
  1488. sizeNeeded = 0;
  1489. break;
  1490. }
  1491. default:
  1492. {
  1493. status = STATUS_WMI_ITEMID_NOT_FOUND;
  1494. }
  1495. }
  1496. } else if (GuidIndex == FilterFireEvent) {
  1497. if (MethodId == FireEvent)
  1498. {
  1499. if (InBufferSize == 3*sizeof(ULONG))
  1500. {
  1501. ULONG wnodeType;
  1502. ULONG dataType;
  1503. ULONG blockIndexA;
  1504. wnodeType = *(PULONG)Buffer;
  1505. Buffer += sizeof(ULONG);
  1506. dataType = *(PULONG)Buffer;
  1507. Buffer += sizeof(ULONG);
  1508. blockIndexA = *(PULONG)Buffer;
  1509. Buffer += sizeof(ULONG);
  1510. status = FilterDoFireEvent(devExt,
  1511. wnodeType,
  1512. dataType,
  1513. blockIndexA);
  1514. sizeNeeded = 0;
  1515. } else {
  1516. status = STATUS_INVALID_PARAMETER_MIX;
  1517. }
  1518. } else {
  1519. status = STATUS_WMI_ITEMID_NOT_FOUND;
  1520. }
  1521. } else {
  1522. status = STATUS_WMI_GUID_NOT_FOUND;
  1523. }
  1524. status = WmiCompleteRequest(
  1525. DeviceObject,
  1526. Irp,
  1527. status,
  1528. sizeNeeded,
  1529. IO_NO_INCREMENT);
  1530. return(status);
  1531. }
  1532. NTSTATUS
  1533. FilterFunctionControl(
  1534. IN PDEVICE_OBJECT DeviceObject,
  1535. IN PIRP Irp,
  1536. IN ULONG GuidIndex,
  1537. IN WMIENABLEDISABLECONTROL Function,
  1538. IN BOOLEAN Enable
  1539. )
  1540. /*++
  1541. Routine Description:
  1542. This routine is a callback into the driver to enabled or disable event
  1543. generation or data block collection. A device should only expect a
  1544. single enable when the first event or data consumer enables events or
  1545. data collection and a single disable when the last event or data
  1546. consumer disables events or data collection. Data blocks will only
  1547. receive collection enable/disable if they were registered as requiring
  1548. it. If the driver can complete enabling/disabling within the callback it
  1549. should call WmiCompleteRequest to complete the irp before returning to
  1550. the caller. Or the driver can return STATUS_PENDING if the irp cannot be
  1551. completed immediately and must then call WmiCompleteRequest once the
  1552. data is changed.
  1553. Arguments:
  1554. DeviceObject is the device object
  1555. GuidIndex is the index into the list of guids provided when the
  1556. device registered
  1557. Function specifies which functionality is being enabled or disabled
  1558. Enable is TRUE then the function is being enabled else disabled
  1559. Return Value:
  1560. status
  1561. --*/
  1562. {
  1563. NTSTATUS status;
  1564. status = WmiCompleteRequest(
  1565. DeviceObject,
  1566. Irp,
  1567. STATUS_SUCCESS,
  1568. 0,
  1569. IO_NO_INCREMENT);
  1570. return(status);
  1571. }
  1572.