VOID NonPnpEvtDeviceIoInCallerContext( IN WDFDEVICE Device, IN WDFREQUEST Request ) /*++ Routine Description: This I/O in-process callback is called in the calling threads context/address space before the request is subjected to any framework locking or queueing scheme based on the device pnp/power or locking attributes set by the driver. The process context of the calling app is guaranteed as long as this driver is a top-level driver and no other filter driver is attached to it. This callback is only required if you are handling method-neither IOCTLs, or want to process requests in the context of the calling process. Driver developers should avoid defining neither IOCTLs and access user buffers, and use much safer I/O tranfer methods such as buffered I/O or direct I/O. Arguments: Device - Handle to a framework device object. Request - Handle to a framework request object. Framework calls PreProcess callback only for Read/Write/ioctls and internal ioctl requests. Return Value: VOID --*/ { NTSTATUS status = STATUS_SUCCESS; PREQUEST_CONTEXT reqContext = NULL; WDF_OBJECT_ATTRIBUTES attributes; WDF_REQUEST_PARAMETERS params; size_t inBufLen, outBufLen; PVOID inBuf, outBuf; PAGED_CODE(); WDF_REQUEST_PARAMETERS_INIT(¶ms); WdfRequestGetParameters(Request, ¶ms ); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Entered NonPnpEvtDeviceIoInCallerContext %p \n", Request); // // Check to see whether we have recevied a METHOD_NEITHER IOCTL. if not // just send the request back to framework because we aren't doing // any pre-processing in the context of the calling thread process. // if(!(params.Type == WdfRequestTypeDeviceControl && params.Parameters.DeviceIoControl.IoControlCode == IOCTL_NONPNP_METHOD_NEITHER)) { // // Forward it for processing by the I/O package // status = WdfDeviceEnqueueRequest(Device, Request); if( !NT_SUCCESS(status) ) { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "Error forwarding Request 0x%x", status); goto End; } return; } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "EvtIoPreProcess: received METHOD_NEITHER ioctl \n"); // // In this type of transfer, the I/O manager assigns the user input // to Type3InputBuffer and the output buffer to UserBuffer of the Irp. // The I/O manager doesn't copy or map the buffers to the kernel // buffers. // status = WdfRequestRetrieveUnsafeUserInputBuffer(Request, 0, &inBuf, &inBufLen); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "Error WdfRequestRetrieveUnsafeUserInputBuffer failed 0x%x", status); goto End; } status = WdfRequestRetrieveUnsafeUserOutputBuffer(Request, 0, &outBuf, &outBufLen); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "Error WdfRequestRetrieveUnsafeUserOutputBuffer failed 0x%x", status); goto End; } // // Allocate a context for this request so that we can store the memory // objects created for input and output buffer. // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, REQUEST_CONTEXT); status = WdfObjectAllocateContext(Request, &attributes, &reqContext); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "Error WdfObjectAllocateContext failed 0x%x", status); goto End; } // // WdfRequestProbleAndLockForRead/Write function checks to see // whether the caller in the right thread context, creates an MDL, // probe and locks the pages, and map the MDL to system address // space and finally creates a WDFMEMORY object representing this // system buffer address. This memory object is associated with the // request. So it will be freed when the request is completed. If we // are accessing this memory buffer else where, we should store these // pointers in the request context. // #pragma prefast(suppress:6387, "If inBuf==NULL at this point, then inBufLen==0") status = WdfRequestProbeAndLockUserBufferForRead(Request, inBuf, inBufLen, &reqContext->InputMemoryBuffer); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "Error WdfRequestProbeAndLockUserBufferForRead failed 0x%x", status); goto End; } #pragma prefast(suppress:6387, "If outBuf==NULL at this point, then outBufLen==0") status = WdfRequestProbeAndLockUserBufferForWrite(Request, outBuf, outBufLen, &reqContext->OutputMemoryBuffer); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "Error WdfRequestProbeAndLockUserBufferForWrite failed 0x%x", status); goto End; } // // Finally forward it for processing by the I/O package // status = WdfDeviceEnqueueRequest(Device, Request); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "Error WdfDeviceEnqueueRequest failed 0x%x", status); goto End; } return; End: TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "EvtIoPreProcess failed %x \n", status); WdfRequestComplete(Request, status); return; }
break; case WdfRequestTypeWrite: DEBUG("Intercepted Write IRP"); status = WdfRequestRetrieveInputBuffer( Request, //!todo This should work for BUFFERED and DIRECT, but I think it will break for Neither !! 1, (PVOID)&buf, &bufLength); CHECKSTATUS(status, ERROR("Failed to retrieve intercepted write buffer. 0x%0.4", status); break;); DEBUG("Intercepted Write of %d bytes: %#0.2x ...", bufLength, (unsigned char)buf[0]); //!todo place the buf into the RAW PDO context break; // All else can just be passed on... } // Try to pass this down the stack status = WdfDeviceEnqueueRequest( Device, Request); if (!NT_SUCCESS(status)) { // If we failed then complete it with an error ERROR("Error passing Intercepted IO request on, completing it ourself."); WdfRequestComplete(Request, status); } } #else // Filter read VOID GFilterRead( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length) { NTSTATUS status = STATUS_ABANDONED;