Something went wrong. Try again.
Reactos
Something went wrong. Try again.
C++
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826/*++
Copyright (c) Microsoft Corporation
Module Name:
FxIoTargetRemote.cpp
Abstract:
Author:
Environment:
Both kernel and user mode
Revision History:
--*/
#include "../fxtargetsshared.hpp"
extern "C" {// #include "FxIoTargetRemote.tmh"}
#include <initguid.h>#include "wdmguid.h"
FxIoTargetRemote::FxIoTargetRemote( __in PFX_DRIVER_GLOBALS FxDriverGlobals ) : FxIoTarget(FxDriverGlobals, sizeof(FxIoTargetRemote)), m_EvtQueryRemove(FxDriverGlobals), m_EvtRemoveCanceled(FxDriverGlobals), m_EvtRemoveComplete(FxDriverGlobals){
// // No automatic state changes based on the pnp state changes of our own // device stack. The one exception is remove where we need to shut // everything down. // m_InStack = FALSE;
m_ClearedPointers = NULL; m_OpenState = FxIoTargetRemoteOpenStateClosed;
m_TargetHandle = NULL;
m_EvtQueryRemove.m_Method = NULL; m_EvtRemoveCanceled.m_Method = NULL; m_EvtRemoveComplete.m_Method = NULL;
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) m_TargetNotifyHandle = NULL;#elif (FX_CORE_MODE == FX_CORE_USER_MODE) m_TargetNotifyHandle = WUDF_TARGET_CONTEXT_INVALID;
m_pIoDispatcher = NULL; m_pRemoteDispatcher = NULL; m_NotificationCallback = NULL;#endif}
FxIoTargetRemote::~FxIoTargetRemote(){}
_Must_inspect_result_NTSTATUSFxIoTargetRemote::_Create( __in PFX_DRIVER_GLOBALS FxDriverGlobals, __in PWDF_OBJECT_ATTRIBUTES Attributes, __in CfxDeviceBase* Device, __out FxIoTargetRemote** Target ){ FxIoTargetRemote* pTarget; FxObject* pParent; WDFOBJECT hTarget; NTSTATUS status;
*Target = NULL;
if (Attributes == NULL || Attributes->ParentObject == NULL) { pParent = Device; } else { CfxDeviceBase* pSearchDevice;
FxObjectHandleGetPtr(FxDriverGlobals, Attributes->ParentObject, FX_TYPE_OBJECT, (PVOID*) &pParent);
pSearchDevice = FxDeviceBase::_SearchForDevice(pParent, NULL);
if (pSearchDevice == NULL) { status = STATUS_INVALID_DEVICE_REQUEST;
DoTraceLevelMessage( FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, "Attributes->ParentObject 0x%p must have WDFDEVICE as an " "eventual ancestor, %!STATUS!", Attributes->ParentObject, status);
return status; } else if (pSearchDevice != Device) { status = STATUS_INVALID_DEVICE_REQUEST;
DoTraceLevelMessage( FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, "Attributes->ParentObject 0x%p ancestor is WDFDEVICE %p, but " "not the same WDFDEVICE 0x%p passed to WdfIoTargetCreate, " "%!STATUS!", Attributes->ParentObject, pSearchDevice->GetHandle(), Device->GetHandle(), status);
return status; } }
pTarget = new (FxDriverGlobals, Attributes) FxIoTargetRemote(FxDriverGlobals);
if (pTarget == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; DoTraceLevelMessage( FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, "Could not allocate memory for target, %!STATUS!", status); return status; }
// // initialize the new target // status = pTarget->InitRemote(Device); if (!NT_SUCCESS(status)) { return status; }
// // Commit and apply the attributes // status = pTarget->Commit(Attributes, &hTarget, pParent);
if (NT_SUCCESS(status)) { *Target = pTarget; } else { // // This will properly clean up the target's state and free it // DoTraceLevelMessage( FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, "Commit failed for target, %!STATUS!", status); pTarget->DeleteFromFailedCreate(); }
return status;}
NTSTATUSFxIoTargetRemote::InitRemote( __in FxDeviceBase* Device ){ NTSTATUS status;
// // do the base class mode-specific initialization // status = FxIoTarget::InitModeSpecific(Device); // __super call if (!NT_SUCCESS(status)) { return status; }
// // Do mode-specific initilialization // status = InitRemoteModeSpecific(Device); if (!NT_SUCCESS(status)) { return status; }
m_Driver = Device->GetDriver();
SetDeviceBase(Device); m_InStackDevice = Device->GetDeviceObject();
(void) Device->AddIoTarget(this);
return STATUS_SUCCESS;}
_Must_inspect_result_NTSTATUSFxIoTargetRemote::Open( __in PWDF_IO_TARGET_OPEN_PARAMS OpenParams ){ FxIoTargetRemoveOpenParams params, *pParams; UNICODE_STRING name; LIST_ENTRY pended; WDF_IO_TARGET_OPEN_TYPE type; NTSTATUS status; BOOLEAN close, reopen; PVOID pEa; ULONG eaLength; KIRQL irql;
RtlZeroMemory(&name, sizeof(name)); close = FALSE; reopen = OpenParams->Type == WdfIoTargetOpenReopen ? TRUE : FALSE;
pEa = NULL; eaLength = 0;
// // We only support reopening using stored settings when we open by name // if (reopen && m_OpenParams.OpenType != WdfIoTargetOpenByName) { status = STATUS_INVALID_DEVICE_REQUEST; DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, "Reopen only supported if the open type is WdfIoTargetOpenByName WDFIOTARGET %p %!STATUS!", GetObjectHandle(), status); return status; }
// // Must preallocate all settings now // if (reopen) { // // convert the type into the type used for the previous open // type = m_OpenParams.OpenType; pParams = &m_OpenParams; } else { type = OpenParams->Type; pParams = ¶ms;
if (OpenParams->Type == WdfIoTargetOpenByName) {
status = FxDuplicateUnicodeString(GetDriverGlobals(), &OpenParams->TargetDeviceName, &name); if (!NT_SUCCESS(status)) { DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, "Could not allocate memory for target name for WDFIOTARGET %p", GetObjectHandle()); goto Done; } if (OpenParams->EaBuffer != NULL && OpenParams->EaBufferLength > 0) {
pEa = FxPoolAllocate(GetDriverGlobals(), PagedPool, OpenParams->EaBufferLength);
if (pEa == NULL) { DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, "Could not allocate memory for target name " "for WDFIOTARGET %p", GetObjectHandle()); status = STATUS_INSUFFICIENT_RESOURCES; goto Done; } else { eaLength = OpenParams->EaBufferLength; RtlCopyMemory(pEa, OpenParams->EaBuffer, eaLength); } } } }
Lock(&irql);
if (m_State == WdfIoTargetDeleted) { DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, "Opening WDFIOTARGET %p which is removed, state %d", GetObjectHandle(), m_State); status = STATUS_INVALID_DEVICE_STATE; } else if (m_OpenState != FxIoTargetRemoteOpenStateClosed) { // // We are either open or are opening // DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, "Opening an already open WDFIOTARGET %p, open state %d", GetObjectHandle(), m_OpenState); status = STATUS_INVALID_DEVICE_STATE; } else { DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, "Opening WDFIOTARGET %p", GetObjectHandle());
// // Clear the event so that if something is waiting on the state // transition, they will block until we are done. // m_OpenedEvent.Clear();
m_OpenState = FxIoTargetRemoteOpenStateOpening; status = STATUS_SUCCESS; } Unlock(irql);
if (!NT_SUCCESS(status)) { goto Done; }
ASSERT(m_TargetFileObject == NULL); ASSERT(m_TargetDevice == NULL); ASSERT(m_TargetPdo == NULL); ASSERT(m_TargetHandle == NULL);
// // m_TargetNotifyHandle can be a valid value if the caller has previously // opened the target, received a query remove, then a cancel remove, and // is now reopening the target. // UnregisterForPnpNotification(m_TargetNotifyHandle); ResetTargetNotifyHandle();
// // Only clear the open parameters if we are not attempting a reopen. // if (reopen == FALSE) { m_OpenParams.Clear(); }
switch (type) { case WdfIoTargetOpenUseExistingDevice: KMDF_ONLY_CODE_PATH_ASSERT();
// // OpenParams must be non NULL b/c we can't reopen a target with a // previous device object. // ASSERT(OpenParams->Type == WdfIoTargetOpenUseExistingDevice);
m_TargetDevice = (MdDeviceObject) OpenParams->TargetDeviceObject; m_TargetFileObject = (MdFileObject) OpenParams->TargetFileObject; m_TargetHandle = NULL;
// // By taking a manual reference here, we simplify the code in // FxIoTargetRemote::Close where we can assume there is an outstanding // reference on the PFILE_OBJECT at all times as long as we have a non // NULL pointer. // if (m_TargetFileObject != NULL) { Mx::MxReferenceObject(m_TargetFileObject); }
status = STATUS_SUCCESS;
break;
case WdfIoTargetOpenLocalTargetByFile: UMDF_ONLY_CODE_PATH_ASSERT();
status = OpenLocalTargetByFile(OpenParams); break;
case WdfIoTargetOpenByName: // // Only capture the open parameters if we are not reopening. // if (reopen == FALSE) { pParams->Set(OpenParams, &name, pEa, eaLength); }
status = OpenTargetHandle(OpenParams, pParams); if (NT_SUCCESS(status)) { if (reopen == FALSE) { m_OpenParams.Set(OpenParams, &name, pEa, eaLength);
// // Setting pEa to NULL stops it from being freed later. // Zeroing out name stops it from being freed later. // pEa = NULL; RtlZeroMemory(&name, sizeof(name)); } } else { close = TRUE; } break; }
InitializeListHead(&pended);
// // Get Target file object for KMDF. Noop for UMDF. // if (NT_SUCCESS(status)) { status = GetTargetDeviceRelations(&close); }
if (NT_SUCCESS(status) && CanRegisterForPnpNotification()) { if (reopen == FALSE) { // // Set the values before the register so that if a notification // comes in before the register returns, we have a function to call. // m_EvtQueryRemove.m_Method = OpenParams->EvtIoTargetQueryRemove; m_EvtRemoveCanceled.m_Method = OpenParams->EvtIoTargetRemoveCanceled; m_EvtRemoveComplete.m_Method = OpenParams->EvtIoTargetRemoveComplete; }
status = RegisterForPnpNotification();
// // Even if we can't register, we still are successful in opening // up the device and we will proceed from there. // if (!NT_SUCCESS(status)) { DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, "WDFIOTARGET %p, could not register pnp notification, %!STATUS! not " "treated as an error", GetObjectHandle(), status);
m_EvtQueryRemove.m_Method = NULL; m_EvtRemoveCanceled.m_Method = NULL; m_EvtRemoveComplete.m_Method = NULL;
status = STATUS_SUCCESS; } }
// // UMDF only. Bind handle to remote dispatcher. //#if (FX_CORE_MODE == FX_CORE_USER_MODE) if (NT_SUCCESS(status) && type != WdfIoTargetOpenLocalTargetByFile) { status = BindToHandle(); if (!NT_SUCCESS(status)) { close = TRUE; } }#endif
Lock(&irql);
if (NT_SUCCESS(status)) {
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) m_TargetStackSize = m_TargetDevice->StackSize; m_TargetIoType = GetTargetIoType();#endif
m_OpenState = FxIoTargetRemoteOpenStateOpen;
// // Set our state to started. This will also resend any pended requests // due to a query remove. // status = GotoStartState(&pended, FALSE);
// // We could not successfully start, close back down // if (!NT_SUCCESS(status)) { DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, "WDFIOTARGET %p could not transition to started state, %!STATUS!", GetObjectHandle(), status);
close = TRUE; } } else { m_OpenState = FxIoTargetRemoteOpenStateClosed; }
// // No matter what, indicate to any waiters that our state change has // completed. // m_OpenedEvent.Set();
Unlock(irql);
Done: // // Resubmit any reads that were pended until now. // if (NT_SUCCESS(status)) { SubmitPendedRequests(&pended); } else if (close) { Close(FxIoTargetRemoteCloseReasonPlainClose); }
if (name.Buffer != NULL) { FxPoolFree(name.Buffer); }
if (pEa != NULL) { FxPoolFree(pEa); }
return status;}
VOIDFxIoTargetRemote::Close( __in FxIoTargetRemoteCloseReason Reason ){ FxIoTargetClearedPointers pointers; MdTargetNotifyHandle pNotifyHandle; SINGLE_LIST_ENTRY sent; LIST_ENTRY pended; WDF_IO_TARGET_STATE removeState; KIRQL irql; BOOLEAN wait; PFX_DRIVER_GLOBALS pFxDriverGlobals;
pFxDriverGlobals = GetDriverGlobals(); DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, "enter: WDFIOTARGET %p, reason %d", GetObjectHandle(), Reason);
RtlZeroMemory(&pointers, sizeof(pointers)); pNotifyHandle = NULL;
sent.Next = NULL; InitializeListHead(&pended);
wait = FALSE;
// // Pick a value that is not used anywhere in the function and make sure that // we have changed it, before we go to the Remove state //#pragma prefast(suppress: __WARNING_UNUSED_SCALAR_ASSIGNMENT, "PFD is warning that the following assignement is unused. Suppress it to prevent changing any logic.") removeState = WdfIoTargetStarted;
CheckState: Lock(&irql);
// // If we are in the process of opening the target, wait for that to finish. // if (m_OpenState == FxIoTargetRemoteOpenStateOpening) { Unlock(irql);
DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, "Closing WDFIOTARGET %p which is opening, waiting on event %p", GetObjectHandle(), m_OpenedEvent.GetEvent());
m_OpenedEvent.EnterCRAndWaitAndLeave();
// // Jump back to the top and recheck // goto CheckState; }
if (Reason == FxIoTargetRemoteCloseReasonDelete) { DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, "Closing WDFIOTARGET %p, reason: delete", GetObjectHandle());
removeState = WdfIoTargetDeleted; } else if (m_OpenState == FxIoTargetRemoteOpenStateOpen) { if (Reason == FxIoTargetRemoteCloseReasonQueryRemove) { DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, "Closing WDFIOTARGET %p, reason: query remove", GetObjectHandle()); // // Not really being removed, but that is what the API name is... // removeState = WdfIoTargetClosedForQueryRemove; } else {
DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, "Closing WDFIOTARGET %p, reason: close", GetObjectHandle());
if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,9)) { removeState = WdfIoTargetClosed; } else { removeState = WdfIoTargetClosedForQueryRemove; } }
// // Either way, we are no longer open for business // m_OpenState = FxIoTargetRemoteOpenStateClosed; } else { DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, "Closing WDFIOTARGET %p which is not open", GetObjectHandle());
// // We are not opened, so treat this as a cleanup // removeState = WdfIoTargetClosed; }
DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, "WDFIOTARGET %p: fileobj %p, devobj %p, handle %p, notify handle %I64d", GetObjectHandle(), m_TargetFileObject, m_TargetDevice, m_TargetHandle, (UINT64)m_TargetNotifyHandle);
if (Reason != FxIoTargetRemoteCloseReasonQueryRemove) { // // If we are closing for a query remove, we want to keep the handle // around so that we can be notified of the final close or if the close // was canceled. // pNotifyHandle = m_TargetNotifyHandle; ResetTargetNotifyHandle(); }
ASSERT(removeState != WdfIoTargetStarted); m_ClearedPointers = &pointers; GotoRemoveState(removeState, &pended, &sent, FALSE, &wait);
Unlock(irql);
UnregisterForPnpNotification(pNotifyHandle);
// // Complete any requests we might have pulled off of our lists // CompletePendedRequestList(&pended); _CancelSentRequests(&sent);
// // We were just removed, wait for any I/O to complete back if necessary. // if (wait) { DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, "WDFIOTARGET %p, waiting for stop to complete", GetObjectHandle());
WaitForSentIoToComplete(); }
switch (Reason) { case FxIoTargetRemoteCloseReasonQueryRemove: // // m_OpenParams is needed for reopen on canceled query remove // DO_NOTHING(); break;
case FxIoTargetRemoteCloseReasonDelete: m_OpenParams.Clear(); break;
default: // // If this object is not about to be deleted, we need to revert some // of the state that just changed. // m_SentIoEvent.Clear(); break; }
if (removeState == WdfIoTargetDeleted) { WaitForDisposeEvent(); }
// // Finally, close down our handle and pointers // if (pointers.TargetPdo != NULL) { DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, "WDFIOTARGET %p derefing PDO %p on close", GetObjectHandle(), pointers.TargetPdo);
Mx::MxDereferenceObject(pointers.TargetPdo); }
if (pointers.TargetFileObject != NULL) { DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, "WDFIOTARGET %p derefing FileObj %p on close", GetObjectHandle(), pointers.TargetFileObject); Mx::MxDereferenceObject(pointers.TargetFileObject);
#if (FX_CORE_MODE == FX_CORE_USER_MODE) CloseWdfFileObject(pointers.TargetFileObject);#endif }
#if (FX_CORE_MODE == FX_CORE_USER_MODE) UnbindHandle(&pointers);#endif
if (pointers.TargetHandle != NULL) { DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, "WDFIOTARGET %p closing handle %p on close", GetObjectHandle(), pointers.TargetHandle); Mx::MxClose(pointers.TargetHandle); }}
VOIDFxIoTargetRemote::ClearTargetPointers( VOID ){ DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, "WDFIOTARGET %p cleared pointers %p state %!WDF_IO_TARGET_STATE!," " open state %d, pdo %p, fileobj %p, handle %p", GetObjectHandle(), m_ClearedPointers, m_State, m_OpenState, m_TargetPdo, m_TargetFileObject, m_TargetHandle);
// // Check to see if the caller who is changing state wants these pointer // values before they being cleared out. // if (m_ClearedPointers != NULL) { m_ClearedPointers->TargetPdo = m_TargetPdo; m_ClearedPointers->TargetFileObject = m_TargetFileObject; m_ClearedPointers->TargetHandle = m_TargetHandle; m_ClearedPointers = NULL; }
// // m_TargetHandle is only an FxIoTargetRemote field, clear it now // m_TargetHandle = NULL;
// // m_TargetPdo and m_TargetFileObject will be cleared in the following call. // // m_TargetNotifyHandle is not cleared in the following call and is left // valid because we want to receive the notification about query remove being // canceled or completing. When we receive either of those notifications, // m_TargetNotifyHandle will be freed then. // FxIoTarget::ClearTargetPointers(); // __super call}
VOIDFxIoTargetRemote::Remove( VOID ){ // // Close is the same as remove in this object // Close(FxIoTargetRemoteCloseReasonDelete);
// // Do mode-specific work // RemoveModeSpecific();
return ;}
VOIDFxIoTargetRemoveOpenParams::Clear( VOID ){ if (EaBuffer != NULL) { FxPoolFree(EaBuffer); }
if (TargetDeviceName.Buffer != NULL) { FxPoolFree(TargetDeviceName.Buffer); }
RtlZeroMemory(this, sizeof(FxIoTargetRemoveOpenParams));}
VOIDFxIoTargetRemoveOpenParams::Set( __in PWDF_IO_TARGET_OPEN_PARAMS OpenParams, __in PUNICODE_STRING Name, __in PVOID Ea, __in ULONG EaLength ){ OpenType = WdfIoTargetOpenByName;
EaBuffer = Ea; EaBufferLength = EaLength;
RtlCopyMemory(&TargetDeviceName, Name, sizeof(UNICODE_STRING));
DesiredAccess = OpenParams->DesiredAccess; FileAttributes = OpenParams->FileAttributes; ShareAccess = OpenParams->ShareAccess; CreateDisposition = OpenParams->CreateDisposition; CreateOptions = OpenParams->CreateOptions;
if (OpenParams->AllocationSize != NULL) { AllocationSize.QuadPart = *(OpenParams->AllocationSize); AllocationSizePointer = &AllocationSize; } else { AllocationSizePointer = NULL; }}