624 lines
11 KiB
C
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;
|
|
}
|
|
}
|