/*++ 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 #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; }