//+--------------------------------------------------------------------------- // // 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 #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. // }