windows-nt/Source/XPSP1/NT/net/ndis/sys/ndiswmi.c
2020-09-26 16:20:57 +08:00

2893 lines
90 KiB
C

/*++
Copyright (c) 1990-1995 Microsoft Corporation
Module Name:
ndiswmi.c
Abstract:
This module contains the routines necessary to process IRPs sent under the
IRP_MJ_SYSTEM_CONTROL major code.
Author:
Kyle Brandon (KyleB)
Environment:
Kernel mode
Revision History:
--*/
#include <precomp.h>
#pragma hdrstop
#define MODULE_NUMBER MODULE_WMI
#define MOF_RESOURCE_NAME L"NdisMofResource"
NTSTATUS
ndisWmiFindInstanceName(
IN PNDIS_CO_VC_PTR_BLOCK *ppVcBlock,
IN PNDIS_MINIPORT_BLOCK Miniport,
IN PWSTR pInstanceName,
IN USHORT cbInstanceName
)
{
NTSTATUS Status = STATUS_SUCCESS;
PNDIS_OPEN_BLOCK pOpen;
PLIST_ENTRY Link;
PNDIS_CO_VC_PTR_BLOCK pVcBlock = NULL;
UINT cListCount;
PLIST_ENTRY pListHead;
UNICODE_STRING usTemp;
*ppVcBlock = NULL;
usTemp.Buffer = pInstanceName;
usTemp.Length = usTemp.MaximumLength = cbInstanceName;
//
// See if this is a VC instance ?
//
if (pInstanceName[VC_ID_INDEX] == VC_IDENTIFIER)
{
//
// The request is for some VC. Go through the Miniport's list of WMI enabled VCs.
//
Link = Miniport->WmiEnabledVcs.Flink;
while (Link != &Miniport->WmiEnabledVcs)
{
//
// Get a pointer to the VC.
//
pVcBlock = CONTAINING_RECORD(Link, NDIS_CO_VC_PTR_BLOCK, WmiLink);
//
// Check the name with the one in the wnode.
//
if (RtlEqualUnicodeString(&pVcBlock->VcInstanceName, &usTemp, TRUE))
{
//
// This is our baby. Slap a reference on it and get out.
//
if (!ndisReferenceVcPtr(pVcBlock))
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisWmiFindInstanceName: Unable to reference the VC\n"));
//
// VC is closing, can't query this one.
//
Status = NDIS_STATUS_FAILURE;
}
break;
}
//
// Initialize this so that we know when we've found the VC in the outer loop.
//
pVcBlock = NULL;
Link = Link->Flink;
}
//
// If we didn't find the VC then return FAILURE.
//
if (Link == &Miniport->WmiEnabledVcs)
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("ndisWmiFindInstanceName: Could not verify the instance name passed in\n"));
Status = STATUS_WMI_INSTANCE_NOT_FOUND;
}
//
// If we found the VC then save it before leaving.
//
if (NT_SUCCESS(Status))
{
*ppVcBlock = pVcBlock;
}
}
else
{
//
// The name belongs to a miniport, check to see if it is for this one.
//
if (!RtlEqualUnicodeString(Miniport->pAdapterInstanceName, &usTemp, TRUE))
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisWmiFindInstanceName: Invalid instance name\n"));
Status = STATUS_WMI_INSTANCE_NOT_FOUND;
}
}
return(Status);
}
BOOLEAN
ndisWmiGuidIsAdapterSpecific(
IN LPGUID guid
)
{
BOOLEAN fAdapterOnly = FALSE;
if (NdisEqualMemory(guid, (PVOID)&GUID_NDIS_ENUMERATE_ADAPTER, sizeof(GUID)) ||
NdisEqualMemory(guid, (PVOID)&GUID_POWER_DEVICE_ENABLE, sizeof(GUID)) ||
NdisEqualMemory(guid, (PVOID)&GUID_POWER_DEVICE_WAKE_ENABLE, sizeof(GUID)) ||
NdisEqualMemory(guid, (PVOID)&GUID_NDIS_WAKE_ON_MAGIC_PACKET_ONLY, sizeof(GUID)))
{
fAdapterOnly = TRUE;
}
return(fAdapterOnly);
}
NDIS_STATUS
ndisQuerySetMiniport(
IN PNDIS_MINIPORT_BLOCK Miniport,
IN PNDIS_CO_VC_PTR_BLOCK pVcBlock,
IN BOOLEAN fSet,
IN PNDIS_REQUEST pRequest,
IN PLARGE_INTEGER pTime OPTIONAL
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
BOOLEAN fQuery = !fSet;
UINT Count;
NDIS_STATUS NdisStatus;
PNDIS_COREQ_RESERVED CoReqRsvd;
PnPReferencePackage();
#define MAX_WAIT_COUNT 5000
#define WAIT_TIME 1000
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_FAILED | fMINIPORT_PM_HALTED))
{
PnPDereferencePackage();
return (fQuery ? NDIS_STATUS_FAILURE : NDIS_STATUS_SUCCESS);
}
//
// Initialize the co-request reserved information.
//
CoReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(pRequest);
PNDIS_RESERVED_FROM_PNDIS_REQUEST(pRequest)->Open = NULL;
//
// preserve the mandatory setting on request
//
PNDIS_RESERVED_FROM_PNDIS_REQUEST(pRequest)->Flags &= REQST_MANDATORY;
PNDIS_RESERVED_FROM_PNDIS_REQUEST(pRequest)->Flags |= REQST_SIGNAL_EVENT;
INITIALIZE_EVENT(&CoReqRsvd->Event);
//
// If the miniport is being reset, then wait for the reset to complete before going any further.
// Make sure we do not wait indefinitely either
//
for (Count = 0; Count < MAX_WAIT_COUNT; Count ++)
{
if (!MINIPORT_TEST_FLAG(Miniport, (fMINIPORT_RESET_IN_PROGRESS | fMINIPORT_RESET_REQUESTED)))
{
break;
}
NdisMSleep(WAIT_TIME); // 1 msec
}
if (Count == MAX_WAIT_COUNT)
{
PnPDereferencePackage();
return(NDIS_STATUS_RESET_IN_PROGRESS);
}
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
{
NDIS_HANDLE MiniportVcContext = NULL;
do
{
if (NULL != pVcBlock)
{
if (!ndisReferenceVcPtr(pVcBlock))
{
NdisStatus = NDIS_STATUS_CLOSING;
break;
}
else
{
MiniportVcContext = pVcBlock->MiniportContext;
}
}
NdisStatus = Miniport->DriverHandle->MiniportCharacteristics.CoRequestHandler(
Miniport->MiniportAdapterContext,
MiniportVcContext,
pRequest);
if (NDIS_STATUS_PENDING == NdisStatus)
{
WAIT_FOR_OBJECT(&CoReqRsvd->Event, pTime);
//
// Get the status that the miniport returned.
//
NdisStatus = CoReqRsvd->Status;
}
if (NULL != pVcBlock)
{
ndisDereferenceVcPtr(pVcBlock);
}
} while (FALSE);
}
else
{
if ((fSet && (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler != NULL)) ||
(fQuery && (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler != NULL)))
{
BOOLEAN LocalLock;
KIRQL OldIrql;
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
ndisMQueueRequest(Miniport, pRequest);
LOCK_MINIPORT(Miniport, LocalLock);
if (LocalLock || MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DESERIALIZE))
{
ndisMDoRequests(Miniport);
}
else
{
//
// Queue the miniport request and wait for it to complete.
//
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL);
}
UNLOCK_MINIPORT(Miniport, LocalLock);
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
if (NT_SUCCESS(WAIT_FOR_OBJECT(&CoReqRsvd->Event, pTime)))
{
//
// Get the status that the miniport returned.
//
NdisStatus = CoReqRsvd->Status;
}
else
{
NdisStatus = -1; // Special error-code to return time-out
}
}
else
{
//
// If there isn't a proper handler then this is not a valid request.
//
NdisStatus = STATUS_INVALID_PARAMETER;
}
}
PnPDereferencePackage();
return(NdisStatus);
}
NDIS_STATUS
ndisQueryCustomGuids(
IN PNDIS_MINIPORT_BLOCK Miniport,
IN PNDIS_REQUEST Request,
OUT PNDIS_GUID * ppGuidToOid,
OUT PUSHORT pcGuidToOid
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
USHORT BytesNeeded;
NDIS_STATUS Status;
USHORT c, cCustomGuids = 0;
PNDIS_GUID pGuidToOid = NULL;
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("==>ndisQueryCustomGuids\n"));
*ppGuidToOid = NULL;
*pcGuidToOid = 0;
do
{
//
// Determine the size needed for the custom GUID to OID map.
//
#if (OID_GEN_CO_SUPPORTED_GUIDS != OID_GEN_SUPPORTED_GUIDS)
#error (OID_GEN_CO_SUPPORTED_GUIDS == OID_GEN_SUPPORTED_GUIDS)
#endif
INIT_INTERNAL_REQUEST(Request, OID_GEN_SUPPORTED_GUIDS, NdisRequestQueryInformation, NULL, 0);
Status = ndisQuerySetMiniport(Miniport, NULL, FALSE, Request, NULL);
BytesNeeded = (USHORT)Request->DATA.QUERY_INFORMATION.BytesNeeded;
//
// If the miniport has custom GUIDs then make sure it returned a valid
// length for the BytesNeeded.
//
if (((NDIS_STATUS_INVALID_LENGTH == Status) ||
(NDIS_STATUS_BUFFER_TOO_SHORT == Status)) && (0 != BytesNeeded))
{
//
// Bytes needed should contain the amount of space needed.
//
cCustomGuids = (BytesNeeded / sizeof(NDIS_GUID));
}
//
// If there are no custom GUIDs to support then get out.
//
if (cCustomGuids == 0)
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("ndisQueryCustomGuids: Miniport does not support custom GUIDS\n"));
Status = NDIS_STATUS_NOT_SUPPORTED;
break;
}
//
// Allocate a buffer to hold the GUID to OID mapping
// for the custom GUIDs.
//
pGuidToOid = ALLOC_FROM_POOL(BytesNeeded, NDIS_TAG_WMI_GUID_TO_OID);
if (NULL == pGuidToOid)
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisQueryCustomGuids: Unable to allocate memory for the GUID to OID map\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
//
// Query the list of GUIDs
//
if (0 != cCustomGuids)
{
//
// Store the buffer with the request.
//
Request->DATA.QUERY_INFORMATION.InformationBuffer = pGuidToOid;
Request->DATA.QUERY_INFORMATION.InformationBufferLength = BytesNeeded;
//
// Query for the list of custom GUIDs and OIDs.
//
Status = ndisQuerySetMiniport(Miniport, NULL, FALSE, Request, NULL);
if (NDIS_STATUS_SUCCESS != Status)
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisQueryCustomGuids: Unable to get the list of supported Co GUIDs\n"));
break;
}
//
// Go through this list and mark the guids as co.
//
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
{
for (c = 0; c < cCustomGuids; c++)
{
NDIS_GUID_SET_FLAG(&pGuidToOid[c], fNDIS_GUID_CO_NDIS);
}
}
}
} while (FALSE);
if (NDIS_STATUS_SUCCESS == Status)
{
*ppGuidToOid = pGuidToOid;
*pcGuidToOid = cCustomGuids;
}
else
{
if (NULL != pGuidToOid)
{
FREE_POOL(pGuidToOid);
}
}
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("<==ndisQueryCustomGuids\n"));
return(Status);
}
USHORT
ndisWmiMapOids(
IN OUT PNDIS_GUID pDst,
IN IN USHORT cDst,
IN PNDIS_OID pOidList,
IN USHORT cOidList,
IN PNDIS_GUID ndisSupportedList,
IN ULONG cSupportedList
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
USHORT c1, c2, ctmp = cDst;
for (c1 = 0; c1 < cSupportedList; c1++)
{
for (c2 = 0; c2 < cOidList; c2++)
{
if (ndisSupportedList[c1].Oid == pOidList[c2])
{
if (NULL != pDst)
{
//
// Copy the guid into the destination buffer.
//
NdisMoveMemory(&pDst[ctmp], &ndisSupportedList[c1], sizeof(NDIS_GUID));
}
ctmp++;
break;
}
}
}
return ctmp;
}
NDIS_STATUS
ndisQuerySupportedGuidToOidList(
IN PNDIS_MINIPORT_BLOCK Miniport
)
/*++
Routine Description:
This routine will query the miniport and determine the mapping of
supported GUIDs and their corresponding OIDs. This will include any
custom OIDs that the driver supports.
Arguments:
Return Value:
--*/
{
ULONG BytesNeeded;
NDIS_STATUS NdisStatus;
USHORT cOidList = 0;
PNDIS_OID pOidList = NULL;
USHORT cCustomGuids = 0;
PNDIS_GUID pCustomGuids = NULL;
USHORT cGuidToOidMap = 0;
PNDIS_GUID pGuidToOidMap = NULL;
USHORT c1, c2;
NDIS_REQUEST Request;
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("==>ndisQuerySupportedGuidToOidList\n"));
do
{
#if (OID_GEN_SUPPORTED_LIST != OID_GEN_CO_SUPPORTED_LIST)
#error (OID_GEN_SUPPORTED_LIST != OID_GEN_CO_SUPPORTED_LIST)
#endif
//
// Determine the amount of buffer space needed for the supported list.
//
INIT_INTERNAL_REQUEST(&Request, OID_GEN_SUPPORTED_LIST, NdisRequestQueryInformation, NULL, 0);
NdisStatus = ndisQuerySetMiniport(Miniport, NULL, FALSE, &Request, NULL);
BytesNeeded = Request.DATA.QUERY_INFORMATION.BytesNeeded;
//
// The driver should have returned invalid length and the
// length needed in BytesNeeded.
//
if (((NDIS_STATUS_INVALID_LENGTH != NdisStatus) && (NDIS_STATUS_BUFFER_TOO_SHORT != NdisStatus)) ||
(0 == BytesNeeded))
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("ndisQuerySupportedGuidToOidList: Failed to get the size of the supported OID list.\n"));
NdisStatus = NDIS_STATUS_FAILURE;
break;
}
//
// Determine the number of Oids supported.
//
cOidList = (USHORT)(BytesNeeded/sizeof(NDIS_OID));
//
// Allocate a buffer to hold the supported list of OIDs.
//
pOidList = ALLOC_FROM_POOL(BytesNeeded, NDIS_TAG_WMI_OID_SUPPORTED_LIST);
if (NULL == pOidList)
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("ndisQuerySupportedGuidToOidList: Failed to allocate memory for the OID list.\n"));
NdisStatus = NDIS_STATUS_RESOURCES;
break;
}
Request.DATA.QUERY_INFORMATION.InformationBuffer = pOidList;
Request.DATA.QUERY_INFORMATION.InformationBufferLength = BytesNeeded;
//
// Now query the supported list of OIDs into the buffer.
//
NdisStatus = ndisQuerySetMiniport(Miniport, NULL, FALSE, &Request, NULL);
if (NDIS_STATUS_SUCCESS != NdisStatus)
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("ndisQuerySupportedGuidToOidList: Failed to read in the supported OID list.\n"));
break;
}
//
// Determine the number of [Co]NDIS OIDs that NDIS will handle on behalf of the miniport
//
cGuidToOidMap = ndisWmiMapOids(NULL,
cGuidToOidMap,
pOidList,
cOidList,
ndisSupportedGuids,
sizeof(ndisSupportedGuids)/sizeof(NDIS_GUID));
cGuidToOidMap = ndisWmiMapOids(NULL,
cGuidToOidMap,
pOidList,
cOidList,
ndisCoSupportedGuids,
sizeof(ndisCoSupportedGuids)/sizeof(NDIS_GUID));
//
// Determine the number of media specific OIDs that NDIS will handle on
// behalf of the miniport
//
cGuidToOidMap = ndisWmiMapOids(NULL,
cGuidToOidMap,
pOidList,
cOidList,
ndisMediaSupportedGuids,
sizeof(ndisMediaSupportedGuids)/sizeof(NDIS_GUID));
//
// Determine the number of custom GUIDs supported.
//
NdisStatus = ndisQueryCustomGuids(Miniport, &Request, &pCustomGuids, &cCustomGuids);
if (NDIS_STATUS_SUCCESS == NdisStatus)
{
cGuidToOidMap += cCustomGuids;
}
//
// Add to the guid count the number of status indications we are
// registering.
//
cGuidToOidMap += (sizeof(ndisStatusSupportedGuids) / sizeof(NDIS_GUID));
//
// Add the number of GUIDs that ndis will handle.
// Add any guids that are not supported with an OID. These will be handled
// entirely by ndis.
//
for (c1 = 0; c1 < sizeof(ndisSupportedGuids) / sizeof(NDIS_GUID); c1++)
{
if (NDIS_GUID_TEST_FLAG(&ndisSupportedGuids[c1], fNDIS_GUID_NDIS_ONLY))
{
//
// Check to see if the miniport is CoNDIS
//
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO) ||
!NDIS_GUID_TEST_FLAG(&ndisSupportedGuids[c1], fNDIS_GUID_CO_NDIS))
{
cGuidToOidMap++;
}
}
}
//
// Allocate space for the GUID to OID map.
//
pGuidToOidMap = ALLOC_FROM_POOL(cGuidToOidMap * sizeof(NDIS_GUID), NDIS_TAG_WMI_GUID_TO_OID);
if (NULL == pGuidToOidMap)
{
NdisStatus = NDIS_STATUS_RESOURCES;
break;
}
NdisZeroMemory(pGuidToOidMap, cGuidToOidMap * sizeof(NDIS_GUID));
//
// Add the GUIDs that NDIS will handle
//
for (c1 = 0, c2 = 0;
c1 < sizeof(ndisSupportedGuids) / sizeof(NDIS_GUID);
c1++)
{
if (NDIS_GUID_TEST_FLAG(&ndisSupportedGuids[c1], fNDIS_GUID_NDIS_ONLY))
{
//
// Check to see if the miniport is CoNDIS
//
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO) ||
!NDIS_GUID_TEST_FLAG(&ndisSupportedGuids[c1], fNDIS_GUID_CO_NDIS))
{
NdisMoveMemory(&pGuidToOidMap[c2], &ndisSupportedGuids[c1], sizeof(NDIS_GUID));
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
{
//
// we need to mark this for the enumerate guids.
//
pGuidToOidMap[c2].Flags |= fNDIS_GUID_CO_NDIS;
}
c2++;
}
}
}
//
// Save the current number of GUIDs in the map in c1
//
c1 = c2;
//
// Find the PNDIS_GUIDs that are appropriate for the miniport.
//
c1 = ndisWmiMapOids(pGuidToOidMap,
c1,
pOidList,
cOidList,
ndisSupportedGuids,
sizeof(ndisSupportedGuids)/sizeof(NDIS_GUID));
c1 = ndisWmiMapOids(pGuidToOidMap,
c1,
pOidList,
cOidList,
ndisCoSupportedGuids,
sizeof(ndisCoSupportedGuids)/sizeof(NDIS_GUID));
//
// Check for media specific OIDs that ndis can support.
//
c1 = ndisWmiMapOids(pGuidToOidMap,
c1,
pOidList,
cOidList,
ndisMediaSupportedGuids,
sizeof(ndisMediaSupportedGuids)/sizeof(NDIS_GUID));
//
// Add the status indications to the map of supported guids.
//
NdisMoveMemory(&pGuidToOidMap[c1], ndisStatusSupportedGuids, sizeof(ndisStatusSupportedGuids));
c1 += (sizeof(ndisStatusSupportedGuids) / sizeof(NDIS_GUID));
//
// Save the GUID to OID mapping with the miniport.
//
Miniport->pNdisGuidMap = pGuidToOidMap;
Miniport->cNdisGuidMap = cGuidToOidMap;
//
// Now copy over the custom GUID information if any.
//
if (NULL != pCustomGuids)
{
NdisMoveMemory(&pGuidToOidMap[c1],
pCustomGuids,
cCustomGuids * sizeof(NDIS_GUID));
Miniport->pCustomGuidMap = &pGuidToOidMap[c1];
Miniport->cCustomGuidMap = cCustomGuids;
}
else
{
//
// Make sure these are initialized if they are not supported.
//
Miniport->pCustomGuidMap = NULL;
Miniport->cCustomGuidMap = 0;
}
//
// We've succeeded.
//
NdisStatus = NDIS_STATUS_SUCCESS;
} while (FALSE);
//
// Free up the buffer that contains the custom GUIDs.
//
if (NULL != pCustomGuids)
{
FREE_POOL(pCustomGuids);
}
//
// Free up the list of supported driver OIDs.
//
if (NULL != pOidList)
{
FREE_POOL(pOidList);
}
//
// If there was an error and we allocated the GUID to OID map then
// free it up also.
//
if (NDIS_STATUS_SUCCESS != NdisStatus)
{
if (NULL != pGuidToOidMap)
{
FREE_POOL(pGuidToOidMap);
}
}
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("<==ndisQuerySupportedGuidToOidList\n"));
return(NdisStatus);
}
NTSTATUS
ndisWmiRegister(
IN PNDIS_MINIPORT_BLOCK Miniport,
IN ULONG_PTR RegistrationType,
IN PWMIREGINFO wmiRegInfo,
IN ULONG wmiRegInfoSize,
IN PULONG pReturnSize
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PWMIREGINFO pwri;
ULONG CustomSizeNeeded = 0;
ULONG CustomBufferSize;
ULONG CommonSizeNeeded;
ULONG cCommonGuids;
PUNICODE_STRING pMiniportRegistryPath;
PNDIS_GUID pndisguid;
PWMIREGGUID pwrg;
PUCHAR ptmp;
NTSTATUS Status;
UINT c;
NDIS_STATUS NdisStatus;
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("==>ndisWmiRegister\n"));
//
// Initialize the return size.
//
*pReturnSize = 0;
do
{
//
// Is this a register request?
//
if (WMIREGISTER == RegistrationType)
{
//
// Get the supported list of OIDs
//
if (Miniport->pNdisGuidMap == NULL)
{
NdisStatus = ndisQuerySupportedGuidToOidList(Miniport);
if (NDIS_STATUS_SUCCESS != NdisStatus)
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisWmiRegister: Unable to get the supported GUID to OID map\n"));
Status = STATUS_UNSUCCESSFUL;
break;
}
}
//
// Determine the amount of space needed for the Custom GUIDs
//
if (Miniport->cCustomGuidMap != 0)
{
//
// Get a pointer to the registry path of the driver.
//
pMiniportRegistryPath = &Miniport->DriverHandle->NdisDriverInfo->ServiceRegPath;
CustomSizeNeeded = sizeof(WMIREGINFO) +
(Miniport->cCustomGuidMap * sizeof(WMIREGGUID)) +
(sizeof(MOF_RESOURCE_NAME) - sizeof(WCHAR) + sizeof(USHORT)) +
(pMiniportRegistryPath->Length + sizeof(USHORT));
}
//
// Determine how much memory we need to allocate.
//
cCommonGuids = Miniport->cNdisGuidMap - Miniport->cCustomGuidMap;
CommonSizeNeeded = sizeof(WMIREGINFO) + (cCommonGuids * sizeof(WMIREGGUID));
CustomBufferSize = CustomSizeNeeded;
CustomSizeNeeded = (CustomSizeNeeded + (sizeof(PVOID) - 1)) & ~(sizeof(PVOID) - 1);
//
// CustomBufferSize represents the number of bytes required to store the
// custom WMI registration info. CustomSizeNeeded is this value rounded
// up so that the adjacent WMI registration info is properly aligned.
//
//
// We need to give this above information back to WMI.
//
if (wmiRegInfoSize < (CustomSizeNeeded + CommonSizeNeeded))
{
ASSERT(wmiRegInfoSize >= 4);
*((PULONG)wmiRegInfo) = (CustomSizeNeeded + CommonSizeNeeded);
*pReturnSize = sizeof(ULONG);
Status = STATUS_BUFFER_TOO_SMALL;
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("ndisWmiRegister: Insufficient buffer space for WMI registration information.\n"));
break;
}
//
// Get a pointer to the buffer passed in.
//
pwri = wmiRegInfo;
*pReturnSize = CustomSizeNeeded + CommonSizeNeeded;
NdisZeroMemory(pwri, CustomSizeNeeded + CommonSizeNeeded);
//
// do we need to initialize a WMIREGINFO struct for custom GUIDs?
//
if (0 != CustomSizeNeeded)
{
//
// Initialize the WMIREGINFO struct for the miniport's
// custom GUIDs.
//
pwri->BufferSize = CustomBufferSize;
pwri->NextWmiRegInfo = CustomSizeNeeded;
pwri->GuidCount = Miniport->cCustomGuidMap;
for (c = 0, pndisguid = Miniport->pCustomGuidMap, pwrg = pwri->WmiRegGuid;
(c < Miniport->cCustomGuidMap);
c++, pndisguid++, pwrg++)
{
CopyMemory(&pwrg->Guid, &pndisguid->Guid, sizeof(GUID));
}
//
// Fill in the registry path.
//
ptmp = (PUCHAR)pwrg;
pwri->RegistryPath = (ULONG)((ULONG_PTR)ptmp - (ULONG_PTR)pwri);
*((PUSHORT)ptmp) = pMiniportRegistryPath->Length;
ptmp += sizeof(USHORT);
CopyMemory(ptmp, pMiniportRegistryPath->Buffer, pMiniportRegistryPath->Length);
//
// Get a pointer to the destination for the MOF name.
//
ptmp += pMiniportRegistryPath->Length;
//
// Save the offset to the mof resource.
//
pwri->MofResourceName = (ULONG)((ULONG_PTR)ptmp - (ULONG_PTR)pwri);
*((PUSHORT)ptmp) = sizeof(MOF_RESOURCE_NAME) - sizeof(WCHAR);
ptmp += sizeof(USHORT);
//
// Copy the mof name into the wri buffer.
//
CopyMemory(ptmp, MOF_RESOURCE_NAME, sizeof(MOF_RESOURCE_NAME) - sizeof(WCHAR));
//
// Go on to the next WMIREGINFO struct for the common GUIDs.
//
pwri = (PWMIREGINFO)((PCHAR)pwri + pwri->NextWmiRegInfo);
}
//
// Initialize the pwri struct for the common Oids.
//
pwri->BufferSize = CommonSizeNeeded;
pwri->NextWmiRegInfo = 0;
pwri->GuidCount = cCommonGuids;
//
// Go through the GUIDs that we support.
//
for (c = 0, pndisguid = Miniport->pNdisGuidMap, pwrg = pwri->WmiRegGuid;
(c < cCommonGuids);
c++, pndisguid++, pwrg++)
{
if (NdisEqualMemory(&pndisguid->Guid, (PVOID)&GUID_POWER_DEVICE_ENABLE, sizeof(GUID)) ||
NdisEqualMemory(&pndisguid->Guid, (PVOID)&GUID_POWER_DEVICE_WAKE_ENABLE, sizeof(GUID)) ||
NdisEqualMemory(&pndisguid->Guid, (PVOID)&GUID_NDIS_WAKE_ON_MAGIC_PACKET_ONLY, sizeof(GUID)))
{
{
(ULONG_PTR)pwrg->InstanceInfo = (ULONG_PTR)(Miniport->PhysicalDeviceObject);
pwrg->Flags = WMIREG_FLAG_INSTANCE_PDO;
pwrg->InstanceCount = 1;
}
}
CopyMemory(&pwrg->Guid, &pndisguid->Guid, sizeof(GUID));
}
pwri->RegistryPath = 0;
pwri->MofResourceName = 0;
Status = STATUS_SUCCESS;
}
else
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("ndisWmiRegister: Unsupported registration type\n"));
Status = STATUS_INVALID_PARAMETER;
break;
}
} while (FALSE);
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("<==ndisWmiRegister\n"));
return(Status);
}
NTSTATUS
ndisWmiGetGuid(
OUT PNDIS_GUID *ppNdisGuid,
IN PNDIS_MINIPORT_BLOCK Miniport,
IN LPGUID guid,
IN NDIS_STATUS status
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
UINT c;
PNDIS_GUID pNdisGuid;
NDIS_STATUS RetStatus = NDIS_STATUS_FAILURE;
//
// Search the custom GUIDs
//
if (NULL != Miniport->pNdisGuidMap)
{
for (c = 0, pNdisGuid = Miniport->pNdisGuidMap;
(c < Miniport->cNdisGuidMap);
c++, pNdisGuid++)
{
//
// Make sure that we have a supported GUID and the GUID maps
// to an OID.
//
if (NULL != guid)
{
//
// We are to look for a guid to oid mapping.
//
if (NdisEqualMemory(&pNdisGuid->Guid, guid, sizeof(GUID)))
{
//
// We found the GUID, save the OID that we will need to
// send to the miniport.
//
RetStatus = NDIS_STATUS_SUCCESS;
*ppNdisGuid = pNdisGuid;
break;
}
}
else
{
//
// We need to find the guid for the status indication
//
if (NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_TO_STATUS) &&
(pNdisGuid->Status == status))
{
RetStatus = NDIS_STATUS_SUCCESS;
*ppNdisGuid = pNdisGuid;
break;
}
}
}
}
return(RetStatus);
}
NTSTATUS
ndisQueryGuidDataSize(
OUT PULONG pBytesNeeded,
IN PNDIS_MINIPORT_BLOCK Miniport,
IN PNDIS_CO_VC_PTR_BLOCK pVcBlock OPTIONAL,
IN LPGUID guid
)
/*++
Routine Description:
This routine will determine the amount of buffer space needed for
the GUID's data.
Arguments:
pBytesNeeded - Pointer to storage for the size needed.
Miniport - Pointer to the miniport block.
guid - GUID to query.
Return Value:
--*/
{
NTSTATUS NtStatus;
NDIS_STATUS Status;
PNDIS_GUID pNdisGuid;
NDIS_REQUEST Request;
ULONG GuidDataSize;
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("==>ndisQueryGuidDataSize\n"));
do
{
//
// Make sure that we support the guid that was passed, and find
// the corresponding OID.
//
NtStatus = ndisWmiGetGuid(&pNdisGuid, Miniport, guid, 0);
if (!NT_SUCCESS(NtStatus))
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisQueryGuidDataSize: Unsupported GUID\n"));
NtStatus = STATUS_INVALID_PARAMETER;
break;
}
//
// Check for an ndis only guid
//
if (NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_NDIS_ONLY))
{
NtStatus = STATUS_SUCCESS;
//
// The following GUIDs all return the same data.
//
if (NdisEqualMemory(&pNdisGuid->Guid, (PVOID)&GUID_NDIS_ENUMERATE_ADAPTER, sizeof(GUID)))
{
//
// Length of string and the string data.
//
*pBytesNeeded = Miniport->MiniportName.Length + sizeof(USHORT);
}
else if (NdisEqualMemory(&pNdisGuid->Guid, (PVOID)&GUID_POWER_DEVICE_ENABLE, sizeof(GUID)))
{
*pBytesNeeded = sizeof(BOOLEAN);
}
else if (NdisEqualMemory(&pNdisGuid->Guid, (PVOID)&GUID_POWER_DEVICE_WAKE_ENABLE, sizeof(GUID)))
{
*pBytesNeeded = sizeof(BOOLEAN);
}
else if (NdisEqualMemory(&pNdisGuid->Guid, (PVOID)&GUID_NDIS_WAKE_ON_MAGIC_PACKET_ONLY, sizeof(GUID)))
{
*pBytesNeeded = sizeof(BOOLEAN);
}
else if ((NULL != pVcBlock) && NdisEqualMemory(&pNdisGuid->Guid, (PVOID)&GUID_NDIS_ENUMERATE_VC, sizeof(GUID)))
{
//
// There is not data for this VC. It's simply used to enumerate VCs on a miniport.
//
*pBytesNeeded = 0;
}
else
{
//
// Unknown guid is being queried...
//
NtStatus = STATUS_INVALID_PARAMETER;
}
break;
}
//
// Is this a GUID to OID mapping?
//
if (!NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_TO_OID))
{
NtStatus = STATUS_INVALID_DEVICE_REQUEST;
break;
}
//
// Do we need to query the OID for the size of the data?
//
if (NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_ARRAY) ||
NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_UNICODE_STRING) ||
NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_ANSI_STRING) ||
(pNdisGuid->Size == (ULONG)-1))
{
//
// Query the miniport for the current size of the variable length block.
//
INIT_INTERNAL_REQUEST(&Request, pNdisGuid->Oid, NdisRequestQueryStatistics, NULL, 0);
Status = ndisQuerySetMiniport(Miniport,
pVcBlock,
FALSE,
&Request,
NULL);
//
// Make sure that the miniport failed the above request with
// the correct error code and that the BytesNeeded is valid.
//
if ((NDIS_STATUS_INVALID_LENGTH != Status) &&
(NDIS_STATUS_BUFFER_TOO_SHORT != Status) &&
(NDIS_STATUS_SUCCESS != Status))
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisQueryGuidDataSize: Failed to query driver OID: 0x%x\n", Status));
MAP_NDIS_STATUS_TO_NT_STATUS(Status, &NtStatus);
break;
}
GuidDataSize = Request.DATA.QUERY_INFORMATION.BytesNeeded;
if (NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_ANSI_STRING))
{
//
// The size returned is the number of ansi characters. Convert this
// to the unicode string size needed
//
GuidDataSize = GuidDataSize * sizeof(WCHAR);
GuidDataSize += sizeof(USHORT);
}
else if (NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_UNICODE_STRING))
{
//
// string data has a USHORT for the size.
//
GuidDataSize += sizeof(USHORT);
}
else if (NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_ARRAY))
{
//
// The data is going to have a ULONG of size information at the
// start of the buffer.
//
GuidDataSize += sizeof(ULONG);
}
}
else
{
GuidDataSize = pNdisGuid->Size;
}
//
// Return the bytes needed.
//
*pBytesNeeded = GuidDataSize;
NtStatus = STATUS_SUCCESS;
} while (FALSE);
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("<==ndisQueryGuidDataSize\n"));
return(NtStatus);
}
NTSTATUS
ndisQueryGuidData(
IN PUCHAR Buffer,
IN ULONG BufferLength,
IN PNDIS_MINIPORT_BLOCK Miniport,
IN PNDIS_CO_VC_PTR_BLOCK pVcBlock,
IN LPGUID guid,
IN PIRP Irp
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS NtStatus;
NDIS_STATUS Status;
PNDIS_GUID pNdisGuid;
NDIS_REQUEST Request;
ANSI_STRING strAnsi = {0};
UNICODE_STRING strUnicode = {0};
ULONG QuerySize;
PUCHAR QueryBuffer;
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("==>ndisQueryGuidData\n"));
do
{
//
// If the buffer length is equal to 0 then there is no data to query.
//
if (0 == BufferLength)
{
NtStatus = STATUS_SUCCESS;
break;
}
ZeroMemory(Buffer, BufferLength);
//
// Make sure that we support the guid that was passed, and find
// the corresponding OID.
//
NtStatus = ndisWmiGetGuid(&pNdisGuid, Miniport, guid, 0);
if (!NT_SUCCESS(NtStatus))
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisQueryGuidData: Unsupported GUID\n"));
NtStatus = STATUS_INVALID_PARAMETER;
break;
}
if (!ndisWmiCheckAccess(pNdisGuid,
fNDIS_GUID_ALLOW_READ,
SE_LOAD_DRIVER_PRIVILEGE,
Irp))
{
NtStatus = STATUS_PRIVILEGE_NOT_HELD;
break;
}
//
// Is this an NDIS supported GUID?
//
if (NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_NDIS_ONLY))
{
NtStatus = STATUS_SUCCESS;
//
// The following GUIDs all return the same data.
//
if (NdisEqualMemory(&pNdisGuid->Guid, (PVOID)&GUID_NDIS_ENUMERATE_ADAPTER, sizeof(GUID)))
{
*(PUSHORT)Buffer = Miniport->MiniportName.Length;
NdisMoveMemory(Buffer + sizeof(USHORT),
Miniport->MiniportName.Buffer,
Miniport->MiniportName.Length);
}
else if (NdisEqualMemory(&pNdisGuid->Guid, (PVOID)&GUID_POWER_DEVICE_ENABLE, sizeof(GUID)))
{
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_PM_SUPPORTED) &&
(!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_NO_HALT_ON_SUSPEND)))
{
*((PBOOLEAN)Buffer) = MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_POWER_ENABLE);
}
else
{
NtStatus = STATUS_INVALID_DEVICE_REQUEST;
}
}
else if (NdisEqualMemory(&pNdisGuid->Guid, (PVOID)&GUID_POWER_DEVICE_WAKE_ENABLE, sizeof(GUID)))
{
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_PM_SUPPORTED) &&
(Miniport->DeviceCaps.SystemWake > PowerSystemWorking))
{
*((PBOOLEAN)Buffer) = MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_POWER_WAKE_ENABLE);
}
else
{
NtStatus = STATUS_INVALID_DEVICE_REQUEST;
}
}
else if (NdisEqualMemory(&pNdisGuid->Guid, (PVOID)&GUID_NDIS_WAKE_ON_MAGIC_PACKET_ONLY, sizeof(GUID)))
{
//
// let the user see this only if we can do wake on magic packet
//
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_PM_SUPPORTED) &&
(Miniport->DeviceCaps.SystemWake > PowerSystemWorking) &&
(Miniport->PMCapabilities.WakeUpCapabilities.MinMagicPacketWakeUp != NdisDeviceStateUnspecified) &&
!(Miniport->PnPCapabilities & NDIS_DEVICE_DISABLE_WAKE_ON_MAGIC_PACKET))
{
*((PBOOLEAN)Buffer) = (Miniport->PnPCapabilities & NDIS_DEVICE_DISABLE_WAKE_ON_PATTERN_MATCH) ?
TRUE:
FALSE;
}
else
{
NtStatus = STATUS_INVALID_DEVICE_REQUEST;
}
}
else if ((NULL != pVcBlock) && NdisEqualMemory(&pNdisGuid->Guid, (PVOID)&GUID_NDIS_ENUMERATE_VC, sizeof(GUID)))
{
//
// There is no data for this VC.
//
break;
}
else
{
//
// Unknown guid is being queried...
//
NtStatus = STATUS_INVALID_PARAMETER;
}
break;
}
//
// Is this a GUID to OID mapping?
//
if (!NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_TO_OID))
{
NtStatus = STATUS_INVALID_DEVICE_REQUEST;
break;
}
//
// Determine the query size. This will depend upon the type of
// data.
//
if (NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_ARRAY))
{
//
// The query size is at least the BufferLength minus the ULONG
// used for the count. The query buffer will start after the
// ULONG of count informaiton in the buffer.
//
QuerySize = BufferLength - sizeof(ULONG);
QueryBuffer = Buffer + sizeof(ULONG);
}
else if (NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_ANSI_STRING) ||
NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_UNICODE_STRING))
{
//
// The query size is at least the BufferLength minus the ULONG
// used for the count. The query buffer will start after the
// ULONG of count informaiton in the buffer.
//
QuerySize = BufferLength - sizeof(USHORT);
QueryBuffer = Buffer + sizeof(USHORT);
//
// Is this a query for an ANSI string?
//
if (NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_ANSI_STRING))
{
//
// The BufferLength is the number of WCHARS not counting a terminating
// NULL.
//
QuerySize = (QuerySize / sizeof(WCHAR)) + 1;
}
}
else
{
QuerySize = BufferLength;
QueryBuffer = Buffer;
}
//
// Query the driver for the actual data.
//
INIT_INTERNAL_REQUEST(&Request, pNdisGuid->Oid, NdisRequestQueryStatistics, QueryBuffer, QuerySize);
Status = ndisQuerySetMiniport(Miniport,
pVcBlock,
FALSE,
&Request,
NULL);
if (NDIS_STATUS_SUCCESS != Status)
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisQueryGuidData: Failed to query the value for driver OID: 0x%x\n", Status));
MAP_NDIS_STATUS_TO_NT_STATUS(Status, &NtStatus);
break;
}
//
// If this is an array or string we need to fill in the
// count/number.
//
NtStatus = STATUS_SUCCESS;
if (NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_ARRAY))
{
//
// Determine the number of elements.
//
*(PULONG)Buffer = QuerySize / pNdisGuid->Size;
}
else if (NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_UNICODE_STRING))
{
//
// The BytesNeeded contains the number of bytes in the string.
//
*(PUSHORT)Buffer = (USHORT)QuerySize;
}
else if (NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_ANSI_STRING))
{
//
// The buffer contains the ASCII string, build an
// ANSI string from this.
//
RtlInitAnsiString(&strAnsi, QueryBuffer);
//
// Convert the ansi string to unicode.
//
NtStatus = RtlAnsiStringToUnicodeString(&strUnicode, &strAnsi, TRUE);
ASSERT(NT_SUCCESS(NtStatus));
if (NT_SUCCESS(NtStatus))
{
//
// Save the length with the string.
//
*(PUSHORT)Buffer = strUnicode.Length;
//
// Copy the string to the wnode buffer.
//
NdisMoveMemory(QueryBuffer, strUnicode.Buffer, strUnicode.Length);
//
// Free the buffer allocated for the unicode string.
//
RtlFreeUnicodeString(&strUnicode);
}
}
} while (FALSE);
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("<==ndisQueryGuidData\n"));
return(NtStatus);
}
NTSTATUS
ndisWmiQueryAllData(
IN PNDIS_MINIPORT_BLOCK Miniport,
IN LPGUID guid,
IN PWNODE_ALL_DATA wnode,
IN ULONG BufferSize,
OUT PULONG pReturnSize,
IN PIRP Irp
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS NtStatus;
ULONG wnodeSize = ALIGN_8_TYPE(WNODE_ALL_DATA);
ULONG InstanceNameOffsetsSize, InstanceNameSize;
ULONG wnodeTotalSize;
ULONG BytesNeeded;
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("==>ndisWmiQueryAllData\n"));
do
{
*pReturnSize = 0;
if (BufferSize < sizeof(WNODE_TOO_SMALL))
{
WMI_BUFFER_TOO_SMALL(BufferSize, wnode, sizeof(WNODE_TOO_SMALL), &NtStatus, pReturnSize);
break;
}
//
// If the guid is only relavent to the adapter then answer it here.
// Is this GUID meant for "adapters" only, i.e. not vc's.
//
if (ndisWmiGuidIsAdapterSpecific(guid) ||
!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
{
ULONG dataSize;
PUCHAR pucTmp;
//
// Determine the buffer size needed for the GUID data.
//
NtStatus = ndisQueryGuidDataSize(&BytesNeeded, Miniport, NULL, guid);
if (!NT_SUCCESS(NtStatus))
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisWmiQueryAllData: Unable to determine GUID data size\n"));
break;
}
//
// Determine the size of the WNODE that is needed.
//
dataSize = ALIGN_UP(BytesNeeded, ULONG);
InstanceNameOffsetsSize = sizeof(ULONG);
InstanceNameSize = sizeof(USHORT) + Miniport->pAdapterInstanceName->Length; // comes at the end, no need to pad
wnodeTotalSize = wnodeSize + dataSize + InstanceNameOffsetsSize + InstanceNameSize;
if (BufferSize < wnodeTotalSize)
{
WMI_BUFFER_TOO_SMALL(BufferSize, wnode, wnodeTotalSize, &NtStatus, pReturnSize);
break;
}
//
// Initialize the wnode.
//
KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
wnode->WnodeHeader.Flags |= WNODE_FLAG_FIXED_INSTANCE_SIZE;
wnode->WnodeHeader.BufferSize = wnodeTotalSize;
wnode->InstanceCount = 1;
wnode->DataBlockOffset = wnodeSize;
wnode->OffsetInstanceNameOffsets = wnodeSize + dataSize;
wnode->FixedInstanceSize = BytesNeeded;
//
// Fill in the data block.
//
NtStatus = ndisQueryGuidData((PUCHAR)wnode + wnodeSize,
BytesNeeded,
Miniport,
NULL,
guid,
Irp);
if (!NT_SUCCESS(NtStatus))
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisWmiQueryAllData: Failed to get the GUID data.\n"));
break;
}
*(PULONG)((PUCHAR)wnode + wnode->OffsetInstanceNameOffsets) = wnodeSize + dataSize + InstanceNameOffsetsSize;
//
// Get the pointer to where we store the instance name.
//
pucTmp = (PUCHAR)((PUCHAR)wnode + wnodeSize + dataSize + InstanceNameOffsetsSize);
*((PUSHORT)pucTmp) = Miniport->pAdapterInstanceName->Length;
NdisMoveMemory(pucTmp + sizeof(USHORT),
Miniport->pAdapterInstanceName->Buffer,
Miniport->pAdapterInstanceName->Length);
NtStatus = STATUS_SUCCESS;
*pReturnSize = wnode->WnodeHeader.BufferSize;
}
else
{
ULONG cRoughInstanceCount = Miniport->VcCount + 1;
UINT cInstanceCount = 0;
PUCHAR pBuffer;
ULONG OffsetToInstanceNames;
PLIST_ENTRY Link;
PNDIS_CO_VC_PTR_BLOCK pVcBlock = NULL;
POFFSETINSTANCEDATAANDLENGTH poidl;
PULONG pInstanceNameOffsets;
ULONG OffsetToInstanceInfo;
BOOLEAN OutOfSpace = FALSE;
//
// Initialize common wnode information.
//
KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
//
// Setup the OFFSETINSTANCEDATAANDLENGTH array.
//
poidl = wnode->OffsetInstanceDataAndLength;
wnode->OffsetInstanceNameOffsets = wnodeSize + ALIGN_UP((sizeof(OFFSETINSTANCEDATAANDLENGTH) * cRoughInstanceCount), ULONG);
//
// Get a pointer to the array of offsets to the instance names.
//
pInstanceNameOffsets = (PULONG)((PUCHAR)wnode + wnode->OffsetInstanceNameOffsets);
//
// Get the offset from the wnode where will will start copying the instance
// data into.
//
OffsetToInstanceInfo = ALIGN_8_LENGTH(wnode->OffsetInstanceNameOffsets + sizeof(ULONG) * cRoughInstanceCount);
//
// Get a pointer to start placing the data.
//
pBuffer = (PUCHAR)wnode + OffsetToInstanceInfo;
//
// Check to make sure we have at least this much buffer space in the wnode.
//
wnodeTotalSize = OffsetToInstanceInfo;
//
// Start with the miniport.
//
NtStatus = ndisQueryGuidDataSize(&BytesNeeded, Miniport, NULL, guid);
if (NT_SUCCESS(NtStatus))
{
//
// Make sure we have enough buffer space for the instance name and
// the data. If not we still continue since we need to find the total
// size
//
wnodeTotalSize += ALIGN_8_LENGTH(Miniport->pAdapterInstanceName->Length + sizeof(USHORT)) +
ALIGN_8_LENGTH(BytesNeeded);
if (BufferSize >= wnodeTotalSize)
{
///
//
// The instance info contains the instance name followed by the
// data for the item.
//
///
//
// Add the offset to the instance name to the table.
//
pInstanceNameOffsets[cInstanceCount] = OffsetToInstanceInfo;
//
// Copy the instance name into the wnode buffer.
//
*((PUSHORT)pBuffer) = Miniport->pAdapterInstanceName->Length;
NdisMoveMemory(pBuffer + sizeof(USHORT),
Miniport->pAdapterInstanceName->Buffer,
Miniport->pAdapterInstanceName->Length);
//
// Keep track of true instance counts.
//
OffsetToInstanceInfo += ALIGN_8_LENGTH(sizeof(USHORT) + Miniport->pAdapterInstanceName->Length);
pBuffer = (PUCHAR)wnode + OffsetToInstanceInfo;
//
// Query the data for the miniport.
//
NtStatus = ndisQueryGuidData(pBuffer, BytesNeeded, Miniport, NULL, guid, Irp);
if (!NT_SUCCESS(NtStatus))
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisWmiQueryAllData: Failed to get the GUID data.\n"));
break;
}
//
// Save the length of the data item for this instance.
//
poidl[cInstanceCount].OffsetInstanceData = OffsetToInstanceInfo;
poidl[cInstanceCount].LengthInstanceData = BytesNeeded;
//
// Keep track of true instance counts.
//
OffsetToInstanceInfo += ALIGN_8_LENGTH(BytesNeeded);
pBuffer = (PUCHAR)wnode + OffsetToInstanceInfo;
}
//
// Increment the current instance count.
//
cInstanceCount++;
}
else
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisWmiQueryAllData: Unable to determine GUID data size\n"));
break;
}
//
// Only the miniport?
//
if (cInstanceCount == cRoughInstanceCount)
{
if (BufferSize >= wnodeTotalSize)
{
wnode->WnodeHeader.BufferSize = wnodeTotalSize;
wnode->InstanceCount = cInstanceCount;
*pReturnSize = wnode->WnodeHeader.BufferSize;
NtStatus = STATUS_SUCCESS;
}
else
{
WMI_BUFFER_TOO_SMALL(BufferSize, wnode, wnodeTotalSize, &NtStatus, pReturnSize);
}
break;
}
//
// First search the inactive vc list.
//
Link = Miniport->WmiEnabledVcs.Flink;
while (Link != &Miniport->WmiEnabledVcs)
{
//
// We only have room for so many VCs.
//
if (cInstanceCount >= cRoughInstanceCount)
{
break;
}
//
// Get a pointer to the VC.
//
pVcBlock = CONTAINING_RECORD(Link, NDIS_CO_VC_PTR_BLOCK, WmiLink);
if (!ndisReferenceVcPtr(pVcBlock))
{
Link = Link->Flink;
//
// This VC is cleaning up.
//
continue;
}
//
// If there is an instance name associated with the VC then we need to query it.
//
if (NULL != pVcBlock->VcInstanceName.Buffer)
{
//
// Start with the miniport.
//
NtStatus = ndisQueryGuidDataSize(&BytesNeeded,
Miniport,
pVcBlock,
guid);
if (NT_SUCCESS(NtStatus))
{
//
// Make sure we have enough buffer space for the instance name and
// the data.
//
wnodeTotalSize += ALIGN_8_LENGTH(pVcBlock->VcInstanceName.Length + sizeof(USHORT)) +
ALIGN_8_LENGTH(BytesNeeded);
if (BufferSize < wnodeTotalSize)
{
WMI_BUFFER_TOO_SMALL(BufferSize, wnode, wnodeTotalSize, &NtStatus, pReturnSize);
OutOfSpace = TRUE;
ndisDereferenceVcPtr(pVcBlock);
Link = Link->Flink;
continue;
}
//
// The instance info contains the instance name followed by the
// data for the item.
//
//
// Add the offset to the instance name to the table.
//
pInstanceNameOffsets[cInstanceCount] = OffsetToInstanceInfo;
//
// Copy the instance name into the wnode buffer.
//
*((PUSHORT)pBuffer) = pVcBlock->VcInstanceName.Length;
NdisMoveMemory(pBuffer + sizeof(USHORT),
pVcBlock->VcInstanceName.Buffer,
pVcBlock->VcInstanceName.Length);
//
// Keep track of true instance counts.
//
OffsetToInstanceInfo += ALIGN_8_LENGTH(sizeof(USHORT) + pVcBlock->VcInstanceName.Length);
pBuffer = (PUCHAR)wnode + OffsetToInstanceInfo;
//
// Query the data for the miniport.
//
NtStatus = ndisQueryGuidData(pBuffer,
BytesNeeded,
Miniport,
pVcBlock,
guid,
Irp);
if (!NT_SUCCESS(NtStatus))
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisWmiQueryAllData: Failed to query GUID data\n"));
ndisDereferenceVcPtr(pVcBlock);
break;
}
//
// Save the length of the data item for this instance.
//
poidl[cInstanceCount].OffsetInstanceData = OffsetToInstanceInfo;
poidl[cInstanceCount].LengthInstanceData = BytesNeeded;
//
// Keep track of true instance counts.
//
OffsetToInstanceInfo += ALIGN_8_LENGTH(BytesNeeded);
pBuffer = (PUCHAR)wnode + OffsetToInstanceInfo;
//
// Increment the current instance count.
//
cInstanceCount++;
}
}
ndisDereferenceVcPtr(pVcBlock);
Link = Link->Flink;
}
if (!OutOfSpace)
{
wnode->WnodeHeader.BufferSize = wnodeTotalSize;
wnode->InstanceCount = cInstanceCount;
//
// Set the status to success.
//
NtStatus = STATUS_SUCCESS;
*pReturnSize = wnode->WnodeHeader.BufferSize;
}
}
} while (FALSE);
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("<==ndisWmiQueryAllData\n"));
return(NtStatus);
}
NTSTATUS
ndisWmiQuerySingleInstance(
IN PNDIS_MINIPORT_BLOCK Miniport,
IN PWNODE_SINGLE_INSTANCE wnode,
IN ULONG BufferSize,
OUT PULONG pReturnSize,
IN PIRP Irp
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS NtStatus;
ULONG BytesNeeded;
ULONG wnodeSize;
USHORT cbInstanceName;
PWSTR pInstanceName;
PNDIS_CO_VC_PTR_BLOCK pVcBlock = NULL;
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("==>ndisWmiQuerySingleInstance\n"));
do
{
*pReturnSize = 0;
if (wnode->WnodeHeader.Flags & WNODE_FLAG_STATIC_INSTANCE_NAMES)
{
//
// This is a static instance name
//
pVcBlock = NULL;
}
else
{
//
// Determine if this is for a VC or a miniport...
//
cbInstanceName = *(PUSHORT)((PUCHAR)wnode + wnode->OffsetInstanceName);
pInstanceName = (PWSTR)((PUCHAR)wnode + wnode->OffsetInstanceName + sizeof(USHORT));
//
// This routine will determine if the wnode's instance name is a miniport or VC.
// If it's a VC then it will find which one.
//
NtStatus = ndisWmiFindInstanceName(&pVcBlock, Miniport, pInstanceName, cbInstanceName);
if (!NT_SUCCESS(NtStatus))
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisWmiQuerySingleInstance: Unable to find the instance name\n"));
pVcBlock = NULL;
break;
}
}
//
// Determine the buffer size needed for the GUID data.
//
NtStatus = ndisQueryGuidDataSize(&BytesNeeded,
Miniport,
pVcBlock,
&wnode->WnodeHeader.Guid);
if (!NT_SUCCESS(NtStatus))
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisWmiQuerySingleInstance: Unable to determine GUID data size\n"));
break;
}
//
// Determine the size of the wnode.
//
wnodeSize = wnode->DataBlockOffset + BytesNeeded;
if (BufferSize < wnodeSize)
{
WMI_BUFFER_TOO_SMALL(BufferSize, wnode, wnodeSize, &NtStatus, pReturnSize);
break;
}
//
// Initialize the wnode.
//
KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
wnode->WnodeHeader.BufferSize = wnodeSize;
wnode->SizeDataBlock = BytesNeeded;
//
// Validate the guid and get the data for it.
//
NtStatus = ndisQueryGuidData((PUCHAR)wnode + wnode->DataBlockOffset,
BytesNeeded,
Miniport,
pVcBlock,
&wnode->WnodeHeader.Guid,
Irp);
if (!NT_SUCCESS(NtStatus))
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisWmiQuerySingleInstance: Failed to get the GUID data.\n"));
break;
}
*pReturnSize = wnodeSize;
NtStatus = STATUS_SUCCESS;
} while (FALSE);
//
// If this was a VC then we need to dereference it.
//
if (NULL != pVcBlock)
{
ndisDereferenceVcPtr(pVcBlock);
}
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("<==ndisWmiQuerySingleInstance\n"));
return(NtStatus);
}
NTSTATUS
ndisWmiChangeSingleInstance(
IN PNDIS_MINIPORT_BLOCK Miniport,
IN PWNODE_SINGLE_INSTANCE wnode,
IN ULONG BufferSize,
OUT PULONG pReturnSize,
IN PIRP Irp
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS NtStatus;
NDIS_STATUS Status;
PNDIS_GUID pNdisGuid;
PUCHAR pGuidData;
ULONG GuidDataSize;
NDIS_REQUEST Request;
USHORT cbInstanceName;
PWSTR pInstanceName;
PNDIS_CO_VC_PTR_BLOCK pVcBlock = NULL;
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("==>ndisWmiChangeSingleInstance\n"));
do
{
if (wnode->WnodeHeader.Flags & WNODE_FLAG_STATIC_INSTANCE_NAMES)
{
//
// This is a static instance name
//
pVcBlock = NULL;
}
else
{
//
// Determine if this is for a VC or a miniport...
//
cbInstanceName = *(PUSHORT)((PUCHAR)wnode + wnode->OffsetInstanceName);
pInstanceName = (PWSTR)((PUCHAR)wnode + wnode->OffsetInstanceName + sizeof(USHORT));
//
// This routine will determine if the wnode's instance name is a miniport or VC.
// If it's a VC then it will find which one.
//
NtStatus = ndisWmiFindInstanceName(&pVcBlock, Miniport, pInstanceName, cbInstanceName);
if (!NT_SUCCESS(NtStatus))
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisWmiChangeSingleInstance: Unable to find the instance name\n"));
pVcBlock = NULL;
break;
}
}
//
// Make sure that we support the guid that was passed, and find
// the corresponding OID.
//
NtStatus = ndisWmiGetGuid(&pNdisGuid,
Miniport,
&wnode->WnodeHeader.Guid,
0);
if (!NT_SUCCESS(NtStatus))
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisWmiChangeSingleInstance: Unsupported GUID\n"));
NtStatus = STATUS_INVALID_PARAMETER;
break;
}
if (!ndisWmiCheckAccess(pNdisGuid,
fNDIS_GUID_ALLOW_WRITE,
SE_LOAD_DRIVER_PRIVILEGE,
Irp))
{
NtStatus = STATUS_PRIVILEGE_NOT_HELD;
break;
}
//
// Is this guid settable?
//
if (NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_NOT_SETTABLE))
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisWmiChangeSingleInstance: Guid is not settable!\n"));
NtStatus = STATUS_NOT_SUPPORTED;
break;
}
//
// Get a pointer to the GUID data and size.
//
GuidDataSize = wnode->SizeDataBlock;
pGuidData = (PUCHAR)wnode + wnode->DataBlockOffset;
if (GuidDataSize == 0)
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisWmiChangeSingleInstance: Guid has not data to set!\n"));
NtStatus = STATUS_INVALID_PARAMETER;
break;
}
//
// Is this an internal ndis guid?
//
if ((NULL == pVcBlock) && NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_NDIS_ONLY))
{
PBOOLEAN pBoolean = (PBOOLEAN)pGuidData;
NtStatus = STATUS_SUCCESS;
//
// for PM set guids, we should update registry for future boots
//
//
if (NdisEqualMemory(&pNdisGuid->Guid, (PVOID)&GUID_POWER_DEVICE_ENABLE, sizeof(GUID)))
{
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_PM_SUPPORTED) &&
(!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_NO_HALT_ON_SUSPEND)))
{
if (*pBoolean)
{
MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_DEVICE_POWER_ENABLE);
//
// enabling power management also enables wake on link change
// assuming the adapter supports it
//
if ((Miniport->PMCapabilities.WakeUpCapabilities.MinLinkChangeWakeUp != NdisDeviceStateUnspecified) &&
(Miniport->MediaDisconnectTimeOut != (USHORT)(-1)))
{
Miniport->WakeUpEnable |= NDIS_PNP_WAKE_UP_LINK_CHANGE;
}
Miniport->PnPCapabilities &= ~NDIS_DEVICE_DISABLE_PM;
}
else
{
//
// disabling power management also disables wake on link and magic packet
//
Miniport->WakeUpEnable &= ~NDIS_PNP_WAKE_UP_LINK_CHANGE;
MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_DEVICE_POWER_ENABLE);
Miniport->PnPCapabilities |= (NDIS_DEVICE_DISABLE_PM |
NDIS_DEVICE_DISABLE_WAKE_UP);
}
}
else
{
NtStatus = STATUS_INVALID_DEVICE_REQUEST;
}
}
else if (NdisEqualMemory(&pNdisGuid->Guid, (PVOID)&GUID_POWER_DEVICE_WAKE_ENABLE, sizeof(GUID)))
{
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_PM_SUPPORTED) &&
(Miniport->DeviceCaps.SystemWake > PowerSystemWorking))
{
if (*pBoolean)
{
MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_DEVICE_POWER_WAKE_ENABLE);
Miniport->PnPCapabilities &= ~NDIS_DEVICE_DISABLE_WAKE_UP;
//
// enableing Wake on Lan enables wake on Magic Packet method
// assuming the miniport supports it and it is not disabled in the registry
//
if ((Miniport->PMCapabilities.WakeUpCapabilities.MinMagicPacketWakeUp != NdisDeviceStateUnspecified) &&
!(Miniport->PnPCapabilities & NDIS_DEVICE_DISABLE_WAKE_ON_MAGIC_PACKET))
{
Miniport->WakeUpEnable |= NDIS_PNP_WAKE_UP_MAGIC_PACKET;
}
}
else
{
MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_DEVICE_POWER_WAKE_ENABLE);
//
// disabling Wake On Lan also disables wake on Magic Packet method
//
Miniport->WakeUpEnable &= ~NDIS_PNP_WAKE_UP_MAGIC_PACKET;
Miniport->PnPCapabilities |= NDIS_DEVICE_DISABLE_WAKE_UP;
}
}
else
{
NtStatus = STATUS_INVALID_DEVICE_REQUEST;
}
}
else if (NdisEqualMemory(&pNdisGuid->Guid, (PVOID)&GUID_NDIS_WAKE_ON_MAGIC_PACKET_ONLY, sizeof(GUID)))
{
//
// let the user set this only if we can do wake on magic packet
//
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_PM_SUPPORTED) &&
(Miniport->DeviceCaps.SystemWake > PowerSystemWorking) &&
(Miniport->PMCapabilities.WakeUpCapabilities.MinMagicPacketWakeUp != NdisDeviceStateUnspecified) &&
!(Miniport->PnPCapabilities & NDIS_DEVICE_DISABLE_WAKE_ON_MAGIC_PACKET))
{
if (*pBoolean)
{
//
// user does -not- want to wake on pattern match
//
Miniport->PnPCapabilities |= NDIS_DEVICE_DISABLE_WAKE_ON_PATTERN_MATCH;
}
else
{
Miniport->PnPCapabilities &= ~NDIS_DEVICE_DISABLE_WAKE_ON_PATTERN_MATCH;
}
}
else
{
NtStatus = STATUS_INVALID_DEVICE_REQUEST;
}
}
else
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisWmiChangeSingleInstance: Invalid NDIS internal GUID!\n"));
NtStatus = STATUS_INVALID_DEVICE_REQUEST;
}
if (NT_SUCCESS(NtStatus))
{
if (MINIPORT_PNP_TEST_FLAGS(Miniport, fMINIPORT_DEVICE_POWER_ENABLE |
fMINIPORT_DEVICE_POWER_WAKE_ENABLE))
{
//
// power management and wol has been enabled by the user
// check to see what we should tell protocols about the new
// WOL capabilities of the device
// NOTE: set NDIS_DEVICE_WAKE_UP_ENABLE only if pattern match is enabled
//
if (Miniport->PnPCapabilities & NDIS_DEVICE_DISABLE_WAKE_ON_PATTERN_MATCH)
Miniport->PMCapabilities.Flags &= ~(NDIS_DEVICE_WAKE_UP_ENABLE |
NDIS_DEVICE_WAKE_ON_PATTERN_MATCH_ENABLE);
else
//
// user did not disable wake on pattern match, for protocol's purpose
// wol is enabled
//
Miniport->PMCapabilities.Flags |= NDIS_DEVICE_WAKE_UP_ENABLE |
NDIS_DEVICE_WAKE_ON_PATTERN_MATCH_ENABLE;
if (Miniport->PnPCapabilities & NDIS_DEVICE_DISABLE_WAKE_ON_MAGIC_PACKET)
Miniport->PMCapabilities.Flags &= ~NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE;
else
//
// user did not disable wake on magic packet, do -not- set the NDIS_DEVICE_WAKE_UP_ENABLE
// bit becasue wake on pattern match may not be enabled
//
Miniport->PMCapabilities.Flags |= NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE;
}
else
Miniport->PMCapabilities.Flags &= ~(NDIS_DEVICE_WAKE_UP_ENABLE |
NDIS_DEVICE_WAKE_ON_PATTERN_MATCH_ENABLE |
NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE);
ndisWritePnPCapabilities(Miniport, Miniport->PnPCapabilities);
ndisPnPNotifyAllTransports(Miniport,
NetEventPnPCapabilities,
&Miniport->PMCapabilities.Flags,
sizeof(ULONG));
}
break;
}
//
// Make sure it's not a stauts indication.
//
if (!NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_TO_OID))
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisWmiChangeSingleInstance: Guid does not translate to an OID\n"));
NtStatus = STATUS_INVALID_DEVICE_REQUEST;
break;
}
//
// Attempt to set the miniport with the information.
//
INIT_INTERNAL_REQUEST(&Request, pNdisGuid->Oid, NdisRequestSetInformation, pGuidData, GuidDataSize);
Status = ndisQuerySetMiniport(Miniport,
pVcBlock,
TRUE,
&Request,
NULL);
if (NDIS_STATUS_SUCCESS != Status)
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisWmiChangeSingleInstance: Failed to set the new information on the miniport\n"));
MAP_NDIS_STATUS_TO_NT_STATUS(Status, &NtStatus);
break;
}
NtStatus = STATUS_SUCCESS;
} while (FALSE);
//
// If this was a VC then we need to dereference it.
//
if (NULL != pVcBlock)
{
ndisDereferenceVcPtr(pVcBlock);
}
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("<==ndisWmiChangeSingleInstance\n"));
return(NtStatus);
}
NTSTATUS
ndisWmiChangeSingleItem(
IN PNDIS_MINIPORT_BLOCK Miniport,
IN PWNODE_SINGLE_ITEM wnode,
IN ULONG BufferSize,
OUT PULONG pReturnSize,
IN PIRP Irp
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("==>ndisWmiChangeSingleItem\n"));
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("<==ndisWmiChangeSingleItem: Not Supported\n"));
return(STATUS_NOT_SUPPORTED);
}
NTSTATUS
FASTCALL
ndisWmiEnableEvents(
IN PNDIS_MINIPORT_BLOCK Miniport,
IN LPGUID Guid
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NDIS_STATUS Status;
PNDIS_GUID pNdisGuid = NULL;
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("==>ndisWmiEnableEvents\n"));
do
{
//
// Get a pointer to the Guid/Status to enable.
//
Status = ndisWmiGetGuid(&pNdisGuid, Miniport, Guid, 0);
if (NdisEqualMemory(Guid, (PVOID)&GUID_NDIS_NOTIFY_BIND, sizeof(GUID)) ||
NdisEqualMemory(Guid, (PVOID)&GUID_NDIS_NOTIFY_UNBIND, sizeof(GUID)) ||
NdisEqualMemory(Guid, (PVOID)&GUID_NDIS_NOTIFY_DEVICE_POWER_ON, sizeof(GUID)) ||
NdisEqualMemory(Guid, (PVOID)&GUID_NDIS_NOTIFY_DEVICE_POWER_OFF, sizeof(GUID)) ||
NdisEqualMemory(Guid, (PVOID)&GUID_NDIS_NOTIFY_ADAPTER_ARRIVAL, sizeof(GUID)) ||
NdisEqualMemory(Guid, (PVOID)&GUID_NDIS_NOTIFY_ADAPTER_REMOVAL, sizeof(GUID)))
{
if (pNdisGuid)
{
NDIS_GUID_SET_FLAG(pNdisGuid, fNDIS_GUID_EVENT_ENABLED);
}
Status = STATUS_SUCCESS;
break;
}
if (!NT_SUCCESS(Status))
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisWmiEnableEvents: Cannot find the guid to enable an event\n"));
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Is this GUID an event indication?
//
if (!NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_TO_STATUS))
{
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
//
// Mark the guid as enabled
//
NDIS_GUID_SET_FLAG(pNdisGuid, fNDIS_GUID_EVENT_ENABLED);
Status = STATUS_SUCCESS;
} while (FALSE);
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("<==ndisWmiEnableEvents\n"));
return(Status);
}
NTSTATUS
FASTCALL
ndisWmiDisableEvents(
IN PNDIS_MINIPORT_BLOCK Miniport,
IN LPGUID Guid
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NDIS_STATUS Status;
PNDIS_GUID pNdisGuid;
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("==>ndisWmiDisableEvents\n"));
do
{
//
// Get a pointer to the Guid/Status to enable.
//
Status = ndisWmiGetGuid(&pNdisGuid, Miniport, Guid, 0);
if (!NT_SUCCESS(Status))
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisWmiDisableEvents: Cannot find the guid to enable an event\n"));
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Is this GUID an event indication?
//
if (!NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_TO_STATUS))
{
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
//
// Mark the guid as enabled
//
NDIS_GUID_CLEAR_FLAG(pNdisGuid, fNDIS_GUID_EVENT_ENABLED);
Status = STATUS_SUCCESS;
} while (FALSE);
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("<==ndisWmiDisableEvents\n"));
return(Status);
}
NTSTATUS
ndisWMIDispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP pirp
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PIO_STACK_LOCATION pirpSp = IoGetCurrentIrpStackLocation(pirp);
PVOID DataPath = pirpSp->Parameters.WMI.DataPath;
ULONG BufferSize = pirpSp->Parameters.WMI.BufferSize;
PVOID Buffer = pirpSp->Parameters.WMI.Buffer;
NTSTATUS Status;
ULONG ReturnSize = 0;
PNDIS_MINIPORT_BLOCK Miniport;
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("==>ndisWMIDispatch\n"));
//
// Get a pointer to miniport block
//
Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1);
try
{
if (Miniport->Signature != (PVOID)MINIPORT_DEVICE_MAGIC_VALUE)
{
//
// This is not a miniport. Likely a device created by the driver. Try dispatching to it.
//
return(ndisDummyIrpHandler(DeviceObject, pirp));
}
}
except(EXCEPTION_EXECUTE_HANDLER)
{
return(STATUS_ACCESS_VIOLATION);
}
//
// If the provider ID is not us then pass it down the stack.
//
if (pirpSp->Parameters.WMI.ProviderId != (ULONG_PTR)DeviceObject)
{
IoSkipCurrentIrpStackLocation(pirp);
Status = IoCallDriver(Miniport->NextDeviceObject, pirp);
return(Status);
}
switch (pirpSp->MinorFunction)
{
case IRP_MN_REGINFO:
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("ndisWMIDispatch: IRP_MN_REGINFO\n"));
Status = ndisWmiRegister(Miniport,
(ULONG_PTR)DataPath,
Buffer,
BufferSize,
&ReturnSize);
break;
case IRP_MN_QUERY_ALL_DATA:
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("ndisWMIDispatch: IRP_MN_QUERY_ALL_DATA\n"));
Status = ndisWmiQueryAllData(Miniport,
(LPGUID)DataPath,
(PWNODE_ALL_DATA)Buffer,
BufferSize,
&ReturnSize,
pirp);
break;
case IRP_MN_QUERY_SINGLE_INSTANCE:
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("ndisWMIDispatch: IRP_MN_QUERY_SINGLE_INSTANCE\n"));
Status = ndisWmiQuerySingleInstance(Miniport,
Buffer,
BufferSize,
&ReturnSize,
pirp);
break;
case IRP_MN_CHANGE_SINGLE_INSTANCE:
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("ndisWMIDispatch: IRP_MN_CHANGE_SINGLE_INSTANCE\n"));
Status = ndisWmiChangeSingleInstance(Miniport,
Buffer,
BufferSize,
&ReturnSize,
pirp);
break;
case IRP_MN_CHANGE_SINGLE_ITEM:
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("ndisWMIDispatch: IRP_MN_CHANGE_SINGLE_ITEM\n"));
Status = ndisWmiChangeSingleItem(Miniport,
Buffer,
BufferSize,
&ReturnSize,
pirp);
break;
case IRP_MN_ENABLE_EVENTS:
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("ndisWMIDispatch: IRP_MN_ENABLE_EVENTS\n"));
Status = ndisWmiEnableEvents(Miniport, (LPGUID)DataPath);
break;
case IRP_MN_DISABLE_EVENTS:
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("ndisWMIDispatch: IRP_MN_DISABLE_EVENTS\n"));
Status = ndisWmiDisableEvents(Miniport, (LPGUID)DataPath);
break;
case IRP_MN_ENABLE_COLLECTION:
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("ndisWMIDispatch: IRP_MN_ENABLE_COLLECTION\n"));
Status = STATUS_NOT_SUPPORTED;
break;
case IRP_MN_DISABLE_COLLECTION:
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("ndisWMIDispatch: IRP_MN_DISABLE_COLLECTION\n"));
Status = STATUS_NOT_SUPPORTED;
break;
default:
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("ndisWMIDispatch: Invalid minor function (0x%x)\n", pirpSp->MinorFunction));
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
pirp->IoStatus.Status = Status;
ASSERT(ReturnSize <= BufferSize);
if (Status == STATUS_BUFFER_TOO_SMALL)
{
pirp->IoStatus.Information = ReturnSize;
}
else
{
pirp->IoStatus.Information = NT_SUCCESS(Status) ? ReturnSize : 0;
}
IoCompleteRequest(pirp, IO_NO_INCREMENT);
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_INFO,
("<==ndisWMIDispatch\n"));
return(Status);
}
VOID
ndisSetupWmiNode(
IN PNDIS_MINIPORT_BLOCK Miniport,
IN PUNICODE_STRING InstanceName,
IN ULONG DataBlockSize,
IN PVOID pGuid,
IN OUT PWNODE_SINGLE_INSTANCE * pwnode
)
{
/*
sets up a wmi node
the caller will fill in the data block after the call returns
*/
PWNODE_SINGLE_INSTANCE wnode;
ULONG wnodeSize;
ULONG wnodeInstanceNameSize;
NTSTATUS Status;
PUCHAR ptmp;
//
// Determine the amount of wnode information we need.
//
wnodeSize = ALIGN_8_TYPE(WNODE_SINGLE_INSTANCE);
wnodeInstanceNameSize = ALIGN_8_LENGTH(InstanceName->Length + sizeof(USHORT));
wnode = ALLOC_FROM_POOL(wnodeSize + wnodeInstanceNameSize + DataBlockSize,
NDIS_TAG_WMI_EVENT_ITEM);
if (NULL != wnode)
{
NdisZeroMemory(wnode, wnodeSize + wnodeInstanceNameSize + DataBlockSize);
wnode->WnodeHeader.BufferSize = wnodeSize + DataBlockSize + wnodeInstanceNameSize;
wnode->WnodeHeader.ProviderId = IoWMIDeviceObjectToProviderId(Miniport->DeviceObject);
wnode->WnodeHeader.Version = 1;
KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
RtlCopyMemory(&wnode->WnodeHeader.Guid, pGuid, sizeof(GUID));
wnode->WnodeHeader.Flags = WNODE_FLAG_EVENT_ITEM | WNODE_FLAG_SINGLE_INSTANCE;
wnode->OffsetInstanceName = wnodeSize;
wnode->DataBlockOffset = wnodeSize + wnodeInstanceNameSize;
wnode->SizeDataBlock = DataBlockSize;
//
// Get a pointer to the start of the instance name.
//
ptmp = (PUCHAR)wnode + wnodeSize;
//
// Copy in the instance name.
//
*((PUSHORT)ptmp) = InstanceName->Length;
RtlCopyMemory(ptmp + sizeof(USHORT),
InstanceName->Buffer,
InstanceName->Length);
}
*pwnode = wnode;
}
BOOLEAN
ndisWmiCheckAccess(
IN PNDIS_GUID pNdisGuid,
IN ULONG DesiredAccess,
IN LONG RequiredPrivilege,
IN PIRP Irp
)
{
LUID Privilege;
BOOLEAN AccessAllowed = FALSE;
//
// SE_LOAD_DRIVER_PRIVILEGE
//
if ((DesiredAccess & fNDIS_GUID_ALLOW_READ) == fNDIS_GUID_ALLOW_READ)
{
if (pNdisGuid->Flags & fNDIS_GUID_ALLOW_READ)
{
AccessAllowed = TRUE;
}
else
{
Privilege = RtlConvertLongToLuid(RequiredPrivilege);
AccessAllowed = SeSinglePrivilegeCheck(Privilege, Irp->RequestorMode);
}
}
else if ((DesiredAccess & fNDIS_GUID_ALLOW_WRITE) == fNDIS_GUID_ALLOW_WRITE)
{
if (pNdisGuid->Flags & fNDIS_GUID_ALLOW_WRITE)
{
AccessAllowed = TRUE;
}
else
{
Privilege = RtlConvertLongToLuid(RequiredPrivilege);
AccessAllowed = SeSinglePrivilegeCheck(Privilege, Irp->RequestorMode);
}
}
else
{
#if DBG
DbgPrint("ndisWmiCheckAccess: DesiredAccess can only be READ or WRITE.\n");
#endif
ASSERT(FALSE);
}
return AccessAllowed;
}