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.

995 lines
30 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. wmilib.c
  5. Abstract:
  6. WMI library utility functions
  7. CONSIDER adding the following functionality to the library:
  8. * Dynamic instance names
  9. * Different instance names for different guids
  10. Author:
  11. AlanWar
  12. Environment:
  13. kernel mode only
  14. Notes:
  15. Revision History:
  16. --*/
  17. #include "wdm.h"
  18. #include "wmistr.h"
  19. #include "wmilib.h"
  20. #include "wmiguid.h"
  21. NTSTATUS
  22. DriverEntry(
  23. IN PDRIVER_OBJECT DriverObject,
  24. IN PUNICODE_STRING RegistryPath
  25. );
  26. BOOLEAN
  27. WmiLibpFindGuid(
  28. IN PWMIGUIDREGINFO GuidList,
  29. IN ULONG GuidCount,
  30. IN LPGUID Guid,
  31. OUT PULONG GuidIndex,
  32. OUT PULONG InstanceCount
  33. );
  34. #ifdef ALLOC_PRAGMA
  35. #pragma alloc_text(INIT, DriverEntry)
  36. #pragma alloc_text(PAGE, WmiLibpFindGuid)
  37. #pragma alloc_text(PAGE, WmiSystemControl)
  38. #endif
  39. //
  40. // Pool tag for WMILIB
  41. #define WMILIBPOOLTAG 'LimW'
  42. NTSTATUS
  43. DriverEntry(
  44. IN PDRIVER_OBJECT DriverObject,
  45. IN PUNICODE_STRING RegistryPath
  46. )
  47. /*++
  48. Routine Description:
  49. Temporary entry point needed to initialize the class system dll.
  50. It doesn't do anything.
  51. Arguments:
  52. DriverObject - Pointer to the driver object created by the system.
  53. Return Value:
  54. STATUS_SUCCESS
  55. --*/
  56. {
  57. return(STATUS_SUCCESS);
  58. }
  59. BOOLEAN
  60. WmiLibpFindGuid(
  61. IN PWMIGUIDREGINFO GuidList,
  62. IN ULONG GuidCount,
  63. IN LPGUID Guid,
  64. OUT PULONG GuidIndex,
  65. OUT PULONG InstanceCount
  66. )
  67. /*++
  68. Routine Description:
  69. This routine will search the list of guids registered and return
  70. the index for the one that was registered.
  71. Arguments:
  72. GuidList is the list of guids to search
  73. GuidCount is the count of guids in the list
  74. Guid is the guid being searched for
  75. *GuidIndex returns the index to the guid
  76. *InstanceCount returns the count of instances for the guid
  77. Return Value:
  78. TRUE if guid is found else FALSE
  79. --*/
  80. {
  81. ULONG i;
  82. PAGED_CODE();
  83. for (i = 0; i < GuidCount; i++)
  84. {
  85. if (IsEqualGUID(Guid, GuidList[i].Guid))
  86. {
  87. *GuidIndex = i;
  88. *InstanceCount = GuidList[i].InstanceCount;
  89. return(TRUE);
  90. }
  91. }
  92. return(FALSE);
  93. }
  94. NTSTATUS
  95. WmiSystemControl(
  96. IN PWMILIB_CONTEXT WmiLibInfo,
  97. IN PDEVICE_OBJECT DeviceObject,
  98. IN PIRP Irp,
  99. OUT PSYSCTL_IRP_DISPOSITION IrpDisposition
  100. )
  101. /*++
  102. Routine Description:
  103. Dispatch helper routine for IRP_MJ_SYSTEM_CONTROL. This routine will
  104. determine if the irp passed contains a WMI request and if so process it
  105. by invoking the appropriate callback in the WMILIB structure.
  106. This routine may only be called at passive level
  107. Arguments:
  108. WmiLibInfo has the WMI information control block
  109. DeviceObject - Supplies a pointer to the device object for this request.
  110. Irp - Supplies the Irp making the request.
  111. IrpDisposition - Returns a value that specifies how the irp was handled.
  112. Return Value:
  113. status
  114. --*/
  115. {
  116. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  117. ULONG bufferSize;
  118. PUCHAR buffer;
  119. NTSTATUS status;
  120. ULONG retSize;
  121. UCHAR minorFunction;
  122. ULONG guidIndex;
  123. ULONG instanceCount;
  124. ULONG instanceIndex;
  125. PAGED_CODE();
  126. //
  127. // First ensure that the irp is a WMI irp
  128. minorFunction = irpStack->MinorFunction;
  129. if ((minorFunction > IRP_MN_EXECUTE_METHOD) &&
  130. (minorFunction != IRP_MN_REGINFO_EX))
  131. {
  132. //
  133. // This is not a WMI irp
  134. *IrpDisposition = IrpNotWmi;
  135. return(STATUS_SUCCESS);
  136. }
  137. //
  138. // If the irp is not targetted at this device
  139. // or this device has not regstered with WMI then just forward it on.
  140. if ( (irpStack->Parameters.WMI.ProviderId != (UINT_PTR)DeviceObject) ||
  141. (WmiLibInfo == NULL) )
  142. {
  143. #if DBG
  144. if (WmiLibInfo == NULL)
  145. {
  146. KdPrint(("WMILIB: DeviceObject %X passed NULL WmiLibInfo\n",
  147. DeviceObject));
  148. }
  149. #endif
  150. *IrpDisposition = IrpForward;
  151. return(STATUS_SUCCESS);
  152. }
  153. //
  154. // The irp is a WMI irp targetted towards this device driver
  155. *IrpDisposition = IrpProcessed;
  156. buffer = (PUCHAR)irpStack->Parameters.WMI.Buffer;
  157. bufferSize = irpStack->Parameters.WMI.BufferSize;
  158. if ((minorFunction != IRP_MN_REGINFO) &&
  159. (minorFunction != IRP_MN_REGINFO_EX))
  160. {
  161. //
  162. // For all requests other than query registration info we are passed
  163. // a guid. Determine if the guid is one that is supported by the
  164. // device.
  165. ASSERT(WmiLibInfo->GuidList != NULL);
  166. if (WmiLibpFindGuid(WmiLibInfo->GuidList,
  167. WmiLibInfo->GuidCount,
  168. (LPGUID)irpStack->Parameters.WMI.DataPath,
  169. &guidIndex,
  170. &instanceCount))
  171. {
  172. status = STATUS_SUCCESS;
  173. } else {
  174. status = STATUS_WMI_GUID_NOT_FOUND;
  175. }
  176. if (NT_SUCCESS(status) &&
  177. ((minorFunction == IRP_MN_QUERY_SINGLE_INSTANCE) ||
  178. (minorFunction == IRP_MN_CHANGE_SINGLE_INSTANCE) ||
  179. (minorFunction == IRP_MN_CHANGE_SINGLE_ITEM) ||
  180. (minorFunction == IRP_MN_EXECUTE_METHOD)))
  181. {
  182. instanceIndex = ((PWNODE_SINGLE_INSTANCE)buffer)->InstanceIndex;
  183. if ( (((PWNODE_HEADER)buffer)->Flags) &
  184. WNODE_FLAG_STATIC_INSTANCE_NAMES)
  185. {
  186. if ( instanceIndex >= instanceCount )
  187. {
  188. status = STATUS_WMI_INSTANCE_NOT_FOUND;
  189. }
  190. } else {
  191. status = STATUS_WMI_INSTANCE_NOT_FOUND;
  192. }
  193. }
  194. //
  195. // If we couldn't find the guid or the instance name index is out
  196. // of range then return an error.
  197. if (! NT_SUCCESS(status))
  198. {
  199. Irp->IoStatus.Status = status;
  200. *IrpDisposition = IrpNotCompleted;
  201. return(status);
  202. }
  203. }
  204. switch(minorFunction)
  205. {
  206. case IRP_MN_REGINFO:
  207. case IRP_MN_REGINFO_EX:
  208. {
  209. ULONG guidCount;
  210. PWMIGUIDREGINFO guidList;
  211. PWMIREGINFOW wmiRegInfo;
  212. PWMIREGGUIDW wmiRegGuid;
  213. PDEVICE_OBJECT pdo;
  214. PUNICODE_STRING regPath;
  215. UNICODE_STRING mofResourceName;
  216. PWCHAR stringPtr;
  217. ULONG registryPathOffset;
  218. ULONG mofResourceOffset;
  219. ULONG bufferNeeded;
  220. ULONG i;
  221. ULONG nameSize, nameOffset, nameFlags;
  222. ULONG_PTR nameInfo;
  223. UNICODE_STRING name;
  224. UNICODE_STRING nullUnicodeString;
  225. BOOLEAN addRefPDO;
  226. //
  227. // Make sure that the required parts of the WMILIB_INFO structure
  228. // are filled in.
  229. ASSERT(WmiLibInfo->QueryWmiRegInfo != NULL);
  230. name.Buffer = NULL;
  231. name.Length = 0;
  232. name.MaximumLength = 0;
  233. mofResourceName.Buffer = NULL;
  234. mofResourceName.Length = 0;
  235. mofResourceName.MaximumLength = 0;
  236. nameFlags = 0;
  237. status = WmiLibInfo->QueryWmiRegInfo(
  238. DeviceObject,
  239. &nameFlags,
  240. &name,
  241. &regPath,
  242. &mofResourceName,
  243. &pdo);
  244. if (NT_SUCCESS(status) &&
  245. (! (nameFlags & WMIREG_FLAG_INSTANCE_PDO) &&
  246. (name.Buffer == NULL)))
  247. {
  248. //
  249. // if PDO flag not specified then an instance name must be
  250. status = STATUS_INVALID_DEVICE_REQUEST;
  251. }
  252. #if DBG
  253. if (nameFlags & WMIREG_FLAG_INSTANCE_PDO)
  254. {
  255. ASSERT(pdo != NULL);
  256. }
  257. #endif
  258. if (NT_SUCCESS(status))
  259. {
  260. ASSERT(WmiLibInfo->GuidList != NULL);
  261. guidList = WmiLibInfo->GuidList;
  262. guidCount = WmiLibInfo->GuidCount;
  263. nameOffset = sizeof(WMIREGINFO) +
  264. guidCount * sizeof(WMIREGGUIDW);
  265. addRefPDO = FALSE;
  266. if (nameFlags & WMIREG_FLAG_INSTANCE_PDO)
  267. {
  268. nameSize = 0;
  269. nameInfo = (UINT_PTR)pdo;
  270. if (minorFunction == IRP_MN_REGINFO_EX)
  271. {
  272. addRefPDO = TRUE;
  273. }
  274. } else {
  275. nameFlags |= WMIREG_FLAG_INSTANCE_LIST;
  276. nameSize = name.Length + sizeof(USHORT);
  277. nameInfo = nameOffset;
  278. }
  279. nullUnicodeString.Buffer = NULL;
  280. nullUnicodeString.Length = 0;
  281. nullUnicodeString.MaximumLength = 0;
  282. if (regPath == NULL)
  283. {
  284. //
  285. // No registry path specified. This is a bad thing for
  286. // the device to do, but is not fatal
  287. #if DBG
  288. KdPrint(("WMI: No registry path specified for device %x\n",
  289. DeviceObject));
  290. #endif
  291. regPath = &nullUnicodeString;
  292. }
  293. mofResourceOffset = nameOffset + nameSize;
  294. registryPathOffset = mofResourceOffset +
  295. mofResourceName.Length + sizeof(USHORT);
  296. bufferNeeded = registryPathOffset +
  297. regPath->Length + sizeof(USHORT);
  298. if (bufferNeeded <= bufferSize)
  299. {
  300. retSize = bufferNeeded;
  301. wmiRegInfo = (PWMIREGINFO)buffer;
  302. wmiRegInfo->BufferSize = bufferNeeded;
  303. wmiRegInfo->NextWmiRegInfo = 0;
  304. wmiRegInfo->MofResourceName = mofResourceOffset;
  305. wmiRegInfo->RegistryPath = registryPathOffset;
  306. wmiRegInfo->GuidCount = guidCount;
  307. for (i = 0; i < guidCount; i++)
  308. {
  309. wmiRegGuid = &wmiRegInfo->WmiRegGuid[i];
  310. wmiRegGuid->Guid = *guidList[i].Guid;
  311. wmiRegGuid->Flags = guidList[i].Flags | nameFlags;
  312. wmiRegGuid->InstanceInfo = nameInfo;
  313. wmiRegGuid->InstanceCount = guidList[i].InstanceCount;
  314. if (addRefPDO)
  315. {
  316. ObReferenceObject(pdo);
  317. }
  318. }
  319. if ( nameFlags & WMIREG_FLAG_INSTANCE_LIST)
  320. {
  321. stringPtr = (PWCHAR)((PUCHAR)buffer + nameOffset);
  322. *stringPtr++ = name.Length;
  323. RtlCopyMemory(stringPtr,
  324. name.Buffer,
  325. name.Length);
  326. }
  327. stringPtr = (PWCHAR)((PUCHAR)buffer + mofResourceOffset);
  328. *stringPtr++ = mofResourceName.Length;
  329. RtlCopyMemory(stringPtr,
  330. mofResourceName.Buffer,
  331. mofResourceName.Length);
  332. stringPtr = (PWCHAR)((PUCHAR)buffer + registryPathOffset);
  333. *stringPtr++ = regPath->Length;
  334. RtlCopyMemory(stringPtr,
  335. regPath->Buffer,
  336. regPath->Length);
  337. } else {
  338. *((PULONG)buffer) = bufferNeeded;
  339. retSize = sizeof(ULONG);
  340. }
  341. } else {
  342. retSize = 0;
  343. }
  344. if (name.Buffer != NULL)
  345. {
  346. ExFreePool(name.Buffer);
  347. }
  348. Irp->IoStatus.Status = status;
  349. Irp->IoStatus.Information = retSize;
  350. *IrpDisposition = IrpNotCompleted;
  351. return(status);
  352. }
  353. case IRP_MN_QUERY_ALL_DATA:
  354. {
  355. PWNODE_ALL_DATA wnode;
  356. ULONG bufferAvail;
  357. PULONG instanceLengthArray;
  358. PUCHAR dataBuffer;
  359. ULONG instanceLengthArraySize;
  360. ULONG dataBlockOffset;
  361. ASSERT(WmiLibInfo->QueryWmiDataBlock != NULL);
  362. wnode = (PWNODE_ALL_DATA)buffer;
  363. if (bufferSize < sizeof(WNODE_ALL_DATA))
  364. {
  365. //
  366. // The buffer should never be smaller than the size of
  367. // WNODE_ALL_DATA, however if it is then return with an
  368. // error requesting the minimum sized buffer.
  369. ASSERT(FALSE);
  370. Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  371. Irp->IoStatus.Information = 0;
  372. *IrpDisposition = IrpNotCompleted;
  373. break;
  374. }
  375. wnode->InstanceCount = instanceCount;
  376. wnode->WnodeHeader.Flags &= ~WNODE_FLAG_FIXED_INSTANCE_SIZE;
  377. instanceLengthArraySize = instanceCount * sizeof(OFFSETINSTANCEDATAANDLENGTH);
  378. dataBlockOffset = (FIELD_OFFSET(WNODE_ALL_DATA, OffsetInstanceDataAndLength) + instanceLengthArraySize + 7) & ~7;
  379. wnode->DataBlockOffset = dataBlockOffset;
  380. if (dataBlockOffset <= bufferSize)
  381. {
  382. instanceLengthArray = (PULONG)&wnode->OffsetInstanceDataAndLength[0];
  383. dataBuffer = buffer + dataBlockOffset;
  384. bufferAvail = bufferSize - dataBlockOffset;
  385. } else {
  386. //
  387. // There is not enough room in the WNODE to complete
  388. // the query
  389. instanceLengthArray = NULL;
  390. dataBuffer = NULL;
  391. bufferAvail = 0;
  392. }
  393. status = WmiLibInfo->QueryWmiDataBlock(
  394. DeviceObject,
  395. Irp,
  396. guidIndex,
  397. 0,
  398. instanceCount,
  399. instanceLengthArray,
  400. bufferAvail,
  401. dataBuffer);
  402. break;
  403. }
  404. case IRP_MN_QUERY_SINGLE_INSTANCE:
  405. {
  406. PWNODE_SINGLE_INSTANCE wnode;
  407. ULONG dataBlockOffset;
  408. ASSERT(WmiLibInfo->QueryWmiDataBlock != NULL);
  409. wnode = (PWNODE_SINGLE_INSTANCE)buffer;
  410. dataBlockOffset = wnode->DataBlockOffset;
  411. status = WmiLibInfo->QueryWmiDataBlock(
  412. DeviceObject,
  413. Irp,
  414. guidIndex,
  415. instanceIndex,
  416. 1,
  417. &wnode->SizeDataBlock,
  418. bufferSize - dataBlockOffset,
  419. (PUCHAR)wnode + dataBlockOffset);
  420. break;
  421. }
  422. case IRP_MN_CHANGE_SINGLE_INSTANCE:
  423. {
  424. PWNODE_SINGLE_INSTANCE wnode;
  425. if (WmiLibInfo->SetWmiDataBlock != NULL)
  426. {
  427. wnode = (PWNODE_SINGLE_INSTANCE)buffer;
  428. status = WmiLibInfo->SetWmiDataBlock(
  429. DeviceObject,
  430. Irp,
  431. guidIndex,
  432. instanceIndex,
  433. wnode->SizeDataBlock,
  434. (PUCHAR)wnode + wnode->DataBlockOffset);
  435. } else {
  436. //
  437. // If set callback is not filled in then it must be readonly
  438. status = /*STATUS_WMI_READ_ONLY*/ STATUS_INVALID_DEVICE_REQUEST;
  439. Irp->IoStatus.Status = status;
  440. Irp->IoStatus.Information = 0;
  441. *IrpDisposition = IrpNotCompleted;
  442. }
  443. break;
  444. }
  445. case IRP_MN_CHANGE_SINGLE_ITEM:
  446. {
  447. PWNODE_SINGLE_ITEM wnode;
  448. if (WmiLibInfo->SetWmiDataItem != NULL)
  449. {
  450. wnode = (PWNODE_SINGLE_ITEM)buffer;
  451. status = WmiLibInfo->SetWmiDataItem(
  452. DeviceObject,
  453. Irp,
  454. guidIndex,
  455. instanceIndex,
  456. wnode->ItemId,
  457. wnode->SizeDataItem,
  458. (PUCHAR)wnode + wnode->DataBlockOffset);
  459. } else {
  460. //
  461. // If set callback is not filled in then it must be readonly
  462. status = /*STATUS_WMI_READ_ONLY*/ STATUS_INVALID_DEVICE_REQUEST;
  463. Irp->IoStatus.Status = status;
  464. Irp->IoStatus.Information = 0;
  465. *IrpDisposition = IrpNotCompleted;
  466. }
  467. break;
  468. }
  469. case IRP_MN_EXECUTE_METHOD:
  470. {
  471. PWNODE_METHOD_ITEM wnode;
  472. if (WmiLibInfo->ExecuteWmiMethod != NULL)
  473. {
  474. wnode = (PWNODE_METHOD_ITEM)buffer;
  475. status = WmiLibInfo->ExecuteWmiMethod(
  476. DeviceObject,
  477. Irp,
  478. guidIndex,
  479. instanceIndex,
  480. wnode->MethodId,
  481. wnode->SizeDataBlock,
  482. bufferSize - wnode->DataBlockOffset,
  483. buffer + wnode->DataBlockOffset);
  484. } else {
  485. //
  486. // If method callback is not filled in then it must be error
  487. status = STATUS_INVALID_DEVICE_REQUEST;
  488. Irp->IoStatus.Status = status;
  489. Irp->IoStatus.Information = 0;
  490. *IrpDisposition = IrpNotCompleted;
  491. }
  492. break;
  493. }
  494. case IRP_MN_ENABLE_EVENTS:
  495. {
  496. if (WmiLibInfo->WmiFunctionControl != NULL)
  497. {
  498. status = WmiLibInfo->WmiFunctionControl(
  499. DeviceObject,
  500. Irp,
  501. guidIndex,
  502. WmiEventControl,
  503. TRUE);
  504. } else {
  505. //
  506. // If callback is not filled in then just succeed
  507. status = STATUS_SUCCESS;
  508. Irp->IoStatus.Status = status;
  509. Irp->IoStatus.Information = 0;
  510. *IrpDisposition = IrpNotCompleted;
  511. }
  512. break;
  513. }
  514. case IRP_MN_DISABLE_EVENTS:
  515. {
  516. if (WmiLibInfo->WmiFunctionControl != NULL)
  517. {
  518. status = WmiLibInfo->WmiFunctionControl(
  519. DeviceObject,
  520. Irp,
  521. guidIndex,
  522. WmiEventControl,
  523. FALSE);
  524. } else {
  525. //
  526. // If callback is not filled in then just succeed
  527. status = STATUS_SUCCESS;
  528. Irp->IoStatus.Status = status;
  529. Irp->IoStatus.Information = 0;
  530. *IrpDisposition = IrpNotCompleted;
  531. }
  532. break;
  533. }
  534. case IRP_MN_ENABLE_COLLECTION:
  535. {
  536. if (WmiLibInfo->WmiFunctionControl != NULL)
  537. {
  538. status = WmiLibInfo->WmiFunctionControl(
  539. DeviceObject,
  540. Irp,
  541. guidIndex,
  542. WmiDataBlockControl,
  543. TRUE);
  544. } else {
  545. //
  546. // If callback is not filled in then just succeed
  547. status = STATUS_SUCCESS;
  548. Irp->IoStatus.Status = status;
  549. Irp->IoStatus.Information = 0;
  550. *IrpDisposition = IrpNotCompleted;
  551. }
  552. break;
  553. }
  554. case IRP_MN_DISABLE_COLLECTION:
  555. {
  556. if (WmiLibInfo->WmiFunctionControl != NULL)
  557. {
  558. status = WmiLibInfo->WmiFunctionControl(
  559. DeviceObject,
  560. Irp,
  561. guidIndex,
  562. WmiDataBlockControl,
  563. FALSE);
  564. } else {
  565. //
  566. // If callback is not filled in then just succeed
  567. status = STATUS_SUCCESS;
  568. Irp->IoStatus.Status = status;
  569. Irp->IoStatus.Information = 0;
  570. *IrpDisposition = IrpNotCompleted;
  571. }
  572. break;
  573. }
  574. default:
  575. {
  576. status = STATUS_INVALID_DEVICE_REQUEST;
  577. Irp->IoStatus.Status = status;
  578. Irp->IoStatus.Information = 0;
  579. *IrpDisposition = IrpNotCompleted;
  580. break;
  581. }
  582. }
  583. return(status);
  584. }
  585. NTSTATUS
  586. WmiCompleteRequest(
  587. IN PDEVICE_OBJECT DeviceObject,
  588. IN PIRP Irp,
  589. IN NTSTATUS Status,
  590. IN ULONG BufferUsed,
  591. IN CCHAR PriorityBoost
  592. )
  593. /*++
  594. Routine Description:
  595. This routine will do the work of completing a WMI irp. Depending upon the
  596. the WMI request this routine will fixup the returned WNODE appropriately.
  597. This may be called at DPC level
  598. Arguments:
  599. DeviceObject - Supplies a pointer to the device object for this request.
  600. Irp - Supplies the Irp making the request.
  601. Status has the return status code for the IRP
  602. BufferUsed has the number of bytes needed by the device to return the
  603. data requested in any query. In the case that the buffer passed to
  604. the device is too small this has the number of bytes needed for the
  605. return data. If the buffer passed is large enough then this has the
  606. number of bytes actually used by the device.
  607. PriorityBoost is the value used for the IoCompleteRequest call.
  608. Return Value:
  609. status
  610. --*/
  611. {
  612. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  613. UCHAR MinorFunction;
  614. PUCHAR buffer;
  615. ULONG retSize;
  616. UCHAR minorFunction;
  617. ULONG bufferSize;
  618. minorFunction = irpStack->MinorFunction;
  619. buffer = (PUCHAR)irpStack->Parameters.WMI.Buffer;
  620. bufferSize = irpStack->Parameters.WMI.BufferSize;
  621. switch(minorFunction)
  622. {
  623. case IRP_MN_QUERY_ALL_DATA:
  624. {
  625. PWNODE_ALL_DATA wnode;
  626. PWNODE_TOO_SMALL wnodeTooSmall;
  627. ULONG bufferNeeded;
  628. ULONG instanceCount;
  629. POFFSETINSTANCEDATAANDLENGTH offsetInstanceDataAndLength;
  630. ULONG i;
  631. PULONG instanceLengthArray;
  632. ULONG dataBlockOffset;
  633. wnode = (PWNODE_ALL_DATA)buffer;
  634. dataBlockOffset = wnode->DataBlockOffset;
  635. instanceCount = wnode->InstanceCount;
  636. bufferNeeded = dataBlockOffset + BufferUsed;
  637. if ((NT_SUCCESS(Status)) &&
  638. (bufferNeeded > irpStack->Parameters.WMI.BufferSize))
  639. {
  640. Status = STATUS_BUFFER_TOO_SMALL;
  641. }
  642. if (! NT_SUCCESS(Status))
  643. {
  644. if (Status == STATUS_BUFFER_TOO_SMALL)
  645. {
  646. wnodeTooSmall = (PWNODE_TOO_SMALL)wnode;
  647. wnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
  648. wnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
  649. wnodeTooSmall->SizeNeeded = bufferNeeded;
  650. retSize = sizeof(WNODE_TOO_SMALL);
  651. Status = STATUS_SUCCESS;
  652. } else {
  653. retSize = 0;
  654. }
  655. break;
  656. }
  657. KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
  658. instanceLengthArray = (PULONG)&wnode->OffsetInstanceDataAndLength[0];
  659. offsetInstanceDataAndLength = (POFFSETINSTANCEDATAANDLENGTH)instanceLengthArray;
  660. wnode->WnodeHeader.BufferSize = bufferNeeded;
  661. retSize = bufferNeeded;
  662. for (i = instanceCount; i != 0; i--)
  663. {
  664. offsetInstanceDataAndLength[i-1].LengthInstanceData = instanceLengthArray[i-1];
  665. }
  666. for (i = 0; i < instanceCount; i++)
  667. {
  668. offsetInstanceDataAndLength[i].OffsetInstanceData = dataBlockOffset;
  669. dataBlockOffset = (dataBlockOffset + offsetInstanceDataAndLength[i].LengthInstanceData + 7) & ~7;
  670. }
  671. break;
  672. }
  673. case IRP_MN_QUERY_SINGLE_INSTANCE:
  674. {
  675. PWNODE_SINGLE_INSTANCE wnode;
  676. PWNODE_TOO_SMALL wnodeTooSmall;
  677. ULONG bufferNeeded;
  678. wnode = (PWNODE_SINGLE_INSTANCE)buffer;
  679. bufferNeeded = wnode->DataBlockOffset + BufferUsed;
  680. if (NT_SUCCESS(Status))
  681. {
  682. retSize = bufferNeeded;
  683. wnode->WnodeHeader.BufferSize = bufferNeeded;
  684. KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
  685. ASSERT(wnode->SizeDataBlock <= BufferUsed);
  686. } else if (Status == STATUS_BUFFER_TOO_SMALL) {
  687. wnodeTooSmall = (PWNODE_TOO_SMALL)wnode;
  688. wnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
  689. wnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
  690. wnodeTooSmall->SizeNeeded = bufferNeeded;
  691. retSize = sizeof(WNODE_TOO_SMALL);
  692. Status = STATUS_SUCCESS;
  693. } else {
  694. retSize = 0;
  695. }
  696. break;
  697. }
  698. case IRP_MN_EXECUTE_METHOD:
  699. {
  700. PWNODE_METHOD_ITEM wnode;
  701. PWNODE_TOO_SMALL wnodeTooSmall;
  702. ULONG bufferNeeded;
  703. wnode = (PWNODE_METHOD_ITEM)buffer;
  704. bufferNeeded = wnode->DataBlockOffset + BufferUsed;
  705. if (NT_SUCCESS(Status))
  706. {
  707. retSize = bufferNeeded;
  708. wnode->WnodeHeader.BufferSize = bufferNeeded;
  709. KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
  710. wnode->SizeDataBlock = BufferUsed;
  711. } else if (Status == STATUS_BUFFER_TOO_SMALL) {
  712. wnodeTooSmall = (PWNODE_TOO_SMALL)wnode;
  713. wnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
  714. wnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
  715. wnodeTooSmall->SizeNeeded = bufferNeeded;
  716. retSize = sizeof(WNODE_TOO_SMALL);
  717. Status = STATUS_SUCCESS;
  718. } else {
  719. retSize = 0;
  720. }
  721. break;
  722. }
  723. default:
  724. {
  725. //
  726. // All other requests don't return any data
  727. retSize = 0;
  728. break;
  729. }
  730. }
  731. Irp->IoStatus.Status = Status;
  732. Irp->IoStatus.Information = retSize;
  733. IoCompleteRequest(Irp, PriorityBoost);
  734. return(Status);
  735. }
  736. NTSTATUS
  737. WmiFireEvent(
  738. IN PDEVICE_OBJECT DeviceObject,
  739. IN LPGUID Guid,
  740. IN ULONG InstanceIndex,
  741. IN ULONG EventDataSize,
  742. IN PVOID EventData
  743. )
  744. /*++
  745. Routine Description:
  746. This routine will fire a WMI event using the data buffer passed. This
  747. routine may be called at or below DPC level
  748. Arguments:
  749. DeviceObject - Supplies a pointer to the device object for this event
  750. Guid is pointer to the GUID that represents the event
  751. InstanceIndex is the index of the instance of the event
  752. EventDataSize is the number of bytes of data that is being fired with
  753. with the event
  754. EventData is the data that is fired with the events. This may be NULL
  755. if there is no data associated with the event
  756. Return Value:
  757. status
  758. --*/
  759. {
  760. ULONG sizeNeeded;
  761. PWNODE_SINGLE_INSTANCE event;
  762. NTSTATUS status;
  763. if (EventData == NULL)
  764. {
  765. EventDataSize = 0;
  766. }
  767. sizeNeeded = sizeof(WNODE_SINGLE_INSTANCE) + EventDataSize;
  768. event = ExAllocatePoolWithTag(NonPagedPool, sizeNeeded, WMILIBPOOLTAG);
  769. if (event != NULL)
  770. {
  771. event->WnodeHeader.Guid = *Guid;
  772. event->WnodeHeader.ProviderId = IoWMIDeviceObjectToProviderId(DeviceObject);
  773. event->WnodeHeader.BufferSize = sizeNeeded;
  774. event->WnodeHeader.Flags = WNODE_FLAG_SINGLE_INSTANCE |
  775. WNODE_FLAG_EVENT_ITEM |
  776. WNODE_FLAG_STATIC_INSTANCE_NAMES;
  777. KeQuerySystemTime(&event->WnodeHeader.TimeStamp);
  778. event->InstanceIndex = InstanceIndex;
  779. event->SizeDataBlock = EventDataSize;
  780. event->DataBlockOffset = sizeof(WNODE_SINGLE_INSTANCE);
  781. if (EventData != NULL)
  782. {
  783. RtlCopyMemory( &event->VariableData, EventData, EventDataSize);
  784. ExFreePool(EventData);
  785. }
  786. status = IoWMIWriteEvent(event);
  787. if (! NT_SUCCESS(status))
  788. {
  789. ExFreePool(event);
  790. }
  791. } else {
  792. if (EventData != NULL)
  793. {
  794. ExFreePool(EventData);
  795. }
  796. status = STATUS_INSUFFICIENT_RESOURCES;
  797. }
  798. return(status);
  799. }