1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxIoTargetRemote.cpp
8 
9 Abstract:
10 
11 Author:
12 
13 Environment:
14 
15     Both kernel and user mode
16 
17 Revision History:
18 
19 --*/
20 
21 #include "../fxtargetsshared.hpp"
22 
23 extern "C" {
24 // #include "FxIoTargetRemote.tmh"
25 }
26 
27 #include <initguid.h>
28 #include "wdmguid.h"
29 
30 
31 FxIoTargetRemote::FxIoTargetRemote(
32     __in PFX_DRIVER_GLOBALS FxDriverGlobals
33     ) :
34     FxIoTarget(FxDriverGlobals, sizeof(FxIoTargetRemote)),
35     m_EvtQueryRemove(FxDriverGlobals),
36     m_EvtRemoveCanceled(FxDriverGlobals),
37     m_EvtRemoveComplete(FxDriverGlobals)
38 {
39 
40     //
41     // No automatic state changes based on the pnp state changes of our own
42     // device stack.  The one exception is remove where we need to shut
43     // everything down.
44     //
45     m_InStack = FALSE;
46 
47     m_ClearedPointers = NULL;
48     m_OpenState = FxIoTargetRemoteOpenStateClosed;
49 
50     m_TargetHandle = NULL;
51 
52     m_EvtQueryRemove.m_Method = NULL;
53     m_EvtRemoveCanceled.m_Method = NULL;
54     m_EvtRemoveComplete.m_Method = NULL;
55 
56 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
57     m_TargetNotifyHandle = NULL;
58 #elif (FX_CORE_MODE == FX_CORE_USER_MODE)
59     m_TargetNotifyHandle = WUDF_TARGET_CONTEXT_INVALID;
60 
61     m_pIoDispatcher = NULL;
62     m_pRemoteDispatcher = NULL;
63     m_NotificationCallback = NULL;
64 #endif
65 }
66 
67 FxIoTargetRemote::~FxIoTargetRemote()
68 {
69 }
70 
71 _Must_inspect_result_
72 NTSTATUS
73 FxIoTargetRemote::_Create(
74     __in PFX_DRIVER_GLOBALS FxDriverGlobals,
75     __in PWDF_OBJECT_ATTRIBUTES Attributes,
76     __in CfxDeviceBase* Device,
77     __out FxIoTargetRemote** Target
78     )
79 {
80     FxIoTargetRemote* pTarget;
81     FxObject* pParent;
82     WDFOBJECT hTarget;
83     NTSTATUS status;
84 
85     *Target = NULL;
86 
87     if (Attributes == NULL || Attributes->ParentObject == NULL) {
88         pParent = Device;
89     }
90     else {
91         CfxDeviceBase* pSearchDevice;
92 
93         FxObjectHandleGetPtr(FxDriverGlobals,
94                              Attributes->ParentObject,
95                              FX_TYPE_OBJECT,
96                              (PVOID*) &pParent);
97 
98         pSearchDevice = FxDeviceBase::_SearchForDevice(pParent, NULL);
99 
100         if (pSearchDevice == NULL) {
101             status = STATUS_INVALID_DEVICE_REQUEST;
102 
103             DoTraceLevelMessage(
104                 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
105                 "Attributes->ParentObject 0x%p must have WDFDEVICE as an "
106                 "eventual ancestor, %!STATUS!",
107                 Attributes->ParentObject, status);
108 
109             return status;
110         }
111         else if (pSearchDevice != Device) {
112             status = STATUS_INVALID_DEVICE_REQUEST;
113 
114             DoTraceLevelMessage(
115                 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
116                 "Attributes->ParentObject 0x%p ancestor is WDFDEVICE %p, but "
117                 "not the same WDFDEVICE 0x%p passed to WdfIoTargetCreate, "
118                 "%!STATUS!",
119                 Attributes->ParentObject, pSearchDevice->GetHandle(),
120                 Device->GetHandle(), status);
121 
122             return status;
123         }
124     }
125 
126     pTarget = new (FxDriverGlobals, Attributes)
127         FxIoTargetRemote(FxDriverGlobals);
128 
129     if (pTarget == NULL) {
130         status =  STATUS_INSUFFICIENT_RESOURCES;
131         DoTraceLevelMessage(
132             FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
133             "Could not allocate memory for target, %!STATUS!", status);
134         return status;
135     }
136 
137     //
138     // initialize the new target
139     //
140     status = pTarget->InitRemote(Device);
141     if (!NT_SUCCESS(status)) {
142         return status;
143     }
144 
145     //
146     // Commit and apply the attributes
147     //
148     status = pTarget->Commit(Attributes, &hTarget, pParent);
149 
150     if (NT_SUCCESS(status)) {
151         *Target = pTarget;
152     }
153     else {
154         //
155         // This will properly clean up the target's state and free it
156         //
157         DoTraceLevelMessage(
158             FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
159             "Commit failed for target, %!STATUS!", status);
160         pTarget->DeleteFromFailedCreate();
161     }
162 
163     return status;
164 }
165 
166 NTSTATUS
167 FxIoTargetRemote::InitRemote(
168     __in FxDeviceBase* Device
169     )
170 {
171     NTSTATUS status;
172 
173     //
174     // do the base class mode-specific initialization
175     //
176     status = FxIoTarget::InitModeSpecific(Device); // __super call
177     if (!NT_SUCCESS(status)) {
178         return status;
179     }
180 
181     //
182     // Do mode-specific initilialization
183     //
184     status = InitRemoteModeSpecific(Device);
185     if (!NT_SUCCESS(status)) {
186         return status;
187     }
188 
189     m_Driver = Device->GetDriver();
190 
191     SetDeviceBase(Device);
192     m_InStackDevice = Device->GetDeviceObject();
193 
194     (void) Device->AddIoTarget(this);
195 
196     return STATUS_SUCCESS;
197 }
198 
199 _Must_inspect_result_
200 NTSTATUS
201 FxIoTargetRemote::Open(
202     __in PWDF_IO_TARGET_OPEN_PARAMS OpenParams
203     )
204 {
205     FxIoTargetRemoveOpenParams params, *pParams;
206     UNICODE_STRING name;
207     LIST_ENTRY pended;
208     WDF_IO_TARGET_OPEN_TYPE type;
209     NTSTATUS status;
210     BOOLEAN close, reopen;
211     PVOID pEa;
212     ULONG eaLength;
213     KIRQL irql;
214 
215     RtlZeroMemory(&name, sizeof(name));
216     close = FALSE;
217     reopen = OpenParams->Type == WdfIoTargetOpenReopen ? TRUE : FALSE;
218 
219     pEa = NULL;
220     eaLength = 0;
221 
222     //
223     // We only support reopening using stored settings when we open by name
224     //
225     if (reopen && m_OpenParams.OpenType != WdfIoTargetOpenByName) {
226         status = STATUS_INVALID_DEVICE_REQUEST;
227         DoTraceLevelMessage(
228             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
229             "Reopen only supported if the open type is WdfIoTargetOpenByName WDFIOTARGET %p %!STATUS!",
230             GetObjectHandle(), status);
231         return status;
232     }
233 
234     //
235     // Must preallocate all settings now
236     //
237     if (reopen) {
238         //
239         // convert the type into the type used for the previous open
240         //
241         type = m_OpenParams.OpenType;
242         pParams = &m_OpenParams;
243     }
244     else {
245         type = OpenParams->Type;
246         pParams = &params;
247 
248         if (OpenParams->Type == WdfIoTargetOpenByName) {
249 
250             status = FxDuplicateUnicodeString(GetDriverGlobals(),
251                                               &OpenParams->TargetDeviceName,
252                                               &name);
253             if (!NT_SUCCESS(status)) {
254                 DoTraceLevelMessage(
255                     GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
256                     "Could not allocate memory for target name for WDFIOTARGET %p",
257                     GetObjectHandle());
258                 goto Done;
259             }
260             if (OpenParams->EaBuffer != NULL && OpenParams->EaBufferLength > 0) {
261 
262                 pEa = FxPoolAllocate(GetDriverGlobals(),
263                                      PagedPool,
264                                      OpenParams->EaBufferLength);
265 
266                 if (pEa == NULL) {
267                     DoTraceLevelMessage(
268                         GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
269                         "Could not allocate memory for target name "
270                         "for WDFIOTARGET %p", GetObjectHandle());
271                     status = STATUS_INSUFFICIENT_RESOURCES;
272                     goto Done;
273                 }
274                 else {
275                     eaLength = OpenParams->EaBufferLength;
276                     RtlCopyMemory(pEa, OpenParams->EaBuffer, eaLength);
277                 }
278             }
279         }
280     }
281 
282     Lock(&irql);
283 
284     if (m_State == WdfIoTargetDeleted) {
285         DoTraceLevelMessage(
286             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
287             "Opening WDFIOTARGET %p which is removed, state %d",
288             GetObjectHandle(), m_State);
289         status = STATUS_INVALID_DEVICE_STATE;
290     }
291     else if (m_OpenState != FxIoTargetRemoteOpenStateClosed) {
292         //
293         // We are either open or are opening
294         //
295         DoTraceLevelMessage(
296             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
297             "Opening an already open WDFIOTARGET %p, open state %d",
298             GetObjectHandle(), m_OpenState);
299         status = STATUS_INVALID_DEVICE_STATE;
300     }
301     else {
302         DoTraceLevelMessage(
303             GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
304             "Opening WDFIOTARGET %p", GetObjectHandle());
305 
306         //
307         // Clear the event so that if something is waiting on the state
308         // transition, they will block until we are done.
309         //
310         m_OpenedEvent.Clear();
311 
312         m_OpenState = FxIoTargetRemoteOpenStateOpening;
313         status = STATUS_SUCCESS;
314     }
315     Unlock(irql);
316 
317     if (!NT_SUCCESS(status)) {
318         goto Done;
319     }
320 
321     ASSERT(m_TargetFileObject == NULL);
322     ASSERT(m_TargetDevice == NULL);
323     ASSERT(m_TargetPdo == NULL);
324     ASSERT(m_TargetHandle == NULL);
325 
326     //
327     // m_TargetNotifyHandle can be a valid value if the caller has previously
328     // opened the target, received a query remove, then a cancel remove, and
329     // is now reopening the target.
330     //
331     UnregisterForPnpNotification(m_TargetNotifyHandle);
332     ResetTargetNotifyHandle();
333 
334     //
335     // Only clear the open parameters if we are not attempting a reopen.
336     //
337     if (reopen == FALSE) {
338         m_OpenParams.Clear();
339     }
340 
341     switch (type) {
342     case WdfIoTargetOpenUseExistingDevice:
343         KMDF_ONLY_CODE_PATH_ASSERT();
344 
345         //
346         // OpenParams must be non NULL b/c we can't reopen a target with a
347         // previous device object.
348         //
349         ASSERT(OpenParams->Type == WdfIoTargetOpenUseExistingDevice);
350 
351         m_TargetDevice = (MdDeviceObject) OpenParams->TargetDeviceObject;
352         m_TargetFileObject = (MdFileObject) OpenParams->TargetFileObject;
353         m_TargetHandle = NULL;
354 
355         //
356         // By taking a manual reference here, we simplify the code in
357         // FxIoTargetRemote::Close where we can assume there is an outstanding
358         // reference on the PFILE_OBJECT at all times as long as we have a non
359         // NULL pointer.
360         //
361         if (m_TargetFileObject != NULL) {
362             Mx::MxReferenceObject(m_TargetFileObject);
363         }
364 
365         status = STATUS_SUCCESS;
366 
367         break;
368 
369     case WdfIoTargetOpenLocalTargetByFile:
370         UMDF_ONLY_CODE_PATH_ASSERT();
371 
372         status = OpenLocalTargetByFile(OpenParams);
373         break;
374 
375     case WdfIoTargetOpenByName:
376         //
377         // Only capture the open parameters if we are not reopening.
378         //
379         if (reopen == FALSE) {
380             pParams->Set(OpenParams, &name, pEa, eaLength);
381         }
382 
383         status = OpenTargetHandle(OpenParams, pParams);
384         if (NT_SUCCESS(status)) {
385             if (reopen == FALSE) {
386                 m_OpenParams.Set(OpenParams, &name, pEa, eaLength);
387 
388                 //
389                 // Setting pEa to NULL stops it from being freed later.
390                 // Zeroing out name stops it from being freed later.
391                 //
392                 pEa = NULL;
393                 RtlZeroMemory(&name, sizeof(name));
394             }
395         }
396         else {
397             close = TRUE;
398         }
399         break;
400     }
401 
402     InitializeListHead(&pended);
403 
404     //
405     // Get Target file object for KMDF. Noop for UMDF.
406     //
407     if (NT_SUCCESS(status)) {
408         status = GetTargetDeviceRelations(&close);
409     }
410 
411     if (NT_SUCCESS(status) && CanRegisterForPnpNotification()) {
412         if (reopen == FALSE) {
413             //
414             // Set the values before the register so that if a notification
415             // comes in before the register returns, we have a function to call.
416             //
417             m_EvtQueryRemove.m_Method = OpenParams->EvtIoTargetQueryRemove;
418             m_EvtRemoveCanceled.m_Method = OpenParams->EvtIoTargetRemoveCanceled;
419             m_EvtRemoveComplete.m_Method = OpenParams->EvtIoTargetRemoveComplete;
420         }
421 
422         status = RegisterForPnpNotification();
423 
424         //
425         // Even if we can't register, we still are successful in opening
426         // up the device and we will proceed from there.
427         //
428         if (!NT_SUCCESS(status)) {
429             DoTraceLevelMessage(
430                 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
431                 "WDFIOTARGET %p, could not register pnp notification, %!STATUS! not "
432                 "treated as an error", GetObjectHandle(), status);
433 
434             m_EvtQueryRemove.m_Method = NULL;
435             m_EvtRemoveCanceled.m_Method = NULL;
436             m_EvtRemoveComplete.m_Method = NULL;
437 
438             status = STATUS_SUCCESS;
439         }
440     }
441 
442     //
443     // UMDF only. Bind handle to remote dispatcher.
444     //
445 #if (FX_CORE_MODE == FX_CORE_USER_MODE)
446     if (NT_SUCCESS(status) && type != WdfIoTargetOpenLocalTargetByFile) {
447         status = BindToHandle();
448         if (!NT_SUCCESS(status)) {
449             close = TRUE;
450         }
451     }
452 #endif
453 
454     Lock(&irql);
455 
456     if (NT_SUCCESS(status)) {
457 
458 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
459         m_TargetStackSize = m_TargetDevice->StackSize;
460         m_TargetIoType = GetTargetIoType();
461 #endif
462 
463         m_OpenState = FxIoTargetRemoteOpenStateOpen;
464 
465         //
466         // Set our state to started.  This will also resend any pended requests
467         // due to a query remove.
468         //
469         status = GotoStartState(&pended, FALSE);
470 
471         //
472         // We could not successfully start, close back down
473         //
474         if (!NT_SUCCESS(status)) {
475             DoTraceLevelMessage(
476                 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
477                 "WDFIOTARGET %p could not transition to started state, %!STATUS!",
478                 GetObjectHandle(), status);
479 
480             close = TRUE;
481         }
482     }
483     else {
484         m_OpenState = FxIoTargetRemoteOpenStateClosed;
485     }
486 
487     //
488     // No matter what, indicate to any waiters that our state change has
489     // completed.
490     //
491     m_OpenedEvent.Set();
492 
493     Unlock(irql);
494 
495 Done:
496     //
497     // Resubmit any reads that were pended until now.
498     //
499     if (NT_SUCCESS(status)) {
500         SubmitPendedRequests(&pended);
501     }
502     else if (close) {
503         Close(FxIoTargetRemoteCloseReasonPlainClose);
504     }
505 
506     if (name.Buffer != NULL) {
507         FxPoolFree(name.Buffer);
508     }
509 
510     if (pEa != NULL) {
511         FxPoolFree(pEa);
512     }
513 
514     return status;
515 }
516 
517 
518 VOID
519 FxIoTargetRemote::Close(
520     __in FxIoTargetRemoteCloseReason Reason
521     )
522 {
523     FxIoTargetClearedPointers pointers;
524     MdTargetNotifyHandle pNotifyHandle;
525     SINGLE_LIST_ENTRY sent;
526     LIST_ENTRY pended;
527     WDF_IO_TARGET_STATE removeState;
528     KIRQL irql;
529     BOOLEAN wait;
530     PFX_DRIVER_GLOBALS pFxDriverGlobals;
531 
532     pFxDriverGlobals = GetDriverGlobals();
533     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
534         "enter:  WDFIOTARGET %p, reason %d", GetObjectHandle(), Reason);
535 
536     RtlZeroMemory(&pointers, sizeof(pointers));
537     pNotifyHandle = NULL;
538 
539     sent.Next = NULL;
540     InitializeListHead(&pended);
541 
542     wait = FALSE;
543 
544     //
545     // Pick a value that is not used anywhere in the function and make sure that
546     // we have changed it, before we go to the Remove state
547     //
548 #pragma prefast(suppress: __WARNING_UNUSED_SCALAR_ASSIGNMENT, "PFD is warning that the following assignement is unused. Suppress it to prevent changing any logic.")
549     removeState = WdfIoTargetStarted;
550 
551 CheckState:
552     Lock(&irql);
553 
554     //
555     // If we are in the process of opening the target, wait for that to finish.
556     //
557     if (m_OpenState == FxIoTargetRemoteOpenStateOpening) {
558         Unlock(irql);
559 
560         DoTraceLevelMessage(
561             pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
562             "Closing WDFIOTARGET %p which is opening, waiting on event %p",
563             GetObjectHandle(), m_OpenedEvent.GetEvent());
564 
565         m_OpenedEvent.EnterCRAndWaitAndLeave();
566 
567         //
568         // Jump back to the top and recheck
569         //
570         goto CheckState;
571     }
572 
573     if (Reason == FxIoTargetRemoteCloseReasonDelete) {
574         DoTraceLevelMessage(
575             pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
576             "Closing WDFIOTARGET %p, reason:   delete", GetObjectHandle());
577 
578         removeState = WdfIoTargetDeleted;
579     }
580     else if (m_OpenState == FxIoTargetRemoteOpenStateOpen) {
581         if (Reason == FxIoTargetRemoteCloseReasonQueryRemove) {
582             DoTraceLevelMessage(
583                 pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
584                 "Closing WDFIOTARGET %p, reason:   query remove",
585                 GetObjectHandle());
586             //
587             // Not really being removed, but that is what the API name is...
588             //
589             removeState = WdfIoTargetClosedForQueryRemove;
590         }
591         else {
592 
593             DoTraceLevelMessage(
594                 pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
595                 "Closing WDFIOTARGET %p, reason:   close", GetObjectHandle());
596 
597             if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,9)) {
598                 removeState = WdfIoTargetClosed;
599             }
600             else {
601                 removeState = WdfIoTargetClosedForQueryRemove;
602             }
603         }
604 
605         //
606         // Either way, we are no longer open for business
607         //
608         m_OpenState = FxIoTargetRemoteOpenStateClosed;
609     }
610     else {
611         DoTraceLevelMessage(
612             pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
613             "Closing WDFIOTARGET %p which is not open", GetObjectHandle());
614 
615         //
616         // We are not opened, so treat this as a cleanup
617         //
618         removeState = WdfIoTargetClosed;
619     }
620 
621     DoTraceLevelMessage(
622         pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
623         "WDFIOTARGET %p:  fileobj %p, devobj %p, handle %p, notify handle %I64d",
624         GetObjectHandle(), m_TargetFileObject,
625         m_TargetDevice, m_TargetHandle, (UINT64)m_TargetNotifyHandle);
626 
627     if (Reason != FxIoTargetRemoteCloseReasonQueryRemove) {
628         //
629         // If we are closing for a query remove, we want to keep the handle
630         // around so that we can be notified of the final close or if the close
631         // was canceled.
632         //
633         pNotifyHandle = m_TargetNotifyHandle;
634         ResetTargetNotifyHandle();
635     }
636 
637     ASSERT(removeState != WdfIoTargetStarted);
638     m_ClearedPointers =  &pointers;
639     GotoRemoveState(removeState, &pended, &sent, FALSE, &wait);
640 
641     Unlock(irql);
642 
643     UnregisterForPnpNotification(pNotifyHandle);
644 
645     //
646     // Complete any requests we might have pulled off of our lists
647     //
648     CompletePendedRequestList(&pended);
649     _CancelSentRequests(&sent);
650 
651     //
652     // We were just removed, wait for any I/O to complete back if necessary.
653     //
654     if (wait) {
655         DoTraceLevelMessage(
656             pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
657             "WDFIOTARGET %p, waiting for stop to complete", GetObjectHandle());
658 
659         WaitForSentIoToComplete();
660     }
661 
662     switch (Reason) {
663     case FxIoTargetRemoteCloseReasonQueryRemove:
664         //
665         // m_OpenParams is needed for reopen on canceled query remove
666         //
667         DO_NOTHING();
668         break;
669 
670     case FxIoTargetRemoteCloseReasonDelete:
671         m_OpenParams.Clear();
672         break;
673 
674     default:
675         //
676         // If this object is not about to be deleted, we need to revert some
677         // of the state that just changed.
678         //
679         m_SentIoEvent.Clear();
680         break;
681     }
682 
683     if (removeState == WdfIoTargetDeleted) {
684        WaitForDisposeEvent();
685     }
686 
687     //
688     // Finally, close down our handle and pointers
689     //
690     if (pointers.TargetPdo != NULL) {
691         DoTraceLevelMessage(
692             pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET,
693             "WDFIOTARGET %p derefing PDO %p on close",
694             GetObjectHandle(), pointers.TargetPdo);
695 
696         Mx::MxDereferenceObject(pointers.TargetPdo);
697     }
698 
699     if (pointers.TargetFileObject != NULL) {
700         DoTraceLevelMessage(
701             pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET,
702             "WDFIOTARGET %p derefing FileObj %p on close",
703             GetObjectHandle(), pointers.TargetFileObject);
704         Mx::MxDereferenceObject(pointers.TargetFileObject);
705 
706 #if (FX_CORE_MODE == FX_CORE_USER_MODE)
707         CloseWdfFileObject(pointers.TargetFileObject);
708 #endif
709     }
710 
711 #if (FX_CORE_MODE == FX_CORE_USER_MODE)
712         UnbindHandle(&pointers);
713 #endif
714 
715     if (pointers.TargetHandle != NULL) {
716         DoTraceLevelMessage(
717             pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET,
718             "WDFIOTARGET %p closing handle %p on close",
719             GetObjectHandle(), pointers.TargetHandle);
720         Mx::MxClose(pointers.TargetHandle);
721     }
722 }
723 
724 VOID
725 FxIoTargetRemote::ClearTargetPointers(
726     VOID
727     )
728 {
729     DoTraceLevelMessage(
730         GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIOTARGET,
731         "WDFIOTARGET %p cleared pointers %p state %!WDF_IO_TARGET_STATE!,"
732         " open state %d, pdo %p, fileobj %p, handle %p",
733         GetObjectHandle(), m_ClearedPointers, m_State, m_OpenState, m_TargetPdo,
734         m_TargetFileObject, m_TargetHandle);
735 
736     //
737     // Check to see if the caller who is changing state wants these pointer
738     // values before they being cleared out.
739     //
740     if (m_ClearedPointers != NULL) {
741         m_ClearedPointers->TargetPdo = m_TargetPdo;
742         m_ClearedPointers->TargetFileObject = m_TargetFileObject;
743         m_ClearedPointers->TargetHandle = m_TargetHandle;
744         m_ClearedPointers = NULL;
745     }
746 
747     //
748     // m_TargetHandle is only an FxIoTargetRemote field, clear it now
749     //
750     m_TargetHandle = NULL;
751 
752     //
753     // m_TargetPdo and m_TargetFileObject will be cleared in the following call.
754     //
755     // m_TargetNotifyHandle is not cleared in the following call and is left
756     // valid because we want to receive the notification about query remove being
757     // canceled or completing.  When we receive either of those notifications,
758     // m_TargetNotifyHandle will be freed then.
759     //
760     FxIoTarget::ClearTargetPointers(); // __super call
761 }
762 
763 VOID
764 FxIoTargetRemote::Remove(
765     VOID
766     )
767 {
768     //
769     // Close is the same as remove in this object
770     //
771     Close(FxIoTargetRemoteCloseReasonDelete);
772 
773     //
774     // Do mode-specific work
775     //
776     RemoveModeSpecific();
777 
778     return ;
779 }
780 
781 VOID
782 FxIoTargetRemoveOpenParams::Clear(
783     VOID
784     )
785 {
786     if (EaBuffer != NULL) {
787         FxPoolFree(EaBuffer);
788     }
789 
790     if (TargetDeviceName.Buffer != NULL) {
791         FxPoolFree(TargetDeviceName.Buffer);
792     }
793 
794     RtlZeroMemory(this, sizeof(FxIoTargetRemoveOpenParams));
795 }
796 
797 VOID
798 FxIoTargetRemoveOpenParams::Set(
799     __in PWDF_IO_TARGET_OPEN_PARAMS OpenParams,
800     __in PUNICODE_STRING Name,
801     __in PVOID Ea,
802     __in ULONG EaLength
803     )
804 {
805     OpenType = WdfIoTargetOpenByName;
806 
807     EaBuffer = Ea;
808     EaBufferLength = EaLength;
809 
810     RtlCopyMemory(&TargetDeviceName, Name, sizeof(UNICODE_STRING));
811 
812     DesiredAccess = OpenParams->DesiredAccess;
813     FileAttributes = OpenParams->FileAttributes;
814     ShareAccess = OpenParams->ShareAccess;
815     CreateDisposition = OpenParams->CreateDisposition;
816     CreateOptions = OpenParams->CreateOptions;
817 
818     if (OpenParams->AllocationSize != NULL) {
819         AllocationSize.QuadPart = *(OpenParams->AllocationSize);
820         AllocationSizePointer = &AllocationSize;
821     }
822     else {
823         AllocationSizePointer = NULL;
824     }
825 }
826