|
|
//============================================================================
// 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; }
|