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

409 lines
12 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1999.
//
// File: P N P B I N D . C P P
//
// Contents: This module is responsible for sending BIND, UNBIND, UNLOAD
// and RECONFIGURE PnP notifications to NDIS and TDI drivers.
//
// Notes:
//
// Author: shaunco 17 Feb 1999
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include "nceh.h"
#include "ncras.h"
#include "ndispnp.h"
#include "netcfg.h"
UINT
GetPnpLayerForBindPath (
IN const CBindPath* pBindPath)
{
const CComponent* pComponent;
UINT Layer;
// Get the component below the component we would be sending the
// BIND or UNBIND to.
//
Assert (pBindPath->CountComponents() > 1);
pComponent = *(pBindPath->begin() + 1);
if (FIsEnumerated(pComponent->Class()))
{
Layer = NDIS;
}
else
{
Layer = TDI;
}
Assert ((NDIS == Layer) || (TDI == Layer));
return Layer;
}
HRESULT
HrPnpBindOrUnbind (
IN UINT Layer,
IN UINT Operation,
IN PCWSTR pszComponentBindName,
IN PCWSTR pszBindString)
{
HRESULT hr;
UNICODE_STRING LowerString;
UNICODE_STRING UpperString;
UNICODE_STRING BindList;
Assert ((NDIS == Layer) || (TDI == Layer));
Assert ((BIND == Operation) || (UNBIND == Operation));
Assert (pszComponentBindName && *pszComponentBindName);
Assert (pszBindString && *pszBindString);
hr = S_OK;
TraceTag (ttidNetCfgPnp, "PnP Event: %s %s %S - %S",
(NDIS == Layer) ? "NDIS" : "TDI",
(BIND == Operation) ? "BIND" : "UNBIND",
pszComponentBindName,
pszBindString);
g_pDiagCtx->Printf (ttidBeDiag, " PnP Event: %s %s %S - %S\n",
(NDIS == Layer) ? "NDIS" : "TDI",
(BIND == Operation) ? "BIND" : "UNBIND",
pszComponentBindName,
pszBindString);
RtlInitUnicodeString (&LowerString, pszBindString);
RtlInitUnicodeString (&UpperString, pszComponentBindName);
// Special case for NetBIOS until it can change its bind handler.
// It blindly dereferences the bind list so we need to make sure it
// gets down there with a valid (but empty) buffer. For some reason,
// the buffer doesn't make it down to kernel mode unless .Length is
// non-zero. .MaximumLength is the same as .Length in this case which
// seems odd. (The old binding engine sent it this way.)
//
// RtlInitUnicodeString (&BindList, L""); (doesn't work because it
// sets .Length to zero.)
//
BindList.Buffer = L"";
BindList.Length = sizeof(WCHAR);
BindList.MaximumLength = sizeof(WCHAR);
NC_TRY
{
if (!(g_pDiagCtx->Flags() & DF_DONT_DO_PNP_BINDS) ||
(BIND != Operation))
{
BOOL fOk;
fOk = NdisHandlePnPEvent (
Layer,
Operation,
&LowerString,
&UpperString,
&BindList,
NULL, 0);
if (!fOk)
{
DWORD dwError = GetLastError();
// Map TDI's version of file not found to the right error.
//
if ((TDI == Layer) && (ERROR_GEN_FAILURE == dwError))
{
dwError = ERROR_FILE_NOT_FOUND;
}
// ERROR_FILE_NOT_FOUND for UNBIND means it it wasn't
// bound to begin with. This is okay.
//
// ERROR_FILE_NOT_FOUND for BIND means one of the drivers
// (above or below) wasn't started. This is okay too.
//
if (ERROR_FILE_NOT_FOUND == dwError)
{
Assert (S_OK == hr);
}
else
{
g_pDiagCtx->Printf (ttidBeDiag, " ^^^ Error = %d\n", dwError);
hr = HRESULT_FROM_WIN32(dwError);
}
}
}
}
NC_CATCH_ALL
{
hr = E_UNEXPECTED;
}
TraceHr (ttidError, FAL, hr, FALSE,
"HrPnpBindOrUnbind: %s %s %S - %S\n",
(NDIS == Layer) ? "NDIS" : "TDI",
(BIND == Operation) ? "BIND" : "UNBIND",
pszComponentBindName,
pszBindString);
return hr;
}
HRESULT
HrPnpUnloadDriver (
IN UINT Layer,
IN PCWSTR pszComponentBindName)
{
HRESULT hr;
UNICODE_STRING LowerString;
UNICODE_STRING UpperString;
UNICODE_STRING BindList;
Assert ((NDIS == Layer) || (TDI == Layer));
Assert (pszComponentBindName && *pszComponentBindName);
hr = S_OK;
TraceTag (ttidNetCfgPnp, "PnP Event: UNLOAD %S",
pszComponentBindName);
g_pDiagCtx->Printf (ttidBeDiag, " PnP Event: UNLOAD %S\n",
pszComponentBindName);
RtlInitUnicodeString (&LowerString, NULL);
RtlInitUnicodeString (&UpperString, pszComponentBindName);
RtlInitUnicodeString (&BindList, NULL);
NC_TRY
{
BOOL fOk;
fOk = NdisHandlePnPEvent (
Layer,
UNLOAD,
&LowerString,
&UpperString,
&BindList,
NULL, 0);
if (!fOk)
{
DWORD dwError = GetLastError();
// ERROR_GEN_FAILURE for UNLOAD means the driver does not
// support UNLOAD. This is okay.
//
if (ERROR_GEN_FAILURE == dwError)
{
g_pDiagCtx->Printf (ttidBeDiag, " %S does not support UNLOAD. "
"(Okay)\n",
pszComponentBindName);
Assert (S_OK == hr);
}
else
{
g_pDiagCtx->Printf (ttidBeDiag, " ^^^ Error = %d\n", dwError);
hr = HRESULT_FROM_WIN32(dwError);
}
}
}
NC_CATCH_ALL
{
hr = E_UNEXPECTED;
}
// UNLOADs are informational, so we do not trace any errors.
//
//TraceHr (ttidError, FAL, hr, FALSE,
// "HrPnpUnloadDriver: UNLOAD %S\n",
// pszComponentBindName);
return hr;
}
VOID
CRegistryBindingsContext::PnpBindOrUnbindBindPaths (
IN UINT Operation,
IN const CBindingSet* pBindSet,
OUT BOOL* pfRebootNeeded)
{
HRESULT hr;
const CBindPath* pBindPath;
CBindPath::const_iterator iter;
const CComponent* pComponent;
WCHAR szBind [_MAX_BIND_LENGTH];
UINT Layer;
Assert ((BIND == Operation) || (UNBIND == Operation));
Assert (pBindSet);
Assert (pfRebootNeeded);
*pfRebootNeeded = FALSE;
for (pBindPath = pBindSet->begin();
pBindPath != pBindSet->end();
pBindPath++)
{
Assert (pBindPath->CountComponents() > 1);
// Special case for multiple interfaces. Unless this is the
// length 2 bindpath of protocol to adapter (e.g. tcpip->ndiswanip),
// check to see if the adapter on this bindpath expose multiple
// interfaces from its protocol. If it does, we're going to skip
// sending bind notifications.
//
// The reason we only do this for bindpaths of length greater than
// two is because the protocol exposes multiple-interfaces but does
// not deal with them in its direct binding (i.e. length 2) to the
// adapter.
//
// Note: in future versions, we may not want to skip it. We do so
// for now because the legacy binding engine skips them and these
// bindings aren't active until RAS calls are made anyhow.
//
if (pBindPath->CountComponents() > 2)
{
const CComponent* pAdapter;
DWORD cInterfaces;
// Get the last component in the bindpath and the component
// just above that. The last component is the adapter,
// and the one above the adapter is the protocol.
//
iter = pBindPath->end();
Assert (iter - 2 > pBindPath->begin());
pComponent = *(iter - 2);
pAdapter = *(iter - 1);
Assert (pComponent);
Assert (pAdapter);
Assert (pAdapter == pBindPath->PLastComponent());
// Calling HrGetInterfaceIdsForAdapter requires the INetCfgComponent
// interface for the adapter. If we don't have it, it is likely
// because the adapter has been removed in which case we don't
// need to bother asking about how many interfaces it supports.
//
if (pComponent->m_pIComp && pAdapter->m_pIComp)
{
hr = pComponent->Notify.HrGetInterfaceIdsForAdapter (
m_pNetConfig->Notify.PINetCfg(),
pAdapter,
&cInterfaces,
NULL);
// If multiple interfaces supported for the adapter,
// continue to the next bindpath.
//
if (S_OK == hr)
{
continue;
}
// On S_FALSE or an error, continue below.
hr = S_OK;
}
}
wcscpy (szBind, L"\\Device\\");
// Skip the first component in each path because it is the
// component we are issuing the BIND/UNBIND for.
//
for (iter = pBindPath->begin() + 1;
iter != pBindPath->end();
iter++)
{
pComponent = *iter;
Assert (pComponent);
// Assert there is enough room in the bind buffer.
//
Assert (wcslen(szBind) + 1 + wcslen(pComponent->Ext.PszBindName())
< celems(szBind));
// If this isn't the first component to come after \Device\,
// add underscores to seperate the components.
//
if (iter != (pBindPath->begin() + 1))
{
wcscat (szBind, L"_");
}
wcscat (szBind, pComponent->Ext.PszBindName());
}
Layer = GetPnpLayerForBindPath (pBindPath);
hr = HrPnpBindOrUnbind (
Layer,
Operation,
pBindPath->POwner()->Ext.PszBindName(),
szBind);
if (S_OK != hr)
{
*pfRebootNeeded = TRUE;
}
}
}
VOID
PruneNdisWanBindPathsIfActiveRasConnections (
IN CBindingSet* pBindSet,
OUT BOOL* pfRebootNeeded)
{
CBindPath* pBindPath;
UINT Layer;
BOOL fExistActiveRasConnections;
Assert (pBindSet);
Assert (pfRebootNeeded);
*pfRebootNeeded = FALSE;
// Special case for binding/unbinding from ndiswan miniports while
// active RAS connections exist. (Don't do it.) (BUG 344504)
// (Binding will be to the NDIS layer, the bindpath will have two
// components, and the service of the last component will be NdisWan.
// (These are ndiswan miniport devices that behave badly if we
// unbind them while active connections exist. Binding them also
// can disconnect any connections they might be running.)
// Order of the if is to do the inexpensive checks first.
//
if (!FExistActiveRasConnections ())
{
return;
}
pBindPath = pBindSet->begin();
while (pBindPath != pBindSet->end())
{
Assert (pBindPath->CountComponents() > 1);
Layer = GetPnpLayerForBindPath (pBindPath);
if ((2 == pBindPath->CountComponents()) &&
(NDIS == Layer) &&
(0 == _wcsicmp (L"NdisWan", pBindPath->back()->Ext.PszService())))
{
g_pDiagCtx->Printf (ttidBeDiag, " Skipping PnP BIND/UNBIND for %S -> %S (active RAS connections)\n",
pBindPath->POwner()->Ext.PszBindName(),
pBindPath->back()->Ext.PszBindName());
*pfRebootNeeded = TRUE;
pBindSet->erase (pBindPath);
}
else
{
pBindPath++;
}
}
}