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.

3204 lines
80 KiB

  1. //============================================================================
  2. // Copyright (c) 1995, Microsoft Corporation
  3. //
  4. // File: Mgm.h
  5. //
  6. // History:
  7. // V Raman June-25-1997 Created.
  8. //
  9. // Entry points into MGM.
  10. //============================================================================
  11. #include "pchmgm.h"
  12. #pragma hdrstop
  13. IPMGM_GLOBALS ig;
  14. RTM_ENTITY_INFO g_reiRtmEntity = { 0, AF_INET, MS_IP_MGM, 0 };
  15. RTM_REGN_PROFILE g_rrpRtmProfile;
  16. RTM_ENTITY_HANDLE g_hRtmHandle;
  17. RTM_NOTIFY_HANDLE g_hNotificationHandle;
  18. RTM_REGN_PROFILE g_rrpRtmProfile;
  19. DWORD
  20. StopMgm(
  21. );
  22. //----------------------------------------------------------------------------
  23. // MgmDllStartup
  24. //
  25. // Invoked from DllMain, to initialize global critical section, set status and
  26. // register for tracing.
  27. //----------------------------------------------------------------------------
  28. BOOL
  29. MgmDllStartup(
  30. )
  31. {
  32. do
  33. {
  34. ZeroMemory( &ig, sizeof( IPMGM_GLOBALS ) );
  35. ig.dwLogLevel = IPMGM_LOGGING_ERROR;
  36. //
  37. // Create private heap
  38. //
  39. ig.hIpMgmGlobalHeap = HeapCreate( 0, 0, 0 );
  40. if ( ig.hIpMgmGlobalHeap == NULL )
  41. {
  42. break;
  43. }
  44. //
  45. // initialize the lock list
  46. //
  47. ig.llStackOfLocks.sleHead.Next = NULL;
  48. try
  49. {
  50. InitializeCriticalSection( &ig.llStackOfLocks.csListLock );
  51. }
  52. except ( EXCEPTION_EXECUTE_HANDLER )
  53. {
  54. break;
  55. }
  56. ig.llStackOfLocks.bInit = TRUE;
  57. //
  58. // Initialize global critical section and set MGM status
  59. //
  60. try
  61. {
  62. InitializeCriticalSection( &ig.csGlobal );
  63. }
  64. except ( EXCEPTION_EXECUTE_HANDLER )
  65. {
  66. break;
  67. }
  68. ig.imscStatus = IPMGM_STATUS_STOPPED;
  69. return TRUE;
  70. } while ( FALSE );
  71. //
  72. // error occurred - clean up and return FALSE
  73. //
  74. //
  75. // destroy the lock list
  76. //
  77. if ( ig.llStackOfLocks.bInit )
  78. {
  79. DeleteCriticalSection( &ig.llStackOfLocks.csListLock );
  80. }
  81. //
  82. // delete private heap
  83. //
  84. if ( ig.hIpMgmGlobalHeap != NULL )
  85. {
  86. HeapDestroy( ig.hIpMgmGlobalHeap );
  87. }
  88. return FALSE;
  89. }
  90. //----------------------------------------------------------------------------
  91. // MgmDllCleanup
  92. //
  93. // Invoked from DllMain, to delete global critical section and
  94. // deregister for tracing.
  95. //----------------------------------------------------------------------------
  96. VOID
  97. MgmDllCleanup(
  98. )
  99. {
  100. DeleteCriticalSection( &ig.csGlobal );
  101. //
  102. // delete lock list
  103. //
  104. DeleteLockList();
  105. if ( ig.llStackOfLocks.bInit )
  106. {
  107. DeleteCriticalSection( &ig.llStackOfLocks.csListLock );
  108. }
  109. //
  110. // delete private heap
  111. //
  112. if ( ig.hIpMgmGlobalHeap != NULL )
  113. {
  114. HeapDestroy( ig.hIpMgmGlobalHeap );
  115. }
  116. return;
  117. }
  118. //----------------------------------------------------------------------------
  119. // MgmInitialize
  120. //
  121. // This function is performs Mgm Initialization that includes allocating
  122. // a private heap, creating a activity count semaphores and the list
  123. // structures for protocol and interface entries.
  124. //----------------------------------------------------------------------------
  125. DWORD
  126. MgmInitialize(
  127. IN PROUTER_MANAGER_CONFIG prmcRmConfig,
  128. IN OUT PMGM_CALLBACKS pmcCallbacks
  129. )
  130. {
  131. DWORD dwErr = NO_ERROR, dwIndex;
  132. LARGE_INTEGER li;
  133. NTSTATUS nsStatus = STATUS_SUCCESS;
  134. ENTER_GLOBAL_SECTION();
  135. //
  136. // verify MGM has not already been started.
  137. //
  138. if ( ig.imscStatus != IPMGM_STATUS_STOPPED )
  139. {
  140. TRACE0( START, "MgmInitialize : MGM already running" );
  141. LOGWARN0( IPMGM_ALREADY_STARTED, NO_ERROR );
  142. LEAVE_GLOBAL_SECTION();
  143. return ERROR_CAN_NOT_COMPLETE;
  144. }
  145. //
  146. // register for tracing
  147. //
  148. TRACESTART();
  149. ig.hLogHandle = RouterLogRegister( "IPMGM" );
  150. TRACE0( ENTER, "ENTERED MgmInitialize" );
  151. do
  152. {
  153. //
  154. // Copy the Router manager callbacks.
  155. //
  156. ig.rmcRmConfig.pfnAddMfeCallback =
  157. prmcRmConfig-> pfnAddMfeCallback;
  158. ig.rmcRmConfig.pfnDeleteMfeCallback =
  159. prmcRmConfig-> pfnDeleteMfeCallback;
  160. ig.rmcRmConfig.pfnGetMfeCallback =
  161. prmcRmConfig-> pfnGetMfeCallback;
  162. ig.rmcRmConfig.pfnHasBoundaryCallback =
  163. prmcRmConfig-> pfnHasBoundaryCallback;
  164. //
  165. // Hash table sizes
  166. //
  167. ig.rmcRmConfig.dwIfTableSize = prmcRmConfig-> dwIfTableSize;
  168. ig.rmcRmConfig.dwGrpTableSize = prmcRmConfig-> dwGrpTableSize + 1;
  169. ig.rmcRmConfig.dwSrcTableSize = prmcRmConfig-> dwSrcTableSize + 1;
  170. ig.dwRouteTableSize = prmcRmConfig-> dwIfTableSize;
  171. ig.dwTimerQTableSize =
  172. min( prmcRmConfig-> dwGrpTableSize / 10 + 1, TIMER_TABLE_MAX_SIZE );
  173. if ( prmcRmConfig-> dwLogLevel <= IPMGM_LOGGING_INFO )
  174. {
  175. ig.dwLogLevel = prmcRmConfig-> dwLogLevel;
  176. }
  177. //
  178. // initialize the protocol list
  179. //
  180. ig.dwNumProtocols = 0;
  181. CREATE_LOCKED_LIST( &ig.mllProtocolList );
  182. //
  183. // initialize the outstanding join list
  184. CREATE_LOCKED_LIST( &ig.mllOutstandingJoinList );
  185. //
  186. // create and initialize the interface hash table
  187. //
  188. ig.pmllIfHashTable = MGM_ALLOC( sizeof( MGM_LOCKED_LIST ) * IF_TABLE_SIZE );
  189. if ( ig.pmllIfHashTable == NULL )
  190. {
  191. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  192. TRACE1(
  193. ANY, "MgmInitialize : Failed to allocate interface table : %x",
  194. dwErr
  195. );
  196. LOGERR0( HEAP_ALLOC_FAILED, dwErr );
  197. break;
  198. }
  199. ZeroMemory(
  200. ig.pmllIfHashTable, sizeof( MGM_LOCKED_LIST ) * IF_TABLE_SIZE
  201. );
  202. for ( dwIndex = 0; dwIndex < IF_TABLE_SIZE; dwIndex++ )
  203. {
  204. CREATE_LOCKED_LIST( &ig.pmllIfHashTable[ dwIndex ] );
  205. }
  206. //
  207. // initialize the master group list and temp group list.
  208. //
  209. CREATE_LOCKED_LIST( &ig.mllGrpList );
  210. CREATE_LOCKED_LIST( &ig.mllTempGrpList );
  211. ig.dwNumTempEntries = 0;
  212. //
  213. // Create and Initialize group Hash table
  214. //
  215. ig.pmllGrpHashTable = MGM_ALLOC( sizeof( MGM_LOCKED_LIST ) * GROUP_TABLE_SIZE );
  216. if ( ig.pmllGrpHashTable == NULL )
  217. {
  218. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  219. TRACE1(
  220. ANY, "MgmInitialize : Failed to allocate group table : %x",
  221. dwErr
  222. );
  223. LOGERR0( HEAP_ALLOC_FAILED, dwErr );
  224. break;
  225. }
  226. ZeroMemory(
  227. ig.pmllGrpHashTable, sizeof( MGM_LOCKED_LIST ) * GROUP_TABLE_SIZE
  228. );
  229. for ( dwIndex = 0; dwIndex < GROUP_TABLE_SIZE; dwIndex++ )
  230. {
  231. CREATE_LOCKED_LIST( &ig.pmllGrpHashTable[ dwIndex ] );
  232. }
  233. //
  234. // Set up the table of timer queues
  235. //
  236. ig.phTimerQHandleTable =
  237. MGM_ALLOC( TIMER_TABLE_SIZE * sizeof( HANDLE ) );
  238. if ( ig.phTimerQHandleTable == NULL )
  239. {
  240. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  241. TRACE1(
  242. ANY, "MgmInitialize : Failed to allocate timer table : %x",
  243. dwErr
  244. );
  245. LOGERR0( HEAP_ALLOC_FAILED, dwErr );
  246. break;
  247. }
  248. ZeroMemory(
  249. ig.phTimerQHandleTable, TIMER_TABLE_SIZE * sizeof( HANDLE )
  250. );
  251. for ( dwIndex = 0; dwIndex < TIMER_TABLE_SIZE; dwIndex++ )
  252. {
  253. nsStatus = RtlCreateTimerQueue( &ig.phTimerQHandleTable[ dwIndex ] );
  254. if ( !NT_SUCCESS( nsStatus ) )
  255. {
  256. dwErr = ERROR_NO_SYSTEM_RESOURCES;
  257. break;
  258. }
  259. }
  260. if ( !NT_SUCCESS( nsStatus ) )
  261. {
  262. break;
  263. }
  264. //
  265. // create activity count semaphore
  266. //
  267. ig.lActivityCount = 0;
  268. ig.hActivitySemaphore = CreateSemaphore( NULL, 0, 0x7FFFFFFF, NULL );
  269. if ( ig.hActivitySemaphore == NULL )
  270. {
  271. dwErr = GetLastError();
  272. TRACE1(
  273. ANY,
  274. "MgmInitialize : Failed to create activity count semaphore : %x",
  275. dwErr
  276. );
  277. LOGERR0( CREATE_SEMAPHORE_FAILED, dwErr );
  278. break;
  279. }
  280. //
  281. // Register with RTMv2 as a client
  282. //
  283. dwErr = RtmRegisterEntity(
  284. &g_reiRtmEntity, NULL, RtmChangeNotificationCallback,
  285. TRUE, &g_rrpRtmProfile, &g_hRtmHandle
  286. );
  287. if ( dwErr != NO_ERROR )
  288. {
  289. TRACE1(
  290. ANY, "MgmInitialize : Failed to register with Rtm : %x",
  291. dwErr
  292. );
  293. LOGERR0( RTM_REGISTER_FAILED, dwErr );
  294. break;
  295. }
  296. //
  297. // Register for marked change notification only
  298. //
  299. dwErr = RtmRegisterForChangeNotification(
  300. g_hRtmHandle, RTM_VIEW_MASK_MCAST,
  301. RTM_CHANGE_TYPE_BEST | RTM_NOTIFY_ONLY_MARKED_DESTS,
  302. NULL, &g_hNotificationHandle
  303. );
  304. if ( dwErr != NO_ERROR )
  305. {
  306. TRACE1(
  307. ANY, "MgmInitialize : Failed to register with Rtm for change"
  308. "notification : %x", dwErr
  309. );
  310. LOGERR0( RTM_REGISTER_FAILED, dwErr );
  311. break;
  312. }
  313. //
  314. // set up callbacks into MGM for the router manager.
  315. //
  316. pmcCallbacks-> pfnMfeDeleteIndication = DeleteFromForwarder;
  317. pmcCallbacks-> pfnNewPacketIndication = MgmNewPacketReceived;
  318. pmcCallbacks-> pfnWrongIfIndication = WrongIfFromForwarder;
  319. pmcCallbacks-> pfnBlockGroups = MgmBlockGroups;
  320. pmcCallbacks-> pfnUnBlockGroups = MgmUnBlockGroups;
  321. //
  322. // set the status to running. All future API calls depend on this
  323. //
  324. ig.imscStatus = IPMGM_STATUS_RUNNING;
  325. } while ( FALSE );
  326. LEAVE_GLOBAL_SECTION();
  327. //
  328. // in case of error, cleanup all resources allocated
  329. //
  330. TRACE1( ENTER, "LEAVING MgmInitialize : %x\n", dwErr );
  331. if ( dwErr != NO_ERROR )
  332. {
  333. MgmDeInitialize();
  334. }
  335. return dwErr;
  336. }
  337. //----------------------------------------------------------------------------
  338. // MgmDeInitialize
  339. //
  340. //
  341. //----------------------------------------------------------------------------
  342. DWORD
  343. MgmDeInitialize(
  344. )
  345. {
  346. DWORD dwErr, dwInd;
  347. TRACE0( ENTER, "ENTERED MgmDeInitialize" );
  348. do
  349. {
  350. //--------------------------------------------------------------------
  351. // Terminate all activity
  352. //--------------------------------------------------------------------
  353. dwErr = StopMgm();
  354. if ( dwErr != NO_ERROR )
  355. {
  356. break;
  357. }
  358. //--------------------------------------------------------------------
  359. // Free all resources
  360. //--------------------------------------------------------------------
  361. //
  362. // de-register from RTM
  363. //
  364. dwErr = RtmDeregisterFromChangeNotification(
  365. g_hRtmHandle, g_hNotificationHandle
  366. );
  367. if ( dwErr != NO_ERROR )
  368. {
  369. TRACE1(
  370. ANY, "Failed to de-register change notification : %x",
  371. dwErr
  372. );
  373. }
  374. dwErr = RtmDeregisterEntity( g_hRtmHandle );
  375. if ( dwErr != NO_ERROR )
  376. {
  377. TRACE1( ANY, "Failed to de-register from RTM: %x", dwErr );
  378. }
  379. //
  380. // delete activity semaphore
  381. //
  382. if ( ig.hActivitySemaphore != NULL )
  383. {
  384. CloseHandle( ig.hActivitySemaphore );
  385. ig.hActivitySemaphore = NULL;
  386. }
  387. //
  388. // delete group lists
  389. //
  390. for ( dwInd = 0; dwInd < GROUP_TABLE_SIZE; dwInd++ )
  391. {
  392. DELETE_LOCKED_LIST( &ig.pmllGrpHashTable[ dwInd ] );
  393. }
  394. MGM_FREE( ig.pmllGrpHashTable );
  395. DELETE_LOCKED_LIST( &ig.mllGrpList );
  396. //
  397. // delete interface lists
  398. //
  399. for ( dwInd = 0; dwInd < IF_TABLE_SIZE; dwInd++ )
  400. {
  401. DELETE_LOCKED_LIST( &ig.pmllIfHashTable[ dwInd ] );
  402. }
  403. MGM_FREE( ig.pmllIfHashTable );
  404. //
  405. // delete protocol list
  406. //
  407. DELETE_LOCKED_LIST( &ig.mllProtocolList );
  408. //
  409. // free timer resources
  410. //
  411. NtClose( ig.hRouteCheckTimer );
  412. for ( dwInd = 0; dwInd < TIMER_TABLE_SIZE; dwInd++ )
  413. {
  414. RtlDeleteTimerQueue( ig.phTimerQHandleTable[ dwInd ] );
  415. }
  416. TRACE1( ENTER, "LEAVING MgmDeInitialize %x\n", dwErr );
  417. //
  418. // trace deregister
  419. //
  420. RouterLogDeregister( ig.hLogHandle );
  421. TRACESTOP();
  422. ig.imscStatus = IPMGM_STATUS_STOPPED;
  423. } while ( FALSE );
  424. return dwErr;
  425. }
  426. //----------------------------------------------------------------------------
  427. // StopMgm
  428. //
  429. // This function waits for all the therads that are currently executing in
  430. // MGM to finish. In addition the status of MGM is marked as stopping which
  431. // prevents the further threads from executing MGM API.
  432. //----------------------------------------------------------------------------
  433. DWORD
  434. StopMgm(
  435. )
  436. {
  437. LONG lThreadCount = 0;
  438. TRACE0( STOP, "ENTERED StopMgm" );
  439. //
  440. // Set status of MGM to be stopping
  441. //
  442. ENTER_GLOBAL_SECTION();
  443. if ( ig.imscStatus != IPMGM_STATUS_RUNNING )
  444. {
  445. LEAVE_GLOBAL_SECTION();
  446. TRACE0( ANY, "Mgm is not running" );
  447. return ERROR_CAN_NOT_COMPLETE;
  448. }
  449. ig.imscStatus = IPMGM_STATUS_STOPPING;
  450. lThreadCount = ig.lActivityCount;
  451. LEAVE_GLOBAL_SECTION();
  452. TRACE1( STOP, "Number of threads in MGM : %x", lThreadCount );
  453. //
  454. // Wait for all the threads in MGM to terminate.
  455. //
  456. while ( lThreadCount-- > 0 )
  457. {
  458. WaitForSingleObject( ig.hActivitySemaphore, INFINITE );
  459. }
  460. //
  461. // Acquire and release global critical section to ensure all
  462. // threads have finished LEAVE_MGM_API()
  463. //
  464. ENTER_GLOBAL_SECTION();
  465. LEAVE_GLOBAL_SECTION();
  466. TRACE0( STOP, "LEAVING StopMgm" );
  467. return NO_ERROR;
  468. }
  469. //----------------------------------------------------------------------------
  470. // MgmRegisterMProtocol
  471. //
  472. // This function is invoked by a routing protocol to obtain a handle. This
  473. // handle must be supplied to all subsequent MGM operations. When invoked
  474. // this function creates an entry in the list of clients.
  475. //----------------------------------------------------------------------------
  476. DWORD
  477. MgmRegisterMProtocol(
  478. IN PROUTING_PROTOCOL_CONFIG prpcInfo,
  479. IN DWORD dwProtocolId,
  480. IN DWORD dwComponentId,
  481. OUT HANDLE * phProtocol
  482. )
  483. {
  484. DWORD dwErr = NO_ERROR;
  485. PPROTOCOL_ENTRY ppeEntry = NULL;
  486. //
  487. // increment count of clients executing MGM apis
  488. //
  489. if ( !ENTER_MGM_API() )
  490. {
  491. return ERROR_CAN_NOT_COMPLETE;
  492. }
  493. TRACE2(
  494. ENTER, "ENTERED MgmRegisterMProtocol %x, %x",
  495. dwProtocolId, dwComponentId
  496. );
  497. //
  498. // Lock Protocol list
  499. //
  500. ACQUIRE_PROTOCOL_LOCK_EXCLUSIVE();
  501. do
  502. {
  503. //
  504. // check if the protocol already exists.
  505. //
  506. ppeEntry = GetProtocolEntry(
  507. &ig.mllProtocolList.leHead, dwProtocolId, dwComponentId
  508. );
  509. if ( ppeEntry != NULL )
  510. {
  511. //
  512. // valid entry is present. quit with error
  513. //
  514. TRACE2(
  515. ANY, "Entry already present for protocol : %x, %x",
  516. dwProtocolId, dwComponentId
  517. );
  518. LOGERR0( PROTOCOL_ALREADY_PRESENT, dwProtocolId );
  519. dwErr = ERROR_ALREADY_EXISTS;
  520. break;
  521. }
  522. //
  523. // create new protocol entry
  524. //
  525. dwErr = CreateProtocolEntry(
  526. &ig.mllProtocolList.leHead,
  527. dwProtocolId, dwComponentId, prpcInfo, &ppeEntry
  528. );
  529. if ( dwErr != NO_ERROR )
  530. {
  531. TRACE1(
  532. ANY, "Failed to create protocol entry %x", dwErr
  533. );
  534. LOGERR0( CREATE_PROTOCOL_FAILED, dwErr );
  535. break;
  536. }
  537. ig.dwNumProtocols++;
  538. //
  539. // return handle to client
  540. //
  541. *phProtocol = (HANDLE) ( ( (ULONG_PTR) ppeEntry )
  542. ^ (ULONG_PTR)MGM_CLIENT_HANDLE_TAG );
  543. dwErr = NO_ERROR;
  544. } while ( FALSE );
  545. RELEASE_PROTOCOL_LOCK_EXCLUSIVE();
  546. LEAVE_MGM_API();
  547. TRACE1( ENTER, "LEAVING MgmRegisterMProtocol : %x\n", dwErr );
  548. return dwErr;
  549. }
  550. //----------------------------------------------------------------------------
  551. // MgmRegisterMProtocol
  552. //
  553. // This function is invoked by a routing protocol to obtain a handle. This
  554. // handle must be supplied to all subsequent MGM operations. When invoked
  555. // this function creates an entry in the list of clients.
  556. //----------------------------------------------------------------------------
  557. DWORD
  558. MgmDeRegisterMProtocol(
  559. IN HANDLE hProtocol
  560. )
  561. {
  562. DWORD dwErr = NO_ERROR;
  563. PPROTOCOL_ENTRY ppeEntry = NULL;
  564. //
  565. // increment count of clients executing MGM apis
  566. //
  567. if ( !ENTER_MGM_API() )
  568. {
  569. return ERROR_CAN_NOT_COMPLETE;
  570. }
  571. TRACE0( ENTER, "ENTERED MgmDeRegisterMProtocol" );
  572. //
  573. // Acquire write lock
  574. //
  575. ACQUIRE_PROTOCOL_LOCK_EXCLUSIVE();
  576. do
  577. {
  578. //
  579. // retrieve entry from handle
  580. //
  581. ppeEntry = (PPROTOCOL_ENTRY)
  582. ( ( (ULONG_PTR) hProtocol )
  583. ^ (ULONG_PTR)MGM_CLIENT_HANDLE_TAG );
  584. dwErr = VerifyProtocolHandle( ppeEntry );
  585. if ( dwErr != NO_ERROR )
  586. {
  587. break;
  588. }
  589. //
  590. // Verify that the protocol entry does not own any interfaces
  591. //
  592. if ( ppeEntry-> dwIfCount != 0 )
  593. {
  594. dwErr = ERROR_CAN_NOT_COMPLETE;
  595. TRACE1( ANY, "%x interfaces present for this protocol", dwErr );
  596. LOGERR0( INTERFACES_PRESENT, dwErr );
  597. break;
  598. }
  599. //
  600. // No interfaces for this protocol
  601. //
  602. DeleteProtocolEntry( ppeEntry );
  603. ig.dwNumProtocols--;
  604. dwErr = NO_ERROR;
  605. } while ( FALSE );
  606. RELEASE_PROTOCOL_LOCK_EXCLUSIVE();
  607. TRACE1( ENTER, "LEAVING MgmDeRegisterMProtocol %x\n", dwErr );
  608. LEAVE_MGM_API();
  609. return dwErr;
  610. }
  611. //============================================================================
  612. // Interface ownership API
  613. //
  614. //============================================================================
  615. //----------------------------------------------------------------------------
  616. // MgmTakeInterfaceOwnership
  617. //
  618. // This function is invoked by a routing protocol when it is enabled on an
  619. // interface. This function creates an entry for the specified interface
  620. // and inserts it into the appropriate interface hash bucket.
  621. //
  622. // Only one protocol can take ownership of an interface at a time. The
  623. // only exception to this rule is IGMP. IGMP can co-exist with another
  624. // routing protocol on an interface. In this case, the routing protocol
  625. // should take ownership of the interface first.
  626. //----------------------------------------------------------------------------
  627. DWORD
  628. MgmTakeInterfaceOwnership(
  629. IN HANDLE hProtocol,
  630. IN DWORD dwIfIndex,
  631. IN DWORD dwIfNextHopAddr
  632. )
  633. {
  634. BOOL bFound = FALSE, bIfLock = FALSE;
  635. DWORD dwErr = NO_ERROR, dwBucket;
  636. PPROTOCOL_ENTRY ppeEntry = NULL;
  637. PIF_ENTRY pieEntry = NULL;
  638. if ( !ENTER_MGM_API() )
  639. {
  640. return ERROR_CAN_NOT_COMPLETE;
  641. }
  642. TRACE2(
  643. ENTER, "ENTERED MgmTakeInterfaceOwnership : Interface %x, %x",
  644. dwIfIndex, dwIfNextHopAddr
  645. );
  646. ACQUIRE_PROTOCOL_LOCK_SHARED();
  647. do
  648. {
  649. //
  650. // verify protocol handle
  651. //
  652. ppeEntry = (PPROTOCOL_ENTRY)
  653. ( ( (ULONG_PTR) hProtocol )
  654. ^ (ULONG_PTR)MGM_CLIENT_HANDLE_TAG );
  655. dwErr = VerifyProtocolHandle( ppeEntry );
  656. if ( dwErr != NO_ERROR )
  657. {
  658. break;
  659. }
  660. TRACEIF2(
  661. IF, "Protocol id: 0x%x 0x%x",
  662. ppeEntry-> dwProtocolId, ppeEntry-> dwComponentId
  663. );
  664. //
  665. // Retrieve interface entry
  666. //
  667. dwBucket = IF_TABLE_HASH( dwIfIndex );
  668. ACQUIRE_IF_LOCK_EXCLUSIVE( dwBucket );
  669. bIfLock = TRUE;
  670. bFound = FindIfEntry(
  671. IF_BUCKET_HEAD( dwBucket ), dwIfIndex, dwIfNextHopAddr,
  672. &pieEntry
  673. );
  674. if ( bFound )
  675. {
  676. //
  677. // interface entry exists
  678. //
  679. if ( IS_PROTOCOL_IGMP( ppeEntry ) )
  680. {
  681. //
  682. // IGMP is being enabled to this interface.
  683. // Set IGMP present flag on this interface entry.
  684. //
  685. SET_ADDED_BY_IGMP( pieEntry );
  686. }
  687. //
  688. // A routing protocol is being enabled to this interface entry.
  689. //
  690. //
  691. // Check if interface is currently owned by IGMP. In this case
  692. // alone the routing protocol may be added to an existing (from
  693. // the MGM point of view) interface.
  694. //
  695. // If another routing protocol owns the interface that is
  696. // an error as per the interop rules for multicast protocols
  697. // on a border router. report the error.
  698. //
  699. else if ( IS_PROTOCOL_ID_IGMP( pieEntry-> dwOwningProtocol ) )
  700. {
  701. //
  702. // Interface currently owned by IGMP
  703. //
  704. dwErr = TransferInterfaceOwnershipToProtocol(
  705. ppeEntry, pieEntry
  706. );
  707. }
  708. else
  709. {
  710. //
  711. // Interface currently owned by another routing protocol.
  712. // This is an error.
  713. //
  714. dwErr = ERROR_ALREADY_EXISTS;
  715. TRACE2(
  716. ANY,
  717. "MgmTakeInterfaceOwnership : Already owned by routing protocol"
  718. " : %d, %d", pieEntry-> dwOwningProtocol,
  719. pieEntry-> dwOwningComponent
  720. );
  721. LOGWARN0( IF_ALREADY_PRESENT, dwErr );
  722. }
  723. break;
  724. }
  725. //
  726. // No interface entry found. Create a new one.
  727. //
  728. if ( pieEntry == NULL )
  729. {
  730. //
  731. // First interface in the hash bucket
  732. //
  733. dwErr = CreateIfEntry(
  734. &ig.pmllIfHashTable[ dwBucket ].leHead,
  735. dwIfIndex, dwIfNextHopAddr,
  736. ppeEntry-> dwProtocolId, ppeEntry-> dwComponentId
  737. );
  738. }
  739. else
  740. {
  741. dwErr = CreateIfEntry(
  742. &pieEntry-> leIfHashList,
  743. dwIfIndex, dwIfNextHopAddr,
  744. ppeEntry-> dwProtocolId, ppeEntry-> dwComponentId
  745. );
  746. }
  747. } while ( FALSE );
  748. //
  749. // Increment interface count for the specified protocol
  750. //
  751. if ( dwErr == NO_ERROR )
  752. {
  753. InterlockedIncrement( &ppeEntry-> dwIfCount );
  754. }
  755. //
  756. // Release held locks.
  757. //
  758. if ( bIfLock )
  759. {
  760. RELEASE_IF_LOCK_EXCLUSIVE( dwBucket );
  761. }
  762. RELEASE_PROTOCOL_LOCK_SHARED();
  763. TRACE1( ENTER, "LEAVING MgmTakeInterfaceOwnership %x\n", dwErr );
  764. LEAVE_MGM_API();
  765. return dwErr;
  766. }
  767. //----------------------------------------------------------------------------
  768. // MgmReleaseInterfaceOwnership
  769. //
  770. // This function is invoked by a routing protocol when it is disabled
  771. // on an interface. This functions deletes the entry for the specified
  772. // interface. Before deleting the interface entry all the
  773. // fowarding entries created by the protocol that use this interface as
  774. // the incoming interface. Also remove all group memberships on this
  775. // interface.
  776. //
  777. // If IGMP and routing protocol are both enabled on this interface
  778. // IGMP should release this interface first followed by the routing
  779. // protocol.
  780. //
  781. //----------------------------------------------------------------------------
  782. DWORD
  783. MgmReleaseInterfaceOwnership(
  784. IN HANDLE hProtocol,
  785. IN DWORD dwIfIndex,
  786. IN DWORD dwIfNextHopAddr
  787. )
  788. {
  789. BOOL bFound = FALSE, bIGMP, bIfLock = FALSE;
  790. DWORD dwErr = NO_ERROR, dwBucket;
  791. PPROTOCOL_ENTRY ppeEntry = NULL, ppe;
  792. PIF_ENTRY pieEntry = NULL;
  793. if ( !ENTER_MGM_API() )
  794. {
  795. return ERROR_CAN_NOT_COMPLETE;
  796. }
  797. TRACE2(
  798. ENTER, "ENTERED MgmReleaseInterfaceOwnership : Interface %x, %x",
  799. dwIfIndex, dwIfNextHopAddr
  800. );
  801. ACQUIRE_PROTOCOL_LOCK_SHARED();
  802. do
  803. {
  804. //
  805. // 1. parameter validation
  806. //
  807. //
  808. // verify protocol handle
  809. //
  810. ppeEntry = (PPROTOCOL_ENTRY)
  811. ( ( (ULONG_PTR) hProtocol )
  812. ^ (ULONG_PTR) MGM_CLIENT_HANDLE_TAG );
  813. dwErr = VerifyProtocolHandle( ppeEntry );
  814. if ( dwErr != NO_ERROR )
  815. {
  816. break;
  817. }
  818. TRACEIF2(
  819. IF, "Protocol id: 0x%x 0x%x",
  820. ppeEntry-> dwProtocolId, ppeEntry-> dwComponentId
  821. );
  822. //
  823. // Retrieve interface entry
  824. //
  825. dwBucket = IF_TABLE_HASH( dwIfIndex );
  826. ACQUIRE_IF_LOCK_EXCLUSIVE( dwBucket );
  827. bIfLock = TRUE;
  828. pieEntry = GetIfEntry(
  829. IF_BUCKET_HEAD( dwBucket ), dwIfIndex, dwIfNextHopAddr
  830. );
  831. if ( pieEntry == NULL )
  832. {
  833. //
  834. // no interface entry
  835. //
  836. dwErr = ERROR_INVALID_PARAMETER;
  837. TRACE2(
  838. ANY, "Interface entry %d, %x not found ",
  839. dwIfIndex, dwIfNextHopAddr
  840. );
  841. LOGWARN0( IF_NOT_FOUND, dwErr );
  842. break;
  843. }
  844. //
  845. // Interface entry present. Make sure it is owned by the protocol
  846. // that is releasing it.
  847. //
  848. if ( IS_PROTOCOL_IGMP( ppeEntry ) && !IS_ADDED_BY_IGMP( pieEntry ) )
  849. {
  850. //
  851. // trying to delete IGMP on an interface that
  852. // it is not present on.
  853. //
  854. dwErr = ERROR_INVALID_PARAMETER;
  855. TRACE2(
  856. ANY, "IGMP not running on interface %x, %x",
  857. pieEntry-> dwIfIndex, pieEntry-> dwIfNextHopAddr
  858. );
  859. LOGWARN0( IF_NOT_FOUND, dwErr );
  860. break;
  861. }
  862. if ( IS_ROUTING_PROTOCOL( ppeEntry ) &&
  863. ( ( ppeEntry-> dwProtocolId != pieEntry-> dwOwningProtocol ) ||
  864. ( ppeEntry-> dwComponentId != pieEntry-> dwOwningComponent ) ) )
  865. {
  866. //
  867. // interface entry not owned by routing protocol
  868. //
  869. dwErr = ERROR_INVALID_PARAMETER;
  870. TRACE2(
  871. ANY, "Routing protcol not running on interface %x, %x",
  872. pieEntry-> dwIfIndex, pieEntry-> dwIfNextHopAddr
  873. );
  874. LOGWARN0( IF_NOT_FOUND, dwErr );
  875. break;
  876. }
  877. //
  878. // 2. Remove protocol state for the interface
  879. //
  880. ppe = ppeEntry;
  881. if ( IS_PROTOCOL_IGMP( ppeEntry ) )
  882. {
  883. //
  884. // IGMP is releasing this interface
  885. //
  886. CLEAR_ADDED_BY_IGMP( pieEntry );
  887. bIGMP = TRUE;
  888. if ( !IS_ADDED_BY_PROTOCOL( pieEntry ) )
  889. {
  890. //
  891. // if IGMP is the only protocol on this interface, then delete
  892. // any MFEs that use this interface as the incoming interface.
  893. // (otherwise these MFEs were created by the routing protocol,
  894. // that co-exists with IGMP on this interface, leave them
  895. // alone)
  896. //
  897. DeleteInInterfaceRefs( &pieEntry-> leInIfList );
  898. }
  899. else
  900. {
  901. //
  902. // Interface is shared by IGMP and Routing Protocol.
  903. //
  904. // Group memberships added on an interface shared by IGMP
  905. // and a routing protocol are owned by the routing protocol (
  906. // with a bit field indicating whether they have been added by
  907. // IGMP )
  908. //
  909. // To delete a group membership added by IGMP on a shared
  910. // interface, lookup the protocol on that interface and use that
  911. // as the protocol that added the group membership.
  912. //
  913. ppeEntry = GetProtocolEntry(
  914. PROTOCOL_LIST_HEAD(), pieEntry-> dwOwningProtocol,
  915. pieEntry-> dwOwningComponent
  916. );
  917. }
  918. }
  919. else
  920. {
  921. //
  922. // Interface is being deleted by a routing protocol
  923. //
  924. if ( IS_ADDED_BY_IGMP( pieEntry ) )
  925. {
  926. //
  927. // IGMP still exists on this interface
  928. //
  929. dwErr = TransferInterfaceOwnershipToIGMP( ppeEntry, pieEntry );
  930. break;
  931. }
  932. //
  933. // only routing protocol existed on this interface.
  934. //
  935. CLEAR_ADDED_BY_PROTOCOL( pieEntry );
  936. bIGMP = FALSE;
  937. //
  938. // delete all mfes that use this interface as the incoming interface
  939. //
  940. DeleteInInterfaceRefs( &pieEntry-> leInIfList );
  941. }
  942. //
  943. // Walk the list of group/source entries that contain this
  944. // interface (for this protocol) and delete the references
  945. // to this interface. References in this case are nothing but
  946. // group memberships added on this interface.
  947. //
  948. DeleteOutInterfaceRefs( ppeEntry, pieEntry, bIGMP );
  949. //
  950. // if neither IGMP nor a routing protocol remain on this interface
  951. // remove this interface entry.
  952. //
  953. if ( !IS_ADDED_BY_IGMP( pieEntry ) &&
  954. !IS_ADDED_BY_PROTOCOL( pieEntry ) )
  955. {
  956. if ( !IsListEmpty( &pieEntry-> leOutIfList ) ||
  957. !IsListEmpty( &pieEntry-> leInIfList ) )
  958. {
  959. dwErr = ERROR_CAN_NOT_COMPLETE;
  960. TRACE0( ANY, "References remain for interface" );
  961. break;
  962. }
  963. DeleteIfEntry( pieEntry );
  964. }
  965. } while ( FALSE );
  966. //
  967. // release locks
  968. //
  969. if ( bIfLock )
  970. {
  971. RELEASE_IF_LOCK_EXCLUSIVE( dwBucket );
  972. }
  973. //
  974. // Ensure any callbacks for source specific leaves
  975. // (caused by the interface being deleted from MGM)
  976. // are issued.
  977. //
  978. // Bug : 154227
  979. //
  980. InvokeOutstandingCallbacks();
  981. //
  982. // decrement count of interfaces owned by protocol
  983. //
  984. if ( dwErr == NO_ERROR )
  985. {
  986. InterlockedDecrement( &ppe-> dwIfCount );
  987. }
  988. RELEASE_PROTOCOL_LOCK_SHARED();
  989. TRACE1( ENTER, "LEAVING MgmReleaseInterfaceOwnership %x\n", dwErr );
  990. LEAVE_MGM_API();
  991. return dwErr;
  992. }
  993. //----------------------------------------------------------------------------
  994. // MgmAddGroupMembershipEntry
  995. //
  996. //
  997. //----------------------------------------------------------------------------
  998. DWORD
  999. MgmGetProtocolOnInterface(
  1000. IN DWORD dwIfIndex,
  1001. IN DWORD dwIfNextHopAddr,
  1002. IN OUT PDWORD pdwIfProtocolId,
  1003. IN OUT PDWORD pdwIfComponentId
  1004. )
  1005. {
  1006. DWORD dwErr = NO_ERROR, dwIfBucket;
  1007. PLIST_ENTRY pleIfHead;
  1008. PIF_ENTRY pie;
  1009. if ( !ENTER_MGM_API() )
  1010. {
  1011. return ERROR_CAN_NOT_COMPLETE;
  1012. }
  1013. TRACE2(
  1014. ENTER, "ENTERED MgmGetProtocolOnInterface : Interface %x, %x",
  1015. dwIfIndex, dwIfNextHopAddr
  1016. );
  1017. dwIfBucket = IF_TABLE_HASH( dwIfIndex );
  1018. pleIfHead = IF_BUCKET_HEAD( dwIfBucket );
  1019. ACQUIRE_IF_LOCK_SHARED( dwIfBucket );
  1020. do
  1021. {
  1022. pie = GetIfEntry( pleIfHead, dwIfIndex, dwIfNextHopAddr );
  1023. if ( pie == NULL )
  1024. {
  1025. dwErr = ERROR_NOT_FOUND;
  1026. TRACE2(
  1027. ANY, "No interface entry present for interface %x, %x",
  1028. dwIfIndex, dwIfNextHopAddr
  1029. );
  1030. LOGWARN0( IF_NOT_FOUND, dwErr );
  1031. break;
  1032. }
  1033. *pdwIfProtocolId = pie-> dwOwningProtocol;
  1034. *pdwIfComponentId = pie-> dwOwningComponent;
  1035. } while ( FALSE );
  1036. RELEASE_IF_LOCK_SHARED( dwIfBucket );
  1037. TRACE1(
  1038. ENTER, "LEAVING MgmGetProtocolOnInterface : %x\n", dwErr
  1039. );
  1040. LEAVE_MGM_API();
  1041. return dwErr;
  1042. }
  1043. //============================================================================
  1044. // Group membership manipulation API. (addition / deletion / retreival)
  1045. //============================================================================
  1046. //----------------------------------------------------------------------------
  1047. // MgmAddGroupMembershipEntry
  1048. //
  1049. //
  1050. //----------------------------------------------------------------------------
  1051. DWORD
  1052. MgmAddGroupMembershipEntry(
  1053. IN HANDLE hProtocol,
  1054. IN DWORD dwSourceAddr,
  1055. IN DWORD dwSourceMask,
  1056. IN DWORD dwGroupAddr,
  1057. IN DWORD dwGroupMask,
  1058. IN DWORD dwIfIndex,
  1059. IN DWORD dwIfNextHopAddr,
  1060. IN DWORD dwFlags
  1061. )
  1062. {
  1063. BOOL bIfLock = FALSE, bgeLock = FALSE,
  1064. bIGMP = FALSE, bUpdateMfe, bWCFound,
  1065. bNewComp = FALSE;
  1066. DWORD dwErr = NO_ERROR, dwIfBucket,
  1067. dwGrpBucket, dwSrcBucket, dwInd,
  1068. dwWCGrpBucket;
  1069. WORD wSourceAddedBy = 0,
  1070. wNumAddsByIGMP = 0, wNumAddsByRP = 0;
  1071. PPROTOCOL_ENTRY ppeEntry = NULL;
  1072. PIF_ENTRY pieEntry = NULL;
  1073. PGROUP_ENTRY pge = NULL, pgeWC = NULL;
  1074. PSOURCE_ENTRY pse = NULL;
  1075. POUT_IF_ENTRY poie = NULL;
  1076. PIF_REFERENCE_ENTRY pire = NULL;
  1077. LIST_ENTRY leSourceList;
  1078. PCREATION_ALERT_CONTEXT pcac;
  1079. if ( !ENTER_MGM_API() )
  1080. {
  1081. return ERROR_CAN_NOT_COMPLETE;
  1082. }
  1083. TRACE6(
  1084. ENTER, "ENTERED MgmAddGroupMembershipEntry : Interface %x, %x : "
  1085. "Source : %x, %x : Group : %x, %x", dwIfIndex, dwIfNextHopAddr,
  1086. dwSourceAddr, dwSourceMask, dwGroupAddr, dwGroupMask
  1087. );
  1088. ACQUIRE_PROTOCOL_LOCK_SHARED();
  1089. //
  1090. // I. Verify input parameters
  1091. //
  1092. do
  1093. {
  1094. //
  1095. // verify protocol handle
  1096. //
  1097. ppeEntry = (PPROTOCOL_ENTRY)
  1098. ( ( (ULONG_PTR) hProtocol )
  1099. ^ (ULONG_PTR) MGM_CLIENT_HANDLE_TAG );
  1100. dwErr = VerifyProtocolHandle( ppeEntry );
  1101. if ( dwErr != NO_ERROR )
  1102. {
  1103. break;
  1104. }
  1105. //
  1106. // Retrieve interface entry
  1107. //
  1108. dwIfBucket = IF_TABLE_HASH( dwIfIndex );
  1109. ACQUIRE_IF_LOCK_EXCLUSIVE( dwIfBucket );
  1110. bIfLock = TRUE;
  1111. pieEntry = GetIfEntry(
  1112. IF_BUCKET_HEAD( dwIfBucket ), dwIfIndex, dwIfNextHopAddr
  1113. );
  1114. if ( pieEntry == NULL )
  1115. {
  1116. dwErr = ERROR_INVALID_PARAMETER;
  1117. TRACE2(
  1118. ANY, "Specified interface was not found : %d, %d", dwIfIndex,
  1119. dwIfNextHopAddr
  1120. );
  1121. LOGWARN0( IF_NOT_FOUND, dwErr );
  1122. break;
  1123. }
  1124. //
  1125. // Verify interface is owned by protocol making this call,
  1126. // or
  1127. // if this operation is being perfomed by IGMP, verify IGMP is
  1128. // enabled on this interface (in this case the interface may
  1129. // be owned by another routing protocol)
  1130. //
  1131. if ( ( pieEntry-> dwOwningProtocol != ppeEntry-> dwProtocolId ||
  1132. pieEntry-> dwOwningComponent != ppeEntry-> dwComponentId ) &&
  1133. ( !IS_PROTOCOL_IGMP( ppeEntry ) ||
  1134. !IS_ADDED_BY_IGMP( pieEntry ) ) )
  1135. {
  1136. dwErr = ERROR_INVALID_PARAMETER;
  1137. TRACE4(
  1138. ANY, "Interface %d, %d is not owned by protocol %d, %d",
  1139. dwIfIndex, dwIfNextHopAddr, ppeEntry-> dwProtocolId,
  1140. ppeEntry-> dwComponentId
  1141. );
  1142. LOGERR0( IF_DIFFERENT_OWNER, dwErr );
  1143. break;
  1144. }
  1145. bIGMP = IS_PROTOCOL_IGMP( ppeEntry );
  1146. if ( bIGMP )
  1147. {
  1148. //
  1149. // if this operation has been invoked by IGMP,
  1150. // retrieve the entry for the routing protocol component
  1151. // that owns this interface.
  1152. //
  1153. ppeEntry = GetProtocolEntry(
  1154. PROTOCOL_LIST_HEAD(), pieEntry-> dwOwningProtocol,
  1155. pieEntry-> dwOwningComponent
  1156. );
  1157. if ( ppeEntry == NULL )
  1158. {
  1159. dwErr = ERROR_CAN_NOT_COMPLETE;
  1160. TRACE2(
  1161. ANY, "IGMP join failed because owning protocol entry"
  1162. " (%x, %x) not found", pieEntry-> dwOwningProtocol,
  1163. pieEntry-> dwOwningComponent
  1164. );
  1165. break;
  1166. }
  1167. }
  1168. } while ( FALSE );
  1169. //
  1170. // return, if parameter validation fails
  1171. //
  1172. if ( dwErr != NO_ERROR )
  1173. {
  1174. if ( bIfLock )
  1175. {
  1176. RELEASE_IF_LOCK_EXCLUSIVE( dwIfBucket );
  1177. }
  1178. RELEASE_PROTOCOL_LOCK_SHARED();
  1179. TRACE1( ENTER, "LEAVING MgmAddGroupMembership %x\n", dwErr );
  1180. LEAVE_MGM_API();
  1181. return dwErr;
  1182. }
  1183. //
  1184. // for JOIN STATE changes, i.e for group membership additions
  1185. //
  1186. if ( dwFlags & MGM_JOIN_STATE_FLAG )
  1187. {
  1188. //
  1189. // Add membership entry
  1190. //
  1191. InitializeListHead( &leSourceList );
  1192. dwErr = AddInterfaceToSourceEntry(
  1193. ppeEntry, dwGroupAddr, dwGroupMask,
  1194. dwSourceAddr, dwSourceMask, dwIfIndex,
  1195. dwIfNextHopAddr, bIGMP, &bUpdateMfe,
  1196. &leSourceList
  1197. );
  1198. if ( dwErr == NO_ERROR )
  1199. {
  1200. //
  1201. // Add to an outgoing interface reference for this group
  1202. //
  1203. AddSourceToRefList(
  1204. &pieEntry-> leOutIfList, dwSourceAddr, dwSourceMask,
  1205. dwGroupAddr, dwGroupMask, bIGMP
  1206. );
  1207. }
  1208. //
  1209. // release locks in prepapation for updating MFEs
  1210. // (invoking creation alerts when updating MFEs requires
  1211. // all locks to be released)
  1212. //
  1213. // When locks are re-acquired you need to verify that
  1214. // the interface (dwIfIndex, dwIfNextHopAddr) and the
  1215. // group membership being added is still present.
  1216. // Any one of those could be deleted in another thread
  1217. // when the locks are released.
  1218. //
  1219. if ( bIfLock )
  1220. {
  1221. RELEASE_IF_LOCK_EXCLUSIVE( dwIfBucket );
  1222. bIfLock = FALSE;
  1223. }
  1224. //
  1225. // Invoke pended Join/Prune alerts
  1226. //
  1227. InvokeOutstandingCallbacks();
  1228. //
  1229. // Update MFEs if required
  1230. //
  1231. if ( ( dwErr == NO_ERROR ) && bUpdateMfe )
  1232. {
  1233. //
  1234. // Queue a work item to update the MFEs
  1235. // Creation alerts have to be invoked from a separate
  1236. // thread. This is done to avoid calling back into the
  1237. // protocol (from MGM) in the context of an add membership
  1238. // call from the the protocol (into MGM). Doing so results
  1239. // in deadlocks (bug #323388)
  1240. //
  1241. pcac = MGM_ALLOC( sizeof( CREATION_ALERT_CONTEXT ) );
  1242. if ( pcac != NULL )
  1243. {
  1244. pcac-> dwSourceAddr = dwSourceAddr;
  1245. pcac-> dwSourceMask = dwSourceMask;
  1246. pcac-> dwGroupAddr = dwGroupAddr;
  1247. pcac-> dwGroupMask = dwGroupMask;
  1248. pcac-> dwIfIndex = dwIfIndex;
  1249. pcac-> dwIfNextHopAddr = dwIfNextHopAddr;
  1250. pcac-> dwProtocolId = ppeEntry-> dwProtocolId;
  1251. pcac-> dwComponentId = ppeEntry-> dwComponentId;
  1252. pcac-> bIGMP = bIGMP;
  1253. pcac-> leSourceList = leSourceList;
  1254. leSourceList.Flink-> Blink = &(pcac-> leSourceList);
  1255. leSourceList.Blink-> Flink = &(pcac-> leSourceList);
  1256. dwErr = QueueMgmWorker(
  1257. WorkerFunctionInvokeCreationAlert,
  1258. (PVOID)pcac
  1259. );
  1260. if ( dwErr != NO_ERROR )
  1261. {
  1262. TRACE1(
  1263. ANY, "Failed to queue "
  1264. "WorkerFunctionInvokeCreationAlert",
  1265. dwErr
  1266. );
  1267. MGM_FREE( pcac );
  1268. dwErr = NO_ERROR;
  1269. }
  1270. }
  1271. else
  1272. {
  1273. TRACE1(
  1274. ANY, "Failed to allocate %d bytes for work item "
  1275. "context", sizeof( CREATION_ALERT_CONTEXT )
  1276. );
  1277. }
  1278. }
  1279. }
  1280. //
  1281. // For FORWARD state changes only.
  1282. //
  1283. else if ( ( dwFlags & MGM_FORWARD_STATE_FLAG ) &&
  1284. !IS_WILDCARD_GROUP( dwGroupAddr, dwGroupMask ) &&
  1285. !IS_WILDCARD_SOURCE( dwSourceAddr, dwSourceMask ) )
  1286. {
  1287. //
  1288. // Forward state changes are for MFEs only.
  1289. // No (*, G) or (*, *) entries are updated
  1290. //
  1291. do
  1292. {
  1293. //
  1294. // Check for boundaries
  1295. //
  1296. if ( IS_HAS_BOUNDARY_CALLBACK() &&
  1297. HAS_BOUNDARY_CALLBACK()( dwIfIndex, dwGroupAddr ) )
  1298. {
  1299. TRACE0( ANY, "Boundary present of group on interface" );
  1300. break;
  1301. }
  1302. //
  1303. // Check for (*, *) membership
  1304. //
  1305. bWCFound = FindRefEntry(
  1306. &pieEntry-> leOutIfList,
  1307. WILDCARD_SOURCE, WILDCARD_SOURCE_MASK,
  1308. WILDCARD_GROUP, WILDCARD_GROUP_MASK,
  1309. &pire
  1310. );
  1311. if ( bWCFound )
  1312. {
  1313. //
  1314. // (*, *) entry present,
  1315. // get counts for (*, *) membership on interface
  1316. //
  1317. dwWCGrpBucket = GROUP_TABLE_HASH(
  1318. WILDCARD_GROUP, WILDCARD_GROUP_MASK
  1319. );
  1320. ACQUIRE_GROUP_LOCK_SHARED( dwWCGrpBucket );
  1321. pgeWC = GetGroupEntry(
  1322. GROUP_BUCKET_HEAD( dwWCGrpBucket ),
  1323. WILDCARD_GROUP, WILDCARD_GROUP_MASK
  1324. );
  1325. if ( pgeWC != NULL )
  1326. {
  1327. ACQUIRE_GROUP_ENTRY_LOCK_SHARED( pgeWC );
  1328. dwSrcBucket = SOURCE_TABLE_HASH(
  1329. WILDCARD_SOURCE, WILDCARD_SOURCE_MASK
  1330. );
  1331. pse = GetSourceEntry(
  1332. SOURCE_BUCKET_HEAD( pgeWC, dwSrcBucket ),
  1333. WILDCARD_SOURCE, WILDCARD_SOURCE_MASK
  1334. );
  1335. if ( pse != NULL )
  1336. {
  1337. poie = GetOutInterfaceEntry(
  1338. &pse-> leOutIfList,
  1339. dwIfIndex, dwIfNextHopAddr,
  1340. ppeEntry-> dwProtocolId,
  1341. ppeEntry-> dwComponentId
  1342. );
  1343. if ( poie != NULL )
  1344. {
  1345. wSourceAddedBy |= poie-> wAddedByFlag;
  1346. wNumAddsByRP = poie-> wNumAddsByRP;
  1347. }
  1348. }
  1349. }
  1350. }
  1351. //
  1352. // Check for (*, G) membership
  1353. //
  1354. dwGrpBucket = GROUP_TABLE_HASH( dwGroupAddr, dwGroupMask );
  1355. ACQUIRE_GROUP_LOCK_SHARED( dwGrpBucket );
  1356. pge = GetGroupEntry(
  1357. GROUP_BUCKET_HEAD( dwGrpBucket),
  1358. dwGroupAddr, dwGroupMask
  1359. );
  1360. if ( pge != NULL )
  1361. {
  1362. ACQUIRE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  1363. dwSrcBucket = SOURCE_TABLE_HASH(
  1364. WILDCARD_SOURCE, WILDCARD_SOURCE_MASK
  1365. );
  1366. pse = GetSourceEntry(
  1367. SOURCE_BUCKET_HEAD( pge, dwSrcBucket ),
  1368. WILDCARD_SOURCE, WILDCARD_SOURCE_MASK
  1369. );
  1370. if ( pse != NULL )
  1371. {
  1372. //
  1373. // get counts for interface
  1374. // if (*, G) is present on the interface
  1375. //
  1376. poie = GetOutInterfaceEntry(
  1377. &pse-> leOutIfList,
  1378. dwIfIndex, dwIfNextHopAddr,
  1379. ppeEntry-> dwProtocolId,
  1380. ppeEntry-> dwComponentId
  1381. );
  1382. if ( poie != NULL )
  1383. {
  1384. wSourceAddedBy |= poie-> wAddedByFlag;
  1385. wNumAddsByIGMP = poie-> wNumAddsByIGMP;
  1386. wNumAddsByRP += poie-> wNumAddsByRP;
  1387. }
  1388. }
  1389. //
  1390. // Get (S, G) entry
  1391. //
  1392. dwSrcBucket = SOURCE_TABLE_HASH( dwSourceAddr, dwSourceMask );
  1393. pse = GetSourceEntry(
  1394. SOURCE_BUCKET_HEAD( pge, dwSrcBucket ),
  1395. dwSourceAddr, dwSourceMask
  1396. );
  1397. if ( pse != NULL )
  1398. {
  1399. poie = GetOutInterfaceEntry(
  1400. &pse-> leOutIfList,
  1401. dwIfIndex, dwIfNextHopAddr,
  1402. ppeEntry-> dwProtocolId,
  1403. ppeEntry-> dwComponentId
  1404. );
  1405. if ( poie != NULL )
  1406. {
  1407. //
  1408. // Get counts for (S, G) membership if
  1409. // present on interface
  1410. //
  1411. wSourceAddedBy |= poie-> wAddedByFlag;
  1412. wNumAddsByIGMP += poie-> wNumAddsByIGMP;
  1413. wNumAddsByRP += poie-> wNumAddsByRP;
  1414. }
  1415. //
  1416. // Add interface to MFE OIF list if any
  1417. // membership
  1418. //
  1419. if ( wSourceAddedBy )
  1420. {
  1421. AddInterfaceToSourceMfe(
  1422. pge, pse, dwIfIndex, dwIfNextHopAddr,
  1423. ppeEntry-> dwProtocolId,
  1424. ppeEntry-> dwComponentId,
  1425. IS_PROTOCOL_IGMP( ppeEntry ),
  1426. &poie
  1427. );
  1428. poie-> wAddedByFlag |= wSourceAddedBy;
  1429. poie-> wNumAddsByIGMP = wNumAddsByIGMP;
  1430. poie-> wNumAddsByRP = wNumAddsByRP;
  1431. }
  1432. else
  1433. {
  1434. TRACE0(
  1435. ANY, "Forward state not updated as no"
  1436. " memberships present on interface"
  1437. );
  1438. }
  1439. }
  1440. RELEASE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  1441. }
  1442. RELEASE_GROUP_LOCK_SHARED( dwGrpBucket );
  1443. if ( bWCFound )
  1444. {
  1445. if ( pgeWC )
  1446. {
  1447. RELEASE_GROUP_ENTRY_LOCK_SHARED( pgeWC );
  1448. }
  1449. RELEASE_GROUP_LOCK_SHARED( dwWCGrpBucket );
  1450. }
  1451. } while ( FALSE );
  1452. }
  1453. if ( bIfLock )
  1454. {
  1455. RELEASE_IF_LOCK_EXCLUSIVE( dwIfBucket );
  1456. }
  1457. RELEASE_PROTOCOL_LOCK_SHARED();
  1458. TRACE1( ENTER, "LEAVING MgmAddGroupMembership %x\n", dwErr );
  1459. LEAVE_MGM_API();
  1460. return dwErr;
  1461. }
  1462. //----------------------------------------------------------------------------
  1463. // MgmDeleteGroupMembershipEntry
  1464. //
  1465. //
  1466. //----------------------------------------------------------------------------
  1467. DWORD
  1468. MgmDeleteGroupMembershipEntry(
  1469. IN HANDLE hProtocol,
  1470. IN DWORD dwSourceAddr,
  1471. IN DWORD dwSourceMask,
  1472. IN DWORD dwGroupAddr,
  1473. IN DWORD dwGroupMask,
  1474. IN DWORD dwIfIndex,
  1475. IN DWORD dwIfNextHopAddr,
  1476. IN DWORD dwFlags
  1477. )
  1478. {
  1479. BOOL bIfLock = FALSE, bIGMP;
  1480. DWORD dwErr = NO_ERROR, dwIfBucket,
  1481. dwGrpBucket, dwSrcBucket;
  1482. PGROUP_ENTRY pge = NULL;
  1483. PSOURCE_ENTRY pse = NULL;
  1484. PPROTOCOL_ENTRY ppeEntry = NULL;
  1485. PIF_ENTRY pieEntry = NULL;
  1486. if ( !ENTER_MGM_API() )
  1487. {
  1488. return ERROR_CAN_NOT_COMPLETE;
  1489. }
  1490. TRACE6(
  1491. ENTER, "ENTERED MgmDeleteGroupMembership : Interface %x, %x : "
  1492. "Source : %x, %x : Group : %x, %x", dwIfIndex, dwIfNextHopAddr,
  1493. dwSourceAddr, dwSourceMask, dwGroupAddr, dwGroupMask
  1494. );
  1495. ACQUIRE_PROTOCOL_LOCK_SHARED();
  1496. //
  1497. // Verify input parameters.
  1498. //
  1499. do
  1500. {
  1501. //
  1502. // verify protocol handle
  1503. //
  1504. ppeEntry = (PPROTOCOL_ENTRY)
  1505. ( ( (ULONG_PTR) hProtocol )
  1506. ^ (ULONG_PTR) MGM_CLIENT_HANDLE_TAG );
  1507. dwErr = VerifyProtocolHandle( ppeEntry );
  1508. if ( dwErr != NO_ERROR )
  1509. {
  1510. break;
  1511. }
  1512. //
  1513. // Retrieve interface entry
  1514. //
  1515. dwIfBucket = IF_TABLE_HASH( dwIfIndex );
  1516. ACQUIRE_IF_LOCK_EXCLUSIVE( dwIfBucket );
  1517. bIfLock = TRUE;
  1518. pieEntry = GetIfEntry(
  1519. IF_BUCKET_HEAD( dwIfBucket ), dwIfIndex, dwIfNextHopAddr
  1520. );
  1521. if ( pieEntry == NULL )
  1522. {
  1523. dwErr = ERROR_NOT_FOUND;
  1524. TRACE0( ANY, "Specified interface was not found" );
  1525. break;
  1526. }
  1527. //
  1528. // Verify interface is owned by protocol making this call.
  1529. // or
  1530. // if IGMP has invoked this api, verify that IGMP is present
  1531. // on this interface.
  1532. //
  1533. if ( ( pieEntry-> dwOwningProtocol != ppeEntry-> dwProtocolId ||
  1534. pieEntry-> dwOwningComponent != ppeEntry-> dwComponentId ) &&
  1535. ( !IS_PROTOCOL_IGMP( ppeEntry ) ||
  1536. !IS_ADDED_BY_IGMP( pieEntry ) ) )
  1537. {
  1538. dwErr = ERROR_INVALID_PARAMETER;
  1539. TRACE4(
  1540. ANY, "Interface %x, %x is not owned by %x, %x",
  1541. dwIfIndex, dwIfNextHopAddr, ppeEntry-> dwProtocolId,
  1542. ppeEntry-> dwComponentId
  1543. );
  1544. LOGERR0( IF_DIFFERENT_OWNER, dwErr );
  1545. break;
  1546. }
  1547. //
  1548. // in case this operation is being performed by IGMP
  1549. // get the routing protocol that co-exists with IGMP
  1550. // on this interface
  1551. //
  1552. bIGMP = IS_PROTOCOL_IGMP( ppeEntry );
  1553. if ( bIGMP )
  1554. {
  1555. //
  1556. // if this operation has been invoked by IGMP,
  1557. // retrieve the entry for the routing protocol component
  1558. // that owns this interface.
  1559. //
  1560. ppeEntry = GetProtocolEntry(
  1561. PROTOCOL_LIST_HEAD(), pieEntry-> dwOwningProtocol,
  1562. pieEntry-> dwOwningComponent
  1563. );
  1564. if ( ppeEntry == NULL )
  1565. {
  1566. dwErr = ERROR_CAN_NOT_COMPLETE;
  1567. TRACE2(
  1568. ANY, "IGMP join failed because owning protocol entry"
  1569. " (%x, %x) not found", pieEntry-> dwOwningProtocol,
  1570. pieEntry-> dwOwningComponent
  1571. );
  1572. break;
  1573. }
  1574. }
  1575. } while ( FALSE );
  1576. //
  1577. // in case of error, release locks and return
  1578. //
  1579. if ( dwErr != NO_ERROR )
  1580. {
  1581. if ( bIfLock )
  1582. {
  1583. RELEASE_IF_LOCK_EXCLUSIVE( dwIfBucket );
  1584. }
  1585. RELEASE_PROTOCOL_LOCK_SHARED();
  1586. TRACE1( ENTER, "LEAVING MgmDeleteGroupMembership %x\n", dwErr );
  1587. LEAVE_MGM_API();
  1588. return dwErr;
  1589. }
  1590. //
  1591. // For JOIN state change
  1592. //
  1593. if ( dwFlags & MGM_JOIN_STATE_FLAG )
  1594. {
  1595. //
  1596. // delete interface from source entry
  1597. //
  1598. DeleteInterfaceFromSourceEntry(
  1599. ppeEntry, dwGroupAddr, dwGroupMask,
  1600. dwSourceAddr, dwSourceMask,
  1601. dwIfIndex, dwIfNextHopAddr, bIGMP
  1602. );
  1603. //
  1604. // delete reference entry
  1605. //
  1606. DeleteSourceFromRefList(
  1607. &pieEntry-> leOutIfList, dwSourceAddr, dwSourceMask,
  1608. dwGroupAddr, dwGroupMask, bIGMP
  1609. );
  1610. //
  1611. // release locks
  1612. //
  1613. if ( bIfLock )
  1614. {
  1615. RELEASE_IF_LOCK_EXCLUSIVE( dwIfBucket );
  1616. bIfLock = FALSE;
  1617. }
  1618. //
  1619. // Invoke pended Join/Prune alerts
  1620. //
  1621. InvokeOutstandingCallbacks();
  1622. }
  1623. //
  1624. // For FORWARD state changes
  1625. //
  1626. else if ( ( dwFlags & MGM_FORWARD_STATE_FLAG ) &&
  1627. !IS_WILDCARD_GROUP( dwGroupAddr, dwGroupMask ) &&
  1628. !IS_WILDCARD_SOURCE( dwSourceAddr, dwSourceMask ) )
  1629. {
  1630. //
  1631. // FORWARD state changes are for MFEs only.
  1632. // No (*, *) or (*, G) entries are updated
  1633. //
  1634. //
  1635. // Find the (S, G) entry and delete the group membership
  1636. //
  1637. dwGrpBucket = GROUP_TABLE_HASH( dwGroupAddr, dwGroupMask );
  1638. ACQUIRE_GROUP_LOCK_SHARED( dwGrpBucket );
  1639. pge = GetGroupEntry(
  1640. GROUP_BUCKET_HEAD( dwGrpBucket ),
  1641. dwGroupAddr, dwGroupMask
  1642. );
  1643. if ( pge != NULL )
  1644. {
  1645. ACQUIRE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  1646. dwSrcBucket = SOURCE_TABLE_HASH( dwSourceAddr, dwSourceMask );
  1647. pse = GetSourceEntry(
  1648. SOURCE_BUCKET_HEAD( pge, dwSrcBucket ),
  1649. dwSourceAddr, dwSourceMask
  1650. );
  1651. if ( pse != NULL )
  1652. {
  1653. DeleteInterfaceFromSourceMfe(
  1654. pge, pse, dwIfIndex, dwIfNextHopAddr,
  1655. ppeEntry-> dwProtocolId,
  1656. ppeEntry-> dwComponentId, bIGMP, TRUE
  1657. );
  1658. }
  1659. RELEASE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  1660. }
  1661. RELEASE_GROUP_LOCK_SHARED( dwGrpBucket );
  1662. }
  1663. //
  1664. // release locks
  1665. //
  1666. if ( bIfLock )
  1667. {
  1668. RELEASE_IF_LOCK_EXCLUSIVE( dwIfBucket );
  1669. }
  1670. RELEASE_PROTOCOL_LOCK_SHARED();
  1671. TRACE1( ENTER, "LEAVING MgmDeleteGroupMembership %x\n", dwErr );
  1672. LEAVE_MGM_API();
  1673. return dwErr;
  1674. }
  1675. //----------------------------------------------------------------------------
  1676. // Mgm MFE Update API.
  1677. //
  1678. //----------------------------------------------------------------------------
  1679. DWORD
  1680. MgmSetMfe(
  1681. IN HANDLE hProtocol,
  1682. IN PMIB_IPMCAST_MFE pmimm
  1683. )
  1684. {
  1685. BOOL bGrpLock = FALSE, bgeLock = FALSE;
  1686. DWORD dwErr = NO_ERROR, dwGrpBucket, dwSrcBucket;
  1687. PPROTOCOL_ENTRY ppeEntry;
  1688. PGROUP_ENTRY pge;
  1689. PSOURCE_ENTRY pse;
  1690. //
  1691. // Check if MGM is still running and increment counts
  1692. //
  1693. if ( !ENTER_MGM_API() )
  1694. {
  1695. return ERROR_CAN_NOT_COMPLETE;
  1696. }
  1697. TRACE2(
  1698. ENTER, "ENTERED MgmSetMfe : (%lx, %lx)", pmimm-> dwSource,
  1699. pmimm-> dwGroup
  1700. );
  1701. ACQUIRE_PROTOCOL_LOCK_SHARED();
  1702. do
  1703. {
  1704. //
  1705. // Verify protocol handle
  1706. //
  1707. ppeEntry = (PPROTOCOL_ENTRY)
  1708. ( ( (ULONG_PTR) hProtocol )
  1709. ^ (ULONG_PTR) MGM_CLIENT_HANDLE_TAG );
  1710. dwErr = VerifyProtocolHandle( ppeEntry );
  1711. if ( dwErr != NO_ERROR )
  1712. {
  1713. break;
  1714. }
  1715. //
  1716. // Get group bucket and find group entry
  1717. //
  1718. dwGrpBucket = GROUP_TABLE_HASH( pmimm-> dwGroup, 0 );
  1719. ACQUIRE_GROUP_LOCK_SHARED( dwGrpBucket );
  1720. bGrpLock = TRUE;
  1721. pge = GetGroupEntry(
  1722. GROUP_BUCKET_HEAD( dwGrpBucket ), pmimm-> dwGroup, 0
  1723. );
  1724. if ( pge == NULL )
  1725. {
  1726. dwErr = ERROR_NOT_FOUND;
  1727. TRACE1( ANY, "Group %lx not found", pmimm-> dwGroup );
  1728. break;
  1729. }
  1730. ACQUIRE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  1731. bgeLock = TRUE;
  1732. //
  1733. // Find source with group entry
  1734. //
  1735. dwSrcBucket = SOURCE_TABLE_HASH(
  1736. pmimm-> dwSource, pmimm-> dwSrcMask
  1737. );
  1738. pse = GetSourceEntry(
  1739. SOURCE_BUCKET_HEAD( pge, dwSrcBucket ), pmimm-> dwSource,
  1740. pmimm-> dwSrcMask
  1741. );
  1742. if ( pse == NULL )
  1743. {
  1744. dwErr = ERROR_NOT_FOUND;
  1745. TRACE1( ANY, "Source %lx not found", pmimm-> dwSource );
  1746. break;
  1747. }
  1748. //
  1749. // Update the source entry
  1750. //
  1751. pse-> dwUpstreamNeighbor = pmimm-> dwUpStrmNgbr;
  1752. } while ( FALSE );
  1753. if ( bgeLock )
  1754. {
  1755. RELEASE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  1756. }
  1757. if ( bGrpLock )
  1758. {
  1759. RELEASE_GROUP_LOCK_SHARED( dwGrpBucket );
  1760. }
  1761. RELEASE_PROTOCOL_LOCK_SHARED();
  1762. LEAVE_MGM_API();
  1763. return dwErr;
  1764. }
  1765. //----------------------------------------------------------------------------
  1766. // Mgm MFE enumeration API.
  1767. //
  1768. //----------------------------------------------------------------------------
  1769. DWORD
  1770. MgmGetMfe(
  1771. IN PMIB_IPMCAST_MFE pmimm,
  1772. IN OUT PDWORD pdwBufferSize,
  1773. IN OUT PBYTE pbBuffer
  1774. )
  1775. {
  1776. DWORD dwErr;
  1777. if ( !ENTER_MGM_API() )
  1778. {
  1779. return ERROR_CAN_NOT_COMPLETE;
  1780. }
  1781. TRACE1( ENTER, "ENTERED MgmGetMfe", *pdwBufferSize );
  1782. dwErr = GetMfe( pmimm, pdwBufferSize, pbBuffer, 0 );
  1783. TRACE1( ENTER, "LEAVING MgmGetMfe %x\n", dwErr );
  1784. LEAVE_MGM_API();
  1785. return dwErr;
  1786. }
  1787. //----------------------------------------------------------------------------
  1788. // Mgm MFE enumeration API.
  1789. //
  1790. //----------------------------------------------------------------------------
  1791. DWORD
  1792. MgmGetFirstMfe(
  1793. IN OUT PDWORD pdwBufferSize,
  1794. IN OUT PBYTE pbBuffer,
  1795. IN OUT PDWORD pdwNumEntries
  1796. )
  1797. {
  1798. DWORD dwErr;
  1799. MIB_IPMCAST_MFE mimm;
  1800. if ( !ENTER_MGM_API() )
  1801. {
  1802. return ERROR_CAN_NOT_COMPLETE;
  1803. }
  1804. TRACE1( ENTER, "ENTERED MgmGetFirstMfe", *pdwBufferSize );
  1805. mimm.dwGroup = 0;
  1806. mimm.dwSource = 0;
  1807. mimm.dwSrcMask = 0;
  1808. dwErr = GetNextMfe(
  1809. &mimm, pdwBufferSize, pbBuffer, pdwNumEntries,
  1810. TRUE, 0
  1811. );
  1812. TRACE1( ENTER, "LEAVING MgmGetFirstMfe %x\n", dwErr );
  1813. LEAVE_MGM_API();
  1814. return dwErr;
  1815. }
  1816. //----------------------------------------------------------------------------
  1817. // Mgm MFE enumeration API.
  1818. //
  1819. //----------------------------------------------------------------------------
  1820. DWORD
  1821. MgmGetNextMfe(
  1822. IN PMIB_IPMCAST_MFE pmimmStart,
  1823. IN OUT PDWORD pdwBufferSize,
  1824. IN OUT PBYTE pbBuffer,
  1825. IN OUT PDWORD pdwNumEntries
  1826. )
  1827. {
  1828. DWORD dwErr;
  1829. if ( !ENTER_MGM_API() )
  1830. {
  1831. return ERROR_CAN_NOT_COMPLETE;
  1832. }
  1833. TRACE1( ENTER, "ENTERED MgmGetNextMfe", *pdwBufferSize );
  1834. dwErr = GetNextMfe(
  1835. pmimmStart, pdwBufferSize, pbBuffer, pdwNumEntries,
  1836. FALSE, 0
  1837. );
  1838. TRACE1( ENTER, "LEAVING MgmGetNextMfe %x\n", dwErr );
  1839. LEAVE_MGM_API();
  1840. return dwErr;
  1841. }
  1842. //----------------------------------------------------------------------------
  1843. // Mgm MFE Statistics enumeration API.
  1844. //
  1845. //----------------------------------------------------------------------------
  1846. DWORD
  1847. MgmGetMfeStats(
  1848. IN PMIB_IPMCAST_MFE pmimm,
  1849. IN OUT PDWORD pdwBufferSize,
  1850. IN OUT PBYTE pbBuffer,
  1851. IN DWORD dwFlags
  1852. )
  1853. {
  1854. DWORD dwErr;
  1855. if ( !ENTER_MGM_API() )
  1856. {
  1857. return ERROR_CAN_NOT_COMPLETE;
  1858. }
  1859. TRACE1( ENTER, "ENTERED MgmGetMfeStats", *pdwBufferSize );
  1860. dwErr = GetMfe( pmimm, pdwBufferSize, pbBuffer, dwFlags );
  1861. TRACE1( ENTER, "LEAVING MgmGetMfeStats %x\n", dwErr );
  1862. LEAVE_MGM_API();
  1863. return dwErr;
  1864. }
  1865. //----------------------------------------------------------------------------
  1866. // Mgm MFE Statistics enumeration API.
  1867. //
  1868. //----------------------------------------------------------------------------
  1869. DWORD
  1870. MgmGetFirstMfeStats(
  1871. IN OUT PDWORD pdwBufferSize,
  1872. IN OUT PBYTE pbBuffer,
  1873. IN OUT PDWORD pdwNumEntries,
  1874. IN DWORD dwFlags
  1875. )
  1876. {
  1877. DWORD dwErr;
  1878. MIB_IPMCAST_MFE mimm;
  1879. if ( !ENTER_MGM_API() )
  1880. {
  1881. return ERROR_CAN_NOT_COMPLETE;
  1882. }
  1883. TRACE1( ENTER, "ENTERED MgmGetFirstMfeStats", *pdwBufferSize );
  1884. mimm.dwGroup = 0;
  1885. mimm.dwSource = 0;
  1886. mimm.dwSrcMask = 0;
  1887. dwErr = GetNextMfe(
  1888. &mimm, pdwBufferSize, pbBuffer, pdwNumEntries,
  1889. TRUE, dwFlags
  1890. );
  1891. TRACE1( ENTER, "LEAVING MgmGetFirstMfeStats %x\n", dwErr );
  1892. LEAVE_MGM_API();
  1893. return dwErr;
  1894. }
  1895. //----------------------------------------------------------------------------
  1896. // Mgm MFE Statistics enumeration API.
  1897. //
  1898. //----------------------------------------------------------------------------
  1899. DWORD
  1900. MgmGetNextMfeStats(
  1901. IN PMIB_IPMCAST_MFE pmimmStart,
  1902. IN OUT PDWORD pdwBufferSize,
  1903. IN OUT PBYTE pbBuffer,
  1904. IN OUT PDWORD pdwNumEntries,
  1905. IN DWORD dwFlags
  1906. )
  1907. {
  1908. DWORD dwErr;
  1909. if ( !ENTER_MGM_API() )
  1910. {
  1911. return ERROR_CAN_NOT_COMPLETE;
  1912. }
  1913. TRACE1( ENTER, "ENTERED MgmGetNextMfeStats", *pdwBufferSize );
  1914. dwErr = GetNextMfe(
  1915. pmimmStart, pdwBufferSize, pbBuffer, pdwNumEntries,
  1916. FALSE, dwFlags
  1917. );
  1918. TRACE1( ENTER, "LEAVING MgmGetNextMfeStats %x\n", dwErr );
  1919. LEAVE_MGM_API();
  1920. return dwErr;
  1921. }
  1922. //----------------------------------------------------------------------------
  1923. // Group menbership entry enumeration API
  1924. //----------------------------------------------------------------------------
  1925. //----------------------------------------------------------------------------
  1926. // MgmGroupEnumerationStart
  1927. //
  1928. //
  1929. //----------------------------------------------------------------------------
  1930. DWORD
  1931. MgmGroupEnumerationStart(
  1932. IN HANDLE hProtocol,
  1933. IN MGM_ENUM_TYPES metEnumType,
  1934. OUT HANDLE * phEnumHandle
  1935. )
  1936. {
  1937. DWORD dwErr = NO_ERROR;
  1938. PPROTOCOL_ENTRY ppeEntry;
  1939. PGROUP_ENUMERATOR pgeEnum;
  1940. if ( !ENTER_MGM_API() )
  1941. {
  1942. return ERROR_CAN_NOT_COMPLETE;
  1943. }
  1944. TRACE0( ENTER, "ENTERED MgmGroupEnumerationStart" );
  1945. ACQUIRE_PROTOCOL_LOCK_SHARED();
  1946. do
  1947. {
  1948. //
  1949. // verify protocol handle
  1950. //
  1951. ppeEntry = (PPROTOCOL_ENTRY)
  1952. ( ( (ULONG_PTR) hProtocol )
  1953. ^ (ULONG_PTR) MGM_CLIENT_HANDLE_TAG );
  1954. dwErr = VerifyProtocolHandle( ppeEntry );
  1955. if ( dwErr != NO_ERROR )
  1956. {
  1957. break;
  1958. }
  1959. //
  1960. // create an enumerator.
  1961. //
  1962. pgeEnum = MGM_ALLOC( sizeof( GROUP_ENUMERATOR ) );
  1963. if ( pgeEnum == NULL )
  1964. {
  1965. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1966. TRACE1(
  1967. ANY, "Failed to allocate group enumerator of size : %d",
  1968. sizeof( GROUP_ENUMERATOR )
  1969. );
  1970. LOGERR0( HEAP_ALLOC_FAILED, dwErr );
  1971. break;
  1972. }
  1973. ZeroMemory( pgeEnum, sizeof( GROUP_ENUMERATOR ) );
  1974. pgeEnum-> dwSignature = MGM_ENUM_SIGNATURE;
  1975. //
  1976. // return handle to the enumerator.
  1977. //
  1978. *phEnumHandle = (HANDLE) ( ( (ULONG_PTR) pgeEnum )
  1979. ^ (ULONG_PTR) MGM_ENUM_HANDLE_TAG );
  1980. } while ( FALSE );
  1981. RELEASE_PROTOCOL_LOCK_SHARED();
  1982. TRACE1( ENTER, "LEAVING MgmGroupEnumerationStart\n", dwErr );
  1983. LEAVE_MGM_API();
  1984. return dwErr;
  1985. }
  1986. //----------------------------------------------------------------------------
  1987. // MgmGroupEnumerationGetNext
  1988. //
  1989. //
  1990. //----------------------------------------------------------------------------
  1991. DWORD
  1992. MgmGroupEnumerationGetNext(
  1993. IN HANDLE hEnum,
  1994. IN OUT PDWORD pdwBufferSize,
  1995. IN OUT PBYTE pbBuffer,
  1996. IN OUT PDWORD pdwNumEntries
  1997. )
  1998. {
  1999. DWORD dwErr;
  2000. PGROUP_ENUMERATOR pgeEnum;
  2001. if ( !ENTER_MGM_API() )
  2002. {
  2003. return ERROR_CAN_NOT_COMPLETE;
  2004. }
  2005. TRACE0( ENTER, "ENTERED MgmGroupEnumerationGetNext" );
  2006. do
  2007. {
  2008. //
  2009. // verify enumeration handle
  2010. //
  2011. pgeEnum = VerifyEnumeratorHandle( hEnum );
  2012. if ( pgeEnum == NULL )
  2013. {
  2014. dwErr = ERROR_INVALID_PARAMETER;
  2015. break;
  2016. }
  2017. //
  2018. // verify buffer has space for atleast one entry.
  2019. // Otherwise return error and note size required for
  2020. // atleast one entry.
  2021. //
  2022. if ( *pdwBufferSize < sizeof( SOURCE_GROUP_ENTRY ) )
  2023. {
  2024. dwErr = ERROR_INSUFFICIENT_BUFFER;
  2025. TRACE1( ANY, "Insufficient buffer size", dwErr );
  2026. *pdwBufferSize = sizeof( SOURCE_GROUP_ENTRY );
  2027. break;
  2028. }
  2029. *pdwNumEntries = 0;
  2030. dwErr = GetNextGroupMemberships(
  2031. pgeEnum, pdwBufferSize, pbBuffer, pdwNumEntries
  2032. );
  2033. //
  2034. // This comment is to be moved, ignore it.
  2035. //
  2036. // If this is the first enumeration call (i.e this is
  2037. // the beginning of the enumeration) then include the
  2038. // (S, G) == (0, 0) entry if present.
  2039. //
  2040. // Usually this call would start with the (source, group)
  2041. // entry following the one mentioned in dwLastSource and
  2042. // dwLastGroup. This would result in the skipping of the
  2043. // entry at (0, 0) since the (dwLastSource, dwLastGroup) are
  2044. // initialized to (0, 0). To overcome this a special flag
  2045. // field is used to note the beginning of the enumeration.
  2046. //
  2047. //
  2048. // Check if this is the first enumeration call.
  2049. // If so include the (S, G) == (0, 0) entry.
  2050. //
  2051. } while ( FALSE );
  2052. TRACE0( ENTER, "LEAVING MgmGroupEnumerationGetNext\n" );
  2053. LEAVE_MGM_API();
  2054. return dwErr;
  2055. }
  2056. //----------------------------------------------------------------------------
  2057. // MgmGroupEnumerationEnd
  2058. //
  2059. //
  2060. //----------------------------------------------------------------------------
  2061. DWORD
  2062. MgmGroupEnumerationEnd(
  2063. IN HANDLE hEnum
  2064. )
  2065. {
  2066. DWORD dwErr = ERROR_INVALID_PARAMETER;
  2067. PGROUP_ENUMERATOR pgeEnum;
  2068. if ( !ENTER_MGM_API() )
  2069. {
  2070. return ERROR_CAN_NOT_COMPLETE;
  2071. }
  2072. TRACE0( ENTER, "ENTERED MgmGroupEnumerationEnd" );
  2073. pgeEnum = VerifyEnumeratorHandle( hEnum );
  2074. if ( pgeEnum != NULL )
  2075. {
  2076. MGM_FREE( pgeEnum );
  2077. dwErr = NO_ERROR;
  2078. }
  2079. TRACE1( ENTER, "LEAVING MgmGroupEnumerationEnd\n", dwErr );
  2080. LEAVE_MGM_API();
  2081. return dwErr;
  2082. }
  2083. VOID
  2084. DisplayGroupTable(
  2085. )
  2086. {
  2087. #if UNIT_DBG
  2088. DWORD dwErr, dwBufSize, dwNumEntries;
  2089. PLIST_ENTRY pleGrp, pleGrpHead, pleSrc, pleSrcHead,
  2090. pleIf, pleIfHead;
  2091. PGROUP_ENTRY pge;
  2092. PSOURCE_ENTRY pse;
  2093. POUT_IF_ENTRY poie;
  2094. PBYTE pbBuffer = NULL;
  2095. MIB_IPMCAST_MFE imm;
  2096. PMIB_IPMCAST_MFE_STATS pimms;
  2097. //
  2098. // Enumerate the MFEs
  2099. // Since the forwarder is not present, stats are junk.
  2100. // so all mfe enum does is exercise the API and merge
  2101. // the master and temp lists so that the subsequent
  2102. // walks of this list can be done.
  2103. //
  2104. dwBufSize = 1024;
  2105. pbBuffer = HeapAlloc( GetProcessHeap(), 0, dwBufSize );
  2106. RtlZeroMemory( pbBuffer, dwBufSize );
  2107. dwErr = MgmGetFirstMfe( &dwBufSize, pbBuffer, &dwNumEntries );
  2108. if ( dwErr != NO_ERROR )
  2109. {
  2110. printf( "MgmGetFirstMfe returned error : %d\n", dwErr );
  2111. }
  2112. imm.dwSource = 0;
  2113. imm.dwSrcMask = 0xffffffff;
  2114. imm.dwGroup = 0;
  2115. RtlZeroMemory( pbBuffer, dwBufSize );
  2116. dwNumEntries = 0;
  2117. while ( MgmGetNextMfe( &imm, &dwBufSize, pbBuffer, &dwNumEntries )
  2118. == NO_ERROR )
  2119. {
  2120. if ( dwNumEntries == 0 )
  2121. {
  2122. break;
  2123. }
  2124. pimms = (PMIB_IPMCAST_MFE_STATS) pbBuffer;
  2125. imm.dwSource = pimms-> dwSource;
  2126. imm.dwSrcMask = pimms-> dwSrcMask;
  2127. imm.dwGroup = pimms-> dwGroup;
  2128. pimms = (PMIB_IPMCAST_MFE_STATS) ( (PBYTE) pimms +
  2129. SIZEOF_MIB_MFE_STATS( pimms-> ulNumOutIf ) );
  2130. }
  2131. if ( dwErr != NO_ERROR )
  2132. {
  2133. printf( "MgmGetNextMfe returned error : %d\n", dwErr );
  2134. }
  2135. //
  2136. // since there is no kernel mode forwarder, just walk the master
  2137. // list of group entries and display all the group entries
  2138. //
  2139. pleGrpHead = MASTER_GROUP_LIST_HEAD();
  2140. pleGrp = pleGrpHead-> Flink;
  2141. while ( pleGrp != pleGrpHead )
  2142. {
  2143. //
  2144. // display the group entry
  2145. //
  2146. pge = CONTAINING_RECORD( pleGrp, GROUP_ENTRY, leGrpList );
  2147. printf( "\n\n====================================================\n" );
  2148. printf( "Group Addr\t: %x, %x\n", pge-> dwGroupAddr, pge-> dwGroupMask );
  2149. printf( "Num Sources\t: %d\n", pge-> dwSourceCount );
  2150. printf( "====================================================\n\n" );
  2151. pleSrcHead = MASTER_SOURCE_LIST_HEAD( pge );
  2152. pleSrc = pleSrcHead-> Flink;
  2153. while ( pleSrc != pleSrcHead )
  2154. {
  2155. pse = CONTAINING_RECORD( pleSrc, SOURCE_ENTRY, leSrcList );
  2156. printf( "\n-----------------------Source----------------------------------" );
  2157. printf( "\nSource Addr\t: %x, %x\n", pse-> dwSourceAddr, pse-> dwSourceMask );
  2158. printf(
  2159. "Route Addr\t: %x, %x\n", pse-> dwRouteNetwork, pse-> dwRouteMask
  2160. );
  2161. printf(
  2162. "Out if component: %d\nOut if count\t: %d\n\n", pse-> dwOutCompCount,
  2163. pse-> dwOutIfCount
  2164. );
  2165. printf(
  2166. "In coming interface : %d, %x\n", pse-> dwInIfIndex,
  2167. pse-> dwInIfNextHopAddr
  2168. );
  2169. printf(
  2170. "In Protocol id : %x, %x\n\n", pse-> dwInProtocolId,
  2171. pse-> dwInComponentId
  2172. );
  2173. //
  2174. // list all outgoing interfaces
  2175. //
  2176. pleIfHead = &pse-> leOutIfList;
  2177. pleIf = pleIfHead-> Flink;
  2178. printf( "\n----------------------Out Interfaces-----------------\n" );
  2179. while ( pleIf != pleIfHead )
  2180. {
  2181. poie = CONTAINING_RECORD( pleIf, OUT_IF_ENTRY, leIfList );
  2182. printf(
  2183. "Out interface\t: %d, %x\n", poie-> dwIfIndex,
  2184. poie-> dwIfNextHopAddr
  2185. );
  2186. printf(
  2187. "Out Protocol id\t: %x, %x\n", poie-> dwProtocolId,
  2188. poie-> dwComponentId
  2189. );
  2190. printf(
  2191. "Added by\t: %x\n", poie-> wAddedByFlag
  2192. );
  2193. printf(
  2194. "Num adds (IGMP, RP)\t: (%d, %d)\n\n", poie-> wNumAddsByIGMP,
  2195. poie-> wNumAddsByRP
  2196. );
  2197. pleIf = pleIf-> Flink;
  2198. }
  2199. //
  2200. // list mfe oil
  2201. //
  2202. pleIfHead = &pse-> leMfeIfList;
  2203. pleIf = pleIfHead-> Flink;
  2204. printf( "\n------------------Mfe Out Interfaces-----------------\n" );
  2205. while ( pleIf != pleIfHead )
  2206. {
  2207. poie = CONTAINING_RECORD( pleIf, OUT_IF_ENTRY, leIfList );
  2208. printf(
  2209. "Out interface\t: %d, %x\n", poie-> dwIfIndex,
  2210. poie-> dwIfNextHopAddr
  2211. );
  2212. printf(
  2213. "Out Protocol id\t: %x, %x\n", poie-> dwProtocolId,
  2214. poie-> dwComponentId
  2215. );
  2216. printf(
  2217. "Added by\t:%x\n", poie-> wAddedByFlag
  2218. );
  2219. printf(
  2220. "Num adds (IGMP, RP)\t: (%d, %d)\n\n", poie-> wNumAddsByIGMP,
  2221. poie-> wNumAddsByRP
  2222. );
  2223. pleIf = pleIf-> Flink;
  2224. }
  2225. pleSrc = pleSrc-> Flink;
  2226. }
  2227. pleGrp = pleGrp-> Flink;
  2228. }
  2229. #endif
  2230. }