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.

1511 lines
41 KiB

  1. //============================================================================
  2. // Copyright (c) 1995, Microsoft Corporation
  3. //
  4. // File: enum.c
  5. //
  6. // History:
  7. // V Raman June-25-1997 Created.
  8. //
  9. // Enumeration functions exported to IP Router Manager.
  10. //============================================================================
  11. #include "pchmgm.h"
  12. #pragma hdrstop
  13. DWORD
  14. GetGroupMfes(
  15. IN PGROUP_ENTRY pge,
  16. IN DWORD dwStartSource,
  17. IN OUT PBYTE pbBuffer,
  18. IN DWORD dwBufferSize,
  19. IN OUT PDWORD pdwSize,
  20. IN OUT PDWORD pdwNumEntries,
  21. IN BOOL bIncludeFirst,
  22. IN DWORD dwFlags
  23. );
  24. VOID
  25. CopyMfe(
  26. IN PGROUP_ENTRY pge,
  27. IN PSOURCE_ENTRY pse,
  28. IN OUT PBYTE pb,
  29. IN DWORD dwFlags
  30. );
  31. //
  32. // MFE enumeration
  33. //
  34. //----------------------------------------------------------------------------
  35. // GetNextMfe
  36. //
  37. //----------------------------------------------------------------------------
  38. DWORD
  39. GetMfe(
  40. IN PMIB_IPMCAST_MFE pmimm,
  41. IN OUT PDWORD pdwBufferSize,
  42. IN OUT PBYTE pbBuffer,
  43. IN DWORD dwFlags
  44. )
  45. {
  46. BOOL bGrpLock = FALSE, bGrpEntryLock = FALSE;
  47. DWORD dwErr = NO_ERROR, dwGrpBucket, dwSrcBucket, dwSizeReqd,
  48. dwInd;
  49. PGROUP_ENTRY pge;
  50. PSOURCE_ENTRY pse;
  51. POUT_IF_ENTRY poie;
  52. PLIST_ENTRY ple, pleHead;
  53. TRACEENUM3(
  54. ENUM, "ENTERED GetMfe : %x, %x, Stats : %x", pmimm-> dwGroup,
  55. pmimm-> dwSource, dwFlags
  56. );
  57. do
  58. {
  59. //
  60. // Find group entry
  61. //
  62. dwGrpBucket = GROUP_TABLE_HASH( pmimm-> dwGroup, 0 );
  63. ACQUIRE_GROUP_LOCK_SHARED( dwGrpBucket );
  64. bGrpLock = TRUE;
  65. pleHead = GROUP_BUCKET_HEAD( dwGrpBucket );
  66. pge = GetGroupEntry( pleHead, pmimm-> dwGroup, 0 );
  67. if ( pge == NULL )
  68. {
  69. //
  70. // group entry not found, quit
  71. //
  72. dwErr = ERROR_NOT_FOUND;
  73. break;
  74. }
  75. //
  76. // acquire group entry lock and release group bucket lock
  77. //
  78. ACQUIRE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  79. bGrpEntryLock = TRUE;
  80. RELEASE_GROUP_LOCK_SHARED( dwGrpBucket );
  81. bGrpLock = FALSE;
  82. //
  83. // Find Source entry
  84. //
  85. dwSrcBucket = SOURCE_TABLE_HASH( pmimm-> dwSource, pmimm-> dwSrcMask );
  86. pleHead = SOURCE_BUCKET_HEAD( pge, dwSrcBucket );
  87. pse = GetSourceEntry( pleHead, pmimm-> dwSource, pmimm-> dwSrcMask );
  88. if ( pse == NULL )
  89. {
  90. //
  91. // Source entry not found, quit
  92. //
  93. dwErr = ERROR_NOT_FOUND;
  94. break;
  95. }
  96. //
  97. // check buffersize requirements
  98. //
  99. dwSizeReqd = ( dwFlags ) ?
  100. ( (dwFlags == MGM_MFE_STATS_0) ?
  101. SIZEOF_MIB_MFE_STATS( pse-> dwMfeIfCount ) :
  102. SIZEOF_MIB_MFE_STATS_EX(
  103. pse-> dwMfeIfCount ) ) :
  104. SIZEOF_MIB_MFE( pse-> dwMfeIfCount );
  105. if ( *pdwBufferSize < dwSizeReqd )
  106. {
  107. //
  108. // buffer supplied is too small to fit the MFE
  109. //
  110. *pdwBufferSize = dwSizeReqd;
  111. dwErr = ERROR_INSUFFICIENT_BUFFER;
  112. break;
  113. }
  114. //
  115. // if mfe statistics have been requested and
  116. // mfe is in the kernel
  117. // get it
  118. //
  119. if ( dwFlags && pse-> bInForwarder )
  120. {
  121. GetMfeFromForwarder( pge, pse );
  122. }
  123. #if 1
  124. CopyMfe( pge, pse, pbBuffer, dwFlags );
  125. #else
  126. //
  127. // copy base MFE into user supplied buffer
  128. //
  129. pmimms = ( PMIB_IPMCAST_MFE_STATS ) pbBuffer;
  130. pmimms-> dwGroup = pge-> dwGroupAddr;
  131. pmimms-> dwSource = pse-> dwSourceAddr;
  132. pmimms-> dwSrcMask = pse-> dwSourceMask;
  133. pmimms-> dwInIfIndex = pse-> dwInIfIndex;
  134. pmimms-> dwUpStrmNgbr = pse-> dwUpstreamNeighbor;
  135. pmimms-> dwInIfProtocol = pse-> dwInProtocolId;
  136. pmimms-> dwRouteProtocol = pse-> dwRouteProtocol;
  137. pmimms-> dwRouteNetwork = pse-> dwRouteNetwork;
  138. pmimms-> dwRouteMask = pse-> dwRouteMask;
  139. pmimms-> ulNumOutIf = pse-> imsStatistics.ulNumOutIf;
  140. pmimms-> ulInPkts = pse-> imsStatistics.ulInPkts;
  141. pmimms-> ulInOctets = pse-> imsStatistics.ulInOctets;
  142. pmimms-> ulPktsDifferentIf = pse-> imsStatistics.ulPktsDifferentIf;
  143. pmimms-> ulQueueOverflow = pse-> imsStatistics.ulQueueOverflow;
  144. MgmElapsedSecs( &pse-> liCreationTime, &pmimms-> ulUpTime );
  145. pmimms-> ulExpiryTime = pse-> dwTimeOut - pmimms-> ulUpTime;
  146. //
  147. // copy all the OIL entries
  148. //
  149. pleHead = &pse-> leMfeIfList;
  150. for ( ple = pleHead-> Flink, dwInd = 0;
  151. ple != pleHead;
  152. ple = ple-> Flink, dwInd++ )
  153. {
  154. poie = CONTAINING_RECORD( ple, OUT_IF_ENTRY, leIfList );
  155. pmimms-> rgmiosOutStats[ dwInd ].dwOutIfIndex =
  156. poie-> imosIfStats.dwOutIfIndex;
  157. pmimms-> rgmiosOutStats[ dwInd ].dwNextHopAddr =
  158. poie-> imosIfStats.dwNextHopAddr;
  159. pmimms-> rgmiosOutStats[ dwInd ].ulTtlTooLow =
  160. poie-> imosIfStats.ulTtlTooLow;
  161. pmimms-> rgmiosOutStats[ dwInd ].ulFragNeeded =
  162. poie-> imosIfStats.ulFragNeeded;
  163. pmimms-> rgmiosOutStats[ dwInd ].ulOutPackets =
  164. poie-> imosIfStats.ulOutPackets;
  165. pmimms-> rgmiosOutStats[ dwInd ].ulOutDiscards =
  166. poie-> imosIfStats.ulOutDiscards;
  167. }
  168. #endif
  169. } while ( FALSE );
  170. //
  171. // release locks are appropriate
  172. //
  173. if ( bGrpEntryLock )
  174. {
  175. RELEASE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  176. }
  177. if ( bGrpLock )
  178. {
  179. RELEASE_GROUP_LOCK_SHARED( dwGrpBucket );
  180. }
  181. TRACEENUM1( ENUM, "LEAVING GetMfe :: %x", dwErr );
  182. return dwErr;
  183. }
  184. //----------------------------------------------------------------------------
  185. // GetNextMfe
  186. //
  187. //----------------------------------------------------------------------------
  188. DWORD
  189. GetNextMfe(
  190. IN PMIB_IPMCAST_MFE pmimmStart,
  191. IN OUT PDWORD pdwBufferSize,
  192. IN OUT PBYTE pbBuffer,
  193. IN OUT PDWORD pdwNumEntries,
  194. IN BOOL bIncludeFirst,
  195. IN DWORD dwFlags
  196. )
  197. {
  198. BOOL bFound, bgeLock = FALSE;
  199. DWORD dwGrpBucket, dwErr = NO_ERROR, dwBufferLeft,
  200. dwStartSource, dwSize;
  201. PBYTE pbStart;
  202. PGROUP_ENTRY pge;
  203. PLIST_ENTRY ple, pleMasterHead, pleGrpBucket;
  204. TRACEENUM2(
  205. ENUM, "ENTERED GetNextMfe (G, S) = (%x, %x)", pmimmStart-> dwGroup,
  206. pmimmStart-> dwSource
  207. );
  208. do
  209. {
  210. //
  211. // 1. Lock group hash bucket.
  212. //
  213. dwGrpBucket = GROUP_TABLE_HASH( pmimmStart-> dwGroup, 0 );
  214. ACQUIRE_GROUP_LOCK_SHARED( dwGrpBucket );
  215. //
  216. // 2. merge temp and master lists
  217. // - Lock temp list
  218. // - merge temp with master list
  219. // - unlock temp list
  220. //
  221. ACQUIRE_TEMP_GROUP_LOCK_EXCLUSIVE();
  222. MergeTempAndMasterGroupLists( TEMP_GROUP_LIST_HEAD() );
  223. ACQUIRE_MASTER_GROUP_LOCK_SHARED();
  224. RELEASE_TEMP_GROUP_LOCK_EXCLUSIVE();
  225. pleMasterHead = MASTER_GROUP_LIST_HEAD();
  226. ple = pleMasterHead-> Flink;
  227. //
  228. // To retrieve the next set of group entries in lexicographic order,
  229. // given a group entry (in this case specified by pmimmStart-> dwGroup)
  230. // the master group list must be walked from the head until either
  231. // the group entry specified is found or the next "higher" group entry
  232. // is found. This is expensive.
  233. //
  234. // As an optimization the group specified (pmimmStart-> dwGroup) is
  235. // looked up in the group hash table. If an entry is found, then the
  236. // group entry contains links into the master (lexicographic) group
  237. // list. These links can the used to determine the next entries in
  238. // the group list. This way we can quickly find an group entry in
  239. // the master list rather than walk the master group list from the
  240. // beginning.
  241. //
  242. // It should be noted that in case the group entry specified in not
  243. // present in the group hash table, it will be necessary to walk the
  244. // master group list from the start.
  245. //
  246. // Each group entry is present in two lists, the hash bucket list
  247. // and either temp group list or the master group list.
  248. //
  249. // For this optimization to "work", it must be ensured that an entry
  250. // present in the hash table is also present in the master
  251. // group list. To ensure this the temp group list is merged into
  252. // the master group list before searching the group hash table for
  253. // the specified entry.
  254. //
  255. //
  256. // At this point the group under consideration (pmimmStart-> dwGroup),
  257. // cannot be added to either the hash bucket or master group list
  258. // if it is not already present because both the group hash bucket lock
  259. // and the master list lock have been acquired.
  260. //
  261. //
  262. // 3. find group entry in the hash list
  263. //
  264. pleGrpBucket = GROUP_BUCKET_HEAD( dwGrpBucket );
  265. pge = GetGroupEntry( pleGrpBucket, pmimmStart-> dwGroup, 0 );
  266. if ( pge != NULL )
  267. {
  268. //
  269. // group entry for pmimmStart-> dwGroup is present. lock the entry.
  270. //
  271. ACQUIRE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  272. bgeLock = TRUE;
  273. //
  274. // release group hash bucket lock
  275. //
  276. RELEASE_GROUP_LOCK_SHARED( dwGrpBucket );
  277. }
  278. else
  279. {
  280. //
  281. // group entry is not present in the hash table, which implies
  282. // that the group entry is not present at all.
  283. //
  284. //
  285. // release group hash bucket lock
  286. //
  287. RELEASE_GROUP_LOCK_SHARED( dwGrpBucket );
  288. //
  289. // 3.1 Walk master list from the start to determine the next
  290. // highest group entry.
  291. //
  292. bFound = FindGroupEntry(
  293. pleMasterHead, pmimmStart-> dwGroup, 0,
  294. &pge, FALSE
  295. );
  296. if ( !bFound && pge == NULL )
  297. {
  298. //
  299. // No more group entries left to enumerate
  300. //
  301. dwErr = ERROR_NO_MORE_ITEMS;
  302. RELEASE_MASTER_GROUP_LOCK_SHARED();
  303. break;
  304. }
  305. //
  306. // Next group entry found. lock it
  307. //
  308. ACQUIRE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  309. bgeLock = TRUE;
  310. bIncludeFirst = TRUE;
  311. }
  312. //
  313. // At this point we have the group entry we want which is
  314. // either the one for pmimmStart-> dwGroup OR the next higher
  315. // one (if there is no group entry for pmimmStart-> Group).
  316. //
  317. //
  318. // 4. Now get as many source entries as will fit into
  319. // the buffer provided.
  320. //
  321. dwBufferLeft = *pdwBufferSize;
  322. pbStart = pbBuffer;
  323. *pdwNumEntries = 0;
  324. dwStartSource = ( bIncludeFirst ) ? 0 : pmimmStart-> dwSource;
  325. dwSize = 0;
  326. while ( ( dwErr = GetGroupMfes( pge, dwStartSource, pbStart,
  327. dwBufferLeft, &dwSize, pdwNumEntries,
  328. bIncludeFirst, dwFlags ) )
  329. == ERROR_MORE_DATA )
  330. {
  331. //
  332. // more data items will fit into this buffer, but no more
  333. // source entries available in this group entry
  334. //
  335. // 4.1 Move forward to next group entry.
  336. //
  337. pbStart += dwSize;
  338. dwBufferLeft -= dwSize;
  339. dwSize = 0;
  340. dwStartSource = 0;
  341. //
  342. // 4.1.1 Release this group entry lock
  343. //
  344. RELEASE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  345. //
  346. // 4.1.2 get next entry lock
  347. //
  348. ple = pge-> leGrpList.Flink;
  349. if ( ple == pleMasterHead )
  350. {
  351. //
  352. // No more group entries in the master group list.
  353. // All MFEs have been exhausted. So quit.
  354. //
  355. dwErr = ERROR_NO_MORE_ITEMS;
  356. bgeLock = FALSE;
  357. break;
  358. }
  359. pge = CONTAINING_RECORD( ple, GROUP_ENTRY, leGrpList );
  360. ACQUIRE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  361. dwStartSource = 0;
  362. bIncludeFirst = TRUE;
  363. }
  364. //
  365. // 5. you have packed as much as possible into the buffer
  366. //
  367. // Clean up and return the correct error code.
  368. //
  369. if ( bgeLock )
  370. {
  371. RELEASE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
  372. }
  373. if ( dwErr == ERROR_INSUFFICIENT_BUFFER )
  374. {
  375. //
  376. // ran out of buffer. If there is at least one Mfe
  377. // packed into the buffer provided then it is ok.
  378. //
  379. if ( *pdwNumEntries != 0 )
  380. {
  381. dwErr = ERROR_MORE_DATA;
  382. }
  383. else
  384. {
  385. //
  386. // not even one entry could be packed into the buffer
  387. // return the size required for this so that an
  388. // appropriately sized buffer can be allocated for the
  389. // next call.
  390. //
  391. *pdwBufferSize = dwSize;
  392. }
  393. }
  394. RELEASE_MASTER_GROUP_LOCK_SHARED();
  395. } while ( FALSE );
  396. TRACEENUM1( ENUM, "LEAVING GetNextMfe : %x", dwErr );
  397. return dwErr;
  398. }
  399. //----------------------------------------------------------------------------
  400. //
  401. // GetGroupMfes
  402. //
  403. // Retrieves as many MFEs for a group starting at the specified source.
  404. // Assumes that the group entry is locked.
  405. //----------------------------------------------------------------------------
  406. DWORD
  407. GetGroupMfes(
  408. IN PGROUP_ENTRY pge,
  409. IN DWORD dwStartSource,
  410. IN OUT PBYTE pbBuffer,
  411. IN DWORD dwBufferSize,
  412. IN OUT PDWORD pdwSize,
  413. IN OUT PDWORD pdwNumEntries,
  414. IN BOOL bIncludeFirst,
  415. IN DWORD dwFlags
  416. )
  417. {
  418. BOOL bFound;
  419. DWORD dwErr = ERROR_MORE_DATA, dwSrcBucket,
  420. dwSizeReqd, dwInd;
  421. PSOURCE_ENTRY pse = NULL;
  422. PLIST_ENTRY pleMasterHead, pleSrcBucket, ple = NULL,
  423. pleSrc;
  424. POUT_IF_ENTRY poie = NULL;
  425. TRACEENUM2(
  426. ENUM, "ENTERED GetGroupMfes : %x, %x",
  427. pge-> dwGroupAddr, dwStartSource
  428. );
  429. do
  430. {
  431. //
  432. // merge temp and group source lists
  433. //
  434. MergeTempAndMasterSourceLists( pge );
  435. //
  436. // similar to the group lookup, optimize the source lookup
  437. // by first trying to find the source entry in the source
  438. // hash table.
  439. //
  440. // If found in the hash table then use the entry's links
  441. // the into master source list to find next entry.
  442. //
  443. // if not found in the hash table walk the master list from
  444. // the beginning to determine the next entry.
  445. //
  446. pleMasterHead = MASTER_SOURCE_LIST_HEAD( pge );
  447. dwSrcBucket = SOURCE_TABLE_HASH( dwStartSource, 0 );
  448. pleSrcBucket = SOURCE_BUCKET_HEAD( pge, dwSrcBucket );
  449. bFound = FindSourceEntry( pleSrcBucket, dwStartSource, 0, &pse, TRUE );
  450. if ( !bFound )
  451. {
  452. //
  453. // source entry is not present in the hash table
  454. // Walk the master source list from the start.
  455. //
  456. pse = NULL;
  457. FindSourceEntry( pleMasterHead, 0, 0, &pse, FALSE );
  458. //
  459. // No next entry found in the master list. Implies
  460. // no more sources in the master source list for this group.
  461. //
  462. if ( pse == NULL )
  463. {
  464. break;
  465. }
  466. }
  467. else
  468. {
  469. //
  470. // Entry for starting source found in hash table.
  471. // Use its links into the master list to get next entry.
  472. //
  473. if ( !bIncludeFirst )
  474. {
  475. ple = pse-> leSrcList.Flink;
  476. pse = CONTAINING_RECORD( ple, SOURCE_ENTRY, leSrcList );
  477. }
  478. }
  479. //
  480. // At this point the entry pointed to by pse is the first entry
  481. // the needs to be packed into the buffer supplied. Starting
  482. // with this source entry keep packing MFEs into the
  483. // buffer till there are no more MFEs for this group.
  484. //
  485. pleSrc = &pse-> leSrcList;
  486. //
  487. // while there are source entries for this group entry
  488. //
  489. while ( pleSrc != pleMasterHead )
  490. {
  491. pse = CONTAINING_RECORD( pleSrc, SOURCE_ENTRY, leSrcList );
  492. //
  493. // Is this source entry an MFE
  494. //
  495. if ( !IS_VALID_INTERFACE( pse-> dwInIfIndex,
  496. pse-> dwInIfNextHopAddr ) )
  497. {
  498. pleSrc = pleSrc-> Flink;
  499. continue;
  500. }
  501. //
  502. // This source entry is an MFE also.
  503. //
  504. //
  505. // Check if enough space left in the buffer to fit this MFE.
  506. //
  507. // If not and not a single MFE is present in the buffer then
  508. // return the size required to fit this MFE.
  509. //
  510. dwSizeReqd = ( dwFlags ) ?
  511. ( ( dwFlags == MGM_MFE_STATS_0 ) ?
  512. SIZEOF_MIB_MFE_STATS( pse-> dwMfeIfCount ) :
  513. SIZEOF_MIB_MFE_STATS_EX(
  514. pse-> dwMfeIfCount
  515. ) ) :
  516. SIZEOF_MIB_MFE( pse-> dwMfeIfCount );
  517. if ( dwBufferSize < dwSizeReqd )
  518. {
  519. dwErr = ERROR_INSUFFICIENT_BUFFER;
  520. if ( *pdwNumEntries == 0 )
  521. {
  522. *pdwSize = dwSizeReqd;
  523. }
  524. break;
  525. }
  526. //
  527. // If MFE stats have been requested and
  528. // MFE is present in the forwarder
  529. // get them.
  530. //
  531. if ( dwFlags && pse-> bInForwarder )
  532. {
  533. //
  534. // MFE is currently in the forwarder. Query it and update
  535. // stats user mode.
  536. //
  537. GetMfeFromForwarder( pge, pse );
  538. }
  539. //
  540. // copy base MFE into user supplied buffer
  541. //
  542. CopyMfe( pge, pse, pbBuffer, dwFlags );
  543. pbBuffer += dwSizeReqd;
  544. dwBufferSize -= dwSizeReqd;
  545. *pdwSize += dwSizeReqd;
  546. (*pdwNumEntries)++;
  547. pleSrc = pleSrc-> Flink;
  548. }
  549. } while ( FALSE );
  550. TRACEENUM2( ENUM, "LEAVING GetGroupsMfes : %d %d", *pdwNumEntries, dwErr );
  551. return dwErr;
  552. }
  553. //============================================================================
  554. // Group Enumeration
  555. //
  556. //============================================================================
  557. PGROUP_ENUMERATOR
  558. VerifyEnumeratorHandle(
  559. IN HANDLE hEnum
  560. )
  561. {
  562. DWORD dwErr;
  563. PGROUP_ENUMERATOR pgeEnum;
  564. pgeEnum = (PGROUP_ENUMERATOR)
  565. ( ( (ULONG_PTR) hEnum )
  566. ^ (ULONG_PTR) MGM_ENUM_HANDLE_TAG );
  567. try
  568. {
  569. if ( pgeEnum-> dwSignature != MGM_ENUM_SIGNATURE )
  570. {
  571. dwErr = ERROR_INVALID_PARAMETER;
  572. TRACE0( ANY, "Invalid Enumeration handle" );
  573. pgeEnum = NULL;
  574. }
  575. }
  576. except ( GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  577. EXCEPTION_EXECUTE_HANDLER :
  578. EXCEPTION_CONTINUE_SEARCH )
  579. {
  580. dwErr = ERROR_INVALID_PARAMETER;
  581. TRACE0( ANY, "Invalid enumeration handle" );
  582. pgeEnum = NULL;
  583. }
  584. return pgeEnum;
  585. }
  586. //
  587. // Get Memberships for buckets
  588. //
  589. DWORD
  590. GetNextGroupMemberships(
  591. IN PGROUP_ENUMERATOR pgeEnum,
  592. IN OUT PDWORD pdwBufferSize,
  593. IN OUT PBYTE pbBuffer,
  594. IN OUT PDWORD pdwNumEntries
  595. )
  596. {
  597. BOOL bIncludeFirst = TRUE, bFound;
  598. DWORD dwMaxEntries, dwGrpBucket, dwErr = ERROR_NO_MORE_ITEMS;
  599. PGROUP_ENTRY pge = NULL;
  600. PSOURCE_GROUP_ENTRY psge;
  601. PLIST_ENTRY ple, pleGrpHead;
  602. do
  603. {
  604. //
  605. // Compute the number of entries that will fit into the buffer
  606. //
  607. dwMaxEntries = (*pdwBufferSize) / sizeof( SOURCE_GROUP_ENTRY );
  608. //
  609. // STEP I :
  610. //
  611. //
  612. // position the start of the GetNext to the group entry that was
  613. // the last enumerated by the previous GetNext operation
  614. //
  615. //
  616. // Find the last group entry retrieved by the previous get operation.
  617. //
  618. dwGrpBucket = GROUP_TABLE_HASH(
  619. pgeEnum-> dwLastGroup, pgeEnum-> dwLastGroupMask
  620. );
  621. ACQUIRE_GROUP_LOCK_SHARED( dwGrpBucket );
  622. pleGrpHead = GROUP_BUCKET_HEAD( dwGrpBucket );
  623. bFound = FindGroupEntry(
  624. pleGrpHead, pgeEnum-> dwLastGroup,
  625. pgeEnum-> dwLastGroupMask, &pge, TRUE
  626. );
  627. if ( bFound )
  628. {
  629. //
  630. // group entry found
  631. //
  632. bIncludeFirst = !pgeEnum-> bEnumBegun;
  633. }
  634. //
  635. // last group entry retrieved by previous getnext is no
  636. // longer present
  637. //
  638. //
  639. // check if there are any more group entries present in
  640. // the same bucket
  641. //
  642. else if ( pge != NULL )
  643. {
  644. //
  645. // Next group entry in the same group bucket.
  646. // For a new group start from the first source bucket,
  647. // first source entry.
  648. //
  649. pgeEnum-> dwLastSource = 0;
  650. pgeEnum-> dwLastSourceMask = 0;
  651. }
  652. else // ( pge == NULL )
  653. {
  654. //
  655. // no more entries in this group bucket, move to next
  656. // non-empty group bucket entry.
  657. //
  658. //
  659. // skip empty buckets in the group hash table
  660. //
  661. do
  662. {
  663. RELEASE_GROUP_LOCK_SHARED( dwGrpBucket );
  664. dwGrpBucket++;
  665. if ( dwGrpBucket >= GROUP_TABLE_SIZE )
  666. {
  667. //
  668. // Entire hash table has been traversed, quit
  669. //
  670. break;
  671. }
  672. //
  673. // Move to next group bucket
  674. //
  675. ACQUIRE_GROUP_LOCK_SHARED( dwGrpBucket );
  676. pleGrpHead = GROUP_BUCKET_HEAD( dwGrpBucket );
  677. //
  678. // Check if any group entries present
  679. //
  680. if ( !IsListEmpty( pleGrpHead ) )
  681. {
  682. //
  683. // group bucket has at least on group entry
  684. //
  685. pge = CONTAINING_RECORD(
  686. pleGrpHead-> Flink, GROUP_ENTRY, leGrpHashList
  687. );
  688. //
  689. // For a new group start from the first source bucket,
  690. // first source entry.
  691. //
  692. pgeEnum-> dwLastSource = 0;
  693. pgeEnum-> dwLastSourceMask = 0;
  694. break;
  695. }
  696. //
  697. // Empty group bucket, move to next one
  698. //
  699. } while ( TRUE );
  700. }
  701. //
  702. // if all hash buckets have been traversed, quit.
  703. //
  704. if ( dwGrpBucket >= GROUP_TABLE_SIZE )
  705. {
  706. break;
  707. }
  708. //
  709. // STEP II:
  710. //
  711. //
  712. // start retrieving group membership entries
  713. //
  714. #pragma prefast(suppress: 11, pge will be initialized else we would broken out above (PREFast bug 758))
  715. ple = &pge-> leGrpHashList;
  716. //
  717. // Walk each hash bucket starting from dwGrpBucket to GROUP_TABLE_SIZE
  718. //
  719. while ( dwGrpBucket < GROUP_TABLE_SIZE )
  720. {
  721. //
  722. // For each group hash table bucket
  723. //
  724. while ( ple != pleGrpHead )
  725. {
  726. //
  727. // For each group entry in the bucket
  728. //
  729. pge = CONTAINING_RECORD( ple, GROUP_ENTRY, leGrpHashList );
  730. ACQUIRE_GROUP_ENTRY_LOCK_SHARED( pge );
  731. dwErr = GetNextMembershipsForThisGroup(
  732. pge, pgeEnum, bIncludeFirst, pbBuffer,
  733. pdwNumEntries, dwMaxEntries
  734. );
  735. RELEASE_GROUP_ENTRY_LOCK_SHARED( pge );
  736. if ( dwErr == ERROR_MORE_DATA )
  737. {
  738. //
  739. // User supplied buffer is full.
  740. //
  741. break;
  742. }
  743. //
  744. // Move to next entry
  745. //
  746. ple = ple-> Flink;
  747. //
  748. // Next group entry in the same group bucket.
  749. // For a new group start from the first source bucket,
  750. // first source entry.
  751. //
  752. pgeEnum-> dwLastSource = 0;
  753. pgeEnum-> dwLastSourceMask = 0;
  754. bIncludeFirst = TRUE;
  755. }
  756. RELEASE_GROUP_LOCK_SHARED( dwGrpBucket );
  757. if ( dwErr == ERROR_MORE_DATA )
  758. {
  759. break;
  760. }
  761. //
  762. // Move to next group bucket
  763. //
  764. dwGrpBucket++;
  765. //
  766. // skip empty group hash buckets
  767. //
  768. while ( dwGrpBucket < GROUP_TABLE_SIZE )
  769. {
  770. ACQUIRE_GROUP_LOCK_SHARED( dwGrpBucket );
  771. pleGrpHead = GROUP_BUCKET_HEAD( dwGrpBucket );
  772. if ( !IsListEmpty( pleGrpHead ) )
  773. {
  774. break;
  775. }
  776. RELEASE_GROUP_LOCK_SHARED( dwGrpBucket );
  777. dwGrpBucket++;
  778. }
  779. if ( dwGrpBucket >= GROUP_TABLE_SIZE )
  780. {
  781. //
  782. // All group buckets have traversed. End of enumeration
  783. //
  784. dwErr = ERROR_NO_MORE_ITEMS;
  785. }
  786. else
  787. {
  788. //
  789. // New group hash bucket, start from source entry 0.
  790. //
  791. ple = pleGrpHead-> Flink;
  792. pgeEnum-> dwLastSource = 0;
  793. pgeEnum-> dwLastSourceMask = 0;
  794. bIncludeFirst = TRUE;
  795. }
  796. }
  797. } while ( FALSE );
  798. pgeEnum-> bEnumBegun = TRUE;
  799. //
  800. // Store the position where the enumeration ended
  801. //
  802. psge = (PSOURCE_GROUP_ENTRY) pbBuffer;
  803. if ( *pdwNumEntries )
  804. {
  805. pgeEnum-> dwLastSource = psge[ *pdwNumEntries - 1 ].dwSourceAddr;
  806. pgeEnum-> dwLastSourceMask = psge[ *pdwNumEntries - 1 ].dwSourceMask;
  807. pgeEnum-> dwLastGroup = psge[ *pdwNumEntries - 1 ].dwGroupAddr;
  808. pgeEnum-> dwLastGroupMask = psge[ *pdwNumEntries - 1 ].dwGroupMask;
  809. }
  810. else
  811. {
  812. pgeEnum-> dwLastSource = 0xFFFFFFFF;
  813. pgeEnum-> dwLastSourceMask = 0xFFFFFFFF;
  814. pgeEnum-> dwLastGroup = 0xFFFFFFFF;
  815. pgeEnum-> dwLastGroupMask = 0xFFFFFFFF;
  816. }
  817. return dwErr;
  818. }
  819. //----------------------------------------------------------------------------
  820. // GetMemberships for Group
  821. //
  822. //----------------------------------------------------------------------------
  823. DWORD
  824. GetNextMembershipsForThisGroup(
  825. IN PGROUP_ENTRY pge,
  826. IN OUT PGROUP_ENUMERATOR pgeEnum,
  827. IN BOOL bIncludeFirst,
  828. IN OUT PBYTE pbBuffer,
  829. IN OUT PDWORD pdwNumEntries,
  830. IN DWORD dwMaxEntries
  831. )
  832. {
  833. BOOL bFound;
  834. DWORD dwErr = ERROR_NO_MORE_ITEMS, dwSrcBucket;
  835. PSOURCE_GROUP_ENTRY psgBuffer;
  836. PSOURCE_ENTRY pse = NULL;
  837. PLIST_ENTRY pleSrcHead, ple;
  838. do
  839. {
  840. if ( *pdwNumEntries >= dwMaxEntries )
  841. {
  842. //
  843. // quit here.
  844. //
  845. dwErr = ERROR_MORE_DATA;
  846. break;
  847. }
  848. psgBuffer = (PSOURCE_GROUP_ENTRY) pbBuffer;
  849. //
  850. // STEP I:
  851. // Position start of enumeration
  852. //
  853. dwSrcBucket = SOURCE_TABLE_HASH(
  854. pgeEnum-> dwLastSource, pgeEnum-> dwLastSourceMask
  855. );
  856. pleSrcHead = SOURCE_BUCKET_HEAD( pge, dwSrcBucket );
  857. bFound = FindSourceEntry(
  858. pleSrcHead, pgeEnum-> dwLastSource,
  859. pgeEnum-> dwLastSourceMask, &pse, TRUE
  860. );
  861. if ( bFound )
  862. {
  863. if ( ( bIncludeFirst ) && !IsListEmpty( &pse-> leOutIfList ) )
  864. {
  865. //
  866. // the first group membership found.
  867. //
  868. psgBuffer[ *pdwNumEntries ].dwSourceAddr = pse-> dwSourceAddr;
  869. psgBuffer[ *pdwNumEntries ].dwSourceMask = pse-> dwSourceMask;
  870. psgBuffer[ *pdwNumEntries ].dwGroupAddr = pge-> dwGroupAddr;
  871. psgBuffer[ (*pdwNumEntries)++ ].dwGroupMask = pge-> dwGroupMask;
  872. if ( *pdwNumEntries >= dwMaxEntries )
  873. {
  874. //
  875. // buffer full. quit here.
  876. //
  877. dwErr = ERROR_MORE_DATA;
  878. break;
  879. }
  880. //
  881. // move to next source
  882. //
  883. ple = pse-> leSrcHashList.Flink;
  884. }
  885. else
  886. {
  887. ple = pse-> leSrcHashList.Flink;
  888. }
  889. }
  890. else if ( pse != NULL )
  891. {
  892. ple = &pse-> leSrcHashList;
  893. }
  894. else
  895. {
  896. ple = pleSrcHead-> Flink;
  897. }
  898. //
  899. // STEP II:
  900. //
  901. // enumerate group memberships
  902. //
  903. while ( *pdwNumEntries < dwMaxEntries )
  904. {
  905. //
  906. // for each source bucket
  907. //
  908. while ( ( ple != pleSrcHead ) &&
  909. ( *pdwNumEntries < dwMaxEntries ) )
  910. {
  911. //
  912. // for each source entry in the bucket
  913. //
  914. //
  915. // if group membership exists for this source
  916. //
  917. pse = CONTAINING_RECORD( ple, SOURCE_ENTRY, leSrcHashList );
  918. if ( !IsListEmpty( &pse-> leOutIfList ) )
  919. {
  920. psgBuffer[ *pdwNumEntries ].dwSourceAddr =
  921. pse-> dwSourceAddr;
  922. psgBuffer[ *pdwNumEntries ].dwSourceMask =
  923. pse-> dwSourceMask;
  924. psgBuffer[ *pdwNumEntries ].dwGroupAddr =
  925. pge-> dwGroupAddr;
  926. psgBuffer[ (*pdwNumEntries)++ ].dwGroupMask =
  927. pge-> dwGroupMask;
  928. if ( *pdwNumEntries >= dwMaxEntries )
  929. {
  930. dwErr = ERROR_MORE_DATA;
  931. }
  932. }
  933. ple = ple-> Flink;
  934. }
  935. dwSrcBucket++;
  936. if ( dwSrcBucket < SOURCE_TABLE_SIZE )
  937. {
  938. pleSrcHead = SOURCE_BUCKET_HEAD( pge, dwSrcBucket );
  939. ple = pleSrcHead-> Flink;
  940. }
  941. else
  942. {
  943. //
  944. // all source buckets for this group have been
  945. // traversed. quit this group entry
  946. //
  947. break;
  948. }
  949. }
  950. } while ( FALSE );
  951. return dwErr;
  952. }
  953. //----------------------------------------------------------------------------
  954. // Copy the MFE (optionally with stats)
  955. //
  956. //----------------------------------------------------------------------------
  957. VOID
  958. CopyMfe(
  959. IN PGROUP_ENTRY pge,
  960. IN PSOURCE_ENTRY pse,
  961. IN OUT PBYTE pb,
  962. IN DWORD dwFlags
  963. )
  964. {
  965. DWORD dwInd;
  966. PLIST_ENTRY ple, pleHead;
  967. POUT_IF_ENTRY poie;
  968. PMIB_IPMCAST_MFE pmimm = NULL;
  969. PMIB_IPMCAST_MFE_STATS pmimms = NULL;
  970. PMIB_IPMCAST_OIF_STATS pmimos = NULL;
  971. //
  972. // copy base MFE into user supplied buffer
  973. //
  974. if ( dwFlags )
  975. {
  976. //
  977. // Need to base MFE
  978. //
  979. pmimms = ( PMIB_IPMCAST_MFE_STATS ) pb;
  980. pmimms-> dwGroup = pge-> dwGroupAddr;
  981. pmimms-> dwSource = pse-> dwSourceAddr;
  982. pmimms-> dwSrcMask = pse-> dwSourceMask;
  983. pmimms-> dwInIfIndex = pse-> dwInIfIndex;
  984. pmimms-> dwUpStrmNgbr = pse-> dwUpstreamNeighbor;
  985. pmimms-> dwInIfProtocol = pse-> dwInProtocolId;
  986. pmimms-> dwRouteProtocol = pse-> dwRouteProtocol;
  987. pmimms-> dwRouteNetwork = pse-> dwRouteNetwork;
  988. pmimms-> dwRouteMask = pse-> dwRouteMask;
  989. MgmElapsedSecs( &pse-> liCreationTime, &pmimms-> ulUpTime );
  990. pmimms-> ulExpiryTime = pse-> dwTimeOut - pmimms-> ulUpTime;
  991. //
  992. // Copy incoming stats
  993. //
  994. pmimms-> ulNumOutIf = pse-> dwMfeIfCount;
  995. pmimms-> ulInPkts = pse-> imsStatistics.ulInPkts;
  996. pmimms-> ulInOctets = pse-> imsStatistics.ulInOctets;
  997. pmimms-> ulPktsDifferentIf = pse-> imsStatistics.ulPktsDifferentIf;
  998. pmimms-> ulQueueOverflow = pse-> imsStatistics.ulQueueOverflow;
  999. if ( dwFlags & MGM_MFE_STATS_1 )
  1000. {
  1001. PMIB_IPMCAST_MFE_STATS_EX pmimmsex =
  1002. ( PMIB_IPMCAST_MFE_STATS_EX ) pb;
  1003. pmimmsex-> ulUninitMfe = pse-> imsStatistics.ulUninitMfe;
  1004. pmimmsex-> ulNegativeMfe = pse-> imsStatistics.ulNegativeMfe;
  1005. pmimmsex-> ulInDiscards = pse-> imsStatistics.ulInDiscards;
  1006. pmimmsex-> ulInHdrErrors = pse-> imsStatistics.ulInHdrErrors;
  1007. pmimmsex-> ulTotalOutPackets= pse-> imsStatistics.ulTotalOutPackets;
  1008. pmimos = pmimmsex-> rgmiosOutStats;
  1009. }
  1010. else
  1011. {
  1012. pmimos = pmimms-> rgmiosOutStats;
  1013. }
  1014. //
  1015. // copy all the OIL entries
  1016. //
  1017. pleHead = &pse-> leMfeIfList;
  1018. for ( ple = pleHead-> Flink, dwInd = 0;
  1019. ple != pleHead;
  1020. ple = ple-> Flink, dwInd++ )
  1021. {
  1022. poie = CONTAINING_RECORD( ple, OUT_IF_ENTRY, leIfList );
  1023. pmimos[ dwInd ].dwOutIfIndex = poie-> dwIfIndex;
  1024. pmimos[ dwInd ].dwNextHopAddr = poie-> dwIfNextHopAddr;
  1025. //
  1026. // Copy outgoing stats
  1027. //
  1028. pmimos[ dwInd ].ulTtlTooLow = poie-> imosIfStats.ulTtlTooLow;
  1029. pmimos[ dwInd ].ulFragNeeded = poie-> imosIfStats.ulFragNeeded;
  1030. pmimos[ dwInd ].ulOutPackets = poie-> imosIfStats.ulOutPackets;
  1031. pmimos[ dwInd ].ulOutDiscards = poie-> imosIfStats.ulOutDiscards;
  1032. }
  1033. }
  1034. else
  1035. {
  1036. //
  1037. // Need to copy non-stats MFE structure only
  1038. //
  1039. pmimm = (PMIB_IPMCAST_MFE) pb;
  1040. pmimm-> dwGroup = pge-> dwGroupAddr;
  1041. pmimm-> dwSource = pse-> dwSourceAddr;
  1042. pmimm-> dwSrcMask = pse-> dwSourceMask;
  1043. pmimm-> dwInIfIndex = pse-> dwInIfIndex;
  1044. pmimm-> dwUpStrmNgbr = pse-> dwUpstreamNeighbor;
  1045. pmimm-> dwInIfProtocol = pse-> dwInProtocolId;
  1046. pmimm-> dwRouteProtocol = pse-> dwRouteProtocol;
  1047. pmimm-> dwRouteNetwork = pse-> dwRouteNetwork;
  1048. pmimm-> dwRouteMask = pse-> dwRouteMask;
  1049. pmimm-> ulNumOutIf = pse-> dwMfeIfCount;
  1050. MgmElapsedSecs( &pse-> liCreationTime, &pmimm-> ulUpTime );
  1051. pmimm-> ulExpiryTime = pse-> dwTimeOut - pmimm-> ulUpTime;
  1052. //
  1053. // copy all the OIL entries minus the stats
  1054. //
  1055. pleHead = &pse-> leMfeIfList;
  1056. for ( ple = pleHead-> Flink, dwInd = 0;
  1057. ple != pleHead;
  1058. ple = ple-> Flink, dwInd++ )
  1059. {
  1060. poie = CONTAINING_RECORD( ple, OUT_IF_ENTRY, leIfList );
  1061. pmimm-> rgmioOutInfo[ dwInd ].dwOutIfIndex =
  1062. poie-> dwIfIndex;
  1063. pmimm-> rgmioOutInfo[ dwInd ].dwNextHopAddr =
  1064. poie-> dwIfNextHopAddr;
  1065. }
  1066. }
  1067. }