293 lines
9.1 KiB
C
293 lines
9.1 KiB
C
/*
|
|
* Process Hacker Plugins -
|
|
* Hardware Devices Plugin
|
|
*
|
|
* Copyright (C) 2015-2016 dmex
|
|
* Copyright (C) 2016 wj32
|
|
*
|
|
* This file is part of Process Hacker.
|
|
*
|
|
* Process Hacker is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Process Hacker is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "devices.h"
|
|
|
|
VOID AdapterEntryDeleteProcedure(
|
|
_In_ PVOID Object,
|
|
_In_ ULONG Flags
|
|
)
|
|
{
|
|
PDV_NETADAPTER_ENTRY entry = Object;
|
|
|
|
PhAcquireQueuedLockExclusive(&NetworkAdaptersListLock);
|
|
PhRemoveItemList(NetworkAdaptersList, PhFindItemList(NetworkAdaptersList, entry));
|
|
PhReleaseQueuedLockExclusive(&NetworkAdaptersListLock);
|
|
|
|
DeleteNetAdapterId(&entry->Id);
|
|
PhClearReference(&entry->AdapterName);
|
|
|
|
PhDeleteCircularBuffer_ULONG64(&entry->InboundBuffer);
|
|
PhDeleteCircularBuffer_ULONG64(&entry->OutboundBuffer);
|
|
}
|
|
|
|
VOID NetAdaptersInitialize(
|
|
VOID
|
|
)
|
|
{
|
|
NetworkAdaptersList = PhCreateList(1);
|
|
NetAdapterEntryType = PhCreateObjectType(L"NetAdapterEntry", 0, AdapterEntryDeleteProcedure);
|
|
}
|
|
|
|
VOID NetAdaptersUpdate(
|
|
VOID
|
|
)
|
|
{
|
|
static ULONG runCount = 0; // MUST keep in sync with runCount in process provider
|
|
|
|
PhAcquireQueuedLockShared(&NetworkAdaptersListLock);
|
|
|
|
for (ULONG i = 0; i < NetworkAdaptersList->Count; i++)
|
|
{
|
|
HANDLE deviceHandle = NULL;
|
|
PDV_NETADAPTER_ENTRY entry;
|
|
ULONG64 networkInOctets = 0;
|
|
ULONG64 networkOutOctets = 0;
|
|
ULONG64 networkRcvSpeed = 0;
|
|
ULONG64 networkXmitSpeed = 0;
|
|
NDIS_MEDIA_CONNECT_STATE mediaState = MediaConnectStateUnknown;
|
|
|
|
entry = PhReferenceObjectSafe(NetworkAdaptersList->Items[i]);
|
|
|
|
if (!entry)
|
|
continue;
|
|
|
|
if (PhGetIntegerSetting(SETTING_NAME_ENABLE_NDIS))
|
|
{
|
|
if (NT_SUCCESS(NetworkAdapterCreateHandle(&deviceHandle, entry->Id.InterfaceGuid)))
|
|
{
|
|
if (!entry->CheckedDeviceSupport)
|
|
{
|
|
// Check the network adapter supports the OIDs we're going to be using.
|
|
if (NetworkAdapterQuerySupported(deviceHandle))
|
|
{
|
|
entry->DeviceSupported = TRUE;
|
|
}
|
|
|
|
entry->CheckedDeviceSupport = TRUE;
|
|
}
|
|
|
|
if (!entry->DeviceSupported)
|
|
{
|
|
// Device is faulty. Close the handle so we can fallback to GetIfEntry.
|
|
NtClose(deviceHandle);
|
|
deviceHandle = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (deviceHandle)
|
|
{
|
|
NDIS_STATISTICS_INFO interfaceStats;
|
|
NDIS_LINK_STATE interfaceState;
|
|
|
|
memset(&interfaceStats, 0, sizeof(NDIS_STATISTICS_INFO));
|
|
|
|
NetworkAdapterQueryStatistics(deviceHandle, &interfaceStats);
|
|
|
|
if (NT_SUCCESS(NetworkAdapterQueryLinkState(deviceHandle, &interfaceState)))
|
|
{
|
|
mediaState = interfaceState.MediaConnectState;
|
|
}
|
|
|
|
if (!(interfaceStats.SupportedStatistics & NDIS_STATISTICS_FLAGS_VALID_BYTES_RCV))
|
|
networkInOctets = NetworkAdapterQueryValue(deviceHandle, OID_GEN_BYTES_RCV);
|
|
else
|
|
networkInOctets = interfaceStats.ifHCInOctets;
|
|
|
|
if (!(interfaceStats.SupportedStatistics & NDIS_STATISTICS_FLAGS_VALID_BYTES_XMIT))
|
|
networkOutOctets = NetworkAdapterQueryValue(deviceHandle, OID_GEN_BYTES_XMIT);
|
|
else
|
|
networkOutOctets = interfaceStats.ifHCOutOctets;
|
|
|
|
networkRcvSpeed = networkInOctets - entry->LastInboundValue;
|
|
networkXmitSpeed = networkOutOctets - entry->LastOutboundValue;
|
|
|
|
// HACK: Pull the Adapter name from the current query.
|
|
if (!entry->AdapterName)
|
|
{
|
|
entry->AdapterName = NetworkAdapterQueryName(deviceHandle, entry->Id.InterfaceGuid);
|
|
}
|
|
|
|
entry->DevicePresent = TRUE;
|
|
|
|
NtClose(deviceHandle);
|
|
}
|
|
else if (WindowsVersion >= WINDOWS_VISTA && GetIfEntry2)
|
|
{
|
|
MIB_IF_ROW2 interfaceRow;
|
|
|
|
if (QueryInterfaceRowVista(&entry->Id, &interfaceRow))
|
|
{
|
|
networkInOctets = interfaceRow.InOctets;
|
|
networkOutOctets = interfaceRow.OutOctets;
|
|
mediaState = interfaceRow.MediaConnectState;
|
|
networkRcvSpeed = networkInOctets - entry->LastInboundValue;
|
|
networkXmitSpeed = networkOutOctets - entry->LastOutboundValue;
|
|
|
|
// HACK: Pull the Adapter name from the current query.
|
|
if (!entry->AdapterName && PhCountStringZ(interfaceRow.Description) > 0)
|
|
{
|
|
entry->AdapterName = PhCreateString(interfaceRow.Description);
|
|
}
|
|
|
|
entry->DevicePresent = TRUE;
|
|
}
|
|
else
|
|
{
|
|
entry->DevicePresent = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MIB_IFROW interfaceRow;
|
|
|
|
if (QueryInterfaceRowXP(&entry->Id, &interfaceRow))
|
|
{
|
|
networkInOctets = interfaceRow.dwInOctets;
|
|
networkOutOctets = interfaceRow.dwOutOctets;
|
|
mediaState = interfaceRow.dwOperStatus == IF_OPER_STATUS_OPERATIONAL ? MediaConnectStateConnected : MediaConnectStateDisconnected;
|
|
networkRcvSpeed = networkInOctets - entry->LastInboundValue;
|
|
networkXmitSpeed = networkOutOctets - entry->LastOutboundValue;
|
|
|
|
// HACK: Pull the Adapter name from the current query.
|
|
if (!entry->AdapterName && strlen(interfaceRow.bDescr) > 0)
|
|
{
|
|
entry->AdapterName = PhConvertMultiByteToUtf16(interfaceRow.bDescr);
|
|
}
|
|
|
|
entry->DevicePresent = TRUE;
|
|
}
|
|
else
|
|
{
|
|
entry->DevicePresent = FALSE;
|
|
}
|
|
}
|
|
|
|
if (mediaState == MediaConnectStateUnknown)
|
|
{
|
|
// We don't want incorrect data when the adapter is disabled.
|
|
networkRcvSpeed = 0;
|
|
networkXmitSpeed = 0;
|
|
}
|
|
|
|
if (!entry->HaveFirstSample)
|
|
{
|
|
// The first sample must be zero.
|
|
networkRcvSpeed = 0;
|
|
networkXmitSpeed = 0;
|
|
entry->HaveFirstSample = TRUE;
|
|
}
|
|
|
|
if (runCount != 0)
|
|
{
|
|
PhAddItemCircularBuffer_ULONG64(&entry->InboundBuffer, networkRcvSpeed);
|
|
PhAddItemCircularBuffer_ULONG64(&entry->OutboundBuffer, networkXmitSpeed);
|
|
}
|
|
|
|
//context->LinkSpeed = networkLinkSpeed;
|
|
entry->InboundValue = networkRcvSpeed;
|
|
entry->OutboundValue = networkXmitSpeed;
|
|
entry->LastInboundValue = networkInOctets;
|
|
entry->LastOutboundValue = networkOutOctets;
|
|
|
|
PhDereferenceObjectDeferDelete(entry);
|
|
}
|
|
|
|
PhReleaseQueuedLockShared(&NetworkAdaptersListLock);
|
|
|
|
runCount++;
|
|
}
|
|
|
|
VOID InitializeNetAdapterId(
|
|
_Out_ PDV_NETADAPTER_ID Id,
|
|
_In_ NET_IFINDEX InterfaceIndex,
|
|
_In_ IF_LUID InterfaceLuid,
|
|
_In_ PPH_STRING InterfaceGuid
|
|
)
|
|
{
|
|
Id->InterfaceIndex = InterfaceIndex;
|
|
Id->InterfaceLuid = InterfaceLuid;
|
|
PhSetReference(&Id->InterfaceGuid, InterfaceGuid);
|
|
}
|
|
|
|
VOID CopyNetAdapterId(
|
|
_Out_ PDV_NETADAPTER_ID Destination,
|
|
_In_ PDV_NETADAPTER_ID Source
|
|
)
|
|
{
|
|
InitializeNetAdapterId(
|
|
Destination,
|
|
Source->InterfaceIndex,
|
|
Source->InterfaceLuid,
|
|
Source->InterfaceGuid
|
|
);
|
|
}
|
|
|
|
VOID DeleteNetAdapterId(
|
|
_Inout_ PDV_NETADAPTER_ID Id
|
|
)
|
|
{
|
|
PhClearReference(&Id->InterfaceGuid);
|
|
}
|
|
|
|
BOOLEAN EquivalentNetAdapterId(
|
|
_In_ PDV_NETADAPTER_ID Id1,
|
|
_In_ PDV_NETADAPTER_ID Id2
|
|
)
|
|
{
|
|
if (WindowsVersion >= WINDOWS_VISTA)
|
|
{
|
|
if (Id1->InterfaceLuid.Value == Id2->InterfaceLuid.Value)
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (Id1->InterfaceIndex == Id2->InterfaceIndex)
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
PDV_NETADAPTER_ENTRY CreateNetAdapterEntry(
|
|
_In_ PDV_NETADAPTER_ID Id
|
|
)
|
|
{
|
|
PDV_NETADAPTER_ENTRY entry;
|
|
|
|
entry = PhCreateObject(sizeof(DV_NETADAPTER_ENTRY), NetAdapterEntryType);
|
|
memset(entry, 0, sizeof(DV_NETADAPTER_ENTRY));
|
|
|
|
CopyNetAdapterId(&entry->Id, Id);
|
|
|
|
PhInitializeCircularBuffer_ULONG64(&entry->InboundBuffer, PhGetIntegerSetting(L"SampleCount"));
|
|
PhInitializeCircularBuffer_ULONG64(&entry->OutboundBuffer, PhGetIntegerSetting(L"SampleCount"));
|
|
|
|
PhAcquireQueuedLockExclusive(&NetworkAdaptersListLock);
|
|
PhAddItemList(NetworkAdaptersList, entry);
|
|
PhReleaseQueuedLockExclusive(&NetworkAdaptersListLock);
|
|
|
|
return entry;
|
|
}
|