[WDF] Add Windows Driver Framework files

Takern from Microsoft GitHub repo:
d9c6040fe9

Licensed under MIT
This commit is contained in:
Victor Perevertkin 2020-09-24 23:51:15 +03:00
parent 545df81502
commit 8a978a179f
No known key found for this signature in database
GPG key ID: C750B7222E9C7830
475 changed files with 285099 additions and 0 deletions

View file

@ -0,0 +1,433 @@
/*++
Copyright (c) Microsoft Corporation
Module Name:
FxIoTargetAPIKm.cpp
Abstract:
This module implements the IO Target APIs
Author:
Environment:
kernel mode only
Revision History:
--*/
#include "..\..\FxTargetsShared.hpp"
extern "C" {
#include "FxIoTargetAPIKm.tmh"
}
//
// Extern the entire file
//
extern "C" {
__drv_maxIRQL(DISPATCH_LEVEL)
PDEVICE_OBJECT
WDFEXPORT(WdfIoTargetWdmGetTargetDeviceObject)(
__in
PWDF_DRIVER_GLOBALS DriverGlobals,
__in
WDFIOTARGET IoTarget
)
/*++
Routine Description:
Returns the PDEVICE_OBJECT. This is the device which PIRPs are sent to.
This is not necessarily the PDEVICE_OBJECT that WDFDEVICE is attached to.
Arguments:
IoTarget - target whose WDM device object is being returned
Return Value:
valid PDEVICE_OBJECT or NULL on failure
--*/
{
PFX_DRIVER_GLOBALS pFxDriverGlobals;
FxIoTarget* pTarget;
PDEVICE_OBJECT pDevice;
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
IoTarget,
FX_TYPE_IO_TARGET,
(PVOID*) &pTarget,
&pFxDriverGlobals);
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
"enter WDFIOTARGET 0x%p", IoTarget);
pDevice = pTarget->GetTargetDevice();
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
"exit WDFIOTARGET 0x%p, WDM DevObj 0x%p", IoTarget, pDevice);
return pDevice;
}
__drv_maxIRQL(DISPATCH_LEVEL)
PDEVICE_OBJECT
WDFEXPORT(WdfIoTargetWdmGetTargetPhysicalDevice)(
__in
PWDF_DRIVER_GLOBALS DriverGlobals,
__in
WDFIOTARGET IoTarget
)
/*++
Routine Description:
Returns the PDO for the target itself. This is not necessarily the same
PDO as the WDFDEVICE that owns the target. Not all targets have a PDO since
you can open a legacy non pnp PDEVICE_OBJECT which does not have one.
Arguments:
IoTarget - target whose PDO is being returned
Return Value:
A valid PDEVICE_OBJECT or NULL upon success
--*/
{
PFX_DRIVER_GLOBALS pFxDriverGlobals;
FxIoTarget* pTarget;
PDEVICE_OBJECT pPdo;
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
IoTarget,
FX_TYPE_IO_TARGET,
(PVOID*) &pTarget,
&pFxDriverGlobals);
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
"enter WDFIOTARGET 0x%p", IoTarget);
pPdo = pTarget->GetTargetPDO();
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
"exit WDFIOTARGET 0x%p, WDM PDO 0x%p", IoTarget, pPdo);
return pPdo;
}
__drv_maxIRQL(DISPATCH_LEVEL)
PFILE_OBJECT
WDFEXPORT(WdfIoTargetWdmGetTargetFileObject)(
__in
PWDF_DRIVER_GLOBALS DriverGlobals,
__in
WDFIOTARGET IoTarget
)
/*++
Routine Description:
Returns the PFILE_OBJECT associated with the target. Not all targets have
an underlying file object so NULL is a valid and successful return value.
Arguments:
IoTarget - the target whose fileobject is being returned
Return Value:
a valid PFILE_OBJECT or NULL upon success
--*/
{
PFX_DRIVER_GLOBALS pFxDriverGlobals;
FxIoTarget* pTarget;
MdFileObject pFile;
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
IoTarget,
FX_TYPE_IO_TARGET,
(PVOID*) &pTarget,
&pFxDriverGlobals);
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
"enter WDFIOTARGET 0x%p", IoTarget);
pFile = pTarget->GetTargetFileObject();
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
"exit WDFIOTARGET 0x%p, WDM FileObj 0x%p", IoTarget, pFile);
return pFile;
}
__drv_maxIRQL(PASSIVE_LEVEL)
_Must_inspect_result_
NTSTATUS
WDFEXPORT(WdfIoTargetQueryForInterface)(
__in
PWDF_DRIVER_GLOBALS DriverGlobals,
__in
WDFIOTARGET IoTarget,
__in
LPCGUID InterfaceType,
__out
PINTERFACE Interface,
__in
USHORT Size,
__in
USHORT Version,
__in_opt
PVOID InterfaceSpecificData
)
/*++
Routine Description:
Sends a query interface pnp request to the top of the target's stack.
Arguments:
IoTarget - the target which is being queried
InterfaceType - interface type specifier
Interface - Interface block which will be filled in by the component which
responds to the query interface
Size - size in bytes of Interface
Version - version of InterfaceType being requested
InterfaceSpecificData - Additional data associated with Interface
Return Value:
NTSTATUS
--*/
{
FxIoTarget* pTarget;
PFX_DRIVER_GLOBALS pFxDriverGlobals;
PDEVICE_OBJECT pTopOfStack;
NTSTATUS status;
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
IoTarget,
FX_TYPE_IO_TARGET,
(PVOID*) &pTarget,
&pFxDriverGlobals);
FxPointerNotNull(pFxDriverGlobals, InterfaceType);
FxPointerNotNull(pFxDriverGlobals, Interface);
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
if (!NT_SUCCESS(status)) {
return status;
}
pTopOfStack = IoGetAttachedDeviceReference(pTarget->GetTargetDevice());
ASSERT(pTopOfStack != NULL);
status = FxQueryInterface::_QueryForInterface(pTopOfStack,
InterfaceType,
Interface,
Size,
Version,
InterfaceSpecificData);
ObDereferenceObject(pTopOfStack);
return status;
}
_Must_inspect_result_
__drv_maxIRQL(PASSIVE_LEVEL)
NTSTATUS
WDFEXPORT(WdfIoTargetQueryTargetProperty)(
__in
PWDF_DRIVER_GLOBALS DriverGlobals,
__in
WDFIOTARGET IoTarget,
__in
DEVICE_REGISTRY_PROPERTY DeviceProperty,
__in
ULONG BufferLength,
__drv_when(BufferLength != 0, __out_bcount_part_opt(BufferLength, *ResultLength))
__drv_when(BufferLength == 0, __out_opt)
PVOID PropertyBuffer,
__deref_out_range(<=,BufferLength)
PULONG ResultLength
)
/*++
Routine Description:
Retrieves the requested device property for the given target
Arguments:
IoTarget - the target whose PDO whose will be queried
DeviceProperty - the property being queried
BufferLength - length of PropertyBuffer in bytes
PropertyBuffer - Buffer which will receive the property being queried
ResultLength - if STATUS_BUFFER_TOO_SMALL is returned, then this will contain
the required length
Return Value:
NTSTATUS
--*/
{
DDI_ENTRY();
PFX_DRIVER_GLOBALS pGlobals;
NTSTATUS status;
FxIoTarget* pTarget;
MdDeviceObject pPdo;
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
IoTarget,
FX_TYPE_IO_TARGET,
(PVOID*) &pTarget,
&pGlobals);
FxPointerNotNull(pGlobals, ResultLength);
if (BufferLength > 0) {
FxPointerNotNull(pGlobals, PropertyBuffer);
}
status = FxVerifierCheckIrqlLevel(pGlobals, PASSIVE_LEVEL);
if (!NT_SUCCESS(status)) {
return status;
}
pPdo = pTarget->GetTargetPDO();
if (pPdo == NULL) {
status = STATUS_INVALID_DEVICE_REQUEST;
DoTraceLevelMessage(pGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"WDFIOTARGET 0x%p has no PDO (not opened yet?), %!STATUS!",
IoTarget, status);
return status;
}
status = FxDevice::_GetDeviceProperty(pPdo,
DeviceProperty,
BufferLength,
PropertyBuffer,
ResultLength);
DoTraceLevelMessage(pGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
"exit WDFIOTARGET 0x%p, Property %d, %!STATUS!",
IoTarget, DeviceProperty, status);
return status;
}
_Must_inspect_result_
__drv_maxIRQL(PASSIVE_LEVEL)
WDFAPI
NTSTATUS
WDFEXPORT(WdfIoTargetAllocAndQueryTargetProperty)(
__in
PWDF_DRIVER_GLOBALS DriverGlobals,
__in
WDFIOTARGET IoTarget,
__in
DEVICE_REGISTRY_PROPERTY DeviceProperty,
__in
__drv_strictTypeMatch(1)
POOL_TYPE PoolType,
__in_opt
PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes,
__out
WDFMEMORY* PropertyMemory
)
/*++
Routine Description:
Allocates and retrieves the requested device property for the given target
Arguments:
IoTarget - the target whose PDO whose will be queried
DeviceProperty - the property being queried
PoolType - what type of pool to allocate
PropertyMemoryAttributes - attributes to associate with PropertyMemory
PropertyMemory - handle which will receive the property buffer
Return Value:
NTSTATUS
--*/
{
DDI_ENTRY();
PFX_DRIVER_GLOBALS pFxDriverGlobals;
NTSTATUS status;
FxIoTarget* pTarget;
MdDeviceObject pPdo;
FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
IoTarget,
FX_TYPE_IO_TARGET,
(PVOID*) &pTarget,
&pFxDriverGlobals);
FxPointerNotNull(pFxDriverGlobals, PropertyMemory);
*PropertyMemory = NULL;
status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
if (!NT_SUCCESS(status)) {
return status;
}
FxVerifierCheckNxPoolType(pFxDriverGlobals, PoolType, pFxDriverGlobals->Tag);
status = FxValidateObjectAttributes(pFxDriverGlobals, PropertyMemoryAttributes);
if (!NT_SUCCESS(status)) {
return status;
}
pPdo = pTarget->GetTargetPDO();
if (pPdo == NULL) {
status = STATUS_INVALID_DEVICE_REQUEST;
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"WDFIOTARGET %p has no PDO (not opened yet?), %!STATUS!",
IoTarget, status);
return status;
}
//
// Worker function which does the 2 passes. First pass to query the size,
// the second pass w/the correctly sized buffer.
//
status = FxDevice::_AllocAndQueryProperty(pFxDriverGlobals,
NULL,
NULL,
pPdo,
DeviceProperty,
PoolType,
PropertyMemoryAttributes,
PropertyMemory);
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
"exit WDFIOTARGET 0x%p, Property %d, %!STATUS!",
IoTarget, DeviceProperty, status);
return status;
}
}

View file

@ -0,0 +1,524 @@
/*++
Copyright (c) Microsoft Corporation
Module Name:
FxIoTargetKm.cpp
Abstract:
This module implements the IO Target APIs
Author:
Environment:
kernel mode only
Revision History:
--*/
#include "..\..\FxTargetsShared.hpp"
extern "C" {
#if defined(EVENT_TRACING)
#include "FxIoTargetKm.tmh"
#endif
}
_Must_inspect_result_
NTSTATUS
FxIoTarget::FormatIoRequest(
__inout FxRequestBase* Request,
__in UCHAR MajorCode,
__in FxRequestBuffer* IoBuffer,
__in_opt PLONGLONG DeviceOffset,
_In_opt_ FxFileObject* FileObject
)
{
FxIoContext* pContext;
PVOID pBuffer;
NTSTATUS status;
ULONG ioLength;
BOOLEAN freeSysBuf;
BOOLEAN setBufferAndLength;
FxIrp* irp;
UNREFERENCED_PARAMETER(FileObject);
ASSERT(MajorCode == IRP_MJ_WRITE || MajorCode == IRP_MJ_READ);
freeSysBuf = FALSE;
pBuffer = NULL;
status = Request->ValidateTarget(this);
if (!NT_SUCCESS(status)) {
return status;
}
if (Request->HasContextType(FX_RCT_IO)) {
pContext = (FxIoContext*) Request->GetContext();
}
else {
pContext = new(GetDriverGlobals()) FxIoContext();
if (pContext == NULL) {
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"could not allocate context for request");
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Since we can error out and return, remember the allocation before
// we do anything so we can free it later.
//
Request->SetContext(pContext);
}
//
// Save away any references to IFxMemory pointers that are passed
//
pContext->StoreAndReferenceMemory(IoBuffer);
irp = Request->GetSubmitFxIrp();
irp->ClearNextStackLocation();
CopyFileObjectAndFlags(Request);
//
// Note that by convention "Set" methods of FxIrp apply to next stack
// location unless specified otherwise in the name.
//
irp->SetMajorFunction(MajorCode);
pContext->m_MajorFunction = MajorCode;
//
// Anytime we return here and we allocated the context above, the context
// will be freed when the FxRequest is freed or reformatted.
//
ioLength = IoBuffer->GetBufferLength();
pContext->CaptureState(irp);
switch (m_TargetIoType) {
case WdfDeviceIoBuffered:
irp->SetUserBuffer(NULL);
if (ioLength != 0) {
if ((pContext->m_BufferToFreeLength >= ioLength) &&
(pContext->m_BufferToFree != NULL)) {
irp->SetSystemBuffer(pContext->m_BufferToFree);
setBufferAndLength = FALSE;
}
else {
irp->SetSystemBuffer(FxPoolAllocate(GetDriverGlobals(),
NonPagedPool,
ioLength));
if (irp->GetSystemBuffer() == NULL) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not allocate common buffer");
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
setBufferAndLength = TRUE;
freeSysBuf = TRUE;
}
status = IoBuffer->GetBuffer(&pBuffer);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not retrieve io buffer, %!STATUS!", status);
break;
}
//
// If its a write, copy into the double buffer now, otherwise,
// no copy into the buffer is needed for a read.
//
if (MajorCode == IRP_MJ_WRITE) {
if (pBuffer != NULL) {
RtlCopyMemory(irp->GetSystemBuffer(),
pBuffer,
ioLength);
}
}
else {
irp->SetUserBuffer(pBuffer);
}
//
// On reads, copy back to the double buffer after the read has
// completed.
//
if (setBufferAndLength) {
pContext->SetBufferAndLength(irp->GetSystemBuffer(),
ioLength,
(MajorCode == IRP_MJ_READ) ? TRUE : FALSE);
freeSysBuf = FALSE; // FxIoContext will free the buffer.
}
else {
pContext->m_CopyBackToBuffer = MajorCode == IRP_MJ_READ ?
TRUE : FALSE;
}
}
else {
//
// This field was captured and will be restored by the context
// later.
//
irp->SetSystemBuffer(NULL);
}
break;
case WdfDeviceIoDirect:
{
BOOLEAN reuseMdl;
reuseMdl = FALSE;
if (pContext->m_MdlToFree != NULL) {
reuseMdl = TRUE;
}
status = IoBuffer->GetOrAllocateMdl(
GetDriverGlobals(),
irp->GetMdlAddressPointer(),
&pContext->m_MdlToFree,
&pContext->m_UnlockPages,
(MajorCode == IRP_MJ_READ) ? IoWriteAccess : IoReadAccess,
reuseMdl,
&pContext->m_MdlToFreeSize
);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not retrieve io buffer as a PMDL, %!STATUS!",
status);
break;
}
break;
}
case WdfDeviceIoNeither:
//
// Neither MDL nor buffered
//
status = IoBuffer->GetBuffer(&pBuffer);
if (NT_SUCCESS(status)) {
irp->SetUserBuffer(pBuffer);
}
else {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not retrieve io buffer as a PVOID, %!STATUS!",
status);
}
break;
case WdfDeviceIoUndefined:
default:
status = STATUS_INVALID_DEVICE_STATE;
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Trying to format closed WDFIOTARGET %p, %!STATUS!",
GetHandle(), status);
break;
}
//
// We are assuming the read and write parts of the Parameters union
// are at the same offset. If this is FALSE, WDFCASSERT will not allow
// this file to compile, so keep these WDFCASSERTs here as long as the
// assumption is being made.
//
WDFCASSERT(FIELD_OFFSET(IO_STACK_LOCATION, Parameters.Write.ByteOffset)
==
FIELD_OFFSET(IO_STACK_LOCATION, Parameters.Read.ByteOffset));
WDFCASSERT(FIELD_OFFSET(IO_STACK_LOCATION, Parameters.Write.Length)
==
FIELD_OFFSET(IO_STACK_LOCATION, Parameters.Read.Length));
if (NT_SUCCESS(status)) {
irp->SetNextParameterWriteLength(ioLength);
if (DeviceOffset != NULL) {
irp->SetNextParameterWriteByteOffsetQuadPart(*DeviceOffset);
}
else {
irp->SetNextParameterWriteByteOffsetQuadPart(0);
}
Request->VerifierSetFormatted();
}
else {
if (freeSysBuf) {
FxPoolFree(irp->GetSystemBuffer());
irp->SetSystemBuffer(NULL);
}
Request->ContextReleaseAndRestore();
}
return status;
}
_Must_inspect_result_
NTSTATUS
FxIoTarget::FormatIoctlRequest(
__in FxRequestBase* Request,
__in ULONG Ioctl,
__in BOOLEAN Internal,
__in FxRequestBuffer* InputBuffer,
__in FxRequestBuffer* OutputBuffer,
_In_opt_ FxFileObject* FileObject
)
{
FxIoContext* pContext;
NTSTATUS status;
PVOID pBuffer;
ULONG inLength, outLength;
BOOLEAN freeSysBuf;
BOOLEAN setBufferAndLength;
FxIrp* irp;
UNREFERENCED_PARAMETER(FileObject);
irp = Request->GetSubmitFxIrp();
freeSysBuf = FALSE;
status = Request->ValidateTarget(this);
if (!NT_SUCCESS(status)) {
return status;
}
if (Request->HasContextType(FX_RCT_IO)) {
pContext = (FxIoContext*) Request->GetContext();
}
else {
pContext = new(GetDriverGlobals()) FxIoContext();
if (pContext == NULL) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not allocate context for request");
return STATUS_INSUFFICIENT_RESOURCES;
}
Request->SetContext(pContext);
}
pContext->CaptureState(irp);
irp->ClearNextStackLocation();
//
// Save away any references to IFxMemory pointers that are passed
//
pContext->StoreAndReferenceMemory(InputBuffer);
pContext->StoreAndReferenceOtherMemory(OutputBuffer);
UCHAR majorFunction;
if (Internal) {
majorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
}
else {
majorFunction = IRP_MJ_DEVICE_CONTROL;
}
irp->SetMajorFunction(majorFunction);
pContext->m_MajorFunction = majorFunction;
CopyFileObjectAndFlags(Request);
inLength = InputBuffer->GetBufferLength();
outLength = OutputBuffer->GetBufferLength();
irp->SetParameterIoctlCode(Ioctl);
irp->SetParameterIoctlInputBufferLength(inLength);
irp->SetParameterIoctlOutputBufferLength(outLength);
//
// Anytime we return here and we allocated the context above, the context
// will be freed when the FxRequest is freed or reformatted.
//
switch (METHOD_FROM_CTL_CODE(Ioctl)) {
case METHOD_BUFFERED:
if (inLength != 0 || outLength != 0) {
ULONG allocationLength;
allocationLength = (inLength > outLength ? inLength : outLength);
if ((pContext->m_BufferToFreeLength >= allocationLength) &&
(pContext->m_BufferToFree != NULL)) {
irp->SetSystemBuffer(pContext->m_BufferToFree);
setBufferAndLength = FALSE;
}
else {
irp->SetSystemBuffer(FxPoolAllocate(GetDriverGlobals(),
NonPagedPool,
allocationLength));
if (irp->GetSystemBuffer() == NULL) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not allocate common buffer");
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
setBufferAndLength = TRUE;
freeSysBuf = TRUE;
}
status = InputBuffer->GetBuffer(&pBuffer);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not retrieve input buffer, %!STATUS!",
status);
break;
}
if (pBuffer != NULL) {
RtlCopyMemory(irp->GetSystemBuffer(),
pBuffer,
inLength);
}
status = OutputBuffer->GetBuffer(&pBuffer);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not retrieve output buffer, %!STATUS!",
status);
break;
}
irp->SetUserBuffer(pBuffer);
if (setBufferAndLength) {
pContext->SetBufferAndLength(irp->GetSystemBuffer(),
allocationLength,
outLength > 0 ? TRUE : FALSE);
freeSysBuf = FALSE; // FxIoContext will free the buffer.
} else {
pContext->m_CopyBackToBuffer = outLength > 0 ? TRUE : FALSE;
}
}
else {
//
// These fields were captured and will be restored by the context
// later.
//
irp->SetUserBuffer(NULL);
irp->SetSystemBuffer(NULL);
}
break;
case METHOD_DIRECT_TO_HARDWARE: // METHOD_IN_DIRECT
case METHOD_DIRECT_FROM_HARDWARE: // METHOD_OUT_DIRECT
{
BOOLEAN reuseMdl;
reuseMdl = FALSE;
status = InputBuffer->GetBuffer(&pBuffer);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not retrieve input buffer as a PVOID, %!STATUS!",
status);
break;
}
irp->SetSystemBuffer(pBuffer);
//
// NOTE: There is no need to compare the operation type since that
// applies only to the Pages locked in memory and not the MDL data
// structure itself per se.
// Also, note that if the size of the Outbuf need not be equal to the
// size of the MdlToFree as long as the number of page entries match.
//
if (pContext->m_MdlToFree != NULL) {
reuseMdl = TRUE;
}
status = OutputBuffer->GetOrAllocateMdl(
GetDriverGlobals(),
irp->GetMdlAddressPointer(),
&pContext->m_MdlToFree,
&pContext->m_UnlockPages,
(METHOD_FROM_CTL_CODE(Ioctl) == METHOD_DIRECT_TO_HARDWARE) ? IoReadAccess : IoWriteAccess,
reuseMdl,
&pContext->m_MdlToFreeSize
);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not retrieve output buffer as a PMDL, %!STATUS!",
status);
break;
}
break;
}
case METHOD_NEITHER:
status = OutputBuffer->GetBuffer(&pBuffer);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not retrieve output buffer as a PVOID, %!STATUS!",
status);
break;
}
irp->SetUserBuffer(pBuffer);
status = InputBuffer->GetBuffer(&pBuffer);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not retrieve input buffer as a PVOID, %!STATUS!",
status);
break;
}
irp->SetParameterIoctlType3InputBuffer(pBuffer);
break;
}
if (NT_SUCCESS(status)) {
Request->VerifierSetFormatted();
}
else {
if (freeSysBuf) {
FxPoolFree(irp->GetSystemBuffer());
irp->SetSystemBuffer(NULL);
}
Request->ContextReleaseAndRestore();
}
return status;
}

View file

@ -0,0 +1,366 @@
/*++
Copyright (c) Microsoft Corporation
Module Name:
FxIoTargetRemoteKm.cpp
Abstract:
Author:
Environment:
kernel mode only
Revision History:
--*/
#include "..\..\FxTargetsShared.hpp"
extern "C" {
#include "FxIoTargetRemoteKm.tmh"
}
#include <initguid.h>
#include "wdmguid.h"
_Must_inspect_result_
NTSTATUS
FxIoTargetRemote::_PlugPlayNotification(
__in PVOID NotificationStructure,
__inout_opt PVOID Context
)
{
PFX_DRIVER_GLOBALS pFxDriverGlobals;
PTARGET_DEVICE_REMOVAL_NOTIFICATION pNotification;
FxIoTargetRemote* pThis;
NTSTATUS status;
ASSERT(Mx::MxGetCurrentIrql() < DISPATCH_LEVEL);
pNotification = (PTARGET_DEVICE_REMOVAL_NOTIFICATION) NotificationStructure;
pThis = (FxIoTargetRemote*) Context;
//
// In one of these callbacks, the driver may decide to delete the target.
// If that is the case, we need to be able to return and deref the object until
// we are done.
//
pThis->ADDREF(_PlugPlayNotification);
pFxDriverGlobals = pThis->GetDriverGlobals();
status = STATUS_SUCCESS;
if (FxIsEqualGuid(&pNotification->Event, &GUID_TARGET_DEVICE_QUERY_REMOVE)) {
DoTraceLevelMessage(
pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
"WDFIOTARGET %p: query remove notification", pThis->GetObjectHandle());
//
// Device is gracefully being removed. PnP is asking us to close down
// the target. If there is a driver callback, there is *no* default
// behavior. This is because we don't know what the callback is going
// to do. For instance, the driver could reopen the target to a
// different device in a multi-path scenario.
//
if (pThis->m_EvtQueryRemove.m_Method != NULL) {
status = pThis->m_EvtQueryRemove.Invoke(pThis->GetHandle());
}
else {
DoTraceLevelMessage(
pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
"WDFIOTARGET %p: query remove, default action (close for QR)",
pThis->GetObjectHandle());
//
// No callback, close it down conditionally.
//
pThis->Close(FxIoTargetRemoteCloseReasonQueryRemove);
}
}
else if (FxIsEqualGuid(&pNotification->Event, &GUID_TARGET_DEVICE_REMOVE_COMPLETE)) {
DoTraceLevelMessage(
pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
"WDFIOTARGET %p: remove complete notification", pThis->GetObjectHandle());
//
// The device was surprise removed, close it for good if the driver has
// no override.
//
if (pThis->m_EvtRemoveComplete.m_Method != NULL) {
pThis->m_EvtRemoveComplete.Invoke(pThis->GetHandle());
}
else {
DoTraceLevelMessage(
pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
"WDFIOTARGET %p: remove complete, default action (close)",
pThis->GetObjectHandle());
//
// The device is now gone for good. Close down the target for good.
//
pThis->Close(FxIoTargetRemoteCloseReasonPlainClose);
}
}
else if (FxIsEqualGuid(&pNotification->Event, &GUID_TARGET_DEVICE_REMOVE_CANCELLED)) {
DoTraceLevelMessage(
pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
"WDFIOTARGET %p: remove canceled notification", pThis->GetObjectHandle());
if (pThis->m_EvtRemoveCanceled.m_Method != NULL) {
pThis->m_EvtRemoveCanceled.Invoke(pThis->GetHandle());
}
else {
WDF_IO_TARGET_OPEN_PARAMS params;
DoTraceLevelMessage(
pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
"WDFIOTARGET %p: remove canceled, default action (reopen)",
pThis->GetObjectHandle());
WDF_IO_TARGET_OPEN_PARAMS_INIT_REOPEN(&params);
//
// Attempt to reopen the target with stored settings
//
status = pThis->Open(&params);
}
}
pThis->RELEASE(_PlugPlayNotification);
return status;
}
NTSTATUS
FxIoTargetRemote::RegisterForPnpNotification(
)
{
NTSTATUS status;
//
// Register for PNP notifications on the handle we just opened.
// This will notify us of pnp state changes on the handle.
//
status = IoRegisterPlugPlayNotification(
EventCategoryTargetDeviceChange,
0,
m_TargetFileObject,
m_Driver->GetDriverObject(),
_PlugPlayNotification,
this,
&m_TargetNotifyHandle);
return status;
}
VOID
FxIoTargetRemote::UnregisterForPnpNotification(
_In_ MdTargetNotifyHandle Handle
)
{
if (Handle != NULL) {
if (FxLibraryGlobals.IoUnregisterPlugPlayNotificationEx != NULL) {
FxLibraryGlobals.IoUnregisterPlugPlayNotificationEx(Handle);
}
else {
IoUnregisterPlugPlayNotification(Handle);
}
}
}
NTSTATUS
FxIoTargetRemote::OpenTargetHandle(
_In_ PWDF_IO_TARGET_OPEN_PARAMS OpenParams,
_Inout_ FxIoTargetRemoveOpenParams* pParams
)
{
OBJECT_ATTRIBUTES oa;
IO_STATUS_BLOCK ioStatus;
NTSTATUS status;
InitializeObjectAttributes(&oa,
&pParams->TargetDeviceName,
OBJ_KERNEL_HANDLE,
NULL,
NULL);
status = ZwCreateFile(&m_TargetHandle,
pParams->DesiredAccess,
&oa,
&ioStatus,
pParams->AllocationSizePointer,
pParams->FileAttributes,
pParams->ShareAccess,
pParams->CreateDisposition,
pParams->CreateOptions,
pParams->EaBuffer,
pParams->EaBufferLength);
OpenParams->FileInformation = (ULONG)ioStatus.Information;
if (NT_SUCCESS(status)) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGIOTARGET,
"ZwCreateFile for WDFIOTARGET %p returned status %!STATUS!, info 0x%x",
GetObjectHandle(), status, (ULONG) ioStatus.Information);
//
// The open operation was successful. Dereference the file handle and
// obtain a pointer to the device object for the handle.
//
status = ObReferenceObjectByHandle(
m_TargetHandle,
pParams->DesiredAccess,
*IoFileObjectType,
KernelMode,
(PVOID*) &m_TargetFileObject,
NULL);
if (NT_SUCCESS(status)) {
m_TargetDevice = IoGetRelatedDeviceObject(m_TargetFileObject);
if (m_TargetDevice == NULL) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"WDFIOTARGET %p, could not convert filobj %p to devobj",
GetObjectHandle(), m_TargetFileObject);
status = STATUS_NO_SUCH_DEVICE;
}
}
else {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"WDFIOTARGET %p, could not convert handle %p to fileobject, "
"status %!STATUS!",
GetObjectHandle(), m_TargetHandle, status);
}
}
else {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"ZwCreateFile for WDFIOTARGET %p returned status %!STATUS!, info 0x%x",
GetObjectHandle(), status, (ULONG) ioStatus.Information);
}
return status;
}
NTSTATUS
FxIoTargetRemote::GetTargetDeviceRelations(
_Inout_ BOOLEAN* Close
)
{
PDEVICE_OBJECT pTopOfStack;
FxAutoIrp irp(NULL);
PIRP pIrp;
NTSTATUS status;
pTopOfStack = IoGetAttachedDeviceReference(m_TargetDevice);
pIrp = IoAllocateIrp(pTopOfStack->StackSize, FALSE);
if (pIrp != NULL) {
PIO_STACK_LOCATION stack;
irp.SetIrp(pIrp);
stack = irp.GetNextIrpStackLocation();
stack->MajorFunction = IRP_MJ_PNP;
stack->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
stack->Parameters.QueryDeviceRelations.Type = TargetDeviceRelation;
//
// Initialize the status to error in case the bus driver decides not
// to set it correctly.
//
irp.SetStatus(STATUS_NOT_SUPPORTED);
status = irp.SendIrpSynchronously(pTopOfStack);
if (NT_SUCCESS(status)) {
PDEVICE_RELATIONS pRelations;
pRelations = (PDEVICE_RELATIONS) irp.GetInformation();
ASSERT(pRelations != NULL);
//
// m_TargetPdo was referenced by the bus driver, it will be
// dereferenced when the target is closed.
//
m_TargetPdo = pRelations->Objects[0];
//
// We, as the caller, are responsible for freeing the relations
// that the bus driver allocated.
//
ExFreePool(pRelations);
}
else {
//
// Could not retrieve the PDO pointer, error handled later
//
DO_NOTHING();
}
}
else {
//
// Could not even allocate an irp, failure.
//
status = STATUS_INSUFFICIENT_RESOURCES;
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Unable to allocate memory for IRP WDFIOTARGET %p, %!STATUS!",
GetObjectHandle(), status);
}
//
// Only fail the open if we cannot allocate an irp or if the lower
// driver could not allocate a relations.
//
if (status == STATUS_INSUFFICIENT_RESOURCES) {
*Close = TRUE;
}
else {
status = STATUS_SUCCESS;
}
//
// Remove the reference taken by IoGetAttachedDeviceReference
//
ObDereferenceObject(pTopOfStack);
return status;
}