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.
3204 lines
80 KiB
3204 lines
80 KiB
//============================================================================
|
|
// Copyright (c) 1995, Microsoft Corporation
|
|
//
|
|
// File: Mgm.h
|
|
//
|
|
// History:
|
|
// V Raman June-25-1997 Created.
|
|
//
|
|
// Entry points into MGM.
|
|
//============================================================================
|
|
|
|
|
|
#include "pchmgm.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
|
|
IPMGM_GLOBALS ig;
|
|
|
|
RTM_ENTITY_INFO g_reiRtmEntity = { 0, AF_INET, MS_IP_MGM, 0 };
|
|
|
|
RTM_REGN_PROFILE g_rrpRtmProfile;
|
|
|
|
RTM_ENTITY_HANDLE g_hRtmHandle;
|
|
|
|
RTM_NOTIFY_HANDLE g_hNotificationHandle;
|
|
|
|
RTM_REGN_PROFILE g_rrpRtmProfile;
|
|
|
|
|
|
DWORD
|
|
StopMgm(
|
|
);
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// MgmDllStartup
|
|
//
|
|
// Invoked from DllMain, to initialize global critical section, set status and
|
|
// register for tracing.
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
MgmDllStartup(
|
|
)
|
|
{
|
|
do
|
|
{
|
|
ZeroMemory( &ig, sizeof( IPMGM_GLOBALS ) );
|
|
|
|
|
|
ig.dwLogLevel = IPMGM_LOGGING_ERROR;
|
|
|
|
//
|
|
// Create private heap
|
|
//
|
|
|
|
ig.hIpMgmGlobalHeap = HeapCreate( 0, 0, 0 );
|
|
|
|
if ( ig.hIpMgmGlobalHeap == NULL )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// initialize the lock list
|
|
//
|
|
|
|
ig.llStackOfLocks.sleHead.Next = NULL;
|
|
|
|
try
|
|
{
|
|
InitializeCriticalSection( &ig.llStackOfLocks.csListLock );
|
|
}
|
|
except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
break;
|
|
}
|
|
|
|
ig.llStackOfLocks.bInit = TRUE;
|
|
|
|
|
|
//
|
|
// Initialize global critical section and set MGM status
|
|
//
|
|
|
|
try
|
|
{
|
|
InitializeCriticalSection( &ig.csGlobal );
|
|
}
|
|
except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
break;
|
|
}
|
|
|
|
ig.imscStatus = IPMGM_STATUS_STOPPED;
|
|
|
|
return TRUE;
|
|
|
|
} while ( FALSE );
|
|
|
|
//
|
|
// error occurred - clean up and return FALSE
|
|
//
|
|
|
|
//
|
|
// destroy the lock list
|
|
//
|
|
|
|
if ( ig.llStackOfLocks.bInit )
|
|
{
|
|
DeleteCriticalSection( &ig.llStackOfLocks.csListLock );
|
|
}
|
|
|
|
//
|
|
// delete private heap
|
|
//
|
|
|
|
if ( ig.hIpMgmGlobalHeap != NULL )
|
|
{
|
|
HeapDestroy( ig.hIpMgmGlobalHeap );
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// MgmDllCleanup
|
|
//
|
|
// Invoked from DllMain, to delete global critical section and
|
|
// deregister for tracing.
|
|
//----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
MgmDllCleanup(
|
|
)
|
|
{
|
|
DeleteCriticalSection( &ig.csGlobal );
|
|
|
|
//
|
|
// delete lock list
|
|
//
|
|
|
|
DeleteLockList();
|
|
|
|
if ( ig.llStackOfLocks.bInit )
|
|
{
|
|
DeleteCriticalSection( &ig.llStackOfLocks.csListLock );
|
|
}
|
|
|
|
//
|
|
// delete private heap
|
|
//
|
|
|
|
if ( ig.hIpMgmGlobalHeap != NULL )
|
|
{
|
|
HeapDestroy( ig.hIpMgmGlobalHeap );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// MgmInitialize
|
|
//
|
|
// This function is performs Mgm Initialization that includes allocating
|
|
// a private heap, creating a activity count semaphores and the list
|
|
// structures for protocol and interface entries.
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
MgmInitialize(
|
|
IN PROUTER_MANAGER_CONFIG prmcRmConfig,
|
|
IN OUT PMGM_CALLBACKS pmcCallbacks
|
|
)
|
|
{
|
|
|
|
DWORD dwErr = NO_ERROR, dwIndex;
|
|
|
|
LARGE_INTEGER li;
|
|
|
|
NTSTATUS nsStatus = STATUS_SUCCESS;
|
|
|
|
|
|
|
|
ENTER_GLOBAL_SECTION();
|
|
|
|
|
|
//
|
|
// verify MGM has not already been started.
|
|
//
|
|
|
|
if ( ig.imscStatus != IPMGM_STATUS_STOPPED )
|
|
{
|
|
TRACE0( START, "MgmInitialize : MGM already running" );
|
|
|
|
LOGWARN0( IPMGM_ALREADY_STARTED, NO_ERROR );
|
|
|
|
LEAVE_GLOBAL_SECTION();
|
|
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
|
|
//
|
|
// register for tracing
|
|
//
|
|
|
|
TRACESTART();
|
|
|
|
ig.hLogHandle = RouterLogRegister( "IPMGM" );
|
|
|
|
|
|
|
|
|
|
TRACE0( ENTER, "ENTERED MgmInitialize" );
|
|
|
|
do
|
|
{
|
|
//
|
|
// Copy the Router manager callbacks.
|
|
//
|
|
|
|
ig.rmcRmConfig.pfnAddMfeCallback =
|
|
prmcRmConfig-> pfnAddMfeCallback;
|
|
|
|
ig.rmcRmConfig.pfnDeleteMfeCallback =
|
|
prmcRmConfig-> pfnDeleteMfeCallback;
|
|
|
|
ig.rmcRmConfig.pfnGetMfeCallback =
|
|
prmcRmConfig-> pfnGetMfeCallback;
|
|
|
|
ig.rmcRmConfig.pfnHasBoundaryCallback =
|
|
prmcRmConfig-> pfnHasBoundaryCallback;
|
|
|
|
|
|
//
|
|
// Hash table sizes
|
|
//
|
|
|
|
ig.rmcRmConfig.dwIfTableSize = prmcRmConfig-> dwIfTableSize;
|
|
ig.rmcRmConfig.dwGrpTableSize = prmcRmConfig-> dwGrpTableSize + 1;
|
|
ig.rmcRmConfig.dwSrcTableSize = prmcRmConfig-> dwSrcTableSize + 1;
|
|
ig.dwRouteTableSize = prmcRmConfig-> dwIfTableSize;
|
|
ig.dwTimerQTableSize =
|
|
min( prmcRmConfig-> dwGrpTableSize / 10 + 1, TIMER_TABLE_MAX_SIZE );
|
|
|
|
|
|
|
|
if ( prmcRmConfig-> dwLogLevel <= IPMGM_LOGGING_INFO )
|
|
{
|
|
ig.dwLogLevel = prmcRmConfig-> dwLogLevel;
|
|
}
|
|
|
|
//
|
|
// initialize the protocol list
|
|
//
|
|
|
|
ig.dwNumProtocols = 0;
|
|
|
|
CREATE_LOCKED_LIST( &ig.mllProtocolList );
|
|
|
|
|
|
//
|
|
// initialize the outstanding join list
|
|
|
|
CREATE_LOCKED_LIST( &ig.mllOutstandingJoinList );
|
|
|
|
|
|
//
|
|
// create and initialize the interface hash table
|
|
//
|
|
|
|
ig.pmllIfHashTable = MGM_ALLOC( sizeof( MGM_LOCKED_LIST ) * IF_TABLE_SIZE );
|
|
|
|
if ( ig.pmllIfHashTable == NULL )
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
TRACE1(
|
|
ANY, "MgmInitialize : Failed to allocate interface table : %x",
|
|
dwErr
|
|
);
|
|
|
|
LOGERR0( HEAP_ALLOC_FAILED, dwErr );
|
|
|
|
break;
|
|
}
|
|
|
|
ZeroMemory(
|
|
ig.pmllIfHashTable, sizeof( MGM_LOCKED_LIST ) * IF_TABLE_SIZE
|
|
);
|
|
|
|
|
|
for ( dwIndex = 0; dwIndex < IF_TABLE_SIZE; dwIndex++ )
|
|
{
|
|
CREATE_LOCKED_LIST( &ig.pmllIfHashTable[ dwIndex ] );
|
|
}
|
|
|
|
|
|
//
|
|
// initialize the master group list and temp group list.
|
|
//
|
|
|
|
CREATE_LOCKED_LIST( &ig.mllGrpList );
|
|
CREATE_LOCKED_LIST( &ig.mllTempGrpList );
|
|
|
|
ig.dwNumTempEntries = 0;
|
|
|
|
|
|
//
|
|
// Create and Initialize group Hash table
|
|
//
|
|
|
|
ig.pmllGrpHashTable = MGM_ALLOC( sizeof( MGM_LOCKED_LIST ) * GROUP_TABLE_SIZE );
|
|
|
|
if ( ig.pmllGrpHashTable == NULL )
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
TRACE1(
|
|
ANY, "MgmInitialize : Failed to allocate group table : %x",
|
|
dwErr
|
|
);
|
|
|
|
LOGERR0( HEAP_ALLOC_FAILED, dwErr );
|
|
|
|
break;
|
|
}
|
|
|
|
ZeroMemory(
|
|
ig.pmllGrpHashTable, sizeof( MGM_LOCKED_LIST ) * GROUP_TABLE_SIZE
|
|
);
|
|
|
|
|
|
for ( dwIndex = 0; dwIndex < GROUP_TABLE_SIZE; dwIndex++ )
|
|
{
|
|
CREATE_LOCKED_LIST( &ig.pmllGrpHashTable[ dwIndex ] );
|
|
}
|
|
|
|
|
|
//
|
|
// Set up the table of timer queues
|
|
//
|
|
|
|
ig.phTimerQHandleTable =
|
|
MGM_ALLOC( TIMER_TABLE_SIZE * sizeof( HANDLE ) );
|
|
|
|
if ( ig.phTimerQHandleTable == NULL )
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
TRACE1(
|
|
ANY, "MgmInitialize : Failed to allocate timer table : %x",
|
|
dwErr
|
|
);
|
|
|
|
LOGERR0( HEAP_ALLOC_FAILED, dwErr );
|
|
|
|
break;
|
|
}
|
|
|
|
ZeroMemory(
|
|
ig.phTimerQHandleTable, TIMER_TABLE_SIZE * sizeof( HANDLE )
|
|
);
|
|
|
|
|
|
for ( dwIndex = 0; dwIndex < TIMER_TABLE_SIZE; dwIndex++ )
|
|
{
|
|
nsStatus = RtlCreateTimerQueue( &ig.phTimerQHandleTable[ dwIndex ] );
|
|
|
|
if ( !NT_SUCCESS( nsStatus ) )
|
|
{
|
|
dwErr = ERROR_NO_SYSTEM_RESOURCES;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !NT_SUCCESS( nsStatus ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// create activity count semaphore
|
|
//
|
|
|
|
ig.lActivityCount = 0;
|
|
|
|
ig.hActivitySemaphore = CreateSemaphore( NULL, 0, 0x7FFFFFFF, NULL );
|
|
|
|
if ( ig.hActivitySemaphore == NULL )
|
|
{
|
|
dwErr = GetLastError();
|
|
|
|
TRACE1(
|
|
ANY,
|
|
"MgmInitialize : Failed to create activity count semaphore : %x",
|
|
dwErr
|
|
);
|
|
|
|
LOGERR0( CREATE_SEMAPHORE_FAILED, dwErr );
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Register with RTMv2 as a client
|
|
//
|
|
|
|
dwErr = RtmRegisterEntity(
|
|
&g_reiRtmEntity, NULL, RtmChangeNotificationCallback,
|
|
TRUE, &g_rrpRtmProfile, &g_hRtmHandle
|
|
);
|
|
|
|
if ( dwErr != NO_ERROR )
|
|
{
|
|
TRACE1(
|
|
ANY, "MgmInitialize : Failed to register with Rtm : %x",
|
|
dwErr
|
|
);
|
|
|
|
LOGERR0( RTM_REGISTER_FAILED, dwErr );
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Register for marked change notification only
|
|
//
|
|
|
|
dwErr = RtmRegisterForChangeNotification(
|
|
g_hRtmHandle, RTM_VIEW_MASK_MCAST,
|
|
RTM_CHANGE_TYPE_BEST | RTM_NOTIFY_ONLY_MARKED_DESTS,
|
|
NULL, &g_hNotificationHandle
|
|
);
|
|
|
|
if ( dwErr != NO_ERROR )
|
|
{
|
|
TRACE1(
|
|
ANY, "MgmInitialize : Failed to register with Rtm for change"
|
|
"notification : %x", dwErr
|
|
);
|
|
|
|
LOGERR0( RTM_REGISTER_FAILED, dwErr );
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// set up callbacks into MGM for the router manager.
|
|
//
|
|
|
|
pmcCallbacks-> pfnMfeDeleteIndication = DeleteFromForwarder;
|
|
|
|
pmcCallbacks-> pfnNewPacketIndication = MgmNewPacketReceived;
|
|
|
|
pmcCallbacks-> pfnWrongIfIndication = WrongIfFromForwarder;
|
|
|
|
pmcCallbacks-> pfnBlockGroups = MgmBlockGroups;
|
|
|
|
pmcCallbacks-> pfnUnBlockGroups = MgmUnBlockGroups;
|
|
|
|
|
|
|
|
//
|
|
// set the status to running. All future API calls depend on this
|
|
//
|
|
|
|
ig.imscStatus = IPMGM_STATUS_RUNNING;
|
|
|
|
|
|
|
|
|
|
} while ( FALSE );
|
|
|
|
|
|
LEAVE_GLOBAL_SECTION();
|
|
|
|
|
|
//
|
|
// in case of error, cleanup all resources allocated
|
|
//
|
|
|
|
TRACE1( ENTER, "LEAVING MgmInitialize : %x\n", dwErr );
|
|
|
|
if ( dwErr != NO_ERROR )
|
|
{
|
|
MgmDeInitialize();
|
|
}
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// MgmDeInitialize
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
MgmDeInitialize(
|
|
)
|
|
{
|
|
DWORD dwErr, dwInd;
|
|
|
|
|
|
TRACE0( ENTER, "ENTERED MgmDeInitialize" );
|
|
|
|
|
|
do
|
|
{
|
|
//--------------------------------------------------------------------
|
|
// Terminate all activity
|
|
//--------------------------------------------------------------------
|
|
|
|
dwErr = StopMgm();
|
|
|
|
if ( dwErr != NO_ERROR )
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// Free all resources
|
|
//--------------------------------------------------------------------
|
|
|
|
|
|
//
|
|
// de-register from RTM
|
|
//
|
|
|
|
dwErr = RtmDeregisterFromChangeNotification(
|
|
g_hRtmHandle, g_hNotificationHandle
|
|
);
|
|
|
|
if ( dwErr != NO_ERROR )
|
|
{
|
|
TRACE1(
|
|
ANY, "Failed to de-register change notification : %x",
|
|
dwErr
|
|
);
|
|
}
|
|
|
|
dwErr = RtmDeregisterEntity( g_hRtmHandle );
|
|
|
|
if ( dwErr != NO_ERROR )
|
|
{
|
|
TRACE1( ANY, "Failed to de-register from RTM: %x", dwErr );
|
|
}
|
|
|
|
|
|
//
|
|
// delete activity semaphore
|
|
//
|
|
|
|
if ( ig.hActivitySemaphore != NULL )
|
|
{
|
|
CloseHandle( ig.hActivitySemaphore );
|
|
ig.hActivitySemaphore = NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// delete group lists
|
|
//
|
|
|
|
for ( dwInd = 0; dwInd < GROUP_TABLE_SIZE; dwInd++ )
|
|
{
|
|
DELETE_LOCKED_LIST( &ig.pmllGrpHashTable[ dwInd ] );
|
|
}
|
|
|
|
MGM_FREE( ig.pmllGrpHashTable );
|
|
|
|
DELETE_LOCKED_LIST( &ig.mllGrpList );
|
|
|
|
|
|
//
|
|
// delete interface lists
|
|
//
|
|
|
|
for ( dwInd = 0; dwInd < IF_TABLE_SIZE; dwInd++ )
|
|
{
|
|
DELETE_LOCKED_LIST( &ig.pmllIfHashTable[ dwInd ] );
|
|
}
|
|
|
|
MGM_FREE( ig.pmllIfHashTable );
|
|
|
|
|
|
//
|
|
// delete protocol list
|
|
//
|
|
|
|
DELETE_LOCKED_LIST( &ig.mllProtocolList );
|
|
|
|
//
|
|
// free timer resources
|
|
//
|
|
|
|
NtClose( ig.hRouteCheckTimer );
|
|
|
|
for ( dwInd = 0; dwInd < TIMER_TABLE_SIZE; dwInd++ )
|
|
{
|
|
RtlDeleteTimerQueue( ig.phTimerQHandleTable[ dwInd ] );
|
|
}
|
|
|
|
|
|
TRACE1( ENTER, "LEAVING MgmDeInitialize %x\n", dwErr );
|
|
|
|
//
|
|
// trace deregister
|
|
//
|
|
|
|
RouterLogDeregister( ig.hLogHandle );
|
|
|
|
TRACESTOP();
|
|
|
|
ig.imscStatus = IPMGM_STATUS_STOPPED;
|
|
|
|
} while ( FALSE );
|
|
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// StopMgm
|
|
//
|
|
// This function waits for all the therads that are currently executing in
|
|
// MGM to finish. In addition the status of MGM is marked as stopping which
|
|
// prevents the further threads from executing MGM API.
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
StopMgm(
|
|
)
|
|
{
|
|
LONG lThreadCount = 0;
|
|
|
|
|
|
TRACE0( STOP, "ENTERED StopMgm" );
|
|
|
|
|
|
//
|
|
// Set status of MGM to be stopping
|
|
//
|
|
|
|
ENTER_GLOBAL_SECTION();
|
|
|
|
if ( ig.imscStatus != IPMGM_STATUS_RUNNING )
|
|
{
|
|
LEAVE_GLOBAL_SECTION();
|
|
|
|
TRACE0( ANY, "Mgm is not running" );
|
|
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
ig.imscStatus = IPMGM_STATUS_STOPPING;
|
|
|
|
lThreadCount = ig.lActivityCount;
|
|
|
|
LEAVE_GLOBAL_SECTION();
|
|
|
|
|
|
|
|
TRACE1( STOP, "Number of threads in MGM : %x", lThreadCount );
|
|
|
|
|
|
//
|
|
// Wait for all the threads in MGM to terminate.
|
|
//
|
|
|
|
while ( lThreadCount-- > 0 )
|
|
{
|
|
WaitForSingleObject( ig.hActivitySemaphore, INFINITE );
|
|
}
|
|
|
|
|
|
//
|
|
// Acquire and release global critical section to ensure all
|
|
// threads have finished LEAVE_MGM_API()
|
|
//
|
|
|
|
ENTER_GLOBAL_SECTION();
|
|
LEAVE_GLOBAL_SECTION();
|
|
|
|
TRACE0( STOP, "LEAVING StopMgm" );
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// MgmRegisterMProtocol
|
|
//
|
|
// This function is invoked by a routing protocol to obtain a handle. This
|
|
// handle must be supplied to all subsequent MGM operations. When invoked
|
|
// this function creates an entry in the list of clients.
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
MgmRegisterMProtocol(
|
|
IN PROUTING_PROTOCOL_CONFIG prpcInfo,
|
|
IN DWORD dwProtocolId,
|
|
IN DWORD dwComponentId,
|
|
OUT HANDLE * phProtocol
|
|
)
|
|
{
|
|
|
|
DWORD dwErr = NO_ERROR;
|
|
|
|
PPROTOCOL_ENTRY ppeEntry = NULL;
|
|
|
|
|
|
//
|
|
// increment count of clients executing MGM apis
|
|
//
|
|
|
|
if ( !ENTER_MGM_API() )
|
|
{
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
TRACE2(
|
|
ENTER, "ENTERED MgmRegisterMProtocol %x, %x",
|
|
dwProtocolId, dwComponentId
|
|
);
|
|
|
|
|
|
//
|
|
// Lock Protocol list
|
|
//
|
|
|
|
ACQUIRE_PROTOCOL_LOCK_EXCLUSIVE();
|
|
|
|
|
|
do
|
|
{
|
|
//
|
|
// check if the protocol already exists.
|
|
//
|
|
|
|
ppeEntry = GetProtocolEntry(
|
|
&ig.mllProtocolList.leHead, dwProtocolId, dwComponentId
|
|
);
|
|
|
|
if ( ppeEntry != NULL )
|
|
{
|
|
//
|
|
// valid entry is present. quit with error
|
|
//
|
|
|
|
TRACE2(
|
|
ANY, "Entry already present for protocol : %x, %x",
|
|
dwProtocolId, dwComponentId
|
|
);
|
|
|
|
LOGERR0( PROTOCOL_ALREADY_PRESENT, dwProtocolId );
|
|
|
|
dwErr = ERROR_ALREADY_EXISTS;
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// create new protocol entry
|
|
//
|
|
|
|
dwErr = CreateProtocolEntry(
|
|
&ig.mllProtocolList.leHead,
|
|
dwProtocolId, dwComponentId, prpcInfo, &ppeEntry
|
|
);
|
|
|
|
if ( dwErr != NO_ERROR )
|
|
{
|
|
TRACE1(
|
|
ANY, "Failed to create protocol entry %x", dwErr
|
|
);
|
|
|
|
LOGERR0( CREATE_PROTOCOL_FAILED, dwErr );
|
|
|
|
break;
|
|
}
|
|
|
|
ig.dwNumProtocols++;
|
|
|
|
|
|
//
|
|
// return handle to client
|
|
//
|
|
|
|
*phProtocol = (HANDLE) ( ( (ULONG_PTR) ppeEntry )
|
|
^ (ULONG_PTR)MGM_CLIENT_HANDLE_TAG );
|
|
|
|
dwErr = NO_ERROR;
|
|
|
|
} while ( FALSE );
|
|
|
|
|
|
RELEASE_PROTOCOL_LOCK_EXCLUSIVE();
|
|
|
|
LEAVE_MGM_API();
|
|
|
|
TRACE1( ENTER, "LEAVING MgmRegisterMProtocol : %x\n", dwErr );
|
|
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// MgmRegisterMProtocol
|
|
//
|
|
// This function is invoked by a routing protocol to obtain a handle. This
|
|
// handle must be supplied to all subsequent MGM operations. When invoked
|
|
// this function creates an entry in the list of clients.
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
MgmDeRegisterMProtocol(
|
|
IN HANDLE hProtocol
|
|
)
|
|
{
|
|
DWORD dwErr = NO_ERROR;
|
|
|
|
PPROTOCOL_ENTRY ppeEntry = NULL;
|
|
|
|
|
|
//
|
|
// increment count of clients executing MGM apis
|
|
//
|
|
|
|
if ( !ENTER_MGM_API() )
|
|
{
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
TRACE0( ENTER, "ENTERED MgmDeRegisterMProtocol" );
|
|
|
|
|
|
//
|
|
// Acquire write lock
|
|
//
|
|
|
|
ACQUIRE_PROTOCOL_LOCK_EXCLUSIVE();
|
|
|
|
|
|
do
|
|
{
|
|
//
|
|
// retrieve entry from handle
|
|
//
|
|
|
|
ppeEntry = (PPROTOCOL_ENTRY)
|
|
( ( (ULONG_PTR) hProtocol )
|
|
^ (ULONG_PTR)MGM_CLIENT_HANDLE_TAG );
|
|
|
|
dwErr = VerifyProtocolHandle( ppeEntry );
|
|
|
|
if ( dwErr != NO_ERROR )
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Verify that the protocol entry does not own any interfaces
|
|
//
|
|
|
|
if ( ppeEntry-> dwIfCount != 0 )
|
|
{
|
|
dwErr = ERROR_CAN_NOT_COMPLETE;
|
|
|
|
TRACE1( ANY, "%x interfaces present for this protocol", dwErr );
|
|
|
|
LOGERR0( INTERFACES_PRESENT, dwErr );
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// No interfaces for this protocol
|
|
//
|
|
|
|
DeleteProtocolEntry( ppeEntry );
|
|
|
|
ig.dwNumProtocols--;
|
|
|
|
dwErr = NO_ERROR;
|
|
|
|
|
|
} while ( FALSE );
|
|
|
|
|
|
RELEASE_PROTOCOL_LOCK_EXCLUSIVE();
|
|
|
|
TRACE1( ENTER, "LEAVING MgmDeRegisterMProtocol %x\n", dwErr );
|
|
|
|
LEAVE_MGM_API();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
// Interface ownership API
|
|
//
|
|
//============================================================================
|
|
|
|
//----------------------------------------------------------------------------
|
|
// MgmTakeInterfaceOwnership
|
|
//
|
|
// This function is invoked by a routing protocol when it is enabled on an
|
|
// interface. This function creates an entry for the specified interface
|
|
// and inserts it into the appropriate interface hash bucket.
|
|
//
|
|
// Only one protocol can take ownership of an interface at a time. The
|
|
// only exception to this rule is IGMP. IGMP can co-exist with another
|
|
// routing protocol on an interface. In this case, the routing protocol
|
|
// should take ownership of the interface first.
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
MgmTakeInterfaceOwnership(
|
|
IN HANDLE hProtocol,
|
|
IN DWORD dwIfIndex,
|
|
IN DWORD dwIfNextHopAddr
|
|
)
|
|
{
|
|
BOOL bFound = FALSE, bIfLock = FALSE;
|
|
|
|
DWORD dwErr = NO_ERROR, dwBucket;
|
|
|
|
PPROTOCOL_ENTRY ppeEntry = NULL;
|
|
|
|
PIF_ENTRY pieEntry = NULL;
|
|
|
|
|
|
|
|
if ( !ENTER_MGM_API() )
|
|
{
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
TRACE2(
|
|
ENTER, "ENTERED MgmTakeInterfaceOwnership : Interface %x, %x",
|
|
dwIfIndex, dwIfNextHopAddr
|
|
);
|
|
|
|
|
|
ACQUIRE_PROTOCOL_LOCK_SHARED();
|
|
|
|
do
|
|
{
|
|
//
|
|
// verify protocol handle
|
|
//
|
|
|
|
ppeEntry = (PPROTOCOL_ENTRY)
|
|
( ( (ULONG_PTR) hProtocol )
|
|
^ (ULONG_PTR)MGM_CLIENT_HANDLE_TAG );
|
|
|
|
dwErr = VerifyProtocolHandle( ppeEntry );
|
|
|
|
if ( dwErr != NO_ERROR )
|
|
{
|
|
break;
|
|
}
|
|
|
|
TRACEIF2(
|
|
IF, "Protocol id: 0x%x 0x%x",
|
|
ppeEntry-> dwProtocolId, ppeEntry-> dwComponentId
|
|
);
|
|
|
|
//
|
|
// Retrieve interface entry
|
|
//
|
|
|
|
dwBucket = IF_TABLE_HASH( dwIfIndex );
|
|
|
|
ACQUIRE_IF_LOCK_EXCLUSIVE( dwBucket );
|
|
bIfLock = TRUE;
|
|
|
|
bFound = FindIfEntry(
|
|
IF_BUCKET_HEAD( dwBucket ), dwIfIndex, dwIfNextHopAddr,
|
|
&pieEntry
|
|
);
|
|
|
|
if ( bFound )
|
|
{
|
|
//
|
|
// interface entry exists
|
|
//
|
|
|
|
if ( IS_PROTOCOL_IGMP( ppeEntry ) )
|
|
{
|
|
//
|
|
// IGMP is being enabled to this interface.
|
|
// Set IGMP present flag on this interface entry.
|
|
//
|
|
|
|
SET_ADDED_BY_IGMP( pieEntry );
|
|
}
|
|
|
|
|
|
//
|
|
// A routing protocol is being enabled to this interface entry.
|
|
//
|
|
|
|
//
|
|
// Check if interface is currently owned by IGMP. In this case
|
|
// alone the routing protocol may be added to an existing (from
|
|
// the MGM point of view) interface.
|
|
//
|
|
// If another routing protocol owns the interface that is
|
|
// an error as per the interop rules for multicast protocols
|
|
// on a border router. report the error.
|
|
//
|
|
|
|
else if ( IS_PROTOCOL_ID_IGMP( pieEntry-> dwOwningProtocol ) )
|
|
{
|
|
//
|
|
// Interface currently owned by IGMP
|
|
//
|
|
|
|
dwErr = TransferInterfaceOwnershipToProtocol(
|
|
ppeEntry, pieEntry
|
|
);
|
|
}
|
|
|
|
|
|
else
|
|
{
|
|
//
|
|
// Interface currently owned by another routing protocol.
|
|
// This is an error.
|
|
//
|
|
|
|
dwErr = ERROR_ALREADY_EXISTS;
|
|
|
|
TRACE2(
|
|
ANY,
|
|
"MgmTakeInterfaceOwnership : Already owned by routing protocol"
|
|
" : %d, %d", pieEntry-> dwOwningProtocol,
|
|
pieEntry-> dwOwningComponent
|
|
);
|
|
|
|
LOGWARN0( IF_ALREADY_PRESENT, dwErr );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// No interface entry found. Create a new one.
|
|
//
|
|
|
|
if ( pieEntry == NULL )
|
|
{
|
|
//
|
|
// First interface in the hash bucket
|
|
//
|
|
|
|
dwErr = CreateIfEntry(
|
|
&ig.pmllIfHashTable[ dwBucket ].leHead,
|
|
dwIfIndex, dwIfNextHopAddr,
|
|
ppeEntry-> dwProtocolId, ppeEntry-> dwComponentId
|
|
);
|
|
}
|
|
|
|
else
|
|
{
|
|
dwErr = CreateIfEntry(
|
|
&pieEntry-> leIfHashList,
|
|
dwIfIndex, dwIfNextHopAddr,
|
|
ppeEntry-> dwProtocolId, ppeEntry-> dwComponentId
|
|
);
|
|
}
|
|
|
|
|
|
} while ( FALSE );
|
|
|
|
|
|
//
|
|
// Increment interface count for the specified protocol
|
|
//
|
|
|
|
if ( dwErr == NO_ERROR )
|
|
{
|
|
InterlockedIncrement( &ppeEntry-> dwIfCount );
|
|
}
|
|
|
|
|
|
//
|
|
// Release held locks.
|
|
//
|
|
|
|
if ( bIfLock )
|
|
{
|
|
RELEASE_IF_LOCK_EXCLUSIVE( dwBucket );
|
|
}
|
|
|
|
RELEASE_PROTOCOL_LOCK_SHARED();
|
|
|
|
|
|
TRACE1( ENTER, "LEAVING MgmTakeInterfaceOwnership %x\n", dwErr );
|
|
|
|
LEAVE_MGM_API();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// MgmReleaseInterfaceOwnership
|
|
//
|
|
// This function is invoked by a routing protocol when it is disabled
|
|
// on an interface. This functions deletes the entry for the specified
|
|
// interface. Before deleting the interface entry all the
|
|
// fowarding entries created by the protocol that use this interface as
|
|
// the incoming interface. Also remove all group memberships on this
|
|
// interface.
|
|
//
|
|
// If IGMP and routing protocol are both enabled on this interface
|
|
// IGMP should release this interface first followed by the routing
|
|
// protocol.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
MgmReleaseInterfaceOwnership(
|
|
IN HANDLE hProtocol,
|
|
IN DWORD dwIfIndex,
|
|
IN DWORD dwIfNextHopAddr
|
|
)
|
|
{
|
|
BOOL bFound = FALSE, bIGMP, bIfLock = FALSE;
|
|
|
|
DWORD dwErr = NO_ERROR, dwBucket;
|
|
|
|
PPROTOCOL_ENTRY ppeEntry = NULL, ppe;
|
|
|
|
PIF_ENTRY pieEntry = NULL;
|
|
|
|
|
|
|
|
if ( !ENTER_MGM_API() )
|
|
{
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
TRACE2(
|
|
ENTER, "ENTERED MgmReleaseInterfaceOwnership : Interface %x, %x",
|
|
dwIfIndex, dwIfNextHopAddr
|
|
);
|
|
|
|
ACQUIRE_PROTOCOL_LOCK_SHARED();
|
|
|
|
|
|
do
|
|
{
|
|
//
|
|
// 1. parameter validation
|
|
//
|
|
|
|
//
|
|
// verify protocol handle
|
|
//
|
|
|
|
ppeEntry = (PPROTOCOL_ENTRY)
|
|
( ( (ULONG_PTR) hProtocol )
|
|
^ (ULONG_PTR) MGM_CLIENT_HANDLE_TAG );
|
|
|
|
dwErr = VerifyProtocolHandle( ppeEntry );
|
|
|
|
if ( dwErr != NO_ERROR )
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
TRACEIF2(
|
|
IF, "Protocol id: 0x%x 0x%x",
|
|
ppeEntry-> dwProtocolId, ppeEntry-> dwComponentId
|
|
);
|
|
|
|
//
|
|
// Retrieve interface entry
|
|
//
|
|
|
|
dwBucket = IF_TABLE_HASH( dwIfIndex );
|
|
|
|
ACQUIRE_IF_LOCK_EXCLUSIVE( dwBucket );
|
|
bIfLock = TRUE;
|
|
|
|
pieEntry = GetIfEntry(
|
|
IF_BUCKET_HEAD( dwBucket ), dwIfIndex, dwIfNextHopAddr
|
|
);
|
|
|
|
if ( pieEntry == NULL )
|
|
{
|
|
//
|
|
// no interface entry
|
|
//
|
|
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
|
|
TRACE2(
|
|
ANY, "Interface entry %d, %x not found ",
|
|
dwIfIndex, dwIfNextHopAddr
|
|
);
|
|
|
|
LOGWARN0( IF_NOT_FOUND, dwErr );
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Interface entry present. Make sure it is owned by the protocol
|
|
// that is releasing it.
|
|
//
|
|
|
|
if ( IS_PROTOCOL_IGMP( ppeEntry ) && !IS_ADDED_BY_IGMP( pieEntry ) )
|
|
{
|
|
//
|
|
// trying to delete IGMP on an interface that
|
|
// it is not present on.
|
|
//
|
|
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
|
|
TRACE2(
|
|
ANY, "IGMP not running on interface %x, %x",
|
|
pieEntry-> dwIfIndex, pieEntry-> dwIfNextHopAddr
|
|
);
|
|
|
|
LOGWARN0( IF_NOT_FOUND, dwErr );
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
if ( IS_ROUTING_PROTOCOL( ppeEntry ) &&
|
|
( ( ppeEntry-> dwProtocolId != pieEntry-> dwOwningProtocol ) ||
|
|
( ppeEntry-> dwComponentId != pieEntry-> dwOwningComponent ) ) )
|
|
{
|
|
//
|
|
// interface entry not owned by routing protocol
|
|
//
|
|
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
|
|
TRACE2(
|
|
ANY, "Routing protcol not running on interface %x, %x",
|
|
pieEntry-> dwIfIndex, pieEntry-> dwIfNextHopAddr
|
|
);
|
|
|
|
LOGWARN0( IF_NOT_FOUND, dwErr );
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// 2. Remove protocol state for the interface
|
|
//
|
|
|
|
ppe = ppeEntry;
|
|
|
|
if ( IS_PROTOCOL_IGMP( ppeEntry ) )
|
|
{
|
|
//
|
|
// IGMP is releasing this interface
|
|
//
|
|
|
|
CLEAR_ADDED_BY_IGMP( pieEntry );
|
|
|
|
bIGMP = TRUE;
|
|
|
|
if ( !IS_ADDED_BY_PROTOCOL( pieEntry ) )
|
|
{
|
|
//
|
|
// if IGMP is the only protocol on this interface, then delete
|
|
// any MFEs that use this interface as the incoming interface.
|
|
// (otherwise these MFEs were created by the routing protocol,
|
|
// that co-exists with IGMP on this interface, leave them
|
|
// alone)
|
|
//
|
|
|
|
DeleteInInterfaceRefs( &pieEntry-> leInIfList );
|
|
}
|
|
|
|
else
|
|
{
|
|
//
|
|
// Interface is shared by IGMP and Routing Protocol.
|
|
//
|
|
// Group memberships added on an interface shared by IGMP
|
|
// and a routing protocol are owned by the routing protocol (
|
|
// with a bit field indicating whether they have been added by
|
|
// IGMP )
|
|
//
|
|
// To delete a group membership added by IGMP on a shared
|
|
// interface, lookup the protocol on that interface and use that
|
|
// as the protocol that added the group membership.
|
|
//
|
|
|
|
ppeEntry = GetProtocolEntry(
|
|
PROTOCOL_LIST_HEAD(), pieEntry-> dwOwningProtocol,
|
|
pieEntry-> dwOwningComponent
|
|
);
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
//
|
|
// Interface is being deleted by a routing protocol
|
|
//
|
|
|
|
if ( IS_ADDED_BY_IGMP( pieEntry ) )
|
|
{
|
|
//
|
|
// IGMP still exists on this interface
|
|
//
|
|
|
|
dwErr = TransferInterfaceOwnershipToIGMP( ppeEntry, pieEntry );
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// only routing protocol existed on this interface.
|
|
//
|
|
|
|
CLEAR_ADDED_BY_PROTOCOL( pieEntry );
|
|
|
|
bIGMP = FALSE;
|
|
|
|
//
|
|
// delete all mfes that use this interface as the incoming interface
|
|
//
|
|
|
|
DeleteInInterfaceRefs( &pieEntry-> leInIfList );
|
|
}
|
|
|
|
|
|
//
|
|
// Walk the list of group/source entries that contain this
|
|
// interface (for this protocol) and delete the references
|
|
// to this interface. References in this case are nothing but
|
|
// group memberships added on this interface.
|
|
//
|
|
|
|
|
|
DeleteOutInterfaceRefs( ppeEntry, pieEntry, bIGMP );
|
|
|
|
|
|
//
|
|
// if neither IGMP nor a routing protocol remain on this interface
|
|
// remove this interface entry.
|
|
//
|
|
|
|
if ( !IS_ADDED_BY_IGMP( pieEntry ) &&
|
|
!IS_ADDED_BY_PROTOCOL( pieEntry ) )
|
|
{
|
|
if ( !IsListEmpty( &pieEntry-> leOutIfList ) ||
|
|
!IsListEmpty( &pieEntry-> leInIfList ) )
|
|
{
|
|
dwErr = ERROR_CAN_NOT_COMPLETE;
|
|
|
|
TRACE0( ANY, "References remain for interface" );
|
|
|
|
break;
|
|
}
|
|
|
|
DeleteIfEntry( pieEntry );
|
|
}
|
|
|
|
|
|
} while ( FALSE );
|
|
|
|
|
|
//
|
|
// release locks
|
|
//
|
|
|
|
if ( bIfLock )
|
|
{
|
|
RELEASE_IF_LOCK_EXCLUSIVE( dwBucket );
|
|
}
|
|
|
|
//
|
|
// Ensure any callbacks for source specific leaves
|
|
// (caused by the interface being deleted from MGM)
|
|
// are issued.
|
|
//
|
|
// Bug : 154227
|
|
//
|
|
|
|
InvokeOutstandingCallbacks();
|
|
|
|
|
|
//
|
|
// decrement count of interfaces owned by protocol
|
|
//
|
|
|
|
if ( dwErr == NO_ERROR )
|
|
{
|
|
InterlockedDecrement( &ppe-> dwIfCount );
|
|
}
|
|
|
|
|
|
RELEASE_PROTOCOL_LOCK_SHARED();
|
|
|
|
TRACE1( ENTER, "LEAVING MgmReleaseInterfaceOwnership %x\n", dwErr );
|
|
|
|
LEAVE_MGM_API();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// MgmAddGroupMembershipEntry
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
MgmGetProtocolOnInterface(
|
|
IN DWORD dwIfIndex,
|
|
IN DWORD dwIfNextHopAddr,
|
|
IN OUT PDWORD pdwIfProtocolId,
|
|
IN OUT PDWORD pdwIfComponentId
|
|
)
|
|
{
|
|
|
|
DWORD dwErr = NO_ERROR, dwIfBucket;
|
|
|
|
PLIST_ENTRY pleIfHead;
|
|
|
|
PIF_ENTRY pie;
|
|
|
|
|
|
|
|
if ( !ENTER_MGM_API() )
|
|
{
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
TRACE2(
|
|
ENTER, "ENTERED MgmGetProtocolOnInterface : Interface %x, %x",
|
|
dwIfIndex, dwIfNextHopAddr
|
|
);
|
|
|
|
|
|
dwIfBucket = IF_TABLE_HASH( dwIfIndex );
|
|
|
|
pleIfHead = IF_BUCKET_HEAD( dwIfBucket );
|
|
|
|
ACQUIRE_IF_LOCK_SHARED( dwIfBucket );
|
|
|
|
|
|
do
|
|
{
|
|
pie = GetIfEntry( pleIfHead, dwIfIndex, dwIfNextHopAddr );
|
|
|
|
if ( pie == NULL )
|
|
{
|
|
dwErr = ERROR_NOT_FOUND;
|
|
|
|
TRACE2(
|
|
ANY, "No interface entry present for interface %x, %x",
|
|
dwIfIndex, dwIfNextHopAddr
|
|
);
|
|
|
|
LOGWARN0( IF_NOT_FOUND, dwErr );
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
*pdwIfProtocolId = pie-> dwOwningProtocol;
|
|
|
|
*pdwIfComponentId = pie-> dwOwningComponent;
|
|
|
|
} while ( FALSE );
|
|
|
|
|
|
RELEASE_IF_LOCK_SHARED( dwIfBucket );
|
|
|
|
TRACE1(
|
|
ENTER, "LEAVING MgmGetProtocolOnInterface : %x\n", dwErr
|
|
);
|
|
|
|
LEAVE_MGM_API();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
// Group membership manipulation API. (addition / deletion / retreival)
|
|
//============================================================================
|
|
|
|
//----------------------------------------------------------------------------
|
|
// MgmAddGroupMembershipEntry
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
MgmAddGroupMembershipEntry(
|
|
IN HANDLE hProtocol,
|
|
IN DWORD dwSourceAddr,
|
|
IN DWORD dwSourceMask,
|
|
IN DWORD dwGroupAddr,
|
|
IN DWORD dwGroupMask,
|
|
IN DWORD dwIfIndex,
|
|
IN DWORD dwIfNextHopAddr,
|
|
IN DWORD dwFlags
|
|
)
|
|
{
|
|
BOOL bIfLock = FALSE, bgeLock = FALSE,
|
|
bIGMP = FALSE, bUpdateMfe, bWCFound,
|
|
bNewComp = FALSE;
|
|
|
|
DWORD dwErr = NO_ERROR, dwIfBucket,
|
|
dwGrpBucket, dwSrcBucket, dwInd,
|
|
dwWCGrpBucket;
|
|
|
|
WORD wSourceAddedBy = 0,
|
|
wNumAddsByIGMP = 0, wNumAddsByRP = 0;
|
|
|
|
PPROTOCOL_ENTRY ppeEntry = NULL;
|
|
|
|
PIF_ENTRY pieEntry = NULL;
|
|
|
|
PGROUP_ENTRY pge = NULL, pgeWC = NULL;
|
|
|
|
PSOURCE_ENTRY pse = NULL;
|
|
|
|
POUT_IF_ENTRY poie = NULL;
|
|
|
|
PIF_REFERENCE_ENTRY pire = NULL;
|
|
|
|
LIST_ENTRY leSourceList;
|
|
|
|
PCREATION_ALERT_CONTEXT pcac;
|
|
|
|
|
|
if ( !ENTER_MGM_API() )
|
|
{
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
TRACE6(
|
|
ENTER, "ENTERED MgmAddGroupMembershipEntry : Interface %x, %x : "
|
|
"Source : %x, %x : Group : %x, %x", dwIfIndex, dwIfNextHopAddr,
|
|
dwSourceAddr, dwSourceMask, dwGroupAddr, dwGroupMask
|
|
);
|
|
|
|
ACQUIRE_PROTOCOL_LOCK_SHARED();
|
|
|
|
|
|
//
|
|
// I. Verify input parameters
|
|
//
|
|
|
|
do
|
|
{
|
|
//
|
|
// verify protocol handle
|
|
//
|
|
|
|
ppeEntry = (PPROTOCOL_ENTRY)
|
|
( ( (ULONG_PTR) hProtocol )
|
|
^ (ULONG_PTR) MGM_CLIENT_HANDLE_TAG );
|
|
|
|
dwErr = VerifyProtocolHandle( ppeEntry );
|
|
|
|
if ( dwErr != NO_ERROR )
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Retrieve interface entry
|
|
//
|
|
|
|
dwIfBucket = IF_TABLE_HASH( dwIfIndex );
|
|
|
|
ACQUIRE_IF_LOCK_EXCLUSIVE( dwIfBucket );
|
|
bIfLock = TRUE;
|
|
|
|
pieEntry = GetIfEntry(
|
|
IF_BUCKET_HEAD( dwIfBucket ), dwIfIndex, dwIfNextHopAddr
|
|
);
|
|
|
|
if ( pieEntry == NULL )
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
|
|
TRACE2(
|
|
ANY, "Specified interface was not found : %d, %d", dwIfIndex,
|
|
dwIfNextHopAddr
|
|
);
|
|
|
|
LOGWARN0( IF_NOT_FOUND, dwErr );
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Verify interface is owned by protocol making this call,
|
|
// or
|
|
// if this operation is being perfomed by IGMP, verify IGMP is
|
|
// enabled on this interface (in this case the interface may
|
|
// be owned by another routing protocol)
|
|
//
|
|
|
|
if ( ( pieEntry-> dwOwningProtocol != ppeEntry-> dwProtocolId ||
|
|
pieEntry-> dwOwningComponent != ppeEntry-> dwComponentId ) &&
|
|
( !IS_PROTOCOL_IGMP( ppeEntry ) ||
|
|
!IS_ADDED_BY_IGMP( pieEntry ) ) )
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
|
|
TRACE4(
|
|
ANY, "Interface %d, %d is not owned by protocol %d, %d",
|
|
dwIfIndex, dwIfNextHopAddr, ppeEntry-> dwProtocolId,
|
|
ppeEntry-> dwComponentId
|
|
);
|
|
|
|
LOGERR0( IF_DIFFERENT_OWNER, dwErr );
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
bIGMP = IS_PROTOCOL_IGMP( ppeEntry );
|
|
|
|
if ( bIGMP )
|
|
{
|
|
//
|
|
// if this operation has been invoked by IGMP,
|
|
// retrieve the entry for the routing protocol component
|
|
// that owns this interface.
|
|
//
|
|
|
|
ppeEntry = GetProtocolEntry(
|
|
PROTOCOL_LIST_HEAD(), pieEntry-> dwOwningProtocol,
|
|
pieEntry-> dwOwningComponent
|
|
);
|
|
|
|
if ( ppeEntry == NULL )
|
|
{
|
|
dwErr = ERROR_CAN_NOT_COMPLETE;
|
|
|
|
TRACE2(
|
|
ANY, "IGMP join failed because owning protocol entry"
|
|
" (%x, %x) not found", pieEntry-> dwOwningProtocol,
|
|
pieEntry-> dwOwningComponent
|
|
);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
} while ( FALSE );
|
|
|
|
|
|
//
|
|
// return, if parameter validation fails
|
|
//
|
|
|
|
if ( dwErr != NO_ERROR )
|
|
{
|
|
if ( bIfLock )
|
|
{
|
|
RELEASE_IF_LOCK_EXCLUSIVE( dwIfBucket );
|
|
}
|
|
|
|
RELEASE_PROTOCOL_LOCK_SHARED();
|
|
|
|
TRACE1( ENTER, "LEAVING MgmAddGroupMembership %x\n", dwErr );
|
|
|
|
LEAVE_MGM_API();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
//
|
|
// for JOIN STATE changes, i.e for group membership additions
|
|
//
|
|
|
|
if ( dwFlags & MGM_JOIN_STATE_FLAG )
|
|
{
|
|
//
|
|
// Add membership entry
|
|
//
|
|
|
|
InitializeListHead( &leSourceList );
|
|
|
|
dwErr = AddInterfaceToSourceEntry(
|
|
ppeEntry, dwGroupAddr, dwGroupMask,
|
|
dwSourceAddr, dwSourceMask, dwIfIndex,
|
|
dwIfNextHopAddr, bIGMP, &bUpdateMfe,
|
|
&leSourceList
|
|
);
|
|
|
|
if ( dwErr == NO_ERROR )
|
|
{
|
|
//
|
|
// Add to an outgoing interface reference for this group
|
|
//
|
|
|
|
AddSourceToRefList(
|
|
&pieEntry-> leOutIfList, dwSourceAddr, dwSourceMask,
|
|
dwGroupAddr, dwGroupMask, bIGMP
|
|
);
|
|
}
|
|
|
|
|
|
//
|
|
// release locks in prepapation for updating MFEs
|
|
// (invoking creation alerts when updating MFEs requires
|
|
// all locks to be released)
|
|
//
|
|
// When locks are re-acquired you need to verify that
|
|
// the interface (dwIfIndex, dwIfNextHopAddr) and the
|
|
// group membership being added is still present.
|
|
// Any one of those could be deleted in another thread
|
|
// when the locks are released.
|
|
//
|
|
|
|
if ( bIfLock )
|
|
{
|
|
RELEASE_IF_LOCK_EXCLUSIVE( dwIfBucket );
|
|
bIfLock = FALSE;
|
|
}
|
|
|
|
//
|
|
// Invoke pended Join/Prune alerts
|
|
//
|
|
|
|
InvokeOutstandingCallbacks();
|
|
|
|
|
|
//
|
|
// Update MFEs if required
|
|
//
|
|
|
|
if ( ( dwErr == NO_ERROR ) && bUpdateMfe )
|
|
{
|
|
//
|
|
// Queue a work item to update the MFEs
|
|
// Creation alerts have to be invoked from a separate
|
|
// thread. This is done to avoid calling back into the
|
|
// protocol (from MGM) in the context of an add membership
|
|
// call from the the protocol (into MGM). Doing so results
|
|
// in deadlocks (bug #323388)
|
|
//
|
|
|
|
pcac = MGM_ALLOC( sizeof( CREATION_ALERT_CONTEXT ) );
|
|
|
|
if ( pcac != NULL )
|
|
{
|
|
pcac-> dwSourceAddr = dwSourceAddr;
|
|
pcac-> dwSourceMask = dwSourceMask;
|
|
|
|
pcac-> dwGroupAddr = dwGroupAddr;
|
|
pcac-> dwGroupMask = dwGroupMask;
|
|
|
|
pcac-> dwIfIndex = dwIfIndex;
|
|
pcac-> dwIfNextHopAddr = dwIfNextHopAddr;
|
|
|
|
pcac-> dwProtocolId = ppeEntry-> dwProtocolId;
|
|
pcac-> dwComponentId = ppeEntry-> dwComponentId;
|
|
|
|
pcac-> bIGMP = bIGMP;
|
|
|
|
pcac-> leSourceList = leSourceList;
|
|
|
|
leSourceList.Flink-> Blink = &(pcac-> leSourceList);
|
|
leSourceList.Blink-> Flink = &(pcac-> leSourceList);
|
|
|
|
dwErr = QueueMgmWorker(
|
|
WorkerFunctionInvokeCreationAlert,
|
|
(PVOID)pcac
|
|
);
|
|
|
|
if ( dwErr != NO_ERROR )
|
|
{
|
|
TRACE1(
|
|
ANY, "Failed to queue "
|
|
"WorkerFunctionInvokeCreationAlert",
|
|
dwErr
|
|
);
|
|
|
|
MGM_FREE( pcac );
|
|
|
|
dwErr = NO_ERROR;
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
TRACE1(
|
|
ANY, "Failed to allocate %d bytes for work item "
|
|
"context", sizeof( CREATION_ALERT_CONTEXT )
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// For FORWARD state changes only.
|
|
//
|
|
|
|
else if ( ( dwFlags & MGM_FORWARD_STATE_FLAG ) &&
|
|
!IS_WILDCARD_GROUP( dwGroupAddr, dwGroupMask ) &&
|
|
!IS_WILDCARD_SOURCE( dwSourceAddr, dwSourceMask ) )
|
|
{
|
|
//
|
|
// Forward state changes are for MFEs only.
|
|
// No (*, G) or (*, *) entries are updated
|
|
//
|
|
|
|
do
|
|
{
|
|
//
|
|
// Check for boundaries
|
|
//
|
|
|
|
if ( IS_HAS_BOUNDARY_CALLBACK() &&
|
|
HAS_BOUNDARY_CALLBACK()( dwIfIndex, dwGroupAddr ) )
|
|
{
|
|
TRACE0( ANY, "Boundary present of group on interface" );
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Check for (*, *) membership
|
|
//
|
|
|
|
bWCFound = FindRefEntry(
|
|
&pieEntry-> leOutIfList,
|
|
WILDCARD_SOURCE, WILDCARD_SOURCE_MASK,
|
|
WILDCARD_GROUP, WILDCARD_GROUP_MASK,
|
|
&pire
|
|
);
|
|
|
|
if ( bWCFound )
|
|
{
|
|
//
|
|
// (*, *) entry present,
|
|
// get counts for (*, *) membership on interface
|
|
//
|
|
|
|
dwWCGrpBucket = GROUP_TABLE_HASH(
|
|
WILDCARD_GROUP, WILDCARD_GROUP_MASK
|
|
);
|
|
|
|
ACQUIRE_GROUP_LOCK_SHARED( dwWCGrpBucket );
|
|
|
|
pgeWC = GetGroupEntry(
|
|
GROUP_BUCKET_HEAD( dwWCGrpBucket ),
|
|
WILDCARD_GROUP, WILDCARD_GROUP_MASK
|
|
);
|
|
|
|
if ( pgeWC != NULL )
|
|
{
|
|
ACQUIRE_GROUP_ENTRY_LOCK_SHARED( pgeWC );
|
|
|
|
dwSrcBucket = SOURCE_TABLE_HASH(
|
|
WILDCARD_SOURCE, WILDCARD_SOURCE_MASK
|
|
);
|
|
|
|
pse = GetSourceEntry(
|
|
SOURCE_BUCKET_HEAD( pgeWC, dwSrcBucket ),
|
|
WILDCARD_SOURCE, WILDCARD_SOURCE_MASK
|
|
);
|
|
|
|
if ( pse != NULL )
|
|
{
|
|
poie = GetOutInterfaceEntry(
|
|
&pse-> leOutIfList,
|
|
dwIfIndex, dwIfNextHopAddr,
|
|
ppeEntry-> dwProtocolId,
|
|
ppeEntry-> dwComponentId
|
|
);
|
|
|
|
if ( poie != NULL )
|
|
{
|
|
wSourceAddedBy |= poie-> wAddedByFlag;
|
|
wNumAddsByRP = poie-> wNumAddsByRP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check for (*, G) membership
|
|
//
|
|
|
|
dwGrpBucket = GROUP_TABLE_HASH( dwGroupAddr, dwGroupMask );
|
|
|
|
ACQUIRE_GROUP_LOCK_SHARED( dwGrpBucket );
|
|
|
|
pge = GetGroupEntry(
|
|
GROUP_BUCKET_HEAD( dwGrpBucket),
|
|
dwGroupAddr, dwGroupMask
|
|
);
|
|
|
|
if ( pge != NULL )
|
|
{
|
|
ACQUIRE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
|
|
|
|
dwSrcBucket = SOURCE_TABLE_HASH(
|
|
WILDCARD_SOURCE, WILDCARD_SOURCE_MASK
|
|
);
|
|
|
|
pse = GetSourceEntry(
|
|
SOURCE_BUCKET_HEAD( pge, dwSrcBucket ),
|
|
WILDCARD_SOURCE, WILDCARD_SOURCE_MASK
|
|
);
|
|
|
|
if ( pse != NULL )
|
|
{
|
|
//
|
|
// get counts for interface
|
|
// if (*, G) is present on the interface
|
|
//
|
|
|
|
poie = GetOutInterfaceEntry(
|
|
&pse-> leOutIfList,
|
|
dwIfIndex, dwIfNextHopAddr,
|
|
ppeEntry-> dwProtocolId,
|
|
ppeEntry-> dwComponentId
|
|
);
|
|
|
|
if ( poie != NULL )
|
|
{
|
|
wSourceAddedBy |= poie-> wAddedByFlag;
|
|
wNumAddsByIGMP = poie-> wNumAddsByIGMP;
|
|
wNumAddsByRP += poie-> wNumAddsByRP;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Get (S, G) entry
|
|
//
|
|
|
|
dwSrcBucket = SOURCE_TABLE_HASH( dwSourceAddr, dwSourceMask );
|
|
|
|
pse = GetSourceEntry(
|
|
SOURCE_BUCKET_HEAD( pge, dwSrcBucket ),
|
|
dwSourceAddr, dwSourceMask
|
|
);
|
|
|
|
if ( pse != NULL )
|
|
{
|
|
poie = GetOutInterfaceEntry(
|
|
&pse-> leOutIfList,
|
|
dwIfIndex, dwIfNextHopAddr,
|
|
ppeEntry-> dwProtocolId,
|
|
ppeEntry-> dwComponentId
|
|
);
|
|
|
|
if ( poie != NULL )
|
|
{
|
|
//
|
|
// Get counts for (S, G) membership if
|
|
// present on interface
|
|
//
|
|
|
|
wSourceAddedBy |= poie-> wAddedByFlag;
|
|
wNumAddsByIGMP += poie-> wNumAddsByIGMP;
|
|
wNumAddsByRP += poie-> wNumAddsByRP;
|
|
}
|
|
|
|
//
|
|
// Add interface to MFE OIF list if any
|
|
// membership
|
|
//
|
|
|
|
if ( wSourceAddedBy )
|
|
{
|
|
AddInterfaceToSourceMfe(
|
|
pge, pse, dwIfIndex, dwIfNextHopAddr,
|
|
ppeEntry-> dwProtocolId,
|
|
ppeEntry-> dwComponentId,
|
|
IS_PROTOCOL_IGMP( ppeEntry ),
|
|
&poie
|
|
);
|
|
|
|
poie-> wAddedByFlag |= wSourceAddedBy;
|
|
poie-> wNumAddsByIGMP = wNumAddsByIGMP;
|
|
poie-> wNumAddsByRP = wNumAddsByRP;
|
|
|
|
}
|
|
|
|
else
|
|
{
|
|
TRACE0(
|
|
ANY, "Forward state not updated as no"
|
|
" memberships present on interface"
|
|
);
|
|
}
|
|
}
|
|
|
|
RELEASE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
|
|
}
|
|
|
|
RELEASE_GROUP_LOCK_SHARED( dwGrpBucket );
|
|
|
|
if ( bWCFound )
|
|
{
|
|
if ( pgeWC )
|
|
{
|
|
RELEASE_GROUP_ENTRY_LOCK_SHARED( pgeWC );
|
|
}
|
|
|
|
RELEASE_GROUP_LOCK_SHARED( dwWCGrpBucket );
|
|
}
|
|
|
|
} while ( FALSE );
|
|
}
|
|
|
|
if ( bIfLock )
|
|
{
|
|
RELEASE_IF_LOCK_EXCLUSIVE( dwIfBucket );
|
|
}
|
|
|
|
RELEASE_PROTOCOL_LOCK_SHARED();
|
|
|
|
TRACE1( ENTER, "LEAVING MgmAddGroupMembership %x\n", dwErr );
|
|
|
|
LEAVE_MGM_API();
|
|
|
|
return dwErr;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// MgmDeleteGroupMembershipEntry
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
MgmDeleteGroupMembershipEntry(
|
|
IN HANDLE hProtocol,
|
|
IN DWORD dwSourceAddr,
|
|
IN DWORD dwSourceMask,
|
|
IN DWORD dwGroupAddr,
|
|
IN DWORD dwGroupMask,
|
|
IN DWORD dwIfIndex,
|
|
IN DWORD dwIfNextHopAddr,
|
|
IN DWORD dwFlags
|
|
)
|
|
{
|
|
BOOL bIfLock = FALSE, bIGMP;
|
|
|
|
DWORD dwErr = NO_ERROR, dwIfBucket,
|
|
dwGrpBucket, dwSrcBucket;
|
|
|
|
PGROUP_ENTRY pge = NULL;
|
|
|
|
PSOURCE_ENTRY pse = NULL;
|
|
|
|
PPROTOCOL_ENTRY ppeEntry = NULL;
|
|
|
|
PIF_ENTRY pieEntry = NULL;
|
|
|
|
|
|
|
|
if ( !ENTER_MGM_API() )
|
|
{
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
TRACE6(
|
|
ENTER, "ENTERED MgmDeleteGroupMembership : Interface %x, %x : "
|
|
"Source : %x, %x : Group : %x, %x", dwIfIndex, dwIfNextHopAddr,
|
|
dwSourceAddr, dwSourceMask, dwGroupAddr, dwGroupMask
|
|
);
|
|
|
|
ACQUIRE_PROTOCOL_LOCK_SHARED();
|
|
|
|
|
|
//
|
|
// Verify input parameters.
|
|
//
|
|
|
|
do
|
|
{
|
|
//
|
|
// verify protocol handle
|
|
//
|
|
|
|
ppeEntry = (PPROTOCOL_ENTRY)
|
|
( ( (ULONG_PTR) hProtocol )
|
|
^ (ULONG_PTR) MGM_CLIENT_HANDLE_TAG );
|
|
|
|
dwErr = VerifyProtocolHandle( ppeEntry );
|
|
|
|
if ( dwErr != NO_ERROR )
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Retrieve interface entry
|
|
//
|
|
|
|
dwIfBucket = IF_TABLE_HASH( dwIfIndex );
|
|
|
|
ACQUIRE_IF_LOCK_EXCLUSIVE( dwIfBucket );
|
|
bIfLock = TRUE;
|
|
|
|
pieEntry = GetIfEntry(
|
|
IF_BUCKET_HEAD( dwIfBucket ), dwIfIndex, dwIfNextHopAddr
|
|
);
|
|
|
|
if ( pieEntry == NULL )
|
|
{
|
|
dwErr = ERROR_NOT_FOUND;
|
|
|
|
TRACE0( ANY, "Specified interface was not found" );
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Verify interface is owned by protocol making this call.
|
|
// or
|
|
// if IGMP has invoked this api, verify that IGMP is present
|
|
// on this interface.
|
|
//
|
|
|
|
if ( ( pieEntry-> dwOwningProtocol != ppeEntry-> dwProtocolId ||
|
|
pieEntry-> dwOwningComponent != ppeEntry-> dwComponentId ) &&
|
|
( !IS_PROTOCOL_IGMP( ppeEntry ) ||
|
|
!IS_ADDED_BY_IGMP( pieEntry ) ) )
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
|
|
TRACE4(
|
|
ANY, "Interface %x, %x is not owned by %x, %x",
|
|
dwIfIndex, dwIfNextHopAddr, ppeEntry-> dwProtocolId,
|
|
ppeEntry-> dwComponentId
|
|
);
|
|
|
|
LOGERR0( IF_DIFFERENT_OWNER, dwErr );
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// in case this operation is being performed by IGMP
|
|
// get the routing protocol that co-exists with IGMP
|
|
// on this interface
|
|
//
|
|
|
|
bIGMP = IS_PROTOCOL_IGMP( ppeEntry );
|
|
|
|
if ( bIGMP )
|
|
{
|
|
//
|
|
// if this operation has been invoked by IGMP,
|
|
// retrieve the entry for the routing protocol component
|
|
// that owns this interface.
|
|
//
|
|
|
|
ppeEntry = GetProtocolEntry(
|
|
PROTOCOL_LIST_HEAD(), pieEntry-> dwOwningProtocol,
|
|
pieEntry-> dwOwningComponent
|
|
);
|
|
|
|
if ( ppeEntry == NULL )
|
|
{
|
|
dwErr = ERROR_CAN_NOT_COMPLETE;
|
|
|
|
TRACE2(
|
|
ANY, "IGMP join failed because owning protocol entry"
|
|
" (%x, %x) not found", pieEntry-> dwOwningProtocol,
|
|
pieEntry-> dwOwningComponent
|
|
);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
} while ( FALSE );
|
|
|
|
|
|
//
|
|
// in case of error, release locks and return
|
|
//
|
|
|
|
if ( dwErr != NO_ERROR )
|
|
{
|
|
if ( bIfLock )
|
|
{
|
|
RELEASE_IF_LOCK_EXCLUSIVE( dwIfBucket );
|
|
}
|
|
|
|
RELEASE_PROTOCOL_LOCK_SHARED();
|
|
|
|
TRACE1( ENTER, "LEAVING MgmDeleteGroupMembership %x\n", dwErr );
|
|
|
|
LEAVE_MGM_API();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
//
|
|
// For JOIN state change
|
|
//
|
|
|
|
if ( dwFlags & MGM_JOIN_STATE_FLAG )
|
|
{
|
|
//
|
|
// delete interface from source entry
|
|
//
|
|
|
|
DeleteInterfaceFromSourceEntry(
|
|
ppeEntry, dwGroupAddr, dwGroupMask,
|
|
dwSourceAddr, dwSourceMask,
|
|
dwIfIndex, dwIfNextHopAddr, bIGMP
|
|
);
|
|
|
|
|
|
//
|
|
// delete reference entry
|
|
//
|
|
|
|
DeleteSourceFromRefList(
|
|
&pieEntry-> leOutIfList, dwSourceAddr, dwSourceMask,
|
|
dwGroupAddr, dwGroupMask, bIGMP
|
|
);
|
|
|
|
//
|
|
// release locks
|
|
//
|
|
|
|
if ( bIfLock )
|
|
{
|
|
RELEASE_IF_LOCK_EXCLUSIVE( dwIfBucket );
|
|
bIfLock = FALSE;
|
|
}
|
|
|
|
//
|
|
// Invoke pended Join/Prune alerts
|
|
//
|
|
|
|
InvokeOutstandingCallbacks();
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// For FORWARD state changes
|
|
//
|
|
|
|
else if ( ( dwFlags & MGM_FORWARD_STATE_FLAG ) &&
|
|
!IS_WILDCARD_GROUP( dwGroupAddr, dwGroupMask ) &&
|
|
!IS_WILDCARD_SOURCE( dwSourceAddr, dwSourceMask ) )
|
|
{
|
|
//
|
|
// FORWARD state changes are for MFEs only.
|
|
// No (*, *) or (*, G) entries are updated
|
|
//
|
|
|
|
//
|
|
// Find the (S, G) entry and delete the group membership
|
|
//
|
|
|
|
dwGrpBucket = GROUP_TABLE_HASH( dwGroupAddr, dwGroupMask );
|
|
|
|
ACQUIRE_GROUP_LOCK_SHARED( dwGrpBucket );
|
|
|
|
pge = GetGroupEntry(
|
|
GROUP_BUCKET_HEAD( dwGrpBucket ),
|
|
dwGroupAddr, dwGroupMask
|
|
);
|
|
|
|
if ( pge != NULL )
|
|
{
|
|
ACQUIRE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
|
|
|
|
dwSrcBucket = SOURCE_TABLE_HASH( dwSourceAddr, dwSourceMask );
|
|
|
|
pse = GetSourceEntry(
|
|
SOURCE_BUCKET_HEAD( pge, dwSrcBucket ),
|
|
dwSourceAddr, dwSourceMask
|
|
);
|
|
|
|
if ( pse != NULL )
|
|
{
|
|
DeleteInterfaceFromSourceMfe(
|
|
pge, pse, dwIfIndex, dwIfNextHopAddr,
|
|
ppeEntry-> dwProtocolId,
|
|
ppeEntry-> dwComponentId, bIGMP, TRUE
|
|
);
|
|
}
|
|
|
|
RELEASE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
|
|
}
|
|
|
|
RELEASE_GROUP_LOCK_SHARED( dwGrpBucket );
|
|
}
|
|
|
|
|
|
//
|
|
// release locks
|
|
//
|
|
|
|
if ( bIfLock )
|
|
{
|
|
RELEASE_IF_LOCK_EXCLUSIVE( dwIfBucket );
|
|
}
|
|
|
|
RELEASE_PROTOCOL_LOCK_SHARED();
|
|
|
|
TRACE1( ENTER, "LEAVING MgmDeleteGroupMembership %x\n", dwErr );
|
|
|
|
LEAVE_MGM_API();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Mgm MFE Update API.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
MgmSetMfe(
|
|
IN HANDLE hProtocol,
|
|
IN PMIB_IPMCAST_MFE pmimm
|
|
)
|
|
{
|
|
BOOL bGrpLock = FALSE, bgeLock = FALSE;
|
|
|
|
DWORD dwErr = NO_ERROR, dwGrpBucket, dwSrcBucket;
|
|
|
|
PPROTOCOL_ENTRY ppeEntry;
|
|
|
|
PGROUP_ENTRY pge;
|
|
|
|
PSOURCE_ENTRY pse;
|
|
|
|
|
|
//
|
|
// Check if MGM is still running and increment counts
|
|
//
|
|
|
|
if ( !ENTER_MGM_API() )
|
|
{
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
|
|
TRACE2(
|
|
ENTER, "ENTERED MgmSetMfe : (%lx, %lx)", pmimm-> dwSource,
|
|
pmimm-> dwGroup
|
|
);
|
|
|
|
|
|
ACQUIRE_PROTOCOL_LOCK_SHARED();
|
|
|
|
|
|
do
|
|
{
|
|
//
|
|
// Verify protocol handle
|
|
//
|
|
|
|
ppeEntry = (PPROTOCOL_ENTRY)
|
|
( ( (ULONG_PTR) hProtocol )
|
|
^ (ULONG_PTR) MGM_CLIENT_HANDLE_TAG );
|
|
|
|
dwErr = VerifyProtocolHandle( ppeEntry );
|
|
|
|
if ( dwErr != NO_ERROR )
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Get group bucket and find group entry
|
|
//
|
|
|
|
dwGrpBucket = GROUP_TABLE_HASH( pmimm-> dwGroup, 0 );
|
|
|
|
ACQUIRE_GROUP_LOCK_SHARED( dwGrpBucket );
|
|
bGrpLock = TRUE;
|
|
|
|
pge = GetGroupEntry(
|
|
GROUP_BUCKET_HEAD( dwGrpBucket ), pmimm-> dwGroup, 0
|
|
);
|
|
|
|
if ( pge == NULL )
|
|
{
|
|
dwErr = ERROR_NOT_FOUND;
|
|
|
|
TRACE1( ANY, "Group %lx not found", pmimm-> dwGroup );
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
ACQUIRE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
|
|
bgeLock = TRUE;
|
|
|
|
|
|
//
|
|
// Find source with group entry
|
|
//
|
|
|
|
dwSrcBucket = SOURCE_TABLE_HASH(
|
|
pmimm-> dwSource, pmimm-> dwSrcMask
|
|
);
|
|
|
|
pse = GetSourceEntry(
|
|
SOURCE_BUCKET_HEAD( pge, dwSrcBucket ), pmimm-> dwSource,
|
|
pmimm-> dwSrcMask
|
|
);
|
|
|
|
if ( pse == NULL )
|
|
{
|
|
dwErr = ERROR_NOT_FOUND;
|
|
|
|
TRACE1( ANY, "Source %lx not found", pmimm-> dwSource );
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Update the source entry
|
|
//
|
|
|
|
pse-> dwUpstreamNeighbor = pmimm-> dwUpStrmNgbr;
|
|
|
|
} while ( FALSE );
|
|
|
|
|
|
if ( bgeLock )
|
|
{
|
|
RELEASE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge );
|
|
}
|
|
|
|
|
|
if ( bGrpLock )
|
|
{
|
|
RELEASE_GROUP_LOCK_SHARED( dwGrpBucket );
|
|
}
|
|
|
|
RELEASE_PROTOCOL_LOCK_SHARED();
|
|
|
|
LEAVE_MGM_API();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Mgm MFE enumeration API.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
MgmGetMfe(
|
|
IN PMIB_IPMCAST_MFE pmimm,
|
|
IN OUT PDWORD pdwBufferSize,
|
|
IN OUT PBYTE pbBuffer
|
|
)
|
|
{
|
|
DWORD dwErr;
|
|
|
|
|
|
if ( !ENTER_MGM_API() )
|
|
{
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
TRACE1( ENTER, "ENTERED MgmGetMfe", *pdwBufferSize );
|
|
|
|
|
|
dwErr = GetMfe( pmimm, pdwBufferSize, pbBuffer, 0 );
|
|
|
|
|
|
TRACE1( ENTER, "LEAVING MgmGetMfe %x\n", dwErr );
|
|
|
|
LEAVE_MGM_API();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Mgm MFE enumeration API.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
DWORD
|
|
MgmGetFirstMfe(
|
|
IN OUT PDWORD pdwBufferSize,
|
|
IN OUT PBYTE pbBuffer,
|
|
IN OUT PDWORD pdwNumEntries
|
|
)
|
|
{
|
|
DWORD dwErr;
|
|
|
|
MIB_IPMCAST_MFE mimm;
|
|
|
|
|
|
|
|
if ( !ENTER_MGM_API() )
|
|
{
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
TRACE1( ENTER, "ENTERED MgmGetFirstMfe", *pdwBufferSize );
|
|
|
|
|
|
mimm.dwGroup = 0;
|
|
mimm.dwSource = 0;
|
|
mimm.dwSrcMask = 0;
|
|
|
|
dwErr = GetNextMfe(
|
|
&mimm, pdwBufferSize, pbBuffer, pdwNumEntries,
|
|
TRUE, 0
|
|
);
|
|
|
|
|
|
TRACE1( ENTER, "LEAVING MgmGetFirstMfe %x\n", dwErr );
|
|
|
|
LEAVE_MGM_API();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Mgm MFE enumeration API.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
MgmGetNextMfe(
|
|
IN PMIB_IPMCAST_MFE pmimmStart,
|
|
IN OUT PDWORD pdwBufferSize,
|
|
IN OUT PBYTE pbBuffer,
|
|
IN OUT PDWORD pdwNumEntries
|
|
)
|
|
{
|
|
|
|
DWORD dwErr;
|
|
|
|
|
|
|
|
if ( !ENTER_MGM_API() )
|
|
{
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
TRACE1( ENTER, "ENTERED MgmGetNextMfe", *pdwBufferSize );
|
|
|
|
|
|
dwErr = GetNextMfe(
|
|
pmimmStart, pdwBufferSize, pbBuffer, pdwNumEntries,
|
|
FALSE, 0
|
|
);
|
|
|
|
|
|
TRACE1( ENTER, "LEAVING MgmGetNextMfe %x\n", dwErr );
|
|
|
|
LEAVE_MGM_API();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Mgm MFE Statistics enumeration API.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
MgmGetMfeStats(
|
|
IN PMIB_IPMCAST_MFE pmimm,
|
|
IN OUT PDWORD pdwBufferSize,
|
|
IN OUT PBYTE pbBuffer,
|
|
IN DWORD dwFlags
|
|
)
|
|
{
|
|
DWORD dwErr;
|
|
|
|
|
|
if ( !ENTER_MGM_API() )
|
|
{
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
TRACE1( ENTER, "ENTERED MgmGetMfeStats", *pdwBufferSize );
|
|
|
|
|
|
dwErr = GetMfe( pmimm, pdwBufferSize, pbBuffer, dwFlags );
|
|
|
|
|
|
TRACE1( ENTER, "LEAVING MgmGetMfeStats %x\n", dwErr );
|
|
|
|
LEAVE_MGM_API();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Mgm MFE Statistics enumeration API.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
DWORD
|
|
MgmGetFirstMfeStats(
|
|
IN OUT PDWORD pdwBufferSize,
|
|
IN OUT PBYTE pbBuffer,
|
|
IN OUT PDWORD pdwNumEntries,
|
|
IN DWORD dwFlags
|
|
)
|
|
{
|
|
DWORD dwErr;
|
|
|
|
MIB_IPMCAST_MFE mimm;
|
|
|
|
|
|
|
|
if ( !ENTER_MGM_API() )
|
|
{
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
TRACE1( ENTER, "ENTERED MgmGetFirstMfeStats", *pdwBufferSize );
|
|
|
|
|
|
mimm.dwGroup = 0;
|
|
mimm.dwSource = 0;
|
|
mimm.dwSrcMask = 0;
|
|
|
|
dwErr = GetNextMfe(
|
|
&mimm, pdwBufferSize, pbBuffer, pdwNumEntries,
|
|
TRUE, dwFlags
|
|
);
|
|
|
|
|
|
TRACE1( ENTER, "LEAVING MgmGetFirstMfeStats %x\n", dwErr );
|
|
|
|
LEAVE_MGM_API();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Mgm MFE Statistics enumeration API.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
MgmGetNextMfeStats(
|
|
IN PMIB_IPMCAST_MFE pmimmStart,
|
|
IN OUT PDWORD pdwBufferSize,
|
|
IN OUT PBYTE pbBuffer,
|
|
IN OUT PDWORD pdwNumEntries,
|
|
IN DWORD dwFlags
|
|
)
|
|
{
|
|
|
|
DWORD dwErr;
|
|
|
|
|
|
|
|
if ( !ENTER_MGM_API() )
|
|
{
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
TRACE1( ENTER, "ENTERED MgmGetNextMfeStats", *pdwBufferSize );
|
|
|
|
|
|
dwErr = GetNextMfe(
|
|
pmimmStart, pdwBufferSize, pbBuffer, pdwNumEntries,
|
|
FALSE, dwFlags
|
|
);
|
|
|
|
|
|
TRACE1( ENTER, "LEAVING MgmGetNextMfeStats %x\n", dwErr );
|
|
|
|
LEAVE_MGM_API();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Group menbership entry enumeration API
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// MgmGroupEnumerationStart
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
MgmGroupEnumerationStart(
|
|
IN HANDLE hProtocol,
|
|
IN MGM_ENUM_TYPES metEnumType,
|
|
OUT HANDLE * phEnumHandle
|
|
)
|
|
{
|
|
DWORD dwErr = NO_ERROR;
|
|
|
|
PPROTOCOL_ENTRY ppeEntry;
|
|
|
|
PGROUP_ENUMERATOR pgeEnum;
|
|
|
|
|
|
|
|
|
|
if ( !ENTER_MGM_API() )
|
|
{
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
TRACE0( ENTER, "ENTERED MgmGroupEnumerationStart" );
|
|
|
|
ACQUIRE_PROTOCOL_LOCK_SHARED();
|
|
|
|
|
|
do
|
|
{
|
|
//
|
|
// verify protocol handle
|
|
//
|
|
|
|
ppeEntry = (PPROTOCOL_ENTRY)
|
|
( ( (ULONG_PTR) hProtocol )
|
|
^ (ULONG_PTR) MGM_CLIENT_HANDLE_TAG );
|
|
|
|
dwErr = VerifyProtocolHandle( ppeEntry );
|
|
|
|
if ( dwErr != NO_ERROR )
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// create an enumerator.
|
|
//
|
|
|
|
pgeEnum = MGM_ALLOC( sizeof( GROUP_ENUMERATOR ) );
|
|
|
|
if ( pgeEnum == NULL )
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
TRACE1(
|
|
ANY, "Failed to allocate group enumerator of size : %d",
|
|
sizeof( GROUP_ENUMERATOR )
|
|
);
|
|
|
|
LOGERR0( HEAP_ALLOC_FAILED, dwErr );
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
ZeroMemory( pgeEnum, sizeof( GROUP_ENUMERATOR ) );
|
|
|
|
pgeEnum-> dwSignature = MGM_ENUM_SIGNATURE;
|
|
|
|
|
|
//
|
|
// return handle to the enumerator.
|
|
//
|
|
|
|
*phEnumHandle = (HANDLE) ( ( (ULONG_PTR) pgeEnum )
|
|
^ (ULONG_PTR) MGM_ENUM_HANDLE_TAG );
|
|
|
|
} while ( FALSE );
|
|
|
|
|
|
RELEASE_PROTOCOL_LOCK_SHARED();
|
|
|
|
TRACE1( ENTER, "LEAVING MgmGroupEnumerationStart\n", dwErr );
|
|
|
|
LEAVE_MGM_API();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// MgmGroupEnumerationGetNext
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
MgmGroupEnumerationGetNext(
|
|
IN HANDLE hEnum,
|
|
IN OUT PDWORD pdwBufferSize,
|
|
IN OUT PBYTE pbBuffer,
|
|
IN OUT PDWORD pdwNumEntries
|
|
)
|
|
{
|
|
|
|
DWORD dwErr;
|
|
|
|
PGROUP_ENUMERATOR pgeEnum;
|
|
|
|
|
|
|
|
if ( !ENTER_MGM_API() )
|
|
{
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
TRACE0( ENTER, "ENTERED MgmGroupEnumerationGetNext" );
|
|
|
|
|
|
do
|
|
{
|
|
//
|
|
// verify enumeration handle
|
|
//
|
|
|
|
pgeEnum = VerifyEnumeratorHandle( hEnum );
|
|
|
|
if ( pgeEnum == NULL )
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// verify buffer has space for atleast one entry.
|
|
// Otherwise return error and note size required for
|
|
// atleast one entry.
|
|
//
|
|
|
|
if ( *pdwBufferSize < sizeof( SOURCE_GROUP_ENTRY ) )
|
|
{
|
|
dwErr = ERROR_INSUFFICIENT_BUFFER;
|
|
|
|
TRACE1( ANY, "Insufficient buffer size", dwErr );
|
|
|
|
*pdwBufferSize = sizeof( SOURCE_GROUP_ENTRY );
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
*pdwNumEntries = 0;
|
|
|
|
dwErr = GetNextGroupMemberships(
|
|
pgeEnum, pdwBufferSize, pbBuffer, pdwNumEntries
|
|
);
|
|
|
|
//
|
|
// This comment is to be moved, ignore it.
|
|
//
|
|
|
|
// If this is the first enumeration call (i.e this is
|
|
// the beginning of the enumeration) then include the
|
|
// (S, G) == (0, 0) entry if present.
|
|
//
|
|
// Usually this call would start with the (source, group)
|
|
// entry following the one mentioned in dwLastSource and
|
|
// dwLastGroup. This would result in the skipping of the
|
|
// entry at (0, 0) since the (dwLastSource, dwLastGroup) are
|
|
// initialized to (0, 0). To overcome this a special flag
|
|
// field is used to note the beginning of the enumeration.
|
|
//
|
|
|
|
//
|
|
// Check if this is the first enumeration call.
|
|
// If so include the (S, G) == (0, 0) entry.
|
|
//
|
|
} while ( FALSE );
|
|
|
|
TRACE0( ENTER, "LEAVING MgmGroupEnumerationGetNext\n" );
|
|
|
|
LEAVE_MGM_API();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// MgmGroupEnumerationEnd
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
MgmGroupEnumerationEnd(
|
|
IN HANDLE hEnum
|
|
)
|
|
{
|
|
DWORD dwErr = ERROR_INVALID_PARAMETER;
|
|
|
|
PGROUP_ENUMERATOR pgeEnum;
|
|
|
|
|
|
if ( !ENTER_MGM_API() )
|
|
{
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
TRACE0( ENTER, "ENTERED MgmGroupEnumerationEnd" );
|
|
|
|
pgeEnum = VerifyEnumeratorHandle( hEnum );
|
|
|
|
if ( pgeEnum != NULL )
|
|
{
|
|
MGM_FREE( pgeEnum );
|
|
|
|
dwErr = NO_ERROR;
|
|
}
|
|
|
|
TRACE1( ENTER, "LEAVING MgmGroupEnumerationEnd\n", dwErr );
|
|
|
|
LEAVE_MGM_API();
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
DisplayGroupTable(
|
|
)
|
|
{
|
|
|
|
#if UNIT_DBG
|
|
|
|
DWORD dwErr, dwBufSize, dwNumEntries;
|
|
|
|
PLIST_ENTRY pleGrp, pleGrpHead, pleSrc, pleSrcHead,
|
|
pleIf, pleIfHead;
|
|
|
|
PGROUP_ENTRY pge;
|
|
|
|
PSOURCE_ENTRY pse;
|
|
|
|
POUT_IF_ENTRY poie;
|
|
|
|
PBYTE pbBuffer = NULL;
|
|
|
|
MIB_IPMCAST_MFE imm;
|
|
|
|
PMIB_IPMCAST_MFE_STATS pimms;
|
|
|
|
|
|
|
|
//
|
|
// Enumerate the MFEs
|
|
// Since the forwarder is not present, stats are junk.
|
|
// so all mfe enum does is exercise the API and merge
|
|
// the master and temp lists so that the subsequent
|
|
// walks of this list can be done.
|
|
//
|
|
|
|
dwBufSize = 1024;
|
|
|
|
pbBuffer = HeapAlloc( GetProcessHeap(), 0, dwBufSize );
|
|
RtlZeroMemory( pbBuffer, dwBufSize );
|
|
|
|
dwErr = MgmGetFirstMfe( &dwBufSize, pbBuffer, &dwNumEntries );
|
|
|
|
if ( dwErr != NO_ERROR )
|
|
{
|
|
printf( "MgmGetFirstMfe returned error : %d\n", dwErr );
|
|
}
|
|
|
|
|
|
imm.dwSource = 0;
|
|
imm.dwSrcMask = 0xffffffff;
|
|
imm.dwGroup = 0;
|
|
RtlZeroMemory( pbBuffer, dwBufSize );
|
|
dwNumEntries = 0;
|
|
|
|
while ( MgmGetNextMfe( &imm, &dwBufSize, pbBuffer, &dwNumEntries )
|
|
== NO_ERROR )
|
|
{
|
|
if ( dwNumEntries == 0 )
|
|
{
|
|
break;
|
|
}
|
|
|
|
pimms = (PMIB_IPMCAST_MFE_STATS) pbBuffer;
|
|
|
|
imm.dwSource = pimms-> dwSource;
|
|
imm.dwSrcMask = pimms-> dwSrcMask;
|
|
imm.dwGroup = pimms-> dwGroup;
|
|
|
|
pimms = (PMIB_IPMCAST_MFE_STATS) ( (PBYTE) pimms +
|
|
SIZEOF_MIB_MFE_STATS( pimms-> ulNumOutIf ) );
|
|
}
|
|
|
|
if ( dwErr != NO_ERROR )
|
|
{
|
|
printf( "MgmGetNextMfe returned error : %d\n", dwErr );
|
|
}
|
|
|
|
|
|
//
|
|
// since there is no kernel mode forwarder, just walk the master
|
|
// list of group entries and display all the group entries
|
|
//
|
|
|
|
pleGrpHead = MASTER_GROUP_LIST_HEAD();
|
|
|
|
pleGrp = pleGrpHead-> Flink;
|
|
|
|
while ( pleGrp != pleGrpHead )
|
|
{
|
|
//
|
|
// display the group entry
|
|
//
|
|
|
|
pge = CONTAINING_RECORD( pleGrp, GROUP_ENTRY, leGrpList );
|
|
|
|
printf( "\n\n====================================================\n" );
|
|
printf( "Group Addr\t: %x, %x\n", pge-> dwGroupAddr, pge-> dwGroupMask );
|
|
printf( "Num Sources\t: %d\n", pge-> dwSourceCount );
|
|
printf( "====================================================\n\n" );
|
|
|
|
|
|
pleSrcHead = MASTER_SOURCE_LIST_HEAD( pge );
|
|
|
|
pleSrc = pleSrcHead-> Flink;
|
|
|
|
while ( pleSrc != pleSrcHead )
|
|
{
|
|
pse = CONTAINING_RECORD( pleSrc, SOURCE_ENTRY, leSrcList );
|
|
|
|
printf( "\n-----------------------Source----------------------------------" );
|
|
printf( "\nSource Addr\t: %x, %x\n", pse-> dwSourceAddr, pse-> dwSourceMask );
|
|
|
|
printf(
|
|
"Route Addr\t: %x, %x\n", pse-> dwRouteNetwork, pse-> dwRouteMask
|
|
);
|
|
|
|
printf(
|
|
"Out if component: %d\nOut if count\t: %d\n\n", pse-> dwOutCompCount,
|
|
pse-> dwOutIfCount
|
|
);
|
|
|
|
printf(
|
|
"In coming interface : %d, %x\n", pse-> dwInIfIndex,
|
|
pse-> dwInIfNextHopAddr
|
|
);
|
|
|
|
printf(
|
|
"In Protocol id : %x, %x\n\n", pse-> dwInProtocolId,
|
|
pse-> dwInComponentId
|
|
);
|
|
|
|
//
|
|
// list all outgoing interfaces
|
|
//
|
|
|
|
pleIfHead = &pse-> leOutIfList;
|
|
|
|
pleIf = pleIfHead-> Flink;
|
|
|
|
printf( "\n----------------------Out Interfaces-----------------\n" );
|
|
|
|
while ( pleIf != pleIfHead )
|
|
{
|
|
poie = CONTAINING_RECORD( pleIf, OUT_IF_ENTRY, leIfList );
|
|
|
|
printf(
|
|
"Out interface\t: %d, %x\n", poie-> dwIfIndex,
|
|
poie-> dwIfNextHopAddr
|
|
);
|
|
|
|
printf(
|
|
"Out Protocol id\t: %x, %x\n", poie-> dwProtocolId,
|
|
poie-> dwComponentId
|
|
);
|
|
|
|
printf(
|
|
"Added by\t: %x\n", poie-> wAddedByFlag
|
|
);
|
|
|
|
printf(
|
|
"Num adds (IGMP, RP)\t: (%d, %d)\n\n", poie-> wNumAddsByIGMP,
|
|
poie-> wNumAddsByRP
|
|
);
|
|
|
|
pleIf = pleIf-> Flink;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// list mfe oil
|
|
//
|
|
|
|
pleIfHead = &pse-> leMfeIfList;
|
|
|
|
pleIf = pleIfHead-> Flink;
|
|
|
|
printf( "\n------------------Mfe Out Interfaces-----------------\n" );
|
|
|
|
while ( pleIf != pleIfHead )
|
|
{
|
|
poie = CONTAINING_RECORD( pleIf, OUT_IF_ENTRY, leIfList );
|
|
|
|
printf(
|
|
"Out interface\t: %d, %x\n", poie-> dwIfIndex,
|
|
poie-> dwIfNextHopAddr
|
|
);
|
|
|
|
printf(
|
|
"Out Protocol id\t: %x, %x\n", poie-> dwProtocolId,
|
|
poie-> dwComponentId
|
|
);
|
|
|
|
printf(
|
|
"Added by\t:%x\n", poie-> wAddedByFlag
|
|
);
|
|
|
|
printf(
|
|
"Num adds (IGMP, RP)\t: (%d, %d)\n\n", poie-> wNumAddsByIGMP,
|
|
poie-> wNumAddsByRP
|
|
);
|
|
|
|
pleIf = pleIf-> Flink;
|
|
}
|
|
|
|
pleSrc = pleSrc-> Flink;
|
|
}
|
|
|
|
pleGrp = pleGrp-> Flink;
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|