|
|
//============================================================================
// 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; }
|