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
FxPkgGeneral(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in CfxDevice * Device)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
~FxPkgGeneral()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
Initialize(__in PWDFDEVICE_INIT DeviceInit)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
ConfigureConstraints(__in PLIST_ENTRY FileObjInfoList)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
ConfigureFileObjectClass(__in PLIST_ENTRY FileObjInfoList)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
PostCreateDeviceInitialize(__in PWDFDEVICE_INIT Init)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
ConfigureForwarding(__in FxIoQueue * TargetQueue)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
Dispatch(__inout MdIrp Irp)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
OnCreate(__inout FxIrp * FxIrp)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
ForwardCreateRequest(__in FxIrp * Irp,__in MdCompletionRoutine CompletionRoutine,__in PVOID Context)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
CreateCompleted(__in FxIrp * Irp)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
_CreateCompletionRoutine(__in MdDeviceObject DeviceObject,__in MdIrp OriginalIrp,__in_opt PVOID Context)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
_CreateCompletionRoutine2(__in MdDeviceObject DeviceObject,__in MdIrp OriginalIrp,__in_opt PVOID Context)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
OnCleanup(__inout FxIrp * FxIrp)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
OnClose(__inout FxIrp * FxIrp)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
AcquireRemoveLockForClose(__in FxIrp * FxIrp)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
OnShutdown(__inout FxIrp * FxIrp)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
DecrementOpenHandleCount(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
CanDestroyControlDevice(VOID)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
GetConstraintsHelper(__out_opt WDF_EXECUTION_LEVEL * ExecutionLevel,__out_opt WDF_SYNCHRONIZATION_SCOPE * SynchronizationScope)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*
GetCallbackLockPtrHelper(__deref_out_opt FxObject ** LockObject)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