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.

2296 lines
59 KiB

  1. //***************************************************************************
  2. //
  3. // EXTCFG.CPP
  4. //
  5. // Module: WMI Framework Instance provider
  6. //
  7. // Purpose: Low-level utilities to configure NICs -- bind/unbind,
  8. // get/set IP address lists, and get/set NLB cluster params.
  9. //
  10. // Copyright (c)2001 Microsoft Corporation, All Rights Reserved
  11. //
  12. // History:
  13. //
  14. // 04/05/01 JosephJ Created (original version, from updatecfg.cpp under
  15. // nlbmgr\provider).
  16. // 07/23/01 JosephJ Moved functionality to lib.
  17. //
  18. //***************************************************************************
  19. #include "private.h"
  20. #include "extcfg.tmh"
  21. //
  22. // NLBUPD_MAX_NETWORK_ADDRESS_LENGTH is the max number of chars (excluding
  23. // the terminating 0) of a string of the form "ip-addr/subnet", eg:
  24. // "10.0.0.1/255.255.255.0"
  25. //
  26. #define NLBUPD_MAX_NETWORK_ADDRESS_LENGTH \
  27. (WLBS_MAX_CL_IP_ADDR + 1 + WLBS_MAX_CL_NET_MASK)
  28. LPWSTR *
  29. allocate_string_array(
  30. UINT NumStrings,
  31. UINT StringLen // excluding ending NULL
  32. );
  33. WBEMSTATUS
  34. address_string_to_ip_and_subnet(
  35. IN LPCWSTR szAddress,
  36. OUT LPWSTR szIp, // max WLBS_MAX_CL_IP_ADDR
  37. OUT LPWSTR szSubnet // max WLBS_MAX_CL_NET_MASK
  38. );
  39. WBEMSTATUS
  40. ip_and_subnet_to_address_string(
  41. IN LPCWSTR szIp,
  42. IN LPCWSTR szSubnet,
  43. IN UINT cchAddress, // length in chars, including NULL.
  44. OUT LPWSTR szAddress // max NLBUPD_MAX_NETWORK_ADDRESS_LENGTH
  45. // + 1 (for NULL)
  46. );
  47. VOID
  48. uint_to_szipaddr(
  49. UINT uIpAddress, // Ip address or subnet -- no validation, network order
  50. UINT cchLen,
  51. WCHAR *rgAddress // Expected to be at least 17 chars long
  52. );
  53. const NLB_IP_ADDRESS_INFO *
  54. find_ip_in_ipinfo(
  55. LPCWSTR szIpToFind,
  56. const NLB_IP_ADDRESS_INFO *pIpInfo,
  57. UINT NumIpInfos
  58. );
  59. NLBERROR
  60. NLB_EXTENDED_CLUSTER_CONFIGURATION::AnalyzeUpdate(
  61. IN OUT NLB_EXTENDED_CLUSTER_CONFIGURATION *pNewCfg,
  62. OUT BOOL *pfConnectivityChange
  63. )
  64. //
  65. // NLBERR_NO_CHANGE -- update is a no-op.
  66. //
  67. // Will MUNGE pNewCfg -- munge NlbParams and also
  68. // fill out pIpAddressInfo if it's NULL.
  69. //
  70. {
  71. NLBERROR nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION;
  72. BOOL fConnectivityChange = FALSE;
  73. BOOL fSettingsChanged = FALSE;
  74. UINT NumIpAddresses = 0;
  75. NLB_IP_ADDRESS_INFO *pNewIpInfo = NULL;
  76. const NLB_EXTENDED_CLUSTER_CONFIGURATION *pOldCfg = this;
  77. UINT u;
  78. LPCWSTR szFriendlyName = m_szFriendlyName;
  79. if (szFriendlyName == NULL)
  80. {
  81. szFriendlyName = L"";
  82. }
  83. if (pOldCfg->fBound && !pOldCfg->fValidNlbCfg)
  84. {
  85. //
  86. // We're starting with a bound but invalid cluster state -- all bets are
  87. // off.
  88. //
  89. fConnectivityChange = TRUE;
  90. TRACE_CRIT("Analyze: Choosing Async because old state is invalid %ws", szFriendlyName);
  91. }
  92. else if (pOldCfg->fBound != pNewCfg->fBound)
  93. {
  94. //
  95. // bound/unbound state is different -- we do async
  96. //
  97. fConnectivityChange = TRUE;
  98. if (pNewCfg->fBound)
  99. {
  100. TRACE_CRIT("Analyze: Request to bind NLB to %ws", szFriendlyName);
  101. }
  102. else
  103. {
  104. TRACE_CRIT("Analyze: Request to unbind NLB from %ws", szFriendlyName);
  105. }
  106. }
  107. else
  108. {
  109. if (pNewCfg->fBound)
  110. {
  111. TRACE_CRIT("Analyze: Request to change NLB configuration on %ws", szFriendlyName);
  112. }
  113. else
  114. {
  115. TRACE_CRIT("Analyze: NLB not bound and to remain not bound on %ws", szFriendlyName);
  116. }
  117. }
  118. if (pNewCfg->fBound)
  119. {
  120. const WLBS_REG_PARAMS *pOldParams = NULL;
  121. if (pOldCfg->fBound)
  122. {
  123. pOldParams = &pOldCfg->NlbParams;
  124. }
  125. //
  126. // We may have been bound before and we remain bound, let's check if we
  127. // still need to do async, and also vaidate pNewCfg wlbs params in the
  128. // process
  129. //
  130. WBEMSTATUS
  131. TmpStatus = CfgUtilsAnalyzeNlbUpdate(
  132. pOldParams,
  133. &pNewCfg->NlbParams,
  134. &fConnectivityChange
  135. );
  136. if (FAILED(TmpStatus))
  137. {
  138. TRACE_CRIT("Analyze: Error analyzing nlb params for %ws", szFriendlyName);
  139. switch(TmpStatus)
  140. {
  141. case WBEM_E_INVALID_PARAMETER:
  142. nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION;
  143. break;
  144. case WBEM_E_INITIALIZATION_FAILURE:
  145. nerr = NLBERR_INITIALIZATION_FAILURE;
  146. break;
  147. default:
  148. nerr = NLBERR_LLAPI_FAILURE;
  149. break;
  150. }
  151. goto end;
  152. }
  153. //
  154. // NOTE: CfgUtilsAnalyzeNlbUpdate can return WBEM_S_FALSE if
  155. // the update is a no-op. We should be careful to preserve this
  156. // on success.
  157. //
  158. if (TmpStatus == WBEM_S_FALSE)
  159. {
  160. //
  161. // Let's check if a new password has been specified...
  162. //
  163. if (pNewCfg->NewRemoteControlPasswordSet())
  164. {
  165. fSettingsChanged = TRUE;
  166. }
  167. }
  168. else
  169. {
  170. fSettingsChanged = TRUE;
  171. }
  172. //
  173. // Check the supplied list of IP addresses, to make sure that
  174. // includes the dedicated IP first and the cluster vip and the
  175. // per-port-rule vips.
  176. //
  177. NumIpAddresses = pNewCfg->NumIpAddresses;
  178. if ((NumIpAddresses == 0) != (pNewCfg->pIpAddressInfo == NULL))
  179. {
  180. // Bogus input
  181. TRACE_CRIT("Analze: mismatch between NumIpAddresses and pIpInfo");
  182. goto end;
  183. }
  184. nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION;
  185. if (NumIpAddresses == 0)
  186. {
  187. BOOL fRet;
  188. NlbIpAddressList IpList;
  189. if (pOldCfg->fBound && pOldCfg->fValidNlbCfg)
  190. {
  191. //
  192. // NLB is currently bound with a valid configuration.
  193. //
  194. //
  195. // If we we're told to do so, we try to preserve
  196. // old IP addresses as far as possible. So we start with the
  197. // old config, remove the old dedicated IP address (if present),
  198. // and primary VIP, and add the new dedicated IP address (if
  199. // present) and cluster vip. If subnet masks have changed for
  200. // these we update them.
  201. //
  202. // All other IP addresses are left intact.
  203. //
  204. //
  205. if (pNewCfg->fAddClusterIps)
  206. {
  207. //
  208. // Start with the original set of ip addresses.
  209. //
  210. fRet = IpList.Set(
  211. pOldCfg->NumIpAddresses,
  212. pOldCfg->pIpAddressInfo,
  213. 0
  214. );
  215. if (!fRet)
  216. {
  217. TRACE_CRIT("!FUNC!: IpList.Set (orig ips) failed");
  218. goto end;
  219. }
  220. if (_wcsicmp(pNewCfg->NlbParams.cl_ip_addr,
  221. pOldCfg->NlbParams.cl_ip_addr) )
  222. {
  223. //
  224. // If the cluster IP has changed,
  225. // remove the old cluster IP address.
  226. //
  227. // 1/25/02 josephj NOTE: we only do this
  228. // if the cluster IP has CHANGED,
  229. // otherwise, by taking it out, we lose it's position
  230. // in the old config, so we may end up changing it's
  231. // position unnecessarily (added the wcsicmp
  232. // check above today).
  233. //
  234. // We don't care if it fails.
  235. //
  236. (VOID) IpList.Modify(
  237. pOldCfg->NlbParams.cl_ip_addr,
  238. NULL,
  239. NULL
  240. );
  241. }
  242. //
  243. // Remove the old dedicated IP address first
  244. // We don't care if this fails.
  245. //
  246. (VOID) IpList.Modify(
  247. pOldCfg->NlbParams.ded_ip_addr,
  248. NULL, // new ip address
  249. NULL // new subnet mask
  250. );
  251. }
  252. }
  253. if (pNewCfg->fAddClusterIps)
  254. {
  255. //
  256. // Now add the new cluster Ip address
  257. //
  258. fRet = IpList.Modify(
  259. NULL,
  260. pNewCfg->NlbParams.cl_ip_addr,
  261. pNewCfg->NlbParams.cl_net_mask
  262. );
  263. if (!fRet)
  264. {
  265. TRACE_CRIT("!FUNC!: IpList.Modify (new cl ip) failed");
  266. goto end;
  267. }
  268. }
  269. if (pNewCfg->fAddDedicatedIp)
  270. {
  271. //
  272. // Add the new dedicated IP address --
  273. // to ensure when we add it, it's at the head of the list.
  274. //
  275. //
  276. // We won't add it if it is null, of course.
  277. //
  278. if (!pNewCfg->IsBlankDedicatedIp())
  279. {
  280. fRet = IpList.Modify(
  281. NULL,
  282. pNewCfg->NlbParams.ded_ip_addr,
  283. pNewCfg->NlbParams.ded_net_mask
  284. );
  285. if (!fRet)
  286. {
  287. TRACE_CRIT("!FUNC!: IpList.Modify (new ded ip) failed");
  288. goto end;
  289. }
  290. }
  291. }
  292. //
  293. // Finally, set these new addresses.
  294. //
  295. pNewCfg->SetNetworkAddressesRaw(NULL,0);
  296. IpList.Extract(
  297. REF pNewCfg->NumIpAddresses,
  298. REF pNewCfg->pIpAddressInfo
  299. );
  300. nerr = NLBERR_OK;
  301. } // End case that NumIpAddresses is zero.
  302. //
  303. // We're done munging IP addresses; Now get the latest
  304. // ip address info and count and make sure things look ok.
  305. //
  306. pNewIpInfo = pNewCfg->pIpAddressInfo;
  307. NumIpAddresses = pNewCfg->NumIpAddresses;
  308. nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION;
  309. //
  310. // Check that dedicated ip address, if present is first.
  311. //
  312. if (pNewCfg->fAddDedicatedIp && !pNewCfg->IsBlankDedicatedIp())
  313. {
  314. if (NumIpAddresses == 0)
  315. {
  316. //
  317. // We don't expect to get here because of checks above, but
  318. // neverthless...
  319. //
  320. TRACE_CRIT("%!FUNC! address list unexpectedly zero");
  321. nerr = NLBERR_INTERNAL_ERROR;
  322. goto end;
  323. }
  324. if (_wcsicmp(pNewIpInfo[0].IpAddress, pNewCfg->NlbParams.ded_ip_addr))
  325. {
  326. TRACE_CRIT("%!FUNC! ERROR: dedicated IP address(%ws) is not first IP address(%ws)",
  327. pNewCfg->NlbParams.ded_ip_addr, pNewIpInfo[0].IpAddress);
  328. goto end;
  329. }
  330. if (_wcsicmp(pNewIpInfo[0].SubnetMask, pNewCfg->NlbParams.ded_net_mask))
  331. {
  332. TRACE_CRIT("%!FUNC! ERROR: dedicated net mask(%ws) does not match IP net mask(%ws)",
  333. pNewCfg->NlbParams.ded_net_mask, pNewIpInfo[0].SubnetMask);
  334. goto end;
  335. }
  336. }
  337. //
  338. // Check that cluster-vip is present
  339. //
  340. if (fAddClusterIps)
  341. {
  342. for (u=0; u< NumIpAddresses; u++)
  343. {
  344. if (!_wcsicmp(pNewIpInfo[u].IpAddress, pNewCfg->NlbParams.cl_ip_addr))
  345. {
  346. //
  347. // Found it! Check that the subnet masks match.
  348. //
  349. if (_wcsicmp(pNewIpInfo[u].SubnetMask, pNewCfg->NlbParams.cl_net_mask))
  350. {
  351. TRACE_CRIT("Cluster subnet mask doesn't match that in addr list");
  352. goto end;
  353. }
  354. break;
  355. }
  356. }
  357. if (u==NumIpAddresses)
  358. {
  359. TRACE_CRIT("Cluster ip address(%ws) is not in the list of addresses!", pNewCfg->NlbParams.cl_ip_addr);
  360. goto end;
  361. }
  362. //
  363. // Check that per-port-rule vips are present.
  364. // TODO
  365. {
  366. }
  367. }
  368. }
  369. else
  370. {
  371. //
  372. // NLB is to be unbound.
  373. //
  374. NumIpAddresses = pNewCfg->NumIpAddresses;
  375. if (NumIpAddresses == 0 && pOldCfg->fBound && pOldCfg->fValidNlbCfg)
  376. {
  377. //
  378. // No ip addresses specified and we're currently bound.
  379. // If the DIP is present in the current
  380. // list of IP addresses, we keep it even after we unbind.
  381. //
  382. const NLB_IP_ADDRESS_INFO *pFoundInfo = NULL;
  383. pFoundInfo = find_ip_in_ipinfo(
  384. pOldCfg->NlbParams.ded_ip_addr,
  385. pOldCfg->pIpAddressInfo,
  386. pOldCfg->NumIpAddresses
  387. );
  388. if (pFoundInfo != NULL)
  389. {
  390. //
  391. // Found it -- let's take it.
  392. //
  393. BOOL fRet;
  394. NlbIpAddressList IpList;
  395. fRet = IpList.Set(1, pFoundInfo, 0);
  396. if (fRet)
  397. {
  398. TRACE_VERB(
  399. "%!FUNC! preserving dedicated ip address %ws on unbind",
  400. pFoundInfo->IpAddress
  401. );
  402. IpList.Extract(
  403. REF pNewCfg->NumIpAddresses,
  404. REF pNewCfg->pIpAddressInfo
  405. );
  406. }
  407. }
  408. }
  409. else
  410. {
  411. //
  412. // We don't do any checking on the supplied
  413. // list of IP addresses -- we assume caller knows best. Note that
  414. // if NULL
  415. // we switch to dhcp/autonet.
  416. //
  417. }
  418. }
  419. nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION;
  420. //
  421. // If there's any change in the list of ipaddresses or subnets, including
  422. // a change in the order, we switch to async.
  423. //
  424. if (pNewCfg->NumIpAddresses != pOldCfg->NumIpAddresses)
  425. {
  426. TRACE_INFO("Analyze: detected change in list of IP addresses on %ws", szFriendlyName);
  427. fConnectivityChange = TRUE;
  428. }
  429. else
  430. {
  431. NLB_IP_ADDRESS_INFO *pOldIpInfo = NULL;
  432. //
  433. // Check if there is a change in the list of ip addresses or
  434. // their order of appearance.
  435. //
  436. NumIpAddresses = pNewCfg->NumIpAddresses;
  437. pOldIpInfo = pOldCfg->pIpAddressInfo;
  438. pNewIpInfo = pNewCfg->pIpAddressInfo;
  439. for (u=0; u<NumIpAddresses; u++)
  440. {
  441. if ( _wcsicmp(pNewIpInfo[u].IpAddress, pOldIpInfo[u].IpAddress)
  442. || _wcsicmp(pNewIpInfo[u].SubnetMask, pOldIpInfo[u].SubnetMask))
  443. {
  444. TRACE_INFO("Analyze: detected change in list of IP addresses on %ws", szFriendlyName);
  445. fConnectivityChange = TRUE;
  446. break;
  447. }
  448. }
  449. }
  450. nerr = NLBERR_OK;
  451. end:
  452. if (nerr == NLBERR_OK)
  453. {
  454. *pfConnectivityChange = fConnectivityChange;
  455. if (fConnectivityChange)
  456. {
  457. fSettingsChanged = TRUE;
  458. }
  459. if (fSettingsChanged)
  460. {
  461. nerr = NLBERR_OK;
  462. }
  463. else
  464. {
  465. nerr = NLBERR_NO_CHANGE;
  466. }
  467. }
  468. return nerr;
  469. }
  470. WBEMSTATUS
  471. NLB_EXTENDED_CLUSTER_CONFIGURATION::Update(
  472. IN const NLB_EXTENDED_CLUSTER_CONFIGURATION *pCfgNew
  473. )
  474. //
  475. // Applies the properties in pCfgNew to this.
  476. // Does NOT copy szNewRemoteControlPassword -- instead sets that field to NULL
  477. //
  478. {
  479. WBEMSTATUS Status;
  480. UINT NumIpAddresses = pCfgNew->NumIpAddresses;
  481. NLB_IP_ADDRESS_INFO *pIpAddressInfo = NULL;
  482. NLB_EXTENDED_CLUSTER_CONFIGURATION *pCfg = this;
  483. //
  484. // Free and realloc pCfg's ip info array if rquired.
  485. //
  486. if (pCfg->NumIpAddresses == NumIpAddresses)
  487. {
  488. //
  489. // we can re-use the existing one
  490. //
  491. pIpAddressInfo = pCfg->pIpAddressInfo;
  492. }
  493. else
  494. {
  495. //
  496. // Free the old one and allocate space for the new array if required.
  497. //
  498. if (NumIpAddresses != 0)
  499. {
  500. pIpAddressInfo = new NLB_IP_ADDRESS_INFO[NumIpAddresses];
  501. if (pIpAddressInfo == NULL)
  502. {
  503. TRACE_CRIT(L"Error allocating space for IP address info array");
  504. Status = WBEM_E_OUT_OF_MEMORY;
  505. goto end;
  506. }
  507. }
  508. if (pCfg->NumIpAddresses!=0)
  509. {
  510. delete pCfg->pIpAddressInfo;
  511. pCfg->pIpAddressInfo = NULL;
  512. pCfg->NumIpAddresses = 0;
  513. }
  514. }
  515. //
  516. // Copy over the new ip address info, if there is any.
  517. //
  518. if (NumIpAddresses)
  519. {
  520. CopyMemory(
  521. pIpAddressInfo,
  522. pCfgNew->pIpAddressInfo,
  523. NumIpAddresses*sizeof(*pIpAddressInfo)
  524. );
  525. }
  526. //
  527. // Do any other error checks here.
  528. //
  529. //
  530. // Struct copy the entire structure, then fix up the pointer to
  531. // ip address info array.
  532. //
  533. (VOID) pCfg->SetFriendlyName(NULL);
  534. delete m_szNewRemoteControlPassword;
  535. *pCfg = *pCfgNew; // struct copy
  536. pCfg->m_szFriendlyName = NULL; // TODO: clean this up.
  537. pCfg->m_szNewRemoteControlPassword = NULL;
  538. pCfg->pIpAddressInfo = pIpAddressInfo;
  539. pCfg->NumIpAddresses = NumIpAddresses;
  540. (VOID) pCfg->SetFriendlyName(pCfgNew->m_szFriendlyName);
  541. //
  542. // Update does NOT copy over the new remote control password or
  543. // new hashed password -- in fact
  544. // it ends up clearing the new password fields.
  545. //
  546. pCfg->ClearNewRemoteControlPassword();
  547. Status = WBEM_NO_ERROR;
  548. end:
  549. return Status;
  550. }
  551. WBEMSTATUS
  552. NLB_EXTENDED_CLUSTER_CONFIGURATION::SetNetworkAddresses(
  553. IN LPCWSTR *pszNetworkAddresses,
  554. IN UINT NumNetworkAddresses
  555. )
  556. /*
  557. pszNetworkAddresses is an array of strings. These strings have the
  558. format "addr/subnet", eg: "10.0.0.1/255.0.0.0"
  559. */
  560. {
  561. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  562. NLB_IP_ADDRESS_INFO *pIpInfo = NULL;
  563. if (NumNetworkAddresses != 0)
  564. {
  565. UINT NumBad = 0;
  566. //
  567. // Allocate space for the new ip-address-info array
  568. //
  569. pIpInfo = new NLB_IP_ADDRESS_INFO[NumNetworkAddresses];
  570. if (pIpInfo == NULL)
  571. {
  572. TRACE_CRIT("%!FUNC!: Alloc failure!");
  573. Status = WBEM_E_OUT_OF_MEMORY;
  574. goto end;
  575. }
  576. ZeroMemory(pIpInfo, NumNetworkAddresses*sizeof(*pIpInfo));
  577. //
  578. // Convert IP addresses to our internal form.
  579. //
  580. for (UINT u=0;u<NumNetworkAddresses; u++)
  581. {
  582. //
  583. // We extrace each IP address and it's corresponding subnet mask
  584. // from the "addr/subnet" format insert it into a
  585. // NLB_IP_ADDRESS_INFO structure.
  586. //
  587. // SAMPLE: 10.0.0.1/255.0.0.0
  588. //
  589. LPCWSTR szAddr = pszNetworkAddresses[u];
  590. UINT uIpAddress = 0;
  591. //
  592. // If this is not a valid address, we skip it.
  593. //
  594. Status = CfgUtilsValidateNetworkAddress(
  595. szAddr,
  596. &uIpAddress,
  597. NULL,
  598. NULL
  599. );
  600. if (FAILED(Status))
  601. {
  602. TRACE_CRIT("%!FUNC!: Invalid ip or subnet: %ws", szAddr);
  603. NumBad++;
  604. continue;
  605. }
  606. ASSERT(u>=NumBad);
  607. Status = address_string_to_ip_and_subnet(
  608. szAddr,
  609. pIpInfo[u-NumBad].IpAddress,
  610. pIpInfo[u-NumBad].SubnetMask
  611. );
  612. if (FAILED(Status))
  613. {
  614. //
  615. // This one of the ip/subnet parms is too large.
  616. //
  617. TRACE_CRIT("%!FUNC!:ip or subnet part too large: %ws", szAddr);
  618. goto end;
  619. }
  620. }
  621. NumNetworkAddresses -= NumBad;
  622. if (NumNetworkAddresses == 0)
  623. {
  624. delete[] pIpInfo;
  625. pIpInfo = NULL;
  626. }
  627. }
  628. //
  629. // Replace the old ip-address-info with the new one
  630. //
  631. if (this->pIpAddressInfo != NULL)
  632. {
  633. delete this->pIpAddressInfo;
  634. this->pIpAddressInfo = NULL;
  635. }
  636. this->pIpAddressInfo = pIpInfo;
  637. pIpInfo = NULL;
  638. this->NumIpAddresses = NumNetworkAddresses;
  639. Status = WBEM_NO_ERROR;
  640. end:
  641. if (pIpInfo != NULL)
  642. {
  643. delete[] pIpInfo;
  644. }
  645. return Status;
  646. }
  647. WBEMSTATUS
  648. NLB_EXTENDED_CLUSTER_CONFIGURATION::GetNetworkAddresses(
  649. OUT LPWSTR **ppszNetworkAddresses, // free using delete
  650. OUT UINT *pNumNetworkAddresses
  651. )
  652. /*
  653. ppszNetworkAddresses is filled out on successful return to
  654. an array of strings. These strings have the
  655. format "addr/subnet", eg: "10.0.0.1/255.0.0.0"
  656. */
  657. {
  658. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  659. UINT AddrCount = this->NumIpAddresses;
  660. NLB_IP_ADDRESS_INFO *pIpInfo = this->pIpAddressInfo;
  661. LPWSTR *pszNetworkAddresses = NULL;
  662. if (AddrCount != 0)
  663. {
  664. //
  665. // Convert IP addresses from our internal form into
  666. // format "addr/subnet", eg: "10.0.0.1/255.0.0.0"
  667. //
  668. //
  669. const UINT cchLen = WLBS_MAX_CL_IP_ADDR // for IP address
  670. + WLBS_MAX_CL_NET_MASK // for subnet mask
  671. + 1; // for separating '/'
  672. pszNetworkAddresses = allocate_string_array(
  673. AddrCount,
  674. cchLen
  675. );
  676. if (pszNetworkAddresses == NULL)
  677. {
  678. TRACE_CRIT("%!FUNC!: Alloc failure!");
  679. Status = WBEM_E_OUT_OF_MEMORY;
  680. goto end;
  681. }
  682. for (UINT u=0;u<AddrCount; u++)
  683. {
  684. //
  685. // We extrace each IP address and it's corresponding subnet mask
  686. // insert them into a NLB_IP_ADDRESS_INFO
  687. // structure.
  688. //
  689. LPCWSTR pIpSrc = pIpInfo[u].IpAddress;
  690. LPCWSTR pSubSrc = pIpInfo[u].SubnetMask;
  691. LPWSTR szDest = pszNetworkAddresses[u];
  692. Status = ip_and_subnet_to_address_string(
  693. pIpSrc,
  694. pSubSrc,
  695. cchLen,
  696. szDest
  697. );
  698. if (FAILED(Status))
  699. {
  700. //
  701. // This would be an implementation error in get_multi_string_...
  702. //
  703. ASSERT(FALSE);
  704. Status = WBEM_E_CRITICAL_ERROR;
  705. goto end;
  706. }
  707. }
  708. }
  709. Status = WBEM_NO_ERROR;
  710. end:
  711. if (FAILED(Status))
  712. {
  713. if (pszNetworkAddresses != NULL)
  714. {
  715. delete pszNetworkAddresses;
  716. pszNetworkAddresses = NULL;
  717. }
  718. AddrCount = 0;
  719. }
  720. *ppszNetworkAddresses = pszNetworkAddresses;
  721. *pNumNetworkAddresses = AddrCount;
  722. return Status;
  723. }
  724. WBEMSTATUS
  725. NLB_EXTENDED_CLUSTER_CONFIGURATION::SetNetworkAddresPairs(
  726. IN LPCWSTR *pszIpAddresses,
  727. IN LPCWSTR *pszSubnetMasks,
  728. IN UINT NumNetworkAddresses
  729. )
  730. {
  731. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  732. goto end;
  733. end:
  734. return Status;
  735. }
  736. WBEMSTATUS
  737. NLB_EXTENDED_CLUSTER_CONFIGURATION::GetNetworkAddressPairs(
  738. OUT LPWSTR **ppszIpAddresses, // free using delete
  739. OUT LPWSTR **ppszIpSubnetMasks, // free using delete
  740. OUT UINT *pNumNetworkAddresses
  741. )
  742. {
  743. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  744. goto end;
  745. end:
  746. return Status;
  747. }
  748. WBEMSTATUS
  749. NLB_EXTENDED_CLUSTER_CONFIGURATION::GetPortRules(
  750. OUT LPWSTR **ppszPortRules,
  751. OUT UINT *pNumPortRules
  752. )
  753. {
  754. WLBS_PORT_RULE *pRules = NULL;
  755. UINT NumRules = 0;
  756. WBEMSTATUS Status;
  757. LPWSTR *pszPortRules = NULL;
  758. // DebugBreak();
  759. *ppszPortRules = NULL;
  760. *pNumPortRules = 0;
  761. Status = CfgUtilGetPortRules(
  762. &NlbParams,
  763. &pRules,
  764. &NumRules
  765. );
  766. if (FAILED(Status) || NumRules == 0)
  767. {
  768. pRules = NULL;
  769. goto end;
  770. }
  771. pszPortRules = CfgUtilsAllocateStringArray(
  772. NumRules,
  773. NLB_MAX_PORT_STRING_SIZE
  774. );
  775. if (pszPortRules == NULL)
  776. {
  777. Status = WBEM_E_OUT_OF_MEMORY;
  778. goto end;
  779. }
  780. //
  781. // Now convert from the binary to the string format.
  782. //
  783. for (UINT u = 0; u< NumRules; u++)
  784. {
  785. BOOL fRet;
  786. fRet = CfgUtilsGetPortRuleString(
  787. pRules+u,
  788. pszPortRules[u]
  789. );
  790. if (!fRet)
  791. {
  792. //
  793. // Must be a bad binary port rule!
  794. // For now, we just set the port rule to "".
  795. //
  796. *pszPortRules[u]=0;
  797. TRACE_INFO("%!FUNC!: Invalid port rule %lu", u);
  798. }
  799. }
  800. Status = WBEM_NO_ERROR;
  801. end:
  802. delete pRules;
  803. *pNumPortRules = NumRules;
  804. *ppszPortRules = pszPortRules;
  805. return Status;
  806. }
  807. WBEMSTATUS
  808. NLB_EXTENDED_CLUSTER_CONFIGURATION::SetPortRules(
  809. IN LPCWSTR *pszPortRules,
  810. IN UINT NumPortRules
  811. )
  812. {
  813. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  814. WLBS_PORT_RULE *pRules = NULL;
  815. // DebugBreak();
  816. if (NumPortRules!=0)
  817. {
  818. pRules = new WLBS_PORT_RULE[NumPortRules];
  819. if (pRules == NULL)
  820. {
  821. TRACE_CRIT("%!FUNC!: Allocation failure!");
  822. Status = WBEM_E_OUT_OF_MEMORY;
  823. goto end;
  824. }
  825. }
  826. //
  827. // Initialiez the binary form of the port rules.
  828. //
  829. for (UINT u=0; u < NumPortRules; u++)
  830. {
  831. LPCWSTR szRule = pszPortRules[u];
  832. BOOL fRet;
  833. fRet = CfgUtilsSetPortRuleString(
  834. szRule,
  835. pRules+u
  836. );
  837. if (fRet == FALSE)
  838. {
  839. Status = WBEM_E_INVALID_PARAMETER;
  840. goto end;
  841. }
  842. }
  843. Status = CfgUtilSetPortRules(
  844. pRules,
  845. NumPortRules,
  846. &NlbParams
  847. );
  848. end:
  849. delete[] pRules;
  850. return Status;
  851. }
  852. WBEMSTATUS
  853. NLB_EXTENDED_CLUSTER_CONFIGURATION::SetPortRulesSafeArray(
  854. IN SAFEARRAY *pSA
  855. )
  856. {
  857. return WBEM_E_CRITICAL_ERROR;
  858. }
  859. WBEMSTATUS
  860. NLB_EXTENDED_CLUSTER_CONFIGURATION::GetPortRulesSafeArray(
  861. OUT SAFEARRAY **ppSA
  862. )
  863. {
  864. return WBEM_E_CRITICAL_ERROR;
  865. }
  866. WBEMSTATUS
  867. NLB_EXTENDED_CLUSTER_CONFIGURATION::GetClusterNetworkAddress(
  868. OUT LPWSTR *pszAddress
  869. )
  870. /*
  871. allocate and return the cluster-ip and mask in address/subnet form.
  872. Eg: "10.0.0.1/255.0.0.0"
  873. */
  874. {
  875. WBEMSTATUS Status = WBEM_E_OUT_OF_MEMORY;
  876. LPWSTR szAddress = NULL;
  877. if (fValidNlbCfg)
  878. {
  879. szAddress = new WCHAR[NLBUPD_MAX_NETWORK_ADDRESS_LENGTH+1];
  880. if (szAddress != NULL)
  881. {
  882. Status = ip_and_subnet_to_address_string(
  883. NlbParams.cl_ip_addr,
  884. NlbParams.cl_net_mask,
  885. NLBUPD_MAX_NETWORK_ADDRESS_LENGTH+1,
  886. szAddress
  887. );
  888. if (FAILED(Status))
  889. {
  890. delete[] szAddress;
  891. szAddress = NULL;
  892. }
  893. }
  894. }
  895. *pszAddress = szAddress;
  896. return Status;
  897. }
  898. VOID
  899. NLB_EXTENDED_CLUSTER_CONFIGURATION::SetClusterNetworkAddress(
  900. IN LPCWSTR szAddress
  901. )
  902. {
  903. if (szAddress == NULL) szAddress = L"";
  904. (VOID) address_string_to_ip_and_subnet(
  905. szAddress,
  906. NlbParams.cl_ip_addr,
  907. NlbParams.cl_net_mask
  908. );
  909. }
  910. WBEMSTATUS
  911. NLB_EXTENDED_CLUSTER_CONFIGURATION::GetClusterName(
  912. OUT LPWSTR *pszName
  913. )
  914. /*
  915. allocate and return the cluster name
  916. */
  917. {
  918. WBEMSTATUS Status = WBEM_E_OUT_OF_MEMORY;
  919. LPWSTR szName = NULL;
  920. if (fValidNlbCfg)
  921. {
  922. UINT len = wcslen(NlbParams.domain_name);
  923. szName = new WCHAR[len+1]; // +1 for ending zero
  924. if (szName != NULL)
  925. {
  926. CopyMemory(szName, NlbParams.domain_name, (len+1)*sizeof(WCHAR));
  927. Status = WBEM_NO_ERROR;
  928. }
  929. }
  930. *pszName = szName;
  931. return Status;
  932. }
  933. VOID
  934. NLB_EXTENDED_CLUSTER_CONFIGURATION::SetClusterName(
  935. IN LPCWSTR szName
  936. )
  937. {
  938. if (szName == NULL) szName = L"";
  939. UINT len = wcslen(szName);
  940. if (len>WLBS_MAX_DOMAIN_NAME)
  941. {
  942. TRACE_CRIT("%!FUNC!: Cluster name too large");
  943. }
  944. CopyMemory(NlbParams.domain_name, szName, (len+1)*sizeof(WCHAR));
  945. }
  946. WBEMSTATUS
  947. NLB_EXTENDED_CLUSTER_CONFIGURATION::GetDedicatedNetworkAddress(
  948. OUT LPWSTR *pszAddress
  949. )
  950. {
  951. WBEMSTATUS Status = WBEM_E_OUT_OF_MEMORY;
  952. LPWSTR szAddress = NULL;
  953. if (fValidNlbCfg)
  954. {
  955. szAddress = new WCHAR[NLBUPD_MAX_NETWORK_ADDRESS_LENGTH+1];
  956. if (szAddress != NULL)
  957. {
  958. Status = ip_and_subnet_to_address_string(
  959. NlbParams.ded_ip_addr,
  960. NlbParams.ded_net_mask,
  961. NLBUPD_MAX_NETWORK_ADDRESS_LENGTH+1,
  962. szAddress
  963. );
  964. if (FAILED(Status))
  965. {
  966. delete[] szAddress;
  967. szAddress = NULL;
  968. }
  969. }
  970. }
  971. *pszAddress = szAddress;
  972. return Status;
  973. }
  974. VOID
  975. NLB_EXTENDED_CLUSTER_CONFIGURATION::SetDedicatedNetworkAddress(
  976. IN LPCWSTR szAddress
  977. )
  978. {
  979. if (szAddress == NULL || *szAddress == 0)
  980. {
  981. ARRAYSTRCPY(NlbParams.ded_ip_addr, CVY_DEF_DED_IP_ADDR);
  982. ARRAYSTRCPY(NlbParams.ded_net_mask, CVY_DEF_DED_NET_MASK);
  983. }
  984. else
  985. {
  986. (VOID) address_string_to_ip_and_subnet(
  987. szAddress,
  988. NlbParams.ded_ip_addr,
  989. NlbParams.ded_net_mask
  990. );
  991. }
  992. }
  993. NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE
  994. NLB_EXTENDED_CLUSTER_CONFIGURATION::GetTrafficMode(
  995. VOID
  996. ) const
  997. {
  998. TRAFFIC_MODE TrafficMode = TRAFFIC_MODE_UNICAST;
  999. if (NlbParams.mcast_support)
  1000. {
  1001. if (NlbParams.fIGMPSupport)
  1002. {
  1003. TrafficMode = TRAFFIC_MODE_IGMPMULTICAST;
  1004. }
  1005. else
  1006. {
  1007. TrafficMode = TRAFFIC_MODE_MULTICAST;
  1008. }
  1009. }
  1010. return TrafficMode;
  1011. }
  1012. VOID
  1013. NLB_EXTENDED_CLUSTER_CONFIGURATION::SetTrafficMode(
  1014. TRAFFIC_MODE Mode
  1015. )
  1016. {
  1017. switch(Mode)
  1018. {
  1019. case TRAFFIC_MODE_UNICAST:
  1020. NlbParams.mcast_support = 0;
  1021. NlbParams.fIGMPSupport = 0;
  1022. break;
  1023. case TRAFFIC_MODE_IGMPMULTICAST:
  1024. NlbParams.mcast_support = 1;
  1025. NlbParams.fIGMPSupport = 1;
  1026. break;
  1027. case TRAFFIC_MODE_MULTICAST:
  1028. NlbParams.mcast_support = 1;
  1029. NlbParams.fIGMPSupport = 0;
  1030. break;
  1031. default:
  1032. ASSERT(FALSE);
  1033. break;
  1034. }
  1035. }
  1036. UINT
  1037. NLB_EXTENDED_CLUSTER_CONFIGURATION::GetHostPriority(
  1038. VOID
  1039. )
  1040. {
  1041. return NlbParams.host_priority;
  1042. }
  1043. VOID
  1044. NLB_EXTENDED_CLUSTER_CONFIGURATION::SetHostPriority(
  1045. UINT Priority
  1046. )
  1047. {
  1048. NlbParams.host_priority = Priority;
  1049. }
  1050. //NLB_EXTENDED_CLUSTER_CONFIGURATION::START_MODE
  1051. DWORD
  1052. NLB_EXTENDED_CLUSTER_CONFIGURATION::GetClusterModeOnStart(
  1053. VOID
  1054. )
  1055. {
  1056. //
  1057. // If we decide to make cluster_mode something besides true/false we
  1058. // need to make the change here too...
  1059. //
  1060. /*
  1061. ASSERT(NlbParams.cluster_mode==TRUE || NlbParams.cluster_mode==FALSE);
  1062. if (NlbParams.cluster_mode)
  1063. {
  1064. return START_MODE_STARTED;
  1065. }
  1066. else
  1067. {
  1068. return START_MODE_STOPPED;
  1069. }
  1070. */
  1071. return NlbParams.cluster_mode;
  1072. }
  1073. VOID
  1074. NLB_EXTENDED_CLUSTER_CONFIGURATION::SetClusterModeOnStart(
  1075. // START_MODE Mode
  1076. DWORD Mode
  1077. )
  1078. {
  1079. /*
  1080. switch(Mode)
  1081. {
  1082. case START_MODE_STARTED:
  1083. NlbParams.cluster_mode = TRUE;
  1084. break;
  1085. case START_MODE_STOPPED:
  1086. NlbParams.cluster_mode = FALSE;
  1087. break;
  1088. default:
  1089. ASSERT(FALSE);
  1090. break;
  1091. }
  1092. */
  1093. NlbParams.cluster_mode = Mode;
  1094. }
  1095. BOOL
  1096. NLB_EXTENDED_CLUSTER_CONFIGURATION::GetPersistSuspendOnReboot(
  1097. VOID
  1098. )
  1099. {
  1100. // This is a straight lift from wmi\ClusterWrapper.cpp\GetNodeConfig()
  1101. // -KarthicN
  1102. return ((NlbParams.persisted_states & CVY_PERSIST_STATE_SUSPENDED) != 0);
  1103. }
  1104. VOID
  1105. NLB_EXTENDED_CLUSTER_CONFIGURATION::SetPersistSuspendOnReboot(
  1106. BOOL bPersistSuspendOnReboot
  1107. )
  1108. {
  1109. // This is a straight lift from wmi\ClusterWrapper.cpp\PutNodeConfig()
  1110. // -KarthicN
  1111. if (bPersistSuspendOnReboot)
  1112. {
  1113. NlbParams.persisted_states |= CVY_PERSIST_STATE_SUSPENDED;
  1114. }
  1115. else
  1116. {
  1117. NlbParams.persisted_states &= ~CVY_PERSIST_STATE_SUSPENDED;
  1118. }
  1119. }
  1120. BOOL
  1121. NLB_EXTENDED_CLUSTER_CONFIGURATION::GetRemoteControlEnabled(
  1122. VOID
  1123. ) const
  1124. {
  1125. return (NlbParams.rct_enabled!=FALSE);
  1126. }
  1127. VOID
  1128. NLB_EXTENDED_CLUSTER_CONFIGURATION::SetRemoteControlEnabled(
  1129. BOOL fEnabled
  1130. )
  1131. {
  1132. NlbParams.rct_enabled = (fEnabled!=FALSE);
  1133. }
  1134. WBEMSTATUS
  1135. NLB_EXTENDED_CLUSTER_CONFIGURATION::SetNetworkAddressesSafeArray(
  1136. IN SAFEARRAY *pSA
  1137. )
  1138. {
  1139. LPWSTR *pStrings=NULL;
  1140. UINT NumStrings = 0;
  1141. WBEMSTATUS Status;
  1142. Status = CfgUtilStringsFromSafeArray(
  1143. pSA,
  1144. &pStrings, // delete when done useing pStrings
  1145. &NumStrings
  1146. );
  1147. if (FAILED(Status))
  1148. {
  1149. pStrings=NULL;
  1150. goto end;
  1151. }
  1152. Status = this->SetNetworkAddresses(
  1153. (LPCWSTR*)pStrings,
  1154. NumStrings
  1155. );
  1156. if (pStrings != NULL)
  1157. {
  1158. delete pStrings;
  1159. }
  1160. end:
  1161. return Status;
  1162. }
  1163. WBEMSTATUS
  1164. NLB_EXTENDED_CLUSTER_CONFIGURATION::GetNetworkAddressesSafeArray(
  1165. OUT SAFEARRAY **ppSA
  1166. )
  1167. {
  1168. LPWSTR *pszNetworkAddresses = NULL;
  1169. UINT NumNetworkAddresses = 0;
  1170. SAFEARRAY *pSA=NULL;
  1171. WBEMSTATUS Status;
  1172. Status = this->GetNetworkAddresses(
  1173. &pszNetworkAddresses,
  1174. &NumNetworkAddresses
  1175. );
  1176. if (FAILED(Status))
  1177. {
  1178. pszNetworkAddresses = NULL;
  1179. goto end;
  1180. }
  1181. Status = CfgUtilSafeArrayFromStrings(
  1182. (LPCWSTR*) pszNetworkAddresses,
  1183. NumNetworkAddresses, // can be zero
  1184. &pSA
  1185. );
  1186. if (FAILED(Status))
  1187. {
  1188. pSA = NULL;
  1189. }
  1190. end:
  1191. *ppSA = pSA;
  1192. if (pszNetworkAddresses != NULL)
  1193. {
  1194. delete pszNetworkAddresses;
  1195. pszNetworkAddresses = NULL;
  1196. }
  1197. if (FAILED(Status))
  1198. {
  1199. TRACE_CRIT("%!FUNC!: couldn't extract network addresses from Cfg");
  1200. }
  1201. return Status;
  1202. }
  1203. LPWSTR *
  1204. allocate_string_array(
  1205. UINT NumStrings,
  1206. UINT MaxStringLen // excluding ending NULL
  1207. )
  1208. /*
  1209. Allocate a single chunk of memory using the new LPWSTR[] operator.
  1210. The first NumStrings LPWSTR values of this operator contain an array
  1211. of pointers to WCHAR strings. Each of these strings
  1212. is of size (MaxStringLen+1) WCHARS.
  1213. The rest of the memory contains the strings themselve.
  1214. Return NULL if NumStrings==0 or on allocation failure.
  1215. Each of the strings are initialized to be empty strings (first char is 0).
  1216. */
  1217. {
  1218. return CfgUtilsAllocateStringArray(NumStrings, MaxStringLen);
  1219. }
  1220. WBEMSTATUS
  1221. address_string_to_ip_and_subnet(
  1222. IN LPCWSTR szAddress,
  1223. OUT LPWSTR szIp, // max WLBS_MAX_CL_IP_ADDR including NULL
  1224. OUT LPWSTR szSubnet // max WLBS_MAX_CL_NET_MASK including NULL
  1225. )
  1226. // Special case: if szAddress == "", we zero out both szIp and szSubnet;
  1227. {
  1228. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  1229. if (*szAddress == 0) {szAddress = L"/";} // Special case mentioned above
  1230. // from the "addr/subnet" format insert it into a
  1231. // NLB_IP_ADDRESS_INFO structure.
  1232. //
  1233. // SAMPLE: 10.0.0.1/255.0.0.0
  1234. //
  1235. LPCWSTR pSlash = NULL;
  1236. LPCWSTR pSrcSub = NULL;
  1237. *szIp = 0;
  1238. *szSubnet = 0;
  1239. pSlash = wcsrchr(szAddress, (int) '/');
  1240. if (pSlash == NULL)
  1241. {
  1242. TRACE_CRIT("%!FUNC!:missing subnet portion in %ws", szAddress);
  1243. Status = WBEM_E_INVALID_PARAMETER;
  1244. goto end;
  1245. }
  1246. pSrcSub = pSlash+1;
  1247. UINT len = (UINT) (pSlash - szAddress);
  1248. UINT len1 = wcslen(pSrcSub);
  1249. if ( (len < WLBS_MAX_CL_IP_ADDR) && (len1 < WLBS_MAX_CL_NET_MASK))
  1250. {
  1251. CopyMemory(szIp, szAddress, len*sizeof(WCHAR));
  1252. szIp[len] = 0;
  1253. CopyMemory(szSubnet, pSrcSub, (len1+1)*sizeof(WCHAR));
  1254. }
  1255. else
  1256. {
  1257. //
  1258. // One of the ip/subnet parms is too large.
  1259. //
  1260. TRACE_CRIT("%!FUNC!:ip or subnet part too large: %ws", szAddress);
  1261. Status = WBEM_E_INVALID_PARAMETER;
  1262. goto end;
  1263. }
  1264. Status = WBEM_NO_ERROR;
  1265. end:
  1266. return Status;
  1267. }
  1268. WBEMSTATUS
  1269. ip_and_subnet_to_address_string(
  1270. IN LPCWSTR szIp,
  1271. IN LPCWSTR szSubnet,
  1272. IN UINT cchAddress,
  1273. OUT LPWSTR szAddress// max WLBS_MAX_CL_IP_ADDR
  1274. // + 1(for slash) + WLBS_MAX_CL_NET_MASK + 1 (for NULL)
  1275. )
  1276. {
  1277. WBEMSTATUS Status = WBEM_E_INVALID_PARAMETER;
  1278. UINT len = wcslen(szIp)+wcslen(szSubnet) + 1; // +1 for separating '/'
  1279. if (len >= NLBUPD_MAX_NETWORK_ADDRESS_LENGTH)
  1280. {
  1281. goto end;
  1282. }
  1283. else
  1284. {
  1285. HRESULT hr;
  1286. hr = StringCchPrintf(
  1287. szAddress,
  1288. cchAddress,
  1289. L"%ws/%ws",
  1290. szIp,
  1291. szSubnet
  1292. );
  1293. if (hr == S_OK)
  1294. {
  1295. Status = WBEM_NO_ERROR;
  1296. }
  1297. else
  1298. {
  1299. Status = WBEM_E_INVALID_PARAMETER;
  1300. }
  1301. }
  1302. end:
  1303. return Status;
  1304. }
  1305. WBEMSTATUS
  1306. NLB_EXTENDED_CLUSTER_CONFIGURATION::GetFriendlyName(
  1307. OUT LPWSTR *pszFriendlyName // Free using delete
  1308. ) const
  1309. {
  1310. WBEMSTATUS Status = WBEM_E_NOT_FOUND;
  1311. LPWSTR szName = NULL;
  1312. *pszFriendlyName = NULL;
  1313. if (m_szFriendlyName != NULL)
  1314. {
  1315. UINT len = wcslen(m_szFriendlyName);
  1316. szName = new WCHAR[len+1]; // +1 for ending 0
  1317. if (szName == NULL)
  1318. {
  1319. Status = WBEM_E_OUT_OF_MEMORY;
  1320. }
  1321. else
  1322. {
  1323. Status = WBEM_NO_ERROR;
  1324. CopyMemory(szName, m_szFriendlyName, (len+1)*sizeof(WCHAR));
  1325. }
  1326. }
  1327. *pszFriendlyName = szName;
  1328. return Status;
  1329. }
  1330. WBEMSTATUS
  1331. NLB_EXTENDED_CLUSTER_CONFIGURATION::SetFriendlyName(
  1332. IN LPCWSTR szFriendlyName // Saves a copy of szFriendlyName
  1333. )
  1334. {
  1335. WBEMSTATUS Status = WBEM_E_OUT_OF_MEMORY;
  1336. LPWSTR szName = NULL;
  1337. if (szFriendlyName != NULL)
  1338. {
  1339. UINT len = wcslen(szFriendlyName);
  1340. szName = new WCHAR[len+1]; // +1 for ending 0
  1341. if (szName == NULL)
  1342. {
  1343. goto end;
  1344. }
  1345. else
  1346. {
  1347. CopyMemory(szName, szFriendlyName, (len+1)*sizeof(WCHAR));
  1348. }
  1349. }
  1350. Status = WBEM_NO_ERROR;
  1351. if (m_szFriendlyName != NULL)
  1352. {
  1353. delete m_szFriendlyName;
  1354. m_szFriendlyName = NULL;
  1355. }
  1356. m_szFriendlyName = szName;
  1357. end:
  1358. return Status;
  1359. }
  1360. WBEMSTATUS
  1361. NLB_EXTENDED_CLUSTER_CONFIGURATION::SetNewRemoteControlPassword(
  1362. IN LPCWSTR szRemoteControlPassword // Saves a copy of szRemoteControlPassword
  1363. )
  1364. {
  1365. WBEMSTATUS Status = WBEM_E_OUT_OF_MEMORY;
  1366. LPWSTR szName = NULL;
  1367. if (szRemoteControlPassword != NULL)
  1368. {
  1369. UINT len = wcslen(szRemoteControlPassword);
  1370. szName = new WCHAR[len+1]; // +1 for ending 0
  1371. if (szName == NULL)
  1372. {
  1373. goto end;
  1374. }
  1375. else
  1376. {
  1377. CopyMemory(szName, szRemoteControlPassword, (len+1)*sizeof(WCHAR));
  1378. }
  1379. m_fSetPassword = TRUE;
  1380. }
  1381. else
  1382. {
  1383. m_fSetPassword = FALSE;
  1384. }
  1385. Status = WBEM_NO_ERROR;
  1386. if (m_szNewRemoteControlPassword != NULL)
  1387. {
  1388. delete m_szNewRemoteControlPassword;
  1389. m_szNewRemoteControlPassword = NULL;
  1390. }
  1391. m_szNewRemoteControlPassword = szName;
  1392. end:
  1393. return Status;
  1394. }
  1395. WBEMSTATUS
  1396. NLB_EXTENDED_CLUSTER_CONFIGURATION::
  1397. ModifyNetworkAddress(
  1398. IN LPCWSTR szOldIpAddress, OPTIONAL // network order
  1399. IN LPCWSTR szNewIpAddress, OPTIONAL
  1400. IN LPCWSTR szNewSubnetMask OPTIONAL
  1401. )
  1402. //
  1403. // NULL, NULL: clear all network addresses
  1404. // NULL, szNew: add
  1405. // szOld, NULL: remove
  1406. // szOld, szNew: replace (or add, if old doesn't exist)
  1407. //
  1408. {
  1409. WBEMSTATUS Status = WBEM_E_INVALID_PARAMETER;
  1410. BOOL fRet;
  1411. NlbIpAddressList IpList;
  1412. fRet = IpList.Set(this->NumIpAddresses, this->pIpAddressInfo, 0);
  1413. if (fRet)
  1414. {
  1415. fRet = IpList.Modify(
  1416. szOldIpAddress,
  1417. szNewIpAddress,
  1418. szNewSubnetMask
  1419. );
  1420. }
  1421. if (fRet)
  1422. {
  1423. this->SetNetworkAddressesRaw(NULL,0);
  1424. IpList.Extract(REF this->NumIpAddresses, REF this->pIpAddressInfo);
  1425. Status = WBEM_NO_ERROR;
  1426. }
  1427. else
  1428. {
  1429. Status = WBEM_E_INVALID_PARAMETER;
  1430. }
  1431. return Status;
  1432. }
  1433. BOOL
  1434. NLB_EXTENDED_CLUSTER_CONFIGURATION::
  1435. IsBlankDedicatedIp(
  1436. VOID
  1437. ) const
  1438. //
  1439. // Dedicated IP is either the empty string or all zeros.
  1440. //
  1441. {
  1442. return (NlbParams.ded_ip_addr[0]==0)
  1443. || (_wcsspnp(NlbParams.ded_ip_addr, L".0")==NULL);
  1444. }
  1445. const NLB_IP_ADDRESS_INFO *
  1446. NlbIpAddressList::Find(
  1447. LPCWSTR szIp // IF NULL, returns first address
  1448. ) const
  1449. //
  1450. // Looks for the specified IP address -- returns an internal pointer
  1451. // to the found IP address info, if fount, otherwise NULL.
  1452. //
  1453. {
  1454. const NLB_IP_ADDRESS_INFO *pInfo = NULL;
  1455. if (szIp == NULL)
  1456. {
  1457. //
  1458. // return the first if there is one, else NULL.
  1459. //
  1460. if (m_uNum != 0)
  1461. {
  1462. pInfo = m_pIpInfo;
  1463. }
  1464. }
  1465. else
  1466. {
  1467. pInfo = find_ip_in_ipinfo(szIp, m_pIpInfo, m_uNum);
  1468. }
  1469. return pInfo;
  1470. }
  1471. BOOL
  1472. NlbIpAddressList::Copy(const NlbIpAddressList &refList)
  1473. {
  1474. BOOL fRet;
  1475. fRet = this->Set(refList.m_uNum, refList.m_pIpInfo, 0);
  1476. return fRet;
  1477. }
  1478. BOOL
  1479. NlbIpAddressList::Validate(void)
  1480. // checks that there are no dups and all valid ip/subnets
  1481. {
  1482. BOOL fRet = FALSE;
  1483. NLB_IP_ADDRESS_INFO *pInfo = m_pIpInfo;
  1484. UINT uNum = m_uNum;
  1485. for (UINT u = 0; u<uNum; u++)
  1486. {
  1487. UINT uIpAddress = 0;
  1488. fRet = sfn_validate_info(REF pInfo[u], REF uIpAddress);
  1489. if (!fRet) break;
  1490. }
  1491. return fRet;
  1492. }
  1493. BOOL
  1494. NlbIpAddressList::Set(
  1495. UINT uNew,
  1496. const NLB_IP_ADDRESS_INFO *pNewInfo,
  1497. UINT uExtraCount
  1498. )
  1499. /*
  1500. Sets internal list to a copy of pNewInfo. Reallocates list if required.
  1501. Reserves uExtraCount empty locations (perhaps more if it kept the old
  1502. internal list)
  1503. */
  1504. {
  1505. BOOL fRet = FALSE;
  1506. UINT uMax = uNew+uExtraCount;
  1507. NLB_IP_ADDRESS_INFO *pInfo = NULL;
  1508. // printf("-> set(%lu, %p, %lu): m_uNum=%lu m_uMax=%lu m_pIpInfo=0x%p\n",
  1509. // uNew, pNewInfo, uExtraCount,
  1510. // m_uNum, m_uMax, m_pIpInfo);
  1511. if (uMax > m_uMax)
  1512. {
  1513. //
  1514. // We'll re-allocate to get more space.
  1515. //
  1516. pInfo = new NLB_IP_ADDRESS_INFO[uMax];
  1517. if (pInfo == NULL)
  1518. {
  1519. TRACE_CRIT("%!FUNC! allocation failure");
  1520. goto end;
  1521. }
  1522. }
  1523. else
  1524. {
  1525. //
  1526. // The current m_pIpInfo is large enough; we'll keep it.
  1527. //
  1528. pInfo = m_pIpInfo;
  1529. uMax = m_uMax;
  1530. }
  1531. if (uNew != 0)
  1532. {
  1533. if (pNewInfo == pInfo)
  1534. {
  1535. // Caller has passed m_pInfo as pNewInfo.
  1536. // No need to copy.
  1537. }
  1538. else
  1539. {
  1540. //
  1541. // MoveMemory can deal with overlapping regions.
  1542. //
  1543. MoveMemory(pInfo, pNewInfo, sizeof(NLB_IP_ADDRESS_INFO)*uNew);
  1544. }
  1545. }
  1546. if (uMax > uNew)
  1547. {
  1548. //
  1549. // Zero out the empty space.
  1550. //
  1551. ZeroMemory(pInfo+uNew, sizeof(NLB_IP_ADDRESS_INFO)*(uMax-uNew));
  1552. }
  1553. m_uNum = uNew;
  1554. m_uMax = uMax;
  1555. if (m_pIpInfo != pInfo)
  1556. {
  1557. delete[] m_pIpInfo;
  1558. m_pIpInfo = pInfo;
  1559. }
  1560. fRet = TRUE;
  1561. end:
  1562. // printf("<- set: fRet=%lu, m_uNum=%lu m_uMax=%lu m_pIpInfo=0x%p\n",
  1563. // fRet, m_uNum, m_uMax, m_pIpInfo);
  1564. return fRet;
  1565. }
  1566. VOID
  1567. NlbIpAddressList::Extract(UINT &uNum, NLB_IP_ADDRESS_INFO * &pNewInfo)
  1568. /*
  1569. Sets pNewInfo to the ip list (not a copy) and sets the internal list to
  1570. null. Free using delete[].
  1571. */
  1572. {
  1573. uNum = m_uNum;
  1574. pNewInfo = m_pIpInfo;
  1575. m_uNum=0;
  1576. m_uMax=0;
  1577. m_pIpInfo = NULL;
  1578. }
  1579. static
  1580. VOID
  1581. uint_to_szipaddr(
  1582. UINT uIpAddress, // Ip address or subnet -- no validation, network order
  1583. UINT cchLen, // length of rgAddress, incluing space for NULL
  1584. WCHAR *rgAddress // Expected to be at least 17 chars long
  1585. )
  1586. {
  1587. BYTE *pb = (BYTE*) &uIpAddress;
  1588. StringCchPrintf(rgAddress, cchLen, L"%lu.%lu.%lu.%lu", pb[0], pb[1], pb[2], pb[3]);
  1589. }
  1590. BOOL
  1591. NlbIpAddressList::Modify(
  1592. LPCWSTR szOldIp,
  1593. LPCWSTR szNewIp,
  1594. LPCWSTR szNewSubnet
  1595. )
  1596. //
  1597. // NULL, NULL, -: clear all network addresses
  1598. // NULL, szNew, -: add
  1599. // szOld, NULL, -: remove
  1600. // szOld, szNew, -: remove szOld if found; add or replace szNew.
  1601. //
  1602. {
  1603. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  1604. BOOL fRet = FALSE;
  1605. UINT uFoundOldOffset = 0;
  1606. BOOL fFoundOldAddress = FALSE;
  1607. // printf("-> modify: m_uNum=%lu m_uMax=%lu m_pIpInfo=0x%p\n",
  1608. // m_uNum, m_uMax, m_pIpInfo);
  1609. if (szOldIp==NULL && szNewIp==NULL)
  1610. {
  1611. this->Clear();
  1612. fRet = TRUE;
  1613. goto end;
  1614. }
  1615. if (szOldIp != NULL && szNewIp != NULL)
  1616. {
  1617. //
  1618. // Both szOld and szNew are specified.
  1619. // We'll first call ourselves recursively to remove szNewIp, if
  1620. // it exists. Later on below we'll replace szOldIp with szNewIp
  1621. // if szOldIp exists (i.e. at the same LOCATION of szOldIp), or
  1622. // add it to the beginning if szOldIp doesn't exist.
  1623. //
  1624. (void) this->Modify(szNewIp, NULL, NULL);
  1625. }
  1626. if (szOldIp == NULL)
  1627. {
  1628. szOldIp = szNewIp; // so we don't add dups.
  1629. }
  1630. if (szOldIp != NULL)
  1631. {
  1632. const NLB_IP_ADDRESS_INFO *pFoundInfo = NULL;
  1633. pFoundInfo = find_ip_in_ipinfo(szOldIp, m_pIpInfo, m_uNum);
  1634. if(pFoundInfo != NULL)
  1635. {
  1636. uFoundOldOffset = (ULONG) (UINT_PTR) (pFoundInfo-m_pIpInfo);
  1637. fFoundOldAddress = TRUE;
  1638. }
  1639. }
  1640. if (szNewIp == NULL)
  1641. {
  1642. //
  1643. // Remove old Ip address
  1644. //
  1645. if (!fFoundOldAddress)
  1646. {
  1647. //
  1648. // Old one not found
  1649. //
  1650. fRet = FALSE;
  1651. goto end;
  1652. }
  1653. //
  1654. // We bump up everything beyond this one
  1655. //
  1656. m_uNum--; // that this was at least 1 because we found the old
  1657. for (UINT u=uFoundOldOffset; u<m_uNum; u++)
  1658. {
  1659. m_pIpInfo[u] = m_pIpInfo[u+1]; // struct copy.
  1660. }
  1661. //
  1662. // Zero out the last (vacated) element.
  1663. //
  1664. ZeroMemory(&m_pIpInfo[m_uNum], sizeof(*m_pIpInfo));
  1665. }
  1666. else
  1667. {
  1668. UINT uNewIpAddress=0;
  1669. UINT uNewSubnetMask=0;
  1670. NLB_IP_ADDRESS_INFO NewIpInfo;
  1671. ZeroMemory(&NewIpInfo, sizeof(NewIpInfo));
  1672. Status = CfgUtilsValidateNetworkAddress(
  1673. szNewIp,
  1674. &uNewIpAddress,
  1675. NULL,
  1676. NULL
  1677. );
  1678. if (!FAILED(Status))
  1679. {
  1680. Status = CfgUtilsValidateNetworkAddress(
  1681. szNewSubnet,
  1682. &uNewSubnetMask,
  1683. NULL,
  1684. NULL
  1685. );
  1686. }
  1687. if (FAILED(Status))
  1688. {
  1689. //
  1690. // Invalid ip address.
  1691. //
  1692. TRACE_CRIT("%!FUNC!:ip or subnet part too large: %ws/%ws",
  1693. szNewIp, szNewSubnet);
  1694. fRet = FALSE;
  1695. goto end;
  1696. }
  1697. //
  1698. // Convert into the IP_ADDRESS_INFO format.
  1699. // Here we also convert to standard dotted notation.
  1700. //
  1701. uint_to_szipaddr(uNewIpAddress, ASIZE(NewIpInfo.IpAddress), NewIpInfo.IpAddress);
  1702. uint_to_szipaddr(uNewSubnetMask, ASIZE(NewIpInfo.SubnetMask), NewIpInfo.SubnetMask);
  1703. if (fFoundOldAddress == TRUE)
  1704. {
  1705. //
  1706. // Replace the old one.
  1707. //
  1708. m_pIpInfo[uFoundOldOffset] = NewIpInfo; // struct copy.
  1709. }
  1710. else
  1711. {
  1712. //
  1713. // Well add the new ip info to the head of the list.
  1714. //
  1715. if (m_uNum == m_uMax)
  1716. {
  1717. //
  1718. // We need to allocate more space.
  1719. // We somewhat arbitrarily reserve 2 spots
  1720. // NOTE: this will cause a change in the value of
  1721. // m_pIpInfo, m_uNum and m_uMax.
  1722. //
  1723. fRet = this->Set(m_uNum, m_pIpInfo, 2);
  1724. if (!fRet)
  1725. {
  1726. goto end;
  1727. }
  1728. }
  1729. //
  1730. // Move existing stuff one place down, to make place for the
  1731. // new one.
  1732. //
  1733. if (m_uNum >= m_uMax)
  1734. {
  1735. // Ahem, should never get here because we just added
  1736. // two extra spaces above.
  1737. fRet = FALSE;
  1738. goto end;
  1739. }
  1740. if (m_uNum)
  1741. {
  1742. // Note the regions overlap -- MoveMemory can handle this.
  1743. //
  1744. MoveMemory(m_pIpInfo+1, m_pIpInfo, m_uNum*sizeof(*m_pIpInfo));
  1745. }
  1746. //
  1747. // Add a new one -- we'll add it to the beginning.
  1748. //
  1749. m_pIpInfo[0] = NewIpInfo; // struct copy.
  1750. m_uNum++;
  1751. }
  1752. }
  1753. fRet = TRUE;
  1754. end:
  1755. // printf("<- modify: fRet=%lu, m_uNum=%lu m_uMax=%lu m_pIpInfo=0x%p\n",
  1756. // fRet, m_uNum, m_uMax, m_pIpInfo);
  1757. return fRet;
  1758. }
  1759. BOOL
  1760. NlbIpAddressList::sfn_validate_info(
  1761. const NLB_IP_ADDRESS_INFO &Info,
  1762. UINT &uIpAddress
  1763. )
  1764. {
  1765. WBEMSTATUS Status;
  1766. UINT uSubnetMask = 0;
  1767. Status = CfgUtilsValidateNetworkAddress(
  1768. Info.IpAddress,
  1769. &uIpAddress,
  1770. NULL,
  1771. NULL
  1772. );
  1773. if (!FAILED(Status))
  1774. {
  1775. Status = CfgUtilsValidateNetworkAddress(
  1776. Info.SubnetMask,
  1777. &uSubnetMask,
  1778. NULL,
  1779. NULL
  1780. );
  1781. }
  1782. return (!FAILED(Status));
  1783. }
  1784. UINT *
  1785. ipaddresses_from_ipaddressinfo(
  1786. const NLB_IP_ADDRESS_INFO *pInfo,
  1787. UINT NumAddresses
  1788. )
  1789. /*
  1790. Free return value using "delete" operator.
  1791. */
  1792. {
  1793. UINT *rgOut = NULL;
  1794. if (NumAddresses == 0) goto end;
  1795. //
  1796. // Allocate space.
  1797. //
  1798. rgOut = new UINT[NumAddresses];
  1799. if (rgOut==NULL) goto end;
  1800. //
  1801. // Validate each address, thereby getting the ip address info.
  1802. //
  1803. for (UINT *pOut = rgOut; NumAddresses--; pOut++, pInfo++)
  1804. {
  1805. WBEMSTATUS wStat;
  1806. wStat = CfgUtilsValidateNetworkAddress(
  1807. pInfo->IpAddress,
  1808. pOut,
  1809. NULL,
  1810. NULL
  1811. );
  1812. if (FAILED(wStat))
  1813. {
  1814. TRACE_CRIT("%!FUNC! -- Validate address \"%ws\" failed!\n",
  1815. pInfo->IpAddress);
  1816. delete[] rgOut;
  1817. rgOut = NULL;
  1818. goto end;
  1819. }
  1820. }
  1821. end:
  1822. return rgOut;
  1823. }
  1824. BOOL
  1825. NlbIpAddressList::Apply(UINT NumNew, const NLB_IP_ADDRESS_INFO *pNewInfo)
  1826. /*
  1827. Set our internal list to be a permutation of the ip addresses in pInfo.
  1828. The permutation attempts to minimize the differences between the
  1829. new and the current version: basically the relative order of any adresses
  1830. that remain in new is preserved, and any new addresses are tacked on at
  1831. the end.
  1832. */
  1833. {
  1834. BOOL fRet = FALSE;
  1835. UINT *rgOldIps = NULL;
  1836. UINT *rgNewIps = NULL;
  1837. NLB_IP_ADDRESS_INFO *rgNewInfo = NULL;
  1838. UINT NumFilled = 0;
  1839. UINT NumOld = m_uNum;
  1840. if (NumNew == 0)
  1841. {
  1842. this->Clear();
  1843. fRet = TRUE;
  1844. goto end;
  1845. }
  1846. if (NumOld!=0)
  1847. {
  1848. rgOldIps = ipaddresses_from_ipaddressinfo(
  1849. m_pIpInfo,
  1850. m_uNum
  1851. );
  1852. if (rgOldIps == NULL) goto end;
  1853. }
  1854. rgNewIps = ipaddresses_from_ipaddressinfo(
  1855. pNewInfo,
  1856. NumNew
  1857. );
  1858. if (rgNewIps==NULL) goto end;
  1859. rgNewInfo = new NLB_IP_ADDRESS_INFO[NumNew];
  1860. if (rgNewInfo == NULL)
  1861. {
  1862. TRACE_CRIT("%!FUNC! allocation failure!");
  1863. goto end;
  1864. }
  1865. //
  1866. // We try to preserve our current order of IP addresses
  1867. // as far as possible. To do this, we go through each ip address
  1868. // in our list in order -- if we find it in the new list, we
  1869. // add it to our new copy -- thereby preserving the order of all
  1870. // old IP addresses that are still present in the new list.
  1871. //
  1872. {
  1873. for (UINT uOld = 0; uOld < NumOld; uOld++)
  1874. {
  1875. UINT uOldIp = rgOldIps[uOld];
  1876. //
  1877. // See if it exists in new version -- if so add to new
  1878. //
  1879. for (UINT uNew=0; uNew<NumNew; uNew++)
  1880. {
  1881. if (uOldIp == rgNewIps[uNew])
  1882. {
  1883. // yes it's still present, keep it.
  1884. if (NumFilled<NumNew)
  1885. {
  1886. rgNewInfo[NumFilled]
  1887. = pNewInfo[uNew]; // struct copy
  1888. NumFilled++;
  1889. rgNewIps[uNew] = 0; // we use this later.
  1890. }
  1891. else
  1892. {
  1893. TRACE_CRIT("%!FUNC! Out of new addresses!");
  1894. fRet = FALSE;
  1895. goto end;
  1896. }
  1897. }
  1898. }
  1899. }
  1900. }
  1901. //
  1902. // Now tack on any cluster IP addresses not already added on.
  1903. //
  1904. {
  1905. //
  1906. // See if it exists in cluster version -- if so add to new
  1907. //
  1908. for (UINT uNew=0; uNew<NumNew; uNew++)
  1909. {
  1910. if (rgNewIps[uNew] != 0)
  1911. {
  1912. //
  1913. // yes it's a new cluster IP -- add it...
  1914. // (remember we set rgClusterIps[uCluster] to zero
  1915. // in the previous block, if we copied it over.
  1916. //
  1917. if (NumFilled<NumNew)
  1918. {
  1919. rgNewInfo[NumFilled]
  1920. = pNewInfo[uNew]; // struct copy
  1921. NumFilled++;
  1922. }
  1923. else
  1924. {
  1925. TRACE_CRIT("%!FUNC! Out of new addresses!");
  1926. fRet = FALSE;
  1927. goto end;
  1928. }
  1929. }
  1930. }
  1931. }
  1932. //
  1933. // At this point, we should have filled up all of the allocated space.
  1934. //
  1935. if (NumFilled != NumNew)
  1936. {
  1937. TRACE_CRIT("%!FUNC! NumNewAddressesFilled != NumNewAddresses!");
  1938. fRet = FALSE;
  1939. goto end;
  1940. }
  1941. //
  1942. // Now update our internal list.
  1943. //
  1944. delete[] m_pIpInfo;
  1945. m_pIpInfo = rgNewInfo;
  1946. m_uNum = m_uMax = NumNew;
  1947. rgNewInfo = NULL; // so it doesn't get deleted below.
  1948. fRet = TRUE;
  1949. end:
  1950. delete[] rgOldIps;
  1951. delete[] rgNewIps;
  1952. delete[] rgNewInfo;
  1953. return fRet;
  1954. }
  1955. const NLB_IP_ADDRESS_INFO *
  1956. find_ip_in_ipinfo(
  1957. LPCWSTR szIpToFind,
  1958. const NLB_IP_ADDRESS_INFO *pIpInfo,
  1959. UINT NumIpInfos
  1960. )
  1961. {
  1962. UINT uIpAddressToFind = 0;
  1963. UINT uIpAddress=0;
  1964. const NLB_IP_ADDRESS_INFO *pInfo = NULL;
  1965. WBEMSTATUS Status;
  1966. Status = CfgUtilsValidateNetworkAddress(
  1967. szIpToFind,
  1968. &uIpAddressToFind,
  1969. NULL,
  1970. NULL
  1971. );
  1972. if (Status == WBEM_NO_ERROR)
  1973. {
  1974. // Find location of old network address
  1975. for (UINT u=0; u<NumIpInfos; u++)
  1976. {
  1977. Status = CfgUtilsValidateNetworkAddress(
  1978. pIpInfo[u].IpAddress,
  1979. &uIpAddress,
  1980. NULL,
  1981. NULL
  1982. );
  1983. if (Status == WBEM_NO_ERROR)
  1984. {
  1985. if (uIpAddressToFind == uIpAddress)
  1986. {
  1987. // found it.
  1988. pInfo = &pIpInfo[u];
  1989. break;
  1990. }
  1991. }
  1992. }
  1993. }
  1994. return pInfo;
  1995. }