/*++ 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 this will be a point to point interface, // ignore the next hop // if((pIcb->dwOperationalState is DISCONNECTED) and (pRoutes[i].dwRtInfoProto is PROTO_IP_NT_STATIC_NON_DOD)) { continue; } 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++) { 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); 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) { if((pRouteTable->table[i].dwForwardMask is HOST_ROUTE_MASK) or ((pRouteTable->table[i].dwForwardDest & ((DWORD) 0x000000FF)) >= ((DWORD) 0x000000E0)) or (pRouteTable->table[i].dwForwardDest == (pRouteTable->table[i].dwForwardDest | ~pRouteTable->table[i].dwForwardMask))) { bStack = FALSE; } } 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; 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, "InitLoopIf: 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, "InitLoopIf: 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, "InitLoopIf: 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; }