// nwlnkipx.cpp : Implementation of CNwlnkIPX #include "pch.h" #pragma hdrstop #include #include #include "ncmisc.h" #include "ncnetcfg.h" #include "ncpnp.h" #include "ncreg.h" #include "nwlnkipx.h" extern const WCHAR c_szAdapterSections[]; extern const WCHAR c_szAdapters[]; extern const WCHAR c_szSpecificTo[]; extern const WCHAR c_szSvcNwlnkIpx[]; extern const WCHAR c_szInfId_MS_NWNB[]; extern const WCHAR c_szInfId_MS_NWSPX[]; static const WCHAR c_szProviderOrderVal[] = L"ProviderOrder"; static const WCHAR c_szSrvProvOrderKey[] = L"System\\CurrentControlSet\\Control\\ServiceProvider\\Order"; const WCHAR c_sz0xPrefix[] = L"0x"; const WCHAR c_sz8Zeros[] = L"00000000"; const DWORD c_dwPktTypeDefault = AUTO; const WCHAR c_szMediaType[] = L"MediaType"; static const WCHAR c_szIpxParameters[] = L"System\\CurrentControlSet\\Services\\NwlnkIpx\\Parameters"; static const WCHAR c_szPktType[] = L"PktType"; static const WCHAR c_szNetworkNumber[] = L"NetworkNumber"; static const WCHAR c_szDedicatedRouter[] = L"DedicatedRouter"; static const WCHAR c_szEnableWANRouter[] = L"EnableWANRouter"; static const WCHAR c_szInitDatagrams[] = L"InitDatagrams"; static const WCHAR c_szMaxDatagrams[] = L"MaxDatagrams"; static const WCHAR c_szReplaceConfigDialog[] = L"ReplaceConfigDialog"; static const WCHAR c_szRipCount[] = L"RipCount"; static const WCHAR c_szRipTimeout[] = L"RipTimeout"; static const WCHAR c_szRipUsageTime[] = L"RipUsageTime"; static const WCHAR c_szSocketEnd[] = L"SocketEnd"; static const WCHAR c_szSocketStart[] = L"SocketStart"; static const WCHAR c_szSocketUniqueness[] = L"SocketUniqueness"; static const WCHAR c_szSourceRouteUsageTime[]= L"SourceRouteUsageTime"; static const WCHAR c_szVirtualNetworkNumber[]= L"VirtualNetworkNumber"; static const DWORD c_dwBindSap = 0x8137; static const DWORD c_dwEnableFuncaddr = 1; static const DWORD c_dwMaxPktSize = 0; static const DWORD c_dwSourceRouteBCast = 0; static const DWORD c_dwSourceRouteMCast = 0; static const DWORD c_dwSourceRouteDef = 0; static const DWORD c_dwSourceRouting = 1; static const WCHAR c_szBindSap[] = L"BindSap"; static const WCHAR c_szEnableFuncaddr[] = L"EnableFuncaddr"; static const WCHAR c_szMaxPktSize[] = L"MaxPktSize"; static const WCHAR c_szSourceRouteBCast[] = L"SourceRouteBCast"; static const WCHAR c_szSourceRouteMCast[] = L"SourceRouteMCast"; static const WCHAR c_szSourceRouteDef[] = L"SourceRouteDef"; static const WCHAR c_szSourceRouting[] = L"SourceRouting"; static const DWORD c_dwDedicatedRouter = 0; static const DWORD c_dwEnableWANRouter = 0; static const DWORD c_dwInitDatagrams = 0xa; static const DWORD c_dwMaxDatagrams = 0x32; static const DWORD c_dwReplaceConfigDialog = 0; static const DWORD c_dwRipCount = 0x5; static const DWORD c_dwRipTimeout = 0x1; static const DWORD c_dwRipUsageTime = 0xf; static const DWORD c_dwSocketEnd = 0x5fff; static const DWORD c_dwSocketStart = 0x4000; static const DWORD c_dwSocketUniqueness = 0x8; static const DWORD c_dwSourceRouteUsageTime = 0xf; static const DWORD c_dwVirtualNetworkNumber = 0; static const REGBATCH regbatchIpx[] = { {HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szDedicatedRouter, REG_DWORD, offsetof(IpxParams,dwDedicatedRouter), (BYTE *)&c_dwDedicatedRouter}, {HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szEnableWANRouter, REG_DWORD, offsetof(IpxParams,dwEnableWANRouter), (BYTE *)&c_dwEnableWANRouter}, {HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szInitDatagrams, REG_DWORD, offsetof(IpxParams,dwInitDatagrams), (BYTE *)&c_dwInitDatagrams}, {HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szMaxDatagrams, REG_DWORD, offsetof(IpxParams,dwMaxDatagrams), (BYTE *)&c_dwMaxDatagrams}, {HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szReplaceConfigDialog, REG_DWORD, offsetof(IpxParams,dwReplaceConfigDialog), (BYTE *)&c_dwReplaceConfigDialog}, {HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szRipCount, REG_DWORD, offsetof(IpxParams,dwRipCount), (BYTE *)&c_dwRipCount}, {HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szRipTimeout, REG_DWORD, offsetof(IpxParams,dwRipTimeout), (BYTE *)&c_dwRipTimeout}, {HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szRipUsageTime, REG_DWORD, offsetof(IpxParams,dwRipUsageTime), (BYTE *)&c_dwRipUsageTime}, {HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szSocketEnd, REG_DWORD, offsetof(IpxParams,dwSocketEnd), (BYTE *)&c_dwSocketEnd}, {HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szSocketStart, REG_DWORD, offsetof(IpxParams,dwSocketStart), (BYTE *)&c_dwSocketStart}, {HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szSocketUniqueness, REG_DWORD, offsetof(IpxParams,dwSocketUniqueness), (BYTE *)&c_dwSocketUniqueness}, {HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szSourceRouteUsageTime, REG_DWORD, offsetof(IpxParams,dwSourceRouteUsageTime), (BYTE *)&c_dwSourceRouteUsageTime}, {HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szVirtualNetworkNumber, REG_DWORD, offsetof(IpxParams,dwVirtualNetworkNumber), (BYTE *)&c_dwVirtualNetworkNumber}}; CNwlnkIPX::CNwlnkIPX() : m_pnccMe(NULL), m_pNetCfg(NULL), m_fNetworkInstall(FALSE), m_fAdapterListChanged(FALSE), m_fPropertyChanged(FALSE), m_eInstallAction(eActUnknown), m_pspObj1(NULL), m_pspObj2(NULL), m_pIpxEnviroment(NULL), m_pUnkPropContext(NULL) { } CNwlnkIPX::~CNwlnkIPX() { ReleaseObj(m_pUnkPropContext); ReleaseObj(m_pNetCfg); ReleaseObj(m_pnccMe); delete m_pIpxEnviroment; CleanupPropPages(); } // INetCfgNotify STDMETHODIMP CNwlnkIPX::Initialize ( INetCfgComponent* pncc, INetCfg* pNetCfg, BOOL fInstalling) { HRESULT hr; Validate_INetCfgNotify_Initialize(pncc, pNetCfg, fInstalling); // Hold on to our the component representing us and our host // INetCfg object. AddRefObj (m_pnccMe = pncc); AddRefObj (m_pNetCfg = pNetCfg); // // Determine if the Netware stack is installed, if so DO NOT // install over it. // if (FIsNetwareIpxInstalled()) { //TODO: EventLog(Novell Netware already installed); //$REVIEW: Do we just want to silently proceed an do nothing? } // Query current settings hr = CIpxEnviroment::HrCreate(this, &m_pIpxEnviroment); TraceError("CNwlnkIPX::Initialize",hr); return hr; } STDMETHODIMP CNwlnkIPX::Upgrade(DWORD, DWORD) { return S_FALSE; } STDMETHODIMP CNwlnkIPX::ReadAnswerFile ( PCWSTR pszAnswerFile, PCWSTR pszAnswerSection) { HRESULT hr = S_OK; Validate_INetCfgNotify_ReadAnswerFile(pszAnswerFile, pszAnswerSection ); // Record the fact that this is a network installation m_fNetworkInstall = TRUE; m_eInstallAction = eActInstall; // Only process answer file and install sub-components if the answer file // is present. If the answer file is not present we should already be installed. if (NULL == pszAnswerFile) { goto Error; // Success case } // Read the Answer file contents hr = HrProcessAnswerFile(pszAnswerFile, pszAnswerSection); if (FAILED(hr)) { goto Error; } Error: TraceError("CNwlnkIPX::ReadAnswerFile",hr); return hr; } // // Function: CNwlnkIPX::HrProcessAnswerFile // // Purpose: Process the answer file information, merging // its contents into the internal information // // Parameters: // // Returns: HRESULT, S_OK on success // HRESULT CNwlnkIPX::HrProcessAnswerFile(PCWSTR pszAnswerFile, PCWSTR pszAnswerSection) { CSetupInfFile csif; DWORD dwData; BOOL fValue; HRESULT hr = S_OK; INFCONTEXT infctx; AssertSz(pszAnswerFile, "Answer file string is NULL!"); AssertSz(pszAnswerSection, "Answer file sections string is NULL!"); // Open the answer file. hr = csif.HrOpen(pszAnswerFile, NULL, INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL); if (FAILED(hr)) { goto Error; } // Release all of the adapter specific info Assert(NULL != m_pIpxEnviroment); m_pIpxEnviroment->ReleaseAdapterInfo(); // Read the DedicatedRouter parameter hr = csif.HrGetStringAsBool(pszAnswerSection, c_szDedicatedRouter, &fValue); if (SUCCEEDED(hr)) { m_pIpxEnviroment->SetDedicatedRouter(fValue); } // Read the EnableWANRouter parameter hr = csif.HrGetStringAsBool(pszAnswerSection, c_szEnableWANRouter, &fValue); if (SUCCEEDED(hr)) { m_pIpxEnviroment->SetEnableWANRouter(fValue); } // Read the virtual network number hr = csif.HrGetDword(pszAnswerSection, c_szVirtualNetworkNumber, &dwData); if (SUCCEEDED(hr)) { m_pIpxEnviroment->SetVirtualNetworkNumber(dwData); } // Read the property containing the list of adapter sections hr = ::HrSetupFindFirstLine(csif.Hinf(), pszAnswerSection, c_szAdapterSections, &infctx); if (SUCCEEDED(hr)) { DWORD dwIdx; DWORD dwCnt = SetupGetFieldCount(&infctx); tstring str; // For each adapter in the list read the adapter information for (dwIdx=1; dwIdx <= dwCnt; dwIdx++) { hr = ::HrSetupGetStringField(infctx, dwIdx, &str); if (FAILED(hr)) { TraceError("CNwlnkIPX::HrProcessAnswerFile - Failed to read adapter section name",hr); break; } hr = HrReadAdapterAnswerFileSection(&csif, str.c_str()); if (FAILED(hr)) { goto Error; } } } hr = S_OK; Error: TraceError("CNwlnkIpx::HrProcessAnswerFile", hr); return hr; } // // Function: CNwlnkIPX::HrReadAdapterAnswerFileSection // // Purpose: Read the adapter answer file section and create // the adapter info section if successful // // Parameters: // // Returns: // HRESULT CNwlnkIPX::HrReadAdapterAnswerFileSection(CSetupInfFile * pcsif, PCWSTR pszSection) { HRESULT hr = S_OK; CIpxAdapterInfo * pAI = NULL; INetCfgComponent* pncc = NULL; tstring str; // Read the SpecificTo adapter name hr = pcsif->HrGetString(pszSection, c_szSpecificTo, &str); if (FAILED(hr)) { goto Error; } // Search for the specified adapter in the set of existing adapters hr = ::HrAnswerFileAdapterToPNCC(m_pNetCfg, str.c_str(), &pncc); if (FAILED(hr)) { goto Error; } // if we found the adapter component object (pncc != NULL) process // the adapter section if (pncc) { DWORD dwIdx; DWORD dwCnt; INFCONTEXT infctx; pAI = new CIpxAdapterInfo; Assert(NULL != pAI); // Query the adapter component info hr = ::HrQueryAdapterComponentInfo(pncc, pAI); if (FAILED(hr)) { goto Error; } // Read the PktType (Failure is usually just "not found") hr = ::HrSetupFindFirstLine(pcsif->Hinf(), pszSection, c_szPktType, &infctx); if (SUCCEEDED(hr)) { dwCnt = ::SetupGetFieldCount(&infctx); // For each adapter in the list read the adapter information for (dwIdx=1; dwIdx <= dwCnt; dwIdx++) { hr = ::HrSetupGetStringField(infctx, dwIdx, &str); if (FAILED(hr)) { TraceError("CNwlnkIPX::HrProcessAnswerFile - Failed to read adapter section name",hr); goto Error; } Assert(!str.empty()); // Raid # 205831 - Trim any leading "0x" // if (0 == _wcsnicmp(str.c_str(), c_sz0xPrefix, wcslen(c_sz0xPrefix))) { str.erase(0, wcslen(c_sz0xPrefix)); } pAI->PFrmTypeList()->push_back(new tstring(str)); } } // Default PktType? if (0 == pAI->PFrmTypeList()->size()) { WCHAR szBuf[10]; // If the info was not found or contained no elements, add the // default value. wsprintfW(szBuf,L"%X",c_dwPktTypeDefault); pAI->PFrmTypeList()->push_back(new tstring(szBuf)); } // Read the NetworkNumber hr = ::HrSetupFindFirstLine(pcsif->Hinf(), pszSection, c_szNetworkNumber, &infctx); if (SUCCEEDED(hr)) { dwCnt = SetupGetFieldCount(&infctx); // For each adapter in the list read the adapter information for (dwIdx=1; dwIdx <= dwCnt; dwIdx++) { hr = ::HrSetupGetStringField(infctx, dwIdx, &str); if (FAILED(hr)) { TraceError("CNwlnkIPX::HrProcessAnswerFile - Failed to read adapter section name",hr); goto Error; } Assert(!str.empty()); pAI->PNetworkNumList()->push_back(new tstring(str)); } } // Default Network Number? if (0 == pAI->PNetworkNumList()->size()) { // If the info was not found or contained no elements, add the // default value. pAI->PNetworkNumList()->push_back(new tstring(c_sz8Zeros)); } // Ensure that the network number list has the same number of // elements as the frame type list. This can happen when the user // configures multiple frame types on 3.51 but only one network // number is used. We'll extend the last network number used // and pad it to make the network number list the same size. // Assert (pAI->PNetworkNumList()->size()); while (pAI->PNetworkNumList()->size() < pAI->PFrmTypeList()->size()) { pAI->PNetworkNumList()->push_back( new tstring(*pAI->PNetworkNumList()->back())); } pAI->SetDirty(TRUE); m_pIpxEnviroment->AdapterInfoList().push_back(pAI); MarkAdapterListChanged(); } #ifdef ENABLETRACE else { TraceTag(ttidDefault, "CNwlnkIPX::HrReadAdapterAnswerFileSection - " "Adapter \"%S\" not yet installed.",str.c_str()); } #endif // Normalize return hr = S_OK; Done: ReleaseObj(pncc); return hr; Error: delete pAI; TraceError("CNwlnkIpx::HrReadAdapterAnswerFileSection",hr); goto Done; } STDMETHODIMP CNwlnkIPX::Install (DWORD) { HRESULT hr; CIpxAdapterInfo * pAI; ADAPTER_INFO_LIST::iterator iter; m_eInstallAction = eActInstall; // Mark all the initially detected adapters as dirty for (iter = m_pIpxEnviroment->AdapterInfoList().begin(); iter != m_pIpxEnviroment->AdapterInfoList().end(); iter++) { pAI = *iter; pAI->SetDirty(TRUE); } // Install NwlnkNb. hr = ::HrInstallComponentOboComponent (m_pNetCfg, NULL, GUID_DEVCLASS_NETTRANS, c_szInfId_MS_NWNB, m_pnccMe, NULL); if (FAILED(hr)) { goto Error; } // Install NwlnkSpx. hr = ::HrInstallComponentOboComponent (m_pNetCfg, NULL, GUID_DEVCLASS_NETTRANS, c_szInfId_MS_NWSPX, m_pnccMe, NULL); Error: TraceError("CNwlnkIPX::Install",hr); return hr; } STDMETHODIMP CNwlnkIPX::Removing () { HRESULT hr; m_eInstallAction = eActRemove; // Remove NwlnkNb. hr = ::HrRemoveComponentOboComponent(m_pNetCfg, GUID_DEVCLASS_NETTRANS, c_szInfId_MS_NWNB, m_pnccMe); if (FAILED(hr)) goto Error; // Remove NwlnkSpx. hr = ::HrRemoveComponentOboComponent(m_pNetCfg, GUID_DEVCLASS_NETTRANS, c_szInfId_MS_NWSPX, m_pnccMe); Error: TraceError("CNwlnkIPX::Removing",hr); return hr; } STDMETHODIMP CNwlnkIPX::Validate ( ) { return S_OK; } STDMETHODIMP CNwlnkIPX::CancelChanges () { return S_OK; } STDMETHODIMP CNwlnkIPX::ApplyRegistryChanges () { HRESULT hr = E_INVALIDARG; switch(m_eInstallAction) { case eActInstall: hr = HrCommitInstall(); break; case eActRemove: hr = HrCommitRemove(); break; default: // eActUnknown (Configuration) if (m_fAdapterListChanged || m_fPropertyChanged) { // Update the registry if the adapter list changed Assert(m_pIpxEnviroment); hr = m_pIpxEnviroment->HrUpdateRegistry(); if (SUCCEEDED(hr)) { // Send change notification hr = HrReconfigIpx(); } } break; } TraceError("CNwlnkIPX::ApplyRegistryChanges",hr); return hr; } // INetCfgComponentPropertyUi STDMETHODIMP CNwlnkIPX::SetContext(IUnknown * pUnk) { ReleaseObj(m_pUnkPropContext); m_pUnkPropContext = pUnk; if (m_pUnkPropContext) { AddRefObj(m_pUnkPropContext); } return S_OK; } STDMETHODIMP CNwlnkIPX::MergePropPages ( IN OUT DWORD* pdwDefPages, OUT LPBYTE* pahpspPrivate, OUT UINT* pcPages, IN HWND hwndParent, OUT PCWSTR* pszStartPage) { Validate_INetCfgProperties_MergePropPages ( pdwDefPages, pahpspPrivate, pcPages, hwndParent, pszStartPage); HRESULT hr = S_OK; HPROPSHEETPAGE * ahpsp = NULL; PRODUCT_FLAVOR pf; int nPages = 0; CIpxAdapterInfo * pAI = NULL; Assert(pahpspPrivate); Assert(*pahpspPrivate == NULL); // Out param init done via Validate above *pcPages = 0; // Start with new property pages each time. CleanupPropPages(); // Get the current Adapter if (NULL != m_pUnkPropContext) { CIpxAdapterInfo * pAITmp; INetLanConnectionUiInfo * pLanConn = NULL; ADAPTER_INFO_LIST::iterator iter; hr = m_pUnkPropContext->QueryInterface(IID_INetLanConnectionUiInfo, reinterpret_cast(&pLanConn)); if (SUCCEEDED(hr)) { GUID guid; hr = pLanConn->GetDeviceGuid(&guid); ReleaseObj(pLanConn); if (FAILED(hr)) { goto Error; } // Find the adapter in our adapter list for (iter = m_pIpxEnviroment->AdapterInfoList().begin(); iter != m_pIpxEnviroment->AdapterInfoList().end(); iter++) { pAITmp = *iter; if (guid == *pAITmp->PInstanceGuid()) { pAI = pAITmp; break; } } Assert(SUCCEEDED(hr)); // If we have an adapter but it's // disabled/hidden/deleted we show no pages if ((NULL != pAI) && (pAI->FDeletePending() || pAI->FDisabled() || pAI->FHidden())) { Assert(0 == *pcPages); hr = S_FALSE; goto cleanup; } } else if (E_NOINTERFACE == hr) { // RAS doesn't have the notion of a current adapter hr = S_OK; } } else { // m_pUnkPropContext should have been set first hr = E_UNEXPECTED; } if (FAILED(hr)) { goto Error; } // If the product is not workstation (therefore NTAS) GetProductFlavor(NULL, &pf); if ((PF_WORKSTATION != pf) && (NULL != pAI)) { // Server #ifdef INCLUDE_RIP_ROUTING nPages = 2; #else nPages = 1; #endif // Allocate a buffer large enough to hold the handle to the IPX config. // property page. ahpsp = (HPROPSHEETPAGE *)CoTaskMemAlloc(sizeof(HPROPSHEETPAGE) * nPages); if (!ahpsp) { hr = E_OUTOFMEMORY; goto cleanup; // Alloc failed to no need to free ahpsp } // Allocate the CPropSheetPage objects m_pspObj1 = new CIpxASConfigDlg(this, m_pIpxEnviroment, pAI); #ifdef INCLUDE_RIP_ROUTING m_pspObj2 = new CIpxASInternalDlg(this, m_pIpxEnviroment, pAI); #endif // Create the actual PROPSHEETPAGE for each object. // This needs to be done regardless of whether the classes existed before. ahpsp[0] = m_pspObj1->CreatePage(DLG_IPXAS_CONFIG, 0); #ifdef INCLUDE_RIP_ROUTING ahpsp[1] = m_pspObj2->CreatePage(DLG_IPXAS_INTERNAL, 0); #endif } else { // Workstation nPages = 1; // Allocate a buffer large enough to hold the handle to the IPX config. // property page. ahpsp = (HPROPSHEETPAGE *)CoTaskMemAlloc(sizeof(HPROPSHEETPAGE) * nPages); if (!ahpsp) { hr = E_OUTOFMEMORY; goto cleanup; // Alloc failed to no need to free ahpsp } // Allocate the CPropSheetPage object m_pspObj1 = new CIpxConfigDlg(this, m_pIpxEnviroment, pAI); // Create the actual PROPSHEETPAGE for each object. // This needs to be done regardless of whether the classes existed before. ahpsp[0] = m_pspObj1->CreatePage(DLG_IPX_CONFIG, 0); } if (NULL != ahpsp[0]) { *pahpspPrivate = (LPBYTE)ahpsp; *pcPages = nPages; } else { hr = E_OUTOFMEMORY; goto Error; } cleanup: TraceError("CNwlnkIPX::MergePropPages", hr); return hr; Error: CoTaskMemFree(ahpsp); goto cleanup; } VOID CNwlnkIPX::CleanupPropPages() { delete m_pspObj1; m_pspObj1 = NULL; #ifdef INCLUDE_RIP_ROUTING delete m_pspObj2; m_pspObj2 = NULL; #endif } STDMETHODIMP CNwlnkIPX::ValidateProperties (HWND) { m_fPropertyChanged = TRUE; return S_OK; } STDMETHODIMP CNwlnkIPX::CancelProperties () { return S_OK; } STDMETHODIMP CNwlnkIPX::ApplyProperties () { return S_OK; } // INetCfgComponentNotifyBinding STDMETHODIMP CNwlnkIPX::QueryBindingPath ( DWORD dwChangeFlag, INetCfgBindingPath* pncbpItem ) { return S_OK; } STDMETHODIMP CNwlnkIPX::NotifyBindingPath ( DWORD dwChangeFlag, INetCfgBindingPath* pncbpItem ) { HRESULT hr = S_OK; INetCfgComponent *pnccFound = NULL; Validate_INetCfgBindNotify_NotifyBindingPath( dwChangeFlag, pncbpItem ); Assert(NULL != m_pIpxEnviroment); // Only Interested in lower binding Add's and Remove's if (dwChangeFlag & (NCN_ADD | NCN_REMOVE | NCN_ENABLE | NCN_DISABLE)) { CIterNetCfgBindingInterface ncbiIter(pncbpItem); INetCfgBindingInterface *pncbi; // Enumerate the binding interfaces looking for an Adapter while (SUCCEEDED(hr) && (S_OK == (hr = ncbiIter.HrNext (&pncbi)))) { INetCfgComponent *pncc; hr = pncbi->GetLowerComponent(&pncc); if (S_OK == hr) { GUID guidClass; hr = pncc->GetClassGuid(&guidClass); if ((S_OK == hr) && (GUID_DEVCLASS_NET == guidClass)) { ReleaseObj(pnccFound); pnccFound = pncc; // Transfer Ownership pncc = NULL; } else { ReleaseObj(pncc); } } ReleaseObj(pncbi); } if (FAILED(hr)) goto Error; // Did we find the Adapter? if (pnccFound) { BOOL fFound = FALSE; PWSTR pszBindName = NULL; CIpxAdapterInfo * pAI; ADAPTER_INFO_LIST::iterator iterAdapterInfo; Assert(m_pIpxEnviroment); hr = pnccFound->GetBindName(&pszBindName); if (S_OK != hr) { goto Error; } // Search the adapter list for (iterAdapterInfo = m_pIpxEnviroment->AdapterInfoList().begin(); iterAdapterInfo != m_pIpxEnviroment->AdapterInfoList().end(); iterAdapterInfo++) { pAI = *iterAdapterInfo; Assert (pAI); if (0 == lstrcmpiW(pszBindName, pAI->SzBindName())) { fFound = TRUE; break; } } Assert(pszBindName); CoTaskMemFree(pszBindName); // Apply the appropriate delta to the adapter list if (fFound && (dwChangeFlag & NCN_REMOVE)) { // Mark the adapter as Delete Pending pAI->SetDeletePending(TRUE); m_fAdapterListChanged = TRUE; } else if (!fFound && (dwChangeFlag & NCN_ADD)) { // Add the adapter to the list hr = m_pIpxEnviroment->HrAddAdapter(pnccFound); m_fAdapterListChanged = TRUE; } else if (fFound && (dwChangeFlag & NCN_ADD)) { // Re-enable the adapters existance pAI->SetDeletePending(FALSE); } if (fFound) { if (dwChangeFlag & NCN_ENABLE) { pAI->SetDisabled(FALSE); m_fAdapterListChanged = TRUE; } else if (dwChangeFlag & NCN_DISABLE) { pAI->SetDisabled(TRUE); m_fAdapterListChanged = TRUE; } } } if (SUCCEEDED(hr)) hr = S_OK; // Normailze return value } Error: ReleaseObj(pnccFound); TraceError("CNwlnkIPX::NotifyBindingPath",hr); return hr; } STDMETHODIMP CNwlnkIPX::GetFrameTypesForAdapter(PCWSTR pszAdapterBindName, DWORD cFrameTypesMax, DWORD* anFrameTypes, DWORD* pcFrameTypes) { Assert(pszAdapterBindName); Assert(cFrameTypesMax); Assert(anFrameTypes); Assert(pcFrameTypes); *pcFrameTypes = 0; ADAPTER_INFO_LIST::iterator iterAI; for (iterAI = m_pIpxEnviroment->AdapterInfoList().begin(); iterAI != m_pIpxEnviroment->AdapterInfoList().end(); iterAI++) { CIpxAdapterInfo *pAI = *iterAI; if (0 == lstrcmpW(pszAdapterBindName, pAI->SzBindName())) { list::iterator iterFrmType; for (iterFrmType = pAI->PFrmTypeList()->begin(); (iterFrmType != pAI->PFrmTypeList()->end()) && (*pcFrameTypes < cFrameTypesMax); iterFrmType++) { // Copy the Frame Type tstring *pstr1 = *iterFrmType; anFrameTypes[(*pcFrameTypes)++] = DwFromSz(pstr1->c_str(), 16); } break; } } return S_OK; } STDMETHODIMP CNwlnkIPX::GetVirtualNetworkNumber(DWORD* pdwVNetworkNumber) { HRESULT hr = S_OK; if (NULL == pdwVNetworkNumber) { hr = E_INVALIDARG; goto Error; } Assert(NULL != m_pIpxEnviroment); *pdwVNetworkNumber = m_pIpxEnviroment->DwVirtualNetworkNumber(); Error: TraceError("CNwlnkIPX::GetVirtualNetworkNumber",hr); return hr; } STDMETHODIMP CNwlnkIPX::SetVirtualNetworkNumber(DWORD dwVNetworkNumber) { HRESULT hr; Assert(NULL != m_pIpxEnviroment); m_pIpxEnviroment->SetVirtualNetworkNumber(dwVNetworkNumber); m_fPropertyChanged = TRUE; // Tell INetCfg that our component is dirty INetCfgComponentPrivate* pinccp = NULL; Assert(NULL != m_pnccMe); hr = m_pnccMe->QueryInterface(IID_INetCfgComponentPrivate, reinterpret_cast(&pinccp)); if (SUCCEEDED(hr)) { hr = pinccp->SetDirty(); pinccp->Release(); } return hr; } // // Function: CNwlnkIPX::HrCommitInstall // // Purpose: Commit Installation registry changes to the registry // // Parameters: None // // Returns: HRESULT, S_OK on success // // STDMETHODIMP CNwlnkIPX::HrCommitInstall() { HRESULT hr; Assert(m_pIpxEnviroment); hr = m_pIpxEnviroment->HrUpdateRegistry(); TraceError("CNwlnkIPX::HrCommitInstall",hr); return hr; } // // Function: CNwlnkIPX::HrCommitRemove // // Purpose: Remove from the registry settings which were created by this // component's installation. // // Parameters: None // // Returns: HRESULT, S_OK on success // // STDMETHODIMP CNwlnkIPX::HrCommitRemove() { // Remove "NwlnkIpx" from the: // System\CurrentControlSet\Control\ServiceProvider\Order\ProviderOrder value (void) HrRegRemoveStringFromMultiSz(c_szSvcNwlnkIpx, HKEY_LOCAL_MACHINE, c_szSrvProvOrderKey, c_szProviderOrderVal, STRING_FLAG_REMOVE_ALL); return S_OK; } CIpxAdapterInfo::CIpxAdapterInfo() : m_dwMediaType(ETHERNET_MEDIA), m_fDeletePending(FALSE), m_fDisabled(FALSE), m_fDirty(FALSE), m_dwCharacteristics(0L) { ZeroMemory(&m_guidInstance, sizeof(m_guidInstance)); } CIpxAdapterInfo::~CIpxAdapterInfo() { DeleteColString(&m_lstpstrFrmType); DeleteColString(&m_lstpstrNetworkNum); } CIpxEnviroment::CIpxEnviroment(CNwlnkIPX *pno) { Assert(NULL != pno); m_pno = pno; // Retain the Notification object m_fRipInstalled = FALSE; m_fEnableRip = FALSE; m_dwRipValue = 0; ZeroMemory(&m_IpxParams, sizeof(m_IpxParams)); } CIpxEnviroment::~CIpxEnviroment() { ReleaseAdapterInfo(); // Note: Do nothing with the m_pno notification object, we just borrowed it } // // Member: CIpxEnviroment::ReleaseAdapterInfo // // Purpose: Release the adapter info // // Arguments: none // // Returns: nothing // void CIpxEnviroment::ReleaseAdapterInfo() { CIpxAdapterInfo *pAI; while (!m_lstpAdapterInfo.empty()) { pAI = m_lstpAdapterInfo.front(); m_lstpAdapterInfo.pop_front(); delete pAI; } } // // Member: CIpxEnviroment::DwCountValidAdapters // // Purpose: Return the count of adapters not marked as delete pending, // disabled, or hidden. // // Arguments: none // // Returns: nothing // DWORD CIpxEnviroment::DwCountValidAdapters() { DWORD dwCount = 0; ADAPTER_INFO_LIST::iterator iterAI; for (iterAI = AdapterInfoList().begin(); iterAI != AdapterInfoList().end(); iterAI++) { CIpxAdapterInfo *pAI = *iterAI; if (pAI->FDeletePending() || pAI->FDisabled() || pAI->FHidden()) continue; dwCount++; } return dwCount; } HRESULT CIpxEnviroment::HrOpenIpxAdapterSubkey(HKEY *phkey, BOOL fCreateIfMissing) { DWORD dwDisposition; HRESULT hr; tstring str; // Open the NetCard key str = c_szIpxParameters; str += L"\\"; str += c_szAdapters; if (fCreateIfMissing) { hr = ::HrRegCreateKeyEx(HKEY_LOCAL_MACHINE, str.c_str(), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, phkey, &dwDisposition); } else { hr = ::HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, str.c_str(), KEY_READ, phkey ); } if (S_OK != hr) goto Error; Error: TraceError("CIpxEnviroment::HrOpenIpxAdapterSubkey", HRESULT_FROM_WIN32 (ERROR_FILE_NOT_FOUND) == hr ? S_OK : hr); return hr; } HRESULT CIpxEnviroment::HrOpenIpxAdapterSubkeyEx(PCWSTR pszKeyName, DWORD dwAccess, BOOL fCreateIfMissing, HKEY *phkey) { HRESULT hr; HKEY hkeyRoot = NULL; Assert(pszKeyName); Assert(0 < lstrlenW(pszKeyName)); // Open the NetCard key hr = HrOpenIpxAdapterSubkey(&hkeyRoot, fCreateIfMissing); if (S_OK != hr) { goto Error; } // Open the adapter specific subkey (creating if requested and required) if (fCreateIfMissing) { DWORD dwDisposition; hr = HrRegCreateKeyEx(HKEY_LOCAL_MACHINE, pszKeyName, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, phkey, &dwDisposition); } else { // Try exact match first, it's faster hr = HrRegOpenKeyEx( hkeyRoot, pszKeyName, dwAccess, phkey ); } Error: RegSafeCloseKey(hkeyRoot); TraceError("CIpxEnviroment::HrOpenIpxAdapterSubkeyEx", HRESULT_FROM_WIN32 (ERROR_FILE_NOT_FOUND) == hr ? S_OK : hr); return hr; } HRESULT CIpxEnviroment::HrGetIpxParams() { RegReadValues(celems(regbatchIpx), regbatchIpx, (BYTE *)&m_IpxParams, KEY_READ); return S_OK; } HRESULT CIpxEnviroment::HrGetOneAdapterInfo(INetCfgComponent *pNCC, CIpxAdapterInfo **ppAI) { HKEY hkeyCard = NULL; HRESULT hr = S_OK; CIpxAdapterInfo * pAI = NULL; Assert(NULL != pNCC); // Init the return value *ppAI = NULL; pAI = (CIpxAdapterInfo *)new CIpxAdapterInfo; Assert(NULL != pAI); if (pAI == NULL) { return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); } // Query the adapter component info hr = ::HrQueryAdapterComponentInfo(pNCC, pAI); if (FAILED(hr)) goto Error; // Open the IPX subkey specific to this adapter hr = HrOpenIpxAdapterSubkeyEx(pAI->SzBindName(), KEY_READ, FALSE, &hkeyCard); if (S_OK == hr) { // Get the packet types // hr = HrRegQueryColString(hkeyCard, c_szPktType, &pAI->m_lstpstrFrmType); if (S_OK != hr) { goto Error; } // Get the network numbers // hr = HrRegQueryColString(hkeyCard, c_szNetworkNumber, &pAI->m_lstpstrNetworkNum); if (S_OK != hr) { goto Error; } } else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) { // Normalize any ERROR_FILE_NOT_FOUND errors hr = S_OK; } else if (FAILED(hr)) { goto Error; } // Default PktType? if (0 == pAI->PFrmTypeList()->size()) { WCHAR szBuf[10]; // If the info was not found or contained no elements, add the // default value. wsprintfW(szBuf,L"%X",c_dwPktTypeDefault); pAI->PFrmTypeList()->push_back(new tstring(szBuf)); } // Default Network Number? if (0 == pAI->PNetworkNumList()->size()) { // If the info was not found or contained no elements, add the // default value. pAI->PNetworkNumList()->push_back(new tstring(c_sz8Zeros)); } // Update the return value with the new object *ppAI = pAI; Done: ::RegSafeCloseKey(hkeyCard); TraceError("CIpxEnviroment::HrGetOneAdapterInfo",hr); return hr; Error: delete pAI; goto Done; } HRESULT CIpxEnviroment::HrGetAdapterInfo() { HRESULT hr = S_OK; CIpxAdapterInfo * pAI = NULL; INetCfgComponent* pncc = NULL; INetCfgComponent* pnccUse = NULL; // Find each netcard, to do so, trace the bindings to their end // If the endpoint is a netcard then add it to the list CIterNetCfgBindingPath ncbpIter(m_pno->m_pnccMe); INetCfgBindingPath* pncbp; while (SUCCEEDED(hr) && (S_OK == (hr = ncbpIter.HrNext (&pncbp)))) { // Iterate the binding interfaces of this path. CIterNetCfgBindingInterface ncbiIter(pncbp); INetCfgBindingInterface* pncbi; while (SUCCEEDED(hr) && (S_OK == (hr = ncbiIter.HrNext (&pncbi)))) { // Retrieve the lower component hr = pncbi->GetLowerComponent(&pncc); if (S_OK == hr) { GUID guidClass; // Is it an Adapter? hr = pncc->GetClassGuid(&guidClass); if ((S_OK == hr) && (guidClass == GUID_DEVCLASS_NET)) { ReleaseObj(pnccUse); pnccUse = pncc; pncc = NULL; } else { // Release the lower component ReleaseObj(pncc); } } // Release the binding interface ReleaseObj (pncbi); } if (NULL != pnccUse) { // Query the Adapter information hr = HrGetOneAdapterInfo(pnccUse, &pAI); if (SUCCEEDED(hr)) { if (S_FALSE == pncbp->IsEnabled()) pAI->SetDisabled(TRUE); // Add this Adapter to the list m_lstpAdapterInfo.push_back(pAI); } ReleaseObj(pnccUse); pnccUse = NULL; } // Release the binding path ReleaseObj (pncbp); } // Normalize the HRESULT. (i.e. don't return S_FALSE) if (SUCCEEDED(hr)) { hr = S_OK; } TraceError("CIpxEnviroment::HrGetNetCardInfo",hr); return hr; } HRESULT CIpxEnviroment::HrWriteOneAdapterInfo(HKEY hkeyAdapters, CIpxAdapterInfo* pAI) { DWORD dwDisposition; HRESULT hr; HKEY hkeyCard = NULL; PWSTR psz = NULL; // Open the IPX subkey for this specific adapter hr = ::HrRegCreateKeyEx(hkeyAdapters, pAI->SzBindName(), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyCard, &dwDisposition); if (S_OK != hr) goto Error; // Write the packet info // Generate the data to write AssertSz(pAI->m_lstpstrFrmType.size(),"Did not expect an empty list, default value missing"); ColStringToMultiSz(pAI->m_lstpstrFrmType, &psz); if (psz) { hr = ::HrRegSetMultiSz(hkeyCard, c_szPktType, psz); if (S_OK != hr) goto Error; delete [] psz; psz = NULL; } #ifdef DBG else { AssertSz(0,"PacketType value is NULL?"); } #endif // Write the network number AssertSz(pAI->m_lstpstrNetworkNum.size(),"Did not expect an empty list, default value missing"); ColStringToMultiSz(pAI->m_lstpstrNetworkNum, &psz); if (psz) { hr = ::HrRegSetMultiSz(hkeyCard, c_szNetworkNumber, psz); if (S_OK != hr) goto Error; delete [] psz; psz = NULL; } #ifdef DBG else { AssertSz(0,"NetworkNumber value is NULL?"); } #endif // If the key for this adapter didn't exist previously // write the base set of values if (REG_CREATED_NEW_KEY == dwDisposition) { struct { PCWSTR pszProp; DWORD dwValue; } rgAdapterSettings[] = {{c_szBindSap,c_dwBindSap}, {c_szEnableFuncaddr,c_dwEnableFuncaddr}, {c_szMaxPktSize,c_dwMaxPktSize}, {c_szSourceRouteBCast,c_dwSourceRouteBCast}, {c_szSourceRouteMCast,c_dwSourceRouteMCast}, {c_szSourceRouteDef,c_dwSourceRouteDef}, {c_szSourceRouting,c_dwSourceRouting}}; for (int nIdx=0; nIdxFDeletePending()) { // Remove the NwlnkIpx\Adapter\{bindname} tree (VOID)::HrRegDeleteKeyTree(hkeyAdapters, pAI->SzBindName()); } else if (pAI->IsDirty()) { hr = HrWriteOneAdapterInfo(hkeyAdapters, pAI); if (S_OK != hr) goto Error; } } Error: ::RegSafeCloseKey(hkeyAdapters); TraceError("CIpxEnviroment::HrWriteAdapterInfo",hr); return hr; } HRESULT CIpxEnviroment::HrCreate(CNwlnkIPX *pno, CIpxEnviroment ** ppIpxEnviroment) { HRESULT hr; CIpxEnviroment * pIpxEnviroment = (CIpxEnviroment *)new CIpxEnviroment(pno); if (pIpxEnviroment == NULL) { return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); } *ppIpxEnviroment = NULL; // Get the Ipx Parameter Key info hr = pIpxEnviroment->HrGetIpxParams(); if (FAILED(hr)) goto Error; // Collect the Adapter Info for all cards installed hr = pIpxEnviroment->HrGetAdapterInfo(); if (FAILED(hr)) goto Error; *ppIpxEnviroment = pIpxEnviroment; Complete: TraceError("CIpxEnviroment::HrCreate",hr); return hr; Error: delete pIpxEnviroment; goto Complete; } HRESULT CIpxEnviroment::HrUpdateRegistry() { HRESULT hr; // Commit the registry changes hr = ::HrRegWriteValues(celems(regbatchIpx), regbatchIpx, (BYTE *)&m_IpxParams, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS); if (S_OK != hr) goto Error; // Write adapter info to registry hr = HrWriteAdapterInfo(); Error: TraceError("CIpxEnviroment::HrUpdateRegistry",hr); return hr; } VOID CIpxEnviroment::RemoveAdapter(CIpxAdapterInfo * pAI) { Assert(NULL != pAI); m_lstpAdapterInfo.remove(pAI); delete pAI; } HRESULT CIpxEnviroment::HrAddAdapter(INetCfgComponent * pncc) { HRESULT hr = S_OK; CIpxAdapterInfo * pAI = NULL; hr = HrGetOneAdapterInfo(pncc, &pAI); if (FAILED(hr)) goto Error; if (SUCCEEDED(hr)) hr = S_OK; // Normalize return // Add the Adapter to the list pAI->SetDirty(TRUE); m_lstpAdapterInfo.push_back(pAI); Error: TraceError("CIpxEnviroment::HrAddAdapter",hr); return hr; } //$ REVIEW - Start - This is moving to windows\inc\ipxpnp.h #define IPX_RECONFIG_VERSION 0x1 #define RECONFIG_AUTO_DETECT 1 #define RECONFIG_MANUAL 2 #define RECONFIG_PREFERENCE_1 3 #define RECONFIG_NETWORK_NUMBER_1 4 #define RECONFIG_PREFERENCE_2 5 #define RECONFIG_NETWORK_NUMBER_2 6 #define RECONFIG_PREFERENCE_3 7 #define RECONFIG_NETWORK_NUMBER_3 8 #define RECONFIG_PREFERENCE_4 9 #define RECONFIG_NETWORK_NUMBER_4 10 #define RECONFIG_PARAMETERS 10 // // Main configuration structure. // struct RECONFIG { ULONG ulVersion; BOOLEAN InternalNetworkNumber; BOOLEAN AdapterParameters[RECONFIG_PARAMETERS]; }; //$ REVIEW - End - This is moving to windows\inc\ipxpnp.h //+--------------------------------------------------------------------------- // // Member: CNwlnkIPX::HrReconfigIpx // // Purpose: Notify Ipx of configuration changes // // Arguments: none // // Returns: HRESULT, S_OK on success, NETCFG_S_REBOOT on failure // HRESULT CNwlnkIPX::HrReconfigIpx() { HRESULT hrRet; HRESULT hr = S_OK; INT nIdx; RECONFIG Config; CIpxAdapterInfo * pAI; PRODUCT_FLAVOR pf; ADAPTER_INFO_LIST::iterator iter; ULONG ulConfigSize; if (0 == m_pIpxEnviroment->DwCountValidAdapters()) { return S_OK; // Nothing to configure } ZeroMemory(&Config, sizeof(Config)); Config.ulVersion = IPX_RECONFIG_VERSION; // Workstation or server? GetProductFlavor(NULL, &pf); if (PF_WORKSTATION != pf) { Config.InternalNetworkNumber = TRUE; // Now submit the global reconfig notification hrRet = HrSendNdisPnpReconfig(NDIS, c_szSvcNwlnkIpx, c_szEmpty, &Config, sizeof(RECONFIG)); if (FAILED(hrRet) && (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hrRet)) { hr = NETCFG_S_REBOOT; } } Config.InternalNetworkNumber = FALSE; // For each adapter... for (nIdx=0, iter = m_pIpxEnviroment->AdapterInfoList().begin(); iter != m_pIpxEnviroment->AdapterInfoList().end(); nIdx++, iter++) { pAI = *iter; if (pAI->FDeletePending() || pAI->FDisabled() || !pAI->IsDirty()) continue; ZeroMemory(&Config.AdapterParameters, sizeof(Config.AdapterParameters)); if (AUTO == pAI->DwFrameType()) Config.AdapterParameters[RECONFIG_AUTO_DETECT] = TRUE; else Config.AdapterParameters[RECONFIG_MANUAL] = TRUE; // We are performing a shortcut here by setting a range to TRUE // based on the number of frames in use. For example if there is // only one frame in use we need to set both: // RECONFIG_PREFERENCE_1 and RECONFIG_NETWORK_NUMBER_1 to TRUE Assert(RECONFIG_PREFERENCE_1 + 1 == RECONFIG_NETWORK_NUMBER_1); Assert(RECONFIG_NETWORK_NUMBER_1 + 1 == RECONFIG_PREFERENCE_2); Assert(RECONFIG_PREFERENCE_2 + 1 == RECONFIG_NETWORK_NUMBER_2); Assert(RECONFIG_NETWORK_NUMBER_2 + 1 == RECONFIG_PREFERENCE_3); Assert(RECONFIG_PREFERENCE_3 + 1 == RECONFIG_NETWORK_NUMBER_3); Assert(RECONFIG_NETWORK_NUMBER_3 + 1 == RECONFIG_PREFERENCE_4); Assert(RECONFIG_PREFERENCE_4 + 1 == RECONFIG_NETWORK_NUMBER_4); INT nCntFrms = pAI->PFrmTypeList()->size(); if ((0 < nCntFrms) && (4 >= nCntFrms)) { memset(&Config.AdapterParameters[RECONFIG_PREFERENCE_1], TRUE, sizeof(BOOLEAN) * nCntFrms * 2); } Assert(lstrlenW(pAI->SzBindName())); // Now submit the reconfig notification hrRet = HrSendNdisPnpReconfig(NDIS, c_szSvcNwlnkIpx, pAI->SzBindName(), &Config, sizeof(RECONFIG)); if (FAILED(hrRet) && (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hrRet)) { hr = NETCFG_S_REBOOT; } } TraceError("CNwlnkIPX::HrReconfigIpx",hr); return hr; }