/*++ Copyright (c) 1995 Microsoft Corporation Module Name: rtmif.c Abstract: Static & local routes management functions Author: Stefan Solomon 03/13/1995 Revision History: --*/ #include "precomp.h" #pragma hdrstop extern UCHAR bcastnode[6]; INT NetNumCmpFunc(PDWORD Net1, PDWORD Net2); INT NextHopAddrCmpFunc(PRTM_IPX_ROUTE Route1p, PRTM_IPX_ROUTE Route2p); BOOL FamSpecDataCmpFunc(PRTM_IPX_ROUTE Route1p, PRTM_IPX_ROUTE Route2p); INT NetNumHashFunc(PDWORD Net); INT RouteMetricCmpFunc(PRTM_IPX_ROUTE Route1p, PRTM_IPX_ROUTE Route2p); DWORD RouteValidateFunc(PRTM_IPX_ROUTE Routep); RTM_PROTOCOL_FAMILY_CONFIG Config = { 0, 0, sizeof(RTM_IPX_ROUTE), NetNumCmpFunc, NextHopAddrCmpFunc, FamSpecDataCmpFunc, RouteMetricCmpFunc, NetNumHashFunc, RouteValidateFunc, FwUpdateRouteTable }; USHORT tickcount(UINT linkspeed); /*++ Function: CreateRouteTable Descr: Creates the IPX route table in RTM --*/ DWORD CreateRouteTable(VOID) { DWORD rc; Config.RPFC_MaxTableSize = MaxRoutingTableSize; Config.RPFC_HashSize = RoutingTableHashSize; rc = RtmCreateRouteTable( RTM_PROTOCOL_FAMILY_IPX, &Config); return rc; } /*++ Function: DeleteRouteTable Descr: Creates the IPX route table in RTM --*/ DWORD DeleteRouteTable(VOID) { DWORD rc; rc = RtmDeleteRouteTable(RTM_PROTOCOL_FAMILY_IPX); return rc; } /*++ Function: StaticToRtmRoute Descr: Creates a RTM IPX route entry out of an IPX_STATIC_ROUTE_INFO --*/ VOID StaticToRtmRoute(PRTM_IPX_ROUTE RtmRoutep, ULONG IfIndex, PIPX_STATIC_ROUTE_INFO StaticRouteInfop) { RtmRoutep->R_Interface = IfIndex; RtmRoutep->R_Protocol = IPX_PROTOCOL_STATIC; GETLONG2ULONG(&RtmRoutep->R_Network, StaticRouteInfop->Network); RtmRoutep->R_TickCount = StaticRouteInfop->TickCount; RtmRoutep->R_HopCount = StaticRouteInfop->HopCount; memcpy(RtmRoutep->R_NextHopMacAddress, StaticRouteInfop->NextHopMacAddress, 6); RtmRoutep->R_Flags = 0; } VOID RtmToStaticRoute(PIPX_STATIC_ROUTE_INFO StaticRouteInfop, PRTM_IPX_ROUTE RtmRoutep) { PUTULONG2LONG(StaticRouteInfop->Network, RtmRoutep->R_Network); StaticRouteInfop->TickCount = (USHORT)(RtmRoutep->R_TickCount); StaticRouteInfop->HopCount = RtmRoutep->R_HopCount; memcpy(StaticRouteInfop->NextHopMacAddress, RtmRoutep->R_NextHopMacAddress, 6); } VOID RtmToIpxRoute(PIPX_ROUTE IpxRoutep, PRTM_IPX_ROUTE RtmRoutep) { IpxRoutep->InterfaceIndex = (ULONG)(RtmRoutep->R_Interface); IpxRoutep->Protocol = RtmRoutep->R_Protocol; PUTULONG2LONG(IpxRoutep->Network, RtmRoutep->R_Network); IpxRoutep->TickCount = (USHORT)(RtmRoutep->R_TickCount); IpxRoutep->HopCount = RtmRoutep->R_HopCount; memcpy(IpxRoutep->NextHopMacAddress, RtmRoutep->R_NextHopMacAddress, 6); IpxRoutep->Flags = RtmRoutep->R_Flags; } DWORD CreateStaticRoute(PICB icbp, PIPX_STATIC_ROUTE_INFO StaticRouteInfop) { DWORD rc, flags; RTM_IPX_ROUTE RtmRoute; StaticToRtmRoute(&RtmRoute, icbp->InterfaceIndex, StaticRouteInfop); if (icbp->AdminState==ADMIN_STATE_DISABLED) RtmRoute.R_Flags = DO_NOT_ADVERTISE_ROUTE; rc = RtmAddRoute(RtmStaticHandle, &RtmRoute, INFINITE, &flags, NULL, NULL); SS_ASSERT(rc == NO_ERROR); if (icbp->AdminState==ADMIN_STATE_DISABLED) { DisableStaticRoute (icbp->InterfaceIndex, StaticRouteInfop->Network); RtmRoute.R_Flags = 0; rc = RtmAddRoute(RtmStaticHandle, &RtmRoute, INFINITE, &flags, NULL, NULL); SS_ASSERT (rc == NO_ERROR); } return rc; } DWORD DeleteStaticRoute(ULONG IfIndex, PIPX_STATIC_ROUTE_INFO StaticRouteInfop) { DWORD rc; DWORD RtmFlags; RTM_IPX_ROUTE RtmRoute; StaticToRtmRoute(&RtmRoute, IfIndex, StaticRouteInfop); rc = RtmDeleteRoute(RtmStaticHandle, &RtmRoute, &RtmFlags, NULL ); SS_ASSERT(rc == NO_ERROR); return rc; } VOID DeleteAllStaticRoutes(ULONG InterfaceIndex) { RTM_IPX_ROUTE RtmCriteriaRoute; Trace(ROUTE_TRACE, "DeleteAllStaticRoutes: Entered for if # %d\n", InterfaceIndex); memset(&RtmCriteriaRoute, 0, sizeof(RTM_IPX_ROUTE)); RtmCriteriaRoute.R_Interface = InterfaceIndex; RtmCriteriaRoute.R_Protocol = IPX_PROTOCOL_STATIC; RtmBlockDeleteRoutes(RtmStaticHandle, RTM_ONLY_THIS_INTERFACE, &RtmCriteriaRoute); } VOID LocalToRtmRoute(PRTM_IPX_ROUTE RtmRoutep, PICB icbp) { RtmRoutep->R_Interface = icbp->InterfaceIndex; RtmRoutep->R_Protocol = IPX_PROTOCOL_LOCAL; GETLONG2ULONG(&RtmRoutep->R_Network, icbp->acbp->AdapterInfo.Network); RtmRoutep->R_TickCount = tickcount(icbp->acbp->AdapterInfo.LinkSpeed); RtmRoutep->R_HopCount = 1; memset(RtmRoutep->R_NextHopMacAddress, 0, 6); // if this is a local workstation dialout interface, then do not // advertise this route over any protocol if(icbp->MIBInterfaceType == IF_TYPE_ROUTER_WORKSTATION_DIALOUT) { RtmRoutep->R_Flags = DO_NOT_ADVERTISE_ROUTE; } else { RtmRoutep->R_Flags = 0; } } DWORD CreateLocalRoute(PICB icbp) { DWORD rc, flags; RTM_IPX_ROUTE RtmRoute; if(!memcmp(icbp->acbp->AdapterInfo.Network, nullnet, 4)) { Trace(ROUTE_TRACE, "CreateLocalRoute: Can't create local NULL route !\n"); return NO_ERROR; } LocalToRtmRoute(&RtmRoute, icbp); rc = RtmAddRoute(RtmLocalHandle, &RtmRoute, INFINITE, &flags, NULL, NULL); SS_ASSERT(rc == NO_ERROR); return rc; } DWORD DeleteLocalRoute(PICB icbp) { DWORD rc; RTM_IPX_ROUTE RtmRoute; DWORD RtmFlags; LocalToRtmRoute(&RtmRoute, icbp); rc = RtmDeleteRoute(RtmLocalHandle, &RtmRoute, &RtmFlags, NULL); SS_ASSERT(rc == NO_ERROR); return rc; } VOID GlobalToRtmRoute(PRTM_IPX_ROUTE RtmRoutep, PUCHAR Network) { RtmRoutep->R_Interface = GLOBAL_INTERFACE_INDEX; RtmRoutep->R_Protocol = IPX_PROTOCOL_LOCAL; GETLONG2ULONG(&RtmRoutep->R_Network, Network); RtmRoutep->R_TickCount = 15; // a good default value -> should be a config param ??? !!! RtmRoutep->R_HopCount = 1; memset(RtmRoutep->R_NextHopMacAddress, 0, 6); RtmRoutep->R_Flags = GLOBAL_WAN_ROUTE; } /*++ Function: CreateGlobalRoute Descr: Creates a route which doesn't have a corresponding interface but represents a set of interfaces (e.g. all client wan interfaces). The interface index for this route is the "global interface" index. --*/ DWORD CreateGlobalRoute(PUCHAR Network) { DWORD rc, flags; RTM_IPX_ROUTE RtmRoute; Trace(ROUTE_TRACE, "CreateGlobalRoute: Entered for route %.2x%.2x%.2x%.2x\n", Network[0], Network[1], Network[2], Network[3]); GlobalToRtmRoute(&RtmRoute, Network); rc = RtmAddRoute(RtmLocalHandle, &RtmRoute, INFINITE, &flags, NULL, NULL); SS_ASSERT(rc == NO_ERROR); return rc; } DWORD DeleteGlobalRoute(PUCHAR Network) { DWORD rc; RTM_IPX_ROUTE RtmRoute; DWORD RtmFlags; Trace(ROUTE_TRACE, "DeleteGlobalRoute: Entered for route %.2x%.2x%.2x%.2x\n", Network[0], Network[1], Network[2], Network[3]); GlobalToRtmRoute(&RtmRoute, Network); rc = RtmDeleteRoute(RtmLocalHandle, &RtmRoute, &RtmFlags, NULL); SS_ASSERT(rc == NO_ERROR); return rc; } DWORD GetRoute(ULONG RoutingTable, PIPX_ROUTE IpxRoutep) { RTM_IPX_ROUTE RtmRoute; DWORD EnumFlags; DWORD rc; switch(RoutingTable) { case IPX_DEST_TABLE: EnumFlags = RTM_ONLY_THIS_NETWORK | RTM_ONLY_BEST_ROUTES | RTM_INCLUDE_DISABLED_ROUTES; GETLONG2ULONG(&RtmRoute.R_Network, IpxRoutep->Network); break; case IPX_STATIC_ROUTE_TABLE: EnumFlags = RTM_ONLY_THIS_NETWORK | RTM_ONLY_THIS_INTERFACE | RTM_ONLY_THIS_PROTOCOL | RTM_INCLUDE_DISABLED_ROUTES; RtmRoute.R_Interface = (IpxRoutep->InterfaceIndex); RtmRoute.R_Protocol = IPX_PROTOCOL_STATIC; GETLONG2ULONG(&RtmRoute.R_Network, IpxRoutep->Network); break; default: SS_ASSERT(FALSE); return ERROR_INVALID_PARAMETER; break; } rc = RtmGetFirstRoute( RTM_PROTOCOL_FAMILY_IPX, EnumFlags, &RtmRoute); RtmToIpxRoute(IpxRoutep, &RtmRoute); return rc; } /*++ Function: IsRoute Descr: returns TRUE if there is a route to the specified network --*/ BOOL IsRoute(PUCHAR Network) { RTM_IPX_ROUTE RtmRoute; DWORD EnumFlags; DWORD rc; EnumFlags = RTM_ONLY_THIS_NETWORK | RTM_ONLY_BEST_ROUTES | RTM_INCLUDE_DISABLED_ROUTES; GETLONG2ULONG(&RtmRoute.R_Network, Network); rc = RtmGetFirstRoute( RTM_PROTOCOL_FAMILY_IPX, EnumFlags, &RtmRoute); if(rc == NO_ERROR) { return TRUE; } return FALSE; } //******************************************************************************** // * // Fast Enumeration Functions - Used by the Router Manager for internal purposes * // * //******************************************************************************** HANDLE CreateStaticRoutesEnumHandle(ULONG InterfaceIndex) { RTM_IPX_ROUTE EnumCriteriaRoute; HANDLE EnumHandle; memset(&EnumCriteriaRoute, 0, sizeof(RTM_IPX_ROUTE)); EnumCriteriaRoute.R_Interface = InterfaceIndex; EnumCriteriaRoute.R_Protocol = IPX_PROTOCOL_STATIC; EnumHandle = RtmCreateEnumerationHandle(RTM_PROTOCOL_FAMILY_IPX, RTM_ONLY_THIS_INTERFACE | RTM_ONLY_THIS_PROTOCOL | RTM_INCLUDE_DISABLED_ROUTES, &EnumCriteriaRoute); if((EnumHandle == NULL) && (GetLastError() != ERROR_NO_ROUTES)) { Trace(ROUTE_TRACE, "CreateStaticRoutesEnumHandle: RtmCreateEnumerationHandle failed with %d\n", GetLastError()); SS_ASSERT(FALSE); } return EnumHandle; } DWORD GetNextStaticRoute(HANDLE EnumHandle, PIPX_STATIC_ROUTE_INFO StaticRtInfop) { RTM_IPX_ROUTE RtmRoute; DWORD rc; rc = RtmEnumerateGetNextRoute(EnumHandle, &RtmRoute); SS_ASSERT((rc == NO_ERROR) || (rc == ERROR_NO_MORE_ROUTES)); RtmToStaticRoute(StaticRtInfop, &RtmRoute); return rc; } VOID CloseStaticRoutesEnumHandle(HANDLE EnumHandle) { if(EnumHandle) { RtmCloseEnumerationHandle(EnumHandle); } } //******************************************************************************** // * // Slow Enumeration Functions - Used by the Router Manager for MIB APIs support * // * //******************************************************************************** DWORD GetFirstRoute(ULONG RoutingTable, PIPX_ROUTE IpxRoutep) { RTM_IPX_ROUTE RtmRoute; DWORD EnumFlags; DWORD rc; switch(RoutingTable) { case IPX_DEST_TABLE: // get the first route in the best routes table EnumFlags = RTM_ONLY_BEST_ROUTES | RTM_INCLUDE_DISABLED_ROUTES; break; case IPX_STATIC_ROUTE_TABLE: // get the first route in the static routes table for this // interface EnumFlags = RTM_ONLY_THIS_INTERFACE | RTM_ONLY_THIS_PROTOCOL | RTM_INCLUDE_DISABLED_ROUTES; RtmRoute.R_Interface = IpxRoutep->InterfaceIndex; RtmRoute.R_Protocol = IPX_PROTOCOL_STATIC; break; default: SS_ASSERT(FALSE); return ERROR_INVALID_PARAMETER; break; } rc = RtmGetFirstRoute( RTM_PROTOCOL_FAMILY_IPX, EnumFlags, &RtmRoute); RtmToIpxRoute(IpxRoutep, &RtmRoute); return rc; } DWORD GetNextRoute(ULONG RoutingTable, PIPX_ROUTE IpxRoutep) { RTM_IPX_ROUTE RtmRoute; DWORD EnumFlags; DWORD rc; ZeroMemory(&RtmRoute, sizeof(RtmRoute)); GETLONG2ULONG(&RtmRoute.R_Network, IpxRoutep->Network); switch(RoutingTable) { case IPX_DEST_TABLE: // get next route in the best routes table EnumFlags = RTM_ONLY_BEST_ROUTES | RTM_INCLUDE_DISABLED_ROUTES; break; case IPX_STATIC_ROUTE_TABLE: // get next route in the static routes table for this interface EnumFlags = RTM_ONLY_THIS_INTERFACE | RTM_ONLY_THIS_PROTOCOL | RTM_INCLUDE_DISABLED_ROUTES; RtmRoute.R_Interface = (IpxRoutep->InterfaceIndex); RtmRoute.R_Protocol = IPX_PROTOCOL_STATIC; memcpy(RtmRoute.R_NextHopMacAddress, bcastnode, 6); break; default: SS_ASSERT(FALSE); return ERROR_INVALID_PARAMETER; break; } rc = RtmGetNextRoute( RTM_PROTOCOL_FAMILY_IPX, EnumFlags, &RtmRoute); RtmToIpxRoute(IpxRoutep, &RtmRoute); return rc; } // // Convert routes added by updating routes protocol to static routes // /*++ Function: ConvertProtocolRoutesToStatic Descr: --*/ VOID ConvertAllProtocolRoutesToStatic(ULONG InterfaceIndex, ULONG RoutingProtocolId) { RTM_IPX_ROUTE RtmRoute; DWORD EnumFlags; DWORD rc; EnumFlags = RTM_ONLY_THIS_INTERFACE | RTM_ONLY_THIS_PROTOCOL; memset(&RtmRoute, 0, sizeof(RTM_IPX_ROUTE)); RtmRoute.R_Interface = InterfaceIndex; RtmRoute.R_Protocol = RoutingProtocolId; rc = RtmBlockConvertRoutesToStatic( RtmStaticHandle, EnumFlags, &RtmRoute); return; } VOID DisableStaticRoutes(ULONG InterfaceIndex) { RTM_IPX_ROUTE RtmRoute; DWORD EnumFlags; DWORD rc; EnumFlags = RTM_ONLY_THIS_INTERFACE; memset(&RtmRoute, 0, sizeof(RTM_IPX_ROUTE)); RtmRoute.R_Interface = InterfaceIndex; RtmRoute.R_Protocol = IPX_PROTOCOL_STATIC; rc = RtmBlockDisableRoutes( RtmStaticHandle, EnumFlags, &RtmRoute); return; } VOID DisableStaticRoute(ULONG InterfaceIndex, PUCHAR Network) { RTM_IPX_ROUTE RtmRoute; DWORD EnumFlags; DWORD rc; EnumFlags = RTM_ONLY_THIS_INTERFACE|RTM_ONLY_THIS_NETWORK; memset(&RtmRoute, 0, sizeof(RTM_IPX_ROUTE)); RtmRoute.R_Interface = InterfaceIndex; RtmRoute.R_Protocol = IPX_PROTOCOL_STATIC; GETLONG2ULONG(&RtmRoute.R_Network, Network); rc = RtmBlockDisableRoutes( RtmStaticHandle, EnumFlags, &RtmRoute); return; } VOID EnableStaticRoutes(ULONG InterfaceIndex) { RTM_IPX_ROUTE RtmRoute; DWORD EnumFlags; DWORD rc; EnumFlags = RTM_ONLY_THIS_INTERFACE; memset(&RtmRoute, 0, sizeof(RTM_IPX_ROUTE)); RtmRoute.R_Interface = InterfaceIndex; RtmRoute.R_Protocol = IPX_PROTOCOL_STATIC; rc = RtmBlockReenableRoutes( RtmStaticHandle, EnumFlags, &RtmRoute); return; } /*++ Function: GetStaticRoutesCount Descr: returns the number of static routes associated with this if --*/ DWORD GetStaticRoutesCount(ULONG InterfaceIndex) { HANDLE EnumHandle; DWORD rc, Count = 0; IPX_STATIC_ROUTE_INFO StaticRtInfo; EnumHandle = CreateStaticRoutesEnumHandle(InterfaceIndex); if(EnumHandle != NULL) { while(GetNextStaticRoute(EnumHandle, &StaticRtInfo) == NO_ERROR) { Count++; } CloseStaticRoutesEnumHandle(EnumHandle); } return Count; } INT NetNumCmpFunc(PDWORD Net1, PDWORD Net2) { if(*Net1 > *Net2) { return 1; } else { if(*Net1 == *Net2) { return 0; } else { return -1; } } } INT NextHopAddrCmpFunc(PRTM_IPX_ROUTE Route1p, PRTM_IPX_ROUTE Route2p) { return ( memcmp(Route1p->R_NextHopMacAddress, Route2p->R_NextHopMacAddress, 6) ); } BOOL FamSpecDataCmpFunc(PRTM_IPX_ROUTE Route1p, PRTM_IPX_ROUTE Route2p) { if((Route1p->R_Flags == Route2p->R_Flags) && (Route1p->R_TickCount == Route2p->R_TickCount) && (Route1p->R_HopCount == Route2p->R_HopCount)) { return TRUE; } else { return FALSE; } } INT NetNumHashFunc(PDWORD Net) { return (*Net % RoutingTableHashSize); } INT RouteMetricCmpFunc(PRTM_IPX_ROUTE Route1p, PRTM_IPX_ROUTE Route2p) { // if either route has 16 hops, it is the worst, no matter how many ticks if((Route1p->R_HopCount == 16) && (Route2p->R_HopCount == 16)) { return 0; } if(Route1p->R_HopCount == 16) { return 1; } if(Route2p->R_HopCount == 16) { return -1; } // shortest number of ticks is the best route if(Route1p->R_TickCount < Route2p->R_TickCount) { return -1; } if(Route1p->R_TickCount > Route2p->R_TickCount) { return 1; } // if two routes exist with equal tick count values, the one with // the least hops should be used if(Route1p->R_HopCount < Route2p->R_HopCount) { return -1; } if(Route1p->R_HopCount > Route2p->R_HopCount) { return 1; } return 0; } DWORD RouteValidateFunc(PRTM_IPX_ROUTE Routep) { return NO_ERROR; } /*++ Function: tickcount Descr: gets nr of ticks to send a 576 bytes packet over this link Argument: link speed as a multiple of 100 bps --*/ USHORT tickcount(UINT linkspeed) { USHORT tc; if(linkspeed == 0) { return 1; } if(linkspeed >= 10000) { // link speed >= 1M bps return 1; } else { // compute the necessary time to send a 576 bytes packet over this // line and express it as nr of ticks. // One tick = 55ms // time in ms to send 576 bytes (assuming 10 bits/byte for serial line) tc = 57600 / linkspeed; // in ticks tc = tc / 55 + 1; return tc; } }