//+--------------------------------------------------------------------------- // // 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++; } } }