// // This inserts a request into the I/O processing pipeline // _Must_inspect_result_ NTSTATUS FxPkgIo::EnqueueRequest( __in CfxDevice* Device, __inout FxRequest* pRequest ) { NTSTATUS status; FxIoQueue* pQueue; FxIrp* Irp = NULL; FxRequestCompletionState oldState; PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); SHORT origVerifierFlags = 0; // // Request is owned by the driver, and has a reference count of == 1 // (or > 1 if EvtIoInCallerContext callback took an additional reference), // with a FxPkgIoInProcessRequestComplete callback registered. // ASSERT(pRequest->GetRefCnt() >= 1); Irp = pRequest->GetFxIrp(); DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, "WDFREQUEST 0x%p", pRequest->GetObjectHandle()); status = VerifyEnqueueRequestUpdateFlags(FxDriverGlobals, pRequest, &origVerifierFlags); if (!NT_SUCCESS(status)) { return status; } // // Get the associated queue // pQueue = (FxIoQueue*) pRequest->GetInternalContext(); if (NULL == pQueue) { pQueue = m_DispatchTable[Irp->GetMajorFunction()]; if (pQueue == NULL) { // // No queue configured yet, fail request unless the driver is a filter. // if (m_Filter) { goto Forward; } status = STATUS_INVALID_DEVICE_REQUEST; DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, "No queue configured for WDFDEVICE 0x%p, " "failing WDFREQUEST 0x%p %!STATUS!", Device->GetHandle(), pRequest->GetObjectHandle(), status); FxVerifierDbgBreakPoint(FxDriverGlobals); // // Return it back to the driver to decide the outcome // goto Error; } } // // If the queue is a default-queue and driver is a filter then before // calling the queue we should make sure the queue can dispatch // requests to the driver. If the queue cannot dispatch request, // we should forward it down to the lower driver ourself. if (m_Filter && pQueue == m_DefaultQueue && pQueue->IsIoEventHandlerRegistered((WDF_REQUEST_TYPE)Irp->GetMajorFunction()) == FALSE) { // // Default queue doesn't have callback events registered to // handle this request. So forward it down. // goto Forward; } pQueue->AddRef(); // Must add a reference before releasing the callback and its reference pRequest->ADDREF(FXREQUEST_STATE_TAG); // Release the callback oldState = pRequest->SetCompletionState(FxRequestCompletionStateNone); ASSERT(oldState != FxRequestCompletionStateNone); UNREFERENCED_PARAMETER(oldState); status = pQueue->QueueRequestFromForward(pRequest); pQueue->Release(); // // If not successfull, must place the request back // to the state it was in on entry so that the driver // can decide what to do next with it // if (!NT_SUCCESS(status)) { // // If the request comes back to us, it should still // have a reference count of 1 // oldState = pRequest->SetCompletionState(FxRequestCompletionStateIoPkg); ASSERT(oldState == FxRequestCompletionStateNone); UNREFERENCED_PARAMETER(oldState); // // Release the reference count on the request since // the callback will hold the only one that gets // decremented when the request is completed // pRequest->RELEASE(FXREQUEST_STATE_TAG); goto Error; } else { // // On success, can not touch the request since it // may have already been completed // } return status; Forward: // // Cannot send-and-forget a request with a formatted IO context. // if (pRequest->HasContext()) { status = STATUS_INVALID_DEVICE_REQUEST; DoTraceLevelMessage( FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, "Cannot send-and-forget WDFREQUEST 0x%p with formatted IO" " context for filter WDFDEVICE 0x%p, %!STATUS!", pRequest->GetObjectHandle(), Device->GetHandle(), status ); FxVerifierDbgBreakPoint(FxDriverGlobals); goto Error; } // // This will skip the current stack location and perform // early dispose on the request. // pRequest->PreProcessSendAndForget(); (VOID)Irp->CallDriver(Device->GetAttachedDevice()); // // This will delete the request and free the memory back // to the device lookaside list. // pRequest->PostProcessSendAndForget(); // // Return a success status in this code path even if the previous call // to send the request to the lower driver failed. The status code returned // by this function should reflect the status of enqueuing the request and // not the status returned by the lower driver. // return STATUS_SUCCESS; Error: // // If not successful, we must set the original verifier flags. // VerifyEnqueueRequestRestoreFlags(FxDriverGlobals, pRequest, origVerifierFlags); return status; }
FORCEINLINE _Must_inspect_result_ NTSTATUS __fastcall FxPkgIo::DispatchStep1( __inout MdIrp Irp, __in WDFCONTEXT DispatchContext ) /*++ Routine Description: Checks for any registered dynamic dispatch callbacks that handles this type of request, else selects the default queue based on the IRP's major code. Arguments: Irp - WDM request. DispatchContext - Is the next FxIrpDynamicDispatchInfo element. Return Value: Irp's status. --*/ { NTSTATUS status; FxIrp fxIrp(Irp); ASSERT(((UCHAR)DispatchContext & FX_IN_DISPATCH_CALLBACK) == 0); ASSERT(fxIrp.GetMajorFunction() <= IRP_MJ_MAXIMUM_FUNCTION); // // Look for I/O dynamic dispatch callbacks. // if ((PLIST_ENTRY)DispatchContext != &m_DynamicDispatchInfoListHead) { int index; index = FxIrpDynamicDispatchInfo::Mj2Index(fxIrp.GetMajorFunction()); // // Only read/writes/ctrls/internal_ctrls IRPs are allowed, i.e., request cannot // IRP type in its callback. // if (index >= (int)FxIrpDynamicDispatchInfo::DynamicDispatchMax) { status = STATUS_INVALID_PARAMETER; DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO, "Driver cannot change the IRP type in its dispatch " "callback Irp 0x%p, %!IRPMJ!, IRP_MN %x, Device 0x%p, " "%!STATUS!", Irp, fxIrp.GetMajorFunction(), fxIrp.GetMinorFunction(), m_Device->GetHandle(), status); FxVerifierDbgBreakPoint(GetDriverGlobals()); goto CompleteIrp; } // // Verifier checks. // status = VerifyDispatchContext(GetDriverGlobals(), DispatchContext); if( !NT_SUCCESS(status)) { goto CompleteIrp; } do { FxIrpDynamicDispatchInfo* info; info = CONTAINING_RECORD(DispatchContext, FxIrpDynamicDispatchInfo, ListEntry); // // Advance to next node. // DispatchContext = (WDFCONTEXT)(((PLIST_ENTRY)DispatchContext)->Flink); ASSERT(((UCHAR)DispatchContext & FX_IN_DISPATCH_CALLBACK) == 0); ASSERT(fxIrp.GetMajorFunction() == IRP_MJ_READ || fxIrp.GetMajorFunction() == IRP_MJ_WRITE || fxIrp.GetMajorFunction() == IRP_MJ_DEVICE_CONTROL || fxIrp.GetMajorFunction() == IRP_MJ_INTERNAL_DEVICE_CONTROL); // // If registered, invoke dispatch callback for this major function. // ASSERT(index < (int)FxIrpDynamicDispatchInfo::DynamicDispatchMax); if (NULL != info->Dispatch[index].EvtDeviceDynamicDispatch) { return info->Dispatch[index].EvtDeviceDynamicDispatch( m_Device->GetHandle(), fxIrp.GetMajorFunction(), fxIrp.GetMinorFunction(), fxIrp.GetParameterIoctlCode(), info->Dispatch[index].DriverContext, reinterpret_cast<PIRP> (fxIrp.GetIrp()), (WDFCONTEXT)((ULONG_PTR)DispatchContext | FX_IN_DISPATCH_CALLBACK) ); } } while ((PLIST_ENTRY)DispatchContext != &m_DynamicDispatchInfoListHead); } // // Only now push these local variables on the stack, this is to keep the // stack from growing unnecessarily in the dynamic dispatch path above. // FxIoQueue* queue; FxIoInCallerContext* ioInCallerCtx; // // Get the queue from the dispatch-table // queue = m_DispatchTable[fxIrp.GetMajorFunction()]; if (queue == NULL) { ioInCallerCtx = GetIoInCallerContextCallback(NULL); if (ioInCallerCtx->m_Method == NULL) { // // No queue configured yet, fail request unless the driver is a filter. // if (m_Filter) { goto Forward; } status = STATUS_INVALID_DEVICE_REQUEST; DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO, "No queue configured for WDFDEVICE 0x%p, failing IRP 0x%p," " %!STATUS!", m_Device->GetHandle(), Irp, status); goto CompleteIrp; } } else { ioInCallerCtx = GetIoInCallerContextCallback(queue->GetCxDeviceInfo()); } // // If the driver is filter and queue is a default-queue then before // calling the queue, we should make sure the queue can dispatch // requests to the driver. If the queue cannot dispatch request, // we should forward it down to the lower driver ourself. // This is to cover the scenario where the driver has registered only // type specific handler and expect the framework to auto-forward other // requests. // if (m_Filter && ioInCallerCtx->m_Method == NULL && queue == m_DefaultQueue && queue->IsIoEventHandlerRegistered((WDF_REQUEST_TYPE)fxIrp.GetMajorFunction()) == FALSE) { // // Default queue doesn't have callback events registered to // handle this request. So forward it down. // goto Forward; } // // Finally queue request. // return DispatchStep2(Irp, ioInCallerCtx, queue); Forward: fxIrp.SkipCurrentIrpStackLocation(); return fxIrp.CallDriver(m_Device->GetAttachedDevice()); CompleteIrp: fxIrp.SetStatus(status); fxIrp.SetInformation(0); fxIrp.CompleteRequest(IO_NO_INCREMENT); return status; }