|
|
//============================================================================
// Copyright (c) 1995, Microsoft Corporation
//
// File: route.c
//
// History:
// V Raman Feb-5-1998 Created.
//
// Routines that manipulate routes entries
//============================================================================
#include "pchmgm.h"
#pragma hdrstop
//----------------------------------------------------------------------------
//
// Route reference operations
//
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// AddSourceGroupToRouteRefList
//
// This function inserts a reference for each MFE that uses this route
// for it RPF check. It is invoked by the new packet function on creation
// of an MFE.
//----------------------------------------------------------------------------
VOID AddSourceGroupToRouteRefList( DWORD dwSourceAddr, DWORD dwSourceMask, DWORD dwGroupAddr, DWORD dwGroupMask, HANDLE hNextHop, PBYTE pbBuffer ) { BOOL bUnLock = FALSE, bMark = FALSE;
DWORD dwErr;
PMGM_LOCKED_LIST pmllMfeList;
PBYTE pbOpaqueInfo = NULL;
PRTM_DEST_INFO prdi = (PRTM_DEST_INFO) pbBuffer;
PROUTE_REFERENCE_ENTRY prre = NULL, prreNew = NULL;
TRACEROUTE0( ROUTE, "ENTERED AddSourceGroupToRouteRefList" );
do { //
// Create a route reference entry
//
prre = MGM_ALLOC( sizeof( ROUTE_REFERENCE_ENTRY ) );
if ( prre == NULL ) { dwErr = ERROR_NOT_ENOUGH_MEMORY;
TRACE1( ANY, "Failed to allocate %d bytes", sizeof( ROUTE_REFERENCE_ENTRY ) );
break; }
prre-> dwSourceAddr = dwSourceAddr; prre-> dwSourceMask = dwSourceMask;
prre-> dwGroupAddr = dwGroupAddr; prre-> dwGroupMask = dwGroupMask;
prre-> hNextHop = hNextHop;
InitializeListHead ( &prre-> leRefList );
//
// Lock the dest
//
dwErr = RtmLockDestination( g_hRtmHandle, prdi-> DestHandle, TRUE, TRUE );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to lock dest %x", dwErr );
break; }
bUnLock = TRUE;
//
// Get the opaque pointer
//
dwErr = RtmGetOpaqueInformationPointer( g_hRtmHandle, prdi-> DestHandle, &pbOpaqueInfo );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to retrieve opaque pointer %x", dwErr );
break; }
if ( *( ( PBYTE * ) pbOpaqueInfo ) == NULL ) { //
// NULL opaque pointer implies this is the first MFe that
// depends on this route
//
//
// create a locked list
//
pmllMfeList = MGM_ALLOC( sizeof( MGM_LOCKED_LIST ) );
if ( pmllMfeList == NULL ) { dwErr = ERROR_NOT_ENOUGH_MEMORY;
TRACE1( ANY, "AddSourceGroupToRouteRefList : " "Failed to allocate route ref list %x", dwErr );
break; }
CREATE_LOCKED_LIST( pmllMfeList );
//
// insert the element into the list
//
InsertTailList( &( pmllMfeList-> leHead ), &( prre-> leRefList ) );
//
// set the opaque pointer
//
*( ( PBYTE *) pbOpaqueInfo ) = (PBYTE) pmllMfeList;
//
// Mark the destination
//
bMark = TRUE; }
else { pmllMfeList = ( PMGM_LOCKED_LIST ) *( ( PBYTE *) pbOpaqueInfo );
//
// Acquire the list lock
//
ACQUIRE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList );
//
// release the dest lock
//
bUnLock = FALSE;
dwErr = RtmLockDestination( g_hRtmHandle, prdi-> DestHandle, TRUE, FALSE );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to release dest %x", dwErr ); }
//
// Insert the rre into the list (in its appropriate place)
//
if ( !FindRouteRefEntry( &pmllMfeList-> leHead, dwSourceAddr, dwSourceMask, dwGroupAddr, dwGroupMask, &prreNew ) ) { InsertTailList( ( prreNew ) ? &prreNew-> leRefList : &pmllMfeList-> leHead, &prre-> leRefList ); }
else { TRACE1( ANY, "Reference already exists for source %x", dwSourceAddr );
MGM_FREE( prre ); }
//
// release the list lock
//
RELEASE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList );
dwErr = NO_ERROR; }
} while ( FALSE );
//
// In case of error , free the allocation for route reference
//
if ( ( dwErr != NO_ERROR ) && ( prre != NULL ) ) { MGM_FREE( prre ); }
//
// release the dest lock
//
if ( bUnLock ) { dwErr = RtmLockDestination( g_hRtmHandle, prdi-> DestHandle, TRUE, FALSE );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to release dest %x", dwErr ); } }
//
// mark dest if required
//
if ( bMark ) { dwErr = RtmMarkDestForChangeNotification( g_hRtmHandle, g_hNotificationHandle, prdi-> DestHandle, TRUE );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to mark destination %x:", dwErr ); } }
TRACEROUTE0( ROUTE, "LEAVING AddSourceGroupToRouteRefList" ); }
//----------------------------------------------------------------------------
// FindRouteRefEntry
//
// Finds a specified (source, group ) entry in the MFE reference list
// for a route.
//
// If the entry is found a pointer to the entry is returned in the parameter
// pprre.
// If the entry is not found a pointer to the "next" entry is returned.
//----------------------------------------------------------------------------
BOOL FindRouteRefEntry( PLIST_ENTRY pleRefList, DWORD dwSourceAddr, DWORD dwSourceMask, DWORD dwGroupAddr, DWORD dwGroupMask, PROUTE_REFERENCE_ENTRY * pprre ) { BOOL bFound = FALSE;
INT iCmp;
PLIST_ENTRY pleRef;
PROUTE_REFERENCE_ENTRY prre;
TRACEROUTE0( ROUTE, "ENTERED RouteRefEntry" );
do { *pprre = NULL;
pleRef = pleRefList-> Flink;
while ( pleRef != pleRefList ) { prre = CONTAINING_RECORD( pleRef, ROUTE_REFERENCE_ENTRY, leRefList );
//
// is same group
//
if ( INET_CMP( prre-> dwGroupAddr, dwGroupAddr, iCmp ) < 0 ) { pleRef = pleRef-> Flink;
continue; }
else if ( iCmp > 0 ) { //
// past possible group entry
//
*pprre = prre;
break; }
//
// same group, now look for source
//
if ( INET_CMP( prre-> dwSourceAddr, dwSourceAddr, iCmp ) < 0 ) { pleRef = pleRef-> Flink;
continue; }
else if ( iCmp > 0 ) { //
// past possible source entry
//
*pprre = prre;
break; }
//
// found entry
//
*pprre = prre;
bFound = TRUE;
break; }
} while ( FALSE );
TRACEROUTE1( ROUTE, "LEAVING RouteRefEntry : %d", bFound );
return bFound; }
//----------------------------------------------------------------------------
// DeletRouteRef
//
//----------------------------------------------------------------------------
VOID DeleteRouteRef( PROUTE_REFERENCE_ENTRY prre ) { TRACEROUTE0( ROUTE, "ENTERED DeleteRefEntry" );
RemoveEntryList( &prre-> leRefList );
MGM_FREE( prre );
TRACEROUTE0( ROUTE, "LEAVING DeleteRefEntry" ); }
DWORD WINAPI RtmChangeNotificationCallback( RTM_ENTITY_HANDLE hRtmHandle, RTM_EVENT_TYPE retEventType, PVOID pvContext1, PVOID pvContext2 ) { DWORD dwErr = NO_ERROR;
if ( !ENTER_MGM_API() ) { TRACE0( ANY, "RtmChangeNotificationCallback : Failed to enter" );
return ERROR_CAN_NOT_COMPLETE; }
TRACE0( ROUTE, "ENTERED RtmChangeNotificationCallback" );
do { //
// Ignore all notifications except change notifications
//
if ( retEventType != RTM_CHANGE_NOTIFICATION ) { break; }
//
// Queue work function to process changed destinations
//
dwErr = QueueMgmWorker( WorkerFunctionProcessRtmChangeNotification, NULL );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to queue work item", dwErr ); }
} while ( FALSE );
LEAVE_MGM_API();
TRACE1( ROUTE, "LEAVING RtmChangeNotificationCallback : %d", dwErr );
return dwErr; }
VOID WorkerFunctionProcessRtmChangeNotification( PVOID pvContext ) { BOOL bMarked = FALSE, bDone = FALSE;
DWORD dwErr, dwNumDests;
RTM_DEST_INFO rdi;
if ( !ENTER_MGM_WORKER() ) { TRACE0( ANY, "WorkerFunctionProcessRtmChangeNotification : Failed to enter" );
return; }
TRACE0( ROUTE, "ENTERED WorkerFunctionRtmChangeNotification" );
do { //
// Get route changes one at a time
//
dwNumDests = 1;
dwErr = RtmGetChangedDests( g_hRtmHandle, g_hNotificationHandle, &dwNumDests, &rdi );
if ( ( dwErr != NO_ERROR ) && ( dwErr != ERROR_NO_MORE_ITEMS ) ) { TRACE1( ANY, "RtmGetChangedDests failed with error : %x", dwErr );
break; }
//
// if there are no changed dests, quit.
//
if ( dwNumDests == 0 ) { TRACE0( ANY, "RtmGetChangedDests returns 0 dests" );
break; }
//
// There are dests. Check if there are no more dests.
// If so set a flag to quit processing after this one
//
if ( dwErr == ERROR_NO_MORE_ITEMS ) { bDone = TRUE; }
//
// Check if there any routes for this destination
//
if ( rdi.ViewInfo[ 0 ].Route == NULL ) { //
// No routes, assume this to be a delete
//
dwErr = ProcessRouteDelete( &rdi ); }
else { //
// Check if dest is marked for change notification
//
dwErr = RtmIsMarkedForChangeNotification( g_hRtmHandle, g_hNotificationHandle, rdi.DestHandle, &bMarked );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "RtmIsMarkedForChangeNotification failed with error : %x", dwErr );
break; }
//
// Process this destination
//
( bMarked ) ? ProcessRouteUpdate( &rdi ) : ProcessUnMarkedDestination( &rdi );
} while ( FALSE );
//
// Release changed destinations
//
dwErr = RtmReleaseChangedDests( g_hRtmHandle, g_hNotificationHandle, 1, &rdi );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to released destination", dwErr ); }
} while ( !bDone );
LEAVE_MGM_WORKER();
TRACE0( ROUTE, "LEAVING WorkerFunctionRtmChangeNotification" ); }
DWORD ProcessUnMarkedDestination( PRTM_DEST_INFO prdi ) { BOOL bRelDest = FALSE, bMarked = FALSE, bUnLock = FALSE, bRelRouteRef = FALSE, bUnMark = FALSE;
DWORD dwErr, dwDestMask;
PBYTE pbOpaqueInfo = NULL;
PLIST_ENTRY ple, pleTemp;
PROUTE_REFERENCE_ENTRY prre;
PMGM_LOCKED_LIST pmllMfeList = NULL;
RTM_DEST_INFO rdiLessSpecificDest;
do { //
// Get next less specific destination
//
dwErr = RtmGetLessSpecificDestination( g_hRtmHandle, prdi-> DestHandle, RTM_BEST_PROTOCOL, RTM_VIEW_MASK_MCAST, &rdiLessSpecificDest );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to get less specific destination", dwErr );
break; }
bRelDest = TRUE;
//
// Check if it is marked
//
dwErr = RtmIsMarkedForChangeNotification( g_hRtmHandle, g_hNotificationHandle, rdiLessSpecificDest.DestHandle, &bMarked );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to check if dest is marked", dwErr );
break; }
//
// if marked
//
if ( bMarked ) { //
// it is marked. Lock it
//
dwErr = RtmLockDestination( g_hRtmHandle, rdiLessSpecificDest.DestHandle, TRUE, TRUE );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to lock less specific dest : %x", dwErr );
break; }
bUnLock = TRUE;
//
// Get its opaque pointer
//
dwErr = RtmGetOpaqueInformationPointer( g_hRtmHandle, rdiLessSpecificDest.DestHandle, &pbOpaqueInfo );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to opaque ptr for less specific dest : %x", dwErr );
break; }
//
// Check if it is NULL
//
if ( *( ( PBYTE * ) pbOpaqueInfo ) == NULL ) { bUnMark = TRUE;
break; }
pmllMfeList = ( PMGM_LOCKED_LIST ) *( ( PBYTE * ) pbOpaqueInfo );
//
// lock the route reference list
//
ACQUIRE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList ); bRelRouteRef = TRUE;
//
// Unlock the dest
//
bUnLock = FALSE;
dwErr = RtmLockDestination( g_hRtmHandle, rdiLessSpecificDest.DestHandle, TRUE, FALSE );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to unlock less specific dest : %x", dwErr );
break; }
//
// Create MASK for new dest. from len
//
dwDestMask = RTM_IPV4_MASK_FROM_LEN( prdi-> DestAddress.NumBits );
//
// For each reference
//
for ( ple = pmllMfeList-> leHead.Flink; ple != &pmllMfeList-> leHead; ) { prre = CONTAINING_RECORD( ple, ROUTE_REFERENCE_ENTRY, leRefList );
//
// Check if this MFE would fall under the
// more specific route
//
if ( ( prre-> dwSourceAddr & dwDestMask ) == (( * ( PDWORD ) prdi-> DestAddress.AddrBits ) & dwDestMask) ) { //
// if it does, delete the MFE. This will force its
// recreation, at which time it will be made dependent
// on the more specific route
//
pleTemp = ple-> Flink;
RemoveEntryList( ple );
DeleteMfeAndRefs( ple );
ple = pleTemp; } else { ple = ple-> Flink; } }
//
// if Ref list is empty, it needs to be deleted too.
//
if ( IsListEmpty( &pmllMfeList-> leHead ) ) { //
// to delete the opaque pointer, the dest needs to be locked
// (via RtmLockDestination)
//
// the dest lock is held before locking the route reference
// list ( via ACQUIRE_ROUTE_LOCK_EXCLUSIVE )
//
// At this point in the code, the route reference is locked
// but the dest is not locked.
//
// To lock it, the route reference lock is first released
// (via RELEASE_ROUTE_LOCK_EXCLUSIVE).
//
// The opaque pointer is then acquired, route ref list locked,
// and double checked for emptiness. This round-about ensures
// that the route ref is not deleted while there are threads
// waiting on its lock. This can happen since the dest lock
// is not held for most of the operations here
//
RELEASE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList ); bRelRouteRef = FALSE;
//
// Lock dest
//
dwErr = RtmLockDestination( g_hRtmHandle, rdiLessSpecificDest.DestHandle, TRUE, TRUE );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to lock dest : %x", dwErr );
break; }
bUnLock = TRUE;
//
// Get Opaque pointer again
//
dwErr = RtmGetOpaqueInformationPointer( g_hRtmHandle, rdiLessSpecificDest.DestHandle, &pbOpaqueInfo );
if ( dwErr != NO_ERROR || ((* ((PBYTE *)pbOpaqueInfo) == NULL)) ) { TRACE1( ANY, "Failed to get opaque ptr : %x", dwErr );
break; }
//
// Get ref. list and lock it.
//
pmllMfeList = ( PMGM_LOCKED_LIST ) * ( ( PBYTE * ) pbOpaqueInfo );
ACQUIRE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList ); bRelRouteRef = TRUE;
//
// If list is still empty
//
if ( IsListEmpty( &pmllMfeList-> leHead ) ) { //
// Clear opaque pointer info
//
* ( PBYTE * )pbOpaqueInfo = NULL;
//
// release list lock
//
RELEASE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList ); bRelRouteRef = FALSE;
MGM_FREE( pmllMfeList );
//
// unmark the dest. Change notifications for this
// dest are no longer required.
//
bUnMark = TRUE; } }
else { RELEASE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList ); bRelRouteRef = FALSE; } }
} while ( FALSE );
//
// release route ref list lock
//
if ( bRelRouteRef ) { RELEASE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList ); }
//
// Unlock dest
//
if ( bUnLock ) { dwErr = RtmLockDestination( g_hRtmHandle, rdiLessSpecificDest.DestHandle, TRUE, FALSE );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to lock dest : %x", dwErr ); } }
//
// Unmark dest
//
if ( bUnMark ) { dwErr = RtmMarkDestForChangeNotification( g_hRtmHandle, g_hNotificationHandle, rdiLessSpecificDest.DestHandle, FALSE );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to unmark DEST: %x", dwErr ); } }
return dwErr; }
DWORD ProcessRouteDelete( PRTM_DEST_INFO prdi ) { BOOL bMark = FALSE;
DWORD dwErr;
PMGM_LOCKED_LIST pmllMfeList;
PBYTE pbOpaqueInfo = NULL;
PLIST_ENTRY ple;
do { //
// Cannot lock dest. Is that OK ?
//
//
// Check if this is a marked destination
// Only marked destinations are processed
//
dwErr = RtmIsMarkedForChangeNotification( g_hRtmHandle, g_hNotificationHandle, prdi-> DestHandle, &bMark );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to check if dest marked", dwErr );
break; }
if ( !bMark ) { TRACE0( ANY, "Ignoring change notification for unmarked destination" ); break; }
//
// Get Opaque pointer & the list of MFEs dependent
// on this dest
//
dwErr = RtmGetOpaqueInformationPointer( g_hRtmHandle, prdi-> DestHandle, &pbOpaqueInfo );
if ( (dwErr != NO_ERROR) || ((* ((PBYTE *)pbOpaqueInfo) == NULL)) ) { TRACE1( ANY, "Failed to get opaque ptr", dwErr );
break; }
//
// Clear out the opaque pointer
//
pmllMfeList = (PMGM_LOCKED_LIST) *( ( PBYTE * ) pbOpaqueInfo );
*( ( PBYTE * ) pbOpaqueInfo ) = NULL;
//
// Cannot unlock dest. Is that ok ?
//
//
// Check if the opaque pointer is NULL
//
if ( pmllMfeList == NULL ) { TRACE0( ANY, "Opaque pointer is NULL" );
break; }
//
// Delete all the MFEs
//
ACQUIRE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList );
while ( !IsListEmpty( &pmllMfeList-> leHead ) ) { ple = RemoveHeadList( &pmllMfeList-> leHead );
DeleteMfeAndRefs( ple ); }
RELEASE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList );
MGM_FREE( pmllMfeList );
dwErr = NO_ERROR;
} while ( FALSE );
return dwErr; }
DWORD ProcessRouteUpdate( PRTM_DEST_INFO prdi ) { BOOL bUnLock = FALSE, bUnMark = FALSE, bFound = FALSE;
DWORD dwSize, dwErr, dwInd;
PBYTE pbOpaqueInfo = NULL;
PMGM_LOCKED_LIST pmllMfeList;
PLIST_ENTRY ple, pleTemp;
PROUTE_REFERENCE_ENTRY prre;
PRTM_ROUTE_INFO prri;
//
// the processing goes as follows :
//
do { //
// Allocate route info structure
//
dwSize = sizeof ( RTM_ROUTE_INFO ) + ( g_rrpRtmProfile.MaxNextHopsInRoute - 1 ) * sizeof( RTM_NEXTHOP_HANDLE );
prri = MGM_ALLOC( dwSize );
if ( prri == NULL ) { dwErr = ERROR_NOT_ENOUGH_MEMORY;
TRACE1( ANY, "Failed to allocate route info, size : %x", dwSize );
break; }
//
// Lock destination
//
dwErr = RtmLockDestination( g_hRtmHandle, prdi-> DestHandle, TRUE, TRUE );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to lock dest : %x", dwErr );
break; }
bUnLock = TRUE;
//
// Get Opaque pointer
//
dwErr = RtmGetOpaqueInformationPointer( g_hRtmHandle, prdi-> DestHandle, &pbOpaqueInfo );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to get opaque ptr : %x", dwErr );
break; }
//
// Unmark dest if there are no MFEs that depend on it.
//
if ( *( ( PBYTE * ) pbOpaqueInfo ) == NULL ) { bUnMark = TRUE;
break; }
pmllMfeList = (PMGM_LOCKED_LIST) *( ( PBYTE * ) pbOpaqueInfo );
//
// get route ref list lock
//
ACQUIRE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList );
//
// Unlock dest
//
bUnLock = FALSE;
dwErr = RtmLockDestination( g_hRtmHandle, prdi-> DestHandle, TRUE, FALSE );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to lock dest : %x", dwErr );
break; }
//
// Get the route info for the best UNICAST route on dest
//
dwErr = RtmGetRouteInfo( g_hRtmHandle, prdi ->ViewInfo[ 0 ].Route, prri, NULL);
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed route info : %x", dwErr);
break; }
//
// For each Reference, check if NEXTHOP is still present
//
for ( ple = pmllMfeList-> leHead.Flink; ple != &pmllMfeList-> leHead; ) { prre = CONTAINING_RECORD( ple, ROUTE_REFERENCE_ENTRY, leRefList );
for ( dwInd = 0; dwInd < prri-> NextHopsList.NumNextHops; dwInd++ ) { bFound = FALSE;
if ( prre-> hNextHop == prri-> NextHopsList.NextHops[ dwInd ] ) { //
// OK next hop still present, nothing further needs
// to be done
//
bFound = TRUE; break; } }
//
// if NEXTHOP is not present
//
if ( !bFound ) { pleTemp = ple-> Flink;
//
// Delete the reference and the corresponding MFE
//
RemoveEntryList( ple );
DeleteMfeAndRefs( ple );
ple = pleTemp; }
else { ple = ple-> Flink; }
}
//
// Release the route info
//
dwErr = RtmReleaseRouteInfo( g_hRtmHandle, prri ); if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to release route info : %x", dwErr ); }
//
// if Ref list is empty, it needs to be deleted too.
//
if ( IsListEmpty( &pmllMfeList-> leHead ) ) { //
// to delete the opaque pointer, the dest needs to be locked
// (via RtmLockDestination)
//
// the dest lock is held before locking the route reference
// list ( via ACQUIRE_ROUTE_LOCK_EXCLUSIVE )
//
// At this point in the code, the route reference is locked
// but the dest is not locked.
//
// To lock it, the route reference lock is first released
// (via RELEASE_ROUTE_LOCK_EXCLUSIVE).
//
// The opaque pointer is then acquired, route ref list locked,
// and double checked for emptiness. This round-about ensures
// that the route ref is not deleted while there are threads
// waiting on its lock. This can happen since the dest lock
// is not held for most of the operations here
//
RELEASE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList );
//
// Lock dest
//
dwErr = RtmLockDestination( g_hRtmHandle, prdi-> DestHandle, TRUE, TRUE );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to lock dest : %x", dwErr );
break; }
bUnLock = TRUE;
//
// Get Opaque pointer again
//
dwErr = RtmGetOpaqueInformationPointer( g_hRtmHandle, prdi-> DestHandle, &pbOpaqueInfo );
if ( dwErr != NO_ERROR || ((* ((PBYTE *)pbOpaqueInfo) == NULL)) ) { TRACE1( ANY, "Failed to get opaque ptr : %x", dwErr );
break; }
//
// Get ref. list and lock it.
//
pmllMfeList = ( PMGM_LOCKED_LIST ) *( ( PBYTE * ) pbOpaqueInfo );
//
// Ensure that the list still exists. it is possible (though
// the chances are small) that this list may have been freed
//
if ( pmllMfeList == NULL ) { TRACE0( ANY, "ProcessRouteUpdate : Route ref list already freed" );
break; }
ACQUIRE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList );
//
// If list is still empty
//
if ( IsListEmpty( &pmllMfeList-> leHead ) ) { //
// Clear opaque pointer info
//
*( ( PBYTE * ) pbOpaqueInfo ) = NULL;
//
// release list lock
//
RELEASE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList );
MGM_FREE( pmllMfeList );
//
// unmark the dest. Change notifications for this
// dest are no longer required.
//
bUnMark = TRUE; }
else { RELEASE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList ); } }
else { RELEASE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList ); }
} while ( FALSE );
//
// Unlock dest
//
if ( bUnLock ) { dwErr = RtmLockDestination( g_hRtmHandle, prdi-> DestHandle, TRUE, FALSE );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to lock dest : %x", dwErr ); } }
//
// Unmark dest
//
if ( bUnMark ) { dwErr = RtmMarkDestForChangeNotification( g_hRtmHandle, g_hNotificationHandle, prdi-> DestHandle, FALSE );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to unmark DEST: %x", dwErr ); } }
//
// Free allocations
//
if ( prri ) { MGM_FREE( prri ); }
return dwErr; }
VOID DeleteMfeAndRefs( PLIST_ENTRY ple ) { DWORD dwInIfIndex = 0, dwInIfNextHopAddr = 0, dwIfBucket;
PROUTE_REFERENCE_ENTRY prre;
PIF_ENTRY pie = NULL;
PIF_REFERENCE_ENTRY pire = NULL;
//
// Get the reference entry
//
prre = CONTAINING_RECORD( ple, ROUTE_REFERENCE_ENTRY, leRefList );
//
// Look up and delete the MFE
//
LookupAndDeleteYourMfe( prre-> dwSourceAddr, prre-> dwSourceMask, prre-> dwGroupAddr, prre-> dwGroupMask, TRUE, &dwInIfIndex, &dwInIfNextHopAddr );
//
// Find incoming interface and delete ref from there too.
//
if ( dwInIfIndex != 0 ) { dwIfBucket = IF_TABLE_HASH( dwInIfIndex );
ACQUIRE_IF_LOCK_EXCLUSIVE( dwIfBucket );
if ( FindIfEntry( IF_BUCKET_HEAD( dwIfBucket ), dwInIfIndex, dwInIfNextHopAddr, &pie ) ) { if ( FindRefEntry( &pie-> leInIfList, prre-> dwSourceAddr, prre-> dwSourceMask, prre-> dwGroupAddr, prre-> dwGroupMask, &pire ) ) { RemoveEntryList( &pire-> leRefList );
MGM_FREE( pire ); }
else { TRACE2( ANY, "Could not find ref entry for %x, %x", prre-> dwSourceAddr, prre-> dwGroupAddr ); } }
else { TRACE2( ANY, "Could not find i/f entry for %x, %x", dwInIfIndex, dwInIfNextHopAddr ); } RELEASE_IF_LOCK_EXCLUSIVE( dwIfBucket );
MGM_FREE( prre ); } }
HANDLE SelectNextHop( PRTM_DEST_INFO prdi ) { DWORD dwErr, dwSize;
HANDLE hNextHop;
PRTM_ROUTE_INFO prri;
//
// Allocate route info structure
//
dwSize = sizeof ( RTM_ROUTE_INFO ) + ( g_rrpRtmProfile.MaxNextHopsInRoute - 1 ) * sizeof( RTM_NEXTHOP_HANDLE );
prri = MGM_ALLOC( dwSize );
if ( prri == NULL ) { dwErr = ERROR_NOT_ENOUGH_MEMORY;
TRACE1( ANY, "Failed to allocate route info, size : %x", dwSize );
return NULL; }
ZeroMemory( prri, dwSize );
//
// get route info
//
dwErr = RtmGetRouteInfo( g_hRtmHandle, prdi-> ViewInfo[ 0 ].Route, prri, NULL );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to get route info : %x", dwErr );
MGM_FREE( prri );
return NULL; }
//
// Pick the first next hop for now
//
hNextHop = prri-> NextHopsList.NextHops[0];
//
// Release the route info
//
dwErr = RtmReleaseRouteInfo( g_hRtmHandle, prri );
if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to release route info : %x", dwErr ); }
MGM_FREE( prri );
return hNextHop; }
|