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