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.

1310 lines
34 KiB

  1. /*++
  2. Copyright(c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. bridge.c
  5. Abstract:
  6. Ethernet MAC level bridge.
  7. Author:
  8. Mark Aiken
  9. (original bridge by Jameel Hyder)
  10. Environment:
  11. Kernel mode driver
  12. Revision History:
  13. Sept 1999 - Original version
  14. Feb 2000 - Overhaul
  15. --*/
  16. #define NDIS_WDM 1
  17. #pragma warning( push, 3 )
  18. #include <ndis.h>
  19. #include <ntddk.h>
  20. #include <tdikrnl.h>
  21. #pragma warning( pop )
  22. #include "bridge.h"
  23. #include "brdgprot.h"
  24. #include "brdgmini.h"
  25. #include "brdgbuf.h"
  26. #include "brdgtbl.h"
  27. #include "brdgfwd.h"
  28. #include "brdgctl.h"
  29. #include "brdgsta.h"
  30. #include "brdgcomp.h"
  31. #include "brdgtdi.h"
  32. // ===========================================================================
  33. //
  34. // GLOBALS
  35. //
  36. // ===========================================================================
  37. // Our driver object
  38. PDRIVER_OBJECT gDriverObject;
  39. // Our registry path
  40. UNICODE_STRING gRegistryPath;
  41. // Size of the allocated memory at gRegistryPath->Buffer
  42. ULONG gRegistryPathBufferSize;
  43. // Whether we're in the process of shutting down (non-zero means true)
  44. LONG gShuttingDown = 0L;
  45. // Whether we successfully initialized each subsystem
  46. BOOLEAN gInitedSTA = FALSE;
  47. BOOLEAN gInitedControl = FALSE;
  48. BOOLEAN gInitedTbl = FALSE;
  49. BOOLEAN gInitedBuf = FALSE;
  50. BOOLEAN gInitedFwd = FALSE;
  51. BOOLEAN gInitedProt = FALSE;
  52. BOOLEAN gInitedMini = FALSE;
  53. BOOLEAN gInitedComp = FALSE;
  54. BOOLEAN gInitedTdiGpo = FALSE;
  55. extern BOOLEAN gBridging;
  56. const PWCHAR gDisableForwarding = L"DisableForwarding";
  57. #if DBG
  58. // Support for optional "soft asserts"
  59. BOOLEAN gSoftAssert = FALSE;
  60. // Fields used for printing current date and time in DBGPRINT
  61. LARGE_INTEGER gTime;
  62. const LARGE_INTEGER gCorrection = { 0xAC5ED800, 0x3A }; // 7 hours in 100-nanoseconds
  63. TIME_FIELDS gTimeFields;
  64. // Used for throttling debug messages that risk overloading the debugger console
  65. ULONG gLastThrottledPrint = 0L;
  66. // Spew flags
  67. ULONG gSpewFlags = 0L;
  68. // Name of registry value that holds the spew flags settings
  69. const PWCHAR gDebugFlagRegValueName = L"DebugFlags";
  70. // Used to bypass Tdi/Gpo code if it's breaking on startup.
  71. BOOLEAN gGpoTesting = TRUE;
  72. #endif
  73. // ===========================================================================
  74. //
  75. // PRIVATE DECLARATIONS
  76. //
  77. // ===========================================================================
  78. // Structure for deferring a function call
  79. typedef struct _DEFER_REC
  80. {
  81. NDIS_WORK_ITEM nwi;
  82. VOID (*pFunc)(PVOID); // The function to defer
  83. } DEFER_REC, *PDEFER_REC;
  84. // ===========================================================================
  85. //
  86. // LOCAL PROTOTYPES
  87. //
  88. // ===========================================================================
  89. NTSTATUS
  90. BrdgDispatchRequest(
  91. IN PDEVICE_OBJECT pDeviceObject,
  92. IN PIRP pIrp
  93. );
  94. NTSTATUS
  95. DriverEntry(
  96. IN PDRIVER_OBJECT DriverObject,
  97. IN PUNICODE_STRING RegistryPath
  98. );
  99. NTSTATUS
  100. BrdgAllocateBuffers(
  101. VOID
  102. );
  103. VOID
  104. BrdgDeferredShutdown(
  105. PVOID pUnused
  106. );
  107. VOID
  108. BrdgDoShutdown(
  109. VOID
  110. );
  111. // ===========================================================================
  112. //
  113. // PUBLIC FUNCTIONS
  114. //
  115. // ===========================================================================
  116. VOID
  117. BrdgDeferredFunction(
  118. IN PNDIS_WORK_ITEM pNwi,
  119. IN PVOID arg
  120. )
  121. /*++
  122. Routine Description:
  123. NDIS worker function for deferring a function call
  124. Arguments:
  125. pNwi Structure describing the function to call
  126. arg Argument to pass to the deferred function
  127. Return Value:
  128. None
  129. --*/
  130. {
  131. PDEFER_REC pdr = (PDEFER_REC)pNwi;
  132. // Call the originally supplied function
  133. (*pdr->pFunc)(arg);
  134. // Release the memory used to store the work item
  135. NdisFreeMemory( pdr, sizeof(DEFER_REC), 0 );
  136. }
  137. NDIS_STATUS
  138. BrdgDeferFunction(
  139. VOID (*pFunc)(PVOID),
  140. PVOID arg
  141. )
  142. /*++
  143. Routine Description:
  144. Defers the indicated function, calling it at low IRQL with the indicated argument.
  145. Arguments:
  146. pFunc The function to call later
  147. arg The argument to pass it when it is called
  148. Return Value:
  149. Status of the attempt to defer the function
  150. --*/
  151. {
  152. PDEFER_REC pdr;
  153. NDIS_STATUS Status;
  154. Status = NdisAllocateMemoryWithTag( &pdr, sizeof(DEFER_REC), 'gdrB' );
  155. if( Status != NDIS_STATUS_SUCCESS )
  156. {
  157. DBGPRINT(GENERAL, ("Allocation failed in BrdgDeferFunction(): %08x\n", Status));
  158. return Status;
  159. }
  160. SAFEASSERT( pdr != NULL );
  161. pdr->pFunc = pFunc;
  162. NdisInitializeWorkItem( &pdr->nwi, BrdgDeferredFunction, arg );
  163. Status = NdisScheduleWorkItem( &pdr->nwi );
  164. if( Status != NDIS_STATUS_SUCCESS )
  165. {
  166. NdisFreeMemory( pdr, sizeof(DEFER_REC), 0 );
  167. }
  168. return Status;
  169. }
  170. NTSTATUS
  171. DriverEntry(
  172. IN PDRIVER_OBJECT DriverObject,
  173. IN PUNICODE_STRING pRegistryPath
  174. )
  175. /*++
  176. Routine Description:
  177. Main driver entry point. Called at driver load time
  178. Arguments:
  179. DriverObject Our driver
  180. RegistryPath A reg key where we can keep parameters
  181. Return Value:
  182. Status of our initialization. A status != STATUS_SUCCESS aborts the
  183. driver load and we don't get called again.
  184. Each component is responsible for logging any error that causes the
  185. driver load to fail.
  186. --*/
  187. {
  188. NTSTATUS Status;
  189. NDIS_STATUS NdisStatus;
  190. PUCHAR pRegistryPathCopy;
  191. DBGPRINT(GENERAL, ("DriverEntry\n"));
  192. // Remember our driver object pointer
  193. gDriverObject = DriverObject;
  194. do
  195. {
  196. ULONG ulDisableForwarding = 0L;
  197. // Make a copy of our registry path
  198. pRegistryPathCopy = NULL;
  199. gRegistryPathBufferSize = pRegistryPath->Length + sizeof(WCHAR);
  200. NdisStatus = NdisAllocateMemoryWithTag( &pRegistryPathCopy, gRegistryPathBufferSize, 'gdrB' );
  201. if( (NdisStatus != NDIS_STATUS_SUCCESS) || (pRegistryPathCopy == NULL) )
  202. {
  203. DBGPRINT(GENERAL, ("Unable to allocate memory for saving the registry path: %08x\n", NdisStatus));
  204. NdisWriteEventLogEntry( gDriverObject, EVENT_BRIDGE_INIT_MALLOC_FAILED, 0, 0, NULL, 0L, NULL );
  205. Status = NdisStatus;
  206. // Make the structure valid even though we failed the malloc
  207. RtlInitUnicodeString( &gRegistryPath, NULL );
  208. gRegistryPathBufferSize = 0L;
  209. break;
  210. }
  211. // Copy the registry name
  212. NdisMoveMemory( pRegistryPathCopy, pRegistryPath->Buffer, pRegistryPath->Length );
  213. // Make sure it's NULL-terminated
  214. *((PWCHAR)(pRegistryPathCopy + pRegistryPath->Length)) = UNICODE_NULL;
  215. // Make the UNICODE_STRING structure point to the string
  216. RtlInitUnicodeString( &gRegistryPath, (PWCHAR)pRegistryPathCopy );
  217. // Set our debug flags
  218. #if DBG
  219. BrdgReadRegDWord(&gRegistryPath, gDebugFlagRegValueName, &gSpewFlags);
  220. #endif
  221. // Initialize the STA part of the driver
  222. Status = BrdgSTADriverInit();
  223. if( Status != STATUS_SUCCESS )
  224. {
  225. DBGPRINT(GENERAL, ("Unable to initialize STA functionality: %08x\n", Status));
  226. break;
  227. }
  228. gInitedSTA = TRUE;
  229. // Initialize the control part of the driver
  230. Status = BrdgCtlDriverInit();
  231. if( Status != STATUS_SUCCESS )
  232. {
  233. DBGPRINT(GENERAL, ("Unable to initialize user-mode control functionality: %08x\n", Status));
  234. break;
  235. }
  236. gInitedControl = TRUE;
  237. // Initialize the MAC table part of our driver
  238. Status = BrdgTblDriverInit();
  239. if( Status != STATUS_SUCCESS )
  240. {
  241. DBGPRINT(GENERAL, ("Unable to initialize MAC table functionality: %08x\n", Status));
  242. break;
  243. }
  244. gInitedTbl = TRUE;
  245. // Initialize the forwarding engine
  246. Status = BrdgFwdDriverInit();
  247. if( Status != STATUS_SUCCESS )
  248. {
  249. DBGPRINT(GENERAL, ("Unable to initialize forwarding engine functionality: %08x\n", Status));
  250. break;
  251. }
  252. gInitedFwd = TRUE;
  253. // Initialize the buffer management part of our driver
  254. Status = BrdgBufDriverInit();
  255. if( Status != STATUS_SUCCESS )
  256. {
  257. DBGPRINT(GENERAL, ("Unable to initialize miniport functionality: %08x\n", Status));
  258. break;
  259. }
  260. gInitedBuf = TRUE;
  261. // Initialize the miniport part of our driver
  262. Status = BrdgMiniDriverInit();
  263. if( Status != STATUS_SUCCESS )
  264. {
  265. DBGPRINT(GENERAL, ("Unable to initialize miniport functionality: %08x\n", Status));
  266. break;
  267. }
  268. gInitedMini = TRUE;
  269. // Initialize the protocol part of our driver
  270. Status = BrdgProtDriverInit();
  271. if( Status != STATUS_SUCCESS )
  272. {
  273. DBGPRINT(GENERAL, ("Unable to initialize protocol functionality: %08x\n", Status));
  274. break;
  275. }
  276. gInitedProt = TRUE;
  277. // Initialize the compatibility-mode code
  278. Status = BrdgCompDriverInit();
  279. if( Status != STATUS_SUCCESS )
  280. {
  281. DBGPRINT(GENERAL, ("Unable to initialize compatibility-mode functionality: %08x\n", Status));
  282. break;
  283. }
  284. gInitedComp = TRUE;
  285. Status = BrdgReadRegDWord(&gRegistryPath, gDisableForwarding, &ulDisableForwarding);
  286. if ((!NT_SUCCESS(Status) || !ulDisableForwarding))
  287. {
  288. //
  289. // Group policies are only in effect on Professional and up.
  290. //
  291. if (!BrdgIsRunningOnPersonal())
  292. {
  293. #if DBG
  294. if (gGpoTesting)
  295. {
  296. #endif
  297. // Initialize the tdi code
  298. Status = BrdgTdiDriverInit();
  299. if( Status != STATUS_SUCCESS )
  300. {
  301. DBGPRINT(GENERAL, ("Unable to initialize tdi functionality: %08x\n", Status));
  302. break;
  303. }
  304. gInitedTdiGpo = TRUE;
  305. #if DBG
  306. }
  307. #endif
  308. }
  309. else
  310. {
  311. gBridging = TRUE;
  312. }
  313. }
  314. // Associate the miniport to the protocol
  315. BrdgMiniAssociate();
  316. } while (FALSE);
  317. if (Status != STATUS_SUCCESS)
  318. {
  319. BrdgDoShutdown();
  320. }
  321. return(Status);
  322. }
  323. NTSTATUS
  324. BrdgDispatchRequest(
  325. IN PDEVICE_OBJECT pDeviceObject,
  326. IN PIRP pIrp
  327. )
  328. /*++
  329. Routine Description:
  330. Receives control requests from the outside
  331. Arguments:
  332. pDeviceObject Our driver
  333. pIrp The IRP to handle
  334. Return Value:
  335. Status of the operation
  336. --*/
  337. {
  338. PVOID Buffer;
  339. PIO_STACK_LOCATION IrpSp;
  340. ULONG Size = 0;
  341. NTSTATUS status = STATUS_SUCCESS;
  342. pIrp->IoStatus.Status = STATUS_SUCCESS;
  343. pIrp->IoStatus.Information = 0;
  344. Buffer = pIrp->AssociatedIrp.SystemBuffer;
  345. IrpSp = IoGetCurrentIrpStackLocation(pIrp);
  346. if( IrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL )
  347. {
  348. // Don't accept IRPs when we're shutting down
  349. if( gShuttingDown )
  350. {
  351. status = STATUS_UNSUCCESSFUL;
  352. pIrp->IoStatus.Information = 0;
  353. }
  354. else
  355. {
  356. status = BrdgCtlHandleIoDeviceControl( pIrp, IrpSp->FileObject, Buffer,
  357. IrpSp->Parameters.DeviceIoControl.InputBufferLength,
  358. IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
  359. IrpSp->Parameters.DeviceIoControl.IoControlCode, &Size );
  360. }
  361. }
  362. else
  363. {
  364. if( IrpSp->MajorFunction == IRP_MJ_CREATE )
  365. {
  366. BrdgCtlHandleCreate();
  367. }
  368. else if( IrpSp->MajorFunction == IRP_MJ_CLEANUP )
  369. {
  370. BrdgCtlHandleCleanup();
  371. }
  372. // Leave status == STATUS_SUCCESS and Size == 0
  373. }
  374. if( status != STATUS_PENDING )
  375. {
  376. pIrp->IoStatus.Information = Size;
  377. pIrp->IoStatus.Status = status;
  378. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  379. }
  380. return status;
  381. }
  382. VOID
  383. BrdgDeferredShutdown(
  384. PVOID pUnused
  385. )
  386. /*++
  387. Routine Description:
  388. Orderly-shutdown routine if we need to defer that task from high IRQL
  389. Arguments:
  390. pUnused Ignored
  391. Return Value:
  392. None
  393. --*/
  394. {
  395. BrdgDoShutdown();
  396. }
  397. VOID
  398. BrdgDoShutdown(
  399. VOID
  400. )
  401. /*++
  402. Routine Description:
  403. Called to do an orderly shutdown at unload time
  404. Arguments:
  405. None
  406. Return Value:
  407. None
  408. --*/
  409. {
  410. DBGPRINT(GENERAL, ("==> BrdgDoShutdown()!\n"));
  411. // Clean up each of the sections
  412. if ( gInitedTdiGpo )
  413. {
  414. gInitedTdiGpo = FALSE;
  415. BrdgTdiCleanup();
  416. }
  417. if( gInitedControl )
  418. {
  419. gInitedControl = FALSE;
  420. BrdgCtlCleanup();
  421. }
  422. if( gInitedProt )
  423. {
  424. gInitedProt = FALSE;
  425. BrdgProtCleanup();
  426. }
  427. // This needs to be cleaned up after the protocol section
  428. if( gInitedSTA )
  429. {
  430. gInitedSTA = FALSE;
  431. BrdgSTACleanup();
  432. }
  433. if( gInitedMini )
  434. {
  435. gInitedMini = FALSE;
  436. BrdgMiniCleanup();
  437. }
  438. if( gInitedTbl )
  439. {
  440. gInitedTbl = FALSE;
  441. BrdgTblCleanup();
  442. }
  443. if( gInitedBuf )
  444. {
  445. gInitedBuf = FALSE;
  446. BrdgBufCleanup();
  447. }
  448. if( gInitedFwd )
  449. {
  450. gInitedFwd = FALSE;
  451. BrdgFwdCleanup();
  452. }
  453. if( gInitedComp )
  454. {
  455. gInitedComp = FALSE;
  456. BrdgCompCleanup();
  457. }
  458. if( gRegistryPath.Buffer != NULL )
  459. {
  460. NdisFreeMemory( gRegistryPath.Buffer, gRegistryPathBufferSize, 0 );
  461. gRegistryPath.Buffer = NULL;
  462. }
  463. DBGPRINT(GENERAL, ("<== BrdgDoShutdown()\n"));
  464. }
  465. VOID
  466. BrdgUnload(
  467. IN PDRIVER_OBJECT DriverObject
  468. )
  469. /*++
  470. Routine Description:
  471. Called to indicate that we are being unloaded and to cause an orderly
  472. shutdown
  473. Arguments:
  474. DriverObject Our driver
  475. Return Value:
  476. None
  477. --*/
  478. {
  479. if( ! InterlockedExchange(&gShuttingDown, 1L) )
  480. {
  481. BrdgDoShutdown();
  482. }
  483. // else was already shutting down; do nothing
  484. }
  485. VOID BrdgShutdown(
  486. VOID
  487. )
  488. {
  489. if( ! InterlockedExchange(&gShuttingDown, 1L) )
  490. {
  491. BrdgDoShutdown();
  492. }
  493. // else was already shutting down; do nothing
  494. }
  495. NTSTATUS
  496. BrdgReadRegUnicode(
  497. IN PUNICODE_STRING KeyName,
  498. IN PWCHAR pValueName,
  499. OUT PWCHAR *String, // The string from the registry, freshly allocated
  500. OUT PULONG StringSize // Size of allocated memory at String
  501. )
  502. /*++
  503. Routine Description:
  504. Reads a Unicode string from a specific registry key and value. Allocates memory
  505. for the string and returns it.
  506. Arguments:
  507. KeyName The key holding the string
  508. pValueName The name of the value holding the string
  509. String A pointer to indicate a freshly allocated buffer containing
  510. the requested string on return
  511. StringSize Size of the returned buffer
  512. Return Value:
  513. Status of the operation. String is not valid if return != STATUS_SUCCESS
  514. --*/
  515. {
  516. NDIS_STATUS NdisStatus;
  517. HANDLE KeyHandle;
  518. OBJECT_ATTRIBUTES ObjAttrs;
  519. NTSTATUS Status;
  520. ULONG RequiredSize;
  521. KEY_VALUE_PARTIAL_INFORMATION *pInfo;
  522. UNICODE_STRING ValueName;
  523. // Turn the string into a UNICODE_STRING
  524. RtlInitUnicodeString( &ValueName, pValueName );
  525. // Describe the key to open
  526. InitializeObjectAttributes( &ObjAttrs, KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL );
  527. // Open it
  528. Status = ZwOpenKey( &KeyHandle, KEY_READ, &ObjAttrs );
  529. if( Status != STATUS_SUCCESS )
  530. {
  531. DBGPRINT(GENERAL, ("Failed to open registry key \"%ws\": %08x\n", KeyName->Buffer, Status));
  532. return Status;
  533. }
  534. // Find out how much memory is necessary to hold the value information
  535. Status = ZwQueryValueKey( KeyHandle, &ValueName, KeyValuePartialInformation, NULL,
  536. 0L, &RequiredSize );
  537. if( (Status != STATUS_BUFFER_OVERFLOW) &&
  538. (Status != STATUS_BUFFER_TOO_SMALL) )
  539. {
  540. DBGPRINT(GENERAL, ("Failed to query for the size of value \"%ws\": %08x\n", ValueName.Buffer, Status));
  541. ZwClose( KeyHandle );
  542. return Status;
  543. }
  544. // Allocate the indicated amount of memory
  545. NdisStatus = NdisAllocateMemoryWithTag( (PVOID*)&pInfo, RequiredSize, 'gdrB' );
  546. if( NdisStatus != NDIS_STATUS_SUCCESS )
  547. {
  548. DBGPRINT(GENERAL, ("NdisAllocateMemoryWithTag failed: %08x\n", NdisStatus));
  549. ZwClose( KeyHandle );
  550. return STATUS_UNSUCCESSFUL;
  551. }
  552. // Actually read out the string
  553. Status = ZwQueryValueKey( KeyHandle, &ValueName, KeyValuePartialInformation, pInfo,
  554. RequiredSize, &RequiredSize );
  555. ZwClose( KeyHandle );
  556. if( Status != STATUS_SUCCESS )
  557. {
  558. DBGPRINT(GENERAL, ("ZwQueryValueKey failed: %08x\n", Status));
  559. NdisFreeMemory( pInfo, RequiredSize, 0 );
  560. return Status;
  561. }
  562. // This had better be a Unicode string with something in it
  563. if( pInfo->Type != REG_SZ && pInfo->Type != REG_MULTI_SZ)
  564. {
  565. SAFEASSERT(FALSE);
  566. NdisFreeMemory( pInfo, RequiredSize, 0 );
  567. return STATUS_UNSUCCESSFUL;
  568. }
  569. // Allocate memory for the string
  570. *StringSize = pInfo->DataLength + sizeof(WCHAR);
  571. NdisStatus = NdisAllocateMemoryWithTag( (PVOID*)String, *StringSize, 'gdrB' );
  572. if( NdisStatus != NDIS_STATUS_SUCCESS )
  573. {
  574. DBGPRINT(GENERAL, ("NdisAllocateMemoryWithTag failed: %08x\n", NdisStatus));
  575. NdisFreeMemory( pInfo, RequiredSize, 0 );
  576. return STATUS_UNSUCCESSFUL;
  577. }
  578. SAFEASSERT( *String != NULL );
  579. // Copy the string to the freshly allocated memory
  580. NdisMoveMemory( *String, &pInfo->Data, pInfo->DataLength );
  581. // Put a two-byte NULL character at the end
  582. ((PUCHAR)*String)[pInfo->DataLength] = '0';
  583. ((PUCHAR)*String)[pInfo->DataLength + 1] = '0';
  584. // Let go of resources we used on the way
  585. NdisFreeMemory( pInfo, RequiredSize, 0 );
  586. return STATUS_SUCCESS;
  587. }
  588. NTSTATUS
  589. BrdgReadRegDWord(
  590. IN PUNICODE_STRING KeyName,
  591. IN PWCHAR pValueName,
  592. OUT PULONG Value
  593. )
  594. /*++
  595. Routine Description:
  596. Reads a DWORD value out of the registry
  597. Arguments:
  598. KeyName The name of the key holding the value
  599. pValueName The name of the value holding the value
  600. Value Receives the value
  601. Return Value:
  602. Status of the operation. Value is junk if return value != STATUS_SUCCESS
  603. --*/
  604. {
  605. HANDLE KeyHandle;
  606. OBJECT_ATTRIBUTES ObjAttrs;
  607. NTSTATUS Status;
  608. UCHAR InfoBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
  609. ULONG RequiredSize;
  610. UNICODE_STRING ValueName;
  611. // Turn the PWCHAR into a UNICODE_STRING
  612. RtlInitUnicodeString( &ValueName, pValueName );
  613. // Describe the key to open
  614. InitializeObjectAttributes( &ObjAttrs, KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL );
  615. // Open it
  616. Status = ZwOpenKey( &KeyHandle, KEY_READ, &ObjAttrs );
  617. if( Status != STATUS_SUCCESS )
  618. {
  619. DBGPRINT(GENERAL, ("Failed to open registry key \"%ws\": %08x\n", KeyName->Buffer, Status));
  620. return Status;
  621. }
  622. // Actually read out the value
  623. Status = ZwQueryValueKey( KeyHandle, &ValueName, KeyValuePartialInformation,
  624. (PKEY_VALUE_PARTIAL_INFORMATION)&InfoBuffer,
  625. sizeof(InfoBuffer), &RequiredSize );
  626. ZwClose( KeyHandle );
  627. if( Status != STATUS_SUCCESS )
  628. {
  629. DBGPRINT(GENERAL, ("ZwQueryValueKey failed: %08x\n", Status));
  630. return Status;
  631. }
  632. // This had better be a DWORD value
  633. if( (((PKEY_VALUE_PARTIAL_INFORMATION)&InfoBuffer)->Type != REG_DWORD) ||
  634. (((PKEY_VALUE_PARTIAL_INFORMATION)&InfoBuffer)->DataLength != sizeof(ULONG)) )
  635. {
  636. DBGPRINT(GENERAL, ("Registry parameter %ws not of the requested type!\n"));
  637. return STATUS_UNSUCCESSFUL;
  638. }
  639. *Value = *((PULONG)((PKEY_VALUE_PARTIAL_INFORMATION)&InfoBuffer)->Data);
  640. return STATUS_SUCCESS;
  641. }
  642. NTSTATUS
  643. BrdgOpenDevice (
  644. IN LPWSTR pDeviceNameStr,
  645. OUT PDEVICE_OBJECT *ppDeviceObject,
  646. OUT HANDLE *pFileHandle,
  647. OUT PFILE_OBJECT *ppFileObject
  648. )
  649. /*++
  650. Routine Description:
  651. Opens specified device driver (control channel) and returns a file object
  652. and a driver object. The caller should call BrdgCloseDevice() to shut
  653. down the connection when it's done.
  654. Arguments:
  655. DeviceNameStr device to open.
  656. pFileHandle Receives a file handle
  657. ppFileObject Receives a pointer to the file object
  658. ppDeviceObject Receives a pointer to the device object
  659. Return Value:
  660. NTSTATUS -- Indicates whether the device was opened OK
  661. --*/
  662. {
  663. NTSTATUS status;
  664. UNICODE_STRING DeviceName;
  665. OBJECT_ATTRIBUTES objectAttributes;
  666. IO_STATUS_BLOCK iosb;
  667. // We make calls that can only be performed at PASSIVE_LEVEL.
  668. SAFEASSERT( CURRENT_IRQL <= PASSIVE_LEVEL );
  669. RtlInitUnicodeString(&DeviceName, pDeviceNameStr);
  670. InitializeObjectAttributes(
  671. &objectAttributes,
  672. &DeviceName,
  673. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, // attributes
  674. NULL,
  675. NULL
  676. );
  677. status = IoCreateFile(
  678. pFileHandle,
  679. MAXIMUM_ALLOWED,
  680. &objectAttributes,
  681. &iosb, // returned status information.
  682. 0, // block size (unused).
  683. 0, // file attributes.
  684. FILE_SHARE_READ | FILE_SHARE_WRITE,
  685. FILE_CREATE, // create disposition.
  686. 0, // create options.
  687. NULL, // eaInfo
  688. 0, // eaLength
  689. CreateFileTypeNone, // CreateFileType
  690. NULL, // ExtraCreateParameters
  691. IO_NO_PARAMETER_CHECKING // Options
  692. | IO_FORCE_ACCESS_CHECK
  693. );
  694. if (NT_SUCCESS(status))
  695. {
  696. status = ObReferenceObjectByHandle (
  697. *pFileHandle,
  698. 0L,
  699. *IoFileObjectType,
  700. KernelMode,
  701. (PVOID *)ppFileObject,
  702. NULL
  703. );
  704. if (! NT_SUCCESS(status))
  705. {
  706. DBGPRINT(ALWAYS_PRINT, ("ObReferenceObjectByHandle FAILED while opening a device: %8x\n", status));
  707. ZwClose (*pFileHandle);
  708. }
  709. else
  710. {
  711. // Recover the driver object
  712. *ppDeviceObject = IoGetRelatedDeviceObject ( *ppFileObject );
  713. SAFEASSERT( *ppDeviceObject != NULL );
  714. // Reference the driver handle, too.
  715. ObReferenceObject( *ppDeviceObject );
  716. }
  717. }
  718. else
  719. {
  720. DBGPRINT(ALWAYS_PRINT, ("IoCreateFile FAILED while opening a device: %8x\n", status));
  721. }
  722. return status;
  723. }
  724. VOID
  725. BrdgCloseDevice(
  726. IN HANDLE FileHandle,
  727. IN PFILE_OBJECT pFileObject,
  728. IN PDEVICE_OBJECT pDeviceObject
  729. )
  730. /*++
  731. Routine Description:
  732. Closes a device
  733. Arguments:
  734. FileHandle The file handle
  735. pFileObject The file object of the device
  736. pDeviceObject The device object of the device
  737. Return Value:
  738. None
  739. --*/
  740. {
  741. NTSTATUS status;
  742. // We make calls that can only be performed at PASSIVE_LEVEL.
  743. SAFEASSERT( CURRENT_IRQL <= PASSIVE_LEVEL );
  744. ObDereferenceObject( pFileObject );
  745. ObDereferenceObject( pDeviceObject );
  746. status = ZwClose( FileHandle );
  747. SAFEASSERT( NT_SUCCESS(status) );
  748. }
  749. VOID
  750. BrdgTimerExpiry(
  751. IN PVOID ignored1,
  752. IN PVOID data,
  753. IN PVOID ignored2,
  754. IN PVOID ignored3
  755. )
  756. /*++
  757. Routine Description:
  758. Master device expiry function. Calls a timer-specific expiry
  759. function if one was specified for this timer.
  760. Arguments:
  761. data The timer pointer
  762. Return Value:
  763. None
  764. --*/
  765. {
  766. PBRIDGE_TIMER pTimer = (PBRIDGE_TIMER)data;
  767. NdisAcquireSpinLock( &pTimer->Lock );
  768. SAFEASSERT( pTimer->bRunning );
  769. if( pTimer->bCancelPending )
  770. {
  771. // This is the rare codepath where a call to NdisCancelTimer() was unable to
  772. // dequeue our timer entry because we were about to be called.
  773. DBGPRINT(GENERAL, ("Timer expiry function called with cancelled timer!\n"));
  774. // Don't call the timer function; just bail out
  775. pTimer->bRunning = FALSE;
  776. pTimer->bCancelPending = FALSE;
  777. NdisReleaseSpinLock( &pTimer->Lock );
  778. // Unblock BrdgShutdownTimer()
  779. NdisSetEvent( &pTimer->Event );
  780. }
  781. else
  782. {
  783. BOOLEAN bRecurring;
  784. UINT interval;
  785. // Read protected values inside the lock
  786. bRecurring = pTimer->bRecurring;
  787. interval = pTimer->Interval;
  788. // Update bRunning inside the spin lock
  789. pTimer->bRunning = bRecurring;
  790. NdisReleaseSpinLock( &pTimer->Lock );
  791. // Call the timer function
  792. (*pTimer->pFunc)(pTimer->data);
  793. if( bRecurring )
  794. {
  795. // Start it up again
  796. NdisSetTimer( &pTimer->Timer, interval );
  797. }
  798. }
  799. }
  800. VOID
  801. BrdgInitializeTimer(
  802. IN PBRIDGE_TIMER pTimer,
  803. IN PBRIDGE_TIMER_FUNC pFunc,
  804. IN PVOID data
  805. )
  806. /*++
  807. Routine Description:
  808. Sets up a BRIDGE_TIMER.
  809. Arguments:
  810. pTimer The timer
  811. pFunc Expiry function
  812. data Cookie to pass to pFunc
  813. Return Value:
  814. None
  815. --*/
  816. {
  817. pTimer->bShuttingDown = FALSE;
  818. pTimer->bRunning = FALSE;
  819. pTimer->bCancelPending = FALSE;
  820. pTimer->pFunc = pFunc;
  821. pTimer->data = data;
  822. NdisInitializeTimer( &pTimer->Timer, BrdgTimerExpiry, (PVOID)pTimer );
  823. NdisInitializeEvent( &pTimer->Event );
  824. NdisResetEvent( &pTimer->Event );
  825. NdisAllocateSpinLock( &pTimer->Lock );
  826. // Leave pTimer->bRecurring alone; it gets a value when the timer is started.
  827. }
  828. VOID
  829. BrdgSetTimer(
  830. IN PBRIDGE_TIMER pTimer,
  831. IN UINT interval,
  832. IN BOOLEAN bRecurring
  833. )
  834. /*++
  835. Routine Description:
  836. Starts a BRIDGE_TIMER ticking.
  837. Arguments:
  838. pTimer The timer
  839. interval Time before expiry in ms
  840. bRecurring TRUE to restart the timer when it expires
  841. Return Value:
  842. None
  843. --*/
  844. {
  845. NdisAcquireSpinLock( &pTimer->Lock );
  846. if( !pTimer->bShuttingDown && !pTimer->bCancelPending )
  847. {
  848. pTimer->bRunning = TRUE;
  849. pTimer->bCancelPending = FALSE;
  850. pTimer->Interval = interval;
  851. pTimer->bRecurring = bRecurring;
  852. NdisReleaseSpinLock( &pTimer->Lock );
  853. // Actually start the timer
  854. NdisSetTimer( &pTimer->Timer, interval );
  855. }
  856. else
  857. {
  858. NdisReleaseSpinLock( &pTimer->Lock );
  859. if (pTimer->bShuttingDown)
  860. {
  861. DBGPRINT(ALWAYS_PRINT, ("WARNING: Ignoring an attempt to restart a timer in final shutdown!\n"));
  862. }
  863. }
  864. }
  865. VOID
  866. BrdgShutdownTimer(
  867. IN PBRIDGE_TIMER pTimer
  868. )
  869. /*++
  870. Routine Description:
  871. Safely shuts down a timer, waiting to make sure that the timer has been
  872. completely dequeued or its expiry function has started executing (there
  873. is no way to guarantee that the expiry function is completely done
  874. executing, however).
  875. Must be called at PASSIVE_LEVEL.
  876. Arguments:
  877. pTimer The timer
  878. Return Value:
  879. None
  880. --*/
  881. {
  882. // We wait on an event
  883. SAFEASSERT( CURRENT_IRQL <= PASSIVE_LEVEL );
  884. NdisAcquireSpinLock( &pTimer->Lock );
  885. // Forbid future calls to BrdgSetTimer().
  886. pTimer->bShuttingDown = TRUE;
  887. if( pTimer->bRunning && !pTimer->bCancelPending)
  888. {
  889. BOOLEAN bCanceled;
  890. // Make sure the timer expiry function will bail out if it's too late to
  891. // dequeue the timer and it ends up getting called
  892. pTimer->bCancelPending = TRUE;
  893. // This will unblock the timer expiry function, but even if it executes
  894. // between now and the call to NdisCancelTimer, it should still end up
  895. // signalling the event we will wait on below.
  896. NdisReleaseSpinLock( &pTimer->Lock );
  897. // Try to cancel the timer.
  898. NdisCancelTimer( &pTimer->Timer, &bCanceled );
  899. if( !bCanceled )
  900. {
  901. //
  902. // bCancelled can be FALSE if the timer wasn't running in the first place,
  903. // or if the OS couldn't dequeue the timer (but our expiry function will
  904. // still be called). Our use of our timer structure's spin lock should
  905. // guarantee that the timer expiry function will be executed after we
  906. // released the spin lock above, if we are on this code path. This means
  907. // that the event we wait on below will be signalled by the timer expiry
  908. // function.
  909. //
  910. DBGPRINT(GENERAL, ("Couldn't dequeue timer; blocking on completion\n"));
  911. // Wait for the completion function to finish its work
  912. NdisWaitEvent( &pTimer->Event, 0 /*Wait forever*/ );
  913. // The completion function should have cleared this
  914. SAFEASSERT( !pTimer->bRunning );
  915. }
  916. else
  917. {
  918. pTimer->bRunning = FALSE;
  919. pTimer->bCancelPending = FALSE;
  920. }
  921. }
  922. else
  923. {
  924. // Tried to shutdown a timer that was not running, or is going to be cancelled soon. This is allowed (it does nothing).
  925. NdisReleaseSpinLock( &pTimer->Lock );
  926. }
  927. }
  928. VOID
  929. BrdgCancelTimer(
  930. IN PBRIDGE_TIMER pTimer
  931. )
  932. /*++
  933. Routine Description:
  934. Attempts to cancel a timer, but provides no guarantee that the timer is
  935. actually stopped on return. It is possible for the timer expiry function
  936. to fire after this function returns.
  937. Arguments:
  938. pTimer The timer
  939. Return Value:
  940. None.
  941. --*/
  942. {
  943. NdisAcquireSpinLock( &pTimer->Lock );
  944. if( pTimer->bRunning && !pTimer->bCancelPending)
  945. {
  946. BOOLEAN bCanceled;
  947. NdisCancelTimer( &pTimer->Timer, &bCanceled );
  948. if( bCanceled )
  949. {
  950. pTimer->bRunning = FALSE;
  951. }
  952. else
  953. {
  954. // Reset this so that BrdgShutdownTimer will block.
  955. NdisResetEvent(&pTimer->Event);
  956. pTimer->bCancelPending = TRUE;
  957. }
  958. // else timer expiry function will set bRunning to FALSE when it completes.
  959. }
  960. // else tried to cancel a timer that was not running. This is allowed (it does nothing).
  961. NdisReleaseSpinLock( &pTimer->Lock );
  962. }
  963. BOOLEAN
  964. BrdgIsRunningOnPersonal(
  965. VOID
  966. )
  967. /*++
  968. Routine Description:
  969. Determines if we're running on a Personal build.
  970. Arguments:
  971. None.
  972. Return Value:
  973. TRUE if we're on Personal, FALSE if we're not.
  974. --*/
  975. {
  976. OSVERSIONINFOEXW OsVer = {0};
  977. ULONGLONG ConditionMask = 0;
  978. BOOLEAN IsPersonal = TRUE;
  979. OsVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  980. OsVer.wSuiteMask = VER_SUITE_PERSONAL;
  981. OsVer.wProductType = VER_NT_WORKSTATION;
  982. VER_SET_CONDITION(ConditionMask, VER_PRODUCT_TYPE, VER_EQUAL);
  983. VER_SET_CONDITION(ConditionMask, VER_SUITENAME, VER_AND);
  984. if (RtlVerifyVersionInfo(&OsVer, VER_PRODUCT_TYPE | VER_SUITENAME,
  985. ConditionMask) == STATUS_REVISION_MISMATCH) {
  986. IsPersonal = FALSE;
  987. }
  988. return IsPersonal;
  989. }