/*++ Copyright (c) 1994 Microsoft Corporation Module Name: dhcp.c Abstract: This file contains utility functions. Author: Madan Appiah (madana) 7-Dec-1993. Environment: User Mode - Win32 Revision History: --*/ #include "precomp.h" #include "dhcpglobal.h" #include #include #define MESSAGE_BOX_WIDTH_IN_CHARS 65 typedef struct _POPUP_THREAD_PARAM { LPWSTR Title; LPWSTR Message; ULONG Flags; } POPUP_THREAD_PARAM, *LPPOPUP_THREAD_PARAM; POPUP_THREAD_PARAM PopupThreadParam = { NULL, NULL, 0 }; DWORD DoPopup( PVOID Buffer ) /*++ Routine Description: This function pops up a message to the user. It must run it's own thread. When the user acknowledge the popup, the thread deallocates the message buffer and returns. Arguments: Buffer - A pointer to a NULL terminated message buffer. Return Values: Always returns 0 --*/ { DWORD Result; LPPOPUP_THREAD_PARAM Params = Buffer; Result = MessageBox( NULL, // no owner Params->Message, Params->Title, ( MB_OK | Params->Flags | MB_SERVICE_NOTIFICATION | MB_SYSTEMMODAL | MB_SETFOREGROUND | MB_DEFAULT_DESKTOP_ONLY ) ); LOCK_POPUP(); if( Params->Message != NULL ) { LocalFree( Params->Message ); Params->Message = NULL; } if( Params->Title != NULL ) { LocalFree( Params->Title ); Params->Title = NULL; } // // close the global handle, so that we will not consume this // thread resource until another popup. // CloseHandle( DhcpGlobalMsgPopupThreadHandle ); DhcpGlobalMsgPopupThreadHandle = NULL; UNLOCK_POPUP(); // // Always return 0 // return 0; } DWORD DisplayUserMessage( IN PDHCP_CONTEXT DhcpContext, IN DWORD MessageId, IN DHCP_IP_ADDRESS IpAddress ) /*++ Routine Description: This function starts a new thread to display a message box. N.B. If a thread already exists which is waiting for user input on a message box, then this routine does not create another thread. Arguments: DhcpContext -- the context to display messages for MessageId - The ID of the message to display. (The actual message string is obtained from the dhcp module). IpAddress - Ip address involved. --*/ { DWORD ThreadID, TitleLength, MsgLength, Flags; LPWSTR Title = NULL, Message = NULL; switch(MessageId) { case MESSAGE_FAILED_TO_OBTAIN_LEASE: Flags = MB_ICONSTOP; break; case MESSAGE_SUCCESSFUL_LEASE : Flags = MB_ICONINFORMATION; break; default: DhcpAssert(FALSE); Flags = MB_ICONSTOP; break; } LOCK_POPUP(); // // if we are asked to display no message popup, simply return. // if ( DhcpGlobalDisplayPopup == FALSE ) { goto Cleanup; } // // if the message popup thread handle is non-null, check to see // the thread is still running, if so don't display another popup, // otherwise close the last popup handle and create another popup // thread for new message. // if( DhcpGlobalMsgPopupThreadHandle != NULL ) { DWORD WaitStatus; // // Time out immediately if the thread is still running. // WaitStatus = WaitForSingleObject( DhcpGlobalMsgPopupThreadHandle, 0 ); if ( WaitStatus == WAIT_TIMEOUT ) { goto Cleanup; } else 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 )); goto Cleanup; } } MsgLength = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_ALLOCATE_BUFFER | MESSAGE_BOX_WIDTH_IN_CHARS, (LPVOID)DhcpGlobalMessageFileHandle, MessageId, 0, // language id. (LPWSTR)&Message, // return buffer place holder. 0, // minimum buffer size to allocate. NULL // No Params ); if ( MsgLength == 0) { DhcpPrint(( DEBUG_ERRORS, "FormatMessage failed, err = %ld.\n", GetLastError())); goto Cleanup; } DhcpAssert( Message != NULL ); DhcpAssert( (wcslen(Message)) == MsgLength ); // // get message box title. // TitleLength = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER, (LPVOID)DhcpGlobalMessageFileHandle, MESSAGE_POPUP_TITLE, 0, // language id. (LPWSTR)&Title, // return buffer place holder. 0, // minimum buffer size to allocate. NULL // insert strings. ); if ( TitleLength == 0) { DhcpPrint(( DEBUG_ERRORS, "FormatMessage to Message box Title failed, err = %ld.\n", GetLastError())); goto Cleanup; } DhcpAssert( Title != NULL ); DhcpAssert( (wcslen(Title)) == TitleLength ); PopupThreadParam.Title = Title; PopupThreadParam.Message = Message; PopupThreadParam.Flags = Flags; // // Create a thread, to display a message box to the user. We need // a new thread because MessageBox() blocks until the user clicks // on the OK button, and we can't block this thread. // // DoPopup frees the buffer. // DhcpGlobalMsgPopupThreadHandle = CreateThread( NULL, // no security. 0, // default stack size. DoPopup, // entry point. (PVOID)&PopupThreadParam, 0, &ThreadID ); if ( DhcpGlobalMsgPopupThreadHandle == NULL ) { DhcpPrint(( DEBUG_ERRORS, "DisplayUserMessage: Could not create thread, err = %ld.\n", GetLastError() )); } Cleanup: UNLOCK_POPUP(); return 0; } VOID DhcpLogEvent( IN PDHCP_CONTEXT DhcpContext, OPTIONAL IN DWORD EventNumber, IN DWORD ErrorCode OPTIONAL ) /*++ Routine Description: This functions formats and writes an event log entry. Arguments: DhcpContext - The context for the event. Optional parameter. EventNumber - The event to log. ErrorCode - Windows Error code to record. Optional parameter. --*/ { LPWSTR HWAddressBuffer = NULL; LPWSTR IPAddressBuffer = NULL; LPWSTR IPAddressBuffer2 = NULL; CHAR ErrorCodeOemStringBuf[32 + 1]; WCHAR ErrorCodeStringBuf[32 + 1]; LPWSTR ErrorCodeString = NULL; LPWSTR Strings[10]; DHCP_IP_ADDRESS IpAddr; if( DhcpContext != NULL ) { if( EVENT_NACK_LEASE == EventNumber ) { IpAddr = DhcpContext->NackedIpAddress; } if( EVENT_ADDRESS_CONFLICT == EventNumber ) { IpAddr = DhcpContext->ConflictAddress; } else { IpAddr = DhcpContext->IpAddress; } HWAddressBuffer = DhcpAllocateMemory( (DhcpContext->HardwareAddressLength * 2 + 1) * sizeof(WCHAR) ); if( HWAddressBuffer == NULL ) { DhcpPrint(( DEBUG_MISC, "Out of memory." )); goto Cleanup; } DhcpHexToString( HWAddressBuffer, DhcpContext->HardwareAddress, DhcpContext->HardwareAddressLength ); HWAddressBuffer[DhcpContext->HardwareAddressLength * 2] = '\0'; IPAddressBuffer = DhcpOemToUnicode( inet_ntoa( *(struct in_addr *)&IpAddr ), NULL ); if( IPAddressBuffer == NULL ) { DhcpPrint(( DEBUG_MISC, "Out of memory." )); goto Cleanup; } if( EVENT_NACK_LEASE == EventNumber ) { IPAddressBuffer2 = DhcpOemToUnicode( inet_ntoa( *(struct in_addr *)&DhcpContext->DhcpServerAddress ), NULL ); if( NULL == IPAddressBuffer2 ) goto Cleanup; } } strcpy( ErrorCodeOemStringBuf, "%%" ); _ultoa( ErrorCode, ErrorCodeOemStringBuf + 2, 10 ); ErrorCodeString = DhcpOemToUnicode( ErrorCodeOemStringBuf, ErrorCodeStringBuf ); // // Log an event // switch ( EventNumber ) { case EVENT_LEASE_TERMINATED: DhcpAssert( HWAddressBuffer != NULL ); DhcpAssert( IPAddressBuffer != NULL ); Strings[0] = HWAddressBuffer; Strings[1] = IPAddressBuffer; DhcpReportEventW( DHCP_EVENT_CLIENT, EVENT_LEASE_TERMINATED, EVENTLOG_ERROR_TYPE, 2, 0, Strings, NULL ); break; case EVENT_FAILED_TO_OBTAIN_LEASE: DhcpAssert( HWAddressBuffer != NULL ); DhcpAssert( ErrorCodeString != NULL ); Strings[0] = HWAddressBuffer; Strings[1] = ErrorCodeString; DhcpReportEventW( DHCP_EVENT_CLIENT, EVENT_FAILED_TO_OBTAIN_LEASE, EVENTLOG_ERROR_TYPE, 2, sizeof(ErrorCode), Strings, &ErrorCode ); break; case EVENT_NACK_LEASE: DhcpAssert( HWAddressBuffer != NULL ); DhcpAssert( IPAddressBuffer != NULL ); DhcpAssert( IPAddressBuffer2 != NULL ); Strings[0] = IPAddressBuffer; Strings[1] = HWAddressBuffer; Strings[2] = IPAddressBuffer2; DhcpReportEventW( DHCP_EVENT_CLIENT, EVENT_NACK_LEASE, EVENTLOG_ERROR_TYPE, 3, 0, Strings, NULL ); break; case EVENT_ADDRESS_CONFLICT: DhcpAssert( IPAddressBuffer != NULL ); DhcpAssert( HWAddressBuffer != NULL ); Strings[0] = IPAddressBuffer; Strings[1] = HWAddressBuffer; DhcpReportEventW( DHCP_EVENT_CLIENT, EVENT_ADDRESS_CONFLICT, EVENTLOG_WARNING_TYPE, 2, 0, Strings, NULL ); break; case EVENT_IPAUTOCONFIGURATION_FAILED: DhcpAssert( HWAddressBuffer != NULL ); DhcpAssert( ErrorCodeString != NULL ); Strings[0] = HWAddressBuffer; Strings[1] = ErrorCodeString; DhcpReportEventW( DHCP_EVENT_CLIENT, EVENT_IPAUTOCONFIGURATION_FAILED, EVENTLOG_WARNING_TYPE, 2, sizeof(ErrorCode), Strings, &ErrorCode ); break; case EVENT_FAILED_TO_RENEW: // The 'timeout' event should be logged only if there is no PPP // adapter up. It is so because having a PPP adapter means the // routes are hijacked, hence renewals up to T2 are expected to // fail. if (ErrorCode != ERROR_SEM_TIMEOUT || DhcpGlobalNdisWanAdaptersCount == 0 || time(NULL) >= DhcpContext->T2Time) { DhcpAssert( HWAddressBuffer != NULL ); DhcpAssert( ErrorCodeString != NULL ); Strings[0] = HWAddressBuffer; Strings[1] = ErrorCodeString; DhcpReportEventW( DHCP_EVENT_CLIENT, EVENT_FAILED_TO_RENEW, EVENTLOG_WARNING_TYPE, 2, sizeof(ErrorCode), Strings, &ErrorCode ); } break; case EVENT_DHCP_SHUTDOWN: DhcpAssert( ErrorCodeString != NULL ); Strings[0] = ErrorCodeString; DhcpReportEventW( DHCP_EVENT_CLIENT, EVENT_DHCP_SHUTDOWN, EVENTLOG_WARNING_TYPE, 1, sizeof(ErrorCode), Strings, &ErrorCode ); break; case EVENT_IPAUTOCONFIGURATION_SUCCEEDED : Strings[0] = HWAddressBuffer; Strings[1] = IPAddressBuffer; DhcpReportEventW( DHCP_EVENT_CLIENT, EVENT_IPAUTOCONFIGURATION_SUCCEEDED, EVENTLOG_WARNING_TYPE, 2, sizeof(ErrorCode), Strings, &ErrorCode ); break; case EVENT_COULD_NOT_INITIALISE_INTERFACE : DhcpAssert( NULL != ErrorCodeString); Strings[0] = ErrorCodeString; DhcpReportEventW( DHCP_EVENT_CLIENT, EVENT_COULD_NOT_INITIALISE_INTERFACE, EVENTLOG_ERROR_TYPE, 1, sizeof(ErrorCode), Strings, &ErrorCode ); break; case EVENT_NET_ERROR: DhcpAssert( NULL != ErrorCodeString); Strings[0] = ErrorCodeString; DhcpReportEventW( DHCP_EVENT_CLIENT, EVENT_NET_ERROR, EVENTLOG_WARNING_TYPE, 1, sizeof(ErrorCode), Strings, &ErrorCode ); break; default: DhcpPrint(( DEBUG_MISC, "Unknown event." )); break; } Cleanup: if( HWAddressBuffer != NULL ) { DhcpFreeMemory( HWAddressBuffer ); } if( IPAddressBuffer != NULL ) { DhcpFreeMemory( IPAddressBuffer ); } if( IPAddressBuffer2 != NULL ) { DhcpFreeMemory( IPAddressBuffer2 ); } } #if DBG VOID DhcpPrintRoutine( IN DWORD DebugFlag, IN LPSTR Format, ... ) { #define MAX_PRINTF_LEN 1024 // Arbitrary. va_list arglist; char OutputBuffer[MAX_PRINTF_LEN]; ULONG length; static BeginningOfLine = TRUE; LPSTR Text; // // If we aren't debugging this functionality, just return. // if ( DebugFlag != 0 && (DhcpGlobalDebugFlag & DebugFlag) == 0 ) { return; } // // vsprintf isn't multithreaded + we don't want to intermingle output // from different threads. // // EnterCriticalSection( &DhcpGlobalDebugFileCritSect ); length = 0; // // Handle the beginning of a new line. // // if ( BeginningOfLine ) { length += (ULONG) sprintf( &OutputBuffer[length], "[Dhcp] " ); // // Put the timestamp at the begining of the line. // IF_DEBUG( TIMESTAMP ) { SYSTEMTIME SystemTime; GetLocalTime( &SystemTime ); length += (ULONG) sprintf( &OutputBuffer[length], "%02u/%02u %02u:%02u:%02u ", SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond ); } // // Indicate the type of message on the line // switch (DebugFlag) { case DEBUG_ERRORS: Text = "ERRR"; break; case DEBUG_PROTOCOL: Text = "PROT"; break; case DEBUG_LEASE: Text = "LEAS"; break; case DEBUG_PROTOCOL_DUMP: Text = "DUMP"; break; case DEBUG_MISC: Text = "MISC"; break; default: Text = "DHCP"; break; } if ( Text != NULL ) { length += (ULONG) sprintf( &OutputBuffer[length], "[%s] ", Text ); } } // // Put a the information requested by the caller onto the line // va_start(arglist, Format); length += (ULONG) vsprintf(&OutputBuffer[length], Format, arglist); BeginningOfLine = (length > 0 && OutputBuffer[length-1] == '\n' ); va_end(arglist); DhcpAssert(length <= MAX_PRINTF_LEN); // // Output to the debug terminal, // if (NULL == DhcpGlobalDebugFile) { (void) DbgPrint( (PCH) OutputBuffer); } else { // // Note: other process can still write to the log file. This should be OK since // only the Dhcp client service is supposed to write to the log file. // EnterCriticalSection( &DhcpGlobalDebugFileCritSect ); SetFilePointer(DhcpGlobalDebugFile, 0, NULL, FILE_END); WriteFile(DhcpGlobalDebugFile, OutputBuffer, length, &length, NULL); LeaveCriticalSection( &DhcpGlobalDebugFileCritSect ); } // LeaveCriticalSection( &DhcpGlobalDebugFileCritSect ); } #endif // DBG PDHCP_CONTEXT FindDhcpContextOnNicList( IN LPCWSTR AdapterName, OPTIONAL IN DWORD InterfaceContext ) /*++ Routine Description: This function finds the DHCP_CONTEXT for the specified adapter name on the Nic list. This function must be called with LOCK_RENEW_LIST(). Arguments: AdapterName - name of the adapter. HardwareAddress - The hardware address to look for. Return Value: A pointer to the desired DHCP work context. NULL - If the specified work context block cannot be found. --*/ { PLIST_ENTRY listEntry; PDHCP_CONTEXT dhcpContext; PLOCAL_CONTEXT_INFO LocalInfo; listEntry = DhcpGlobalNICList.Flink; while ( listEntry != &DhcpGlobalNICList ) { dhcpContext = CONTAINING_RECORD( listEntry, DHCP_CONTEXT, NicListEntry ); LocalInfo = dhcpContext->LocalInformation; if ( AdapterName ) { if( _wcsicmp( LocalInfo->AdapterName, AdapterName ) == 0 ) { return( dhcpContext ); } } else { if( LocalInfo->IpInterfaceContext == InterfaceContext ) { return( dhcpContext ); } } listEntry = listEntry->Flink; } return( NULL ); } // // End of file //