windows-nt/Source/XPSP1/NT/net/rras/ipx/rip/rtmif.c
2020-09-26 16:20:57 +08:00

624 lines
11 KiB
C

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
rtmif.c
Abstract:
Contains the RTM interface functions
Author:
Stefan Solomon 07/06/1995
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
// RTM RIP Client Handle
HANDLE RtmRipHandle;
typedef struct _ROUTE_NODE {
LIST_ENTRY Linkage;
IPX_ROUTE IpxRoute;
} ROUTE_NODE, *PROUTE_NODE;
// List of route nodes with RIP route changes
LIST_ENTRY RipChangedList;
// state of the RipChangedList
BOOL RipChangedListOpen = FALSE;
// Lock for the RIP changed list
CRITICAL_SECTION RipChangedListCritSec;
VOID
AddRouteToRipChangedList(PIPX_ROUTE IpxRoutep);
HANDLE
CreateRipRoutesEnumHandle(ULONG InterfaceIndex);
DWORD
OpenRTM(VOID)
{
// initialize the variables for the RIP changes list
InitializeListHead(&RipChangedList);
RipChangedListOpen = TRUE;
// register as RTM client
if((RtmRipHandle = RtmRegisterClient(RTM_PROTOCOL_FAMILY_IPX,
IPX_PROTOCOL_RIP,
WorkerThreadObjects[RTM_EVENT],
0)) == NULL) {
return ERROR_CAN_NOT_COMPLETE;
}
else
{
return NO_ERROR;
}
}
VOID
CloseRTM(VOID)
{
PLIST_ENTRY lep;
PROUTE_NODE rnp;
// flush the RIP changed list and destroy its critical section
ACQUIRE_RIP_CHANGED_LIST_LOCK;
while(!IsListEmpty(&RipChangedList))
{
lep = RemoveHeadList(&RipChangedList);
rnp = CONTAINING_RECORD(lep, ROUTE_NODE, Linkage);
GlobalFree(rnp);
}
RipChangedListOpen = FALSE;
RELEASE_RIP_CHANGED_LIST_LOCK;
// deregister as RTM client
RtmDeregisterClient(RtmRipHandle);
}
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 = RtmRoutep->R_TickCount;
IpxRoutep->HopCount = RtmRoutep->R_HopCount;
memcpy(IpxRoutep->NextHopMacAddress,
RtmRoutep->R_NextHopMacAddress,
6);
IpxRoutep->Flags = RtmRoutep->R_Flags;
}
VOID
IpxToRtmRoute(PRTM_IPX_ROUTE RtmRoutep,
PIPX_ROUTE IpxRoutep)
{
RtmRoutep->R_Interface = IpxRoutep->InterfaceIndex;
RtmRoutep->R_Protocol = IpxRoutep->Protocol;
GETLONG2ULONG(&RtmRoutep->R_Network, IpxRoutep->Network);
RtmRoutep->R_TickCount = IpxRoutep->TickCount;
RtmRoutep->R_HopCount = IpxRoutep->HopCount;
memcpy(RtmRoutep->R_NextHopMacAddress,
IpxRoutep->NextHopMacAddress,
6);
RtmRoutep->R_Flags = IpxRoutep->Flags;
}
/*++
Function: AddRipRoute
Descr: adds a RIP route to RTM
--*/
DWORD
AddRipRoute(PIPX_ROUTE IpxRoutep,
ULONG TimeToLive)
{
DWORD rc = 0;
DWORD flags = 0;
RTM_IPX_ROUTE RtmRoute;
RTM_IPX_ROUTE CurBestRoute;
RTM_IPX_ROUTE PrevBestRoute;
IPX_ROUTE PrevBestIpxRoute;
IpxRoutep->Protocol = IPX_PROTOCOL_RIP;
IpxToRtmRoute(&RtmRoute, IpxRoutep);
if((rc = RtmAddRoute(
RtmRipHandle,
&RtmRoute,
TimeToLive,
&flags,
&CurBestRoute,
&PrevBestRoute)) != NO_ERROR) {
return rc;
}
// check the type of change
switch(flags) {
case RTM_ROUTE_ADDED:
AddRouteToRipChangedList(IpxRoutep);
break;
case RTM_ROUTE_CHANGED:
if(CurBestRoute.R_HopCount == 16) {
if(PrevBestRoute.R_HopCount < 16) {
// advertise that the previous route is down
RtmToIpxRoute(&PrevBestIpxRoute, &PrevBestRoute);
PrevBestIpxRoute.HopCount = 16;
AddRouteToRipChangedList(&PrevBestIpxRoute);
}
}
else
{
if((CurBestRoute.R_TickCount != PrevBestRoute.R_TickCount) ||
(CurBestRoute.R_HopCount != PrevBestRoute.R_HopCount)) {
AddRouteToRipChangedList(IpxRoutep);
}
}
break;
default:
break;
}
return rc;
}
/*++
Function: DeleteRipRoute
Descr: deletes a RIP route from RTM
--*/
DWORD
DeleteRipRoute(PIPX_ROUTE IpxRoutep)
{
DWORD rc;
DWORD flags = 0;
RTM_IPX_ROUTE RtmRoute;
RTM_IPX_ROUTE CurBestRoute;
IPX_ROUTE CurBestIpxRoute;
IpxRoutep->Protocol = IPX_PROTOCOL_RIP;
IpxToRtmRoute(&RtmRoute, IpxRoutep);
if((rc = RtmDeleteRoute(RtmRipHandle,
&RtmRoute,
&flags,
&CurBestRoute
)) != NO_ERROR) {
return rc;
}
switch(flags) {
case RTM_ROUTE_DELETED:
// bcast that we lost the previous route
AddRouteToRipChangedList(IpxRoutep);
break;
case RTM_ROUTE_CHANGED:
// current best route changed
RtmToIpxRoute(&CurBestIpxRoute, &CurBestRoute);
if(CurBestIpxRoute.HopCount == 16) {
// bcast that we lost the previous route
AddRouteToRipChangedList(IpxRoutep);
}
else
{
// bcast that we have a new best route
AddRouteToRipChangedList(&CurBestIpxRoute);
}
break;
default:
break;
}
return rc;
}
/*++
Function: DeleteAllRipRoutes
Descr: deletes all RIP routes for the specified interface
--*/
VOID
DeleteAllRipRoutes(ULONG InterfaceIndex)
{
HANDLE EnumHandle;
IPX_ROUTE IpxRoute;
RTM_IPX_ROUTE RtmCriteriaRoute;
DWORD rc;
Trace(RTM_TRACE, "DeleteAllRipRoutes: Entered for if # %d\n", InterfaceIndex);
// enumerate all the routes for this interface and add them in the rip changed
// list
if((EnumHandle = CreateRipRoutesEnumHandle(InterfaceIndex)) == NULL) {
Trace(RTM_TRACE, "DeleteAllRipRoutes: cannot create enum handle for if # %d\n", InterfaceIndex);
goto DeleteRoutes;
}
while(EnumGetNextRoute(EnumHandle, &IpxRoute) == NO_ERROR)
{
if(IpxRoute.HopCount < 16) {
IpxRoute.HopCount = 16;
AddRouteToRipChangedList(&IpxRoute);
}
}
CloseEnumHandle(EnumHandle);
DeleteRoutes:
// ... and now delete all routes for this interface
memset(&RtmCriteriaRoute,
0,
sizeof(RTM_IPX_ROUTE));
RtmCriteriaRoute.R_Interface = InterfaceIndex;
RtmCriteriaRoute.R_Protocol = IPX_PROTOCOL_RIP;
rc = RtmBlockDeleteRoutes(RtmRipHandle,
RTM_ONLY_THIS_INTERFACE,
&RtmCriteriaRoute);
Trace(RTM_TRACE, "DeleteAllRipRoutes: RtmBlockDeleteRoutes returned rc=%d for if # %d\n",
rc,
InterfaceIndex);
}
/*++
Function: IsRoute
Descr: returns TRUE if a route to the specified net exists
--*/
BOOL
IsRoute(PUCHAR Network,
PIPX_ROUTE IpxRoutep)
{
DWORD RtmNetwork;
RTM_IPX_ROUTE RtmRoute;
GETLONG2ULONG(&RtmNetwork, Network);
if(RtmIsRoute(RTM_PROTOCOL_FAMILY_IPX,
&RtmNetwork,
&RtmRoute)) {
if (IpxRoutep!=NULL)
RtmToIpxRoute(IpxRoutep, &RtmRoute);
return TRUE;
}
else
{
return FALSE;
}
}
//***********************************************************************
// *
// Fast Enumeration Functions *
// *
//***********************************************************************
HANDLE
CreateBestRoutesEnumHandle(VOID)
{
HANDLE EnumHandle;
RTM_IPX_ROUTE CriteriaRoute;
EnumHandle = RtmCreateEnumerationHandle(RTM_PROTOCOL_FAMILY_IPX,
RTM_ONLY_BEST_ROUTES,
&CriteriaRoute);
return EnumHandle;
}
DWORD
EnumGetNextRoute(HANDLE EnumHandle,
PIPX_ROUTE IpxRoutep)
{
RTM_IPX_ROUTE RtmRoute;
DWORD rc;
rc = RtmEnumerateGetNextRoute(EnumHandle,
&RtmRoute);
if (rc == NO_ERROR)
{
RtmToIpxRoute(IpxRoutep, &RtmRoute);
}
return rc;
}
VOID
CloseEnumHandle(HANDLE EnumHandle)
{
RtmCloseEnumerationHandle(EnumHandle);
}
HANDLE
CreateRipRoutesEnumHandle(ULONG InterfaceIndex)
{
RTM_IPX_ROUTE EnumCriteriaRoute;
HANDLE EnumHandle;
memset(&EnumCriteriaRoute, 0, sizeof(RTM_IPX_ROUTE));
EnumCriteriaRoute.R_Interface = InterfaceIndex;
EnumCriteriaRoute.R_Protocol = IPX_PROTOCOL_RIP;
EnumHandle = RtmCreateEnumerationHandle(RTM_PROTOCOL_FAMILY_IPX,
RTM_ONLY_BEST_ROUTES | RTM_ONLY_THIS_INTERFACE | RTM_ONLY_THIS_PROTOCOL,
&EnumCriteriaRoute);
return EnumHandle;
}
/*++
Function: GetRipRoutesCount
Descr: returns the number of rip routes associated with this interface
--*/
ULONG
GetRipRoutesCount(ULONG InterfaceIndex)
{
HANDLE EnumHandle;
ULONG RipRoutesCount = 0;
IPX_ROUTE IpxRoute;
if((EnumHandle = CreateRipRoutesEnumHandle(InterfaceIndex)) == NULL) {
return 0;
}
while(EnumGetNextRoute(EnumHandle, &IpxRoute) == NO_ERROR)
{
RipRoutesCount++;
}
CloseEnumHandle(EnumHandle);
return RipRoutesCount;
}
/*++
Function: DequeueRouteChangeFromRip
Descr:
Remark: >> called with the database & queues lock held <<
--*/
DWORD
DequeueRouteChangeFromRip(PIPX_ROUTE IpxRoutep)
{
PLIST_ENTRY lep;
PROUTE_NODE rnp;
if(!IsListEmpty(&RipChangedList)) {
lep = RemoveHeadList(&RipChangedList);
rnp = CONTAINING_RECORD(lep, ROUTE_NODE, Linkage);
*IpxRoutep = rnp->IpxRoute;
GlobalFree(rnp);
return NO_ERROR;
}
else
{
return ERROR_NO_MORE_ITEMS;
}
}
/*++
Function: DequeueRouteChangeFromRtm
Descr:
Remark: >> called with the database locks held <<
--*/
DWORD
DequeueRouteChangeFromRtm(PIPX_ROUTE IpxRoutep,
PBOOL skipitp,
PBOOL lastmessagep)
{
RTM_IPX_ROUTE CurBestRoute, PrevBestRoute;
DWORD Flags = 0;
DWORD rc;
*skipitp = FALSE;
*lastmessagep = FALSE;
rc = RtmDequeueRouteChangeMessage(RtmRipHandle,
&Flags,
&CurBestRoute,
&PrevBestRoute);
switch(rc) {
case NO_ERROR:
*lastmessagep = TRUE;
break;
case ERROR_MORE_MESSAGES:
break;
default:
return ERROR_NO_MORE_ITEMS;
}
switch(Flags) {
case RTM_ROUTE_ADDED:
RtmToIpxRoute(IpxRoutep, &CurBestRoute);
break;
case RTM_ROUTE_DELETED:
RtmToIpxRoute(IpxRoutep, &PrevBestRoute);
IpxRoutep->HopCount = 16;
break;
case RTM_ROUTE_CHANGED:
// if there was a change in metric advertise it.
// Else, ignore it.
if(CurBestRoute.R_TickCount != PrevBestRoute.R_TickCount) {
RtmToIpxRoute(IpxRoutep, &CurBestRoute);
}
else
{
*skipitp = TRUE;
}
break;
default:
*skipitp = TRUE;
break;
}
return NO_ERROR;
}
VOID
AddRouteToRipChangedList(PIPX_ROUTE IpxRoutep)
{
PROUTE_NODE rnp;
if((rnp = GlobalAlloc(GPTR, sizeof(ROUTE_NODE))) == NULL) {
return;
}
rnp->IpxRoute = *IpxRoutep;
ACQUIRE_RIP_CHANGED_LIST_LOCK;
if(!RipChangedListOpen) {
GlobalFree(rnp);
}
else
{
InsertTailList(&RipChangedList, &rnp->Linkage);
SetEvent(WorkerThreadObjects[RIP_CHANGES_EVENT]);
}
RELEASE_RIP_CHANGED_LIST_LOCK;
}
BOOL
IsDuplicateBestRoute(PICB icbp,
PIPX_ROUTE IpxRoutep)
{
RTM_IPX_ROUTE RtmRoute;
DWORD rc;
GETLONG2ULONG(&RtmRoute.R_Network, IpxRoutep->Network);
RtmRoute.R_Interface = icbp->InterfaceIndex;
rc = RtmGetFirstRoute(
RTM_PROTOCOL_FAMILY_IPX,
RTM_ONLY_THIS_NETWORK | RTM_ONLY_THIS_INTERFACE,
&RtmRoute);
// check if it has the same metric
if((rc == NO_ERROR) &&
((USHORT)(RtmRoute.R_TickCount) == IpxRoutep->TickCount)) {
// duplicate !
return TRUE;
}
else
{
return FALSE;
}
}