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.

1964 lines
53 KiB

  1. //============================================================================
  2. // Copyright (c) 1995, Microsoft Corporation
  3. //
  4. // File: packet.c
  5. //
  6. // History:
  7. // V Raman June-25-1997 Created.
  8. //
  9. // New packet processing.
  10. //============================================================================
  11. #include "pchmgm.h"
  12. #pragma hdrstop
  13. BOOL
  14. IsMFEPresent(
  15. DWORD dwSourceAddr,
  16. DWORD dwSourceMask,
  17. DWORD dwGroupAddr,
  18. DWORD dwGroupMask,
  19. BOOL bAddToForwarder
  20. );
  21. DWORD
  22. InvokeRPFCallbacks(
  23. PPROTOCOL_ENTRY * pppe,
  24. PIF_ENTRY * ppieInIf,
  25. PDWORD pdwIfBucket,
  26. DWORD dwSourceAddr,
  27. DWORD dwSourceMask,
  28. DWORD dwGroupAddr,
  29. DWORD dwGroupMask,
  30. PDWORD pdwInIfIndex,
  31. PDWORD pdwInIfNextHopAddr,
  32. PDWORD pdwUpstreamNbr,
  33. DWORD dwHdrSize,
  34. PBYTE pbPacketHdr,
  35. PHANDLE phNextHop,
  36. PBYTE pbBuffer
  37. );
  38. VOID
  39. CopyAndMergeIfLists(
  40. PLIST_ENTRY pleMfeOutIfList,
  41. PLIST_ENTRY pleOutIfList
  42. );
  43. VOID
  44. CopyAndAppendIfList(
  45. PLIST_ENTRY pleMfeIfList,
  46. PLIST_ENTRY pleOutIfList,
  47. PLIST_ENTRY pleOutIfHead
  48. );
  49. VOID
  50. CopyAndAppendIfList(
  51. PLIST_ENTRY pleMfeIfList,
  52. PLIST_ENTRY pleOutIfList,
  53. PLIST_ENTRY pleOutIfHead
  54. );
  55. VOID
  56. InvokeCreationAlert(
  57. DWORD dwSourceAddr,
  58. DWORD dwSourceMask,
  59. DWORD dwGroupAddr,
  60. DWORD dwGroupMask,
  61. DWORD dwInIfIndex,
  62. DWORD dwInIfNextHopAddr,
  63. PLIST_ENTRY pleMfeOutIfList,
  64. PDWORD pdwMfeOutIfCount
  65. );
  66. BOOL
  67. IsListSame(
  68. IN PLIST_ENTRY pleHead1,
  69. IN PLIST_ENTRY pleHead2
  70. );
  71. VOID
  72. FreeList (
  73. IN PLIST_ENTRY pleHead
  74. );
  75. //----------------------------------------------------------------------------
  76. // MgmNewPacketReceived
  77. //
  78. //----------------------------------------------------------------------------
  79. DWORD
  80. MgmNewPacketReceived(
  81. DWORD dwSourceAddr,
  82. DWORD dwGroupAddr,
  83. DWORD dwInIfIndex,
  84. DWORD dwInIfNextHopAddr,
  85. DWORD dwHdrSize,
  86. PBYTE pbPacketHdr
  87. )
  88. {
  89. BOOL bGrpEntryLock = FALSE,
  90. bGrpLock = FALSE,
  91. bWCGrpEntryLock = FALSE,
  92. bWCGrpLock = FALSE,
  93. bGrpFound = FALSE,
  94. bSrcFound = FALSE,
  95. bIfLock = FALSE;
  96. DWORD dwErr = NO_ERROR,
  97. dwIfBucket,
  98. dwUpStreamNbr = 0,
  99. dwGroupMask = 0, dwGrpBucket, dwWCGrpBucket,
  100. dwSrcBucket, dwWCSrcBucket,
  101. dwSourceMask = 0xFFFFFFFF,
  102. dwTimeOut = EXPIRY_INTERVAL, dwTimerQ,
  103. dwOutIfCount = 0;
  104. PPROTOCOL_ENTRY ppe = NULL;
  105. PIF_ENTRY pieInIf = NULL;
  106. PGROUP_ENTRY pge = NULL, pgeWC = NULL, pgeNew = NULL;
  107. PSOURCE_ENTRY pse = NULL, pseWC = NULL, pseNew = NULL;
  108. POUT_IF_ENTRY poie;
  109. PLIST_ENTRY pleGrpList = NULL, pleSrcList = NULL,
  110. pleWCGrpList = NULL, pleWCSrcList = NULL,
  111. ple, pleTemp;
  112. PTIMER_CONTEXT ptwc = NULL;
  113. LIST_ENTRY leMfeOutIfList, lePrevMfeOutIfList;
  114. NTSTATUS ntStatus;
  115. RTM_ENTITY_INFO reiEntityInfo;
  116. RTM_DEST_INFO rdiDestInfo;
  117. HANDLE hNextHop;
  118. BOOL bRelDest = FALSE;
  119. if ( !ENTER_MGM_API() )
  120. {
  121. return ERROR_CAN_NOT_COMPLETE;
  122. }
  123. TRACE6(
  124. ENTER, "ENTERED MgmNewPacketReceived : Source %x, %x : "
  125. "Group %x, %x : In Interface : %x, %x", dwSourceAddr, dwSourceMask,
  126. dwGroupAddr, dwGroupMask, dwInIfIndex, dwInIfNextHopAddr
  127. );
  128. //--------------------------------------------------------------------
  129. // Check if Mfe is already present for this ( source, group ).
  130. // If so add it to the Kernel mode forwarder.
  131. //--------------------------------------------------------------------
  132. if ( IsMFEPresent(
  133. dwSourceAddr, dwSourceMask, dwGroupAddr, dwGroupMask, TRUE ) )
  134. {
  135. TRACE1( ENTER, "LEAVING MgmNewPacketReceived %x\n", dwErr );
  136. LEAVE_MGM_API();
  137. return dwErr;
  138. }
  139. //--------------------------------------------------------------------
  140. // No Mfe is present for this ( source, group )
  141. //--------------------------------------------------------------------
  142. ACQUIRE_PROTOCOL_LOCK_SHARED();
  143. do
  144. {
  145. //
  146. // Perform RPF check on the incoming interface.
  147. //
  148. RtlZeroMemory( &rdiDestInfo, sizeof( RTM_DEST_INFO ) );
  149. dwErr = InvokeRPFCallbacks(
  150. &ppe, &pieInIf, &dwIfBucket,
  151. dwSourceAddr, dwSourceMask, dwGroupAddr, dwGroupMask,
  152. &dwInIfIndex, &dwInIfNextHopAddr, &dwUpStreamNbr,
  153. dwHdrSize, pbPacketHdr, &hNextHop, (PBYTE) &rdiDestInfo
  154. );
  155. //
  156. // Something is hosed here.
  157. //
  158. if ( dwErr != NO_ERROR )
  159. {
  160. break;
  161. }
  162. bRelDest = TRUE;
  163. bIfLock = TRUE;
  164. //--------------------------------------------------------------------
  165. // In one of the most dramatic events in the multicast world
  166. // scattered membership entries now morph into an MFE, capable of
  167. // sustaining traffic and bringing multicast applications to life.
  168. //
  169. // Gag-gag-gag-uggggghh. Ok enough bad poetic license.
  170. // Just create the MFE asap. (and get a life please)
  171. //--------------------------------------------------------------------
  172. InitializeListHead( &leMfeOutIfList );
  173. InitializeListHead( &lePrevMfeOutIfList );
  174. //
  175. // Check if there is administrative-scoped boundary for this
  176. // group on the incoming interface
  177. //
  178. if ( IS_HAS_BOUNDARY_CALLBACK() &&
  179. HAS_BOUNDARY_CALLBACK()( dwInIfIndex, dwGroupAddr ) )
  180. {
  181. //
  182. // Admin-scoped bounday exists on incoming interface.
  183. // Create a negative MFE to prevent forwarding of
  184. // traffic for this (S, G)
  185. //
  186. TRACEPACKET2(
  187. GROUP, "Admin-scope on for group %lx, incoming interface",
  188. dwInIfIndex, dwGroupAddr
  189. );
  190. //
  191. // find the group entry
  192. //
  193. dwGrpBucket = GROUP_TABLE_HASH( dwGroupAddr, dwGroupMask );
  194. ACQUIRE_GROUP_LOCK_EXCLUSIVE( dwGrpBucket );
  195. bGrpLock = TRUE;
  196. //
  197. // acquire group lock and find group entry in the hash bucket again
  198. //
  199. pleGrpList = GROUP_BUCKET_HEAD( dwGrpBucket );
  200. bGrpFound = FindGroupEntry(
  201. pleGrpList, dwGroupAddr, dwGroupMask, &pge, TRUE
  202. );
  203. if ( bGrpFound )
  204. {
  205. //
  206. // Found group, look up source entry
  207. //
  208. ACQUIRE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  209. bGrpEntryLock = TRUE;
  210. dwSrcBucket = SOURCE_TABLE_HASH( dwSourceAddr, dwSourceMask );
  211. pleSrcList = SOURCE_BUCKET_HEAD( pge, dwSrcBucket );
  212. bSrcFound = FindSourceEntry(
  213. pleSrcList, dwSourceAddr, dwSourceMask,
  214. &pse, TRUE
  215. );
  216. }
  217. }
  218. else
  219. {
  220. do
  221. {
  222. //
  223. // No admin-scope on incoming interface. Proceed to create
  224. // the OIF list for this MFE.
  225. //
  226. //
  227. // 1. check if (*, *) entry is present
  228. //
  229. dwWCGrpBucket = GROUP_TABLE_HASH( 0, 0 );
  230. ACQUIRE_GROUP_LOCK_SHARED( dwWCGrpBucket );
  231. bWCGrpLock = TRUE;
  232. pleWCGrpList = GROUP_BUCKET_HEAD( dwWCGrpBucket );
  233. if ( FindGroupEntry( pleWCGrpList, 0, 0, &pgeWC, TRUE ) )
  234. {
  235. //
  236. // ok wildcard group entry exists.
  237. // find the wildcard source entry.
  238. //
  239. ACQUIRE_GROUP_ENTRY_LOCK_SHARED( pgeWC );
  240. bWCGrpEntryLock = TRUE;
  241. dwWCSrcBucket = SOURCE_TABLE_HASH( 0, 0 );
  242. pleWCSrcList = SOURCE_BUCKET_HEAD( pgeWC, dwWCSrcBucket );
  243. if ( FindSourceEntry( pleWCSrcList, 0, 0, &pseWC, TRUE ) )
  244. {
  245. //
  246. // Copy the outgoing interface list for the (*, *) entry
  247. //
  248. InterlockedExchange( &pseWC-> dwInUse, 1 );
  249. CopyAndMergeIfLists( &leMfeOutIfList, &pseWC-> leOutIfList );
  250. }
  251. }
  252. //
  253. // 2. check if a (*, G) entry is present.
  254. //
  255. dwGrpBucket = GROUP_TABLE_HASH( dwGroupAddr, dwGroupMask );
  256. ACQUIRE_GROUP_LOCK_EXCLUSIVE( dwGrpBucket );
  257. bGrpLock = TRUE;
  258. //
  259. // acquire group lock and find group entry in the hash bucket again
  260. //
  261. pleGrpList = GROUP_BUCKET_HEAD( dwGrpBucket );
  262. bGrpFound = FindGroupEntry(
  263. pleGrpList, dwGroupAddr, dwGroupMask, &pge, TRUE
  264. );
  265. if ( bGrpFound )
  266. {
  267. pseWC = NULL;
  268. //
  269. // group entry present, check if wildcard source is present
  270. //
  271. ACQUIRE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  272. bGrpEntryLock = TRUE;
  273. dwWCSrcBucket = SOURCE_TABLE_HASH( 0, 0 );
  274. pleWCSrcList = SOURCE_BUCKET_HEAD( pge, dwWCSrcBucket );
  275. if ( FindSourceEntry( pleWCSrcList, 0, 0, &pseWC, TRUE ) )
  276. {
  277. //
  278. // Merge the OIL of the (*, G) entry with the OIL of
  279. // the (*, *) entry
  280. //
  281. pseWC-> dwInUse = 1;
  282. CopyAndMergeIfLists( &leMfeOutIfList, &pseWC-> leOutIfList );
  283. }
  284. //
  285. // 3. Check if (S, G) entry is present
  286. //
  287. dwSrcBucket = SOURCE_TABLE_HASH( dwSourceAddr, dwSourceMask );
  288. pleSrcList = SOURCE_BUCKET_HEAD( pge, dwSrcBucket );
  289. bSrcFound = FindSourceEntry(
  290. pleSrcList, dwSourceAddr, dwSourceMask, &pse, TRUE
  291. );
  292. if ( bSrcFound )
  293. {
  294. //
  295. // Source Entry present. Merge with source OIL
  296. //
  297. pse-> dwInUse = 1;
  298. CopyAndMergeIfLists( &leMfeOutIfList, &pse-> leOutIfList );
  299. }
  300. }
  301. //
  302. // If OIF list is empty, no CREATION_ALERTs required.
  303. //
  304. if ( IsListEmpty( &leMfeOutIfList ) )
  305. {
  306. FreeList( &lePrevMfeOutIfList );
  307. InitializeListHead( &lePrevMfeOutIfList );
  308. break;
  309. }
  310. //
  311. // Check if OIF list is the same as previous iteration
  312. //
  313. if ( IsListSame( &lePrevMfeOutIfList, &leMfeOutIfList ) )
  314. {
  315. FreeList( &leMfeOutIfList );
  316. break;
  317. }
  318. //--------------------------------------------------------------------
  319. // It's callback time
  320. //--------------------------------------------------------------------
  321. //
  322. // release all locks before invoking the CREATION_ALERT callback
  323. //
  324. if ( bGrpEntryLock )
  325. {
  326. RELEASE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  327. bGrpEntryLock = FALSE;
  328. }
  329. if ( bGrpLock )
  330. {
  331. RELEASE_GROUP_LOCK_EXCLUSIVE( dwGrpBucket );
  332. bGrpLock = FALSE;
  333. }
  334. if ( bWCGrpEntryLock )
  335. {
  336. RELEASE_GROUP_ENTRY_LOCK_SHARED( pgeWC );
  337. bWCGrpEntryLock = FALSE;
  338. }
  339. if ( bWCGrpLock )
  340. {
  341. RELEASE_GROUP_LOCK_SHARED( dwWCGrpBucket );
  342. bWCGrpLock = FALSE;
  343. }
  344. RELEASE_IF_LOCK_SHARED( dwIfBucket );
  345. bGrpFound = FALSE;
  346. bSrcFound = FALSE;
  347. //
  348. // invoked creation alert for each protocol component that
  349. // has an interface in the OIL.
  350. //
  351. InvokeCreationAlert(
  352. dwSourceAddr, dwSourceMask, dwGroupAddr, dwGroupMask,
  353. dwInIfIndex, dwInIfNextHopAddr, &leMfeOutIfList, &dwOutIfCount
  354. );
  355. //
  356. // Save list from previous iteration
  357. //
  358. FreeList( &lePrevMfeOutIfList );
  359. lePrevMfeOutIfList = leMfeOutIfList;
  360. leMfeOutIfList.Flink-> Blink = &lePrevMfeOutIfList;
  361. leMfeOutIfList.Blink-> Flink = &lePrevMfeOutIfList;
  362. InitializeListHead( &leMfeOutIfList );
  363. ACQUIRE_IF_LOCK_SHARED( dwIfBucket );
  364. } while (TRUE);
  365. }
  366. //
  367. // if OIL is empty, invoke deletion alert for the protocol component
  368. // on the incoming interface interface
  369. //
  370. if ( IsListEmpty( &lePrevMfeOutIfList ) )
  371. {
  372. //
  373. // Outgoing interface list is empty for this MFE
  374. // Invoke deleteion alert on the protocol component on the
  375. // incoming interface
  376. //
  377. if ( IS_PRUNE_ALERT( ppe ) )
  378. {
  379. PRUNE_ALERT( ppe ) (
  380. dwSourceAddr, dwSourceMask, dwGroupAddr, dwGroupMask,
  381. dwInIfIndex, dwInIfNextHopAddr, FALSE, &dwTimeOut
  382. );
  383. }
  384. }
  385. //
  386. // if there was no group entry, create one
  387. //
  388. if ( !bGrpFound )
  389. {
  390. if ( pge != NULL )
  391. {
  392. dwErr = CreateGroupEntry(
  393. &pge-> leGrpHashList, dwGroupAddr, dwGroupMask,
  394. &pgeNew
  395. );
  396. }
  397. else
  398. {
  399. dwErr = CreateGroupEntry(
  400. pleGrpList, dwGroupAddr, dwGroupMask, &pgeNew
  401. );
  402. }
  403. if ( dwErr != NO_ERROR )
  404. {
  405. break;
  406. }
  407. pge = pgeNew;
  408. //
  409. // find source hash bucket
  410. //
  411. ACQUIRE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  412. bGrpEntryLock = TRUE;
  413. dwSrcBucket = SOURCE_TABLE_HASH( dwSourceAddr, dwSourceMask );
  414. pleSrcList = SOURCE_BUCKET_HEAD( pge, dwSrcBucket );
  415. }
  416. //
  417. // if there was no source entry
  418. //
  419. if ( !bSrcFound )
  420. {
  421. if ( pse != NULL )
  422. {
  423. dwErr = CreateSourceEntry(
  424. pge, &pse-> leSrcHashList, dwSourceAddr, dwSourceMask,
  425. &pseNew
  426. );
  427. }
  428. else
  429. {
  430. dwErr = CreateSourceEntry(
  431. pge, pleSrcList, dwSourceAddr, dwSourceMask,
  432. &pseNew
  433. );
  434. }
  435. if ( dwErr != NO_ERROR )
  436. {
  437. break;
  438. }
  439. pse = pseNew;
  440. pge-> dwSourceCount++;
  441. }
  442. //
  443. // Set incoming interface
  444. //
  445. pse-> dwInIfIndex = dwInIfIndex;
  446. pse-> dwInIfNextHopAddr = dwInIfNextHopAddr;
  447. pse-> dwUpstreamNeighbor = dwUpStreamNbr;
  448. pse-> dwInProtocolId = ppe-> dwProtocolId;
  449. pse-> dwInComponentId = ppe-> dwComponentId;
  450. //
  451. // Set route information
  452. //
  453. dwErr = RtmGetEntityInfo(
  454. g_hRtmHandle, rdiDestInfo.ViewInfo[ 0 ].Owner,
  455. &reiEntityInfo
  456. );
  457. if ( dwErr != NO_ERROR )
  458. {
  459. TRACEPACKET1( ANY, "failed to get entity info : %x", dwErr );
  460. pse-> dwRouteProtocol = 0;
  461. }
  462. else
  463. {
  464. pse-> dwRouteProtocol = reiEntityInfo.EntityId.EntityProtocolId;
  465. }
  466. pse-> dwRouteNetwork =
  467. *( (PDWORD) rdiDestInfo.DestAddress.AddrBits );
  468. pse-> dwRouteMask =
  469. RTM_IPV4_MASK_FROM_LEN( rdiDestInfo.DestAddress.NumBits );
  470. pse-> bInForwarder = TRUE;
  471. //
  472. // save timeout in seconds and creation time
  473. //
  474. pse-> dwTimeOut = dwTimeOut / 1000;
  475. NtQuerySystemTime( &pse-> liCreationTime );
  476. //
  477. // save the MFE OIL
  478. //
  479. if ( !IsListEmpty( &lePrevMfeOutIfList ) )
  480. {
  481. pse-> dwMfeIfCount = dwOutIfCount;
  482. pse-> leMfeIfList = lePrevMfeOutIfList;
  483. lePrevMfeOutIfList.Flink-> Blink = &pse-> leMfeIfList;
  484. lePrevMfeOutIfList.Blink-> Flink = &pse-> leMfeIfList;
  485. //
  486. // Free OIF entries on which forwarding is disabled
  487. //
  488. ple = pse-> leMfeIfList.Flink;
  489. while ( ple != &pse-> leMfeIfList )
  490. {
  491. poie = CONTAINING_RECORD( ple, OUT_IF_ENTRY, leIfList );
  492. pleTemp = ple-> Flink;
  493. if ( !poie-> wForward )
  494. {
  495. RemoveEntryList( ple );
  496. MGM_FREE( poie );
  497. }
  498. ple = pleTemp;
  499. }
  500. }
  501. //
  502. // add a reference for the incoming interface
  503. //
  504. AddSourceToRefList(
  505. &pieInIf-> leInIfList, dwSourceAddr, dwSourceMask,
  506. dwGroupAddr, dwGroupMask, IS_PROTOCOL_IGMP( ppe )
  507. );
  508. //
  509. // Set the MFE in the forwarder.
  510. //
  511. AddMfeToForwarder( pge, pse, dwTimeOut );
  512. //
  513. // create timer entry and store timer object
  514. //
  515. //
  516. // allocate a timer context structure
  517. //
  518. ptwc = MGM_ALLOC( sizeof( TIMER_CONTEXT ) );
  519. if ( ptwc == NULL )
  520. {
  521. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  522. TRACE1(
  523. ANY, "Failed to allocate timer context of size : %d",
  524. sizeof( TIMER_CONTEXT )
  525. );
  526. LOGERR0( HEAP_ALLOC_FAILED, dwErr );
  527. break;
  528. }
  529. ptwc-> dwSourceAddr = pse-> dwSourceAddr;
  530. ptwc-> dwSourceMask = pse-> dwSourceMask;
  531. ptwc-> dwGroupAddr = pge-> dwGroupAddr;
  532. ptwc-> dwGroupMask = pge-> dwGroupMask;
  533. ptwc-> dwIfIndex = pse-> dwInIfIndex;
  534. ptwc-> dwIfNextHopAddr = pse-> dwInIfNextHopAddr;
  535. //
  536. // Add timer to appropriate timer Q
  537. //
  538. dwTimerQ = TIMER_TABLE_HASH( pge-> dwGroupAddr );
  539. ntStatus = RtlCreateTimer(
  540. TIMER_QUEUE_HANDLE( dwTimerQ ), &pse-> hTimer,
  541. MFETimerProc, ptwc, dwTimeOut, 0, 0
  542. );
  543. if ( !NT_SUCCESS( ntStatus ) )
  544. {
  545. TRACE1( ANY, "Timer set failed with status %lx", ntStatus );
  546. LOGERR0( INVALID_TIMER_HANDLE, ntStatus );
  547. }
  548. } while ( FALSE );
  549. //
  550. // Release locks and quit
  551. //
  552. if ( bGrpEntryLock )
  553. {
  554. RELEASE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  555. }
  556. if ( bGrpLock )
  557. {
  558. RELEASE_GROUP_LOCK_EXCLUSIVE( dwGrpBucket );
  559. }
  560. if ( bWCGrpEntryLock )
  561. {
  562. RELEASE_GROUP_ENTRY_LOCK_SHARED( pgeWC );
  563. }
  564. if ( bWCGrpLock )
  565. {
  566. RELEASE_GROUP_LOCK_SHARED( dwWCGrpBucket );
  567. }
  568. if ( bIfLock )
  569. {
  570. RELEASE_IF_LOCK_SHARED( dwIfBucket );
  571. }
  572. //
  573. // Add route retuned by RPF check to route table.
  574. //
  575. if ( dwErr == NO_ERROR )
  576. {
  577. AddSourceGroupToRouteRefList(
  578. dwSourceAddr, dwSourceMask, dwGroupAddr, dwGroupMask, hNextHop,
  579. (PBYTE) &rdiDestInfo
  580. );
  581. }
  582. if ( bRelDest )
  583. {
  584. RtmReleaseDestInfo( g_hRtmHandle, &rdiDestInfo );
  585. }
  586. RELEASE_PROTOCOL_LOCK_SHARED();
  587. TRACE1( ENTER, "LEAVING MgmNewPacketReceived %x\n", dwErr );
  588. LEAVE_MGM_API();
  589. return dwErr;
  590. }
  591. //----------------------------------------------------------------------------
  592. // IsMFEPresent
  593. //
  594. // Check if MFE is present for a given (source, group). If it is add it to
  595. // to the kernel mode forwarder.
  596. //----------------------------------------------------------------------------
  597. BOOL
  598. IsMFEPresent(
  599. DWORD dwSourceAddr,
  600. DWORD dwSourceMask,
  601. DWORD dwGroupAddr,
  602. DWORD dwGroupMask,
  603. BOOL bAddToForwarder
  604. )
  605. {
  606. BOOL bMfeFound = FALSE;
  607. DWORD dwGrpBucket, dwSrcBucket;
  608. PLIST_ENTRY pleGrpList, pleSrcList;
  609. PGROUP_ENTRY pge = NULL;
  610. PSOURCE_ENTRY pse = NULL;
  611. //
  612. // check MFE is present for the specified (source, group)
  613. //
  614. dwGrpBucket = GROUP_TABLE_HASH( dwGroupAddr, dwGroupMask );
  615. ACQUIRE_GROUP_LOCK_EXCLUSIVE( dwGrpBucket );
  616. pleGrpList = GROUP_BUCKET_HEAD( dwGrpBucket );
  617. if ( FindGroupEntry(
  618. pleGrpList, dwGroupAddr, dwGroupMask, &pge, TRUE
  619. ) )
  620. {
  621. //
  622. // group entry exists, find source entry
  623. //
  624. ACQUIRE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  625. dwSrcBucket = SOURCE_TABLE_HASH( dwSourceAddr, dwSourceMask );
  626. pleSrcList = SOURCE_BUCKET_HEAD( pge, dwSrcBucket );
  627. if ( FindSourceEntry(
  628. pleSrcList, dwSourceAddr, dwSourceMask, &pse, TRUE
  629. ) )
  630. {
  631. //
  632. // Source entry exists, Is this source entry an MFE ?
  633. //
  634. if ( IS_VALID_INTERFACE( pse-> dwInIfIndex,
  635. pse-> dwInIfNextHopAddr ) )
  636. {
  637. if ( bAddToForwarder )
  638. {
  639. //
  640. // MFE exists, set it to the forwarder
  641. //
  642. AddMfeToForwarder( pge, pse, 0 );
  643. pse-> bInForwarder = TRUE;
  644. }
  645. bMfeFound = TRUE;
  646. }
  647. }
  648. RELEASE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  649. }
  650. RELEASE_GROUP_LOCK_EXCLUSIVE( dwGrpBucket );
  651. return bMfeFound;
  652. }
  653. //----------------------------------------------------------------------------
  654. // InvokeRPFCallbacks
  655. //
  656. // Assumes that the protocol list and the interface bucket are read locked
  657. //----------------------------------------------------------------------------
  658. DWORD
  659. InvokeRPFCallbacks(
  660. PPROTOCOL_ENTRY * pppe,
  661. PIF_ENTRY * ppieInIf,
  662. PDWORD pdwIfBucket,
  663. DWORD dwSourceAddr,
  664. DWORD dwSourceMask,
  665. DWORD dwGroupAddr,
  666. DWORD dwGroupMask,
  667. PDWORD pdwInIfIndex,
  668. PDWORD pdwInIfNextHopAddr,
  669. PDWORD pdwUpStreamNbr,
  670. DWORD dwHdrSize,
  671. PBYTE pbPacketHdr,
  672. PHANDLE phNextHop,
  673. PBYTE pbBuffer
  674. )
  675. {
  676. BOOL bFound = FALSE, bIfLock = FALSE;
  677. DWORD dwErr, dwCount = 0,
  678. dwNewIfBucket;
  679. PPROTOCOL_ENTRY ppe = NULL;
  680. PLIST_ENTRY pleIfList;
  681. BOOL bRelNextHop = FALSE;
  682. RTM_NET_ADDRESS rnaSource;
  683. PRTM_DEST_INFO prdiDestInfo = (PRTM_DEST_INFO) pbBuffer;
  684. RTM_NEXTHOP_INFO rniNextHopInfo;
  685. TRACEPACKET2(
  686. PACKET, "ENTERED InvokeRPFCallbacks : In interface : %x, %x",
  687. *pdwInIfIndex, *pdwInIfNextHopAddr
  688. );
  689. *pppe = NULL;
  690. do
  691. {
  692. //
  693. // format the address
  694. //
  695. RTM_IPV4_MAKE_NET_ADDRESS(
  696. &rnaSource, dwSourceAddr, IPv4_ADDR_LEN
  697. );
  698. //
  699. // lookup route
  700. //
  701. dwErr = RtmGetMostSpecificDestination(
  702. g_hRtmHandle, &rnaSource, RTM_BEST_PROTOCOL,
  703. RTM_VIEW_MASK_MCAST, prdiDestInfo
  704. );
  705. if ( dwErr != NO_ERROR )
  706. {
  707. dwErr = ERROR_CAN_NOT_COMPLETE;
  708. TRACE1( ANY, "No Route to source %x", dwSourceAddr );
  709. break;
  710. }
  711. //
  712. // Pick NHOP
  713. //
  714. *phNextHop = SelectNextHop( prdiDestInfo );
  715. if ( *phNextHop == NULL )
  716. {
  717. dwErr = ERROR_CAN_NOT_COMPLETE;
  718. TRACE1( ANY, "No NextHop to source %x", dwSourceAddr );
  719. break;
  720. }
  721. //
  722. // Get NHOP info
  723. //
  724. dwErr = RtmGetNextHopInfo( g_hRtmHandle, *phNextHop, &rniNextHopInfo );
  725. if ( ( dwErr != NO_ERROR ) ||
  726. ( rniNextHopInfo.State != RTM_NEXTHOP_STATE_CREATED ) )
  727. {
  728. dwErr = ERROR_CAN_NOT_COMPLETE;
  729. TRACE1( ANY, "No Nexthop info to source %x", dwSourceAddr );
  730. break;
  731. }
  732. bRelNextHop = TRUE;
  733. //
  734. // Set the incoming interface as per the route table
  735. //
  736. *pdwInIfIndex = rniNextHopInfo.InterfaceIndex;
  737. //
  738. // The next hop is set to zero by default. This is fine for
  739. // Ethernet and P2P interfaces where this value is 0 for the
  740. // the corresponding IF entries in the IF table.
  741. // But for Point to Multi Point interfaces such
  742. // as the RAS server (internal) interface or NBMA interfaces,
  743. // the NHOP field is used to distinguish interfaces that
  744. // share an IF index. e.g. RAS clients all connect on the
  745. // same interface and are distinguished by different NHOP
  746. // values. Consequently to find an entry in the IF hash
  747. // table we need the (IF index, NHOP) pair.
  748. //
  749. // Here we run into a special case. The new interface as
  750. // determined by the route lookup above gives just an IF
  751. // index. So we have an IF index.
  752. // How do we get a NHOP on this interface ?
  753. //
  754. // (The reason for looking up an interface here is that we
  755. // would like to determine the protocol component that owns
  756. // it and then invoke the RPF callback of that protocol
  757. // component).
  758. //
  759. // The solution to this is based on two assumptions.
  760. // One is
  761. // that only one protocol runs on an interface (single IF
  762. // index). This is true for P2MP interfaces too. So to
  763. // determine the protocol on an interface all one needs to
  764. // do is to find any IF entry that has the same IF index
  765. // (immaterial of the NEXT HOP).
  766. //
  767. // Second is that, all interfaces with the same IF index
  768. // hash to the same bucket in the IF table.
  769. // So all the NHOP on a P2MP will be present in the same
  770. // hash bucket. Also if the route lookup yields say
  771. // IF index X, then looking up (X, (NHOP) 0) in the IF hash
  772. // table will result in finding either IF entry (X, 0) for
  773. // ethernet or P2P interfaces OR IF entry (X, Y) for P2MP
  774. // interfaces where Y is the first among the multiple NHOPs
  775. // that share the same IF index. If neither exists then
  776. // we assume that no entry exits for an interface with
  777. // IF index X and we report an error and quit.
  778. //
  779. // On success we can determine the protocol on IF index X.
  780. //
  781. // All this since we have a hash table index of (IF index,
  782. // NHOP) and we need to look having only a partial key.
  783. //
  784. *pdwInIfNextHopAddr = 0;
  785. TRACEPACKET2(
  786. PACKET, "New incoming interface : %d, %d", *pdwInIfIndex,
  787. *pdwInIfNextHopAddr
  788. );
  789. //
  790. // get the new incoming interface entry
  791. //
  792. dwNewIfBucket = IF_TABLE_HASH( *pdwInIfIndex );
  793. ACQUIRE_IF_LOCK_SHARED( dwNewIfBucket );
  794. bIfLock = TRUE;
  795. *pdwIfBucket = dwNewIfBucket;
  796. bFound = FindIfEntry(
  797. IF_BUCKET_HEAD( dwNewIfBucket), *pdwInIfIndex,
  798. *pdwInIfNextHopAddr, ppieInIf
  799. );
  800. //
  801. // Check if the interface index of this interface is the same
  802. // as that of the incoming interface. Since we are looking
  803. // up the interface purely on IF index and not on
  804. // IF index/NEXTHOP,
  805. // there is a chance for point to multipoint interface e.g.
  806. // RAS server interface, that we could have found a different
  807. // interface
  808. //
  809. if ( ( *ppieInIf == NULL ) ||
  810. ( (*ppieInIf)-> dwIfIndex != *pdwInIfIndex ) )
  811. {
  812. dwErr = ERROR_CAN_NOT_COMPLETE;
  813. TRACE3(
  814. ANY, "InvokeRPFCallbacks : New incoming Interface not"
  815. " found : %x, %x, %x", *pdwInIfIndex,
  816. *pdwInIfNextHopAddr, *ppieInIf
  817. );
  818. LOGWARN0( IF_NOT_FOUND, dwErr );
  819. break;
  820. }
  821. //
  822. // The incoming interface is now correct as per the route table
  823. // Look up the protocol on this interface.
  824. //
  825. ppe = GetProtocolEntry(
  826. PROTOCOL_LIST_HEAD(), (*ppieInIf)-> dwOwningProtocol,
  827. (*ppieInIf)-> dwOwningComponent
  828. );
  829. if ( ppe == NULL )
  830. {
  831. //
  832. // Internal MGM inconsistency. Interface exists
  833. // but the protocol on it does not. Should not
  834. // happen.
  835. //
  836. dwErr = ERROR_CAN_NOT_COMPLETE;
  837. TRACE2(
  838. ANY, "InvokeRPFCallbacks : No protocol entry for"
  839. "incoming interface : %x, %x",
  840. (*ppieInIf)-> dwOwningProtocol,
  841. (*ppieInIf)-> dwOwningComponent
  842. );
  843. break;
  844. }
  845. TRACEPACKET2(
  846. PACKET, "ProtocolEntry for packet %x, %x",
  847. ppe-> dwProtocolId, ppe-> dwComponentId
  848. );
  849. //
  850. // Protocol entry found. Invoke its RPF callback
  851. //
  852. if ( !( IS_RPF_CALLBACK( ppe ) ) )
  853. {
  854. //
  855. // No RPF callback provided by the protocol on the
  856. // incoming interface.
  857. //
  858. dwErr = NO_ERROR;
  859. TRACEPACKET4(
  860. ANY, "InvokeRPFCallbacks : No RPF callback for "
  861. "protocol %x, %x on incoming interface %x, %x",
  862. (*ppieInIf)-> dwOwningProtocol,
  863. (*ppieInIf)-> dwOwningComponent,
  864. (*ppieInIf)-> dwIfIndex,
  865. (*ppieInIf)-> dwIfNextHopAddr
  866. );
  867. break;
  868. }
  869. dwErr = RPF_CALLBACK( ppe )(
  870. dwSourceAddr, dwSourceMask, dwGroupAddr,
  871. dwGroupMask, pdwInIfIndex, pdwInIfNextHopAddr,
  872. pdwUpStreamNbr, dwHdrSize, pbPacketHdr, pbBuffer
  873. );
  874. if ( dwErr == ERROR_INVALID_PARAMETER )
  875. {
  876. //
  877. // In the RPF callback the protocol component has
  878. // changed the incoming interface again. Make sure
  879. // to set the IF bucket value correctly
  880. //
  881. dwNewIfBucket = IF_TABLE_HASH( *pdwInIfIndex );
  882. //
  883. // if this interface is in another hash bucket
  884. //
  885. if ( *pdwIfBucket != dwNewIfBucket )
  886. {
  887. RELEASE_IF_LOCK_SHARED( *pdwIfBucket );
  888. ACQUIRE_IF_LOCK_SHARED( dwNewIfBucket );
  889. *pdwIfBucket = dwNewIfBucket;
  890. }
  891. //
  892. // Find the interface entry corresp. to the
  893. // IF/NHOP as per the protocol
  894. //
  895. TRACEPACKET2(
  896. PACKET, "RPF check returned interface : %x, %x", *pdwInIfIndex,
  897. *pdwInIfNextHopAddr
  898. );
  899. if ( FindIfEntry(
  900. IF_BUCKET_HEAD( dwNewIfBucket ), *pdwInIfIndex,
  901. *pdwInIfNextHopAddr, ppieInIf ) )
  902. {
  903. dwErr = NO_ERROR;
  904. }
  905. else
  906. {
  907. dwErr = ERROR_CAN_NOT_COMPLETE;
  908. }
  909. }
  910. } while ( FALSE );
  911. //
  912. // Clean up
  913. //
  914. if ( bRelNextHop )
  915. {
  916. if ( RtmReleaseNextHopInfo( g_hRtmHandle, &rniNextHopInfo ) !=
  917. NO_ERROR )
  918. {
  919. TRACE1( ANY, "Failed to release next hop : %x", dwErr );
  920. }
  921. }
  922. if ( ( dwErr != NO_ERROR ) && ( bIfLock ) )
  923. {
  924. RELEASE_IF_LOCK_SHARED( dwNewIfBucket );
  925. }
  926. //
  927. // set up the return parameters
  928. //
  929. //
  930. // TDB : in that we need to set a negative MFE if the RPF callback fails
  931. // without generating a route
  932. *pppe = ppe;
  933. TRACE1( PACKET, "LEAVING RPF Callback : %d", dwErr );
  934. return dwErr;
  935. }
  936. //----------------------------------------------------------------------------
  937. // CopyAndMergeIfLists
  938. //
  939. //----------------------------------------------------------------------------
  940. VOID
  941. CopyAndMergeIfLists(
  942. PLIST_ENTRY pleMfeOutIfList,
  943. PLIST_ENTRY pleOutIfList
  944. )
  945. {
  946. BOOL bFound = FALSE;
  947. INT iCmp = 0;
  948. DWORD dwErr = NO_ERROR;
  949. POUT_IF_ENTRY poieOut = NULL, poieMfe = NULL, poie = NULL;
  950. PLIST_ENTRY pleMfe = NULL, pleOut = NULL;
  951. do
  952. {
  953. if ( IsListEmpty( pleOutIfList ) )
  954. {
  955. break;
  956. }
  957. if ( IsListEmpty( pleMfeOutIfList ) )
  958. {
  959. CopyAndAppendIfList(
  960. pleMfeOutIfList, pleOutIfList->Flink, pleOutIfList
  961. );
  962. break;
  963. }
  964. pleMfe = pleMfeOutIfList-> Flink;
  965. pleOut = pleOutIfList-> Flink;
  966. while ( pleMfe != pleMfeOutIfList &&
  967. pleOut != pleOutIfList &&
  968. dwErr == NO_ERROR )
  969. {
  970. poieOut = CONTAINING_RECORD( pleOut, OUT_IF_ENTRY, leIfList );
  971. //
  972. // find location to insert new entry
  973. //
  974. bFound = FALSE;
  975. for ( ; pleMfe != pleMfeOutIfList; pleMfe = pleMfe-> Flink )
  976. {
  977. poieMfe = CONTAINING_RECORD( pleMfe, OUT_IF_ENTRY, leIfList );
  978. if ( poieMfe-> dwProtocolId < poieOut-> dwProtocolId )
  979. {
  980. continue;
  981. }
  982. else if ( poieMfe-> dwProtocolId > poieOut-> dwProtocolId )
  983. {
  984. //
  985. // Interface entry not found
  986. //
  987. break;
  988. }
  989. //
  990. // same protocol
  991. //
  992. //
  993. // is same component
  994. //
  995. if ( poieMfe-> dwComponentId < poieOut-> dwComponentId )
  996. {
  997. continue;
  998. }
  999. else if ( poieMfe-> dwComponentId > poieOut-> dwComponentId )
  1000. {
  1001. //
  1002. // Interface entry not found
  1003. //
  1004. break;
  1005. }
  1006. //
  1007. // same component
  1008. //
  1009. //
  1010. // is same interface
  1011. //
  1012. if ( poieMfe-> dwIfIndex < poieOut-> dwIfIndex )
  1013. {
  1014. continue;
  1015. }
  1016. else if ( poieMfe-> dwIfIndex > poieOut-> dwIfIndex )
  1017. {
  1018. //
  1019. // interface not found
  1020. //
  1021. break;
  1022. }
  1023. //
  1024. // is same next hop addr
  1025. // to do IP address comparison function.
  1026. //
  1027. if ( INET_CMP(
  1028. poieMfe-> dwIfNextHopAddr, poieOut-> dwIfNextHopAddr, iCmp
  1029. ) < 0 )
  1030. {
  1031. continue;
  1032. }
  1033. else if ( iCmp > 0 )
  1034. {
  1035. //
  1036. // interface not found
  1037. //
  1038. break;
  1039. }
  1040. //
  1041. // Interface found
  1042. //
  1043. bFound = TRUE;
  1044. break;
  1045. }
  1046. if ( bFound )
  1047. {
  1048. //
  1049. // Update entry in the Mfe out list
  1050. //
  1051. if ( IS_ADDED_BY_IGMP( poieOut ) )
  1052. {
  1053. SET_ADDED_BY_IGMP( poieMfe );
  1054. poieMfe-> wNumAddsByIGMP += poieOut-> wNumAddsByIGMP;
  1055. }
  1056. if ( IS_ADDED_BY_PROTOCOL( poieOut ) )
  1057. {
  1058. SET_ADDED_BY_PROTOCOL( poieMfe );
  1059. poieMfe-> wNumAddsByRP += poieOut-> wNumAddsByRP;
  1060. }
  1061. pleMfe = pleMfe-> Flink;
  1062. }
  1063. else
  1064. {
  1065. //
  1066. // no matching entry in the mfe list
  1067. //
  1068. poie = MGM_ALLOC( sizeof( OUT_IF_ENTRY ) );
  1069. if ( poie == NULL )
  1070. {
  1071. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1072. TRACE1(
  1073. ANY, "CreateOutInterfaceEntry : Could not allocate"
  1074. "out interface entry %x", dwErr
  1075. );
  1076. LOGERR0( HEAP_ALLOC_FAILED, dwErr );
  1077. break;
  1078. }
  1079. CopyMemory( poie, poieOut, sizeof( OUT_IF_ENTRY ) );
  1080. InsertTailList( pleMfe, &poie-> leIfList );
  1081. }
  1082. pleOut = pleOut-> Flink;
  1083. }
  1084. if ( dwErr != NO_ERROR )
  1085. {
  1086. break;
  1087. }
  1088. //
  1089. // if entries remain in the out list
  1090. //
  1091. if ( pleOut != pleOutIfList )
  1092. {
  1093. CopyAndAppendIfList( pleMfeOutIfList, pleOut, pleOutIfList );
  1094. }
  1095. } while ( FALSE );
  1096. return;
  1097. }
  1098. //----------------------------------------------------------------------------
  1099. // CopyAndAppendIfList
  1100. //
  1101. //----------------------------------------------------------------------------
  1102. VOID
  1103. CopyAndAppendIfList(
  1104. PLIST_ENTRY pleMfeIfList,
  1105. PLIST_ENTRY pleOutIfList,
  1106. PLIST_ENTRY pleOutIfHead
  1107. )
  1108. {
  1109. DWORD dwErr = NO_ERROR;
  1110. POUT_IF_ENTRY poieOut = NULL, poie = NULL;
  1111. for ( ;pleOutIfList != pleOutIfHead; pleOutIfList = pleOutIfList-> Flink )
  1112. {
  1113. poieOut = CONTAINING_RECORD( pleOutIfList, OUT_IF_ENTRY, leIfList );
  1114. poie = MGM_ALLOC( sizeof( OUT_IF_ENTRY ) );
  1115. if ( poie == NULL )
  1116. {
  1117. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1118. TRACE1(
  1119. ANY, "CopyAndAppendIfList : Could not allocate"
  1120. "out interface entry %x", dwErr
  1121. );
  1122. LOGERR0( HEAP_ALLOC_FAILED, dwErr );
  1123. break;
  1124. }
  1125. CopyMemory( poie, poieOut, sizeof( OUT_IF_ENTRY ) );
  1126. InsertTailList( pleMfeIfList, &poie-> leIfList );
  1127. }
  1128. }
  1129. //----------------------------------------------------------------------------
  1130. // InvokeCreationAlert
  1131. //
  1132. //----------------------------------------------------------------------------
  1133. VOID
  1134. InvokeCreationAlert(
  1135. DWORD dwSourceAddr,
  1136. DWORD dwSourceMask,
  1137. DWORD dwGroupAddr,
  1138. DWORD dwGroupMask,
  1139. DWORD dwInIfIndex,
  1140. DWORD dwInIfNextHopAddr,
  1141. PLIST_ENTRY pleMfeOutIfList,
  1142. PDWORD pdwMfeOutIfCount
  1143. )
  1144. {
  1145. DWORD dwCount = 0, dwErr = NO_ERROR, dwInd;
  1146. PPROTOCOL_ENTRY ppe = NULL;
  1147. POUT_IF_ENTRY poieFirst, poieNext, poieTemp;
  1148. PMGM_IF_ENTRY pmie = NULL;
  1149. PLIST_ENTRY ple = NULL, pleFirst = NULL, pleTemp = NULL;
  1150. TRACEPACKET6(
  1151. PACKET, "ENTERED InvokeCreationAlert : Source %x, %x : Group : %x, %x"
  1152. " : Interface %x, %x", dwSourceAddr, dwSourceMask, dwGroupAddr,
  1153. dwGroupMask, dwInIfIndex, dwInIfNextHopAddr
  1154. );
  1155. //
  1156. // remove the incoming interface from the list of outgoing interfaces.
  1157. // remove all interfaces that have have an scope-boundary for this group.
  1158. //
  1159. ple = pleMfeOutIfList-> Flink;
  1160. while ( ple != pleMfeOutIfList )
  1161. {
  1162. poieTemp = CONTAINING_RECORD( ple, OUT_IF_ENTRY, leIfList );
  1163. ple = ple-> Flink;
  1164. //
  1165. // Check if this is the incoming interface or
  1166. // if this interface has a scope-boundary for this group
  1167. //
  1168. if ( ( ( poieTemp-> dwIfIndex == dwInIfIndex ) &&
  1169. ( poieTemp-> dwIfNextHopAddr == dwInIfNextHopAddr ) ) ||
  1170. ( IS_HAS_BOUNDARY_CALLBACK() &&
  1171. HAS_BOUNDARY_CALLBACK()( poieTemp-> dwIfIndex, dwGroupAddr ) ) )
  1172. {
  1173. #if 1
  1174. poieTemp-> wForward = 0;
  1175. #else
  1176. RemoveEntryList( &poieTemp-> leIfList );
  1177. MGM_FREE( poieTemp );
  1178. #endif
  1179. }
  1180. }
  1181. //
  1182. // invoke creation alerts for all components with interfaces in the OIL
  1183. //
  1184. ple = pleMfeOutIfList-> Flink;
  1185. while ( ple != pleMfeOutIfList )
  1186. {
  1187. //
  1188. // The OIL is sorted by components i.e. all interfaces for
  1189. // a component are bunched together.
  1190. //
  1191. // Save the start of the interfaces for current component
  1192. //
  1193. pleFirst = ple;
  1194. poieFirst = CONTAINING_RECORD( pleFirst, OUT_IF_ENTRY, leIfList );
  1195. //
  1196. // Count all interfaces for same component
  1197. //
  1198. dwCount = 0;
  1199. while ( ple != pleMfeOutIfList )
  1200. {
  1201. poieNext = CONTAINING_RECORD( ple, OUT_IF_ENTRY, leIfList );
  1202. #if 1
  1203. if ( !poieNext-> wForward )
  1204. {
  1205. ple = ple-> Flink;
  1206. continue;
  1207. }
  1208. #endif
  1209. if ( poieNext-> dwProtocolId != poieFirst-> dwProtocolId ||
  1210. poieNext-> dwComponentId != poieFirst-> dwComponentId )
  1211. {
  1212. break;
  1213. }
  1214. //
  1215. // another outgoing interface for the same protocol
  1216. //
  1217. dwCount++;
  1218. ple = ple-> Flink;
  1219. }
  1220. //
  1221. // check if we have atleast one out interface entry
  1222. // If not move to next protocol component in the OIL
  1223. //
  1224. if ( dwCount == 0 )
  1225. {
  1226. continue;
  1227. }
  1228. TRACEPACKET3(
  1229. PACKET, "Out If count %d for component %x %x", dwCount,
  1230. poieFirst-> dwProtocolId, poieFirst-> dwComponentId
  1231. );
  1232. pmie = MGM_ALLOC( sizeof( MGM_IF_ENTRY ) * dwCount );
  1233. if ( pmie == NULL )
  1234. {
  1235. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1236. TRACE1(
  1237. ANY, "CopyAndAppendIfList : Could not allocate"
  1238. "out interface entry %x", dwErr
  1239. );
  1240. LOGERR0( HEAP_ALLOC_FAILED, dwErr );
  1241. break;
  1242. }
  1243. //
  1244. // fill up buffer with list of interfaces for the
  1245. // the protocol component and invoke its creation alert.
  1246. //
  1247. pleTemp = pleFirst;
  1248. for ( dwInd = 0; dwInd < dwCount; dwInd++ )
  1249. {
  1250. poieTemp = CONTAINING_RECORD( pleTemp, OUT_IF_ENTRY, leIfList );
  1251. #if 1
  1252. if ( !poieTemp-> wForward )
  1253. {
  1254. pleTemp = pleTemp-> Flink;
  1255. continue;
  1256. }
  1257. #endif
  1258. pmie[ dwInd ].dwIfIndex = poieTemp-> dwIfIndex;
  1259. pmie[ dwInd ].dwIfNextHopAddr = poieTemp-> dwIfNextHopAddr;
  1260. pmie[ dwInd ].bIsEnabled = TRUE;
  1261. pmie[ dwInd ].bIGMP = IS_ADDED_BY_IGMP( poieTemp );
  1262. pleTemp = pleTemp-> Flink;
  1263. }
  1264. ppe = GetProtocolEntry(
  1265. PROTOCOL_LIST_HEAD(), poieFirst-> dwProtocolId,
  1266. poieFirst-> dwComponentId
  1267. );
  1268. if ( IS_CREATION_ALERT( ppe ) )
  1269. {
  1270. CREATION_ALERT( ppe )(
  1271. dwSourceAddr, dwSourceMask, dwGroupAddr, dwGroupMask,
  1272. dwInIfIndex, dwInIfNextHopAddr, dwCount, pmie
  1273. );
  1274. }
  1275. //
  1276. // Accumulate the count of OIF
  1277. //
  1278. *pdwMfeOutIfCount += dwCount;
  1279. //
  1280. // remove the interface the are flaged as disabled
  1281. //
  1282. pleTemp = pleFirst;
  1283. for ( dwInd = 0; dwInd < dwCount; dwInd++ )
  1284. {
  1285. poieTemp = CONTAINING_RECORD( pleTemp, OUT_IF_ENTRY, leIfList );
  1286. ple = pleTemp-> Flink;
  1287. if ( !pmie[ dwInd ].bIsEnabled )
  1288. {
  1289. //
  1290. // Forwarding for this (S, G) for this interface has been
  1291. // disabled by the protocol
  1292. //
  1293. #if 1
  1294. poieTemp-> wForward = 0;
  1295. #else
  1296. RemoveEntryList( pleTemp );
  1297. MGM_FREE( poieTemp );
  1298. #endif
  1299. (*pdwMfeOutIfCount)--;
  1300. }
  1301. pleTemp = ple;
  1302. }
  1303. MGM_FREE( pmie );
  1304. }
  1305. TRACEPACKET2(
  1306. PACKET, "LEAVING InvokeCreationAlert : count %x, error : %x",
  1307. *pdwMfeOutIfCount, dwErr
  1308. );
  1309. }
  1310. //----------------------------------------------------------------------------
  1311. // WrongIfFromForwarder
  1312. //
  1313. //----------------------------------------------------------------------------
  1314. DWORD
  1315. WrongIfFromForwarder(
  1316. IN DWORD dwSourceAddr,
  1317. IN DWORD dwGroupAddr,
  1318. IN DWORD dwInIfIndex,
  1319. IN DWORD dwInIfNextHopAddr,
  1320. IN DWORD dwHdrSize,
  1321. IN PBYTE pbPacketHdr
  1322. )
  1323. {
  1324. DWORD dwErr = NO_ERROR;
  1325. if ( !ENTER_MGM_API() )
  1326. {
  1327. return ERROR_CAN_NOT_COMPLETE;
  1328. }
  1329. TRACE3(
  1330. PACKET, "ENTERED WrongIfFromForwarder for (%lx, %lx) on interface "
  1331. " %lx", dwSourceAddr, dwGroupAddr, dwInIfIndex
  1332. );
  1333. TRACE1( PACKET, "LEAVING WrongIfFromForwarder : %lx\n", dwErr );
  1334. LEAVE_MGM_API();
  1335. return dwErr;
  1336. }
  1337. //----------------------------------------------------------------------------
  1338. // FreeList
  1339. //
  1340. //----------------------------------------------------------------------------
  1341. VOID
  1342. FreeList (
  1343. IN PLIST_ENTRY pleHead
  1344. )
  1345. {
  1346. PLIST_ENTRY ple, pleTemp;
  1347. if ( IsListEmpty( pleHead ) )
  1348. {
  1349. return;
  1350. }
  1351. ple = pleHead-> Flink;
  1352. while ( ple != pleHead )
  1353. {
  1354. pleTemp = ple-> Flink;
  1355. RemoveEntryList( ple );
  1356. MGM_FREE( ple );
  1357. ple = pleTemp;
  1358. }
  1359. }
  1360. //----------------------------------------------------------------------------
  1361. // IsListSame
  1362. //
  1363. //----------------------------------------------------------------------------
  1364. BOOL
  1365. IsListSame(
  1366. IN PLIST_ENTRY pleHead1,
  1367. IN PLIST_ENTRY pleHead2
  1368. )
  1369. {
  1370. PLIST_ENTRY ple1, ple2;
  1371. POUT_IF_ENTRY poif1, poif2;
  1372. //
  1373. // Check for empty lists
  1374. //
  1375. if ( ( IsListEmpty( pleHead1 ) && !IsListEmpty( pleHead2 ) ) ||
  1376. ( !IsListEmpty( pleHead1 ) && IsListEmpty( pleHead2 ) ) )
  1377. {
  1378. return FALSE;
  1379. }
  1380. if ( IsListEmpty( pleHead1 ) && IsListEmpty( pleHead2 ) )
  1381. {
  1382. return TRUE;
  1383. }
  1384. //
  1385. // walk lists in tandem and verify equality
  1386. //
  1387. ple1 = pleHead1-> Flink;
  1388. ple2 = pleHead2-> Flink;
  1389. do
  1390. {
  1391. poif1 = CONTAINING_RECORD( ple1, OUT_IF_ENTRY, leIfList );
  1392. poif2 = CONTAINING_RECORD( ple2, OUT_IF_ENTRY, leIfList );
  1393. if ( ( poif1-> dwIfIndex != poif2-> dwIfIndex ) ||
  1394. ( poif1-> dwIfNextHopAddr != poif2-> dwIfNextHopAddr ) )
  1395. {
  1396. return FALSE;
  1397. }
  1398. ple1 = ple1-> Flink;
  1399. ple2 = ple2-> Flink;
  1400. } while ( ( ple1 != pleHead1 ) && ( ple2 != pleHead2 ) );
  1401. //
  1402. // If both lists have reached their ends, they match else they don't
  1403. //
  1404. if ( ( ( ple1 != pleHead1 ) && ( ple2 == pleHead2 ) ) ||
  1405. ( ( ple1 == pleHead1 ) && ( ple2 != pleHead2 ) ) )
  1406. {
  1407. return FALSE;
  1408. }
  1409. else
  1410. {
  1411. return TRUE;
  1412. }
  1413. }