/*++ BUILD Version: 0001 // Increment this if a change has global effects Copyright (c) 1992 Microsoft Corporation Module Name: perfnbf.c Abstract: This file implements the Extensible Objects for the Nbf LAN object types This code originally existed for NetBEUI only. Later, it was adaped to handle Netrware protocol level NWNB, SPX, and IPX. The code was not everywhere changed to reflect this, due to the lateness of the change. Therefore, sometimes you will see NBF where you should see TDI. Created: Russ Blake 07/30/92 Revision History --*/ // // Include Files // #include #include #include #include #include #include #include #include #include #include #include "perfctr.h" // error message definition #include "perfmsg.h" #include "perfutil.h" #include "datanbf.h" // // References to constants which initialize the Object type definitions // extern NBF_DATA_DEFINITION NbfDataDefinition; extern NBF_RESOURCE_DATA_DEFINITION NbfResourceDataDefinition; // // TDI data structures // #define NBF_PROTOCOL 0 #define IPX_PROTOCOL 1 #define SPX_PROTOCOL 2 #define NWNB_PROTOCOL 3 #define NUMBER_OF_PROTOCOLS_HANDLED 4 typedef struct _TDI_DATA_DEFINITION { int NumberOfResources; HANDLE fileHandle; UNICODE_STRING DeviceName; } TDI_DATA_DEFINITION, *PTDI_DATA_DEFINITION; typedef struct _TDI_PROTOCOLS_DATA { int NumOfDevices; int MaxDeviceName; int MaxNumOfResources; PTDI_DATA_DEFINITION pTDIData; } TDI_PROTOCOLS_DATA; TDI_PROTOCOLS_DATA TDITbl[NUMBER_OF_PROTOCOLS_HANDLED]; DWORD ObjectNameTitleIndices[NUMBER_OF_PROTOCOLS_HANDLED] = { 492, 488, 490, 398 }; // // NBF data structures // ULONG ProviderStatsLength; // Resource-dependent size PTDI_PROVIDER_STATISTICS ProviderStats = NULL; // Provider statistics // // NetBUEI Resource Instance Names // WCHAR *NetResourceName[] = { L"Link(11)", L"Address(12)", L"Address File(13)", L"Connection(14)", L"Request(15)", L"UI Frame(21)", L"Packet(22)", L"Receive Packet(23)", L"Receive Buffer(24)" }; #define NUMBER_OF_NAMES sizeof(NetResourceName)/sizeof(NetResourceName[0]) #define MAX_NBF_RESOURCE_NAME_LENGTH 20 // // Function Prototypes // PM_OPEN_PROC OpenNbfPerformanceData; PM_COLLECT_PROC CollectNbfPerformanceData; PM_CLOSE_PROC CloseNbfPerformanceData; PM_OPEN_PROC OpenIPXPerformanceData; PM_COLLECT_PROC CollectIPXPerformanceData; PM_CLOSE_PROC CloseIPXPerformanceData; PM_OPEN_PROC OpenSPXPerformanceData; PM_COLLECT_PROC CollectSPXPerformanceData; PM_CLOSE_PROC CloseSPXPerformanceData; PM_OPEN_PROC OpenNWNBPerformanceData; PM_COLLECT_PROC CollectNWNBPerformanceData; PM_CLOSE_PROC CloseNWNBPerformanceData; DWORD OpenTDIPerformanceData(LPWSTR lpDeviceNames, DWORD CurrentProtocol); DWORD CollectTDIPerformanceData(IN LPWSTR lpValueName, IN OUT LPVOID *lppData, IN OUT LPDWORD lpcbTotalBytes, IN OUT LPDWORD lpNumObjectTypes, IN DWORD CurrentProtocol); DWORD CloseTDIPerformanceData(DWORD CurrentProtocol); DWORD OpenNbfPerformanceData( LPWSTR lpDeviceNames ) /*++ Routine Description: This routine will open each device and remember the handle that the device returns. Arguments: Pointer to each device to be opened Return Value: None. --*/ { return OpenTDIPerformanceData(lpDeviceNames, NBF_PROTOCOL); } DWORD OpenIPXPerformanceData( LPWSTR lpDeviceNames ) /*++ Routine Description: This routine will open each device and remember the handle that the device returns. Arguments: Pointer to each device to be opened Return Value: None. --*/ { return OpenTDIPerformanceData(lpDeviceNames, IPX_PROTOCOL); } DWORD OpenSPXPerformanceData( LPWSTR lpDeviceNames ) /*++ Routine Description: This routine will open each device and remember the handle that the device returns. Arguments: Pointer to each device to be opened Return Value: None. --*/ { DWORD dwStatus; dwStatus = OpenTDIPerformanceData(lpDeviceNames, SPX_PROTOCOL); if (dwStatus == ERROR_FILE_NOT_FOUND) { // no devices is not really an error, even though no counters // will be collected, this presents a much less alarming // message to the user. REPORT_WARNING (SPX_NO_DEVICE, LOG_USER); dwStatus = ERROR_SUCCESS; } return dwStatus; } DWORD OpenNWNBPerformanceData( LPWSTR lpDeviceNames ) /*++ Routine Description: This routine will open each device and remember the handle that the device returns. Arguments: Pointer to each device to be opened Return Value: None. --*/ { return OpenTDIPerformanceData(lpDeviceNames, NWNB_PROTOCOL); } void CleanUpTDIData ( DWORD CurrentProtocol ) /*++ Routine Description: This routine will celanup all the memory allocated for the CurrentProtocol Arguments: IN DWORD CurrentProtocol this is the index of the protocol for which we are currently gathering statistics Return Value: None. --*/ { int NumOfDevices; int i; PTDI_DATA_DEFINITION pTDIData; pTDIData = TDITbl[CurrentProtocol].pTDIData; if (pTDIData == NULL) // nothing to cleanup return; NumOfDevices = TDITbl[CurrentProtocol].NumOfDevices; for (i=0; i < NumOfDevices; i++, pTDIData++) { if (pTDIData->DeviceName.Buffer) { RtlFreeHeap(RtlProcessHeap(), 0, pTDIData->DeviceName.Buffer); } if (pTDIData->fileHandle) { NtClose (pTDIData->fileHandle); } } RtlFreeHeap(RtlProcessHeap(), 0, TDITbl[CurrentProtocol].pTDIData); TDITbl[CurrentProtocol].pTDIData = NULL; } DWORD OpenTDIPerformanceData( LPWSTR lpDeviceNames, DWORD CurrentProtocol ) /*++ Routine Description: This routine will open each device and remember the handle that the device returns. Arguments: IN LPWSTR lpDeviceNames pointer to each device to be opened IN DWORD CurrentProtocol this is the index of the protocol for which we are currently gathering statistics Return Value: None. --*/ { NTSTATUS Status; UNICODE_STRING FileString; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES ObjectAttributes; TDI_REQUEST_USER_QUERY_INFO QueryInfo; HANDLE fileHandle; LPWSTR lpLocalDeviceNames; int NumOfDevices; LPWSTR lpSaveDeviceName; PTDI_DATA_DEFINITION pTemp; PTDI_PROVIDER_INFO ProviderInfo=NULL; MonOpenEventLog(); lpLocalDeviceNames = lpDeviceNames; TDITbl[CurrentProtocol].MaxDeviceName = 0; NumOfDevices = TDITbl[CurrentProtocol].NumOfDevices = 0; TDITbl[CurrentProtocol].pTDIData = NULL; while (TRUE) { if (lpLocalDeviceNames == NULL || *lpLocalDeviceNames == L'\0') { break; } REPORT_INFORMATION_DATA (TDI_OPEN_ENTERED, LOG_VERBOSE, lpLocalDeviceNames, (lstrlenW(lpLocalDeviceNames) * sizeof(WCHAR))); RtlInitUnicodeString (&FileString, lpLocalDeviceNames); lpSaveDeviceName = RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, sizeof (WCHAR) * (lstrlenW(lpLocalDeviceNames) + 1)); if (!lpSaveDeviceName) { REPORT_ERROR (TDI_PROVIDER_STATS_MEMORY, LOG_USER); if (NumOfDevices == 0) return ERROR_OUTOFMEMORY; else break; } InitializeObjectAttributes( &ObjectAttributes, &FileString, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile( &fileHandle, SYNCHRONIZE | FILE_READ_DATA, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_ALERT); if (!NT_SUCCESS(Status)) { RtlFreeHeap(RtlProcessHeap(), 0, lpSaveDeviceName); REPORT_ERROR_DATA (TDI_OPEN_FILE_ERROR, LOG_DEBUG, lpLocalDeviceNames, (lstrlenW(lpLocalDeviceNames) * sizeof(WCHAR))); REPORT_ERROR_DATA (TDI_OPEN_FILE_ERROR, LOG_DEBUG, &IoStatusBlock, sizeof(IoStatusBlock)); if (NumOfDevices == 0) { return RtlNtStatusToDosError(Status); } else { break; } } if (NumOfDevices == 0) { // allocate memory to hold the device data TDITbl[CurrentProtocol].pTDIData = RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TDI_DATA_DEFINITION)); if (TDITbl[CurrentProtocol].pTDIData == NULL) { REPORT_ERROR (TDI_PROVIDER_STATS_MEMORY, LOG_DEBUG); NtClose(fileHandle); RtlFreeHeap(RtlProcessHeap(), 0, lpSaveDeviceName); return ERROR_OUTOFMEMORY; } } else { // resize to hold multiple devices pTemp = RtlReAllocateHeap(RtlProcessHeap(), 0, TDITbl[CurrentProtocol].pTDIData, sizeof(TDI_DATA_DEFINITION) * (NumOfDevices + 1)); if (pTemp == NULL) { NtClose(fileHandle); RtlFreeHeap(RtlProcessHeap(), 0, lpSaveDeviceName); REPORT_ERROR (TDI_PROVIDER_STATS_MEMORY, LOG_USER); break; } else { TDITbl[CurrentProtocol].pTDIData = pTemp; } } // build the TDI Data structure for this device instance TDITbl[CurrentProtocol].pTDIData[NumOfDevices].fileHandle = fileHandle; TDITbl[CurrentProtocol].pTDIData[NumOfDevices].DeviceName.MaximumLength = sizeof (WCHAR) * (lstrlenW(lpLocalDeviceNames) + 1); TDITbl[CurrentProtocol].pTDIData[NumOfDevices].DeviceName.Length = TDITbl[CurrentProtocol].pTDIData[NumOfDevices].DeviceName.Length - sizeof(WCHAR); TDITbl[CurrentProtocol].pTDIData[NumOfDevices].DeviceName.Buffer = lpSaveDeviceName; RtlCopyUnicodeString ( &(TDITbl[CurrentProtocol].pTDIData[NumOfDevices].DeviceName), &FileString); if (TDITbl[CurrentProtocol].pTDIData[NumOfDevices].DeviceName.MaximumLength > TDITbl[CurrentProtocol].MaxDeviceName) { TDITbl[CurrentProtocol].MaxDeviceName = TDITbl[CurrentProtocol].pTDIData[NumOfDevices].DeviceName.MaximumLength; } // now increment NumOfDevices NumOfDevices++; TDITbl[CurrentProtocol].NumOfDevices = NumOfDevices; // increment to the next device string lpLocalDeviceNames += lstrlenW(lpLocalDeviceNames) + 1; } REPORT_INFORMATION (TDI_OPEN_FILE_SUCCESS, LOG_VERBOSE); if (TDITbl[CurrentProtocol].NumOfDevices == 0) { return ERROR_SUCCESS; } // // The following common buffer is used by all protocols. NBF // is bigger because of resource data returned. // if (ProviderStats == NULL && CurrentProtocol != NBF_PROTOCOL) { ProviderStatsLength = sizeof(TDI_PROVIDER_STATISTICS); ProviderStats = RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, ProviderStatsLength); if (ProviderStats == NULL) { REPORT_ERROR (TDI_PROVIDER_STATS_MEMORY, LOG_USER); CleanUpTDIData(CurrentProtocol); return ERROR_OUTOFMEMORY; } } if (CurrentProtocol == NBF_PROTOCOL) { // // Query provider info to get resource count. // ProviderInfo = RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TDI_PROVIDER_INFO)); if ( ProviderInfo == NULL ) { REPORT_ERROR (TDI_PROVIDER_INFO_MEMORY, LOG_USER); CleanUpTDIData(CurrentProtocol); return ERROR_OUTOFMEMORY; } QueryInfo.QueryType = TDI_QUERY_PROVIDER_INFO; pTemp = TDITbl[CurrentProtocol].pTDIData; TDITbl[CurrentProtocol].MaxNumOfResources = 0; for (NumOfDevices = 0; NumOfDevices < TDITbl[CurrentProtocol].NumOfDevices; NumOfDevices++, pTemp++) { // loop thru all the devices to see if they can be opened // if one of them fails, then stop the whole thing. // we should probably save the good ones but... Status = NtDeviceIoControlFile( pTemp->fileHandle, NULL, NULL, NULL, &IoStatusBlock, IOCTL_TDI_QUERY_INFORMATION, (PVOID)&QueryInfo, sizeof(TDI_REQUEST_USER_QUERY_INFO), (PVOID)ProviderInfo, sizeof(TDI_PROVIDER_INFO)); pTemp->NumberOfResources = ProviderInfo->NumberOfResources; if ((int)ProviderInfo->NumberOfResources > TDITbl[CurrentProtocol].MaxNumOfResources) { TDITbl[CurrentProtocol].MaxNumOfResources = ProviderInfo->NumberOfResources; } if (!NT_SUCCESS(Status)) { RtlFreeHeap(RtlProcessHeap(), 0, ProviderInfo); REPORT_ERROR (TDI_UNABLE_READ_DEVICE, LOG_DEBUG); REPORT_ERROR_DATA (TDI_IOCTL_FILE_ERROR, LOG_DEBUG, &IoStatusBlock, sizeof(IoStatusBlock)); CleanUpTDIData(CurrentProtocol); return RtlNtStatusToDosError(Status); } } REPORT_INFORMATION (TDI_IOCTL_FILE, LOG_VERBOSE); ProviderStatsLength = sizeof(TDI_PROVIDER_STATISTICS) + (TDITbl[CurrentProtocol].MaxNumOfResources * sizeof(TDI_PROVIDER_RESOURCE_STATS)); // // Buffer may have been allocated smaller by other protocol. // if (ProviderStats != NULL) { RtlFreeHeap(RtlProcessHeap(), 0, ProviderStats); } ProviderStats = RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, ProviderStatsLength); if (ProviderStats == NULL) { REPORT_ERROR (TDI_PROVIDER_STATS_MEMORY, LOG_USER); RtlFreeHeap(RtlProcessHeap(), 0, ProviderInfo); CleanUpTDIData(CurrentProtocol); return ERROR_OUTOFMEMORY; } } if (ProviderInfo) { RtlFreeHeap(RtlProcessHeap(), 0, ProviderInfo); } REPORT_INFORMATION (TDI_OPEN_PERFORMANCE_DATA, LOG_DEBUG); return ERROR_SUCCESS; } DWORD CollectNbfPerformanceData( 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 Nbf 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 updated 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. --*/ { return CollectTDIPerformanceData(lpValueName, lppData, lpcbTotalBytes, lpNumObjectTypes, NBF_PROTOCOL); } DWORD CollectIPXPerformanceData( 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 IPX 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 updated 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. --*/ { return CollectTDIPerformanceData(lpValueName, lppData, lpcbTotalBytes, lpNumObjectTypes, IPX_PROTOCOL); } DWORD CollectSPXPerformanceData( 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 SPX 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 updated 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. --*/ { return CollectTDIPerformanceData(lpValueName, lppData, lpcbTotalBytes, lpNumObjectTypes, SPX_PROTOCOL); } DWORD CollectNWNBPerformanceData( 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 NWNB 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 updated 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. --*/ { return CollectTDIPerformanceData(lpValueName, lppData, lpcbTotalBytes, lpNumObjectTypes, NWNB_PROTOCOL); } DWORD CollectTDIPerformanceData( IN LPWSTR lpValueName, IN OUT LPVOID *lppData, IN OUT LPDWORD lpcbTotalBytes, IN OUT LPDWORD lpNumObjectTypes, IN DWORD CurrentProtocol ) /*++ Routine Description: This routine will return the data for the TDI 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 updated 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 IN DWORD CurrentProtocol this is the index of the protocol for which we are currently gathering statistics 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 UNALIGNED *pliFrameBytes; LARGE_INTEGER UNALIGNED *pliDatagramBytes; PERF_COUNTER_BLOCK *pPerfCounterBlock; NBF_DATA_DEFINITION *pNbfDataDefinition; NBF_RESOURCE_DATA_DEFINITION *pNbfResourceDataDefinition; // Variables for collecting the data from Nbf NTSTATUS Status; IO_STATUS_BLOCK IoStatusBlock; PERF_INSTANCE_DEFINITION *pPerfInstanceDefinition; TDI_REQUEST_USER_QUERY_INFO QueryInfo; // Variables for collecting data about Nbf Resouces int NumResource; ULONG ResourceSpace; UNICODE_STRING ResourceName; WCHAR ResourceNameBuffer[MAX_NBF_RESOURCE_NAME_LENGTH + 1]; INT NumOfDevices; PTDI_DATA_DEFINITION pTDIData; INT i; INT TotalNumberOfResources; // variables used for error logging DWORD dwDataReturn[2]; DWORD dwQueryType; if (lpValueName == NULL) { REPORT_INFORMATION (TDI_COLLECT_ENTERED, LOG_VERBOSE); } else { REPORT_INFORMATION_DATA (TDI_COLLECT_ENTERED, LOG_VERBOSE, lpValueName, (DWORD)(lstrlenW(lpValueName)*sizeof(WCHAR))); } // // before doing anything else, // see if this is a foreign (i.e. non-NT) computer data request // dwQueryType = GetQueryType (lpValueName); if ((dwQueryType == QUERY_COSTLY) || (dwQueryType == QUERY_FOREIGN)) { // NBF foriegn data requests are not supported so bail out REPORT_INFORMATION (TDI_FOREIGN_DATA_REQUEST, LOG_VERBOSE); *lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ERROR_SUCCESS; } if (dwQueryType == QUERY_ITEMS){ if (CurrentProtocol == NBF_PROTOCOL) { if ( !(IsNumberInUnicodeList (ObjectNameTitleIndices[CurrentProtocol], lpValueName)) && !(IsNumberInUnicodeList (NBF_RESOURCE_OBJECT_TITLE_INDEX, lpValueName))) { // request received for objects not provided by NBF REPORT_INFORMATION (TDI_UNSUPPORTED_ITEM_REQUEST, LOG_VERBOSE); *lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ERROR_SUCCESS; } } // NBF_PROTOCOL else if ( !(IsNumberInUnicodeList (ObjectNameTitleIndices[CurrentProtocol], lpValueName))) { // request received for objects not provided by this protocol REPORT_INFORMATION (TDI_UNSUPPORTED_ITEM_REQUEST, LOG_VERBOSE); *lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ERROR_SUCCESS; } // other protocol } // dwQueryType == QUERY_ITEMS // if no NBF devices were opened, in the OPEN routine, then // leave now. if (TDITbl[CurrentProtocol].pTDIData == NULL) { REPORT_WARNING (TDI_NULL_HANDLE, LOG_DEBUG); *lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ERROR_SUCCESS; } pNbfDataDefinition = (NBF_DATA_DEFINITION *) *lppData; pTDIData = TDITbl[CurrentProtocol].pTDIData; NumOfDevices = TDITbl[CurrentProtocol].NumOfDevices; // Compute space needed to hold Nbf Resource Data if (CurrentProtocol != NBF_PROTOCOL) { ResourceSpace = 0; } else { ResourceSpace = sizeof(NBF_RESOURCE_DATA_DEFINITION) + (TDITbl[CurrentProtocol].MaxNumOfResources * (sizeof(PERF_INSTANCE_DEFINITION) + DWORD_MULTIPLE( (MAX_NBF_RESOURCE_NAME_LENGTH * sizeof(WCHAR)) + sizeof(UNICODE_NULL)) + SIZE_OF_NBF_RESOURCE_DATA)); ResourceSpace *= NumOfDevices; } SpaceNeeded = sizeof(NBF_DATA_DEFINITION) + SIZE_OF_NBF_DATA + ResourceSpace; // now add in the per instance NBF data SpaceNeeded += NumOfDevices * (SIZE_OF_NBF_DATA + sizeof(PERF_INSTANCE_DEFINITION) + DWORD_MULTIPLE( (TDITbl[CurrentProtocol].MaxDeviceName * sizeof(WCHAR)) + sizeof(UNICODE_NULL))); if ( *lpcbTotalBytes < SpaceNeeded ) { dwDataReturn[0] = *lpcbTotalBytes; dwDataReturn[1] = SpaceNeeded; REPORT_WARNING_DATA (TDI_DATA_BUFFER_SIZE_ERROR, LOG_DEBUG, &dwDataReturn, sizeof(dwDataReturn)); *lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ERROR_MORE_DATA; } REPORT_INFORMATION (TDI_DATA_BUFFER_SIZE_SUCCESS, LOG_VERBOSE); // // Copy the (constant, initialized) Object Type and counter definitions // RtlMoveMemory(pNbfDataDefinition, &NbfDataDefinition, sizeof(NBF_DATA_DEFINITION)); pNbfDataDefinition->NbfObjectType.ObjectNameTitleIndex = ObjectNameTitleIndices[CurrentProtocol]; pNbfDataDefinition->NbfObjectType.ObjectHelpTitleIndex = ObjectNameTitleIndices[CurrentProtocol] + 1; pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *) &pNbfDataDefinition[1]; for (i=0; i < NumOfDevices; i++, pTDIData++) { // // Format and collect Nbf data // QueryInfo.QueryType = TDI_QUERY_PROVIDER_STATISTICS; Status = NtDeviceIoControlFile( pTDIData->fileHandle, NULL, NULL, NULL, &IoStatusBlock, IOCTL_TDI_QUERY_INFORMATION, (PVOID)&QueryInfo, sizeof(TDI_REQUEST_USER_QUERY_INFO), (PVOID)ProviderStats, ProviderStatsLength); if (Status != STATUS_SUCCESS) { REPORT_ERROR (TDI_UNABLE_READ_DEVICE, LOG_DEBUG); REPORT_ERROR_DATA (TDI_QUERY_INFO_ERROR, LOG_DEBUG, &IoStatusBlock, sizeof (IoStatusBlock)); *lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ERROR_SUCCESS; } REPORT_INFORMATION (TDI_QUERY_INFO_SUCCESS, LOG_DEBUG); MonBuildInstanceDefinition( pPerfInstanceDefinition, (PVOID *)&pPerfCounterBlock, 0, 0, i, &(pTDIData->DeviceName)); pPerfCounterBlock->ByteLength = SIZE_OF_NBF_DATA; pdwCounter = (PDWORD) (&pPerfCounterBlock[1]); *pdwCounter = ProviderStats->DatagramsSent + ProviderStats->DatagramsReceived; pliCounter = (LARGE_INTEGER UNALIGNED *) ++pdwCounter; pliDatagramBytes = pliCounter; pliCounter->QuadPart = ProviderStats->DatagramBytesSent.QuadPart + ProviderStats->DatagramBytesReceived.QuadPart; pdwCounter = (PDWORD) ++pliCounter; *pdwCounter = ProviderStats->PacketsSent + ProviderStats->PacketsReceived; *++pdwCounter = ProviderStats->DataFramesSent + ProviderStats->DataFramesReceived; pliCounter = (LARGE_INTEGER UNALIGNED *) ++pdwCounter; pliFrameBytes = pliCounter; pliCounter->QuadPart = ProviderStats->DataFrameBytesSent.QuadPart + ProviderStats->DataFrameBytesReceived.QuadPart; // Get the Bytes Total/sec which is the sum of Frame Byte /sec // and Datagram byte/sec ++pliCounter; pliCounter->QuadPart = pliDatagramBytes->QuadPart + pliFrameBytes->QuadPart; // // Get the TDI raw data. // pdwCounter = (PDWORD) ++pliCounter; *pdwCounter = ProviderStats->OpenConnections; *++pdwCounter = ProviderStats->ConnectionsAfterNoRetry; *++pdwCounter = ProviderStats->ConnectionsAfterRetry; *++pdwCounter = ProviderStats->LocalDisconnects; *++pdwCounter = ProviderStats->RemoteDisconnects; *++pdwCounter = ProviderStats->LinkFailures; *++pdwCounter = ProviderStats->AdapterFailures; *++pdwCounter = ProviderStats->SessionTimeouts; *++pdwCounter = ProviderStats->CancelledConnections; *++pdwCounter = ProviderStats->RemoteResourceFailures; *++pdwCounter = ProviderStats->LocalResourceFailures; *++pdwCounter = ProviderStats->NotFoundFailures; *++pdwCounter = ProviderStats->NoListenFailures; *++pdwCounter = ProviderStats->DatagramsSent; pliCounter = (LARGE_INTEGER UNALIGNED *) ++pdwCounter; *pliCounter = ProviderStats->DatagramBytesSent; pdwCounter = (PDWORD) ++pliCounter; *pdwCounter = ProviderStats->DatagramsReceived; pliCounter = (LARGE_INTEGER UNALIGNED *) ++pdwCounter; *pliCounter = ProviderStats->DatagramBytesReceived; pdwCounter = (PDWORD) ++pliCounter; *pdwCounter = ProviderStats->PacketsSent; *++pdwCounter = ProviderStats->PacketsReceived; *++pdwCounter = ProviderStats->DataFramesSent; pliCounter = (LARGE_INTEGER UNALIGNED *) ++pdwCounter; *pliCounter = ProviderStats->DataFrameBytesSent; pdwCounter = (PDWORD) ++pliCounter; *pdwCounter = ProviderStats->DataFramesReceived; pliCounter = (LARGE_INTEGER UNALIGNED *) ++pdwCounter; *pliCounter = ProviderStats->DataFrameBytesReceived; pdwCounter = (PDWORD) ++pliCounter; *pdwCounter = ProviderStats->DataFramesResent; pliCounter = (LARGE_INTEGER UNALIGNED *) ++pdwCounter; *pliCounter = ProviderStats->DataFrameBytesResent; pdwCounter = (PDWORD) ++pliCounter; *pdwCounter = ProviderStats->DataFramesRejected; pliCounter = (LARGE_INTEGER UNALIGNED *) ++pdwCounter; *pliCounter = ProviderStats->DataFrameBytesRejected; pdwCounter = (PDWORD) ++pliCounter; *pdwCounter = ProviderStats->ResponseTimerExpirations; *++pdwCounter = ProviderStats->AckTimerExpirations; *++pdwCounter = ProviderStats->MaximumSendWindow; *++pdwCounter = ProviderStats->AverageSendWindow; *++pdwCounter = ProviderStats->PiggybackAckQueued; *++pdwCounter = ProviderStats->PiggybackAckTimeouts; pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *) ((PBYTE) pPerfCounterBlock + SIZE_OF_NBF_DATA); } pNbfResourceDataDefinition = (NBF_RESOURCE_DATA_DEFINITION *) ++pdwCounter; TotalNumberOfResources = 0; pNbfDataDefinition->NbfObjectType.NumInstances = NumOfDevices; pNbfDataDefinition->NbfObjectType.TotalByteLength = (PBYTE) pdwCounter - (PBYTE) pNbfDataDefinition; if (CurrentProtocol == NBF_PROTOCOL) { RtlMoveMemory(pNbfResourceDataDefinition, &NbfResourceDataDefinition, sizeof(NBF_RESOURCE_DATA_DEFINITION)); pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *) &pNbfResourceDataDefinition[1]; pTDIData = TDITbl[CurrentProtocol].pTDIData; for (i = 0; i < NumOfDevices; i++, pTDIData++) { // for most cases, we will have only one deivce, // then we could just use the ProviderStats read // for NBF data. if (NumOfDevices > 1) { // need to read ProviderStat again for multiple devices QueryInfo.QueryType = TDI_QUERY_PROVIDER_STATISTICS; Status = NtDeviceIoControlFile( pTDIData->fileHandle, NULL, NULL, NULL, &IoStatusBlock, IOCTL_TDI_QUERY_INFORMATION, (PVOID)&QueryInfo, sizeof(TDI_REQUEST_USER_QUERY_INFO), (PVOID)ProviderStats, ProviderStatsLength); if (Status != STATUS_SUCCESS) { REPORT_ERROR (TDI_UNABLE_READ_DEVICE, LOG_DEBUG); REPORT_ERROR_DATA (TDI_QUERY_INFO_ERROR, LOG_DEBUG, &IoStatusBlock, sizeof (IoStatusBlock)); *lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ERROR_SUCCESS; } } TotalNumberOfResources += pTDIData->NumberOfResources; for ( NumResource = 0; NumResource < pTDIData->NumberOfResources; NumResource++ ) { // // Format and collect Nbf Resource data // if (NumResource < NUMBER_OF_NAMES) { RtlInitUnicodeString(&ResourceName, NetResourceName[NumResource]); } else { ResourceName.Length = 0; ResourceName.MaximumLength = MAX_NBF_RESOURCE_NAME_LENGTH + sizeof(UNICODE_NULL); ResourceName.Buffer = ResourceNameBuffer; RtlIntegerToUnicodeString(NumResource, 10, &ResourceName); } MonBuildInstanceDefinition( pPerfInstanceDefinition, (PVOID *)&pPerfCounterBlock, ObjectNameTitleIndices[CurrentProtocol], i, NumResource, &ResourceName); pPerfCounterBlock->ByteLength = SIZE_OF_NBF_RESOURCE_DATA; pdwCounter = (PDWORD)&pPerfCounterBlock[1]; // define pointer to first // counter in block *pdwCounter++ = ProviderStats->ResourceStats[NumResource].MaximumResourceUsed; *pdwCounter++ = ProviderStats->ResourceStats[NumResource].AverageResourceUsed; *pdwCounter++ = ProviderStats->ResourceStats[NumResource].ResourceExhausted; // set pointer to where next instance buffer should show up pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *) ((PBYTE) pPerfCounterBlock + SIZE_OF_NBF_RESOURCE_DATA); // set for loop termination pdwCounter = (PDWORD) pPerfInstanceDefinition; } // NumberOfResources } // NumOfDevices } // NBF_PROTOCOL *lppData = pdwCounter; pNbfResourceDataDefinition->NbfResourceObjectType.TotalByteLength = (PBYTE) pdwCounter - (PBYTE) pNbfResourceDataDefinition; if (CurrentProtocol != NBF_PROTOCOL) { *lpNumObjectTypes = 1; // bytes used are those of the first (i.e. only) object returned *lpcbTotalBytes = pNbfDataDefinition->NbfObjectType.TotalByteLength; } else { // set count of object types returned *lpNumObjectTypes = NBF_NUM_PERF_OBJECT_TYPES; // set length of this object *lpcbTotalBytes; // note the bytes used by first object *lpcbTotalBytes = pNbfDataDefinition->NbfObjectType.TotalByteLength; // add the bytes used by the second object *lpcbTotalBytes += pNbfResourceDataDefinition->NbfResourceObjectType.TotalByteLength; // set number of instances loaded pNbfResourceDataDefinition->NbfResourceObjectType.NumInstances = TotalNumberOfResources; } REPORT_INFORMATION (TDI_COLLECT_DATA, LOG_DEBUG); return ERROR_SUCCESS; } DWORD CloseNbfPerformanceData( ) /*++ Routine Description: This routine closes the open handles to Nbf devices. Arguments: None. Return Value: ERROR_SUCCESS --*/ { return CloseTDIPerformanceData(NBF_PROTOCOL); } DWORD CloseIPXPerformanceData( ) /*++ Routine Description: This routine closes the open handles to IPX devices. Arguments: None. Return Value: ERROR_SUCCESS --*/ { return CloseTDIPerformanceData(IPX_PROTOCOL); } DWORD CloseSPXPerformanceData( ) /*++ Routine Description: This routine closes the open handles to SPX devices. Arguments: None. Return Value: ERROR_SUCCESS --*/ { return CloseTDIPerformanceData(SPX_PROTOCOL); } DWORD CloseNWNBPerformanceData( ) /*++ Routine Description: This routine closes the open handles to NWNB devices. Arguments: None. Return Value: ERROR_SUCCESS --*/ { return CloseTDIPerformanceData(NWNB_PROTOCOL); } DWORD CloseTDIPerformanceData( DWORD CurrentProtocol ) /*++ Routine Description: This routine closes the open handles to TDI devices. Arguments: Current protocol index. Return Value: ERROR_SUCCESS --*/ { REPORT_INFORMATION (TDI_CLOSE_ENTERED, LOG_VERBOSE); CleanUpTDIData (CurrentProtocol); if ( ProviderStats ) { RtlFreeHeap(RtlProcessHeap(), 0, ProviderStats); ProviderStats = NULL; REPORT_INFORMATION (TDI_PROVIDER_STATS_FREED, LOG_VERBOSE); } MonCloseEventLog (); return ERROR_SUCCESS; }