////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2012 Microsoft Corporation. All Rights Reserved.
//
// Module Name:
// Framework_PowerStates.cpp
//
// Abstract:
//
// Author:
// Dusty Harper (DHarper)
//
// Revision History:
//
// [ Month ][Day] [Year] - [Revision]-[ Comments ]
// May 01, 2010 - 1.0 - Creation
//
////////////////////////////////////////////////////////////////////////////////////////////////////
#include "Framework_WFPSamplerCalloutDriver.h" /// .
#include "Framework_PowerStates.tmh" /// $(OBJ_PATH)\$(O)\
KGUARDED_MUTEX guardedMutex = {0};
/**
@framework_function="ActOnPowerStateEnter"
Purpose: Passive function to handle entering a power managed state. Prior to dropping into a power managed
state, unregister the callouts. This prevents the driver from potentially taking any more
references on NBLs, and instead causes the filters to return BLOCK. This should also allow adequate
time to drain currently queued NBLs.
Notes:
MSDN_Ref: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/nc-wdm-io_workitem_routine
*/
_IRQL_requires_(PASSIVE_LEVEL)
_IRQL_requires_same_
_Function_class_(IO_WORKITEM_ROUTINE)
VOID ActOnPowerStateEnter(_In_ PDEVICE_OBJECT pDeviceObject,
_Inout_opt_ PVOID pContext)
{
#if DBG
DbgPrintEx(DPFLTR_IHVNETWORK_ID,
DPFLTR_INFO_LEVEL,
" ---> ActOnPowerStateEnter()\n");
#endif /// DBG
UNREFERENCED_PARAMETER(pDeviceObject);
UNREFERENCED_PARAMETER(pContext);
KeAcquireGuardedMutex(&guardedMutex);
if(g_calloutsRegistered == TRUE)
{
NTSTATUS status = STATUS_SUCCESS;
status = KrnlHlprExposedCalloutsUnregister();
HLPR_BAIL_ON_FAILURE(status);
g_calloutsRegistered = FALSE;
}
HLPR_BAIL_LABEL:
KeReleaseGuardedMutex(&guardedMutex);
#if DBG
DbgPrintEx(DPFLTR_IHVNETWORK_ID,
DPFLTR_INFO_LEVEL,
" <--- ActOnPowerStateEnter()\n");
#endif /// DBG
return;
}
/**
@framework_function="ActOnPowerStateExit"
Purpose: Passive function to handle exiting a power managed state. When coming out of a power managed state,
register the callouts so normal processing of NBLs will commence.
Notes:
MSDN_Ref: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/nc-wdm-io_workitem_routine
*/
_IRQL_requires_(PASSIVE_LEVEL)
_IRQL_requires_same_
_Function_class_(IO_WORKITEM_ROUTINE)
VOID ActOnPowerStateExit(_In_ PDEVICE_OBJECT pDeviceObject,
_Inout_opt_ PVOID pContext)
{
#if DBG
DbgPrintEx(DPFLTR_IHVNETWORK_ID,
DPFLTR_INFO_LEVEL,
" ---> ActOnPowerStateExit()\n");
#endif /// DBG
UNREFERENCED_PARAMETER(pDeviceObject);
UNREFERENCED_PARAMETER(pContext);
KeAcquireGuardedMutex(&guardedMutex);
if(g_calloutsRegistered == FALSE)
{
NTSTATUS status = STATUS_SUCCESS;
status = KrnlHlprExposedCalloutsRegister();
HLPR_BAIL_ON_FAILURE(status);
g_calloutsRegistered = TRUE;
}
HLPR_BAIL_LABEL:
KeReleaseGuardedMutex(&guardedMutex);
#if DBG
DbgPrintEx(DPFLTR_IHVNETWORK_ID,
DPFLTR_INFO_LEVEL,
" <--- ActOnPowerStateExit()\n");
#endif /// DBG
return;
}
/**
@framework_function="PowerStateCallback"
Purpose: Callback which handles various power state transitions for the callout driver.
Notes:
MSDN_Ref:
*/
_IRQL_requires_same_
_Function_class_(CALLBACK_FUNCTION)
VOID PowerStateCallback(_In_ VOID* pCallbackContext,
_In_ VOID* pPowerStateEvent,
_In_ VOID* pEventSpecifics)
{
#if DBG
DbgPrintEx(DPFLTR_IHVNETWORK_ID,
DPFLTR_INFO_LEVEL,
" ---> PowerStateCallback()\n");
#endif /// DBG
UNREFERENCED_PARAMETER(pCallbackContext);
if(pPowerStateEvent == (VOID*)PO_CB_SYSTEM_STATE_LOCK)
{
if(pEventSpecifics)
{
/// entering the ON state (S0), so return operation to normal
IoQueueWorkItem(g_pPowerStateExitIOWorkItem,
ActOnPowerStateExit,
DelayedWorkQueue,
0);
}
else
{
IoQueueWorkItem(g_pPowerStateEnterIOWorkItem,
ActOnPowerStateEnter,
DelayedWorkQueue,
0);
}
}
#if DBG
DbgPrintEx(DPFLTR_IHVNETWORK_ID,
DPFLTR_INFO_LEVEL,
" <--- PowerStateCallback()\n");
#endif /// DBG
return;
}
/**
@framework_function="UnregisterPowerStateChangeCallback"
Purpose: Unregister a callback that handled notifications of power state changes.
Notes:
MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/FF545649.aspx
HTTP://MSDN.Microsoft.com/En-US/Library/FF547724.aspx
*/
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(APC_LEVEL)
_IRQL_requires_same_
VOID UnregisterPowerStateChangeCallback(_Inout_ DEVICE_EXTENSION* pDeviceExtension)
{
#if DBG
DbgPrintEx(DPFLTR_IHVNETWORK_ID,
DPFLTR_INFO_LEVEL,
" ---> UnregisterPowerStateChangeCallback()\n");
#endif /// DBG
NT_ASSERT(pDeviceExtension);
if(pDeviceExtension->pRegistration)
{
ExUnregisterCallback(pDeviceExtension->pRegistration);
pDeviceExtension->pRegistration = 0;
}
if(pDeviceExtension->pCallbackObject)
{
ObDereferenceObject(pDeviceExtension->pCallbackObject);
pDeviceExtension->pCallbackObject = 0;
}
#if DBG
DbgPrintEx(DPFLTR_IHVNETWORK_ID,
DPFLTR_INFO_LEVEL,
" <--- UnregisterPowerStateChangeCallback()\n");
#endif /// DBG
return;
}
/**
@framework_function="RegisterPowerStateChangeCallback"
Purpose: Create and register a callback to handle notifications of power state changes.
Notes:
MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/FF544560.aspx
HTTP://MSDN.Microsoft.com/En-US/Library/FF545534.aspx
*/
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(APC_LEVEL)
_IRQL_requires_same_
_Success_(return == STATUS_SUCCESS)
NTSTATUS RegisterPowerStateChangeCallback(_Inout_ DEVICE_EXTENSION* pDeviceExtension)
{
#if DBG
DbgPrintEx(DPFLTR_IHVNETWORK_ID,
DPFLTR_INFO_LEVEL,
" ---> RegisterPowerStateChangeCallback()\n");
#endif /// DBG
NT_ASSERT(pDeviceExtension);
NTSTATUS status = STATUS_SUCCESS;
OBJECT_ATTRIBUTES objectAttributes = {0};
UNICODE_STRING unicodeString = {0};
KeInitializeGuardedMutex(&guardedMutex);
RtlInitUnicodeString(&unicodeString,
L"\\Callback\\PowerState");
InitializeObjectAttributes(&objectAttributes,
&unicodeString,
OBJ_CASE_INSENSITIVE,
0,
0);
status = ExCreateCallback(&(pDeviceExtension->pCallbackObject),
&objectAttributes,
FALSE, /// Do not create as the system should already have done this
TRUE); /// Allow multiple callbacks
if(status != STATUS_SUCCESS)
{
DbgPrintEx(DPFLTR_IHVNETWORK_ID,
DPFLTR_ERROR_LEVEL,
" !!!! RegisterPowerStateChangeCallback : ExCreateCallback() [status: %#x]\n",
status);
HLPR_BAIL;
}
pDeviceExtension->pRegistration = ExRegisterCallback(pDeviceExtension->pCallbackObject,
PowerStateCallback,
pDeviceExtension);
HLPR_BAIL_LABEL:
#if DBG
DbgPrintEx(DPFLTR_IHVNETWORK_ID,
DPFLTR_INFO_LEVEL,
" <--- RegisterPowerStateChangeCallback() [status: %#x]\n",
status);
#endif /// DBG
return status;
}