Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4323 lines
174 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // File: netcfgconfig.cpp
  4. //
  5. // Module:
  6. //
  7. // Description: Implement class CNetcfgCluster and class CWlbsConfig
  8. //
  9. // Copyright (C) Microsoft Corporation. All rights reserved.
  10. //
  11. // Author: fengsun Created 3/2/00
  12. //
  13. //+----------------------------------------------------------------------------
  14. #include "pch.h"
  15. #pragma hdrstop
  16. #define ENABLE_PROFILE
  17. #include <winsock2.h>
  18. #include <windows.h>
  19. #include <clusapi.h>
  20. #include "debug.h"
  21. #include "netcon.h"
  22. #include "ncatlui.h"
  23. #include "ndispnp.h"
  24. #include "ncsetup.h"
  25. #include "netcfgn.h"
  26. #include "afilestr.h"
  27. #include "help.h"
  28. #include "resource.h"
  29. #include "ClusterDlg.h"
  30. #include "host.h"
  31. #include "ports.h"
  32. #include "wlbsparm.h"
  33. #include "wlbsconfig.h"
  34. #include "wlbscfg.h"
  35. #include <time.h>
  36. #include "netcfgcluster.h"
  37. #include "license.h"
  38. #include <strsafe.h>
  39. #include "utils.h"
  40. #include "netcfgconfig.tmh"
  41. #include "log_msgs.h"
  42. /* For IPSec notification that NLB is bound to at least one adapter in this host. */
  43. #include "winipsec.h"
  44. #define NETCFG_WLBS_ID L"ms_wlbs"
  45. typedef DWORD (CALLBACK* LPFNGNCS)(LPCWSTR,DWORD*);
  46. // Used by Netsetup and Component's who's answer file references AdapterSections
  47. static const WCHAR c_szAdapterSections[] = L"AdapterSections";
  48. void WlbsToNetcfgConfig(const WlbsApiFuncs* pApiFuncs, const WLBS_REG_PARAMS* pWlbsConfig, NETCFG_WLBS_CONFIG* pBNetcfgConfig);
  49. void RemoveAllPortRules(PWLBS_REG_PARAMS reg_data);
  50. HRESULT ParamReadAnswerFile(CSetupInfFile& caf, PCWSTR answer_sections, WLBS_REG_PARAMS* paramp);
  51. bool WriteAdapterName(CWlbsConfig* pConfig, GUID& AdapterGuid);
  52. /* 353752 - Persist host state across reboots, etc. This function creates the key that holds the state
  53. on bind and defaults its initial value to the host properties TAB dropdown list (ClusterModeOnStart). */
  54. bool WriteHostStateRegistryKey (CWlbsConfig * pConfig, GUID & AdapterGuid, ULONG State);
  55. /* Notify IPSec of the NLB presence. Typically this is done via an RPC call to the IPSec service;
  56. if the service is unavailable, this function attempts to manually create/modify the appropriate
  57. registry settings. */
  58. bool WriteIPSecNLBRegistryKey (DWORD dwNLBSFlags);
  59. bool ValidateVipInRule(const PWCHAR pwszRuleString, const WCHAR pwToken, DWORD& dwVipLen);
  60. #if DBG
  61. static void TraceMsg(PCWSTR pszFormat, ...);
  62. #else
  63. #define TraceMsg NOP_FUNCTION
  64. #define DbgDumpBindPath NOP_FUNCTION
  65. #endif
  66. //
  67. // Function pointers to avoid link with wlbsctrl.dll
  68. //
  69. bool WINAPI ParamReadReg(const GUID& AdaperGuid, PWLBS_REG_PARAMS reg_data, bool fUpgradeFromWin2k = false, bool *pfPortRulesInBinaryForm = NULL);
  70. typedef bool (WINAPI* ParamReadRegFUNC)(const GUID& AdaperGuid, PWLBS_REG_PARAMS reg_data, bool fUpgradeFromWin2k /*= false*/, bool *pfPortRulesInBinaryForm /*= NULL*/);
  71. bool WINAPI ParamWriteReg(const GUID& AdaperGuid, PWLBS_REG_PARAMS reg_data);
  72. typedef bool (WINAPI* ParamWriteRegFUNC)(const GUID& AdaperGuid, PWLBS_REG_PARAMS reg_data);
  73. bool WINAPI ParamDeleteReg(const GUID& AdaperGuid, bool fDeleteObsoleteEntries = false);
  74. typedef bool (WINAPI* ParamDeleteRegFUNC)(const GUID& AdaperGuid, bool fDeleteObsoleteEntries /*= false*/);
  75. DWORD WINAPI ParamSetDefaults(PWLBS_REG_PARAMS reg_data);
  76. typedef DWORD (WINAPI* ParamSetDefaultsFUNC)(PWLBS_REG_PARAMS reg_data);
  77. bool WINAPI RegChangeNetworkAddress(const GUID& AdapterGuid, const WCHAR* mac_address, BOOL fRemove);
  78. typedef bool(WINAPI* RegChangeNetworkAddressFUNC) (const GUID& AdapterGuid, const WCHAR* mac_address, BOOL fRemove);
  79. void WINAPI NotifyAdapterAddressChangeEx(const WCHAR* pszPnpDevNodeId, const GUID& AdapterGuid, bool bWaitAndQuery);
  80. typedef void (WINAPI* NotifyAdapterAddressChangeExFUNC)(const WCHAR* pszPnpDevNodeId, const GUID& AdapterGuid, bool bWaitAndQuery);
  81. DWORD WINAPI WlbsAddPortRule(PWLBS_REG_PARAMS reg_data, PWLBS_PORT_RULE rule);
  82. typedef DWORD (WINAPI* WlbsAddPortRuleFUNC)(PWLBS_REG_PARAMS reg_data, PWLBS_PORT_RULE rule);
  83. DWORD WINAPI WlbsSetRemotePassword(PWLBS_REG_PARAMS reg_data, const WCHAR* password);
  84. typedef DWORD (WINAPI* WlbsSetRemotePasswordFUNC)(const PWLBS_REG_PARAMS reg_data, const WCHAR* password);
  85. DWORD WINAPI WlbsEnumPortRules(PWLBS_REG_PARAMS reg_data, PWLBS_PORT_RULE rules, PDWORD num_rules);
  86. typedef DWORD (WINAPI* WlbsEnumPortRulesFUNC)(PWLBS_REG_PARAMS reg_data, PWLBS_PORT_RULE rules, PDWORD num_rules);
  87. DWORD WINAPI NotifyDriverConfigChanges(HANDLE hDeviceWlbs, const GUID& AdapterGuid);
  88. typedef DWORD (WINAPI* NotifyDriverConfigChangesFUNC)(HANDLE hDeviceWlbs, const GUID& AdapterGuid);
  89. HKEY WINAPI RegOpenWlbsSetting(const GUID& AdapterGuid, bool fReadOnly);
  90. typedef HKEY (WINAPI* RegOpenWlbsSettingFUNC)(const GUID& AdapterGuid, bool fReadOnly);
  91. struct WlbsApiFuncs {
  92. ParamReadRegFUNC pfnParamReadReg;
  93. ParamWriteRegFUNC pfnParamWriteReg;
  94. ParamDeleteRegFUNC pfnParamDeleteReg;
  95. ParamSetDefaultsFUNC pfnParamSetDefaults;
  96. RegChangeNetworkAddressFUNC pfnRegChangeNetworkAddress;
  97. NotifyAdapterAddressChangeExFUNC pfnNotifyAdapterAddressChangeEx;
  98. WlbsAddPortRuleFUNC pfnWlbsAddPortRule;
  99. WlbsSetRemotePasswordFUNC pfnWlbsSetRemotePassword;
  100. WlbsEnumPortRulesFUNC pfnWlbsEnumPortRules;
  101. NotifyDriverConfigChangesFUNC pfnNotifyDriverConfigChanges;
  102. RegOpenWlbsSettingFUNC pfnRegOpenWlbsSetting;
  103. };
  104. //+----------------------------------------------------------------------------
  105. //
  106. // Function: LoadWlbsCtrlDll
  107. //
  108. // Description: Load wlbsctrl.dll and get all function pointers
  109. //
  110. // Arguments: WlbsApiFuncs* pFuncs -
  111. //
  112. // Returns: HINSTANCE - wlbsctrl.dll handle
  113. //
  114. // History: fengsun Created Header 3/2/00
  115. //
  116. //+----------------------------------------------------------------------------
  117. HINSTANCE LoadWlbsCtrlDll(WlbsApiFuncs* pFuncs) {
  118. TRACE_VERB("->%!FUNC!");
  119. TraceMsg(L"LoadWlbsCtrlDll");
  120. ASSERT(pFuncs);
  121. HINSTANCE hDll;
  122. DWORD dwStatus = 0;
  123. hDll = LoadLibrary(L"wlbsctrl.dll");
  124. if (hDll == NULL) {
  125. dwStatus = GetLastError();
  126. TraceError("Failed to load wlbsctrl.dll", dwStatus);
  127. TRACE_CRIT("%!FUNC! Could not load wlbsctrl.dll with %d", dwStatus);
  128. TRACE_VERB("<-%!FUNC!");
  129. return NULL;
  130. }
  131. pFuncs->pfnParamReadReg = (ParamReadRegFUNC)GetProcAddress(hDll, "ParamReadReg");
  132. pFuncs->pfnParamWriteReg = (ParamWriteRegFUNC)GetProcAddress(hDll, "ParamWriteReg");
  133. pFuncs->pfnParamDeleteReg = (ParamDeleteRegFUNC)GetProcAddress(hDll, "ParamDeleteReg");
  134. pFuncs->pfnParamSetDefaults = (ParamSetDefaultsFUNC)GetProcAddress(hDll, "ParamSetDefaults");
  135. pFuncs->pfnRegChangeNetworkAddress = (RegChangeNetworkAddressFUNC)GetProcAddress(hDll, "RegChangeNetworkAddress");
  136. pFuncs->pfnNotifyAdapterAddressChangeEx = (NotifyAdapterAddressChangeExFUNC)GetProcAddress(hDll, "NotifyAdapterAddressChangeEx");
  137. pFuncs->pfnWlbsAddPortRule = (WlbsAddPortRuleFUNC)GetProcAddress(hDll, "WlbsAddPortRule");
  138. pFuncs->pfnWlbsSetRemotePassword = (WlbsSetRemotePasswordFUNC)GetProcAddress(hDll, "WlbsSetRemotePassword");
  139. pFuncs->pfnWlbsEnumPortRules = (WlbsEnumPortRulesFUNC)GetProcAddress(hDll, "WlbsEnumPortRules");
  140. pFuncs->pfnNotifyDriverConfigChanges = (NotifyDriverConfigChangesFUNC)GetProcAddress(hDll, "NotifyDriverConfigChanges");
  141. pFuncs->pfnRegOpenWlbsSetting = (RegOpenWlbsSettingFUNC)GetProcAddress(hDll, "RegOpenWlbsSetting");
  142. ASSERT (pFuncs->pfnParamReadReg != NULL);
  143. ASSERT (pFuncs->pfnParamWriteReg != NULL);
  144. ASSERT (pFuncs->pfnParamDeleteReg != NULL);
  145. ASSERT (pFuncs->pfnParamSetDefaults != NULL);
  146. ASSERT (pFuncs->pfnRegChangeNetworkAddress != NULL);
  147. ASSERT (pFuncs->pfnNotifyAdapterAddressChangeEx != NULL);
  148. ASSERT (pFuncs->pfnWlbsAddPortRule != NULL);
  149. ASSERT (pFuncs->pfnWlbsSetRemotePassword != NULL);
  150. ASSERT (pFuncs->pfnWlbsEnumPortRules != NULL);
  151. ASSERT (pFuncs->pfnNotifyDriverConfigChanges != NULL);
  152. ASSERT (pFuncs->pfnRegOpenWlbsSetting != NULL);
  153. if (pFuncs->pfnParamReadReg == NULL ||
  154. pFuncs->pfnParamWriteReg == NULL||
  155. pFuncs->pfnParamDeleteReg == NULL||
  156. pFuncs->pfnParamSetDefaults == NULL||
  157. pFuncs->pfnRegChangeNetworkAddress == NULL||
  158. pFuncs->pfnNotifyAdapterAddressChangeEx == NULL||
  159. pFuncs->pfnWlbsAddPortRule == NULL||
  160. pFuncs->pfnWlbsSetRemotePassword == NULL||
  161. pFuncs->pfnWlbsEnumPortRules == NULL||
  162. pFuncs->pfnNotifyDriverConfigChanges == NULL ||
  163. pFuncs->pfnRegOpenWlbsSetting == NULL) {
  164. dwStatus = GetLastError();
  165. TraceError("LoadWlbsCtrlDll GetProcAddress failed %d", dwStatus);
  166. TRACE_CRIT("%!FUNC! GetProcAddress failed %d", dwStatus);
  167. FreeLibrary(hDll);
  168. TRACE_VERB("<-%!FUNC!");
  169. return NULL;
  170. }
  171. TRACE_VERB("<-%!FUNC!");
  172. return hDll;
  173. }
  174. // Maximum characters in an IP address string of the form a.b.c.d
  175. const DWORD MAXIPSTRLEN = 20;
  176. void TransformOldPortRulesToNew(PWLBS_OLD_PORT_RULE p_old_port_rules,
  177. PWLBS_PORT_RULE p_new_port_rules,
  178. DWORD num_rules)
  179. {
  180. TRACE_VERB("->%!FUNC!");
  181. if (num_rules == 0)
  182. {
  183. TRACE_INFO("%!FUNC! No port rules");
  184. TRACE_VERB("<-%!FUNC!");
  185. return;
  186. }
  187. while(num_rules--)
  188. {
  189. (VOID) StringCchCopy(p_new_port_rules->virtual_ip_addr, ASIZECCH(p_new_port_rules->virtual_ip_addr), CVY_DEF_ALL_VIP);
  190. p_new_port_rules->start_port = p_old_port_rules->start_port;
  191. p_new_port_rules->end_port = p_old_port_rules->end_port;
  192. #ifdef WLBSAPI_INTERNAL_ONLY
  193. p_new_port_rules->code = p_old_port_rules->code;
  194. #else
  195. p_new_port_rules->Private1 = p_old_port_rules->Private1;
  196. #endif
  197. p_new_port_rules->mode = p_old_port_rules->mode;
  198. p_new_port_rules->protocol = p_old_port_rules->protocol;
  199. #ifdef WLBSAPI_INTERNAL_ONLY
  200. p_new_port_rules->valid = p_old_port_rules->valid;
  201. #else
  202. p_new_port_rules->Private2 = p_old_port_rules->Private2;
  203. #endif
  204. switch (p_new_port_rules->mode)
  205. {
  206. case CVY_MULTI :
  207. p_new_port_rules->mode_data.multi.equal_load = p_old_port_rules->mode_data.multi.equal_load;
  208. p_new_port_rules->mode_data.multi.affinity = p_old_port_rules->mode_data.multi.affinity;
  209. p_new_port_rules->mode_data.multi.load = p_old_port_rules->mode_data.multi.load;
  210. break;
  211. case CVY_SINGLE :
  212. p_new_port_rules->mode_data.single.priority = p_old_port_rules->mode_data.single.priority;
  213. break;
  214. default:
  215. break;
  216. }
  217. p_old_port_rules++;
  218. p_new_port_rules++;
  219. }
  220. TRACE_VERB("<-%!FUNC!");
  221. return;
  222. }
  223. /* Initialize static data members of CNetcfgCluster */
  224. bool CNetcfgCluster::m_fMSCSWarningEventLatched = false;
  225. bool CNetcfgCluster::m_fMSCSWarningPopupLatched = false;
  226. //+----------------------------------------------------------------------------
  227. //
  228. // Function: CNetcfgCluster::CNetcfgCluster
  229. //
  230. // Description:
  231. //
  232. // Arguments: None
  233. //
  234. // Returns: Nothing
  235. //
  236. // History: fengsun Created Header 2/11/00
  237. //
  238. //+----------------------------------------------------------------------------
  239. CNetcfgCluster::CNetcfgCluster(CWlbsConfig* pConfig) {
  240. TRACE_VERB("->%!FUNC!");
  241. TraceMsg(L"CNetcfgCluster::CNetcfgCluster");
  242. m_fHasOriginalConfig = false;
  243. m_fMacAddrChanged = false;
  244. m_fReloadRequired = false;
  245. m_fRemoveAdapter = false;
  246. m_fOriginalBindingEnabled = false;
  247. m_fReenableAdapter = false;
  248. ZeroMemory(&m_AdapterGuid, sizeof(m_AdapterGuid));
  249. ASSERT(pConfig);
  250. m_pConfig = pConfig;
  251. TRACE_VERB("<-%!FUNC!");
  252. }
  253. //+----------------------------------------------------------------------------
  254. //
  255. // Function: CNetcfgCluster::~CNetcfgCluster
  256. //
  257. // Description:
  258. //
  259. // Arguments: None
  260. //
  261. // Returns: Nothing
  262. //
  263. // History: fengsun Created Header 2/11/00
  264. //
  265. //+----------------------------------------------------------------------------
  266. CNetcfgCluster::~CNetcfgCluster() {
  267. TRACE_VERB("<->%!FUNC!");
  268. TraceMsg(L"CNetcfgCluster::~CNetcfgCluster");
  269. }
  270. //+----------------------------------------------------------------------------
  271. //
  272. // Function: CNetcfgCluster::InitializeFromRegistry
  273. //
  274. // Description: Read the cluster settings from registry
  275. //
  276. // Arguments: const GUID& guidAdapter -
  277. //
  278. // Returns: DWORD - Win32 Error
  279. //
  280. // History: fengsun Created Header 2/13/00
  281. //
  282. //+----------------------------------------------------------------------------
  283. DWORD CNetcfgCluster::InitializeFromRegistry(const GUID& guidAdapter, bool fBindingEnabled, bool fUpgradeFromWin2k) {
  284. TRACE_VERB("->%!FUNC!");
  285. TraceMsg(L"CNetcfgCluster::InitializeFromRegistry");
  286. bool fPortRulesInBinaryForm = false;
  287. ASSERT(m_fHasOriginalConfig == false);
  288. m_fHasOriginalConfig = true;
  289. m_fOriginalBindingEnabled = fBindingEnabled;
  290. m_AdapterGuid = guidAdapter;
  291. if (!m_pConfig->m_pWlbsApiFuncs->pfnParamReadReg(m_AdapterGuid, &m_OriginalConfig, fUpgradeFromWin2k, &fPortRulesInBinaryForm))
  292. {
  293. TRACE_VERB("%!FUNC! error reading settings from the registry"); // This is verbose because this is invoked for non-NLB adapters too.
  294. TRACE_VERB("<-%!FUNC!");
  295. return ERROR_CANTREAD;
  296. }
  297. /* Force a write at apply. */
  298. if (fUpgradeFromWin2k || fPortRulesInBinaryForm)
  299. {
  300. m_fHasOriginalConfig = false;
  301. TRACE_INFO("%!FUNC! upgrading from win2k or port rules are in binary form");
  302. }
  303. CopyMemory(&m_CurrentConfig, &m_OriginalConfig, sizeof(m_CurrentConfig));
  304. TRACE_VERB("<-%!FUNC!");
  305. return ERROR_SUCCESS;
  306. }
  307. //+----------------------------------------------------------------------------
  308. //
  309. // Function: CNetcfgCluster::InitializeFromAnswerFile
  310. //
  311. // Description: Read cluster settings from answer file
  312. //
  313. // Arguments: PCWSTR answer_file -
  314. // PCWSTR answer_sections -
  315. //
  316. // Returns: DWORD -
  317. //
  318. // History: fengsun Created Header 2/13/00
  319. //
  320. //+----------------------------------------------------------------------------
  321. HRESULT CNetcfgCluster::InitializeFromAnswerFile(const GUID& AdapterGuid, CSetupInfFile& caf, PCWSTR answer_sections) {
  322. TRACE_VERB("->%!FUNC!");
  323. TraceMsg(L"CNetcfgCluster::InitializeFromAnswerFile");
  324. /* Setup with the default values first. */
  325. InitializeWithDefault(AdapterGuid);
  326. HRESULT hr = ParamReadAnswerFile(caf, answer_sections, &m_CurrentConfig);
  327. if (FAILED(hr)) {
  328. TRACE_CRIT("%!FUNC! failed CNetcfgCluster::ParamReadAnswerFile failed. returned: %d", hr);
  329. TraceError("CNetcfgCluster::InitializeFromAnswerFile failed at ParamReadAnswerFile", hr);
  330. }
  331. TRACE_VERB("<-%!FUNC!");
  332. return hr;
  333. }
  334. //+----------------------------------------------------------------------------
  335. //
  336. // Function: CNetcfgCluster::InitializeWithDefault
  337. //
  338. // Description: Set the cluster settings to default
  339. //
  340. // Arguments: None
  341. //
  342. // Returns: Nothing
  343. //
  344. // History: fengsun Created Header 2/13/00
  345. //
  346. //+----------------------------------------------------------------------------
  347. void CNetcfgCluster::InitializeWithDefault(const GUID& guidAdapter) {
  348. TRACE_VERB("->%!FUNC!");
  349. TraceMsg(L"CNetcfgCluster::InitializeWithDefault");
  350. time_t cur_time;
  351. ASSERT(m_fHasOriginalConfig == false);
  352. m_fHasOriginalConfig = false;
  353. m_pConfig->m_pWlbsApiFuncs->pfnParamSetDefaults(&m_CurrentConfig); // Always returns WLBS_OK
  354. // time() returns a 64-bit value on ia64 and 32-bit value on x86.
  355. // We store this value in the registry and we do not want to
  356. // change the type of this value from DWORD this late in the release
  357. // cycle. So, we are going to care only about the lower 4 bytes returned
  358. // by time().
  359. // -KarthicN, 05/17/02
  360. m_CurrentConfig.install_date = (DWORD) time(& cur_time);
  361. // JosephJ 11/00 -- We used to call License_stamp to set this value,
  362. // but that was a holdover from convoy days.
  363. // We no longer use this field.
  364. //
  365. m_CurrentConfig.i_verify_date = 0;
  366. m_AdapterGuid = guidAdapter;
  367. TRACE_VERB("<-%!FUNC!");
  368. }
  369. //+----------------------------------------------------------------------------
  370. //
  371. // Function: CNetcfgCluster::SetConfig
  372. //
  373. // Description: SetConfig caches the settings without saving to registry
  374. // and can be retrieved by GetConfig.
  375. //
  376. // Arguments: const NETCFG_WLBS_CONFIG* pClusterConfig -
  377. //
  378. // Returns: Nothing
  379. //
  380. // History: fengsun Created Header 2/11/00
  381. //
  382. //+----------------------------------------------------------------------------
  383. void CNetcfgCluster::SetConfig(const NETCFG_WLBS_CONFIG* pClusterConfig) {
  384. TRACE_VERB("->%!FUNC!");
  385. TraceMsg(L"CNetcfgCluster::SetConfig");
  386. DWORD dwStatus = WLBS_OK; // Used for tracing output
  387. ASSERT(pClusterConfig != NULL);
  388. m_CurrentConfig.host_priority = pClusterConfig->dwHostPriority;
  389. m_CurrentConfig.rct_enabled = pClusterConfig->fRctEnabled ;
  390. m_CurrentConfig.cluster_mode = pClusterConfig->dwInitialState;
  391. m_CurrentConfig.persisted_states = pClusterConfig->dwPersistedStates;
  392. m_CurrentConfig.mcast_support = pClusterConfig->fMcastSupport;
  393. m_CurrentConfig.fIGMPSupport = pClusterConfig->fIGMPSupport;
  394. m_CurrentConfig.fIpToMCastIp = pClusterConfig->fIpToMCastIp;
  395. (VOID) StringCchCopy(m_CurrentConfig.szMCastIpAddress, ASIZECCH(m_CurrentConfig.szMCastIpAddress), pClusterConfig->szMCastIpAddress);
  396. (VOID) StringCchCopy(m_CurrentConfig.cl_mac_addr , ASIZECCH(m_CurrentConfig.cl_mac_addr) , pClusterConfig->cl_mac_addr);
  397. (VOID) StringCchCopy(m_CurrentConfig.cl_ip_addr , ASIZECCH(m_CurrentConfig.cl_ip_addr) , pClusterConfig->cl_ip_addr);
  398. (VOID) StringCchCopy(m_CurrentConfig.cl_net_mask , ASIZECCH(m_CurrentConfig.cl_net_mask) , pClusterConfig->cl_net_mask);
  399. (VOID) StringCchCopy(m_CurrentConfig.ded_ip_addr , ASIZECCH(m_CurrentConfig.ded_ip_addr) , pClusterConfig->ded_ip_addr);
  400. (VOID) StringCchCopy(m_CurrentConfig.ded_net_mask , ASIZECCH(m_CurrentConfig.ded_net_mask) , pClusterConfig->ded_net_mask);
  401. (VOID) StringCchCopy(m_CurrentConfig.domain_name , ASIZECCH(m_CurrentConfig.domain_name) , pClusterConfig->domain_name);
  402. if (pClusterConfig->fChangePassword)
  403. {
  404. dwStatus = m_pConfig->m_pWlbsApiFuncs->pfnWlbsSetRemotePassword(&m_CurrentConfig, (WCHAR*)pClusterConfig->szPassword);
  405. if (WLBS_OK != dwStatus)
  406. {
  407. TRACE_CRIT("%!FUNC! set password failed with return code = %d", dwStatus);
  408. }
  409. }
  410. RemoveAllPortRules(&m_CurrentConfig);
  411. for (DWORD i=0; i<pClusterConfig->dwNumRules; i++) {
  412. WLBS_PORT_RULE PortRule;
  413. ZeroMemory(&PortRule, sizeof(PortRule));
  414. (VOID) StringCchCopy(PortRule.virtual_ip_addr, ASIZECCH(PortRule.virtual_ip_addr), pClusterConfig->port_rules[i].virtual_ip_addr);
  415. PortRule.start_port = pClusterConfig->port_rules[i].start_port;
  416. PortRule.end_port = pClusterConfig->port_rules[i].end_port;
  417. PortRule.mode = pClusterConfig->port_rules[i].mode;
  418. PortRule.protocol = pClusterConfig->port_rules[i].protocol;
  419. if (PortRule.mode == WLBS_AFFINITY_SINGLE) {
  420. PortRule.mode_data.single.priority =
  421. pClusterConfig->port_rules[i].mode_data.single.priority;
  422. } else {
  423. PortRule.mode_data.multi.equal_load =
  424. pClusterConfig->port_rules[i].mode_data.multi.equal_load;
  425. PortRule.mode_data.multi.affinity =
  426. pClusterConfig->port_rules[i].mode_data.multi.affinity;
  427. PortRule.mode_data.multi.load =
  428. pClusterConfig->port_rules[i].mode_data.multi.load;
  429. }
  430. PortRule.valid = TRUE;
  431. CVY_RULE_CODE_SET(&PortRule);
  432. dwStatus = m_pConfig->m_pWlbsApiFuncs->pfnWlbsAddPortRule( &m_CurrentConfig, &PortRule );
  433. if (WLBS_OK != dwStatus)
  434. {
  435. TRACE_CRIT("%!FUNC! add port rule failed with return code = %d", dwStatus);
  436. }
  437. }
  438. (VOID) StringCchCopy(m_CurrentConfig.bda_teaming.team_id, ASIZECCH(m_CurrentConfig.bda_teaming.team_id), pClusterConfig->bda_teaming.team_id);
  439. m_CurrentConfig.bda_teaming.active = pClusterConfig->bda_teaming.active;
  440. m_CurrentConfig.bda_teaming.master = pClusterConfig->bda_teaming.master;
  441. m_CurrentConfig.bda_teaming.reverse_hash = pClusterConfig->bda_teaming.reverse_hash;
  442. TRACE_VERB("<-%!FUNC!");
  443. }
  444. //+----------------------------------------------------------------------------
  445. //
  446. // Function: CNetcfgCluster::GetConfig
  447. //
  448. // Description: Get the config, which could be cached by SetConfig call
  449. //
  450. // Arguments: NETCFG_WLBS_CONFIG* pClusterConfig -
  451. //
  452. // Returns: Nothing
  453. //
  454. // History: fengsun Created Header 2/11/00
  455. //
  456. //+----------------------------------------------------------------------------
  457. void CNetcfgCluster::GetConfig(NETCFG_WLBS_CONFIG* pClusterConfig) {
  458. TRACE_VERB("->%!FUNC!");
  459. TraceMsg(L"CNetcfgCluster::GetConfig");
  460. ASSERT(pClusterConfig != NULL);
  461. WlbsToNetcfgConfig(m_pConfig->m_pWlbsApiFuncs, &m_CurrentConfig, pClusterConfig);
  462. TRACE_VERB("<-%!FUNC!");
  463. }
  464. //+----------------------------------------------------------------------------
  465. //
  466. // Function: CNetcfgCluster::NotifyBindingChanges
  467. //
  468. // Description: Notify binding changes
  469. //
  470. // Arguments: DWORD dwChangeFlag -
  471. //
  472. // Returns: Nothing
  473. //
  474. // History: fengsun Created Header 2/13/00
  475. //
  476. //+----------------------------------------------------------------------------
  477. void CNetcfgCluster::NotifyBindingChanges(DWORD dwChangeFlag, INetCfgBindingPath* pncbp) {
  478. TRACE_VERB("->%!FUNC!");
  479. TraceMsg(L"CNetcfgCluster::NotifyBindingChanges");
  480. ASSERT(!(dwChangeFlag & NCN_ADD && dwChangeFlag & NCN_REMOVE));
  481. Assert(!(dwChangeFlag & NCN_ENABLE && dwChangeFlag & NCN_DISABLE));
  482. if (dwChangeFlag & NCN_ADD) { m_fRemoveAdapter = false; }
  483. if ((dwChangeFlag & NCN_ENABLE) && !m_fMSCSWarningPopupLatched)
  484. {
  485. HINSTANCE hDll = LoadLibrary(L"clusapi.dll");
  486. if (NULL != hDll)
  487. {
  488. LPFNGNCS pfnGetNodeClusterState = (LPFNGNCS) GetProcAddress(hDll, "GetNodeClusterState");
  489. if (NULL != pfnGetNodeClusterState)
  490. {
  491. /* Warn the user via a pop-up if we detect MSCS is installed, but allow the NLB install to proceed. */
  492. DWORD dwClusterState = 0;
  493. if (ERROR_SUCCESS == pfnGetNodeClusterState(NULL, &dwClusterState))
  494. {
  495. if (ClusterStateNotRunning == dwClusterState || ClusterStateRunning == dwClusterState)
  496. {
  497. NcMsgBox(::GetActiveWindow(), IDS_PARM_WARN, IDS_PARM_MSCS_INSTALLED,
  498. MB_APPLMODAL | MB_ICONEXCLAMATION | MB_OK);
  499. m_fMSCSWarningPopupLatched = true;
  500. TRACE_INFO("%!FUNC! Cluster Service is installed");
  501. TraceMsg(L"CNetcfgCluster::NotifyBindingChanges Cluster Service is installed.");
  502. } else { /* MSCS is not installed. That's good! */ }
  503. } else {
  504. TRACE_CRIT("%!FUNC! error determining if MSCS is installed.");
  505. TraceMsg(L"CNetcfgCluster::NotifyBindingChanges error getting MSCS status.");
  506. }
  507. }
  508. else
  509. {
  510. TRACE_CRIT("%!FUNC! Get function address for GetNodeClusterState in clusapi.dll failed with %d", GetLastError());
  511. }
  512. if (!FreeLibrary(hDll))
  513. {
  514. TRACE_CRIT("%!FUNC! FreeLibrary for clusapi.dll failed with %d", GetLastError());
  515. }
  516. }
  517. else
  518. {
  519. TRACE_CRIT("%!FUNC! Load clusapi.dll failed with %d", GetLastError());
  520. }
  521. }
  522. if (dwChangeFlag & NCN_REMOVE) { m_fRemoveAdapter = true; }
  523. TRACE_VERB("<-%!FUNC!");
  524. }
  525. /*
  526. * Function: CNetcfgCluster::NotifyAdapter
  527. * Description: Notify an adapter of a state change
  528. * Author: shouse 6.1.00
  529. */
  530. DWORD CNetcfgCluster::NotifyAdapter (INetCfgComponent * pAdapter, DWORD newStatus) {
  531. TRACE_VERB("->%!FUNC!");
  532. HRESULT hr = S_OK;
  533. HDEVINFO hdi;
  534. SP_DEVINFO_DATA deid;
  535. PWSTR pszPnpDevNodeId;
  536. switch (newStatus) {
  537. case DICS_PROPCHANGE:
  538. TraceMsg(L"##### CWLBS::HrNotifyAdapter: Reload the adapter\n");
  539. break;
  540. case DICS_DISABLE:
  541. TraceMsg(L"##### CWLBS::HrNotifyAdapter: Disable the adapter\n");
  542. break;
  543. case DICS_ENABLE:
  544. TraceMsg(L"##### CWLBS::HrNotifyAdapter: Enable the adapter\n");
  545. break;
  546. default:
  547. TRACE_CRIT("%!FUNC! Invalid Notification 0x%x", newStatus);
  548. TraceMsg(L"##### CWLBS::HrNotifyAdapter: Invalid Notification 0x%x\n", newStatus);
  549. return ERROR_INVALID_PARAMETER;
  550. }
  551. if ((hr = HrSetupDiCreateDeviceInfoList(& GUID_DEVCLASS_NET, NULL, &hdi)) == S_OK) {
  552. if ((hr = pAdapter->GetPnpDevNodeId (& pszPnpDevNodeId)) == S_OK) {
  553. if ((hr = HrSetupDiOpenDeviceInfo (hdi, pszPnpDevNodeId, NULL, 0, &deid)) == S_OK) {
  554. if ((hr = HrSetupDiSendPropertyChangeNotification (hdi, & deid, newStatus, DICS_FLAG_GLOBAL, 0)) == S_OK) {
  555. TraceMsg(L"##### CWLBS::HrNotifyAdapter notified NIC\n");
  556. } else {
  557. TRACE_CRIT("%!FUNC! error %x in HrSetupDiSendPropertyChangeNotification", hr);
  558. TraceMsg(L"##### CWLBS::HrNotifyAdapter error %x in HrSetupDiSendPropertyChangeNotification\n", hr);
  559. }
  560. } else {
  561. TRACE_CRIT("%!FUNC! error %x in HrSetupDiOpenDeviceInfo", hr);
  562. TraceMsg(L"##### CWLBS::HrNotifyAdapter error %x in HrSetupDiOpenDeviceInfo\n", hr);
  563. }
  564. } else {
  565. TRACE_CRIT("%!FUNC! error %x in GetPnpDevNodeId", hr);
  566. TraceMsg(L"##### CWLBS::HrNotifyAdapter error %x in GetPnpDevNodeId\n", hr);
  567. }
  568. SetupDiDestroyDeviceInfoList (hdi);
  569. } else {
  570. TRACE_CRIT("%!FUNC! error %x in HrSetupDiCreateDeviceInfoList for Change: 0x%x", hr, newStatus);
  571. TraceMsg(L"##### CWLBS::HrNotifyAdapter error %x in HrSetupDiCreateDeviceInfoList for Change: 0x%x\n", newStatus);
  572. }
  573. TRACE_VERB("<-%!FUNC!");
  574. return hr;
  575. }
  576. //+----------------------------------------------------------------------------
  577. //
  578. // Function: CNetcfgCluster::ApplyRegistryChanges
  579. //
  580. // Description: Apply registry changes
  581. //
  582. // Arguments: None
  583. //
  584. // Returns: DWORD -
  585. //
  586. // History: fengsun Created Header 2/11/00
  587. //
  588. //+----------------------------------------------------------------------------
  589. DWORD CNetcfgCluster::ApplyRegistryChanges(bool fUninstall) {
  590. TRACE_VERB("->%!FUNC!");
  591. HRESULT hr = S_OK;
  592. DWORD dwStatus = 0;
  593. m_fReenableAdapter = false;
  594. m_fReloadRequired = false;
  595. /* Uninstall WLBS or remove the adapter. */
  596. if (fUninstall || m_fRemoveAdapter) {
  597. if (m_fHasOriginalConfig &&m_OriginalConfig.mcast_support == false ) {
  598. /* If we were in unicast mode, remove the mac, and reload Nic driver upon PnP. */
  599. if (fUninstall) {
  600. INetCfgComponent * pAdapter = NULL;
  601. /* If the adapter is enabled, disable it when the MAC address changes. This prevents a
  602. switch from learning a MAC address due to ARPs that TCP/IP sends out before WLBS is
  603. enabled and able to spoof the source MAC. The NIC will be re-enabled in ApplyPnpChanges(). */
  604. if ((hr = GetAdapterFromGuid(m_pConfig->m_pNetCfg, m_AdapterGuid, &pAdapter)) == S_OK) {
  605. ULONG status = 0UL;
  606. /* Only disable the adapter if the adapter is currently enabled and NLB was initially
  607. (in this netcfg session) bound to the adapter. */
  608. if (m_fOriginalBindingEnabled) {
  609. if ((hr = pAdapter->GetDeviceStatus(&status)) == S_OK) {
  610. if (status != CM_PROB_DISABLED) {
  611. m_fReenableAdapter = true;
  612. m_fReloadRequired = false;
  613. TRACE_INFO("%!FUNC! disable adapter");
  614. dwStatus = NotifyAdapter(pAdapter, DICS_DISABLE);
  615. if (!SUCCEEDED(dwStatus))
  616. {
  617. TRACE_CRIT("%!FUNC! disable the adapter for NLB uninstall or adapter remove failed with %d", dwStatus);
  618. } else
  619. {
  620. TRACE_INFO("%!FUNC! disable the adapter for NLB uninstall or adapter remove succeeded");
  621. }
  622. }
  623. }
  624. }
  625. pAdapter->Release();
  626. pAdapter = NULL;
  627. }
  628. m_fMacAddrChanged = true;
  629. }
  630. /* remove mac addr, */
  631. if (m_pConfig->m_pWlbsApiFuncs->pfnRegChangeNetworkAddress(m_AdapterGuid, m_OriginalConfig.cl_mac_addr, true) == false) {
  632. dwStatus = GetLastError();
  633. TraceError("CWlbsCluster::WriteConfig failed at RegChangeNetworkAddress", dwStatus);
  634. TRACE_CRIT("<-%!FUNC! failed removing MAC address with %d", dwStatus);
  635. }
  636. }
  637. m_pConfig->m_pWlbsApiFuncs->pfnParamDeleteReg(m_AdapterGuid, false);
  638. TRACE_INFO("<-%!FUNC! Exiting on success removing adapter or uninstalling NLB");
  639. TRACE_VERB("<-%!FUNC!");
  640. return ERROR_SUCCESS;
  641. }
  642. /* Find out whether the adapter is bound to NLB. */
  643. INetCfgComponent* pAdapter = NULL;
  644. bool fCurrentBindingEnabled;
  645. // bool fOriginalMacAddrSet;
  646. bool fCurrentMacAddrSet;
  647. bool fAdapterDisabled = false; // Assuming that Adapter is NOT disabled
  648. if ((hr = GetAdapterFromGuid(m_pConfig->m_pNetCfg, m_AdapterGuid, &pAdapter)) != S_OK) {
  649. fCurrentBindingEnabled = false;
  650. } else {
  651. ULONG status = 0UL;
  652. fCurrentBindingEnabled = (m_pConfig->IsBoundTo(pAdapter) == S_OK);
  653. if ((hr = pAdapter->GetDeviceStatus(&status)) == S_OK) {
  654. TRACE_INFO("%!FUNC! device status is 0x%x", status);
  655. if (status == CM_PROB_DISABLED)
  656. {
  657. fAdapterDisabled = true;
  658. }
  659. }
  660. else
  661. {
  662. TRACE_CRIT("%!FUNC! GetDeviceStatus failed with 0x%x, Assuming that adapter is NOT disabled", hr);
  663. }
  664. pAdapter->Release();
  665. pAdapter = NULL;
  666. }
  667. // Note: make sure to call ParamWriteReg before early exit. Needed in case
  668. // upgrading to build where new reg keys are introduced
  669. // The m_fHasOriginalConfig flag will be false if
  670. // 1. Bind NLB for the first time
  671. // 2. Clean Installs with NLB info in Answer file
  672. // 3. Upgrade from NT 4 or Win 2k or XP with Port Rules in Binary format
  673. // In case #1 & #2, the following attempt to delete registry entries from the old location
  674. // will be a no-op 'cos there will be no old registry entries to delete
  675. bool bStatus = true;
  676. if (!m_fHasOriginalConfig)
  677. {
  678. TRACE_INFO("%!FUNC! deleting old parameters from the registry");
  679. if (!m_pConfig->m_pWlbsApiFuncs->pfnParamDeleteReg(m_AdapterGuid, true))
  680. {
  681. TRACE_CRIT("%!FUNC! error deleting parameters from the registry");
  682. }
  683. }
  684. TRACE_INFO("%!FUNC! writing parameters to the registry");
  685. if (!m_pConfig->m_pWlbsApiFuncs->pfnParamWriteReg(m_AdapterGuid, &m_CurrentConfig))
  686. {
  687. TRACE_CRIT("%!FUNC! error writing parameters to the registry");
  688. TRACE_VERB("<-%!FUNC!");
  689. return WLBS_REG_ERROR;
  690. }
  691. if ((m_fOriginalBindingEnabled == fCurrentBindingEnabled) && m_fHasOriginalConfig) {
  692. if (!memcmp(&m_OriginalConfig, &m_CurrentConfig, sizeof(m_CurrentConfig))) {
  693. /* If the binding hasn't changed and we have previously bound to this adapter
  694. (originalconfig -> loaded from registry) and the NLB parameters haven't
  695. changed, then nothing changed and we can bail out here. */
  696. TRACE_INFO("%!FUNC! no changes needed...exiting");
  697. TRACE_VERB("<-%!FUNC!");
  698. return WLBS_OK;
  699. } else {
  700. /* Otherwise, if the binding hasn't changed, NLB is currently bound, and we have
  701. previously bound to this adapter (originalconfig -> loaded from registry)
  702. and the NLB parameters HAVE changed, then we need to reload the driver. */
  703. if (fCurrentBindingEnabled && !fAdapterDisabled)
  704. {
  705. m_fReloadRequired = true;
  706. TRACE_INFO("%!FUNC! will reload adapter");
  707. }
  708. }
  709. }
  710. /* If MSCS is installed and NLB is bound, throw an NT event (event is latched, so check this too) */
  711. DWORD dwClusterState = 0;
  712. if (fCurrentBindingEnabled && !m_fMSCSWarningEventLatched)
  713. {
  714. HINSTANCE hDll = LoadLibrary(L"clusapi.dll");
  715. if (NULL != hDll)
  716. {
  717. LPFNGNCS pfnGetNodeClusterState = (LPFNGNCS) GetProcAddress(hDll, "GetNodeClusterState");
  718. if (NULL != pfnGetNodeClusterState)
  719. {
  720. if (ERROR_SUCCESS == pfnGetNodeClusterState(NULL, &dwClusterState))
  721. {
  722. if (ClusterStateNotRunning == dwClusterState || ClusterStateRunning == dwClusterState)
  723. {
  724. /* Log NT event -- Do not throw an error if these calls fail. This is just best effort. */
  725. HANDLE hES = RegisterEventSourceW (NULL, CVY_NAME);
  726. if (NULL != hES)
  727. {
  728. TRACE_INFO("%!FUNC! detected that MSCS is installed");
  729. TraceMsg(L"CNetcfgCluster::ApplyRegistryChanges MSCS warning event needs to be logged.");
  730. if (ReportEventW(hES, /* Handle to event log*/
  731. EVENTLOG_WARNING_TYPE, /* Event type */
  732. 0, /* Category */
  733. IDS_INSTALL_WITH_MSCS_INSTALLED, /* MessageId */
  734. NULL, /* Security identifier */
  735. 0, /* Num args to event string */
  736. 0, /* Size of binary data */
  737. NULL, /* Ptr to args for event string */
  738. NULL)) /* Ptr to binary data */
  739. {
  740. /* Latch the event, so it won't be thrown again */
  741. m_fMSCSWarningEventLatched = true;
  742. }
  743. else
  744. {
  745. /* Couldn't log the NT event. Don't fail anything; we aren't latched so we'll try to log again on next change */
  746. TRACE_CRIT("%!FUNC! call to write the MSCS warning event failed");
  747. TraceMsg(L"CNetcfgCluster::ApplyRegistryChanges failed to write MSCS warning event to log.");
  748. }
  749. DeregisterEventSource(hES);
  750. }
  751. else
  752. {
  753. TRACE_CRIT("%!FUNC! failed call to RegisterEventSource to log the MSCS warning event.");
  754. TraceMsg(L"CNetcfgCluster::ApplyRegistryChanges failed call to RegisterEventSource for MSCS warning event.");
  755. }
  756. }
  757. else { /* MS Cluster Service is not installed. That's good! */ }
  758. }
  759. else
  760. {
  761. TRACE_CRIT("%!FUNC! error determining if MSCS is installed.");
  762. TraceMsg(L"CNetcfgCluster::ApplyRegistryChanges error checking MSCS state.");
  763. }
  764. }
  765. else
  766. {
  767. TRACE_CRIT("%!FUNC! Get function address for GetNodeClusterState in clusapi.dll failed with %d", GetLastError());
  768. }
  769. if (!FreeLibrary(hDll))
  770. {
  771. TRACE_CRIT("%!FUNC! FreeLibrary for clusapi.dll failed with %d", GetLastError());
  772. }
  773. }
  774. else
  775. {
  776. TRACE_CRIT("%!FUNC! Load clusapi.dll failed with %d", GetLastError());
  777. }
  778. }
  779. /* Write adapter name into the registry for API use. */
  780. if(!WriteAdapterName(m_pConfig, m_AdapterGuid))
  781. {
  782. TRACE_CRIT("%!FUNC! error writing adapter name into the registry (for API use)");
  783. }
  784. if (!m_fOriginalBindingEnabled && fCurrentBindingEnabled) {
  785. /* This is a BIND operation. Create/Modify the initial state registry
  786. key. We initialize the state to the user-specified preference in
  787. the host TAB of the UI - ClusterModeOnStart. The driver will
  788. subsequently update this key with the current state of the driver
  789. in order to persist that state across reboots, etc. */
  790. if (!WriteHostStateRegistryKey(m_pConfig, m_AdapterGuid, m_CurrentConfig.cluster_mode)) {
  791. TRACE_CRIT("%!FUNC! error writing host state into the registry");
  792. } else {
  793. TRACE_INFO("%!FUNC! host state set to: %s", (m_CurrentConfig.cluster_mode == CVY_HOST_STATE_STARTED) ? "Started" :
  794. (m_CurrentConfig.cluster_mode == CVY_HOST_STATE_STOPPED) ? "Stopped" :
  795. (m_CurrentConfig.cluster_mode == CVY_HOST_STATE_SUSPENDED) ? "Suspended" : "Unknown");
  796. }
  797. }
  798. /* Figure out whether we need to change MAC address. */
  799. // if (!m_fOriginalBindingEnabled || !m_fHasOriginalConfig)
  800. // fOriginalMacAddrSet = false;
  801. // else
  802. // fOriginalMacAddrSet = !m_OriginalConfig.mcast_support;
  803. if (!fCurrentBindingEnabled)
  804. fCurrentMacAddrSet = false;
  805. else
  806. fCurrentMacAddrSet = !m_CurrentConfig.mcast_support;
  807. /* If the MAC address changes because we are unbinding NLB, disable the adapter. The reload flag should be set true already
  808. if that is needed. So we modify it to false if we are disabling the adapter, but leave it untouched otherwise. Because
  809. an IP address change does not ALWAYS cause a MAC address change, we will also bounce the NIC if the cluster IP address
  810. changes. Although this is not necessary from an operational perspective, we do it to achieve consistency in the resulting
  811. state of NLB - we bounce the NIC in these cases to cause NLB to re-assume its initial host state in all cases where we
  812. change our cluster membership (primary IP change, MAC change or bind/unbind). */
  813. if (m_fOriginalBindingEnabled != fCurrentBindingEnabled ||
  814. m_CurrentConfig.mcast_support != m_OriginalConfig.mcast_support ||
  815. wcscmp(m_CurrentConfig.cl_mac_addr, m_OriginalConfig.cl_mac_addr) ||
  816. wcscmp(m_CurrentConfig.cl_ip_addr, m_OriginalConfig.cl_ip_addr) )
  817. {
  818. if (m_fOriginalBindingEnabled && !fCurrentBindingEnabled)
  819. {
  820. if ((hr = GetAdapterFromGuid(m_pConfig->m_pNetCfg, m_AdapterGuid, &pAdapter)) == S_OK) {
  821. ULONG status = 0UL;
  822. if ((hr = pAdapter->GetDeviceStatus(&status)) == S_OK) {
  823. TRACE_INFO("%!FUNC! device status is 0x%x", status);
  824. if (status != CM_PROB_DISABLED) {
  825. m_fReenableAdapter = true;
  826. m_fReloadRequired = false;
  827. TRACE_INFO("%!FUNC! disable adapter");
  828. dwStatus = NotifyAdapter(pAdapter, DICS_DISABLE);
  829. if (!SUCCEEDED(dwStatus))
  830. {
  831. TRACE_CRIT("%!FUNC! a call to NotifyAdapter to disable the adapter for a MAC address change failed with %d", dwStatus);
  832. } else
  833. {
  834. TRACE_INFO("%!FUNC! a call to NotifyAdapter to disable the adapter for a MAC address change succeeded");
  835. }
  836. }
  837. }
  838. else
  839. {
  840. TRACE_CRIT("%!FUNC! GetDeviceStatus failed with 0x%x", hr);
  841. }
  842. pAdapter->Release();
  843. pAdapter = NULL;
  844. }
  845. else
  846. {
  847. TRACE_CRIT("%!FUNC! GetAdapterFromGuid failed with 0x%x", hr);
  848. }
  849. }
  850. /* Change the mac address. */
  851. m_fMacAddrChanged = true;
  852. m_pConfig->m_pWlbsApiFuncs->pfnRegChangeNetworkAddress(m_AdapterGuid, m_CurrentConfig.cl_mac_addr, !fCurrentMacAddrSet);
  853. TraceMsg(L"New MAC address written to registry");
  854. TRACE_INFO("%!FUNC! new MAC address written to registry");
  855. }
  856. CopyMemory(&m_OriginalConfig, &m_CurrentConfig, sizeof(m_CurrentConfig));
  857. m_fHasOriginalConfig = true;
  858. m_fOriginalBindingEnabled = fCurrentBindingEnabled;
  859. TRACE_VERB("<-%!FUNC!");
  860. return ERROR_SUCCESS;
  861. }
  862. //+----------------------------------------------------------------------------
  863. //
  864. // Function: CNetcfgCluster::ResetMSCSLatches
  865. //
  866. // Description: Resets the static flags for latching warning popup and NT event
  867. // when MSCS is already installed. This reset allows the user to
  868. // control the period during which latching is valid
  869. //
  870. // Arguments: None
  871. //
  872. // Returns: None
  873. //
  874. // History: chrisdar Created: 01.05.07
  875. //
  876. //+----------------------------------------------------------------------------
  877. void CNetcfgCluster::ResetMSCSLatches() {
  878. TRACE_VERB("->%!FUNC!");
  879. CNetcfgCluster::m_fMSCSWarningEventLatched = false;
  880. CNetcfgCluster::m_fMSCSWarningPopupLatched = false;
  881. TRACE_VERB("<-%!FUNC!");
  882. }
  883. //+----------------------------------------------------------------------------
  884. //
  885. // Function: CNetcfgCluster::ApplyPnpChanges
  886. //
  887. // Description: Apply the changes to drivers
  888. //
  889. // Arguments: HANDLE hWlbsDevice -
  890. //
  891. // Returns: DWORD - Win32 Error
  892. //
  893. // History: fengsun Created Header 2/11/00
  894. //
  895. //+----------------------------------------------------------------------------
  896. DWORD CNetcfgCluster::ApplyPnpChanges(HANDLE hDeviceWlbs) {
  897. TRACE_VERB("->%!FUNC!");
  898. if (m_fReloadRequired && (hDeviceWlbs != INVALID_HANDLE_VALUE)) {
  899. DWORD dwStatus = m_pConfig->m_pWlbsApiFuncs->pfnNotifyDriverConfigChanges(hDeviceWlbs, m_AdapterGuid); // Always returns ERROR_SUCCESS
  900. TraceMsg(L"NLB driver notified of configuration changes");
  901. TRACE_INFO("%!FUNC! nlb driver notified of configuration changes and returned %d where %d indicates success", dwStatus, ERROR_SUCCESS);
  902. }
  903. if (m_fMacAddrChanged) {
  904. PWSTR pszPnpDevNodeId = NULL;
  905. INetCfgComponent* pAdapter = NULL;
  906. HRESULT hr;
  907. hr = GetAdapterFromGuid(m_pConfig->m_pNetCfg, m_AdapterGuid, &pAdapter);
  908. if (hr != S_OK) {
  909. TraceError("GetAdapterFromGuid failed at GetPnpDevNodeId", hr);
  910. TRACE_CRIT("%!FUNC! call to GetAdapterFromGuid failed with %d", hr);
  911. return false;
  912. }
  913. hr = pAdapter->GetPnpDevNodeId (& pszPnpDevNodeId);
  914. if (hr != S_OK) {
  915. TraceError("HrWriteAdapterName failed at GetPnpDevNodeId", hr);
  916. TRACE_CRIT("%!FUNC! call to GetPnpDevNodeId failed with %d", hr);
  917. pAdapter->Release();
  918. pAdapter = NULL;
  919. return false;
  920. }
  921. /*
  922. The following function "NotifyAdapterAddressChangeEx" calls into setup apis
  923. to get the network adapter to adopt its new mac address. This leads to the
  924. network adapter getting disabled and re-enabled. Because the setup apis
  925. are asynchronous, NotifyAdapterAddressChangeEx, in order to determine the completeness
  926. of the disable and re-enable process, waits until a "Query" to the NLB driver
  927. is successful. Obviously, in order for the "Query" to succeed, the NLB driver has to be
  928. re-bound to the network adapter upon re-enable of the network adapter. So, we check
  929. if NLB is bound to the network adapter NOW (this means NLB will be re-bound) to
  930. indicate to "NotifyAdapterAddressChangeEx" if it should wait until the "Query" succeeds.
  931. If we are executing in the context of an Unbind or Uninstall+Unbind of NLB, obviously,
  932. NLB will NOT re-bound to the network adapter upon re-enable. So, "NotifyAdapterAddressChangeEx"
  933. will NOT wait. But, we are fine because the network adapter *should* already have been
  934. disabled (in ApplyRegistryChanges). So, the call to "NotifyAdapterAddressChangeEx"
  935. will be a no-op.
  936. -- KarthicN, 05-31-02
  937. */
  938. m_pConfig->m_pWlbsApiFuncs->pfnNotifyAdapterAddressChangeEx(pszPnpDevNodeId,
  939. m_AdapterGuid,
  940. (m_pConfig->IsBoundTo(pAdapter) == S_OK));
  941. TraceMsg(L"Adapter notified of new MAC address");
  942. TRACE_INFO("%!FUNC! adapter notified of new MAC address");
  943. /* If the adapter was disabled in ApplyRegistryChanges() because the MAC
  944. address changed and the NIC was enabled, then re-enable it here. */
  945. if (m_fReenableAdapter) {
  946. TRACE_INFO("%!FUNC! enable adapter");
  947. DWORD dwStatus = NotifyAdapter(pAdapter, DICS_ENABLE);
  948. if (!SUCCEEDED(dwStatus))
  949. {
  950. TRACE_CRIT("%!FUNC! a call to NotifyAdapter to reenable the adapter after a previous disable for a MAC address change failed with %d", dwStatus);
  951. } else
  952. {
  953. TRACE_INFO("%!FUNC! a call to NotifyAdapter to reenable the adapter after a previous disable for a MAC address change succeeded");
  954. }
  955. }
  956. pAdapter->Release();
  957. pAdapter = NULL;
  958. CoTaskMemFree(pszPnpDevNodeId);
  959. }
  960. TRACE_VERB("<-%!FUNC!");
  961. return ERROR_SUCCESS;
  962. }
  963. /*
  964. * Function: CNetcfgCluster::CheckForDuplicateClusterIPAddress
  965. * Description: Used to check for duplicate cluster IP addresses across multiple NICs.
  966. * Note that this method uses IP information taken from the NLB registry, not from TCP/IP.
  967. * As a result, this checking is incomplete and no guarantee can be made that an IP will not be usurped.
  968. * Author: shouse 10.24.00
  969. * History: ChrisDar 06.06.02 Adapter must be currently installed for it to contribute to the duplicate checking.
  970. */
  971. bool CNetcfgCluster::CheckForDuplicateClusterIPAddress (WCHAR * szOtherIP) {
  972. TRACE_VERB("->%!FUNC!");
  973. TraceMsg(L"CNetcfgCluster::CheckForDuplicateClusterIPAddress");
  974. HRESULT hr = S_OK;
  975. /* First check to see whether the cluster IP addresses match. */
  976. if (!wcscmp(m_CurrentConfig.cl_ip_addr, szOtherIP)) {
  977. INetCfgComponent* pAdapter = NULL;
  978. TRACE_INFO("%!FUNC! possible duplicate IP address found");
  979. /* If they do match, get the INetCfgComponent interface for this GUID. */
  980. if ((hr = GetAdapterFromGuid(m_pConfig->m_pNetCfg, m_AdapterGuid, &pAdapter)) != S_OK) {
  981. TraceError("GetAdapterFromGuid failed in CNetcfgCluster::CheckForDuplicateClusterIPAddress", hr);
  982. TRACE_CRIT("%!FUNC! call to GetAdapterFromGuid failed with %d. Treating this as a 'match-not-found' case.", hr);
  983. TRACE_VERB("<-%!FUNC!");
  984. return FALSE;
  985. }
  986. {
  987. ULONG status = E_UNEXPECTED;
  988. hr = pAdapter->GetDeviceStatus(&status);
  989. if (hr == S_OK)
  990. {
  991. /* The device with this IP is installed, but we don't have a duplicate unless NLB is bound to it. */
  992. if (m_pConfig->IsBoundTo(pAdapter) == S_OK)
  993. {
  994. TRACE_INFO("%!FUNC! duplicate IP address found");
  995. TRACE_VERB("<-%!FUNC!");
  996. pAdapter->Release();
  997. pAdapter = NULL;
  998. return TRUE;
  999. }
  1000. TRACE_INFO("%!FUNC! NLB is not bound to this adapter. This is not a duplicate match.");
  1001. }
  1002. else if (hr == NETCFG_E_ADAPTER_NOT_FOUND)
  1003. {
  1004. TRACE_INFO("%!FUNC! matching adapter found but it is not currently installed. This is not a duplicate match.");
  1005. }
  1006. else
  1007. {
  1008. TRACE_CRIT("%!FUNC! error 0x%x while getting device status of adapter. Treating this as a 'match-not-found' case.", hr);
  1009. }
  1010. }
  1011. pAdapter->Release();
  1012. pAdapter = NULL;
  1013. }
  1014. TRACE_INFO("%!FUNC! no duplicate IP address was found");
  1015. TRACE_VERB("<-%!FUNC!");
  1016. return FALSE;
  1017. }
  1018. /*
  1019. * Function: CNetcfgCluster::CheckForDuplicateBDATeamMaster
  1020. * Description: Used to check for duplicate masters in the same BDA team.
  1021. * Author: shouse 1.29.02
  1022. */
  1023. bool CNetcfgCluster::CheckForDuplicateBDATeamMaster (NETCFG_WLBS_BDA_TEAMING * pBDATeaming) {
  1024. TRACE_VERB("->%!FUNC!");
  1025. TraceMsg(L"CNetcfgCluster::CheckForDuplicateBDATeamMaster");
  1026. HRESULT hr = S_OK;
  1027. /* If the adapter being operated on (probably being bound, if we've come down
  1028. this path) is not part of a BDA team, or is not the master of its team, then
  1029. there is no reason to check. Note that this check should have already been
  1030. done by the calling function. */
  1031. if (!m_CurrentConfig.bda_teaming.active || !m_CurrentConfig.bda_teaming.master) {
  1032. TRACE_INFO("%!FUNC! this adapter is not the master of a BDA team.");
  1033. TRACE_VERB("<-%!FUNC!");
  1034. return FALSE;
  1035. }
  1036. /* Otherwise, if the adapter we're comparing against is not part of a BDA team,
  1037. or is not the master of its team, there's nothing to compare. */
  1038. if (!pBDATeaming->active || !pBDATeaming->master) {
  1039. TRACE_INFO("%!FUNC! other adapter is not the master of a BDA team.");
  1040. TRACE_VERB("<-%!FUNC!");
  1041. return FALSE;
  1042. }
  1043. /* At this point, both adapters are masters of a BDA team. Check to see
  1044. whether its the SAME BDA team. */
  1045. if (!wcscmp(m_CurrentConfig.bda_teaming.team_id, pBDATeaming->team_id)) {
  1046. INetCfgComponent* pAdapter = NULL;
  1047. /* If they do match, get the INetCfgComponent interface for this GUID. */
  1048. if ((hr = GetAdapterFromGuid(m_pConfig->m_pNetCfg, m_AdapterGuid, &pAdapter)) != S_OK) {
  1049. TraceError("GetAdapterFromGuid failed in CNetcfgCluster::CheckForDuplicateBDATeamMaster", hr);
  1050. TRACE_CRIT("%!FUNC! call to GetAdapterFromGuid failed with %d", hr);
  1051. TRACE_VERB("<-%!FUNC!");
  1052. return FALSE;
  1053. }
  1054. /* If NLB is bound to this adapter, then there is a conflict. */
  1055. if (m_pConfig->IsBoundTo(pAdapter) == S_OK)
  1056. {
  1057. TRACE_INFO("%!FUNC! duplicate BDA team masters found");
  1058. TRACE_VERB("<-%!FUNC!");
  1059. pAdapter->Release();
  1060. pAdapter = NULL;
  1061. return TRUE;
  1062. }
  1063. pAdapter->Release();
  1064. pAdapter = NULL;
  1065. }
  1066. TRACE_INFO("%!FUNC! no duplicate BDA team master was found");
  1067. TRACE_VERB("<-%!FUNC!");
  1068. return FALSE;
  1069. }
  1070. // ----------------------------------------------------------------------
  1071. //
  1072. // Function: CWlbsConfig::CWlbsConfig
  1073. //
  1074. // Purpose: constructor for class CWlbsConfig
  1075. //
  1076. // Arguments: None
  1077. //
  1078. // Returns: None
  1079. //
  1080. // Notes:
  1081. //
  1082. // ----------------------------------------------------------------------
  1083. CWlbsConfig::CWlbsConfig(VOID) {
  1084. TRACE_VERB("->%!FUNC!");
  1085. TraceMsg(L"CWlbsConfig::CWlbsConfig");
  1086. m_pWlbsComponent = NULL;
  1087. m_pNetCfg = NULL;
  1088. m_ServiceOperation = WLBS_SERVICE_NONE;
  1089. m_hDeviceWlbs = INVALID_HANDLE_VALUE;
  1090. m_hdllWlbsCtrl = NULL;
  1091. m_pWlbsApiFuncs = NULL;
  1092. /* Initialize latched flags of CNetCfgCluster so that we get pristine
  1093. MSCS popup and NT events when making config changes and MSCS is installed.
  1094. Comment out this call if the NT event and popup should be thrown only
  1095. once per loading of this dll */
  1096. CNetcfgCluster::ResetMSCSLatches();
  1097. TRACE_VERB("<-%!FUNC!");
  1098. }
  1099. // ----------------------------------------------------------------------
  1100. //
  1101. // Function: CWlbsConfig::~CWlbsConfig
  1102. //
  1103. // Purpose: destructor for class CWlbsConfig
  1104. //
  1105. // Arguments: None
  1106. //
  1107. // Returns: None
  1108. //
  1109. // Notes:
  1110. //
  1111. // ----------------------------------------------------------------------
  1112. CWlbsConfig::~CWlbsConfig(VOID) {
  1113. TRACE_VERB("->%!FUNC!");
  1114. TraceMsg(L"CWlbsConfig::~CWlbsConfig");
  1115. /* Release interfaces if acquired. */
  1116. ReleaseObj(m_pWlbsComponent);
  1117. ReleaseObj(m_pNetCfg);
  1118. if (m_pWlbsApiFuncs) delete m_pWlbsApiFuncs;
  1119. if (m_hdllWlbsCtrl) FreeLibrary(m_hdllWlbsCtrl);
  1120. /* Free all clusters. */
  1121. for (vector<CNetcfgCluster*>::iterator iter = m_vtrCluster.begin(); iter != m_vtrCluster.end(); iter++) {
  1122. CNetcfgCluster* pCluster = *iter;
  1123. ASSERT(pCluster != NULL);
  1124. delete pCluster;
  1125. }
  1126. TRACE_VERB("<-%!FUNC!");
  1127. }
  1128. // ----------------------------------------------------------------------
  1129. //
  1130. // Function: CWlbsConfig::Initialize
  1131. //
  1132. // Purpose: Initialize the notify object
  1133. //
  1134. // Arguments:
  1135. // pnccItem [in] pointer to INetCfgComponent object
  1136. // pnc [in] pointer to INetCfg object
  1137. // fInstalling [in] TRUE if we are being installed
  1138. //
  1139. // Returns:
  1140. //
  1141. // Notes:
  1142. //
  1143. // ----------------------------------------------------------------------
  1144. STDMETHODIMP CWlbsConfig::Initialize(INetCfg* pNetCfg, BOOL fInstalling) {
  1145. TRACE_VERB("->%!FUNC!");
  1146. TraceMsg(L"CWlbsConfig::Initialize");
  1147. HRESULT hr = S_OK;
  1148. /* Load wlbsctrl.dll */
  1149. ASSERT(m_pWlbsApiFuncs == NULL);
  1150. ASSERT(m_hdllWlbsCtrl == NULL);
  1151. m_pWlbsApiFuncs = new WlbsApiFuncs;
  1152. if (m_pWlbsApiFuncs == NULL)
  1153. {
  1154. TRACE_CRIT("%!FUNC! memory allocation failed for m_pWlbsApiFuncs");
  1155. return E_OUTOFMEMORY;
  1156. }
  1157. m_hdllWlbsCtrl = LoadWlbsCtrlDll(m_pWlbsApiFuncs);
  1158. if (m_hdllWlbsCtrl == NULL) {
  1159. DWORD dwStatus = GetLastError();
  1160. TRACE_CRIT("%!FUNC! failed to load wlbsctrl.dll with error %d", dwStatus);
  1161. TraceError("CWlbsConfig::Initialize Failed to load wlbsctrl.dll", dwStatus);
  1162. // CLD: What in the world is going on here?
  1163. if (dwStatus == ERROR_SUCCESS)
  1164. {
  1165. TRACE_VERB("<-%!FUNC!");
  1166. return E_FAIL;
  1167. }
  1168. TRACE_VERB("<-%!FUNC!");
  1169. return HRESULT_FROM_WIN32(dwStatus);
  1170. }
  1171. AddRefObj (m_pNetCfg = pNetCfg);
  1172. /* Find the WLBS component. */
  1173. ASSERT(m_pWlbsComponent == NULL);
  1174. m_pWlbsComponent = NULL;
  1175. /* The WLBS conponent object is not available at installation time. */
  1176. if (!fInstalling) {
  1177. if (FAILED(hr = pNetCfg->FindComponent(NETCFG_WLBS_ID, &m_pWlbsComponent)) || m_pWlbsComponent == NULL) {
  1178. ASSERT(fInstalling);
  1179. TRACE_CRIT("%!FUNC! find for nlb component object failed with %d", hr);
  1180. TraceError("INetCfg::FindComponent failed",hr);
  1181. }
  1182. hr = LoadAllAdapterSettings(false); // fUpgradeFromWin2k = false
  1183. if (FAILED(hr))
  1184. {
  1185. TRACE_CRIT("%!FUNC! loading all adapter settings for a non-window 2000 upgrade failed with %d", hr);
  1186. }
  1187. }
  1188. ASSERT_VALID(this);
  1189. TRACE_VERB("<-%!FUNC!");
  1190. return S_OK;
  1191. }
  1192. //+----------------------------------------------------------------------------
  1193. //
  1194. // Function: CWlbsConfig::LoadAllAdapters
  1195. //
  1196. // Description: Load all cluster settings from registry
  1197. //
  1198. // Arguments: None
  1199. //
  1200. // Returns: HRESULT -
  1201. //
  1202. // History: fengsun Created Header 2/14/00
  1203. //
  1204. //+----------------------------------------------------------------------------
  1205. HRESULT CWlbsConfig::LoadAllAdapterSettings(bool fUpgradeFromWin2k) {
  1206. TRACE_VERB("->%!FUNC!");
  1207. TraceMsg(L"CWlbsConfig::LoadAllAdapterSettings");
  1208. HRESULT hr = S_OK;
  1209. INetCfgClass *pNetCfgClass = NULL;
  1210. INetCfgComponent* pNetCardComponent = NULL;
  1211. ASSERT_VALID(this);
  1212. hr = m_pNetCfg->QueryNetCfgClass(&GUID_DEVCLASS_NET, IID_INetCfgClass, (void **)&pNetCfgClass);
  1213. if (FAILED(hr)) {
  1214. TraceError("INetCfg::QueryNetCfgClass failed", hr);
  1215. TRACE_CRIT("%!FUNC! call to QueryNetCfgClass failed with %d", hr);
  1216. TRACE_VERB("<-%!FUNC!");
  1217. return hr;
  1218. }
  1219. /* Get an enumerator to list all network devices. */
  1220. IEnumNetCfgComponent *pIEnumComponents = NULL;
  1221. if (FAILED(hr = pNetCfgClass->EnumComponents(&pIEnumComponents))) {
  1222. TraceError("INetCfg::EnumComponents failed", hr);
  1223. TRACE_CRIT("%!FUNC! call to enumerate components failed with %d", hr);
  1224. pNetCfgClass->Release();
  1225. TRACE_VERB("<-%!FUNC!");
  1226. return hr;
  1227. }
  1228. /* Go through all the adapters and load settings for adapters that are bound to WLBS. */
  1229. while (pIEnumComponents->Next(1, &pNetCardComponent, NULL) == S_OK) {
  1230. GUID AdapterGuid;
  1231. /* Retrieve the instance GUID of the component. */
  1232. if (FAILED(hr = (pNetCardComponent)->GetInstanceGuid(&AdapterGuid))) {
  1233. pNetCardComponent->Release();
  1234. pNetCardComponent = NULL;
  1235. TraceError("GetInstanceGuid failed", hr);
  1236. TRACE_CRIT("%!FUNC! call to retrieve the guid instance of the adapter failed with %d", hr);
  1237. continue;
  1238. }
  1239. bool fBound = (IsBoundTo(pNetCardComponent) == S_OK);
  1240. pNetCardComponent->Release();
  1241. pNetCardComponent = NULL;
  1242. /* Win2k support only one adapter. The settings will be lost if not bound. */
  1243. if (fUpgradeFromWin2k && !fBound) continue;
  1244. /* Load settings regardless of bindings for non-upgrade case. */
  1245. CNetcfgCluster* pCluster = new CNetcfgCluster(this);
  1246. if (pCluster == NULL)
  1247. {
  1248. TRACE_CRIT("%!FUNC! failed memory allocation for CNetcfgCluster");
  1249. TRACE_VERB("<-%!FUNC!");
  1250. return ERROR_OUTOFMEMORY;
  1251. }
  1252. DWORD dwStatus = pCluster->InitializeFromRegistry(AdapterGuid, fBound, fUpgradeFromWin2k);
  1253. if (dwStatus != ERROR_SUCCESS) {
  1254. /* If NLB is already bound to this adapter, this may be an issue. Normally, it will be
  1255. an indication of something heinous, but in the case of a win2k (perhaps NT4.0 as well),
  1256. its only happening because we're looking for the NLB settings in the wrong place. If
  1257. so, a subsequent call to our Upgrade COM API will fall-back to attempt to read from
  1258. the win2k location in the registry. Because we don't know here whether or not this is
  1259. an upgrade, etc., we don't have the necessary information to be able to ASSERT that
  1260. this is wrong with any real certainty. */
  1261. if (fBound) {
  1262. TRACE_CRIT("%!FUNC! Reading NLB information from registry failed with status=0x%08x", dwStatus);
  1263. }
  1264. delete pCluster;
  1265. continue;
  1266. }
  1267. m_vtrCluster.push_back(pCluster);
  1268. }
  1269. pIEnumComponents->Release();
  1270. pNetCfgClass->Release();
  1271. TRACE_VERB("<-%!FUNC!");
  1272. return S_OK;
  1273. }
  1274. // ----------------------------------------------------------------------
  1275. //
  1276. // Function: CWlbsConfig::ReadAnswerFile
  1277. //
  1278. // Purpose: Read settings from answerfile and configure WLBS
  1279. //
  1280. // Arguments:
  1281. // pszAnswerFile [in] name of AnswerFile
  1282. // pszAnswerSection [in] name of parameters section
  1283. //
  1284. // Returns:
  1285. //
  1286. // Notes: Dont do anything irreversible (like modifying registry) yet
  1287. // since the config. actually complete only when Apply is called!
  1288. //
  1289. // ----------------------------------------------------------------------
  1290. STDMETHODIMP CWlbsConfig::ReadAnswerFile(PCWSTR pszAnswerFile, PCWSTR pszAnswerSection) {
  1291. TRACE_VERB("->%!FUNC!");
  1292. TraceMsg(L"CWlbsConfig::ReadAnswerFile");
  1293. HRESULT hr = S_OK;
  1294. CSetupInfFile caf;
  1295. ASSERT_VALID(this);
  1296. AssertSz(pszAnswerFile, "Answer file string is NULL!");
  1297. AssertSz(pszAnswerSection, "Answer file sections string is NULL!");
  1298. // Open the answer file.
  1299. hr = caf.HrOpen(pszAnswerFile, NULL, INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL);
  1300. if (FAILED(hr)) {
  1301. TraceError("caf.HrOpen failed", hr);
  1302. WriteNlbSetupErrorLog(IDS_PARM_OPEN_ANS_FILE_FAILED, hr);
  1303. TRACE_CRIT("%!FUNC! attempt to open answer file failed with %d", hr);
  1304. TRACE_VERB("<-%!FUNC!");
  1305. return S_OK;
  1306. }
  1307. // Get the adapter specific parameters
  1308. WCHAR * mszAdapterList;
  1309. TRACE_INFO("%!FUNC! answer section name from answer file=%ls", pszAnswerSection);
  1310. hr = HrSetupGetFirstMultiSzFieldWithAlloc(caf.Hinf(), pszAnswerSection, c_szAdapterSections, &mszAdapterList);
  1311. if (FAILED(hr)) {
  1312. TraceError("WLBS HrSetupGetFirstMultiSzFieldWithAlloc failed", hr);
  1313. //
  1314. // We get here on any error reading the answer file. Log to setuperr.log only if the problem is not
  1315. // a missing section. NLB is optional, not mandatory, for an install.
  1316. //
  1317. // Check for, and ignore, both missing section and missing line. The latter is returned currently, but the former
  1318. // makes more sense here, because that means the NLB section is completely missing.
  1319. //
  1320. if ((SPAPI_E_LINE_NOT_FOUND != hr) && (SPAPI_E_SECTION_NOT_FOUND != hr))
  1321. {
  1322. WriteNlbSetupErrorLog(IDS_PARM_GET_ADAPTERS_FAILED, hr);
  1323. }
  1324. TRACE_CRIT("%!FUNC! attempt to retrieve adapter list from answer file failed with %d", hr);
  1325. TRACE_VERB("<-%!FUNC!");
  1326. return S_OK;
  1327. }
  1328. TRACE_INFO("%!FUNC! list of adapters with nlb settings=%ls", mszAdapterList);
  1329. tstring strAdapterName;
  1330. tstring strInterfaceRegPath;
  1331. for (PCWSTR pszAdapterSection = mszAdapterList; *pszAdapterSection; pszAdapterSection += lstrlenW(pszAdapterSection) + 1) {
  1332. // Get the card name "SpecificTo = ..."
  1333. TRACE_INFO("%!FUNC! adapter section=%ls", pszAdapterSection);
  1334. hr = HrSetupGetFirstString(caf.Hinf(), pszAdapterSection, c_szAfSpecificTo, &strAdapterName);
  1335. if (FAILED(hr)) {
  1336. TraceError("WLBS HrSetupGetFirstString failed", hr);
  1337. WriteNlbSetupErrorLog(IDS_PARM_GET_SPECIFIC_TO, pszAdapterSection, hr);
  1338. TRACE_CRIT("%!FUNC! attempt to retrieve adapter name from answer file failed with %d. Skipping to next adapter", hr);
  1339. continue;
  1340. }
  1341. TRACE_INFO("%!FUNC! adapter to which nlb settings apply=%ls", strAdapterName.c_str());
  1342. GUID guidNetCard;
  1343. if (!FGetInstanceGuidOfComponentInAnswerFile(strAdapterName.c_str(), m_pNetCfg, &guidNetCard)) {
  1344. TraceError("WLBS FGetInstanceGuidOfComponentInAnswerFile failed", FALSE);
  1345. WriteNlbSetupErrorLog(IDS_PARM_GET_NETCARD_GUID);
  1346. TRACE_CRIT("%!FUNC! attempt to retrieve netcard guid from answer file failed. Skipping to next adapter");
  1347. continue;
  1348. }
  1349. CNetcfgCluster* pCluster = new CNetcfgCluster(this);
  1350. if (pCluster == NULL)
  1351. {
  1352. WriteNlbSetupErrorLog(IDS_PARM_OOM_NETCFGCLUS);
  1353. TRACE_CRIT("%!FUNC! memory allocation failure for CNetcfgCluster");
  1354. TRACE_VERB("<-%!FUNC!");
  1355. return ERROR_OUTOFMEMORY;
  1356. }
  1357. if (FAILED(hr = pCluster->InitializeFromAnswerFile(guidNetCard, caf, pszAdapterSection))) {
  1358. TraceError("WLBS InitializeFromAnswerFile failed", hr);
  1359. TRACE_CRIT("%!FUNC! attempt to initialize the adapter settings from answer file failed with %d. Skipping to next adapter", hr);
  1360. delete pCluster;
  1361. continue;
  1362. }
  1363. m_vtrCluster.push_back(pCluster);
  1364. }
  1365. delete [] mszAdapterList;
  1366. caf.Close();
  1367. TRACE_VERB("<-%!FUNC!");
  1368. return S_OK;
  1369. }
  1370. // ----------------------------------------------------------------------
  1371. //
  1372. // Function: CWlbsConfig::Install
  1373. //
  1374. // Purpose: Do operations necessary for install.
  1375. //
  1376. // Arguments:
  1377. // dwSetupFlags [in] Setup flags
  1378. //
  1379. // Returns: S_OK on success, otherwise an error code
  1380. //
  1381. // Notes: Dont do anything irreversible (like modifying registry) yet
  1382. // since the config. actually complete only when Apply is called!
  1383. //
  1384. // ----------------------------------------------------------------------
  1385. STDMETHODIMP CWlbsConfig::Install(DWORD /* dw */) {
  1386. TRACE_VERB("->%!FUNC!");
  1387. TraceMsg(L"CWlbsConfig::Install");
  1388. HRESULT hr = S_OK;
  1389. ASSERT_VALID(this);
  1390. /* Start up the install process. */
  1391. m_ServiceOperation = WLBS_SERVICE_INSTALL;
  1392. if (m_pWlbsComponent == NULL && FAILED(m_pNetCfg->FindComponent(NETCFG_WLBS_ID, &m_pWlbsComponent)) || m_pWlbsComponent == NULL) {
  1393. TraceError("INetCfg::FindComponent failed at Install",hr);
  1394. TRACE_CRIT("%!FUNC! find for nlb component object failed with %d", hr);
  1395. }
  1396. TRACE_VERB("->%!FUNC!");
  1397. return hr;
  1398. }
  1399. // ----------------------------------------------------------------------
  1400. //
  1401. // Function: CWlbsConfig::Upgrade
  1402. //
  1403. // Purpose: Do operations necessary for upgrade.
  1404. //
  1405. // Arguments:
  1406. // dwSetupFlags [in] Setup flags
  1407. //
  1408. // Returns: S_OK on success, otherwise an error code
  1409. //
  1410. // ----------------------------------------------------------------------
  1411. STDMETHODIMP CWlbsConfig::Upgrade(DWORD /* dwSetupFlags */, DWORD /* dwUpgradeFromBuildNo */) {
  1412. TRACE_VERB("->%!FUNC!");
  1413. TraceMsg(L"CWlbsConfig::Upgrade");
  1414. ASSERT_VALID(this);
  1415. /* If we do not have any cluster, there might be
  1416. old registry settings under different place. */
  1417. if (m_vtrCluster.size() == 0)
  1418. {
  1419. HRESULT hr = LoadAllAdapterSettings(true); // fUpgradeFromWin2k = true
  1420. if (FAILED(hr))
  1421. {
  1422. TRACE_CRIT("%!FUNC! loading all adapter settings for a window 2000 upgrade failed with %d", hr);
  1423. }
  1424. }
  1425. m_ServiceOperation = WLBS_SERVICE_UPGRADE;
  1426. TRACE_VERB("<-%!FUNC!");
  1427. return S_OK;
  1428. }
  1429. // ----------------------------------------------------------------------
  1430. //
  1431. // Function: CWlbsConfig::Removing
  1432. //
  1433. // Purpose: Do necessary cleanup when being removed
  1434. //
  1435. // Arguments: None
  1436. //
  1437. // Returns: S_OK on success, otherwise an error code
  1438. //
  1439. // Notes: Dont do anything irreversible (like modifying registry) yet
  1440. // since the removal is actually complete only when Apply is called!
  1441. //
  1442. // ----------------------------------------------------------------------
  1443. STDMETHODIMP CWlbsConfig::Removing(VOID) {
  1444. TRACE_VERB("->%!FUNC!");
  1445. TraceMsg(L"##### CWlbsConfig::Removing\n");
  1446. ASSERT_VALID(this);
  1447. m_ServiceOperation = WLBS_SERVICE_REMOVE;
  1448. TRACE_VERB("<-%!FUNC!");
  1449. return S_OK;
  1450. }
  1451. //+----------------------------------------------------------------------------
  1452. //
  1453. // Function: CWlbsConfig::GetAdapterConfig
  1454. //
  1455. // Description: Read the adapter config, which could be cached by SetAdapterConfig
  1456. //
  1457. // Arguments: const GUID& AdapterGuid -
  1458. // NETCFG_WLBS_CONFIG* pClusterConfig -
  1459. //
  1460. // Returns: STDMETHODIMP -
  1461. //
  1462. // History: fengsun Created Header 3/2/00
  1463. //
  1464. //+----------------------------------------------------------------------------
  1465. STDMETHODIMP CWlbsConfig::GetAdapterConfig(const GUID& AdapterGuid, NETCFG_WLBS_CONFIG* pClusterConfig) {
  1466. TRACE_VERB("->%!FUNC!");
  1467. TraceMsg(L"CWlbsConfig::GetAdapterConfig");
  1468. ASSERT_VALID(this);
  1469. ASSERT(pClusterConfig);
  1470. CNetcfgCluster* pCluster = GetCluster(AdapterGuid);
  1471. if (pCluster == NULL)
  1472. {
  1473. TRACE_INFO("%!FUNC! did not find cluster");
  1474. return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
  1475. }
  1476. pCluster->GetConfig(pClusterConfig); // Returns void
  1477. TRACE_VERB("<-%!FUNC!");
  1478. return S_OK;
  1479. }
  1480. //+----------------------------------------------------------------------------
  1481. //
  1482. // Function: CWlbsConfig::SetAdapterConfig
  1483. //
  1484. // Description: Set the adapter config, the result is cached and not saved to registry
  1485. //
  1486. // Arguments: const GUID& AdapterGuid -
  1487. // NETCFG_WLBS_CONFIG* pClusterConfig -
  1488. //
  1489. // Returns: STDMETHODIMP -
  1490. //
  1491. // History: fengsun Created Header 3/2/00
  1492. //
  1493. //+----------------------------------------------------------------------------
  1494. STDMETHODIMP CWlbsConfig::SetAdapterConfig(const GUID& AdapterGuid, NETCFG_WLBS_CONFIG* pClusterConfig) {
  1495. TRACE_VERB("->%!FUNC!");
  1496. TraceMsg(L"CWlbsConfig::SetAdapterConfig");
  1497. ASSERT_VALID(this);
  1498. ASSERT(pClusterConfig);
  1499. CNetcfgCluster* pCluster = GetCluster(AdapterGuid);
  1500. if (pCluster == NULL) {
  1501. TRACE_INFO("%!FUNC! did not find cluster. Will create instance");
  1502. pCluster = new CNetcfgCluster(this);
  1503. if (pCluster == NULL)
  1504. {
  1505. TRACE_CRIT("%!FUNC! memory allocation failure creating instance of CNetcfgCluster");
  1506. TRACE_VERB("<-%!FUNC!");
  1507. return E_OUTOFMEMORY;
  1508. }
  1509. pCluster->InitializeWithDefault(AdapterGuid); // Returns void
  1510. //
  1511. // See bug 233962, NLB configuration lost when leaving nlb properties
  1512. // The reason is that NLB notifier object is not notified when NLB is checked.
  1513. // Currently, there is no consistant repro. Uncommented the code below will fix the peoblem.
  1514. // But will leaves potential bug in netcfg hard to catch.
  1515. // Uncomment the code only after the netcfg bug is fixed.
  1516. //
  1517. // m_vtrCluster.push_back(pCluster);
  1518. }
  1519. pCluster->SetConfig(pClusterConfig); // Returns void
  1520. TRACE_VERB("<-%!FUNC!");
  1521. return S_OK;
  1522. }
  1523. // ----------------------------------------------------------------------
  1524. //
  1525. // Function: CWlbsConfig::ApplyRegistryChanges
  1526. //
  1527. // Purpose: Apply changes.
  1528. //
  1529. // Arguments: None
  1530. //
  1531. // Returns: S_OK on success, otherwise an error code
  1532. //
  1533. // Notes: We can make changes to registry etc. here.
  1534. //
  1535. // ----------------------------------------------------------------------
  1536. STDMETHODIMP CWlbsConfig::ApplyRegistryChanges(VOID) {
  1537. DWORD dwIPSecFlags = 0;
  1538. DWORD dwStatus;
  1539. TRACE_VERB("->%!FUNC!");
  1540. TraceMsg(L"CWlbsConfig::ApplyRegistryChanges");
  1541. ASSERT_VALID(this);
  1542. for (vector<CNetcfgCluster*>::iterator iter = m_vtrCluster.begin(); iter != m_vtrCluster.end(); iter++) {
  1543. CNetcfgCluster* pCluster = *iter;
  1544. ASSERT(pCluster != NULL);
  1545. if (pCluster != NULL)
  1546. {
  1547. dwStatus = pCluster->ApplyRegistryChanges(m_ServiceOperation == WLBS_SERVICE_REMOVE);
  1548. if (ERROR_SUCCESS != dwStatus && WLBS_OK != dwStatus)
  1549. {
  1550. TRACE_CRIT("%!FUNC! applying registry changes to a CNetcfgCluster failed with %d. Continue with next instance", dwStatus);
  1551. }
  1552. }
  1553. else
  1554. {
  1555. TRACE_CRIT("%!FUNC! retrieved null instance of CNetcfgCluster");
  1556. }
  1557. }
  1558. /* If NLB is being uninstalled, then we definately need to notify
  1559. IPSec that we're going away, so turn off the "NLB bound" bit
  1560. in the NLB flags. */
  1561. if (m_ServiceOperation == WLBS_SERVICE_REMOVE) {
  1562. dwIPSecFlags &= ~FLAGS_NLBS_BOUND; /* Defined in winipsec.h */
  1563. } else {
  1564. /* Count the number of adapters that NLB is currently bound to.
  1565. This count INCLUDES the operation we are in the middle of
  1566. performing, if we happen to be binding or unbinding. */
  1567. ULONG dwNLBInstances = CountNLBBindings();
  1568. /* If this is a bind and we are the first instance of NLB on this host,
  1569. then notify IPSec that NLB is now bound. */
  1570. if (dwNLBInstances > 0) {
  1571. dwIPSecFlags |= FLAGS_NLBS_BOUND; /* Defined in winipsec.h */
  1572. } else {
  1573. dwIPSecFlags &= ~FLAGS_NLBS_BOUND; /* Defined in winipsec.h */
  1574. }
  1575. }
  1576. if (!WriteIPSecNLBRegistryKey(dwIPSecFlags)) {
  1577. TRACE_CRIT("%!FUNC! Unable to notify IPSec of NLB binding changes... This will affect the ability of NLB to track IPSec sessions");
  1578. } else {
  1579. TRACE_INFO("%!FUNC! IPSec successfully notified of NLB binding status");
  1580. }
  1581. TRACE_VERB("<-%!FUNC!");
  1582. return S_OK;
  1583. }
  1584. // ----------------------------------------------------------------------
  1585. //
  1586. // Function: CWlbsConfig::ApplyPnpChanges
  1587. //
  1588. // Purpose: Apply changes.
  1589. //
  1590. // Arguments: None
  1591. //
  1592. // Returns: S_OK on success, otherwise an error code
  1593. //
  1594. // Notes: Propagate changes to the driver.
  1595. //
  1596. // ----------------------------------------------------------------------
  1597. STDMETHODIMP CWlbsConfig::ApplyPnpChanges() {
  1598. TRACE_VERB("->%!FUNC!");
  1599. TraceMsg(L"CWlbsConfig::ApplyPnpChanges");
  1600. vector<CNetcfgCluster*>::iterator iter;
  1601. bool bCreateDevice = FALSE;
  1602. DWORD dwStatus = ERROR_SUCCESS;
  1603. ASSERT_VALID(this);
  1604. /* Check to see if we need to open the IOCTL interface to the driver. This is necessary
  1605. if any adapter in our cluster list requries a reload (which is done via an IOCTL). */
  1606. for (iter = m_vtrCluster.begin(); iter != m_vtrCluster.end(); iter++) {
  1607. CNetcfgCluster* pCluster = *iter;
  1608. if (bCreateDevice |= pCluster->IsReloadRequired()) break;
  1609. }
  1610. /* Open the file and return an error if this is unsuccessful. */
  1611. if (bCreateDevice) {
  1612. TRACE_INFO("%!FUNC! at least one adapter requires a reload. Open an IOCTL.");
  1613. ASSERT(m_hDeviceWlbs == INVALID_HANDLE_VALUE);
  1614. m_hDeviceWlbs = CreateFile(_TEXT("\\\\.\\WLBS"), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
  1615. if (m_hDeviceWlbs == INVALID_HANDLE_VALUE) {
  1616. dwStatus = GetLastError();
  1617. TraceMsg(L"Error opening \\\\.\\WLBS device %x", dwStatus);
  1618. TraceError("Invalid \\\\.\\WLBS handle", dwStatus);
  1619. TRACE_CRIT("%!FUNC! invalid handle opening \\\\.\\WLBS device. Error is %d", dwStatus);
  1620. return HRESULT_FROM_WIN32(dwStatus);
  1621. }
  1622. ASSERT(m_hDeviceWlbs != INVALID_HANDLE_VALUE);
  1623. }
  1624. for (iter = m_vtrCluster.begin(); iter != m_vtrCluster.end(); iter++) {
  1625. CNetcfgCluster* pCluster = *iter;
  1626. ASSERT(pCluster != NULL);
  1627. if (pCluster != NULL)
  1628. {
  1629. dwStatus = pCluster->ApplyPnpChanges(m_hDeviceWlbs);
  1630. if (ERROR_SUCCESS != dwStatus)
  1631. {
  1632. TRACE_CRIT("%!FUNC! apply pnp changes on CNetcfgCluster failed with %d", dwStatus);
  1633. }
  1634. }
  1635. else
  1636. {
  1637. TRACE_CRIT("%!FUNC! retrieved null instance of CNetcfgCluster");
  1638. }
  1639. }
  1640. if (m_hDeviceWlbs != INVALID_HANDLE_VALUE)
  1641. {
  1642. if (!CloseHandle(m_hDeviceWlbs))
  1643. {
  1644. dwStatus = GetLastError();
  1645. TRACE_CRIT("%!FUNC! close nlb device handle failed with %d", dwStatus);
  1646. }
  1647. }
  1648. TRACE_VERB("<-%!FUNC!");
  1649. return S_OK;
  1650. }
  1651. // ----------------------------------------------------------------------
  1652. //
  1653. // Function: CWlbsConfig::QueryBindingPath
  1654. //
  1655. // Purpose: Allow or veto a binding path involving us
  1656. //
  1657. // Arguments:
  1658. // dwChangeFlag [in] type of binding change
  1659. // pncbi [in] pointer to INetCfgBindingPath object
  1660. //
  1661. // Returns: S_OK on success, otherwise an error code
  1662. //
  1663. // Notes:
  1664. //
  1665. // ----------------------------------------------------------------------
  1666. STDMETHODIMP CWlbsConfig::QueryBindingPath(DWORD dwChangeFlag, INetCfgComponent* pAdapter) {
  1667. TRACE_VERB("->%!FUNC!");
  1668. TraceMsg(L"CWlbsConfig::QueryBindingPath");
  1669. ASSERT_VALID(this);
  1670. TRACE_VERB("<-%!FUNC!");
  1671. return NETCFG_S_DISABLE_QUERY;
  1672. }
  1673. // ----------------------------------------------------------------------
  1674. //
  1675. // Function: CWlbsConfig::NotifyBindingPath
  1676. //
  1677. // Purpose: System tells us by calling this function which
  1678. // binding path involving us has just been formed.
  1679. //
  1680. // Arguments:
  1681. // dwChangeFlag [in] type of binding change
  1682. // pncbp [in] pointer to INetCfgBindingPath object
  1683. //
  1684. // Returns: S_OK on success, otherwise an error code
  1685. //
  1686. // Notes:
  1687. //
  1688. // ----------------------------------------------------------------------
  1689. STDMETHODIMP CWlbsConfig::NotifyBindingPath(DWORD dwChangeFlag, INetCfgBindingPath* pncbp) {
  1690. TRACE_VERB("->%!FUNC!");
  1691. TraceMsg(L"CWlbsConfig::NotifyBindingPath");
  1692. HRESULT hr = S_OK;
  1693. INetCfgComponent * pAdapter;
  1694. PWSTR pszInterfaceName;
  1695. GUID AdapterGuid;
  1696. DWORD dwStatus = 0;
  1697. ASSERT_VALID(this);
  1698. if (m_pWlbsComponent == NULL && FAILED(m_pNetCfg->FindComponent(NETCFG_WLBS_ID, &m_pWlbsComponent)) || m_pWlbsComponent == NULL) {
  1699. dwStatus = GetLastError();
  1700. TraceError("NotifyBindingPath failed at INetCfg::FindComponent\n", dwStatus);
  1701. TRACE_CRIT("%!FUNC! find for nlb component object failed with %d", dwStatus);
  1702. TRACE_VERB("<-%!FUNC!");
  1703. return S_FALSE;
  1704. }
  1705. hr = HrGetLastComponentAndInterface (pncbp, &pAdapter, &pszInterfaceName);
  1706. if (FAILED(hr))
  1707. {
  1708. TRACE_CRIT("%!FUNC! enumerating binding path failed with %d", hr);
  1709. TRACE_VERB("<-%!FUNC!");
  1710. return hr;
  1711. }
  1712. CoTaskMemFree(pszInterfaceName);
  1713. hr = pAdapter->GetInstanceGuid(&AdapterGuid);
  1714. pAdapter->Release();
  1715. pAdapter = NULL;
  1716. if (FAILED(hr))
  1717. {
  1718. TRACE_CRIT("%!FUNC! retrieval of adapter guid from adapter failed with %d", hr);
  1719. TRACE_VERB("<-%!FUNC!");
  1720. return hr;
  1721. }
  1722. CNetcfgCluster* pCluster = GetCluster(AdapterGuid);
  1723. if (pCluster == NULL) {
  1724. if (dwChangeFlag & NCN_ENABLE) {
  1725. /* new configuration. */
  1726. pCluster = new CNetcfgCluster(this);
  1727. if (pCluster == NULL)
  1728. {
  1729. TRACE_CRIT("%!FUNC! memory allocation failure creating instance of CNetcfgCluster");
  1730. TRACE_VERB("<-%!FUNC!");
  1731. return E_OUTOFMEMORY;
  1732. }
  1733. pCluster->InitializeWithDefault(AdapterGuid); // Returns void
  1734. m_vtrCluster.push_back(pCluster);
  1735. } else {
  1736. TraceMsg(L"CWlbsConfig::NotifyBindingPath adapter not bound");
  1737. TRACE_INFO("%!FUNC! adapter is not bound");
  1738. TRACE_VERB("<-%!FUNC!");
  1739. return S_OK;
  1740. }
  1741. }
  1742. pCluster->NotifyBindingChanges(dwChangeFlag, pncbp); // Returns void
  1743. /* If we are enabling a binding path, then check for cluster IP address conflicts. */
  1744. if (dwChangeFlag & NCN_ENABLE) {
  1745. NETCFG_WLBS_CONFIG adapterConfig;
  1746. /* Retrieve the cluster configuration. */
  1747. pCluster->GetConfig(&adapterConfig); // Returns void
  1748. /* If we detect another bound adapter with this cluster IP address, then revert this cluster's
  1749. cluster IP Address to the default value. If the user opens the property dialog, they can
  1750. change the IP address, but we CANNOT warn them here - this code can be run programmatically.
  1751. However, because the user CAN bind NLB without opening the properties, we MUST check this here. */
  1752. if ((hr = CheckForDuplicateCLusterIPAddresses(AdapterGuid, &adapterConfig)) != S_OK) {
  1753. TRACE_CRIT("%!FUNC! another adapter is bound and has the same cluster IP address %ls. Status of check is %d", adapterConfig.cl_ip_addr, hr);
  1754. /* Revert this cluster IP Address to the default (0.0.0.0). */
  1755. (VOID) StringCchCopy(adapterConfig.cl_ip_addr, ASIZECCH(adapterConfig.cl_ip_addr), CVY_DEF_CL_IP_ADDR);
  1756. /* Revert this cluster subnet mask to the default (0.0.0.0). */
  1757. (VOID) StringCchCopy(adapterConfig.cl_net_mask, ASIZECCH(adapterConfig.cl_net_mask), CVY_DEF_CL_NET_MASK);
  1758. /* Set the cluster configuration. */
  1759. pCluster->SetConfig(&adapterConfig); // Returns void
  1760. }
  1761. /* If this adapter happens to be configured for BDA teaming, and is the master, make sure that
  1762. no other adapter was set to be the master of this team while NLB was unbound from this NIC.
  1763. If there is a conflict, inactivate BDA teaming on this NIC. */
  1764. if ((hr = CheckForDuplicateBDATeamMasters(AdapterGuid, &adapterConfig)) != S_OK) {
  1765. TRACE_CRIT("%!FUNC! another adapter is bound and is the master for this BDA team %ls. Status of check is %d", adapterConfig.bda_teaming.team_id, hr);
  1766. /* Remove the BDA teaming settings for this adapter. */
  1767. adapterConfig.bda_teaming.active = FALSE;
  1768. /* Set the cluster configuration. */
  1769. pCluster->SetConfig(&adapterConfig); // Returns void
  1770. }
  1771. }
  1772. TRACE_VERB("<-%!FUNC!");
  1773. return S_OK;
  1774. }
  1775. /*
  1776. * Function: NLBIsBound
  1777. * Description: Returns TRUE if this instance of NLB is currently bound,
  1778. * FALSE if it is not.
  1779. * Author: shouse, 8.27.01
  1780. */
  1781. bool CNetcfgCluster::NLBIsBound () {
  1782. INetCfgComponent * pAdapter = NULL;
  1783. HRESULT hr = S_OK;
  1784. bool bBound = false;
  1785. TRACE_VERB("->%!FUNC!");
  1786. /* Use our GUID to get our netcfg component object pointer.
  1787. If this fails, then we are definately not bound. */
  1788. if ((hr = GetAdapterFromGuid(m_pConfig->m_pNetCfg, m_AdapterGuid, &pAdapter)) != S_OK) {
  1789. TRACE_INFO("%!FUNC! Unable to get Adapter from GUID.");
  1790. bBound = false;
  1791. } else {
  1792. /* Otherwise, call IsBoundTo to query the binding of this
  1793. instance. A return value of S_OK indicates bound. */
  1794. bBound = (m_pConfig->IsBoundTo(pAdapter) == S_OK);
  1795. /* Release the interface reference. */
  1796. pAdapter->Release();
  1797. pAdapter = NULL;
  1798. }
  1799. TRACE_VERB("<-%!FUNC!");
  1800. return bBound;
  1801. }
  1802. /*
  1803. * Function: CountNLBBindings
  1804. * Description: Returns the number of instances of NLB that are currently bound.
  1805. * Author: shouse, 8.27.01
  1806. */
  1807. ULONG CWlbsConfig::CountNLBBindings () {
  1808. ULONG status = E_UNEXPECTED;
  1809. ULONG count = 0;
  1810. HRESULT hr = S_OK;
  1811. TRACE_VERB("->%!FUNC!");
  1812. /* Loop through all of our cluster objects and determine the binding state of each one. */
  1813. for (vector<CNetcfgCluster *>::iterator iter = m_vtrCluster.begin(); iter != m_vtrCluster.end(); iter++) {
  1814. CNetcfgCluster * pCluster = *iter;
  1815. INetCfgComponent* pAdapter = NULL;
  1816. ASSERT(pCluster);
  1817. if (!pCluster) {
  1818. TRACE_INFO("%!FUNC! Found NULL pointer to a CNetcfgCluster.");
  1819. continue;
  1820. }
  1821. /* Get the INetCfgComponent interface for this instance. */
  1822. if ((hr = GetAdapterFromGuid(m_pNetCfg, pCluster->GetAdapterGuid(), &pAdapter)) != S_OK) {
  1823. TRACE_CRIT("%!FUNC! Call to GetAdapterFromGuid failed, hr=0x%08x.", hr);
  1824. continue;
  1825. }
  1826. hr = pAdapter->GetDeviceStatus(&status);
  1827. if (hr == S_OK)
  1828. {
  1829. /* A return value of OK means that the device is physically present. If NLB
  1830. is bound to this adapter, add one to the count. */
  1831. if (pCluster->NLBIsBound())
  1832. {
  1833. count++;
  1834. TRACE_INFO("%!FUNC! NLB is bound to this adapter.");
  1835. }
  1836. else
  1837. {
  1838. TRACE_INFO("%!FUNC! NLB is not bound to this adapter.");
  1839. }
  1840. }
  1841. else if (hr == NETCFG_E_ADAPTER_NOT_FOUND)
  1842. {
  1843. TRACE_INFO("%!FUNC! Adapter is not currently installed.");
  1844. }
  1845. else
  1846. {
  1847. TRACE_CRIT("%!FUNC! Error while getting device status of the adapter, hr=0x%08x.", hr);
  1848. }
  1849. pAdapter->Release();
  1850. pAdapter = NULL;
  1851. }
  1852. TRACE_VERB("<-%!FUNC!");
  1853. return count;
  1854. }
  1855. //+----------------------------------------------------------------------------
  1856. //
  1857. // Function: CWlbsConfig::GetCluster
  1858. //
  1859. // Description:
  1860. //
  1861. // Arguments: const GUID& AdapterGuid -
  1862. //
  1863. // Returns: CNetcfgCluster* -
  1864. //
  1865. // History: fengsun Created Header 2/14/00
  1866. //
  1867. //+----------------------------------------------------------------------------
  1868. CNetcfgCluster* CWlbsConfig::GetCluster(const GUID& AdapterGuid) {
  1869. TRACE_VERB("->%!FUNC!");
  1870. TraceMsg(L"CWlbsConfig::GetCluster");
  1871. ASSERT_VALID(this);
  1872. for (vector<CNetcfgCluster*>::iterator iter = m_vtrCluster.begin(); iter != m_vtrCluster.end(); iter++) {
  1873. CNetcfgCluster* pCluster = *iter;
  1874. ASSERT(pCluster != NULL);
  1875. if (pCluster != NULL) {
  1876. if (IsEqualGUID(pCluster->GetAdapterGuid(), AdapterGuid))
  1877. {
  1878. TRACE_INFO("%!FUNC! cluster instance found");
  1879. TRACE_VERB("<-%!FUNC!");
  1880. return pCluster;
  1881. }
  1882. }
  1883. else
  1884. {
  1885. TRACE_CRIT("%!FUNC! retrieved null instance of CNetcfgCluster. Skipping it.");
  1886. }
  1887. }
  1888. TRACE_INFO("%!FUNC! cluster instance not found");
  1889. TRACE_VERB("<-%!FUNC!");
  1890. return NULL;
  1891. }
  1892. //+----------------------------------------------------------------------------
  1893. //
  1894. // Function: CWlbsConfig::IsBoundTo
  1895. //
  1896. // Description:
  1897. //
  1898. // Arguments: INetCfgComponent* pAdapter -
  1899. //
  1900. // Returns: HRESULT -
  1901. //
  1902. // History: fengsun Created Header 2/14/00
  1903. //
  1904. //+----------------------------------------------------------------------------
  1905. HRESULT CWlbsConfig::IsBoundTo(INetCfgComponent* pAdapter) {
  1906. TRACE_VERB("->%!FUNC!");
  1907. TraceMsg(L"CWlbsConfig::IsBoundTo");
  1908. HRESULT hr;
  1909. ASSERT_VALID(this);
  1910. ASSERT(pAdapter != NULL);
  1911. if (m_pWlbsComponent == NULL) {
  1912. TraceMsg(L"CWlbsConfig::IsBoundTo wlbs not installed");
  1913. TRACE_INFO("%!FUNC! nlb is not installed");
  1914. TRACE_VERB("<-%!FUNC!");
  1915. return S_FALSE;
  1916. }
  1917. INetCfgComponentBindings *pIBinding = NULL;
  1918. if (FAILED(m_pWlbsComponent->QueryInterface(IID_INetCfgComponentBindings, (void**)&pIBinding))) {
  1919. DWORD dwStatus = GetLastError();
  1920. TraceError("QI for INetCfgComponentBindings failed\n", dwStatus);
  1921. TRACE_INFO("%!FUNC! QueryInterface on the nlb component object failed with %d", dwStatus);
  1922. }
  1923. if (FAILED(hr = pIBinding->IsBoundTo(pAdapter))) {
  1924. TraceError("Failed to IsBoundTo", hr);
  1925. TRACE_INFO("%!FUNC! the check whether nlb is bound to an adapter failed with %d", hr);
  1926. }
  1927. if (pIBinding) pIBinding->Release();
  1928. TRACE_VERB("<-%!FUNC!");
  1929. return hr;
  1930. }
  1931. //+----------------------------------------------------------------------------
  1932. //
  1933. // Function: CWlbsConfig::SetDefaults
  1934. //
  1935. // Description:
  1936. //
  1937. // Arguments: NETCFG_WLBS_CONFIG* pClusterConfig -
  1938. //
  1939. // Returns: Nothing
  1940. //
  1941. // History: fengsun Created Header 2/14/00
  1942. //
  1943. //+----------------------------------------------------------------------------
  1944. void CWlbsConfig::SetDefaults(NETCFG_WLBS_CONFIG* pClusterConfig) {
  1945. TRACE_VERB("->%!FUNC!");
  1946. TraceMsg(L"CWlbsConfig::SetDefaults");
  1947. WLBS_REG_PARAMS config;
  1948. ASSERT_VALID(this);
  1949. ASSERT(pClusterConfig);
  1950. ASSERT(m_pWlbsApiFuncs);
  1951. ASSERT(m_pWlbsApiFuncs->pfnParamSetDefaults);
  1952. DWORD dwStatus = m_pWlbsApiFuncs->pfnParamSetDefaults(&config);
  1953. if (WLBS_OK != dwStatus)
  1954. {
  1955. TRACE_CRIT("%!FUNC! failed to set defaults for the cluster configuration");
  1956. }
  1957. WlbsToNetcfgConfig(m_pWlbsApiFuncs, &config, pClusterConfig); // Returns void
  1958. TRACE_VERB("<-%!FUNC!");
  1959. }
  1960. /*
  1961. * Function: CWlbsConfig::ValidateProperties
  1962. * Description: Check for conflicting cluster IP addresses and alert the user.
  1963. * Author: shouse 7.13.00
  1964. */
  1965. STDMETHODIMP CWlbsConfig::ValidateProperties (HWND hwndSheet, GUID adapterGUID, NETCFG_WLBS_CONFIG * adapterConfig) {
  1966. TRACE_VERB("->%!FUNC!");
  1967. TraceMsg(L"CWlbsConfig::ValidateProperties");
  1968. HRESULT hr = S_OK;
  1969. ASSERT_VALID(this);
  1970. /* If we detect another bound adapter with this cluster IP address, then fail the check and
  1971. pop-up an error message warning the user that there are conflicting IP addresses. */
  1972. if ((hr = CheckForDuplicateCLusterIPAddresses(adapterGUID, adapterConfig)) != S_OK)
  1973. {
  1974. NcMsgBox(hwndSheet, IDS_PARM_ERROR, IDS_PARM_MULTINIC_IP_CONFLICT, MB_APPLMODAL | MB_ICONSTOP | MB_OK);
  1975. TRACE_CRIT("%!FUNC! another network adapter is using IP address %ls", adapterConfig->cl_ip_addr);
  1976. }
  1977. TRACE_VERB("<-%!FUNC!");
  1978. return hr;
  1979. }
  1980. /*
  1981. * Function: CWlbsConfig::CheckForDuplicateCLusterIPAddresses
  1982. * Description: Loop through all adapters and check for conflicting cluster IP addresses.
  1983. * Author: shouse 7.13.00
  1984. */
  1985. STDMETHODIMP CWlbsConfig::CheckForDuplicateCLusterIPAddresses (GUID adapterGUID, NETCFG_WLBS_CONFIG * adapterConfig) {
  1986. TRACE_VERB("->%!FUNC!");
  1987. TraceMsg(L"CWlbsConfig::CheckForDuplicateCLusterIPAddresses");
  1988. CNetcfgCluster * pClusterMe = NULL;
  1989. ASSERT_VALID(this);
  1990. /* Get the cluster pointer for this adapter GUID. */
  1991. pClusterMe = GetCluster(adapterGUID);
  1992. ASSERT(pClusterMe);
  1993. if (!pClusterMe)
  1994. {
  1995. TRACE_INFO("%!FUNC! no cluster instance was found for the supplied adapter");
  1996. TRACE_VERB("<-%!FUNC!");
  1997. return S_OK;
  1998. }
  1999. /* If the cluster IP address is the default, then don't check other adapters because
  2000. if they have not been configured yet, this may cause confusion for the user. We
  2001. will ignore the error here and other validation in the cluster properties should
  2002. catch this error instead. */
  2003. if (!lstrcmpi(adapterConfig->cl_ip_addr, CVY_DEF_CL_IP_ADDR))
  2004. {
  2005. TRACE_INFO("%!FUNC! the adapter has the default cluster IP address. No checking needed.");
  2006. TRACE_VERB("<-%!FUNC!");
  2007. return S_OK;
  2008. }
  2009. /* Loop through the rest of the list and check this cluster IP against the cluster
  2010. IP of each adapter left in the list. */
  2011. for (vector<CNetcfgCluster *>::iterator iter = m_vtrCluster.begin(); iter != m_vtrCluster.end(); iter++) {
  2012. CNetcfgCluster * pCluster = *iter;
  2013. ASSERT(pCluster);
  2014. if (!pCluster)
  2015. {
  2016. /* CLD: 05.17.01 is this a no op or do we store nulls in the vector? */
  2017. TRACE_INFO("%!FUNC! Found NULL pointer to a CNetcfgCluster.");
  2018. TRACE_VERB("<-%!FUNC!");
  2019. continue;
  2020. }
  2021. /* Obviously, don't check against myself. */
  2022. if (pClusterMe == pCluster) continue;
  2023. /* If we find a match, report and error and do not allow the dialog to close. */
  2024. if (pCluster->CheckForDuplicateClusterIPAddress(adapterConfig->cl_ip_addr))
  2025. {
  2026. TRACE_INFO("%!FUNC! duplicate cluster IP address found.");
  2027. TRACE_VERB("<-%!FUNC!");
  2028. return S_FALSE;
  2029. }
  2030. }
  2031. TRACE_VERB("<-%!FUNC!");
  2032. return S_OK;
  2033. }
  2034. /*
  2035. * Function: CWlbsConfig::CheckForDuplicateBDATeamMasters
  2036. * Description: Loop through all adapters and check for conflicting BDA teaming master specifications.
  2037. * Author: shouse 1.29.02
  2038. */
  2039. STDMETHODIMP CWlbsConfig::CheckForDuplicateBDATeamMasters (GUID adapterGUID, NETCFG_WLBS_CONFIG * adapterConfig) {
  2040. TRACE_VERB("->%!FUNC!");
  2041. TraceMsg(L"CWlbsConfig::CheckForDuplicateBDATeamMasters");
  2042. CNetcfgCluster * pClusterMe = NULL;
  2043. ASSERT_VALID(this);
  2044. /* Get the cluster pointer for this adapter GUID. */
  2045. pClusterMe = GetCluster(adapterGUID);
  2046. ASSERT(pClusterMe);
  2047. if (!pClusterMe)
  2048. {
  2049. TRACE_INFO("%!FUNC! no cluster instance was found for the supplied adapter");
  2050. TRACE_VERB("<-%!FUNC!");
  2051. return S_OK;
  2052. }
  2053. /* If this adapter is not part of a BDA team, or if it is not the designated
  2054. master for its BDA team, then there is no reason to check this adapter for
  2055. conflicts with other adapters. */
  2056. if (!adapterConfig->bda_teaming.active || !adapterConfig->bda_teaming.master)
  2057. {
  2058. TRACE_INFO("%!FUNC! the adapter is not the master of a BDA team. No checking needed.");
  2059. TRACE_VERB("<-%!FUNC!");
  2060. return S_OK;
  2061. }
  2062. /* Loop through the rest of the list and check its BDA team settings against the
  2063. settings of all other adapters in our list. */
  2064. for (vector<CNetcfgCluster *>::iterator iter = m_vtrCluster.begin(); iter != m_vtrCluster.end(); iter++) {
  2065. CNetcfgCluster * pCluster = *iter;
  2066. ASSERT(pCluster);
  2067. if (!pCluster)
  2068. {
  2069. /* CLD: 05.17.01 is this a no op or do we store nulls in the vector? */
  2070. TRACE_INFO("%!FUNC! Found NULL pointer to a CNetcfgCluster.");
  2071. TRACE_VERB("<-%!FUNC!");
  2072. continue;
  2073. }
  2074. /* Obviously, don't check against myself. */
  2075. if (pClusterMe == pCluster) continue;
  2076. /* If we find a match, report and error and do not allow the dialog to close. */
  2077. if (pCluster->CheckForDuplicateBDATeamMaster(&adapterConfig->bda_teaming))
  2078. {
  2079. TRACE_INFO("%!FUNC! duplicate BDA team master assignment found.");
  2080. TRACE_VERB("<-%!FUNC!");
  2081. return S_FALSE;
  2082. }
  2083. }
  2084. TRACE_VERB("<-%!FUNC!");
  2085. return S_OK;
  2086. }
  2087. //+----------------------------------------------------------------------------
  2088. //
  2089. // Function: WlbsToNetcfgConfig
  2090. //
  2091. // Description:
  2092. //
  2093. // Arguments: const WLBS_REG_PARAMS* pWlbsConfig -
  2094. // NETCFG_WLBS_CONFIG* pNetcfgConfig -
  2095. //
  2096. // Returns: Nothing
  2097. //
  2098. // History: fengsun Created Header 2/14/00
  2099. //
  2100. //+----------------------------------------------------------------------------
  2101. void WlbsToNetcfgConfig(const WlbsApiFuncs* pWlbsApiFuncs, const WLBS_REG_PARAMS* pWlbsConfig, NETCFG_WLBS_CONFIG* pNetcfgConfig) {
  2102. TRACE_VERB("->%!FUNC!");
  2103. TraceMsg(L"WlbsToNetcfgConfig");
  2104. ASSERT(pNetcfgConfig != NULL);
  2105. ASSERT(pWlbsConfig != NULL);
  2106. ASSERT(pWlbsApiFuncs);
  2107. ASSERT(pWlbsApiFuncs->pfnWlbsEnumPortRules);
  2108. pNetcfgConfig->dwHostPriority = pWlbsConfig->host_priority;
  2109. pNetcfgConfig->fRctEnabled = (pWlbsConfig->rct_enabled != FALSE);
  2110. pNetcfgConfig->dwInitialState = pWlbsConfig->cluster_mode;
  2111. pNetcfgConfig->dwPersistedStates = pWlbsConfig->persisted_states;
  2112. pNetcfgConfig->fMcastSupport = (pWlbsConfig->mcast_support != FALSE);
  2113. pNetcfgConfig->fIGMPSupport = (pWlbsConfig->fIGMPSupport != FALSE);
  2114. pNetcfgConfig->fIpToMCastIp = (pWlbsConfig->fIpToMCastIp != FALSE);
  2115. pNetcfgConfig->fConvertMac = (pWlbsConfig->i_convert_mac != FALSE);
  2116. pNetcfgConfig->dwMaxHosts = pWlbsConfig->i_max_hosts;
  2117. pNetcfgConfig->dwMaxRules = pWlbsConfig->i_max_rules;
  2118. (VOID) StringCchCopy(pNetcfgConfig->szMCastIpAddress, ASIZECCH(pNetcfgConfig->szMCastIpAddress), pWlbsConfig->szMCastIpAddress);
  2119. (VOID) StringCchCopy(pNetcfgConfig->cl_mac_addr , ASIZECCH(pNetcfgConfig->cl_mac_addr) , pWlbsConfig->cl_mac_addr);
  2120. (VOID) StringCchCopy(pNetcfgConfig->cl_ip_addr , ASIZECCH(pNetcfgConfig->cl_ip_addr) , pWlbsConfig->cl_ip_addr);
  2121. (VOID) StringCchCopy(pNetcfgConfig->cl_net_mask , ASIZECCH(pNetcfgConfig->cl_net_mask) , pWlbsConfig->cl_net_mask);
  2122. (VOID) StringCchCopy(pNetcfgConfig->ded_ip_addr , ASIZECCH(pNetcfgConfig->ded_ip_addr) , pWlbsConfig->ded_ip_addr);
  2123. (VOID) StringCchCopy(pNetcfgConfig->ded_net_mask , ASIZECCH(pNetcfgConfig->ded_net_mask) , pWlbsConfig->ded_net_mask);
  2124. (VOID) StringCchCopy(pNetcfgConfig->domain_name , ASIZECCH(pNetcfgConfig->domain_name) , pWlbsConfig->domain_name);
  2125. pNetcfgConfig->fChangePassword =false;
  2126. pNetcfgConfig->szPassword[0] = L'\0';
  2127. ZeroMemory(pNetcfgConfig->port_rules, sizeof(pNetcfgConfig->port_rules));
  2128. WLBS_PORT_RULE PortRules[WLBS_MAX_RULES];
  2129. DWORD dwNumRules = WLBS_MAX_RULES;
  2130. if (pWlbsApiFuncs->pfnWlbsEnumPortRules((WLBS_REG_PARAMS*)pWlbsConfig, PortRules, &dwNumRules)!= WLBS_OK) {
  2131. DWORD dwStatus = GetLastError();
  2132. TraceError("CNetcfgCluster::GetConfig failed at WlbsEnumPortRules", dwStatus);
  2133. TRACE_CRIT("%!FUNC! api call to enumerate port rules failed with %d", dwStatus);
  2134. TRACE_VERB("<-%!FUNC!");
  2135. return;
  2136. }
  2137. ASSERT(dwNumRules <= WLBS_MAX_RULES);
  2138. pNetcfgConfig->dwNumRules = dwNumRules;
  2139. for (DWORD i=0; i<dwNumRules; i++) {
  2140. (VOID) StringCchCopy(pNetcfgConfig->port_rules[i].virtual_ip_addr, ASIZECCH(pNetcfgConfig->port_rules[i].virtual_ip_addr), PortRules[i].virtual_ip_addr);
  2141. pNetcfgConfig->port_rules[i].start_port = PortRules[i].start_port;
  2142. pNetcfgConfig->port_rules[i].end_port = PortRules[i].end_port;
  2143. pNetcfgConfig->port_rules[i].mode = PortRules[i].mode;
  2144. pNetcfgConfig->port_rules[i].protocol = PortRules[i].protocol;
  2145. if (pNetcfgConfig->port_rules[i].mode == WLBS_AFFINITY_SINGLE) {
  2146. pNetcfgConfig->port_rules[i].mode_data.single.priority =
  2147. PortRules[i].mode_data.single.priority;
  2148. } else {
  2149. pNetcfgConfig->port_rules[i].mode_data.multi.equal_load =
  2150. PortRules[i].mode_data.multi.equal_load;
  2151. pNetcfgConfig->port_rules[i].mode_data.multi.affinity =
  2152. PortRules[i].mode_data.multi.affinity;
  2153. pNetcfgConfig->port_rules[i].mode_data.multi.load =
  2154. PortRules[i].mode_data.multi.load;
  2155. }
  2156. }
  2157. /* Copy the BDA teaming settings. */
  2158. (VOID) StringCchCopy(pNetcfgConfig->bda_teaming.team_id, ASIZECCH(pNetcfgConfig->bda_teaming.team_id), pWlbsConfig->bda_teaming.team_id);
  2159. pNetcfgConfig->bda_teaming.active = pWlbsConfig->bda_teaming.active;
  2160. pNetcfgConfig->bda_teaming.master = pWlbsConfig->bda_teaming.master;
  2161. pNetcfgConfig->bda_teaming.reverse_hash = pWlbsConfig->bda_teaming.reverse_hash;
  2162. }
  2163. #if DBG
  2164. void TraceMsg(PCWSTR pszFormat, ...) {
  2165. static WCHAR szTempBufW[4096];
  2166. static CHAR szTempBufA[4096];
  2167. va_list arglist;
  2168. va_start(arglist, pszFormat);
  2169. (VOID) StringCchVPrintf(szTempBufW, ASIZECCH(szTempBufW), pszFormat, arglist);
  2170. /* Convert the WCHAR to CHAR. This is for backward compatability with TraceMsg
  2171. so that it was not necessary to change all pre-existing calls thereof. */
  2172. if(WideCharToMultiByte(CP_ACP, 0, szTempBufW, -1, szTempBufA, ASIZECCH(szTempBufA), NULL, NULL) != 0)
  2173. {
  2174. /* Traced messages are now sent through the netcfg TraceTag routine so that
  2175. they can be turned on/off dynamically. */
  2176. TraceTag(ttidWlbs, szTempBufA);
  2177. }
  2178. va_end(arglist);
  2179. }
  2180. #endif
  2181. #ifdef DEBUG
  2182. void CWlbsConfig::AssertValid() {
  2183. ASSERT(m_ServiceOperation >= WLBS_SERVICE_NONE && m_ServiceOperation <= WLBS_SERVICE_UPGRADE);
  2184. ASSERT(m_pNetCfg != NULL);
  2185. ASSERT(m_hdllWlbsCtrl != NULL);
  2186. ASSERT(m_pWlbsApiFuncs != NULL);
  2187. ASSERT (m_pWlbsApiFuncs->pfnParamReadReg != NULL);
  2188. ASSERT (m_pWlbsApiFuncs->pfnParamWriteReg != NULL);
  2189. ASSERT (m_pWlbsApiFuncs->pfnParamDeleteReg != NULL);
  2190. ASSERT (m_pWlbsApiFuncs->pfnParamSetDefaults != NULL);
  2191. ASSERT (m_pWlbsApiFuncs->pfnRegChangeNetworkAddress != NULL);
  2192. ASSERT (m_pWlbsApiFuncs->pfnNotifyAdapterAddressChangeEx != NULL);
  2193. ASSERT (m_pWlbsApiFuncs->pfnWlbsAddPortRule != NULL);
  2194. ASSERT (m_pWlbsApiFuncs->pfnWlbsSetRemotePassword != NULL);
  2195. ASSERT (m_pWlbsApiFuncs->pfnWlbsEnumPortRules != NULL);
  2196. ASSERT (m_pWlbsApiFuncs->pfnNotifyDriverConfigChanges != NULL);
  2197. ASSERT(m_vtrCluster.size()<=128);
  2198. }
  2199. #endif
  2200. //+----------------------------------------------------------------------------
  2201. //
  2202. // Function: ParamReadAnswerFile
  2203. //
  2204. // Description:
  2205. //
  2206. // Arguments: CWSTR answer_file -
  2207. // PCWSTR answer_sections -
  2208. // WLBS_REG_PARAMS* paramp -
  2209. //
  2210. // Returns: HRESULT -
  2211. //
  2212. // The minimal parameters that must be specified are cluster IP address,
  2213. // cluster network mask and host priority. All others are considered optional.
  2214. // Though the appearance of an optional parameter may make another optional
  2215. // parameter mandatory (e.g. setting IPToMACEnable to false but not providing
  2216. // a cluster MAC address), that is ignored for now.
  2217. //
  2218. // History: fengsun Created Header 3/2/00
  2219. // chrisdar 07.13.01 Added tracing and logging to setuperr.log for certain
  2220. // failures.
  2221. //
  2222. //+----------------------------------------------------------------------------
  2223. HRESULT ParamReadAnswerFile(CSetupInfFile& caf, PCWSTR answer_sections, WLBS_REG_PARAMS* paramp) {
  2224. TRACE_VERB("->%!FUNC!");
  2225. TraceMsg(L"ParamReadAnswerFile");
  2226. HRESULT hr = S_OK;
  2227. tstring str;
  2228. DWORD dword;
  2229. ULONG code;
  2230. INFCONTEXT ctx;
  2231. PWCHAR port_str;
  2232. ULONG ulDestLen;
  2233. ULONG ulSourceLen;
  2234. hr = caf.HrGetDword(answer_sections, CVY_NAME_VERSION, & dword);
  2235. if (SUCCEEDED(hr))
  2236. {
  2237. paramp -> i_parms_ver = dword;
  2238. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_VERSION, paramp -> i_parms_ver);
  2239. TraceMsg(L"#### ParamReadAnswerFile read %ls %d", CVY_NAME_VERSION, paramp -> i_parms_ver);
  2240. }
  2241. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2242. {
  2243. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_VERSION);
  2244. }
  2245. else
  2246. {
  2247. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_VERSION, hr);
  2248. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_VERSION, paramp -> i_parms_ver);
  2249. }
  2250. // Host priority is a mandatory parameter
  2251. hr = caf.HrGetDword(answer_sections, CVY_NAME_HOST_PRIORITY, & dword);
  2252. if (SUCCEEDED(hr)) {
  2253. paramp -> host_priority = dword;
  2254. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_HOST_PRIORITY, paramp -> host_priority);
  2255. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_HOST_PRIORITY, paramp -> host_priority);
  2256. }
  2257. else
  2258. {
  2259. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_HOST_PRIORITY, hr);
  2260. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_HOST_PRIORITY, paramp -> host_priority);
  2261. }
  2262. hr = caf.HrGetDword(answer_sections, CVY_NAME_CLUSTER_MODE, & dword);
  2263. if (SUCCEEDED(hr)) {
  2264. paramp -> cluster_mode = dword;
  2265. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_CLUSTER_MODE, paramp -> cluster_mode);
  2266. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_CLUSTER_MODE, paramp -> cluster_mode);
  2267. }
  2268. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2269. {
  2270. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_CLUSTER_MODE);
  2271. }
  2272. else
  2273. {
  2274. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_CLUSTER_MODE, hr);
  2275. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_CLUSTER_MODE, paramp -> cluster_mode);
  2276. }
  2277. hr = caf.HrGetDword(answer_sections, CVY_NAME_PERSISTED_STATES, & dword);
  2278. if (SUCCEEDED(hr)) {
  2279. paramp -> persisted_states = dword;
  2280. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_PERSISTED_STATES, paramp -> persisted_states);
  2281. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_PERSISTED_STATES, paramp -> persisted_states);
  2282. }
  2283. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2284. {
  2285. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_PERSISTED_STATES);
  2286. }
  2287. else
  2288. {
  2289. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_PERSISTED_STATES, hr);
  2290. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_PERSISTED_STATES, paramp -> persisted_states);
  2291. }
  2292. hr = caf.HrGetString(answer_sections, CVY_NAME_NETWORK_ADDR, & str);
  2293. if (SUCCEEDED(hr)) {
  2294. ulDestLen = (sizeof (paramp -> cl_mac_addr) / sizeof (WCHAR)) - 1;
  2295. ulSourceLen = wcslen(str.c_str());
  2296. wcsncpy(paramp -> cl_mac_addr, str.c_str(), ulSourceLen > ulDestLen ? ulDestLen : ulSourceLen + 1);
  2297. // Terminate the end of the destination with a NULL, even in the case that we don't need to. It's simpler than checking if we need to.
  2298. paramp -> cl_mac_addr[ulDestLen] = L'\0';
  2299. TRACE_VERB("%!FUNC! read %ls %ls", CVY_NAME_NETWORK_ADDR, paramp -> cl_mac_addr);
  2300. TraceMsg(L"#### ParamReadAnswerFile read %ls %ls\n", CVY_NAME_NETWORK_ADDR, paramp -> cl_mac_addr);
  2301. }
  2302. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2303. {
  2304. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_NETWORK_ADDR);
  2305. }
  2306. else
  2307. {
  2308. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_NETWORK_ADDR, hr);
  2309. if (NULL != str.c_str())
  2310. {
  2311. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %ls", CVY_NAME_NETWORK_ADDR, str.c_str());
  2312. } else {
  2313. TRACE_CRIT("%!FUNC! failed reading %ls. String was not retrieved", CVY_NAME_NETWORK_ADDR);
  2314. }
  2315. }
  2316. // Cluster IP address is a mandatory parameter
  2317. hr = caf.HrGetString(answer_sections, CVY_NAME_CL_IP_ADDR, & str);
  2318. if (SUCCEEDED(hr)) {
  2319. ulDestLen = (sizeof (paramp -> cl_ip_addr) / sizeof (WCHAR)) - 1;
  2320. ulSourceLen = wcslen(str.c_str());
  2321. wcsncpy(paramp -> cl_ip_addr, str.c_str(), ulSourceLen > ulDestLen ? ulDestLen : ulSourceLen + 1);
  2322. // Terminate the end of the destination with a NULL, even in the case that we don't need to. It's simpler than checking if we need to.
  2323. paramp -> cl_ip_addr[ulDestLen] = L'\0';
  2324. TRACE_VERB("%!FUNC! read %ls %ls", CVY_NAME_CL_IP_ADDR, paramp -> cl_ip_addr);
  2325. TraceMsg(L"#### ParamReadAnswerFile read %ls %ls\n", CVY_NAME_CL_IP_ADDR, paramp -> cl_ip_addr);
  2326. }
  2327. else
  2328. {
  2329. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_CL_IP_ADDR, hr);
  2330. TRACE_CRIT("%!FUNC! failed reading %ls.", CVY_NAME_CL_IP_ADDR);
  2331. }
  2332. // Cluster network mask is a mandatory parameter
  2333. hr = caf.HrGetString(answer_sections, CVY_NAME_CL_NET_MASK, & str);
  2334. if (SUCCEEDED(hr)) {
  2335. ulDestLen = (sizeof (paramp -> cl_net_mask) / sizeof (WCHAR)) - 1;
  2336. ulSourceLen = wcslen(str.c_str());
  2337. wcsncpy(paramp -> cl_net_mask, str.c_str(), ulSourceLen > ulDestLen ? ulDestLen : ulSourceLen + 1);
  2338. // Terminate the end of the destination with a NULL, even in the case that we don't need to. It's simpler than checking if we need to.
  2339. paramp -> cl_net_mask[ulDestLen] = L'\0';
  2340. TRACE_VERB("%!FUNC! read %ls %ls", CVY_NAME_CL_NET_MASK, paramp -> cl_net_mask);
  2341. TraceMsg(L"#### ParamReadAnswerFile read %ls %ls\n", CVY_NAME_CL_NET_MASK, paramp -> cl_net_mask);
  2342. }
  2343. else
  2344. {
  2345. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_CL_NET_MASK, hr);
  2346. TRACE_CRIT("%!FUNC! failed reading %ls.", CVY_NAME_CL_NET_MASK);
  2347. }
  2348. hr = caf.HrGetString(answer_sections, CVY_NAME_DED_IP_ADDR, & str);
  2349. if (SUCCEEDED(hr)) {
  2350. ulDestLen = (sizeof (paramp -> ded_ip_addr) / sizeof (WCHAR)) - 1;
  2351. ulSourceLen = wcslen(str.c_str());
  2352. wcsncpy(paramp -> ded_ip_addr, str.c_str(), ulSourceLen > ulDestLen ? ulDestLen : ulSourceLen + 1);
  2353. // Terminate the end of the destination with a NULL, even in the case that we don't need to. It's simpler than checking if we need to.
  2354. paramp -> ded_ip_addr[ulDestLen] = L'\0';
  2355. TRACE_VERB("%!FUNC! read %ls %ls", CVY_NAME_DED_IP_ADDR, paramp -> ded_ip_addr);
  2356. TraceMsg(L"#### ParamReadAnswerFile read %ls %ls\n", CVY_NAME_DED_IP_ADDR, paramp -> ded_ip_addr);
  2357. }
  2358. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2359. {
  2360. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_DED_IP_ADDR);
  2361. }
  2362. else
  2363. {
  2364. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_DED_IP_ADDR, hr);
  2365. TRACE_CRIT("%!FUNC! failed reading %ls", CVY_NAME_DED_IP_ADDR);
  2366. }
  2367. hr = caf.HrGetString(answer_sections, CVY_NAME_DED_NET_MASK, & str);
  2368. if (SUCCEEDED(hr)) {
  2369. ulDestLen = (sizeof (paramp -> ded_net_mask) / sizeof (WCHAR)) - 1;
  2370. ulSourceLen = wcslen(str.c_str());
  2371. wcsncpy(paramp -> ded_net_mask, str.c_str(), ulSourceLen > ulDestLen ? ulDestLen : ulSourceLen + 1);
  2372. // Terminate the end of the destination with a NULL, even in the case that we don't need to. It's simpler than checking if we need to.
  2373. paramp -> ded_net_mask[ulDestLen] = L'\0';
  2374. TRACE_VERB("%!FUNC! read %ls %ls", CVY_NAME_DED_NET_MASK, paramp -> ded_net_mask);
  2375. TraceMsg(L"#### ParamReadAnswerFile read %ls %ls\n", CVY_NAME_DED_NET_MASK, paramp -> ded_net_mask);
  2376. }
  2377. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2378. {
  2379. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_DED_NET_MASK);
  2380. }
  2381. else
  2382. {
  2383. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_DED_NET_MASK, hr);
  2384. TRACE_CRIT("%!FUNC! failed reading %ls.", CVY_NAME_DED_NET_MASK);
  2385. }
  2386. hr = caf.HrGetString(answer_sections, CVY_NAME_DOMAIN_NAME, & str);
  2387. if (SUCCEEDED(hr)) {
  2388. ulDestLen = (sizeof (paramp -> domain_name) / sizeof (WCHAR)) - 1;
  2389. ulSourceLen = wcslen(str.c_str());
  2390. wcsncpy(paramp -> domain_name, str.c_str(), ulSourceLen > ulDestLen ? ulDestLen : ulSourceLen + 1);
  2391. // Terminate the end of the destination with a NULL, even in the case that we don't need to. It's simpler than checking if we need to.
  2392. paramp -> domain_name[ulDestLen] = L'\0';
  2393. TRACE_VERB("%!FUNC! read %ls %ls", CVY_NAME_DOMAIN_NAME, paramp -> domain_name);
  2394. TraceMsg(L"#### ParamReadAnswerFile read %ls %ls\n", CVY_NAME_DOMAIN_NAME, paramp -> domain_name);
  2395. }
  2396. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2397. {
  2398. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_DOMAIN_NAME);
  2399. }
  2400. else
  2401. {
  2402. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_DOMAIN_NAME, hr);
  2403. TRACE_CRIT("%!FUNC! failed reading %ls.", CVY_NAME_DOMAIN_NAME);
  2404. }
  2405. hr = caf.HrGetDword(answer_sections, CVY_NAME_ALIVE_PERIOD, & dword);
  2406. if (SUCCEEDED(hr)) {
  2407. paramp -> alive_period = dword;
  2408. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_ALIVE_PERIOD, paramp -> alive_period);
  2409. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_ALIVE_PERIOD, paramp -> alive_period);
  2410. }
  2411. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2412. {
  2413. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_ALIVE_PERIOD);
  2414. }
  2415. else
  2416. {
  2417. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_ALIVE_PERIOD, hr);
  2418. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_ALIVE_PERIOD, paramp -> alive_period);
  2419. }
  2420. hr = caf.HrGetDword(answer_sections, CVY_NAME_ALIVE_TOLER, & dword);
  2421. if (SUCCEEDED(hr)) {
  2422. paramp -> alive_tolerance = dword;
  2423. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_ALIVE_TOLER, paramp -> alive_tolerance);
  2424. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_ALIVE_TOLER, paramp -> alive_tolerance);
  2425. }
  2426. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2427. {
  2428. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_ALIVE_TOLER);
  2429. }
  2430. else
  2431. {
  2432. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_ALIVE_TOLER, hr);
  2433. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_ALIVE_TOLER, paramp -> alive_tolerance);
  2434. }
  2435. hr = caf.HrGetDword(answer_sections, CVY_NAME_NUM_ACTIONS, & dword);
  2436. if (SUCCEEDED(hr)) {
  2437. paramp -> num_actions = dword;
  2438. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_NUM_ACTIONS, paramp -> num_actions);
  2439. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_NUM_ACTIONS, paramp -> num_actions);
  2440. }
  2441. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2442. {
  2443. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_NUM_ACTIONS);
  2444. }
  2445. else
  2446. {
  2447. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_NUM_ACTIONS, hr);
  2448. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_NUM_ACTIONS, paramp -> num_actions);
  2449. }
  2450. hr = caf.HrGetDword(answer_sections, CVY_NAME_NUM_PACKETS, & dword);
  2451. if (SUCCEEDED(hr)) {
  2452. paramp -> num_packets = dword;
  2453. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_NUM_PACKETS, paramp -> num_packets);
  2454. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_NUM_PACKETS, paramp -> num_packets);
  2455. }
  2456. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2457. {
  2458. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_NUM_PACKETS);
  2459. }
  2460. else
  2461. {
  2462. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_NUM_PACKETS, hr);
  2463. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_NUM_PACKETS, paramp -> num_packets);
  2464. }
  2465. hr = caf.HrGetDword(answer_sections, CVY_NAME_NUM_SEND_MSGS, & dword);
  2466. if (SUCCEEDED(hr)) {
  2467. paramp -> num_send_msgs = dword;
  2468. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_NUM_SEND_MSGS, paramp -> num_send_msgs);
  2469. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_NUM_SEND_MSGS, paramp -> num_send_msgs);
  2470. }
  2471. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2472. {
  2473. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_NUM_SEND_MSGS);
  2474. }
  2475. else
  2476. {
  2477. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_NUM_SEND_MSGS, hr);
  2478. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_NUM_SEND_MSGS, paramp -> num_send_msgs);
  2479. }
  2480. hr = caf.HrGetDword(answer_sections, CVY_NAME_DSCR_PER_ALLOC, & dword);
  2481. if (SUCCEEDED(hr)) {
  2482. paramp -> dscr_per_alloc = dword;
  2483. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_DSCR_PER_ALLOC, paramp -> dscr_per_alloc);
  2484. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_DSCR_PER_ALLOC, paramp -> dscr_per_alloc);
  2485. }
  2486. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2487. {
  2488. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_DSCR_PER_ALLOC);
  2489. }
  2490. else
  2491. {
  2492. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_DSCR_PER_ALLOC, hr);
  2493. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_DSCR_PER_ALLOC, paramp -> dscr_per_alloc);
  2494. }
  2495. hr = caf.HrGetDword(answer_sections, CVY_NAME_TCP_TIMEOUT, & dword);
  2496. if (SUCCEEDED(hr)) {
  2497. paramp -> tcp_dscr_timeout = dword;
  2498. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_TCP_TIMEOUT, paramp -> tcp_dscr_timeout);
  2499. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_TCP_TIMEOUT, paramp -> tcp_dscr_timeout);
  2500. }
  2501. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2502. {
  2503. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_TCP_TIMEOUT);
  2504. }
  2505. else
  2506. {
  2507. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_TCP_TIMEOUT, hr);
  2508. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_TCP_TIMEOUT, paramp -> tcp_dscr_timeout);
  2509. }
  2510. hr = caf.HrGetDword(answer_sections, CVY_NAME_IPSEC_TIMEOUT, & dword);
  2511. if (SUCCEEDED(hr)) {
  2512. paramp -> ipsec_dscr_timeout = dword;
  2513. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_IPSEC_TIMEOUT, paramp -> ipsec_dscr_timeout);
  2514. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_IPSEC_TIMEOUT, paramp -> ipsec_dscr_timeout);
  2515. }
  2516. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2517. {
  2518. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_IPSEC_TIMEOUT);
  2519. }
  2520. else
  2521. {
  2522. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_IPSEC_TIMEOUT, hr);
  2523. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_IPSEC_TIMEOUT, paramp -> ipsec_dscr_timeout);
  2524. }
  2525. hr = caf.HrGetDword(answer_sections, CVY_NAME_FILTER_ICMP, & dword);
  2526. if (SUCCEEDED(hr)) {
  2527. paramp -> filter_icmp = dword;
  2528. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_FILTER_ICMP, paramp -> filter_icmp);
  2529. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_FILTER_ICMP, paramp -> filter_icmp);
  2530. }
  2531. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2532. {
  2533. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_FILTER_ICMP);
  2534. }
  2535. else
  2536. {
  2537. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_FILTER_ICMP, hr);
  2538. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_FILTER_ICMP, paramp -> filter_icmp);
  2539. }
  2540. hr = caf.HrGetDword(answer_sections, CVY_NAME_MAX_DSCR_ALLOCS, & dword);
  2541. if (SUCCEEDED(hr)) {
  2542. paramp -> max_dscr_allocs = dword;
  2543. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_MAX_DSCR_ALLOCS, paramp -> max_dscr_allocs);
  2544. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_MAX_DSCR_ALLOCS, paramp -> max_dscr_allocs);
  2545. }
  2546. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2547. {
  2548. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_MAX_DSCR_ALLOCS);
  2549. }
  2550. else
  2551. {
  2552. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_MAX_DSCR_ALLOCS, hr);
  2553. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_MAX_DSCR_ALLOCS, paramp -> max_dscr_allocs);
  2554. }
  2555. hr = caf.HrGetDword(answer_sections, CVY_NAME_SCALE_CLIENT, & dword);
  2556. if (SUCCEEDED(hr)) {
  2557. paramp -> i_scale_client = dword;
  2558. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_SCALE_CLIENT, paramp -> i_scale_client);
  2559. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_SCALE_CLIENT, paramp -> i_scale_client);
  2560. }
  2561. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2562. {
  2563. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_SCALE_CLIENT);
  2564. }
  2565. else
  2566. {
  2567. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_SCALE_CLIENT, hr);
  2568. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_SCALE_CLIENT, paramp -> i_scale_client);
  2569. }
  2570. hr = caf.HrGetDword(answer_sections, CVY_NAME_CLEANUP_DELAY, & dword);
  2571. if (SUCCEEDED(hr)) {
  2572. paramp -> i_cleanup_delay = dword;
  2573. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_CLEANUP_DELAY, paramp -> i_cleanup_delay);
  2574. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_CLEANUP_DELAY, paramp -> i_cleanup_delay);
  2575. }
  2576. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2577. {
  2578. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_CLEANUP_DELAY);
  2579. }
  2580. else
  2581. {
  2582. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_CLEANUP_DELAY, hr);
  2583. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_CLEANUP_DELAY, paramp -> i_cleanup_delay);
  2584. }
  2585. hr = caf.HrGetDword(answer_sections, CVY_NAME_NBT_SUPPORT, & dword);
  2586. if (SUCCEEDED(hr)) {
  2587. paramp -> i_nbt_support = dword;
  2588. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_NBT_SUPPORT, paramp -> i_nbt_support);
  2589. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_NBT_SUPPORT, paramp -> i_nbt_support);
  2590. }
  2591. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2592. {
  2593. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_NBT_SUPPORT);
  2594. }
  2595. else
  2596. {
  2597. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_NBT_SUPPORT, hr);
  2598. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_NBT_SUPPORT, paramp -> i_nbt_support);
  2599. }
  2600. hr = caf.HrGetDword(answer_sections, CVY_NAME_MCAST_SUPPORT, & dword);
  2601. if (SUCCEEDED(hr)) {
  2602. paramp -> mcast_support = dword;
  2603. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_MCAST_SUPPORT, paramp -> mcast_support);
  2604. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_MCAST_SUPPORT, paramp -> mcast_support);
  2605. }
  2606. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2607. {
  2608. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_MCAST_SUPPORT);
  2609. }
  2610. else
  2611. {
  2612. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_MCAST_SUPPORT, hr);
  2613. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_MCAST_SUPPORT, paramp -> mcast_support);
  2614. }
  2615. hr = caf.HrGetDword(answer_sections, CVY_NAME_MCAST_SPOOF, & dword);
  2616. if (SUCCEEDED(hr)) {
  2617. paramp -> i_mcast_spoof = dword;
  2618. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_MCAST_SPOOF, paramp -> i_mcast_spoof);
  2619. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_MCAST_SPOOF, paramp -> i_mcast_spoof);
  2620. }
  2621. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2622. {
  2623. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_MCAST_SPOOF);
  2624. }
  2625. else
  2626. {
  2627. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_MCAST_SPOOF, hr);
  2628. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_MCAST_SPOOF, paramp -> i_mcast_spoof);
  2629. }
  2630. hr = caf.HrGetDword(answer_sections, CVY_NAME_MASK_SRC_MAC, & dword);
  2631. if (SUCCEEDED(hr)) {
  2632. paramp -> mask_src_mac = dword;
  2633. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_MASK_SRC_MAC, paramp -> mask_src_mac);
  2634. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_MASK_SRC_MAC, paramp -> mask_src_mac);
  2635. }
  2636. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2637. {
  2638. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_MASK_SRC_MAC);
  2639. }
  2640. else
  2641. {
  2642. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_MASK_SRC_MAC, hr);
  2643. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_MASK_SRC_MAC, paramp -> mask_src_mac);
  2644. }
  2645. hr = caf.HrGetDword(answer_sections, CVY_NAME_NETMON_ALIVE, & dword);
  2646. if (SUCCEEDED(hr)) {
  2647. paramp -> i_netmon_alive = dword;
  2648. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_NETMON_ALIVE, paramp -> i_netmon_alive);
  2649. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_NETMON_ALIVE, paramp -> i_netmon_alive);
  2650. }
  2651. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2652. {
  2653. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_NETMON_ALIVE);
  2654. }
  2655. else
  2656. {
  2657. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_NETMON_ALIVE, hr);
  2658. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_NETMON_ALIVE, paramp -> i_netmon_alive);
  2659. }
  2660. hr = caf.HrGetDword(answer_sections, CVY_NAME_IP_CHG_DELAY, & dword);
  2661. if (SUCCEEDED(hr)) {
  2662. paramp -> i_ip_chg_delay = dword;
  2663. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_IP_CHG_DELAY, paramp -> i_ip_chg_delay);
  2664. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_IP_CHG_DELAY, paramp -> i_ip_chg_delay);
  2665. }
  2666. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2667. {
  2668. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_IP_CHG_DELAY);
  2669. }
  2670. else
  2671. {
  2672. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_IP_CHG_DELAY, hr);
  2673. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_IP_CHG_DELAY, paramp -> i_ip_chg_delay);
  2674. }
  2675. hr = caf.HrGetDword(answer_sections, CVY_NAME_CONVERT_MAC, & dword);
  2676. if (SUCCEEDED(hr)) {
  2677. paramp -> i_convert_mac = dword;
  2678. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_CONVERT_MAC, paramp -> i_convert_mac);
  2679. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_CONVERT_MAC, paramp -> i_convert_mac);
  2680. }
  2681. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2682. {
  2683. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_CONVERT_MAC);
  2684. }
  2685. else
  2686. {
  2687. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_CONVERT_MAC, hr);
  2688. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_CONVERT_MAC, paramp -> i_convert_mac);
  2689. }
  2690. hr = caf.HrGetString(answer_sections, CVY_NAME_LICENSE_KEY, & str);
  2691. if (SUCCEEDED(hr)) {
  2692. ulDestLen = (sizeof (paramp -> i_license_key) / sizeof (WCHAR)) - 1;
  2693. ulSourceLen = wcslen(str.c_str());
  2694. wcsncpy(paramp -> i_license_key, str.c_str(), ulSourceLen > ulDestLen ? ulDestLen : ulSourceLen + 1);
  2695. // Terminate the end of the destination with a NULL, even in the case that we don't need to. It's simpler than checking if we need to.
  2696. paramp -> i_license_key[ulDestLen] = L'\0';
  2697. TRACE_VERB("%!FUNC! read %ls %ls", CVY_NAME_LICENSE_KEY, paramp -> i_license_key);
  2698. TraceMsg(L"#### ParamReadAnswerFile read %ls %ls\n", CVY_NAME_LICENSE_KEY, paramp -> i_license_key);
  2699. }
  2700. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2701. {
  2702. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_LICENSE_KEY);
  2703. }
  2704. else
  2705. {
  2706. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_LICENSE_KEY, hr);
  2707. TRACE_CRIT("%!FUNC! failed reading %ls.", CVY_NAME_LICENSE_KEY);
  2708. }
  2709. hr = caf.HrGetDword(answer_sections, CVY_NAME_RMT_PASSWORD, & dword);
  2710. if (SUCCEEDED(hr)) {
  2711. paramp -> i_rmt_password = dword;
  2712. TRACE_VERB("%!FUNC! read %ls %x", CVY_NAME_RMT_PASSWORD, paramp -> i_rmt_password);
  2713. TraceMsg(L"#### ParamReadAnswerFile read %ls %x\n", CVY_NAME_RMT_PASSWORD, paramp -> i_rmt_password);
  2714. }
  2715. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2716. {
  2717. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_RMT_PASSWORD);
  2718. }
  2719. else
  2720. {
  2721. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_RMT_PASSWORD, hr);
  2722. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %x", CVY_NAME_RMT_PASSWORD, paramp -> i_rmt_password);
  2723. }
  2724. hr = caf.HrGetDword(answer_sections, CVY_NAME_RCT_PASSWORD, & dword);
  2725. if (SUCCEEDED(hr)) {
  2726. paramp -> i_rct_password = dword;
  2727. TRACE_VERB("%!FUNC! read %ls %x", CVY_NAME_RCT_PASSWORD, paramp -> i_rct_password);
  2728. TraceMsg(L"#### ParamReadAnswerFile read %ls %x\n", CVY_NAME_RCT_PASSWORD, paramp -> i_rct_password);
  2729. }
  2730. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2731. {
  2732. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_RCT_PASSWORD);
  2733. }
  2734. else
  2735. {
  2736. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_RCT_PASSWORD, hr);
  2737. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %x", CVY_NAME_RCT_PASSWORD, paramp -> i_rct_password);
  2738. }
  2739. hr = caf.HrGetDword(answer_sections, CVY_NAME_RCT_PORT, & dword);
  2740. if (SUCCEEDED(hr)) {
  2741. paramp -> rct_port = dword;
  2742. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_RCT_PORT, paramp -> rct_port);
  2743. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_RCT_PORT, paramp -> rct_port);
  2744. }
  2745. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2746. {
  2747. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_RCT_PORT);
  2748. }
  2749. else
  2750. {
  2751. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_RCT_PORT, hr);
  2752. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_RCT_PORT, paramp -> rct_port);
  2753. }
  2754. hr = caf.HrGetDword(answer_sections, CVY_NAME_RCT_ENABLED, & dword);
  2755. if (SUCCEEDED(hr)) {
  2756. paramp -> rct_enabled = dword;
  2757. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_RCT_ENABLED, paramp -> rct_enabled);
  2758. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_RCT_ENABLED, paramp -> rct_enabled);
  2759. }
  2760. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2761. {
  2762. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_RCT_ENABLED);
  2763. }
  2764. else
  2765. {
  2766. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_RCT_ENABLED, hr);
  2767. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_RCT_ENABLED, paramp -> rct_enabled);
  2768. }
  2769. hr = caf.HrGetString(answer_sections, CVY_NAME_PASSWORD, & str);
  2770. if (SUCCEEDED(hr)) {
  2771. WCHAR passw [LICENSE_STR_IMPORTANT_CHARS + 1];
  2772. ulDestLen = (sizeof (passw) / sizeof (WCHAR)) - 1;
  2773. ulSourceLen = wcslen(str.c_str());
  2774. wcsncpy(passw, str.c_str(), ulSourceLen > ulDestLen ? ulDestLen : ulSourceLen + 1);
  2775. // Terminate the end of the destination with a NULL, even in the case that we don't need to. It's simpler than checking if we need to.
  2776. passw[ulDestLen] = L'\0';
  2777. paramp -> i_rct_password = License_wstring_encode (passw);
  2778. TRACE_VERB("%!FUNC! read %ls %ls %x", CVY_NAME_PASSWORD, passw, paramp -> i_rct_password);
  2779. TraceMsg(TEXT("#### ParamReadAnswerFile read %ls %ls %x\n"), CVY_NAME_PASSWORD, passw, paramp -> i_rct_password);
  2780. }
  2781. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2782. {
  2783. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_PASSWORD);
  2784. }
  2785. else
  2786. {
  2787. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_PASSWORD, hr);
  2788. TRACE_CRIT("%!FUNC! failed reading %ls.", CVY_NAME_PASSWORD);
  2789. }
  2790. hr = caf.HrGetDword(answer_sections, CVY_NAME_ID_HB_PERIOD, & dword);
  2791. if (SUCCEEDED(hr)) {
  2792. paramp -> identity_period = dword;
  2793. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_ID_HB_PERIOD, paramp -> identity_period);
  2794. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_ID_HB_PERIOD, paramp -> identity_period);
  2795. }
  2796. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2797. {
  2798. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_ID_HB_PERIOD);
  2799. }
  2800. else
  2801. {
  2802. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_ID_HB_PERIOD, hr);
  2803. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_ID_HB_PERIOD, paramp -> identity_period);
  2804. }
  2805. hr = caf.HrGetDword(answer_sections, CVY_NAME_ID_HB_ENABLED, & dword);
  2806. if (SUCCEEDED(hr)) {
  2807. paramp -> identity_enabled = dword;
  2808. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_ID_HB_ENABLED, paramp -> identity_enabled);
  2809. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_ID_HB_ENABLED, paramp -> identity_enabled);
  2810. }
  2811. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2812. {
  2813. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_ID_HB_ENABLED);
  2814. }
  2815. else
  2816. {
  2817. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_ID_HB_ENABLED, hr);
  2818. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_ID_HB_ENABLED, paramp -> identity_enabled);
  2819. }
  2820. /* IGMP support. */
  2821. hr = caf.HrGetDword(answer_sections, CVY_NAME_IGMP_SUPPORT, &dword);
  2822. if (SUCCEEDED(hr)) {
  2823. // Since we read a DWORD and want a BOOL be paranoid. Assume FALSE is a fixed integer value (should be 0). Anything else will be TRUE.
  2824. paramp->fIGMPSupport = TRUE;
  2825. if (FALSE == dword) paramp->fIGMPSupport = FALSE;
  2826. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_IGMP_SUPPORT, paramp->fIGMPSupport);
  2827. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_IGMP_SUPPORT, paramp->fIGMPSupport);
  2828. }
  2829. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2830. {
  2831. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_IGMP_SUPPORT);
  2832. }
  2833. else
  2834. {
  2835. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_IGMP_SUPPORT, hr);
  2836. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_IGMP_SUPPORT, paramp->fIGMPSupport);
  2837. }
  2838. hr = caf.HrGetDword(answer_sections, CVY_NAME_IP_TO_MCASTIP, &dword);
  2839. if (SUCCEEDED(hr)) {
  2840. // Since we read a DWORD and want a BOOL be paranoid. Assume FALSE is a fixed integer value (should be 0). Anything else will be TRUE.
  2841. paramp->fIpToMCastIp = TRUE;
  2842. if (FALSE == dword) paramp->fIpToMCastIp = FALSE;
  2843. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_IP_TO_MCASTIP, paramp->fIpToMCastIp);
  2844. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_IP_TO_MCASTIP, paramp->fIpToMCastIp);
  2845. }
  2846. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2847. {
  2848. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_IP_TO_MCASTIP);
  2849. }
  2850. else
  2851. {
  2852. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_IP_TO_MCASTIP, hr);
  2853. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_IP_TO_MCASTIP, paramp->fIpToMCastIp);
  2854. }
  2855. hr = caf.HrGetString(answer_sections, CVY_NAME_MCAST_IP_ADDR, &str);
  2856. if (SUCCEEDED(hr)) {
  2857. ulDestLen = (sizeof (paramp -> szMCastIpAddress) / sizeof (WCHAR)) - 1;
  2858. ulSourceLen = wcslen(str.c_str());
  2859. wcsncpy(paramp -> szMCastIpAddress, str.c_str(), ulSourceLen > ulDestLen ? ulDestLen : ulSourceLen + 1);
  2860. // Terminate the end of the destination with a NULL, even in the case that we don't need to. It's simpler than checking if we need to.
  2861. paramp -> szMCastIpAddress[ulDestLen] = L'\0';
  2862. TRACE_VERB("%!FUNC! read %ls %ls", CVY_NAME_MCAST_IP_ADDR, paramp->szMCastIpAddress);
  2863. TraceMsg(L"#### ParamReadAnswerFile read %ls %ls\n", CVY_NAME_MCAST_IP_ADDR, paramp->szMCastIpAddress);
  2864. }
  2865. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2866. {
  2867. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_MCAST_IP_ADDR);
  2868. }
  2869. else
  2870. {
  2871. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_MCAST_IP_ADDR, hr);
  2872. TRACE_CRIT("%!FUNC! failed reading %ls.", CVY_NAME_MCAST_IP_ADDR);
  2873. }
  2874. /* End IGMP support. */
  2875. /* BDA support */
  2876. // Read the team id, which must be a GUID with "{}" included
  2877. hr = caf.HrGetString(answer_sections, CVY_NAME_BDA_TEAM_ID, &str);
  2878. if (SUCCEEDED(hr)) {
  2879. ulDestLen = (sizeof (paramp -> bda_teaming . team_id) / sizeof (WCHAR)) - 1;
  2880. ulSourceLen = wcslen(str.c_str());
  2881. wcsncpy(paramp -> bda_teaming . team_id, str.c_str(), ulSourceLen > ulDestLen ? ulDestLen : ulSourceLen + 1);
  2882. // Terminate the end of the destination with a NULL, even in the case that we don't need to. It's simpler than checking if we need to.
  2883. paramp -> bda_teaming . team_id [ulDestLen] = L'\0';
  2884. //
  2885. // Since we read a team id, we assume that the user intends to run BDA, even though it may turn out that the
  2886. // supplied id may not be a valid one. Set the active flag so that WriteRegParams knows we are gonna be teamed
  2887. //
  2888. paramp->bda_teaming.active = TRUE;
  2889. TRACE_VERB("%!FUNC! read %ls %ls", CVY_NAME_BDA_TEAM_ID, paramp->bda_teaming.team_id);
  2890. TraceMsg(L"#### ParamReadAnswerFile read %ls %ls\n", CVY_NAME_BDA_TEAM_ID, paramp->bda_teaming.team_id);
  2891. }
  2892. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2893. {
  2894. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_BDA_TEAM_ID);
  2895. }
  2896. else
  2897. {
  2898. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_BDA_TEAM_ID, hr);
  2899. TRACE_CRIT("%!FUNC! failed reading %ls.", CVY_NAME_BDA_TEAM_ID);
  2900. }
  2901. // Read the BDA "master" property
  2902. hr = caf.HrGetDword(answer_sections, CVY_NAME_BDA_MASTER, &dword);
  2903. if (SUCCEEDED(hr)) {
  2904. // Since we read a DWORD and want a BOOL be paranoid. Assume FALSE is a fixed integer value (should be 0). Anything else will be TRUE.
  2905. paramp->bda_teaming.master = TRUE;
  2906. if (FALSE == dword) paramp->bda_teaming.master = FALSE;
  2907. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_BDA_MASTER, paramp->bda_teaming.master);
  2908. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_BDA_MASTER, paramp->bda_teaming.master);
  2909. }
  2910. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2911. {
  2912. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_BDA_MASTER);
  2913. }
  2914. else
  2915. {
  2916. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_BDA_MASTER, hr);
  2917. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_BDA_MASTER, paramp->bda_teaming.master);
  2918. }
  2919. // Read the reverse_hash property
  2920. hr = caf.HrGetDword(answer_sections, CVY_NAME_BDA_REVERSE_HASH, &dword);
  2921. if (SUCCEEDED(hr)) {
  2922. // Since we read a DWORD and want a BOOL be paranoid. Assume FALSE is a fixed integer value (should be 0). Anything else will be TRUE.
  2923. paramp->bda_teaming.reverse_hash = TRUE;
  2924. if (FALSE == dword) paramp->bda_teaming.reverse_hash = FALSE;
  2925. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_BDA_REVERSE_HASH, paramp->bda_teaming.reverse_hash);
  2926. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_BDA_REVERSE_HASH, paramp->bda_teaming.reverse_hash);
  2927. }
  2928. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  2929. {
  2930. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_BDA_REVERSE_HASH);
  2931. }
  2932. else
  2933. {
  2934. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_BDA_REVERSE_HASH, hr);
  2935. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_BDA_REVERSE_HASH, paramp->bda_teaming.reverse_hash);
  2936. }
  2937. /* End BDA support */
  2938. hr = HrSetupGetFirstMultiSzFieldWithAlloc(caf.Hinf(), answer_sections, CVY_NAME_PORTS, & port_str);
  2939. if (SUCCEEDED(hr)) {
  2940. PWCHAR ptr;
  2941. PWLBS_PORT_RULE rp, rulep;
  2942. /* distinct rule elements for parsing */
  2943. typedef enum
  2944. {
  2945. vip,
  2946. start,
  2947. end,
  2948. protocol,
  2949. mode,
  2950. affinity,
  2951. load,
  2952. priority
  2953. }
  2954. CVY_RULE_ELEMENT;
  2955. CVY_RULE_ELEMENT elem = vip;
  2956. DWORD count = 0;
  2957. DWORD i;
  2958. DWORD dwVipLen = 0;
  2959. const DWORD dwVipAllNameLen = sizeof(CVY_NAME_PORTRULE_VIPALL)/sizeof(WCHAR) - 1; // Used below in a loop. Set it here since it is a constant.
  2960. WCHAR wszTraceOutputTmp[WLBS_MAX_CL_IP_ADDR + 1];
  2961. bool bFallThrough = false; // Used in 'vip' case statement below.
  2962. ptr = port_str;
  2963. TRACE_VERB("%!FUNC! %ls", ptr);
  2964. TraceMsg(L"%ls\n", ptr);
  2965. while (!(*ptr == 0 && *(ptr+1) == 0)) {
  2966. if (*ptr == 0) {
  2967. *ptr = L',';
  2968. TRACE_VERB("%!FUNC! %ls", ptr);
  2969. TraceMsg(L"%ls\n", ptr);
  2970. }
  2971. ptr++;
  2972. }
  2973. TRACE_VERB("%!FUNC! read %ls %ls", CVY_NAME_PORTS, port_str);
  2974. TraceMsg(L"#### ParamReadAnswerFile read %ls %ls\n", CVY_NAME_PORTS, port_str);
  2975. rulep = paramp->i_port_rules;
  2976. ptr = port_str;
  2977. while (ptr != NULL) {
  2978. switch (elem) {
  2979. case vip:
  2980. // DO NOT MOVE THIS CASE STATEMENT. IT MUST ALWAYS COME BEFORE THE 'start' CASE STATEMENT. See FALLTHROUGH comment below.
  2981. bFallThrough = false;
  2982. dwVipLen = 0;
  2983. if (ValidateVipInRule(ptr, L',', dwVipLen))
  2984. {
  2985. ASSERT(dwVipLen <= WLBS_MAX_CL_IP_ADDR);
  2986. // rulep->virtual_ip_addr is a TCHAR and ptr is a WCHAR.
  2987. // Data is moved from the latter to the former so ASSERT TCHAR is WCHAR.
  2988. ASSERT(sizeof(TCHAR) == sizeof(WCHAR));
  2989. // This is a rule for a specific VIP
  2990. _tcsncpy(rulep->virtual_ip_addr, ptr, dwVipLen);
  2991. (rulep->virtual_ip_addr)[dwVipLen] = '\0';
  2992. }
  2993. else
  2994. {
  2995. // This is either an 'all' rule, a VIP-less rule or a malformed rule. We can't distinguish a malformed rule
  2996. // from a VIP-less rule, so we will assume the rule is either an 'all' rule or a VIP-less rule. In both cases
  2997. // set the VIP component of the rule to be the default or 'all' value.
  2998. // Copy the 'all' IP into the rule.
  2999. (VOID) StringCchCopy(rulep->virtual_ip_addr, ASIZECCH(rulep->virtual_ip_addr), CVY_DEF_ALL_VIP);
  3000. if (dwVipAllNameLen != dwVipLen || (_tcsnicmp(ptr, CVY_NAME_PORTRULE_VIPALL, dwVipAllNameLen) != 0))
  3001. {
  3002. // The rule is either VIP-less or it is malformed. We assume it is VIP-less and let the 'start'
  3003. // case handle the current token as a start_port property by falling through to the next case clause
  3004. // rather than breaking.
  3005. bFallThrough = true;
  3006. _tcsncpy(wszTraceOutputTmp, ptr, dwVipLen);
  3007. wszTraceOutputTmp[dwVipLen] = '\0';
  3008. TRACE_VERB("%!FUNC! VIP element of port rule is invalid = %ls", wszTraceOutputTmp);
  3009. TraceMsg(L"-----\n#### VIP element of port rule is invalid = %s\n", wszTraceOutputTmp);
  3010. }
  3011. }
  3012. TRACE_VERB("%!FUNC! Port rule vip = %ls", rulep->virtual_ip_addr);
  3013. TraceMsg(L"-----\n#### Port rule vip = %s\n", rulep->virtual_ip_addr);
  3014. elem = start;
  3015. // !!!!!!!!!!!!!!!!!!!!
  3016. // FALLTHROUGH
  3017. // !!!!!!!!!!!!!!!!!!!!
  3018. // When we have a VIP-less port rule, we will fall through this case statement into the 'start' case statement
  3019. // below so that the current token can be used as the start_port for a port rule.
  3020. if (!bFallThrough)
  3021. {
  3022. // We have a VIP in the port rule. We do a "break;" as std operating procedure.
  3023. TRACE_VERB("%!FUNC! Fallthrough case statement from port rule vip to start");
  3024. TraceMsg(L"-----\n#### Fallthrough case statement from port rule vip to start\n");
  3025. break;
  3026. }
  3027. // NO AUTOMATIC "break;" STATEMENT HERE. Above, we conditionally flow to the 'start' case...
  3028. case start:
  3029. // DO NOT MOVE THIS CASE STATEMENT. IT MUST ALWAYS COME AFTER THE 'vip' CASE STATEMENT.
  3030. // See comments (FALLTHROUGH) inside the 'vip' case statement.
  3031. rulep->start_port = _wtoi(ptr);
  3032. // CVY_CHECK_MIN (rulep->start_port, CVY_MIN_PORT);
  3033. CVY_CHECK_MAX (rulep->start_port, CVY_MAX_PORT);
  3034. TRACE_VERB("%!FUNC! Start port = %d", rulep->start_port);
  3035. TraceMsg(L"-----\n#### Start port = %d\n", rulep->start_port);
  3036. elem = end;
  3037. break;
  3038. case end:
  3039. rulep->end_port = _wtoi(ptr);
  3040. // CVY_CHECK_MIN (rulep->end_port, CVY_MIN_PORT);
  3041. CVY_CHECK_MAX (rulep->end_port, CVY_MAX_PORT);
  3042. TRACE_VERB("%!FUNC! End port = %d", rulep->end_port);
  3043. TraceMsg(L"#### End port = %d\n", rulep->end_port);
  3044. elem = protocol;
  3045. break;
  3046. case protocol:
  3047. switch (ptr [0]) {
  3048. case L'T':
  3049. case L't':
  3050. rulep->protocol = CVY_TCP;
  3051. TRACE_VERB("%!FUNC! Protocol = TCP");
  3052. TraceMsg(L"#### Protocol = TCP\n");
  3053. break;
  3054. case L'U':
  3055. case L'u':
  3056. rulep->protocol = CVY_UDP;
  3057. TRACE_VERB("%!FUNC! Protocol = UDP");
  3058. TraceMsg(L"#### Protocol = UDP\n");
  3059. break;
  3060. default:
  3061. rulep->protocol = CVY_TCP_UDP;
  3062. TRACE_VERB("%!FUNC! Protocol = Both");
  3063. TraceMsg(L"#### Protocol = Both\n");
  3064. break;
  3065. }
  3066. elem = mode;
  3067. break;
  3068. case mode:
  3069. switch (ptr [0]) {
  3070. case L'D':
  3071. case L'd':
  3072. rulep->mode = CVY_NEVER;
  3073. TRACE_VERB("%!FUNC! Mode = Disabled");
  3074. TraceMsg(L"#### Mode = Disabled\n");
  3075. goto end_rule;
  3076. case L'S':
  3077. case L's':
  3078. rulep->mode = CVY_SINGLE;
  3079. TRACE_VERB("%!FUNC! Mode = Single");
  3080. TraceMsg(L"#### Mode = Single\n");
  3081. elem = priority;
  3082. break;
  3083. default:
  3084. rulep->mode = CVY_MULTI;
  3085. TRACE_VERB("%!FUNC! Mode = Multiple");
  3086. TraceMsg(L"#### Mode = Multiple\n");
  3087. elem = affinity;
  3088. break;
  3089. }
  3090. break;
  3091. case affinity:
  3092. switch (ptr [0]) {
  3093. case L'C':
  3094. case L'c':
  3095. rulep->mode_data.multi.affinity = CVY_AFFINITY_CLASSC;
  3096. TRACE_VERB("%!FUNC! Affinity = Class C");
  3097. TraceMsg(L"#### Affinity = Class C\n");
  3098. break;
  3099. case L'N':
  3100. case L'n':
  3101. rulep->mode_data.multi.affinity = CVY_AFFINITY_NONE;
  3102. TRACE_VERB("%!FUNC! Affinity = None");
  3103. TraceMsg(L"#### Affinity = None\n");
  3104. break;
  3105. default:
  3106. rulep->mode_data.multi.affinity = CVY_AFFINITY_SINGLE;
  3107. TRACE_VERB("%!FUNC! Affinity = Single");
  3108. TraceMsg(L"#### Affinity = Single\n");
  3109. break;
  3110. }
  3111. elem = load;
  3112. break;
  3113. case load:
  3114. if (ptr [0] == L'E' || ptr [0] == L'e') {
  3115. rulep->mode_data.multi.equal_load = TRUE;
  3116. rulep->mode_data.multi.load = CVY_DEF_LOAD;
  3117. TRACE_VERB("%!FUNC! Load = Equal");
  3118. TraceMsg(L"#### Load = Equal\n");
  3119. } else {
  3120. rulep->mode_data.multi.equal_load = FALSE;
  3121. rulep->mode_data.multi.load = _wtoi(ptr);
  3122. // CVY_CHECK_MIN (rulep->mode_data.multi.load, CVY_MIN_LOAD);
  3123. CVY_CHECK_MAX (rulep->mode_data.multi.load, CVY_MAX_LOAD);
  3124. TRACE_VERB("%!FUNC! Load = %d", rulep->mode_data.multi.load);
  3125. TraceMsg(L"#### Load = %d\n", rulep->mode_data.multi.load);
  3126. }
  3127. goto end_rule;
  3128. case priority:
  3129. rulep->mode_data.single.priority = _wtoi(ptr);
  3130. CVY_CHECK_MIN (rulep->mode_data.single.priority, CVY_MIN_PRIORITY);
  3131. CVY_CHECK_MAX (rulep->mode_data.single.priority, CVY_MAX_PRIORITY);
  3132. TRACE_VERB("%!FUNC! Priority = %d", rulep->mode_data.single.priority);
  3133. TraceMsg(L"#### Priority = %d\n", rulep->mode_data.single.priority);
  3134. goto end_rule;
  3135. default:
  3136. TRACE_VERB("%!FUNC! Bad rule element %d", elem);
  3137. TraceMsg(L"#### Bad rule element %d\n", elem);
  3138. break;
  3139. }
  3140. next_field:
  3141. ptr = wcschr(ptr, L',');
  3142. if (ptr != NULL) {
  3143. ptr ++;
  3144. continue;
  3145. } else break;
  3146. end_rule:
  3147. elem = vip;
  3148. for (i = 0; i < count; i ++) {
  3149. rp = paramp->i_port_rules + i;
  3150. if ((rulep -> start_port < rp -> start_port &&
  3151. rulep -> end_port >= rp -> start_port) ||
  3152. (rulep -> start_port >= rp -> start_port &&
  3153. rulep -> start_port <= rp -> end_port) &&
  3154. (wcscmp(rulep -> virtual_ip_addr, rp -> virtual_ip_addr) == 0))
  3155. {
  3156. TRACE_VERB("%!FUNC! Rule %d (%d - %d) overlaps with rule %d (%d - %d)", i, rp -> start_port, rp -> end_port, count, rulep -> start_port, rulep -> end_port);
  3157. TraceMsg(L"#### Rule %d (%d - %d) overlaps with rule %d (%d - %d)\n", i, rp -> start_port, rp -> end_port, count, rulep -> start_port, rulep -> end_port);
  3158. break;
  3159. }
  3160. }
  3161. rulep -> valid = TRUE;
  3162. CVY_RULE_CODE_SET (rulep);
  3163. if (i >= count) {
  3164. count++;
  3165. rulep++;
  3166. if (count >= CVY_MAX_RULES) break;
  3167. }
  3168. goto next_field;
  3169. }
  3170. TRACE_VERB("%!FUNC! Port rules = %d", count);
  3171. TraceMsg(L"-----\n#### Port rules = %d\n", count);
  3172. paramp->i_num_rules = count;
  3173. delete [] port_str;
  3174. }
  3175. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  3176. {
  3177. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_PORTS);
  3178. }
  3179. else
  3180. {
  3181. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_PORTS, hr);
  3182. TRACE_CRIT("%!FUNC! failed reading %ls.", CVY_NAME_PORTS);
  3183. }
  3184. hr = caf.HrGetDword(answer_sections, CVY_NAME_NUM_RULES, & dword);
  3185. if (SUCCEEDED(hr)) {
  3186. paramp -> i_num_rules = dword;
  3187. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_NUM_RULES, paramp -> i_num_rules);
  3188. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_NUM_RULES, paramp -> i_num_rules);
  3189. }
  3190. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  3191. {
  3192. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_NUM_RULES);
  3193. }
  3194. else
  3195. {
  3196. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_NUM_RULES, hr);
  3197. TRACE_CRIT("%!FUNC! failed reading %ls. Retrieved %d", CVY_NAME_NUM_RULES, paramp -> i_num_rules);
  3198. }
  3199. WLBS_OLD_PORT_RULE old_port_rules [WLBS_MAX_RULES];
  3200. hr = HrSetupFindFirstLine (caf.Hinf(), answer_sections, CVY_NAME_OLD_PORT_RULES, & ctx);
  3201. if (SUCCEEDED(hr)) {
  3202. // hr = HrSetupGetBinaryField (ctx, 1, (PBYTE) paramp -> i_port_rules, sizeof (paramp -> i_port_rules), & dword);
  3203. hr = HrSetupGetBinaryField (ctx, 1, (PBYTE) old_port_rules, sizeof (old_port_rules), & dword);
  3204. if (SUCCEEDED(hr)) {
  3205. TRACE_VERB("%!FUNC! read %ls %d", CVY_NAME_OLD_PORT_RULES, dword);
  3206. TraceMsg(L"#### ParamReadAnswerFile read %ls %d\n", CVY_NAME_OLD_PORT_RULES, dword);
  3207. if (dword % sizeof (WLBS_OLD_PORT_RULE) != 0 ||
  3208. paramp -> i_num_rules != dword / sizeof (WLBS_OLD_PORT_RULE)) {
  3209. TRACE_VERB("%!FUNC! bad port rules length %d %d %d", paramp -> i_num_rules, sizeof (WLBS_OLD_PORT_RULE), dword);
  3210. TraceMsg(L"#### ParamReadAnswerFile bad port rules length %d %d %d\n", paramp -> i_num_rules, sizeof (WLBS_OLD_PORT_RULE), dword),
  3211. paramp -> i_num_rules = 0;
  3212. }
  3213. else // Convert the port rules to new format
  3214. {
  3215. if (paramp -> i_parms_ver > 3)
  3216. {
  3217. TransformOldPortRulesToNew(old_port_rules, paramp -> i_port_rules, paramp -> i_num_rules); // Returns void
  3218. TRACE_INFO("%!FUNC! transformed binary port rules to current format");
  3219. }
  3220. else
  3221. {
  3222. TRACE_INFO("%!FUNC! will not transform port rules to current format because param version is <=3: %d", paramp -> i_parms_ver);
  3223. }
  3224. }
  3225. }
  3226. else if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_SECTION_NOT_FOUND == hr))
  3227. {
  3228. paramp -> i_num_rules = 0;
  3229. TRACE_INFO("%!FUNC! optional parameter %ls not provided", CVY_NAME_OLD_PORT_RULES);
  3230. }
  3231. else
  3232. {
  3233. paramp -> i_num_rules = 0;
  3234. WriteNlbSetupErrorLog(IDS_PARM_GET_VALUE_FAILED, CVY_NAME_OLD_PORT_RULES, hr);
  3235. TRACE_CRIT("%!FUNC! failed retrieve of binary port rules %ls while reading %d", CVY_NAME_OLD_PORT_RULES, dword);
  3236. }
  3237. }
  3238. else // Did the answer file contain port rules in the non-binary form and ParametersVersion <= 3 ?
  3239. {
  3240. if ((paramp -> i_parms_ver <= 3) && (paramp -> i_num_rules > 0))
  3241. {
  3242. TRACE_VERB("%!FUNC! Answer file contains port rules in the non-binary format and yet the version number is <=3, Assuming default port rule");
  3243. TraceMsg(L"#### ParamReadAnswerFile Answer file contains port rules in the non-binary format and yet the version number is <=3, Assuming default port rule\n");
  3244. paramp -> i_num_rules = 0;
  3245. }
  3246. }
  3247. /* decode port rules prior to version 3 */
  3248. if (paramp -> i_parms_ver <= 3) {
  3249. TRACE_VERB("%!FUNC! converting port rules from version <= 3");
  3250. TraceMsg(L"#### ParamReadAnswerFile converting port rules from version 3\n");
  3251. paramp -> i_parms_ver = CVY_PARAMS_VERSION;
  3252. /* decode the port rules */
  3253. if (paramp -> i_num_rules > 0)
  3254. {
  3255. if (! License_data_decode ((PCHAR) old_port_rules, paramp -> i_num_rules * sizeof (WLBS_OLD_PORT_RULE)))
  3256. {
  3257. paramp -> i_num_rules = 0;
  3258. WriteNlbSetupErrorLog(IDS_PARM_LICENSE_DECODE_FAILED);
  3259. TRACE_CRIT("%!FUNC! license data decode failed. Port rules will not be converted to new format.");
  3260. }
  3261. else
  3262. {
  3263. TransformOldPortRulesToNew(old_port_rules, paramp -> i_port_rules, paramp -> i_num_rules);
  3264. TRACE_INFO("%!FUNC! transformed port rules to current format. Old port rule version = %d", paramp -> i_parms_ver);
  3265. }
  3266. }
  3267. else
  3268. {
  3269. TRACE_INFO("%!FUNC! there were no port rules to transform");
  3270. }
  3271. }
  3272. /* upgrade port rules from params V1 to params V2 */
  3273. if (paramp -> i_parms_ver == 1) {
  3274. paramp -> i_parms_ver = CVY_PARAMS_VERSION;
  3275. TRACE_VERB("%!FUNC! converting from version 1");
  3276. TraceMsg(L"#### ParamReadAnswerFile converting from version 1\n");
  3277. /* keep multicast off by default for old users */
  3278. paramp -> mcast_support = FALSE;
  3279. for (ULONG i = 0; i < paramp -> i_num_rules; i ++) {
  3280. PWLBS_PORT_RULE rp = paramp -> i_port_rules + i;
  3281. code = CVY_RULE_CODE_GET (rp);
  3282. CVY_RULE_CODE_SET (rp);
  3283. if (code != CVY_RULE_CODE_GET (rp)) {
  3284. rp -> code = code;
  3285. TRACE_INFO("%!FUNC! (early exit) port rule %d transformed to current version from version 1", i);
  3286. continue;
  3287. }
  3288. if (! rp -> valid) {
  3289. WriteNlbSetupErrorLog(IDS_PARM_PORT_RULE_INVALID, i);
  3290. TRACE_CRIT("%!FUNC! port rule %d (version 1 format) is not valid and will be skipped", i);
  3291. continue;
  3292. }
  3293. /* set affinity according to current ScaleSingleClient setting */
  3294. if (rp -> mode == CVY_MULTI)
  3295. rp -> mode_data . multi . affinity = (WORD)(CVY_AFFINITY_SINGLE - paramp -> i_scale_client);
  3296. CVY_RULE_CODE_SET (rp);
  3297. TRACE_INFO("%!FUNC! port rule %d transformed to current version from version 1", i);
  3298. }
  3299. }
  3300. /* upgrade max number of descriptor allocs */
  3301. if (paramp -> i_parms_ver == 2) {
  3302. TRACE_VERB("%!FUNC! upgrading descriptor settings from version 2 parameters to current");
  3303. TraceMsg(L"#### ParamReadAnswerFile converting port rules from version 2\n");
  3304. paramp -> i_parms_ver = CVY_PARAMS_VERSION;
  3305. paramp -> max_dscr_allocs = CVY_DEF_MAX_DSCR_ALLOCS;
  3306. paramp -> dscr_per_alloc = CVY_DEF_DSCR_PER_ALLOC;
  3307. }
  3308. paramp -> i_max_hosts = CVY_MAX_HOSTS;
  3309. paramp -> i_max_rules = CVY_MAX_USABLE_RULES;
  3310. // CVY_CHECK_MIN (paramp -> i_num_rules, CVY_MIN_NUM_RULES);
  3311. CVY_CHECK_MAX (paramp -> i_num_rules, CVY_MAX_NUM_RULES);
  3312. CVY_CHECK_MIN (paramp -> host_priority, CVY_MIN_HOST_PRIORITY);
  3313. CVY_CHECK_MAX (paramp -> host_priority, CVY_MAX_HOST_PRIORITY);
  3314. TRACE_VERB("<-%!FUNC!");
  3315. return S_OK;
  3316. }
  3317. //+----------------------------------------------------------------------------
  3318. //
  3319. // Function: RemoveAllPortRules
  3320. //
  3321. // Description: Remove all port rules from PWLBS_REG_PARAMS
  3322. //
  3323. // Arguments: PWLBS_REG_PARAMS reg_data -
  3324. //
  3325. // Returns: Nothing
  3326. //
  3327. // History: fengsun Created Header 3/2/00
  3328. //
  3329. //+----------------------------------------------------------------------------
  3330. void RemoveAllPortRules(PWLBS_REG_PARAMS reg_data) {
  3331. TRACE_VERB("->%!FUNC!");
  3332. TraceMsg(L"RemoveAllPortRules");
  3333. reg_data -> i_num_rules = 0;
  3334. ZeroMemory(reg_data -> i_port_rules, sizeof(reg_data -> i_port_rules));
  3335. TRACE_VERB("<-%!FUNC!");
  3336. }
  3337. //+----------------------------------------------------------------------------
  3338. //
  3339. // Function: GetAdapterFromGuid
  3340. //
  3341. // Description:
  3342. //
  3343. // Arguments: INetCfg *pNetCfg -
  3344. // const GUID& NetCardGuid -
  3345. // OUT INetCfgComponent** ppNetCardComponent -
  3346. //
  3347. // Returns: HRESULT -
  3348. //
  3349. // History: fengsun Created Header 1/21/00
  3350. //
  3351. //+----------------------------------------------------------------------------
  3352. HRESULT GetAdapterFromGuid(INetCfg *pNetCfg, const GUID& NetCardGuid, OUT INetCfgComponent** ppNetCardComponent) {
  3353. TRACE_VERB("->%!FUNC!");
  3354. *ppNetCardComponent = NULL;
  3355. HRESULT hr = S_OK;
  3356. INetCfgClass *pNetCfgClass = NULL;
  3357. BOOL fFoundMatch = FALSE;
  3358. hr = pNetCfg->QueryNetCfgClass(&GUID_DEVCLASS_NET, IID_INetCfgClass, (void **)&pNetCfgClass);
  3359. if (FAILED(hr)) {
  3360. TraceError("INetCfg::QueryNetCfgClass failed", hr);
  3361. TRACE_CRIT("%!FUNC! QueryNetCfgClass failed with %d", hr);
  3362. return hr;
  3363. }
  3364. /* Get an enumerator to list all network devices. */
  3365. IEnumNetCfgComponent *pIEnumComponents = NULL;
  3366. if (FAILED(hr = pNetCfgClass->EnumComponents(&pIEnumComponents))) {
  3367. TraceError("INetCfg::EnumComponents failed", hr);
  3368. TRACE_CRIT("%!FUNC! failed enumerating components with %d", hr);
  3369. pNetCfgClass->Release();
  3370. return hr;
  3371. }
  3372. /* Go through all the components and bind to the matching netcard. */
  3373. while (pIEnumComponents->Next(1, ppNetCardComponent, NULL) == S_OK) {
  3374. GUID guidInstance;
  3375. /* Retrieve the instance GUID of the component. */
  3376. if (FAILED(hr = (*ppNetCardComponent)->GetInstanceGuid(&guidInstance))) {
  3377. TraceError("GetInstanceGuid failed", hr);
  3378. TRACE_CRIT("%!FUNC! getting instance guid from the net card failed with %d", hr);
  3379. continue;
  3380. }
  3381. /* Check whether we found a match. */
  3382. if (IsEqualGUID(NetCardGuid, guidInstance)) {
  3383. fFoundMatch = TRUE;
  3384. TRACE_INFO("%!FUNC! netcard matched to component");
  3385. break;
  3386. }
  3387. (*ppNetCardComponent)->Release();
  3388. *ppNetCardComponent = NULL;
  3389. }
  3390. if (!fFoundMatch) {
  3391. TraceMsg(L"Found no netcard\n");
  3392. TRACE_CRIT("%!FUNC! no adapter found with the input GUID");
  3393. hr = HRESULT_FROM_WIN32( ERROR_NOT_FOUND );
  3394. }
  3395. if (pIEnumComponents) pIEnumComponents->Release();
  3396. if (pNetCfgClass) pNetCfgClass->Release();
  3397. TRACE_VERB("<-%!FUNC!");
  3398. return hr;
  3399. }
  3400. //+----------------------------------------------------------------------------
  3401. //
  3402. // Function: WriteAdapterName
  3403. //
  3404. // Description:
  3405. //
  3406. // Arguments: CWlbsConfig* pConfig -
  3407. // GUID& AdapterGuid -
  3408. //
  3409. // Returns: bool -
  3410. //
  3411. // History: fengsun Created Header 7/6/00
  3412. //
  3413. //+----------------------------------------------------------------------------
  3414. bool WriteAdapterName(CWlbsConfig* pConfig, GUID& AdapterGuid) {
  3415. TRACE_VERB("->%!FUNC!");
  3416. PWSTR pszPnpDevNodeId = NULL;
  3417. HKEY key;
  3418. DWORD status;
  3419. HRESULT hr;
  3420. INetCfgComponent* pAdapter = NULL;
  3421. hr = GetAdapterFromGuid(pConfig->m_pNetCfg, AdapterGuid, &pAdapter);
  3422. if (hr != S_OK) {
  3423. TraceError("GetAdapterFromGuid failed at GetPnpDevNodeId", hr);
  3424. TRACE_CRIT("%!FUNC! GetAdapterFromGuid failed with %d", hr);
  3425. TRACE_VERB("<-%!FUNC!");
  3426. return false;
  3427. }
  3428. hr = pAdapter->GetPnpDevNodeId (& pszPnpDevNodeId);
  3429. pAdapter->Release();
  3430. pAdapter = NULL;
  3431. if (hr != S_OK) {
  3432. TraceError("HrWriteAdapterName failed at GetPnpDevNodeId", hr);
  3433. TRACE_CRIT("%!FUNC! GetPnpDevNodeId on adapter failed with %d", hr);
  3434. TRACE_VERB("<-%!FUNC!");
  3435. return false;
  3436. }
  3437. key = pConfig->m_pWlbsApiFuncs->pfnRegOpenWlbsSetting(AdapterGuid, false);
  3438. if (key == NULL) {
  3439. status = GetLastError();
  3440. TraceError("HrWriteAdapterName failed at RegOpenWlbsSetting", status);
  3441. CoTaskMemFree(pszPnpDevNodeId);
  3442. TRACE_CRIT("%!FUNC! RegOpenWlbsSetting failed with %d", status);
  3443. TRACE_VERB("<-%!FUNC!");
  3444. return false;
  3445. }
  3446. status = RegSetValueEx (key, CVY_NAME_CLUSTER_NIC, 0L, CVY_TYPE_CLUSTER_NIC, (LPBYTE) pszPnpDevNodeId, wcslen(pszPnpDevNodeId) * sizeof (WCHAR));
  3447. CoTaskMemFree(pszPnpDevNodeId);
  3448. RegCloseKey(key);
  3449. if (status != ERROR_SUCCESS) {
  3450. TraceError("HrWriteAdapterName failed at RegSetValueEx", status);
  3451. TRACE_CRIT("%!FUNC! RegSetValueEx failed with %d", status);
  3452. TRACE_VERB("<-%!FUNC!");
  3453. return false;
  3454. }
  3455. TRACE_VERB("<-%!FUNC!");
  3456. return true;
  3457. }
  3458. /*
  3459. * Function: WriteIPSecNLBRegistryKey
  3460. * Description: This function updates IPSec as to the current binding state
  3461. * of NLB. That is, if NLB is bound to at least one adapter on
  3462. * this host, we notify IPSec so that they begin to notify us
  3463. * when IPSec sessions are created and destroyed. This is
  3464. * usually accomplished through an RPC call to the IPSec service;
  3465. * however, if the service is unavailable, we attempt to create
  3466. * or modify the key(s) ourselves.
  3467. * Parameters: dwNLBSFlags - the current value of the NLB flags to pass to IPSec
  3468. * Returns: boolean - true if successful, false otherwise
  3469. * Author: shouse, 11.27.01
  3470. */
  3471. bool WriteIPSecNLBRegistryKey (DWORD dwNLBSFlags) {
  3472. IKE_CONFIG IKEConfig; /* Defined in winipsec.h */
  3473. bool bForceUpdate = false;
  3474. DWORD dwDisposition =0;
  3475. HKEY registry;
  3476. DWORD key_type;
  3477. DWORD key_size = sizeof(DWORD);
  3478. DWORD tmp;
  3479. ZeroMemory(&IKEConfig, sizeof(IKE_CONFIG));
  3480. /* If it failed because the RPC server was unavailable, then the IPSec
  3481. service is not currently running - this happens certainly during
  3482. upgrades and installs, but can also happen if the service has been
  3483. purposefully stopped. In this case, try to create the keys ourselves
  3484. and IPSec will pick up the changes when the service is re-started. */
  3485. if (GetConfigurationVariables(NULL, &IKEConfig) != ERROR_SUCCESS) {
  3486. TRACE_CRIT("%!FUNC! IPSec RPC server unavailable... Trying to read registry settings manually");
  3487. /* Try to open the Oakley (IKE) settings registry key. */
  3488. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\PolicyAgent\\Oakley", 0, KEY_QUERY_VALUE, &registry) == ERROR_SUCCESS) {
  3489. /* Try to query the current value of the NLBSFlags. */
  3490. if (RegQueryValueEx(registry, L"NLBSFlags", 0, &key_type, (unsigned char *)&tmp, &key_size) == ERROR_SUCCESS) {
  3491. /* If successful, store the retrieved value in the IKEConfig structure. */
  3492. IKEConfig.dwNLBSFlags = tmp;
  3493. } else {
  3494. TRACE_INFO("%!FUNC! Unable to read NLBSFlags registry value... Will force a write to try to create it");
  3495. /* If querying the key failed, it might not yet exist, so force an
  3496. update to attempt to create the key later. */
  3497. bForceUpdate = true;
  3498. }
  3499. /* Close the Oakley registry key. */
  3500. RegCloseKey(registry);
  3501. } else {
  3502. TRACE_INFO("%!FUNC! Unable to open Oakley registry key... Will force a write to try to create it");
  3503. /* If we can't open the Oakley registry key, it might not yet exist,
  3504. so force an update to try to create it ourselves later. */
  3505. bForceUpdate = true;
  3506. }
  3507. /* If the registry contains the same flag value that we're trying to set
  3508. it to, there is no reason to proceed unless we're forcing an update. */
  3509. if (!bForceUpdate && (IKEConfig.dwNLBSFlags == dwNLBSFlags))
  3510. return true;
  3511. /* Set the NLB flags - this tells IPSec whether or not NLB is bound to at least one adapter. */
  3512. IKEConfig.dwNLBSFlags = dwNLBSFlags;
  3513. } else {
  3514. /* If the registry contains the same flag value that we're trying to set
  3515. it to, there is no reason to proceed. */
  3516. if (IKEConfig.dwNLBSFlags == dwNLBSFlags)
  3517. return true;
  3518. /* Set the NLB flags - this tells IPSec whether or not NLB is bound to at least one adapter. */
  3519. IKEConfig.dwNLBSFlags = dwNLBSFlags;
  3520. /* Set the new configuration, of which only the NLB flags are changed. Only attempt
  3521. this if the corresponding RPC read succeeded. Note that the value of dwStatus is
  3522. only set by the GetConfigurationVariables and SetConfigurationVariables RPC calls. */
  3523. if (SetConfigurationVariables(NULL, IKEConfig) == ERROR_SUCCESS)
  3524. return true;
  3525. }
  3526. TRACE_CRIT("%!FUNC! IPSec RPC server unavailable... Trying to write registry settings manually");
  3527. /* Try to open the Oakley registry key. */
  3528. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\PolicyAgent\\Oakley", 0, KEY_SET_VALUE, &registry) != ERROR_SUCCESS) {
  3529. /* If opening the key fails, it might not exist, so try to create it. */
  3530. if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\PolicyAgent\\Oakley", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &registry, &dwDisposition) != ERROR_SUCCESS) {
  3531. TRACE_CRIT("%!FUNC! Unable to create Oakley registry key");
  3532. /* If we can't create the key, we're hosed; bail out. */
  3533. return false;
  3534. }
  3535. }
  3536. /* Now try to set the new value of the NLBSFlags settings. */
  3537. if (RegSetValueEx(registry, L"NLBSFlags", 0, REG_DWORD, (unsigned char *)&IKEConfig.dwNLBSFlags, sizeof(DWORD)) != ERROR_SUCCESS) {
  3538. /* If setting the value fails, close the Oakley key and bail out. */
  3539. RegCloseKey(registry);
  3540. TRACE_CRIT("%!FUNC! Unable to write NLBSFlags registry value");
  3541. return false;
  3542. }
  3543. /* Now that we've successfully updated the NLB settings, close the Oakley key. */
  3544. RegCloseKey(registry);
  3545. /* Return successfully. */
  3546. return true;
  3547. }
  3548. /*
  3549. * Function: WriteHostStateRegistryKey
  3550. * Description: This function writes the HostState registry key, which is the key
  3551. * that the driver will use to determine the state of the host on boot.
  3552. * Author: shouse, 7.22.01
  3553. * Notes:
  3554. */
  3555. bool WriteHostStateRegistryKey (CWlbsConfig * pConfig, GUID & AdapterGuid, ULONG State) {
  3556. HKEY key;
  3557. DWORD status;
  3558. HRESULT hr;
  3559. TRACE_VERB("->%!FUNC!");
  3560. /* Open the WLBS registry settings. */
  3561. key = pConfig->m_pWlbsApiFuncs->pfnRegOpenWlbsSetting(AdapterGuid, false);
  3562. /* If we can't open the key, just bail out. */
  3563. if (key == NULL) {
  3564. status = GetLastError();
  3565. TraceError("WriteHostStateRegistryKey failed at RegOpenWlbsSetting", status);
  3566. TRACE_CRIT("%!FUNC! RegOpenWlbsSetting failed with %d", status);
  3567. TRACE_VERB("<-%!FUNC!");
  3568. return false;
  3569. }
  3570. /* Set the value of the HostState registry entry. */
  3571. status = RegSetValueEx(key, CVY_NAME_HOST_STATE, 0L, CVY_TYPE_HOST_STATE, (LPBYTE)&State, sizeof(State));
  3572. /* Close the handle. */
  3573. RegCloseKey(key);
  3574. /* If writing failed, bail out. */
  3575. if (status != ERROR_SUCCESS) {
  3576. TraceError("WriteHostStateRegistryKey failed at RegSetValueEx", status);
  3577. TRACE_CRIT("%!FUNC! RegSetValueEx failed with %d", status);
  3578. TRACE_VERB("<-%!FUNC!");
  3579. return false;
  3580. }
  3581. TRACE_VERB("<-%!FUNC!");
  3582. return true;
  3583. }
  3584. //+----------------------------------------------------------------------------
  3585. //
  3586. // Function: ValidateVipInRule
  3587. //
  3588. // Description: Parses pwszRuleString, looking for a valid VIP which must be
  3589. // in the first token
  3590. //
  3591. // Arguments: PWCHAR pwszRuleString - tokenized string concatentating all
  3592. // defined port rules
  3593. // PWCHAR pwToken - the token character that separates the fields
  3594. // DWORD& dwVipLen - if a token is found, this contains the size
  3595. // of the string; 0 otherwise. The number of
  3596. // characters returned is bound to <=
  3597. // WLBS_MAX_CL_IP_ADDR
  3598. //
  3599. // NOTES: A non-zero value for dwVipLen does NOT imply that the VIP is valid,
  3600. // only that there was a non-zero length string in the expected
  3601. // location. The user must check the return value to validate the VIP.
  3602. //
  3603. // Returns: bool - true if the first field in the string has a valid IP address
  3604. // format; false otherwise.
  3605. //
  3606. // Assumptions: First token is the VIP element of a port rule
  3607. //
  3608. // History: chrisdar Created 01/05/15
  3609. //
  3610. //+----------------------------------------------------------------------------
  3611. bool ValidateVipInRule(const PWCHAR pwszRuleString, const WCHAR pwToken, DWORD& dwVipLen)
  3612. {
  3613. TRACE_VERB("->%!FUNC!");
  3614. ASSERT(NULL != pwszRuleString);
  3615. bool ret = false;
  3616. dwVipLen = 0;
  3617. // Find the first occurence of the token string, which will denote the end of
  3618. // the VIP part of the rule
  3619. PWCHAR pwcAtSeparator = wcschr(pwszRuleString, pwToken);
  3620. if (NULL == pwcAtSeparator) {
  3621. TRACE_CRIT("%!FUNC! No token separator when one was expected");
  3622. TRACE_VERB("<-%!FUNC!");
  3623. return ret;
  3624. }
  3625. // Found the token string. Copy out the VIP and validate it.
  3626. WCHAR wszIP[WLBS_MAX_CL_IP_ADDR + 1];
  3627. DWORD dwStrLen = min((UINT)(pwcAtSeparator - pwszRuleString),
  3628. WLBS_MAX_CL_IP_ADDR);
  3629. wcsncpy(wszIP, pwszRuleString, dwStrLen);
  3630. wszIP[dwStrLen] = '\0';
  3631. ASSERT(dwStrLen == wcslen(wszIP));
  3632. dwVipLen = dwStrLen;
  3633. // IpAddressFromAbcdWsz calls inet_addr to check the format of the IP address, but the
  3634. // allowed formats are very flexible. For our port rule definition of a VIP we require
  3635. // a rigid a.b.c.d format. To ensure that we only say the IP address is valid for IPs
  3636. // specified in this manner, ensure that there are 3 and only 3 '.' in the string.
  3637. DWORD dwTmpCount = 0;
  3638. PWCHAR pwszTmp = pwszRuleString;
  3639. while (pwszTmp < pwcAtSeparator)
  3640. {
  3641. if (*pwszTmp++ == L'.') { dwTmpCount++; }
  3642. }
  3643. if (dwTmpCount == 3 && INADDR_NONE != IpAddressFromAbcdWsz(wszIP)) {
  3644. TRACE_INFO("%!FUNC! The IP address %ls is a valid IP of the form a.b.c.d", wszIP);
  3645. ret = true;
  3646. } else {
  3647. TRACE_INFO("%!FUNC! The IP address %ls is NOT a valid IP of the form a.b.c.d", wszIP);
  3648. }
  3649. TRACE_VERB("<-%!FUNC!");
  3650. return ret;
  3651. }