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.

1299 lines
32 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. Status = STATUS_SUCCESS;
  313. }
  314. }
  315. // Associate the miniport to the protocol
  316. BrdgMiniAssociate();
  317. } while (FALSE);
  318. if (Status != STATUS_SUCCESS)
  319. {
  320. BrdgDoShutdown();
  321. }
  322. return(Status);
  323. }
  324. NTSTATUS
  325. BrdgDispatchRequest(
  326. IN PDEVICE_OBJECT pDeviceObject,
  327. IN PIRP pIrp
  328. )
  329. /*++
  330. Routine Description:
  331. Receives control requests from the outside
  332. Arguments:
  333. pDeviceObject Our driver
  334. pIrp The IRP to handle
  335. Return Value:
  336. Status of the operation
  337. --*/
  338. {
  339. PVOID Buffer;
  340. PIO_STACK_LOCATION IrpSp;
  341. ULONG Size = 0;
  342. NTSTATUS status = STATUS_SUCCESS;
  343. pIrp->IoStatus.Status = STATUS_SUCCESS;
  344. pIrp->IoStatus.Information = 0;
  345. Buffer = pIrp->AssociatedIrp.SystemBuffer;
  346. IrpSp = IoGetCurrentIrpStackLocation(pIrp);
  347. if( IrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL )
  348. {
  349. // Don't accept IRPs when we're shutting down
  350. if( gShuttingDown )
  351. {
  352. status = STATUS_UNSUCCESSFUL;
  353. pIrp->IoStatus.Information = 0;
  354. }
  355. else
  356. {
  357. status = BrdgCtlHandleIoDeviceControl( pIrp, IrpSp->FileObject, Buffer,
  358. IrpSp->Parameters.DeviceIoControl.InputBufferLength,
  359. IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
  360. IrpSp->Parameters.DeviceIoControl.IoControlCode, &Size );
  361. }
  362. }
  363. else
  364. {
  365. if( IrpSp->MajorFunction == IRP_MJ_CREATE )
  366. {
  367. BrdgCtlHandleCreate();
  368. }
  369. else if( IrpSp->MajorFunction == IRP_MJ_CLEANUP )
  370. {
  371. BrdgCtlHandleCleanup();
  372. }
  373. // Leave status == STATUS_SUCCESS and Size == 0
  374. }
  375. if( status != STATUS_PENDING )
  376. {
  377. pIrp->IoStatus.Information = Size;
  378. pIrp->IoStatus.Status = status;
  379. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  380. }
  381. return status;
  382. }
  383. VOID
  384. BrdgDeferredShutdown(
  385. PVOID pUnused
  386. )
  387. /*++
  388. Routine Description:
  389. Orderly-shutdown routine if we need to defer that task from high IRQL
  390. Arguments:
  391. pUnused Ignored
  392. Return Value:
  393. None
  394. --*/
  395. {
  396. BrdgDoShutdown();
  397. }
  398. VOID
  399. BrdgDoShutdown(
  400. VOID
  401. )
  402. /*++
  403. Routine Description:
  404. Called to do an orderly shutdown at unload time
  405. Arguments:
  406. None
  407. Return Value:
  408. None
  409. --*/
  410. {
  411. DBGPRINT(GENERAL, ("==> BrdgDoShutdown()!\n"));
  412. // Clean up each of the sections
  413. if ( gInitedTdiGpo )
  414. {
  415. gInitedTdiGpo = FALSE;
  416. BrdgTdiCleanup();
  417. }
  418. if( gInitedControl )
  419. {
  420. gInitedControl = FALSE;
  421. BrdgCtlCleanup();
  422. }
  423. if( gInitedProt )
  424. {
  425. gInitedProt = FALSE;
  426. BrdgProtCleanup();
  427. }
  428. // This needs to be cleaned up after the protocol section
  429. if( gInitedSTA )
  430. {
  431. gInitedSTA = FALSE;
  432. BrdgSTACleanup();
  433. }
  434. if( gInitedMini )
  435. {
  436. gInitedMini = FALSE;
  437. BrdgMiniCleanup();
  438. }
  439. if( gInitedTbl )
  440. {
  441. gInitedTbl = FALSE;
  442. BrdgTblCleanup();
  443. }
  444. if( gInitedBuf )
  445. {
  446. gInitedBuf = FALSE;
  447. BrdgBufCleanup();
  448. }
  449. if( gInitedFwd )
  450. {
  451. gInitedFwd = FALSE;
  452. BrdgFwdCleanup();
  453. }
  454. if( gInitedComp )
  455. {
  456. gInitedComp = FALSE;
  457. BrdgCompCleanup();
  458. }
  459. if( gRegistryPath.Buffer != NULL )
  460. {
  461. NdisFreeMemory( gRegistryPath.Buffer, gRegistryPathBufferSize, 0 );
  462. gRegistryPath.Buffer = NULL;
  463. }
  464. DBGPRINT(GENERAL, ("<== BrdgDoShutdown()\n"));
  465. }
  466. VOID
  467. BrdgUnload(
  468. IN PDRIVER_OBJECT DriverObject
  469. )
  470. /*++
  471. Routine Description:
  472. Called to indicate that we are being unloaded and to cause an orderly
  473. shutdown
  474. Arguments:
  475. DriverObject Our driver
  476. Return Value:
  477. None
  478. --*/
  479. {
  480. if( ! InterlockedExchange(&gShuttingDown, 1L) )
  481. {
  482. BrdgDoShutdown();
  483. }
  484. // else was already shutting down; do nothing
  485. }
  486. VOID BrdgShutdown(
  487. VOID
  488. )
  489. {
  490. if( ! InterlockedExchange(&gShuttingDown, 1L) )
  491. {
  492. BrdgDoShutdown();
  493. }
  494. // else was already shutting down; do nothing
  495. }
  496. NTSTATUS
  497. BrdgReadRegUnicode(
  498. IN PUNICODE_STRING KeyName,
  499. IN PWCHAR pValueName,
  500. OUT PWCHAR *String, // The string from the registry, freshly allocated
  501. OUT PULONG StringSize // Size of allocated memory at String
  502. )
  503. /*++
  504. Routine Description:
  505. Reads a Unicode string from a specific registry key and value. Allocates memory
  506. for the string and returns it.
  507. Arguments:
  508. KeyName The key holding the string
  509. pValueName The name of the value holding the string
  510. String A pointer to indicate a freshly allocated buffer containing
  511. the requested string on return
  512. StringSize Size of the returned buffer
  513. Return Value:
  514. Status of the operation. String is not valid if return != STATUS_SUCCESS
  515. --*/
  516. {
  517. NDIS_STATUS NdisStatus;
  518. HANDLE KeyHandle;
  519. OBJECT_ATTRIBUTES ObjAttrs;
  520. NTSTATUS Status;
  521. ULONG RequiredSize;
  522. KEY_VALUE_PARTIAL_INFORMATION *pInfo;
  523. UNICODE_STRING ValueName;
  524. // Turn the string into a UNICODE_STRING
  525. RtlInitUnicodeString( &ValueName, pValueName );
  526. // Describe the key to open
  527. InitializeObjectAttributes( &ObjAttrs, KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL );
  528. // Open it
  529. Status = ZwOpenKey( &KeyHandle, KEY_READ, &ObjAttrs );
  530. if( Status != STATUS_SUCCESS )
  531. {
  532. DBGPRINT(GENERAL, ("Failed to open registry key \"%ws\": %08x\n", KeyName->Buffer, Status));
  533. return Status;
  534. }
  535. // Find out how much memory is necessary to hold the value information
  536. Status = ZwQueryValueKey( KeyHandle, &ValueName, KeyValuePartialInformation, NULL,
  537. 0L, &RequiredSize );
  538. if( (Status != STATUS_BUFFER_OVERFLOW) &&
  539. (Status != STATUS_BUFFER_TOO_SMALL) )
  540. {
  541. DBGPRINT(GENERAL, ("Failed to query for the size of value \"%ws\": %08x\n", ValueName.Buffer, Status));
  542. ZwClose( KeyHandle );
  543. return Status;
  544. }
  545. // Allocate the indicated amount of memory
  546. NdisStatus = NdisAllocateMemoryWithTag( (PVOID*)&pInfo, RequiredSize, 'gdrB' );
  547. if( NdisStatus != NDIS_STATUS_SUCCESS )
  548. {
  549. DBGPRINT(GENERAL, ("NdisAllocateMemoryWithTag failed: %08x\n", NdisStatus));
  550. ZwClose( KeyHandle );
  551. return STATUS_UNSUCCESSFUL;
  552. }
  553. // Actually read out the string
  554. Status = ZwQueryValueKey( KeyHandle, &ValueName, KeyValuePartialInformation, pInfo,
  555. RequiredSize, &RequiredSize );
  556. ZwClose( KeyHandle );
  557. if( Status != STATUS_SUCCESS )
  558. {
  559. DBGPRINT(GENERAL, ("ZwQueryValueKey failed: %08x\n", Status));
  560. NdisFreeMemory( pInfo, RequiredSize, 0 );
  561. return Status;
  562. }
  563. // This had better be a Unicode string with something in it
  564. if( pInfo->Type != REG_SZ && pInfo->Type != REG_MULTI_SZ)
  565. {
  566. SAFEASSERT(FALSE);
  567. NdisFreeMemory( pInfo, RequiredSize, 0 );
  568. return STATUS_UNSUCCESSFUL;
  569. }
  570. // Allocate memory for the string
  571. *StringSize = pInfo->DataLength + sizeof(WCHAR);
  572. NdisStatus = NdisAllocateMemoryWithTag( (PVOID*)String, *StringSize, 'gdrB' );
  573. if( NdisStatus != NDIS_STATUS_SUCCESS )
  574. {
  575. DBGPRINT(GENERAL, ("NdisAllocateMemoryWithTag failed: %08x\n", NdisStatus));
  576. NdisFreeMemory( pInfo, RequiredSize, 0 );
  577. return STATUS_UNSUCCESSFUL;
  578. }
  579. SAFEASSERT( *String != NULL );
  580. // Copy the string to the freshly allocated memory
  581. NdisMoveMemory( *String, &pInfo->Data, pInfo->DataLength );
  582. // Put a two-byte NULL character at the end
  583. ((PUCHAR)*String)[pInfo->DataLength] = '0';
  584. ((PUCHAR)*String)[pInfo->DataLength + 1] = '0';
  585. // Let go of resources we used on the way
  586. NdisFreeMemory( pInfo, RequiredSize, 0 );
  587. return STATUS_SUCCESS;
  588. }
  589. NTSTATUS
  590. BrdgReadRegDWord(
  591. IN PUNICODE_STRING KeyName,
  592. IN PWCHAR pValueName,
  593. OUT PULONG Value
  594. )
  595. /*++
  596. Routine Description:
  597. Reads a DWORD value out of the registry
  598. Arguments:
  599. KeyName The name of the key holding the value
  600. pValueName The name of the value holding the value
  601. Value Receives the value
  602. Return Value:
  603. Status of the operation. Value is junk if return value != STATUS_SUCCESS
  604. --*/
  605. {
  606. HANDLE KeyHandle;
  607. OBJECT_ATTRIBUTES ObjAttrs;
  608. NTSTATUS Status;
  609. UCHAR InfoBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
  610. ULONG RequiredSize;
  611. UNICODE_STRING ValueName;
  612. // Turn the PWCHAR into a UNICODE_STRING
  613. RtlInitUnicodeString( &ValueName, pValueName );
  614. // Describe the key to open
  615. InitializeObjectAttributes( &ObjAttrs, KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL );
  616. // Open it
  617. Status = ZwOpenKey( &KeyHandle, KEY_READ, &ObjAttrs );
  618. if( Status != STATUS_SUCCESS )
  619. {
  620. DBGPRINT(GENERAL, ("Failed to open registry key \"%ws\": %08x\n", KeyName->Buffer, Status));
  621. return Status;
  622. }
  623. // Actually read out the value
  624. Status = ZwQueryValueKey( KeyHandle, &ValueName, KeyValuePartialInformation,
  625. (PKEY_VALUE_PARTIAL_INFORMATION)&InfoBuffer,
  626. sizeof(InfoBuffer), &RequiredSize );
  627. ZwClose( KeyHandle );
  628. if( Status != STATUS_SUCCESS )
  629. {
  630. DBGPRINT(GENERAL, ("ZwQueryValueKey failed: %08x\n", Status));
  631. return Status;
  632. }
  633. // This had better be a DWORD value
  634. if( (((PKEY_VALUE_PARTIAL_INFORMATION)&InfoBuffer)->Type != REG_DWORD) ||
  635. (((PKEY_VALUE_PARTIAL_INFORMATION)&InfoBuffer)->DataLength != sizeof(ULONG)) )
  636. {
  637. DBGPRINT(GENERAL, ("Registry parameter %ws not of the requested type!\n"));
  638. return STATUS_UNSUCCESSFUL;
  639. }
  640. *Value = *((PULONG)((PKEY_VALUE_PARTIAL_INFORMATION)&InfoBuffer)->Data);
  641. return STATUS_SUCCESS;
  642. }
  643. NTSTATUS
  644. BrdgOpenDevice (
  645. IN LPWSTR pDeviceNameStr,
  646. OUT PDEVICE_OBJECT *ppDeviceObject,
  647. OUT HANDLE *pFileHandle,
  648. OUT PFILE_OBJECT *ppFileObject
  649. )
  650. /*++
  651. Routine Description:
  652. Opens specified device driver (control channel) and returns a file object
  653. and a driver object. The caller should call BrdgCloseDevice() to shut
  654. down the connection when it's done.
  655. Arguments:
  656. DeviceNameStr device to open.
  657. pFileHandle Receives a file handle
  658. ppFileObject Receives a pointer to the file object
  659. ppDeviceObject Receives a pointer to the device object
  660. Return Value:
  661. NTSTATUS -- Indicates whether the device was opened OK
  662. --*/
  663. {
  664. NTSTATUS status;
  665. UNICODE_STRING DeviceName;
  666. OBJECT_ATTRIBUTES objectAttributes;
  667. IO_STATUS_BLOCK iosb;
  668. // We make calls that can only be performed at PASSIVE_LEVEL.
  669. SAFEASSERT( CURRENT_IRQL <= PASSIVE_LEVEL );
  670. RtlInitUnicodeString(&DeviceName, pDeviceNameStr);
  671. InitializeObjectAttributes(
  672. &objectAttributes,
  673. &DeviceName,
  674. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, // attributes
  675. NULL,
  676. NULL
  677. );
  678. status = IoCreateFile(
  679. pFileHandle,
  680. MAXIMUM_ALLOWED,
  681. &objectAttributes,
  682. &iosb, // returned status information.
  683. 0, // block size (unused).
  684. 0, // file attributes.
  685. FILE_SHARE_READ | FILE_SHARE_WRITE,
  686. FILE_CREATE, // create disposition.
  687. 0, // create options.
  688. NULL, // eaInfo
  689. 0, // eaLength
  690. CreateFileTypeNone, // CreateFileType
  691. NULL, // ExtraCreateParameters
  692. IO_NO_PARAMETER_CHECKING // Options
  693. | IO_FORCE_ACCESS_CHECK
  694. );
  695. if (NT_SUCCESS(status))
  696. {
  697. status = ObReferenceObjectByHandle (
  698. *pFileHandle,
  699. 0L,
  700. *IoFileObjectType,
  701. KernelMode,
  702. (PVOID *)ppFileObject,
  703. NULL
  704. );
  705. if (! NT_SUCCESS(status))
  706. {
  707. DBGPRINT(ALWAYS_PRINT, ("ObReferenceObjectByHandle FAILED while opening a device: %8x\n", status));
  708. ZwClose (*pFileHandle);
  709. }
  710. else
  711. {
  712. // Recover the driver object
  713. *ppDeviceObject = IoGetRelatedDeviceObject ( *ppFileObject );
  714. SAFEASSERT( *ppDeviceObject != NULL );
  715. // Reference the driver handle, too.
  716. ObReferenceObject( *ppDeviceObject );
  717. }
  718. }
  719. else
  720. {
  721. DBGPRINT(ALWAYS_PRINT, ("IoCreateFile FAILED while opening a device: %8x\n", status));
  722. }
  723. return status;
  724. }
  725. VOID
  726. BrdgCloseDevice(
  727. IN HANDLE FileHandle,
  728. IN PFILE_OBJECT pFileObject,
  729. IN PDEVICE_OBJECT pDeviceObject
  730. )
  731. /*++
  732. Routine Description:
  733. Closes a device
  734. Arguments:
  735. FileHandle The file handle
  736. pFileObject The file object of the device
  737. pDeviceObject The device object of the device
  738. Return Value:
  739. None
  740. --*/
  741. {
  742. NTSTATUS status;
  743. // We make calls that can only be performed at PASSIVE_LEVEL.
  744. SAFEASSERT( CURRENT_IRQL <= PASSIVE_LEVEL );
  745. ObDereferenceObject( pFileObject );
  746. ObDereferenceObject( pDeviceObject );
  747. status = ZwClose( FileHandle );
  748. SAFEASSERT( NT_SUCCESS(status) );
  749. }
  750. VOID
  751. BrdgTimerExpiry(
  752. IN PVOID ignored1,
  753. IN PVOID data,
  754. IN PVOID ignored2,
  755. IN PVOID ignored3
  756. )
  757. /*++
  758. Routine Description:
  759. Master device expiry function. Calls a timer-specific expiry
  760. function if one was specified for this timer.
  761. Arguments:
  762. data The timer pointer
  763. Return Value:
  764. None
  765. --*/
  766. {
  767. PBRIDGE_TIMER pTimer = (PBRIDGE_TIMER)data;
  768. NdisAcquireSpinLock( &pTimer->Lock );
  769. SAFEASSERT( pTimer->bRunning );
  770. if( pTimer->bCanceled )
  771. {
  772. // This is the rare codepath where a call to NdisCancelTimer() was unable to
  773. // dequeue our timer entry because we were about to be called.
  774. DBGPRINT(GENERAL, ("Timer expiry function called with cancelled timer!\n"));
  775. // Don't call the timer function; just bail out
  776. pTimer->bRunning = 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->bCanceled = 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 )
  847. {
  848. pTimer->bRunning = TRUE;
  849. pTimer->bCanceled = 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. DBGPRINT(ALWAYS_PRINT, ("WARNING: Ignoring an attempt to restart a timer in final shutdown!\n"));
  860. }
  861. }
  862. VOID
  863. BrdgShutdownTimer(
  864. IN PBRIDGE_TIMER pTimer
  865. )
  866. /*++
  867. Routine Description:
  868. Safely shuts down a timer, waiting to make sure that the timer has been
  869. completely dequeued or its expiry function has started executing (there
  870. is no way to guarantee that the expiry function is completely done
  871. executing, however).
  872. Must be called at PASSIVE_LEVEL.
  873. Arguments:
  874. pTimer The timer
  875. Return Value:
  876. None
  877. --*/
  878. {
  879. // We wait on an event
  880. SAFEASSERT( CURRENT_IRQL <= PASSIVE_LEVEL );
  881. NdisAcquireSpinLock( &pTimer->Lock );
  882. // Forbid future calls to BrdgSetTimer().
  883. pTimer->bShuttingDown = TRUE;
  884. if( pTimer->bRunning )
  885. {
  886. BOOLEAN bCanceled;
  887. // Make sure the timer expiry function will bail out if it's too late to
  888. // dequeue the timer and it ends up getting called
  889. pTimer->bCanceled = TRUE;
  890. // This will unblock the timer expiry function, but even if it executes
  891. // between now and the call to NdisCancelTimer, it should still end up
  892. // signalling the event we will wait on below.
  893. NdisReleaseSpinLock( &pTimer->Lock );
  894. // Try to cancel the timer.
  895. NdisCancelTimer( &pTimer->Timer, &bCanceled );
  896. if( !bCanceled )
  897. {
  898. //
  899. // bCancelled can be FALSE if the timer wasn't running in the first place,
  900. // or if the OS couldn't dequeue the timer (but our expiry function will
  901. // still be called). Our use of our timer structure's spin lock should
  902. // guarantee that the timer expiry function will be executed after we
  903. // released the spin lock above, if we are on this code path. This means
  904. // that the event we wait on below will be signalled by the timer expiry
  905. // function.
  906. //
  907. DBGPRINT(GENERAL, ("Couldn't dequeue timer; blocking on completion\n"));
  908. // Wait for the completion function to finish its work
  909. NdisWaitEvent( &pTimer->Event, 0 /*Wait forever*/ );
  910. // The completion function should have cleared this
  911. SAFEASSERT( !pTimer->bRunning );
  912. }
  913. else
  914. {
  915. pTimer->bRunning = FALSE;
  916. }
  917. }
  918. else
  919. {
  920. // Tried to shutdown a timer that was not running. This is allowed (it does nothing).
  921. NdisReleaseSpinLock( &pTimer->Lock );
  922. }
  923. }
  924. VOID
  925. BrdgCancelTimer(
  926. IN PBRIDGE_TIMER pTimer
  927. )
  928. /*++
  929. Routine Description:
  930. Attempts to cancel a timer, but provides no guarantee that the timer is
  931. actually stopped on return. It is possible for the timer expiry function
  932. to fire after this function returns.
  933. Arguments:
  934. pTimer The timer
  935. Return Value:
  936. None.
  937. --*/
  938. {
  939. NdisAcquireSpinLock( &pTimer->Lock );
  940. if( pTimer->bRunning )
  941. {
  942. BOOLEAN bCanceled;
  943. pTimer->bCanceled = TRUE;
  944. NdisCancelTimer( &pTimer->Timer, &bCanceled );
  945. if( bCanceled )
  946. {
  947. pTimer->bRunning = FALSE;
  948. }
  949. // else timer expiry function will set bRunning to FALSE when it completes.
  950. }
  951. // else tried to cancel a timer that was not running. This is allowed (it does nothing).
  952. NdisReleaseSpinLock( &pTimer->Lock );
  953. }
  954. BOOLEAN
  955. BrdgIsRunningOnPersonal(
  956. VOID
  957. )
  958. /*++
  959. Routine Description:
  960. Determines if we're running on a Personal build.
  961. Arguments:
  962. None.
  963. Return Value:
  964. TRUE if we're on Personal, FALSE if we're not.
  965. --*/
  966. {
  967. OSVERSIONINFOEXW OsVer = {0};
  968. ULONGLONG ConditionMask = 0;
  969. BOOLEAN IsPersonal = TRUE;
  970. OsVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  971. OsVer.wSuiteMask = VER_SUITE_PERSONAL;
  972. OsVer.wProductType = VER_NT_WORKSTATION;
  973. VER_SET_CONDITION(ConditionMask, VER_PRODUCT_TYPE, VER_EQUAL);
  974. VER_SET_CONDITION(ConditionMask, VER_SUITENAME, VER_AND);
  975. if (RtlVerifyVersionInfo(&OsVer, VER_PRODUCT_TYPE | VER_SUITENAME,
  976. ConditionMask) == STATUS_REVISION_MISMATCH) {
  977. IsPersonal = FALSE;
  978. }
  979. return IsPersonal;
  980. }