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.

1076 lines
25 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. tcpip\ip\mcastini.c
  5. Abstract:
  6. Initialization for IP Multicasting
  7. Author:
  8. Amritansh Raghav
  9. Revision History:
  10. AmritanR Created
  11. Notes:
  12. --*/
  13. #include "precomp.h"
  14. #if IPMCAST
  15. #define __FILE_SIG__ INI_SIG
  16. #include "ipmcast.h"
  17. #include "ipmcstxt.h"
  18. #include "mcastioc.h"
  19. #include "mcastmfe.h"
  20. //
  21. // Storage for extern declarations
  22. //
  23. //#pragma data_seg("PAGE")
  24. LIST_ENTRY g_lePendingNotification;
  25. LIST_ENTRY g_lePendingIrpQueue;
  26. GROUP_ENTRY g_rgGroupTable[GROUP_TABLE_SIZE];
  27. NPAGED_LOOKASIDE_LIST g_llGroupBlocks;
  28. NPAGED_LOOKASIDE_LIST g_llSourceBlocks;
  29. NPAGED_LOOKASIDE_LIST g_llOifBlocks;
  30. NPAGED_LOOKASIDE_LIST g_llMsgBlocks;
  31. PVOID g_pvCodeSectionHandle, g_pvDataSectionHandle;
  32. KTIMER g_ktTimer;
  33. KDPC g_kdTimerDpc;
  34. DWORD g_ulNextHashIndex;
  35. DWORD g_dwMcastState;
  36. DWORD g_dwNumThreads;
  37. LONG g_lNumOpens;
  38. KEVENT g_keStateEvent;
  39. FAST_MUTEX g_StartStopMutex;
  40. RT_LOCK g_rlStateLock;
  41. //#pragma data_seg()
  42. //
  43. // Forward declarations of functions
  44. //
  45. BOOLEAN
  46. SetupExternalName(
  47. PUNICODE_STRING pusNtName,
  48. BOOLEAN bCreate
  49. );
  50. NTSTATUS
  51. InitializeMcastData(
  52. VOID
  53. );
  54. NTSTATUS
  55. InitializeIpMcast(
  56. IN PDRIVER_OBJECT DriverObject,
  57. IN PUNICODE_STRING RegistryPath,
  58. OUT PDEVICE_OBJECT * ppIpMcastDevice
  59. );
  60. NTSTATUS
  61. IpMcastDispatch(
  62. IN PDEVICE_OBJECT DeviceObject,
  63. IN PIRP Irp
  64. );
  65. NTSTATUS
  66. StartDriver(
  67. VOID
  68. );
  69. NTSTATUS
  70. StopDriver(
  71. VOID
  72. );
  73. VOID
  74. McastTimerRoutine(
  75. PKDPC Dpc,
  76. PVOID DeferredContext,
  77. PVOID SystemArgument1,
  78. PVOID SystemArgument2
  79. );
  80. NTSTATUS
  81. OpenRegKeyEx(
  82. OUT PHANDLE phHandle,
  83. IN PUNICODE_STRING pusKeyName
  84. );
  85. NTSTATUS
  86. GetRegDWORDValue(
  87. HANDLE KeyHandle,
  88. PWCHAR ValueName,
  89. PULONG ValueData
  90. );
  91. BOOLEAN
  92. EnterDriverCode(
  93. IN DWORD dwIoCode
  94. );
  95. VOID
  96. ExitDriverCode(
  97. IN DWORD dwIoCode
  98. );
  99. //////////////////////////////////////////////////////////////////////////////
  100. // //
  101. // Routines //
  102. // //
  103. //////////////////////////////////////////////////////////////////////////////
  104. //
  105. // The code is only called on initialization
  106. //
  107. #pragma alloc_text(INIT, InitializeIpMcast)
  108. NTSTATUS
  109. InitializeIpMcast(
  110. IN PDRIVER_OBJECT DriverObject,
  111. IN PUNICODE_STRING RegistryPath,
  112. OUT PDEVICE_OBJECT * ppIpMcastDevice
  113. )
  114. /*++
  115. Routine Description:
  116. Reads the registry value for multicast forwarding. If enabled,
  117. creates the IPMcast device object. Does other MCast specific
  118. initialization
  119. Locks:
  120. Arguments:
  121. pIpMcastDevice Pointer to created device
  122. Return Value:
  123. STATUS_SUCCESS or an error status
  124. --*/
  125. {
  126. UNICODE_STRING usDeviceName, usParamString, usTempString;
  127. NTSTATUS nStatus;
  128. HANDLE hRegKey;
  129. DWORD dwVal;
  130. USHORT usRegLen;
  131. PWCHAR pwcBuffer;
  132. dwVal = 0;
  133. RtInitializeDebug();
  134. usRegLen = (USHORT) (RegistryPath->Length +
  135. (uint) (sizeof(WCHAR) * (wcslen(L"\\Parameters") + 2)));
  136. //
  137. // use a random tag
  138. //
  139. pwcBuffer = ExAllocatePoolWithTag(NonPagedPool,
  140. usRegLen,
  141. MSG_TAG);
  142. if(pwcBuffer is NULL)
  143. {
  144. return STATUS_INSUFFICIENT_RESOURCES;
  145. }
  146. RtlZeroMemory(pwcBuffer,
  147. usRegLen);
  148. usParamString.MaximumLength = usRegLen;
  149. usParamString.Buffer = pwcBuffer;
  150. RtlCopyUnicodeString(&usParamString,
  151. RegistryPath);
  152. RtlInitUnicodeString(&usTempString,
  153. L"\\Parameters");
  154. RtlAppendUnicodeStringToString(&usParamString,
  155. &usTempString);
  156. nStatus = OpenRegKeyEx(&hRegKey,
  157. &usParamString);
  158. ExFreePool(pwcBuffer);
  159. if(nStatus is STATUS_SUCCESS)
  160. {
  161. #if RT_TRACE_DEBUG
  162. nStatus = GetRegDWORDValue(hRegKey,
  163. L"DebugLevel",
  164. &dwVal);
  165. if(nStatus is STATUS_SUCCESS)
  166. {
  167. g_byDebugLevel = (BYTE) dwVal;
  168. }
  169. nStatus = GetRegDWORDValue(hRegKey,
  170. L"DebugComp",
  171. &dwVal);
  172. if(nStatus is STATUS_SUCCESS)
  173. {
  174. g_fDebugComp = dwVal;
  175. }
  176. #endif
  177. #if DBG
  178. nStatus = GetRegDWORDValue(hRegKey,
  179. L"DebugBreak",
  180. &dwVal);
  181. if((nStatus is STATUS_SUCCESS) and
  182. (dwVal is 1))
  183. {
  184. DbgBreakPoint();
  185. }
  186. #endif
  187. ZwClose(hRegKey);
  188. }
  189. TraceEnter(GLOBAL, "InitializeIpMcast");
  190. //
  191. // Read the value for multicast forwarding
  192. //
  193. //
  194. // The g_dwMcastStart controls whether any forwarding actually happens
  195. // It gets set to 1 one an NtCreateFile is done on the Multicast Device.
  196. // It gets reset when the handle is closed
  197. //
  198. g_dwMcastState = MCAST_STOPPED;
  199. g_dwNumThreads = 0;
  200. g_lNumOpens = 0;
  201. //
  202. // Handles to code and data sections
  203. //
  204. g_pvCodeSectionHandle = NULL;
  205. g_pvDataSectionHandle = NULL;
  206. //
  207. // Used for the timer routine. Tells the DPC which index to start in in the
  208. // group hash table
  209. //
  210. g_ulNextHashIndex = 0;
  211. //
  212. // Create the device
  213. //
  214. RtlInitUnicodeString(&usDeviceName,
  215. DD_IPMCAST_DEVICE_NAME);
  216. nStatus = IoCreateDevice(DriverObject,
  217. 0,
  218. &usDeviceName,
  219. FILE_DEVICE_NETWORK,
  220. FILE_DEVICE_SECURE_OPEN,
  221. FALSE,
  222. ppIpMcastDevice);
  223. if(!NT_SUCCESS(nStatus))
  224. {
  225. Trace(GLOBAL, ERROR,
  226. ("InitializeIpMcast: IP initialization failed: Unable to create device object %ws, status %lx.\n",
  227. DD_IPMCAST_DEVICE_NAME,
  228. nStatus));
  229. TraceLeave(GLOBAL, "InitializeIpMcast");
  230. return nStatus;
  231. }
  232. //
  233. // Create a symbolic link in Dos Space
  234. //
  235. if(!SetupExternalName(&usDeviceName, TRUE))
  236. {
  237. Trace(GLOBAL, ERROR,
  238. ("InitializeIpMcast: Win32 device name could not be created\n"));
  239. IoDeleteDevice(*ppIpMcastDevice);
  240. TraceLeave(GLOBAL, "InitializeIpMcast");
  241. return STATUS_UNSUCCESSFUL;
  242. }
  243. RtInitializeSpinLock(&g_rlStateLock);
  244. KeInitializeEvent(&(g_keStateEvent),
  245. SynchronizationEvent,
  246. FALSE);
  247. ExInitializeFastMutex(&g_StartStopMutex);
  248. return STATUS_SUCCESS;
  249. }
  250. VOID
  251. DeinitializeIpMcast(
  252. IN PDEVICE_OBJECT DeviceObject
  253. )
  254. {
  255. StopDriver();
  256. IoDeleteDevice(DeviceObject);
  257. }
  258. #pragma alloc_text(PAGE, SetupExternalName)
  259. BOOLEAN
  260. SetupExternalName(
  261. PUNICODE_STRING pusNtName,
  262. BOOLEAN bCreate
  263. )
  264. {
  265. UNICODE_STRING usSymbolicLinkName;
  266. WCHAR rgwcBuffer[100];
  267. PAGED_CODE();
  268. //
  269. // Form the full symbolic link name we wish to create.
  270. //
  271. usSymbolicLinkName.Buffer = rgwcBuffer;
  272. RtlInitUnicodeString(&usSymbolicLinkName,
  273. WIN32_IPMCAST_SYMBOLIC_LINK);
  274. if(bCreate)
  275. {
  276. if(!NT_SUCCESS(IoCreateSymbolicLink(&usSymbolicLinkName,
  277. pusNtName)))
  278. {
  279. return FALSE;
  280. }
  281. }
  282. else
  283. {
  284. IoDeleteSymbolicLink(&usSymbolicLinkName);
  285. }
  286. return TRUE;
  287. }
  288. #pragma alloc_text(PAGE, InitializeMcastData)
  289. NTSTATUS
  290. InitializeMcastData(
  291. VOID
  292. )
  293. {
  294. LARGE_INTEGER liDueTime;
  295. ULONG ulCnt;
  296. if(g_pvCodeSectionHandle)
  297. {
  298. MmLockPagableSectionByHandle(g_pvCodeSectionHandle);
  299. }else
  300. {
  301. g_pvCodeSectionHandle = MmLockPagableCodeSection(McastTimerRoutine);
  302. if(g_pvCodeSectionHandle is NULL)
  303. {
  304. #pragma warning(push)
  305. #pragma warning(disable:4127) // conditional expression is constant
  306. RtAssert(FALSE);
  307. #pragma warning(pop)
  308. }
  309. }
  310. for(ulCnt = 0; ulCnt < GROUP_TABLE_SIZE; ulCnt++)
  311. {
  312. InitializeListHead(&(g_rgGroupTable[ulCnt].leHashHead));
  313. InitRwLock(&(g_rgGroupTable[ulCnt].rwlLock));
  314. #if DBG
  315. g_rgGroupTable[ulCnt].ulGroupCount = 0;
  316. g_rgGroupTable[ulCnt].ulCacheHits = 0;
  317. g_rgGroupTable[ulCnt].ulCacheMisses = 0;
  318. #endif
  319. g_rgGroupTable[ulCnt].pGroup = NULL;
  320. }
  321. InitializeListHead(&g_lePendingNotification);
  322. InitializeListHead(&g_lePendingIrpQueue);
  323. ExInitializeNPagedLookasideList(&g_llGroupBlocks,
  324. NULL,
  325. NULL,
  326. 0,
  327. sizeof(GROUP),
  328. GROUP_TAG,
  329. GROUP_LOOKASIDE_DEPTH);
  330. ExInitializeNPagedLookasideList(&g_llSourceBlocks,
  331. NULL,
  332. NULL,
  333. 0,
  334. sizeof(SOURCE),
  335. SOURCE_TAG,
  336. SOURCE_LOOKASIDE_DEPTH);
  337. ExInitializeNPagedLookasideList(&g_llOifBlocks,
  338. NULL,
  339. NULL,
  340. 0,
  341. sizeof(OUT_IF),
  342. OIF_TAG,
  343. OIF_LOOKASIDE_DEPTH);
  344. ExInitializeNPagedLookasideList(&g_llMsgBlocks,
  345. NULL,
  346. NULL,
  347. 0,
  348. sizeof(NOTIFICATION_MSG),
  349. MSG_TAG,
  350. MSG_LOOKASIDE_DEPTH);
  351. KeInitializeDpc(&g_kdTimerDpc,
  352. McastTimerRoutine,
  353. NULL);
  354. KeInitializeTimer(&g_ktTimer);
  355. liDueTime = RtlEnlargedUnsignedMultiply(TIMER_IN_MILLISECS,
  356. SYS_UNITS_IN_ONE_MILLISEC);
  357. liDueTime = RtlLargeIntegerNegate(liDueTime);
  358. KeSetTimerEx(&g_ktTimer,
  359. liDueTime,
  360. 0,
  361. &g_kdTimerDpc);
  362. return STATUS_SUCCESS;
  363. }
  364. #pragma alloc_text(PAGE, IpMcastDispatch)
  365. NTSTATUS
  366. IpMcastDispatch(
  367. IN PDEVICE_OBJECT DeviceObject,
  368. IN PIRP Irp
  369. )
  370. /*++
  371. Routine Description:
  372. The functions which handles the IRPs sent to the driver
  373. The IOCTLS are further dispatched using a function table
  374. THIS CODE IS PAGEABLE so it CAN NOT ACQUIRE ANY LOCKS
  375. Locks:
  376. Must be at passive
  377. Arguments:
  378. Return Value:
  379. NO_ERROR
  380. --*/
  381. {
  382. PIO_STACK_LOCATION irpStack;
  383. ULONG ulInputBuffLen;
  384. ULONG ulOutputBuffLen;
  385. ULONG ioControlCode;
  386. NTSTATUS ntStatus;
  387. BOOLEAN bEnter;
  388. UNREFERENCED_PARAMETER(DeviceObject);
  389. PAGED_CODE();
  390. TraceEnter(GLOBAL, "IpMcastDispatch");
  391. Irp->IoStatus.Information = 0;
  392. //
  393. // Get a pointer to the current location in the Irp. This is where
  394. // the function codes and parameters are located.
  395. //
  396. irpStack = IoGetCurrentIrpStackLocation(Irp);
  397. //
  398. // Get the pointer to the input/output buffer and it's length
  399. //
  400. ulInputBuffLen = irpStack->Parameters.DeviceIoControl.InputBufferLength;
  401. ulOutputBuffLen = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  402. switch (irpStack->MajorFunction)
  403. {
  404. case IRP_MJ_CREATE:
  405. {
  406. Trace(GLOBAL, TRACE,
  407. ("IpMcastDispatch: IRP_MJ_CREATE\n"));
  408. //
  409. // Make sure that the user is not attempting to sneak around the
  410. // security checks. Make sure that FileObject->RelatedFileObject is
  411. // NULL and that the FileName length is zero!
  412. //
  413. if((irpStack->FileObject->RelatedFileObject isnot NULL) or
  414. (irpStack->FileObject->FileName.Length isnot 0))
  415. {
  416. ntStatus = STATUS_ACCESS_DENIED;
  417. break;
  418. }
  419. InterlockedIncrement(&g_lNumOpens);
  420. ntStatus = STATUS_SUCCESS;
  421. break;
  422. }
  423. case IRP_MJ_CLOSE:
  424. {
  425. Trace(GLOBAL, TRACE,
  426. ("IpMcastDispatch: IRP_MJ_CLOSE\n"));
  427. ntStatus = STATUS_SUCCESS;
  428. break;
  429. }
  430. case IRP_MJ_CLEANUP:
  431. {
  432. Trace(GLOBAL, TRACE,
  433. ("IpMcastDispatch: IRP_MJ_CLEANUP\n"));
  434. if((InterlockedDecrement(&g_lNumOpens) is 0) and
  435. (g_dwMcastState isnot MCAST_STOPPED))
  436. {
  437. StopDriver();
  438. }
  439. ntStatus = STATUS_SUCCESS;
  440. break;
  441. }
  442. case IRP_MJ_DEVICE_CONTROL:
  443. {
  444. ULONG ulControl;
  445. //
  446. // The assumption is that IOCTL_IPMCAST_START_STOP will be
  447. // serialized wrt to 2 calls, i.e we wont get a stop when a start
  448. // is in progress and we will not get a start when a stop has been
  449. // issued. No assumption is made about IOCTL_IPMCAST_START_STOP's
  450. // serialization with other IRPS.
  451. // So when we are in this code we assume that we wont get
  452. // a close beneath us
  453. //
  454. ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
  455. ulControl = IoGetFunctionCodeFromCtlCode(ioControlCode);
  456. bEnter = EnterDriverCode(ioControlCode);
  457. if(!bEnter)
  458. {
  459. // keep devioctl testers happy
  460. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
  461. "IpMcastDispatch: Driver is not started\n"));
  462. ntStatus = STATUS_NO_SUCH_DEVICE;
  463. break;
  464. }
  465. switch (ioControlCode)
  466. {
  467. case IOCTL_IPMCAST_SET_MFE:
  468. {
  469. ntStatus = SetMfe(Irp,
  470. ulInputBuffLen,
  471. ulOutputBuffLen);
  472. break;
  473. }
  474. case IOCTL_IPMCAST_GET_MFE:
  475. {
  476. ntStatus = GetMfe(Irp,
  477. ulInputBuffLen,
  478. ulOutputBuffLen);
  479. break;
  480. }
  481. case IOCTL_IPMCAST_DELETE_MFE:
  482. {
  483. ntStatus = DeleteMfe(Irp,
  484. ulInputBuffLen,
  485. ulOutputBuffLen);
  486. break;
  487. }
  488. case IOCTL_IPMCAST_SET_TTL:
  489. {
  490. ntStatus = SetTtl(Irp,
  491. ulInputBuffLen,
  492. ulOutputBuffLen);
  493. break;
  494. }
  495. case IOCTL_IPMCAST_GET_TTL:
  496. {
  497. ntStatus = GetTtl(Irp,
  498. ulInputBuffLen,
  499. ulOutputBuffLen);
  500. break;
  501. }
  502. case IOCTL_IPMCAST_POST_NOTIFICATION:
  503. {
  504. ntStatus = ProcessNotification(Irp,
  505. ulInputBuffLen,
  506. ulOutputBuffLen);
  507. break;
  508. }
  509. case IOCTL_IPMCAST_START_STOP:
  510. {
  511. ntStatus = StartStopDriver(Irp,
  512. ulInputBuffLen,
  513. ulOutputBuffLen);
  514. break;
  515. }
  516. case IOCTL_IPMCAST_SET_IF_STATE:
  517. {
  518. ntStatus = SetIfState(Irp,
  519. ulInputBuffLen,
  520. ulOutputBuffLen);
  521. break;
  522. }
  523. default:
  524. {
  525. // Keep devioctl testers happy
  526. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
  527. "IpMcastDispatch: unknown IRP_MJ_DEVICE_CONTROL - 0x%X which evaluates to a code of %d\n",
  528. ioControlCode, ulControl));
  529. ntStatus = STATUS_INVALID_PARAMETER;
  530. break;
  531. }
  532. }
  533. ExitDriverCode(ioControlCode);
  534. break;
  535. }
  536. default:
  537. {
  538. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
  539. "IpMcastDispatch: unknown IRP_MJ_XX - %x\n",
  540. irpStack->MajorFunction));
  541. ntStatus = STATUS_INVALID_PARAMETER;
  542. break;
  543. }
  544. }
  545. //
  546. // Fill in status into IRP
  547. //
  548. //
  549. // This bit commented out because we cant touch the irp since it
  550. // may have been completed
  551. //
  552. // Trace(GLOBAL, INFO,
  553. // ("IpMcastDispatch: Returning status %x info %d\n",
  554. // ntStatus, Irp->IoStatus.Information));
  555. if(ntStatus isnot STATUS_PENDING)
  556. {
  557. Irp->IoStatus.Status = ntStatus;
  558. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  559. }
  560. TraceLeave(GLOBAL, "IpMcastDispatch");
  561. return ntStatus;
  562. }
  563. NTSTATUS
  564. StartDriver(
  565. VOID
  566. )
  567. {
  568. KIRQL irql;
  569. TraceEnter(GLOBAL, "StartDriver");
  570. RtAcquireSpinLock(&g_rlStateLock,
  571. &irql);
  572. if(g_dwMcastState is MCAST_STARTED)
  573. {
  574. RtReleaseSpinLock(&g_rlStateLock,
  575. irql);
  576. return STATUS_SUCCESS;
  577. }
  578. RtReleaseSpinLock(&g_rlStateLock,
  579. irql);
  580. InitializeMcastData();
  581. g_dwMcastState = MCAST_STARTED;
  582. TraceLeave(GLOBAL, "StartDriver");
  583. return STATUS_SUCCESS;
  584. }
  585. //
  586. // MUST BE PAGED IN
  587. //
  588. #pragma alloc_text(PAGEIPMc, StopDriver)
  589. NTSTATUS
  590. StopDriver(
  591. VOID
  592. )
  593. {
  594. DWORD i;
  595. KIRQL irql;
  596. PLIST_ENTRY pleGrpNode, pleSrcNode;
  597. PGROUP pGroup;
  598. PSOURCE pSource;
  599. BOOLEAN bWait;
  600. NTSTATUS nStatus;
  601. TraceEnter(GLOBAL, "StopDriver");
  602. //
  603. // Set the state to STOPPING
  604. //
  605. RtAcquireSpinLock(&g_rlStateLock,
  606. &irql);
  607. if(g_dwMcastState isnot MCAST_STARTED)
  608. {
  609. Trace(GLOBAL, ERROR,
  610. ("StopDriver: Called when state is %d\n", g_dwMcastState));
  611. // RtAssert(FALSE);
  612. RtReleaseSpinLock(&g_rlStateLock,
  613. irql);
  614. TraceLeave(GLOBAL, "StopDriver");
  615. return STATUS_SUCCESS;
  616. }
  617. else
  618. {
  619. g_dwMcastState = MCAST_STOPPED;
  620. }
  621. RtReleaseSpinLock(&g_rlStateLock,
  622. irql);
  623. //
  624. // First of all, kill the timer
  625. //
  626. i = 0;
  627. while(KeCancelTimer(&g_ktTimer) is FALSE)
  628. {
  629. LARGE_INTEGER liTimeOut;
  630. //
  631. // Hmm, timer was not in the system queue.
  632. // Set the wait to 2, 4, 6... secs
  633. //
  634. liTimeOut.QuadPart = (LONGLONG) ((i + 1) * 2 * 1000 * 1000 * 10 * -1);
  635. KeDelayExecutionThread(UserMode,
  636. FALSE,
  637. &liTimeOut);
  638. i++;
  639. }
  640. //
  641. // Delete all the (S,G) entries
  642. //
  643. for(i = 0; i < GROUP_TABLE_SIZE; i++)
  644. {
  645. //
  646. // Lock out the bucket
  647. //
  648. EnterWriter(&g_rgGroupTable[i].rwlLock,
  649. &irql);
  650. pleGrpNode = g_rgGroupTable[i].leHashHead.Flink;
  651. while(pleGrpNode isnot & (g_rgGroupTable[i].leHashHead))
  652. {
  653. pGroup = CONTAINING_RECORD(pleGrpNode, GROUP, leHashLink);
  654. pleGrpNode = pleGrpNode->Flink;
  655. pleSrcNode = pGroup->leSrcHead.Flink;
  656. while(pleSrcNode isnot & pGroup->leSrcHead)
  657. {
  658. pSource = CONTAINING_RECORD(pleSrcNode, SOURCE, leGroupLink);
  659. pleSrcNode = pleSrcNode->Flink;
  660. //
  661. // Ref and lock the source, since we need to pass it that
  662. // way to RemoveSource
  663. //
  664. ReferenceSource(pSource);
  665. RtAcquireSpinLockAtDpcLevel(&(pSource->mlLock));
  666. RemoveSource(pGroup->dwGroup,
  667. pSource->dwSource,
  668. pSource->dwSrcMask,
  669. pGroup,
  670. pSource);
  671. }
  672. }
  673. ExitWriter(&g_rgGroupTable[i].rwlLock,
  674. irql);
  675. }
  676. //
  677. // Complete any pendying IRP
  678. //
  679. ClearPendingIrps();
  680. //
  681. // Free any pending messages
  682. //
  683. ClearPendingNotifications();
  684. //
  685. // Wait for everyone to leave the code
  686. //
  687. RtAcquireSpinLock(&g_rlStateLock,
  688. &irql);
  689. //
  690. // Need to wait if the number of threads isnot 0
  691. //
  692. bWait = (BOOLEAN) (g_dwNumThreads isnot 0);
  693. RtReleaseSpinLock(&g_rlStateLock,
  694. irql);
  695. if(bWait)
  696. {
  697. nStatus = KeWaitForSingleObject(&g_keStateEvent,
  698. Executive,
  699. KernelMode,
  700. FALSE,
  701. NULL);
  702. RtAssert(nStatus is STATUS_SUCCESS);
  703. }
  704. //
  705. // Clear out the last of the data structures
  706. //
  707. ExDeleteNPagedLookasideList(&g_llGroupBlocks);
  708. ExDeleteNPagedLookasideList(&g_llSourceBlocks);
  709. ExDeleteNPagedLookasideList(&g_llOifBlocks);
  710. ExDeleteNPagedLookasideList(&g_llMsgBlocks);
  711. //
  712. // Page out the code and data
  713. //
  714. MmUnlockPagableImageSection(g_pvCodeSectionHandle);
  715. g_pvCodeSectionHandle = NULL;
  716. //MmUnlockPagableImageSection(g_pvDataSectionHandle);
  717. g_pvDataSectionHandle = NULL;
  718. TraceLeave(GLOBAL, "StopDriver");
  719. return STATUS_SUCCESS;
  720. }
  721. BOOLEAN
  722. EnterDriverCode(
  723. DWORD dwIoCode
  724. )
  725. {
  726. KIRQL irql;
  727. BOOLEAN bEnter;
  728. RtAcquireSpinLock(&g_rlStateLock,
  729. &irql);
  730. if((g_dwMcastState is MCAST_STARTED) or
  731. (dwIoCode is IOCTL_IPMCAST_START_STOP))
  732. {
  733. g_dwNumThreads++;
  734. bEnter = TRUE;
  735. }
  736. else
  737. {
  738. bEnter = FALSE;
  739. }
  740. RtReleaseSpinLock(&g_rlStateLock,
  741. irql);
  742. if(dwIoCode is IOCTL_IPMCAST_START_STOP)
  743. {
  744. ExAcquireFastMutex(&g_StartStopMutex);
  745. }
  746. return bEnter;
  747. }
  748. VOID
  749. ExitDriverCode(
  750. DWORD dwIoCode
  751. )
  752. {
  753. KIRQL irql;
  754. RtAcquireSpinLock(&g_rlStateLock,
  755. &irql);
  756. g_dwNumThreads--;
  757. if((g_dwMcastState is MCAST_STOPPED) and
  758. (g_dwNumThreads is 0))
  759. {
  760. KeSetEvent(&g_keStateEvent,
  761. 0,
  762. FALSE);
  763. }
  764. RtReleaseSpinLock(&g_rlStateLock,
  765. irql);
  766. if(dwIoCode is IOCTL_IPMCAST_START_STOP)
  767. {
  768. ExReleaseFastMutex(&g_StartStopMutex);
  769. }
  770. }
  771. #pragma alloc_text(PAGE, OpenRegKeyEx)
  772. NTSTATUS
  773. OpenRegKeyEx(
  774. OUT PHANDLE phHandle,
  775. IN PUNICODE_STRING pusKeyName
  776. )
  777. {
  778. NTSTATUS Status;
  779. OBJECT_ATTRIBUTES ObjectAttributes;
  780. PAGED_CODE();
  781. RtlZeroMemory(&ObjectAttributes,
  782. sizeof(OBJECT_ATTRIBUTES));
  783. InitializeObjectAttributes(&ObjectAttributes,
  784. pusKeyName,
  785. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  786. NULL,
  787. NULL);
  788. Status = ZwOpenKey(phHandle,
  789. KEY_READ,
  790. &ObjectAttributes);
  791. return Status;
  792. }
  793. #endif // IPMCAST