Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

914 lines
17 KiB

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