|
|
//============================================================================
// Copyright (c) 1995, Microsoft Corporation
//
// File: api.c
//
// History:
// Abolade Gbadegesin August 31, 1995 Created
//
// BOOTP Relay Agent's interface to Router Manager
//============================================================================
#include "pchbootp.h"
IPBOOTP_GLOBALS ig;
DWORD MibGetInternal( PIPBOOTP_MIB_GET_INPUT_DATA pimgid, PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod, PDWORD pdwOutputSize, DWORD dwGetMode );
BOOL DllStartup( );
BOOL DllCleanup( );
DWORD ProtocolStartup( HANDLE hEventEvent, PSUPPORT_FUNCTIONS pFunctionTable, PVOID pConfig );
DWORD ProtocolCleanup( BOOL bCleanupWinsock );
DWORD BindInterface( IN DWORD dwIndex, IN PVOID pBinding );
DWORD UnBindInterface( IN DWORD dwIndex );
DWORD EnableInterface( IN DWORD dwIndex );
DWORD DisableInterface( IN DWORD dwIndex );
//----------------------------------------------------------------------------
// Function: DLLMAIN
//
// This is the entry-point for IPBOOTP.DLL.
//----------------------------------------------------------------------------
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
//
// This function initializes IPBOOTP's global structure
// in preparation for calls to the API functions exported.
// It creates the global critical section, heap, and router-manager
// event message queue.
//----------------------------------------------------------------------------
BOOL DllStartup( ) {
BOOL bErr; DWORD dwErr;
bErr = FALSE;
do {
ZeroMemory(&ig, sizeof(IPBOOTP_GLOBALS));
try { InitializeCriticalSection(&ig.IG_CS); } except (EXCEPTION_EXECUTE_HANDLER) {
dwErr = GetExceptionCode(); break; }
ig.IG_Status = IPBOOTP_STATUS_STOPPED;
//
// create the global heap for BOOTP
//
ig.IG_GlobalHeap = HeapCreate(0, 0, 0); if (ig.IG_GlobalHeap == NULL) {
dwErr = GetLastError(); break; }
//
// allocate space for the Router manager event queue
//
ig.IG_EventQueue = BOOTP_ALLOC(sizeof(LOCKED_LIST));
if (ig.IG_EventQueue == NULL) {
dwErr = GetLastError(); break; }
//
// now initialize the locked-list allocated
//
try { CREATE_LOCKED_LIST(ig.IG_EventQueue); } except(EXCEPTION_EXECUTE_HANDLER) {
dwErr = GetExceptionCode(); break; }
bErr = TRUE;
} while(FALSE);
if (!bErr) { DllCleanup(); }
return bErr; }
//----------------------------------------------------------------------------
// Function: DllCleanup
//
// This function is called when the IPBOOTP DLL is being unloaded.
// It releases the resources allocated in DllStartup.
//----------------------------------------------------------------------------
BOOL DllCleanup( ) {
BOOL bErr;
bErr = TRUE;
do {
//
// delete and deallocate the event message queue
//
if (ig.IG_EventQueue != NULL) {
if (LOCKED_LIST_CREATED(ig.IG_EventQueue)) { DELETE_LOCKED_LIST(ig.IG_EventQueue); }
BOOTP_FREE(ig.IG_EventQueue); }
//
// destroy the global heap
//
if (ig.IG_GlobalHeap != NULL) {
HeapDestroy(ig.IG_GlobalHeap); }
//
// delete the global critical section
//
DeleteCriticalSection(&ig.IG_CS);
if (ig.IG_LoggingHandle != NULL) RouterLogDeregister(ig.IG_LoggingHandle); if (ig.IG_TraceID != INVALID_TRACEID) { TraceDeregister(ig.IG_TraceID); }
} while(FALSE);
return bErr; }
//----------------------------------------------------------------------------
// Function: ProtocolStartup
//
// This function is called by the router manager to start IPBOOTP.
// It sets up the data structures needed and starts the input thread.
//----------------------------------------------------------------------------
DWORD ProtocolStartup( HANDLE hEventEvent, PSUPPORT_FUNCTIONS pFunctionTable, PVOID pConfig ) {
WSADATA wd; HANDLE hThread; BOOL bCleanupWinsock; DWORD dwErr, dwSize, dwThread; PIPBOOTP_GLOBAL_CONFIG pgcsrc, pgcdst;
ig.IG_TraceID = TraceRegister("IPBOOTP"); ig.IG_LoggingHandle = RouterLogRegister("IPBOOTP");
//
// acquire the global critical section
// while we look at the status code
//
EnterCriticalSection(&ig.IG_CS);
//
// make sure that BOOTP has not already started up
//
if (ig.IG_Status != IPBOOTP_STATUS_STOPPED) {
TRACE0(START, "StartProtocol() has already been called"); LOGWARN0(ALREADY_STARTED, 0);
LeaveCriticalSection(&ig.IG_CS);
return ERROR_CAN_NOT_COMPLETE; }
//
// initialize the global structures:
//
bCleanupWinsock = FALSE;
do { // error break-out loop
TRACE0(START, "IPBOOTP is starting up...");
//
// copy the global configuration passed in:
// find its size, and the allocate space for the copy
//
pgcsrc = (PIPBOOTP_GLOBAL_CONFIG)pConfig; dwSize = GC_SIZEOF(pgcsrc);
pgcdst = BOOTP_ALLOC(dwSize);
if (pgcdst == NULL) {
dwErr = GetLastError(); TRACE2( START, "error %d allocating %d bytes for global config", dwErr, dwSize ); LOGERR0(HEAP_ALLOC_FAILED, dwErr);
break; }
RtlCopyMemory(pgcdst, pgcsrc, dwSize);
ig.IG_Config = pgcdst; ig.IG_LoggingLevel = pgcdst->GC_LoggingLevel;
//
// initialize Windows Sockets
//
dwErr = (DWORD)WSAStartup(MAKEWORD(1,1), &wd);
if (dwErr != NO_ERROR) {
TRACE1(START, "error %d initializing Windows Sockets", dwErr); LOGERR0(INIT_WINSOCK_FAILED, dwErr);
break; }
bCleanupWinsock = TRUE;
//
// create the global structure lock
//
try { CREATE_READ_WRITE_LOCK(&ig.IG_RWL); } except (EXCEPTION_EXECUTE_HANDLER) {
dwErr = GetExceptionCode(); TRACE1(START, "error %d creating synchronization object", dwErr); LOGERR0(CREATE_RWL_FAILED, dwErr);
break; }
//
// initialize the interface table
//
ig.IG_IfTable = BOOTP_ALLOC(sizeof(IF_TABLE));
if (ig.IG_IfTable == NULL) {
dwErr = GetLastError(); TRACE2( START, "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 the receive queue
//
ig.IG_RecvQueue = BOOTP_ALLOC(sizeof(LOCKED_LIST));
if (ig.IG_RecvQueue == NULL) {
dwErr = GetLastError(); TRACE2( START, "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 locked list", dwErr); LOGERR0(INIT_CRITSEC_FAILED, dwErr);
break; }
//
// copy the support-function table and Router Manager event
//
ig.IG_FunctionTable = pFunctionTable;
ig.IG_EventEvent = hEventEvent;
//
// initialize count of active threads, and create the semaphore
// signalled by threads exiting API functions and work functions
//
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", dwErr); LOGERR0(CREATE_SEMAPHORE_FAILED, dwErr);
break; }
//
// create the event used to signal on incoming packets
//
ig.IG_InputEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (ig.IG_InputEvent == NULL) {
dwErr = GetLastError(); TRACE1(START, "error %d creating input-event", dwErr); LOGERR0(CREATE_EVENT_FAILED, dwErr);
break; }
//
// register the InputEvent with the NtdllWait thread
//
if (! RegisterWaitForSingleObject( &ig.IG_InputEventHandle, ig.IG_InputEvent, CallbackFunctionNetworkEvents, NULL, //null context
INFINITE, //no timeout
(WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE) )) {
dwErr = GetLastError(); TRACE1( START, "error %d returned by RegisterWaitForSingleObjectEx", dwErr ); LOGERR0(REGISTER_WAIT_FAILED, dwErr); break;
}
//
// now set the status to running
//
ig.IG_Status = IPBOOTP_STATUS_RUNNING;
#if DBG
//
// register a timer queue with the NtdllTimer thread
//
ig.IG_TimerQueueHandle = CreateTimerQueue();
if (!ig.IG_TimerQueueHandle) {
dwErr = GetLastError(); TRACE1(START, "error %d returned by CreateTimerQueue()", dwErr); LOGERR0(CREATE_TIMER_QUEUE_FAILED, dwErr);
break; }
//
// set timer with NtdllTimer thread to display IPBOOTP MIB periodically
//
ig.IG_MibTraceID = TraceRegisterEx("IPBOOTPMIB", TRACE_USE_CONSOLE);
if (ig.IG_MibTraceID != INVALID_TRACEID) {
if (! CreateTimerQueueTimer( &ig.IG_MibTimerHandle, ig.IG_TimerQueueHandle, CallbackFunctionMibDisplay, NULL, // null context
10000, // display after 10 seconds
10000, // display every 10 seconds
0 // execute in timer thread
)) {
dwErr = GetLastError(); TRACE1( START, "error %d returned by CreateTimerQueueTimer()", dwErr ); break; } }
#endif
TRACE0(START, "IP BOOTP started successfully");
LOGINFO0(STARTED, 0);
LeaveCriticalSection(&ig.IG_CS);
return NO_ERROR;
} while(FALSE);
//
// an error occurred if control-flow brings us here
//
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 cleans up resources used by IPBOOTP while it is
// in operation. Essentially, everything created in ProtocolStartup
// is cleaned up by the function.
//----------------------------------------------------------------------------
DWORD ProtocolCleanup( BOOL bCleanupWinsock ) {
DWORD dwErr;
//
// lock things down while we clean up
//
EnterCriticalSection(&ig.IG_CS);
#if DBG
TraceDeregister(ig.IG_MibTraceID);
#endif
if (ig.IG_InputEvent != NULL) {
CloseHandle(ig.IG_InputEvent); ig.IG_InputEvent = NULL; }
if (ig.IG_ActivitySemaphore != NULL) {
CloseHandle(ig.IG_ActivitySemaphore); ig.IG_ActivitySemaphore = NULL; }
if (ig.IG_RecvQueue != NULL) {
if (LOCKED_LIST_CREATED(ig.IG_RecvQueue)) { DELETE_LOCKED_LIST(ig.IG_RecvQueue); }
BOOTP_FREE(ig.IG_RecvQueue); ig.IG_RecvQueue = NULL; }
if (ig.IG_IfTable != NULL) {
if (IF_TABLE_CREATED(ig.IG_IfTable)) { DeleteIfTable(ig.IG_IfTable); }
BOOTP_FREE(ig.IG_IfTable); ig.IG_IfTable = NULL; }
if (READ_WRITE_LOCK_CREATED(&ig.IG_RWL)) {
try { DELETE_READ_WRITE_LOCK(&ig.IG_RWL); } except (EXCEPTION_EXECUTE_HANDLER) { dwErr = GetExceptionCode(); } }
if (bCleanupWinsock) { WSACleanup(); }
if (ig.IG_Config != NULL) {
BOOTP_FREE(ig.IG_Config); ig.IG_Config = NULL; }
ig.IG_Status = IPBOOTP_STATUS_STOPPED;
LeaveCriticalSection(&ig.IG_CS);
return NO_ERROR; }
//----------------------------------------------------------------------------
// Function: RegisterProtocol
//
// This function is called by the router manager
// to retrieve information about IPBOOTP's capabilities
//----------------------------------------------------------------------------
DWORD APIENTRY RegisterProtocol( IN OUT PMPR_ROUTING_CHARACTERISTICS pRoutingChar, IN OUT PMPR_SERVICE_CHARACTERISTICS pServiceChar ) { if(pRoutingChar->dwProtocolId != MS_IP_BOOTP) { return ERROR_NOT_SUPPORTED; }
pServiceChar->fSupportedFunctionality = 0;
if(!(pRoutingChar->fSupportedFunctionality & RF_ROUTING)) { return ERROR_NOT_SUPPORTED; }
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 = NULL;
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
//
// This function is called by the router manager
// to start IPBOOTP.
//----------------------------------------------------------------------------
DWORD WINAPI StartProtocol ( HANDLE NotificationEvent, SUPPORT_FUNCTIONS *SupportFunctions, LPVOID GlobalInfo, ULONG StructureVersion, ULONG StructureSize, ULONG StructureCount ) { return ProtocolStartup(NotificationEvent, SupportFunctions, GlobalInfo); }
//----------------------------------------------------------------------------
// Function: StartComplete
//
// This function is called by the router manager
// to start IPBOOTP.
//----------------------------------------------------------------------------
DWORD WINAPI StartComplete ( VOID ) { return NO_ERROR; }
//----------------------------------------------------------------------------
// Function: StopProtocol
//
// This function notifies all active threads to stop, and frees resources
// used by IP BOOTP
//----------------------------------------------------------------------------
DWORD APIENTRY StopProtocol( VOID ) {
DWORD dwErr; LONG lThreadCount; HANDLE WaitHandle;
//
// make sure IPBOOTP has not already stopped
//
EnterCriticalSection(&ig.IG_CS);
if (ig.IG_Status != IPBOOTP_STATUS_RUNNING) {
LeaveCriticalSection(&ig.IG_CS); return ERROR_CAN_NOT_COMPLETE; }
TRACE0(ENTER, "entering StopProtocol");
//
// update the status to prevent any APIs or worker-functions from running
//
ig.IG_Status = IPBOOTP_STATUS_STOPPING;
//
// see how many threads are already in API calls
// or in worker-function code
//
lThreadCount = ig.IG_ActivityCount;
TRACE1(STOP, "%d threads are active in IPBOOTP", lThreadCount);
LeaveCriticalSection(&ig.IG_CS);
//
// wait for active threads to stop
//
while (lThreadCount-- > 0) { WaitForSingleObject(ig.IG_ActivitySemaphore, INFINITE); }
//
// deregister the mib timer from the Ntdll threads
// This has to be done outside IG_CS lock.
//
#if DBG
DeleteTimerQueueEx(ig.IG_TimerQueueHandle, INVALID_HANDLE_VALUE); #endif
//
// set the handle to NULL, so that Unregister wont be called
//
WaitHandle = InterlockedExchangePointer(&ig.IG_InputEventHandle, NULL); if (WaitHandle) { UnregisterWaitEx( WaitHandle, INVALID_HANDLE_VALUE ) ; }
//
// enter the critical section and leave,
// to make certain all the threads have returned from LeaveBootpWorker
//
EnterCriticalSection(&ig.IG_CS); LeaveCriticalSection(&ig.IG_CS);
//
// now all threads have stopped
//
TRACE0(STOP, "all threads stopped, BOOTP is cleaning up resources");
LOGINFO0(STOPPED, 0);
ProtocolCleanup(TRUE);
return NO_ERROR; }
//----------------------------------------------------------------------------
// Function: GetGlobalInfo
//
// Copies BOOTP's global config into the buffer provided.
//----------------------------------------------------------------------------
DWORD WINAPI GetGlobalInfo ( PVOID OutGlobalInfo, PULONG GlobalInfoSize, PULONG StructureVersion, PULONG StructureSize, PULONG StructureCount ) { DWORD dwErr = NO_ERROR, dwSize;
if (!ENTER_BOOTP_API()) { return ERROR_CAN_NOT_COMPLETE; }
TRACE2(ENTER, "entering GetGlobalInfo: 0x%08x 0x%08x", OutGlobalInfo, GlobalInfoSize);
//
// in order to do anything, we need a valid size pointer
//
if (GlobalInfoSize == NULL) { dwErr = ERROR_INVALID_PARAMETER; } else {
//
// check the size of the config block passed in
// and copy the config if the buffer is large enough
//
ACQUIRE_READ_LOCK(&ig.IG_RWL);
dwSize = GC_SIZEOF(ig.IG_Config); if (*GlobalInfoSize < dwSize) { dwErr = ERROR_INSUFFICIENT_BUFFER; } else if (OutGlobalInfo != NULL) {
RtlCopyMemory( OutGlobalInfo, ig.IG_Config, dwSize ); }
*GlobalInfoSize = dwSize;
if (StructureSize) *StructureSize = *GlobalInfoSize; if (StructureCount) *StructureCount = 1; if (StructureVersion) *StructureVersion = BOOTP_CONFIG_VERSION_500; RELEASE_READ_LOCK(&ig.IG_RWL); }
TRACE1(LEAVE, "leaving GetGlobalInfo: %d", dwErr);
LEAVE_BOOTP_API();
return dwErr; }
//----------------------------------------------------------------------------
// Function: SetGlobalInfo
//
// Copies over the specified configuration .
//----------------------------------------------------------------------------
DWORD WINAPI SetGlobalInfo ( PVOID GlobalInfo, ULONG StructureVersion, ULONG StructureSize, ULONG StructureCount ) { DWORD dwErr, dwSize; PIPBOOTP_GLOBAL_CONFIG pgcsrc, pgcdst;
if (!GlobalInfo || !ENTER_BOOTP_API()) { return ERROR_CAN_NOT_COMPLETE; }
TRACE1(ENTER, "entering SetGlobalInfo: %p", GlobalInfo);
ACQUIRE_WRITE_LOCK(&ig.IG_RWL);
pgcsrc = (PIPBOOTP_GLOBAL_CONFIG)GlobalInfo; dwSize = GC_SIZEOF(pgcsrc);
//
// allocate memory for the new config block, and copy it over
//
pgcdst = BOOTP_ALLOC(dwSize);
if (pgcdst == NULL) {
dwErr = GetLastError(); TRACE2( CONFIG, "error %d allocating %d bytes for global config", dwErr, dwSize ); LOGERR0(HEAP_ALLOC_FAILED, dwErr); } else {
RtlCopyMemory( pgcdst, pgcsrc, dwSize );
BOOTP_FREE(ig.IG_Config); ig.IG_Config = pgcdst;
dwErr = NO_ERROR; }
RELEASE_WRITE_LOCK(&ig.IG_RWL);
TRACE1(LEAVE, "leaving SetGlobalInfo: %d", dwErr);
LEAVE_BOOTP_API();
return dwErr; }
//----------------------------------------------------------------------------
// Function: AddInterface
//
// Adds an interface with the specified index and configuration.
//----------------------------------------------------------------------------
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; PIF_TABLE pTable;
if (!ENTER_BOOTP_API()) { return ERROR_CAN_NOT_COMPLETE; }
TRACE3( ENTER, "entering AddInterface: %d %d %p", InterfaceIndex, InterfaceType, InterfaceInfo );
pTable = ig.IG_IfTable;
ACQUIRE_WRITE_LOCK(&pTable->IT_RWL);
dwErr = CreateIfEntry(pTable, InterfaceIndex, InterfaceInfo);
RELEASE_WRITE_LOCK(&pTable->IT_RWL);
TRACE1(LEAVE, "leaving AddInterface: %d", dwErr);
LEAVE_BOOTP_API();
return dwErr; }
//----------------------------------------------------------------------------
// Function: DeleteInterface
//
// Removes the interface with the specified index.
//----------------------------------------------------------------------------
DWORD APIENTRY DeleteInterface( IN DWORD dwIndex ) {
DWORD dwErr; PIF_TABLE pTable;
if (!ENTER_BOOTP_API()) { return ERROR_CAN_NOT_COMPLETE; }
TRACE1(ENTER, "entering DeleteInterface: %d", dwIndex);
pTable = ig.IG_IfTable;
ACQUIRE_WRITE_LOCK(&pTable->IT_RWL);
dwErr = DeleteIfEntry(pTable, dwIndex);
RELEASE_WRITE_LOCK(&pTable->IT_RWL);
TRACE1(LEAVE, "leaving DeleteInterface: %d", dwErr);
LEAVE_BOOTP_API();
return dwErr; }
//----------------------------------------------------------------------------
// Function: GetEventMessage
//
// Returns the first event in the ROuter Manager event queue, if any.
//----------------------------------------------------------------------------
DWORD APIENTRY GetEventMessage( OUT ROUTING_PROTOCOL_EVENTS *pEvent, OUT MESSAGE *pResult ) {
DWORD dwErr; PLOCKED_LIST pll;
if (!ENTER_BOOTP_API()) { return ERROR_CAN_NOT_COMPLETE; }
TRACE2(ENTER, "entering GetEventMessage: 0x%08x 0x%08x", pEvent, pResult);
pll = ig.IG_EventQueue;
ACQUIRE_LIST_LOCK(pll);
dwErr = DequeueEvent(pll, pEvent, pResult);
RELEASE_LIST_LOCK(pll);
TRACE1(LEAVE, "leaving GetEventMessage: %d", dwErr);
LEAVE_BOOTP_API();
return dwErr; }
//----------------------------------------------------------------------------
// Function: GetInterfaceConfigInfo
//
// Returns the configuration for the specified interface.
//----------------------------------------------------------------------------
DWORD WINAPI GetInterfaceConfigInfo ( ULONG InterfaceIndex, PVOID OutInterfaceInfo, PULONG InterfaceInfoSize, PULONG StructureVersion, PULONG StructureSize, PULONG StructureCount ) { PIF_TABLE pTable; DWORD dwErr, dwSize; PIF_TABLE_ENTRY pite;
if (!ENTER_BOOTP_API()) { return ERROR_CAN_NOT_COMPLETE; }
TRACE3( ENTER, "entering GetInterfaceConfigInfo: %d %p %p", InterfaceIndex, InterfaceInfoSize, OutInterfaceInfo );
//
// in order to do anything, we need a valid size pointer
//
if (InterfaceInfoSize == NULL) { dwErr = ERROR_INVALID_PARAMETER; } else {
pTable = ig.IG_IfTable;
ACQUIRE_READ_LOCK(&pTable->IT_RWL);
//
// retrieve the interface to be re-configured
//
pite = GetIfByIndex(pTable, InterfaceIndex);
if (pite == NULL) { dwErr = ERROR_INVALID_PARAMETER; } else {
//
// compute the interface configuration's size,
// and copy the config to the caller's buffer
// if the caller's buffer is large enough
//
dwSize = IC_SIZEOF(pite->ITE_Config);
if (*InterfaceInfoSize < dwSize || OutInterfaceInfo == NULL) { dwErr = ERROR_INSUFFICIENT_BUFFER; } else {
PIPBOOTP_IF_CONFIG picdst = OutInterfaceInfo;
CopyMemory(picdst, pite->ITE_Config, dwSize);
picdst->IC_State = 0;
if (IF_IS_ENABLED(pite)) { picdst->IC_State |= IPBOOTP_STATE_ENABLED; }
if (IF_IS_BOUND(pite)) { picdst->IC_State |= IPBOOTP_STATE_BOUND; }
dwErr = NO_ERROR; }
*InterfaceInfoSize = dwSize; if (StructureSize) *StructureSize = *InterfaceInfoSize; if (StructureCount) *StructureCount = 1; if (StructureVersion) *StructureVersion = BOOTP_CONFIG_VERSION_500; }
RELEASE_READ_LOCK(&pTable->IT_RWL); }
TRACE1(LEAVE, "leaving GetInterfaceConfigInfo: %d", dwErr);
LEAVE_BOOTP_API();
return dwErr; }
//----------------------------------------------------------------------------
// Function: SetInterfaceConfigInfo
//
// Copies over the specified interface configuration.
//----------------------------------------------------------------------------
DWORD WINAPI SetInterfaceConfigInfo ( ULONG InterfaceIndex, PVOID InterfaceInfo, ULONG StructureVersion, ULONG StructureSize, ULONG StructureCount ) { PIF_TABLE pTable; DWORD dwErr, dwSize; PIF_TABLE_ENTRY pite; PIPBOOTP_IF_CONFIG picsrc, picdst;
if (!ENTER_BOOTP_API()) { return ERROR_CAN_NOT_COMPLETE; }
TRACE2( ENTER, "entering SetInterfaceConfigInfo: %d %p", InterfaceIndex, InterfaceInfo );
pTable = ig.IG_IfTable;
ACQUIRE_WRITE_LOCK(&pTable->IT_RWL);
dwErr = ConfigureIfEntry(pTable, InterfaceIndex, InterfaceInfo);
RELEASE_WRITE_LOCK(&pTable->IT_RWL);
TRACE1(LEAVE, "leaving SetInterfaceConfigInfo: %d", dwErr);
LEAVE_BOOTP_API();
return dwErr; }
DWORD WINAPI InterfaceStatus( ULONG InterfaceIndex, BOOL InterfaceActive, DWORD StatusType, PVOID StatusInfo ) { DWORD dwResult;
if (!ENTER_BOOTP_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_BOOTP_API();
return dwResult; }
//----------------------------------------------------------------------------
// Function: BindInterface
//
// Sets the IP address and network mask for the specified interface.
//----------------------------------------------------------------------------
DWORD APIENTRY BindInterface( IN DWORD dwIndex, IN PVOID pBinding ) {
DWORD dwErr; PIF_TABLE pTable;
TRACE2(ENTER, "entering BindInterface: %d 0x%08x", dwIndex, pBinding);
pTable = ig.IG_IfTable;
ACQUIRE_WRITE_LOCK(&pTable->IT_RWL);
dwErr = BindIfEntry(pTable, dwIndex, pBinding);
RELEASE_WRITE_LOCK(&pTable->IT_RWL);
TRACE1(LEAVE, "leaving BindInterface: %d", dwErr);
return dwErr; }
//----------------------------------------------------------------------------
// Function: UnBindInterface
//
// Removes the IP address associated with the specified interface
//----------------------------------------------------------------------------
DWORD APIENTRY UnBindInterface( IN DWORD dwIndex ) {
DWORD dwErr; PIF_TABLE pTable;
TRACE1(ENTER, "entering UnBindInterface: %d", dwIndex);
pTable = ig.IG_IfTable;
ACQUIRE_WRITE_LOCK(&pTable->IT_RWL);
dwErr = UnBindIfEntry(pTable, dwIndex);
RELEASE_WRITE_LOCK(&pTable->IT_RWL);
TRACE1(LEAVE, "leaving UnBindInterface: %d", dwErr);
return dwErr; }
//----------------------------------------------------------------------------
// Function: EnableInterface
//
//----------------------------------------------------------------------------
DWORD APIENTRY EnableInterface( IN DWORD dwIndex ) {
DWORD dwErr; PIF_TABLE pTable;
TRACE1(ENTER, "entering EnableInterface: %d", dwIndex);
pTable = ig.IG_IfTable;
ACQUIRE_WRITE_LOCK(&pTable->IT_RWL);
dwErr = EnableIfEntry(pTable, dwIndex);
RELEASE_WRITE_LOCK(&pTable->IT_RWL);
TRACE1(LEAVE, "leaving EnableInterface: %d", dwErr);
return dwErr; }
//----------------------------------------------------------------------------
// Function: DisableInterface
//
//----------------------------------------------------------------------------
DWORD APIENTRY DisableInterface( IN DWORD dwIndex ) {
DWORD dwErr; PIF_TABLE pTable; PIF_TABLE_ENTRY pite;
TRACE1(ENTER, "entering DisableInterface: %d", dwIndex);
pTable = ig.IG_IfTable;
ACQUIRE_WRITE_LOCK(&pTable->IT_RWL);
dwErr = DisableIfEntry(pTable, dwIndex);
RELEASE_WRITE_LOCK(&pTable->IT_RWL);
TRACE1(LEAVE, "leaving DisableInterface: %d", dwErr);
return dwErr; }
//----------------------------------------------------------------------------
// Function: DoUpdateRoutes
//
// This API is unsupported since BOOTP is not a routing protocol.
//----------------------------------------------------------------------------
DWORD APIENTRY DoUpdateRoutes( IN DWORD dwIndex ) {
return ERROR_CAN_NOT_COMPLETE; }
//----------------------------------------------------------------------------
// Function: MibCreate
//
// BOOTP does not have create-able MIB fields.
//----------------------------------------------------------------------------
DWORD APIENTRY MibCreate( IN DWORD dwInputSize, IN PVOID pInputData ) {
return ERROR_CAN_NOT_COMPLETE; }
//----------------------------------------------------------------------------
// Function: MibDelete
//
// BOOTP does not have delete-able MIB fields
//----------------------------------------------------------------------------
DWORD APIENTRY MibDelete( IN DWORD dwInputSize, IN PVOID pInputData ) {
return ERROR_CAN_NOT_COMPLETE; }
//----------------------------------------------------------------------------
// Function: MibSet
//
// This is called to modify writable MIB variables.
// The writable entries are the global config and interface config.
//----------------------------------------------------------------------------
DWORD APIENTRY MibSet( IN DWORD dwInputSize, IN PVOID pInputData ) {
DWORD dwErr; PIPBOOTP_MIB_SET_INPUT_DATA pimsid;
if (!ENTER_BOOTP_API()) { return ERROR_CAN_NOT_COMPLETE; }
TRACE2(ENTER, "entering MibSet: %d 0x%08x", dwInputSize, pInputData);
dwErr = NO_ERROR;
do { // breakout loop
//
// make certain the parameters are acceptable
//
if (pInputData == NULL || dwInputSize < sizeof(IPBOOTP_MIB_SET_INPUT_DATA)) {
dwErr = ERROR_INVALID_PARAMETER; break; }
//
// see which entry type is to be set
//
pimsid = (PIPBOOTP_MIB_SET_INPUT_DATA)pInputData;
switch(pimsid->IMSID_TypeID) {
case IPBOOTP_GLOBAL_CONFIG_ID: {
PIPBOOTP_GLOBAL_CONFIG pigc;
//
// make sure the buffer is big enough
// to hold a global config block
//
if (pimsid->IMSID_BufferSize < sizeof(IPBOOTP_GLOBAL_CONFIG)) { dwErr = ERROR_INSUFFICIENT_BUFFER; break; }
//
// call the router manager API to set the config
//
dwErr = SetGlobalInfo(pimsid->IMSID_Buffer, 1, sizeof(IPBOOTP_GLOBAL_CONFIG), 1);
if (dwErr == NO_ERROR) {
//
// the set succeeded, so notify the router manager
// that the global config has changed and should be saved
//
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 IPBOOTP_IF_CONFIG_ID: {
DWORD dwSize; PIF_TABLE pTable; PIF_TABLE_ENTRY pite; PIPBOOTP_IF_CONFIG pic;
//
// make sure the buffer is big enough
// to hold an interface config block
//
if (pimsid->IMSID_BufferSize < sizeof(IPBOOTP_IF_CONFIG)) { dwErr = ERROR_INSUFFICIENT_BUFFER; break; }
pic = (PIPBOOTP_IF_CONFIG)pimsid->IMSID_Buffer;
pTable = ig.IG_IfTable;
ACQUIRE_WRITE_LOCK(&pTable->IT_RWL);
//
// find the interface and update its config
//
pite = GetIfByIndex( pTable, pimsid->IMSID_IfIndex );
if (pite == NULL) {
TRACE1( CONFIG, "MibSet: could not find interface %d", pimsid->IMSID_IfIndex );
dwErr = ERROR_INVALID_PARAMETER; } else {
//
// configure the interface
//
dwErr = ConfigureIfEntry(pTable, pite->ITE_Index, pic); }
if (dwErr == NO_ERROR) {
//
// notify Router manager that config has changed
//
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_WRITE_LOCK(&pTable->IT_RWL);
break; } default: { dwErr = ERROR_INVALID_PARAMETER; } } } while(FALSE);
LEAVE_BOOTP_API();
return dwErr; }
//----------------------------------------------------------------------------
// Function: MibGet
//
// This function retrieves a MIB entry.
//----------------------------------------------------------------------------
DWORD APIENTRY MibGet( IN DWORD dwInputSize, IN PVOID pInputData, IN OUT PDWORD pdwOutputSize, OUT PVOID pOutputData ) {
DWORD dwErr; PIPBOOTP_MIB_GET_INPUT_DATA pimgid; PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod;
if (!ENTER_BOOTP_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(IPBOOTP_MIB_GET_INPUT_DATA) || pdwOutputSize == NULL) { dwErr = ERROR_INVALID_PARAMETER; } else {
//
// invoke the internal function for retrieving the MIB
//
pimgid = (PIPBOOTP_MIB_GET_INPUT_DATA)pInputData; pimgod = (PIPBOOTP_MIB_GET_OUTPUT_DATA)pOutputData;
dwErr = MibGetInternal(pimgid, pimgod, pdwOutputSize, GETMODE_EXACT); }
TRACE1(LEAVE, "leaving MibGet: %d", dwErr);
LEAVE_BOOTP_API();
return dwErr; }
//----------------------------------------------------------------------------
// Function: MibGetFirst
//
// This function retrieve a MIB entry from one of the MIB tables,
// but it differs from MibGet in that it always returns the first entry
// in the table specified.
//----------------------------------------------------------------------------
DWORD APIENTRY MibGetFirst( IN DWORD dwInputSize, IN PVOID pInputData, IN OUT PDWORD pdwOutputSize, OUT PVOID pOutputData ) {
DWORD dwErr; PIPBOOTP_MIB_GET_INPUT_DATA pimgid; PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod;
if (!ENTER_BOOTP_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(IPBOOTP_MIB_GET_INPUT_DATA) || pdwOutputSize == NULL) { dwErr = ERROR_INVALID_PARAMETER; } else {
pimgid = (PIPBOOTP_MIB_GET_INPUT_DATA)pInputData; pimgod = (PIPBOOTP_MIB_GET_OUTPUT_DATA)pOutputData;
dwErr = MibGetInternal(pimgid, pimgod, pdwOutputSize, GETMODE_FIRST); }
TRACE1(LEAVE, "leaving MibGetFirst: %d", dwErr);
LEAVE_BOOTP_API();
return dwErr; }
//----------------------------------------------------------------------------
// Function: MibGetNext
//
// This function retrieves a MIB entry from one of the MIB tables.
// It differs from MibGet() and MibGetFirst() in that the input
// specifies the index of a MIB entry, and this entry returns the MIB entry
// which is AFTER the entry whose index is specified.
//
// If the index specified is that of the last entry in the specified table,
// this function wraps to the FIRST entry in 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
// will return the first entry in the interface config table.
//----------------------------------------------------------------------------
DWORD APIENTRY MibGetNext( IN DWORD dwInputSize, IN PVOID pInputData, IN OUT PDWORD pdwOutputSize, OUT PVOID pOutputData ) {
DWORD dwErr, dwOutSize = 0, dwBufSize = 0; PIPBOOTP_MIB_GET_INPUT_DATA pimgid; PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod;
if (!ENTER_BOOTP_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(IPBOOTP_MIB_GET_INPUT_DATA) || pdwOutputSize == NULL) { dwErr = ERROR_INVALID_PARAMETER; } else {
pimgid = (PIPBOOTP_MIB_GET_INPUT_DATA)pInputData; pimgod = (PIPBOOTP_MIB_GET_OUTPUT_DATA)pOutputData;
dwOutSize = *pdwOutputSize;
dwErr = MibGetInternal(pimgid, pimgod, pdwOutputSize, GETMODE_NEXT);
if (dwErr == ERROR_NO_MORE_ITEMS) {
//
// wrap to the first entry in the next table
//
TRACE1( CONFIG, "MibGetNext is wrapping to table %d", pimgid->IMGID_TypeID + 1 );
//
// restore the size passed in
//
*pdwOutputSize = dwOutSize;
//
// wrap to the next table by incrementing the type ID
//
++pimgid->IMGID_TypeID; dwErr = MibGetInternal( pimgid, pimgod, pdwOutputSize, GETMODE_FIRST ); --pimgid->IMGID_TypeID; } }
TRACE1(LEAVE, "leaving MibGetNext: %d", dwErr);
LEAVE_BOOTP_API();
return dwErr; }
//----------------------------------------------------------------------------
// Function: MibGetInternal
//
// This function handles the structure queries necessary to read MIB data.
// Each table exposed by IPBOOTP supports three types of queries:
// EXACT, FIRST, and NEXT, which correspond to the functions MibGet(),
// MibGetFirst(), and MibGetNext() respectively.
//----------------------------------------------------------------------------
DWORD MibGetInternal( PIPBOOTP_MIB_GET_INPUT_DATA pimgid, PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod, PDWORD pdwOutputSize, DWORD dwGetMode ) {
DWORD dwErr, dwBufSize, dwSize; ULONG ulVersion, ulSize,ulCount;
dwErr = NO_ERROR;
//
// first we use pdwOutputSize to compute the size of the buffer
// available (i.e. the size of IMGOD_Buffer
//
if (pimgod == NULL || *pdwOutputSize < sizeof(IPBOOTP_MIB_GET_OUTPUT_DATA)) { dwBufSize = 0; } else { dwBufSize = *pdwOutputSize - sizeof(IPBOOTP_MIB_GET_OUTPUT_DATA) + 1; }
*pdwOutputSize = 0;
//
// determine which type of data is to be returned
//
switch (pimgid->IMGID_TypeID) {
case IPBOOTP_GLOBAL_CONFIG_ID: {
//
// the global config struct is variable-length,
// so we wait until it has been retrieved before setting the size;
// GETMODE_NEXT is invalid since there is only one global config
//
if (pimgod) { pimgod->IMGOD_TypeID = IPBOOTP_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 it will set the required size. Then all we need to do
// is write out the size set by GetGlobalInfo.
//
if (pimgod == NULL) { dwErr = GetGlobalInfo(NULL, &dwBufSize, NULL, NULL, NULL); } else {
dwErr = GetGlobalInfo( pimgod->IMGOD_Buffer, &dwBufSize, &ulVersion, &ulSize, &ulCount ); }
*pdwOutputSize = sizeof(IPBOOTP_MIB_GET_OUTPUT_DATA) - 1 + dwBufSize;
break; }
case IPBOOTP_IF_STATS_ID: {
//
// the interface stats struct is fixed-length,
// with as many entries as there are interfaces
//
PIF_TABLE pTable; PIF_TABLE_ENTRY pite; PIPBOOTP_IF_STATS pissrc, pisdst;
//
// set the size needed right away
//
*pdwOutputSize = sizeof(IPBOOTP_MIB_GET_OUTPUT_DATA) - 1 + sizeof(IPBOOTP_IF_STATS); if (pimgod) { pimgod->IMGOD_TypeID = IPBOOTP_IF_STATS_ID; }
pTable = ig.IG_IfTable;
ACQUIRE_READ_LOCK(&pTable->IT_RWL);
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
// GETMODE_NEXT was attempted on the last interface,
// in which case dwErr contains ERROR_NO_MORE_ITEMS.
// In any case, we make sure dwErr contains an error code
// and then return.
//
if (pite == NULL) { if (dwErr == NO_ERROR) { dwErr = ERROR_INVALID_PARAMETER; } } else if (pimgod == NULL) { dwErr = ERROR_INSUFFICIENT_BUFFER; } else {
//
// write the index of the interface
// whose stats are to be returned
//
pimgod->IMGOD_IfIndex = pite->ITE_Index;
//
// if the buffer is large enough, copy the stats to it
//
if (dwBufSize < sizeof(IPBOOTP_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 = (PIPBOOTP_IF_STATS)pimgod->IMGOD_Buffer;
pisdst->IS_State = 0;
if (IF_IS_ENABLED(pite)) { pisdst->IS_State |= IPBOOTP_STATE_ENABLED; }
if (IF_IS_BOUND(pite)) { pisdst->IS_State |= IPBOOTP_STATE_BOUND; }
pisdst->IS_SendFailures = pissrc->IS_SendFailures; pisdst->IS_ReceiveFailures = pissrc->IS_ReceiveFailures; pisdst->IS_ArpUpdateFailures = pissrc->IS_ArpUpdateFailures; pisdst->IS_RequestsReceived = pissrc->IS_RequestsReceived; pisdst->IS_RequestsDiscarded = pissrc->IS_RequestsDiscarded; pisdst->IS_RepliesReceived = pissrc->IS_RepliesReceived; pisdst->IS_RepliesDiscarded = pissrc->IS_RepliesDiscarded; } }
RELEASE_READ_LOCK(&pTable->IT_RWL);
break; }
case IPBOOTP_IF_CONFIG_ID: {
PIF_TABLE pTable; PIF_TABLE_ENTRY pite; PIPBOOTP_IF_CONFIG picsrc, picdst;
if (pimgod) { pimgod->IMGOD_TypeID = IPBOOTP_IF_CONFIG_ID; }
pTable = ig.IG_IfTable;
ACQUIRE_READ_LOCK(&pTable->IT_RWL);
//
// retrieve the interface whose config is to be read
//
pite = GetIfByListIndex( pTable, pimgid->IMGID_IfIndex, dwGetMode, &dwErr );
//
// if the interface was not 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_INVALID_PARAMETER; } } else {
picsrc = pite->ITE_Config; dwSize = IC_SIZEOF(picsrc); *pdwOutputSize = sizeof(IPBOOTP_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 (dwBufSize < dwSize) { dwErr = ERROR_INSUFFICIENT_BUFFER; } else {
//
// copy the configuration
//
picdst = (PIPBOOTP_IF_CONFIG)pimgod->IMGOD_Buffer; CopyMemory(picdst, picsrc, dwSize);
picdst->IC_State = 0;
if (IF_IS_ENABLED(pite)) { picdst->IC_State |= IPBOOTP_STATE_ENABLED; }
if (IF_IS_BOUND(pite)) { picdst->IC_State |= IPBOOTP_STATE_BOUND; } }
pimgod->IMGOD_IfIndex = pite->ITE_Index; }
}
RELEASE_READ_LOCK(&pTable->IT_RWL);
break; }
case IPBOOTP_IF_BINDING_ID: {
PIF_TABLE pTable; PIF_TABLE_ENTRY pite; PIPBOOTP_IF_BINDING pibsrc, pibdst;
if (pimgod) { pimgod->IMGOD_TypeID = IPBOOTP_IF_BINDING_ID; }
pTable = ig.IG_IfTable;
ACQUIRE_READ_LOCK(&pTable->IT_RWL);
//
// retrieve the interface whose binding is to be read
//
pite = GetIfByListIndex( pTable, pimgid->IMGID_IfIndex, dwGetMode, &dwErr );
//
// if the interface was not 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_INVALID_PARAMETER; } } else {
pibsrc = pite->ITE_Binding; if (pibsrc == NULL ) { TRACE1( IF, "MibGetInternal: interface %d not bound", pimgid->IMGID_IfIndex );
dwErr = ERROR_INVALID_PARAMETER; } else {
dwSize = (pibsrc ? IPBOOTP_IF_BINDING_SIZE(pibsrc) : sizeof(IPBOOTP_IF_BINDING)); *pdwOutputSize = sizeof(IPBOOTP_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 (dwBufSize < dwSize) { dwErr = ERROR_INSUFFICIENT_BUFFER; } else {
//
// copy the binding
//
pibdst = (PIPBOOTP_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 |= IPBOOTP_STATE_ENABLED; }
if (IF_IS_BOUND(pite)) { pibdst->IB_State |= IPBOOTP_STATE_BOUND; } }
pimgod->IMGOD_IfIndex = pite->ITE_Index; }
}
}
RELEASE_READ_LOCK(&pTable->IT_RWL);
break; }
default: { dwErr = ERROR_INVALID_PARAMETER; } }
return dwErr; }
//----------------------------------------------------------------------------
// Function: EnableDhcpInformServer
//
// Called to supply the address of a server to whom DHCP inform messages
// will be redirected. Note that this is an exported routine, invoked
// in the context of the caller's process, whatever that might be;
// the assumption is that it will be called from within the router process.
//
// If the relay-agent is configured, then this sets an address which will
// be picked up in 'ProcessRequest' for every incoming request.
// If the relay-agent is not configured, the routine has no effect.
// If the relay-agent is configured *after* this routine is called,
// then the DHCP inform server will be encountered as soon as the relay-agent
// starts, since it is saved directly into the relay-agents 'IPBOOTP_GLOBALS'.
//----------------------------------------------------------------------------
VOID APIENTRY EnableDhcpInformServer( DWORD DhcpInformServer ) { InterlockedExchange(&ig.IG_DhcpInformServer, DhcpInformServer); }
//----------------------------------------------------------------------------
// Function: DisableDhcpInformServer
//
// Called to clear the previously-enabled DHCP inform server, if any.
//----------------------------------------------------------------------------
VOID APIENTRY DisableDhcpInformServer( VOID ) { InterlockedExchange(&ig.IG_DhcpInformServer, 0); }
|