--- /dev/null
+/*++
+
+Copyright (c) Microsoft Corporation
+
+Module Name:
+
+ FxRequest.hpp
+
+Abstract:
+
+ This is the request object for the driver frameworks.
+
+ The request object wraps the IRP, containing persistent
+ information required by the driver frameworks.
+
+Author:
+
+
+
+
+
+Environment:
+
+ Both kernel and user mode
+
+Revision History:
+
+--*/
+
+#ifndef _FXREQUEST_H_
+#define _FXREQUEST_H_
+
+//
+// Magic number to differentiate between default value and caller provided one
+//
+#define USE_DEFAULT_PRIORITY_BOOST ((CHAR) 0x7F)
+
+//
+// This tag is used to set and clear the completion callback state as the
+// ownership of the request transfers from I/O pkg-to-queue or queue-to-queue.
+//
+#define FXREQUEST_STATE_TAG (PVOID) 'tatS'
+
+//
+// This tag is used when the request is added and removed from FxIrpQueue.
+//
+#define FXREQUEST_QUEUE_TAG (PVOID) 'ueuQ'
+
+//
+// This tag is used to take a reference in the completion path.
+//
+#define FXREQUEST_COMPLETE_TAG (PVOID) 'pmoC'
+
+//
+// Use this tag when you want to temporarily hold the object from
+// disappearing between unlock and lock operation.
+//
+#define FXREQUEST_HOLD_TAG (PVOID) 'dloH'
+
+//
+// This tag is used to take a reference in the completion path.
+//
+#define FXREQUEST_FWDPRG_TAG (PVOID) 'PdwF'
+
+//
+// This tag is used to take a reference in the completion path for driver created
+// requests that support completion operations.
+//
+#define FXREQUEST_DCRC_TAG (PVOID) 'CRCD'
+
+extern "C" {
+#if defined(EVENT_TRACING)
+#include "FxRequest.hpp.tmh"
+#endif
+}
+
+#if (FX_CORE_MODE == FX_CORE_USER_MODE)
+#define WDF_REQUEST_SEND_OPTION_IMPERSONATION_FLAGS \
+ (WDF_REQUEST_SEND_OPTION_IMPERSONATE_CLIENT | \
+ WDF_REQUEST_SEND_OPTION_IMPERSONATION_IGNORE_FAILURE)
+
+#define FxIrpStackFlagsFromSendFlags(sendFlags) \
+ ((WUDFX_IRP_STACK_FLAGS) \
+ ((sendFlags) & WDF_REQUEST_SEND_OPTION_IMPERSONATION_FLAGS))
+#endif
+
+typedef
+NTSTATUS
+(*PFN_FX_QUEUE_REQUEST_COMPLETE) (
+ __in FxRequest* Request,
+ __in FxIoQueue* Queue,
+ __in_opt WDFCONTEXT Context
+ );
+
+struct FxRequestSystemBuffer : public IFxMemory {
+ friend FxRequest;
+
+public:
+ FxRequestSystemBuffer(
+ VOID
+ )
+ {
+ m_Buffer = NULL;
+ }
+
+ _Must_inspect_result_
+ virtual
+ PVOID
+ GetBuffer(
+ VOID
+ );
+
+ virtual
+ size_t
+ GetBufferSize(
+ VOID
+ );
+
+ _Must_inspect_result_
+ virtual
+ PMDL
+ GetMdl(
+ VOID
+ );
+
+ virtual
+ WDFMEMORY
+ GetHandle(
+ VOID
+ );
+
+ virtual
+ USHORT
+ GetFlags(
+ VOID
+ );
+
+ virtual
+ PFX_DRIVER_GLOBALS
+ GetDriverGlobals(
+ VOID
+ );
+
+ virtual
+ ULONG
+ AddRef(
+ __in PVOID Tag,
+ __in LONG Line,
+ __in_opt PSTR File
+ );
+
+ virtual
+ ULONG
+ Release(
+ __in PVOID Tag,
+ __in LONG Line,
+ __in_opt PSTR File
+ );
+
+ virtual
+ VOID
+ Delete(
+ VOID
+ );
+
+ __inline
+ BOOLEAN
+ IsBufferSet(
+ VOID
+ )
+ {
+ return m_Buffer != NULL ? TRUE : FALSE;
+ }
+
+ __inline
+ VOID
+ ClearBufferMdl(
+ VOID
+ )
+ {
+ m_Buffer = NULL;
+ m_Mdl = NULL;
+ }
+
+protected:
+ __inline
+ VOID
+ SetBuffer(
+ PVOID Buffer
+ )
+ {
+ ASSERT(m_Buffer == NULL);
+ m_Buffer = Buffer;
+ }
+
+ __inline
+ VOID
+ SetMdl(
+ PMDL Mdl
+ )
+ {
+ ASSERT(m_Mdl == NULL);
+ m_Mdl = Mdl;
+ }
+
+ FxRequest*
+ GetRequest(
+ VOID
+ );
+
+protected:
+ //
+ // The current irp stack location indicates which type to use
+ //
+ // The buffer / MDL is cached away as a copy instead of using the PIRP values
+ // directly because we want to capture the current state of the irp when
+ // returning the WDFMEMORY. For instance, if used the PIRP value directly
+ // when implementing GetBuffer(), we are subject to the PIRP being formatted
+ // for the next stack location and changing the buffer pointer, or worse,
+ // changing the MDL value and have the resulting MDL not be mapped, and then
+ // a call to MmGetSystemAddressForMdlSafe can return NULL, and thus GetBuffer(),
+ // return NULL, which would violate the contract for GetBuffer().
+ //
+ // As an example, let's
+ // 1) the WDFREQUEST/PIRP comes in as a read on a direct io device object,
+ // so Irp->MdlAddress = <read MDL>
+ // 2) This WDFMEMORY will return <read MDL VA> in GetBuffer()
+ // 3) the WDFREQUEST is formatted for an IOCTL which is METHOD_OUT_DIRECT
+ // with a new output buffer. Irp->MdlAddres = <IOCTL MDL> now.
+ // 4) This same WDFMEMORY will now return <IOCTL MDL VA> in GetBuffer()
+ //
+ // Essentialy, formatting the WDFREQUEST causes unintended side affects for
+ // the WDFMEMORYs it returns. To eliminate those side affects, we capture
+ // the original buffer.
+ //
+ union {
+ PVOID m_Buffer;
+ PMDL m_Mdl;
+ };
+};
+
+struct FxRequestOutputBuffer : public IFxMemory {
+ friend FxRequest;
+
+public:
+ FxRequestOutputBuffer(
+ VOID
+ )
+ {
+ m_Buffer = NULL;
+ }
+
+ virtual
+ PVOID
+ GetBuffer(
+ VOID
+ );
+
+ virtual
+ size_t
+ GetBufferSize(
+ VOID
+ );
+
+ _Must_inspect_result_
+ virtual
+ PMDL
+ GetMdl(
+ VOID
+ );
+
+ virtual
+ WDFMEMORY
+ GetHandle(
+ VOID
+ );
+
+ virtual
+ USHORT
+ GetFlags(
+ VOID
+ );
+
+ virtual
+ PFX_DRIVER_GLOBALS
+ GetDriverGlobals(
+ VOID
+ );
+
+ virtual
+ ULONG
+ AddRef(
+ __in PVOID Tag,
+ __in LONG Line,
+ __in_opt PSTR File
+ );
+
+ virtual
+ ULONG
+ Release(
+ __in PVOID Tag,
+ __in LONG Line,
+ __in_opt PSTR File
+ );
+
+ virtual
+ VOID
+ Delete(
+ VOID
+ );
+
+ __inline
+ BOOLEAN
+ IsBufferSet(
+ VOID
+ )
+ {
+ return m_Buffer != NULL ? TRUE : FALSE;
+ }
+
+ __inline
+ VOID
+ ClearBufferMdl(
+ VOID
+ )
+ {
+ m_Buffer = NULL;
+ m_Mdl = NULL;
+ }
+
+protected:
+ __inline
+ VOID
+ SetBuffer(
+ __in PVOID Buffer
+ )
+ {
+ ASSERT(m_Buffer == NULL);
+ m_Buffer = Buffer;
+ }
+
+ __inline
+ VOID
+ SetMdl(
+ __in PMDL Mdl
+ )
+ {
+ ASSERT(m_Mdl == NULL);
+ m_Mdl = Mdl;
+ }
+
+ FxRequest*
+ GetRequest(
+ VOID
+ );
+
+protected:
+ //
+ // The current irp stack location indicates which type to use
+ //
+ // See comments in FxRequestSystemBuffer's union for why we capture the
+ // values vs using them directly from the PIRP.
+ //
+ union {
+ PVOID m_Buffer;
+ PMDL m_Mdl;
+ };
+};
+
+// begin_wpp enum
+enum FxListEntryNames {
+ FxListEntryNameCleanup = 0,
+
+ // this entry is used when the request is owned by the framework
+ FxListEntryQueueOwned,
+
+ // this entry is used when the request is presented to the driver
+ FxListEntryDriverOwned,
+
+ // this entry is used for forward progress
+ FxListEntryForwardProgress
+};
+
+enum FxRequestPowerStopState {
+ FxRequestPowerStopUnknown = 0, // Initial state
+
+ // Set when the driver calls WdfRequestStopAcknowledge
+ FxRequestPowerStopAcknowledged = 0x1,
+
+ // Set when the driver WdfRequestStopAcknowledge with requeue option
+ FxRequestPowerStopAcknowledgedWithRequeue = 0x2,
+};
+
+// end_wpp
+
+class FxRequest : public FxRequestBase {
+
+ friend FxIoTarget;
+ friend FxIoQueue;
+
+ friend FxRequestMemory;
+ friend FxRequestOutputBuffer;
+ friend FxRequestSystemBuffer;
+ friend VOID GetTriageInfo(VOID);
+
+protected:
+ //
+ // This field points to the queue that the request is currently
+ // associated with.
+ //
+ FxIoQueue* m_IoQueue;
+
+ FxRequestSystemBuffer m_SystemBuffer;
+
+ FxRequestOutputBuffer m_OutputBuffer;
+
+ //
+ // This is for use by the owner of the FxRequest which is FxIoQueue OR FxIoTarget
+ //
+ LIST_ENTRY m_OwnerListEntry;
+
+ LIST_ENTRY m_OwnerListEntry2;
+
+ //
+ // This is used by the queue to keep track of all forward progress requests
+ //
+ LIST_ENTRY m_ForwardProgressList;
+
+ //
+ // Used when the request is a reserved request to track the queue it was
+ // originally allocated for, so that it can be returned to the forward
+ // progress queue for reuse when the request is completed.
+ //
+ FxIoQueue *m_ForwardProgressQueue;
+
+ //
+ // Generic context exposed to other modules.
+ //
+ PVOID m_InternalContext;
+
+ //
+ // If TRUE, the client driver has been presented with this WDFREQUEST at
+ // least once.
+ //
+ BOOLEAN m_Presented;
+
+ //
+ // For tracking whether the driver has acknowledged power stop/purge notifications.
+ //
+ BYTE m_PowerStopState;
+
+ //
+ // If TRUE, this is a reserved request
+ //
+ BOOLEAN m_Reserved;
+
+ //
+ // If TRUE, this is used to determine how to free the request -
+ // either to the lookaside list or using ExFreePool
+ //
+ BOOLEAN m_ForwardRequestToParent;
+
+public:
+
+ //
+ // Normally, this is available by the object implementing
+ // IFxListEntry, but currently all callers of this know they
+ // are dealing with an FxRequest*.
+ //
+ // If FxRequests must go on a general typeless list, then
+ // the IFxListEntry interface should be added to FxRequest.
+ //
+ __inline
+ PLIST_ENTRY
+ GetListEntry(
+ __in FxListEntryNames Index
+ )
+ {
+ switch (Index) {
+ case FxListEntryQueueOwned: return &m_OwnerListEntry;
+ case FxListEntryDriverOwned: return &m_OwnerListEntry2;
+ case FxListEntryForwardProgress: return &m_ForwardProgressList;
+ default: ASSERT(FALSE); return NULL;
+ }
+ }
+
+ static
+ FxRequest*
+ _FromOwnerListEntry(
+ __in FxListEntryNames Index,
+ __in PLIST_ENTRY OwnerListEntry
+ )
+ {
+ switch (Index) {
+ case FxListEntryQueueOwned:
+ return CONTAINING_RECORD(OwnerListEntry, FxRequest, m_OwnerListEntry);
+ case FxListEntryDriverOwned:
+ return CONTAINING_RECORD(OwnerListEntry, FxRequest, m_OwnerListEntry2);
+ case FxListEntryForwardProgress:
+ return CONTAINING_RECORD(OwnerListEntry, FxRequest, m_ForwardProgressList);
+ default:
+ ASSERT(FALSE);
+ return NULL;
+ }
+ }
+
+ __inline
+ VOID
+ CopyCurrentIrpStackLocationToNext(
+ VOID
+ )
+ {
+ FxIrp* irp = GetSubmitFxIrp();
+ irp->CopyCurrentIrpStackLocationToNext();
+ }
+
+ _Must_inspect_result_
+ NTSTATUS
+ Reuse(
+ __in PWDF_REQUEST_REUSE_PARAMS ReuseParams
+ );
+
+ __inline
+ BOOLEAN
+ IsCancelled(
+ VOID
+ )
+ {
+ return m_Irp.IsCanceled() || m_Canceled;
+ }
+
+ __inline
+ VOID
+ CopyCompletionParams(
+ __in PWDF_REQUEST_COMPLETION_PARAMS Params
+ )
+ {
+ if (m_RequestContext != NULL) {
+ RtlCopyMemory(Params,
+ &m_RequestContext->m_CompletionParams,
+ sizeof(WDF_REQUEST_COMPLETION_PARAMS));
+ }
+ else {
+ DoTraceLevelMessage(
+ GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
+ "WdfRequestGetCompletionParams will not return valid information if the"
+ " request is not formatted using WdfIoTargetFormatxxx DDIs"
+ );
+
+ FxVerifierDbgBreakPoint(GetDriverGlobals());
+
+ WDF_REQUEST_COMPLETION_PARAMS_INIT(Params);
+ }
+ }
+
+ VOID
+ __inline
+ SetPresented(
+ VOID
+ )
+ {
+ //
+ // No need to synchronize setting this value with checking it because
+ // we check it in the complete path. We will not be about to present
+ // and completing the request in 2 simultaneous contexts.
+ //
+ m_Presented = TRUE;
+ }
+
+ VOID
+ AddIrpReference(
+ VOID
+ );
+
+ VOID
+ ReleaseIrpReference(
+ VOID
+ );
+
+ virtual
+ ULONG
+ AddRefOverride(
+ __in WDFOBJECT_OFFSET Offset,
+ __in PVOID Tag = NULL,
+ __in LONG Line = 0,
+ __in_opt PSTR File = NULL
+ );
+
+ virtual
+ ULONG
+ ReleaseOverride(
+ __in WDFOBJECT_OFFSET Offset,
+ __in PVOID Tag = NULL,
+ __in LONG Line = 0,
+ __in_opt PSTR File = NULL
+ );
+
+ __inline
+ CfxDevice*
+ GetDevice(
+ VOID
+ )
+ {
+ return m_Device;
+ }
+
+ __inline
+ BOOLEAN
+ IsReserved(
+ )
+ {
+ return m_Reserved;
+ }
+
+ __inline
+ VOID
+ SetReserved(
+ )
+ {
+ m_Reserved = TRUE;
+ }
+
+ __inline
+ VOID
+ SetForwardProgressQueue(
+ __in FxIoQueue *Queue
+ )
+ {
+ m_ForwardProgressQueue = Queue;
+ }
+
+protected:
+ FxRequest(
+ __in PFX_DRIVER_GLOBALS FxDriverGlobals,
+ __in MdIrp Irp,
+ __in FxRequestIrpOwnership Ownership,
+ __in FxRequestConstructorCaller Caller,
+ __in USHORT ObjectSize
+ );
+
+ #if DBG
+ FxRequest::~FxRequest(
+ VOID
+ );
+ #endif // DBG
+
+ __inline
+ VOID
+ SetCurrentQueue(
+ __in FxIoQueue *Queue
+ )
+ {
+ m_IoQueue = Queue;
+ }
+
+
+ WDFMEMORY
+ GetMemoryHandle(
+ __in USHORT Offset
+ )
+ {
+ ULONG_PTR handle;
+
+ //
+ // The offset into this object must be self relative.
+ //
+ ASSERT(*((PUSHORT) WDF_PTR_ADD_OFFSET(this, Offset)) == Offset);
+
+ handle = (ULONG_PTR) WDF_PTR_ADD_OFFSET(this, Offset);
+
+ //
+ // Make sure initial value has the flag bits cleared.
+ //
+ ASSERT((handle & FxHandleFlagMask) == 0);
+
+ //
+ // We always apply the mask.
+ //
+ handle = handle ^ FxHandleValueMask;
+
+ //
+ // Make sure final value (before we set the flag) has the flag bits
+ // cleared.
+ //
+ ASSERT((handle & FxHandleFlagMask) == 0);
+
+ //
+ // This handle is an offset
+ handle |= FxHandleFlagIsOffset;
+
+ return (WDFMEMORY) handle;
+ }
+
+ _Must_inspect_result_
+ virtual
+ NTSTATUS
+ QueryInterface(
+ __in FxQueryInterfaceParams* Params
+ );
+
+public:
+ // Factory functions to create FxRequest* objects
+ _Must_inspect_result_
+ static
+ NTSTATUS
+ _CreateForPackage(
+ __in CfxDevice* Device,
+ __in PWDF_OBJECT_ATTRIBUTES RequestAttributes,
+ __in MdIrp Irp,
+ __deref_out FxRequest** Request
+ );
+
+ _Must_inspect_result_
+ static
+ NTSTATUS
+ _Create(
+ __in PFX_DRIVER_GLOBALS FxDriverGlobals,
+ __in_opt PWDF_OBJECT_ATTRIBUTES RequestAttributes,
+ __in_opt MdIrp Irp,
+ __in_opt FxIoTarget* Target,
+ __in FxRequestIrpOwnership Ownership,
+ __in FxRequestConstructorCaller Caller,
+ __deref_out FxRequest** Request
+ );
+
+ _Must_inspect_result_
+ FxIoQueue*
+ GetCurrentQueue(
+ VOID
+ )
+ {
+ if(m_Completed) {
+ return NULL;
+ }
+
+ return m_IoQueue;
+ }
+
+ FxRequestCompletionState
+ SetCompletionState(
+ __in FxRequestCompletionState NewState
+ );
+
+ VOID
+ __inline
+ SetStatus(
+ __in NTSTATUS Status
+ )
+ {
+ m_Irp.SetStatus(Status);
+ }
+
+ NTSTATUS
+ SetInformation(
+ __in ULONG_PTR Information
+ );
+
+ ULONG_PTR
+ GetInformation(
+ VOID
+ );
+
+ KPROCESSOR_MODE
+ GetRequestorMode(
+ VOID
+ );
+
+ __inline
+ NTSTATUS
+ Complete(
+ __in NTSTATUS Status
+ )
+ {
+ CfxDevice* const fxDevice = GetDevice();
+
+ //
+ // Complete the current request object. Can be called directly
+ // by the FxIoQueue to complete a request.
+ //
+ // When an FxRequest is completed, it is marked as completed,
+ // removed from any CSQ it may be a member of, and any registered
+ // callback functions are called. Then the NT IRP is completed,
+ // and the reference count on the object due to the callback routine
+ // is released if a callback routine was specified.
+ //
+ // Completing a request object can cause its reference
+ // count to go to zero, thus deleting it. So the caller
+ // must either reference it explicitly, or not touch it
+ // any more after calling complete.
+ //
+
+ DoTraceLevelMessage(
+ GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGREQUEST,
+ "Completing WDFREQUEST 0x%p for IRP 0x%p with "
+ "Information 0x%I64x, %!STATUS!",
+ GetHandle(), m_Irp.GetIrp(), m_Irp.GetInformation(), Status);
+
+ if (fxDevice != NULL) {
+ SetPriorityBoost(fxDevice->GetDefaultPriorityBoost());
+ }
+ else {
+ SetPriorityBoost(0);
+ }
+
+ return CompleteInternal(Status);
+ }
+
+ __inline
+ NTSTATUS
+ CompleteWithInformation(
+ __in NTSTATUS Status,
+ __in ULONG_PTR Information
+ )
+ {
+ //
+ // Complete the request object. If the status is success, get the
+ // priority boost for the owning device type, and complete the request.
+ //
+ m_Irp.SetInformation(Information);
+ return Complete(Status);
+ }
+
+ __inline
+ NTSTATUS
+ CompleteWithPriority(
+ __in NTSTATUS Status,
+ __in CCHAR PriorityBoost
+ )
+ {
+ //
+ // Complete the current request object. Can be called directly
+ // by the FxIoQueue to complete a request.
+ //
+ // When an FxRequest is completed, it is marked as completed,
+ // removed from any CSQ it may be a member of, and any registered
+ // callback functions are called. Then the NT IRP is completed,
+ // and the reference count on the object due to the callback routine
+ // is released if a callback routine was specified.
+ //
+ // Completing a request object can cause its reference
+ // count to go to zero, thus deleting it. So the caller
+ // must either reference it explicitly, or not touch it
+ // any more after calling complete.
+ //
+
+ DoTraceLevelMessage(
+ GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGREQUEST,
+ "Completing WDFREQUEST 0x%p for IRP 0x%p with "
+ "Information 0x%I64x, %!STATUS!",
+ GetHandle(), m_Irp.GetIrp(), m_Irp.GetInformation(), Status);
+
+ SetPriorityBoost(PriorityBoost);
+ return CompleteInternal(Status);
+ }
+
+ // Do not specify argument names
+ FX_DECLARE_VF_FUNCTION(
+ VOID,
+ VerifyPreProcessSendAndForget
+ );
+
+ VOID
+ PreProcessSendAndForget(
+ VOID
+ );
+
+ VOID
+ PostProcessSendAndForget(
+ VOID
+ );
+
+ NTSTATUS
+ GetStatus(
+ VOID
+ );
+
+ _Must_inspect_result_
+ NTSTATUS
+ GetParameters(
+ __out PWDF_REQUEST_PARAMETERS Parameters
+ );
+
+ _Must_inspect_result_
+ NTSTATUS
+ GetMemoryObject(
+ __deref_out IFxMemory** Memory,
+ __out PVOID* Buffer,
+ __out size_t* Length
+ );
+
+ _Must_inspect_result_
+ NTSTATUS
+ GetMdl(
+ __out PMDL *pMdl
+ );
+
+ _Must_inspect_result_
+ NTSTATUS
+ GetDeviceControlOutputMemoryObject(
+ __deref_out IFxMemory** MemoryObject,
+ __out PVOID* Buffer,
+ __out size_t* Length
+ );
+
+ _Must_inspect_result_
+ NTSTATUS
+ GetDeviceControlOutputMdl(
+ __out PMDL *pMdl
+ );
+
+ // Do not specify argument names
+ FX_DECLARE_VF_FUNCTION(
+ NTSTATUS,
+ VerifyProbeAndLock
+ );
+
+ _Must_inspect_result_
+ NTSTATUS
+ ProbeAndLockForRead(
+ __in PVOID Buffer,
+ __in ULONG Length,
+ __deref_out FxRequestMemory** pMemoryObject
+ );
+
+ _Must_inspect_result_
+ NTSTATUS
+ ProbeAndLockForWrite(
+ __in PVOID Buffer,
+ __in ULONG Length,
+ __deref_out FxRequestMemory** pMemoryObject
+ );
+
+#if (FX_CORE_MODE == FX_CORE_USER_MODE)
+ _Must_inspect_result_
+ NTSTATUS
+ Impersonate(
+ _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
+ _In_ PFN_WDF_REQUEST_IMPERSONATE EvtRequestImpersonate,
+ _In_opt_ PVOID Context
+ );
+#endif
+
+ VOID
+ SetImpersonationFlags(
+ _In_ ULONG Flags
+ )
+ {
+#if (FX_CORE_MODE == FX_CORE_USER_MODE)
+ GetSubmitFxIrp()->GetIoIrp()->SetFlagsForNextStackLocation(
+ FxIrpStackFlagsFromSendFlags(Flags));
+#else
+ UNREFERENCED_PARAMETER(Flags);
+#endif
+ }
+
+ FxIrp*
+ GetFxIrp(
+ VOID
+ )
+ {
+ return &m_Irp;
+ }
+
+ __inline
+ FxIoQueue*
+ GetIoQueue(
+ VOID
+ )
+ {
+ return m_IoQueue;
+ }
+
+ _Must_inspect_result_
+ NTSTATUS
+ GetIrp(
+ __deref_out MdIrp* ppIrp
+ )
+ {
+ if (GetDriverGlobals()->FxVerifierIO) {
+ NTSTATUS status;
+ KIRQL irql;
+
+ Lock(&irql);
+
+ status = VerifyRequestIsNotCompleted(GetDriverGlobals());
+ if (!NT_SUCCESS(status)) {
+ *ppIrp = NULL;
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+ else {
+ *ppIrp = m_Irp.GetIrp();
+ }
+
+ Unlock(irql);
+
+ return status;
+ }
+ else {
+ *ppIrp = m_Irp.GetIrp();
+ return STATUS_SUCCESS;
+ }
+ }
+
+ //
+ // Return the FxFileObject if associated with this request
+ //
+ _Must_inspect_result_
+ NTSTATUS
+ GetFileObject(
+ __deref_out_opt FxFileObject** pFileObject
+ );
+
+ //
+ // Get the IoStack location of the request.
+ //
+ // Since this returns the pointer to the underlying IRP
+ // IO_STACK_LOCATION, it can not be called in a situation
+ // which the request is completed out from underneath us.
+ //
+ // Note: Must implemention a version for the drivers use.
+ // Must interact with completion events from the
+ // driver due to cancel as well.
+ //
+ //
+ PIO_STACK_LOCATION
+ GetCurrentIrpStackLocation(
+ VOID
+ )
+ {
+ if (GetDriverGlobals()->FxVerifierIO) {
+ PIO_STACK_LOCATION ios;
+ KIRQL irql;
+ NTSTATUS status;
+
+ Lock(&irql);
+ status = VerifyRequestIsNotCompleted(GetDriverGlobals());
+ if (!NT_SUCCESS(status)) {
+ ios = NULL;
+ }
+ else {
+ ios = m_Irp.GetCurrentIrpStackLocation();
+ }
+ Unlock(irql);
+
+ return ios;
+ }
+ else {
+ return m_Irp.GetCurrentIrpStackLocation();
+ }
+ }
+
+ //
+ // The following functions are to support use of
+ // the Cancel Safe FxIrpQueue.
+ //
+
+ // Do not specify argument names
+ FX_DECLARE_VF_FUNCTION_P1(
+ NTSTATUS,
+ VerifyInsertIrpQueue,
+ _In_ FxIrpQueue*
+ );
+
+ //
+ // Insert the request in the supplied FxIrpQueue
+ // and associated it with it.
+ //
+ _Must_inspect_result_
+ NTSTATUS
+ InsertTailIrpQueue(
+ __in FxIrpQueue* IrpQueue,
+ __out_opt ULONG* pRequestCount
+ );
+
+ _Must_inspect_result_
+ NTSTATUS
+ InsertHeadIrpQueue(
+ __in FxIrpQueue* IrpQueue,
+ __out_opt ULONG* pRequestCount
+ );
+
+ //
+ // Remove it from the FxIrpQueue it is associated with.
+ //
+ // Returns STATUS_CANCELLED if the cancel routine has
+ // fired and removed it from the queue first.
+ //
+ //
+ _Must_inspect_result_
+ NTSTATUS
+ RemoveFromIrpQueue(
+ __in FxIrpQueue* IrpQueue
+ );
+
+ //
+ // Mark that this request is no longer on the IrpQueue
+ //
+ __inline
+ VOID
+ MarkRemovedFromIrpQueue(
+ VOID
+ )
+ {
+ m_IrpQueue = NULL;
+ return;
+ }
+
+ //
+ // Return the FxRequest's CsqContext address
+ //
+ __inline
+ PMdIoCsqIrpContext
+ GetCsqContext(
+ VOID
+ )
+ {
+ return &m_CsqContext;
+ }
+
+
+ //
+ // Function to return an FxRequest from an FxIrpQueue
+ //
+ _Must_inspect_result_
+ static
+ FxRequest*
+ GetNextRequest(
+ __in FxIrpQueue* IrpQueue
+ );
+
+ _Must_inspect_result_
+ static
+ NTSTATUS
+ GetNextRequest(
+ __in FxIrpQueue* IrpQueue,
+ __in_opt MdFileObject FileObject,
+ __in_opt FxRequest* TagRequest,
+ __deref_out FxRequest** ppOutRequest
+ );
+
+ //
+ // Allow peeking at requests in the IrpQueue
+ //
+ _Must_inspect_result_
+ static
+ NTSTATUS
+ PeekRequest(
+ __in FxIrpQueue* IrpQueue,
+ __in_opt FxRequest* TagRequest,
+ __in_opt MdFileObject FileObject,
+ __out_opt PWDF_REQUEST_PARAMETERS Parameters,
+ __deref_out FxRequest** ppOutRequest
+ );
+
+ //
+ // Internal function to retrieve the FxRequest
+ // structure from a pointer to its CsqContext
+ // member.
+ //
+ __inline
+ static
+ FxRequest*
+ RetrieveFromCsqContext(
+ __in PMdIoCsqIrpContext pCsqContext
+ )
+ {
+ return CONTAINING_RECORD(pCsqContext, FxRequest, m_CsqContext);
+ }
+
+
+ __inline
+ BOOLEAN
+ IsInIrpQueue(
+ __in FxIrpQueue* pIrpQueue
+ )
+ {
+ return pIrpQueue->IsIrpInQueue(GetCsqContext());
+ }
+
+
+ // Do not specify argument names
+ FX_DECLARE_VF_FUNCTION_P1(
+ NTSTATUS,
+ VerifyStopAcknowledge,
+ _In_ BOOLEAN
+ );
+
+ VOID
+ StopAcknowledge(
+ __in BOOLEAN Requeue
+ );
+
+ __inline
+ BOOLEAN
+ IsPowerStopAcknowledged(
+ VOID
+ )
+ {
+ return ((m_PowerStopState == FxRequestPowerStopAcknowledged)
+ ||
+ (m_PowerStopState == FxRequestPowerStopAcknowledgedWithRequeue))? TRUE : FALSE;
+ }
+
+ __inline
+ BOOLEAN
+ IsPowerStopAcknowledgedWithRequeue(
+ VOID
+ )
+ {
+ return (m_PowerStopState == FxRequestPowerStopAcknowledgedWithRequeue) ? TRUE : FALSE;
+ }
+
+ VOID
+ ClearPowerStopState(
+ VOID
+ )
+ {
+ m_PowerStopState = FxRequestPowerStopUnknown;
+ }
+
+ // Do not specify argument names
+ FX_DECLARE_VF_FUNCTION(
+ VOID,
+ VerifierBreakpoint_RequestEarlyDisposeDeferred
+ );
+
+ // Do not specify argument names
+ FX_DECLARE_VF_FUNCTION(
+ NTSTATUS,
+ VerifyRequestIsDriverOwned
+ );
+
+ // Do not specify argument names
+ FX_DECLARE_VF_FUNCTION(
+ NTSTATUS,
+ VerifyRequestIsCancelable
+ );
+
+ // Do not specify argument names
+ FX_DECLARE_VF_FUNCTION(
+ NTSTATUS,
+ VerifyRequestIsNotCancelable
+ );
+
+ // Do not specify argument names
+ FX_DECLARE_VF_FUNCTION(
+ NTSTATUS,
+ VerifyRequestIsInCallerContext
+ );
+
+ // Do not specify argument names
+ FX_DECLARE_VF_FUNCTION(
+ NTSTATUS,
+ VerifyRequestIsInEvtIoStopContext
+ );
+
+ // Do not specify argument names
+ FX_DECLARE_VF_FUNCTION(
+ NTSTATUS,
+ VerifyRequestIsNotCompleted
+ );
+
+ // Do not specify argument names
+ FX_DECLARE_VF_FUNCTION(
+ NTSTATUS,
+ VerifyRequestIsTagRequest
+ );
+
+ // Do not specify argument names
+ FX_DECLARE_VF_FUNCTION(
+ NTSTATUS,
+ VerifyRequestIsAllocatedFromIo
+ );
+
+ // Do not specify argument names
+ FX_DECLARE_VF_FUNCTION(
+ NTSTATUS,
+ VerifyRequestIsCurrentStackValid
+ );
+
+ // Do not specify argument names
+ FX_DECLARE_VF_FUNCTION(
+ NTSTATUS,
+ VerifyRequestCanBeCompleted
+ );
+
+ VOID
+ FreeRequest(
+ VOID
+ );
+
+ __inline
+ VOID
+ ClearFieldsForReuse(
+ VOID
+ )
+ {
+ m_SystemBuffer.ClearBufferMdl();
+ m_OutputBuffer.ClearBufferMdl();
+
+ ASSERT(m_ForwardRequestToParent == FALSE);
+
+ __super::ClearFieldsForReuse();
+ }
+
+ virtual
+ ULONG
+ Release(
+ __in PVOID Tag,
+ __in LONG Line,
+ __in_opt PSTR File
+ );
+
+ __inline
+ BOOLEAN
+ IsRequestForwardedToParent(
+ VOID
+ )
+ {
+ return m_ForwardRequestToParent;
+ }
+
+private:
+ FX_DECLARE_VF_FUNCTION_P1(
+ VOID,
+ VerifyCompleteInternal,
+ _In_ NTSTATUS
+ );
+
+ NTSTATUS
+ CompleteInternalReserved(
+ __in NTSTATUS Status,
+ __in CCHAR PriorityBoost
+ );
+
+ NTSTATUS
+ CompleteInternal(
+ __in NTSTATUS Status
+ );
+
+ VOID
+ PostProcessCompletion(
+ __in FxRequestCompletionState State,
+ __in FxIoQueue* Queue
+ );
+
+ VOID
+ PostProcessCompletionForReserved(
+ __in FxRequestCompletionState State,
+ __in FxIoQueue* Queue
+ );
+
+ VOID
+ PreProcessCompletionForDriverRequest(
+ __in FxRequestCompletionState State,
+ __in FxIoQueue* Queue
+ );
+
+ VOID
+ PostProcessCompletionForDriverRequest(
+ __in FxRequestCompletionState State,
+ __in FxIoQueue* Queue
+ );
+
+ static
+ VOID
+ CheckAssumptions(
+ VOID
+ );
+
+ VOID
+ AssignMemoryBuffers(
+ __in WDF_DEVICE_IO_TYPE IoType
+ )
+{
+
+ switch (m_Irp.GetMajorFunction()) {
+ case IRP_MJ_DEVICE_CONTROL:
+ case IRP_MJ_INTERNAL_DEVICE_CONTROL:
+
+
+
+
+
+
+
+
+
+ switch (m_Irp.GetParameterIoctlCodeBufferMethod()) {
+ case METHOD_BUFFERED:
+ //
+ // Set the buffer in the memory interface. For kernel mode,
+ // GetOutputBuffer is same as GetSystemBuffer, but for user-mode,
+ // host provides separate buffers, so that input buffer can only be
+ // read, and output buffer can only be written to.
+ //
+ m_SystemBuffer.SetBuffer(m_Irp.GetSystemBuffer());
+ m_OutputBuffer.SetBuffer(m_Irp.GetOutputBuffer());
+ break;
+
+ case METHOD_IN_DIRECT:
+ //
+ // InputBuffer is in SystemBuffer
+ // OutputBuffer is in MdlAddress with read access
+ //
+ KMDF_ONLY_CODE_PATH_ASSERT();
+ m_SystemBuffer.SetBuffer(m_Irp.GetSystemBuffer());
+ break;
+
+ case METHOD_OUT_DIRECT:
+ //
+ // InputBuffer is in SystemBuffer
+ // OutputBuffer is in MdlAddress with write access
+ //
+ KMDF_ONLY_CODE_PATH_ASSERT();
+ m_SystemBuffer.SetBuffer(m_Irp.GetSystemBuffer());
+ break;
+
+ case METHOD_NEITHER:
+ //
+ // Internal device controls are kernel mode to kernel mode, and deal
+ // with direct unmapped pointers.
+ //
+ // In addition, a normal device control with
+ // RequestorMode == KernelMode is also treated as kernel mode
+ // to kernel mode since the I/O Manager will not generate requests
+ // with this setting from a user mode request.
+ //
+ KMDF_ONLY_CODE_PATH_ASSERT();
+ if (m_Irp.GetMajorFunction() == IRP_MJ_INTERNAL_DEVICE_CONTROL ||
+ (m_Irp.GetRequestorMode() == KernelMode)) {
+ m_SystemBuffer.SetBuffer(
+ m_Irp.GetParameterIoctlType3InputBuffer()
+ );
+ m_OutputBuffer.SetBuffer(m_Irp.GetUserBuffer());
+ }
+ else {
+ return;
+ }
+ break;
+ }
+ break;
+
+ case IRP_MJ_READ:
+ case IRP_MJ_WRITE:
+ switch (IoType) {
+ case WdfDeviceIoBuffered:
+ m_SystemBuffer.SetBuffer(m_Irp.GetSystemBuffer());
+ break;
+
+ case WdfDeviceIoNeither:
+ KMDF_ONLY_CODE_PATH_ASSERT();
+ if (m_Irp.GetRequestorMode() == KernelMode) {
+ m_SystemBuffer.SetBuffer(m_Irp.GetUserBuffer());
+ }
+ else {
+ return;
+ }
+ break;
+
+ default:
+ return;
+ }
+ break;
+
+ default:
+ return;
+ }
+
+ if (m_SystemBuffer.IsBufferSet()) {
+ m_RequestBaseStaticFlags |= FxRequestBaseStaticSystemBufferValid;
+ }
+ if (m_OutputBuffer.IsBufferSet()) {
+ m_RequestBaseStaticFlags |= FxRequestBaseStaticOutputBufferValid;
+ }
+}
+
+
+public:
+ __inline
+ VOID
+ SetInternalContext(
+ PVOID Context
+ )
+ {
+ ASSERT(NULL == m_InternalContext);
+ m_InternalContext = Context;
+ }
+
+ __inline
+ PVOID
+ GetInternalContext(
+ VOID
+ )
+ {
+ PVOID context;
+
+ context = m_InternalContext;
+ m_InternalContext = NULL;
+
+ return context;
+ }
+};
+
+class FxRequestFromLookaside : public FxRequest {
+
+public:
+ FxRequestFromLookaside(
+ __in CfxDevice* Device,
+ __in MdIrp Irp
+ );
+
+ PVOID
+ operator new(
+ __in size_t Size,
+ __in CfxDevice* Device,
+ __in_opt PWDF_OBJECT_ATTRIBUTES Attributes
+ );
+
+protected:
+ //
+ // FxObject override
+ //
+ VOID
+ SelfDestruct(
+ VOID
+ );
+};
+
+#endif // _FXREQUEST_H_