|
|
/*++
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; }
|