Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3485 lines
96 KiB

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
routing\ip\rtrmgr\route.c
Abstract:
All routes related code lives here.
Revision History:
Gurdeep Singh Pall 6/15/95 Created
--*/
#include "allinc.h"
DWORD
WINAPI
GetBestRoute(
IN DWORD dwDestAddr,
IN DWORD dwSourceAddr, OPTIONAL
OUT PMIB_IPFORWARDROW pBestRoute
);
DWORD
InitializeStaticRoutes(
PICB pIcb,
PRTR_INFO_BLOCK_HEADER pInfoHdr
)
/*++
Routine Description:
Adds static routes with RTM
Arguments:
pIcb The ICB of the interface for whom the routes are
pInfoHdr Pointer to info block containing IP_ROUTE_INFO
Return Value:
NO_ERROR
--*/
{
DWORD dwNumRoutes, dwResult;
DWORD i, j;
PRTR_TOC_ENTRY pToc;
PINTERFACE_ROUTE_INFO pRoutes;
BOOL bP2P;
TraceEnter("IntializeStaticRoutes");
//
// If this is a client, only do the special client processing
//
if(pIcb->ritType is ROUTER_IF_TYPE_CLIENT)
{
CopyOutClientRoutes(pIcb,
pInfoHdr);
return NO_ERROR;
}
//
// We first go through the init route table and add any route going
// over that interface that is
// (i) not a local net route
// (ii) not a subnet/net broadcast route
// (iii) not a Loopback route,
// (iv) not a CLASS D or E route and not a 255.255.255.255 destination
// (vi) a PROTO_IP_LOCAL or PROTO_IP_NETMGMT route
//
CheckBindingConsistency(pIcb);
bP2P = IsIfP2P(pIcb->ritType);
pToc = GetPointerToTocEntry(IP_ROUTE_INFO,
pInfoHdr);
if((pToc is NULL) or
(pToc->InfoSize is 0))
{
Trace0(ROUTE,"IntializeStaticRoutes: No Routes found");
TraceLeave("IntializeStaticRoutes");
return NO_ERROR;
}
pRoutes = GetInfoFromTocEntry(pInfoHdr,
pToc);
if(pRoutes is NULL)
{
Trace0(ROUTE,"IntializeStaticRoutes: No Routes found");
TraceLeave("IntializeStaticRoutes");
return NO_ERROR;
}
dwNumRoutes = pToc->Count;
for (i=0; i< dwNumRoutes; i++)
{
DWORD dwMask;
dwMask = GetBestNextHopMaskGivenICB(pIcb,
pRoutes[i].dwRtInfoNextHop);
dwResult = AddSingleRoute(pIcb->dwIfIndex,
(&pRoutes[i]),
dwMask,
0, // RTM_ROUTE_INFO::Flags
TRUE, // Valid route
TRUE,
bP2P,
NULL); // Add the route to stack, if need be
if(dwResult isnot NO_ERROR)
{
Trace3(ERR,
"IntializeStaticRoutes: Error %d adding config route to %x over %S",
dwResult,
pRoutes[i].dwRtInfoDest,
pIcb->pwszName);
}
}
TraceLeave("IntializeStaticRoutes");
return NO_ERROR;
}
DWORD
CopyOutClientRoutes(
PICB pIcb,
PRTR_INFO_BLOCK_HEADER pInfoHdr
)
/*++
Routine Description:
Stores a copy of the client static routes
Arguments:
pIcb The ICB of the interface for whom the routes are
pInfoHdr Pointer to info block containing IP_ROUTE_INFO
Return Value:
NO_ERROR
--*/
{
PINTERFACE_ROUTE_INFO pRoutes;
PINTERFACE_ROUTE_TABLE pStore;
DWORD i, dwNumRoutes;
PRTR_TOC_ENTRY pToc;
pToc = GetPointerToTocEntry(IP_ROUTE_INFO,
pInfoHdr);
if((pToc is NULL) or
(pToc->InfoSize is 0))
{
return NO_ERROR;
}
pRoutes = GetInfoFromTocEntry(pInfoHdr,
pToc);
if (pRoutes is NULL)
{
return NO_ERROR;
}
dwNumRoutes = pToc->Count;
if(dwNumRoutes is 0)
{
return NO_ERROR;
}
pStore = HeapAlloc(IPRouterHeap,
HEAP_ZERO_MEMORY,
SIZEOF_IPFORWARDTABLE(dwNumRoutes));
if(pStore is NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
pStore->dwNumEntries = dwNumRoutes;
for(i = 0; i < dwNumRoutes; i++)
{
pStore->table[i] = pRoutes[i];
}
pIcb->pStoredRoutes = pStore;
return NO_ERROR;
}
DWORD
AddSingleRoute(
DWORD dwIfIndex,
PINTERFACE_ROUTE_INFO pRtInfo,
DWORD dwNextHopMask,
WORD wRtmFlags,
BOOL bValid,
BOOL bAddToStack,
BOOL bP2P,
HANDLE *phRtmRoute OPTIONAL
)
/*++
Routine Description
Adds a route with RTM
Arguments
pIcb The ICB of the interface for whom the route is
pIpForw The route
mask Mask for destination
Return Value
NO_ERROR or some code from RTM
--*/
{
DWORD i, dwResult, dwRouteFlags;
HANDLE hRtmHandle;
DWORD dwOldIfIndex;
TraceEnter("AddSingleRoute");
TraceRoute2(ROUTE,
"route to %d.%d.%d.%d/%d.%d.%d.%d",
PRINT_IPADDR(pRtInfo->dwRtInfoDest),
PRINT_IPADDR(pRtInfo->dwRtInfoMask));
TraceRoute4(ROUTE,
"Flags 0x%x Valid %d Stack %d P2P %d",
wRtmFlags, bValid, bAddToStack, bP2P
);
hRtmHandle = NULL;
for(i = 0;
i < sizeof(g_rgRtmHandles)/sizeof(RTM_HANDLE_INFO);
i++)
{
if(pRtInfo->dwRtInfoProto is g_rgRtmHandles[i].dwProtoId)
{
hRtmHandle = g_rgRtmHandles[i].hRouteHandle;
break;
}
}
if(hRtmHandle is NULL)
{
Trace1(ERR,
"AddSingleRoute: Protocol %d not valid",
pRtInfo->dwRtInfoProto);
return ERROR_INVALID_PARAMETER;
}
if((pRtInfo->dwRtInfoDest & pRtInfo->dwRtInfoMask) isnot pRtInfo->dwRtInfoDest)
{
Trace2(ERR,
"AddSingleRoute: Dest %d.%d.%d.%d and Mask %d.%d.%d.%d wrong",
PRINT_IPADDR(pRtInfo->dwRtInfoDest),
PRINT_IPADDR(pRtInfo->dwRtInfoMask));
TraceLeave("AddSingleRoute");
return ERROR_INVALID_PARAMETER;
}
if((((DWORD)(pRtInfo->dwRtInfoDest & 0x000000FF)) >= (DWORD)0x000000E0) and
(pRtInfo->dwRtInfoDest isnot ALL_ONES_BROADCAST) and
(pRtInfo->dwRtInfoDest isnot LOCAL_NET_MULTICAST))
{
//
// This will catch the CLASS D/E
//
Trace1(ERR,
"AddSingleRoute: Dest %d.%d.%d.%d is invalid",
PRINT_IPADDR(pRtInfo->dwRtInfoDest));
TraceLeave("AddSingleRoute");
return ERROR_INVALID_PARAMETER;
}
// Special case to deal with weird utilities (legacy UI, etc):
if (pRtInfo->dwRtInfoViewSet is 0)
{
pRtInfo->dwRtInfoViewSet = RTM_VIEW_MASK_UCAST | RTM_VIEW_MASK_MCAST;
}
#if 0
// Removed this check since a metric of 0 is legal, for example for
// routes to the loopback interface.
if(pRtInfo->dwRtInfoMetric1 is 0)
{
Trace0(ERR,
"AddSingleRoute: Metric1 cant be 0");
TraceLeave("AddSingleRoute");
return ERROR_INVALID_PARAMETER;
}
#endif
if(bP2P)
{
dwNextHopMask = ALL_ONES_MASK;
//pRtInfo->dwRtInfoNextHop = 0;
}
//
// The route might not have the right index since config routes dont know
// their interface id
//
dwOldIfIndex = pRtInfo->dwRtInfoIfIndex;
pRtInfo->dwRtInfoIfIndex = dwIfIndex;
//
// Set the appropritate route flags
//
dwRouteFlags = 0;
if(bValid)
{
dwRouteFlags |= IP_VALID_ROUTE;
}
if(bAddToStack)
{
dwRouteFlags |= IP_STACK_ROUTE;
}
if(bP2P)
{
dwRouteFlags |= IP_P2P_ROUTE;
}
// these flags correspond to RTM_ROUTE_INFO::Flags
dwRouteFlags |= (wRtmFlags << 16);
//
// Add the forward route with RTM
//
dwResult = AddRtmRoute(hRtmHandle,
pRtInfo,
dwRouteFlags,
dwNextHopMask,
INFINITE,
phRtmRoute);
if (dwResult isnot NO_ERROR)
{
Trace1(ERR, "AddSingleRoute: Could not add route to: %x",
pRtInfo->dwRtInfoDest) ;
}
pRtInfo->dwRtInfoIfIndex = dwOldIfIndex;
TraceLeave("AddSingleRoute");
return dwResult;
}
DWORD
DeleteSingleRoute(
DWORD dwIfIndex,
DWORD dwDestAddr,
DWORD dwDestMask,
DWORD dwNexthop,
DWORD dwProtoId,
BOOL bP2P
)
/*++
Routine Description:
Deletes a single route from RTM
Arguments:
InterfaceID Index of the interface
dest Destination address
nexthop Next hop address
Return Value:
NO_ERROR or some code from RTM
--*/
{
DWORD i, dwResult;
HANDLE hRtmHandle;
INTERFACE_ROUTE_INFO RtInfo;
TraceEnter("DeleteSingleRoute");
TraceRoute2(
ROUTE, "DeleteSingleRoute: %d.%d.%d.%d/%d.%d.%d.%d",
PRINT_IPADDR( dwDestAddr ),
PRINT_IPADDR( dwDestMask )
);
hRtmHandle = NULL;
for(i = 0;
i < sizeof(g_rgRtmHandles)/sizeof(RTM_HANDLE_INFO);
i++)
{
if(dwProtoId is g_rgRtmHandles[i].dwProtoId)
{
hRtmHandle = g_rgRtmHandles[i].hRouteHandle;
break;
}
}
if(hRtmHandle is NULL)
{
Trace1(ERR,
"DeleteSingleRoute: Protocol %d not valid",
dwProtoId);
return ERROR_INVALID_PARAMETER;
}
RtInfo.dwRtInfoNextHop = dwNexthop;
/*
if(bP2P)
{
RtInfo.dwRtInfoNextHop = 0;
}
else
{
RtInfo.dwRtInfoNextHop = dwNexthop;
}
*/
RtInfo.dwRtInfoDest = dwDestAddr;
RtInfo.dwRtInfoMask = dwDestMask;
RtInfo.dwRtInfoIfIndex = dwIfIndex;
RtInfo.dwRtInfoProto = dwProtoId;
//
// Delete this forward route from RTM
//
dwResult = DeleteRtmRoute(hRtmHandle,
&RtInfo);
if(dwResult isnot NO_ERROR)
{
Trace1(ERR,
"DeleteSingleRoute: Error %d deleting route in RTM.",
dwResult);
}
TraceLeave("DeleteSingleRoute");
return dwResult;
}
DWORD
DeleteAllRoutes(
IN DWORD dwIfIndex,
IN BOOL bStaticOnly
)
/*++
Routine Description
Deletes all the routes (owned by IP Router Manager) on the interface
Arguments
dwIfIndex
bStaticOnly
Return Value
Error returned from RTM
--*/
{
DWORD i, dwResult = NO_ERROR;
TraceEnter("DeleteAllRoutes");
for(i = 0;
i < sizeof(g_rgRtmHandles)/sizeof(RTM_HANDLE_INFO);
i++)
{
if(bStaticOnly && !g_rgRtmHandles[i].bStatic)
{
continue;
}
dwResult = DeleteRtmRoutesOnInterface(g_rgRtmHandles[i].hRouteHandle,
dwIfIndex);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"DeleteAllRoutes: BlockDeleteRoutes returned %d for %d",
dwResult,
g_rgRtmHandles[i].dwProtoId);
continue;
}
dwResult = DeleteRtmNexthopsOnInterface(g_rgRtmHandles[i].hRouteHandle,
dwIfIndex);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"DeleteAllRoutes: BlockDeleteNextHops returned %d for %d",
dwResult,
g_rgRtmHandles[i].dwProtoId);
continue;
}
}
TraceLeave("DeleteAllRoutes");
return dwResult;
}
VOID
DeleteAllClientRoutes(
PICB pIcb,
DWORD dwServerIfIndex
)
/*++
Routine Description
Deletes all routes going to a client. Only needed for removal from
RTM, stack removes them since the link has been deleted
Arguments
pIcb
dwServerIfIndex - ServerInterface's ifIndex
Return Value
--*/
{
ULONG i;
TraceEnter("DeleteAllClientRoutes");
IpRtAssert(pIcb->ritType is ROUTER_IF_TYPE_CLIENT);
if((pIcb->pStoredRoutes is NULL) or
(pIcb->pibBindings is NULL))
{
return;
}
for(i = 0 ; i < pIcb->pStoredRoutes->dwNumEntries; i++)
{
DeleteSingleRoute(dwServerIfIndex,
pIcb->pStoredRoutes->table[i].dwRtInfoDest,
pIcb->pStoredRoutes->table[i].dwRtInfoMask,
pIcb->pibBindings[0].dwAddress,
PROTO_IP_NT_STATIC_NON_DOD,
FALSE);
}
}
VOID
AddAllClientRoutes(
PICB pIcb,
DWORD dwServerIfIndex
)
/*++
Routine Description
Adds the stored routes over the server interface
Arguments
pIcb
dwServerIfIndex - ServerInterface's ifIndex
Return Value
--*/
{
ULONG i;
TraceEnter("AddAllClientRoutes");
IpRtAssert(pIcb->ritType is ROUTER_IF_TYPE_CLIENT);
if((pIcb->pStoredRoutes is NULL) or
(pIcb->pibBindings is NULL))
{
return;
}
for(i = 0; i < pIcb->pStoredRoutes->dwNumEntries; i++)
{
//
// Fix the next hop since that is not known
// Also fix someother fields which we know are not being set
// correctly for client routes
//
pIcb->pStoredRoutes->table[i].dwRtInfoNextHop =
pIcb->pibBindings[0].dwAddress;
pIcb->pStoredRoutes->table[i].dwRtInfoProto =
PROTO_IP_NT_STATIC_NON_DOD;
pIcb->pStoredRoutes->table[i].dwRtInfoMetric2 = 0;
pIcb->pStoredRoutes->table[i].dwRtInfoMetric3 = 0;
pIcb->pStoredRoutes->table[i].dwRtInfoPreference =
ComputeRouteMetric(MIB_IPPROTO_LOCAL);
pIcb->pStoredRoutes->table[i].dwRtInfoViewSet =
RTM_VIEW_MASK_UCAST | RTM_VIEW_MASK_MCAST;
AddSingleRoute(dwServerIfIndex,
&(pIcb->pStoredRoutes->table[i]),
pIcb->pibBindings[0].dwMask,
0, // RTM_ROUTE_INFO::Flags
TRUE,
TRUE,
FALSE,
NULL);
}
}
DWORD
GetNumStaticRoutes(
PICB pIcb
)
/*++
Routine Description
Figure out the number of static routes associated with an interface
Arguments
pIcb The ICB of the interface whose route count is needed
Return Value
Number of routes associated with an interface
--*/
{
HANDLE hRtmHandle;
HANDLE hRtmEnum;
PHANDLE hRoutes;
DWORD dwHandles;
DWORD dwNumRoutes;
DWORD i, j;
DWORD dwResult;
hRoutes = HeapAlloc(
IPRouterHeap,
0,
g_rtmProfile.MaxHandlesInEnum * sizeof(HANDLE)
);
if (hRoutes == NULL)
{
Trace1(ERR,
"GetNumStaticRoutes: Error allocating %d bytes for "
"handles\n",
g_rtmProfile.MaxHandlesInEnum * sizeof(HANDLE)
);
return 0;
}
dwNumRoutes = 0;
for(i = 0;
i < sizeof(g_rgRtmHandles)/sizeof(RTM_HANDLE_INFO);
i++)
{
if(!g_rgRtmHandles[i].bStatic)
{
continue;
}
hRtmHandle = g_rgRtmHandles[i].hRouteHandle;
dwResult = RtmCreateRouteEnum(hRtmHandle,
NULL,
RTM_VIEW_MASK_UCAST|RTM_VIEW_MASK_MCAST,
RTM_ENUM_OWN_ROUTES,
NULL,
RTM_MATCH_INTERFACE,
NULL,
pIcb->dwIfIndex,
&hRtmEnum);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"GetNumStaticRoutes: Error %d creating handle for %d\n",
dwResult,
g_rgRtmHandles[i].dwProtoId);
continue;
}
do
{
dwHandles = g_rtmProfile.MaxHandlesInEnum;
dwResult = RtmGetEnumRoutes(hRtmHandle,
hRtmEnum,
&dwHandles,
hRoutes);
dwNumRoutes += dwHandles;
RtmReleaseRoutes(hRtmHandle, dwHandles, hRoutes);
}
while (dwResult is NO_ERROR);
RtmDeleteEnumHandle(hRtmHandle, hRtmEnum);
}
HeapFree(IPRouterHeap, 0, hRoutes);
return dwNumRoutes;
}
DWORD
GetInterfaceRouteInfo(
IN PICB pIcb,
IN PRTR_TOC_ENTRY pToc,
IN PBYTE pbDataPtr,
IN OUT PRTR_INFO_BLOCK_HEADER pInfoHdr,
IN OUT PDWORD pdwInfoSize
)
/*++
Routine Description
Gets the route info (static routes) associated with an interface
Arguments
pIcb The ICB of the interface for whom the info is requested
pToc Pointer to TOC for the total inforamtion
pbDataPtr Pointer to free space where info can be written
pInfoHdr Pointer to Info Hdr
pdwInfoSize Size of free space
Return Value
NO_ERROR or some code from RTM
--*/
{
DWORD dwNumRoutes;
PINTERFACE_ROUTE_INFO pRoutes = (PINTERFACE_ROUTE_INFO) pbDataPtr ;
DWORD dwMaxRoutes;
TraceEnter("GetInterfaceRouteInfo");
dwNumRoutes = GetNumStaticRoutes(pIcb);
dwMaxRoutes = MAX_ROUTES_IN_BUFFER(*pdwInfoSize);
if(dwNumRoutes > dwMaxRoutes)
{
*pdwInfoSize = SIZEOF_ROUTEINFO(dwNumRoutes);
return ERROR_INSUFFICIENT_BUFFER;
}
dwNumRoutes = ReadAllStaticRoutesIntoBuffer(pIcb,
pRoutes,
dwMaxRoutes);
*pdwInfoSize = SIZEOF_ROUTEINFO(dwNumRoutes);
//pToc->InfoVersion = sizeof(INTERFACE_ROUTE_INFO);
pToc->InfoSize = sizeof(INTERFACE_ROUTE_INFO);
pToc->InfoType = IP_ROUTE_INFO ;
pToc->Count = dwNumRoutes;
pToc->Offset = (ULONG)(pbDataPtr - (PBYTE) pInfoHdr) ;
TraceLeave("GetInterfaceRouteInfo");
return NO_ERROR;
}
DWORD
ReadAllStaticRoutesIntoBuffer(
PICB pIcb,
PINTERFACE_ROUTE_INFO pRoutes,
DWORD dwMaxRoutes
)
/*++
Routine Description
Reads out static routes from RTM
Arguments
pIcb The ICB of the interface for whom the route is
routptr Pointer to where info has to be written out
dwMaxRoutes Max routes the buffer can hold
Return Value
Count of routes written out
--*/
{
HANDLE hRtmHandle;
HANDLE hRtmEnum;
PHANDLE hRoutes;
PRTM_NET_ADDRESS pDestAddr;
PRTM_ROUTE_INFO pRoute;
RTM_NEXTHOP_INFO nhiInfo;
RTM_ENTITY_INFO entityInfo;
DWORD dwNumRoutes;
DWORD dwHandles;
DWORD i, j;
DWORD dwResult;
pRoute = HeapAlloc(
IPRouterHeap,
0,
RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
);
if (pRoute == NULL)
{
return 0;
}
hRoutes = HeapAlloc(
IPRouterHeap,
0,
g_rtmProfile.MaxHandlesInEnum * sizeof(HANDLE)
);
if (hRoutes == NULL)
{
HeapFree(IPRouterHeap, 0, pRoute);
return 0;
}
pDestAddr = HeapAlloc(
IPRouterHeap,
0,
sizeof(RTM_NET_ADDRESS)
);
if (pDestAddr == NULL)
{
HeapFree(IPRouterHeap, 0, pRoute);
HeapFree(IPRouterHeap, 0, hRoutes);
return 0;
}
dwNumRoutes = 0;
for(i = 0;
(i < sizeof(g_rgRtmHandles)/sizeof(RTM_HANDLE_INFO)) and
(dwNumRoutes < dwMaxRoutes);
i++)
{
if(!g_rgRtmHandles[i].bStatic)
{
continue;
}
hRtmHandle = g_rgRtmHandles[i].hRouteHandle;
dwResult = RtmCreateRouteEnum(hRtmHandle,
NULL,
RTM_VIEW_MASK_UCAST|RTM_VIEW_MASK_MCAST,
RTM_ENUM_OWN_ROUTES,
NULL,
RTM_MATCH_INTERFACE,
NULL,
pIcb->dwIfIndex,
&hRtmEnum);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"ReadAllStaticRoutesIntoBuffer: Error %d creating handle for %d\n",
dwResult,
g_rgRtmHandles[i].dwProtoId);
continue;
}
do
{
dwHandles = g_rtmProfile.MaxHandlesInEnum;
dwResult = RtmGetEnumRoutes(hRtmHandle,
hRtmEnum,
&dwHandles,
hRoutes);
//
// We pick up all that we can in the buffer. If things
// change between the time the size of the buffer was
// calculated and now,we discard the additional routes
//
// TBD: * Log an event if the buffer was too small *
//
for (j = 0; (j < dwHandles) && (dwNumRoutes < dwMaxRoutes); j++)
{
// Get the route info corr. to this handle
if (RtmGetRouteInfo(hRtmHandle,
hRoutes[j],
pRoute,
pDestAddr) is NO_ERROR)
{
if (RtmGetEntityInfo(hRtmHandle,
pRoute->RouteOwner,
&entityInfo) is NO_ERROR)
{
if (RtmGetNextHopInfo(hRtmHandle,
pRoute->NextHopsList.NextHops[0],
&nhiInfo) is NO_ERROR)
{
// We assume that static routes have only 1 nexthop
ConvertRtmToRouteInfo(entityInfo.EntityId.EntityProtocolId,
pDestAddr,
pRoute,
&nhiInfo,
&(pRoutes[dwNumRoutes++]));
RtmReleaseNextHopInfo(hRtmHandle, &nhiInfo);
}
}
RtmReleaseRouteInfo(hRtmHandle, pRoute);
}
}
RtmReleaseRoutes(hRtmHandle, dwHandles, hRoutes);
}
while ((dwResult is NO_ERROR) && (dwNumRoutes < dwMaxRoutes));
RtmDeleteEnumHandle(hRtmHandle, hRtmEnum);
}
HeapFree(IPRouterHeap, 0, pRoute);
HeapFree(IPRouterHeap, 0, hRoutes);
HeapFree(IPRouterHeap, 0, pDestAddr);
return dwNumRoutes;
}
DWORD
SetRouteInfo(
PICB pIcb,
PRTR_INFO_BLOCK_HEADER pInfoHdr
)
/*++
Routine Description
Sets the route info associated with an interface
First we add the routes present in the route info. Then we enumerate
the routes and delete those that we dont find in the route info
Arguments
pIcb The ICB of the interface for whom the route info is
Return Value
NO_ERROR
--*/
{
PINTERFACE_ROUTE_INFO pRoutes;
PRTR_TOC_ENTRY pToc;
BOOL bP2P;
HANDLE hRtmHandle;
HANDLE hRtmEnum;
PHANDLE hAddedRoutes;
DWORD dwNumRoutes;
PHANDLE hRoutes;
DWORD dwHandles;
DWORD i, j, k;
DWORD dwFlags, dwResult;
TraceEnter("SetRouteInfo");
if(pIcb->dwOperationalState is UNREACHABLE)
{
Trace1(ROUTE,
"SetRouteInfo: %S is unreachable, not setting routes",
pIcb->pwszName);
return NO_ERROR;
}
pToc = GetPointerToTocEntry(IP_ROUTE_INFO, pInfoHdr);
if(pToc is NULL)
{
//
// No TOC means no change
//
TraceLeave("SetRouteInfo");
return NO_ERROR;
}
pRoutes = (PINTERFACE_ROUTE_INFO)GetInfoFromTocEntry(pInfoHdr,
pToc);
if((pToc->InfoSize is 0) or (pRoutes is NULL))
{
//
// Delete all the static routes
//
DeleteAllRoutes(pIcb->dwIfIndex,
TRUE);
TraceLeave("SetRouteInfo");
return NO_ERROR;
}
dwResult = NO_ERROR;
dwNumRoutes = pToc->Count;
// Handles to routes added are stored here
hAddedRoutes = HeapAlloc(
IPRouterHeap,
0,
dwNumRoutes * sizeof(HANDLE)
);
if (hAddedRoutes == NULL)
{
Trace1(ERR,
"SetRouteInfo: Error allocating %d bytes for addded "
"route handles",
dwNumRoutes * sizeof(HANDLE));
TraceLeave("SetRouteInfo");
return ERROR_NOT_ENOUGH_MEMORY;
}
hRoutes = HeapAlloc(
IPRouterHeap,
0,
g_rtmProfile.MaxHandlesInEnum * sizeof(HANDLE)
);
if (hRoutes == NULL)
{
Trace1(ERR,
"SetRouteInfo: Error allocating %d bytes for route "
"handles",
dwNumRoutes * sizeof(HANDLE));
HeapFree(IPRouterHeap, 0, hAddedRoutes);
TraceLeave("SetRouteInfo");
return ERROR_NOT_ENOUGH_MEMORY;
}
//
// The route info is set in two phases. First, all the routes specified
// are added, and then, the ones present, but not in the info are deleted
//
bP2P = IsIfP2P(pIcb->ritType);
for(i = j = 0; i < dwNumRoutes; i++)
{
DWORD dwMask;
if((pIcb->dwOperationalState is DISCONNECTED) and
(pRoutes[i].dwRtInfoProto is PROTO_IP_NT_STATIC_NON_DOD))
{
continue;
}
//
// If this will be a point to point interface,
// ignore the next hop
//
if(bP2P)
{
pRoutes[i].dwRtInfoNextHop = pIcb->dwRemoteAddress;
dwMask = ALL_ONES_MASK;
}
else
{
dwMask = GetBestNextHopMaskGivenIndex(pIcb->dwIfIndex,
pRoutes[i].dwRtInfoNextHop);
}
if (AddSingleRoute(pIcb->dwIfIndex,
&(pRoutes[i]),
dwMask,
0, // RTM_ROUTE_INFO::Flags
TRUE, // Valid route
TRUE,
bP2P,
&hAddedRoutes[j]) is NO_ERROR)
{
j++;
}
}
dwNumRoutes = j;
//
// Now enumerate the static routes, deleting the routes that are
// not in the new list.
//
for(i = 0;
i < sizeof(g_rgRtmHandles)/sizeof(RTM_HANDLE_INFO);
i++)
{
if(!g_rgRtmHandles[i].bStatic)
{
continue;
}
hRtmHandle = g_rgRtmHandles[i].hRouteHandle;
dwResult = RtmCreateRouteEnum(hRtmHandle,
NULL,
RTM_VIEW_MASK_UCAST | RTM_VIEW_MASK_MCAST,
RTM_ENUM_OWN_ROUTES,
NULL,
RTM_MATCH_INTERFACE,
NULL,
pIcb->dwIfIndex,
&hRtmEnum);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"SetRouteInfo: Error %d creating enum handle for %d",
dwResult,
g_rgRtmHandles[i].dwProtoId);
continue;
}
do
{
dwHandles = g_rtmProfile.MaxHandlesInEnum;
dwResult = RtmGetEnumRoutes(hRtmHandle,
hRtmEnum,
&dwHandles,
hRoutes);
for (j = 0; j < dwHandles; j++)
{
BOOL bFound = FALSE;
for (k = 0; k < dwNumRoutes; k++)
{
if (hRoutes[j] == hAddedRoutes[k])
{
bFound = TRUE;
break;
}
}
if(!bFound)
{
if (RtmDeleteRouteToDest(g_rgRtmHandles[i].hRouteHandle,
hRoutes[j],
&dwFlags) is NO_ERROR)
{
continue;
}
}
RtmReleaseRoutes(g_rgRtmHandles[i].hRouteHandle,
1,
&hRoutes[j]);
}
}
while (dwResult is NO_ERROR);
RtmDeleteEnumHandle(hRtmHandle, hRtmEnum);
}
// Release the array of handles for routes added
RtmReleaseRoutes(g_hLocalRoute, dwNumRoutes, hAddedRoutes);
HeapFree(IPRouterHeap, 0, hAddedRoutes);
HeapFree(IPRouterHeap, 0, hRoutes);
TraceLeave("SetRouteInfo");
return NO_ERROR;
}
#if 0
DWORD
EnableAllStaticRoutes (
DWORD dwInterfaceIndex,
BOOL fenable
)
/*++
Routine Description
Enables or disables Static Routes for an interface
Locks
Called with ICB_LIST lock held as READER
Arguments
pIcb The ICB of the interface
fenable TRUE if enable
Return Value
NO_ERROR
--*/
{
RTM_IP_ROUTE route ;
TraceEnter("EnableAllStaticRoutes");
Trace1(ROUTE, "EnableAllStaticRoutes entered with fenable = %d\n",
fenable) ;
route.RR_InterfaceID = dwInterfaceIndex;
route.RR_RoutingProtocol = PROTO_IP_LOCAL;
RtmBlockSetRouteEnable(g_hRtmHandle,
RTM_ONLY_THIS_INTERFACE | RTM_ONLY_THIS_PROTOCOL,
&route,
fenable);
route.RR_InterfaceID = dwInterfaceIndex;
route.RR_RoutingProtocol = PROTO_IP_NT_AUTOSTATIC;
RtmBlockSetRouteEnable(g_hAutoStaticHandle,
RTM_ONLY_THIS_INTERFACE | RTM_ONLY_THIS_PROTOCOL,
&route,
fenable);
TraceLeave("EnableAllStaticRoutes");
return NO_ERROR;
}
#endif
DWORD
ConvertRoutesToAutoStatic(
DWORD dwProtocolId,
DWORD dwIfIndex
)
/*++
Routine Description
Called to convert routes from a protocol's ownership (IP_RIP) to static
(PROTO_IP_NT_AUTOSTATIC)
Used for autostatic updates etc.
Arguments
protocolid Id of protocol whose routes are to be converted
interfaceindex Index of the interface whose routes are to be converted
Return Value
--*/
{
DWORD dwResult, dwFlags;
TraceEnter("ConvertRoutesToAutoStatic");
#if 0
//
// We now do the delete before calling the protocols update
// route
//
dwResult = DeleteRtmRoutesOnInterface(g_hAutoStaticHandle,
dwIfIndex);
if((dwResult isnot ERROR_NO_ROUTES) and
(dwResult isnot NO_ERROR))
{
Trace1(ERR,
"ConvertRoutesToAutoStatic: Error %d block deleting routes",
dwResult);
}
#endif
if(((dwResult = BlockConvertRoutesToStatic(g_hAutoStaticRoute,
dwIfIndex,
dwProtocolId)) isnot NO_ERROR))
{
dwResult = GetLastError();
Trace1(ROUTE,
"ConvertRoutesToAutoStatic: Rtm returned error: %d",
dwResult);
}
TraceLeave("ConvertRoutesToAutoStatic");
return dwResult;
}
VOID
ChangeAdapterIndexForDodRoutes (
DWORD dwInterfaceIndex
)
/*++
Routine Description
Changes the adapter index for static routes associated with an
interface. The adapter index can go from being valid (the index of a
net card known to the stack) to INVALID_INDEX. This happens when an
interface gets unmapped (say on disconnection). The stack special
cases the routes with index = 0xffffffff (invalid_index) and does demand
dial call out for packets destined on such adapters.
We only enumerate best routes, because this function short circuits
the normal metric comparison of RTM. If we ran this on all the routes,
we would be adding some routes to stack which were not meant to be there.
Arguments
pIcb The ICB of the interface
Return Value
None
--*/
{
HANDLE hRtmHandles[2];
HANDLE hRtmHandle;
HANDLE hRtmEnum;
PHANDLE hRoutes;
PRTM_NET_ADDRESS pDestAddr;
PRTM_ROUTE_INFO pRoute;
RTM_VIEW_SET fBestInViews;
DWORD dwHandles;
DWORD i, j;
DWORD dwResult;
pRoute = HeapAlloc(
IPRouterHeap,
0,
RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
);
if (pRoute == NULL)
{
Trace1(
ERR, "ChangeAdapterIndexForDodRoutes : Error allocating %d "
" bytes for route info",
RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
);
return;
}
hRoutes = HeapAlloc(
IPRouterHeap,
0,
g_rtmProfile.MaxHandlesInEnum * sizeof(HANDLE)
);
if (hRoutes == NULL)
{
Trace1(
ERR, "ChangeAdapterIndexForDodRoutes : Error allocating %d "
" bytes for route handles",
g_rtmProfile.MaxHandlesInEnum * sizeof(HANDLE)
);
HeapFree(IPRouterHeap, 0, pRoute);
return;
}
pDestAddr = HeapAlloc(
IPRouterHeap,
0,
sizeof(RTM_NET_ADDRESS)
);
if (pDestAddr == NULL)
{
Trace1(
ERR, "ChangeAdapterIndexForDodRoutes : Error allocating %d "
" bytes for dest. address",
sizeof(RTM_NET_ADDRESS)
);
HeapFree(IPRouterHeap, 0, pRoute);
HeapFree(IPRouterHeap, 0, hRoutes);
return;
}
hRtmHandles[0] = g_hStaticRoute; // For all static (dod) routes..
hRtmHandles[1] = g_hAutoStaticRoute; // For all autostatic routes....
for (i = 0; i < 2; i++)
{
hRtmHandle = hRtmHandles[i];
dwResult = RtmCreateRouteEnum(hRtmHandle,
NULL,
RTM_VIEW_MASK_UCAST,
RTM_ENUM_OWN_ROUTES,
NULL,
RTM_MATCH_INTERFACE,
NULL,
dwInterfaceIndex,
&hRtmEnum);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"ChangeAdapterIndexForDodRoutes: Error %d creating enum handle for %s routes",
dwResult,
(i == 0) ? "static" : "autostatic");
}
else
{
do
{
dwHandles = g_rtmProfile.MaxHandlesInEnum;
dwResult = RtmGetEnumRoutes(hRtmHandle,
hRtmEnum,
&dwHandles,
hRoutes);
for (j = 0; j < dwHandles; j++)
{
// Is this the best route in unicast view
dwResult = RtmIsBestRoute(hRtmHandle,
hRoutes[j],
&fBestInViews);
if ((dwResult isnot NO_ERROR) or
(!(fBestInViews & RTM_VIEW_MASK_UCAST)))
{
continue;
}
// Get the route info corr. to this handle
if (RtmGetRouteInfo(hRtmHandle,
hRoutes[j],
pRoute,
pDestAddr) is NO_ERROR)
{
//
// This call adds the same route with the forwarder - with
// the current adapter index
//
/*
pRoute->RR_FamilySpecificData.FSD_Metric +=
g_ulDisconnectedMetricIncrement;
RtmAddRoute(g_hStaticRoute,
pRoute,
INFINITE,
&fFlags,
NULL,
NULL);
*/
ChangeRouteWithForwarder(pDestAddr,
pRoute,
TRUE,
TRUE);
RtmReleaseRouteInfo(hRtmHandle, pRoute);
}
}
RtmReleaseRoutes(hRtmHandle, dwHandles, hRoutes);
}
while (dwResult is NO_ERROR);
RtmDeleteEnumHandle(hRtmHandle, hRtmEnum);
}
}
HeapFree(IPRouterHeap, 0, pRoute);
HeapFree(IPRouterHeap, 0, hRoutes);
HeapFree(IPRouterHeap, 0, pDestAddr);
return;
}
#if 0
DWORD
GetMaskForClientSubnet(
DWORD dwInternalAddress
)
/*++
Routine Description
Arguments
Return Value
--*/
{
HANDLE hEnum;
RTM_IP_ROUTE route;
TraceEnter("IsRoutePresent");
route.RR_RoutingProtocol = PROTO_IP_LOCAL;
hEnum = RtmCreateEnumerationHandle(RTM_PROTOCOL_FAMILY_IP,
RTM_ONLY_THIS_PROTOCOL,
&route);
if(hEnum is NULL)
{
return GetClassMask(dwInternalAddress);
}
while(RtmEnumerateGetNextRoute(hEnum, &route) isnot ERROR_NO_MORE_ROUTES)
{
if(route.RR_Network.N_NetMask is 0x00000000)
{
//
// Dont match default route
//
continue;
}
if((dwInternalAddress & route.RR_Network.N_NetMask) is route.RR_Network.N_NetNumber)
{
RtmCloseEnumerationHandle(hEnum);
TraceLeave("IsRoutePresent");
return route.RR_Network.N_NetMask;
}
}
RtmCloseEnumerationHandle(hEnum);
TraceLeave("IsRoutePresent");
return GetClassMask(dwInternalAddress);
}
#endif
VOID
AddAutomaticRoutes(
PICB pIcb,
DWORD dwAddress,
DWORD dwMask
)
/*++
Routine Description
This function adds the routes that are otherwise generated by the
stack. This is mainly done for consistency between RTM and kernel tables
The routes added are:
(i) local loopback
(ii) local multicast
(iii) local subnet -> if the dwMask is not 255.255.255.255
(iv) all subnets broadcast -> if the ClassMask and Mask are different
(v) all 1's broadcast
Since some of the routes are added to the stack the interface to adapter
index map must already be set before this function is called
VERY IMPORTANT:
One MUST add the local route before binding the interface because this
route is not going to be added to stack. However it has higher
priority than say an OSPF route. Now if we first bind the interface
to OSPF, it will add a network route for this interface (which will
get added to the stack since only Router Manager can add non
stack routes). Now when we add the local route to RTM, we will find
our route better because we are higher priority. So RTM will tell
us to delete the OSPF route (which we will since its a stack route).
Then he will tell us to add our route to the stack. But we wont
do this since its a non stack route. So we basically end up deleting
network route from the routing table
Locks
Arguments
Return Value
--*/
{
DWORD dwClassMask, dwResult;
INTERFACE_ROUTE_INFO RtInfo;
BOOL bP2P;
IpRtAssert(pIcb->bBound);
IpRtAssert(dwAddress isnot INVALID_IP_ADDRESS);
return;
bP2P = IsIfP2P(pIcb->ritType);
if(dwMask isnot ALL_ONES_MASK)
{
BOOL bStack, bDontAdd;
RTM_NET_ADDRESS DestAddr;
PRTM_DEST_INFO pDestInfo;
DWORD dwLen;
//
// We now add the subnet route to stack so that if race condition
// had deleted the route on stopping, the restarting
// fixes the problem
//
//
// NOTE: For the RAS Server Interface we need to add the route to the
// routing table only if such a route doesnt exist. We need to add it
// because we want the pool advertised by the routing protocols
// However, adding to the stack will fail since we dont have a valid
// next hop (which is needed for p2mp)
//
bDontAdd = FALSE;
if(pIcb->ritType is ROUTER_IF_TYPE_INTERNAL)
{
//
// If a route to this virtual net exists, dont add it
//
__try
{
pDestInfo =
_alloca(RTM_SIZE_OF_DEST_INFO(g_rtmProfile.NumberOfViews));
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
IpRtAssert(FALSE);
}
RTM_IPV4_LEN_FROM_MASK(dwLen, dwMask);
RTM_IPV4_MAKE_NET_ADDRESS(&DestAddr, (dwAddress & dwMask), dwLen);
if (RtmGetExactMatchDestination(g_hLocalRoute,
&DestAddr,
RTM_BEST_PROTOCOL,
RTM_VIEW_MASK_UCAST,
pDestInfo) is NO_ERROR)
{
RtmReleaseDestInfo(g_hLocalRoute, pDestInfo);
Trace1(IF,
"AddAutomaticRoutes: Route to virtual LAN %d.%d.%d.%d already exists",
PRINT_IPADDR(dwAddress));
bDontAdd = TRUE;
}
}
if(!bDontAdd)
{
//
// Add the network route
//
RtInfo.dwRtInfoDest = (dwAddress & dwMask);
RtInfo.dwRtInfoMask = dwMask;
RtInfo.dwRtInfoNextHop = dwAddress;
RtInfo.dwRtInfoIfIndex = pIcb->dwIfIndex;
RtInfo.dwRtInfoMetric1 = 1;
RtInfo.dwRtInfoMetric2 = 1;
RtInfo.dwRtInfoMetric3 = 1;
RtInfo.dwRtInfoPreference = ComputeRouteMetric(MIB_IPPROTO_LOCAL);
RtInfo.dwRtInfoViewSet = RTM_VIEW_MASK_UCAST |
RTM_VIEW_MASK_MCAST; // XXX config
RtInfo.dwRtInfoType = MIB_IPROUTE_TYPE_DIRECT;
RtInfo.dwRtInfoProto = MIB_IPPROTO_LOCAL;
RtInfo.dwRtInfoAge = INFINITE;
RtInfo.dwRtInfoNextHopAS = 0;
RtInfo.dwRtInfoPolicy = 0;
bStack = TRUE;
IpRtAssert(bP2P is FALSE);
dwResult = AddSingleRoute(pIcb->dwIfIndex,
&RtInfo,
dwMask,
// RTM_ROUTE_INFO::Flags
RTM_ROUTE_FLAGS_LOCAL,
TRUE, // Valid route
bStack,
bP2P,
NULL);
if(dwResult isnot NO_ERROR)
{
Trace1(ERR,
"AddAutoRoutes: Can't add subnet route for %d.%d.%d.%d",
PRINT_IPADDR(dwAddress));
}
}
}
if(g_pLoopbackInterfaceCb)
{
RtInfo.dwRtInfoDest = dwAddress;
RtInfo.dwRtInfoMask = HOST_ROUTE_MASK;
RtInfo.dwRtInfoNextHop = IP_LOOPBACK_ADDRESS;
RtInfo.dwRtInfoIfIndex = g_pLoopbackInterfaceCb->dwIfIndex;
RtInfo.dwRtInfoMetric1 = 1;
RtInfo.dwRtInfoMetric2 = 1;
RtInfo.dwRtInfoMetric3 = 1;
RtInfo.dwRtInfoPreference= ComputeRouteMetric(MIB_IPPROTO_LOCAL);
RtInfo.dwRtInfoViewSet = RTM_VIEW_MASK_UCAST |
RTM_VIEW_MASK_MCAST;
RtInfo.dwRtInfoType = MIB_IPROUTE_TYPE_DIRECT;
RtInfo.dwRtInfoProto = MIB_IPPROTO_LOCAL;
RtInfo.dwRtInfoAge = INFINITE;
RtInfo.dwRtInfoNextHopAS = 0;
RtInfo.dwRtInfoPolicy = 0;
dwResult = AddSingleRoute(g_pLoopbackInterfaceCb->dwIfIndex,
&RtInfo,
dwMask,
// RTM_ROUTE_INFO::Flags
RTM_ROUTE_FLAGS_MYSELF,
TRUE,
FALSE,
FALSE,
NULL);
if(dwResult isnot NO_ERROR)
{
Trace1(ERR,
"AddAutoRoutes: Cant add 127.0.0.1 route for %d.%d.%d.%d",
PRINT_IPADDR(dwAddress));
}
}
RtInfo.dwRtInfoDest = LOCAL_NET_MULTICAST;
RtInfo.dwRtInfoMask = LOCAL_NET_MULTICAST_MASK;
RtInfo.dwRtInfoNextHop = dwAddress;
RtInfo.dwRtInfoIfIndex = pIcb->dwIfIndex;
RtInfo.dwRtInfoMetric1 = 1;
RtInfo.dwRtInfoMetric2 = 1;
RtInfo.dwRtInfoMetric3 = 1;
RtInfo.dwRtInfoPreference = ComputeRouteMetric(MIB_IPPROTO_LOCAL);
RtInfo.dwRtInfoViewSet = RTM_VIEW_MASK_UCAST;
RtInfo.dwRtInfoType = MIB_IPROUTE_TYPE_DIRECT;
RtInfo.dwRtInfoProto = MIB_IPPROTO_LOCAL;
RtInfo.dwRtInfoAge = INFINITE;
RtInfo.dwRtInfoNextHopAS = 0;
RtInfo.dwRtInfoPolicy = 0;
dwResult = AddSingleRoute(pIcb->dwIfIndex,
&RtInfo,
dwMask,
0, // RTM_ROUTE_INFO::Flags
FALSE, // Protocols dont like a mcast route
FALSE, // No need to add to stack
bP2P,
NULL);
if(dwResult isnot NO_ERROR)
{
Trace1(ERR,
"AddAutoRoutes: Couldnt add 224.0.0.0 route for %d.%d.%d.%d",
PRINT_IPADDR(dwAddress));
}
//
// We add the All 1's Bcast route to all interfaces. This is
// actually a BUG since we should see if the medium allows
// broadcast (X.25 would be an example of one that didnt)
//
RtInfo.dwRtInfoDest = ALL_ONES_BROADCAST;
RtInfo.dwRtInfoMask = HOST_ROUTE_MASK;
RtInfo.dwRtInfoNextHop = dwAddress;
RtInfo.dwRtInfoIfIndex = pIcb->dwIfIndex;
RtInfo.dwRtInfoMetric1 = 1;
RtInfo.dwRtInfoMetric2 = 1;
RtInfo.dwRtInfoMetric3 = 1;
RtInfo.dwRtInfoPreference = ComputeRouteMetric(MIB_IPPROTO_LOCAL);
RtInfo.dwRtInfoViewSet = RTM_VIEW_MASK_UCAST;
RtInfo.dwRtInfoType = MIB_IPROUTE_TYPE_DIRECT;
RtInfo.dwRtInfoProto = MIB_IPPROTO_LOCAL;
RtInfo.dwRtInfoAge = INFINITE;
RtInfo.dwRtInfoNextHopAS = 0;
RtInfo.dwRtInfoPolicy = 0;
dwResult = AddSingleRoute(pIcb->dwIfIndex,
&RtInfo,
dwMask,
0, // RTM_ROUTE_INFO::Flags
FALSE, // Protocols dont like a bcast route
FALSE, // No need to add to stack
bP2P,
NULL);
if(dwResult isnot NO_ERROR)
{
Trace1(ERR,
"AddAutRoutes: Couldnt add all 1's bcast route for %d.%d.%d.%d",
PRINT_IPADDR(dwAddress));
}
//
// We add the All Subnets Broadcast route if the class mask is different
// from the subnet mask
//
dwClassMask = GetClassMask(dwAddress);
if(dwClassMask isnot dwMask)
{
RtInfo.dwRtInfoDest = (dwAddress | ~dwClassMask);
RtInfo.dwRtInfoMask = HOST_ROUTE_MASK;
RtInfo.dwRtInfoNextHop = dwAddress;
RtInfo.dwRtInfoIfIndex = pIcb->dwIfIndex;
RtInfo.dwRtInfoMetric1 = 1;
RtInfo.dwRtInfoMetric2 = 1;
RtInfo.dwRtInfoMetric3 = 1;
RtInfo.dwRtInfoPreference= ComputeRouteMetric(MIB_IPPROTO_LOCAL);
RtInfo.dwRtInfoViewSet = RTM_VIEW_MASK_UCAST |
RTM_VIEW_MASK_MCAST; // XXX configurable
RtInfo.dwRtInfoType = MIB_IPROUTE_TYPE_DIRECT;
RtInfo.dwRtInfoProto = MIB_IPPROTO_LOCAL;
RtInfo.dwRtInfoAge = INFINITE;
RtInfo.dwRtInfoNextHopAS = 0;
RtInfo.dwRtInfoPolicy = 0;
dwResult = AddSingleRoute(pIcb->dwIfIndex,
&RtInfo,
dwMask,
0, // RTM_ROUTE_INFO::Flags
FALSE, // Protocols dont like a bcast route
FALSE, // No need to add to stack
bP2P,
NULL);
if(dwResult isnot NO_ERROR)
{
Trace1(ERR,
"AddAutoRoutes: Couldnt add all nets bcast route for %d.%d.%d.%d",
PRINT_IPADDR(dwAddress));
}
}
}
VOID
DeleteAutomaticRoutes(
PICB pIcb,
DWORD dwAddress,
DWORD dwMask
)
/*++
Routine Description
Locks
Arguments
Return Value
--*/
{
DWORD dwClassMask, dwResult;
BOOL bP2P;
if(dwAddress is INVALID_IP_ADDRESS)
{
IpRtAssert(FALSE);
}
return;
bP2P = IsIfP2P(pIcb->ritType);
//
// Delete the loopback route we added
//
if(g_pLoopbackInterfaceCb)
{
dwResult = DeleteSingleRoute(g_pLoopbackInterfaceCb->dwIfIndex,
dwAddress,
HOST_ROUTE_MASK,
IP_LOOPBACK_ADDRESS,
PROTO_IP_LOCAL,
FALSE);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"DeleteAutoRoutes: Error %d deleting loopback route on %d.%d.%d.%d",
dwResult,
PRINT_IPADDR(dwAddress));
}
}
//
// Delete the multicast route
//
dwResult = DeleteSingleRoute(pIcb->dwIfIndex,
LOCAL_NET_MULTICAST,
LOCAL_NET_MULTICAST_MASK,
dwAddress,
PROTO_IP_LOCAL,
bP2P);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"DeleteAutoRoutes: Error %d deleting 224.0.0.0 route on %d.%d.%d.%d",
dwResult,
PRINT_IPADDR(dwAddress));
}
if(dwMask isnot ALL_ONES_MASK)
{
//
// Delete the network route we added
//
IpRtAssert(bP2P is FALSE);
dwResult = DeleteSingleRoute(pIcb->dwIfIndex,
(dwAddress & dwMask),
dwMask,
dwAddress,
PROTO_IP_LOCAL,
bP2P);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"DeleteAutoRoutes: Error %d deleting subnet route for %d.%d.%d.%d",
dwResult,
PRINT_IPADDR(dwAddress));
}
}
//
// Delete the all nets bcast route
//
dwClassMask = GetClassMask(dwAddress);
if(dwClassMask isnot dwMask)
{
dwResult = DeleteSingleRoute(pIcb->dwIfIndex,
(dwAddress | ~dwClassMask),
HOST_ROUTE_MASK,
dwAddress,
PROTO_IP_LOCAL,
bP2P);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"DeleteAutoRoutes: Error %d deleting subnet bcast route on %x",
dwResult,
dwAddress);
}
//
// Delete the all 1's bcast route
//
}
dwResult = DeleteSingleRoute(pIcb->dwIfIndex,
ALL_ONES_BROADCAST,
HOST_ROUTE_MASK,
dwAddress,
PROTO_IP_LOCAL,
bP2P);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"DeleteAutoRoutes: Error %d deleting all 1's bcast route on %d.%d.%d.%d",
dwResult,
PRINT_IPADDR(dwAddress));
}
}
VOID
ChangeDefaultRouteMetrics(
IN BOOL bIncrement
)
/*++
Routine Description
Increments or decrements the default route(s) metrics.
For increment, it should be called BEFORE the default route for the
dial out interface is added, and for decrement it should be called AFTER
the dial out interface has been deleted
Locks
Called with the ICB lock held. This ensures that two such operations
are not being executed simultaneously (which would do the nasties to our
route table)
Arguments
bIncrement TRUE if we need to increment the metric
Return Value
None
--*/
{
ULONG i;
DWORD dwErr;
RTM_NET_ADDRESS NetAddress;
PRTM_ROUTE_HANDLE phRoutes;
PRTM_ROUTE_INFO pRouteInfo;
RTM_DEST_INFO DestInfo;
RTM_ENUM_HANDLE hEnum;
ZeroMemory(&NetAddress,
sizeof(NetAddress));
__try
{
phRoutes =
_alloca(sizeof(RTM_ROUTE_HANDLE) * g_rtmProfile.MaxHandlesInEnum);
pRouteInfo =
_alloca(RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute));
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
return;
}
//
// Use any handle
//
dwErr = RtmGetExactMatchDestination(g_hLocalRoute,
&NetAddress,
RTM_BEST_PROTOCOL, // rather any
RTM_VIEW_ID_UCAST,
&DestInfo);
if(dwErr isnot NO_ERROR)
{
return;
}
hEnum = NULL;
dwErr = RtmCreateRouteEnum(g_hLocalRoute,
DestInfo.DestHandle,
RTM_VIEW_ID_UCAST,
RTM_ENUM_ALL_ROUTES,
NULL,
RTM_MATCH_NONE,
NULL,
0,
&hEnum);
if(dwErr isnot NO_ERROR)
{
RtmReleaseDestInfo(g_hLocalRoute,
&DestInfo);
return;
}
do
{
RTM_ENTITY_HANDLE hRtmHandle;
ULONG j, ulCount;
ulCount = g_rtmProfile.MaxHandlesInEnum;
dwErr = RtmGetEnumRoutes(g_hLocalRoute,
hEnum,
&ulCount,
phRoutes);
if(ulCount < 1)
{
break;
}
for(i = 0 ; i < ulCount; i++)
{
PRTM_ROUTE_INFO pRtmRoute;
DWORD dwFlags;
dwErr = RtmGetRouteInfo(g_hLocalRoute,
phRoutes[i],
pRouteInfo,
NULL);
if(dwErr isnot NO_ERROR)
{
continue;
}
//
// See if we are the owner of this route
//
hRtmHandle = NULL;
for(j = 0;
j < sizeof(g_rgRtmHandles)/sizeof(RTM_HANDLE_INFO);
j++)
{
if(pRouteInfo->RouteOwner is g_rgRtmHandles[j].hRouteHandle)
{
hRtmHandle = g_rgRtmHandles[j].hRouteHandle;
break;
}
}
RtmReleaseRouteInfo(g_hLocalRoute,
pRouteInfo);
if(hRtmHandle is NULL)
{
continue;
}
//
// Lock the route (and re-read the info)
//
dwErr = RtmLockRoute(hRtmHandle,
phRoutes[i],
TRUE,
TRUE,
&pRtmRoute);
if(dwErr isnot NO_ERROR)
{
continue;
}
//
// If we have to decrease the metric and it is already 1,
// let it be
//
if(!bIncrement)
{
if(pRtmRoute->PrefInfo.Metric <= 1)
{
RtmLockRoute(hRtmHandle,
phRoutes[i],
TRUE,
FALSE,
NULL);
continue;
}
}
//
// Now update the route
//
if(bIncrement)
{
pRtmRoute->PrefInfo.Metric++;
}
else
{
pRtmRoute->PrefInfo.Metric--;
}
dwFlags = 0;
dwErr = RtmUpdateAndUnlockRoute(hRtmHandle,
phRoutes[i],
INFINITE,
NULL,
0,
NULL,
&dwFlags);
if(dwErr isnot NO_ERROR)
{
RtmLockRoute(hRtmHandle,
phRoutes[i],
TRUE,
FALSE,
NULL);
}
}
RtmReleaseRoutes(g_hLocalRoute,
ulCount,
phRoutes);
}while(TRUE);
RtmDeleteEnumHandle(g_hLocalRoute,
hEnum);
RtmReleaseDestInfo(g_hLocalRoute,
&DestInfo);
return;
}
VOID
AddAllStackRoutes(
PICB pIcb
)
/*++
Routine Description:
This function picks up the default gateway and persistent routes
that the stack may have added under the covers for this interface
and adds them to RTM
Locks:
ICB_LIST lock must be held as WRITER
Arguments:
dwIfIndex Interface index
Return Value:
none
--*/
{
DWORD dwErr, dwMask, i;
BOOL bStack;
PMIB_IPFORWARDTABLE pRouteTable;
TraceEnter("AddAllStackRoutes");
IpRtAssert(!IsIfP2P(pIcb->ritType));
dwErr = AllocateAndGetIpForwardTableFromStack(&pRouteTable,
FALSE,
IPRouterHeap,
0);
if(dwErr isnot NO_ERROR)
{
Trace1(ERR,
"AddAllStackRoutes: Couldnt get initial routes. Error %d",
dwErr);
return;
}
for(i = 0; i < pRouteTable->dwNumEntries; i++)
{
TraceRoute4(ROUTE,
"route to %d.%d.%d.%d/%d.%d.%d.%d, If Index %d, proto %d",
PRINT_IPADDR(pRouteTable->table[i].dwForwardDest),
PRINT_IPADDR(pRouteTable->table[i].dwForwardMask),
pRouteTable->table[i].dwForwardIfIndex,
pRouteTable->table[i].dwForwardProto);
if(pRouteTable->table[i].dwForwardIfIndex isnot pIcb->dwIfIndex)
{
//
// Not going out over this interface
//
continue;
}
#if 1
//
// Pick up only PROTO_IP_LOCAL and PROTO_IP_NETMGMT routes
// from the IP stack
//
if((pRouteTable->table[i].dwForwardProto isnot PROTO_IP_LOCAL) and
(pRouteTable->table[i].dwForwardProto isnot PROTO_IP_NETMGMT))
{
continue;
}
#else
if((pRouteTable->table[i].dwForwardProto isnot PROTO_IP_NT_STATIC_NON_DOD) and
(pRouteTable->table[i].dwForwardDest isnot 0))
{
//
// Only pick up default gateways and persistent routes
//
continue;
}
#endif
dwMask = GetBestNextHopMaskGivenICB(pIcb,
pRouteTable->table[i].dwForwardDest);
//
// Routes learned from the stack should be added back to the stack if
// required. This can happen as follows:
//
// 1. Route R1 from stack is currently best route for destination D1.
// 2. Subsequently it is superseeded by route R2 as the best route for
// destination D1.
// R2 is added to the stack, deleting R1 as a side effect.
// 3. Eventually R2 is deleted and R1 is again the best route to D1
// 4. R1 now needs to be added back to the stack and can only be done
// if its stack bit is set.
//
bStack = TRUE;
//if((pRouteTable->table[i].dwForwardProto is PROTO_IP_NETMGMT) &&
// (pRouteTable->table[i].dwForwardMask is HOST_ROUTE_MASK))
//{
// bStack = FALSE;
//}
if(pRouteTable->table[i].dwForwardProto is PROTO_IP_LOCAL)
{
//
// PROTO_IP_LOCAL routes as a rule need not be added back
// as they are entirely managed by the stack.
//
// The one exception as routes to the local subnet.
// These need to added back to the stack so that any
// routes to the local subnet learned over other interfaces
// are deleted as a side effect.
//
// This is required as follows:
// 1. Interface I1 connected to network N1 is disabled.
// 2. Route R1 to network N1 is learnt over interface
// I2 connected to network N2 from a neighboring
// router running RIP.
// 3. So the best route to N1 is the RIP route R1.
// 4. Interface I1 is now enabled.
// 5. PROTO_IP_LOCAL route R2 to N1 is added by the stack.
// But the stack does not delete R1 automatically.
// 6. In RTMv2 in user-mode R2 is added as the best route.
// 7. If R2 does not have its stack bit set, it is not
// added back to the stack, allowing both R2 and R1 to
// remain in the stack.
// 8. Route R1 is deleted by RIP. Since it is not the
// best route in RTMv2 no changes are propagated to the
// stack even though R1 is present in the stack.
//
//
// As per above disable stack bit for PROTO_IP_LOCAL routes
// except route to the local subnet.
//
if(
//
// Do not add the loopback route back to the stack.
// PROTO_IP_LOCAL host route check catches the loopback route
//
(pRouteTable->table[i].dwForwardMask is HOST_ROUTE_MASK) or
//
// Do not add the multicast and all 1's broadcast route
//
((pRouteTable->table[i].dwForwardDest &
((DWORD) 0x000000FF)) >= ((DWORD) 0x000000E0)) or
//
// Do not add subnet broadcast route
//
(pRouteTable->table[i].dwForwardDest ==
(pRouteTable->table[i].dwForwardDest |
~pRouteTable->table[i].dwForwardMask)))
{
bStack = FALSE;
}
//
// This should leave only the subnet route with its stack bit set
//
}
dwErr = AddSingleRoute(pIcb->dwIfIndex,
ConvertMibRouteToRouteInfo(&(pRouteTable->table[i])),
dwMask,
0, // RTM_ROUTE_INFO::Flags
TRUE, // Valid route
bStack, // Do not add back to stack
FALSE, // Only called for non P2P i/fs
NULL);
}
TraceLeave("AddAllStackRoutes");
return;
}
VOID
UpdateDefaultRoutes(
VOID
)
{
DWORD dwErr, dwMask, i, j;
BOOL bFound;
PMIB_IPFORWARDTABLE pRouteTable;
PINTERFACE_ROUTE_INFO pRtInfo;
TraceEnter("UpdateDefaultRoutes");
//
// Get the routes in an ordered table
//
dwErr = AllocateAndGetIpForwardTableFromStack(&pRouteTable,
TRUE,
IPRouterHeap,
0);
if(dwErr isnot NO_ERROR)
{
Trace1(ERR,
"UpdateDefaultRoutes: Couldnt get routes. Error %d",
dwErr);
return;
}
//
// Now add the dgs not already present
//
for(i = 0; i < pRouteTable->dwNumEntries; i++)
{
PICB pIcb;
TraceRoute2(
ROUTE, "%d.%d.%d.%d/%d.%d.%d.%d",
PRINT_IPADDR( pRouteTable-> table[i].dwForwardDest ),
PRINT_IPADDR( pRouteTable-> table[i].dwForwardMask )
);
//
// Once we get past the default routes, we are done
//
if(pRouteTable->table[i].dwForwardDest isnot 0)
{
#if TRACE_DBG
continue;
#else
break;
#endif
}
if(pRouteTable->table[i].dwForwardIfIndex is INVALID_IF_INDEX)
{
continue;
}
if(pRouteTable->table[i].dwForwardProto isnot PROTO_IP_NETMGMT)
{
continue;
}
pIcb = InterfaceLookupByIfIndex(pRouteTable->table[i].dwForwardIfIndex);
if(pIcb is NULL)
{
Trace1(ERR,
"UpdateDefaultRoutes: Couldnt get icb for %x",
pRouteTable->table[i].dwForwardIfIndex);
continue;
}
//
// Dont need to do this for p2p interfaces
//
if(IsIfP2P(pIcb->ritType))
{
continue;
}
dwMask = GetBestNextHopMaskGivenICB(pIcb,
pRouteTable->table[i].dwForwardDest);
Trace1(ROUTE,
"UpdateDefaultRoutes: Adding default route over %S",
pIcb->pwszName);
dwErr = AddSingleRoute(pIcb->dwIfIndex,
ConvertMibRouteToRouteInfo(&(pRouteTable->table[i])),
dwMask,
0, // RTM_ROUTE_INFO::Flags
TRUE, // Valid route
TRUE, // Add the route to stack
FALSE, // Only called for non P2P i/fs
NULL);
if(dwErr isnot NO_ERROR)
{
Trace3(ERR,
"UpdateDefaultRoutes: Error %d adding dg to %d.%d.%d.%d over %x",
dwErr,
PRINT_IPADDR(pRouteTable->table[i].dwForwardNextHop),
pRouteTable->table[i].dwForwardIfIndex);
}
#if 0
else
{
if(g_ulGatewayCount < g_ulGatewayMaxCount)
{
g_pGateways[g_ulGatewayCount].dwAddress =
pRouteTable->table[i].dwForwardNextHop;
g_pGateways[g_ulGatewayCount].dwMetric =
pRouteTable->table[i].dwForwardMetric1;
g_pGateways[g_ulGatewayCount].dwIfIndex =
pRouteTable->table[i].dwForwardIfIndex;
g_ulGatewayCount++;
}
else
{
PGATEWAY_INFO pNewGw;
IpRtAssert(g_ulGatewayCount == g_ulGatewayMaxCount);
pNewGw = HeapAlloc(IPRouterHeap,
HEAP_ZERO_MEMORY,
(g_ulGatewayMaxCount + 5) * sizeof(GATEWAY_INFO));
if(pNewGw isnot NULL)
{
g_ulGatewayMaxCount = g_ulGatewayMaxCount + 5;
for(j = 0; j < g_ulGatewayCount; j++)
{
pNewGw[j] = g_pGateways[j];
}
if(g_pGateways isnot NULL)
{
HeapFree(IPRouterHeap,
0,
g_pGateways);
}
g_pGateways = pNewGw;
g_pGateways[g_ulGatewayCount].dwAddress =
pRouteTable->table[i].dwForwardNextHop;
g_pGateways[g_ulGatewayCount].dwMetric =
pRouteTable->table[i].dwForwardMetric1;
g_pGateways[g_ulGatewayCount].dwIfIndex =
pRouteTable->table[i].dwForwardIfIndex;
g_ulGatewayCount++;
}
}
}
#endif
}
HeapFree(IPRouterHeap,
0,
pRouteTable);
TraceLeave("UpdateDefaultRoutes");
return;
}
NTSTATUS
PostIoctlForRouteChangeNotification(
DWORD ulIndex
)
/*++
Routine Description:
This routine posts an IOCTL with the TCP/IP driver for route change
notifications caused by addition of routes to the stack by entities
other than Router Manager
Arguments:
ulIndex - Index into array of notifications indicating which one
needs to be posted
Return Value
STATUS_SUCCESS - Success
NTSTATUS code - Otherwise
Environment:
--*/
{
NTSTATUS status;
status = NtDeviceIoControlFile(
g_hIpRouteChangeDevice,
g_hRouteChangeEvents[ulIndex],
NULL,
NULL,
&g_rgIpRouteNotifyOutput[ulIndex].ioStatus,
IOCTL_IP_RTCHANGE_NOTIFY_REQUEST_EX,
&g_IpNotifyData,
sizeof(IPNotifyData),
&g_rgIpRouteNotifyOutput[ulIndex].ipNotifyOutput,
sizeof(IPRouteNotifyOutput)
);
if ((status isnot STATUS_SUCCESS) and
(status isnot STATUS_PENDING))
{
Trace2(
ERR,
"Error 0x%x posting route change notification[%d]",
status, ulIndex
);
}
return status;
}
DWORD
HandleRouteChangeNotification(
ULONG ulIndex
)
/*++
--*/
{
DWORD dwResult = NO_ERROR, dwFlags, dwClassMask;
BOOL bValid, bStack = FALSE;
WORD wRouteFlags = 0;
INTERFACE_ROUTE_INFO RtInfo;
PICB pIcb;
TraceEnter("HandleRouteChangeNotification");
TraceRoute2(
ROUTE, "Change for route to %d.%d.%d.%d/%d.%d.%d.%d",
PRINT_IPADDR(g_rgIpRouteNotifyOutput[ulIndex].ipNotifyOutput.irno_dest),
PRINT_IPADDR(g_rgIpRouteNotifyOutput[ulIndex].ipNotifyOutput.irno_mask)
);
TraceRoute3(
ROUTE, "Proto : %d, via i/f 0x%x, nexthop %d.%d.%d.%d",
g_rgIpRouteNotifyOutput[ulIndex].ipNotifyOutput.irno_proto,
g_rgIpRouteNotifyOutput[ulIndex].ipNotifyOutput.irno_ifindex,
PRINT_IPADDR(g_rgIpRouteNotifyOutput[ulIndex].ipNotifyOutput.irno_nexthop)
);
TraceRoute2(
ROUTE, "Metric : %d, Change : 0x%x",
g_rgIpRouteNotifyOutput[ulIndex].ipNotifyOutput.irno_metric,
g_rgIpRouteNotifyOutput[ulIndex].ipNotifyOutput.irno_flags
);
//
// Update RTM route table as per route change indication
//
ENTER_READER(ICB_LIST);
do
{
pIcb = InterfaceLookupByIfIndex(
g_rgIpRouteNotifyOutput[ulIndex].ipNotifyOutput.irno_ifindex
);
if (pIcb == NULL)
{
//
// if there is no interface with the specified index in
// router manager, skip this route
//
Trace3(
ERR,
"Failed to add route to %d.%d.%d.%d/%d.%d.%d.%d."
"Interface index %d not present with router manager",
PRINT_IPADDR(g_rgIpRouteNotifyOutput[ulIndex].ipNotifyOutput.irno_dest),
PRINT_IPADDR(g_rgIpRouteNotifyOutput[ulIndex].ipNotifyOutput.irno_mask),
g_rgIpRouteNotifyOutput[ulIndex].ipNotifyOutput.irno_ifindex
);
break;
}
//
// if route had been added to stack, add it to RTM
//
dwFlags =
g_rgIpRouteNotifyOutput[ulIndex].ipNotifyOutput.irno_flags;
ConvertRouteNotifyOutputToRouteInfo(
&g_rgIpRouteNotifyOutput[ulIndex].ipNotifyOutput,
&RtInfo
);
if ((dwFlags is 0) or (dwFlags & IRNO_FLAG_ADD))
{
bValid = TRUE;
if (RtInfo.dwRtInfoProto == PROTO_IP_LOCAL)
{
//
// Set appropriate RTM flags for local routes
//
if (RtInfo.dwRtInfoNextHop == IP_LOOPBACK_ADDRESS)
{
//
// Route over loopback. Set MYSELF flag
//
wRouteFlags = RTM_ROUTE_FLAGS_MYSELF;
}
else if ((RtInfo.dwRtInfoMask != HOST_ROUTE_MASK ) &&
((RtInfo.dwRtInfoDest & RtInfo.dwRtInfoMask) <
((DWORD) 0x000000E0)))
{
//
// RTM_ROUTE_FLAGS_LOCAL is set only for subnet
// routes. Not sure why this is so. I am only
// preserving the semantics from AddAutomaticRoutes
// Either way the consequences are not drastic since
// this does not affect the IP forwarding table in
// the stack.
// - VRaman
//
//
// We arrive at the fact that this is a subnet route
// in a roundabout fashion by eliminating
// PROTO_IP_LOCAL routes that are host routes and
// by eliminating any broadcast routes
//
// Since the host route check eliminates all routes
// with an all 1's mask, subnet/net broadcast routes
// are also eliminated.
//
wRouteFlags = RTM_ROUTE_FLAGS_LOCAL;
}
//
// mark mcast/bcast route as invalid so the protocols
// do not advertize them
//
dwClassMask = GetClassMask(RtInfo.dwRtInfoDest);
if ((RtInfo.dwRtInfoDest & (DWORD) 0x000000FF) >=
((DWORD) 0x000000E0) ||
(RtInfo.dwRtInfoDest ==
(RtInfo.dwRtInfoDest | ~dwClassMask)))
{
bValid = FALSE;
}
else
{
//
// For PROTO_IP_LOCAL we do not add them back to
// the stack since these are managed by the stack
// We add them to RTM only to keep the user mode
// route table synchronized with the stack
//
// On second thoughts, we do need to add them
// back to the stack. More accurately, we need to
// try and add them back to the stack. This
// operation should fail, but as a side effect of
// this existing non PROTO_IP_LOCAL in the stack
// will be deleted.
// This is required in case of local subnet
// routes. It is possible that before an
// interface is enabled with IP, a route to the
// connected subnet may have been learnt over
// another interface via a routing protocol and
// added to the stack. When an interface is
// enabled all previously added routes to the
// local subnet should be deleted if the
// PROTO_IP_LOCAL route is the best route (which
// it should be unless you have a really wierd set
// of protocol preferences).
// Otherwise we run the risk of having non-best
// routes in the IP stack that are never deleted
// when the user mode route corresponding to it is
// deleted since you do not get a route change
// notification for non-best routes. The result is
// that you end up with state routes in the stack
//
if (RtInfo.dwRtInfoMask != HOST_ROUTE_MASK)
{
bStack = TRUE;
}
}
}
//
// Routes learn't from the stack are normally not
// added back to the stack. Hence the bStack is
// initialized to FALSE.
//
// PROTO_IP_NETMGT are not managed by the stack. They
// can be added/deleted/updated by user mode processes.
// As consequence a NETMGT route learned from the stack
// may be superseded by a route with a different protocol
// ID e.g. static. When the superseding route is deleted
// the NETMGMT routes need to be restored to the stack.
// Hence for NETMGMT routes we set bStack = true.
//
// An exception the processing of NETMGMT routes are HOST routes
// It is assumed by host routes added directly to the
// stack are managed by the process adding/deleting them
// e.g.RASIPCP
// They are added to RTM for sync. with the stack route table
// only. So for these we set bStack = FALSE
//
//
if ((RtInfo.dwRtInfoProto is PROTO_IP_NETMGMT) &&
(RtInfo.dwRtInfoMask isnot HOST_ROUTE_MASK))
{
bStack = TRUE;
}
TraceRoute5(
ROUTE, "NHOP mask %d.%d.%d.%d, Flag 0x%x, Valid %d, "
"Stack %d, P2P %d",
PRINT_IPADDR(GetBestNextHopMaskGivenICB(
pIcb, RtInfo.dwRtInfoNextHop)),
wRouteFlags,
bValid,
bStack,
IsIfP2P(pIcb->ritType)
);
dwResult = AddSingleRoute(
RtInfo.dwRtInfoIfIndex,
&RtInfo,
GetBestNextHopMaskGivenICB(
pIcb, RtInfo.dwRtInfoNextHop
),
wRouteFlags,
bValid,
bStack,
IsIfP2P(pIcb->ritType),
NULL
);
if (dwResult != NO_ERROR)
{
Trace2(
ERR, "HandleRouteChangeNotification: Failed to add "
"route %d.%d.%d.%d, error %d",
PRINT_IPADDR(RtInfo.dwRtInfoDest),
dwResult
);
break;
}
}
else if (dwFlags & IRNO_FLAG_DELETE)
{
dwResult = DeleteSingleRoute(
g_rgIpRouteNotifyOutput[ulIndex].ipNotifyOutput.irno_ifindex,
g_rgIpRouteNotifyOutput[ulIndex].ipNotifyOutput.irno_dest,
g_rgIpRouteNotifyOutput[ulIndex].ipNotifyOutput.irno_mask,
g_rgIpRouteNotifyOutput[ulIndex].ipNotifyOutput.irno_nexthop,
g_rgIpRouteNotifyOutput[ulIndex].ipNotifyOutput.irno_proto,
IsIfP2P(pIcb->ritType)
);
if (dwResult != NO_ERROR)
{
Trace2(
ERR, "HandleRouteChangeNotification: Failed to"
"delete route %d.%d.%d.%d, error %d",
PRINT_IPADDR(
g_rgIpRouteNotifyOutput[ulIndex].ipNotifyOutput.irno_dest),
dwResult
);
break;
}
}
else
{
Trace1(
ERR, "HandleRouteChangeNotification: Invalid flags "
"0x%x",
g_rgIpRouteNotifyOutput[ulIndex].ipNotifyOutput.irno_flags
);
break;
}
if (RtInfo.dwRtInfoProto is PROTO_IP_NETMGMT)
{
UpdateStackRoutesToRestoreList(
ConvertRouteInfoToMibRoute( &RtInfo ),
dwFlags
);
}
} while (FALSE);
EXIT_LOCK(ICB_LIST);
PostIoctlForRouteChangeNotification(ulIndex);
TraceLeave("HandleRouteChangeNotification");
return dwResult;
}
VOID
AddLoopbackRoute(
DWORD dwIfAddress,
DWORD dwIfMask
)
{
DWORD dwResult;
INTERFACE_ROUTE_INFO rifRoute;
MIB_IPFORWARDROW mibRoute;
if(g_pLoopbackInterfaceCb is NULL)
{
Trace0(ERR, "AddLoopbackRoute: No loopback interface");
return;
}
rifRoute.dwRtInfoMask = HOST_ROUTE_MASK;
rifRoute.dwRtInfoNextHop = IP_LOOPBACK_ADDRESS;
rifRoute.dwRtInfoDest = dwIfAddress;
rifRoute.dwRtInfoIfIndex = g_pLoopbackInterfaceCb->dwIfIndex;
rifRoute.dwRtInfoMetric2 = 0;
rifRoute.dwRtInfoMetric3 = 0;
rifRoute.dwRtInfoPreference = ComputeRouteMetric(MIB_IPPROTO_LOCAL);
rifRoute.dwRtInfoViewSet = RTM_VIEW_MASK_UCAST |
RTM_VIEW_MASK_MCAST; // XXX config
rifRoute.dwRtInfoType = MIB_IPROUTE_TYPE_DIRECT;
rifRoute.dwRtInfoProto = MIB_IPPROTO_LOCAL;
rifRoute.dwRtInfoAge = 0;
rifRoute.dwRtInfoNextHopAS = 0;
rifRoute.dwRtInfoPolicy = 0;
//
// Query IP stack to verify for loopback route
// corresponding to this binding
//
dwResult = GetBestRoute(
dwIfAddress,
0,
&mibRoute
);
if(dwResult isnot NO_ERROR)
{
Trace2(
ERR,
"AddLoopbackRoute: Stack query for loopback route"
" associated with %d.%d.%d.%d failed, error %d",
PRINT_IPADDR(dwIfAddress),
dwResult
);
return;
}
if (mibRoute.dwForwardIfIndex !=
g_pLoopbackInterfaceCb->dwIfIndex)
{
//
// There appears to be no loopback address
// very strange
//
Trace1(
ERR,
"AddLoopbackRoute: No loopback route for %d.%d.%d.%d"
"in stack",
PRINT_IPADDR(dwIfAddress)
);
return;
}
//
// Use metric returned from stack.
//
rifRoute.dwRtInfoMetric1 = mibRoute.dwForwardMetric1;
dwResult = AddSingleRoute(g_pLoopbackInterfaceCb->dwIfIndex,
&rifRoute,
dwIfMask,
0, // RTM_ROUTE_INFO::Flags
TRUE,
FALSE,
FALSE,
NULL);
if(dwResult isnot NO_ERROR)
{
Trace1(ERR,
"AddLoopbackRoute: Couldnt add 127.0.0.1 route associated with %x",
dwIfAddress);
}
return;
}
VOID
UpdateStackRoutesToRestoreList(
IN PMIB_IPFORWARDROW pmibRoute,
IN DWORD dwFlags
)
/*++
Routine Description:
This routine adds/deletes PROTO_IP_NETMGMT routes to/from the global
list g_leStackRoutesToRestore. This list is used by IP router
manager to restore routes these routes to the TCP/IP stack when it
is shutting down
Parameters
pirf - Route to be added or deleted
dwFlags - Specifies whether the operation is add or delete
Return Value
None
Context:
Invoked from
HandleRouteChangeNotification
[Set/Delete]IpForwardRow
--*/
{
BOOL bFound;
PROUTE_LIST_ENTRY prl, prlNew;
TraceEnter("UpdateStackRoutes");
TraceRoute5(
ROUTE,
"UpdateStackRoutes : Route "
"%d.%d.%d.%d/%d.%d.%d.%d via i/f 0x%x "
"nexthop %d.%d.%d.%d is being 0x%x "
"user mode",
PRINT_IPADDR(pmibRoute->dwForwardDest),
PRINT_IPADDR(pmibRoute->dwForwardMask),
pmibRoute->dwForwardIfIndex,
PRINT_IPADDR(pmibRoute->dwForwardNextHop),
dwFlags
);
ENTER_WRITER(STACK_ROUTE_LIST);
//
// Locate route in list
//
bFound = LookupStackRoutesToRestoreList(
pmibRoute,
&prl
);
do
{
//
// Is this a route update or add
//
if ((dwFlags is 0) or (dwFlags & IRNO_FLAG_ADD))
{
//
// if route is not found, add it
//
if (!bFound)
{
if (dwFlags is 0)
{
//
// Strange that route is not around in
// user mode though it is present in the
// stack (update case).
//
// Print a trace to note this and add it
// anyway
//
Trace4(
ERR,
"UpdateStackRoutes : Route "
"%d.%d.%d.%d/%d.%d.%d.%d via i/f 0x%x "
"nexthop %d.%d.%d.%d not found in "
"user mode",
PRINT_IPADDR(pmibRoute->dwForwardDest),
PRINT_IPADDR(pmibRoute->dwForwardMask),
pmibRoute->dwForwardIfIndex,
PRINT_IPADDR(pmibRoute->dwForwardNextHop)
);
}
//
// Allocate and store route in a linked list
//
prlNew = HeapAlloc(
IPRouterHeap, HEAP_ZERO_MEMORY,
sizeof(ROUTE_LIST_ENTRY)
);
if (prlNew is NULL)
{
Trace2(
ERR,
"UpdateStackRoutes : error %d allocating %d"
" bytes for stack route entry",
ERROR_NOT_ENOUGH_MEMORY,
sizeof(ROUTE_LIST_ENTRY)
);
break;
}
InitializeListHead( &prlNew->leRouteList );
prlNew->mibRoute = *pmibRoute;
InsertTailList(
(prl is NULL) ?
&g_leStackRoutesToRestore :
&prl->leRouteList,
&prlNew->leRouteList
);
break;
}
//
// route is found, update it
//
prl->mibRoute = *pmibRoute;
break;
}
//
// Is this a route delete
//
if (dwFlags & IRNO_FLAG_DELETE)
{
if (bFound)
{
RemoveEntryList( &prl->leRouteList );
HeapFree(IPRouterHeap, 0, prl);
}
}
} while( FALSE );
EXIT_LOCK(STACK_ROUTE_LIST);
TraceLeave("UpdateStackRoutes");
}
BOOL
LookupStackRoutesToRestoreList(
IN PMIB_IPFORWARDROW pmibRoute,
OUT PROUTE_LIST_ENTRY *pRoute
)
/*++
Routine Description:
This routine searches g_leStackRoutesToRestore to determine if the
route specified by pmibRoute is present. If it is it returns TRUE
and a pointer to the specified route in pRoute. If is not present
FALSE is returned along with a pointer to the next route in list.
If there are no routes, pRoute is NULL
Parameters
pmibRoute - Route to locate in g_leStackRoutesToRestore
pRoute - Pointer to the route entry if present
- Pointer to the next route entry if not present
(save additional lookups in case of route entry
additions)
- NULL if list is empty
Return Value:
TRUE - if route found
FALSE - otherwise
Context:
Should be called with the lock for g_leStackRoutesToRestore
--*/
{
INT iCmp;
BOOL bFound = FALSE;
PLIST_ENTRY ple;
PROUTE_LIST_ENTRY prl;
*pRoute = NULL;
if (IsListEmpty(&g_leStackRoutesToRestore))
{
return bFound;
}
for (ple = g_leStackRoutesToRestore.Flink;
ple != &g_leStackRoutesToRestore;
ple = ple->Flink)
{
prl = CONTAINING_RECORD(
ple, ROUTE_LIST_ENTRY, leRouteList
);
if (INET_CMP(
prl->mibRoute.dwForwardDest &
prl->mibRoute.dwForwardMask,
pmibRoute->dwForwardDest &
pmibRoute->dwForwardMask,
iCmp
) < 0 )
{
continue;
}
else if (iCmp > 0)
{
//
// we have gone past the possible location
// of the specified route
//
break;
}
//
// found a matching dest, check if the i/f is
// the same.
//
if ((prl->mibRoute.dwForwardIfIndex is
pmibRoute->dwForwardIfIndex ) and
(prl->mibRoute.dwForwardNextHop is
pmibRoute->dwForwardNextHop))
{
bFound = TRUE;
break;
}
}
if (ple == &g_leStackRoutesToRestore)
{
*pRoute = (PROUTE_LIST_ENTRY)NULL;
}
else
{
*pRoute = prl;
}
return bFound;
}