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.

2419 lines
73 KiB

  1. #include "pchigmp.h"
  2. #pragma hdrstop
  3. //deldel
  4. #define PRINT_SOURCES_LIST 0
  5. VOID
  6. DebugSources(
  7. PGI_ENTRY pgie
  8. )
  9. {
  10. PGI_SOURCE_ENTRY pSourceEntry, pSourceEntry2;
  11. PLIST_ENTRY pHead, ple;
  12. DebugPrintSourcesList(pgie);
  13. pHead = &pgie->V3InclusionListSorted;
  14. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  15. pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY,LinkSourcesInclListSorted);
  16. if (GetSourceEntry(pgie, pSourceEntry->IpAddr,EXCLUSION, NULL, 0, 0))
  17. DbgBreakPoint();
  18. if (ple->Flink!=pHead) {
  19. pSourceEntry2 = CONTAINING_RECORD(ple->Flink, GI_SOURCE_ENTRY,LinkSourcesInclListSorted);
  20. if (pSourceEntry2->IpAddr==pSourceEntry->IpAddr)
  21. DbgBreakPoint();
  22. }
  23. }
  24. pHead = &pgie->V3ExclusionList;
  25. for (ple=pHead->Flink; ple!=pHead && ple->Flink!=pHead; ple=ple->Flink) {
  26. pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY,LinkSources);
  27. pSourceEntry2 = CONTAINING_RECORD(ple->Flink, GI_SOURCE_ENTRY,LinkSources);
  28. if (pSourceEntry->IpAddr == pSourceEntry2->IpAddr)
  29. DbgBreakPoint();
  30. }
  31. return;
  32. }
  33. DWORD
  34. ProcessGroupQuery(
  35. PIF_TABLE_ENTRY pite,
  36. IGMP_HEADER UNALIGNED *pHdr,
  37. DWORD InPacketSize,
  38. DWORD InputSrcAddr,
  39. DWORD DstnMcastAddr
  40. )
  41. {
  42. PGROUP_TABLE_ENTRY pge; //group table entry
  43. PGI_ENTRY pgie; //group interface entry
  44. BOOL bCreateGroup, bCreateGI;
  45. DWORD NHAddr =0, PacketSize, Group, i,RealPktVersion,
  46. IfIndex=pite->IfIndex, PktVersion, GIVersion, IfVersion;
  47. BOOL bRas=FALSE, bUpdateGroupTimer=FALSE;
  48. DWORD NumGroupRecords;
  49. LONGLONG llCurTime = GetCurrentIgmpTime();
  50. PIGMP_IF_CONFIG pConfig = &pite->Config;
  51. PIGMP_HEADER_V3_EXT pSourcesRecord;
  52. Trace0(ENTER1, "Entering _ProcessGroupQuery()");
  53. RealPktVersion = InPacketSize>sizeof(IGMP_HEADER)?3:2;
  54. PktVersion = (InPacketSize>sizeof(IGMP_HEADER) && IS_IF_VER3(pite))?3:2;
  55. IfVersion = IS_IF_VER1(pite)? 1: (IS_IF_VER2(pite)?2:3);
  56. Group = pHdr->Group;
  57. Trace3(RECEIVE,
  58. "Group-specific-query(%d) received from %d.%d.%d.%d for "
  59. "group(%d.%d.%d.%d)",
  60. RealPktVersion, PRINT_IPADDR(InputSrcAddr), PRINT_IPADDR(DstnMcastAddr));
  61. if (RealPktVersion==3) {
  62. // validate packet size
  63. if (InPacketSize<sizeof(IGMP_HEADER)+sizeof(IGMP_HEADER_V3_EXT)) {
  64. Trace0(RECEIVE,
  65. "Group-specific-query dropped. Invalid packet size");
  66. return ERROR_CAN_NOT_COMPLETE;
  67. }
  68. pSourcesRecord = (PIGMP_HEADER_V3_EXT)(pHdr+1);
  69. //convert to host order
  70. pSourcesRecord->NumSources = ntohs(pSourcesRecord->NumSources);
  71. if (InPacketSize<sizeof(IGMP_HEADER)+sizeof(IGMP_HEADER_V3_EXT)
  72. + pSourcesRecord->NumSources*sizeof(IPADDR))
  73. {
  74. Trace0(RECEIVE,
  75. "Group-specific-query dropped. Invalid packet size");
  76. return ERROR_CAN_NOT_COMPLETE;
  77. }
  78. for (i=0; i<pSourcesRecord->NumSources; i++) {
  79. Trace1(RECEIVE," %d.%d.%d.%d",
  80. PRINT_IPADDR(pSourcesRecord->Sources[i]));
  81. }
  82. }
  83. //
  84. // the multicast group should not be 224.0.0.x
  85. //
  86. if (LOCAL_MCAST_GROUP(DstnMcastAddr)) {
  87. Trace2(RECEIVE,
  88. "Group-specific-query received from %d.%d.%d.%d for "
  89. "Local group(%d.%d.%d.%d)",
  90. PRINT_IPADDR(InputSrcAddr), PRINT_IPADDR(DstnMcastAddr));
  91. return ERROR_CAN_NOT_COMPLETE;
  92. }
  93. //
  94. // make sure that the dstn addr and the group fields match
  95. //
  96. if (Group!=DstnMcastAddr) {
  97. Trace4(RECEIVE,
  98. "Received Igmp packet (%d) from(%d.%d.%d.%d) with "
  99. "Multicast(%d.%d.%d.%d) addr different from "
  100. "Group(%d.%d.%d.%d)",
  101. IfIndex, PRINT_IPADDR(InputSrcAddr),
  102. PRINT_IPADDR(DstnMcastAddr),
  103. PRINT_IPADDR(pHdr->Group)
  104. );
  105. return ERROR_CAN_NOT_COMPLETE;
  106. }
  107. // note that a querier can receive a group-Sp query from a non querier
  108. //
  109. // if Leave processing not enabled or currently version-1 or ras server interface
  110. // then ignore.
  111. //
  112. if ( !IF_PROCESS_GRPQUERY(pite) ) {
  113. Trace0(RECEIVE, "Ignoring the Group-Specific-Query");
  114. return ERROR_CAN_NOT_COMPLETE;
  115. }
  116. //
  117. // Lock the group table
  118. //
  119. ACQUIRE_GROUP_LOCK(Group, "_ProcessGroupQuery");
  120. //
  121. // find the group entry. If entry not found then ignore the group query
  122. //
  123. pge = GetGroupFromGroupTable(Group, NULL, llCurTime);
  124. if (pge==NULL) {
  125. Trace2(ERR, "group sp-query received for nonexisting "
  126. "group(%d.%d.%d.%d) on IfIndex(%0x)",
  127. PRINT_IPADDR(Group), IfIndex);
  128. RELEASE_GROUP_LOCK(Group, "_ProcessGroupQuery");
  129. return ERROR_CAN_NOT_COMPLETE;
  130. }
  131. //
  132. // find the GI entry. If GI entry does not exist or has deletedFlag then
  133. // ignore the GroupSpQuery
  134. //
  135. pgie = GetGIFromGIList(pge, pite, InputSrcAddr, NOT_STATIC_GROUP, NULL, llCurTime);
  136. if ( (pgie==NULL)||(pgie->Status&DELETED_FLAG) ) {
  137. Trace2(ERR, "group sp-query received for group(%d.%d.%d.%d) on "
  138. "IfIndex(%0x). Not member.",
  139. PRINT_IPADDR(Group), IfIndex);
  140. RELEASE_GROUP_LOCK(Group, "_ProcessGroupQuery");
  141. return ERROR_CAN_NOT_COMPLETE;
  142. }
  143. GIVersion = pgie->Version;
  144. // treat it as ver 2 packet if group in ver-2 mode
  145. if (GIVersion==2 && PktVersion==3)
  146. PktVersion = 2;
  147. if (RealPktVersion==3 && PktVersion==2)
  148. Trace0(RECEIVE, "Processing the Version:3 GroupSpQuery as Version:2");
  149. //
  150. // if interface is ver-1 or its leave enabled flag is not set or
  151. // if v1-report received recently for that group, then ignore
  152. // LastMemQuery messages.
  153. //
  154. if ( !GI_PROCESS_GRPQUERY(pite, pgie) )
  155. {
  156. Trace2(RECEIVE,
  157. "Leave not processed for group(%d.%d.%d.%d) on IfIndex(%0x)"
  158. "(recent v1 report) or interface ver-1",
  159. PRINT_IPADDR(Group), IfIndex
  160. );
  161. RELEASE_GROUP_LOCK(Group, "_ProcessGroupQuery");
  162. return ERROR_CAN_NOT_COMPLETE;
  163. }
  164. ACQUIRE_TIMER_LOCK("_ProcessGroupQuery");
  165. BEGIN_BREAKOUT_BLOCK1 {
  166. if (PktVersion==2 && GIVersion==2) {
  167. //
  168. // if membership timer already expired then return. The group will be
  169. // deleted by the expiry of the membership timer
  170. //
  171. if ( (!(pgie->GroupMembershipTimer.Status&TIMER_STATUS_ACTIVE))
  172. ||(pgie->GroupMembershipTimer.Timeout<llCurTime) )
  173. {
  174. //DeleteGIEntry(pgie, TRUE);
  175. GOTO_END_BLOCK1;
  176. }
  177. //
  178. // if currently processing a leave then remove LeaveTimer if received
  179. // LastMemquery from lower Ip, else ignore the LastMemQuery
  180. //
  181. if (pgie->LastMemQueryCount>0) {
  182. INT cmp;
  183. if (INET_CMP(InputSrcAddr,pite->IpAddr, cmp)<0) {
  184. if (pgie->LastMemQueryTimer.Status==TIMER_STATUS_ACTIVE) {
  185. RemoveTimer(&pgie->LastMemQueryTimer, DBG_Y);
  186. }
  187. pgie->LastMemQueryCount = 0;
  188. }
  189. GOTO_END_BLOCK1;
  190. }
  191. //
  192. // set membership timer to
  193. // min{currentValue,MaxResponseTimeInPacket*LastMemQueryCount}
  194. //
  195. if (pgie->GroupMembershipTimer.Timeout >
  196. (llCurTime+( ((LONGLONG)pConfig->LastMemQueryCount)
  197. *pHdr->ResponseTime*100 ))
  198. )
  199. {
  200. //divide by 10, as Response time in units of 100ms
  201. #if DEBUG_TIMER_TIMERID
  202. SET_TIMER_ID(&pgie->GroupMembershipTimer, 330,
  203. pite->IfIndex, Group, 0);
  204. #endif
  205. if (IS_TIMER_ACTIVE(pgie->GroupMembershipTimer)) {
  206. UpdateLocalTimer(&pgie->GroupMembershipTimer,
  207. pConfig->LastMemQueryCount*pHdr->ResponseTime*100, DBG_N);
  208. }
  209. else {
  210. InsertTimer(&pgie->GroupMembershipTimer,
  211. pConfig->LastMemQueryCount*pHdr->ResponseTime*100,
  212. TRUE, DBG_N
  213. );
  214. }
  215. // update GroupExpiryTime so that correct stats are displayed
  216. pgie->Info.GroupExpiryTime = llCurTime
  217. + CONFIG_TO_SYSTEM_TIME(pConfig->LastMemQueryCount
  218. *pHdr->ResponseTime*100);
  219. }
  220. }
  221. else if (PktVersion==2 && GIVersion==3){
  222. // ignore the packet
  223. Trace0(RECEIVE, "Ignoring the version-2 group specific query");
  224. }
  225. else if (PktVersion==3 && GIVersion==3) {
  226. // ignore it if SFlag set
  227. if (pSourcesRecord->SFlag == 1)
  228. GOTO_END_BLOCK1;
  229. for (i=0; i<pSourcesRecord->NumSources; i++) {
  230. IPADDR Source;
  231. PGI_SOURCE_ENTRY pSourceEntry;
  232. Source = pSourcesRecord->Sources[i];
  233. pSourceEntry = GetSourceEntry(pgie, Source, INCLUSION,
  234. NULL, 0, 0);
  235. if (!pSourceEntry)
  236. continue;
  237. if ((QueryRemainingTime(&pSourceEntry->SourceExpTimer, 0)
  238. >pgie->pIfTableEntry->Config.LastMemQueryInterval) )
  239. {
  240. #if DEBUG_TIMER_TIMERID
  241. pSourceEntry->SourceExpTimer.Id = 621;
  242. pSourceEntry->SourceExpTimer.Id2 = TimerId++;
  243. #endif
  244. UpdateLocalTimer(&pSourceEntry->SourceExpTimer,
  245. pite->Config.LastMemQueryInterval, DBG_N);
  246. }
  247. }
  248. }
  249. } END_BREAKOUT_BLOCK1;
  250. //
  251. //release timer and groupBucket locks
  252. //
  253. RELEASE_TIMER_LOCK("_ProcessGroupQuery");
  254. RELEASE_GROUP_LOCK(Group, "_ProcessGroupQuery");
  255. Trace0(LEAVE1, "Leaving _ProcessGroupQuery()");
  256. return NO_ERROR;
  257. }
  258. DWORD
  259. ProcessReport(
  260. PIF_TABLE_ENTRY pite,
  261. IGMP_HEADER UNALIGNED *pHdr,
  262. DWORD InPacketSize,
  263. DWORD InputSrcAddr,
  264. DWORD DstnMcastAddr
  265. )
  266. {
  267. PGROUP_TABLE_ENTRY pge; //group table entry
  268. PGI_ENTRY pgie; //group interface entry
  269. BOOL bCreateGroup, bCreateGI;
  270. DWORD NHAddr =0, PacketSize, Group, i,
  271. IfIndex=pite->IfIndex, PktVersion, GIVersion, IfVersion;
  272. BOOL bRas=FALSE, bUpdateGroupTimer=FALSE;
  273. DWORD NumGroupRecords;
  274. LONGLONG llCurTime = GetCurrentIgmpTime();
  275. PIGMP_IF_CONFIG pConfig = &pite->Config;
  276. //v3
  277. PGROUP_RECORD pGroupRecord;
  278. Trace0(ENTER1, "Entering _ProcessReport()");
  279. switch(pHdr->Vertype)
  280. {
  281. case IGMP_REPORT_V1: PktVersion=1; break;
  282. case IGMP_REPORT_V2: PktVersion=2; break;
  283. case IGMP_REPORT_V3: PktVersion=3; break;
  284. }
  285. IfVersion = IS_IF_VER1(pite)? 1: (IS_IF_VER2(pite)?2:3);
  286. Trace5(RECEIVE,
  287. "IGMP-V%d Report from (%d.%d.%d.%d) on "
  288. "IfIndex(%0x)%d.%d.%d.%d dstaddr:%d.%d.%d.%d",
  289. PktVersion, PRINT_IPADDR(InputSrcAddr), IfIndex,
  290. PRINT_IPADDR(pite->IpAddr),
  291. PRINT_IPADDR(DstnMcastAddr)
  292. );
  293. //
  294. // the multicast group should not be 224.0.0.x or SSM
  295. //
  296. if (PktVersion!=3 && (LOCAL_MCAST_GROUP(pHdr->Group) ||
  297. SSM_MCAST_GROUP(pHdr->Group)))
  298. {
  299. Trace3(RECEIVE,
  300. "Igmp-v%d report received from %d.%d.%d.%d for Local/SSM group(%d.%d.%d.%d)",
  301. PktVersion, PRINT_IPADDR(InputSrcAddr), PRINT_IPADDR(DstnMcastAddr));
  302. return ERROR_CAN_NOT_COMPLETE;
  303. }
  304. if (PktVersion!=3)
  305. Trace1(RECEIVE, " Group:%d.%d.%d.%d\n", PRINT_IPADDR(pHdr->Group));
  306. if (PktVersion==3) {
  307. //
  308. // validate packet size
  309. //
  310. // convert to host order
  311. pHdr->NumGroupRecords = ntohs(pHdr->NumGroupRecords);
  312. PacketSize = sizeof(IGMP_HEADER);
  313. NumGroupRecords = pHdr->NumGroupRecords;
  314. // min size of each group record is 2*ipaddr
  315. PacketSize += NumGroupRecords*2*sizeof(IPADDR);
  316. BEGIN_BREAKOUT_BLOCK1 {
  317. PCHAR StrRecordType[] = {"", "is_in", "is_ex", "to_in",
  318. "to_ex", "allow", "BLOCK"};
  319. i = 0;
  320. if (PacketSize>InPacketSize) {
  321. GOTO_END_BLOCK1;
  322. }
  323. pGroupRecord = GET_FIRST_GROUP_RECORD(pHdr);
  324. for (; i<NumGroupRecords; i++) {
  325. DWORD j;
  326. // convert to host order
  327. pGroupRecord->NumSources = ntohs(pGroupRecord->NumSources);
  328. PacketSize += pGroupRecord->NumSources*sizeof(IPADDR);
  329. if (PacketSize>InPacketSize)
  330. GOTO_END_BLOCK1;
  331. // print group record
  332. Trace3(RECEIVE,
  333. "< Group:%d.%d.%d.%d RecordType:%s NumSources:%d >",
  334. PRINT_IPADDR(pGroupRecord->Group),
  335. StrRecordType[pGroupRecord->RecordType],
  336. pGroupRecord->NumSources
  337. );
  338. for (j=0; j<pGroupRecord->NumSources; j++)
  339. Trace1(RECEIVE, " %d.%d.%d.%d",
  340. PRINT_IPADDR(pGroupRecord->Sources[j]));
  341. //
  342. // error if local_mcast or ssm-exclude mode
  343. //
  344. if (LOCAL_MCAST_GROUP(pGroupRecord->Group) ||
  345. (SSM_MCAST_GROUP(pGroupRecord->Group)
  346. && (pGroupRecord->RecordType == IS_EX
  347. || pGroupRecord->RecordType == TO_EX)) )
  348. {
  349. Trace3(RECEIVE,
  350. "Igmp-v%d report received from %d.%d.%d.%d for Local/SSM group(%d.%d.%d.%d)",
  351. PktVersion, PRINT_IPADDR(InputSrcAddr), PRINT_IPADDR(DstnMcastAddr));
  352. return ERROR_CAN_NOT_COMPLETE;
  353. }
  354. pGroupRecord = (PGROUP_RECORD)
  355. &(pGroupRecord->Sources[pGroupRecord->NumSources]);
  356. }
  357. } END_BREAKOUT_BLOCK1;
  358. if (i!=NumGroupRecords || PacketSize>InPacketSize) {
  359. Trace0(ERR, "Received IGMP-v3 report small size");
  360. InterlockedIncrement(&pite->Info.ShortPacketsReceived);
  361. return ERROR_CAN_NOT_COMPLETE;
  362. }
  363. if (PacketSize<InPacketSize){
  364. Trace0(ERR, "Received IGMP-v3 report large size");
  365. InterlockedIncrement(&pite->Info.LongPacketsReceived);
  366. }
  367. pGroupRecord = GET_FIRST_GROUP_RECORD(pHdr);
  368. }//pktversion==3
  369. // for v1 and v2, set num group records to 1 so that it will come out of
  370. // loop
  371. else {
  372. NumGroupRecords = 1;
  373. }
  374. //
  375. // check that the dstn addr is correct.
  376. // should be same as group, or unicast ipaddr
  377. // or v3: could be All_Igmp_routers group
  378. //
  379. if (! ((DstnMcastAddr==pite->IpAddr)
  380. || (PktVersion!=3 && DstnMcastAddr==pHdr->Group)
  381. || (PktVersion==3 && DstnMcastAddr==ALL_IGMP_ROUTERS_MCAST)) )
  382. {
  383. Trace3(RECEIVE,
  384. "received IGMP report packet on IfIndex(%0x) from "
  385. "SrcAddr(%d.%d.%d.%d) but invalid DstnMcastAddr(%d.%d.%d.%d)",
  386. IfIndex, PRINT_IPADDR(InputSrcAddr), PRINT_IPADDR(DstnMcastAddr)
  387. );
  388. return ERROR_CAN_NOT_COMPLETE;
  389. }
  390. //
  391. // V1 router ignores V2/V3 reports. V2 router ignores v3 reports
  392. //
  393. if ( (IfVersion==1 && (PktVersion==2||PktVersion==3))
  394. ||(IfVersion==2 && PktVersion==3) )
  395. {
  396. Trace1(RECEIVE, "Ignoring higher version:%d IGMP report", PktVersion);
  397. return NO_ERROR;
  398. }
  399. //
  400. // update statistics
  401. //
  402. InterlockedIncrement(&pite->Info.JoinsReceived);
  403. // numgrouprecords==1 for v1,v2
  404. for (i=0; i<NumGroupRecords; i++) {
  405. Group = (PktVersion==3)? pGroupRecord->Group : pHdr->Group;
  406. if ( !IS_MCAST_ADDR(Group) ) {
  407. Trace4(RECEIVE,
  408. "received IGMP Leave packet with illegal Group(%d.%d.%d.%d) field: "
  409. "IfIndex(%0x) SrcAddr(%d.%d.%d.%d) DstnMcastAddr(%d.%d.%d.%d)",
  410. PRINT_IPADDR(Group), IfIndex, PRINT_IPADDR(InputSrcAddr),
  411. PRINT_IPADDR(DstnMcastAddr)
  412. );
  413. }
  414. if (LOCAL_MCAST_GROUP(Group)) {
  415. if (PktVersion==3){
  416. pGroupRecord = (PGROUP_RECORD)
  417. &(pGroupRecord->Sources[pGroupRecord->NumSources]);
  418. continue;
  419. }
  420. else
  421. break;
  422. }
  423. //kslksl
  424. if (PktVersion==3 && pGroupRecord->NumSources==0 &&
  425. pGroupRecord->RecordType==IS_IN)
  426. {
  427. pGroupRecord = (PGROUP_RECORD)
  428. &(pGroupRecord->Sources[pGroupRecord->NumSources]);
  429. continue;
  430. }
  431. //
  432. // Lock the group table
  433. //
  434. ACQUIRE_GROUP_LOCK(Group, "_ProcessReport");
  435. //
  436. // find the group entry and create one if not found
  437. // also increment GroupMembership count if req
  438. //
  439. bCreateGroup = TRUE;
  440. pge = GetGroupFromGroupTable(Group, &bCreateGroup, llCurTime);
  441. if (pge==NULL) {
  442. RELEASE_GROUP_LOCK(Group, "_ProcessReport");
  443. return ERROR_CAN_NOT_COMPLETE;
  444. }
  445. //
  446. // find the GI entry and if not found create one.
  447. // the version in GI entry is same as that of interface
  448. //
  449. bCreateGI = TRUE;
  450. pgie = GetGIFromGIList(pge, pite, InputSrcAddr, NOT_STATIC_GROUP,
  451. &bCreateGI, llCurTime);
  452. if (pgie==NULL) {
  453. RELEASE_GROUP_LOCK(Group, "_ProcessReport");
  454. return ERROR_CAN_NOT_COMPLETE;
  455. }
  456. GIVersion = pgie->Version;
  457. // acquire timer lock
  458. ACQUIRE_TIMER_LOCK("_ProcessReport");
  459. //
  460. // update the ver-1, membership, and lastMemTimer.
  461. // Note: the GI entry might be a new one or old one
  462. //
  463. //
  464. // shift to version 1 level processing
  465. //
  466. if (PktVersion==1) {
  467. if (GIVersion!=1) {
  468. pgie->Version = 1;
  469. if (GIVersion==3) {
  470. if (pgie->FilterType!=EXCLUSION) {
  471. // add (*,g) to MGM
  472. MGM_ADD_GROUP_MEMBERSHIP_ENTRY(pite, NHAddr, 0, 0, Group,
  473. 0xffffffff, MGM_JOIN_STATE_FLAG);
  474. }
  475. GIDeleteAllV3Sources(pgie, TRUE);
  476. }
  477. // gi version from 2,3-> 1
  478. GIVersion = 1;
  479. }
  480. //
  481. // received v1 report when IF not v1. update v1host timer.
  482. //
  483. if (!IS_IF_VER1(pite)) {
  484. #if DEBUG_TIMER_TIMERID
  485. SET_TIMER_ID(&pgie->LastVer1ReportTimer,510, pite->IfIndex,
  486. Group, 0);
  487. #endif
  488. if (IS_TIMER_ACTIVE(pgie->LastVer1ReportTimer)) {
  489. UpdateLocalTimer(&pgie->LastVer1ReportTimer,
  490. pConfig->GroupMembershipTimeout, DBG_N);
  491. }
  492. else {
  493. InsertTimer(&pgie->LastVer1ReportTimer,
  494. pConfig->GroupMembershipTimeout, TRUE, DBG_N);
  495. }
  496. // set the V1HostPresentTimeLeft value for stats
  497. pgie->Info.V1HostPresentTimeLeft = llCurTime
  498. + CONFIG_TO_SYSTEM_TIME(pConfig->GroupMembershipTimeout);
  499. }
  500. // update group timer for all versions
  501. bUpdateGroupTimer = TRUE;
  502. }
  503. //
  504. // shift to version 2 level processing
  505. //
  506. else if (PktVersion==2) {
  507. if (GIVersion==3) {
  508. pgie->Version = 2;
  509. if (pgie->FilterType!=EXCLUSION) {
  510. // add (*,g) to MGM
  511. MGM_ADD_GROUP_MEMBERSHIP_ENTRY(
  512. pite, NHAddr, 0, 0, Group, 0xffffffff,
  513. MGM_JOIN_STATE_FLAG);
  514. }
  515. GIDeleteAllV3Sources(pgie, TRUE);
  516. // gi version from 3->2
  517. GIVersion = 2;
  518. }
  519. //
  520. // received v2 report when in in v3 mode. update v2host timer.
  521. if (IS_IF_VER3(pite)) {
  522. #if DEBUG_TIMER_TIMERID
  523. SET_TIMER_ID(&pgie->LastVer2ReportTimer,550, pite->IfIndex,
  524. Group, 0);
  525. #endif
  526. if (IS_TIMER_ACTIVE(pgie->LastVer2ReportTimer)) {
  527. UpdateLocalTimer(&pgie->LastVer2ReportTimer,
  528. pConfig->GroupMembershipTimeout, DBG_N);
  529. }
  530. else {
  531. InsertTimer(&pgie->LastVer2ReportTimer,
  532. pConfig->GroupMembershipTimeout, TRUE, DBG_N);
  533. }
  534. // set the V2HostPresentTimeLeft value for stats
  535. pgie->Info.V2HostPresentTimeLeft = llCurTime
  536. + CONFIG_TO_SYSTEM_TIME(pConfig->GroupMembershipTimeout);
  537. }
  538. // update group timer for all versions
  539. bUpdateGroupTimer = TRUE;
  540. }
  541. else if (PktVersion==3) {
  542. if (GIVersion!=3) {
  543. // update timer only if it is not a v3 block message
  544. if (bCreateGI || pGroupRecord->RecordType!=BLOCK)
  545. bUpdateGroupTimer = TRUE;
  546. }
  547. else {
  548. ProcessV3Report(pgie, pGroupRecord, &bUpdateGroupTimer);
  549. }
  550. }
  551. // NOTE: if giversion==3, then pgie may be invalid below here
  552. //
  553. // report received. so remove the lastMemTimer if pgie is not v3.
  554. //
  555. if (GIVersion!=3 && pgie->LastMemQueryCount>0) {
  556. if (pgie->LastMemQueryTimer.Status&TIMER_STATUS_ACTIVE)
  557. RemoveTimer(&pgie->LastMemQueryTimer, DBG_Y);
  558. pgie->LastMemQueryCount = 0;
  559. }
  560. if (bUpdateGroupTimer) {
  561. //
  562. // update membership timer
  563. //
  564. #if DEBUG_TIMER_TIMERID
  565. (&pgie->GroupMembershipTimer)->Id = 320;
  566. (&pgie->GroupMembershipTimer)->IfIndex = 320;
  567. SET_TIMER_ID(&pgie->GroupMembershipTimer,320, pite->IfIndex,
  568. Group, 0);
  569. #endif
  570. if (IS_TIMER_ACTIVE(pgie->GroupMembershipTimer)) {
  571. UpdateLocalTimer(&pgie->GroupMembershipTimer,
  572. pite->Config.GroupMembershipTimeout, DBG_N);
  573. }
  574. else {
  575. InsertTimer(&pgie->GroupMembershipTimer,
  576. pite->Config.GroupMembershipTimeout, TRUE, DBG_N);
  577. }
  578. // update GroupExpiryTime
  579. {
  580. LONGLONG tempTime;
  581. tempTime = llCurTime
  582. + CONFIG_TO_SYSTEM_TIME(pite->Config.GroupMembershipTimeout);
  583. pgie->Info.GroupExpiryTime = tempTime;
  584. }
  585. }
  586. if (pgie->Version==3 && pgie->FilterType==INCLUSION && pgie->NumSources==0) {
  587. DeleteGIEntry(pgie, TRUE, TRUE);
  588. }
  589. RELEASE_TIMER_LOCK("_ProcessReport");
  590. //
  591. //update the last reporter field
  592. //
  593. if (GIVersion!=3)
  594. InterlockedExchange(&pgie->Info.LastReporter, InputSrcAddr);
  595. //
  596. // Release the group table lock
  597. //
  598. RELEASE_GROUP_LOCK(Group, "_ProcessReport");
  599. if (PktVersion==3) {
  600. pGroupRecord = (PGROUP_RECORD)
  601. &(pGroupRecord->Sources[pGroupRecord->NumSources]);
  602. }
  603. else
  604. break;
  605. }//for all group records
  606. Trace0(LEAVE1, "Leaving _ProcessReport()");
  607. return NO_ERROR;
  608. }
  609. //------------------------------------------------------------------------------
  610. DWORD
  611. ProcessV3Report(
  612. PGI_ENTRY pgie,
  613. PGROUP_RECORD pGroupRecord,
  614. BOOL *bUpdateGroupTimer
  615. )
  616. {
  617. BOOL bCreate;
  618. PGI_SOURCE_ENTRY pSourceEntry;
  619. DWORD i,j;
  620. IPADDR Source;
  621. PLIST_ENTRY ple, pHead;
  622. Trace0(ENTER1, "Entering _Processv3Report()");
  623. *bUpdateGroupTimer = FALSE;
  624. //deldel
  625. //DebugPrintSourcesList(pgie);
  626. //DebugPrintSourcesList1(pgie);
  627. //DebugPrintIfGroups(pgie->pIfTableEntry,0);
  628. //kslksl
  629. if (pGroupRecord->NumSources==0 && pGroupRecord->RecordType==IS_IN)
  630. return NO_ERROR;
  631. switch(pGroupRecord->RecordType) {
  632. case IS_IN:
  633. {
  634. //(11)---------------------------
  635. // INCLUSION(A), IS_IN(b): A=A+b,(B)=gmi
  636. if (pgie->FilterType==INCLUSION) {
  637. //
  638. // include all sources in groupRecord and update timers for them
  639. //
  640. for (i=0; i<pGroupRecord->NumSources; i++) {//sources in pkt
  641. //kslksl
  642. if (pGroupRecord->Sources[i]==0||pGroupRecord->Sources[i]==0xffffffff)
  643. continue;
  644. Source = pGroupRecord->Sources[i];
  645. bCreate = TRUE;
  646. pSourceEntry = GetSourceEntry(pgie, Source, INCLUSION,
  647. &bCreate, GMI, MGM_YES);
  648. if (pSourceEntry==NULL)
  649. return ERROR_NOT_ENOUGH_MEMORY;
  650. // update source timer if already exists
  651. if (bCreate==FALSE) {
  652. UpdateSourceExpTimer(pSourceEntry,
  653. GMI,
  654. FALSE //remove from lastmem list
  655. );
  656. }
  657. }
  658. }
  659. else {
  660. //(13)--------------------------------(same as 6)
  661. // exclusion Mode(x,y), IS_IN pkt(a): (x+a,y-a), (a)=gmi
  662. MoveFromExcludeToIncludeList(pgie, pGroupRecord);
  663. }
  664. break;
  665. }//end case _IS_IN
  666. case IS_EX:
  667. {
  668. //(12)----------------------------------------
  669. //INCLUSION Mode(A), IS_EX(B): (A*B,B-A),
  670. //Delete(A-B),GT=GMI,(b-a)=0
  671. if (pgie->FilterType==INCLUSION) {
  672. // change from in->ex
  673. pgie->FilterType = EXCLUSION;
  674. MGM_ADD_GROUP_MEMBERSHIP_ENTRY(pgie->pIfTableEntry,pgie->NHAddr, 0, 0,
  675. pgie->pGroupTableEntry->Group, 0xffffffff, MGM_JOIN_STATE_FLAG);
  676. // delete (A-B)
  677. SourcesSubtraction(pgie, pGroupRecord, INCLUSION);
  678. // create (B-A) in exclusion Mode
  679. for (j=0; j<pGroupRecord->NumSources; j++) {
  680. if (!GetSourceEntry(pgie, pGroupRecord->Sources[j],INCLUSION,
  681. NULL,0,0))
  682. {
  683. BOOL bCreate=TRUE;
  684. // IF already pruned from mfe. keep it that way
  685. GetSourceEntry(pgie, pGroupRecord->Sources[j], EXCLUSION,
  686. &bCreate,0, MGM_YES);
  687. }
  688. }
  689. // update group timer
  690. *bUpdateGroupTimer = TRUE;
  691. }
  692. //(14)--------------------------------------
  693. // EXCLUSION Mode(x,y), IS_EX(a); D(x-a),D(y-a),GT=gmi
  694. else {
  695. //(X-A), (y-a)
  696. SourcesSubtraction(pgie, pGroupRecord, INCLUSION);
  697. SourcesSubtraction(pgie, pGroupRecord, EXCLUSION);
  698. // if a not in y, then insert in x(IN) (a-x-y)=GMI
  699. for (j=0; j<pGroupRecord->NumSources; j++) {
  700. //kslksl
  701. if (pGroupRecord->Sources[j]==0||pGroupRecord->Sources[j]==0xffffffff)
  702. continue;
  703. pSourceEntry = GetSourceEntry(pgie, pGroupRecord->Sources[j], EXCLUSION,
  704. NULL,0,0);
  705. if (!pSourceEntry) {
  706. bCreate = TRUE;
  707. pSourceEntry = GetSourceEntry(pgie, pGroupRecord->Sources[j],
  708. INCLUSION, &bCreate, GMI, MGM_YES);
  709. }
  710. }
  711. // update group timer
  712. *bUpdateGroupTimer = TRUE;
  713. }//end4
  714. break;
  715. }//case IS_EX
  716. case ALLOW :
  717. {
  718. //(1)----------------------------------------
  719. // INCLUSION Mode(a), ALLOW pkt(b): (a+b), (b)=gmi
  720. if (pgie->FilterType==INCLUSION) {
  721. InclusionSourcesUnion(pgie, pGroupRecord);
  722. }
  723. //(6)----------------------------------------
  724. // EXCLUSION Mode(x,y), ALLOW pkt(a): (same as 13: (x+a, y-a)
  725. else {
  726. MoveFromExcludeToIncludeList(pgie, pGroupRecord);
  727. }
  728. break;
  729. }//case ALLOW
  730. case BLOCK :
  731. {
  732. //(2)----------------------------------------
  733. // INCLUSION Mode(x), BLOCK pkt(a): Send Q(G,A*B)
  734. if (pgie->FilterType==INCLUSION) {
  735. BuildAndSendSourcesQuery(pgie, pGroupRecord, INTERSECTION);
  736. }
  737. //(7)----------------------------------------
  738. // EXCLUSION Mode(x,y), BLOCK pkt(a): (x+(a-y),y),Send Q(a-y)
  739. else {
  740. BuildAndSendSourcesQuery(pgie, pGroupRecord, EXCLUSION);
  741. }
  742. break;
  743. }//case BLOCK
  744. case TO_EX :
  745. {
  746. //(4)----------------------------------------
  747. // INCLUSION Mode(x), TO_EX pkt(a)
  748. // move to EX mode: EX(A*b,b-a),Send Q(G,A*B)
  749. if (pgie->FilterType==INCLUSION) {
  750. pgie->FilterType = EXCLUSION;
  751. // exclusion mode: add (*,g) to MGM
  752. MGM_ADD_GROUP_MEMBERSHIP_ENTRY(pgie->pIfTableEntry,pgie->NHAddr, 0, 0,
  753. pgie->pGroupTableEntry->Group, 0xffffffff, MGM_JOIN_STATE_FLAG);
  754. // delete (a-b) from IN list
  755. SourcesSubtraction(pgie, pGroupRecord, INCLUSION);
  756. //
  757. // add (b-a) to EX list. IF not added to mfe. so no mgm.
  758. //
  759. for (j=0; j<pGroupRecord->NumSources; j++) {
  760. //kslksl
  761. if (pGroupRecord->Sources[j]==0||pGroupRecord->Sources[j]==0xffffffff)
  762. continue;
  763. pSourceEntry = GetSourceEntry(pgie, pGroupRecord->Sources[j],
  764. INCLUSION, NULL, 0, 0);
  765. if (!pSourceEntry) {
  766. bCreate = TRUE;
  767. GetSourceEntry(pgie, pGroupRecord->Sources[j],
  768. EXCLUSION, &bCreate, 0, MGM_NO);
  769. }
  770. }
  771. // send Q for sources left in IN list
  772. BuildAndSendSourcesQuery(pgie, pGroupRecord, INCLUSION);
  773. // update group timer
  774. *bUpdateGroupTimer = TRUE;
  775. }
  776. //(9)----------------------------------------
  777. // EXCLUSION Mode(x,y), TO_EX pkt(a): (
  778. else {
  779. // delete (x-a) from IN list
  780. SourcesSubtraction(pgie, pGroupRecord, INCLUSION);
  781. // delete (y-a) from EX list
  782. SourcesSubtraction(pgie, pGroupRecord, EXCLUSION);
  783. // add x+(a-y) and send Q(a-y)
  784. BuildAndSendSourcesQuery(pgie, pGroupRecord, EXCLUSION);
  785. // update group timer
  786. *bUpdateGroupTimer = TRUE;
  787. }
  788. break;
  789. }//case TO_EX
  790. case TO_IN :
  791. {
  792. //(5)----------------------------------------
  793. // INCLUSION Mode(a), TO_IN(b): IN(a+b),Send Q(G,A*B)
  794. if (pgie->FilterType==INCLUSION) {
  795. // for all a not in b, send sources query
  796. BuildAndSendSourcesQuery(pgie, pGroupRecord, RULE5);
  797. // inc a+b
  798. InclusionSourcesUnion(pgie, pGroupRecord);
  799. }
  800. //(10)----------------------------------------
  801. // EXCLUSION Mode(x,y), TO_IN pkt(a): (
  802. else {
  803. PIGMP_IF_CONFIG pConfig = &pgie->pIfTableEntry->Config;
  804. // for all x not in a, send sources query
  805. BuildAndSendSourcesQuery(pgie, pGroupRecord, RULE5);
  806. // x+a. a=gmi. if in ex list move it to in list
  807. InclusionSourcesUnion(pgie, pGroupRecord);
  808. // set group query count
  809. pgie->LastMemQueryCount = pConfig->LastMemQueryCount;
  810. ACQUIRE_TIMER_LOCK("_ProcessV3Report");
  811. // set group query timer
  812. #if DEBUG_TIMER_TIMERID
  813. SET_TIMER_ID(&pgie->LastMemQueryTimer, 410,
  814. pgie->pIfTableEntry->IfIndex, pgie->pGroupTableEntry->Group, 0);
  815. #endif
  816. InsertTimer(&pgie->LastMemQueryTimer,
  817. pConfig->LastMemQueryInterval/pConfig->LastMemQueryCount, TRUE,
  818. DBG_N);
  819. // update group expiry timer to LMQI
  820. UpdateLocalTimer(&pgie->GroupMembershipTimer,
  821. pConfig->LastMemQueryInterval, DBG_Y);
  822. RELEASE_TIMER_LOCK("_ProcessV3Report");
  823. // send group query
  824. SendV3GroupQuery(pgie);
  825. }
  826. break;
  827. }//case TO_IN
  828. }//end switch
  829. #if PRINT_SOURCES_LIST
  830. DebugPrintSourcesList(pgie);
  831. #endif
  832. //DebugPrintIfGroups(pgie->pIfTableEntry,0);//deldel
  833. Trace0(LEAVE1, "Leaving _ProcessV3Report()");
  834. return NO_ERROR;
  835. }
  836. VOID
  837. DebugPrintSourcesList(
  838. PGI_ENTRY pgie
  839. )
  840. {
  841. PLIST_ENTRY pHead, ple;
  842. PGI_SOURCE_ENTRY pSourceEntry;
  843. LONGLONG llCurTime = GetCurrentIgmpTime();
  844. DWORD Count=0;
  845. Trace2(SOURCES,
  846. "\nPrinting SourcesList for Group: %d.%d.%d.%d Mode:%s",
  847. PRINT_IPADDR(pgie->pGroupTableEntry->Group),
  848. pgie->FilterType==INCLUSION ? "inc" : "exc"
  849. );
  850. {
  851. DWORD Tmp;
  852. Trace1(SOURCES,
  853. "Num sources in query list:%d", pgie->V3SourcesQueryCount);
  854. pHead = &pgie->V3SourcesQueryList;
  855. Tmp = ListLength(&pgie->V3SourcesQueryList);
  856. pHead = &pgie->V3SourcesQueryList;
  857. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink){
  858. pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY, V3SourcesQueryList);
  859. Trace1(SOURCES, "%d.%d.%d.%d source in query list",
  860. PRINT_IPADDR(pSourceEntry->IpAddr));
  861. }
  862. }
  863. pHead = &pgie->V3ExclusionList;
  864. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  865. pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY,LinkSources);
  866. Trace5(SOURCES, "Src: %d.%d.%d.%d %s %d|%d SrcQueryLeft:%d",
  867. PRINT_IPADDR(pSourceEntry->IpAddr),
  868. pSourceEntry->bInclusionList? "INC":"EXC",
  869. (DWORD)(llCurTime - pSourceEntry->SourceInListTime)/1000,
  870. (IS_TIMER_ACTIVE(pSourceEntry->SourceExpTimer)
  871. ?QueryRemainingTime(&pSourceEntry->SourceExpTimer, llCurTime)/1000 :
  872. 0),
  873. pSourceEntry->V3SourcesQueryLeft
  874. );
  875. }
  876. pHead = &pgie->V3InclusionListSorted;
  877. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  878. pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY,LinkSourcesInclListSorted);
  879. Trace5(SOURCES, "Src: %d.%d.%d.%d %s %d|%d SrcQueryLeft:%d",
  880. PRINT_IPADDR(pSourceEntry->IpAddr),
  881. pSourceEntry->bInclusionList? "INC":"EXC",
  882. IS_TIMER_ACTIVE(pSourceEntry->SourceExpTimer)
  883. ?QueryRemainingTime(&pSourceEntry->SourceExpTimer, llCurTime)/1000 : 0,
  884. (DWORD)(llCurTime - pSourceEntry->SourceInListTime)/1000,
  885. pSourceEntry->V3SourcesQueryLeft
  886. );
  887. }
  888. Trace0(SOURCES, "\n");
  889. }
  890. VOID
  891. DebugPrintSourcesList1(
  892. PGI_ENTRY pgie
  893. )
  894. {
  895. PLIST_ENTRY pHead, ple;
  896. PGI_SOURCE_ENTRY pSourceEntry;
  897. LONGLONG llCurTime = GetCurrentIgmpTime();
  898. DWORD Count=0;
  899. {
  900. DWORD Tmp;
  901. Trace1(SOURCES,
  902. "Num sources in query list:%d", pgie->V3SourcesQueryCount);
  903. pHead = &pgie->V3SourcesQueryList;
  904. Tmp = ListLength(&pgie->V3SourcesQueryList);
  905. pHead = &pgie->V3SourcesQueryList;
  906. if (Tmp!=pgie->V3SourcesQueryCount) {
  907. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink){
  908. pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY, V3SourcesQueryList);
  909. Trace1(SOURCES, "%d.%d.%d.%d source in query list",
  910. PRINT_IPADDR(pSourceEntry->IpAddr));
  911. }
  912. DbgBreakPoint();
  913. }
  914. }
  915. Trace2(SOURCES,
  916. "\nPrinting SourcesList for Group: %d.%d.%d.%d Mode:%s",
  917. PRINT_IPADDR(pgie->pGroupTableEntry->Group),
  918. pgie->FilterType==INCLUSION ? "inc" : "exc"
  919. );
  920. pHead = &pgie->V3ExclusionList;
  921. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  922. pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY,LinkSources);
  923. if (pSourceEntry->IpAddr <0x01010101 || pSourceEntry->IpAddr>0x3F010101) {
  924. Trace5(SOURCES, "Src: %d.%d.%d.%d %s %d|%d SrcQueryLeft:%d",
  925. PRINT_IPADDR(pSourceEntry->IpAddr),
  926. pSourceEntry->bInclusionList? "INC":"EXC",
  927. (DWORD)(llCurTime - pSourceEntry->SourceInListTime)/1000,
  928. (IS_TIMER_ACTIVE(pSourceEntry->SourceExpTimer)
  929. ?QueryRemainingTime(&pSourceEntry->SourceExpTimer, llCurTime)/1000 :
  930. 0),
  931. pSourceEntry->V3SourcesQueryLeft
  932. );
  933. DbgBreakPoint();
  934. }
  935. }
  936. if (ListLength(&pgie->V3InclusionListSorted)!=ListLength(&pgie->V3InclusionList[0])
  937. ||(ListLength(&pgie->V3InclusionListSorted)!=pgie->NumSources))
  938. {
  939. Trace0(SOURCES, "Sorted");
  940. pHead = &pgie->V3InclusionListSorted;
  941. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  942. pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY,LinkSourcesInclListSorted);
  943. Trace5(SOURCES, "Src: %d.%d.%d.%d %s %d|%d SrcQueryLeft:%d",
  944. PRINT_IPADDR(pSourceEntry->IpAddr),
  945. pSourceEntry->bInclusionList? "INC":"EXC",
  946. IS_TIMER_ACTIVE(pSourceEntry->SourceExpTimer)
  947. ?QueryRemainingTime(&pSourceEntry->SourceExpTimer, llCurTime)/1000 : 0,
  948. (DWORD)(llCurTime - pSourceEntry->SourceInListTime)/1000,
  949. pSourceEntry->V3SourcesQueryLeft
  950. );
  951. }
  952. Trace0(SOURCES, "NotSorted");
  953. pHead = &pgie->V3InclusionList[0];
  954. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  955. pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY,LinkSources);
  956. Trace5(SOURCES, "Src: %d.%d.%d.%d %s %d|%d SrcQueryLeft:%d",
  957. PRINT_IPADDR(pSourceEntry->IpAddr),
  958. pSourceEntry->bInclusionList? "INC":"EXC",
  959. IS_TIMER_ACTIVE(pSourceEntry->SourceExpTimer)
  960. ?QueryRemainingTime(&pSourceEntry->SourceExpTimer, llCurTime)/1000 : 0,
  961. (DWORD)(llCurTime - pSourceEntry->SourceInListTime)/1000,
  962. pSourceEntry->V3SourcesQueryLeft
  963. );
  964. }
  965. DbgBreakPoint();
  966. }
  967. Trace0(SOURCES, "\n");
  968. }
  969. //------------------------------------------------------------------------------
  970. // _SendV3GroupQuery
  971. //------------------------------------------------------------------------------
  972. VOID
  973. SendV3GroupQuery(
  974. PGI_ENTRY pgie
  975. )
  976. {
  977. PLIST_ENTRY pHead, ple;
  978. PGI_SOURCE_ENTRY pSourceEntry;
  979. if (pgie->LastMemQueryCount==0 || pgie->Version!=3)
  980. return;
  981. Trace0(ENTER1, "Entering _SendV3GroupQuery()");
  982. // send group query
  983. SEND_GROUP_QUERY_V3(pgie->pIfTableEntry, pgie, pgie->pGroupTableEntry->Group);
  984. // set group query count
  985. if (--pgie->LastMemQueryCount) {
  986. ACQUIRE_TIMER_LOCK("_SendV3GroupQuery");
  987. // set group query timer
  988. #if DEBUG_TIMER_TIMERID
  989. SET_TIMER_ID(&pgie->LastMemQueryTimer, 410,
  990. pgie->pIfTableEntry->IfIndex, pgie->pGroupTableEntry->Group, 0);
  991. #endif
  992. InsertTimer(&pgie->LastMemQueryTimer,
  993. pgie->pIfTableEntry->Config.LastMemQueryInterval
  994. /pgie->pIfTableEntry->Config.LastMemQueryCount,
  995. TRUE, DBG_Y);
  996. RELEASE_TIMER_LOCK("_SendV3GroupQuery");
  997. }
  998. // reduce pending source queries for those with S bit set
  999. pHead = &pgie->V3SourcesQueryList;
  1000. for (ple=pHead->Flink; ple!=pHead; ) {
  1001. pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY, V3SourcesQueryList);
  1002. ple = ple->Flink;
  1003. if (QueryRemainingTime(&pSourceEntry->SourceExpTimer, 0)
  1004. >pgie->pIfTableEntry->Config.LastMemQueryInterval)
  1005. {
  1006. if (--pSourceEntry->V3SourcesQueryLeft == 0) {
  1007. RemoveEntryList(&pSourceEntry->V3SourcesQueryList);
  1008. pSourceEntry->bInV3SourcesQueryList = FALSE;
  1009. pSourceEntry->V3SourcesQueryLeft--;
  1010. }
  1011. }
  1012. }
  1013. Trace0(LEAVE1, "Leaving _SendV3GroupQuery()");
  1014. return;
  1015. }
  1016. VOID
  1017. ChangeSourceFilterMode(
  1018. PGI_ENTRY pgie,
  1019. PGI_SOURCE_ENTRY pSourceEntry
  1020. )
  1021. {
  1022. DWORD Mode = (pSourceEntry->bInclusionList) ? INCLUSION : EXCLUSION;
  1023. Trace0(ENTER1, "Entering _ChangeSourceFilterMode()");
  1024. //deldel
  1025. //DebugPrintSourcesList(pgie);
  1026. //DebugPrintSourcesList1(pgie);
  1027. if (Mode==EXCLUSION) {
  1028. // remove from exclusion list
  1029. RemoveEntryList(&pSourceEntry->LinkSources);
  1030. pSourceEntry->bInclusionList = TRUE;
  1031. // insert in both inclusion lists
  1032. INSERT_IN_SORTED_LIST(
  1033. &pgie->V3InclusionList[pSourceEntry->IpAddr%SOURCES_BUCKET_SZ],
  1034. pSourceEntry, IpAddr, GI_SOURCE_ENTRY, LinkSources
  1035. );
  1036. INSERT_IN_SORTED_LIST(
  1037. &pgie->V3InclusionListSorted,
  1038. pSourceEntry, IpAddr, GI_SOURCE_ENTRY, LinkSourcesInclListSorted
  1039. );
  1040. pgie->NumSources ++;
  1041. // add to mgm. this will also remove any -ve state.
  1042. MGM_ADD_GROUP_MEMBERSHIP_ENTRY(pgie->pIfTableEntry,
  1043. pgie->NHAddr, pSourceEntry->IpAddr, 0xffffffff,
  1044. pgie->pGroupTableEntry->Group, 0xffffffff,
  1045. MGM_JOIN_STATE_FLAG);
  1046. }
  1047. // remove source from inclusion state
  1048. else {
  1049. RemoveEntryList(&pSourceEntry->LinkSources);
  1050. RemoveEntryList(&pSourceEntry->LinkSourcesInclListSorted);
  1051. pSourceEntry->bInclusionList = FALSE;
  1052. if (pSourceEntry->bInV3SourcesQueryList) {
  1053. RemoveEntryList(&pSourceEntry->V3SourcesQueryList);
  1054. pSourceEntry->bInV3SourcesQueryList = FALSE;
  1055. pgie->V3SourcesQueryCount--;
  1056. pSourceEntry->V3SourcesQueryLeft = 0;
  1057. }
  1058. pgie->NumSources--;
  1059. INSERT_IN_SORTED_LIST(
  1060. &pgie->V3ExclusionList,
  1061. pSourceEntry, IpAddr, GI_SOURCE_ENTRY, LinkSources
  1062. );
  1063. ACQUIRE_TIMER_LOCK("_ChangeSourceFilterMode");
  1064. // remove sourceexptimer
  1065. if (IS_TIMER_ACTIVE(pSourceEntry->SourceExpTimer))
  1066. RemoveTimer(&pSourceEntry->SourceExpTimer, DBG_N);
  1067. RELEASE_TIMER_LOCK("_ChangeSourceFilterMode");
  1068. // removing from inclusion list. so delete join state
  1069. MGM_DELETE_GROUP_MEMBERSHIP_ENTRY(pgie->pIfTableEntry,
  1070. pgie->NHAddr, pSourceEntry->IpAddr, 0xffffffff,
  1071. pgie->pGroupTableEntry->Group, 0xffffffff,
  1072. MGM_JOIN_STATE_FLAG);
  1073. // dont have to delete any +ve mfe as the mgm call would have done that
  1074. }
  1075. //deldel
  1076. //DebugPrintSourcesList(pgie);
  1077. //DebugPrintSourcesList1(pgie);
  1078. Trace0(LEAVE1, "Leaving _ChangeSourceFilterMode()");
  1079. return;
  1080. }
  1081. //------------------------------------------------------------------------------
  1082. VOID
  1083. DeleteSourceEntry(
  1084. PGI_SOURCE_ENTRY pSourceEntry,
  1085. BOOL bMgm
  1086. )
  1087. {
  1088. Trace0(ENTER1, "Entering _DeleteSourceEntry()");
  1089. RemoveEntryList(&pSourceEntry->LinkSources);
  1090. RemoveEntryList(&pSourceEntry->LinkSourcesInclListSorted);
  1091. if (pSourceEntry->bInV3SourcesQueryList) {
  1092. RemoveEntryList(&pSourceEntry->V3SourcesQueryList);
  1093. pSourceEntry->pGIEntry->V3SourcesQueryCount--;
  1094. }
  1095. ACQUIRE_TIMER_LOCK("_DeleteSourceEntry");
  1096. if (IS_TIMER_ACTIVE(pSourceEntry->SourceExpTimer))
  1097. RemoveTimer(&pSourceEntry->SourceExpTimer, DBG_Y);
  1098. RELEASE_TIMER_LOCK("_DeleteSourceEntry");
  1099. //inclusion list
  1100. if (pSourceEntry->bInclusionList) {
  1101. pSourceEntry->pGIEntry->NumSources --;
  1102. if (bMgm) {
  1103. MGM_DELETE_GROUP_MEMBERSHIP_ENTRY(
  1104. pSourceEntry->pGIEntry->pIfTableEntry,
  1105. pSourceEntry->pGIEntry->NHAddr,
  1106. pSourceEntry->IpAddr, 0xffffffff,
  1107. pSourceEntry->pGIEntry->pGroupTableEntry->Group, 0xffffffff,
  1108. MGM_JOIN_STATE_FLAG);
  1109. }
  1110. }
  1111. // exclusion list
  1112. else {
  1113. // join IF in MFE
  1114. if (bMgm) {
  1115. MGM_ADD_GROUP_MEMBERSHIP_ENTRY(
  1116. pSourceEntry->pGIEntry->pIfTableEntry,
  1117. pSourceEntry->pGIEntry->NHAddr,
  1118. pSourceEntry->IpAddr, 0xffffffff,
  1119. pSourceEntry->pGIEntry->pGroupTableEntry->Group, 0xffffffff,
  1120. MGM_FORWARD_STATE_FLAG);
  1121. }
  1122. }
  1123. IGMP_FREE(pSourceEntry);
  1124. Trace0(LEAVE1, "Leaving _DeleteSourceEntry()");
  1125. }
  1126. //------------------------------------------------------------------------------
  1127. PGI_SOURCE_ENTRY
  1128. GetSourceEntry(
  1129. PGI_ENTRY pgie,
  1130. IPADDR Source,
  1131. DWORD Mode,
  1132. BOOL *bCreate,
  1133. DWORD Gmi,
  1134. BOOL bMgm
  1135. )
  1136. {
  1137. PLIST_ENTRY ple, pHead;
  1138. PGI_SOURCE_ENTRY pSourceEntry;
  1139. DWORD Error = NO_ERROR;
  1140. PIGMP_TIMER_ENTRY SourceExpTimer;
  1141. Trace0(ENTER1, "Entering _GetSourceEntry()");
  1142. //deldel
  1143. //DebugPrintSourcesList(pgie);
  1144. //DebugPrintSourcesList1(pgie);
  1145. pHead = (Mode==INCLUSION) ?
  1146. &pgie->V3InclusionList[Source%SOURCES_BUCKET_SZ]
  1147. : &pgie->V3ExclusionList;
  1148. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  1149. pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY, LinkSources);
  1150. if (pSourceEntry->IpAddr > Source)
  1151. break;
  1152. if (pSourceEntry->IpAddr==Source) {
  1153. if (bCreate) *bCreate = FALSE;
  1154. return pSourceEntry;
  1155. }
  1156. }
  1157. if (!bCreate || *bCreate==FALSE)
  1158. return NULL;
  1159. *bCreate = FALSE;
  1160. //
  1161. // create new entry
  1162. //
  1163. pSourceEntry = (PGI_SOURCE_ENTRY)
  1164. IGMP_ALLOC(sizeof(GI_SOURCE_ENTRY), 0x800200,
  1165. pgie->pIfTableEntry->IfIndex);
  1166. PROCESS_ALLOC_FAILURE2(pSourceEntry,
  1167. "error %d allocating %d bytes for sourceEntry", Error,
  1168. sizeof(GI_SOURCE_ENTRY),
  1169. return NULL;
  1170. );
  1171. InsertTailList(ple, &pSourceEntry->LinkSources);
  1172. InitializeListHead(&pSourceEntry->V3SourcesQueryList);
  1173. pSourceEntry->pGIEntry = pgie;
  1174. pSourceEntry->bInclusionList = Mode==INCLUSION;
  1175. pSourceEntry->IpAddr = Source;
  1176. pSourceEntry->V3SourcesQueryLeft = 0;
  1177. pSourceEntry->bInV3SourcesQueryList = FALSE;
  1178. pSourceEntry->SourceInListTime = GetCurrentIgmpTime();
  1179. pSourceEntry->bStaticSource = (Gmi==STATIC);
  1180. // initialize SourceExpTimer
  1181. SourceExpTimer = &pSourceEntry->SourceExpTimer;
  1182. SourceExpTimer->Function = T_SourceExpTimer;
  1183. SourceExpTimer->Context = &SourceExpTimer->Context;
  1184. SourceExpTimer->Timeout = (Gmi==GMI)
  1185. ? pgie->pIfTableEntry->Config.GroupMembershipTimeout
  1186. : pgie->pIfTableEntry->Config.LastMemQueryInterval;
  1187. SourceExpTimer->Status = TIMER_STATUS_CREATED;
  1188. #if DEBUG_TIMER_TIMERID
  1189. SET_TIMER_ID(SourceExpTimer, 610, pgie->pIfTableEntry->IfIndex,
  1190. pgie->pGroupTableEntry->Group, Source);
  1191. #endif;
  1192. if (Mode==INCLUSION) {
  1193. INSERT_IN_SORTED_LIST(
  1194. &pgie->V3InclusionListSorted,
  1195. pSourceEntry, IpAddr, GI_SOURCE_ENTRY, LinkSourcesInclListSorted
  1196. );
  1197. pgie->NumSources++;
  1198. }
  1199. else {
  1200. InitializeListHead(&pSourceEntry->LinkSourcesInclListSorted);
  1201. }
  1202. // insert in inclusion list and set timer. add to mgm
  1203. if (Mode==INCLUSION) {
  1204. // timer set only in inclusion list
  1205. InsertTimer(SourceExpTimer,
  1206. SourceExpTimer->Timeout,
  1207. TRUE, DBG_N
  1208. );
  1209. if (!pSourceEntry->bStaticSource) {
  1210. // insert in sources query list
  1211. if (Gmi==LMI) {
  1212. InsertSourceInQueryList(pSourceEntry);
  1213. }
  1214. }
  1215. if (bMgm) {
  1216. // add (s,g) to MGM
  1217. MGM_ADD_GROUP_MEMBERSHIP_ENTRY(
  1218. pgie->pIfTableEntry, pgie->NHAddr,
  1219. Source, 0xffffffff, pgie->pGroupTableEntry->Group, 0xffffffff,
  1220. MGM_JOIN_STATE_FLAG
  1221. );
  1222. }
  1223. }
  1224. else {
  1225. if (bMgm) {
  1226. // no timer set, but delete any +ve mfe
  1227. MGM_DELETE_GROUP_MEMBERSHIP_ENTRY(
  1228. pgie->pIfTableEntry, pgie->NHAddr,
  1229. Source, 0xffffffff, pgie->pGroupTableEntry->Group, 0xffffffff,
  1230. MGM_FORWARD_STATE_FLAG
  1231. );
  1232. }
  1233. }
  1234. *bCreate = TRUE;
  1235. //deldel
  1236. //DebugPrintSourcesList(pgie);
  1237. //DebugPrintSourcesList1(pgie);
  1238. Trace0(LEAVE1, "Leaving _GetSourceEntry()");
  1239. return pSourceEntry;
  1240. }
  1241. //------------------------------------------------------------------------------
  1242. VOID
  1243. GIDeleteAllV3Sources(
  1244. PGI_ENTRY pgie,
  1245. BOOL bMgm
  1246. )
  1247. {
  1248. PGI_SOURCE_ENTRY pSourceEntry;
  1249. DWORD i;
  1250. PLIST_ENTRY ple, pHead;
  1251. Trace0(ENTER1, "Entering _GIDeleteAllV3Sources()");
  1252. pHead = &pgie->V3InclusionListSorted;
  1253. for (ple=pHead->Flink; ple!=pHead; ) {
  1254. pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY,LinkSourcesInclListSorted);
  1255. ple = ple->Flink;
  1256. DeleteSourceEntry(pSourceEntry, bMgm);
  1257. }
  1258. InitializeListHead(&pgie->V3InclusionListSorted);
  1259. pHead = &pgie->V3ExclusionList;
  1260. for (ple=pHead->Flink; ple!=pHead; ) {
  1261. pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY, LinkSources);
  1262. ple = ple->Flink;
  1263. DeleteSourceEntry(pSourceEntry, bMgm);
  1264. }
  1265. //
  1266. // dont call delete (*,G) if in exclusion mode as I want to remain in that
  1267. // state
  1268. //
  1269. pgie->NumSources = 0;
  1270. pgie->FilterType = INCLUSION;
  1271. pgie->Info.LastReporter = 0;
  1272. pgie->Info.GroupExpiryTime = ~0;
  1273. //deldel
  1274. //DebugPrintSourcesList(pgie);
  1275. //DebugPrintSourcesList1(pgie);
  1276. Trace0(LEAVE1, "Leaving _GIDeleteAllV3Sources()");
  1277. return;
  1278. }
  1279. //++------------------------------------------------------------------------------
  1280. // todo:remove 3rd field
  1281. DWORD
  1282. UpdateSourceExpTimer(
  1283. PGI_SOURCE_ENTRY pSourceEntry,
  1284. DWORD Gmi,
  1285. BOOL bRemoveLastMem
  1286. )
  1287. {
  1288. Trace0(ENTER1, "Entering _UpdateSourceExpTimer()");
  1289. ACQUIRE_TIMER_LOCK("_UpdateSourceExpTimer");
  1290. #if DEBUG_TIMER_TIMERID
  1291. pSourceEntry->SourceExpTimer.Id = 620;
  1292. pSourceEntry->SourceExpTimer.Id2 = TimerId++;
  1293. #endif
  1294. UpdateLocalTimer(&pSourceEntry->SourceExpTimer,
  1295. Gmi==GMI? GET_IF_CONFIG_FOR_SOURCE(pSourceEntry).GroupMembershipTimeout
  1296. :GET_IF_CONFIG_FOR_SOURCE(pSourceEntry).LastMemQueryInterval,
  1297. DBG_Y
  1298. );
  1299. //remove from expiry list, and exp timer
  1300. if (bRemoveLastMem && pSourceEntry->bInV3SourcesQueryList) {
  1301. pSourceEntry->V3SourcesQueryLeft = 0;
  1302. pSourceEntry->bInV3SourcesQueryList = FALSE;
  1303. RemoveEntryList(&pSourceEntry->V3SourcesQueryList);
  1304. pSourceEntry->pGIEntry->V3SourcesQueryCount--;
  1305. }
  1306. RELEASE_TIMER_LOCK("_UpdateSourceExpTimer");
  1307. Trace0(LEAVE1, "Entering _UpdateSourceExpTimer()");
  1308. return NO_ERROR;
  1309. }
  1310. //------------------------------------------------------------------------------
  1311. DWORD
  1312. ChangeGroupFilterMode(
  1313. PGI_ENTRY pgie,
  1314. DWORD Mode
  1315. )
  1316. {
  1317. Trace0(ENTER1, "Entering _ChangeGroupFilterMode()");
  1318. // shift from exclusion to inclusion mode
  1319. if (Mode==INCLUSION) {
  1320. if (pgie->NumSources == 0) {
  1321. DeleteGIEntry(pgie, TRUE, TRUE);
  1322. }
  1323. else {
  1324. PLIST_ENTRY pHead, ple;
  1325. pgie->FilterType = INCLUSION;
  1326. //
  1327. // remove all sources in exclusion list
  1328. //
  1329. pHead = &pgie->V3ExclusionList;
  1330. for (ple=pHead->Flink; ple!=pHead; ) {
  1331. PGI_SOURCE_ENTRY pSourceEntry;
  1332. pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY,
  1333. LinkSources);
  1334. ple = ple->Flink;
  1335. // dont have to call mgm as it will remain in -ve mfe
  1336. IGMP_FREE(pSourceEntry);
  1337. }
  1338. InitializeListHead(&pgie->V3ExclusionList);
  1339. // remove (*,g) join. the entries in inclusion list are
  1340. // already joined
  1341. MGM_DELETE_GROUP_MEMBERSHIP_ENTRY(pgie->pIfTableEntry, pgie->NHAddr,
  1342. 0, 0, pgie->pGroupTableEntry->Group,
  1343. 0xffffffff, MGM_JOIN_STATE_FLAG);
  1344. }
  1345. }
  1346. Trace0(LEAVE1, "Leaving _ChangeGroupFilterMode()");
  1347. return NO_ERROR;
  1348. }
  1349. //------------------------------------------------------------------------------
  1350. // if inclusion: create source in IN_List if not found in IN_LIST
  1351. // update timer if source already found
  1352. // if source present in exclusion list, move it to inclusion list
  1353. //------------------------------------------------------------------------------
  1354. VOID
  1355. InclusionSourcesUnion(
  1356. PGI_ENTRY pgie,
  1357. PGROUP_RECORD pGroupRecord
  1358. )
  1359. {
  1360. PGI_SOURCE_ENTRY pSourceEntry;
  1361. DWORD j;
  1362. BOOL bCreate;
  1363. Trace0(ENTER1, "Entering _InclusionSourcesUnion()");
  1364. if (pGroupRecord->NumSources==0)
  1365. return;
  1366. //deldel
  1367. //DebugPrintSourcesList(pgie);
  1368. //DebugPrintSourcesList1(pgie);
  1369. for (j=0; j<pGroupRecord->NumSources; j++) {
  1370. //kslksl
  1371. if (pGroupRecord->Sources[j]==0||pGroupRecord->Sources[j]==0xffffffff)
  1372. continue;
  1373. //
  1374. // if in exclusion list, move it to inclusion list and continue
  1375. // if static group, leave it in exclusion list
  1376. //
  1377. pSourceEntry = GetSourceEntry(pgie, pGroupRecord->Sources[j],
  1378. EXCLUSION, NULL, 0, 0);
  1379. if (pSourceEntry!=NULL && !pSourceEntry->bStaticSource) {
  1380. ChangeSourceFilterMode(pgie, pSourceEntry);
  1381. continue;
  1382. }
  1383. //deldel
  1384. //DebugPrintSourcesList(pgie);
  1385. //DebugPrintSourcesList1(pgie);
  1386. bCreate = TRUE;
  1387. pSourceEntry = GetSourceEntry(pgie, pGroupRecord->Sources[j],
  1388. INCLUSION, &bCreate, GMI, MGM_YES);
  1389. if (!pSourceEntry)
  1390. return;
  1391. // if already in IN_LIST, update source exp timer
  1392. if (!bCreate) {
  1393. UpdateSourceExpTimer(pSourceEntry, GMI, FALSE);
  1394. }
  1395. }
  1396. Trace0(LEAVE1, "Leaving _InclusionSourcesUnion()");
  1397. return;
  1398. }
  1399. //------------------------------------------------------------------------------
  1400. // delete sources present in group record
  1401. VOID
  1402. SourcesSubtraction(
  1403. PGI_ENTRY pgie,
  1404. PGROUP_RECORD pGroupRecord,
  1405. BOOL Mode
  1406. )
  1407. {
  1408. PGI_SOURCE_ENTRY pSourceEntry;
  1409. DWORD i,j;
  1410. PLIST_ENTRY pHead, ple;
  1411. BOOL bFound;
  1412. Trace0(ENTER1, "Entering _SourcesSubtraction()");
  1413. // note: num sources in groupRecord can be 0
  1414. // delete sources in inclusion list which are not there in the packet
  1415. //deldel
  1416. //DebugPrintSourcesList(pgie);
  1417. //DebugPrintSourcesList1(pgie);
  1418. if (Mode==INCLUSION) {
  1419. pHead = &pgie->V3InclusionListSorted;
  1420. for (ple=pHead->Flink; ple!=pHead; ) {
  1421. pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY,
  1422. LinkSourcesInclListSorted);
  1423. ple = ple->Flink;
  1424. for (j=0, bFound=FALSE; j<pGroupRecord->NumSources; j++) {
  1425. if (pSourceEntry->IpAddr == pGroupRecord->Sources[j]) {
  1426. bFound = TRUE;
  1427. break;
  1428. }
  1429. }
  1430. if (!bFound)
  1431. DeleteSourceEntry(pSourceEntry, MGM_YES);
  1432. }
  1433. }
  1434. // delete sources in exclusion list which are not there in the packet
  1435. else {
  1436. pHead = &pgie->V3ExclusionList;
  1437. for (ple=pHead->Flink; ple!=pHead; ) {
  1438. pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY, LinkSources);
  1439. ple = ple->Flink;
  1440. for (j=0, bFound=FALSE; j<pGroupRecord->NumSources; j++) {
  1441. if (pSourceEntry->IpAddr == pGroupRecord->Sources[j]) {
  1442. bFound = TRUE;
  1443. break;
  1444. }
  1445. }
  1446. if (!bFound){
  1447. // dont have to process in mgm. IF not in mfe anyway
  1448. DeleteSourceEntry(pSourceEntry, MGM_YES);
  1449. }
  1450. }
  1451. }
  1452. //deldel
  1453. //DebugPrintSourcesList(pgie);
  1454. //DebugPrintSourcesList1(pgie);
  1455. Trace0(LEAVE1, "Leaving _SourcesSubtraction()");
  1456. return;
  1457. }
  1458. //------------------------------------------------------------------------------
  1459. // intersection: rule(2)
  1460. // exclusion: (7)(9)
  1461. // inclusion:(4)
  1462. // rule_5:(5)(10)
  1463. //------------------------------------------------------------------------------
  1464. DWORD
  1465. BuildAndSendSourcesQuery(
  1466. PGI_ENTRY pgie,
  1467. PGROUP_RECORD pGroupRecord,
  1468. DWORD Type
  1469. )
  1470. {
  1471. PGI_SOURCE_ENTRY pSourceEntry;
  1472. DWORD i,j;
  1473. PLIST_ENTRY ple, pHead;
  1474. BOOL bCreate;
  1475. Trace0(ENTER1, "Entering _BuildAndSendSourcesQuery()");
  1476. //deldel
  1477. //DebugPrintSourcesList(pgie);
  1478. //DebugPrintSourcesList1(pgie);
  1479. // intersection of inclusion and group record
  1480. if (Type==INTERSECTION) {
  1481. if (pGroupRecord->NumSources==0)
  1482. return NO_ERROR;
  1483. for (j=0; j<pGroupRecord->NumSources; j++) {
  1484. pSourceEntry = GetSourceEntry(pgie, pGroupRecord->Sources[j],
  1485. INCLUSION, NULL, 0, 0);
  1486. if (pSourceEntry && !pSourceEntry->bStaticSource) {
  1487. InsertSourceInQueryList(pSourceEntry);
  1488. }
  1489. }
  1490. }
  1491. //add a-y to x, and query(a-y)
  1492. else if (Type==EXCLUSION) {
  1493. for (j=0; j<pGroupRecord->NumSources; j++) {
  1494. //kslksl
  1495. if (pGroupRecord->Sources[j]==0||pGroupRecord->Sources[j]==0xffffffff)
  1496. continue;
  1497. // if found in EX list, then do nothing, else add to IN list and
  1498. // send group query
  1499. pSourceEntry = GetSourceEntry(pgie, pGroupRecord->Sources[j],
  1500. EXCLUSION, NULL, 0, 0);
  1501. if (pSourceEntry) {
  1502. continue;
  1503. }
  1504. bCreate = TRUE;
  1505. pSourceEntry = GetSourceEntry(pgie, pGroupRecord->Sources[j],
  1506. INCLUSION, &bCreate, LMI, MGM_YES);
  1507. if (!pSourceEntry)
  1508. return ERROR_NOT_ENOUGH_MEMORY;
  1509. // if created, then already in query list as time==lmi
  1510. if (!bCreate && !pSourceEntry->bStaticSource)
  1511. InsertSourceInQueryList(pSourceEntry);
  1512. }
  1513. }
  1514. // send queries for all sources in inclusion list
  1515. else if (Type==INCLUSION) {
  1516. pHead = &pgie->V3InclusionListSorted;
  1517. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  1518. pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY,
  1519. LinkSourcesInclListSorted);
  1520. InsertSourceInQueryList(pSourceEntry);
  1521. }
  1522. }
  1523. // send for sources in IN list but not in packet
  1524. else if (Type==RULE5) {
  1525. pHead = &pgie->V3InclusionListSorted;
  1526. for (ple=pHead->Flink; ple!=pHead; ) {
  1527. BOOL bFound;
  1528. pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY,
  1529. LinkSourcesInclListSorted);
  1530. ple = ple->Flink;
  1531. for (j=0, bFound=FALSE; j<pGroupRecord->NumSources; j++) {
  1532. if (pSourceEntry->IpAddr == pGroupRecord->Sources[j]) {
  1533. bFound = TRUE;
  1534. break;
  1535. }
  1536. }
  1537. if (!bFound)
  1538. InsertSourceInQueryList(pSourceEntry);
  1539. }
  1540. }
  1541. if (pgie->bV3SourcesQueryNow) {
  1542. SEND_SOURCES_QUERY(pgie);
  1543. }
  1544. //deldel
  1545. //DebugPrintSourcesList(pgie);
  1546. //DebugPrintSourcesList1(pgie);
  1547. Trace0(LEAVE1, "Leaving _BuildAndSendSourcesQuery()");
  1548. return NO_ERROR;
  1549. }
  1550. //------------------------------------------------------------------------------
  1551. VOID
  1552. InsertSourceInQueryList(
  1553. PGI_SOURCE_ENTRY pSourceEntry
  1554. )
  1555. {
  1556. Trace0(ENTER1, "Entering _InsertSourceInQueryList()");
  1557. //already in sources query list. return
  1558. if (pSourceEntry->bInV3SourcesQueryList) {
  1559. if (QueryRemainingTime(&pSourceEntry->SourceExpTimer, 0)
  1560. >GET_IF_CONFIG_FOR_SOURCE(pSourceEntry).LastMemQueryInterval)
  1561. {
  1562. // update exp timer to lmqi
  1563. UpdateSourceExpTimer(pSourceEntry,
  1564. LMI,
  1565. FALSE //dont remove from last mem list
  1566. );
  1567. pSourceEntry->pGIEntry->bV3SourcesQueryNow = TRUE;
  1568. }
  1569. return;
  1570. }
  1571. pSourceEntry->V3SourcesQueryLeft =
  1572. GET_IF_CONFIG_FOR_SOURCE(pSourceEntry).LastMemQueryCount;
  1573. //
  1574. // insert in sources query list
  1575. //
  1576. InsertHeadList(&pSourceEntry->pGIEntry->V3SourcesQueryList,
  1577. &pSourceEntry->V3SourcesQueryList);
  1578. pSourceEntry->bInV3SourcesQueryList = TRUE;
  1579. pSourceEntry->pGIEntry->V3SourcesQueryCount++;
  1580. // update exp timer to lmqi
  1581. UpdateSourceExpTimer(pSourceEntry,
  1582. LMI,
  1583. FALSE //dont remove from last mem list
  1584. );
  1585. pSourceEntry->pGIEntry->bV3SourcesQueryNow = TRUE;
  1586. Trace0(LEAVE1, "Leaving _InsertSourceInQueryList()");
  1587. return;
  1588. }
  1589. //------------------------------------------------------------------------------
  1590. // _MoveFromExcludeToIncludeList
  1591. // EX(x,y), GrpRecord(a) -> EX(x+a,y-a), (a)=gmi
  1592. // used by rules (6) and (13)
  1593. //------------------------------------------------------------------------------
  1594. VOID
  1595. MoveFromExcludeToIncludeList(
  1596. PGI_ENTRY pgie,
  1597. PGROUP_RECORD pGroupRecord
  1598. )
  1599. {
  1600. PGI_SOURCE_ENTRY pSourceEntry;
  1601. DWORD i;
  1602. IPADDR Source;
  1603. Trace0(ENTER1, "Entering _MoveFromExcludeToIncludeList");
  1604. // note:all a should be in x
  1605. for (i=0; i<pGroupRecord->NumSources; i++) {
  1606. //kslksl
  1607. if (pGroupRecord->Sources[i]==0||pGroupRecord->Sources[i]==0xffffffff)
  1608. continue;
  1609. //
  1610. // if in exclusion list remove it and place in inclusion list
  1611. //
  1612. Source = pGroupRecord->Sources[i];
  1613. pSourceEntry = GetSourceEntry(pgie, Source, EXCLUSION, NULL,0,0);
  1614. if (pSourceEntry) {
  1615. if (!pSourceEntry->bStaticSource) {
  1616. ChangeSourceFilterMode(pgie, pSourceEntry);
  1617. UpdateSourceExpTimer(pSourceEntry,
  1618. GMI,
  1619. FALSE //dont have to process lastmem list
  1620. );
  1621. }
  1622. }
  1623. else {
  1624. // not found in exclusion list, so create new entry in IN
  1625. BOOL bCreate = TRUE;
  1626. pSourceEntry = GetSourceEntry(pgie, Source, INCLUSION, &bCreate, GMI, MGM_YES);
  1627. // entry already exists. update it
  1628. if (pSourceEntry && !bCreate) {
  1629. UpdateSourceExpTimer(pSourceEntry,
  1630. GMI,
  1631. FALSE //wont be there in lastmem list
  1632. );
  1633. }
  1634. }
  1635. }
  1636. Trace0(LEAVE1, "Leaving _MoveFromExcludeToIncludeList");
  1637. return;
  1638. }
  1639. //------------------------------------------------------------------------------
  1640. DWORD
  1641. T_V3SourcesQueryTimer (
  1642. PVOID pvContext
  1643. )
  1644. {
  1645. DWORD Error=NO_ERROR;
  1646. PIGMP_TIMER_ENTRY pTimer; //ptr to timer entry
  1647. PGI_ENTRY pgie; //group interface entry
  1648. PWORK_CONTEXT pWorkContext;
  1649. PRAS_TABLE_ENTRY prte;
  1650. PIF_TABLE_ENTRY pite;
  1651. Trace0(ENTER1, "Entering _T_V3SourcesQueryTimer()");
  1652. //
  1653. // get pointer to LastMemQueryTimer, GI entry, pite, prte
  1654. //
  1655. pTimer = CONTAINING_RECORD( pvContext, IGMP_TIMER_ENTRY, Context);
  1656. pgie = CONTAINING_RECORD( pTimer, GI_ENTRY, V3SourcesQueryTimer);
  1657. pite = pgie->pIfTableEntry;
  1658. prte = pgie->pRasTableEntry;
  1659. Trace2(TIMER, "_T_V3SourcesQueryTimer() called for If(%0x), Group(%d.%d.%d.%d)",
  1660. pite->IfIndex, PRINT_IPADDR(pgie->pGroupTableEntry->Group));
  1661. //
  1662. // if GI or pite or prte has flag already set, then exit
  1663. //
  1664. if ( (pgie->Status&DELETED_FLAG) || (pite->Status&DELETED_FLAG) )
  1665. return NO_ERROR;
  1666. if ( (prte!=NULL) && (prte->Status&DELETED_FLAG) )
  1667. return NO_ERROR;
  1668. if (pgie->Version!=3)
  1669. return NO_ERROR;
  1670. //
  1671. // queue work item for sending the Sources query even if the router
  1672. // is not a Querier
  1673. //
  1674. CREATE_WORK_CONTEXT(pWorkContext, Error);
  1675. if (Error!=NO_ERROR) {
  1676. return ERROR_CAN_NOT_COMPLETE;
  1677. }
  1678. pWorkContext->IfIndex = pite->IfIndex;
  1679. pWorkContext->Group = pgie->pGroupTableEntry->Group;
  1680. pWorkContext->NHAddr = pgie->NHAddr; //valid only for ras: should i use it?
  1681. pWorkContext->WorkType = MSG_SOURCES_QUERY;
  1682. Trace0(WORKER, "Queueing WF_TimerProcessing() to send SourcesQuery:");
  1683. if (QueueIgmpWorker(WF_TimerProcessing, (PVOID)pWorkContext)!=NO_ERROR)
  1684. IGMP_FREE(pWorkContext);
  1685. Trace0(LEAVE1, "Leaving _T_V3SourcesQueryTimer()");
  1686. return NO_ERROR;
  1687. }
  1688. //------------------------------------------------------------------------------
  1689. // _T_LastVer2ReportTimer
  1690. //
  1691. // For this GI entry, the last ver-1 report has timed out. Change to ver-3 if
  1692. // the interface is set to ver-3.
  1693. // Locks: Assumes timer lock.
  1694. //------------------------------------------------------------------------------
  1695. DWORD
  1696. T_LastVer2ReportTimer (
  1697. PVOID pvContext
  1698. )
  1699. {
  1700. PIGMP_TIMER_ENTRY pTimer; //ptr to timer entry
  1701. PGI_ENTRY pgie; //group interface entry
  1702. PIF_TABLE_ENTRY pite;
  1703. LONGLONG llCurTime = GetCurrentIgmpTime();
  1704. Trace0(ENTER1, "Entering _T_LastVer2ReportTimer()");
  1705. //
  1706. // get pointer to LastMemQueryTimer, GI entry, pite
  1707. //
  1708. pTimer = CONTAINING_RECORD( pvContext, IGMP_TIMER_ENTRY, Context);
  1709. pgie = CONTAINING_RECORD( pTimer, GI_ENTRY, LastVer2ReportTimer);
  1710. pite = pgie->pIfTableEntry;
  1711. Trace2(TIMER, "T_LastVer2ReportTimer() called for If(%0x), Group(%d.%d.%d.%d)",
  1712. pite->IfIndex, PRINT_IPADDR(pgie->pGroupTableEntry->Group));
  1713. // set the state to ver-3, if ver1 time not active
  1714. if (IS_PROTOCOL_TYPE_IGMPV3(pite) &&
  1715. !IS_TIMER_ACTIVE(pgie->LastVer1ReportTimer))
  1716. {
  1717. PWORK_CONTEXT pWorkContext;
  1718. DWORD Error=NO_ERROR;
  1719. //
  1720. // queue work item for shifting to v3 for that group
  1721. //
  1722. CREATE_WORK_CONTEXT(pWorkContext, Error);
  1723. if (Error!=NO_ERROR) {
  1724. return ERROR_CAN_NOT_COMPLETE;
  1725. }
  1726. pWorkContext->IfIndex = pite->IfIndex;
  1727. pWorkContext->Group = pgie->pGroupTableEntry->Group;
  1728. pWorkContext->NHAddr = pgie->NHAddr; //valid only for ras: should i us
  1729. pWorkContext->WorkType = SHIFT_TO_V3;
  1730. Trace0(WORKER, "Queueing WF_TimerProcessing() to shift to v3");
  1731. if (QueueIgmpWorker(WF_TimerProcessing, (PVOID)pWorkContext)!=NO_ERROR)
  1732. IGMP_FREE(pWorkContext);
  1733. }
  1734. Trace0(LEAVE1, "Leaving _T_LastVer2ReportTimer()");
  1735. return NO_ERROR;
  1736. }
  1737. //------------------------------------------------------------------------------
  1738. DWORD
  1739. T_SourceExpTimer (
  1740. PVOID pvContext
  1741. )
  1742. {
  1743. PIGMP_TIMER_ENTRY pTimer; //ptr to timer entry
  1744. PGI_ENTRY pgie; //group interface entry
  1745. PGI_SOURCE_ENTRY pSourceEntry;
  1746. PWORK_CONTEXT pWorkContext;
  1747. DWORD Error=NO_ERROR;
  1748. Trace0(ENTER1, "Entering _T_SourceExpTimer()");
  1749. pTimer = CONTAINING_RECORD( pvContext, IGMP_TIMER_ENTRY, Context);
  1750. pSourceEntry =
  1751. CONTAINING_RECORD(pTimer, GI_SOURCE_ENTRY, SourceExpTimer);
  1752. pgie = pSourceEntry->pGIEntry;
  1753. //IN entry. delete it
  1754. if (pSourceEntry->bInclusionList) {
  1755. CREATE_WORK_CONTEXT(pWorkContext, Error);
  1756. if (Error!=NO_ERROR)
  1757. return Error;
  1758. pWorkContext->IfIndex = pgie->pIfTableEntry->IfIndex;
  1759. pWorkContext->NHAddr = pgie->NHAddr;
  1760. pWorkContext->Group = pgie->pGroupTableEntry->Group;
  1761. pWorkContext->Source = pSourceEntry->IpAddr;
  1762. pWorkContext->WorkType = (pgie->FilterType==INCLUSION)
  1763. ? DELETE_SOURCE
  1764. : MOVE_SOURCE_TO_EXCL;
  1765. Trace0(WORKER, "_T_SourceExpTimer queued _WF_TimerProcessing:");
  1766. if (QueueIgmpWorker(WF_TimerProcessing, (PVOID)pWorkContext)!=NO_ERROR)
  1767. IGMP_FREE(pWorkContext);
  1768. }
  1769. Trace0(LEAVE1, "Leaving _T_SourceExpTimer()");
  1770. return NO_ERROR;
  1771. }
  1772. #if DEBUG_FLAGS_MEM_ALLOC
  1773. LIST_ENTRY g_MemoryList;
  1774. CRITICAL_SECTION g_MemCS;
  1775. PVOID
  1776. IgmpDebugAlloc(
  1777. DWORD sz,
  1778. DWORD Flags,
  1779. DWORD Id,
  1780. DWORD IfIndex
  1781. )
  1782. {
  1783. static DWORD Initialize = TRUE;
  1784. PMEM_HDR Ptr;
  1785. if (Initialize) {
  1786. InitializeListHead(&g_MemoryList);
  1787. try {
  1788. InitializeCriticalSection(&g_MemCS);
  1789. }
  1790. except (EXCEPTION_EXECUTE_HANDLER) {
  1791. return NULL;
  1792. }
  1793. Initialize = FALSE;
  1794. }
  1795. // allign for 64 bit
  1796. sz = (sz + 63) & 0xFFFFFFc0;
  1797. Ptr = (PMEM_HDR)HeapAlloc(g_Heap,Flags,(sz)+sizeof(MEM_HDR)+sizeof(DWORD));
  1798. if (Ptr==NULL)
  1799. return NULL;
  1800. // Trace1(ERR, "----- alloc:%0x", (ULONG_PTR)Ptr);
  1801. EnterCriticalSection(&g_MemCS);
  1802. Ptr->Signature = 0xabcdefaa;
  1803. Ptr->IfIndex = IfIndex;
  1804. Ptr->Tail = (PDWORD)((PCHAR)Ptr + sz + sizeof(MEM_HDR));
  1805. *Ptr->Tail = 0xabcdefbb;
  1806. Ptr->Id = Id;
  1807. InsertHeadList(&g_MemoryList, &Ptr->Link);
  1808. LeaveCriticalSection(&g_MemCS);
  1809. Trace1(KSL, "Alloc heap:%0x", PtrToUlong(((PCHAR)Ptr+sizeof(MEM_HDR))));//deldel
  1810. return (PVOID)((PCHAR)Ptr+sizeof(MEM_HDR));
  1811. }
  1812. VOID
  1813. IgmpDebugFree(
  1814. PVOID mem
  1815. )
  1816. {
  1817. PMEM_HDR Ptr = (PMEM_HDR)((PCHAR)mem - sizeof(MEM_HDR));
  1818. if (Ptr->Signature != 0xabcdefaa) {
  1819. DbgBreakPoint();
  1820. Trace2(KSL, "\n=======================\n"
  1821. "Freeing Invalid memory:%0x:Id:%0x\n", (ULONG_PTR)Ptr, Ptr->Id);
  1822. }
  1823. if (*Ptr->Tail != 0xabcdefbb) {
  1824. DbgBreakPoint();
  1825. Trace2(KSL, "\n=======================\n"
  1826. "Freeing Invalid memory:Tail corrupted:%0x:Id:%0x\n", (ULONG_PTR)Ptr, Ptr->Id);
  1827. }
  1828. EnterCriticalSection(&g_MemCS);
  1829. Ptr->Signature = 0xaafedcba;
  1830. *Ptr->Tail = 0xbbfedcba;
  1831. RemoveEntryList(&Ptr->Link);
  1832. LeaveCriticalSection(&g_MemCS);
  1833. Trace1(KSL, "Freed heap:%0x", PtrToUlong(mem));//deldel
  1834. HeapFree(g_Heap, 0, Ptr);
  1835. }
  1836. VOID
  1837. DebugScanMemoryInterface(
  1838. DWORD IfIndex
  1839. )
  1840. {
  1841. PMEM_HDR Ptr;
  1842. PLIST_ENTRY ple;
  1843. DWORD Count=0;
  1844. Trace0(ENTER1, "InDebugScanMemoryInterface");
  1845. EnterCriticalSection(&g_MemCS);
  1846. for (ple=g_MemoryList.Flink; ple!=&g_MemoryList; ple=ple->Flink) {
  1847. Ptr = CONTAINING_RECORD(ple, MEM_HDR, Link);
  1848. if (Ptr->IfIndex==IfIndex) {
  1849. if (Count++==0)
  1850. Trace1(ERR, "\n\nMEMORY checking for interface: %0x", IfIndex);
  1851. Trace2(ERR, "MEMORY: %0x Id:%0x", (ULONG_PTR)Ptr, Ptr->Id);
  1852. }
  1853. }
  1854. if (Count!=0) {
  1855. Trace0(ERR, "\n\n");
  1856. DbgBreakPoint();
  1857. }
  1858. LeaveCriticalSection(&g_MemCS);
  1859. }
  1860. VOID
  1861. DebugScanMemory(
  1862. )
  1863. {
  1864. PMEM_HDR Ptr;
  1865. PLIST_ENTRY ple;
  1866. Trace0(ENTER1, "InDebugScanMemory");
  1867. EnterCriticalSection(&g_MemCS);
  1868. for (ple=g_MemoryList.Flink; ple!=&g_MemoryList; ple=ple->Flink) {
  1869. Ptr = CONTAINING_RECORD(ple, MEM_HDR, Link);
  1870. Trace2(ERR, "MEMORY: %0x Id:%0x", (ULONG_PTR)Ptr, Ptr->Id);
  1871. }
  1872. if (!(IsListEmpty(&g_MemoryList))) {
  1873. DbgBreakPoint();
  1874. }
  1875. DeleteCriticalSection(&g_MemCS);
  1876. }
  1877. #endif