windows-nt/Source/XPSP1/NT/net/rras/ipx/rip/ripmain.c

874 lines
16 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
ripmain.c
Abstract:
Contains the rcv and worker threads
Author:
Stefan Solomon 07/06/1995
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
DWORD
APIENTRY
RegisterProtocol(
IN OUT PMPR_ROUTING_CHARACTERISTICS pRoutingChar,
IN OUT PMPR_SERVICE_CHARACTERISTICS pServiceChar
);
DWORD
APIENTRY
StartProtocol(
IN HANDLE hMgrNotifyEvent,
IN PSUPPORT_FUNCTIONS pSupportFunctions,
IN PVOID pConfig
);
DWORD
APIENTRY
StopProtocol(
VOID
);
DWORD
APIENTRY
GetGlobalInfo(
IN OUT PVOID pConfig,
IN OUT PDWORD pdwSize
);
DWORD
APIENTRY
SetGlobalInfo(
IN PVOID pConfig
);
DWORD
APIENTRY
AddInterface(
IN PWCHAR pwszInterfaceName,
IN DWORD dwIndex,
IN NET_INTERFACE_TYPE dwIfType,
IN PVOID pConfig
);
DWORD
APIENTRY
DeleteInterface(
IN DWORD dwIndex
);
DWORD
APIENTRY
GetEventMessage(
OUT ROUTING_PROTOCOL_EVENTS *pEvent,
OUT MESSAGE *pResult
);
DWORD
APIENTRY
GetInterfaceConfigInfo(
IN DWORD dwIndex,
IN OUT PVOID pConfig,
IN OUT PDWORD pdwSize
);
DWORD
APIENTRY
SetInterfaceConfigInfo(
IN DWORD dwIndex,
IN PVOID pConfig
);
DWORD
APIENTRY
BindInterface(
IN DWORD dwIndex,
IN PVOID pBinding
);
DWORD
APIENTRY
UnbindInterface(
IN DWORD dwIndex
);
DWORD
APIENTRY
EnableInterface(
IN DWORD dwIndex
);
DWORD
APIENTRY
DisableInterface(
IN DWORD dwIndex
);
DWORD
APIENTRY
DoUpdateRoutes(
IN DWORD dwIndex
);
DWORD
APIENTRY
MibCreate(
IN DWORD dwInputSize,
IN PVOID pInputData
);
DWORD
APIENTRY
MibDelete(
IN DWORD dwInputSize,
IN PVOID pInputData
);
DWORD
APIENTRY
MibGet(
IN DWORD dwInputSize,
IN PVOID pInputData,
IN OUT PDWORD pdwOutputSize,
OUT PVOID pOutputData
);
DWORD
APIENTRY
MibSet(
IN DWORD dwInputSize,
IN PVOID pInputData
);
DWORD
APIENTRY
MibGetFirst(
IN DWORD dwInputSize,
IN PVOID pInputData,
IN OUT PDWORD pdwOutputSize,
OUT PVOID pOutputData
);
DWORD
APIENTRY
MibGetNext(
IN DWORD dwInputSize,
IN PVOID pInputData,
IN OUT PDWORD pdwOutputSize,
OUT PVOID pOutputData
);
// Router Manager Notification Event
HANDLE RM_Event;
TCHAR ModuleName[MAX_PATH+1];
VOID
WorkerThread(VOID);
DWORD
CreateWorkerThreadObjects(VOID);
VOID
DestroyWorkerThreadObjects(VOID);
VOID
ProcessDequeuedIoPacket(DWORD ErrorCode,
DWORD BytesTransferred,
LPOVERLAPPED Overlappedp);
BOOL WINAPI
IpxRipDllEntry(HINSTANCE hInstDll,
DWORD fdwReason,
LPVOID pReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
GetModuleFileName (hInstDll, ModuleName,
sizeof (ModuleName)/sizeof (ModuleName[0]));
SS_DBGINITIALIZE;
RipOperState = OPER_STATE_DOWN;
// Create the database lock
InitializeCriticalSection(&DbaseCritSec);
// Create the queues lock
InitializeCriticalSection(&QueuesCritSec);
// Create the RIP changed list lock
InitializeCriticalSection(&RipChangedListCritSec);
break;
case DLL_PROCESS_DETACH:
// delete the RIP changed list lock
DeleteCriticalSection(&RipChangedListCritSec);
// delete the database lock
DeleteCriticalSection(&DbaseCritSec);
// delete the queues lock
DeleteCriticalSection(&QueuesCritSec);
break;
default:
break;
}
return TRUE;
}
DWORD WINAPI
RegisterProtocol(
IN OUT PMPR_ROUTING_CHARACTERISTICS pRoutingChar,
IN OUT PMPR_SERVICE_CHARACTERISTICS pServiceChar
)
{
if(pRoutingChar->dwProtocolId != IPX_PROTOCOL_RIP)
{
return ERROR_NOT_SUPPORTED;
}
pServiceChar->fSupportedFunctionality = 0;
pRoutingChar->fSupportedFunctionality = (ROUTING | DEMAND_UPDATE_ROUTES);
pRoutingChar->pfnStartProtocol = StartProtocol;
pRoutingChar->pfnStopProtocol = StopProtocol;
pRoutingChar->pfnAddInterface = AddInterface;
pRoutingChar->pfnDeleteInterface = DeleteInterface;
pRoutingChar->pfnGetEventMessage = GetEventMessage;
pRoutingChar->pfnGetInterfaceInfo = GetInterfaceConfigInfo;
pRoutingChar->pfnSetInterfaceInfo = SetInterfaceConfigInfo;
pRoutingChar->pfnBindInterface = BindInterface;
pRoutingChar->pfnUnbindInterface = UnbindInterface;
pRoutingChar->pfnEnableInterface = EnableInterface;
pRoutingChar->pfnDisableInterface = DisableInterface;
pRoutingChar->pfnGetGlobalInfo = GetGlobalInfo;
pRoutingChar->pfnSetGlobalInfo = SetGlobalInfo;
pRoutingChar->pfnMibCreateEntry = MibCreate;
pRoutingChar->pfnMibDeleteEntry = MibDelete;
pRoutingChar->pfnMibGetEntry = MibGet;
pRoutingChar->pfnMibSetEntry = MibSet;
pRoutingChar->pfnMibGetFirstEntry = MibGetFirst;
pRoutingChar->pfnMibGetNextEntry = MibGetNext;
pRoutingChar->pfnUpdateRoutes = DoUpdateRoutes;
return NO_ERROR;
}
DWORD WINAPI
StartProtocol(IN HANDLE NotificationEvent,
IN PSUPPORT_FUNCTIONS SupportFunctions,
IN PVOID GlobalInfo)
{
#define ripGlobalInfo ((PRIP_GLOBAL_INFO)GlobalInfo)
DWORD threadid, i;
HANDLE ThreadHandle;
RipEventLogMask = ripGlobalInfo->EventLogMask;
StartTracing();
Trace(INIT_TRACE, "StartProtocol: Entered\n");
ACQUIRE_DATABASE_LOCK;
ACQUIRE_QUEUES_LOCK;
RipOperState = OPER_STATE_STARTING;
GetIpxRipRegistryParameters();
RM_Event = NotificationEvent;
//init the interfaces database
InitIfDbase();
//
// init all the queues
//
// InitializeListHead(&WorkersQueue);
InitializeListHead(&TimerQueue);
InitializeListHead(&RepostRcvPacketsQueue);
InitializeListHead(&RipMessageQueue);
// create the workers work items heap
if(CreateWorkItemsManager() != NO_ERROR) {
goto ErrorExit;
}
// open the RIP socket for I/O
if(OpenRipSocket() != NO_ERROR) {
Trace(INIT_TRACE, "Cannot open RIP socket\n");
goto ErrorExit;
}
if(! BindIoCompletionCallback(RipSocketHandle,
ProcessDequeuedIoPacket, 0)) {
Trace(INIT_TRACE, "Cannot associate IO Completion Port\n");
goto ErrorExit;
}
// create synchronization objects for the rip threads
if(CreateWorkerThreadObjects() != NO_ERROR) {
Trace(INIT_TRACE, "Cannot create synchronization objects\n");
goto ErrorExit;
}
// Open RTM for RIP
if(OpenRTM()) {
Trace(INIT_TRACE, "Cannot open RTM\n");
goto ErrorExit;
}
// create the Worker thread
if ((ThreadHandle = CreateThread(
(LPSECURITY_ATTRIBUTES) NULL,
0,
(LPTHREAD_START_ROUTINE) WorkerThread,
NULL,
0,
&threadid)) == NULL) {
// !!! log error cannot create the worker thread !!!
goto ErrorExit;
}
else
CloseHandle (ThreadHandle);
RipOperState = OPER_STATE_UP;
RELEASE_QUEUES_LOCK;
RELEASE_DATABASE_LOCK;
CreateStartChangesBcastWi();
Trace(INIT_TRACE, "Started successfully\n");
return NO_ERROR;
ErrorExit:
RELEASE_QUEUES_LOCK;
RELEASE_DATABASE_LOCK;
return ERROR_CAN_NOT_COMPLETE;
#undef ripGlobalInfo
}
DWORD
WINAPI
StopProtocol(VOID)
{
PWORK_ITEM wip;
Trace(INIT_TRACE, "StopProtocol: Entered\n");
ACQUIRE_DATABASE_LOCK;
if(RipOperState != OPER_STATE_UP) {
SS_ASSERT(FALSE);
goto ErrorExit;
}
RipOperState = OPER_STATE_STOPPING;
// send interfaces shutdown work item to the workers
if((wip = AllocateWorkItem(SHUTDOWN_INTERFACES_TYPE)) == NULL) {
goto ErrorExit;
}
wip->WorkItemSpecific.WIS_ShutdownInterfaces.ShutdownState = SHUTDOWN_START;
RtlQueueWorkItem(ProcessWorkItem, wip, 0);
RELEASE_DATABASE_LOCK;
return NO_ERROR;
ErrorExit:
RELEASE_DATABASE_LOCK;
return ERROR_CAN_NOT_COMPLETE;
}
VOID
WorkerThread(VOID)
{
DWORD rc;
DWORD signaled_event, delay;
ULONG dueTime = GetTickCount() + MAXULONG/2;
PWORK_ITEM wip;
PLIST_ENTRY lep;
HANDLE hModuleReference;
hModuleReference = LoadLibrary (ModuleName);
StartReceiver();
while(TRUE)
{
delay = dueTime - GetTickCount();
if(delay < MAXULONG/2) {
// dueTime is later then present time
while((rc = WaitForMultipleObjects(
MAX_WORKER_THREAD_OBJECTS,
WorkerThreadObjects,
FALSE, // wait any
delay // timeout
)) == WAIT_IO_COMPLETION);
}
else
{
// dueTime already happened
rc = WAIT_TIMEOUT;
}
if(rc == WAIT_TIMEOUT) {
dueTime = ProcessTimerQueue();
}
else
{
signaled_event = rc - WAIT_OBJECT_0;
if(signaled_event < MAX_WORKER_THREAD_OBJECTS) {
switch(signaled_event) {
case TIMER_EVENT:
dueTime = ProcessTimerQueue();
break;
case REPOST_RCV_PACKETS_EVENT:
RepostRcvPackets();
break;
// case WORKERS_QUEUE_EVENT:
// dequeue only one item from the work items queue
// ACQUIRE_QUEUES_LOCK;
// while(!IsListEmpty(&WorkersQueue)) {
// lep = RemoveHeadList(&WorkersQueue);
// wip = CONTAINING_RECORD(lep, WORK_ITEM, Linkage);
// RELEASE_QUEUES_LOCK;
// Queue the work item for processing by the
// worker threads
// RtlQueueWorkItem(ProcessWorkItem,
// wip,
// WT_EXECUTEINIOTHREAD); // never dieing workers so we can do send submits
// and the thread won't die before send completes
// ACQUIRE_QUEUES_LOCK;
// }
// RELEASE_QUEUES_LOCK;
// break;
case RTM_EVENT:
ProcessRTMChanges();
break;
case RIP_CHANGES_EVENT:
ProcessRIPChanges();
break;
case TERMINATE_WORKER_EVENT:
// stop the StartChangesBcast work item
DestroyStartChangesBcastWi = TRUE;
// close the rip socket
CloseRipSocket();
FlushTimerQueue();
CloseRTM();
// wait until no more work items
while(WorkItemsCount != 0) {
Trace(INIT_TRACE, "Terminating: Waiting for work items to be freed: %d outstanding ...\n",
WorkItemsCount);
Sleep(1000);
}
// destroy worker thread objects
DestroyWorkerThreadObjects();
// destroy workers heap
DestroyWorkItemsManager();
// post stop complete message
PostEventMessage(ROUTER_STOPPED, NULL);
Trace(INIT_TRACE, "Terminating: Stop completed and STOP Event Message posted\n");
FreeLibraryAndExitThread(hModuleReference, 0);
break;
default:
break;
}
}
}
}
}
// table of handlers for work items which keep a reference to the if CB
typedef VOID (* IF_WORK_ITEM_HANDLER)(PWORK_ITEM wip);
IF_WORK_ITEM_HANDLER IfWorkItemHandler[] = {
IfPeriodicBcast,
IfCompleteGenResponse,
IfChangeBcast,
IfCheckUpdateStatus,
IfPeriodicGenRequest
};
#define MAX_IF_WORK_ITEM_HANDLERS sizeof(IfWorkItemHandler)/sizeof(IF_WORK_ITEM_HANDLER)
VOID
ProcessWorkItem(PWORK_ITEM wip)
{
PLIST_ENTRY lep;
PICB icbp;
switch(wip->Type) {
case RECEIVE_PACKET_TYPE:
// this work item references the interface via the adapter index
ACQUIRE_DATABASE_LOCK;
if(RipOperState != OPER_STATE_UP) {
RELEASE_DATABASE_LOCK;
}
else
{
if((icbp = GetInterfaceByAdapterIndex(wip->AdapterIndex)) != NULL) {
wip->icbp = icbp;
ACQUIRE_IF_LOCK(icbp);
RELEASE_DATABASE_LOCK;
ProcessReceivedPacket(wip);
RELEASE_IF_LOCK(icbp);
}
else
{
RELEASE_DATABASE_LOCK;
}
}
// queue the receive packet back to recv thread for reposting
EnqueueRcvPacketToRepostQueue(wip);
break;
case START_CHANGES_BCAST_TYPE:
ACQUIRE_DATABASE_LOCK;
StartChangesBcast(wip);
RELEASE_DATABASE_LOCK;
break;
case SHUTDOWN_INTERFACES_TYPE:
ACQUIRE_DATABASE_LOCK;
ShutdownInterfaces(wip);
RELEASE_DATABASE_LOCK;
break;
case DEBUG_TYPE:
FreeWorkItem(wip);
break;
default:
// all these work items reference the interface via an if CB pointer
icbp = wip->icbp;
ACQUIRE_IF_LOCK(icbp);
(*IfWorkItemHandler[wip->Type])(wip);
if(icbp->Discarded) {
RELEASE_IF_LOCK(icbp);
ACQUIRE_DATABASE_LOCK;
ACQUIRE_IF_LOCK(icbp);
if(--icbp->RefCount == 0) {
// remove the if CB from the discarded queue and free it
RemoveEntryList(&icbp->IfListLinkage);
// free the interface CB
Trace(INIT_TRACE, "ProcessWorkItem: Free DISCARDED if CB for if # %d\n", icbp->InterfaceIndex);
DestroyInterfaceCB(icbp);
}
else
{
RELEASE_IF_LOCK(icbp);
}
RELEASE_DATABASE_LOCK;
}
else
{
icbp->RefCount--;
RELEASE_IF_LOCK(icbp);
}
}
}
DWORD
WINAPI
GetEventMessage(ROUTING_PROTOCOL_EVENTS *Event,
PMESSAGE Result)
{
PRIP_MESSAGE emp;
PLIST_ENTRY lep;
Trace(INIT_TRACE, "GetEventMessage: Entered\n");
ACQUIRE_DATABASE_LOCK;
if((RipOperState == OPER_STATE_DOWN) ||
(RipOperState == OPER_STATE_STARTING)) {
RELEASE_DATABASE_LOCK;
return ERROR_CAN_NOT_COMPLETE;
}
ACQUIRE_QUEUES_LOCK;
if(IsListEmpty(&RipMessageQueue)) {
RELEASE_QUEUES_LOCK;
RELEASE_DATABASE_LOCK;
return ERROR_NO_MORE_ITEMS;
}
lep = RemoveHeadList(&RipMessageQueue);
emp = CONTAINING_RECORD(lep, RIP_MESSAGE, Linkage);
*Event = emp->Event;
if(Result != NULL) {
*Result = emp->Result;
}
if(emp->Event == ROUTER_STOPPED) {
RipOperState = OPER_STATE_DOWN;
StopTracing();
}
GlobalFree(emp);
RELEASE_QUEUES_LOCK;
RELEASE_DATABASE_LOCK;
return NO_ERROR;
}
VOID
PostEventMessage(ROUTING_PROTOCOL_EVENTS Event,
PMESSAGE Result)
{
PRIP_MESSAGE emp;
if((emp = GlobalAlloc(GPTR, sizeof(RIP_MESSAGE))) == NULL) {
return;
}
emp->Event = Event;
if(Result != NULL) {
emp->Result = *Result;
}
ACQUIRE_QUEUES_LOCK;
InsertTailList(&RipMessageQueue, &emp->Linkage);
RELEASE_QUEUES_LOCK;
SetEvent(RM_Event);
}
DWORD
CreateWorkerThreadObjects(VOID)
{
int i;
for(i=0; i<MAX_WORKER_THREAD_OBJECTS; i++) {
if((WorkerThreadObjects[i] = CreateEvent(NULL,
FALSE,
FALSE,
NULL)) == NULL) {
return ERROR_CAN_NOT_COMPLETE;
}
}
return NO_ERROR;
}
VOID
DestroyWorkerThreadObjects(VOID)
{
int i;
for(i=0; i<MAX_WORKER_THREAD_OBJECTS; i++) {
CloseHandle(WorkerThreadObjects[i]);
}
}
DWORD WINAPI
SetGlobalInfo(PVOID GlobalInfo)
{
#define ripGlobalInfo ((PRIP_GLOBAL_INFO)GlobalInfo)
ACQUIRE_DATABASE_LOCK;
if(RipOperState != OPER_STATE_UP) {
RELEASE_DATABASE_LOCK;
return ERROR_CAN_NOT_COMPLETE;
}
RipEventLogMask = ripGlobalInfo->EventLogMask;
RELEASE_DATABASE_LOCK;
return NO_ERROR;
#undef ripGlobalInfo
}
DWORD WINAPI
GetGlobalInfo(
IN PVOID GlobalInfo,
IN OUT PULONG GlobalInfoSize
)
{
ACQUIRE_DATABASE_LOCK;
if(RipOperState != OPER_STATE_UP) {
RELEASE_DATABASE_LOCK;
return ERROR_CAN_NOT_COMPLETE;
}
if ((*GlobalInfoSize>=sizeof (RIP_GLOBAL_INFO))
&& (GlobalInfo!=NULL)) {
#define ripGlobalInfo ((PRIP_GLOBAL_INFO)GlobalInfo)
ripGlobalInfo->EventLogMask = RipEventLogMask;
#undef ripGlobalInfo
}
*GlobalInfoSize = sizeof (RIP_GLOBAL_INFO);
RELEASE_DATABASE_LOCK;
return NO_ERROR;
}
VOID
ProcessDequeuedIoPacket(DWORD ErrorCode,
DWORD BytesTransferred,
LPOVERLAPPED Overlappedp)
{
PWORK_ITEM wip;
wip = CONTAINING_RECORD(Overlappedp, WORK_ITEM, Overlapped);
wip->IoCompletionStatus = (DWORD)Overlappedp->Internal;
switch(wip->Type) {
case RECEIVE_PACKET_TYPE:
ReceiveComplete(wip);
break;
default:
SendComplete(wip);
break;
}
}