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