Source code of Windows XP (NT5)
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.

8960 lines
246 KiB

  1. /*++
  2. Copyright (c) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. mcast.c
  5. Abstract:
  6. Implements the Node Manager's network multicast management routines.
  7. Author:
  8. David Dion (daviddio) 15-Mar-2001
  9. Revision History:
  10. --*/
  11. #include "nmp.h"
  12. #include <align.h>
  13. /////////////////////////////////////////////////////////////////////////////
  14. //
  15. // Constants
  16. //
  17. /////////////////////////////////////////////////////////////////////////////
  18. //
  19. // Multicast configuration types.
  20. // - Manual: administrator configured address
  21. // - Madcap: lease obtained from MADCAP server
  22. // - Auto: address chosen after no MADCAP server detected
  23. //
  24. typedef enum {
  25. NmMcastConfigManual = 0,
  26. NmMcastConfigMadcap,
  27. NmMcastConfigAuto
  28. } NM_MCAST_CONFIG, *PNM_MCAST_CONFIG;
  29. //
  30. // Lease status.
  31. //
  32. typedef enum {
  33. NmMcastLeaseValid = 0,
  34. NmMcastLeaseNeedsRenewal,
  35. NmMcastLeaseExpired
  36. } NM_MCAST_LEASE_STATUS, *PNM_MCAST_LEASE_STATUS;
  37. #define CLUSREG_NAME_CLUSTER_DISABLE_MULTICAST L"MulticastClusterDisable"
  38. #define CLUSREG_NAME_NET_MULTICAST_ADDRESS L"MulticastAddress"
  39. #define CLUSREG_NAME_NET_DISABLE_MULTICAST L"MulticastDisable"
  40. #define CLUSREG_NAME_NET_MULTICAST_KEY_SALT L"MulticastSalt"
  41. #define CLUSREG_NAME_NET_MCAST_LEASE_OBTAINED L"MulticastLeaseObtained"
  42. #define CLUSREG_NAME_NET_MCAST_LEASE_EXPIRES L"MulticastLeaseExpires"
  43. #define CLUSREG_NAME_NET_MCAST_REQUEST_ID L"MulticastRequestId"
  44. #define CLUSREG_NAME_NET_MCAST_SERVER_ADDRESS L"MulticastLeaseServer"
  45. #define CLUSREG_NAME_NET_MCAST_CONFIG_TYPE L"MulticastConfigType"
  46. #define CLUSREG_NAME_NET_MCAST_RANGE_LOWER L"MulticastAddressRangeLower"
  47. #define CLUSREG_NAME_NET_MCAST_RANGE_UPPER L"MulticastAddressRangeUpper"
  48. #define NMP_MCAST_DISABLED_DEFAULT 0 // NOT disabled
  49. #define NMP_SINGLE_SOURCE_SCOPE_ADDRESS 0x000000E8 // (232.*.*.*)
  50. #define NMP_SINGLE_SOURCE_SCOPE_MASK 0x000000FF // (255.0.0.0)
  51. #define NMP_LOCAL_SCOPE_ADDRESS 0x0000FFEF // (239.255.*.*)
  52. #define NMP_LOCAL_SCOPE_MASK 0x0000FFFF // (255.255.*.*)
  53. #define NMP_ORG_SCOPE_ADDRESS 0x0000C0EF // (239.192.*.*)
  54. #define NMP_ORG_SCOPE_MASK 0x0000FCFF // (255.63.*.*)
  55. #define NMP_MCAST_DEFAULT_RANGE_LOWER 0x0000FFEF // (239.255.0.0)
  56. #define NMP_MCAST_DEFAULT_RANGE_UPPER 0xFFFEFFEF // (239.255.254.255)
  57. #define NMP_MCAST_LEASE_RENEWAL_THRESHOLD 300 // 5 minutes
  58. #define NMP_MCAST_LEASE_RENEWAL_WINDOW 1800 // 30 minutes
  59. #define NMP_MADCAP_REQUERY_PERDIOD 3600 * 24 // 1 day
  60. #define NMP_MCAST_CONFIG_STABILITY_DELAY 5 * 1000 // 5 seconds
  61. #define NMP_MANUAL_DEFAULT_WAIT_INTERVAL 60 * 1000 // 2 minutes
  62. //
  63. // Minimum cluster node count in which to run multicast
  64. //
  65. #define NMP_MCAST_MIN_CLUSTER_NODE_COUNT 3
  66. //
  67. // MADCAP lease request/response buffer sizes. These sizes are based on
  68. // IPv4 addresses.
  69. //
  70. #define NMP_MADCAP_REQUEST_BUFFER_SIZE \
  71. (ROUND_UP_COUNT(sizeof(MCAST_LEASE_REQUEST),TYPE_ALIGNMENT(DWORD)) + \
  72. sizeof(DWORD))
  73. #define NMP_MADCAP_REQUEST_ADDR_OFFSET \
  74. (ROUND_UP_COUNT(sizeof(MCAST_LEASE_REQUEST),TYPE_ALIGNMENT(DWORD)))
  75. #define NMP_MADCAP_RESPONSE_BUFFER_SIZE \
  76. (ROUND_UP_COUNT(sizeof(MCAST_LEASE_RESPONSE),TYPE_ALIGNMENT(DWORD)) + \
  77. sizeof(DWORD))
  78. #define NMP_MADCAP_RESPONSE_ADDR_OFFSET \
  79. (ROUND_UP_COUNT(sizeof(MCAST_LEASE_RESPONSE),TYPE_ALIGNMENT(DWORD)))
  80. //
  81. // MADCAP lease times are in seconds. NM timers are in milliseconds.
  82. //
  83. #define NMP_MADCAP_TO_NM_TIME(_mc_time) ((_mc_time) * 1000)
  84. //
  85. // Force a time_t value into a DWORD.
  86. //
  87. #define NMP_TIME_TO_DWORD(_tm, _dw) \
  88. (_tm) = ((_tm) < 0) ? 0 : (_tm); \
  89. (_tm) = ((_tm) > MAXLONG) ? MAXLONG : (_tm); \
  90. (_dw) = (DWORD) (_tm)
  91. //
  92. // Avoid trying to free a global NM string.
  93. //
  94. #define NMP_GLOBAL_STRING(_string) \
  95. (((_string) == NmpNullMulticastAddress) || \
  96. ((_string) == NmpNullString))
  97. //
  98. // Conditions in which we release an address.
  99. //
  100. #define NmpNeedRelease(_Address, _Server, _RequestId, _Expires) \
  101. (((_Address) != NULL) && \
  102. (NmpMulticastValidateAddress(_Address)) && \
  103. ((_Server) != NULL) && \
  104. ((_RequestId)->ClientUID != NULL) && \
  105. ((_RequestId)->ClientUIDLength != 0) && \
  106. ((_Expires) != 0))
  107. //
  108. // Convert IPv4 addr DWORD into four arguments for a printf/log routine.
  109. //
  110. #define NmpIpAddrPrintArgs(_ip) \
  111. ((_ip >> 0 ) & 0xff), \
  112. ((_ip >> 8 ) & 0xff), \
  113. ((_ip >> 16) & 0xff), \
  114. ((_ip >> 24) & 0xff)
  115. /////////////////////////////////////////////////////////////////////////////
  116. //
  117. // Data
  118. //
  119. /////////////////////////////////////////////////////////////////////////////
  120. LPWSTR NmpNullMulticastAddress = L"0.0.0.0";
  121. BOOLEAN NmpMadcapClientInitialized = FALSE;
  122. BOOLEAN NmpIsNT5NodeInCluster = FALSE;
  123. BOOLEAN NmpMulticastIsNotEnoughNodes = FALSE;
  124. // MADCAP lease release node.
  125. typedef struct _NM_NETWORK_MADCAP_ADDRESS_RELEASE {
  126. LIST_ENTRY Linkage;
  127. LPWSTR McastAddress;
  128. LPWSTR ServerAddress;
  129. MCAST_CLIENT_UID RequestId;
  130. } NM_NETWORK_MADCAP_ADDRESS_RELEASE, *PNM_NETWORK_MADCAP_ADDRESS_RELEASE;
  131. // Data structure for GUM update
  132. typedef struct _NM_NETWORK_MULTICAST_UPDATE {
  133. DWORD Disabled;
  134. DWORD AddressOffset;
  135. DWORD SaltOffset;
  136. DWORD SaltLength;
  137. time_t LeaseObtained;
  138. time_t LeaseExpires;
  139. DWORD LeaseRequestIdOffset;
  140. DWORD LeaseRequestIdLength;
  141. DWORD LeaseServerOffset;
  142. NM_MCAST_CONFIG ConfigType;
  143. } NM_NETWORK_MULTICAST_UPDATE, *PNM_NETWORK_MULTICAST_UPDATE;
  144. // Data structure for multicast parameters, converted to and from the
  145. // GUM update data structure
  146. typedef struct _NM_NETWORK_MULTICAST_PARAMETERS {
  147. DWORD Disabled;
  148. LPWSTR Address;
  149. PVOID Salt;
  150. DWORD SaltLength;
  151. PVOID Key;
  152. DWORD KeyLength;
  153. time_t LeaseObtained;
  154. time_t LeaseExpires;
  155. MCAST_CLIENT_UID LeaseRequestId;
  156. LPWSTR LeaseServer;
  157. NM_MCAST_CONFIG ConfigType;
  158. } NM_NETWORK_MULTICAST_PARAMETERS, *PNM_NETWORK_MULTICAST_PARAMETERS;
  159. // Data structure for multicast property validation
  160. typedef struct _NM_NETWORK_MULTICAST_INFO {
  161. LPWSTR MulticastAddress;
  162. DWORD MulticastDisable;
  163. PVOID MulticastSalt;
  164. DWORD MulticastLeaseObtained;
  165. DWORD MulticastLeaseExpires;
  166. PVOID MulticastLeaseRequestId;
  167. LPWSTR MulticastLeaseServer;
  168. DWORD MulticastConfigType;
  169. LPWSTR MulticastAddressRangeLower;
  170. LPWSTR MulticastAddressRangeUpper;
  171. } NM_NETWORK_MULTICAST_INFO, *PNM_NETWORK_MULTICAST_INFO;
  172. RESUTIL_PROPERTY_ITEM
  173. NmpNetworkMulticastProperties[] =
  174. {
  175. {
  176. CLUSREG_NAME_NET_MULTICAST_ADDRESS, NULL, CLUSPROP_FORMAT_SZ,
  177. 0, 0, 0,
  178. 0, // no flags - multicast address is writeable
  179. FIELD_OFFSET(NM_NETWORK_MULTICAST_INFO, MulticastAddress)
  180. },
  181. {
  182. CLUSREG_NAME_NET_DISABLE_MULTICAST, NULL, CLUSPROP_FORMAT_DWORD,
  183. NMP_MCAST_DISABLED_DEFAULT, 0, 0xFFFFFFFF,
  184. 0, // no flags - disable is writeable
  185. FIELD_OFFSET(NM_NETWORK_MULTICAST_INFO, MulticastDisable)
  186. },
  187. {
  188. CLUSREG_NAME_NET_MULTICAST_KEY_SALT, NULL, CLUSPROP_FORMAT_BINARY,
  189. 0, 0, 0,
  190. RESUTIL_PROPITEM_READ_ONLY,
  191. FIELD_OFFSET(NM_NETWORK_MULTICAST_INFO, MulticastSalt)
  192. },
  193. {
  194. CLUSREG_NAME_NET_MCAST_LEASE_OBTAINED, NULL, CLUSPROP_FORMAT_DWORD,
  195. 0, 0, MAXLONG,
  196. RESUTIL_PROPITEM_READ_ONLY,
  197. FIELD_OFFSET(NM_NETWORK_MULTICAST_INFO, MulticastLeaseObtained)
  198. },
  199. {
  200. CLUSREG_NAME_NET_MCAST_LEASE_EXPIRES, NULL, CLUSPROP_FORMAT_DWORD,
  201. 0, 0, MAXLONG,
  202. RESUTIL_PROPITEM_READ_ONLY,
  203. FIELD_OFFSET(NM_NETWORK_MULTICAST_INFO, MulticastLeaseExpires)
  204. },
  205. {
  206. CLUSREG_NAME_NET_MCAST_REQUEST_ID, NULL, CLUSPROP_FORMAT_BINARY,
  207. 0, 0, 0,
  208. RESUTIL_PROPITEM_READ_ONLY,
  209. FIELD_OFFSET(NM_NETWORK_MULTICAST_INFO, MulticastLeaseRequestId)
  210. },
  211. {
  212. CLUSREG_NAME_NET_MCAST_SERVER_ADDRESS, NULL, CLUSPROP_FORMAT_SZ,
  213. 0, 0, 0,
  214. RESUTIL_PROPITEM_READ_ONLY,
  215. FIELD_OFFSET(NM_NETWORK_MULTICAST_INFO, MulticastLeaseServer)
  216. },
  217. {
  218. CLUSREG_NAME_NET_MCAST_CONFIG_TYPE, NULL, CLUSPROP_FORMAT_DWORD,
  219. NmMcastConfigManual, NmMcastConfigManual, NmMcastConfigAuto,
  220. RESUTIL_PROPITEM_READ_ONLY,
  221. FIELD_OFFSET(NM_NETWORK_MULTICAST_INFO, MulticastConfigType)
  222. },
  223. {
  224. CLUSREG_NAME_NET_MCAST_RANGE_LOWER, NULL, CLUSPROP_FORMAT_SZ,
  225. 0, 0, 0,
  226. 0, // no flags - multicast address range is writeable
  227. FIELD_OFFSET(NM_NETWORK_MULTICAST_INFO, MulticastAddressRangeLower)
  228. },
  229. {
  230. CLUSREG_NAME_NET_MCAST_RANGE_UPPER, NULL, CLUSPROP_FORMAT_SZ,
  231. 0, 0, 0,
  232. 0, // no flags - multicast address range is writeable
  233. FIELD_OFFSET(NM_NETWORK_MULTICAST_INFO, MulticastAddressRangeUpper)
  234. },
  235. {
  236. 0
  237. }
  238. };
  239. //
  240. // Cluster registry API function pointers. Need a separate collection
  241. // of function pointers for multicast because nobody else (e.g. FM, NM)
  242. // fills in DmLocalXXX.
  243. //
  244. CLUSTER_REG_APIS
  245. NmpMcastClusterRegApis = {
  246. (PFNCLRTLCREATEKEY) DmRtlCreateKey,
  247. (PFNCLRTLOPENKEY) DmRtlOpenKey,
  248. (PFNCLRTLCLOSEKEY) DmCloseKey,
  249. (PFNCLRTLSETVALUE) DmSetValue,
  250. (PFNCLRTLQUERYVALUE) DmQueryValue,
  251. (PFNCLRTLENUMVALUE) DmEnumValue,
  252. (PFNCLRTLDELETEVALUE) DmDeleteValue,
  253. (PFNCLRTLLOCALCREATEKEY) DmLocalCreateKey,
  254. (PFNCLRTLLOCALSETVALUE) DmLocalSetValue,
  255. (PFNCLRTLLOCALDELETEVALUE) DmLocalDeleteValue
  256. };
  257. //
  258. // Restricted ranges: we cannot choose a multicast address out of these
  259. // ranges, even if an administrator defines a selection range that
  260. // overlaps with a restricted range.
  261. //
  262. // Note, however, that if an administrator manually configures an
  263. // address, we accept it without question.
  264. //
  265. struct _NM_MCAST_RESTRICTED_RANGE {
  266. DWORD Lower;
  267. DWORD Upper;
  268. LPWSTR Description;
  269. } NmpMulticastRestrictedRange[] =
  270. {
  271. // single-source scope
  272. { NMP_SINGLE_SOURCE_SCOPE_ADDRESS,
  273. NMP_SINGLE_SOURCE_SCOPE_ADDRESS | ~NMP_SINGLE_SOURCE_SCOPE_MASK,
  274. L"Single-Source IP Multicast Address Range" },
  275. // upper /24 of admin local scope
  276. { (NMP_LOCAL_SCOPE_ADDRESS | ~NMP_LOCAL_SCOPE_MASK) & 0x00FFFFFF,
  277. NMP_LOCAL_SCOPE_ADDRESS | ~NMP_LOCAL_SCOPE_MASK,
  278. L"Administrative Local Scope Relative Assignment Range" },
  279. // upper /24 of admin organizational scope
  280. { (NMP_ORG_SCOPE_ADDRESS | ~NMP_ORG_SCOPE_MASK) & 0x00FFFFFF,
  281. NMP_ORG_SCOPE_ADDRESS | ~NMP_ORG_SCOPE_MASK,
  282. L"Administrative Organizational Scope Relative Assignment Range" }
  283. };
  284. DWORD NmpMulticastRestrictedRangeCount =
  285. sizeof(NmpMulticastRestrictedRange) /
  286. sizeof(struct _NM_MCAST_RESTRICTED_RANGE);
  287. //
  288. // Range intervals: intervals in the IPv4 class D address space
  289. // from which we can choose an address.
  290. //
  291. typedef struct _NM_MCAST_RANGE_INTERVAL {
  292. LIST_ENTRY Linkage;
  293. DWORD hlLower;
  294. DWORD hlUpper;
  295. } NM_MCAST_RANGE_INTERVAL, *PNM_MCAST_RANGE_INTERVAL;
  296. #define NmpMulticastRangeIntervalSize(_interval) \
  297. ((_interval)->hlUpper - (_interval)->hlLower + 1)
  298. /////////////////////////////////////////////////////////////////////////////
  299. //
  300. // Internal prototypes
  301. //
  302. /////////////////////////////////////////////////////////////////////////////
  303. DWORD
  304. NmpScheduleNetworkMadcapWorker(
  305. PNM_NETWORK Network
  306. );
  307. DWORD
  308. NmpReconfigureMulticast(
  309. IN PNM_NETWORK Network
  310. );
  311. /////////////////////////////////////////////////////////////////////////////
  312. //
  313. // Initialization & cleanup routines
  314. //
  315. /////////////////////////////////////////////////////////////////////////////
  316. DWORD
  317. NmpCleanupMulticast(
  318. VOID
  319. )
  320. /*++
  321. Notes:
  322. Called with NM lock held.
  323. --*/
  324. {
  325. //
  326. // Cleanup the MADCAP client.
  327. //
  328. if (NmpMadcapClientInitialized) {
  329. McastApiCleanup();
  330. NmpMadcapClientInitialized = FALSE;
  331. }
  332. return(ERROR_SUCCESS);
  333. } // NmpCleanupMulticast
  334. /////////////////////////////////////////////////////////////////////////////
  335. //
  336. // Internal routines.
  337. //
  338. /////////////////////////////////////////////////////////////////////////////
  339. #if CLUSTER_BETA
  340. LPWSTR
  341. NmpCreateLogString(
  342. IN PVOID Source,
  343. IN DWORD SourceLength
  344. )
  345. {
  346. PWCHAR displayBuf, bufp;
  347. PCHAR chp;
  348. DWORD x, i;
  349. displayBuf = LocalAlloc(
  350. LMEM_FIXED | LMEM_ZEROINIT,
  351. SourceLength * ( 7 * sizeof(WCHAR) )
  352. );
  353. if (displayBuf == NULL) {
  354. ClRtlLogPrint(LOG_NOISE,
  355. "[NM] Failed to allocate display buffer of size %1!u!.\n",
  356. SourceLength * sizeof(WCHAR)
  357. );
  358. goto error_exit;
  359. }
  360. bufp = displayBuf;
  361. chp = (PCHAR) Source;
  362. for (i = 0; i < SourceLength; i++) {
  363. x = (DWORD) (*chp);
  364. x &= 0xff;
  365. wsprintf(bufp, L"%02x ", x);
  366. chp++;
  367. bufp = &displayBuf[wcslen(displayBuf)];
  368. }
  369. error_exit:
  370. return(displayBuf);
  371. } // NmpCreateLogString
  372. #endif // CLUSTER_BETA
  373. BOOLEAN
  374. NmpMulticastValidateAddress(
  375. IN LPWSTR McastAddress
  376. )
  377. /*++
  378. Routine Description:
  379. Determines whether McastAddress is a valid
  380. multicast address.
  381. Notes:
  382. IPv4 specific.
  383. --*/
  384. {
  385. DWORD status;
  386. DWORD address;
  387. status = ClRtlTcpipStringToAddress(McastAddress, &address);
  388. if (status == ERROR_SUCCESS) {
  389. address = ntohl(address);
  390. if (IN_CLASSD(address)) {
  391. return(TRUE);
  392. }
  393. }
  394. return(FALSE);
  395. } // NmpMulticastValidateAddress
  396. VOID
  397. NmpFreeNetworkMulticastInfo(
  398. IN PNM_NETWORK_MULTICAST_INFO McastInfo
  399. )
  400. {
  401. NM_MIDL_FREE_OBJECT_FIELD(McastInfo, MulticastAddress);
  402. NM_MIDL_FREE_OBJECT_FIELD(McastInfo, MulticastSalt);
  403. NM_MIDL_FREE_OBJECT_FIELD(McastInfo, MulticastLeaseRequestId);
  404. NM_MIDL_FREE_OBJECT_FIELD(McastInfo, MulticastLeaseServer);
  405. NM_MIDL_FREE_OBJECT_FIELD(McastInfo, MulticastAddressRangeLower);
  406. NM_MIDL_FREE_OBJECT_FIELD(McastInfo, MulticastAddressRangeUpper);
  407. return;
  408. } // NmpFreeNetworkMulticastInfo
  409. DWORD
  410. NmpStoreString(
  411. IN LPWSTR Source,
  412. IN OUT LPWSTR * Dest,
  413. IN OUT DWORD * DestLength OPTIONAL
  414. )
  415. {
  416. DWORD sourceSize;
  417. DWORD destLength;
  418. if (Source != NULL) {
  419. sourceSize = NM_WCSLEN(Source);
  420. } else {
  421. sourceSize = 0;
  422. }
  423. if (DestLength == NULL) {
  424. destLength = 0;
  425. } else {
  426. destLength = *DestLength;
  427. }
  428. if (*Dest != NULL && ((destLength < sourceSize) || (Source == NULL))) {
  429. MIDL_user_free(*Dest);
  430. *Dest = NULL;
  431. }
  432. if (*Dest == NULL) {
  433. if (sourceSize > 0) {
  434. *Dest = MIDL_user_allocate(sourceSize);
  435. if (*Dest == NULL) {
  436. ClRtlLogPrint(LOG_UNUSUAL,
  437. "[NM] Failed to allocate buffer of size %1!u! "
  438. "for source string %2!ws!.\n",
  439. sourceSize, Source
  440. );
  441. return(ERROR_NOT_ENOUGH_MEMORY);
  442. }
  443. }
  444. if (DestLength != NULL) {
  445. *DestLength = sourceSize;
  446. }
  447. }
  448. if (sourceSize > 0) {
  449. RtlCopyMemory(*Dest, Source, sourceSize);
  450. }
  451. return(ERROR_SUCCESS);
  452. } // NmpStoreString
  453. DWORD
  454. NmpStoreRequestId(
  455. IN LPMCAST_CLIENT_UID Source,
  456. IN OUT LPMCAST_CLIENT_UID Dest
  457. )
  458. {
  459. DWORD status;
  460. DWORD len;
  461. len = Source->ClientUIDLength;
  462. if (Source->ClientUID == NULL) {
  463. len = 0;
  464. }
  465. if (Dest->ClientUID != NULL &&
  466. (Dest->ClientUIDLength < Source->ClientUIDLength || len == 0)) {
  467. MIDL_user_free(Dest->ClientUID);
  468. Dest->ClientUID = NULL;
  469. Dest->ClientUIDLength = 0;
  470. }
  471. if (Dest->ClientUID == NULL && len > 0) {
  472. Dest->ClientUID = MIDL_user_allocate(len);
  473. if (Dest->ClientUID == NULL) {
  474. status = ERROR_NOT_ENOUGH_MEMORY;
  475. goto error_exit;
  476. }
  477. }
  478. if (len > 0) {
  479. RtlCopyMemory(
  480. Dest->ClientUID,
  481. Source->ClientUID,
  482. len
  483. );
  484. }
  485. Dest->ClientUIDLength = len;
  486. status = ERROR_SUCCESS;
  487. error_exit:
  488. return(status);
  489. } // NmpStoreRequestId
  490. VOID
  491. NmpStartNetworkMulticastAddressRenewTimer(
  492. PNM_NETWORK Network,
  493. DWORD Timeout
  494. )
  495. /*++
  496. Notes:
  497. Must be called with NM lock held.
  498. --*/
  499. {
  500. LPCWSTR networkId = OmObjectId(Network);
  501. LPCWSTR networkName = OmObjectName(Network);
  502. if (Network->McastAddressRenewTimer != Timeout) {
  503. Network->McastAddressRenewTimer = Timeout;
  504. ClRtlLogPrint(LOG_NOISE,
  505. "[NM] %1!ws! multicast address lease renew "
  506. "timer (%2!u!ms) for network %3!ws! (%4!ws!)\n",
  507. ((Timeout == 0) ? L"Cleared" : L"Started"),
  508. Network->McastAddressRenewTimer,
  509. networkId,
  510. networkName
  511. );
  512. }
  513. return;
  514. } // NmpStartNetworkMulticastAddressRenewTimer
  515. DWORD
  516. NmpGenerateMulticastKey(
  517. IN PNM_NETWORK Network,
  518. IN OUT PVOID * Key,
  519. IN OUT ULONG * KeyLength
  520. )
  521. /*++
  522. Routine Description:
  523. Obtain a secret key that all nodes in the cluster can
  524. independently generate.
  525. --*/
  526. {
  527. DWORD status;
  528. LPCWSTR networkId = OmObjectId(Network);
  529. PVOID key = NULL;
  530. DWORD keyLength = 0;
  531. ClRtlLogPrint(LOG_NOISE,
  532. "[NM] Obtaining multicast key for network %1!ws!.\n",
  533. networkId
  534. );
  535. status = NmpGetClusterKey(key, &keyLength);
  536. if (status != ERROR_SUCCESS) {
  537. if (status == ERROR_INSUFFICIENT_BUFFER) {
  538. key = MIDL_user_allocate(keyLength);
  539. if (key == NULL) {
  540. ClRtlLogPrint(LOG_UNUSUAL,
  541. "[NM] Failed to allocate key buffer of "
  542. "size %1!u! for network %2!ws!.\n",
  543. keyLength, networkId
  544. );
  545. return(ERROR_NOT_ENOUGH_MEMORY);
  546. }
  547. status = NmpGetClusterKey(key, &keyLength);
  548. }
  549. }
  550. if (status != ERROR_SUCCESS) {
  551. ClRtlLogPrint(LOG_UNUSUAL,
  552. "[NM] Failed to obtain multicast key for "
  553. "network %1!ws!, status %2!u!.\n",
  554. networkId, status
  555. );
  556. return(status);
  557. }
  558. *Key = key;
  559. *KeyLength = keyLength;
  560. return(ERROR_SUCCESS);
  561. } // NmpGenerateMulticastKey
  562. VOID
  563. NmpMulticastFreeParameters(
  564. IN PNM_NETWORK_MULTICAST_PARAMETERS Parameters
  565. )
  566. {
  567. if (Parameters->Address != NULL) {
  568. if (!NMP_GLOBAL_STRING(Parameters->Address)) {
  569. MIDL_user_free(Parameters->Address);
  570. }
  571. Parameters->Address = NULL;
  572. }
  573. NM_MIDL_FREE_OBJECT_FIELD(Parameters, Salt);
  574. Parameters->SaltLength = 0;
  575. NM_MIDL_FREE_OBJECT_FIELD(Parameters, Key);
  576. Parameters->KeyLength = 0;
  577. NM_MIDL_FREE_OBJECT_FIELD(Parameters, LeaseRequestId.ClientUID);
  578. Parameters->LeaseRequestId.ClientUIDLength = 0;
  579. if (Parameters->LeaseServer != NULL) {
  580. if (!NMP_GLOBAL_STRING(Parameters->LeaseServer)) {
  581. MIDL_user_free(Parameters->LeaseServer);
  582. }
  583. Parameters->LeaseServer = NULL;
  584. }
  585. return;
  586. } // NmpMulticastFreeParameters
  587. DWORD
  588. NmpMulticastCreateParameters(
  589. IN DWORD Disabled,
  590. IN LPWSTR Address,
  591. IN PVOID Salt,
  592. IN DWORD SaltLength,
  593. IN PVOID Key,
  594. IN DWORD KeyLength,
  595. IN time_t LeaseObtained,
  596. IN time_t LeaseExpires,
  597. IN LPMCAST_CLIENT_UID LeaseRequestId,
  598. IN LPWSTR LeaseServer,
  599. IN NM_MCAST_CONFIG ConfigType,
  600. OUT PNM_NETWORK_MULTICAST_PARAMETERS Parameters
  601. )
  602. {
  603. DWORD status;
  604. RtlZeroMemory(Parameters, sizeof(*Parameters));
  605. // disabled
  606. Parameters->Disabled = Disabled;
  607. // address
  608. if (Address != NULL) {
  609. status = NmpStoreString(Address, &(Parameters->Address), NULL);
  610. if (status != ERROR_SUCCESS) {
  611. goto error_exit;
  612. }
  613. }
  614. // salt
  615. if (Salt != NULL) {
  616. Parameters->Salt = MIDL_user_allocate(SaltLength);
  617. if (Parameters->Salt == NULL) {
  618. status = ERROR_NOT_ENOUGH_MEMORY;
  619. goto error_exit;
  620. }
  621. RtlCopyMemory(Parameters->Salt, Salt, SaltLength);
  622. Parameters->SaltLength = SaltLength;
  623. }
  624. // key
  625. if (Key != NULL) {
  626. Parameters->Key = MIDL_user_allocate(KeyLength);
  627. if (Parameters->Key == NULL) {
  628. status = ERROR_NOT_ENOUGH_MEMORY;
  629. goto error_exit;
  630. }
  631. RtlCopyMemory(Parameters->Key, Key, KeyLength);
  632. Parameters->KeyLength = KeyLength;
  633. }
  634. Parameters->LeaseObtained = LeaseObtained;
  635. Parameters->LeaseExpires = LeaseExpires;
  636. // lease request id
  637. if (LeaseRequestId->ClientUID != NULL) {
  638. status = NmpStoreRequestId(LeaseRequestId, &Parameters->LeaseRequestId);
  639. if (status != ERROR_SUCCESS) {
  640. goto error_exit;
  641. }
  642. }
  643. // lease server address
  644. if (LeaseServer != NULL) {
  645. status = NmpStoreString(LeaseServer, &(Parameters->LeaseServer), NULL);
  646. if (status != ERROR_SUCCESS) {
  647. goto error_exit;
  648. }
  649. }
  650. // config type
  651. Parameters->ConfigType = ConfigType;
  652. return(ERROR_SUCCESS);
  653. error_exit:
  654. NmpMulticastFreeParameters(Parameters);
  655. return(status);
  656. } // NmpMulticastCreateParameters
  657. DWORD
  658. NmpMulticastCreateParametersFromUpdate(
  659. IN PNM_NETWORK Network,
  660. IN PNM_NETWORK_MULTICAST_UPDATE Update,
  661. IN BOOLEAN GenerateKey,
  662. OUT PNM_NETWORK_MULTICAST_PARAMETERS Parameters
  663. )
  664. /*++
  665. Routine Description:
  666. Converts a data structure received in a GUM update
  667. into a locally allocated parameters data structure.
  668. The base Parameters data structure must be allocated
  669. by the caller, though the fields are allocated in
  670. this routine.
  671. --*/
  672. {
  673. DWORD status;
  674. MCAST_CLIENT_UID requestId;
  675. requestId.ClientUID =
  676. ((Update->LeaseRequestIdOffset == 0) ? NULL :
  677. (LPBYTE)((PUCHAR)Update + Update->LeaseRequestIdOffset));
  678. requestId.ClientUIDLength = Update->LeaseRequestIdLength;
  679. status = NmpMulticastCreateParameters(
  680. Update->Disabled,
  681. ((Update->AddressOffset == 0) ? NULL :
  682. (LPWSTR)((PUCHAR)Update + Update->AddressOffset)),
  683. ((Update->SaltOffset == 0) ? NULL :
  684. (PVOID)((PUCHAR)Update + Update->SaltOffset)),
  685. Update->SaltLength,
  686. NULL,
  687. 0,
  688. Update->LeaseObtained,
  689. Update->LeaseExpires,
  690. &requestId,
  691. ((Update->LeaseServerOffset == 0) ? NULL :
  692. (LPWSTR)((PUCHAR)Update + Update->LeaseServerOffset)),
  693. Update->ConfigType,
  694. Parameters
  695. );
  696. if (status == ERROR_SUCCESS && GenerateKey) {
  697. status = NmpGenerateMulticastKey(
  698. Network,
  699. &(Parameters->Key),
  700. &(Parameters->KeyLength)
  701. );
  702. }
  703. if (status != ERROR_SUCCESS) {
  704. NmpMulticastFreeParameters(Parameters);
  705. }
  706. return(status);
  707. } // NmpMulticastCreateParametersFromUpdate
  708. DWORD
  709. NmpMulticastCreateUpdateFromParameters(
  710. IN PNM_NETWORK Network,
  711. IN PNM_NETWORK_MULTICAST_PARAMETERS Parameters,
  712. OUT PNM_NETWORK_MULTICAST_UPDATE * Update,
  713. OUT DWORD * UpdateSize
  714. )
  715. {
  716. DWORD updateSize;
  717. PNM_NETWORK_MULTICAST_UPDATE update;
  718. DWORD address = 0;
  719. DWORD salt = 0;
  720. DWORD requestId = 0;
  721. DWORD leaseServer = 0;
  722. //
  723. // Calculate the size of the update data buffer.
  724. //
  725. updateSize = sizeof(*update);
  726. // address
  727. if (Parameters->Address != NULL) {
  728. updateSize = ROUND_UP_COUNT(updateSize, TYPE_ALIGNMENT(LPWSTR));
  729. address = updateSize;
  730. updateSize += NM_WCSLEN(Parameters->Address);
  731. }
  732. // salt
  733. if (Parameters->Salt != NULL) {
  734. updateSize = ROUND_UP_COUNT(updateSize, TYPE_ALIGNMENT(PVOID));
  735. salt = updateSize;
  736. updateSize += Parameters->SaltLength;
  737. }
  738. // request id
  739. if (Parameters->LeaseRequestId.ClientUID != NULL) {
  740. updateSize = ROUND_UP_COUNT(updateSize, TYPE_ALIGNMENT(LPBYTE));
  741. requestId = updateSize;
  742. updateSize += Parameters->LeaseRequestId.ClientUIDLength;
  743. }
  744. // lease server
  745. if (Parameters->LeaseServer != NULL) {
  746. updateSize = ROUND_UP_COUNT(updateSize, TYPE_ALIGNMENT(LPWSTR));
  747. leaseServer = updateSize;
  748. updateSize += NM_WCSLEN(Parameters->LeaseServer);
  749. }
  750. //
  751. // Allocate the update buffer.
  752. //
  753. update = MIDL_user_allocate(updateSize);
  754. if (update == NULL) {
  755. return(ERROR_NOT_ENOUGH_MEMORY);
  756. }
  757. //
  758. // Fill in the update buffer.
  759. //
  760. update->Disabled = Parameters->Disabled;
  761. update->AddressOffset = address;
  762. if (address != 0) {
  763. RtlCopyMemory(
  764. (PUCHAR)update + address,
  765. Parameters->Address,
  766. NM_WCSLEN(Parameters->Address)
  767. );
  768. }
  769. update->SaltOffset = salt;
  770. update->SaltLength = Parameters->SaltLength;
  771. if (salt != 0) {
  772. RtlCopyMemory(
  773. (PUCHAR)update + salt,
  774. Parameters->Salt,
  775. Parameters->SaltLength
  776. );
  777. }
  778. update->LeaseObtained = Parameters->LeaseObtained;
  779. update->LeaseExpires = Parameters->LeaseExpires;
  780. update->LeaseRequestIdOffset = requestId;
  781. update->LeaseRequestIdLength = Parameters->LeaseRequestId.ClientUIDLength;
  782. if (requestId != 0) {
  783. RtlCopyMemory(
  784. (PUCHAR)update + requestId,
  785. Parameters->LeaseRequestId.ClientUID,
  786. Parameters->LeaseRequestId.ClientUIDLength
  787. );
  788. }
  789. update->LeaseServerOffset = leaseServer;
  790. if (leaseServer != 0) {
  791. RtlCopyMemory(
  792. (PUCHAR)update + leaseServer,
  793. Parameters->LeaseServer,
  794. NM_WCSLEN(Parameters->LeaseServer)
  795. );
  796. }
  797. update->ConfigType = Parameters->ConfigType;
  798. *Update = update;
  799. *UpdateSize = updateSize;
  800. return(ERROR_SUCCESS);
  801. } // NmpMulticastCreateUpdateFromParameters
  802. VOID
  803. NmpFreeMulticastAddressRelease(
  804. IN PNM_NETWORK_MADCAP_ADDRESS_RELEASE Release
  805. )
  806. {
  807. if (Release == NULL) {
  808. return;
  809. }
  810. if (Release->McastAddress != NULL &&
  811. !NMP_GLOBAL_STRING(Release->McastAddress)) {
  812. MIDL_user_free(Release->McastAddress);
  813. Release->McastAddress = NULL;
  814. }
  815. if (Release->ServerAddress != NULL &&
  816. !NMP_GLOBAL_STRING(Release->ServerAddress)) {
  817. MIDL_user_free(Release->ServerAddress);
  818. Release->ServerAddress = NULL;
  819. }
  820. if (Release->RequestId.ClientUID != NULL) {
  821. MIDL_user_free(Release->RequestId.ClientUID);
  822. Release->RequestId.ClientUID = NULL;
  823. Release->RequestId.ClientUIDLength = 0;
  824. }
  825. LocalFree(Release);
  826. return;
  827. } // NmpFreeMulticastAddressRelease
  828. DWORD
  829. NmpCreateMulticastAddressRelease(
  830. IN LPWSTR McastAddress,
  831. IN LPWSTR ServerAddress,
  832. IN LPMCAST_CLIENT_UID RequestId,
  833. OUT PNM_NETWORK_MADCAP_ADDRESS_RELEASE * Release
  834. )
  835. /*++
  836. Routine Description:
  837. Allocate and initialize an entry for an address
  838. release list.
  839. --*/
  840. {
  841. DWORD status;
  842. PNM_NETWORK_MADCAP_ADDRESS_RELEASE release = NULL;
  843. release = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(*release));
  844. if (release == NULL) {
  845. status = ERROR_NOT_ENOUGH_MEMORY;
  846. goto error_exit;
  847. }
  848. status = NmpStoreString(McastAddress, &(release->McastAddress), NULL);
  849. if (status != ERROR_SUCCESS) {
  850. goto error_exit;
  851. }
  852. status = NmpStoreString(ServerAddress, &(release->ServerAddress), NULL);
  853. if (status != ERROR_SUCCESS) {
  854. goto error_exit;
  855. }
  856. status = NmpStoreRequestId(RequestId, &(release->RequestId));
  857. if (status != ERROR_SUCCESS) {
  858. goto error_exit;
  859. }
  860. *Release = release;
  861. return(ERROR_SUCCESS);
  862. error_exit:
  863. NmpFreeMulticastAddressRelease(release);
  864. return(status);
  865. } // NmpCreateMulticastAddressRelease
  866. VOID
  867. NmpInitiateMulticastAddressRelease(
  868. IN PNM_NETWORK Network,
  869. IN PNM_NETWORK_MADCAP_ADDRESS_RELEASE Release
  870. )
  871. /*++
  872. Routine Description:
  873. Stores an entry for the network multicast
  874. address release list on the list and schedules
  875. the release.
  876. Notes:
  877. Called and returns with NM lock held.
  878. --*/
  879. {
  880. InsertTailList(&(Network->McastAddressReleaseList), &(Release->Linkage));
  881. NmpScheduleMulticastAddressRelease(Network);
  882. return;
  883. } // NmpInitiateMulticastAddressRelease
  884. DWORD
  885. NmpQueryMulticastAddress(
  886. IN PNM_NETWORK Network,
  887. IN HDMKEY NetworkKey,
  888. IN OUT HDMKEY * NetworkParametersKey,
  889. IN OUT LPWSTR * McastAddr,
  890. IN OUT ULONG * McastAddrLength
  891. )
  892. {
  893. DWORD status;
  894. LPCWSTR networkId = OmObjectId(Network);
  895. HDMKEY netParamKey = NULL;
  896. BOOLEAN openedNetParamKey = FALSE;
  897. DWORD size = 0;
  898. if (Network == NULL || NetworkKey == NULL) {
  899. status = ERROR_INVALID_PARAMETER;
  900. goto error_exit;
  901. }
  902. #if CLUSTER_BETA
  903. ClRtlLogPrint(LOG_NOISE,
  904. "[NM] Querying multicast address for "
  905. "network %1!ws! from cluster database.\n",
  906. networkId
  907. );
  908. #endif // CLUSTER_BETA
  909. //
  910. // Open the network parameters key, if necessary.
  911. //
  912. netParamKey = *NetworkParametersKey;
  913. if (netParamKey == NULL) {
  914. netParamKey = DmOpenKey(
  915. NetworkKey,
  916. CLUSREG_KEYNAME_PARAMETERS,
  917. MAXIMUM_ALLOWED
  918. );
  919. if (netParamKey == NULL) {
  920. status = GetLastError();
  921. ClRtlLogPrint(LOG_NOISE,
  922. "[NM] Failed to find Parameters key "
  923. "for network %1!ws!, status %2!u!. Using default "
  924. "multicast parameters.\n",
  925. networkId, status
  926. );
  927. goto error_exit;
  928. } else {
  929. openedNetParamKey = TRUE;
  930. }
  931. }
  932. //
  933. // Query for the multicast address.
  934. //
  935. status = NmpQueryString(
  936. netParamKey,
  937. CLUSREG_NAME_NET_MULTICAST_ADDRESS,
  938. REG_SZ,
  939. McastAddr,
  940. McastAddrLength,
  941. &size
  942. );
  943. if (status != ERROR_SUCCESS) {
  944. ClRtlLogPrint(LOG_UNUSUAL,
  945. "[NM] Failed to read multicast address for "
  946. "network %1!ws! from cluster database, "
  947. "status %2!u!. Using default.\n",
  948. networkId, status
  949. );
  950. goto error_exit;
  951. }
  952. *NetworkParametersKey = netParamKey;
  953. netParamKey = NULL;
  954. #if CLUSTER_BETA
  955. ClRtlLogPrint(LOG_NOISE,
  956. "[NM] Found multicast address %1!ws! for "
  957. "network %2!ws! in cluster database.\n",
  958. *McastAddr, networkId
  959. );
  960. #endif // CLUSTER_BETA
  961. error_exit:
  962. if (openedNetParamKey && netParamKey != NULL) {
  963. DmCloseKey(netParamKey);
  964. netParamKey = NULL;
  965. }
  966. return(status);
  967. } // NmpQueryMulticastAddress
  968. DWORD
  969. NmpQueryMulticastDisabled(
  970. IN PNM_NETWORK Network,
  971. IN OUT HDMKEY * ClusterParametersKey,
  972. IN OUT HDMKEY * NetworkKey,
  973. IN OUT HDMKEY * NetworkParametersKey,
  974. OUT DWORD * Disabled
  975. )
  976. /*++
  977. Routine Description:
  978. Checks whether multicast has been disabled for this
  979. network in the cluster database. Both the network
  980. paramters key and the cluster parameters key are
  981. checked. The order of precedence is as follows:
  982. - a value in the network parameters key has top
  983. precedence
  984. - if no value is found in the network parameters
  985. key, a value is checked in the cluster parameters
  986. key.
  987. - if no value is found in the cluster parameters
  988. key, return NMP_MCAST_DISABLED_DEFAULT.
  989. If an error is returned, the return value of
  990. Disabled is undefined.
  991. Notes:
  992. Must not be called with NM lock held.
  993. --*/
  994. {
  995. DWORD status;
  996. LPCWSTR networkId = OmObjectId(Network);
  997. DWORD type;
  998. DWORD disabled;
  999. DWORD len = sizeof(disabled);
  1000. BOOLEAN found = FALSE;
  1001. HDMKEY clusParamKey = NULL;
  1002. BOOLEAN openedClusParamKey = FALSE;
  1003. HDMKEY networkKey = NULL;
  1004. BOOLEAN openedNetworkKey = FALSE;
  1005. HDMKEY netParamKey = NULL;
  1006. BOOLEAN openedNetParamKey = FALSE;
  1007. //
  1008. // Open the network key, if necessary.
  1009. //
  1010. networkKey = *NetworkKey;
  1011. if (networkKey == NULL) {
  1012. networkKey = DmOpenKey(
  1013. DmNetworksKey,
  1014. networkId,
  1015. MAXIMUM_ALLOWED
  1016. );
  1017. if (networkKey == NULL) {
  1018. status = GetLastError();
  1019. ClRtlLogPrint(LOG_UNUSUAL,
  1020. "[NM] Failed to open key for network %1!ws!, "
  1021. "status %2!u!\n",
  1022. networkId, status
  1023. );
  1024. goto error_exit;
  1025. } else {
  1026. openedNetworkKey = TRUE;
  1027. }
  1028. }
  1029. //
  1030. // Open the network parameters key, if necessary.
  1031. //
  1032. netParamKey = *NetworkParametersKey;
  1033. if (netParamKey == NULL) {
  1034. netParamKey = DmOpenKey(
  1035. networkKey,
  1036. CLUSREG_KEYNAME_PARAMETERS,
  1037. MAXIMUM_ALLOWED
  1038. );
  1039. if (netParamKey == NULL) {
  1040. status = GetLastError();
  1041. #if CLUSTER_BETA
  1042. ClRtlLogPrint(LOG_NOISE,
  1043. "[NM] Failed to find Parameters key "
  1044. "for network %1!ws!, status %2!u!. Using default "
  1045. "multicast parameters.\n",
  1046. networkId, status
  1047. );
  1048. #endif // CLUSTER_BETA
  1049. } else {
  1050. openedNetParamKey = TRUE;
  1051. }
  1052. }
  1053. //
  1054. // If we found a network parameters key, check for the
  1055. // disabled value.
  1056. //
  1057. if (netParamKey != NULL) {
  1058. status = DmQueryValue(
  1059. netParamKey,
  1060. CLUSREG_NAME_NET_DISABLE_MULTICAST,
  1061. &type,
  1062. (LPBYTE) &disabled,
  1063. &len
  1064. );
  1065. if (status == ERROR_SUCCESS) {
  1066. if (type != REG_DWORD) {
  1067. ClRtlLogPrint(LOG_NOISE,
  1068. "[NM] Unexpected type (%1!u!) for network "
  1069. "%2!ws! %3!ws!, status %4!u!. Checking "
  1070. "cluster parameters ...\n",
  1071. type, networkId,
  1072. CLUSREG_NAME_NET_DISABLE_MULTICAST, status
  1073. );
  1074. } else {
  1075. found = TRUE;
  1076. }
  1077. }
  1078. }
  1079. //
  1080. // If we were unsuccessful at finding a value in the
  1081. // network parameters key, try under the cluster
  1082. // parameters key.
  1083. //
  1084. if (!found) {
  1085. //
  1086. // Open the cluster parameters key, if necessary.
  1087. //
  1088. clusParamKey = *NetworkParametersKey;
  1089. if (clusParamKey == NULL) {
  1090. clusParamKey = DmOpenKey(
  1091. DmClusterParametersKey,
  1092. CLUSREG_KEYNAME_PARAMETERS,
  1093. KEY_READ
  1094. );
  1095. if (clusParamKey == NULL) {
  1096. status = GetLastError();
  1097. #if CLUSTER_BETA
  1098. ClRtlLogPrint(LOG_NOISE,
  1099. "[NM] Failed to find cluster Parameters "
  1100. "key, status %1!u!.\n",
  1101. status
  1102. );
  1103. #endif // CLUSTER_BETA
  1104. } else {
  1105. openedClusParamKey = TRUE;
  1106. //
  1107. // Query the disabled value under the cluster parameters
  1108. // key.
  1109. //
  1110. status = DmQueryValue(
  1111. clusParamKey,
  1112. CLUSREG_NAME_CLUSTER_DISABLE_MULTICAST,
  1113. &type,
  1114. (LPBYTE) &disabled,
  1115. &len
  1116. );
  1117. if (status != ERROR_SUCCESS) {
  1118. #if CLUSTER_BETA
  1119. ClRtlLogPrint(LOG_NOISE,
  1120. "[NM] Failed to read cluster "
  1121. "%1!ws! value, status %2!u!. "
  1122. "Using default value ...\n",
  1123. CLUSREG_NAME_CLUSTER_DISABLE_MULTICAST, status
  1124. );
  1125. #endif // CLUSTER_BETA
  1126. }
  1127. else if (type != REG_DWORD) {
  1128. ClRtlLogPrint(LOG_UNUSUAL,
  1129. "[NM] Unexpected type (%1!u!) for cluster "
  1130. "%2!ws!, status %3!u!. "
  1131. "Using default value ...\n",
  1132. type, CLUSREG_NAME_CLUSTER_DISABLE_MULTICAST, status
  1133. );
  1134. } else {
  1135. found = TRUE;
  1136. }
  1137. }
  1138. }
  1139. }
  1140. //
  1141. // Return what we found. If we didn't find anything,
  1142. // return the default.
  1143. //
  1144. if (found) {
  1145. *Disabled = disabled;
  1146. } else {
  1147. *Disabled = NMP_MCAST_DISABLED_DEFAULT;
  1148. }
  1149. *NetworkKey = networkKey;
  1150. networkKey = NULL;
  1151. *NetworkParametersKey = netParamKey;
  1152. netParamKey = NULL;
  1153. *ClusterParametersKey = clusParamKey;
  1154. clusParamKey = NULL;
  1155. //
  1156. // Even if we didn't find anything, we return success
  1157. // because we have a default. Note that we return error
  1158. // if a fundamental operation (such as locating the
  1159. // network key) failed.
  1160. //
  1161. status = ERROR_SUCCESS;
  1162. error_exit:
  1163. if (openedClusParamKey && clusParamKey != NULL) {
  1164. DmCloseKey(clusParamKey);
  1165. clusParamKey = NULL;
  1166. }
  1167. if (openedNetParamKey && netParamKey != NULL) {
  1168. DmCloseKey(netParamKey);
  1169. netParamKey = NULL;
  1170. }
  1171. if (openedNetworkKey && networkKey != NULL) {
  1172. DmCloseKey(networkKey);
  1173. networkKey = NULL;
  1174. }
  1175. return(status);
  1176. } // NmpQueryMulticastDisabled
  1177. DWORD
  1178. NmpQueryMulticastConfigType(
  1179. IN PNM_NETWORK Network,
  1180. IN HDMKEY NetworkKey,
  1181. IN OUT HDMKEY * NetworkParametersKey,
  1182. OUT NM_MCAST_CONFIG * ConfigType
  1183. )
  1184. /*++
  1185. Routine Description:
  1186. Reads the multicast config type from the cluster
  1187. database.
  1188. --*/
  1189. {
  1190. LPCWSTR networkId = OmObjectId(Network);
  1191. HDMKEY netParamKey = NULL;
  1192. BOOLEAN openedNetParamKey = FALSE;
  1193. DWORD type;
  1194. DWORD len = sizeof(*ConfigType);
  1195. DWORD status;
  1196. #if CLUSTER_BETA
  1197. ClRtlLogPrint(LOG_NOISE,
  1198. "[NM] Querying multicast address config type for "
  1199. "network %1!ws! from cluster database.\n",
  1200. networkId
  1201. );
  1202. #endif // CLUSTER_BETA
  1203. if (Network == NULL || NetworkKey == NULL) {
  1204. status = ERROR_INVALID_PARAMETER;
  1205. goto error_exit;
  1206. }
  1207. //
  1208. // Open the network parameters key, if necessary.
  1209. //
  1210. netParamKey = *NetworkParametersKey;
  1211. if (netParamKey == NULL) {
  1212. netParamKey = DmOpenKey(
  1213. NetworkKey,
  1214. CLUSREG_KEYNAME_PARAMETERS,
  1215. MAXIMUM_ALLOWED
  1216. );
  1217. if (netParamKey == NULL) {
  1218. status = GetLastError();
  1219. ClRtlLogPrint(LOG_NOISE,
  1220. "[NM] Failed to find Parameters key "
  1221. "for network %1!ws!, status %2!u!. Using default "
  1222. "multicast parameters.\n",
  1223. networkId, status
  1224. );
  1225. goto error_exit;
  1226. } else {
  1227. openedNetParamKey = TRUE;
  1228. }
  1229. }
  1230. //
  1231. // Read the config type.
  1232. //
  1233. status = DmQueryValue(
  1234. netParamKey,
  1235. CLUSREG_NAME_NET_MCAST_CONFIG_TYPE,
  1236. &type,
  1237. (LPBYTE) ConfigType,
  1238. &len
  1239. );
  1240. if (status == ERROR_SUCCESS) {
  1241. if (type != REG_DWORD) {
  1242. ClRtlLogPrint(LOG_UNUSUAL,
  1243. "[NM] Unexpected type (%1!u!) for network "
  1244. "%2!ws! %3!ws!, status %4!u!. Checking "
  1245. "cluster parameters ...\n",
  1246. type, networkId,
  1247. CLUSREG_NAME_NET_MCAST_CONFIG_TYPE, status
  1248. );
  1249. status = ERROR_DATATYPE_MISMATCH;
  1250. goto error_exit;
  1251. }
  1252. } else {
  1253. ClRtlLogPrint(LOG_UNUSUAL,
  1254. "[NM] Failed to query network %2!ws! %3!ws! "
  1255. "from cluster database, status %4!u!.\n",
  1256. networkId, CLUSREG_NAME_NET_MCAST_CONFIG_TYPE, status
  1257. );
  1258. goto error_exit;
  1259. }
  1260. *NetworkParametersKey = netParamKey;
  1261. netParamKey = NULL;
  1262. #if CLUSTER_BETA
  1263. ClRtlLogPrint(LOG_NOISE,
  1264. "[NM] Found multicast address config type %1!u! "
  1265. "for network %2!ws! in cluster database.\n",
  1266. *ConfigType, networkId
  1267. );
  1268. #endif // CLUSTER_BETA
  1269. error_exit:
  1270. if (openedNetParamKey && netParamKey != NULL) {
  1271. DmCloseKey(netParamKey);
  1272. netParamKey = NULL;
  1273. }
  1274. return(status);
  1275. } // NmpQueryMulticastConfigType
  1276. DWORD
  1277. NmpQueryMulticastKeySalt(
  1278. IN PNM_NETWORK Network,
  1279. IN HDMKEY NetworkKey,
  1280. IN OUT HDMKEY * NetworkParametersKey,
  1281. IN OUT PVOID * Salt,
  1282. IN OUT ULONG * SaltLength
  1283. )
  1284. /*++
  1285. Routine Description:
  1286. Reads the multicast key salt from the cluster
  1287. database.
  1288. Notes:
  1289. Must not be called with NM lock held.
  1290. --*/
  1291. {
  1292. LPCWSTR networkId = OmObjectId(Network);
  1293. HDMKEY netParamKey = NULL;
  1294. BOOLEAN openedNetParamKey = FALSE;
  1295. DWORD type;
  1296. PUCHAR salt = NULL;
  1297. DWORD saltLength;
  1298. DWORD status;
  1299. #if CLUSTER_BETA
  1300. ClRtlLogPrint(LOG_NOISE,
  1301. "[NM] Querying multicast salt for "
  1302. "network %1!ws! from cluster database.\n",
  1303. networkId
  1304. );
  1305. #endif // CLUSTER_BETA
  1306. if (Network == NULL || NetworkKey == NULL) {
  1307. status = ERROR_INVALID_PARAMETER;
  1308. goto error_exit;
  1309. }
  1310. //
  1311. // Open the network parameters key, if necessary.
  1312. //
  1313. netParamKey = *NetworkParametersKey;
  1314. if (netParamKey == NULL) {
  1315. netParamKey = DmOpenKey(
  1316. NetworkKey,
  1317. CLUSREG_KEYNAME_PARAMETERS,
  1318. MAXIMUM_ALLOWED
  1319. );
  1320. if (netParamKey == NULL) {
  1321. status = GetLastError();
  1322. ClRtlLogPrint(LOG_NOISE,
  1323. "[NM] Failed to find Parameters key "
  1324. "for network %1!ws!, status %2!u!. Using default "
  1325. "multicast parameters.\n",
  1326. networkId, status
  1327. );
  1328. goto error_exit;
  1329. } else {
  1330. openedNetParamKey = TRUE;
  1331. }
  1332. }
  1333. //
  1334. // Allocate a buffer for the salt, if necessary.
  1335. //
  1336. salt = *Salt;
  1337. saltLength = *SaltLength;
  1338. if (salt != NULL && saltLength != sizeof(FILETIME)) {
  1339. MIDL_user_free(salt);
  1340. salt = NULL;
  1341. saltLength = 0;
  1342. *SaltLength = 0;
  1343. }
  1344. if (salt == NULL) {
  1345. saltLength = sizeof(FILETIME);
  1346. salt = MIDL_user_allocate(saltLength);
  1347. if (salt == NULL) {
  1348. status = ERROR_NOT_ENOUGH_MEMORY;
  1349. ClRtlLogPrint(LOG_UNUSUAL,
  1350. "[NM] Failed to allocate buffer for multicast "
  1351. "salt for network %1!ws!.\n",
  1352. networkId
  1353. );
  1354. goto error_exit;
  1355. }
  1356. }
  1357. //
  1358. // Query the salt value from the cluster database.
  1359. //
  1360. status = DmQueryValue(
  1361. netParamKey,
  1362. CLUSREG_NAME_NET_MULTICAST_KEY_SALT,
  1363. &type,
  1364. (LPBYTE) salt,
  1365. &saltLength
  1366. );
  1367. if (status != ERROR_SUCCESS) {
  1368. ClRtlLogPrint(LOG_UNUSUAL,
  1369. "[NM] Failed to read multicast key salt for "
  1370. "network %1!ws! from cluster database, "
  1371. "status %2!u!. Using default.\n",
  1372. networkId, status
  1373. );
  1374. goto error_exit;
  1375. } else if (type != REG_BINARY) {
  1376. ClRtlLogPrint(LOG_UNUSUAL,
  1377. "[NM] Unexpected type (%1!u!) for network "
  1378. "%2!ws! %3!ws!. Using default.\n",
  1379. type, networkId, CLUSREG_NAME_NET_MULTICAST_KEY_SALT
  1380. );
  1381. status = ERROR_DATATYPE_MISMATCH;
  1382. goto error_exit;
  1383. }
  1384. *NetworkParametersKey = netParamKey;
  1385. netParamKey = NULL;
  1386. *Salt = salt;
  1387. salt = NULL;
  1388. *SaltLength = saltLength;
  1389. #if CLUSTER_BETA
  1390. //
  1391. // Display the salt.
  1392. //
  1393. {
  1394. LPWSTR displayBuf = NULL;
  1395. displayBuf = NmpCreateLogString(*Salt, *SaltLength);
  1396. if (displayBuf != NULL) {
  1397. ClRtlLogPrint(LOG_NOISE,
  1398. "[NM] Found multicast key salt (length %1!u!): %2!ws!.\n",
  1399. saltLength, displayBuf
  1400. );
  1401. LocalFree(displayBuf);
  1402. }
  1403. }
  1404. #endif // CLUSTER_BETA
  1405. error_exit:
  1406. if (openedNetParamKey && netParamKey != NULL) {
  1407. DmCloseKey(netParamKey);
  1408. netParamKey = NULL;
  1409. }
  1410. if (salt != NULL) {
  1411. MIDL_user_free(salt);
  1412. salt = NULL;
  1413. }
  1414. return(status);
  1415. } // NmpQueryMulticastKeySalt
  1416. DWORD
  1417. NmpGenerateMulticastKeySalt(
  1418. IN PNM_NETWORK Network,
  1419. IN OUT PVOID * Salt,
  1420. IN OUT ULONG * SaltLength
  1421. )
  1422. /*++
  1423. Routine Description:
  1424. Generates a default multicast key salt.
  1425. Notes:
  1426. Must not be called with NM lock held.
  1427. --*/
  1428. {
  1429. LPCWSTR networkId = OmObjectId(Network);
  1430. HDMKEY netParamKey = NULL;
  1431. DWORD createDisposition;
  1432. PUCHAR salt;
  1433. DWORD saltLength;
  1434. DWORD status;
  1435. #if CLUSTER_BETA
  1436. ClRtlLogPrint(LOG_NOISE,
  1437. "[NM] Generating multicast key salt for "
  1438. "network %1!ws!.\n",
  1439. networkId
  1440. );
  1441. #endif // CLUSTER_BETA
  1442. //
  1443. // Allocate a buffer for the salt, if necessary.
  1444. //
  1445. salt = *Salt;
  1446. saltLength = *SaltLength;
  1447. if (salt != NULL && saltLength != sizeof(FILETIME)) {
  1448. MIDL_user_free(salt);
  1449. salt = NULL;
  1450. saltLength = 0;
  1451. *SaltLength = 0;
  1452. }
  1453. if (salt == NULL) {
  1454. saltLength = sizeof(FILETIME);
  1455. salt = MIDL_user_allocate(saltLength);
  1456. if (salt == NULL) {
  1457. status = ERROR_NOT_ENOUGH_MEMORY;
  1458. ClRtlLogPrint(LOG_UNUSUAL,
  1459. "[NM] Failed to allocate buffer for multicast "
  1460. "salt for network %1!ws!.\n",
  1461. networkId
  1462. );
  1463. goto error_exit;
  1464. }
  1465. }
  1466. //
  1467. // Create the salt. Use the current time.
  1468. //
  1469. GetSystemTimeAsFileTime((LPFILETIME) salt);
  1470. *Salt = salt;
  1471. salt = NULL;
  1472. *SaltLength = saltLength;
  1473. status = ERROR_SUCCESS;
  1474. #if CLUSTER_BETA
  1475. //
  1476. // Display the salt.
  1477. //
  1478. {
  1479. LPWSTR displayBuf = NULL;
  1480. displayBuf = NmpCreateLogString(*Salt, *SaltLength);
  1481. if (displayBuf != NULL) {
  1482. ClRtlLogPrint(LOG_NOISE,
  1483. "[NM] Generated multicast key salt (length %1!u!): %2!ws!.\n",
  1484. saltLength, displayBuf
  1485. );
  1486. LocalFree(displayBuf);
  1487. }
  1488. }
  1489. #endif // CLUSTER_BETA
  1490. error_exit:
  1491. if (salt != NULL) {
  1492. MIDL_user_free(salt);
  1493. salt = NULL;
  1494. }
  1495. return(status);
  1496. } // NmpGenerateMulticastKeySalt
  1497. DWORD
  1498. NmpMulticastNotifyConfigChange(
  1499. IN PNM_NETWORK Network,
  1500. IN HDMKEY NetworkKey,
  1501. IN OUT HDMKEY * NetworkParametersKey,
  1502. IN PNM_NETWORK_MULTICAST_PARAMETERS Parameters,
  1503. IN PVOID PropBuffer,
  1504. IN DWORD PropBufferSize
  1505. )
  1506. /*++
  1507. Routine Description:
  1508. Notify other cluster nodes of the new multicast
  1509. configuration parameters by initiating a GUM
  1510. update.
  1511. If this is a manual update, there may be other
  1512. properties to distribute in the GUM update.
  1513. Notes:
  1514. Cannot be called with NM lock held.
  1515. --*/
  1516. {
  1517. DWORD status = ERROR_SUCCESS;
  1518. LPCWSTR networkId = OmObjectId(Network);
  1519. PNM_NETWORK_MULTICAST_UPDATE update = NULL;
  1520. DWORD updateSize = 0;
  1521. ClRtlLogPrint(LOG_NOISE,
  1522. "[NM] Notifying other nodes of type %1!u! multicast "
  1523. "reconfiguration for network %2!ws!.\n",
  1524. Parameters->ConfigType, networkId
  1525. );
  1526. status = NmpMulticastCreateUpdateFromParameters(
  1527. Network,
  1528. Parameters,
  1529. &update,
  1530. &updateSize
  1531. );
  1532. if (status != ERROR_SUCCESS) {
  1533. ClRtlLogPrint(LOG_UNUSUAL,
  1534. "[NM] Failed to build GUM update for "
  1535. "multicast configuration of network %1!ws!, "
  1536. "status %2!u!.\n",
  1537. networkId, status
  1538. );
  1539. goto error_exit;
  1540. }
  1541. //
  1542. // BUGBUG: Disseminate database updates to downlevel
  1543. // nodes!
  1544. //
  1545. //
  1546. // Send junk if the prop buffer is empty.
  1547. //
  1548. if (PropBuffer == NULL || PropBufferSize == 0) {
  1549. PropBuffer = &updateSize;
  1550. PropBufferSize = sizeof(updateSize);
  1551. }
  1552. //
  1553. // Send the update.
  1554. //
  1555. status = GumSendUpdateEx(
  1556. GumUpdateMembership,
  1557. NmUpdateSetNetworkMulticastConfiguration,
  1558. 4,
  1559. NM_WCSLEN(networkId),
  1560. networkId,
  1561. updateSize,
  1562. update,
  1563. PropBufferSize,
  1564. PropBuffer,
  1565. sizeof(PropBufferSize),
  1566. &PropBufferSize
  1567. );
  1568. if (status != ERROR_SUCCESS) {
  1569. ClRtlLogPrint(LOG_UNUSUAL,
  1570. "[NM] Failed to send GUM update for "
  1571. "multicast configuration of network %1!ws!, "
  1572. "status %2!u!.\n",
  1573. networkId, status
  1574. );
  1575. goto error_exit;
  1576. }
  1577. error_exit:
  1578. if (update != NULL) {
  1579. MIDL_user_free(update);
  1580. update = NULL;
  1581. }
  1582. return(status);
  1583. } // NmpMulticastNotifyConfigChange
  1584. DWORD
  1585. NmpWriteMulticastParameters(
  1586. IN PNM_NETWORK Network,
  1587. IN HDMKEY NetworkKey,
  1588. IN HDMKEY NetworkParametersKey,
  1589. IN HLOCALXSACTION Xaction,
  1590. IN PNM_NETWORK_MULTICAST_PARAMETERS Parameters
  1591. )
  1592. {
  1593. DWORD status = ERROR_SUCCESS;
  1594. LPCWSTR networkId = OmObjectId(Network);
  1595. LPWSTR failValueName = NULL;
  1596. CL_ASSERT(NetworkKey != NULL);
  1597. CL_ASSERT(NetworkParametersKey != NULL);
  1598. CL_ASSERT(Xaction != NULL);
  1599. #if CLUSTER_BETA
  1600. ClRtlLogPrint(LOG_NOISE,
  1601. "[NM] Writing multicast parameters for "
  1602. "network %1!ws! to cluster database.\n",
  1603. networkId
  1604. );
  1605. #endif // CLUSTER_BETA
  1606. //
  1607. // Address.
  1608. //
  1609. if (Parameters->Address != NULL) {
  1610. status = DmLocalSetValue(
  1611. Xaction,
  1612. NetworkParametersKey,
  1613. CLUSREG_NAME_NET_MULTICAST_ADDRESS,
  1614. REG_SZ,
  1615. (BYTE *) Parameters->Address,
  1616. NM_WCSLEN(Parameters->Address)
  1617. );
  1618. if (status != ERROR_SUCCESS) {
  1619. failValueName = CLUSREG_NAME_NET_MULTICAST_ADDRESS;
  1620. goto error_exit;
  1621. }
  1622. }
  1623. //
  1624. // Salt.
  1625. //
  1626. if (Parameters->Salt != NULL) {
  1627. status = DmLocalSetValue(
  1628. Xaction,
  1629. NetworkParametersKey,
  1630. CLUSREG_NAME_NET_MULTICAST_KEY_SALT,
  1631. REG_BINARY,
  1632. (BYTE *) Parameters->Salt,
  1633. Parameters->SaltLength
  1634. );
  1635. if (status != ERROR_SUCCESS) {
  1636. failValueName = CLUSREG_NAME_NET_MULTICAST_KEY_SALT;
  1637. goto error_exit;
  1638. }
  1639. }
  1640. //
  1641. // Lease server address.
  1642. //
  1643. if (Parameters->LeaseServer != NULL) {
  1644. status = DmLocalSetValue(
  1645. Xaction,
  1646. NetworkParametersKey,
  1647. CLUSREG_NAME_NET_MCAST_SERVER_ADDRESS,
  1648. REG_SZ,
  1649. (BYTE *) Parameters->LeaseServer,
  1650. NM_WCSLEN(Parameters->LeaseServer)
  1651. );
  1652. if (status != ERROR_SUCCESS) {
  1653. failValueName = CLUSREG_NAME_NET_MCAST_SERVER_ADDRESS;
  1654. goto error_exit;
  1655. }
  1656. }
  1657. //
  1658. // Client request id.
  1659. //
  1660. if (Parameters->LeaseRequestId.ClientUID != NULL &&
  1661. Parameters->LeaseRequestId.ClientUIDLength > 0) {
  1662. status = DmLocalSetValue(
  1663. Xaction,
  1664. NetworkParametersKey,
  1665. CLUSREG_NAME_NET_MCAST_REQUEST_ID,
  1666. REG_BINARY,
  1667. (BYTE *) Parameters->LeaseRequestId.ClientUID,
  1668. Parameters->LeaseRequestId.ClientUIDLength
  1669. );
  1670. if (status != ERROR_SUCCESS) {
  1671. failValueName = CLUSREG_NAME_NET_MCAST_REQUEST_ID;
  1672. goto error_exit;
  1673. }
  1674. }
  1675. //
  1676. // Lease obtained.
  1677. //
  1678. status = DmLocalSetValue(
  1679. Xaction,
  1680. NetworkParametersKey,
  1681. CLUSREG_NAME_NET_MCAST_LEASE_OBTAINED,
  1682. REG_DWORD,
  1683. (BYTE *) &(Parameters->LeaseObtained),
  1684. sizeof(Parameters->LeaseObtained)
  1685. );
  1686. if (status != ERROR_SUCCESS) {
  1687. failValueName = CLUSREG_NAME_NET_MCAST_LEASE_OBTAINED;
  1688. goto error_exit;
  1689. }
  1690. //
  1691. // Lease expires.
  1692. //
  1693. status = DmLocalSetValue(
  1694. Xaction,
  1695. NetworkParametersKey,
  1696. CLUSREG_NAME_NET_MCAST_LEASE_EXPIRES,
  1697. REG_DWORD,
  1698. (BYTE *) &(Parameters->LeaseExpires),
  1699. sizeof(Parameters->LeaseExpires)
  1700. );
  1701. if (status != ERROR_SUCCESS) {
  1702. failValueName = CLUSREG_NAME_NET_MCAST_LEASE_EXPIRES;
  1703. goto error_exit;
  1704. }
  1705. //
  1706. // Config type.
  1707. //
  1708. status = DmLocalSetValue(
  1709. Xaction,
  1710. NetworkParametersKey,
  1711. CLUSREG_NAME_NET_MCAST_CONFIG_TYPE,
  1712. REG_DWORD,
  1713. (BYTE *) &(Parameters->ConfigType),
  1714. sizeof(Parameters->ConfigType)
  1715. );
  1716. if (status != ERROR_SUCCESS) {
  1717. failValueName = CLUSREG_NAME_NET_MCAST_CONFIG_TYPE;
  1718. goto error_exit;
  1719. }
  1720. error_exit:
  1721. if (status != ERROR_SUCCESS) {
  1722. ClRtlLogPrint(LOG_UNUSUAL,
  1723. "[NM] Failed to write %1!ws! value "
  1724. "for network %2!ws!, status %3!u!.\n",
  1725. failValueName, networkId, status
  1726. );
  1727. }
  1728. return(status);
  1729. } // NmpWriteMulticastParameters
  1730. DWORD
  1731. NmpMulticastEnumerateScopes(
  1732. IN BOOLEAN Requery,
  1733. OUT PMCAST_SCOPE_ENTRY * ScopeList,
  1734. OUT DWORD * ScopeCount
  1735. )
  1736. /*++
  1737. Routine Description:
  1738. Call MADCAP API to enumerate multicast scopes.
  1739. --*/
  1740. {
  1741. DWORD status;
  1742. PMCAST_SCOPE_ENTRY scopeList = NULL;
  1743. DWORD scopeListLength;
  1744. DWORD scopeCount = 0;
  1745. //
  1746. // Initialize MADCAP, if not done already.
  1747. //
  1748. if (!NmpMadcapClientInitialized) {
  1749. DWORD madcapVersion = MCAST_API_CURRENT_VERSION;
  1750. status = McastApiStartup(&madcapVersion);
  1751. if (status != ERROR_SUCCESS) {
  1752. ClRtlLogPrint(LOG_UNUSUAL,
  1753. "[NM] Failed to initialize MADCAP API, "
  1754. "status %1!u!.\n",
  1755. status
  1756. );
  1757. return(status);
  1758. }
  1759. NmpMadcapClientInitialized = TRUE;
  1760. }
  1761. //
  1762. // Enumerate the multicast scopes.
  1763. //
  1764. scopeList = NULL;
  1765. scopeListLength = 0;
  1766. do {
  1767. PVOID watchdogHandle;
  1768. //
  1769. // Set watchdog timer to try to catch bug 400242. Specify
  1770. // timeout of 5 minutes (in milliseconds).
  1771. //
  1772. watchdogHandle = ClRtlSetWatchdogTimer(
  1773. 5 * 60 * 1000,
  1774. L"McastEnumerateScopes (Bug 400242)"
  1775. );
  1776. if (watchdogHandle == NULL) {
  1777. ClRtlLogPrint(LOG_NOISE,
  1778. "[NM] Failed to set %1!u!ms watchdog timer for "
  1779. "McastEnumerateScopes.\n",
  1780. 5 * 60 * 1000
  1781. );
  1782. }
  1783. status = McastEnumerateScopes(
  1784. AF_INET,
  1785. Requery,
  1786. scopeList,
  1787. &scopeListLength,
  1788. &scopeCount
  1789. );
  1790. //
  1791. // Cancel watchdog timer.
  1792. //
  1793. if (watchdogHandle != NULL) {
  1794. ClRtlCancelWatchdogTimer(watchdogHandle);
  1795. }
  1796. if ( (scopeList == NULL && status == ERROR_SUCCESS) ||
  1797. (status == ERROR_MORE_DATA)
  1798. ) {
  1799. if (scopeList != NULL) {
  1800. LocalFree(scopeList);
  1801. }
  1802. scopeList = LocalAlloc(LMEM_FIXED, scopeListLength);
  1803. if (scopeList == NULL) {
  1804. ClRtlLogPrint(LOG_UNUSUAL,
  1805. "[NM] Failed to allocate multicast scope list "
  1806. "of length %1!u!.\n",
  1807. scopeListLength
  1808. );
  1809. status = ERROR_NOT_ENOUGH_MEMORY;
  1810. break;
  1811. } else {
  1812. //
  1813. // Call McastEnumerateScopes again with proper
  1814. // size scopeList buffer.
  1815. //
  1816. Requery = FALSE;
  1817. continue;
  1818. }
  1819. } else {
  1820. //
  1821. // McastEnumerateScopes failed with an unexpected
  1822. // error. Bail out.
  1823. //
  1824. break;
  1825. }
  1826. } while (TRUE);
  1827. if (status != ERROR_SUCCESS) {
  1828. if (scopeList != NULL) {
  1829. LocalFree(scopeList);
  1830. scopeList = NULL;
  1831. scopeCount = 0;
  1832. }
  1833. }
  1834. *ScopeList = scopeList;
  1835. *ScopeCount = scopeCount;
  1836. return(status);
  1837. } // NmpMulticastEnumerateScopes
  1838. DWORD
  1839. NmpRandomizeLeaseRenewTime(
  1840. IN PNM_NETWORK Network,
  1841. IN DWORD BaseRenewTime,
  1842. IN DWORD Window
  1843. )
  1844. /*++
  1845. Routine Description:
  1846. Randomizes the lease renew time within Window
  1847. on either side of BaseRenewTime.
  1848. Current algorithm favors the NM leader, which
  1849. gets BaseRenewTime. Other nodes are
  1850. spread out in the Window according to node id.
  1851. The nodes are grouped tighter as the number
  1852. of nodes grows, since the common case is only
  1853. a few nodes.
  1854. Arguments:
  1855. Network - network
  1856. BaseRenewTime - time when lease should be renewed
  1857. Window - period on either side of BaseRenewTime
  1858. during which lease could be renewed
  1859. Return value:
  1860. Randomized lease renew time.
  1861. --*/
  1862. {
  1863. DWORD result = 0;
  1864. DWORD interval, delta;
  1865. DWORD index;
  1866. static USHORT spread[] =
  1867. {0, 16, 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15};
  1868. if (BaseRenewTime == 0) {
  1869. result = 0;
  1870. goto error_exit;
  1871. }
  1872. if (Window == 0) {
  1873. result = BaseRenewTime;
  1874. goto error_exit;
  1875. }
  1876. interval = Window / ClusterDefaultMaxNodes;
  1877. if (NmpLeaderNodeId == NmLocalNodeId) {
  1878. result = BaseRenewTime;
  1879. } else {
  1880. if (interval == 0) {
  1881. result = BaseRenewTime + Window;
  1882. } else {
  1883. if (NmLocalNodeId > sizeof(spread)/sizeof(spread[0]) - 1) {
  1884. index = sizeof(spread)/sizeof(spread[0]) - 1;
  1885. } else {
  1886. index = NmLocalNodeId;
  1887. }
  1888. result = BaseRenewTime + spread[index] * interval;
  1889. }
  1890. }
  1891. error_exit:
  1892. return(result);
  1893. } // NmpRandomizeLeaseRenewTime
  1894. DWORD
  1895. NmpCalculateLeaseRenewTime(
  1896. IN PNM_NETWORK Network,
  1897. IN NM_MCAST_CONFIG ConfigType,
  1898. IN OUT time_t * LeaseObtained,
  1899. IN OUT time_t * LeaseExpires
  1900. )
  1901. /*++
  1902. Routine Description:
  1903. Determines when to schedule a lease renewal, based
  1904. on the lease obtained and expires times and whether
  1905. the current lease was obtained from a MADCAP server.
  1906. If the lease was obtained from a MADCAP server, the
  1907. policy mimics DHCP client renewal behavior. A
  1908. renewal is scheduled for half the time until the
  1909. lease expires. However, if the lease half-life is
  1910. less than the renewal threshold, renew at the lease
  1911. expiration time.
  1912. If the address was selected after a MADCAP timeout,
  1913. we still periodically query to make sure a MADCAP
  1914. server doesn't suddenly appear on the network. In
  1915. this case, LeaseExpires and LeaseObtained will be
  1916. garbage, and we need to fill them in.
  1917. If the address was configured by an administrator,
  1918. return 0, indicating that the timer should not be set.
  1919. Return value:
  1920. Relative NM ticks from current time that lease
  1921. renewal should be scheduled.
  1922. --*/
  1923. {
  1924. time_t currentTime;
  1925. time_t leaseExpires;
  1926. time_t leaseObtained;
  1927. time_t result = 0;
  1928. time_t window = 0;
  1929. time_t leaseHalfLife = 0;
  1930. DWORD dwResult = 0;
  1931. DWORD dwWindow = 0;
  1932. currentTime = time(NULL);
  1933. leaseExpires = *LeaseExpires;
  1934. leaseObtained = *LeaseObtained;
  1935. switch (ConfigType) {
  1936. case NmMcastConfigManual:
  1937. result = 0;
  1938. *LeaseObtained = 0;
  1939. *LeaseExpires = 0;
  1940. break;
  1941. case NmMcastConfigMadcap:
  1942. if (leaseExpires < currentTime) {
  1943. result = 1;
  1944. } else if (leaseExpires <= leaseObtained) {
  1945. result = 1;
  1946. } else {
  1947. leaseHalfLife = (leaseExpires - leaseObtained) / 2;
  1948. if (leaseHalfLife < NMP_MCAST_LEASE_RENEWAL_THRESHOLD) {
  1949. // The half life is too small.
  1950. result = leaseExpires - currentTime;
  1951. if (result == 0) {
  1952. result = 1;
  1953. }
  1954. window = result / 2;
  1955. } else {
  1956. // The half life is acceptable.
  1957. result = leaseHalfLife;
  1958. window = NMP_MCAST_LEASE_RENEWAL_WINDOW;
  1959. if (result + window > leaseExpires) {
  1960. window = leaseExpires - result;
  1961. }
  1962. }
  1963. }
  1964. break;
  1965. case NmMcastConfigAuto:
  1966. result = NMP_MADCAP_REQUERY_PERDIOD;
  1967. window = NMP_MCAST_LEASE_RENEWAL_WINDOW;
  1968. //
  1969. // Return the lease expiration time to be
  1970. // written into the cluster database.
  1971. //
  1972. *LeaseObtained = currentTime;
  1973. *LeaseExpires = currentTime + NMP_MADCAP_REQUERY_PERDIOD;
  1974. break;
  1975. default:
  1976. CL_ASSERT(FALSE);
  1977. result = 0;
  1978. break;
  1979. }
  1980. NMP_TIME_TO_DWORD(result, dwResult);
  1981. NMP_TIME_TO_DWORD(window, dwWindow);
  1982. dwResult = NmpRandomizeLeaseRenewTime(
  1983. Network,
  1984. NMP_MADCAP_TO_NM_TIME(dwResult),
  1985. NMP_MADCAP_TO_NM_TIME(dwWindow)
  1986. );
  1987. return(dwResult);
  1988. } // NmpCalculateLeaseRenewTime
  1989. VOID
  1990. NmpReportMulticastAddressLease(
  1991. IN PNM_NETWORK Network,
  1992. IN PNM_NETWORK_MULTICAST_PARAMETERS Parameters,
  1993. IN LPWSTR OldAddress
  1994. )
  1995. /*++
  1996. Routine Description:
  1997. Write an event log entry, if not repetitive,
  1998. reporting that a multicast address lease was
  1999. obtained.
  2000. The repetitive criteria is that the address
  2001. changed.
  2002. --*/
  2003. {
  2004. BOOLEAN writeLogEntry = FALSE;
  2005. LPCWSTR nodeName;
  2006. LPCWSTR networkName;
  2007. if (Parameters->Address == NULL || Parameters->LeaseServer == NULL) {
  2008. return;
  2009. }
  2010. if (OldAddress == NULL || wcscmp(Parameters->Address, OldAddress) != 0) {
  2011. networkName = OmObjectName(Network);
  2012. nodeName = OmObjectName(Network->LocalInterface->Node);
  2013. ClusterLogEvent4(
  2014. LOG_NOISE,
  2015. LOG_CURRENT_MODULE,
  2016. __FILE__,
  2017. __LINE__,
  2018. NM_EVENT_OBTAINED_MULTICAST_LEASE,
  2019. 0,
  2020. NULL,
  2021. nodeName,
  2022. Parameters->Address,
  2023. networkName,
  2024. Parameters->LeaseServer
  2025. );
  2026. }
  2027. return;
  2028. } // NmpReportMulticastAddressLease
  2029. VOID
  2030. NmpReportMulticastAddressChoice(
  2031. IN PNM_NETWORK Network,
  2032. IN LPWSTR Address,
  2033. IN LPWSTR OldAddress
  2034. )
  2035. /*++
  2036. Routine Description:
  2037. Write an event log entry, if not repetitive,
  2038. reporting that a multicast address was
  2039. automatically selected for this network.
  2040. The repetitive criteria is that our previous
  2041. config type was anything other than automatic
  2042. selection or the chosen address is different.
  2043. Notes:
  2044. Must not be called with NM lock held.
  2045. --*/
  2046. {
  2047. DWORD status;
  2048. LPCWSTR networkId = OmObjectId(Network);
  2049. HDMKEY networkKey = NULL;
  2050. HDMKEY netParamKey = NULL;
  2051. NM_MCAST_CONFIG configType;
  2052. BOOLEAN writeLogEntry = FALSE;
  2053. LPCWSTR nodeName;
  2054. LPCWSTR networkName;
  2055. if (Address == NULL) {
  2056. writeLogEntry = FALSE;
  2057. goto error_exit;
  2058. }
  2059. if (OldAddress == NULL || wcscmp(Address, OldAddress) != 0) {
  2060. writeLogEntry = TRUE;
  2061. }
  2062. if (!writeLogEntry) {
  2063. //
  2064. // Open the network key.
  2065. //
  2066. networkKey = DmOpenKey(
  2067. DmNetworksKey,
  2068. networkId,
  2069. MAXIMUM_ALLOWED
  2070. );
  2071. if (networkKey == NULL) {
  2072. status = GetLastError();
  2073. ClRtlLogPrint(LOG_UNUSUAL,
  2074. "[NM] Failed to open key for network %1!ws!, "
  2075. "status %2!u!\n",
  2076. networkId, status
  2077. );
  2078. goto error_exit;
  2079. }
  2080. status = NmpQueryMulticastConfigType(
  2081. Network,
  2082. networkKey,
  2083. &netParamKey,
  2084. &configType
  2085. );
  2086. if (status != ERROR_SUCCESS) {
  2087. ClRtlLogPrint(LOG_UNUSUAL,
  2088. "[NM] Failed to query multicast config type "
  2089. "for network %1!ws!, status %2!u!\n",
  2090. networkId, status
  2091. );
  2092. goto error_exit;
  2093. }
  2094. if (configType != NmMcastConfigAuto) {
  2095. writeLogEntry = TRUE;
  2096. }
  2097. }
  2098. if (writeLogEntry) {
  2099. networkName = OmObjectName(Network);
  2100. nodeName = OmObjectName(Network->LocalInterface->Node);
  2101. CsLogEvent3(
  2102. LOG_NOISE,
  2103. NM_EVENT_MULTICAST_ADDRESS_CHOICE,
  2104. nodeName,
  2105. Address,
  2106. networkName
  2107. );
  2108. }
  2109. error_exit:
  2110. if (networkKey != NULL) {
  2111. DmCloseKey(networkKey);
  2112. networkKey = NULL;
  2113. }
  2114. if (netParamKey != NULL) {
  2115. DmCloseKey(netParamKey);
  2116. netParamKey = NULL;
  2117. }
  2118. return;
  2119. } // NmpReportMulticastAddressChoice
  2120. VOID
  2121. NmpReportMulticastAddressFailure(
  2122. IN PNM_NETWORK Network,
  2123. IN DWORD Error
  2124. )
  2125. /*++
  2126. Routine Description:
  2127. Write an event log entry reporting failure
  2128. to obtain a multicast address for specified
  2129. network with specified error.
  2130. --*/
  2131. {
  2132. LPCWSTR nodeName = OmObjectName(Network->LocalInterface->Node);
  2133. LPCWSTR networkName = OmObjectName(Network);
  2134. WCHAR errorString[12];
  2135. wsprintfW(&(errorString[0]), L"%u", Error);
  2136. CsLogEvent3(
  2137. LOG_UNUSUAL,
  2138. NM_EVENT_MULTICAST_ADDRESS_FAILURE,
  2139. nodeName,
  2140. networkName,
  2141. errorString
  2142. );
  2143. return;
  2144. } // NmpReportMulticastAddressFailure
  2145. DWORD
  2146. NmpGetMulticastAddressSelectionRange(
  2147. IN PNM_NETWORK Network,
  2148. IN HDMKEY NetworkKey,
  2149. IN OUT HDMKEY * NetworkParametersKey,
  2150. OUT ULONG * RangeLower,
  2151. OUT ULONG * RangeUpper
  2152. )
  2153. /*++
  2154. Routine Description:
  2155. Queries the cluster database to determine if a selection
  2156. range has been configured. If both lower and upper bounds
  2157. of range are valid, returns that range. Otherwise, returns
  2158. default range.
  2159. Notes:
  2160. Must not be called with NM lock held.
  2161. --*/
  2162. {
  2163. DWORD status;
  2164. LPCWSTR networkId = OmObjectId(Network);
  2165. HDMKEY netParamKey = NULL;
  2166. BOOLEAN openedNetParamKey = FALSE;
  2167. LPWSTR addr = NULL;
  2168. DWORD addrLen;
  2169. DWORD size;
  2170. DWORD hllower, hlupper;
  2171. if (Network == NULL || NetworkKey == NULL) {
  2172. status = ERROR_INVALID_PARAMETER;
  2173. goto error_exit;
  2174. }
  2175. #if CLUSTER_BETA
  2176. ClRtlLogPrint(LOG_NOISE,
  2177. "[NM] Querying multicast address selection range "
  2178. "for network %1!ws! from cluster database.\n",
  2179. networkId
  2180. );
  2181. #endif // CLUSTER_BETA
  2182. //
  2183. // Open the network parameters key, if necessary.
  2184. //
  2185. netParamKey = *NetworkParametersKey;
  2186. if (netParamKey == NULL) {
  2187. netParamKey = DmOpenKey(
  2188. NetworkKey,
  2189. CLUSREG_KEYNAME_PARAMETERS,
  2190. MAXIMUM_ALLOWED
  2191. );
  2192. if (netParamKey == NULL) {
  2193. status = GetLastError();
  2194. #if CLUSTER_BETA
  2195. ClRtlLogPrint(LOG_NOISE,
  2196. "[NM] Failed to find Parameters key "
  2197. "for network %1!ws!, status %2!u!. "
  2198. "Using default multicast address range.\n",
  2199. networkId, status
  2200. );
  2201. #endif // CLUSTER_BETA
  2202. goto usedefault;
  2203. } else {
  2204. openedNetParamKey = TRUE;
  2205. }
  2206. }
  2207. //
  2208. // Query for the lower bound of the range.
  2209. //
  2210. addr = NULL;
  2211. addrLen = 0;
  2212. size = 0;
  2213. status = NmpQueryString(
  2214. netParamKey,
  2215. CLUSREG_NAME_NET_MCAST_RANGE_LOWER,
  2216. REG_SZ,
  2217. &addr,
  2218. &addrLen,
  2219. &size
  2220. );
  2221. if (status != ERROR_SUCCESS) {
  2222. ClRtlLogPrint(LOG_NOISE,
  2223. "[NM] Failed to read lower bound of "
  2224. "multicast address selection range for "
  2225. "network %1!ws! from cluster database, "
  2226. "status %2!u!. Using default.\n",
  2227. networkId, status
  2228. );
  2229. goto usedefault;
  2230. }
  2231. status = ClRtlTcpipStringToAddress(addr, RangeLower);
  2232. if (status != ERROR_SUCCESS) {
  2233. ClRtlLogPrint(LOG_NOISE,
  2234. "[NM] Failed to convert lower bound of "
  2235. "multicast address selection range %1!ws! for "
  2236. "network %2!ws! into TCP/IP address, "
  2237. "status %3!u!. Using default.\n",
  2238. addr, networkId, status
  2239. );
  2240. goto usedefault;
  2241. }
  2242. hllower = ntohl(*RangeLower);
  2243. if (!IN_CLASSD(hllower)) {
  2244. ClRtlLogPrint(LOG_NOISE,
  2245. "[NM] Lower bound of multicast address "
  2246. "selection range %1!ws! for network %2!ws! "
  2247. "is not a class D IPv4 address. "
  2248. "Using default.\n",
  2249. addr, networkId
  2250. );
  2251. goto usedefault;
  2252. }
  2253. //
  2254. // Query for the upper bound of the range.
  2255. //
  2256. size = 0;
  2257. status = NmpQueryString(
  2258. netParamKey,
  2259. CLUSREG_NAME_NET_MCAST_RANGE_UPPER,
  2260. REG_SZ,
  2261. &addr,
  2262. &addrLen,
  2263. &size
  2264. );
  2265. if (status != ERROR_SUCCESS) {
  2266. ClRtlLogPrint(LOG_NOISE,
  2267. "[NM] Failed to read upper bound of "
  2268. "multicast address selection range for "
  2269. "network %1!ws! from cluster database, "
  2270. "status %2!u!. Using default.\n",
  2271. networkId, status
  2272. );
  2273. goto usedefault;
  2274. }
  2275. status = ClRtlTcpipStringToAddress(addr, RangeUpper);
  2276. if (status != ERROR_SUCCESS) {
  2277. ClRtlLogPrint(LOG_NOISE,
  2278. "[NM] Failed to convert upper bound of "
  2279. "multicast address selection range %1!ws! for "
  2280. "network %2!ws! into TCP/IP address, "
  2281. "status %3!u!. Using default.\n",
  2282. addr, networkId, status
  2283. );
  2284. goto usedefault;
  2285. }
  2286. hlupper = ntohl(*RangeUpper);
  2287. if (!IN_CLASSD(hlupper)) {
  2288. ClRtlLogPrint(LOG_NOISE,
  2289. "[NM] Upper bound of multicast address "
  2290. "selection range %1!ws! for network %2!ws! "
  2291. "is not a class D IPv4 address. "
  2292. "Using default.\n",
  2293. addr, networkId
  2294. );
  2295. goto usedefault;
  2296. }
  2297. //
  2298. // Make sure it's a legitimate range.
  2299. //
  2300. if (hllower >= hlupper) {
  2301. ClRtlLogPrint(LOG_NOISE,
  2302. "[NM] Multicast address selection range "
  2303. "[%1!u!.%2!u!.%3!u!.%4!u!, %5!u!.%6!u!.%7!u!.%8!u!] "
  2304. "for network %2!ws! is not valid. "
  2305. "Using default.\n",
  2306. NmpIpAddrPrintArgs(*RangeLower),
  2307. NmpIpAddrPrintArgs(*RangeUpper), networkId
  2308. );
  2309. goto usedefault;
  2310. }
  2311. status = ERROR_SUCCESS;
  2312. goto error_exit;
  2313. usedefault:
  2314. *RangeLower = NMP_MCAST_DEFAULT_RANGE_LOWER;
  2315. *RangeUpper = NMP_MCAST_DEFAULT_RANGE_UPPER;
  2316. status = ERROR_SUCCESS;
  2317. error_exit:
  2318. if (status == ERROR_SUCCESS) {
  2319. ClRtlLogPrint(LOG_NOISE,
  2320. "[NM] Using multicast address selection range "
  2321. "[%1!u!.%2!u!.%3!u!.%4!u!, %5!u!.%6!u!.%7!u!.%8!u!] "
  2322. "for network %9!ws! in cluster database.\n",
  2323. NmpIpAddrPrintArgs(*RangeLower),
  2324. NmpIpAddrPrintArgs(*RangeUpper), networkId
  2325. );
  2326. *NetworkParametersKey = netParamKey;
  2327. netParamKey = NULL;
  2328. }
  2329. if (openedNetParamKey && netParamKey != NULL) {
  2330. DmCloseKey(netParamKey);
  2331. netParamKey = NULL;
  2332. }
  2333. if (addr != NULL) {
  2334. MIDL_user_free(addr);
  2335. addr = NULL;
  2336. }
  2337. return(status);
  2338. } // NmpGetMulticastAddressSelectionRange
  2339. DWORD
  2340. NmpMulticastExcludeRange(
  2341. IN OUT PLIST_ENTRY SelectionRange,
  2342. IN DWORD HlLower,
  2343. IN DWORD HlUpper
  2344. )
  2345. /*++
  2346. Routine Description:
  2347. Exclude range defined by (HlLower, HlUpper) from
  2348. list of selection intervals in SelectionRange.
  2349. Arguments:
  2350. SelectionRange - sorted list of non-overlapping
  2351. selection intervals
  2352. HlLower - lower bound of exclusion in host format
  2353. HlUpper - upper bound of exclusion in host format
  2354. --*/
  2355. {
  2356. PNM_MCAST_RANGE_INTERVAL interval;
  2357. PNM_MCAST_RANGE_INTERVAL newInterval;
  2358. PLIST_ENTRY entry;
  2359. // Determine if the exclusion overlaps with any interval.
  2360. for (entry = SelectionRange->Flink;
  2361. entry != SelectionRange;
  2362. entry = entry->Flink) {
  2363. interval = CONTAINING_RECORD(
  2364. entry,
  2365. NM_MCAST_RANGE_INTERVAL,
  2366. Linkage
  2367. );
  2368. if (HlLower < interval->hlLower &&
  2369. HlUpper < interval->hlUpper) {
  2370. // Exclusion completely misses below interval.
  2371. // Since list is sorted, there is no possibility
  2372. // of a matching interval farther down list.
  2373. break;
  2374. }
  2375. else if (HlLower > interval->hlUpper) {
  2376. // Exclusion completely misses above interval.
  2377. // There might be matching intervals later
  2378. // in sorted list.
  2379. }
  2380. else if (HlLower <= interval->hlLower &&
  2381. HlUpper >= interval->hlUpper) {
  2382. // Exclusion completely covers interval.
  2383. // Remove interval.
  2384. RemoveEntryList(entry);
  2385. }
  2386. else if (HlLower > interval->hlLower &&
  2387. HlUpper < interval->hlUpper) {
  2388. // Exclusion splits interval.
  2389. newInterval = LocalAlloc(LMEM_FIXED, sizeof(*newInterval));
  2390. if (newInterval == NULL) {
  2391. return(ERROR_NOT_ENOUGH_MEMORY);
  2392. }
  2393. newInterval->hlLower = HlUpper+1;
  2394. newInterval->hlUpper = interval->hlUpper;
  2395. interval->hlUpper = HlLower-1;
  2396. // Insert the new interval after the current interval
  2397. InsertHeadList(entry, &newInterval->Linkage);
  2398. // We can skip the new interval because we already
  2399. // know how it compares to the exclusion.
  2400. entry = &newInterval->Linkage;
  2401. continue;
  2402. }
  2403. else if (HlLower <= interval->hlLower) {
  2404. // Exclusion overlaps lower part of interval. Shrink
  2405. // interval from below.
  2406. interval->hlLower = HlUpper + 1;
  2407. }
  2408. else {
  2409. // Exclusion overlaps upper part of interval. Shrink
  2410. // interval from above.
  2411. interval->hlUpper = HlLower - 1;
  2412. }
  2413. }
  2414. return(ERROR_SUCCESS);
  2415. } // NmpMulticastExcludeRange
  2416. BOOLEAN
  2417. NmpMulticastAddressInRange(
  2418. IN PLIST_ENTRY SelectionRange,
  2419. IN LPWSTR McastAddress
  2420. )
  2421. /*++
  2422. Routine Description:
  2423. Determines if McastAddress is in one of range intervals.
  2424. --*/
  2425. {
  2426. DWORD mcastAddress;
  2427. PNM_MCAST_RANGE_INTERVAL interval;
  2428. PLIST_ENTRY entry;
  2429. // Convert the address from a string into an address.
  2430. if (ClRtlTcpipStringToAddress(
  2431. McastAddress,
  2432. &mcastAddress
  2433. ) != ERROR_SUCCESS) {
  2434. return(FALSE);
  2435. }
  2436. mcastAddress = ntohl(mcastAddress);
  2437. // Walk the list of intervals.
  2438. for (entry = SelectionRange->Flink;
  2439. entry != SelectionRange;
  2440. entry = entry->Flink) {
  2441. interval = CONTAINING_RECORD(
  2442. entry,
  2443. NM_MCAST_RANGE_INTERVAL,
  2444. Linkage
  2445. );
  2446. if (mcastAddress >= interval->hlLower &&
  2447. mcastAddress <= interval->hlUpper) {
  2448. return(TRUE);
  2449. }
  2450. else if (mcastAddress < interval->hlLower) {
  2451. // Address is below current interval.
  2452. // Since interval list is sorted in
  2453. // increasing order, there is no chance
  2454. // of a match later in list.
  2455. break;
  2456. }
  2457. }
  2458. return(FALSE);
  2459. } // NmpMulticastAddressInRange
  2460. DWORD
  2461. NmpMulticastAddressRangeSize(
  2462. IN PLIST_ENTRY SelectionRange
  2463. )
  2464. /*++
  2465. Routine Description:
  2466. Returns size of selection range.
  2467. --*/
  2468. {
  2469. PNM_MCAST_RANGE_INTERVAL interval;
  2470. PLIST_ENTRY entry;
  2471. DWORD size = 0;
  2472. // Walk the list of intervals.
  2473. for (entry = SelectionRange->Flink;
  2474. entry != SelectionRange;
  2475. entry = entry->Flink) {
  2476. interval = CONTAINING_RECORD(
  2477. entry,
  2478. NM_MCAST_RANGE_INTERVAL,
  2479. Linkage
  2480. );
  2481. size += NmpMulticastRangeIntervalSize(interval);
  2482. }
  2483. return(size);
  2484. } // NmpMulticastAddressRangeSize
  2485. DWORD
  2486. NmpMulticastRangeOffsetToAddress(
  2487. IN PLIST_ENTRY SelectionRange,
  2488. IN DWORD Offset
  2489. )
  2490. /*++
  2491. Routine Description:
  2492. Returns the address that is Offset into the
  2493. SelectionRange. The address is returned in
  2494. host format.
  2495. If SelectionRange is empty, returns 0.
  2496. If Offset falls outside of non-empty range,
  2497. returns upper or lower boundary of selection
  2498. range.
  2499. --*/
  2500. {
  2501. PNM_MCAST_RANGE_INTERVAL interval;
  2502. PLIST_ENTRY entry;
  2503. DWORD address = 0;
  2504. // Walk the list of intervals.
  2505. for (entry = SelectionRange->Flink;
  2506. entry != SelectionRange;
  2507. entry = entry->Flink) {
  2508. interval = CONTAINING_RECORD(
  2509. entry,
  2510. NM_MCAST_RANGE_INTERVAL,
  2511. Linkage
  2512. );
  2513. address = interval->hlLower;
  2514. if (address + Offset <= interval->hlUpper) {
  2515. address = address + Offset;
  2516. break;
  2517. } else {
  2518. address = interval->hlUpper;
  2519. Offset -= NmpMulticastRangeIntervalSize(interval);
  2520. }
  2521. }
  2522. return(address);
  2523. } // NmpMulticastRangeOffsetToAddress
  2524. VOID
  2525. NmpMulticastFreeSelectionRange(
  2526. IN PLIST_ENTRY SelectionRange
  2527. )
  2528. {
  2529. PNM_MCAST_RANGE_INTERVAL interval;
  2530. PLIST_ENTRY entry;
  2531. while (!IsListEmpty(SelectionRange)) {
  2532. entry = RemoveHeadList(SelectionRange);
  2533. interval = CONTAINING_RECORD(
  2534. entry,
  2535. NM_MCAST_RANGE_INTERVAL,
  2536. Linkage
  2537. );
  2538. LocalFree(interval);
  2539. }
  2540. return;
  2541. } // NmpMulticastFreeSelectionRange
  2542. DWORD
  2543. NmpChooseMulticastAddress(
  2544. IN PNM_NETWORK Network,
  2545. OUT PNM_NETWORK_MULTICAST_PARAMETERS Parameters
  2546. )
  2547. /*++
  2548. Routine Description:
  2549. Choose a default multicast address and fill in
  2550. Parameters appropriately.
  2551. If there is already a valid multicast address in
  2552. the selection range stored in the cluster database,
  2553. continue to use it.
  2554. If there is not already a valid multicast address,
  2555. choose an address within the multicast address range
  2556. by hashing on the last few bytes of the network id
  2557. GUID.
  2558. Arguments:
  2559. Network - network address is being chosen for
  2560. Parameters - configuration parameters with new address
  2561. --*/
  2562. {
  2563. LPCWSTR networkId = OmObjectId(Network);
  2564. DWORD status = ERROR_SUCCESS;
  2565. HDMKEY networkKey = NULL;
  2566. HDMKEY netParamKey = NULL;
  2567. PMCAST_SCOPE_ENTRY scopeList = NULL;
  2568. DWORD scopeCount;
  2569. LIST_ENTRY selectionRange;
  2570. PNM_MCAST_RANGE_INTERVAL interval;
  2571. DWORD index;
  2572. DWORD hlLower;
  2573. DWORD hlUpper;
  2574. DWORD networkAddress;
  2575. DWORD networkSubnet;
  2576. UUID networkIdGuid;
  2577. DWORD rangeSize;
  2578. DWORD offset;
  2579. DWORD address;
  2580. LPWSTR mcastAddress = NULL;
  2581. DWORD mcastAddressLength = 0;
  2582. MCAST_CLIENT_UID requestId = { NULL, 0 };
  2583. InitializeListHead(&selectionRange);
  2584. ClRtlLogPrint(LOG_NOISE,
  2585. "[NM] Choosing multicast address for "
  2586. "network %1!ws!.\n",
  2587. networkId
  2588. );
  2589. networkKey = DmOpenKey(
  2590. DmNetworksKey,
  2591. networkId,
  2592. MAXIMUM_ALLOWED
  2593. );
  2594. if (networkKey == NULL) {
  2595. status = GetLastError();
  2596. ClRtlLogPrint(LOG_UNUSUAL,
  2597. "[NM] Failed to open key for network %1!ws!, "
  2598. "status %2!u!\n",
  2599. networkId, status
  2600. );
  2601. goto error_exit;
  2602. }
  2603. //
  2604. // Build an array of selection intervals. These are intervals
  2605. // in the IPv4 class D address space from which an address
  2606. // can be selected.
  2607. //
  2608. // Start with the entire range.
  2609. interval = LocalAlloc(LMEM_FIXED, sizeof(*interval));
  2610. if (interval == NULL) {
  2611. status = ERROR_NOT_ENOUGH_MEMORY;
  2612. goto error_exit;
  2613. }
  2614. InsertHeadList(&selectionRange, &interval->Linkage);
  2615. //
  2616. // Get the selection range.
  2617. //
  2618. status = NmpGetMulticastAddressSelectionRange(
  2619. Network,
  2620. networkKey,
  2621. &netParamKey,
  2622. &interval->hlLower,
  2623. &interval->hlUpper
  2624. );
  2625. if (status != ERROR_SUCCESS) {
  2626. ClRtlLogPrint(LOG_UNUSUAL,
  2627. "[NM] Failed to determine multicast "
  2628. "address selection range for network %1!ws!, "
  2629. "status %2!u!.\n",
  2630. networkId, status
  2631. );
  2632. goto error_exit;
  2633. }
  2634. interval->hlLower = ntohl(interval->hlLower);
  2635. interval->hlUpper = ntohl(interval->hlUpper);
  2636. //
  2637. // Process exclusions from the multicast address
  2638. // selection range, starting with well-known exclusions.
  2639. //
  2640. for (index = 0; index < NmpMulticastRestrictedRangeCount; index++) {
  2641. ClRtlLogPrint(LOG_NOISE,
  2642. "[NM] Excluding %1!ws! "
  2643. "[%2!u!.%3!u!.%4!u!.%5!u!, %6!u!.%7!u!.%8!u!.%9!u!] "
  2644. "from multicast address range for network %10!ws!.\n",
  2645. NmpMulticastRestrictedRange[index].Description,
  2646. NmpIpAddrPrintArgs(NmpMulticastRestrictedRange[index].Lower),
  2647. NmpIpAddrPrintArgs(NmpMulticastRestrictedRange[index].Upper),
  2648. networkId
  2649. );
  2650. // Convert the exclusion to host format.
  2651. hlLower = ntohl(NmpMulticastRestrictedRange[index].Lower);
  2652. hlUpper = ntohl(NmpMulticastRestrictedRange[index].Upper);
  2653. NmpMulticastExcludeRange(&selectionRange, hlLower, hlUpper);
  2654. // If the selection range is now empty, there is no point
  2655. // in examining other exclusions.
  2656. if (IsListEmpty(&selectionRange)) {
  2657. status = ERROR_INCORRECT_ADDRESS;
  2658. goto error_exit;
  2659. }
  2660. }
  2661. //
  2662. // Process multicast scopes as exclusions. Specifically, any
  2663. // scope whose interface matches this network is excluded
  2664. // because it is conceivable that machines on the network are
  2665. // already using addresses in these scopes.
  2666. //
  2667. status = ClRtlTcpipStringToAddress(
  2668. Network->Address,
  2669. &networkAddress
  2670. );
  2671. if (status != ERROR_SUCCESS) {
  2672. ClRtlLogPrint(LOG_UNUSUAL,
  2673. "[NM] Failed to convert network address string "
  2674. "%1!ws! into an IPv4 address, status %2!u!.\n",
  2675. Network->Address, status
  2676. );
  2677. goto error_exit;
  2678. }
  2679. status = ClRtlTcpipStringToAddress(
  2680. Network->AddressMask,
  2681. &networkSubnet
  2682. );
  2683. if (status != ERROR_SUCCESS) {
  2684. ClRtlLogPrint(LOG_UNUSUAL,
  2685. "[NM] Failed to convert network address mask string "
  2686. "%1!ws! into an IPv4 address, status %2!u!.\n",
  2687. Network->AddressMask, status
  2688. );
  2689. goto error_exit;
  2690. }
  2691. //
  2692. // Query multicast scopes to determine if we should
  2693. // exclude any addresses from the selection range.
  2694. //
  2695. status = NmpMulticastEnumerateScopes(
  2696. FALSE, // do not force requery
  2697. &scopeList,
  2698. &scopeCount
  2699. );
  2700. if (status != ERROR_SUCCESS) {
  2701. scopeCount = 0;
  2702. }
  2703. for (index = 0; index < scopeCount; index++) {
  2704. if (ClRtlAreTcpipAddressesOnSameSubnet(
  2705. networkAddress,
  2706. scopeList[index].ScopeCtx.Interface.IpAddrV4,
  2707. networkSubnet
  2708. )) {
  2709. ClRtlLogPrint(LOG_NOISE,
  2710. "[NM] Excluding MADCAP scope "
  2711. "[%1!u!.%2!u!.%3!u!.%4!u!, %5!u!.%6!u!.%7!u!.%8!u!] "
  2712. "from multicast address selection range for "
  2713. "network %9!ws!.\n",
  2714. NmpIpAddrPrintArgs(scopeList[index].ScopeCtx.ScopeID.IpAddrV4),
  2715. NmpIpAddrPrintArgs(scopeList[index].LastAddr.IpAddrV4),
  2716. networkId
  2717. );
  2718. hlLower = ntohl(scopeList[index].ScopeCtx.ScopeID.IpAddrV4);
  2719. hlUpper = ntohl(scopeList[index].LastAddr.IpAddrV4);
  2720. NmpMulticastExcludeRange(&selectionRange, hlLower, hlUpper);
  2721. // If the selection range is empty, there is no point
  2722. // in examining other exclusions.
  2723. if (IsListEmpty(&selectionRange)) {
  2724. status = ERROR_INCORRECT_ADDRESS;
  2725. goto error_exit;
  2726. }
  2727. }
  2728. }
  2729. //
  2730. // The range of intervals from which we can select an
  2731. // address is now constructed.
  2732. //
  2733. // Before choosing an address, see if there is already an
  2734. // old one in the database that matches the selection range.
  2735. //
  2736. status = NmpQueryMulticastAddress(
  2737. Network,
  2738. networkKey,
  2739. &netParamKey,
  2740. &mcastAddress,
  2741. &mcastAddressLength
  2742. );
  2743. if (status == ERROR_SUCCESS) {
  2744. //
  2745. // We found an address. See if it falls in the range.
  2746. //
  2747. if (!NmpMulticastAddressInRange(&selectionRange, mcastAddress)) {
  2748. //
  2749. // We can't use this address. Free the string.
  2750. //
  2751. MIDL_user_free(mcastAddress);
  2752. mcastAddress = NULL;
  2753. }
  2754. } else {
  2755. mcastAddress = NULL;
  2756. }
  2757. if (mcastAddress == NULL) {
  2758. //
  2759. // Calculate the size of the selection range.
  2760. //
  2761. rangeSize = NmpMulticastAddressRangeSize(&selectionRange);
  2762. //
  2763. // Calculate the range offset using the last DWORD of
  2764. // the network id GUID.
  2765. //
  2766. status = UuidFromString((LPWSTR)networkId, &networkIdGuid);
  2767. if (status == RPC_S_OK) {
  2768. offset = (*((PDWORD)&(networkIdGuid.Data4[4]))) % rangeSize;
  2769. } else {
  2770. offset = 0;
  2771. }
  2772. //
  2773. // Choose an address within the specified range.
  2774. //
  2775. address = NmpMulticastRangeOffsetToAddress(&selectionRange, offset);
  2776. CL_ASSERT(address != 0);
  2777. CL_ASSERT(IN_CLASSD(address));
  2778. address = htonl(address);
  2779. //
  2780. // Convert the address to a string.
  2781. //
  2782. status = ClRtlTcpipAddressToString(address, &mcastAddress);
  2783. if (status != ERROR_SUCCESS) {
  2784. ClRtlLogPrint(LOG_UNUSUAL,
  2785. "[NM] Failed to convert selected multicast "
  2786. "address %1!u!.%2!u!.%3!u!.%4!u! for "
  2787. "network %5!ws! to a TCP/IP "
  2788. "address string, status %6!u!.\n",
  2789. NmpIpAddrPrintArgs(address), networkId, status
  2790. );
  2791. goto error_exit;
  2792. }
  2793. }
  2794. //
  2795. // Build a parameters data structure for this address.
  2796. //
  2797. status = NmpMulticastCreateParameters(
  2798. 0, // disabled
  2799. mcastAddress,
  2800. NULL, // salt
  2801. 0, // salt length
  2802. NULL, // key
  2803. 0, // key length
  2804. 0, // lease obtained
  2805. 0, // lease expires (filled in below)
  2806. &requestId,
  2807. NmpNullMulticastAddress, // lease server
  2808. NmMcastConfigAuto,
  2809. Parameters
  2810. );
  2811. if (status != ERROR_SUCCESS) {
  2812. ClRtlLogPrint(LOG_UNUSUAL,
  2813. "[NM] Failed to build multicast parameters "
  2814. "for network %1!ws! after choosing address, "
  2815. "status %2!u!.\n",
  2816. networkId, status
  2817. );
  2818. goto error_exit;
  2819. }
  2820. //
  2821. // Calculate the lease renew time. We don't need
  2822. // the lease renew time right now, but a side
  2823. // effect of this routine is to ensure that the
  2824. // lease end time is set correctly (e.g. for
  2825. // manual or auto config).
  2826. //
  2827. NmpCalculateLeaseRenewTime(
  2828. Network,
  2829. NmMcastConfigAuto,
  2830. &Parameters->LeaseObtained,
  2831. &Parameters->LeaseExpires
  2832. );
  2833. ClRtlLogPrint(LOG_NOISE,
  2834. "[NM] Chose multicast address %1!ws! for "
  2835. "network %2!ws!.\n",
  2836. Parameters->Address, networkId
  2837. );
  2838. error_exit:
  2839. //
  2840. // If the list is empty, then the selection range
  2841. // is empty, and we could not choose an address.
  2842. //
  2843. if (IsListEmpty(&selectionRange)) {
  2844. CL_ASSERT(status != ERROR_SUCCESS);
  2845. ClRtlLogPrint(LOG_UNUSUAL,
  2846. "[NM] Multicast address selection range for "
  2847. "network %1!ws! is empty. Unable to select "
  2848. "a multicast address.\n",
  2849. networkId
  2850. );
  2851. } else {
  2852. NmpMulticastFreeSelectionRange(&selectionRange);
  2853. }
  2854. if (networkKey != NULL) {
  2855. DmCloseKey(networkKey);
  2856. networkKey = NULL;
  2857. }
  2858. if (netParamKey != NULL) {
  2859. DmCloseKey(netParamKey);
  2860. netParamKey = NULL;
  2861. }
  2862. if (scopeList != NULL) {
  2863. LocalFree(scopeList);
  2864. }
  2865. if (mcastAddress != NULL) {
  2866. MIDL_user_free(mcastAddress);
  2867. mcastAddress = NULL;
  2868. }
  2869. return(status);
  2870. } // NmpChooseMulticastAddress
  2871. VOID
  2872. NmpChooseBetterMulticastScope(
  2873. IN PIPNG_ADDRESS LocalAddress,
  2874. IN PIPNG_ADDRESS LocalMask,
  2875. IN PMCAST_SCOPE_ENTRY CurrentScope,
  2876. OUT BOOLEAN * CurrentCorrectInterface,
  2877. IN OUT PMCAST_SCOPE_ENTRY * BestScope
  2878. )
  2879. /*++
  2880. Routine Description:
  2881. Try to choose a good scope using the following criteria:
  2882. - the interface must match (same subnet) the network address.
  2883. - the scope must not be single-source (232.*.*.*), as defined
  2884. by the IANA
  2885. - aim for link-local
  2886. - aim for a scope with a large range, increasing the
  2887. probability that other clusters that may be on our subnet
  2888. are assigned different group addresses
  2889. - aim for the lowest TTL
  2890. Arguments:
  2891. LocalAddress - local address for network
  2892. LocalMask - subnet mask for network
  2893. CurrentScope - scope under consideration
  2894. CurrentCorrectInterface - indicates whether current scope
  2895. is on the same interface as the
  2896. local network interface
  2897. BestScope - current best scope (may be NULL)
  2898. Return value:
  2899. None.
  2900. --*/
  2901. {
  2902. BOOL bestLocal, currentLocal;
  2903. DWORD bestRange, currentRange;
  2904. *CurrentCorrectInterface = FALSE;
  2905. //
  2906. // This scope is not a candidate if it is not on
  2907. // the correct interface or if it is single-source.
  2908. //
  2909. if (!ClRtlAreTcpipAddressesOnSameSubnet(
  2910. CurrentScope->ScopeCtx.Interface.IpAddrV4,
  2911. LocalAddress->IpAddrV4,
  2912. LocalMask->IpAddrV4
  2913. )) {
  2914. return;
  2915. }
  2916. *CurrentCorrectInterface = TRUE;
  2917. if (ClRtlAreTcpipAddressesOnSameSubnet(
  2918. CurrentScope->ScopeCtx.Interface.IpAddrV4,
  2919. NMP_SINGLE_SOURCE_SCOPE_ADDRESS,
  2920. NMP_SINGLE_SOURCE_SCOPE_MASK
  2921. )) {
  2922. return;
  2923. }
  2924. //
  2925. // If the current best scope is NULL, then this
  2926. // is the first match.
  2927. //
  2928. if (*BestScope == NULL) {
  2929. goto use_current;
  2930. }
  2931. //
  2932. // If the current scope is an administrative
  2933. // link-local and the current best is not,
  2934. // then the current scope wins.
  2935. //
  2936. bestLocal = ClRtlAreTcpipAddressesOnSameSubnet(
  2937. (*BestScope)->ScopeCtx.Interface.IpAddrV4,
  2938. NMP_LOCAL_SCOPE_ADDRESS,
  2939. NMP_LOCAL_SCOPE_MASK
  2940. );
  2941. currentLocal = ClRtlAreTcpipAddressesOnSameSubnet(
  2942. CurrentScope->ScopeCtx.Interface.IpAddrV4,
  2943. NMP_LOCAL_SCOPE_ADDRESS,
  2944. NMP_LOCAL_SCOPE_MASK
  2945. );
  2946. if (currentLocal && !bestLocal) {
  2947. goto use_current;
  2948. } else if (bestLocal && !currentLocal) {
  2949. return;
  2950. }
  2951. //
  2952. // If the current scope has a larger range than
  2953. // the current best, the current wins. The scope
  2954. // range is the last address minus the scope ID.
  2955. // We do not consider exclusions.
  2956. //
  2957. bestRange = (*BestScope)->LastAddr.IpAddrV4 -
  2958. (*BestScope)->ScopeCtx.ScopeID.IpAddrV4;
  2959. currentRange = CurrentScope->LastAddr.IpAddrV4 -
  2960. CurrentScope->ScopeCtx.ScopeID.IpAddrV4;
  2961. if (currentRange > bestRange) {
  2962. goto use_current;
  2963. } else if (bestRange > currentRange) {
  2964. return;
  2965. }
  2966. //
  2967. // If the current scope has a smaller TTL than
  2968. // the current best, the current wins.
  2969. //
  2970. if (CurrentScope->TTL < (*BestScope)->TTL) {
  2971. goto use_current;
  2972. } else if ((*BestScope)->TTL < CurrentScope->TTL) {
  2973. return;
  2974. }
  2975. //
  2976. // Found no reason to replace BestScope.
  2977. //
  2978. return;
  2979. use_current:
  2980. *BestScope = CurrentScope;
  2981. return;
  2982. } // NmpChooseBetterMulticastScope
  2983. DWORD
  2984. NmpFindMulticastScope(
  2985. IN PNM_NETWORK Network,
  2986. OUT PMCAST_SCOPE_CTX ScopeCtx,
  2987. OUT BOOLEAN * FoundInterfaceMatch
  2988. )
  2989. {
  2990. LPCWSTR networkId = OmObjectId(Network);
  2991. DWORD status;
  2992. PMCAST_SCOPE_ENTRY scopeList = NULL;
  2993. DWORD scopeCount;
  2994. DWORD scope;
  2995. PMCAST_SCOPE_ENTRY bestScope;
  2996. BOOLEAN currentCorrectInterface = FALSE;
  2997. BOOLEAN foundInterfaceMatch = FALSE;
  2998. IPNG_ADDRESS networkAddress;
  2999. IPNG_ADDRESS networkSubnet;
  3000. CL_ASSERT(ScopeCtx != NULL);
  3001. #if CLUSTER_BETA
  3002. ClRtlLogPrint(LOG_NOISE,
  3003. "[NM] Finding multicast scope for "
  3004. "network %1!ws!.\n",
  3005. networkId
  3006. );
  3007. #endif // CLUSTER_BETA
  3008. status = NmpMulticastEnumerateScopes(
  3009. TRUE, // force requery
  3010. &scopeList,
  3011. &scopeCount
  3012. );
  3013. if (status != ERROR_SUCCESS) {
  3014. if (status == ERROR_TIMEOUT || status == ERROR_NO_DATA) {
  3015. ClRtlLogPrint(LOG_NOISE,
  3016. "[NM] Request to MADCAP server failed while "
  3017. "enumerating scopes for network %1!ws! "
  3018. "(status %2!u!). Assuming there are currently "
  3019. "no MADCAP servers on the network.\n",
  3020. networkId, status
  3021. );
  3022. goto error_exit;
  3023. } else {
  3024. ClRtlLogPrint(LOG_UNUSUAL,
  3025. "[NM] Failed to enumerate multicast scopes for "
  3026. "network %1!ws!, status %2!u!.\n",
  3027. networkId, status
  3028. );
  3029. goto error_exit;
  3030. }
  3031. }
  3032. if (scopeCount == 0) {
  3033. ClRtlLogPrint(LOG_UNUSUAL,
  3034. "[NM] Zero multicast scopes located in enumeration "
  3035. "on network %1!ws!.\n",
  3036. networkId
  3037. );
  3038. goto error_exit;
  3039. }
  3040. //
  3041. // Try to choose the best scope among those enumerated.
  3042. //
  3043. // Note: this code is IPv4 specific in that it relies on the
  3044. // IP address fitting into a ULONG. It uses the
  3045. // IPNG_ADDRESS data structure only to work with the
  3046. // MADCAP API.
  3047. //
  3048. status = ClRtlTcpipStringToAddress(
  3049. Network->Address,
  3050. &(networkAddress.IpAddrV4)
  3051. );
  3052. if (status != ERROR_SUCCESS) {
  3053. ClRtlLogPrint(LOG_UNUSUAL,
  3054. "[NM] Failed to convert network address string "
  3055. "%1!ws! into an IPv4 address, status %2!u!.\n",
  3056. status
  3057. );
  3058. goto error_exit;
  3059. }
  3060. status = ClRtlTcpipStringToAddress(
  3061. Network->AddressMask,
  3062. &(networkSubnet.IpAddrV4)
  3063. );
  3064. if (status != ERROR_SUCCESS) {
  3065. ClRtlLogPrint(LOG_UNUSUAL,
  3066. "[NM] Failed to convert network address mask string "
  3067. "%1!ws! into an IPv4 address, status %2!u!.\n",
  3068. status
  3069. );
  3070. goto error_exit;
  3071. }
  3072. #if CLUSTER_BETA
  3073. ClRtlLogPrint(
  3074. LOG_NOISE,
  3075. "[NM] Trying to choose multicast scope for network "
  3076. "%1!ws! with address %2!ws! and mask %3!ws!.\n",
  3077. networkId, Network->Address, Network->AddressMask
  3078. );
  3079. #endif // CLUSTER_BETA
  3080. bestScope = NULL;
  3081. for (scope = 0; scope < scopeCount; scope++) {
  3082. #if CLUSTER_BETA
  3083. ClRtlLogPrint(LOG_NOISE,
  3084. "[NM] Examining scope on "
  3085. "interface %1!u!.%2!u!.%3!u!.%4!u!, "
  3086. "id %5!u!.%6!u!.%7!u!.%8!u!, "
  3087. "last address %9!u!.%10!u!.%11!u!.%12!u!, "
  3088. "from server %13!u!.%14!u!.%15!u!.%16!u!, with "
  3089. "description %17!ws!.\n",
  3090. NmpIpAddrPrintArgs(scopeList[scope].ScopeCtx.Interface.IpAddrV4),
  3091. NmpIpAddrPrintArgs(scopeList[scope].ScopeCtx.ScopeID.IpAddrV4),
  3092. NmpIpAddrPrintArgs(scopeList[scope].LastAddr.IpAddrV4),
  3093. NmpIpAddrPrintArgs(scopeList[scope].ScopeCtx.ServerID.IpAddrV4),
  3094. scopeList[scope].ScopeDesc.Buffer
  3095. );
  3096. #endif // CLUSTER_BETA
  3097. NmpChooseBetterMulticastScope(
  3098. &networkAddress,
  3099. &networkSubnet,
  3100. &(scopeList[scope]),
  3101. &currentCorrectInterface,
  3102. &bestScope
  3103. );
  3104. foundInterfaceMatch =
  3105. (BOOLEAN)(foundInterfaceMatch || currentCorrectInterface);
  3106. }
  3107. if (bestScope == NULL) {
  3108. ClRtlLogPrint(LOG_UNUSUAL,
  3109. "[NM] Failed to find multicast scope matching "
  3110. "network id %1!ws!.\n",
  3111. networkId
  3112. );
  3113. status = ERROR_NOT_FOUND;
  3114. goto error_exit;
  3115. } else {
  3116. ClRtlLogPrint(LOG_NOISE,
  3117. "[NM] Selecting MADCAP scope [%1!u!.%2!u!.%3!u!.%4!u!, "
  3118. "%5!u!.%6!u!.%7!u!.%8!u!] from server "
  3119. "%9!u!.%10!u!.%11!u!.%12!u! on interface "
  3120. "%13!u!.%14!u!.%15!u!.%16!u! with description "
  3121. "%17!ws! for network %18!ws!.\n",
  3122. NmpIpAddrPrintArgs(bestScope->ScopeCtx.ScopeID.IpAddrV4),
  3123. NmpIpAddrPrintArgs(bestScope->LastAddr.IpAddrV4),
  3124. NmpIpAddrPrintArgs(bestScope->ScopeCtx.ServerID.IpAddrV4),
  3125. NmpIpAddrPrintArgs(bestScope->ScopeCtx.Interface.IpAddrV4),
  3126. bestScope->ScopeDesc.Buffer, networkId
  3127. );
  3128. }
  3129. RtlCopyMemory(ScopeCtx, &(bestScope->ScopeCtx), sizeof(*ScopeCtx));
  3130. error_exit:
  3131. *FoundInterfaceMatch = foundInterfaceMatch;
  3132. if (scopeList != NULL) {
  3133. LocalFree(scopeList);
  3134. }
  3135. return(status);
  3136. } // NmpFindMulticastScope
  3137. DWORD
  3138. NmpGenerateMulticastRequestId(
  3139. IN OUT LPMCAST_CLIENT_UID RequestId
  3140. )
  3141. /*++
  3142. Routine Description:
  3143. Allocate, if necessary, and generate a client request id
  3144. data structure. If the buffer described by the input
  3145. MCAST_CLIENT_UID data structure is too small, it is
  3146. deallocated.
  3147. Arguments:
  3148. RequestId - IN: pointer to MCAST_CLIENT_UID data structure.
  3149. if ClientUID field is non-NULL, it points
  3150. to a buffer for the generated ID and
  3151. ClientUIDLength is the length of that
  3152. buffer.
  3153. OUT: filled in MCAST_CLIENT_UID data structure.
  3154. --*/
  3155. {
  3156. DWORD status;
  3157. LPBYTE clientUid = NULL;
  3158. MCAST_CLIENT_UID requestId;
  3159. DWORD clientUidLength;
  3160. CL_ASSERT(RequestId != NULL);
  3161. #if CLUSTER_BETA
  3162. ClRtlLogPrint(LOG_NOISE,
  3163. "[NM] Generating MADCAP client request id.\n"
  3164. );
  3165. #endif // CLUSTER_BETA
  3166. //
  3167. // Initialize MADCAP, if not done already.
  3168. //
  3169. if (!NmpMadcapClientInitialized) {
  3170. DWORD madcapVersion = MCAST_API_CURRENT_VERSION;
  3171. status = McastApiStartup(&madcapVersion);
  3172. if (status != ERROR_SUCCESS) {
  3173. ClRtlLogPrint(LOG_UNUSUAL,
  3174. "[NM] Failed to initialize MADCAP API, "
  3175. "status %1!u!.\n",
  3176. status
  3177. );
  3178. goto error_exit;
  3179. }
  3180. NmpMadcapClientInitialized = TRUE;
  3181. }
  3182. //
  3183. // Allocate a buffer for the client uid, if necessary.
  3184. //
  3185. clientUid = RequestId->ClientUID;
  3186. clientUidLength = RequestId->ClientUIDLength;
  3187. if (clientUid != NULL && clientUidLength < MCAST_CLIENT_ID_LEN) {
  3188. MIDL_user_free(clientUid);
  3189. clientUid = NULL;
  3190. clientUidLength = 0;
  3191. RequestId->ClientUID = NULL;
  3192. }
  3193. if (clientUid == NULL) {
  3194. clientUidLength = MCAST_CLIENT_ID_LEN;
  3195. clientUid = MIDL_user_allocate(clientUidLength);
  3196. if (clientUid == NULL) {
  3197. status = ERROR_NOT_ENOUGH_MEMORY;
  3198. ClRtlLogPrint(LOG_UNUSUAL,
  3199. "[NM] Failed to allocate buffer for multicast "
  3200. "clientUid.\n"
  3201. );
  3202. goto error_exit;
  3203. }
  3204. }
  3205. //
  3206. // Obtain a new ID.
  3207. //
  3208. requestId.ClientUID = clientUid;
  3209. requestId.ClientUIDLength = clientUidLength;
  3210. status = McastGenUID(&requestId);
  3211. if (status != ERROR_SUCCESS) {
  3212. ClRtlLogPrint(LOG_UNUSUAL,
  3213. "[NM] Failed to obtain multicast address "
  3214. "request client id, status %1!u!.\n",
  3215. status
  3216. );
  3217. goto error_exit;
  3218. }
  3219. *RequestId = requestId;
  3220. clientUid = NULL;
  3221. error_exit:
  3222. if (clientUid != NULL) {
  3223. MIDL_user_free(clientUid);
  3224. clientUid = NULL;
  3225. }
  3226. return(status);
  3227. } // NmpGenerateMulticastRequestId
  3228. DWORD
  3229. NmpRequestMulticastAddress(
  3230. IN PNM_NETWORK Network,
  3231. IN BOOLEAN Renew,
  3232. IN PMCAST_SCOPE_CTX ScopeCtx,
  3233. IN LPMCAST_CLIENT_UID RequestId,
  3234. IN OUT LPWSTR * McastAddress,
  3235. IN OUT DWORD * McastAddressLength,
  3236. IN OUT LPWSTR * ServerAddress,
  3237. IN OUT DWORD * ServerAddressLength,
  3238. OUT time_t * LeaseStartTime,
  3239. OUT time_t * LeaseEndTime,
  3240. OUT BOOLEAN * NewMcastAddress
  3241. )
  3242. /*++
  3243. Routine Description:
  3244. Renew lease on multicast group address using MADCAP
  3245. client API.
  3246. Arguments:
  3247. Network - network on which address is used
  3248. ScopeCtx - multicast scope (ignored if Renew)
  3249. RequestId - client request id
  3250. McastAddress - IN: address to renew (ignored if !Renew)
  3251. OUT: resulting address
  3252. McastAddressLength - length of McastAddress buffer
  3253. ServerAddress - IN: address of server on which to renew
  3254. (ignored if !Renew)
  3255. OUT: address of address where renew occurred
  3256. ServerAddressLength - length of ServerAddress buffer
  3257. LeaseStartTime - UTC lease start time in seconds (buffer
  3258. allocated by caller)
  3259. LeaseEndTime - UTC lease stop time in seconds (buffer
  3260. allocated by caller)
  3261. NewMcastAddress - whether resulting mcast address is
  3262. new (different than request on renewal
  3263. and always true on successful request)
  3264. --*/
  3265. {
  3266. DWORD status;
  3267. LPCWSTR networkId = OmObjectId(Network);
  3268. UCHAR requestBuffer[NMP_MADCAP_REQUEST_BUFFER_SIZE];
  3269. PMCAST_LEASE_REQUEST request;
  3270. UCHAR responseBuffer[NMP_MADCAP_RESPONSE_BUFFER_SIZE];
  3271. PMCAST_LEASE_RESPONSE response;
  3272. LPWSTR address = NULL;
  3273. DWORD addressSize;
  3274. DWORD requestAddress = 0;
  3275. ClRtlLogPrint(LOG_NOISE,
  3276. "[NM] Preparing to send multicast address %1!ws! "
  3277. "for network %2!ws! to MADCAP server.\n",
  3278. ((Renew) ? L"renewal" : L"request"),
  3279. OmObjectId(Network)
  3280. );
  3281. //
  3282. // Initialize MADCAP, if not done already.
  3283. //
  3284. if (!NmpMadcapClientInitialized) {
  3285. DWORD madcapVersion = MCAST_API_CURRENT_VERSION;
  3286. status = McastApiStartup(&madcapVersion);
  3287. if (status != ERROR_SUCCESS) {
  3288. ClRtlLogPrint(LOG_UNUSUAL,
  3289. "[NM] Failed to initialize MADCAP API, "
  3290. "status %1!u!.\n",
  3291. status
  3292. );
  3293. goto error_exit;
  3294. }
  3295. NmpMadcapClientInitialized = TRUE;
  3296. }
  3297. //
  3298. // Fill in the request. All fields are zero except those
  3299. // set below.
  3300. //
  3301. request = (PMCAST_LEASE_REQUEST) &requestBuffer[0];
  3302. RtlZeroMemory(request, sizeof(requestBuffer));
  3303. request->MinLeaseDuration = 0; // currently ignored
  3304. request->MinAddrCount = 1; // currently ignored
  3305. request->MaxLeaseStartTime = (LONG) time(NULL); // currently ignored
  3306. request->AddrCount = 1;
  3307. //
  3308. // Set the renew parameters.
  3309. //
  3310. if (Renew) {
  3311. request->pAddrBuf = (PBYTE)request + NMP_MADCAP_REQUEST_ADDR_OFFSET;
  3312. status = ClRtlTcpipStringToAddress(
  3313. *McastAddress,
  3314. &requestAddress
  3315. );
  3316. if (status != ERROR_SUCCESS) {
  3317. ClRtlLogPrint(LOG_UNUSUAL,
  3318. "[NM] Failed to convert requested address %1!ws! "
  3319. "into a TCP/IP address, status %2!u!.\n",
  3320. *McastAddress, status
  3321. );
  3322. goto error_exit;
  3323. }
  3324. *((PULONG) request->pAddrBuf) = requestAddress;
  3325. status = ClRtlTcpipStringToAddress(
  3326. *ServerAddress,
  3327. (PULONG) &(request->ServerAddress.IpAddrV4)
  3328. );
  3329. if (status != ERROR_SUCCESS) {
  3330. ClRtlLogPrint(LOG_UNUSUAL,
  3331. "[NM] Failed to convert server address %1!ws! "
  3332. "into a TCP/IP address, status %2!u!.\n",
  3333. *ServerAddress, status
  3334. );
  3335. goto error_exit;
  3336. }
  3337. }
  3338. //
  3339. // Set the address count and buffer fields in the response.
  3340. //
  3341. response = (PMCAST_LEASE_RESPONSE) &responseBuffer[0];
  3342. RtlZeroMemory(response, sizeof(responseBuffer));
  3343. response->AddrCount = 1;
  3344. response->pAddrBuf = (PBYTE)(response) + NMP_MADCAP_RESPONSE_ADDR_OFFSET;
  3345. //
  3346. // Renew or request, as indicated.
  3347. //
  3348. if (Renew) {
  3349. status = McastRenewAddress(
  3350. AF_INET,
  3351. RequestId,
  3352. request,
  3353. response
  3354. );
  3355. if (status != ERROR_SUCCESS) {
  3356. ClRtlLogPrint(LOG_UNUSUAL,
  3357. "[NM] Failed to renew multicast address %1!ws! "
  3358. "with server %2!ws!, status %3!u!.\n",
  3359. *McastAddress, *ServerAddress, status
  3360. );
  3361. goto error_exit;
  3362. }
  3363. } else {
  3364. status = McastRequestAddress(
  3365. AF_INET,
  3366. RequestId,
  3367. ScopeCtx,
  3368. request,
  3369. response
  3370. );
  3371. if (status != ERROR_SUCCESS) {
  3372. ClRtlLogPrint(LOG_UNUSUAL,
  3373. "[NM] Failed to request multicast address on "
  3374. "Scope ID %1!x!, Server ID %2!x!, Interface "
  3375. "%3!x!, status %4!u!.\n",
  3376. ScopeCtx->ScopeID.IpAddrV4, ScopeCtx->ServerID.IpAddrV4,
  3377. ScopeCtx->Interface.IpAddrV4, status
  3378. );
  3379. goto error_exit;
  3380. }
  3381. }
  3382. //
  3383. // Return results through out parameters.
  3384. //
  3385. address = NULL;
  3386. status = ClRtlTcpipAddressToString(
  3387. response->ServerAddress.IpAddrV4,
  3388. &address
  3389. );
  3390. if (status != ERROR_SUCCESS) {
  3391. ClRtlLogPrint(LOG_UNUSUAL,
  3392. "[NM] Failed to convert server address %1!x! "
  3393. "into a TCP/IP address string, status %2!u!.\n",
  3394. response->ServerAddress.IpAddrV4, status
  3395. );
  3396. goto error_exit;
  3397. }
  3398. status = NmpStoreString(address, ServerAddress, ServerAddressLength);
  3399. if (status != ERROR_SUCCESS) {
  3400. ClRtlLogPrint(LOG_UNUSUAL,
  3401. "[NM] Failed to store server address %1!ws! "
  3402. "in return buffer, status %2!u!.\n",
  3403. address, status
  3404. );
  3405. goto error_exit;
  3406. }
  3407. LocalFree(address);
  3408. address = NULL;
  3409. status = ClRtlTcpipAddressToString(
  3410. *((PULONG) response->pAddrBuf),
  3411. &address
  3412. );
  3413. if (status != ERROR_SUCCESS) {
  3414. ClRtlLogPrint(LOG_UNUSUAL,
  3415. "[NM] Failed to convert leased address %1!x! "
  3416. "into a TCP/IP address string, status %2!u!.\n",
  3417. *((PULONG) response->pAddrBuf), status
  3418. );
  3419. goto error_exit;
  3420. }
  3421. status = NmpStoreString(address, McastAddress, McastAddressLength);
  3422. if (status != ERROR_SUCCESS) {
  3423. ClRtlLogPrint(LOG_UNUSUAL,
  3424. "[NM] Failed to store leased address %1!ws! "
  3425. "in return buffer, status %2!u!.\n",
  3426. address, status
  3427. );
  3428. goto error_exit;
  3429. }
  3430. if (Renew) {
  3431. if (*((PULONG) response->pAddrBuf) != requestAddress) {
  3432. *NewMcastAddress = TRUE;
  3433. } else {
  3434. *NewMcastAddress = FALSE;
  3435. }
  3436. } else {
  3437. *NewMcastAddress = TRUE;
  3438. }
  3439. *LeaseStartTime = response->LeaseStartTime;
  3440. *LeaseEndTime = response->LeaseEndTime;
  3441. ClRtlLogPrint(LOG_NOISE,
  3442. "[NM] Obtained lease on multicast address %1!ws! "
  3443. "(%2!ws!) from MADCAP server %3!ws! for network %4!ws!.\n",
  3444. *McastAddress,
  3445. ((*NewMcastAddress) ? L"new" : L"same"),
  3446. *ServerAddress, networkId
  3447. );
  3448. #if CLUSTER_BETA
  3449. ClRtlLogPrint(LOG_NOISE,
  3450. "[NM] Lease starts at %1!u!, ends at %2!u!, "
  3451. "duration %3!u!.\n",
  3452. *LeaseStartTime, *LeaseEndTime, *LeaseEndTime - *LeaseStartTime
  3453. );
  3454. #endif // CLUSTER_BETA
  3455. error_exit:
  3456. if (address != NULL) {
  3457. LocalFree(address);
  3458. address = NULL;
  3459. }
  3460. return(status);
  3461. } // NmpRequestMulticastAddress
  3462. NM_MCAST_LEASE_STATUS
  3463. NmpCalculateLeaseStatus(
  3464. IN PNM_NETWORK Network,
  3465. IN time_t LeaseObtained,
  3466. IN time_t LeaseExpires
  3467. )
  3468. /*++
  3469. Routine Description:
  3470. Calculate lease status based on current time
  3471. and lease end time.
  3472. Rely on the compiler's correct code generation for
  3473. time_t math!
  3474. Return value:
  3475. Lease status
  3476. --*/
  3477. {
  3478. LPCWSTR networkId = OmObjectId(Network);
  3479. time_t currentTime;
  3480. time_t halfLife;
  3481. NM_MCAST_LEASE_STATUS status;
  3482. if (LeaseExpires == 0 || LeaseExpires <= LeaseObtained) {
  3483. //
  3484. // A lease expiration of 0 means we hold the lease
  3485. // forever. Most likely, an administrator statically
  3486. // configured the network with this address.
  3487. //
  3488. status = NmMcastLeaseValid;
  3489. } else {
  3490. time(&currentTime);
  3491. if (currentTime > LeaseExpires) {
  3492. status = NmMcastLeaseExpired;
  3493. } else {
  3494. halfLife = LeaseObtained +
  3495. ((LeaseExpires - LeaseObtained) / 2);
  3496. if (currentTime >= halfLife) {
  3497. status = NmMcastLeaseNeedsRenewal;
  3498. } else {
  3499. status = NmMcastLeaseValid;
  3500. }
  3501. }
  3502. }
  3503. #if CLUSTER_BETA
  3504. if (LeaseExpires == 0 || LeaseExpires <= LeaseObtained) {
  3505. ClRtlLogPrint(LOG_NOISE,
  3506. "[NM] Found that multicast address lease for "
  3507. "network %1!ws! does not expire.\n",
  3508. networkId
  3509. );
  3510. } else if (status == NmMcastLeaseExpired) {
  3511. ClRtlLogPrint(LOG_NOISE,
  3512. "[NM] Found that multicast address lease for "
  3513. "network %1!ws! expired %2!u! seconds ago.\n",
  3514. networkId, currentTime - LeaseExpires
  3515. );
  3516. } else {
  3517. ClRtlLogPrint(LOG_NOISE,
  3518. "[NM] Found that multicast address lease for "
  3519. "network %1!ws! expires in %2!u! seconds. With "
  3520. "lease obtained %3!u! seconds ago, renewal is "
  3521. "%4!ws!needed.\n",
  3522. networkId, LeaseExpires - currentTime,
  3523. currentTime - LeaseObtained,
  3524. ((status > NmMcastLeaseValid) ? L"" : L"not ")
  3525. );
  3526. }
  3527. #endif // CLUSTER_BETA
  3528. return(status);
  3529. } // NmpCalculateLeaseStatus
  3530. DWORD
  3531. NmpQueryMulticastAddressLease(
  3532. IN PNM_NETWORK Network,
  3533. IN HDMKEY NetworkKey,
  3534. IN OUT HDMKEY * NetworkParametersKey,
  3535. OUT NM_MCAST_LEASE_STATUS * LeaseStatus,
  3536. OUT time_t * LeaseObtained,
  3537. OUT time_t * LeaseExpires
  3538. )
  3539. /*++
  3540. Routine Description:
  3541. Query the lease obtained and expires times stored in the
  3542. cluster database.
  3543. Return value:
  3544. Error if lease times not found.
  3545. Notes:
  3546. Must not be called with NM lock held.
  3547. --*/
  3548. {
  3549. DWORD status;
  3550. LPCWSTR networkId = OmObjectId(Network);
  3551. HDMKEY netParamKey = NULL;
  3552. BOOLEAN openedNetParamKey = FALSE;
  3553. DWORD type;
  3554. DWORD len;
  3555. time_t leaseExpires;
  3556. time_t leaseObtained;
  3557. #if CLUSTER_BETA
  3558. ClRtlLogPrint(LOG_NOISE,
  3559. "[NM] Querying multicast address lease for "
  3560. "network %1!ws!.\n",
  3561. networkId
  3562. );
  3563. #endif // CLUSTER_BETA
  3564. if (Network == NULL || NetworkKey == NULL) {
  3565. status = ERROR_INVALID_PARAMETER;
  3566. goto error_exit;
  3567. }
  3568. //
  3569. // Open the network parameters key, if necessary.
  3570. //
  3571. netParamKey = *NetworkParametersKey;
  3572. if (netParamKey == NULL) {
  3573. netParamKey = DmOpenKey(
  3574. NetworkKey,
  3575. CLUSREG_KEYNAME_PARAMETERS,
  3576. MAXIMUM_ALLOWED
  3577. );
  3578. if (netParamKey == NULL) {
  3579. status = GetLastError();
  3580. ClRtlLogPrint(LOG_NOISE,
  3581. "[NM] Failed to find Parameters key "
  3582. "for network %1!ws!, status %2!u!. Using default "
  3583. "multicast parameters.\n",
  3584. networkId, status
  3585. );
  3586. goto error_exit;
  3587. } else {
  3588. openedNetParamKey = TRUE;
  3589. }
  3590. }
  3591. //
  3592. // Query the lease obtained and expires value from the
  3593. // cluster database.
  3594. //
  3595. len = sizeof(leaseObtained);
  3596. status = DmQueryValue(
  3597. netParamKey,
  3598. CLUSREG_NAME_NET_MCAST_LEASE_OBTAINED,
  3599. &type,
  3600. (LPBYTE) &leaseObtained,
  3601. &len
  3602. );
  3603. if (status != ERROR_SUCCESS) {
  3604. ClRtlLogPrint(LOG_UNUSUAL,
  3605. "[NM] Failed to read multicast lease obtained "
  3606. " time for network %1!ws! from cluster database, "
  3607. "status %2!u!.\n",
  3608. networkId, status
  3609. );
  3610. goto error_exit;
  3611. } else if (type != REG_DWORD) {
  3612. ClRtlLogPrint(LOG_UNUSUAL,
  3613. "[NM] Unexpected type (%1!u!) for network "
  3614. "%2!ws! %3!ws!.\n",
  3615. type, networkId, CLUSREG_NAME_NET_MCAST_LEASE_OBTAINED
  3616. );
  3617. status = ERROR_DATATYPE_MISMATCH;
  3618. goto error_exit;
  3619. }
  3620. len = sizeof(leaseExpires);
  3621. status = DmQueryValue(
  3622. netParamKey,
  3623. CLUSREG_NAME_NET_MCAST_LEASE_EXPIRES,
  3624. &type,
  3625. (LPBYTE) &leaseExpires,
  3626. &len
  3627. );
  3628. if (status != ERROR_SUCCESS) {
  3629. ClRtlLogPrint(LOG_UNUSUAL,
  3630. "[NM] Failed to read multicast lease expiration "
  3631. " time for network %1!ws! from cluster database, "
  3632. "status %2!u!.\n",
  3633. networkId, status
  3634. );
  3635. goto error_exit;
  3636. } else if (type != REG_DWORD) {
  3637. ClRtlLogPrint(LOG_UNUSUAL,
  3638. "[NM] Unexpected type (%1!u!) for network "
  3639. "%2!ws! %3!ws!.\n",
  3640. type, networkId, CLUSREG_NAME_NET_MCAST_LEASE_EXPIRES
  3641. );
  3642. status = ERROR_DATATYPE_MISMATCH;
  3643. goto error_exit;
  3644. }
  3645. *NetworkParametersKey = netParamKey;
  3646. netParamKey = NULL;
  3647. *LeaseStatus = NmpCalculateLeaseStatus(
  3648. Network,
  3649. leaseObtained,
  3650. leaseExpires
  3651. );
  3652. *LeaseObtained = leaseObtained;
  3653. *LeaseExpires = leaseExpires;
  3654. error_exit:
  3655. if (openedNetParamKey && netParamKey != NULL) {
  3656. DmCloseKey(netParamKey);
  3657. netParamKey = NULL;
  3658. }
  3659. return(status);
  3660. } // NmpQueryMulticastAddressLease
  3661. VOID
  3662. NmpCheckMulticastAddressLease(
  3663. IN PNM_NETWORK Network,
  3664. OUT NM_MCAST_LEASE_STATUS * LeaseStatus,
  3665. OUT time_t * LeaseObtained,
  3666. OUT time_t * LeaseExpires
  3667. )
  3668. /*++
  3669. Routine Description:
  3670. Check the lease parameters stored in the network
  3671. object. Determine if a lease renew is required.
  3672. Notes:
  3673. Called and returns with NM lock held.
  3674. --*/
  3675. {
  3676. #if CLUSTER_BETA
  3677. LPCWSTR networkId = OmObjectId(Network);
  3678. ClRtlLogPrint(LOG_NOISE,
  3679. "[NM] Checking multicast address lease for "
  3680. "network %1!ws!.\n",
  3681. networkId
  3682. );
  3683. #endif // CLUSTER_BETA
  3684. //
  3685. // Determine if we need to renew.
  3686. //
  3687. *LeaseStatus = NmpCalculateLeaseStatus(
  3688. Network,
  3689. Network->MulticastLeaseObtained,
  3690. Network->MulticastLeaseExpires
  3691. );
  3692. *LeaseObtained = Network->MulticastLeaseObtained;
  3693. *LeaseExpires = Network->MulticastLeaseExpires;
  3694. return;
  3695. } // NmpCheckMulticastAddressLease
  3696. DWORD
  3697. NmpMulticastGetDatabaseLeaseParameters(
  3698. IN PNM_NETWORK Network,
  3699. IN OUT HDMKEY * NetworkKey,
  3700. IN OUT HDMKEY * NetworkParametersKey,
  3701. OUT LPMCAST_CLIENT_UID RequestId, OPTIONAL
  3702. OUT LPWSTR * ServerAddress, OPTIONAL
  3703. OUT LPWSTR * McastAddress OPTIONAL
  3704. )
  3705. /*++
  3706. Routine Description:
  3707. Read parameters needed to renew a lease from the
  3708. cluster database.
  3709. Return value:
  3710. SUCCESS if all parameters were successfully read.
  3711. Notes:
  3712. Must not be called with NM lock held.
  3713. --*/
  3714. {
  3715. DWORD status;
  3716. LPCWSTR networkId = OmObjectId(Network);
  3717. HDMKEY networkKey = NULL;
  3718. BOOLEAN openedNetworkKey = FALSE;
  3719. HDMKEY netParamKey = NULL;
  3720. BOOLEAN openedNetParamKey = FALSE;
  3721. DWORD type;
  3722. DWORD len;
  3723. MCAST_CLIENT_UID requestId = { NULL, 0 };
  3724. LPWSTR serverAddress = NULL;
  3725. DWORD serverAddressLength = 0;
  3726. LPWSTR mcastAddress = NULL;
  3727. DWORD mcastAddressLength = 0;
  3728. //
  3729. // Open the network key, if necessary.
  3730. //
  3731. networkKey = *NetworkKey;
  3732. if (networkKey == NULL) {
  3733. networkKey = DmOpenKey(
  3734. DmNetworksKey,
  3735. networkId,
  3736. MAXIMUM_ALLOWED
  3737. );
  3738. if (networkKey == NULL) {
  3739. status = GetLastError();
  3740. ClRtlLogPrint(LOG_UNUSUAL,
  3741. "[NM] Failed to open key for network %1!ws!, "
  3742. "status %2!u!\n",
  3743. networkId, status
  3744. );
  3745. goto error_exit;
  3746. }
  3747. openedNetworkKey = TRUE;
  3748. }
  3749. //
  3750. // Open the network parameters key if necessary.
  3751. //
  3752. netParamKey = *NetworkParametersKey;
  3753. if (netParamKey == NULL) {
  3754. netParamKey = DmOpenKey(
  3755. networkKey,
  3756. CLUSREG_KEYNAME_PARAMETERS,
  3757. MAXIMUM_ALLOWED
  3758. );
  3759. if (netParamKey == NULL) {
  3760. status = GetLastError();
  3761. ClRtlLogPrint(LOG_UNUSUAL,
  3762. "[NM] Failed to open Parameters key for "
  3763. "network %1!ws!, status %2!u!\n",
  3764. networkId, status
  3765. );
  3766. goto error_exit;
  3767. }
  3768. openedNetParamKey = TRUE;
  3769. }
  3770. //
  3771. // Read the client request id.
  3772. //
  3773. if (RequestId != NULL) {
  3774. requestId.ClientUIDLength = MCAST_CLIENT_ID_LEN;
  3775. requestId.ClientUID = MIDL_user_allocate(requestId.ClientUIDLength);
  3776. if (requestId.ClientUID == NULL) {
  3777. ClRtlLogPrint(LOG_UNUSUAL,
  3778. "[NM] Failed to allocate buffer to read "
  3779. "request id from Parameters database "
  3780. "key for network %1!ws!.\n",
  3781. networkId
  3782. );
  3783. status = ERROR_NOT_ENOUGH_MEMORY;
  3784. goto error_exit;
  3785. }
  3786. len = requestId.ClientUIDLength;
  3787. status = DmQueryValue(
  3788. netParamKey,
  3789. CLUSREG_NAME_NET_MCAST_REQUEST_ID,
  3790. &type,
  3791. (LPBYTE) requestId.ClientUID,
  3792. &len
  3793. );
  3794. if (status == ERROR_SUCCESS) {
  3795. if (type != REG_BINARY) {
  3796. ClRtlLogPrint(LOG_NOISE,
  3797. "[NM] Unexpected type (%1!u!) for network "
  3798. "%2!ws! %3!ws!, status %4!u!.\n",
  3799. type, networkId,
  3800. CLUSREG_NAME_NET_MCAST_REQUEST_ID, status
  3801. );
  3802. goto error_exit;
  3803. }
  3804. requestId.ClientUIDLength = len;
  3805. } else {
  3806. goto error_exit;
  3807. }
  3808. }
  3809. //
  3810. // Read the address of the server that granted the
  3811. // current lease.
  3812. //
  3813. if (ServerAddress != NULL) {
  3814. serverAddress = NULL;
  3815. serverAddressLength = 0;
  3816. status = NmpQueryString(
  3817. netParamKey,
  3818. CLUSREG_NAME_NET_MCAST_SERVER_ADDRESS,
  3819. REG_SZ,
  3820. &serverAddress,
  3821. &serverAddressLength,
  3822. &len
  3823. );
  3824. if (status != ERROR_SUCCESS) {
  3825. goto error_exit;
  3826. }
  3827. }
  3828. //
  3829. // Read the last known multicast address.
  3830. //
  3831. if (McastAddress != NULL) {
  3832. status = NmpQueryMulticastAddress(
  3833. Network,
  3834. networkKey,
  3835. &netParamKey,
  3836. &mcastAddress,
  3837. &mcastAddressLength
  3838. );
  3839. if (status != ERROR_SUCCESS) {
  3840. goto error_exit;
  3841. }
  3842. if (!NmpMulticastValidateAddress(mcastAddress)) {
  3843. MIDL_user_free(mcastAddress);
  3844. mcastAddress = NULL;
  3845. mcastAddressLength = 0;
  3846. goto error_exit;
  3847. }
  3848. }
  3849. //
  3850. // We found all the parameters.
  3851. //
  3852. *NetworkKey = networkKey;
  3853. networkKey = NULL;
  3854. *NetworkParametersKey = netParamKey;
  3855. netParamKey = NULL;
  3856. if (RequestId != NULL) {
  3857. *RequestId = requestId;
  3858. requestId.ClientUID = NULL;
  3859. requestId.ClientUIDLength = 0;
  3860. }
  3861. if (ServerAddress != NULL) {
  3862. *ServerAddress = serverAddress;
  3863. serverAddress = NULL;
  3864. }
  3865. if (McastAddress != NULL) {
  3866. *McastAddress = mcastAddress;
  3867. mcastAddress = NULL;
  3868. }
  3869. status = ERROR_SUCCESS;
  3870. error_exit:
  3871. if (requestId.ClientUID != NULL) {
  3872. MIDL_user_free(requestId.ClientUID);
  3873. requestId.ClientUID = NULL;
  3874. requestId.ClientUIDLength = 0;
  3875. }
  3876. if (serverAddress != NULL) {
  3877. MIDL_user_free(serverAddress);
  3878. serverAddress = NULL;
  3879. }
  3880. if (mcastAddress != NULL) {
  3881. MIDL_user_free(mcastAddress);
  3882. mcastAddress = NULL;
  3883. }
  3884. if (openedNetworkKey && networkKey != NULL) {
  3885. DmCloseKey(networkKey);
  3886. networkKey = NULL;
  3887. }
  3888. if (openedNetParamKey && netParamKey != NULL) {
  3889. DmCloseKey(netParamKey);
  3890. netParamKey = NULL;
  3891. }
  3892. return(status);
  3893. } // NmpMulticastGetDatabaseLeaseParameters
  3894. DWORD
  3895. NmpMulticastGetNetworkLeaseParameters(
  3896. IN PNM_NETWORK Network,
  3897. OUT LPMCAST_CLIENT_UID RequestId,
  3898. OUT LPWSTR * ServerAddress,
  3899. OUT LPWSTR * McastAddress
  3900. )
  3901. /*++
  3902. Routine Description:
  3903. Read parameters needed to renew a lease from the
  3904. network object data structure.
  3905. Return value:
  3906. SUCCESS if all parameters were successfully read.
  3907. Notes:
  3908. Must be called with NM lock held.
  3909. --*/
  3910. {
  3911. DWORD status;
  3912. LPCWSTR networkId = OmObjectId(Network);
  3913. MCAST_CLIENT_UID requestId = { NULL, 0 };
  3914. LPWSTR serverAddress = NULL;
  3915. DWORD serverAddressLength = 0;
  3916. LPWSTR mcastAddress = NULL;
  3917. DWORD mcastAddressLength = 0;
  3918. if (Network->MulticastAddress == NULL ||
  3919. Network->MulticastLeaseServer == NULL ||
  3920. Network->MulticastLeaseRequestId.ClientUID == NULL) {
  3921. ClRtlLogPrint(LOG_NOISE,
  3922. "[NM] Failed to locate multicast lease "
  3923. "parameter in network object %1!ws!.\n",
  3924. networkId
  3925. );
  3926. status = ERROR_NOT_FOUND;
  3927. goto error_exit;
  3928. }
  3929. status = NmpStoreString(
  3930. Network->MulticastAddress,
  3931. &mcastAddress,
  3932. NULL
  3933. );
  3934. if (status != ERROR_SUCCESS) {
  3935. ClRtlLogPrint(LOG_UNUSUAL,
  3936. "[NM] Failed to copy multicast address %1!ws! "
  3937. "from network object %2!ws!, status %3!u!.\n",
  3938. Network->MulticastAddress,
  3939. networkId, status
  3940. );
  3941. goto error_exit;
  3942. }
  3943. status = NmpStoreString(
  3944. Network->MulticastLeaseServer,
  3945. &serverAddress,
  3946. NULL
  3947. );
  3948. if (status != ERROR_SUCCESS) {
  3949. ClRtlLogPrint(LOG_UNUSUAL,
  3950. "[NM] Failed to copy lease server address %1!ws! "
  3951. "from network object %2!ws!, status %3!u!.\n",
  3952. Network->MulticastLeaseServer,
  3953. networkId, status
  3954. );
  3955. goto error_exit;
  3956. }
  3957. status = NmpStoreRequestId(
  3958. &(Network->MulticastLeaseRequestId),
  3959. &requestId
  3960. );
  3961. if (status != ERROR_SUCCESS) {
  3962. ClRtlLogPrint(LOG_UNUSUAL,
  3963. "[NM] Failed to copy lease request id "
  3964. "from network object %1!ws!, status %2!u!.\n",
  3965. networkId, status
  3966. );
  3967. goto error_exit;
  3968. }
  3969. *RequestId = requestId;
  3970. requestId.ClientUID = NULL;
  3971. requestId.ClientUIDLength = 0;
  3972. *ServerAddress = serverAddress;
  3973. serverAddress = NULL;
  3974. *McastAddress = mcastAddress;
  3975. mcastAddress = NULL;
  3976. status = ERROR_SUCCESS;
  3977. error_exit:
  3978. if (requestId.ClientUID != NULL) {
  3979. MIDL_user_free(requestId.ClientUID);
  3980. RtlZeroMemory(&requestId, sizeof(requestId));
  3981. }
  3982. if (mcastAddress != NULL) {
  3983. MIDL_user_free(mcastAddress);
  3984. mcastAddress = NULL;
  3985. }
  3986. if (serverAddress != NULL) {
  3987. MIDL_user_free(serverAddress);
  3988. serverAddress = NULL;
  3989. }
  3990. return(status);
  3991. } // NmpMulticastGetNetworkLeaseParameters
  3992. DWORD
  3993. NmpMulticastNeedRetryRenew(
  3994. IN PNM_NETWORK Network,
  3995. OUT DWORD * DeferRetry
  3996. )
  3997. /*++
  3998. Routine Description:
  3999. Called after a MADCAP timeout, determines whether
  4000. a new MADCAP request should be sent after a delay.
  4001. Specifically, a retry after delay is in order when
  4002. the current address was obtained from a MADCAP
  4003. server that might simply be temporarily unresponsive.
  4004. The default is to not retry.
  4005. Arguments:
  4006. Network - network
  4007. DeferRetry - OUT: seconds to defer until retrying
  4008. MADCAP query, or zero if should
  4009. not retry
  4010. --*/
  4011. {
  4012. DWORD status;
  4013. LPCWSTR networkId = OmObjectId(Network);
  4014. HDMKEY networkKey = NULL;
  4015. HDMKEY netParamKey = NULL;
  4016. NM_MCAST_CONFIG configType;
  4017. NM_MCAST_LEASE_STATUS leaseStatus;
  4018. time_t leaseObtained;
  4019. time_t leaseExpires;
  4020. time_t currentTime;
  4021. time_t halfhalfLife;
  4022. time_t result;
  4023. *DeferRetry = 0;
  4024. //
  4025. // Open the network key.
  4026. //
  4027. networkKey = DmOpenKey(
  4028. DmNetworksKey,
  4029. networkId,
  4030. MAXIMUM_ALLOWED
  4031. );
  4032. if (networkKey == NULL) {
  4033. status = GetLastError();
  4034. ClRtlLogPrint(LOG_UNUSUAL,
  4035. "[NM] Failed to open key for network %1!ws!, "
  4036. "status %2!u!\n",
  4037. networkId, status
  4038. );
  4039. goto error_exit;
  4040. }
  4041. status = NmpQueryMulticastConfigType(
  4042. Network,
  4043. networkKey,
  4044. &netParamKey,
  4045. &configType
  4046. );
  4047. if (status != ERROR_SUCCESS) {
  4048. ClRtlLogPrint(LOG_UNUSUAL,
  4049. "[NM] Failed to query multicast config type "
  4050. "for network %1!ws!, status %2!u!\n",
  4051. networkId, status
  4052. );
  4053. goto error_exit;
  4054. }
  4055. if (configType != NmMcastConfigMadcap) {
  4056. goto error_exit;
  4057. }
  4058. status = NmpQueryMulticastAddressLease(
  4059. Network,
  4060. networkKey,
  4061. &netParamKey,
  4062. &leaseStatus,
  4063. &leaseObtained,
  4064. &leaseExpires
  4065. );
  4066. if (status != ERROR_SUCCESS) {
  4067. ClRtlLogPrint(LOG_UNUSUAL,
  4068. "[NM] Failed to query multicast lease expiration "
  4069. "time for network %1!ws!, status %2!u!\n",
  4070. networkId, status
  4071. );
  4072. goto error_exit;
  4073. }
  4074. //
  4075. // Check if the lease has expired.
  4076. //
  4077. if (leaseStatus == NmMcastLeaseExpired) {
  4078. goto error_exit;
  4079. }
  4080. //
  4081. // Check if we are within the threshold of expiration.
  4082. //
  4083. currentTime = time(NULL);
  4084. if (leaseExpires - currentTime < NMP_MCAST_LEASE_RENEWAL_THRESHOLD) {
  4085. goto error_exit;
  4086. }
  4087. //
  4088. // Calculate half the time until expiration.
  4089. //
  4090. halfhalfLife = currentTime + ((leaseExpires - currentTime) / 2);
  4091. if (leaseExpires - halfhalfLife < NMP_MCAST_LEASE_RENEWAL_THRESHOLD) {
  4092. result = leaseExpires - NMP_MCAST_LEASE_RENEWAL_THRESHOLD;
  4093. } else {
  4094. result = halfhalfLife - currentTime;
  4095. }
  4096. NMP_TIME_TO_DWORD(result, *DeferRetry);
  4097. status = ERROR_SUCCESS;
  4098. error_exit:
  4099. if (networkKey != NULL) {
  4100. DmCloseKey(networkKey);
  4101. networkKey = NULL;
  4102. }
  4103. if (netParamKey != NULL) {
  4104. DmCloseKey(netParamKey);
  4105. netParamKey = NULL;
  4106. }
  4107. return(status);
  4108. } // NmpMulticastNeedRetryRenew
  4109. DWORD
  4110. NmpGetMulticastAddress(
  4111. IN PNM_NETWORK Network,
  4112. IN OUT LPWSTR * McastAddress,
  4113. IN OUT LPWSTR * ServerAddress,
  4114. IN OUT LPMCAST_CLIENT_UID RequestId,
  4115. OUT PNM_NETWORK_MULTICAST_PARAMETERS Parameters
  4116. )
  4117. /*++
  4118. Routine Description:
  4119. Try to obtain a multicast address lease. If the
  4120. address, server, and request id are non-NULL, first
  4121. try to renew. If unsuccessful in renewing, try a
  4122. new lease.
  4123. Return lease parameters through Parameters.
  4124. Free McastAddress, ServerAddress, and RequestId
  4125. if new values are returned through Parameters.
  4126. Notes:
  4127. Must not be called with NM lock held.
  4128. --*/
  4129. {
  4130. DWORD status;
  4131. LPCWSTR networkId = OmObjectId(Network);
  4132. BOOLEAN renew = FALSE;
  4133. BOOLEAN retryFresh = FALSE;
  4134. BOOLEAN madcapTimeout = FALSE;
  4135. BOOLEAN newMcastAddress = FALSE;
  4136. NM_MCAST_CONFIG configType = NmMcastConfigAuto;
  4137. MCAST_SCOPE_CTX scopeCtx;
  4138. BOOLEAN interfaceMatch = FALSE;
  4139. DWORD mcastAddressLength = 0;
  4140. LPWSTR serverAddress = NULL;
  4141. DWORD serverAddressLength = 0;
  4142. MCAST_CLIENT_UID requestId = {NULL, 0};
  4143. time_t leaseStartTime;
  4144. time_t leaseEndTime;
  4145. DWORD len;
  4146. renew = (BOOLEAN)(*McastAddress != NULL &&
  4147. *ServerAddress != NULL &&
  4148. RequestId->ClientUID != NULL &&
  4149. NmpMulticastValidateAddress(*McastAddress) &&
  4150. lstrcmpW(*ServerAddress, NmpNullMulticastAddress) != 0
  4151. );
  4152. do {
  4153. if (!renew) {
  4154. //
  4155. // Find a scope.
  4156. //
  4157. status = NmpFindMulticastScope(
  4158. Network,
  4159. &scopeCtx,
  4160. &interfaceMatch
  4161. );
  4162. if (status != ERROR_SUCCESS) {
  4163. if (status == ERROR_TIMEOUT) {
  4164. ClRtlLogPrint(LOG_NOISE,
  4165. "[NM] Attempt to contact MADCAP server timed "
  4166. "out while enumerating multicast scopes "
  4167. "(status %1!u!). Selecting default multicast "
  4168. "address for network %2!ws! ...\n",
  4169. status, networkId
  4170. );
  4171. madcapTimeout = TRUE;
  4172. goto error_exit;
  4173. } else if (interfaceMatch) {
  4174. ClRtlLogPrint(LOG_UNUSUAL,
  4175. "[NM] Failed to find viable multicast scope "
  4176. "for network %1!ws!, status %2!u!.\n",
  4177. networkId, status
  4178. );
  4179. goto error_exit;
  4180. } else {
  4181. ClRtlLogPrint(LOG_NOISE,
  4182. "[NM] MADCAP server reported no multicast "
  4183. "scopes on interface for network %1!ws!. "
  4184. "Selecting default multicast address ... \n",
  4185. networkId
  4186. );
  4187. //
  4188. // Treat this situation as a MADCAP timeout,
  4189. // because there are likely no MADCAP servers
  4190. // for this network.
  4191. //
  4192. madcapTimeout = TRUE;
  4193. goto error_exit;
  4194. }
  4195. }
  4196. //
  4197. // Generate a client request id.
  4198. //
  4199. status = NmpGenerateMulticastRequestId(RequestId);
  4200. if (status != ERROR_SUCCESS) {
  4201. ClRtlLogPrint(LOG_UNUSUAL,
  4202. "[NM] Failed to generate multicast client "
  4203. "request ID for network %1!ws!, status %2!u!.\n",
  4204. networkId, status
  4205. );
  4206. goto error_exit;
  4207. }
  4208. }
  4209. //
  4210. // Request a lease.
  4211. //
  4212. mcastAddressLength =
  4213. (*McastAddress == NULL) ? 0 : NM_WCSLEN(*McastAddress);
  4214. serverAddressLength =
  4215. (*ServerAddress == NULL) ? 0 : NM_WCSLEN(*ServerAddress);
  4216. status = NmpRequestMulticastAddress(
  4217. Network,
  4218. renew,
  4219. ((renew) ? NULL : &scopeCtx),
  4220. RequestId,
  4221. McastAddress,
  4222. &mcastAddressLength,
  4223. ServerAddress,
  4224. &serverAddressLength,
  4225. &leaseStartTime,
  4226. &leaseEndTime,
  4227. &newMcastAddress
  4228. );
  4229. if (status != ERROR_SUCCESS) {
  4230. if (status == ERROR_TIMEOUT) {
  4231. ClRtlLogPrint(LOG_UNUSUAL,
  4232. "[NM] Attempt to contact MADCAP server timed "
  4233. "out while requesting a multicast address "
  4234. "(status %1!u!). Selecting default multicast "
  4235. "address for network %2!ws! ...\n",
  4236. status, networkId
  4237. );
  4238. madcapTimeout = TRUE;
  4239. goto error_exit;
  4240. } else if (renew && !retryFresh) {
  4241. ClRtlLogPrint(LOG_UNUSUAL,
  4242. "[NM] Failed to renew multicast address "
  4243. "for network %1!ws!, status %2!u!. Attempting "
  4244. "a fresh request ...\n",
  4245. networkId, status
  4246. );
  4247. retryFresh = TRUE;
  4248. renew = FALSE;
  4249. } else {
  4250. ClRtlLogPrint(LOG_UNUSUAL,
  4251. "[NM] Failed to request multicast address "
  4252. "for network %1!ws!, status %2!u!.\n",
  4253. networkId, status
  4254. );
  4255. goto error_exit;
  4256. }
  4257. } else {
  4258. //
  4259. // Madcap config succeeded.
  4260. //
  4261. configType = NmMcastConfigMadcap;
  4262. madcapTimeout = FALSE;
  4263. //
  4264. // Save lease renewal parameters.
  4265. //
  4266. requestId = *RequestId;
  4267. serverAddress = *ServerAddress;
  4268. //
  4269. // Break out of loop.
  4270. //
  4271. retryFresh = FALSE;
  4272. }
  4273. } while ( retryFresh );
  4274. //
  4275. // Fill in the parameters data structure.
  4276. //
  4277. status = NmpMulticastCreateParameters(
  4278. 0, // disabled
  4279. *McastAddress,
  4280. NULL, // salt
  4281. 0, // salt length
  4282. NULL, // key
  4283. 0, // key length
  4284. leaseStartTime,
  4285. leaseEndTime,
  4286. &requestId,
  4287. serverAddress,
  4288. configType,
  4289. Parameters
  4290. );
  4291. if (status != ERROR_SUCCESS) {
  4292. ClRtlLogPrint(LOG_UNUSUAL,
  4293. "[NM] Failed to create multicast parameters "
  4294. "data structure for network %1!ws!, "
  4295. "status %2!u!.\n",
  4296. networkId, status
  4297. );
  4298. goto error_exit;
  4299. }
  4300. status = ERROR_SUCCESS;
  4301. error_exit:
  4302. if (madcapTimeout) {
  4303. status = ERROR_TIMEOUT;
  4304. }
  4305. return(status);
  4306. } // NmpGetMulticastAddress
  4307. DWORD
  4308. NmpMulticastSetNullAddressParameters(
  4309. IN PNM_NETWORK Network,
  4310. OUT PNM_NETWORK_MULTICAST_PARAMETERS Parameters
  4311. )
  4312. /*++
  4313. Routine Description:
  4314. Called after failure to process multicast parameters.
  4315. Changes only address field in parameters to turn
  4316. off multicast in clusnet.
  4317. --*/
  4318. {
  4319. LPCWSTR networkId = OmObjectId(Network);
  4320. ClRtlLogPrint(LOG_NOISE,
  4321. "[NM] Setting NULL multicast address (%1!ws!) "
  4322. "for network %2!ws!.\n",
  4323. NmpNullMulticastAddress, networkId
  4324. );
  4325. if (Parameters->Address != NULL) {
  4326. MIDL_user_free(Parameters->Address);
  4327. }
  4328. Parameters->Address = NmpNullMulticastAddress;
  4329. return(ERROR_SUCCESS);
  4330. } // NmpMulticastSetNullAddressParameters
  4331. DWORD
  4332. NmpMulticastSetNoAddressParameters(
  4333. IN PNM_NETWORK Network,
  4334. OUT PNM_NETWORK_MULTICAST_PARAMETERS Parameters
  4335. )
  4336. /*++
  4337. Routine Description:
  4338. Called after failure to obtain a multicast address.
  4339. Fills in parameters data structure to reflect
  4340. failure and to establish retry.
  4341. --*/
  4342. {
  4343. NmpMulticastSetNullAddressParameters(Network, Parameters);
  4344. Parameters->ConfigType = NmMcastConfigAuto;
  4345. NmpCalculateLeaseRenewTime(
  4346. Network,
  4347. Parameters->ConfigType,
  4348. &Parameters->LeaseObtained,
  4349. &Parameters->LeaseExpires
  4350. );
  4351. return(ERROR_SUCCESS);
  4352. } // NmpMulticastSetNoAddressParameters
  4353. DWORD
  4354. NmpRenewMulticastAddressLease(
  4355. IN PNM_NETWORK Network
  4356. )
  4357. /*++
  4358. Routine Description:
  4359. Renew a multicast address lease, as determined by lease
  4360. parameters stored in the cluster database.
  4361. Notes:
  4362. Called with NM lock held and must return with NM lock held.
  4363. --*/
  4364. {
  4365. DWORD status;
  4366. LPCWSTR networkId = OmObjectId(Network);
  4367. HDMKEY networkKey = NULL;
  4368. HDMKEY netParamKey = NULL;
  4369. BOOLEAN lockAcquired = TRUE;
  4370. MCAST_CLIENT_UID requestId = { NULL, 0 };
  4371. LPWSTR serverAddress = NULL;
  4372. DWORD serverAddressLength = 0;
  4373. LPWSTR mcastAddress = NULL;
  4374. DWORD mcastAddressLength = 0;
  4375. LPWSTR oldMcastAddress = NULL;
  4376. NM_NETWORK_MULTICAST_PARAMETERS parameters;
  4377. DWORD deferRetry = 0;
  4378. BOOLEAN localInterface = FALSE;
  4379. localInterface = (BOOLEAN)(Network->LocalInterface != NULL);
  4380. if (localInterface) {
  4381. ClRtlLogPrint(LOG_NOISE,
  4382. "[NM] Renewing multicast address lease for "
  4383. "network %1!ws!.\n",
  4384. networkId
  4385. );
  4386. } else {
  4387. ClRtlLogPrint(LOG_UNUSUAL,
  4388. "[NM] Attempting to renew multicast address "
  4389. "lease for network %1!ws! despite the lack of "
  4390. "a local interface.\n",
  4391. networkId
  4392. );
  4393. }
  4394. RtlZeroMemory(&parameters, sizeof(parameters));
  4395. //
  4396. // Get the lease parameters from the network object.
  4397. //
  4398. status = NmpMulticastGetNetworkLeaseParameters(
  4399. Network,
  4400. &requestId,
  4401. &serverAddress,
  4402. &mcastAddress
  4403. );
  4404. if (status != ERROR_SUCCESS) {
  4405. ClRtlLogPrint(LOG_NOISE,
  4406. "[NM] Failed to find multicast lease "
  4407. "parameters in network object %1!ws!, "
  4408. "status %2!u!.\n",
  4409. networkId, status
  4410. );
  4411. }
  4412. //
  4413. // Release the NM lock.
  4414. //
  4415. NmpReleaseLock();
  4416. lockAcquired = FALSE;
  4417. //
  4418. // Check if we found the parameters we need. If not,
  4419. // try the cluster database.
  4420. //
  4421. if (status != ERROR_SUCCESS) {
  4422. status = NmpMulticastGetDatabaseLeaseParameters(
  4423. Network,
  4424. &networkKey,
  4425. &netParamKey,
  4426. &requestId,
  4427. &serverAddress,
  4428. &mcastAddress
  4429. );
  4430. if (status != ERROR_SUCCESS) {
  4431. ClRtlLogPrint(LOG_UNUSUAL,
  4432. "[NM] Failed to find multicast lease "
  4433. "parameters for network %1!ws! in "
  4434. "cluster database, status %2!u!.\n",
  4435. networkId, status
  4436. );
  4437. }
  4438. }
  4439. //
  4440. // Remember the old multicast address.
  4441. //
  4442. if (mcastAddress != NULL) {
  4443. status = NmpStoreString(mcastAddress, &oldMcastAddress, NULL);
  4444. if (status != ERROR_SUCCESS) {
  4445. ClRtlLogPrint(LOG_UNUSUAL,
  4446. "[NM] Failed to copy current multicast "
  4447. "address (%1!ws!) for network %2!ws! "
  4448. "during lease renewal, status %3!u!.\n",
  4449. mcastAddress, networkId, status
  4450. );
  4451. //
  4452. // Not a fatal error. Only affects event-log
  4453. // decision.
  4454. //
  4455. oldMcastAddress = NULL;
  4456. }
  4457. }
  4458. //
  4459. // Get an address either by renewing a current
  4460. // lease or obtaining a new lease.
  4461. //
  4462. status = NmpGetMulticastAddress(
  4463. Network,
  4464. &mcastAddress,
  4465. &serverAddress,
  4466. &requestId,
  4467. &parameters
  4468. );
  4469. if (status != ERROR_SUCCESS) {
  4470. if (status == ERROR_TIMEOUT) {
  4471. //
  4472. // The MADCAP server, if it exists, is currently not
  4473. // responding.
  4474. //
  4475. status = NmpMulticastNeedRetryRenew(
  4476. Network,
  4477. &deferRetry
  4478. );
  4479. if (status != ERROR_SUCCESS || deferRetry == 0) {
  4480. //
  4481. // Choose an address, but only if there is a
  4482. // local interface on this network. Otherwise,
  4483. // we cannot assume that the MADCAP server is
  4484. // unresponsive because we may have no way to
  4485. // contact it.
  4486. //
  4487. if (!localInterface) {
  4488. status = ERROR_CLUSTER_NETINTERFACE_NOT_FOUND;
  4489. ClRtlLogPrint(LOG_UNUSUAL,
  4490. "[NM] Cannot choose a multicast address "
  4491. "for network %1!ws! because this node "
  4492. "has no local interface.\n",
  4493. networkId
  4494. );
  4495. goto error_exit;
  4496. }
  4497. status = NmpChooseMulticastAddress(
  4498. Network,
  4499. &parameters
  4500. );
  4501. if (status != ERROR_SUCCESS) {
  4502. ClRtlLogPrint(LOG_UNUSUAL,
  4503. "[NM] Failed to choose a default multicast "
  4504. "address for network %1!ws!, status %2!u!.\n",
  4505. networkId, status
  4506. );
  4507. goto error_exit;
  4508. } else {
  4509. NmpReportMulticastAddressChoice(
  4510. Network,
  4511. parameters.Address,
  4512. oldMcastAddress
  4513. );
  4514. }
  4515. } else {
  4516. //
  4517. // Set the renew timer once we reacquire the
  4518. // network lock.
  4519. //
  4520. }
  4521. }
  4522. } else {
  4523. NmpReportMulticastAddressLease(
  4524. Network,
  4525. &parameters,
  4526. oldMcastAddress
  4527. );
  4528. }
  4529. if (deferRetry == 0) {
  4530. if (status != ERROR_SUCCESS) {
  4531. ClRtlLogPrint(LOG_UNUSUAL,
  4532. "[NM] Failed to obtain a multicast "
  4533. "address for network %1!ws! during "
  4534. "lease renewal, status %2!u!.\n",
  4535. networkId, status
  4536. );
  4537. NmpReportMulticastAddressFailure(Network, status);
  4538. NmpMulticastSetNoAddressParameters(Network, &parameters);
  4539. }
  4540. //
  4541. // This may be the first configuration for this
  4542. // network for this cluster instantiation, so
  4543. // generate a new salt value.
  4544. //
  4545. status = NmpGenerateMulticastKeySalt(
  4546. Network,
  4547. &parameters.Salt,
  4548. &parameters.SaltLength
  4549. );
  4550. if (status != ERROR_SUCCESS) {
  4551. ClRtlLogPrint(LOG_UNUSUAL,
  4552. "[NM] Failed to generate multicast "
  4553. "key salt for network %1!ws! during "
  4554. "lease renewal, status %2!u!.\n",
  4555. networkId, status
  4556. );
  4557. goto error_exit;
  4558. }
  4559. //
  4560. // Disseminate the new multicast parameters.
  4561. //
  4562. status = NmpMulticastNotifyConfigChange(
  4563. Network,
  4564. networkKey,
  4565. &netParamKey,
  4566. &parameters,
  4567. NULL,
  4568. 0
  4569. );
  4570. if (status != ERROR_SUCCESS) {
  4571. ClRtlLogPrint(LOG_UNUSUAL,
  4572. "[NM] Failed to disseminate multicast "
  4573. "configuration for network %1!ws! during "
  4574. "lease renewal, status %2!u!.\n",
  4575. networkId, status
  4576. );
  4577. goto error_exit;
  4578. }
  4579. }
  4580. error_exit:
  4581. if (lockAcquired && (networkKey != NULL || netParamKey != NULL)) {
  4582. NmpReleaseLock();
  4583. lockAcquired = FALSE;
  4584. }
  4585. if (networkKey != NULL) {
  4586. DmCloseKey(networkKey);
  4587. networkKey = NULL;
  4588. }
  4589. if (netParamKey != NULL) {
  4590. DmCloseKey(netParamKey);
  4591. netParamKey = NULL;
  4592. }
  4593. if (requestId.ClientUID != NULL) {
  4594. MIDL_user_free(requestId.ClientUID);
  4595. RtlZeroMemory(&requestId, sizeof(requestId));
  4596. }
  4597. if (mcastAddress != NULL) {
  4598. MIDL_user_free(mcastAddress);
  4599. mcastAddress = NULL;
  4600. }
  4601. if (serverAddress != NULL) {
  4602. MIDL_user_free(serverAddress);
  4603. serverAddress = NULL;
  4604. }
  4605. if (oldMcastAddress != NULL) {
  4606. MIDL_user_free(oldMcastAddress);
  4607. oldMcastAddress = NULL;
  4608. }
  4609. NmpMulticastFreeParameters(&parameters);
  4610. if (!lockAcquired) {
  4611. NmpAcquireLock();
  4612. lockAcquired = TRUE;
  4613. }
  4614. if (deferRetry != 0) {
  4615. //
  4616. // Now that the lock is held, start the timer to
  4617. // renew again.
  4618. //
  4619. NmpStartNetworkMulticastAddressRenewTimer(
  4620. Network,
  4621. NMP_MADCAP_TO_NM_TIME(deferRetry)
  4622. );
  4623. status = ERROR_SUCCESS;
  4624. }
  4625. return(status);
  4626. } // NmpRenewMulticastAddressLease
  4627. DWORD
  4628. NmpReleaseMulticastAddress(
  4629. IN PNM_NETWORK Network
  4630. )
  4631. /*++
  4632. Routine Description:
  4633. Contacts MADCAP server to release a multicast address
  4634. that was previously obtained in a lease.
  4635. If multiple addresses need to be released, reschedules
  4636. MADCAP worker thread.
  4637. Notes:
  4638. Called and must return with NM lock held.
  4639. --*/
  4640. {
  4641. DWORD status;
  4642. LPCWSTR networkId = OmObjectId(Network);
  4643. BOOLEAN lockAcquired = TRUE;
  4644. PNM_NETWORK_MADCAP_ADDRESS_RELEASE releaseInfo = NULL;
  4645. PLIST_ENTRY entry;
  4646. UCHAR requestBuffer[NMP_MADCAP_REQUEST_BUFFER_SIZE];
  4647. PMCAST_LEASE_REQUEST request;
  4648. //
  4649. // Pop a lease data structure off the release list.
  4650. //
  4651. if (IsListEmpty(&(Network->McastAddressReleaseList))) {
  4652. return(ERROR_SUCCESS);
  4653. }
  4654. entry = RemoveHeadList(&(Network->McastAddressReleaseList));
  4655. releaseInfo = CONTAINING_RECORD(
  4656. entry,
  4657. NM_NETWORK_MADCAP_ADDRESS_RELEASE,
  4658. Linkage
  4659. );
  4660. //
  4661. // Release the network lock.
  4662. //
  4663. NmpReleaseLock();
  4664. lockAcquired = FALSE;
  4665. ClRtlLogPrint(LOG_NOISE,
  4666. "[NM] Releasing multicast address %1!ws! for "
  4667. "network %2!ws!.\n",
  4668. releaseInfo->McastAddress, networkId
  4669. );
  4670. //
  4671. // Initialize MADCAP, if not done already.
  4672. //
  4673. if (!NmpMadcapClientInitialized) {
  4674. DWORD madcapVersion = MCAST_API_CURRENT_VERSION;
  4675. status = McastApiStartup(&madcapVersion);
  4676. if (status != ERROR_SUCCESS) {
  4677. ClRtlLogPrint(LOG_UNUSUAL,
  4678. "[NM] Failed to initialize MADCAP API, "
  4679. "status %1!u!.\n",
  4680. status
  4681. );
  4682. goto error_exit;
  4683. }
  4684. NmpMadcapClientInitialized = TRUE;
  4685. }
  4686. //
  4687. // Build the MADCAP request structure.
  4688. //
  4689. request = (PMCAST_LEASE_REQUEST) &requestBuffer[0];
  4690. RtlZeroMemory(request, sizeof(requestBuffer));
  4691. request->MinLeaseDuration = 0; // currently ignored
  4692. request->MinAddrCount = 1; // currently ignored
  4693. request->MaxLeaseStartTime = (LONG) time(NULL); // currently ignored
  4694. request->AddrCount = 1;
  4695. request->pAddrBuf = (PBYTE)request + NMP_MADCAP_REQUEST_ADDR_OFFSET;
  4696. status = ClRtlTcpipStringToAddress(
  4697. releaseInfo->McastAddress,
  4698. ((PULONG) request->pAddrBuf)
  4699. );
  4700. if (status != ERROR_SUCCESS) {
  4701. ClRtlLogPrint(LOG_UNUSUAL,
  4702. "[NM] Failed to convert requested address %1!ws! "
  4703. "into a TCP/IP address, status %2!u!.\n",
  4704. releaseInfo->McastAddress, status
  4705. );
  4706. goto error_exit;
  4707. }
  4708. status = ClRtlTcpipStringToAddress(
  4709. releaseInfo->ServerAddress,
  4710. (PULONG) &(request->ServerAddress.IpAddrV4)
  4711. );
  4712. if (status != ERROR_SUCCESS) {
  4713. ClRtlLogPrint(LOG_UNUSUAL,
  4714. "[NM] Failed to convert server address %1!ws! "
  4715. "into a TCP/IP address, status %2!u!.\n",
  4716. releaseInfo->ServerAddress, status
  4717. );
  4718. goto error_exit;
  4719. }
  4720. //
  4721. // Call MADCAP to release the address.
  4722. //
  4723. status = McastReleaseAddress(
  4724. AF_INET,
  4725. &releaseInfo->RequestId,
  4726. request
  4727. );
  4728. if (status != ERROR_SUCCESS) {
  4729. ClRtlLogPrint(LOG_UNUSUAL,
  4730. "[NM] Failed to release multicast address %1!ws! "
  4731. "through MADCAP server %2!ws!, status %3!u!.\n",
  4732. releaseInfo->McastAddress,
  4733. releaseInfo->ServerAddress,
  4734. status
  4735. );
  4736. goto error_exit;
  4737. }
  4738. ClRtlLogPrint(LOG_NOISE,
  4739. "[NM] Successfully released multicast address "
  4740. "%1!ws! for network %2!ws!.\n",
  4741. releaseInfo->McastAddress, networkId
  4742. );
  4743. error_exit:
  4744. NmpFreeMulticastAddressRelease(releaseInfo);
  4745. if (!lockAcquired) {
  4746. NmpAcquireLock();
  4747. lockAcquired = TRUE;
  4748. }
  4749. if (!IsListEmpty(&(Network->McastAddressReleaseList))) {
  4750. NmpScheduleMulticastAddressRelease(Network);
  4751. }
  4752. return(status);
  4753. } // NmpReleaseMulticastAddress
  4754. DWORD
  4755. NmpProcessMulticastConfiguration(
  4756. IN PNM_NETWORK Network,
  4757. IN PNM_NETWORK_MULTICAST_PARAMETERS Parameters,
  4758. OUT PNM_NETWORK_MULTICAST_PARAMETERS UndoParameters
  4759. )
  4760. /*++
  4761. Routine Description:
  4762. Processes configuration changes and calls clusnet if
  4763. appropriate.
  4764. If multicast is disabled, the address, key, and
  4765. salt may be NULL. In this case, choose defaults
  4766. to send to clusnet, but do not commit the changes
  4767. in the local network object.
  4768. Arguments:
  4769. Network - network to process
  4770. Parameters - parameters with which to configure Network.
  4771. If successful, Parameters data structure
  4772. is cleared.
  4773. UndoParameters - If successful, former multicast
  4774. parameters of Network. Must be freed
  4775. by caller.
  4776. Notes:
  4777. Called and returns with NM lock held.
  4778. --*/
  4779. {
  4780. DWORD status = ERROR_SUCCESS;
  4781. LPWSTR networkId = (LPWSTR) OmObjectId(Network);
  4782. BOOLEAN callClusnet = FALSE;
  4783. LPWSTR mcastAddress = NULL;
  4784. DWORD brand;
  4785. PVOID tdiMcastAddress = NULL;
  4786. DWORD tdiMcastAddressLength = 0;
  4787. UUID networkIdGuid;
  4788. BOOLEAN mcastAddrChange = FALSE;
  4789. BOOLEAN mcastKeyChange = FALSE;
  4790. BOOLEAN mcastSaltChange = FALSE;
  4791. #if CLUSTER_BETA
  4792. ClRtlLogPrint(LOG_NOISE,
  4793. "[NM] Processing multicast configuration parameters "
  4794. "for network %1!ws!.\n",
  4795. networkId
  4796. /* ,
  4797. ((Parameters->Address != NULL) ? Parameters->Address : L"<NULL>") */
  4798. );
  4799. #endif // CLUSTER_BETA
  4800. //
  4801. // Zero the undo parameters so that freeing them is not
  4802. // destructive.
  4803. //
  4804. RtlZeroMemory(UndoParameters, sizeof(*UndoParameters));
  4805. //
  4806. // If multicast is not disabled, we need valid parameters.
  4807. //
  4808. if (!Parameters->Disabled &&
  4809. ((Parameters->Address == NULL) ||
  4810. (Parameters->Key == NULL) ||
  4811. (Parameters->Salt == NULL)
  4812. )) {
  4813. status = ERROR_INVALID_PARAMETER;
  4814. goto error_exit;
  4815. }
  4816. //
  4817. // First determine if we need to reconfigure clusnet.
  4818. //
  4819. if (Parameters->Address != NULL) {
  4820. if (Network->MulticastAddress == NULL ||
  4821. wcscmp(Network->MulticastAddress, Parameters->Address) != 0) {
  4822. // The multicast address in the config parameters is
  4823. // different from the one in memory.
  4824. mcastAddrChange = TRUE;
  4825. }
  4826. mcastAddress = Parameters->Address;
  4827. } else {
  4828. mcastAddress = NmpNullMulticastAddress;
  4829. }
  4830. if (Parameters->Key != NULL) {
  4831. if (Network->MulticastKey == NULL ||
  4832. (Network->MulticastKeyLength != Parameters->KeyLength ||
  4833. RtlCompareMemory(
  4834. Network->MulticastKey,
  4835. Parameters->Key,
  4836. Parameters->KeyLength
  4837. ) != Parameters->KeyLength
  4838. )) {
  4839. // The key in the config parameters is different
  4840. // from the key in memory.
  4841. mcastKeyChange = TRUE;
  4842. }
  4843. }
  4844. if (Parameters->Salt != NULL) {
  4845. if (Network->MulticastKeySalt == NULL ||
  4846. (Network->MulticastKeySaltLength != Parameters->SaltLength ||
  4847. RtlCompareMemory(
  4848. Network->MulticastKeySalt,
  4849. Parameters->Salt,
  4850. Parameters->SaltLength
  4851. ) != Parameters->SaltLength
  4852. )) {
  4853. // The salt in the config parameters is different
  4854. // from the salt in memory.
  4855. mcastSaltChange = TRUE;
  4856. }
  4857. }
  4858. if (!Parameters->Disabled &&
  4859. (NmpIsNetworkMulticastEnabled(Network))) {
  4860. // Multicast is now enabled. Call clusnet with the new address.
  4861. callClusnet = TRUE;
  4862. }
  4863. if (Parameters->Disabled &&
  4864. (NmpIsNetworkMulticastEnabled(Network))) {
  4865. // Multicast is now disabled. Call clusnet with NULL address
  4866. // regardless of which address was specified in the
  4867. // parameters.
  4868. mcastAddress = NmpNullMulticastAddress;
  4869. callClusnet = TRUE;
  4870. }
  4871. if (!Parameters->Disabled &&
  4872. (mcastAddrChange || mcastKeyChange || mcastSaltChange)) {
  4873. // The multicast address, key, and/or salt changed and
  4874. // multicast is enabled.
  4875. callClusnet = TRUE;
  4876. }
  4877. //
  4878. // If this network does not have a local interface, do not
  4879. // plumb the configuration into clusnet. If this network
  4880. // does have a local interface, the network must already
  4881. // be registered.
  4882. //
  4883. if (Network->LocalInterface != NULL) {
  4884. //
  4885. // Verify that the network is registered.
  4886. //
  4887. if (!NmpIsNetworkRegistered(Network)) {
  4888. status = ERROR_CLUSTER_NETWORK_NOT_FOUND;
  4889. ClRtlLogPrint(LOG_UNUSUAL,
  4890. "[NM] Cannot configure multicast parameters "
  4891. "for unregistered network %1!ws!.\n",
  4892. networkId
  4893. );
  4894. goto error_exit;
  4895. }
  4896. } else {
  4897. //
  4898. // Do not call clusnet, but don't fail call. Also,
  4899. // store new parameters in network object.
  4900. //
  4901. callClusnet = FALSE;
  4902. ClRtlLogPrint(LOG_NOISE,
  4903. "[NM] Not configuring cluster network driver with "
  4904. "multicast parameters because network %1!ws! "
  4905. "has no local interface.\n",
  4906. networkId
  4907. );
  4908. }
  4909. //
  4910. // Plumb the new configuration into clusnet. The new
  4911. // configuration will reflect the current parameters
  4912. // block except for the address, which is stored in
  4913. // temporary mcastAddress variable. mcastAddress points
  4914. // either to the address in the parameters block or
  4915. // the NULL multicast address if we are disabling.
  4916. //
  4917. if (callClusnet) {
  4918. //
  4919. // Build a TDI address from the address string.
  4920. //
  4921. status = ClRtlBuildTcpipTdiAddress(
  4922. mcastAddress,
  4923. Network->LocalInterface->ClusnetEndpoint,
  4924. &tdiMcastAddress,
  4925. &tdiMcastAddressLength
  4926. );
  4927. if (status != ERROR_SUCCESS) {
  4928. ClRtlLogPrint(LOG_UNUSUAL,
  4929. "[NM] Failed to build TCP/IP TDI multicast address "
  4930. "%1!ws! port %2!ws! for network %3!ws!, "
  4931. "status %4!u!.\n",
  4932. mcastAddress,
  4933. Network->LocalInterface->ClusnetEndpoint,
  4934. networkId, status
  4935. );
  4936. goto error_exit;
  4937. }
  4938. //
  4939. // Use the lower bytes of the network GUID for the
  4940. // brand.
  4941. //
  4942. status = UuidFromString(networkId, &networkIdGuid);
  4943. if (status == RPC_S_OK) {
  4944. brand = *((PDWORD)&(networkIdGuid.Data4[4]));
  4945. } else {
  4946. brand = 0;
  4947. }
  4948. ClRtlLogPrint(LOG_NOISE,
  4949. "[NM] Configuring cluster network driver with "
  4950. "multicast parameters for network %1!ws!.\n",
  4951. networkId
  4952. );
  4953. status = ClusnetConfigureMulticast(
  4954. NmClusnetHandle,
  4955. Network->ShortId,
  4956. brand,
  4957. tdiMcastAddress,
  4958. tdiMcastAddressLength,
  4959. Parameters->Key,
  4960. Parameters->KeyLength,
  4961. Parameters->Salt,
  4962. Parameters->SaltLength
  4963. );
  4964. if (status != ERROR_SUCCESS) {
  4965. ClRtlLogPrint(LOG_UNUSUAL,
  4966. "[NM] Failed to configure multicast parameters "
  4967. "for network %1!ws!, status %2!u!.\n",
  4968. networkId, status
  4969. );
  4970. goto error_exit;
  4971. } else {
  4972. if (!Parameters->Disabled) {
  4973. Network->Flags |= NM_FLAG_NET_MULTICAST_ENABLED;
  4974. } else {
  4975. Network->Flags &= ~NM_FLAG_NET_MULTICAST_ENABLED;
  4976. }
  4977. }
  4978. }
  4979. //
  4980. // If successful, commit the changes to the network object.
  4981. // The old state of the network object will be stored in
  4982. // the undo parameters, in case we need to undo this change.
  4983. // The new state of the network object will reflect the
  4984. // paramters block, including the address (even if we
  4985. // disabled).
  4986. //
  4987. UndoParameters->Address = Network->MulticastAddress;
  4988. Network->MulticastAddress = Parameters->Address;
  4989. UndoParameters->Key = Network->MulticastKey;
  4990. Network->MulticastKey = Parameters->Key;
  4991. UndoParameters->KeyLength = Network->MulticastKeyLength;
  4992. Network->MulticastKeyLength = Parameters->KeyLength;
  4993. UndoParameters->Salt = Network->MulticastKeySalt;
  4994. Network->MulticastKeySalt = Parameters->Salt;
  4995. UndoParameters->SaltLength = Network->MulticastKeySaltLength;
  4996. Network->MulticastKeySaltLength = Parameters->SaltLength;
  4997. UndoParameters->LeaseObtained = Network->MulticastLeaseObtained;
  4998. Network->MulticastLeaseObtained = Parameters->LeaseObtained;
  4999. UndoParameters->LeaseExpires = Network->MulticastLeaseExpires;
  5000. Network->MulticastLeaseExpires = Parameters->LeaseExpires;
  5001. UndoParameters->LeaseRequestId = Network->MulticastLeaseRequestId;
  5002. Network->MulticastLeaseRequestId = Parameters->LeaseRequestId;
  5003. UndoParameters->LeaseServer = Network->MulticastLeaseServer;
  5004. Network->MulticastLeaseServer = Parameters->LeaseServer;
  5005. //
  5006. // Zero the parameters structure so that the memory now
  5007. // pointed to by the network object is not freed.
  5008. //
  5009. RtlZeroMemory(Parameters, sizeof(*Parameters));
  5010. error_exit:
  5011. if (tdiMcastAddress != NULL) {
  5012. LocalFree(tdiMcastAddress);
  5013. tdiMcastAddress = NULL;
  5014. }
  5015. return(status);
  5016. } // NmpProcessMulticastConfiguration
  5017. VOID
  5018. NmpNetworkMadcapWorker(
  5019. IN PCLRTL_WORK_ITEM WorkItem,
  5020. IN DWORD Status,
  5021. IN DWORD BytesTransferred,
  5022. IN ULONG_PTR IoContext
  5023. )
  5024. /*++
  5025. Routine Description:
  5026. Worker routine for deferred operations on network objects.
  5027. Invoked to process items placed in the cluster delayed work queue.
  5028. Arguments:
  5029. WorkItem - A pointer to a work item structure that identifies the
  5030. network for which to perform work.
  5031. Status - Ignored.
  5032. BytesTransferred - Ignored.
  5033. IoContext - Ignored.
  5034. Return Value:
  5035. None.
  5036. Notes:
  5037. This routine is run in an asynchronous worker thread.
  5038. The NmpActiveThreadCount was incremented when the thread was
  5039. scheduled. The network object was also referenced.
  5040. --*/
  5041. {
  5042. DWORD status;
  5043. PNM_NETWORK network = (PNM_NETWORK) WorkItem->Context;
  5044. LPCWSTR networkId = OmObjectId(network);
  5045. BOOLEAN rescheduled = FALSE;
  5046. NmpAcquireLock();
  5047. ClRtlLogPrint(LOG_NOISE,
  5048. "[NM] Worker thread processing MADCAP client requests "
  5049. "for network %1!ws!.\n",
  5050. networkId
  5051. );
  5052. if ((NmpState >= NmStateOnlinePending) && !NM_DELETE_PENDING(network)) {
  5053. while (TRUE) {
  5054. if (!(network->Flags & NM_NET_MADCAP_WORK_FLAGS)) {
  5055. //
  5056. // No more work to do - break out of loop.
  5057. //
  5058. break;
  5059. }
  5060. //
  5061. // Reconfigure multicast if needed.
  5062. //
  5063. if (network->Flags & NM_FLAG_NET_RECONFIGURE_MCAST) {
  5064. network->Flags &= ~NM_FLAG_NET_RECONFIGURE_MCAST;
  5065. status = NmpReconfigureMulticast(network);
  5066. if (status != ERROR_SUCCESS) {
  5067. ClRtlLogPrint(LOG_UNUSUAL,
  5068. "[NM] Failed to reconfigure multicast "
  5069. "for network %1!ws!, status %2!u!.\n",
  5070. networkId, status
  5071. );
  5072. }
  5073. }
  5074. //
  5075. // Renew an address lease if needed.
  5076. //
  5077. if (network->Flags & NM_FLAG_NET_RENEW_MCAST_ADDRESS) {
  5078. network->Flags &= ~NM_FLAG_NET_RENEW_MCAST_ADDRESS;
  5079. status = NmpRenewMulticastAddressLease(network);
  5080. if (status != ERROR_SUCCESS) {
  5081. ClRtlLogPrint(LOG_UNUSUAL,
  5082. "[NM] Failed to renew multicast address "
  5083. "lease for network %1!ws!, status %2!u!.\n",
  5084. networkId, status
  5085. );
  5086. }
  5087. }
  5088. //
  5089. // Release an address lease if needed.
  5090. //
  5091. if (network->Flags & NM_FLAG_NET_RELEASE_MCAST_ADDRESS) {
  5092. network->Flags &= ~NM_FLAG_NET_RELEASE_MCAST_ADDRESS;
  5093. status = NmpReleaseMulticastAddress(network);
  5094. if (status != ERROR_SUCCESS) {
  5095. ClRtlLogPrint(LOG_UNUSUAL,
  5096. "[NM] Failed to release multicast address "
  5097. "lease for network %1!ws!, status %2!u!.\n",
  5098. networkId, status
  5099. );
  5100. }
  5101. }
  5102. if (!(network->Flags & NM_NET_MADCAP_WORK_FLAGS)) {
  5103. //
  5104. // No more work to do - break out of loop.
  5105. //
  5106. break;
  5107. }
  5108. //
  5109. // More work to do. Resubmit the work item. We do this instead
  5110. // of looping so we don't hog the worker thread. If
  5111. // rescheduling fails, we will loop again in this thread.
  5112. //
  5113. ClRtlLogPrint(LOG_NOISE,
  5114. "[NM] More MADCAP work to do for network %1!ws!. "
  5115. "Rescheduling worker thread.\n",
  5116. networkId
  5117. );
  5118. status = NmpScheduleNetworkMadcapWorker(network);
  5119. if (status == ERROR_SUCCESS) {
  5120. rescheduled = TRUE;
  5121. break;
  5122. }
  5123. }
  5124. } else {
  5125. network->Flags &= ~NM_NET_MADCAP_WORK_FLAGS;
  5126. }
  5127. if (!rescheduled) {
  5128. network->Flags &= ~NM_FLAG_NET_MADCAP_WORKER_RUNNING;
  5129. }
  5130. ClRtlLogPrint(LOG_NOISE,
  5131. "[NM] Worker thread finished processing MADCAP client "
  5132. "requests for network %1!ws!.\n",
  5133. networkId
  5134. );
  5135. NmpLockedLeaveApi();
  5136. NmpReleaseLock();
  5137. OmDereferenceObject(network);
  5138. return;
  5139. } // NmpNetworkMadcapWorker
  5140. DWORD
  5141. NmpScheduleNetworkMadcapWorker(
  5142. PNM_NETWORK Network
  5143. )
  5144. /*++
  5145. Routine Description:
  5146. Schedule a worker thread to execute madcap client
  5147. requests for this network
  5148. Arguments:
  5149. Network - Pointer to the network for which to schedule a worker thread.
  5150. Return Value:
  5151. A Win32 status code.
  5152. Notes:
  5153. Called with the NM global lock held.
  5154. --*/
  5155. {
  5156. DWORD status;
  5157. LPCWSTR networkId = OmObjectId(Network);
  5158. ClRtlInitializeWorkItem(
  5159. &(Network->MadcapWorkItem),
  5160. NmpNetworkMadcapWorker,
  5161. (PVOID) Network
  5162. );
  5163. status = ClRtlPostItemWorkQueue(
  5164. CsDelayedWorkQueue,
  5165. &(Network->MadcapWorkItem),
  5166. 0,
  5167. 0
  5168. );
  5169. if (status == ERROR_SUCCESS) {
  5170. ClRtlLogPrint(LOG_NOISE,
  5171. "[NM] Scheduled worker thread to execute MADCAP "
  5172. "client requests for network %1!ws!.\n",
  5173. networkId
  5174. );
  5175. NmpActiveThreadCount++;
  5176. Network->Flags |= NM_FLAG_NET_MADCAP_WORKER_RUNNING;
  5177. OmReferenceObject(Network);
  5178. }
  5179. else {
  5180. ClRtlLogPrint(LOG_UNUSUAL,
  5181. "[NM] Failed to schedule worker thread to execute "
  5182. "MADCAP client requests for network "
  5183. "%1!ws!, status %2!u!\n",
  5184. networkId,
  5185. status
  5186. );
  5187. }
  5188. return(status);
  5189. } // NmpScheduleNetworkMadcapWorker
  5190. VOID
  5191. NmpShareMulticastAddressLease(
  5192. IN PNM_NETWORK Network,
  5193. IN NM_MCAST_CONFIG ConfigType
  5194. )
  5195. /*++
  5196. Routine description:
  5197. Called after a non-manual refresh of the multicast
  5198. configuration, sets a timer to renew the multicast
  5199. address lease for this network, if one exists.
  5200. Notes:
  5201. Called and returns with NM lock held.
  5202. --*/
  5203. {
  5204. DWORD status;
  5205. LPCWSTR networkId = OmObjectId(Network);
  5206. DWORD disabled;
  5207. BOOLEAN lockAcquired = TRUE;
  5208. time_t leaseObtained;
  5209. time_t leaseExpires;
  5210. DWORD leaseTimer = 0;
  5211. NM_MCAST_LEASE_STATUS leaseStatus = NmMcastLeaseValid;
  5212. #if CLUSTER_BETA
  5213. ClRtlLogPrint(LOG_NOISE,
  5214. "[NM] Sharing ownership of multicast lease "
  5215. "for network %1!ws!.\n",
  5216. networkId
  5217. );
  5218. #endif // CLUSTER_BETA
  5219. NmpCheckMulticastAddressLease(
  5220. Network,
  5221. &leaseStatus,
  5222. &leaseObtained,
  5223. &leaseExpires
  5224. );
  5225. if (leaseStatus != NmMcastLeaseValid) {
  5226. NmpScheduleMulticastAddressRenewal(Network);
  5227. } else {
  5228. leaseTimer = NmpCalculateLeaseRenewTime(
  5229. Network,
  5230. ConfigType,
  5231. &leaseObtained,
  5232. &leaseExpires
  5233. );
  5234. NmpStartNetworkMulticastAddressRenewTimer(Network, leaseTimer);
  5235. }
  5236. return;
  5237. } // NmpShareMulticastAddressLease
  5238. DWORD
  5239. NmpMulticastFormManualConfigParameters(
  5240. IN PNM_NETWORK Network,
  5241. IN HDMKEY NetworkKey,
  5242. IN HDMKEY NetworkParametersKey,
  5243. IN BOOLEAN DisableConfig,
  5244. IN DWORD Disabled,
  5245. IN BOOLEAN McastAddressConfig,
  5246. IN LPWSTR McastAddress,
  5247. OUT BOOLEAN * NeedUpdate,
  5248. OUT PNM_NETWORK_MULTICAST_PARAMETERS Parameters
  5249. )
  5250. /*++
  5251. Routine Description:
  5252. Using parameters provided and those already configured,
  5253. form a parameters structure to reflect a manual
  5254. configuration.
  5255. Arguments:
  5256. Network - network being configured
  5257. NetworkKey - network key in cluster database
  5258. NetworkParametersKey - network parameters key in cluster database
  5259. DisableConfig - whether the disabled value was set
  5260. Disabled - if DisableConfig, the value that was set
  5261. McastAddressConfig - whether the multicast address value was set
  5262. McastAddress - if McastAddressConfig, the value that was set
  5263. NeedUpdate - indicates whether an update is needed, i.e. whether
  5264. anything changed
  5265. Parameters - parameter structure, allocated by caller, to fill in
  5266. --*/
  5267. {
  5268. DWORD status;
  5269. LPCWSTR networkId = OmObjectId(Network);
  5270. BOOLEAN lockAcquired = FALSE;
  5271. DWORD netobjDisabled;
  5272. BOOLEAN disabledChange = FALSE;
  5273. BOOLEAN mcastAddressDefault = FALSE;
  5274. BOOLEAN mcastAddressChange = FALSE;
  5275. BOOLEAN getAddress = FALSE;
  5276. DWORD len;
  5277. BOOLEAN localInterface = FALSE;
  5278. LPWSTR mcastAddress = NULL;
  5279. LPWSTR serverAddress = NULL;
  5280. MCAST_CLIENT_UID requestId = {NULL, 0};
  5281. PNM_NETWORK_MADCAP_ADDRESS_RELEASE release = NULL;
  5282. //
  5283. // Validate incoming parameters.
  5284. //
  5285. // Any nonzero disabled value is set to 1 for simplification.
  5286. //
  5287. if (DisableConfig) {
  5288. if (Disabled != 0) {
  5289. Disabled = 1;
  5290. }
  5291. }
  5292. //
  5293. // Non-valid and NULL multicast addresses signify
  5294. // revert-to-default.
  5295. //
  5296. if (McastAddressConfig &&
  5297. (McastAddress == NULL || !NmpMulticastValidateAddress(McastAddress))) {
  5298. mcastAddressDefault = TRUE;
  5299. McastAddress = NULL;
  5300. }
  5301. //
  5302. // Base decisions on the current status of the network
  5303. // object.
  5304. //
  5305. NmpAcquireLock();
  5306. lockAcquired = TRUE;
  5307. netobjDisabled = (NmpIsNetworkMulticastEnabled(Network) ? 0 : 1);
  5308. //
  5309. // See if anything changed.
  5310. //
  5311. if (DisableConfig) {
  5312. if (Disabled != netobjDisabled) {
  5313. disabledChange = TRUE;
  5314. }
  5315. }
  5316. if (McastAddressConfig) {
  5317. if (mcastAddressDefault) {
  5318. mcastAddressChange = TRUE;
  5319. } else {
  5320. if (Network->MulticastAddress != NULL) {
  5321. if (lstrcmpW(Network->MulticastAddress, McastAddress) != 0) {
  5322. mcastAddressChange = TRUE;
  5323. }
  5324. } else {
  5325. mcastAddressChange = TRUE;
  5326. }
  5327. }
  5328. }
  5329. if (!disabledChange && !mcastAddressChange) {
  5330. *NeedUpdate = FALSE;
  5331. status = ERROR_SUCCESS;
  5332. #if CLUSTER_BETA
  5333. ClRtlLogPrint(LOG_NOISE,
  5334. "[NM] Private property update to network %1!ws! "
  5335. "contains no multicast changes.\n",
  5336. networkId
  5337. );
  5338. #endif // CLUSTER_BETA
  5339. goto error_exit;
  5340. }
  5341. //
  5342. // Initialize the parameters from the network object.
  5343. //
  5344. status = NmpMulticastCreateParameters(
  5345. netobjDisabled,
  5346. Network->MulticastAddress,
  5347. NULL, // salt
  5348. 0, // salt length
  5349. NULL, // key
  5350. 0, // key length
  5351. Network->MulticastLeaseObtained,
  5352. Network->MulticastLeaseExpires,
  5353. &Network->MulticastLeaseRequestId,
  5354. Network->MulticastLeaseServer,
  5355. NmMcastConfigManual,
  5356. Parameters
  5357. );
  5358. if (status != ERROR_SUCCESS) {
  5359. goto error_exit;
  5360. }
  5361. localInterface = (BOOLEAN)(Network->LocalInterface != NULL);
  5362. NmpReleaseLock();
  5363. lockAcquired = FALSE;
  5364. if (mcastAddressChange) {
  5365. //
  5366. // Figure out what address to use.
  5367. //
  5368. if (!mcastAddressDefault) {
  5369. //
  5370. // An address was dictated.
  5371. //
  5372. // If we currently have a leased address, release it.
  5373. //
  5374. if (NmpNeedRelease(
  5375. Parameters->Address,
  5376. Parameters->LeaseServer,
  5377. &(Parameters->LeaseRequestId),
  5378. Parameters->LeaseExpires
  5379. )) {
  5380. status = NmpCreateMulticastAddressRelease(
  5381. Parameters->Address,
  5382. Parameters->LeaseServer,
  5383. &(Parameters->LeaseRequestId),
  5384. &release
  5385. );
  5386. if (status != ERROR_SUCCESS) {
  5387. ClRtlLogPrint(LOG_UNUSUAL,
  5388. "[NM] Failed to create multicast address "
  5389. "release for address %1!ws! on network %2!ws! "
  5390. "during manual configuration, status %3!u!.\n",
  5391. ((Parameters->Address != NULL) ?
  5392. Parameters->Address : L"<NULL>"),
  5393. networkId, status
  5394. );
  5395. goto error_exit;
  5396. }
  5397. }
  5398. //
  5399. // Store the new address in the parameters data structure.
  5400. //
  5401. status = NmpStoreString(
  5402. McastAddress,
  5403. &Parameters->Address,
  5404. NULL
  5405. );
  5406. if (status != ERROR_SUCCESS) {
  5407. goto error_exit;
  5408. }
  5409. Parameters->ConfigType = NmMcastConfigManual;
  5410. Parameters->LeaseObtained = 0;
  5411. Parameters->LeaseExpires = 0;
  5412. //
  5413. // Clear out the lease server.
  5414. //
  5415. len = (Parameters->LeaseServer != NULL) ?
  5416. NM_WCSLEN(Parameters->LeaseServer) : 0;
  5417. status = NmpStoreString(
  5418. NmpNullMulticastAddress,
  5419. &Parameters->LeaseServer,
  5420. &len
  5421. );
  5422. if (status != ERROR_SUCCESS) {
  5423. goto error_exit;
  5424. }
  5425. } else {
  5426. //
  5427. // Need to find an address elsewhere.
  5428. //
  5429. getAddress = TRUE;
  5430. }
  5431. }
  5432. //
  5433. // We also may need to renew the lease if we are moving from
  5434. // disabled to enabled and an address was not specified, but
  5435. // only if we don't already have a lease that doesn't expire.
  5436. //
  5437. if (disabledChange && !Disabled) {
  5438. Parameters->Disabled = 0;
  5439. if (!mcastAddressChange) {
  5440. //
  5441. // An address was not set. All we currently have is
  5442. // what's in the network object (and copied to the
  5443. // parameters block).
  5444. //
  5445. if (Parameters->Address != NULL &&
  5446. NmpMulticastValidateAddress(Parameters->Address)) {
  5447. //
  5448. // We already have a valid multicast address, but
  5449. // the lease may need to be renewed.
  5450. //
  5451. if (Parameters->LeaseExpires != 0) {
  5452. getAddress = TRUE;
  5453. } else {
  5454. Parameters->ConfigType = NmMcastConfigManual;
  5455. }
  5456. } else {
  5457. //
  5458. // We have no valid multicast address. Get one.
  5459. //
  5460. getAddress = TRUE;
  5461. }
  5462. }
  5463. }
  5464. //
  5465. // We don't bother renewing the lease if we are disabling.
  5466. //
  5467. if (Disabled) {
  5468. getAddress = FALSE;
  5469. Parameters->Disabled = Disabled;
  5470. //
  5471. // If we currently have a leased address that we haven't
  5472. // already decided to release, release it.
  5473. //
  5474. if (release == NULL && NmpNeedRelease(
  5475. Parameters->Address,
  5476. Parameters->LeaseServer,
  5477. &(Parameters->LeaseRequestId),
  5478. Parameters->LeaseExpires
  5479. )) {
  5480. status = NmpCreateMulticastAddressRelease(
  5481. Parameters->Address,
  5482. Parameters->LeaseServer,
  5483. &(Parameters->LeaseRequestId),
  5484. &release
  5485. );
  5486. if (status != ERROR_SUCCESS) {
  5487. ClRtlLogPrint(LOG_UNUSUAL,
  5488. "[NM] Failed to create multicast address "
  5489. "release for address %1!ws! on network %2!ws! "
  5490. "during manual configuration, status %3!u!.\n",
  5491. ((Parameters->Address != NULL) ?
  5492. Parameters->Address : L"<NULL>"),
  5493. networkId, status
  5494. );
  5495. goto error_exit;
  5496. }
  5497. //
  5498. // Since we are releasing the address, there is not
  5499. // much point in saving it. If we re-enable multicast
  5500. // in the future, we will request a fresh lease.
  5501. //
  5502. len = (Parameters->LeaseServer != NULL) ?
  5503. NM_WCSLEN(Parameters->LeaseServer) : 0;
  5504. status = NmpStoreString(
  5505. NmpNullMulticastAddress,
  5506. &Parameters->LeaseServer,
  5507. &len
  5508. );
  5509. if (status != ERROR_SUCCESS) {
  5510. goto error_exit;
  5511. }
  5512. len = (Parameters->Address != NULL) ?
  5513. NM_WCSLEN(Parameters->Address) : 0;
  5514. status = NmpStoreString(
  5515. NmpNullMulticastAddress,
  5516. &Parameters->Address,
  5517. &len
  5518. );
  5519. if (status != ERROR_SUCCESS) {
  5520. goto error_exit;
  5521. }
  5522. // requestId is initialized to be blank
  5523. status = NmpStoreRequestId(
  5524. &requestId,
  5525. &Parameters->LeaseRequestId
  5526. );
  5527. if (status != ERROR_SUCCESS) {
  5528. goto error_exit;
  5529. }
  5530. //
  5531. // Remember that this had been a MADCAP address.
  5532. //
  5533. Parameters->ConfigType = NmMcastConfigMadcap;
  5534. } else if (!(mcastAddressChange && !mcastAddressDefault)) {
  5535. //
  5536. // If no address is being set, we may keep the former
  5537. // address in the database even though it is not being
  5538. // used. We also need to remember the way we got that
  5539. // address in case it is ever used again. If we fail
  5540. // to determine the previous configuration, we need
  5541. // to set it to manual so that we don't lose a manual
  5542. // configuration.
  5543. //
  5544. status = NmpQueryMulticastConfigType(
  5545. Network,
  5546. NetworkKey,
  5547. &NetworkParametersKey,
  5548. &Parameters->ConfigType
  5549. );
  5550. if (status != ERROR_SUCCESS) {
  5551. ClRtlLogPrint(LOG_UNUSUAL,
  5552. "[NM] Failed to query multicast address "
  5553. "config type for network %1!ws! during "
  5554. "manual configuration, status %2!u!.\n",
  5555. networkId, status
  5556. );
  5557. Parameters->ConfigType = NmMcastConfigManual;
  5558. }
  5559. }
  5560. }
  5561. //
  5562. // Synchronously get a new address.
  5563. //
  5564. if (getAddress) {
  5565. //
  5566. // Create temporary strings for proposed address, lease
  5567. // server, and request id.
  5568. //
  5569. status = NmpStoreString(Parameters->Address, &mcastAddress, NULL);
  5570. if (status != ERROR_SUCCESS) {
  5571. goto error_exit;
  5572. }
  5573. status = NmpStoreString(Parameters->LeaseServer, &serverAddress, NULL);
  5574. if (status != ERROR_SUCCESS) {
  5575. goto error_exit;
  5576. }
  5577. status = NmpStoreRequestId(&Parameters->LeaseRequestId, &requestId);
  5578. if (status != ERROR_SUCCESS) {
  5579. goto error_exit;
  5580. }
  5581. //
  5582. // Get the address.
  5583. //
  5584. status = NmpGetMulticastAddress(
  5585. Network,
  5586. &mcastAddress,
  5587. &serverAddress,
  5588. &requestId,
  5589. Parameters
  5590. );
  5591. if (status != ERROR_SUCCESS) {
  5592. if (status == ERROR_TIMEOUT) {
  5593. //
  5594. // MADCAP server is not responding. Choose an
  5595. // address, but only if there is a local
  5596. // interface on this network. Otherwise, we
  5597. // cannot assume that the MADCAP server is
  5598. // unresponsive because we may have no way to
  5599. // contact it.
  5600. //
  5601. if (!localInterface) {
  5602. status = ERROR_CLUSTER_NETINTERFACE_NOT_FOUND;
  5603. ClRtlLogPrint(LOG_UNUSUAL,
  5604. "[NM] Cannot choose a multicast address "
  5605. "for network %1!ws! because this node "
  5606. "has no local interface.\n",
  5607. networkId
  5608. );
  5609. }
  5610. //
  5611. status = NmpChooseMulticastAddress(
  5612. Network,
  5613. Parameters
  5614. );
  5615. if (status != ERROR_SUCCESS) {
  5616. ClRtlLogPrint(LOG_UNUSUAL,
  5617. "[NM] Failed to choose a default multicast "
  5618. "address for network %1!ws!, status %2!u!.\n",
  5619. networkId, status
  5620. );
  5621. } else {
  5622. NmpReportMulticastAddressChoice(
  5623. Network,
  5624. Parameters->Address,
  5625. NULL
  5626. );
  5627. }
  5628. }
  5629. } else {
  5630. NmpReportMulticastAddressLease(
  5631. Network,
  5632. Parameters,
  5633. NULL
  5634. );
  5635. }
  5636. if (status != ERROR_SUCCESS) {
  5637. ClRtlLogPrint(LOG_UNUSUAL,
  5638. "[NM] Failed to get multicast address for "
  5639. "network %1!ws! during manual configuration, "
  5640. "status %2!u!.\n",
  5641. networkId, status
  5642. );
  5643. NmpReportMulticastAddressFailure(Network, status);
  5644. NmpMulticastSetNoAddressParameters(Network, Parameters);
  5645. }
  5646. }
  5647. //
  5648. // If we are not disabling multicast, we will need
  5649. // a new salt value.
  5650. //
  5651. if (!Disabled) {
  5652. status = NmpGenerateMulticastKeySalt(
  5653. Network,
  5654. &Parameters->Salt,
  5655. &Parameters->SaltLength
  5656. );
  5657. if (status != ERROR_SUCCESS) {
  5658. ClRtlLogPrint(LOG_UNUSUAL,
  5659. "[NM] Failed to generate multicast "
  5660. "key salt for network %1!ws! during "
  5661. "manual configuration, status %2!u!.\n",
  5662. networkId, status
  5663. );
  5664. goto error_exit;
  5665. }
  5666. }
  5667. *NeedUpdate = TRUE;
  5668. //
  5669. // Check if we have an address to release.
  5670. //
  5671. if (release != NULL) {
  5672. NmpAcquireLock();
  5673. NmpInitiateMulticastAddressRelease(Network, release);
  5674. release = NULL;
  5675. NmpReleaseLock();
  5676. }
  5677. error_exit:
  5678. if (lockAcquired) {
  5679. NmpReleaseLock();
  5680. lockAcquired = FALSE;
  5681. }
  5682. if (requestId.ClientUID != NULL) {
  5683. MIDL_user_free(requestId.ClientUID);
  5684. RtlZeroMemory(&requestId, sizeof(requestId));
  5685. }
  5686. if (mcastAddress != NULL && !NMP_GLOBAL_STRING(mcastAddress)) {
  5687. MIDL_user_free(mcastAddress);
  5688. mcastAddress = NULL;
  5689. }
  5690. if (serverAddress != NULL && !NMP_GLOBAL_STRING(serverAddress)) {
  5691. MIDL_user_free(serverAddress);
  5692. serverAddress = NULL;
  5693. }
  5694. if (release != NULL) {
  5695. NmpFreeMulticastAddressRelease(release);
  5696. }
  5697. return(status);
  5698. } // NmpMulticastFormManualConfigParameters
  5699. DWORD
  5700. NmpReconfigureMulticast(
  5701. IN PNM_NETWORK Network
  5702. )
  5703. /*++
  5704. Routine Description:
  5705. Create the multicast configuration for this network
  5706. for the cluster. This includes the following:
  5707. - Check the address lease and renew if necessary.
  5708. - Generate a key.
  5709. - Generate a salt.
  5710. The address lease is checked first. If the lease
  5711. needs to be renewed, schedule a worker thread to
  5712. do it asynchronously.
  5713. Notes:
  5714. Called and returns with NM lock held.
  5715. --*/
  5716. {
  5717. DWORD status;
  5718. LPWSTR networkId = (LPWSTR) OmObjectId(Network);
  5719. HDMKEY networkKey = NULL;
  5720. HDMKEY netParamKey = NULL;
  5721. HDMKEY clusParamKey = NULL;
  5722. BOOLEAN lockAcquired = TRUE;
  5723. NM_NETWORK_MULTICAST_PARAMETERS params = { 0 };
  5724. NM_MCAST_LEASE_STATUS leaseStatus = NmMcastLeaseValid;
  5725. DWORD mcastAddressLength = 0;
  5726. ClRtlLogPrint(LOG_NOISE,
  5727. "[NM] Reconfiguring multicast for network %1!ws!.\n",
  5728. networkId
  5729. );
  5730. NmpReleaseLock();
  5731. lockAcquired = FALSE;
  5732. //
  5733. // Check if multicast is disabled. This has the side-effect,
  5734. // on success, of opening at least the network key, and
  5735. // possibly the network parameters key (if it exists) and
  5736. // the cluster parameters key.
  5737. //
  5738. status = NmpQueryMulticastDisabled(
  5739. Network,
  5740. &clusParamKey,
  5741. &networkKey,
  5742. &netParamKey,
  5743. &params.Disabled
  5744. );
  5745. if (status != ERROR_SUCCESS) {
  5746. ClRtlLogPrint(LOG_UNUSUAL,
  5747. "[NM] Failed to determine whether multicast "
  5748. "is disabled for network %1!ws!, status %2!u!.\n",
  5749. networkId, status
  5750. );
  5751. goto error_exit;
  5752. }
  5753. //
  5754. // Read the address from the database. It may have
  5755. // been configured manually, and we do not want to
  5756. // lose it.
  5757. //
  5758. status = NmpQueryMulticastAddress(
  5759. Network,
  5760. networkKey,
  5761. &netParamKey,
  5762. &params.Address,
  5763. &mcastAddressLength
  5764. );
  5765. if (status != ERROR_SUCCESS) {
  5766. ClRtlLogPrint(LOG_UNUSUAL,
  5767. "[NM] Failed to read multicast address "
  5768. "for network %1!ws! from cluster "
  5769. "database, status %2!u!.\n",
  5770. networkId, status
  5771. );
  5772. }
  5773. //
  5774. // Only proceed with lease renewal if multicast is
  5775. // not disabled.
  5776. //
  5777. if (!params.Disabled) {
  5778. //
  5779. // Check the address lease.
  5780. //
  5781. status = NmpQueryMulticastAddressLease(
  5782. Network,
  5783. networkKey,
  5784. &netParamKey,
  5785. &leaseStatus,
  5786. &params.LeaseObtained,
  5787. &params.LeaseExpires
  5788. );
  5789. if (status != ERROR_SUCCESS) {
  5790. ClRtlLogPrint(LOG_UNUSUAL,
  5791. "[NM] Failed to determine multicast address "
  5792. "lease status for network %1!ws!, status %2!u!.\n",
  5793. networkId, status
  5794. );
  5795. if (params.Address == NULL) {
  5796. // We did not find an address. Assume we
  5797. // should obtain an address automatically.
  5798. params.LeaseObtained = time(NULL);
  5799. params.LeaseExpires = time(NULL);
  5800. leaseStatus = NmMcastLeaseExpired;
  5801. } else {
  5802. // We found an address but not any lease
  5803. // parameters. Assume that the address
  5804. // was manually configured.
  5805. params.ConfigType = NmMcastConfigManual;
  5806. params.LeaseObtained = 0;
  5807. params.LeaseExpires = 0;
  5808. leaseStatus = NmMcastLeaseValid;
  5809. }
  5810. }
  5811. //
  5812. // If we think we have a valid lease, check first
  5813. // how we got it. If the address was selected
  5814. // rather than obtained via MADCAP, go through
  5815. // the MADCAP query process again.
  5816. //
  5817. if (leaseStatus == NmMcastLeaseValid) {
  5818. status = NmpQueryMulticastConfigType(
  5819. Network,
  5820. networkKey,
  5821. &netParamKey,
  5822. &params.ConfigType
  5823. );
  5824. if (status != ERROR_SUCCESS) {
  5825. //
  5826. // Since we already have an address, stick
  5827. // with whatever information we deduced
  5828. // from the lease expiration.
  5829. //
  5830. ClRtlLogPrint(LOG_UNUSUAL,
  5831. "[NM] Failed to determine the type of the "
  5832. "multicast address for network %1!ws!, "
  5833. "status %2!u!. Assuming manual configuration.\n",
  5834. networkId, status
  5835. );
  5836. } else if (params.ConfigType == NmMcastConfigAuto) {
  5837. leaseStatus = NmMcastLeaseNeedsRenewal;
  5838. }
  5839. }
  5840. //
  5841. // If we need to renew the lease, we may block
  5842. // indefinitely due to the madcap API. Schedule
  5843. // the renewal and defer configuration to when
  5844. // it completes.
  5845. //
  5846. if (leaseStatus != NmMcastLeaseValid) {
  5847. NmpAcquireLock();
  5848. NmpScheduleMulticastAddressRenewal(Network);
  5849. NmpReleaseLock();
  5850. status = ERROR_IO_PENDING;
  5851. goto error_exit;
  5852. } else {
  5853. //
  5854. // Ensure that the lease expiration is set correctly
  5855. // (a side effect of calculating the lease renew time).
  5856. // We don't actually set the lease renew timer
  5857. // here. Instead, we wait for the notification
  5858. // that the new parameters have been disseminated
  5859. // to all cluster nodes.
  5860. //
  5861. NmpCalculateLeaseRenewTime(
  5862. Network,
  5863. params.ConfigType,
  5864. &params.LeaseObtained,
  5865. &params.LeaseExpires
  5866. );
  5867. }
  5868. }
  5869. //
  5870. // Generate a new multicast salt.
  5871. //
  5872. status = NmpGenerateMulticastKeySalt(
  5873. Network,
  5874. &params.Salt,
  5875. &params.SaltLength
  5876. );
  5877. if (status != ERROR_SUCCESS) {
  5878. ClRtlLogPrint(LOG_UNUSUAL,
  5879. "[NM] Failed to generate multicast key salt for "
  5880. "network %1!ws!, status %2!u!.\n",
  5881. networkId, status
  5882. );
  5883. goto error_exit;
  5884. }
  5885. //
  5886. // Registry keys are no longer needed.
  5887. //
  5888. if (clusParamKey != NULL) {
  5889. DmCloseKey(clusParamKey);
  5890. clusParamKey = NULL;
  5891. }
  5892. if (netParamKey != NULL) {
  5893. DmCloseKey(netParamKey);
  5894. netParamKey = NULL;
  5895. }
  5896. if (networkKey != NULL) {
  5897. DmCloseKey(networkKey);
  5898. networkKey = NULL;
  5899. }
  5900. //
  5901. // Disseminate the configuration.
  5902. //
  5903. status = NmpMulticastNotifyConfigChange(
  5904. Network,
  5905. networkKey,
  5906. &netParamKey,
  5907. &params,
  5908. NULL,
  5909. 0
  5910. );
  5911. if (status != ERROR_SUCCESS) {
  5912. ClRtlLogPrint(LOG_UNUSUAL,
  5913. "[NM] Failed to disseminate multicast "
  5914. "configuration for network %1!ws!, "
  5915. "status %2!u!.\n",
  5916. networkId, status
  5917. );
  5918. goto error_exit;
  5919. }
  5920. error_exit:
  5921. if (clusParamKey != NULL || netParamKey != NULL || networkKey != NULL) {
  5922. if (lockAcquired) {
  5923. NmpReleaseLock();
  5924. lockAcquired = FALSE;
  5925. }
  5926. if (clusParamKey != NULL) {
  5927. DmCloseKey(clusParamKey);
  5928. clusParamKey = NULL;
  5929. }
  5930. if (netParamKey != NULL) {
  5931. DmCloseKey(netParamKey);
  5932. netParamKey = NULL;
  5933. }
  5934. if (networkKey != NULL) {
  5935. DmCloseKey(networkKey);
  5936. networkKey = NULL;
  5937. }
  5938. }
  5939. NmpMulticastFreeParameters(&params);
  5940. if (!lockAcquired) {
  5941. NmpAcquireLock();
  5942. lockAcquired = TRUE;
  5943. }
  5944. return(status);
  5945. } // NmpReconfigureMulticast
  5946. DWORD
  5947. NmpReconfigureClusterMulticast(
  5948. VOID
  5949. )
  5950. /*++
  5951. Routine Description:
  5952. Configures multicast from scratch for all networks in cluster.
  5953. --*/
  5954. {
  5955. DWORD status = ERROR_SUCCESS;
  5956. PNM_NETWORK * networkList;
  5957. DWORD networkCount;
  5958. PNM_NETWORK network;
  5959. PLIST_ENTRY entry;
  5960. DWORD i = 0;
  5961. ClRtlLogPrint(LOG_NOISE,
  5962. "[NM] Reconfiguring multicast on all cluster networks.\n"
  5963. );
  5964. NmpAcquireLock();
  5965. networkCount = NmpNetworkCount;
  5966. networkList = (PNM_NETWORK *) LocalAlloc(
  5967. LMEM_FIXED,
  5968. networkCount * sizeof(PNM_NETWORK)
  5969. );
  5970. if (networkList == NULL) {
  5971. NmpReleaseLock();
  5972. return(ERROR_NOT_ENOUGH_MEMORY);
  5973. }
  5974. for (entry = NmpNetworkList.Flink;
  5975. entry != &NmpNetworkList;
  5976. entry = entry->Flink
  5977. )
  5978. {
  5979. network = CONTAINING_RECORD(
  5980. entry,
  5981. NM_NETWORK,
  5982. Linkage
  5983. );
  5984. //
  5985. // Place a pointer to the network in the network list,
  5986. // and reference the network so it doesn't disappear.
  5987. //
  5988. networkList[i] = network;
  5989. NmpReferenceNetwork(network);
  5990. i++;
  5991. CL_ASSERT(i <= networkCount);
  5992. }
  5993. NmpReleaseLock();
  5994. for (i = 0; i < networkCount; i++) {
  5995. status = NmpReconfigureMulticast(networkList[i]);
  5996. if (status != ERROR_SUCCESS) {
  5997. if (status == ERROR_IO_PENDING) {
  5998. ClRtlLogPrint(LOG_UNUSUAL,
  5999. "[NM] Deferred multicast reconfiguration "
  6000. "for network %1!ws! to worker thread.\n",
  6001. OmObjectId(networkList[i])
  6002. );
  6003. status = ERROR_SUCCESS;
  6004. } else {
  6005. ClRtlLogPrint(LOG_UNUSUAL,
  6006. "[NM] Failed to reconfigure multicast "
  6007. "for network %1!ws!, status %2!u!.\n",
  6008. OmObjectId(networkList[i]), status
  6009. );
  6010. //
  6011. // Not a de facto fatal error.
  6012. //
  6013. status = ERROR_SUCCESS;
  6014. }
  6015. }
  6016. //
  6017. // Drop the reference that was taken in the
  6018. // enum routine.
  6019. //
  6020. NmpDereferenceNetwork(networkList[i]);
  6021. }
  6022. //
  6023. // Deallocate the network list.
  6024. //
  6025. LocalFree(networkList);
  6026. return(status);
  6027. } // NmpReconfigureClusterMulticast
  6028. VOID
  6029. NmpScheduleMulticastReconfiguration(
  6030. IN PNM_NETWORK Network
  6031. )
  6032. /*++
  6033. Routine Description:
  6034. Schedules a worker thread to reconfigure multicast
  6035. for a network.
  6036. Note that we do not use the network worker thread
  6037. because the madcap API is unfamiliar and therefore
  6038. unpredictable.
  6039. Arguments:
  6040. A pointer to the network to renew.
  6041. Return Value:
  6042. None.
  6043. Notes:
  6044. This routine is called with the NM lock held.
  6045. --*/
  6046. {
  6047. DWORD status = ERROR_SUCCESS;
  6048. //
  6049. // Check if a worker thread is already scheduled to
  6050. // service this network.
  6051. //
  6052. if (!NmpIsNetworkMadcapWorkerRunning(Network)) {
  6053. status = NmpScheduleNetworkMadcapWorker(Network);
  6054. }
  6055. if (status == ERROR_SUCCESS) {
  6056. //
  6057. // We succeeded in scheduling a worker thread. Stop the
  6058. // retry timer and set the registration work flag.
  6059. //
  6060. Network->McastAddressReconfigureRetryTimer = 0;
  6061. Network->Flags |= NM_FLAG_NET_RECONFIGURE_MCAST;
  6062. }
  6063. else {
  6064. //
  6065. // We failed to schedule a worker thread. Set the retry
  6066. // timer to expire on the next tick, so we can try again.
  6067. //
  6068. Network->McastAddressReconfigureRetryTimer = 1;
  6069. }
  6070. return;
  6071. } // NmpScheduleMulticastReconfiguration
  6072. /////////////////////////////////////////////////////////////////////////////
  6073. //
  6074. // Routines exported within NM.
  6075. //
  6076. /////////////////////////////////////////////////////////////////////////////
  6077. VOID
  6078. NmpMulticastInitialize(
  6079. VOID
  6080. )
  6081. /*++
  6082. Routine Description:
  6083. Initialize multicast readiness variables.
  6084. --*/
  6085. {
  6086. //
  6087. // Figure out if this is a mixed NT5/NT5.1 cluster.
  6088. //
  6089. if (CLUSTER_GET_MAJOR_VERSION(CsClusterHighestVersion) == 3) {
  6090. ClRtlLogPrint(LOG_NOISE,
  6091. "[NM] Enabling mixed NT5/NT5.1 operation.\n"
  6092. );
  6093. NmpIsNT5NodeInCluster = TRUE;
  6094. }
  6095. else {
  6096. ClRtlLogPrint(LOG_NOISE,
  6097. "[NM] Disabling mixed NT5/NT5.1 operation.\n"
  6098. );
  6099. NmpIsNT5NodeInCluster = FALSE;
  6100. }
  6101. //
  6102. // Figure out if there are enough nodes in this cluster
  6103. // to run multicast.
  6104. //
  6105. if (NmpNodeCount < NMP_MCAST_MIN_CLUSTER_NODE_COUNT) {
  6106. NmpMulticastIsNotEnoughNodes = TRUE;
  6107. } else {
  6108. NmpMulticastIsNotEnoughNodes = FALSE;
  6109. }
  6110. return;
  6111. } // NmpMulticastInitialize
  6112. BOOLEAN
  6113. NmpIsClusterMulticastReady(
  6114. IN BOOLEAN CheckNodeCount
  6115. )
  6116. /*++
  6117. Routine Description:
  6118. Determines from the cluster version and the NM up node
  6119. set whether multicast should be run in this cluster.
  6120. Criteria: no nodes with version below Whistler
  6121. at least three nodes configured (at this point,
  6122. we're not worried about how many nodes are
  6123. actually running)
  6124. Arguments:
  6125. CheckNodeCount - indicates whether number of nodes
  6126. configured in cluster should be
  6127. considered
  6128. Return value:
  6129. TRUE if multicast should be run.
  6130. Notes:
  6131. Called and returns with NM lock held.
  6132. --*/
  6133. {
  6134. LPWSTR reason = NULL;
  6135. //
  6136. // First check for the lowest version.
  6137. //
  6138. if (NmpIsNT5NodeInCluster) {
  6139. reason = L"there is at least one NT5 node configured "
  6140. L"in the cluster membership";
  6141. }
  6142. //
  6143. // Count the nodes.
  6144. //
  6145. else if (CheckNodeCount && NmpMulticastIsNotEnoughNodes) {
  6146. reason = L"there are not enough nodes configured "
  6147. L"in the cluster membership";
  6148. }
  6149. if (reason != NULL) {
  6150. ClRtlLogPrint(LOG_NOISE,
  6151. "[NM] Multicast is not justified for this "
  6152. "cluster because %1!ws!.\n",
  6153. reason
  6154. );
  6155. }
  6156. return((BOOLEAN)(reason == NULL));
  6157. } // NmpIsClusterMulticastReady
  6158. VOID
  6159. NmpMulticastProcessClusterVersionChange(
  6160. VOID
  6161. )
  6162. /*++
  6163. Routine Description:
  6164. Called when the cluster version changes. Updates
  6165. global variables to track whether this is a mixed-mode
  6166. cluster, and starts or stops multicast if necessary.
  6167. Notes:
  6168. Called and returns with NM lock held.
  6169. --*/
  6170. {
  6171. BOOLEAN checkReady = FALSE;
  6172. BOOLEAN stop = FALSE;
  6173. //
  6174. // Figure out if there is a node in this cluster whose
  6175. // version reveals that it doesn't speak multicast.
  6176. //
  6177. if (CLUSTER_GET_MAJOR_VERSION(CsClusterHighestVersion) < 4) {
  6178. if (NmpIsNT5NodeInCluster == FALSE) {
  6179. ClRtlLogPrint(LOG_NOISE,
  6180. "[NM] Disabling multicast in mixed-mode cluster.\n"
  6181. );
  6182. NmpIsNT5NodeInCluster = TRUE;
  6183. stop = TRUE;
  6184. }
  6185. }
  6186. else {
  6187. if (NmpIsNT5NodeInCluster == TRUE) {
  6188. ClRtlLogPrint(LOG_NOISE,
  6189. "[NM] Enabling multicast after upgrade from "
  6190. "mixed-mode cluster.\n"
  6191. );
  6192. NmpIsNT5NodeInCluster = FALSE;
  6193. checkReady = TRUE;
  6194. }
  6195. }
  6196. if (NmpNodeCount < NMP_MCAST_MIN_CLUSTER_NODE_COUNT) {
  6197. if (NmpMulticastIsNotEnoughNodes == FALSE) {
  6198. ClRtlLogPrint(LOG_NOISE,
  6199. "[NM] There are no longer the minimum number of "
  6200. "nodes configured in the cluster membership to "
  6201. "justify multicast.\n"
  6202. );
  6203. NmpMulticastIsNotEnoughNodes = TRUE;
  6204. stop = TRUE;
  6205. }
  6206. } else {
  6207. if (NmpMulticastIsNotEnoughNodes == TRUE) {
  6208. ClRtlLogPrint(LOG_NOISE,
  6209. "[NM] The cluster is configured with enough "
  6210. "nodes configured to justify multicast.\n"
  6211. );
  6212. NmpMulticastIsNotEnoughNodes = FALSE;
  6213. checkReady = TRUE;
  6214. }
  6215. }
  6216. if (stop) {
  6217. //
  6218. // Stop multicast, since we are no longer
  6219. // multicast-ready.
  6220. //
  6221. NmpStopMulticast(NULL);
  6222. //
  6223. // Don't bother checking whether we are now
  6224. // multicast-ready.
  6225. //
  6226. checkReady = FALSE;
  6227. }
  6228. //
  6229. // Start multicast if this is the NM leader node
  6230. // and we have now become multicast-ready.
  6231. //
  6232. if (checkReady &&
  6233. NmpLeaderNodeId == NmLocalNodeId &&
  6234. NmpIsClusterMulticastReady(TRUE)) {
  6235. NmpStartMulticast(NULL);
  6236. }
  6237. return;
  6238. } // NmpMulticastProcessClusterVersionChange
  6239. VOID
  6240. NmpScheduleMulticastAddressRenewal(
  6241. PNM_NETWORK Network
  6242. )
  6243. /*++
  6244. Routine Description:
  6245. Schedules a worker thread to renew the multicast
  6246. address lease for a network.
  6247. Note that we do not use the network worker thread
  6248. because the madcap API is unfamiliar and therefore
  6249. unpredictable.
  6250. Arguments:
  6251. A pointer to the network to renew.
  6252. Return Value:
  6253. None.
  6254. Notes:
  6255. This routine is called with the NM lock held.
  6256. --*/
  6257. {
  6258. DWORD status = ERROR_SUCCESS;
  6259. //
  6260. // Check if a worker thread is already scheduled to
  6261. // service this network.
  6262. //
  6263. if (!NmpIsNetworkMadcapWorkerRunning(Network)) {
  6264. status = NmpScheduleNetworkMadcapWorker(Network);
  6265. }
  6266. if (status == ERROR_SUCCESS) {
  6267. //
  6268. // We succeeded in scheduling a worker thread. Stop the
  6269. // retry timer and set the registration work flag.
  6270. //
  6271. Network->McastAddressRenewTimer = 0;
  6272. Network->Flags |= NM_FLAG_NET_RENEW_MCAST_ADDRESS;
  6273. }
  6274. else {
  6275. //
  6276. // We failed to schedule a worker thread. Set the retry
  6277. // timer to expire on the next tick, so we can try again.
  6278. //
  6279. Network->McastAddressRenewTimer = 1;
  6280. }
  6281. return;
  6282. } // NmpScheduleMulticastAddressRenewal
  6283. VOID
  6284. NmpScheduleMulticastAddressRelease(
  6285. PNM_NETWORK Network
  6286. )
  6287. /*++
  6288. Routine Description:
  6289. Schedules a worker thread to renew the multicast
  6290. address lease for a network.
  6291. Note that we do not use the network worker thread
  6292. because the madcap API is unfamiliar and therefore
  6293. unpredictable.
  6294. Arguments:
  6295. A pointer to the network to renew.
  6296. Return Value:
  6297. None.
  6298. Notes:
  6299. This routine is called with the NM lock held.
  6300. --*/
  6301. {
  6302. DWORD status = ERROR_SUCCESS;
  6303. //
  6304. // Check if a worker thread is already scheduled to
  6305. // service this network.
  6306. //
  6307. if (!NmpIsNetworkMadcapWorkerRunning(Network)) {
  6308. status = NmpScheduleNetworkMadcapWorker(Network);
  6309. }
  6310. if (status == ERROR_SUCCESS) {
  6311. //
  6312. // We succeeded in scheduling a worker thread. Stop the
  6313. // retry timer and set the registration work flag.
  6314. //
  6315. Network->McastAddressReleaseRetryTimer = 0;
  6316. Network->Flags |= NM_FLAG_NET_RELEASE_MCAST_ADDRESS;
  6317. }
  6318. else {
  6319. //
  6320. // We failed to schedule a worker thread. Set the retry
  6321. // timer to expire on the next tick, so we can try again.
  6322. //
  6323. Network->McastAddressReleaseRetryTimer = 1;
  6324. }
  6325. return;
  6326. } // NmpScheduleMulticastAddressRelease
  6327. VOID
  6328. NmpFreeMulticastAddressReleaseList(
  6329. IN PNM_NETWORK Network
  6330. )
  6331. /*++
  6332. Routine Description:
  6333. Free all release data structures on network list.
  6334. Notes:
  6335. Assume that the Network object will not be accessed
  6336. by any other threads during this call.
  6337. --*/
  6338. {
  6339. PNM_NETWORK_MADCAP_ADDRESS_RELEASE releaseInfo = NULL;
  6340. PLIST_ENTRY entry;
  6341. while (!IsListEmpty(&(Network->McastAddressReleaseList))) {
  6342. //
  6343. // Simply free the memory -- don't try to release the
  6344. // leases.
  6345. //
  6346. entry = RemoveHeadList(&(Network->McastAddressReleaseList));
  6347. releaseInfo = CONTAINING_RECORD(
  6348. entry,
  6349. NM_NETWORK_MADCAP_ADDRESS_RELEASE,
  6350. Linkage
  6351. );
  6352. NmpFreeMulticastAddressRelease(releaseInfo);
  6353. }
  6354. return;
  6355. } // NmpFreeMulticastAddressReleaseList
  6356. DWORD
  6357. NmpMulticastManualConfigChange(
  6358. IN PNM_NETWORK Network,
  6359. IN HDMKEY NetworkKey,
  6360. IN HDMKEY NetworkParametersKey,
  6361. IN PVOID InBuffer,
  6362. IN DWORD InBufferSize,
  6363. OUT BOOLEAN * SetProperties
  6364. )
  6365. /*++
  6366. Routine Description:
  6367. Called by node that receives a clusapi request to set
  6368. multicast parameters for a network. Generates a new
  6369. multicast key salt. Then writes the new salt to the
  6370. cluster database and sets the lease expiration to
  6371. zero.
  6372. This routine is a no-op in mixed-mode clusters.
  6373. Notes:
  6374. Must not be called with NM lock held.
  6375. --*/
  6376. {
  6377. DWORD status;
  6378. LPCWSTR networkId = OmObjectId(Network);
  6379. BOOLEAN disableConfig = FALSE;
  6380. BOOLEAN addrConfig = FALSE;
  6381. DWORD disabled;
  6382. NM_NETWORK_MULTICAST_PARAMETERS params;
  6383. LPWSTR mcastAddress = NULL;
  6384. BOOLEAN needUpdate = FALSE;
  6385. if (!NmpIsClusterMulticastReady(TRUE)) {
  6386. *SetProperties = TRUE;
  6387. return(ERROR_SUCCESS);
  6388. }
  6389. #if CLUSTER_BETA
  6390. ClRtlLogPrint(LOG_NOISE,
  6391. "[NM] Examining update to private properties "
  6392. "for network %1!ws!.\n",
  6393. networkId
  6394. );
  6395. #endif // CLUSTER_BETA
  6396. RtlZeroMemory(&params, sizeof(params));
  6397. //
  6398. // Cannot proceed if either registry key is NULL.
  6399. //
  6400. if (NetworkKey == NULL || NetworkParametersKey == NULL) {
  6401. ClRtlLogPrint(LOG_UNUSUAL,
  6402. "[NM] Ignoring possible multicast changes in "
  6403. "private properties update to network %1!ws! "
  6404. "because registry keys are missing.\n",
  6405. networkId
  6406. );
  6407. status = ERROR_INVALID_PARAMETER;
  6408. goto error_exit;
  6409. }
  6410. //
  6411. // If a writeable multicast parameter is among those properties
  6412. // being set, we may need to take action before the update is
  6413. // disseminated.
  6414. //
  6415. // Check whether multicast is being disabled for this network.
  6416. //
  6417. status = ClRtlFindDwordProperty(
  6418. InBuffer,
  6419. InBufferSize,
  6420. CLUSREG_NAME_NET_DISABLE_MULTICAST,
  6421. &disabled
  6422. );
  6423. if (status == ERROR_SUCCESS) {
  6424. disableConfig = TRUE;
  6425. } else {
  6426. disabled = NMP_MCAST_DISABLED_DEFAULT;
  6427. }
  6428. //
  6429. // Check whether a multicast address is being set for this
  6430. // network.
  6431. //
  6432. status = ClRtlFindSzProperty(
  6433. InBuffer,
  6434. InBufferSize,
  6435. CLUSREG_NAME_NET_MULTICAST_ADDRESS,
  6436. &mcastAddress
  6437. );
  6438. if (status == ERROR_SUCCESS) {
  6439. addrConfig = TRUE;
  6440. }
  6441. if (disableConfig || addrConfig) {
  6442. //
  6443. // Multicast parameters are being written.
  6444. //
  6445. ClRtlLogPrint(LOG_NOISE,
  6446. "[NM] Processing manual update to multicast "
  6447. "configuration for network %1!ws!.\n",
  6448. networkId
  6449. );
  6450. status = NmpMulticastFormManualConfigParameters(
  6451. Network,
  6452. NetworkKey,
  6453. NetworkParametersKey,
  6454. disableConfig,
  6455. disabled,
  6456. addrConfig,
  6457. mcastAddress,
  6458. &needUpdate,
  6459. &params
  6460. );
  6461. if (status != ERROR_SUCCESS) {
  6462. ClRtlLogPrint(LOG_UNUSUAL,
  6463. "[NM] Failed to determine multicast "
  6464. "configuration parameters for network "
  6465. "%1!ws! during manual configuration, "
  6466. "status %2!u!.\n",
  6467. networkId, status
  6468. );
  6469. goto error_exit;
  6470. }
  6471. //
  6472. // Notify other nodes of the config change.
  6473. //
  6474. if (needUpdate) {
  6475. status = NmpMulticastNotifyConfigChange(
  6476. Network,
  6477. NetworkKey,
  6478. &NetworkParametersKey,
  6479. &params,
  6480. InBuffer,
  6481. InBufferSize
  6482. );
  6483. if (status != ERROR_SUCCESS) {
  6484. ClRtlLogPrint(LOG_UNUSUAL,
  6485. "[NM] Failed to disseminate multicast "
  6486. "configuration for network %1!ws! during "
  6487. "manual configuration, status %2!u!.\n",
  6488. networkId, status
  6489. );
  6490. goto error_exit;
  6491. }
  6492. //
  6493. // The properties have been disseminated. There is
  6494. // no need to set them again (in fact, if we changed
  6495. // one of the multicast properties, it could be
  6496. // overwritten).
  6497. //
  6498. *SetProperties = FALSE;
  6499. }
  6500. }
  6501. if (!needUpdate) {
  6502. //
  6503. // No multicast properties are affected. Set them
  6504. // in the cluster database normally.
  6505. //
  6506. *SetProperties = TRUE;
  6507. status = ERROR_SUCCESS;
  6508. }
  6509. error_exit:
  6510. if (mcastAddress != NULL) {
  6511. LocalFree(mcastAddress);
  6512. mcastAddress = NULL;
  6513. }
  6514. NmpMulticastFreeParameters(&params);
  6515. //
  6516. // If multicast config failed, default to setting properties.
  6517. //
  6518. if (status != ERROR_SUCCESS) {
  6519. *SetProperties = TRUE;
  6520. }
  6521. return(status);
  6522. } // NmpMulticastManualConfigChange
  6523. DWORD
  6524. NmpUpdateSetNetworkMulticastConfiguration(
  6525. IN BOOL SourceNode,
  6526. IN LPWSTR NetworkId,
  6527. IN PVOID UpdateBuffer,
  6528. IN PVOID PropBuffer,
  6529. IN LPDWORD PropBufferSize
  6530. )
  6531. /*++
  6532. Routine Description:
  6533. Global update routine for multicast configuration.
  6534. Starts a local transaction.
  6535. Commits property buffer to local database.
  6536. Commits multicast configuration to local database,
  6537. possibly overwriting properties from buffer.
  6538. Configures multicast parameters.
  6539. Commits transaction.
  6540. Backs out multicast configuration changes if needed.
  6541. Starts lease renew timer if needed.
  6542. Arguments:
  6543. SourceNode - whether this node is source of update.
  6544. NetworkId - affected network
  6545. Update - new multicast configuration
  6546. PropBuffer - other properties to set in local
  6547. transaction. may be absent.
  6548. PropBufferSize - size of property buffer.
  6549. Return value:
  6550. SUCCESS if properties or configuration could not be
  6551. committed. Error not necessarily returned if
  6552. multicast config failed.
  6553. --*/
  6554. {
  6555. DWORD status;
  6556. PNM_NETWORK network = NULL;
  6557. PNM_NETWORK_MULTICAST_UPDATE update = UpdateBuffer;
  6558. NM_NETWORK_MULTICAST_PARAMETERS params = { 0 };
  6559. NM_NETWORK_MULTICAST_PARAMETERS undoParams = { 0 };
  6560. HLOCALXSACTION xaction = NULL;
  6561. HDMKEY networkKey = NULL;
  6562. HDMKEY netParamKey = NULL;
  6563. DWORD createDisposition;
  6564. BOOLEAN lockAcquired = FALSE;
  6565. DWORD leaseRenewTime;
  6566. NM_MCAST_CONFIG configType;
  6567. if (!NmpEnterApi(NmStateOnline)) {
  6568. ClRtlLogPrint(LOG_NOISE,
  6569. "[NM] Not in valid state to process SetNetworkCommonProperties "
  6570. "update.\n"
  6571. );
  6572. return(ERROR_NODE_NOT_AVAILABLE);
  6573. }
  6574. ClRtlLogPrint(LOG_NOISE,
  6575. "[NM] Received update to multicast configuration "
  6576. "for network %1!ws!.\n",
  6577. NetworkId
  6578. );
  6579. //
  6580. // Find the network's object
  6581. //
  6582. network = OmReferenceObjectById(ObjectTypeNetwork, NetworkId);
  6583. if (network == NULL) {
  6584. ClRtlLogPrint(LOG_CRITICAL,
  6585. "[NM] Unable to find network %1!ws!.\n",
  6586. NetworkId
  6587. );
  6588. status = ERROR_CLUSTER_NETWORK_NOT_FOUND;
  6589. goto error_exit;
  6590. }
  6591. //
  6592. // Convert the update into a parameters data structure.
  6593. //
  6594. status = NmpMulticastCreateParametersFromUpdate(
  6595. network,
  6596. update,
  6597. (BOOLEAN)(update->Disabled == 0),
  6598. &params
  6599. );
  6600. if (status != ERROR_SUCCESS) {
  6601. ClRtlLogPrint(LOG_CRITICAL,
  6602. "[NM] Failed to convert update parameters to "
  6603. "multicast parameters for network %1!ws!, "
  6604. "status %2!u!.\n",
  6605. NetworkId, status
  6606. );
  6607. goto error_exit;
  6608. }
  6609. //
  6610. // Open the network's database key
  6611. //
  6612. networkKey = DmOpenKey(DmNetworksKey, NetworkId, KEY_WRITE);
  6613. if (networkKey == NULL) {
  6614. status = GetLastError();
  6615. ClRtlLogPrint(LOG_CRITICAL,
  6616. "[NM] Failed to open database key for network %1!ws!, "
  6617. "status %2!u!\n",
  6618. NetworkId, status
  6619. );
  6620. goto error_exit;
  6621. }
  6622. //
  6623. // Start a transaction - this must be done before acquiring the NM lock.
  6624. //
  6625. xaction = DmBeginLocalUpdate();
  6626. if (xaction == NULL) {
  6627. status = GetLastError();
  6628. ClRtlLogPrint(LOG_CRITICAL,
  6629. "[NM] Failed to begin a transaction, status %1!u!\n",
  6630. status
  6631. );
  6632. goto error_exit;
  6633. }
  6634. //
  6635. // Open or create the network's parameters key.
  6636. //
  6637. netParamKey = DmLocalCreateKey(
  6638. xaction,
  6639. networkKey,
  6640. CLUSREG_KEYNAME_PARAMETERS,
  6641. 0, // registry options
  6642. MAXIMUM_ALLOWED,
  6643. NULL,
  6644. &createDisposition
  6645. );
  6646. if (netParamKey == NULL) {
  6647. status = GetLastError();
  6648. ClRtlLogPrint(LOG_CRITICAL,
  6649. "[NM] Failed to open/create Parameters database "
  6650. "key for network %1!ws!, status %2!u!.\n",
  6651. NetworkId, status
  6652. );
  6653. goto error_exit;
  6654. }
  6655. NmpAcquireLock();
  6656. lockAcquired = TRUE;
  6657. //
  6658. // If we were given a property buffer, then this update was
  6659. // caused by a manual configuration (setting of private
  6660. // properties). Write those properties first, knowing that
  6661. // they may get overwritten later when we write multicast
  6662. // parameters.
  6663. //
  6664. if (*PropBufferSize > sizeof(DWORD)) {
  6665. status = ClRtlSetPrivatePropertyList(
  6666. xaction,
  6667. netParamKey,
  6668. &NmpMcastClusterRegApis,
  6669. PropBuffer,
  6670. *PropBufferSize
  6671. );
  6672. if (status != ERROR_SUCCESS) {
  6673. ClRtlLogPrint(LOG_CRITICAL,
  6674. "[NM] Failed to set private properties for "
  6675. "network %1!ws! during a multicast configuration "
  6676. "update, status %2!u!.\n",
  6677. NetworkId, status
  6678. );
  6679. goto error_exit;
  6680. }
  6681. }
  6682. //
  6683. // Write the multicast configuration.
  6684. //
  6685. status = NmpWriteMulticastParameters(
  6686. network,
  6687. networkKey,
  6688. netParamKey,
  6689. xaction,
  6690. &params
  6691. );
  6692. if (status != ERROR_SUCCESS) {
  6693. ClRtlLogPrint(LOG_CRITICAL,
  6694. "[NM] Failed to write multicast configuration for "
  6695. "network %1!ws!, status %2!u!.\n",
  6696. NetworkId, status
  6697. );
  6698. goto error_exit;
  6699. }
  6700. //
  6701. // Save the config type.
  6702. //
  6703. configType = params.ConfigType;
  6704. //
  6705. // Process the multicast configuration, including storing new
  6706. // parameters in the network object and plumbing them into
  6707. // clusnet.
  6708. //
  6709. status = NmpProcessMulticastConfiguration(network, &params, &undoParams);
  6710. if (status == ERROR_SUCCESS) {
  6711. //
  6712. // Share renewal responsibility for this lease.
  6713. //
  6714. NmpShareMulticastAddressLease(network, configType);
  6715. } else {
  6716. ClRtlLogPrint(LOG_UNUSUAL,
  6717. "[NM] Failed to process multicast configuration for "
  6718. "network %1!ws!, status %2!u!. Attempting null "
  6719. "multicast configuration.\n",
  6720. NetworkId, status
  6721. );
  6722. NmpMulticastSetNullAddressParameters(network, &params);
  6723. status = NmpProcessMulticastConfiguration(
  6724. network,
  6725. &params,
  6726. &undoParams
  6727. );
  6728. if (status != ERROR_SUCCESS) {
  6729. ClRtlLogPrint(LOG_CRITICAL,
  6730. "[NM] Failed to process multicast configuration for "
  6731. "network %1!ws!, status %2!u!.\n",
  6732. NetworkId, status
  6733. );
  6734. goto error_exit;
  6735. }
  6736. }
  6737. error_exit:
  6738. if (lockAcquired) {
  6739. NmpLockedLeaveApi();
  6740. NmpReleaseLock();
  6741. }
  6742. else {
  6743. NmpLeaveApi();
  6744. }
  6745. //
  6746. // Close the network parameters key, which was obtained with
  6747. // DmLocalCreateKey, before committing/aborting the transaction.
  6748. //
  6749. if (netParamKey != NULL) {
  6750. DmCloseKey(netParamKey);
  6751. netParamKey = NULL;
  6752. }
  6753. if (xaction != NULL) {
  6754. //
  6755. // Complete the transaction - this must be done after releasing
  6756. // the NM lock.
  6757. //
  6758. if (status == ERROR_SUCCESS) {
  6759. DmCommitLocalUpdate(xaction);
  6760. }
  6761. else {
  6762. DmAbortLocalUpdate(xaction);
  6763. }
  6764. }
  6765. NmpMulticastFreeParameters(&params);
  6766. NmpMulticastFreeParameters(&undoParams);
  6767. if (networkKey != NULL) {
  6768. DmCloseKey(networkKey);
  6769. networkKey = NULL;
  6770. }
  6771. if (network != NULL) {
  6772. OmDereferenceObject(network);
  6773. }
  6774. return(status);
  6775. } // NmpUpdateSetNetworkMulticastConfiguration
  6776. DWORD
  6777. NmpRefreshMulticastConfiguration(
  6778. IN PNM_NETWORK Network
  6779. )
  6780. /*++
  6781. Routine Description:
  6782. NmpRefreshMulticastConfiguration enables multicast on
  6783. the specified Network according to parameters in the
  6784. cluster database.
  6785. Notes:
  6786. Must not be called with the NM lock held.
  6787. --*/
  6788. {
  6789. LPWSTR networkId = (LPWSTR) OmObjectId(Network);
  6790. DWORD status;
  6791. HDMKEY networkKey = NULL;
  6792. HDMKEY netParamKey = NULL;
  6793. HDMKEY clusParamKey = NULL;
  6794. NM_NETWORK_MULTICAST_PARAMETERS params = { 0 };
  6795. NM_NETWORK_MULTICAST_PARAMETERS undoParams = { 0 };
  6796. DWORD mcastAddrLength = 0;
  6797. NM_MCAST_LEASE_STATUS leaseStatus;
  6798. NM_MCAST_CONFIG configType;
  6799. DWORD disabled;
  6800. ClRtlLogPrint(LOG_NOISE,
  6801. "[NM] Configuring multicast for network %1!ws!.\n",
  6802. networkId
  6803. );
  6804. //
  6805. // Check if multicast is disabled. This has the side-effect,
  6806. // on success, of opening at least the network key, and
  6807. // possibly the network parameters key (if it exists) and
  6808. // the cluster parameters key.
  6809. //
  6810. status = NmpQueryMulticastDisabled(
  6811. Network,
  6812. &clusParamKey,
  6813. &networkKey,
  6814. &netParamKey,
  6815. &params.Disabled
  6816. );
  6817. if (status != ERROR_SUCCESS) {
  6818. ClRtlLogPrint(LOG_UNUSUAL,
  6819. "[NM] Failed to determine whether multicast "
  6820. "is disabled for network %1!ws!, status %2!u!.\n",
  6821. networkId, status
  6822. );
  6823. goto error_exit;
  6824. }
  6825. if (params.Disabled > 0) {
  6826. ClRtlLogPrint(LOG_NOISE,
  6827. "[NM] Multicast is disabled for network %1!ws!.\n",
  6828. networkId
  6829. );
  6830. }
  6831. //
  6832. // Determine what type of configuration this is.
  6833. //
  6834. status = NmpQueryMulticastConfigType(
  6835. Network,
  6836. networkKey,
  6837. &netParamKey,
  6838. &params.ConfigType
  6839. );
  6840. if (status != ERROR_SUCCESS) {
  6841. ClRtlLogPrint(LOG_UNUSUAL,
  6842. "[NM] Failed to determine configuration type "
  6843. "for network %1!ws!, status %2!u!.\n",
  6844. networkId, status
  6845. );
  6846. goto error_exit;
  6847. }
  6848. //
  6849. // Read the multicast address.
  6850. //
  6851. status = NmpQueryMulticastAddress(
  6852. Network,
  6853. networkKey,
  6854. &netParamKey,
  6855. &params.Address,
  6856. &mcastAddrLength
  6857. );
  6858. if ( (status == ERROR_SUCCESS &&
  6859. !NmpMulticastValidateAddress(params.Address)) ||
  6860. (status != ERROR_SUCCESS)
  6861. ) {
  6862. ClRtlLogPrint(LOG_UNUSUAL,
  6863. "[NM] Failed to get valid multicast address "
  6864. "for network %1!ws! from cluster database, "
  6865. "status %2!u!, address %3!ws!.\n",
  6866. networkId, status,
  6867. ((params.Address != NULL) ? params.Address : L"<NULL>")
  6868. );
  6869. goto error_exit;
  6870. }
  6871. //
  6872. // Only re-generate the key if multicast is not disabled.
  6873. //
  6874. if (!params.Disabled) {
  6875. status = NmpGenerateMulticastKey(
  6876. Network,
  6877. &params.Key,
  6878. &params.KeyLength
  6879. );
  6880. if (status != ERROR_SUCCESS) {
  6881. ClRtlLogPrint(LOG_UNUSUAL,
  6882. "[NM] Failed to generate multicast key for "
  6883. "network %1!ws!, status %2!u!.\n",
  6884. networkId, status
  6885. );
  6886. goto error_exit;
  6887. }
  6888. }
  6889. //
  6890. // Get the multicast salt.
  6891. //
  6892. status = NmpQueryMulticastKeySalt(
  6893. Network,
  6894. networkKey,
  6895. &netParamKey,
  6896. &params.Salt,
  6897. &params.SaltLength
  6898. );
  6899. if (status != ERROR_SUCCESS) {
  6900. ClRtlLogPrint(LOG_UNUSUAL,
  6901. "[NM] Failed to get multicast key salt for "
  6902. "network %1!ws!, status %2!u!.\n",
  6903. networkId, status
  6904. );
  6905. goto error_exit;
  6906. }
  6907. //
  6908. // Get the lease parameters.
  6909. //
  6910. status = NmpQueryMulticastAddressLease(
  6911. Network,
  6912. networkKey,
  6913. &netParamKey,
  6914. &leaseStatus,
  6915. &params.LeaseObtained,
  6916. &params.LeaseExpires
  6917. );
  6918. if (status != ERROR_SUCCESS) {
  6919. ClRtlLogPrint(LOG_UNUSUAL,
  6920. "[NM] Failed to get multicast address lease "
  6921. "expiration for network %1!ws!, status %2!u!.\n",
  6922. networkId, status
  6923. );
  6924. //
  6925. // Not fatal.
  6926. //
  6927. params.LeaseObtained = 0;
  6928. params.LeaseExpires = 0;
  6929. status = ERROR_SUCCESS;
  6930. }
  6931. //
  6932. // Remember parameters we will need later.
  6933. //
  6934. disabled = params.Disabled;
  6935. configType = params.ConfigType;
  6936. //
  6937. // Process the configuration changes.
  6938. //
  6939. NmpAcquireLock();
  6940. status = NmpProcessMulticastConfiguration(
  6941. Network,
  6942. &params,
  6943. &undoParams
  6944. );
  6945. //
  6946. // Check the lease renew parameters if this was not a
  6947. // manual configuration.
  6948. //
  6949. if (!disabled && configType != NmMcastConfigManual) {
  6950. NmpShareMulticastAddressLease(
  6951. Network,
  6952. configType
  6953. );
  6954. }
  6955. NmpReleaseLock();
  6956. if (status != ERROR_SUCCESS) {
  6957. ClRtlLogPrint(LOG_UNUSUAL,
  6958. "[NM] Failed to process multicast configuration "
  6959. "for network %1!ws!, status %2!u!.\n",
  6960. networkId, status
  6961. );
  6962. goto error_exit;
  6963. }
  6964. ClRtlLogPrint(LOG_NOISE,
  6965. "[NM] Multicast configuration for network %1!ws! "
  6966. "was successful.\n",
  6967. networkId
  6968. );
  6969. error_exit:
  6970. if (clusParamKey != NULL) {
  6971. DmCloseKey(clusParamKey);
  6972. clusParamKey = NULL;
  6973. }
  6974. if (netParamKey != NULL) {
  6975. DmCloseKey(netParamKey);
  6976. netParamKey = NULL;
  6977. }
  6978. if (networkKey != NULL) {
  6979. DmCloseKey(networkKey);
  6980. networkKey = NULL;
  6981. }
  6982. NmpMulticastFreeParameters(&params);
  6983. NmpMulticastFreeParameters(&undoParams);
  6984. return(status);
  6985. } // NmpRefreshMulticastConfiguration
  6986. DWORD
  6987. NmpRefreshClusterMulticastConfiguration(
  6988. VOID
  6989. )
  6990. /*++
  6991. Routine Description:
  6992. Configures multicast on all networks in cluster.
  6993. --*/
  6994. {
  6995. DWORD status = ERROR_SUCCESS;
  6996. PNM_NETWORK * networkList;
  6997. DWORD networkCount;
  6998. PNM_NETWORK network;
  6999. PLIST_ENTRY entry;
  7000. DWORD i = 0;
  7001. ClRtlLogPrint(LOG_NOISE,
  7002. "[NM] Configuring multicast on all cluster networks.\n"
  7003. );
  7004. NmpAcquireLock();
  7005. networkCount = NmpNetworkCount;
  7006. networkList = (PNM_NETWORK *) LocalAlloc(
  7007. LMEM_FIXED,
  7008. networkCount * sizeof(PNM_NETWORK)
  7009. );
  7010. if (networkList == NULL) {
  7011. NmpReleaseLock();
  7012. return(ERROR_NOT_ENOUGH_MEMORY);
  7013. }
  7014. for (entry = NmpNetworkList.Flink;
  7015. entry != &NmpNetworkList;
  7016. entry = entry->Flink
  7017. )
  7018. {
  7019. network = CONTAINING_RECORD(
  7020. entry,
  7021. NM_NETWORK,
  7022. Linkage
  7023. );
  7024. //
  7025. // Place a pointer to the network in the network list,
  7026. // and reference the network so it doesn't disappear.
  7027. //
  7028. networkList[i] = network;
  7029. NmpReferenceNetwork(network);
  7030. i++;
  7031. CL_ASSERT(i <= networkCount);
  7032. }
  7033. NmpReleaseLock();
  7034. for (i = 0; i < networkCount; i++) {
  7035. status = NmpRefreshMulticastConfiguration(networkList[i]);
  7036. if (status != ERROR_SUCCESS) {
  7037. ClRtlLogPrint(LOG_UNUSUAL,
  7038. "[NM] Failed to configure multicast "
  7039. "parameters for network, %1!ws!, "
  7040. "status %2!u!.\n",
  7041. OmObjectId(networkList[i]), status
  7042. );
  7043. //
  7044. // Not a de facto fatal error.
  7045. //
  7046. status = ERROR_SUCCESS;
  7047. }
  7048. //
  7049. // Drop the reference that was taken in the
  7050. // enum routine.
  7051. //
  7052. NmpDereferenceNetwork(networkList[i]);
  7053. }
  7054. //
  7055. // Deallocate the network list.
  7056. //
  7057. LocalFree(networkList);
  7058. return(status);
  7059. } // NmpRefreshClusterMulticastConfiguration
  7060. DWORD
  7061. NmpMulticastValidatePrivateProperties(
  7062. IN PNM_NETWORK Network,
  7063. IN HDMKEY NetworkKey,
  7064. IN PVOID InBuffer,
  7065. IN DWORD InBufferSize
  7066. )
  7067. /*++
  7068. Routine Description:
  7069. Called when a manual update to the private properties
  7070. of a network is detected. Only called on the node
  7071. that receives the clusapi clusctl request.
  7072. Verifies that no read-only properties are being set.
  7073. Determines whether the multicast configuration of
  7074. the network will need to be refreshed after the
  7075. update.
  7076. This routine is a no-op in a mixed-mode cluster.
  7077. --*/
  7078. {
  7079. DWORD status;
  7080. LPCWSTR networkId = OmObjectId(Network);
  7081. NM_NETWORK_MULTICAST_INFO mcastInfo;
  7082. //
  7083. // Enforce property-validation regardless of number of
  7084. // nodes in cluster.
  7085. //
  7086. if (!NmpIsClusterMulticastReady(FALSE)) {
  7087. return(ERROR_SUCCESS);
  7088. }
  7089. //
  7090. // Don't allow any read-only properties to be set.
  7091. //
  7092. RtlZeroMemory(&mcastInfo, sizeof(mcastInfo));
  7093. status = ClRtlVerifyPropertyTable(
  7094. NmpNetworkMulticastProperties,
  7095. NULL, // Reserved
  7096. TRUE, // Allow unknowns
  7097. InBuffer,
  7098. InBufferSize,
  7099. (LPBYTE) &mcastInfo
  7100. );
  7101. if ( status != ERROR_SUCCESS ) {
  7102. ClRtlLogPrint(LOG_UNUSUAL,
  7103. "[NM] Error verifying private properties for "
  7104. "network %1!ws!, status %2!u!.\n",
  7105. networkId, status
  7106. );
  7107. goto error_exit;
  7108. }
  7109. error_exit:
  7110. NmpFreeNetworkMulticastInfo(&mcastInfo);
  7111. return(status);
  7112. } // NmpMulticastValidatePrivateProperties
  7113. DWORD
  7114. NmpMulticastRegenerateKey(
  7115. IN PNM_NETWORK Network
  7116. )
  7117. /*++
  7118. Routine Description:
  7119. Regenerates the network multicast key, and reconfigures
  7120. ClusNet with new key if it has changed.
  7121. Arguments:
  7122. Network - network to regenerate key for, or NULL if
  7123. key should be regenerated for all
  7124. Notes:
  7125. Called and returns with NM lock held.
  7126. --*/
  7127. {
  7128. DWORD status = ERROR_SUCCESS;
  7129. PLIST_ENTRY entry;
  7130. PNM_NETWORK network;
  7131. LPWSTR networkId;
  7132. NM_NETWORK_MULTICAST_PARAMETERS params = { 0 };
  7133. NM_NETWORK_MULTICAST_PARAMETERS undoParams = { 0 };
  7134. if (Network == NULL) {
  7135. ClRtlLogPrint(LOG_NOISE,
  7136. "[NM] Regenerating key for all cluster networks.\n"
  7137. );
  7138. for (entry = NmpNetworkList.Flink;
  7139. entry != &NmpNetworkList;
  7140. entry = entry->Flink) {
  7141. network = CONTAINING_RECORD(entry, NM_NETWORK, Linkage);
  7142. NmpMulticastRegenerateKey(network);
  7143. }
  7144. status = ERROR_SUCCESS;
  7145. } else if (NmpIsNetworkMulticastEnabled(Network)) {
  7146. networkId = (LPWSTR) OmObjectId(Network);
  7147. ClRtlLogPrint(LOG_NOISE,
  7148. "[NM] Regenerating key for cluster network %1!ws!.\n",
  7149. networkId
  7150. );
  7151. //
  7152. // Create a parameters structure with the current
  7153. // configuration.
  7154. //
  7155. status = NmpMulticastCreateParameters(
  7156. 0, // disabled
  7157. Network->MulticastAddress,
  7158. Network->MulticastKeySalt,
  7159. Network->MulticastKeySaltLength,
  7160. NULL, // leave key blank
  7161. 0, // leave key length blank
  7162. Network->MulticastLeaseObtained,
  7163. Network->MulticastLeaseExpires,
  7164. &(Network->MulticastLeaseRequestId),
  7165. Network->MulticastLeaseServer,
  7166. NmMcastConfigManual, // doesn't matter
  7167. &params
  7168. );
  7169. if (status != ERROR_SUCCESS) {
  7170. ClRtlLogPrint(LOG_UNUSUAL,
  7171. "[NM] Failed to create multicast configuration "
  7172. "parameter block for network %1!ws!, status %2!u!.\n",
  7173. networkId, status
  7174. );
  7175. goto error_exit;
  7176. }
  7177. //
  7178. // Generate the new key.
  7179. //
  7180. status = NmpGenerateMulticastKey(
  7181. Network,
  7182. &params.Key,
  7183. &params.KeyLength
  7184. );
  7185. if (status != ERROR_SUCCESS) {
  7186. ClRtlLogPrint(LOG_UNUSUAL,
  7187. "[NM] Failed to generate multicast "
  7188. "key for network %1!ws!, status %2!u!.\n",
  7189. networkId, status
  7190. );
  7191. goto error_exit;
  7192. }
  7193. status = NmpProcessMulticastConfiguration(
  7194. Network,
  7195. &params,
  7196. &undoParams
  7197. );
  7198. if (status != ERROR_SUCCESS) {
  7199. ClRtlLogPrint(LOG_UNUSUAL,
  7200. "[NM] Failed to process multicast "
  7201. "configuration for network %1!ws! "
  7202. "after key regeneration, status %2!u!.\n",
  7203. networkId, status
  7204. );
  7205. NmpMulticastSetNullAddressParameters(Network, &params);
  7206. status = NmpProcessMulticastConfiguration(
  7207. Network,
  7208. &params,
  7209. &undoParams
  7210. );
  7211. if (status != ERROR_SUCCESS) {
  7212. ClRtlLogPrint(LOG_UNUSUAL,
  7213. "[NM] Failed to set null multicast "
  7214. "configuration for network %1!ws! "
  7215. "after key regeneration, status %2!u!.\n",
  7216. networkId, status
  7217. );
  7218. goto error_exit;
  7219. }
  7220. }
  7221. }
  7222. error_exit:
  7223. if (status != ERROR_SUCCESS && Network != NULL) {
  7224. ClRtlLogPrint(LOG_NOISE,
  7225. "[NM] Failed to regenerate multicast key for "
  7226. "network %1!ws!, status %2!u!.\n",
  7227. OmObjectId(Network), status
  7228. );
  7229. }
  7230. NmpMulticastFreeParameters(&params);
  7231. NmpMulticastFreeParameters(&undoParams);
  7232. return(status);
  7233. } // NmpMulticastRegenerateKey
  7234. DWORD
  7235. NmpStartMulticast(
  7236. IN PNM_NETWORK Network OPTIONAL
  7237. )
  7238. /*++
  7239. Routine Description:
  7240. Start multicast on a network by configuring multicast
  7241. parameters and sending a GUM update.
  7242. Deferred to the network worker thread.
  7243. Arguments:
  7244. Network - network on which to start multicast. If NULL,
  7245. start multicast on all networks.
  7246. Notes:
  7247. Must be called with NM lock held.
  7248. --*/
  7249. {
  7250. PLIST_ENTRY entry;
  7251. PNM_NETWORK network;
  7252. LPWSTR networkId;
  7253. CL_ASSERT(NmpLeaderNodeId == NmLocalNodeId);
  7254. if (Network == NULL) {
  7255. ClRtlLogPrint(LOG_NOISE,
  7256. "[NM] Starting multicast for all cluster networks.\n"
  7257. );
  7258. for (entry = NmpNetworkList.Flink;
  7259. entry != &NmpNetworkList;
  7260. entry = entry->Flink) {
  7261. network = CONTAINING_RECORD(entry, NM_NETWORK, Linkage);
  7262. NmpStartMulticast(network);
  7263. }
  7264. } else {
  7265. networkId = (LPWSTR) OmObjectId(Network);
  7266. ClRtlLogPrint(LOG_NOISE,
  7267. "[NM] Starting multicast for cluster network %1!ws!.\n",
  7268. networkId
  7269. );
  7270. NmpScheduleMulticastReconfiguration(Network);
  7271. }
  7272. return(ERROR_SUCCESS);
  7273. } // NmpStartMulticast
  7274. DWORD
  7275. NmpStopMulticast(
  7276. IN PNM_NETWORK Network OPTIONAL
  7277. )
  7278. /*++
  7279. Routine Description:
  7280. Stop multicast on the local node by configuring clusnet
  7281. with a NULL address. This routine should be called
  7282. from a GUM update or another barrier.
  7283. Routine Description:
  7284. Network - network on which to stop multicast. If NULL,
  7285. stop multicast on all networks.
  7286. Notes:
  7287. Must be called with NM lock held.
  7288. --*/
  7289. {
  7290. DWORD status = ERROR_SUCCESS;
  7291. PLIST_ENTRY entry;
  7292. PNM_NETWORK network;
  7293. LPWSTR networkId;
  7294. DWORD disabled;
  7295. NM_NETWORK_MULTICAST_PARAMETERS params = { 0 };
  7296. NM_NETWORK_MULTICAST_PARAMETERS undoParams = { 0 };
  7297. if (Network == NULL) {
  7298. ClRtlLogPrint(LOG_NOISE,
  7299. "[NM] Starting multicast for all cluster networks.\n"
  7300. );
  7301. for (entry = NmpNetworkList.Flink;
  7302. entry != &NmpNetworkList;
  7303. entry = entry->Flink) {
  7304. network = CONTAINING_RECORD(entry, NM_NETWORK, Linkage);
  7305. status = NmpStopMulticast(network);
  7306. }
  7307. } else {
  7308. networkId = (LPWSTR) OmObjectId(Network);
  7309. disabled = (NmpIsNetworkMulticastEnabled(Network) ? 0 : 1);
  7310. //
  7311. // Check if telling clusnet to stop multicast would
  7312. // be redundant.
  7313. //
  7314. if (disabled != 0 ||
  7315. Network->MulticastAddress == NULL ||
  7316. !wcscmp(Network->MulticastAddress, NmpNullMulticastAddress)) {
  7317. ClRtlLogPrint(LOG_NOISE,
  7318. "[NM] Not necessary to stop multicast for "
  7319. "cluster network %1!ws! (disabled = %2!u!, "
  7320. "multicast address = %3!ws!).\n",
  7321. networkId, disabled,
  7322. ((Network->MulticastAddress == NULL) ?
  7323. L"<NULL>" : Network->MulticastAddress)
  7324. );
  7325. status = ERROR_SUCCESS;
  7326. } else {
  7327. ClRtlLogPrint(LOG_NOISE,
  7328. "[NM] Stopping multicast for cluster network %1!ws!.\n",
  7329. networkId
  7330. );
  7331. //
  7332. // Create parameters from the current state of the network.
  7333. // However, don't use any lease info, since we are stopping
  7334. // multicast and will not be renewing.
  7335. //
  7336. status = NmpMulticastCreateParameters(
  7337. disabled,
  7338. NULL, // blank address initially
  7339. Network->MulticastKeySalt,
  7340. Network->MulticastKeySaltLength,
  7341. Network->MulticastKey,
  7342. Network->MulticastKeyLength,
  7343. 0, // lease obtained
  7344. 0, // lease expires
  7345. NULL, // lease request id
  7346. NULL, // lease server
  7347. NmMcastConfigManual, // doesn't matter
  7348. &params
  7349. );
  7350. if (status != ERROR_SUCCESS) {
  7351. ClRtlLogPrint(LOG_UNUSUAL,
  7352. "[NM] Failed to create multicast configuration "
  7353. "parameter block for network %1!ws!, status %2!u!, "
  7354. "while stopping multicast.\n",
  7355. networkId, status
  7356. );
  7357. goto error_exit;
  7358. }
  7359. //
  7360. // Nullify the address.
  7361. //
  7362. NmpMulticastSetNullAddressParameters(Network, &params);
  7363. //
  7364. // Send the parameters to clusnet.
  7365. //
  7366. status = NmpProcessMulticastConfiguration(
  7367. Network,
  7368. &params,
  7369. &undoParams
  7370. );
  7371. if (status != ERROR_SUCCESS) {
  7372. ClRtlLogPrint(LOG_UNUSUAL,
  7373. "[NM] Failed to set null multicast "
  7374. "configuration for network %1!ws! "
  7375. "while stopping multicast, status %2!u!.\n",
  7376. networkId, status
  7377. );
  7378. goto error_exit;
  7379. }
  7380. }
  7381. //
  7382. // Cancel the lease renew timer, if set.
  7383. //
  7384. NmpStartNetworkMulticastAddressRenewTimer(Network, 0);
  7385. //
  7386. // Clear multicast configuration work flags. Note
  7387. // that this is best effort -- we do not attempt
  7388. // to prevent race conditions where a multicast
  7389. // configuration operation may already be in
  7390. // progress, since such conditions would not
  7391. // affect the integrity of the cluster.
  7392. //
  7393. Network->Flags &= ~NM_FLAG_NET_RENEW_MCAST_ADDRESS;
  7394. Network->Flags &= ~NM_FLAG_NET_RECONFIGURE_MCAST;
  7395. }
  7396. error_exit:
  7397. if (status != ERROR_SUCCESS && Network != NULL) {
  7398. ClRtlLogPrint(LOG_NOISE,
  7399. "[NM] Failed to stop multicast for "
  7400. "network %1!ws!, status %2!u!.\n",
  7401. OmObjectId(Network), status
  7402. );
  7403. }
  7404. NmpMulticastFreeParameters(&params);
  7405. NmpMulticastFreeParameters(&undoParams);
  7406. return(status);
  7407. } // NmpStopMulticast