windows-nt/Source/XPSP1/NT/net/wlbs/nlbmgr/inetcfg/niccard.cpp
2020-09-26 16:20:57 +08:00

904 lines
21 KiB
C++

// Copyright (c) Microsoft. All rights reserved.
//
// This is unpublished source code of Microsoft.
// The copyright notice above does not evidence any
// actual or intended publication of such source code.
// OneLiner : Implementation of NICCard
// DevUnit : wlbstest
// Author : Murtaza Hakim
// History:
// --------
//
// Revised by : mhakim
// Date : 02-16-01
// Reason : Added code to find friendly name of nic.
// include files
#include "NICCard.h"
#include <iostream>
#include <devguid.h>
#include <cfg.h>
using namespace std;
// constructor
NICCard::NICCard( IdentifierType type,
wstring id )
:
pnc( NULL ),
nameType( type ),
nicName( id ),
status( NICCard_SUCCESS )
{
HRESULT hr;
// initialize com.
hr = CoInitializeEx(NULL,
COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED );
if( !SUCCEEDED( hr ) )
{
// failure to initialize com
cout << "CoInitializeEx failure " << endl;
// status = COM_FAILURE;
// return;
}
// get INetCfg com interface.
hr = CoCreateInstance( CLSID_CNetCfg,
NULL,
CLSCTX_SERVER,
IID_INetCfg,
(void **) &pnc );
if( !SUCCEEDED( hr ) )
{
// failure to create instance.
cout << "CoCreateInstance failure" << endl;
status = COM_FAILURE;
return;
}
}
// destructor
NICCard::~NICCard()
{
// release resources.
HRESULT hr;
if( pnc )
{
hr = pnc->Release();
pnc = 0;
}
// uninitialize.
CoUninitialize();
}
//+----------------------------------------------------------------------------
//
// Function: NICCard::isBoundTo
//
// Description: whether a component is bound to the adapter
//
// Arguments: wstring component - component id, e.g. "ms_wlbs"
//
// Returns: NICCard::NICCard_Error -
//
// History: Murtaza intitial code
// fengsun Created Header 12/21/00
//
//+----------------------------------------------------------------------------
NICCard::NICCard_Error
NICCard::isBoundTo( wstring component )
{
HRESULT hr;
NICCard_Error err;
INetCfgComponent *pnccNic = NULL;
INetCfgComponent *pnccComponent = NULL;
INetCfgComponentBindings *pnccb = NULL;
// check creation status.
// if not success something went wrong during construction
// and this object cannot be used.
//
if( status != NICCard_SUCCESS )
{
err = status;
goto cleanup;
}
// Initializes network configuration by loading into
// memory all basic networking information
//
hr = pnc->Initialize( NULL );
if( !SUCCEEDED( hr ) )
{
// failure to Initialize
cout << "INetCfg::Initialize failure " << endl;
err = COM_FAILURE;
goto cleanup;
}
// check if physical nic object of nameType, and nicName exists.
//
err = findNIC( nameType,
nicName,
&pnccNic );
if( err != NICCard_SUCCESS )
{
// nic specified does not exist.
wprintf(L"nic specified as %s does not exist\n", nicName.c_str() );
// err value set by findNic
goto cleanup;
}
if (FAILED(hr = pnc->FindComponent(component.c_str(),
&pnccComponent)))
{
// not protocol, service or client. No such component exists.
wprintf(L"component specified as %s does not exist\n", component.c_str() );
err = NO_SUCH_COMPONENT;
goto cleanup;
}
// check if binding exists.
//
hr = pnccComponent->QueryInterface( IID_INetCfgComponentBindings, (void **) &pnccb );
if( !SUCCEEDED( hr ) )
{
cout << "INetCfgComponent::QueryInterface failed " << endl;
err = COM_FAILURE;
goto cleanup;
}
hr = pnccb->IsBoundTo( pnccNic );
if( hr == S_OK )
{
err = BOUND;
}
else if( hr == S_FALSE )
{
err = UNBOUND;
}
else
{
err = COM_FAILURE;
}
goto cleanup;
// free up com resources.
cleanup:
if( pnccb )
{
pnccb->Release();
pnccb = 0;
}
if( pnccComponent )
{
pnccComponent->Release();
pnccComponent = 0;
}
if( pnccNic )
{
pnccNic->Release();
pnccNic = 0;
}
pnc->Uninitialize();
return err;
}
//+----------------------------------------------------------------------------
//
// Function: NICCard::bind
//
// Description: bind a component to the adapter
//
// Arguments: wstring component - component id, e.g. "ms_wlbs"
//
// Returns: NICCard::NICCard_Error -
//
// History: Murtaza intitial code
// fengsun Created Header 12/21/00
//
//+----------------------------------------------------------------------------
NICCard::NICCard_Error
NICCard::bind( wstring component )
{
NICCard_Error err;
err = isBoundTo( component );
if( err == UNBOUND )
{
return toggleState( component );
}
else if( err == BOUND )
{
return NICCard_SUCCESS;
}
else
{
return err;
}
}
//+----------------------------------------------------------------------------
//
// Function: NICCard::unbind
//
// Description: unbind a component to the adapter
//
// Arguments: wstring component - component id, e.g. "ms_wlbs"
//
// Returns: NICCard::NICCard_Error -
//
// History: Murtaza intitial code
// fengsun Created Header 12/21/00
//
//+----------------------------------------------------------------------------
NICCard::NICCard_Error
NICCard::unbind( wstring component )
{
NICCard_Error err;
err = isBoundTo( component );
if( err == BOUND )
{
return toggleState( component );
}
else if( err == UNBOUND )
{
return NICCard_SUCCESS;
}
else
{
return err;
}
}
// private
// returns true if found, else false.
NICCard::NICCard_Error
NICCard::findNIC( IdentifierType type,
wstring nicName,
INetCfgComponent** ppnccNic )
{
HRESULT hr;
IEnumNetCfgComponent* pencc;
INetCfgComponent* pncc;
ULONG countToFetch = 1;
ULONG countFetched;
DWORD characteristics;
wstring name;
LPWSTR pName;
hr = pnc->EnumComponents( &GUID_DEVCLASS_NET,
&pencc );
if( !SUCCEEDED( hr ) )
{
// failure to Enumerate net components
cout << "INetCfg::EnumComponents failure " << endl;
return COM_FAILURE;
}
while( ( hr = pencc->Next( countToFetch, &pncc, &countFetched ) )== S_OK )
{
// here we have been given guid.
if( type == guid )
{
hr = pncc->GetBindName( &pName );
}
else
{
hr = pncc->GetDisplayName( &pName );
}
name = pName;
CoTaskMemFree( pName );
if( name == nicName )
{
*ppnccNic = pncc;
if( pencc )
{
pencc->Release();
pencc = 0;
}
return NICCard_SUCCESS;
}
pncc->Release();
}
if( pencc )
{
pencc->Release();
pencc = 0;
}
*ppnccNic = NULL;
return NO_SUCH_NIC;
}
//+----------------------------------------------------------------------------
//
// Function: NICCard::toggleState
//
// Description: toggle a component binding state to the adapter
//
// Arguments: wstring component - component id, e.g. "ms_wlbs"
//
// Returns: NICCard::NICCard_Error -
//
// History: Murtaza intitial code
// fengsun Created Header 12/21/00
//
//+----------------------------------------------------------------------------
NICCard::NICCard_Error
NICCard::toggleState( wstring component )
{
HRESULT hr;
NICCard_Error err;
INetCfgComponent *pnccNic = NULL;
INetCfgComponent *pnccComponent = NULL;
INetCfgComponentBindings *pnccb = NULL;
INetCfgLock *pncl = NULL;
LPWSTR presentLockHolder = new wchar_t[1000];
// check creation status.
// if not success something went wrong during construction
// and this object cannot be used.
//
if( status != NICCard_SUCCESS )
{
err = status;
goto cleanup;
}
// as this operation can make modifications we require a lock.
// thus get lock.
//
hr = pnc->QueryInterface( IID_INetCfgLock, ( void **) &pncl );
if( !SUCCEEDED( hr ) )
{
cout << "INetCfg QueryInterface for IID_INetCfgLock failed " << endl;
err = COM_FAILURE;
goto cleanup;
}
hr = pncl->AcquireWriteLock( TIME_TO_WAIT,
L"NLBManager",
&presentLockHolder );
if( hr != S_OK )
{
cout << "INetCfgLock::AcquireWriteLock failure is " << hr << endl;
err = COM_FAILURE;
goto cleanup;
}
// Initializes network configuration by loading into
// memory all basic networking information
//
hr = pnc->Initialize( NULL );
if( !SUCCEEDED( hr ) )
{
// failure to Initialize
cout << "INetCfg::Initialize failed with " << hr << endl;
err = COM_FAILURE;
goto cleanup;
}
// check if physical nic object of nameType, and nicName exists.
//
err = findNIC( nameType,
nicName,
&pnccNic );
if( err != NICCard_SUCCESS )
{
// nic specified does not exist.
wprintf(L"nic specified as %s does not exist\n", nicName.c_str() );
goto cleanup;
}
if (FAILED(hr = pnc->FindComponent(component.c_str(),
&pnccComponent)))
{
// not protocol, service or client. No such component exists.
wprintf(L"component specified as %s does not exist\n", component.c_str() );
err = NO_SUCH_COMPONENT;
goto cleanup;
}
// check if binding exists.
//
hr = pnccComponent->QueryInterface( IID_INetCfgComponentBindings, (void **) &pnccb );
if( !SUCCEEDED( hr ) )
{
cout << "INetCfgComponent::QueryInterface failed " << endl;
err = COM_FAILURE;
goto cleanup;
}
hr = pnccb->IsBoundTo( pnccNic );
if( hr == S_OK )
{
hr = pnccb->UnbindFrom( pnccNic );
if( !SUCCEEDED( hr ) )
{
if( hr == NETCFG_E_NO_WRITE_LOCK )
cout << "Unable to obtain write lock. Please verify properties page not already open" << endl;
else
cout << "INetCfgBindings::UnbindFrom failed with " << hr << endl;
err = COM_FAILURE;
}
else
{
// apply the binding change made.
hr = pnc->Apply();
if( !SUCCEEDED( hr ) )
{
cout << "INetCfg::Apply failed with " << hr << endl;
err = COM_FAILURE;
}
else
{
err = NICCard_SUCCESS;
}
}
}
else if( hr == S_FALSE )
{
hr = pnccb->BindTo( pnccNic );
if( !SUCCEEDED( hr ) )
{
if( hr == NETCFG_E_NO_WRITE_LOCK )
cout << "Unable to obtain write lock. Please verify properties page not already open" << endl;
else
cout << "INetCfgBindings::BindTo failed with " << hr << endl;
err = COM_FAILURE;
}
else
{
// apply the binding change made.
hr = pnc->Apply();
if( !SUCCEEDED( hr ) )
{
cout << "INetCfg::Apply failed with " << hr << endl;
err = COM_FAILURE;
}
else
{
err = NICCard_SUCCESS;
}
}
}
else
{
cout << "INetCfgComponentBindings::IsBoundTo failed with " << hr << endl;
err = COM_FAILURE;
}
goto cleanup;
// free up com resources.
cleanup:
if( pnccb )
{
pnccb->Release();
pnccb = 0;
}
if( pnccComponent )
{
pnccComponent->Release();
pnccComponent = 0;
}
if( pnccNic )
{
pnccNic->Release();
pnccNic = 0;
}
if( pnc )
pnc->Uninitialize();
if( pncl )
{
pncl->ReleaseWriteLock();
pncl->Release();
pncl = 0;
}
delete [] presentLockHolder;
return err;
}
// getNics
//
NICCard::NICCard_Error
NICCard::getNics( vector<NICCard::Info>* nicList )
{
HRESULT hr;
INetCfg *pncStatic = 0;
IEnumNetCfgComponent *pencc = 0;
INetCfgComponent *pncc = 0;
wstring name;
LPWSTR pName;
NICCard_Error err;
ULONG countToFetch = 1;
ULONG countFetched;
ULONG status;
Info info;
DWORD characteristics = 0;
// initialize com.
hr = CoInitializeEx(NULL,
COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED );
if( !SUCCEEDED( hr ) )
{
// failure to initialize com
cout << "CoInitializeEx failure " << endl;
// err = COM_FAILURE;
// goto cleanup;
}
// get INetCfg com interface.
hr = CoCreateInstance( CLSID_CNetCfg,
NULL,
CLSCTX_SERVER,
IID_INetCfg,
(void **) &pncStatic );
if( !SUCCEEDED( hr ) )
{
// failure to create instance.
cout << "CoCreateInstance failure" << endl;
err = COM_FAILURE;
goto cleanup;
}
// Initializes network configuration by loading into
// memory all basic networking information
//
hr = pncStatic->Initialize( NULL );
if( !SUCCEEDED( hr ) )
{
// failure to Initialize
cout << "INetCfg::Initialize failure " << endl;
err = COM_FAILURE;
goto cleanup;
}
hr = pncStatic->EnumComponents( &GUID_DEVCLASS_NET,
&pencc );
if( !SUCCEEDED( hr ) )
{
// failure to Enumerate net components
cout << "INetCfg::EnumComponents failure " << endl;
err = COM_FAILURE;
goto cleanup;
}
while( ( hr = pencc->Next( countToFetch, &pncc, &countFetched ) )== S_OK )
{
hr = pncc->GetBindName( &pName );
if( !SUCCEEDED( hr ) )
{
cout << "INetCfgComponent::GetBindName failure " << endl;
err = COM_FAILURE;
goto cleanup;
}
info.guid = pName;
CoTaskMemFree( pName );
hr = pncc->GetDisplayName( &pName );
if( !SUCCEEDED( hr ) )
{
cout << "INetCfgComponent::GetDisplayName failure " << endl;
err = COM_FAILURE;
goto cleanup;
}
info.fullName = pName;
CoTaskMemFree( pName );
hr = pncc->GetCharacteristics( &characteristics );
if( !SUCCEEDED( hr ) )
{
cout << "INetCfgComponent::GetCharacteristics failure " << endl;
err = COM_FAILURE;
goto cleanup;
}
GetFriendlyNICName( info.guid, info.friendlyName );
if( characteristics & NCF_PHYSICAL )
{
// this is a physical network card.
// we are only interested in such devices
// check if the nic is enabled, we are only
// interested in enabled nics.
//
hr = pncc->GetDeviceStatus( &status );
if( !SUCCEEDED( hr ) )
{
cout << "INetCfgComponent::GetDeviceStatus failure " << endl;
err = COM_FAILURE;
goto cleanup;
}
// if any of the nics has any of the problem codes
// then it cannot be used.
if( status != CM_PROB_NOT_CONFIGURED
&&
status != CM_PROB_FAILED_START
&&
status != CM_PROB_NORMAL_CONFLICT
&&
status != CM_PROB_NEED_RESTART
&&
status != CM_PROB_REINSTALL
&&
status != CM_PROB_WILL_BE_REMOVED
&&
status != CM_PROB_DISABLED
&&
status != CM_PROB_FAILED_INSTALL
&&
status != CM_PROB_FAILED_ADD
)
{
// no problem with this nic and also
// physical device
// thus we want it.
nicList->push_back( info );
}
}
if( pncc )
{
pncc->Release();
pncc = 0;
}
characteristics = 0;
countToFetch = 1;
}
err = NICCard_SUCCESS;
cleanup:
if( pncStatic )
{
pncStatic->Uninitialize();
pncStatic->Release();
pncStatic = 0;
}
if( pencc )
{
pencc->Release();
pencc = 0;
}
if( pncc )
{
pncc->Release();
pncc = 0;
}
return err;
}
NICCard::NICCard_Error
NICCard::isNetCfgAvailable()
{
NICCard_Error err;
HRESULT hr;
INetCfgLock *pncl = NULL;
LPWSTR presentLockHolder = new wchar_t[1000];
hr = pnc->QueryInterface( IID_INetCfgLock, ( void **) &pncl );
if( !SUCCEEDED( hr ) )
{
cout << "INetCfg QueryInterface for IID_INetCfgLock failed " << endl;
err = COM_FAILURE;
goto cleanup;
}
hr = pncl->AcquireWriteLock( TIME_TO_WAIT,
L"NLBManager",
&presentLockHolder );
if( hr != S_OK )
{
cout << "INetCfgLock::AcquireWriteLock failure is " << hr << endl;
err = COM_FAILURE;
goto cleanup;
}
err = NICCard_SUCCESS;
cleanup:
if( pncl )
{
pncl->ReleaseWriteLock();
pncl->Release();
pncl = 0;
}
delete [] presentLockHolder;
return err;
}
// code to find friendly name of nic.
// this code is modified for wstring, but
// otherwise is courtesy of hengz.
//
int
NICCard::GetFriendlyNICName(const wstring& guid, wstring& name )
{
// HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Network
HKEY hregkey=NULL, hkOpenKey=NULL, hkQueryKey=NULL;
DWORD dwDataBuffer=200;
DWORD dwValueType=REG_SZ;
wchar_t data[200], path[200], adapters[200];
wchar_t *pHost=NULL;
int num=0, ret;
FILETIME time;
//make connection to the machine's registry
if ((ret=RegConnectRegistry(pHost, HKEY_LOCAL_MACHINE, &hregkey)) != ERROR_SUCCESS) {
// TRACE( MTrace::SEVERE_ERROR, L"(RegConnectRegistry) failure" );
return (-1);
}
//look for the GUID
if( (ret=RegOpenKeyEx(hregkey, L"SYSTEM\\CurrentControlSet\\Control\\Network", 0, KEY_READ, &hkOpenKey)) != ERROR_SUCCESS ) {
RegCloseKey(hregkey);
// TRACE( MTrace::SEVERE_ERROR, L"(RegOpenKeyEx) failed to open HKLM\\SYSTEM\\CurrentControlSet\\Control\\Network" );
return (-1);
}
while (1) {
adapters[0]=L'\0';
dwDataBuffer=200;
if( ((ret=RegEnumKeyEx(hkOpenKey, num, adapters, &dwDataBuffer, NULL,NULL,NULL, &time)) != ERROR_SUCCESS)
&& (ret!=ERROR_MORE_DATA) )
{
if (ret==ERROR_NO_MORE_ITEMS)
{
// TRACE(MTrace::SEVERE_ERROR,L"(RegEnumKeyEx): failed to find network adapters in HKLM\\SYSTEM\\CurrentControlSet\\Control\\Network");
}
else
{
// TRACE(MTrace::SEVERE_ERROR,L"(RegEnumKeyEx): fail to enum HKLM\\SYSTEM\\CurrentControlSet\\Control\\Network" );
}
RegCloseKey(hkOpenKey);
RegCloseKey(hregkey);
return (-1);
}
//open the items one by one
swprintf(path, L"SYSTEM\\CurrentControlSet\\Control\\Network\\%s", adapters);
if( (ret=RegOpenKeyEx(hregkey, path, 0, KEY_READ, &hkQueryKey)) != ERROR_SUCCESS ) {
num++;
continue;
}
dwDataBuffer=200;
data[0]=L'\0';
if((ret=RegQueryValueEx(hkQueryKey, L"", 0, &dwValueType, (LPBYTE)data, &dwDataBuffer)) != ERROR_SUCCESS) {
num++;
continue;
}
RegCloseKey(hkQueryKey);
num++;
if (wcscmp(L"Network Adapters", data)==0)
break;
}
RegCloseKey(hkOpenKey);
//found the guid now
//look for friendly nic name
swprintf(path, L"SYSTEM\\CurrentControlSet\\Control\\Network\\%s\\%s\\Connection", adapters, guid.c_str() );
if( (ret=RegOpenKeyEx(hregkey, path, 0, KEY_READ, &hkOpenKey)) != ERROR_SUCCESS ) {
RegCloseKey(hregkey);
// TRACE(MTrace::SEVERE_ERROR, L"(RegOpenKeyEx) fail to open " + wstring( path ) );
return (-1);
}
dwDataBuffer=200;
data[0]=L'\0';
if((ret=RegQueryValueEx(hkOpenKey, L"Name", 0, &dwValueType, (LPBYTE)data, &dwDataBuffer)) != ERROR_SUCCESS) {
// TRACE(MTrace::SEVERE_ERROR, L"(RegQueryValueEx) fail to query name " + wstring (path ) );
RegCloseKey(hkOpenKey);
RegCloseKey(hregkey);
return (-1);
}
RegCloseKey(hkOpenKey);
RegCloseKey(hregkey);
name = data;
return 0;
}