1 /*++
2
3 Copyright (c) Microsoft Corporation
4
5 Module Name:
6
7 FxIoTargetRemoteKm.cpp
8
9 Abstract:
10
11 Author:
12
13 Environment:
14
15 kernel mode only
16
17 Revision History:
18
19 --*/
20
21 #include "../../fxtargetsshared.hpp"
22
23 extern "C" {
24 // #include "FxIoTargetRemoteKm.tmh"
25 }
26
27 #include <initguid.h>
28 #include "wdmguid.h"
29
30 _Must_inspect_result_
31 NTSTATUS
32 STDCALL
_PlugPlayNotification(__in PVOID NotificationStructure,__inout_opt PVOID Context)33 FxIoTargetRemote::_PlugPlayNotification(
34 __in PVOID NotificationStructure,
35 __inout_opt PVOID Context
36 )
37 {
38 PFX_DRIVER_GLOBALS pFxDriverGlobals;
39 PTARGET_DEVICE_REMOVAL_NOTIFICATION pNotification;
40 FxIoTargetRemote* pThis;
41 NTSTATUS status;
42
43 ASSERT(Mx::MxGetCurrentIrql() < DISPATCH_LEVEL);
44 pNotification = (PTARGET_DEVICE_REMOVAL_NOTIFICATION) NotificationStructure;
45 pThis = (FxIoTargetRemote*) Context;
46
47 //
48 // In one of these callbacks, the driver may decide to delete the target.
49 // If that is the case, we need to be able to return and deref the object until
50 // we are done.
51 //
52 pThis->ADDREF((PVOID)_PlugPlayNotification);
53
54 pFxDriverGlobals = pThis->GetDriverGlobals();
55
56 status = STATUS_SUCCESS;
57
58 if (FxIsEqualGuid(&pNotification->Event, &GUID_TARGET_DEVICE_QUERY_REMOVE)) {
59
60 DoTraceLevelMessage(
61 pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
62 "WDFIOTARGET %p: query remove notification", pThis->GetObjectHandle());
63
64 //
65 // Device is gracefully being removed. PnP is asking us to close down
66 // the target. If there is a driver callback, there is *no* default
67 // behavior. This is because we don't know what the callback is going
68 // to do. For instance, the driver could reopen the target to a
69 // different device in a multi-path scenario.
70 //
71 if (pThis->m_EvtQueryRemove.m_Method != NULL) {
72 status = pThis->m_EvtQueryRemove.Invoke(pThis->GetHandle());
73 }
74 else {
75 DoTraceLevelMessage(
76 pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
77 "WDFIOTARGET %p: query remove, default action (close for QR)",
78 pThis->GetObjectHandle());
79
80 //
81 // No callback, close it down conditionally.
82 //
83 pThis->Close(FxIoTargetRemoteCloseReasonQueryRemove);
84 }
85 }
86 else if (FxIsEqualGuid(&pNotification->Event, &GUID_TARGET_DEVICE_REMOVE_COMPLETE)) {
87
88 DoTraceLevelMessage(
89 pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
90 "WDFIOTARGET %p: remove complete notification", pThis->GetObjectHandle());
91
92 //
93 // The device was surprise removed, close it for good if the driver has
94 // no override.
95 //
96 if (pThis->m_EvtRemoveComplete.m_Method != NULL) {
97 pThis->m_EvtRemoveComplete.Invoke(pThis->GetHandle());
98 }
99 else {
100 DoTraceLevelMessage(
101 pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
102 "WDFIOTARGET %p: remove complete, default action (close)",
103 pThis->GetObjectHandle());
104
105 //
106 // The device is now gone for good. Close down the target for good.
107 //
108 pThis->Close(FxIoTargetRemoteCloseReasonPlainClose);
109 }
110 }
111 else if (FxIsEqualGuid(&pNotification->Event, &GUID_TARGET_DEVICE_REMOVE_CANCELLED)) {
112
113 DoTraceLevelMessage(
114 pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
115 "WDFIOTARGET %p: remove canceled notification", pThis->GetObjectHandle());
116
117 if (pThis->m_EvtRemoveCanceled.m_Method != NULL) {
118 pThis->m_EvtRemoveCanceled.Invoke(pThis->GetHandle());
119 }
120 else {
121 WDF_IO_TARGET_OPEN_PARAMS params;
122
123 DoTraceLevelMessage(
124 pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
125 "WDFIOTARGET %p: remove canceled, default action (reopen)",
126 pThis->GetObjectHandle());
127
128 WDF_IO_TARGET_OPEN_PARAMS_INIT_REOPEN(¶ms);
129
130 //
131 // Attempt to reopen the target with stored settings
132 //
133 status = pThis->Open(¶ms);
134 }
135 }
136
137 pThis->RELEASE((PVOID)_PlugPlayNotification);
138
139 return status;
140 }
141
142 NTSTATUS
RegisterForPnpNotification()143 FxIoTargetRemote::RegisterForPnpNotification(
144 )
145 {
146 NTSTATUS status;
147
148 //
149 // Register for PNP notifications on the handle we just opened.
150 // This will notify us of pnp state changes on the handle.
151 //
152 status = IoRegisterPlugPlayNotification(
153 EventCategoryTargetDeviceChange,
154 0,
155 m_TargetFileObject,
156 m_Driver->GetDriverObject(),
157 _PlugPlayNotification,
158 this,
159 &m_TargetNotifyHandle);
160
161 return status;
162 }
163
164 VOID
UnregisterForPnpNotification(_In_ MdTargetNotifyHandle Handle)165 FxIoTargetRemote::UnregisterForPnpNotification(
166 _In_ MdTargetNotifyHandle Handle
167 )
168 {
169 if (Handle != NULL) {
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193 if (FxLibraryGlobals.IoUnregisterPlugPlayNotificationEx != NULL) {
194 FxLibraryGlobals.IoUnregisterPlugPlayNotificationEx(Handle);
195 }
196 else {
197 IoUnregisterPlugPlayNotification(Handle);
198 }
199 }
200 }
201
202 NTSTATUS
OpenTargetHandle(_In_ PWDF_IO_TARGET_OPEN_PARAMS OpenParams,_Inout_ FxIoTargetRemoveOpenParams * pParams)203 FxIoTargetRemote::OpenTargetHandle(
204 _In_ PWDF_IO_TARGET_OPEN_PARAMS OpenParams,
205 _Inout_ FxIoTargetRemoveOpenParams* pParams
206 )
207 {
208 OBJECT_ATTRIBUTES oa;
209 IO_STATUS_BLOCK ioStatus;
210 NTSTATUS status;
211
212 InitializeObjectAttributes(&oa,
213 &pParams->TargetDeviceName,
214 OBJ_KERNEL_HANDLE,
215 NULL,
216 NULL);
217
218 status = ZwCreateFile(&m_TargetHandle,
219 pParams->DesiredAccess,
220 &oa,
221 &ioStatus,
222 pParams->AllocationSizePointer,
223 pParams->FileAttributes,
224 pParams->ShareAccess,
225 pParams->CreateDisposition,
226 pParams->CreateOptions,
227 pParams->EaBuffer,
228 pParams->EaBufferLength);
229
230 OpenParams->FileInformation = (ULONG)ioStatus.Information;
231
232 if (NT_SUCCESS(status)) {
233 DoTraceLevelMessage(
234 GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGIOTARGET,
235 "ZwCreateFile for WDFIOTARGET %p returned status %!STATUS!, info 0x%x",
236 GetObjectHandle(), status, (ULONG) ioStatus.Information);
237
238 //
239 // The open operation was successful. Dereference the file handle and
240 // obtain a pointer to the device object for the handle.
241 //
242 status = ObReferenceObjectByHandle(
243 m_TargetHandle,
244 pParams->DesiredAccess,
245 *IoFileObjectType,
246 KernelMode,
247 (PVOID*) &m_TargetFileObject,
248 NULL);
249
250 if (NT_SUCCESS(status)) {
251 m_TargetDevice = IoGetRelatedDeviceObject(m_TargetFileObject);
252
253 if (m_TargetDevice == NULL) {
254 DoTraceLevelMessage(
255 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
256 "WDFIOTARGET %p, could not convert filobj %p to devobj",
257 GetObjectHandle(), m_TargetFileObject);
258
259 status = STATUS_NO_SUCH_DEVICE;
260 }
261 }
262 else {
263 DoTraceLevelMessage(
264 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
265 "WDFIOTARGET %p, could not convert handle %p to fileobject, "
266 "status %!STATUS!",
267 GetObjectHandle(), m_TargetHandle, status);
268 }
269 }
270 else {
271 DoTraceLevelMessage(
272 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
273 "ZwCreateFile for WDFIOTARGET %p returned status %!STATUS!, info 0x%x",
274 GetObjectHandle(), status, (ULONG) ioStatus.Information);
275 }
276
277 return status;
278 }
279
280 NTSTATUS
GetTargetDeviceRelations(_Inout_ BOOLEAN * Close)281 FxIoTargetRemote::GetTargetDeviceRelations(
282 _Inout_ BOOLEAN* Close
283 )
284 {
285 PDEVICE_OBJECT pTopOfStack;
286 FxAutoIrp irp(NULL);
287 PIRP pIrp;
288 NTSTATUS status;
289
290 pTopOfStack = IoGetAttachedDeviceReference(m_TargetDevice);
291
292 pIrp = IoAllocateIrp(pTopOfStack->StackSize, FALSE);
293
294 if (pIrp != NULL) {
295 PIO_STACK_LOCATION stack;
296
297 irp.SetIrp(pIrp);
298
299 stack = irp.GetNextIrpStackLocation();
300 stack->MajorFunction = IRP_MJ_PNP;
301 stack->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
302 stack->Parameters.QueryDeviceRelations.Type = TargetDeviceRelation;
303
304 //
305 // Initialize the status to error in case the bus driver decides not
306 // to set it correctly.
307 //
308 irp.SetStatus(STATUS_NOT_SUPPORTED);
309
310 status = irp.SendIrpSynchronously(pTopOfStack);
311
312 if (NT_SUCCESS(status)) {
313 PDEVICE_RELATIONS pRelations;
314
315 pRelations = (PDEVICE_RELATIONS) irp.GetInformation();
316
317 ASSERT(pRelations != NULL);
318
319 //
320 // m_TargetPdo was referenced by the bus driver, it will be
321 // dereferenced when the target is closed.
322 //
323 m_TargetPdo = pRelations->Objects[0];
324
325 //
326 // We, as the caller, are responsible for freeing the relations
327 // that the bus driver allocated.
328 //
329 ExFreePool(pRelations);
330 }
331 else {
332 //
333 // Could not retrieve the PDO pointer, error handled later
334 //
335 DO_NOTHING();
336 }
337 }
338 else {
339 //
340 // Could not even allocate an irp, failure.
341 //
342 status = STATUS_INSUFFICIENT_RESOURCES;
343 DoTraceLevelMessage(
344 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
345 "Unable to allocate memory for IRP WDFIOTARGET %p, %!STATUS!",
346 GetObjectHandle(), status);
347 }
348
349 //
350 // Only fail the open if we cannot allocate an irp or if the lower
351 // driver could not allocate a relations.
352 //
353 if (status == STATUS_INSUFFICIENT_RESOURCES) {
354 *Close = TRUE;
355 }
356 else {
357 status = STATUS_SUCCESS;
358 }
359
360 //
361 // Remove the reference taken by IoGetAttachedDeviceReference
362 //
363 ObDereferenceObject(pTopOfStack);
364
365 return status;
366 }
367
368