FYI: this is a bit of a long post, but I wanted to be thorough and illustrative and give some insight into how the framework works and potential design that could have been made, but were not for the sake of simplicity and performance
A common misconception a WDFREQUEST handle is the assumption that the WDFREQUEST handle value “follows” (e.g. stays the same) the PIRP around everywhere that the PIRP goes to. Basically, the idea is that everywhere that the PIRP is sent or presented, the same WDFREQUST handle will be used. The reality is that the same WDFREQUEST handle value will only be used while the PIRP is owned by the WDFDEVICE for which it was created. This means that if you send the WDFREQUEST to another driver with a call to WdfRequestSend (e.g. transfer ownership to the driver you are sending it to), the driver which receives the PIRP will have a different handle for the WFDREQUEST.
This means that the WDFREQUEST cannot be used to send extra data or buffers to the driver which will receive the sent request. For instance, this pattern does not work. First, in the sending driver (let's say request's handle value is 0xA) you format a request context, format the request and send it to the WDFIOTARGET
typedef struct _EXTRA_BUFFER { PVOID Data; ULONG DataLength; ... } EXTRA_BUFFER, *PEXTRA_BUFFER; PEXTRA_BUFFER pExtra = NULL; WDF_OBEJCT_ATTRIBUTES woa; WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&woa, EXTRA_BUFFER); NTSTATUS status; status = WdfObjectAllocateContext(request, &woa, (PVOID*) &pExtra); // .. initialize pExtra ... // ... format request as an internal IOCTL ... if (WdfRequestSend(request, ...) == FALSE) { WdfRequestComplete(request, WdfRequestGetStatus(request)); }
And then in the receiving driver's WDFQUEUE dispatch routine would have a new WDFREQUEST handle value (let’s say 0xAA) and not the sender’s WDFREQUEST (0xA).
VOID EvtInternalDeviceIoControl( __in WDFQUEUE Queue, __in WDFREQUEST Request, __in size_t OutputBufferLength, __in size_t InputBufferLength, __in ULONG IoControlCode ) { ... }
Think about how KMDf would have been implemented if the same WDFREQUEST was presented to the lower driver. One of two things would have had to occur:
Let’s take a step back and look at why there is a WDFREQUEST handle value when you send a request to another device. Here is what happens when a PIRP arrives in a KMDF driver
Step #2 is the key here. The WDFREQUEST is always allocated (from a lookaside if that matters). It means that there is no 1:1 correspondence between a PIRP and WDFREQUEST value. Let’s say we wanted to have a 1:1 correspondence for a singular WDFDEVICE though(and not across multiple WDFDEVICE as in the first example). We would need a WDFDEVICE based mapping of active PIRPs to WDFREQUEST handles to see if the PIRP is an active PIRP in the WDFDEVICE. As in the case with the previously proposed global mapping, such a WDFDEVICE wide mapping would also be prohibitively expensive. While the lock contention would move from a global scope to a WDFDEVICE scope and thus reducing some contention, such a lock would still be a performance hot spot since all PIRPs arriving into the driver would be contending on this lock.
When you look at how KMDF allocates a WDFREQUEST it becomes clear that the WDFRQUEST loosely maps back to the current stack location in the PIRP, not the PIRP itself! Think about the sending the WDFREQUEST to another driver case. The sending driver has its own stack location and its own WDFREQUEST. The receiving driver has its own stack location and WDFREQUEST as well. Just to reinforce this idea, let’s consider a final example. Let’s say
When PIRP enters your driver as IOCTL 'B', it will have a new WDFREQUEST handle! This is completely by design. The first stack location (IOCTL ‘A’) has one WDFREQUEST, the subsequent stack location (IOCTL ‘B’) has another WDFREQUEST.
In conclusion, WDFREQUEST handles are local to a specific WDFDEVICE. In fact, they are local to a specific stack location. The context off of a WDFREQUEST can only be used by your driver for that particular WDFDEVICE and is not meant to be shared across WDFDEVICEs.