|
|
//=============================================================================
// 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; }
|