1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxCxDeviceInitApi.cpp
8 
9 Abstract:
10 
11     This module exposes the "C" interface to the FxDevice object
12     for the class extensions.
13 
14 Author:
15 
16 
17 
18 Environment:
19 
20     Both kernel and user mode
21 
22 Revision History:
23 
24 
25 
26 --*/
27 
28 #include "coreprivshared.hpp"
29 
30 extern "C" {
31 // #include "FxCxDeviceInitApi.tmh"
32 }
33 
34 //
35 // Extern "C" the entire file
36 //
37 extern "C" {
38 
39 __inline
40 static
41 NTSTATUS
42 FxValiateCx(
43     __in PFX_DRIVER_GLOBALS FxDriverGlobals,
44     __in PFX_DRIVER_GLOBALS CxDriverGlobals
45     )
46 {
47     NTSTATUS status = STATUS_SUCCESS;
48 
49     if (FxIsClassExtension(FxDriverGlobals, CxDriverGlobals) == FALSE) {
50         status = STATUS_INVALID_DEVICE_REQUEST;
51         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
52                             "This function can only be called by a WDF "
53                             "extension driver, Driver 0x%p, %!STATUS!",
54                             CxDriverGlobals->Public.Driver, status);
55         FxVerifierDbgBreakPoint(FxDriverGlobals);
56     }
57 
58     return status;
59 }
60 
61 _Must_inspect_result_
62 __drv_maxIRQL(DISPATCH_LEVEL)
63 WDFAPI
64 NTSTATUS
65 WDFEXPORT(WdfCxDeviceInitAssignWdmIrpPreprocessCallback)(
66     __in
67     PWDF_DRIVER_GLOBALS DriverGlobals,
68     __in
69     PWDFCXDEVICE_INIT   CxDeviceInit,
70     __in
71     PFN_WDFCXDEVICE_WDM_IRP_PREPROCESS EvtCxDeviceWdmIrpPreprocess,
72     __in
73     UCHAR MajorFunction,
74     __drv_when(NumMinorFunctions > 0, __in_bcount(NumMinorFunctions))
75     __drv_when(NumMinorFunctions == 0, __in_opt)
76     PUCHAR MinorFunctions,
77     __in
78     ULONG NumMinorFunctions
79     )
80 {
81     DDI_ENTRY();
82 
83     PFX_DRIVER_GLOBALS fxDriverGlobals;
84     PFX_DRIVER_GLOBALS cxDriverGlobals;
85     NTSTATUS status;
86 
87     cxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
88     FxPointerNotNull(cxDriverGlobals, CxDeviceInit);
89     fxDriverGlobals = CxDeviceInit->ClientDriverGlobals;
90 
91     //
92     // Caller must be a class extension driver.
93     //
94     status = FxValiateCx(fxDriverGlobals, cxDriverGlobals);
95     if (!NT_SUCCESS(status)) {
96         goto Done;
97     }
98 
99     FxPointerNotNull(fxDriverGlobals, EvtCxDeviceWdmIrpPreprocess);
100 
101     if (NumMinorFunctions > 0) {
102         FxPointerNotNull(fxDriverGlobals, MinorFunctions);
103     }
104 
105     //
106     // ARRAY_SIZE(CxDeviceInit->PreprocessInfo->Dispatch) just returns a
107     // constant size, it does not actually deref PreprocessInfo (which could
108     // be NULL)
109     //
110     if (MajorFunction >= ARRAY_SIZE(CxDeviceInit->PreprocessInfo->Dispatch)) {
111         status = STATUS_INVALID_PARAMETER;
112         DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
113                             "MajorFunction %x is invalid, %!STATUS!",
114                             (ULONG)MajorFunction, status);
115 
116         goto Done;
117     }
118 
119     //
120     // CX must call this API multiple times if it wants to register preprocess callbacks for
121     // multiple IRP major codes.
122     //
123     if (CxDeviceInit->PreprocessInfo == NULL) {
124         CxDeviceInit->PreprocessInfo = new(fxDriverGlobals) FxIrpPreprocessInfo();
125         if (CxDeviceInit->PreprocessInfo == NULL) {
126             status = STATUS_INSUFFICIENT_RESOURCES;
127             DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
128                                 "Couldn't create object PreprocessInfo, "
129                                 "%!STATUS!", status);
130 
131             goto Done;
132         }
133         CxDeviceInit->PreprocessInfo->ClassExtension = TRUE;
134     }
135 
136     ASSERT(CxDeviceInit->PreprocessInfo->ClassExtension);
137 
138     if (NumMinorFunctions > 0) {
139         if (CxDeviceInit->PreprocessInfo->Dispatch[MajorFunction].NumMinorFunctions != 0) {
140             status = STATUS_INVALID_DEVICE_REQUEST;
141             DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
142                                 "Already assigned Minorfunctions, %!STATUS!",
143                                 status);
144             goto Done;
145         }
146 
147         CxDeviceInit->PreprocessInfo->Dispatch[MajorFunction].MinorFunctions =
148             (PUCHAR) FxPoolAllocate(fxDriverGlobals,
149                                     NonPagedPool,
150                                     sizeof(UCHAR) * NumMinorFunctions);
151 
152         if (CxDeviceInit->PreprocessInfo->Dispatch[MajorFunction].MinorFunctions == NULL) {
153             status = STATUS_INSUFFICIENT_RESOURCES;
154             DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
155                                 "Couldn't create object MinorFunctions, "
156                                 "%!STATUS!", status);
157             goto Done;
158         }
159 
160         RtlCopyMemory(
161             &CxDeviceInit->PreprocessInfo->Dispatch[MajorFunction].MinorFunctions[0],
162             &MinorFunctions[0],
163             NumMinorFunctions
164             );
165 
166         CxDeviceInit->PreprocessInfo->Dispatch[MajorFunction].NumMinorFunctions =
167             NumMinorFunctions;
168     }
169 
170     CxDeviceInit->PreprocessInfo->Dispatch[MajorFunction].EvtCxDevicePreprocess =
171         EvtCxDeviceWdmIrpPreprocess;
172 
173     status = STATUS_SUCCESS;
174 
175 Done:
176     return status;
177 }
178 
179 __drv_maxIRQL(DISPATCH_LEVEL)
180 VOID
181 WDFEXPORT(WdfCxDeviceInitSetIoInCallerContextCallback)(
182     __in
183     PWDF_DRIVER_GLOBALS DriverGlobals,
184     __in
185     PWDFCXDEVICE_INIT CxDeviceInit,
186     __in
187     PFN_WDF_IO_IN_CALLER_CONTEXT EvtIoInCallerContext
188     )
189 
190 /*++
191 
192 Routine Description:
193 
194     Registers an I/O pre-processing callback for the class extension device.
195 
196     If registered, any I/O for the device is first presented to this
197     callback function before being placed in any I/O Queue's.
198 
199     The callback is invoked in the thread and/or DPC context of the
200     original WDM caller as presented to the I/O package. No framework
201     threading, locking, synchronization, or queuing occurs, and
202     responsibility for synchronization is up to the device driver.
203 
204     This API is intended to support METHOD_NEITHER IRP_MJ_DEVICE_CONTROL's
205     which must access the user buffer in the original callers context. The
206     driver would probe and lock the buffer pages from within this event
207     handler using the functions supplied on the WDFREQUEST object, storing
208     any required mapped buffers and/or pointers on the WDFREQUEST context
209     whose size is set by the RequestContextSize of the WDF_DRIVER_CONFIG structure.
210 
211     It is the responsibility of this routine to either complete the request, or
212     pass it on to the I/O package through WdfDeviceEnqueueRequest(Device, Request).
213 
214 Arguments:
215 
216     CxDeviceInit - Class Extension Device initialization structure
217 
218     EvtIoInCallerContext - Pointer to driver supplied callback function
219 
220 Return Value:
221 
222     None
223 
224 --*/
225 {
226     DDI_ENTRY();
227 
228     PFX_DRIVER_GLOBALS fxDriverGlobals;
229     PFX_DRIVER_GLOBALS cxDriverGlobals;
230     NTSTATUS status;
231 
232     cxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
233     FxPointerNotNull(cxDriverGlobals, CxDeviceInit);
234     fxDriverGlobals = CxDeviceInit->ClientDriverGlobals;
235 
236     //
237     // Caller must be a class extension driver.
238     //
239     status = FxValiateCx(fxDriverGlobals, cxDriverGlobals);
240     if (!NT_SUCCESS(status)) {
241         goto Done;
242     }
243 
244     FxPointerNotNull(fxDriverGlobals, EvtIoInCallerContext);
245 
246     CxDeviceInit->IoInCallerContextCallback = EvtIoInCallerContext;
247 
248 Done:
249     return;
250 }
251 
252 __drv_maxIRQL(DISPATCH_LEVEL)
253 VOID
254 WDFEXPORT(WdfCxDeviceInitSetRequestAttributes)(
255     __in
256     PWDF_DRIVER_GLOBALS DriverGlobals,
257     __in
258     PWDFCXDEVICE_INIT CxDeviceInit,
259     __in
260     PWDF_OBJECT_ATTRIBUTES RequestAttributes
261     )
262 {
263     DDI_ENTRY();
264 
265     PFX_DRIVER_GLOBALS fxDriverGlobals;
266     PFX_DRIVER_GLOBALS cxDriverGlobals;
267     NTSTATUS status;
268 
269     cxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
270     FxPointerNotNull(cxDriverGlobals, CxDeviceInit);
271     fxDriverGlobals = CxDeviceInit->ClientDriverGlobals;
272 
273     //
274     // Caller must be a class extension driver.
275     //
276     status = FxValiateCx(fxDriverGlobals, cxDriverGlobals);
277     if (!NT_SUCCESS(status)) {
278         goto Done;
279     }
280 
281     FxPointerNotNull(fxDriverGlobals, RequestAttributes);
282 
283     //
284     // Parent of all requests created from WDFDEVICE are parented by the WDFDEVICE.
285     //
286     status = FxValidateObjectAttributes(fxDriverGlobals,
287                                         RequestAttributes,
288                                         FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED);
289 
290     if (!NT_SUCCESS(status)) {
291         FxVerifierDbgBreakPoint(fxDriverGlobals);
292         return;
293     }
294 
295     RtlCopyMemory(&CxDeviceInit->RequestAttributes,
296                   RequestAttributes,
297                   sizeof(WDF_OBJECT_ATTRIBUTES));
298 
299 Done:
300     return;
301 }
302 
303 __drv_maxIRQL(DISPATCH_LEVEL)
304 VOID
305 WDFEXPORT(WdfCxDeviceInitSetFileObjectConfig)(
306     __in
307     PWDF_DRIVER_GLOBALS DriverGlobals,
308     __in
309     PWDFCXDEVICE_INIT CxDeviceInit,
310     __in
311     PWDFCX_FILEOBJECT_CONFIG CxFileObjectConfig,
312     __in_opt
313     PWDF_OBJECT_ATTRIBUTES FileObjectAttributes
314     )
315 
316 /*++
317 
318 Routine Description:
319 
320     Registers file object callbacks for class extensions.
321 
322     Defaults to WdfFileObjectNotRequired if no file obj config set.
323 
324 Arguments:
325 
326 Returns:
327 
328 --*/
329 
330 {
331     DDI_ENTRY();
332 
333     PFX_DRIVER_GLOBALS fxDriverGlobals;
334     PFX_DRIVER_GLOBALS cxDriverGlobals;
335     NTSTATUS status;
336     WDF_FILEOBJECT_CLASS normalizedFileClass;
337 
338     cxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
339     FxPointerNotNull(cxDriverGlobals, CxDeviceInit);
340     fxDriverGlobals = CxDeviceInit->ClientDriverGlobals;
341 
342     //
343     // Caller must be a class extension driver.
344     //
345     status = FxValiateCx(fxDriverGlobals, cxDriverGlobals);
346     if (!NT_SUCCESS(status)) {
347         goto Done;
348     }
349 
350     FxPointerNotNull(fxDriverGlobals, CxFileObjectConfig);
351 
352     if (CxFileObjectConfig->Size != sizeof(WDFCX_FILEOBJECT_CONFIG)) {
353         DoTraceLevelMessage(
354             fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
355             "Invalid CxFileObjectConfig Size %d, expected %d",
356             CxFileObjectConfig->Size, sizeof(WDFCX_FILEOBJECT_CONFIG));
357 
358         FxVerifierDbgBreakPoint(fxDriverGlobals);
359         goto Done;
360     }
361 
362     status = FxValidateObjectAttributes(
363         fxDriverGlobals,
364         FileObjectAttributes,
365         FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED |
366             FX_VALIDATE_OPTION_EXECUTION_LEVEL_ALLOWED |
367             FX_VALIDATE_OPTION_SYNCHRONIZATION_SCOPE_ALLOWED
368         );
369 
370     if (!NT_SUCCESS(status)) {
371         FxVerifierDbgBreakPoint(fxDriverGlobals);
372         goto Done;
373     }
374 
375     //
376     // Validate AutoForwardCleanupClose.
377     //
378     switch (CxFileObjectConfig->AutoForwardCleanupClose) {
379     case WdfTrue:
380     case WdfFalse:
381     case WdfUseDefault:
382         break;
383 
384     default:
385         DoTraceLevelMessage(
386             fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
387             "Invalid CxFileObjectConfig->AutoForwardCleanupClose value 0x%x, "
388             "expected WDF_TRI_STATE value",
389             CxFileObjectConfig->AutoForwardCleanupClose);
390 
391         FxVerifierDbgBreakPoint(fxDriverGlobals);
392         goto Done;
393     }
394 
395     CxDeviceInit->FileObject.Set = TRUE;
396 
397     CxDeviceInit->FileObject.AutoForwardCleanupClose =
398         CxFileObjectConfig->AutoForwardCleanupClose;
399 
400     //
401     // Remove bit flags and validate file object class value.
402     //
403     normalizedFileClass = FxFileObjectClassNormalize(
404                                 CxFileObjectConfig->FileObjectClass);
405 
406     if (normalizedFileClass == WdfFileObjectInvalid ||
407         normalizedFileClass > WdfFileObjectWdfCannotUseFsContexts)  {
408         DoTraceLevelMessage(
409             fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
410             "Out of range CxFileObjectConfig->FileObjectClass %d",
411             CxFileObjectConfig->FileObjectClass);
412         FxVerifierDbgBreakPoint(fxDriverGlobals);
413         goto Done;
414     }
415 
416     //
417     // The optional flag can only be combined with a subset of values.
418     //
419     if (FxIsFileObjectOptional(CxFileObjectConfig->FileObjectClass)) {
420         switch(normalizedFileClass) {
421         case WdfFileObjectWdfCanUseFsContext:
422         case WdfFileObjectWdfCanUseFsContext2:
423         case WdfFileObjectWdfCannotUseFsContexts:
424             break;
425 
426         default:
427             DoTraceLevelMessage(
428                 fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
429                 "Invalid CxFileObjectConfig->FileObjectClass %d",
430                 CxFileObjectConfig->FileObjectClass);
431             FxVerifierDbgBreakPoint(fxDriverGlobals);
432             goto Done;
433             break; // just in case static verification tools complain.
434         }
435     }
436 
437     CxDeviceInit->FileObject.Class = CxFileObjectConfig->FileObjectClass;
438 
439     RtlCopyMemory(&CxDeviceInit->FileObject.Callbacks,
440                   CxFileObjectConfig,
441                   sizeof(CxDeviceInit->FileObject.Callbacks));
442 
443     if (FileObjectAttributes != NULL) {
444         RtlCopyMemory(&CxDeviceInit->FileObject.Attributes,
445                       FileObjectAttributes,
446                       sizeof(CxDeviceInit->FileObject.Attributes));
447     }
448 
449 Done:
450     return;
451 }
452 
453 _Must_inspect_result_
454 __drv_maxIRQL(PASSIVE_LEVEL)
455 PWDFCXDEVICE_INIT
456 WDFEXPORT(WdfCxDeviceInitAllocate)(
457     __in
458     PWDF_DRIVER_GLOBALS DriverGlobals,
459     __in
460     PWDFDEVICE_INIT DeviceInit
461     )
462 {
463     DDI_ENTRY();
464 
465     PFX_DRIVER_GLOBALS cxDriverGlobals;
466     PFX_DRIVER_GLOBALS fxDriverGlobals;
467     PWDFCXDEVICE_INIT  cxDeviceInit;
468     NTSTATUS status;
469 
470     cxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
471     FxPointerNotNull(cxDriverGlobals, DeviceInit);
472     fxDriverGlobals = DeviceInit->DriverGlobals;
473     cxDeviceInit = NULL;
474 
475     //
476     // Caller must be a class extension driver.
477     //
478     status = FxValiateCx(fxDriverGlobals, cxDriverGlobals);
479     if (!NT_SUCCESS(status)) {
480         goto Done;
481     }
482 
483     status = FxVerifierCheckIrqlLevel(fxDriverGlobals, PASSIVE_LEVEL);
484     if (!NT_SUCCESS(status)) {
485         goto Done;
486     }
487 
488     cxDeviceInit = WDFCXDEVICE_INIT::_AllocateCxDeviceInit(DeviceInit);
489     if (NULL == cxDeviceInit) {
490         goto Done;
491     }
492 
493     cxDeviceInit->ClientDriverGlobals = fxDriverGlobals;
494     cxDeviceInit->CxDriverGlobals = cxDriverGlobals;
495 
496 Done:
497     return cxDeviceInit;
498 }
499 
500 } // extern "C"
501 
502