518 lines
16 KiB
C++
518 lines
16 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1997.
|
||
|
//
|
||
|
// File: N M D I A G P . C P P
|
||
|
//
|
||
|
// Contents: Diagnostics for the netman process
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
// Author: danielwe 23 Mar 1999
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include "pch.h"
|
||
|
#pragma hdrstop
|
||
|
#include "enuml.h"
|
||
|
#include "diag.h"
|
||
|
#include "kkenet.h"
|
||
|
#include "ncnetcon.h"
|
||
|
#include "ncreg.h"
|
||
|
#include "ncsetup.h"
|
||
|
#include "ncstring.h"
|
||
|
#include "netcon.h"
|
||
|
#include "ntddndis.h"
|
||
|
|
||
|
struct LAN_CONNECTION
|
||
|
{
|
||
|
GUID guidId;
|
||
|
tstring strName;
|
||
|
NETCON_STATUS Status;
|
||
|
tstring strDeviceName;
|
||
|
DWORD dwMediaState;
|
||
|
ULONG ulDevNodeStatus;
|
||
|
ULONG ulDevNodeProblem;
|
||
|
tstring strPnpName;
|
||
|
};
|
||
|
|
||
|
typedef list<LAN_CONNECTION *> LAN_CONNECTION_LIST;
|
||
|
typedef list<LAN_CONNECTION *>::iterator LAN_CONNECTION_LIST_ITERATOR;
|
||
|
|
||
|
HRESULT HrInitializeConMan(INetConnectionManager **ppConMan)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = CoCreateInstance(CLSID_LanConnectionManager, NULL,
|
||
|
CLSCTX_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
|
||
|
IID_INetConnectionManager,
|
||
|
reinterpret_cast<LPVOID *>(ppConMan));
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT HrUninitializeConMan(INetConnectionManager *pConMan)
|
||
|
{
|
||
|
ReleaseObj(pConMan);
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT HrEnumerateLanConnections(INetConnectionManager *pConMan,
|
||
|
LAN_CONNECTION_LIST &listCon)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
CIterNetCon ncIter(pConMan, NCME_DEFAULT);
|
||
|
INetConnection * pconn;
|
||
|
|
||
|
while (SUCCEEDED(hr) &&
|
||
|
(S_OK == (ncIter.HrNext(&pconn))))
|
||
|
{
|
||
|
NETCON_PROPERTIES * pProps;
|
||
|
|
||
|
hr = pconn->GetProperties(&pProps);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
LAN_CONNECTION * pLanCon;
|
||
|
BOOL fMediaConnected;
|
||
|
WCHAR szwInstance[_MAX_PATH];
|
||
|
|
||
|
pLanCon = new LAN_CONNECTION;
|
||
|
if (pLanCon)
|
||
|
{
|
||
|
pLanCon->guidId = pProps->guidId;
|
||
|
pLanCon->strName = pProps->pszwName;
|
||
|
pLanCon->Status = pProps->Status;
|
||
|
pLanCon->strDeviceName = pProps->pszwDeviceName;
|
||
|
|
||
|
if (SUCCEEDED(hr = HrQueryLanMediaState(&pProps->guidId,
|
||
|
&fMediaConnected)))
|
||
|
{
|
||
|
pLanCon->dwMediaState = fMediaConnected ?
|
||
|
NdisMediaStateConnected : NdisMediaStateDisconnected;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pLanCon->dwMediaState = hr;
|
||
|
}
|
||
|
|
||
|
hr = HrPnpInstanceIdFromGuid(&pProps->guidId, szwInstance,
|
||
|
celems(szwInstance));
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
DEVINST devinst;
|
||
|
pLanCon->strPnpName = szwInstance;
|
||
|
|
||
|
if (CR_SUCCESS == CM_Locate_DevNode(&devinst,
|
||
|
szwInstance,
|
||
|
CM_LOCATE_DEVNODE_NORMAL))
|
||
|
{
|
||
|
ULONG ulStatus;
|
||
|
ULONG ulProblem;
|
||
|
CONFIGRET cfgRet;
|
||
|
|
||
|
cfgRet = CM_Get_DevNode_Status_Ex(&ulStatus, &ulProblem,
|
||
|
devinst, 0, NULL);
|
||
|
if (CR_SUCCESS == cfgRet)
|
||
|
{
|
||
|
pLanCon->ulDevNodeProblem = ulProblem;
|
||
|
pLanCon->ulDevNodeStatus = ulStatus;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
listCon.push_back(pLanCon);
|
||
|
}
|
||
|
|
||
|
FreeNetconProperties(pProps);
|
||
|
}
|
||
|
|
||
|
ReleaseObj(pconn);
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT HrFindLanConnection(INetConnectionManager *pConMan,
|
||
|
PCWSTR szLanConnection,
|
||
|
INetConnection **ppcon)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
CIterNetCon ncIter(pConMan, NCME_DEFAULT);
|
||
|
INetConnection * pconn;
|
||
|
|
||
|
*ppcon = NULL;
|
||
|
|
||
|
while (SUCCEEDED(hr) &&
|
||
|
(S_OK == (ncIter.HrNext(&pconn))))
|
||
|
{
|
||
|
NETCON_PROPERTIES * pProps;
|
||
|
|
||
|
hr = pconn->GetProperties(&pProps);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
if (!lstrcmpiW(pProps->pszwName, szLanConnection))
|
||
|
{
|
||
|
*ppcon = pconn;
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ReleaseObj(pconn);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
if (*ppcon == NULL)
|
||
|
{
|
||
|
hr = S_FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
extern const WCHAR c_szRegValueNetCfgInstanceId[];
|
||
|
|
||
|
VOID CmdShowAllDevices(DIAG_OPTIONS *pOptions, INetConnectionManager *pConMan)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
DWORD dwIndex = 0;
|
||
|
SP_DEVINFO_DATA deid = {0};
|
||
|
HDEVINFO hdi = NULL;
|
||
|
WCHAR szBuffer [MAX_PATH];
|
||
|
|
||
|
hr = HrSetupDiGetClassDevs(&GUID_DEVCLASS_NET, NULL, NULL,
|
||
|
DIGCF_PRESENT, &hdi);
|
||
|
|
||
|
while (SUCCEEDED(hr = HrSetupDiEnumDeviceInfo(hdi,
|
||
|
dwIndex,
|
||
|
&deid)))
|
||
|
{
|
||
|
HKEY hkey;
|
||
|
|
||
|
dwIndex++;
|
||
|
|
||
|
hr = HrSetupDiOpenDevRegKey(hdi, &deid, DICS_FLAG_GLOBAL, 0,
|
||
|
DIREG_DRV, KEY_READ, &hkey);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
ULONG ulProblem;
|
||
|
ULONG ulStatus;
|
||
|
PWSTR pszName;
|
||
|
|
||
|
hr = HrSetupDiGetDeviceName(hdi, &deid, &pszName);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "Device name: %S\n", pszName);
|
||
|
delete [] reinterpret_cast<BYTE*>(pszName);
|
||
|
}
|
||
|
|
||
|
(VOID) CM_Get_DevNode_Status_Ex(&ulStatus, &ulProblem,
|
||
|
deid.DevInst, 0, NULL);
|
||
|
|
||
|
tstring strStatus;
|
||
|
|
||
|
SzFromCmStatus(ulStatus, &strStatus);
|
||
|
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "Device CM Status: (0x%08X) %S\n", ulStatus,
|
||
|
strStatus.c_str());
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "Device CM Problem: (0x%08X) %S\n", ulProblem,
|
||
|
SzFromCmProb(ulProblem));
|
||
|
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "Lan capable: ");
|
||
|
if (S_OK == HrIsLanCapableAdapterFromHkey(hkey))
|
||
|
{
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "Yes\n");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "No\n");
|
||
|
}
|
||
|
|
||
|
HRESULT hr = S_OK;
|
||
|
WCHAR szGuid[c_cchGuidWithTerm] = {0};
|
||
|
DWORD cbBuf = sizeof(szGuid);
|
||
|
|
||
|
hr = HrRegQuerySzBuffer(hkey, c_szRegValueNetCfgInstanceId,
|
||
|
szGuid, &cbBuf);
|
||
|
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "Valid NetCfg device: ");
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "Yes\n");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "No\n");
|
||
|
}
|
||
|
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "NetCfg instance ID: %S\n", szGuid);
|
||
|
|
||
|
hr = HrSetupDiGetDeviceInstanceId(hdi, &deid, szBuffer,
|
||
|
sizeof(szBuffer), NULL);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "PnP instance ID: %S\n", szBuffer);
|
||
|
}
|
||
|
|
||
|
DWORD dwChars;
|
||
|
tstring strChars;
|
||
|
|
||
|
if (SUCCEEDED(HrRegQueryDword(hkey, L"Characteristics", &dwChars)))
|
||
|
{
|
||
|
SzFromCharacteristics(dwChars, &strChars);
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "Characteristics: (0x%08X) %S\n", dwChars,
|
||
|
strChars.c_str());
|
||
|
}
|
||
|
|
||
|
hr = HrSetupDiGetDeviceRegistryProperty (hdi, &deid,
|
||
|
SPDRP_LOCATION_INFORMATION, NULL, (BYTE*)szBuffer,
|
||
|
sizeof (szBuffer), NULL);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "Location: %S\n", szBuffer);
|
||
|
}
|
||
|
|
||
|
if ((NCF_PHYSICAL & dwChars) && *szGuid)
|
||
|
{
|
||
|
ULONGLONG MacAddr;
|
||
|
hr = HrGetNetCardAddr (szGuid, &MacAddr);
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "Mac Address: 0x%012.12I64X\n", MacAddr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
GUID guid;
|
||
|
BOOL fMediaConnected;
|
||
|
DWORD dwMediaState;
|
||
|
|
||
|
IIDFromString(szGuid, &guid);
|
||
|
if (SUCCEEDED(hr = HrQueryLanMediaState(&guid,
|
||
|
&fMediaConnected)))
|
||
|
{
|
||
|
dwMediaState = fMediaConnected ?
|
||
|
NdisMediaStateConnected : NdisMediaStateDisconnected;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dwMediaState = hr;
|
||
|
}
|
||
|
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "NDIS media status: ");
|
||
|
switch (dwMediaState)
|
||
|
{
|
||
|
case NdisMediaStateConnected:
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "Connected\n");
|
||
|
break;
|
||
|
|
||
|
case NdisMediaStateDisconnected:
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "Disconnected\n");
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "Error 0x%08X\n", dwMediaState);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
RegCloseKey(hkey);
|
||
|
}
|
||
|
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "------------------------------------------------------------------------------------\n");
|
||
|
}
|
||
|
|
||
|
SetupDiDestroyDeviceInfoListSafe(hdi);
|
||
|
}
|
||
|
|
||
|
VOID CmdShowLanConnections(DIAG_OPTIONS *pOptions, INetConnectionManager *pConMan)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
LAN_CONNECTION_LIST listCon;
|
||
|
LAN_CONNECTION_LIST_ITERATOR iterListCon;
|
||
|
|
||
|
hr = HrEnumerateLanConnections(pConMan, listCon);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "Current LAN connections\n\n");
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "%-20S%-50S%-20S%\n", L"Connection Name", L"Device Name", L"Status");
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "----------------------------------------------------------------------------------------\n");
|
||
|
|
||
|
for (iterListCon = listCon.begin(); iterListCon != listCon.end(); iterListCon++)
|
||
|
{
|
||
|
LAN_CONNECTION * pLanCon;
|
||
|
|
||
|
pLanCon = *iterListCon;
|
||
|
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "%-20S%-50S%-20S%\n",
|
||
|
pLanCon->strName.c_str(),
|
||
|
pLanCon->strDeviceName.c_str(),
|
||
|
SzFromNetconStatus(pLanCon->Status));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID CmdShowLanDetails(DIAG_OPTIONS *pOptions, INetConnectionManager *pConMan)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
LAN_CONNECTION_LIST listCon;
|
||
|
LAN_CONNECTION_LIST_ITERATOR iterListCon;
|
||
|
BOOL fFound = FALSE;
|
||
|
|
||
|
hr = HrEnumerateLanConnections(pConMan, listCon);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
for (iterListCon = listCon.begin(); iterListCon != listCon.end(); iterListCon++)
|
||
|
{
|
||
|
LAN_CONNECTION * pLanCon;
|
||
|
|
||
|
pLanCon = *iterListCon;
|
||
|
if (!lstrcmpiW(pLanCon->strName.c_str(), pOptions->szLanConnection))
|
||
|
{
|
||
|
WCHAR szwGuid[c_cchGuidWithTerm];
|
||
|
|
||
|
StringFromGUID2(pLanCon->guidId, szwGuid, c_cchGuidWithTerm);
|
||
|
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "Details for %S:\n", pOptions->szLanConnection);
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "------------------------------------------\n\n");
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "Device name: %S\n", pLanCon->strDeviceName.c_str());
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "Device GUID: %S\n", szwGuid);
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "PnP Instance ID: %S\n", pLanCon->strPnpName.c_str());
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "Netman Status: %S\n", SzFromNetconStatus(pLanCon->Status));
|
||
|
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "NDIS media status: ");
|
||
|
switch (pLanCon->dwMediaState)
|
||
|
{
|
||
|
case NdisMediaStateConnected:
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "Connected\n");
|
||
|
break;
|
||
|
|
||
|
case NdisMediaStateDisconnected:
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "Disconnected\n");
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "Error 0x%08X\n", pLanCon->dwMediaState);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
tstring strStatus;
|
||
|
|
||
|
SzFromCmStatus(pLanCon->ulDevNodeStatus, &strStatus);
|
||
|
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "CM DevNode Status: (0x%08X) %S\n",
|
||
|
pLanCon->ulDevNodeStatus, strStatus.c_str());
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "CM DevNode Problem: (0x%08X) %S\n",
|
||
|
pLanCon->ulDevNodeProblem,
|
||
|
SzFromCmProb(pLanCon->ulDevNodeProblem));
|
||
|
|
||
|
fFound = TRUE;
|
||
|
|
||
|
// No need to keep looping
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!fFound)
|
||
|
{
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "Could not find match for connection name: %S\n",
|
||
|
pOptions->szLanConnection);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID CmdLanChangeState(DIAG_OPTIONS *pOptions, INetConnectionManager *pConMan)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
INetConnection * pcon = NULL;
|
||
|
|
||
|
hr = HrFindLanConnection(pConMan, pOptions->szLanConnection, &pcon);
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
NETCON_PROPERTIES * pProps;
|
||
|
|
||
|
hr = pcon->GetProperties(&pProps);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
if (pOptions->fConnect)
|
||
|
{
|
||
|
if (pProps->Status != NCS_CONNECTED)
|
||
|
{
|
||
|
pcon->Connect();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "%S is already connected.\n",
|
||
|
pOptions->szLanConnection);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (pProps->Status != NCS_DISCONNECTED)
|
||
|
{
|
||
|
pcon->Disconnect();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "%S is already disconnected.\n",
|
||
|
pOptions->szLanConnection);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
FreeNetconProperties(pProps);
|
||
|
}
|
||
|
}
|
||
|
else if (S_FALSE == hr)
|
||
|
{
|
||
|
g_pDiagCtx->Printf(ttidNcDiag, "Could not find match for connection name: %S\n",
|
||
|
pOptions->szLanConnection);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
EXTERN_C
|
||
|
VOID
|
||
|
WINAPI
|
||
|
NetManDiagFromCommandArgs (DIAG_OPTIONS *pOptions)
|
||
|
{
|
||
|
Assert (pOptions);
|
||
|
Assert (pOptions->pDiagCtx);
|
||
|
g_pDiagCtx = pOptions->pDiagCtx;
|
||
|
|
||
|
INetConnectionManager * pConMan;
|
||
|
|
||
|
HrInitializeConMan(&pConMan);
|
||
|
|
||
|
switch (pOptions->Command)
|
||
|
{
|
||
|
case CMD_SHOW_LAN_CONNECTIONS:
|
||
|
CmdShowLanConnections(pOptions, pConMan);
|
||
|
break;
|
||
|
|
||
|
case CMD_SHOW_ALL_DEVICES:
|
||
|
CmdShowAllDevices(pOptions, pConMan);
|
||
|
break;
|
||
|
|
||
|
case CMD_SHOW_LAN_DETAILS:
|
||
|
CmdShowLanDetails(pOptions, pConMan);
|
||
|
break;
|
||
|
|
||
|
case CMD_LAN_CHANGE_STATE:
|
||
|
CmdLanChangeState(pOptions, pConMan);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
HrUninitializeConMan(pConMan);
|
||
|
|
||
|
g_pDiagCtx = NULL;
|
||
|
}
|
||
|
|