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.
648 lines
18 KiB
648 lines
18 KiB
/*++
|
|
|
|
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);
|
|
|
|
//
|
|
// Ensure minimum DHCP_HEADER size
|
|
//
|
|
|
|
if (BytesTransferred < sizeof(DHCP_HEADER)) {
|
|
NhTrace(
|
|
TRACE_FLAG_DHCP,
|
|
"DhcpReadCompletionRoutine: message size %d too small",
|
|
BytesTransferred
|
|
);
|
|
NhWarningLog(
|
|
IP_AUTO_DHCP_LOG_MESSAGE_TOO_SMALL,
|
|
0,
|
|
""
|
|
);
|
|
InterlockedIncrement(
|
|
reinterpret_cast<LPLONG>(&DhcpStatistics.MessagesIgnored)
|
|
);
|
|
|
|
//
|
|
// Repost read
|
|
//
|
|
|
|
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;
|
|
}
|
|
|
|
//
|
|
// 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
|
|
|