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