windows-nt/Source/XPSP1/NT/net/rras/ip/bootp/api.c

2436 lines
55 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
//============================================================================
// 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);
}