windows-nt/Source/XPSP1/NT/net/rras/mgm/if.c
2020-09-26 16:20:57 +08:00

935 lines
21 KiB
C

//============================================================================
// Copyright (c) 1995, Microsoft Corporation
//
// File: if.c
//
// History:
// V Raman June-25-1997 Created.
//
// routines that manipulate interface entries
//============================================================================
#include "pchmgm.h"
#pragma hdrstop
//----------------------------------------------------------------------------
// CreateIfEntry
//
// This function creates a new interface entry. Duh
// Assumes that the interface list is locked.
//----------------------------------------------------------------------------
DWORD
CreateIfEntry(
PLIST_ENTRY pleIfList,
DWORD dwIfIndex,
DWORD dwIfNextHopAddr,
DWORD dwProtocolId,
DWORD dwComponentId
)
{
DWORD dwErr = NO_ERROR;
PIF_ENTRY pie = NULL, pieEntry = NULL;
TRACEIF4(
IF,
"ENTERED CreateIfEntry : Interface %x, %x : Protocol %x, %x",
dwIfIndex, dwIfNextHopAddr, dwProtocolId, dwComponentId
);
do
{
//
// allocate an interface entry.
//
pie = MGM_ALLOC( sizeof( IF_ENTRY ) );
if ( pie == NULL )
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
TRACE1(
ANY, "CreateIfEntry : Failed to allocate entry %x", dwErr
);
LOGERR0( HEAP_ALLOC_FAILED, dwErr );
break;
}
ZeroMemory( pie, sizeof( IF_ENTRY ) );
//
// init. i/f structure
//
pie-> dwIfIndex = dwIfIndex;
pie-> dwIfNextHopAddr = dwIfNextHopAddr;
pie-> dwOwningProtocol = dwProtocolId;
pie-> dwOwningComponent = dwComponentId;
pie-> wAddedByFlag = 0;
if ( IS_PROTOCOL_ID_IGMP( dwProtocolId ) )
{
SET_ADDED_BY_IGMP( pie );
}
else
{
SET_ADDED_BY_PROTOCOL( pie );
}
InitializeListHead( &pie-> leInIfList );
InitializeListHead( &pie-> leOutIfList );
//
// insert in protocol list
//
InitializeListHead( &pie-> leIfHashList );
InsertTailList( pleIfList, &pie-> leIfHashList );
} while ( FALSE );
TRACEIF1( IF, "LEAVING CreateIfEntry : %x", dwErr );
return dwErr;
}
//----------------------------------------------------------------------------
// DeleteIfEntry
//
// This function deletes an interface entry. Duh
// Assumes that the interface list is locked.
//----------------------------------------------------------------------------
VOID
DeleteIfEntry(
PIF_ENTRY pieEntry
)
{
TRACEIF0( IF, "ENTERED DeleteIfEntry" );
RemoveEntryList( &pieEntry-> leIfHashList );
MGM_FREE( pieEntry );
TRACEIF0( IF, "LEAVING DeleteIfEntry" );
}
//----------------------------------------------------------------------------
// GetIfEntry
//
// This function retrieves an interface entry. Duh
//
// Assumes that the interface list is locked.
//----------------------------------------------------------------------------
PIF_ENTRY
GetIfEntry(
PLIST_ENTRY pleIfList,
DWORD dwIfIndex,
DWORD dwIfNextHopAddr
)
{
PIF_ENTRY pie;
if ( FindIfEntry( pleIfList, dwIfIndex, dwIfNextHopAddr, &pie ) )
{
return pie;
}
return NULL;
}
//----------------------------------------------------------------------------
// FindIfEntry
//
// This function retrieves an interface entry. Duh
//
// Assumes that the interface list is locked.
//----------------------------------------------------------------------------
BOOL
FindIfEntry(
PLIST_ENTRY pleIfList,
DWORD dwIfIndex,
DWORD dwIfNextHopAddr,
PIF_ENTRY * ppie
)
{
BOOL bFound = FALSE;
INT iCmp = 0;
PIF_ENTRY pie = NULL;
PLIST_ENTRY ple = NULL;
TRACEIF2( IF, "ENTERED FindIfEntry : %x, %x", dwIfIndex, dwIfNextHopAddr );
//
// Scan interface list. Interface list is ordered by
// interface index, next hop address
//
*ppie = NULL;
for ( ple = pleIfList-> Flink; ple != pleIfList; ple = ple-> Flink )
{
pie = CONTAINING_RECORD( ple, IF_ENTRY, leIfHashList );
if ( pie-> dwIfIndex < dwIfIndex )
{
continue;
}
else if ( pie-> dwIfIndex > dwIfIndex )
{
//
// Entry not present
//
*ppie = pie;
break;
}
if ( INET_CMP( pie-> dwIfNextHopAddr, dwIfNextHopAddr, iCmp ) < 0 )
{
continue;
}
else if ( iCmp > 0 )
{
*ppie = pie;
break;
}
*ppie = pie;
bFound = TRUE;
break;
}
TRACEIF1( IF, "LEAVING FindIfEntry : %x", bFound );
return bFound;
}
//----------------------------------------------------------------------------
// AddSourceToOutList
//
// Each interface entry maintains a list of (source, group) entries that
// reference this interface in their outgoing interface list. Each time
// membership entry is added the (source, group) to the reference list.
// When this interface is eventually deleted these (source, group) entries
// need to be updated to reflect the deletion of this interface.
//
// Assumes that the interface entry is locked.
//----------------------------------------------------------------------------
VOID
AddSourceToRefList(
PLIST_ENTRY pleRefList,
DWORD dwSourceAddr,
DWORD dwSourceMask,
DWORD dwGroupAddr,
DWORD dwGroupMask,
BOOL bIGMP
)
{
BOOL bFound = FALSE;
DWORD dwErr = NO_ERROR;
PIF_REFERENCE_ENTRY pire = NULL, pireNew = NULL;
TRACEIF5(
IF,
"ENTERED AddSourceToIfEntry : Source %x, %x : Group %x, %x"
" : IGMP %x",
dwSourceAddr, dwSourceMask, dwGroupAddr, dwGroupMask, bIGMP
);
do
{
//
// Check if reference already present
//
bFound = FindRefEntry(
pleRefList, dwSourceAddr, dwSourceMask,
dwGroupAddr, dwGroupMask, &pire
);
if ( !bFound )
{
//
// no previous reference for this (source, group) was found
// create a new one.
//
pireNew = MGM_ALLOC( sizeof( IF_REFERENCE_ENTRY ) );
if ( pireNew == NULL )
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
TRACE1(
ANY,
"AddSourceToOutList : Failed to allocate reference entry %x",
dwErr
);
LOGERR0( HEAP_ALLOC_FAILED, dwErr );
break;
}
ZeroMemory( pireNew, sizeof( IF_REFERENCE_ENTRY ) );
pireNew-> dwSourceAddr = dwSourceAddr;
pireNew-> dwSourceMask = dwSourceMask;
pireNew-> dwGroupAddr = dwGroupAddr;
pireNew-> dwGroupMask = dwGroupMask;
pireNew-> wAddedByFlag = 0;
//
// set the appropriate bit for the protocol
//
if ( bIGMP )
{
SET_ADDED_BY_IGMP( pireNew );
}
else
{
SET_ADDED_BY_PROTOCOL( pireNew );
}
//
// insert into ref list
//
if ( pire == NULL )
{
InsertTailList( pleRefList, &pireNew-> leRefList );
}
else
{
InsertTailList( &pire-> leRefList, &pireNew-> leRefList );
}
}
else
{
//
// set the appropriate bit for the protocol
//
if ( bIGMP )
{
SET_ADDED_BY_IGMP( pire );
}
else
{
SET_ADDED_BY_PROTOCOL( pire );
}
}
} while ( FALSE );
TRACEIF1( IF, "LEAVING AddSourceToRefList : %x", bFound );
return;
}
//----------------------------------------------------------------------------
// DeleeSourceFomrRefList
//
// Delete a reference to a (source, group).
//----------------------------------------------------------------------------
VOID
DeleteSourceFromRefList(
PLIST_ENTRY pleIfRefList,
DWORD dwSourceAddr,
DWORD dwSourceMask,
DWORD dwGroupAddr,
DWORD dwGroupMask,
BOOL bIGMP
)
{
BOOL bFound = FALSE;
PIF_REFERENCE_ENTRY pire = NULL, pireEntry = NULL;
TRACEIF5(
IF,
"ENTERED DeleteSourceFromIfEntry : Source %x %x, Group : %x, %x"
" : IGMP %x",
dwSourceAddr, dwSourceMask, dwGroupAddr, dwGroupMask, bIGMP
);
//
// find the entry is already present.
// list is arranged in descending order in terms of
// Group address, source address
//
bFound = FindRefEntry(
pleIfRefList, dwSourceAddr, dwSourceMask,
dwGroupAddr, dwGroupMask, &pire
);
//
// if entry was not found
//
if ( !bFound )
{
TRACE1( IF, "LEAVING DeleteSourceFromRefList : %x", FALSE );
return;
}
//
// reset the appropriate bit for the protocol
//
if ( bIGMP )
{
CLEAR_ADDED_BY_IGMP( pire );
}
else
{
CLEAR_ADDED_BY_PROTOCOL( pire );
}
//
// if no more references left, remove this entry
//
if ( !IS_ADDED_BY_IGMP( pire ) &&
!IS_ADDED_BY_PROTOCOL( pire ) )
{
RemoveEntryList( &pire-> leRefList );
MGM_FREE( pire );
}
TRACEIF1( IF, "LEAVING DeleteSourceFromRefList : %x", TRUE );
return;
}
//----------------------------------------------------------------------------
// FindRefEntry
//
// Locate a reference entry. If not found return the expected location in
// the list.
//----------------------------------------------------------------------------
BOOL
FindRefEntry(
PLIST_ENTRY pleRefList,
DWORD dwSourceAddr,
DWORD dwSourceMask,
DWORD dwGroupAddr,
DWORD dwGroupMask,
PIF_REFERENCE_ENTRY * ppire
)
{
INT iCmp;
PLIST_ENTRY ple = NULL;
PIF_REFERENCE_ENTRY pire = NULL;
BOOL bFound = FALSE;
TRACEIF4(
IF,
"ENTERED FindRefEntry : Source %x, %x : Group %x, %x",
dwSourceAddr, dwSourceMask, dwGroupAddr, dwGroupMask
);
*ppire = NULL;
for ( ple = pleRefList-> Flink; ple != pleRefList; ple = ple-> Flink )
{
pire = CONTAINING_RECORD( ple, IF_REFERENCE_ENTRY, leRefList );
if ( INET_CMP( pire-> dwGroupAddr, dwGroupAddr, iCmp ) < 0 )
{
continue;
}
else if ( iCmp > 0 )
{
//
// you are now past the position where an existing
// entry would be.
//
*ppire = pire;
break;
}
if ( INET_CMP( pire-> dwSourceAddr, dwSourceAddr, iCmp ) < 0 )
{
continue;
}
else if ( iCmp > 0 )
{
//
// you are now past the position where an existing
// entry would be.
//
*ppire = pire;
break;
}
//
// entry found
//
*ppire = pire;
bFound = TRUE;
break;
}
TRACEIF1( IF, "LEAVING FindRefEntry : %x", bFound );
return bFound;
}
//----------------------------------------------------------------------------
// DeleteOutInterfaceRefs
//
// When a interface is deleted by a protocol (or IGMP) all (source, group)
// entries that use this interface in their outgoing interface lists have to
// be updated to reflect ththe deletion.
//
//----------------------------------------------------------------------------
VOID
DeleteOutInterfaceRefs(
PPROTOCOL_ENTRY ppe,
PIF_ENTRY pie,
BOOL bIGMP
)
{
PLIST_ENTRY ple = NULL, pleRefList = NULL, pleNext = NULL;
PIF_REFERENCE_ENTRY pire = NULL;
TRACEIF1( IF, "ENTERED DeleteOutInterfaceRefs: IGMP %x", bIGMP );
do
{
//
// No references for this interface in any outgoing
// interface lists of source entries
//
pleRefList = &pie-> leOutIfList;
if ( IsListEmpty( pleRefList ) )
{
break;
}
//
// walk the reference list and remove the (source, group) entries
// for each reference
//
for ( ple = pleRefList-> Flink; ple != pleRefList; )
{
pire = CONTAINING_RECORD( ple, IF_REFERENCE_ENTRY, leRefList );
//
// was this reference added by this protocol
//
if ( ( bIGMP && !IS_ADDED_BY_IGMP( pire ) ) ||
( !bIGMP && !IS_ADDED_BY_PROTOCOL( pire ) ) )
{
//
// no, skip it
//
ple = ple-> Flink;
continue;
}
//
// Delete this interface from the (source, group) entry.
//
DeleteInterfaceFromSourceEntry(
ppe,
pire-> dwGroupAddr, pire-> dwGroupMask,
pire-> dwSourceAddr, pire-> dwSourceMask,
pie-> dwIfIndex, pie-> dwIfNextHopAddr,
bIGMP
);
if ( bIGMP )
{
CLEAR_ADDED_BY_IGMP( pire );
}
else
{
CLEAR_ADDED_BY_PROTOCOL( pire );
}
//
// remove reference entry.
//
if ( !IS_ADDED_BY_IGMP( pire ) &&
!IS_ADDED_BY_PROTOCOL( pire ) )
{
//
// no more references to interface for IGMP
// or for routing protocol.
// remove this reference entry altogether.
//
pleNext = ple-> Flink;
RemoveEntryList( ple );
MGM_FREE ( pire );
ple = pleNext;
}
else
{
ple = ple-> Flink;
}
}
} while ( FALSE );
TRACEIF0( IF, "LEAVING DeleteOutInterfaceRefs:" );
return;
}
//----------------------------------------------------------------------------
// DeleteInInterfaceRefs
//
// When a interface is deleted by a protocol (or IGMP) all (source, group)
// entries that use this interface as their incoming interface have to
// be updated to reflect the deletion.
//----------------------------------------------------------------------------
VOID
DeleteInInterfaceRefs(
PLIST_ENTRY pleRefList
)
{
PLIST_ENTRY ple = NULL;
PIF_REFERENCE_ENTRY pire = NULL;
TRACEIF0( IF, "Entering DeleteInInterfaceRefs" );
while ( !IsListEmpty( pleRefList ) )
{
ple = RemoveHeadList( pleRefList );
pire = CONTAINING_RECORD( ple, IF_REFERENCE_ENTRY, leRefList );
//
// A Zappaesque function call here
//
LookupAndDeleteYourMfe(
pire-> dwSourceAddr, pire-> dwSourceMask,
pire-> dwGroupAddr, pire-> dwGroupMask,
TRUE, NULL, NULL
);
MGM_FREE( pire );
}
TRACEIF0( IF, "LEAVING DeleteInInterfaceRefs" );
}
//----------------------------------------------------------------------------
// TransferInterfaceOwnershipToProtocol
//
//
//----------------------------------------------------------------------------
DWORD
TransferInterfaceOwnershipToProtocol(
PPROTOCOL_ENTRY ppe,
PIF_ENTRY pie
)
{
DWORD dwErr = NO_ERROR;
PPROTOCOL_ENTRY ppeIgmp;
do
{
//
// get protocol entry for IGMP
//
ppeIgmp = GetProtocolEntry(
PROTOCOL_LIST_HEAD(), pie-> dwOwningProtocol,
pie-> dwOwningComponent
);
if ( ppeIgmp == NULL )
{
//
// interface is owned by IGMP, but protocol entry is not
// present for IGMP. MGM data is in an inconsistent state
//
dwErr = ERROR_UNKNOWN;
TRACE2(
ANY, "TransferInterfaceOwnershipToProtocol : Could not find"
" IGMP protocol entry", pie-> dwIfIndex,
pie-> dwIfNextHopAddr
);
break;
}
//
// indicate to IGMP that interface has been disabled. This should
// stop IGMP from adding state to this interface while it is being
// transferred to the protocol
//
IGMP_DISABLE_CALLBACK( ppeIgmp ) (
pie-> dwIfIndex, pie-> dwIfNextHopAddr
);
//
// delete all IGMP references in and out
//
DeleteInInterfaceRefs( &pie-> leInIfList );
DeleteOutInterfaceRefs( ppeIgmp, pie, TRUE );
//
// mark interface as added by Routing protocol
//
SET_ADDED_BY_PROTOCOL( pie );
pie-> dwOwningProtocol = ppe-> dwProtocolId;
pie-> dwOwningComponent = ppe-> dwComponentId;
//
// indicate to IGMP that interface has been enabled.
//
IGMP_ENABLE_CALLBACK( ppeIgmp ) (
pie-> dwIfIndex, pie-> dwIfNextHopAddr
);
} while ( FALSE );
return dwErr;
}
//----------------------------------------------------------------------------
// TransferInterfaceOwnershipToIGMP
//
//
//----------------------------------------------------------------------------
DWORD
TransferInterfaceOwnershipToIGMP(
PPROTOCOL_ENTRY ppe,
PIF_ENTRY pie
)
{
DWORD dwErr = NO_ERROR;
PPROTOCOL_ENTRY ppeIgmp;
do
{
//
// get IGMP protocol entry
//
ppeIgmp = GetIgmpProtocolEntry( PROTOCOL_LIST_HEAD() );
if ( ppeIgmp == NULL )
{
//
// interface is has IGMP enabled on it, but a protocol entry is not
// present for IGMP. MGM data is in an inconsistent state
//
dwErr = ERROR_UNKNOWN;
TRACE2(
ANY, "TransferInterfaceOwnershipToProtocol : Could not find"
" IGMP protocol entry", pie-> dwIfIndex,
pie-> dwIfNextHopAddr
);
break;
}
//
// indicate to IGMP that interface has been disabled. This should
// stop IGMP from adding state to this interface while it is being
// transferred to IGMP
//
IGMP_DISABLE_CALLBACK( ppeIgmp ) (
pie-> dwIfIndex, pie-> dwIfNextHopAddr
);
//
// delete all protocol references (in and out)
//
DeleteInInterfaceRefs( &pie-> leInIfList );
DeleteOutInterfaceRefs( ppe, pie, FALSE );
CLEAR_ADDED_BY_PROTOCOL( pie );
//
// delete all IGMP references, these will get added back by
// IGMP when is enabled on this interface. This is done
// below.
//
DeleteOutInterfaceRefs( ppe, pie, TRUE );
//
// Mark interface as being owned by IGMP
//
pie-> dwOwningProtocol = ppeIgmp-> dwProtocolId;
pie-> dwOwningComponent = ppeIgmp-> dwComponentId;
//
// enable IGMP on the interface
//
IGMP_ENABLE_CALLBACK( ppeIgmp ) (
pie-> dwIfIndex, pie-> dwIfNextHopAddr
);
} while ( FALSE );
return dwErr;
}