Source code of Windows XP (NT5)
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.

1442 lines
39 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. RxInit.c
  5. Abstract:
  6. This module implements the DRIVER_INITIALIZATION routine for the RDBSS.
  7. Also, the routines for pagingio resource selection/allocation are here; since
  8. we have to delete the resources when we unload, having them here simply centralizes
  9. all the pagingio resource stuff.
  10. Finally, the routines that are here that implement the wrapper's version of
  11. network provider order. Basically, the wrapper MUST implement the same concept of
  12. network provider order as the MUP so that the UI will work as expected. So, we
  13. read the provider order from the registry at init time and memorize the order. Then,
  14. we can assign the correct order when minirdrs register. Obviously, provider order is
  15. not an issue in MONOLITHIC mode.
  16. Author:
  17. Joe Linn [JoeLinn] 20-jul-1994
  18. Revision History:
  19. --*/
  20. #include "precomp.h"
  21. #pragma hdrstop
  22. #include "ntverp.h"
  23. #include "NtDdNfs2.h"
  24. #include "netevent.h"
  25. //
  26. // The local debug trace level
  27. //
  28. #define Dbg (0)
  29. ULONG RxBuildNumber = VER_PRODUCTBUILD;
  30. #ifdef RX_PRIVATE_BUILD
  31. ULONG RxPrivateBuild = 1;
  32. #else
  33. ULONG RxPrivateBuild = 0;
  34. #endif
  35. #ifdef MONOLITHIC_MINIRDR
  36. RDBSS_DEVICE_OBJECT RxSpaceForTheWrappersDeviceObject;
  37. #endif
  38. #define LANMAN_WORKSTATION_PARAMETERS \
  39. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\LanmanWorkStation\\Parameters"
  40. BOOLEAN DisableByteRangeLockingOnReadOnlyFiles = FALSE;
  41. VOID
  42. RxReadRegistryParameters();
  43. NPAGED_LOOKASIDE_LIST RxContextLookasideList;
  44. VOID
  45. RxGetRegistryParameters(
  46. IN PUNICODE_STRING RegistryPath
  47. );
  48. NTSTATUS
  49. RxInitializeRegistrationStructures(
  50. void
  51. );
  52. VOID
  53. RxUninitializeRegistrationStructures(
  54. void
  55. );
  56. VOID
  57. RxAbbreviatedWriteLogEntry__ (
  58. IN NTSTATUS Status,
  59. IN ULONG OneExtraUlong
  60. );
  61. #define RxAbbreviatedWriteLogEntry(STATUS__) RxAbbreviatedWriteLogEntry__(STATUS__,__LINE__)
  62. NTSTATUS
  63. RxGetStringRegistryParameter(
  64. HANDLE ParametersHandle,
  65. PWCHAR ParameterName,
  66. PUNICODE_STRING ParamString,
  67. PKEY_VALUE_PARTIAL_INFORMATION Value,
  68. ULONG ValueSize,
  69. BOOLEAN LogFailure
  70. );
  71. NTSTATUS
  72. RxGetUlongRegistryParameter(
  73. HANDLE ParametersHandle,
  74. PWCHAR ParameterName,
  75. PULONG ParamUlong,
  76. PKEY_VALUE_PARTIAL_INFORMATION Value,
  77. ULONG ValueSize,
  78. BOOLEAN LogFailure
  79. );
  80. //this type and variable are used for unwinding the initialization so that stuff doesn't go thru the cracks
  81. // the way that this works is that stuff is done in the reverse order of the enumeration. that way i can just
  82. // use a switch-no-break to unwind.
  83. typedef enum _RX_INIT_STATES {
  84. RXINIT_ALL_INITIALIZATION_COMPLETED,
  85. RXINIT_CONSTRUCTED_PROVIDERORDER,
  86. RXINIT_CREATED_LOG,
  87. RXINIT_CREATED_DEVICE_OBJECT,
  88. RXINIT_CREATED_FIRST_LINK,
  89. RXINIT_START
  90. } RX_INIT_STATES;
  91. VOID
  92. RxInitUnwind(
  93. IN PDRIVER_OBJECT DriverObject,
  94. IN RX_INIT_STATES RxInitState
  95. );
  96. #ifdef ALLOC_PRAGMA
  97. #pragma alloc_text(INIT, RxDriverEntry)
  98. #pragma alloc_text(INIT, RxGetRegistryParameters)
  99. #pragma alloc_text(INIT, RxGetStringRegistryParameter)
  100. #pragma alloc_text(INIT, RxGetUlongRegistryParameter)
  101. #pragma alloc_text(INIT, RxAbbreviatedWriteLogEntry__)
  102. #pragma alloc_text(PAGE, RxUnload)
  103. #pragma alloc_text(PAGE, RxInitUnwind)
  104. #pragma alloc_text(PAGE, RxGetNetworkProviderPriority)
  105. #pragma alloc_text(PAGE, RxInitializeRegistrationStructures)
  106. #pragma alloc_text(PAGE, RxUninitializeRegistrationStructures)
  107. #pragma alloc_text(PAGE, RxInitializeMinirdrDispatchTable)
  108. #pragma alloc_text(PAGE, __RxFillAndInstallFastIoDispatch)
  109. #pragma alloc_text(PAGE, RxReadRegistryParameters)
  110. #endif
  111. #define RX_SYMLINK_NAME L"\\??\\fsWrap"
  112. BOOLEAN EnableWmiLog = FALSE;
  113. NTSTATUS
  114. RxDriverEntry(
  115. IN PDRIVER_OBJECT DriverObject,
  116. IN PUNICODE_STRING RegistryPath
  117. )
  118. /*++
  119. Routine Description:
  120. This is the initialization routine for the Rx file system
  121. device driver. This routine creates the device object for the FileSystem
  122. device and performs all other driver initialization.
  123. Arguments:
  124. DriverObject - Pointer to driver object created by the system.
  125. Return Value:
  126. RXSTATUS - The function value is the final status from the initialization
  127. operation.
  128. --*/
  129. {
  130. NTSTATUS Status;
  131. RX_INIT_STATES RxInitState = 0;
  132. #ifndef MONOLITHIC_MINIRDR
  133. UNICODE_STRING UnicodeString,LinkName;
  134. #endif
  135. //Structure checks
  136. RxCheckFcbStructuresForAlignment(); //this will bugcheck if things are bad
  137. //
  138. // Initialize the global data structures
  139. ZeroAndInitializeNodeType( &RxData, RDBSS_NTC_DATA_HEADER, sizeof(RDBSS_DATA));
  140. RxData.DriverObject = DriverObject;
  141. ZeroAndInitializeNodeType( &RxDeviceFCB, RDBSS_NTC_DEVICE_FCB, sizeof(FCB));
  142. KeInitializeSpinLock( &RxStrucSupSpinLock );
  143. RxExports.pRxStrucSupSpinLock = &RxStrucSupSpinLock;
  144. RxInitializeDebugSupport();
  145. try {
  146. Status = RXINIT_START;
  147. #ifndef MONOLITHIC_MINIRDR
  148. //
  149. // Create a symbolic link from \\dosdevices\fswrap to the rdbss device object name
  150. RtlInitUnicodeString(&LinkName, RX_SYMLINK_NAME);
  151. RtlInitUnicodeString(&UnicodeString, DD_NFS2_DEVICE_NAME_U);
  152. IoDeleteSymbolicLink(&LinkName);
  153. Status = IoCreateSymbolicLink(&LinkName, &UnicodeString);
  154. if (!NT_SUCCESS( Status )) {
  155. try_return( Status );
  156. }
  157. RxInitState = RXINIT_CREATED_FIRST_LINK;
  158. //
  159. // Create the device object.
  160. Status = IoCreateDevice(DriverObject,
  161. sizeof(RDBSS_DEVICE_OBJECT) - sizeof(DEVICE_OBJECT),
  162. &UnicodeString,
  163. FILE_DEVICE_NETWORK_FILE_SYSTEM,
  164. FILE_REMOTE_DEVICE,
  165. FALSE,
  166. (PDEVICE_OBJECT *)(&RxFileSystemDeviceObject));
  167. if (!NT_SUCCESS( Status )) {
  168. try_return( Status );
  169. }
  170. RxInitState = RXINIT_CREATED_DEVICE_OBJECT;
  171. #else
  172. // in monolithic mode, the wrapper doesn't really need a device object but
  173. // we allocate stuff in the wrapper's device object in order to appropriately throttle
  174. // thread usage per device object.
  175. RxFileSystemDeviceObject = &RxSpaceForTheWrappersDeviceObject;
  176. RtlZeroMemory(RxFileSystemDeviceObject,sizeof(RxSpaceForTheWrappersDeviceObject));
  177. #endif
  178. //
  179. // Initialize the trace and logging facilities. loginit is a big allocation.
  180. RxInitializeDebugTrace();
  181. RxInitializeLog();
  182. RxInitState = RXINIT_CREATED_LOG;
  183. RxGetRegistryParameters(RegistryPath);
  184. RxDbgTrace(0, (DEBUG_TRACE_ALWAYS), ("Constants %08lx %08lx\n",
  185. RX_CONTEXT_FLAG_WAIT,
  186. RX_CONTEXT_CREATE_FLAG_ADDEDBACKSLASH
  187. ));
  188. RxReadRegistryParameters();
  189. //
  190. // Initialize the minirdr registration facilities.
  191. Status = RxInitializeRegistrationStructures();
  192. if (!NT_SUCCESS( Status )) {
  193. try_return( Status );
  194. }
  195. RxInitState = RXINIT_CONSTRUCTED_PROVIDERORDER;
  196. try_exit: NOTHING;
  197. } finally {
  198. if (Status != STATUS_SUCCESS) {
  199. RxLogFailure (
  200. RxFileSystemDeviceObject,
  201. NULL,
  202. EVENT_RDR_UNEXPECTED_ERROR,
  203. Status);
  204. RxInitUnwind(DriverObject,RxInitState);
  205. }
  206. }
  207. if (Status != STATUS_SUCCESS) {
  208. return(Status);
  209. }
  210. //
  211. //
  212. //
  213. //
  214. // ##### ## # # #### ###### #####
  215. // # # # # ## # # # # # #
  216. // # # # # # # # # ##### # #
  217. // # # ###### # # # # ### # #####
  218. // # # # # # ## # # # # #
  219. // ##### # # # # #### ###### # #
  220. //
  221. //
  222. //
  223. // EVERYTHING FROM HERE DOWN BETTER WORK BECAUSE THERE IS NO MORE UNWINDING!!!
  224. //
  225. //
  226. RxInitializeDispatcher();
  227. RxInitializeBackoffPackage();
  228. // Initialize the look aside list for RxContext allocation
  229. ExInitializeNPagedLookasideList(
  230. &RxContextLookasideList,
  231. ExAllocatePoolWithTag,
  232. ExFreePool,
  233. 0,
  234. sizeof(RX_CONTEXT),
  235. RX_IRPC_POOLTAG,
  236. 4);
  237. // Initialize the list of transport Irps to an empty list
  238. InitializeListHead(&RxIrpsList);
  239. KeInitializeSpinLock(&RxIrpsListSpinLock);
  240. // Initialize the list of active contexts to an empty list
  241. InitializeListHead(&RxActiveContexts);
  242. // Initialize the list of srv call downs active
  243. InitializeListHead(&RxSrvCalldownList);
  244. // a fastmutex is used to serialize access to the Qs that serialize blocking pipe operations
  245. ExInitializeFastMutex(&RxContextPerFileSerializationMutex);
  246. // and to serialize access to the Qs that serialize some pagingio operations
  247. ExInitializeFastMutex(&RxLowIoPagingIoSyncMutex);
  248. // Initialize the scavenger mutex
  249. KeInitializeMutex(&RxScavengerMutex,1);
  250. // Initialize the global serialization Mutex.
  251. KeInitializeMutex(&RxSerializationMutex,1);
  252. //
  253. // Initialize the wrapper's overflow queue
  254. //
  255. {
  256. PRDBSS_DEVICE_OBJECT MyDo = (PRDBSS_DEVICE_OBJECT)RxFileSystemDeviceObject;
  257. LONG Index;
  258. for (Index = 0; Index < MaximumWorkQueue; Index++) {
  259. MyDo->OverflowQueueCount[Index] = 0;
  260. InitializeListHead( &MyDo->OverflowQueue[Index] );
  261. MyDo->PostedRequestCount[Index] = 0;
  262. }
  263. KeInitializeSpinLock( &MyDo->OverflowQueueSpinLock );
  264. }
  265. //
  266. // Initialize dispatch vector for driver object AND ALSO FOR the devicefcb
  267. RxInitializeDispatchVectors(DriverObject);
  268. ExInitializeResourceLite( &RxData.Resource );
  269. //
  270. // Set up global pointer to our process.
  271. RxData.OurProcess = PsGetCurrentProcess();
  272. //
  273. // Put in a bunch of sanity checks about various structures...hey, it's init code!
  274. IF_DEBUG {
  275. ULONG FcbStateBufferingMask = FCB_STATE_BUFFERING_STATE_MASK;
  276. ULONG MinirdrBufStateCommandMask = MINIRDR_BUFSTATE_COMMAND_MASK;
  277. USHORT EightBitsPerChar = 8;
  278. //we could put in defines for the ULONG/USHORTS here...but they don't change often
  279. ASSERT ( MRDRBUFSTCMD_MAXXX == (sizeof(ULONG)*EightBitsPerChar) );
  280. ASSERT (!(FcbStateBufferingMask&MinirdrBufStateCommandMask));
  281. }
  282. //
  283. // Setup the timer subsystem
  284. RxInitializeRxTimer();
  285. #ifndef MONOLITHIC_MINIRDR
  286. Status = IoWMIRegistrationControl ((PDEVICE_OBJECT)RxFileSystemDeviceObject, WMIREG_ACTION_REGISTER);
  287. if (Status != STATUS_SUCCESS) {
  288. DbgPrint("Rdbss fails to register WMI %lx\n",Status);
  289. } else {
  290. EnableWmiLog = TRUE;
  291. }
  292. #endif
  293. return( STATUS_SUCCESS );
  294. }
  295. //
  296. // Unload routine
  297. //
  298. VOID
  299. RxUnload(
  300. IN PDRIVER_OBJECT DriverObject
  301. )
  302. /*++
  303. Routine Description:
  304. This is the unload routine for the RDBSS.
  305. Arguments:
  306. DriverObject - pointer to the driver object for the RDBSS
  307. Return Value:
  308. None
  309. --*/
  310. {
  311. //UNICODE_STRING LinkName;
  312. PAGED_CODE();
  313. RxTearDownRxTimer();
  314. //remember this
  315. // RdrUnloadSecurity();
  316. RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("RxUnload: DriverObject =%08lx\n", DriverObject ));
  317. ExDeleteResourceLite(&RxData.Resource);
  318. RxUninitializeBackoffPackage();
  319. RxTearDownDispatcher();
  320. RxTearDownDebugSupport();
  321. ExDeleteNPagedLookasideList(
  322. &RxContextLookasideList);
  323. RxInitUnwind(DriverObject, RXINIT_ALL_INITIALIZATION_COMPLETED);
  324. if (EnableWmiLog) {
  325. NTSTATUS Status;
  326. Status = IoWMIRegistrationControl ((PDEVICE_OBJECT)RxFileSystemDeviceObject, WMIREG_ACTION_DEREGISTER);
  327. if (Status != STATUS_SUCCESS) {
  328. DbgPrint("Rdbss fails to deregister WMI %lx\n",Status);
  329. }
  330. }
  331. }
  332. #if DBG
  333. PCHAR RxUnwindFollower = NULL;
  334. #define UNWIND_CASE(x) case x: RxUnwindFollower = #x;
  335. #else
  336. #define UNWIND_CASE(x) case x:
  337. #endif
  338. VOID
  339. RxInitUnwind(
  340. IN PDRIVER_OBJECT DriverObject,
  341. IN RX_INIT_STATES RxInitState
  342. )
  343. /*++
  344. Routine Description:
  345. This routine does the common uninit work for unwinding from a bad driver entry or for unloading.
  346. Arguments:
  347. RxInitState - tells how far we got into the intialization
  348. Return Value:
  349. None
  350. --*/
  351. {
  352. #ifndef MONOLITHIC_MINIRDR
  353. UNICODE_STRING LinkName;
  354. #endif
  355. PAGED_CODE();
  356. switch (RxInitState) {
  357. UNWIND_CASE(RXINIT_ALL_INITIALIZATION_COMPLETED)
  358. //Nothing extra to do...this is just so that the constant in RxUnload doesn't change.......
  359. //lack of break intentional
  360. UNWIND_CASE(RXINIT_CONSTRUCTED_PROVIDERORDER)
  361. RxUninitializeRegistrationStructures();
  362. //lack of break intentional
  363. UNWIND_CASE(RXINIT_CREATED_LOG)
  364. RxUninitializeLog();
  365. //lack of break intentional
  366. #ifndef MONOLITHIC_MINIRDR
  367. UNWIND_CASE(RXINIT_CREATED_DEVICE_OBJECT)
  368. IoDeleteDevice((PDEVICE_OBJECT)RxFileSystemDeviceObject);
  369. //lack of break intentional
  370. UNWIND_CASE(RXINIT_CREATED_FIRST_LINK)
  371. RtlInitUnicodeString(&LinkName, RX_SYMLINK_NAME);
  372. IoDeleteSymbolicLink(&LinkName);
  373. // lack of break intentional
  374. #endif
  375. UNWIND_CASE(RXINIT_START)
  376. //RdrUninitializeDiscardableCode();
  377. //DbgBreakPoint();
  378. break;
  379. }
  380. }
  381. VOID
  382. RxAbbreviatedWriteLogEntry__ (
  383. IN NTSTATUS Status,
  384. IN ULONG OneExtraUlong
  385. )
  386. /*++
  387. Routine Description:
  388. This routine write a log entry with most of the fields set to fixed values.
  389. Arguments:
  390. Status - the status to be stored in the log record
  391. OneExtraUlong - a key for finding out what happened
  392. Return Value:
  393. none.
  394. --*/
  395. {
  396. //RxLogFailureWithBuffer (
  397. // RxFileSystemDeviceObject,
  398. // NULL,
  399. // EVENT_RDR_CANT_READ_REGISTRY,
  400. // Status,
  401. // &OneExtraUlong,
  402. // sizeof(ULONG)
  403. // );
  404. }
  405. VOID
  406. RxGetRegistryParameters(
  407. PUNICODE_STRING RegistryPath
  408. )
  409. {
  410. ULONG Storage[256];
  411. UNICODE_STRING UnicodeString;
  412. HANDLE ConfigHandle;
  413. HANDLE ParametersHandle;
  414. NTSTATUS Status;
  415. //ULONG BytesRead;
  416. OBJECT_ATTRIBUTES ObjectAttributes;
  417. PKEY_VALUE_FULL_INFORMATION Value = (PKEY_VALUE_FULL_INFORMATION)Storage;
  418. PAGED_CODE(); //INIT
  419. InitializeObjectAttributes(
  420. &ObjectAttributes,
  421. RegistryPath, // name
  422. OBJ_CASE_INSENSITIVE, // attributes
  423. NULL, // root
  424. NULL // security descriptor
  425. );
  426. Status = ZwOpenKey (&ConfigHandle, KEY_READ, &ObjectAttributes);
  427. if (!NT_SUCCESS(Status)) {
  428. //RxLogFailure (
  429. // RxFileSystemDeviceObject,
  430. // NULL,
  431. // EVENT_RDR_CANT_READ_REGISTRY,
  432. // Status);
  433. return;
  434. }
  435. RtlInitUnicodeString(&UnicodeString, L"Parameters");
  436. InitializeObjectAttributes(
  437. &ObjectAttributes,
  438. &UnicodeString,
  439. OBJ_CASE_INSENSITIVE,
  440. ConfigHandle,
  441. NULL
  442. );
  443. Status = ZwOpenKey (&ParametersHandle, KEY_READ, &ObjectAttributes);
  444. if (!NT_SUCCESS(Status)) {
  445. //RxLogFailure (
  446. // RxFileSystemDeviceObject,
  447. // NULL,
  448. // EVENT_RDR_CANT_READ_REGISTRY,
  449. // Status);
  450. ZwClose(ConfigHandle);
  451. return;
  452. }
  453. #ifdef RDBSSLOG
  454. RxGetStringRegistryParameter(ParametersHandle,
  455. L"InitialDebugString",
  456. &UnicodeString,
  457. (PKEY_VALUE_PARTIAL_INFORMATION) Storage,
  458. sizeof(Storage),
  459. FALSE
  460. );
  461. //DbgPrint("String From Registry %wZ, buffer = %08lx\n",&UnicodeString,UnicodeString.Buffer);
  462. if (UnicodeString.Length && UnicodeString.Length<320) {
  463. PWCH u = UnicodeString.Buffer;
  464. ULONG l;
  465. PCH p = (PCH)u;
  466. for (l=0;l<UnicodeString.Length;l++) {
  467. *p++ = (CHAR)*u++;
  468. *p = 0;
  469. }
  470. DbgPrint("InitialDebugString From Registry as singlebytestring: <%s>\n",UnicodeString.Buffer);
  471. RxDebugControlCommand((PCH)UnicodeString.Buffer);
  472. }
  473. #endif //RDBSSLOG
  474. ZwClose(ParametersHandle);
  475. ZwClose(ConfigHandle);
  476. }
  477. NTSTATUS
  478. RxGetStringRegistryParameter(
  479. HANDLE ParametersHandle,
  480. PWCHAR ParameterName,
  481. PUNICODE_STRING ParamString,
  482. PKEY_VALUE_PARTIAL_INFORMATION Value,
  483. ULONG ValueSize,
  484. BOOLEAN LogFailure
  485. )
  486. {
  487. UNICODE_STRING UnicodeString;
  488. NTSTATUS Status;
  489. ULONG BytesRead;
  490. PAGED_CODE(); //INIT
  491. RtlInitUnicodeString(&UnicodeString, ParameterName);
  492. Status = ZwQueryValueKey(ParametersHandle,
  493. &UnicodeString,
  494. KeyValuePartialInformation,
  495. Value,
  496. ValueSize,
  497. &BytesRead);
  498. ParamString->Length = 0;
  499. ParamString->Buffer = NULL;
  500. if (NT_SUCCESS(Status)) {
  501. ParamString->Buffer = (PWCH)(&Value->Data[0]);
  502. //the datalength actually accounts for the trailing null
  503. ParamString->Length = ((USHORT)Value->DataLength) - sizeof(WCHAR);
  504. ParamString->MaximumLength = ParamString->Length;
  505. return STATUS_SUCCESS;
  506. }
  507. if (!LogFailure) { return Status; }
  508. RxLogFailure (
  509. RxFileSystemDeviceObject,
  510. NULL,
  511. EVENT_RDR_CANT_READ_REGISTRY,
  512. Status);
  513. return Status;
  514. }
  515. NTSTATUS
  516. RxGetUlongRegistryParameter(
  517. HANDLE ParametersHandle,
  518. PWCHAR ParameterName,
  519. PULONG ParamUlong,
  520. PKEY_VALUE_PARTIAL_INFORMATION Value,
  521. ULONG ValueSize,
  522. BOOLEAN LogFailure
  523. )
  524. {
  525. UNICODE_STRING UnicodeString;
  526. NTSTATUS Status;
  527. ULONG BytesRead;
  528. PAGED_CODE(); //INIT
  529. RtlInitUnicodeString(&UnicodeString, ParameterName);
  530. Status = ZwQueryValueKey(ParametersHandle,
  531. &UnicodeString,
  532. KeyValuePartialInformation,
  533. Value,
  534. ValueSize,
  535. &BytesRead);
  536. if (NT_SUCCESS(Status)) {
  537. if (Value->Type == REG_DWORD) {
  538. PULONG ConfigValue = (PULONG)&Value->Data[0];
  539. *ParamUlong = *((PULONG)ConfigValue);
  540. DbgPrint("readRegistryvalue %wZ = %08lx\n",&UnicodeString,*ParamUlong);
  541. return(STATUS_SUCCESS);
  542. } else {
  543. Status = STATUS_INVALID_PARAMETER;
  544. }
  545. }
  546. if (!LogFailure) { return Status; }
  547. RxLogFailureWithBuffer (
  548. RxFileSystemDeviceObject,
  549. NULL,
  550. EVENT_RDR_CANT_READ_REGISTRY,
  551. Status,
  552. ParameterName,
  553. (USHORT)(wcslen(ParameterName)*sizeof(WCHAR))
  554. );
  555. return Status;
  556. }
  557. /*-------------------------------
  558. This set of routines implements the network provider order in the wrapper.
  559. The way that this works is somewhat complicated. First, we go to the registry
  560. to get the provider order; it is stored at key=PROVIDERORDER_REGISTRY_KEY and
  561. value=L"ProviderOrder". This is a list of service providers whereas what we need
  562. are the device names. So, for each ServiceProverName, we go to the registry to
  563. get the device name at key=SERVICE_REGISTRY_KEY, subkey=ServiceProverName,
  564. subsubkey=NETWORK_PROVIDER_SUBKEY, and value=L"Devicename".
  565. We build a linked list of these guys. Later when a minirdr registers, we look
  566. on this list for the corresponding device name and that gives us the priority.
  567. simple? i think NOT.
  568. ----------------------------------*/
  569. #ifndef MONOLITHIC_MINIRDR
  570. NTSTATUS
  571. RxAccrueProviderFromServiceName (
  572. HANDLE ServicesHandle,
  573. PUNICODE_STRING ServiceName,
  574. ULONG Priority,
  575. PWCHAR ProviderInfoNameBuffer,
  576. ULONG ProviderInfoNameBufferLength
  577. );
  578. NTSTATUS
  579. RxConstructProviderOrder (
  580. void
  581. );
  582. VOID
  583. RxDestructProviderOrder (
  584. void
  585. );
  586. #ifdef ALLOC_PRAGMA
  587. #pragma alloc_text(INIT, RxAccrueProviderFromServiceName)
  588. #pragma alloc_text(INIT, RxConstructProviderOrder)
  589. #pragma alloc_text(PAGE, RxDestructProviderOrder)
  590. #endif
  591. #define PROVIDERORDER_REGISTRY_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\NetworkProvider\\Order"
  592. #define SERVICE_REGISTRY_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
  593. #define NETWORK_PROVIDER_SUBKEY L"\\networkprovider"
  594. typedef struct _RX_UNC_PROVIDER_HEADER {
  595. union {
  596. LIST_ENTRY;
  597. LIST_ENTRY Links;
  598. };
  599. ULONG Priority;
  600. union {
  601. UNICODE_STRING;
  602. UNICODE_STRING DeviceName;
  603. };
  604. } RX_UNC_PROVIDER_HEADER;
  605. typedef struct _RX_UNC_PROVIDER {
  606. RX_UNC_PROVIDER_HEADER;
  607. KEY_VALUE_PARTIAL_INFORMATION Info;
  608. } RX_UNC_PROVIDER, *PRX_UNC_PROVIDER;
  609. LIST_ENTRY RxUncProviders;
  610. ULONG
  611. RxGetNetworkProviderPriority(
  612. IN PUNICODE_STRING DeviceName
  613. )
  614. /*++
  615. Routine Description:
  616. This routine is called at minirdr registration time to find out the priority
  617. of the provider with the given DeviceName. It simply looks it up on a list.
  618. Arguments:
  619. DeviceName - name of the device whose priority is to be found
  620. Return Value:
  621. the network provider priority that the MUP will use.
  622. --*/
  623. {
  624. PLIST_ENTRY Entry;
  625. PAGED_CODE();
  626. RxLog(("FindUncProvider %wZ \n",DeviceName));
  627. RxWmiLog(LOG,
  628. RxGetNetworkProviderPriority,
  629. LOGUSTR(*DeviceName));
  630. for (Entry = RxUncProviders.Flink;
  631. Entry != &RxUncProviders;
  632. ) {
  633. PRX_UNC_PROVIDER UncProvider = (PRX_UNC_PROVIDER)Entry;
  634. Entry = Entry->Flink;
  635. if ( RtlEqualUnicodeString( DeviceName, &UncProvider->DeviceName, TRUE )) {
  636. return(UncProvider->Priority);
  637. }
  638. }
  639. // no corresponding entry was found
  640. return(0x7effffff); //got this constant from the MUP........
  641. }
  642. NTSTATUS
  643. RxAccrueProviderFromServiceName (
  644. HANDLE ServicesHandle,
  645. PUNICODE_STRING ServiceName,
  646. ULONG Priority,
  647. PWCHAR ProviderInfoNameBuffer,
  648. ULONG ProviderInfoNameBufferLength
  649. )
  650. /*++
  651. Routine Description:
  652. This routine has the responsibility to look up the device name corresponding
  653. to a particular provider name; if successful, the device name and the corresponding
  654. priority are recorded on the UncProvider List.
  655. Arguments:
  656. HANDLE ServicesHandle - a handle to the services root in the registry
  657. PUNICODE_STRING ServiceName - the name of the service relative to the servicehandle
  658. ULONG Priority, - the priority of this provider
  659. PWCHAR ProviderInfoNameBuffer, - a buffer that can be used to accrue the subkey name
  660. ULONG ProviderInfoNameBufferLength - and the length
  661. Return Value:
  662. STATUS_SUCCESS if everything worked elsewise an error status.
  663. --*/
  664. {
  665. NTSTATUS Status;
  666. OBJECT_ATTRIBUTES ObjectAttributes;
  667. UNICODE_STRING ProviderInfoName,ProviderInfoKey,ParameterDeviceName;
  668. HANDLE NetworkProviderInfoHandle = INVALID_HANDLE_VALUE;
  669. KEY_VALUE_PARTIAL_INFORMATION InitialValuePartialInformation;
  670. ULONG DummyBytesRead,ProviderLength;
  671. PRX_UNC_PROVIDER UncProvider = NULL;
  672. PAGED_CODE();
  673. RxLog(("SvcNm %wZ",ServiceName));
  674. RxWmiLog(LOG,
  675. RxAccrueProviderFromServiceName_1,
  676. LOGUSTR(*ServiceName));
  677. //
  678. // Form the correct keyname using the bufferspace provided
  679. ProviderInfoName.Buffer = ProviderInfoNameBuffer;
  680. ProviderInfoName.Length = 0;
  681. ProviderInfoName.MaximumLength = (USHORT)ProviderInfoNameBufferLength;
  682. Status = RtlAppendUnicodeStringToString(&ProviderInfoName,ServiceName);
  683. if (Status != STATUS_SUCCESS) {
  684. DbgPrint("Could append1: %08lx %wZ\n",Status,&ProviderInfoName);
  685. //RxAbbreviatedWriteLogEntry(Status);
  686. goto FINALLY;
  687. }
  688. RtlInitUnicodeString(&ProviderInfoKey, NETWORK_PROVIDER_SUBKEY);
  689. Status = RtlAppendUnicodeStringToString(&ProviderInfoName,&ProviderInfoKey);
  690. if (Status != STATUS_SUCCESS) {
  691. DbgPrint("Could append2: %08lx %wZ\n",Status,&ProviderInfoName);
  692. RxAbbreviatedWriteLogEntry(Status);
  693. goto FINALLY;
  694. }
  695. //
  696. // Open the key in preparation for reeading the devicename value
  697. //DbgPrint("RxAccrueProviderFromServiceName providerinfoname %wZ\n",&ProviderInfoName);
  698. InitializeObjectAttributes(
  699. &ObjectAttributes,
  700. &ProviderInfoName, // name
  701. OBJ_CASE_INSENSITIVE, // attributes
  702. ServicesHandle, // root
  703. NULL // security descriptor
  704. );
  705. Status = ZwOpenKey (&NetworkProviderInfoHandle, KEY_READ, &ObjectAttributes);
  706. if (!NT_SUCCESS(Status)) {
  707. DbgPrint("NetWorkProviderInfoFailed: %08lx %wZ\n",Status,&ProviderInfoName);
  708. RxAbbreviatedWriteLogEntry(Status);
  709. goto FINALLY;
  710. }
  711. //
  712. // Read the devicename. we do this in two steps. first, we do a partial read to find out
  713. // how big the name really is. Then, we allocate a UncProviderEntry of the correctsize and make
  714. // a second call to fill it in.
  715. //DbgPrint("RxAccrueProviderFromServiceName ServiceName %wZ; worked\n",ServiceName);
  716. RtlInitUnicodeString(&ParameterDeviceName, L"DeviceName");
  717. Status = ZwQueryValueKey(NetworkProviderInfoHandle,
  718. &ParameterDeviceName,
  719. KeyValuePartialInformation,
  720. &InitialValuePartialInformation,
  721. sizeof(InitialValuePartialInformation),
  722. &DummyBytesRead);
  723. if (Status==STATUS_BUFFER_OVERFLOW) {
  724. Status=STATUS_SUCCESS;
  725. }
  726. if (Status!=STATUS_SUCCESS) {
  727. RxAbbreviatedWriteLogEntry(Status);
  728. goto FINALLY;
  729. }
  730. //DbgPrint("RxAccrueProviderFromServiceName ServiceName %wZ; worked; devicenamesize=%08lx\n",
  731. // ServiceName,InitialValuePartialInformation.DataLength);
  732. ProviderLength = sizeof(RX_UNC_PROVIDER)+InitialValuePartialInformation.DataLength;
  733. UncProvider = RxAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION ,ProviderLength,RX_MRX_POOLTAG);
  734. if (UncProvider==NULL) {
  735. Status = STATUS_INSUFFICIENT_RESOURCES;
  736. DbgPrint("UncProviderAllocationFailed: %08lx %wZ\n",Status,&ProviderInfoName);
  737. RxAbbreviatedWriteLogEntry(Status);
  738. goto FINALLY;
  739. }
  740. Status = ZwQueryValueKey(NetworkProviderInfoHandle,
  741. &ParameterDeviceName,
  742. KeyValuePartialInformation,
  743. &UncProvider->Info,
  744. ProviderLength,
  745. &DummyBytesRead);
  746. if (Status!=STATUS_SUCCESS) {
  747. RxAbbreviatedWriteLogEntry(Status);
  748. goto FINALLY;
  749. }
  750. //
  751. // Finish filling in the UncProviderEntry and link it in
  752. UncProvider->Buffer = (PWCHAR)(&UncProvider->Info.Data[0]);
  753. UncProvider->Length = (USHORT)(UncProvider->Info.DataLength-sizeof(WCHAR)); //dont include trailing NULL
  754. UncProvider->MaximumLength = UncProvider->Length;
  755. UncProvider->Priority = Priority;
  756. InsertTailList(&RxUncProviders,&UncProvider->Links);
  757. RxLog(("Dvc p=%lx Nm %wZ",UncProvider->Priority,&UncProvider->DeviceName));
  758. RxWmiLog(LOG,
  759. RxAccrueProviderFromServiceName_2,
  760. LOGULONG(UncProvider->Priority)
  761. LOGUSTR(UncProvider->DeviceName));
  762. UncProvider = NULL;
  763. FINALLY:
  764. //
  765. // if we obtained a handle to ...\\services\<sevicename>\providerinfo then close it
  766. if (NetworkProviderInfoHandle!=INVALID_HANDLE_VALUE) ZwClose(NetworkProviderInfoHandle);
  767. if (UncProvider != NULL) {
  768. RxFreePool(UncProvider);
  769. }
  770. return Status;
  771. }
  772. NTSTATUS
  773. RxConstructProviderOrder(
  774. void
  775. )
  776. /*++
  777. Routine Description:
  778. This routine has the responsibility to build the list of network providers
  779. that is used to look up provider priority at minirdr registration time. It does this
  780. by first reading the providerorder string fron the registry; then for each provider
  781. listed in the string, a helper routine is called to lookup the corresponding device
  782. name and insert an entry on the provider list.
  783. Arguments:
  784. none.
  785. Return Value:
  786. STATUS_SUCCESS if everything worked elsewise an error status.
  787. --*/
  788. {
  789. KEY_VALUE_PARTIAL_INFORMATION InitialValuePartialInformation;
  790. UNICODE_STRING ProviderOrderValueName;
  791. ULONG DummyBytesRead;
  792. PBYTE ProviderOrderStringBuffer;
  793. PBYTE ServiceNameStringBuffer = NULL;
  794. ULONG ProviderOrderStringLength,ServiceNameStringLength,AllocationLength;
  795. UNICODE_STRING UnicodeString;
  796. UNICODE_STRING ProviderOrder;
  797. PWCHAR ScanPtr,FinalScanPtr;
  798. HANDLE NPOrderHandle = INVALID_HANDLE_VALUE;
  799. HANDLE ServiceRootHandle = INVALID_HANDLE_VALUE;
  800. NTSTATUS Status;
  801. OBJECT_ATTRIBUTES ObjectAttributes;
  802. ULONG Priority = 0;
  803. PAGED_CODE();
  804. RxLog(("RxConstructProviderOrder"));
  805. RxWmiLog(LOG,
  806. RxConstructProviderOrder_1,
  807. LOGULONG(Priority));
  808. InitializeListHead(&RxUncProviders);
  809. //
  810. // Start by opening the service registry key. This is the root key of all services
  811. // and is used for relative opens by the helper routine so that string manipulation
  812. // is reduced.
  813. RtlInitUnicodeString(&UnicodeString, SERVICE_REGISTRY_KEY);
  814. InitializeObjectAttributes(
  815. &ObjectAttributes,
  816. &UnicodeString, // name
  817. OBJ_CASE_INSENSITIVE, // attributes
  818. NULL, // root
  819. NULL // security descriptor
  820. );
  821. Status = ZwOpenKey (&ServiceRootHandle, KEY_READ, &ObjectAttributes);
  822. if (!NT_SUCCESS(Status)) {
  823. DbgPrint("ServiceRootOpenFailed: %08lx %wZ\n",Status,&UnicodeString);
  824. RxAbbreviatedWriteLogEntry(Status);
  825. goto FINALLY;
  826. }
  827. //
  828. // Now open up the key where we find the provider order string
  829. RtlInitUnicodeString(&UnicodeString, PROVIDERORDER_REGISTRY_KEY);
  830. InitializeObjectAttributes(
  831. &ObjectAttributes,
  832. &UnicodeString, // name
  833. OBJ_CASE_INSENSITIVE, // attributes
  834. NULL, // root
  835. NULL // security descriptor
  836. );
  837. Status = ZwOpenKey (&NPOrderHandle, KEY_READ, &ObjectAttributes);
  838. if (!NT_SUCCESS(Status)) {
  839. DbgPrint("NetProviderOpenFailed: %08lx %wZ\n",Status,&UnicodeString);
  840. RxAbbreviatedWriteLogEntry(Status);
  841. goto FINALLY;
  842. }
  843. //
  844. //Find out how long the provider order string is
  845. RtlInitUnicodeString(&ProviderOrderValueName, L"ProviderOrder");
  846. Status = ZwQueryValueKey(NPOrderHandle,
  847. &ProviderOrderValueName,
  848. KeyValuePartialInformation,
  849. &InitialValuePartialInformation,
  850. sizeof(InitialValuePartialInformation),
  851. &DummyBytesRead);
  852. if (Status==STATUS_BUFFER_OVERFLOW) {
  853. Status=STATUS_SUCCESS;
  854. }
  855. if (Status!=STATUS_SUCCESS) {
  856. DbgPrint("ProviderOrderStringPartialInfoFailed: %08lx %wZ\n",Status,&ProviderOrderValueName);
  857. RxAbbreviatedWriteLogEntry(Status);
  858. goto FINALLY;
  859. }
  860. //
  861. // allocate two buffers: one buffer will hold the provider string -- ProviderOrderStringBuffer.
  862. // it has to be as long as the providerorder string plus enough extra for the registry
  863. // structure used in the call. the second buffer is used to hold the servicename key--it has
  864. // to be as long as any element of the provider string plus enough extra to hold the suffix
  865. // NETWORK_PROVIDER_SUBKEY. in order to only parse the string once, we just allocate for a complete
  866. // additional copy of the provider string. we actually combine these into a single allocation.
  867. ProviderOrderStringLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + InitialValuePartialInformation.DataLength;
  868. ProviderOrderStringLength = QuadAlign(ProviderOrderStringLength +2*sizeof(WCHAR)); //chars added below
  869. ServiceNameStringLength = sizeof(NETWORK_PROVIDER_SUBKEY) + InitialValuePartialInformation.DataLength;
  870. ServiceNameStringLength = QuadAlign(ServiceNameStringLength);
  871. AllocationLength = ProviderOrderStringLength + ServiceNameStringLength;
  872. RxLog(("prov string=%lx,alloc=%lx\n",
  873. InitialValuePartialInformation.DataLength,
  874. AllocationLength));
  875. RxWmiLog(LOG,
  876. RxConstructProviderOrder_2,
  877. LOGULONG(InitialValuePartialInformation.DataLength)
  878. LOGULONG(AllocationLength));
  879. ServiceNameStringBuffer = RxAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,AllocationLength,RX_MRX_POOLTAG);
  880. if (ServiceNameStringBuffer==NULL) {
  881. Status = STATUS_INSUFFICIENT_RESOURCES;
  882. RxAbbreviatedWriteLogEntry(Status);
  883. goto FINALLY;
  884. }
  885. ProviderOrderStringBuffer = ServiceNameStringBuffer+ServiceNameStringLength;
  886. //
  887. // now do the final read to get the providerorder string
  888. RxGetStringRegistryParameter(NPOrderHandle,
  889. L"ProviderOrder",
  890. &ProviderOrder,
  891. (PKEY_VALUE_PARTIAL_INFORMATION) ProviderOrderStringBuffer,
  892. ProviderOrderStringLength,
  893. FALSE
  894. );
  895. if (ProviderOrder.Buffer == NULL) {
  896. Status = STATUS_UNSUCCESSFUL;
  897. RxAbbreviatedWriteLogEntry(Status);
  898. goto FINALLY;
  899. }
  900. //
  901. // comma-terminate the string for easier living. then scan down the string
  902. // looking for comma terminated entries. for each entry found, try to accrue
  903. // it to the list
  904. ProviderOrder.Buffer[ProviderOrder.Length/sizeof(WCHAR)] = L',';
  905. ScanPtr = ProviderOrder.Buffer;
  906. FinalScanPtr = ScanPtr+(ProviderOrder.Length/sizeof(WCHAR));
  907. for (;;) {
  908. UNICODE_STRING ServiceName;
  909. // check for loop termination
  910. if (ScanPtr >= FinalScanPtr) { break; }
  911. if (*ScanPtr==L',') { ScanPtr++; continue; }
  912. // parse for a servicename
  913. ServiceName.Buffer = ScanPtr;
  914. for (;*ScanPtr!=L',';ScanPtr++) {
  915. //DbgPrint("Considering %c\n",*ScanPtr);
  916. }
  917. ASSERT(*ScanPtr==L',');
  918. ServiceName.Length = (USHORT)(sizeof(WCHAR)*(ScanPtr - ServiceName.Buffer));
  919. //DbgPrint("Length %08lx\n",ServiceName.Length);
  920. //DbgPrint("ServiceName %wZ\n",&ServiceName);
  921. // accrue it to the list
  922. Priority++;
  923. Status = RxAccrueProviderFromServiceName(ServiceRootHandle,
  924. &ServiceName,
  925. Priority,
  926. (PWCHAR)ServiceNameStringBuffer,
  927. ServiceNameStringLength );
  928. if (Status == STATUS_INSUFFICIENT_RESOURCES) {
  929. goto FINALLY; //a log entry has already been generated
  930. } else {
  931. Status = STATUS_SUCCESS;
  932. }
  933. }
  934. FINALLY:
  935. //
  936. // give back anything that we got in this procedure
  937. if (NPOrderHandle!=INVALID_HANDLE_VALUE) ZwClose(NPOrderHandle);
  938. if (ServiceRootHandle!=INVALID_HANDLE_VALUE) ZwClose(ServiceRootHandle);
  939. if (ServiceNameStringBuffer!=NULL) RxFreePool(ServiceNameStringBuffer);
  940. //
  941. // if things didn't work, then we won't start....so give back
  942. // the stuff that we have
  943. if (!NT_SUCCESS(Status)) {
  944. RxDestructProviderOrder();
  945. }
  946. return Status;
  947. }
  948. VOID
  949. RxDestructProviderOrder(
  950. void
  951. )
  952. {
  953. PLIST_ENTRY Entry;
  954. PAGED_CODE();
  955. //DbgPrint("RxDestructProviderOrder \n");
  956. for (Entry = RxUncProviders.Flink;
  957. Entry != &RxUncProviders;
  958. ) {
  959. PRX_UNC_PROVIDER UncProvider = (PRX_UNC_PROVIDER)Entry;
  960. Entry = Entry->Flink;
  961. //DbgPrint("RxDO UncP %wZ p=%x\n",&UncProvider->DeviceName,UncProvider->Priority);
  962. RxFreePool(UncProvider);
  963. }
  964. return;
  965. }
  966. #else
  967. ULONG
  968. RxGetNetworkProviderPriority(
  969. PUNICODE_STRING DeviceName
  970. )
  971. {
  972. PAGED_CODE(); //DUPLICATE
  973. return(1); //this number is irrelevant for monolithic
  974. }
  975. #endif //#ifndef MONOLITHIC_MINIRDR
  976. NTSTATUS
  977. RxInitializeRegistrationStructures(
  978. void
  979. )
  980. {
  981. NTSTATUS Status = STATUS_SUCCESS;
  982. PAGED_CODE();
  983. ExInitializeFastMutex(&RxData.MinirdrRegistrationMutex);
  984. RxData.NumberOfMinirdrsRegistered = 0;
  985. RxData.NumberOfMinirdrsStarted = 0;
  986. InitializeListHead( &RxData.RegisteredMiniRdrs );
  987. #ifndef MONOLITHIC_MINIRDR
  988. Status = RxConstructProviderOrder();
  989. #endif
  990. return(Status);
  991. }
  992. VOID
  993. RxUninitializeRegistrationStructures(
  994. void
  995. )
  996. {
  997. PAGED_CODE();
  998. #ifndef MONOLITHIC_MINIRDR
  999. RxDestructProviderOrder();
  1000. #endif
  1001. }
  1002. VOID
  1003. RxInitializeMinirdrDispatchTable(
  1004. IN PDRIVER_OBJECT DriverObject
  1005. )
  1006. {
  1007. PAGED_CODE();
  1008. #ifndef MONOLITHIC_MINIRDR
  1009. {ULONG i;
  1010. //finally, fill in the dispatch tables for normal guys.........
  1011. for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
  1012. DriverObject->MajorFunction[i] = RxData.DriverObject->MajorFunction[i];
  1013. }}
  1014. DriverObject->FastIoDispatch = RxData.DriverObject->FastIoDispatch;
  1015. #endif
  1016. }
  1017. VOID
  1018. NTAPI
  1019. __RxFillAndInstallFastIoDispatch(
  1020. IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
  1021. IN OUT PFAST_IO_DISPATCH FastIoDispatch,
  1022. IN ULONG FastIoDispatchSize
  1023. )
  1024. /*++
  1025. Routine Description:
  1026. This routine fills out a fastiodispatch vector to be identical with
  1027. that normal one and installs it into the driver object associated with
  1028. the device object passed.
  1029. Arguments:
  1030. RxDeviceObject - the device object that is to have its driver's fastiodispatch changed
  1031. FastIoDispatch - the fastiodispatch table to fill in and use
  1032. FastIoDispatchSize - the size of the table passed
  1033. Return Value:
  1034. NONE
  1035. --*/
  1036. {
  1037. ULONG TableSize = min(FastIoDispatchSize,
  1038. RxFastIoDispatch.SizeOfFastIoDispatch);
  1039. PAGED_CODE();
  1040. #ifndef MONOLITHIC_MINIRDR
  1041. RtlCopyMemory(FastIoDispatch,&RxFastIoDispatch,TableSize);
  1042. FastIoDispatch->SizeOfFastIoDispatch = TableSize;
  1043. RxDeviceObject->DriverObject->FastIoDispatch = FastIoDispatch;
  1044. return;
  1045. #endif
  1046. }
  1047. VOID
  1048. RxReadRegistryParameters(
  1049. void
  1050. )
  1051. {
  1052. ULONG Storage[16];
  1053. UNICODE_STRING UnicodeString;
  1054. HANDLE ParametersHandle;
  1055. NTSTATUS Status;
  1056. OBJECT_ATTRIBUTES ObjectAttributes;
  1057. UNICODE_STRING WorkStationParametersRegistryKeyName;
  1058. PKEY_VALUE_PARTIAL_INFORMATION Value = (PKEY_VALUE_PARTIAL_INFORMATION)Storage;
  1059. ULONG ValueSize;
  1060. ULONG BytesRead;
  1061. PAGED_CODE(); //INIT
  1062. RtlInitUnicodeString(&WorkStationParametersRegistryKeyName,
  1063. LANMAN_WORKSTATION_PARAMETERS);
  1064. ValueSize = sizeof(Storage);
  1065. InitializeObjectAttributes(
  1066. &ObjectAttributes,
  1067. &WorkStationParametersRegistryKeyName, // name
  1068. OBJ_CASE_INSENSITIVE, // attributes
  1069. NULL, // root
  1070. NULL // security descriptor
  1071. );
  1072. Status = ZwOpenKey (&ParametersHandle, KEY_READ, &ObjectAttributes);
  1073. if (!NT_SUCCESS(Status)) {
  1074. //RxLogFailure (
  1075. // RxFileSystemDeviceObject,
  1076. // NULL,
  1077. // EVENT_RDR_CANT_READ_REGISTRY,
  1078. // Status);
  1079. return;
  1080. }
  1081. RtlInitUnicodeString(&UnicodeString, L"DisableByteRangeLockingOnReadOnlyFiles");
  1082. Status = ZwQueryValueKey(ParametersHandle,
  1083. &UnicodeString,
  1084. KeyValuePartialInformation,
  1085. Value,
  1086. ValueSize,
  1087. &BytesRead);
  1088. if (NT_SUCCESS(Status)) {
  1089. if (Value->Type == REG_DWORD) {
  1090. PULONG ConfigValue = (PULONG)&Value->Data[0];
  1091. DisableByteRangeLockingOnReadOnlyFiles =
  1092. (BOOLEAN) (*((PULONG)ConfigValue) != 0);
  1093. }
  1094. }
  1095. ZwClose(ParametersHandle);
  1096. }
  1097.