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

717 lines
16 KiB
C

//=============================================================================
// Copyright (c) 1998 Microsoft Corporation
// File Name: main.c
// Abstract:
//
// Author: K.S.Lokesh (lokeshs@) 1-1-98
//=============================================================================
#include "pchdvmrp.h"
#pragma hdrstop
GLOBALS Globals;
GLOBALS1 Globals1;
GLOBAL_CONFIG GlobalConfig;
//----------------------------------------------------------------------------
// _DLLMAIN
//
// Called when the dll is being loaded/unloaded
//----------------------------------------------------------------------------
BOOL
WINAPI
DLLMAIN (
HINSTANCE Module,
DWORD Reason,
LPVOID Reserved
)
{
BOOL NoError;
switch (Reason) {
case DLL_PROCESS_ATTACH:
{
DisableThreadLibraryCalls(Module);
// create and initialize global data
NoError = DllStartup();
break;
}
case DLL_PROCESS_DETACH:
{
// free global data
NoError = DllCleanup();
break;
}
default:
{
NoError = TRUE;
break;
}
}
return NoError;
} //end _DLLMAIN
//----------------------------------------------------------------------------
// _DllStartup
//
// Initializes Globals1 structure
//----------------------------------------------------------------------------
BOOL
DllStartup(
)
{
BEGIN_BREAKOUT_BLOCK1 {
//
// create a private heap for dvmrp
//
Globals1.Heap = HeapCreate(0, 0, 0);
if (Globals1.Heap == NULL) {
GOTO_END_BLOCK1;
}
try {
// initialize the Router Manager event queue
CREATE_LOCKED_LIST(&Globals1.RtmQueue);
// create WorkItem CS
InitializeCriticalSection(&Globals1.WorkItemCS);
}
except (EXCEPTION_EXECUTE_HANDLER) {
GOTO_END_BLOCK1;
}
// if reached here, then return no error.
return TRUE;
} END_BREAKOUT_BLOCK1;
// there was some error. Cleanup before returning error.
DllCleanup();
return FALSE;
}
//----------------------------------------------------------------------------
// _DllCleanup
//
// This function is called when the dll is being unloaded. It frees any global
// structures set in _DllStartup
//----------------------------------------------------------------------------
BOOL
DllCleanup(
)
{
// destroy the router manager event queue
if (LOCKED_LIST_CREATED(&Globals1.RtmQueue)) {
DELETE_LOCKED_LIST(&Globals1.RtmQueue, EVENT_QUEUE_ENTRY, Link);
}
// delete WorkItem CS
DeleteCriticalSection(&Globals1.WorkItemCS);
// destroy private heap
if (Globals1.Heap != NULL) {
HeapDestroy(Globals1.Heap);
}
return TRUE;
}
//----------------------------------------------------------------------------
// _RegisterProtocol
//
// This function is called after the Dll is loaded, and before StartProtocol
// is called. It checks to ensure that the correct version is being configured
//
// No deinitialization is required for this function call.
//----------------------------------------------------------------------------
DWORD
WINAPI
RegisterProtocol(
IN OUT PMPR_ROUTING_CHARACTERISTICS pRoutingChar,
IN OUT PMPR_SERVICE_CHARACTERISTICS pServiceChar
)
{
DWORD Error = NO_ERROR;
//
// initialize tracing and error logging
//
INITIALIZE_TRACING_LOGGING();
Trace0(ENTER, "RegisterProtocol()");
//
// The Router Manager should be calling us to register our protocol.
// The Router Manager must be atleast the version we are compiled with
// The Router Manager must support routing and multicast.
//
#ifdef MS_IP_DVMRP
if(pRoutingChar->dwProtocolId != MS_IP_DVMRP)
return ERROR_NOT_SUPPORTED;
#endif
if(pRoutingChar->dwVersion < MS_ROUTER_VERSION)
return ERROR_NOT_SUPPORTED;
if(!(pRoutingChar->fSupportedFunctionality & RF_ROUTING)
|| !(pRoutingChar->fSupportedFunctionality & RF_MULTICAST) )
return ERROR_NOT_SUPPORTED;
//
// We setup our characteristics and function pointers
// All pointers should be set to NULL by the caller.
//
pServiceChar->fSupportedFunctionality = 0;
pRoutingChar->fSupportedFunctionality = RF_MULTICAST | RF_ROUTING;
pRoutingChar->pfnStartProtocol = StartProtocol;
pRoutingChar->pfnStartComplete = StartComplete;
pRoutingChar->pfnStopProtocol = StopProtocol;
pRoutingChar->pfnAddInterface = AddInterface;
pRoutingChar->pfnDeleteInterface = DeleteInterface;
pRoutingChar->pfnInterfaceStatus = InterfaceStatus;
pRoutingChar->pfnGetEventMessage = GetEventMessage;
pRoutingChar->pfnGetInterfaceInfo = GetInterfaceConfigInfo;
pRoutingChar->pfnSetInterfaceInfo = SetInterfaceConfigInfo;
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 = NULL;
pRoutingChar->pfnConnectClient = NULL;
pRoutingChar->pfnDisconnectClient = NULL;
pRoutingChar->pfnGetNeighbors = NULL;
pRoutingChar->pfnGetMfeStatus = NULL;
pRoutingChar->pfnQueryPower = NULL;
pRoutingChar->pfnSetPower = NULL;
Trace0(LEAVE, "Leaving RegisterProtocol():\n");
return NO_ERROR;
} //end _RegisterProtocol
//----------------------------------------------------------------------------
// _StartProtocol
//
// Initializes global structures
//----------------------------------------------------------------------------
DWORD
WINAPI
StartProtocol(
IN HANDLE RtmNotifyEvent, //notify Rtm when dvmrp stopped
IN PSUPPORT_FUNCTIONS pSupportFunctions, //NULL
IN PVOID pDvmrpGlobalConfig,
IN ULONG StructureVersion,
IN ULONG StructureSize,
IN ULONG StructureCount
)
{
DWORD Error=NO_ERROR;
BOOL IsError;
//
// initialize tracing and error logging if StartProtocol called after
// StopProtocol
//
INITIALIZE_TRACING_LOGGING();
//
// acquire global lock
//
ACQUIRE_WORKITEM_LOCK("_StartProtocol");
//
// make certain dvmrp is not already running (StartProtocol might get
// called before StopProtocol completes)
//
if (Globals1.RunningStatus != DVMRP_STATUS_STOPPED) {
Trace0(ERR,
"Error: _StartProtocol called when dvmrp is already running");
Logwarn0(DVMRP_ALREADY_STARTED, NO_ERROR);
RELEASE_WORKITEM_LOCK("_StartProtocol");
return ERROR_CAN_NOT_COMPLETE;
}
IsError = TRUE;
BEGIN_BREAKOUT_BLOCK1 {
// save the Router Manager notification event
Globals.RtmNotifyEvent = RtmNotifyEvent;
//
// set the Global Config (after validating it)
//
if(pDvmrpGlobalConfig == NULL) {
Trace0(ERR, "_StartProtocol: Called with NULL global config");
Error = ERROR_INVALID_PARAMETER;
GOTO_END_BLOCK1;
}
{
PDVMRP_GLOBAL_CONFIG pGlobalConfig;
pGlobalConfig = (PDVMRP_GLOBAL_CONFIG) pDvmrpGlobalConfig;
// Check the global config, and correct if values are not correct.
// Not a fatal error.
if (! ValidateGlobalConfig(pGlobalConfig, StructureSize)) {
Error = ERROR_INVALID_PARAMETER;
GOTO_END_BLOCK1;
}
memcpy(&GlobalConfig, pGlobalConfig, sizeof(GlobalConfig));
}
//
// Initialize Winsock version 2.0
//
{
WSADATA WsaData;
Error = (DWORD)WSAStartup(MAKEWORD(2,0), &WsaData);
if ( (Error!=0) || (LOBYTE(WsaData.wVersion)<2) ) {
Trace1(ERR,
"StartProtocol:Error %d:could not initialize winsock v-2",
Error);
Logerr0(WSASTARTUP_FAILED, Error);
if (LOBYTE(WsaData.wVersion)<2)
WSACleanup();
GOTO_END_BLOCK1;
}
}
//
// Initialise the Dynamic CS and ReadWrite locks main struct
//
Error = InitializeDynamicLocks(&Globals.DynamicCSStore);
if (Error!=NO_ERROR) {
GOTO_END_BLOCK1;
}
Error = InitializeDynamicLocks(&Globals.DynamicRWLStore);
if (Error!=NO_ERROR) {
GOTO_END_BLOCK1;
}
//
// Initialize Interface Table
//
InitializeIfTable();
IsError = FALSE;
} END_BREAKOUT_BLOCK1;
if (IsError) {
Trace1(START, "Dvmrp could not be started: %d", Error);
ProtocolCleanup();
}
else {
Trace0(START, "Dvmrp started successfully");
Loginfo0(DVMRP_STARTED, NO_ERROR);
}
RELEASE_WORKITEM_LOCK("_StartProtocol()");
Trace1(LEAVE, "Leaving StartProtocol():%d\n", Error);
return Error;
} //end _StartProtocol
//----------------------------------------------------------------------------
// _ValidateGlobalConfig
//----------------------------------------------------------------------------
DWORD
ValidateGlobalConfig(
PDVMRP_GLOBAL_CONFIG pGlobalConfig,
DWORD StructureSize
)
{
//
// check structure size
//
if (StructureSize != sizeof(DVMRP_GLOBAL_CONFIG)) {
Trace1(ERR, "Dvmrp global config size too small.\n", StructureSize);
return ERROR_INVALID_DATA;
}
DebugPrintGlobalConfig(pGlobalConfig);
//
// check version
//
if (pGlobalConfig->MajorVersion != 3) {
Trace1(ERR, "Invalid version:%d in global config.",
pGlobalConfig->MajorVersion);
Logerr1(INVALID_VERSION, "%d", pGlobalConfig->MajorVersion,
ERROR_INVALID_DATA);
return ERROR_INVALID_DATA;
}
// check loggingLevel
switch (pGlobalConfig->LoggingLevel) {
case DVMRP_LOGGING_NONE :
case DVMRP_LOGGING_ERROR :
case DVMRP_LOGGING_WARN :
case DVMRP_LOGGING_INFO :
break;
default :
{
Trace1(ERR, "Invalid value:%d for LoggingLevel in global config.",
pGlobalConfig->LoggingLevel);
return ERROR_INVALID_DATA;
}
}
//
// check RouteReportInterval (min 10 sec)
//
if (pGlobalConfig->RouteReportInterval != DVMRP_ROUTE_REPORT_INTERVAL) {
Trace2(CONFIG,
"RouteReportInterval being set to %d. Suggested value:%d",
pGlobalConfig->RouteReportInterval, DVMRP_ROUTE_REPORT_INTERVAL);
}
if (pGlobalConfig->RouteReportInterval < 10000) {
Trace2(ERR,
"RouteReportInterval has very low value:%d, suggested:%d",
pGlobalConfig->RouteReportInterval, DVMRP_ROUTE_REPORT_INTERVAL);
return ERROR_INVALID_DATA;
}
//
// check RouteExpirationInterval (min 40)
//
if (pGlobalConfig->RouteExpirationInterval
!= DVMRP_ROUTE_EXPIRATION_INTERVAL
) {
Trace2(CONFIG,
"RouteExpirationInterval being set to %d. Suggested value:%d",
pGlobalConfig->RouteExpirationInterval,
DVMRP_ROUTE_EXPIRATION_INTERVAL);
}
if (pGlobalConfig->RouteExpirationInterval < (2*10 + 20)) {
Trace2(ERR,
"RouteExpirationInterval has very low value:%d, suggested:%d",
pGlobalConfig->RouteExpirationInterval,
DVMRP_ROUTE_EXPIRATION_INTERVAL);
return ERROR_INVALID_DATA;
}
//
// check RouteHolddownInterval
//
if (pGlobalConfig->RouteHolddownInterval != DVMRP_ROUTE_HOLDDOWN_INTERVAL
) {
Trace2(CONFIG,
"RouteHolddownInterval being set to %d. Suggested value:%d",
pGlobalConfig->RouteHolddownInterval,
DVMRP_ROUTE_HOLDDOWN_INTERVAL);
}
//
// check PruneLifetimeInterval
//
if (pGlobalConfig->PruneLifetimeInterval != DVMRP_PRUNE_LIFETIME_INTERVAL
) {
Trace2(CONFIG,
"PruneLifetimeInterval being set to %d. Suggested value:%d\n",
pGlobalConfig->PruneLifetimeInterval,
DVMRP_PRUNE_LIFETIME_INTERVAL);
}
if (pGlobalConfig->PruneLifetimeInterval < 600000) {
Trace2(ERR,
"PruneLifeTime has very low value:%d, suggested:%d",
pGlobalConfig->PruneLifetimeInterval,
DVMRP_PRUNE_LIFETIME_INTERVAL);
return ERROR_INVALID_DATA;
}
return NO_ERROR;
} //end _ValidateGlobalConfig
DWORD
APIENTRY
StartComplete(
VOID
)
{
return NO_ERROR;
}
/*-----------------------------------------------------------------------------
Functions to display the MibTable on the TraceWindow periodically
Locks:
Arguments:
Return Values:
-----------------------------------------------------------------------------*/
DWORD
APIENTRY
StopProtocol(
VOID
)
{
return NO_ERROR;
}
VOID
WF_StopProtocolComplete(
)
{
//
// deregister tracing/error logging if they were
// registered in RegisterProtocol/StartProtocol call
//
DEINITIALIZE_TRACING_LOGGING();
return;
}
VOID
ProtocolCleanup(
)
{
if (Globals.ActivityEvent) {
CloseHandle(Globals.ActivityEvent);
}
ZeroMemory(&Globals, sizeof(Globals));
ZeroMemory(&GlobalConfig, sizeof(GlobalConfig));
}
DWORD
WINAPI
GetGlobalInfo(
IN OUT PVOID pvConfig,
IN OUT PDWORD pdwSize,
IN OUT PULONG pulStructureVersion,
IN OUT PULONG pulStructureSize,
IN OUT PULONG pulStructureCount
)
{
DWORD Error = NO_ERROR;
return Error;
}
DWORD
WINAPI
SetGlobalInfo(
IN PVOID pvConfig,
IN ULONG ulStructureVersion,
IN ULONG ulStructureSize,
IN ULONG ulStructureCount
)
{
DWORD Error = NO_ERROR;
return Error;
}
DWORD
APIENTRY
GetEventMessage(
OUT ROUTING_PROTOCOL_EVENTS *pEvent,
OUT PMESSAGE pResult
)
{
DWORD Error;
//
// Note: _GetEventMessage() does not use the
// EnterIgmpApi()/LeaveIgmpApi() mechanism,
// since it may be called after Igmp has stopped, when the
// Router Manager is retrieving the ROUTER_STOPPED message
//
Trace2(ENTER, "entering _GetEventMessage: pEvent(%08x) pResult(%08x)",
pEvent, pResult);
ACQUIRE_LIST_LOCK(&Globals1.RtmQueue, "RtmQueue", "_GetEventMessage");
Error = DequeueEvent(&Globals1.RtmQueue, pEvent, pResult);
RELEASE_LIST_LOCK(&Globals1.RtmQueue, "RtmQueue", "_GetEventMessage");
Trace1(LEAVE, "leaving _GetEventMessage: %d\n", Error);
return Error;
}
DWORD
DequeueEvent(
PLOCKED_LIST pQueue,
ROUTING_PROTOCOL_EVENTS *pEventType,
PMESSAGE pMsg
)
{
PLIST_ENTRY pHead, pLe;
PEVENT_QUEUE_ENTRY pEqe;
pHead = &pQueue->Link;
if (IsListEmpty(pHead)) {
return ERROR_NO_MORE_ITEMS;
}
pLe = RemoveHeadList(pHead);
pEqe = CONTAINING_RECORD(pLe, EVENT_QUEUE_ENTRY, Link);
*pEventType = pEqe->EventType;
*pMsg = pEqe->Msg;
DVMRP_FREE(pEqe);
return NO_ERROR;
}