1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxDevice.cpp
8 
9 Abstract:
10 
11     This is the class implementation for the base Device class.
12 
13 Author:
14 
15 
16 
17 Environment:
18 
19     Both kernel and user mode
20 
21 Revision History:
22 
23 --*/
24 
25 #include "coreprivshared.hpp"
26 
27 extern "C" {
28 // #include "FxDevice.tmh"
29 }
30 
31 //
32 // This table contains the mapping between device type and the
33 // default priority boost used by the the framework when
34 // an I/O request is completed. The DeviceObject->DeviceType
35 // is used as an index into this table.
36 //
37 const CHAR FxDevice::m_PriorityBoosts[] = {
38     IO_NO_INCREMENT,        // FILE_DEVICE_UNDEFINED           0x00000000
39     IO_NO_INCREMENT,        // FILE_DEVICE_BEEP                0x00000001
40     IO_CD_ROM_INCREMENT,    // FILE_DEVICE_CD_ROM              0x00000002
41     IO_CD_ROM_INCREMENT,    // FILE_DEVICE_CD_ROM_FILE_SYSTEM  0x00000003
42     IO_NO_INCREMENT,        // FILE_DEVICE_CONTROLLER          0x00000004
43     IO_NO_INCREMENT,        // FILE_DEVICE_DATALINK            0x00000005
44     IO_NO_INCREMENT,        // FILE_DEVICE_DFS                 0x00000006
45     IO_DISK_INCREMENT,      // FILE_DEVICE_DISK                0x00000007
46     IO_DISK_INCREMENT,      // FILE_DEVICE_DISK_FILE_SYSTEM    0x00000008
47     IO_NO_INCREMENT,        // FILE_DEVICE_FILE_SYSTEM         0x00000009
48     IO_NO_INCREMENT,        // FILE_DEVICE_INPORT_PORT         0x0000000a
49     IO_KEYBOARD_INCREMENT,  // FILE_DEVICE_KEYBOARD            0x0000000b
50     IO_MAILSLOT_INCREMENT,  // FILE_DEVICE_MAILSLOT            0x0000000c
51     IO_SOUND_INCREMENT,     // FILE_DEVICE_MIDI_IN             0x0000000d
52     IO_SOUND_INCREMENT,     // FILE_DEVICE_MIDI_OUT            0x0000000e
53     IO_MOUSE_INCREMENT,     // FILE_DEVICE_MOUSE               0x0000000f
54     IO_NO_INCREMENT,        // FILE_DEVICE_MULTI_UNC_PROVIDER  0x00000010
55     IO_NAMED_PIPE_INCREMENT,// FILE_DEVICE_NAMED_PIPE          0x00000011
56     IO_NETWORK_INCREMENT,   // FILE_DEVICE_NETWORK             0x00000012
57     IO_NETWORK_INCREMENT,   // FILE_DEVICE_NETWORK_BROWSER     0x00000013
58     IO_NETWORK_INCREMENT,   // FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014
59     IO_NO_INCREMENT,        // FILE_DEVICE_NULL                0x00000015
60     IO_PARALLEL_INCREMENT,  // FILE_DEVICE_PARALLEL_PORT       0x00000016
61     IO_NETWORK_INCREMENT,   // FILE_DEVICE_PHYSICAL_NETCARD    0x00000017
62     IO_NO_INCREMENT,        // FILE_DEVICE_PRINTER             0x00000018
63     IO_NO_INCREMENT,        // FILE_DEVICE_SCANNER             0x00000019
64     IO_SERIAL_INCREMENT,    // FILE_DEVICE_SERIAL_MOUSE_PORT   0x0000001a
65     IO_SERIAL_INCREMENT,    // FILE_DEVICE_SERIAL_PORT         0x0000001b
66     IO_VIDEO_INCREMENT,     // FILE_DEVICE_SCREEN              0x0000001c
67     IO_SOUND_INCREMENT,     // FILE_DEVICE_SOUND               0x0000001d
68     IO_SOUND_INCREMENT,     // FILE_DEVICE_STREAMS             0x0000001e
69     IO_NO_INCREMENT,        // FILE_DEVICE_TAPE                0x0000001f
70     IO_NO_INCREMENT,        // FILE_DEVICE_TAPE_FILE_SYSTEM    0x00000020
71     IO_NO_INCREMENT,        // FILE_DEVICE_TRANSPORT           0x00000021
72     IO_NO_INCREMENT,        // FILE_DEVICE_UNKNOWN             0x00000022
73     IO_VIDEO_INCREMENT,     // FILE_DEVICE_VIDEO               0x00000023
74     IO_DISK_INCREMENT,      // FILE_DEVICE_VIRTUAL_DISK        0x00000024
75     IO_SOUND_INCREMENT,     // FILE_DEVICE_WAVE_IN             0x00000025
76     IO_SOUND_INCREMENT,     // FILE_DEVICE_WAVE_OUT            0x00000026
77     IO_KEYBOARD_INCREMENT,  // FILE_DEVICE_8042_PORT           0x00000027
78     IO_NETWORK_INCREMENT,   // FILE_DEVICE_NETWORK_REDIRECTOR  0x00000028
79     IO_NO_INCREMENT,        // FILE_DEVICE_BATTERY             0x00000029
80     IO_NO_INCREMENT,        // FILE_DEVICE_BUS_EXTENDER        0x0000002a
81     IO_SERIAL_INCREMENT,    // FILE_DEVICE_MODEM               0x0000002b
82     IO_NO_INCREMENT,        // FILE_DEVICE_VDM                 0x0000002c
83     IO_DISK_INCREMENT,      // FILE_DEVICE_MASS_STORAGE        0x0000002d
84     IO_NETWORK_INCREMENT,   // FILE_DEVICE_SMB                 0x0000002e
85     IO_SOUND_INCREMENT,     // FILE_DEVICE_KS                  0x0000002f
86     IO_NO_INCREMENT,        // FILE_DEVICE_CHANGER             0x00000030
87     IO_NO_INCREMENT,        // FILE_DEVICE_SMARTCARD           0x00000031
88     IO_NO_INCREMENT,        // FILE_DEVICE_ACPI                0x00000032
89     IO_NO_INCREMENT,        // FILE_DEVICE_DVD                 0x00000033
90     IO_VIDEO_INCREMENT,     // FILE_DEVICE_FULLSCREEN_VIDEO    0x00000034
91     IO_NO_INCREMENT,        // FILE_DEVICE_DFS_FILE_SYSTEM     0x00000035
92     IO_NO_INCREMENT,        // FILE_DEVICE_DFS_VOLUME          0x00000036
93     IO_SERIAL_INCREMENT,    // FILE_DEVICE_SERENUM             0x00000037
94     IO_NO_INCREMENT,        // FILE_DEVICE_TERMSRV             0x00000038
95     IO_NO_INCREMENT,        // FILE_DEVICE_KSEC                0x00000039
96     IO_NO_INCREMENT,        // FILE_DEVICE_FIPS                0x0000003A
97     IO_NO_INCREMENT,        // FILE_DEVICE_INFINIBAND          0x0000003B
98 };
99 
100 NTSTATUS
_CompletionRoutineForRemlockMaintenance(__in MdDeviceObject DeviceObject,__in MdIrp Irp,__in PVOID Context)101 FxDevice::_CompletionRoutineForRemlockMaintenance(
102     __in MdDeviceObject   DeviceObject,
103     __in MdIrp             Irp,
104     __in PVOID            Context
105     )
106 /*++
107 
108 Routine Description:
109 
110     A completion routine for the IRPs for which we acquired opt-in remove lock.
111 
112 Arguments:
113     DeviceObject - Pointer to deviceobject
114     Irp          - Pointer to the Irp for which we acquired opt-in remove lock.
115     Context      - NULL
116 Return Value:
117 
118     NT Status is returned.
119 
120 --*/
121 
122 {
123     FxIrp irp(Irp);
124 
125     UNREFERENCED_PARAMETER(Context);
126 
127     //
128     // Let the irp continue on its way.
129     //
130     irp.PropagatePendingReturned();
131 
132 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
133     Mx::MxReleaseRemoveLock(&((FxDevice::_GetFxWdmExtension(
134                             DeviceObject))->IoRemoveLock), Irp);
135 #else
136     UNREFERENCED_PARAMETER(DeviceObject);
137 #endif
138 
139     return STATUS_CONTINUE_COMPLETION;
140 }
141 
142 
FxDevice(__in FxDriver * ArgDriver)143 FxDevice::FxDevice(
144     __in FxDriver *ArgDriver
145     ) :
146     FxDeviceBase(ArgDriver->GetDriverGlobals(), ArgDriver, FX_TYPE_DEVICE, sizeof(FxDevice)),
147     m_ParentDevice(NULL)
148 {
149     SetInitialState();
150 }
151 
152 VOID
SetInitialState(VOID)153 FxDevice::SetInitialState(
154     VOID
155     )
156 {
157     //
158     // Set the initial device state
159     //
160     m_CurrentPnpState           = WdfDevStatePnpObjectCreated;
161     m_CurrentPowerState         = WdfDevStatePowerObjectCreated;
162     m_CurrentPowerPolicyState   = WdfDevStatePwrPolObjectCreated;
163 
164     //
165     // Set the default IO type to "buffered"
166     //
167     m_ReadWriteIoType = WdfDeviceIoBuffered;
168 
169     RtlZeroMemory(&m_DeviceName, sizeof(m_DeviceName));
170     RtlZeroMemory(&m_SymbolicLinkName, sizeof(m_SymbolicLinkName));
171     RtlZeroMemory(&m_MofResourceName, sizeof(m_MofResourceName));
172 
173     m_Filter = FALSE;
174     m_Exclusive = FALSE;
175     m_PowerPageableCapable = FALSE;
176     m_ParentWaitingOnChild = FALSE;
177     m_Legacy = FALSE;
178     m_DeviceObjectDeleted = FALSE;
179     m_PdoKnown = FALSE;
180     m_Legacy = FALSE;
181     m_AutoForwardCleanupClose = FALSE;
182     m_SelfIoTargetNeeded = FALSE;
183     m_DeviceTelemetryInfoFlags = 0;
184 
185     //
186     // Clear all packages by default
187     //
188 
189     m_PkgIo      = NULL;
190     m_PkgPnp     = NULL;
191     m_PkgGeneral = NULL;
192     m_PkgWmi     = NULL;
193     m_PkgDefault  = NULL;
194 
195     InitializeListHead(&m_PreprocessInfoListHead);
196     InitializeListHead(&m_CxDeviceInfoListHead);
197 
198 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
199     m_FileObjectClass = WdfFileObjectNotRequired;
200 #else // UMDF
201     //
202     // In UMDF file object is always required. So indicate that now.
203     //
204     m_FileObjectClass = WdfFileObjectWdfCannotUseFsContexts;
205 #endif
206 
207     m_DefaultPriorityBoost = IO_NO_INCREMENT;
208 
209     InitializeListHead(&m_FileObjectListHead);
210 
211     m_RequestLookasideListElementSize = 0;
212     RtlZeroMemory(&m_RequestLookasideList, sizeof(m_RequestLookasideList));
213     RtlZeroMemory(&m_RequestAttributes, sizeof(m_RequestAttributes));
214 
215 #if (FX_CORE_MODE == FX_CORE_USER_MODE)
216     //
217     // Init UMDF specific members
218     //
219     m_CleanupFromFailedCreate = FALSE;
220     m_Dispatcher = NULL;
221     m_DevStack = NULL;
222     m_PdoDevKey = NULL;
223     m_DeviceKeyPath = NULL;
224     m_KernelDeviceName = NULL;
225     m_DeviceInstanceId = NULL;
226 
227     m_RetrievalMode = UMINT::WdfDeviceIoBufferRetrievalDeferred;
228     m_IoctlIoType = WdfDeviceIoBuffered;
229     m_DirectTransferThreshold = 0;
230 
231     m_DirectHardwareAccess = FX_DIRECT_HARDWARE_ACCESS_DEFAULT;
232     m_RegisterAccessMode = FX_REGISTER_ACCESS_MODE_DEFAULT;
233     m_FileObjectPolicy = FX_FILE_OBJECT_POLICY_DEFAULT;
234     m_FsContextUsePolicy = FX_FS_CONTEXT_USE_POLICY_DEFAULT;
235     m_InteruptThreadpool = NULL;
236 #endif
237 }
238 
~FxDevice()239 FxDevice::~FxDevice()
240 {
241     PLIST_ENTRY next;
242 
243     // Make it always present right now even on free builds
244     if (IsDisposed() == FALSE) {
245         DoTraceLevelMessage(
246             GetDriverGlobals(), TRACE_LEVEL_FATAL, TRACINGDEVICE,
247             "FxDevice 0x%p not disposed: this maybe a driver reference count "
248             "problem with WDFDEVICE %p", this, GetObjectHandleUnchecked());
249 
250         FxVerifierBugCheck(GetDriverGlobals(),
251                            WDF_OBJECT_ERROR,
252                            (ULONG_PTR) GetObjectHandleUnchecked(),
253                            (ULONG_PTR) this);
254     }
255 
256     //
257     // Execute mode-specific destructor. Noop for KMDF, but does
258     // does detach and delete of UM device object for UMDF. Therefore
259     // can be done before other cleanup.
260     //
261     DestructorInternal();
262 
263     //
264     // If the device has been initialized but hasn't yet been
265     // destroyed, destroy it now.
266     //
267 
268 
269 
270 
271 
272 
273 
274     ASSERT(m_DeviceObject.GetObject() == NULL);
275 
276     ASSERT(m_DeviceName.Buffer == NULL);
277 
278 #if FX_CORE_MODE == FX_CORE_KERNEL_MODE
279     //
280     // Assert only applicable to KM because FxDevice can get destroyed in UMDF
281     // without going through normal pnp remove path, for example, when an
282     // AddDevice failure is done in reflector, after all um drivers have
283     // succeeded AddDevice. KMDF and host use fake remove irp to handle
284     // AddDevice failure in KMDF and host respectively, but reflector does not
285     // do that for AddDevice failure that happens in reflector.
286     // Note that symbolicName buffer will anyway be deleted in this destructor
287     // later on so the symbolic link buffer doesn't leak out.
288     //
289     ASSERT(m_SymbolicLinkName.Buffer == NULL);
290 #endif
291 
292     ASSERT(m_MofResourceName.Buffer == NULL);
293 
294     if (m_PkgIo != NULL) {
295         m_PkgIo->RELEASE(NULL);
296         m_PkgIo = NULL;
297     }
298 
299     if (m_PkgPnp != NULL) {
300         m_PkgPnp->RELEASE(NULL);
301         m_PkgPnp = NULL;
302     }
303 
304     if (m_PkgGeneral != NULL) {
305         m_PkgGeneral->RELEASE(NULL);
306         m_PkgGeneral = NULL;
307     }
308 
309     if (m_PkgWmi != NULL) {
310         m_PkgWmi->RELEASE(NULL);
311         m_PkgWmi = NULL;
312     }
313 
314     if (m_PkgDefault != NULL) {
315         m_PkgDefault->RELEASE(NULL);
316         m_PkgDefault = NULL;
317     }
318 
319     while (!IsListEmpty(&m_PreprocessInfoListHead)) {
320         next = RemoveHeadList(&m_PreprocessInfoListHead);
321         FxIrpPreprocessInfo* info;
322         info = CONTAINING_RECORD(next, FxIrpPreprocessInfo, ListEntry);
323         InitializeListHead(next);
324         delete info;
325     }
326 
327     while (!IsListEmpty(&m_CxDeviceInfoListHead)) {
328         next = RemoveHeadList(&m_CxDeviceInfoListHead);
329         FxCxDeviceInfo* info;
330         info = CONTAINING_RECORD(next, FxCxDeviceInfo, ListEntry);
331         InitializeListHead(next);
332         delete info;
333     }
334 
335     //
336     // Clean up any referenced objects
337     //
338     if (m_DeviceName.Buffer != NULL) {
339         FxPoolFree(m_DeviceName.Buffer);
340         RtlZeroMemory(&m_DeviceName, sizeof(m_DeviceName));
341     }
342 
343     DeleteSymbolicLink();
344 
345     if (m_MofResourceName.Buffer != NULL) {
346         FxPoolFree(m_MofResourceName.Buffer);
347         RtlZeroMemory(&m_MofResourceName, sizeof(m_DeviceName));
348     }
349 
350     //
351     // m_RequestLookasideListElementSize will be set to non zero if we have
352     // initialized the request lookaside list.
353     //
354     if (m_RequestLookasideListElementSize != 0) {
355         Mx::MxDeleteNPagedLookasideList(&m_RequestLookasideList);
356         m_RequestLookasideListElementSize = 0;
357     }
358 
359     if (m_ParentDevice != NULL) {
360         m_ParentDevice->RELEASE(this);
361     }
362 }
363 
364 _Must_inspect_result_
365 NTSTATUS
_Create(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in PWDFDEVICE_INIT * DeviceInit,__in_opt PWDF_OBJECT_ATTRIBUTES DeviceAttributes,__out FxDevice ** Device)366 FxDevice::_Create(
367     __in PFX_DRIVER_GLOBALS FxDriverGlobals,
368     __in PWDFDEVICE_INIT* DeviceInit,
369     __in_opt PWDF_OBJECT_ATTRIBUTES DeviceAttributes,
370     __out FxDevice** Device
371     )
372 {
373     PWDFDEVICE_INIT     pInit;
374     FxDevice*           pDevice;
375     NTSTATUS            status;
376     WDFOBJECT           object;
377     PLIST_ENTRY         pNext;
378     PWDFCXDEVICE_INIT   pCxInit;
379     FxWdmDeviceExtension* wdmDeviceExtension;
380 
381     *Device = NULL;
382     pInit = *DeviceInit;
383 
384     pDevice = new (FxDriverGlobals, DeviceAttributes)
385         FxDevice(pInit->Driver);
386 
387     if (pDevice == NULL) {
388         status = STATUS_INSUFFICIENT_RESOURCES;
389         goto Done;
390     }
391 
392     status = pDevice->Initialize(pInit, DeviceAttributes);
393     if (!NT_SUCCESS(status)) {
394         goto Done;
395     }
396 
397     switch (pInit->InitType) {
398     case FxDeviceInitTypeFdo:
399         status = pDevice->FdoInitialize(pInit);
400         break;
401 
402     case FxDeviceInitTypePdo:
403         status = pDevice->PdoInitialize(pInit);
404         break;
405 
406     case FxDeviceInitTypeControlDevice:
407         status = pDevice->ControlDeviceInitialize(pInit);
408         break;
409 
410     default:
411         //
412         // Should not drop here
413         //
414         ASSERT(FALSE);
415         break;
416     }
417     if (!NT_SUCCESS(status)) {
418         goto Done;
419     }
420 
421     //
422     // Ok, we have created the device.  Now lets create a handle for it.
423     //
424     status = pDevice->PostInitialize();
425     if (!NT_SUCCESS(status)) {
426         goto Done;
427     }
428 
429     //
430     // Can't use the PDO's FxDevice m_Parent as the object hierarchy parent
431     // because the Fx object hierarchy lifetime rules do not match the
432     // rules for a pnp PDO lifetime vs its FDO.
433     //
434     status = pDevice->Commit(DeviceAttributes,
435                              &object,
436                              pDevice->GetDriver());
437     if (!NT_SUCCESS(status)) {
438         goto Done;
439     }
440 
441     //
442     // NOTE: ---> DO NOT FAIL FROM HERE FORWARD <---
443     //
444 
445     //
446     // Up until now we have not reassigned any of the allocations in pInit
447     // and assigned them to the underlying objects.  We are now at the point
448     // of "no return", ie we cannot fail.  If we reassigned the allocations
449     // before this point and the driver retried to create the device (let's
450     // say with a different name), we would have freed those allocations
451     // and the driver writer would have thought that particular settings
452     // we valid, but were not b/c we freed them on error.  So, to avoid a
453     // huge tracking mess, we only grab the allocations once we know for
454     // *sure* we are going to return success.
455     //
456     if (pInit->DeviceName != NULL) {
457         pInit->DeviceName->ReleaseString(&pDevice->m_DeviceName);
458     }
459 
460     //
461     // Check for driver preprocess requirements.
462     //
463     if (pInit->PreprocessInfo != NULL) {
464         ASSERT( pInit->PreprocessInfo->ClassExtension == FALSE);
465         ASSERT(IsListEmpty(&pDevice->m_PreprocessInfoListHead));
466         InsertTailList(&pDevice->m_PreprocessInfoListHead,
467                         &pInit->PreprocessInfo->ListEntry);
468         pInit->PreprocessInfo = NULL;
469 
470         //
471         // If the driver is preprocessing requests on this device, they need
472         // their own stack location so that they can set their own completion
473         // routine.
474         //
475         pDevice->SetStackSize(pDevice->GetStackSize()+1);
476     }
477 
478 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
479     wdmDeviceExtension = _GetFxWdmExtension(pDevice->GetDeviceObject());
480     if (wdmDeviceExtension->RemoveLockOptionFlags &
481             WDF_REMOVE_LOCK_OPTION_ACQUIRE_FOR_IO) {
482         //
483         // We will use a completion routine for remlock maintenance
484         //
485         pDevice->SetStackSize(pDevice->GetStackSize()+1);
486     }
487 
488     //
489     // Note: In case of UMDF StackSize is incremented prior to attaching
490     // the device to stack. See the comment in FxDeviceUm.cpp
491     //
492     if (pDevice->m_SelfIoTargetNeeded) {
493         pDevice->SetStackSize(pDevice->GetStackSize()+1);
494     }
495 
496 #else
497     UNREFERENCED_PARAMETER(wdmDeviceExtension);
498 #endif
499 
500     //
501     // Check for any class-extensions' preprocess requirements.
502     //
503     for (pNext = pInit->CxDeviceInitListHead.Flink;
504          pNext != &pInit->CxDeviceInitListHead;
505          pNext = pNext->Flink) {
506 
507         pCxInit = CONTAINING_RECORD(pNext, WDFCXDEVICE_INIT, ListEntry);
508 
509         if (pCxInit->PreprocessInfo != NULL) {
510             ASSERT(pCxInit->PreprocessInfo->ClassExtension);
511             InsertTailList(&pDevice->m_PreprocessInfoListHead,
512                            &pCxInit->PreprocessInfo->ListEntry);
513             pCxInit->PreprocessInfo = NULL;
514 
515             //
516             // If the class extension is preprocessing requests on this
517             // device, it needs its own stack location so that it can
518             // set its own completion routine.
519             //
520             pDevice->SetStackSize(pDevice->GetStackSize()+1);
521         }
522     }
523 
524     if (pDevice->IsPnp()) {
525         //
526         // Take all of the allocations out of pInit related to pnp.  This
527         // will also transition the pnp state machine into the added state.
528         //
529         pDevice->m_PkgPnp->FinishInitialize(pInit);
530     }
531 
532     pInit->CreatedDevice = pDevice;
533 
534     //
535     // Clear out the pointer, we freed it on behalf of the caller
536     //
537     *DeviceInit = NULL;
538 
539     if (pInit->CreatedOnStack == FALSE) {
540         delete pInit;
541     }
542 
543 Done:
544     if (!NT_SUCCESS(status) && pDevice != NULL) {
545         //
546         // We want to propagate the original error code
547         //
548         (void) pDevice->DeleteDeviceFromFailedCreate(status, FALSE);
549         pDevice = NULL;
550     }
551 
552     *Device = pDevice;
553 
554     return status;
555 }
556 
557 _Must_inspect_result_
558 NTSTATUS
DeleteDeviceFromFailedCreateNoDelete(__in NTSTATUS FailedStatus,__in BOOLEAN UseStateMachine)559 FxDevice::DeleteDeviceFromFailedCreateNoDelete(
560     __in NTSTATUS FailedStatus,
561     __in BOOLEAN UseStateMachine
562     )
563 {
564     //
565     // Cleanup the device, the driver may have allocated resources
566     // associated with the WDFDEVICE
567     //
568     DoTraceLevelMessage(
569         GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
570         "WDFDEVICE %p !devobj %p created, but EvtDriverDeviceAdd returned "
571         "status %!STATUS! or failure in creation",
572         GetObjectHandleUnchecked(), GetDeviceObject(), FailedStatus);
573 
574     //
575     // We do not let filters affect the building of the rest of the stack.
576     // If they return error, we convert it to STATUS_SUCCESS, remove the
577     // attached device from the stack, and cleanup.
578     //
579     if (IsFilter()) {
580         DoTraceLevelMessage(
581             GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
582             "WDFDEVICE %p, !devobj %p is a filter, converting %!STATUS! to"
583             " STATUS_SUCCESS", GetObjectHandleUnchecked(), GetDeviceObject(),
584             FailedStatus);
585         FailedStatus = STATUS_SUCCESS;
586     }
587 
588     if (UseStateMachine) {
589         MxEvent waitEvent;
590 
591         //
592         // See comments for m_CleanupFromFailedCreate in class definition file
593         // for use of this statement.
594         //
595         SetCleanupFromFailedCreate(TRUE);
596 
597 
598 
599 
600 
601         waitEvent.Initialize(SynchronizationEvent, FALSE);
602         m_PkgPnp->CleanupDeviceFromFailedCreate(waitEvent.GetSelfPointer());
603     }
604     else {
605         //
606         // Upon certain types of failure, like STATUS_OBJECT_NAME_COLLISION, we
607         // could keep the pDevice around and the caller retry after changing
608         // a property, but the simpler route for now is to just recreate
609         // everything from scratch on the retry.
610         //
611         // Usually the pnp state machine will do this and the FxDevice destructor
612         // relies on it running b/c it does some cleanup.
613         //
614         EarlyDispose();
615         DestroyChildren();
616 
617         //
618         // Wait for all children to drain out and cleanup.
619         //
620         if (m_DisposeList != NULL) {
621             m_DisposeList->WaitForEmpty();
622         }
623 
624         //
625         // We keep a reference on m_PkgPnp which is released in the destructor
626         // so  we can safely touch m_PkgPnp after destroying all of the child
627         // objects.
628         //
629         if (m_PkgPnp != NULL) {
630             m_PkgPnp->CleanupStateMachines(TRUE);
631         }
632     }
633 
634     //
635     // This will detach and delete the device object
636     //
637     Destroy();
638 
639     return FailedStatus;
640 }
641 
642 _Must_inspect_result_
643 NTSTATUS
DeleteDeviceFromFailedCreate(__in NTSTATUS FailedStatus,__in BOOLEAN UseStateMachine)644 FxDevice::DeleteDeviceFromFailedCreate(
645     __in NTSTATUS FailedStatus,
646     __in BOOLEAN UseStateMachine
647     )
648 {
649     NTSTATUS status;
650 
651     status = DeleteDeviceFromFailedCreateNoDelete(FailedStatus, UseStateMachine);
652 
653     //
654     // Delete the Fx object now
655     //
656     DeleteObject();
657 
658     return status;
659 }
660 
661 _Must_inspect_result_
662 NTSTATUS
Initialize(__in PWDFDEVICE_INIT DeviceInit,__in_opt PWDF_OBJECT_ATTRIBUTES DeviceAttributes)663 FxDevice::Initialize(
664     __in PWDFDEVICE_INIT DeviceInit,
665     __in_opt PWDF_OBJECT_ATTRIBUTES DeviceAttributes
666     )
667 /*++
668 
669 Routine Description:
670     Generic initialization for an FxDevice regardless of role (pdo, fdo, control).
671 
672 Arguments:
673 
674 
675 Return Value:
676 
677 
678   --*/
679 
680 {
681     PFX_DRIVER_GLOBALS  pGlobals;
682     PLIST_ENTRY         next;
683     NTSTATUS            status;
684     size_t              reqCtxSize;
685     PWDFCXDEVICE_INIT   cxInit;
686     CCHAR               cxIndex;
687     FxCxDeviceInfo*     cxDeviceInfo;
688 
689     pGlobals    = GetDriverGlobals();
690     m_Exclusive = DeviceInit->Exclusive;
691     cxIndex     = 0;
692 
693     MarkDisposeOverride(ObjectDoNotLock);
694 
695     //
696     // Configure device constraints.
697     //
698     status = ConfigureConstraints(DeviceAttributes);
699     if (!NT_SUCCESS(status)) {
700         return status;
701     }
702 
703     //
704     // Generic catch all
705     //
706     m_PkgDefault = new (pGlobals) FxDefaultIrpHandler(pGlobals, (CfxDevice*)this);
707     if (m_PkgDefault == NULL) {
708         return STATUS_INSUFFICIENT_RESOURCES;
709     }
710 
711     InstallPackage(m_PkgDefault);
712 
713     if (DeviceInit->InitType == FxDeviceInitTypeControlDevice) {
714         m_Legacy = TRUE;
715     }
716 
717     //
718     // Size will be set to a non zero if the driver wants request attributes
719     // associated with each created request.
720     //
721     if (DeviceInit->RequestAttributes.Size  != 0) {
722         ASSERT(DeviceInit->RequestAttributes.Size == sizeof(WDF_OBJECT_ATTRIBUTES));
723         RtlCopyMemory(&m_RequestAttributes,
724                       &DeviceInit->RequestAttributes,
725                       sizeof(DeviceInit->RequestAttributes));
726     }
727 
728     reqCtxSize = FxGetContextSize(&m_RequestAttributes);
729 
730     //
731     // If present, setup a I/O class extensions info chain.
732     //
733     for (next = DeviceInit->CxDeviceInitListHead.Flink;
734          next != &DeviceInit->CxDeviceInitListHead;
735          next = next->Flink) {
736 
737         cxInit = CONTAINING_RECORD(next, WDFCXDEVICE_INIT, ListEntry);
738 
739         cxDeviceInfo = new(pGlobals) FxCxDeviceInfo(pGlobals);
740         if (NULL == cxDeviceInfo) {
741             return STATUS_INSUFFICIENT_RESOURCES;
742         }
743 
744         cxDeviceInfo->Index = ++cxIndex; // 1-based.
745         cxDeviceInfo->Driver = cxInit->CxDriverGlobals->Driver;
746         cxDeviceInfo->IoInCallerContextCallback.m_Method =
747                         cxInit->IoInCallerContextCallback;
748         cxDeviceInfo->RequestAttributes = cxInit->RequestAttributes;
749 
750         InsertTailList(&m_CxDeviceInfoListHead, &cxDeviceInfo->ListEntry);
751 
752         //
753         // Set weak ref to this run-time cx struct to help file-object logic later on.
754         //
755         cxInit->CxDeviceInfo = cxDeviceInfo;
756 
757         //
758         // Find the max size for the request context. Used below.
759         //
760         ASSERT(cxInit->RequestAttributes.Size == 0 ||
761                cxInit->RequestAttributes.Size == sizeof(WDF_OBJECT_ATTRIBUTES));
762 
763         reqCtxSize = MAX(FxGetContextSize(&cxInit->RequestAttributes),
764                          reqCtxSize);
765     }
766 
767     //
768     // Memory layout for memory backing FxRequest which is allocated from the
769     // lookaside list:
770     //
771     // If we are tracking memory, the allocation layout is
772     // 0x0                                                 - FX_POOL_TRACKER
773     // 0x0 + sizeof(FX_POOL_TRACKER)                       - FX_POOL_HEADER
774     // 0x0 + sizeof(FX_POOL_TRACKER) + FX_POOL_HEADER_SIZE - start of FxRequest
775     //
776     // if no tracking is occuring, the allocation layout is
777     // 0x0                                                 - FX_POOL_HEADER
778     // 0x0 + FX_POOL_HEADER_SIZE                           - start of FxRequest
779     //
780     // NOTE:  If the computation of m_RequestLookasideListElementSize changes,
781     //        FxDevice::AllocateRequestMemory and FxDevice::FreeRequestMemory will also
782     //        need to be updated to reflect the changes made.
783     //
784     status = FxCalculateObjectTotalSize2(pGlobals,
785                                          sizeof(FxRequest),
786                                          0,
787                                          reqCtxSize,
788                                          &m_RequestLookasideListElementSize);
789     if (!NT_SUCCESS(status)) {
790         return status;
791     }
792 
793     status = FxPoolAddHeaderSize(pGlobals,
794                                  m_RequestLookasideListElementSize,
795                                  &m_RequestLookasideListElementSize);
796 
797     if (!NT_SUCCESS(status)) {
798         //
799         // FxPoolAddHeaderSize will log to the IFR on error
800         //
801         return status;
802     }
803 
804     Mx::MxInitializeNPagedLookasideList(&m_RequestLookasideList,
805                                     NULL,
806                                     NULL,
807                                     0,
808                                     m_RequestLookasideListElementSize,
809                                     pGlobals->Tag,
810                                     0);
811     //
812     // Init device's auto_forward_cleanup_close.
813     //
814     ConfigureAutoForwardCleanupClose(DeviceInit);
815 
816     //
817     // Create, close, cleanup, shutdown
818     //
819     m_PkgGeneral = new(pGlobals) FxPkgGeneral(pGlobals, this);
820     if (m_PkgGeneral == NULL) {
821         return STATUS_INSUFFICIENT_RESOURCES;
822     }
823 
824     InstallPackage(m_PkgGeneral);
825 
826 #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
827 
828 
829 
830 
831 
832 
833     // m_PkgWmi = new(pGlobals) FxWmiIrpHandler(pGlobals, this); __REACTOS__
834     // if (m_PkgWmi == NULL) {
835     //     return STATUS_INSUFFICIENT_RESOURCES;
836     // }
837     // InstallPackage(m_PkgWmi);
838 #endif
839 
840     //
841     // IO package handles reads, writes, internal and external IOCTLs
842     //
843     m_PkgIo = new(pGlobals) FxPkgIo(pGlobals, (CfxDevice*) this);
844 
845     if (m_PkgIo == NULL) {
846         return STATUS_INSUFFICIENT_RESOURCES;
847     }
848 
849     InstallPackage(m_PkgIo);
850 
851     //
852     // Configure I/O package.
853     //
854     m_PkgIo->SetIoInCallerContextCallback(DeviceInit->IoInCallerContextCallback);
855 
856     if (DeviceInit->RequiresSelfIoTarget) {
857         m_SelfIoTargetNeeded = TRUE;
858     }
859 
860     return STATUS_SUCCESS;
861 }
862 
863 VOID
ConfigureAutoForwardCleanupClose(__in PWDFDEVICE_INIT DeviceInit)864 FxDevice::ConfigureAutoForwardCleanupClose(
865     __in PWDFDEVICE_INIT DeviceInit
866     )
867 {
868     WDF_TRI_STATE   autoForwardCleanupClose;
869     PLIST_ENTRY     next;
870     BOOLEAN         checkClientDriver;
871 
872     autoForwardCleanupClose = WdfUseDefault;
873     checkClientDriver = TRUE;
874 
875     //
876     // Device-wide configuration for auto forwarding cleanup and close requests:
877     //  . Use WdfFalse if one of the devices in the chain use this setting with a create
878     //    callback (this means it will complete all create IRPs).
879     //  . Else use lowest driver's setting in the chain (order of cx chain: lower to higher).
880     //  . If no settings are present, use default.
881     //
882     for (next = DeviceInit->CxDeviceInitListHead.Blink;
883          next != &DeviceInit->CxDeviceInitListHead;
884          next = next->Blink) {
885 
886         PWDFCXDEVICE_INIT cxInit;
887 
888         cxInit = CONTAINING_RECORD(next, WDFCXDEVICE_INIT, ListEntry);
889 
890         if (cxInit->FileObject.Set) {
891             autoForwardCleanupClose = cxInit->FileObject.AutoForwardCleanupClose;
892 
893             if (autoForwardCleanupClose == WdfFalse &&
894                 cxInit->FileObject.Callbacks.EvtCxDeviceFileCreate != NULL) {
895 
896                 checkClientDriver = FALSE;
897                 break;
898             }
899         }
900     }
901 
902     if (checkClientDriver && DeviceInit->FileObject.Set) {
903         autoForwardCleanupClose = DeviceInit->FileObject.AutoForwardCleanupClose;
904     }
905 
906     switch (autoForwardCleanupClose) {
907     case WdfTrue:
908 
909         m_AutoForwardCleanupClose = TRUE;
910         //
911         // If the device is legacy then set it to false because you can't forward
912         // requests.
913         //
914         if(m_Legacy) {
915             m_AutoForwardCleanupClose = FALSE;
916         }
917         break;
918 
919     case WdfFalse:
920         m_AutoForwardCleanupClose = FALSE;
921         break;
922 
923     case WdfUseDefault:
924         //
925         // For filters (which must be FDOs), we default to TRUE.  All other
926         // device roles (FDO, PDO, control) default to FALSE.  We cannot check
927         // m_Filter yet because it is set in FdoInitialize which occurs later.
928         //
929         if (DeviceInit->IsFdoInit() && DeviceInit->Fdo.Filter) {
930             m_AutoForwardCleanupClose = TRUE;
931         }
932         else {
933             m_AutoForwardCleanupClose = FALSE;
934         }
935     }
936 }
937 
938 _Must_inspect_result_
939 NTSTATUS
PostInitialize(VOID)940 FxDevice::PostInitialize(
941     VOID
942     )
943 {
944     NTSTATUS status;
945 
946     status = FxDisposeList::_Create(GetDriverGlobals(),
947                                    m_DeviceObject.GetObject(),
948                                    &m_DisposeList);
949 
950     return status;
951 }
952 
953 
954 
955 
956 
957 
958 
959 
960 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
961 
962 _Must_inspect_result_
963 NTSTATUS
CreateDevice(__in PWDFDEVICE_INIT DeviceInit)964 FxDevice::CreateDevice(
965     __in PWDFDEVICE_INIT DeviceInit
966     )
967 {
968     MdDeviceObject  pNewDeviceObject;
969     ULONG           characteristics;
970     NTSTATUS        status;
971     DEVICE_TYPE     devType;
972 
973     status = m_PkgGeneral->Initialize(DeviceInit);
974     if (!NT_SUCCESS(status)) {
975         return status;
976     }
977 
978     devType = DeviceInit->DeviceType;
979     if (devType < ARRAY_SIZE(m_PriorityBoosts)) {
980         m_DefaultPriorityBoost= m_PriorityBoosts[devType];
981     }
982 
983     characteristics = DeviceInit->Characteristics;
984 
985     //
986     // You can only create secure device objects which have a name.  All other
987     // device objects rely on the PDO's security
988     //
989     if (DeviceInit->ShouldCreateSecure()) {
990         PUNICODE_STRING pName, pSddl;
991         LPGUID pGuid;
992 
993         if (DeviceInit->DeviceName != NULL) {
994             pName = DeviceInit->DeviceName->GetUnicodeString();
995         }
996         else {
997             pName = NULL;
998         }
999 
1000         if (DeviceInit->Security.DeviceClassSet) {
1001             pGuid = &DeviceInit->Security.DeviceClass;
1002         }
1003         else {
1004             pGuid = NULL;
1005         }
1006 
1007         if (DeviceInit->Security.Sddl != NULL) {
1008             pSddl = DeviceInit->Security.Sddl->GetUnicodeString();
1009         }
1010         else {
1011             //
1012             // Always provide an SDDL if one is not supplied.
1013             //
1014             // SDDL_DEVOBJ_SYS_ALL_ADM_ALL = "D:P(A;;GA;;;SY)(A;;GA;;;BA)"
1015             //
1016             // SDDL_DEVOBJ_SYS_ALL_ADM_ALL allows the kernel, system, and
1017             // administrator complete control over the device. No other users
1018             // may access the device.
1019             //
1020             // pSddl = (PUNICODE_STRING) &SDDL_DEVOBJ_SYS_ALL_ADM_ALL;
1021             pSddl = NULL; // __REACTOS__ : wdmsec.lib is not supported
1022         }
1023 
1024         status = Mx::MxCreateDeviceSecure(
1025             m_Driver->m_DriverObject.GetObject(),
1026             sizeof(FxWdmDeviceExtension),
1027             pName,
1028             devType,
1029             characteristics,
1030             m_Exclusive,
1031             pSddl,
1032             pGuid,
1033             &pNewDeviceObject);
1034     }
1035     else {
1036         status = Mx::MxCreateDevice(
1037             m_Driver->m_DriverObject.GetObject(),
1038             sizeof(FxWdmDeviceExtension),
1039             NULL,
1040             devType,
1041             characteristics,
1042             m_Exclusive,
1043             &pNewDeviceObject);
1044     }
1045 
1046     if (NT_SUCCESS(status)) {
1047         FxWdmDeviceExtension* pWdmExt;
1048 
1049         pWdmExt = _GetFxWdmExtension(pNewDeviceObject);
1050 
1051         //
1052         // We reassign DeviceExtension below and then use the knowledge that
1053         // we can always retrieve DeviceExtension by adding sizeof(DEVICE_OBJECT)
1054         // to pNewDeviceObject.  ASSERT that this assumption is correct.
1055         //
1056         MxDeviceObject newDeviceObject(pNewDeviceObject);
1057         ASSERT(pWdmExt == newDeviceObject.GetDeviceExtension());
1058 
1059         Mx::MxInitializeRemoveLock(&pWdmExt->IoRemoveLock,
1060                                GetDriverGlobals()->Tag,
1061                                0,          // max min
1062                                0           // highwater mark
1063                                );
1064 
1065         //
1066         // Option for remove lock is stored in device extension
1067         // since this option may be examined after FxDevice is destroyed
1068         // (if an Irp is sent after removal of device).
1069         // We combine the flags from DeviceInit with what's set through registry
1070         //
1071         pWdmExt->RemoveLockOptionFlags = DeviceInit->RemoveLockOptionFlags |
1072                                             GetDriverGlobals()->RemoveLockOptionFlags;
1073 
1074         //
1075         // We assign the first context assigned to this object as the
1076         // DeviceExtension for compatibility reasons.  This allows existing
1077         // WDM extensions to work as well as any stack which exports a known
1078         // structure for the extension (ie the FDO knows the extension of its
1079         // PDO and casts it and accesses it directly).
1080         //
1081         newDeviceObject.SetDeviceExtension(&GetContextHeader()->Context[0]);
1082         m_DeviceObject.SetObject(pNewDeviceObject);
1083 
1084         //
1085         // Set some device object flags based on properties of DeviceInit.
1086         //
1087         // If we are a filter, we will set these flags later
1088         // (in FxDevice::FdoInitialize) based on the device we are attached to.
1089         //
1090         if (m_Filter == FALSE) {
1091             if (DeviceInit->ReadWriteIoType == WdfDeviceIoBuffered) {
1092                 m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() | DO_BUFFERED_IO);
1093             }
1094             else if (DeviceInit->ReadWriteIoType == WdfDeviceIoDirect) {
1095                 m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() | DO_DIRECT_IO);
1096             }
1097 
1098             m_ReadWriteIoType = DeviceInit->ReadWriteIoType;
1099             m_PowerPageableCapable = DeviceInit->PowerPageable;
1100         }
1101     }
1102 
1103     return status;
1104 }
1105 
1106 #endif  // (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
1107 
1108 VOID
FinishInitializing(VOID)1109 FxDevice::FinishInitializing(
1110     VOID
1111     )
1112 
1113 /*++
1114 
1115 Routine Description:
1116 
1117     This routine is called when the device is completely initialized.
1118 
1119 Arguments:
1120 
1121     none.
1122 
1123 Returns:
1124 
1125     none.
1126 
1127 --*/
1128 
1129 {
1130 
1131     m_DeviceObject.SetFlags( m_DeviceObject.GetFlags() & ~DO_DEVICE_INITIALIZING);
1132 }
1133 
1134 VOID
DeleteObject(VOID)1135 FxDevice::DeleteObject(
1136     VOID
1137     )
1138 /*++
1139 
1140 Routine Description:
1141     Virtual override of an FxObject::DeleteObject.  For PDOs which are created
1142     statically and then deleted before being reported to WDF, we must simulate
1143     a pnp remove event to trigger cleanup.
1144 
1145 Arguments:
1146     None
1147 
1148 Return Value:
1149     None
1150 
1151   --*/
1152 {
1153     if (IsPnp() && IsPdo()) {
1154         FxPkgPdo* pPkgPdo;
1155         KIRQL irql;
1156         BOOLEAN remove;
1157 
1158         remove = FALSE;
1159 
1160         pPkgPdo = GetPdoPkg();
1161 
1162         pPkgPdo->Lock(&irql);
1163 
1164         if (pPkgPdo->m_Static && pPkgPdo->m_AddedToStaticList == FALSE) {
1165             //
1166             // Since no pnp action has been taken since the child was created, we
1167             // should be in the initial state.
1168             //
1169             if (m_CurrentPnpState == WdfDevStatePnpInit) {
1170                 //
1171                 // A PDO in this state should be deletable
1172                 //
1173                 ASSERT(IsNoDeleteDDI() == FALSE);
1174 
1175                 remove = TRUE;
1176             }
1177             else {
1178                 //
1179                 // If we are not in the init state, we should be in the created
1180                 // state. This means we are failing from FxDevice::CreateDevice.
1181                 //
1182                 ASSERT(m_CurrentPnpState == WdfDevStatePnpObjectCreated);
1183             }
1184         }
1185 
1186         pPkgPdo->Unlock(irql);
1187 
1188         if (remove) {
1189             //
1190             // Cleanup the device and then let the super class delete the object.
1191             //
1192             (void) DeleteDeviceFromFailedCreateNoDelete(
1193                 STATUS_UNSUCCESSFUL, TRUE);
1194         }
1195     }
1196     else if (IsLegacy() && m_PkgGeneral != NULL && m_DeviceObject.GetObject() != NULL) {
1197         //
1198         // We allow tracing devices to go through a normal DeleteObject() path
1199         // where we do not prematurely delete the device object.
1200         //
1201         (void) FxVerifierCheckIrqlLevel(GetDriverGlobals(), PASSIVE_LEVEL);
1202 
1203         m_DeviceObjectDeleted = TRUE;
1204 
1205         //
1206         // This reference will be released in Destroy().
1207         //
1208         Mx::MxReferenceObject(m_DeviceObject.GetObject());
1209 
1210         if (m_PkgWmi != NULL) {
1211             //
1212             // Since a legacy NT4 driver does not have an explicit WMI
1213             // deregistration DDI, we do it for them on deletion.
1214             //
1215             // This is done in DeleteObject because we need to deregister before
1216             // we delete the device object, otherwise we can bugcheck when
1217             // running under driver verifier.
1218             //
1219             // m_PkgWmi->Deregister(); __REACTOS__
1220         }
1221 
1222         //
1223         // By deleting the device object now, we prevent any new creates from
1224         // being sent to the device (the io manager enforces this).
1225         //
1226         Mx::MxDeleteDevice(m_DeviceObject.GetObject());
1227 
1228         if (m_PkgGeneral->CanDestroyControlDevice() == FALSE) {
1229             //
1230             // Delay the actual destruction of the device until the last open
1231             // handle has been closed.  ControlDeviceDelete() will perform the
1232             // destruction later.
1233             //
1234             return;
1235         }
1236     }
1237 
1238     FxDeviceBase::DeleteObject(); // __super call
1239 }
1240 
1241 BOOLEAN
Dispose(VOID)1242 FxDevice::Dispose(
1243     VOID
1244     )
1245 {
1246     ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL);
1247 
1248     if (m_Legacy) {
1249         if (m_PkgWmi != NULL) {
1250             //
1251             // We deregister in Dispose() (as well as DeleteObject()) for
1252             // control devices which are implicitly destroyed when the driver
1253             // unloads and FxDriver is being deleted.
1254             //
1255             // Since a legacy NT4 driver does not have an explicit WMI
1256             // deregistration DDI, we do it for them on destruction.
1257             //
1258             // This is done in Dispose because we are guaranteed to be at
1259             // passive level here.  Even though m_PkgWmi was already
1260             // Dispose()'ed (because it is a child of this object), it is still
1261             // valid to reference the pointer because there is an explicit
1262             // reference on the object that was taken when we created this object.
1263             //
1264             // m_PkgWmi->Deregister(); __REACTOS__
1265         }
1266 
1267         //
1268         // Important that the cleanup routine be called while the PDEVICE_OBJECT
1269         // is valid!
1270         //
1271         CallCleanup();
1272 
1273         //
1274         // Manually destroy the children now so that by the time we wait on the
1275         // dispose empty out, all of the children will have been added to it.
1276         //
1277         DestroyChildren();
1278 
1279         if (m_DisposeList != NULL) {
1280             m_DisposeList->WaitForEmpty();
1281         }
1282 
1283         //
1284         // Now delete the device object
1285         //
1286         Destroy();
1287 
1288         return FALSE;
1289     }
1290 
1291     return FxDeviceBase::Dispose(); // __super call
1292 }
1293 
1294 _Must_inspect_result_
1295 NTSTATUS
_AcquireOptinRemoveLock(__in MdDeviceObject DeviceObject,__in MdIrp Irp)1296 FxDevice::_AcquireOptinRemoveLock(
1297     __in MdDeviceObject DeviceObject,
1298     __in MdIrp Irp
1299     )
1300 {
1301     NTSTATUS status;
1302     FxIrp irp(Irp);
1303 
1304     FxWdmDeviceExtension * wdmDeviceExtension =
1305         FxDevice::_GetFxWdmExtension(DeviceObject);
1306 
1307     if (wdmDeviceExtension->RemoveLockOptionFlags &
1308             WDF_REMOVE_LOCK_OPTION_ACQUIRE_FOR_IO) {
1309 
1310         status = Mx::MxAcquireRemoveLock(&(wdmDeviceExtension->IoRemoveLock), Irp);
1311 
1312         if (!NT_SUCCESS(status)) {
1313             return status;
1314         }
1315 
1316         irp.CopyCurrentIrpStackLocationToNext();
1317 
1318         irp.SetCompletionRoutineEx(
1319                 DeviceObject,
1320                 _CompletionRoutineForRemlockMaintenance,
1321                 DeviceObject,
1322                 TRUE,
1323                 TRUE,
1324                 TRUE
1325                 );
1326 
1327         irp.SetNextIrpStackLocation();
1328     }
1329 
1330     return STATUS_SUCCESS;
1331 }
1332 
1333 _Must_inspect_result_
1334 NTSTATUS
1335 STDCALL
DispatchWithLock(__in MdDeviceObject DeviceObject,__in MdIrp Irp)1336 FxDevice::DispatchWithLock(
1337     __in MdDeviceObject DeviceObject,
1338     __in MdIrp Irp
1339     )
1340 {
1341     NTSTATUS status;
1342     FxIrp irp(Irp);
1343 
1344     switch (_RequiresRemLock(irp.GetMajorFunction(),
1345                              irp.GetMinorFunction())) {
1346 
1347     case FxDeviceRemLockRequired:
1348         status = Mx::MxAcquireRemoveLock(
1349             &_GetFxWdmExtension(DeviceObject)->IoRemoveLock,
1350             Irp
1351             );
1352 
1353         if (!NT_SUCCESS(status)) {
1354             irp.SetStatus(status);
1355             irp.CompleteRequest(IO_NO_INCREMENT);
1356 
1357             return status;
1358         }
1359 
1360         break;
1361 
1362     case FxDeviceRemLockOptIn:
1363         status = _AcquireOptinRemoveLock(
1364             DeviceObject,
1365             Irp
1366             );
1367 
1368         if (!NT_SUCCESS(status)) {
1369             irp.SetStatus(status);
1370             irp.CompleteRequest(IO_NO_INCREMENT);
1371 
1372             return status;
1373         }
1374 
1375         break;
1376 
1377     case FxDeviceRemLockTestValid:
1378         //
1379         // Try to Acquire and Release the RemLock.  If acquiring the lock
1380         // fails then it is not safe to process the IRP and the IRP should
1381         // be completed immediately.
1382         //
1383         status = Mx::MxAcquireRemoveLock(
1384             &_GetFxWdmExtension(DeviceObject)->IoRemoveLock,
1385             Irp
1386             );
1387 
1388         if (!NT_SUCCESS(status)) {
1389             irp.SetStatus(status);
1390             irp.CompleteRequest(IO_NO_INCREMENT);
1391 
1392             return status;
1393         }
1394 
1395         Mx::MxReleaseRemoveLock(
1396             &_GetFxWdmExtension(DeviceObject)->IoRemoveLock,
1397             Irp
1398             );
1399         break;
1400     }
1401 
1402     return Dispatch(DeviceObject, Irp);
1403 }
1404 
1405 _Must_inspect_result_
1406 __inline
1407 BOOLEAN
IsPreprocessIrp(__in MdIrp Irp,__in FxIrpPreprocessInfo * Info)1408 IsPreprocessIrp(
1409     __in MdIrp       Irp,
1410     __in FxIrpPreprocessInfo*  Info
1411     )
1412 {
1413     UCHAR       major, minor;
1414     BOOLEAN     preprocess;
1415     FxIrp irp(Irp);
1416 
1417     major = irp.GetMajorFunction();
1418     minor = irp.GetMinorFunction();
1419 
1420     preprocess = FALSE;
1421 
1422     if (Info->Dispatch[major].EvtDevicePreprocess != NULL) {
1423         if (Info->Dispatch[major].NumMinorFunctions == 0) {
1424             //
1425             // If the driver is not interested in particular minor codes,
1426             // just give the irp to it.
1427             //
1428             preprocess = TRUE;
1429         }
1430         else {
1431             ULONG i;
1432 
1433             //
1434             // Try to match up to a minor code.
1435             //
1436             for (i = 0; i < Info->Dispatch[major].NumMinorFunctions; i++) {
1437                 if (Info->Dispatch[major].MinorFunctions[i] == minor) {
1438                     preprocess = TRUE;
1439                     break;
1440                 }
1441             }
1442         }
1443     }
1444 
1445     return preprocess;
1446 }
1447 
1448 _Must_inspect_result_
1449 __inline
1450 NTSTATUS
PreprocessIrp(__in FxDevice * Device,__in MdIrp Irp,__in FxIrpPreprocessInfo * Info,__in PVOID DispatchContext)1451 PreprocessIrp(
1452     __in FxDevice*  Device,
1453     __in MdIrp       Irp,
1454     __in FxIrpPreprocessInfo*  Info,
1455     __in PVOID      DispatchContext
1456     )
1457 {
1458     NTSTATUS        status;
1459     UCHAR           major, minor;
1460     FxIrp irp(Irp);
1461 
1462     major = irp.GetMajorFunction();
1463     minor = irp.GetMinorFunction();
1464 
1465     //
1466     // If this is a pnp remove irp, this object could be deleted by the time
1467     // EvtDevicePreprocess returns.  To not touch freed pool, capture all
1468     // values we will need before preprocessing.
1469     //
1470 
1471     if (Info->ClassExtension == FALSE) {
1472         status = Info->Dispatch[major].EvtDevicePreprocess( Device->GetHandle(),
1473                                                             Irp);
1474     }
1475     else {
1476         status = Info->Dispatch[major].EvtCxDevicePreprocess(
1477                                                             Device->GetHandle(),
1478                                                             Irp,
1479                                                             DispatchContext);
1480     }
1481 
1482     //
1483     // If we got this far, we handed the irp off to EvtDevicePreprocess, so we
1484     // must now do our remlock maintainance if necessary.
1485     //
1486     if (FxDevice::_RequiresRemLock(major, minor) == FxDeviceRemLockRequired) {
1487         //
1488         // Keep the remove lock active until after we call into the driver.
1489         // If the driver redispatches the irp to the framework, we will
1490         // reacquire the remove lock at that point in time.
1491         //
1492         // Touching pDevObj after sending the pnp remove irp to the framework
1493         // is OK b/c we have acquired the remlock previously and that will
1494         // prevent this irp's processing racing with the pnp remove irp
1495         // processing.
1496         //
1497         Mx::MxReleaseRemoveLock(Device->GetRemoveLock(),
1498                                 Irp);
1499     }
1500 
1501     return status;
1502 }
1503 
1504 _Must_inspect_result_
1505 __inline
1506 NTSTATUS
DispatchWorker(__in FxDevice * Device,__in MdIrp Irp,__in WDFCONTEXT DispatchContext)1507 DispatchWorker(
1508     __in FxDevice*  Device,
1509     __in MdIrp       Irp,
1510     __in WDFCONTEXT DispatchContext
1511     )
1512 {
1513     PLIST_ENTRY next;
1514     FxIrp irp(Irp);
1515 
1516     next = (PLIST_ENTRY)DispatchContext;
1517 
1518     ASSERT(NULL != DispatchContext &&
1519            ((UCHAR)(ULONG_PTR)DispatchContext & FX_IN_DISPATCH_CALLBACK) == 0);
1520 
1521     //
1522     // Check for any driver/class-extensions' preprocess requirements.
1523     //
1524     while (next != &Device->m_PreprocessInfoListHead) {
1525         FxIrpPreprocessInfo* info;
1526 
1527         info = CONTAINING_RECORD(next, FxIrpPreprocessInfo, ListEntry);
1528 
1529         //
1530         // Advance to next node.
1531         //
1532         next = next->Flink;
1533 
1534         if (IsPreprocessIrp(Irp, info)) {
1535             return PreprocessIrp(Device, Irp, info, next);
1536         }
1537     }
1538 
1539     //
1540     // No preprocess requirements, directly dispatch the IRP.
1541     //
1542     return Device->GetDispatchPackage(
1543         irp.GetMajorFunction()
1544         )->Dispatch(Irp);
1545 }
1546 
1547 
1548 _Must_inspect_result_
1549 NTSTATUS
1550 STDCALL
Dispatch(__in MdDeviceObject DeviceObject,__in MdIrp Irp)1551 FxDevice::Dispatch(
1552     __in MdDeviceObject DeviceObject,
1553     __in MdIrp       Irp
1554     )
1555 {
1556     FxDevice* device = FxDevice::GetFxDevice(DeviceObject);
1557     return DispatchWorker(device,
1558                           Irp,
1559                           device->m_PreprocessInfoListHead.Flink);
1560 }
1561 
1562 _Must_inspect_result_
1563 NTSTATUS
DispatchPreprocessedIrp(__in MdIrp Irp,__in WDFCONTEXT DispatchContext)1564 FxDevice::DispatchPreprocessedIrp(
1565     __in MdIrp       Irp,
1566     __in WDFCONTEXT DispatchContext
1567     )
1568 {
1569     NTSTATUS    status;
1570     UCHAR       major, minor;
1571     FxIrp irp(Irp);
1572 
1573     //
1574     // The contract for this DDI is just like IoCallDriver.  The caller sets up
1575     // their stack location and then the DDI advances to the next stack location.
1576     // This means that the caller either has to call IoSkipCurrentIrpStackLocation
1577     // or IoCopyCurrentIrpStackLocationToNext before calling this DDI.
1578     //
1579     irp.SetNextIrpStackLocation();
1580 
1581     major = irp.GetMajorFunction();
1582     minor = irp.GetMinorFunction();
1583 
1584     //
1585     // FxPkgPnp and FxWmiIrpHandler expect that there will be a remove lock
1586     // acquired for all power irps.  We release the remlock when we called
1587     // Evt(Ext)DevicePreprocessIrp.
1588     //
1589     if (_RequiresRemLock(major, minor) == FxDeviceRemLockRequired) {
1590         status = Mx::MxAcquireRemoveLock(
1591             GetRemoveLock(),
1592             Irp
1593             );
1594 
1595         if (!NT_SUCCESS(status)) {
1596             goto Done;
1597         }
1598     }
1599 
1600     return DispatchWorker(this, Irp, DispatchContext);
1601 
1602 Done:
1603     irp.SetStatus(status);
1604     irp.SetInformation(0);
1605     irp.CompleteRequest(IO_NO_INCREMENT);
1606 
1607     return status;
1608 }
1609 
1610 VOID
InstallPackage(__inout FxPackage * Package)1611 FxDevice::InstallPackage(
1612     __inout FxPackage *Package
1613     )
1614 
1615 {
1616     //
1617     // Add this package as an association on FxDevice
1618     // so its children get Dispose notifications.
1619     //
1620     // Note: This assumes a transfer of the controlling reference
1621     //       count which it will dereference on FxDevice teardown.
1622     //       We need to add an extra one here since packages have
1623     //       an existing reference count model.
1624     //
1625     Package->AddRef();
1626     Package->AssignParentObject(this);
1627 }
1628 
1629 PVOID
AllocateRequestMemory(__in_opt PWDF_OBJECT_ATTRIBUTES RequestAttributes)1630 FxDevice::AllocateRequestMemory(
1631     __in_opt PWDF_OBJECT_ATTRIBUTES RequestAttributes
1632     )
1633 /*++
1634 
1635 Routine Description:
1636     Allocates enough memory for an FxRequest* plus any additonal memory required
1637     for the device's specific context memory.
1638 
1639     If we are tracking memory, the allocation layout is
1640     0x0                                                 - FX_POOL_TRACKER
1641     0x0 + sizeof(FX_POOL_TRACKER)                       - FX_POOL_HEADER
1642     0x0 + sizeof(FX_POOL_TRACKER) + FX_POOL_HEADER_SIZE - start of FxRequest
1643 
1644     if no tracking is occuring, the allocation layout is
1645     0x0                                                 - FX_POOL_HEADER
1646     0x0 + FX_POOL_HEADER_SIZE                           - start of FxRequest
1647 
1648     the total size is precomputed in m_RequestLookasideListElementSize during
1649     FxDevice::Initialize
1650 
1651 Arguments:
1652     RequestAttributes - Attributes setting for the request.
1653 
1654 Return Value:
1655     valid ptr or NULL
1656 
1657   --*/
1658 
1659 {
1660     PFX_DRIVER_GLOBALS pGlobals;
1661     PFX_POOL_TRACKER pTracker;
1662     PFX_POOL_HEADER  pHeader;
1663     PVOID ptr, pTrueBase;
1664 
1665     pGlobals = GetDriverGlobals();
1666     ptr = NULL;
1667 
1668     if (IsPdo() && GetPdoPkg()->IsForwardRequestToParentEnabled()) {
1669         pTrueBase = FxAllocateFromNPagedLookasideListNoTracking(&m_RequestLookasideList);
1670     }
1671     else {
1672         pTrueBase = FxAllocateFromNPagedLookasideList(&m_RequestLookasideList,
1673                                                       m_RequestLookasideListElementSize);
1674     }
1675 
1676     if (pTrueBase != NULL) {
1677         if (pGlobals->IsPoolTrackingOn()) {
1678             pTracker = (PFX_POOL_TRACKER) pTrueBase;
1679             pHeader  = WDF_PTR_ADD_OFFSET_TYPE(pTrueBase,
1680                                                sizeof(FX_POOL_TRACKER),
1681                                                PFX_POOL_HEADER);
1682 
1683             //
1684             // Format and insert the Tracker in the NonPagedHeader list.
1685             //
1686             FxPoolInsertNonPagedAllocateTracker(&pGlobals->FxPoolFrameworks,
1687                                                 pTracker,
1688                                                 m_RequestLookasideListElementSize,
1689                                                 pGlobals->Tag,
1690                                                 _ReturnAddress());
1691         }
1692         else {
1693             pHeader = (PFX_POOL_HEADER) pTrueBase;
1694         }
1695 
1696         //
1697         // Common init
1698         //
1699         pHeader->Base = pTrueBase;
1700         pHeader->FxDriverGlobals = pGlobals;
1701 
1702         ptr = &pHeader->AllocationStart[0];
1703 
1704         if (RequestAttributes == NULL) {
1705             RequestAttributes = &m_RequestAttributes;
1706         }
1707 
1708         ptr = FxObjectAndHandleHeaderInit(
1709             pGlobals,
1710             ptr,
1711             COMPUTE_OBJECT_SIZE(sizeof(FxRequest), 0),
1712             RequestAttributes,
1713             FxObjectTypeExternal
1714             );
1715 
1716 #if FX_VERBOSE_TRACE
1717         DoTraceLevelMessage(pGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST,
1718                             "Allocating FxRequest* %p, WDFREQUEST %p",
1719                             ptr, _ToHandle((FxObject*) ptr));
1720 #endif
1721         return ptr;
1722     }
1723 
1724     return NULL;
1725 }
1726 
1727 VOID
FreeRequestMemory(__in FxRequest * Request)1728 FxDevice::FreeRequestMemory(
1729     __in FxRequest* Request
1730     )
1731 {
1732     PFX_POOL_HEADER pHeader;
1733 
1734 #if FX_VERBOSE_TRACE
1735     DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGREQUEST,
1736                         "Free FxRequest* %p memory", Request);
1737 #endif
1738 
1739     //
1740     // Remove the request from the list of outstanding requests against this
1741     // driver.
1742     //
1743     pHeader = FxObject::_CleanupPointer(GetDriverGlobals(), Request);
1744     if (IsPdo() && GetPdoPkg()->IsForwardRequestToParentEnabled()) {
1745         FxFreeToNPagedLookasideListNoTracking(&m_RequestLookasideList, pHeader->Base);
1746     }
1747     else {
1748         FxFreeToNPagedLookasideList(&m_RequestLookasideList, pHeader->Base);
1749     }
1750 }
1751 
1752 _Must_inspect_result_
1753 NTSTATUS
QueryInterface(__inout FxQueryInterfaceParams * Params)1754 FxDevice::QueryInterface(
1755     __inout FxQueryInterfaceParams* Params
1756     )
1757 {
1758     switch (Params->Type) {
1759     case FX_TYPE_DEVICE:
1760         *Params->Object = (FxDevice*) this;
1761         break;
1762 
1763     default:
1764         return FxDeviceBase::QueryInterface(Params); // __super call
1765     }
1766 
1767     return STATUS_SUCCESS;
1768 }
1769 
1770 _Must_inspect_result_
1771 NTSTATUS
AddIoTarget(__inout FxIoTarget * IoTarget)1772 FxDevice::AddIoTarget(
1773     __inout FxIoTarget* IoTarget
1774     )
1775 {
1776     NTSTATUS status;
1777 
1778     status = m_IoTargetsList.Add(GetDriverGlobals(),
1779                                  &IoTarget->m_TransactionedEntry);
1780 
1781     if (NT_SUCCESS(status)) {
1782         IoTarget->m_AddedToDeviceList = TRUE;
1783         IoTarget->ADDREF(this);
1784     }
1785 
1786     return status;
1787 }
1788 
1789 VOID
RemoveIoTarget(__inout FxIoTarget * IoTarget)1790 FxDevice::RemoveIoTarget(
1791     __inout FxIoTarget* IoTarget
1792     )
1793 {
1794     m_IoTargetsList.Remove(GetDriverGlobals(),
1795                            &IoTarget->m_TransactionedEntry);
1796 
1797     //
1798     // Assumes that the caller has its own reference on the IoTarget
1799     //
1800     IoTarget->RELEASE(this);
1801 }
1802 
1803 _Must_inspect_result_
1804 NTSTATUS
AllocateEnumInfo(VOID)1805 FxDevice::AllocateEnumInfo(
1806     VOID
1807     )
1808 {
1809     if (IsPnp()) {
1810         return m_PkgPnp->AllocateEnumInfo();
1811     }
1812     else {
1813         return STATUS_SUCCESS;
1814     }
1815 }
1816 
1817 FxIoTarget*
GetDefaultIoTarget(VOID)1818 FxDevice::GetDefaultIoTarget(
1819     VOID
1820     )
1821 {
1822     if (IsPnp() && IsFdo()) {
1823         return GetFdoPkg()->m_DefaultTarget;
1824     }
1825     else {
1826         return NULL;
1827     }
1828 }
1829 
1830 FxIoTargetSelf*
GetSelfIoTarget(VOID)1831 FxDevice::GetSelfIoTarget(
1832     VOID
1833     )
1834 /*++
1835 Routine Description:
1836     Returns the Self IO target for this FxDevice.
1837     Currently Self IO Target is supported only for a Pnp FDO.
1838     If the Self IO Target has not been established, it returns NULL.
1839 --*/
1840 {
1841     if (IsPnp() && IsFdo()) {
1842         return GetFdoPkg()->m_SelfTarget;
1843     }
1844     else {
1845         return NULL;
1846     }
1847 }
1848 
1849 _Must_inspect_result_
1850 NTSTATUS
SetFilter(__in BOOLEAN Value)1851 FxDevice::SetFilter(
1852     __in BOOLEAN Value
1853     )
1854 {
1855     NTSTATUS status;
1856 
1857     ASSERT(IsFdo());
1858 
1859     status = m_PkgIo->SetFilter(Value);
1860 
1861     if (NT_SUCCESS(status) && m_PkgPnp != NULL) {
1862         status = GetFdoPkg()->SetFilter(Value);
1863     }
1864 
1865     if (NT_SUCCESS(status)) {
1866         m_Filter = Value;
1867     }
1868 
1869     return status;
1870 }
1871 
1872 VOID
SetFilterIoType(VOID)1873 FxDevice::SetFilterIoType(
1874     VOID
1875     )
1876 {
1877     FxIoTarget * ioTarget;
1878     FxTransactionedEntry * targetsList = NULL;
1879 
1880     ASSERT(IsFilter());
1881 
1882     m_DeviceObject.SetFlags( m_DeviceObject.GetFlags() & ~(DO_BUFFERED_IO | DO_DIRECT_IO));
1883 
1884     //
1885     // m_AttachedDevice can be NULL for UMDF, so check for NULL
1886     //
1887     if (m_AttachedDevice.GetObject() != NULL) {
1888         m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() |
1889             (m_AttachedDevice.GetFlags() & (DO_BUFFERED_IO | DO_DIRECT_IO)));
1890     }
1891 
1892     if (m_DeviceObject.GetFlags() & DO_BUFFERED_IO) {
1893         m_ReadWriteIoType = WdfDeviceIoBuffered;
1894     }
1895     else if (m_DeviceObject.GetFlags() & DO_DIRECT_IO) {
1896         m_ReadWriteIoType = WdfDeviceIoDirect;
1897     }
1898     else {
1899         m_ReadWriteIoType = WdfDeviceIoNeither;
1900     }
1901 
1902     //
1903     // We also need to propagate these settings to any io targets that
1904     // have already been created
1905     //
1906 
1907     m_IoTargetsList.LockForEnum(GetDriverGlobals());
1908 
1909     targetsList = m_IoTargetsList.GetNextEntry(targetsList);
1910 
1911     while (targetsList != NULL) {
1912 
1913         ioTarget = (FxIoTarget *) targetsList->GetTransactionedObject();
1914 
1915         if (ioTarget->GetTargetPDO() == GetPhysicalDevice()) {
1916             ioTarget->UpdateTargetIoType();
1917         }
1918 
1919         targetsList = m_IoTargetsList.GetNextEntry(targetsList);
1920     }
1921 
1922     m_IoTargetsList.UnlockFromEnum(GetDriverGlobals());
1923 }
1924 
1925 BOOLEAN
IsInterfaceRegistered(_In_ const GUID * InterfaceClassGUID,_In_opt_ PCUNICODE_STRING RefString)1926 FxDevice::IsInterfaceRegistered(
1927     _In_ const GUID* InterfaceClassGUID,
1928     _In_opt_ PCUNICODE_STRING RefString
1929     )
1930 {
1931     PSINGLE_LIST_ENTRY ple;
1932     BOOLEAN found = FALSE;
1933 
1934     m_PkgPnp->m_DeviceInterfaceLock.AcquireLock(GetDriverGlobals());
1935 
1936     //
1937     // Iterate over the interfaces and see if we have a match
1938     //
1939     for (ple = m_PkgPnp->m_DeviceInterfaceHead.Next; ple != NULL; ple = ple->Next) {
1940         FxDeviceInterface *pDI;
1941 
1942         pDI = FxDeviceInterface::_FromEntry(ple);
1943 
1944         if (FxIsEqualGuid(&pDI->m_InterfaceClassGUID, InterfaceClassGUID)) {
1945             if (RefString != NULL) {
1946                 if ((RefString->Length == pDI->m_ReferenceString.Length)
1947                     &&
1948                     (RtlCompareMemory(RefString->Buffer,
1949                                       pDI->m_ReferenceString.Buffer,
1950                                       RefString->Length) == RefString->Length)) {
1951                     //
1952                     // They match, carry on
1953                     //
1954                     DO_NOTHING();
1955                 }
1956                 else {
1957                     //
1958                     // The ref strings do not match, continue on in the search
1959                     // of the collection.
1960                     //
1961                     continue;
1962                 }
1963             }
1964             else if (pDI->m_ReferenceString.Length > 0) {
1965                 //
1966                 // Caller didn't specify a ref string but this interface has
1967                 // one, continue on in the search through the collection.
1968                 //
1969                 continue;
1970             }
1971 
1972             //
1973             // Set the state and break out of the loop because we found our
1974             // interface.
1975             //
1976             found = TRUE;
1977             break;
1978         }
1979     }
1980 
1981     m_PkgPnp->m_DeviceInterfaceLock.ReleaseLock(GetDriverGlobals());
1982 
1983     return found;
1984 }
1985 
1986 _Must_inspect_result_
1987 NTSTATUS
_AllocAndQueryProperty(_In_ PFX_DRIVER_GLOBALS Globals,_In_opt_ PWDFDEVICE_INIT DeviceInit,_In_opt_ FxDevice * Device,_In_opt_ MdDeviceObject RemotePdo,_In_ DEVICE_REGISTRY_PROPERTY DeviceProperty,_In_ POOL_TYPE PoolType,_In_opt_ PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes,_Out_ WDFMEMORY * PropertyMemory)1988 FxDevice::_AllocAndQueryProperty(
1989     _In_ PFX_DRIVER_GLOBALS Globals,
1990     _In_opt_ PWDFDEVICE_INIT DeviceInit,
1991     _In_opt_ FxDevice* Device,
1992     _In_opt_ MdDeviceObject RemotePdo,
1993     _In_ DEVICE_REGISTRY_PROPERTY DeviceProperty,
1994     _In_ POOL_TYPE PoolType,
1995     _In_opt_ PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes,
1996     _Out_ WDFMEMORY* PropertyMemory
1997     )
1998 {
1999     FxMemoryObject* pMemory;
2000     NTSTATUS status;
2001     ULONG length = 0;
2002 
2003     status = FxDevice::_QueryProperty(Globals,
2004                                       DeviceInit,
2005                                       Device,
2006                                       RemotePdo,
2007                                       DeviceProperty,
2008                                       0,
2009                                       NULL,
2010                                       &length);
2011     if (status != STATUS_BUFFER_TOO_SMALL) {
2012         DoTraceLevelMessage(Globals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
2013                             "Could not retrieve property %d length, %!STATUS!",
2014                             DeviceProperty, status);
2015         _Analysis_assume_(!NT_SUCCESS(status));
2016         return status;
2017     }
2018 
2019     status = FxMemoryObject::_Create(Globals,
2020                                      PropertyMemoryAttributes,
2021                                      PoolType,
2022                                      Globals->Tag,
2023                                      length,
2024                                      &pMemory);
2025     if (!NT_SUCCESS(status)) {
2026         DoTraceLevelMessage(Globals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
2027                             "Could not allocate WDFMEMORY, %!STATUS!", status);
2028         return status;
2029     }
2030 
2031     status = FxDevice::_QueryProperty(Globals,
2032                                       DeviceInit,
2033                                       Device,
2034                                       RemotePdo,
2035                                       DeviceProperty,
2036                                       length,
2037                                       pMemory->GetBuffer(),
2038                                       &length);
2039     if (!NT_SUCCESS(status)) {
2040         DoTraceLevelMessage(Globals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
2041                             "Could not query for full buffer, size %d, for "
2042                             "property %d, %!STATUS!",
2043                             length, DeviceProperty, status);
2044         pMemory->DeleteObject();
2045         return status;
2046     }
2047 
2048     status = pMemory->Commit(PropertyMemoryAttributes,
2049                              (WDFOBJECT*)PropertyMemory);
2050 
2051     if (!NT_SUCCESS(status)) {
2052         DoTraceLevelMessage(Globals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
2053                             "Could not commit memory object, %!STATUS!",
2054                             status);
2055         pMemory->DeleteObject();
2056     }
2057 
2058     return status;
2059 }
2060 
2061 _Must_inspect_result_
2062 NTSTATUS
_AllocAndQueryPropertyEx(_In_ PFX_DRIVER_GLOBALS DriverGlobals,_In_opt_ PWDFDEVICE_INIT DeviceInit,_In_opt_ FxDevice * Device,_In_ PVOID PropertyData,_In_ FxPropertyType FxPropertyType,_In_ POOL_TYPE PoolType,_In_opt_ PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes,_Out_ WDFMEMORY * PropertyMemory,_Out_ PDEVPROPTYPE PropertyType)2063 FxDevice::_AllocAndQueryPropertyEx(
2064     _In_ PFX_DRIVER_GLOBALS DriverGlobals,
2065     _In_opt_ PWDFDEVICE_INIT DeviceInit,
2066     _In_opt_ FxDevice* Device,
2067     _In_ PVOID PropertyData,
2068     _In_ FxPropertyType FxPropertyType,
2069     _In_ POOL_TYPE PoolType,
2070     _In_opt_ PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes,
2071     _Out_ WDFMEMORY*  PropertyMemory,
2072     _Out_ PDEVPROPTYPE PropertyType
2073     )
2074 {
2075     FxMemoryObject* pMemory;
2076     NTSTATUS status;
2077     ULONG length = 0;
2078     DEVPROPTYPE propType;
2079     ULONG requiredLength;
2080 
2081     status = FxDevice::_QueryPropertyEx(DriverGlobals,
2082                                         DeviceInit,
2083                                         Device,
2084                                         PropertyData,
2085                                         FxPropertyType,
2086                                         0,
2087                                         NULL,
2088                                         &requiredLength,
2089                                         &propType);
2090     if (status != STATUS_BUFFER_TOO_SMALL) {
2091         DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
2092                             "Could not retrieve property, %!STATUS!",
2093                             status);
2094         _Analysis_assume_(!NT_SUCCESS(status));
2095         return status;
2096     }
2097 
2098     *PropertyMemory = NULL;
2099     *PropertyType = 0;
2100 
2101     length = requiredLength;
2102     status = FxMemoryObject::_Create(DriverGlobals,
2103                                      PropertyMemoryAttributes,
2104                                      PoolType,
2105                                      DriverGlobals->Tag,
2106                                      length,
2107                                      &pMemory);
2108     if (!NT_SUCCESS(status)) {
2109         DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
2110                             "Could not allocate WDFMEMORY, %!STATUS!", status);
2111         return status;
2112     }
2113 
2114     status = FxDevice::_QueryPropertyEx(DriverGlobals,
2115                                         DeviceInit,
2116                                         Device,
2117                                         PropertyData,
2118                                         FxPropertyType,
2119                                         length,
2120                                         pMemory->GetBuffer(),
2121                                         &requiredLength,
2122                                         &propType);
2123     if (!NT_SUCCESS(status)) {
2124         DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
2125                             "Could not query for full buffer, size %d, for "
2126                             "property, %!STATUS!",
2127                             length, status);
2128         pMemory->DeleteObject();
2129         return status;
2130     }
2131 
2132     status = pMemory->Commit(PropertyMemoryAttributes,
2133                              (WDFOBJECT*)PropertyMemory);
2134 
2135     if (!NT_SUCCESS(status)) {
2136         DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
2137                             "Could not commit memory object, %!STATUS!",
2138                             status);
2139         pMemory->DeleteObject();
2140     }
2141     else {
2142         *PropertyMemory = pMemory->GetHandle();
2143         *PropertyType = propType;
2144     }
2145 
2146     return status;
2147 }
2148 
2149 _Must_inspect_result_
2150 NTSTATUS
_ValidateOpenKeyParams(_In_ PFX_DRIVER_GLOBALS FxDriverGlobals,_In_opt_ PWDFDEVICE_INIT DeviceInit,_In_opt_ FxDevice * Device)2151 FxDevice::_ValidateOpenKeyParams(
2152     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
2153     _In_opt_ PWDFDEVICE_INIT DeviceInit,
2154     _In_opt_ FxDevice* Device
2155     )
2156 {
2157     NTSTATUS status = STATUS_SUCCESS;
2158 
2159     //
2160     // This function should be called with exactly one valid WDFDEVICE_INIT
2161     // or one valid FxDevice object. Supplying neither or both is an error.
2162     //
2163     if ((DeviceInit == NULL && Device == NULL) ||
2164         (DeviceInit != NULL && Device != NULL)) {
2165 
2166         status = STATUS_INVALID_PARAMETER;
2167         DoTraceLevelMessage(
2168             FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
2169             "Device OpenKey/QueryProperty was called with invalid "
2170             "DeviceInit and Device parameters, %!STATUS!", status);
2171         FxVerifierDbgBreakPoint(FxDriverGlobals);
2172     }
2173 
2174     return status;
2175 }
2176 
2177