2592 lines
79 KiB
C
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
|