You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2481 lines
77 KiB
2481 lines
77 KiB
#include "pchigmp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
//deldel
|
|
#define PRINT_SOURCES_LIST 1
|
|
|
|
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))
|
|
IgmpDbgBreakPoint();
|
|
|
|
if (ple->Flink!=pHead) {
|
|
pSourceEntry2 = CONTAINING_RECORD(ple->Flink, GI_SOURCE_ENTRY,LinkSourcesInclListSorted);
|
|
if (pSourceEntry2->IpAddr==pSourceEntry->IpAddr)
|
|
IgmpDbgBreakPoint();
|
|
}
|
|
}
|
|
|
|
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)
|
|
IgmpDbgBreakPoint();
|
|
}
|
|
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, Error=NO_ERROR,
|
|
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)))
|
|
{
|
|
if (pHdr->Group == ALL_ROUTERS_MCAST && (LOCAL_MCAST_GROUP(pHdr->Group)))
|
|
return NO_ERROR;
|
|
|
|
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, SourceCount=0; //deldel remove sourcecount
|
|
|
|
// 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++)
|
|
{
|
|
if (pGroupRecord->Sources[j]==0
|
|
|| pGroupRecord->Sources[j]==~0)
|
|
{
|
|
Trace1(ERR, "Received invalid packet with source %d.%d.%d.%d",
|
|
PRINT_IPADDR(pGroupRecord->Sources[j]));
|
|
Error = ERROR_BAD_FORMAT;
|
|
|
|
//IgmpDbgBreakPoint(); //kslksl
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
Trace1(RECEIVE, " %d.%d.%d.%d",
|
|
PRINT_IPADDR(pGroupRecord->Sources[j]));
|
|
}
|
|
|
|
//
|
|
// error if ssm-exclude mode
|
|
// local groups will be ignored later
|
|
//
|
|
if (SSM_MCAST_GROUP(pGroupRecord->Group)
|
|
&& (pGroupRecord->RecordType == IS_EX
|
|
|| pGroupRecord->RecordType == TO_EX) )
|
|
{
|
|
Trace3(ERR,
|
|
"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));
|
|
Error = ERROR_BAD_FORMAT;
|
|
IgmpDbgBreakPoint(); //kslksl
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
|
|
pGroupRecord = (PGROUP_RECORD)
|
|
&(pGroupRecord->Sources[pGroupRecord->NumSources]);
|
|
|
|
}
|
|
} END_BREAKOUT_BLOCK1;
|
|
|
|
if (i!=NumGroupRecords || PacketSize>InPacketSize) {
|
|
if (Error == ERROR_BAD_FORMAT)
|
|
{
|
|
Trace0(ERR, "Received invalid packet");
|
|
}
|
|
else
|
|
{
|
|
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 group, then skip it.
|
|
|
|
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))
|
|
{
|
|
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,Count++){
|
|
pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY, V3SourcesQueryList);
|
|
Trace1(SOURCES, "%d.%d.%d.%d source in query list",
|
|
PRINT_IPADDR(pSourceEntry->IpAddr));
|
|
if (Count>300) IgmpDbgBreakPoint(); //deldel
|
|
}
|
|
}
|
|
|
|
|
|
pHead = &pgie->V3ExclusionList;
|
|
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink,Count++) {
|
|
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
|
|
);
|
|
if (Count>300) IgmpDbgBreakPoint();
|
|
}
|
|
|
|
|
|
pHead = &pgie->V3InclusionListSorted;
|
|
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink,Count++) {
|
|
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
|
|
);
|
|
if (Count>300) IgmpDbgBreakPoint();
|
|
}
|
|
|
|
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));
|
|
}
|
|
IgmpDbgBreakPoint();
|
|
}
|
|
}
|
|
|
|
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
|
|
);
|
|
IgmpDbgBreakPoint();
|
|
}
|
|
}
|
|
|
|
|
|
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
|
|
);
|
|
}
|
|
|
|
IgmpDbgBreakPoint();
|
|
}
|
|
|
|
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 ++;
|
|
|
|
// set the timeout value for source in inc mode
|
|
|
|
ACQUIRE_TIMER_LOCK("_ChangeSourceFilterMode");
|
|
#if DEBUG_TIMER_TIMERID
|
|
SET_TIMER_ID((&pSourceEntry->SourceExpTimer), 611, pgie->pIfTableEntry->IfIndex,
|
|
pgie->pGroupTableEntry->Group, pSourceEntry->IpAddr);
|
|
#endif;
|
|
InsertTimer(&pSourceEntry->SourceExpTimer,
|
|
pSourceEntry->SourceExpTimer.Timeout,
|
|
TRUE, DBG_N
|
|
);
|
|
RELEASE_TIMER_LOCK("_ChangeSourceFilterMode");
|
|
|
|
|
|
// 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);
|
|
|
|
if (pSourceEntry->bInclusionList) {
|
|
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
|
|
ACQUIRE_TIMER_LOCK("_GetSourceEntry");
|
|
InsertTimer(SourceExpTimer,
|
|
SourceExpTimer->Timeout,
|
|
TRUE, DBG_N
|
|
);
|
|
RELEASE_TIMER_LOCK("_GetSourceEntry");
|
|
|
|
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;
|
|
}
|
|
|
|
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()");
|
|
//deldel
|
|
//DebugPrintSourcesList(pgie);
|
|
//DebugPrintSourcesList1(pgie);
|
|
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;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Dont delete timer or update other timers...
|
|
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.
|
|
// Dont delete timer or update other timers...
|
|
//------------------------------------------------------------------------------
|
|
|
|
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;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Dont delete timer or update other timers...
|
|
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 g_MemoryLast;
|
|
|
|
|
|
PVOID
|
|
IgmpDebugAlloc(
|
|
DWORD sz,
|
|
DWORD Flags,
|
|
DWORD Id,
|
|
DWORD IfIndex
|
|
)
|
|
{
|
|
static DWORD Initialize = TRUE;
|
|
PMEM_HDR Ptr;
|
|
|
|
if (Initialize) {
|
|
DWORD Tmp;
|
|
Tmp = InterlockedExchange(&Initialize, FALSE);
|
|
if (Tmp)
|
|
{
|
|
InitializeListHead(&g_MemoryList);
|
|
try {
|
|
InitializeCriticalSection(&g_MemCS);
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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);
|
|
g_MemoryLast = Ptr;
|
|
|
|
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));
|
|
|
|
Trace1(KSL, "Freed heap:%0x", PtrToUlong(mem));//deldel
|
|
|
|
if (Ptr->Signature != 0xabcdefaa) {
|
|
DbgBreakPoint(); //deldel
|
|
Trace2(KSL, "\n=======================\n"
|
|
"Freeing Invalid memory:%0x:Id:%0x\n", (ULONG_PTR)Ptr, Ptr->Id);
|
|
return;
|
|
}
|
|
if (*Ptr->Tail != 0xabcdefbb) {
|
|
DbgBreakPoint(); //deldel
|
|
Trace2(KSL, "\n=======================\n"
|
|
"Freeing Invalid memory:Tail corrupted:%0x:Id:%0x\n", (ULONG_PTR)Ptr, Ptr->Id);
|
|
return;
|
|
}
|
|
|
|
EnterCriticalSection(&g_MemCS);
|
|
Ptr->Signature = 0xaafedcba;
|
|
*Ptr->Tail = 0xbbfedcba;
|
|
RemoveEntryList(&Ptr->Link);
|
|
LeaveCriticalSection(&g_MemCS);
|
|
|
|
|
|
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");
|
|
IgmpDbgBreakPoint();
|
|
}
|
|
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))) {
|
|
IgmpDbgBreakPoint();
|
|
}
|
|
|
|
DeleteCriticalSection(&g_MemCS);
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|