Source code of Windows XP (NT5)
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.

1764 lines
53 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. DataProv.c
  5. Abstract:
  6. WMI internal data provider interface
  7. Author:
  8. AlanWar
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. --*/
  13. #include "wmikmp.h"
  14. #if defined(_IA64_)
  15. #ifdef MCE_INSERTION
  16. typedef struct _MCEQUERYINFO MCEQUERYINFO, *PMCEQUERYINFO;
  17. extern MCEQUERYINFO WmipMcaQueryInfo;
  18. extern MCEQUERYINFO WmipCmcQueryInfo;
  19. extern MCEQUERYINFO WmipCpeQueryInfo;
  20. NTSTATUS WmipInsertMce(
  21. PMCEQUERYINFO QueryInfo,
  22. ULONG LogSize,
  23. PUCHAR Log
  24. );
  25. #endif
  26. #endif
  27. NTSTATUS
  28. WmipQueryWmiDataBlock(
  29. IN PDEVICE_OBJECT DeviceObject,
  30. IN PIRP Irp,
  31. IN ULONG GuidIndex,
  32. IN ULONG InstanceIndex,
  33. IN ULONG InstanceCount,
  34. IN OUT PULONG InstanceLengthArray,
  35. IN ULONG BufferAvail,
  36. OUT PUCHAR Buffer
  37. );
  38. NTSTATUS
  39. WmipQueryWmiRegInfo(
  40. IN PDEVICE_OBJECT DeviceObject,
  41. OUT ULONG *RegFlags,
  42. OUT PUNICODE_STRING InstanceName,
  43. OUT PUNICODE_STRING *RegistryPath
  44. );
  45. NTSTATUS WmipSetWmiDataBlock(
  46. PDEVICE_OBJECT DeviceObject,
  47. PIRP Irp,
  48. ULONG GuidIndex,
  49. ULONG InstanceIndex,
  50. ULONG BufferSize,
  51. PUCHAR Buffer
  52. );
  53. NTSTATUS
  54. WmipExecuteWmiMethod (
  55. IN PDEVICE_OBJECT DeviceObject,
  56. IN PIRP Irp,
  57. IN ULONG GuidIndex,
  58. IN ULONG InstanceIndex,
  59. IN ULONG MethodId,
  60. IN ULONG InBufferSize,
  61. IN ULONG OutBufferSize,
  62. IN OUT PUCHAR Buffer
  63. );
  64. BOOLEAN
  65. WmipFindGuid(
  66. IN PGUIDREGINFO GuidList,
  67. IN ULONG GuidCount,
  68. IN LPGUID Guid,
  69. OUT PULONG GuidIndex,
  70. OUT PULONG InstanceCount
  71. );
  72. NTSTATUS
  73. IoWMICompleteRequest(
  74. IN PWMILIB_INFO WmiLibInfo,
  75. IN PDEVICE_OBJECT DeviceObject,
  76. IN PIRP Irp,
  77. IN NTSTATUS Status,
  78. IN ULONG BufferUsed,
  79. IN CCHAR PriorityBoost
  80. );
  81. NTSTATUS
  82. IoWMISystemControl(
  83. IN PWMILIB_INFO WmiLibInfo,
  84. IN PDEVICE_OBJECT DeviceObject,
  85. IN PIRP Irp
  86. );
  87. #ifdef ALLOC_DATA_PRAGMA
  88. #pragma const_seg("PAGECONST")
  89. #endif
  90. #ifdef GENERATE_MCA
  91. #define GenerateMCEGuid { 0x3001bce4, 0xd9b6, 0x4167, { 0xb5, 0xe1, 0x39, 0xa7, 0x28, 0x59, 0xe2, 0x67 } }
  92. GUID WmipGenerateMCEGuid = GenerateMCEGuid;
  93. #endif
  94. const GUIDREGINFO WmipGuidList[] =
  95. {
  96. //
  97. // This is the pnp id guid which is registered by wmi into other device
  98. // objects' registration info. And requests to the innocent devices
  99. // are hijacked by wmi so that wmi can complete the request for it. We
  100. // have the WMIREG_FLAG_REMOVE_GUID set so that the guid is not registered
  101. // for the wmi device which does not support it.
  102. {
  103. DATA_PROVIDER_PNPID_GUID,
  104. 0,
  105. WMIREG_FLAG_REMOVE_GUID
  106. },
  107. {
  108. DATA_PROVIDER_PNPID_INSTANCE_NAMES_GUID,
  109. 0,
  110. WMIREG_FLAG_REMOVE_GUID
  111. },
  112. {
  113. MSAcpiInfoGuid,
  114. 1,
  115. 0
  116. },
  117. #if defined(_AMD64_) || defined(_IA64_) || defined(i386) || defined(MEMPHIS)
  118. {
  119. SMBIOS_DATA_GUID,
  120. 1,
  121. 0
  122. },
  123. {
  124. SYSID_UUID_DATA_GUID,
  125. 1,
  126. 0
  127. },
  128. {
  129. SYSID_1394_DATA_GUID,
  130. 1,
  131. 0
  132. },
  133. {
  134. MSSmBios_SMBiosEventlogGuid,
  135. 1,
  136. 0
  137. },
  138. #endif
  139. #if defined(_IA64_)
  140. {
  141. MSMCAInfo_RawMCADataGuid,
  142. 1,
  143. 0
  144. },
  145. #ifdef CPE_CONTROL
  146. {
  147. MSMCAInfo_CPEControlGuid,
  148. 1,
  149. 0
  150. },
  151. #endif
  152. #ifdef GENERATE_MCA
  153. {
  154. GenerateMCEGuid,
  155. 1,
  156. 0
  157. },
  158. #endif
  159. {
  160. MSMCAInfo_RawMCAEventGuid,
  161. 1,
  162. WMIREG_FLAG_EVENT_ONLY_GUID
  163. },
  164. {
  165. MSMCAInfo_RawCMCEventGuid,
  166. 1,
  167. WMIREG_FLAG_EVENT_ONLY_GUID
  168. },
  169. {
  170. MSMCAInfo_RawCorrectedPlatformEventGuid,
  171. 1,
  172. WMIREG_FLAG_EVENT_ONLY_GUID
  173. },
  174. #endif
  175. };
  176. #define WmipGuidCount (sizeof(WmipGuidList) / sizeof(GUIDREGINFO))
  177. typedef enum
  178. {
  179. PnPIdGuidIndex = 0,
  180. PnPIdInstanceNamesGuidIndex,
  181. MSAcpiInfoGuidIndex,
  182. #if defined(_AMD64_) || defined(_IA64_) || defined(i386) || defined(MEMPHIS)
  183. SmbiosDataGuidIndex,
  184. SysidUuidGuidIndex,
  185. Sysid1394GuidIndex,
  186. SmbiosEventGuidIndex,
  187. #endif
  188. #if defined(_IA64_)
  189. MCARawDataGuidIndex,
  190. #ifdef CPE_CONTROL
  191. CPEControlGuidIndex,
  192. #endif
  193. #ifdef GENERATE_MCA
  194. GenerateMCEGuidIndex,
  195. #endif
  196. RawMCAEventGuidIndex,
  197. RawCMCEventGuidIndex,
  198. RawCPEEventGuidIndex,
  199. #endif
  200. } WMIGUIDINDEXES;
  201. const WMILIB_INFO WmipWmiLibInfo =
  202. {
  203. NULL,
  204. NULL,
  205. WmipGuidCount,
  206. (PGUIDREGINFO)WmipGuidList,
  207. WmipQueryWmiRegInfo,
  208. WmipQueryWmiDataBlock,
  209. #ifdef CPE_CONTROL
  210. WmipSetWmiDataBlock,
  211. #else
  212. NULL,
  213. #endif
  214. NULL,
  215. #ifdef GENERATE_MCA
  216. WmipExecuteWmiMethod,
  217. #else
  218. NULL,
  219. #endif
  220. NULL
  221. };
  222. #ifdef ALLOC_PRAGMA
  223. #pragma alloc_text(PAGE,WmipQueryWmiRegInfo)
  224. #pragma alloc_text(PAGE,WmipQueryWmiDataBlock)
  225. #pragma alloc_text(PAGE,WmipSetWmiDataBlock)
  226. #pragma alloc_text(PAGE,WmipExecuteWmiMethod)
  227. #pragma alloc_text(PAGE,WmipFindGuid)
  228. #pragma alloc_text(PAGE,IoWMISystemControl)
  229. #pragma alloc_text(PAGE,IoWMICompleteRequest)
  230. #endif
  231. NTSTATUS
  232. WmipQueryWmiRegInfo(
  233. IN PDEVICE_OBJECT DeviceObject,
  234. OUT ULONG *RegFlags,
  235. OUT PUNICODE_STRING InstanceName,
  236. OUT PUNICODE_STRING *RegistryPath
  237. )
  238. /*++
  239. Routine Description:
  240. This routine is a callback into the driver to retrieve the list of
  241. guids or data blocks that the driver wants to register with WMI. This
  242. routine may not pend or block. Driver should NOT call
  243. ClassWmiCompleteRequest.
  244. Arguments:
  245. DeviceObject is the device whose data block is being queried
  246. *RegFlags returns with a set of flags that describe the guids being
  247. registered for this device. If the device wants enable and disable
  248. collection callbacks before receiving queries for the registered
  249. guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the
  250. returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case
  251. the instance name is determined from the PDO associated with the
  252. device object. Note that the PDO must have an associated devnode. If
  253. WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique
  254. name for the device.
  255. InstanceName returns with the instance name for the guids if
  256. WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The
  257. caller will call ExFreePool with the buffer returned.
  258. *RegistryPath returns with the registry path of the driver
  259. Return Value:
  260. status
  261. --*/
  262. {
  263. ANSI_STRING AnsiString;
  264. NTSTATUS Status;
  265. PAGED_CODE();
  266. *RegistryPath = &WmipRegistryPath;
  267. RtlInitAnsiString(&AnsiString, "SMBiosData");
  268. Status = RtlAnsiStringToUnicodeString(InstanceName, &AnsiString, TRUE);
  269. return(Status);
  270. }
  271. NTSTATUS
  272. WmipQueryWmiDataBlock(
  273. IN PDEVICE_OBJECT DeviceObject,
  274. IN PIRP Irp,
  275. IN ULONG GuidIndex,
  276. IN ULONG InstanceIndex,
  277. IN ULONG InstanceCount,
  278. IN OUT PULONG InstanceLengthArray,
  279. IN ULONG BufferAvail,
  280. OUT PUCHAR Buffer
  281. )
  282. /*++
  283. Routine Description:
  284. This routine is a callback into the driver to query for the contents of
  285. all instances of a data block. When the driver has finished filling the
  286. data block it must call IoWMICompleteRequest to complete the irp. The
  287. driver can return STATUS_PENDING if the irp cannot be completed
  288. immediately.
  289. Arguments:
  290. DeviceObject is the device whose data block is being queried. In the case
  291. of the PnPId guid this is the device object of the device on whose
  292. behalf the request is being processed.
  293. Irp is the Irp that makes this request
  294. GuidIndex is the index into the list of guids provided when the
  295. device registered
  296. InstanceCount is the number of instnaces expected to be returned for
  297. the data block.
  298. InstanceLengthArray is a pointer to an array of ULONG that returns the
  299. lengths of each instance of the data block. If this is NULL then
  300. there was not enough space in the output buffer to fufill the request
  301. so the irp should be completed with the buffer needed.
  302. BufferAvail on entry has the maximum size available to write the data
  303. blocks.
  304. Buffer on return is filled with the returned data blocks. Note that each
  305. instance of the data block must be aligned on a 8 byte boundry.
  306. Return Value:
  307. status
  308. --*/
  309. {
  310. NTSTATUS status = STATUS_UNSUCCESSFUL;
  311. ULONG sizeNeeded = 0, sizeSMBios;
  312. PUCHAR BufferPtr;
  313. PSMBIOSVERSIONINFO SMBiosVersionInfo;
  314. PULONG TableSize;
  315. PAGED_CODE();
  316. switch (GuidIndex)
  317. {
  318. case SmbiosDataGuidIndex:
  319. {
  320. //
  321. // SMBIOS data table query
  322. #if defined(_AMD64_) || defined(_IA64_) || defined(i386) || defined(MEMPHIS)
  323. WmipAssert((InstanceIndex == 0) && (InstanceCount == 1));
  324. sizeNeeded = sizeof(SMBIOSVERSIONINFO) + sizeof(ULONG);
  325. if (BufferAvail >= sizeNeeded)
  326. {
  327. sizeSMBios = BufferAvail - sizeNeeded;
  328. SMBiosVersionInfo = (PSMBIOSVERSIONINFO)Buffer;
  329. TableSize = (PULONG) (Buffer + sizeof(SMBIOSVERSIONINFO));
  330. BufferPtr = Buffer + sizeNeeded;
  331. } else {
  332. sizeSMBios = 0;
  333. BufferPtr = NULL;
  334. SMBiosVersionInfo = NULL;
  335. }
  336. status = WmipGetSMBiosTableData(BufferPtr,
  337. &sizeSMBios,
  338. SMBiosVersionInfo);
  339. sizeNeeded += sizeSMBios;
  340. if (NT_SUCCESS(status))
  341. {
  342. *(TableSize) = sizeSMBios;
  343. *InstanceLengthArray = sizeNeeded;
  344. }
  345. #else
  346. status = STATUS_WMI_GUID_NOT_FOUND;
  347. #endif
  348. break;
  349. }
  350. case PnPIdGuidIndex:
  351. {
  352. PDEVICE_OBJECT pDO;
  353. UNICODE_STRING instancePath;
  354. PREGENTRY regEntry;
  355. ULONG dataBlockSize, paddedDataBlockSize, padSize;
  356. ULONG i;
  357. regEntry = WmipFindRegEntryByDevice(DeviceObject, FALSE);
  358. if (regEntry != NULL)
  359. {
  360. pDO = regEntry->PDO;
  361. WmipAssert(pDO != NULL);
  362. if (pDO != NULL)
  363. {
  364. status = WmipPDOToDeviceInstanceName(pDO, &instancePath);
  365. } else {
  366. status = STATUS_UNSUCCESSFUL;
  367. }
  368. if (NT_SUCCESS(status))
  369. {
  370. dataBlockSize = instancePath.Length + sizeof(USHORT);
  371. paddedDataBlockSize = (dataBlockSize + 7) & ~7;
  372. padSize = paddedDataBlockSize - dataBlockSize;
  373. sizeNeeded = paddedDataBlockSize * InstanceCount;
  374. if (sizeNeeded <= BufferAvail)
  375. {
  376. for (i = InstanceIndex;
  377. i < (InstanceIndex + InstanceCount);
  378. i++)
  379. {
  380. *InstanceLengthArray++ = dataBlockSize;
  381. *((PUSHORT)Buffer) = instancePath.Length;
  382. Buffer += sizeof(USHORT);
  383. RtlCopyMemory(Buffer,
  384. instancePath.Buffer,
  385. instancePath.Length);
  386. Buffer += instancePath.Length;
  387. RtlZeroMemory(Buffer, padSize);
  388. Buffer += padSize;
  389. }
  390. } else {
  391. status = STATUS_BUFFER_TOO_SMALL;
  392. }
  393. RtlFreeUnicodeString(&instancePath);
  394. } else {
  395. status = STATUS_WMI_GUID_NOT_FOUND;
  396. }
  397. WmipUnreferenceRegEntry(regEntry);
  398. } else {
  399. WmipAssert(FALSE);
  400. status = STATUS_WMI_GUID_NOT_FOUND;
  401. }
  402. break;
  403. }
  404. case PnPIdInstanceNamesGuidIndex:
  405. {
  406. PDEVICE_OBJECT pDO;
  407. UNICODE_STRING instancePath;
  408. PREGENTRY regEntry;
  409. regEntry = WmipFindRegEntryByDevice(DeviceObject, FALSE);
  410. if (regEntry != NULL)
  411. {
  412. pDO = regEntry->PDO;
  413. WmipAssert(pDO != NULL);
  414. if (pDO != NULL)
  415. {
  416. status = WmipPDOToDeviceInstanceName(pDO, &instancePath);
  417. } else {
  418. status = STATUS_UNSUCCESSFUL;
  419. }
  420. if (NT_SUCCESS(status))
  421. {
  422. sizeNeeded = sizeof(ULONG) +
  423. instancePath.Length + 2 * sizeof(WCHAR) +
  424. sizeof(USHORT);
  425. if (sizeNeeded <= BufferAvail)
  426. {
  427. *((PULONG)Buffer) = 1;
  428. Buffer += sizeof(ULONG);
  429. *InstanceLengthArray = sizeNeeded;
  430. *((PUSHORT)Buffer) = instancePath.Length + 2*sizeof(WCHAR);
  431. Buffer += sizeof(USHORT);
  432. RtlCopyMemory(Buffer,
  433. instancePath.Buffer,
  434. instancePath.Length);
  435. Buffer += instancePath.Length;
  436. *((PWCHAR)Buffer) = '_';
  437. Buffer += sizeof(WCHAR);
  438. *((PWCHAR)Buffer) = '0';
  439. } else {
  440. status = STATUS_BUFFER_TOO_SMALL;
  441. }
  442. RtlFreeUnicodeString(&instancePath);
  443. } else {
  444. status = STATUS_WMI_GUID_NOT_FOUND;
  445. }
  446. WmipUnreferenceRegEntry(regEntry);
  447. } else {
  448. WmipAssert(FALSE);
  449. status = STATUS_WMI_GUID_NOT_FOUND;
  450. }
  451. break;
  452. }
  453. case MSAcpiInfoGuidIndex:
  454. {
  455. RTL_QUERY_REGISTRY_TABLE queryTable[4];
  456. ULONG bootArchitecture = 0;
  457. ULONG preferredProfile = 0;
  458. ULONG capabilities = 0;
  459. queryTable[0].QueryRoutine = NULL;
  460. queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT |
  461. RTL_QUERY_REGISTRY_REQUIRED;
  462. queryTable[0].Name = L"BootArchitecture";
  463. queryTable[0].EntryContext = &bootArchitecture;
  464. queryTable[0].DefaultType = REG_NONE;
  465. queryTable[1].QueryRoutine = NULL;
  466. queryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT |
  467. RTL_QUERY_REGISTRY_REQUIRED;
  468. queryTable[1].Name = L"PreferredProfile";
  469. queryTable[1].EntryContext = &preferredProfile;
  470. queryTable[1].DefaultType = REG_NONE;
  471. queryTable[2].QueryRoutine = NULL;
  472. queryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT |
  473. RTL_QUERY_REGISTRY_REQUIRED;
  474. queryTable[2].Name = L"Capabilities";
  475. queryTable[2].EntryContext = &capabilities;
  476. queryTable[2].DefaultType = REG_NONE;
  477. queryTable[3].QueryRoutine = NULL;
  478. queryTable[3].Flags = 0;
  479. status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
  480. L"\\Registry\\Machine\\Hardware\\Description\\System",
  481. queryTable,
  482. NULL,
  483. NULL);
  484. if (NT_SUCCESS(status))
  485. {
  486. sizeNeeded = sizeof(MSAcpiInfo);
  487. if (sizeNeeded <= BufferAvail)
  488. {
  489. PMSAcpiInfo info = (PMSAcpiInfo)Buffer;
  490. info->BootArchitecture = bootArchitecture;
  491. info->PreferredProfile = preferredProfile;
  492. info->Capabilities = capabilities;
  493. status = STATUS_SUCCESS;
  494. } else {
  495. status = STATUS_BUFFER_TOO_SMALL;
  496. }
  497. } else {
  498. status = STATUS_WMI_GUID_NOT_FOUND;
  499. }
  500. break;
  501. }
  502. case Sysid1394GuidIndex:
  503. case SysidUuidGuidIndex:
  504. {
  505. PSYSID_UUID uuid;
  506. ULONG uuidCount;
  507. PSYSID_1394 x1394;
  508. ULONG x1394Count;
  509. PUCHAR data;
  510. ULONG count;
  511. #if defined(_AMD64_) || defined(_IA64_) || defined(i386) || defined(MEMPHIS)
  512. status = WmipGetSysIds(&uuid,
  513. &uuidCount,
  514. &x1394,
  515. &x1394Count);
  516. if (NT_SUCCESS(status))
  517. {
  518. if (GuidIndex == Sysid1394GuidIndex)
  519. {
  520. sizeNeeded = x1394Count * sizeof(SYSID_1394) +
  521. sizeof(ULONG);
  522. data = (PUCHAR)x1394;
  523. count = x1394Count;
  524. } else {
  525. sizeNeeded = uuidCount * sizeof(SYSID_UUID) +
  526. sizeof(ULONG);
  527. data = (PUCHAR)uuid;
  528. count = uuidCount;
  529. }
  530. if (BufferAvail >= sizeNeeded)
  531. {
  532. *InstanceLengthArray = sizeNeeded;
  533. *((PULONG)Buffer) = count;
  534. Buffer += sizeof(ULONG);
  535. RtlCopyMemory(Buffer, data, sizeNeeded-sizeof(ULONG));
  536. status = STATUS_SUCCESS;
  537. } else {
  538. status = STATUS_BUFFER_TOO_SMALL;
  539. }
  540. }
  541. #else
  542. status = STATUS_WMI_GUID_NOT_FOUND;
  543. #endif
  544. break;
  545. }
  546. case SmbiosEventGuidIndex:
  547. {
  548. //
  549. // SMBIOS eventlog query
  550. #if defined(_AMD64_) || defined(_IA64_) || defined(i386) || defined(MEMPHIS)
  551. WmipAssert((InstanceIndex == 0) && (InstanceCount == 1));
  552. if (BufferAvail == 0)
  553. {
  554. sizeNeeded = 0;
  555. BufferPtr = NULL;
  556. } else {
  557. sizeNeeded = BufferAvail;
  558. BufferPtr = Buffer;
  559. }
  560. status = WmipGetSMBiosEventlog(BufferPtr, &sizeNeeded);
  561. if (NT_SUCCESS(status))
  562. {
  563. *InstanceLengthArray = sizeNeeded;
  564. }
  565. #else
  566. status = STATUS_WMI_GUID_NOT_FOUND;
  567. #endif
  568. break;
  569. }
  570. #if defined(_IA64_)
  571. case MCARawDataGuidIndex:
  572. {
  573. PULONG ptr;
  574. ULONG size;
  575. if (WmipRawMCA != NULL)
  576. {
  577. //
  578. // MCA data is available from last boot so return that
  579. // to the caller
  580. //
  581. sizeNeeded = 2 * sizeof(ULONG) + WmipRawMCASize;
  582. if (BufferAvail >= sizeNeeded)
  583. {
  584. ptr = (PULONG)Buffer;
  585. *ptr++ = 1; // 1 MCA record
  586. *ptr++ = WmipRawMCASize; // record size
  587. size = BufferAvail - 2*sizeof(ULONG);
  588. status = WmipGetRawMCAInfo((PUCHAR)ptr,
  589. &size);
  590. if (status == STATUS_BUFFER_TOO_SMALL)
  591. {
  592. sizeNeeded = size + 2*sizeof(ULONG);
  593. }
  594. } else {
  595. status = STATUS_BUFFER_TOO_SMALL;
  596. }
  597. } else {
  598. //
  599. // MCA data is not available so return 0 records
  600. //
  601. sizeNeeded = sizeof(ULONG);
  602. if (BufferAvail >= sizeNeeded)
  603. {
  604. ptr = (PULONG)Buffer;
  605. *ptr = 0;
  606. status = STATUS_SUCCESS;
  607. } else {
  608. status = STATUS_BUFFER_TOO_SMALL;
  609. }
  610. }
  611. if (NT_SUCCESS(status))
  612. {
  613. *InstanceLengthArray = sizeNeeded;
  614. }
  615. break;
  616. }
  617. #endif
  618. //
  619. // For now don't expose the CPE control guid
  620. //
  621. #ifdef CPE_CONTROL
  622. case CPEControlGuidIndex:
  623. {
  624. sizeNeeded = sizeof(MSMCAInfo_CPEControl);
  625. if (BufferAvail >= sizeNeeded)
  626. {
  627. PMSMCAInfo_CPEControl cpeControl;
  628. cpeControl = (PMSMCAInfo_CPEControl)Buffer;
  629. cpeControl->CPEPollingInterval = WmipCpePollInterval;
  630. cpeControl->CPEGenerationEnabled = (WmipCpePollInterval != HAL_CPE_DISABLED) ?
  631. TRUE :
  632. FALSE;
  633. *InstanceLengthArray = sizeNeeded;
  634. status = STATUS_SUCCESS;
  635. } else {
  636. status = STATUS_BUFFER_TOO_SMALL;
  637. }
  638. break;
  639. }
  640. #endif
  641. #ifdef GENERATE_MCA
  642. case GenerateMCEGuidIndex:
  643. {
  644. sizeNeeded = sizeof(ULONG);
  645. if (BufferAvail >= sizeNeeded)
  646. {
  647. *((PULONG)Buffer) = 0;
  648. *InstanceLengthArray = sizeNeeded;
  649. } else {
  650. status = STATUS_BUFFER_TOO_SMALL;
  651. }
  652. break;
  653. }
  654. #endif
  655. default:
  656. {
  657. WmipAssert(FALSE);
  658. status = STATUS_WMI_GUID_NOT_FOUND;
  659. break;
  660. }
  661. }
  662. status = IoWMICompleteRequest((PWMILIB_INFO)&WmipWmiLibInfo,
  663. DeviceObject,
  664. Irp,
  665. status,
  666. sizeNeeded,
  667. IO_NO_INCREMENT);
  668. return(status);
  669. }
  670. #ifdef CPE_CONTROL
  671. NTSTATUS WmipSetWmiDataBlock(
  672. PDEVICE_OBJECT DeviceObject,
  673. PIRP Irp,
  674. ULONG GuidIndex,
  675. ULONG InstanceIndex,
  676. ULONG BufferSize,
  677. PUCHAR Buffer
  678. )
  679. {
  680. NTSTATUS status;
  681. ULONG sizeNeeded;
  682. PAGED_CODE();
  683. if (GuidIndex == CPEControlGuidIndex)
  684. {
  685. sizeNeeded = FIELD_OFFSET(MSMCAInfo_CPEControl,
  686. CPEGenerationEnabled) +
  687. sizeof(BOOLEAN);
  688. if (BufferSize == sizeNeeded)
  689. {
  690. PMSMCAInfo_CPEControl cpeControl;
  691. cpeControl = (PMSMCAInfo_CPEControl)Buffer;
  692. status = WmipSetCPEPolling(cpeControl->CPEGenerationEnabled,
  693. cpeControl->CPEPollingInterval);
  694. } else {
  695. status = STATUS_INVALID_PARAMETER;
  696. }
  697. } else {
  698. status = STATUS_WMI_READ_ONLY;
  699. }
  700. status = IoWMICompleteRequest((PWMILIB_INFO)&WmipWmiLibInfo,
  701. DeviceObject,
  702. Irp,
  703. status,
  704. 0,
  705. IO_NO_INCREMENT);
  706. return(status);
  707. }
  708. #endif
  709. #ifdef GENERATE_MCA
  710. NTSTATUS
  711. WmipExecuteWmiMethod (
  712. IN PDEVICE_OBJECT DeviceObject,
  713. IN PIRP Irp,
  714. IN ULONG GuidIndex,
  715. IN ULONG InstanceIndex,
  716. IN ULONG MethodId,
  717. IN ULONG InBufferSize,
  718. IN ULONG OutBufferSize,
  719. IN OUT PUCHAR Buffer
  720. )
  721. {
  722. NTSTATUS status;
  723. ULONG sizeNeeded;
  724. PAGED_CODE();
  725. if (GuidIndex == GenerateMCEGuidIndex)
  726. {
  727. switch (MethodId)
  728. {
  729. //
  730. // MCA insertion by ID
  731. //
  732. case 1:
  733. {
  734. if (InBufferSize == sizeof(ULONG))
  735. {
  736. sizeNeeded = sizeof(NTSTATUS);
  737. if (OutBufferSize >= sizeNeeded)
  738. {
  739. status = WmipGenerateMCE(*((PULONG)Buffer));
  740. *((NTSTATUS *)Buffer) = status;
  741. status = STATUS_SUCCESS;
  742. }
  743. } else {
  744. status = STATUS_INVALID_PARAMETER;
  745. }
  746. break;
  747. }
  748. //
  749. // Corrected MCA insertion by fully formed MCA exception
  750. //
  751. case 2:
  752. {
  753. #ifdef MCE_INSERTION
  754. status = WmipInsertMce(&WmipCmcQueryInfo,
  755. InBufferSize,
  756. Buffer);
  757. #else
  758. WmipGenerateMCAEventlog(Buffer,
  759. InBufferSize,
  760. FALSE);
  761. status = STATUS_SUCCESS;
  762. #endif
  763. sizeNeeded = 0;
  764. break;
  765. }
  766. //
  767. // Fatal MCA insertion by fully formed MCA exception
  768. //
  769. case 3:
  770. {
  771. #ifdef MCE_INSERTION
  772. status = WmipInsertMce(&WmipCpeQueryInfo,
  773. InBufferSize,
  774. Buffer);
  775. #else
  776. WmipGenerateMCAEventlog(Buffer,
  777. InBufferSize,
  778. TRUE);
  779. status = STATUS_SUCCESS;
  780. #endif
  781. sizeNeeded = 0;
  782. break;
  783. }
  784. default:
  785. {
  786. status = STATUS_WMI_ITEMID_NOT_FOUND;
  787. }
  788. }
  789. } else {
  790. status = STATUS_WMI_GUID_NOT_FOUND;
  791. }
  792. status = IoWMICompleteRequest((PWMILIB_INFO)&WmipWmiLibInfo,
  793. DeviceObject,
  794. Irp,
  795. status,
  796. sizeNeeded,
  797. IO_NO_INCREMENT);
  798. return(status);
  799. }
  800. #endif
  801. BOOLEAN
  802. WmipFindGuid(
  803. IN PGUIDREGINFO GuidList,
  804. IN ULONG GuidCount,
  805. IN LPGUID Guid,
  806. OUT PULONG GuidIndex,
  807. OUT PULONG InstanceCount
  808. )
  809. /*++
  810. Routine Description:
  811. This routine will search the list of guids registered and return
  812. the index for the one that was registered.
  813. Arguments:
  814. GuidList is the list of guids to search
  815. GuidCount is the count of guids in the list
  816. Guid is the guid being searched for
  817. *GuidIndex returns the index to the guid
  818. *InstanceCount returns the count of instances for the guid
  819. Return Value:
  820. TRUE if guid is found else FALSE
  821. --*/
  822. {
  823. ULONG i;
  824. PAGED_CODE();
  825. for (i = 0; i < GuidCount; i++)
  826. {
  827. if (IsEqualGUID(Guid, &GuidList[i].Guid))
  828. {
  829. *GuidIndex = i;
  830. *InstanceCount = GuidList[i].InstanceCount;
  831. return(TRUE);
  832. }
  833. }
  834. return(FALSE);
  835. }
  836. NTSTATUS
  837. IoWMISystemControl(
  838. IN PWMILIB_INFO WmiLibInfo,
  839. IN PDEVICE_OBJECT DeviceObject,
  840. IN PIRP Irp
  841. )
  842. /*++
  843. Routine Description:
  844. Dispatch routine for IRP_MJ_SYSTEM_CONTROL. This routine will process
  845. all wmi requests received, forwarding them if they are not for this
  846. driver or determining if the guid is valid and if so passing it to
  847. the driver specific function for handing wmi requests.
  848. Arguments:
  849. WmiLibInfo has the WMI information control block
  850. DeviceObject - Supplies a pointer to the device object for this request.
  851. Irp - Supplies the Irp making the request.
  852. Return Value:
  853. status
  854. --*/
  855. {
  856. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  857. ULONG bufferSize;
  858. PUCHAR buffer;
  859. NTSTATUS status;
  860. ULONG retSize;
  861. UCHAR minorFunction;
  862. ULONG guidIndex;
  863. ULONG instanceCount;
  864. ULONG instanceIndex;
  865. PAGED_CODE();
  866. //
  867. // If the irp is not a WMI irp or it is not targetted at this device
  868. // or this device has not regstered with WMI then just forward it on.
  869. minorFunction = irpStack->MinorFunction;
  870. if ((minorFunction > IRP_MN_REGINFO_EX) ||
  871. (irpStack->Parameters.WMI.ProviderId != (ULONG_PTR)DeviceObject) ||
  872. (((minorFunction != IRP_MN_REGINFO) &&
  873. ((minorFunction != IRP_MN_REGINFO_EX))) &&
  874. (WmiLibInfo->GuidList == NULL)))
  875. {
  876. //
  877. // IRP is not for us so forward if there is a lower device object
  878. if (WmiLibInfo->LowerDeviceObject != NULL)
  879. {
  880. IoSkipCurrentIrpStackLocation(Irp);
  881. return(IoCallDriver(WmiLibInfo->LowerDeviceObject, Irp));
  882. } else {
  883. status = STATUS_INVALID_DEVICE_REQUEST;
  884. Irp->IoStatus.Status = status;
  885. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  886. return(status);
  887. }
  888. }
  889. buffer = (PUCHAR)irpStack->Parameters.WMI.Buffer;
  890. bufferSize = irpStack->Parameters.WMI.BufferSize;
  891. if ((minorFunction != IRP_MN_REGINFO) &&
  892. (minorFunction != IRP_MN_REGINFO_EX))
  893. {
  894. //
  895. // For all requests other than query registration info we are passed
  896. // a guid. Determine if the guid is one that is supported by the
  897. // device.
  898. if (WmipFindGuid(WmiLibInfo->GuidList,
  899. WmiLibInfo->GuidCount,
  900. (LPGUID)irpStack->Parameters.WMI.DataPath,
  901. &guidIndex,
  902. &instanceCount))
  903. {
  904. status = STATUS_SUCCESS;
  905. } else {
  906. status = STATUS_WMI_GUID_NOT_FOUND;
  907. }
  908. if (NT_SUCCESS(status) &&
  909. ((minorFunction == IRP_MN_QUERY_SINGLE_INSTANCE) ||
  910. (minorFunction == IRP_MN_CHANGE_SINGLE_INSTANCE) ||
  911. (minorFunction == IRP_MN_CHANGE_SINGLE_ITEM) ||
  912. (minorFunction == IRP_MN_EXECUTE_METHOD)))
  913. {
  914. instanceIndex = ((PWNODE_SINGLE_INSTANCE)buffer)->InstanceIndex;
  915. if ( ! (((PWNODE_HEADER)buffer)->Flags) &
  916. WNODE_FLAG_STATIC_INSTANCE_NAMES)
  917. {
  918. status = STATUS_WMI_INSTANCE_NOT_FOUND;
  919. }
  920. }
  921. if (! NT_SUCCESS(status))
  922. {
  923. Irp->IoStatus.Status = status;
  924. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  925. return(status);
  926. }
  927. }
  928. switch(minorFunction)
  929. {
  930. case IRP_MN_REGINFO:
  931. case IRP_MN_REGINFO_EX:
  932. {
  933. ULONG guidCount;
  934. PGUIDREGINFO guidList;
  935. PWMIREGINFOW wmiRegInfo;
  936. PWMIREGGUIDW wmiRegGuid;
  937. PDEVICE_OBJECT pdo;
  938. PUNICODE_STRING regPath;
  939. PWCHAR stringPtr;
  940. ULONG registryPathOffset;
  941. ULONG mofResourceOffset;
  942. ULONG bufferNeeded;
  943. ULONG i;
  944. ULONG_PTR nameInfo;
  945. ULONG nameSize, nameOffset, nameFlags;
  946. UNICODE_STRING name;
  947. UNICODE_STRING nullRegistryPath;
  948. WmipAssert(WmiLibInfo->QueryWmiRegInfo != NULL);
  949. WmipAssert(WmiLibInfo->QueryWmiDataBlock != NULL);
  950. name.Buffer = NULL;
  951. name.Length = 0;
  952. name.MaximumLength = 0;
  953. nameFlags = 0;
  954. status = WmiLibInfo->QueryWmiRegInfo(
  955. DeviceObject,
  956. &nameFlags,
  957. &name,
  958. &regPath);
  959. if (NT_SUCCESS(status) &&
  960. (! (nameFlags & WMIREG_FLAG_INSTANCE_PDO) &&
  961. (name.Buffer == NULL)))
  962. {
  963. //
  964. // if PDO flag not specified then an instance name must be
  965. status = STATUS_INVALID_DEVICE_REQUEST;
  966. }
  967. #if DBG
  968. if (nameFlags & WMIREG_FLAG_INSTANCE_PDO)
  969. {
  970. WmipAssert(WmiLibInfo->LowerPDO != NULL);
  971. }
  972. #endif
  973. if (NT_SUCCESS(status))
  974. {
  975. WmipAssert(WmiLibInfo->GuidList != NULL);
  976. guidList = WmiLibInfo->GuidList;
  977. guidCount = WmiLibInfo->GuidCount;
  978. nameOffset = FIELD_OFFSET(WMIREGINFOW, WmiRegGuid) +
  979. guidCount * sizeof(WMIREGGUIDW);
  980. if (nameFlags & WMIREG_FLAG_INSTANCE_PDO)
  981. {
  982. nameSize = 0;
  983. nameInfo = (ULONG_PTR)WmiLibInfo->LowerPDO;
  984. } else {
  985. nameFlags |= WMIREG_FLAG_INSTANCE_LIST;
  986. nameSize = name.Length + sizeof(USHORT);
  987. nameInfo = nameOffset;
  988. }
  989. if (regPath == NULL)
  990. {
  991. //
  992. // No registry path specified. This is a bad thing for
  993. // the device to do, but is not fatal
  994. nullRegistryPath.Buffer = NULL;
  995. nullRegistryPath.Length = 0;
  996. nullRegistryPath.MaximumLength = 0;
  997. regPath = &nullRegistryPath;
  998. }
  999. mofResourceOffset = 0;
  1000. registryPathOffset = nameOffset + nameSize;
  1001. bufferNeeded = registryPathOffset +
  1002. regPath->Length + sizeof(USHORT);
  1003. if (bufferNeeded <= bufferSize)
  1004. {
  1005. retSize = bufferNeeded;
  1006. wmiRegInfo = (PWMIREGINFO)buffer;
  1007. wmiRegInfo->BufferSize = bufferNeeded;
  1008. wmiRegInfo->NextWmiRegInfo = 0;
  1009. wmiRegInfo->MofResourceName = mofResourceOffset;
  1010. wmiRegInfo->RegistryPath = registryPathOffset;
  1011. wmiRegInfo->GuidCount = guidCount;
  1012. for (i = 0; i < guidCount; i++)
  1013. {
  1014. wmiRegGuid = &wmiRegInfo->WmiRegGuid[i];
  1015. wmiRegGuid->Guid = guidList[i].Guid;
  1016. wmiRegGuid->Flags = guidList[i].Flags | nameFlags;
  1017. wmiRegGuid->InstanceInfo = nameInfo;
  1018. wmiRegGuid->InstanceCount = guidList[i].InstanceCount;
  1019. }
  1020. if ( nameFlags & WMIREG_FLAG_INSTANCE_LIST)
  1021. {
  1022. stringPtr = (PWCHAR)((PUCHAR)buffer + nameOffset);
  1023. *stringPtr++ = name.Length;
  1024. RtlCopyMemory(stringPtr,
  1025. name.Buffer,
  1026. name.Length);
  1027. }
  1028. stringPtr = (PWCHAR)((PUCHAR)buffer + registryPathOffset);
  1029. *stringPtr++ = regPath->Length;
  1030. RtlCopyMemory(stringPtr,
  1031. regPath->Buffer,
  1032. regPath->Length);
  1033. } else {
  1034. *((PULONG)buffer) = bufferNeeded;
  1035. retSize = sizeof(ULONG);
  1036. }
  1037. } else {
  1038. retSize = 0;
  1039. }
  1040. if (name.Buffer != NULL)
  1041. {
  1042. ExFreePool(name.Buffer);
  1043. }
  1044. Irp->IoStatus.Status = status;
  1045. Irp->IoStatus.Information = retSize;
  1046. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1047. return(status);
  1048. }
  1049. case IRP_MN_QUERY_ALL_DATA:
  1050. {
  1051. PWNODE_ALL_DATA wnode;
  1052. ULONG bufferAvail;
  1053. PULONG instanceLengthArray;
  1054. PUCHAR dataBuffer;
  1055. ULONG instanceLengthArraySize;
  1056. ULONG dataBlockOffset;
  1057. PREGENTRY regEntry;
  1058. wnode = (PWNODE_ALL_DATA)buffer;
  1059. if (bufferSize < FIELD_OFFSET(WNODE_ALL_DATA,
  1060. OffsetInstanceDataAndLength))
  1061. {
  1062. //
  1063. // The buffer should never be smaller than the size of
  1064. // WNODE_ALL_DATA, however if it is then return with an
  1065. // error requesting the minimum sized buffer.
  1066. WmipAssert(FALSE);
  1067. status = IoWMICompleteRequest(WmiLibInfo,
  1068. DeviceObject,
  1069. Irp,
  1070. STATUS_BUFFER_TOO_SMALL,
  1071. FIELD_OFFSET(WNODE_ALL_DATA,
  1072. OffsetInstanceDataAndLength),
  1073. IO_NO_INCREMENT);
  1074. break;
  1075. }
  1076. //
  1077. // If this is the pnp id guid then we need to get the instance
  1078. // count from the regentry for the device and switch the
  1079. // device object.
  1080. if ((guidIndex == PnPIdGuidIndex) ||
  1081. (guidIndex == PnPIdInstanceNamesGuidIndex))
  1082. {
  1083. regEntry = WmipFindRegEntryByProviderId(wnode->WnodeHeader.ProviderId,
  1084. FALSE);
  1085. if (regEntry == NULL)
  1086. {
  1087. //
  1088. // Why couldn't we get the regentry again ??
  1089. WmipAssert(FALSE);
  1090. status = IoWMICompleteRequest(WmiLibInfo,
  1091. DeviceObject,
  1092. Irp,
  1093. STATUS_WMI_GUID_NOT_FOUND,
  1094. 0,
  1095. IO_NO_INCREMENT);
  1096. break;
  1097. }
  1098. DeviceObject = regEntry->DeviceObject;
  1099. instanceCount = (guidIndex == PnPIdGuidIndex) ? regEntry->MaxInstanceNames : 1;
  1100. WmipUnreferenceRegEntry(regEntry);
  1101. }
  1102. wnode->InstanceCount = instanceCount;
  1103. wnode->WnodeHeader.Flags &= ~WNODE_FLAG_FIXED_INSTANCE_SIZE;
  1104. instanceLengthArraySize = instanceCount * sizeof(OFFSETINSTANCEDATAANDLENGTH);
  1105. dataBlockOffset = (FIELD_OFFSET(WNODE_ALL_DATA, OffsetInstanceDataAndLength) + instanceLengthArraySize + 7) & ~7;
  1106. wnode->DataBlockOffset = dataBlockOffset;
  1107. if (dataBlockOffset <= bufferSize)
  1108. {
  1109. instanceLengthArray = (PULONG)&wnode->OffsetInstanceDataAndLength[0];
  1110. dataBuffer = buffer + dataBlockOffset;
  1111. bufferAvail = bufferSize - dataBlockOffset;
  1112. } else {
  1113. //
  1114. // There is not enough room in the WNODE to complete
  1115. // the query
  1116. instanceLengthArray = NULL;
  1117. dataBuffer = NULL;
  1118. bufferAvail = 0;
  1119. }
  1120. status = WmiLibInfo->QueryWmiDataBlock(
  1121. DeviceObject,
  1122. Irp,
  1123. guidIndex,
  1124. 0,
  1125. instanceCount,
  1126. instanceLengthArray,
  1127. bufferAvail,
  1128. dataBuffer);
  1129. break;
  1130. }
  1131. case IRP_MN_QUERY_SINGLE_INSTANCE:
  1132. {
  1133. PWNODE_SINGLE_INSTANCE wnode;
  1134. ULONG dataBlockOffset;
  1135. PREGENTRY regEntry;
  1136. wnode = (PWNODE_SINGLE_INSTANCE)buffer;
  1137. if ((guidIndex == PnPIdGuidIndex) ||
  1138. (guidIndex == PnPIdInstanceNamesGuidIndex))
  1139. {
  1140. regEntry = WmipFindRegEntryByProviderId(wnode->WnodeHeader.ProviderId,
  1141. FALSE);
  1142. if (regEntry != NULL)
  1143. {
  1144. DeviceObject = regEntry->DeviceObject;
  1145. WmipUnreferenceRegEntry(regEntry);
  1146. } else {
  1147. //
  1148. // Why couldn't we get the regentry again ??
  1149. WmipAssert(FALSE);
  1150. status = IoWMICompleteRequest(WmiLibInfo,
  1151. DeviceObject,
  1152. Irp,
  1153. STATUS_WMI_GUID_NOT_FOUND,
  1154. 0,
  1155. IO_NO_INCREMENT);
  1156. break;
  1157. }
  1158. }
  1159. dataBlockOffset = wnode->DataBlockOffset;
  1160. status = WmiLibInfo->QueryWmiDataBlock(
  1161. DeviceObject,
  1162. Irp,
  1163. guidIndex,
  1164. instanceIndex,
  1165. 1,
  1166. &wnode->SizeDataBlock,
  1167. bufferSize - dataBlockOffset,
  1168. (PUCHAR)wnode + dataBlockOffset);
  1169. break;
  1170. }
  1171. case IRP_MN_CHANGE_SINGLE_INSTANCE:
  1172. {
  1173. PWNODE_SINGLE_INSTANCE wnode;
  1174. if (WmiLibInfo->SetWmiDataBlock != NULL)
  1175. {
  1176. wnode = (PWNODE_SINGLE_INSTANCE)buffer;
  1177. status = WmiLibInfo->SetWmiDataBlock(
  1178. DeviceObject,
  1179. Irp,
  1180. guidIndex,
  1181. instanceIndex,
  1182. wnode->SizeDataBlock,
  1183. (PUCHAR)wnode + wnode->DataBlockOffset);
  1184. } else {
  1185. //
  1186. // If set callback is not filled in then it must be readonly
  1187. status = STATUS_WMI_READ_ONLY;
  1188. Irp->IoStatus.Status = status;
  1189. Irp->IoStatus.Information = 0;
  1190. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1191. }
  1192. break;
  1193. }
  1194. case IRP_MN_CHANGE_SINGLE_ITEM:
  1195. {
  1196. PWNODE_SINGLE_ITEM wnode;
  1197. if (WmiLibInfo->SetWmiDataItem != NULL)
  1198. {
  1199. wnode = (PWNODE_SINGLE_ITEM)buffer;
  1200. status = WmiLibInfo->SetWmiDataItem(
  1201. DeviceObject,
  1202. Irp,
  1203. guidIndex,
  1204. instanceIndex,
  1205. wnode->ItemId,
  1206. wnode->SizeDataItem,
  1207. (PUCHAR)wnode + wnode->DataBlockOffset);
  1208. } else {
  1209. //
  1210. // If set callback is not filled in then it must be readonly
  1211. status = STATUS_WMI_READ_ONLY;
  1212. Irp->IoStatus.Status = status;
  1213. Irp->IoStatus.Information = 0;
  1214. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1215. }
  1216. break;
  1217. }
  1218. case IRP_MN_EXECUTE_METHOD:
  1219. {
  1220. PWNODE_METHOD_ITEM wnode;
  1221. if (WmiLibInfo->ExecuteWmiMethod != NULL)
  1222. {
  1223. wnode = (PWNODE_METHOD_ITEM)buffer;
  1224. status = WmiLibInfo->ExecuteWmiMethod(
  1225. DeviceObject,
  1226. Irp,
  1227. guidIndex,
  1228. instanceIndex,
  1229. wnode->MethodId,
  1230. wnode->SizeDataBlock,
  1231. bufferSize - wnode->DataBlockOffset,
  1232. buffer + wnode->DataBlockOffset);
  1233. } else {
  1234. //
  1235. // If method callback is not filled in then it must be error
  1236. status = STATUS_INVALID_DEVICE_REQUEST;
  1237. Irp->IoStatus.Status = status;
  1238. Irp->IoStatus.Information = 0;
  1239. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1240. }
  1241. break;
  1242. }
  1243. case IRP_MN_ENABLE_EVENTS:
  1244. {
  1245. if (WmiLibInfo->WmiFunctionControl != NULL)
  1246. {
  1247. status = WmiLibInfo->WmiFunctionControl(
  1248. DeviceObject,
  1249. Irp,
  1250. guidIndex,
  1251. WmiEventGeneration,
  1252. TRUE);
  1253. } else {
  1254. //
  1255. // If callback is not filled in then just succeed
  1256. status = STATUS_SUCCESS;
  1257. Irp->IoStatus.Status = status;
  1258. Irp->IoStatus.Information = 0;
  1259. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1260. }
  1261. break;
  1262. }
  1263. case IRP_MN_DISABLE_EVENTS:
  1264. {
  1265. if (WmiLibInfo->WmiFunctionControl != NULL)
  1266. {
  1267. status = WmiLibInfo->WmiFunctionControl(
  1268. DeviceObject,
  1269. Irp,
  1270. guidIndex,
  1271. WmiEventGeneration,
  1272. FALSE);
  1273. } else {
  1274. //
  1275. // If callback is not filled in then just succeed
  1276. status = STATUS_SUCCESS;
  1277. Irp->IoStatus.Status = status;
  1278. Irp->IoStatus.Information = 0;
  1279. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1280. }
  1281. break;
  1282. }
  1283. case IRP_MN_ENABLE_COLLECTION:
  1284. {
  1285. if (WmiLibInfo->WmiFunctionControl != NULL)
  1286. {
  1287. status = WmiLibInfo->WmiFunctionControl(
  1288. DeviceObject,
  1289. Irp,
  1290. guidIndex,
  1291. WmiDataBlockCollection,
  1292. TRUE);
  1293. } else {
  1294. //
  1295. // If callback is not filled in then just succeed
  1296. status = STATUS_SUCCESS;
  1297. Irp->IoStatus.Status = status;
  1298. Irp->IoStatus.Information = 0;
  1299. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1300. }
  1301. break;
  1302. }
  1303. case IRP_MN_DISABLE_COLLECTION:
  1304. {
  1305. if (WmiLibInfo->WmiFunctionControl != NULL)
  1306. {
  1307. status = WmiLibInfo->WmiFunctionControl(
  1308. DeviceObject,
  1309. Irp,
  1310. guidIndex,
  1311. WmiDataBlockCollection,
  1312. FALSE);
  1313. } else {
  1314. //
  1315. // If callback is not filled in then just succeed
  1316. status = STATUS_SUCCESS;
  1317. Irp->IoStatus.Status = status;
  1318. Irp->IoStatus.Information = 0;
  1319. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1320. }
  1321. break;
  1322. }
  1323. default:
  1324. {
  1325. status = STATUS_INVALID_DEVICE_REQUEST;
  1326. break;
  1327. }
  1328. }
  1329. return(status);
  1330. }
  1331. NTSTATUS
  1332. IoWMICompleteRequest(
  1333. IN PWMILIB_INFO WmiLibInfo,
  1334. IN PDEVICE_OBJECT DeviceObject,
  1335. IN PIRP Irp,
  1336. IN NTSTATUS Status,
  1337. IN ULONG BufferUsed,
  1338. IN CCHAR PriorityBoost
  1339. )
  1340. /*++
  1341. Routine Description:
  1342. This routine will do the work of completing a WMI irp. Depending upon the
  1343. the WMI request this routine will fixup the returned WNODE appropriately.
  1344. Arguments:
  1345. WmiLibInfo has the WMI information control block
  1346. DeviceObject - Supplies a pointer to the device object for this request.
  1347. Irp - Supplies the Irp making the request.
  1348. Status has the return status code for the IRP
  1349. BufferUsed has the number of bytes needed by the device to return the
  1350. data requested in any query. In the case that the buffer passed to
  1351. the device is too small this has the number of bytes needed for the
  1352. return data. If the buffer passed is large enough then this has the
  1353. number of bytes actually used by the device.
  1354. PriorityBoost is the value used for the IoCompleteRequest call.
  1355. Return Value:
  1356. status
  1357. --*/
  1358. {
  1359. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  1360. UCHAR MinorFunction;
  1361. PUCHAR buffer;
  1362. ULONG retSize;
  1363. UCHAR minorFunction;
  1364. ULONG bufferSize;
  1365. PAGED_CODE();
  1366. minorFunction = irpStack->MinorFunction;
  1367. buffer = (PUCHAR)irpStack->Parameters.WMI.Buffer;
  1368. bufferSize = irpStack->Parameters.WMI.BufferSize;
  1369. switch(minorFunction)
  1370. {
  1371. case IRP_MN_QUERY_ALL_DATA:
  1372. {
  1373. PWNODE_ALL_DATA wnode;
  1374. PWNODE_TOO_SMALL wnodeTooSmall;
  1375. ULONG bufferNeeded;
  1376. ULONG instanceCount;
  1377. POFFSETINSTANCEDATAANDLENGTH offsetInstanceDataAndLength;
  1378. ULONG i;
  1379. PULONG instanceLengthArray;
  1380. ULONG dataBlockOffset;
  1381. wnode = (PWNODE_ALL_DATA)buffer;
  1382. dataBlockOffset = wnode->DataBlockOffset;
  1383. instanceCount = wnode->InstanceCount;
  1384. bufferNeeded = dataBlockOffset + BufferUsed;
  1385. if ((NT_SUCCESS(Status)) &&
  1386. (bufferNeeded > irpStack->Parameters.WMI.BufferSize))
  1387. {
  1388. Status = STATUS_BUFFER_TOO_SMALL;
  1389. }
  1390. if (! NT_SUCCESS(Status))
  1391. {
  1392. if (Status == STATUS_BUFFER_TOO_SMALL)
  1393. {
  1394. wnodeTooSmall = (PWNODE_TOO_SMALL)wnode;
  1395. wnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
  1396. wnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
  1397. wnodeTooSmall->SizeNeeded = bufferNeeded;
  1398. retSize = sizeof(WNODE_TOO_SMALL);
  1399. Status = STATUS_SUCCESS;
  1400. } else {
  1401. retSize = 0;
  1402. }
  1403. break;
  1404. }
  1405. KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
  1406. instanceLengthArray = (PULONG)&wnode->OffsetInstanceDataAndLength[0];
  1407. offsetInstanceDataAndLength = (POFFSETINSTANCEDATAANDLENGTH)instanceLengthArray;
  1408. wnode->WnodeHeader.BufferSize = bufferNeeded;
  1409. retSize = bufferNeeded;
  1410. for (i = instanceCount; i != 0; i--)
  1411. {
  1412. offsetInstanceDataAndLength[i-1].LengthInstanceData = instanceLengthArray[i-1];
  1413. }
  1414. for (i = 0; i < instanceCount; i++)
  1415. {
  1416. offsetInstanceDataAndLength[i].OffsetInstanceData = dataBlockOffset;
  1417. dataBlockOffset = (dataBlockOffset + offsetInstanceDataAndLength[i].LengthInstanceData + 7) & ~7;
  1418. }
  1419. break;
  1420. }
  1421. case IRP_MN_QUERY_SINGLE_INSTANCE:
  1422. {
  1423. PWNODE_SINGLE_INSTANCE wnode;
  1424. PWNODE_TOO_SMALL wnodeTooSmall;
  1425. ULONG bufferNeeded;
  1426. wnode = (PWNODE_SINGLE_INSTANCE)buffer;
  1427. bufferNeeded = wnode->DataBlockOffset + BufferUsed;
  1428. if (NT_SUCCESS(Status))
  1429. {
  1430. retSize = bufferNeeded;
  1431. wnode->WnodeHeader.BufferSize = bufferNeeded;
  1432. KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
  1433. WmipAssert(wnode->SizeDataBlock <= BufferUsed);
  1434. } else if (Status == STATUS_BUFFER_TOO_SMALL) {
  1435. wnodeTooSmall = (PWNODE_TOO_SMALL)wnode;
  1436. wnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
  1437. wnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
  1438. wnodeTooSmall->SizeNeeded = bufferNeeded;
  1439. retSize = sizeof(WNODE_TOO_SMALL);
  1440. Status = STATUS_SUCCESS;
  1441. } else {
  1442. retSize = 0;
  1443. }
  1444. break;
  1445. }
  1446. case IRP_MN_EXECUTE_METHOD:
  1447. {
  1448. PWNODE_METHOD_ITEM wnode;
  1449. PWNODE_TOO_SMALL wnodeTooSmall;
  1450. ULONG bufferNeeded;
  1451. wnode = (PWNODE_METHOD_ITEM)buffer;
  1452. bufferNeeded = wnode->DataBlockOffset + BufferUsed;
  1453. if (NT_SUCCESS(Status))
  1454. {
  1455. retSize = bufferNeeded;
  1456. wnode->WnodeHeader.BufferSize = bufferNeeded;
  1457. KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
  1458. wnode->SizeDataBlock = BufferUsed;
  1459. } else if (Status == STATUS_BUFFER_TOO_SMALL) {
  1460. wnodeTooSmall = (PWNODE_TOO_SMALL)wnode;
  1461. wnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
  1462. wnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
  1463. wnodeTooSmall->SizeNeeded = bufferNeeded;
  1464. retSize = sizeof(WNODE_TOO_SMALL);
  1465. Status = STATUS_SUCCESS;
  1466. } else {
  1467. retSize = 0;
  1468. }
  1469. break;
  1470. }
  1471. default:
  1472. {
  1473. //
  1474. // All other requests don't return any data
  1475. retSize = 0;
  1476. break;
  1477. }
  1478. }
  1479. Irp->IoStatus.Status = Status;
  1480. Irp->IoStatus.Information = retSize;
  1481. IoCompleteRequest(Irp, PriorityBoost);
  1482. return(Status);
  1483. }