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