windows-nt/Source/XPSP1/NT/net/config/shell/statmon/smlan.cpp
2020-09-26 16:20:57 +08:00

700 lines
22 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997.
//
// File: S M L A N . C P P
//
// Contents: The LAN engine that provides statistics to the status monitor
//
// Notes:
//
// Author: CWill 12/02/1997
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include "sminc.h"
#include "smpsh.h"
#include "ndispnp.h"
#include "ntddndis.h"
#include "ncnetcfg.h"
#include "..\\folder\\cfutils.h"
#include "..\\folder\\shutil.h"
#include "naming.h"
//
// External data
//
extern const WCHAR c_szDevice[];
extern const WCHAR c_szSpace[];
extern SM_TOOL_FLAGS g_asmtfMap[];
extern WCHAR c_szCmdLineFlagPrefix[];
const ULONG c_aulConStateMap[] =
{
NCS_DISCONNECTED,
NCS_CONNECTED
};
//+---------------------------------------------------------------------------
//
// Member: CLanStatEngine::CLanStatEngine
//
// Purpose: Creator
//
// Arguments: None
//
// Returns: Nil
//
CLanStatEngine::CLanStatEngine(VOID)
{
m_ncmType = NCM_LAN;
m_ncsmType = NCSM_LAN;
m_dwCharacter = 0;
return;
}
//+---------------------------------------------------------------------------
//
// Member: CLanStatEngine::HrUpdateData
//
// Purpose: Get new statistics from the devices. This data is used to be
// displayed in the UI.
//
// Arguments: pdwChangeFlags - Where to modify the changed flags. This
// param may be NULL.
//
// Returns: Error code
//
HRESULT
CLanStatEngine::HrUpdateData (
DWORD* pdwChangeFlags,
BOOL* pfNoLongerConnected)
{
HRESULT hr = S_OK;
// Initialize the output parameter.
//
*pfNoLongerConnected = FALSE;
UINT uiRet = 0;
NIC_STATISTICS nsNewLanStats = { 0 };
// Prime the structure
//
nsNewLanStats.Size = sizeof(NIC_STATISTICS);
// Retrieve the statistics
//
uiRet = ::NdisQueryStatistics(&m_ustrDevice, &nsNewLanStats);
EnterCriticalSection(&g_csStatmonData);
// Make sure we have a statistics structure
//
if (!m_psmEngineData)
{
m_psmEngineData = new STATMON_ENGINEDATA;
if (m_psmEngineData)
{
ZeroMemory(m_psmEngineData, sizeof(STATMON_ENGINEDATA));
}
}
if (m_psmEngineData)
{
if (uiRet && (MEDIA_STATE_DISCONNECTED != nsNewLanStats.MediaState))
{
AssertSz((c_aulConStateMap[MEDIA_STATE_DISCONNECTED] == NCS_DISCONNECTED)
&& (c_aulConStateMap[MEDIA_STATE_CONNECTED] == NCS_CONNECTED),
"Someone is messing around with NETCON_STATUS values");
// Update the change flags if asked for
//
if (pdwChangeFlags)
{
*pdwChangeFlags = SMDCF_NULL;
// Bytes Transmitting
//
if (m_psmEngineData->SMED_PACKETSTRANSMITTING
!= nsNewLanStats.PacketsSent)
{
*pdwChangeFlags |= SMDCF_TRANSMITTING;
}
// Bytes Received
//
if (m_psmEngineData->SMED_PACKETSRECEIVING
!= nsNewLanStats.DirectedPacketsReceived)
{
*pdwChangeFlags |= SMDCF_RECEIVING;
}
}
// No Compression on LAN devices
//
m_psmEngineData->SMED_COMPRESSIONTRANSMITTING = 0;
m_psmEngineData->SMED_COMPRESSIONRECEIVING = 0;
//
// Update the LAN statistics
//
// LinkSpeed is in 100 bps
//
m_psmEngineData->SMED_SPEEDTRANSMITTING = nsNewLanStats.LinkSpeed * 100;
m_psmEngineData->SMED_SPEEDRECEIVING = nsNewLanStats.LinkSpeed * 100;
Assert((nsNewLanStats.MediaState == MEDIA_STATE_CONNECTED) ||
(nsNewLanStats.MediaState == MEDIA_STATE_DISCONNECTED));
m_psmEngineData->SMED_CONNECTIONSTATUS = c_aulConStateMap[nsNewLanStats.MediaState];
m_psmEngineData->SMED_DURATION = nsNewLanStats.ConnectTime;
m_psmEngineData->SMED_BYTESTRANSMITTING = nsNewLanStats.BytesSent;
m_psmEngineData->SMED_BYTESRECEIVING = nsNewLanStats.DirectedBytesReceived;
m_psmEngineData->SMED_ERRORSTRANSMITTING = nsNewLanStats.PacketsSendErrors;
m_psmEngineData->SMED_ERRORSRECEIVING = nsNewLanStats.PacketsReceiveErrors;
m_psmEngineData->SMED_PACKETSTRANSMITTING = nsNewLanStats.PacketsSent;
m_psmEngineData->SMED_PACKETSRECEIVING = nsNewLanStats.DirectedPacketsReceived;
HrGetAutoNetSetting(m_guidId, &(m_psmEngineData->SMED_DHCP_ADDRESS_TYPE) );
m_psmEngineData->SMED_INFRASTRUCTURE_MODE = IM_NOT_SUPPORTED;
if (IsMediaWireless(NCM_LAN, m_guidId))
{
DWORD dwInfraStructureMode;
DWORD dwInfraStructureModeSize = sizeof(DWORD);
HRESULT hrT = HrQueryNDISAdapterOID(m_guidId,
OID_802_11_INFRASTRUCTURE_MODE,
&dwInfraStructureModeSize,
&dwInfraStructureMode);
if (SUCCEEDED(hrT))
{
switch (dwInfraStructureMode)
{
case Ndis802_11IBSS:
m_psmEngineData->SMED_INFRASTRUCTURE_MODE = IM_NDIS802_11IBSS;
break;
case Ndis802_11Infrastructure:
m_psmEngineData->SMED_INFRASTRUCTURE_MODE = IM_NDIS802_11INFRASTRUCTURE;
break;
case Ndis802_11AutoUnknown:
m_psmEngineData->SMED_INFRASTRUCTURE_MODE = IM_NDIS802_11AUTOUNKNOWN;
break;
default:
m_psmEngineData->SMED_INFRASTRUCTURE_MODE = IM_NOT_SUPPORTED;
}
}
NDIS_802_11_SSID ndisSSID;
DWORD dwndisSSIDSize = sizeof(NDIS_802_11_SSID);
hrT = HrQueryNDISAdapterOID(m_guidId,
OID_802_11_SSID,
&dwndisSSIDSize,
&ndisSSID);
if (SUCCEEDED(hrT))
{
if (ndisSSID.SsidLength > 1)
{
DWORD dwLen = ndisSSID.SsidLength;
if (dwLen > sizeof(ndisSSID.Ssid))
{
dwLen = sizeof(ndisSSID.Ssid);
AssertSz(FALSE, "Unexpected SSID encountered");
}
ndisSSID.Ssid[dwLen] = 0;
mbstowcs(m_psmEngineData->SMED_802_11_SSID, reinterpret_cast<LPSTR>(ndisSSID.Ssid), celems(m_psmEngineData->SMED_802_11_SSID));
}
}
DWORD dwWepStatus;
DWORD dwWepStatusSize = sizeof(DWORD);
hrT = HrQueryNDISAdapterOID(m_guidId,
OID_802_11_WEP_STATUS,
&dwWepStatusSize,
&dwWepStatus);
if (SUCCEEDED(hrT))
{
if (Ndis802_11WEPEnabled == dwWepStatus)
{
m_psmEngineData->SMED_802_11_ENCRYPTION_ENABLED = TRUE;
}
}
LONG lSignalStrength;
DWORD dwSignalStrengthSize = sizeof(DWORD);
hrT = HrQueryNDISAdapterOID(m_guidId,
OID_802_11_RSSI,
&dwSignalStrengthSize,
&lSignalStrength);
if (SUCCEEDED(hrT))
{
m_psmEngineData->SMED_802_11_SIGNAL_STRENGTH = lSignalStrength;
}
}
}
else
{
*pfNoLongerConnected = TRUE;
// set the connection status to "disconnected" so we can close the UI
m_psmEngineData->SMED_CONNECTIONSTATUS = c_aulConStateMap[NCS_DISCONNECTED];
if (!uiRet)
{
TraceTag(ttidStatMon,
"NdisQueryStatistics failed on %S. err=%u. "
"Treating as disconnected.",
m_strDevice.c_str(),
GetLastError ());
}
else
{
TraceTag(ttidStatMon,
"NdisQueryStatistics returned MediaState = MEDIA_STATE_DISCONNECTED on %S.",
m_strDevice.c_str());
}
hr = S_OK;
}
}
else
{
hr = E_OUTOFMEMORY;
}
LeaveCriticalSection(&g_csStatmonData);
TraceError("CLanStatEngine::HrUpdateData", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CLanStatEngine::put_Device
//
// Purpose: Sets the device that is associated with this device
//
// Arguments: pstrDevice - The name of the device
//
// Returns: Error code.
//
HRESULT CLanStatEngine::put_Device(tstring* pstrDevice)
{
HRESULT hr = S_OK;
// Set the new device name
if (pstrDevice)
{
CExceptionSafeComObjectLock EsLock(this);
// Remember the name
m_strDevice = *pstrDevice;
// Make sure we have a nice UNICODE string as well
::RtlInitUnicodeString(&m_ustrDevice, m_strDevice.c_str());
}
else
{
hr = E_POINTER;
}
TraceError("CLanStatEngine::put_Device", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CLanStatEngine::put_MediaType
//
// Purpose: Pass media type of LAN connection type to the LAN engine
//
// Arguments: ncmType - NETCON_MEDIATYPE being set
// ncsmType - NETCON_SUBMEDIATYPE being set
//
// Returns:
//
VOID CLanStatEngine::put_MediaType(NETCON_MEDIATYPE ncmType, NETCON_SUBMEDIATYPE ncsmType)
{
m_ncmType = ncmType;
m_ncsmType = ncsmType;
}
//////////////////////////////////////////////////////////////////////////////
// //
// CPspLanGen //
// //
//////////////////////////////////////////////////////////////////////////////
CPspLanGen::CPspLanGen(VOID)
{
m_ncmType = NCM_LAN;
m_ncsmType = NCSM_LAN;
m_dwCharacter =0;
m_adwHelpIDs = NULL;
return;
}
//////////////////////////////////////////////////////////////////////////////
// //
// CPspLanGen //
// //
//////////////////////////////////////////////////////////////////////////////
VOID CPspLanGen::put_MediaType(NETCON_MEDIATYPE ncmType, NETCON_SUBMEDIATYPE ncsmType)
{
m_ncmType = ncmType;
m_ncsmType = ncsmType;
return;
}
//////////////////////////////////////////////////////////////////////////////
// //
// CPspLanTool //
// //
//////////////////////////////////////////////////////////////////////////////
CPspLanTool::CPspLanTool(VOID)
{
m_ncmType = NCM_LAN;
m_ncsmType = NCSM_LAN;
m_dwCharacter = 0;
return;
}
//+---------------------------------------------------------------------------
//
// Member: CPspLanTool::HrInitToolPageType
//
// Purpose: Gets from the connection any information that is relevant to
// this particular connection type.
//
// Arguments: pncInit - The connection assocatied with this dialog
//
// Returns: Error code
//
HRESULT CPspLanTool::HrInitToolPageType(INetConnection* pncInit)
{
HRESULT hr = S_OK;
INetLanConnection* pnlcInit = NULL;
// Get some LAN specific info
//
hr = HrQIAndSetProxyBlanket(pncInit, &pnlcInit);
if (SUCCEEDED(hr))
{
GUID guidDevice = { 0 };
// Find the component's GUID
//
hr = pnlcInit->GetDeviceGuid(&guidDevice);
if (SUCCEEDED(hr))
{
WCHAR achGuid[c_cchGuidWithTerm];
// Make the device name
//
::StringFromGUID2(guidDevice, achGuid,
c_cchGuidWithTerm);
m_strDeviceName = c_szDevice;
m_strDeviceName.append(achGuid);
}
::ReleaseObj(pnlcInit);
}
TraceError("CPspLanTool::HrInitToolPageType", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CPspLanTool::HrAddCommandLineFlags
//
// Purpose: Adds the flags for this selection to the command line for the
// tool being launched.
//
// Arguments: pstrFlags - The command line that the flags have to be
// appended to
// psmteSel - The tool entry associated with this selection
//
// Returns: Error code
//
HRESULT CPspLanTool::HrAddCommandLineFlags(tstring* pstrFlags,
CStatMonToolEntry* psmteSel)
{
HRESULT hr = S_OK;
DWORD dwFlags = 0x0;
// Same some indirections
//
dwFlags = psmteSel->dwFlags;
//
// Check what flags are asked for and provide them if we can
//
if (SCLF_ADAPTER & dwFlags)
{
pstrFlags->append(c_szCmdLineFlagPrefix);
pstrFlags->append(g_asmtfMap[STFI_ADAPTER].pszFlag);
pstrFlags->append(c_szSpace);
pstrFlags->append(m_strDeviceName);
}
TraceError("CPspStatusMonitorTool::HrAddCommandLineFlags", hr);
return hr;
}
HRESULT CPspLanTool::HrGetDeviceType(INetConnection* pncInit)
{
TraceFileFunc(ttidStatMon);
UINT uiRet = 0;
NIC_STATISTICS nsLanStats = { 0 };
// Set the default type
m_strDeviceType = L"Ethernet";
// Prime the structure
//
nsLanStats.Size = sizeof(NIC_STATISTICS);
// Retrieve the statistics
//
WCHAR szDeviceGuid[c_cchGuidWithTerm];
::StringFromGUID2(m_guidId, szDeviceGuid, c_cchGuidWithTerm);
tstring strDeviceName = c_szDevice;
strDeviceName.append(szDeviceGuid);
UNICODE_STRING ustrDevice;
::RtlInitUnicodeString(&ustrDevice, strDeviceName.c_str());
uiRet = ::NdisQueryStatistics(&ustrDevice, &nsLanStats);
if (uiRet)
{
switch(nsLanStats.MediaType)
{
case NdisMedium802_3:
TraceTag(ttidStatMon, "Medium type: NdisMedium802_3 - Ethernet");
m_strDeviceType = L"Ethernet";
break;
case NdisMedium802_5:
TraceTag(ttidStatMon, "Medium type: NdisMedium802_5 - Token Ring");
m_strDeviceType = L"Token ring";
break;
case NdisMediumFddi:
TraceTag(ttidStatMon, "Medium type: NdisMediumFddi - FDDI");
m_strDeviceType = L"FDDI";
break;
case NdisMediumLocalTalk:
TraceTag(ttidStatMon, "Medium type: NdisMediumLocalTalk - Local Talk");
m_strDeviceType = L"Local Talk";
break;
case NdisMediumAtm:
TraceTag(ttidStatMon, "Medium type: NdisMediumAtm - Atm");
m_strDeviceType = L"Atm";
break;
case NdisMediumIrda:
TraceTag(ttidStatMon, "Medium type: NdisMediumIrda - IRDA");
m_strDeviceType = L"IRDA";
break;
case NdisMediumBpc:
TraceTag(ttidStatMon, "Medium type: NdisMediumBpc - BPC");
m_strDeviceType = L"BPC";
break;
case NdisMediumArcnetRaw:
TraceTag(ttidStatMon, "Medium type: NdisMediumArcnetRaw - ArcnetRaw");
m_strDeviceType = L"ArcnetRaw";
break;
case NdisMediumArcnet878_2:
TraceTag(ttidStatMon, "Medium type: NdisMediumArcnet878_2 - MediumArcnet878_2");
m_strDeviceType = L"MediumArcnet878_2";
break;
case NdisMediumWirelessWan:
TraceTag(ttidStatMon, "Medium type: NdisMediumWirelessWan - WirelessWan");
m_strDeviceType = L"WirelessWan";
break;
case NdisMediumWan:
TraceTag(ttidStatMon, "Medium type: NdisMediumWan - Wan");
m_strDeviceType = L"Wan";
break;
case NdisMediumCoWan:
TraceTag(ttidStatMon, "Medium type: NdisMediumCoWan - CoWan");
m_strDeviceType = L"CoWan";
break;
case NdisMediumMax:
TraceTag(ttidStatMon, "Not real medium type ??? NdisMediumMax");
break;
case NdisMediumDix:
TraceTag(ttidStatMon, "Not real medium type ??? NdisMediumDix");
break;
default:
TraceTag(ttidStatMon, "Unknown medium type ??? %d", nsLanStats.MediaType);
break;
}
}
return S_OK;
}
HRESULT CPspLanTool::HrGetComponentList(INetConnection* pncInit)
{
// Get a readonly INetCfg, enumerate components bound to this adapter
HRESULT hr = S_OK;
INetCfg * pNetCfg = NULL;
PWSTR pszClientDesc = NULL;
BOOL fInitCom = TRUE;
BOOL fWriteLock = FALSE;
// Get a read-only INetCfg
hr = HrCreateAndInitializeINetCfg(&fInitCom, &pNetCfg, fWriteLock, 0,
SzLoadIds(IDS_STATMON_CAPTION),
&pszClientDesc);
if (SUCCEEDED(hr))
{
Assert(pNetCfg);
if (pNetCfg)
{
// Get the INetCfgComponent for the adapter in this connection
// ?? Has the GUID been set already ?
INetCfgComponent * pnccAdapter = NULL;
BOOL fFound = FALSE;
CIterNetCfgComponent nccIter(pNetCfg, &GUID_DEVCLASS_NET);
INetCfgComponent* pnccAdapterTemp = NULL;
while (!fFound && SUCCEEDED(hr) &&
(S_OK == (hr = nccIter.HrNext(&pnccAdapterTemp))))
{
GUID guidDev;
hr = pnccAdapterTemp->GetInstanceGuid(&guidDev);
if (S_OK == hr)
{
if (m_guidId == guidDev)
{
fFound = TRUE;
pnccAdapter = pnccAdapterTemp;
AddRefObj(pnccAdapter);
}
}
ReleaseObj (pnccAdapterTemp);
}
// Enumerate the binding paths from the adapter
// and fill in the components list m_lstpstrCompIds
if (pnccAdapter)
{
HRESULT hrTmp;
PWSTR pszCompId;
// Add the adapter to our list
hrTmp = pnccAdapter->GetId(&pszCompId);
if (SUCCEEDED(hrTmp))
{
if (!FIsStringInList(&m_lstpstrCompIds, pszCompId))
{
m_lstpstrCompIds.push_back(new tstring(pszCompId));
}
CoTaskMemFree(pszCompId);
}
// Add other components to our list
CIterNetCfgUpperBindingPath ncbpIter(pnccAdapter);
INetCfgBindingPath * pncbp;
while(SUCCEEDED(hr) && (hr = ncbpIter.HrNext(&pncbp)) == S_OK)
{
// Note: (tongl 9/17/98): should we only consider enabled paths ?
// If we do, how does the tool list refresh when component bindings change ?
// Also, what about component getting added\removed ? Does the tool list
// need to refresh ??
// Enumerate components on the path and add to our list
CIterNetCfgBindingInterface ncbiIter(pncbp);
INetCfgBindingInterface* pncbi;
while(SUCCEEDED(hr) && (hr = ncbiIter.HrNext(&pncbi)) == S_OK)
{
INetCfgComponent * pnccUpper = NULL;
hrTmp = pncbi->GetUpperComponent(&pnccUpper);
if (SUCCEEDED(hrTmp))
{
PWSTR pszCompId;
hrTmp = pnccUpper->GetId(&pszCompId);
if(SUCCEEDED(hrTmp))
{
if (!FIsStringInList(&m_lstpstrCompIds, pszCompId))
{
m_lstpstrCompIds.push_back(new tstring(pszCompId));
}
CoTaskMemFree(pszCompId);
}
ReleaseObj(pnccUpper);
}
ReleaseObj (pncbi);
}
if (hr == S_FALSE) // We just got to the end of the loop
hr = S_OK;
ReleaseObj(pncbp);
}
if (hr == S_FALSE) // We just got to the end of the loop
hr = S_OK;
}
}
// Release the INetCfg
(VOID) HrUninitializeAndReleaseINetCfg(fInitCom, pNetCfg, fWriteLock);
CoTaskMemFree(pszClientDesc);
}
return hr;
}