/*++ Copyright (c) 1994 Microsoft Corporation Module Name: leaseapi.c Abstract: This file contains apis that obtains/releases ip address from a dhcpserver. These apis can be called by any apps that needs an ip address for lease. Author: Madan Appiah (madana) 30-Nov-1993 Environment: User Mode - Win32 Revision History: --*/ #include "precomp.h" #include "dhcpglobal.h" #include #include #include #include #include #define DEFAULT_RAS_CLASS "RRAS.Microsoft" // // Helper routine // VOID GetHardwareAddressForIpAddress( IN ULONG IpAddress, IN OUT LPBYTE Buf, IN OUT PULONG BufSize ) /*++ Routine Description: This routine calls into iphlpapi to try to figure out the hardware address for an adapter with the given Ip address.. In case of failure, it sets the BufSize to zero. Arguments: IpAddress -- N/W order IpAddress of context for which h/w addr is needed. Buf -- buffer to fill hardware address BufSize -- input size of buffer, and on output how much of buffer is used. --*/ { MIB_IPADDRTABLE *AddrTable; MIB_IFTABLE *IfTable; ULONG Error, i, Index, OldBufSize; ULONG AllocateAndGetIpAddrTableFromStack( MIB_IPADDRTABLE **, BOOL, HANDLE, ULONG ); ULONG AllocateAndGetIfTableFromStack( MIB_IFTABLE **, BOOL, HANDLE, ULONG, BOOL ); IpAddress = ntohl(IpAddress); OldBufSize = (*BufSize); (*BufSize) = 0; AddrTable = NULL; IfTable = NULL; do { Error = AllocateAndGetIpAddrTableFromStack( &AddrTable, FALSE, GetProcessHeap(), 0 ); if( ERROR_SUCCESS != Error ) break; Error = AllocateAndGetIfTableFromStack( &IfTable, FALSE, GetProcessHeap(), 0, FALSE ); if( ERROR_SUCCESS != Error ) break; // // Got both tables.. Now walk the ip addr table to get the index. // for( i = 0; i < AddrTable->dwNumEntries ; i ++ ) { if( AddrTable->table[i].dwAddr == IpAddress ) break; } if( i >= AddrTable->dwNumEntries ) break; Index = AddrTable->table[i].dwIndex; // // Now walk the iftable to find the hwaddr entyr. // for( i = 0; i < IfTable->dwNumEntries ; i ++ ) { if( IfTable->table[i].dwIndex == Index ) { break; } } if( i >= IfTable->dwNumEntries ) break; // // Copy the hw address if there is space. // if( OldBufSize <= IfTable->table[i].dwPhysAddrLen ) break; *BufSize = IfTable->table[i].dwPhysAddrLen; RtlCopyMemory( Buf, IfTable->table[i].bPhysAddr, *BufSize ); // // done // } while ( 0 ); if( NULL != AddrTable ) HeapFree( GetProcessHeap(), 0, AddrTable ); if( NULL != IfTable ) HeapFree( GetProcessHeap(), 0, IfTable ); return ; } ULONG GetSeed( VOID ) /*++ Routine Description: This routine returns a rand number seed that can be used on any thread... (If the routine is called on multiple threads, it tries to make sure that the same number isn't returned in different threads). --*/ { static LONG Seed = 0; LONG OldSeed; OldSeed = InterlockedIncrement(&Seed) - 1; if( 0 == OldSeed ) { OldSeed = Seed = (LONG) time(NULL); } srand((OldSeed << 16) + (LONG)time(NULL)); OldSeed = (rand() << 16) + (rand()); Seed = (rand() << 16) + (rand()); return OldSeed; } DWORD DhcpLeaseIpAddressEx( IN DWORD AdapterIpAddress, IN LPDHCP_CLIENT_UID ClientUID, IN DWORD DesiredIpAddress OPTIONAL, IN OUT LPDHCP_OPTION_LIST OptionList, OUT LPDHCP_LEASE_INFO *LeaseInfo, IN OUT LPDHCP_OPTION_INFO *OptionInfo, IN LPBYTE ClassId OPTIONAL, IN ULONG ClassIdLen ) /*++ Routine Description: This api obtains an IP address lease from a dhcp server. The caller should specify the client uid and a desired ip address. The client uid must be globally unique. Set the desired ip address to zero if you can accept any ip address. Otherwise this api will try to obtain the ip address you have specified, but not guaranteed. The caller may optionally requtest additional option info from the dhcp server, The caller should specify the list in OptionList parameter and the api will return the available option data in OptionInfo structure. ?? Option retrival is not implemented in the first phase. This requires several modification in the dhcp client code. WSAStartup must haave been successfully called before this function can be called. Arguments: AdapterIpAddress - IpAddress of the adapter. On a multi-homed machined this specifies the subnet from which an address is requested. This value can be set to zero if the machine is a non-multi-homed machine or you like to get ip address from any of the subnets. This must be network byte order.. ClientUID - pointer to a client UID structure. DesiredIpAddress - the ip address you prefer. OptionList - list of option ids. LeaseInfo - pointer to a location where the lease info structure pointer is retured. The caller should free up this structure after use. OptionInfo - pointer to a location where the option info structure pointer is returned. The caller should free up this structure after use. ClassId - a byte sequence for user class ClassIdLen - number of bytes present in ClassId Return Value: Windows Error. --*/ { DWORD Error; PDHCP_CONTEXT DhcpContext = NULL; ULONG DhcpContextSize; PLOCAL_CONTEXT_INFO LocalInfo = NULL; LPVOID Ptr; DHCP_OPTIONS DhcpOptions; LPDHCP_LEASE_INFO LocalLeaseInfo = NULL; time_t LeaseObtained; DWORD T1, T2, Lease; BYTE DefaultParamRequests[] = { 0x2E, 0x2C, 0x0F, 0x01, 0x03, 0x06, 0x2F }; DWORD nDefaultParamRequests = sizeof(DefaultParamRequests); ULONG HwAddrSize; BYTE HwAddrBuf[200]; BOOL fAutoConfigure = TRUE; DHCP_OPTION ParamRequestList = { { NULL, NULL /* List entry */}, OPTION_PARAMETER_REQUEST_LIST, FALSE /* not a vendor specific option */, NULL, 0 /* no class id */, 0 /* expiration time useless */, DefaultParamRequests, nDefaultParamRequests }; if( NULL == ClassId && 0 != ClassIdLen || 0 == ClassIdLen && NULL != ClassId ) { return ERROR_INVALID_PARAMETER; } Error = DhcpCommonInit(); if( ERROR_SUCCESS != Error ) return Error; HwAddrSize = 0; if( INADDR_ANY != AdapterIpAddress && INADDR_LOOPBACK != AdapterIpAddress ) { HwAddrSize = sizeof(HwAddrBuf); GetHardwareAddressForIpAddress( AdapterIpAddress, HwAddrBuf, &HwAddrSize );; } if( 0 == HwAddrSize ) { HwAddrSize = ClientUID->ClientUIDLength; if( HwAddrSize > sizeof(HwAddrBuf) ) return ERROR_INVALID_DATA; RtlCopyMemory(HwAddrBuf, ClientUID->ClientUID, HwAddrSize ); } DhcpContextSize = // allocate memory for dhcpcontext, in one blob ROUND_UP_COUNT(sizeof(DHCP_CONTEXT), ALIGN_WORST) + ROUND_UP_COUNT(ClientUID->ClientUIDLength, ALIGN_WORST) + ROUND_UP_COUNT(HwAddrSize, 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 ); memset(Ptr, 0, DhcpContextSize); DhcpContext = Ptr; // align up the pointers Ptr = ROUND_UP_POINTER( (LPBYTE)Ptr + sizeof(DHCP_CONTEXT), ALIGN_WORST); DhcpContext->ClientIdentifier.pbID = Ptr; Ptr = ROUND_UP_POINTER( (LPBYTE)Ptr + ClientUID->ClientUIDLength, ALIGN_WORST); DhcpContext->HardwareAddress = Ptr; Ptr = ROUND_UP_POINTER( (LPBYTE)Ptr + HwAddrSize, ALIGN_WORST); DhcpContext->LocalInformation = Ptr; LocalInfo = Ptr; Ptr = ROUND_UP_POINTER( (LPBYTE)Ptr + sizeof(LOCAL_CONTEXT_INFO), ALIGN_WORST); DhcpContext->MessageBuffer = Ptr; // // initialize fields. // DhcpContext->HardwareAddressType = HARDWARE_TYPE_10MB_EITHERNET; DhcpContext->HardwareAddressLength = HwAddrSize; DhcpContext->RefCount = 1 ; RtlCopyMemory(DhcpContext->HardwareAddress,HwAddrBuf, HwAddrSize); DhcpContext->ClientIdentifier.cbID = ClientUID->ClientUIDLength; DhcpContext->ClientIdentifier.bType = HARDWARE_TYPE_10MB_EITHERNET; DhcpContext->ClientIdentifier.fSpecified = TRUE; RtlCopyMemory( DhcpContext->ClientIdentifier.pbID, ClientUID->ClientUID, ClientUID->ClientUIDLength ); DhcpContext->IpAddress = 0; DhcpContext->SubnetMask = DhcpDefaultSubnetMask(0); DhcpContext->DhcpServerAddress = 0xFFFFFFFF; DhcpContext->DesiredIpAddress = DesiredIpAddress; DhcpContext->Lease = 0; DhcpContext->LeaseObtained = 0; DhcpContext->T1Time = 0; DhcpContext->T2Time = 0; DhcpContext->LeaseExpires = 0; INIT_STATE(DhcpContext); AUTONET_ENABLED(DhcpContext); APICTXT_ENABLED(DhcpContext); // mark the context as being created by the API DhcpContext->IPAutoconfigurationContext.Address = 0; DhcpContext->IPAutoconfigurationContext.Subnet = inet_addr(DHCP_IPAUTOCONFIGURATION_DEFAULT_SUBNET); DhcpContext->IPAutoconfigurationContext.Mask = inet_addr(DHCP_IPAUTOCONFIGURATION_DEFAULT_MASK); DhcpContext->IPAutoconfigurationContext.Seed = GetSeed(); InitializeListHead(&DhcpContext->RecdOptionsList); InitializeListHead(&DhcpContext->SendOptionsList); InsertHeadList(&DhcpContext->SendOptionsList, &ParamRequestList.OptionList); DhcpContext->ClassId = ClassId; DhcpContext->ClassIdLength = ClassIdLen; // // copy local info. // // // unused portion of the local info. // LocalInfo->IpInterfaceContext = 0xFFFFFFFF; LocalInfo->AdapterName= NULL; //LocalInfo->DeviceName= NULL; LocalInfo->NetBTDeviceName= NULL; LocalInfo->RegistryKey= NULL; LocalInfo->DefaultGatewaysSet = FALSE; // used portion of the local info. LocalInfo->Socket = INVALID_SOCKET; // if AdapterIpAddress is loopback addr then, the client just wants us to // fabricate autonet address. The client can do this if there is no interface // available on this machine to autonet on. if (INADDR_LOOPBACK == AdapterIpAddress) { DhcpContext->IpAddress = GrandHashing( DhcpContext->HardwareAddress, DhcpContext->HardwareAddressLength, &DhcpContext->IPAutoconfigurationContext.Seed, DhcpContext->IPAutoconfigurationContext.Mask, DhcpContext->IPAutoconfigurationContext.Subnet ); DhcpContext->SubnetMask = DhcpContext->IPAutoconfigurationContext.Mask; ACQUIRED_AUTO_ADDRESS(DhcpContext); } else { // // open socket now. receive any. // Error = InitializeDhcpSocket(&LocalInfo->Socket,ntohl( AdapterIpAddress ), IS_APICTXT_ENABLED(DhcpContext) ); if( Error != ERROR_SUCCESS ) { goto Cleanup; } // // now discover an ip address. // Error = ObtainInitialParameters( DhcpContext, &DhcpOptions, &fAutoConfigure ); if( ERROR_SEM_TIMEOUT == Error ) { DhcpPrint((DEBUG_PROTOCOL, "RAS: No server found, trying to autoconfigure\n")); if( fAutoConfigure ) { Error = DhcpPerformIPAutoconfiguration(DhcpContext); } if( ERROR_SUCCESS != Error ) { DhcpPrint((DEBUG_ERRORS, "Autoconfiguration for RAS failed: 0x%lx\n", Error)); } } // // no matter what happens here, freeup the list of options as that is not really needed.. // LOCK_OPTIONS_LIST(); (void) DhcpDestroyOptionsList(&DhcpContext->RecdOptionsList, &DhcpGlobalClassesList); UNLOCK_OPTIONS_LIST(); if( Error != ERROR_SUCCESS ) { goto Cleanup; } } // // allocate memory for the return client info structure. // LocalLeaseInfo = DhcpAllocateMemory( sizeof(DHCP_LEASE_INFO) ); if( LocalLeaseInfo == NULL ) { Error = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } LocalLeaseInfo->ClientUID = *ClientUID; LocalLeaseInfo->IpAddress = ntohl( DhcpContext->IpAddress ); if( IS_ADDRESS_AUTO(DhcpContext) ) { LocalLeaseInfo->SubnetMask = ntohl(DhcpContext->SubnetMask); LocalLeaseInfo->DhcpServerAddress = ntohl(DhcpContext->DhcpServerAddress); LocalLeaseInfo->Lease = DhcpContext->Lease; LocalLeaseInfo->LeaseObtained = DhcpContext->LeaseObtained; LocalLeaseInfo->T1Time = DhcpContext->T1Time; LocalLeaseInfo->T2Time = DhcpContext->T2Time; LocalLeaseInfo->LeaseExpires = DhcpContext->LeaseExpires; Error = ERROR_SUCCESS; *LeaseInfo = LocalLeaseInfo; goto Cleanup; } if ( DhcpOptions.SubnetMask != NULL ) { LocalLeaseInfo->SubnetMask= ntohl( *DhcpOptions.SubnetMask ); } else { LocalLeaseInfo->SubnetMask = ntohl(DhcpDefaultSubnetMask( DhcpContext->IpAddress )); } LocalLeaseInfo->DhcpServerAddress = ntohl( DhcpContext->DhcpServerAddress ); if ( DhcpOptions.LeaseTime != NULL) { LocalLeaseInfo->Lease = ntohl( *DhcpOptions.LeaseTime ); } else { LocalLeaseInfo->Lease = DHCP_MINIMUM_LEASE; } Lease = LocalLeaseInfo->Lease; LeaseObtained = time( NULL ); LocalLeaseInfo->LeaseObtained = LeaseObtained; T1 = 0; if ( DhcpOptions.T1Time != NULL ) { T1 = ntohl( *DhcpOptions.T1Time ); } T2 = 0; if ( DhcpOptions.T2Time != NULL ) { T2 = ntohl( *DhcpOptions.T2Time ); } // // make sure T1 < T2 < Lease // if( (T2 == 0) || (T2 > Lease) ) { T2 = Lease * 7 / 8; // default 87.7 %. } if( (T1 == 0) || (T1 > T2) ) { T1 = (T2 > Lease / 2) ? (Lease / 2) : (T2 - 1); // default 50 %.; } LocalLeaseInfo->T1Time = LeaseObtained + T1; if ( LocalLeaseInfo->T1Time < LeaseObtained ) { LocalLeaseInfo->T1Time = INFINIT_TIME; // over flow. } LocalLeaseInfo->T2Time = LeaseObtained + T2; if ( LocalLeaseInfo->T2Time < LeaseObtained ) { LocalLeaseInfo->T2Time = INFINIT_TIME; } LocalLeaseInfo->LeaseExpires = LeaseObtained + Lease; if ( LocalLeaseInfo->LeaseExpires < LeaseObtained ) { LocalLeaseInfo->LeaseExpires = INFINIT_TIME; } *LeaseInfo = LocalLeaseInfo; Error = ERROR_SUCCESS; Cleanup: if( OptionInfo ) *OptionInfo = NULL; // not implemented. // // close socket. // if( (LocalInfo != NULL) && (LocalInfo->Socket != INVALID_SOCKET) ) { closesocket( LocalInfo->Socket ); } if( DhcpContext != NULL ) { DhcpFreeMemory( DhcpContext ); } if( Error != ERROR_SUCCESS ) { // // free locally allocated memory, if we aren't successful. // if( LocalLeaseInfo != NULL ) { DhcpFreeMemory( LocalLeaseInfo ); *LeaseInfo = NULL; } } return( Error ); } DWORD DhcpRenewIpAddressLeaseEx( DWORD AdapterIpAddress, LPDHCP_LEASE_INFO ClientLeaseInfo, LPDHCP_OPTION_LIST OptionList, LPDHCP_OPTION_INFO *OptionInfo, LPBYTE ClassId OPTIONAL, ULONG ClassIdLen ) /*++ Routine Description: This api renews an ip address that the client already has. When a client gets an ip address, it can use the address until the lease expires. The client should stop using the ip address after that. Also the client should renew the address after T1 time if the client is planning to use the address longer than the current lease time. WSAStartup must have been successfully called before this function can be called. Arguments: AdapterIpAddress - IpAddress of the adapter. On a multi-homed machined this specifies the subnet from which an address is renewed. This value can be set to zero if the machine is non-multi-homed machine. ClientLeaseInfo : pointer to the client lease info structure. On entry the structure should contain the information that was returned by the DhcpLeaseIpAddress or DhcpRenewIpAddressLease apis. On return this structure is updated to reflect the lease extension. OptionList - list of option ids. OptionInfo - pointer to a location where the option info structure pointer is returned. The caller should free up this structure after use. ClassId - a byte sequence for user class ClassIdLen - number of bytes present in ClassId Return Value: Windows Error. --*/ { DWORD Error; PDHCP_CONTEXT DhcpContext = NULL; ULONG DhcpContextSize; PLOCAL_CONTEXT_INFO LocalInfo; LPVOID Ptr; DHCP_OPTIONS DhcpOptions; time_t LeaseObtained; DWORD T1, T2, Lease; BYTE DefaultParamRequests[] = { 0x2E, 0x2C, 0x0F, 0x01, 0x03, 0x06, 0x2F }; DWORD nDefaultParamRequests = sizeof(DefaultParamRequests); LPDHCP_CLIENT_UID ClientUID = &(ClientLeaseInfo->ClientUID); ULONG HwAddrSize; BYTE HwAddrBuf[200]; DHCP_OPTION ParamRequestList = { { NULL, NULL /* List entry */}, OPTION_PARAMETER_REQUEST_LIST, FALSE /* not a vendor specific option */, NULL, 0 /* no class id */, 0 /* expiration time useless */, DefaultParamRequests, nDefaultParamRequests }; if( NULL == ClassId && 0 != ClassIdLen || 0 == ClassIdLen && NULL != ClassId) { return ERROR_INVALID_PARAMETER; } Error = DhcpCommonInit(); if( ERROR_SUCCESS != Error ) return Error; // // prepare dhcp context structure. // HwAddrSize = 0; if( INADDR_ANY != AdapterIpAddress && INADDR_LOOPBACK != AdapterIpAddress ) { HwAddrSize = sizeof(HwAddrBuf); GetHardwareAddressForIpAddress( AdapterIpAddress, HwAddrBuf, &HwAddrSize );; } if( 0 == HwAddrSize ) { HwAddrSize = ClientUID->ClientUIDLength; if( HwAddrSize > sizeof(HwAddrBuf) ) return ERROR_INVALID_DATA; RtlCopyMemory(HwAddrBuf, ClientUID->ClientUID, HwAddrSize ); } DhcpContextSize = // allocate memory for dhcpcontext, in one blob ROUND_UP_COUNT(sizeof(DHCP_CONTEXT), ALIGN_WORST) + ROUND_UP_COUNT(ClientUID->ClientUIDLength, ALIGN_WORST) + ROUND_UP_COUNT(HwAddrSize, 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 ); } // // make sure the pointers are aligned. // DhcpContext = Ptr; // align up the pointers Ptr = ROUND_UP_POINTER( (LPBYTE)Ptr + sizeof(DHCP_CONTEXT), ALIGN_WORST); DhcpContext->ClientIdentifier.pbID = Ptr; Ptr = ROUND_UP_POINTER( (LPBYTE)Ptr + ClientUID->ClientUIDLength, ALIGN_WORST); DhcpContext->HardwareAddress = Ptr; Ptr = ROUND_UP_POINTER( (LPBYTE)Ptr + HwAddrSize, ALIGN_WORST); DhcpContext->LocalInformation = Ptr; LocalInfo = Ptr; Ptr = ROUND_UP_POINTER( (LPBYTE)Ptr + sizeof(LOCAL_CONTEXT_INFO), ALIGN_WORST); DhcpContext->MessageBuffer = Ptr; // // initialize fields. // DhcpContext->HardwareAddressType = HARDWARE_TYPE_10MB_EITHERNET; DhcpContext->HardwareAddressLength = HwAddrSize; RtlCopyMemory(DhcpContext->HardwareAddress,HwAddrBuf, HwAddrSize); DhcpContext->RefCount = 1 ; DhcpContext->ClientIdentifier.cbID = ClientUID->ClientUIDLength; DhcpContext->ClientIdentifier.bType = HARDWARE_TYPE_10MB_EITHERNET; DhcpContext->ClientIdentifier.fSpecified = TRUE; RtlCopyMemory( DhcpContext->ClientIdentifier.pbID, ClientUID->ClientUID, ClientUID->ClientUIDLength ); DhcpContext->IpAddress = htonl( ClientLeaseInfo->IpAddress ); DhcpContext->SubnetMask = htonl( ClientLeaseInfo->SubnetMask ); if( time(NULL) > ClientLeaseInfo->T2Time ) { DhcpContext->DhcpServerAddress = 0xFFFFFFFF; } else { DhcpContext->DhcpServerAddress = htonl( ClientLeaseInfo->DhcpServerAddress ); } DhcpContext->DesiredIpAddress = DhcpContext->IpAddress; DhcpContext->Lease = ClientLeaseInfo->Lease; DhcpContext->LeaseObtained = ClientLeaseInfo->LeaseObtained; DhcpContext->T1Time = ClientLeaseInfo->T1Time; DhcpContext->T2Time = ClientLeaseInfo->T2Time; DhcpContext->LeaseExpires = ClientLeaseInfo->LeaseExpires; INIT_STATE(DhcpContext); AUTONET_ENABLED(DhcpContext); CTXT_WAS_LOOKED(DhcpContext); // this is to prevent PING from happeneing. APICTXT_ENABLED(DhcpContext); // mark the context as being created by the API DhcpContext->DontPingGatewayFlag = TRUE; // double assurance against the former.. DhcpContext->IPAutoconfigurationContext.Address = 0; DhcpContext->IPAutoconfigurationContext.Subnet = inet_addr(DHCP_IPAUTOCONFIGURATION_DEFAULT_SUBNET); DhcpContext->IPAutoconfigurationContext.Mask = inet_addr(DHCP_IPAUTOCONFIGURATION_DEFAULT_MASK); DhcpContext->IPAutoconfigurationContext.Seed = GetSeed(); InitializeListHead(&DhcpContext->RecdOptionsList); InitializeListHead(&DhcpContext->SendOptionsList); InsertHeadList(&DhcpContext->SendOptionsList, &ParamRequestList.OptionList); DhcpContext->ClassId = ClassId; DhcpContext->ClassIdLength = ClassIdLen; // // copy local info. // // // unused portion of the local info. // LocalInfo->IpInterfaceContext = 0xFFFFFFFF; LocalInfo->AdapterName= NULL; //LocalInfo->DeviceName= NULL; LocalInfo->NetBTDeviceName= NULL; LocalInfo->RegistryKey= NULL; // // used portion of the local info. // LocalInfo->Socket = INVALID_SOCKET; LocalInfo->DefaultGatewaysSet = FALSE; // // open socket now. // Error = InitializeDhcpSocket( &LocalInfo->Socket, htonl( AdapterIpAddress ), IS_APICTXT_ENABLED(DhcpContext)); if( Error != ERROR_SUCCESS ) { goto Cleanup; } // // now discover ip address. // Error = RenewLease( DhcpContext, &DhcpOptions ); // // no matter what happens here, freeup the list of options as that is not really needed.. // LOCK_OPTIONS_LIST(); (void) DhcpDestroyOptionsList(&DhcpContext->RecdOptionsList, &DhcpGlobalClassesList); UNLOCK_OPTIONS_LIST(); if( Error != ERROR_SUCCESS ) { goto Cleanup; } ClientLeaseInfo->DhcpServerAddress = ntohl( DhcpContext->DhcpServerAddress ); if ( DhcpOptions.LeaseTime != NULL) { ClientLeaseInfo->Lease = ntohl( *DhcpOptions.LeaseTime ); } else { ClientLeaseInfo->Lease = DHCP_MINIMUM_LEASE; } Lease = ClientLeaseInfo->Lease; LeaseObtained = time( NULL ); ClientLeaseInfo->LeaseObtained = LeaseObtained; T1 = 0; if ( DhcpOptions.T1Time != NULL ) { T1 = ntohl( *DhcpOptions.T1Time ); } T2 = 0; if ( DhcpOptions.T2Time != NULL ) { T2 = ntohl( *DhcpOptions.T2Time ); } // // make sure T1 < T2 < Lease // if( (T2 == 0) || (T2 > Lease) ) { T2 = Lease * 7 / 8; // default 87.7 %. } if( (T1 == 0) || (T1 > T2) ) { T1 = (T2 > Lease / 2) ? (Lease / 2) : (T2 - 1); // default 50 %. } ClientLeaseInfo->T1Time = LeaseObtained + T1; if ( ClientLeaseInfo->T1Time < LeaseObtained ) { ClientLeaseInfo->T1Time = INFINIT_TIME; // over flow. } ClientLeaseInfo->T2Time = LeaseObtained + T2; if ( ClientLeaseInfo->T2Time < LeaseObtained ) { ClientLeaseInfo->T2Time = INFINIT_TIME; } ClientLeaseInfo->LeaseExpires = LeaseObtained + Lease; if ( ClientLeaseInfo->LeaseExpires < LeaseObtained ) { ClientLeaseInfo->LeaseExpires = INFINIT_TIME; } Error = ERROR_SUCCESS; Cleanup: if( OptionInfo ) *OptionInfo = NULL; // not implemented. if( (LocalInfo != NULL) && (LocalInfo->Socket != INVALID_SOCKET) ) { closesocket( LocalInfo->Socket ); } if( DhcpContext != NULL ) { DhcpFreeMemory( DhcpContext ); } return( Error ); } DWORD DhcpReleaseIpAddressLeaseEx( DWORD AdapterIpAddress, LPDHCP_LEASE_INFO ClientLeaseInfo, LPBYTE ClassId OPTIONAL, ULONG ClassIdLen ) /*++ Routine Description: This function releases an ip address the client has. WSAStartup must have already been called before this function can be called. Arguments: AdapterIpAddress - IpAddress of the adapter. On a multi-homed machined this specifies the subnet to which an address is released. This value can be set to zero if the machine is non-multi-homed machine. ClientLeaseInfo : pointer to the client lease info structure. On entry the structure should contain the information that was returned by the DhcpLeaseIpAddress or DhcpRenewIpAddressLease apis. ClassId - a byte sequence for user class ClassIdLen - number of bytes present in ClassId Return Value: Windows Error. --*/ { DWORD Error; PDHCP_CONTEXT DhcpContext = NULL; ULONG DhcpContextSize; PLOCAL_CONTEXT_INFO LocalInfo; LPDHCP_CLIENT_UID ClientUID = &(ClientLeaseInfo->ClientUID); ULONG HwAddrSize; BYTE HwAddrBuf[200]; LPVOID Ptr; if( NULL == ClassId && 0 != ClassIdLen || 0 == ClassIdLen && NULL != ClassId ) { return ERROR_INVALID_PARAMETER; } Error = DhcpCommonInit(); if( ERROR_SUCCESS != Error ) return Error; if( (DWORD) -1 == ClientLeaseInfo->DhcpServerAddress ) { // this means the address was autoconfigured, nothing to release.. return ERROR_SUCCESS; } // // prepare dhcp context structure. // HwAddrSize = 0; if( INADDR_ANY != AdapterIpAddress && INADDR_LOOPBACK != AdapterIpAddress ) { HwAddrSize = sizeof(HwAddrBuf); GetHardwareAddressForIpAddress( AdapterIpAddress, HwAddrBuf, &HwAddrSize );; } if( 0 == HwAddrSize ) { HwAddrSize = ClientUID->ClientUIDLength; if( HwAddrSize > sizeof(HwAddrBuf) ) return ERROR_INVALID_DATA; RtlCopyMemory(HwAddrBuf, ClientUID->ClientUID, HwAddrSize ); } DhcpContextSize = // allocate memory for dhcpcontext, in one blob ROUND_UP_COUNT(sizeof(DHCP_CONTEXT), ALIGN_WORST) + ROUND_UP_COUNT(ClientUID->ClientUIDLength, ALIGN_WORST) + ROUND_UP_COUNT(HwAddrSize, 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 ); } // // make sure the pointers are aligned. // DhcpContext = Ptr; // align up the pointers Ptr = ROUND_UP_POINTER( (LPBYTE)Ptr + sizeof(DHCP_CONTEXT), ALIGN_WORST); DhcpContext->ClientIdentifier.pbID = Ptr; Ptr = ROUND_UP_POINTER( (LPBYTE)Ptr + ClientUID->ClientUIDLength, ALIGN_WORST); DhcpContext->HardwareAddress = Ptr; Ptr = ROUND_UP_POINTER( (LPBYTE)Ptr + HwAddrSize, ALIGN_WORST); DhcpContext->LocalInformation = Ptr; LocalInfo = Ptr; Ptr = ROUND_UP_POINTER( (LPBYTE)Ptr + sizeof(LOCAL_CONTEXT_INFO), ALIGN_WORST); DhcpContext->MessageBuffer = Ptr; // // initialize fields. // DhcpContext->HardwareAddressType = HARDWARE_TYPE_10MB_EITHERNET; DhcpContext->HardwareAddressLength = HwAddrSize; RtlCopyMemory(DhcpContext->HardwareAddress,HwAddrBuf, HwAddrSize); DhcpContext->RefCount = 1 ; DhcpContext->ClientIdentifier.cbID = ClientUID->ClientUIDLength; DhcpContext->ClientIdentifier.bType = HARDWARE_TYPE_10MB_EITHERNET; DhcpContext->ClientIdentifier.fSpecified = TRUE; RtlCopyMemory( DhcpContext->ClientIdentifier.pbID, ClientUID->ClientUID, ClientUID->ClientUIDLength ); DhcpContext->IpAddress = htonl( ClientLeaseInfo->IpAddress ); DhcpContext->SubnetMask = htonl( ClientLeaseInfo->SubnetMask ); DhcpContext->DhcpServerAddress = htonl( ClientLeaseInfo->DhcpServerAddress ); DhcpContext->DesiredIpAddress = DhcpContext->IpAddress; DhcpContext->Lease = ClientLeaseInfo->Lease; DhcpContext->LeaseObtained = ClientLeaseInfo->LeaseObtained; DhcpContext->T1Time = ClientLeaseInfo->T1Time; DhcpContext->T2Time = ClientLeaseInfo->T2Time; DhcpContext->LeaseExpires = ClientLeaseInfo->LeaseExpires; INIT_STATE(DhcpContext); APICTXT_ENABLED(DhcpContext); // mark the context as being created by the API DhcpContext->IPAutoconfigurationContext.Address = 0; DhcpContext->IPAutoconfigurationContext.Subnet = inet_addr(DHCP_IPAUTOCONFIGURATION_DEFAULT_SUBNET); DhcpContext->IPAutoconfigurationContext.Mask = inet_addr(DHCP_IPAUTOCONFIGURATION_DEFAULT_MASK); DhcpContext->IPAutoconfigurationContext.Seed = GetSeed(); InitializeListHead(&DhcpContext->RecdOptionsList); InitializeListHead(&DhcpContext->SendOptionsList); DhcpContext->ClassId = ClassId; DhcpContext->ClassIdLength = ClassIdLen; // // copy local info. // // // unused portion of the local info. // LocalInfo->IpInterfaceContext = 0xFFFFFFFF; LocalInfo->AdapterName= NULL; //LocalInfo->DeviceName= NULL; LocalInfo->NetBTDeviceName= NULL; LocalInfo->RegistryKey= NULL; // // used portion of the local info. // LocalInfo->Socket = INVALID_SOCKET; LocalInfo->DefaultGatewaysSet = FALSE; // // open socket now. // Error = InitializeDhcpSocket( &LocalInfo->Socket, htonl( AdapterIpAddress ), IS_APICTXT_ENABLED(DhcpContext)); if( Error != ERROR_SUCCESS ) { goto Cleanup; } // // now release ip address. // Error = ReleaseIpAddress( DhcpContext ); ClientLeaseInfo->IpAddress = 0; ClientLeaseInfo->SubnetMask = DhcpDefaultSubnetMask( 0 ); ClientLeaseInfo->DhcpServerAddress = 0xFFFFFFFF; ClientLeaseInfo->Lease = 0; ClientLeaseInfo->LeaseObtained = ClientLeaseInfo->T1Time = ClientLeaseInfo->T2Time = ClientLeaseInfo->LeaseExpires = time( NULL ); // // recd options list cannot have any elements now..! // DhcpAssert(IsListEmpty(&DhcpContext->RecdOptionsList)); Cleanup: if( (LocalInfo != NULL) && (LocalInfo->Socket != INVALID_SOCKET) ) { closesocket( LocalInfo->Socket ); } if( DhcpContext != NULL ) { DhcpFreeMemory( DhcpContext ); } return( Error ); } DWORD DhcpLeaseIpAddress( DWORD AdapterIpAddress, LPDHCP_CLIENT_UID ClientUID, DWORD DesiredIpAddress, LPDHCP_OPTION_LIST OptionList, LPDHCP_LEASE_INFO *LeaseInfo, LPDHCP_OPTION_INFO *OptionInfo ) /*++ Routine Description: This api obtains an IP address lease from a dhcp server. The caller should specify the client uid and a desired ip address. The client uid must be globally unique. Set the desired ip address to zero if you can accept any ip address. Otherwise this api will try to obtain the ip address you have specified, but not guaranteed. The caller may optionally requtest additional option info from the dhcp server, The caller should specify the list in OptionList parameter and the api will return the available option data in OptionInfo structure. ?? Option retrival is not implemented in the first phase. This requires several modification in the dhcp client code. Please do not use this function -- this is deprecated. Use the Ex functions instead. Arguments: AdapterIpAddress - IpAddress of the adapter. On a multi-homed machined this specifies the subnet from which an address is requested. This value can be set to zero if the machine is a non-multi-homed machine or you like to get ip address from any of the subnets. This must be network byte order.. ClientUID - pointer to a client UID structure. DesiredIpAddress - the ip address you prefer. OptionList - list of option ids. LeaseInfo - pointer to a location where the lease info structure pointer is retured. The caller should free up this structure after use. OptionInfo - pointer to a location where the option info structure pointer is returned. The caller should free up this structure after use. Return Value: Windows Error. --*/ { return DhcpLeaseIpAddressEx( AdapterIpAddress, ClientUID, DesiredIpAddress, OptionList, LeaseInfo, OptionInfo, DEFAULT_RAS_CLASS, strlen(DEFAULT_RAS_CLASS) ); } DWORD DhcpRenewIpAddressLease( DWORD AdapterIpAddress, LPDHCP_LEASE_INFO ClientLeaseInfo, LPDHCP_OPTION_LIST OptionList, LPDHCP_OPTION_INFO *OptionInfo ) /*++ Routine Description: This api renews an ip address that the client already has. When a client gets an ip address, it can use the address until the lease expires. The client should stop using the ip address after that. Also the client should renew the address after T1 time if the client is planning to use the address longer than the current lease time. Arguments: AdapterIpAddress - IpAddress of the adapter. On a multi-homed machined this specifies the subnet from which an address is renewed. This value can be set to zero if the machine is non-multi-homed machine. ClientLeaseInfo : pointer to the client lease info structure. On entry the structure should contain the information that was returned by the DhcpLeaseIpAddress or DhcpRenewIpAddressLease apis. On return this structure is updated to reflect the lease extension. OptionList - list of option ids. OptionInfo - pointer to a location where the option info structure pointer is returned. The caller should free up this structure after use. Return Value: Windows Error. --*/ { return DhcpRenewIpAddressLeaseEx( AdapterIpAddress, ClientLeaseInfo, OptionList, OptionInfo, DEFAULT_RAS_CLASS, strlen(DEFAULT_RAS_CLASS) ); } DWORD DhcpReleaseIpAddressLease( DWORD AdapterIpAddress, LPDHCP_LEASE_INFO ClientLeaseInfo ) /*++ Routine Description: This function releases an ip address the client has. Arguments: AdapterIpAddress - IpAddress of the adapter. On a multi-homed machined this specifies the subnet to which an address is released. This value can be set to zero if the machine is non-multi-homed machine. ClientLeaseInfo : pointer to the client lease info structure. On entry the structure should contain the information that was returned by the DhcpLeaseIpAddress or DhcpRenewIpAddressLease apis. Return Value: Windows Error. --*/ { return DhcpReleaseIpAddressLeaseEx( AdapterIpAddress, ClientLeaseInfo, DEFAULT_RAS_CLASS, strlen(DEFAULT_RAS_CLASS) ); } //================================================================================ // end of file //================================================================================