mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1955 lines
43 KiB
1955 lines
43 KiB
/*++
|
|
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dhcp.c
|
|
|
|
Abstract:
|
|
|
|
This file contains specific to NT dhcp service.
|
|
|
|
Author:
|
|
|
|
Madan Appiah (madana) 7-Dec-1993.
|
|
|
|
Environment:
|
|
|
|
User Mode - Win32
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#define GLOBAL_DATA_ALLOCATE
|
|
#include <dhcpcli.h>
|
|
#include <dhcploc.h>
|
|
#include <dhcppro.h>
|
|
#include <lmsname.h>
|
|
#include <svcs.h>
|
|
|
|
BOOL DhcpGlobalServiceRunning = FALSE;
|
|
|
|
|
|
BOOLEAN
|
|
DhcpClientDllInit (
|
|
IN PVOID DllHandle,
|
|
IN ULONG Reason,
|
|
IN PCONTEXT Context OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the DLL initialization routine for dhcpcsvc.dll.
|
|
|
|
Arguments:
|
|
|
|
Standard.
|
|
|
|
Return Value:
|
|
|
|
TRUE iff initialization succeeded.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error = ERROR_SUCCESS;
|
|
DWORD Length;
|
|
|
|
UNREFERENCED_PARAMETER(DllHandle); // avoid compiler warnings
|
|
UNREFERENCED_PARAMETER(Context); // avoid compiler warnings
|
|
|
|
|
|
//
|
|
// Handle attaching netlogon.dll to a new process.
|
|
//
|
|
|
|
if (Reason == DLL_PROCESS_ATTACH) {
|
|
|
|
if ( !DisableThreadLibraryCalls( DllHandle ) ) {
|
|
#if DBG
|
|
KdPrint(("DHCP: DisableThreadLibraryCalls failed: %ld\n",
|
|
GetLastError() ));
|
|
#endif // DBG
|
|
return( FALSE );
|
|
}
|
|
|
|
//
|
|
// start winsock.
|
|
//
|
|
|
|
Error = WSAStartup( 0x0101, &DhcpGlobalWsaData );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
#if DBG
|
|
KdPrint(("DHCP:WSAStartup failed: %ld\n", Error));
|
|
#endif // DBG
|
|
return( FALSE );
|
|
}
|
|
|
|
DhcpGlobalWinSockInitialized = TRUE;
|
|
DhcpGlobalIsService = FALSE;
|
|
|
|
//
|
|
// create a named event flag that synchonize the winsock
|
|
// access. ??
|
|
//
|
|
|
|
//
|
|
// read host name parameter.
|
|
//
|
|
|
|
Length = MAX_COMPUTERNAME_LENGTH + 1;
|
|
DhcpGlobalHostName = DhcpAllocateMemory( MAX_COMPUTERNAME_LENGTH + 1 );
|
|
|
|
if( DhcpGlobalHostName == NULL ) {
|
|
#if DBG
|
|
KdPrint(("DHCP:LocalAlloc failed %ld\n", ERROR_NOT_ENOUGH_MEMORY));
|
|
#endif // DBG
|
|
return( FALSE );
|
|
}
|
|
|
|
Error = GetComputerNameA( DhcpGlobalHostName, &Length );
|
|
|
|
if( Error == FALSE ) {
|
|
#if DBG
|
|
KdPrint(("DHCP:GetComputerNameA failed %ld\n", GetLastError() ));
|
|
#endif // DBG
|
|
return( FALSE );
|
|
}
|
|
|
|
DhcpAssert( Length <= MAX_COMPUTERNAME_LENGTH );
|
|
DhcpGlobalHostName[Length] = '\0'; // terminate computer name.
|
|
|
|
//
|
|
// Handle detaching dhcpcsvc.dll from a process.
|
|
//
|
|
|
|
} else if (Reason == DLL_PROCESS_DETACH) {
|
|
|
|
//
|
|
// stop winsock.
|
|
//
|
|
|
|
if( DhcpGlobalWinSockInitialized == TRUE ) {
|
|
WSACleanup();
|
|
DhcpGlobalWinSockInitialized = FALSE;
|
|
}
|
|
|
|
if( DhcpGlobalHostName != NULL ) {
|
|
DhcpFreeMemory( DhcpGlobalHostName );
|
|
DhcpGlobalHostName = NULL;
|
|
}
|
|
|
|
} else {
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
DWORD
|
|
UpdateStatus(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function updates the dhcp service status with the Service
|
|
Controller.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Return code from SetServiceStatus.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error = ERROR_SUCCESS;
|
|
|
|
|
|
if ( DhcpGlobalServiceStatusHandle !=
|
|
(SERVICE_STATUS_HANDLE)NULL ) {
|
|
|
|
DhcpGlobalServiceStatus.dwCheckPoint++;
|
|
if (!SetServiceStatus(
|
|
DhcpGlobalServiceStatusHandle,
|
|
&DhcpGlobalServiceStatus)) {
|
|
Error = GetLastError();
|
|
DhcpPrint((DEBUG_ERRORS, "SetServiceStatus failed, %ld.\n", Error ));
|
|
}
|
|
}
|
|
|
|
return(Error);
|
|
}
|
|
|
|
VOID
|
|
ServiceControlHandler(
|
|
IN DWORD Opcode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the service control handler of the dhcp service.
|
|
|
|
Arguments:
|
|
|
|
Opcode - Supplies a value which specifies the action for the
|
|
service to perform.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
switch (Opcode) {
|
|
|
|
case SERVICE_CONTROL_STOP:
|
|
|
|
if (DhcpGlobalServiceStatus.dwCurrentState != SERVICE_STOP_PENDING) {
|
|
|
|
DhcpPrint(( DEBUG_MISC, "Service is stop pending.\n"));
|
|
|
|
DhcpGlobalServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
|
|
DhcpGlobalServiceStatus.dwCheckPoint = 0;
|
|
|
|
//
|
|
// Send the status response.
|
|
//
|
|
|
|
UpdateStatus();
|
|
|
|
if (! SetEvent(DhcpGlobalTerminateEvent)) {
|
|
|
|
//
|
|
// Problem with setting event to terminate dhcp
|
|
// service.
|
|
//
|
|
|
|
DhcpPrint(( DEBUG_ERRORS,
|
|
"Error setting Terminate Event %lu\n",
|
|
GetLastError() ));
|
|
|
|
DhcpAssert(FALSE);
|
|
}
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case SERVICE_CONTROL_PAUSE:
|
|
|
|
DhcpGlobalServiceStatus.dwCurrentState = SERVICE_PAUSED;
|
|
DhcpPrint(( DEBUG_MISC, "Service is paused.\n"));
|
|
break;
|
|
|
|
case SERVICE_CONTROL_CONTINUE:
|
|
|
|
DhcpGlobalServiceStatus.dwCurrentState = SERVICE_RUNNING;
|
|
DhcpPrint(( DEBUG_MISC, "Service is Continued.\n"));
|
|
break;
|
|
|
|
case SERVICE_CONTROL_INTERROGATE:
|
|
DhcpPrint(( DEBUG_MISC, "Service is interrogated.\n"));
|
|
break;
|
|
|
|
default:
|
|
DhcpPrint(( DEBUG_MISC, "Service received unknown control.\n"));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Send the status response.
|
|
//
|
|
|
|
UpdateStatus();
|
|
}
|
|
|
|
|
|
VOID
|
|
ScheduleWakeUp(
|
|
PDHCP_CONTEXT DhcpContext,
|
|
DWORD TimeToSleep
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This functions schedules a DHCP routine to run.
|
|
|
|
Arguments:
|
|
|
|
Context - A pointer to a DHCP context block.
|
|
|
|
TimeToSleep - The time to sleep before running the renewal function,
|
|
in seconds.
|
|
|
|
Return Value:
|
|
|
|
The status of the operation.
|
|
|
|
--*/
|
|
{
|
|
time_t TimeNow;
|
|
BOOL BoolError;
|
|
|
|
TimeNow = time( NULL);
|
|
|
|
if ( TimeToSleep == INFINIT_LEASE ) {
|
|
DhcpContext->RunTime = INFINIT_TIME;
|
|
} else {
|
|
DhcpContext->RunTime = TimeNow + TimeToSleep;
|
|
|
|
if( DhcpContext->RunTime < TimeNow ) {
|
|
|
|
//
|
|
// time raped around.
|
|
//
|
|
|
|
DhcpContext->RunTime = INFINIT_TIME;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Append this work item to the DhcpGlobalRenewList and kick the
|
|
// list event.
|
|
//
|
|
|
|
LOCK_RENEW_LIST();
|
|
InsertTailList( &DhcpGlobalRenewList, &DhcpContext->RenewalListEntry );
|
|
UNLOCK_RENEW_LIST();
|
|
|
|
BoolError = SetEvent( DhcpGlobalRecomputeTimerEvent );
|
|
DhcpAssert( BoolError == TRUE );
|
|
}
|
|
|
|
|
|
DWORD
|
|
OpenDhcpSocket(
|
|
PDHCP_CONTEXT DhcpContext
|
|
)
|
|
{
|
|
|
|
DWORD Error;
|
|
PLOCAL_CONTEXT_INFO localInfo;
|
|
|
|
localInfo = DhcpContext->LocalInformation;
|
|
|
|
if ( localInfo->Socket != INVALID_SOCKET ) {
|
|
return ( ERROR_SUCCESS );
|
|
}
|
|
|
|
Error = InitializeDhcpSocket(
|
|
&localInfo->Socket,
|
|
(DhcpContext->InterfacePlumbed) ?
|
|
DhcpContext->IpAddress : (DHCP_IP_ADDRESS)(0)
|
|
);
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
localInfo->Socket = INVALID_SOCKET;
|
|
DhcpPrint(( DEBUG_ERRORS, " Socket Open failed, %ld\n", Error ));
|
|
}
|
|
|
|
return(Error);
|
|
}
|
|
|
|
|
|
DWORD
|
|
CloseDhcpSocket(
|
|
PDHCP_CONTEXT DhcpContext
|
|
)
|
|
{
|
|
|
|
DWORD Error = ERROR_SUCCESS;
|
|
PLOCAL_CONTEXT_INFO localInfo;
|
|
|
|
localInfo = DhcpContext->LocalInformation;
|
|
|
|
if( localInfo->Socket != INVALID_SOCKET ) {
|
|
|
|
DWORD Error1;
|
|
|
|
Error = closesocket( localInfo->Socket );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpPrint(( DEBUG_ERRORS, " Socket close failed, %ld\n", Error ));
|
|
}
|
|
|
|
localInfo->Socket = INVALID_SOCKET;
|
|
|
|
//
|
|
// Reset the IP stack to send DHCP broadcast to first
|
|
// uninitialized stack.
|
|
//
|
|
|
|
Error1 = IPResetInterface();
|
|
DhcpAssert( Error1 == ERROR_SUCCESS );
|
|
}
|
|
|
|
return( Error );
|
|
}
|
|
|
|
|
|
DWORD
|
|
UninitializeInterface(
|
|
PDHCP_CONTEXT DhcpContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function uninitializes a DHCP NIC for DHCP'ing.
|
|
|
|
In NT this function closes the DHCP socket and unplumbs the streams link.
|
|
|
|
Arguments:
|
|
|
|
DhcpContext - A pointer to a DHCP context block.
|
|
fUpdateIP - If non-zero, the IP adapter will be reset.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
DWORD ReturnError = ERROR_SUCCESS;
|
|
PLOCAL_CONTEXT_INFO LocalInfo;
|
|
|
|
LocalInfo = DhcpContext->LocalInformation;
|
|
|
|
if( DhcpContext->InterfacePlumbed ) {
|
|
|
|
//
|
|
// first close socket.
|
|
//
|
|
|
|
Error = CloseDhcpSocket( DhcpContext );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
ReturnError = Error;
|
|
}
|
|
|
|
//
|
|
// Bring down NetBt.
|
|
//
|
|
|
|
Error = NetBTResetIPAddress(
|
|
LocalInfo->NetBTDeviceName,
|
|
DhcpContext->SubnetMask
|
|
);
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
ReturnError = Error;
|
|
}
|
|
|
|
Error = IPResetIPAddress(
|
|
LocalInfo->IpInterfaceContext,
|
|
DhcpContext->SubnetMask );
|
|
|
|
if( Error != ERROR_SUCCESS )
|
|
ReturnError = Error;
|
|
|
|
DhcpContext->InterfacePlumbed = FALSE;
|
|
LocalInfo->DefaultGatewaysSet = FALSE;
|
|
}
|
|
|
|
if( ReturnError != ERROR_SUCCESS ) {
|
|
DhcpPrint(( DEBUG_ERRORS,
|
|
"UninitializeInterface failed, %ld\n", ReturnError));
|
|
}
|
|
|
|
return(ReturnError);
|
|
}
|
|
|
|
|
|
DWORD
|
|
InitializeInterface(
|
|
PDHCP_CONTEXT DhcpContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes a DHCP NIC for DHCP'ing.
|
|
|
|
In NT this function initializes a socket to be used to send and
|
|
receive DHCP messages.
|
|
|
|
Arguments:
|
|
|
|
DhcpContext - A pointer to a DHCP context block.
|
|
|
|
Return Value:
|
|
|
|
The status of the operation.
|
|
|
|
--*/
|
|
{
|
|
PLOCAL_CONTEXT_INFO LocalInfo;
|
|
DWORD Error;
|
|
DWORD ReturnError = ERROR_SUCCESS;
|
|
|
|
LocalInfo = DhcpContext->LocalInformation;
|
|
|
|
if ( DhcpContext->InterfacePlumbed == FALSE )
|
|
{
|
|
|
|
|
|
Error = IPSetIPAddress(
|
|
LocalInfo->IpInterfaceContext,
|
|
DhcpContext->IpAddress,
|
|
DhcpContext->SubnetMask );
|
|
|
|
|
|
if( Error != ERROR_SUCCESS )
|
|
return ERROR_DHCP_ADDRESS_CONFLICT;
|
|
|
|
//
|
|
// if no DefaultGateways is set to this adapter, do it now.
|
|
//
|
|
|
|
if( LocalInfo->DefaultGatewaysSet == FALSE ) {
|
|
|
|
Error = SetDhcpOption(
|
|
LocalInfo->AdapterName,
|
|
OPTION_ROUTER_ADDRESS,
|
|
&LocalInfo->DefaultGatewaysSet,
|
|
TRUE ); // set last known default gateways.
|
|
|
|
// if( (Error != ERROR_SUCCESS ) &&
|
|
// ReturnError = Error;
|
|
// }
|
|
}
|
|
|
|
//
|
|
// Bring back IP first with new address
|
|
//
|
|
|
|
Error = NetBTSetIPAddress(
|
|
LocalInfo->NetBTDeviceName,
|
|
DhcpContext->IpAddress,
|
|
DhcpContext->SubnetMask );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
ReturnError = Error;
|
|
}
|
|
|
|
DhcpContext->InterfacePlumbed = TRUE;
|
|
|
|
//
|
|
// finally open socket.
|
|
//
|
|
|
|
Error = OpenDhcpSocket( DhcpContext );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
ReturnError = Error;
|
|
}
|
|
}
|
|
|
|
if( ReturnError != ERROR_SUCCESS ) {
|
|
DhcpPrint(( DEBUG_ERRORS,
|
|
"InitializeInterface failed, %ld\n",
|
|
ReturnError));
|
|
}
|
|
|
|
|
|
return( ReturnError );
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
SetIpConfigurationForNIC(
|
|
PDHCP_CONTEXT DhcpContext,
|
|
PDHCP_OPTIONS DhcpOptions,
|
|
DHCP_IP_ADDRESS IpAddress,
|
|
DHCP_IP_ADDRESS ServerIpAddress,
|
|
BOOL ObtainedNewAddress
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function updates the registry parameters for a specific NIC.
|
|
If any IP parameters have changed, it also handles reconfiguring the
|
|
network with the new parameters.
|
|
|
|
Arguments:
|
|
|
|
DhcpContext - A pointer to a DHCP context block.
|
|
|
|
DhcpOptions - The options to set.
|
|
|
|
IpAddress - New Ip Address.
|
|
|
|
ServerIpAddress - Address DHCP server that gave the IpAddress.
|
|
|
|
ObtainedNewAddress - TRUE if this is a new address.
|
|
|
|
Return Value:
|
|
|
|
The status of the operation.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
HKEY KeyHandle = NULL;
|
|
|
|
DHCP_IP_ADDRESS SubnetMask;
|
|
|
|
DWORD Lease;
|
|
DWORD T1;
|
|
DWORD T2;
|
|
|
|
time_t LeaseObtained;
|
|
time_t T1Time;
|
|
time_t T2Time;
|
|
time_t LeaseExpires;
|
|
|
|
//
|
|
// If we're being called through the DHCP lease APIs then we don't
|
|
// want to change the registry in any way.
|
|
//
|
|
|
|
if ( ((PLOCAL_CONTEXT_INFO)
|
|
DhcpContext->LocalInformation)->RegistryKey == NULL ) {
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// Open registry key.
|
|
//
|
|
|
|
Error = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
((PLOCAL_CONTEXT_INFO)
|
|
DhcpContext->LocalInformation)->RegistryKey,
|
|
0,
|
|
DHCP_CLIENT_KEY_ACCESS,
|
|
&KeyHandle );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Write changed information.
|
|
//
|
|
|
|
//
|
|
// Update the IP address
|
|
//
|
|
|
|
if ( ObtainedNewAddress) {
|
|
|
|
Error = RegSetIpAddress(
|
|
KeyHandle,
|
|
DHCP_IP_ADDRESS_STRING,
|
|
DHCP_IP_ADDRESS_STRING_TYPE,
|
|
IpAddress );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// if we have obtained a new (and non-zero) address then set it
|
|
// in DesiredIpAddress for next discovery.
|
|
//
|
|
|
|
if( IpAddress != 0 ) {
|
|
|
|
DhcpContext->DesiredIpAddress = IpAddress;
|
|
}
|
|
else {
|
|
|
|
//
|
|
// if we are setting the IP address to zero, remember
|
|
// last know good address to request in next discovery.
|
|
//
|
|
|
|
DhcpContext->DesiredIpAddress = DhcpContext->IpAddress;
|
|
}
|
|
|
|
DhcpContext->IpAddress = IpAddress;
|
|
|
|
DhcpPrint(( DEBUG_LEASE, "New Address: %s\n",
|
|
inet_ntoa( *(struct in_addr *)&IpAddress ) ));
|
|
|
|
//
|
|
// Update the subnet mask
|
|
//
|
|
|
|
if ( DhcpOptions != NULL && DhcpOptions->SubnetMask != NULL ) {
|
|
|
|
SubnetMask= *DhcpOptions->SubnetMask;
|
|
}
|
|
else {
|
|
|
|
//
|
|
// DhcpAssert( FALSE ); should check this point.
|
|
// release hits this BP.
|
|
//
|
|
|
|
SubnetMask = htonl(DhcpDefaultSubnetMask( IpAddress ));
|
|
|
|
}
|
|
|
|
Error = RegSetIpAddress(
|
|
KeyHandle,
|
|
DHCP_SUBNET_MASK_STRING,
|
|
DHCP_SUBNET_MASK_STRING_TYPE,
|
|
SubnetMask );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
DhcpContext->SubnetMask = SubnetMask;
|
|
DhcpPrint(( DEBUG_LEASE, "New SubnetMask: %s\n",
|
|
inet_ntoa( *(struct in_addr *)&SubnetMask) ));
|
|
|
|
Error = RegSetIpAddress(
|
|
KeyHandle,
|
|
DHCP_SERVER,
|
|
DHCP_SERVER_TYPE,
|
|
ServerIpAddress );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
DhcpContext->DhcpServerAddress = ServerIpAddress;
|
|
DhcpPrint(( DEBUG_LEASE, "Server Address: %s\n",
|
|
inet_ntoa( *(struct in_addr *)&ServerIpAddress) ));
|
|
|
|
}
|
|
else {
|
|
|
|
DhcpPrint(( DEBUG_LEASE, "Renewed Address: %s\n",
|
|
inet_ntoa( *(struct in_addr *)&IpAddress ) ));
|
|
}
|
|
|
|
//
|
|
// Update lease time in seconds.
|
|
//
|
|
|
|
if ( DhcpOptions != NULL && DhcpOptions->LeaseTime != NULL ) {
|
|
Lease = ntohl( *DhcpOptions->LeaseTime );
|
|
}
|
|
else {
|
|
Lease = DHCP_MINIMUM_LEASE;
|
|
}
|
|
|
|
DhcpContext->Lease = Lease;
|
|
Error = RegSetValueEx(
|
|
KeyHandle,
|
|
DHCP_LEASE,
|
|
0,
|
|
DHCP_LEASE_TYPE,
|
|
(LPBYTE)&Lease,
|
|
sizeof(Lease) );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Update Lease Obtained Time.
|
|
//
|
|
|
|
LeaseObtained = time( NULL );
|
|
|
|
DhcpContext->LeaseObtained = LeaseObtained;
|
|
|
|
#if DBG
|
|
Error = RegSetTimeField(
|
|
KeyHandle,
|
|
DHCP_LEASE_OBTAINED_CTIME,
|
|
DHCP_LEASE_OBTAINED_CTIME_TYPE,
|
|
LeaseObtained );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
#endif
|
|
|
|
Error = RegSetValueEx(
|
|
KeyHandle,
|
|
DHCP_LEASE_OBTAINED_TIME,
|
|
0,
|
|
DHCP_LEASE_OBTAINED_TIME_TYPE,
|
|
(LPBYTE)&LeaseObtained,
|
|
sizeof(LeaseObtained) );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Update T1 time.
|
|
//
|
|
|
|
if ( DhcpOptions != NULL && DhcpOptions->T1Time != NULL ) {
|
|
T1 = ntohl( *DhcpOptions->T1Time );
|
|
DhcpAssert( T1 < Lease );
|
|
}
|
|
else {
|
|
T1 = Lease / 2; // default 50 %.
|
|
}
|
|
|
|
T1Time = LeaseObtained + T1;
|
|
if ( T1Time < LeaseObtained ) {
|
|
|
|
//
|
|
// overflow has occurred.
|
|
//
|
|
|
|
T1Time = INFINIT_TIME;
|
|
}
|
|
|
|
DhcpContext->T1Time = T1Time;
|
|
#if DBG
|
|
Error = RegSetTimeField(
|
|
KeyHandle,
|
|
DHCP_LEASE_T1_CTIME,
|
|
DHCP_LEASE_T1_CTIME_TYPE,
|
|
T1Time );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
#endif
|
|
|
|
Error = RegSetValueEx(
|
|
KeyHandle,
|
|
DHCP_LEASE_T1_TIME,
|
|
0,
|
|
DHCP_LEASE_T1_TIME_TYPE,
|
|
(LPBYTE)&T1Time,
|
|
sizeof(T1Time) );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Update T2 time.
|
|
//
|
|
|
|
if ( DhcpOptions != NULL && DhcpOptions->T2Time != NULL ) {
|
|
T2 = ntohl( *DhcpOptions->T2Time );
|
|
|
|
//
|
|
// make sure T1 < T2 < Lease.
|
|
//
|
|
|
|
DhcpAssert( T2 < Lease );
|
|
DhcpAssert( T1 < T2 );
|
|
}
|
|
else {
|
|
T2 = Lease * 7 / 8; // default 87.5 %
|
|
}
|
|
|
|
T2Time = LeaseObtained + T2;
|
|
if ( T2Time < LeaseObtained ) {
|
|
|
|
//
|
|
// overflow has occurred.
|
|
//
|
|
|
|
T2Time = INFINIT_TIME;
|
|
}
|
|
|
|
DhcpContext->T2Time = T2Time;
|
|
|
|
#if DBG
|
|
Error = RegSetTimeField(
|
|
KeyHandle,
|
|
DHCP_LEASE_T2_CTIME,
|
|
DHCP_LEASE_T2_CTIME_TYPE,
|
|
T2Time );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
#endif
|
|
|
|
Error = RegSetValueEx(
|
|
KeyHandle,
|
|
DHCP_LEASE_T2_TIME,
|
|
0,
|
|
DHCP_LEASE_T2_TIME_TYPE,
|
|
(LPBYTE)&T2Time,
|
|
sizeof(T2Time) );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
LeaseExpires = LeaseObtained + Lease;
|
|
if( LeaseExpires < LeaseObtained ) {
|
|
|
|
//
|
|
// the lease time raped around, so set it to max.
|
|
//
|
|
|
|
LeaseExpires = INFINIT_TIME;
|
|
}
|
|
|
|
DhcpContext->LeaseExpires = LeaseExpires;
|
|
#if DBG
|
|
Error = RegSetTimeField(
|
|
KeyHandle,
|
|
DHCP_LEASE_TERMINATED_CTIME,
|
|
DHCP_LEASE_TERMINATED_CTIME_TYPE,
|
|
LeaseExpires );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
#endif
|
|
|
|
Error = RegSetValueEx(
|
|
KeyHandle,
|
|
DHCP_LEASE_TERMINATED_TIME,
|
|
0,
|
|
DHCP_LEASE_TERMINATED_TIME_TYPE,
|
|
(LPBYTE)&LeaseExpires,
|
|
sizeof(LeaseExpires) );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
DhcpPrint(( DEBUG_LEASE,
|
|
"New lease expires %s", ctime( &LeaseExpires ) ));
|
|
|
|
//
|
|
// now handle other options.
|
|
//
|
|
|
|
if ( DhcpOptions != NULL ) {
|
|
Error = SetEnvSpecificDhcpOptions( DhcpContext );
|
|
}
|
|
|
|
//
|
|
// If the IP address or subnet mask has been changed,
|
|
// we need to reset NetBt and IP stack
|
|
//
|
|
|
|
if ( ObtainedNewAddress )
|
|
{
|
|
BOOL BoolError;
|
|
|
|
//
|
|
// Bring down network.
|
|
//
|
|
|
|
Error = UninitializeInterface( DhcpContext );
|
|
|
|
if( Error != ERROR_SUCCESS )
|
|
{
|
|
|
|
DhcpPrint(( DEBUG_ERRORS,
|
|
"UninitializeInterface failed: %ld.\n", Error ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// Bring back network with new address.
|
|
//
|
|
|
|
Error = InitializeInterface( DhcpContext );
|
|
if ( ERROR_SUCCESS != Error )
|
|
{
|
|
DhcpPrint( ( DEBUG_ERRORS,
|
|
"InitializeInterface failed: %d\n",
|
|
Error ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// notify other apps.
|
|
//
|
|
|
|
BoolError = PulseEvent( DhcpGlobalNewIpAddressNotifyEvent );
|
|
DhcpAssert( BoolError == TRUE );
|
|
}
|
|
|
|
//
|
|
// finally notify services that the DHCP parameters have been
|
|
// modified.
|
|
//
|
|
|
|
NetBTNotifyRegChanges(
|
|
((PLOCAL_CONTEXT_INFO)
|
|
DhcpContext->LocalInformation)->NetBTDeviceName );
|
|
|
|
//
|
|
// RLF 07/04/94
|
|
//
|
|
// don't reset the popup flag: if the user answers "No" to the any more
|
|
// popups question then there are no more popups: simple
|
|
//
|
|
|
|
// //
|
|
// // reset the popup flag when we successfully renewed the current
|
|
// // IpAddress or discovered a new IpAddress.
|
|
// //
|
|
//
|
|
// if( IpAddress != 0 ) {
|
|
//
|
|
// LOCK_POPUP();
|
|
// DhcpGlobalDisplayPopup = TRUE;
|
|
// UNLOCK_POPUP();
|
|
// }
|
|
|
|
Cleanup:
|
|
|
|
if( KeyHandle != NULL ) {
|
|
RegCloseKey( KeyHandle );
|
|
}
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
|
|
DhcpPrint(( DEBUG_ERRORS,
|
|
"SetIpConfigurationForNIC failed, %ld.\n", Error ));
|
|
}
|
|
|
|
return( Error );
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
SystemInitialize(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function performs implementation specific initialization
|
|
of DHCP.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
The status of the operation.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
|
|
HKEY OptionInfoKey = NULL;
|
|
DHCP_KEY_QUERY_INFO QueryInfo;
|
|
DWORD OptionInfoSize;
|
|
DWORD Index;
|
|
|
|
#if 0
|
|
PLIST_ENTRY listEntry;
|
|
PDHCP_CONTEXT dhcpContext;
|
|
#endif
|
|
|
|
DWORD Version;
|
|
|
|
//
|
|
// Init Global variables.
|
|
//
|
|
|
|
DhcpGlobalOptionCount = 0;
|
|
DhcpGlobalOptionInfo = NULL;
|
|
DhcpGlobalOptionList = NULL;
|
|
DhcpGlobalMultiHomedHost = FALSE;
|
|
|
|
//
|
|
// Seed the random number generator for Transaction IDs.
|
|
//
|
|
|
|
srand( time( NULL ) );
|
|
|
|
//
|
|
// read NT specific options registry info.
|
|
//
|
|
|
|
Error = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
DHCP_CLIENT_OPTION_KEY,
|
|
0, // Reserved field
|
|
DHCP_CLIENT_KEY_ACCESS,
|
|
&OptionInfoKey
|
|
);
|
|
|
|
if ( Error != ERROR_SUCCESS ) {
|
|
goto NoOption;
|
|
}
|
|
|
|
//
|
|
// read number of options specified in the registry.
|
|
//
|
|
|
|
Error = DhcpRegQueryInfoKey(
|
|
OptionInfoKey,
|
|
&QueryInfo );
|
|
|
|
if ( Error != ERROR_SUCCESS ) {
|
|
goto NoOption;
|
|
}
|
|
|
|
//
|
|
// allocate memory for the service specific options list.
|
|
//
|
|
|
|
if( QueryInfo.NumSubKeys == 0 ) {
|
|
goto NoOption;
|
|
}
|
|
|
|
|
|
OptionInfoSize =
|
|
QueryInfo.NumSubKeys * sizeof(SERVICE_SPECIFIC_DHCP_OPTION);
|
|
|
|
DhcpGlobalOptionInfo = DhcpAllocateMemory( OptionInfoSize );
|
|
|
|
if( DhcpGlobalOptionInfo == NULL ) {
|
|
Error = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
DhcpGlobalOptionCount = QueryInfo.NumSubKeys;
|
|
|
|
//
|
|
// read option info from registry.
|
|
//
|
|
|
|
for(Index = 0; Index < DhcpGlobalOptionCount ; Index++ ) {
|
|
|
|
DWORD OptionIDLength;
|
|
WCHAR OptionIDBuffer[DHCP_OPTION_KEY_LEN];
|
|
FILETIME KeyLastWrite;
|
|
HKEY OptionIDKey = NULL;
|
|
|
|
DWORD OptionIDKeyType;
|
|
DWORD OptionIDTypeSize;
|
|
|
|
LPWSTR ValueString;
|
|
|
|
//
|
|
// read next option ID string.
|
|
//
|
|
|
|
OptionIDLength = DHCP_OPTION_KEY_LEN;
|
|
Error = RegEnumKeyEx(
|
|
OptionInfoKey,
|
|
Index, // index.
|
|
OptionIDBuffer,
|
|
&OptionIDLength,
|
|
0, // reserved.
|
|
NULL, // class string not required.
|
|
0, // class string buffer size.
|
|
&KeyLastWrite );
|
|
|
|
DhcpAssert( OptionIDLength <= DHCP_IP_KEY_LEN );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// open option key;
|
|
//
|
|
|
|
Error = RegOpenKeyEx(
|
|
OptionInfoKey,
|
|
OptionIDBuffer,
|
|
0,
|
|
DHCP_CLIENT_KEY_ACCESS,
|
|
&OptionIDKey );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// read option info. Reg Key location and key type.
|
|
//
|
|
|
|
DhcpGlobalOptionInfo[Index].OptionId =
|
|
DhcpRegKeyToOptionId( OptionIDBuffer );
|
|
|
|
Error = GetRegistryString(
|
|
OptionIDKey,
|
|
DHCP_CLIENT_OPTION_REG_LOCATION,
|
|
&DhcpGlobalOptionInfo[Index].RegKey,
|
|
NULL );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
RegCloseKey( OptionIDKey );
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// split the key and the value name.
|
|
//
|
|
|
|
ValueString = wcsrchr( DhcpGlobalOptionInfo[Index].RegKey,
|
|
REGISTRY_CONNECT );
|
|
|
|
if( ValueString == NULL ) {
|
|
RegCloseKey( OptionIDKey );
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
DhcpGlobalOptionInfo[Index].ValueName = ValueString + 1;
|
|
*ValueString = L'\0'; // terminate RegKey.
|
|
|
|
OptionIDTypeSize = sizeof(DhcpGlobalOptionInfo[Index].ValueType);
|
|
Error = RegQueryValueEx(
|
|
OptionIDKey,
|
|
DHCP_CLIENT_OPTION_REG_KEY_TYPE,
|
|
0,
|
|
&OptionIDKeyType,
|
|
(LPBYTE)&DhcpGlobalOptionInfo[Index].ValueType,
|
|
&OptionIDTypeSize );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
RegCloseKey( OptionIDKey );
|
|
goto Cleanup;
|
|
}
|
|
|
|
DhcpAssert( OptionIDKeyType ==
|
|
DHCP_CLIENT_OPTION_REG_KEY_TYPE_TYPE );
|
|
DhcpAssert( OptionIDTypeSize ==
|
|
sizeof(DhcpGlobalOptionInfo[Index].ValueType) );
|
|
|
|
RegCloseKey( OptionIDKey );
|
|
}
|
|
|
|
NoOption:
|
|
|
|
//
|
|
// make host comment, windows' version.
|
|
//
|
|
|
|
DhcpGlobalHostComment = DhcpAllocateMemory( HOST_COMMENT_LENGTH );
|
|
|
|
if( DhcpGlobalHostComment == NULL ) {
|
|
Error = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
Version = GetVersion();
|
|
sprintf( DhcpGlobalHostComment, "%s %d.%d, BUILD %d",
|
|
((Version & 0x80000000) ? WINDOWS_32S : WINDOWS_NT),
|
|
Version & 0xFF,
|
|
(Version >> 8) & 0xFF,
|
|
((Version >> 16) & 0x7FFF) );
|
|
|
|
//
|
|
// Obtain a handle to the message file.
|
|
//
|
|
|
|
DhcpGlobalMessageFileHandle = LoadLibrary( DHCP_SERVICE_DLL );
|
|
|
|
Error = ERROR_SUCCESS;
|
|
|
|
Cleanup:
|
|
|
|
if( OptionInfoKey != NULL ) {
|
|
RegCloseKey( OptionInfoKey );
|
|
}
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
|
|
//
|
|
// if we aren't successful,
|
|
// free the memory we allotted in this function.
|
|
//
|
|
|
|
if( DhcpGlobalOptionInfo != NULL ) {
|
|
for(Index = 0;
|
|
Index < DhcpGlobalOptionCount ;
|
|
Index++ ) {
|
|
if( DhcpGlobalOptionInfo[Index].RegKey != NULL ) {
|
|
DhcpFreeMemory(DhcpGlobalOptionInfo[Index].RegKey);
|
|
}
|
|
}
|
|
DhcpFreeMemory(DhcpGlobalOptionInfo);
|
|
DhcpGlobalOptionInfo = NULL;
|
|
}
|
|
}
|
|
|
|
return( Error );
|
|
}
|
|
|
|
|
|
DWORD
|
|
DhcpInitData(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes DHCP Global data.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Windows Error.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
|
|
|
|
DhcpGlobalMessageFileHandle = NULL;
|
|
DhcpGlobalRecomputeTimerEvent = NULL;
|
|
DhcpGlobalTerminateEvent = NULL;
|
|
DhcpGlobalClientApiPipe = NULL;
|
|
DhcpGlobalClientApiPipeEvent = NULL;
|
|
DhcpGlobalHostComment = NULL;
|
|
DhcpGlobalNewIpAddressNotifyEvent = NULL;
|
|
|
|
InitializeListHead( &DhcpGlobalNICList );
|
|
InitializeListHead( &DhcpGlobalRenewList );
|
|
|
|
InitializeCriticalSection( &DhcpGlobalRenewListCritSect );
|
|
|
|
DhcpGlobalMsgPopupThreadHandle = NULL;
|
|
DhcpGlobalDisplayPopup = TRUE;
|
|
InitializeCriticalSection( &DhcpGlobalPopupCritSect );
|
|
DhcpGlobalIsService = TRUE;
|
|
|
|
#if DBG
|
|
|
|
Error = DhcpGetRegistryValue(
|
|
DHCP_CLIENT_PARAMETER_KEY,
|
|
DHCP_DEBUG_FLAG_VALUE,
|
|
DHCP_DEBUG_FLAG_VALUE_TYPE,
|
|
(PVOID *)&DhcpGlobalDebugFlag );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpGlobalDebugFlag = 0x0000FFFF;
|
|
}
|
|
|
|
if( DhcpGlobalDebugFlag & DEBUG_BREAK_POINT ) {
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// init service status data.
|
|
//
|
|
|
|
DhcpGlobalServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
|
DhcpGlobalServiceStatus.dwCurrentState = SERVICE_START_PENDING;
|
|
DhcpGlobalServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
|
|
DhcpGlobalServiceStatus.dwCheckPoint = 1;
|
|
DhcpGlobalServiceStatus.dwWaitHint = 25000;
|
|
// should be larger than the wait before the last retry.
|
|
|
|
DhcpGlobalServiceStatus.dwWin32ExitCode = ERROR_SUCCESS;
|
|
DhcpGlobalServiceStatus.dwServiceSpecificExitCode = 0;
|
|
|
|
//
|
|
// Initialize dhcp to receive service requests by registering the
|
|
// control handler.
|
|
//
|
|
|
|
DhcpGlobalServiceStatusHandle = RegisterServiceCtrlHandler(
|
|
SERVICE_DHCP,
|
|
ServiceControlHandler );
|
|
|
|
if ( DhcpGlobalServiceStatusHandle == 0 ) {
|
|
Error = GetLastError();
|
|
DhcpPrint(( DEBUG_INIT,
|
|
"RegisterServiceCtrlHandlerW failed, %ld.\n", Error ));
|
|
return(Error);
|
|
}
|
|
|
|
//
|
|
// Tell Service Controller that we are start pending.
|
|
//
|
|
|
|
UpdateStatus();
|
|
|
|
DhcpGlobalRecomputeTimerEvent =
|
|
CreateEvent(
|
|
NULL, // no security.
|
|
FALSE, // automatic reset.
|
|
TRUE, // initial state is signaled.
|
|
NULL ); // no name.
|
|
|
|
|
|
if( DhcpGlobalRecomputeTimerEvent == NULL ) {
|
|
Error = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
DhcpGlobalTerminateEvent =
|
|
CreateEvent(
|
|
NULL, // no security.
|
|
FALSE, // automatic reset.
|
|
FALSE, // initial state is signaled.
|
|
NULL ); // no name.
|
|
|
|
|
|
if( DhcpGlobalTerminateEvent == NULL ) {
|
|
Error = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// create a named event that notifies the ip address changes to
|
|
// external apps.
|
|
//
|
|
|
|
DhcpGlobalNewIpAddressNotifyEvent = DhcpOpenGlobalEvent();
|
|
|
|
if( DhcpGlobalNewIpAddressNotifyEvent == NULL ) {
|
|
Error = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
Error = DhcpApiInit();
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
Error = ERROR_SUCCESS;
|
|
|
|
Cleanup:
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
DhcpPrint(( DEBUG_ERRORS, "DhcpInitData failed, %ld.\n", Error ));
|
|
}
|
|
|
|
return( Error );
|
|
}
|
|
|
|
|
|
VOID
|
|
DhcpCleanup(
|
|
DWORD Error
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function cleans up DHCP Global data before stopping the
|
|
service.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Windows Error.
|
|
|
|
--*/
|
|
{
|
|
DhcpPrint(( DEBUG_MISC,
|
|
"Dhcp Client service is shutting down, %ld.\n", Error ));
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
|
|
DhcpLogEvent( NULL, EVENT_DHCP_SHUTDOWN, Error );
|
|
}
|
|
|
|
//
|
|
// Service is shuting down, may be due to some service problem or
|
|
// the administrator is stopping the service. Inform the service.
|
|
//
|
|
|
|
DhcpGlobalServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
|
|
DhcpGlobalServiceStatus.dwCheckPoint = 0;
|
|
UpdateStatus();
|
|
|
|
DhcpGlobalServiceRunning = FALSE;
|
|
|
|
DhcpApiCleanup();
|
|
|
|
if( DhcpGlobalOptionInfo != NULL) {
|
|
DhcpFreeMemory( DhcpGlobalOptionInfo );
|
|
DhcpGlobalOptionInfo = NULL;
|
|
}
|
|
|
|
if( DhcpGlobalOptionList != NULL) {
|
|
DhcpFreeMemory( DhcpGlobalOptionList );
|
|
DhcpGlobalOptionList = NULL;
|
|
}
|
|
|
|
if( DhcpGlobalMessageFileHandle != NULL ) {
|
|
FreeLibrary( DhcpGlobalMessageFileHandle );
|
|
DhcpGlobalMessageFileHandle = NULL;
|
|
}
|
|
|
|
if( DhcpGlobalTerminateEvent != NULL ) {
|
|
CloseHandle( DhcpGlobalTerminateEvent );
|
|
DhcpGlobalTerminateEvent = NULL;
|
|
}
|
|
|
|
if( DhcpGlobalNewIpAddressNotifyEvent != NULL ) {
|
|
CloseHandle( DhcpGlobalNewIpAddressNotifyEvent );
|
|
DhcpGlobalNewIpAddressNotifyEvent = NULL;
|
|
}
|
|
|
|
while( !IsListEmpty(&DhcpGlobalNICList) ) {
|
|
PLIST_ENTRY NextEntry;
|
|
PDHCP_CONTEXT DhcpContext;
|
|
DWORD DefaultSubnetMask;
|
|
PLOCAL_CONTEXT_INFO LocalInfo;
|
|
DWORD LocalError;
|
|
|
|
|
|
NextEntry = RemoveHeadList(&DhcpGlobalNICList);
|
|
|
|
DhcpContext = CONTAINING_RECORD( NextEntry, DHCP_CONTEXT, NicListEntry );
|
|
LocalInfo = DhcpContext->LocalInformation;
|
|
|
|
DefaultSubnetMask = DhcpDefaultSubnetMask(0);
|
|
|
|
//
|
|
// reset the stack since dhcp is going away and we dont want IP to keep
|
|
// using an expired address if we are not brought back up
|
|
//
|
|
LocalError = IPResetIPAddress(
|
|
LocalInfo->IpInterfaceContext,
|
|
DefaultSubnetMask );
|
|
|
|
if( LocalError != ERROR_SUCCESS ) {
|
|
DhcpPrint(( DEBUG_ERRORS,
|
|
"DhcpCleanup: could not reset IP address\n",
|
|
LocalError));
|
|
}
|
|
|
|
|
|
|
|
LocalError = NetBTResetIPAddress(
|
|
LocalInfo->NetBTDeviceName,
|
|
DefaultSubnetMask );
|
|
|
|
if( LocalError != ERROR_SUCCESS ) {
|
|
DhcpPrint(( DEBUG_ERRORS,
|
|
"DhcpCleanup: could not reset NetBT stack\n",
|
|
LocalError));
|
|
}
|
|
|
|
|
|
DhcpFreeMemory( NextEntry );
|
|
}
|
|
|
|
DeleteCriticalSection( &DhcpGlobalRenewListCritSect );
|
|
|
|
if( DhcpGlobalMsgPopupThreadHandle != NULL ) {
|
|
DWORD WaitStatus;
|
|
|
|
WaitStatus = WaitForSingleObject(
|
|
DhcpGlobalMsgPopupThreadHandle,
|
|
0 );
|
|
|
|
if ( WaitStatus == 0 ) {
|
|
|
|
//
|
|
// This shouldn't be a case, because we close this handle at
|
|
// the end of popup thread.
|
|
//
|
|
|
|
DhcpAssert( WaitStatus == 0 );
|
|
|
|
CloseHandle( DhcpGlobalMsgPopupThreadHandle );
|
|
DhcpGlobalMsgPopupThreadHandle = NULL;
|
|
|
|
} else {
|
|
|
|
DhcpPrint((DEBUG_ERRORS,
|
|
"Cannot WaitFor message popup thread: %ld\n",
|
|
WaitStatus ));
|
|
|
|
if( TerminateThread(
|
|
DhcpGlobalMsgPopupThreadHandle,
|
|
(DWORD)(-1)) == TRUE) {
|
|
|
|
DhcpPrint(( DEBUG_ERRORS, "Terminated popup Thread.\n" ));
|
|
}
|
|
else {
|
|
DhcpPrint(( DEBUG_ERRORS,
|
|
"Can't terminate popup Thread %ld.\n",
|
|
GetLastError() ));
|
|
}
|
|
}
|
|
}
|
|
|
|
DeleteCriticalSection( &DhcpGlobalPopupCritSect );
|
|
|
|
if( DhcpGlobalRecomputeTimerEvent != NULL ) {
|
|
CloseHandle( DhcpGlobalRecomputeTimerEvent );
|
|
DhcpGlobalRecomputeTimerEvent = NULL;
|
|
}
|
|
|
|
DhcpGlobalServiceStatus.dwCurrentState = SERVICE_STOPPED;
|
|
// DhcpGlobalServiceStatus.dwControlsAccepted = 0;
|
|
DhcpGlobalServiceStatus.dwWin32ExitCode = Error;
|
|
DhcpGlobalServiceStatus.dwServiceSpecificExitCode = 0;
|
|
|
|
DhcpGlobalServiceStatus.dwCheckPoint = 0;
|
|
DhcpGlobalServiceStatus.dwWaitHint = 0;
|
|
UpdateStatus();
|
|
|
|
return;
|
|
}
|
|
|
|
DWORD
|
|
ProcessDhcpRequestForever(
|
|
DWORD TimeToSleep
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function process incoming DHCP API request and renew DHCP
|
|
request.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Never returns.
|
|
|
|
--*/
|
|
{
|
|
#define TIMER_EVENT 0
|
|
#define PIPE_EVENT 1
|
|
#define TERMINATE_EVENT 2
|
|
|
|
#define EVENT_COUNT 3
|
|
|
|
DWORD Error;
|
|
HANDLE WaitHandle[EVENT_COUNT];
|
|
DWORD LocalTimeToSleep = TimeToSleep;
|
|
|
|
//
|
|
// Wait and Process the following work items:
|
|
//
|
|
// 1. Wait for Timer recompute event for Client renewal.
|
|
// 2. DHCP Client APIs.
|
|
//
|
|
|
|
WaitHandle[TIMER_EVENT] = DhcpGlobalRecomputeTimerEvent;
|
|
WaitHandle[PIPE_EVENT] = DhcpGlobalClientApiPipeEvent;
|
|
WaitHandle[TERMINATE_EVENT] = DhcpGlobalTerminateEvent;
|
|
|
|
for(;;) {
|
|
|
|
DWORD Waiter;
|
|
DWORD SleepTimeMsec;
|
|
|
|
//
|
|
// don't sleep more than a day long.
|
|
//
|
|
|
|
if( LocalTimeToSleep > DAY_LONG_SLEEP ) {
|
|
LocalTimeToSleep = DAY_LONG_SLEEP;
|
|
}
|
|
|
|
SleepTimeMsec = LocalTimeToSleep * 1000;
|
|
DhcpAssert( SleepTimeMsec > LocalTimeToSleep );
|
|
|
|
Waiter = WaitForMultipleObjects(
|
|
EVENT_COUNT, // num. of handles.
|
|
WaitHandle, // handle array.
|
|
FALSE, // wait for any.
|
|
SleepTimeMsec ); // timeout in msecs.
|
|
|
|
//
|
|
// if either we have timed out or need to recompute timer.
|
|
// do so.
|
|
//
|
|
|
|
switch( Waiter ) {
|
|
case TIMER_EVENT:
|
|
case WAIT_TIMEOUT: {
|
|
|
|
PDHCP_CONTEXT DhcpContext;
|
|
time_t TimeNow;
|
|
PLIST_ENTRY ListEntry;
|
|
|
|
LocalTimeToSleep = INFINIT_LEASE;
|
|
TimeNow = time( NULL );
|
|
|
|
//
|
|
// lock list.
|
|
//
|
|
|
|
LOCK_RENEW_LIST();
|
|
|
|
//
|
|
// Stop the service when the NIC list becomes empty.
|
|
// This happens when the DHCP on last Netcard on this
|
|
// machine is disabled.
|
|
//
|
|
|
|
if( IsListEmpty( &DhcpGlobalNICList ) ) {
|
|
LOCK_RENEW_LIST();
|
|
|
|
#if 0
|
|
// NOT NEEDED ANYMORE: Bug # 18334
|
|
//
|
|
// HACK, delay this shutdown to make the service
|
|
// controller happy during system bootup. Otherwise
|
|
// service controller thinks that the DHCP service
|
|
// fails to start and displays an error popup.
|
|
//
|
|
// This hack should be removed when the setup is fixed,
|
|
// not to place the DHCP in TDI group when none of the
|
|
// network card is DHCP configured.
|
|
//
|
|
|
|
|
|
Sleep( 5 * 60 * 1000 ); // 5 mins delay
|
|
|
|
#endif
|
|
|
|
return( ERROR_SUCCESS );
|
|
}
|
|
|
|
//
|
|
// recompute multi home flag.
|
|
//
|
|
|
|
DhcpGlobalMultiHomedHost = IsMultiHomeMachine();
|
|
|
|
//
|
|
// Loop through the list of DHCP contexts looking for any
|
|
// renewals to run. Also, reset timeToSleep to the nearest
|
|
// future renewal.
|
|
//
|
|
|
|
for( ListEntry = DhcpGlobalRenewList.Flink;
|
|
ListEntry != &DhcpGlobalRenewList; ) {
|
|
|
|
DhcpContext = CONTAINING_RECORD(
|
|
ListEntry,
|
|
DHCP_CONTEXT,
|
|
RenewalListEntry );
|
|
|
|
ListEntry = ListEntry->Flink;
|
|
|
|
//
|
|
// If it is time to run this renewal function, remove the
|
|
// renewal context from the list.
|
|
//
|
|
|
|
if ( DhcpContext->RunTime <= TimeNow ) {
|
|
|
|
//
|
|
// This client has to renew NOW.
|
|
// This renewal can be performed in another thread,
|
|
// but for now it is done here.
|
|
//
|
|
// This client is removed from the list for renewal,
|
|
// when the renewal is performed his entry will be
|
|
// queued again and DhcpGlobalRecomputeTimerEvent is set.
|
|
//
|
|
|
|
RemoveEntryList( &DhcpContext->RenewalListEntry );
|
|
Error = DhcpContext->RenewalFunction( DhcpContext, NULL );
|
|
|
|
if( (Error != ERROR_SUCCESS) &&
|
|
(Error != ERROR_SEM_TIMEOUT) &&
|
|
(Error != ERROR_ACCESS_DENIED) ) {
|
|
|
|
UNLOCK_RENEW_LIST();
|
|
return( Error );
|
|
}
|
|
|
|
} else {
|
|
|
|
DWORD ElapseTime;
|
|
|
|
ElapseTime = DhcpContext->RunTime - TimeNow;
|
|
|
|
if ( LocalTimeToSleep > ElapseTime ) {
|
|
LocalTimeToSleep = ElapseTime;
|
|
}
|
|
}
|
|
}
|
|
|
|
UNLOCK_RENEW_LIST();
|
|
break;
|
|
}
|
|
case PIPE_EVENT: {
|
|
|
|
BOOL BoolError;
|
|
|
|
//
|
|
// Process the API request.
|
|
//
|
|
|
|
ProcessApiRequest(
|
|
DhcpGlobalClientApiPipe,
|
|
&DhcpGlobalClientApiOverLapBuffer );
|
|
|
|
//
|
|
// Disconnect from the current client, and setup to
|
|
// listen for the next request.
|
|
//
|
|
|
|
BoolError = DisconnectNamedPipe( DhcpGlobalClientApiPipe );
|
|
DhcpAssert( BoolError );
|
|
|
|
//
|
|
// ensure the event handle in the overlapped structure is reset
|
|
// before we initiate putting the pipe into listening state
|
|
//
|
|
|
|
ResetEvent(DhcpGlobalClientApiPipeEvent);
|
|
|
|
BoolError = ConnectNamedPipe(
|
|
DhcpGlobalClientApiPipe,
|
|
&DhcpGlobalClientApiOverLapBuffer );
|
|
|
|
// DhcpAssert( BoolError );
|
|
|
|
break;
|
|
}
|
|
|
|
case TERMINATE_EVENT:
|
|
return( ERROR_SUCCESS );
|
|
|
|
case WAIT_FAILED:
|
|
DhcpPrint(( DEBUG_ERRORS,
|
|
"WaitForMultipleObjects failed, %ld.\n",
|
|
GetLastError() ));
|
|
break;
|
|
|
|
default:
|
|
DhcpPrint(( DEBUG_ERRORS,
|
|
"WaitForMultipleObjects received invalid handle, %ld.\n",
|
|
Waiter ));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
SVCS_ENTRY_POINT ( // (SVC_main)
|
|
IN DWORD argc,
|
|
IN LPTSTR argv[],
|
|
IN PSVCS_GLOBAL_DATA pGlobalData,
|
|
IN HANDLE SvcRefHandle
|
|
)
|
|
|
|
{
|
|
DWORD Error;
|
|
time_t timeToSleep;
|
|
|
|
UNREFERENCED_PARAMETER(SvcRefHandle);
|
|
|
|
Error = DhcpInitData();
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
UpdateStatus(); // send heart beat to the service controller.
|
|
|
|
Error = DhcpMakeNICList();
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
#if 0
|
|
//
|
|
// if the NIC list is empty, terminate the service.
|
|
//
|
|
|
|
if( IsListEmpty(&DhcpGlobalNICList) ) {
|
|
|
|
//
|
|
// ?? better error code and log this error.
|
|
//
|
|
|
|
Error = ERROR_NO_NETWORK;
|
|
|
|
DhcpAssert(( DEBUG_ERRORS,
|
|
"NIC list is empty, Service terminates.\n" ));
|
|
|
|
goto Cleanup;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// compute multi home flag.
|
|
//
|
|
|
|
LOCK_RENEW_LIST();
|
|
DhcpGlobalMultiHomedHost = IsMultiHomeMachine();
|
|
UNLOCK_RENEW_LIST();
|
|
|
|
//
|
|
// Attempt to initialize all IP addresses. If we fail, defunct
|
|
// address may be acquired in the DHCP processing loop, below.
|
|
//
|
|
|
|
Error = DhcpInitialize( &timeToSleep );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// set the service is running.
|
|
//
|
|
|
|
DhcpGlobalServiceStatus.dwCurrentState = SERVICE_RUNNING;
|
|
|
|
#if 0
|
|
//
|
|
// don't accept pause, continue and stop controls.
|
|
//
|
|
|
|
DhcpGlobalServiceStatus.dwControlsAccepted = 0;
|
|
#endif
|
|
|
|
UpdateStatus();
|
|
DhcpPrint(( DEBUG_MISC, "Service is running.\n"));
|
|
|
|
DhcpGlobalServiceRunning = TRUE;
|
|
|
|
Error = ProcessDhcpRequestForever( timeToSleep );
|
|
|
|
Cleanup:
|
|
|
|
DhcpCleanup( Error );
|
|
return;
|
|
}
|