592 lines
16 KiB
C++
592 lines
16 KiB
C++
/*++
|
||
|
||
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<LPLONG>(&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<LPLONG>(&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
|
||
|