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

381 lines
9.7 KiB
C

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
net\rtm\rtm.c
Abstract:
Routing Table Manager DLL. Helper routines
Author:
Vadim Eydelman
Revision History:
--*/
#include "pchrtm.h"
#pragma hdrstop
// Initializes sync list object
VOID
InitializeSyncList (
PRTM_SYNC_LIST list
) {
list->RSL_Sync = NULL;
list->RSL_UseCount = 0;
InitializeListHead (&list->RSL_Head);
}
// Get mutually exclusive access to the sync list obect
// Returns TRUE if access if obtained, FALSE otherwise
BOOLEAN
DoEnterSyncList (
PRTM_TABLE table, // Table this list belongs to
PRTM_SYNC_LIST list, // List of interest
BOOLEAN wait // True if caller wants to wait
// until list becomes available
#if DBG
, LPSTR file,
ULONG line
#endif
) {
DWORD status; // Status of OS calls
BOOLEAN result; // Result of operation
EnterCriticalSection (&table->RT_Lock);
// Protect manipilation by table-wide critical section
#if DBG
IF_DEBUG (SYNCHRONIZATION)
Trace4 (ANY, "%08lx (%s,%ld) - trying to enter sync list: %08x\n",
GetCurrentThreadId (), file, line, (ULONG_PTR)list);
#endif
if (list->RSL_UseCount<=0) {
// Nobody uses the list -> get it and return ok
list->RSL_UseCount = 1;
#if DBG
IF_DEBUG (SYNCHRONIZATION)
Trace0 (ANY, "\t - first to enter\n");
#endif
result = TRUE;
}
else if (wait) { // Somebody is using it, but caller agrees to wait
list->RSL_UseCount += 1; // Increment usage count
#if DBG
IF_DEBUG (SYNCHRONIZATION)
Trace1 (ANY, "\t - list in use: %d\n", list->RSL_UseCount);
#endif
if (list->RSL_Sync==NULL) { // if there is no event to wait on,
// get one
// First see if one is available
// in the stack
PSINGLE_LIST_ENTRY cur = PopEntryList (&table->RT_SyncObjectList);
#if DBG
IF_DEBUG (SYNCHRONIZATION)
Trace0 (ANY, "\t - need event\n");
#endif
if (cur==NULL) { // No, we'll have to create one
PRTM_SYNC_OBJECT sync;
sync = (PRTM_SYNC_OBJECT)GlobalAlloc (
GMEM_FIXED,
sizeof (RTM_SYNC_OBJECT));
if (sync==NULL) {
#if DBG
Trace2 (ANY,
"Can't allocate synchronization object.\n"
"\tat line %ld of %s\n",
__LINE__, __FILE__);
#endif
list->RSL_UseCount -= 1;
LeaveCriticalSection (&table->RT_Lock);
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
sync->RSO_Event = CreateEvent (NULL,
FALSE, // Auto reset event
FALSE, // Initially nonsignaled
NULL);
if (sync->RSO_Event==NULL) {
status = GetLastError ();
#if DBG
Trace2 (ANY,
"Can't allocate synchronization event.\n"
"\tat line %ld of %s\n",
__LINE__, __FILE__);
#endif
list->RSL_UseCount -= 1;
GlobalFree (sync);
LeaveCriticalSection (&table->RT_Lock);
SetLastError (status);
return FALSE;
}
list->RSL_Sync = sync;
#if DBG
IF_DEBUG (SYNCHRONIZATION)
Trace0 (ANY, "\t - event created\n");
#endif
}
else { // Yes, make sure it is reset
list->RSL_Sync = CONTAINING_RECORD (cur, RTM_SYNC_OBJECT, RSO_Link);
// Autoreset event gets reset after releasing a thread anyway
// status = ResetEvent (list->RSL_Sync->RSO_Event);
// ASSERTERRMSG ("Can't reset event.", status);
}
}
// Now as we set up the object to wait, we can leave critical
// section and wait on event
LeaveCriticalSection (&table->RT_Lock);
status = WaitForSingleObject (
list->RSL_Sync->RSO_Event,
INFINITE
);
ASSERTERRMSG ("Wait event failed.", status==WAIT_OBJECT_0);
// Event is signaled, we may now access the list (auto reset event
// releases only one thread
EnterCriticalSection (&table->RT_Lock);
#if DBG
IF_DEBUG (SYNCHRONIZATION)
Trace1 (ANY, "%08lx - wait completed\n", GetCurrentThreadId ());
#endif
// If our caller was the only one waiting,
// we can release the event
if (list->RSL_UseCount==1) {
#if DBG
IF_DEBUG (SYNCHRONIZATION)
Trace0 (ANY, "\t - restocking event\n");
#endif
PushEntryList (&table->RT_SyncObjectList, &list->RSL_Sync->RSO_Link);
list->RSL_Sync = NULL;
}
result = TRUE;
}
else {
// Caller does not want to wait
result = FALSE;
#if DBG
IF_DEBUG (SYNCHRONIZATION)
Trace0 (ANY, "\t - doesn't want to wait\n");
#endif
}
LeaveCriticalSection (&table->RT_Lock);
return result;
}
// Release previously owned sync list object
VOID
LeaveSyncList (
PRTM_TABLE table, // Table to which this object belongs
PRTM_SYNC_LIST list // List to release
) {
DWORD status;
EnterCriticalSection (&table->RT_Lock);
#if DBG
IF_DEBUG (SYNCHRONIZATION)
Trace2 (ANY, "%08lx - leaving sync list: %08x\n",
GetCurrentThreadId (), (ULONG_PTR)list);
#endif
// Decrement the count and signal the event (only one thread
// will be released for the auto-reset events
list->RSL_UseCount -= 1;
if (list->RSL_UseCount>0) {
#if DBG
IF_DEBUG (SYNCHRONIZATION)
Trace1 (ANY, "%\t - releasing one of %d waiting threads\n",
list->RSL_UseCount);
#endif
status = SetEvent (list->RSL_Sync->RSO_Event);
ASSERTERRMSG ("Can't signal event.", status);
}
LeaveCriticalSection (&table->RT_Lock);
}
// Finds list of routes that are associated with given interface and returns
// pointer to its head
// Creates new list of none exists yet
PLIST_ENTRY
FindInterfaceList (
PRTM_SYNC_LIST intfHash,
DWORD InterfaceID, // Interface to look for
BOOL CreateNew
) {
PRTM_INTERFACE_NODE intfNode;
PLIST_ENTRY cur;
// First try to find existing one in the list of interface lists
cur = intfHash->RSL_Head.Flink;
while (cur!=&intfHash->RSL_Head) {
intfNode = CONTAINING_RECORD (cur, RTM_INTERFACE_NODE, IN_Link);
if (InterfaceID<=intfNode->IN_InterfaceID) // List is ordered
// so we can stop
// if bigger number is reached
break;
cur = cur->Flink;
}
if ((cur==&intfHash->RSL_Head)
|| (InterfaceID!=intfNode->IN_InterfaceID)) { // Create new interface
// list
if (!CreateNew)
return NULL;
intfNode = (PRTM_INTERFACE_NODE)GlobalAlloc (
GMEM_FIXED,
sizeof (RTM_INTERFACE_NODE));
if (intfNode==NULL) {
#if DBG
// Report error in debuging builds
Trace2 (ANY,
"Can't allocate interface node\n\tat line %ld of %s\n",
__LINE__, __FILE__);
#endif
return NULL;
}
intfNode->IN_InterfaceID = InterfaceID;
InitializeListHead (&intfNode->IN_Head); // Insert it in
// list of interface lists
InsertTailList (cur, &intfNode->IN_Link);
}
return &intfNode->IN_Head;
}
#if RTM_USE_PROTOCOL_LISTS
// Finds list of routes that are associated with given iprotocol and returns
// pointer to its head
// Creates new list of none exists yet
PLIST_ENTRY
FindProtocolList (
PRTM_TABLE Table,
DWORD RoutingProtocol,
BOOL CreateNew
) {
PRTM_PROTOCOL_NODE protNode;
PLIST_ENTRY cur;
cur = Table->RT_ProtocolList.RSL_Head.Flink;
while (cur!=&Table->RT_ProtocolList.RSL_Head) {
protNode = CONTAINING_RECORD (cur, RTM_PROTOCOL_NODE, PN_Link);
if (RoutingProtocol<=protNode->PN_RoutingProtocol)
break;
cur = cur->Flink;
}
if ((cur==&Table->RT_ProtocolList.RSL_Head)
|| (RoutingProtocol!=protNode->PN_RoutingProtocol)) {
if (!CreateNew)
return NULL;
protNode = (PRTM_PROTOCOL_NODE)GlobalAlloc (
GMEM_FIXED,
sizeof (RTM_PROTOCOL_NODE));
if (protNode==NULL) {
#if DBG
// Report error in debuging builds
Trace2 (ANY,
"Can't allocate protocol node\n\tat line %ld of %s\n",
__LINE__, __FILE__);
#endif
return NULL;
}
protNode->PN_RoutingProtocol = RoutingProtocol;
InitializeListHead (&protNode->PN_Head);
InsertTailList (cur, &protNode->PN_Link);
}
return &protNode->PN_Head;
}
#endif
// Adds node to temporary net number list (to be later merged with master list)
// Both lists are ordered by net number.interface.protocol.next hop address
VOID
AddNetNumberListNode (
PRTM_TABLE Table,
PRTM_ROUTE_NODE newNode
) {
PLIST_ENTRY cur;
INT res;
cur = Table->RT_NetNumberTempList.RSL_Head.Flink;
while (cur!=&Table->RT_NetNumberTempList.RSL_Head) {
PRTM_ROUTE_NODE node = CONTAINING_RECORD (
cur,
RTM_ROUTE_NODE,
RN_Links[RTM_NET_NUMBER_LIST_LINK]
);
res = NetNumCmp (Table, &newNode->RN_Route, &node->RN_Route);
if ((res<0)
||((res==0)
&&((newNode->RN_Route.XX_PROTOCOL
< node->RN_Route.XX_PROTOCOL)
||((newNode->RN_Route.XX_PROTOCOL
==node->RN_Route.XX_PROTOCOL)
&&((newNode->RN_Route.XX_INTERFACE
< node->RN_Route.XX_INTERFACE)
||((newNode->RN_Route.XX_INTERFACE
== node->RN_Route.XX_INTERFACE)
&& (NextHopCmp (Table, &newNode->RN_Route,
&node->RN_Route)
< 0)))))))
break;
cur = cur->Flink;
}
InsertTailList (cur, &newNode->RN_Links[RTM_NET_NUMBER_LIST_LINK]);
}
// Adds node to expiration time queue. (Queue is ordered by expiration time)
// Return TRUE if new node is the first in the queue
BOOL
AddExpirationQueueNode (
PRTM_TABLE Table,
PRTM_ROUTE_NODE newNode
) {
PLIST_ENTRY cur;
BOOL res = TRUE;
// We'll travers the queue from the back, because normally
// new entries are added closer the end of the queue
cur = Table->RT_ExpirationQueue.RSL_Head.Blink;
while (cur!=&Table->RT_ExpirationQueue.RSL_Head) {
PRTM_ROUTE_NODE node = CONTAINING_RECORD (
cur,
RTM_ROUTE_NODE,
RN_Links[RTM_EXPIRATION_QUEUE_LINK]
);
if (IsLater(newNode->RN_ExpirationTime, node->RN_ExpirationTime)) {
res = FALSE;
break;
}
cur = cur->Blink;
}
InsertHeadList (cur, &newNode->RN_Links[RTM_EXPIRATION_QUEUE_LINK]);
return res;
}