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.

1512 lines
48 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. diags.c
  5. Abstract:
  6. Diagnostic helper apis
  7. Author:
  8. AlanWar
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. --*/
  13. #include "wmikmp.h"
  14. //
  15. // Each diag request and result is stored in one of these structures. It
  16. // can be uniquely identified by the following combination of properties
  17. //
  18. // IrpMn
  19. // Guid
  20. // MethodId (If IrpMn == IRP_MN_EXECUTE_METHOD, otherwise ignored)
  21. // InstanceContext
  22. // InstanceId
  23. //
  24. typedef struct
  25. {
  26. ULONG NextOffset; // Offset to next result/request
  27. UCHAR IrpMn; // Operation
  28. BOOLEAN IsValid; // if FALSE then this is ignored
  29. UCHAR Reserved1;
  30. UCHAR Reserved2;
  31. GUID Guid;
  32. ULONG MethodId;
  33. ULONG InstanceContextOffset; // Offset to instance context from
  34. // beginning of structure. If 0 then
  35. // no instance context.
  36. ULONG InstanceContextSize;
  37. ULONG InstanceIndex;
  38. ULONG DataOffset; // Offset to data from beginning of
  39. // stru
  40. ULONG DataSize;
  41. ULONG OutDataSize;
  42. UCHAR VariableData[1];
  43. } SCHEDULEDDIAG, *PSCHEDULEDDIAG;
  44. //
  45. // Results are stored under the Checkpoint reg key which is volatile
  46. //
  47. #define REGSTR_CHECKPOINT L"CheckpointDiags"
  48. //
  49. // Permament requests are stored under the Permament reg key
  50. //
  51. #define REGSTR_PERMAMENT L"PermamentDiags"
  52. //
  53. // Temporary requests are stored under the Scheduled reg key
  54. //
  55. #define REGSTR_SCHEDULED L"ScheduledDiags"
  56. NTSTATUS
  57. WmipOpenRegistryKeyEx(
  58. OUT PHANDLE Handle,
  59. IN HANDLE BaseHandle OPTIONAL,
  60. IN PUNICODE_STRING KeyName,
  61. IN ACCESS_MASK DesiredAccess
  62. )
  63. /*++
  64. //
  65. // Temporary requests are stored under the Scheduled reg key
  66. //
  67. #define REGSTR_SCHEDULED L"Scheduled"
  68. NTSTATUS
  69. WmipOpenRegistryKeyEx(
  70. OUT PHANDLE Handle,
  71. IN HANDLE BaseHandle OPTIONAL,
  72. IN PUNICODE_STRING KeyName,
  73. IN ACCESS_MASK DesiredAccess
  74. )
  75. /*++
  76. Routine Description:
  77. Opens a registry key using the name passed in based at the BaseHandle node.
  78. This name may specify a key that is actually a registry path.
  79. Arguments:
  80. Handle - Pointer to the handle which will contain the registry key that
  81. was opened.
  82. BaseHandle - Optional handle to the base path from which the key must be opened.
  83. If KeyName specifies a registry path that must be created, then this parameter
  84. must be specified, and KeyName must be a relative path.
  85. KeyName - Name of the Key that must be opened/created (possibly a registry path)
  86. DesiredAccess - Specifies the desired access that the caller needs to
  87. the key.
  88. Return Value:
  89. The function value is the final status of the operation.
  90. --*/
  91. {
  92. OBJECT_ATTRIBUTES objectAttributes;
  93. PAGED_CODE();
  94. InitializeObjectAttributes( &objectAttributes,
  95. KeyName,
  96. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  97. BaseHandle,
  98. (PSECURITY_DESCRIPTOR) NULL
  99. );
  100. //
  101. // Simply attempt to open the path, as specified.
  102. //
  103. return ZwOpenKey( Handle, DesiredAccess, &objectAttributes );
  104. }
  105. NTSTATUS
  106. WmipCreateRegistryKeyEx(
  107. OUT PHANDLE Handle,
  108. IN HANDLE BaseHandle OPTIONAL,
  109. IN PUNICODE_STRING KeyName,
  110. IN ACCESS_MASK DesiredAccess,
  111. IN ULONG CreateOptions,
  112. OUT PULONG Disposition OPTIONAL
  113. )
  114. /*++
  115. Routine Description:
  116. Opens or creates a registry key using the name
  117. passed in based at the BaseHandle node. This name may specify a key
  118. that is actually a registry path, in which case each intermediate subkey
  119. will be created (if Create is TRUE).
  120. NOTE: Creating a registry path (i.e., more than one of the keys in the path
  121. do not presently exist) requires that a BaseHandle be specified.
  122. Arguments:
  123. Handle - Pointer to the handle which will contain the registry key that
  124. was opened.
  125. BaseHandle - Optional handle to the base path from which the key must be opened.
  126. If KeyName specifies a registry path that must be created, then this parameter
  127. must be specified, and KeyName must be a relative path.
  128. KeyName - Name of the Key that must be opened/created (possibly a registry path)
  129. DesiredAccess - Specifies the desired access that the caller needs to
  130. the key.
  131. CreateOptions - Options passed to ZwCreateKey.
  132. Disposition - If Create is TRUE, this optional pointer receives a ULONG indicating
  133. whether the key was newly created:
  134. REG_CREATED_NEW_KEY - A new Registry Key was created
  135. REG_OPENED_EXISTING_KEY - An existing Registry Key was opened
  136. Return Value:
  137. The function value is the final status of the operation.
  138. --*/
  139. {
  140. OBJECT_ATTRIBUTES objectAttributes;
  141. ULONG disposition, baseHandleIndex = 0, keyHandleIndex = 1, closeBaseHandle;
  142. HANDLE handles[2];
  143. BOOLEAN continueParsing;
  144. PWCHAR pathEndPtr, pathCurPtr, pathBeginPtr;
  145. ULONG pathComponentLength;
  146. UNICODE_STRING unicodeString;
  147. NTSTATUS status;
  148. PAGED_CODE();
  149. InitializeObjectAttributes( &objectAttributes,
  150. KeyName,
  151. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  152. BaseHandle,
  153. (PSECURITY_DESCRIPTOR) NULL
  154. );
  155. //
  156. // Attempt to create the path as specified. We have to try it this
  157. // way first, because it allows us to create a key without a BaseHandle
  158. // (if only the last component of the registry path is not present).
  159. //
  160. status = ZwCreateKey(&(handles[keyHandleIndex]),
  161. DesiredAccess,
  162. &objectAttributes,
  163. 0,
  164. (PUNICODE_STRING) NULL,
  165. CreateOptions,
  166. &disposition
  167. );
  168. if (status == STATUS_OBJECT_NAME_NOT_FOUND && ARGUMENT_PRESENT(BaseHandle)) {
  169. //
  170. // If we get to here, then there must be more than one element of the
  171. // registry path that does not currently exist. We will now parse the
  172. // specified path, extracting each component and doing a ZwCreateKey on it.
  173. //
  174. handles[baseHandleIndex] = NULL;
  175. handles[keyHandleIndex] = BaseHandle;
  176. closeBaseHandle = 0;
  177. continueParsing = TRUE;
  178. pathBeginPtr = KeyName->Buffer;
  179. pathEndPtr = (PWCHAR)((PCHAR)pathBeginPtr + KeyName->Length);
  180. status = STATUS_SUCCESS;
  181. while(continueParsing) {
  182. //
  183. // There's more to do, so close the previous base handle (if necessary),
  184. // and replace it with the current key handle.
  185. //
  186. if(closeBaseHandle > 1) {
  187. ZwClose(handles[baseHandleIndex]);
  188. }
  189. baseHandleIndex = keyHandleIndex;
  190. keyHandleIndex = (keyHandleIndex + 1) & 1; // toggle between 0 and 1.
  191. handles[keyHandleIndex] = NULL;
  192. //
  193. // Extract next component out of the specified registry path.
  194. //
  195. for(pathCurPtr = pathBeginPtr;
  196. ((pathCurPtr < pathEndPtr) && (*pathCurPtr != OBJ_NAME_PATH_SEPARATOR));
  197. pathCurPtr++);
  198. if((pathComponentLength = (ULONG)((PCHAR)pathCurPtr - (PCHAR)pathBeginPtr))) {
  199. //
  200. // Then we have a non-empty path component (key name). Attempt
  201. // to create this key.
  202. //
  203. unicodeString.Buffer = pathBeginPtr;
  204. unicodeString.Length = unicodeString.MaximumLength = (USHORT)pathComponentLength;
  205. InitializeObjectAttributes(&objectAttributes,
  206. &unicodeString,
  207. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  208. handles[baseHandleIndex],
  209. (PSECURITY_DESCRIPTOR) NULL
  210. );
  211. status = ZwCreateKey(&(handles[keyHandleIndex]),
  212. DesiredAccess,
  213. &objectAttributes,
  214. 0,
  215. (PUNICODE_STRING) NULL,
  216. CreateOptions,
  217. &disposition
  218. );
  219. if(NT_SUCCESS(status)) {
  220. //
  221. // Increment the closeBaseHandle value, which basically tells us whether
  222. // the BaseHandle passed in has been 'shifted out' of our way, so that
  223. // we should start closing our base handles when we're finished with them.
  224. //
  225. closeBaseHandle++;
  226. } else {
  227. continueParsing = FALSE;
  228. continue;
  229. }
  230. } else {
  231. //
  232. // Either a path separator ('\') was included at the beginning of
  233. // the path, or we hit 2 consecutive separators.
  234. //
  235. status = STATUS_INVALID_PARAMETER;
  236. continueParsing = FALSE;
  237. continue;
  238. }
  239. if((pathCurPtr == pathEndPtr) ||
  240. ((pathBeginPtr = pathCurPtr + 1) == pathEndPtr)) {
  241. //
  242. // Then we've reached the end of the path
  243. //
  244. continueParsing = FALSE;
  245. }
  246. }
  247. if(closeBaseHandle > 1) {
  248. ZwClose(handles[baseHandleIndex]);
  249. }
  250. }
  251. if(NT_SUCCESS(status)) {
  252. *Handle = handles[keyHandleIndex];
  253. if(ARGUMENT_PRESENT(Disposition)) {
  254. *Disposition = disposition;
  255. }
  256. }
  257. return status;
  258. }
  259. NTSTATUS WmipReadValueKey(
  260. IN HANDLE Key,
  261. IN PUNICODE_STRING ValueName,
  262. IN ULONG ValueType,
  263. OUT PKEY_VALUE_PARTIAL_INFORMATION *PartialInfoPtr,
  264. OUT PULONG InfoSizePtr
  265. )
  266. {
  267. KEY_VALUE_PARTIAL_INFORMATION PartialInfo;
  268. ULONG InfoSize;
  269. PUCHAR Buffer;
  270. NTSTATUS Status;
  271. InfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION);
  272. Status = ZwQueryValueKey(Key,
  273. ValueName,
  274. KeyValuePartialInformation,
  275. &PartialInfo,
  276. InfoSize,
  277. &InfoSize);
  278. if (((Status != STATUS_BUFFER_OVERFLOW) && (! NT_SUCCESS(Status))) ||
  279. (PartialInfo.Type != ValueType))
  280. {
  281. //
  282. // if there is no value or it is not the correct type then don't
  283. // return anything
  284. //
  285. *PartialInfoPtr = NULL;
  286. *InfoSizePtr = 0;
  287. } else {
  288. //
  289. // Allocate a buffer to hold the previous and new diags
  290. //
  291. Buffer = ExAllocatePoolWithTag(PagedPool,
  292. InfoSize,
  293. WMIPSCHEDPOOLTAG);
  294. if (Buffer != NULL)
  295. {
  296. Status = ZwQueryValueKey(Key,
  297. ValueName,
  298. KeyValuePartialInformation,
  299. Buffer,
  300. InfoSize,
  301. &InfoSize);
  302. if (NT_SUCCESS(Status))
  303. {
  304. *InfoSizePtr = InfoSize;
  305. *PartialInfoPtr = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer;
  306. } else {
  307. ExFreePool(Buffer);
  308. }
  309. } else {
  310. Status = STATUS_INSUFFICIENT_RESOURCES;
  311. }
  312. }
  313. return(Status);
  314. }
  315. NTSTATUS WmipOpenDiagRegKey(
  316. IN PDEVICE_OBJECT DeviceObject,
  317. IN PUNICODE_STRING SubKey,
  318. IN ULONG DesiredAccess,
  319. IN BOOLEAN CreateIfNeeded,
  320. OUT PHANDLE Key
  321. )
  322. {
  323. HANDLE BaseKey;
  324. NTSTATUS Status;
  325. ULONG Disposition;
  326. PDEVICE_OBJECT PDO;
  327. PAGED_CODE();
  328. Status = WmipGetDevicePDO(DeviceObject, &PDO);
  329. if (NT_SUCCESS(Status))
  330. {
  331. Status = IoOpenDeviceRegistryKey(PDO,
  332. PLUGPLAY_REGKEY_DEVICE,
  333. DesiredAccess,
  334. &BaseKey);
  335. if (NT_SUCCESS(Status))
  336. {
  337. if (SubKey != NULL)
  338. {
  339. if (CreateIfNeeded)
  340. {
  341. Status = WmipCreateRegistryKeyEx(Key,
  342. BaseKey,
  343. SubKey,
  344. DesiredAccess,
  345. REG_OPTION_NON_VOLATILE,
  346. &Disposition);
  347. } else {
  348. Status = WmipOpenRegistryKeyEx(Key,
  349. BaseKey,
  350. SubKey,
  351. DesiredAccess);
  352. }
  353. ZwClose(BaseKey);
  354. } else {
  355. *Key = BaseKey;
  356. }
  357. }
  358. ObDereferenceObject(PDO);
  359. }
  360. return(Status);
  361. }
  362. BOOLEAN WmipDoesSigMatchDiag(
  363. IN PSCHEDULEDDIAG Diag,
  364. IN UCHAR IrpMn,
  365. IN LPGUID Guid,
  366. IN ULONG InstanceContextSize,
  367. IN PUCHAR InstanceContext,
  368. IN ULONG InstanceIndex,
  369. IN ULONG MethodId
  370. )
  371. /*++
  372. Routine Description:
  373. This routine will determine if the diag passed matches the signature
  374. passed.
  375. Arguments:
  376. Diag is the diag structure to check
  377. IrpMn is the irp operation to perform
  378. Guid is the guid for the diag request/result
  379. InstanceContextSize is the size of the optional instance context
  380. InstanceContext is a pointer to the optional instance context
  381. InstanceIndex is the instance index
  382. MethodId is the method id if the operation is IRP_MN_EXECUTE_METHOD
  383. Return Value:
  384. TRUE if signature matches
  385. --*/
  386. {
  387. BOOLEAN RetVal = FALSE;
  388. PUCHAR DiagInstanceContext;
  389. if ((Diag->IsValid) &&
  390. (Diag->IrpMn == IrpMn) &&
  391. (IsEqualGUID(&Diag->Guid, Guid)) &&
  392. (Diag->InstanceContextSize == InstanceContextSize) &&
  393. ((IrpMn != IRP_MN_EXECUTE_METHOD) || (Diag->MethodId == MethodId)))
  394. {
  395. //
  396. // Diag is valid and the IrpMn, Guid, InstanceContext size
  397. // and Method Id match. Now if the InstanceContext data
  398. // matches then we have a match.
  399. //
  400. if ((InstanceContext == NULL) &&
  401. (Diag->InstanceContextOffset == 0))
  402. {
  403. if (InstanceIndex == Diag->InstanceIndex)
  404. {
  405. //
  406. // There is no instance context, but the instance index
  407. // match so we have a match
  408. RetVal = TRUE;
  409. }
  410. //
  411. // There is no instance context, but the instance index
  412. // do not match
  413. } else {
  414. DiagInstanceContext = OffsetToPtr(Diag,
  415. Diag->InstanceContextOffset);
  416. if (RtlCompareMemory(DiagInstanceContext,
  417. InstanceContext,
  418. InstanceContextSize) == InstanceContextSize)
  419. {
  420. //
  421. // There is an instance context and it matches
  422. //
  423. RetVal = TRUE;
  424. }
  425. }
  426. }
  427. return(RetVal);
  428. }
  429. PSCHEDULEDDIAG WmipFindDiagInBuffer(
  430. IN PUCHAR DiagList,
  431. IN ULONG DiagBufferSize,
  432. IN UCHAR IrpMn,
  433. IN LPGUID Guid,
  434. IN ULONG InstanceContextSize,
  435. IN PUCHAR InstanceContext,
  436. IN ULONG InstanceIndex,
  437. IN ULONG MethodId
  438. )
  439. /*++
  440. Routine Description:
  441. This routine will search the diags in the DiagList buffer for a valid
  442. diag structure that matches the diag signature
  443. Arguments:
  444. DiagList is the diag structures to check
  445. DiagBufferSize is the size of the diag list
  446. IrpMn is the irp operation to perform
  447. Guid is the guid for the diag request/result
  448. InstanceContextSize is the size of the optional instance context
  449. InstanceContext is a pointer to the optional instance context
  450. InstanceIndex is the instance index
  451. MethodId is the method id if the operation is IRP_MN_EXECUTE_METHOD
  452. Return Value:
  453. pointer to the diag that matches the signature or NULL if none do
  454. --*/
  455. {
  456. ULONG Offset;
  457. PSCHEDULEDDIAG Diag;
  458. Offset = 0;
  459. while (Offset < DiagBufferSize)
  460. {
  461. Diag = (PSCHEDULEDDIAG)OffsetToPtr(DiagList, Offset);
  462. if (WmipDoesSigMatchDiag(Diag,
  463. IrpMn,
  464. Guid,
  465. InstanceContextSize,
  466. InstanceContext,
  467. InstanceIndex,
  468. MethodId))
  469. {
  470. //
  471. // we have a match, so return the pointer
  472. //
  473. return(Diag);
  474. }
  475. Offset += Diag->NextOffset;
  476. }
  477. return(NULL);
  478. }
  479. NTSTATUS WmipUpdateOrAppendDiag(
  480. IN PDEVICE_OBJECT DeviceObject,
  481. IN PUNICODE_STRING DiagType,
  482. IN PUNICODE_STRING DiagSet,
  483. IN UCHAR IrpMn,
  484. IN LPGUID Guid,
  485. IN ULONG InstanceContextSize,
  486. IN PUCHAR InstanceContext,
  487. IN ULONG InstanceIndex,
  488. IN ULONG MethodId,
  489. IN ULONG DataSize,
  490. IN PUCHAR Data
  491. )
  492. /*++
  493. Routine Description:
  494. This routine will update or append a new diag to the diag set specified.
  495. If an existing diag with the same signature exists then the existing
  496. diag is made invalid and a new diag to replace it is appended.
  497. CONSIDER: If we reach a threshold of many invalid diags then we may
  498. want to repack the buffer.
  499. Arguments:
  500. DeviceObject is the device object for the device
  501. DiagType is the type of diag, ie SCHEDULED, PERMAMENT or CHECKPOINT
  502. DiagSet is the unique diag set name
  503. IrpMn is the irp operation to perform
  504. Guid is the guid for the diag request/result
  505. InstanceContextSize is the size of the optional instance context
  506. InstanceContext is a pointer to the optional instance context
  507. InstanceIndex is the instance index
  508. MethodId is the method id if the operation is IRP_MN_EXECUTE_METHOD
  509. DataSize is the size of the request/result data
  510. Data is a pointer to the data
  511. Return Value:
  512. NT status code
  513. --*/
  514. {
  515. KEY_VALUE_PARTIAL_INFORMATION PartialInfo;
  516. PKEY_VALUE_PARTIAL_INFORMATION DiagPartialInfo;
  517. NTSTATUS Status;
  518. UNICODE_STRING Scheduled;
  519. ULONG InstanceContextOffset, DataOffset;
  520. ULONG InfoSize;
  521. HANDLE Key;
  522. ULONG DiagSize, SizeNeeded;
  523. PUCHAR DiagBuffer;
  524. PSCHEDULEDDIAG Diag;
  525. PUCHAR Ptr;
  526. PUCHAR RegDataPtr;
  527. ULONG RegDataSize;
  528. PAGED_CODE();
  529. //
  530. // Get the current contents for the diag set
  531. //
  532. Status = WmipOpenDiagRegKey(DeviceObject,
  533. DiagType,
  534. KEY_WRITE | KEY_READ,
  535. TRUE,
  536. &Key);
  537. if (NT_SUCCESS(Status))
  538. {
  539. //
  540. // Comupte size needed to append the new diagnostic
  541. //
  542. InstanceContextOffset = FIELD_OFFSET(SCHEDULEDDIAG, VariableData);
  543. DataOffset = ((InstanceContextOffset + 7) &~7) + InstanceContextSize;
  544. DiagSize = ((DataOffset+ 7)&~7) + DataSize;
  545. //
  546. // Obtain the size of the current diags already setup in the registry
  547. //
  548. InfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION);
  549. Status = ZwQueryValueKey(Key,
  550. DiagSet,
  551. KeyValuePartialInformation,
  552. &PartialInfo,
  553. InfoSize,
  554. &InfoSize);
  555. if (((Status != STATUS_BUFFER_OVERFLOW) && (! NT_SUCCESS(Status))) ||
  556. (PartialInfo.Type != REG_BINARY))
  557. {
  558. //
  559. // if there is no value or it is not a REG_BINARY then ignore
  560. // it.
  561. //
  562. InfoSize = 0;
  563. Status = STATUS_SUCCESS;
  564. }
  565. //
  566. // Allocate a buffer to hold the previous and new diags
  567. //
  568. SizeNeeded = InfoSize + DiagSize;
  569. DiagBuffer = ExAllocatePoolWithTag(PagedPool,
  570. SizeNeeded,
  571. WMIPSCHEDPOOLTAG);
  572. if (DiagBuffer != NULL)
  573. {
  574. //
  575. // If there are previous diagnostics then read them in
  576. //
  577. if (InfoSize != 0)
  578. {
  579. Status = ZwQueryValueKey(Key,
  580. DiagSet,
  581. KeyValuePartialInformation,
  582. DiagBuffer,
  583. InfoSize,
  584. &InfoSize);
  585. if (NT_SUCCESS(Status))
  586. {
  587. //
  588. // Setup pointers to the diag data
  589. //
  590. DiagPartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)DiagBuffer;
  591. RegDataPtr = &DiagPartialInfo->Data[0];
  592. RegDataSize = DiagPartialInfo->DataLength + DiagSize;
  593. //
  594. // See if there is a duplicate diag for the
  595. // diag signature
  596. //
  597. Diag = WmipFindDiagInBuffer(RegDataPtr,
  598. DiagPartialInfo->DataLength,
  599. IrpMn,
  600. Guid,
  601. InstanceContextSize,
  602. InstanceContext,
  603. InstanceIndex,
  604. MethodId);
  605. if (Diag != NULL)
  606. {
  607. //
  608. // There is already a signature so we mark this as
  609. // invalid
  610. //
  611. ASSERT(Diag->IsValid);
  612. Diag->IsValid = FALSE;
  613. }
  614. } else {
  615. //
  616. // For some reason we failed reading in a second time
  617. //
  618. ASSERT(FALSE);
  619. RegDataPtr = DiagBuffer;
  620. RegDataSize = DiagSize;
  621. Status = STATUS_SUCCESS;
  622. }
  623. } else {
  624. //
  625. // Setup pointers to the diag data
  626. //
  627. RegDataPtr = DiagBuffer;
  628. RegDataSize = DiagSize;
  629. }
  630. if (NT_SUCCESS(Status))
  631. {
  632. //
  633. // Initialize the Diag structure at the end of the diag buffer
  634. //
  635. Diag = (PSCHEDULEDDIAG)OffsetToPtr(DiagBuffer, InfoSize);
  636. RtlZeroMemory(Diag, DiagSize);
  637. Diag->IsValid = TRUE;
  638. Diag->NextOffset = DiagSize;
  639. Diag->IrpMn = IrpMn;
  640. Diag->Guid = *Guid;
  641. Diag->MethodId = MethodId;
  642. if (InstanceContext != NULL)
  643. {
  644. //
  645. // If there is an instance context then initialize it
  646. //
  647. Diag->InstanceIndex = InstanceIndex;
  648. Diag->InstanceContextOffset = InstanceContextOffset;
  649. Diag->InstanceContextSize = InstanceContextSize;
  650. Ptr = (PUCHAR)OffsetToPtr(Diag, InstanceContextOffset);
  651. RtlCopyMemory(Ptr, InstanceContext, InstanceContextSize);
  652. }
  653. if (Data != NULL)
  654. {
  655. //
  656. // If there is data then initialize it
  657. //
  658. Diag->DataOffset = DataOffset;
  659. Diag->DataSize = DataSize;
  660. Ptr = (PUCHAR)OffsetToPtr(Diag, DataOffset);
  661. RtlCopyMemory(Ptr, Data, DataSize);
  662. }
  663. //
  664. // Write diag buffer back to registry
  665. //
  666. Status = ZwSetValueKey(Key,
  667. DiagSet,
  668. 0,
  669. REG_BINARY,
  670. RegDataPtr,
  671. RegDataSize);
  672. }
  673. ExFreePool(DiagBuffer);
  674. } else {
  675. Status = STATUS_INSUFFICIENT_RESOURCES;
  676. }
  677. ZwClose(Key);
  678. }
  679. return(Status);
  680. }
  681. NTSTATUS IoWMIScheduleDiagnostic(
  682. IN PDEVICE_OBJECT DeviceObject,
  683. IN PUNICODE_STRING DiagSet,
  684. IN UCHAR IrpMn,
  685. IN LPGUID Guid,
  686. IN ULONG InstanceContextSize,
  687. IN PUCHAR InstanceContext,
  688. IN ULONG InstanceIndex,
  689. IN ULONG MethodId,
  690. IN ULONG DataSize,
  691. IN PUCHAR Data
  692. )
  693. {
  694. NTSTATUS Status;
  695. UNICODE_STRING Scheduled;
  696. PAGED_CODE();
  697. //
  698. // Get the current contents for the diag set
  699. //
  700. RtlInitUnicodeString(&Scheduled, REGSTR_SCHEDULED);
  701. Status = WmipUpdateOrAppendDiag(DeviceObject,
  702. &Scheduled,
  703. DiagSet,
  704. IrpMn,
  705. Guid,
  706. InstanceContextSize,
  707. InstanceContext,
  708. InstanceIndex,
  709. MethodId,
  710. DataSize,
  711. Data);
  712. return(Status);
  713. }
  714. NTSTATUS IoWMICancelDiagnostic(
  715. IN PDEVICE_OBJECT DeviceObject,
  716. IN PUNICODE_STRING DiagSet,
  717. IN UCHAR IrpMn,
  718. IN LPGUID Guid,
  719. IN ULONG InstanceContextSize,
  720. IN PUCHAR InstanceContext,
  721. IN ULONG InstanceIndex,
  722. IN ULONG MethodId
  723. )
  724. {
  725. NTSTATUS Status;
  726. UNICODE_STRING Value;
  727. HANDLE Key;
  728. KEY_VALUE_PARTIAL_INFORMATION PartialInfo;
  729. PKEY_VALUE_PARTIAL_INFORMATION DiagPartialInfo;
  730. UNICODE_STRING Scheduled;
  731. ULONG InstanceContextOffset, DataOffset;
  732. ULONG InfoSize;
  733. PUCHAR DiagBuffer;
  734. PSCHEDULEDDIAG Diag;
  735. PUCHAR Ptr;
  736. PUCHAR DiagList;
  737. ULONG DiagListSize;
  738. PAGED_CODE();
  739. //
  740. // Get the current contents for the diag set
  741. //
  742. RtlInitUnicodeString(&Scheduled, REGSTR_SCHEDULED);
  743. Status = WmipOpenDiagRegKey(DeviceObject,
  744. &Scheduled,
  745. KEY_WRITE | KEY_READ,
  746. TRUE,
  747. &Key);
  748. if (NT_SUCCESS(Status))
  749. {
  750. //
  751. // Obtain the size of the current diags already setup in the registry
  752. //
  753. InfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION);
  754. Status = ZwQueryValueKey(Key,
  755. DiagSet,
  756. KeyValuePartialInformation,
  757. &PartialInfo,
  758. InfoSize,
  759. &InfoSize);
  760. if ( ((Status == STATUS_BUFFER_OVERFLOW) || NT_SUCCESS(Status)) &&
  761. (PartialInfo.Type == REG_BINARY) )
  762. {
  763. //
  764. // Allocate a buffer to hold the diag list
  765. //
  766. DiagBuffer = ExAllocatePoolWithTag(PagedPool,
  767. InfoSize,
  768. WMIPSCHEDPOOLTAG);
  769. if (DiagBuffer != NULL)
  770. {
  771. //
  772. // Read in all of the diags in the list
  773. //
  774. Status = ZwQueryValueKey(Key,
  775. DiagSet,
  776. KeyValuePartialInformation,
  777. DiagBuffer,
  778. InfoSize,
  779. &InfoSize);
  780. if (NT_SUCCESS(Status))
  781. {
  782. //
  783. // Setup pointers to the diag data
  784. //
  785. DiagPartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)DiagBuffer;
  786. DiagList = &DiagPartialInfo->Data[0];
  787. DiagListSize = DiagPartialInfo->DataLength;
  788. //
  789. // See if there is a duplicate diag for the
  790. // diag signature
  791. //
  792. Diag = WmipFindDiagInBuffer(DiagList,
  793. DiagListSize,
  794. IrpMn,
  795. Guid,
  796. InstanceContextSize,
  797. InstanceContext,
  798. InstanceIndex,
  799. MethodId);
  800. if (Diag != NULL)
  801. {
  802. //
  803. // There is already a signature so we mark this as
  804. // invalid or cancelled.
  805. //
  806. ASSERT(Diag->IsValid);
  807. Diag->IsValid = FALSE;
  808. //
  809. // Write diag buffer back to registry
  810. //
  811. Status = ZwSetValueKey(Key,
  812. DiagSet,
  813. 0,
  814. REG_BINARY,
  815. DiagList,
  816. DiagListSize);
  817. } else {
  818. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  819. }
  820. } else {
  821. //
  822. // For some reason we failed reading in a second time
  823. //
  824. ASSERT(FALSE);
  825. }
  826. ExFreePool(DiagBuffer);
  827. } else {
  828. //
  829. // Couldn't alloc memory
  830. //
  831. Status = STATUS_INSUFFICIENT_RESOURCES;
  832. }
  833. } else if (NT_SUCCESS(Status)) {
  834. //
  835. // Value is not a REG_BINARY so we skip it and return an error
  836. //
  837. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  838. }
  839. ZwClose(Key);
  840. }
  841. return(Status);
  842. }
  843. NTSTATUS WmipSendMethodDiagRequest(
  844. PDEVICE_OBJECT DeviceObject,
  845. PSCHEDULEDDIAG Diag,
  846. PWNODE_METHOD_ITEM *WnodeMethodPtr
  847. )
  848. {
  849. PWNODE_METHOD_ITEM WnodeMethod;
  850. NTSTATUS Status;
  851. ULONG SizeNeeded, DataOffset, InstanceOffset;
  852. BOOLEAN Looping;
  853. ULONG ProviderId;
  854. PWCHAR DPtr, SPtr;
  855. IO_STATUS_BLOCK Iosb;
  856. SizeNeeded = sizeof(WNODE_METHOD_ITEM) +
  857. Diag->InstanceContextSize +
  858. ((Diag->OutDataSize > Diag->DataSize) ?
  859. Diag->OutDataSize : Diag->DataSize);
  860. Looping = TRUE;
  861. while(Looping)
  862. {
  863. WnodeMethod = ExAllocatePoolWithTag(NonPagedPool,
  864. SizeNeeded,
  865. WMIPSCHEDPOOLTAG);
  866. if (WnodeMethod != NULL)
  867. {
  868. //
  869. // Build the WNODE to query with
  870. //
  871. RtlZeroMemory(WnodeMethod, SizeNeeded);
  872. ProviderId = IoWMIDeviceObjectToProviderId(DeviceObject);
  873. InstanceOffset = FIELD_OFFSET(WNODE_SINGLE_INSTANCE,
  874. VariableData);
  875. DataOffset = (InstanceOffset +
  876. Diag->InstanceContextSize +
  877. sizeof(USHORT) + 7) &~7;
  878. WnodeMethod->WnodeHeader.BufferSize = DataOffset;
  879. WnodeMethod->WnodeHeader.ProviderId = ProviderId;
  880. WnodeMethod->WnodeHeader.Guid = Diag->Guid;
  881. WnodeMethod->WnodeHeader.Flags = WNODE_FLAG_METHOD_ITEM |
  882. WNODE_FLAG_DIAG_REQUEST;
  883. WnodeMethod->InstanceIndex = Diag->InstanceIndex;
  884. WnodeMethod->OffsetInstanceName = InstanceOffset;
  885. WnodeMethod->MethodId = Diag->MethodId;
  886. if (Diag->InstanceContextOffset != 0)
  887. {
  888. //
  889. // Copy in any instance context
  890. //
  891. DPtr = (PWCHAR)OffsetToPtr(WnodeMethod, InstanceOffset);
  892. SPtr = (PWCHAR)OffsetToPtr(Diag, Diag->InstanceContextOffset);
  893. *DPtr++ = (USHORT)Diag->InstanceContextSize;
  894. RtlCopyMemory(DPtr, SPtr, Diag->InstanceContextSize);
  895. } else {
  896. WnodeMethod->WnodeHeader.Flags |= WNODE_FLAG_STATIC_INSTANCE_NAMES;
  897. }
  898. WnodeMethod->DataBlockOffset = DataOffset;
  899. WnodeMethod->SizeDataBlock = Diag->DataSize;
  900. if (Diag->DataSize != 0)
  901. {
  902. //
  903. // Copy in method input data
  904. //
  905. DPtr = (PWCHAR)OffsetToPtr(WnodeMethod, DataOffset);
  906. SPtr = (PWCHAR)OffsetToPtr(Diag, Diag->DataOffset);
  907. RtlCopyMemory(DPtr, SPtr, Diag->DataSize);
  908. }
  909. Status = WmipSendWmiIrp(IRP_MN_EXECUTE_METHOD,
  910. ProviderId,
  911. &WnodeMethod->WnodeHeader.Guid,
  912. SizeNeeded,
  913. WnodeMethod,
  914. &Iosb);
  915. if (NT_SUCCESS(Status))
  916. {
  917. if (Iosb.Information == sizeof(WNODE_TOO_SMALL))
  918. {
  919. //
  920. // Buffer was too small, so setup to alloc a bigger one
  921. //
  922. SizeNeeded = ((PWNODE_TOO_SMALL)WnodeMethod)->SizeNeeded;
  923. ExFreePool(WnodeMethod);
  924. } else {
  925. //
  926. // We have successfully returned from the query
  927. //
  928. *WnodeMethodPtr = WnodeMethod;
  929. Looping = FALSE;
  930. }
  931. } else {
  932. //
  933. // Some sort of failure, we just return it to the caller
  934. //
  935. ExFreePool(WnodeMethod);
  936. Looping = FALSE;
  937. }
  938. } else {
  939. Status = STATUS_INSUFFICIENT_RESOURCES;
  940. Looping = FALSE;
  941. }
  942. }
  943. return(Status);
  944. }
  945. NTSTATUS WmipSendQSIDiagRequest(
  946. PDEVICE_OBJECT DeviceObject,
  947. PSCHEDULEDDIAG Diag,
  948. PWNODE_SINGLE_INSTANCE *WnodeSIPtr
  949. )
  950. {
  951. PWNODE_SINGLE_INSTANCE WnodeSI;
  952. NTSTATUS Status;
  953. ULONG SizeNeeded, DataOffset, InstanceOffset;
  954. BOOLEAN Looping;
  955. ULONG ProviderId;
  956. PWCHAR SPtr, DPtr;
  957. IO_STATUS_BLOCK Iosb;
  958. SizeNeeded = sizeof(WNODE_SINGLE_INSTANCE) +
  959. Diag->InstanceContextSize +
  960. (Diag->OutDataSize > Diag->DataSize) ?
  961. Diag->OutDataSize : Diag->DataSize;
  962. Looping = TRUE;
  963. while(Looping)
  964. {
  965. WnodeSI = ExAllocatePoolWithTag(NonPagedPool,
  966. SizeNeeded,
  967. WMIPSCHEDPOOLTAG);
  968. if (WnodeSI != NULL)
  969. {
  970. //
  971. // Build the WNODE to query with
  972. //
  973. RtlZeroMemory(WnodeSI, SizeNeeded);
  974. ProviderId = IoWMIDeviceObjectToProviderId(DeviceObject);
  975. InstanceOffset = FIELD_OFFSET(WNODE_SINGLE_INSTANCE,
  976. VariableData);
  977. DataOffset = (InstanceOffset +
  978. Diag->InstanceContextSize +
  979. sizeof(USHORT) + 7) &~7;
  980. WnodeSI->WnodeHeader.BufferSize = DataOffset;
  981. WnodeSI->WnodeHeader.ProviderId = ProviderId;
  982. WnodeSI->WnodeHeader.Guid = Diag->Guid;
  983. WnodeSI->WnodeHeader.Flags = WNODE_FLAG_SINGLE_INSTANCE |
  984. WNODE_FLAG_DIAG_REQUEST;
  985. WnodeSI->InstanceIndex = Diag->InstanceIndex;
  986. WnodeSI->OffsetInstanceName = InstanceOffset;
  987. if (Diag->InstanceContextOffset != 0)
  988. {
  989. //
  990. // Copy in any instance context
  991. //
  992. DPtr = (PWCHAR)OffsetToPtr(WnodeSI, InstanceOffset);
  993. SPtr = (PWCHAR)OffsetToPtr(Diag, Diag->InstanceContextOffset);
  994. *DPtr++ = (USHORT)Diag->InstanceContextSize;
  995. RtlCopyMemory(DPtr, SPtr, Diag->InstanceContextSize);
  996. } else {
  997. WnodeSI->WnodeHeader.Flags |= WNODE_FLAG_STATIC_INSTANCE_NAMES;
  998. }
  999. WnodeSI->DataBlockOffset = DataOffset;
  1000. Status = WmipSendWmiIrp(IRP_MN_QUERY_SINGLE_INSTANCE,
  1001. ProviderId,
  1002. &WnodeSI->WnodeHeader.Guid,
  1003. SizeNeeded,
  1004. WnodeSI,
  1005. &Iosb);
  1006. if (NT_SUCCESS(Status))
  1007. {
  1008. if (Iosb.Information == sizeof(WNODE_TOO_SMALL))
  1009. {
  1010. //
  1011. // Buffer was too small, so setup to alloc a bigger one
  1012. //
  1013. SizeNeeded = ((PWNODE_TOO_SMALL)WnodeSI)->SizeNeeded;
  1014. ExFreePool(WnodeSI);
  1015. } else {
  1016. //
  1017. // We have successfully returned from the query
  1018. //
  1019. *WnodeSIPtr = WnodeSI;
  1020. Looping = FALSE;
  1021. }
  1022. } else {
  1023. //
  1024. // Some sort of failure, we just return it to the caller
  1025. //
  1026. ExFreePool(WnodeSI);
  1027. Looping = FALSE;
  1028. }
  1029. } else {
  1030. Status = STATUS_INSUFFICIENT_RESOURCES;
  1031. Looping = FALSE;
  1032. }
  1033. }
  1034. return(Status);
  1035. }
  1036. NTSTATUS IoWMIStartScheduledDiagnostics(
  1037. IN PDEVICE_OBJECT DeviceObject,
  1038. IN PUNICODE_STRING DiagSet
  1039. )
  1040. {
  1041. NTSTATUS Status, Status2;
  1042. HANDLE Key;
  1043. UNICODE_STRING Scheduled;
  1044. ULONG Index;
  1045. KEY_FULL_INFORMATION KeyFullInfo;
  1046. ULONG ReturnSize;
  1047. PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
  1048. ULONG InfoSize;
  1049. PUCHAR DiagData;
  1050. ULONG DiagSize;
  1051. PSCHEDULEDDIAG Diag;
  1052. ULONG Offset;
  1053. PWNODE_SINGLE_INSTANCE WnodeSI;
  1054. PWNODE_METHOD_ITEM WnodeMethod;
  1055. UNICODE_STRING Checkpoint;
  1056. PUCHAR InstanceContext;
  1057. PUCHAR Data;
  1058. PAGED_CODE();
  1059. RtlInitUnicodeString(&Scheduled, REGSTR_SCHEDULED);
  1060. RtlInitUnicodeString(&Checkpoint, REGSTR_CHECKPOINT);
  1061. Status = WmipOpenDiagRegKey(DeviceObject,
  1062. &Scheduled,
  1063. KEY_READ,
  1064. FALSE,
  1065. &Key);
  1066. if (NT_SUCCESS(Status))
  1067. {
  1068. Status = WmipReadValueKey(Key,
  1069. DiagSet,
  1070. REG_BINARY,
  1071. &PartialInfo,
  1072. &InfoSize);
  1073. if (NT_SUCCESS(Status))
  1074. {
  1075. //
  1076. // Loop over all Diags in the value and then send them
  1077. // to the device
  1078. //
  1079. DiagData = &PartialInfo->Data[0];
  1080. DiagSize = PartialInfo->DataLength;
  1081. Offset = 0;
  1082. while (Offset < DiagSize)
  1083. {
  1084. //
  1085. // Send the appropriate diag to the device object
  1086. //
  1087. Diag = (PSCHEDULEDDIAG)OffsetToPtr(DiagData, Offset);
  1088. if (Diag->IsValid)
  1089. {
  1090. switch(Diag->IrpMn)
  1091. {
  1092. case IRP_MN_QUERY_SINGLE_INSTANCE:
  1093. {
  1094. PWNODE_SINGLE_INSTANCE WnodeSI;
  1095. Status2 = WmipSendQSIDiagRequest(DeviceObject,
  1096. Diag,
  1097. &WnodeSI);
  1098. if (NT_SUCCESS(Status2))
  1099. {
  1100. if (Diag->InstanceContextOffset != 0)
  1101. {
  1102. InstanceContext = OffsetToPtr(Diag,
  1103. Diag->InstanceContextOffset);
  1104. } else {
  1105. InstanceContext = NULL;
  1106. }
  1107. Data = OffsetToPtr(WnodeSI,
  1108. WnodeSI->DataBlockOffset);
  1109. Status2 = WmipUpdateOrAppendDiag(
  1110. DeviceObject,
  1111. &Checkpoint,
  1112. DiagSet,
  1113. Diag->IrpMn,
  1114. &Diag->Guid,
  1115. Diag->InstanceContextSize,
  1116. InstanceContext,
  1117. Diag->InstanceIndex,
  1118. Diag->MethodId,
  1119. WnodeSI->SizeDataBlock,
  1120. Data);
  1121. ExFreePool(WnodeSI);
  1122. }
  1123. break;
  1124. }
  1125. case IRP_MN_EXECUTE_METHOD:
  1126. {
  1127. PWNODE_METHOD_ITEM WnodeMethod;
  1128. Status2 = WmipSendMethodDiagRequest(DeviceObject,
  1129. Diag,
  1130. &WnodeMethod);
  1131. if (NT_SUCCESS(Status2))
  1132. {
  1133. if (Diag->InstanceContextOffset != 0)
  1134. {
  1135. InstanceContext = OffsetToPtr(Diag,
  1136. Diag->InstanceContextOffset);
  1137. } else {
  1138. InstanceContext = NULL;
  1139. }
  1140. Data = OffsetToPtr(WnodeMethod,
  1141. WnodeMethod->DataBlockOffset);
  1142. Status2 = WmipUpdateOrAppendDiag(
  1143. DeviceObject,
  1144. &Checkpoint,
  1145. DiagSet,
  1146. Diag->IrpMn,
  1147. &Diag->Guid,
  1148. Diag->InstanceContextSize,
  1149. InstanceContext,
  1150. Diag->InstanceIndex,
  1151. Diag->MethodId,
  1152. WnodeMethod->SizeDataBlock,
  1153. Data);
  1154. ExFreePool(WnodeMethod);
  1155. }
  1156. break;
  1157. }
  1158. default:
  1159. {
  1160. WmipAssert(FALSE);
  1161. break;
  1162. }
  1163. }
  1164. }
  1165. //
  1166. // Advance to next diagnostic in
  1167. //
  1168. Offset += Diag->NextOffset;
  1169. }
  1170. ExFreePool(PartialInfo);
  1171. }
  1172. ZwClose(Key);
  1173. }
  1174. return(Status);
  1175. }
  1176. NTSTATUS IoWMIGetDiagnosticResult(
  1177. IN PDEVICE_OBJECT DeviceObject,
  1178. IN PUNICODE_STRING DiagSet,
  1179. IN UCHAR IrpMn,
  1180. IN LPGUID Guid,
  1181. IN ULONG InstanceContextSize,
  1182. IN PUCHAR InstanceContext,
  1183. IN ULONG InstanceIndex,
  1184. IN ULONG MethodId,
  1185. IN OUT ULONG *DataSize,
  1186. OUT PUCHAR Data
  1187. )
  1188. {
  1189. NTSTATUS Status;
  1190. UNICODE_STRING Checkpoint;
  1191. HANDLE Key;
  1192. PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
  1193. ULONG InfoSize;
  1194. PUCHAR DiagList;
  1195. PSCHEDULEDDIAG Diag;
  1196. ULONG DiagSize;
  1197. PUCHAR DataPtr;
  1198. PAGED_CODE();
  1199. RtlInitUnicodeString(&Checkpoint, REGSTR_CHECKPOINT);
  1200. Status = WmipOpenDiagRegKey(DeviceObject,
  1201. &Checkpoint,
  1202. KEY_READ,
  1203. FALSE,
  1204. &Key);
  1205. if (NT_SUCCESS(Status))
  1206. {
  1207. Status = WmipReadValueKey(Key,
  1208. DiagSet,
  1209. REG_BINARY,
  1210. &PartialInfo,
  1211. &InfoSize);
  1212. if (NT_SUCCESS(Status))
  1213. {
  1214. //
  1215. // See if a diag is available that matches the sig passed
  1216. //
  1217. DiagList = &PartialInfo->Data[0];
  1218. DiagSize = PartialInfo->DataLength;
  1219. Diag = WmipFindDiagInBuffer(DiagList,
  1220. DiagSize,
  1221. IrpMn,
  1222. Guid,
  1223. InstanceContextSize,
  1224. InstanceContext,
  1225. InstanceIndex,
  1226. MethodId);
  1227. if (Diag != NULL)
  1228. {
  1229. if (Diag->DataOffset != 0)
  1230. {
  1231. if (*DataSize >= Diag->DataSize)
  1232. {
  1233. //
  1234. // There is enough room, so copy out the data
  1235. //
  1236. DataPtr = OffsetToPtr(Diag, Diag->DataOffset);
  1237. RtlCopyMemory(Data, DataPtr, Diag->DataSize);
  1238. } else {
  1239. //
  1240. // Not enough room to return the data
  1241. //
  1242. Status = STATUS_BUFFER_TOO_SMALL;
  1243. }
  1244. *DataSize = Diag->DataSize;
  1245. } else {
  1246. //
  1247. // There is no data for this diag result
  1248. //
  1249. *DataSize = 0;
  1250. }
  1251. } else {
  1252. //
  1253. // Diag was not in the list
  1254. //
  1255. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  1256. }
  1257. ExFreePool(PartialInfo);
  1258. }
  1259. }
  1260. return(Status);
  1261. }
  1262. NTSTATUS IoWMISaveDiagnosticResult(
  1263. IN PDEVICE_OBJECT DeviceObject,
  1264. IN PUNICODE_STRING DiagSet,
  1265. IN UCHAR IrpMn,
  1266. IN LPGUID Guid,
  1267. IN ULONG InstanceContextSize,
  1268. IN PUCHAR InstanceContext,
  1269. IN ULONG InstanceIndex,
  1270. IN ULONG MethodId,
  1271. IN ULONG DataSize,
  1272. IN PUCHAR Data
  1273. )
  1274. {
  1275. NTSTATUS Status;
  1276. UNICODE_STRING Checkpoint;
  1277. PAGED_CODE();
  1278. //
  1279. // Write saved diagnostic results into the Checkpoint key
  1280. //
  1281. RtlInitUnicodeString(&Checkpoint, REGSTR_CHECKPOINT);
  1282. Status = WmipUpdateOrAppendDiag(DeviceObject,
  1283. &Checkpoint,
  1284. DiagSet,
  1285. IrpMn,
  1286. Guid,
  1287. InstanceContextSize,
  1288. InstanceContext,
  1289. InstanceIndex,
  1290. MethodId,
  1291. DataSize,
  1292. Data);
  1293. return(Status);
  1294. }