#include "pchigmp.h" #pragma hdrstop //deldel #define PRINT_SOURCES_LIST 0 VOID DebugSources( PGI_ENTRY pgie ) { PGI_SOURCE_ENTRY pSourceEntry, pSourceEntry2; PLIST_ENTRY pHead, ple; DebugPrintSourcesList(pgie); pHead = &pgie->V3InclusionListSorted; for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) { pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY,LinkSourcesInclListSorted); if (GetSourceEntry(pgie, pSourceEntry->IpAddr,EXCLUSION, NULL, 0, 0)) DbgBreakPoint(); if (ple->Flink!=pHead) { pSourceEntry2 = CONTAINING_RECORD(ple->Flink, GI_SOURCE_ENTRY,LinkSourcesInclListSorted); if (pSourceEntry2->IpAddr==pSourceEntry->IpAddr) DbgBreakPoint(); } } pHead = &pgie->V3ExclusionList; for (ple=pHead->Flink; ple!=pHead && ple->Flink!=pHead; ple=ple->Flink) { pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY,LinkSources); pSourceEntry2 = CONTAINING_RECORD(ple->Flink, GI_SOURCE_ENTRY,LinkSources); if (pSourceEntry->IpAddr == pSourceEntry2->IpAddr) DbgBreakPoint(); } return; } DWORD ProcessGroupQuery( PIF_TABLE_ENTRY pite, IGMP_HEADER UNALIGNED *pHdr, DWORD InPacketSize, DWORD InputSrcAddr, DWORD DstnMcastAddr ) { PGROUP_TABLE_ENTRY pge; //group table entry PGI_ENTRY pgie; //group interface entry BOOL bCreateGroup, bCreateGI; DWORD NHAddr =0, PacketSize, Group, i,RealPktVersion, IfIndex=pite->IfIndex, PktVersion, GIVersion, IfVersion; BOOL bRas=FALSE, bUpdateGroupTimer=FALSE; DWORD NumGroupRecords; LONGLONG llCurTime = GetCurrentIgmpTime(); PIGMP_IF_CONFIG pConfig = &pite->Config; PIGMP_HEADER_V3_EXT pSourcesRecord; Trace0(ENTER1, "Entering _ProcessGroupQuery()"); RealPktVersion = InPacketSize>sizeof(IGMP_HEADER)?3:2; PktVersion = (InPacketSize>sizeof(IGMP_HEADER) && IS_IF_VER3(pite))?3:2; IfVersion = IS_IF_VER1(pite)? 1: (IS_IF_VER2(pite)?2:3); Group = pHdr->Group; Trace3(RECEIVE, "Group-specific-query(%d) received from %d.%d.%d.%d for " "group(%d.%d.%d.%d)", RealPktVersion, PRINT_IPADDR(InputSrcAddr), PRINT_IPADDR(DstnMcastAddr)); if (RealPktVersion==3) { // validate packet size if (InPacketSizeNumSources = ntohs(pSourcesRecord->NumSources); if (InPacketSizeNumSources*sizeof(IPADDR)) { Trace0(RECEIVE, "Group-specific-query dropped. Invalid packet size"); return ERROR_CAN_NOT_COMPLETE; } for (i=0; iNumSources; i++) { Trace1(RECEIVE," %d.%d.%d.%d", PRINT_IPADDR(pSourcesRecord->Sources[i])); } } // // the multicast group should not be 224.0.0.x // if (LOCAL_MCAST_GROUP(DstnMcastAddr)) { Trace2(RECEIVE, "Group-specific-query received from %d.%d.%d.%d for " "Local group(%d.%d.%d.%d)", PRINT_IPADDR(InputSrcAddr), PRINT_IPADDR(DstnMcastAddr)); return ERROR_CAN_NOT_COMPLETE; } // // make sure that the dstn addr and the group fields match // if (Group!=DstnMcastAddr) { Trace4(RECEIVE, "Received Igmp packet (%d) from(%d.%d.%d.%d) with " "Multicast(%d.%d.%d.%d) addr different from " "Group(%d.%d.%d.%d)", IfIndex, PRINT_IPADDR(InputSrcAddr), PRINT_IPADDR(DstnMcastAddr), PRINT_IPADDR(pHdr->Group) ); return ERROR_CAN_NOT_COMPLETE; } // note that a querier can receive a group-Sp query from a non querier // // if Leave processing not enabled or currently version-1 or ras server interface // then ignore. // if ( !IF_PROCESS_GRPQUERY(pite) ) { Trace0(RECEIVE, "Ignoring the Group-Specific-Query"); return ERROR_CAN_NOT_COMPLETE; } // // Lock the group table // ACQUIRE_GROUP_LOCK(Group, "_ProcessGroupQuery"); // // find the group entry. If entry not found then ignore the group query // pge = GetGroupFromGroupTable(Group, NULL, llCurTime); if (pge==NULL) { Trace2(ERR, "group sp-query received for nonexisting " "group(%d.%d.%d.%d) on IfIndex(%0x)", PRINT_IPADDR(Group), IfIndex); RELEASE_GROUP_LOCK(Group, "_ProcessGroupQuery"); return ERROR_CAN_NOT_COMPLETE; } // // find the GI entry. If GI entry does not exist or has deletedFlag then // ignore the GroupSpQuery // pgie = GetGIFromGIList(pge, pite, InputSrcAddr, NOT_STATIC_GROUP, NULL, llCurTime); if ( (pgie==NULL)||(pgie->Status&DELETED_FLAG) ) { Trace2(ERR, "group sp-query received for group(%d.%d.%d.%d) on " "IfIndex(%0x). Not member.", PRINT_IPADDR(Group), IfIndex); RELEASE_GROUP_LOCK(Group, "_ProcessGroupQuery"); return ERROR_CAN_NOT_COMPLETE; } GIVersion = pgie->Version; // treat it as ver 2 packet if group in ver-2 mode if (GIVersion==2 && PktVersion==3) PktVersion = 2; if (RealPktVersion==3 && PktVersion==2) Trace0(RECEIVE, "Processing the Version:3 GroupSpQuery as Version:2"); // // if interface is ver-1 or its leave enabled flag is not set or // if v1-report received recently for that group, then ignore // LastMemQuery messages. // if ( !GI_PROCESS_GRPQUERY(pite, pgie) ) { Trace2(RECEIVE, "Leave not processed for group(%d.%d.%d.%d) on IfIndex(%0x)" "(recent v1 report) or interface ver-1", PRINT_IPADDR(Group), IfIndex ); RELEASE_GROUP_LOCK(Group, "_ProcessGroupQuery"); return ERROR_CAN_NOT_COMPLETE; } ACQUIRE_TIMER_LOCK("_ProcessGroupQuery"); BEGIN_BREAKOUT_BLOCK1 { if (PktVersion==2 && GIVersion==2) { // // if membership timer already expired then return. The group will be // deleted by the expiry of the membership timer // if ( (!(pgie->GroupMembershipTimer.Status&TIMER_STATUS_ACTIVE)) ||(pgie->GroupMembershipTimer.TimeoutLastMemQueryCount>0) { INT cmp; if (INET_CMP(InputSrcAddr,pite->IpAddr, cmp)<0) { if (pgie->LastMemQueryTimer.Status==TIMER_STATUS_ACTIVE) { RemoveTimer(&pgie->LastMemQueryTimer, DBG_Y); } pgie->LastMemQueryCount = 0; } GOTO_END_BLOCK1; } // // set membership timer to // min{currentValue,MaxResponseTimeInPacket*LastMemQueryCount} // if (pgie->GroupMembershipTimer.Timeout > (llCurTime+( ((LONGLONG)pConfig->LastMemQueryCount) *pHdr->ResponseTime*100 )) ) { //divide by 10, as Response time in units of 100ms #if DEBUG_TIMER_TIMERID SET_TIMER_ID(&pgie->GroupMembershipTimer, 330, pite->IfIndex, Group, 0); #endif if (IS_TIMER_ACTIVE(pgie->GroupMembershipTimer)) { UpdateLocalTimer(&pgie->GroupMembershipTimer, pConfig->LastMemQueryCount*pHdr->ResponseTime*100, DBG_N); } else { InsertTimer(&pgie->GroupMembershipTimer, pConfig->LastMemQueryCount*pHdr->ResponseTime*100, TRUE, DBG_N ); } // update GroupExpiryTime so that correct stats are displayed pgie->Info.GroupExpiryTime = llCurTime + CONFIG_TO_SYSTEM_TIME(pConfig->LastMemQueryCount *pHdr->ResponseTime*100); } } else if (PktVersion==2 && GIVersion==3){ // ignore the packet Trace0(RECEIVE, "Ignoring the version-2 group specific query"); } else if (PktVersion==3 && GIVersion==3) { // ignore it if SFlag set if (pSourcesRecord->SFlag == 1) GOTO_END_BLOCK1; for (i=0; iNumSources; i++) { IPADDR Source; PGI_SOURCE_ENTRY pSourceEntry; Source = pSourcesRecord->Sources[i]; pSourceEntry = GetSourceEntry(pgie, Source, INCLUSION, NULL, 0, 0); if (!pSourceEntry) continue; if ((QueryRemainingTime(&pSourceEntry->SourceExpTimer, 0) >pgie->pIfTableEntry->Config.LastMemQueryInterval) ) { #if DEBUG_TIMER_TIMERID pSourceEntry->SourceExpTimer.Id = 621; pSourceEntry->SourceExpTimer.Id2 = TimerId++; #endif UpdateLocalTimer(&pSourceEntry->SourceExpTimer, pite->Config.LastMemQueryInterval, DBG_N); } } } } END_BREAKOUT_BLOCK1; // //release timer and groupBucket locks // RELEASE_TIMER_LOCK("_ProcessGroupQuery"); RELEASE_GROUP_LOCK(Group, "_ProcessGroupQuery"); Trace0(LEAVE1, "Leaving _ProcessGroupQuery()"); return NO_ERROR; } DWORD ProcessReport( PIF_TABLE_ENTRY pite, IGMP_HEADER UNALIGNED *pHdr, DWORD InPacketSize, DWORD InputSrcAddr, DWORD DstnMcastAddr ) { PGROUP_TABLE_ENTRY pge; //group table entry PGI_ENTRY pgie; //group interface entry BOOL bCreateGroup, bCreateGI; DWORD NHAddr =0, PacketSize, Group, i, IfIndex=pite->IfIndex, PktVersion, GIVersion, IfVersion; BOOL bRas=FALSE, bUpdateGroupTimer=FALSE; DWORD NumGroupRecords; LONGLONG llCurTime = GetCurrentIgmpTime(); PIGMP_IF_CONFIG pConfig = &pite->Config; //v3 PGROUP_RECORD pGroupRecord; Trace0(ENTER1, "Entering _ProcessReport()"); switch(pHdr->Vertype) { case IGMP_REPORT_V1: PktVersion=1; break; case IGMP_REPORT_V2: PktVersion=2; break; case IGMP_REPORT_V3: PktVersion=3; break; } IfVersion = IS_IF_VER1(pite)? 1: (IS_IF_VER2(pite)?2:3); Trace5(RECEIVE, "IGMP-V%d Report from (%d.%d.%d.%d) on " "IfIndex(%0x)%d.%d.%d.%d dstaddr:%d.%d.%d.%d", PktVersion, PRINT_IPADDR(InputSrcAddr), IfIndex, PRINT_IPADDR(pite->IpAddr), PRINT_IPADDR(DstnMcastAddr) ); // // the multicast group should not be 224.0.0.x or SSM // if (PktVersion!=3 && (LOCAL_MCAST_GROUP(pHdr->Group) || SSM_MCAST_GROUP(pHdr->Group))) { Trace3(RECEIVE, "Igmp-v%d report received from %d.%d.%d.%d for Local/SSM group(%d.%d.%d.%d)", PktVersion, PRINT_IPADDR(InputSrcAddr), PRINT_IPADDR(DstnMcastAddr)); return ERROR_CAN_NOT_COMPLETE; } if (PktVersion!=3) Trace1(RECEIVE, " Group:%d.%d.%d.%d\n", PRINT_IPADDR(pHdr->Group)); if (PktVersion==3) { // // validate packet size // // convert to host order pHdr->NumGroupRecords = ntohs(pHdr->NumGroupRecords); PacketSize = sizeof(IGMP_HEADER); NumGroupRecords = pHdr->NumGroupRecords; // min size of each group record is 2*ipaddr PacketSize += NumGroupRecords*2*sizeof(IPADDR); BEGIN_BREAKOUT_BLOCK1 { PCHAR StrRecordType[] = {"", "is_in", "is_ex", "to_in", "to_ex", "allow", "BLOCK"}; i = 0; if (PacketSize>InPacketSize) { GOTO_END_BLOCK1; } pGroupRecord = GET_FIRST_GROUP_RECORD(pHdr); for (; iNumSources = ntohs(pGroupRecord->NumSources); PacketSize += pGroupRecord->NumSources*sizeof(IPADDR); if (PacketSize>InPacketSize) GOTO_END_BLOCK1; // print group record Trace3(RECEIVE, "< Group:%d.%d.%d.%d RecordType:%s NumSources:%d >", PRINT_IPADDR(pGroupRecord->Group), StrRecordType[pGroupRecord->RecordType], pGroupRecord->NumSources ); for (j=0; jNumSources; j++) Trace1(RECEIVE, " %d.%d.%d.%d", PRINT_IPADDR(pGroupRecord->Sources[j])); // // error if local_mcast or ssm-exclude mode // if (LOCAL_MCAST_GROUP(pGroupRecord->Group) || (SSM_MCAST_GROUP(pGroupRecord->Group) && (pGroupRecord->RecordType == IS_EX || pGroupRecord->RecordType == TO_EX)) ) { Trace3(RECEIVE, "Igmp-v%d report received from %d.%d.%d.%d for Local/SSM group(%d.%d.%d.%d)", PktVersion, PRINT_IPADDR(InputSrcAddr), PRINT_IPADDR(DstnMcastAddr)); return ERROR_CAN_NOT_COMPLETE; } pGroupRecord = (PGROUP_RECORD) &(pGroupRecord->Sources[pGroupRecord->NumSources]); } } END_BREAKOUT_BLOCK1; if (i!=NumGroupRecords || PacketSize>InPacketSize) { Trace0(ERR, "Received IGMP-v3 report small size"); InterlockedIncrement(&pite->Info.ShortPacketsReceived); return ERROR_CAN_NOT_COMPLETE; } if (PacketSizeInfo.LongPacketsReceived); } pGroupRecord = GET_FIRST_GROUP_RECORD(pHdr); }//pktversion==3 // for v1 and v2, set num group records to 1 so that it will come out of // loop else { NumGroupRecords = 1; } // // check that the dstn addr is correct. // should be same as group, or unicast ipaddr // or v3: could be All_Igmp_routers group // if (! ((DstnMcastAddr==pite->IpAddr) || (PktVersion!=3 && DstnMcastAddr==pHdr->Group) || (PktVersion==3 && DstnMcastAddr==ALL_IGMP_ROUTERS_MCAST)) ) { Trace3(RECEIVE, "received IGMP report packet on IfIndex(%0x) from " "SrcAddr(%d.%d.%d.%d) but invalid DstnMcastAddr(%d.%d.%d.%d)", IfIndex, PRINT_IPADDR(InputSrcAddr), PRINT_IPADDR(DstnMcastAddr) ); return ERROR_CAN_NOT_COMPLETE; } // // V1 router ignores V2/V3 reports. V2 router ignores v3 reports // if ( (IfVersion==1 && (PktVersion==2||PktVersion==3)) ||(IfVersion==2 && PktVersion==3) ) { Trace1(RECEIVE, "Ignoring higher version:%d IGMP report", PktVersion); return NO_ERROR; } // // update statistics // InterlockedIncrement(&pite->Info.JoinsReceived); // numgrouprecords==1 for v1,v2 for (i=0; iGroup : pHdr->Group; if ( !IS_MCAST_ADDR(Group) ) { Trace4(RECEIVE, "received IGMP Leave packet with illegal Group(%d.%d.%d.%d) field: " "IfIndex(%0x) SrcAddr(%d.%d.%d.%d) DstnMcastAddr(%d.%d.%d.%d)", PRINT_IPADDR(Group), IfIndex, PRINT_IPADDR(InputSrcAddr), PRINT_IPADDR(DstnMcastAddr) ); } if (LOCAL_MCAST_GROUP(Group)) { if (PktVersion==3){ pGroupRecord = (PGROUP_RECORD) &(pGroupRecord->Sources[pGroupRecord->NumSources]); continue; } else break; } //kslksl if (PktVersion==3 && pGroupRecord->NumSources==0 && pGroupRecord->RecordType==IS_IN) { pGroupRecord = (PGROUP_RECORD) &(pGroupRecord->Sources[pGroupRecord->NumSources]); continue; } // // Lock the group table // ACQUIRE_GROUP_LOCK(Group, "_ProcessReport"); // // find the group entry and create one if not found // also increment GroupMembership count if req // bCreateGroup = TRUE; pge = GetGroupFromGroupTable(Group, &bCreateGroup, llCurTime); if (pge==NULL) { RELEASE_GROUP_LOCK(Group, "_ProcessReport"); return ERROR_CAN_NOT_COMPLETE; } // // find the GI entry and if not found create one. // the version in GI entry is same as that of interface // bCreateGI = TRUE; pgie = GetGIFromGIList(pge, pite, InputSrcAddr, NOT_STATIC_GROUP, &bCreateGI, llCurTime); if (pgie==NULL) { RELEASE_GROUP_LOCK(Group, "_ProcessReport"); return ERROR_CAN_NOT_COMPLETE; } GIVersion = pgie->Version; // acquire timer lock ACQUIRE_TIMER_LOCK("_ProcessReport"); // // update the ver-1, membership, and lastMemTimer. // Note: the GI entry might be a new one or old one // // // shift to version 1 level processing // if (PktVersion==1) { if (GIVersion!=1) { pgie->Version = 1; if (GIVersion==3) { if (pgie->FilterType!=EXCLUSION) { // add (*,g) to MGM MGM_ADD_GROUP_MEMBERSHIP_ENTRY(pite, NHAddr, 0, 0, Group, 0xffffffff, MGM_JOIN_STATE_FLAG); } GIDeleteAllV3Sources(pgie, TRUE); } // gi version from 2,3-> 1 GIVersion = 1; } // // received v1 report when IF not v1. update v1host timer. // if (!IS_IF_VER1(pite)) { #if DEBUG_TIMER_TIMERID SET_TIMER_ID(&pgie->LastVer1ReportTimer,510, pite->IfIndex, Group, 0); #endif if (IS_TIMER_ACTIVE(pgie->LastVer1ReportTimer)) { UpdateLocalTimer(&pgie->LastVer1ReportTimer, pConfig->GroupMembershipTimeout, DBG_N); } else { InsertTimer(&pgie->LastVer1ReportTimer, pConfig->GroupMembershipTimeout, TRUE, DBG_N); } // set the V1HostPresentTimeLeft value for stats pgie->Info.V1HostPresentTimeLeft = llCurTime + CONFIG_TO_SYSTEM_TIME(pConfig->GroupMembershipTimeout); } // update group timer for all versions bUpdateGroupTimer = TRUE; } // // shift to version 2 level processing // else if (PktVersion==2) { if (GIVersion==3) { pgie->Version = 2; if (pgie->FilterType!=EXCLUSION) { // add (*,g) to MGM MGM_ADD_GROUP_MEMBERSHIP_ENTRY( pite, NHAddr, 0, 0, Group, 0xffffffff, MGM_JOIN_STATE_FLAG); } GIDeleteAllV3Sources(pgie, TRUE); // gi version from 3->2 GIVersion = 2; } // // received v2 report when in in v3 mode. update v2host timer. if (IS_IF_VER3(pite)) { #if DEBUG_TIMER_TIMERID SET_TIMER_ID(&pgie->LastVer2ReportTimer,550, pite->IfIndex, Group, 0); #endif if (IS_TIMER_ACTIVE(pgie->LastVer2ReportTimer)) { UpdateLocalTimer(&pgie->LastVer2ReportTimer, pConfig->GroupMembershipTimeout, DBG_N); } else { InsertTimer(&pgie->LastVer2ReportTimer, pConfig->GroupMembershipTimeout, TRUE, DBG_N); } // set the V2HostPresentTimeLeft value for stats pgie->Info.V2HostPresentTimeLeft = llCurTime + CONFIG_TO_SYSTEM_TIME(pConfig->GroupMembershipTimeout); } // update group timer for all versions bUpdateGroupTimer = TRUE; } else if (PktVersion==3) { if (GIVersion!=3) { // update timer only if it is not a v3 block message if (bCreateGI || pGroupRecord->RecordType!=BLOCK) bUpdateGroupTimer = TRUE; } else { ProcessV3Report(pgie, pGroupRecord, &bUpdateGroupTimer); } } // NOTE: if giversion==3, then pgie may be invalid below here // // report received. so remove the lastMemTimer if pgie is not v3. // if (GIVersion!=3 && pgie->LastMemQueryCount>0) { if (pgie->LastMemQueryTimer.Status&TIMER_STATUS_ACTIVE) RemoveTimer(&pgie->LastMemQueryTimer, DBG_Y); pgie->LastMemQueryCount = 0; } if (bUpdateGroupTimer) { // // update membership timer // #if DEBUG_TIMER_TIMERID (&pgie->GroupMembershipTimer)->Id = 320; (&pgie->GroupMembershipTimer)->IfIndex = 320; SET_TIMER_ID(&pgie->GroupMembershipTimer,320, pite->IfIndex, Group, 0); #endif if (IS_TIMER_ACTIVE(pgie->GroupMembershipTimer)) { UpdateLocalTimer(&pgie->GroupMembershipTimer, pite->Config.GroupMembershipTimeout, DBG_N); } else { InsertTimer(&pgie->GroupMembershipTimer, pite->Config.GroupMembershipTimeout, TRUE, DBG_N); } // update GroupExpiryTime { LONGLONG tempTime; tempTime = llCurTime + CONFIG_TO_SYSTEM_TIME(pite->Config.GroupMembershipTimeout); pgie->Info.GroupExpiryTime = tempTime; } } if (pgie->Version==3 && pgie->FilterType==INCLUSION && pgie->NumSources==0) { DeleteGIEntry(pgie, TRUE, TRUE); } RELEASE_TIMER_LOCK("_ProcessReport"); // //update the last reporter field // if (GIVersion!=3) InterlockedExchange(&pgie->Info.LastReporter, InputSrcAddr); // // Release the group table lock // RELEASE_GROUP_LOCK(Group, "_ProcessReport"); if (PktVersion==3) { pGroupRecord = (PGROUP_RECORD) &(pGroupRecord->Sources[pGroupRecord->NumSources]); } else break; }//for all group records Trace0(LEAVE1, "Leaving _ProcessReport()"); return NO_ERROR; } //------------------------------------------------------------------------------ DWORD ProcessV3Report( PGI_ENTRY pgie, PGROUP_RECORD pGroupRecord, BOOL *bUpdateGroupTimer ) { BOOL bCreate; PGI_SOURCE_ENTRY pSourceEntry; DWORD i,j; IPADDR Source; PLIST_ENTRY ple, pHead; Trace0(ENTER1, "Entering _Processv3Report()"); *bUpdateGroupTimer = FALSE; //deldel //DebugPrintSourcesList(pgie); //DebugPrintSourcesList1(pgie); //DebugPrintIfGroups(pgie->pIfTableEntry,0); //kslksl if (pGroupRecord->NumSources==0 && pGroupRecord->RecordType==IS_IN) return NO_ERROR; switch(pGroupRecord->RecordType) { case IS_IN: { //(11)--------------------------- // INCLUSION(A), IS_IN(b): A=A+b,(B)=gmi if (pgie->FilterType==INCLUSION) { // // include all sources in groupRecord and update timers for them // for (i=0; iNumSources; i++) {//sources in pkt //kslksl if (pGroupRecord->Sources[i]==0||pGroupRecord->Sources[i]==0xffffffff) continue; Source = pGroupRecord->Sources[i]; bCreate = TRUE; pSourceEntry = GetSourceEntry(pgie, Source, INCLUSION, &bCreate, GMI, MGM_YES); if (pSourceEntry==NULL) return ERROR_NOT_ENOUGH_MEMORY; // update source timer if already exists if (bCreate==FALSE) { UpdateSourceExpTimer(pSourceEntry, GMI, FALSE //remove from lastmem list ); } } } else { //(13)--------------------------------(same as 6) // exclusion Mode(x,y), IS_IN pkt(a): (x+a,y-a), (a)=gmi MoveFromExcludeToIncludeList(pgie, pGroupRecord); } break; }//end case _IS_IN case IS_EX: { //(12)---------------------------------------- //INCLUSION Mode(A), IS_EX(B): (A*B,B-A), //Delete(A-B),GT=GMI,(b-a)=0 if (pgie->FilterType==INCLUSION) { // change from in->ex pgie->FilterType = EXCLUSION; MGM_ADD_GROUP_MEMBERSHIP_ENTRY(pgie->pIfTableEntry,pgie->NHAddr, 0, 0, pgie->pGroupTableEntry->Group, 0xffffffff, MGM_JOIN_STATE_FLAG); // delete (A-B) SourcesSubtraction(pgie, pGroupRecord, INCLUSION); // create (B-A) in exclusion Mode for (j=0; jNumSources; j++) { if (!GetSourceEntry(pgie, pGroupRecord->Sources[j],INCLUSION, NULL,0,0)) { BOOL bCreate=TRUE; // IF already pruned from mfe. keep it that way GetSourceEntry(pgie, pGroupRecord->Sources[j], EXCLUSION, &bCreate,0, MGM_YES); } } // update group timer *bUpdateGroupTimer = TRUE; } //(14)-------------------------------------- // EXCLUSION Mode(x,y), IS_EX(a); D(x-a),D(y-a),GT=gmi else { //(X-A), (y-a) SourcesSubtraction(pgie, pGroupRecord, INCLUSION); SourcesSubtraction(pgie, pGroupRecord, EXCLUSION); // if a not in y, then insert in x(IN) (a-x-y)=GMI for (j=0; jNumSources; j++) { //kslksl if (pGroupRecord->Sources[j]==0||pGroupRecord->Sources[j]==0xffffffff) continue; pSourceEntry = GetSourceEntry(pgie, pGroupRecord->Sources[j], EXCLUSION, NULL,0,0); if (!pSourceEntry) { bCreate = TRUE; pSourceEntry = GetSourceEntry(pgie, pGroupRecord->Sources[j], INCLUSION, &bCreate, GMI, MGM_YES); } } // update group timer *bUpdateGroupTimer = TRUE; }//end4 break; }//case IS_EX case ALLOW : { //(1)---------------------------------------- // INCLUSION Mode(a), ALLOW pkt(b): (a+b), (b)=gmi if (pgie->FilterType==INCLUSION) { InclusionSourcesUnion(pgie, pGroupRecord); } //(6)---------------------------------------- // EXCLUSION Mode(x,y), ALLOW pkt(a): (same as 13: (x+a, y-a) else { MoveFromExcludeToIncludeList(pgie, pGroupRecord); } break; }//case ALLOW case BLOCK : { //(2)---------------------------------------- // INCLUSION Mode(x), BLOCK pkt(a): Send Q(G,A*B) if (pgie->FilterType==INCLUSION) { BuildAndSendSourcesQuery(pgie, pGroupRecord, INTERSECTION); } //(7)---------------------------------------- // EXCLUSION Mode(x,y), BLOCK pkt(a): (x+(a-y),y),Send Q(a-y) else { BuildAndSendSourcesQuery(pgie, pGroupRecord, EXCLUSION); } break; }//case BLOCK case TO_EX : { //(4)---------------------------------------- // INCLUSION Mode(x), TO_EX pkt(a) // move to EX mode: EX(A*b,b-a),Send Q(G,A*B) if (pgie->FilterType==INCLUSION) { pgie->FilterType = EXCLUSION; // exclusion mode: add (*,g) to MGM MGM_ADD_GROUP_MEMBERSHIP_ENTRY(pgie->pIfTableEntry,pgie->NHAddr, 0, 0, pgie->pGroupTableEntry->Group, 0xffffffff, MGM_JOIN_STATE_FLAG); // delete (a-b) from IN list SourcesSubtraction(pgie, pGroupRecord, INCLUSION); // // add (b-a) to EX list. IF not added to mfe. so no mgm. // for (j=0; jNumSources; j++) { //kslksl if (pGroupRecord->Sources[j]==0||pGroupRecord->Sources[j]==0xffffffff) continue; pSourceEntry = GetSourceEntry(pgie, pGroupRecord->Sources[j], INCLUSION, NULL, 0, 0); if (!pSourceEntry) { bCreate = TRUE; GetSourceEntry(pgie, pGroupRecord->Sources[j], EXCLUSION, &bCreate, 0, MGM_NO); } } // send Q for sources left in IN list BuildAndSendSourcesQuery(pgie, pGroupRecord, INCLUSION); // update group timer *bUpdateGroupTimer = TRUE; } //(9)---------------------------------------- // EXCLUSION Mode(x,y), TO_EX pkt(a): ( else { // delete (x-a) from IN list SourcesSubtraction(pgie, pGroupRecord, INCLUSION); // delete (y-a) from EX list SourcesSubtraction(pgie, pGroupRecord, EXCLUSION); // add x+(a-y) and send Q(a-y) BuildAndSendSourcesQuery(pgie, pGroupRecord, EXCLUSION); // update group timer *bUpdateGroupTimer = TRUE; } break; }//case TO_EX case TO_IN : { //(5)---------------------------------------- // INCLUSION Mode(a), TO_IN(b): IN(a+b),Send Q(G,A*B) if (pgie->FilterType==INCLUSION) { // for all a not in b, send sources query BuildAndSendSourcesQuery(pgie, pGroupRecord, RULE5); // inc a+b InclusionSourcesUnion(pgie, pGroupRecord); } //(10)---------------------------------------- // EXCLUSION Mode(x,y), TO_IN pkt(a): ( else { PIGMP_IF_CONFIG pConfig = &pgie->pIfTableEntry->Config; // for all x not in a, send sources query BuildAndSendSourcesQuery(pgie, pGroupRecord, RULE5); // x+a. a=gmi. if in ex list move it to in list InclusionSourcesUnion(pgie, pGroupRecord); // set group query count pgie->LastMemQueryCount = pConfig->LastMemQueryCount; ACQUIRE_TIMER_LOCK("_ProcessV3Report"); // set group query timer #if DEBUG_TIMER_TIMERID SET_TIMER_ID(&pgie->LastMemQueryTimer, 410, pgie->pIfTableEntry->IfIndex, pgie->pGroupTableEntry->Group, 0); #endif InsertTimer(&pgie->LastMemQueryTimer, pConfig->LastMemQueryInterval/pConfig->LastMemQueryCount, TRUE, DBG_N); // update group expiry timer to LMQI UpdateLocalTimer(&pgie->GroupMembershipTimer, pConfig->LastMemQueryInterval, DBG_Y); RELEASE_TIMER_LOCK("_ProcessV3Report"); // send group query SendV3GroupQuery(pgie); } break; }//case TO_IN }//end switch #if PRINT_SOURCES_LIST DebugPrintSourcesList(pgie); #endif //DebugPrintIfGroups(pgie->pIfTableEntry,0);//deldel Trace0(LEAVE1, "Leaving _ProcessV3Report()"); return NO_ERROR; } VOID DebugPrintSourcesList( PGI_ENTRY pgie ) { PLIST_ENTRY pHead, ple; PGI_SOURCE_ENTRY pSourceEntry; LONGLONG llCurTime = GetCurrentIgmpTime(); DWORD Count=0; Trace2(SOURCES, "\nPrinting SourcesList for Group: %d.%d.%d.%d Mode:%s", PRINT_IPADDR(pgie->pGroupTableEntry->Group), pgie->FilterType==INCLUSION ? "inc" : "exc" ); { DWORD Tmp; Trace1(SOURCES, "Num sources in query list:%d", pgie->V3SourcesQueryCount); pHead = &pgie->V3SourcesQueryList; Tmp = ListLength(&pgie->V3SourcesQueryList); pHead = &pgie->V3SourcesQueryList; for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink){ pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY, V3SourcesQueryList); Trace1(SOURCES, "%d.%d.%d.%d source in query list", PRINT_IPADDR(pSourceEntry->IpAddr)); } } pHead = &pgie->V3ExclusionList; for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) { pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY,LinkSources); Trace5(SOURCES, "Src: %d.%d.%d.%d %s %d|%d SrcQueryLeft:%d", PRINT_IPADDR(pSourceEntry->IpAddr), pSourceEntry->bInclusionList? "INC":"EXC", (DWORD)(llCurTime - pSourceEntry->SourceInListTime)/1000, (IS_TIMER_ACTIVE(pSourceEntry->SourceExpTimer) ?QueryRemainingTime(&pSourceEntry->SourceExpTimer, llCurTime)/1000 : 0), pSourceEntry->V3SourcesQueryLeft ); } pHead = &pgie->V3InclusionListSorted; for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) { pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY,LinkSourcesInclListSorted); Trace5(SOURCES, "Src: %d.%d.%d.%d %s %d|%d SrcQueryLeft:%d", PRINT_IPADDR(pSourceEntry->IpAddr), pSourceEntry->bInclusionList? "INC":"EXC", IS_TIMER_ACTIVE(pSourceEntry->SourceExpTimer) ?QueryRemainingTime(&pSourceEntry->SourceExpTimer, llCurTime)/1000 : 0, (DWORD)(llCurTime - pSourceEntry->SourceInListTime)/1000, pSourceEntry->V3SourcesQueryLeft ); } Trace0(SOURCES, "\n"); } VOID DebugPrintSourcesList1( PGI_ENTRY pgie ) { PLIST_ENTRY pHead, ple; PGI_SOURCE_ENTRY pSourceEntry; LONGLONG llCurTime = GetCurrentIgmpTime(); DWORD Count=0; { DWORD Tmp; Trace1(SOURCES, "Num sources in query list:%d", pgie->V3SourcesQueryCount); pHead = &pgie->V3SourcesQueryList; Tmp = ListLength(&pgie->V3SourcesQueryList); pHead = &pgie->V3SourcesQueryList; if (Tmp!=pgie->V3SourcesQueryCount) { for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink){ pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY, V3SourcesQueryList); Trace1(SOURCES, "%d.%d.%d.%d source in query list", PRINT_IPADDR(pSourceEntry->IpAddr)); } DbgBreakPoint(); } } Trace2(SOURCES, "\nPrinting SourcesList for Group: %d.%d.%d.%d Mode:%s", PRINT_IPADDR(pgie->pGroupTableEntry->Group), pgie->FilterType==INCLUSION ? "inc" : "exc" ); pHead = &pgie->V3ExclusionList; for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) { pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY,LinkSources); if (pSourceEntry->IpAddr <0x01010101 || pSourceEntry->IpAddr>0x3F010101) { Trace5(SOURCES, "Src: %d.%d.%d.%d %s %d|%d SrcQueryLeft:%d", PRINT_IPADDR(pSourceEntry->IpAddr), pSourceEntry->bInclusionList? "INC":"EXC", (DWORD)(llCurTime - pSourceEntry->SourceInListTime)/1000, (IS_TIMER_ACTIVE(pSourceEntry->SourceExpTimer) ?QueryRemainingTime(&pSourceEntry->SourceExpTimer, llCurTime)/1000 : 0), pSourceEntry->V3SourcesQueryLeft ); DbgBreakPoint(); } } if (ListLength(&pgie->V3InclusionListSorted)!=ListLength(&pgie->V3InclusionList[0]) ||(ListLength(&pgie->V3InclusionListSorted)!=pgie->NumSources)) { Trace0(SOURCES, "Sorted"); pHead = &pgie->V3InclusionListSorted; for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) { pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY,LinkSourcesInclListSorted); Trace5(SOURCES, "Src: %d.%d.%d.%d %s %d|%d SrcQueryLeft:%d", PRINT_IPADDR(pSourceEntry->IpAddr), pSourceEntry->bInclusionList? "INC":"EXC", IS_TIMER_ACTIVE(pSourceEntry->SourceExpTimer) ?QueryRemainingTime(&pSourceEntry->SourceExpTimer, llCurTime)/1000 : 0, (DWORD)(llCurTime - pSourceEntry->SourceInListTime)/1000, pSourceEntry->V3SourcesQueryLeft ); } Trace0(SOURCES, "NotSorted"); pHead = &pgie->V3InclusionList[0]; for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) { pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY,LinkSources); Trace5(SOURCES, "Src: %d.%d.%d.%d %s %d|%d SrcQueryLeft:%d", PRINT_IPADDR(pSourceEntry->IpAddr), pSourceEntry->bInclusionList? "INC":"EXC", IS_TIMER_ACTIVE(pSourceEntry->SourceExpTimer) ?QueryRemainingTime(&pSourceEntry->SourceExpTimer, llCurTime)/1000 : 0, (DWORD)(llCurTime - pSourceEntry->SourceInListTime)/1000, pSourceEntry->V3SourcesQueryLeft ); } DbgBreakPoint(); } Trace0(SOURCES, "\n"); } //------------------------------------------------------------------------------ // _SendV3GroupQuery //------------------------------------------------------------------------------ VOID SendV3GroupQuery( PGI_ENTRY pgie ) { PLIST_ENTRY pHead, ple; PGI_SOURCE_ENTRY pSourceEntry; if (pgie->LastMemQueryCount==0 || pgie->Version!=3) return; Trace0(ENTER1, "Entering _SendV3GroupQuery()"); // send group query SEND_GROUP_QUERY_V3(pgie->pIfTableEntry, pgie, pgie->pGroupTableEntry->Group); // set group query count if (--pgie->LastMemQueryCount) { ACQUIRE_TIMER_LOCK("_SendV3GroupQuery"); // set group query timer #if DEBUG_TIMER_TIMERID SET_TIMER_ID(&pgie->LastMemQueryTimer, 410, pgie->pIfTableEntry->IfIndex, pgie->pGroupTableEntry->Group, 0); #endif InsertTimer(&pgie->LastMemQueryTimer, pgie->pIfTableEntry->Config.LastMemQueryInterval /pgie->pIfTableEntry->Config.LastMemQueryCount, TRUE, DBG_Y); RELEASE_TIMER_LOCK("_SendV3GroupQuery"); } // reduce pending source queries for those with S bit set pHead = &pgie->V3SourcesQueryList; for (ple=pHead->Flink; ple!=pHead; ) { pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY, V3SourcesQueryList); ple = ple->Flink; if (QueryRemainingTime(&pSourceEntry->SourceExpTimer, 0) >pgie->pIfTableEntry->Config.LastMemQueryInterval) { if (--pSourceEntry->V3SourcesQueryLeft == 0) { RemoveEntryList(&pSourceEntry->V3SourcesQueryList); pSourceEntry->bInV3SourcesQueryList = FALSE; pSourceEntry->V3SourcesQueryLeft--; } } } Trace0(LEAVE1, "Leaving _SendV3GroupQuery()"); return; } VOID ChangeSourceFilterMode( PGI_ENTRY pgie, PGI_SOURCE_ENTRY pSourceEntry ) { DWORD Mode = (pSourceEntry->bInclusionList) ? INCLUSION : EXCLUSION; Trace0(ENTER1, "Entering _ChangeSourceFilterMode()"); //deldel //DebugPrintSourcesList(pgie); //DebugPrintSourcesList1(pgie); if (Mode==EXCLUSION) { // remove from exclusion list RemoveEntryList(&pSourceEntry->LinkSources); pSourceEntry->bInclusionList = TRUE; // insert in both inclusion lists INSERT_IN_SORTED_LIST( &pgie->V3InclusionList[pSourceEntry->IpAddr%SOURCES_BUCKET_SZ], pSourceEntry, IpAddr, GI_SOURCE_ENTRY, LinkSources ); INSERT_IN_SORTED_LIST( &pgie->V3InclusionListSorted, pSourceEntry, IpAddr, GI_SOURCE_ENTRY, LinkSourcesInclListSorted ); pgie->NumSources ++; // add to mgm. this will also remove any -ve state. MGM_ADD_GROUP_MEMBERSHIP_ENTRY(pgie->pIfTableEntry, pgie->NHAddr, pSourceEntry->IpAddr, 0xffffffff, pgie->pGroupTableEntry->Group, 0xffffffff, MGM_JOIN_STATE_FLAG); } // remove source from inclusion state else { RemoveEntryList(&pSourceEntry->LinkSources); RemoveEntryList(&pSourceEntry->LinkSourcesInclListSorted); pSourceEntry->bInclusionList = FALSE; if (pSourceEntry->bInV3SourcesQueryList) { RemoveEntryList(&pSourceEntry->V3SourcesQueryList); pSourceEntry->bInV3SourcesQueryList = FALSE; pgie->V3SourcesQueryCount--; pSourceEntry->V3SourcesQueryLeft = 0; } pgie->NumSources--; INSERT_IN_SORTED_LIST( &pgie->V3ExclusionList, pSourceEntry, IpAddr, GI_SOURCE_ENTRY, LinkSources ); ACQUIRE_TIMER_LOCK("_ChangeSourceFilterMode"); // remove sourceexptimer if (IS_TIMER_ACTIVE(pSourceEntry->SourceExpTimer)) RemoveTimer(&pSourceEntry->SourceExpTimer, DBG_N); RELEASE_TIMER_LOCK("_ChangeSourceFilterMode"); // removing from inclusion list. so delete join state MGM_DELETE_GROUP_MEMBERSHIP_ENTRY(pgie->pIfTableEntry, pgie->NHAddr, pSourceEntry->IpAddr, 0xffffffff, pgie->pGroupTableEntry->Group, 0xffffffff, MGM_JOIN_STATE_FLAG); // dont have to delete any +ve mfe as the mgm call would have done that } //deldel //DebugPrintSourcesList(pgie); //DebugPrintSourcesList1(pgie); Trace0(LEAVE1, "Leaving _ChangeSourceFilterMode()"); return; } //------------------------------------------------------------------------------ VOID DeleteSourceEntry( PGI_SOURCE_ENTRY pSourceEntry, BOOL bMgm ) { Trace0(ENTER1, "Entering _DeleteSourceEntry()"); RemoveEntryList(&pSourceEntry->LinkSources); RemoveEntryList(&pSourceEntry->LinkSourcesInclListSorted); if (pSourceEntry->bInV3SourcesQueryList) { RemoveEntryList(&pSourceEntry->V3SourcesQueryList); pSourceEntry->pGIEntry->V3SourcesQueryCount--; } ACQUIRE_TIMER_LOCK("_DeleteSourceEntry"); if (IS_TIMER_ACTIVE(pSourceEntry->SourceExpTimer)) RemoveTimer(&pSourceEntry->SourceExpTimer, DBG_Y); RELEASE_TIMER_LOCK("_DeleteSourceEntry"); //inclusion list if (pSourceEntry->bInclusionList) { pSourceEntry->pGIEntry->NumSources --; if (bMgm) { MGM_DELETE_GROUP_MEMBERSHIP_ENTRY( pSourceEntry->pGIEntry->pIfTableEntry, pSourceEntry->pGIEntry->NHAddr, pSourceEntry->IpAddr, 0xffffffff, pSourceEntry->pGIEntry->pGroupTableEntry->Group, 0xffffffff, MGM_JOIN_STATE_FLAG); } } // exclusion list else { // join IF in MFE if (bMgm) { MGM_ADD_GROUP_MEMBERSHIP_ENTRY( pSourceEntry->pGIEntry->pIfTableEntry, pSourceEntry->pGIEntry->NHAddr, pSourceEntry->IpAddr, 0xffffffff, pSourceEntry->pGIEntry->pGroupTableEntry->Group, 0xffffffff, MGM_FORWARD_STATE_FLAG); } } IGMP_FREE(pSourceEntry); Trace0(LEAVE1, "Leaving _DeleteSourceEntry()"); } //------------------------------------------------------------------------------ PGI_SOURCE_ENTRY GetSourceEntry( PGI_ENTRY pgie, IPADDR Source, DWORD Mode, BOOL *bCreate, DWORD Gmi, BOOL bMgm ) { PLIST_ENTRY ple, pHead; PGI_SOURCE_ENTRY pSourceEntry; DWORD Error = NO_ERROR; PIGMP_TIMER_ENTRY SourceExpTimer; Trace0(ENTER1, "Entering _GetSourceEntry()"); //deldel //DebugPrintSourcesList(pgie); //DebugPrintSourcesList1(pgie); pHead = (Mode==INCLUSION) ? &pgie->V3InclusionList[Source%SOURCES_BUCKET_SZ] : &pgie->V3ExclusionList; for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) { pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY, LinkSources); if (pSourceEntry->IpAddr > Source) break; if (pSourceEntry->IpAddr==Source) { if (bCreate) *bCreate = FALSE; return pSourceEntry; } } if (!bCreate || *bCreate==FALSE) return NULL; *bCreate = FALSE; // // create new entry // pSourceEntry = (PGI_SOURCE_ENTRY) IGMP_ALLOC(sizeof(GI_SOURCE_ENTRY), 0x800200, pgie->pIfTableEntry->IfIndex); PROCESS_ALLOC_FAILURE2(pSourceEntry, "error %d allocating %d bytes for sourceEntry", Error, sizeof(GI_SOURCE_ENTRY), return NULL; ); InsertTailList(ple, &pSourceEntry->LinkSources); InitializeListHead(&pSourceEntry->V3SourcesQueryList); pSourceEntry->pGIEntry = pgie; pSourceEntry->bInclusionList = Mode==INCLUSION; pSourceEntry->IpAddr = Source; pSourceEntry->V3SourcesQueryLeft = 0; pSourceEntry->bInV3SourcesQueryList = FALSE; pSourceEntry->SourceInListTime = GetCurrentIgmpTime(); pSourceEntry->bStaticSource = (Gmi==STATIC); // initialize SourceExpTimer SourceExpTimer = &pSourceEntry->SourceExpTimer; SourceExpTimer->Function = T_SourceExpTimer; SourceExpTimer->Context = &SourceExpTimer->Context; SourceExpTimer->Timeout = (Gmi==GMI) ? pgie->pIfTableEntry->Config.GroupMembershipTimeout : pgie->pIfTableEntry->Config.LastMemQueryInterval; SourceExpTimer->Status = TIMER_STATUS_CREATED; #if DEBUG_TIMER_TIMERID SET_TIMER_ID(SourceExpTimer, 610, pgie->pIfTableEntry->IfIndex, pgie->pGroupTableEntry->Group, Source); #endif; if (Mode==INCLUSION) { INSERT_IN_SORTED_LIST( &pgie->V3InclusionListSorted, pSourceEntry, IpAddr, GI_SOURCE_ENTRY, LinkSourcesInclListSorted ); pgie->NumSources++; } else { InitializeListHead(&pSourceEntry->LinkSourcesInclListSorted); } // insert in inclusion list and set timer. add to mgm if (Mode==INCLUSION) { // timer set only in inclusion list InsertTimer(SourceExpTimer, SourceExpTimer->Timeout, TRUE, DBG_N ); if (!pSourceEntry->bStaticSource) { // insert in sources query list if (Gmi==LMI) { InsertSourceInQueryList(pSourceEntry); } } if (bMgm) { // add (s,g) to MGM MGM_ADD_GROUP_MEMBERSHIP_ENTRY( pgie->pIfTableEntry, pgie->NHAddr, Source, 0xffffffff, pgie->pGroupTableEntry->Group, 0xffffffff, MGM_JOIN_STATE_FLAG ); } } else { if (bMgm) { // no timer set, but delete any +ve mfe MGM_DELETE_GROUP_MEMBERSHIP_ENTRY( pgie->pIfTableEntry, pgie->NHAddr, Source, 0xffffffff, pgie->pGroupTableEntry->Group, 0xffffffff, MGM_FORWARD_STATE_FLAG ); } } *bCreate = TRUE; //deldel //DebugPrintSourcesList(pgie); //DebugPrintSourcesList1(pgie); Trace0(LEAVE1, "Leaving _GetSourceEntry()"); return pSourceEntry; } //------------------------------------------------------------------------------ VOID GIDeleteAllV3Sources( PGI_ENTRY pgie, BOOL bMgm ) { PGI_SOURCE_ENTRY pSourceEntry; DWORD i; PLIST_ENTRY ple, pHead; Trace0(ENTER1, "Entering _GIDeleteAllV3Sources()"); pHead = &pgie->V3InclusionListSorted; for (ple=pHead->Flink; ple!=pHead; ) { pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY,LinkSourcesInclListSorted); ple = ple->Flink; DeleteSourceEntry(pSourceEntry, bMgm); } InitializeListHead(&pgie->V3InclusionListSorted); pHead = &pgie->V3ExclusionList; for (ple=pHead->Flink; ple!=pHead; ) { pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY, LinkSources); ple = ple->Flink; DeleteSourceEntry(pSourceEntry, bMgm); } // // dont call delete (*,G) if in exclusion mode as I want to remain in that // state // pgie->NumSources = 0; pgie->FilterType = INCLUSION; pgie->Info.LastReporter = 0; pgie->Info.GroupExpiryTime = ~0; //deldel //DebugPrintSourcesList(pgie); //DebugPrintSourcesList1(pgie); Trace0(LEAVE1, "Leaving _GIDeleteAllV3Sources()"); return; } //++------------------------------------------------------------------------------ // todo:remove 3rd field DWORD UpdateSourceExpTimer( PGI_SOURCE_ENTRY pSourceEntry, DWORD Gmi, BOOL bRemoveLastMem ) { Trace0(ENTER1, "Entering _UpdateSourceExpTimer()"); ACQUIRE_TIMER_LOCK("_UpdateSourceExpTimer"); #if DEBUG_TIMER_TIMERID pSourceEntry->SourceExpTimer.Id = 620; pSourceEntry->SourceExpTimer.Id2 = TimerId++; #endif UpdateLocalTimer(&pSourceEntry->SourceExpTimer, Gmi==GMI? GET_IF_CONFIG_FOR_SOURCE(pSourceEntry).GroupMembershipTimeout :GET_IF_CONFIG_FOR_SOURCE(pSourceEntry).LastMemQueryInterval, DBG_Y ); //remove from expiry list, and exp timer if (bRemoveLastMem && pSourceEntry->bInV3SourcesQueryList) { pSourceEntry->V3SourcesQueryLeft = 0; pSourceEntry->bInV3SourcesQueryList = FALSE; RemoveEntryList(&pSourceEntry->V3SourcesQueryList); pSourceEntry->pGIEntry->V3SourcesQueryCount--; } RELEASE_TIMER_LOCK("_UpdateSourceExpTimer"); Trace0(LEAVE1, "Entering _UpdateSourceExpTimer()"); return NO_ERROR; } //------------------------------------------------------------------------------ DWORD ChangeGroupFilterMode( PGI_ENTRY pgie, DWORD Mode ) { Trace0(ENTER1, "Entering _ChangeGroupFilterMode()"); // shift from exclusion to inclusion mode if (Mode==INCLUSION) { if (pgie->NumSources == 0) { DeleteGIEntry(pgie, TRUE, TRUE); } else { PLIST_ENTRY pHead, ple; pgie->FilterType = INCLUSION; // // remove all sources in exclusion list // pHead = &pgie->V3ExclusionList; for (ple=pHead->Flink; ple!=pHead; ) { PGI_SOURCE_ENTRY pSourceEntry; pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY, LinkSources); ple = ple->Flink; // dont have to call mgm as it will remain in -ve mfe IGMP_FREE(pSourceEntry); } InitializeListHead(&pgie->V3ExclusionList); // remove (*,g) join. the entries in inclusion list are // already joined MGM_DELETE_GROUP_MEMBERSHIP_ENTRY(pgie->pIfTableEntry, pgie->NHAddr, 0, 0, pgie->pGroupTableEntry->Group, 0xffffffff, MGM_JOIN_STATE_FLAG); } } Trace0(LEAVE1, "Leaving _ChangeGroupFilterMode()"); return NO_ERROR; } //------------------------------------------------------------------------------ // if inclusion: create source in IN_List if not found in IN_LIST // update timer if source already found // if source present in exclusion list, move it to inclusion list //------------------------------------------------------------------------------ VOID InclusionSourcesUnion( PGI_ENTRY pgie, PGROUP_RECORD pGroupRecord ) { PGI_SOURCE_ENTRY pSourceEntry; DWORD j; BOOL bCreate; Trace0(ENTER1, "Entering _InclusionSourcesUnion()"); if (pGroupRecord->NumSources==0) return; //deldel //DebugPrintSourcesList(pgie); //DebugPrintSourcesList1(pgie); for (j=0; jNumSources; j++) { //kslksl if (pGroupRecord->Sources[j]==0||pGroupRecord->Sources[j]==0xffffffff) continue; // // if in exclusion list, move it to inclusion list and continue // if static group, leave it in exclusion list // pSourceEntry = GetSourceEntry(pgie, pGroupRecord->Sources[j], EXCLUSION, NULL, 0, 0); if (pSourceEntry!=NULL && !pSourceEntry->bStaticSource) { ChangeSourceFilterMode(pgie, pSourceEntry); continue; } //deldel //DebugPrintSourcesList(pgie); //DebugPrintSourcesList1(pgie); bCreate = TRUE; pSourceEntry = GetSourceEntry(pgie, pGroupRecord->Sources[j], INCLUSION, &bCreate, GMI, MGM_YES); if (!pSourceEntry) return; // if already in IN_LIST, update source exp timer if (!bCreate) { UpdateSourceExpTimer(pSourceEntry, GMI, FALSE); } } Trace0(LEAVE1, "Leaving _InclusionSourcesUnion()"); return; } //------------------------------------------------------------------------------ // delete sources present in group record VOID SourcesSubtraction( PGI_ENTRY pgie, PGROUP_RECORD pGroupRecord, BOOL Mode ) { PGI_SOURCE_ENTRY pSourceEntry; DWORD i,j; PLIST_ENTRY pHead, ple; BOOL bFound; Trace0(ENTER1, "Entering _SourcesSubtraction()"); // note: num sources in groupRecord can be 0 // delete sources in inclusion list which are not there in the packet //deldel //DebugPrintSourcesList(pgie); //DebugPrintSourcesList1(pgie); if (Mode==INCLUSION) { pHead = &pgie->V3InclusionListSorted; for (ple=pHead->Flink; ple!=pHead; ) { pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY, LinkSourcesInclListSorted); ple = ple->Flink; for (j=0, bFound=FALSE; jNumSources; j++) { if (pSourceEntry->IpAddr == pGroupRecord->Sources[j]) { bFound = TRUE; break; } } if (!bFound) DeleteSourceEntry(pSourceEntry, MGM_YES); } } // delete sources in exclusion list which are not there in the packet else { pHead = &pgie->V3ExclusionList; for (ple=pHead->Flink; ple!=pHead; ) { pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY, LinkSources); ple = ple->Flink; for (j=0, bFound=FALSE; jNumSources; j++) { if (pSourceEntry->IpAddr == pGroupRecord->Sources[j]) { bFound = TRUE; break; } } if (!bFound){ // dont have to process in mgm. IF not in mfe anyway DeleteSourceEntry(pSourceEntry, MGM_YES); } } } //deldel //DebugPrintSourcesList(pgie); //DebugPrintSourcesList1(pgie); Trace0(LEAVE1, "Leaving _SourcesSubtraction()"); return; } //------------------------------------------------------------------------------ // intersection: rule(2) // exclusion: (7)(9) // inclusion:(4) // rule_5:(5)(10) //------------------------------------------------------------------------------ DWORD BuildAndSendSourcesQuery( PGI_ENTRY pgie, PGROUP_RECORD pGroupRecord, DWORD Type ) { PGI_SOURCE_ENTRY pSourceEntry; DWORD i,j; PLIST_ENTRY ple, pHead; BOOL bCreate; Trace0(ENTER1, "Entering _BuildAndSendSourcesQuery()"); //deldel //DebugPrintSourcesList(pgie); //DebugPrintSourcesList1(pgie); // intersection of inclusion and group record if (Type==INTERSECTION) { if (pGroupRecord->NumSources==0) return NO_ERROR; for (j=0; jNumSources; j++) { pSourceEntry = GetSourceEntry(pgie, pGroupRecord->Sources[j], INCLUSION, NULL, 0, 0); if (pSourceEntry && !pSourceEntry->bStaticSource) { InsertSourceInQueryList(pSourceEntry); } } } //add a-y to x, and query(a-y) else if (Type==EXCLUSION) { for (j=0; jNumSources; j++) { //kslksl if (pGroupRecord->Sources[j]==0||pGroupRecord->Sources[j]==0xffffffff) continue; // if found in EX list, then do nothing, else add to IN list and // send group query pSourceEntry = GetSourceEntry(pgie, pGroupRecord->Sources[j], EXCLUSION, NULL, 0, 0); if (pSourceEntry) { continue; } bCreate = TRUE; pSourceEntry = GetSourceEntry(pgie, pGroupRecord->Sources[j], INCLUSION, &bCreate, LMI, MGM_YES); if (!pSourceEntry) return ERROR_NOT_ENOUGH_MEMORY; // if created, then already in query list as time==lmi if (!bCreate && !pSourceEntry->bStaticSource) InsertSourceInQueryList(pSourceEntry); } } // send queries for all sources in inclusion list else if (Type==INCLUSION) { pHead = &pgie->V3InclusionListSorted; for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) { pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY, LinkSourcesInclListSorted); InsertSourceInQueryList(pSourceEntry); } } // send for sources in IN list but not in packet else if (Type==RULE5) { pHead = &pgie->V3InclusionListSorted; for (ple=pHead->Flink; ple!=pHead; ) { BOOL bFound; pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY, LinkSourcesInclListSorted); ple = ple->Flink; for (j=0, bFound=FALSE; jNumSources; j++) { if (pSourceEntry->IpAddr == pGroupRecord->Sources[j]) { bFound = TRUE; break; } } if (!bFound) InsertSourceInQueryList(pSourceEntry); } } if (pgie->bV3SourcesQueryNow) { SEND_SOURCES_QUERY(pgie); } //deldel //DebugPrintSourcesList(pgie); //DebugPrintSourcesList1(pgie); Trace0(LEAVE1, "Leaving _BuildAndSendSourcesQuery()"); return NO_ERROR; } //------------------------------------------------------------------------------ VOID InsertSourceInQueryList( PGI_SOURCE_ENTRY pSourceEntry ) { Trace0(ENTER1, "Entering _InsertSourceInQueryList()"); //already in sources query list. return if (pSourceEntry->bInV3SourcesQueryList) { if (QueryRemainingTime(&pSourceEntry->SourceExpTimer, 0) >GET_IF_CONFIG_FOR_SOURCE(pSourceEntry).LastMemQueryInterval) { // update exp timer to lmqi UpdateSourceExpTimer(pSourceEntry, LMI, FALSE //dont remove from last mem list ); pSourceEntry->pGIEntry->bV3SourcesQueryNow = TRUE; } return; } pSourceEntry->V3SourcesQueryLeft = GET_IF_CONFIG_FOR_SOURCE(pSourceEntry).LastMemQueryCount; // // insert in sources query list // InsertHeadList(&pSourceEntry->pGIEntry->V3SourcesQueryList, &pSourceEntry->V3SourcesQueryList); pSourceEntry->bInV3SourcesQueryList = TRUE; pSourceEntry->pGIEntry->V3SourcesQueryCount++; // update exp timer to lmqi UpdateSourceExpTimer(pSourceEntry, LMI, FALSE //dont remove from last mem list ); pSourceEntry->pGIEntry->bV3SourcesQueryNow = TRUE; Trace0(LEAVE1, "Leaving _InsertSourceInQueryList()"); return; } //------------------------------------------------------------------------------ // _MoveFromExcludeToIncludeList // EX(x,y), GrpRecord(a) -> EX(x+a,y-a), (a)=gmi // used by rules (6) and (13) //------------------------------------------------------------------------------ VOID MoveFromExcludeToIncludeList( PGI_ENTRY pgie, PGROUP_RECORD pGroupRecord ) { PGI_SOURCE_ENTRY pSourceEntry; DWORD i; IPADDR Source; Trace0(ENTER1, "Entering _MoveFromExcludeToIncludeList"); // note:all a should be in x for (i=0; iNumSources; i++) { //kslksl if (pGroupRecord->Sources[i]==0||pGroupRecord->Sources[i]==0xffffffff) continue; // // if in exclusion list remove it and place in inclusion list // Source = pGroupRecord->Sources[i]; pSourceEntry = GetSourceEntry(pgie, Source, EXCLUSION, NULL,0,0); if (pSourceEntry) { if (!pSourceEntry->bStaticSource) { ChangeSourceFilterMode(pgie, pSourceEntry); UpdateSourceExpTimer(pSourceEntry, GMI, FALSE //dont have to process lastmem list ); } } else { // not found in exclusion list, so create new entry in IN BOOL bCreate = TRUE; pSourceEntry = GetSourceEntry(pgie, Source, INCLUSION, &bCreate, GMI, MGM_YES); // entry already exists. update it if (pSourceEntry && !bCreate) { UpdateSourceExpTimer(pSourceEntry, GMI, FALSE //wont be there in lastmem list ); } } } Trace0(LEAVE1, "Leaving _MoveFromExcludeToIncludeList"); return; } //------------------------------------------------------------------------------ DWORD T_V3SourcesQueryTimer ( PVOID pvContext ) { DWORD Error=NO_ERROR; PIGMP_TIMER_ENTRY pTimer; //ptr to timer entry PGI_ENTRY pgie; //group interface entry PWORK_CONTEXT pWorkContext; PRAS_TABLE_ENTRY prte; PIF_TABLE_ENTRY pite; Trace0(ENTER1, "Entering _T_V3SourcesQueryTimer()"); // // get pointer to LastMemQueryTimer, GI entry, pite, prte // pTimer = CONTAINING_RECORD( pvContext, IGMP_TIMER_ENTRY, Context); pgie = CONTAINING_RECORD( pTimer, GI_ENTRY, V3SourcesQueryTimer); pite = pgie->pIfTableEntry; prte = pgie->pRasTableEntry; Trace2(TIMER, "_T_V3SourcesQueryTimer() called for If(%0x), Group(%d.%d.%d.%d)", pite->IfIndex, PRINT_IPADDR(pgie->pGroupTableEntry->Group)); // // if GI or pite or prte has flag already set, then exit // if ( (pgie->Status&DELETED_FLAG) || (pite->Status&DELETED_FLAG) ) return NO_ERROR; if ( (prte!=NULL) && (prte->Status&DELETED_FLAG) ) return NO_ERROR; if (pgie->Version!=3) return NO_ERROR; // // queue work item for sending the Sources query even if the router // is not a Querier // CREATE_WORK_CONTEXT(pWorkContext, Error); if (Error!=NO_ERROR) { return ERROR_CAN_NOT_COMPLETE; } pWorkContext->IfIndex = pite->IfIndex; pWorkContext->Group = pgie->pGroupTableEntry->Group; pWorkContext->NHAddr = pgie->NHAddr; //valid only for ras: should i use it? pWorkContext->WorkType = MSG_SOURCES_QUERY; Trace0(WORKER, "Queueing WF_TimerProcessing() to send SourcesQuery:"); if (QueueIgmpWorker(WF_TimerProcessing, (PVOID)pWorkContext)!=NO_ERROR) IGMP_FREE(pWorkContext); Trace0(LEAVE1, "Leaving _T_V3SourcesQueryTimer()"); return NO_ERROR; } //------------------------------------------------------------------------------ // _T_LastVer2ReportTimer // // For this GI entry, the last ver-1 report has timed out. Change to ver-3 if // the interface is set to ver-3. // Locks: Assumes timer lock. //------------------------------------------------------------------------------ DWORD T_LastVer2ReportTimer ( PVOID pvContext ) { PIGMP_TIMER_ENTRY pTimer; //ptr to timer entry PGI_ENTRY pgie; //group interface entry PIF_TABLE_ENTRY pite; LONGLONG llCurTime = GetCurrentIgmpTime(); Trace0(ENTER1, "Entering _T_LastVer2ReportTimer()"); // // get pointer to LastMemQueryTimer, GI entry, pite // pTimer = CONTAINING_RECORD( pvContext, IGMP_TIMER_ENTRY, Context); pgie = CONTAINING_RECORD( pTimer, GI_ENTRY, LastVer2ReportTimer); pite = pgie->pIfTableEntry; Trace2(TIMER, "T_LastVer2ReportTimer() called for If(%0x), Group(%d.%d.%d.%d)", pite->IfIndex, PRINT_IPADDR(pgie->pGroupTableEntry->Group)); // set the state to ver-3, if ver1 time not active if (IS_PROTOCOL_TYPE_IGMPV3(pite) && !IS_TIMER_ACTIVE(pgie->LastVer1ReportTimer)) { PWORK_CONTEXT pWorkContext; DWORD Error=NO_ERROR; // // queue work item for shifting to v3 for that group // CREATE_WORK_CONTEXT(pWorkContext, Error); if (Error!=NO_ERROR) { return ERROR_CAN_NOT_COMPLETE; } pWorkContext->IfIndex = pite->IfIndex; pWorkContext->Group = pgie->pGroupTableEntry->Group; pWorkContext->NHAddr = pgie->NHAddr; //valid only for ras: should i us pWorkContext->WorkType = SHIFT_TO_V3; Trace0(WORKER, "Queueing WF_TimerProcessing() to shift to v3"); if (QueueIgmpWorker(WF_TimerProcessing, (PVOID)pWorkContext)!=NO_ERROR) IGMP_FREE(pWorkContext); } Trace0(LEAVE1, "Leaving _T_LastVer2ReportTimer()"); return NO_ERROR; } //------------------------------------------------------------------------------ DWORD T_SourceExpTimer ( PVOID pvContext ) { PIGMP_TIMER_ENTRY pTimer; //ptr to timer entry PGI_ENTRY pgie; //group interface entry PGI_SOURCE_ENTRY pSourceEntry; PWORK_CONTEXT pWorkContext; DWORD Error=NO_ERROR; Trace0(ENTER1, "Entering _T_SourceExpTimer()"); pTimer = CONTAINING_RECORD( pvContext, IGMP_TIMER_ENTRY, Context); pSourceEntry = CONTAINING_RECORD(pTimer, GI_SOURCE_ENTRY, SourceExpTimer); pgie = pSourceEntry->pGIEntry; //IN entry. delete it if (pSourceEntry->bInclusionList) { CREATE_WORK_CONTEXT(pWorkContext, Error); if (Error!=NO_ERROR) return Error; pWorkContext->IfIndex = pgie->pIfTableEntry->IfIndex; pWorkContext->NHAddr = pgie->NHAddr; pWorkContext->Group = pgie->pGroupTableEntry->Group; pWorkContext->Source = pSourceEntry->IpAddr; pWorkContext->WorkType = (pgie->FilterType==INCLUSION) ? DELETE_SOURCE : MOVE_SOURCE_TO_EXCL; Trace0(WORKER, "_T_SourceExpTimer queued _WF_TimerProcessing:"); if (QueueIgmpWorker(WF_TimerProcessing, (PVOID)pWorkContext)!=NO_ERROR) IGMP_FREE(pWorkContext); } Trace0(LEAVE1, "Leaving _T_SourceExpTimer()"); return NO_ERROR; } #if DEBUG_FLAGS_MEM_ALLOC LIST_ENTRY g_MemoryList; CRITICAL_SECTION g_MemCS; PVOID IgmpDebugAlloc( DWORD sz, DWORD Flags, DWORD Id, DWORD IfIndex ) { static DWORD Initialize = TRUE; PMEM_HDR Ptr; if (Initialize) { InitializeListHead(&g_MemoryList); try { InitializeCriticalSection(&g_MemCS); } except (EXCEPTION_EXECUTE_HANDLER) { return NULL; } Initialize = FALSE; } // allign for 64 bit sz = (sz + 63) & 0xFFFFFFc0; Ptr = (PMEM_HDR)HeapAlloc(g_Heap,Flags,(sz)+sizeof(MEM_HDR)+sizeof(DWORD)); if (Ptr==NULL) return NULL; // Trace1(ERR, "----- alloc:%0x", (ULONG_PTR)Ptr); EnterCriticalSection(&g_MemCS); Ptr->Signature = 0xabcdefaa; Ptr->IfIndex = IfIndex; Ptr->Tail = (PDWORD)((PCHAR)Ptr + sz + sizeof(MEM_HDR)); *Ptr->Tail = 0xabcdefbb; Ptr->Id = Id; InsertHeadList(&g_MemoryList, &Ptr->Link); LeaveCriticalSection(&g_MemCS); Trace1(KSL, "Alloc heap:%0x", PtrToUlong(((PCHAR)Ptr+sizeof(MEM_HDR))));//deldel return (PVOID)((PCHAR)Ptr+sizeof(MEM_HDR)); } VOID IgmpDebugFree( PVOID mem ) { PMEM_HDR Ptr = (PMEM_HDR)((PCHAR)mem - sizeof(MEM_HDR)); if (Ptr->Signature != 0xabcdefaa) { DbgBreakPoint(); Trace2(KSL, "\n=======================\n" "Freeing Invalid memory:%0x:Id:%0x\n", (ULONG_PTR)Ptr, Ptr->Id); } if (*Ptr->Tail != 0xabcdefbb) { DbgBreakPoint(); Trace2(KSL, "\n=======================\n" "Freeing Invalid memory:Tail corrupted:%0x:Id:%0x\n", (ULONG_PTR)Ptr, Ptr->Id); } EnterCriticalSection(&g_MemCS); Ptr->Signature = 0xaafedcba; *Ptr->Tail = 0xbbfedcba; RemoveEntryList(&Ptr->Link); LeaveCriticalSection(&g_MemCS); Trace1(KSL, "Freed heap:%0x", PtrToUlong(mem));//deldel HeapFree(g_Heap, 0, Ptr); } VOID DebugScanMemoryInterface( DWORD IfIndex ) { PMEM_HDR Ptr; PLIST_ENTRY ple; DWORD Count=0; Trace0(ENTER1, "InDebugScanMemoryInterface"); EnterCriticalSection(&g_MemCS); for (ple=g_MemoryList.Flink; ple!=&g_MemoryList; ple=ple->Flink) { Ptr = CONTAINING_RECORD(ple, MEM_HDR, Link); if (Ptr->IfIndex==IfIndex) { if (Count++==0) Trace1(ERR, "\n\nMEMORY checking for interface: %0x", IfIndex); Trace2(ERR, "MEMORY: %0x Id:%0x", (ULONG_PTR)Ptr, Ptr->Id); } } if (Count!=0) { Trace0(ERR, "\n\n"); DbgBreakPoint(); } LeaveCriticalSection(&g_MemCS); } VOID DebugScanMemory( ) { PMEM_HDR Ptr; PLIST_ENTRY ple; Trace0(ENTER1, "InDebugScanMemory"); EnterCriticalSection(&g_MemCS); for (ple=g_MemoryList.Flink; ple!=&g_MemoryList; ple=ple->Flink) { Ptr = CONTAINING_RECORD(ple, MEM_HDR, Link); Trace2(ERR, "MEMORY: %0x Id:%0x", (ULONG_PTR)Ptr, Ptr->Id); } if (!(IsListEmpty(&g_MemoryList))) { DbgBreakPoint(); } DeleteCriticalSection(&g_MemCS); } #endif