windows-nt/Source/XPSP1/NT/net/dhcp/client/nt/mdhcpcli.c
2020-09-26 16:20:57 +08:00

2592 lines
79 KiB
C

/*++
Copyright (c) 1994 Microsoft Corporation
Module Name:
mdhccapi.c
Abstract:
This file contains the client side APIs for the Madcap.
Author:
Munil Shah (munils) 02-Sept-97
Environment:
User Mode - Win32
Revision History:
--*/
#include "precomp.h"
#include "dhcpglobal.h"
#include <dhcploc.h>
#include <dhcppro.h>
#define MADCAP_DATA_ALLOCATE
#include "mdhcpcli.h"
#include <rpc.h>
//
// constants
//
#define Madcap_ADAPTER_NAME L"Madcap Adapter"
#define MadcapMiscPrint( Msg ) DhcpPrint(( DEBUG_MISC, ( Msg ) ))
static
LONG Initialized = 0;
WSADATA MadcapGlobalWsaData;
DWORD
MadcapInitGlobalData(
VOID
)
/*++
Routine Description:
This routine initializes data required for Multicast APIs to work
correctly. This has to be called exactly once (and this is ensured
by calling it in DLL init in dhcp.c )
Return Value:
This function returns a Win32 status.
--*/
{
DWORD Error;
LOCK_MSCOPE_LIST();
do {
if( Initialized > 0 ) {
Initialized ++;
Error = NO_ERROR;
break;
}
gMadcapScopeList = NULL;
gMScopeQueryInProgress = FALSE;
gMScopeQueryEvent =
CreateEvent(
NULL, // no security.
TRUE, // manual reset.
FALSE, // initial state is not-signaled.
NULL ); // no name.
if( gMScopeQueryEvent == NULL ) {
Error = GetLastError();
break;
}
Error = WSAStartup( 0x0101, &MadcapGlobalWsaData );
if( ERROR_SUCCESS != Error ) {
CloseHandle(gMScopeQueryEvent);
gMScopeQueryEvent = NULL;
break;
}
Initialized ++;
Error = NO_ERROR;
} while ( 0 );
UNLOCK_MSCOPE_LIST();
return Error;
}
VOID
MadcapCleanupGlobalData(
VOID
)
/*++
Routine Description:
This routine cleans up any resources allocated in MadcapInitGlobalData.
This can be called even if the InitData routine fails..
Return Value:
Nothing
--*/
{
LOCK_MSCOPE_LIST();
do {
DhcpAssert(Initialized >= 0);
if( Initialized <= 0 ) break;
Initialized --;
if( 0 != Initialized ) break;
gMadcapScopeList = NULL;
gMScopeQueryInProgress = FALSE;
if( NULL != gMScopeQueryEvent ) {
CloseHandle(gMScopeQueryEvent);
gMScopeQueryEvent = NULL;
}
WSACleanup();
} while ( 0 );
UNLOCK_MSCOPE_LIST();
}
BOOL
ShouldRequeryMScopeList()
/*++
Routine Description:
This routine checks if the multicast scope list can be
queried or not.
* If there is already a query in progress, then this routine
waits for that to complete and then returns FALSE.
* If there is no query in progress, it returns TRUE.
Arguments:
Return Value:
The status of the operation.
--*/
{
LOCK_MSCOPE_LIST();
if ( gMScopeQueryInProgress ) {
DWORD result;
DhcpPrint((DEBUG_API, "MScopeQuery is in progress - waiting\n"));
// make sure the event is not in signalled state from before.
ResetEvent( gMScopeQueryEvent );
UNLOCK_MSCOPE_LIST();
switch( result = WaitForSingleObject( gMScopeQueryEvent, INFINITE ) ) {
case WAIT_OBJECT_0:
// it's signled now, no need to requery the list, just take the result from previous query.
DhcpPrint((DEBUG_API, "MScopeQuery event signalled\n"));
return FALSE;
case WAIT_ABANDONED:
DhcpPrint((DEBUG_ERRORS, "WaitForSingleObject - thread died before the wait completed\n"));
return TRUE;
case WAIT_FAILED:
DhcpPrint((DEBUG_ERRORS, "WaitForSingleObject failed - %lx\n",GetLastError()));
DhcpAssert(FALSE);
default:
DhcpPrint((DEBUG_ERRORS, "WaitForSingleObject returned unknown value - %lx\n", result));
DhcpAssert(FALSE);
return TRUE;
}
} else {
gMScopeQueryInProgress = TRUE;
UNLOCK_MSCOPE_LIST();
return TRUE;
}
}
DWORD
InitializeMadcapSocket(
SOCKET *Socket,
DHCP_IP_ADDRESS IpAddress
)
/*++
Routine Description:
This function initializes and binds a socket to the specified IP address.
Arguments:
Socket - Returns a pointer to the initialized socket.
IpAddress - The IP address to bind the socket to.
Return Value:
The status of the operation.
--*/
{
DWORD error;
DWORD closeError;
DWORD value;
struct sockaddr_in socketName;
DWORD i;
SOCKET sock;
//
// Sockets initialization
//
sock = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
if ( sock == INVALID_SOCKET ) {
error = WSAGetLastError();
DhcpPrint(( DEBUG_ERRORS, "socket failed, error = %ld\n", error ));
return( error );
}
//
// Make the socket share-able
//
value = 1;
error = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (char FAR *)&value, sizeof(value) );
if ( error != 0 ) {
error = WSAGetLastError();
DhcpPrint((DEBUG_ERRORS, "setsockopt failed, err = %ld\n", error ));
closeError = closesocket( sock );
if ( closeError != 0 ) {
DhcpPrint((DEBUG_ERRORS, "closesocket failed, err = %d\n", closeError ));
}
return( error );
}
socketName.sin_family = PF_INET;
socketName.sin_port = 0; // let the winsock pick a port for us.
socketName.sin_addr.s_addr = IpAddress;
for ( i = 0; i < 8 ; i++ ) {
socketName.sin_zero[i] = 0;
}
//
// Bind this socket to the DHCP server port
//
error = bind(
sock,
(struct sockaddr FAR *)&socketName,
sizeof( socketName )
);
if ( error != 0 ) {
error = WSAGetLastError();
DhcpPrint((DEBUG_ERRORS, "bind failed, err = %ld\n", error ));
closeError = closesocket( sock );
if ( closeError != 0 ) {
DhcpPrint((DEBUG_ERRORS, "closesocket failed, err = %d\n", closeError ));
}
return( error );
}
// set the multicast IF to be the one on which we are doing Madcap
if (INADDR_ANY != IpAddress) {
value = IpAddress;
DhcpPrint((DEBUG_ERRORS, "setsockopt: IP_MULTICAST_IF, if = %lx\n", IpAddress ));
error = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_IF,
(char FAR *)&value, sizeof(value) );
if ( error != 0 ) {
error = WSAGetLastError();
DhcpPrint((DEBUG_ERRORS, "setsockopt failed, err = %ld\n", error ));
closeError = closesocket( sock );
if ( closeError != 0 ) {
DhcpPrint((DEBUG_ERRORS, "closesocket failed, err = %d\n", closeError ));
}
return( error );
}
}
*Socket = sock;
return( NO_ERROR );
}
DWORD
ReInitializeMadcapSocket(
SOCKET *Socket,
DHCP_IP_ADDRESS IpAddress
)
/*++
Routine Description:
This function closes and reinitializes the socket to specified IP address.
Arguments:
Socket - Returns a pointer to the initialized socket.
IpAddress - The IP address to bind the socket to.
Return Value:
The status of the operation.
--*/
{
DWORD Error;
if (*Socket != INVALID_SOCKET) {
Error = closesocket( *Socket );
if ( Error != 0 ) {
DhcpPrint((DEBUG_ERRORS, "closesocket failed, err = %d\n", Error ));
return Error;
}
}
return InitializeMadcapSocket( Socket, IpAddress );
}
DWORD
OpenMadcapSocket(
PDHCP_CONTEXT DhcpContext
)
{
DWORD Error;
PLOCAL_CONTEXT_INFO localInfo;
struct sockaddr_in socketName;
int sockAddrLen;
localInfo = DhcpContext->LocalInformation;
if ( INVALID_SOCKET == localInfo->Socket ) {
Error = InitializeMadcapSocket(&localInfo->Socket, DhcpContext->IpAddress);
if( Error != ERROR_SUCCESS ) {
localInfo->Socket = INVALID_SOCKET;
DhcpPrint(( DEBUG_ERRORS, " Socket Open failed, %ld\n", Error ));
return Error;
}
}
// find out which port we are bound to.
sockAddrLen = sizeof(struct sockaddr_in);
Error = getsockname(
localInfo->Socket ,
(struct sockaddr FAR *)&socketName,
&sockAddrLen
);
if ( Error != 0 ) {
DWORD closeError;
Error = WSAGetLastError();
DhcpPrint((DEBUG_ERRORS, "bind failed, err = %ld\n", Error ));
closeError = closesocket( localInfo->Socket );
if ( closeError != 0 ) {
DhcpPrint((DEBUG_ERRORS, "closesocket failed, err = %d\n", closeError ));
}
return( Error );
}
return(Error);
}
DWORD
CreateMadcapContext(
IN OUT PDHCP_CONTEXT *ppContext,
IN LPMCAST_CLIENT_UID pRequestID,
IN DHCP_IP_ADDRESS IpAddress
)
/*++
Routine Description:
This routine creates a dummy context for doing Madcap operation
on it.
Arguments:
ppContext - pointer to where context pointer is to be stored.
pRequestID - The client id to be used in the context.
IpAddress - The ipaddress the context is initialized with.
Return Value:
The status of the operation.
--*/
{
DWORD Error;
PDHCP_CONTEXT DhcpContext = NULL;
ULONG DhcpContextSize;
PLOCAL_CONTEXT_INFO LocalInfo = NULL;
LPVOID Ptr;
LPDHCP_LEASE_INFO LocalLeaseInfo = NULL;
time_t LeaseObtained;
DWORD T1, T2, Lease;
DWORD AdapterNameLen;
//
// prepare dhcp context structure.
//
DhcpContextSize =
ROUND_UP_COUNT(sizeof(DHCP_CONTEXT), ALIGN_WORST) +
ROUND_UP_COUNT(pRequestID->ClientUIDLength, ALIGN_WORST) +
ROUND_UP_COUNT(sizeof(LOCAL_CONTEXT_INFO), ALIGN_WORST) +
ROUND_UP_COUNT(DHCP_RECV_MESSAGE_SIZE, ALIGN_WORST);
Ptr = DhcpAllocateMemory( DhcpContextSize );
if ( Ptr == NULL ) {
return( ERROR_NOT_ENOUGH_MEMORY );
}
RtlZeroMemory( Ptr, DhcpContextSize );
//
// make sure the pointers are aligned.
//
DhcpContext = Ptr;
Ptr = ROUND_UP_POINTER( (LPBYTE)Ptr + sizeof(DHCP_CONTEXT), ALIGN_WORST);
DhcpContext->ClientIdentifier.pbID = Ptr;
Ptr = ROUND_UP_POINTER( (LPBYTE)Ptr + pRequestID->ClientUIDLength, ALIGN_WORST);
DhcpContext->LocalInformation = Ptr;
LocalInfo = Ptr;
Ptr = ROUND_UP_POINTER( (LPBYTE)Ptr + sizeof(LOCAL_CONTEXT_INFO), ALIGN_WORST);
DhcpContext->MadcapMessageBuffer = Ptr;
//
// initialize fields.
//
DhcpContext->ClientIdentifier.fSpecified = TRUE;
DhcpContext->ClientIdentifier.bType = HARDWARE_TYPE_NONE;
DhcpContext->ClientIdentifier.cbID = pRequestID->ClientUIDLength;
RtlCopyMemory(
DhcpContext->ClientIdentifier.pbID,
pRequestID->ClientUID,
pRequestID->ClientUIDLength
);
DhcpContext->IpAddress = IpAddress;
DhcpContext->SubnetMask = DhcpDefaultSubnetMask(0);
DhcpContext->DhcpServerAddress = MADCAP_SERVER_IP_ADDRESS;
DhcpContext->DesiredIpAddress = 0;
SET_MDHCP_STATE(DhcpContext);
InitializeListHead(&DhcpContext->RenewalListEntry);
InitializeListHead(&DhcpContext->SendOptionsList);
InitializeListHead(&DhcpContext->RecdOptionsList);
InitializeListHead(&DhcpContext->FbOptionsList);
InitializeListHead(&DhcpContext->NicListEntry);
DhcpContext->DontPingGatewayFlag = TRUE;
//
// copy local info.
//
//
// unused portion of the local info.
//
LocalInfo->IpInterfaceContext = 0xFFFFFFFF;
LocalInfo->IpInterfaceInstance = 0xFFFFFFFF;
LocalInfo->AdapterName = NULL;
LocalInfo->NetBTDeviceName= NULL;
LocalInfo->RegistryKey= NULL;
LocalInfo->Socket = INVALID_SOCKET;
LocalInfo->DefaultGatewaysSet = FALSE;
//
// used portion of the local info.
//
LocalInfo->Socket = INVALID_SOCKET;
//
// open socket now. receive any.
//
Error = InitializeMadcapSocket(&LocalInfo->Socket,DhcpContext->IpAddress);
if( Error != ERROR_SUCCESS ) {
DhcpFreeMemory( DhcpContext );
return Error;
} else {
*ppContext = DhcpContext;
return Error;
}
}
DWORD
SendMadcapMessage(
PDHCP_CONTEXT DhcpContext,
DWORD MessageLength,
PDWORD TransactionId
)
/*++
Routine Description:
This function sends a UDP message to the DHCP server specified
in the DhcpContext.
Arguments:
DhcpContext - A pointer to a DHCP context block.
MessageLength - The length of the message to send.
TransactionID - The transaction ID for this message. If 0, the
function generates a random ID, and returns it.
Return Value:
The status of the operation.
--*/
{
DWORD error;
int i;
struct sockaddr_in socketName;
time_t TimeNow;
BOOL LockedInterface = FALSE;
if ( *TransactionId == 0 ) {
*TransactionId = (rand() << 16) + rand();
}
DhcpContext->MadcapMessageBuffer->TransactionID = *TransactionId;
//
// Initialize the outgoing address.
//
socketName.sin_family = PF_INET;
socketName.sin_port = htons( MADCAP_SERVER_PORT);
socketName.sin_addr.s_addr = DhcpContext->DhcpServerAddress;
if ( CLASSD_NET_ADDR( DhcpContext->DhcpServerAddress ) ) {
int TTL = 16;
//
// Set TTL
// MBUG: we need to read this from the registry.
//
if (setsockopt(
((PLOCAL_CONTEXT_INFO)DhcpContext->LocalInformation)->Socket,
IPPROTO_IP,
IP_MULTICAST_TTL,
(char *)&TTL,
sizeof((int)TTL)) == SOCKET_ERROR){
error = WSAGetLastError();
DhcpPrint((DEBUG_ERRORS,"could not set MCast TTL %ld\n",error ));
return error;
}
}
for ( i = 0; i < 8 ; i++ ) {
socketName.sin_zero[i] = 0;
}
error = sendto(
((PLOCAL_CONTEXT_INFO)
DhcpContext->LocalInformation)->Socket,
(PCHAR)DhcpContext->MadcapMessageBuffer,
MessageLength,
0,
(struct sockaddr *)&socketName,
sizeof( struct sockaddr )
);
if ( error == SOCKET_ERROR ) {
error = WSAGetLastError();
DhcpPrint(( DEBUG_ERRORS, "Send failed, error = %ld\n", error ));
} else {
IF_DEBUG( PROTOCOL ) {
DhcpPrint(( DEBUG_PROTOCOL, "Sent message to %s: \n", inet_ntoa( socketName.sin_addr )));
}
MadcapDumpMessage(
DEBUG_PROTOCOL_DUMP,
DhcpContext->MadcapMessageBuffer,
DHCP_MESSAGE_SIZE
);
error = NO_ERROR;
}
return( error );
}
WIDE_OPTION UNALIGNED * // ptr to add additional options
FormatMadcapCommonMessage( // format the packet for an INFORM
IN PDHCP_CONTEXT DhcpContext, // format for this context
IN BYTE MessageType
) {
DWORD size;
DWORD Error;
WIDE_OPTION UNALIGNED *option;
LPBYTE OptionEnd;
PMADCAP_MESSAGE dhcpMessage;
dhcpMessage = DhcpContext->MadcapMessageBuffer;
RtlZeroMemory( dhcpMessage, DHCP_SEND_MESSAGE_SIZE );
dhcpMessage->Version = MADCAP_VERSION;
dhcpMessage->MessageType = MessageType;
dhcpMessage->AddressFamily = htons(MADCAP_ADDR_FAMILY_V4);
option = &dhcpMessage->Option;
OptionEnd = (LPBYTE)dhcpMessage + DHCP_SEND_MESSAGE_SIZE;
option = AppendWideOption( // ==> use this client id as option
option,
MADCAP_OPTION_LEASE_ID,
DhcpContext->ClientIdentifier.pbID,
(WORD)DhcpContext->ClientIdentifier.cbID,
OptionEnd
);
return( option );
}
DWORD // status
SendMadcapInform( // send an inform packet after filling required options
IN PDHCP_CONTEXT DhcpContext, // sned out for this context
IN OUT DWORD *pdwXid // use this Xid (if zero fill something and return it)
) {
DWORD size;
WIDE_OPTION UNALIGNED * option;
LPBYTE OptionEnd;
WORD OptVal[] = { // for now we just need this one option.
htons(MADCAP_OPTION_MCAST_SCOPE_LIST) // multicast scope list.
};
option = FormatMadcapCommonMessage(DhcpContext, MADCAP_INFORM_MESSAGE);
OptionEnd = (LPBYTE)(DhcpContext->MadcapMessageBuffer) + DHCP_SEND_MESSAGE_SIZE;
option = AppendWideOption(
option,
MADCAP_OPTION_REQUEST_LIST,
OptVal,
sizeof (OptVal),
OptionEnd
);
option = AppendWideOption( option, MADCAP_OPTION_END, NULL, 0, OptionEnd );
size = (DWORD)((PBYTE)option - (PBYTE)DhcpContext->MadcapMessageBuffer);
return SendMadcapMessage( // finally send the message and return
DhcpContext,
size,
pdwXid
);
}
DWORD // status
SendMadcapDiscover( // send an inform packet after filling required options
IN PDHCP_CONTEXT DhcpContext, // sned out for this context
IN PIPNG_ADDRESS pScopeID,
IN PMCAST_LEASE_REQUEST pAddrRequest,
IN OUT DWORD *pdwXid // use this Xid (if zero fill something and return it)
) {
DWORD size;
WIDE_OPTION UNALIGNED * option;
LPBYTE OptionEnd;
option = FormatMadcapCommonMessage(DhcpContext, MADCAP_DISCOVER_MESSAGE);
OptionEnd = (LPBYTE)(DhcpContext->MadcapMessageBuffer) + DHCP_SEND_MESSAGE_SIZE;
DhcpAssert(pScopeID);
option = AppendWideOption(
option,
MADCAP_OPTION_MCAST_SCOPE,
(LPBYTE)&pScopeID->IpAddrV4,
sizeof (pScopeID->IpAddrV4),
OptionEnd
);
if (pAddrRequest->LeaseDuration) {
DWORD Lease = htonl(pAddrRequest->LeaseDuration);
option = AppendWideOption(
option,
MADCAP_OPTION_LEASE_TIME,
(LPBYTE)&Lease,
sizeof (Lease),
OptionEnd
);
}
if( pAddrRequest->MinLeaseDuration ) {
DWORD MinLease = htonl(pAddrRequest->MinLeaseDuration);
option = AppendWideOption(
option,
MADCAP_OPTION_MIN_LEASE_TIME,
(LPBYTE)&MinLease,
sizeof(MinLease),
OptionEnd
);
}
if( pAddrRequest->MaxLeaseStartTime ) {
DWORD TimeNow = htonl((DWORD)time(NULL));
DWORD StartTime = htonl(pAddrRequest->MaxLeaseStartTime);
option = AppendWideOption(
option,
MADCAP_OPTION_MAX_START_TIME,
(LPBYTE)&StartTime,
sizeof (StartTime),
OptionEnd
);
if( !(pAddrRequest->LeaseStartTime) ) {
//
// if lease start time specified, then current time
// option will be added at a later point
//
option = AppendWideOption(
option,
MADCAP_OPTION_TIME,
(LPBYTE)&TimeNow,
sizeof (TimeNow),
OptionEnd
);
}
}
if (pAddrRequest->LeaseStartTime) {
DWORD TimeNow = htonl((DWORD)time(NULL));
DWORD StartTime = htonl(pAddrRequest->LeaseStartTime);
option = AppendWideOption(
option,
MADCAP_OPTION_START_TIME,
(LPBYTE)&StartTime,
sizeof (StartTime),
OptionEnd
);
option = AppendWideOption(
option,
MADCAP_OPTION_TIME,
(LPBYTE)&TimeNow,
sizeof (TimeNow),
OptionEnd
);
}
option = AppendWideOption( option, MADCAP_OPTION_END, NULL, 0, OptionEnd );
size = (DWORD)((PBYTE)option - (PBYTE)DhcpContext->MadcapMessageBuffer);
return SendMadcapMessage( // finally send the message and return
DhcpContext,
size,
pdwXid
);
}
DWORD // status
SendMadcapRequest( //
IN PDHCP_CONTEXT DhcpContext, // sned out for this context
IN PIPNG_ADDRESS pScopeID,
IN PMCAST_LEASE_REQUEST pAddrRequest,
IN DWORD SelectedServer, // is there a prefernce for a server?
IN OUT DWORD *pdwXid // use this Xid (if zero fill something and return it)
) {
DWORD size;
WIDE_OPTION UNALIGNED * option;
LPBYTE OptionEnd;
BYTE ServerId[6];
WORD AddrFamily = htons(MADCAP_ADDR_FAMILY_V4);
option = FormatMadcapCommonMessage(DhcpContext, MADCAP_REQUEST_MESSAGE);
OptionEnd = (LPBYTE)(DhcpContext->MadcapMessageBuffer) + DHCP_SEND_MESSAGE_SIZE;
option = AppendMadcapAddressList(
option,
(DWORD UNALIGNED *)pAddrRequest->pAddrBuf,
pAddrRequest->AddrCount,
OptionEnd
);
option = AppendWideOption(
option,
MADCAP_OPTION_MCAST_SCOPE,
(LPBYTE)&pScopeID->IpAddrV4,
sizeof (pScopeID->IpAddrV4),
OptionEnd
);
if (pAddrRequest->LeaseDuration) {
DWORD TimeNow = (DWORD)time(NULL);
DWORD Lease = htonl(pAddrRequest->LeaseDuration);
option = AppendWideOption(
option,
MADCAP_OPTION_LEASE_TIME,
(LPBYTE)&Lease,
sizeof (Lease),
OptionEnd
);
}
if( pAddrRequest->MinLeaseDuration ) {
DWORD MinLease = htonl(pAddrRequest->MinLeaseDuration);
option = AppendWideOption(
option,
MADCAP_OPTION_MIN_LEASE_TIME,
(LPBYTE)&MinLease,
sizeof(MinLease),
OptionEnd
);
}
if( pAddrRequest->MaxLeaseStartTime ) {
DWORD TimeNow = htonl((DWORD)time(NULL));
DWORD StartTime = htonl(pAddrRequest->MaxLeaseStartTime);
option = AppendWideOption(
option,
MADCAP_OPTION_MAX_START_TIME,
(LPBYTE)&StartTime,
sizeof (StartTime),
OptionEnd
);
if( !(pAddrRequest->LeaseStartTime) ) {
//
// if lease start time specified, then current time
// option will be added at a later point
//
option = AppendWideOption(
option,
MADCAP_OPTION_TIME,
(LPBYTE)&TimeNow,
sizeof (TimeNow),
OptionEnd
);
}
}
if (pAddrRequest->LeaseStartTime) {
DWORD TimeNow = htonl((DWORD)time(NULL));
DWORD StartTime = htonl(pAddrRequest->LeaseStartTime);
option = AppendWideOption(
option,
MADCAP_OPTION_START_TIME,
(LPBYTE)&StartTime,
sizeof (StartTime),
OptionEnd
);
option = AppendWideOption(
option,
MADCAP_OPTION_TIME,
(LPBYTE)&TimeNow,
sizeof (TimeNow),
OptionEnd
);
}
memcpy(ServerId, &AddrFamily, 2);
memcpy(ServerId + 2, &SelectedServer, 4);
option = AppendWideOption(
option, // append this option to talk to that server alone
MADCAP_OPTION_SERVER_ID,
(LPBYTE)&ServerId,
sizeof( ServerId ),
OptionEnd
);
option = AppendWideOption( option, MADCAP_OPTION_END, NULL, 0, OptionEnd );
size = (DWORD)((PBYTE)option - (PBYTE)DhcpContext->MadcapMessageBuffer);
return SendMadcapMessage( // finally send the message and return
DhcpContext,
size,
pdwXid
);
}
DWORD // status
SendMadcapRenew( // send an inform packet after filling required options
IN PDHCP_CONTEXT DhcpContext, // sned out for this context
IN PMCAST_LEASE_REQUEST pAddrRequest,
IN OUT DWORD *pdwXid // use this Xid (if zero fill something and return it)
) {
DWORD size;
WIDE_OPTION UNALIGNED * option;
LPBYTE OptionEnd;
option = FormatMadcapCommonMessage(DhcpContext, MADCAP_RENEW_MESSAGE);
OptionEnd = (LPBYTE)(DhcpContext->MadcapMessageBuffer) + DHCP_SEND_MESSAGE_SIZE;
if (pAddrRequest->LeaseDuration) {
DWORD Lease = htonl(pAddrRequest->LeaseDuration);
option = AppendWideOption(
option,
MADCAP_OPTION_LEASE_TIME,
(LPBYTE)&Lease,
sizeof (Lease),
OptionEnd
);
}
if( pAddrRequest->MinLeaseDuration ) {
DWORD MinLease = htonl(pAddrRequest->MinLeaseDuration);
option = AppendWideOption(
option,
MADCAP_OPTION_MIN_LEASE_TIME,
(LPBYTE)&MinLease,
sizeof(MinLease),
OptionEnd
);
}
if( pAddrRequest->MaxLeaseStartTime ) {
DWORD TimeNow = htonl((DWORD)time(NULL));
DWORD StartTime = htonl(pAddrRequest->MaxLeaseStartTime);
option = AppendWideOption(
option,
MADCAP_OPTION_MAX_START_TIME,
(LPBYTE)&StartTime,
sizeof (StartTime),
OptionEnd
);
if( !(pAddrRequest->LeaseStartTime) ) {
//
// if lease start time specified, then current time
// option will be added at a later point
//
option = AppendWideOption(
option,
MADCAP_OPTION_TIME,
(LPBYTE)&TimeNow,
sizeof (TimeNow),
OptionEnd
);
}
}
if (pAddrRequest->LeaseStartTime) {
DWORD TimeNow = htonl((DWORD)time(NULL));
DWORD StartTime = htonl(pAddrRequest->LeaseStartTime);
option = AppendWideOption(
option,
MADCAP_OPTION_START_TIME,
(LPBYTE)&StartTime,
sizeof (StartTime),
OptionEnd
);
option = AppendWideOption(
option,
MADCAP_OPTION_TIME,
(LPBYTE)&TimeNow,
sizeof (TimeNow),
OptionEnd
);
}
option = AppendWideOption( option, MADCAP_OPTION_END, NULL, 0, OptionEnd );
size = (DWORD)((PBYTE)option - (PBYTE)DhcpContext->MadcapMessageBuffer);
return SendMadcapMessage( // finally send the message and return
DhcpContext,
size,
pdwXid
);
}
DWORD // status
SendMadcapRelease( // send an inform packet after filling required options
IN PDHCP_CONTEXT DhcpContext, // sned out for this context
IN OUT DWORD *pdwXid // use this Xid (if zero fill something and return it)
) {
DWORD size;
WIDE_OPTION UNALIGNED * option;
LPBYTE OptionEnd;
option = FormatMadcapCommonMessage(DhcpContext, MADCAP_RELEASE_MESSAGE);
OptionEnd = (LPBYTE)(DhcpContext->MadcapMessageBuffer) + DHCP_SEND_MESSAGE_SIZE;
option = AppendWideOption( option, MADCAP_OPTION_END, NULL, 0, OptionEnd );
size = (DWORD)((PBYTE)option - (PBYTE)DhcpContext->MadcapMessageBuffer);
return SendMadcapMessage( // finally send the message and return
DhcpContext,
size,
pdwXid
);
}
#define RATIO 1
DWORD
GetSpecifiedMadcapMessage(
PDHCP_CONTEXT DhcpContext,
PDWORD BufferLength,
DWORD TransactionId,
DWORD TimeToWait
)
/*++
Routine Description:
This function waits TimeToWait seconds to receives the specified
DHCP response.
Arguments:
DhcpContext - A pointer to a DHCP context block.
BufferLength - Returns the size of the input buffer.
TransactionID - A filter. Wait for a message with this TID.
TimeToWait - Time, in milli seconds, to wait for the message.
Return Value:
The status of the operation. If the specified message has been
been returned, the status is ERROR_TIMEOUT.
--*/
{
struct sockaddr socketName;
int socketNameSize = sizeof( socketName );
struct timeval timeout;
time_t startTime, now;
DWORD error;
time_t actualTimeToWait;
SOCKET clientSocket;
fd_set readSocketSet;
PMADCAP_MESSAGE MadcapMessage;
startTime = time( NULL );
actualTimeToWait = TimeToWait;
//
// Setup the file descriptor set for select.
//
clientSocket = ((PLOCAL_CONTEXT_INFO)DhcpContext->LocalInformation)->Socket;
MadcapMessage = DhcpContext->MadcapMessageBuffer;
FD_ZERO( &readSocketSet );
FD_SET( clientSocket, &readSocketSet );
while ( 1 ) {
timeout.tv_sec = (long)(actualTimeToWait / RATIO);
timeout.tv_usec = (long)(actualTimeToWait % RATIO);
DhcpPrint((DEBUG_TRACE, "Select: waiting for: %ld seconds\n", actualTimeToWait));
error = select( 0, &readSocketSet, NULL, NULL, &timeout );
if ( error == 0 ) {
//
// Timeout before read data is available.
//
DhcpPrint(( DEBUG_ERRORS, "Recv timed out\n", 0 ));
error = ERROR_TIMEOUT;
break;
}
error = recvfrom(
clientSocket,
(PCHAR)MadcapMessage,
*BufferLength,
0,
&socketName,
&socketNameSize
);
if ( error == SOCKET_ERROR ) {
error = WSAGetLastError();
DhcpPrint(( DEBUG_ERRORS, "Recv failed, error = %ld\n", error ));
if( WSAECONNRESET != error ) break;
//
// ignore connreset -- this could be caused by someone sending random ICMP port unreachable.
//
} else if (error <= MADCAP_MESSAGE_FIXED_PART_SIZE) {
DhcpPrint(( DEBUG_PROTOCOL, "Received a too short madcap message, length = %lx\n",
error ));
} else if (MadcapMessage->TransactionID == TransactionId ) {
DhcpPrint(( DEBUG_PROTOCOL,
"Received Message, XID = %lx\n",
TransactionId));
// just sanity check the remaining fields
if ( MADCAP_VERSION == MadcapMessage->Version &&
MADCAP_ADDR_FAMILY_V4 == ntohs(MadcapMessage->AddressFamily)) {
MadcapDumpMessage(
DEBUG_PROTOCOL_DUMP,
MadcapMessage,
DHCP_RECV_MESSAGE_SIZE
);
*BufferLength = error;
error = NO_ERROR;
break;
}
} else {
DhcpPrint(( DEBUG_PROTOCOL,
"Received a buffer with unknown XID = %lx\n",
MadcapMessage->TransactionID ));
}
//
// We received a message, but not the one we're interested in.
// Reset the timeout to reflect elapsed time, and wait for
// another message.
//
now = time( NULL );
actualTimeToWait = TimeToWait - RATIO * (now - startTime);
if ( (LONG)actualTimeToWait < 0 ) {
error = ERROR_TIMEOUT;
break;
}
}
return( error );
}
//--------------------------------------------------------------------------------
// This function decides if multicast offer is to be accepted or not.
//--------------------------------------------------------------------------------
BOOL
AcceptMadcapMsg(
IN DWORD MessageType, // message type to which this response came
IN PDHCP_CONTEXT DhcpContext, // The context of the adapter..
IN PMADCAP_OPTIONS MadcapOptions, // rcvd options.
IN DHCP_IP_ADDRESS SelectedServer, // the server which we care about.
OUT DWORD *Error // additional fatal error.
) {
PMADCAP_MESSAGE MadcapMessage;
*Error = ERROR_SUCCESS;
MadcapMessage = DhcpContext->MadcapMessageBuffer;
if ( !MadcapOptions->ServerIdentifier ){
DhcpPrint((DEBUG_ERRORS, "Received no server identifier, dropping response\n"));
return FALSE;
}
if ( !MadcapOptions->ClientGuid ){
DhcpPrint((DEBUG_ERRORS, "Received no client identifier, dropping response\n"));
return FALSE;
}
if (DhcpContext->ClientIdentifier.cbID != MadcapOptions->ClientGuidLength ||
0 != memcmp(DhcpContext->ClientIdentifier.pbID,
MadcapOptions->ClientGuid,
MadcapOptions->ClientGuidLength) ) {
return FALSE;
}
if (MadcapOptions->MCastLeaseStartTime && !MadcapOptions->Time) {
DhcpPrint((DEBUG_ERRORS, "Received start time but no current time\n"));
return FALSE;
}
switch( MessageType ) {
case MADCAP_INFORM_MESSAGE:
if (MADCAP_ACK_MESSAGE != MadcapMessage->MessageType) {
return FALSE;
}
break;
case MADCAP_DISCOVER_MESSAGE:
if (MADCAP_OFFER_MESSAGE != MadcapMessage->MessageType) {
return FALSE;
}
if (!MadcapOptions->AddrRangeList) {
return FALSE;
}
if (!MadcapOptions->LeaseTime) {
return FALSE;
}
if (!MadcapOptions->McastScope) {
return FALSE;
}
break;
case MADCAP_RENEW_MESSAGE:
case MADCAP_REQUEST_MESSAGE:
if (MADCAP_NACK_MESSAGE == MadcapMessage->MessageType &&
SelectedServer == *MadcapOptions->ServerIdentifier) {
DhcpPrint((DEBUG_ERRORS, "Received NACK\n"));
*Error = ERROR_ACCESS_DENIED;
return FALSE;
}
if (MADCAP_ACK_MESSAGE != MadcapMessage->MessageType) {
return FALSE;
}
if (SelectedServer && SelectedServer != *MadcapOptions->ServerIdentifier) {
return FALSE;
}
if (!MadcapOptions->LeaseTime) {
return FALSE;
}
if (!MadcapOptions->AddrRangeList) {
return FALSE;
}
if (!MadcapOptions->McastScope) {
return FALSE;
}
break;
case MADCAP_RELEASE_MESSAGE:
if (MADCAP_ACK_MESSAGE != MadcapMessage->MessageType) {
return FALSE;
}
break;
default:
DhcpAssert( FALSE );
DhcpPrint(( DEBUG_PROTOCOL, "Received Unknown Message.\n"));
return FALSE;
}
// Is this really necessary?
if (MadcapOptions->Error) {
return FALSE;
}
return TRUE; // accept this message.
}
VOID
MadcapExtractOptions( // Extract some important options alone or ALL
IN PDHCP_CONTEXT DhcpContext, // input context
IN LPBYTE OptStart, // start of the options stuff
IN DWORD MessageSize, // # of bytes of options
OUT PMADCAP_OPTIONS MadcapOptions, // this is where the options would be stored
IN OUT PLIST_ENTRY RecdOptions, // if !LiteOnly this gets filled with all incoming options
IN DWORD ServerId // if !LiteOnly this specifies the server which gave this
) {
WIDE_OPTION UNALIGNED* NextOpt;
BYTE UNALIGNED* EndOpt;
WORD Size;
DWORD OptionType;
DWORD Error;
WORD AddrFamily;
EndOpt = OptStart + MessageSize; // all options should be < EndOpt;
RtlZeroMemory((LPBYTE)MadcapOptions, sizeof(*MadcapOptions));
if( 0 == MessageSize ) goto DropPkt; // nothing to do in this case
NextOpt = (WIDE_OPTION UNALIGNED*)OptStart;
while( NextOpt->OptionValue <= EndOpt &&
MADCAP_OPTION_END != (OptionType = ntohs(NextOpt->OptionType)) ) {
Size = ntohs(NextOpt->OptionLength);
if ((NextOpt->OptionValue + Size) > EndOpt) {
goto DropPkt;
}
switch( OptionType ) {
case MADCAP_OPTION_LEASE_TIME:
if( Size != sizeof(DWORD) ) goto DropPkt;
MadcapOptions->LeaseTime = (DWORD UNALIGNED *)NextOpt->OptionValue;
break;
case MADCAP_OPTION_SERVER_ID:
if (Size != 6) goto DropPkt;
AddrFamily = ntohs(*(WORD UNALIGNED *)NextOpt->OptionValue);
if ( MADCAP_ADDR_FAMILY_V4 != AddrFamily ) goto DropPkt;
MadcapOptions->ServerIdentifier = (DHCP_IP_ADDRESS UNALIGNED *)(NextOpt->OptionValue+2);
break;
case MADCAP_OPTION_LEASE_ID:
if( 0 == Size ) goto DropPkt;
MadcapOptions->ClientGuidLength = Size;
MadcapOptions->ClientGuid = NextOpt->OptionValue;
break;
case MADCAP_OPTION_MCAST_SCOPE:
if( Size != sizeof(DWORD) ) goto DropPkt;
MadcapOptions->McastScope = (DWORD UNALIGNED *)NextOpt->OptionValue;
break;
case MADCAP_OPTION_START_TIME:
if ( Size != sizeof(DATE_TIME) ) goto DropPkt;
MadcapOptions->MCastLeaseStartTime = (DWORD UNALIGNED *)NextOpt->OptionValue;
break;
case MADCAP_OPTION_ADDR_LIST:
if( Size % 6 ) goto DropPkt;
MadcapOptions->AddrRangeList = NextOpt->OptionValue;
MadcapOptions->AddrRangeListSize = Size;
break;
case MADCAP_OPTION_TIME:
if( Size != sizeof(DWORD) ) goto DropPkt;
MadcapOptions->Time = (DWORD UNALIGNED *)NextOpt->OptionValue;
break;
case MADCAP_OPTION_FEATURE_LIST:
break;
case MADCAP_OPTION_RETRY_TIME:
if( Size != sizeof(DWORD) ) goto DropPkt;
MadcapOptions->RetryTime = (DWORD UNALIGNED *)NextOpt->OptionValue;
break;
case MADCAP_OPTION_ERROR:
if( Size != sizeof(DWORD) ) goto DropPkt;
MadcapOptions->Error = (DWORD UNALIGNED *)NextOpt->OptionValue;
break;
default:
// unknowm message, nothing to do.. especially dont log this
break;
}
if (RecdOptions) {
DhcpAssert(ServerId);
Error = MadcapAddIncomingOption( // Now add this option to the list
RecdOptions,
OptionType,
ServerId,
NextOpt->OptionValue,
Size,
(DWORD)INFINIT_TIME
);
if (ERROR_SUCCESS != Error) {
goto DropPkt;
}
}
NextOpt = (WIDE_OPTION UNALIGNED*)(NextOpt->OptionValue + Size);
} // while NextOpt < EndOpt
return;
DropPkt:
RtlZeroMemory(MadcapOptions, sizeof(MadcapOptions));
if(RecdOptions) DhcpFreeAllOptions(RecdOptions);// ok undo the options that we just added
}
DWORD
MadcapDoInform(
IN PDHCP_CONTEXT DhcpContext
)
/*++
Routine Description:
This routine does the inform part by sending inform messages and
collecting responses etc. on given context.
In case of no-response, no error is returned as a timeout is not
considered an error.
Arguments:
DhcpContext -- context to dhcp struct
fBroadcast -- should the inform be broadcast or unicast?
Return Values:
Win32 errors
--*/
{
time_t StartTime;
time_t TimeNow;
time_t TimeToWait;
DWORD Error;
DWORD Xid;
DWORD MessageSize;
DWORD RoundNum;
DWORD MessageCount;
DWORD LeaseExpirationTime;
MADCAP_OPTIONS MadcapOptions;
BOOL GotAck;
#define MIN_ACKS_FOR_INFORM MADCAP_QUERY_SCOPE_LIST_RETRIES
DWORD MadcapServers[MIN_ACKS_FOR_INFORM];
DhcpPrint((DEBUG_PROTOCOL, "MadcapDoInform entered\n"));
Xid = 0; // Will be generated by first SendDhcpPacket
MessageCount = 0; // total # of messages we have got
TimeToWait = MADCAP_QUERY_SCOPE_LIST_TIME * 1000;
TimeToWait += ((rand() * ((DWORD) 1000))/RAND_MAX);
TimeToWait /= 1000;
for( RoundNum = 0; RoundNum <= MADCAP_QUERY_SCOPE_LIST_RETRIES; RoundNum ++ ) {
if( RoundNum != MADCAP_QUERY_SCOPE_LIST_RETRIES ) {
Error = SendMadcapInform(DhcpContext, &Xid);
if( ERROR_SUCCESS != Error ) {
DhcpPrint((DEBUG_ERRORS, "SendMadcapInform: %ld\n", Error));
goto Cleanup;
} else {
DhcpPrint((DEBUG_PROTOCOL, "Sent DhcpInform\n"));
}
}
StartTime = time(NULL);
while ( TRUE ) { // wiat for the specified wait time
MessageSize = DHCP_RECV_MESSAGE_SIZE;
DhcpPrint((DEBUG_TRACE, "Waiting for ACK[Xid=%x]: %ld seconds\n",Xid, TimeToWait));
Error = GetSpecifiedMadcapMessage( // try to receive an ACK
DhcpContext,
&MessageSize,
Xid,
(DWORD)TimeToWait
);
if ( Error == ERROR_TIMEOUT ) break;
if( Error != ERROR_SUCCESS ) {
DhcpPrint((DEBUG_ERRORS, "GetSpecifiedMadcapMessage: %ld\n", Error));
goto Cleanup;
}
MadcapExtractOptions( // Need to see if this is an ACK
DhcpContext,
(LPBYTE)&DhcpContext->MadcapMessageBuffer->Option,
MessageSize - MADCAP_MESSAGE_FIXED_PART_SIZE,
&MadcapOptions, // check for only expected options
NULL, // unused
0 // unused
);
GotAck = AcceptMadcapMsg( // check up and see if we find this offer kosher
MADCAP_INFORM_MESSAGE,
DhcpContext,
&MadcapOptions,
0,
&Error
);
if (GotAck) {
ULONG i;
for( i = 0; i < MessageCount ; i ++ ) {
if( MadcapServers[i] == *MadcapOptions.ServerIdentifier ) {
break;
}
}
if( i == MessageCount && MessageCount < MIN_ACKS_FOR_INFORM ) {
MessageCount ++;
MadcapServers[i] = *MadcapOptions.ServerIdentifier;
}
DhcpPrint((DEBUG_TRACE, "Received %ld ACKS so far\n", MessageCount));
MadcapExtractOptions( // do FULL options..
DhcpContext,
(LPBYTE)&DhcpContext->MadcapMessageBuffer->Option,
MessageSize - MADCAP_MESSAGE_FIXED_PART_SIZE,
&MadcapOptions,
&(DhcpContext->RecdOptionsList),
*MadcapOptions.ServerIdentifier
);
}
TimeNow = time(NULL); // Reset the time values to reflect new time
if( TimeToWait < (TimeNow - StartTime) ) {
break; // no more time left to wait..
}
TimeToWait -= (TimeNow - StartTime); // recalculate time now
StartTime = TimeNow; // reset start time also
} // end of while ( TimeToWait > 0)
if( MessageCount >= MIN_ACKS_FOR_INFORM ) goto Cleanup;
if( RoundNum != 0 && MessageCount != 0 ) goto Cleanup;
TimeToWait = MADCAP_QUERY_SCOPE_LIST_TIME ;
} // for (RoundNum = 0; RoundNum < nInformsToSend ; RoundNum ++ )
Cleanup:
CloseDhcpSocket(DhcpContext);
if( MessageCount ) Error = ERROR_SUCCESS;
DhcpPrint((DEBUG_PROTOCOL, "MadcapDoInform: got %d ACKS (returning %ld)\n", MessageCount,Error));
return Error;
}
DWORD
CopyMScopeList(
IN OUT PMCAST_SCOPE_ENTRY pScopeList,
IN OUT PDWORD pScopeLen,
OUT PDWORD pScopeCount
)
/*++
Routine Description:
This routine obtains the multicast scope list from the Madcap
server. It sends DHCPINFORM to Madcap multicast address and
collects all the responses.
Arguments:
Return Value:
The status of the operation.
--*/
{
PMCAST_SCOPE_ENTRY pScopeSource;
DWORD i;
LOCK_MSCOPE_LIST();
if ( *pScopeLen >= gMadcapScopeList->ScopeLen ) {
RtlCopyMemory( pScopeList, gMadcapScopeList->pScopeBuf, gMadcapScopeList->ScopeLen );
*pScopeLen = gMadcapScopeList->ScopeLen;
*pScopeCount = gMadcapScopeList->ScopeCount;
// remember the start pointer because we need to remap all the buffers into client space.
pScopeSource = gMadcapScopeList->pScopeBuf;
UNLOCK_MSCOPE_LIST();
// now remap UNICODE_STRING scope desc to client address space.
for (i=0;i<*pScopeCount;i++) {
pScopeList[i].ScopeDesc.Buffer = (USHORT *) ((PBYTE)pScopeList +
((PBYTE)pScopeList[i].ScopeDesc.Buffer - (PBYTE)pScopeSource));
}
return ERROR_SUCCESS;
} else {
UNLOCK_MSCOPE_LIST();
return ERROR_INSUFFICIENT_BUFFER;
}
}
DWORD
StoreMScopeList(
IN PDHCP_CONTEXT pContext,
IN BOOL NewList
)
/*++
Routine Description:
This routine stores the scope list it retrieved from the inform requests
into the global scope list..
the scope option is of the following form.
---------------------------------
| code (2 byte) | length (2byte)|
---------------------------------
| count ( 4 bytes ) |
---------------------------------
| Scope list
---------------------------------
where scope list is of the following form
--------------------------------------------------------------------------
| scope ID(4 byte) | Last Addr(4/16) |TTL(1) | Count (1) | Description...|
--------------------------------------------------------------------------
where scope description is of the following form
Language Tag
--------------------------------------------------------------
| Flags(1) | Tag Length(1) | Tag...| Name Length(1) | Name...|
--------------------------------------------------------------
Arguments:
pContext - pointer to the context to be used during inform
NewList - TRUE if a new list is to be created o/w prepend the
current list.
Return Value:
The status of the operation.
--*/
{
PBYTE pOptBuf;
PBYTE pOptBufEnd;
PLIST_ENTRY pOptionList;
PDHCP_OPTION pScopeOption, pFirstOption, pPrevOption;
DWORD TotalNewScopeDescLen;
DWORD TotalNewScopeCount;
DWORD TotalNewScopeListMem;
PMCAST_SCOPE_LIST pScopeList;
PMCAST_SCOPE_ENTRY pNextScope;
LPWSTR pNextUnicodeBuf;
DWORD TotalCurrScopeListMem;
DWORD TotalCurrScopeCount;
DWORD Error;
DWORD IpAddrLen;
BOOL WellFormed;
// MBUG - make sure we collect options from all the servers when
// we do dhcpinform.
// initialize variables.
TotalNewScopeCount = TotalCurrScopeCount = 0;
TotalNewScopeDescLen = 0;
pScopeList = NULL;
Error = ERROR_SUCCESS;
LOCK_MSCOPE_LIST();
if (FALSE == NewList) {
TotalCurrScopeListMem = gMadcapScopeList->ScopeLen;
TotalCurrScopeCount = gMadcapScopeList->ScopeCount;
DhcpPrint(( DEBUG_API, "StoreMScopeList: appending to CurrScopeLen %ld, ScopeCount %ld\n",
gMadcapScopeList->ScopeLen, gMadcapScopeList->ScopeCount ));
}
// First calculate the space required for the scope list.
// pFirstOption is used to track that we traverse the list only once
pOptionList = &pContext->RecdOptionsList;
pFirstOption = NULL;
WellFormed = TRUE;
while ( ( pScopeOption = DhcpFindOption(
pOptionList,
MADCAP_OPTION_MCAST_SCOPE_LIST,
FALSE,
NULL,
0,
0 //dont care about serverid
)) &&
( pScopeOption != pFirstOption ) ) {
DWORD ScopeCount;
DWORD i;
// point to the next entry in the list.
pOptionList = &pScopeOption->OptionList;
// set the pFirstOption if it is not set already.
if ( !pFirstOption ) {
pFirstOption = pScopeOption;
IpAddrLen = (pScopeOption->OptionVer.Proto == PROTO_MADCAP_V6 ? 16 : 4);
}
// if the last option was not well formatted from the list
// then remove it from the list.
if (!WellFormed) {
DhcpDelOption(pPrevOption);
//we may need to reset first option pointer.
if (pPrevOption == pFirstOption) {
pFirstOption = pScopeOption;
}
} else {
WellFormed = FALSE; // set it back to false for this iteration.
}
// save the prev option pointer
pPrevOption = pScopeOption;
pOptBuf = pScopeOption->Data;
pOptBufEnd = pScopeOption->Data + pScopeOption->DataLen;
ScopeCount = 0;
// Read the scope count
if ( pOptBuf < pOptBufEnd ) {
ScopeCount = *pOptBuf;
pOptBuf ++;
}
else continue;
for ( i=0;i<ScopeCount;i++ ) {
DWORD ScopeDescLen;
DWORD ScopeDescWLen;
PBYTE pScopeDesc;
DWORD NameCount, TagLen;
// skip the scopeid, last addr and ttl
pOptBuf += (2*IpAddrLen + 1);
// read name count
if (pOptBuf < pOptBufEnd) {
NameCount = *pOptBuf;
pOptBuf++;
} else break;
if (0 == NameCount) {
break;
}
do {
// Skip flags
pOptBuf++;
// read language tag len
if (pOptBuf < pOptBufEnd) {
TagLen = *pOptBuf;
pOptBuf++;
}else break;
// skip the tag
pOptBuf += TagLen;
// Read the name length
if (pOptBuf < pOptBufEnd) {
ScopeDescLen = *pOptBuf;
ScopeDescWLen = ConvertUTF8ToUnicode(pOptBuf+1, *pOptBuf, NULL, 0);
pOptBuf ++;
} else break;
// pick the scope name
pScopeDesc = pOptBuf;
pOptBuf += ScopeDescLen;
}while(--NameCount);
// if formatted correctly namecount should drop to 0
if (0 != NameCount) {
break;
}
// update total desc len count.
if ( pOptBuf <= pOptBufEnd ) {
if (pScopeDesc[ScopeDescLen-1]) { // if not NULL terminated.
ScopeDescWLen++;
}
TotalNewScopeDescLen += ScopeDescWLen * sizeof(WCHAR);
TotalNewScopeCount++;
// Set the wellformed to true so that this option stays
WellFormed = TRUE;
}
else break;
}
}
if ( !TotalNewScopeCount ) {
DhcpPrint((DEBUG_ERRORS, "StoreMScopeList - no scopes found in the options, bad format..\n"));
Error = ERROR_BAD_FORMAT;
goto Cleanup;
}
DhcpPrint(( DEBUG_API, "TotalNewScopeCount %d, TotalNewScopeDescLen %d\n",TotalNewScopeCount,TotalNewScopeDescLen));
// now allocate the memory.
TotalNewScopeListMem = ROUND_UP_COUNT( sizeof(MCAST_SCOPE_LIST) + // scope list struct
sizeof(MCAST_SCOPE_ENTRY) * (TotalNewScopeCount -1),
ALIGN_WORST) + // scope buffers.
TotalNewScopeDescLen; // scope descriptors,
if (FALSE == NewList) {
TotalNewScopeListMem += TotalCurrScopeListMem;
TotalNewScopeCount += TotalCurrScopeCount;
}
pScopeList = DhcpAllocateMemory( TotalNewScopeListMem );
if ( !pScopeList ) {
UNLOCK_MSCOPE_LIST();
return ERROR_NOT_ENOUGH_MEMORY;
}
RtlZeroMemory( pScopeList, TotalNewScopeListMem );
pScopeList->ScopeCount = 0; // we will fill this up as we go.
pScopeList->ScopeLen = TotalNewScopeListMem - sizeof(MCAST_SCOPE_LIST) + sizeof(MCAST_SCOPE_ENTRY);
// set the first scope pointer.
pNextScope = pScopeList->pScopeBuf;
// unicode strings starts after all the fixed sized scope structures.
pNextUnicodeBuf = (LPWSTR)((PBYTE)pScopeList +
ROUND_UP_COUNT( sizeof(MCAST_SCOPE_LIST) + // scope list struct
sizeof(MCAST_SCOPE_ENTRY) * (TotalNewScopeCount -1),
ALIGN_WORST)); // scope buffers.
DhcpPrint(( DEBUG_API, "ScopeList %lx TotalNewScopeListMem %d, ScopeDescBuff %lx\n",
pScopeList, TotalNewScopeListMem,pNextUnicodeBuf));
// now repeat the loop and fill up the scopelist.
pOptionList = &pContext->RecdOptionsList;
pFirstOption = NULL;
while ( ( pScopeOption = DhcpFindOption(
pOptionList,
MADCAP_OPTION_MCAST_SCOPE_LIST,
FALSE,
NULL,
0,
0 //dont care about serverid
)) &&
( pScopeOption != pFirstOption ) ) {
DWORD ScopeCount;
DWORD i;
DHCP_IP_ADDRESS ServerIpAddr;
// point to the next entry in the list.
pOptionList = &pScopeOption->OptionList;
// set the pFirstOption if it is not set already.
if ( !pFirstOption ) {
pFirstOption = pScopeOption;
}
pOptBuf = pScopeOption->Data;
DhcpPrint(( DEBUG_API, "MScopeOption - Data %lx\n", pOptBuf ));
pOptBufEnd = pScopeOption->Data + pScopeOption->DataLen;
// store ipaddr
ServerIpAddr = pScopeOption->ServerId;
DhcpPrint(( DEBUG_API, "MScopeOption - ServerIpAddr %lx\n", ServerIpAddr ));
// read the scope count.
ScopeCount = *pOptBuf; pOptBuf++;
DhcpPrint(( DEBUG_API, "MScopeOption - ScopeCount %ld\n", ScopeCount ));
for ( i=0;i<ScopeCount;i++ ) {
BYTE ScopeDescLen;
PBYTE pScopeDesc;
IPNG_ADDRESS ScopeID, LastAddr;
DWORD NameCount, TagLen;
DWORD TTL;
// read the scopeid, last addr.
RtlZeroMemory (&ScopeID, sizeof (ScopeID));
RtlCopyMemory (&ScopeID, pOptBuf, IpAddrLen);
pOptBuf += IpAddrLen;
RtlZeroMemory (&LastAddr, sizeof (ScopeID));
RtlCopyMemory (&LastAddr, pOptBuf, IpAddrLen);
pOptBuf += IpAddrLen;
DhcpPrint(( DEBUG_API, "MScopeOption - ScopeID %lx\n", ntohl(ScopeID.IpAddrV4) ));
DhcpPrint(( DEBUG_API, "MScopeOption - LastAddr %lx\n", ntohl(LastAddr.IpAddrV4) ));
TTL = *pOptBuf++;
NameCount = *pOptBuf++;
while (NameCount--) {
// MBUG ignore the flags for now
pOptBuf++;
TagLen = *pOptBuf++;
// MBUG ignore lang tag also
pOptBuf += TagLen;
ScopeDescLen = *pOptBuf++;
pScopeDesc = pOptBuf;
DhcpPrint(( DEBUG_API, "MScopeOption - ScopeDesc %lx ScopeDescLen %ld\n", pScopeDesc, ScopeDescLen ));
pOptBuf += ScopeDescLen;
}
if ( ScopeDescLen ) {
BYTE ScopeDescWLen;
WORD MaximumLength;
/* CHAR DescAnsi[256];
WORD MaximumLength;
RtlCopyMemory(DescAnsi, pScopeDesc, ScopeDescLen );
// null terminate it if necessary.
if ( pScopeDesc[ScopeDescLen - 1] ) {
DescAnsi[ScopeDescLen] = '\0';
MaximumLength = (ScopeDescLen + 1) * sizeof(WCHAR);
} else {
MaximumLength = (ScopeDescLen) * sizeof(WCHAR);
}
pNextUnicodeBuf = DhcpOemToUnicode( DescAnsi, pNextUnicodeBuf ); */
ScopeDescWLen = (BYTE)ConvertUTF8ToUnicode(pScopeDesc, ScopeDescLen, pNextUnicodeBuf, TotalNewScopeDescLen);
if ( pNextUnicodeBuf[ScopeDescWLen - 1] ) {
pNextUnicodeBuf[ScopeDescWLen] = L'\0';
MaximumLength = (ScopeDescWLen + 1) * sizeof(WCHAR);
} else {
MaximumLength = (ScopeDescWLen) * sizeof(WCHAR);
}
TotalNewScopeDescLen -= MaximumLength;
DhcpPrint(( DEBUG_API, "MScopeOption - UnicodeScopeDesc %lx %ws\n",pNextUnicodeBuf, pNextUnicodeBuf));
RtlInitUnicodeString(&pNextScope->ScopeDesc, pNextUnicodeBuf );
pNextScope->ScopeDesc.MaximumLength = MaximumLength;
pNextUnicodeBuf = (LPWSTR)((PBYTE)pNextUnicodeBuf + MaximumLength);
DhcpAssert((PBYTE)pNextUnicodeBuf <= ((PBYTE)pScopeList + TotalNewScopeListMem));
} else {
// set the unicode descriptor string to NULL;
pNextScope->ScopeDesc.Length = pNextScope->ScopeDesc.MaximumLength = 0;
pNextScope->ScopeDesc.Buffer = NULL;
}
// everything looks good, now fill up the NextScope
pNextScope->ScopeCtx.ScopeID = ScopeID;
pNextScope->ScopeCtx.ServerID.IpAddrV4 = ServerIpAddr;
pNextScope->ScopeCtx.Interface.IpAddrV4 = pContext->IpAddress;
pNextScope->LastAddr = LastAddr;
pNextScope->TTL = TTL;
pNextScope++;
pScopeList->ScopeCount++;
}
}
DhcpAssert( pScopeList->ScopeCount == (TotalNewScopeCount - TotalCurrScopeCount) );
// now append the previous scope list if exist.
if (FALSE == NewList) {
DWORD CurrScopeCount;
PMCAST_SCOPE_ENTRY CurrScopeNextPtr;
CurrScopeCount = gMadcapScopeList->ScopeCount;
CurrScopeNextPtr = gMadcapScopeList->pScopeBuf;
while(CurrScopeCount--) {
*pNextScope = *CurrScopeNextPtr;
// now copy the unicode strings also.
RtlCopyMemory( pNextUnicodeBuf, CurrScopeNextPtr->ScopeDesc.Buffer, CurrScopeNextPtr->ScopeDesc.MaximumLength);
pNextScope->ScopeDesc.Buffer = pNextUnicodeBuf ;
pNextUnicodeBuf = (LPWSTR)((PBYTE)pNextUnicodeBuf + CurrScopeNextPtr->ScopeDesc.MaximumLength);
pNextScope++; CurrScopeNextPtr++;
}
pScopeList->ScopeCount += gMadcapScopeList->ScopeCount;
DhcpAssert( pScopeList->ScopeCount == TotalNewScopeCount);
}
// Finally copy this buffer to our global pointer.
// first free the existing list.
if (gMadcapScopeList) DhcpFreeMemory( gMadcapScopeList );
gMadcapScopeList = pScopeList;
Cleanup:
UNLOCK_MSCOPE_LIST();
return Error;
}
DWORD
ObtainMScopeList(
)
/*++
Routine Description:
This routine obtains the multicast scope list from the Madcap
server. It sends DHCPINFORM to Madcap multicast address and
collects all the responses.
Arguments:
Return Value:
The status of the operation.
--*/
{
MCAST_CLIENT_UID RequestID;
BYTE IDBuf[MCAST_CLIENT_ID_LEN];
PDHCP_CONTEXT pContext;
DWORD Error;
PMIB_IPADDRTABLE pIpAddrTable;
PLOCAL_CONTEXT_INFO localInfo;
DWORD i;
BOOL NewList;
pContext = NULL;
Error = ERROR_SUCCESS;
pIpAddrTable = NULL;
if ( !ShouldRequeryMScopeList() ) {
return ERROR_SUCCESS;
} else {
RequestID.ClientUID = IDBuf;
RequestID.ClientUIDLength = MCAST_CLIENT_ID_LEN;
Error = GenMadcapClientUID( RequestID.ClientUID, &RequestID.ClientUIDLength );
if ( ERROR_SUCCESS != Error)
goto Exit;
Error = CreateMadcapContext(&pContext, &RequestID, INADDR_ANY );
if ( ERROR_SUCCESS != Error )
goto Exit;
APICTXT_ENABLED(pContext); // mark the context as being created by the API
localInfo = pContext->LocalInformation;
// now get primary ipaddresses on each adapter.
Error = GetIpPrimaryAddresses(&pIpAddrTable);
if ( ERROR_SUCCESS != Error ) {
goto Exit;
}
DhcpPrint((DEBUG_API, "ObtainMScopeList: ipaddress table has %d addrs\n",
pIpAddrTable->dwNumEntries));
NewList = TRUE;
Error = ERROR_TIMEOUT;
for (i = 0; i < pIpAddrTable->dwNumEntries; i++) {
DWORD LocalError;
PMIB_IPADDRROW pAddrRow;
pAddrRow = &pIpAddrTable->table[i];
// if primary bit set this is a primary address.
if (0 == (pAddrRow->wType & MIB_IPADDR_PRIMARY) ||
0 == pAddrRow->dwAddr ||
htonl(INADDR_LOOPBACK) == pAddrRow->dwAddr) {
continue;
}
DhcpPrint((DEBUG_API, "ObtainMScopeList: DoInform on %s interface\n",
DhcpIpAddressToDottedString(ntohl(pAddrRow->dwAddr)) ));
LocalError = ReInitializeMadcapSocket(&localInfo->Socket, pAddrRow->dwAddr);
if (ERROR_SUCCESS != LocalError) {
continue;
}
pContext->IpAddress = pAddrRow->dwAddr;
// now do the inform and get scope list.
LocalError = MadcapDoInform(pContext);
if ( ERROR_SUCCESS == LocalError ) {
// now copy the scope list.
LocalError = StoreMScopeList(pContext, NewList);
if (ERROR_SUCCESS == LocalError ) {
NewList = FALSE;
Error = ERROR_SUCCESS;
}
}
LOCK_OPTIONS_LIST();
DhcpDestroyOptionsList(&pContext->SendOptionsList, &DhcpGlobalClassesList);
DhcpDestroyOptionsList(&pContext->RecdOptionsList, &DhcpGlobalClassesList);
UNLOCK_OPTIONS_LIST();
}
Exit:
// signal the thread could be waiting on this.
LOCK_MSCOPE_LIST();
gMScopeQueryInProgress = FALSE;
UNLOCK_MSCOPE_LIST();
SetEvent( gMScopeQueryEvent );
if ( pContext ) {
DhcpDestroyContext( pContext );
}
if (pIpAddrTable) {
DhcpFreeMemory( pIpAddrTable );
}
return Error;
}
}
DWORD
GenMadcapClientUID(
OUT PBYTE pRequestID,
IN OUT PDWORD pRequestIDLen
)
/*++
Routine Description:
This routine generates a client UID.
Arguments:
pRequestID - pointer where client UID is to be stored.
pRequestIDLen - pointer where the length of request id is stored.
Return Value:
--*/
{
PULONG UID;
RPC_STATUS Status;
GUID RequestGuid;
DhcpAssert( pRequestID && pRequestIDLen );
if (*pRequestIDLen < MCAST_CLIENT_ID_LEN) {
DhcpPrint((DEBUG_ERRORS,"GenMadcapId - IDLen too small, %ld\n", *pRequestIDLen ));
return ERROR_INVALID_PARAMETER;
}
Status = UuidCreate( &RequestGuid );
if (Status != RPC_S_OK) {
Status = ERROR_LUIDS_EXHAUSTED;
}
*pRequestID++ = 0; // first octet is type and for guid the type is 0
*((GUID UNALIGNED *)pRequestID) = RequestGuid;
return Status;
}
DWORD
ObtainMadcapAddress(
IN PDHCP_CONTEXT DhcpContext,
IN PIPNG_ADDRESS pScopeID,
IN PMCAST_LEASE_REQUEST pAddrRequest,
IN OUT PMCAST_LEASE_RESPONSE pAddrResponse
)
/*++
Routine Description:
This routine attempts to obtains a new lease from a DHCP server.
Arguments:
DhcpContext - Points to a DHCP context block for the NIC to initialize.
MadcapOptions - Returns DHCP options returned by the DHCP server.
Return Value:
--*/
{
MADCAP_OPTIONS MadcapOptions;
DATE_TIME HostOrderLeaseTime;
DWORD Error;
time_t StartTime;
time_t InitialStartTime;
time_t TimeNow;
time_t TimeToWait;
DWORD Xid;
DWORD RoundNum;
DWORD MessageSize;
DWORD SelectedServer;
DWORD SelectedAddress;
DWORD LeaseExpiryTime;
BOOL GotOffer;
PMCAST_LEASE_REQUEST pRenewRequest;
Xid = 0; // generate xid on first send. keep it same throughout
SelectedServer = (DWORD)-1;
SelectedAddress = (DWORD)-1;
GotOffer = FALSE;
InitialStartTime = time(NULL);
Error = ERROR_SEM_TIMEOUT;
// Make private copy of the request so that we don't modify original request.
pRenewRequest = DhcpAllocateMemory(
sizeof(*pAddrRequest) +
sizeof(DWORD)*(pAddrRequest->AddrCount));
if (NULL == pRenewRequest) {
return ERROR_NOT_ENOUGH_MEMORY;
}
memcpy(pRenewRequest,pAddrRequest,sizeof(*pAddrRequest) );
pRenewRequest->pAddrBuf = (PBYTE)pRenewRequest + sizeof(*pRenewRequest);
if (pAddrRequest->pAddrBuf) {
memcpy(pRenewRequest->pAddrBuf, pAddrRequest->pAddrBuf, sizeof(DWORD)*(pAddrRequest->AddrCount));
}
for (RoundNum = 0; RoundNum < MADCAP_MAX_RETRIES; RoundNum++ ) {
Error = SendMadcapDiscover( // send a discover packet
DhcpContext,
pScopeID,
pAddrRequest,
&Xid
);
if ( Error != ERROR_SUCCESS ) { // can't really fail here
DhcpPrint((DEBUG_ERRORS, "Send Dhcp Discover failed, %ld.\n", Error));
return Error ;
}
DhcpPrint((DEBUG_PROTOCOL, "Sent DhcpDiscover Message.\n"));
TimeToWait = DhcpCalculateWaitTime(RoundNum, NULL);
StartTime = time(NULL);
while ( TimeToWait > 0 ) { // wait for specified time
MessageSize = DHCP_RECV_MESSAGE_SIZE;
DhcpPrint((DEBUG_TRACE, "Waiting for Offer: %ld seconds\n", TimeToWait));
Error = GetSpecifiedMadcapMessage( // try to receive an offer
DhcpContext,
&MessageSize,
Xid,
(DWORD)TimeToWait
);
if ( Error == ERROR_TIMEOUT ) { // get out and try another discover
DhcpPrint(( DEBUG_PROTOCOL, "Dhcp offer receive Timeout.\n" ));
break;
}
if ( ERROR_SUCCESS != Error ) { // unexpected error
DhcpPrint(( DEBUG_PROTOCOL, "Dhcp Offer receive failed, %ld.\n", Error ));
return Error ;
}
MadcapExtractOptions( // now extract basic information
DhcpContext,
(LPBYTE)&DhcpContext->MadcapMessageBuffer->Option,
MessageSize - MADCAP_MESSAGE_FIXED_PART_SIZE,
&MadcapOptions,
NULL,
0
);
GotOffer = AcceptMadcapMsg( // check up and see if we find this offer kosher
MADCAP_DISCOVER_MESSAGE,
DhcpContext,
&MadcapOptions,
0,
&Error
);
DhcpAssert(ERROR_SUCCESS == Error);
Error = ExpandMadcapAddressList(
MadcapOptions.AddrRangeList,
MadcapOptions.AddrRangeListSize,
(DWORD UNALIGNED *)pRenewRequest->pAddrBuf,
&pRenewRequest->AddrCount
);
if (ERROR_SUCCESS != Error) {
GotOffer = FALSE;
}
if (GotOffer) {
break;
}
TimeNow = time( NULL ); // calc the remaining wait time for this round
TimeToWait -= ((TimeNow - StartTime));
StartTime = TimeNow;
} // while (TimeToWait > 0 )
if(GotOffer) { // if we got an offer, everything should be fine
DhcpAssert(ERROR_SUCCESS == Error);
break;
}
} // for n tries... send discover.
if(!GotOffer ) { // did not get any valid offers
DhcpPrint((DEBUG_ERRORS, "ObtainMadcapAddress timed out\n"));
Error = ERROR_TIMEOUT ;
goto Cleanup;
}
DhcpPrint((DEBUG_PROTOCOL, "Successfully received a DhcpOffer (%s) ",
inet_ntoa(*(struct in_addr *)pRenewRequest->pAddrBuf) ));
DhcpPrint((DEBUG_PROTOCOL, "from %s.\n",
inet_ntoa(*(struct in_addr*)MadcapOptions.ServerIdentifier) ));
SelectedServer = *MadcapOptions.ServerIdentifier;
Error = RenewMadcapAddress(
DhcpContext,
pScopeID,
pRenewRequest,
pAddrResponse,
SelectedServer
);
Cleanup:
if (pRenewRequest) {
DhcpFreeMemory(pRenewRequest);
}
return Error;
}
DWORD
RenewMadcapAddress(
IN PDHCP_CONTEXT DhcpContext,
IN PIPNG_ADDRESS pScopeID,
IN PMCAST_LEASE_REQUEST pAddrRequest,
IN OUT PMCAST_LEASE_RESPONSE pAddrResponse,
IN DHCP_IP_ADDRESS SelectedServer
)
/*++
Routine Description:
This routine is called for two different purposes.
1. To request an address for which we got offer.
2. To renew an address.
Arguments:
DhcpContext - Points to a DHCP context block for the NIC to initialize.
pScopeID - ScopeId from which the address is to be renewed. for renewals
this is passed as null.
pAddrRequest - The lease info structure describing the request.
pAddrResponse - The lease info structure which receives the response data.
SelectedServer - If we are sending REQUEST message then this describes the server
from which we accepted the offer originally.
Return Value:
The status of the operation.
--*/
{
MADCAP_OPTIONS MadcapOptions;
DWORD Error;
DWORD Xid;
DWORD RoundNum;
size_t TimeToWait;
DWORD MessageSize;
DWORD LeaseTime;
DWORD LeaseExpiryTime;
time_t InitialStartTime;
time_t StartTime;
time_t TimeNow;
BOOL GotAck;
DATE_TIME HostOrderLeaseTime;
BOOL Renew;
Xid = 0; // new Xid will be generated first time
InitialStartTime = time(NULL);
GotAck = FALSE;
Error = ERROR_TIMEOUT;
Renew = (0 == SelectedServer);
for ( RoundNum = 0; RoundNum < MADCAP_MAX_RETRIES; RoundNum ++ ) {
if (Renew) {
Error = SendMadcapRenew(
DhcpContext,
pAddrRequest,
&Xid
);
} else {
Error = SendMadcapRequest( // send a request
DhcpContext,
pScopeID,
pAddrRequest,
SelectedServer, //
&Xid
);
}
if ( Error != ERROR_SUCCESS ) { // dont expect send to fail
DhcpPrint(( DEBUG_ERRORS,"Send request failed, %ld.\n", Error));
return Error ;
}
TimeToWait = DhcpCalculateWaitTime(RoundNum, NULL);
StartTime = time(NULL);
while ( TimeToWait > 0 ) { // try to recv message for this full period
MessageSize = DHCP_RECV_MESSAGE_SIZE;
Error = GetSpecifiedMadcapMessage( // expect to recv an ACK
DhcpContext,
&MessageSize,
Xid,
TimeToWait
);
if ( Error == ERROR_TIMEOUT ) { // No response, so resend DHCP REQUEST.
DhcpPrint(( DEBUG_PROTOCOL, "Dhcp ACK receive Timeout.\n" ));
break;
}
if ( ERROR_SUCCESS != Error ) { // unexpected error
DhcpPrint(( DEBUG_PROTOCOL, "Dhcp ACK receive failed, %ld.\n", Error ));
return Error ;
}
MadcapExtractOptions( // now extract basic information
DhcpContext,
(LPBYTE)&DhcpContext->MadcapMessageBuffer->Option,
MessageSize - MADCAP_MESSAGE_FIXED_PART_SIZE,
&MadcapOptions,
NULL,
0
);
GotAck = AcceptMadcapMsg( // check up and see if we find this offer kosher
Renew ? MADCAP_RENEW_MESSAGE : MADCAP_REQUEST_MESSAGE,
DhcpContext,
&MadcapOptions,
SelectedServer,
&Error
);
if (ERROR_SUCCESS != Error) {
return Error;
}
// check that the ack came from the same server as the selected server.
if ( SelectedServer && SelectedServer != *MadcapOptions.ServerIdentifier ) {
GotAck = FALSE;
}
Error = ExpandMadcapAddressList(
MadcapOptions.AddrRangeList,
MadcapOptions.AddrRangeListSize,
(DWORD UNALIGNED *)pAddrResponse->pAddrBuf,
&pAddrResponse->AddrCount
);
if (ERROR_SUCCESS != Error) {
GotAck = FALSE;
}
if ( GotAck ) {
break;
}
TimeNow = time( NULL );
TimeToWait -= (TimeNow - StartTime);
StartTime = TimeNow;
} // while time to wait
if(TRUE == GotAck) { // if we got an ack, everything must be good
DhcpAssert(ERROR_SUCCESS == Error); // cannot have any errors
break;
}
DhcpContext->SecondsSinceBoot = (DWORD)(InitialStartTime - TimeNow);
} // for RoundNum < MAX_RETRIES
if(!GotAck) {
DhcpPrint((DEBUG_ERRORS, "RenewMadcapAddress timed out\n"));
return ERROR_TIMEOUT;
}
if (0 == SelectedServer ) SelectedServer = *MadcapOptions.ServerIdentifier;
if( MadcapOptions.LeaseTime ) LeaseTime = ntohl(*MadcapOptions.LeaseTime);
else LeaseTime = 0;
pAddrResponse->ServerAddress.IpAddrV4 = SelectedServer;
time( &TimeNow );
pAddrResponse->LeaseStartTime = (LONG)TimeNow;
pAddrResponse->LeaseEndTime = (LONG)(TimeNow+LeaseTime);
DhcpPrint((DEBUG_PROTOCOL, "Accepted ACK (%s) ",
inet_ntoa(*(struct in_addr *)pAddrResponse->pAddrBuf) ));
DhcpPrint((DEBUG_PROTOCOL, "from %s.\n",
inet_ntoa(*(struct in_addr *)&SelectedServer)));
DhcpPrint((DEBUG_PROTOCOL, "Lease is %ld secs.\n", LeaseTime));
return ERROR_SUCCESS;
}
DWORD
ReleaseMadcapAddress(
PDHCP_CONTEXT DhcpContext
)
/*++
Routine Description:
This routine to releases a lease for an IP address. Since the
packet we send is not responded to, we assume that the release
works.
Arguments:
DhcpContext - Points to a DHCP context block for the NIC to initialize.
Return Value:
None.
--*/
{
DWORD Xid;
MADCAP_OPTIONS MadcapOptions;
DWORD Error;
time_t StartTime;
time_t InitialStartTime;
time_t TimeNow;
time_t TimeToWait;
DWORD RoundNum;
DWORD MessageSize;
BOOL GotAck;
Xid = 0; // new Xid will be generated first time
GotAck = FALSE;
InitialStartTime = time(NULL);
Error = ERROR_TIMEOUT;
for (RoundNum = 0; RoundNum < MADCAP_MAX_RETRIES; RoundNum++ ) {
Error = SendMadcapRelease( // send a discover packet
DhcpContext,
&Xid
);
if ( Error != ERROR_SUCCESS ) { // can't really fail here
DhcpPrint((DEBUG_ERRORS, "Send Dhcp Release failed, %ld.\n", Error));
return Error ;
}
DhcpPrint((DEBUG_PROTOCOL, "Sent DhcpRelease Message.\n"));
TimeToWait = DhcpCalculateWaitTime(RoundNum, NULL);
StartTime = time(NULL);
while ( TimeToWait > 0 ) { // wait for specified time
MessageSize = DHCP_RECV_MESSAGE_SIZE;
DhcpPrint((DEBUG_TRACE, "Waiting for Ack: %ld seconds\n", TimeToWait));
Error = GetSpecifiedMadcapMessage( // try to receive an offer
DhcpContext,
&MessageSize,
Xid,
(DWORD)TimeToWait
);
if ( Error == ERROR_TIMEOUT ) { // get out and try another discover
DhcpPrint(( DEBUG_PROTOCOL, "Dhcp Ack receive Timeout.\n" ));
break;
}
if ( ERROR_SUCCESS != Error ) { // unexpected error
DhcpPrint(( DEBUG_PROTOCOL, "Dhcp Ack receive failed, %ld.\n", Error ));
return Error ;
}
MadcapExtractOptions( // now extract basic information
DhcpContext,
(LPBYTE)&DhcpContext->MadcapMessageBuffer->Option,
MessageSize - MADCAP_MESSAGE_FIXED_PART_SIZE,
&MadcapOptions,
NULL,
0
);
GotAck = AcceptMadcapMsg( // check up and see if we find this offer kosher
MADCAP_RELEASE_MESSAGE,
DhcpContext,
&MadcapOptions,
DhcpContext->DhcpServerAddress,
&Error
);
DhcpAssert(ERROR_SUCCESS == Error);
if (GotAck) {
break;
}
TimeNow = time( NULL ); // calc the remaining wait time for this round
TimeToWait -= ((TimeNow - StartTime));
StartTime = TimeNow;
} // while (TimeToWait > 0 )
if(GotAck) { // if we got an offer, everything should be fine
DhcpAssert(ERROR_SUCCESS == Error);
break;
}
} // for n tries... send discover.
if(!GotAck ) { // did not get any valid offers
DhcpPrint((DEBUG_ERRORS, "MadcapReleaseAddress timed out\n"));
Error = ERROR_TIMEOUT ;
} else {
DhcpPrint((DEBUG_PROTOCOL, "Successfully released the address\n" ));
Error = ERROR_SUCCESS;
}
return Error;
}