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

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