/*++ Copyright (c) 1994 Microsoft Corporation Module Name: dhcp.c Abstract: This module contains DHCP specific utility routines used by the DHCP components. Author: Manny Weiser (mannyw) 12-Aug-1992 Revision History: Madan Appiah (madana) 21-Oct-1992 --*/ #include #include #include #include DWORD NTTimeToNTPTime(PULONG pTime, PFILETIME pft OPTIONAL); DWORD NTPTimeToNTFileTime(PLONG pTime, PFILETIME pft, BOOL bHostOrder); #undef DhcpAllocateMemory #undef DhcpFreeMemory PVOID DhcpAllocateMemory( DWORD Size ) /*++ Routine Description: This function allocates the required size of memory by calling LocalAlloc. Arguments: Size - size of the memory block required. Return Value: Pointer to the allocated block. --*/ { ASSERT( Size != 0 ); return( LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, Size ) ); } #undef DhcpFreeMemory VOID DhcpFreeMemory( PVOID Memory ) /*++ Routine Description: This function frees up the memory that was allocated by DhcpAllocateMemory. Arguments: Memory - pointer to the memory block that needs to be freed up. Return Value: none. --*/ { LPVOID Ptr; ASSERT( Memory != NULL ); Ptr = LocalFree( Memory ); ASSERT( Ptr == NULL ); } DATE_TIME DhcpCalculateTime( DWORD RelativeTime ) /*++ Routine Description: The function calculates the absolute time of a time RelativeTime seconds from now. Arguments: RelativeTime - Relative time, in seconds. Return Value: The time in RelativeTime seconds from the current system time. --*/ { SYSTEMTIME systemTime; ULONGLONG absoluteTime; if( RelativeTime == INFINIT_LEASE ) { ((DATE_TIME *)&absoluteTime)->dwLowDateTime = DHCP_DATE_TIME_INFINIT_LOW; ((DATE_TIME *)&absoluteTime)->dwHighDateTime = DHCP_DATE_TIME_INFINIT_HIGH; } else { GetSystemTime( &systemTime ); SystemTimeToFileTime( &systemTime, (FILETIME *)&absoluteTime ); absoluteTime = absoluteTime + RelativeTime * (ULONGLONG)10000000; } return( *(DATE_TIME *)&absoluteTime ); } DATE_TIME DhcpGetDateTime( VOID ) /*++ Routine Description: This function returns FILETIME. Arguments: none. Return Value: FILETIME. --*/ { SYSTEMTIME systemTime; DATE_TIME Time; GetSystemTime( &systemTime ); SystemTimeToFileTime( &systemTime, (FILETIME *)&Time ); return( Time ); } VOID DhcpNTToNTPTime( LPDATE_TIME AbsNTTime, DWORD Offset, PULONG NTPTimeStamp ) /*++ Routine Description: The function calculates the absolute NTP timestamp from AbsTime on NT added by given offset. Arguments: AbsNTTime - AbsTime on NT. If 0, it will use current time. RelativeOffset - offset to be added to AnsNTTime (in seconds.) Return Value: The time in RelativeTime seconds from the current system time. --*/ { ULONGLONG LocalAbsNTTime; DWORD Error; if ( AbsNTTime == 0 ) { GetSystemTimeAsFileTime((FILETIME *)&LocalAbsNTTime ); } else { LocalAbsNTTime = *(ULONGLONG *)AbsNTTime; } // add offset LocalAbsNTTime += Offset * (ULONGLONG)10000000; // now convert to NT timestamp Error = NTTimeToNTPTime( NTPTimeStamp, (PFILETIME)&LocalAbsNTTime ); DhcpAssert( ERROR_SUCCESS == Error ); return; } VOID DhcpNTPToNTTime( PULONG NTPTimeStamp, DWORD Offset, DATE_TIME *NTTime ) /*++ Routine Description: The function calculates the absolute NTP timestamp from AbsTime on NT added by given offset. Arguments: AbsNTTime - AbsTime on NT. If 0, it will use current time. RelativeOffset - offset to be added to AnsNTTime (in seconds.) Return Value: The time in RelativeTime seconds from the current system time. --*/ { ULONGLONG LocalAbsNTTime; DWORD Error; Error = NTPTimeToNTFileTime( NTPTimeStamp, (FILETIME *)&LocalAbsNTTime, FALSE // not in host order. ); DhcpAssert( ERROR_SUCCESS == Error ); // add offset LocalAbsNTTime += Offset * (ULONGLONG)10000000; // now convert to NT timestamp // MBUG *(ULONGLONG *)NTTime = LocalAbsNTTime; return; } DWORD DhcpReportEventW( LPWSTR Source, DWORD EventID, DWORD EventType, DWORD NumStrings, DWORD DataLength, LPWSTR *Strings, LPVOID Data ) /*++ Routine Description: This function writes the specified (EventID) log at the end of the eventlog. Arguments: Source - Points to a null-terminated string that specifies the name of the module referenced. The node must exist in the registration database, and the module name has the following format: \EventLog\System\Lanmanworkstation EventID - The specific event identifier. This identifies the message that goes with this event. EventType - Specifies the type of event being logged. This parameter can have one of the following values: Value Meaning EVENTLOG_ERROR_TYPE Error event EVENTLOG_WARNING_TYPE Warning event EVENTLOG_INFORMATION_TYPE Information event NumStrings - Specifies the number of strings that are in the array at 'Strings'. A value of zero indicates no strings are present. DataLength - Specifies the number of bytes of event-specific raw (binary) data to write to the log. If cbData is zero, no event-specific data is present. Strings - Points to a buffer containing an array of null-terminated strings that are merged into the message before displaying to the user. This parameter must be a valid pointer (or NULL), even if cStrings is zero. Data - Buffer containing the raw data. This parameter must be a valid pointer (or NULL), even if cbData is zero. Return Value: Returns the WIN32 extended error obtained by GetLastError(). NOTE : This function works slow since it calls the open and close eventlog source everytime. --*/ { HANDLE EventlogHandle; DWORD ReturnCode; // // open eventlog section. // EventlogHandle = RegisterEventSourceW( NULL, Source ); if (EventlogHandle == NULL) { ReturnCode = GetLastError(); goto Cleanup; } // // Log the error code specified // if( !ReportEventW( EventlogHandle, (WORD)EventType, 0, // event category EventID, NULL, (WORD)NumStrings, DataLength, Strings, Data ) ) { ReturnCode = GetLastError(); goto Cleanup; } ReturnCode = NO_ERROR; Cleanup: if( EventlogHandle != NULL ) { DeregisterEventSource(EventlogHandle); } return ReturnCode; } DWORD DhcpReportEventA( LPWSTR Source, DWORD EventID, DWORD EventType, DWORD NumStrings, DWORD DataLength, LPSTR *Strings, LPVOID Data ) /*++ Routine Description: This function writes the specified (EventID) log at the end of the eventlog. Arguments: Source - Points to a null-terminated string that specifies the name of the module referenced. The node must exist in the registration database, and the module name has the following format: \EventLog\System\Lanmanworkstation EventID - The specific event identifier. This identifies the message that goes with this event. EventType - Specifies the type of event being logged. This parameter can have one of the following values: Value Meaning EVENTLOG_ERROR_TYPE Error event EVENTLOG_WARNING_TYPE Warning event EVENTLOG_INFORMATION_TYPE Information event NumStrings - Specifies the number of strings that are in the array at 'Strings'. A value of zero indicates no strings are present. DataLength - Specifies the number of bytes of event-specific raw (binary) data to write to the log. If cbData is zero, no event-specific data is present. Strings - Points to a buffer containing an array of null-terminated strings that are merged into the message before displaying to the user. This parameter must be a valid pointer (or NULL), even if cStrings is zero. Data - Buffer containing the raw data. This parameter must be a valid pointer (or NULL), even if cbData is zero. Return Value: Returns the WIN32 extended error obtained by GetLastError(). NOTE : This function works slow since it calls the open and close eventlog source everytime. --*/ { HANDLE EventlogHandle; DWORD ReturnCode; // // open eventlog section. // EventlogHandle = RegisterEventSourceW( NULL, Source ); if (EventlogHandle == NULL) { ReturnCode = GetLastError(); goto Cleanup; } // // Log the error code specified // if( !ReportEventA( EventlogHandle, (WORD)EventType, 0, // event category EventID, NULL, (WORD)NumStrings, DataLength, Strings, Data ) ) { ReturnCode = GetLastError(); goto Cleanup; } ReturnCode = NO_ERROR; Cleanup: if( EventlogHandle != NULL ) { DeregisterEventSource(EventlogHandle); } return ReturnCode; } DWORD DhcpLogUnknownOption( LPWSTR Source, DWORD EventID, LPOPTION Option ) /*++ Routine Description: This routine logs an unknown DHCP option to event log. Arguments: Source - name of the app that logs this error. it should be either "DhcpClient" or "DhcpServer". EventID - Event identifier number. Option - pointer to the unknown option structure. Return Value: Windows Error code. --*/ { LPWSTR Strings[2]; WCHAR StringsBuffer[ 2 * (3 + 1) ]; // for two string each is 1byte decimal number (0 - 255). LPWSTR StringsPtr = StringsBuffer; // // convert option number. // Strings[0] = StringsPtr; DhcpDecimalToString( StringsPtr, Option->OptionType ); StringsPtr += 3; *StringsPtr++ = L'\0'; // // convert option length. // Strings[1] = StringsPtr; DhcpDecimalToString( StringsPtr, Option->OptionLength ); StringsPtr += 3; *StringsPtr++ = L'\0'; // // log error. // return( DhcpReportEventW( Source, EventID, EVENTLOG_WARNING_TYPE, 2, (DWORD)Option->OptionLength, Strings, (PVOID)Option->OptionValue ) ); } #if DBG VOID DhcpAssertFailed( LPSTR FailedAssertion, LPSTR FileName, DWORD LineNumber, LPSTR Message ) /*++ Routine Description: Assertion failed. Arguments: FailedAssertion : FileName : LineNumber : Message : Return Value: none. --*/ { #ifndef DHCP_NOASSERT RtlAssert( FailedAssertion, FileName, (ULONG) LineNumber, (PCHAR) Message); #endif DhcpPrint(( 0, "Assert @ %s \n", FailedAssertion )); DhcpPrint(( 0, "Assert Filename, %s \n", FileName )); DhcpPrint(( 0, "Line Num. = %ld.\n", LineNumber )); DhcpPrint(( 0, "Message is %s\n", Message )); } #endif LPWSTR DhcpRegIpAddressToKey( DHCP_IP_ADDRESS IpAddress, LPWSTR KeyBuffer ) /*++ Routine Description: This function converts an IpAddress to registry key. The registry key is unicode string of IpAddress in dotted form. Arguments: IpAddress : IpAddress that needs conversion. The IpAddress is in host order. KeyBuffer : pointer a buffer that will hold the converted registry key. The buffer should be big enough to converted key. Return Value: Pointer to the key the buffer. --*/ { LPSTR OemKey; LPWSTR UnicodeKey; DWORD NetworkOrderIpAddress; NetworkOrderIpAddress = htonl(IpAddress); OemKey = inet_ntoa( *(struct in_addr *)&NetworkOrderIpAddress ); UnicodeKey = DhcpOemToUnicode( OemKey, KeyBuffer ); DhcpAssert( UnicodeKey == KeyBuffer ); return( UnicodeKey ); } DHCP_IP_ADDRESS DhcpRegKeyToIpAddress( LPWSTR Key ) /*++ Routine Description: This function converts registry key to Ip Address. Arguments: Key : Pointer to registry key. Return Value: Converted IpAddress. --*/ { CHAR OemKeyBuffer[DHCP_IP_KEY_LEN]; LPSTR OemKey; OemKey = DhcpUnicodeToOem( Key, OemKeyBuffer ); DhcpAssert( OemKey == OemKeyBuffer ); return( ntohl(inet_addr( OemKey )) ); } LPWSTR DhcpRegOptionIdToKey( DHCP_OPTION_ID OptionId, LPWSTR KeyBuffer ) /*++ Routine Description: This function converts an OptionId to registry key. The registry key is unicode string of OptionId, 3 unicode char. long and of the form L"000". Arguments: IpAddress : IpAddress that needs conversion. KeyBuffer : pointer a buffer that will hold the converted registry key. The buffer should be at least 8 char. long. Return Value: Pointer to the key the buffer. --*/ { int i; for (i = 2; i >= 0; i--) { KeyBuffer[i] = L'0' + (BYTE)(OptionId % 10 ); OptionId /= 10; } KeyBuffer[3] = L'\0'; return( KeyBuffer ); } DHCP_OPTION_ID DhcpRegKeyToOptionId( LPWSTR Key ) /*++ Routine Description: This function converts registry key to OptionId. Arguments: Key : Pointer to registry key. Return Value: Converted OptionId. --*/ { DHCP_OPTION_ID OptionId = 0; int i; for (i = 0; i < 3 && Key[i] != L'\0'; i++) { OptionId = (OptionId * 10) + (Key[i] - L'0'); } return( OptionId ); } DWORD DhcpStartWaitableTimer( HANDLE TimerHandle, DWORD SleepTime) /*++ Routine Description: This routine starts the waitable timer. This timer fires off even when the system is in hibernate state. Arguments TimerHandle - Waitable Timer Handle SleepTime - Sleep Time in seconds. Return Value: Status of the operation. --*/ { DATE_TIME SleepTimeInNSec; // sleep time in nano seconds since Jan 1 1901 DWORD Error; BOOL Result; Error = STATUS_SUCCESS; SleepTimeInNSec = DhcpCalculateTime( SleepTime ); Result = SetWaitableTimer( TimerHandle, // handle to timer object (LARGE_INTEGER *)&SleepTimeInNSec, // due time. 0, // not periodic NULL, // completion routine NULL, // completion routine arg TRUE // resume power state when due ); if ( !Result ) { DhcpPrint((0, "SetWaitableTimer reported Error = %d\n",Error=GetLastError())); } return Error; } VOID DhcpCancelWaitableTimer( HANDLE TimerHandle ) /*++ Routine Description: This routine cancels the waitable timer. Arguments TimerHandle - Waitable Timer Handle Return Value: --*/ { BOOL Result; Result = CancelWaitableTimer( TimerHandle ); if ( !Result ) { DhcpPrint((0,"SetWaitableTimer reported Error = %lx\n",GetLastError())); } }