/*++ BUILD Version: 0001 // Increment this if a change has global effects Copyright (c) 1992 Microsoft Corporation Module Name: perfatk.c Abstract: This file implements the Extensible Objects for the Appletalk object types Created: 10/11/93 Sue Adams (suea) Revision History 02/23/94 Sue Adams - No longer need to open registry key \AppleTalk\Performance to query FirstCounter and FirstHelp indices. These are now hardcoded as part of the base NT system. ATKOBJ = 1050, ATKOBJ_HELP = 1051, PKTDROPPED = 1096, PKTDROPPED_HELP = 1097 --*/ // // Include Files // #include #include #include #include #include #include #include #include #define GLOBAL extern #define EQU ; /##/ #define ATALK_SPIN_LOCK LONG #define PMDL PVOID #include #include #include #include "atkctrs.h" // error message definition #include "perfmsg.h" #include "perfutil.h" #include "dataatk.h" #include // // References to constants which initialize the Object type definitions // (see dataatk.h & .c) // #define MAX_PORTS 32 extern ATK_DATA_DEFINITION AtkDataDefinition; DWORD dwOpenCount = 0; // count of "Open" threads BOOL bInitOK = FALSE; // true = DLL initialized OK HANDLE AddressHandle = NULL; // handle to appletalk driver DWORD LengthOfInstanceNames = 0; // including padding to DWORD length int NumOfDevices = 0; // Number of appletalk ports with stats PATALK_STATS pAtalkStats; PATALK_PORT_STATS pAtalkPortStats; CHAR Buffer[ sizeof(ATALK_STATS) + sizeof(ATALK_PORT_STATS) * MAX_PORTS + sizeof(GET_STATISTICS_ACTION)]; PGET_STATISTICS_ACTION GetStats = (PGET_STATISTICS_ACTION)Buffer; // // Function Prototypes // PM_OPEN_PROC OpenAtkPerformanceData; PM_COLLECT_PROC CollectAtkPerformanceData; PM_CLOSE_PROC CloseAtkPerformanceData; DWORD OpenAtkPerformanceData( LPWSTR lpDeviceNames ) /*++ Routine Description: This routine will open the Appletalk driver and remember the handle returned to be used in subsequent Ioctls for performance data to the driver. Each device name exported by Appletalk will be mapped to an array index into the performance data arrays for all the ports handled by Appletalk. These indices will then be used in the collect routine to know which set of performance data belongs to which device. Arguments: Pointer to each device to be opened. Note that for Appletalk, we do not actually open each device (port), we only open one Tdi provider name to use when ioctling the driver for performance data on all ports. Return Value: None. --*/ { NTSTATUS Status = ERROR_SUCCESS; UNICODE_STRING DriverName; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES ObjectAttributes; LPWSTR lpLocalDeviceNames; int i; if (!dwOpenCount) { if ((lpLocalDeviceNames = lpDeviceNames) == NULL) return ERROR_INVALID_NAME; // There are no devices to query MonOpenEventLog(); // Open the Appletalk driver and obtain the device (port)/index // mappings for performance data table RtlInitUnicodeString(&DriverName, ATALKPAP_DEVICENAME); InitializeObjectAttributes ( &ObjectAttributes, &DriverName, 0, NULL, NULL); Status = NtCreateFile( &AddressHandle, GENERIC_READ | SYNCHRONIZE, // desired access. &ObjectAttributes, // object attributes. &IoStatusBlock, // returned status information. 0, // block size (unused). 0, // file attributes. FILE_SHARE_READ, // share access. FILE_OPEN, // create disposition. FILE_SYNCHRONOUS_IO_NONALERT, // create options. NULL, 0); if (!NT_SUCCESS(Status)) { REPORT_ERROR_DATA (ATK_OPEN_FILE_ERROR, LOG_USER, &IoStatusBlock, sizeof(IoStatusBlock)); return RtlNtStatusToDosError(Status); } // // Now make a NtDeviceIoControl file (corresponding to TdiAction) to // get the statistics - here we are only interested in the array // of device/port names // GetStats->ActionHeader.ActionCode = COMMON_ACTION_GETSTATISTICS; GetStats->ActionHeader.TransportId = MATK; Status = NtDeviceIoControlFile( AddressHandle, NULL, NULL, NULL, &IoStatusBlock, IOCTL_TDI_ACTION, NULL, 0, (PVOID)GetStats, sizeof(Buffer)); if (!NT_SUCCESS(Status)) { REPORT_ERROR_DATA (ATK_IOCTL_FILE_ERROR, LOG_DEBUG, &IoStatusBlock, sizeof(IoStatusBlock)); NtClose(AddressHandle); return RtlNtStatusToDosError(Status); } pAtalkStats = (PATALK_STATS)(Buffer + sizeof(GET_STATISTICS_ACTION)); pAtalkPortStats = (PATALK_PORT_STATS)( Buffer + sizeof(GET_STATISTICS_ACTION) + sizeof(ATALK_STATS)); NumOfDevices = pAtalkStats->stat_NumActivePorts; for (i = 0; i < NumOfDevices; i++, pAtalkPortStats ++) { LengthOfInstanceNames += DWORD_MULTIPLE((lstrlenW(pAtalkPortStats->prtst_PortName) * sizeof(WCHAR))); } bInitOK = TRUE; // ok to use this function } // end if dwOpenCount is zero (first opener) if (!NT_SUCCESS(Status)) { if (AddressHandle != NULL) { NtClose(AddressHandle); } return RtlNtStatusToDosError(Status); } else { dwOpenCount++; // increment OPEN counter REPORT_INFORMATION (ATK_OPEN_PERFORMANCE_DATA, LOG_DEBUG); } return Status; } DWORD CollectAtkPerformanceData( IN LPWSTR lpValueName, IN OUT LPVOID *lppData, IN OUT LPDWORD lpcbTotalBytes, IN OUT LPDWORD lpNumObjectTypes ) /*++ Routine Description: This routine will return the data for the AppleTalk counters. Arguments: IN LPWSTR lpValueName pointer to a wide character string passed by registry. IN OUT LPVOID *lppData IN: pointer to the address of the buffer to receive the completed PerfDataBlock and subordinate structures. This routine will append its data to the buffer starting at the point referenced by *lppData. OUT: points to the first byte after the data structure added by this routine. This routine updates the value at lppdata after appending its data. IN OUT LPDWORD lpcbTotalBytes IN: the address of the DWORD that tells the size in bytes of the buffer referenced by the lppData argument OUT: the number of bytes added by this routine is writted to the DWORD pointed to by this argument IN OUT LPDWORD NumObjectTypes IN: the address of the DWORD to receive the number of objects added by this routine OUT: the number of objects added by this routine is writted to the DWORD pointed to by this argument Return Value: ERROR_MORE_DATA if buffer passed is too small to hold data any error conditions encountered are reported to the event log if event logging is enabled. ERROR_SUCCESS if success or any other error. Errors, however are also reported to the event log. --*/ { // Variables for reformating the data ULONG SpaceNeeded; PDWORD pdwCounter; LARGE_INTEGER UNALIGNED *pliCounter; LARGE_INTEGER li1000; PERF_COUNTER_BLOCK *pPerfCounterBlock; ATK_DATA_DEFINITION *pAtkDataDefinition; PERF_INSTANCE_DEFINITION *pPerfInstanceDefinition; int i; UNICODE_STRING UCurDeviceName; // Variables for collecting the data from Appletalk NTSTATUS Status; IO_STATUS_BLOCK IoStatusBlock; DWORD dwQueryType; li1000.QuadPart = 1000; // // before doing anything else, see if Open went OK // if (!bInitOK) { // unable to continue because open failed. *lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ERROR_SUCCESS; // yes, this is a successful exit } if (lpValueName == NULL) { REPORT_INFORMATION (ATK_COLLECT_ENTERED, LOG_VERBOSE); } else { REPORT_INFORMATION_DATA (ATK_COLLECT_ENTERED, LOG_VERBOSE, lpValueName, (DWORD)(lstrlenW(lpValueName)*sizeof(WCHAR))); } // // see if this is a foreign (i.e. non-NT) computer data request // dwQueryType = GetQueryType (lpValueName); if ((dwQueryType == QUERY_COSTLY) || (dwQueryType == QUERY_FOREIGN)) { // ATK foreign data requests are not supported so bail out REPORT_INFORMATION (ATK_FOREIGN_DATA_REQUEST, LOG_VERBOSE); *lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ERROR_SUCCESS; } if (dwQueryType == QUERY_ITEMS){ if ( !(IsNumberInUnicodeList (AtkDataDefinition.AtkObjectType.ObjectNameTitleIndex, lpValueName))) { // request received for data object not provided by this routine REPORT_INFORMATION (ATK_UNSUPPORTED_ITEM_REQUEST, LOG_VERBOSE); *lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ERROR_SUCCESS; } } pAtkDataDefinition = (ATK_DATA_DEFINITION *) *lppData; // Compute space needed to hold AppleTalk performance Data SpaceNeeded = sizeof(ATK_DATA_DEFINITION) + (NumOfDevices * (SIZE_ATK_PERFORMANCE_DATA + sizeof(PERF_INSTANCE_DEFINITION))) + LengthOfInstanceNames; if ( *lpcbTotalBytes < SpaceNeeded ) { *lpcbTotalBytes = (DWORD) SpaceNeeded; *lpNumObjectTypes = (DWORD) 0; return ERROR_MORE_DATA; } // // Copy the (constant, initialized) Object Type and counter definitions // RtlMoveMemory(pAtkDataDefinition, &AtkDataDefinition, sizeof(ATK_DATA_DEFINITION)); // // Format and collect SFM data from IOCTL // GetStats->ActionHeader.ActionCode = COMMON_ACTION_GETSTATISTICS; GetStats->ActionHeader.TransportId = MATK; Status = NtDeviceIoControlFile( AddressHandle, NULL, NULL, NULL, &IoStatusBlock, IOCTL_TDI_ACTION, NULL, 0, (PVOID)GetStats, sizeof(Buffer)); if ((!NT_SUCCESS(Status)) || (!NT_SUCCESS(IoStatusBlock.Status))) { REPORT_ERROR_DATA (ATK_IOCTL_FILE_ERROR, LOG_DEBUG, &IoStatusBlock, sizeof(IoStatusBlock)); *lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ERROR_SUCCESS; } // The real statistics data starts after the TDI action header pAtalkStats = (ATALK_STATS *)(Buffer + sizeof(GET_STATISTICS_ACTION)); pAtalkPortStats = (PATALK_PORT_STATS)( Buffer + sizeof(GET_STATISTICS_ACTION) + sizeof(ATALK_STATS)); // // due to some PnP event, if one more adapter has come in, make adjustments! // if (pAtalkStats->stat_NumActivePorts > (DWORD)NumOfDevices) { NumOfDevices = pAtalkStats->stat_NumActivePorts; LengthOfInstanceNames = 0; for (i = 0; i < NumOfDevices; i++, pAtalkPortStats ++) { LengthOfInstanceNames += DWORD_MULTIPLE((lstrlenW(pAtalkPortStats->prtst_PortName) * sizeof(WCHAR))); } SpaceNeeded = sizeof(ATK_DATA_DEFINITION) + (NumOfDevices * (SIZE_ATK_PERFORMANCE_DATA + sizeof(PERF_INSTANCE_DEFINITION))) + LengthOfInstanceNames; if ( *lpcbTotalBytes < SpaceNeeded ) { *lpcbTotalBytes = (DWORD) SpaceNeeded; *lpNumObjectTypes = (DWORD) 0; return ERROR_MORE_DATA; } } // Now point to the location where the first instance definition will go pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)&pAtkDataDefinition[1]; for (i = 0; i < NumOfDevices; i++, pAtalkPortStats ++) { // // Format Appletalk statistics for each active port (instance) // RtlInitUnicodeString(&UCurDeviceName, pAtalkPortStats->prtst_PortName); MonBuildInstanceDefinition( pPerfInstanceDefinition, (PVOID *)&pPerfCounterBlock, 0, 0, i, &UCurDeviceName); pPerfCounterBlock->ByteLength = SIZE_ATK_PERFORMANCE_DATA; pdwCounter = (PDWORD) (&pPerfCounterBlock[1]); // Begin filling in the actual counter data *pdwCounter++ = pAtalkPortStats->prtst_NumPacketsIn; *pdwCounter++ = pAtalkPortStats->prtst_NumPacketsOut; pliCounter = (LARGE_INTEGER UNALIGNED *) pdwCounter; *pliCounter++ = pAtalkPortStats->prtst_DataIn; *pliCounter++ = pAtalkPortStats->prtst_DataOut; *pliCounter = pAtalkPortStats->prtst_DdpPacketInProcessTime; // convert this to 1msec time base pliCounter->QuadPart = li1000.QuadPart * (pliCounter->QuadPart/pAtalkStats->stat_PerfFreq.QuadPart); pdwCounter = (PDWORD) ++pliCounter; *pdwCounter++ = pAtalkPortStats->prtst_NumDdpPacketsIn; pliCounter = (LARGE_INTEGER UNALIGNED *) pdwCounter; *pliCounter = pAtalkPortStats->prtst_AarpPacketInProcessTime; // convert this to 1msec time base pliCounter->QuadPart = li1000.QuadPart * (pliCounter->QuadPart/pAtalkStats->stat_PerfFreq.QuadPart); pdwCounter = (PDWORD) ++pliCounter; *pdwCounter++ = pAtalkPortStats->prtst_NumAarpPacketsIn; pliCounter = (LARGE_INTEGER UNALIGNED *) pdwCounter; *pliCounter = pAtalkStats->stat_AtpPacketInProcessTime; // convert this to 1msec time base pliCounter->QuadPart = li1000.QuadPart * (pliCounter->QuadPart, pAtalkStats->stat_PerfFreq.QuadPart); pdwCounter = (PDWORD) ++pliCounter; *pdwCounter++ = pAtalkStats->stat_AtpNumPackets; *pdwCounter++ = pAtalkStats->stat_AtpNumRespTimeout; *pdwCounter++ = pAtalkStats->stat_AtpNumLocalRetries; *pdwCounter++ = pAtalkStats->stat_AtpNumRemoteRetries; *pdwCounter++ = pAtalkStats->stat_AtpNumXoResponse; *pdwCounter++ = pAtalkStats->stat_AtpNumAloResponse; *pdwCounter++ = pAtalkStats->stat_AtpNumRecdRelease; pliCounter = (LARGE_INTEGER UNALIGNED *) pdwCounter; *pliCounter = pAtalkPortStats->prtst_NbpPacketInProcessTime; // convert this to 1msec time base pliCounter->QuadPart = li1000.QuadPart * (pliCounter->QuadPart, pAtalkStats->stat_PerfFreq.QuadPart); pdwCounter = (PDWORD) ++pliCounter; *pdwCounter++ = pAtalkPortStats->prtst_NumNbpPacketsIn; pliCounter = (LARGE_INTEGER UNALIGNED *) pdwCounter; *pliCounter = pAtalkPortStats->prtst_ZipPacketInProcessTime; // convert this to 1msec time base pliCounter->QuadPart = li1000.QuadPart * (pliCounter->QuadPart, pAtalkStats->stat_PerfFreq.QuadPart); pdwCounter = (PDWORD) ++pliCounter; *pdwCounter++ = pAtalkPortStats->prtst_NumZipPacketsIn; pliCounter = (LARGE_INTEGER UNALIGNED *) pdwCounter; *pliCounter = pAtalkPortStats->prtst_RtmpPacketInProcessTime; // convert this to 1msec time base pliCounter->QuadPart = li1000.QuadPart * (pliCounter->QuadPart, pAtalkStats->stat_PerfFreq.QuadPart); pdwCounter = (PDWORD) ++pliCounter; *pdwCounter++ = pAtalkPortStats->prtst_NumRtmpPacketsIn; *pdwCounter++ = pAtalkStats->stat_CurAllocSize; *pdwCounter++ = pAtalkPortStats->prtst_NumPktRoutedIn; *pdwCounter++ = pAtalkPortStats->prtst_NumPktRoutedOut; *pdwCounter++ = pAtalkPortStats->prtst_NumPktDropped; pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *) ((PBYTE) pPerfCounterBlock + SIZE_ATK_PERFORMANCE_DATA); } pAtkDataDefinition->AtkObjectType.NumInstances = NumOfDevices; pAtkDataDefinition->AtkObjectType.TotalByteLength = (DWORD)((PBYTE) pdwCounter - (PBYTE) pAtkDataDefinition); *lppData = pdwCounter; *lpcbTotalBytes = (DWORD)((PBYTE) pdwCounter - (PBYTE) pAtkDataDefinition); *lpNumObjectTypes = 1; REPORT_INFORMATION (ATK_COLLECT_DATA, LOG_DEBUG); return ERROR_SUCCESS; } DWORD CloseAtkPerformanceData( ) /*++ Routine Description: This routine closes the open handles to Appletalk driver and eventlog. Arguments: None. Return Value: ERROR_SUCCESS --*/ { REPORT_INFORMATION (ATK_CLOSE_ENTERED, LOG_VERBOSE); if (!(--dwOpenCount)) { // when this is the last thread... NtClose(AddressHandle); MonCloseEventLog(); } return ERROR_SUCCESS; }