|
|
//============================================================================
// Copyright (c) 1995, Microsoft Corporation
//
// File: api.c
//
// History:
// Abolade Gbadegesin Aug-8-1995 Created.
//
// router manager API implementations
//============================================================================
#include "pchrip.h"
#pragma hdrstop
//
// Definition of sole global variable for IPRIP
//
IPRIP_GLOBALS ig;
//----------------------------------------------------------------------------
// Function: DLLMAIN
//
// This is the DLL entrypoint handler. It calls DllStartup
// to initialize locking and event queue and to create IPRIP's heap,
// and calls DllCleanup to delete the lock and event queue.
//----------------------------------------------------------------------------
BOOL WINAPI DLLMAIN( HINSTANCE hInstance, DWORD dwReason, PVOID pUnused ) {
BOOL bErr;
bErr = FALSE;
switch(dwReason) { case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hInstance);
bErr = DllStartup(); break;
case DLL_PROCESS_DETACH:
bErr = DllCleanup(); break;
default:
bErr = TRUE; break; }
return bErr; }
//----------------------------------------------------------------------------
// Function: DllStartup
//
// Initializes IPRIP's function lock, event queue, and global heap.
//----------------------------------------------------------------------------
BOOL DllStartup( ) {
BOOL bErr; DWORD dwErr;
bErr = TRUE;
do { // error breakout loop
ZeroMemory(&ig, sizeof(IPRIP_GLOBALS));
//
// create the global critical section and set IPRIP's status
//
try { InitializeCriticalSection(&ig.IG_CS); } except (EXCEPTION_EXECUTE_HANDLER) {
bErr = FALSE; break; }
ig.IG_Status = IPRIP_STATUS_STOPPED;
//
// attempt to create a private heap for IPRIP
//
ig.IG_IpripGlobalHeap = HeapCreate(0, 0, 0);
if (ig.IG_IpripGlobalHeap == NULL) {
bErr = FALSE; break; }
//
// create the router manager message queue
//
ig.IG_EventQueue = RIP_ALLOC(sizeof(LOCKED_LIST));
if (ig.IG_EventQueue == NULL) {
bErr = FALSE; break; }
//
// initialize the Router Manager event queue
//
try { CREATE_LOCKED_LIST(ig.IG_EventQueue); } except (EXCEPTION_EXECUTE_HANDLER) {
bErr = FALSE; break; }
} while(FALSE);
return bErr; }
//----------------------------------------------------------------------------
// Function: DllCleanup
//
// Deletes the global heap, event queue, and function lock.
//----------------------------------------------------------------------------
BOOL DllCleanup( ) {
BOOL bErr;
bErr = TRUE;
do { // error breakout loop
//
// destroy the router manager event queue
//
if (ig.IG_EventQueue != NULL) {
if (LOCKED_LIST_CREATED(ig.IG_EventQueue)) {
DELETE_LOCKED_LIST( ig.IG_EventQueue, EVENT_QUEUE_ENTRY, EQE_Link ); }
RIP_FREE(ig.IG_EventQueue); }
if (ig.IG_IpripGlobalHeap != NULL) { HeapDestroy(ig.IG_IpripGlobalHeap); }
//
// delete the global critical section
//
DeleteCriticalSection(&ig.IG_CS);
RouterLogDeregister(ig.IG_LogHandle); if (ig.IG_TraceID != INVALID_TRACEID) { TraceDeregister(ig.IG_TraceID); } } while(FALSE);
return bErr; }
//----------------------------------------------------------------------------
// Function: ProtocolStartup
//
// This is called by StartProtocol. Initializes data structures,
// creates IPRIP threads.
//----------------------------------------------------------------------------
DWORD ProtocolStartup( HANDLE hEventEvent, PVOID pConfig ) {
WSADATA wd; HANDLE hThread; BOOL bCleanupWinsock; DWORD dwErr, dwSize, dwThread; PIPRIP_GLOBAL_CONFIG pgcsrc, pgcdst;
EnterCriticalSection(&ig.IG_CS);
ig.IG_TraceID = TraceRegister("IPRIP2"); ig.IG_LogHandle = RouterLogRegister("IPRIP2");
//
// make certain RIP is not already running
//
if (ig.IG_Status != IPRIP_STATUS_STOPPED) {
TRACE0(START, "ERROR: StartProtocol called with IPRIP already running"); LOGWARN0(IPRIP_ALREADY_STARTED, NO_ERROR);
LeaveCriticalSection(&ig.IG_CS); return ERROR_CAN_NOT_COMPLETE; }
bCleanupWinsock = FALSE;
do { // break-out construct
TRACE0(ENTER, "IPRIP is starting up");
//
// save the Router Manager notification event
//
ig.IG_EventEvent = hEventEvent;
//
// find the size of the global configuration passed in
//
pgcsrc = (PIPRIP_GLOBAL_CONFIG)pConfig;
dwSize = IPRIP_GLOBAL_CONFIG_SIZE(pgcsrc);
//
// allocate a block to hold the configuration
//
ig.IG_Config = pgcdst = RIP_ALLOC(dwSize);
if (pgcdst == NULL) {
dwErr = GetLastError(); TRACE2( ANY, "error %d allocating %d bytes for global config", dwErr, dwSize ); LOGERR0(HEAP_ALLOC_FAILED, dwErr);
break; }
//
// copy the supplied configuration
//
CopyMemory(pgcdst, pgcsrc, dwSize); ig.IG_LogLevel = pgcsrc->GC_LoggingLevel;
//
// attempt to start Winsock
//
dwErr = (DWORD)WSAStartup(MAKEWORD(1,1), &wd);
if (dwErr != 0) {
TRACE1(START, "error %d starting Windows Sockets.", dwErr); LOGERR0(WSASTARTUP_FAILED, dwErr);
break; }
bCleanupWinsock = TRUE;
//
// attempt to create synchronization object for global config
//
dwErr = CreateReadWriteLock(&ig.IG_RWL); if (dwErr != NO_ERROR) {
TRACE1(START, "error %d creating read-write lock", dwErr); LOGERR0(CREATE_RWL_FAILED, dwErr);
break; }
//
// register a timer queue with Ntdll timer thread
//
ig.IG_TimerQueueHandle = CreateTimerQueue();
if ( !ig.IG_TimerQueueHandle) {
dwErr = GetLastError(); TRACE1(START, "error %d registering time queue with NtdllTimer thread", dwErr ); LOGERR0(CREATE_TIMER_QUEUE_FAILED, dwErr);
break; }
//
// allocate space for an interface table
//
ig.IG_IfTable = RIP_ALLOC(sizeof(IF_TABLE)); if (ig.IG_IfTable == NULL) {
dwErr = GetLastError(); TRACE2( ANY, "error %d allocating %d bytes for interface table", dwErr, sizeof(IF_TABLE) ); LOGERR0(HEAP_ALLOC_FAILED, dwErr);
break; }
//
// initialize the interface table
//
dwErr = CreateIfTable(ig.IG_IfTable);
if (dwErr != NO_ERROR) {
TRACE1(START, "error %d initializing interface table", dwErr); LOGERR0(CREATE_IF_TABLE_FAILED, dwErr);
break; }
//
// allocate space for the peer statistics table
//
ig.IG_PeerTable = RIP_ALLOC(sizeof(PEER_TABLE));
if (ig.IG_PeerTable == NULL) {
dwErr = GetLastError(); TRACE2( ANY, "error %d allocating %d bytes for peer table", dwErr, sizeof(PEER_TABLE) ); LOGERR0(HEAP_ALLOC_FAILED, dwErr);
break; }
//
// initialize the peer statistics table
//
dwErr = CreatePeerTable(ig.IG_PeerTable);
if (dwErr != NO_ERROR) {
TRACE1(START, "error %d initializing peer statistics table", dwErr); LOGERR0(CREATE_PEER_TABLE_FAILED, dwErr);
break; }
//
// allocate space for the binding table
//
ig.IG_BindingTable = RIP_ALLOC(sizeof(BINDING_TABLE));
if (ig.IG_BindingTable == NULL) {
dwErr = GetLastError(); TRACE2( ANY, "error %d allocating %d bytes for binding table", dwErr, sizeof(PEER_TABLE) ); LOGERR0(HEAP_ALLOC_FAILED, dwErr);
break; }
//
// initialize the binding table
//
dwErr = CreateBindingTable(ig.IG_BindingTable); if (dwErr != NO_ERROR) {
TRACE1(START, "error %d creating binding table", dwErr); LOGERR0(CREATE_BINDING_TABLE_FAILED, dwErr);
break; }
//
// allocate space for the send queue
//
ig.IG_SendQueue = RIP_ALLOC(sizeof(LOCKED_LIST));
if (ig.IG_SendQueue == NULL) {
dwErr = GetLastError(); TRACE2( ANY, "error %d allocating %d bytes for send-queue", dwErr, sizeof(LOCKED_LIST) ); LOGERR0(HEAP_ALLOC_FAILED, dwErr);
break; }
//
// initialize the send queue
//
try { CREATE_LOCKED_LIST(ig.IG_SendQueue); } except (EXCEPTION_EXECUTE_HANDLER) {
dwErr = GetExceptionCode(); TRACE1(START, "exception %d initializing send queue", dwErr); LOGERR0(INIT_CRITSEC_FAILED, dwErr);
break; }
//
// allocate space for the receive queue
//
ig.IG_RecvQueue = RIP_ALLOC(sizeof(LOCKED_LIST));
if (ig.IG_RecvQueue == NULL) {
dwErr = GetLastError(); TRACE2( ANY, "error %d allocating %d bytes for receive queue", dwErr, sizeof(LOCKED_LIST) ); LOGERR0(HEAP_ALLOC_FAILED, dwErr);
break; }
//
// initialize the receive queue
//
try { CREATE_LOCKED_LIST(ig.IG_RecvQueue); } except (EXCEPTION_EXECUTE_HANDLER) {
dwErr = GetExceptionCode(); TRACE1(START, "exception %d initializing receive queue", dwErr); LOGERR0(INIT_CRITSEC_FAILED, dwErr);
break; }
//
// create event signalled by WinSock when input arrives
// and register it with the NtdllWait thread
//
ig.IG_IpripInputEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (ig.IG_IpripInputEvent == NULL) {
dwErr = GetLastError(); TRACE1(START, "error %d creating event to signal input", dwErr); LOGERR0(CREATE_EVENT_FAILED, dwErr);
break; }
if (! RegisterWaitForSingleObject( &ig.IG_IpripInputEventHandle, ig.IG_IpripInputEvent, CallbackFunctionNetworkEvents, NULL, INFINITE, (WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE) )) {
dwErr = GetLastError(); TRACE1(START, "error %d registering input event with NtdllWait thread", dwErr); LOGERR0(REGISTER_WAIT_FAILED, dwErr);
break; }
//
// initialize the count of threads which are active in IPRIP
// (includes IpripThread and worker threads),
// and create the semaphore released by each thread when it is done
//
ig.IG_ActivityCount = 0;
ig.IG_ActivitySemaphore = CreateSemaphore(NULL, 0, 0xfffffff, NULL);
if (ig.IG_ActivitySemaphore == NULL) {
dwErr = GetLastError(); TRACE1( START, "error %d creating semaphore for IPRIP threads", dwErr ); LOGERR0(CREATE_SEMAPHORE_FAILED, dwErr);
break; }
//
// register with RTMv2
//
ig.IG_RtmEntityInfo.RtmInstanceId = 0; ig.IG_RtmEntityInfo.AddressFamily = AF_INET; ig.IG_RtmEntityInfo.EntityId.EntityProtocolId = PROTO_IP_RIP; ig.IG_RtmEntityInfo.EntityId.EntityInstanceId = 0; dwErr = RtmRegisterEntity( &ig.IG_RtmEntityInfo, NULL, ProcessRtmNotification, FALSE, &ig.IG_RtmProfile, &ig.IG_RtmHandle );
if (dwErr != NO_ERROR ) { TRACE1(START, "error %d registering with RTM", dwErr); LOGERR0(RTM_REGISTER_FAILED, dwErr);
break; }
dwErr = RtmRegisterForChangeNotification( ig.IG_RtmHandle, RTM_VIEW_MASK_UCAST, RTM_CHANGE_TYPE_BEST, NULL, &ig.IG_RtmNotifHandle );
if (dwErr != NO_ERROR ) { TRACE1(START, "error %d registering for change with RTM", dwErr); LOGERR0(RTM_REGISTER_FAILED, dwErr);
break; }
//
// set IPRIP's status to running now, before we attempt
// to queue the MIB display work-item;
// QueueRipWorker() will check the status,
// and it will refuse to queue any work-items
// unless the status is IPRIP_STATUS_RUNNING
//
ig.IG_Status = IPRIP_STATUS_RUNNING;
#if CONFIG_DBG
//
// queue work item to display IPRIP's MIB tables periodically
//
ig.IG_MibTraceID = TraceRegisterEx("IPRIPMIB", TRACE_USE_CONSOLE);
if (ig.IG_MibTraceID != INVALID_TRACEID) { //
// create the persistent timer for the timer queue
//
if (!CreateTimerQueueTimer( &ig.IG_MibTimerHandle, ig.IG_TimerQueueHandle, WorkerFunctionMibDisplay, NULL, 0, 10000, 0)) {
dwErr = GetLastError(); TRACE1(START, "error %d creating MIB display timer", dwErr); } }
#endif
TRACE0(START, "IPRIP has started successfully"); LOGINFO0(IPRIP_STARTED, NO_ERROR);
LeaveCriticalSection(&ig.IG_CS);
return NO_ERROR;
} while (FALSE);
//
// something went wrong, so we cleanup.
// Note that we needn't worry about the main thread,
// since when we finally leave this critical section it will find
// that the status is IPRIP_STATUS_STOPPED, and it will immediately quit
//
TRACE0(START, "IPRIP failed to start");
ProtocolCleanup(bCleanupWinsock);
LeaveCriticalSection(&ig.IG_CS);
return (dwErr == NO_ERROR ? ERROR_CAN_NOT_COMPLETE : dwErr); }
//----------------------------------------------------------------------------
// Function: ProtocolCleanup
//
// This function deallocates allocated memory, closes open handles, and
// cleans up the global struct. It leaves IPRIP in clean state, so that
// it should be possible to do StartProtocol again with no memory leaks.
//----------------------------------------------------------------------------
DWORD ProtocolCleanup( BOOL bCleanupWinsock ) {
DWORD dwErr; // EnterCriticalSection(&ig.IG_CS);
#ifdef CONFIG_DBG
TraceDeregister(ig.IG_MibTraceID); ig.IG_MibTraceID = INVALID_TRACEID; #endif
if ( ig.IG_RtmNotifHandle != NULL ) { dwErr = RtmDeregisterFromChangeNotification( ig.IG_RtmHandle, ig.IG_RtmNotifHandle );
if ( dwErr != NO_ERROR ) {
TRACE1(STOP, "error %d deregistering change notification", dwErr); } }
if (ig.IG_RtmHandle != NULL) { dwErr = RtmDeregisterEntity(ig.IG_RtmHandle);
if ( dwErr != NO_ERROR ) {
TRACE1(STOP, "error %d deregistering from RTM", dwErr); } }
if (ig.IG_ActivitySemaphore != NULL) {
CloseHandle(ig.IG_ActivitySemaphore); ig.IG_ActivitySemaphore = NULL; }
if (ig.IG_IpripInputEvent != NULL) {
CloseHandle(ig.IG_IpripInputEvent); ig.IG_IpripInputEvent = NULL; }
if (ig.IG_RecvQueue != NULL) {
if (LOCKED_LIST_CREATED(ig.IG_RecvQueue)) {
FlushRecvQueue(ig.IG_RecvQueue);
DELETE_LOCKED_LIST(ig.IG_RecvQueue, RECV_QUEUE_ENTRY, RQE_Link); }
RIP_FREE(ig.IG_RecvQueue); ig.IG_RecvQueue = NULL; }
if (ig.IG_SendQueue != NULL) {
if (LOCKED_LIST_CREATED(ig.IG_SendQueue)) {
FlushSendQueue(ig.IG_SendQueue);
DELETE_LOCKED_LIST(ig.IG_SendQueue, SEND_QUEUE_ENTRY, SQE_Link); }
RIP_FREE(ig.IG_SendQueue); ig.IG_SendQueue = NULL; }
if (ig.IG_BindingTable != NULL) { if (BINDING_TABLE_CREATED(ig.IG_BindingTable)) { DeleteBindingTable(ig.IG_BindingTable); }
RIP_FREE(ig.IG_BindingTable); ig.IG_BindingTable = NULL; }
if (ig.IG_PeerTable != NULL) {
if (PEER_TABLE_CREATED(ig.IG_PeerTable)) { DeletePeerTable(ig.IG_PeerTable); }
RIP_FREE(ig.IG_PeerTable); ig.IG_PeerTable = NULL; }
if (ig.IG_IfTable != NULL) {
if (IF_TABLE_CREATED(ig.IG_IfTable)) { DeleteIfTable(ig.IG_IfTable); }
RIP_FREE(ig.IG_IfTable); ig.IG_IfTable = NULL; }
if (READ_WRITE_LOCK_CREATED(&ig.IG_RWL)) { DeleteReadWriteLock(&ig.IG_RWL); }
if (bCleanupWinsock) { WSACleanup(); }
if (ig.IG_Config != NULL) {
RIP_FREE(ig.IG_Config); ig.IG_Config = NULL; }
ig.IG_Status = IPRIP_STATUS_STOPPED;
// LeaveCriticalSection(&ig.IG_CS);
return NO_ERROR;
}
//----------------------------------------------------------------------------
// Function: RegisterProtocol
//
// Returns protocol ID and functionality for IPRIP
//----------------------------------------------------------------------------
DWORD APIENTRY RegisterProtocol( IN OUT PMPR_ROUTING_CHARACTERISTICS pRoutingChar, IN OUT PMPR_SERVICE_CHARACTERISTICS pServiceChar ) { if(pRoutingChar->dwProtocolId != MS_IP_RIP) { return ERROR_NOT_SUPPORTED; }
//
// Since we are not a service advertiser (and IPX thing)
//
pServiceChar->fSupportedFunctionality = 0;
if((pRoutingChar->fSupportedFunctionality & (RF_ROUTING|RF_DEMAND_UPDATE_ROUTES)) != (RF_ROUTING|RF_DEMAND_UPDATE_ROUTES)) { return ERROR_NOT_SUPPORTED; }
pRoutingChar->fSupportedFunctionality = (RF_ROUTING | RF_DEMAND_UPDATE_ROUTES);
pRoutingChar->fSupportedFunctionality = RF_ROUTING;
pRoutingChar->pfnStartProtocol = StartProtocol; pRoutingChar->pfnStartComplete = StartComplete; pRoutingChar->pfnStopProtocol = StopProtocol; pRoutingChar->pfnGetGlobalInfo = GetGlobalInfo; pRoutingChar->pfnSetGlobalInfo = SetGlobalInfo; pRoutingChar->pfnQueryPower = NULL; pRoutingChar->pfnSetPower = NULL;
pRoutingChar->pfnAddInterface = AddInterface; pRoutingChar->pfnDeleteInterface = DeleteInterface; pRoutingChar->pfnInterfaceStatus = InterfaceStatus; pRoutingChar->pfnGetInterfaceInfo = GetInterfaceConfigInfo; pRoutingChar->pfnSetInterfaceInfo = SetInterfaceConfigInfo;
pRoutingChar->pfnGetEventMessage = GetEventMessage;
pRoutingChar->pfnUpdateRoutes = DoUpdateRoutes;
pRoutingChar->pfnConnectClient = NULL; pRoutingChar->pfnDisconnectClient = NULL;
pRoutingChar->pfnGetNeighbors = NULL; pRoutingChar->pfnGetMfeStatus = NULL;
pRoutingChar->pfnMibCreateEntry = MibCreate; pRoutingChar->pfnMibDeleteEntry = MibDelete; pRoutingChar->pfnMibGetEntry = MibGet; pRoutingChar->pfnMibSetEntry = MibSet; pRoutingChar->pfnMibGetFirstEntry = MibGetFirst; pRoutingChar->pfnMibGetNextEntry = MibGetNext;
return NO_ERROR; }
//----------------------------------------------------------------------------
// Function: StartProtocol
//
// creates events, tables and queues used by IPRIP, registers with RTM,
// and starts threads.
//----------------------------------------------------------------------------
DWORD WINAPI StartProtocol ( HANDLE NotificationEvent, SUPPORT_FUNCTIONS *SupportFunctions, LPVOID GlobalInfo, ULONG StructureVersion, ULONG StructureSize, ULONG StructureCount ) { ig.IG_SupportFunctions = *SupportFunctions; return ProtocolStartup(NotificationEvent, GlobalInfo); }
//----------------------------------------------------------------------------
// Function: StartComplete
//
// Invoked by RouterManager to inform protocol that startup (init + interface
// additions are complete). Protocol is expected to wait for this before
// starting protocol specfic behavior
//----------------------------------------------------------------------------
DWORD APIENTRY StartComplete( VOID ) { return NO_ERROR; }
//----------------------------------------------------------------------------
// Function: StopProtocol
//
// This function is onvoked by Router Manager. It informs the main thread
// that it should exit, and then queues a work-item which waits for it
// to exit as well as any active or queued work-items.
//----------------------------------------------------------------------------
DWORD APIENTRY StopProtocol( VOID ) {
LONG lThreadCount;
EnterCriticalSection(&ig.IG_CS);
//
// cannot stop if already stopped
//
if (ig.IG_Status != IPRIP_STATUS_RUNNING) {
LeaveCriticalSection(&ig.IG_CS); return ERROR_CAN_NOT_COMPLETE; }
TRACE0(ENTER, "entering StopProtocol");
//
// set IPRIP's status to STOPPING;
// this prevents any more work-items from being queued,
// and it prevents the ones already queued from executing
//
ig.IG_Status = IPRIP_STATUS_STOPPING;
//
// find out how many threads are active in IPRIP;
// we will have to wait for this many threads to exit
// before we clean up RIP's resources
//
lThreadCount = ig.IG_ActivityCount;
TRACE1(STOP, "%d threads are active in IPRIP", lThreadCount);
LeaveCriticalSection(&ig.IG_CS);
//
// queue the stopprotocol work-item, and return PENDING to Router Manager
//
QueueUserWorkItem( (LPTHREAD_START_ROUTINE)WorkerFunctionFinishStopProtocol, (PVOID)UlongToPtr(lThreadCount), 0 );
TRACE0(LEAVE, "leaving StopProtocol");
return ERROR_PROTOCOL_STOP_PENDING; }
//----------------------------------------------------------------------------
// Function: GetGlobalInfo
//
// Copies to the given buffer the global information currently in use by
// IPRIP.
//----------------------------------------------------------------------------
DWORD WINAPI GetGlobalInfo ( PVOID OutGlobalInfo, PULONG GlobalInfoSize, PULONG StructureVersion, PULONG StructureSize, PULONG StructureCount ) { DWORD dwErr, dwSize; PIPRIP_GLOBAL_CONFIG pgcsrc, pgcdst;
if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
TRACE2(ENTER, "entering GetGlobalInfo: 0x%08x 0x%08x", OutGlobalInfo, GlobalInfoSize);
dwErr = NO_ERROR;
ACQUIRE_GLOBAL_LOCK_SHARED();
do {
//
// check the arguments
//
if (GlobalInfoSize == NULL) { dwErr = ERROR_INVALID_PARAMETER; break; }
pgcsrc = ig.IG_Config; dwSize = IPRIP_GLOBAL_CONFIG_SIZE(pgcsrc);
//
// check the buffer size
//
if (*GlobalInfoSize < dwSize || OutGlobalInfo == NULL) { dwErr = ERROR_INSUFFICIENT_BUFFER; } else { pgcdst = (PIPRIP_GLOBAL_CONFIG)OutGlobalInfo;
*StructureVersion = 1; *StructureSize = dwSize; *StructureCount = 1;
CopyMemory(pgcdst, pgcsrc, dwSize); }
*GlobalInfoSize = dwSize;
} while(FALSE);
RELEASE_GLOBAL_LOCK_SHARED();
TRACE1(LEAVE, "leaving GetGlobalInfo: %d", dwErr);
LEAVE_RIP_API();
return dwErr; }
//----------------------------------------------------------------------------
// Function: SetGlobalInfo
//
// Changes IPRIP's global configuration to the supplied values.
//----------------------------------------------------------------------------
DWORD WINAPI SetGlobalInfo ( PVOID GlobalInfo, ULONG StructureVersion, ULONG StructureSize, ULONG StructureCount ) { DWORD dwErr, dwSize; PIPRIP_GLOBAL_CONFIG pgcsrc, pgcdst;
if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
TRACE1(ENTER, "entering SetGlobalInfo: 0x%08x", GlobalInfo);
dwErr = NO_ERROR;
ACQUIRE_GLOBAL_LOCK_EXCLUSIVE();
do {
//
// check the argument
//
if (GlobalInfo == NULL) { dwErr = ERROR_INVALID_PARAMETER; break; }
pgcsrc = (PIPRIP_GLOBAL_CONFIG)GlobalInfo;
//
// find the size of the new global config
//
dwSize = IPRIP_GLOBAL_CONFIG_SIZE(pgcsrc);
//
// allocate space for the private copy of the config
//
pgcdst = (PIPRIP_GLOBAL_CONFIG)RIP_ALLOC(dwSize);
if (pgcdst == NULL) {
dwErr = GetLastError(); TRACE2( ANY, "error %d allocating %d bytes for global config", dwErr, dwSize ); LOGERR0(HEAP_ALLOC_FAILED, dwErr);
break; }
//
// copy from the buffer
//
CopyMemory(pgcdst, pgcsrc, dwSize); InterlockedExchange(&ig.IG_LogLevel, pgcsrc->GC_LoggingLevel);
if (ig.IG_Config != NULL) { RIP_FREE(ig.IG_Config); }
ig.IG_Config = pgcdst;
} while(FALSE);
RELEASE_GLOBAL_LOCK_EXCLUSIVE();
TRACE1(LEAVE, "leaving SetGlobalInfo: %d", dwErr);
LEAVE_RIP_API();
return dwErr; }
//----------------------------------------------------------------------------
// Function: AddInterface
//
// This function is called to add an interface with the given configuration
// to IPRIP. The interface is created inactive.
//----------------------------------------------------------------------------
DWORD WINAPI AddInterface ( PWCHAR pwszInterfaceName, ULONG InterfaceIndex, NET_INTERFACE_TYPE InterfaceType, DWORD MediaType, WORD AccessType, WORD ConnectionType, PVOID InterfaceInfo, ULONG StructureVersion, ULONG StructureSize, ULONG StructureCount ) { DWORD dwErr;
if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
TRACE3( ENTER, "entering AddInterface: %d %d 0x%08x", InterfaceIndex, InterfaceType, InterfaceInfo );
ACQUIRE_IF_LOCK_EXCLUSIVE();
dwErr = CreateIfEntry(ig.IG_IfTable, InterfaceIndex, InterfaceType, InterfaceInfo, NULL);
RELEASE_IF_LOCK_EXCLUSIVE();
TRACE1(LEAVE, "leaving AddInterface: %d", dwErr);
LEAVE_RIP_API();
return dwErr; }
//----------------------------------------------------------------------------
// Function: DeleteInterface
//
// This removes the interface with the given index, deactivating it if
// necessary.
//----------------------------------------------------------------------------
DWORD APIENTRY DeleteInterface( IN DWORD dwIndex ) {
DWORD dwErr; PIF_TABLE pTable;
if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
TRACE1(ENTER, "entering DeleteInterface: %d", dwIndex);
ACQUIRE_IF_LOCK_EXCLUSIVE();
dwErr = DeleteIfEntry(ig.IG_IfTable, dwIndex);
RELEASE_IF_LOCK_EXCLUSIVE();
TRACE1(LEAVE, "leaving DeleteInterface: %d", dwErr);
LEAVE_RIP_API();
return dwErr; }
//----------------------------------------------------------------------------
// Function: GetEventMessage
//
// Dequeues a message for Router Manager from IPRIP's event queue.
//----------------------------------------------------------------------------
DWORD APIENTRY GetEventMessage( OUT ROUTING_PROTOCOL_EVENTS *pEvent, OUT PMESSAGE pResult ) {
DWORD dwErr;
//
// note that GetEventMessage does not use the
// ENTER_RIP_API()/LEAVE_RIP_API() mechanism,
// since it may be called after RIP has stopped, when the
// Router Manager is retrieving the ROUTER_STOPPED message
//
TRACE2(ENTER, "entering GetEventMessage: 0x%08x 0x%08x", pEvent, pResult);
ACQUIRE_LIST_LOCK(ig.IG_EventQueue);
dwErr = DequeueEvent(ig.IG_EventQueue, pEvent, pResult);
RELEASE_LIST_LOCK(ig.IG_EventQueue);
TRACE1(LEAVE, "leaving GetEventMessage: %d", dwErr);
return dwErr; }
//----------------------------------------------------------------------------
// Function: GetInterfaceConfigInfo
//
// Copies to the caller's buffer the configuration for the interface
// with the specified index.
//----------------------------------------------------------------------------
DWORD WINAPI GetInterfaceConfigInfo ( ULONG InterfaceIndex, PVOID OutInterfaceInfo, PULONG InterfaceInfoSize, PULONG StructureVersion, PULONG StructureSize, PULONG StructureCount ) { DWORD dwErr, dwSize; PIF_TABLE pTable; PIF_TABLE_ENTRY pite; PIPRIP_IF_CONFIG picsrc, picdst;
if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
TRACE3( ENTER, "entering GetInterfaceConfigInfo: %d 0x%08x 0x%08x", InterfaceIndex,, OutInterfaceInfo, InterfaceInfoSize );
dwErr = NO_ERROR;
do {
//
// check the arguments
//
if (InterfaceInfoSize == NULL) { dwErr = ERROR_INVALID_PARAMETER; break; }
pTable = ig.IG_IfTable;
ACQUIRE_IF_LOCK_SHARED();
//
// find the interface specified
//
pite = GetIfByIndex(pTable, InterfaceIndex);
if (pite == NULL) { dwErr = ERROR_INVALID_PARAMETER; } else {
//
// get the size of the interface config
//
picsrc = pite->ITE_Config; dwSize = IPRIP_IF_CONFIG_SIZE(picsrc);
//
// check the buffer size
//
if (*InterfaceInfoSize < dwSize) { dwErr = ERROR_INSUFFICIENT_BUFFER; } else {
picdst = (PIPRIP_IF_CONFIG)OutInterfaceInfo;
//
// copy the interface config, and set the IP address
//
CopyMemory(picdst, picsrc, dwSize);
*StructureVersion = 1; *StructureSize = dwSize; *StructureCount = 1;
picdst->IC_State = 0;
if (IF_IS_ENABLED(pite)) { picdst->IC_State |= IPRIP_STATE_ENABLED; }
if (IF_IS_BOUND(pite)) { picdst->IC_State |= IPRIP_STATE_BOUND; } }
*InterfaceInfoSize = dwSize;
}
RELEASE_IF_LOCK_SHARED();
} while(FALSE);
TRACE1(LEAVE, "leaving GetInterfaceConfigInfo: %d", dwErr);
LEAVE_RIP_API();
return dwErr; }
//----------------------------------------------------------------------------
// Function: SetInterfaceConfigInfo
//
// This sets the configuration for the interface with the given index.
//----------------------------------------------------------------------------
DWORD WINAPI SetInterfaceConfigInfo ( ULONG InterfaceIndex, PVOID InterfaceInfo, ULONG StructureVersion, ULONG StructureSize, ULONG StructureCount ) { DWORD dwErr; PIF_TABLE pTable; PIF_TABLE_ENTRY pite;
if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
TRACE2( ENTER, "entering SetInterfaceConfigInfo: %d, 0x%08x", InterfaceIndex, InterfaceInfo );
dwErr = NO_ERROR;
do {
if (InterfaceInfo == NULL) { dwErr = ERROR_INVALID_PARAMETER; break; }
pTable = ig.IG_IfTable;
ACQUIRE_IF_LOCK_EXCLUSIVE();
dwErr = ConfigureIfEntry(pTable, InterfaceIndex, InterfaceInfo);
RELEASE_IF_LOCK_EXCLUSIVE();
} while(FALSE);
TRACE1(LEAVE, "leaving SetInterfaceConfigInfo: %d", dwErr);
LEAVE_RIP_API();
return dwErr;
}
DWORD WINAPI InterfaceStatus( ULONG InterfaceIndex, BOOL InterfaceActive, DWORD StatusType, PVOID StatusInfo ) { DWORD dwResult;
if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
switch(StatusType) { case RIS_INTERFACE_ADDRESS_CHANGE: { PIP_ADAPTER_BINDING_INFO pBindInfo;
pBindInfo = (PIP_ADAPTER_BINDING_INFO)StatusInfo;
if(pBindInfo->AddressCount) { dwResult = BindInterface(InterfaceIndex, pBindInfo); } else { dwResult = UnBindInterface(InterfaceIndex); }
break; }
case RIS_INTERFACE_ENABLED: { dwResult = EnableInterface(InterfaceIndex);
break; }
case RIS_INTERFACE_DISABLED: { dwResult = DisableInterface(InterfaceIndex);
break;
}
default: { RTASSERT(FALSE);
dwResult = ERROR_INVALID_PARAMETER; } }
LEAVE_RIP_API();
return dwResult; }
//---------------------------------------------------------------------------
// Function: BindInterface
//
// This function is called to supply the binding information
// for an interface
//---------------------------------------------------------------------------
DWORD APIENTRY BindInterface( IN DWORD dwIndex, IN PVOID pBinding ) {
DWORD dwErr; PIF_TABLE pTable;
TRACE2(ENTER, "entering BindInterface: %d 0x%08x", dwIndex, pBinding);
if (pBinding == NULL) {
TRACE0(IF, "error: binding struct pointer is NULL"); TRACE1(LEAVE, "leaving BindInterface: %d", ERROR_INVALID_PARAMETER);
return ERROR_INVALID_PARAMETER; }
//
// now bind the interface in the interface table
//
pTable = ig.IG_IfTable;
ACQUIRE_IF_LOCK_EXCLUSIVE();
dwErr = BindIfEntry(pTable, dwIndex, pBinding);
RELEASE_IF_LOCK_EXCLUSIVE();
TRACE1(LEAVE, "leaving BindInterface: %d", dwErr);
return dwErr; }
//---------------------------------------------------------------------------
// Function: UnBindInterface
//
// This function removes the binding for an interface.
//---------------------------------------------------------------------------
DWORD APIENTRY UnBindInterface( IN DWORD dwIndex ) {
DWORD dwErr; PIF_TABLE pTable; PIF_TABLE_ENTRY pite;
TRACE1(ENTER, "entering UnBindInterface: %d", dwIndex);
pTable = ig.IG_IfTable;
//
// unbind the interface
//
ACQUIRE_IF_LOCK_EXCLUSIVE();
dwErr = UnBindIfEntry(pTable, dwIndex);
RELEASE_IF_LOCK_EXCLUSIVE();
TRACE1(LEAVE, "leaving UnBindInterface: %d", dwErr);
return dwErr; }
//----------------------------------------------------------------------------
// Function: EnableInterface
//
// This function starts IPRIP activity over the interface with
// the given index, using the given binding information.
//----------------------------------------------------------------------------
DWORD APIENTRY EnableInterface( IN DWORD dwIndex ) {
DWORD dwErr; PIF_TABLE pTable;
TRACE1(ENTER, "entering EnableInterface: %d", dwIndex);
pTable = ig.IG_IfTable;
//
// activate the interface
//
ACQUIRE_IF_LOCK_EXCLUSIVE();
dwErr = EnableIfEntry(pTable, dwIndex);
RELEASE_IF_LOCK_EXCLUSIVE();
TRACE1(LEAVE, "leaving EnableInterface: %d", dwErr);
return dwErr;
}
//----------------------------------------------------------------------------
// Function: DisableInterface
//
// This function stops IPRIP activity on an interface, also removing
// routes associated with the interface from RTM and purging the network
// of such routes.
//----------------------------------------------------------------------------
DWORD APIENTRY DisableInterface( IN DWORD dwIndex ) {
DWORD dwErr; PIF_TABLE pTable;
TRACE1(ENTER, "entering DisableInterface: %d", dwIndex);
pTable = ig.IG_IfTable;
//
// stop activity on the interface
//
ACQUIRE_IF_LOCK_EXCLUSIVE();
dwErr = DisableIfEntry(pTable, dwIndex);
RELEASE_IF_LOCK_EXCLUSIVE();
TRACE1(LEAVE, "leaving DisableInterface: %d", dwIndex);
return dwErr; }
//----------------------------------------------------------------------------
// Function: DoUpdateRoutes
//
// This function begins a demand-update of routes, by queuing a work-item
// which will send out requests on the specified interface.
//----------------------------------------------------------------------------
DWORD APIENTRY DoUpdateRoutes( IN DWORD dwIndex ) {
DWORD dwErr;
if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
TRACE1(ENTER, "entering DoUpdateRoutes: %d", dwIndex);
//
// queue the work-item; perhaps we could call the function directly,
// but using a worker-thread lets us return to Router Manager right away
//
dwErr = QueueRipWorker( WorkerFunctionStartDemandUpdate, (PVOID)UlongToPtr(dwIndex) );
TRACE1(LEAVE,"leaving DoUpdateRoutes(), errcode %d", dwErr);
LEAVE_RIP_API();
return dwErr; }
//----------------------------------------------------------------------------
// Function: MibCreate
//
// This function does nothing, since IPRIP does not support creation of
// interface objects via SNMP. However, this could be implemented as a call
// to CreateIfEntry() followed by a call to ActivateIfEntry(), and the input
// data would have to contain the interface's index, configuration,
// and binding.
//----------------------------------------------------------------------------
DWORD APIENTRY MibCreate( IN DWORD dwInputSize, IN PVOID pInputData ) {
DWORD dwErr;
if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
TRACE2(ENTER, "entering MibCreate: %d 0x%08x", dwInputSize, pInputData);
dwErr = ERROR_CAN_NOT_COMPLETE;
TRACE1(LEAVE, "leaving MibCreate: %d", dwErr);
LEAVE_RIP_API();
return dwErr; }
//----------------------------------------------------------------------------
// Function: MibDelete
//
// This function does nothing, since IPRIP does not support deletion of
// interface objects via SNMP. This could be implemented as a call to
// DeactivateIfEntry() followed by a call to DeleteIfEntry(), and the
// input data would have to contain the interface's index
//----------------------------------------------------------------------------
DWORD APIENTRY MibDelete( IN DWORD dwInputSize, IN PVOID pInputData ) {
DWORD dwErr;
if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
TRACE2(ENTER, "entering MibDelete: %d 0x%08x", dwInputSize, pInputData);
dwErr = ERROR_CAN_NOT_COMPLETE;
TRACE1(LEAVE, "leaving MibDelete: %d", dwErr);
LEAVE_RIP_API();
return dwErr; }
//----------------------------------------------------------------------------
// Function: MibSet
//
// The function sets global or interface configuration.
//----------------------------------------------------------------------------
DWORD APIENTRY MibSet( IN DWORD dwInputSize, IN PVOID pInputData ) {
DWORD dwErr; PIPRIP_MIB_SET_INPUT_DATA pimsid;
if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
TRACE2(ENTER, "entering MibSet: %d 0x%08x", dwInputSize, pInputData);
dwErr = NO_ERROR;
do { // breakout loop
if (pInputData == NULL) { dwErr = ERROR_INVALID_PARAMETER; break; }
if (dwInputSize < sizeof(IPRIP_MIB_SET_INPUT_DATA)) { dwErr = ERROR_INSUFFICIENT_BUFFER; break; }
pimsid = (PIPRIP_MIB_SET_INPUT_DATA)pInputData;
switch (pimsid->IMSID_TypeID) {
case IPRIP_GLOBAL_CONFIG_ID: {
PIPRIP_GLOBAL_CONFIG pigc;
if (pimsid->IMSID_BufferSize < sizeof(IPRIP_GLOBAL_CONFIG)) { dwErr = ERROR_INSUFFICIENT_BUFFER; break; }
dwErr = SetGlobalInfo(pimsid->IMSID_Buffer,1,0,1);
if (dwErr == NO_ERROR) {
MESSAGE msg = {0, 0, 0};
ACQUIRE_LIST_LOCK(ig.IG_EventQueue); EnqueueEvent( ig.IG_EventQueue, SAVE_GLOBAL_CONFIG_INFO, msg ); SetEvent(ig.IG_EventEvent); RELEASE_LIST_LOCK(ig.IG_EventQueue); }
break; }
case IPRIP_IF_CONFIG_ID: {
DWORD dwSize; PIF_TABLE pTable; PIPRIP_IF_CONFIG pic; PIF_TABLE_ENTRY pite;
if (pimsid->IMSID_BufferSize < sizeof(IPRIP_IF_CONFIG)) { dwErr = ERROR_INSUFFICIENT_BUFFER; break; }
pic = (PIPRIP_IF_CONFIG)pimsid->IMSID_Buffer;
pTable = ig.IG_IfTable;
ACQUIRE_IF_LOCK_EXCLUSIVE();
//
// retrieve the interface to be configured
//
pite = GetIfByIndex( pTable, pimsid->IMSID_IfIndex ); if (pite == NULL) { dwErr = ERROR_INVALID_PARAMETER; } else {
dwErr = ConfigureIfEntry(pTable, pite->ITE_Index, pic); }
//
// notify Router Manager
//
if (dwErr == NO_ERROR) {
MESSAGE msg = {0, 0, 0};
msg.InterfaceIndex = pite->ITE_Index;
ACQUIRE_LIST_LOCK(ig.IG_EventQueue); EnqueueEvent( ig.IG_EventQueue, SAVE_INTERFACE_CONFIG_INFO, msg ); SetEvent(ig.IG_EventEvent); RELEASE_LIST_LOCK(ig.IG_EventQueue); }
RELEASE_IF_LOCK_EXCLUSIVE();
break; }
default: { dwErr = ERROR_INVALID_PARAMETER; } }
} while(FALSE);
TRACE1(LEAVE, "leaving MibSet: %d", dwErr);
LEAVE_RIP_API();
return dwErr; }
//----------------------------------------------------------------------------
// Function: MibGetInternal
//
// Forward declaration of internal implementation function
//----------------------------------------------------------------------------
DWORD MibGetInternal( PIPRIP_MIB_GET_INPUT_DATA pimgid, PIPRIP_MIB_GET_OUTPUT_DATA pimgod, PDWORD pdwOutputSize, DWORD dwGetMode );
//----------------------------------------------------------------------------
// Function: MibGet
//
// This function retrieves global or interface configuration, as well as
// global stats, interface stats, and peer-router stats.
//----------------------------------------------------------------------------
DWORD APIENTRY MibGet( IN DWORD dwInputSize, IN PVOID pInputData, IN OUT PDWORD pdwOutputSize, OUT PVOID pOutputData ) {
DWORD dwErr; PIPRIP_MIB_GET_INPUT_DATA pimgid; PIPRIP_MIB_GET_OUTPUT_DATA pimgod;
if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
TRACE4( ENTER, "entering MibGet: %d 0x%08x 0x%08x 0x%08x", dwInputSize, pInputData, pdwOutputSize, pOutputData );
if (pInputData == NULL || dwInputSize < sizeof(IPRIP_MIB_GET_INPUT_DATA) || pdwOutputSize == NULL) { dwErr = ERROR_INVALID_PARAMETER; } else {
pimgid = (PIPRIP_MIB_GET_INPUT_DATA)pInputData; pimgod = (PIPRIP_MIB_GET_OUTPUT_DATA)pOutputData;
dwErr = MibGetInternal(pimgid, pimgod, pdwOutputSize, GETMODE_EXACT);
}
TRACE1(LEAVE, "leaving MibGet: %d", dwErr);
LEAVE_RIP_API();
return dwErr; }
//----------------------------------------------------------------------------
// Function: MibGetFirst
//
// This function retrieves global or interface configuration, as well as
// global stats, interface stats, and peer-router stats. It differs from
// MibGet() in that it always returns the FIRST entry in whichever table
// is being queried. There is only one entry in the global stats and config
// tables, but the interface config, interface stats, and peer stats tables
// are sorted by IP address; this function returns the first entry from these.
//----------------------------------------------------------------------------
DWORD APIENTRY MibGetFirst( IN DWORD dwInputSize, IN PVOID pInputData, IN OUT PDWORD pdwOutputSize, OUT PVOID pOutputData ) {
DWORD dwErr; PIPRIP_MIB_GET_INPUT_DATA pimgid; PIPRIP_MIB_GET_OUTPUT_DATA pimgod;
if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
TRACE4( ENTER, "entering MibGetFirst: %d 0x%08x 0x%08x 0x%08x", dwInputSize, pInputData, pdwOutputSize, pOutputData );
if (pInputData == NULL || dwInputSize < sizeof(IPRIP_MIB_GET_INPUT_DATA) || pdwOutputSize == NULL) { dwErr = ERROR_INVALID_PARAMETER; } else { pimgid = (PIPRIP_MIB_GET_INPUT_DATA)pInputData; pimgod = (PIPRIP_MIB_GET_OUTPUT_DATA)pOutputData;
dwErr = MibGetInternal(pimgid, pimgod, pdwOutputSize, GETMODE_FIRST); }
TRACE1(LEAVE, "leaving MibGetFirst: %d", dwErr);
LEAVE_RIP_API();
return dwErr; }
//----------------------------------------------------------------------------
// Function: MibGetNext
//
// This function retrieves global or interface configuration, as well as
// global stats, interface stats, and peer-router stats. It differs from both
// MibGet() and MibGetFirst(0 in that it always returns the entry AFTER the
// specified in the specified table. Thus, in the interface config, interface
// stats, and peer stats tables, this function supplies the entry after the
// one with the address passed in.
//
// If the end of the table being queried has been reached, this function will
// return the FIRST entry from the NEXT table, where "NEXT" here means the
// table whose ID is one greater than the ID passed in.
// Thus calling MibGetNext() for the last entry in the interface
// stats table (ID==2) will return the first entry in the interface config
// table (ID==3).
//
// In any case, this function writes the required size to pdwOutputSize and
// writes the ID of the object that WOULD have been returned into the output
// buffer.
//----------------------------------------------------------------------------
DWORD APIENTRY MibGetNext( IN DWORD dwInputSize, IN PVOID pInputData, IN OUT PDWORD pdwOutputSize, OUT PVOID pOutputData ) {
DWORD dwErr, dwOutSize = 0, dwBufSize = 0; PIPRIP_MIB_GET_INPUT_DATA pimgid; PIPRIP_MIB_GET_OUTPUT_DATA pimgod;
if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
TRACE4( ENTER, "entering MibGetNext: %d 0x%08x 0x%08x 0x%08x", dwInputSize, pInputData, pdwOutputSize, pOutputData );
if (pInputData == NULL || dwInputSize < sizeof(IPRIP_MIB_GET_INPUT_DATA) || pdwOutputSize == NULL) { dwErr = ERROR_INVALID_PARAMETER; } else {
pimgid = (PIPRIP_MIB_GET_INPUT_DATA)pInputData; pimgod = (PIPRIP_MIB_GET_OUTPUT_DATA)pOutputData;
dwOutSize = *pdwOutputSize;
dwErr = MibGetInternal(pimgid, pimgod, pdwOutputSize, GETMODE_NEXT);
if (dwErr == ERROR_NO_MORE_ITEMS) {
//
// need to wrap to the first entry in the next table,
// if there is a next table
//
TRACE1( CONFIG, "MibGetNext is wrapping to table %d", pimgid->IMGID_TypeID + 1 );
*pdwOutputSize = dwOutSize;
//
// wrap to next table by incrementing the type ID
//
++pimgid->IMGID_TypeID; if (pimgid->IMGID_TypeID <= IPRIP_PEER_STATS_ID) { dwErr = MibGetInternal( pimgid, pimgod, pdwOutputSize, GETMODE_FIRST ); } --pimgid->IMGID_TypeID; } }
TRACE1(LEAVE, "leaving MibGetNext: %d", dwErr);
LEAVE_RIP_API();
return dwErr; }
//----------------------------------------------------------------------------
// Function: MibGetInternal
//
// This handles the actual structure access required to read MIB data.
// Each table supported by IPRIP supports three modes of querying;
// EXACT, FIRST, and NEXT, which correspond to the functions MibGet(),
// MibGetFirst(), and MibGetNext() respectively.
//----------------------------------------------------------------------------
DWORD MibGetInternal( PIPRIP_MIB_GET_INPUT_DATA pimgid, PIPRIP_MIB_GET_OUTPUT_DATA pimgod, PDWORD pdwOutputSize, DWORD dwGetMode ) {
DWORD dwErr, dwBufferSize, dwSize; ULONG ulVersion, ulSize, ulCount;
dwErr = NO_ERROR;
//
// first we use pdwOutputSize to compute the size of the buffer
// available for storing returned structures (the size of IMGOD_Buffer)
//
if (pimgod == NULL) { dwBufferSize = 0; } else { if (*pdwOutputSize < sizeof(IPRIP_MIB_GET_OUTPUT_DATA)) { dwBufferSize = 0; } else { dwBufferSize = *pdwOutputSize - sizeof(IPRIP_MIB_GET_OUTPUT_DATA) + 1; } }
*pdwOutputSize = 0;
//
// determine which type of data is to be returned
//
switch (pimgid->IMGID_TypeID) {
case IPRIP_GLOBAL_STATS_ID: {
//
// the global stats structure is constant size.
// there is only one instance, so if the mode is GETMODE_NEXT
// we always return ERROR_NO_MORE_ITEMS
//
PIPRIP_GLOBAL_STATS pigsdst, pigssrc;
//
// set the output size required for this entry,
// as well as the type of data to be returned
//
*pdwOutputSize = sizeof(IPRIP_MIB_GET_OUTPUT_DATA) - 1 + sizeof(IPRIP_GLOBAL_STATS); if (pimgod) { pimgod->IMGOD_TypeID = IPRIP_GLOBAL_STATS_ID; }
//
// only GETMODE_EXACT and GETMODE_FIRST are valid for
// the global stats object, since there is only one entry
//
if (dwGetMode == GETMODE_NEXT) { dwErr = ERROR_NO_MORE_ITEMS; break; }
if (pimgod == NULL) { dwErr = ERROR_INSUFFICIENT_BUFFER; break; }
//
// check that the output buffer is big enough
//
if (dwBufferSize < sizeof(IPRIP_GLOBAL_STATS)) { dwErr = ERROR_INSUFFICIENT_BUFFER; } else {
//
// since access to this structure is not synchronized,
// we must copy it field by field
//
pigssrc = &ig.IG_Stats; pigsdst = (PIPRIP_GLOBAL_STATS)pimgod->IMGOD_Buffer;
pigsdst->GS_SystemRouteChanges = pigssrc->GS_SystemRouteChanges; pigsdst->GS_TotalResponsesSent = pigssrc->GS_TotalResponsesSent; }
break; }
case IPRIP_GLOBAL_CONFIG_ID: {
//
// the global config struct is variable length,
// so we wait until it has been retrieved
// before we set the size.
// furthermore, there is only one global config object,
// so GETMODE_NEXT doesn't make any sense
//
if (pimgod) { pimgod->IMGOD_TypeID = IPRIP_GLOBAL_CONFIG_ID; }
if (dwGetMode == GETMODE_NEXT) { dwErr = ERROR_NO_MORE_ITEMS; break; }
//
// Use GetGlobalInfo to retrieve the global information.
// It will decide whether the buffer is large enough,
// and if not will set the required size. Then all we need do
// is write out the size set by GetGlobalInfo() and
// relay its return-value to the caller
//
if (pimgod == NULL) { dwErr = GetGlobalInfo(NULL, &dwBufferSize, &ulVersion, &ulSize, &ulCount); } else {
dwErr = GetGlobalInfo( pimgod->IMGOD_Buffer, &dwBufferSize, &ulVersion, &ulSize, &ulCount ); }
*pdwOutputSize = sizeof(IPRIP_MIB_GET_OUTPUT_DATA) - 1 + dwBufferSize;
break; }
case IPRIP_IF_STATS_ID: {
//
// the interface statistics struct is fixed-length.
// there may be multiple instances.
//
PIF_TABLE pTable; PIF_TABLE_ENTRY pite; PIPRIP_IF_STATS pissrc, pisdst;
//
// set the size needed right away
//
*pdwOutputSize = sizeof(IPRIP_MIB_GET_OUTPUT_DATA) - 1 + sizeof(IPRIP_IF_STATS); if (pimgod) { pimgod->IMGOD_TypeID = IPRIP_IF_STATS_ID; }
pTable = ig.IG_IfTable;
ACQUIRE_IF_LOCK_SHARED();
//
// retrieve the interface whose stats are to be read
//
pite = GetIfByListIndex( pTable, pimgid->IMGID_IfIndex, dwGetMode, &dwErr );
//
// if the interface was not found, it may mean
// the specified index was invalid, or it may mean
// that the GETMODE_NEXT was called on the last interface
// in which case ERROR_NO_MORE_ITEMS was returned.
// In any case, we make sure dwErr indicates an error
// and then return the value.
//
// if the interface was found but no output buffer was passed,
// indicate in the error that memory needs to be allocated.
//
// otherwise, copy the stats struct of the interface
//
if (pite == NULL) { if (dwErr == NO_ERROR) { dwErr = ERROR_NOT_FOUND; } } else if (pimgod == NULL) { dwErr = ERROR_INSUFFICIENT_BUFFER; } else {
//
// set the index of the interface returned
//
pimgod->IMGOD_IfIndex = pite->ITE_Index;
//
// if the buffer is large enough, copy over the stats
//
if (dwBufferSize < sizeof(IPRIP_IF_STATS)) { dwErr = ERROR_INSUFFICIENT_BUFFER; } else {
//
// since access to this structure is not synchronized,
// we must copy it field by field
//
pissrc = &pite->ITE_Stats; pisdst = (PIPRIP_IF_STATS)pimgod->IMGOD_Buffer;
pisdst->IS_State = 0;
if (IF_IS_ENABLED(pite)) { pisdst->IS_State |= IPRIP_STATE_ENABLED; }
if (IF_IS_BOUND(pite)) { pisdst->IS_State |= IPRIP_STATE_BOUND; }
pisdst->IS_SendFailures = pissrc->IS_SendFailures; pisdst->IS_ReceiveFailures = pissrc->IS_ReceiveFailures; pisdst->IS_RequestsSent = pissrc->IS_RequestsSent; pisdst->IS_RequestsReceived = pissrc->IS_RequestsReceived; pisdst->IS_ResponsesSent = pissrc->IS_ResponsesSent; pisdst->IS_RequestsReceived = pissrc->IS_RequestsReceived; pisdst->IS_ResponsesReceived = pissrc->IS_ResponsesReceived; pisdst->IS_BadResponsePacketsReceived = pissrc->IS_BadResponsePacketsReceived; pisdst->IS_BadResponseEntriesReceived = pissrc->IS_BadResponseEntriesReceived; pisdst->IS_TriggeredUpdatesSent = pissrc->IS_TriggeredUpdatesSent; } }
RELEASE_IF_LOCK_SHARED();
break; }
case IPRIP_IF_CONFIG_ID: {
//
// the interface configuration is variable-length.
// thus we must actually retrieve the requested interface
// before we know how large a buffer is needed.
//
PIF_TABLE pTable; PIF_TABLE_ENTRY pite; PIPRIP_IF_CONFIG picsrc, picdst;
if (pimgod) { pimgod->IMGOD_TypeID = IPRIP_IF_CONFIG_ID; }
pTable = ig.IG_IfTable;
ACQUIRE_IF_LOCK_SHARED();
//
// retrieve the interface whose config is to be read
//
pite = GetIfByListIndex( pTable, pimgid->IMGID_IfIndex, dwGetMode, &dwErr );
//
// if the interface was found, it may mean that the index
// specified was invalid, or it may mean that a GETMODE_NEXT
// retrieval was attempted on the last interface, in which case
// ERROR_NO_MORE_ITEMS would have been returned.
//
if (pite == NULL) { if (dwErr == NO_ERROR) { dwErr = ERROR_NOT_FOUND; } } else {
//
// compute the size of the interface config retrieved,
// and write it over the caller's supplied size
//
picsrc = pite->ITE_Config; dwSize = IPRIP_IF_CONFIG_SIZE(picsrc); *pdwOutputSize = sizeof(IPRIP_MIB_GET_OUTPUT_DATA) - 1 + dwSize;
//
// if no buffer was specified, indicate one should be allocated
//
if (pimgod == NULL) { dwErr = ERROR_INSUFFICIENT_BUFFER; } else {
//
// if the buffer is not large enough,
// indicate that it should be enlarged
//
if (dwBufferSize < dwSize) { dwErr = ERROR_INSUFFICIENT_BUFFER; } else {
//
// copy the configuration
//
picdst = (PIPRIP_IF_CONFIG)pimgod->IMGOD_Buffer;
CopyMemory(picdst, picsrc, dwSize); ZeroMemory( picdst->IC_AuthenticationKey, IPRIP_MAX_AUTHKEY_SIZE );
picdst->IC_State = 0;
if (IF_IS_ENABLED(pite)) { picdst->IC_State |= IPRIP_STATE_ENABLED; }
if (IF_IS_BOUND(pite)) { picdst->IC_State |= IPRIP_STATE_BOUND; } }
pimgod->IMGOD_IfIndex = pite->ITE_Index; } }
RELEASE_IF_LOCK_SHARED();
break; }
case IPRIP_IF_BINDING_ID: {
//
// the interface binding is variable-length
// thus we must actually retrieve the requested interface
// before we know how large a buffer is needed.
//
PIF_TABLE pTable; PIF_TABLE_ENTRY pite; PIPRIP_IF_BINDING pibsrc, pibdst;
if (pimgod) { pimgod->IMGOD_TypeID = IPRIP_IF_BINDING_ID; }
pTable = ig.IG_IfTable;
ACQUIRE_IF_LOCK_SHARED();
//
// retrieve the interface whose binding is to be read
//
pite = GetIfByListIndex( pTable, pimgid->IMGID_IfIndex, dwGetMode, &dwErr );
//
// if the interface was found, it may mean that the index
// specified was invalid, or it may mean that a GETMODE_NEXT
// retrieval was attempted on the last interface, in which case
// ERROR_NO_MORE_ITEMS would have been returned.
//
if (pite == NULL) { if (dwErr == NO_ERROR) { dwErr = ERROR_NOT_FOUND; } } else {
//
// compute the size of the interface binding retrieved,
// and write it over the caller's supplied size
//
pibsrc = pite->ITE_Binding; dwSize = (pibsrc ? IPRIP_IF_BINDING_SIZE(pibsrc) : sizeof(IPRIP_IF_BINDING)); *pdwOutputSize = sizeof(IPRIP_MIB_GET_OUTPUT_DATA) - 1 + dwSize;
//
// if no buffer was specified, indicate one should be allocated
//
if (pimgod == NULL) { dwErr = ERROR_INSUFFICIENT_BUFFER; } else {
//
// if the buffer is not large enough,
// indicate that it should be enlarged
//
if (dwBufferSize < dwSize) { dwErr = ERROR_INSUFFICIENT_BUFFER; } else {
//
// copy the binding
//
pibdst = (PIPRIP_IF_BINDING)pimgod->IMGOD_Buffer;
if (pibsrc) { CopyMemory(pibdst, pibsrc, dwSize); } else { pibdst->IB_AddrCount = 0; }
pibdst->IB_State = 0;
if (IF_IS_ENABLED(pite)) { pibdst->IB_State |= IPRIP_STATE_ENABLED; }
if (IF_IS_BOUND(pite)) { pibdst->IB_State |= IPRIP_STATE_BOUND; } }
pimgod->IMGOD_IfIndex = pite->ITE_Index; } }
RELEASE_IF_LOCK_SHARED();
break; }
case IPRIP_PEER_STATS_ID: {
//
// the peer statistics struct is fixed-length.
//
DWORD dwAddress; PPEER_TABLE pTable; PPEER_TABLE_ENTRY ppte; PIPRIP_PEER_STATS ppssrc, ppsdst;
//
// set the output size right away
//
*pdwOutputSize = sizeof(IPRIP_MIB_GET_OUTPUT_DATA) - 1 + sizeof(IPRIP_PEER_STATS); if (pimgod) { pimgod->IMGOD_TypeID = IPRIP_PEER_STATS_ID; }
pTable = ig.IG_PeerTable; dwAddress = pimgid->IMGID_PeerAddress;
ACQUIRE_PEER_LOCK_SHARED();
//
// retrieve the peer specified
//
ppte = GetPeerByAddress(pTable, dwAddress, dwGetMode, &dwErr);
//
// if no struct was returned, it means that either
// an invalid address was specifed, or GETMODE_NExT
// was attempted on the last peer.
// In either case, we return an error code.
//
// if no buffer was specifed, return ERROR_INSUFFICIENT_BUFFER
// to indicate to the caller that a buffer should be allocated
//
if (ppte == NULL) { if (dwErr == NO_ERROR) { dwErr = ERROR_NOT_FOUND; } } else if (pimgod == NULL) { dwErr = ERROR_INSUFFICIENT_BUFFER; } else {
//
// save the address of the peer retrieved
//
pimgod->IMGOD_PeerAddress = ppte->PTE_Address;
//
// if the buffer is not large enough,
// return an error to indicate it should be enlarged
//
if (dwBufferSize < sizeof(IPRIP_PEER_STATS)) { dwErr = ERROR_INSUFFICIENT_BUFFER; } else {
//
// since access to this structure is not synchronized,
// we must copy it field by field
//
ppssrc = &ppte->PTE_Stats; ppsdst = (PIPRIP_PEER_STATS)pimgod->IMGOD_Buffer;
ppsdst->PS_LastPeerRouteTag = ppssrc->PS_LastPeerRouteTag; ppsdst->PS_LastPeerUpdateTickCount = ppssrc->PS_LastPeerUpdateTickCount; ppsdst->PS_LastPeerUpdateVersion = ppssrc->PS_LastPeerUpdateVersion; ppsdst->PS_BadResponsePacketsFromPeer = ppssrc->PS_BadResponsePacketsFromPeer; ppsdst->PS_BadResponseEntriesFromPeer = ppssrc->PS_BadResponseEntriesFromPeer; } }
RELEASE_PEER_LOCK_SHARED();
break;
}
default: { dwErr = ERROR_INVALID_PARAMETER; } }
return dwErr; }
|