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.

999 lines
31 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(Irp->IoStatus.Status);
  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. if ((nameFlags & WMIREG_FLAG_INSTANCE_BASENAME) == 0)
  276. {
  277. nameFlags |= WMIREG_FLAG_INSTANCE_LIST;
  278. }
  279. nameSize = name.Length + sizeof(USHORT);
  280. nameInfo = nameOffset;
  281. }
  282. nullUnicodeString.Buffer = NULL;
  283. nullUnicodeString.Length = 0;
  284. nullUnicodeString.MaximumLength = 0;
  285. if (regPath == NULL)
  286. {
  287. //
  288. // No registry path specified. This is a bad thing for
  289. // the device to do, but is not fatal
  290. #if DBG
  291. KdPrint(("WMI: No registry path specified for device %x\n",
  292. DeviceObject));
  293. #endif
  294. regPath = &nullUnicodeString;
  295. }
  296. mofResourceOffset = nameOffset + nameSize;
  297. registryPathOffset = mofResourceOffset +
  298. mofResourceName.Length + sizeof(USHORT);
  299. bufferNeeded = registryPathOffset +
  300. regPath->Length + sizeof(USHORT);
  301. if (bufferNeeded <= bufferSize)
  302. {
  303. retSize = bufferNeeded;
  304. wmiRegInfo = (PWMIREGINFO)buffer;
  305. wmiRegInfo->BufferSize = bufferNeeded;
  306. wmiRegInfo->NextWmiRegInfo = 0;
  307. wmiRegInfo->MofResourceName = mofResourceOffset;
  308. wmiRegInfo->RegistryPath = registryPathOffset;
  309. wmiRegInfo->GuidCount = guidCount;
  310. for (i = 0; i < guidCount; i++)
  311. {
  312. wmiRegGuid = &wmiRegInfo->WmiRegGuid[i];
  313. wmiRegGuid->Guid = *guidList[i].Guid;
  314. wmiRegGuid->Flags = guidList[i].Flags | nameFlags;
  315. wmiRegGuid->InstanceInfo = nameInfo;
  316. wmiRegGuid->InstanceCount = guidList[i].InstanceCount;
  317. if (addRefPDO)
  318. {
  319. ObReferenceObject(pdo);
  320. }
  321. }
  322. if ( nameFlags & (WMIREG_FLAG_INSTANCE_LIST |
  323. WMIREG_FLAG_INSTANCE_BASENAME))
  324. {
  325. stringPtr = (PWCHAR)((PUCHAR)buffer + nameOffset);
  326. *stringPtr++ = name.Length;
  327. RtlCopyMemory(stringPtr,
  328. name.Buffer,
  329. name.Length);
  330. }
  331. stringPtr = (PWCHAR)((PUCHAR)buffer + mofResourceOffset);
  332. *stringPtr++ = mofResourceName.Length;
  333. RtlCopyMemory(stringPtr,
  334. mofResourceName.Buffer,
  335. mofResourceName.Length);
  336. stringPtr = (PWCHAR)((PUCHAR)buffer + registryPathOffset);
  337. *stringPtr++ = regPath->Length;
  338. RtlCopyMemory(stringPtr,
  339. regPath->Buffer,
  340. regPath->Length);
  341. } else {
  342. *((PULONG)buffer) = bufferNeeded;
  343. retSize = sizeof(ULONG);
  344. }
  345. } else {
  346. retSize = 0;
  347. }
  348. if (name.Buffer != NULL)
  349. {
  350. ExFreePool(name.Buffer);
  351. }
  352. Irp->IoStatus.Status = status;
  353. Irp->IoStatus.Information = retSize;
  354. *IrpDisposition = IrpNotCompleted;
  355. return(status);
  356. }
  357. case IRP_MN_QUERY_ALL_DATA:
  358. {
  359. PWNODE_ALL_DATA wnode;
  360. ULONG bufferAvail;
  361. PULONG instanceLengthArray;
  362. PUCHAR dataBuffer;
  363. ULONG instanceLengthArraySize;
  364. ULONG dataBlockOffset;
  365. ASSERT(WmiLibInfo->QueryWmiDataBlock != NULL);
  366. wnode = (PWNODE_ALL_DATA)buffer;
  367. if (bufferSize < sizeof(WNODE_ALL_DATA))
  368. {
  369. //
  370. // The buffer should never be smaller than the size of
  371. // WNODE_ALL_DATA, however if it is then return with an
  372. // error requesting the minimum sized buffer.
  373. ASSERT(FALSE);
  374. Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  375. Irp->IoStatus.Information = 0;
  376. *IrpDisposition = IrpNotCompleted;
  377. break;
  378. }
  379. wnode->InstanceCount = instanceCount;
  380. wnode->WnodeHeader.Flags &= ~WNODE_FLAG_FIXED_INSTANCE_SIZE;
  381. instanceLengthArraySize = instanceCount * sizeof(OFFSETINSTANCEDATAANDLENGTH);
  382. dataBlockOffset = (FIELD_OFFSET(WNODE_ALL_DATA, OffsetInstanceDataAndLength) + instanceLengthArraySize + 7) & ~7;
  383. wnode->DataBlockOffset = dataBlockOffset;
  384. if (dataBlockOffset <= bufferSize)
  385. {
  386. instanceLengthArray = (PULONG)&wnode->OffsetInstanceDataAndLength[0];
  387. dataBuffer = buffer + dataBlockOffset;
  388. bufferAvail = bufferSize - dataBlockOffset;
  389. } else {
  390. //
  391. // There is not enough room in the WNODE to complete
  392. // the query
  393. instanceLengthArray = NULL;
  394. dataBuffer = NULL;
  395. bufferAvail = 0;
  396. }
  397. status = WmiLibInfo->QueryWmiDataBlock(
  398. DeviceObject,
  399. Irp,
  400. guidIndex,
  401. 0,
  402. instanceCount,
  403. instanceLengthArray,
  404. bufferAvail,
  405. dataBuffer);
  406. break;
  407. }
  408. case IRP_MN_QUERY_SINGLE_INSTANCE:
  409. {
  410. PWNODE_SINGLE_INSTANCE wnode;
  411. ULONG dataBlockOffset;
  412. ASSERT(WmiLibInfo->QueryWmiDataBlock != NULL);
  413. wnode = (PWNODE_SINGLE_INSTANCE)buffer;
  414. dataBlockOffset = wnode->DataBlockOffset;
  415. status = WmiLibInfo->QueryWmiDataBlock(
  416. DeviceObject,
  417. Irp,
  418. guidIndex,
  419. instanceIndex,
  420. 1,
  421. &wnode->SizeDataBlock,
  422. bufferSize - dataBlockOffset,
  423. (PUCHAR)wnode + dataBlockOffset);
  424. break;
  425. }
  426. case IRP_MN_CHANGE_SINGLE_INSTANCE:
  427. {
  428. PWNODE_SINGLE_INSTANCE wnode;
  429. if (WmiLibInfo->SetWmiDataBlock != NULL)
  430. {
  431. wnode = (PWNODE_SINGLE_INSTANCE)buffer;
  432. status = WmiLibInfo->SetWmiDataBlock(
  433. DeviceObject,
  434. Irp,
  435. guidIndex,
  436. instanceIndex,
  437. wnode->SizeDataBlock,
  438. (PUCHAR)wnode + wnode->DataBlockOffset);
  439. } else {
  440. //
  441. // If set callback is not filled in then it must be readonly
  442. status = /*STATUS_WMI_READ_ONLY*/ STATUS_INVALID_DEVICE_REQUEST;
  443. Irp->IoStatus.Status = status;
  444. Irp->IoStatus.Information = 0;
  445. *IrpDisposition = IrpNotCompleted;
  446. }
  447. break;
  448. }
  449. case IRP_MN_CHANGE_SINGLE_ITEM:
  450. {
  451. PWNODE_SINGLE_ITEM wnode;
  452. if (WmiLibInfo->SetWmiDataItem != NULL)
  453. {
  454. wnode = (PWNODE_SINGLE_ITEM)buffer;
  455. status = WmiLibInfo->SetWmiDataItem(
  456. DeviceObject,
  457. Irp,
  458. guidIndex,
  459. instanceIndex,
  460. wnode->ItemId,
  461. wnode->SizeDataItem,
  462. (PUCHAR)wnode + wnode->DataBlockOffset);
  463. } else {
  464. //
  465. // If set callback is not filled in then it must be readonly
  466. status = /*STATUS_WMI_READ_ONLY*/ STATUS_INVALID_DEVICE_REQUEST;
  467. Irp->IoStatus.Status = status;
  468. Irp->IoStatus.Information = 0;
  469. *IrpDisposition = IrpNotCompleted;
  470. }
  471. break;
  472. }
  473. case IRP_MN_EXECUTE_METHOD:
  474. {
  475. PWNODE_METHOD_ITEM wnode;
  476. if (WmiLibInfo->ExecuteWmiMethod != NULL)
  477. {
  478. wnode = (PWNODE_METHOD_ITEM)buffer;
  479. status = WmiLibInfo->ExecuteWmiMethod(
  480. DeviceObject,
  481. Irp,
  482. guidIndex,
  483. instanceIndex,
  484. wnode->MethodId,
  485. wnode->SizeDataBlock,
  486. bufferSize - wnode->DataBlockOffset,
  487. buffer + wnode->DataBlockOffset);
  488. } else {
  489. //
  490. // If method callback is not filled in then it must be error
  491. status = STATUS_INVALID_DEVICE_REQUEST;
  492. Irp->IoStatus.Status = status;
  493. Irp->IoStatus.Information = 0;
  494. *IrpDisposition = IrpNotCompleted;
  495. }
  496. break;
  497. }
  498. case IRP_MN_ENABLE_EVENTS:
  499. {
  500. if (WmiLibInfo->WmiFunctionControl != NULL)
  501. {
  502. status = WmiLibInfo->WmiFunctionControl(
  503. DeviceObject,
  504. Irp,
  505. guidIndex,
  506. WmiEventControl,
  507. TRUE);
  508. } else {
  509. //
  510. // If callback is not filled in then just succeed
  511. status = STATUS_SUCCESS;
  512. Irp->IoStatus.Status = status;
  513. Irp->IoStatus.Information = 0;
  514. *IrpDisposition = IrpNotCompleted;
  515. }
  516. break;
  517. }
  518. case IRP_MN_DISABLE_EVENTS:
  519. {
  520. if (WmiLibInfo->WmiFunctionControl != NULL)
  521. {
  522. status = WmiLibInfo->WmiFunctionControl(
  523. DeviceObject,
  524. Irp,
  525. guidIndex,
  526. WmiEventControl,
  527. FALSE);
  528. } else {
  529. //
  530. // If callback is not filled in then just succeed
  531. status = STATUS_SUCCESS;
  532. Irp->IoStatus.Status = status;
  533. Irp->IoStatus.Information = 0;
  534. *IrpDisposition = IrpNotCompleted;
  535. }
  536. break;
  537. }
  538. case IRP_MN_ENABLE_COLLECTION:
  539. {
  540. if (WmiLibInfo->WmiFunctionControl != NULL)
  541. {
  542. status = WmiLibInfo->WmiFunctionControl(
  543. DeviceObject,
  544. Irp,
  545. guidIndex,
  546. WmiDataBlockControl,
  547. TRUE);
  548. } else {
  549. //
  550. // If callback is not filled in then just succeed
  551. status = STATUS_SUCCESS;
  552. Irp->IoStatus.Status = status;
  553. Irp->IoStatus.Information = 0;
  554. *IrpDisposition = IrpNotCompleted;
  555. }
  556. break;
  557. }
  558. case IRP_MN_DISABLE_COLLECTION:
  559. {
  560. if (WmiLibInfo->WmiFunctionControl != NULL)
  561. {
  562. status = WmiLibInfo->WmiFunctionControl(
  563. DeviceObject,
  564. Irp,
  565. guidIndex,
  566. WmiDataBlockControl,
  567. FALSE);
  568. } else {
  569. //
  570. // If callback is not filled in then just succeed
  571. status = STATUS_SUCCESS;
  572. Irp->IoStatus.Status = status;
  573. Irp->IoStatus.Information = 0;
  574. *IrpDisposition = IrpNotCompleted;
  575. }
  576. break;
  577. }
  578. default:
  579. {
  580. status = STATUS_INVALID_DEVICE_REQUEST;
  581. Irp->IoStatus.Status = status;
  582. Irp->IoStatus.Information = 0;
  583. *IrpDisposition = IrpNotCompleted;
  584. break;
  585. }
  586. }
  587. return(status);
  588. }
  589. NTSTATUS
  590. WmiCompleteRequest(
  591. IN PDEVICE_OBJECT DeviceObject,
  592. IN PIRP Irp,
  593. IN NTSTATUS Status,
  594. IN ULONG BufferUsed,
  595. IN CCHAR PriorityBoost
  596. )
  597. /*++
  598. Routine Description:
  599. This routine will do the work of completing a WMI irp. Depending upon the
  600. the WMI request this routine will fixup the returned WNODE appropriately.
  601. This may be called at DPC level
  602. Arguments:
  603. DeviceObject - Supplies a pointer to the device object for this request.
  604. Irp - Supplies the Irp making the request.
  605. Status has the return status code for the IRP
  606. BufferUsed has the number of bytes needed by the device to return the
  607. data requested in any query. In the case that the buffer passed to
  608. the device is too small this has the number of bytes needed for the
  609. return data. If the buffer passed is large enough then this has the
  610. number of bytes actually used by the device.
  611. PriorityBoost is the value used for the IoCompleteRequest call.
  612. Return Value:
  613. status
  614. --*/
  615. {
  616. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  617. UCHAR MinorFunction;
  618. PUCHAR buffer;
  619. ULONG retSize;
  620. UCHAR minorFunction;
  621. ULONG bufferSize;
  622. minorFunction = irpStack->MinorFunction;
  623. buffer = (PUCHAR)irpStack->Parameters.WMI.Buffer;
  624. bufferSize = irpStack->Parameters.WMI.BufferSize;
  625. switch(minorFunction)
  626. {
  627. case IRP_MN_QUERY_ALL_DATA:
  628. {
  629. PWNODE_ALL_DATA wnode;
  630. PWNODE_TOO_SMALL wnodeTooSmall;
  631. ULONG bufferNeeded;
  632. ULONG instanceCount;
  633. POFFSETINSTANCEDATAANDLENGTH offsetInstanceDataAndLength;
  634. ULONG i;
  635. PULONG instanceLengthArray;
  636. ULONG dataBlockOffset;
  637. wnode = (PWNODE_ALL_DATA)buffer;
  638. dataBlockOffset = wnode->DataBlockOffset;
  639. instanceCount = wnode->InstanceCount;
  640. bufferNeeded = dataBlockOffset + BufferUsed;
  641. if ((NT_SUCCESS(Status)) &&
  642. (bufferNeeded > irpStack->Parameters.WMI.BufferSize))
  643. {
  644. Status = STATUS_BUFFER_TOO_SMALL;
  645. }
  646. if (! NT_SUCCESS(Status))
  647. {
  648. if (Status == STATUS_BUFFER_TOO_SMALL)
  649. {
  650. wnodeTooSmall = (PWNODE_TOO_SMALL)wnode;
  651. wnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
  652. wnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
  653. wnodeTooSmall->SizeNeeded = bufferNeeded;
  654. retSize = sizeof(WNODE_TOO_SMALL);
  655. Status = STATUS_SUCCESS;
  656. } else {
  657. retSize = 0;
  658. }
  659. break;
  660. }
  661. KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
  662. instanceLengthArray = (PULONG)&wnode->OffsetInstanceDataAndLength[0];
  663. offsetInstanceDataAndLength = (POFFSETINSTANCEDATAANDLENGTH)instanceLengthArray;
  664. wnode->WnodeHeader.BufferSize = bufferNeeded;
  665. retSize = bufferNeeded;
  666. for (i = instanceCount; i != 0; i--)
  667. {
  668. offsetInstanceDataAndLength[i-1].LengthInstanceData = instanceLengthArray[i-1];
  669. }
  670. for (i = 0; i < instanceCount; i++)
  671. {
  672. offsetInstanceDataAndLength[i].OffsetInstanceData = dataBlockOffset;
  673. dataBlockOffset = (dataBlockOffset + offsetInstanceDataAndLength[i].LengthInstanceData + 7) & ~7;
  674. }
  675. break;
  676. }
  677. case IRP_MN_QUERY_SINGLE_INSTANCE:
  678. {
  679. PWNODE_SINGLE_INSTANCE wnode;
  680. PWNODE_TOO_SMALL wnodeTooSmall;
  681. ULONG bufferNeeded;
  682. wnode = (PWNODE_SINGLE_INSTANCE)buffer;
  683. bufferNeeded = wnode->DataBlockOffset + BufferUsed;
  684. if (NT_SUCCESS(Status))
  685. {
  686. retSize = bufferNeeded;
  687. wnode->WnodeHeader.BufferSize = bufferNeeded;
  688. KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
  689. ASSERT(wnode->SizeDataBlock <= BufferUsed);
  690. } else if (Status == STATUS_BUFFER_TOO_SMALL) {
  691. wnodeTooSmall = (PWNODE_TOO_SMALL)wnode;
  692. wnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
  693. wnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
  694. wnodeTooSmall->SizeNeeded = bufferNeeded;
  695. retSize = sizeof(WNODE_TOO_SMALL);
  696. Status = STATUS_SUCCESS;
  697. } else {
  698. retSize = 0;
  699. }
  700. break;
  701. }
  702. case IRP_MN_EXECUTE_METHOD:
  703. {
  704. PWNODE_METHOD_ITEM wnode;
  705. PWNODE_TOO_SMALL wnodeTooSmall;
  706. ULONG bufferNeeded;
  707. wnode = (PWNODE_METHOD_ITEM)buffer;
  708. bufferNeeded = wnode->DataBlockOffset + BufferUsed;
  709. if (NT_SUCCESS(Status))
  710. {
  711. retSize = bufferNeeded;
  712. wnode->WnodeHeader.BufferSize = bufferNeeded;
  713. KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
  714. wnode->SizeDataBlock = BufferUsed;
  715. } else if (Status == STATUS_BUFFER_TOO_SMALL) {
  716. wnodeTooSmall = (PWNODE_TOO_SMALL)wnode;
  717. wnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
  718. wnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
  719. wnodeTooSmall->SizeNeeded = bufferNeeded;
  720. retSize = sizeof(WNODE_TOO_SMALL);
  721. Status = STATUS_SUCCESS;
  722. } else {
  723. retSize = 0;
  724. }
  725. break;
  726. }
  727. default:
  728. {
  729. //
  730. // All other requests don't return any data
  731. retSize = 0;
  732. break;
  733. }
  734. }
  735. Irp->IoStatus.Status = Status;
  736. Irp->IoStatus.Information = retSize;
  737. IoCompleteRequest(Irp, PriorityBoost);
  738. return(Status);
  739. }
  740. NTSTATUS
  741. WmiFireEvent(
  742. IN PDEVICE_OBJECT DeviceObject,
  743. IN LPGUID Guid,
  744. IN ULONG InstanceIndex,
  745. IN ULONG EventDataSize,
  746. IN PVOID EventData
  747. )
  748. /*++
  749. Routine Description:
  750. This routine will fire a WMI event using the data buffer passed. This
  751. routine may be called at or below DPC level
  752. Arguments:
  753. DeviceObject - Supplies a pointer to the device object for this event
  754. Guid is pointer to the GUID that represents the event
  755. InstanceIndex is the index of the instance of the event
  756. EventDataSize is the number of bytes of data that is being fired with
  757. with the event
  758. EventData is the data that is fired with the events. This may be NULL
  759. if there is no data associated with the event
  760. Return Value:
  761. status
  762. --*/
  763. {
  764. ULONG sizeNeeded;
  765. PWNODE_SINGLE_INSTANCE event;
  766. NTSTATUS status;
  767. if (EventData == NULL)
  768. {
  769. EventDataSize = 0;
  770. }
  771. sizeNeeded = sizeof(WNODE_SINGLE_INSTANCE) + EventDataSize;
  772. event = ExAllocatePoolWithTag(NonPagedPool, sizeNeeded, WMILIBPOOLTAG);
  773. if (event != NULL)
  774. {
  775. event->WnodeHeader.Guid = *Guid;
  776. event->WnodeHeader.ProviderId = IoWMIDeviceObjectToProviderId(DeviceObject);
  777. event->WnodeHeader.BufferSize = sizeNeeded;
  778. event->WnodeHeader.Flags = WNODE_FLAG_SINGLE_INSTANCE |
  779. WNODE_FLAG_EVENT_ITEM |
  780. WNODE_FLAG_STATIC_INSTANCE_NAMES;
  781. KeQuerySystemTime(&event->WnodeHeader.TimeStamp);
  782. event->InstanceIndex = InstanceIndex;
  783. event->SizeDataBlock = EventDataSize;
  784. event->DataBlockOffset = sizeof(WNODE_SINGLE_INSTANCE);
  785. if (EventData != NULL)
  786. {
  787. RtlCopyMemory( &event->VariableData, EventData, EventDataSize);
  788. ExFreePool(EventData);
  789. }
  790. status = IoWMIWriteEvent(event);
  791. if (! NT_SUCCESS(status))
  792. {
  793. ExFreePool(event);
  794. }
  795. } else {
  796. if (EventData != NULL)
  797. {
  798. ExFreePool(EventData);
  799. }
  800. status = STATUS_INSUFFICIENT_RESOURCES;
  801. }
  802. return(status);
  803. }