mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
716 lines
16 KiB
716 lines
16 KiB
//=============================================================================
|
|
// 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;
|
|
}
|