/*++

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(
        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);

        FxRequestBase::ClearFieldsForReuse(); // __super call
    }

    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_