2436 lines
55 KiB
C
2436 lines
55 KiB
C
//============================================================================
|
|
// 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);
|
|
}
|
|
|