1 /*++
2
3 Copyright (c) Microsoft Corporation
4
5 Module Name:
6
7 FxRequest.cpp
8
9 Abstract:
10
11 This module implements FxRequest object
12
13 Author:
14
15
16
17 Environment:
18
19 Both kernel and user mode
20
21 Revision History:
22
23
24 --*/
25
26 #include "coreprivshared.hpp"
27
28 // Tracing support
29 extern "C" {
30 // #include "FxRequest.tmh"
31 }
32
FxRequest(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in MdIrp Irp,__in FxRequestIrpOwnership Ownership,__in FxRequestConstructorCaller Caller,__in USHORT ObjectSize)33 FxRequest::FxRequest(
34 __in PFX_DRIVER_GLOBALS FxDriverGlobals,
35 __in MdIrp Irp,
36 __in FxRequestIrpOwnership Ownership,
37 __in FxRequestConstructorCaller Caller,
38 __in USHORT ObjectSize
39 ) :
40 FxRequestBase(FxDriverGlobals,
41 ObjectSize,
42 Irp,
43 Ownership,
44 Caller)
45 {
46 m_OutputBufferOffset = FIELD_OFFSET(FxRequest, m_OutputBufferOffset);
47 m_SystemBufferOffset = FIELD_OFFSET(FxRequest, m_SystemBufferOffset);
48 m_IoQueue = NULL;
49
50 m_PowerStopState = FxRequestPowerStopUnknown;
51
52 InitializeListHead(&m_OwnerListEntry);
53 InitializeListHead(&m_OwnerListEntry2);
54 InitializeListHead(&m_ForwardProgressList);
55
56 m_Presented = (Caller == FxRequestConstructorCallerIsDriver) ? TRUE : FALSE;
57 m_Reserved = FALSE;
58 m_ForwardProgressQueue = NULL;
59 m_ForwardRequestToParent = FALSE;
60 m_InternalContext = NULL;
61 }
62
63 #if DBG
~FxRequest(VOID)64 FxRequest::~FxRequest(
65 VOID
66 )
67 {
68 ASSERT(IsListEmpty(&m_OwnerListEntry));
69 ASSERT(IsListEmpty(&m_OwnerListEntry2));
70 }
71 #endif // DBG
72
73 _Must_inspect_result_
74 NTSTATUS
_CreateForPackage(__in CfxDevice * Device,__in PWDF_OBJECT_ATTRIBUTES RequestAttributes,__in MdIrp Irp,__deref_out FxRequest ** Request)75 FxRequest::_CreateForPackage(
76 __in CfxDevice* Device,
77 __in PWDF_OBJECT_ATTRIBUTES RequestAttributes,
78 __in MdIrp Irp,
79 __deref_out FxRequest** Request
80 )
81 /*++
82
83 Routine Description:
84
85 Creates an FxRequest object and returns its pointer to the caller.
86
87 Arguments:
88
89 Device - Pointer to FxDevice object request will be associated with
90
91 RequestAttributes - Specifies the object's attributes for the request.
92
93 Irp - Pointer to Irp
94
95 Request - Pointer to location to store the returned FxRequest pointer
96
97 Return Value:
98
99 NTSTATUS
100
101 --*/
102 {
103 NTSTATUS status;
104 FxRequest* pRequest;
105
106 *Request = NULL;
107
108 //
109 // Allocate the new FxRequest object in the per driver tracking pool
110 //
111 pRequest = new(Device, RequestAttributes) FxRequestFromLookaside(Device, Irp);
112
113 if (pRequest == NULL) {
114 DoTraceLevelMessage(
115 Device->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
116 "Memory allocation failed %!STATUS!",
117 STATUS_INSUFFICIENT_RESOURCES);
118 return STATUS_INSUFFICIENT_RESOURCES;
119 }
120
121 //
122 // For forward progress the IRP can be NULL.
123 //
124 if (Irp != NULL) {
125 pRequest->AssignMemoryBuffers(Device->GetIoTypeForReadWriteBufferAccess());
126 }
127
128 //
129 // Improve I/O perf by not parenting it to device. However, if verifier is
130 // turned on, the request is parented to the device to help track reference
131 // leaks.
132 //
133 if (Device->GetDriverGlobals()->FxRequestParentOptimizationOn) {
134 status = pRequest->Commit(RequestAttributes,
135 NULL,
136 NULL,
137 FALSE);
138 }
139 else {
140 status = pRequest->Commit(RequestAttributes,
141 NULL,
142 Device,
143 FALSE);
144 }
145
146 if (NT_SUCCESS(status)) {
147 *Request = pRequest;
148 }
149 else {
150 DoTraceLevelMessage(
151 Device->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
152 "Could not commit FxRequest %!STATUS!", status);
153 pRequest->DeleteFromFailedCreate();
154 }
155
156 return status;
157 }
158
159 _Must_inspect_result_
160 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)161 FxRequest::_Create(
162 __in PFX_DRIVER_GLOBALS FxDriverGlobals,
163 __in_opt PWDF_OBJECT_ATTRIBUTES RequestAttributes,
164 __in_opt MdIrp Irp,
165 __in_opt FxIoTarget* Target,
166 __in FxRequestIrpOwnership Ownership,
167 __in FxRequestConstructorCaller Caller,
168 __deref_out FxRequest** Request
169 )
170 {
171 WDFOBJECT hRequest;
172 NTSTATUS status;
173 FxRequest* pRequest;
174
175 *Request = NULL;
176
177 status = FxValidateObjectAttributes(FxDriverGlobals, RequestAttributes);
178 if (!NT_SUCCESS(status)) {
179 return status;
180 }
181
182 pRequest = new (FxDriverGlobals, RequestAttributes)
183 FxRequest(FxDriverGlobals,
184 Irp,
185 Ownership,
186 Caller,
187 sizeof(FxRequest));
188
189 if (pRequest != NULL) {
190 if (Target != NULL) {
191 status = pRequest->ValidateTarget(Target);
192 }
193
194 if (NT_SUCCESS(status)) {
195 status = pRequest->Commit(RequestAttributes, &hRequest, NULL, TRUE);
196 }
197
198 if (NT_SUCCESS(status)) {
199 *Request = pRequest;
200 }
201 else {
202 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
203 "Handle create failed %!STATUS!", status);
204
205 if (Irp != NULL) {
206 //
207 // Clear the irp out of the request so that the destructor does
208 // not free it. Since we are returning failure, the caller does
209 // not expect the PIRP passed in to be freed.
210 //
211 pRequest->SetSubmitIrp(NULL, FALSE);
212 }
213
214 pRequest->DeleteFromFailedCreate();
215 }
216 }
217 else {
218 status = STATUS_INSUFFICIENT_RESOURCES;
219 }
220
221 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST,
222 "Irp %p Ownership %!FxRequestIrpOwnership! FxRequest %p, status %!STATUS!",
223 Irp, Ownership, *Request, status);
224
225 return status;
226 }
227
228 NTSTATUS
SetInformation(__in ULONG_PTR Information)229 FxRequest::SetInformation(
230 __in ULONG_PTR Information
231 )
232 /*++
233
234 Routine Description:
235
236 Set the IRP's IoStatus.Information field.
237
238 NOTE: If the caller calls Complete(status, information), as opposed
239 to Complete(status), the value will get overwritten.
240
241 Arguments:
242
243 Information - Information value to set
244
245 Returns:
246
247 NTSTATUS
248
249 --*/
250 {
251 PFX_DRIVER_GLOBALS pFxDriverGlobals;
252
253 pFxDriverGlobals = GetDriverGlobals();
254
255 if (pFxDriverGlobals->FxVerifierIO) {
256 NTSTATUS status;
257 KIRQL irql;
258
259 Lock(&irql);
260
261 status = VerifyRequestIsNotCompleted(pFxDriverGlobals);
262 if (NT_SUCCESS(status)) {
263 m_Irp.SetInformation(Information);
264 }
265
266 Unlock(irql);
267
268 return status;
269 }
270 else {
271 m_Irp.SetInformation(Information);
272 return STATUS_SUCCESS;
273 }
274 }
275
276 ULONG_PTR
GetInformation(VOID)277 FxRequest::GetInformation(
278 VOID
279 )
280 /*++
281
282 Routine Description:
283
284 Get the IRP's IoStatus.Information field.
285
286
287 Arguments:
288
289 None
290
291 Returns:
292
293 ULONG_PTR
294
295 --*/
296 {
297 PFX_DRIVER_GLOBALS pFxDriverGlobals;
298
299 pFxDriverGlobals = GetDriverGlobals();
300
301 // Verifier
302 if (pFxDriverGlobals->FxVerifierIO) {
303 ULONG_PTR info;
304 KIRQL irql;
305 NTSTATUS status;
306
307 Lock(&irql);
308
309 status = VerifyRequestIsNotCompleted(pFxDriverGlobals);
310 if (!NT_SUCCESS(status)) {
311 info = NULL;
312 }
313 else {
314 info = m_Irp.GetInformation();
315 }
316
317 Unlock(irql);
318
319 return info;
320 }
321 else {
322 return m_Irp.GetInformation();
323 }
324 }
325
326 KPROCESSOR_MODE
GetRequestorMode(VOID)327 FxRequest::GetRequestorMode(
328 VOID
329 )
330 /*++
331
332 Routine Description:
333 Get the Irp->RequestorMode value.
334
335 Arguments:
336 None
337
338 Returns:
339 KPROCESSOR_MODE
340
341 --*/
342 {
343 PFX_DRIVER_GLOBALS pFxDriverGlobals;
344
345 pFxDriverGlobals = GetDriverGlobals();
346
347 if (pFxDriverGlobals->FxVerifierIO) {
348 KPROCESSOR_MODE mode;
349 KIRQL irql;
350 NTSTATUS status;
351
352 Lock(&irql);
353
354 status = VerifyRequestIsNotCompleted(pFxDriverGlobals);
355 if (!NT_SUCCESS(status)) {
356 mode = UserMode;
357 } else {
358 mode = m_Irp.GetRequestorMode();
359 }
360
361 Unlock(irql);
362
363 return mode;
364 }
365 else {
366 return m_Irp.GetRequestorMode();
367 }
368 }
369
370
371 VOID
FX_VF_METHOD(FxRequest,VerifyCompleteInternal)372 FX_VF_METHOD(FxRequest, VerifyCompleteInternal)(
373 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
374 _In_ NTSTATUS Status
375 )
376 {
377 UNREFERENCED_PARAMETER(FxDriverGlobals);
378 ULONG length;
379 KIRQL irql;
380 BOOLEAN validateLength;
381
382 PAGED_CODE_LOCKED();
383
384 Lock(&irql);
385
386 if (GetDriverGlobals()->FxVerifierIO ) {
387 (VOID) VerifyRequestIsNotCompleted(GetDriverGlobals());
388 } else {
389 ASSERT(m_Completed == FALSE);
390 }
391
392
393 if ((m_VerifierFlags & FXREQUEST_FLAG_DRIVER_CANCELABLE) &&
394 (m_VerifierFlags & FXREQUEST_FLAG_CANCELLED) == 0x0) {
395
396 //
397 // We could trace each sentence separate, but that takes up valuable
398 // room in the IFR. Instead, trace the entire "paragraph" as one
399 // message so that we have more room in the IFR.
400 //
401 DoTraceLevelMessage(
402 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
403 "Completing Cancelable WDFREQUEST %p. "
404
405 "This results in a race condition in the device driver that can "
406 "cause double completions. "
407
408 "Call WdfRequestUnmarkCancelable before WdfRequestComplete. "
409
410 "If WdfRequestUnmarkCancelable returns STATUS_CANCELLED, "
411 "do not complete the request until the EvtIoCancel handler is called. "
412
413 "The straightforward way to ensure this is to complete a canceled "
414 "request from the EvIoCancel callback.",
415
416 GetHandle()
417 );
418
419 FxVerifierDbgBreakPoint(GetDriverGlobals());
420
421 }
422
423 validateLength = FALSE;
424 length = 0;
425
426 switch (m_Irp.GetMajorFunction()) {
427 case IRP_MJ_READ:
428 length = m_Irp.GetParameterReadLength();
429 validateLength = TRUE;
430 break;
431
432 case IRP_MJ_WRITE:
433 length = m_Irp.GetParameterWriteLength();
434 validateLength = TRUE;
435 break;
436
437 case IRP_MJ_DEVICE_CONTROL:
438 if (m_Irp.GetRequestorMode() == UserMode) {
439 length = m_Irp.GetParameterIoctlOutputBufferLength();
440
441 if (length > 0) {
442 validateLength = TRUE;
443 }
444 else {
445 //
446 // For an output length == 0, a driver can indicate the number
447 // of bytes used of the input buffer.
448 //
449 DO_NOTHING();
450 }
451 }
452 else {
453 //
454 // If the IOCTL came from kernel mode, the same reasoning applies
455 // here as for an internal IOCTL...we don't know deterministically
456 // how to find the output buffer length.
457 //
458 DO_NOTHING();
459 }
460 break;
461
462 case IRP_MJ_INTERNAL_DEVICE_CONTROL:
463 //
464 // Because the current stack location can use any part of the union
465 // (like Parameters.Others instead of Parameters.DeviceIoControl), we
466 // cannot deterministically figure out the output buffer length for
467 // internal IOCTLs.
468 //
469 // || || Fall through || ||
470 // \/ \/ \/ \/
471 default:
472 DO_NOTHING();
473 }
474
475 //
476 // We shouldn't validate the information field if the status is warning
477 // because it's valid for a driver to fill partial data in the buffer
478 // and ask for large buffer size.
479 //
480 if (validateLength &&
481 NT_SUCCESS(Status) &&
482 m_Irp.GetInformation() > length) {
483
484 WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA data;
485
486 DoTraceLevelMessage(
487 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
488 "WDFREQUEST %p, MJ 0x%x, Information 0x%I64x is greater then "
489 "buffer length 0x%x", GetHandle(), m_Irp.GetMajorFunction(),
490 m_Irp.GetInformation(), length);
491
492 data.Request = GetHandle();
493 data.Irp = reinterpret_cast<PIRP>(m_Irp.GetIrp());
494 data.OutputBufferLength = length;
495 data.Information = m_Irp.GetInformation();
496 data.MajorFunction = m_Irp.GetMajorFunction();
497
498 FxVerifierBugCheck(
499 GetDriverGlobals(),
500 WDF_REQUEST_FATAL_ERROR,
501 WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH,
502 (ULONG_PTR) &data
503 );
504
505 // will not get here
506 }
507
508 // Set IRP to NULL when NT IRP is completed
509 m_Completed = TRUE;
510
511 Unlock(irql);
512 }
513
514 NTSTATUS
CompleteInternal(__in NTSTATUS Status)515 FxRequest::CompleteInternal(
516 __in NTSTATUS Status
517 )
518
519 /*++
520
521 Routine Description:
522
523 Internal worker to complete the current request object.
524
525 This is called with the FxRequest object lock held, and
526 state validation as far as IRP completion already done.
527
528 Callers must use Complete(Status), or Complete(Status,Information)
529
530 It returns with the FxRequest object locked *released*
531
532 Arguments:
533
534 Status - Status to complete the request with
535
536 Returns:
537
538 NTSTATUS
539
540 --*/
541
542 {
543 PFX_DRIVER_GLOBALS pFxDriverGlobals;
544 MdIrp pIrp;
545 FxRequestCompletionState state;
546 FxIoQueue* queue;
547 CfxDevice* pRefedDevice;
548
549 pFxDriverGlobals = GetDriverGlobals();
550 queue = NULL;
551 //
552 // Store off the irp into a local variable
553 //
554 pIrp = m_Irp.GetIrp();
555
556 //
557 // Lock is no longer required, since it's only used
558 // by verifier for already completed requests. This is a
559 // serious driver error anyway
560 //
561
562
563 VerifyCompleteInternal(pFxDriverGlobals, Status);
564
565 if (pFxDriverGlobals->FxVerifierOn == FALSE) {
566 //
567 // No lock needed in non-verifier case since this is only
568 // used to detect double completions with verifier on
569 //
570 ASSERT(m_Completed == FALSE);
571 m_Completed = TRUE;
572 }
573
574
575
576
577
578
579 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
580
581
582
583
584
585
586
587 ULONG flagsMasked = m_Irp.GetFlags() & IRP_INPUT_OPERATION;
588 if (m_Irp.GetMajorFunction()== IRP_MJ_DEVICE_CONTROL &&
589 m_Irp.GetParameterIoctlCodeBufferMethod() == METHOD_BUFFERED &&
590 m_Irp.GetRequestorMode() == UserMode &&
591 m_Irp.GetParameterIoctlOutputBufferLength()== 0 &&
592 (flagsMasked != 0)) {
593
594 DoTraceLevelMessage(
595 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
596 "Driver that handled WDFREQUEST 0x%p is requesting data to "
597 " be written back to the UserBuffer by returing a non zero value "
598 " in the Irp 0x%p Information field even though the OutputBufferLength "
599 " is zero", GetObjectHandle(), pIrp);
600
601 //
602 // We will assert only if the Information field is not zero to warn
603 // the developer that it's a bad thing to do. However, we do avoid
604 // corruption of UserBuffer on completion by clearing the flag
605 // erroneously set by the I/O manager.
606 //
607 if (m_Irp.GetInformation() != 0L) {
608 FxVerifierDbgBreakPoint(pFxDriverGlobals);
609 }
610
611 //
612 // Clear the flag to prevent the I/O manager from coping the
613 // data back from the SystemBuffer to Irp->UserBuffer
614 //
615 m_Irp.SetFlags(m_Irp.GetFlags() & (~IRP_INPUT_OPERATION));
616 }
617 #endif
618
619 //
620 // If the status code is one of the framework facility codes,
621 // map it to a standard NTSTATUS
622 //
623
624
625 if ((Status & 0x0FFF0000) == (FACILITY_DRIVER_FRAMEWORK << 16)) {
626 DoTraceLevelMessage(
627 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
628 "Converting WDF NTSTATUS value 0x%x...", Status);
629
630 switch (Status) {
631 case STATUS_WDF_PAUSED:
632 case STATUS_WDF_BUSY:
633 Status = STATUS_DEVICE_BUSY;
634 break;
635
636 case STATUS_WDF_INTERNAL_ERROR:
637 Status = STATUS_INTERNAL_ERROR;
638 break;
639
640 case STATUS_WDF_TOO_FRAGMENTED:
641 Status = STATUS_INVALID_DEVICE_REQUEST;
642 break;
643
644 default:
645 DoTraceLevelMessage(
646 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
647 "Unknown WDF NTSTATUS 0x%x", Status);
648 Status = STATUS_INVALID_DEVICE_REQUEST;
649 break;
650 }
651
652 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
653 "... to %!STATUS!", Status);
654 }
655
656 if (IsAllocatedFromIo() == FALSE && IsCanComplete() == FALSE) {
657 FxVerifierDbgBreakPoint(pFxDriverGlobals);
658 }
659
660 //
661 // It is invalid to complete any requests on an IRPQUEUE
662 //
663 ASSERTMSG("WDFREQUEST is part of a WDFQUEUE, it could be Cancellable\n",
664 (m_IrpQueue == NULL));
665
666 state = (FxRequestCompletionState) m_CompletionState;
667 queue = m_IoQueue;
668
669 //
670 // Some I/O request cleanup. Do not do this for driver created requests.
671 //
672 if (IsAllocatedFromIo()) {
673 //
674 // Set the completion state to none
675 //
676 m_CompletionState = FxRequestCompletionStateNone;
677
678 if (IsReserved() == FALSE) {
679 //
680 // Don't set the Queue to NULL for reserved requests.
681 //
682 m_IoQueue = NULL;
683 }
684 }
685
686 //
687 // IMPORTANT: the context must free its references before the request is
688 // completed. Any of these references could be on a memory interface that is
689 // an embedded interface in this object. If this reference
690 // is left outstanding when we check m_IrpReferenceCount below, we would
691 // bugcheck (and the driver writer would be unaware of why things are going
692 // wrong).
693 //
694 // Also, if the driver is freeing the referenced mmemory interface in its
695 // cleanup routine, we don't want an oustanding reference against it.
696 //
697 if (m_RequestContext != NULL) {
698 //
699 // m_RequestContext will be freed when the FxRequest's desctructor runs
700 //
701 m_RequestContext->ReleaseAndRestore(this);
702 }
703
704 //
705 // If the request is not presented to the driver then clear the
706 // cleanup & destroy callbacks before calling PerformEarlyDispose.
707 //
708 if (m_Presented == FALSE) {
709 ClearEvtCallbacks();
710 }
711
712 if (IsReserved() == FALSE && IsAllocatedFromIo()) {
713 //
714 // Fire the driver supplied Cleanup callback if set
715 //
716 // This will allow the driver to release any IRP specific resources such
717 // as MDLs before we complete the IRP back to the OS, and release the
718 // process/thread reference.
719 //
720 // This is also the callback used to tell the driver the WDM IRP is going
721 // away if it has used the WDM "escape" API's to either get the IRP, or
722 // any resources it references.
723 //
724
725 //
726 // If a cleanup callback has been registered, we call it
727 // just before completing the IRP to WDM, which can cause any
728 // associated buffers, MDLs, or memory interfaces to be invalidated.
729 //
730 if (EarlyDispose() == FALSE) {
731 VerifierBreakpoint_RequestEarlyDisposeDeferred(GetDriverGlobals());
732 }
733
734 //
735 // Now that the entire tree is disposed, we want to destroy all of the
736 // children. This will not put this object in the destroyed state. For
737 // m_IrpReferenceCount to go to zero, we need to destroy the child WDFMEMORYs
738 // that were created when we probed and locked the buffers.
739 //
740 DestroyChildren();
741 }
742 else {
743 //
744 // We don't call cleanup callback for Reserved Requests.
745 // The driver can perform any cleanp it wants before completing the Request
746 // or before reusing the Reserved Request in its Dispatch callback.
747
748
749
750
751
752
753 DO_NOTHING();
754 }
755
756 //
757 // If this is non-zero, indicates a reference count problem on any
758 // WDFMEMORY objects returned to the device driver from this WDFREQUEST.
759 //
760 if (m_IrpReferenceCount != 0) {
761 //
762 // NOTE: you cannot call GetBuffer or GetMdl
763 DoTraceLevelMessage(
764 pFxDriverGlobals, TRACE_LEVEL_FATAL, TRACINGREQUEST,
765 "WDFREQUEST 0x%p, PIRP 0x%p, Major Function 0x%x, completed with "
766 "outstanding references on WDFMEMORY 0x%p or 0x%p retrieved from "
767 "this request",
768 GetObjectHandle(), m_Irp.GetIrp(), m_Irp.GetMajorFunction(),
769 ((m_RequestBaseFlags & FxRequestBaseSystemMdlMapped) ||
770 (m_RequestBaseStaticFlags & FxRequestBaseStaticSystemBufferValid)) ?
771 m_SystemBuffer.GetHandle() : NULL,
772 ((m_RequestBaseFlags & FxRequestBaseOutputMdlMapped) ||
773 (m_RequestBaseStaticFlags & FxRequestBaseStaticOutputBufferValid)) ?
774 m_OutputBuffer.GetHandle() : NULL
775 );
776
777 if ((m_RequestBaseFlags & FxRequestBaseSystemMdlMapped) ||
778 (m_RequestBaseStaticFlags & FxRequestBaseStaticSystemBufferValid)) {
779 DoTraceLevelMessage(
780 pFxDriverGlobals, TRACE_LEVEL_FATAL, TRACINGREQUEST,
781 "WDFMEMORY 0x%p, buffer %p, PMDL %p, length %I64d bytes",
782 m_SystemBuffer.GetHandle(), m_SystemBuffer.GetBuffer(),
783 m_SystemBuffer.GetMdl(), m_SystemBuffer.GetBufferSize());
784 }
785
786 if ((m_RequestBaseFlags & FxRequestBaseOutputMdlMapped) ||
787 (m_RequestBaseStaticFlags & FxRequestBaseStaticOutputBufferValid)) {
788 DoTraceLevelMessage(
789 pFxDriverGlobals, TRACE_LEVEL_FATAL, TRACINGREQUEST,
790 "IOCTL output WDFMEMORY 0x%p, buffer %p, PMDL %p, length %I64d bytes",
791 m_OutputBuffer.GetHandle(), m_OutputBuffer.GetBuffer(),
792 m_OutputBuffer.GetMdl(), m_OutputBuffer.GetBufferSize());
793 }
794
795 FxVerifierBugCheck(pFxDriverGlobals,
796 WDF_VERIFIER_FATAL_ERROR,
797 (ULONG_PTR) GetObjectHandle(),
798 (ULONG_PTR) m_IrpReferenceCount);
799 }
800
801 FxIrp irp(pIrp);
802
803 //
804 // Complete the NT IRP through the frameworks FxIrp
805 //
806 irp.SetStatus(Status);
807
808 ASSERT(IsCancelRoutineSet() == FALSE);
809
810 //
811 // For driver created requests we need to use two phase
812 // completion (pre and post) to detach the request from the queue before the
813 // IRP is completed, and then allow a new request to be dispatched.
814 // Note that the IRP is actually completed when the reference on this object
815 // goes to 1 (See FxRequest::Release() for more info).
816 //
817 if (IsAllocatedFromIo() == FALSE) {
818 //
819 // Do not touch the request after this call.
820 // Do not clear the request's IRP field before making this call.
821 //
822 PreProcessCompletionForDriverRequest(state, queue);
823 }
824 else {
825 //
826 // We only clear the irp from this object after PerformEarlyDispose has been
827 // called. m_SystemBuffer and m_OutputBuffer use m_Irp to return their
828 // buffers and their WDFMEMORY handles should be valid in the cleanup routine
829 // for the WDFREQUEST. We also keep m_Irp valid until after the
830 // m_IrpReferenceCount check, so we can trace out the buffers in case of
831 // error.
832 //
833 m_Irp.SetIrp(NULL);
834
835 if (irp.GetMajorFunction() == IRP_MJ_CREATE) {
836 //
837 // If this is the last handle to be closed on the device, then the call
838 // to CreateCompleted can cause the device to be deleted if the create
839 // has failed. We add a reference so that we make sure we have a device
840 // to free the request memory back to.
841 //
842 pRefedDevice = GetDevice();
843 pRefedDevice->ADDREF(&irp);
844
845 pRefedDevice->m_PkgGeneral->CreateCompleted(&irp);
846 }
847 else {
848 pRefedDevice = NULL;
849 }
850
851 //
852 // WDM IRP is completed.
853 //
854 irp.CompleteRequest(GetPriorityBoost());
855
856 if (IsReserved() == FALSE) {
857 PostProcessCompletion(state, queue);
858 }
859 else {
860 PostProcessCompletionForReserved(state, queue);
861 }
862
863 if (pRefedDevice != NULL) {
864 pRefedDevice->RELEASE(&irp);
865 pRefedDevice = NULL;
866 }
867 }
868
869 return Status;
870 }
871
872
873 VOID
PostProcessCompletion(__in FxRequestCompletionState State,__in FxIoQueue * Queue)874 FxRequest::PostProcessCompletion(
875 __in FxRequestCompletionState State,
876 __in FxIoQueue* Queue
877 )
878 {
879 //
880 // Fire frameworks internal callback event if one is set
881 // (FxIoQueue or IoTarget's internal use)
882 //
883 if (State != FxRequestCompletionStateNone) {
884 //
885 // NOTE: This occurs after the IRP has already been released,
886 // and is only used for notification that the request
887 // has completed.
888 //
889 if (State & FxRequestCompletionStateIoPkgFlag) {
890 GetDevice()->m_PkgIo->RequestCompletedCallback(this);
891 }
892 else {
893 ASSERT(Queue != NULL);
894 Queue->RequestCompletedCallback(this);
895 //FxIoQueueToMx::RequestCompletedCallback(Queue, this);
896 }
897
898 //
899 // DeleteObject will dereference the object reference taken when the callback
900 // was registered
901 //
902 DeleteEarlyDisposedObject();
903 }
904 else {
905 //
906 // Caller still wants the FxRequest class to be valid on return,
907 // but must call DeleteObject in order to ensure the object is
908 // no longer assigned any child objects, etc.
909 //
910 ADDREF(FXREQUEST_COMPLETE_TAG);
911 DeleteObject();
912 }
913 }
914
915 VOID
PostProcessCompletionForReserved(__in FxRequestCompletionState State,__in FxIoQueue * Queue)916 FxRequest::PostProcessCompletionForReserved(
917 __in FxRequestCompletionState State,
918 __in FxIoQueue* Queue
919 )
920 {
921 //
922 // Fire frameworks internal callback event if one is set
923 // (FxIoQueue or IoTarget's internal use)
924 //
925 if (State != FxRequestCompletionStateNone) {
926 //
927 // NOTE: This occurs after the IRP has already been released,
928 // and is only used for notification that the request
929 // has completed.
930 //
931 if (State & FxRequestCompletionStateIoPkgFlag) {
932 GetDevice()->m_PkgIo->RequestCompletedCallback(this);
933 }
934 else {
935 ASSERT(m_IoQueue == Queue);
936 Queue->RequestCompletedCallback(this);
937 }
938 }
939 else {
940 //
941 // Caller still wants the FxRequest class to be valid on return,
942 // but must call DeleteObject in order to ensure the object is
943 // no longer assigned any child objects, etc.
944 //
945 ADDREF(FXREQUEST_COMPLETE_TAG);
946 }
947
948 RELEASE(FXREQUEST_FWDPRG_TAG);
949 }
950
951 //
952 // Handles pre-process completion for driver-created-requests queued by the driver.
953 //
954 VOID
PreProcessCompletionForDriverRequest(__in FxRequestCompletionState State,__in FxIoQueue * Queue)955 FxRequest::PreProcessCompletionForDriverRequest(
956 __in FxRequestCompletionState State,
957 __in FxIoQueue* Queue
958 )
959 {
960 ASSERT(State == FxRequestCompletionStateNone ||
961 State == FxRequestCompletionStateQueue);
962 //
963 // Fire frameworks internal callback (pre) event if one is set.
964 //
965 if (FxRequestCompletionStateQueue == State) {
966 //
967 // NOTE: This occurs before the IRP has already been released,
968 // and is only used to notify the queue to remove this request from this queue's
969 // internal lists. A second notification (lPostProcessCompletionForAllocatedDriver)
970 // is made after the IRP is completed.
971 //
972 Queue->PreRequestCompletedCallback(this);
973 }
974 else if (Queue != NULL){
975 //
976 // On return from PostProcessCompletionForDriverRequest, caller (framework)
977 // will try to release the last ref. Increase the ref count so request stays alive until
978 // driver invokes WdfObjectDelete on this request.
979 //
980 ADDREF(FXREQUEST_COMPLETE_TAG);
981 }
982
983 //
984 // Let the system know that it is OK to complete this request.
985 //
986 RELEASE(FXREQUEST_DCRC_TAG);
987 }
988
989 //
990 // Handles post-process completion for driver-created-requests queued by the driver.
991 // On return the driver can delete the request with WdfObjectDelete.
992 // NOTE: request may be already gone/reused. Do not dereference this or access any of its
993 // members... its pointer is only used for logging.
994 //
995 VOID
PostProcessCompletionForDriverRequest(__in FxRequestCompletionState State,__in FxIoQueue * Queue)996 FxRequest::PostProcessCompletionForDriverRequest(
997 __in FxRequestCompletionState State,
998 __in FxIoQueue* Queue
999 )
1000 {
1001 //
1002 // NOTE: Do not touch the request object here. The request object may already be
1003 // re-used or deleted.
1004 //
1005
1006 ASSERT(State == FxRequestCompletionStateNone ||
1007 State == FxRequestCompletionStateQueue);
1008 //
1009 // Fire frameworks internal callback (post) event if one is set.
1010 //
1011 if (FxRequestCompletionStateQueue == State) {
1012 //
1013 // NOTE: This occurs after the IRP has already been released, and is only used
1014 // to notify the queue to update its internal state and if appropriate, send
1015 // another request.
1016 //
1017 Queue->PostRequestCompletedCallback(this);
1018 }
1019 }
1020
1021 VOID
FreeRequest(VOID)1022 FxRequest::FreeRequest(
1023 VOID
1024 )
1025 /*++
1026
1027 Routine Description:
1028
1029 This routine is called to free a reserved request or in case of Fxpkgio
1030 a non-reserved request.
1031
1032 --*/
1033 {
1034 //
1035 // Restore any fields if necessary
1036 //
1037 if (m_RequestContext != NULL) {
1038 //
1039 // m_RequestContext will be freed when the FxRequest's destructor runs
1040 //
1041 m_RequestContext->ReleaseAndRestore(this);
1042 }
1043
1044 //
1045 // If the request is not presented to the driver then clear the
1046 // cleanup & destroy callbacks before calling PerformEarlyDispose.
1047 //
1048 if (m_Presented == FALSE) {
1049 ClearEvtCallbacks();
1050 }
1051
1052 DeleteObject();
1053 }
1054
1055 VOID
FX_VF_METHOD(FxRequest,VerifyPreProcessSendAndForget)1056 FX_VF_METHOD(FxRequest, VerifyPreProcessSendAndForget) (
1057 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
1058 )
1059 {
1060 PAGED_CODE_LOCKED();
1061
1062 if (m_CompletionRoutine.m_Completion != NULL) {
1063 DoTraceLevelMessage(
1064 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
1065 "WDFREQUEST %p cannot send and forget will not execute completion "
1066 "routine %p",
1067 GetHandle(), m_CompletionRoutine.m_Completion);
1068
1069 FxVerifierDbgBreakPoint(FxDriverGlobals);
1070
1071
1072
1073
1074
1075
1076
1077
1078 }
1079
1080 //
1081 // You cannot fire and forget a create irp if we created a WDFFILEOBJECT
1082 // for it since you must post process the status of the create because
1083 // the create can fail in the driver to which we are sending the irp.
1084 //
1085 if ((m_Irp.GetMajorFunction() == IRP_MJ_CREATE)
1086 &&
1087 (FxFileObjectClassNormalize(GetDevice()->GetFileObjectClass()) !=
1088 WdfFileObjectNotRequired)) {
1089
1090 DoTraceLevelMessage(
1091 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
1092 "WDFREQUEST %p cannot send and forget a create request which "
1093 "has a WDFFILEOBJECT created for it, it must have a completion "
1094 "routine and be post processsed", GetHandle());
1095
1096 FxVerifierDbgBreakPoint(FxDriverGlobals);
1097 }
1098 }
1099
1100 VOID
PreProcessSendAndForget(VOID)1101 FxRequest::PreProcessSendAndForget(
1102 VOID
1103 )
1104 {
1105 VerifyPreProcessSendAndForget(GetDriverGlobals());
1106
1107 //
1108 // To be sent and forgotten, the irp must have been presented
1109 //
1110 ASSERT(m_Presented);
1111
1112 //
1113 // To be sent and forgotten, the irp must not have a formatted IO context.
1114 //
1115 ASSERT(HasContext() == FALSE);
1116
1117 //
1118 // If the driver writer setup the next stack location using the current
1119 // stack location or did a manual IO_STACK_LOCATION copy, we do not want to
1120 // skip the current stack location that their format is used by the target
1121 // driver.
1122 //
1123 if (m_NextStackLocationFormatted == FALSE) {
1124 m_Irp.SkipCurrentIrpStackLocation();
1125 }
1126
1127 if (IsReserved() == FALSE) {
1128
1129 //
1130 // If a cleanup callback has been registered, we call it
1131 // just before sending the IRP on its way. The contract is that the cleanup
1132 // routine for a WDFREQUEST is called while the PIRP is still valid.
1133 //
1134 if (EarlyDispose() == FALSE) {
1135 VerifierBreakpoint_RequestEarlyDisposeDeferred(GetDriverGlobals());
1136 }
1137
1138 //
1139 // Now that the entire tree is disposed, we want to destroy all of the
1140 // children. This will not put this object in the destroyed state. For
1141 // m_IrpReferenceCount to go to zero, we need to destroy the child WDFMEMORYs
1142 // that were created when we probed and locked the buffers.
1143 //
1144 DestroyChildren();
1145 }
1146 }
1147
1148 VOID
PostProcessSendAndForget(VOID)1149 FxRequest::PostProcessSendAndForget(
1150 VOID
1151 )
1152 {
1153 FxRequestCompletionState state;
1154 FxIoQueue* pQueue;
1155
1156 m_Irp.SetIrp(NULL);
1157
1158 //
1159 // Capture the m_IoQueue value before making any other calls.
1160 // Note: m_IoQueue could be NULL if the request is freed before it's queued.
1161 //
1162 pQueue = m_IoQueue;
1163
1164 ASSERT(m_CompletionState != FxRequestCompletionStateNone);
1165
1166 state = (FxRequestCompletionState) m_CompletionState;
1167 m_CompletionState = FxRequestCompletionStateNone;
1168
1169 //
1170 // Technically we did not complete the irp, but a send and forget is
1171 // functionally the same. We no longer own the irp.
1172 //
1173 if (IsReserved() == FALSE) {
1174 PostProcessCompletion(state, pQueue);
1175 }
1176 else {
1177 //
1178 // Release checks m_Completed flag to decide whether to return
1179 // the request to reserved pool.
1180 //
1181 m_Completed = TRUE;
1182 PostProcessCompletionForReserved(state, pQueue);
1183 }
1184 }
1185
1186 NTSTATUS
GetStatus(VOID)1187 FxRequest::GetStatus(
1188 VOID
1189 )
1190 {
1191 PFX_DRIVER_GLOBALS pFxDriverGlobals;
1192 NTSTATUS status;
1193
1194 pFxDriverGlobals = GetDriverGlobals();
1195
1196 if (pFxDriverGlobals->FxVerifierIO) {
1197 KIRQL irql;
1198
1199 Lock(&irql);
1200
1201
1202
1203
1204
1205
1206
1207
1208 status = m_Irp.GetStatus();
1209
1210 Unlock(irql);
1211
1212 return status;
1213 }
1214 else {
1215 return m_Irp.GetStatus();
1216 }
1217 }
1218
1219 _Must_inspect_result_
1220 NTSTATUS
GetParameters(__out PWDF_REQUEST_PARAMETERS Parameters)1221 FxRequest::GetParameters(
1222 __out PWDF_REQUEST_PARAMETERS Parameters
1223 )
1224 {
1225 PFX_DRIVER_GLOBALS pFxDriverGlobals;
1226
1227 pFxDriverGlobals = GetDriverGlobals();
1228
1229 //
1230 // No lock needed. Only reason this may be invalid is due
1231 // to previous completion, which is a serious driver bug
1232 // that will result in a crash anyway.
1233 //
1234
1235 if (pFxDriverGlobals->FxVerifierIO) {
1236 KIRQL irql;
1237 NTSTATUS status;
1238
1239 Lock(&irql);
1240
1241 status = VerifyRequestIsCurrentStackValid(pFxDriverGlobals);
1242 if (NT_SUCCESS(status)) {
1243 status = VerifyRequestIsNotCompleted(pFxDriverGlobals);
1244 }
1245
1246 Unlock(irql);
1247
1248 if (!NT_SUCCESS(status)) {
1249 return status;
1250 }
1251 }
1252
1253 ASSERT(Parameters->Size >= sizeof(WDF_REQUEST_PARAMETERS));
1254
1255 // How much we copied
1256 Parameters->Size = sizeof(WDF_REQUEST_PARAMETERS);
1257
1258
1259 // Copy parameters
1260 Parameters->Type = (WDF_REQUEST_TYPE)m_Irp.GetMajorFunction();
1261 Parameters->MinorFunction = m_Irp.GetMinorFunction();
1262
1263 // Copy the Parameters structure which we are a subset of
1264 m_Irp.CopyParameters(Parameters);
1265
1266 if (pFxDriverGlobals->FxVerifierIO) {
1267 //
1268 // If verifier is on, and the operation is an IRP_MJ_DEVICE_CONTROL
1269 // with METHOD_NEITHER, then set Type3InputBuffer to zero since
1270 // this should not be used to pass parameters in the normal path
1271 //
1272 if((m_Irp.GetMajorFunction() == IRP_MJ_DEVICE_CONTROL) &&
1273 m_Irp.GetParameterIoctlCodeBufferMethod() == METHOD_NEITHER) {
1274 Parameters->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
1275 }
1276 }
1277
1278 return STATUS_SUCCESS;
1279 }
1280
1281
1282 _Must_inspect_result_
1283 NTSTATUS
GetMemoryObject(__deref_out IFxMemory ** MemoryObject,__out PVOID * Buffer,__out size_t * Length)1284 FxRequest::GetMemoryObject(
1285 __deref_out IFxMemory** MemoryObject,
1286 __out PVOID* Buffer,
1287 __out size_t* Length
1288 )
1289 {
1290 PMDL pMdl;
1291 NTSTATUS status;
1292 ULONG length;
1293 KIRQL irql;
1294 BOOLEAN mapMdl;
1295 UCHAR majorFunction;
1296
1297 status = STATUS_SUCCESS;
1298 length = 0x0;
1299 mapMdl = FALSE;
1300 irql = PASSIVE_LEVEL;
1301 majorFunction = m_Irp.GetMajorFunction();
1302
1303
1304 //
1305 // Verifier
1306 //
1307 if (GetDriverGlobals()->FxVerifierIO) {
1308 status = VerifyRequestIsNotCompleted(GetDriverGlobals());
1309 if (!NT_SUCCESS(status)) {
1310 goto Done;
1311 }
1312 if (m_Irp.GetRequestorMode() == UserMode
1313 &&
1314 (majorFunction == IRP_MJ_WRITE ||
1315 majorFunction == IRP_MJ_READ)
1316 &&
1317 GetDevice()->GetIoType() == WdfDeviceIoNeither) {
1318 status = STATUS_INVALID_DEVICE_REQUEST;
1319
1320 DoTraceLevelMessage(
1321 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1322 "Attempt to get UserMode Buffer Pointer for WDFDEVICE 0x%p, "
1323 "WDFREQUEST 0x%p, %!STATUS!",
1324 GetDevice()->GetHandle(), GetHandle(), status);
1325
1326 DoTraceLevelMessage(
1327 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1328 "Driver must use buffered or direct I/O for this call, or use "
1329 "WdfDeviceInitSetIoInCallerContextCallback to probe and lock "
1330 "user mode memory");
1331
1332 FxVerifierDbgBreakPoint(GetDriverGlobals());
1333 }
1334 }
1335
1336 if ((m_RequestBaseStaticFlags & FxRequestBaseStaticSystemBufferValid) == 0x00) {
1337 Lock(&irql);
1338 }
1339
1340 //
1341 // We must dig into the IRP to get the buffer, length, and readonly status
1342 //
1343
1344 switch (majorFunction) {
1345 case IRP_MJ_DEVICE_CONTROL:
1346 case IRP_MJ_INTERNAL_DEVICE_CONTROL:
1347 length = m_Irp.GetParameterIoctlInputBufferLength();
1348
1349 if (length == 0) {
1350 status = STATUS_BUFFER_TOO_SMALL;
1351
1352 DoTraceLevelMessage(
1353 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1354 "WDFREQUEST %p InputBufferLength length is zero, %!STATUS!",
1355 GetObjectHandle(), status);
1356
1357 goto Done;
1358 }
1359
1360 if (m_Irp.GetParameterIoctlCodeBufferMethod() == METHOD_NEITHER) {
1361 //
1362 // Internal device controls are kernel mode to kernel mode, and deal
1363 // with direct unmapped pointers.
1364 //
1365 // In addition, a normal device control with
1366 // RequestorMode == KernelMode is also treated as kernel mode
1367 // to kernel mode since the I/O Manager will not generate requests
1368 // with this setting from a user mode request.
1369 //
1370 if ((m_Irp.GetRequestorMode() == KernelMode) ||
1371 (majorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)) {
1372 DO_NOTHING();
1373 }
1374 else {
1375 status = STATUS_INVALID_DEVICE_REQUEST;
1376
1377 DoTraceLevelMessage(
1378 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1379 "Attempt to get UserMode Buffer Pointer for METHOD_NEITHER "
1380 "DeviceControl 0x%x, WDFDEVICE 0x%p, WDFREQUEST 0x%p, "
1381 "%!STATUS!",
1382 m_Irp.GetParameterIoctlCode(),
1383 GetDevice()->GetHandle(), GetHandle(), status);
1384
1385 DoTraceLevelMessage(
1386 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1387 "Driver must use METHOD_BUFFERED or METHOD_xx_DIRECT I/O for "
1388 "this call, or use WdfDeviceInitSetIoInCallerContextCallback to "
1389 "probe and lock user mode memory %!STATUS!",
1390 STATUS_INVALID_DEVICE_REQUEST);
1391
1392 goto Done;
1393 }
1394 }
1395 break;
1396
1397 case IRP_MJ_READ:
1398 length = m_Irp.GetParameterReadLength();
1399
1400 if (GetDevice()->GetIoTypeForReadWriteBufferAccess() == WdfDeviceIoDirect) {
1401 KMDF_ONLY_CODE_PATH_ASSERT();
1402 mapMdl = TRUE;
1403 }
1404 break;
1405
1406 case IRP_MJ_WRITE:
1407 length = m_Irp.GetParameterWriteLength();
1408
1409 if (GetDevice()->GetIoTypeForReadWriteBufferAccess() == WdfDeviceIoDirect) {
1410 KMDF_ONLY_CODE_PATH_ASSERT();
1411 mapMdl = TRUE;
1412 }
1413 break;
1414
1415 default:
1416 DoTraceLevelMessage(
1417 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1418 "Unrecognized Major Function 0x%x on WDFDEVICE 0x%p WDFREQUEST 0x%p",
1419 majorFunction, GetDevice()->GetHandle(), GetHandle());
1420
1421 FxVerifierDbgBreakPoint(GetDriverGlobals());
1422
1423 status = STATUS_INVALID_DEVICE_REQUEST;
1424 goto Done;
1425 }
1426
1427 if (length == 0) {
1428 status = STATUS_BUFFER_TOO_SMALL;
1429
1430 DoTraceLevelMessage(
1431 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1432 "WDFREQUEST 0x%p length is zero, %!STATUS!",
1433 GetHandle(), status);
1434
1435 goto Done;
1436 }
1437
1438 //
1439 // See if we need to map
1440 //
1441 if (mapMdl && (m_RequestBaseFlags & FxRequestBaseSystemMdlMapped) == 0x00) {
1442 pMdl = m_Irp.GetMdl();
1443
1444 if (pMdl == NULL) {
1445 //
1446 // Zero length transfer
1447 //
1448 status = STATUS_BUFFER_TOO_SMALL;
1449
1450 DoTraceLevelMessage(
1451 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1452 "WDFREQUEST 0x%p, direct io device, PMDL is NULL, "
1453 "%!STATUS!", GetHandle(), status);
1454
1455 ASSERT(length == 0);
1456 }
1457 else {
1458 PVOID pVA;
1459
1460 //
1461 // PagePriority may need to be a property, and/or parameter to
1462 // this call
1463 //
1464 //
1465 // Upon success, MmGetSystemAddressForMdlSafe stores the mapped
1466 // VA pointer in the pMdl and upon subsequent calls to
1467 // MmGetSystemAddressForMdlSafe, no mapping is done, just
1468 // the stored VA is returned. FxRequestSystemBuffer relies
1469 // on this behavior and, more importantly, relies on this function
1470 // to do the initial mapping so that FxRequestSystemBuffer::GetBuffer()
1471 // will not return a NULL pointer.
1472 //
1473 pVA = Mx::MxGetSystemAddressForMdlSafe(pMdl, NormalPagePriority);
1474
1475 if (pVA == NULL) {
1476 status = STATUS_INSUFFICIENT_RESOURCES;
1477
1478 DoTraceLevelMessage(
1479 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1480 "WDFREQUEST 0x%p could not get a system address for PMDL "
1481 "0x%p, %!STATUS!", GetHandle(), pMdl, status);
1482 }
1483 else {
1484 //
1485 // System will automatically release the mapping PTE's when
1486 // the MDL is released by the I/O request
1487 //
1488
1489
1490
1491
1492
1493 m_SystemBuffer.SetMdl(m_Irp.GetMdl());
1494
1495 m_RequestBaseFlags |= FxRequestBaseSystemMdlMapped;
1496 }
1497 }
1498 }
1499
1500 Done:
1501 if ((m_RequestBaseStaticFlags & FxRequestBaseStaticSystemBufferValid) == 0x00) {
1502 Unlock(irql);
1503 }
1504
1505 if (NT_SUCCESS(status)) {
1506 *MemoryObject = &m_SystemBuffer;
1507
1508 if (mapMdl) {
1509 *Buffer = Mx::MxGetSystemAddressForMdlSafe(m_SystemBuffer.m_Mdl,
1510 NormalPagePriority);
1511 }
1512 else {
1513 *Buffer = m_SystemBuffer.m_Buffer;
1514 }
1515
1516 *Length = length;
1517 }
1518
1519 return status;
1520 }
1521
1522 _Must_inspect_result_
1523 NTSTATUS
GetDeviceControlOutputMemoryObject(__deref_out IFxMemory ** MemoryObject,__out PVOID * Buffer,__out size_t * Length)1524 FxRequest::GetDeviceControlOutputMemoryObject(
1525 __deref_out IFxMemory** MemoryObject,
1526 __out PVOID* Buffer,
1527 __out size_t* Length
1528 )
1529 /*++
1530
1531 Routine Description:
1532
1533 Return the IRP_MJ_DEVICE_CONTROL OutputBuffer.
1534
1535 The memory buffer is valid in any thread/process context,
1536 and may be accessed at IRQL > PASSIVE_LEVEL.
1537
1538 The memory buffer is automatically released when the request
1539 is completed.
1540
1541 The memory buffer is not valid for a METHOD_NEITHER IRP_MJ_DEVICE_CONTROL,
1542 or for any request other than IRP_MJ_DEVICE_CONTROL.
1543
1544 The Memory buffer is as follows for each buffering mode:
1545
1546 METHOD_BUFFERED:
1547
1548 Irp->UserBuffer // This is actually a system address
1549
1550 METHOD_IN_DIRECT:
1551
1552 MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority)
1553
1554 METHOD_OUT_DIRECT:
1555
1556 MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority)
1557
1558 METHOD_NEITHER:
1559
1560 NULL. Must use WdfDeviceInitSetIoInCallerContextCallback in order
1561 to access the request in the calling threads address space before
1562 it is placed into any I/O Queues.
1563
1564 The buffer is only valid until the request is completed.
1565
1566 Arguments:
1567
1568 MemoryObject - Pointer location to return the memory object interface.
1569
1570 Buffer - Pointer location to return buffer ptr
1571
1572 Length - Pointer location to return buffer length.
1573
1574 Returns:
1575
1576 NTSTATUS
1577
1578 --*/
1579 {
1580 size_t length;
1581 NTSTATUS status;
1582 KIRQL irql;
1583 BOOLEAN mapMdl;
1584 UCHAR majorFunction;
1585
1586 UNREFERENCED_PARAMETER(Buffer);
1587 UNREFERENCED_PARAMETER(Length);
1588
1589 status = STATUS_SUCCESS;
1590 length = 0;
1591 irql = PASSIVE_LEVEL;
1592 mapMdl = FALSE;
1593
1594 //
1595 // Verifier
1596 //
1597 if (GetDriverGlobals()->FxVerifierIO ) {
1598 status = VerifyRequestIsNotCompleted(GetDriverGlobals());
1599 if (!NT_SUCCESS(status)) {
1600 return status;
1601 }
1602 }
1603
1604 if ((m_RequestBaseStaticFlags & FxRequestBaseStaticOutputBufferValid) == 0x00) {
1605 Lock(&irql);
1606 }
1607
1608 //
1609 // See if we already have a validated buffer
1610 //
1611 //if (m_RequestBaseFlags & FxRequestBaseOutputBufferValid) {
1612 // status = STATUS_SUCCESS;
1613 //}
1614
1615 majorFunction = m_Irp.GetMajorFunction();
1616
1617 ASSERT(majorFunction == IRP_MJ_DEVICE_CONTROL ||
1618 majorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL);
1619
1620 length = m_Irp.GetParameterIoctlOutputBufferLength();
1621
1622 if (length == 0) {
1623 status = STATUS_BUFFER_TOO_SMALL;
1624
1625 DoTraceLevelMessage(
1626 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1627 "WDFREQUEST 0x%p IOCTL output buffer length is zero, %!STATUS!",
1628 GetHandle(), status);
1629
1630 goto Done;
1631 }
1632
1633 switch (m_Irp.GetParameterIoctlCodeBufferMethod()) {
1634 //
1635 // InputBuffer is in SystemBuffer
1636 // OutputBuffer is in MdlAddress with read access
1637 //
1638 case METHOD_IN_DIRECT:
1639 // || || fall || ||
1640 // \/ \/ through \/ \/
1641
1642 //
1643 // InputBuffer is in SystemBuffer
1644 // OutputBuffer is in MdlAddress with read access
1645 //
1646 case METHOD_OUT_DIRECT:
1647 mapMdl = TRUE;
1648 break;
1649
1650 case METHOD_NEITHER:
1651 //
1652 // Internal device controls are kernel mode to kernel mode, and deal
1653 // with direct unmapped pointers.
1654 //
1655 // In addition, a normal device control with
1656 // RequestorMode == KernelMode is also treated as kernel mode
1657 // to kernel mode since the I/O Manager will not generate requests
1658 // with this setting from a user mode request.
1659 //
1660 if ((m_Irp.GetRequestorMode() == KernelMode) ||
1661 (majorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)) {
1662 DO_NOTHING();
1663 }
1664 else {
1665 status = STATUS_INVALID_DEVICE_REQUEST;
1666
1667 DoTraceLevelMessage(
1668 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1669 "Attempt to get UserMode Buffer Pointer for "
1670 "METHOD_NEITHER DeviceControl 0x%x, WDFDEVICE 0x%p, "
1671 "WDFREQUEST 0x%p, %!STATUS!",
1672 m_Irp.GetParameterIoctlCode(),
1673 GetDevice()->GetHandle(), GetObjectHandle(), status);
1674
1675 DoTraceLevelMessage(
1676 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1677 "Driver must use METHOD_BUFFERED or METHOD_xx_DIRECT "
1678 "I/O for this call, or use "
1679 "WdfDeviceInitSetIoInCallerContextCallback to probe and "
1680 "lock user mode memory");
1681 }
1682 break;
1683 }
1684
1685 if (mapMdl && (m_RequestBaseFlags & FxRequestBaseOutputMdlMapped) == 0x0) {
1686 PMDL pMdl;
1687 PVOID pVA;
1688
1689
1690 pMdl = m_Irp.GetMdl();
1691
1692 if (pMdl == NULL) {
1693 //
1694 // Zero length transfer
1695 //
1696 status = STATUS_BUFFER_TOO_SMALL;
1697
1698 DoTraceLevelMessage(
1699 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1700 "WDFREQUEST 0x%p, METHOD_IN_DIRECT IOCTL PMDL is NULL, "
1701 "%!STATUS!", GetHandle(), status);
1702
1703 ASSERT(
1704 m_Irp.GetParameterIoctlOutputBufferLength()== 0
1705 );
1706 }
1707 else {
1708 //
1709 // PagePriority may need to be a property, and/or parameter to
1710 // this call
1711 //
1712 //
1713 // Upon success, MmGetSystemAddressForMdlSafe stores the mapped
1714 // VA pointer in the pMdl and upon subsequent calls to
1715 // MmGetSystemAddressForMdlSafe, no mapping is done, just
1716 // the stored VA is returned. FxRequestOutputBuffer relies
1717 // on this behavior and, more importantly, relies on this function
1718 // to do the initial mapping so that FxRequestOutputBuffer::GetBuffer()
1719 // will not return a NULL pointer.
1720 //
1721 pVA = Mx::MxGetSystemAddressForMdlSafe(pMdl, NormalPagePriority);
1722
1723 if (pVA == NULL) {
1724 status = STATUS_INSUFFICIENT_RESOURCES;
1725
1726 DoTraceLevelMessage(
1727 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1728 "WDFREQUEST 0x%p could not get a system address for PMDL"
1729 "0x%p, %!STATUS!", GetHandle(), pMdl, status);
1730 }
1731 else {
1732 m_OutputBuffer.SetMdl(pMdl);
1733 m_RequestBaseFlags |= FxRequestBaseOutputMdlMapped;
1734 status = STATUS_SUCCESS;
1735 }
1736 }
1737 }
1738
1739 Done:
1740 if ((m_RequestBaseStaticFlags & FxRequestBaseStaticOutputBufferValid) == 0x00) {
1741 Unlock(irql);
1742 }
1743
1744 if (NT_SUCCESS(status)) {
1745 *MemoryObject = &m_OutputBuffer;
1746 if (mapMdl) {
1747 *Buffer = Mx::MxGetSystemAddressForMdlSafe(m_OutputBuffer.m_Mdl,
1748 NormalPagePriority);
1749 }
1750 else {
1751 *Buffer = m_OutputBuffer.m_Buffer;
1752 }
1753 *Length = length;
1754 }
1755
1756 return status;
1757 }
1758
1759 FxRequestCompletionState
SetCompletionState(__in FxRequestCompletionState NewState)1760 FxRequest::SetCompletionState(
1761 __in FxRequestCompletionState NewState
1762 )
1763 {
1764 FxRequestCompletionState oldState;
1765
1766 //
1767 // The flag by itself should never be specified
1768 //
1769 ASSERT(NewState != FxRequestCompletionStateIoPkgFlag);
1770
1771 //
1772 // No need to lock. Only the "owner" can set the completion
1773 // callback function, and this is when under the general
1774 // FxIoQueue lock.
1775 //
1776
1777 // Request is already completed, awaiting final dereference
1778 if (m_Completed) {
1779 oldState = FxRequestCompletionStateNone;
1780 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1781 "WDFREQUEST 0x%p has already been completed",
1782 GetHandle());
1783 FxVerifierDbgBreakPoint(GetDriverGlobals());
1784 }
1785 else {
1786 ASSERT(m_Irp.GetIrp() != NULL);
1787
1788 oldState = (FxRequestCompletionState) m_CompletionState;
1789
1790 m_CompletionState = (BYTE) NewState;
1791
1792 if (NewState == FxRequestCompletionStateNone &&
1793 oldState != FxRequestCompletionStateNone) {
1794 //
1795 // Cancelling a callback, so release the callback reference
1796 //
1797 RELEASE(FXREQUEST_STATE_TAG);
1798 }
1799 else if (NewState != FxRequestCompletionStateNone &&
1800 oldState == FxRequestCompletionStateNone) {
1801 //
1802 // Adding a callback requires a reference
1803 //
1804 ADDREF(FXREQUEST_STATE_TAG);
1805 }
1806 else {
1807 //
1808 // else we leave the current reference alone
1809 //
1810 DO_NOTHING();
1811 }
1812 }
1813
1814 return oldState;
1815 }
1816
1817 _Must_inspect_result_
1818 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyInsertIrpQueue)1819 FX_VF_METHOD(FxRequest, VerifyInsertIrpQueue) (
1820 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
1821 _In_ FxIrpQueue* IrpQueue
1822 )
1823 {
1824 NTSTATUS status;
1825
1826 PAGED_CODE_LOCKED();
1827
1828 //
1829 // Check to make sure we are not already in an Irp queue
1830 //
1831 if (m_IrpQueue != NULL) {
1832 status = STATUS_INTERNAL_ERROR;
1833
1834 DoTraceLevelMessage(
1835 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
1836 "Already in FxIrpQueue 0x%p WDFREQUEST 0x%p %!STATUS!",
1837 IrpQueue, GetHandle(), status);
1838
1839 FxVerifierDbgBreakPoint(FxDriverGlobals);
1840
1841 goto Done;
1842 }
1843
1844 //
1845 // If request is completed, fail.
1846 // This is because the driver can complete the request
1847 // right away in another thread while returning STATUS_PENDING
1848 // from EvtIoDefault
1849 //
1850 status = VerifyRequestIsNotCompleted(FxDriverGlobals);
1851
1852 Done:
1853 return status;
1854 }
1855
1856 _Must_inspect_result_
1857 NTSTATUS
InsertTailIrpQueue(__in FxIrpQueue * IrpQueue,__out_opt ULONG * pRequestCount)1858 FxRequest::InsertTailIrpQueue(
1859 __in FxIrpQueue* IrpQueue,
1860 __out_opt ULONG* pRequestCount
1861 )
1862 {
1863 PFX_DRIVER_GLOBALS pFxDriverGlobals;
1864 NTSTATUS status;
1865
1866 pFxDriverGlobals = GetDriverGlobals();
1867
1868 // No locking required since only one accessor till inserted on queue
1869
1870 status = VerifyInsertIrpQueue(pFxDriverGlobals, IrpQueue);
1871 if (!NT_SUCCESS(status)) {
1872 return status;
1873 }
1874
1875 //
1876 // If a request is on an IrpQueue, it must be referenced
1877 //
1878
1879
1880
1881
1882
1883
1884 ADDREF(FXREQUEST_QUEUE_TAG);
1885
1886 ASSERT(m_Completed == FALSE);
1887 ASSERT(m_IrpQueue == NULL);
1888
1889 m_IrpQueue = IrpQueue;
1890
1891 status = IrpQueue->InsertTailRequest(m_Irp.GetIrp(),
1892 &m_CsqContext,
1893 pRequestCount);
1894
1895 //
1896 // If this insert failed, we must release the extra reference we took
1897 //
1898 if (!NT_SUCCESS(status)) {
1899 MarkRemovedFromIrpQueue();
1900 RELEASE(FXREQUEST_QUEUE_TAG);
1901 }
1902
1903 return status;
1904 }
1905
1906 _Must_inspect_result_
1907 NTSTATUS
InsertHeadIrpQueue(__in FxIrpQueue * IrpQueue,__out_opt ULONG * pRequestCount)1908 FxRequest::InsertHeadIrpQueue(
1909 __in FxIrpQueue* IrpQueue,
1910 __out_opt ULONG* pRequestCount
1911 )
1912 {
1913 PFX_DRIVER_GLOBALS pFxDriverGlobals;
1914 NTSTATUS status;
1915
1916 pFxDriverGlobals = GetDriverGlobals();
1917
1918 // No locking required since only one accessor till inserted on queue
1919
1920 status = VerifyInsertIrpQueue(pFxDriverGlobals, IrpQueue);
1921 if (!NT_SUCCESS(status)) {
1922 return status;
1923 }
1924
1925 //
1926 // If a request is on an IrpQueue, it must be referenced
1927 //
1928
1929
1930
1931
1932
1933
1934 ADDREF(FXREQUEST_QUEUE_TAG);
1935
1936 ASSERT(m_Completed == FALSE);
1937 ASSERT(m_IrpQueue == NULL);
1938
1939 m_IrpQueue = IrpQueue;
1940
1941 status = IrpQueue->InsertHeadRequest(m_Irp.GetIrp(),
1942 &m_CsqContext,
1943 pRequestCount);
1944
1945 //
1946 // If this insert failed, we must release the extra reference we took
1947 //
1948 if (!NT_SUCCESS(status)) {
1949 MarkRemovedFromIrpQueue();
1950 RELEASE(FXREQUEST_QUEUE_TAG);
1951 }
1952
1953 return status;
1954 }
1955
1956 //
1957 // Remove request from its IRP queue
1958 //
1959 _Must_inspect_result_
1960 NTSTATUS
RemoveFromIrpQueue(__in FxIrpQueue * IrpQueue)1961 FxRequest::RemoveFromIrpQueue(
1962 __in FxIrpQueue* IrpQueue
1963 )
1964 {
1965 PFX_DRIVER_GLOBALS pFxDriverGlobals;
1966 MdIrp pIrp;
1967
1968 pFxDriverGlobals = GetDriverGlobals();
1969
1970 //
1971 // Cancel Safe Queues allow this request
1972 // removal to be race free even if the
1973 // request has been cancelled already.
1974 //
1975 // It signals this by returning NULL for
1976 // the Irp.
1977 //
1978 pIrp = IrpQueue->RemoveRequest(&m_CsqContext);
1979
1980 if (pIrp == NULL) {
1981
1982 //
1983 // Cancel routine removed it from the cancel
1984 // safe queue.
1985 //
1986 // The cancel handler will remove this reference
1987 // in FxIoQueue::_IrpCancelForDriver /
1988 // FxIrpQueue::_WdmCancelRoutineInternal
1989 //
1990
1991 return STATUS_CANCELLED;
1992 }
1993 else {
1994
1995 //
1996 // We retrieved the Irp from the cancel safe queue
1997 // without it having been cancelled first.
1998 //
1999 // It is no longer cancelable
2000 //
2001 if (pFxDriverGlobals->FxVerifierOn) {
2002 if (m_IrpQueue == NULL) {
2003 DoTraceLevelMessage(
2004 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2005 "WDFREQUEST 0x%p not on IrpQueue",
2006 GetHandle());
2007
2008 FxVerifierDbgBreakPoint(pFxDriverGlobals);
2009 }
2010 }
2011
2012 MarkRemovedFromIrpQueue();
2013
2014 RELEASE(FXREQUEST_QUEUE_TAG);
2015
2016 return STATUS_SUCCESS;
2017 }
2018 }
2019
2020 //
2021 // Function to return the next FxRequest from an FxIrpQueue
2022 //
2023 _Must_inspect_result_
2024 FxRequest*
GetNextRequest(__in FxIrpQueue * IrpQueue)2025 FxRequest::GetNextRequest(
2026 __in FxIrpQueue* IrpQueue
2027 )
2028 {
2029 MdIrp pIrp;
2030 FxRequest* pRequest;
2031 PMdIoCsqIrpContext pCsqContext;
2032
2033 pIrp = IrpQueue->GetNextRequest(&pCsqContext);
2034
2035 if (pIrp == NULL) {
2036 return NULL;
2037 }
2038
2039 // Irp is not cancellable now
2040 pRequest = FxRequest::RetrieveFromCsqContext(pCsqContext);
2041
2042 // Must tell the request it's off the queue
2043 pRequest->MarkRemovedFromIrpQueue();
2044
2045 // Remove reference placed when on IrpQueue
2046 pRequest->RELEASE(FXREQUEST_QUEUE_TAG);
2047
2048 return pRequest;
2049 }
2050
2051 //
2052 // Function to return an FxRequest from an FxIrpQueue based
2053 // on optional context and/or file object.
2054 //
2055 _Must_inspect_result_
2056 NTSTATUS
GetNextRequest(__in FxIrpQueue * IrpQueue,__in_opt MdFileObject FileObject,__in_opt FxRequest * TagRequest,__deref_out FxRequest ** ppOutRequest)2057 FxRequest::GetNextRequest(
2058 __in FxIrpQueue* IrpQueue,
2059 __in_opt MdFileObject FileObject,
2060 __in_opt FxRequest* TagRequest,
2061 __deref_out FxRequest** ppOutRequest
2062 )
2063 {
2064 NTSTATUS Status;
2065 FxRequest* pRequest;
2066 PMdIoCsqIrpContext TagCsqContext;
2067
2068 if( TagRequest != NULL ) {
2069 TagCsqContext = TagRequest->GetCsqContext();
2070 }
2071 else {
2072 TagCsqContext = NULL;
2073 }
2074
2075 Status = IrpQueue->GetNextRequest( TagCsqContext, FileObject, &pRequest );
2076 if( !NT_SUCCESS(Status) ) {
2077 return Status;
2078 }
2079
2080 // Irp is not cancellable now
2081
2082 // Must tell the request its off the queue
2083 pRequest->MarkRemovedFromIrpQueue();
2084
2085 // Remove reference placed when on IrpQueue
2086 pRequest->RELEASE(FXREQUEST_QUEUE_TAG);
2087
2088 *ppOutRequest = pRequest;
2089
2090 return STATUS_SUCCESS;
2091 }
2092
2093 //
2094 // Allow peeking at requests in the IrpQueue
2095 //
2096 _Must_inspect_result_
2097 NTSTATUS
PeekRequest(__in FxIrpQueue * IrpQueue,__in_opt FxRequest * TagRequest,__in_opt MdFileObject FileObject,__out_opt PWDF_REQUEST_PARAMETERS Parameters,__deref_out FxRequest ** ppOutRequest)2098 FxRequest::PeekRequest(
2099 __in FxIrpQueue* IrpQueue,
2100 __in_opt FxRequest* TagRequest,
2101 __in_opt MdFileObject FileObject,
2102 __out_opt PWDF_REQUEST_PARAMETERS Parameters,
2103 __deref_out FxRequest** ppOutRequest
2104 )
2105 {
2106 NTSTATUS Status;
2107
2108 PMdIoCsqIrpContext TagContext = NULL;
2109
2110 //
2111 // IrpQueue::PeekRequest works with CSQ_CONTEXT
2112 // structures since this is the only value that
2113 // is valid across cancellation.
2114 //
2115 if( TagRequest != NULL ) {
2116 TagContext = TagRequest->GetCsqContext();
2117 }
2118
2119 Status = IrpQueue->PeekRequest(
2120 TagContext,
2121 FileObject,
2122 ppOutRequest
2123 );
2124 if(NT_SUCCESS(Status)) {
2125
2126 if( Parameters != NULL ) {
2127 Status = (*ppOutRequest)->GetParameters(Parameters);
2128 }
2129 }
2130
2131 return Status;
2132 }
2133
2134 _Must_inspect_result_
2135 NTSTATUS
Reuse(__in PWDF_REQUEST_REUSE_PARAMS ReuseParams)2136 FxRequest::Reuse(
2137 __in PWDF_REQUEST_REUSE_PARAMS ReuseParams
2138 )
2139 {
2140 FxIrp currentIrp;
2141 PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals();
2142
2143 //
2144 // Make sure request is not pended in IoTarget.
2145 //
2146 if (pFxDriverGlobals->IsVerificationEnabled(1, 9, OkForDownLevel)) {
2147 SHORT flags;
2148 KIRQL irql;
2149
2150 Lock(&irql);
2151 flags = GetVerifierFlagsLocked();
2152 if (flags & FXREQUEST_FLAG_SENT_TO_TARGET) {
2153 DoTraceLevelMessage(
2154 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2155 "Driver is trying to reuse WDFREQUEST 0x%p while it is still "
2156 "active on WDFIOTARGET 0x%p. ",
2157 GetTraceObjectHandle(), GetTarget()->GetHandle());
2158 FxVerifierDbgBreakPoint(pFxDriverGlobals);
2159 }
2160 Unlock(irql);
2161 }
2162
2163 //
2164 // For drivers 1.9 and above (for maintaining backwards compatibility)
2165 // deregister previously registered completion routine.
2166 //
2167 if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,9)) {
2168 SetCompletionRoutine(NULL, NULL);
2169 }
2170
2171 currentIrp.SetIrp(m_Irp.GetIrp());
2172
2173 if (currentIrp.GetIrp() != NULL) {
2174 //
2175 // Release all outstanding references and restore original fields in
2176 // the PIRP
2177 //
2178 if (m_RequestContext != NULL) {
2179 m_RequestContext->ReleaseAndRestore(this);
2180 }
2181
2182 if (m_IrpAllocation == REQUEST_ALLOCATED_FROM_IO) {
2183 //
2184 // An irp presented by io queue can only reset a limited state
2185 //
2186 if (ReuseParams->Flags & WDF_REQUEST_REUSE_SET_NEW_IRP) {
2187 //
2188 // Not allowed to set a new irp
2189 //
2190 return STATUS_WDF_REQUEST_INVALID_STATE;
2191 }
2192
2193 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
2194 currentIrp.SetStatus(ReuseParams->Status);
2195 currentIrp.SetCancel(FALSE);
2196 #else
2197 //
2198 // For UMDF, host sets cancel flag to false as part of Reuse(), so no
2199 // need to have a separate call for UMDF (that's why host irp doesn't
2200 // expose any interface to set this independently).
2201
2202
2203
2204
2205 //
2206 currentIrp.Reuse(ReuseParams->Status);
2207 #endif
2208 m_Completed = FALSE;
2209 m_Canceled = FALSE;
2210
2211 return STATUS_SUCCESS;
2212 }
2213 else if (m_IrpAllocation == REQUEST_ALLOCATED_DRIVER) {
2214 //
2215 // Release outstanding reference on a must complete driver request.
2216 //
2217 if (m_CanComplete && m_Completed == FALSE) {
2218 ASSERT(GetRefCnt() >= 2);
2219
2220 if (pFxDriverGlobals->FxVerifierOn) {
2221 ClearVerifierFlags(FXREQUEST_FLAG_DRIVER_OWNED);
2222 }
2223
2224 RELEASE(FXREQUEST_DCRC_TAG);
2225 }
2226 }
2227 }
2228 else {
2229 //
2230 // We should not have a m_RequestContext with anything to ReleaseAndRestore
2231 // because there is no IRP to have anything formatted off of.
2232 //
2233 DO_NOTHING();
2234 }
2235
2236 //
2237 // This cannot be a request on a queue
2238 //
2239 ASSERT(m_CompletionState == FxRequestCompletionStateNone &&
2240 m_IoQueue == NULL);
2241
2242 if (ReuseParams->Flags & WDF_REQUEST_REUSE_SET_NEW_IRP) {
2243 currentIrp.SetIrp((MdIrp)ReuseParams->NewIrp);
2244
2245 //
2246 // If we are replacing an internal irp, we must free it later.
2247 //
2248 if (m_IrpAllocation == REQUEST_ALLOCATED_INTERNAL) {
2249 MdIrp pOldIrp;
2250
2251 ASSERT(m_CanComplete == FALSE);
2252 pOldIrp = m_Irp.SetIrp(currentIrp.GetIrp());
2253
2254 if (pOldIrp != NULL) {
2255 FxIrp oldIrp(pOldIrp);
2256 oldIrp.FreeIrp();
2257 }
2258 }
2259 else {
2260 (void) m_Irp.SetIrp(currentIrp.GetIrp());
2261 }
2262
2263 m_IrpAllocation = REQUEST_ALLOCATED_DRIVER;
2264 }
2265
2266 //
2267 // Only reinitialize an internal irp. If the irp is external, then its
2268 // still valid.
2269 //
2270 if (m_IrpAllocation == REQUEST_ALLOCATED_INTERNAL && currentIrp.GetIrp() != NULL) {
2271 ASSERT(m_CanComplete == FALSE);
2272 ASSERT(m_Completed == FALSE);
2273 currentIrp.Reuse(ReuseParams->Status);
2274
2275 //
2276 // For UMDF, host sets cancel flag to false as part of Reuse(), so no
2277 // need to have a separate call for UMDF (that's why host irp doesn't
2278 // expose any interface to set this independently).
2279
2280
2281
2282
2283 //
2284 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
2285 currentIrp.SetCancel(FALSE);
2286 #endif
2287 }
2288
2289 //
2290 // If necessary, reinit the request to support WdfRequestComplete.
2291 //
2292 if (ReuseParams->Flags & WDF_REQUEST_REUSE_MUST_COMPLETE) {
2293 NTSTATUS status;
2294
2295 //
2296 // WDF guarantees a successful return code when the driver calls Reuse() from its
2297 // completion routine with valid input.
2298 //
2299
2300 //
2301 // This feature can only be used from WDF v1.11 and above.
2302 //
2303 if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11) == FALSE) {
2304 status = STATUS_INVALID_DEVICE_REQUEST;
2305 DoTraceLevelMessage(
2306 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2307 "WDFREQUEST %p doesn't belong to any queue, %!STATUS!",
2308 GetTraceObjectHandle(), status);
2309 FxVerifierDbgBreakPoint(pFxDriverGlobals);
2310 return status;
2311 }
2312
2313 //
2314 // 'must_complete' flag requires an IRP.
2315 //
2316 if (currentIrp.GetIrp() == NULL) {
2317 status = STATUS_INVALID_PARAMETER;
2318 DoTraceLevelMessage(
2319 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2320 "Driver is trying to reuse WDFREQUEST 0x%p without "
2321 "specifying an IRP with "
2322 "WDF_REQUEST_REUSE_MUST_COMPLETE flag, %!STATUS!",
2323 GetTraceObjectHandle(), status);
2324 FxVerifierDbgBreakPoint(pFxDriverGlobals);
2325 return status;
2326 }
2327
2328 //
2329 // Do not support internal IRPs.
2330 //
2331 if (m_IrpAllocation == REQUEST_ALLOCATED_INTERNAL) {
2332 status = STATUS_INVALID_DEVICE_REQUEST;
2333 DoTraceLevelMessage(
2334 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2335 "Driver is trying to reuse WDFREQUEST 0x%p holding an"
2336 "internal allocated IRP with "
2337 "WDF_REQUEST_REUSE_MUST_COMPLETE flag, %!STATUS!",
2338 GetTraceObjectHandle(), status);
2339 FxVerifierDbgBreakPoint(pFxDriverGlobals);
2340 return status;
2341 }
2342
2343 //
2344 // Ref count must be 1.
2345 //
2346 if (GetRefCnt() != 1) {
2347 status = STATUS_INVALID_DEVICE_REQUEST;
2348 DoTraceLevelMessage(
2349 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2350 "Driver is trying to reuse WDFREQUEST 0x%p with "
2351 "WDF_REQUEST_REUSE_MUST_COMPLETE flag while request is "
2352 "being referenced, reference count:%d, %!STATUS!",
2353 GetTraceObjectHandle(), GetRefCnt(), status);
2354 FxVerifierDbgBreakPoint(pFxDriverGlobals);
2355 return status;
2356 }
2357
2358 //
2359 // Make sure current IRP stack location is valid.
2360 //
2361 if (currentIrp.IsCurrentIrpStackLocationValid() == FALSE) {
2362 status = STATUS_INVALID_DEVICE_REQUEST;
2363 DoTraceLevelMessage(
2364 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2365 "IRP %p of WDFREQUEST %p doesn't have a valid"
2366 " stack location, %!STATUS!",
2367 currentIrp.GetIrp(), GetHandle(), status);
2368 FxVerifierDbgBreakPoint(pFxDriverGlobals);
2369 return status;
2370 }
2371
2372 //
2373 // This ref is removed when:
2374 // (a) the request is completed or
2375 // (b) the request is reused and old request/IRP was never sent and completed.
2376 //
2377 ADDREF(FXREQUEST_DCRC_TAG);
2378
2379 //
2380 // Note: strange why ClearFieldsForReuse() is not used all the time... just in case,
2381 // keeping old logic for compatibility.
2382 //
2383 ClearFieldsForReuse();
2384 m_CanComplete = TRUE;
2385
2386 if (pFxDriverGlobals->FxVerifierOn) {
2387 SetVerifierFlags(FXREQUEST_FLAG_DRIVER_OWNED);
2388 }
2389 }
2390 else {
2391 m_CanComplete = FALSE;
2392 m_Completed = FALSE;
2393 m_Canceled = FALSE;
2394
2395 if (pFxDriverGlobals->FxVerifierOn) {
2396 ClearVerifierFlags(FXREQUEST_FLAG_DRIVER_OWNED);
2397 }
2398 }
2399
2400 return STATUS_SUCCESS;
2401 }
2402
2403 //
2404 // Return the FxFileObject if associated with this request
2405 //
2406 _Must_inspect_result_
2407 NTSTATUS
GetFileObject(__deref_out_opt FxFileObject ** FileObject)2408 FxRequest::GetFileObject(
2409 __deref_out_opt FxFileObject** FileObject
2410 )
2411 {
2412 NTSTATUS status;
2413 FxFileObject* pFileObject;
2414 CfxDevice* pDevice;
2415 PFX_DRIVER_GLOBALS pFxDriverGlobals;
2416
2417 pFileObject = NULL;
2418 pFxDriverGlobals = GetDriverGlobals();
2419
2420 pDevice = GetDevice();
2421
2422 if (pFxDriverGlobals->FxVerifierIO) {
2423 KIRQL irql;
2424 *FileObject = NULL;
2425
2426 Lock(&irql);
2427 status = VerifyRequestIsNotCompleted(pFxDriverGlobals);
2428
2429 Unlock(irql);
2430 if (!NT_SUCCESS(status)) {
2431 return status;
2432 }
2433
2434 }
2435
2436 if (NULL == m_Irp.GetFileObject() && IsAllocatedDriver()) {
2437 ASSERT(TRUE == m_CanComplete);
2438 //
2439 // This is a 'must_complete' driver created request.
2440 //
2441 *FileObject = NULL;
2442 return STATUS_SUCCESS;
2443 }
2444
2445 status = FxFileObject::_GetFileObjectFromWdm(
2446 pDevice,
2447 pDevice->GetFileObjectClass(),
2448 m_Irp.GetFileObject(),
2449 &pFileObject
2450 );
2451
2452 if (NT_SUCCESS(status) && pFileObject != NULL) {
2453 *FileObject = pFileObject;
2454 return STATUS_SUCCESS;
2455 }
2456 else if (NT_SUCCESS(status) &&
2457 FxIsFileObjectOptional(pDevice->GetFileObjectClass())) {
2458 //
2459 // Driver told us that it is ok for the file object to be NULL.
2460 //
2461 *FileObject = NULL;
2462 return STATUS_SUCCESS;
2463 }
2464 else {
2465 return STATUS_INVALID_DEVICE_REQUEST;
2466 }
2467 }
2468
2469 VOID
AddIrpReference(VOID)2470 FxRequest::AddIrpReference(
2471 VOID
2472 )
2473 /*++
2474
2475 Routine Description:
2476
2477 Adds a reference to the IRP contained in the request.
2478
2479 This is used to check that FxRequest::Complete is not
2480 called with outstanding references to any IRP related
2481 fields such as memory buffers.
2482
2483 Arguments:
2484
2485 None
2486
2487 Return Value:
2488
2489 None
2490
2491 --*/
2492 {
2493 PFX_DRIVER_GLOBALS pFxDriverGlobals;
2494 pFxDriverGlobals = GetDriverGlobals();
2495
2496 if (pFxDriverGlobals->FxVerifierOn) {
2497 KIRQL irql;
2498
2499 Lock(&irql);
2500
2501 (VOID)VerifyRequestIsNotCompleted(pFxDriverGlobals);
2502
2503 Unlock(irql);
2504 }
2505
2506 InterlockedIncrement(&m_IrpReferenceCount);
2507
2508 return;
2509 }
2510
2511 VOID
ReleaseIrpReference(VOID)2512 FxRequest::ReleaseIrpReference(
2513 VOID
2514 )
2515 /*++
2516
2517 Routine Description:
2518
2519 Release a reference to the IRP contained in the request.
2520
2521 Arguments:
2522
2523 None
2524
2525 Return Value:
2526
2527 None
2528
2529 --*/
2530 {
2531 LONG count;
2532
2533 count = InterlockedDecrement(&m_IrpReferenceCount);
2534
2535 if( count < 0 ) {
2536 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
2537 "Attempt to release an IRP reference without adding "
2538 "one first WDFREQUEST 0x%p",GetHandle());
2539 FxVerifierDbgBreakPoint(GetDriverGlobals());
2540 }
2541
2542 return;
2543 }
2544
2545 _Must_inspect_result_
2546 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyProbeAndLock)2547 FX_VF_METHOD(FxRequest, VerifyProbeAndLock) (
2548 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
2549 )
2550 {
2551 NTSTATUS status = STATUS_SUCCESS;
2552
2553 PAGED_CODE_LOCKED();
2554
2555 MdEThread thread = m_Irp.GetThread();
2556
2557 //
2558 // Some kernel mode drivers issue I/O without setting this
2559 //
2560 if (thread != NULL) {
2561 //
2562 // Currently DDK level headers don't let us reach into a threads
2563 // parent process, so we can't do the process level check, just
2564 // a thread level check.
2565 //
2566 if (m_Irp.GetRequestorMode() == UserMode && thread != Mx::GetCurrentEThread()) {
2567 status = STATUS_ACCESS_VIOLATION;
2568
2569 // Error, wrong process context...
2570 DoTraceLevelMessage(
2571 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2572 "Attempt to access user mode memory from the wrong process "
2573 "Irp->Tail.Overlay.Thread 0x%p, PsGetCurrentThread 0x%p, "
2574 "%!STATUS!", thread, Mx::GetCurrentEThread(), status);
2575
2576 return status;
2577 }
2578 }
2579 else {
2580 // Irp->Thread should be issued for all user mode requests
2581 ASSERT(m_Irp.GetRequestorMode() == KernelMode);
2582 }
2583
2584 return status;
2585 }
2586
2587 _Must_inspect_result_
2588 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyStopAcknowledge)2589 FX_VF_METHOD(FxRequest, VerifyStopAcknowledge) (
2590 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
2591 _In_ BOOLEAN Requeue
2592 )
2593 {
2594 NTSTATUS status;
2595 KIRQL irql;
2596
2597 PAGED_CODE_LOCKED();
2598
2599 Lock(&irql);
2600
2601 //
2602 // Make sure the driver is calling this function in the context
2603 // of EvtIoStop callback.
2604 //
2605 status = VerifyRequestIsInEvtIoStopContext(FxDriverGlobals);
2606 if (!NT_SUCCESS(status)) {
2607 goto Done;
2608 }
2609
2610 if (m_Completed == FALSE && Requeue) {
2611
2612 // Make sure the driver owns the request
2613
2614 status = VerifyRequestIsDriverOwned(FxDriverGlobals);
2615 if (!NT_SUCCESS(status)) {
2616 goto Done;
2617 }
2618
2619 //
2620 // Can't re-enqueue a cancelable request
2621 //
2622 status = VerifyRequestIsNotCancelable(FxDriverGlobals);
2623 if (!NT_SUCCESS(status)) {
2624 goto Done;
2625 }
2626 }
2627
2628 Done:
2629 Unlock(irql);
2630 return status;
2631 }
2632
2633 VOID
StopAcknowledge(__in BOOLEAN Requeue)2634 FxRequest::StopAcknowledge(
2635 __in BOOLEAN Requeue
2636 )
2637 /*++
2638
2639 Routine Description:
2640
2641 This routine saves the acknowledgement in the request object
2642 which will be looked at and processed later by the queue
2643 dispatch event loop
2644
2645 Arguments:
2646
2647 Requeue - if TRUE, put the request back into the head
2648 of queue from which it was delivered to the driver.
2649 Return Value:
2650
2651 None
2652
2653 --*/
2654 {
2655 NTSTATUS status;
2656
2657 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
2658
2659 status = VerifyStopAcknowledge(FxDriverGlobals, Requeue);
2660 if(!NT_SUCCESS(status)) {
2661 return;
2662 }
2663
2664 if (Requeue) {
2665 m_PowerStopState = FxRequestPowerStopAcknowledgedWithRequeue;
2666 }
2667 else {
2668 m_PowerStopState = FxRequestPowerStopAcknowledged;
2669 }
2670
2671 return;
2672 }
2673
2674 ULONG
AddRefOverride(__in WDFOBJECT_OFFSET Offset,__in PVOID Tag,__in LONG Line,__in_opt PSTR File)2675 FxRequest::AddRefOverride(
2676 __in WDFOBJECT_OFFSET Offset,
2677 __in PVOID Tag,
2678 __in LONG Line,
2679 __in_opt PSTR File
2680 )
2681 {
2682 if (Offset != 0x0) {
2683 ASSERT(Offset == FIELD_OFFSET(FxRequest, m_SystemBufferOffset) ||
2684 Offset == FIELD_OFFSET(FxRequest, m_OutputBufferOffset));
2685 AddIrpReference();
2686 return 2;
2687 }
2688 else {
2689 return FxObject::AddRef(Tag, Line, File);
2690 }
2691 }
2692
2693 ULONG
ReleaseOverride(__in WDFOBJECT_OFFSET Offset,__in PVOID Tag,__in LONG Line,__in_opt PSTR File)2694 FxRequest::ReleaseOverride(
2695 __in WDFOBJECT_OFFSET Offset,
2696 __in PVOID Tag,
2697 __in LONG Line,
2698 __in_opt PSTR File
2699 )
2700 {
2701 if (Offset != 0x0) {
2702 ASSERT(Offset == FIELD_OFFSET(FxRequest, m_SystemBufferOffset) ||
2703 Offset == FIELD_OFFSET(FxRequest, m_OutputBufferOffset));
2704 ReleaseIrpReference();
2705 return 1;
2706 }
2707 else {
2708 return FxObject::Release(Tag, Line, File);
2709 }
2710 }
2711
2712 _Must_inspect_result_
2713 NTSTATUS
QueryInterface(__in FxQueryInterfaceParams * Params)2714 FxRequest::QueryInterface(
2715 __in FxQueryInterfaceParams* Params
2716 )
2717 {
2718 switch (Params->Type) {
2719 case FX_TYPE_REQUEST:
2720 *Params->Object = (FxRequest*) this;
2721 break;
2722
2723 case IFX_TYPE_MEMORY:
2724 if (Params->Offset == FIELD_OFFSET(FxRequest, m_SystemBufferOffset)) {
2725 *Params->Object = (IFxMemory*) &m_SystemBuffer;
2726 break;
2727 }
2728 else if (Params->Offset == FIELD_OFFSET(FxRequest, m_OutputBufferOffset)) {
2729 *Params->Object = (IFxMemory*) &m_OutputBuffer;
2730 break;
2731 }
2732
2733 // || || Fall || ||
2734 // \/ \/ through \/ \/
2735 default:
2736 return FxRequestBase::QueryInterface(Params); // __super call
2737 }
2738
2739 return STATUS_SUCCESS;
2740 }
2741
2742 VOID
FX_VF_METHOD(FxRequest,VerifierBreakpoint_RequestEarlyDisposeDeferred)2743 FX_VF_METHOD(FxRequest, VerifierBreakpoint_RequestEarlyDisposeDeferred) (
2744 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
2745 )
2746 {
2747 PAGED_CODE_LOCKED();
2748
2749 //
2750 // For backwards compatibility break only if WDF is v1.11 or above, or if
2751 // the developer/client enabled these tests on down-level drivers.
2752 //
2753 if (FxDriverGlobals->IsVerificationEnabled(1, 11, OkForDownLevel)) {
2754 DoTraceLevelMessage(
2755 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2756 "WDFREQUEST %p deferred the dispose operation. This normally "
2757 "indicates that at least one of its children asked for passive "
2758 "level disposal. This is not supported.", GetHandle());
2759
2760 FxVerifierDbgBreakPoint(FxDriverGlobals);
2761 }
2762 }
2763
2764 _Must_inspect_result_
2765 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyRequestIsDriverOwned)2766 FX_VF_METHOD(FxRequest, VerifyRequestIsDriverOwned) (
2767 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
2768 )
2769 {
2770 NTSTATUS status;
2771
2772 PAGED_CODE_LOCKED();
2773
2774 if ((m_VerifierFlags & FXREQUEST_FLAG_DRIVER_OWNED) == 0) {
2775 status = STATUS_INVALID_DEVICE_REQUEST;
2776
2777 DoTraceLevelMessage(
2778 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2779 "WDFREQUEST 0x%p is not owned by the driver, %!STATUS!",
2780 GetHandle(), status);
2781
2782 //
2783 // See if it's a tag request, since this could be a common mistake
2784 //
2785 if (m_VerifierFlags & FXREQUEST_FLAG_TAG_REQUEST) {
2786 DoTraceLevelMessage(
2787 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2788 "WDFREQUEST 0x%p has been "
2789 "used as a TagRequest in WdfIoQueueFindRequest. "
2790 "A TagRequest cannot be used until it is retrieved "
2791 "by WdfIoQueueRetrieveFoundRequest",
2792 GetHandle());
2793 }
2794
2795 FxVerifierDbgBreakPoint(FxDriverGlobals);
2796 }
2797 else {
2798 status = STATUS_SUCCESS;
2799 }
2800
2801 return status;
2802 }
2803
2804 _Must_inspect_result_
2805 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyRequestIsCancelable)2806 FX_VF_METHOD(FxRequest, VerifyRequestIsCancelable)(
2807 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
2808 )
2809 {
2810 NTSTATUS status;
2811
2812 PAGED_CODE_LOCKED();
2813
2814 if ((m_VerifierFlags & FXREQUEST_FLAG_DRIVER_CANCELABLE) == 0) {
2815 status = STATUS_INVALID_DEVICE_REQUEST;
2816
2817 DoTraceLevelMessage(
2818 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2819 "WDFREQUEST 0x%p is not cancelable, %!STATUS!",
2820 GetHandle(), status);
2821
2822 FxVerifierDbgBreakPoint(FxDriverGlobals);
2823 }
2824 else {
2825 status = STATUS_SUCCESS;
2826 }
2827
2828 return status;
2829 }
2830
2831 _Must_inspect_result_
2832 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyRequestIsNotCancelable)2833 FX_VF_METHOD(FxRequest, VerifyRequestIsNotCancelable)(
2834 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
2835 )
2836 {
2837 NTSTATUS status;
2838
2839 PAGED_CODE_LOCKED();
2840
2841 if (m_VerifierFlags & FXREQUEST_FLAG_DRIVER_CANCELABLE) {
2842 status = STATUS_INVALID_DEVICE_REQUEST;
2843
2844 DoTraceLevelMessage(
2845 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2846 "WDFREQUEST 0x%p should be unmarked cancelable by calling "
2847 "WdfRequestUnmarkCancelable, %!STATUS!",
2848 GetHandle(), status);
2849
2850 FxVerifierDbgBreakPoint(FxDriverGlobals);
2851 }
2852 else {
2853 status = STATUS_SUCCESS;
2854 }
2855
2856 return status;
2857 }
2858
2859 _Must_inspect_result_
2860 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyRequestIsInCallerContext)2861 FX_VF_METHOD(FxRequest, VerifyRequestIsInCallerContext)(
2862 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
2863 )
2864 {
2865 NTSTATUS status;
2866
2867 PAGED_CODE_LOCKED();
2868
2869 if ((m_VerifierFlags & FXREQUEST_FLAG_DRIVER_INPROCESS_CONTEXT) == 0) {
2870 status = STATUS_INVALID_DEVICE_REQUEST;
2871
2872 DoTraceLevelMessage(
2873 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2874 "This call is valid only in EvtIoInCallerContext callback, "
2875 "WDFREQUEST 0x%p, %!STATUS!", GetHandle(), status);
2876
2877 FxVerifierDbgBreakPoint(FxDriverGlobals);
2878 }
2879 else {
2880 status = STATUS_SUCCESS;
2881 }
2882
2883 return status;
2884 }
2885
2886 _Must_inspect_result_
2887 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyRequestIsInEvtIoStopContext)2888 FX_VF_METHOD(FxRequest, VerifyRequestIsInEvtIoStopContext)(
2889 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
2890 )
2891 {
2892 NTSTATUS status;
2893
2894 PAGED_CODE_LOCKED();
2895
2896 if ((m_VerifierFlags & FXREQUEST_FLAG_DRIVER_IN_EVTIOSTOP_CONTEXT) == 0) {
2897 status = STATUS_INVALID_DEVICE_REQUEST;
2898
2899 DoTraceLevelMessage(
2900 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
2901 "This call is valid only in EvtIoStop callback, "
2902 "WDFREQUEST 0x%p, %!STATUS!", GetHandle(), status);
2903
2904 FxVerifierDbgBreakPoint(FxDriverGlobals);
2905 }
2906 else {
2907 status = STATUS_SUCCESS;
2908 }
2909
2910 return status;
2911 }
2912
2913 _Must_inspect_result_
2914 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyRequestIsNotCompleted)2915 FX_VF_METHOD(FxRequest, VerifyRequestIsNotCompleted)(
2916 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
2917 )
2918 {
2919 NTSTATUS status;
2920
2921 PAGED_CODE_LOCKED();
2922
2923 if (m_Completed) {
2924 status = STATUS_INTERNAL_ERROR;
2925
2926 DoTraceLevelMessage(
2927 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2928 "WDFREQUEST 0x%p is already completed, %!STATUS!",
2929 GetHandle(), status);
2930
2931 FxVerifierDbgBreakPoint(FxDriverGlobals);
2932 }
2933 else {
2934 status = STATUS_SUCCESS;
2935 }
2936
2937 return status;
2938 }
2939
2940 _Must_inspect_result_
2941 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyRequestIsTagRequest)2942 FX_VF_METHOD(FxRequest, VerifyRequestIsTagRequest) (
2943 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
2944 )
2945 {
2946 NTSTATUS status;
2947
2948 PAGED_CODE_LOCKED();
2949
2950 //
2951 // A request that has been marked as a tag request can be retrieved
2952 // by the driver by calling WdfIoQueueRetrieveNextRequest instead of
2953 // WdfIoQueueRetrieveFoundRequest. Some drivers use multiple threads
2954 // to scan the queue, not the best design but allowed. This means that
2955 // it is possible for one thread to remove and complete a request that is
2956 // used as a tag by another thread.
2957 //
2958 if (FALSE == m_Completed && (0x0 == (m_VerifierFlags &
2959 (FXREQUEST_FLAG_TAG_REQUEST | FXREQUEST_FLAG_DRIVER_OWNED)))) {
2960
2961 status = STATUS_INVALID_PARAMETER;
2962 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
2963 "Request 0x%p is not returned by WdfIoQueueFindRequest, "
2964 "%!STATUS!", GetHandle(), status);
2965 FxVerifierDbgBreakPoint(FxDriverGlobals);
2966 }
2967 else {
2968 status = STATUS_SUCCESS;
2969 }
2970
2971 return status;
2972 }
2973
2974 _Must_inspect_result_
2975 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyRequestIsAllocatedFromIo)2976 FX_VF_METHOD(FxRequest, VerifyRequestIsAllocatedFromIo)(
2977 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
2978 )
2979 {
2980 NTSTATUS status;
2981
2982 PAGED_CODE_LOCKED();
2983
2984 if (IsAllocatedFromIo() == FALSE) {
2985 status = STATUS_INVALID_PARAMETER;
2986 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
2987 "Request 0x%p was not allocated for an incoming IRP, "
2988 "%!STATUS!", GetHandle(), status);
2989 FxVerifierDbgBreakPoint(FxDriverGlobals);
2990
2991 } else {
2992 status = STATUS_SUCCESS;
2993 }
2994
2995 return status;
2996 }
2997
2998 _Must_inspect_result_
2999 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyRequestIsCurrentStackValid)3000 FX_VF_METHOD(FxRequest, VerifyRequestIsCurrentStackValid)(
3001 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
3002 )
3003 {
3004 NTSTATUS status;
3005 MdIrp irp;
3006
3007 PAGED_CODE_LOCKED();
3008
3009 //
3010 //Make sure there is an IRP.
3011 //
3012 irp = GetFxIrp()->GetIrp();
3013 if (NULL == irp) {
3014 status = STATUS_INVALID_DEVICE_REQUEST;
3015 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
3016 "WDFREQUEST %p doesn't have an IRP, %!STATUS!",
3017 GetHandle(), status);
3018 FxVerifierDbgBreakPoint(FxDriverGlobals);
3019 goto Done;
3020 }
3021
3022 //
3023 // Validate the IRP's stack location values.
3024 //
3025 if (m_Irp.IsCurrentIrpStackLocationValid() == FALSE) {
3026 status = STATUS_INVALID_DEVICE_REQUEST;
3027 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
3028 "IRP %p of WDFREQUEST %p doesn't have a valid"
3029 " stack location, %!STATUS!",
3030 irp, GetHandle(), status);
3031 FxVerifierDbgBreakPoint(FxDriverGlobals);
3032 goto Done;
3033 }
3034
3035 status = STATUS_SUCCESS;
3036
3037 Done:
3038 return status;
3039 }
3040
3041 _Must_inspect_result_
3042 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyRequestCanBeCompleted)3043 FX_VF_METHOD(FxRequest, VerifyRequestCanBeCompleted)(
3044 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
3045 )
3046 {
3047 NTSTATUS status;
3048
3049 PAGED_CODE_LOCKED();
3050
3051 if (GetDriverGlobals()->IsVersionGreaterThanOrEqualTo(1,11) == FALSE) {
3052 status = VerifyRequestIsAllocatedFromIo(FxDriverGlobals);
3053 goto Done;
3054 }
3055
3056 //
3057 // Validate the IRP's stack location.
3058 //
3059 status = VerifyRequestIsCurrentStackValid(FxDriverGlobals);
3060 if (!NT_SUCCESS(status)) {
3061 goto Done;
3062 }
3063
3064 //
3065 // Note: There is no guarantees that the request has a completion routine in the current
3066 // IRP stack location; thus we cannot check for it.
3067 //
3068
3069 //
3070 // Make sure this request can be completed.
3071 //
3072 if (IsCanComplete() == FALSE) {
3073 status = STATUS_INVALID_DEVICE_REQUEST;
3074 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
3075 "IRP %p of WDFREQUEST %p cannot be completed, "
3076 "%!STATUS!",
3077 GetFxIrp()->GetIrp(), GetHandle(), status);
3078 FxVerifierDbgBreakPoint(FxDriverGlobals);
3079 goto Done;
3080 }
3081
3082 status = STATUS_SUCCESS;
3083
3084 Done:
3085 return status;
3086 }
3087
3088 ULONG
Release(__in PVOID Tag,__in LONG Line,__in_opt PSTR File)3089 FxRequest::Release(
3090 __in PVOID Tag,
3091 __in LONG Line,
3092 __in_opt PSTR File
3093 )
3094 {
3095 ULONG retValue;
3096 BOOLEAN reservedRequest;
3097 BOOLEAN allocFromIo;
3098 BOOLEAN canComplete;
3099
3100 //
3101 // This may be the last ref, copy flags before calling Release().
3102 //
3103 reservedRequest = IsReserved();
3104 allocFromIo = IsAllocatedFromIo();
3105 canComplete = IsCanComplete();
3106
3107 retValue = FxRequestBase::Release(Tag, Line, File); // __super call
3108
3109 if (reservedRequest && retValue == 1 && m_Completed) {
3110 //
3111 // Reserved requests should have an associated queue all the time.
3112 //
3113 m_ForwardProgressQueue->ReturnReservedRequest(this);
3114 }
3115 else if (allocFromIo == FALSE && canComplete && retValue == 1 && m_Completed) {
3116
3117 FxRequestCompletionState state;
3118 FxIoQueue* queue;
3119
3120 //
3121 // Make a local copy before request is gone.
3122 //
3123 state = (FxRequestCompletionState) m_CompletionState;
3124 queue = m_IoQueue;
3125
3126 m_CompletionState = FxRequestCompletionStateNone;
3127 m_IoQueue = NULL;
3128
3129 //
3130 // We are now ready to complete this driver created request.
3131 //
3132 FxIrp irp(m_Irp.GetIrp());
3133
3134 m_Irp.SetIrp(NULL);
3135
3136 irp.CompleteRequest(GetPriorityBoost());
3137
3138 PostProcessCompletionForDriverRequest(state, queue);
3139 }
3140
3141 return retValue;
3142 }
3143
FxRequestFromLookaside(__in CfxDevice * Device,__in MdIrp Irp)3144 FxRequestFromLookaside::FxRequestFromLookaside(
3145 __in CfxDevice* Device,
3146 __in MdIrp Irp
3147 ) : FxRequest(Device->GetDriverGlobals(),
3148 Irp,
3149 FxRequestDoesNotOwnIrp,
3150 FxRequestConstructorCallerIsFx,
3151 sizeof(FxRequestFromLookaside))
3152 {
3153 SetDeviceBase(Device->GetDeviceBase());
3154 }
3155
3156 PVOID
operator new(__in size_t Size,__in CfxDevice * Device,__in_opt PWDF_OBJECT_ATTRIBUTES Attributes)3157 FxRequestFromLookaside::operator new(
3158 __in size_t Size,
3159 __in CfxDevice* Device,
3160 __in_opt PWDF_OBJECT_ATTRIBUTES Attributes
3161 )
3162 {
3163 UNREFERENCED_PARAMETER(Size);
3164
3165 //
3166 // Allocate out of a device specific lookaside list
3167 //
3168 return Device->AllocateRequestMemory(Attributes);
3169 }
3170
3171 VOID
SelfDestruct(VOID)3172 FxRequestFromLookaside::SelfDestruct(
3173 VOID
3174 )
3175 {
3176 CfxDevice* pDevice;
3177 PFX_POOL_HEADER pHeader;
3178
3179 //
3180 // Store off the device in case the destructor chain sets it to NULL.
3181 //
3182 pDevice = GetDevice();
3183 ASSERT(pDevice != NULL);
3184
3185 //
3186 // Destroy the object
3187 //
3188 // FxRequestFromLookaside::~FxRequestFromLookaside(); __REACTOS__
3189
3190 if (IsRequestForwardedToParent()) {
3191
3192 #if FX_VERBOSE_TRACE
3193 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGREQUEST,
3194 "Free FxRequest* %p memory", this);
3195 #endif
3196
3197 //
3198 // Remove the request from the list of outstanding requests against this
3199 // driver.
3200 //
3201 pHeader = FxObject::_CleanupPointer(GetDriverGlobals(), this);
3202 MxMemory::MxFreePool(pHeader->Base);
3203 }
3204 else {
3205 pDevice->FreeRequestMemory(this);
3206 }
3207 }
3208