windows-nt/Source/XPSP1/NT/net/config/netcfg/engine/filtdevs.cpp
2020-09-26 16:20:57 +08:00

867 lines
24 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1999.
//
// File: F I L T D E V S . C P P
//
// Contents: Implements the basic datatype for a collection of filter
// devices.
//
// Notes:
//
// Author: shaunco 15 Jan 1999
//
//----------------------------------------------------------------------------
#include <pch.h>
#pragma hdrstop
#include "classinst.h"
#include "filtdevs.h"
#include "nceh.h"
#include "ncreg.h"
#include "ncstl.h"
#include "ncsetup.h"
CFilterDevices::CFilterDevices (
IN CNetConfigCore* pCore)
{
Assert (pCore);
ZeroMemory (this, sizeof(*this));
m_pCore = pCore;
}
CFilterDevices::~CFilterDevices ()
{
// Free had better have been called before this.
//
Assert (this);
Assert (!m_hdi);
Assert (!m_pmszFilterClasses);
Assert (empty());
}
HRESULT
CFilterDevices::HrInsertFilterDevice (
IN CFilterDevice* pDevice)
{
HRESULT hr;
Assert (this);
Assert (pDevice);
// Assert there is not already a device in the list with the
// same instance guid.
//
Assert (!PFindFilterDeviceByInstanceGuid (pDevice->m_szInstanceGuid));
// Assert there is not already a device in the list with the
// same parent filter AND the same filtered adapter.
//
Assert (!PFindFilterDeviceByAdapterAndFilter (
pDevice->m_pAdapter,
pDevice->m_pFilter));
NC_TRY
{
push_back (pDevice);
hr = S_OK;
}
NC_CATCH_ALL
{
hr = E_OUTOFMEMORY;
}
TraceHr (ttidError, FAL, hr, FALSE, "CFilterDevices::HrInsertFilterDevice");
return hr;
}
HRESULT
CFilterDevices::HrPrepare ()
{
HRESULT hr;
HKEY hkeyNetwork;
// Reserve room for 8 different filters in our internal member.
// We use this component list at various times as "scratch space" when
// figuring out which filters are enabled for an adapter.
//
hr = m_Filters.HrReserveRoomForComponents (8);
if (S_OK != hr)
{
goto finished;
}
hr = m_BindPathsToRebind.HrReserveRoomForBindPaths (8);
if (S_OK != hr)
{
goto finished;
}
// Load the FilterClasses multi-sz.
//
hr = HrOpenNetworkKey (KEY_READ, &hkeyNetwork);
if (S_OK == hr)
{
hr = HrRegQueryMultiSzWithAlloc (
hkeyNetwork,
L"FilterClasses",
&m_pmszFilterClasses);
if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
{
Assert (!m_pmszFilterClasses);
hr = S_OK;
}
RegCloseKey (hkeyNetwork);
}
finished:
TraceHr (ttidError, FAL, hr, FALSE, "CFilterDevices::HrPrepare");
return hr;
}
CFilterDevice*
CFilterDevices::PFindFilterDeviceByAdapterAndFilter (
IN const CComponent* pAdapter,
IN const CComponent* pFilter) const
{
const_iterator iter;
CFilterDevice* pDevice;
Assert (this);
Assert (pAdapter);
Assert (pFilter);
Assert (FIsEnumerated(pAdapter->Class()));
Assert (NC_NETSERVICE == pFilter->Class());
Assert (pFilter->FIsFilter());
for (iter = begin(); iter != end(); iter++)
{
pDevice = *iter;
Assert (pDevice);
if ((pAdapter == pDevice->m_pAdapter) &&
(pFilter == pDevice->m_pFilter))
{
return pDevice;
}
}
return NULL;
}
DWORD
CFilterDevices::MapFilterClassToOrdinal (
IN PCWSTR pszFilterClass)
{
DWORD Ordinal;
DWORD dwIndex;
DWORD cStrings;
Assert (pszFilterClass);
#if DBG
Ordinal = 0;
#endif
// If the class is found in the list, return its position.
//
if (FGetSzPositionInMultiSzSafe (
pszFilterClass,
m_pmszFilterClasses,
&dwIndex,
NULL,
&cStrings))
{
Ordinal = dwIndex + 1;
}
else
{
HRESULT hr;
PWSTR pmszNew;
BOOL fChanged;
// We're adding another string, so compute the new ordinal value
// for return.
//
Ordinal = cStrings + 1;
// String was not found, so we append it at the end.
// It is important to insert at the end so we don't have to
// change the ordinals of any existing filters that already
// had their ordinal computed.
//
hr = HrAddSzToMultiSz (pszFilterClass, m_pmszFilterClasses,
STRING_FLAG_ENSURE_AT_END, 0, &pmszNew, &fChanged);
if (S_OK == hr)
{
HKEY hkeyNetwork;
// It better have changed because we didn't find the string
// above.
//
Assert (fChanged);
// Out with the old. In with the new.
//
MemFree (m_pmszFilterClasses);
m_pmszFilterClasses = pmszNew;
// Save it back to the registry.
//
hr = HrOpenNetworkKey (KEY_WRITE, &hkeyNetwork);
if (S_OK == hr)
{
hr = HrRegSetMultiSz (
hkeyNetwork,
L"FilterClasses",
m_pmszFilterClasses);
Assert (S_OK == hr);
RegCloseKey (hkeyNetwork);
}
}
}
// By definition, Ordinal is 1-based. This is so that when stored
// in CComponent, we know we have to load the filter class and get
// its ordinal if CComponent::FilterClassOrdinal is zero. i.e. zero
// is a sentinel value that means we need to do work and when non-zero
// means we don't have to do that work again.
//
Assert (Ordinal != 0);
return Ordinal;
}
CFilterDevice*
CFilterDevices::PFindFilterDeviceByInstanceGuid (
IN PCWSTR pszInstanceGuid) const
{
const_iterator iter;
CFilterDevice* pDevice;
Assert (this);
Assert (pszInstanceGuid && *pszInstanceGuid);
for (iter = begin(); iter != end(); iter++)
{
pDevice = *iter;
Assert (pDevice);
if (0 == wcscmp(pszInstanceGuid, pDevice->m_szInstanceGuid))
{
return pDevice;
}
}
return NULL;
}
HRESULT
CFilterDevices::HrLoadFilterDevice (
IN SP_DEVINFO_DATA* pdeid,
IN HKEY hkeyInstance,
IN PCWSTR pszFilterInfId,
OUT BOOL* pfRemove)
{
HRESULT hr;
CComponent* pAdapter;
CComponent* pFilter;
WCHAR szInstanceGuid [c_cchGuidWithTerm];
DWORD cbBuffer;
Assert (pszFilterInfId && *pszFilterInfId);
Assert (pfRemove);
*pfRemove = FALSE;
// Initialize these to NULL. If we don't find them below, they will
// remain NULL and this will tell us something.
//
pAdapter = NULL;
pFilter = NULL;
cbBuffer = sizeof(szInstanceGuid);
hr = HrRegQuerySzBuffer (
hkeyInstance,
L"NetCfgInstanceId",
szInstanceGuid, &cbBuffer);
if (S_OK == hr)
{
HKEY hkeyLinkage;
// Read the RootDevice registry value for this filter device. The
// last entry in that multi-sz will be the bindname of the adapter
// being filtered.
//
hr = HrRegOpenKeyEx (
hkeyInstance,
L"Linkage",
KEY_READ,
&hkeyLinkage);
if (S_OK == hr)
{
PWSTR pmszRootDevice;
hr = HrRegQueryMultiSzWithAlloc (
hkeyLinkage,
L"RootDevice",
&pmszRootDevice);
if (S_OK == hr)
{
PCWSTR pszScan;
PCWSTR pszLastDevice = NULL;
// Scan to the last string in the multi-sz and note it.
//
for (pszScan = pmszRootDevice;
*pszScan;
pszScan += wcslen(pszScan) + 1)
{
pszLastDevice = pszScan;
}
// The last string in the multi-sz is the bindname of the
// adapter being filtered.
//
if (pszLastDevice)
{
pAdapter = m_pCore->Components.PFindComponentByBindName (
NC_NET, pszLastDevice);
if (!pAdapter)
{
hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
}
}
MemFree (pmszRootDevice);
}
RegCloseKey (hkeyLinkage);
}
if (S_OK == hr)
{
// Should have the adapter if no error.
//
Assert (pAdapter);
// Get the enabled filters for the adapter.
//
hr = m_pCore->HrGetFiltersEnabledForAdapter (pAdapter, &m_Filters);
if (S_OK == hr)
{
// Use pszFilterInfId to find the parent filter component for
// this filter device. If it is not found, it probably means
// the entire filter is in the process of being removed.
// (Or the registry was messed with.)
//
pFilter = m_pCore->Components.PFindComponentByInfId (
pszFilterInfId, NULL);
// If the filter corresponding to this device is still
// installed and is enabled over the adapter, then we'll
// insert the device into our list. Otherwise, we're going
// to remove it.
//
if (pFilter && m_Filters.FComponentInList (pFilter))
{
CFilterDevice* pFilterDevice;
// Create an instance of the filter device class to
// represent this filter device.
//
hr = CFilterDevice::HrCreateInstance (
pAdapter,
pFilter,
pdeid,
szInstanceGuid,
&pFilterDevice);
if (S_OK == hr)
{
// Add the filter device to our list of filter devices.
//
hr = HrInsertFilterDevice (pFilterDevice);
if (S_OK != hr)
{
delete pFilterDevice;
}
}
}
else
{
*pfRemove = TRUE;
Assert (pszFilterInfId && *pszFilterInfId);
Assert (pAdapter);
g_pDiagCtx->Printf (ttidBeDiag,
" Removing filter device for %S over %S adapter\n",
pszFilterInfId,
pAdapter->m_pszPnpId);
// Since we will be removing a filter device from the
// chain, we need to rebind the protocols above the
// adapter we are removing the filter device for.
//
// So, get the upper bindings of the adapter (bindpaths
// are only 2 levels deep) and add them to the bind set
// that we will rebind later on.
//
hr = m_pCore->HrGetComponentUpperBindings (
pAdapter,
GBF_ADD_TO_BINDSET | GBF_PRUNE_DISABLED_BINDINGS,
&m_BindPathsToRebind);
}
}
}
}
TraceHr (ttidError, FAL, hr,
HRESULT_FROM_WIN32(ERROR_NOT_FOUND) == hr,
"CFilterDevices::HrLoadFilterDevice");
return hr;
}
VOID
CFilterDevices::LoadAndRemoveFilterDevicesIfNeeded ()
{
HRESULT hr;
SP_DEVINFO_DATA deid;
DWORD dwIndex;
DWORD cbBuffer;
WCHAR szFilterInfId [_MAX_PATH];
Assert (this);
Assert (m_pCore);
Assert (!m_hdi);
Assert (empty());
// Filter devices can only be of net class.
//
hr = HrSetupDiGetClassDevs (&GUID_DEVCLASS_NET, NULL, NULL,
DIGCF_PROFILE, &m_hdi);
if (S_OK != hr)
{
return;
}
Assert (m_hdi);
// Enumerate all net class devices from setupapi.
//
for (dwIndex = 0; S_OK == hr; dwIndex++)
{
hr = HrSetupDiEnumDeviceInfo (m_hdi, dwIndex, &deid);
if (S_OK == hr)
{
HKEY hkeyInstance;
hr = HrSetupDiOpenDevRegKey (
m_hdi, &deid,
DICS_FLAG_GLOBAL, 0, DIREG_DRV,
KEY_READ, &hkeyInstance);
if (S_OK == hr)
{
// If the device has a "FilterInfId" value under its
// instance key, its one of ours.
//
cbBuffer = sizeof(szFilterInfId);
hr = HrRegQuerySzBuffer (
hkeyInstance,
L"FilterInfId",
szFilterInfId,
&cbBuffer);
if (S_OK == hr)
{
BOOL fRemove;
// Load the rest of the filter device, and add it to
// our list. If this fails for any reason, remove the
// filter device because its of no use to us anymore.
//
hr = HrLoadFilterDevice (
&deid,
hkeyInstance,
szFilterInfId,
&fRemove);
if ((S_OK != hr) || fRemove)
{
if (S_OK != hr)
{
g_pDiagCtx->Printf (ttidBeDiag,
" Removing filter device for %S\n",
szFilterInfId);
}
(VOID) HrCiRemoveFilterDevice (m_hdi, &deid);
hr = S_OK;
}
}
//else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
//{
// Not a filter device. Skip it.
//}
RegCloseKey (hkeyInstance);
}
// Allow the loop to continue;
//
hr = S_OK;
}
}
if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr)
{
hr = S_OK;
}
g_pDiagCtx->Printf (ttidBeDiag, " Loaded %d filter devices\n", size());
}
VOID
CFilterDevices::InstallFilterDevicesIfNeeded ()
{
HRESULT hr;
CComponentList::iterator iterAdapter;
CComponentList::iterator iterFilter;
CComponent* pAdapter;
CComponent* pFilter;
HKEY hkeyInstance;
HKEY hkeyNdi;
DWORD cbBuffer;
BOOL fAddDevice;
BOOL fAddedDeviceForAdapter;
WCHAR szFilterDeviceInfId [_MAX_PATH];
WCHAR szFilterClass [_MAX_PATH];
Assert (this);
Assert (m_pCore);
// If, for some reason, we couldn't get m_hdi up in
// RemoveFilterDevicesIfNeeded, we can't proceed.
//
if (!m_hdi)
{
return;
}
// For all adapters (because filters possibly bind to any adapter)
// we get the filters enabled for each. For each on of these filters
// that don't already have an associated filter device for the adapter,
// we create a new one and associated it.
//
for (iterAdapter = m_pCore->Components.begin();
iterAdapter != m_pCore->Components.end();
iterAdapter++)
{
pAdapter = *iterAdapter;
Assert (pAdapter);
// Skip components that are not network adapters.
//
if (NC_NET != pAdapter->Class())
{
continue;
}
hr = m_pCore->HrGetFiltersEnabledForAdapter (pAdapter, &m_Filters);
if (S_OK != hr)
{
// More than likely, we are out of memory.
//
TraceHr (ttidError, FAL, hr, FALSE,
"HrGetFiltersEnabledForAdapter failed in "
"InstallFilterDevicesIfNeeded. Adapter=%S",
pAdapter->m_pszPnpId);
break;
}
// We haven't yet added any devices for this adapter.
//
fAddedDeviceForAdapter = FALSE;
// For each of the filters enabled for this adapter, install
// a filter device if needed and make sure the filter has its
// ordinal position with respect other filters read from the
// registry. We need m_dwFilterClassOrdinal to be valid (non-zero)
// before we sort the filter devices when writing their bindings.
//
for (iterFilter = m_Filters.begin();
iterFilter != m_Filters.end();
iterFilter++)
{
pFilter = *iterFilter;
Assert (pFilter);
// If there isn't a filter device for the current adapter
// and filter, we need to install one.
//
fAddDevice = !PFindFilterDeviceByAdapterAndFilter (
pAdapter, pFilter);
// If we don't need to add a filter device and we already
// have the ordinal position of the filter, we can continue with
// the next filter for this adapter.
//
if (!fAddDevice && (0 != pFilter->m_dwFilterClassOrdinal))
{
continue;
}
*szFilterDeviceInfId = 0;
// Open the instance key of the filter so we can read
// a few values.
//
hr = pFilter->HrOpenInstanceKey (KEY_READ, &hkeyInstance,
NULL, NULL);
if (S_OK == hr)
{
// Open the Ndi key.
//
hr = HrRegOpenKeyEx (hkeyInstance, L"Ndi",
KEY_READ, &hkeyNdi);
if (S_OK == hr)
{
if (0 == pFilter->m_dwFilterClassOrdinal)
{
// Read the filter class and convert it to an
// ordinal based on its position in the
// filter classes list.
//
cbBuffer = sizeof(szFilterClass);
hr = HrRegQuerySzBuffer (hkeyNdi,
L"FilterClass",
szFilterClass,
&cbBuffer);
if (S_OK == hr)
{
pFilter->m_dwFilterClassOrdinal =
MapFilterClassToOrdinal (szFilterClass);
}
}
if (fAddDevice)
{
// Read the ind id of the filter device.
//
cbBuffer = sizeof(szFilterDeviceInfId);
hr = HrRegQuerySzBuffer (
hkeyNdi, L"FilterDeviceInfId",
szFilterDeviceInfId, &cbBuffer);
}
RegCloseKey (hkeyNdi);
}
RegCloseKey (hkeyInstance);
}
if ((S_OK == hr) && fAddDevice)
{
CFilterDevice* pFilterDevice;
Assert (*szFilterDeviceInfId);
g_pDiagCtx->Printf (ttidBeDiag,
" Installing filter device for %S over %S adapter\n",
pFilter->m_pszInfId,
pAdapter->m_pszPnpId);
hr = HrCiInstallFilterDevice (m_hdi,
szFilterDeviceInfId,
pAdapter,
pFilter,
&pFilterDevice);
if (S_OK == hr)
{
hr = HrInsertFilterDevice (pFilterDevice);
if (S_OK == hr)
{
fAddedDeviceForAdapter = TRUE;
}
else
{
delete pFilterDevice;
}
}
}
}
// If we added at least one filter device in the chain for this
// adapter, we'll need to unbind the adapter from whatever it is
// currently bound to before we start the filter device.
//
if (fAddedDeviceForAdapter)
{
// So, get the upper bindings of the adapter (bindpaths
// are only 2 levels deep) and add them to the bind set
// that we will rebind later on.
//
hr = m_pCore->HrGetComponentUpperBindings (
pAdapter,
GBF_ADD_TO_BINDSET | GBF_PRUNE_DISABLED_BINDINGS,
&m_BindPathsToRebind);
}
}
}
INT
__cdecl
CompareFilterDevices (
const VOID* pv1,
const VOID* pv2)
{
CFilterDevice* pDevice1 = *((CFilterDevice**)pv1);
CFilterDevice* pDevice2 = *((CFilterDevice**)pv2);
if (pDevice1->m_pAdapter == pDevice2->m_pAdapter)
{
Assert (pDevice1->m_pFilter != pDevice2->m_pFilter);
if (pDevice1->m_pFilter->m_dwFilterClassOrdinal ==
pDevice2->m_pFilter->m_dwFilterClassOrdinal)
{
AssertSz (0, "We have two filters of the same class installed.");
return 0;
}
return (pDevice1->m_pFilter->m_dwFilterClassOrdinal <
pDevice2->m_pFilter->m_dwFilterClassOrdinal)
? -1 : 1;
}
return (pDevice1->m_pAdapter < pDevice2->m_pAdapter) ? -1 : 1;
/*
if (pDevice1->m_pFilter == pDevice2->m_pFilter)
{
Assert (pDevice1->m_pAdapter != pDevice2->m_pAdapter);
return (pDevice1->m_pAdapter < pDevice2->m_pAdapter) ? -1 : 1;
}
if (pDevice1->m_pFilter->m_dwFilterClassOrdinal ==
pDevice2->m_pFilter->m_dwFilterClassOrdinal)
{
AssertSz (0, "We have two filters of the same class installed.");
return 0;
}
return (pDevice1->m_pFilter->m_dwFilterClassOrdinal <
pDevice2->m_pFilter->m_dwFilterClassOrdinal)
? -1 : 1;
*/
}
VOID
CFilterDevices::SortForWritingBindings ()
{
Assert (this);
// If we're empty, there is nothing to do.
//
if (empty())
{
return;
}
qsort (begin(), size(), sizeof(CFilterDevice*), CompareFilterDevices);
}
VOID
CFilterDevices::StartFilterDevices ()
{
HRESULT hr;
CFilterDevices::reverse_iterator iter;
CFilterDevice* pDevice;
Assert (this);
Assert (m_pCore);
// If we're empty, there is nothing to do.
//
if (empty())
{
return;
}
// If we're not empty, we must have had m_hdi to insert something.
//
Assert (m_hdi);
for (iter = rbegin(); iter != rend(); iter++)
{
pDevice = *iter;
Assert (pDevice);
g_pDiagCtx->Printf (ttidBeDiag, " %S filter over %S adapter\n",
pDevice->m_pFilter->m_pszInfId,
pDevice->m_pAdapter->m_pszPnpId);
hr = HrSetupDiSendPropertyChangeNotification (
m_hdi,
&pDevice->m_deid,
DICS_START,
DICS_FLAG_CONFIGSPECIFIC,
0);
if (S_OK != hr)
{
g_pDiagCtx->Printf (ttidBeDiag, " Failed to start filter device for "
"%S over %S adapter\n",
pDevice->m_pFilter->m_pszInfId,
pDevice->m_pAdapter->m_pszPnpId);
}
}
}
VOID
CFilterDevices::Free ()
{
Assert (this);
MemFree (m_pmszFilterClasses);
m_pmszFilterClasses = NULL;
SetupDiDestroyDeviceInfoListSafe (m_hdi);
m_hdi = NULL;
FreeCollectionAndItem (*this);
// Do NOT free m_BindPathsToRebind. This is used even after ApplyChanges
// calls Free.
//
}