/*++ Copyright (c) 1998, Microsoft Corporation Module Name: dhcpio.c Abstract: This module contains code for the DHCP allocator's network I/O. Author: Abolade Gbadegesin (aboladeg) 5-Mar-1998 Revision History: --*/ #include "precomp.h" #pragma hdrstop VOID DhcpReadCompletionRoutine( ULONG ErrorCode, ULONG BytesTransferred, PNH_BUFFER Bufferp ) /*++ Routine Description: This routine is invoked upon completion of a read operation on a datagram socket bound to the DHCP server UDP port. The message read is validated and processed, and if necessary, a reply is generated and sent to the client. Arguments: ErrorCode - Win32 status code for the I/O operation BytesTransferred - number of bytes in 'Bufferp' Bufferp - holds data read from the datagram socket Return Value: none. Environment: Runs in the context of an RTUTILS.DLL worker-thread which has just dequeued an I/O completion packet from the common I/O completion port with which our datagram sockets are associated. A reference to the component will have been made on our behalf by 'NhReadDatagramSocket'. --*/ { ULONG Error; PDHCP_HEADER Headerp; PDHCP_INTERFACE Interfacep; PROFILE("DhcpReadCompletionRoutine"); do { // // There are two cases where we don't process the message; // (a) the I/O operation failed // (b) the interface is no longer active // In cases (a) we repost the buffer; in case (b) we do not. // Interfacep = (PDHCP_INTERFACE)Bufferp->Context; // // First look for an error code // if (ErrorCode) { NhTrace( TRACE_FLAG_IO, "DhcpReadCompletionRoutine: error %d for read-context %x", ErrorCode, Bufferp->Context ); // // See if the interface is still active // ACQUIRE_LOCK(Interfacep); if (!DHCP_INTERFACE_ACTIVE(Interfacep)) { RELEASE_LOCK(Interfacep); NhReleaseBuffer(Bufferp); } else { RELEASE_LOCK(Interfacep); EnterCriticalSection(&DhcpInterfaceLock); if (!DHCP_REFERENCE_INTERFACE(Interfacep)) { NhReleaseBuffer(Bufferp); } else { // // Repost the buffer for another read operation // Error = NhReadDatagramSocket( &DhcpComponentReference, Bufferp->Socket, Bufferp, DhcpReadCompletionRoutine, Bufferp->Context, Bufferp->Context2 ); if (Error) { ACQUIRE_LOCK(Interfacep); DhcpDeferReadInterface(Interfacep, Bufferp->Socket); RELEASE_LOCK(Interfacep); DHCP_DEREFERENCE_INTERFACE(Interfacep); NhWarningLog( IP_AUTO_DHCP_LOG_RECEIVE_FAILED, Error, "%I", NhQueryAddressSocket(Bufferp->Socket) ); NhReleaseBuffer(Bufferp); } } LeaveCriticalSection(&DhcpInterfaceLock); } break; } // // Now see if the interface is operational // ACQUIRE_LOCK(Interfacep); if (!DHCP_INTERFACE_ACTIVE(Interfacep)) { RELEASE_LOCK(Interfacep); NhReleaseBuffer(Bufferp); NhTrace( TRACE_FLAG_IO, "DhcpReadCompletionRoutine: interface %x inactive", Interfacep ); break; } RELEASE_LOCK(Interfacep); // // Now look at the message // Headerp = (PDHCP_HEADER)Bufferp->Buffer; switch (Headerp->Operation) { case BOOTP_OPERATION_REQUEST: { DhcpProcessMessage( Interfacep, Bufferp ); break; } case BOOTP_OPERATION_REPLY: { InterlockedIncrement( reinterpret_cast(&DhcpStatistics.MessagesIgnored) ); NhTrace( TRACE_FLAG_IO, "DhcpReadCompletionRoutine: ignoring BOOTPREPLY" ); // // Repost the buffer for another read operation. // EnterCriticalSection(&DhcpInterfaceLock); if (!DHCP_REFERENCE_INTERFACE(Interfacep)) { LeaveCriticalSection(&DhcpInterfaceLock); NhReleaseBuffer(Bufferp); } else { LeaveCriticalSection(&DhcpInterfaceLock); Error = NhReadDatagramSocket( &DhcpComponentReference, Bufferp->Socket, Bufferp, DhcpReadCompletionRoutine, Bufferp->Context, Bufferp->Context2 ); if (Error) { ACQUIRE_LOCK(Interfacep); DhcpDeferReadInterface(Interfacep, Bufferp->Socket); RELEASE_LOCK(Interfacep); DHCP_DEREFERENCE_INTERFACE(Interfacep); NhWarningLog( IP_AUTO_DHCP_LOG_RECEIVE_FAILED, Error, "%I", NhQueryAddressSocket(Bufferp->Socket) ); NhReleaseBuffer(Bufferp); } } break; } default: { InterlockedIncrement( reinterpret_cast(&DhcpStatistics.MessagesIgnored) ) ; NhTrace( TRACE_FLAG_IO, "DhcpReadCompletionRoutine: ignoring invalid BOOTP operation %d", Headerp->Operation ); NhInformationLog( IP_AUTO_DHCP_LOG_INVALID_BOOTP_OPERATION, 0, "%d", Headerp->Operation ); // // Repost the buffer for another read operation. // EnterCriticalSection(&DhcpInterfaceLock); if (!DHCP_REFERENCE_INTERFACE(Interfacep)) { LeaveCriticalSection(&DhcpInterfaceLock); NhReleaseBuffer(Bufferp); } else { LeaveCriticalSection(&DhcpInterfaceLock); Error = NhReadDatagramSocket( &DhcpComponentReference, Bufferp->Socket, Bufferp, DhcpReadCompletionRoutine, Bufferp->Context, Bufferp->Context2 ); if (Error) { ACQUIRE_LOCK(Interfacep); DhcpDeferReadInterface(Interfacep, Bufferp->Socket); RELEASE_LOCK(Interfacep); DHCP_DEREFERENCE_INTERFACE(Interfacep); NhWarningLog( IP_AUTO_DHCP_LOG_RECEIVE_FAILED, Error, "%I", NhQueryAddressSocket(Bufferp->Socket) ); NhReleaseBuffer(Bufferp); } } break; } } } while(FALSE); DHCP_DEREFERENCE_INTERFACE(Interfacep); DEREFERENCE_DHCP(); } // DhcpReadCompletionRoutine VOID DhcpReadServerReplyCompletionRoutine( ULONG ErrorCode, ULONG BytesTransferred, PNH_BUFFER Bufferp ) /*++ Routine Description: This routine is invoked upon completion of a receive-operation on a socket bound to the DHCP client port, when the component is attempting to detect the presence of a DHCP server. Arguments: ErrorCode - system-supplied status code BytesTransferred - system-supplied byte count Bufferp - send buffer Return Value: none. Environment: Runs in the context of an RTUTILS.DLL worker thread upon removal of an I/O completion packet. A reference to the component will have been made on our behalf by 'NhReadDatagramSocket'. --*/ { ULONG Address; ULONG Error; PDHCP_INTERFACE Interfacep; PROFILE("DhcpReadServerReplyCompletionRoutine"); Interfacep = (PDHCP_INTERFACE)Bufferp->Context; if (ErrorCode) { NhTrace( TRACE_FLAG_IO, "DhcpReadServerReplyCompletionRoutine: error %d receiving %s", ErrorCode, INET_NTOA(Bufferp->Context2) ); NhReleaseBuffer(Bufferp); DHCP_DEREFERENCE_INTERFACE(Interfacep); DEREFERENCE_DHCP(); return; } ACQUIRE_LOCK(Interfacep); if (!DHCP_INTERFACE_ACTIVE(Interfacep)) { RELEASE_LOCK(Interfacep); NhReleaseBuffer(Bufferp); DHCP_DEREFERENCE_INTERFACE(Interfacep); DEREFERENCE_DHCP(); return; } RELEASE_LOCK(Interfacep); // // Inspect the message read // Address = NhQueryAddressSocket(Bufferp->Socket); if (NhIsLocalAddress(Bufferp->ReadAddress.sin_addr.s_addr)) { NhTrace( TRACE_FLAG_IO, "DhcpReadServerReplyCompletionRoutine: ignoring, from self (%s)", INET_NTOA(Address) ); } else { CHAR LocalAddress[16]; lstrcpyA(LocalAddress, INET_NTOA(Address)); NhTrace( TRACE_FLAG_IO, "DhcpReadServerReplyCompletionRoutine: %s found, disabling %d (%s)", INET_NTOA(Bufferp->ReadAddress.sin_addr), Interfacep->Index, LocalAddress ); // // We received this from another server. // We'll need to disable this interface. // DhcpDisableInterface(Interfacep->Index); NhErrorLog( IP_AUTO_DHCP_LOG_DUPLICATE_SERVER, 0, "%I%I", Bufferp->ReadAddress.sin_addr.s_addr, Address ); NhReleaseBuffer(Bufferp); DHCP_DEREFERENCE_INTERFACE(Interfacep); DEREFERENCE_DHCP(); return; } // // We received it from ourselves. // Look for another server. // Error = NhReadDatagramSocket( &DhcpComponentReference, Bufferp->Socket, Bufferp, DhcpReadServerReplyCompletionRoutine, Bufferp->Context, Bufferp->Context2 ); if (Error) { NhTrace( TRACE_FLAG_IO, "DhcpReadServerReplyCompletionRoutine: error %d reposting %s", ErrorCode, INET_NTOA(Bufferp->Context2) ); NhReleaseBuffer(Bufferp); NhWarningLog( IP_AUTO_DHCP_LOG_DETECTION_UNAVAILABLE, Error, "%I", Address ); DHCP_DEREFERENCE_INTERFACE(Interfacep); DEREFERENCE_DHCP(); return; } DEREFERENCE_DHCP(); } // DhcpReadServerReplyCompletionRoutine VOID DhcpWriteClientRequestCompletionRoutine( ULONG ErrorCode, ULONG BytesTransferred, PNH_BUFFER Bufferp ) /*++ Routine Description: This routine is invoked upon completion of a send-operation on a socket bound to the DHCP client port, when the component is attempting to detect the presence of a DHCP server. Arguments: ErrorCode - system-supplied status code BytesTransferred - system-supplied byte count Bufferp - send buffer Return Value: none. Environment: Runs in the context of an RTUTILS.DLL worker thread upon removal of an I/O completion packet. A reference to the interface will have been made on our behalf by 'DhcpWriteClientRequestMessage'. A reference to the component will have been made on our behalf by 'NhWriteDatagramSocket'. --*/ { PDHCP_INTERFACE Interfacep; ULONG Error; PROFILE("DhcpWriteClientRequestCompletionRoutine"); Interfacep = (PDHCP_INTERFACE)Bufferp->Context; if (ErrorCode) { NhTrace( TRACE_FLAG_IO, "DhcpWriteClientRequestCompletionRoutine: error %d broadcast %s", ErrorCode, INET_NTOA(Bufferp->Context2) ); NhWarningLog( IP_AUTO_DHCP_LOG_DETECTION_UNAVAILABLE, ErrorCode, "%I", NhQueryAddressSocket(Bufferp->Socket) ); NhReleaseBuffer(Bufferp); DHCP_DEREFERENCE_INTERFACE(Interfacep); DEREFERENCE_DHCP(); return; } ACQUIRE_LOCK(Interfacep); if (!DHCP_INTERFACE_ACTIVE(Interfacep)) { RELEASE_LOCK(Interfacep); NhReleaseBuffer(Bufferp); DHCP_DEREFERENCE_INTERFACE(Interfacep); DEREFERENCE_DHCP(); return; } RELEASE_LOCK(Interfacep); // // Reuse the send buffer to listen for a response from the server // Error = NhReadDatagramSocket( &DhcpComponentReference, Bufferp->Socket, Bufferp, DhcpReadServerReplyCompletionRoutine, Bufferp->Context, Bufferp->Context2 ); if (Error) { NhTrace( TRACE_FLAG_IO, "DhcpWriteClientRequestCompletionRoutine: error %d receiving %s", ErrorCode, INET_NTOA(Bufferp->Context2) ); NhWarningLog( IP_AUTO_DHCP_LOG_DETECTION_UNAVAILABLE, Error, "%I", NhQueryAddressSocket(Bufferp->Socket) ); NhReleaseBuffer(Bufferp); DHCP_DEREFERENCE_INTERFACE(Interfacep); DEREFERENCE_DHCP(); return; } DEREFERENCE_DHCP(); } // DhcpWriteClientRequestCompletionRoutine VOID DhcpWriteCompletionRoutine( ULONG ErrorCode, ULONG BytesTransferred, PNH_BUFFER Bufferp ) /*++ Routine Description: This routine is invoked upon completion of a write-operation on a datagram socket bound to the DHCP server UDP port. Arguments: ErrorCode - Win32 status code for the I/O operation BytesTransferred - number of bytes in 'Bufferp' Bufferp - holds data read from the datagram socket Return Value: none. Environment: Runs in the context of an RTUTILS.DLL worker-thread which has just dequeued an I/O completion packet from the common I/O completion port with which our datagram sockets are associated. A reference to the interface will have been made on our behalf by the code which invoked 'NhWriteDatagramSocket'. A reference to the component will have been made on our behalf within 'NhWriteDatagramSocket'. --*/ { PDHCP_INTERFACE Interfacep; PROFILE("DhcpWriteCompletionRoutine"); Interfacep = (PDHCP_INTERFACE)Bufferp->Context; DHCP_DEREFERENCE_INTERFACE(Interfacep); NhReleaseBuffer(Bufferp); DEREFERENCE_DHCP(); } // DhcpWriteCompletionRoutine