Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1314 lines
39 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. RxInit.c
  5. Abstract:
  6. This module implements the FSD-level dispatch routine for the RDBSS.
  7. Author:
  8. Joe Linn [JoeLinn] 2-dec-1994
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #include <ntddnfs.h>
  14. #include <dfsfsctl.h>
  15. #include "NtDspVec.h"
  16. //
  17. // The debug trace level
  18. //
  19. #define Dbg (DEBUG_TRACE_DISPATCH)
  20. NTSTATUS
  21. RxCommonUnimplemented (
  22. IN PRX_CONTEXT RxContext,
  23. IN PIRP Irp
  24. );
  25. VOID
  26. RxInitializeTopLevelIrpPackage (
  27. VOID
  28. );
  29. RX_FSD_DISPATCH_VECTOR RxFsdDispatchVector[IRP_MJ_MAXIMUM_FUNCTION + 1] = {
  30. {RxCommonCreate, 0x10}, // 0 IRP_MJ_CREATE
  31. {RxCommonUnimplemented, 0x10}, // 1 IRP_MJ_CREATE_NAME_PIPE
  32. {RxCommonClose, 0x10}, // 2 IRP_MJ_CLOSE
  33. {RxCommonRead, 0x10}, // 3 IRP_MJ_READ
  34. {RxCommonWrite, 0x10}, // 4 IRP_MJ_WRITE
  35. {RxCommonQueryInformation, 0x10}, // 5 IRP_MJ_QUERY_INFORMATION
  36. {RxCommonSetInformation, 0x10}, // 6 IRP_MJ_SET_INFORMATION
  37. {RxCommonQueryEa, 0x10}, // 7 IRP_MJ_QUERY_EA
  38. {RxCommonSetEa, 0x10}, // 8 IRP_MJ_SET_EA
  39. {RxCommonFlushBuffers, 0x10}, // 9 IRP_MJ_FLUSH_BUFFERS
  40. {RxCommonQueryVolumeInformation, 0x10}, // 10 IRP_MJ_QUERY_VOLUME_INFORMATION
  41. {RxCommonSetVolumeInformation, 0x10}, // 11 IRP_MJ_SET_VOLUME_INFORMATION
  42. {RxCommonDirectoryControl, 0x10}, // 12 IRP_MJ_DIRECTORY_CONTROL
  43. {RxCommonFileSystemControl, 0x10}, // 13 IRP_MJ_FILE_SYSTEM_CONTROL
  44. {RxCommonDeviceControl, 0x10}, // 14 IRP_MJ_DEVICE_CONTROL
  45. {RxCommonDeviceControl, 0x10}, // 15 IRP_MJ_INTERNAL_DEVICE_CONTROL
  46. {RxCommonUnimplemented, 0x10}, // 16 IRP_MJ_SHUTDOWN
  47. {RxCommonLockControl, 0x10}, // 17 IRP_MJ_LOCK_CONTROL
  48. {RxCommonCleanup, 0x10}, // 18 IRP_MJ_CLEANUP
  49. {RxCommonUnimplemented, 0x10}, // 19 IRP_MJ_CREATE_MAILSLOT
  50. {RxCommonQuerySecurity, 0x10}, // 20 IRP_MJ_QUERY_SECURITY
  51. {RxCommonSetSecurity, 0x10}, // 21 IRP_MJ_SET_SECURITY
  52. {RxCommonUnimplemented, 0x10}, // 22 IRP_MJ_POWER
  53. {RxCommonUnimplemented, 0x10}, // 23 IRP_MJ_SYSTEM_CONTROL
  54. {RxCommonUnimplemented, 0x10}, // 24 IRP_MJ_DEVICE_CHANGE
  55. {RxCommonQueryQuotaInformation, 0x10}, // 25 IRP_MJ_QUERY_QUOTA_INFORMATION
  56. {RxCommonSetQuotaInformation, 0x10}, // 26 IRP_MJ_SET_QUOTA_INFORMATION
  57. {RxCommonUnimplemented, 0x10} // 27 IRP_MJ_PNP
  58. };
  59. RX_FSD_DISPATCH_VECTOR RxDeviceFCBVector[IRP_MJ_MAXIMUM_FUNCTION + 1] = {
  60. {RxCommonUnimplemented, 0x10}, // 0 IRP_MJ_CREATE
  61. {RxCommonUnimplemented, 0x10}, // 1 IRP_MJ_CREATE_NAME_PIPE
  62. {RxCommonDevFCBClose, 0x10}, // 2 IRP_MJ_CLOSE
  63. {RxCommonUnimplemented, 0x10}, // 3 IRP_MJ_READ
  64. {RxCommonUnimplemented, 0x10}, // 4 IRP_MJ_WRITE
  65. {RxCommonUnimplemented, 0x10}, // 5 IRP_MJ_QUERY_INFORMATION
  66. {RxCommonUnimplemented, 0x10}, // 6 IRP_MJ_SET_INFORMATION
  67. {RxCommonUnimplemented, 0x10}, // 7 IRP_MJ_QUERY_EA
  68. {RxCommonUnimplemented, 0x10}, // 8 IRP_MJ_SET_EA
  69. {RxCommonUnimplemented, 0x10}, // 9 IRP_MJ_FLUSH_BUFFERS
  70. {RxCommonDevFCBQueryVolInfo, 0x10}, // 10 IRP_MJ_QUERY_VOLUME_INFORMATION
  71. {RxCommonUnimplemented, 0x10}, // 11 IRP_MJ_SET_VOLUME_INFORMATION
  72. {RxCommonUnimplemented, 0x10}, // 12 IRP_MJ_DIRECTORY_CONTROL
  73. {RxCommonDevFCBFsCtl, 0x10}, // 13 IRP_MJ_FILE_SYSTEM_CONTROL
  74. {RxCommonDevFCBIoCtl, 0x10}, // 14 IRP_MJ_DEVICE_CONTROL
  75. {RxCommonDevFCBIoCtl, 0x10}, // 15 IRP_MJ_INTERNAL_DEVICE_CONTROL
  76. {RxCommonUnimplemented, 0x10}, // 16 IRP_MJ_SHUTDOWN
  77. {RxCommonUnimplemented, 0x10}, // 17 IRP_MJ_LOCK_CONTROL
  78. {RxCommonDevFCBCleanup, 0x10}, // 18 IRP_MJ_CLEANUP
  79. {RxCommonUnimplemented, 0x10}, // 19 IRP_MJ_CREATE_MAILSLOT
  80. {RxCommonUnimplemented, 0x10}, // 20 IRP_MJ_QUERY_SECURITY
  81. {RxCommonUnimplemented, 0x10}, // 21 IRP_MJ_SET_SECURITY
  82. {RxCommonUnimplemented, 0x10}, // 22 IRP_MJ_POWER
  83. {RxCommonUnimplemented, 0x10}, // 23 IRP_MJ_SYSTEM_CONTROL
  84. {RxCommonUnimplemented, 0x10}, // 24 IRP_MJ_DEVICE_CHANGE
  85. {RxCommonUnimplemented, 0x10}, // 25 IRP_MJ_QUERY_QUOTA_INFORMATION
  86. {RxCommonUnimplemented, 0x10}, // 26 IRP_MJ_SET_QUOTA_INFORMATION
  87. {RxCommonUnimplemented, 0x10} // 27 IRP_MJ_PNP
  88. };
  89. FAST_IO_DISPATCH RxFastIoDispatch;
  90. //
  91. // To allow NFS to run RDBSS on W2K, we now look up the kenel routine
  92. // FsRtlTeardownPerStreamContexts dynamically at run time.
  93. // This is the global variable that contains the function pointer or NULL
  94. // if the routine could not be found (as on W2K.
  95. //
  96. VOID (*RxTeardownPerStreamContexts)(IN PFSRTL_ADVANCED_FCB_HEADER AdvancedHeader) = NULL;
  97. NTSTATUS
  98. RxFsdCommonDispatch (
  99. PRX_FSD_DISPATCH_VECTOR DispatchVector,
  100. IN PIRP Irp,
  101. IN PFILE_OBJECT FileObject,
  102. IN PRDBSS_DEVICE_OBJECT RxDeviceObject
  103. );
  104. VOID
  105. RxInitializeDispatchVectors (
  106. OUT PDRIVER_OBJECT DriverObject
  107. );
  108. #ifdef ALLOC_PRAGMA
  109. #pragma alloc_text(INIT, RxInitializeDispatchVectors)
  110. // not pageable SPINLOCK #pragma alloc_text(PAGE, RxFsdCommonDispatch)
  111. #pragma alloc_text(PAGE, RxCommonUnimplemented)
  112. #pragma alloc_text(PAGE, RxCommonUnimplemented)
  113. #pragma alloc_text(PAGE, RxFsdDispatch)
  114. #pragma alloc_text(PAGE, RxTryToBecomeTheTopLevelIrp)
  115. #endif
  116. VOID
  117. RxInitializeDispatchVectors (
  118. OUT PDRIVER_OBJECT DriverObject
  119. )
  120. /*++
  121. Routine Description:
  122. This routine initializes the dispatch table for the driver object
  123. Arguments:
  124. DriverObject - Supplies the driver object
  125. --*/
  126. {
  127. ULONG i;
  128. UNICODE_STRING funcName;
  129. PAGED_CODE();
  130. //
  131. // Set the routine address for FsRtlTeardownPerStreamContexts
  132. //
  133. RtlInitUnicodeString( &funcName, L"FsRtlTeardownPerStreamContexts" );
  134. RxTeardownPerStreamContexts = MmGetSystemRoutineAddress( &funcName );
  135. //
  136. // Set IRP dispatch vectors
  137. //
  138. for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
  139. DriverObject->MajorFunction[i] = (PDRIVER_DISPATCH)RxFsdDispatch;
  140. }
  141. //
  142. // Set Dispatch Vector for the DevFCB
  143. //
  144. RxDeviceFCB.PrivateDispatchVector = &RxDeviceFCBVector[0];
  145. ASSERT( RxFsdDispatchVector[IRP_MJ_MAXIMUM_FUNCTION].CommonRoutine != NULL );
  146. ASSERT( RxDeviceFCBVector[IRP_MJ_MAXIMUM_FUNCTION].CommonRoutine != NULL );
  147. //
  148. // this is dangerous!!!
  149. //
  150. DriverObject->FastIoDispatch = &RxFastIoDispatch;
  151. RxFastIoDispatch.SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH);
  152. RxFastIoDispatch.FastIoCheckIfPossible = RxFastIoCheckIfPossible;
  153. RxFastIoDispatch.FastIoRead = RxFastIoRead;
  154. RxFastIoDispatch.FastIoWrite = RxFastIoWrite;
  155. RxFastIoDispatch.FastIoQueryBasicInfo = NULL;
  156. RxFastIoDispatch.FastIoQueryStandardInfo = NULL;
  157. RxFastIoDispatch.FastIoLock = NULL;
  158. RxFastIoDispatch.FastIoUnlockSingle = NULL;
  159. RxFastIoDispatch.FastIoUnlockAll = NULL;
  160. RxFastIoDispatch.FastIoUnlockAllByKey = NULL;
  161. RxFastIoDispatch.FastIoDeviceControl = RxFastIoDeviceControl;
  162. RxFastIoDispatch.AcquireForCcFlush = RxAcquireForCcFlush;
  163. RxFastIoDispatch.ReleaseForCcFlush = RxReleaseForCcFlush;
  164. RxFastIoDispatch.AcquireFileForNtCreateSection = RxAcquireFileForNtCreateSection;
  165. RxFastIoDispatch.ReleaseFileForNtCreateSection = RxReleaseFileForNtCreateSection;
  166. //
  167. // Initialize stuff for the toplevelirp package
  168. //
  169. RxInitializeTopLevelIrpPackage();
  170. //
  171. // Initialize the cache manager callback routines
  172. //
  173. RxData.CacheManagerCallbacks.AcquireForLazyWrite = &RxAcquireFcbForLazyWrite;
  174. RxData.CacheManagerCallbacks.ReleaseFromLazyWrite = &RxReleaseFcbFromLazyWrite;
  175. RxData.CacheManagerCallbacks.AcquireForReadAhead = &RxAcquireFcbForReadAhead;
  176. RxData.CacheManagerCallbacks.ReleaseFromReadAhead = &RxReleaseFcbFromReadAhead;
  177. }
  178. NTSTATUS
  179. RxCommonUnimplemented (
  180. IN PRX_CONTEXT RxContext,
  181. IN PIRP Irp
  182. )
  183. {
  184. PAGED_CODE();
  185. RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("RxFsdDispatRxFsdUnImplementedchPROBLEM: IrpC =%08lx,Code=",
  186. RxContext, RxContext->MajorFunction) );
  187. RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("---------------------UNIMLEMENTED-----%s\n", "" ) );
  188. return STATUS_NOT_IMPLEMENTED;
  189. }
  190. RxDbgTraceDoit(ULONG RxDbgTraceEnableCommand = 0xffff;)
  191. WML_CONTROL_GUID_REG Rdbss_ControlGuids[] = {
  192. { // cddc01e2-fdce-479a-b8ee-3c87053fb55e Rdbss
  193. 0xcddc01e2,0xfdce,0x479a,{0xb8,0xee,0x3c,0x87,0x05,0x3f,0xb5,0x5e},
  194. { // 529ae497-0a1f-43a5-8cb5-2aa60b497831
  195. {0x529ae497,0x0a1f,0x43a5,{0x8c,0xb5,0x2a,0xa6,0x0b,0x49,0x78,0x31},},
  196. // b7e3da1d-67f4-49bd-b9c0-1e61ce7417a8
  197. {0xb7e3da1d,0x67f4,0x49bd,{0xb9,0xc0,0x1e,0x61,0xce,0x74,0x17,0xa8},},
  198. // c966bef5-21c5-4630-84a0-4334875f41b8
  199. {0xc966bef5,0x21c5,0x4630,{0x84,0xa0,0x43,0x34,0x87,0x5f,0x41,0xb8},}
  200. },
  201. },
  202. };
  203. #define Rdbss_ControlGuids_len 1
  204. extern BOOLEAN EnableWmiLog;
  205. NTSTATUS
  206. RxSystemControl(
  207. IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
  208. IN PIRP Irp
  209. )
  210. /*++
  211. Routine Description:
  212. This is the common routine for doing System control operations called
  213. by both the fsd and fsp threads
  214. Arguments:
  215. Irp - Supplies the Irp to process
  216. InFsp - Indicates if this is the fsp thread or someother thread
  217. Return Value:
  218. RXSTATUS - The return status for the operation
  219. --*/
  220. {
  221. NTSTATUS Status;
  222. WML_TINY_INFO Info;
  223. UNICODE_STRING RegPath;
  224. PAGED_CODE();
  225. if (EnableWmiLog) {
  226. RtlInitUnicodeString( &RegPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Rdbss" );
  227. RtlZeroMemory( &Info, sizeof( Info ) );
  228. Info.ControlGuids = Rdbss_ControlGuids;
  229. Info.GuidCount = Rdbss_ControlGuids_len;
  230. Info.DriverRegPath = &RegPath;
  231. Status = WmlTinySystemControl( &Info,
  232. (PDEVICE_OBJECT)RxDeviceObject,
  233. Irp );
  234. if (Status != STATUS_SUCCESS) {
  235. // DbgPrint("Rdbss WMI control return %lx\n", Status);
  236. }
  237. } else {
  238. Status = STATUS_INVALID_DEVICE_REQUEST;
  239. Irp->IoStatus.Status = Status;
  240. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  241. }
  242. return Status;
  243. }
  244. NTSTATUS
  245. RxFsdDispatch (
  246. IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
  247. IN PIRP Irp
  248. )
  249. /*++
  250. Routine Description:
  251. This routine implements the FSD dispatch for the RDBSS.
  252. Arguments:
  253. RxDeviceObject - Supplies the device object for the packet being processed.
  254. Irp - Supplies the Irp being processed
  255. Return Value:
  256. RXSTATUS - The Fsd status for the Irp
  257. --*/
  258. {
  259. NTSTATUS Status;
  260. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); // ok4ioget
  261. UCHAR MajorFunctionCode = IrpSp->MajorFunction;
  262. PFILE_OBJECT FileObject = IrpSp->FileObject; // ok4->fileobj
  263. PRX_FSD_DISPATCH_VECTOR DispatchVector;
  264. PAGED_CODE();
  265. RxDbgTraceDoit(
  266. if (MajorFunctionCode == RxDbgTraceEnableCommand) {
  267. RxNextGlobalTraceSuppress = RxGlobalTraceSuppress = FALSE;
  268. }
  269. if (0) {
  270. RxNextGlobalTraceSuppress = RxGlobalTraceSuppress = FALSE;
  271. }
  272. );
  273. RxDbgTrace( 0, Dbg, ("RxFsdDispatch: Code =%02lx (%lu) ----------%s-----------\n",
  274. MajorFunctionCode,
  275. ++RxIrpCodeCount[IrpSp->MajorFunction],
  276. RxIrpCodeToName[MajorFunctionCode]) );
  277. if (IrpSp->MajorFunction == IRP_MJ_SYSTEM_CONTROL) {
  278. return RxSystemControl( RxDeviceObject, Irp );
  279. }
  280. if ((MajorFunctionCode == IRP_MJ_CREATE_MAILSLOT) ||
  281. (MajorFunctionCode == IRP_MJ_CREATE_NAMED_PIPE)) {
  282. DispatchVector = NULL;
  283. Status = STATUS_OBJECT_NAME_INVALID;
  284. } else {
  285. //
  286. // get a private dispatch table if there is one
  287. //
  288. if (MajorFunctionCode == IRP_MJ_CREATE) {
  289. DispatchVector = RxFsdDispatchVector;
  290. } else if ((FileObject != NULL) && (FileObject->FsContext != NULL)) {
  291. if ((NodeTypeIsFcb( (PFCB)(FileObject->FsContext) )) &&
  292. (((PFCB)(FileObject->FsContext))->PrivateDispatchVector != NULL)) { // ok4fscontext
  293. RxDbgTraceLV( 0, Dbg, 2500, ("Using Private Dispatch Vector\n" ));
  294. DispatchVector = ((PFCB)(FileObject->FsContext))->PrivateDispatchVector;
  295. } else {
  296. DispatchVector = RxFsdDispatchVector;
  297. }
  298. if (RxDeviceObject == RxFileSystemDeviceObject) {
  299. DispatchVector = NULL;
  300. Status = STATUS_INVALID_DEVICE_REQUEST;
  301. }
  302. } else {
  303. DispatchVector = NULL;
  304. Status = STATUS_INVALID_DEVICE_REQUEST;
  305. RxDbgTrace( 0,
  306. Dbg,
  307. ("RxFsdDispatch: Code =%02lx (%lu) ----------%s-----------\n",
  308. MajorFunctionCode,
  309. ++RxIrpCodeCount[IrpSp->MajorFunction],
  310. RxIrpCodeToName[MajorFunctionCode]) );
  311. }
  312. }
  313. if (DispatchVector != NULL) {
  314. Status = RxFsdCommonDispatch( DispatchVector,
  315. Irp,
  316. FileObject,
  317. RxDeviceObject );
  318. RxDbgTrace( 0, Dbg, ("RxFsdDispatch: Status =%02lx %s....\n",
  319. Status,
  320. RxIrpCodeToName[MajorFunctionCode]) );
  321. RxDbgTraceDoit(
  322. if (RxGlobalTraceIrpCount > 0) {
  323. RxGlobalTraceIrpCount -= 1;
  324. RxGlobalTraceSuppress = FALSE;
  325. } else {
  326. RxGlobalTraceSuppress = RxNextGlobalTraceSuppress;
  327. }
  328. );
  329. } else {
  330. IoMarkIrpPending( Irp );
  331. Irp->IoStatus.Status = Status;
  332. Irp->IoStatus.Information = 0;
  333. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  334. Status = STATUS_PENDING;
  335. }
  336. return Status;
  337. }
  338. NTSTATUS
  339. RxFsdCommonDispatch (
  340. PRX_FSD_DISPATCH_VECTOR DispatchVector,
  341. IN PIRP Irp,
  342. IN PFILE_OBJECT FileObject,
  343. IN PRDBSS_DEVICE_OBJECT RxDeviceObject
  344. )
  345. /*++
  346. Routine Description:
  347. This routine implements the FSD part of dispatch for IRP's
  348. Arguments:
  349. DispatchVector - the dispatch vector
  350. Irp - the IRP
  351. FileObject - the file object
  352. RxDeviceObject -
  353. Return Value:
  354. RXSTATUS - The FSD Status for the IRP
  355. Notes:
  356. --*/
  357. {
  358. NTSTATUS Status = STATUS_SUCCESS;
  359. PRX_CONTEXT RxContext = NULL;
  360. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  361. RX_TOPLEVELIRP_CONTEXT TopLevelContext;
  362. ULONG ContextFlags = 0;
  363. KIRQL SavedIrql;
  364. PRX_DISPATCH DispatchRoutine = NULL;
  365. PDRIVER_CANCEL CancelRoutine = NULL;
  366. BOOLEAN TopLevel = FALSE;
  367. BOOLEAN Wait;
  368. BOOLEAN Cancellable;
  369. BOOLEAN ModWriter = FALSE;
  370. BOOLEAN CleanupOrClose = FALSE;
  371. BOOLEAN Continue = TRUE;
  372. BOOLEAN PostRequest = FALSE;
  373. FsRtlEnterFileSystem();
  374. TopLevel = RxTryToBecomeTheTopLevelIrp( &TopLevelContext, Irp, RxDeviceObject, FALSE ); // dont force
  375. try {
  376. //
  377. // Treat all operations as being cancellable and waitable.
  378. //
  379. Wait = TRUE;
  380. Cancellable = TRUE;
  381. CancelRoutine = RxCancelRoutine;
  382. //
  383. // Retract the capability based upon the operation
  384. //
  385. switch (IrpSp->MajorFunction) {
  386. case IRP_MJ_FILE_SYSTEM_CONTROL:
  387. //
  388. // Call the common FileSystem Control routine, with blocking allowed if
  389. // synchronous. This opeation needs to special case the mount
  390. // and verify suboperations because we know they are allowed to block.
  391. // We identify these suboperations by looking at the file object field
  392. // and seeing if its null.
  393. //
  394. if (FileObject == NULL) {
  395. Wait = TRUE;
  396. } else {
  397. Wait = CanFsdWait( Irp );
  398. }
  399. break;
  400. case IRP_MJ_READ:
  401. case IRP_MJ_LOCK_CONTROL:
  402. case IRP_MJ_DIRECTORY_CONTROL:
  403. case IRP_MJ_QUERY_VOLUME_INFORMATION:
  404. case IRP_MJ_WRITE:
  405. case IRP_MJ_QUERY_INFORMATION:
  406. case IRP_MJ_SET_INFORMATION:
  407. case IRP_MJ_QUERY_EA:
  408. case IRP_MJ_SET_EA:
  409. case IRP_MJ_QUERY_SECURITY:
  410. case IRP_MJ_SET_SECURITY:
  411. case IRP_MJ_FLUSH_BUFFERS:
  412. case IRP_MJ_DEVICE_CONTROL:
  413. case IRP_MJ_SET_VOLUME_INFORMATION:
  414. Wait = CanFsdWait( Irp );
  415. break;
  416. case IRP_MJ_CLEANUP:
  417. case IRP_MJ_CLOSE:
  418. Cancellable = FALSE;
  419. CleanupOrClose = TRUE;
  420. break;
  421. default:
  422. break;
  423. }
  424. KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql );
  425. Continue = TRUE;
  426. switch (RxDeviceObject->StartStopContext.State) {
  427. case RDBSS_STARTABLE:
  428. //
  429. // Only device creates and device operations can go thru
  430. //
  431. if ((DispatchVector == RxDeviceFCBVector) ||
  432. ((FileObject->FileName.Length == 0) &&
  433. (FileObject->RelatedFileObject == NULL))) {
  434. NOTHING;
  435. } else {
  436. Continue = FALSE;
  437. Status = STATUS_REDIRECTOR_NOT_STARTED;
  438. }
  439. break;
  440. case RDBSS_STOP_IN_PROGRESS:
  441. if (!CleanupOrClose) {
  442. Continue = FALSE;
  443. Status = STATUS_REDIRECTOR_NOT_STARTED;
  444. }
  445. break;
  446. //
  447. // case RDBSS_STOPPED:
  448. // {
  449. // if ((MajorFunctionCode == IRP_MJ_FILE_SYSTEM_CONTROL) &&
  450. // (MinorFunctionCode == IRP_MN_USER_FS_REQUEST) &&
  451. // (IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_LMR_START)) {
  452. // RxDeviceObject->StartStopContext.State = RDBSS_START_IN_PROGRESS;
  453. // RxDeviceObject->StartStopContext.Version++;
  454. // Continue = TRUE;
  455. // } else {
  456. // Continue = FALSE;
  457. // Status = STATUS_REDIRECTOR_NOT_STARTED);
  458. // }
  459. // }
  460. //
  461. case RDBSS_STARTED:
  462. //
  463. // intentional fallthrough
  464. //
  465. default:
  466. break;
  467. }
  468. KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql );
  469. if ((IrpSp->FileObject != NULL) &&
  470. (IrpSp->FileObject->FsContext != NULL)) {
  471. PFCB Fcb = (PFCB)IrpSp->FileObject->FsContext;
  472. BOOLEAN Orphaned = FALSE;
  473. if ((IrpSp->FileObject->FsContext2 != UIntToPtr( DFS_OPEN_CONTEXT )) &&
  474. (IrpSp->FileObject->FsContext2 != UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT)) &&
  475. (IrpSp->FileObject->FsContext != &RxDeviceFCB)) {
  476. Orphaned = BooleanFlagOn( Fcb->FcbState, FCB_STATE_ORPHANED );
  477. if (!Orphaned && IrpSp->FileObject->FsContext2) {
  478. PFOBX Fobx = (PFOBX)IrpSp->FileObject->FsContext2;
  479. if (Fobx->SrvOpen != NULL) {
  480. Orphaned = BooleanFlagOn( Fobx->SrvOpen->Flags, SRVOPEN_FLAG_ORPHANED );
  481. }
  482. }
  483. }
  484. if (Orphaned) {
  485. if (!CleanupOrClose) {
  486. RxDbgTrace( 0,
  487. Dbg,
  488. ("Ignoring operation on ORPHANED FCB %lx %lx %lx\n",
  489. Fcb,
  490. IrpSp->MajorFunction,
  491. IrpSp->MinorFunction) );
  492. Continue = FALSE;
  493. Status = STATUS_UNEXPECTED_NETWORK_ERROR;
  494. RxLog(( "#### Orphaned FCB op %lx\n", Fcb ));
  495. RxWmiLog( LOG,
  496. RxFsdCommonDispatch_OF,
  497. LOGPTR( Fcb ) );
  498. } else {
  499. RxDbgTrace( 0, Dbg, ("Delayed Close/Cleanup on ORPHANED FCB %lx\n", Fcb) );
  500. Continue = TRUE;
  501. }
  502. }
  503. }
  504. if ((RxDeviceObject->StartStopContext.State == RDBSS_STOP_IN_PROGRESS) &&
  505. CleanupOrClose) {
  506. PFILE_OBJECT FileObject = IrpSp->FileObject;
  507. PFCB Fcb = (PFCB)FileObject->FsContext;
  508. RxDbgPrint(( "RDBSS -- Close after Stop" ));
  509. RxDbgPrint(( "RDBSS: Irp(%lx) MJ %ld MN %ld FileObject(%lx) FCB(%lx) \n",
  510. Irp, IrpSp->MajorFunction, IrpSp->MinorFunction, FileObject, Fcb ));
  511. if ((FileObject != NULL) &&
  512. (Fcb != NULL) &&
  513. (Fcb != &RxDeviceFCB) &&
  514. NodeTypeIsFcb( Fcb )) {
  515. RxDbgPrint(( "RDBSS: OpenCount(%ld) UncleanCount(%ld) Name(%wZ)\n", Fcb->OpenCount, Fcb->UncleanCount, &Fcb->FcbTableEntry.Path ));
  516. }
  517. }
  518. if (!Continue) {
  519. if ((IrpSp->MajorFunction != IRP_MJ_DIRECTORY_CONTROL) ||
  520. (IrpSp->MinorFunction !=IRP_MN_NOTIFY_CHANGE_DIRECTORY)) {
  521. IoMarkIrpPending( Irp );
  522. Irp->IoStatus.Status = Status;
  523. Irp->IoStatus.Information = 0;
  524. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  525. Status = STATUS_PENDING;
  526. } else {
  527. //
  528. // this is a changenotify directory control
  529. // Fail the operation
  530. // The usermode API cannot get the error in the IO Status block
  531. // correctly, due to the way FindFirstChangeNotify/FindNextChangeNotify
  532. // APIs are designed
  533. //
  534. Irp->IoStatus.Status = Status;
  535. Irp->IoStatus.Information = 0;
  536. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  537. }
  538. try_return( Status );
  539. }
  540. if (Wait) {
  541. SetFlag( ContextFlags, RX_CONTEXT_FLAG_WAIT );
  542. }
  543. RxContext = RxCreateRxContext( Irp, RxDeviceObject, ContextFlags );
  544. if (RxContext == NULL) {
  545. Status = STATUS_INSUFFICIENT_RESOURCES;
  546. RxCompleteRequest_OLD( RxNull, Irp, Status );
  547. try_return( Status );
  548. }
  549. //
  550. // Assume ownership of the Irp by setting the cancelling routine.
  551. //
  552. if (Cancellable) {
  553. RxSetCancelRoutine( Irp, CancelRoutine );
  554. } else {
  555. //
  556. // Ensure that those operations regarded as non cancellable will
  557. // not be cancelled.
  558. //
  559. RxSetCancelRoutine( Irp, NULL );
  560. }
  561. ASSERT( IrpSp->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION );
  562. Irp->IoStatus.Information = 0;
  563. Irp->IoStatus.Status = STATUS_SUCCESS;
  564. DispatchRoutine = DispatchVector[IrpSp->MajorFunction].CommonRoutine;
  565. switch (IrpSp->MajorFunction) {
  566. case IRP_MJ_READ:
  567. case IRP_MJ_WRITE:
  568. //
  569. // If this is an Mdl complete request, don't go through
  570. // common read.
  571. //
  572. if (FlagOn( IrpSp->MinorFunction, IRP_MN_COMPLETE )) {
  573. DispatchRoutine = RxCompleteMdl;
  574. } else if (FlagOn( IrpSp->MinorFunction, IRP_MN_DPC )) {
  575. //
  576. // Post all DPC calls.
  577. //
  578. RxDbgTrace( 0, Dbg, ("Passing DPC call to Fsp\n", 0 ) );
  579. PostRequest = TRUE;
  580. } else if ((IrpSp->MajorFunction == IRP_MJ_READ) &&
  581. (IoGetRemainingStackSize() < 0xe00)) {
  582. //
  583. // Check if we have enough stack space to process this request. If there
  584. // isn't enough then we will pass the request off to the stack overflow thread.
  585. //
  586. // NTBUG 61951 Shishirp 2/23/2000 where did the number come from......
  587. // this number should come from the minirdr....only he knows how much he needs
  588. // and in my configuration it should definitely be bigger than for FAT!
  589. // plus......i can't go to the net on the hypercrtical thread!!! this will have to be
  590. // reworked! maybe we should have our own hypercritical thread............
  591. //
  592. RxDbgTrace(0, Dbg, ("Passing StackOverflowRead off\n", 0 ));
  593. RxContext->PendingReturned = TRUE;
  594. Status = RxPostStackOverflowRead( RxContext, (PFCB)IrpSp->FileObject->FsContext );
  595. if (Status != STATUS_PENDING) {
  596. RxContext->PendingReturned = FALSE;
  597. RxCompleteRequest( RxContext, Status );
  598. }
  599. try_return(Status);
  600. }
  601. break;
  602. default:
  603. NOTHING;
  604. }
  605. //
  606. // set the resume routine for the fsp to be the dispatch routine and then either post immediately
  607. // or calldow to the common dispatch as appropriate
  608. //
  609. RxContext->ResumeRoutine = DispatchRoutine;
  610. if (DispatchRoutine != NULL) {
  611. RxContext->PendingReturned = TRUE;
  612. if (PostRequest) {
  613. Status = RxFsdPostRequest( RxContext );
  614. } else {
  615. do {
  616. Status = DispatchRoutine( RxContext, Irp );
  617. } while (Status == STATUS_RETRY);
  618. if (Status != STATUS_PENDING) {
  619. if (!((RxContext->CurrentIrp == Irp) &&
  620. (RxContext->CurrentIrpSp == IrpSp) &&
  621. (RxContext->MajorFunction == IrpSp->MajorFunction) &&
  622. (RxContext->MinorFunction == IrpSp->MinorFunction))) {
  623. DbgPrint( "RXCONTEXT CONTAMINATED!!!! rxc=%08lx\n", RxContext );
  624. DbgPrint( "-irp> %08lx %08lx\n", RxContext->CurrentIrp, Irp );
  625. DbgPrint( "--sp> %08lx %08lx\n", RxContext->CurrentIrpSp, IrpSp );
  626. DbgPrint( "--mj> %08lx %08lx\n", RxContext->MajorFunction, IrpSp->MajorFunction );
  627. DbgPrint( "--mn> %08lx %08lx\n", RxContext->MinorFunction, IrpSp->MinorFunction );
  628. // DbgBreakPoint();
  629. }
  630. RxContext->PendingReturned = FALSE;
  631. Status = RxCompleteRequest( RxContext, Status );
  632. }
  633. }
  634. } else {
  635. Status = STATUS_NOT_IMPLEMENTED;
  636. }
  637. try_exit: NOTHING;
  638. } except( RxExceptionFilter( RxContext, GetExceptionInformation() )) {
  639. //
  640. // The I/O request was not handled successfully, abort the I/O request with
  641. // the error Status that we get back from the execption code
  642. //
  643. if (RxContext != NULL) {
  644. RxContext->PendingReturned = FALSE;
  645. }
  646. Status = RxProcessException( RxContext, GetExceptionCode() );
  647. }
  648. if (TopLevel) {
  649. RxUnwindTopLevelIrp( &TopLevelContext );
  650. }
  651. FsRtlExitFileSystem();
  652. return Status;
  653. UNREFERENCED_PARAMETER( IrpSp );
  654. }
  655. #ifdef RX_PRIVATE_BUILD
  656. #undef IoGetTopLevelIrp
  657. #undef IoSetTopLevelIrp
  658. #endif // ifdef RX_PRIVATE_BUILD
  659. #define RX_TOPLEVELCTX_FLAG_FROM_POOL (0x00000001)
  660. KSPIN_LOCK TopLevelIrpSpinLock;
  661. LIST_ENTRY TopLevelIrpAllocatedContextsList;
  662. VOID
  663. RxInitializeTopLevelIrpPackage (
  664. VOID
  665. )
  666. {
  667. KeInitializeSpinLock( &TopLevelIrpSpinLock );
  668. InitializeListHead( &TopLevelIrpAllocatedContextsList );
  669. }
  670. VOID
  671. RxAddToTopLevelIrpAllocatedContextsList (
  672. IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext
  673. )
  674. /*++
  675. Routine Description:
  676. This the passed context is added to the allocatedcontexts list. THIS
  677. ROUTINE TAKES A SPINLOCK...CANNOT BE PAGED.
  678. Arguments:
  679. TopLevelContext - the context to be removed
  680. Return Value:
  681. --*/
  682. {
  683. KIRQL SavedIrql;
  684. ASSERT( TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE );
  685. ASSERT( FlagOn( TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL ) );
  686. KeAcquireSpinLock( &TopLevelIrpSpinLock, &SavedIrql );
  687. InsertHeadList( &TopLevelIrpAllocatedContextsList, &TopLevelContext->ListEntry );
  688. KeReleaseSpinLock( &TopLevelIrpSpinLock, SavedIrql );
  689. }
  690. VOID
  691. RxRemoveFromTopLevelIrpAllocatedContextsList (
  692. IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext
  693. )
  694. /*++
  695. Routine Description:
  696. This the passed context is removed from the allocatedcontexts list. THIS
  697. ROUTINE TAKES A SPINLOCK...CANNOT BE PAGED.
  698. Arguments:
  699. TopLevelContext - the context to be removed
  700. Return Value:
  701. --*/
  702. {
  703. KIRQL SavedIrql;
  704. ASSERT( TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE );
  705. ASSERT( FlagOn( TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL ) );
  706. KeAcquireSpinLock( &TopLevelIrpSpinLock, &SavedIrql );
  707. RemoveEntryList( &TopLevelContext->ListEntry );
  708. KeReleaseSpinLock( &TopLevelIrpSpinLock, SavedIrql );
  709. }
  710. BOOLEAN
  711. RxIsMemberOfTopLevelIrpAllocatedContextsList (
  712. IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext
  713. )
  714. /*++
  715. Routine Description:
  716. This looks to see if the passed context is on the allocatedcontexts list.
  717. THIS ROUTINE TAKES A SPINLOCK...CANNOT BE PAGED.
  718. Arguments:
  719. TopLevelContext - the context to be looked up
  720. Return Value:
  721. TRUE if TopLevelContext is on the list, FALSE otherwise
  722. --*/
  723. {
  724. KIRQL SavedIrql;
  725. PLIST_ENTRY ListEntry;
  726. BOOLEAN Found = FALSE;
  727. KeAcquireSpinLock( &TopLevelIrpSpinLock, &SavedIrql );
  728. ListEntry = TopLevelIrpAllocatedContextsList.Flink;
  729. while (ListEntry != &TopLevelIrpAllocatedContextsList) {
  730. PRX_TOPLEVELIRP_CONTEXT ListTopLevelContext
  731. = CONTAINING_RECORD( ListEntry, RX_TOPLEVELIRP_CONTEXT, ListEntry );
  732. ASSERT( ListTopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE );
  733. ASSERT( FlagOn( ListTopLevelContext->Flags,RX_TOPLEVELCTX_FLAG_FROM_POOL ) );
  734. if (ListTopLevelContext == TopLevelContext) {
  735. Found = TRUE;
  736. break;
  737. } else {
  738. ListEntry = ListEntry->Flink;
  739. }
  740. }
  741. KeReleaseSpinLock( &TopLevelIrpSpinLock, SavedIrql );
  742. return Found;
  743. }
  744. BOOLEAN
  745. RxIsThisAnRdbssTopLevelContext (
  746. IN PRX_TOPLEVELIRP_CONTEXT TopLevelContext
  747. )
  748. {
  749. ULONG_PTR StackBottom;
  750. ULONG_PTR StackTop;
  751. //
  752. // if it's a magic value....then no
  753. //
  754. if ((ULONG_PTR)TopLevelContext <= FSRTL_MAX_TOP_LEVEL_IRP_FLAG) {
  755. return FALSE;
  756. }
  757. //
  758. // if it's on the stack...check the signature
  759. //
  760. IoGetStackLimits( &StackTop, &StackBottom );
  761. if (((ULONG_PTR) TopLevelContext <= StackBottom - sizeof( RX_TOPLEVELIRP_CONTEXT )) &&
  762. ((ULONG_PTR) TopLevelContext >= StackTop)) {
  763. //
  764. // it's on the stack check it
  765. //
  766. if (!FlagOn( (ULONG_PTR) TopLevelContext, 0x3 ) &&
  767. (TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE)) {
  768. return TRUE;
  769. } else {
  770. return FALSE;
  771. }
  772. }
  773. return RxIsMemberOfTopLevelIrpAllocatedContextsList( TopLevelContext );
  774. }
  775. BOOLEAN
  776. RxTryToBecomeTheTopLevelIrp (
  777. IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext,
  778. IN PIRP Irp,
  779. IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
  780. IN BOOLEAN ForceTopLevel
  781. )
  782. /*++
  783. Routine Description:
  784. This routine detects if an Irp is the Top level requestor, ie. if it os OK
  785. to do a verify or pop-up now. If TRUE is returned, then no file system
  786. resources are held above us. Also, we have left a context in TLS that will
  787. allow us to tell if we are the top level...even if we are entered recursively.
  788. Arguments:
  789. TopLevelContext - the toplevelirp context to use. if NULL, allocate one
  790. Irp - the irp. could be a magic value
  791. RxDeviceObject - the associated deviceobject
  792. ForceTopLevel - if true, we force ourselves onto the TLS
  793. Return Value:
  794. BOOLEAN tells whether we became the toplevel.
  795. --*/
  796. {
  797. ULONG ContextFlags = 0;
  798. PAGED_CODE();
  799. if ((IoGetTopLevelIrp() != NULL ) && !ForceTopLevel) {
  800. return FALSE;
  801. }
  802. //
  803. // i hate doing this allocate....toplevelirp is the world's biggest kludge
  804. //
  805. if (TopLevelContext == NULL) {
  806. TopLevelContext = RxAllocatePool( NonPagedPool, sizeof( RX_TOPLEVELIRP_CONTEXT ) );
  807. if (TopLevelContext == NULL) {
  808. return FALSE;
  809. }
  810. ContextFlags = RX_TOPLEVELCTX_FLAG_FROM_POOL;
  811. }
  812. __RxInitializeTopLevelIrpContext( TopLevelContext,
  813. Irp,
  814. RxDeviceObject,
  815. ContextFlags );
  816. ASSERT( TopLevelContext->Signature == RX_TOPLEVELIRP_CONTEXT_SIGNATURE );
  817. ASSERT( (ContextFlags == 0) || FlagOn( TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL ));
  818. IoSetTopLevelIrp( (PIRP)TopLevelContext );
  819. return TRUE;
  820. }
  821. VOID
  822. __RxInitializeTopLevelIrpContext (
  823. IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext,
  824. IN PIRP Irp,
  825. IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
  826. IN ULONG Flags
  827. )
  828. /*++
  829. Routine Description:
  830. This routine initalizes a toplevelirp context.
  831. Arguments:
  832. TopLevelContext - the toplevelirp context to use.
  833. Irp - the irp. could be a magic value
  834. RxDeviceObject - the associated deviceobject
  835. Flags - could be various...currently just tells if context is allocated or not
  836. Return Value:
  837. None.
  838. --*/
  839. {
  840. RtlZeroMemory( TopLevelContext, sizeof( RX_TOPLEVELIRP_CONTEXT ) );
  841. TopLevelContext->Signature = RX_TOPLEVELIRP_CONTEXT_SIGNATURE;
  842. TopLevelContext->Irp = Irp;
  843. TopLevelContext->Flags = Flags;
  844. TopLevelContext->RxDeviceObject = RxDeviceObject;
  845. TopLevelContext->Previous = IoGetTopLevelIrp();
  846. TopLevelContext->Thread = PsGetCurrentThread();
  847. //
  848. // if this is an allocated context, add it to the allocatedcontextslist
  849. //
  850. if (FlagOn( TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL )) {
  851. RxAddToTopLevelIrpAllocatedContextsList( TopLevelContext );
  852. }
  853. }
  854. VOID
  855. RxUnwindTopLevelIrp (
  856. IN OUT PRX_TOPLEVELIRP_CONTEXT TopLevelContext
  857. )
  858. /*++
  859. Routine Description:
  860. This routine removes us from the TLC....replacing by the previous.
  861. Arguments:
  862. TopLevelContext - the toplevelirp context to use. if NULL, use the one from TLS
  863. Return Value:
  864. None.
  865. --*/
  866. {
  867. if (TopLevelContext == NULL) {
  868. //
  869. // get the one off the thread and do some asserts to make sure it's me
  870. //
  871. TopLevelContext = (PRX_TOPLEVELIRP_CONTEXT)(IoGetTopLevelIrp());
  872. //
  873. // depending on a race condition, this context could be NULL.
  874. // we chkec it before hand and bail if so.
  875. // In this case the Irp was completed by another thread.
  876. //
  877. if (!TopLevelContext) {
  878. return;
  879. }
  880. ASSERT( RxIsThisAnRdbssTopLevelContext( TopLevelContext ) );
  881. ASSERT( FlagOn( TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL ) );
  882. }
  883. ASSERT( TopLevelContext->Thread == PsGetCurrentThread() );
  884. IoSetTopLevelIrp( TopLevelContext->Previous );
  885. if (FlagOn( TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL )) {
  886. RxRemoveFromTopLevelIrpAllocatedContextsList( TopLevelContext );
  887. RxFreePool( TopLevelContext );
  888. }
  889. }
  890. BOOLEAN
  891. RxIsThisTheTopLevelIrp (
  892. IN PIRP Irp
  893. )
  894. /*++
  895. Routine Description:
  896. This determines if the irp at hand is the toplevel irp.
  897. Arguments:
  898. Irp - the one to find out if it's toplevel...btw, it works for NULL.
  899. Return Value:
  900. TRUE if irp is the toplevelirp.
  901. --*/
  902. {
  903. PIRP TopIrp = IoGetTopLevelIrp();
  904. PRX_TOPLEVELIRP_CONTEXT TopLevelContext;
  905. TopLevelContext = (PRX_TOPLEVELIRP_CONTEXT)TopIrp;
  906. if (RxIsThisAnRdbssTopLevelContext( TopLevelContext )) {
  907. TopIrp = TopLevelContext->Irp;
  908. }
  909. return (TopIrp == Irp);
  910. }
  911. PIRP
  912. RxGetTopIrpIfRdbssIrp (
  913. VOID
  914. )
  915. /*++
  916. Routine Description:
  917. This gets the toplevelirp if it belongs to the rdbss.
  918. Arguments:
  919. Return Value:
  920. topirp if topirp is rdbss-irp and NULL otherwise.
  921. --*/
  922. {
  923. PRX_TOPLEVELIRP_CONTEXT TopLevelContext;
  924. TopLevelContext = (PRX_TOPLEVELIRP_CONTEXT)(IoGetTopLevelIrp());
  925. if (RxIsThisAnRdbssTopLevelContext( TopLevelContext )) {
  926. return TopLevelContext->Irp;
  927. } else {
  928. return NULL;
  929. }
  930. }
  931. PRDBSS_DEVICE_OBJECT
  932. RxGetTopDeviceObjectIfRdbssIrp (
  933. VOID
  934. )
  935. /*++
  936. Routine Description:
  937. This gets the deviceobject assoc'd w/ toplevelirp if topirp belongs to the rdbss.
  938. Arguments:
  939. Return Value:
  940. deviceobject for topirp if topirp is rdbss-irp and NULL otherwise.
  941. --*/
  942. {
  943. PRX_TOPLEVELIRP_CONTEXT TopLevelContext;
  944. TopLevelContext = (PRX_TOPLEVELIRP_CONTEXT)(IoGetTopLevelIrp());
  945. if (RxIsThisAnRdbssTopLevelContext( TopLevelContext )) {
  946. return TopLevelContext->RxDeviceObject;
  947. } else {
  948. return NULL;
  949. }
  950. }