409 lines
12 KiB
C++
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++;
|
|
}
|
|
}
|
|
}
|
|
|