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.
1286 lines
42 KiB
1286 lines
42 KiB
//=============================================================================
|
|
// Copyright (c) 1997 Microsoft Corporation
|
|
// File Name: mgmigmp.c
|
|
//
|
|
// Abstract:
|
|
// This file the calls and callbacks with respect to mgm
|
|
//
|
|
// Author: K.S.Lokesh (lokeshs@) 11-1-97
|
|
//=============================================================================
|
|
|
|
#include "pchigmp.h"
|
|
#pragma hdrstop
|
|
|
|
VOID
|
|
DebugPrintProxyGroupTable (
|
|
);
|
|
|
|
|
|
|
|
#define DISABLE_FLAG 0
|
|
#define ENABLE_FLAG 1
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _MgmDisableIgmprtrCallback
|
|
//
|
|
// This call is made by mgm to igmp. After this call, till igmp is enabled
|
|
// again, no more AddMembership calls will be made to Mgm. However, igmp
|
|
// will be owning the interface and will be functioning normally.
|
|
//------------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
MgmDisableIgmprtrCallback(
|
|
DWORD IfIndex,
|
|
DWORD NHAddr //not used
|
|
)
|
|
{
|
|
return MgmChangeIgmprtrStatus(IfIndex, DISABLE_FLAG);
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _MgmEnableIgmprtrCallback
|
|
//
|
|
// This call is made by mgm to igmprtr. igmprtr should refresh all group joins.
|
|
//------------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
MgmEnableIgmprtrCallback(
|
|
DWORD IfIndex,
|
|
DWORD NHAddr //not used
|
|
)
|
|
{
|
|
return MgmChangeIgmprtrStatus(IfIndex, ENABLE_FLAG);
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// MgmChangeIgmprtrStatus
|
|
//------------------------------------------------------------------------------
|
|
DWORD
|
|
MgmChangeIgmprtrStatus (
|
|
DWORD IfIndex,
|
|
BOOL Flag
|
|
)
|
|
{
|
|
PIF_TABLE_ENTRY pite;
|
|
DWORD Error=NO_ERROR, dwRetval;
|
|
BOOL PrevCanAddGroupsToMgm;
|
|
|
|
|
|
if (!EnterIgmpApi()) { return ERROR_CAN_NOT_COMPLETE; }
|
|
Trace0(ENTER1, "Entering MgmDisableIgmpCallback");
|
|
|
|
|
|
ACQUIRE_IF_LOCK_EXCLUSIVE(IfIndex, "MgmDisableIgmpCallback");
|
|
|
|
BEGIN_BREAKOUT_BLOCK1 {
|
|
|
|
//
|
|
// retrieve the interface entry
|
|
//
|
|
pite = GetIfByIndex(IfIndex);
|
|
|
|
|
|
//
|
|
// return error if interface does not exist, or it is not activated
|
|
// or is already in that state
|
|
//
|
|
if ( (pite == NULL)||(!IS_IF_ACTIVATED(pite))
|
|
|| ((Flag==ENABLE_FLAG)&&(IS_IGMPRTR_ENABLED_BY_MGM(pite)))
|
|
|| ((Flag==DISABLE_FLAG)&&(!IS_IGMPRTR_ENABLED_BY_MGM(pite)))
|
|
)
|
|
{
|
|
if (Flag==ENABLE_FLAG) {
|
|
Trace1(ERR,
|
|
"MgmEnableIgmpCallback(): interface:%0x nonexistant or active",
|
|
IfIndex);
|
|
IgmpAssertOnError(FALSE);
|
|
}
|
|
else {
|
|
Trace1(ERR,
|
|
"MgmDisableIgmpCallback(): interface:%0x nonexistant or inactive",
|
|
IfIndex);
|
|
IgmpAssertOnError(FALSE);
|
|
}
|
|
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
|
|
|
|
PrevCanAddGroupsToMgm = CAN_ADD_GROUPS_TO_MGM(pite);
|
|
|
|
|
|
if (Flag==ENABLE_FLAG) {
|
|
DWORD dwProtoId, dwComponentId;
|
|
|
|
// set the status field to enabled.
|
|
MGM_ENABLE_IGMPRTR(pite);
|
|
|
|
MgmGetProtocolOnInterface(IfIndex, 0, &dwProtoId, &dwComponentId);
|
|
|
|
if (dwProtoId!=PROTO_IP_IGMP)
|
|
SET_MPROTOCOL_PRESENT_ON_IGMPRTR(pite);
|
|
|
|
}
|
|
else {
|
|
// set the flag to disabled and also reset MProtocol present field
|
|
MGM_DISABLE_IGMPRTR(pite);
|
|
|
|
}
|
|
|
|
if (PrevCanAddGroupsToMgm && !CAN_ADD_GROUPS_TO_MGM(pite))
|
|
Trace1(MGM, "Igmp Router stop propagating groups to MGM on If:%0x",
|
|
IfIndex);
|
|
|
|
if (!PrevCanAddGroupsToMgm && CAN_ADD_GROUPS_TO_MGM(pite))
|
|
Trace1(MGM, "Igmp Router start propagating groups to MGM on If:%0x",
|
|
IfIndex);
|
|
|
|
|
|
//
|
|
// for all the groups for this interface, call MgmDeleteGroupMembershipEntry
|
|
//
|
|
|
|
if (CAN_ADD_GROUPS_TO_MGM(pite)) {
|
|
|
|
if (Flag==ENABLE_FLAG)
|
|
RefreshMgmIgmprtrGroups(pite, ADD_FLAG);
|
|
else
|
|
RefreshMgmIgmprtrGroups(pite, DELETE_FLAG);
|
|
|
|
}
|
|
|
|
|
|
|
|
} END_BREAKOUT_BLOCK1;
|
|
|
|
|
|
RELEASE_IF_LOCK_EXCLUSIVE(IfIndex, "MgmDisableIgmpCallback");
|
|
|
|
Trace1(LEAVE1, "Leaving MgmDisableIgmpCallback(%d)", Error);
|
|
LeaveIgmpApi();
|
|
return Error;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// RefreshMgmIgmprtrGroups
|
|
//------------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
RefreshMgmIgmprtrGroups (
|
|
PIF_TABLE_ENTRY pite,
|
|
BOOL Flag
|
|
)
|
|
{
|
|
PLIST_ENTRY pHead, ple;
|
|
PGI_ENTRY pgie;
|
|
DWORD Error=NO_ERROR;
|
|
PGI_SOURCE_ENTRY pSourceEntry;
|
|
|
|
|
|
ACQUIRE_ENUM_LOCK_EXCLUSIVE("_RefreshMgmIgmprtrGroups");
|
|
ACQUIRE_IF_GROUP_LIST_LOCK(pite->IfIndex, "_RefreshMgmIgmprtrGroups");
|
|
|
|
pHead = &pite->ListOfSameIfGroups;
|
|
|
|
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
|
|
|
|
pgie = CONTAINING_RECORD(ple, GI_ENTRY, LinkBySameIfGroups);
|
|
|
|
|
|
if (Flag==ADD_FLAG) {
|
|
|
|
if (pgie->Version==1 || pgie->Version==2
|
|
|| (pgie->Version==3 && pgie->FilterType==EXCLUSION) )
|
|
{
|
|
MGM_ADD_GROUP_MEMBERSHIP_ENTRY(pite, pgie->NHAddr, 0, 0,
|
|
pgie->pGroupTableEntry->Group,
|
|
0xffffffff, MGM_JOIN_STATE_FLAG);
|
|
}
|
|
else {//ver3 inclusion
|
|
|
|
PLIST_ENTRY pSourceHead, pSourceLE;
|
|
|
|
pSourceHead = &pgie->V3InclusionListSorted;
|
|
for (pSourceLE=pSourceHead->Flink; pSourceLE!=pSourceHead;
|
|
pSourceLE=pSourceLE->Flink)
|
|
{
|
|
pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY, LinkSourcesInclListSorted);
|
|
MGM_ADD_GROUP_MEMBERSHIP_ENTRY(pite, pgie->NHAddr, pSourceEntry->IpAddr, 0xffffffff,
|
|
pgie->pGroupTableEntry->Group,
|
|
0xffffffff, MGM_JOIN_STATE_FLAG);
|
|
}
|
|
|
|
}
|
|
}
|
|
else {
|
|
|
|
if (pgie->Version==1 || pgie->Version==2
|
|
|| (pgie->Version==3 && pgie->FilterType==EXCLUSION) )
|
|
{
|
|
MGM_DELETE_GROUP_MEMBERSHIP_ENTRY(pite, pgie->NHAddr, 0, 0,
|
|
pgie->pGroupTableEntry->Group,
|
|
0xffffffff, MGM_JOIN_STATE_FLAG);
|
|
}
|
|
else {//ver3 inclusion
|
|
|
|
PLIST_ENTRY pSourceHead, pSourceLE;
|
|
|
|
pSourceHead = &pgie->V3InclusionListSorted;
|
|
for (pSourceLE=pSourceHead->Flink; pSourceLE!=pSourceHead;
|
|
pSourceLE=pSourceLE->Flink)
|
|
{
|
|
pSourceEntry = CONTAINING_RECORD(ple, GI_SOURCE_ENTRY, LinkSourcesInclListSorted);
|
|
MGM_DELETE_GROUP_MEMBERSHIP_ENTRY(pite, pgie->NHAddr,
|
|
pSourceEntry->IpAddr, 0xffffffff,
|
|
pgie->pGroupTableEntry->Group, 0xffffffff, MGM_JOIN_STATE_FLAG);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
RELEASE_ENUM_LOCK_EXCLUSIVE("_RefreshMgmIgmprtrGroups");
|
|
RELEASE_IF_GROUP_LIST_LOCK(pite->IfIndex, "_RefreshMgmIgmprtrGroups");
|
|
|
|
|
|
return Error;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// RegisterProtocolWithMgm
|
|
//------------------------------------------------------------------------------
|
|
DWORD
|
|
RegisterProtocolWithMgm(
|
|
DWORD ProxyOrRouter
|
|
)
|
|
{
|
|
DWORD Error=NO_ERROR;
|
|
ROUTING_PROTOCOL_CONFIG rpiInfo; //for mgm
|
|
|
|
|
|
// register router with mgm
|
|
|
|
if (ProxyOrRouter==PROTO_IP_IGMP) {
|
|
|
|
ZeroMemory(&rpiInfo, sizeof(rpiInfo));
|
|
rpiInfo.dwCallbackFlags = 0;
|
|
rpiInfo.pfnRpfCallback
|
|
= (PMGM_RPF_CALLBACK)IgmpRpfCallback;
|
|
rpiInfo.pfnCreationAlertCallback
|
|
= (PMGM_CREATION_ALERT_CALLBACK)IgmpRtrCreationAlertCallback;
|
|
rpiInfo.pfnPruneAlertCallback
|
|
= NULL;
|
|
rpiInfo.pfnJoinAlertCallback
|
|
= NULL;
|
|
rpiInfo.pfnWrongIfCallback
|
|
= NULL;
|
|
rpiInfo.pfnLocalJoinCallback
|
|
= NULL;
|
|
rpiInfo.pfnLocalLeaveCallback
|
|
= NULL;
|
|
rpiInfo.pfnEnableIgmpCallback
|
|
= MgmEnableIgmprtrCallback;
|
|
|
|
rpiInfo.pfnDisableIgmpCallback
|
|
= MgmDisableIgmprtrCallback;
|
|
|
|
|
|
|
|
Error = MgmRegisterMProtocol( &rpiInfo, PROTO_IP_IGMP, IGMP_ROUTER_V2,
|
|
&g_MgmIgmprtrHandle);
|
|
if (Error!=NO_ERROR) {
|
|
Trace1(ERR, "Error:%d registering IGMP Router with MGM", Error);
|
|
IgmpAssertOnError(FALSE);
|
|
Logerr0(MGM_REGISTER_FAILED, Error);
|
|
return Error;
|
|
}
|
|
}
|
|
|
|
// register proxy with mgm
|
|
|
|
else {
|
|
|
|
//
|
|
// register Igmp proxy with MGM. I register Proxy irrespective of whether
|
|
// this router might be setup as a proxy or not.
|
|
//
|
|
|
|
rpiInfo.dwCallbackFlags = 0;
|
|
rpiInfo.pfnRpfCallback
|
|
= (PMGM_RPF_CALLBACK)ProxyRpfCallback;
|
|
rpiInfo.pfnCreationAlertCallback
|
|
= (PMGM_CREATION_ALERT_CALLBACK)ProxyCreationAlertCallback;
|
|
rpiInfo.pfnPruneAlertCallback
|
|
= (PMGM_PRUNE_ALERT_CALLBACK)ProxyPruneAlertCallback;
|
|
rpiInfo.pfnJoinAlertCallback
|
|
= (PMGM_JOIN_ALERT_CALLBACK)ProxyJoinAlertCallback;
|
|
rpiInfo.pfnWrongIfCallback
|
|
= NULL;
|
|
rpiInfo.pfnLocalJoinCallback
|
|
= NULL;
|
|
rpiInfo.pfnLocalLeaveCallback
|
|
= NULL;
|
|
|
|
|
|
Error = MgmRegisterMProtocol( &rpiInfo, PROTO_IP_IGMP_PROXY, IGMP_PROXY,
|
|
&g_MgmProxyHandle);
|
|
|
|
if (Error!=NO_ERROR) {
|
|
Trace1(ERR, "Error:%d registering Igmp Proxy with Mgm", Error);
|
|
IgmpAssertOnError(FALSE);
|
|
Logerr0(MGM_PROXY_REGISTER_FAILED, Error);
|
|
return Error;
|
|
}
|
|
}
|
|
|
|
return Error;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// IgmpRpfCallback
|
|
//------------------------------------------------------------------------------
|
|
DWORD
|
|
IgmpRpfCallback (
|
|
DWORD dwSourceAddr,
|
|
DWORD dwSourceMask,
|
|
DWORD dwGroupAddr,
|
|
DWORD dwGroupMask,
|
|
PDWORD dwInIfIndex,
|
|
PDWORD dwInIfNextHopAddr,
|
|
PDWORD dwUpstreamNeighbor,
|
|
DWORD dwHdrSize,
|
|
PBYTE pbPacketHdr,
|
|
PBYTE pbBuffer
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Called by MGM when a packet is received on an interface owned by Igmp to see
|
|
if it can go ahead and create an MFE. Igmp does an Rpf check with RTM
|
|
and returns the value. No check is done to see if the interface is really
|
|
owned by igmp. It doesnt matter if the interface is activated or not.
|
|
--*/
|
|
{
|
|
DWORD Error = NO_ERROR;
|
|
|
|
#if RTMv2
|
|
return Error;
|
|
#else
|
|
|
|
|
|
PRTM_IP_ROUTE prirRpfRoute = (PRTM_IP_ROUTE) pbBuffer;
|
|
|
|
// enterIgmpApi not required, as this call cannot be made when igmp is not up
|
|
|
|
//
|
|
// Perform Rpf check with Rtm
|
|
//
|
|
if (RtmLookupIPDestination(dwSourceAddr, prirRpfRoute)==TRUE) {
|
|
|
|
if (prirRpfRoute->RR_InterfaceID!=*dwInIfIndex) {
|
|
|
|
*dwInIfIndex = prirRpfRoute->RR_InterfaceID;
|
|
|
|
// the route was found, but the interface is incorrect
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else {
|
|
// rpf check successful
|
|
Error = NO_ERROR;
|
|
}
|
|
}
|
|
else {
|
|
// route not found
|
|
Error = ERROR_NOT_FOUND;
|
|
}
|
|
|
|
Trace4(MGM,
|
|
"Rpf callback for MGroup(%d.%d.%d.%d) Src(%d.%d.%d.%d) IncomingIf(%0x):%d",
|
|
PRINT_IPADDR(dwGroupAddr), PRINT_IPADDR(dwSourceAddr), *dwInIfIndex, Error);
|
|
|
|
|
|
return Error;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// ProxyRpfCallback
|
|
//------------------------------------------------------------------------------
|
|
DWORD
|
|
ProxyRpfCallback (
|
|
DWORD dwSourceAddr,
|
|
DWORD dwSourceMask,
|
|
DWORD dwGroupAddr,
|
|
DWORD dwGroupMask,
|
|
DWORD *dwInIfIndex,
|
|
DWORD *dwInIfNextHopAddr,
|
|
DWORD *dwUpstreamNeighbor,
|
|
DWORD dwHdrSize,
|
|
PBYTE pbPacketHdr,
|
|
PBYTE pbBuffer
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Called by MGM when a packet is received on an interface owned by Proxy to see
|
|
if it can go ahead and create an MFE. Proxy does an Rpf check with RTM
|
|
and returns the value. No check is done to see if the interface is really
|
|
owned by igmp. It doesnt matter if the interface is activated or not.
|
|
--*/
|
|
{
|
|
DWORD Error = NO_ERROR;
|
|
|
|
#if RTMv2
|
|
return Error;
|
|
#else
|
|
// enterIgmpApi not required, as this call cannot be made when igmp is not up
|
|
|
|
|
|
PRTM_IP_ROUTE prirRpfRoute = (PRTM_IP_ROUTE) pbBuffer;
|
|
|
|
//
|
|
// Perform Rpf check with Rtm
|
|
//
|
|
if (RtmLookupIPDestination(dwSourceAddr, prirRpfRoute)==TRUE) {
|
|
|
|
if (prirRpfRoute->RR_InterfaceID!=*dwInIfIndex) {
|
|
|
|
*dwInIfIndex = prirRpfRoute->RR_InterfaceID;
|
|
|
|
|
|
// the route was found, but the interface is incorrect
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
else {
|
|
// rpf check successful
|
|
Error = NO_ERROR;
|
|
}
|
|
}
|
|
else {
|
|
// route not found
|
|
Error = ERROR_NOT_FOUND;
|
|
}
|
|
|
|
Trace4(MGM,
|
|
"Rpf callback for MGroup(%d.%d.%d.%d) Src(%d.%d.%d.%d) IncomingIf(%0x):%d",
|
|
PRINT_IPADDR(dwGroupAddr), PRINT_IPADDR(dwSourceAddr), *dwInIfIndex, Error);
|
|
|
|
|
|
return Error;
|
|
#endif
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// IgmpRtrCreationAlertCallback
|
|
//------------------------------------------------------------------------------
|
|
DWORD
|
|
IgmpRtrCreationAlertCallback (
|
|
DWORD Source,
|
|
DWORD dwSourceMask,
|
|
DWORD Group,
|
|
DWORD dwGroupMask,
|
|
DWORD dwInIfIndex,
|
|
DWORD dwInIfNextHopAddr,
|
|
DWORD dwIfCount,
|
|
PMGM_IF_ENTRY Oif
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Called when the first interface owned by some other protocol joins any group.
|
|
This routine does nothing, as igmp does not send any joins upstream.
|
|
Return Value:
|
|
NO_ERROR
|
|
--*/
|
|
{
|
|
DWORD i, IfIndex, NextHop;
|
|
DWORD Error=NO_ERROR;
|
|
PIF_TABLE_ENTRY pite;
|
|
PGROUP_TABLE_ENTRY pge;
|
|
PGI_ENTRY pgie;
|
|
PGI_SOURCE_ENTRY pSourceEntry;
|
|
|
|
|
|
if (!EnterIgmpApi()) { return ERROR_CAN_NOT_COMPLETE; }
|
|
|
|
for (i=0; i<dwIfCount; i++) {
|
|
|
|
IfIndex = Oif[i].dwIfIndex;
|
|
NextHop = Oif[i].dwIfNextHopAddr;
|
|
if (!Oif[i].bIGMP)
|
|
continue;
|
|
|
|
|
|
ACQUIRE_IF_LOCK_SHARED(IfIndex, "_IgmpRtrCreationAlertCallback");
|
|
|
|
//
|
|
// retrieve the interface
|
|
//
|
|
pite = GetIfByIndex(IfIndex);
|
|
if ( (pite==NULL) || !IS_IF_ACTIVATED(pite) ) {
|
|
|
|
Oif[i].bIsEnabled = FALSE;
|
|
|
|
Trace1(IF,
|
|
"_IgmpRtrCreationAlertCallback: interface %0x not found/activated",
|
|
IfIndex);
|
|
RELEASE_IF_LOCK_SHARED(IfIndex, "_IgmpRtrCreationAlertCallback");
|
|
continue;
|
|
}
|
|
|
|
// if interface is not version 3, then return true immediately
|
|
if (!IS_IF_VER3(pite)) {
|
|
Oif[i].bIsEnabled = TRUE;
|
|
RELEASE_IF_LOCK_SHARED(IfIndex, "_IgmpRtrCreationAlertCallback");
|
|
continue;
|
|
}
|
|
|
|
|
|
ACQUIRE_GROUP_LOCK(Group, "_IgmpRtrCreationAlertCallback");
|
|
|
|
BEGIN_BREAKOUT_BLOCK1 {
|
|
|
|
pge = GetGroupFromGroupTable(Group, NULL, 0);
|
|
if (pge==NULL) {
|
|
Oif[i].bIsEnabled = FALSE;
|
|
Error = ERROR_CAN_NOT_COMPLETE;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
pgie = GetGIFromGIList(pge, pite, NextHop, FALSE, NULL, 0);
|
|
if (pgie==NULL) {
|
|
Oif[i].bIsEnabled = FALSE;
|
|
Error = ERROR_CAN_NOT_COMPLETE;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
// if pgie not ver3 return true immediately
|
|
if (pgie->Version != 3) {
|
|
Oif[i].bIsEnabled = TRUE;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
|
|
pSourceEntry = GetSourceEntry(pgie, Source,
|
|
pgie->FilterType, NULL, 0, 0);
|
|
|
|
if ( (pgie->FilterType==INCLUSION && pSourceEntry==NULL)
|
|
|| (pgie->FilterType==EXCLUSION && pSourceEntry!=NULL) )
|
|
{
|
|
Oif[i].bIsEnabled = FALSE;
|
|
}
|
|
else {
|
|
Oif[i].bIsEnabled = TRUE;
|
|
}
|
|
|
|
} END_BREAKOUT_BLOCK1;
|
|
|
|
RELEASE_GROUP_LOCK(Group, "_IgmpRtrCreationAlertCallback");
|
|
RELEASE_IF_LOCK_SHARED(IfIndex, "_IgmpRtrCreationAlertCallback");
|
|
|
|
}//for all IFs in Oif
|
|
|
|
for (i=0; i<dwIfCount; i++) {
|
|
Trace6(MGM,
|
|
"[%d] IGMP-Rtr Creation Alert: <%d.%d.%d.%d : %d.%d.%d.%d> : <%0x:%0x> : :bIgmp:%d",
|
|
Oif[i].bIsEnabled, PRINT_IPADDR(Group), PRINT_IPADDR(Source),
|
|
Oif[i].dwIfIndex, Oif[i].dwIfNextHopAddr,
|
|
Oif[i].bIGMP
|
|
);
|
|
}
|
|
|
|
LeaveIgmpApi();
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// ProxyCreationAlertCallback
|
|
//------------------------------------------------------------------------------
|
|
DWORD
|
|
ProxyCreationAlertCallback (
|
|
DWORD dwSourceAddr,
|
|
DWORD dwSourceMask,
|
|
DWORD dwGroupAddr,
|
|
DWORD dwGroupMask,
|
|
DWORD dwInIfIndex,
|
|
DWORD dwInIfNextHopAddr,
|
|
DWORD dwIfCount,
|
|
PMGM_IF_ENTRY pmieOutIfList
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Called when the first interface owned by some other protocol joins any group.
|
|
This routine does nothing, as igmp does not send any joins upstream.
|
|
Return Value:
|
|
NO_ERROR
|
|
--*/
|
|
{
|
|
if (!EnterIgmpApi()) { return ERROR_CAN_NOT_COMPLETE; }
|
|
|
|
LeaveIgmpApi();
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// ProxyPruneAlertCallback
|
|
//------------------------------------------------------------------------------
|
|
DWORD
|
|
ProxyPruneAlertCallback (
|
|
DWORD dwSourceAddr,
|
|
DWORD dwSourceMask,
|
|
DWORD dwGroupAddr,
|
|
DWORD dwGroupMask,
|
|
DWORD dwIfIndex,
|
|
DWORD dwIfNextHopAddr,//not used
|
|
BOOL bMemberDelete,
|
|
PDWORD pdwTimeout
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Called by MGM when the outgoing interface list of an MFE becomes empty,
|
|
or when the last interface for a group goes off.
|
|
Proxy owns the incoming interface. Proxy leaves the Group on the incoming
|
|
interface if no more members exist for that group. Also sets the timeout
|
|
value for the negative MFE.
|
|
--*/
|
|
{
|
|
DWORD Error=NO_ERROR;
|
|
PPROXY_ALERT_ENTRY pProxyAlertEntry;
|
|
|
|
|
|
if (!EnterIgmpApi()) { return ERROR_CAN_NOT_COMPLETE; }
|
|
|
|
if (pdwTimeout!=NULL)
|
|
*pdwTimeout = 300000;
|
|
|
|
// ignoring ProxyPruneAlertCallback for MFE deletion
|
|
if (!bMemberDelete) {
|
|
LeaveIgmpApi();
|
|
return NO_ERROR;
|
|
}
|
|
|
|
ACQUIRE_PROXY_ALERT_LOCK("_ProxyPruneAlertCallback");
|
|
|
|
BEGIN_BREAKOUT_BLOCK1 {
|
|
|
|
pProxyAlertEntry = IGMP_ALLOC(sizeof(PROXY_ALERT_ENTRY), 0xa00,g_ProxyIfIndex);
|
|
|
|
PROCESS_ALLOC_FAILURE2(pProxyAlertEntry,
|
|
"error %d allocating %d bytes",
|
|
Error, sizeof(PROXY_ALERT_ENTRY),
|
|
GOTO_END_BLOCK1);
|
|
|
|
pProxyAlertEntry->Group = dwGroupAddr;
|
|
pProxyAlertEntry->Source = dwSourceAddr;
|
|
pProxyAlertEntry->bPrune = TRUE;
|
|
|
|
InsertTailList(&g_ProxyAlertsList, &pProxyAlertEntry->Link);
|
|
|
|
Trace0(WORKER, "Queueing _WF_ProcessProxyAlert() to prune");
|
|
QueueIgmpWorker(WF_ProcessProxyAlert, NULL);
|
|
|
|
} END_BREAKOUT_BLOCK1;
|
|
|
|
RELEASE_PROXY_ALERT_LOCK("_ProxyPruneAlertCallback");
|
|
|
|
LeaveIgmpApi();
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
VOID
|
|
WF_ProcessProxyAlert (
|
|
PVOID pContext
|
|
)
|
|
{
|
|
DWORD ProxyIfIndex, Error = NO_ERROR;
|
|
PIF_TABLE_ENTRY pite;
|
|
|
|
|
|
if (!EnterIgmpWorker()) return;
|
|
|
|
Trace0(ENTER1, "Entering WF_ProcessProxyAlert()");
|
|
|
|
|
|
//
|
|
// acquire lock on the interface and make sure that it exists
|
|
//
|
|
while (1) {
|
|
ProxyIfIndex = g_ProxyIfIndex;
|
|
|
|
ACQUIRE_IF_LOCK_EXCLUSIVE(ProxyIfIndex, "_Wf_ProcessProxyAlert");
|
|
|
|
// the interface was a proxy interface
|
|
if (ProxyIfIndex==g_ProxyIfIndex)
|
|
break;
|
|
|
|
// someone changed the proxy interface. so try to access it again.
|
|
else {
|
|
RELEASE_IF_LOCK_EXCLUSIVE(ProxyIfIndex,
|
|
"_Wf_ProcessProxyAlert");
|
|
}
|
|
}
|
|
|
|
|
|
BEGIN_BREAKOUT_BLOCK1 {
|
|
|
|
//
|
|
// make sure that the Proxy handle is correct
|
|
//
|
|
|
|
pite = g_pProxyIfEntry;
|
|
|
|
if ( (g_ProxyIfIndex==0)||(pite==NULL) )
|
|
{
|
|
Trace1(ERR,
|
|
"Proxy(Deletion/Creation)Alert Callback by MGM for "
|
|
"interface(%0x) not owned by Igmp-Proxy",
|
|
g_ProxyIfIndex);
|
|
IgmpAssertOnError(FALSE);
|
|
Error = ERROR_NO_SUCH_INTERFACE;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
if (!(IS_IF_ACTIVATED(g_pProxyIfEntry))) {
|
|
Trace1(ERR,
|
|
"Proxy(Deletion/Creation)Alert Callback by MGM for "
|
|
"inactivated Proxy interface(%0x)",
|
|
g_ProxyIfIndex);
|
|
IgmpAssertOnError(FALSE);
|
|
Error = ERROR_CAN_NOT_COMPLETE;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
while (TRUE) {
|
|
|
|
PPROXY_ALERT_ENTRY pProxyAlertEntry;
|
|
DWORD Group, Source;
|
|
BOOL bPrune;
|
|
|
|
|
|
ACQUIRE_PROXY_ALERT_LOCK("_WF_ProcessProxyAlert");
|
|
|
|
if (IsListEmpty(&g_ProxyAlertsList)) {
|
|
RELEASE_PROXY_ALERT_LOCK("_WF_ProcessProxyAlert");
|
|
break;
|
|
}
|
|
|
|
pProxyAlertEntry = CONTAINING_RECORD(g_ProxyAlertsList.Flink,
|
|
PROXY_ALERT_ENTRY, Link);
|
|
Group = pProxyAlertEntry->Group;
|
|
Source = pProxyAlertEntry->Source;
|
|
bPrune = pProxyAlertEntry->bPrune;
|
|
RemoveEntryList(&pProxyAlertEntry->Link);
|
|
IGMP_FREE(pProxyAlertEntry);
|
|
|
|
|
|
Trace3(MGM, "Received %s for Grp(%d.%d.%d.%d), Src(%d.%d.%d.%d)",
|
|
(bPrune)? "ProxyPruneAlertCallback"
|
|
:"ProxyJoinAlertCallback",
|
|
PRINT_IPADDR(Group), PRINT_IPADDR(Source)
|
|
);
|
|
|
|
RELEASE_PROXY_ALERT_LOCK("_WF_ProcessProxyAlert");
|
|
|
|
|
|
//
|
|
// delete/add group from Proxy's group list. decrement/increment refcount
|
|
//
|
|
ProcessProxyGroupChange(Source, Group,
|
|
bPrune?DELETE_FLAG:ADD_FLAG, NOT_STATIC_GROUP);
|
|
}
|
|
|
|
} END_BREAKOUT_BLOCK1;
|
|
|
|
|
|
RELEASE_IF_LOCK_EXCLUSIVE(g_ProxyIfIndex, "_ProcessProxyGroupChange");
|
|
|
|
|
|
LeaveIgmpWorker();
|
|
Trace0(LEAVE1, "Leaving _Wf_ProcessProxyAlert()");
|
|
return;
|
|
|
|
} //_wf_processProxyAlert
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _ProxyNewMemberCallback
|
|
//------------------------------------------------------------------------------
|
|
DWORD
|
|
ProxyJoinAlertCallback (
|
|
DWORD dwSourceAddr,
|
|
DWORD dwSourceMask,
|
|
DWORD dwGroupAddr,
|
|
DWORD dwGroupMask,
|
|
BOOL bMemberDelete
|
|
)
|
|
{
|
|
DWORD Error=NO_ERROR;
|
|
PPROXY_ALERT_ENTRY pProxyAlertEntry;
|
|
|
|
|
|
if (!EnterIgmpApi()) { return ERROR_CAN_NOT_COMPLETE; }
|
|
|
|
|
|
// ignoring ProxyJoinAlertCallback for MFE deletion
|
|
if (!bMemberDelete) {
|
|
LeaveIgmpApi();
|
|
return NO_ERROR;
|
|
}
|
|
|
|
ACQUIRE_PROXY_ALERT_LOCK("_ProxyJoinAlertCallback");
|
|
|
|
BEGIN_BREAKOUT_BLOCK1 {
|
|
|
|
pProxyAlertEntry = IGMP_ALLOC(sizeof(PROXY_ALERT_ENTRY), 0x200,g_ProxyIfIndex);
|
|
|
|
PROCESS_ALLOC_FAILURE2(pProxyAlertEntry,
|
|
"error %d allocating %d bytes",
|
|
Error, sizeof(PROXY_ALERT_ENTRY),
|
|
GOTO_END_BLOCK1);
|
|
|
|
pProxyAlertEntry->Group = dwGroupAddr;
|
|
pProxyAlertEntry->Source = dwSourceAddr;
|
|
pProxyAlertEntry->bPrune = FALSE;
|
|
|
|
InsertTailList(&g_ProxyAlertsList, &pProxyAlertEntry->Link);
|
|
|
|
Trace0(WORKER, "Queueing _WF_ProcessProxyAlert() to Join");
|
|
QueueIgmpWorker(WF_ProcessProxyAlert, NULL);
|
|
|
|
} END_BREAKOUT_BLOCK1;
|
|
|
|
RELEASE_PROXY_ALERT_LOCK("_ProxyJoinAlertCallback");
|
|
|
|
LeaveIgmpApi();
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// ProcessProxyGroupChange
|
|
//------------------------------------------------------------------------------
|
|
DWORD
|
|
ProcessProxyGroupChange (
|
|
DWORD dwSourceAddr,
|
|
DWORD dwGroup,
|
|
BOOL bAddFlag,
|
|
BOOL bStaticGroup
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Called when a group is being joined/left by some interface. As proxy acts
|
|
as an igmp host on that interface, it does a join/leave for that group
|
|
on that interface.
|
|
There can be both static and dynamic joins. There is no distinction between
|
|
them. They will just bump up the refcount.
|
|
Return Value:
|
|
ERROR_NO_SUCH_INTERFACE, ERROR_CAN_NOT_COMPLETE, NO_ERROR
|
|
Called by:
|
|
|
|
--*/
|
|
{
|
|
PIF_TABLE_ENTRY pite;
|
|
PLIST_ENTRY ple, pHead;
|
|
DWORD Error = NO_ERROR;
|
|
DWORD GroupLittleEndian = NETWORK_TO_LITTLE_ENDIAN(dwGroup);
|
|
PLIST_ENTRY pHeadSrc, pleSrc;
|
|
PPROXY_SOURCE_ENTRY pSourceEntry = NULL;
|
|
|
|
|
|
|
|
//
|
|
// if Proxy does not exist, or is not activated, then return error
|
|
//
|
|
if ( (g_pProxyIfEntry==NULL)
|
|
|| (!(IS_IF_ACTIVATED(g_pProxyIfEntry))) )
|
|
{
|
|
Trace0(ERR, "Leaving ProcessProxyGroupChange(): Proxy not active");
|
|
IgmpAssertOnError(FALSE);
|
|
|
|
if (g_pProxyIfEntry==NULL)
|
|
return ERROR_NO_SUCH_INTERFACE;
|
|
else
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
|
|
pite = g_pProxyIfEntry;
|
|
|
|
|
|
BEGIN_BREAKOUT_BLOCK1 {
|
|
|
|
PPROXY_GROUP_ENTRY ppge, ppgeNew;
|
|
|
|
pHead = &pite->pProxyHashTable[PROXY_HASH_VALUE(dwGroup)];
|
|
|
|
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
|
|
ppge = CONTAINING_RECORD(ple, PROXY_GROUP_ENTRY, HT_Link);
|
|
if ( GroupLittleEndian <= ppge->GroupLittleEndian )
|
|
break;
|
|
}
|
|
|
|
//
|
|
// adding group to proxy
|
|
//
|
|
if (bAddFlag) {
|
|
|
|
//new group addition
|
|
|
|
//
|
|
// the group entry does not exist
|
|
//
|
|
//ppge may not be valid(if ple==pHead)
|
|
if ( (ple==pHead)||(dwGroup!=ppge->Group) ) {
|
|
|
|
ppgeNew = IGMP_ALLOC(sizeof(PROXY_GROUP_ENTRY), 0x400,0xaaaa);
|
|
|
|
PROCESS_ALLOC_FAILURE2(ppgeNew,
|
|
"error %d allocating %d bytes for Proxy group entry",
|
|
Error, sizeof(PROXY_GROUP_ENTRY),
|
|
GOTO_END_BLOCK1);
|
|
|
|
InitializeListHead(&ppgeNew->ListSources);
|
|
ppgeNew->NumSources = 0;
|
|
ppgeNew->Group = dwGroup;
|
|
ppgeNew->GroupLittleEndian = GroupLittleEndian;
|
|
ppgeNew->RefCount = 0;
|
|
|
|
InsertTailList(ple, &ppgeNew->HT_Link);
|
|
|
|
InsertInProxyList(pite, ppgeNew);
|
|
|
|
// set the time when the entry was created.
|
|
ppgeNew->InitTime = GetCurrentIgmpTime();
|
|
|
|
ppgeNew->bStaticGroup = (dwSourceAddr==0)? bStaticGroup : FALSE;
|
|
|
|
|
|
//
|
|
// update stats
|
|
//
|
|
InterlockedIncrement(&pite->Info.CurrentGroupMemberships);
|
|
InterlockedIncrement(&pite->Info.GroupMembershipsAdded);
|
|
|
|
ppge = ppgeNew;
|
|
|
|
// join the group
|
|
if (dwSourceAddr==0) {
|
|
Error = JoinMulticastGroup(pite->SocketEntry.Socket, dwGroup,
|
|
pite->IfIndex, pite->IpAddr, 0);
|
|
ppgeNew->RefCount = 1;
|
|
}
|
|
// else process source entry later
|
|
|
|
ppge->FilterType = (dwSourceAddr==0)? EXCLUSION : INCLUSION;
|
|
|
|
} //end new group entry created
|
|
|
|
// increase group refcount
|
|
else if (dwSourceAddr==0) {
|
|
|
|
//
|
|
// leave all source mode joins and join *,G
|
|
//
|
|
if (ppge->RefCount==0) {
|
|
pHeadSrc = &ppge->ListSources;
|
|
for (pleSrc=pHeadSrc->Flink; pleSrc!=pHeadSrc; pleSrc=pleSrc->Flink) {
|
|
|
|
pSourceEntry = CONTAINING_RECORD(pleSrc,
|
|
PROXY_SOURCE_ENTRY, LinkSources);
|
|
Error = LeaveMulticastGroup(pite->SocketEntry.Socket, dwGroup,
|
|
pite->IfIndex, pite->IpAddr,
|
|
pSourceEntry->IpAddr);
|
|
pSourceEntry->JoinMode = IGMP_GROUP_NO_STATE;
|
|
pSourceEntry->JoinModeIntended = IGMP_GROUP_ALLOW;
|
|
}
|
|
|
|
Error = JoinMulticastGroup(pite->SocketEntry.Socket, dwGroup,
|
|
pite->IfIndex, pite->IpAddr, 0);
|
|
ppge->FilterType = EXCLUSION;
|
|
}
|
|
|
|
ppge->RefCount++;
|
|
ppge->bStaticGroup |= bStaticGroup;
|
|
|
|
} //group entry exists. group join
|
|
|
|
if (dwSourceAddr!=0) {
|
|
|
|
// check if source already present
|
|
|
|
pHeadSrc = &ppge->ListSources;
|
|
for (pleSrc=pHeadSrc->Flink; pleSrc!=pHeadSrc; pleSrc=pleSrc->Flink) {
|
|
|
|
pSourceEntry = CONTAINING_RECORD(pleSrc,
|
|
PROXY_SOURCE_ENTRY, LinkSources);
|
|
if (pSourceEntry->IpAddr >= dwSourceAddr)
|
|
break;
|
|
}
|
|
|
|
// create new source
|
|
if (pleSrc==pHeadSrc ||
|
|
(pSourceEntry //(dont need to check pSourceEntry)
|
|
&& pSourceEntry->IpAddr!=dwSourceAddr))
|
|
{
|
|
|
|
pSourceEntry = (PPROXY_SOURCE_ENTRY) IGMP_ALLOC_AND_ZERO(sizeof(PROXY_SOURCE_ENTRY),
|
|
0x800,g_ProxyIfIndex);
|
|
PROCESS_ALLOC_FAILURE2(pSourceEntry,
|
|
"error %d allocating %d bytes",
|
|
Error,
|
|
sizeof(PROXY_SOURCE_ENTRY),
|
|
GOTO_END_BLOCK1);
|
|
|
|
InsertTailList(pleSrc, &pSourceEntry->LinkSources);
|
|
pSourceEntry->IpAddr = dwSourceAddr;
|
|
pSourceEntry->RefCount = 1;
|
|
pSourceEntry->bStaticSource = bStaticGroup;
|
|
ppge->NumSources++;
|
|
|
|
//
|
|
// if not joined the whole group. have to join individual
|
|
// sources
|
|
//
|
|
if (ppge->FilterType==INCLUSION) {
|
|
Error = JoinMulticastGroup(pite->SocketEntry.Socket, dwGroup,
|
|
pite->IfIndex, pite->IpAddr,
|
|
dwSourceAddr);
|
|
pSourceEntry->JoinMode = IGMP_GROUP_ALLOW;
|
|
}
|
|
else {
|
|
pSourceEntry->JoinMode = IGMP_GROUP_NO_STATE;
|
|
}
|
|
pSourceEntry->JoinModeIntended = IGMP_GROUP_ALLOW;
|
|
|
|
} //end new source
|
|
|
|
// join: source already exists
|
|
else
|
|
if (pSourceEntry) // dont need to check this. suppress warning
|
|
{
|
|
//
|
|
// join back an excluded source
|
|
//
|
|
if (pSourceEntry->JoinMode==IGMP_GROUP_BLOCK) {
|
|
|
|
if (!pSourceEntry->bStaticSource) {
|
|
|
|
UnBlockSource(pite->SocketEntry.Socket, dwGroup,
|
|
pite->IfIndex, pite->IpAddr,
|
|
dwSourceAddr);
|
|
RemoveEntryList(&pSourceEntry->LinkSources);
|
|
IGMP_FREE(pSourceEntry);
|
|
}
|
|
|
|
}
|
|
|
|
else {//fix this
|
|
if (bStaticGroup)
|
|
pSourceEntry->bStaticSource = TRUE;
|
|
|
|
pSourceEntry->RefCount++;
|
|
}
|
|
}//end: join when existing source
|
|
}
|
|
}
|
|
|
|
//
|
|
// deleting group from proxy
|
|
//
|
|
else {
|
|
|
|
if ((ple==pHead) || (dwGroup>ppge->Group) ) {
|
|
Error = ERROR_CAN_NOT_COMPLETE;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
else {
|
|
|
|
// leave source
|
|
|
|
if (dwSourceAddr!=0) {
|
|
|
|
pHeadSrc = &ppge->ListSources;
|
|
for (pleSrc=pHeadSrc->Flink; pleSrc!=pHeadSrc; pleSrc=pleSrc->Flink) {
|
|
|
|
pSourceEntry = CONTAINING_RECORD(pleSrc,
|
|
PROXY_SOURCE_ENTRY, LinkSources);
|
|
if (pSourceEntry->IpAddr >= dwSourceAddr)
|
|
break;
|
|
}
|
|
|
|
// leave source: source does not exist
|
|
if ((pleSrc==pHeadSrc) || (pSourceEntry->IpAddr!=dwSourceAddr)) {
|
|
|
|
// if in exclude mode then create an exclusion entry
|
|
if (ppge->FilterType==EXCLUSION) {
|
|
|
|
pSourceEntry = (PPROXY_SOURCE_ENTRY) IGMP_ALLOC_AND_ZERO(sizeof(PROXY_SOURCE_ENTRY),
|
|
0x800,g_ProxyIfIndex);
|
|
PROCESS_ALLOC_FAILURE2(pSourceEntry,
|
|
"error %d allocating %d bytes",
|
|
Error,
|
|
sizeof(PROXY_SOURCE_ENTRY),
|
|
GOTO_END_BLOCK1);
|
|
|
|
InsertTailList(pleSrc, &pSourceEntry->LinkSources);
|
|
pSourceEntry->IpAddr = dwSourceAddr;
|
|
pSourceEntry->RefCount = 1;
|
|
pSourceEntry->bStaticSource = bStaticGroup;
|
|
ppge->NumSources++;
|
|
Error = BlockSource(pite->SocketEntry.Socket, dwGroup,
|
|
pite->IfIndex, pite->IpAddr,
|
|
dwSourceAddr);
|
|
pSourceEntry->JoinMode = IGMP_GROUP_BLOCK;
|
|
pSourceEntry->JoinModeIntended = IGMP_GROUP_BLOCK;
|
|
|
|
}
|
|
else { //include mode. trying to leave non-existing source
|
|
IgmpAssert(FALSE);
|
|
}
|
|
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
// leave source: source exists
|
|
else {
|
|
|
|
if ( (pSourceEntry->JoinMode==IGMP_GROUP_ALLOW)
|
|
||(pSourceEntry->JoinMode==IGMP_GROUP_NO_STATE)
|
|
) {
|
|
if (--pSourceEntry->RefCount==0) {
|
|
if (pSourceEntry->JoinMode==IGMP_GROUP_ALLOW) {
|
|
Error = LeaveMulticastGroup(pite->SocketEntry.Socket, dwGroup,
|
|
pite->IfIndex, pite->IpAddr, dwSourceAddr);
|
|
}
|
|
RemoveEntryList(&pSourceEntry->LinkSources);
|
|
IGMP_FREE(pSourceEntry);
|
|
|
|
if (--ppge->NumSources==0) {
|
|
|
|
if (ppge->RefCount==0) {
|
|
RemoveEntryList(&ppge->HT_Link);
|
|
RemoveEntryList(&ppge->LinkBySameIfGroups);
|
|
IGMP_FREE(ppge);
|
|
InterlockedDecrement(&pite->Info.CurrentGroupMemberships);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (bStaticGroup)
|
|
pSourceEntry->bStaticSource = FALSE;
|
|
}
|
|
}
|
|
else {
|
|
//if (!pSourceEntry->bStaticSource || ++pSourceEntry->RefCount>2)
|
|
//IgmpAssert(FALSE);
|
|
// do nothing. this might happen
|
|
}
|
|
}
|
|
} // end leave source
|
|
|
|
// leave group
|
|
else if (--ppge->RefCount == 0) {
|
|
|
|
Error = LeaveMulticastGroup(pite->SocketEntry.Socket, dwGroup,
|
|
pite->IfIndex, pite->IpAddr, 0);
|
|
|
|
// if no S,G then delete this group, else join the
|
|
// individual sources
|
|
|
|
if (ppge->NumSources==0) {
|
|
RemoveEntryList(&ppge->HT_Link);
|
|
RemoveEntryList(&ppge->LinkBySameIfGroups);
|
|
|
|
IGMP_FREE(ppge);
|
|
|
|
//
|
|
// update stats
|
|
//
|
|
InterlockedDecrement(&pite->Info.CurrentGroupMemberships);
|
|
}
|
|
else {
|
|
|
|
pHeadSrc = &ppge->ListSources;
|
|
for (pleSrc=pHeadSrc->Flink; pleSrc!=pHeadSrc; pleSrc=pleSrc->Flink) {
|
|
|
|
pSourceEntry = CONTAINING_RECORD(pleSrc,
|
|
PROXY_SOURCE_ENTRY, LinkSources);
|
|
|
|
Error = JoinMulticastGroup(pite->SocketEntry.Socket, dwGroup,
|
|
pite->IfIndex, pite->IpAddr,
|
|
pSourceEntry->IpAddr);
|
|
pSourceEntry->JoinMode = IGMP_GROUP_ALLOW;
|
|
pSourceEntry->JoinModeIntended = IGMP_GROUP_ALLOW;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (bStaticGroup)
|
|
ppge->bStaticGroup = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
} END_BREAKOUT_BLOCK1;
|
|
|
|
|
|
return NO_ERROR;
|
|
|
|
} //end ProcessProxyGroupChange
|
|
|
|
|
|
VOID
|
|
DebugPrintProxyGroupTable (
|
|
)
|
|
{
|
|
PIF_TABLE_ENTRY pite;
|
|
PLIST_ENTRY ple, pHead;
|
|
DWORD Error = NO_ERROR, dwCount;
|
|
PPROXY_GROUP_ENTRY ppge;
|
|
|
|
|
|
//
|
|
// if Proxy does not exist, or is not activated, then return error
|
|
//
|
|
if ( (g_pProxyIfEntry==NULL)
|
|
|| (!(IS_IF_ACTIVATED(g_pProxyIfEntry))) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
pite = g_pProxyIfEntry;
|
|
|
|
pHead = &pite->ListOfSameIfGroups;
|
|
|
|
Trace0(KSL, "---------------------------");
|
|
Trace0(KSL, "Printing Proxy GroupTable");
|
|
Trace0(KSL, "---------------------------");
|
|
|
|
for (ple=pHead->Flink,dwCount=1; ple!=pHead; ple=ple->Flink,dwCount++) {
|
|
|
|
ppge = CONTAINING_RECORD(ple, PROXY_GROUP_ENTRY, LinkBySameIfGroups);
|
|
|
|
Trace3(KSL, "%2d. %d.%d.%d.%d %10d",
|
|
dwCount, PRINT_IPADDR(ppge->Group), ppge->RefCount);
|
|
|
|
}
|
|
|
|
return;
|
|
}
|