1765 lines
53 KiB
C
1765 lines
53 KiB
C
/*++
|
|
|
|
Copyright (c) 1997-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
DataProv.c
|
|
|
|
Abstract:
|
|
|
|
WMI internal data provider interface
|
|
|
|
Author:
|
|
|
|
AlanWar
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "wmikmp.h"
|
|
|
|
#if defined(_IA64_)
|
|
#ifdef MCE_INSERTION
|
|
typedef struct _MCEQUERYINFO MCEQUERYINFO, *PMCEQUERYINFO;
|
|
extern MCEQUERYINFO WmipMcaQueryInfo;
|
|
extern MCEQUERYINFO WmipCmcQueryInfo;
|
|
extern MCEQUERYINFO WmipCpeQueryInfo;
|
|
|
|
NTSTATUS WmipInsertMce(
|
|
PMCEQUERYINFO QueryInfo,
|
|
ULONG LogSize,
|
|
PUCHAR Log
|
|
);
|
|
#endif
|
|
#endif
|
|
|
|
NTSTATUS
|
|
WmipQueryWmiDataBlock(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN ULONG GuidIndex,
|
|
IN ULONG InstanceIndex,
|
|
IN ULONG InstanceCount,
|
|
IN OUT PULONG InstanceLengthArray,
|
|
IN ULONG BufferAvail,
|
|
OUT PUCHAR Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
WmipQueryWmiRegInfo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
OUT ULONG *RegFlags,
|
|
OUT PUNICODE_STRING InstanceName,
|
|
OUT PUNICODE_STRING *RegistryPath
|
|
);
|
|
|
|
NTSTATUS WmipSetWmiDataBlock(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp,
|
|
ULONG GuidIndex,
|
|
ULONG InstanceIndex,
|
|
ULONG BufferSize,
|
|
PUCHAR Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
WmipExecuteWmiMethod (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN ULONG GuidIndex,
|
|
IN ULONG InstanceIndex,
|
|
IN ULONG MethodId,
|
|
IN ULONG InBufferSize,
|
|
IN ULONG OutBufferSize,
|
|
IN OUT PUCHAR Buffer
|
|
);
|
|
|
|
BOOLEAN
|
|
WmipFindGuid(
|
|
IN PGUIDREGINFO GuidList,
|
|
IN ULONG GuidCount,
|
|
IN LPGUID Guid,
|
|
OUT PULONG GuidIndex,
|
|
OUT PULONG InstanceCount
|
|
);
|
|
|
|
NTSTATUS
|
|
IoWMICompleteRequest(
|
|
IN PWMILIB_INFO WmiLibInfo,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN NTSTATUS Status,
|
|
IN ULONG BufferUsed,
|
|
IN CCHAR PriorityBoost
|
|
);
|
|
|
|
NTSTATUS
|
|
IoWMISystemControl(
|
|
IN PWMILIB_INFO WmiLibInfo,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
|
|
|
|
#ifdef ALLOC_DATA_PRAGMA
|
|
#pragma const_seg("PAGECONST")
|
|
#endif
|
|
|
|
#ifdef GENERATE_MCA
|
|
#define GenerateMCEGuid { 0x3001bce4, 0xd9b6, 0x4167, { 0xb5, 0xe1, 0x39, 0xa7, 0x28, 0x59, 0xe2, 0x67 } }
|
|
GUID WmipGenerateMCEGuid = GenerateMCEGuid;
|
|
#endif
|
|
|
|
|
|
const GUIDREGINFO WmipGuidList[] =
|
|
{
|
|
//
|
|
// This is the pnp id guid which is registered by wmi into other device
|
|
// objects' registration info. And requests to the innocent devices
|
|
// are hijacked by wmi so that wmi can complete the request for it. We
|
|
// have the WMIREG_FLAG_REMOVE_GUID set so that the guid is not registered
|
|
// for the wmi device which does not support it.
|
|
{
|
|
DATA_PROVIDER_PNPID_GUID,
|
|
0,
|
|
WMIREG_FLAG_REMOVE_GUID
|
|
},
|
|
|
|
{
|
|
DATA_PROVIDER_PNPID_INSTANCE_NAMES_GUID,
|
|
0,
|
|
WMIREG_FLAG_REMOVE_GUID
|
|
},
|
|
|
|
{
|
|
MSAcpiInfoGuid,
|
|
1,
|
|
0
|
|
},
|
|
|
|
#if defined(_AMD64_) || defined(_IA64_) || defined(i386) || defined(MEMPHIS)
|
|
{
|
|
SMBIOS_DATA_GUID,
|
|
1,
|
|
0
|
|
},
|
|
|
|
{
|
|
SYSID_UUID_DATA_GUID,
|
|
1,
|
|
0
|
|
},
|
|
|
|
{
|
|
SYSID_1394_DATA_GUID,
|
|
1,
|
|
0
|
|
},
|
|
|
|
{
|
|
MSSmBios_SMBiosEventlogGuid,
|
|
1,
|
|
0
|
|
},
|
|
#endif
|
|
|
|
#if defined(_IA64_)
|
|
{
|
|
MSMCAInfo_RawMCADataGuid,
|
|
1,
|
|
0
|
|
},
|
|
|
|
#ifdef CPE_CONTROL
|
|
{
|
|
MSMCAInfo_CPEControlGuid,
|
|
1,
|
|
0
|
|
},
|
|
#endif
|
|
|
|
#ifdef GENERATE_MCA
|
|
{
|
|
GenerateMCEGuid,
|
|
1,
|
|
0
|
|
},
|
|
|
|
#endif
|
|
|
|
{
|
|
MSMCAInfo_RawMCAEventGuid,
|
|
1,
|
|
WMIREG_FLAG_EVENT_ONLY_GUID
|
|
},
|
|
|
|
{
|
|
MSMCAInfo_RawCMCEventGuid,
|
|
1,
|
|
WMIREG_FLAG_EVENT_ONLY_GUID
|
|
},
|
|
|
|
{
|
|
MSMCAInfo_RawCorrectedPlatformEventGuid,
|
|
1,
|
|
WMIREG_FLAG_EVENT_ONLY_GUID
|
|
},
|
|
|
|
#endif
|
|
|
|
};
|
|
#define WmipGuidCount (sizeof(WmipGuidList) / sizeof(GUIDREGINFO))
|
|
|
|
typedef enum
|
|
{
|
|
PnPIdGuidIndex = 0,
|
|
PnPIdInstanceNamesGuidIndex,
|
|
MSAcpiInfoGuidIndex,
|
|
#if defined(_AMD64_) || defined(_IA64_) || defined(i386) || defined(MEMPHIS)
|
|
SmbiosDataGuidIndex,
|
|
SysidUuidGuidIndex,
|
|
Sysid1394GuidIndex,
|
|
SmbiosEventGuidIndex,
|
|
#endif
|
|
#if defined(_IA64_)
|
|
MCARawDataGuidIndex,
|
|
#ifdef CPE_CONTROL
|
|
CPEControlGuidIndex,
|
|
#endif
|
|
#ifdef GENERATE_MCA
|
|
GenerateMCEGuidIndex,
|
|
#endif
|
|
RawMCAEventGuidIndex,
|
|
RawCMCEventGuidIndex,
|
|
RawCPEEventGuidIndex,
|
|
#endif
|
|
} WMIGUIDINDEXES;
|
|
|
|
|
|
const WMILIB_INFO WmipWmiLibInfo =
|
|
{
|
|
NULL,
|
|
NULL,
|
|
WmipGuidCount,
|
|
(PGUIDREGINFO)WmipGuidList,
|
|
WmipQueryWmiRegInfo,
|
|
WmipQueryWmiDataBlock,
|
|
#ifdef CPE_CONTROL
|
|
WmipSetWmiDataBlock,
|
|
#else
|
|
NULL,
|
|
#endif
|
|
NULL,
|
|
#ifdef GENERATE_MCA
|
|
WmipExecuteWmiMethod,
|
|
#else
|
|
NULL,
|
|
#endif
|
|
NULL
|
|
};
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE,WmipQueryWmiRegInfo)
|
|
#pragma alloc_text(PAGE,WmipQueryWmiDataBlock)
|
|
#pragma alloc_text(PAGE,WmipSetWmiDataBlock)
|
|
#pragma alloc_text(PAGE,WmipExecuteWmiMethod)
|
|
#pragma alloc_text(PAGE,WmipFindGuid)
|
|
#pragma alloc_text(PAGE,IoWMISystemControl)
|
|
#pragma alloc_text(PAGE,IoWMICompleteRequest)
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
WmipQueryWmiRegInfo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
OUT ULONG *RegFlags,
|
|
OUT PUNICODE_STRING InstanceName,
|
|
OUT PUNICODE_STRING *RegistryPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is a callback into the driver to retrieve the list of
|
|
guids or data blocks that the driver wants to register with WMI. This
|
|
routine may not pend or block. Driver should NOT call
|
|
ClassWmiCompleteRequest.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject is the device whose data block is being queried
|
|
|
|
*RegFlags returns with a set of flags that describe the guids being
|
|
registered for this device. If the device wants enable and disable
|
|
collection callbacks before receiving queries for the registered
|
|
guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the
|
|
returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case
|
|
the instance name is determined from the PDO associated with the
|
|
device object. Note that the PDO must have an associated devnode. If
|
|
WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique
|
|
name for the device.
|
|
|
|
InstanceName returns with the instance name for the guids if
|
|
WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The
|
|
caller will call ExFreePool with the buffer returned.
|
|
|
|
*RegistryPath returns with the registry path of the driver
|
|
|
|
Return Value:
|
|
|
|
status
|
|
|
|
--*/
|
|
{
|
|
ANSI_STRING AnsiString;
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
*RegistryPath = &WmipRegistryPath;
|
|
|
|
RtlInitAnsiString(&AnsiString, "SMBiosData");
|
|
|
|
Status = RtlAnsiStringToUnicodeString(InstanceName, &AnsiString, TRUE);
|
|
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
WmipQueryWmiDataBlock(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN ULONG GuidIndex,
|
|
IN ULONG InstanceIndex,
|
|
IN ULONG InstanceCount,
|
|
IN OUT PULONG InstanceLengthArray,
|
|
IN ULONG BufferAvail,
|
|
OUT PUCHAR Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is a callback into the driver to query for the contents of
|
|
all instances of a data block. When the driver has finished filling the
|
|
data block it must call IoWMICompleteRequest to complete the irp. The
|
|
driver can return STATUS_PENDING if the irp cannot be completed
|
|
immediately.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject is the device whose data block is being queried. In the case
|
|
of the PnPId guid this is the device object of the device on whose
|
|
behalf the request is being processed.
|
|
|
|
Irp is the Irp that makes this request
|
|
|
|
GuidIndex is the index into the list of guids provided when the
|
|
device registered
|
|
|
|
InstanceCount is the number of instnaces expected to be returned for
|
|
the data block.
|
|
|
|
InstanceLengthArray is a pointer to an array of ULONG that returns the
|
|
lengths of each instance of the data block. If this is NULL then
|
|
there was not enough space in the output buffer to fufill the request
|
|
so the irp should be completed with the buffer needed.
|
|
|
|
BufferAvail on entry has the maximum size available to write the data
|
|
blocks.
|
|
|
|
Buffer on return is filled with the returned data blocks. Note that each
|
|
instance of the data block must be aligned on a 8 byte boundry.
|
|
|
|
|
|
Return Value:
|
|
|
|
status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
|
ULONG sizeNeeded = 0, sizeSMBios;
|
|
PUCHAR BufferPtr;
|
|
PSMBIOSVERSIONINFO SMBiosVersionInfo;
|
|
PULONG TableSize;
|
|
|
|
PAGED_CODE();
|
|
|
|
switch (GuidIndex)
|
|
{
|
|
case SmbiosDataGuidIndex:
|
|
{
|
|
//
|
|
// SMBIOS data table query
|
|
#if defined(_AMD64_) || defined(_IA64_) || defined(i386) || defined(MEMPHIS)
|
|
WmipAssert((InstanceIndex == 0) && (InstanceCount == 1));
|
|
|
|
sizeNeeded = sizeof(SMBIOSVERSIONINFO) + sizeof(ULONG);
|
|
if (BufferAvail >= sizeNeeded)
|
|
{
|
|
sizeSMBios = BufferAvail - sizeNeeded;
|
|
SMBiosVersionInfo = (PSMBIOSVERSIONINFO)Buffer;
|
|
TableSize = (PULONG) (Buffer + sizeof(SMBIOSVERSIONINFO));
|
|
BufferPtr = Buffer + sizeNeeded;
|
|
} else {
|
|
sizeSMBios = 0;
|
|
BufferPtr = NULL;
|
|
SMBiosVersionInfo = NULL;
|
|
}
|
|
|
|
status = WmipGetSMBiosTableData(BufferPtr,
|
|
&sizeSMBios,
|
|
SMBiosVersionInfo);
|
|
|
|
sizeNeeded += sizeSMBios;
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
*(TableSize) = sizeSMBios;
|
|
*InstanceLengthArray = sizeNeeded;
|
|
}
|
|
#else
|
|
status = STATUS_WMI_GUID_NOT_FOUND;
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
case PnPIdGuidIndex:
|
|
{
|
|
PDEVICE_OBJECT pDO;
|
|
UNICODE_STRING instancePath;
|
|
PREGENTRY regEntry;
|
|
ULONG dataBlockSize, paddedDataBlockSize, padSize;
|
|
ULONG i;
|
|
|
|
regEntry = WmipFindRegEntryByDevice(DeviceObject, FALSE);
|
|
if (regEntry != NULL)
|
|
{
|
|
pDO = regEntry->PDO;
|
|
WmipAssert(pDO != NULL);
|
|
|
|
if (pDO != NULL)
|
|
{
|
|
status = WmipPDOToDeviceInstanceName(pDO, &instancePath);
|
|
} else {
|
|
status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
dataBlockSize = instancePath.Length + sizeof(USHORT);
|
|
paddedDataBlockSize = (dataBlockSize + 7) & ~7;
|
|
padSize = paddedDataBlockSize - dataBlockSize;
|
|
sizeNeeded = paddedDataBlockSize * InstanceCount;
|
|
if (sizeNeeded <= BufferAvail)
|
|
{
|
|
for (i = InstanceIndex;
|
|
i < (InstanceIndex + InstanceCount);
|
|
i++)
|
|
{
|
|
*InstanceLengthArray++ = dataBlockSize;
|
|
*((PUSHORT)Buffer) = instancePath.Length;
|
|
Buffer += sizeof(USHORT);
|
|
RtlCopyMemory(Buffer,
|
|
instancePath.Buffer,
|
|
instancePath.Length);
|
|
Buffer += instancePath.Length;
|
|
RtlZeroMemory(Buffer, padSize);
|
|
Buffer += padSize;
|
|
}
|
|
} else {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
RtlFreeUnicodeString(&instancePath);
|
|
|
|
} else {
|
|
status = STATUS_WMI_GUID_NOT_FOUND;
|
|
}
|
|
WmipUnreferenceRegEntry(regEntry);
|
|
} else {
|
|
WmipAssert(FALSE);
|
|
status = STATUS_WMI_GUID_NOT_FOUND;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case PnPIdInstanceNamesGuidIndex:
|
|
{
|
|
PDEVICE_OBJECT pDO;
|
|
UNICODE_STRING instancePath;
|
|
PREGENTRY regEntry;
|
|
|
|
regEntry = WmipFindRegEntryByDevice(DeviceObject, FALSE);
|
|
if (regEntry != NULL)
|
|
{
|
|
pDO = regEntry->PDO;
|
|
WmipAssert(pDO != NULL);
|
|
|
|
if (pDO != NULL)
|
|
{
|
|
status = WmipPDOToDeviceInstanceName(pDO, &instancePath);
|
|
} else {
|
|
status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
sizeNeeded = sizeof(ULONG) +
|
|
instancePath.Length + 2 * sizeof(WCHAR) +
|
|
sizeof(USHORT);
|
|
|
|
if (sizeNeeded <= BufferAvail)
|
|
{
|
|
*((PULONG)Buffer) = 1;
|
|
Buffer += sizeof(ULONG);
|
|
*InstanceLengthArray = sizeNeeded;
|
|
*((PUSHORT)Buffer) = instancePath.Length + 2*sizeof(WCHAR);
|
|
Buffer += sizeof(USHORT);
|
|
RtlCopyMemory(Buffer,
|
|
instancePath.Buffer,
|
|
instancePath.Length);
|
|
Buffer += instancePath.Length;
|
|
*((PWCHAR)Buffer) = '_';
|
|
Buffer += sizeof(WCHAR);
|
|
*((PWCHAR)Buffer) = '0';
|
|
} else {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
RtlFreeUnicodeString(&instancePath);
|
|
|
|
} else {
|
|
status = STATUS_WMI_GUID_NOT_FOUND;
|
|
}
|
|
WmipUnreferenceRegEntry(regEntry);
|
|
} else {
|
|
WmipAssert(FALSE);
|
|
status = STATUS_WMI_GUID_NOT_FOUND;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case MSAcpiInfoGuidIndex:
|
|
{
|
|
RTL_QUERY_REGISTRY_TABLE queryTable[4];
|
|
ULONG bootArchitecture = 0;
|
|
ULONG preferredProfile = 0;
|
|
ULONG capabilities = 0;
|
|
|
|
queryTable[0].QueryRoutine = NULL;
|
|
queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT |
|
|
RTL_QUERY_REGISTRY_REQUIRED;
|
|
queryTable[0].Name = L"BootArchitecture";
|
|
queryTable[0].EntryContext = &bootArchitecture;
|
|
queryTable[0].DefaultType = REG_NONE;
|
|
|
|
queryTable[1].QueryRoutine = NULL;
|
|
queryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT |
|
|
RTL_QUERY_REGISTRY_REQUIRED;
|
|
queryTable[1].Name = L"PreferredProfile";
|
|
queryTable[1].EntryContext = &preferredProfile;
|
|
queryTable[1].DefaultType = REG_NONE;
|
|
|
|
queryTable[2].QueryRoutine = NULL;
|
|
queryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT |
|
|
RTL_QUERY_REGISTRY_REQUIRED;
|
|
queryTable[2].Name = L"Capabilities";
|
|
queryTable[2].EntryContext = &capabilities;
|
|
queryTable[2].DefaultType = REG_NONE;
|
|
|
|
queryTable[3].QueryRoutine = NULL;
|
|
queryTable[3].Flags = 0;
|
|
|
|
status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
|
|
L"\\Registry\\Machine\\Hardware\\Description\\System",
|
|
queryTable,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
sizeNeeded = sizeof(MSAcpiInfo);
|
|
if (sizeNeeded <= BufferAvail)
|
|
{
|
|
PMSAcpiInfo info = (PMSAcpiInfo)Buffer;
|
|
info->BootArchitecture = bootArchitecture;
|
|
info->PreferredProfile = preferredProfile;
|
|
info->Capabilities = capabilities;
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
} else {
|
|
status = STATUS_WMI_GUID_NOT_FOUND;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case Sysid1394GuidIndex:
|
|
case SysidUuidGuidIndex:
|
|
{
|
|
PSYSID_UUID uuid;
|
|
ULONG uuidCount;
|
|
PSYSID_1394 x1394;
|
|
ULONG x1394Count;
|
|
PUCHAR data;
|
|
ULONG count;
|
|
|
|
#if defined(_AMD64_) || defined(_IA64_) || defined(i386) || defined(MEMPHIS)
|
|
|
|
status = WmipGetSysIds(&uuid,
|
|
&uuidCount,
|
|
&x1394,
|
|
&x1394Count);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
if (GuidIndex == Sysid1394GuidIndex)
|
|
{
|
|
sizeNeeded = x1394Count * sizeof(SYSID_1394) +
|
|
sizeof(ULONG);
|
|
data = (PUCHAR)x1394;
|
|
count = x1394Count;
|
|
} else {
|
|
sizeNeeded = uuidCount * sizeof(SYSID_UUID) +
|
|
sizeof(ULONG);
|
|
data = (PUCHAR)uuid;
|
|
count = uuidCount;
|
|
}
|
|
|
|
if (BufferAvail >= sizeNeeded)
|
|
{
|
|
*InstanceLengthArray = sizeNeeded;
|
|
*((PULONG)Buffer) = count;
|
|
Buffer += sizeof(ULONG);
|
|
RtlCopyMemory(Buffer, data, sizeNeeded-sizeof(ULONG));
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
}
|
|
#else
|
|
status = STATUS_WMI_GUID_NOT_FOUND;
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
|
|
case SmbiosEventGuidIndex:
|
|
{
|
|
//
|
|
// SMBIOS eventlog query
|
|
|
|
#if defined(_AMD64_) || defined(_IA64_) || defined(i386) || defined(MEMPHIS)
|
|
WmipAssert((InstanceIndex == 0) && (InstanceCount == 1));
|
|
|
|
if (BufferAvail == 0)
|
|
{
|
|
sizeNeeded = 0;
|
|
BufferPtr = NULL;
|
|
} else {
|
|
sizeNeeded = BufferAvail;
|
|
BufferPtr = Buffer;
|
|
}
|
|
|
|
status = WmipGetSMBiosEventlog(BufferPtr, &sizeNeeded);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
*InstanceLengthArray = sizeNeeded;
|
|
}
|
|
#else
|
|
status = STATUS_WMI_GUID_NOT_FOUND;
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
#if defined(_IA64_)
|
|
case MCARawDataGuidIndex:
|
|
{
|
|
PULONG ptr;
|
|
ULONG size;
|
|
|
|
if (WmipRawMCA != NULL)
|
|
{
|
|
//
|
|
// MCA data is available from last boot so return that
|
|
// to the caller
|
|
//
|
|
sizeNeeded = 2 * sizeof(ULONG) + WmipRawMCASize;
|
|
if (BufferAvail >= sizeNeeded)
|
|
{
|
|
ptr = (PULONG)Buffer;
|
|
*ptr++ = 1; // 1 MCA record
|
|
*ptr++ = WmipRawMCASize; // record size
|
|
size = BufferAvail - 2*sizeof(ULONG);
|
|
status = WmipGetRawMCAInfo((PUCHAR)ptr,
|
|
&size);
|
|
if (status == STATUS_BUFFER_TOO_SMALL)
|
|
{
|
|
sizeNeeded = size + 2*sizeof(ULONG);
|
|
}
|
|
} else {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
} else {
|
|
//
|
|
// MCA data is not available so return 0 records
|
|
//
|
|
sizeNeeded = sizeof(ULONG);
|
|
if (BufferAvail >= sizeNeeded)
|
|
{
|
|
ptr = (PULONG)Buffer;
|
|
*ptr = 0;
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
}
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
*InstanceLengthArray = sizeNeeded;
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// For now don't expose the CPE control guid
|
|
//
|
|
#ifdef CPE_CONTROL
|
|
case CPEControlGuidIndex:
|
|
{
|
|
sizeNeeded = sizeof(MSMCAInfo_CPEControl);
|
|
if (BufferAvail >= sizeNeeded)
|
|
{
|
|
PMSMCAInfo_CPEControl cpeControl;
|
|
|
|
cpeControl = (PMSMCAInfo_CPEControl)Buffer;
|
|
cpeControl->CPEPollingInterval = WmipCpePollInterval;
|
|
cpeControl->CPEGenerationEnabled = (WmipCpePollInterval != HAL_CPE_DISABLED) ?
|
|
TRUE :
|
|
FALSE;
|
|
*InstanceLengthArray = sizeNeeded;
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
#ifdef GENERATE_MCA
|
|
case GenerateMCEGuidIndex:
|
|
{
|
|
sizeNeeded = sizeof(ULONG);
|
|
if (BufferAvail >= sizeNeeded)
|
|
{
|
|
*((PULONG)Buffer) = 0;
|
|
*InstanceLengthArray = sizeNeeded;
|
|
} else {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
default:
|
|
{
|
|
WmipAssert(FALSE);
|
|
status = STATUS_WMI_GUID_NOT_FOUND;
|
|
break;
|
|
}
|
|
}
|
|
|
|
status = IoWMICompleteRequest((PWMILIB_INFO)&WmipWmiLibInfo,
|
|
DeviceObject,
|
|
Irp,
|
|
status,
|
|
sizeNeeded,
|
|
IO_NO_INCREMENT);
|
|
return(status);
|
|
}
|
|
|
|
|
|
#ifdef CPE_CONTROL
|
|
NTSTATUS WmipSetWmiDataBlock(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp,
|
|
ULONG GuidIndex,
|
|
ULONG InstanceIndex,
|
|
ULONG BufferSize,
|
|
PUCHAR Buffer
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
ULONG sizeNeeded;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (GuidIndex == CPEControlGuidIndex)
|
|
{
|
|
sizeNeeded = FIELD_OFFSET(MSMCAInfo_CPEControl,
|
|
CPEGenerationEnabled) +
|
|
sizeof(BOOLEAN);
|
|
if (BufferSize == sizeNeeded)
|
|
{
|
|
PMSMCAInfo_CPEControl cpeControl;
|
|
|
|
cpeControl = (PMSMCAInfo_CPEControl)Buffer;
|
|
status = WmipSetCPEPolling(cpeControl->CPEGenerationEnabled,
|
|
cpeControl->CPEPollingInterval);
|
|
} else {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
} else {
|
|
status = STATUS_WMI_READ_ONLY;
|
|
}
|
|
|
|
status = IoWMICompleteRequest((PWMILIB_INFO)&WmipWmiLibInfo,
|
|
DeviceObject,
|
|
Irp,
|
|
status,
|
|
0,
|
|
IO_NO_INCREMENT);
|
|
return(status);
|
|
}
|
|
#endif
|
|
|
|
#ifdef GENERATE_MCA
|
|
NTSTATUS
|
|
WmipExecuteWmiMethod (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN ULONG GuidIndex,
|
|
IN ULONG InstanceIndex,
|
|
IN ULONG MethodId,
|
|
IN ULONG InBufferSize,
|
|
IN ULONG OutBufferSize,
|
|
IN OUT PUCHAR Buffer
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
ULONG sizeNeeded;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (GuidIndex == GenerateMCEGuidIndex)
|
|
{
|
|
switch (MethodId)
|
|
{
|
|
//
|
|
// MCA insertion by ID
|
|
//
|
|
case 1:
|
|
{
|
|
if (InBufferSize == sizeof(ULONG))
|
|
{
|
|
sizeNeeded = sizeof(NTSTATUS);
|
|
if (OutBufferSize >= sizeNeeded)
|
|
{
|
|
status = WmipGenerateMCE(*((PULONG)Buffer));
|
|
*((NTSTATUS *)Buffer) = status;
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
} else {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Corrected MCA insertion by fully formed MCA exception
|
|
//
|
|
case 2:
|
|
{
|
|
#ifdef MCE_INSERTION
|
|
status = WmipInsertMce(&WmipCmcQueryInfo,
|
|
InBufferSize,
|
|
Buffer);
|
|
#else
|
|
WmipGenerateMCAEventlog(Buffer,
|
|
InBufferSize,
|
|
FALSE);
|
|
status = STATUS_SUCCESS;
|
|
#endif
|
|
sizeNeeded = 0;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Fatal MCA insertion by fully formed MCA exception
|
|
//
|
|
case 3:
|
|
{
|
|
#ifdef MCE_INSERTION
|
|
status = WmipInsertMce(&WmipCpeQueryInfo,
|
|
InBufferSize,
|
|
Buffer);
|
|
#else
|
|
WmipGenerateMCAEventlog(Buffer,
|
|
InBufferSize,
|
|
TRUE);
|
|
status = STATUS_SUCCESS;
|
|
#endif
|
|
sizeNeeded = 0;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
status = STATUS_WMI_ITEMID_NOT_FOUND;
|
|
}
|
|
}
|
|
} else {
|
|
status = STATUS_WMI_GUID_NOT_FOUND;
|
|
}
|
|
|
|
status = IoWMICompleteRequest((PWMILIB_INFO)&WmipWmiLibInfo,
|
|
DeviceObject,
|
|
Irp,
|
|
status,
|
|
sizeNeeded,
|
|
IO_NO_INCREMENT);
|
|
|
|
return(status);
|
|
}
|
|
#endif
|
|
|
|
BOOLEAN
|
|
WmipFindGuid(
|
|
IN PGUIDREGINFO GuidList,
|
|
IN ULONG GuidCount,
|
|
IN LPGUID Guid,
|
|
OUT PULONG GuidIndex,
|
|
OUT PULONG InstanceCount
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will search the list of guids registered and return
|
|
the index for the one that was registered.
|
|
|
|
Arguments:
|
|
|
|
GuidList is the list of guids to search
|
|
|
|
GuidCount is the count of guids in the list
|
|
|
|
Guid is the guid being searched for
|
|
|
|
*GuidIndex returns the index to the guid
|
|
|
|
*InstanceCount returns the count of instances for the guid
|
|
|
|
Return Value:
|
|
|
|
TRUE if guid is found else FALSE
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
|
|
PAGED_CODE();
|
|
|
|
for (i = 0; i < GuidCount; i++)
|
|
{
|
|
if (IsEqualGUID(Guid, &GuidList[i].Guid))
|
|
{
|
|
*GuidIndex = i;
|
|
*InstanceCount = GuidList[i].InstanceCount;
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
IoWMISystemControl(
|
|
IN PWMILIB_INFO WmiLibInfo,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dispatch routine for IRP_MJ_SYSTEM_CONTROL. This routine will process
|
|
all wmi requests received, forwarding them if they are not for this
|
|
driver or determining if the guid is valid and if so passing it to
|
|
the driver specific function for handing wmi requests.
|
|
|
|
Arguments:
|
|
|
|
WmiLibInfo has the WMI information control block
|
|
|
|
DeviceObject - Supplies a pointer to the device object for this request.
|
|
|
|
Irp - Supplies the Irp making the request.
|
|
|
|
Return Value:
|
|
|
|
status
|
|
|
|
--*/
|
|
|
|
{
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
ULONG bufferSize;
|
|
PUCHAR buffer;
|
|
NTSTATUS status;
|
|
ULONG retSize;
|
|
UCHAR minorFunction;
|
|
ULONG guidIndex;
|
|
ULONG instanceCount;
|
|
ULONG instanceIndex;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// If the irp is not a WMI irp or it is not targetted at this device
|
|
// or this device has not regstered with WMI then just forward it on.
|
|
minorFunction = irpStack->MinorFunction;
|
|
if ((minorFunction > IRP_MN_REGINFO_EX) ||
|
|
(irpStack->Parameters.WMI.ProviderId != (ULONG_PTR)DeviceObject) ||
|
|
(((minorFunction != IRP_MN_REGINFO) &&
|
|
((minorFunction != IRP_MN_REGINFO_EX))) &&
|
|
(WmiLibInfo->GuidList == NULL)))
|
|
{
|
|
//
|
|
// IRP is not for us so forward if there is a lower device object
|
|
if (WmiLibInfo->LowerDeviceObject != NULL)
|
|
{
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
return(IoCallDriver(WmiLibInfo->LowerDeviceObject, Irp));
|
|
} else {
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return(status);
|
|
}
|
|
}
|
|
|
|
buffer = (PUCHAR)irpStack->Parameters.WMI.Buffer;
|
|
bufferSize = irpStack->Parameters.WMI.BufferSize;
|
|
|
|
if ((minorFunction != IRP_MN_REGINFO) &&
|
|
(minorFunction != IRP_MN_REGINFO_EX))
|
|
{
|
|
//
|
|
// For all requests other than query registration info we are passed
|
|
// a guid. Determine if the guid is one that is supported by the
|
|
// device.
|
|
if (WmipFindGuid(WmiLibInfo->GuidList,
|
|
WmiLibInfo->GuidCount,
|
|
(LPGUID)irpStack->Parameters.WMI.DataPath,
|
|
&guidIndex,
|
|
&instanceCount))
|
|
{
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
status = STATUS_WMI_GUID_NOT_FOUND;
|
|
}
|
|
|
|
if (NT_SUCCESS(status) &&
|
|
((minorFunction == IRP_MN_QUERY_SINGLE_INSTANCE) ||
|
|
(minorFunction == IRP_MN_CHANGE_SINGLE_INSTANCE) ||
|
|
(minorFunction == IRP_MN_CHANGE_SINGLE_ITEM) ||
|
|
(minorFunction == IRP_MN_EXECUTE_METHOD)))
|
|
{
|
|
instanceIndex = ((PWNODE_SINGLE_INSTANCE)buffer)->InstanceIndex;
|
|
|
|
if ( ! (((PWNODE_HEADER)buffer)->Flags) &
|
|
WNODE_FLAG_STATIC_INSTANCE_NAMES)
|
|
{
|
|
status = STATUS_WMI_INSTANCE_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
if (! NT_SUCCESS(status))
|
|
{
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return(status);
|
|
}
|
|
}
|
|
|
|
switch(minorFunction)
|
|
{
|
|
case IRP_MN_REGINFO:
|
|
case IRP_MN_REGINFO_EX:
|
|
{
|
|
ULONG guidCount;
|
|
PGUIDREGINFO guidList;
|
|
PWMIREGINFOW wmiRegInfo;
|
|
PWMIREGGUIDW wmiRegGuid;
|
|
PDEVICE_OBJECT pdo;
|
|
PUNICODE_STRING regPath;
|
|
PWCHAR stringPtr;
|
|
ULONG registryPathOffset;
|
|
ULONG mofResourceOffset;
|
|
ULONG bufferNeeded;
|
|
ULONG i;
|
|
ULONG_PTR nameInfo;
|
|
ULONG nameSize, nameOffset, nameFlags;
|
|
UNICODE_STRING name;
|
|
UNICODE_STRING nullRegistryPath;
|
|
|
|
WmipAssert(WmiLibInfo->QueryWmiRegInfo != NULL);
|
|
WmipAssert(WmiLibInfo->QueryWmiDataBlock != NULL);
|
|
|
|
name.Buffer = NULL;
|
|
name.Length = 0;
|
|
name.MaximumLength = 0;
|
|
nameFlags = 0;
|
|
status = WmiLibInfo->QueryWmiRegInfo(
|
|
DeviceObject,
|
|
&nameFlags,
|
|
&name,
|
|
®Path);
|
|
|
|
if (NT_SUCCESS(status) &&
|
|
(! (nameFlags & WMIREG_FLAG_INSTANCE_PDO) &&
|
|
(name.Buffer == NULL)))
|
|
{
|
|
//
|
|
// if PDO flag not specified then an instance name must be
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
#if DBG
|
|
if (nameFlags & WMIREG_FLAG_INSTANCE_PDO)
|
|
{
|
|
WmipAssert(WmiLibInfo->LowerPDO != NULL);
|
|
}
|
|
#endif
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
WmipAssert(WmiLibInfo->GuidList != NULL);
|
|
|
|
guidList = WmiLibInfo->GuidList;
|
|
guidCount = WmiLibInfo->GuidCount;
|
|
|
|
nameOffset = FIELD_OFFSET(WMIREGINFOW, WmiRegGuid) +
|
|
guidCount * sizeof(WMIREGGUIDW);
|
|
|
|
if (nameFlags & WMIREG_FLAG_INSTANCE_PDO)
|
|
{
|
|
nameSize = 0;
|
|
nameInfo = (ULONG_PTR)WmiLibInfo->LowerPDO;
|
|
} else {
|
|
nameFlags |= WMIREG_FLAG_INSTANCE_LIST;
|
|
nameSize = name.Length + sizeof(USHORT);
|
|
nameInfo = nameOffset;
|
|
}
|
|
|
|
if (regPath == NULL)
|
|
{
|
|
//
|
|
// No registry path specified. This is a bad thing for
|
|
// the device to do, but is not fatal
|
|
nullRegistryPath.Buffer = NULL;
|
|
nullRegistryPath.Length = 0;
|
|
nullRegistryPath.MaximumLength = 0;
|
|
regPath = &nullRegistryPath;
|
|
}
|
|
|
|
mofResourceOffset = 0;
|
|
|
|
registryPathOffset = nameOffset + nameSize;
|
|
|
|
bufferNeeded = registryPathOffset +
|
|
regPath->Length + sizeof(USHORT);
|
|
|
|
if (bufferNeeded <= bufferSize)
|
|
{
|
|
retSize = bufferNeeded;
|
|
|
|
wmiRegInfo = (PWMIREGINFO)buffer;
|
|
wmiRegInfo->BufferSize = bufferNeeded;
|
|
wmiRegInfo->NextWmiRegInfo = 0;
|
|
wmiRegInfo->MofResourceName = mofResourceOffset;
|
|
wmiRegInfo->RegistryPath = registryPathOffset;
|
|
wmiRegInfo->GuidCount = guidCount;
|
|
|
|
for (i = 0; i < guidCount; i++)
|
|
{
|
|
wmiRegGuid = &wmiRegInfo->WmiRegGuid[i];
|
|
wmiRegGuid->Guid = guidList[i].Guid;
|
|
wmiRegGuid->Flags = guidList[i].Flags | nameFlags;
|
|
wmiRegGuid->InstanceInfo = nameInfo;
|
|
wmiRegGuid->InstanceCount = guidList[i].InstanceCount;
|
|
}
|
|
|
|
if ( nameFlags & WMIREG_FLAG_INSTANCE_LIST)
|
|
{
|
|
stringPtr = (PWCHAR)((PUCHAR)buffer + nameOffset);
|
|
*stringPtr++ = name.Length;
|
|
RtlCopyMemory(stringPtr,
|
|
name.Buffer,
|
|
name.Length);
|
|
}
|
|
|
|
stringPtr = (PWCHAR)((PUCHAR)buffer + registryPathOffset);
|
|
*stringPtr++ = regPath->Length;
|
|
RtlCopyMemory(stringPtr,
|
|
regPath->Buffer,
|
|
regPath->Length);
|
|
} else {
|
|
*((PULONG)buffer) = bufferNeeded;
|
|
retSize = sizeof(ULONG);
|
|
}
|
|
} else {
|
|
retSize = 0;
|
|
}
|
|
|
|
if (name.Buffer != NULL)
|
|
{
|
|
ExFreePool(name.Buffer);
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = retSize;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return(status);
|
|
}
|
|
|
|
case IRP_MN_QUERY_ALL_DATA:
|
|
{
|
|
PWNODE_ALL_DATA wnode;
|
|
ULONG bufferAvail;
|
|
PULONG instanceLengthArray;
|
|
PUCHAR dataBuffer;
|
|
ULONG instanceLengthArraySize;
|
|
ULONG dataBlockOffset;
|
|
PREGENTRY regEntry;
|
|
|
|
wnode = (PWNODE_ALL_DATA)buffer;
|
|
|
|
if (bufferSize < FIELD_OFFSET(WNODE_ALL_DATA,
|
|
OffsetInstanceDataAndLength))
|
|
{
|
|
//
|
|
// The buffer should never be smaller than the size of
|
|
// WNODE_ALL_DATA, however if it is then return with an
|
|
// error requesting the minimum sized buffer.
|
|
WmipAssert(FALSE);
|
|
status = IoWMICompleteRequest(WmiLibInfo,
|
|
DeviceObject,
|
|
Irp,
|
|
STATUS_BUFFER_TOO_SMALL,
|
|
FIELD_OFFSET(WNODE_ALL_DATA,
|
|
OffsetInstanceDataAndLength),
|
|
IO_NO_INCREMENT);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If this is the pnp id guid then we need to get the instance
|
|
// count from the regentry for the device and switch the
|
|
// device object.
|
|
|
|
if ((guidIndex == PnPIdGuidIndex) ||
|
|
(guidIndex == PnPIdInstanceNamesGuidIndex))
|
|
{
|
|
regEntry = WmipFindRegEntryByProviderId(wnode->WnodeHeader.ProviderId,
|
|
FALSE);
|
|
if (regEntry == NULL)
|
|
{
|
|
//
|
|
// Why couldn't we get the regentry again ??
|
|
WmipAssert(FALSE);
|
|
status = IoWMICompleteRequest(WmiLibInfo,
|
|
DeviceObject,
|
|
Irp,
|
|
STATUS_WMI_GUID_NOT_FOUND,
|
|
0,
|
|
IO_NO_INCREMENT);
|
|
break;
|
|
}
|
|
|
|
DeviceObject = regEntry->DeviceObject;
|
|
instanceCount = (guidIndex == PnPIdGuidIndex) ? regEntry->MaxInstanceNames : 1;
|
|
|
|
WmipUnreferenceRegEntry(regEntry);
|
|
}
|
|
|
|
wnode->InstanceCount = instanceCount;
|
|
|
|
wnode->WnodeHeader.Flags &= ~WNODE_FLAG_FIXED_INSTANCE_SIZE;
|
|
|
|
instanceLengthArraySize = instanceCount * sizeof(OFFSETINSTANCEDATAANDLENGTH);
|
|
|
|
dataBlockOffset = (FIELD_OFFSET(WNODE_ALL_DATA, OffsetInstanceDataAndLength) + instanceLengthArraySize + 7) & ~7;
|
|
|
|
wnode->DataBlockOffset = dataBlockOffset;
|
|
if (dataBlockOffset <= bufferSize)
|
|
{
|
|
instanceLengthArray = (PULONG)&wnode->OffsetInstanceDataAndLength[0];
|
|
dataBuffer = buffer + dataBlockOffset;
|
|
bufferAvail = bufferSize - dataBlockOffset;
|
|
} else {
|
|
//
|
|
// There is not enough room in the WNODE to complete
|
|
// the query
|
|
instanceLengthArray = NULL;
|
|
dataBuffer = NULL;
|
|
bufferAvail = 0;
|
|
}
|
|
|
|
status = WmiLibInfo->QueryWmiDataBlock(
|
|
DeviceObject,
|
|
Irp,
|
|
guidIndex,
|
|
0,
|
|
instanceCount,
|
|
instanceLengthArray,
|
|
bufferAvail,
|
|
dataBuffer);
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_QUERY_SINGLE_INSTANCE:
|
|
{
|
|
PWNODE_SINGLE_INSTANCE wnode;
|
|
ULONG dataBlockOffset;
|
|
PREGENTRY regEntry;
|
|
|
|
wnode = (PWNODE_SINGLE_INSTANCE)buffer;
|
|
|
|
if ((guidIndex == PnPIdGuidIndex) ||
|
|
(guidIndex == PnPIdInstanceNamesGuidIndex))
|
|
{
|
|
regEntry = WmipFindRegEntryByProviderId(wnode->WnodeHeader.ProviderId,
|
|
FALSE);
|
|
if (regEntry != NULL)
|
|
{
|
|
DeviceObject = regEntry->DeviceObject;
|
|
WmipUnreferenceRegEntry(regEntry);
|
|
} else {
|
|
//
|
|
// Why couldn't we get the regentry again ??
|
|
WmipAssert(FALSE);
|
|
status = IoWMICompleteRequest(WmiLibInfo,
|
|
DeviceObject,
|
|
Irp,
|
|
STATUS_WMI_GUID_NOT_FOUND,
|
|
0,
|
|
IO_NO_INCREMENT);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
dataBlockOffset = wnode->DataBlockOffset;
|
|
|
|
status = WmiLibInfo->QueryWmiDataBlock(
|
|
DeviceObject,
|
|
Irp,
|
|
guidIndex,
|
|
instanceIndex,
|
|
1,
|
|
&wnode->SizeDataBlock,
|
|
bufferSize - dataBlockOffset,
|
|
(PUCHAR)wnode + dataBlockOffset);
|
|
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_CHANGE_SINGLE_INSTANCE:
|
|
{
|
|
PWNODE_SINGLE_INSTANCE wnode;
|
|
|
|
if (WmiLibInfo->SetWmiDataBlock != NULL)
|
|
{
|
|
wnode = (PWNODE_SINGLE_INSTANCE)buffer;
|
|
|
|
status = WmiLibInfo->SetWmiDataBlock(
|
|
DeviceObject,
|
|
Irp,
|
|
guidIndex,
|
|
instanceIndex,
|
|
wnode->SizeDataBlock,
|
|
(PUCHAR)wnode + wnode->DataBlockOffset);
|
|
} else {
|
|
//
|
|
// If set callback is not filled in then it must be readonly
|
|
status = STATUS_WMI_READ_ONLY;
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_CHANGE_SINGLE_ITEM:
|
|
{
|
|
PWNODE_SINGLE_ITEM wnode;
|
|
|
|
if (WmiLibInfo->SetWmiDataItem != NULL)
|
|
{
|
|
wnode = (PWNODE_SINGLE_ITEM)buffer;
|
|
|
|
status = WmiLibInfo->SetWmiDataItem(
|
|
DeviceObject,
|
|
Irp,
|
|
guidIndex,
|
|
instanceIndex,
|
|
wnode->ItemId,
|
|
wnode->SizeDataItem,
|
|
(PUCHAR)wnode + wnode->DataBlockOffset);
|
|
|
|
} else {
|
|
//
|
|
// If set callback is not filled in then it must be readonly
|
|
status = STATUS_WMI_READ_ONLY;
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_EXECUTE_METHOD:
|
|
{
|
|
PWNODE_METHOD_ITEM wnode;
|
|
|
|
if (WmiLibInfo->ExecuteWmiMethod != NULL)
|
|
{
|
|
wnode = (PWNODE_METHOD_ITEM)buffer;
|
|
|
|
status = WmiLibInfo->ExecuteWmiMethod(
|
|
DeviceObject,
|
|
Irp,
|
|
guidIndex,
|
|
instanceIndex,
|
|
wnode->MethodId,
|
|
wnode->SizeDataBlock,
|
|
bufferSize - wnode->DataBlockOffset,
|
|
buffer + wnode->DataBlockOffset);
|
|
|
|
} else {
|
|
//
|
|
// If method callback is not filled in then it must be error
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_ENABLE_EVENTS:
|
|
{
|
|
if (WmiLibInfo->WmiFunctionControl != NULL)
|
|
{
|
|
status = WmiLibInfo->WmiFunctionControl(
|
|
DeviceObject,
|
|
Irp,
|
|
guidIndex,
|
|
WmiEventGeneration,
|
|
TRUE);
|
|
} else {
|
|
//
|
|
// If callback is not filled in then just succeed
|
|
status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_DISABLE_EVENTS:
|
|
{
|
|
if (WmiLibInfo->WmiFunctionControl != NULL)
|
|
{
|
|
status = WmiLibInfo->WmiFunctionControl(
|
|
DeviceObject,
|
|
Irp,
|
|
guidIndex,
|
|
WmiEventGeneration,
|
|
FALSE);
|
|
} else {
|
|
//
|
|
// If callback is not filled in then just succeed
|
|
status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_ENABLE_COLLECTION:
|
|
{
|
|
if (WmiLibInfo->WmiFunctionControl != NULL)
|
|
{
|
|
status = WmiLibInfo->WmiFunctionControl(
|
|
DeviceObject,
|
|
Irp,
|
|
guidIndex,
|
|
WmiDataBlockCollection,
|
|
TRUE);
|
|
} else {
|
|
//
|
|
// If callback is not filled in then just succeed
|
|
status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_DISABLE_COLLECTION:
|
|
{
|
|
if (WmiLibInfo->WmiFunctionControl != NULL)
|
|
{
|
|
status = WmiLibInfo->WmiFunctionControl(
|
|
DeviceObject,
|
|
Irp,
|
|
guidIndex,
|
|
WmiDataBlockCollection,
|
|
FALSE);
|
|
} else {
|
|
//
|
|
// If callback is not filled in then just succeed
|
|
status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
|
|
NTSTATUS
|
|
IoWMICompleteRequest(
|
|
IN PWMILIB_INFO WmiLibInfo,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN NTSTATUS Status,
|
|
IN ULONG BufferUsed,
|
|
IN CCHAR PriorityBoost
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
This routine will do the work of completing a WMI irp. Depending upon the
|
|
the WMI request this routine will fixup the returned WNODE appropriately.
|
|
|
|
Arguments:
|
|
|
|
WmiLibInfo has the WMI information control block
|
|
|
|
DeviceObject - Supplies a pointer to the device object for this request.
|
|
|
|
Irp - Supplies the Irp making the request.
|
|
|
|
Status has the return status code for the IRP
|
|
|
|
BufferUsed has the number of bytes needed by the device to return the
|
|
data requested in any query. In the case that the buffer passed to
|
|
the device is too small this has the number of bytes needed for the
|
|
return data. If the buffer passed is large enough then this has the
|
|
number of bytes actually used by the device.
|
|
|
|
PriorityBoost is the value used for the IoCompleteRequest call.
|
|
|
|
Return Value:
|
|
|
|
status
|
|
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
UCHAR MinorFunction;
|
|
PUCHAR buffer;
|
|
ULONG retSize;
|
|
UCHAR minorFunction;
|
|
ULONG bufferSize;
|
|
|
|
PAGED_CODE();
|
|
|
|
minorFunction = irpStack->MinorFunction;
|
|
buffer = (PUCHAR)irpStack->Parameters.WMI.Buffer;
|
|
bufferSize = irpStack->Parameters.WMI.BufferSize;
|
|
|
|
switch(minorFunction)
|
|
{
|
|
case IRP_MN_QUERY_ALL_DATA:
|
|
{
|
|
PWNODE_ALL_DATA wnode;
|
|
PWNODE_TOO_SMALL wnodeTooSmall;
|
|
ULONG bufferNeeded;
|
|
ULONG instanceCount;
|
|
POFFSETINSTANCEDATAANDLENGTH offsetInstanceDataAndLength;
|
|
ULONG i;
|
|
PULONG instanceLengthArray;
|
|
ULONG dataBlockOffset;
|
|
|
|
wnode = (PWNODE_ALL_DATA)buffer;
|
|
|
|
dataBlockOffset = wnode->DataBlockOffset;
|
|
instanceCount = wnode->InstanceCount;
|
|
bufferNeeded = dataBlockOffset + BufferUsed;
|
|
|
|
if ((NT_SUCCESS(Status)) &&
|
|
(bufferNeeded > irpStack->Parameters.WMI.BufferSize))
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
if (! NT_SUCCESS(Status))
|
|
{
|
|
if (Status == STATUS_BUFFER_TOO_SMALL)
|
|
{
|
|
wnodeTooSmall = (PWNODE_TOO_SMALL)wnode;
|
|
|
|
wnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
|
|
wnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
|
|
wnodeTooSmall->SizeNeeded = bufferNeeded;
|
|
|
|
retSize = sizeof(WNODE_TOO_SMALL);
|
|
Status = STATUS_SUCCESS;
|
|
} else {
|
|
retSize = 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
|
|
|
|
instanceLengthArray = (PULONG)&wnode->OffsetInstanceDataAndLength[0];
|
|
offsetInstanceDataAndLength = (POFFSETINSTANCEDATAANDLENGTH)instanceLengthArray;
|
|
|
|
wnode->WnodeHeader.BufferSize = bufferNeeded;
|
|
retSize = bufferNeeded;
|
|
|
|
for (i = instanceCount; i != 0; i--)
|
|
{
|
|
offsetInstanceDataAndLength[i-1].LengthInstanceData = instanceLengthArray[i-1];
|
|
}
|
|
|
|
for (i = 0; i < instanceCount; i++)
|
|
{
|
|
offsetInstanceDataAndLength[i].OffsetInstanceData = dataBlockOffset;
|
|
dataBlockOffset = (dataBlockOffset + offsetInstanceDataAndLength[i].LengthInstanceData + 7) & ~7;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_QUERY_SINGLE_INSTANCE:
|
|
{
|
|
PWNODE_SINGLE_INSTANCE wnode;
|
|
PWNODE_TOO_SMALL wnodeTooSmall;
|
|
ULONG bufferNeeded;
|
|
|
|
wnode = (PWNODE_SINGLE_INSTANCE)buffer;
|
|
|
|
bufferNeeded = wnode->DataBlockOffset + BufferUsed;
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
retSize = bufferNeeded;
|
|
wnode->WnodeHeader.BufferSize = bufferNeeded;
|
|
KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
|
|
|
|
WmipAssert(wnode->SizeDataBlock <= BufferUsed);
|
|
|
|
} else if (Status == STATUS_BUFFER_TOO_SMALL) {
|
|
wnodeTooSmall = (PWNODE_TOO_SMALL)wnode;
|
|
|
|
wnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
|
|
wnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
|
|
wnodeTooSmall->SizeNeeded = bufferNeeded;
|
|
retSize = sizeof(WNODE_TOO_SMALL);
|
|
Status = STATUS_SUCCESS;
|
|
} else {
|
|
retSize = 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_EXECUTE_METHOD:
|
|
{
|
|
PWNODE_METHOD_ITEM wnode;
|
|
PWNODE_TOO_SMALL wnodeTooSmall;
|
|
ULONG bufferNeeded;
|
|
|
|
wnode = (PWNODE_METHOD_ITEM)buffer;
|
|
|
|
bufferNeeded = wnode->DataBlockOffset + BufferUsed;
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
retSize = bufferNeeded;
|
|
wnode->WnodeHeader.BufferSize = bufferNeeded;
|
|
KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
|
|
wnode->SizeDataBlock = BufferUsed;
|
|
|
|
} else if (Status == STATUS_BUFFER_TOO_SMALL) {
|
|
wnodeTooSmall = (PWNODE_TOO_SMALL)wnode;
|
|
|
|
wnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
|
|
wnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
|
|
wnodeTooSmall->SizeNeeded = bufferNeeded;
|
|
retSize = sizeof(WNODE_TOO_SMALL);
|
|
Status = STATUS_SUCCESS;
|
|
} else {
|
|
retSize = 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
//
|
|
// All other requests don't return any data
|
|
retSize = 0;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
Irp->IoStatus.Information = retSize;
|
|
IoCompleteRequest(Irp, PriorityBoost);
|
|
return(Status);
|
|
}
|
|
|