Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1414 lines
35 KiB

//============================================================================
// Copyright (c) 1995, Microsoft Corporation
//
// File: work.c
//
// History:
// Abolade Gbadegesin August 31, 1995 Created
//
// Worker function implementation
//============================================================================
#include "pchbootp.h"
//----------------------------------------------------------------------------
// Function: CallbackFunctionNetworkEvents
//
// This function runs in the context of the ntdll wait thread. Using
// QueueBootpWorker ensures that the bootp dll is running
//----------------------------------------------------------------------------
VOID
CallbackFunctionNetworkEvents(
PVOID pvContext,
BOOLEAN NotUsed
) {
HANDLE WaitHandle;
if (!ENTER_BOOTP_API()) { return; }
//
// set the handle to NULL, so that Unregister wont be called
//
WaitHandle = InterlockedExchangePointer(&ig.IG_InputEventHandle, NULL);
if (WaitHandle) {
UnregisterWaitEx( WaitHandle, NULL ) ;
}
QueueBootpWorker(WorkerFunctionNetworkEvents, pvContext);
LEAVE_BOOTP_API();
return;
}
//----------------------------------------------------------------------------
// Function: WorkerFunctionNetworkEvents
//
// This function enumerates the input events on each interface and processes
// any incoming input packets. Queued by CallbackFunctionNetworkEvents
//----------------------------------------------------------------------------
VOID
WorkerFunctionNetworkEvents(
PVOID pvContextNotused
) {
DWORD i, dwErr;
PIF_TABLE pTable;
PIPBOOTP_IF_CONFIG pic;
PIPBOOTP_IF_BINDING pib;
PIPBOOTP_IP_ADDRESS paddr;
PIF_TABLE_ENTRY pite;
PLIST_ENTRY ple, phead;
WSANETWORKEVENTS wsane;
if (!ENTER_BOOTP_WORKER()) { return; }
pTable = ig.IG_IfTable;
ACQUIRE_READ_LOCK(&pTable->IT_RWL);
//
// go through the list of active interfaces
// processing sockets which are read-ready
//
phead = &pTable->IT_ListByAddress;
for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByAddress);
pic = pite->ITE_Config;
pib = pite->ITE_Binding;
paddr = IPBOOTP_IF_ADDRESS_TABLE(pib);
for (i = 0; i < pib->IB_AddrCount; i++, paddr++) {
if (pite->ITE_Sockets[i] == INVALID_SOCKET) { continue; }
//
// enumerate network events to see whether
// any packets have arrived on this interface
//
dwErr = WSAEnumNetworkEvents(pite->ITE_Sockets[i], NULL, &wsane);
if (dwErr != NO_ERROR) {
LPSTR lpszAddr = INET_NTOA(paddr->IA_Address);
TRACE3(
RECEIVE, "error %d checking for input on interface %d (%s)",
dwErr, pite->ITE_Index, lpszAddr
);
LOGWARN1(ENUM_NETWORK_EVENTS_FAILED, lpszAddr, dwErr);
continue;
}
//
// see if the input bit is set
//
if (!(wsane.lNetworkEvents & FD_READ)) { continue; }
//
// the input flag is set, now see if there was an error
//
if (wsane.iErrorCode[FD_READ_BIT] != NO_ERROR) {
LPSTR lpszAddr = INET_NTOA(paddr->IA_Address);
TRACE3(
RECEIVE, "error %d in input record for interface %d (%s)",
wsane.iErrorCode[FD_READ_BIT], pite->ITE_Index, lpszAddr
);
LOGWARN1(INPUT_RECORD_ERROR, lpszAddr, dwErr);
continue;
}
//
// there is no error, so process the socket
//
ProcessSocket(pite, i, pTable);
}
}
RELEASE_READ_LOCK(&pTable->IT_RWL);
//
// register the InputEvent with the NtdllWait Thread again (only if the
// dll is not stopping). I use this model of registering the event with
// ntdll every time, to prevent the worker function from being called for
// every packet received (when packets are received at the same time).
//
if (ig.IG_Status != IPBOOTP_STATUS_STOPPING) {
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);
}
}
LEAVE_BOOTP_WORKER();
return;
}
//----------------------------------------------------------------------------
// Function: ProcessSocket
//
// This function processes a packet on an interface, queueing
// the packet for processing by a worker function after doing some
// basic validation.
//----------------------------------------------------------------------------
DWORD
ProcessSocket(
PIF_TABLE_ENTRY pite,
DWORD dwAddrIndex,
PIF_TABLE pTable
) {
BOOL bFreePacket;
WORKERFUNCTION pwf;
PINPUT_CONTEXT pwc;
PIPBOOTP_IF_STATS pis;
PIPBOOTP_IF_CONFIG pic;
PIPBOOTP_IP_ADDRESS paddr;
PIPBOOTP_PACKET pibp;
PLIST_ENTRY ple, phead;
DWORD dwErr, dwInputSource;
SOCKADDR_IN sinInputSource;
PIPBOOTP_GLOBAL_CONFIG pigc;
INT iInputLength, iAddrLength;
PBYTE pInputPacket;
pigc = ig.IG_Config;
pis = &pite->ITE_Stats;
paddr = IPBOOTP_IF_ADDRESS_TABLE(pite->ITE_Binding) + dwAddrIndex;
//
// the descriptor for this interface is set,
// so allocate space for the packet
//
pwc = BOOTP_ALLOC(sizeof(INPUT_CONTEXT));
if (pwc == NULL) {
dwErr = GetLastError();
TRACE2(
RECEIVE, "error %d allocating %d bytes for incoming packet",
dwErr, sizeof(INPUT_CONTEXT)
);
LOGERR0(HEAP_ALLOC_FAILED, dwErr);
return dwErr;
}
pInputPacket = pwc->IC_InputPacket;
dwErr = NO_ERROR;
bFreePacket = TRUE;
do {
CHAR szSource[20];
//
// receive the packet
//
iAddrLength = sizeof(SOCKADDR_IN);
iInputLength = recvfrom(
pite->ITE_Sockets[dwAddrIndex], pInputPacket,
MAX_PACKET_SIZE, 0, (PSOCKADDR)&sinInputSource,
&iAddrLength
);
if (iInputLength == 0 || iInputLength == SOCKET_ERROR) {
LPSTR lpszAddr;
dwErr = WSAGetLastError();
lpszAddr = INET_NTOA(paddr->IA_Address);
TRACE3(
RECEIVE, "error %d receiving on interface %d (%s)",
dwErr, pite->ITE_Index, lpszAddr
);
LOGERR1(RECVFROM_FAILED, lpszAddr, dwErr);
InterlockedIncrement(&pis->IS_ReceiveFailures);
break;
}
dwInputSource = sinInputSource.sin_addr.s_addr;
//
// filter out packets we sent ourselves
//
if (GetIfByAddress(pTable, dwInputSource, NULL)) {
break;
}
{
PCHAR pStr1, pStr2;
pStr1 = INET_NTOA(dwInputSource);
if (pStr1)
lstrcpy(szSource, pStr1);
pStr2 = INET_NTOA(paddr->IA_Address);
if (pStr1 && pStr2) {
TRACE4(
RECEIVE, "received %d-byte packet from %s on interface %d (%s)",
iInputLength, szSource, pite->ITE_Index,
pStr2
);
}
}
//
// cast packet as a BOOTP message
//
pibp = (PIPBOOTP_PACKET)pInputPacket;
//
// consistency check 1: length of packet must exceed the length
// of the BOOTP header
//
if (iInputLength < sizeof(IPBOOTP_PACKET)) {
LPSTR lpszAddr = INET_NTOA(paddr->IA_Address);
TRACE3(
RECEIVE,
"minimum BOOTP data is %d bytes, dropping %d byte packet from %s",
sizeof(IPBOOTP_PACKET), iInputLength, szSource
);
LOGWARN2(PACKET_TOO_SMALL, lpszAddr, szSource, 0);
break;
}
//
// consistency check 2: op field must be either BOOTP_REQUEST
// or BOOTP_REPLY
//
if (pibp->IP_Operation != IPBOOTP_OPERATION_REQUEST &&
pibp->IP_Operation != IPBOOTP_OPERATION_REPLY) {
LPSTR lpszAddr = INET_NTOA(paddr->IA_Address);
TRACE2(
RECEIVE,
"dropping packet from %s due to unknown operation field %d",
szSource, pibp->IP_Operation
);
LOGWARN2(PACKET_OPCODE_INVALID, lpszAddr, szSource, 0);
break;
}
//
// update statistics on incoming packets
//
switch (pibp->IP_Operation) {
case IPBOOTP_OPERATION_REQUEST:
InterlockedIncrement(&pis->IS_RequestsReceived);
break;
case IPBOOTP_OPERATION_REPLY:
InterlockedIncrement(&pis->IS_RepliesReceived);
break;
}
//
// finish initializing the work context
//
pwc->IC_InterfaceIndex = pite->ITE_Index;
pwc->IC_AddrIndex = dwAddrIndex;
pwc->IC_InputSource = sinInputSource;
pwc->IC_InputLength = iInputLength;
//
// place the packet on the receive queue
//
ACQUIRE_READ_LOCK(&ig.IG_RWL);
ACQUIRE_LIST_LOCK(ig.IG_RecvQueue);
dwErr = EnqueueRecvEntry(
ig.IG_RecvQueue, (DWORD)pibp->IP_Operation, (PBYTE)pwc
);
RELEASE_LIST_LOCK(ig.IG_RecvQueue);
RELEASE_READ_LOCK(&ig.IG_RWL);
if (dwErr != NO_ERROR) {
LPSTR lpszAddr = INET_NTOA(paddr->IA_Address);
TRACE4(
RECEIVE, "error %d queueing packet from %s on interface %d (%s)",
dwErr, szSource, pite->ITE_Index, lpszAddr
);
LOGERR2(QUEUE_PACKET_FAILED, lpszAddr, szSource, dwErr);
break;
}
//
// queue the function to handle the packet
//
dwErr = QueueBootpWorker(WorkerFunctionProcessInput, NULL);
if (dwErr != NO_ERROR) {
PLIST_ENTRY phead;
TRACE2(
RECEIVE, "error %d queueing packet from %s for processing",
dwErr, szSource
);
LOGERR0(QUEUE_WORKER_FAILED, dwErr);
ACQUIRE_LIST_LOCK(ig.IG_RecvQueue);
phead = &ig.IG_RecvQueue->LL_Head;
RemoveTailList(phead);
ig.IG_RecvQueueSize -= sizeof(RECV_QUEUE_ENTRY);
RELEASE_LIST_LOCK(ig.IG_RecvQueue);
break;
}
//
// all went well, so we let the input processor free the packet
//
bFreePacket = FALSE;
} while(FALSE);
if (bFreePacket) { BOOTP_FREE(pwc); }
return dwErr;
}
//----------------------------------------------------------------------------
// Function: WorkerFunctionProcessInput
//
// This function processes an incoming packet.
//----------------------------------------------------------------------------
VOID
WorkerFunctionProcessInput(
PVOID pContext
) {
PINPUT_CONTEXT pwc;
DWORD dwErr, dwCommand;
if (!ENTER_BOOTP_WORKER()) { return; }
TRACE0(ENTER, "entering WorkerFunctionProcessInput");
do {
ACQUIRE_LIST_LOCK(ig.IG_RecvQueue);
dwErr = DequeueRecvEntry(ig.IG_RecvQueue, &dwCommand, (PBYTE *)&pwc);
RELEASE_LIST_LOCK(ig.IG_RecvQueue);
if (dwErr != NO_ERROR) {
TRACE1(
RECEIVE, "error %d dequeueing packet from receive queue", dwErr
);
break;
}
switch (dwCommand) {
case IPBOOTP_OPERATION_REQUEST:
ProcessRequest(pwc);
break;
case IPBOOTP_OPERATION_REPLY:
ProcessReply(pwc);
break;
}
} while(FALSE);
TRACE0(LEAVE, "leaving WorkerFunctionProcessInput");
LEAVE_BOOTP_WORKER();
}
//----------------------------------------------------------------------------
// Function: ProcessRequest
//
// This function handles the processing of BOOT_REQUEST messages
//----------------------------------------------------------------------------
VOID
ProcessRequest(
PVOID pContext
) {
INT iErr;
PIF_TABLE pTable;
PINPUT_CONTEXT pwc;
SOCKADDR_IN sinsrv;
PIPBOOTP_PACKET pibp;
PIF_TABLE_ENTRY pite;
PIPBOOTP_IF_STATS pis;
PIPBOOTP_IF_CONFIG pic;
PIPBOOTP_IP_ADDRESS paddr;
PIPBOOTP_GLOBAL_CONFIG pigc;
DWORD dwErr, dwIndex, dwDhcpInformServer;
PDWORD pdwAddr, pdwEnd;
PDHCP_PACKET pdp;
TRACE0(ENTER, "entering ProcessRequest");
pwc = (PINPUT_CONTEXT)pContext;
pTable = ig.IG_IfTable;
ACQUIRE_READ_LOCK(&pTable->IT_RWL);
do { // error breakout loop
//
// find the interface on which the input arrived
//
dwIndex = pwc->IC_InterfaceIndex;
pite = GetIfByIndex(pTable, dwIndex);
if (pite == NULL) {
TRACE1(
REQUEST, "processing request: interface %d not found", dwIndex
);
break;
}
pis = &pite->ITE_Stats;
pic = pite->ITE_Config;
//
// Check if interface still bound to an IP address
//
if (pite->ITE_Binding == NULL) {
TRACE1(
REQUEST, "processing request: interface %d not bound",
dwIndex
);
break;
}
paddr = IPBOOTP_IF_ADDRESS_TABLE(pite->ITE_Binding) + pwc->IC_AddrIndex;
//
// if we are not configured to relay, do nothing
//
if (pic->IC_RelayMode == IPBOOTP_RELAY_DISABLED) { break; }
pibp = (PIPBOOTP_PACKET)pwc->IC_InputPacket;
//
// check the hop-count field to see if it is over the max hop-count
// configured for this interface
//
if (pibp->IP_HopCount > IPBOOTP_MAX_HOP_COUNT ||
pibp->IP_HopCount > pic->IC_MaxHopCount) {
//
// discard and log
//
CHAR szHops[12], *lpszAddr = INET_NTOA(paddr->IA_Address);
_ltoa(pibp->IP_HopCount, szHops, 10);
TRACE4(
REQUEST,
"dropping REQUEST with hop-count %d: max hop-count is %d on interface %d (%s)",
pibp->IP_HopCount, pic->IC_MaxHopCount, dwIndex, lpszAddr
);
LOGWARN2(HOP_COUNT_TOO_HIGH, lpszAddr, szHops, 0);
InterlockedIncrement(&pis->IS_RequestsDiscarded);
break;
}
//
// check the seconds threshold to make sure it is up to the minimum
//
if (pibp->IP_SecondsSinceBoot < pic->IC_MinSecondsSinceBoot) {
//
// discard and log
//
CHAR szSecs[12], *lpszAddr = INET_NTOA(paddr->IA_Address);
_ltoa(pibp->IP_SecondsSinceBoot, szSecs, 10);
TRACE3(
REQUEST,
"dropping REQUEST with secs-since-boot %d on interface %d (%s)",
pibp->IP_SecondsSinceBoot, dwIndex, lpszAddr
);
LOGINFO2(SECS_SINCE_BOOT_TOO_LOW, lpszAddr, szSecs, 0);
InterlockedIncrement(&pis->IS_RequestsDiscarded);
break;
}
//
// increment the hop-count
//
++pibp->IP_HopCount;
//
// fill in relay agent IP address if it is empty
//
if (pibp->IP_AgentAddress == 0) {
pibp->IP_AgentAddress = paddr->IA_Address;
}
//
// if a dhcp-inform server has been set,
// and this packet is a dhcp inform packet,
// we will forward it to the dhcp-inform server.
//
pdp = (PDHCP_PACKET)(pibp + 1);
if (!(dwDhcpInformServer = ig.IG_DhcpInformServer) ||
pwc->IC_InputLength <
sizeof(IPBOOTP_PACKET) + sizeof(DHCP_PACKET) + 1 ||
*(DWORD UNALIGNED *)pdp->Cookie != DHCP_MAGIC_COOKIE ||
pdp->Tag != DHCP_TAG_MESSAGE_TYPE ||
pdp->Length != 1 ||
pdp->Option[0] != DHCP_MESSAGE_INFORM
) {
dwDhcpInformServer = 0;
}
//
// relay the request to all configured BOOTP servers
//
ACQUIRE_READ_LOCK(&ig.IG_RWL);
pigc = ig.IG_Config;
if (dwDhcpInformServer) {
pdwAddr = &dwDhcpInformServer;
pdwEnd = pdwAddr + 1;
}
else {
pdwAddr = (PDWORD)((PBYTE)pigc + sizeof(IPBOOTP_GLOBAL_CONFIG));
pdwEnd = pdwAddr + pigc->GC_ServerCount;
}
for ( ; pdwAddr < pdwEnd; pdwAddr++) {
sinsrv.sin_family = AF_INET;
sinsrv.sin_port = htons(IPBOOTP_SERVER_PORT);
sinsrv.sin_addr.s_addr = *pdwAddr;
iErr = sendto(
pite->ITE_Sockets[pwc->IC_AddrIndex],
pwc->IC_InputPacket, pwc->IC_InputLength, 0,
(PSOCKADDR)&sinsrv, sizeof(SOCKADDR_IN)
);
if (iErr == SOCKET_ERROR || iErr < (INT)pwc->IC_InputLength) {
CHAR szSrv[20], *lpszAddr;
dwErr = WSAGetLastError();
if ((lpszAddr = INET_NTOA(*pdwAddr)) != NULL) {
lstrcpy(szSrv, lpszAddr);
lpszAddr = INET_NTOA(paddr->IA_Address);
if (lpszAddr != NULL) {
TRACE4(
REQUEST,
"error %d relaying REQUEST to server %s on interface %d (%s)",
dwErr, szSrv, dwIndex, lpszAddr
);
LOGERR2(RELAY_REQUEST_FAILED, lpszAddr, szSrv, dwErr);
}
}
InterlockedIncrement(&pis->IS_SendFailures);
}
}
RELEASE_READ_LOCK(&ig.IG_RWL);
} while(FALSE);
RELEASE_READ_LOCK(&pTable->IT_RWL);
BOOTP_FREE(pwc);
TRACE0(LEAVE, "leaving ProcessRequest");
return;
}
//----------------------------------------------------------------------------
// Function: ProcessReply
//
// This function handles the relaying of BOOT_REPLY packets
//----------------------------------------------------------------------------
VOID
ProcessReply(
PVOID pContext
) {
INT iErr;
PIF_TABLE pTable;
BOOL bArpUpdated;
SOCKADDR_IN sincli;
PINPUT_CONTEXT pwc;
PIPBOOTP_PACKET pibp;
PIPBOOTP_IP_ADDRESS paddrin, paddrout;
PIPBOOTP_IF_STATS pisin, pisout;
PIF_TABLE_ENTRY pitein, piteout;
DWORD dwErr, dwIndex, dwAddress, dwAddrIndexOut;
TRACE0(ENTER, "entering ProcessReply");
pwc = (PINPUT_CONTEXT)pContext;
pTable = ig.IG_IfTable;
ACQUIRE_READ_LOCK(&pTable->IT_RWL);
do { // error breakout loop
//
// get the interface on which the packet was received
//
dwIndex = pwc->IC_InterfaceIndex;
pitein = GetIfByIndex(pTable, dwIndex);
if (pitein == NULL) {
TRACE1(REPLY, "processing REPLY: interface %d not found", dwIndex);
break;
}
if (pitein->ITE_Binding == NULL) {
TRACE1(REPLY, "processing REPLY: interface %d not bound", dwIndex);
break;
}
paddrin = IPBOOTP_IF_ADDRESS_TABLE(pitein->ITE_Binding) +
pwc->IC_AddrIndex;
//
// if we are not configured t relay on this interface, do nothing
//
if (pitein->ITE_Config->IC_RelayMode == IPBOOTP_RELAY_DISABLED) {
TRACE2(
REPLY,
"dropping REPLY: relaying on interface %d (%s) is disabled",
pitein->ITE_Index, INET_NTOA(paddrin->IA_Address)
);
break;
}
pisin = &pitein->ITE_Stats;
//
// place a template over the packet, and retrieve
// the AgentAddress field; this contains the address
// of the relay agent responsible for relaying this REPLY
//
pibp = (PIPBOOTP_PACKET)pwc->IC_InputPacket;
dwAddress = pibp->IP_AgentAddress;
//
// see if the address in the reply matches any local interface
//
piteout = GetIfByAddress(pTable, dwAddress, &dwAddrIndexOut);
if (piteout == NULL) {
CHAR szAddress[20];
PCHAR pStr1, pStr2;
pStr1 = INET_NTOA(dwAddress);
if (pStr1)
lstrcpy(szAddress, pStr1);
pStr2 = INET_NTOA(paddrin->IA_Address);
if (pStr1 && pStr2) {
TRACE3(
REPLY,
"dropping REPLY packet on interface %d (%s); no interfaces have address %s",
pitein->ITE_Index, pStr2, szAddress
);
}
InterlockedIncrement(&pisin->IS_RepliesDiscarded);
break;
}
if (piteout->ITE_Binding == NULL) {
TRACE1(REPLY, "processing REPLY: outgoing interface %d is not bound", dwIndex);
break;
}
paddrout = IPBOOTP_IF_ADDRESS_TABLE(piteout->ITE_Binding) +
dwAddrIndexOut;
//
// only relay if relay is enabled on the outgoing interface
//
if (piteout->ITE_Config->IC_RelayMode == IPBOOTP_RELAY_DISABLED) {
TRACE2(
REPLY,
"dropping REPLY: relaying on interface %d (%s) is disabled",
piteout->ITE_Index, INET_NTOA(paddrout->IA_Address)
);
break;
}
pisout = &piteout->ITE_Stats;
//
// the message must be relayed on the interface whose address
// was specifed in the packet;
//
// if the broadcast bit is not set and the clients IP address
// is in the packet, add an entry to the ARP cache for the client
// and then relay the packet by unicast
//
sincli.sin_family = AF_INET;
sincli.sin_port = htons(IPBOOTP_CLIENT_PORT);
if ((pibp->IP_Flags & htons(IPBOOTP_FLAG_BROADCAST)) != 0 ||
pibp->IP_OfferedAddress == 0) {
//
// the broadcast bit is set of the offered address is 0,
// which is not an address we can add to the ARP cache;
// in this case, send by broadcast
//
bArpUpdated = FALSE;
sincli.sin_addr.s_addr = INADDR_BROADCAST;
}
else {
//
// attempt to seed the ARP cache with the address
// offered to the client in the packet we are about
// to send to the client.
//
dwErr = UpdateArpCache(
piteout->ITE_Index, pibp->IP_OfferedAddress,
(PBYTE)pibp->IP_MacAddr, pibp->IP_MacAddrLength,
TRUE, ig.IG_FunctionTable
);
if (dwErr == NO_ERROR) {
bArpUpdated = TRUE;
sincli.sin_addr.s_addr = pibp->IP_OfferedAddress;
}
else {
//
// okay, that didn't work,
// so fall back on broadcasting the packet
//
TRACE3(
REPLY,
"error %d adding entry to ARP cache on interface %d (%s)",
dwErr, piteout->ITE_Index, INET_NTOA(paddrout->IA_Address)
);
bArpUpdated = FALSE;
sincli.sin_addr.s_addr = INADDR_BROADCAST;
InterlockedIncrement(&pisout->IS_ArpUpdateFailures);
}
}
//
// relay the packet
//
iErr = sendto(
piteout->ITE_Sockets[dwAddrIndexOut], pwc->IC_InputPacket,
pwc->IC_InputLength, 0,
(PSOCKADDR)&sincli, sizeof(SOCKADDR_IN)
);
if (iErr == SOCKET_ERROR || iErr < (INT)pwc->IC_InputLength) {
INT i;
BYTE *pb;
CHAR szCli[64], *psz, *lpszAddr, szDigits[] = "0123456789ABCDEF";
dwErr = WSAGetLastError();
lpszAddr = INET_NTOA(paddrout->IA_Address);
//
// format the client's hardware address
//
for (i = 0, psz = szCli, pb = pibp->IP_MacAddr;
i < 16 && i < pibp->IP_MacAddrLength;
i++, pb++) {
*psz++ = szDigits[*pb / 16];
*psz++ = szDigits[*pb % 16];
*psz++ = ':';
}
(psz == szCli) ? (*psz = '\0') : (*(psz - 1) = '\0');
TRACE4(
REPLY,
"error %d relaying REPLY to client %s on interface %d (%s)",
dwErr, szCli, dwIndex, lpszAddr
);
LOGERR2(RELAY_REPLY_FAILED, lpszAddr, szCli, dwErr);
InterlockedIncrement(&pisout->IS_SendFailures);
}
//
// remove the ARP entry if one was added
//
if (bArpUpdated) {
dwErr = UpdateArpCache(
piteout->ITE_Index, pibp->IP_OfferedAddress,
(PBYTE)pibp->IP_MacAddr, pibp->IP_MacAddrLength,
FALSE, ig.IG_FunctionTable
);
if (dwErr != NO_ERROR) {
InterlockedIncrement(&pisout->IS_ArpUpdateFailures);
}
}
} while(FALSE);
RELEASE_READ_LOCK(&pTable->IT_RWL);
BOOTP_FREE(pwc);
TRACE0(LEAVE, "leaving ProcessReply");
return;
}
#define ClearScreen(h) { \
DWORD _dwin,_dwout; \
COORD _c = {0, 0}; \
CONSOLE_SCREEN_BUFFER_INFO _csbi; \
GetConsoleScreenBufferInfo(h,&_csbi); \
_dwin = _csbi.dwSize.X * _csbi.dwSize.Y; \
FillConsoleOutputCharacter(h,' ',_dwin,_c,&_dwout); \
}
VOID
PrintGlobalConfig(
HANDLE hConsole,
PCOORD pc,
PIPBOOTP_MIB_GET_INPUT_DATA pimgid,
PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod
);
VOID
PrintIfConfig(
HANDLE hConsole,
PCOORD pc,
PIPBOOTP_MIB_GET_INPUT_DATA pimgid,
PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod
);
VOID
PrintIfBinding(
HANDLE hConsole,
PCOORD pc,
PIPBOOTP_MIB_GET_INPUT_DATA pimgid,
PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod
);
VOID
PrintIfStats(
HANDLE hConsole,
PCOORD pc,
PIPBOOTP_MIB_GET_INPUT_DATA pimgid,
PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod
);
#if DBG
VOID
CallbackFunctionMibDisplay(
PVOID pContext,
BOOLEAN NotUsed
) {
// enter/leaveBootpWorker not required as timer queue is persistent
QueueBootpWorker(WorkerFunctionMibDisplay, pContext);
return;
}
VOID
WorkerFunctionMibDisplay(
PVOID pContext
) {
COORD c;
INT iErr;
FD_SET fdsRead;
HANDLE hConsole;
TIMEVAL tvTimeout;
DWORD dwErr, dwTraceID;
DWORD dwExactSize, dwInSize, dwOutSize;
IPBOOTP_MIB_GET_INPUT_DATA imgid;
PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod;
if (!ENTER_BOOTP_WORKER()) { return; }
TraceGetConsole(ig.IG_MibTraceID, &hConsole);
if (hConsole == NULL) {
LEAVE_BOOTP_WORKER();
return;
}
ClearScreen(hConsole);
c.X = c.Y = 0;
dwInSize = sizeof(imgid);
imgid.IMGID_TypeID = IPBOOTP_GLOBAL_CONFIG_ID;
dwOutSize = 0;
pimgod = NULL;
dwErr = MibGetFirst(dwInSize, &imgid, &dwOutSize, pimgod);
if (dwErr == ERROR_INSUFFICIENT_BUFFER) {
pimgod = BOOTP_ALLOC(dwOutSize);
if (pimgod) {
dwErr = MibGetFirst(dwInSize, &imgid, &dwOutSize, pimgod);
}
}
while (dwErr == NO_ERROR) {
switch(pimgod->IMGOD_TypeID) {
case IPBOOTP_GLOBAL_CONFIG_ID:
PrintGlobalConfig(hConsole, &c, &imgid, pimgod);
break;
case IPBOOTP_IF_CONFIG_ID:
PrintIfConfig(hConsole, &c, &imgid, pimgod);
break;
case IPBOOTP_IF_BINDING_ID:
PrintIfBinding(hConsole, &c, &imgid, pimgod);
break;
case IPBOOTP_IF_STATS_ID:
PrintIfStats(hConsole, &c, &imgid, pimgod);
break;
default:
break;
}
//
// move to next line
//
++c.Y;
dwOutSize = 0;
if (pimgod) { BOOTP_FREE(pimgod); pimgod = NULL; }
dwErr = MibGetNext(dwInSize, &imgid, &dwOutSize, pimgod);
if (dwErr == ERROR_INSUFFICIENT_BUFFER) {
pimgod = BOOTP_ALLOC(dwOutSize);
if (pimgod) {
dwErr = MibGetNext(dwInSize, &imgid, &dwOutSize, pimgod);
}
}
}
if (pimgod != NULL) { BOOTP_FREE(pimgod); }
LEAVE_BOOTP_WORKER();
return;
}
#endif //if DBG
#define WriteLine(h,c,fmt,arg) { \
DWORD _dw; \
CHAR _sz[200], _fmt[200]; \
wsprintf(_fmt,"%-100s",fmt); \
wsprintf(_sz,_fmt,arg); \
WriteConsoleOutputCharacter(h,_sz,lstrlen(_sz),c,&_dw); \
++(c).Y; \
}
VOID
PrintGlobalConfig(
HANDLE hConsole,
PCOORD pc,
PIPBOOTP_MIB_GET_INPUT_DATA pimgid,
PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod
) {
PDWORD pdwsrv, pdwsrvend;
PIPBOOTP_GLOBAL_CONFIG pgc;
pgc = (PIPBOOTP_GLOBAL_CONFIG)pimgod->IMGOD_Buffer;
WriteLine(
hConsole,
*pc,
"Logging Level: %d",
pgc->GC_LoggingLevel
);
WriteLine(
hConsole,
*pc,
"Max Receive Queue Size: %d",
pgc->GC_MaxRecvQueueSize
);
WriteLine(
hConsole,
*pc,
"BOOTP Server Count: %d",
pgc->GC_ServerCount
);
pdwsrv = (PDWORD)(pgc + 1);
pdwsrvend = pdwsrv + pgc->GC_ServerCount;
for ( ; pdwsrv < pdwsrvend; pdwsrv++) {
WriteLine(
hConsole,
*pc,
"BOOTP Server: %s",
INET_NTOA(*pdwsrv)
);
}
pimgid->IMGID_TypeID = IPBOOTP_GLOBAL_CONFIG_ID;
}
VOID
PrintIfConfig(
HANDLE hConsole,
PCOORD pc,
PIPBOOTP_MIB_GET_INPUT_DATA pimgid,
PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod
) {
CHAR szMode[20];
PIPBOOTP_IF_CONFIG pic;
pic = (PIPBOOTP_IF_CONFIG)pimgod->IMGOD_Buffer;
switch (pic->IC_RelayMode) {
case IPBOOTP_RELAY_ENABLED:
strcpy(szMode, "enabled"); break;
case IPBOOTP_RELAY_DISABLED:
strcpy(szMode, "disabled"); break;
default:
break;
}
WriteLine(
hConsole,
*pc,
"Interface Index: %d",
pimgod->IMGOD_IfIndex
);
WriteLine(
hConsole,
*pc,
"Relay Mode: %s",
szMode
);
WriteLine(
hConsole,
*pc,
"Max Hop Count: %d",
pic->IC_MaxHopCount
);
WriteLine(
hConsole,
*pc,
"Min Seconds Since Boot: %d",
pic->IC_MinSecondsSinceBoot
);
pimgid->IMGID_TypeID = IPBOOTP_IF_CONFIG_ID;
pimgid->IMGID_IfIndex = pimgod->IMGOD_IfIndex;
}
VOID
PrintIfBinding(
HANDLE hConsole,
PCOORD pc,
PIPBOOTP_MIB_GET_INPUT_DATA pimgid,
PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod
) {
DWORD i;
CHAR szAddr[64];
PIPBOOTP_IF_BINDING pib;
PIPBOOTP_IP_ADDRESS paddr;
pib = (PIPBOOTP_IF_BINDING)pimgod->IMGOD_Buffer;
paddr = IPBOOTP_IF_ADDRESS_TABLE(pib);
WriteLine(
hConsole, *pc, "Interface Index: %d",
pimgod->IMGOD_IfIndex
);
WriteLine(
hConsole, *pc, "Address Count: %d",
pib->IB_AddrCount
);
for (i = 0; i < pib->IB_AddrCount; i++, paddr++) {
LPSTR szTemp;
szTemp = INET_NTOA(paddr->IA_Address);
if (szTemp != NULL) {
lstrcpy(szAddr, szTemp);
lstrcat(szAddr, " - ");
szTemp = INET_NTOA(paddr->IA_Netmask);
if ( szTemp != NULL ) { lstrcat(szAddr, szTemp); }
WriteLine(
hConsole, *pc, "Address Entry: %s",
szAddr
);
}
}
pimgid->IMGID_TypeID = IPBOOTP_IF_BINDING_ID;
pimgid->IMGID_IfIndex = pimgod->IMGOD_IfIndex;
}
VOID
PrintIfStats(
HANDLE hConsole,
PCOORD pc,
PIPBOOTP_MIB_GET_INPUT_DATA pimgid,
PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod
) {
PIPBOOTP_IF_STATS pis;
pis = (PIPBOOTP_IF_STATS)pimgod->IMGOD_Buffer;
WriteLine(
hConsole,
*pc,
"Interface Index: %d",
pimgod->IMGOD_IfIndex
);
WriteLine(
hConsole,
*pc,
"Send Failures: %d",
pis->IS_SendFailures
);
WriteLine(
hConsole,
*pc,
"Receive Failures: %d",
pis->IS_ReceiveFailures
);
WriteLine(
hConsole,
*pc,
"ARP Cache Update Failures: %d",
pis->IS_ArpUpdateFailures
);
WriteLine(
hConsole,
*pc,
"Requests Received: %d",
pis->IS_RequestsReceived
);
WriteLine(
hConsole,
*pc,
"Requests Discarded: %d",
pis->IS_RequestsDiscarded
);
WriteLine(
hConsole,
*pc,
"Replies Received: %d",
pis->IS_RepliesReceived
);
WriteLine(
hConsole,
*pc,
"Replies Discarded: %d",
pis->IS_RepliesDiscarded
);
pimgid->IMGID_TypeID = IPBOOTP_IF_STATS_ID;
pimgid->IMGID_IfIndex = pimgod->IMGOD_IfIndex;
}