windows-nt/Source/XPSP1/NT/net/rras/ip/igmp/work1.c

2420 lines
73 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
#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 (InPacketSize<sizeof(IGMP_HEADER)+sizeof(IGMP_HEADER_V3_EXT)) {
Trace0(RECEIVE,
"Group-specific-query dropped. Invalid packet size");
return ERROR_CAN_NOT_COMPLETE;
}
pSourcesRecord = (PIGMP_HEADER_V3_EXT)(pHdr+1);
//convert to host order
pSourcesRecord->NumSources = ntohs(pSourcesRecord->NumSources);
if (InPacketSize<sizeof(IGMP_HEADER)+sizeof(IGMP_HEADER_V3_EXT)
+ pSourcesRecord->NumSources*sizeof(IPADDR))
{
Trace0(RECEIVE,
"Group-specific-query dropped. Invalid packet size");
return ERROR_CAN_NOT_COMPLETE;
}
for (i=0; i<pSourcesRecord->NumSources; 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.Timeout<llCurTime) )
{
//DeleteGIEntry(pgie, TRUE);
GOTO_END_BLOCK1;
}
//
// if currently processing a leave then remove LeaveTimer if received
// LastMemquery from lower Ip, else ignore the LastMemQuery
//
if (pgie->LastMemQueryCount>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; i<pSourcesRecord->NumSources; 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 (; i<NumGroupRecords; i++) {
DWORD j;
// convert to host order
pGroupRecord->NumSources = 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; j<pGroupRecord->NumSources; 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 (PacketSize<InPacketSize){
Trace0(ERR, "Received IGMP-v3 report large size");
InterlockedIncrement(&pite->Info.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; i<NumGroupRecords; i++) {
Group = (PktVersion==3)? pGroupRecord->Group : 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; i<pGroupRecord->NumSources; 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; j<pGroupRecord->NumSources; 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; j<pGroupRecord->NumSources; 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; j<pGroupRecord->NumSources; 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; j<pGroupRecord->NumSources; 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; j<pGroupRecord->NumSources; 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; j<pGroupRecord->NumSources; 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; j<pGroupRecord->NumSources; 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; j<pGroupRecord->NumSources; 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; j<pGroupRecord->NumSources; 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; i<pGroupRecord->NumSources; 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