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.

3206 lines
86 KiB

  1. //============================================================================
  2. // Copyright (c) 1995, Microsoft Corporation
  3. //
  4. // File: scope.c
  5. //
  6. // History:
  7. // V Raman June-25-1997 Created.
  8. //
  9. // Functions that deal with addition/deletion of scope-boundary.
  10. //============================================================================
  11. #include "pchmgm.h"
  12. #pragma hdrstop
  13. //
  14. // prototypes for local functions
  15. //
  16. VOID
  17. ScopeIfAndInvokeCallbacks(
  18. PGROUP_ENTRY pge,
  19. PSOURCE_ENTRY pse,
  20. POUT_IF_ENTRY poie
  21. );
  22. VOID
  23. UnScopeIfAndInvokeCallbacks(
  24. PGROUP_ENTRY pge,
  25. PSOURCE_ENTRY pse,
  26. POUT_IF_ENTRY poie
  27. );
  28. PJOIN_ENTRY
  29. GetNextJoinEntry(
  30. );
  31. BOOL
  32. FindJoinEntry(
  33. PLIST_ENTRY pleJoinList,
  34. DWORD dwSourceAddr,
  35. DWORD dwSourceMask,
  36. DWORD dwGroupAddr,
  37. DWORD dwGroupMask,
  38. DWORD dwIfIndex,
  39. DWORD dwIfNextHopAddr,
  40. PJOIN_ENTRY * ppje
  41. );
  42. DWORD
  43. APIENTRY
  44. MgmBlockGroups(
  45. IN DWORD dwFirstGroup,
  46. IN DWORD dwLastGroup,
  47. IN DWORD dwIfIndex,
  48. IN DWORD dwIfNextHopAddr
  49. )
  50. /*++
  51. Routine Description :
  52. This function walks the Master group list and updates all group entries
  53. that fall in the range specified by dwFirstGroup-dwLastGroup. It ensures
  54. that the interface specified by dwifIndex is not present in the OIF list
  55. of any MFE for groups in that range. In addition any memberships for
  56. groups in the range on interface dwIfIndex are removed and added to the
  57. scoped interface list for the corresponding group. The scoped i/f list
  58. is maintained so that subsequent unblocking of a group is transparently
  59. handled by MGM. The interfaces present in the scoped i/f list for
  60. a group are automatically moved back to the OIF list when traffic for
  61. that group is unblocked.
  62. Arguements :
  63. dwFirstGroup - Lower end of the range to be blocked
  64. dwLastGroup - Upper end of the range to be blocked
  65. dwIfIndex - Interface on which traffic is to be blocked
  66. Return Value :
  67. NO_ERROR - Success
  68. Environment :
  69. This routine is invoked by the IP RouterManager in response to setting
  70. of a administrative scoped boundary on an interface.
  71. --*/
  72. {
  73. INT iCmp;
  74. DWORD dwIfBucket, dwTimeOut = 0;
  75. BOOL bFound, bDeleteCallback, bNewComp = FALSE;
  76. PIF_ENTRY pieIfEntry;
  77. PPROTOCOL_ENTRY ppe;
  78. PGROUP_ENTRY pge;
  79. PSOURCE_ENTRY pse;
  80. POUT_IF_ENTRY poie, poieTemp;
  81. PLIST_ENTRY pleGrpHead, pleGrp, pleSrcHead, pleSrc, ple;
  82. //
  83. // Verify that MGM is up and running and update thread-count
  84. //
  85. if ( !ENTER_MGM_API() )
  86. {
  87. return ERROR_CAN_NOT_COMPLETE;
  88. }
  89. TRACE3(
  90. SCOPE, "ENTERED MgmBlockGroups (%lx - %lx) on %lx",
  91. dwFirstGroup, dwLastGroup, dwIfIndex
  92. );
  93. do
  94. {
  95. ACQUIRE_PROTOCOL_LOCK_SHARED();
  96. //
  97. // Verify that interface specified by dwIfIndex exists
  98. //
  99. dwIfBucket = IF_TABLE_HASH( dwIfIndex );
  100. ACQUIRE_IF_LOCK_SHARED( dwIfBucket );
  101. pieIfEntry = GetIfEntry(
  102. IF_BUCKET_HEAD( dwIfBucket ), dwIfIndex,
  103. dwIfNextHopAddr
  104. );
  105. if ( pieIfEntry == NULL )
  106. {
  107. TRACE1( SCOPE, "Interface %lx not found", dwIfIndex );
  108. break;
  109. }
  110. //
  111. // merge temp and master group lists
  112. //
  113. ACQUIRE_TEMP_GROUP_LOCK_EXCLUSIVE();
  114. MergeTempAndMasterGroupLists( TEMP_GROUP_LIST_HEAD() );
  115. RELEASE_TEMP_GROUP_LOCK_EXCLUSIVE();
  116. //
  117. // Lock master group list for reading
  118. //
  119. ACQUIRE_MASTER_GROUP_LOCK_SHARED();
  120. for ( pleGrpHead = MASTER_GROUP_LIST_HEAD(),
  121. pleGrp = pleGrpHead-> Flink;
  122. pleGrp != pleGrpHead;
  123. pleGrp = pleGrp-> Flink )
  124. {
  125. pge = CONTAINING_RECORD( pleGrp, GROUP_ENTRY, leGrpList );
  126. //
  127. // check if group is within range
  128. //
  129. if ( INET_CMP( pge-> dwGroupAddr, dwLastGroup, iCmp ) > 0 )
  130. {
  131. //
  132. // The master group list is ordered by group number and
  133. // the high end of the range to be blocked has been crossed.
  134. //
  135. break;
  136. }
  137. else if ( INET_CMP( pge-> dwGroupAddr, dwFirstGroup, iCmp ) < 0 )
  138. {
  139. //
  140. // Skip group entries smaller than the lower end of the range
  141. //
  142. continue;
  143. }
  144. //
  145. // Group Entry in range
  146. //
  147. //
  148. // lock the entry and merge the temp and master source lists
  149. //
  150. ACQUIRE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  151. MergeTempAndMasterSourceLists( pge );
  152. //
  153. // Walk the Master source list.
  154. // For each source in the group
  155. //
  156. for ( pleSrcHead = MASTER_SOURCE_LIST_HEAD( pge ),
  157. pleSrc = pleSrcHead-> Flink;
  158. pleSrc != pleSrcHead;
  159. pleSrc = pleSrc-> Flink )
  160. {
  161. pse = CONTAINING_RECORD( pleSrc, SOURCE_ENTRY, leSrcList );
  162. //-----------------------------------------------------------
  163. // Part 1 : Membership updates.
  164. //-----------------------------------------------------------
  165. //
  166. // If there are any memberships for this group on this
  167. // interface, move them to the scoped interface list
  168. //
  169. bFound = FindOutInterfaceEntry(
  170. &pse-> leOutIfList, pieIfEntry-> dwIfIndex,
  171. pieIfEntry-> dwIfNextHopAddr,
  172. pieIfEntry-> dwOwningProtocol,
  173. pieIfEntry-> dwOwningComponent, &bNewComp, &poie
  174. );
  175. if ( bFound )
  176. {
  177. //
  178. // Move interface entry from OIF list to scoped list
  179. // and invoke deletion alerts are per interop rules.
  180. //
  181. ScopeIfAndInvokeCallbacks( pge, pse, poie );
  182. }
  183. //-------------------------------------------------------
  184. // Part 2 : MFE update.
  185. //-------------------------------------------------------
  186. bDeleteCallback = FALSE;
  187. //
  188. // Check if this source entry has an MFE.
  189. //
  190. if ( !IS_VALID_INTERFACE(
  191. pse-> dwInIfIndex, pse-> dwInIfNextHopAddr
  192. ) )
  193. {
  194. //
  195. // This source entry is not an MFE. No further
  196. // processing required, Move to next source entry
  197. //
  198. continue;
  199. }
  200. //
  201. // This source entry is also an MFE
  202. //
  203. //
  204. // check if the boundary being added in on incoming
  205. // interface. If so create negative MFE, and issue
  206. // callbacks
  207. //
  208. if ( ( pse-> dwInIfIndex == pieIfEntry-> dwIfIndex ) &&
  209. ( pse-> dwInIfNextHopAddr ==
  210. pieIfEntry-> dwIfNextHopAddr ) )
  211. {
  212. //
  213. // Interface on which this group is to blocked is the
  214. // incoming interface
  215. //
  216. //
  217. // Check if this is already a negative MFE. If so
  218. // nothing more to be done, move on to next source
  219. // entry
  220. //
  221. if ( IsListEmpty( &pse-> leMfeIfList ) )
  222. {
  223. continue;
  224. }
  225. //
  226. // Delete all the outgoing interfaces in the MFE OIF
  227. // list
  228. //
  229. while ( !IsListEmpty( &pse-> leMfeIfList ) )
  230. {
  231. ple = RemoveHeadList( &pse-> leMfeIfList ) ;
  232. poieTemp = CONTAINING_RECORD(
  233. ple, OUT_IF_ENTRY, leIfList
  234. );
  235. MGM_FREE( poieTemp );
  236. }
  237. pse-> dwMfeIfCount = 0;
  238. //
  239. // this MFE is now a negative MFE. Make sure to
  240. // invoke the deletion alert callback for the
  241. // protocol component that owns the incoming
  242. // interface
  243. //
  244. bDeleteCallback = TRUE;
  245. }
  246. else
  247. {
  248. //
  249. // Check if interface is present in the OIF of MFE.
  250. // If so remove interface from OIF and issue
  251. // callbacks as appropriate
  252. //
  253. bFound = FindOutInterfaceEntry(
  254. &pse-> leMfeIfList, pieIfEntry-> dwIfIndex,
  255. pieIfEntry-> dwIfNextHopAddr,
  256. pieIfEntry-> dwOwningProtocol,
  257. pieIfEntry-> dwOwningComponent, &bNewComp,
  258. &poie
  259. );
  260. if ( !bFound )
  261. {
  262. //
  263. // interface not present in the OIF list of MFE
  264. // move on to next entry
  265. //
  266. continue;
  267. }
  268. //
  269. // Delete the outgoing interface
  270. //
  271. DeleteOutInterfaceEntry( poie );
  272. pse-> dwMfeIfCount--;
  273. if ( !pse-> dwMfeIfCount )
  274. {
  275. //
  276. // MFE OIF list has no more outgoing interfaces.
  277. // Need to issue deletion alert to protocol component
  278. // owning incoming interface
  279. //
  280. bDeleteCallback = TRUE;
  281. }
  282. }
  283. //
  284. // If needed issue deletion alert to the protocol on the
  285. // incoming interface
  286. //
  287. if ( bDeleteCallback )
  288. {
  289. ppe = GetProtocolEntry(
  290. PROTOCOL_LIST_HEAD(), pse-> dwInProtocolId,
  291. pse-> dwInComponentId
  292. );
  293. if ( ppe == NULL )
  294. {
  295. //
  296. // Protocol owning incoming interface is not present
  297. // in incoming list. Very strange and should not happen.
  298. // Nothing to be done here, move on to next source.
  299. //
  300. TRACE3(
  301. SCOPE,
  302. "Protocol (%d, %d) not present for interface %d",
  303. pse-> dwInProtocolId, pse-> dwInComponentId,
  304. dwIfIndex
  305. );
  306. continue;
  307. }
  308. if ( IS_PRUNE_ALERT( ppe ) )
  309. {
  310. PRUNE_ALERT( ppe )(
  311. pse-> dwSourceAddr, pse-> dwSourceMask,
  312. pge-> dwGroupAddr, pge-> dwGroupMask,
  313. pse-> dwInIfIndex, pse-> dwInIfNextHopAddr,
  314. FALSE, &dwTimeOut
  315. );
  316. }
  317. }
  318. //
  319. // Update Kernel Mode forwarder
  320. //
  321. AddMfeToForwarder( pge, pse, dwTimeOut );
  322. }
  323. RELEASE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  324. }
  325. RELEASE_MASTER_GROUP_LOCK_SHARED();
  326. } while ( FALSE );
  327. RELEASE_IF_LOCK_SHARED( dwIfBucket);
  328. //
  329. // Invoke pended Join/Prune alerts
  330. //
  331. InvokeOutstandingCallbacks();
  332. RELEASE_PROTOCOL_LOCK_SHARED();
  333. LEAVE_MGM_API();
  334. TRACE3(
  335. SCOPE, "LEAVING MgmBlockGroups (%lx - %lx) on %lx\n",
  336. dwFirstGroup, dwLastGroup, dwIfIndex
  337. );
  338. return NO_ERROR;
  339. }
  340. VOID
  341. ScopeIfAndInvokeCallbacks(
  342. PGROUP_ENTRY pge,
  343. PSOURCE_ENTRY pse,
  344. POUT_IF_ENTRY poie
  345. )
  346. /*++
  347. Routine Description :
  348. This routine remove an interface entry from the outgoing interface
  349. list for the specified source entry and puts it into the scoped
  350. interface list. If the deletion of the interface to the OIF list
  351. requires deletion alert callbacks to be issued to protocol components
  352. these are issued by this routine.
  353. Arguements :
  354. pge - Group entry correspondong to the group being blocked.
  355. pse - Source entry for the group being blocked
  356. poie - Interface entry corresponding to the interface over which
  357. the (source, group) entry is being blocked
  358. Return Value :
  359. None
  360. Environment :
  361. Invoked from MgmBlockGroups. Assumes the protocol list and
  362. interface bucket are locked for read, and the group entry is
  363. locked for write.
  364. --*/
  365. {
  366. BOOL bFound, bNewComp;
  367. PPROTOCOL_ENTRY ppe;
  368. POUT_IF_ENTRY poieTemp = NULL;
  369. do
  370. {
  371. //
  372. // find the protocol component on the interface specified by poie
  373. //
  374. ppe = GetProtocolEntry(
  375. PROTOCOL_LIST_HEAD(), poie-> dwProtocolId,
  376. poie-> dwComponentId
  377. );
  378. if ( ppe == NULL )
  379. {
  380. //
  381. // Outgoing interface entry but corresponding owning
  382. // protocol is no present. This should not happen.
  383. // Print a warning indicating bad state and return
  384. //
  385. TRACE3(
  386. SCOPE, "Protocol (%d, %d) not present for interface %d",
  387. poie-> dwProtocolId, poie-> dwComponentId,
  388. poie-> dwIfIndex
  389. );
  390. break;
  391. }
  392. //
  393. // Remove interface entry from the OIF list
  394. //
  395. RemoveEntryList( &poie-> leIfList );
  396. //
  397. // Find the locaion in the scoped i/f list and insert it
  398. //
  399. bFound = FindOutInterfaceEntry(
  400. &pse-> leScopedIfList, poie-> dwIfIndex,
  401. poie-> dwIfNextHopAddr, poie-> dwProtocolId,
  402. poie-> dwComponentId, &bNewComp, &poieTemp
  403. );
  404. if ( bFound )
  405. {
  406. //
  407. // Interface being scoped is already present in scoped
  408. // i/f list. Strange. Print warning and quit.
  409. //
  410. TRACE4(
  411. ANY, "Interface (%d, %d) already present in the scoped list"
  412. " for (%x, %x)", poie-> dwIfIndex, poie-> dwIfNextHopAddr,
  413. pse-> dwSourceAddr, pge-> dwGroupAddr
  414. );
  415. MGM_FREE( poie );
  416. break;
  417. }
  418. InsertTailList(
  419. ( poieTemp == NULL ) ? &pse-> leScopedIfList :
  420. &poieTemp-> leIfList,
  421. &poie-> leIfList
  422. );
  423. //
  424. // If group membership has been added by IGMP and this interface
  425. // is owned by a different protocol, inform the protocol that IGMP
  426. // has just left the interface. 'Hank you, 'hank you very much.
  427. //
  428. if ( IS_ADDED_BY_IGMP( poie ) && !IS_PROTOCOL_IGMP( ppe ) )
  429. {
  430. if ( IS_LOCAL_LEAVE_ALERT( ppe ) )
  431. {
  432. LOCAL_LEAVE_ALERT( ppe )(
  433. pse-> dwSourceAddr, pse-> dwSourceMask,
  434. pge-> dwGroupAddr, pge-> dwGroupMask,
  435. poie-> dwIfIndex, poie-> dwIfNextHopAddr
  436. );
  437. }
  438. }
  439. //
  440. // Check if the removal of this interface from the OIF list
  441. // resulted in decreasing the number of components present
  442. // in the OIF list.
  443. //
  444. FindOutInterfaceEntry(
  445. &pse-> leOutIfList, poie-> dwIfIndex, poie-> dwIfNextHopAddr,
  446. poie-> dwProtocolId, poie-> dwComponentId, &bNewComp, &poieTemp
  447. );
  448. if ( bNewComp )
  449. {
  450. pse-> dwOutCompCount--;
  451. //
  452. // number of componets in OIF list has decreased.
  453. // Invoke deletion alerts as per interop rules.
  454. //
  455. InvokePruneAlertCallbacks(
  456. pge, pse, poie-> dwIfIndex, poie-> dwIfNextHopAddr, ppe
  457. );
  458. }
  459. } while ( FALSE );
  460. }
  461. VOID
  462. InvokePruneAlertCallbacks(
  463. PGROUP_ENTRY pge,
  464. PSOURCE_ENTRY pse,
  465. DWORD dwIfIndex,
  466. DWORD dwIfNextHopAddr,
  467. PPROTOCOL_ENTRY ppe
  468. )
  469. /*++
  470. Routine Description :
  471. This routine invokes deletion alert callbacks of protocol components
  472. in response to an interface being removed from the OIF list of a
  473. source entry. Deletion alert callbacks are issued as per the
  474. interop rules.
  475. Arguements :
  476. pge - Entry corresponding to group for which deletion alert callbacks
  477. are being issued.
  478. pse - Entry corresponding to source for which deletion alert callbacks
  479. are being issued.
  480. dwIfIndex - Index of interface that is being deleted (or scoped)
  481. dwIfNextHopAddr - Next hop on interface that is being deleted (or scoped)
  482. ppe - Protocol entry for the protocol component that owns the interface
  483. corresponding to poie.
  484. Return Value :
  485. None
  486. Environment :
  487. Invoked from ScopeIfAndCanInvokeCallbacks and
  488. DeleteInterfaceFromSourceEntry
  489. --*/
  490. {
  491. PPROTOCOL_ENTRY ppeEntry;
  492. POUT_IF_ENTRY poieTemp;
  493. PLIST_ENTRY pleStart, pleProtocol;
  494. //----------------------------------------------------------------
  495. // Callback time
  496. //----------------------------------------------------------------
  497. //
  498. // Check if Source specific join
  499. //
  500. if ( !IS_WILDCARD_SOURCE( pse-> dwSourceAddr, pse-> dwSourceMask ) )
  501. {
  502. if ( pse-> dwOutCompCount == 0 )
  503. {
  504. TRACESCOPE0( GROUP, "Last component in OIL for source specific" );
  505. AddToOutstandingJoinList(
  506. pse-> dwSourceAddr, pse-> dwSourceMask,
  507. pge-> dwGroupAddr, pge-> dwGroupMask,
  508. dwIfIndex, dwIfNextHopAddr,
  509. FALSE
  510. );
  511. }
  512. }
  513. else if ( pse-> dwOutCompCount == 1 )
  514. {
  515. TRACESCOPE0(
  516. GROUP, "Number of components in the OIL is down to 1"
  517. );
  518. //
  519. // Number of protocol components that have interfaces in the OIL
  520. // has reduced from 2 to 1.
  521. //
  522. // invoke PRUNE_ALERT to the remaining protocol component
  523. //
  524. poieTemp = CONTAINING_RECORD(
  525. pse-> leOutIfList.Flink, OUT_IF_ENTRY, leIfList
  526. );
  527. ppeEntry = GetProtocolEntry(
  528. PROTOCOL_LIST_HEAD(), poieTemp-> dwProtocolId,
  529. poieTemp-> dwComponentId
  530. );
  531. if ( ppeEntry == NULL )
  532. {
  533. TRACE2(
  534. ANY, "InvokePruneAlertCallbacks : Could not"
  535. " find protocol (%x, %x)", poieTemp-> dwProtocolId,
  536. poieTemp-> dwComponentId
  537. );
  538. }
  539. //
  540. // invoke the delete membership callback for only the remaining
  541. // interface.
  542. //
  543. else if ( IS_PRUNE_ALERT( ppeEntry ) )
  544. {
  545. PRUNE_ALERT( ppeEntry ) (
  546. pse-> dwSourceAddr, pse-> dwSourceMask,
  547. pge-> dwGroupAddr, pge-> dwGroupMask,
  548. dwIfIndex, dwIfNextHopAddr, TRUE, NULL
  549. );
  550. }
  551. }
  552. else if ( pse-> dwOutCompCount == 0 )
  553. {
  554. TRACESCOPE0(
  555. GROUP, "Number of components in the OIL is down to 0"
  556. );
  557. //
  558. // Number of protocol components that have interfaces in the
  559. // OIL has reduced from 1 to 0.
  560. //
  561. // invoke PRUNE_ALERT to all the other protocol
  562. // components
  563. //
  564. for ( pleStart = PROTOCOL_LIST_HEAD(),
  565. pleProtocol = pleStart-> Flink;
  566. pleProtocol != pleStart;
  567. pleProtocol = pleProtocol-> Flink )
  568. {
  569. ppeEntry = CONTAINING_RECORD(
  570. pleProtocol, PROTOCOL_ENTRY, leProtocolList
  571. );
  572. if ( ( ppeEntry-> dwProtocolId == ppe-> dwProtocolId ) &&
  573. ( ppeEntry-> dwComponentId == ppe-> dwComponentId ) )
  574. {
  575. continue;
  576. }
  577. if ( IS_PRUNE_ALERT( ppeEntry ) )
  578. {
  579. PRUNE_ALERT( ppeEntry ) (
  580. pse-> dwSourceAddr, pse-> dwSourceMask,
  581. pge-> dwGroupAddr, pge-> dwGroupMask,
  582. dwIfIndex, dwIfNextHopAddr, TRUE, NULL
  583. );
  584. }
  585. }
  586. }
  587. }
  588. DWORD
  589. APIENTRY
  590. MgmUnBlockGroups(
  591. IN DWORD dwFirstGroup,
  592. IN DWORD dwLastGroup,
  593. IN DWORD dwIfIndex,
  594. IN DWORD dwIfNextHopAddr
  595. )
  596. /*++
  597. Routine Description :
  598. This function walks the master group list and updates the memberships
  599. of each group entry. If the interface (dwIfIndex) has previously been
  600. removed from the outgoing list of the group entry (and placed in the
  601. scoped i/f list) on account of a previous call to MgmBlockGroups
  602. it is put back and all the MFEs for the group are
  603. updated to reflect this addition.
  604. In addition if this interface was the incoming interface for an MFE
  605. update the timer to expire the MFE in short order (within a second).
  606. This way we force the recreation of an MFE should there be traffic
  607. for this group.
  608. Arguements :
  609. dwFirstGroup - Lower end of the range of groups to be unblocked
  610. dwLastGroup - Upper end of the range of groups be be unblocked
  611. dwIfIndex - Interface over which groups have to be unblocked.
  612. Return Value :
  613. NO_ERROR - Group range successfully unblocked
  614. Environment :
  615. This function is invoked by the IP RouterManager in response to
  616. removal of a group boundary.
  617. --*/
  618. {
  619. BOOL bNewComp = FALSE, bWCGrpLock = FALSE,
  620. bUpdatePass = FALSE;
  621. WORD wWCGroupAddedBy = 0, wWCGroupNumAddsByRP = 0,
  622. wGroupAddedBy, wGroupNumAddsByRP, wGroupNumAddsByIGMP,
  623. wSourceAddedBy, wSourceNumAddsByRP,
  624. wSourceNumAddsByIGMP;
  625. INT iCmp;
  626. DWORD dwIfBucket, dwWCBucket, dwIfProtocol,
  627. dwIfComponent, dwErr;
  628. PIF_ENTRY pieIfEntry;
  629. PGROUP_ENTRY pgeWC = NULL, pge;
  630. PSOURCE_ENTRY pseWC = NULL, pse;
  631. POUT_IF_ENTRY poie = NULL;
  632. PLIST_ENTRY pleGrpHead, pleGrp, pleSrcHead, pleSrc;
  633. LIST_ENTRY leForwardList;
  634. //
  635. // Ensure that MGM is running and increment count of threads
  636. // exceuting in MGM
  637. //
  638. if ( !ENTER_MGM_API() )
  639. {
  640. return ERROR_CAN_NOT_COMPLETE;
  641. }
  642. TRACE3(
  643. SCOPE, "ENTERED MgmUnblockGroups : (%lx - %lx) on %lx",
  644. dwFirstGroup, dwLastGroup, dwIfIndex
  645. );
  646. ACQUIRE_PROTOCOL_LOCK_SHARED ();
  647. InitializeListHead( &leForwardList );
  648. do
  649. {
  650. //
  651. // Pass I : aka Scan pass (bupdatePass == FALSE)
  652. // Scan and Collect all MFEs for which CREATION_ALERTS need to
  653. // invoked before updating the MFEs. Invoke the CREATION_ALERTS
  654. // outside of any locks (which is why we need two passes).
  655. //
  656. // Pass II : Update pass (bupdatePass == TRUE)
  657. // Update memberships and MFEs
  658. //
  659. //
  660. // Verify dwIfIndex is a valid interface with MGM
  661. //
  662. dwIfBucket = IF_TABLE_HASH( dwIfIndex );
  663. ACQUIRE_IF_LOCK_SHARED( dwIfBucket );
  664. pieIfEntry = GetIfEntry(
  665. IF_BUCKET_HEAD( dwIfBucket ), dwIfIndex,
  666. dwIfNextHopAddr
  667. );
  668. if ( pieIfEntry == NULL )
  669. {
  670. TRACE2(
  671. SCOPE, "Interface (%lx-%lx) not found", dwIfIndex,
  672. dwIfNextHopAddr
  673. );
  674. RELEASE_IF_LOCK_SHARED( dwIfBucket );
  675. break;
  676. }
  677. if ( bUpdatePass )
  678. {
  679. //
  680. // Verify the interface is still owned by the same protocol
  681. // as when you made the scan pass.
  682. // If not the protocol on the interface (on the scan pass)
  683. // has released the interface and there is no update to be done.
  684. //
  685. if ( ( pieIfEntry-> dwOwningProtocol != dwIfProtocol ) ||
  686. ( pieIfEntry-> dwOwningComponent != dwIfComponent ) )
  687. {
  688. TRACE2(
  689. SCOPE, "Ne protocol on interface (%lx-%lx)", dwIfIndex,
  690. dwIfNextHopAddr
  691. );
  692. RELEASE_IF_LOCK_SHARED( dwIfBucket );
  693. break;
  694. }
  695. }
  696. else
  697. {
  698. //
  699. // On the scan pass, store the protocol on the interface.
  700. // We need to verify that the protocol remains the same
  701. // between the scan and update passes.
  702. //
  703. dwIfProtocol = pieIfEntry-> dwOwningProtocol;
  704. dwIfComponent = pieIfEntry-> dwOwningComponent;
  705. }
  706. //
  707. // Merge temp and master group lists
  708. //
  709. ACQUIRE_TEMP_GROUP_LOCK_EXCLUSIVE();
  710. MergeTempAndMasterGroupLists( TEMP_GROUP_LIST_HEAD() );
  711. RELEASE_TEMP_GROUP_LOCK_EXCLUSIVE();
  712. //
  713. // Lock the master group list for reading
  714. //
  715. ACQUIRE_MASTER_GROUP_LOCK_SHARED( );
  716. //
  717. // Check if wild card recevier (*, *) for this interface. If it is
  718. // note this. i.e. mark as added by protocol and numaddsbyRp = 1.
  719. //
  720. // N.B.
  721. // You are scanning the master group list for the
  722. // WILDCARD_GROUP. This is not as expensive as it seems since the
  723. // WC entry if present would right at the beginning of the master
  724. // list.
  725. //
  726. if ( FindGroupEntry(
  727. MASTER_GROUP_LIST_HEAD(), WILDCARD_GROUP,
  728. WILDCARD_GROUP_MASK, &pgeWC, FALSE
  729. ) )
  730. {
  731. //
  732. // Lock this group entry to prevent changes to its OIF list
  733. // while unblokcing is in progress
  734. //
  735. ACQUIRE_GROUP_ENTRY_LOCK_SHARED( pgeWC );
  736. bWCGrpLock = TRUE;
  737. dwWCBucket = SOURCE_TABLE_HASH(
  738. WILDCARD_SOURCE, WILDCARD_SOURCE_MASK
  739. );
  740. if ( FindSourceEntry(
  741. SOURCE_BUCKET_HEAD( pgeWC, dwWCBucket ),
  742. WILDCARD_SOURCE, WILDCARD_SOURCE_MASK, &pseWC, TRUE
  743. ) )
  744. {
  745. //
  746. // (*, *) entry present, check if dwIfIndex is present in its
  747. // OIF list
  748. //
  749. if ( FindOutInterfaceEntry(
  750. &pseWC-> leOutIfList, pieIfEntry-> dwIfIndex,
  751. pieIfEntry-> dwIfNextHopAddr,
  752. pieIfEntry->dwOwningProtocol,
  753. pieIfEntry-> dwOwningComponent, &bNewComp, &poie
  754. ) )
  755. {
  756. //
  757. // This interface is a wildcard receiver. Note this as
  758. // added by routing protocol since IGMP would never be
  759. // a (*, *) receiver
  760. //
  761. wWCGroupAddedBy = poie-> wAddedByFlag;
  762. wWCGroupNumAddsByRP = poie-> wNumAddsByRP;
  763. }
  764. }
  765. }
  766. for ( pleGrpHead = MASTER_GROUP_LIST_HEAD(),
  767. pleGrp = pleGrpHead-> Flink;
  768. pleGrp != pleGrpHead;
  769. pleGrp = pleGrp-> Flink )
  770. {
  771. //
  772. // For each group in the master list
  773. //
  774. pge = CONTAINING_RECORD( pleGrp, GROUP_ENTRY, leGrpList );
  775. //
  776. // Skip the (*, *) entry. i.e. Skip the wildcard group.
  777. // This group entry has already been examined above (just
  778. // before the for loop). There is no need to look at this
  779. // entry as the ref. counts for this entry have been collected
  780. // above. In addition the "group entry lock" for this entry
  781. // has been acquired above and attempting to reacquire it will
  782. // lead to DEAD-LOCK. This presents only a minor inconvience
  783. // in this "for" loop i.e. having to check and skip this entry.
  784. //
  785. if ( IS_WILDCARD_GROUP( pge-> dwGroupAddr, pge-> dwGroupMask ) )
  786. {
  787. continue;
  788. }
  789. //
  790. // check is in range specified
  791. //
  792. if ( INET_CMP( pge-> dwGroupAddr, dwLastGroup, iCmp ) > 0 )
  793. {
  794. //
  795. // The master group list is ordered by group number and
  796. // the high end of the range has been crossed. Quit
  797. //
  798. break;
  799. }
  800. if ( INET_CMP( pge-> dwGroupAddr, dwFirstGroup, iCmp ) < 0 )
  801. {
  802. //
  803. // Skip groups entries smaller than the lower end of the
  804. // range
  805. //
  806. continue;
  807. }
  808. //
  809. // Group entry in range specified
  810. //
  811. ACQUIRE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  812. //
  813. // This group entry inherits the counts from the wildcard
  814. // group entry
  815. //
  816. wGroupAddedBy = wWCGroupAddedBy;
  817. wGroupNumAddsByRP = wWCGroupNumAddsByRP;
  818. wGroupNumAddsByIGMP = 0;
  819. //
  820. // Check if there are group memberships for the wildcard source
  821. // that have been scoped. Update interface counts appropriately
  822. //
  823. dwWCBucket = SOURCE_TABLE_HASH(
  824. WILDCARD_SOURCE, WILDCARD_SOURCE_MASK
  825. );
  826. if ( FindSourceEntry(
  827. SOURCE_BUCKET_HEAD( pge, dwWCBucket ), WILDCARD_SOURCE,
  828. WILDCARD_SOURCE_MASK, &pseWC, TRUE
  829. ) )
  830. {
  831. //
  832. // Wild card source present. Check if this interface
  833. // is present in its scoped i/f list
  834. //
  835. if ( FindOutInterfaceEntry(
  836. &pseWC-> leScopedIfList, pieIfEntry-> dwIfIndex,
  837. pieIfEntry-> dwIfNextHopAddr,
  838. pieIfEntry-> dwOwningProtocol,
  839. pieIfEntry-> dwOwningComponent,
  840. &bNewComp, &poie
  841. ) )
  842. {
  843. //
  844. // Wildcard member ship present present on the interface.
  845. // Note it by updating counts
  846. //
  847. wGroupAddedBy |= poie-> wAddedByFlag;
  848. wGroupNumAddsByRP += poie-> wNumAddsByRP;
  849. wGroupNumAddsByIGMP = poie-> wNumAddsByIGMP;
  850. }
  851. }
  852. //
  853. // Merge the temp and master source lists, before walking
  854. // the source list
  855. //
  856. MergeTempAndMasterSourceLists( pge );
  857. //
  858. // for each source entry
  859. //
  860. pleSrcHead = MASTER_SOURCE_LIST_HEAD( pge );
  861. for ( pleSrc = pleSrcHead-> Flink;
  862. pleSrc != pleSrcHead;
  863. pleSrc = pleSrc-> Flink )
  864. {
  865. pse = CONTAINING_RECORD( pleSrc, SOURCE_ENTRY, leSrcList );
  866. //
  867. // each source entry inherits the aggregated counts of
  868. // the wildcard group (*, *) and the wildcard source (*, G)
  869. // entry
  870. //
  871. wSourceAddedBy = wGroupAddedBy;
  872. wSourceNumAddsByRP = wGroupNumAddsByRP;
  873. wSourceNumAddsByIGMP = wGroupNumAddsByIGMP;
  874. //
  875. // Check if interface being unblocked is present in
  876. // the scoped i/f list for this source
  877. //
  878. if ( FindOutInterfaceEntry(
  879. &pse-> leScopedIfList, pieIfEntry-> dwIfIndex,
  880. pieIfEntry-> dwIfNextHopAddr,
  881. pieIfEntry-> dwOwningProtocol,
  882. pieIfEntry-> dwOwningComponent, &bNewComp, &poie
  883. ) )
  884. {
  885. //
  886. // If this is not the wildcard source entry, presence
  887. // of this interface in the scoped i/f list indicates
  888. // that a source specific join for this group was
  889. // performed. Note the counts for this interface for
  890. // the source specific join
  891. //
  892. if ( !IS_WILDCARD_SOURCE(
  893. pse-> dwSourceAddr, pse-> dwSourceMask
  894. ) )
  895. {
  896. wSourceAddedBy |= poie-> wAddedByFlag;
  897. wSourceNumAddsByRP += poie-> wNumAddsByRP;
  898. wSourceNumAddsByIGMP += poie-> wNumAddsByIGMP;
  899. }
  900. //
  901. // The function name says it.
  902. //
  903. if ( bUpdatePass )
  904. {
  905. UnScopeIfAndInvokeCallbacks( pge, pse, poie );
  906. }
  907. }
  908. //-----------------------------------------------------------
  909. // Part 2 : MFE Update
  910. //-----------------------------------------------------------
  911. if ( IS_VALID_INTERFACE(
  912. pse-> dwInIfIndex, pse-> dwInIfNextHopAddr
  913. ) )
  914. {
  915. //
  916. // This is an MFE
  917. //
  918. //
  919. // Check if the interface being unblocked is the
  920. // incoming interface for this MFE
  921. //
  922. if ( ( pse-> dwInIfIndex == pieIfEntry-> dwIfIndex ) &&
  923. ( pse-> dwInIfNextHopAddr ==
  924. pieIfEntry-> dwIfNextHopAddr ) )
  925. {
  926. //
  927. // The incoming interface is being unblocked.
  928. // That implies this MFE is currently a negative.
  929. // The easiest way to re-create the correct MFE
  930. // is to delete the MFE and force its re-creation
  931. // when the next packet arrives from the same
  932. // (source, group). The simplest way to delete
  933. // the MFE and references to it in the interface
  934. // table is to update the expiry time (set
  935. // arbitrarily to 2 seconds here) and let the
  936. // deletion happen via the MFETimerProc (timer.c)
  937. //
  938. if ( bUpdatePass )
  939. {
  940. RtlUpdateTimer(
  941. TIMER_QUEUE_HANDLE(
  942. TIMER_TABLE_HASH( pge-> dwGroupAddr )
  943. ),
  944. pse-> hTimer, 2000, 0
  945. );
  946. }
  947. }
  948. //
  949. // ELSE clause comment
  950. //
  951. // Interface being unblocked is not the incoming
  952. // interface. It could be an outgoing interface
  953. // for this MFE. Check if any component is
  954. // interested in traffic for this (S, G). To do
  955. // this check the added by flag and if it is
  956. // non-zero the interface should be added to the
  957. // MFE OIF list.
  958. //
  959. // In addition, make sure that the incoming interface
  960. // does not have a (scope) boundary on it. In that
  961. // case, there is no MFE OIF list changes required.
  962. //
  963. else if ( wSourceAddedBy &&
  964. ( !( IS_HAS_BOUNDARY_CALLBACK() ) ||
  965. ( IS_HAS_BOUNDARY_CALLBACK() &&
  966. !HAS_BOUNDARY_CALLBACK()(
  967. dwIfIndex, pge-> dwGroupAddr
  968. ) ) ) )
  969. {
  970. if ( bUpdatePass &&
  971. IsForwardingEnabled(
  972. pge-> dwGroupAddr, pge-> dwGroupMask,
  973. pse-> dwSourceAddr, pse-> dwSourceMask,
  974. &leForwardList
  975. ) )
  976. {
  977. poie = NULL;
  978. AddInterfaceToSourceMfe(
  979. pge, pse, pieIfEntry-> dwIfIndex,
  980. pieIfEntry-> dwIfNextHopAddr,
  981. pieIfEntry-> dwOwningProtocol,
  982. pieIfEntry-> dwOwningComponent, FALSE, &poie
  983. );
  984. //
  985. // Update counts for the OIF in the MFE list
  986. //
  987. if ( poie != NULL )
  988. {
  989. poie-> wAddedByFlag = wSourceAddedBy;
  990. poie-> wNumAddsByRP = wSourceNumAddsByRP;
  991. poie-> wNumAddsByIGMP = wSourceNumAddsByIGMP;
  992. }
  993. }
  994. else if ( !bUpdatePass )
  995. {
  996. AddToCheckForCreationAlertList(
  997. pge-> dwGroupAddr, pge-> dwGroupMask,
  998. pse-> dwSourceAddr, pse->dwSourceMask,
  999. pse-> dwInIfIndex, pse-> dwInIfNextHopAddr,
  1000. &leForwardList
  1001. );
  1002. }
  1003. }
  1004. }
  1005. }
  1006. RELEASE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  1007. }
  1008. //
  1009. // if lock on the Wildcard group entry is held, release it
  1010. //
  1011. if ( bWCGrpLock )
  1012. {
  1013. RELEASE_GROUP_ENTRY_LOCK_SHARED( pgeWC );
  1014. }
  1015. RELEASE_MASTER_GROUP_LOCK_SHARED( );
  1016. RELEASE_IF_LOCK_SHARED( dwIfBucket );
  1017. if ( !bUpdatePass )
  1018. {
  1019. dwErr = InvokeCreationAlertForList(
  1020. &leForwardList, dwIfProtocol, dwIfComponent,
  1021. dwIfIndex, dwIfNextHopAddr
  1022. );
  1023. if ( dwErr != NO_ERROR )
  1024. {
  1025. break;
  1026. }
  1027. bUpdatePass = TRUE;
  1028. }
  1029. else
  1030. {
  1031. break;
  1032. }
  1033. } while ( TRUE );
  1034. //
  1035. // Release all locks and decrement thread-counts etc.
  1036. //
  1037. //
  1038. // Invoke pended Join/Prune alerts
  1039. //
  1040. InvokeOutstandingCallbacks();
  1041. RELEASE_PROTOCOL_LOCK_SHARED();
  1042. FreeList( &leForwardList );
  1043. LEAVE_MGM_API();
  1044. TRACE0( SCOPE, "LEAVING MgmUnblockGroups" );
  1045. return NO_ERROR;
  1046. }
  1047. VOID
  1048. UnScopeIfAndInvokeCallbacks(
  1049. PGROUP_ENTRY pge,
  1050. PSOURCE_ENTRY pse,
  1051. POUT_IF_ENTRY poie
  1052. )
  1053. /*++
  1054. Routine Description :
  1055. This routine remove an interface entry from the scoped interface
  1056. list for the specified source entry and puts it into the outgoing
  1057. interface list. If the addition of the interface to the OIF list
  1058. requires new member callbacks to be issued to protocol components
  1059. these are issued by this routine.
  1060. Arguements :
  1061. pge - Group entry correspondong to the group being unblocked.
  1062. pse - Source entry for the group being unblocked
  1063. poie - Interface entry corresponding to the interface over which
  1064. the (source, group) entry is being unblocked
  1065. Return Value :
  1066. None
  1067. Environment :
  1068. Invoked from MgmUnBlockGroups. Assumes the protocol list and
  1069. interface bucket are locked for read, and the group entry is
  1070. locked for write.
  1071. --*/
  1072. {
  1073. BOOL bFound, bNewComp = FALSE;
  1074. PPROTOCOL_ENTRY ppe;
  1075. POUT_IF_ENTRY poieNext = NULL;
  1076. do
  1077. {
  1078. //
  1079. // Remove interface entry from the scoped I/f list
  1080. //
  1081. RemoveEntryList( &poie-> leIfList );
  1082. //
  1083. // Find its place in the OIF list for the source entry
  1084. // and insert it in
  1085. //
  1086. bFound = FindOutInterfaceEntry(
  1087. &pse-> leOutIfList, poie-> dwIfIndex,
  1088. poie-> dwIfNextHopAddr, poie-> dwProtocolId,
  1089. poie-> dwComponentId, &bNewComp, &poieNext
  1090. );
  1091. if ( bFound )
  1092. {
  1093. //
  1094. // Trouble. The interface to be inserted should not be
  1095. // present in the OIF list for the source entry. Since it
  1096. // print a warning message and move on.
  1097. //
  1098. TRACE4(
  1099. ANY, "Interface (%d-%d) present in OIF list of (%x-%x)"
  1100. " inspite of being scoped", poie-> dwIfIndex,
  1101. poie-> dwIfNextHopAddr, pse-> dwSourceAddr, pge-> dwGroupAddr
  1102. );
  1103. MGM_FREE( poie );
  1104. break;
  1105. }
  1106. InsertTailList(
  1107. ( poieNext == NULL ) ? &pse-> leOutIfList :
  1108. &poieNext-> leIfList,
  1109. &poie-> leIfList
  1110. );
  1111. //
  1112. // if new component, update component count and
  1113. // call callback invoker
  1114. //
  1115. if ( bNewComp )
  1116. {
  1117. pse-> dwOutCompCount++;
  1118. ppe = GetProtocolEntry(
  1119. PROTOCOL_LIST_HEAD(), poie-> dwProtocolId,
  1120. poie-> dwComponentId
  1121. );
  1122. if ( ppe == NULL )
  1123. {
  1124. //
  1125. // Trouble. Interface present without any owning
  1126. // protocol component.
  1127. //
  1128. TRACE4(
  1129. ANY, "Owning protocol(%d, %) for interface(%d, %d)"
  1130. " not found", poie-> dwProtocolId, poie-> dwComponentId,
  1131. poie-> dwIfIndex, poie-> dwIfNextHopAddr
  1132. );
  1133. return;
  1134. }
  1135. InvokeJoinAlertCallbacks(
  1136. pge, pse, poie, IS_ADDED_BY_IGMP( poie ), ppe
  1137. );
  1138. }
  1139. } while ( FALSE );
  1140. }
  1141. VOID
  1142. InvokeJoinAlertCallbacks(
  1143. PGROUP_ENTRY pge,
  1144. PSOURCE_ENTRY pse,
  1145. POUT_IF_ENTRY poie,
  1146. BOOL bIGMP,
  1147. PPROTOCOL_ENTRY ppe
  1148. )
  1149. /*++
  1150. Routine Description :
  1151. This routine invokes New Member callbacks in response to a new
  1152. protocol component being added to the outgoing interface list
  1153. of a source entry. New member callbacks are issued according
  1154. to interop rules.
  1155. Argumements :
  1156. pge - Entry corresponding to group for which new member callbacks
  1157. are being issued.
  1158. pse - Entry corresponding to source for which new member callbacks
  1159. are being issued.
  1160. poie - Entry corresponding to interface whose addition triggered the
  1161. callback mechanism.
  1162. bIGMP - Indicates if IGMP is adding this interface.
  1163. ppe - Protocol entry for the protocol component that owns the interface
  1164. corresponding to poie.
  1165. Return Value :
  1166. None
  1167. Environment :
  1168. Invoked from AddInterfaceToSourceEntry and UnScopeIfAndInvokeCallbacks
  1169. --*/
  1170. {
  1171. PPROTOCOL_ENTRY ppeEntry;
  1172. POUT_IF_ENTRY poiePrev;
  1173. PLIST_ENTRY ple, pleStart;
  1174. //
  1175. // Check if Source specific join
  1176. //
  1177. if ( !IS_WILDCARD_SOURCE( pse-> dwSourceAddr, pse-> dwSourceMask ) )
  1178. {
  1179. if ( pse-> dwOutCompCount == 1 )
  1180. {
  1181. TRACESCOPE0( GROUP, "First component in OIL for source specific" );
  1182. AddToOutstandingJoinList(
  1183. pse-> dwSourceAddr, pse-> dwSourceMask,
  1184. pge-> dwGroupAddr, pge-> dwGroupMask,
  1185. poie-> dwIfIndex, poie-> dwIfNextHopAddr,
  1186. TRUE
  1187. );
  1188. }
  1189. }
  1190. else if ( pse-> dwOutCompCount == 1 )
  1191. {
  1192. TRACESCOPE0( GROUP, "First component in OIL" );
  1193. //
  1194. // Interaction between routing protocols.
  1195. //
  1196. //
  1197. // first component in the OIL.
  1198. //
  1199. // Send new member callback to all the other (than the
  1200. // the one adding this group membership on
  1201. // this interface) routing protocol components
  1202. //
  1203. // At this point you have a read lock on the protocol list
  1204. // so you can walk the list
  1205. //
  1206. pleStart = PROTOCOL_LIST_HEAD();
  1207. for ( ple = pleStart-> Flink; ple != pleStart; ple = ple-> Flink )
  1208. {
  1209. ppeEntry = CONTAINING_RECORD(
  1210. ple, PROTOCOL_ENTRY, leProtocolList
  1211. );
  1212. //
  1213. // all OTHER protocol components need to be told of the
  1214. // interface addition. So skip the component adding
  1215. // this interface.
  1216. //
  1217. if ( ( ppeEntry-> dwProtocolId == ppe-> dwProtocolId ) &&
  1218. ( ppeEntry-> dwComponentId == ppe-> dwComponentId ) )
  1219. {
  1220. continue;
  1221. }
  1222. //
  1223. // if routing protocol has requested new member callback
  1224. //
  1225. if ( IS_JOIN_ALERT( ppeEntry ) )
  1226. {
  1227. JOIN_ALERT( ppeEntry )(
  1228. pse-> dwSourceAddr, pse-> dwSourceMask,
  1229. pge-> dwGroupAddr, pge-> dwGroupMask, TRUE
  1230. );
  1231. }
  1232. }
  1233. }
  1234. //
  1235. // if second component to add an interface to the OIL
  1236. // invoke new member callback to first component.
  1237. //
  1238. // Note :
  1239. // If the first component that added a group membership
  1240. // was IGMP skip JOIN_ALERT callback.
  1241. //
  1242. else if ( pse-> dwOutCompCount == 2 )
  1243. {
  1244. TRACESCOPE0( GROUP, "Second component in OIL" );
  1245. //
  1246. // find the "other (first)" routing protocol component to add
  1247. // an interface to the OIL
  1248. //
  1249. for ( ple = pse-> leOutIfList.Flink;
  1250. ple != &pse-> leOutIfList;
  1251. ple = ple-> Flink )
  1252. {
  1253. poiePrev = CONTAINING_RECORD(
  1254. ple, OUT_IF_ENTRY, leIfList
  1255. );
  1256. //
  1257. // if the protocol component that added this interface to
  1258. // the OIL is different indicating that it is the other
  1259. // component invoke its new member interface
  1260. //
  1261. if ( ( poiePrev-> dwProtocolId != ppe-> dwProtocolId ) ||
  1262. ( poiePrev-> dwComponentId != ppe-> dwComponentId ) )
  1263. {
  1264. //
  1265. // Find the protocol entry for the other interface
  1266. //
  1267. ppeEntry = GetProtocolEntry(
  1268. &ig.mllProtocolList.leHead,
  1269. poiePrev-> dwProtocolId,
  1270. poiePrev-> dwComponentId
  1271. );
  1272. if ( ppeEntry == NULL )
  1273. {
  1274. TRACE2(
  1275. ANY, "InvokeJoinAlertCallbacks : Could not"
  1276. "find protocol %x, %x", poie-> dwProtocolId,
  1277. poie-> dwComponentId
  1278. );
  1279. }
  1280. else if ( IS_ROUTING_PROTOCOL( ppeEntry ) &&
  1281. IS_JOIN_ALERT( ppeEntry ) )
  1282. {
  1283. //
  1284. // JOIN_ALERT callback will be skipped if
  1285. // the first component is IGMP
  1286. //
  1287. JOIN_ALERT( ppeEntry )(
  1288. pse-> dwSourceAddr, pse-> dwSourceMask,
  1289. pge-> dwGroupAddr, pge-> dwGroupMask, TRUE
  1290. );
  1291. }
  1292. break;
  1293. }
  1294. }
  1295. }
  1296. //
  1297. // if this group membership was added by IGMP, and
  1298. // a routing protocol co-exists with IGMP on this interface
  1299. // inform the routing protocol too.
  1300. //
  1301. if ( bIGMP && IS_ROUTING_PROTOCOL( ppe ) )
  1302. {
  1303. if ( IS_LOCAL_JOIN_ALERT( ppe ) )
  1304. {
  1305. LOCAL_JOIN_ALERT( ppe )(
  1306. pse-> dwSourceAddr, pse-> dwSourceMask,
  1307. pge-> dwGroupAddr, pge-> dwGroupMask,
  1308. poie-> dwIfIndex, poie-> dwIfNextHopAddr
  1309. );
  1310. }
  1311. }
  1312. }
  1313. DWORD
  1314. AddToOutstandingJoinList(
  1315. DWORD dwSourceAddr,
  1316. DWORD dwSourceMask,
  1317. DWORD dwGroupAddr,
  1318. DWORD dwGroupMask,
  1319. DWORD dwIfIndex,
  1320. DWORD dwIfNextHopAddr,
  1321. BOOL bJoin
  1322. )
  1323. /*++
  1324. Routine Description :
  1325. This routine adds a Join entry to the global outstanding join list.
  1326. Each entry in this list represents a "source specific" join/leave for
  1327. which the corresponding join/prune alerts have not yet been issued.
  1328. The reason for deferring the callbacks has to do with the order of
  1329. locking of buckets in the IF HASH table. When a membership is
  1330. added/deleted a lock is taken on the interface bucket that contains
  1331. the interface on which the membership is being changed. When the
  1332. source entry for which the membership is being changed has been
  1333. updated you determine (as per interop rules) whether
  1334. a join/prune needs to be issued to the protocol on the incoming
  1335. interface. If it must you need to look up the incoming interface
  1336. and then find the protocol on that interface and invoke its callbacks.
  1337. To do this you need to look up the incoming interface in the
  1338. IF hash table and locking the bucket for that IF entry. You lock two
  1339. buckets simultaneously. Hence the deferral
  1340. Arguements :
  1341. dwSourceAddr - Source address for which a join/leave has occured
  1342. dwSourceMask - Mask corresponding to dwSourceAddr
  1343. dwGroupAddr - Group for which a join/leave has occured
  1344. dwGroupMask - Mask corresponding to dwGroupAddr
  1345. dwIfIndex - Incoming interface index as per the MCAST RIB
  1346. dwIfNextHopAddr - Next hop address corresponding to dwIfIndex
  1347. bJoin - Indicates if an outstanding entry is being added because of a
  1348. join or leave
  1349. Return Value :
  1350. NO_ERROR - Success
  1351. ERROR_NOT_ENOUGH_MEMORY - failed to allocate a join entry
  1352. Environment :
  1353. Invoked in the context of Invoke[PruneAlert/JoinAlert]Callbacks
  1354. --*/
  1355. {
  1356. BOOL bFound;
  1357. DWORD dwErr = NO_ERROR;
  1358. PJOIN_ENTRY pje = NULL, pjeNew;
  1359. ACQUIRE_JOIN_LIST_LOCK_EXCLUSIVE();
  1360. do
  1361. {
  1362. bFound = FindJoinEntry(
  1363. JOIN_LIST_HEAD(), dwSourceAddr, dwSourceMask,
  1364. dwGroupAddr, dwGroupMask, dwIfIndex, dwIfNextHopAddr,
  1365. &pje
  1366. );
  1367. if ( bFound )
  1368. {
  1369. //
  1370. // Join entry already exists for this interface.
  1371. // Check if it is of the same type
  1372. //
  1373. if ( pje-> bJoin != bJoin )
  1374. {
  1375. //
  1376. // Join entries of different types, null each other
  1377. // remove this join entry
  1378. //
  1379. RemoveEntryList( &pje-> leJoinList );
  1380. MGM_FREE( pje );
  1381. }
  1382. }
  1383. else
  1384. {
  1385. //
  1386. // Join entry does not exist. Create one and insert it.
  1387. //
  1388. pjeNew = MGM_ALLOC( sizeof( JOIN_ENTRY ) );
  1389. if ( pjeNew == NULL )
  1390. {
  1391. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1392. TRACE1( ANY, "Failed to create Join Entry : %x", dwErr );
  1393. break;
  1394. }
  1395. InitializeListHead( &pjeNew-> leJoinList );
  1396. pjeNew-> dwSourceAddr = dwSourceAddr;
  1397. pjeNew-> dwSourceMask = dwSourceMask;
  1398. pjeNew-> dwGroupAddr = dwGroupAddr;
  1399. pjeNew-> dwGroupMask = dwGroupMask;
  1400. pjeNew-> dwIfIndex = dwIfIndex;
  1401. pjeNew-> dwIfNextHopAddr = dwIfNextHopAddr;
  1402. pjeNew-> bJoin = bJoin;
  1403. InsertTailList(
  1404. ( pje == NULL ) ? JOIN_LIST_HEAD() : &pje-> leJoinList,
  1405. &pjeNew-> leJoinList
  1406. );
  1407. }
  1408. } while ( FALSE );
  1409. RELEASE_JOIN_LIST_LOCK_EXCLUSIVE();
  1410. return dwErr;
  1411. }
  1412. PJOIN_ENTRY
  1413. GetNextJoinEntry(
  1414. )
  1415. /*++
  1416. Routine Description :
  1417. This function removes the first outstanding join entry and returns it
  1418. Arguements :
  1419. Return Values :
  1420. NULL - if outstanding join list is empty
  1421. pointer to a join entry otherwise
  1422. Environment :
  1423. Invoked from InvokeOutstandingCallbacks
  1424. --*/
  1425. {
  1426. PLIST_ENTRY ple;
  1427. PJOIN_ENTRY pje = NULL;
  1428. ACQUIRE_JOIN_LIST_LOCK_EXCLUSIVE();
  1429. if ( !IsListEmpty( JOIN_LIST_HEAD() ) )
  1430. {
  1431. ple = RemoveHeadList( JOIN_LIST_HEAD() );
  1432. pje = CONTAINING_RECORD( ple, JOIN_ENTRY, leJoinList );
  1433. }
  1434. RELEASE_JOIN_LIST_LOCK_EXCLUSIVE();
  1435. return pje;
  1436. }
  1437. BOOL
  1438. FindJoinEntry(
  1439. PLIST_ENTRY pleJoinList,
  1440. DWORD dwSourceAddr,
  1441. DWORD dwSourceMask,
  1442. DWORD dwGroupAddr,
  1443. DWORD dwGroupMask,
  1444. DWORD dwIfIndex,
  1445. DWORD dwIfNextHopAddr,
  1446. PJOIN_ENTRY * ppje
  1447. )
  1448. /*++
  1449. Routine Description :
  1450. This routine finds a specified join entry in the outstanding join list.
  1451. Arguements :
  1452. pleJoinList - Join list to be searched
  1453. dwSourceAddr - Source address for which a join/leave has occured
  1454. dwSourceMask - Mask corresponding to dwSourceAddr
  1455. dwGroupAddr - Group for which a join/leave has occured
  1456. dwGroupMask - Mask corresponding to dwGroupAddr
  1457. dwIfIndex - Incoming interface index as per the MCAST RIB
  1458. dwIfNextHopAddr - Next hop address corresponding to dwIfIndex
  1459. ppje - a pointer to join entry if found or
  1460. a pointer to the next element in the join list if it exists or
  1461. NULL
  1462. Return Values :
  1463. TRUE - Join entry found
  1464. FALSE - Join entry not found
  1465. Environment :
  1466. Invoked from AddToOutstandingJoinList
  1467. --*/
  1468. {
  1469. INT iCmp;
  1470. PLIST_ENTRY ple = NULL;
  1471. PJOIN_ENTRY pje = NULL;
  1472. BOOL bFound = FALSE;
  1473. *ppje = NULL;
  1474. for ( ple = pleJoinList-> Flink; ple != pleJoinList; ple = ple-> Flink )
  1475. {
  1476. pje = CONTAINING_RECORD( ple, JOIN_ENTRY, leJoinList );
  1477. if ( INET_CMP( pje-> dwGroupAddr, dwGroupAddr, iCmp ) < 0 )
  1478. {
  1479. continue;
  1480. }
  1481. else if ( iCmp > 0 )
  1482. {
  1483. //
  1484. // you are now past the position where an existing
  1485. // entry would be.
  1486. //
  1487. *ppje = pje;
  1488. break;
  1489. }
  1490. if ( INET_CMP( pje-> dwSourceAddr, dwSourceAddr, iCmp ) < 0 )
  1491. {
  1492. continue;
  1493. }
  1494. else if ( iCmp > 0 )
  1495. {
  1496. //
  1497. // you are now past the position where an existing
  1498. // entry would be.
  1499. //
  1500. *ppje = pje;
  1501. break;
  1502. }
  1503. if ( pje-> dwIfIndex < dwIfIndex )
  1504. {
  1505. continue;
  1506. }
  1507. else if ( pje-> dwIfIndex > dwIfIndex )
  1508. {
  1509. //
  1510. // you are now past the position where an existing
  1511. // entry would be.
  1512. //
  1513. *ppje = pje;
  1514. break;
  1515. }
  1516. if ( INET_CMP( pje-> dwIfNextHopAddr, dwIfNextHopAddr, iCmp ) < 0 )
  1517. {
  1518. continue;
  1519. }
  1520. else if ( iCmp > 0 )
  1521. {
  1522. //
  1523. // you are now past the position where an existing
  1524. // entry would be.
  1525. //
  1526. *ppje = pje;
  1527. break;
  1528. }
  1529. //
  1530. // entry found
  1531. //
  1532. *ppje = pje;
  1533. bFound = TRUE;
  1534. break;
  1535. }
  1536. return bFound;
  1537. }
  1538. VOID
  1539. InvokeOutstandingCallbacks(
  1540. )
  1541. /*++
  1542. Routine Description :
  1543. This routine walks the global outstanding join list, and for each entry
  1544. finds the incoming interface and the protocol on it and invokes the
  1545. appropriate callback (JoinAlert/PruneAlert).
  1546. Arguements :
  1547. Return Values :
  1548. Environment :
  1549. Whenever a source specific join or leave occurs or when scoped boundaries
  1550. change.
  1551. --*/
  1552. {
  1553. BOOL bFound;
  1554. DWORD dwIfBucket;
  1555. PJOIN_ENTRY pje;
  1556. PIF_ENTRY pie;
  1557. PPROTOCOL_ENTRY ppe;
  1558. DWORD dwErr;
  1559. RTM_NET_ADDRESS rnaAddr;
  1560. RTM_DEST_INFO rdiDest;
  1561. RTM_NEXTHOP_INFO rniNextHop;
  1562. BOOL bRelDest, bRelNextHop, bRelIfLock;
  1563. HANDLE hNextHop;
  1564. //
  1565. // While there are join entries
  1566. // - Get the next join entry
  1567. // - Look source and find incoming interface
  1568. // - Find the interface entry and get the protocol on that i/f
  1569. // - invoke its callback
  1570. //
  1571. while ( ( pje = GetNextJoinEntry() ) != NULL )
  1572. {
  1573. bRelDest = bRelNextHop = bRelIfLock = FALSE;
  1574. do
  1575. {
  1576. //
  1577. // Get route to source
  1578. //
  1579. RTM_IPV4_MAKE_NET_ADDRESS(
  1580. &rnaAddr, pje-> dwSourceAddr, IPv4_ADDR_LEN
  1581. );
  1582. dwErr = RtmGetMostSpecificDestination(
  1583. g_hRtmHandle, &rnaAddr, RTM_BEST_PROTOCOL,
  1584. RTM_VIEW_MASK_MCAST, &rdiDest
  1585. );
  1586. if ( dwErr != NO_ERROR )
  1587. {
  1588. TRACE1(
  1589. ANY, "InvokeOutstandingCallbacks : Failed to lookup "
  1590. "route : %x", dwErr
  1591. );
  1592. break;
  1593. }
  1594. bRelDest = TRUE;
  1595. //
  1596. // Select next hop info
  1597. //
  1598. hNextHop = SelectNextHop( &rdiDest );
  1599. if ( hNextHop == NULL )
  1600. {
  1601. TRACE1(
  1602. ANY, "InvokeOutstandingCallbacks : Failed to select "
  1603. "next hop : %x", dwErr
  1604. );
  1605. break;
  1606. }
  1607. //
  1608. // Get nexthop info
  1609. //
  1610. dwErr = RtmGetNextHopInfo(
  1611. g_hRtmHandle, hNextHop, &rniNextHop
  1612. );
  1613. if ( dwErr != NO_ERROR )
  1614. {
  1615. TRACE1(
  1616. ANY, "InvokeOutstandingCallbacks : Failed to get "
  1617. "next hop info : %x", dwErr
  1618. );
  1619. break;
  1620. }
  1621. bRelNextHop = TRUE;
  1622. //
  1623. // Find the incming interface entry
  1624. //
  1625. dwIfBucket = IF_TABLE_HASH( rniNextHop.InterfaceIndex );
  1626. ACQUIRE_IF_LOCK_SHARED( dwIfBucket );
  1627. bRelIfLock = TRUE;
  1628. bFound = FindIfEntry(
  1629. IF_BUCKET_HEAD( dwIfBucket ), rniNextHop.InterfaceIndex,
  1630. 0, &pie
  1631. );
  1632. if ( ( pie == NULL ) ||
  1633. ( !bFound &&
  1634. pie-> dwIfIndex != rniNextHop.InterfaceIndex ) )
  1635. {
  1636. //
  1637. // No interface with the specified ID exists.
  1638. // Nothing to be done
  1639. //
  1640. break;
  1641. }
  1642. //
  1643. // Check if the interface on which JOIN/PRUNE occured is
  1644. // the same as the incoming interface.
  1645. //
  1646. // If so skip it.
  1647. //
  1648. if ( ( pje-> dwIfIndex == pie-> dwIfIndex ) &&
  1649. ( pje-> dwIfNextHopAddr == pie-> dwIfNextHopAddr ) )
  1650. {
  1651. //
  1652. // No join/prune required
  1653. //
  1654. TRACEGROUP2(
  1655. GROUP, "No callback as incoming if == joined/pruned "
  1656. "if 0x%x 0x%x",
  1657. pje-> dwIfIndex, pje-> dwIfNextHopAddr
  1658. );
  1659. break;
  1660. }
  1661. ppe = GetProtocolEntry(
  1662. PROTOCOL_LIST_HEAD(), pie-> dwOwningProtocol,
  1663. pie-> dwOwningComponent
  1664. );
  1665. if ( ppe == NULL )
  1666. {
  1667. //
  1668. // No protocol present for interface entry. Strange
  1669. //
  1670. break;
  1671. }
  1672. if ( pje-> bJoin )
  1673. {
  1674. if ( IS_JOIN_ALERT( ppe ) )
  1675. {
  1676. JOIN_ALERT( ppe )(
  1677. pje-> dwSourceAddr, pje-> dwSourceMask,
  1678. pje-> dwGroupAddr, pje-> dwGroupMask,
  1679. TRUE
  1680. );
  1681. }
  1682. }
  1683. else
  1684. {
  1685. if ( IS_PRUNE_ALERT( ppe ) )
  1686. {
  1687. PRUNE_ALERT( ppe )(
  1688. pje-> dwSourceAddr, pje-> dwSourceMask,
  1689. pje-> dwGroupAddr, pje-> dwGroupMask,
  1690. pje-> dwIfIndex, pje-> dwIfNextHopAddr,
  1691. TRUE, NULL
  1692. );
  1693. }
  1694. }
  1695. } while ( FALSE );
  1696. MGM_FREE( pje );
  1697. if ( bRelIfLock )
  1698. {
  1699. RELEASE_IF_LOCK_SHARED( dwIfBucket );
  1700. }
  1701. if ( bRelDest )
  1702. {
  1703. dwErr = RtmReleaseDestInfo( g_hRtmHandle, &rdiDest );
  1704. if ( dwErr != NO_ERROR )
  1705. {
  1706. TRACE1( ANY, "Failed to release dest info : %x", dwErr );
  1707. }
  1708. }
  1709. if ( bRelNextHop )
  1710. {
  1711. dwErr = RtmReleaseNextHopInfo( g_hRtmHandle, &rniNextHop );
  1712. if ( dwErr != NO_ERROR )
  1713. {
  1714. TRACE1( ANY, "Failed to release dest info : %x", dwErr );
  1715. }
  1716. }
  1717. }
  1718. }
  1719. VOID
  1720. AddToCheckForCreationAlertList(
  1721. DWORD dwGroupAddr,
  1722. DWORD dwGroupMask,
  1723. DWORD dwSourceAddr,
  1724. DWORD dwSourceMask,
  1725. DWORD dwInIfIndex,
  1726. DWORD dwInIfNextHopAddr,
  1727. PLIST_ENTRY pleForwardList
  1728. )
  1729. /*++
  1730. Routine Description :
  1731. Arguements :
  1732. Return Values :
  1733. Environment :
  1734. --*/
  1735. {
  1736. PJOIN_ENTRY pje;
  1737. //
  1738. // Create an entry in the forward list
  1739. //
  1740. pje = MGM_ALLOC( sizeof( JOIN_ENTRY ) );
  1741. if ( pje == NULL )
  1742. {
  1743. TRACE0( ANY, "Failed to allocate forward list entry" );
  1744. return;
  1745. }
  1746. InitializeListHead( &pje-> leJoinList );
  1747. pje-> dwSourceAddr = dwSourceAddr;
  1748. pje-> dwSourceMask = dwSourceMask;
  1749. pje-> dwGroupAddr = dwGroupAddr;
  1750. pje-> dwGroupMask = dwGroupMask;
  1751. pje-> dwIfIndex = dwInIfIndex;
  1752. pje-> dwIfNextHopAddr = dwInIfNextHopAddr;
  1753. pje-> bJoin = TRUE;
  1754. //
  1755. // Insert at the end of the list
  1756. //
  1757. InsertTailList( pleForwardList, &pje-> leJoinList );
  1758. return;
  1759. }
  1760. BOOL
  1761. IsForwardingEnabled(
  1762. DWORD dwGroupAddr,
  1763. DWORD dwGroupMask,
  1764. DWORD dwSourceAddr,
  1765. DWORD dwSourceMask,
  1766. PLIST_ENTRY pleForwardList
  1767. )
  1768. /*++
  1769. --*/
  1770. {
  1771. PLIST_ENTRY ple, pleTemp;
  1772. PJOIN_ENTRY pje;
  1773. BOOL bEnable = FALSE;
  1774. INT iCmp;
  1775. //
  1776. // find the source group entry and
  1777. // check if forwarding is enabled for it
  1778. //
  1779. ple = pleForwardList-> Flink;
  1780. while ( ple != pleForwardList )
  1781. {
  1782. pje = CONTAINING_RECORD( ple, JOIN_ENTRY, leJoinList );
  1783. if ( INET_CMP( pje-> dwGroupAddr, dwGroupAddr, iCmp ) < 0 )
  1784. {
  1785. pleTemp = ple-> Flink;
  1786. RemoveEntryList( ple );
  1787. MGM_FREE( pje );
  1788. ple = pleTemp;
  1789. continue;
  1790. }
  1791. else if ( iCmp > 0 )
  1792. {
  1793. //
  1794. // you are now past the position where an existing
  1795. // entry would be.
  1796. //
  1797. break;
  1798. }
  1799. if ( INET_CMP( pje-> dwSourceAddr, dwSourceAddr, iCmp ) < 0 )
  1800. {
  1801. pleTemp = ple-> Flink;
  1802. RemoveEntryList( ple );
  1803. MGM_FREE( pje );
  1804. ple = pleTemp;
  1805. continue;
  1806. }
  1807. else if ( iCmp > 0 )
  1808. {
  1809. //
  1810. // you are now past the position where an existing
  1811. // entry would be.
  1812. //
  1813. break;
  1814. }
  1815. //
  1816. // found source-group entry
  1817. //
  1818. bEnable = pje-> bJoin;
  1819. RemoveEntryList( ple );
  1820. MGM_FREE( pje );
  1821. break;
  1822. }
  1823. return bEnable;
  1824. }
  1825. DWORD
  1826. InvokeCreationAlertForList(
  1827. PLIST_ENTRY pleForwardList,
  1828. DWORD dwProtocolId,
  1829. DWORD dwComponentId,
  1830. DWORD dwIfIndex,
  1831. DWORD dwIfNextHopAddr
  1832. )
  1833. {
  1834. PPROTOCOL_ENTRY ppe;
  1835. PLIST_ENTRY ple;
  1836. PJOIN_ENTRY pje;
  1837. MGM_IF_ENTRY mie;
  1838. //
  1839. // Get the protocol entry on which CREATION_ALERTs are to
  1840. // be invoked.
  1841. //
  1842. ppe = GetProtocolEntry(
  1843. PROTOCOL_LIST_HEAD(), dwProtocolId, dwComponentId
  1844. );
  1845. if ( ppe == NULL )
  1846. {
  1847. TRACE2(
  1848. ANY, "Could not invoke CREATION_ALERTs since protocol"
  1849. "(%ld, %ld) not found", dwProtocolId, dwComponentId
  1850. );
  1851. return ERROR_NOT_FOUND;
  1852. }
  1853. if ( !( IS_CREATION_ALERT( ppe ) ) )
  1854. {
  1855. TRACE2(
  1856. ANY, "Protocol (%ld, %ld) does not have a CREATION_ALERT",
  1857. dwProtocolId, dwComponentId
  1858. );
  1859. return NO_ERROR;
  1860. }
  1861. //
  1862. // for each member of the list invoke CREATION_ALERT
  1863. //
  1864. ple = pleForwardList-> Flink;
  1865. while ( ple != pleForwardList )
  1866. {
  1867. pje = CONTAINING_RECORD( ple, JOIN_ENTRY, leJoinList );
  1868. mie.dwIfIndex = dwIfIndex;
  1869. mie.dwIfNextHopAddr = dwIfNextHopAddr;
  1870. mie.bIGMP = TRUE;
  1871. mie.bIsEnabled = pje-> bJoin;
  1872. CREATION_ALERT( ppe )(
  1873. pje-> dwSourceAddr, pje-> dwSourceMask,
  1874. pje-> dwGroupAddr, pje-> dwGroupMask,
  1875. pje-> dwIfIndex, pje-> dwIfNextHopAddr,
  1876. 1, &mie
  1877. );
  1878. pje-> bJoin = mie.bIsEnabled;
  1879. ple = ple-> Flink;
  1880. }
  1881. return NO_ERROR;
  1882. }
  1883. VOID
  1884. WorkerFunctionInvokeCreationAlert(
  1885. PVOID pvContext
  1886. )
  1887. /*++
  1888. Routine Description:
  1889. This routine invokes the creation alert for the protocol that
  1890. owns the interface specified in the context. This invocation
  1891. needs to happen from a worker thread for locking reasons.
  1892. For a group join the protocol calls into MGM via the
  1893. MgmAddGroupMembership API. We cannot call back into the protocol
  1894. in the context of this API call since the protocol could be holding
  1895. locks when invoking this API which in turn may be acquired in the
  1896. context of the callback. Hence the call back are invoked from a
  1897. worker thread
  1898. Parameters
  1899. pvContext - pointer to a CREATION_ALERT_CONTEXT structure
  1900. containing the source, group, and interface on which
  1901. a membership join occured.
  1902. Return Value:
  1903. None
  1904. Environment:
  1905. Invoked from MgmAddGroupMembership for (*, G) and (*, *) joins.
  1906. Calls in protocols to issue CREATION_ALERT_CALLBACK
  1907. --*/
  1908. {
  1909. DWORD dwInd, dwErr, dwIfBucket, dwGrpBucket, dwSrcBucket;
  1910. BOOL bNewComp, bIfLock = FALSE, bGrpLock = FALSE, bgeLock = FALSE;
  1911. PIF_ENTRY pieEntry;
  1912. PGROUP_ENTRY pge;
  1913. PSOURCE_ENTRY pse;
  1914. POUT_IF_ENTRY poie;
  1915. LIST_ENTRY leSourceList;
  1916. PCREATION_ALERT_CONTEXT pcac = (PCREATION_ALERT_CONTEXT) pvContext;
  1917. if (!ENTER_MGM_WORKER())
  1918. {
  1919. TRACE0(
  1920. ANY, "InvokeCreationAlert: Failed to enter"
  1921. );
  1922. MGM_FREE( pcac );
  1923. return;
  1924. }
  1925. TRACE0( GROUP, "ENTERED WorkerFunctionInvokeCreationAlert" );
  1926. //
  1927. // Acquire protocol lock first to maintain locking order
  1928. //
  1929. ACQUIRE_PROTOCOL_LOCK_SHARED();
  1930. do
  1931. {
  1932. dwIfBucket = IF_TABLE_HASH(
  1933. pcac-> dwIfIndex
  1934. );
  1935. //
  1936. // For wildcard group - i.e. (*, *) membership adds.
  1937. //
  1938. if ( IS_WILDCARD_GROUP( pcac-> dwGroupAddr, pcac-> dwGroupMask ) )
  1939. {
  1940. InitializeListHead( &leSourceList );
  1941. //
  1942. // Walk each bucket of the group table
  1943. //
  1944. for ( dwInd = 1; dwInd < GROUP_TABLE_SIZE; dwInd++ )
  1945. {
  1946. //
  1947. // Lock the interface to prevent the (*, *)
  1948. // membership from being deleted while MFEs
  1949. // are being updated.
  1950. //
  1951. ACQUIRE_IF_LOCK_SHARED( dwIfBucket );
  1952. pieEntry = GetIfEntry(
  1953. IF_BUCKET_HEAD( dwIfBucket ),
  1954. pcac-> dwIfIndex, pcac-> dwIfNextHopAddr
  1955. );
  1956. if ( pieEntry == NULL )
  1957. {
  1958. //
  1959. // Interface is no longer present with MGM.
  1960. // possibly deleted in another thread.
  1961. // There is no further MFE update to be performed.
  1962. // quit now.
  1963. //
  1964. RELEASE_IF_LOCK_SHARED( dwIfBucket );
  1965. break;
  1966. }
  1967. //
  1968. // Pass 1: Accumulate (S, G) values for all groups
  1969. // in this group bucket into leSourceList.
  1970. //
  1971. AddInterfaceToAllMfeInGroupBucket(
  1972. pcac-> dwIfIndex, pcac-> dwIfNextHopAddr,
  1973. pcac-> dwProtocolId, pcac-> dwComponentId,
  1974. dwInd, pcac-> bIGMP, FALSE, &leSourceList
  1975. );
  1976. RELEASE_IF_LOCK_SHARED( dwIfBucket );
  1977. //
  1978. // Invoke CREATION_ALERTs on them outside locks
  1979. //
  1980. dwErr = InvokeCreationAlertForList(
  1981. &leSourceList,
  1982. pcac-> dwProtocolId, pcac-> dwComponentId,
  1983. pcac-> dwIfIndex, pcac-> dwIfNextHopAddr
  1984. );
  1985. if ( dwErr == NO_ERROR )
  1986. {
  1987. //
  1988. // Lock the interface to prevent the (*, *)
  1989. // membership from being deleted while MFEs
  1990. // are being updated.
  1991. //
  1992. ACQUIRE_IF_LOCK_SHARED( dwIfBucket );
  1993. pieEntry = GetIfEntry(
  1994. IF_BUCKET_HEAD( dwIfBucket ),
  1995. pcac-> dwIfIndex, pcac-> dwIfNextHopAddr
  1996. );
  1997. if ( pieEntry == NULL )
  1998. {
  1999. //
  2000. // Interface is no longer present with MGM.
  2001. // possibly deleted in another thread.
  2002. // There is no further MFE update to be performed.
  2003. // quit now.
  2004. //
  2005. RELEASE_IF_LOCK_SHARED( dwIfBucket );
  2006. break;
  2007. }
  2008. //
  2009. // Verify that the (*, *) membership on this interface
  2010. // is still present.
  2011. // It could have been deleted in a separate thread.
  2012. //
  2013. dwGrpBucket = GROUP_TABLE_HASH( 0, 0 );
  2014. ACQUIRE_GROUP_LOCK_SHARED( dwGrpBucket );
  2015. pge = GetGroupEntry(
  2016. GROUP_BUCKET_HEAD( dwGrpBucket ), 0, 0
  2017. );
  2018. if ( pge != NULL )
  2019. {
  2020. ACQUIRE_GROUP_ENTRY_LOCK_SHARED( pge );
  2021. dwSrcBucket = SOURCE_TABLE_HASH( 0, 0 );
  2022. if ( FindSourceEntry(
  2023. SOURCE_BUCKET_HEAD( pge, dwSrcBucket ),
  2024. 0, 0, &pse, TRUE ) )
  2025. {
  2026. if ( FindOutInterfaceEntry(
  2027. &pse-> leOutIfList,
  2028. pcac-> dwIfIndex,
  2029. pcac-> dwIfNextHopAddr,
  2030. pcac-> dwProtocolId,
  2031. pcac-> dwComponentId,
  2032. &bNewComp,
  2033. &poie ) )
  2034. {
  2035. //
  2036. // (*, *) membership is present on
  2037. // this interface
  2038. //
  2039. //
  2040. // Pass 2 : Update all MFEs in this
  2041. // bucket as per the results
  2042. // of the CREATION_ALERTs
  2043. //
  2044. AddInterfaceToAllMfeInGroupBucket(
  2045. pcac-> dwIfIndex,
  2046. pcac-> dwIfNextHopAddr,
  2047. pcac-> dwProtocolId,
  2048. pcac-> dwComponentId,
  2049. dwInd,
  2050. pcac-> bIGMP,
  2051. TRUE,
  2052. &leSourceList
  2053. );
  2054. }
  2055. else
  2056. {
  2057. //
  2058. // (*, *) membership is NO longer
  2059. // present on this interface
  2060. //
  2061. dwInd = GROUP_TABLE_SIZE;
  2062. }
  2063. }
  2064. else
  2065. {
  2066. //
  2067. // (*, *) membership is no longer present
  2068. //
  2069. dwInd = GROUP_TABLE_SIZE;
  2070. }
  2071. RELEASE_GROUP_ENTRY_LOCK_SHARED( pge );
  2072. }
  2073. else
  2074. {
  2075. //
  2076. // (*, *) membership is no longer present
  2077. //
  2078. dwInd = GROUP_TABLE_SIZE;
  2079. }
  2080. RELEASE_GROUP_LOCK_SHARED( dwGrpBucket );
  2081. RELEASE_IF_LOCK_SHARED( dwIfBucket );
  2082. }
  2083. FreeList( &leSourceList );
  2084. }
  2085. FreeList( &leSourceList );
  2086. }
  2087. //
  2088. // For wildard sources i.e. (*, G) membership adds
  2089. //
  2090. else if ( IS_WILDCARD_SOURCE(
  2091. pcac-> dwSourceAddr, pcac-> dwSourceMask
  2092. ) )
  2093. {
  2094. do
  2095. {
  2096. //
  2097. // Invoke CREATION_ALERTs for all MFEs for the group
  2098. //
  2099. dwErr = InvokeCreationAlertForList(
  2100. &(pcac-> leSourceList),
  2101. pcac-> dwProtocolId,
  2102. pcac-> dwComponentId,
  2103. pcac-> dwIfIndex,
  2104. pcac-> dwIfNextHopAddr
  2105. );
  2106. if ( dwErr != NO_ERROR )
  2107. {
  2108. break;
  2109. }
  2110. //
  2111. // Lock the interface to prevent the (*, G)
  2112. // membership from being deleted while MFEs
  2113. // are being updated.
  2114. //
  2115. ACQUIRE_IF_LOCK_SHARED( dwIfBucket );
  2116. bIfLock = TRUE;
  2117. pieEntry = GetIfEntry(
  2118. IF_BUCKET_HEAD( dwIfBucket ),
  2119. pcac-> dwIfIndex,
  2120. pcac-> dwIfNextHopAddr
  2121. );
  2122. if ( pieEntry == NULL )
  2123. {
  2124. //
  2125. // Interface is no longer present with MGM.
  2126. // possibly deleted in another thread.
  2127. // There is no further MFE update to be performed.
  2128. // quit now.
  2129. //
  2130. TRACE2(
  2131. ANY, "InvokeCreationAlert: Interface 0x%x 0x%x"
  2132. " is no longer present",
  2133. pcac-> dwIfIndex,
  2134. pcac-> dwIfNextHopAddr
  2135. );
  2136. break;
  2137. }
  2138. //
  2139. // Verify that the (*, G) membership is still
  2140. // present on the interface
  2141. //
  2142. dwGrpBucket = GROUP_TABLE_HASH(
  2143. pcac-> dwGroupAddr,
  2144. pcac-> dwGroupMask
  2145. );
  2146. ACQUIRE_GROUP_LOCK_EXCLUSIVE( dwGrpBucket );
  2147. bGrpLock = TRUE;
  2148. pge = GetGroupEntry(
  2149. GROUP_BUCKET_HEAD( dwGrpBucket ),
  2150. pcac-> dwGroupAddr,
  2151. pcac-> dwGroupMask
  2152. );
  2153. if ( pge == NULL )
  2154. {
  2155. //
  2156. // Group entry no longer present, possibly
  2157. // deleted in some other thread
  2158. //
  2159. TRACE2(
  2160. ANY, "InvokeCreationAlert: Group 0x%x 0x%x "
  2161. "is no longer present",
  2162. pcac-> dwGroupAddr, pcac-> dwGroupMask
  2163. );
  2164. break;
  2165. }
  2166. ACQUIRE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  2167. bgeLock = TRUE;
  2168. dwSrcBucket = SOURCE_TABLE_HASH(
  2169. pcac-> dwSourceAddr,
  2170. pcac-> dwSourceMask
  2171. );
  2172. pse = GetSourceEntry(
  2173. SOURCE_BUCKET_HEAD( pge, dwSrcBucket ),
  2174. pcac-> dwSourceAddr,
  2175. pcac-> dwSourceMask
  2176. );
  2177. if ( pse == NULL )
  2178. {
  2179. //
  2180. // Source entry no longer present, possibly
  2181. // deleted in some other thread
  2182. //
  2183. TRACE2(
  2184. ANY, "InvokeCreationAlert: Source 0x%x 0x%x "
  2185. "is no longer present",
  2186. pcac-> dwSourceAddr, pcac-> dwSourceMask
  2187. );
  2188. break;
  2189. }
  2190. poie = GetOutInterfaceEntry(
  2191. &pse-> leOutIfList,
  2192. pcac-> dwIfIndex, pcac-> dwIfNextHopAddr,
  2193. pcac-> dwProtocolId, pcac-> dwComponentId
  2194. );
  2195. if ( poie == NULL )
  2196. {
  2197. TRACE2(
  2198. ANY, "InvokeCreationAlert: Interface 0x%x 0x%x "
  2199. "is no longer present in OIF",
  2200. pcac-> dwIfIndex, pcac-> dwIfNextHopAddr
  2201. );
  2202. break;
  2203. }
  2204. //
  2205. // (*, G) present on this interface.
  2206. // Update all for group MFE as per results of
  2207. // creation alerts.
  2208. //
  2209. AddInterfaceToGroupMfe(
  2210. pge, pcac-> dwIfIndex, pcac-> dwIfNextHopAddr,
  2211. pcac-> dwProtocolId, pcac-> dwComponentId,
  2212. pcac-> bIGMP, TRUE, &(pcac-> leSourceList)
  2213. );
  2214. } while ( FALSE );
  2215. //
  2216. // release locks
  2217. //
  2218. if ( bgeLock )
  2219. {
  2220. RELEASE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  2221. bgeLock = FALSE;
  2222. }
  2223. if ( bGrpLock )
  2224. {
  2225. RELEASE_GROUP_LOCK_EXCLUSIVE( dwGrpBucket );
  2226. bgeLock = FALSE;
  2227. }
  2228. if ( bIfLock )
  2229. {
  2230. RELEASE_IF_LOCK_SHARED( dwIfBucket );
  2231. bIfLock = FALSE;
  2232. }
  2233. FreeList( &(pcac-> leSourceList) );
  2234. }
  2235. } while ( FALSE );
  2236. if ( bIfLock )
  2237. {
  2238. RELEASE_IF_LOCK_SHARED( dwIfBucket );
  2239. }
  2240. RELEASE_PROTOCOL_LOCK_SHARED();
  2241. MGM_FREE( pcac );
  2242. LEAVE_MGM_WORKER();
  2243. TRACE0( GROUP, "LEAVING WorkerFunctionInvokeCreationAlert" );
  2244. return;
  2245. }
  2246. #if 0
  2247. v()
  2248. {
  2249. //
  2250. // Ensure interface on which join occured is still present
  2251. //
  2252. dwIfBucket = IF_TABLE_HASH(
  2253. pcac-> dwIfIndex, pcac-> dwIfNextHopAddr
  2254. );
  2255. ACQUIRE_IF_LOCK_SHARED( dwIfBucket );
  2256. bIfLock = TRUE;
  2257. pieEntry = GetIfEntry(
  2258. IF_BUCKET_HEAD( dwIfBucket ),
  2259. pcac-> dwIfIndex, pcac-> dwIfNextHopAddr
  2260. );
  2261. if ( pieEntry == NULL )
  2262. {
  2263. TRACE2(
  2264. ANY,
  2265. "InvokeCreationAlert: Could not find interface 0x%x 0x%x",
  2266. pcac-> dwIfIndex, pcac-> dwIfNextHopAddr
  2267. );
  2268. break;
  2269. }
  2270. //
  2271. // Ensure that group is still joined on the interface. Since this
  2272. // is being executed asynchronously, it is possible that between
  2273. // the time this work item was queued and the time it gets executed
  2274. // the membership may have been deleted.
  2275. //
  2276. dwGrpBucket = GROUP_TABLE_HASH(
  2277. pcac-> dwGroupAddr, pcac-> dwGroupMask
  2278. );
  2279. ACQUIRE_GROUP_LOCK_SHARED( dwGrpBucket );
  2280. bGrpBucket = TRUE;
  2281. pge = GetGroupEntry(
  2282. GROUP_BUCKET_HEAD( dwGrpBucket ),
  2283. pcac-> dwGroupAddr, pcac-> dwGroupMask
  2284. );
  2285. if ( pge == NULL )
  2286. {
  2287. TRACE2(
  2288. ANY, "InvokeCreationAlert: Could not find group 0x%x 0x%x",
  2289. pcac-> dwGroupAddr, pcac-> dwGroupMask
  2290. );
  2291. break;
  2292. }
  2293. ACQUIRE_GROUP_ENTRY_LOCK_SHARED( pge );
  2294. bGrpLock = TRUE;
  2295. dwSrcBucket = SOURCE_TABLE_HASH(
  2296. pcac-> dwSourceAddr, pcac-> dwSourceMask
  2297. );
  2298. pse = GetSourceEntry(
  2299. SOURCE_BUCKET_HEAD( pge, dwSrcBucket ),
  2300. pcac-> dwSourceAddr, pcac-> dwSourceMask
  2301. );
  2302. if ( pse == NULL )
  2303. {
  2304. TRACE2(
  2305. ANY, "InvokeCreationAlert: Could not find source 0x%x "
  2306. "0x%x",
  2307. pcac-> dwSourceAddr, pcac-> dwSourceMask
  2308. );
  2309. break;
  2310. }
  2311. if (GetOutInterfaceEntry(
  2312. &pse-> leOutIfList,
  2313. pcac-> dwIfIndex, pcac-> dwIfNextHopAddr,
  2314. pcac-> dwProtocolId, pcac-> dwComponentId
  2315. ) == NULL)
  2316. {
  2317. TRACE2(
  2318. ANY, "InvokeCreationAlert: Interface 0x%x 0x%x not "
  2319. "present in OIF list",
  2320. pcac-> dwIfIndex, pcac-> dwIfNextHopAddr
  2321. );
  2322. break;
  2323. }
  2324. //
  2325. // release locks
  2326. //
  2327. RELEASE_GROUP_ENTRY_LOCK_SHARED( pge );
  2328. bGrpLock = FALSE;
  2329. RELEASE_GROUP_LOCK_SHARED( dwGrpBucket );
  2330. bGrpBucket = FALSE;
  2331. }
  2332. #endif