988 lines
26 KiB
C
988 lines
26 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1995 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
routing\ip\rtrmgr\init.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
IP Router Manager code
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
Gurdeep Singh Pall 6/14/95 Created
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "allinc.h"
|
||
|
|
||
|
|
||
|
// ChangeRouteWithForwarder()
|
||
|
//
|
||
|
// Function: If addroute is TRUE this function adds an IP route. If addroute is FALSE
|
||
|
// this function deletes the given route with the forwarder.
|
||
|
//
|
||
|
// Returns: Nothing
|
||
|
//
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
ChangeRouteWithForwarder(
|
||
|
PRTM_NET_ADDRESS pDestAddr,
|
||
|
PRTM_ROUTE_INFO pRoute,
|
||
|
BOOL bAddRoute,
|
||
|
BOOL bDelOld
|
||
|
)
|
||
|
{
|
||
|
IPMultihopRouteEntry *pMultiRouteEntry;
|
||
|
IPRouteEntry *pRouteEntry;
|
||
|
IPRouteNextHopEntry *pNexthopEntry;
|
||
|
RTM_ENTITY_INFO entityInfo;
|
||
|
RTM_NEXTHOP_INFO nhiInfo;
|
||
|
PADAPTER_INFO pBinding;
|
||
|
UINT numnexthops, i;
|
||
|
ULONG numbytes;
|
||
|
DWORD dwAddr, dwMask;
|
||
|
UINT dwLen;
|
||
|
ULONG ifindex, nexthop, type;
|
||
|
BOOL bValidNHop;
|
||
|
DWORD context;
|
||
|
DWORD dwLocalNet, dwLocalMask;
|
||
|
DWORD dwResult;
|
||
|
|
||
|
TraceEnter("ChangeRouteWithForwarder");
|
||
|
|
||
|
if(!g_bSetRoutesToStack)
|
||
|
{
|
||
|
Trace0(ROUTE,
|
||
|
"ChangeRouteWithForwarder: SetRoutesToStack is FALSE");
|
||
|
|
||
|
TraceLeave("ChangeRouteWithForwarder");
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
if (bAddRoute)
|
||
|
{
|
||
|
//
|
||
|
// Ensure that the stack bit is set
|
||
|
//
|
||
|
|
||
|
if (!pRoute || !IsRouteStack(pRoute))
|
||
|
{
|
||
|
if (!pRoute )
|
||
|
{
|
||
|
Trace0(ROUTE,
|
||
|
"Error adding route, route == NULL"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
else
|
||
|
{
|
||
|
Trace1(ROUTE,
|
||
|
"Error adding route, Stack bit == %d",
|
||
|
IsRouteStack(pRoute)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
TraceLeave("ChangeRouteWithForwarder");
|
||
|
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
|
||
|
// We should have atleast one nexthop
|
||
|
numnexthops = pRoute->NextHopsList.NumNextHops;
|
||
|
if (numnexthops == 0)
|
||
|
{
|
||
|
Trace0(ROUTE,
|
||
|
"Error adding route, no nexthops");
|
||
|
|
||
|
TraceLeave("ChangeRouteWithForwarder");
|
||
|
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
numbytes = sizeof(IPMultihopRouteEntry) +
|
||
|
(numnexthops - 1) *
|
||
|
sizeof(IPRouteNextHopEntry);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// for routes to be deleted, they should be stack
|
||
|
// routes
|
||
|
//
|
||
|
|
||
|
// We do not have any next hops here
|
||
|
numbytes = sizeof(IPMultihopRouteEntry);
|
||
|
}
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
pMultiRouteEntry = _alloca(numbytes);
|
||
|
}
|
||
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
||
|
{
|
||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||
|
}
|
||
|
|
||
|
pRouteEntry = &pMultiRouteEntry->imre_routeinfo;
|
||
|
|
||
|
//
|
||
|
// Fill the dest and mask for the current route
|
||
|
//
|
||
|
|
||
|
RTM_IPV4_GET_ADDR_AND_LEN(pRouteEntry->ire_dest,
|
||
|
dwLen,
|
||
|
pDestAddr);
|
||
|
|
||
|
pRouteEntry->ire_mask = RTM_IPV4_MASK_FROM_LEN(dwLen);
|
||
|
|
||
|
TraceRoute2(ROUTE,
|
||
|
"route to %d.%d.%d.%d/%d.%d.%d.%d",
|
||
|
PRINT_IPADDR(pRouteEntry->ire_dest),
|
||
|
PRINT_IPADDR(pRouteEntry->ire_mask));
|
||
|
|
||
|
if (!bAddRoute)
|
||
|
{
|
||
|
//
|
||
|
// Prepare to delete old information on dest
|
||
|
//
|
||
|
|
||
|
pRouteEntry->ire_type = IRE_TYPE_INVALID;
|
||
|
|
||
|
pMultiRouteEntry->imre_numnexthops = 0;
|
||
|
|
||
|
Trace2(ROUTE,
|
||
|
"ChangeRouteWithForwarder: Deleting all " \
|
||
|
"routes to %d.%d.%d.%d/%d.%d.%d.%d",
|
||
|
PRINT_IPADDR(pRouteEntry->ire_dest),
|
||
|
PRINT_IPADDR(pRouteEntry->ire_mask));
|
||
|
|
||
|
dwResult = SetIpMultihopRouteEntryToStack(pMultiRouteEntry);
|
||
|
|
||
|
TraceLeave("ChangeRouteWithForwarder");
|
||
|
|
||
|
return dwResult;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Get the routing protocol of the route's owner
|
||
|
//
|
||
|
|
||
|
dwResult = RtmGetEntityInfo(g_hLocalRoute,
|
||
|
pRoute->RouteOwner,
|
||
|
&entityInfo);
|
||
|
|
||
|
if (dwResult isnot NO_ERROR)
|
||
|
{
|
||
|
Trace1(ROUTE,
|
||
|
"Error %d retrieving entity info from RTM",
|
||
|
dwResult);
|
||
|
|
||
|
TraceLeave("ChangeRouteWithForwarder");
|
||
|
|
||
|
return dwResult;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Prepare to add a multihop route on this dest
|
||
|
//
|
||
|
|
||
|
// Prepare information common to all nexthops
|
||
|
|
||
|
pRouteEntry->ire_proto = entityInfo.EntityId.EntityProtocolId;
|
||
|
pRouteEntry->ire_metric1 = pRoute->PrefInfo.Metric;
|
||
|
pRouteEntry->ire_metric2 = IRE_METRIC_UNUSED;
|
||
|
pRouteEntry->ire_metric3 = IRE_METRIC_UNUSED;
|
||
|
pRouteEntry->ire_metric4 = IRE_METRIC_UNUSED;
|
||
|
pRouteEntry->ire_metric5 = IRE_METRIC_UNUSED;
|
||
|
pRouteEntry->ire_age = 0;
|
||
|
|
||
|
numnexthops = 0;
|
||
|
|
||
|
for (i = 0; i < pRoute->NextHopsList.NumNextHops; i++)
|
||
|
{
|
||
|
// Get and release next hop info as we got a copy
|
||
|
|
||
|
dwResult = RtmGetNextHopInfo(g_hLocalRoute,
|
||
|
pRoute->NextHopsList.NextHops[i],
|
||
|
&nhiInfo);
|
||
|
|
||
|
if (dwResult isnot NO_ERROR)
|
||
|
{
|
||
|
Trace1(ROUTE,
|
||
|
"Error %d retrieving next hop info from RTM",
|
||
|
dwResult);
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
RtmReleaseNextHopInfo(g_hLocalRoute, &nhiInfo);
|
||
|
|
||
|
// Get the next hop address from the nexthop info
|
||
|
|
||
|
RTM_IPV4_GET_ADDR_AND_LEN(nexthop,
|
||
|
dwLen,
|
||
|
&nhiInfo.NextHopAddress);
|
||
|
|
||
|
TraceRoute3(
|
||
|
ROUTE, "Next Hop %d.%d.%d.%d, If 0x%x, handle is 0x%x",
|
||
|
PRINT_IPADDR(nexthop),
|
||
|
nhiInfo.InterfaceIndex,
|
||
|
pRoute->NextHopsList.NextHops[i]
|
||
|
);
|
||
|
|
||
|
ENTER_READER(BINDING_LIST);
|
||
|
|
||
|
//
|
||
|
// find the binding given the interface id
|
||
|
//
|
||
|
|
||
|
pBinding = GetInterfaceBinding(nhiInfo.InterfaceIndex);
|
||
|
|
||
|
if(!(pBinding))
|
||
|
{
|
||
|
//
|
||
|
// The interface was deleted so lets just get out
|
||
|
//
|
||
|
|
||
|
EXIT_LOCK(BINDING_LIST);
|
||
|
|
||
|
TraceRoute2(ERR,
|
||
|
"**Warning** tried to %s route with interface %d which "
|
||
|
"is no longer present",
|
||
|
bAddRoute?"add":"delete",
|
||
|
nhiInfo.InterfaceIndex);
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// set adapter index - this is 0xffffffff
|
||
|
// if the nexthop interface is not MAPPED
|
||
|
//
|
||
|
|
||
|
ifindex = pBinding->bBound ? pBinding->dwIfIndex : INVALID_IF_INDEX;
|
||
|
|
||
|
if(((pRouteEntry->ire_proto is PROTO_IP_NT_STATIC) or
|
||
|
(pRouteEntry->ire_proto is PROTO_IP_NT_AUTOSTATIC)) and
|
||
|
(pBinding->ritType is ROUTER_IF_TYPE_FULL_ROUTER))
|
||
|
{
|
||
|
context = pBinding->dwSeqNumber;
|
||
|
|
||
|
TraceRoute1(ROUTE,
|
||
|
"route context : ICB == %d\n\n",
|
||
|
pBinding->dwSeqNumber);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
context = 0;
|
||
|
|
||
|
if(ifindex is INVALID_IF_INDEX)
|
||
|
{
|
||
|
Trace3(ERR,
|
||
|
"**Error** Tried to %s route to %d.%d.%d.%d over %d as DOD\n",
|
||
|
bAddRoute?"add":"delete",
|
||
|
PRINT_IPADDR(pRouteEntry->ire_dest),
|
||
|
pBinding->dwIfIndex);
|
||
|
|
||
|
EXIT_LOCK(BINDING_LIST);
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// First we figure out the correct nexthop for p2p links
|
||
|
// For all other links, we take the whatever is given to us
|
||
|
//
|
||
|
|
||
|
if(IsIfP2P(pBinding->ritType))
|
||
|
{
|
||
|
if(pBinding->bBound)
|
||
|
{
|
||
|
TraceRoute2(
|
||
|
ROUTE, "Next Hop %d.%d.%d.%d, remote address %d.%d.%d.%d, "
|
||
|
"bound p2p",
|
||
|
PRINT_IPADDR(nexthop),
|
||
|
PRINT_IPADDR(pBinding->dwRemoteAddress)
|
||
|
);
|
||
|
|
||
|
if (nexthop is 0)
|
||
|
{
|
||
|
nexthop = pBinding->dwRemoteAddress;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
nexthop = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now we figure out if the route is a direct route or indirect routes
|
||
|
// Routes over unconnected demand dial routes are marked OTHER
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// For connected WAN interfaces (P2P with mask of 255.255.255.255) we
|
||
|
// do two checks:
|
||
|
// The next hop should be local address or remote address.
|
||
|
// AR: We used to do the above check but removed it because when
|
||
|
// we set a route over a disconnected interface, we dont
|
||
|
// know the address of the remote endpoint
|
||
|
// If the dest is remote address, then the MASK must be all ONES
|
||
|
// We mark all valid routes as DIRECT
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// For LAN interfaces and WAN with non all ones mask, we check the
|
||
|
// following:
|
||
|
// A direct route to a host must have the Destination as the NextHop
|
||
|
// A direct route to a network must have the the NextHop as one of the
|
||
|
// local interfaces
|
||
|
// The next hop must be on the same subnet as one of the bindings
|
||
|
//
|
||
|
|
||
|
type = IRE_TYPE_OTHER;
|
||
|
|
||
|
if(pBinding->bBound)
|
||
|
{
|
||
|
if((pBinding->dwNumAddresses is 1) and
|
||
|
(pBinding->rgibBinding[0].dwMask is ALL_ONES_MASK))
|
||
|
{
|
||
|
//
|
||
|
// route over P2P link or P2MP link, possibly unnumbered.
|
||
|
//
|
||
|
|
||
|
if(((pBinding->dwRemoteAddress isnot 0) and
|
||
|
(pRouteEntry->ire_dest is pBinding->dwRemoteAddress)) or
|
||
|
(pRouteEntry->ire_dest is nexthop))
|
||
|
{
|
||
|
type = IRE_TYPE_DIRECT;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
type = IRE_TYPE_INDIRECT;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// A route over a non P2P link or a bay style p2p link which
|
||
|
// has a /30 mask
|
||
|
//
|
||
|
|
||
|
bValidNHop = FALSE;
|
||
|
|
||
|
type = IRE_TYPE_INDIRECT;
|
||
|
|
||
|
for(i = 0; i < pBinding->dwNumAddresses; i++)
|
||
|
{
|
||
|
dwLocalMask = pBinding->rgibBinding[i].dwMask;
|
||
|
|
||
|
dwLocalNet = pBinding->rgibBinding[i].dwAddress & dwLocalMask;
|
||
|
|
||
|
if((dwLocalNet is (pRouteEntry->ire_dest & dwLocalMask)) or
|
||
|
(nexthop is IP_LOOPBACK_ADDRESS) or
|
||
|
(nexthop is pBinding->rgibBinding[i].dwAddress))
|
||
|
{
|
||
|
//
|
||
|
// Route to local net or over loopback
|
||
|
//
|
||
|
|
||
|
type = IRE_TYPE_DIRECT;
|
||
|
}
|
||
|
|
||
|
if(((nexthop & dwLocalMask) is dwLocalNet) or
|
||
|
((nexthop is IP_LOOPBACK_ADDRESS)))
|
||
|
{
|
||
|
//
|
||
|
// Next hop is on local net or loopback
|
||
|
// That is good
|
||
|
//
|
||
|
|
||
|
bValidNHop = TRUE;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(!bValidNHop and
|
||
|
(pBinding->dwNumAddresses isnot 0) and
|
||
|
(pBinding->ritType isnot ROUTER_IF_TYPE_INTERNAL))
|
||
|
{
|
||
|
Trace0(ERR,
|
||
|
"ERROR - Nexthop not on same network");
|
||
|
|
||
|
for(i = 0; i < pBinding->dwNumAddresses; i ++)
|
||
|
{
|
||
|
Trace3(ROUTE,"AdapterId: %d, %d.%d.%d.%d/%d.%d.%d.%d",
|
||
|
pBinding->dwIfIndex,
|
||
|
PRINT_IPADDR(pBinding->rgibBinding[i].dwAddress),
|
||
|
PRINT_IPADDR(pBinding->rgibBinding[i].dwMask));
|
||
|
}
|
||
|
|
||
|
EXIT_LOCK(BINDING_LIST);
|
||
|
|
||
|
|
||
|
// PrintRoute(ERR, ipRoute);
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
EXIT_LOCK(BINDING_LIST);
|
||
|
|
||
|
#if 0
|
||
|
// DGT workaround for bug where stack won't accept
|
||
|
// nexthop of 0.0.0.0. Until Chait fixes this, we'll
|
||
|
// set nexthop to the ifindex.
|
||
|
|
||
|
if (!nexthop)
|
||
|
{
|
||
|
nexthop = ifindex;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Fill the current nexthop info into the route
|
||
|
//
|
||
|
|
||
|
if (numnexthops)
|
||
|
{
|
||
|
// Copy to the next posn in the route
|
||
|
pNexthopEntry =
|
||
|
&pMultiRouteEntry->imre_morenexthops[numnexthops - 1];
|
||
|
|
||
|
pNexthopEntry->ine_iretype = type;
|
||
|
pNexthopEntry->ine_ifindex = ifindex;
|
||
|
pNexthopEntry->ine_nexthop = nexthop;
|
||
|
pNexthopEntry->ine_context = context;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Copy to the first posn in the route
|
||
|
pRouteEntry->ire_type = type;
|
||
|
pRouteEntry->ire_index = ifindex;
|
||
|
pRouteEntry->ire_nexthop = nexthop;
|
||
|
pRouteEntry->ire_context = context;
|
||
|
}
|
||
|
|
||
|
numnexthops++;
|
||
|
}
|
||
|
|
||
|
pMultiRouteEntry->imre_numnexthops = numnexthops;
|
||
|
pMultiRouteEntry->imre_flags = bDelOld ? IMRE_FLAG_DELETE_DEST : 0;
|
||
|
|
||
|
if (numnexthops > 0)
|
||
|
{
|
||
|
dwResult = SetIpMultihopRouteEntryToStack(pMultiRouteEntry);
|
||
|
|
||
|
if(dwResult isnot NO_ERROR)
|
||
|
{
|
||
|
if(pRouteEntry->ire_nexthop != IP_LOOPBACK_ADDRESS)
|
||
|
{
|
||
|
Trace1(ERR,
|
||
|
"Route addition failed with %x for", dwResult);
|
||
|
|
||
|
PrintRoute(ERR, pMultiRouteEntry);
|
||
|
}
|
||
|
|
||
|
Trace1(ERR,
|
||
|
"Route addition failed with %x for local route", dwResult);
|
||
|
|
||
|
TraceLeave("ChangeRouteWithForwarder");
|
||
|
|
||
|
return dwResult;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Trace0(ROUTE,
|
||
|
"Route addition succeeded for");
|
||
|
|
||
|
PrintRoute(ROUTE, pMultiRouteEntry);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
else
|
||
|
{
|
||
|
Trace0(ERR, "Route not added since there are no next hops" );
|
||
|
|
||
|
PrintRoute(ROUTE, pMultiRouteEntry);
|
||
|
}
|
||
|
|
||
|
TraceLeave("ChangeRouteWithForwarder");
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
ValidateRouteForProtocol(
|
||
|
IN DWORD dwProtoId,
|
||
|
IN PVOID pRouteInfo,
|
||
|
IN PVOID pDestAddr OPTIONAL
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function is called by the router Manger (and indirectly by routing
|
||
|
protocols) to validate the route info. We set the preference and the
|
||
|
type of the route
|
||
|
|
||
|
Locks:
|
||
|
|
||
|
Acquires the binding lock
|
||
|
This function CAN NOT acquire the ICB lock
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
dwProtoId Protocols Id
|
||
|
pRoute
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NO_ERROR
|
||
|
RtmError code
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
RTM_DEST_INFO destInfo;
|
||
|
PRTM_ROUTE_INFO pRoute;
|
||
|
RTM_NEXTHOP_INFO nextHop;
|
||
|
PADAPTER_INFO pBinding;
|
||
|
HANDLE hNextHop;
|
||
|
BOOL bValidNHop;
|
||
|
DWORD dwIfIndex;
|
||
|
DWORD dwLocalNet;
|
||
|
DWORD dwLocalMask;
|
||
|
DWORD destAddr;
|
||
|
DWORD destMask;
|
||
|
DWORD nexthop;
|
||
|
DWORD nhopMask;
|
||
|
DWORD dwType;
|
||
|
DWORD dwResult;
|
||
|
UINT i, j;
|
||
|
|
||
|
pRoute = (PRTM_ROUTE_INFO)pRouteInfo;
|
||
|
|
||
|
if (pRoute->PrefInfo.Preference is 0)
|
||
|
{
|
||
|
//
|
||
|
// Map the metric weight based on the weight assigned by admin
|
||
|
//
|
||
|
|
||
|
pRoute->PrefInfo.Preference = ComputeRouteMetric(dwProtoId);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// This validation applies to the unicast routes only.
|
||
|
// [ This does not apply to INACTIVE routes and such ]
|
||
|
//
|
||
|
|
||
|
if (!(pRoute->BelongsToViews & RTM_VIEW_MASK_UCAST))
|
||
|
{
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the destination address if it is not specified
|
||
|
//
|
||
|
|
||
|
if (!ARGUMENT_PRESENT(pDestAddr))
|
||
|
{
|
||
|
//
|
||
|
// Get the destination information from the route
|
||
|
//
|
||
|
|
||
|
dwResult = RtmGetDestInfo(g_hLocalRoute,
|
||
|
pRoute->DestHandle,
|
||
|
RTM_BEST_PROTOCOL,
|
||
|
RTM_VIEW_MASK_UCAST,
|
||
|
&destInfo);
|
||
|
|
||
|
if (dwResult != NO_ERROR)
|
||
|
{
|
||
|
Trace0(ERR,
|
||
|
"**ERROR:ValidateRoute: Invalid destination");
|
||
|
|
||
|
return dwResult;
|
||
|
}
|
||
|
|
||
|
pDestAddr = &destInfo.DestAddress;
|
||
|
|
||
|
RtmReleaseDestInfo(g_hLocalRoute, &destInfo);
|
||
|
}
|
||
|
|
||
|
RTM_IPV4_GET_ADDR_AND_MASK(destAddr,
|
||
|
destMask,
|
||
|
(PRTM_NET_ADDRESS)pDestAddr);
|
||
|
|
||
|
//
|
||
|
// If the dest&Mask != dest then the stack will not set this route
|
||
|
// Hence lets do the check here
|
||
|
//
|
||
|
|
||
|
if((destAddr & destMask) isnot destAddr)
|
||
|
{
|
||
|
|
||
|
#if TRACE_DBG
|
||
|
|
||
|
Trace2(ROUTE,
|
||
|
"**ERROR:ValidateRoute: called with Dest %d.%d.%d.%d and Mask %d.%d.%d.%d - This will fail**",
|
||
|
PRINT_IPADDR(destAddr),
|
||
|
PRINT_IPADDR(destMask));
|
||
|
|
||
|
#endif // TRACE_DBG
|
||
|
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
if((((DWORD)(destAddr & 0x000000FF)) >= (DWORD)0x000000E0) and
|
||
|
(destAddr isnot ALL_ONES_BROADCAST) and
|
||
|
(destAddr isnot LOCAL_NET_MULTICAST))
|
||
|
{
|
||
|
//
|
||
|
// This will catch the CLASS D/E but allow all 1's bcast
|
||
|
//
|
||
|
|
||
|
Trace1(ERR,
|
||
|
"**ERROR:ValidateRoute: Dest %d.%d.%d.%d is invalid",
|
||
|
PRINT_IPADDR(destAddr));
|
||
|
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
// Removed this since metric=0 is legal for routes to the loopback
|
||
|
// interface.
|
||
|
if(pRoute->PrefInfo.Metric is 0)
|
||
|
{
|
||
|
Trace0(ERR,
|
||
|
"**ERROR:ValidateRoute: Metric cant be 0");
|
||
|
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (pRoute->NextHopsList.NumNextHops == 0)
|
||
|
{
|
||
|
Trace0(ERR,
|
||
|
"**ERROR:ValidateRoute: Zero next hops");
|
||
|
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
// Make sure each next hop on the route is a valid one
|
||
|
|
||
|
for (i = 0; i < pRoute->NextHopsList.NumNextHops; i++)
|
||
|
{
|
||
|
hNextHop = pRoute->NextHopsList.NextHops[i];
|
||
|
|
||
|
dwResult = RtmGetNextHopInfo(g_hLocalRoute,
|
||
|
hNextHop,
|
||
|
&nextHop);
|
||
|
|
||
|
if (dwResult != NO_ERROR)
|
||
|
{
|
||
|
Trace0(ERR,
|
||
|
"**ERROR:ValidateRoute: Invalid next hop");
|
||
|
|
||
|
return dwResult;
|
||
|
}
|
||
|
|
||
|
dwIfIndex = nextHop.InterfaceIndex;
|
||
|
|
||
|
RTM_IPV4_GET_ADDR_AND_MASK(nexthop,
|
||
|
nhopMask,
|
||
|
(PRTM_NET_ADDRESS)&nextHop.NextHopAddress);
|
||
|
|
||
|
RtmReleaseNextHopInfo(g_hLocalRoute, &nextHop);
|
||
|
|
||
|
// *** Exclusion Begin ***
|
||
|
ENTER_READER(BINDING_LIST);
|
||
|
|
||
|
//
|
||
|
// find the interface given the interface id
|
||
|
//
|
||
|
|
||
|
pBinding = GetInterfaceBinding(dwIfIndex);
|
||
|
|
||
|
if(!pBinding)
|
||
|
{
|
||
|
EXIT_LOCK(BINDING_LIST);
|
||
|
|
||
|
#if TRACE_DBG
|
||
|
|
||
|
Trace0(ERR,
|
||
|
"**ERROR:ValidateRoute: Interface block doesnt exist");
|
||
|
|
||
|
#endif // TRACE_DBG
|
||
|
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Set whether the route is P2P
|
||
|
//
|
||
|
|
||
|
if(IsIfP2P(pBinding->ritType))
|
||
|
{
|
||
|
// Note that in the multihop case, we just overwrite value
|
||
|
SetRouteP2P(pRoute);
|
||
|
/*
|
||
|
ipRoute->RR_NextHopAddress.N_NetNumber =
|
||
|
RtlUlongByteSwap(pBinding->dwIfIndex);
|
||
|
|
||
|
ipRoute->RR_NextHopAddress.N_NetMask = ALL_ONES_MASK;
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
//
|
||
|
// If the next hop mask is not set, we need to do so now. Normally
|
||
|
// this shouldnt happen
|
||
|
//
|
||
|
|
||
|
#if ROUTE_DBG
|
||
|
|
||
|
if(!(ipRoute->RR_NextHopAddress.N_NetMask))
|
||
|
{
|
||
|
Trace0(ERR,
|
||
|
"**WARNING:Route doesnt seem to have any next hop mask**");
|
||
|
}
|
||
|
|
||
|
#endif // ROUTE_DBG
|
||
|
*/
|
||
|
|
||
|
//
|
||
|
// Now we figure out if the route is a direct route or indirect routes
|
||
|
// Routes over unconnected demand dial routes are marked OTHER
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// For connected WAN interfaces (P2P with mask of 255.255.255.255) we
|
||
|
// do two checks:
|
||
|
// The next hop should be local address or remote address.
|
||
|
// AR: We used to do the above check but removed it because when
|
||
|
// we set a route over a disconnected interface, we dont
|
||
|
// know the address of the remote endpoint
|
||
|
// If the dest is remote address, then the MASK must be all ONES
|
||
|
// We mark all valid routes as DIRECT
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// For LAN interfaces and WAN with non all ones mask, we check the
|
||
|
// following:
|
||
|
// A direct route to a host to must have the Destination as the NextHop
|
||
|
// A direct route to a network to must have the the NextHop as one of the
|
||
|
// local interfaces
|
||
|
// The next hop must be on the same subnet as one of the bindings
|
||
|
//
|
||
|
|
||
|
dwType = IRE_TYPE_OTHER;
|
||
|
|
||
|
if(pBinding->bBound and IsRouteValid(pRoute))
|
||
|
{
|
||
|
//
|
||
|
// Comment this block out - as we validate this
|
||
|
// next hop for the LAN case below, and dont care
|
||
|
// what it is in the WAN case as we set it to 0.
|
||
|
//
|
||
|
/*
|
||
|
//
|
||
|
// So outgoing interface has a valid address
|
||
|
// and next hop should have been plumbed in
|
||
|
//
|
||
|
if(nexthop && (destAddr is nexthop))
|
||
|
{
|
||
|
//
|
||
|
// A direct host route
|
||
|
//
|
||
|
|
||
|
if(destMask isnot HOST_ROUTE_MASK)
|
||
|
{
|
||
|
EXIT_LOCK(BINDING_LIST);
|
||
|
|
||
|
Trace0(ERR,
|
||
|
"ValidateRoute: Host route with wrong mask");
|
||
|
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
dwType = IRE_TYPE_DIRECT;
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
if((pBinding->dwNumAddresses is 1) and
|
||
|
(pBinding->rgibBinding[0].dwMask is ALL_ONES_MASK))
|
||
|
{
|
||
|
//
|
||
|
// route over P2P link.
|
||
|
// Set it to indirect and mark it as a P2P route
|
||
|
//
|
||
|
|
||
|
dwType = IRE_TYPE_DIRECT;
|
||
|
|
||
|
//IpRtAssert(IsRouteP2P(pRoute));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// A route over a non P2P link possibly unnumbered
|
||
|
//
|
||
|
|
||
|
bValidNHop = FALSE;
|
||
|
|
||
|
dwType = IRE_TYPE_INDIRECT;
|
||
|
|
||
|
for(j = 0; j < pBinding->dwNumAddresses; j++)
|
||
|
{
|
||
|
dwLocalMask = pBinding->rgibBinding[j].dwMask;
|
||
|
|
||
|
dwLocalNet = pBinding->rgibBinding[j].dwAddress & dwLocalMask;
|
||
|
|
||
|
if((dwLocalNet is (destAddr & dwLocalMask)) or
|
||
|
(nexthop is IP_LOOPBACK_ADDRESS) or
|
||
|
//(nexthop is dwLocalNet) or
|
||
|
(nexthop is pBinding->rgibBinding[i].dwAddress))
|
||
|
{
|
||
|
//
|
||
|
// Route to local net or over loopback
|
||
|
//
|
||
|
|
||
|
dwType = IRE_TYPE_DIRECT;
|
||
|
}
|
||
|
|
||
|
if(((nexthop & dwLocalMask) is dwLocalNet) or
|
||
|
((nexthop is IP_LOOPBACK_ADDRESS)))
|
||
|
{
|
||
|
//
|
||
|
// Next hop is on local net or loopback
|
||
|
// That is good
|
||
|
//
|
||
|
|
||
|
bValidNHop = TRUE;
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(!bValidNHop and
|
||
|
pBinding->dwNumAddresses and
|
||
|
(pBinding->ritType isnot ROUTER_IF_TYPE_INTERNAL))
|
||
|
{
|
||
|
Trace1(ERR,
|
||
|
"ValidateRoute: Nexthop %d.%d.%d.%d not on network",
|
||
|
PRINT_IPADDR(nexthop));
|
||
|
|
||
|
for(j = 0; j < pBinding->dwNumAddresses; j++)
|
||
|
{
|
||
|
Trace3(ROUTE,"AdapterId: %d, %d.%d.%d.%d/%d.%d.%d.%d",
|
||
|
pBinding->dwIfIndex,
|
||
|
PRINT_IPADDR(pBinding->rgibBinding[j].dwAddress),
|
||
|
PRINT_IPADDR(pBinding->rgibBinding[j].dwMask));
|
||
|
}
|
||
|
|
||
|
EXIT_LOCK(BINDING_LIST);
|
||
|
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
#if ROUTE_DBG
|
||
|
|
||
|
if(ipRoute->RR_NextHopAddress.N_NetMask isnot dwLocalMask)
|
||
|
{
|
||
|
Trace0(ERR,
|
||
|
"**WARNING:Route doesnt seem to have the right next hop mask**");
|
||
|
|
||
|
PrintRoute(ERR,ipRoute);
|
||
|
|
||
|
ipRoute->RR_NextHopAddress.N_NetMask = dwLocalMask;
|
||
|
}
|
||
|
|
||
|
#endif // ROUTE_DBG
|
||
|
*/
|
||
|
|
||
|
// *** Exclusion End ***
|
||
|
EXIT_LOCK(BINDING_LIST);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Set the appropriate route flags in the route - stack flag etc.
|
||
|
//
|
||
|
|
||
|
// pRoute->Flags1 |= IP_STACK_ROUTE;
|
||
|
|
||
|
g_LastUpdateTable[IPFORWARDCACHE] = 0;
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
ValidateRouteForProtocolEx(
|
||
|
IN DWORD dwProtoId,
|
||
|
IN PVOID pRouteInfo,
|
||
|
IN PVOID pDestAddr OPTIONAL
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function is called by the router Manger (and indirectly by routing
|
||
|
protocols) to validate the route info. We set the preference and the
|
||
|
type of the route
|
||
|
|
||
|
Locks:
|
||
|
|
||
|
Acquires the binding lock
|
||
|
This function CAN NOT acquire the ICB lock
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
dwProtoId Protocols Id
|
||
|
pRoute
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NO_ERROR
|
||
|
RtmError code
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD dwResult;
|
||
|
|
||
|
dwResult = ValidateRouteForProtocol(
|
||
|
dwProtoId,
|
||
|
pRouteInfo,
|
||
|
pDestAddr
|
||
|
);
|
||
|
|
||
|
if (dwResult is NO_ERROR)
|
||
|
{
|
||
|
((PRTM_ROUTE_INFO)pRouteInfo)->Flags1 |= IP_STACK_ROUTE;
|
||
|
}
|
||
|
|
||
|
return dwResult;
|
||
|
}
|
||
|
|