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.

2481 lines
77 KiB

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