1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxPkgGeneral.cpp
8 
9 Abstract:
10 
11     This module implements the wmi package for the driver frameworks.
12 
13 Author:
14 
15 
16 
17 
18 Environment:
19 
20     Both kernel and user mode
21 
22 Revision History:
23 
24 --*/
25 
26 #if ((FX_CORE_MODE)==(FX_CORE_USER_MODE))
27 #define FX_IS_USER_MODE (TRUE)
28 #define FX_IS_KERNEL_MODE (FALSE)
29 #elif ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE))
30 #define FX_IS_USER_MODE (FALSE)
31 #define FX_IS_KERNEL_MODE (TRUE)
32 #endif
33 
34 extern "C" {
35 #include "mx.h"
36 }
37 #include "fxmin.hpp"
38 
39 extern "C" {
40 // #include "FxPkgGeneral.tmh"
41 }
42 
43 
44 FxPkgGeneral::FxPkgGeneral(
45     __in PFX_DRIVER_GLOBALS FxDriverGlobals,
46     __in CfxDevice *Device
47     ) :
48     FxPackage(FxDriverGlobals, Device, FX_TYPE_PACKAGE_GENERAL)
49 {
50     //
51     // The count is biased to one and not zero for control device objects.  When
52     // a control devobj is deleted, we will decrement this bias out so that we
53     // know when the last handle has been closed and it is now safe to free the
54     // FxDevice.
55     //
56     m_OpenHandleCount = 1;
57 
58     //
59     // List of file object info.
60     //
61     InitializeListHead(&m_FileObjectInfoHeadList);
62 
63     m_Flags = 0;
64     m_ExecutionLevel = WdfExecutionLevelInheritFromParent;
65     m_SynchronizationScope = WdfSynchronizationScopeInheritFromParent;
66     m_CallbackLockPtr      = NULL;
67     m_CallbackLockObjectPtr = NULL;
68     m_DriverCreatedQueue = NULL;
69     m_DefaultQueueForCreates = NULL;
70 }
71 
72 FxPkgGeneral::~FxPkgGeneral()
73 {
74     PLIST_ENTRY next;
75 
76     ASSERT(m_OpenHandleCount <= 1);
77 
78     //
79     // Delete the file object info list if present.
80     //
81     while (!IsListEmpty(&m_FileObjectInfoHeadList)) {
82         next = RemoveHeadList(&m_FileObjectInfoHeadList);
83         FxFileObjectInfo* info;
84         info = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry);
85         InitializeListHead(next);
86         delete info;
87     }
88 }
89 
90 _Must_inspect_result_
91 NTSTATUS
92 FxPkgGeneral::Initialize(
93     __in PWDFDEVICE_INIT DeviceInit
94     )
95 /*++
96 
97 Routine Description:
98     Initiliazes how the driver will handle fileobjects and their associated
99     event callbacks (create, close, cleanup).
100 
101     Assumes that FileObjectAttributes has been validated by the caller.
102 
103 Arguments:
104     DeviceInit - Chain of device_init and cx_device_init with file object config.
105 
106 Return Value:
107     STATUS_SUCCESS or other NTSTATUS values.
108 
109   --*/
110 {
111     NTSTATUS                    status;
112     PLIST_ENTRY                 next;
113     FxFileObjectInfo*           fileObjInfo;
114     PFX_DRIVER_GLOBALS          fxDriverGlobals;
115 
116     fxDriverGlobals = GetDriverGlobals();
117 
118     //
119     // Init file object info.
120     //
121     if (DeviceInit->FileObject.Set) {
122         fileObjInfo = new(fxDriverGlobals) FxFileObjectInfo();
123         if (fileObjInfo == NULL) {
124             status = STATUS_INSUFFICIENT_RESOURCES;
125             DoTraceLevelMessage(fxDriverGlobals,
126                                 TRACE_LEVEL_ERROR, TRACINGDEVICE,
127                                 "Couldn't create object FileObjectInfo, "
128                                 "%!STATUS!", status);
129             goto Done;
130         }
131 
132         fileObjInfo->ClassExtension = FALSE;
133         fileObjInfo->FileObjectClass = DeviceInit->FileObject.Class;
134         fileObjInfo->Attributes = DeviceInit->FileObject.Attributes;
135 
136         fileObjInfo->AutoForwardCleanupClose =
137             DeviceInit->FileObject.AutoForwardCleanupClose;
138 
139         fileObjInfo->EvtFileCreate.Method =
140             DeviceInit->FileObject.Callbacks.EvtDeviceFileCreate;
141 
142         fileObjInfo->EvtFileCleanup.Method =
143             DeviceInit->FileObject.Callbacks.EvtFileCleanup;
144 
145         fileObjInfo->EvtFileClose.Method =
146             DeviceInit->FileObject.Callbacks.EvtFileClose;
147 
148         InsertTailList(&m_FileObjectInfoHeadList, &fileObjInfo->ListEntry);
149 
150         m_Flags |= FX_PKG_GENERAL_FLAG_CLIENT_INFO;
151 
152         if (fileObjInfo->EvtFileCreate.Method != NULL) {
153             m_Flags |= FX_PKG_GENERAL_FLAG_CLIENT_CREATE;
154         }
155     }
156 
157     //
158     // Build file object info chain for any class extension.
159     //
160     for (next = DeviceInit->CxDeviceInitListHead.Flink;
161          next != &DeviceInit->CxDeviceInitListHead;
162          next = next->Flink) {
163 
164         PWDFCXDEVICE_INIT cxInit;
165 
166         cxInit = CONTAINING_RECORD(next, WDFCXDEVICE_INIT, ListEntry);
167 
168         if (cxInit->FileObject.Set == FALSE) {
169             continue;
170         }
171 
172         fileObjInfo = new(fxDriverGlobals) FxFileObjectInfo();
173         if (fileObjInfo == NULL) {
174             status = STATUS_INSUFFICIENT_RESOURCES;
175             DoTraceLevelMessage(fxDriverGlobals,
176                                 TRACE_LEVEL_ERROR, TRACINGDEVICE,
177                                 "Couldn't create object FileObjectInfo, "
178                                 "%!STATUS!", status);
179             goto Done;
180         }
181 
182         fileObjInfo->ClassExtension = TRUE;
183         fileObjInfo->FileObjectClass = cxInit->FileObject.Class;
184         fileObjInfo->Attributes = cxInit->FileObject.Attributes;
185 
186         fileObjInfo->AutoForwardCleanupClose =
187             cxInit->FileObject.AutoForwardCleanupClose;
188 
189         fileObjInfo->EvtCxFileCreate.Method =
190             cxInit->FileObject.Callbacks.EvtCxDeviceFileCreate;
191 
192         fileObjInfo->EvtFileCleanup.Method =
193             cxInit->FileObject.Callbacks.EvtFileCleanup;
194 
195         fileObjInfo->EvtFileClose.Method =
196             cxInit->FileObject.Callbacks.EvtFileClose;
197 
198         fileObjInfo->CxDeviceInfo = cxInit->CxDeviceInfo;
199 
200         InsertTailList(&m_FileObjectInfoHeadList, &fileObjInfo->ListEntry);
201 
202         m_Flags |= FX_PKG_GENERAL_FLAG_CX_INFO;
203 
204         if (fileObjInfo->EvtCxFileCreate.Method != NULL) {
205             m_Flags |= FX_PKG_GENERAL_FLAG_CX_CREATE;
206         }
207     }
208 
209     //
210     // Nothing to do if list if empty.
211     //
212     if (IsListEmpty(&m_FileObjectInfoHeadList)) {
213         status = STATUS_SUCCESS;
214         goto Done;
215     }
216 
217     //
218     // We will enable this once the unlocking model is figured out.
219     // It's not okay to sent request downstack with the presentation lock held.
220     //
221     status = ConfigureConstraints(&m_FileObjectInfoHeadList);
222     if(!NT_SUCCESS(status)) {
223         goto Done;
224     }
225 
226     //
227     // Configure file object class.
228     //
229     status = ConfigureFileObjectClass(&m_FileObjectInfoHeadList);
230     if (!NT_SUCCESS(status)) {
231         goto Done;
232     }
233 
234     status = STATUS_SUCCESS;
235 
236 Done:
237     return status;
238 }
239 
240 _Must_inspect_result_
241 NTSTATUS
242 FxPkgGeneral::ConfigureConstraints(
243     __in PLIST_ENTRY FileObjInfoList
244     )
245 /*++
246 
247 Routine Description:
248 
249   Configure the callback synchronization according to the configuration supplied by the
250   client and class extension device driver.
251   It is a requirement for this driver chain (CXs and client driver) to use the same settings.
252 
253 Arguments:
254     FileObjInfoList - List of FxFileObjectInfo structs.
255 
256 Returns:
257     NTSTATUS
258 
259 --*/
260 {
261     WDF_EXECUTION_LEVEL         execLevel, parentExecLevel;
262     WDF_SYNCHRONIZATION_SCOPE   synchScope, parentSynchScope;
263     BOOLEAN                     automaticLockingRequired;
264     PLIST_ENTRY                 next;
265     FxFileObjectInfo           *fileObjInfo;
266     NTSTATUS                    status;
267     PFX_DRIVER_GLOBALS          fxDriverGlobals;
268 
269     automaticLockingRequired = FALSE;
270     fxDriverGlobals = GetDriverGlobals();
271 
272     ASSERT(!IsListEmpty(FileObjInfoList));
273 
274     //
275     // Get parent values.
276     //
277     m_Device->GetConstraints(&parentExecLevel, &parentSynchScope);
278 
279     //
280     // Default constraints settings when driver uses WDF_NO_OBJECT_ATTRIBUTES:
281     //
282     // v1.9 and below:
283     //     WdfExecutionLevelDispatch and WdfSynchronizationScopeNone
284     //
285     // v1.11 and above:
286     //     WdfExecutionLevelPassive and WdfSynchronizationScopeNone
287     //
288     // In v1.9 and below if driver used WDF_NO_OBJECT_ATTRIBUTES for
289     // the file object's attributes, the synchronization scope and execution
290     // level were left uninitialized (i.e., zero), which means that WDF
291     // defaulted to WdfSynchronizationScopeInvalid and WdfExecutionLevelInvalid,
292     // WDF interpreted these values as no_passive and no_synchronization.
293     //
294     // This default execution level is used when disposing the device's
295     // general package object and file object object.
296     // Independently of these settings WDF guarantees that Create,
297     // Cleanup and Close callbacks are always called at passive level.
298     //
299     m_ExecutionLevel = fxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11) ?
300                         WdfExecutionLevelPassive :
301                         WdfExecutionLevelDispatch;
302 
303     m_SynchronizationScope = WdfSynchronizationScopeNone;
304 
305     //
306     // Make sure file object info chain follow these constrains:
307     //  Cx's synch scope: none
308     //
309     for (next = FileObjInfoList->Blink;
310          next != FileObjInfoList;
311          next = next->Blink) {
312 
313         fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry);
314 
315         //
316         // Size is zero if driver didn't specify any attributes.
317         //
318         if (0 == fileObjInfo->Attributes.Size) {
319             continue;
320         }
321 
322         //
323         // Execution level checks.
324         //
325         execLevel = fileObjInfo->Attributes.ExecutionLevel;
326         if (WdfExecutionLevelInheritFromParent == execLevel) {
327             execLevel = parentExecLevel;
328         }
329 
330         //
331         // Passive level wins over DPC level.
332         //
333         if (WdfExecutionLevelPassive == execLevel) {
334             m_ExecutionLevel = WdfExecutionLevelPassive;
335         }
336 
337         //
338         // Synchronization scope checks.
339         //
340         synchScope = fileObjInfo->Attributes.SynchronizationScope;
341         if (WdfSynchronizationScopeInheritFromParent == synchScope) {
342             synchScope = parentSynchScope;
343         }
344 
345         //
346         // Make sure the Cx's synch scope is none.
347         //
348         if (fileObjInfo->ClassExtension) {
349             if (synchScope != WdfSynchronizationScopeNone) {
350                 status = STATUS_INVALID_DEVICE_REQUEST;
351                 DoTraceLevelMessage(
352                     fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
353                     "Driver 0x%p - Device 0x%p - synchronization scope: "
354                     "%!WDF_SYNCHRONIZATION_SCOPE! should be"
355                     "WdfSynchronizationScopeNone, %!STATUS!",
356                     m_Device->GetCxDriver(fileObjInfo->CxDeviceInfo)->GetHandle(),
357                     m_Device->GetHandle(),
358                     synchScope,
359                     status
360                     );
361 
362                 FxVerifierDbgBreakPoint(fxDriverGlobals);
363                 goto Done;
364             }
365         }
366         else {
367             //
368             // Always use client's synch scope for file object.
369             //
370             m_SynchronizationScope = synchScope;
371         }
372     }
373 
374     if(m_SynchronizationScope == WdfSynchronizationScopeQueue) {
375         status = STATUS_INVALID_DEVICE_REQUEST;
376         DoTraceLevelMessage(
377             fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
378             "WdfSynchronizationScopeQueue is not allowed on "
379             "FileObject, %!STATUS!",
380             status);
381         goto Done;
382     }
383 
384     if (m_ExecutionLevel == WdfExecutionLevelPassive) {
385 
386         //
387         // Mark FxObject as passive level to ensure that Dispose and Destroy
388         // callbacks are passive to the driver
389         //
390         MarkPassiveCallbacks(ObjectDoNotLock);
391         //
392         // We aren't going to use a workitem to  defer the invocation of fileevents
393         // to passive-level if the caller is at DISPATCH_LEVEL because we wouldn't
394         // be able to guarantee the caller's context for fileevents. It's up to the
395         // driver writer to ensure that the layer above doesn't send create requests
396         // at dispatch-level.
397         //
398     }
399 
400     if(m_SynchronizationScope == WdfSynchronizationScopeNone) {
401         status = STATUS_SUCCESS;
402         goto Done;
403     }
404 
405     if(m_SynchronizationScope == WdfSynchronizationScopeDevice) {
406         //
407         // Since FileEvents can be invoked only at passive-level, we check the
408         // parent executionlevel to see if it's set to passive. If not, we return an error
409         // because we can't use the presentation lock of the device.
410         //
411         if(parentExecLevel != WdfExecutionLevelPassive) {
412             status = STATUS_INVALID_DEVICE_REQUEST;
413             DoTraceLevelMessage(
414                 fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
415                 "WdfSynchronizationScopeDevice or "
416                 "WdfSynchronizationScopeInheritFromParent "
417                 "allowed only if the parent WDFDEVICE 0x%p, "
418                 "ExecutionLevel is passive, %!STATUS!",
419                 m_Device->GetHandle(), status);
420             goto Done;
421         }
422 
423         m_CallbackLockPtr = m_Device->GetCallbackLockPtr(&m_CallbackLockObjectPtr);
424         automaticLockingRequired = TRUE;
425     }
426 
427     //
428     // Set lock constraint in client's callbacks object only.
429     //
430     if (automaticLockingRequired) {
431         if (!IsListEmpty(FileObjInfoList)) {
432             fileObjInfo = CONTAINING_RECORD(FileObjInfoList->Flink,
433                                             FxFileObjectInfo,
434                                             ListEntry);
435 
436             if (FALSE == fileObjInfo->ClassExtension) {
437                 fileObjInfo->EvtFileCreate.SetCallbackLockPtr(m_CallbackLockPtr);
438                 fileObjInfo->EvtFileCleanup.SetCallbackLockPtr(m_CallbackLockPtr);
439                 fileObjInfo->EvtFileClose.SetCallbackLockPtr(m_CallbackLockPtr);
440             }
441         }
442     }
443 
444     status = STATUS_SUCCESS;
445 
446 Done:
447     return status;
448 }
449 
450 _Must_inspect_result_
451 NTSTATUS
452 FxPkgGeneral::ConfigureFileObjectClass(
453     __in PLIST_ENTRY FileObjInfoList
454     )
455 /*++
456 
457 Routine Description:
458 
459   Configure the file object class for this device.
460 
461   These are the possible class settings:
462 
463     WdfFileObjectNotRequired
464     WdfFileObjectWdfCanUseFsContext*
465     WdfFileObjectWdfCanUseFsContext2*,
466     WdfFileObjectWdfCannotUseFsContexts*
467 
468     * these can also be combined with WdfFileObjectCanBeOptional flag.
469 
470   Logic:
471 
472     - default: not_required.
473     - if cx/driver selects not_required, skip it.
474     - if cx/driver selects !not_required, than
475         . if everyone agrees on the setting, use that setting.
476         . else use cannot_use_fs_contexts.
477 
478 Arguments:
479     FileObjInfoList - List of FxFileObjectInfo structs.
480 
481 Returns:
482     NTSTATUS
483 
484 --*/
485 {
486     PLIST_ENTRY                 next;
487     FxFileObjectInfo*           fileObjInfo;
488     NTSTATUS                    status;
489     PFX_DRIVER_GLOBALS          fxDriverGlobals;
490     WDF_FILEOBJECT_CLASS        fileObjClass;
491     FxCxDeviceInfo*             previousCxInfo;
492 
493     fxDriverGlobals = GetDriverGlobals();
494     fileObjClass = WdfFileObjectNotRequired;
495     previousCxInfo = NULL;
496 
497     ASSERT(!IsListEmpty(FileObjInfoList));
498 
499     //
500     // Compute the execution level and synchronization scope for all the chain.
501     //
502     for (next = FileObjInfoList->Blink;
503          next != FileObjInfoList;
504          next = next->Blink) {
505 
506         fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry);
507 
508         //
509         // If not required, skip it.
510         //
511         if (WdfFileObjectNotRequired == fileObjInfo->FileObjectClass) {
512             continue;
513         }
514 
515         //
516         // If the same, skip it.
517         //
518         if (fileObjClass == fileObjInfo->FileObjectClass) {
519             continue;
520         }
521 
522         //
523         // If not set yet, use new value.
524         //
525         if (WdfFileObjectNotRequired == fileObjClass) {
526             fileObjClass = fileObjInfo->FileObjectClass;
527             previousCxInfo = fileObjInfo->CxDeviceInfo;
528             continue;
529         }
530 
531         //
532         // Make sure optional flag is compatible.
533         //
534         if (FxIsFileObjectOptional(fileObjClass) !=
535             FxIsFileObjectOptional(fileObjInfo->FileObjectClass)) {
536 
537             status = STATUS_INVALID_DEVICE_REQUEST;
538             DoTraceLevelMessage(
539                 fxDriverGlobals,
540                 TRACE_LEVEL_ERROR, TRACINGDEVICE,
541                 "Device 0x%p - "
542                 "Driver 0x%p - WdfFileObjectCanBeOptional (%d) is not "
543                 "compatible with wdf extension "
544                 "Driver 0x%p - WdfFileObjectCanBeOptional (%d), %!STATUS!",
545                 m_Device->GetHandle(),
546                 m_Device->GetCxDriver(fileObjInfo->CxDeviceInfo)->GetHandle(),
547                 FxIsFileObjectOptional(fileObjInfo->FileObjectClass) ? 1:0,
548                 previousCxInfo->Driver->GetHandle(),
549                 FxIsFileObjectOptional(fileObjClass) ? 1:0,
550                 status
551                 );
552 
553             FxVerifierDbgBreakPoint(fxDriverGlobals);
554             goto Done;
555         }
556 
557         //
558         // Drivers do not agree on the location, set cannot use fx contexts.
559         //
560         fileObjClass = WdfFileObjectWdfCannotUseFsContexts;
561         if (FxIsFileObjectOptional(fileObjInfo->FileObjectClass)) {
562             fileObjClass = (WDF_FILEOBJECT_CLASS)
563                 ((ULONG)fileObjClass |  WdfFileObjectCanBeOptional);
564         }
565 
566         DoTraceLevelMessage(
567             fxDriverGlobals,
568             TRACE_LEVEL_INFORMATION, TRACINGDEVICE,
569             "Converting file object class for Driver 0x%p - Device 0x%p, "
570             "from 0x%x to 0x%x",
571             m_Device->GetCxDriver(fileObjInfo->CxDeviceInfo)->GetHandle(),
572             m_Device->GetHandle(),
573             fileObjInfo->FileObjectClass,
574             fileObjClass
575             );
576     }
577 
578     //
579     // Set the file object support level on the FxDevice
580     //
581     m_Device->SetFileObjectClass(fileObjClass);
582 
583     status = STATUS_SUCCESS;
584 
585 Done:
586     return status;
587 }
588 
589 _Must_inspect_result_
590 NTSTATUS
591 FxPkgGeneral::PostCreateDeviceInitialize(
592     __in PWDFDEVICE_INIT Init
593     )
594 /*++
595 
596 Routine Description:
597     Optionally registers a shutdown and last chance shutdown notification on
598     behalf of the device.
599 
600 Arguments:
601     Init - Initialization structure which will indicate if registration is required
602 
603 Return Value:
604     NTSTATUS
605 
606   --*/
607 {
608     MdDeviceObject pDevice;
609     NTSTATUS status;
610     WDF_IO_QUEUE_CONFIG queueConfig;
611     WDF_OBJECT_ATTRIBUTES attributes;
612     PFX_DRIVER_GLOBALS pFxDriverGlobals;
613 
614     pFxDriverGlobals = GetDriverGlobals();
615     status = STATUS_SUCCESS;
616 
617 
618 
619 
620 #if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE))
621     if (Init->Control.Flags != 0) {
622         pDevice = m_Device->GetDeviceObject();
623 
624         if (Init->Control.Flags & WdfDeviceShutdown) {
625             status = IoRegisterShutdownNotification(pDevice);
626         }
627 
628         if (NT_SUCCESS(status) &&
629             (Init->Control.Flags & WdfDeviceLastChanceShutdown)) {
630             status = IoRegisterLastChanceShutdownNotification(pDevice);
631 
632         }
633 
634         if (NT_SUCCESS(status)) {
635             //
636             // IoDeleteDevice will automatically unregister the shutdown
637             // notifications if the device is deleted before the machine is
638             // shutdown, so we don't need to track registration beyond this point.
639             //
640             m_EvtDeviceShutdown.m_Method = Init->Control.ShutdownNotification;
641         }
642         else {
643             //
644             // This unregisters both the normal and last chance notifications
645             //
646             IoUnregisterShutdownNotification(pDevice);
647         }
648     }
649 #else
650     UNREFERENCED_PARAMETER(Init);
651     UNREFERENCED_PARAMETER(pDevice);
652 #endif
653 
654     if (NT_SUCCESS(status) && (m_Flags & FX_PKG_GENERAL_FLAG_CREATE)) {
655         //
656         // Create an internal queue to track create requests presented to the driver.
657         // This special queue is used so that we can invoke the events in the context
658         // of the caller.
659         //
660         WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual);
661 
662         //
663         // non power managed queue because we don't anticipate drivers touching
664         // hardware in the fileevent callbacks. If they do, then they should make sure
665         // to power up the device.
666         //
667         queueConfig.PowerManaged = WdfFalse;
668 
669         //
670         // Queue inherits the sync & exec level of fileobject.
671         //
672         WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
673         attributes.ExecutionLevel = m_ExecutionLevel;
674         attributes.SynchronizationScope = m_SynchronizationScope;
675 
676         status = m_Device->m_PkgIo->CreateQueue(&queueConfig,
677                                                 &attributes,
678                                                 NULL,
679                                                 &m_DefaultQueueForCreates);
680 
681         if (!NT_SUCCESS(status)) {
682            DoTraceLevelMessage(
683                pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
684                "Unable to create an internal queue for creates for WDFDEVICE "
685                "0x%p, %!STATUS!", m_Device->GetHandle(), status);
686            return status;
687         }
688     }
689 
690     return status;
691 }
692 
693 _Must_inspect_result_
694 NTSTATUS
695 FxPkgGeneral::ConfigureForwarding(
696     __in FxIoQueue* TargetQueue
697     )
698 /*++
699 
700 Routine Description:
701 
702     Used to register driver specified for dispatching create requests.
703 
704 Arguments:
705 
706 Return Value:
707 
708     NTSTATUS
709 
710   --*/
711 {
712     NTSTATUS status;
713     PFX_DRIVER_GLOBALS pFxDriverGlobals;
714     KIRQL irql;
715 
716     status = STATUS_SUCCESS;
717     pFxDriverGlobals = GetDriverGlobals();
718 
719     if(TargetQueue->IsIoEventHandlerRegistered(WdfRequestTypeCreate) == FALSE){
720         status = STATUS_INVALID_DEVICE_REQUEST;
721         DoTraceLevelMessage(
722                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
723                 "Must have EvtIoDefault registered to receive "
724                 "WdfRequestTypeCreate requests for WDFQUEUE 0x%p, "
725                 "%!STATUS!", TargetQueue->GetObjectHandle(), status);
726         FxVerifierDbgBreakPoint(pFxDriverGlobals);
727         return status;
728     }
729 
730     Lock(&irql);
731 
732     if (m_DriverCreatedQueue) {
733         status = STATUS_INVALID_PARAMETER;
734 
735         DoTraceLevelMessage(
736             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
737             "Another WDFQUEUE 0x%p is already configured for auto dispatching "
738             "create request, %!STATUS!",
739             m_DriverCreatedQueue->GetObjectHandle(), status);
740 
741         FxVerifierDbgBreakPoint(pFxDriverGlobals);
742     }
743     else {
744         m_DriverCreatedQueue = TargetQueue;
745     }
746 
747     Unlock(irql);
748 
749     return status;
750 }
751 
752 _Must_inspect_result_
753 NTSTATUS
754 FxPkgGeneral::Dispatch(
755     __inout MdIrp Irp
756     )
757 /*++
758 
759 Routine Description:
760 
761     Dispatch routine for handling create, cleanup, close, and shutdown requests.
762 
763 Arguments:
764 
765 
766 Return Value:
767 
768     NTSTATUS
769 
770   --*/
771 {
772     NTSTATUS status;
773     PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals();
774     FxIrp fxIrp(Irp);
775 
776     FX_TRACK_DRIVER(pFxDriverGlobals);
777 
778     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
779                         "WDFDEVICE 0x%p !devobj 0x%p %!IRPMJ! IRP 0x%p",
780                         m_Device->GetHandle(), m_Device->GetDeviceObject(),
781                         fxIrp.GetMajorFunction(), Irp);
782 
783     switch (fxIrp.GetMajorFunction()) {
784     case IRP_MJ_CREATE:
785         status = OnCreate(&fxIrp);
786         break;
787 
788     case IRP_MJ_CLOSE:
789         status = OnClose(&fxIrp);
790         break;
791 
792     case IRP_MJ_CLEANUP:
793         status = OnCleanup(&fxIrp);
794         break;
795 
796     case IRP_MJ_SHUTDOWN:
797         status = OnShutdown(&fxIrp);
798         break;
799 
800     default:
801         ASSERT(FALSE);
802         status = STATUS_NOT_SUPPORTED;
803         fxIrp.SetStatus(status);
804         fxIrp.CompleteRequest(IO_NO_INCREMENT);
805         break;
806     }
807 
808     return status;
809 }
810 
811 _Must_inspect_result_
812 NTSTATUS
813 FxPkgGeneral::OnCreate(
814     __inout FxIrp* FxIrp
815     )
816 /*++
817 
818 Routine Description:
819 
820     1) Allow only one handle to be open for exclusive device.
821     2) Create a WDFFILEOBJECT to represent the WDM fileobject. This
822         fileobject is created only if the driver registers for EvtFile events and
823         doesn't specify WdfFileObjectNotRequired. If the file-events are not
824         registered, the default FileobjectClass is WdfFileObjectNotRequired - set
825         during DeviceInit.
826     3) If the EvtFileCreate event is *not* set or any driver queue is not configured,
827         then complete or forward the request to the lower
828         driver depending on AutoForwardCleanupClose. AutoForwardCleanupClose
829         is set to TRUE by default for filter drivers.
830     4) Create a FxRequest.
831     5) First try to dispatch it to a driver specified queue.
832     6) If there is no driver specified queue, then check to see if the driver has
833          registered EvtDeviceFileCreate event.
834     7) If EvtFileCreate is set then dispatch the request to to an internal
835         manual queue, retrieve the request by fileobject and present the request to
836         the driver in the EvtFileCreate event.  This allow the driver to forward the request
837         to another queue to mark the request cancelable and complete it later.
838 
839 Arguments:
840 
841 Return Value:
842 
843     NTSTATUS
844 
845  --*/
846 {
847     NTSTATUS                    status;
848     FxFileObject*               pFxFO ;
849     WDFFILEOBJECT               hwdfFO;
850     FxRequest *                 pRequest;
851     PFX_DRIVER_GLOBALS          pFxDriverGlobals;
852     MdFileObject                fileObject;
853     LONG                        count;
854     BOOLEAN                     inCriticalRegion;
855     BOOLEAN                     inDefaultQueue;
856     FxFileObjectInfo*           fileObjInfo;
857     WDF_OBJECT_ATTRIBUTES       attributes;
858     PLIST_ENTRY                 next;
859 
860     pFxFO = NULL;
861     hwdfFO = NULL;
862     pRequest = NULL;
863     inCriticalRegion = FALSE;
864     inDefaultQueue = FALSE;
865     pFxDriverGlobals = GetDriverGlobals();
866     fileObject = FxIrp->GetFileObject();
867     fileObjInfo = NULL;
868 
869     //
870     // Check for exclusivity.
871     //
872     count = InterlockedIncrement(&m_OpenHandleCount);
873 
874     //
875     // The count is biased by one to help track when to delete the control
876     // device, so we need to check for 2, not 1.
877     //
878     if (m_Device->IsExclusive() && count > 2) {
879        DoTraceLevelMessage(
880            pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
881            "Exclusive WDFDEVICE 0x%p, only one open handle is allowed",
882            m_Device->GetHandle());
883        status =  STATUS_ACCESS_DENIED;
884        goto Error;
885     }
886 
887     // ------------------------------------------------------------------------
888     //
889     // Create WDFFILEOBJECT. By default we allocate the root driver's file obj
890     // context; then we attach the other file obj contexts.
891     //
892 
893     //
894     // Init the file obj's attributes. Use default if not present (legacy behavior).
895     //
896     WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
897     if (!IsListEmpty(&m_FileObjectInfoHeadList)) {
898         //
899         // file obj info is set, use the top most driver's info, i.e., cx if present.
900         //
901         fileObjInfo = CONTAINING_RECORD(m_FileObjectInfoHeadList.Blink,
902                                         FxFileObjectInfo,
903                                         ListEntry);
904 
905         //
906         // Use this layer's attributes if present.
907         // Size is zero if driver didn't specify file object's attributes.
908         //
909         if (0 != fileObjInfo->Attributes.Size) {
910             ASSERT(fileObjInfo->Attributes.Size == sizeof(WDF_OBJECT_ATTRIBUTES));
911             attributes = fileObjInfo->Attributes;
912         }
913 
914         //
915         // Use computed constraint settings.
916         //
917         attributes.ExecutionLevel = m_ExecutionLevel;
918         attributes.SynchronizationScope = m_SynchronizationScope;
919     }
920 
921     //
922     // Create the file object.
923     //
924     status = FxFileObject::_CreateFileObject(
925         m_Device,
926         FxIrp->GetIrp(),
927         m_Device->GetFileObjectClass(),
928         &attributes,
929         fileObject,
930         &pFxFO
931         );
932 
933     if (!NT_SUCCESS(status) ) {
934         DoTraceLevelMessage(
935             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
936             "Could not create WDFFILEOBJECT for WDFDEVICE 0x%p, failing "
937             "IRP_MJ_CREATE %!STATUS!", m_Device->GetHandle(), status);
938         goto Error;
939     }
940 
941     if (pFxFO != NULL) {
942         hwdfFO = pFxFO->GetHandle();
943 
944         //
945         // If any, attach the file obj's contexts of the other drivers in this chain.
946         //
947         for (next = m_FileObjectInfoHeadList.Blink->Blink; // skip one.
948              next != &m_FileObjectInfoHeadList;
949              next = next->Blink) {
950 
951             fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry);
952 
953             attributes = fileObjInfo->Attributes;
954 
955             //
956             // Size is zero if driver didn't specify file object's attributes.
957             //
958             if (0 == attributes.Size) {
959                 continue;
960             }
961 
962             //
963             // Don't need these settings for extra contexts.
964             //
965             attributes.ExecutionLevel = WdfExecutionLevelInheritFromParent;
966             attributes.SynchronizationScope = WdfSynchronizationScopeInheritFromParent;
967             attributes.ParentObject = NULL;
968 
969             status = FxObjectAllocateContext(pFxFO,
970                                              &attributes,
971                                              TRUE,
972                                              NULL);
973             if(!NT_SUCCESS(status)) {
974                 DoTraceLevelMessage(
975                     pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
976                     "Couldn't allocate file object context 0x%p for "
977                     "device 0x%p - driver 0x%p, %!STATUS!",
978                     &fileObjInfo->Attributes,
979                     m_Device->GetHandle(),
980                     m_Device->GetCxDriver(fileObjInfo->CxDeviceInfo)->GetHandle(),
981                     status
982                     );
983 
984                 goto Error;
985             }
986         }
987     }
988 
989     // ------------------------------------------------------------------------
990     //
991     // If there is no driver configured queue or m_EvtFileCreate is not registered,
992     // complete the request with status-success. The reason for making this
993     // check after creating the fileobject is to  allow WdfRequestGetFileObject even
994     // if the driver hasn't registered any file-event callbacks.
995     //
996     if (m_DriverCreatedQueue == NULL &&
997         (m_Flags & FX_PKG_GENERAL_FLAG_CREATE) == 0) {
998 
999         //
1000         // Check to see if the driver has opted to autoforward cleanup and close.
1001         // If so, we should forward create requests also. Else, we should
1002         // complete the request with STATUS_SUCCESS. Note, if the driver is
1003         // a filter driver, the default value of m_AutoForwardCleanupClose is TRUE.
1004         //
1005         //
1006         if (m_Device->m_AutoForwardCleanupClose) {
1007             status = ForwardCreateRequest(FxIrp, _CreateCompletionRoutine, this);
1008             //
1009             // _CreateCompletionRoutine will do the cleanup when the request is
1010             // completed with error status by the lower driver.
1011             //
1012         }
1013         else {
1014             status = STATUS_SUCCESS;
1015             FxIrp->SetStatus(status);
1016             FxIrp->SetInformation(0);
1017             FxIrp->CompleteRequest(IO_NO_INCREMENT);
1018         }
1019 
1020        goto RequestIsGone;
1021     }
1022 
1023     // ------------------------------------------------------------------------
1024     //
1025     // Create a FxRequest for this IRP. By default we allocate the top most driver's request
1026     // context; then we attach the other request contexts.
1027     //
1028 
1029     //
1030     // Init the request's attributes.
1031     //
1032     if (!IsListEmpty(&m_FileObjectInfoHeadList)) {
1033         //
1034         // file obj info is set, use the top most driver's info, i.e., cx if present.
1035         //
1036         fileObjInfo = CONTAINING_RECORD(m_FileObjectInfoHeadList.Blink,
1037                                         FxFileObjectInfo,
1038                                         ListEntry);
1039         if (fileObjInfo->ClassExtension) {
1040             attributes = fileObjInfo->CxDeviceInfo->RequestAttributes;
1041         }
1042         else {
1043             attributes = *m_Device->GetRequestAttributes();
1044         }
1045     }
1046     else {
1047         attributes = *m_Device->GetRequestAttributes();
1048     }
1049 
1050     if (m_Device->IsCxInIoPath()) {
1051         //
1052         // Apply cx's constrains for create requests:
1053         //
1054         attributes.ExecutionLevel = WdfExecutionLevelDispatch;
1055         attributes.SynchronizationScope = WdfSynchronizationScopeNone;
1056         attributes.ParentObject = NULL;
1057     }
1058 
1059     //
1060     // Create the request.
1061     //
1062     status = FxRequest::_CreateForPackage(m_Device,
1063                                           &attributes,
1064                                           FxIrp->GetIrp(),
1065                                           &pRequest);
1066     if(!NT_SUCCESS(status)) {
1067         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
1068                             "Could not create request for WDFDEVICE 0x%p, %!STATUS!",
1069                             m_Device->GetHandle(), status);
1070         goto Error;
1071     }
1072 
1073     //
1074     // If any, attach the request's contexts of the other drivers in this chain.
1075     //
1076     for (next = m_FileObjectInfoHeadList.Blink->Blink; // skip one.
1077          next != &m_FileObjectInfoHeadList;
1078          next = next->Blink) {
1079 
1080         fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry);
1081 
1082         if (fileObjInfo->ClassExtension) {
1083             attributes = fileObjInfo->CxDeviceInfo->RequestAttributes;
1084         }
1085         else {
1086             attributes = *m_Device->GetRequestAttributes();
1087         }
1088 
1089         //
1090         // Size is zero if driver didn't specify request's attributes.
1091         //
1092         if (0 == attributes.Size) {
1093             continue;
1094         }
1095 
1096         //
1097         // Don't need these settings for extra contexts.
1098         //
1099         attributes.ExecutionLevel = WdfExecutionLevelInheritFromParent;
1100         attributes.SynchronizationScope = WdfSynchronizationScopeInheritFromParent;
1101         attributes.ParentObject = NULL;
1102 
1103         status = FxObjectAllocateContext(
1104                             pRequest,
1105                             &attributes,
1106                             TRUE,
1107                             NULL);
1108 
1109         if(!NT_SUCCESS(status)) {
1110             DoTraceLevelMessage(
1111                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
1112                 "Couldn't allocate request context for "
1113                 "device 0x%p - driver 0x%p, %!STATUS!",
1114                 m_Device->GetHandle(),
1115                 m_Device->GetCxDriver(fileObjInfo->CxDeviceInfo)->GetHandle(),
1116                 status
1117                 );
1118 
1119             goto Error;
1120         }
1121     }
1122 
1123     //
1124     // Disable thread suspension beyond this point by entering critical region.
1125     //
1126     if (Mx::MxGetCurrentIrql() <= APC_LEVEL)
1127     {
1128         Mx::MxEnterCriticalRegion();
1129         inCriticalRegion = TRUE;
1130     }
1131 
1132     // ------------------------------------------------------------------------
1133     //
1134     // Queue request in default queue before invoking cx or client's create callbacks.
1135     //
1136     if ((m_Flags & FX_PKG_GENERAL_FLAG_CX_CREATE) ||
1137         m_DriverCreatedQueue == NULL) {
1138 
1139         FxRequest* outputRequest;
1140 
1141         ASSERT(m_Flags & FX_PKG_GENERAL_FLAG_CREATE);
1142 
1143         //
1144         // Make sure we are calling FileEvents at the right IRQL level.
1145         //
1146         if (m_ExecutionLevel ==  WdfExecutionLevelPassive &&
1147             Mx::MxGetCurrentIrql() >= DISPATCH_LEVEL) {
1148 
1149             status = STATUS_INVALID_DEVICE_REQUEST;
1150             DoTraceLevelMessage(
1151                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
1152                 "WDFDEVICE 0x%p cannot handle create request at or above "
1153                 "dispatch-level, fail the Irp: 0x%p, %!STATUS!",
1154                 m_Device->GetObjectHandle(), FxIrp->GetIrp(), status);
1155 
1156             goto Error;
1157         }
1158 
1159         //
1160         // Now queue and immediately retrieve the request by FileObject.
1161         // QueueRequest will return an error if the queue is not accepting request
1162         // or the request is already cancelled. Either way, the request is completed by
1163         // the FxIoQueue.
1164         //
1165         status = m_DefaultQueueForCreates->QueueRequest(pRequest);
1166         if (!NT_SUCCESS(status)) {
1167             DoTraceLevelMessage(
1168                     pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
1169                     "Couldn't forward request to the WDFQUEUE 0x%p, %!STATUS!",
1170                     m_DefaultQueueForCreates->GetObjectHandle(), status);
1171             goto RequestIsGone;
1172         }
1173 
1174         status = m_DefaultQueueForCreates->GetRequest(fileObject,
1175                                                       NULL,
1176                                                       &outputRequest);
1177         if (!NT_SUCCESS(status)) {
1178             //
1179             // Oops, request got cancelled and completed by another thread.
1180             //
1181             ASSERT(status == STATUS_NO_MORE_ENTRIES);
1182             status = STATUS_PENDING; // IRP was already marked pending.
1183             goto RequestIsGone;
1184         }
1185 
1186         ASSERT(outputRequest == pRequest);
1187 
1188         inDefaultQueue = TRUE;
1189     }
1190 
1191     // ------------------------------------------------------------------------
1192     //
1193     // Invoke Cx's create callbacks.  Here we add the cx's file obj and request contexts.
1194     //
1195     if (m_Flags & FX_PKG_GENERAL_FLAG_CX_CREATE) {
1196 
1197         //
1198         // Loop through all cx's file obj info.
1199         //
1200         for (next = m_FileObjectInfoHeadList.Blink;
1201              next != &m_FileObjectInfoHeadList;
1202              next = next->Blink) {
1203 
1204             //
1205             // Get ready to invoke next layer cx's create.
1206             //
1207             fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry);
1208 
1209             //
1210             // Do not invoke the client driver's create callback (if any). For compatibility
1211             // we need to check first the driver 'create' queue.
1212             //
1213             if (FALSE == fileObjInfo->ClassExtension) {
1214                 break;
1215             }
1216 
1217             ASSERT(fileObjInfo->EvtFileCreate.Method == NULL);
1218             ASSERT(fileObjInfo->EvtCxFileCreate.Method != NULL);
1219 
1220             //
1221             // Keep track where we stopped (end, not inclusive node).
1222             // Note that we cannot do this after the Invoke b/c File Object
1223             // may be gone by the time callback returns.
1224             //
1225             if (pFxFO) {
1226                 pFxFO->SetPkgCleanupCloseContext(next->Blink);
1227             }
1228 
1229             //
1230             // Invoke knows how to handle NULL callbacks.
1231             //
1232             if (fileObjInfo->EvtCxFileCreate.Invoke(
1233                                 m_Device->GetHandle(),
1234                                 (WDFREQUEST)pRequest->GetObjectHandle(),
1235                                 hwdfFO)) {
1236                 //
1237                 // Callback claimed the request.
1238                 //
1239                 status = STATUS_PENDING; // IRP was already marked pending.
1240                 goto RequestIsGone;
1241             }
1242         }
1243     }
1244 
1245     //-------------------------------------------------------------------------
1246     //
1247     // First check for driver configured queue. If there is one, dispatch the request
1248     // to that queue.
1249     //
1250     if (m_DriverCreatedQueue != NULL) {
1251         if (inDefaultQueue) {
1252             ASSERT(m_Flags & FX_PKG_GENERAL_FLAG_CX_INFO);
1253 
1254             status = m_DefaultQueueForCreates->ForwardRequest(
1255                                 m_DriverCreatedQueue,
1256                                 pRequest);
1257 
1258             if(!NT_SUCCESS(status)) {
1259                 DoTraceLevelMessage(
1260                     pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
1261                     "Couldn't forward request to the WDFQUEUE 0x%p, %!STATUS!",
1262                     m_DriverCreatedQueue->GetObjectHandle(), status);
1263 
1264                 pRequest->Complete(status);
1265             }
1266 
1267             status = STATUS_PENDING; // IRP was already marked pending.
1268             goto RequestIsGone;
1269         }
1270         else {
1271             ASSERT(pRequest->GetRefCnt() == 1);
1272             //
1273             // QueueRequest will return an error if the queue is not accepting request
1274             // or the request is already cancelled. Either way, the request is completed by
1275             // the FxIoQueue.
1276             //
1277             status = m_DriverCreatedQueue->QueueRequest(pRequest);
1278             if(!NT_SUCCESS(status)) {
1279                 DoTraceLevelMessage(
1280                     pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
1281                     "Couldn't forward request to the WDFQUEUE 0x%p, %!STATUS!",
1282                     m_DriverCreatedQueue->GetObjectHandle(), status);
1283             }
1284 
1285             goto RequestIsGone;
1286         }
1287     }
1288 
1289     //-------------------------------------------------------------------------
1290     //
1291     // At this point invoke the client driver callback if present.
1292     //
1293     if (m_Flags & FX_PKG_GENERAL_FLAG_CLIENT_CREATE) {
1294         ASSERT(m_Flags & FX_PKG_GENERAL_FLAG_CLIENT_INFO);
1295         ASSERT(TRUE == inDefaultQueue);
1296         ASSERT(fileObjInfo->EvtFileCreate.Method != NULL);
1297         ASSERT(fileObjInfo->EvtCxFileCreate.Method == NULL);
1298 
1299         //
1300         // Invoke the client driver create requests.
1301         //
1302         fileObjInfo->EvtFileCreate.Invoke(
1303                             m_Device->GetHandle(),
1304                             (WDFREQUEST)pRequest->GetObjectHandle(),
1305                             hwdfFO);
1306         //
1307         // QueueRequest has already marked the request pending.
1308         //
1309         status = STATUS_PENDING;
1310         goto RequestIsGone;
1311     }
1312 
1313     //
1314     // We should be here only if CX's create returned 'continue' but client didn't have
1315     // a create callback.
1316     //
1317     ASSERT(m_Flags & FX_PKG_GENERAL_FLAG_CX_INFO);
1318 
1319     //
1320     // Check to see if the driver has opted to autoforward cleanup and close.
1321     // If so, we should forward create requests to lower drivers. Else, we should
1322     // complete the request with STATUS_SUCCESS. Note, if the driver is
1323     // a filter driver, the default value of m_AutoForwardCleanupClose is TRUE.
1324     //
1325     if (m_Device->m_AutoForwardCleanupClose) {
1326         (void)ForwardCreateRequest(FxIrp, _CreateCompletionRoutine2, pRequest);
1327         //
1328         // _CreateCompletionRoutine2 will complete the WDF request.
1329         //
1330     }
1331     else {
1332         pRequest->Complete(STATUS_SUCCESS);
1333     }
1334 
1335     //
1336     // Done processing this request.
1337     //
1338     status = STATUS_PENDING; // IRP was already marked pending.
1339     goto RequestIsGone;
1340 
1341 Error:
1342     if (pRequest != NULL) {
1343         pRequest->DeleteFromFailedCreate();
1344         pRequest = NULL;
1345     }
1346 
1347     ASSERT(!NT_SUCCESS(status));
1348 
1349     if (pFxFO != NULL) {
1350         pFxFO->DeleteFileObjectFromFailedCreate();
1351         pFxFO = NULL;
1352     }
1353 
1354     //
1355     // NOTE:  after this call, this object may have been deleted!
1356     //
1357     DecrementOpenHandleCount();
1358 
1359     FxIrp->SetStatus(status);
1360     FxIrp->SetInformation(0);
1361     FxIrp->CompleteRequest(IO_NO_INCREMENT);
1362 
1363     // fallthrough
1364 
1365 RequestIsGone:
1366 
1367     //
1368     // We have lost the ownership of the request. We have either successfully
1369     // presented the request to the driver or the queue function we called to
1370     // present the request returned error but completed the FxRequest on its own.
1371     // Either way we don't need to worry about cleaning up the resources
1372     // (fileobject, handle-count, etc) because the FxRequest:Completion routine
1373     // will call FxPkgGeneral::CreateCompleted to post process IRP upon completion.
1374     //
1375     if (inCriticalRegion) {
1376         Mx::MxLeaveCriticalRegion();
1377     }
1378 
1379     return status;
1380 }
1381 
1382 _Must_inspect_result_
1383 NTSTATUS
1384 FxPkgGeneral::ForwardCreateRequest(
1385     __in FxIrp* Irp,
1386     __in MdCompletionRoutine CompletionRoutine,
1387     __in PVOID  Context
1388     )
1389 {
1390     NTSTATUS status;
1391 
1392     Irp->CopyCurrentIrpStackLocationToNext();
1393     Irp->SetCompletionRoutineEx(m_Device->GetDeviceObject(),
1394                                  CompletionRoutine,
1395                                  Context);
1396     status = Irp->CallDriver(m_Device->GetAttachedDevice());
1397 
1398     return status;
1399 }
1400 
1401 VOID
1402 FxPkgGeneral::CreateCompleted(
1403     __in FxIrp *Irp
1404     )
1405 /*++
1406 
1407 Routine Description:
1408 
1409     This method is called when the WDFREQUEST for Irp
1410     is completed either by the driver or framework.
1411 
1412     Here, we check the completion status of the IRP and if
1413     it's not success, we destroy the fileobject and decrement
1414     the openhandle count on the device.
1415 
1416 Arguments:
1417 
1418 Return Value:
1419 
1420     VOID
1421 
1422  --*/
1423 {
1424     NTSTATUS status = Irp->GetStatus();
1425 
1426     //
1427     // If the create is completed with error status,
1428     // we destroy the WDFFILEOBJECT since the IoMgr will destroy
1429     // the PFILE_OBJECT if the IRP_MJ_CREATE fails and wouldn't send
1430     // Cleanup or Close IRP.
1431     //
1432     if (!NT_SUCCESS(status)) {
1433 
1434         // Now destroy the WDFFILEOBJECT
1435         FxFileObject::_DestroyFileObject(
1436             m_Device,
1437             m_Device->GetFileObjectClass(),
1438             Irp->GetFileObject()
1439             );
1440 
1441         DecrementOpenHandleCount();
1442     }
1443 }
1444 
1445 _Must_inspect_result_
1446 NTSTATUS
1447 STDCALL
1448 FxPkgGeneral::_CreateCompletionRoutine(
1449     __in MdDeviceObject DeviceObject,
1450     __in MdIrp           OriginalIrp,
1451     __in_opt PVOID      Context
1452     )
1453 /*++
1454 
1455 Routine Description:
1456 
1457     This completion routine is set only when the IRP is forwarded
1458     directly by the framework to the lower driver. Framework forwards
1459     the IRP request if:
1460     1) The driver happens to be a filter and hasn't registered any
1461        callbacks to handle create request.
1462     2) The driver is not a filter but has explicitly requested the
1463        framework to autoforward create/cleanup/close requests down.
1464 
1465     We need to intercept the create in the completion path to find
1466     out whether the lower driver has succeeded or failed the request.
1467     If the request is failed, we should inform the package so that
1468     it can cleanup the state because I/O manager wouldn't send
1469     cleanup & close requests if the create is failed.
1470 
1471 Arguments:
1472 
1473 Return Value:
1474 
1475     NTSTATUS
1476 
1477  --*/
1478 {
1479     FxPkgGeneral* pFxPkgGeneral;
1480     FxIrp irp(OriginalIrp);
1481 
1482     UNREFERENCED_PARAMETER(DeviceObject);
1483 
1484     pFxPkgGeneral = (FxPkgGeneral*) Context;
1485 
1486     ASSERT(pFxPkgGeneral != NULL);
1487 
1488     //
1489     // Let the package know that create is completed
1490     // so that it can cleanup the state.
1491     //
1492     pFxPkgGeneral->CreateCompleted(&irp);
1493 
1494     //
1495     // Let the irp continue on its way.
1496     //
1497     irp.PropagatePendingReturned();
1498 
1499     return irp.GetStatus();
1500 }
1501 
1502 _Must_inspect_result_
1503 NTSTATUS
1504 STDCALL
1505 FxPkgGeneral::_CreateCompletionRoutine2(
1506     __in MdDeviceObject DeviceObject,
1507     __in MdIrp           OriginalIrp,
1508     __in_opt PVOID      Context
1509     )
1510 /*++
1511 
1512 Routine Description:
1513 
1514     Routine Description:
1515 
1516         This completion routine is set only when the create request is forwarded by the
1517         framework to the lower driver. Framework forwards the create request using this
1518         completion routine if:
1519 
1520         1) Class extension's create callback is set by did not claim the request.
1521         2) Client driver did not register for a create callback or a create queue.
1522 
1523 Arguments:
1524 
1525 Return Value:
1526 
1527     STATUS_MORE_PROCESSING_REQUIRED
1528 
1529  --*/
1530 {
1531     FxRequest*  request;
1532     FxIrp       irp(OriginalIrp);
1533 
1534     UNREFERENCED_PARAMETER(DeviceObject);
1535 
1536     request = (FxRequest*) Context;
1537 
1538     ASSERT(request != NULL);
1539 
1540     irp.PropagatePendingReturned();
1541 
1542     request->Complete(irp.GetStatus());
1543 
1544     return STATUS_MORE_PROCESSING_REQUIRED;
1545 }
1546 
1547 _Must_inspect_result_
1548 NTSTATUS
1549 FxPkgGeneral::OnCleanup(
1550     __inout FxIrp* FxIrp
1551     )
1552 /*++
1553 
1554 Routine Description:
1555 
1556     Called in response to IRP_MJ_CLEANUP. This means an handle to
1557     the device is closed. After invoking the driver registered callback
1558     event, flush all the queues to cancel requests that belong to the
1559     file handle being closed. There is however a possibility for
1560     new requests to come in with the same fileobject.
1561 
1562 
1563 
1564 
1565 
1566 Arguments:
1567 
1568 Return Value:
1569 
1570     NTSTATUS
1571 
1572  --*/
1573 {
1574     NTSTATUS                status;
1575     FxFileObject*           pFxFO = NULL;
1576     WDFFILEOBJECT           hwdfFO = NULL;
1577     PLIST_ENTRY             next;
1578     FxFileObjectInfo*       fileObjInfo;
1579     MxFileObject            fileObject;
1580 
1581 
1582 
1583 
1584 
1585 
1586     //
1587     // Check to see if the fileobject represents a stream fileobject
1588     // created using IoCreateStreamFileObjectLite.
1589     //
1590     fileObject.SetFileObject(FxIrp->GetFileObject());
1591     if (FxIrp->GetFileObject() &&
1592         (fileObject.GetFlags() & FO_STREAM_FILE)){
1593         status = STATUS_SUCCESS;
1594         goto Passthru;
1595     }
1596 
1597     status = FxFileObject::_GetFileObjectFromWdm(
1598                  m_Device,
1599                  m_Device->GetFileObjectClass(),
1600                  FxIrp->GetFileObject(),
1601                  &pFxFO
1602                  );
1603 
1604     ASSERT(status == STATUS_SUCCESS);
1605 
1606     if (pFxFO != NULL && NT_SUCCESS(status)) {
1607         hwdfFO = pFxFO->GetHandle();
1608     }
1609 
1610     //
1611     // Invoke cleanup callbacks.
1612     //
1613     if (NULL == pFxFO) {
1614         //
1615         // Invoke cleanup callbacks of next layer (cx or client driver) based on the
1616         // autoforward setting of previous layer. (top to bottom).
1617         // AutoforwardCleanupClose set to FALSE with a not null create callback
1618         // means that create request was never forwarded to lower layer.
1619         //
1620         for (next = m_FileObjectInfoHeadList.Blink;
1621              next != &m_FileObjectInfoHeadList;
1622              next = next->Blink) {
1623 
1624              fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry);
1625 
1626              if (WdfFalse == fileObjInfo->AutoForwardCleanupClose &&
1627                  fileObjInfo->EvtCxFileCreate.Method != NULL) {
1628                  next = next->Blink; // one before the real start entry.
1629                  break;
1630              }
1631          }
1632      }
1633      else {
1634          //
1635          // 'OnCreate' sets this package context.
1636          //
1637          next = (PLIST_ENTRY) pFxFO->GetPkgCleanupCloseContext();
1638          if (NULL == next) {
1639              next = &m_FileObjectInfoHeadList;
1640          }
1641      }
1642 
1643     //
1644     // Invoke cleanup callbacks only if this layer (cx or client driver) had the
1645     // opprtunity to see the create request.
1646     //
1647     for (next = next->Flink;
1648          next != &m_FileObjectInfoHeadList;
1649          next = next->Flink) {
1650 
1651          fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry);
1652          fileObjInfo->EvtFileCleanup.Invoke(hwdfFO);
1653     }
1654 
1655     //
1656     // hwdfFO could be NULL depending on the FileObjectClass
1657     //
1658 
1659     //
1660     // Scan all the I/O queues associated with this device
1661     // and cancel the requests that matches with the handle
1662     // being closed. We will be able to cancel only requests that
1663     // are waiting to be dispatched. If the requests are already
1664     // presented to the driver then it's the responsibility of the
1665     // driver to complete them when the cleanup callback is invoked.
1666     //
1667     if(FxIrp->GetFileObject() != NULL ) {
1668         FxPkgIo*   pPkgIo;
1669 
1670         pPkgIo = (FxPkgIo*)m_Device->m_PkgIo;
1671         pPkgIo->FlushAllQueuesByFileObject(FxIrp->GetFileObject());
1672     }
1673 
1674 Passthru:
1675     if (m_Device->m_AutoForwardCleanupClose) {
1676         FxIrp->SkipCurrentIrpStackLocation();
1677         status = FxIrp->CallDriver(m_Device->GetAttachedDevice());
1678     } else {
1679         FxIrp->SetStatus(status);
1680         FxIrp->SetInformation(0);
1681         FxIrp->CompleteRequest(IO_NO_INCREMENT);
1682     }
1683 
1684     return status;
1685 
1686 }
1687 
1688 _Must_inspect_result_
1689 NTSTATUS
1690 FxPkgGeneral::OnClose(
1691     __inout FxIrp* FxIrp
1692     )
1693 /*++
1694 
1695 Routine Description:
1696 
1697     Called in response to IRP_MJ_CLOSE.  Invoke EvtFileClose event
1698     if registered and destroy the WDFFILEOBJECT.
1699 
1700 Arguments:
1701 
1702 Return Value:
1703 
1704     NTSTATUS
1705 
1706  --*/
1707 {
1708     NTSTATUS                status;
1709     FxFileObject*           pFxFO = NULL;
1710     WDFFILEOBJECT           hwdfFO = NULL;
1711     BOOLEAN                 isStreamFileObject = FALSE;
1712     BOOLEAN                 acquiredRemLock = FALSE;
1713     PLIST_ENTRY             next;
1714     FxFileObjectInfo*       fileObjInfo;
1715     MxFileObject            fileObject;
1716     MdIrp                   irp;
1717 
1718     //
1719     // FxIrp.CompleteRequest NULLs the m_Irp so store m_Irp separately
1720     // for use in ReleaseRemoveLock.
1721     //
1722     irp = FxIrp->GetIrp();
1723 
1724     //
1725     // Check to see if the fileobject represents a stream fileobject
1726     // created using IoCreateStreamFileObjectLite. If so, this is a
1727     // is spurious close sent by the I/O manager when it invalidates
1728     // the volumes (IopInvalidateVolumesForDevice).
1729     //
1730     fileObject.SetFileObject(FxIrp->GetFileObject());
1731     if (FxIrp->GetFileObject() &&
1732         (fileObject.GetFlags() & FO_STREAM_FILE)){
1733         isStreamFileObject = TRUE;
1734         status = STATUS_SUCCESS;
1735         goto Passthru;
1736     }
1737 
1738     status = FxFileObject::_GetFileObjectFromWdm(
1739         m_Device,
1740         m_Device->GetFileObjectClass(),
1741         FxIrp->GetFileObject(),
1742         &pFxFO
1743         );
1744 
1745     ASSERT(status == STATUS_SUCCESS);
1746 
1747     if (pFxFO != NULL && NT_SUCCESS(status)) {
1748         hwdfFO = pFxFO->GetHandle();
1749     }
1750 
1751     //
1752     // Invoke close callbacks.
1753     //
1754     if (NULL == pFxFO) {
1755         //
1756         // Invoke close callbacks of next layer (cx or client driver)  based on the autoforward
1757         // setting of previous layer. (top to bottom).
1758         // AutoforwardCleanupClose set to FALSE with a not null create callback
1759         // means that create request was never forwarded to lower layer.
1760         //
1761         for (next = m_FileObjectInfoHeadList.Blink;
1762              next != &m_FileObjectInfoHeadList;
1763              next = next->Blink) {
1764 
1765             fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry);
1766 
1767             if (WdfFalse == fileObjInfo->AutoForwardCleanupClose &&
1768                 fileObjInfo->EvtCxFileCreate.Method != NULL) {
1769                 next = next->Blink; // one before the real start entry.
1770                 break;
1771             }
1772         }
1773     }
1774     else {
1775         //
1776         // 'OnCreate' sets this package context.
1777         //
1778         next = (PLIST_ENTRY) pFxFO->GetPkgCleanupCloseContext();
1779         if (NULL == next) {
1780             next = &m_FileObjectInfoHeadList;
1781         }
1782     }
1783 
1784     //
1785     // Invoke close callbacks only if this layer (cx or client driver) had the opprtunity
1786     // to see the create request.
1787     //
1788     for (next = next->Flink;
1789          next != &m_FileObjectInfoHeadList;
1790          next = next->Flink) {
1791 
1792          fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry);
1793          fileObjInfo->EvtFileClose.Invoke(hwdfFO);
1794     }
1795 
1796     //
1797     // Destroy the WDFFILEOBJECT. This will result in
1798     // fileobject EvtCleanup and EvtDestroy event.
1799     //
1800     FxFileObject::_DestroyFileObject(
1801         m_Device,
1802         m_Device->GetFileObjectClass(),
1803         FxIrp->GetFileObject()
1804         );
1805 
1806 Passthru:
1807 
1808     if (m_Device->m_AutoForwardCleanupClose) {
1809         FxIrp->SkipCurrentIrpStackLocation();
1810         status = FxIrp->CallDriver(m_Device->GetAttachedDevice());
1811     } else {
1812         //
1813         // We're about to complete the request, but we need to decrement the
1814         // open handle count after we complete the request. However, completing
1815         // the request immediately opens the gate for the remove IRP to arrive
1816         // and run down the device. Hence we'll acquire the remove lock in order
1817         // to ensure that the device is not removed before we've decremented the
1818         // open handle count.
1819         //
1820 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
1821         acquiredRemLock = AcquireRemoveLockForClose(FxIrp);
1822 #endif
1823         FxIrp->SetStatus(status);
1824         FxIrp->SetInformation(0);
1825         FxIrp->CompleteRequest(IO_NO_INCREMENT);
1826     }
1827 
1828     if (isStreamFileObject == FALSE) {
1829         //
1830         // Note that after this call returns, this object may have been deleted!
1831 
1832 
1833 
1834 
1835 
1836 
1837 
1838 
1839         DecrementOpenHandleCount();
1840     }
1841 
1842     if (acquiredRemLock) {
1843         Mx::MxReleaseRemoveLock(m_Device->GetRemoveLock(),
1844                                 irp);
1845     }
1846 
1847     return status;
1848 
1849 }
1850 
1851 BOOLEAN
1852 FxPkgGeneral::AcquireRemoveLockForClose(
1853     __in  FxIrp* FxIrp
1854     )
1855 /*++
1856 
1857 Routine Description:
1858 
1859     For PNP devices, this routine acquires the remove lock when handling the
1860     close IRP.
1861 
1862 Arguments:
1863     Irp - Pointer to the close IRP
1864 
1865 Return Value:
1866 
1867     A BOOLEAN value that indicates whether or not the function actually acquired
1868         the remove lock
1869 
1870  --*/
1871 {
1872     NTSTATUS status;
1873     BOOLEAN lockAcquired;
1874     FxWdmDeviceExtension * wdmExtension = FxDevice::_GetFxWdmExtension(
1875             m_Device->GetDeviceObject());
1876 
1877     //
1878     // Initialization
1879     //
1880     lockAcquired = FALSE;
1881 
1882     //
1883     // We attempt to acquire the remove lock only for PNP device objects
1884     //
1885     if (m_Device->IsPnp() == FALSE) {
1886         goto Done;
1887     }
1888 
1889     //
1890     // If driver has opted in for remove lock for I/O operations we have
1891     // already acquired remove lock for Close so no need to do it again.
1892     //
1893     if (wdmExtension->RemoveLockOptionFlags &
1894             WDF_REMOVE_LOCK_OPTION_ACQUIRE_FOR_IO) {
1895         goto Done;
1896     }
1897 
1898     status = Mx::MxAcquireRemoveLock(
1899                 m_Device->GetRemoveLock(),
1900                 FxIrp->GetIrp());
1901     if (NT_SUCCESS(status)) {
1902         //
1903         // Successfully acquired the remove lock
1904         //
1905         lockAcquired = TRUE;
1906     } else {
1907         //
1908         // This is likely to have failed because we got the remove IRP and
1909         // called IoReleaseRemoveLockAndWait on another thread. This would
1910         // happen if there's a bug in the driver above us in the stack that
1911         // caused it to forward us the remove IRP before we completed the close
1912         // IRP.
1913         //
1914         // There's not much we can do now, since we're already racing against
1915         // the remove IRP.
1916         //
1917         PFX_DRIVER_GLOBALS pFxDriverGlobals;
1918 
1919         pFxDriverGlobals = GetDriverGlobals();
1920 
1921         DoTraceLevelMessage(
1922                     pFxDriverGlobals,
1923                     TRACE_LEVEL_ERROR,
1924                     TRACINGIO,
1925                     "Unable to acquire remove lock while handling the close IRP"
1926                     " 0x%p, %!STATUS!",
1927                     FxIrp->GetIrp(), status);
1928 
1929         if (pFxDriverGlobals->IsVerificationEnabled(1,9, OkForDownLevel)) {
1930             FxVerifierDbgBreakPoint(pFxDriverGlobals);
1931         }
1932     }
1933 
1934 Done:
1935     return lockAcquired;
1936 }
1937 
1938 
1939 _Must_inspect_result_
1940 NTSTATUS
1941 FxPkgGeneral::OnShutdown(
1942     __inout FxIrp* FxIrp
1943     )
1944 /*++
1945 
1946 Routine Description:
1947 
1948     Called in response to IRP_MJ_SHUTDOWN.
1949 
1950 Arguments:
1951 
1952 Return Value:
1953 
1954     NTSTATUS
1955 
1956  --*/
1957 {
1958     NTSTATUS status;
1959 
1960     m_EvtDeviceShutdown.Invoke(m_Device->GetHandle());
1961 
1962     if(m_Device->IsFilter()) {
1963         FxIrp->SkipCurrentIrpStackLocation();
1964         status = FxIrp->CallDriver(m_Device->GetAttachedDevice());
1965     }
1966     else {
1967         status = STATUS_SUCCESS;
1968         FxIrp->SetStatus(status);
1969         FxIrp->SetInformation(0);
1970         FxIrp->CompleteRequest(IO_NO_INCREMENT);
1971     }
1972 
1973     return status;
1974 
1975 }
1976 
1977 VOID
1978 FxPkgGeneral::DecrementOpenHandleCount(
1979     VOID
1980     )
1981 {
1982     if (InterlockedDecrement(&m_OpenHandleCount) == 0 && m_Device->IsLegacy()) {
1983         m_Device->ControlDeviceDelete();
1984     }
1985 }
1986 
1987 BOOLEAN
1988 FxPkgGeneral::CanDestroyControlDevice(
1989     VOID
1990     )
1991 {
1992     //
1993     // Remove the bias of one that we use to track if a control device should be
1994     // deleted.
1995     //
1996     if (InterlockedDecrement(&m_OpenHandleCount) == 0) {
1997         return TRUE;
1998     }
1999     else {
2000         return FALSE;
2001     }
2002 
2003 }
2004 
2005 VOID
2006 FxPkgGeneral::GetConstraintsHelper(
2007     __out_opt WDF_EXECUTION_LEVEL*       ExecutionLevel,
2008     __out_opt WDF_SYNCHRONIZATION_SCOPE* SynchronizationScope
2009     )
2010 /*++
2011 
2012 Routine Description:
2013     This routine is the helper routine and is used by FxFileObject to get the
2014     ExecutionLevel and SynchronizationScope.
2015 
2016 Arguments:
2017 
2018 Return Value:
2019     VOID
2020 
2021 --*/
2022 
2023 {
2024     if (ExecutionLevel != NULL) {
2025         *ExecutionLevel = m_ExecutionLevel;
2026     }
2027 
2028     if (SynchronizationScope != NULL) {
2029         *SynchronizationScope = m_SynchronizationScope;
2030     }
2031 }
2032 
2033 FxCallbackLock*
2034 FxPkgGeneral::GetCallbackLockPtrHelper(
2035     __deref_out_opt FxObject** LockObject
2036     )
2037 /*++
2038 
2039 Routine Description:
2040     This routine is the helper routine and is used by FxFileObject to get the
2041     LockObject.
2042 
2043 
2044 Arguments:
2045 
2046 Return Value:
2047     FxCallbackLock *
2048 
2049 --*/
2050 
2051 {
2052     if (LockObject != NULL) {
2053         *LockObject = m_CallbackLockObjectPtr;
2054     }
2055 
2056     return m_CallbackLockPtr;
2057 }
2058 
2059 
2060