|
|
/*++
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);
//
// BUG 519461
//
// Add the "return TRUE" to make typo.pl happy
//
return TRUE;
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, 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)(time(NULL) - InitialStartTime); } // 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; }
|