windows-nt/Source/XPSP1/NT/net/rras/ip/rtrmgr/rtmops.c

1952 lines
55 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
#include "allinc.h"
DWORD
RtmEventCallback (
IN RTM_ENTITY_HANDLE hRtmHandle,
IN RTM_EVENT_TYPE retEvent,
IN PVOID pContext1,
IN PVOID pContext2
)
/*++
Routine Description:
This callback is given by RTM when we have changed dests
to process. We just queue a work item to process changed
destinations.
Arguments:
hRtmHandle - Handle that we got during registration
retEvent - Event type - we only handle events of
type "more changes available" for now
pContext1 - Notification handle on which changes
are available
pContext2 - Context supplied during notification
registration time
Return Value:
Status of the operation.
--*/
{
DWORD dwResult;
// Only "change notifications available" is supported
if (retEvent != RTM_CHANGE_NOTIFICATION)
{
return ERROR_NOT_SUPPORTED;
}
return ((HANDLE) pContext1) == g_hNotification ?
ProcessChanges(g_hNotification) :
ProcessDefaultRouteChanges( g_hDefaultRouteNotification );
}
DWORD
WINAPI
ProcessChanges (
IN HANDLE hNotifyHandle
)
/*++
Routine Description:
Upon learning that we have changed destinations to
process, this function gets called. We retrieve all
destinations to process and take appropriate action.
Arguments:
hRtmHandle - RTM registration handle
hNotifyHandle - Handle correponding to the change notification
that is being signalled
Return Value:
Status of the operation.
--*/
{
PRTM_DEST_INFO pDestInfo;
PRTM_ROUTE_INFO pRouteInfo;
DWORD dwDests;
DWORD dwResult;
BOOL bMark = FALSE;
TraceEnter("ProcessChanges");
pRouteInfo = HeapAlloc(
IPRouterHeap,
0,
RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
);
if (pRouteInfo == NULL)
{
Trace1(
ERR, "ProcessChanges : error allocating %d bytes for "
"route info",
RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
);
TraceLeave("ProcessChanges");
return ERROR_NOT_ENOUGH_MEMORY;
}
pDestInfo = HeapAlloc(
IPRouterHeap,
0,
RTM_SIZE_OF_DEST_INFO(g_rtmProfile.NumberOfViews)
);
if (pDestInfo == NULL)
{
Trace1(
ERR, "ProcessChanges : error allocating %d bytes for "
"dest. info",
RTM_SIZE_OF_DEST_INFO(g_rtmProfile.NumberOfViews)
);
HeapFree(IPRouterHeap, 0, pRouteInfo);
TraceLeave("ProcessChanges");
return ERROR_NOT_ENOUGH_MEMORY;
}
dwDests = 1;
// Get each changed dest from the table
do
{
RtmGetChangedDests(g_hLocalRoute,
hNotifyHandle,
&dwDests,
pDestInfo);
if (dwDests < 1)
{
break;
}
//
// For default routes, mark the route so that future changes
// are managed by ProcessDefaultRouteChanges.
//
// We need to do this here so that default routes added by
// routing protocols RIP/OSPF are marked for change notification
// These default routes are added by entities other than
// RouterManager. Default routes added by RM i.e STATIC,
// AUTO-STATIC and NETMGMT default routes are already marked for
// change notification when they are added by RM.
//
// By marking routing protocol default routes here we make sure
// that all default routes are subsequently handled by marked changed
// mechanism (ProcessDefaultRouteChanges).
//
if (pDestInfo->DestAddress.NumBits is 0)
{
TraceRoute2(
ROUTE, "Checking dest %d.%d.%d.%d/%d is marked",
PRINT_IPADDR(*(ULONG *)pDestInfo->DestAddress.AddrBits),
PRINT_IPADDR(pDestInfo->DestAddress.NumBits)
);
dwResult = RtmIsMarkedForChangeNotification(
g_hNetMgmtRoute,
g_hDefaultRouteNotification,
pDestInfo->DestHandle,
&bMark
);
if (dwResult is NO_ERROR)
{
if (bMark)
{
//
// default route is already marked, nothing further
// to do here. This default route change will be
// handled by ProcessDefaultRouteChanges
//
TraceRoute0(
ROUTE,
"ProcessChanges : Route 0/0 is already marked"
);
RtmReleaseChangedDests(g_hLocalRoute,
hNotifyHandle,
dwDests,
pDestInfo);
continue;
}
//
// Default route is not marked, mark it
//
dwResult = RtmMarkDestForChangeNotification(
g_hNetMgmtRoute,
g_hDefaultRouteNotification,
pDestInfo->DestHandle,
TRUE
);
if (dwResult isnot NO_ERROR)
{
//
// Failed to mark 0/0 route. The consequence is that
// only best route changes are processed. We will
// have to live with the fact that we cannot
// install multiple NETMGMT default routes since
// this is performed by the mark dest. change
// processing (in ProcessDefaultRouteChanges)
//
Trace1(
ERR,
"ProcessChanges: error %d marking default route",
dwResult
);
}
}
else
{
//
// Failed to check is 0/0 destination has been
// marked for change notification
// - Refer previous comment
//
Trace1(
ERR,
"ProcessChanges: error %d checking if default route "
"marked",
dwResult
);
}
}
// Check if we have a route in Unicast view
if (pDestInfo->BelongsToViews & RTM_VIEW_MASK_UCAST)
{
// This is either a new or update route
// Update the same route in KM Frwder
ASSERT(pDestInfo->ViewInfo[0].ViewId is RTM_VIEW_ID_UCAST);
dwResult = RtmGetRouteInfo(g_hLocalRoute,
pDestInfo->ViewInfo[0].Route,
pRouteInfo,
NULL);
// An error mean route just got deleted
// Ignore this change as it is obsolete
if (dwResult is NO_ERROR)
{
ChangeRouteWithForwarder(&pDestInfo->DestAddress,
pRouteInfo,
TRUE,
TRUE);
RtmReleaseRouteInfo(g_hLocalRoute,
pRouteInfo);
}
}
else
{
// The last UCAST route has been deleted
// Delete the same route from KM Frwder
ChangeRouteWithForwarder(&pDestInfo->DestAddress,
NULL,
FALSE,
TRUE);
}
RtmReleaseChangedDests(g_hLocalRoute,
hNotifyHandle,
dwDests,
pDestInfo);
}
while (TRUE);
HeapFree(IPRouterHeap, 0, pRouteInfo);
HeapFree(IPRouterHeap, 0, pDestInfo);
TraceLeave("ProcessChanges");
return NO_ERROR;
}
DWORD
WINAPI
ProcessDefaultRouteChanges(
IN HANDLE hNotifyHandle
)
/*++
Routine Description:
This function is invoked in response to changes to
the default route. If the best default route is owned
by protocol PROTO_IP_NETMGMT enumerate all PROTO_IP_NETMGMT
routes for default route 0/0 and set them as one
multihop route to the forwarder
Arguments:
hRtmHandle - RTM registration handle
hNotifyHandle - Handle correponding to the change notification
that is being signalled
Return Value:
NO_ERROR - Success
System error code - Otherwise
--*/
{
PRTM_DEST_INFO pDestInfo;
PRTM_ROUTE_INFO pRouteInfo;
DWORD dwDests;
DWORD dwResult;
TraceEnter("ProcessDefaultRouteChanges");
pRouteInfo = HeapAlloc(
IPRouterHeap,
0,
RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
);
if (pRouteInfo == NULL)
{
Trace1(
ERR, "ProcessDefaultRouteChanges : error allocating %d bytes for "
"route info",
RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
);
TraceLeave("ProcessDefaultRouteChanges");
return ERROR_NOT_ENOUGH_MEMORY;
}
pDestInfo = HeapAlloc(
IPRouterHeap,
0,
RTM_SIZE_OF_DEST_INFO(g_rtmProfile.NumberOfViews)
);
if (pDestInfo == NULL)
{
Trace1(
ERR, "ProcessDefaultRouteChanges : error allocating %d bytes for "
"dest. info",
RTM_SIZE_OF_DEST_INFO(g_rtmProfile.NumberOfViews)
);
HeapFree(IPRouterHeap, 0, pRouteInfo);
TraceLeave("ProcessDefaultRouteChanges");
return ERROR_NOT_ENOUGH_MEMORY;
}
do
{
//
// retreive changed dests
//
dwDests = 1;
dwResult = RtmGetChangedDests(
g_hNetMgmtRoute,
hNotifyHandle,
&dwDests,
pDestInfo
);
if ((dwResult isnot NO_ERROR) and
(dwResult isnot ERROR_NO_MORE_ITEMS))
{
Trace1(
ERR,
"ProcessDefaultRouteChanges: error %d retrieving changed dests",
dwResult
);
break;
}
if (dwDests < 1)
{
//
// no more dests to enumerate
//
break;
}
do
{
//
// Make sure this the default route 0/0. This functions
// only processes default route changes.
//
if ((pDestInfo->DestAddress.NumBits isnot 0) or
(*((ULONG *)pDestInfo->DestAddress.AddrBits) isnot 0))
{
Trace2(
ERR,
"ProcessDefaultRouteChanges: Not default route %d.%d.%d.%d/%d",
PRINT_IPADDR(*((ULONG *)pDestInfo->DestAddress.AddrBits)),
pDestInfo->DestAddress.NumBits
);
break;
}
//
// If all routes to 0/0 have been deleted,
// delete it from the forwarder too.
//
if (!(pDestInfo->BelongsToViews & RTM_VIEW_MASK_UCAST))
{
dwResult = ChangeRouteWithForwarder(
&(pDestInfo->DestAddress),
NULL,
FALSE,
TRUE
);
break;
}
//
// A route to 0/0 was added/updated
//
if (pDestInfo->ViewInfo[0].Owner isnot g_hNetMgmtRoute)
{
//
// Default route is not owned by PROTO_IP_NETMGT
// Add only the best route to forwarder
//
TraceRoute1(
ROUTE,
"ProcessDefaultRouteChanges: Adding non-NetMgmt"
" route to forwarder, owner RTM handle 0x%x",
pDestInfo->ViewInfo[0].Owner
);
dwResult = RtmGetRouteInfo(
g_hNetMgmtRoute,
pDestInfo->ViewInfo[0].Route,
pRouteInfo,
NULL
);
if (dwResult is NO_ERROR)
{
ChangeRouteWithForwarder(
&pDestInfo->DestAddress,
pRouteInfo,
TRUE,
TRUE
);
dwResult = RtmReleaseRouteInfo(
g_hNetMgmtRoute,
pRouteInfo
);
if (dwResult isnot NO_ERROR)
{
Trace1(
ERR,
"ProcessDefaultRouteChanges: Failed "
"to release route info",
dwResult
);
}
}
break;
}
//
// Default route owned by PROTO_IP_NETMGMT
//
//
// First delete existing 0/0 from the TCP/IP forwarder
//
dwResult = ChangeRouteWithForwarder(
&(pDestInfo->DestAddress),
NULL,
FALSE,
TRUE
);
if (dwResult isnot NO_ERROR)
{
Trace1(
ERR,
"ProcessDefaultRouteChanges: error %d deleting "
"old NetMgmt default routes from forwarder",
dwResult
);
// break;
}
//
// Second add all NETMGMT 0/0 to the TCP/IP forwarder
//
AddNetmgmtDefaultRoutesToForwarder(pDestInfo);
} while( FALSE );
//
// release handles to changed destinations
//
dwResult = RtmReleaseChangedDests(
g_hNetMgmtRoute,
hNotifyHandle,
dwDests,
pDestInfo
);
if (dwResult isnot NO_ERROR)
{
Trace1(
ERR,
"ProcessDefaultRouteChanges: error %d releasing dests ",
dwResult
);
}
} while ( TRUE );
HeapFree(IPRouterHeap, 0, pRouteInfo);
HeapFree(IPRouterHeap, 0, pDestInfo);
TraceLeave("ProcessDefaultRouteChanges");
return dwResult;
}
DWORD
WINAPI
AddNetmgmtDefaultRoutesToForwarder(
PRTM_DEST_INFO pDestInfo
)
/*++
Routine Description:
This routine enumerates the routes to 0/0 added by protocol
PROTO_IP_NETMGT and adds them to the forwarder. This routine
is invoked in response to any change to the default route
If the best default route is owned by PROTO_IP_NETMGMT, all
PROTO_IP_NETMGMT default routes are added to the TCP/IP
forwarder.
This is required since the TCP/IP stack does dead gateway
detection and that required multiple default routes if
present to be installed in the stack.
An implicit assumption here is that PROTO_IP_NETMGMT routes
alone merit this treatment. In case of static or other
protocol generated 0/0 routes, only the best route is
added to the stack. It is assumed that in the later case(s)
the administrator (for static routes) or the protocol has
a better idea of routing and so the dead gateway detection
is suppressed in the stack by the addition of the best route
to 0/0 alone.
Arguments:
pDestInfo - RTM destination info structure of 0/0 route
Return Value :
NO_ERROR - Sucess
Win32 error code - Otherwise
--*/
{
DWORD dwResult, dwNumHandles = 0, i;
BOOL bRelEnum = FALSE, bRelRoutes = FALSE;
PRTM_ROUTE_INFO pRouteInfo;
PRTM_ROUTE_HANDLE pHandles;
RTM_ENUM_HANDLE hRouteEnum;
dwNumHandles = pDestInfo->ViewInfo[0].NumRoutes;
pHandles = HeapAlloc(
IPRouterHeap,
0,
dwNumHandles * sizeof(RTM_ROUTE_HANDLE)
);
if (pHandles == NULL)
{
Trace1(
ERR,
"AddNetmgmtDefaultRoutesToForwarder: error allocating %d bytes"
"for route handles",
dwNumHandles * sizeof(RTM_ROUTE_HANDLE)
);
return ERROR_NOT_ENOUGH_MEMORY;
}
pRouteInfo = HeapAlloc(
IPRouterHeap,
0,
RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
);
if (pRouteInfo == NULL)
{
Trace1(
ERR,
"AddNetmgmtDefaultRoutesToForwarder: error allocating %d bytes"
"for route info",
RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
);
HeapFree(IPRouterHeap, 0, pHandles);
return ERROR_NOT_ENOUGH_MEMORY;
}
do
{
//
// Enumerate and add all NETMGMT routes to the forwarder
//
dwResult = RtmCreateRouteEnum(
g_hNetMgmtRoute,
pDestInfo->DestHandle,
RTM_VIEW_MASK_UCAST,
RTM_ENUM_OWN_ROUTES,
NULL,
0,
NULL,
0,
&hRouteEnum
);
if (dwResult isnot NO_ERROR)
{
Trace1(
ERR,
"AddNetmgmtDefaultRoutesToForwarder: error %d creating route "
"enumeration",
dwResult
);
break;
}
bRelEnum = TRUE;
dwResult = RtmGetEnumRoutes(
g_hNetMgmtRoute,
hRouteEnum,
&dwNumHandles,
pHandles
);
if (dwResult isnot NO_ERROR)
{
Trace1(
ERR,
"ProcessDefaultRouteChanges:error %d enumerating "
"routes",
dwResult
);
break;
}
bRelRoutes = TRUE;
//
// Change route with the forwarder
//
for (i = 0; i < dwNumHandles; i++)
{
dwResult = RtmGetRouteInfo(
g_hNetMgmtRoute,
pHandles[i],
pRouteInfo,
NULL
);
if (dwResult is NO_ERROR)
{
ChangeRouteWithForwarder(
&(pDestInfo->DestAddress),
pRouteInfo,
TRUE,
FALSE
);
dwResult = RtmReleaseRouteInfo(
g_hNetMgmtRoute,
pRouteInfo
);
if (dwResult isnot NO_ERROR)
{
Trace1(
ERR,
"ProcessDefaultRouteChanges: error %d releasing "
"route info ",
dwResult
);
}
}
else
{
Trace2(
ERR,
"ProcessDefaultRouteChanges: error %d getting route "
"info for route %d",
dwResult, i
);
}
}
} while( FALSE );
//
// Release handles
//
if (bRelRoutes)
{
Trace0(ROUTE, "Releasing routes to 0/0");
dwResult = RtmReleaseRoutes(
g_hNetMgmtRoute,
dwNumHandles,
pHandles
);
if (dwResult isnot NO_ERROR)
{
Trace1(
ERR,
"ProcessDefaultRouteChanges: error %d deleting enum "
"handle",
dwResult
);
}
}
if (bRelEnum)
{
Trace0(ROUTE, "Releasing route enum for 0/0");
dwResult = RtmDeleteEnumHandle(
g_hNetMgmtRoute,
hRouteEnum
);
if (dwResult isnot NO_ERROR)
{
Trace1(
ERR,
"ProcessDefaultRouteChanges: error %d deleting enum "
"handle",
dwResult
);
}
}
HeapFree(IPRouterHeap, 0, pHandles);
HeapFree(IPRouterHeap, 0, pRouteInfo);
return dwResult;
}
DWORD
AddRtmRoute (
IN HANDLE hRtmHandle,
IN PINTERFACE_ROUTE_INFO pRtInfo,
IN DWORD dwRouteFlags,
IN DWORD dwNextHopMask,
IN DWORD dwTimeToLive,
OUT HANDLE *phRtmRoute
)
/*++
Routine Description:
Adds a route to RTM with the specified route information.
Arguments:
hRtmHandle - RTM registration handle used in RTM calls
pRtInfo -
dwNextHopMask -
dwTimeToLive - Time for which the route is kept in RTM
before being deleted (value is seconds).
Return Value:
Status of the operation.
--*/
{
PRTM_NET_ADDRESS pDestAddr;
PRTM_ROUTE_INFO pRouteInfo;
RTM_NEXTHOP_INFO rniInfo;
DWORD dwFlags;
DWORD dwResult;
HANDLE hNextHopHandle;
PADAPTER_INFO pBinding;
// Initialize output before caling ops
if (ARGUMENT_PRESENT(phRtmRoute))
{
*phRtmRoute = NULL;
}
pDestAddr = HeapAlloc(
IPRouterHeap,
0,
sizeof(RTM_NET_ADDRESS)
);
if (pDestAddr == NULL)
{
Trace1(
ERR,
"AddRtmRoute : error allocating %d bytes"
"for dest. address",
RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
);
return ERROR_NOT_ENOUGH_MEMORY;
}
pRouteInfo = HeapAlloc(
IPRouterHeap,
0,
RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
);
if (pRouteInfo == NULL)
{
Trace1(
ERR,
"AddRtmRoute : error allocating %d bytes"
"for route info",
RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
);
HeapFree(IPRouterHeap, 0, pDestAddr);
return ERROR_NOT_ENOUGH_MEMORY;
}
//
// Add a next hop if not already present
//
RTM_IPV4_MAKE_NET_ADDRESS(&rniInfo.NextHopAddress,
pRtInfo->dwRtInfoNextHop,
32);
rniInfo.InterfaceIndex = pRtInfo->dwRtInfoIfIndex;
rniInfo.EntitySpecificInfo = (PVOID) (ULONG_PTR)dwNextHopMask;
rniInfo.Flags = 0;
rniInfo.RemoteNextHop = NULL;
hNextHopHandle = NULL;
dwResult = RtmAddNextHop(hRtmHandle,
&rniInfo,
&hNextHopHandle,
&dwFlags);
if (dwResult is NO_ERROR)
{
TraceRoute2(
ROUTE, "Route to %d.%d.%d.%d/%d.%d.%d.%d",
PRINT_IPADDR(pRtInfo->dwRtInfoDest),
PRINT_IPADDR(pRtInfo->dwRtInfoMask)
);
TraceRoute4(
ROUTE, "Next Hop %d.%d.%d.%d/%d.%d.%d.%d, If 0x%x, handle is 0x%x",
PRINT_IPADDR(pRtInfo->dwRtInfoNextHop),
PRINT_IPADDR(dwNextHopMask),
pRtInfo->dwRtInfoIfIndex,
hNextHopHandle
);
dwResult = ConvertRouteInfoToRtm(hRtmHandle,
pRtInfo,
hNextHopHandle,
dwRouteFlags,
pDestAddr,
pRouteInfo);
if (dwResult is NO_ERROR)
{
//
// If we are adding a non-dod route we should
// adjust the state of the route to match
// that of the interface it is being added on
//
if ((hRtmHandle == g_hNonDodRoute) ||
(hRtmHandle == g_hNetMgmtRoute))
{
//
// Find the binding given the interface id
//
ENTER_READER(BINDING_LIST);
pBinding = GetInterfaceBinding(pRtInfo->dwRtInfoIfIndex);
if ((!pBinding) || (!pBinding->bBound))
{
// Interface has been deleted meanwhile
// or is not bound at this point - quit
EXIT_LOCK(BINDING_LIST);
return ERROR_INVALID_PARAMETER;
}
}
//
// Convert TimeToLive from secs to millisecs
//
if (dwTimeToLive != INFINITE)
{
if (dwTimeToLive < (INFINITE / 1000))
{
dwTimeToLive *= 1000;
}
else
{
dwTimeToLive = INFINITE;
}
}
dwFlags = 0;
//
// Add the new route using the RTMv2 API call
//
dwResult = RtmAddRouteToDest(hRtmHandle,
phRtmRoute,
pDestAddr,
pRouteInfo,
dwTimeToLive,
NULL,
0,
NULL,
&dwFlags);
if ((hRtmHandle == g_hNonDodRoute) ||
(hRtmHandle == g_hNetMgmtRoute))
{
EXIT_LOCK(BINDING_LIST);
}
//
// check if route is 0/0 and route protocol is
// PROTO_IP_NETMGMT. If so mark for change notification
//
if ((pRtInfo->dwRtInfoDest is 0) and
(pRtInfo->dwRtInfoMask is 0))
{
RTM_DEST_INFO rdi;
BOOL bMark;
BOOL bRelDest = FALSE;
do
{
TraceRoute2(
ROUTE, "Checking dest %d.%d.%d.%d/%d for mark",
PRINT_IPADDR(*(ULONG *)pDestAddr->AddrBits),
PRINT_IPADDR(pDestAddr->NumBits)
);
dwResult = RtmGetExactMatchDestination(
g_hNetMgmtRoute,
pDestAddr,
RTM_THIS_PROTOCOL,
RTM_VIEW_MASK_UCAST,
&rdi
);
if (dwResult isnot NO_ERROR)
{
Trace1(
ERR,
"AddRtmRoute: error %d failed to get "
"destination 0/0 for change notification",
dwResult
);
break;
}
bRelDest = TRUE;
dwResult = RtmIsMarkedForChangeNotification(
g_hNetMgmtRoute,
g_hDefaultRouteNotification,
rdi.DestHandle,
&bMark
);
if (dwResult isnot NO_ERROR)
{
Trace1(
ERR,
"AddRtmRoute: error %d failed to check "
"destination 0/0 for change notification",
dwResult
);
break;
}
if (!bMark)
{
dwResult = RtmMarkDestForChangeNotification(
g_hNetMgmtRoute,
g_hDefaultRouteNotification,
rdi.DestHandle,
TRUE
);
if (dwResult isnot NO_ERROR)
{
Trace1(
ERR,
"AddRtmRoute: error %d failed to nark "
"destination 0/0 for change notification",
dwResult
);
break;
}
//
// Add route once more, to force marked dest
// change notifications to be issued for this
// change
//
dwFlags = 0;
dwResult = RtmAddRouteToDest(
hRtmHandle,
phRtmRoute,
pDestAddr,
pRouteInfo,
dwTimeToLive,
NULL,
0,
NULL,
&dwFlags
);
if (dwResult isnot NO_ERROR)
{
Trace1(
ERR,
"AddRtmRoute: error %d added route after "
"marking destination",
dwResult
);
break;
}
TraceRoute2(
ROUTE, "Marked dest %d.%d.%d.%d/%d and added",
PRINT_IPADDR(*(ULONG *)pDestAddr->AddrBits),
PRINT_IPADDR(pDestAddr->NumBits)
);
}
} while (FALSE);
if (bRelDest)
{
RtmReleaseDestInfo(
g_hNetMgmtRoute,
&rdi
);
}
}
}
// Release the next hop handle obtained above
RtmReleaseNextHops(hRtmHandle,
1,
&hNextHopHandle);
}
HeapFree(IPRouterHeap, 0, pDestAddr);
HeapFree(IPRouterHeap, 0, pRouteInfo);
return dwResult;
}
DWORD
DeleteRtmRoute (
IN HANDLE hRtmHandle,
IN PINTERFACE_ROUTE_INFO pRtInfo
)
/*++
Routine Description:
Deletes an RTM route with the specified route information.
Arguments:
hRtmHandle - RTM registration handle used in RTM calls
pRtInfo -
Return Value:
Status of the operation.
--*/
{
PRTM_NET_ADDRESS pDestAddr;
PRTM_ROUTE_INFO pRouteInfo;
RTM_NEXTHOP_INFO rniInfo;
DWORD dwFlags;
DWORD dwResult;
HANDLE hRouteHandle;
HANDLE hNextHopHandle;
pRouteInfo = HeapAlloc(
IPRouterHeap,
0,
RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
);
if (pRouteInfo == NULL)
{
Trace1(
ERR,
"DeleteRtmRoute : error allocating %d bytes"
"for route info",
RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
);
return ERROR_NOT_ENOUGH_MEMORY;
}
pDestAddr = HeapAlloc(
IPRouterHeap,
0,
sizeof(RTM_NET_ADDRESS)
);
if (pDestAddr == NULL)
{
Trace1(
ERR,
"AddRtmRoute : error allocating %d bytes"
"for dest. address",
RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
);
HeapFree(IPRouterHeap, 0, pRouteInfo);
return ERROR_NOT_ENOUGH_MEMORY;
}
//
// Obtain a handle to the next hop in the route
//
RTM_IPV4_MAKE_NET_ADDRESS(&rniInfo.NextHopAddress,
pRtInfo->dwRtInfoNextHop,
32);
rniInfo.InterfaceIndex = pRtInfo->dwRtInfoIfIndex;
rniInfo.NextHopOwner = hRtmHandle;
dwResult = RtmFindNextHop(hRtmHandle,
&rniInfo,
&hNextHopHandle,
NULL);
if (dwResult isnot NO_ERROR)
{
HeapFree(IPRouterHeap, 0, pDestAddr);
HeapFree(IPRouterHeap, 0, pRouteInfo);
return dwResult;
}
//
// We can get this route by matching the route's
// net addr, its owner and neighbour learnt from
//
ConvertRouteInfoToRtm(hRtmHandle,
pRtInfo,
hNextHopHandle,
0,
pDestAddr,
pRouteInfo);
dwResult = RtmGetExactMatchRoute(hRtmHandle,
pDestAddr,
RTM_MATCH_OWNER | RTM_MATCH_NEIGHBOUR,
pRouteInfo,
0,
0,
&hRouteHandle);
if (dwResult is NO_ERROR)
{
//
// Delete the route found above using the handle
//
dwResult = RtmDeleteRouteToDest(hRtmHandle,
hRouteHandle,
&dwFlags);
if (dwResult isnot NO_ERROR)
{
// If delete successful, deref is automatic
RtmReleaseRoutes(hRtmHandle,
1,
&hRouteHandle);
}
// Release the route information obtained above
RtmReleaseRouteInfo(hRtmHandle,
pRouteInfo);
}
// Release the next hop handle obtained above
RtmReleaseNextHops(hRtmHandle,
1,
&hNextHopHandle);
HeapFree(IPRouterHeap, 0, pDestAddr);
HeapFree(IPRouterHeap, 0, pRouteInfo);
return dwResult;
}
DWORD
ConvertRouteInfoToRtm(
IN HANDLE hRtmHandle,
IN PINTERFACE_ROUTE_INFO pRtInfo,
IN HANDLE hNextHopHandle,
IN DWORD dwRouteFlags,
OUT PRTM_NET_ADDRESS pDestAddr,
OUT PRTM_ROUTE_INFO pRouteInfo
)
{
DWORD dwAddrLen;
// Fill the destination addr structure
RTM_IPV4_LEN_FROM_MASK(dwAddrLen, pRtInfo->dwRtInfoMask);
RTM_IPV4_MAKE_NET_ADDRESS(pDestAddr,
pRtInfo->dwRtInfoDest,
dwAddrLen);
// Fill in the route information now
ZeroMemory(pRouteInfo, sizeof(RTM_ROUTE_INFO));
pRouteInfo->RouteOwner = hRtmHandle;
pRouteInfo->Neighbour = hNextHopHandle;
pRouteInfo->PrefInfo.Metric = pRtInfo->dwRtInfoMetric1;
pRouteInfo->PrefInfo.Preference = pRtInfo->dwRtInfoPreference;
pRouteInfo->BelongsToViews = pRtInfo->dwRtInfoViewSet;
//
// BUG BUG BUG BUG :
// This is broken for future references
//
if(g_pLoopbackInterfaceCb &&
pRtInfo->dwRtInfoIfIndex is g_pLoopbackInterfaceCb->dwIfIndex)
{
pRouteInfo->BelongsToViews &= ~RTM_VIEW_MASK_MCAST;
}
pRouteInfo->NextHopsList.NumNextHops = 1;
pRouteInfo->NextHopsList.NextHops[0] = hNextHopHandle;
// an unsigned integer is converted to a shorter
// unsigned integer by truncating the high-order bits!
pRouteInfo->Flags1 = (UCHAR) dwRouteFlags;
pRouteInfo->Flags = (USHORT) (dwRouteFlags >> 16);
// Get the preference for this route
return ValidateRouteForProtocol(pRtInfo->dwRtInfoProto,
pRouteInfo,
pDestAddr);
// The following information is lost
//
// dwForwardMetric2,3
// dwForwardPolicy
// dwForwardType
// dwForwardAge
// dwForwardNextHopAS
}
VOID
ConvertRtmToRouteInfo (
IN DWORD ownerProtocol,
IN PRTM_NET_ADDRESS pDestAddr,
IN PRTM_ROUTE_INFO pRouteInfo,
IN PRTM_NEXTHOP_INFO pNextHop,
OUT PINTERFACE_ROUTE_INFO pRtInfo
)
{
pRtInfo->dwRtInfoDest = *(ULONG *)pDestAddr->AddrBits;
pRtInfo->dwRtInfoMask = RTM_IPV4_MASK_FROM_LEN(pDestAddr->NumBits);
pRtInfo->dwRtInfoIfIndex = pNextHop->InterfaceIndex;
pRtInfo->dwRtInfoNextHop = *(ULONG *)pNextHop->NextHopAddress.AddrBits;
pRtInfo->dwRtInfoProto = ownerProtocol;
pRtInfo->dwRtInfoMetric1 =
pRtInfo->dwRtInfoMetric2 =
pRtInfo->dwRtInfoMetric3 = pRouteInfo->PrefInfo.Metric;
pRtInfo->dwRtInfoPreference = pRouteInfo->PrefInfo.Preference;
pRtInfo->dwRtInfoViewSet = pRouteInfo->BelongsToViews;
pRtInfo->dwRtInfoPolicy = 0;
pRtInfo->dwRtInfoType = 0;
pRtInfo->dwRtInfoAge = 0;
pRtInfo->dwRtInfoNextHopAS = 0;
return;
}
PINTERFACE_ROUTE_INFO
ConvertMibRouteToRouteInfo(
IN PMIB_IPFORWARDROW pMibRow
)
{
PINTERFACE_ROUTE_INFO pRouteInfo = (PINTERFACE_ROUTE_INFO)pMibRow;
pMibRow->dwForwardMetric2 = 0;
pMibRow->dwForwardMetric3 = 0;
pMibRow->dwForwardMetric4 = 0;
pMibRow->dwForwardMetric5 = 0;
// Make sure Metric1 isn't 0
if (pRouteInfo->dwRtInfoMetric1 is 0)
{
pRouteInfo->dwRtInfoMetric1 = 1;
}
// By default put it in both views
pRouteInfo->dwRtInfoViewSet = RTM_VIEW_MASK_UCAST | RTM_VIEW_MASK_MCAST;
return pRouteInfo;
}
PMIB_IPFORWARDROW
ConvertRouteInfoToMibRoute(
IN PINTERFACE_ROUTE_INFO pRouteInfo
)
{
PMIB_IPFORWARDROW pMibRoute = (PMIB_IPFORWARDROW) pRouteInfo;
pMibRoute->dwForwardMetric2 =
pMibRoute->dwForwardMetric3 =
pMibRoute->dwForwardMetric4 =
pMibRoute->dwForwardMetric5 = IRE_METRIC_UNUSED;
pMibRoute->dwForwardAge = INFINITE;
pMibRoute->dwForwardPolicy = 0;
pMibRoute->dwForwardNextHopAS = 0;
pMibRoute->dwForwardType = IRE_TYPE_INDIRECT;
return pMibRoute;
}
VOID
ConvertRouteNotifyOutputToRouteInfo(
IN PIPRouteNotifyOutput pirno,
OUT PINTERFACE_ROUTE_INFO pRtInfo
)
{
ZeroMemory(pRtInfo, sizeof(INTERFACE_ROUTE_INFO));
pRtInfo->dwRtInfoDest = pirno->irno_dest;
pRtInfo->dwRtInfoMask = pirno->irno_mask;
pRtInfo->dwRtInfoIfIndex = pirno->irno_ifindex;
pRtInfo->dwRtInfoNextHop = pirno->irno_nexthop;
pRtInfo->dwRtInfoProto = pirno->irno_proto;
pRtInfo->dwRtInfoMetric1 =
pRtInfo->dwRtInfoMetric2 =
pRtInfo->dwRtInfoMetric3 = pirno->irno_metric;
pRtInfo->dwRtInfoPreference = ComputeRouteMetric(pirno->irno_proto);
pRtInfo->dwRtInfoViewSet = RTM_VIEW_MASK_UCAST |
RTM_VIEW_MASK_MCAST;
pRtInfo->dwRtInfoType = (pirno->irno_proto == PROTO_IP_LOCAL) ?
MIB_IPROUTE_TYPE_DIRECT : 0;
pRtInfo->dwRtInfoAge = INFINITE;
pRtInfo->dwRtInfoNextHopAS = 0;
pRtInfo->dwRtInfoPolicy = 0;
return;
}
DWORD
BlockConvertRoutesToStatic (
IN HANDLE hRtmHandle,
IN DWORD dwIfIndex,
IN DWORD dwProtocolId
)
{
HANDLE hRtmEnum;
RTM_ENTITY_INFO reiInfo;
RTM_NET_ADDRESS rnaDest;
PRTM_ROUTE_INFO pRouteInfo1;
PRTM_ROUTE_INFO pRouteInfo2;
RTM_NEXTHOP_INFO nhiInfo;
RTM_NEXTHOP_HANDLE hNextHop;
PHANDLE hRoutes;
DWORD dwHandles;
DWORD dwFlags;
DWORD dwNumBytes;
DWORD i, j, k;
BOOL fDeleted;
DWORD dwResult;
hRoutes = HeapAlloc(
IPRouterHeap,
0,
g_rtmProfile.MaxHandlesInEnum * sizeof(HANDLE)
);
if (hRoutes == NULL)
{
Trace1(
ERR,
"BlockConvertRoutesToStatic : error allocating %d bytes"
"for route handes",
g_rtmProfile.MaxHandlesInEnum * sizeof(HANDLE)
);
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return ERROR_NOT_ENOUGH_MEMORY;
}
dwNumBytes = RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute);
pRouteInfo1 = HeapAlloc(
IPRouterHeap,
0,
dwNumBytes
);
if (pRouteInfo1 == NULL)
{
Trace1(
ERR,
"BlockConvertRoutesToStatic : error allocating %d bytes"
"for route info",
dwNumBytes
);
HeapFree(IPRouterHeap, 0, hRoutes);
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return ERROR_NOT_ENOUGH_MEMORY;
}
pRouteInfo2 = HeapAlloc(
IPRouterHeap,
0,
dwNumBytes
);
if (pRouteInfo2 == NULL)
{
Trace1(
ERR,
"BlockConvertRoutesToStatic : error allocating %d bytes"
"for route info",
dwNumBytes
);
HeapFree(IPRouterHeap, 0, hRoutes);
HeapFree(IPRouterHeap, 0, pRouteInfo1);
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return ERROR_NOT_ENOUGH_MEMORY;
}
//
// Enum all routes on the interface that we need
//
dwResult = RtmCreateRouteEnum(hRtmHandle,
NULL,
RTM_VIEW_MASK_ANY,
RTM_ENUM_ALL_ROUTES,
NULL,
RTM_MATCH_INTERFACE,
NULL,
dwIfIndex,
&hRtmEnum);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"BlockConvertRoutesToStatic: Error %d creating handle for %d\n",
dwResult,
hRtmHandle);
HeapFree(IPRouterHeap, 0, hRoutes);
HeapFree(IPRouterHeap, 0, pRouteInfo1);
HeapFree(IPRouterHeap, 0, pRouteInfo2);
return dwResult;
}
do
{
dwHandles = g_rtmProfile.MaxHandlesInEnum;
dwResult = RtmGetEnumRoutes(hRtmHandle,
hRtmEnum,
&dwHandles,
hRoutes);
for (i = 0; i < dwHandles; i++)
{
fDeleted = FALSE;
// Get the route info from the handle
if (RtmGetRouteInfo(hRtmHandle,
hRoutes[i],
pRouteInfo1,
&rnaDest) is NO_ERROR)
{
// Does this match the routing protocol we want ?
if ((RtmGetEntityInfo(hRtmHandle,
pRouteInfo1->RouteOwner,
&reiInfo) is NO_ERROR) &&
(reiInfo.EntityId.EntityProtocolId is dwProtocolId))
{
//
// Add new static route with same information
//
CopyMemory(pRouteInfo2,
pRouteInfo1,
sizeof(RTM_ROUTE_INFO));
// Adjust the preference to confirm to protocol
pRouteInfo2->PrefInfo.Preference =
ComputeRouteMetric(PROTO_IP_NT_AUTOSTATIC);
// Adjust the neighbour to corr to new protocol
if (pRouteInfo1->Neighbour)
{
// In case we cant get convert the neighbour
pRouteInfo2->Neighbour = NULL;
if (RtmGetNextHopInfo(hRtmHandle,
pRouteInfo1->Neighbour,
&nhiInfo) is NO_ERROR)
{
// Add the same neigbour using new protocol
hNextHop = NULL;
if (RtmAddNextHop(hRtmHandle,
&nhiInfo,
&hNextHop,
&dwFlags) is NO_ERROR)
{
pRouteInfo2->Neighbour = hNextHop;
}
RtmReleaseNextHopInfo(hRtmHandle, &nhiInfo);
}
}
// Adjust the next hops to corr to new protocol
for (j = k = 0;
j < pRouteInfo1->NextHopsList.NumNextHops;
j++)
{
if (RtmGetNextHopInfo(hRtmHandle,
pRouteInfo1->NextHopsList.NextHops[j],
&nhiInfo) is NO_ERROR)
{
// Add the same nexthop using new protocol
hNextHop = NULL;
if (RtmAddNextHop(hRtmHandle,
&nhiInfo,
&hNextHop,
&dwFlags) is NO_ERROR)
{
pRouteInfo2->NextHopsList.NextHops[k++] = hNextHop;
}
RtmReleaseNextHopInfo(hRtmHandle, &nhiInfo);
}
}
pRouteInfo2->NextHopsList.NumNextHops = (USHORT) k;
// Add the new route with the next hop information
if (k > 0)
{
dwFlags = 0;
if (RtmAddRouteToDest(hRtmHandle,
NULL,
&rnaDest,
pRouteInfo2,
INFINITE,
NULL,
0,
NULL,
&dwFlags) is NO_ERROR)
{
// Route add is successful - delete old route
if (RtmDeleteRouteToDest(pRouteInfo1->RouteOwner,
hRoutes[i],
&dwFlags) is NO_ERROR)
{
fDeleted = TRUE;
}
}
RtmReleaseNextHops(hRtmHandle,
k,
pRouteInfo2->NextHopsList.NextHops);
}
}
RtmReleaseRouteInfo(hRtmHandle, pRouteInfo1);
}
if (!fDeleted)
{
RtmReleaseRoutes(hRtmHandle, 1, &hRoutes[i]);
}
}
}
while (dwResult is NO_ERROR);
RtmDeleteEnumHandle(hRtmHandle, hRtmEnum);
HeapFree(IPRouterHeap, 0, hRoutes);
HeapFree(IPRouterHeap, 0, pRouteInfo1);
HeapFree(IPRouterHeap, 0, pRouteInfo2);
return NO_ERROR;
}
DWORD
DeleteRtmRoutes (
IN HANDLE hRtmHandle,
IN DWORD dwIfIndex,
IN BOOL fDeleteAll
)
{
HANDLE hRtmEnum;
PHANDLE hRoutes;
DWORD dwHandles;
DWORD dwFlags;
DWORD i;
DWORD dwResult;
hRoutes = HeapAlloc(
IPRouterHeap,
0,
g_rtmProfile.MaxHandlesInEnum * sizeof(HANDLE)
);
if (hRoutes == NULL)
{
Trace1(ERR,
"DeleteRtmRoutes: Error allocating %d bytes",
g_rtmProfile.MaxHandlesInEnum * sizeof(HANDLE));
return ERROR_NOT_ENOUGH_MEMORY;
}
dwFlags = fDeleteAll ? 0: RTM_MATCH_INTERFACE;
dwResult = RtmCreateRouteEnum(hRtmHandle,
NULL,
RTM_VIEW_MASK_ANY,
RTM_ENUM_OWN_ROUTES,
NULL,
dwFlags,
NULL,
dwIfIndex,
&hRtmEnum);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"DeleteRtmRoutes: Error %d creating handle for %d\n",
dwResult,
hRtmHandle);
HeapFree(IPRouterHeap, 0, hRoutes);
return dwResult;
}
do
{
dwHandles = g_rtmProfile.MaxHandlesInEnum;
dwResult = RtmGetEnumRoutes(hRtmHandle,
hRtmEnum,
&dwHandles,
hRoutes);
for (i = 0; i < dwHandles; i++)
{
if (RtmDeleteRouteToDest(hRtmHandle,
hRoutes[i],
&dwFlags) isnot NO_ERROR)
{
// If delete is successful, this is automatic
RtmReleaseRoutes(hRtmHandle, 1, &hRoutes[i]);
}
}
}
while (dwResult is NO_ERROR);
RtmDeleteEnumHandle(hRtmHandle, hRtmEnum);
HeapFree(IPRouterHeap, 0, hRoutes);
return NO_ERROR;
}
DWORD
DeleteRtmNexthops (
IN HANDLE hRtmHandle,
IN DWORD dwIfIndex,
IN BOOL fDeleteAll
)
{
PRTM_NEXTHOP_INFO pNexthop;
PHANDLE hNexthops;
HANDLE hRtmEnum;
DWORD dwHandles;
DWORD i;
DWORD dwResult;
hNexthops = HeapAlloc(
IPRouterHeap,
0,
g_rtmProfile.MaxHandlesInEnum * sizeof(HANDLE)
);
if (hNexthops == NULL)
{
Trace1(ERR,
"DeleteRtmNextHops: Error allocating %d bytes",
g_rtmProfile.MaxHandlesInEnum * sizeof(HANDLE));
return ERROR_NOT_ENOUGH_MEMORY;
}
dwResult = RtmCreateNextHopEnum(hRtmHandle,
0,
NULL,
&hRtmEnum);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"DeleteAllNexthops: Error %d creating handle for %d\n",
dwResult,
hRtmHandle);
HeapFree(IPRouterHeap, 0, hNexthops);
return dwResult;
}
do
{
dwHandles = g_rtmProfile.MaxHandlesInEnum;
dwResult = RtmGetEnumNextHops(hRtmHandle,
hRtmEnum,
&dwHandles,
hNexthops);
for (i = 0; i < dwHandles; i++)
{
if (!fDeleteAll)
{
//
// Make sure that the interface matches
//
if ((RtmGetNextHopPointer(hRtmHandle,
hNexthops[i],
&pNexthop) isnot NO_ERROR) ||
(pNexthop->InterfaceIndex != dwIfIndex))
{
RtmReleaseNextHops(hRtmHandle, 1, &hNexthops[i]);
continue;
}
}
// We need to delete this next hop here
if (RtmDeleteNextHop(hRtmHandle,
hNexthops[i],
NULL) isnot NO_ERROR)
{
// If delete is successful, this is automatic
RtmReleaseNextHops(hRtmHandle, 1, &hNexthops[i]);
}
}
}
while (dwResult is NO_ERROR);
RtmDeleteEnumHandle(hRtmHandle, hRtmEnum);
HeapFree(IPRouterHeap, 0, hNexthops);
return NO_ERROR;
}