/*++ Copyright (c) 1992 Microsoft Corporation Module Name: errorlog.c Abstract: This module implements the error logging in the server. !!! This module must be nonpageable. Author: Manny Weiser (mannyw) 11-Feb-92 Revision History: --*/ #include "precomp.h" #pragma hdrstop // // Local procedure forwards // VOID BowserLogIllegalNameWorker( IN PVOID Ctx ); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, BowserWriteErrorLogEntry) #pragma alloc_text(PAGE, BowserLogIllegalNameWorker ) #endif ULONG BowserSequenceNumber = 0; //#pragma optimize("",off) VOID _cdecl BowserWriteErrorLogEntry( IN ULONG UniqueErrorCode, IN NTSTATUS NtStatusCode, IN PVOID ExtraInformationBuffer, IN USHORT ExtraInformationLength, IN USHORT NumberOfInsertionStrings, ... ) #define LAST_NAMED_ARGUMENT NumberOfInsertionStrings /*++ Routine Description: This function allocates an I/O error log record, fills it in and writes it to the I/O error log. Arguments: Return Value: None. --*/ { PIO_ERROR_LOG_PACKET ErrorLogEntry; int TotalErrorLogEntryLength; ULONG SizeOfStringData = 0; va_list ParmPtr; // Pointer to stack parms. ULONG Length; PAGED_CODE(); if (NumberOfInsertionStrings != 0) { ULONG i; va_start(ParmPtr, LAST_NAMED_ARGUMENT); for (i = 0; i < NumberOfInsertionStrings; i += 1) { PWSTR String = va_arg(ParmPtr, PWSTR); Length = wcslen(String); while ( (Length > 0) && (String[Length-1] == L' ') ) { Length--; } SizeOfStringData += (Length + 1) * sizeof(WCHAR); } } // // Ideally we want the packet to hold the servername and ExtraInformation. // Usually the ExtraInformation gets truncated. // TotalErrorLogEntryLength = min( ExtraInformationLength + sizeof(IO_ERROR_LOG_PACKET) + 1 + SizeOfStringData, ERROR_LOG_MAXIMUM_SIZE ); ErrorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( (PDEVICE_OBJECT)BowserDeviceObject, (UCHAR)TotalErrorLogEntryLength ); if (ErrorLogEntry != NULL) { PCHAR DumpData; ULONG RemainingSpace = TotalErrorLogEntryLength - FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData); ULONG i; ULONG SizeOfRawData; if (RemainingSpace > SizeOfStringData) { SizeOfRawData = RemainingSpace - SizeOfStringData; } else { SizeOfStringData = RemainingSpace; SizeOfRawData = 0; } // // Fill in the error log entry // ErrorLogEntry->ErrorCode = UniqueErrorCode; ErrorLogEntry->MajorFunctionCode = 0; ErrorLogEntry->RetryCount = 0; ErrorLogEntry->UniqueErrorValue = 0; ErrorLogEntry->FinalStatus = NtStatusCode; ErrorLogEntry->IoControlCode = 0; ErrorLogEntry->DeviceOffset.LowPart = 0; ErrorLogEntry->DeviceOffset.HighPart = 0; ErrorLogEntry->SequenceNumber = (ULONG)BowserSequenceNumber ++; ErrorLogEntry->StringOffset = (USHORT)(ROUND_UP_COUNT( FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData) + SizeOfRawData, ALIGN_WORD)); DumpData = (PCHAR)ErrorLogEntry->DumpData; // // Append the extra information. This information is typically // an SMB header. // if (( ARGUMENT_PRESENT( ExtraInformationBuffer )) && ( SizeOfRawData != 0 )) { ULONG Length; Length = min(ExtraInformationLength, (USHORT)SizeOfRawData); RtlCopyMemory( DumpData, ExtraInformationBuffer, Length); ErrorLogEntry->DumpDataSize = (USHORT)Length; } else { ErrorLogEntry->DumpDataSize = 0; } ErrorLogEntry->NumberOfStrings = 0; if (NumberOfInsertionStrings != 0) { PWSTR StringOffset = (PWSTR)((PCHAR)ErrorLogEntry + ErrorLogEntry->StringOffset); PWSTR InsertionString; // // Set up ParmPtr to point to first of the caller's parameters. // va_start(ParmPtr, LAST_NAMED_ARGUMENT); for (i = 0 ; i < NumberOfInsertionStrings ; i+= 1) { InsertionString = va_arg(ParmPtr, PWSTR); Length = wcslen(InsertionString); while ( (Length > 0) && (InsertionString[Length-1] == L' ') ) { Length--; } if ( ((Length + 1) * sizeof(WCHAR)) > SizeOfStringData ) { Length = (SizeOfStringData/sizeof(WCHAR))-1; } if ( Length > 0 ) { RtlCopyMemory(StringOffset, InsertionString, Length*sizeof(WCHAR)); StringOffset += Length; *StringOffset++ = L'\0'; SizeOfStringData -= (Length + 1) * sizeof(WCHAR); ErrorLogEntry->NumberOfStrings += 1; } } } IoWriteErrorLogEntry(ErrorLogEntry); } } typedef struct _ILLEGAL_NAME_CONTEXT { WORK_QUEUE_ITEM WorkItem; PTRANSPORT_NAME TransportName; NTSTATUS EventStatus; NTSTATUS NtStatusCode; USHORT BufferSize; UCHAR Buffer[1]; } ILLEGAL_NAME_CONTEXT, *PILLEGAL_NAME_CONTEXT; VOID BowserLogIllegalName( IN NTSTATUS NtStatusCode, IN PVOID NameBuffer, IN USHORT NameBufferSize ) { KIRQL OldIrql; NTSTATUS ErrorStatus = STATUS_SUCCESS; ACQUIRE_SPIN_LOCK(&BowserTimeSpinLock, &OldIrql); if (BowserIllegalNameCount > 0) { BowserIllegalNameCount -= 1; ErrorStatus = EVENT_BOWSER_NAME_CONVERSION_FAILED; } else if (!BowserIllegalNameThreshold) { BowserIllegalNameThreshold = TRUE; ErrorStatus = EVENT_BOWSER_NAME_CONVERSION_FAILED; } RELEASE_SPIN_LOCK(&BowserTimeSpinLock, OldIrql); if (ErrorStatus != STATUS_SUCCESS) { PILLEGAL_NAME_CONTEXT Context = NULL; Context = ALLOCATE_POOL(NonPagedPool, sizeof(ILLEGAL_NAME_CONTEXT)+NameBufferSize, POOL_ILLEGALDGRAM); if (Context != NULL) { Context->EventStatus = ErrorStatus; Context->NtStatusCode = NtStatusCode; Context->BufferSize = NameBufferSize; RtlCopyMemory( Context->Buffer, NameBuffer, NameBufferSize ); ExInitializeWorkItem(&Context->WorkItem, BowserLogIllegalNameWorker, Context); BowserQueueDelayedWorkItem( &Context->WorkItem ); } } } VOID BowserLogIllegalNameWorker( IN PVOID Ctx ) { PILLEGAL_NAME_CONTEXT Context = Ctx; NTSTATUS EventContext = Context->EventStatus; PAGED_CODE(); BowserWriteErrorLogEntry( Context->EventStatus, Context->NtStatusCode, Context->Buffer, Context->BufferSize, 0 ); FREE_POOL(Context); }