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.

4101 lines
108 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. cnpnet.c
  5. Abstract:
  6. Network management routines for the Cluster Network Protocol.
  7. Author:
  8. Mike Massa (mikemas) July 29, 1996
  9. Revision History:
  10. Who When What
  11. -------- -------- ----------------------------------------------
  12. mikemas 07-29-96 created
  13. Notes:
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. #include "cnpnet.tmh"
  18. #include <tdiinfo.h>
  19. #include <tcpinfo.h>
  20. #include <align.h>
  21. #include <sspi.h>
  22. //
  23. // Global Data
  24. //
  25. LIST_ENTRY CnpNetworkList = {NULL, NULL};
  26. LIST_ENTRY CnpDeletingNetworkList = {NULL, NULL};
  27. #if DBG
  28. CN_LOCK CnpNetworkListLock = {0,0};
  29. #else // DBG
  30. CN_LOCK CnpNetworkListLock = 0;
  31. #endif // DBG
  32. BOOLEAN CnpIsNetworkShutdownPending = FALSE;
  33. PKEVENT CnpNetworkShutdownEvent = NULL;
  34. USHORT CnpReservedClusnetPort = 0;
  35. #ifdef ALLOC_PRAGMA
  36. #pragma alloc_text(INIT, CnpLoadNetworks)
  37. #pragma alloc_text(PAGE, CnpInitializeNetworks)
  38. #endif // ALLOC_PRAGMA
  39. //
  40. // Private utiltity routines
  41. //
  42. #define CnpIpAddrPrintArgs(_ip) \
  43. ((_ip >> 0 ) & 0xff), \
  44. ((_ip >> 8 ) & 0xff), \
  45. ((_ip >> 16) & 0xff), \
  46. ((_ip >> 24) & 0xff)
  47. #define CnpIsInternalMulticastNetwork(_network) \
  48. (((_network)->State == ClusnetNetworkStateOnline) && \
  49. (!CnpIsNetworkRestricted((_network))) && \
  50. (CnpIsNetworkMulticastCapable((_network))))
  51. VOID
  52. CnpMulticastGetReachableNodesLocked(
  53. OUT CX_CLUSTERSCREEN * McastReachableNodes,
  54. OUT ULONG * McastReachableCount
  55. )
  56. {
  57. PLIST_ENTRY entry;
  58. PCNP_NETWORK network = NULL;
  59. CnVerifyCpuLockMask(
  60. CNP_NETWORK_LIST_LOCK, // required
  61. 0, // forbidden
  62. CNP_NETWORK_OBJECT_LOCK_MAX // max
  63. );
  64. if (!IsListEmpty(&CnpNetworkList)) {
  65. entry = CnpNetworkList.Flink;
  66. network = CONTAINING_RECORD(entry, CNP_NETWORK, Linkage);
  67. //
  68. // The old screen and count are only valid if
  69. // this is a valid internal network.
  70. //
  71. if (CnpIsInternalMulticastNetwork(network)) {
  72. *McastReachableNodes = network->McastReachableNodes;
  73. *McastReachableCount = network->McastReachableCount;
  74. } else {
  75. network = NULL;
  76. }
  77. }
  78. if (network == NULL) {
  79. RtlZeroMemory(McastReachableNodes, sizeof(*McastReachableNodes));
  80. *McastReachableCount = 0;
  81. }
  82. return;
  83. } // CnpMulticastGetReachableNodesLocked
  84. BOOLEAN
  85. CnpRemoveNetworkListEntryLocked(
  86. IN PCNP_NETWORK Network,
  87. IN BOOLEAN RaiseEvent,
  88. OUT CX_CLUSTERSCREEN * McastReachableNodes OPTIONAL
  89. )
  90. /*++
  91. Routine Description:
  92. Remove Network from the network list and return the new
  93. multicast reachable mask.
  94. Return value:
  95. TRUE if the reachable set changed
  96. Notes:
  97. Called and returns with network list lock held.
  98. --*/
  99. {
  100. ULONG count;
  101. BOOLEAN setChanged;
  102. CX_CLUSTERSCREEN oldScreen;
  103. CX_CLUSTERSCREEN newScreen;
  104. CnVerifyCpuLockMask(
  105. CNP_NETWORK_LIST_LOCK, // required
  106. 0, // forbidden
  107. CNP_NETWORK_OBJECT_LOCK_MAX // max
  108. );
  109. CnpMulticastGetReachableNodesLocked(&oldScreen, &count);
  110. RemoveEntryList(&(Network->Linkage));
  111. Network->Flags &= ~CNP_NET_FLAG_MCASTSORTED;
  112. CnpMulticastGetReachableNodesLocked(&newScreen, &count);
  113. setChanged = (BOOLEAN)
  114. (oldScreen.UlongScreen != newScreen.UlongScreen);
  115. if (RaiseEvent && setChanged) {
  116. CnTrace(CNP_NET_DETAIL, CnpTraceMulticastReachEventRemove,
  117. "[CNP] Issuing event for new multicast "
  118. "reachable set (%lx) after removing "
  119. "network %u.",
  120. newScreen.UlongScreen,
  121. Network->Id
  122. );
  123. CnIssueEvent(
  124. ClusnetEventMulticastSet,
  125. newScreen.UlongScreen,
  126. 0
  127. );
  128. }
  129. if (McastReachableNodes != NULL) {
  130. *McastReachableNodes = newScreen;
  131. }
  132. CnVerifyCpuLockMask(
  133. CNP_NETWORK_LIST_LOCK, // required
  134. 0, // forbidden
  135. CNP_NETWORK_OBJECT_LOCK_MAX // max
  136. );
  137. return(setChanged);
  138. } // CnpRemoveNetworkListEntryLocked
  139. BOOLEAN
  140. CnpIsBetterMulticastNetwork(
  141. IN PCNP_NETWORK Network1,
  142. IN PCNP_NETWORK Network2
  143. )
  144. /*++
  145. Routine Description:
  146. Compares two networks according to multicast reachability
  147. criteria:
  148. 1. online/registered AND
  149. not restricted (e.g. enabled for intracluster comm) AND
  150. not disconnected AND
  151. multicast-enabled
  152. 2. priority
  153. 3. number of multicast reachable nodes
  154. Return value:
  155. TRUE if Network1 is better than Network2
  156. --*/
  157. {
  158. if (!CnpIsInternalMulticastNetwork(Network1)) {
  159. return(FALSE);
  160. }
  161. if (!CnpIsInternalMulticastNetwork(Network2)) {
  162. return(TRUE);
  163. }
  164. //
  165. // Both networks are equal with respect to basic
  166. // multicast requirements.
  167. //
  168. // Now compare the priority.
  169. //
  170. if (CnpIsEqualPriority(Network1->Priority, Network2->Priority)) {
  171. //
  172. // The priority is the same. Although this is unexpected,
  173. // we now compare the number of nodes reachable by
  174. // multicast.
  175. //
  176. return(Network1->McastReachableCount > Network2->McastReachableCount);
  177. } else {
  178. return(CnpIsHigherPriority(Network1->Priority, Network2->Priority));
  179. }
  180. } // CnpIsBetterMulticastNetwork
  181. BOOLEAN
  182. CnpSortMulticastNetworkLocked(
  183. IN PCNP_NETWORK Network,
  184. IN BOOLEAN RaiseEvent,
  185. OUT CX_CLUSTERSCREEN * NewMcastReachableNodes OPTIONAL
  186. )
  187. /*++
  188. Routine Description:
  189. Positions Network in network list according to multicast
  190. reachability. Network must already be inserted in the
  191. network list.
  192. The network list is always sorted, but it is possible
  193. for one network in the list to be "perturbed". In this
  194. case, that entry must be repositioned correctly. This
  195. routine handles repositioning.
  196. Returns new screen through NewMcastReachableNodes.
  197. Return value:
  198. TRUE if number of reachable nodes changes.
  199. Notes:
  200. Called and returns with network list locked.
  201. --*/
  202. {
  203. ULONG count;
  204. CX_CLUSTERSCREEN oldScreen;
  205. CX_CLUSTERSCREEN newScreen;
  206. BOOLEAN newScreenValid = FALSE;
  207. PLIST_ENTRY entry;
  208. PCNP_NETWORK network = NULL;
  209. KIRQL irql;
  210. BOOLEAN move = FALSE;
  211. BOOLEAN setChanged = FALSE;
  212. CnVerifyCpuLockMask(
  213. CNP_NETWORK_LIST_LOCK, // required
  214. 0, // forbidden
  215. CNP_NETWORK_OBJECT_LOCK_MAX // max
  216. );
  217. //
  218. // If the network has already been removed from the
  219. // sorted list, there is no sense in resorting it.
  220. //
  221. if (CnpIsNetworkMulticastSorted(Network)) {
  222. //
  223. // Remember the current screen and count to detect
  224. // changes.
  225. //
  226. CnpMulticastGetReachableNodesLocked(&oldScreen, &count);
  227. //
  228. // Check if it needs to be moved up.
  229. //
  230. for (entry = Network->Linkage.Blink;
  231. entry != &CnpNetworkList;
  232. entry = entry->Blink) {
  233. network = CONTAINING_RECORD(entry, CNP_NETWORK, Linkage);
  234. if (CnpIsBetterMulticastNetwork(Network, network)) {
  235. move = TRUE;
  236. } else {
  237. break;
  238. }
  239. }
  240. if (move) {
  241. RemoveEntryList(&(Network->Linkage));
  242. InsertHeadList(entry, &(Network->Linkage));
  243. } else {
  244. //
  245. // Check if it needs to be moved down.
  246. //
  247. for (entry = Network->Linkage.Flink;
  248. entry != &CnpNetworkList;
  249. entry = entry->Flink) {
  250. network = CONTAINING_RECORD(entry, CNP_NETWORK, Linkage);
  251. if (CnpIsBetterMulticastNetwork(network, Network)) {
  252. move = TRUE;
  253. } else {
  254. break;
  255. }
  256. }
  257. if (move) {
  258. RemoveEntryList(&(Network->Linkage));
  259. InsertTailList(entry, &(Network->Linkage));
  260. }
  261. }
  262. //
  263. // Determine if the set of reachable nodes has changed.
  264. //
  265. CnpMulticastGetReachableNodesLocked(&newScreen, &count);
  266. newScreenValid = TRUE;
  267. setChanged = (BOOLEAN)
  268. (oldScreen.UlongScreen != newScreen.UlongScreen);
  269. }
  270. if (RaiseEvent && setChanged) {
  271. if (!newScreenValid) {
  272. CnpMulticastGetReachableNodesLocked(&newScreen, &count);
  273. newScreenValid = TRUE;
  274. }
  275. CnTrace(CNP_NET_DETAIL, CnpTraceMulticastReachEventSort,
  276. "[CNP] Issuing event for new multicast "
  277. "reachable set (%lx) after sorting "
  278. "network %u.",
  279. newScreen.UlongScreen,
  280. Network->Id
  281. );
  282. CnIssueEvent(
  283. ClusnetEventMulticastSet,
  284. newScreen.UlongScreen,
  285. 0
  286. );
  287. }
  288. if (NewMcastReachableNodes != NULL) {
  289. if (!newScreenValid) {
  290. CnpMulticastGetReachableNodesLocked(&newScreen, &count);
  291. newScreenValid = TRUE;
  292. }
  293. *NewMcastReachableNodes = newScreen;
  294. }
  295. CnVerifyCpuLockMask(
  296. CNP_NETWORK_LIST_LOCK, // required
  297. 0, // forbidden
  298. CNP_NETWORK_OBJECT_LOCK_MAX // max
  299. );
  300. return(setChanged);
  301. } // CnpSortMulticastNetworkLocked
  302. BOOLEAN
  303. CnpMulticastChangeNodeReachabilityLocked(
  304. IN PCNP_NETWORK Network,
  305. IN PCNP_NODE Node,
  306. IN BOOLEAN Reachable,
  307. IN BOOLEAN RaiseEvent,
  308. OUT CX_CLUSTERSCREEN * NewMcastReachableNodes OPTIONAL
  309. )
  310. /*++
  311. Routine Description:
  312. Changes the multicast reachability state of Node
  313. on Network.
  314. If the set of reachable nodes changes, returns
  315. the new screen through NewMcastReachableNodes.
  316. Return value:
  317. TRUE if set of reachable nodes changes.
  318. Notes:
  319. Called and returns with node lock held.
  320. Called and returns with network list lock held.
  321. --*/
  322. {
  323. KIRQL irql;
  324. BOOLEAN netSetChanged = FALSE;
  325. BOOLEAN setChanged = FALSE;
  326. CX_CLUSTERSCREEN oldScreen;
  327. CX_CLUSTERSCREEN newScreen;
  328. BOOLEAN newScreenValid = FALSE;
  329. ULONG count;
  330. CnVerifyCpuLockMask(
  331. CNP_NODE_OBJECT_LOCK | CNP_NETWORK_LIST_LOCK, // required
  332. 0, // forbidden
  333. CNP_NETWORK_OBJECT_LOCK_MAX // max
  334. );
  335. if (Reachable) {
  336. if (Node != CnpLocalNode) {
  337. if (!CnpClusterScreenMember(
  338. Network->McastReachableNodes.ClusterScreen,
  339. INT_NODE(Node->Id)
  340. )) {
  341. //
  342. // Remember the current screen and count to detect
  343. // changes.
  344. //
  345. CnpMulticastGetReachableNodesLocked(&oldScreen, &count);
  346. CnpClusterScreenInsert(
  347. Network->McastReachableNodes.ClusterScreen,
  348. INT_NODE(Node->Id)
  349. );
  350. Network->McastReachableCount++;
  351. netSetChanged = TRUE;
  352. }
  353. }
  354. } else {
  355. if (Node == CnpLocalNode) {
  356. //
  357. // Remember the current screen and count to detect
  358. // changes.
  359. //
  360. CnpMulticastGetReachableNodesLocked(&oldScreen, &count);
  361. //
  362. // The local interface on this network
  363. // no longer speaks multicast. Declare all
  364. // other nodes unreachable.
  365. //
  366. CnpNetworkResetMcastReachableNodes(Network);
  367. if (Network->McastReachableCount != 0) {
  368. netSetChanged = TRUE;
  369. }
  370. Network->McastReachableCount = 0;
  371. } else {
  372. if (CnpClusterScreenMember(
  373. Network->McastReachableNodes.ClusterScreen,
  374. INT_NODE(Node->Id)
  375. )) {
  376. //
  377. // Remember the current screen and count to detect
  378. // changes.
  379. //
  380. CnpMulticastGetReachableNodesLocked(&oldScreen, &count);
  381. CnpClusterScreenDelete(
  382. Network->McastReachableNodes.ClusterScreen,
  383. INT_NODE(Node->Id)
  384. );
  385. Network->McastReachableCount--;
  386. netSetChanged = TRUE;
  387. }
  388. }
  389. }
  390. if (netSetChanged) {
  391. CnpSortMulticastNetworkLocked(Network, FALSE, &newScreen);
  392. newScreenValid = TRUE;
  393. setChanged = (BOOLEAN)(oldScreen.UlongScreen != newScreen.UlongScreen);
  394. }
  395. if (RaiseEvent && setChanged) {
  396. if (!newScreenValid) {
  397. CnpMulticastGetReachableNodesLocked(&newScreen, &count);
  398. newScreenValid = TRUE;
  399. }
  400. CnTrace(CNP_NET_DETAIL, CnpTraceMulticastReachEventReach,
  401. "[CNP] Issuing event for new multicast "
  402. "reachable set (%lx) after setting "
  403. "reachability for network %u to %!bool!.",
  404. newScreen.UlongScreen,
  405. Network->Id, Reachable
  406. );
  407. CnIssueEvent(
  408. ClusnetEventMulticastSet,
  409. newScreen.UlongScreen,
  410. 0
  411. );
  412. }
  413. if (NewMcastReachableNodes != NULL) {
  414. if (!newScreenValid) {
  415. CnpMulticastGetReachableNodesLocked(&newScreen, &count);
  416. newScreenValid = TRUE;
  417. }
  418. *NewMcastReachableNodes = newScreen;
  419. }
  420. CnVerifyCpuLockMask(
  421. CNP_NODE_OBJECT_LOCK | CNP_NETWORK_LIST_LOCK, // required
  422. 0, // forbidden
  423. CNP_NETWORK_OBJECT_LOCK_MAX // max
  424. );
  425. return(setChanged);
  426. } // CnpMulticastChangeNodeReachabilityLocked
  427. PCNP_NETWORK
  428. CnpLockedFindNetwork(
  429. IN CL_NETWORK_ID NetworkId,
  430. IN CN_IRQL ListIrql
  431. )
  432. /*++
  433. Routine Description:
  434. Searches the network list for a specified network object.
  435. Arguments:
  436. NetworkId - The ID of the network object to locate.
  437. ListIrql - The IRQL level at which the network list lock was
  438. acquired before calling this routine.
  439. Return Value:
  440. A pointer to the requested network object, if it exists.
  441. NULL otherwise.
  442. Notes:
  443. Called with CnpNetworkListLock held.
  444. Returns with CnpNetworkListLock released.
  445. If return value is non-NULL, returns with network object lock held.
  446. --*/
  447. {
  448. PLIST_ENTRY entry;
  449. CN_IRQL networkIrql;
  450. PCNP_NETWORK network = NULL;
  451. CnVerifyCpuLockMask(
  452. CNP_NETWORK_LIST_LOCK, // Required
  453. 0, // Forbidden
  454. CNP_NETWORK_LIST_LOCK_MAX // Maximum
  455. );
  456. for (entry = CnpNetworkList.Flink;
  457. entry != &CnpNetworkList;
  458. entry = entry->Flink
  459. )
  460. {
  461. network = CONTAINING_RECORD(entry, CNP_NETWORK, Linkage);
  462. CnAcquireLock(&(network->Lock), &networkIrql);
  463. if (NetworkId == network->Id) {
  464. CnReleaseLock(&CnpNetworkListLock, networkIrql);
  465. network->Irql = ListIrql;
  466. CnVerifyCpuLockMask(
  467. CNP_NETWORK_OBJECT_LOCK, // Required
  468. CNP_NETWORK_LIST_LOCK, // Forbidden
  469. CNP_NETWORK_OBJECT_LOCK_MAX // Maximum
  470. );
  471. return(network);
  472. }
  473. CnReleaseLock(&(network->Lock), networkIrql);
  474. }
  475. CnReleaseLock(&CnpNetworkListLock, ListIrql);
  476. CnVerifyCpuLockMask(
  477. 0, // Required
  478. (CNP_NETWORK_LIST_LOCK | CNP_NETWORK_OBJECT_LOCK), // Forbidden
  479. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  480. );
  481. return(NULL);
  482. } // CnpLockedFindNetwork
  483. VOID
  484. CnpOfflineNetwork(
  485. PCNP_NETWORK Network
  486. )
  487. /*++
  488. Notes:
  489. Called with network object lock held.
  490. Returns with network object lock released.
  491. May not be called while holding any higher-ranked locks.
  492. --*/
  493. {
  494. NTSTATUS status;
  495. PFILE_OBJECT fileObject = NULL;
  496. PDEVICE_OBJECT deviceObject = NULL;
  497. CnVerifyCpuLockMask(
  498. CNP_NETWORK_OBJECT_LOCK, // Required
  499. (ULONG) ~(CNP_NETWORK_OBJECT_LOCK), // Forbidden
  500. CNP_NETWORK_OBJECT_LOCK_MAX // Maximum
  501. );
  502. CnAssert(Network->State >= ClusnetNetworkStateOnlinePending);
  503. IF_CNDBG(CN_DEBUG_CONFIG) {
  504. CNPRINT((
  505. "[CNP] Offline of network %u pending....\n",
  506. Network->Id
  507. ));
  508. }
  509. Network->State = ClusnetNetworkStateOfflinePending;
  510. //
  511. // Get the UDP file and device objects associated
  512. // with this network to clear the receive event
  513. // handler. Referencing the file object will keep
  514. // both the file and device objects from going away,
  515. // since the I/O mgr maintains a ref on the device
  516. // object for the file object.
  517. //
  518. fileObject = Network->DatagramFileObject;
  519. if (fileObject != NULL) {
  520. ObReferenceObject(fileObject);
  521. }
  522. deviceObject = Network->DatagramDeviceObject;
  523. CnReleaseLock(&(Network->Lock), Network->Irql);
  524. CnTrace(
  525. CNP_NET_DETAIL, CnpTraceNetworkOfflinePending,
  526. "[CNP] Offline of network %u pending.",
  527. Network->Id
  528. );
  529. //
  530. // If the network is still on the sorted network list,
  531. // re-sort.
  532. //
  533. CnpSortMulticastNetwork(Network, TRUE, NULL);
  534. //
  535. // Take all of the interfaces on this network offline.
  536. //
  537. // Note that the network cannot go away while we do this
  538. // because we still hold an active reference on it.
  539. //
  540. IF_CNDBG(CN_DEBUG_CONFIG) {
  541. CNPRINT((
  542. "[CNP] Taking all interfaces on network %u offline...\n",
  543. Network->Id
  544. ));
  545. }
  546. CnpWalkInterfacesOnNetwork(Network, CnpOfflineInterfaceWrapper);
  547. //
  548. // Stop the incoming data flow by clearing the receive
  549. // datagram TDI event handler.
  550. //
  551. if (fileObject != NULL && deviceObject != NULL) {
  552. status = CnpTdiSetEventHandler(
  553. fileObject,
  554. deviceObject,
  555. TDI_EVENT_RECEIVE_DATAGRAM,
  556. NULL, // handler
  557. NULL, // context
  558. NULL // IRP for re-use
  559. );
  560. if (!NT_SUCCESS(status)) {
  561. CnTrace(CNP_NET_DETAIL, CnpTraceNetworkClearRecv,
  562. "[CNP] Failed to clear receive datagram handler "
  563. "for network ID %u, status %!status!",
  564. Network->Id, // LOGULONG
  565. status // LOGSTATUS
  566. );
  567. // Non-fatal error. All will be cleaned up when we
  568. // close the file object.
  569. }
  570. }
  571. //
  572. // Drop the reference we took on the file object.
  573. //
  574. if (fileObject != NULL) {
  575. ObDereferenceObject(fileObject);
  576. }
  577. CnAcquireLock(&(Network->Lock), &(Network->Irql));
  578. //
  579. // Remove the initial active reference. When the active
  580. // reference count goes to zero, the network will be taken
  581. // offline and the irp completed.
  582. //
  583. // The network object lock will be released by
  584. // the dereference.
  585. //
  586. CnpActiveDereferenceNetwork(Network);
  587. CnVerifyCpuLockMask(
  588. 0, // Required
  589. 0xFFFFFFFF, // Forbidden
  590. 0 // Maximum
  591. );
  592. return;
  593. } // CnpOfflineNetwork
  594. VOID
  595. CnpOfflineNetworkWorkRoutine(
  596. IN PVOID Parameter
  597. )
  598. /*++
  599. Routine Description:
  600. Performs the actual work involved in taking a network offline.
  601. This routine runs in the context of an ExWorkerThread.
  602. Arguments:
  603. Parameter - A pointer to the network object on which to operate.
  604. Return Value:
  605. None.
  606. --*/
  607. {
  608. NTSTATUS status;
  609. HANDLE handle = NULL;
  610. PFILE_OBJECT fileObject = NULL;
  611. PIRP offlineIrp;
  612. PCNP_NETWORK network = Parameter;
  613. CnAssert(KeGetCurrentIrql() == PASSIVE_LEVEL);
  614. CnAssert(network->State == ClusnetNetworkStateOfflinePending);
  615. CnAssert(CnSystemProcess == (PKPROCESS) IoGetCurrentProcess());
  616. CnAcquireLock(&(network->Lock), &(network->Irql));
  617. handle = network->DatagramHandle;
  618. network->DatagramHandle = NULL;
  619. fileObject = network->DatagramFileObject;
  620. network->DatagramFileObject = NULL;
  621. network->DatagramDeviceObject = NULL;
  622. IF_CNDBG(CN_DEBUG_CONFIG) {
  623. CNPRINT(("[CNP] Taking network %u offline...\n", network->Id));
  624. }
  625. CnReleaseLock(&(network->Lock), network->Irql);
  626. CnTrace(CNP_NET_DETAIL, CnpTraceNetworkTakingOffline,
  627. "[CNP] Taking network %u offline, dgram handle %p, "
  628. "dgram fileobj %p.",
  629. network->Id, // LOGULONG
  630. handle, // LOGHANDLE
  631. fileObject // LOGPTR
  632. );
  633. if (fileObject != NULL) {
  634. ObDereferenceObject(fileObject);
  635. }
  636. if (handle != NULL) {
  637. status = ZwClose(handle);
  638. IF_CNDBG(CN_DEBUG_CONFIG) {
  639. if (!NT_SUCCESS(status)) {
  640. CNPRINT(("[CNP] Failed to close handle for network %u, "
  641. "status %lx.\n",
  642. network->Id, status));
  643. }
  644. }
  645. CnAssert(NT_SUCCESS(status));
  646. CnTrace(CNP_NET_DETAIL, CnpTraceNetworkClosed,
  647. "[CNP] Closed handle %p for network ID %u, status %!status!",
  648. handle, // LOGHANDLE
  649. network->Id, // LOGULONG
  650. status // LOGSTATUS
  651. );
  652. }
  653. CnAcquireLock(&(network->Lock), &(network->Irql));
  654. CnAssert(network->State == ClusnetNetworkStateOfflinePending);
  655. network->State = ClusnetNetworkStateOffline;
  656. offlineIrp = network->PendingOfflineIrp;
  657. network->PendingOfflineIrp = NULL;
  658. IF_CNDBG(CN_DEBUG_CONFIG) {
  659. CNPRINT(("[CNP] Network %u is now offline.\n", network->Id));
  660. }
  661. //
  662. // Remove the active reference from the base refcount.
  663. // This releases the network object lock.
  664. //
  665. CnpDereferenceNetwork(network);
  666. if (offlineIrp != NULL) {
  667. CN_IRQL cancelIrql;
  668. CnAcquireCancelSpinLock(&cancelIrql);
  669. offlineIrp->CancelIrql = cancelIrql;
  670. CnCompletePendingRequest(offlineIrp, STATUS_SUCCESS, 0);
  671. }
  672. CnAssert(KeGetCurrentIrql() == PASSIVE_LEVEL);
  673. return;
  674. } // CnpOfflineNetworkWorkRoutine
  675. VOID
  676. CnpDeleteNetwork(
  677. PCNP_NETWORK Network,
  678. CN_IRQL NetworkListIrql
  679. )
  680. /*++
  681. Notes:
  682. Called with the CnpNetworkListLock and network object lock held.
  683. Returns with both locks released.
  684. --*/
  685. {
  686. NTSTATUS status;
  687. ULONG i;
  688. PCNP_INTERFACE interface;
  689. CL_NETWORK_ID networkId = Network->Id;
  690. CnVerifyCpuLockMask(
  691. (CNP_NETWORK_LIST_LOCK | CNP_NETWORK_OBJECT_LOCK), // Required
  692. 0, // Forbidden
  693. CNP_NETWORK_OBJECT_LOCK_MAX // Maximum
  694. );
  695. IF_CNDBG(CN_DEBUG_CONFIG) {
  696. CNPRINT(("[CNP] Deleting network %u\n", Network->Id));
  697. }
  698. //
  699. // Move the network to the deleting list. Once we do this,
  700. // no new threads can reference the network object.
  701. //
  702. CnpRemoveNetworkListEntryLocked(Network, TRUE, NULL);
  703. InsertTailList(&CnpDeletingNetworkList, &(Network->Linkage));
  704. IF_CNDBG(CN_DEBUG_CONFIG) {
  705. CNPRINT((
  706. "[CNP] Moved network %u to deleting list\n",
  707. Network->Id
  708. ));
  709. }
  710. CnReleaseLockFromDpc(&CnpNetworkListLock);
  711. Network->Irql = NetworkListIrql;
  712. Network->Flags |= CNP_NET_FLAG_DELETING;
  713. if (Network->State >= ClusnetNetworkStateOnlinePending) {
  714. //
  715. // Take the network offline. This will force all of the
  716. // associated interfaces offline as well.
  717. //
  718. // This will release the network object lock.
  719. //
  720. CnpOfflineNetwork(Network);
  721. }
  722. else {
  723. CnReleaseLock(&(Network->Lock), Network->Irql);
  724. }
  725. //
  726. // Delete all the interfaces on this network.
  727. //
  728. IF_CNDBG(CN_DEBUG_CONFIG) {
  729. CNPRINT((
  730. "[CNP] Deleting all interfaces on network %u...\n",
  731. Network->Id
  732. ));
  733. }
  734. CnpWalkInterfacesOnNetwork(Network, CnpDeleteInterface);
  735. //
  736. // Remove the initial reference on the object. The object will be
  737. // destroyed when the reference count goes to zero. The delete irp
  738. // will be completed at that time.
  739. //
  740. CnAcquireLock(&(Network->Lock), &(Network->Irql));
  741. CnpDereferenceNetwork(Network);
  742. CnVerifyCpuLockMask(
  743. 0, // Required
  744. (CNP_NETWORK_OBJECT_LOCK | CNP_NETWORK_OBJECT_LOCK), // Forbidden
  745. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  746. );
  747. return;
  748. } // CnpDeleteNework
  749. VOID
  750. CnpDestroyNetworkWorkRoutine(
  751. IN PVOID Parameter
  752. )
  753. /*++
  754. Routine Description:
  755. Performs the actual work involved in destroying a network.
  756. This routine runs in the context of an ExWorkerThread.
  757. Arguments:
  758. Parameter - A pointer to the network object on which to operate.
  759. Return Value:
  760. None.
  761. --*/
  762. {
  763. PLIST_ENTRY entry;
  764. CN_IRQL listIrql;
  765. BOOLEAN setCleanupEvent = FALSE;
  766. PCNP_NETWORK network = Parameter;
  767. CnAssert(KeGetCurrentIrql() == PASSIVE_LEVEL);
  768. CnAssert(network->State == ClusnetNetworkStateOffline);
  769. CnAssert(CnSystemProcess == (PKPROCESS) IoGetCurrentProcess());
  770. IF_CNDBG(CN_DEBUG_CONFIG) {
  771. CNPRINT(("[CNP] Destroying network %u\n", network->Id));
  772. }
  773. CnAcquireLock(&CnpNetworkListLock, &listIrql);
  774. #if DBG
  775. {
  776. PCNP_NETWORK oldNetwork = NULL;
  777. //
  778. // Verify that the network object is on the deleting list.
  779. //
  780. for (entry = CnpDeletingNetworkList.Flink;
  781. entry != &CnpDeletingNetworkList;
  782. entry = entry->Flink
  783. )
  784. {
  785. oldNetwork = CONTAINING_RECORD(entry, CNP_NETWORK, Linkage);
  786. if (oldNetwork == network) {
  787. break;
  788. }
  789. }
  790. CnAssert(oldNetwork == network);
  791. }
  792. #endif // DBG
  793. RemoveEntryList(&(network->Linkage));
  794. if (CnpIsNetworkShutdownPending) {
  795. if (IsListEmpty(&CnpDeletingNetworkList)) {
  796. setCleanupEvent = TRUE;
  797. }
  798. }
  799. CnReleaseLock(&CnpNetworkListLock, listIrql);
  800. if (network->PendingDeleteIrp != NULL) {
  801. CnAcquireCancelSpinLock(&(network->PendingDeleteIrp->CancelIrql));
  802. CnCompletePendingRequest(
  803. network->PendingDeleteIrp,
  804. STATUS_SUCCESS,
  805. 0
  806. );
  807. //
  808. // The IoCancelSpinLock was released by CnCompletePendingRequest()
  809. //
  810. }
  811. if (network->CurrentMcastGroup != NULL) {
  812. CnpDereferenceMulticastGroup(network->CurrentMcastGroup);
  813. network->CurrentMcastGroup = NULL;
  814. }
  815. if (network->PreviousMcastGroup != NULL) {
  816. CnpDereferenceMulticastGroup(network->PreviousMcastGroup);
  817. network->PreviousMcastGroup = NULL;
  818. }
  819. CnFreePool(network);
  820. if (setCleanupEvent) {
  821. IF_CNDBG(CN_DEBUG_INIT) {
  822. CNPRINT(("[CNP] Setting network cleanup event.\n"));
  823. }
  824. KeSetEvent(CnpNetworkShutdownEvent, 0, FALSE);
  825. }
  826. CnAssert(KeGetCurrentIrql() == PASSIVE_LEVEL);
  827. return;
  828. } // CnpDestroyNetworkWorkRoutine
  829. //
  830. // Routines exported within CNP
  831. //
  832. PCNP_NETWORK
  833. CnpFindNetwork(
  834. IN CL_NETWORK_ID NetworkId
  835. )
  836. /*++
  837. Notes:
  838. --*/
  839. {
  840. CN_IRQL listIrql;
  841. CnAcquireLock(&CnpNetworkListLock, &listIrql);
  842. return(CnpLockedFindNetwork(NetworkId, listIrql));
  843. } // CnpFindNetwork
  844. VOID
  845. CnpReferenceNetwork(
  846. PCNP_NETWORK Network
  847. )
  848. /*++
  849. Notes:
  850. Called with network object lock held.
  851. --*/
  852. {
  853. CnAssert(Network->RefCount != 0xFFFFFFFF);
  854. CnVerifyCpuLockMask(
  855. CNP_NETWORK_OBJECT_LOCK, // Required
  856. 0, // Forbidden
  857. CNP_NETWORK_OBJECT_LOCK_MAX // Maximum
  858. );
  859. Network->RefCount++;
  860. IF_CNDBG(CN_DEBUG_CNPREF) {
  861. CNPRINT((
  862. "[CNP] Referencing network %u, new refcount %u\n",
  863. Network->Id,
  864. Network->RefCount
  865. ));
  866. }
  867. return;
  868. } // CnpReferenceNetwork
  869. VOID
  870. CnpDereferenceNetwork(
  871. PCNP_NETWORK Network
  872. )
  873. /*++
  874. Notes:
  875. Called with network object lock held.
  876. Returns with network object lock released.
  877. Sometimes called with a node object lock held as well.
  878. --*/
  879. {
  880. PLIST_ENTRY entry;
  881. CN_IRQL listIrql;
  882. BOOLEAN setCleanupEvent = FALSE;
  883. ULONG newRefCount;
  884. PCNP_NETWORK network;
  885. CnVerifyCpuLockMask(
  886. CNP_NETWORK_OBJECT_LOCK, // Required
  887. 0, // Forbidden
  888. CNP_NETWORK_OBJECT_LOCK_MAX // Maximum
  889. );
  890. CnAssert(Network->RefCount != 0);
  891. newRefCount = --(Network->RefCount);
  892. IF_CNDBG(CN_DEBUG_CNPREF) {
  893. CNPRINT((
  894. "[CNP] Dereferencing network %u, new refcount %u\n",
  895. Network->Id,
  896. Network->RefCount
  897. ));
  898. }
  899. CnReleaseLock(&(Network->Lock), Network->Irql);
  900. if (newRefCount > 0) {
  901. CnVerifyCpuLockMask(
  902. 0, // Required
  903. CNP_NETWORK_OBJECT_LOCK, // Forbidden
  904. CNP_NETWORK_LIST_LOCK_MAX // Maximum
  905. );
  906. return;
  907. }
  908. CnAssert(Network->ActiveRefCount == 0);
  909. CnAssert(Network->State == ClusnetNetworkStateOffline);
  910. CnAssert(Network->DatagramHandle == NULL);
  911. //
  912. // Schedule an ExWorkerThread to destroy the network.
  913. // We do this because we don't know if a higher-level lock,
  914. // such as a node object lock, is held when this routine is
  915. // called. We may need to acquire the IoCancelSpinLock,
  916. // which must be acquired before a node lock, in
  917. // order to complete a deregister Irp.
  918. //
  919. IF_CNDBG(CN_DEBUG_CONFIG) {
  920. CNPRINT((
  921. "[CNP] Posting destroy work item for network %u.\n",
  922. Network->Id
  923. ));
  924. }
  925. ExInitializeWorkItem(
  926. &(Network->ExWorkItem),
  927. CnpDestroyNetworkWorkRoutine,
  928. Network
  929. );
  930. ExQueueWorkItem(&(Network->ExWorkItem), DelayedWorkQueue);
  931. CnVerifyCpuLockMask(
  932. 0, // Required
  933. CNP_NETWORK_OBJECT_LOCK, // Forbidden
  934. CNP_NETWORK_LIST_LOCK_MAX // Maximum
  935. );
  936. return;
  937. } // CnpDereferenceNetwork
  938. ULONG
  939. CnpActiveReferenceNetwork(
  940. PCNP_NETWORK Network
  941. )
  942. /*++
  943. Return value:
  944. New ref count.
  945. Notes:
  946. Called with network object lock held.
  947. Will not allow reference if current refcount is zero.
  948. --*/
  949. {
  950. CnVerifyCpuLockMask(
  951. CNP_NETWORK_OBJECT_LOCK, // Required
  952. 0, // Forbidden
  953. CNP_NETWORK_OBJECT_LOCK_MAX // Maximum
  954. );
  955. CnAssert(Network->ActiveRefCount != 0xFFFFFFFF);
  956. CnAssert(Network->RefCount != 0);
  957. if (Network->ActiveRefCount == 0) {
  958. CnTrace(CNP_NET_DETAIL, CnpActiveRefNetFailed,
  959. "[CNP] Cannot take active reference on "
  960. "network %u because the active refcount "
  961. "is already zero.",
  962. Network->Id
  963. );
  964. return(Network->ActiveRefCount);
  965. }
  966. return (++Network->ActiveRefCount);
  967. } // CnpActiveReferenceNetwork
  968. VOID
  969. CnpActiveDereferenceNetwork(
  970. PCNP_NETWORK Network
  971. )
  972. /*++
  973. Notes:
  974. Called with network object lock held.
  975. Returns with network object lock released.
  976. --*/
  977. {
  978. ULONG newRefCount;
  979. CnVerifyCpuLockMask(
  980. CNP_NETWORK_OBJECT_LOCK, // Required
  981. 0, // Forbidden
  982. CNP_NETWORK_OBJECT_LOCK_MAX // Maximum
  983. );
  984. CnAssert(Network->ActiveRefCount != 0);
  985. CnAssert(Network->State != ClusnetNetworkStateOffline);
  986. newRefCount = --(Network->ActiveRefCount);
  987. CnReleaseLock(&(Network->Lock), Network->Irql);
  988. if (newRefCount > 0) {
  989. CnVerifyCpuLockMask(
  990. 0, // Required
  991. CNP_NETWORK_OBJECT_LOCK, // Forbidden
  992. CNP_NETWORK_LIST_LOCK_MAX // Maximum
  993. );
  994. return;
  995. }
  996. //
  997. // The network's active reference count has gone to zero.
  998. //
  999. CnAssert(Network->State == ClusnetNetworkStateOfflinePending);
  1000. //
  1001. // Schedule an ExWorkerThread to take the network offline.
  1002. // We do this because we don't know if a higher-level lock,
  1003. // such as a node object lock, is held when this routine is
  1004. // called. The base transport file handle must be closed at
  1005. // PASSIVE_LEVEL. We may also need to acquire the IoCancelSpinLock
  1006. // in order to complete an Offline Irp.
  1007. //
  1008. IF_CNDBG(CN_DEBUG_CONFIG) {
  1009. CNPRINT((
  1010. "[CNP] Posting offline work item for network %u.\n",
  1011. Network->Id
  1012. ));
  1013. }
  1014. CnTrace(
  1015. CNP_NET_DETAIL, CnpTraceNetworkSchedulingOffline,
  1016. "[CNP] Scheduling offline of network %u.",
  1017. Network->Id
  1018. );
  1019. ExInitializeWorkItem(
  1020. &(Network->ExWorkItem),
  1021. CnpOfflineNetworkWorkRoutine,
  1022. Network
  1023. );
  1024. ExQueueWorkItem(&(Network->ExWorkItem), DelayedWorkQueue);
  1025. CnVerifyCpuLockMask(
  1026. 0, // Required
  1027. CNP_NETWORK_OBJECT_LOCK, // Forbidden
  1028. CNP_NETWORK_LIST_LOCK_MAX // Maximum
  1029. );
  1030. return;
  1031. } // CnpActiveDereferenceNetwork
  1032. NTSTATUS
  1033. CnpAllocateMulticastGroup(
  1034. IN ULONG Brand,
  1035. IN PTRANSPORT_ADDRESS TdiMulticastAddress,
  1036. IN ULONG TdiMulticastAddressLength,
  1037. IN PVOID Key,
  1038. IN ULONG KeyLength,
  1039. OUT PCNP_MULTICAST_GROUP * Group
  1040. )
  1041. /*++
  1042. Routine Description:
  1043. Allocates and initializes a network multicast group
  1044. structure.
  1045. --*/
  1046. {
  1047. PCNP_MULTICAST_GROUP group;
  1048. ULONG groupSize;
  1049. UCHAR keyBuffer[DES_BLOCKLEN];
  1050. PUCHAR key;
  1051. //
  1052. // Allocate the data structure.
  1053. //
  1054. groupSize = sizeof(CNP_MULTICAST_GROUP);
  1055. if (TdiMulticastAddressLength != 0) {
  1056. groupSize = ROUND_UP_COUNT(groupSize,
  1057. TYPE_ALIGNMENT(TRANSPORT_ADDRESS)) +
  1058. TdiMulticastAddressLength;
  1059. }
  1060. if (KeyLength != 0) {
  1061. groupSize = ROUND_UP_COUNT(groupSize, TYPE_ALIGNMENT(PVOID)) +
  1062. KeyLength;
  1063. }
  1064. group = CnAllocatePool(groupSize);
  1065. if (group == NULL) {
  1066. return(STATUS_INSUFFICIENT_RESOURCES);
  1067. }
  1068. //
  1069. // Fill in parameter fields.
  1070. //
  1071. group->McastNetworkBrand = Brand;
  1072. group->McastTdiAddress = (PTRANSPORT_ADDRESS)
  1073. ROUND_UP_POINTER((PUCHAR)group + sizeof(CNP_MULTICAST_GROUP),
  1074. TYPE_ALIGNMENT(TRANSPORT_ADDRESS));
  1075. group->McastTdiAddressLength = TdiMulticastAddressLength;
  1076. RtlCopyMemory(
  1077. group->McastTdiAddress,
  1078. TdiMulticastAddress,
  1079. TdiMulticastAddressLength
  1080. );
  1081. group->Key = (PVOID)
  1082. ROUND_UP_POINTER((PUCHAR)group->McastTdiAddress
  1083. + TdiMulticastAddressLength,
  1084. TYPE_ALIGNMENT(PVOID));
  1085. group->KeyLength = KeyLength;
  1086. RtlCopyMemory(
  1087. group->Key,
  1088. Key,
  1089. KeyLength
  1090. );
  1091. group->SignatureLength = CX_SIGNATURE_LENGTH;
  1092. //
  1093. // Set the initial refcount to 1.
  1094. //
  1095. group->RefCount = 1;
  1096. *Group = group;
  1097. return(STATUS_SUCCESS);
  1098. } // CnpAllocateMulticastGroup
  1099. VOID
  1100. CnpFreeMulticastGroup(
  1101. IN PCNP_MULTICAST_GROUP Group
  1102. )
  1103. {
  1104. if (Group != NULL) {
  1105. CnFreePool(Group);
  1106. }
  1107. return;
  1108. } // CnpFreeMulticastGroup
  1109. NTSTATUS
  1110. CnpConfigureBasicMulticastSettings(
  1111. IN HANDLE Handle,
  1112. IN PFILE_OBJECT FileObject,
  1113. IN PDEVICE_OBJECT DeviceObject,
  1114. IN PTDI_ADDRESS_INFO TdiBindAddressInfo,
  1115. IN ULONG McastTtl,
  1116. IN UCHAR McastLoop,
  1117. IN PIRP Irp
  1118. )
  1119. /*++
  1120. Routine Description:
  1121. Set basic multicast parameters on the address object
  1122. represented by Handle, FileObject, and DeviceObject
  1123. using the interface represented by TdiBindAddressInfo.
  1124. Notes:
  1125. This routine attaches to the system process when using
  1126. handles, so it should not be called pre-attached.
  1127. --*/
  1128. {
  1129. UDPMCastIFReq mcastIfReq;
  1130. ULONG ifBindIp;
  1131. BOOLEAN attached = FALSE;
  1132. NTSTATUS status;
  1133. //
  1134. // Set this interface for outgoing multicast traffic.
  1135. //
  1136. ifBindIp = *((ULONG UNALIGNED *)
  1137. (&(((PTA_IP_ADDRESS)&(TdiBindAddressInfo->Address))
  1138. ->Address[0].Address[0].in_addr)
  1139. )
  1140. );
  1141. mcastIfReq.umi_addr = ifBindIp;
  1142. KeAttachProcess(CnSystemProcess);
  1143. attached = TRUE;
  1144. status = CnpSetTcpInfoEx(
  1145. Handle,
  1146. CL_TL_ENTITY,
  1147. INFO_CLASS_PROTOCOL,
  1148. INFO_TYPE_ADDRESS_OBJECT,
  1149. AO_OPTION_MCASTIF,
  1150. &mcastIfReq,
  1151. sizeof(mcastIfReq)
  1152. );
  1153. IF_CNDBG(CN_DEBUG_NETOBJ) {
  1154. CNPRINT(("[CNP] Set mcast interface for "
  1155. "AO handle %p, IF %d.%d.%d.%d, status %x.\n",
  1156. Handle,
  1157. CnpIpAddrPrintArgs(ifBindIp),
  1158. status
  1159. ));
  1160. }
  1161. if (!NT_SUCCESS(status)) {
  1162. goto error_exit;
  1163. }
  1164. status = CnpSetTcpInfoEx(
  1165. Handle,
  1166. CL_TL_ENTITY,
  1167. INFO_CLASS_PROTOCOL,
  1168. INFO_TYPE_ADDRESS_OBJECT,
  1169. AO_OPTION_MCASTTTL,
  1170. &McastTtl,
  1171. sizeof(McastTtl)
  1172. );
  1173. IF_CNDBG(CN_DEBUG_NETOBJ) {
  1174. CNPRINT(("[CNP] Set mcast TTL to %d on "
  1175. "AO handle %p, IF %d.%d.%d.%d, "
  1176. "status %x.\n",
  1177. McastTtl,
  1178. Handle,
  1179. CnpIpAddrPrintArgs(ifBindIp),
  1180. status
  1181. ));
  1182. }
  1183. if (!NT_SUCCESS(status)) {
  1184. goto error_exit;
  1185. }
  1186. status = CnpSetTcpInfoEx(
  1187. Handle,
  1188. CL_TL_ENTITY,
  1189. INFO_CLASS_PROTOCOL,
  1190. INFO_TYPE_ADDRESS_OBJECT,
  1191. AO_OPTION_MCASTLOOP,
  1192. &McastLoop,
  1193. sizeof(McastLoop)
  1194. );
  1195. IF_CNDBG(CN_DEBUG_NETOBJ) {
  1196. CNPRINT(("[CNP] Set mcast loopback flag to %d on "
  1197. "AO handle %p, IF %d.%d.%d.%d, status %x.\n",
  1198. McastLoop,
  1199. Handle,
  1200. CnpIpAddrPrintArgs(ifBindIp),
  1201. status
  1202. ));
  1203. }
  1204. if (!NT_SUCCESS(status)) {
  1205. goto error_exit;
  1206. }
  1207. error_exit:
  1208. if (attached) {
  1209. KeDetachProcess();
  1210. attached = FALSE;
  1211. }
  1212. return(status);
  1213. } // CnpConfigureBasicMulticastSettings
  1214. NTSTATUS
  1215. CnpAddRemoveMulticastAddress(
  1216. IN HANDLE Handle,
  1217. IN PFILE_OBJECT FileObject,
  1218. IN PDEVICE_OBJECT DeviceObject,
  1219. IN PTDI_ADDRESS_INFO TdiBindAddressInfo,
  1220. IN PTRANSPORT_ADDRESS TdiMcastBindAddress,
  1221. IN ULONG OpId,
  1222. IN PIRP Irp
  1223. )
  1224. /*++
  1225. Routine Description:
  1226. Add or remove the multicast address specified by
  1227. TdiMcastBindAddress from the interface specified
  1228. by TdiBindAddressInfo.
  1229. Arguments:
  1230. OpId - either AO_OPTION_ADD_MCAST or AO_OPTION_DEL_MCAST
  1231. Notes:
  1232. This routine attaches to the system process when using
  1233. handles, so it should not be called pre-attached.
  1234. --*/
  1235. {
  1236. UDPMCastReq mcastAddDelReq;
  1237. ULONG mcastBindIp;
  1238. ULONG ifBindIp;
  1239. BOOLEAN attached = FALSE;
  1240. NTSTATUS status;
  1241. mcastBindIp = *((ULONG UNALIGNED *)
  1242. (&(((PTA_IP_ADDRESS)TdiMcastBindAddress)
  1243. ->Address[0].Address[0].in_addr)
  1244. )
  1245. );
  1246. ifBindIp = *((ULONG UNALIGNED *)
  1247. (&(((PTA_IP_ADDRESS)&(TdiBindAddressInfo->Address))
  1248. ->Address[0].Address[0].in_addr)
  1249. )
  1250. );
  1251. mcastAddDelReq.umr_addr = mcastBindIp;
  1252. mcastAddDelReq.umr_if = ifBindIp;
  1253. KeAttachProcess(CnSystemProcess);
  1254. attached = TRUE;
  1255. status = CnpSetTcpInfoEx(
  1256. Handle,
  1257. CL_TL_ENTITY,
  1258. INFO_CLASS_PROTOCOL,
  1259. INFO_TYPE_ADDRESS_OBJECT,
  1260. OpId,
  1261. &mcastAddDelReq,
  1262. sizeof(mcastAddDelReq)
  1263. );
  1264. IF_CNDBG(CN_DEBUG_NETOBJ) {
  1265. CNPRINT(("[CNP] Adjusted mcast binding on "
  1266. "interface for AO handle %p, "
  1267. "IF %d.%d.%d.%d, mcast addr %d.%d.%d.%d, "
  1268. "OpId %d, status %x.\n",
  1269. Handle,
  1270. CnpIpAddrPrintArgs(ifBindIp),
  1271. CnpIpAddrPrintArgs(mcastBindIp),
  1272. OpId,
  1273. status
  1274. ));
  1275. }
  1276. if (!NT_SUCCESS(status)) {
  1277. goto error_exit;
  1278. }
  1279. error_exit:
  1280. if (attached) {
  1281. KeDetachProcess();
  1282. attached = FALSE;
  1283. }
  1284. return(status);
  1285. } // CnpAddRemoveMulticastAddress
  1286. VOID
  1287. CnpStartInterfaceMcastTransition(
  1288. PCNP_INTERFACE Interface
  1289. )
  1290. /*++
  1291. Routine Description:
  1292. Called during a multicast group transition. Clears
  1293. the multicast received flag and enables discovery.
  1294. Arguments:
  1295. Interface - A pointer to the interface to change.
  1296. Return Value:
  1297. None.
  1298. Notes:
  1299. Conforms to the calling convention for
  1300. PCNP_INTERFACE_UPDATE_ROUTINE.
  1301. Called with associated node and network locks held.
  1302. Returns with network lock released.
  1303. --*/
  1304. {
  1305. if (Interface->Node != CnpLocalNode) {
  1306. CnpInterfaceClearReceivedMulticast(Interface);
  1307. Interface->McastDiscoverCount = CNP_INTERFACE_MCAST_DISCOVERY;
  1308. }
  1309. CnReleaseLock(&(Interface->Network->Lock), Interface->Network->Irql);
  1310. return;
  1311. } // CnpStartInterfaceMcastTransition
  1312. //
  1313. // Cluster Transport Public Routines
  1314. //
  1315. NTSTATUS
  1316. CnpLoadNetworks(
  1317. VOID
  1318. )
  1319. /*++
  1320. Routine Description:
  1321. Called when the Cluster Network driver is loading. Initializes
  1322. static network-related data structures.
  1323. Arguments:
  1324. None.
  1325. Return Value:
  1326. None.
  1327. --*/
  1328. {
  1329. InitializeListHead(&CnpNetworkList);
  1330. InitializeListHead(&CnpDeletingNetworkList);
  1331. CnInitializeLock(&CnpNetworkListLock, CNP_NETWORK_LIST_LOCK);
  1332. return(STATUS_SUCCESS);
  1333. } // CnpLoadNetworks
  1334. NTSTATUS
  1335. CnpInitializeNetworks(
  1336. VOID
  1337. )
  1338. /*++
  1339. Routine Description:
  1340. Called when the Cluster Network driver is being (re)initialized.
  1341. Initializes dynamic network-related data structures.
  1342. Arguments:
  1343. None.
  1344. Return Value:
  1345. None.
  1346. --*/
  1347. {
  1348. PAGED_CODE();
  1349. CnAssert(CnpNetworkShutdownEvent == NULL);
  1350. CnAssert(IsListEmpty(&CnpNetworkList));
  1351. CnAssert(IsListEmpty(&CnpDeletingNetworkList));
  1352. CnpNetworkShutdownEvent = CnAllocatePool(sizeof(KEVENT));
  1353. if (CnpNetworkShutdownEvent == NULL) {
  1354. return(STATUS_INSUFFICIENT_RESOURCES);
  1355. }
  1356. KeInitializeEvent(CnpNetworkShutdownEvent, NotificationEvent, FALSE);
  1357. CnpIsNetworkShutdownPending = FALSE;
  1358. return(STATUS_SUCCESS);
  1359. } // CnpInitializeNetworks
  1360. VOID
  1361. CnpShutdownNetworks(
  1362. VOID
  1363. )
  1364. /*++
  1365. Routine Description:
  1366. Called when a shutdown request is issued to the Cluster Network
  1367. Driver. Deletes all network objects.
  1368. Arguments:
  1369. None.
  1370. Return Value:
  1371. None.
  1372. --*/
  1373. {
  1374. PLIST_ENTRY entry;
  1375. CN_IRQL listIrql;
  1376. CN_IRQL networkIrql;
  1377. PCNP_NETWORK network;
  1378. NTSTATUS status;
  1379. BOOLEAN waitEvent = FALSE;
  1380. if (CnpNetworkShutdownEvent != NULL) {
  1381. IF_CNDBG(CN_DEBUG_INIT) {
  1382. CNPRINT(("[CNP] Cleaning up networks...\n"));
  1383. }
  1384. CnAcquireLock(&CnpNetworkListLock, &listIrql);
  1385. while (!IsListEmpty(&CnpNetworkList)) {
  1386. entry = CnpNetworkList.Flink;
  1387. network = CONTAINING_RECORD(entry, CNP_NETWORK, Linkage);
  1388. CnAcquireLockAtDpc(&(network->Lock));
  1389. network->Irql = DISPATCH_LEVEL;
  1390. CnpDeleteNetwork(network, listIrql);
  1391. //
  1392. // Both locks were released.
  1393. //
  1394. CnAcquireLock(&CnpNetworkListLock, &listIrql);
  1395. }
  1396. if (!IsListEmpty(&CnpDeletingNetworkList)) {
  1397. CnpIsNetworkShutdownPending = TRUE;
  1398. waitEvent = TRUE;
  1399. KeResetEvent(CnpNetworkShutdownEvent);
  1400. }
  1401. CnReleaseLock(&CnpNetworkListLock, listIrql);
  1402. if (waitEvent) {
  1403. IF_CNDBG(CN_DEBUG_INIT) {
  1404. CNPRINT(("[CNP] Network deletes are pending...\n"));
  1405. }
  1406. status = KeWaitForSingleObject(
  1407. CnpNetworkShutdownEvent,
  1408. Executive,
  1409. KernelMode,
  1410. FALSE, // not alertable
  1411. NULL // no timeout
  1412. );
  1413. CnAssert(status == STATUS_SUCCESS);
  1414. }
  1415. CnAssert(IsListEmpty(&CnpNetworkList));
  1416. CnAssert(IsListEmpty(&CnpDeletingNetworkList));
  1417. CnFreePool(CnpNetworkShutdownEvent); CnpNetworkShutdownEvent = NULL;
  1418. IF_CNDBG(CN_DEBUG_INIT) {
  1419. CNPRINT(("[CNP] Networks cleaned up.\n"));
  1420. }
  1421. }
  1422. CnVerifyCpuLockMask(
  1423. 0, // Required
  1424. 0xFFFFFFFF, // Forbidden
  1425. 0 // Maximum
  1426. );
  1427. return;
  1428. }
  1429. NTSTATUS
  1430. CxRegisterNetwork(
  1431. CL_NETWORK_ID NetworkId,
  1432. ULONG Priority,
  1433. BOOLEAN Restricted
  1434. )
  1435. {
  1436. NTSTATUS status = STATUS_SUCCESS;
  1437. PLIST_ENTRY entry;
  1438. CN_IRQL listIrql;
  1439. PCNP_NETWORK network = NULL;
  1440. if (!CnpIsValidNetworkId(NetworkId)) {
  1441. return(STATUS_CLUSTER_INVALID_NETWORK);
  1442. }
  1443. //
  1444. // Allocate and initialize a network object.
  1445. //
  1446. network = CnAllocatePool(sizeof(CNP_NETWORK));
  1447. if (network == NULL) {
  1448. return(STATUS_INSUFFICIENT_RESOURCES);
  1449. }
  1450. RtlZeroMemory(network, sizeof(CNP_NETWORK));
  1451. CN_INIT_SIGNATURE(network, CNP_NETWORK_SIG);
  1452. network->RefCount = 1;
  1453. network->Id = NetworkId;
  1454. network->State = ClusnetNetworkStateOffline;
  1455. network->Priority = Priority;
  1456. if (Restricted) {
  1457. IF_CNDBG(CN_DEBUG_CONFIG) {
  1458. CNPRINT(("[CNP] Registering network %u as restricted\n", NetworkId));
  1459. }
  1460. network->Flags |= CNP_NET_FLAG_RESTRICTED;
  1461. }
  1462. else {
  1463. IF_CNDBG(CN_DEBUG_CONFIG) {
  1464. CNPRINT(("[CNP] Registering network %u as unrestricted\n", NetworkId));
  1465. }
  1466. }
  1467. CnpNetworkResetMcastReachableNodes(network);
  1468. CnInitializeLock(&(network->Lock), CNP_NETWORK_OBJECT_LOCK);
  1469. CnAcquireLock(&CnpNetworkListLock, &listIrql);
  1470. //
  1471. // Check if the specified network already exists.
  1472. //
  1473. for (entry = CnpNetworkList.Flink;
  1474. entry != &CnpNetworkList;
  1475. entry = entry->Flink
  1476. )
  1477. {
  1478. PCNP_NETWORK oldNetwork = CONTAINING_RECORD(
  1479. entry,
  1480. CNP_NETWORK,
  1481. Linkage
  1482. );
  1483. CnAcquireLock(&(oldNetwork->Lock), &(oldNetwork->Irql));
  1484. if (NetworkId == oldNetwork->Id) {
  1485. CnReleaseLock(&(oldNetwork->Lock), oldNetwork->Irql);
  1486. CnReleaseLock(&CnpNetworkListLock, listIrql);
  1487. status = STATUS_CLUSTER_NETWORK_EXISTS;
  1488. IF_CNDBG(CN_DEBUG_CONFIG) {
  1489. CNPRINT(("[CNP] Network %u already exists\n", NetworkId));
  1490. }
  1491. goto error_exit;
  1492. }
  1493. CnReleaseLock(&(oldNetwork->Lock), oldNetwork->Irql);
  1494. }
  1495. InsertTailList(&CnpNetworkList, &(network->Linkage));
  1496. network->Flags |= CNP_NET_FLAG_MCASTSORTED;
  1497. CnReleaseLock(&CnpNetworkListLock, listIrql);
  1498. IF_CNDBG(CN_DEBUG_CONFIG) {
  1499. CNPRINT(("[CNP] Registered network %u\n", NetworkId));
  1500. }
  1501. CnVerifyCpuLockMask(
  1502. 0, // Required
  1503. 0xFFFFFFFF, // Forbidden
  1504. 0 // Maximum
  1505. );
  1506. return(STATUS_SUCCESS);
  1507. error_exit:
  1508. if (network != NULL) {
  1509. CnFreePool(network);
  1510. }
  1511. CnVerifyCpuLockMask(
  1512. 0, // Required
  1513. 0xFFFFFFFF, // Forbidden
  1514. 0 // Maximum
  1515. );
  1516. return(status);
  1517. } // CxRegisterNetwork
  1518. VOID
  1519. CxCancelDeregisterNetwork(
  1520. PDEVICE_OBJECT DeviceObject,
  1521. PIRP Irp
  1522. )
  1523. /*++
  1524. Routine Description:
  1525. Cancellation handler for DeregisterNetwork requests.
  1526. Return Value:
  1527. None.
  1528. Notes:
  1529. Called with cancel spinlock held.
  1530. Returns with cancel spinlock released.
  1531. --*/
  1532. {
  1533. PFILE_OBJECT fileObject;
  1534. CN_IRQL cancelIrql = Irp->CancelIrql;
  1535. PLIST_ENTRY entry;
  1536. PCNP_NETWORK network;
  1537. CnMarkIoCancelLockAcquired();
  1538. IF_CNDBG(CN_DEBUG_CONFIG) {
  1539. CNPRINT((
  1540. "[CNP] Attempting to cancel DeregisterNetwork irp %p\n",
  1541. Irp
  1542. ));
  1543. }
  1544. CnAssert(DeviceObject == CnDeviceObject);
  1545. fileObject = CnBeginCancelRoutine(Irp);
  1546. CnAcquireLockAtDpc(&CnpNetworkListLock);
  1547. CnReleaseCancelSpinLock(DISPATCH_LEVEL);
  1548. //
  1549. // We can only complete the irp if we can find it stashed in a
  1550. // deleting network object. The deleting network object could have
  1551. // been destroyed and the IRP completed before we acquired the
  1552. // CnpNetworkListLock.
  1553. //
  1554. for (entry = CnpDeletingNetworkList.Flink;
  1555. entry != &CnpDeletingNetworkList;
  1556. entry = entry->Flink
  1557. )
  1558. {
  1559. network = CONTAINING_RECORD(entry, CNP_NETWORK, Linkage);
  1560. if (network->PendingDeleteIrp == Irp) {
  1561. IF_CNDBG(CN_DEBUG_CONFIG) {
  1562. CNPRINT((
  1563. "[CNP] Found dereg irp on network %u\n",
  1564. network->Id
  1565. ));
  1566. }
  1567. //
  1568. // Found the Irp. Now take it away and complete it.
  1569. //
  1570. network->PendingDeleteIrp = NULL;
  1571. CnReleaseLock(&CnpNetworkListLock, cancelIrql);
  1572. CnAcquireCancelSpinLock(&(Irp->CancelIrql));
  1573. CnEndCancelRoutine(fileObject);
  1574. CnCompletePendingRequest(Irp, STATUS_CANCELLED, 0);
  1575. //
  1576. // IoCancelSpinLock was released by CnCompletePendingRequest().
  1577. //
  1578. CnVerifyCpuLockMask(
  1579. 0, // Required
  1580. 0xFFFFFFFF, // Forbidden
  1581. 0 // Maximum
  1582. );
  1583. return;
  1584. }
  1585. }
  1586. CnReleaseLock(&CnpNetworkListLock, cancelIrql);
  1587. CnAcquireCancelSpinLock(&cancelIrql);
  1588. CnEndCancelRoutine(fileObject);
  1589. CnReleaseCancelSpinLock(cancelIrql);
  1590. CnVerifyCpuLockMask(
  1591. 0, // Required
  1592. 0xFFFFFFFF, // Forbidden
  1593. 0 // Maximum
  1594. );
  1595. return;
  1596. } // CnpCancelApiDeregisterNetwork
  1597. NTSTATUS
  1598. CxDeregisterNetwork(
  1599. IN CL_NETWORK_ID NetworkId,
  1600. IN PIRP Irp,
  1601. IN PIO_STACK_LOCATION IrpSp
  1602. )
  1603. {
  1604. NTSTATUS status;
  1605. PLIST_ENTRY entry;
  1606. CN_IRQL irql;
  1607. PCNP_NETWORK network = NULL;
  1608. CnAcquireCancelSpinLock(&irql);
  1609. CnAcquireLockAtDpc(&CnpNetworkListLock);
  1610. status = CnMarkRequestPending(Irp, IrpSp, CxCancelDeregisterNetwork);
  1611. CnReleaseCancelSpinLock(DISPATCH_LEVEL);
  1612. if (status != STATUS_CANCELLED) {
  1613. CnAssert(status == STATUS_SUCCESS);
  1614. for (entry = CnpNetworkList.Flink;
  1615. entry != &CnpNetworkList;
  1616. entry = entry->Flink
  1617. )
  1618. {
  1619. network = CONTAINING_RECORD(entry, CNP_NETWORK, Linkage);
  1620. CnAcquireLockAtDpc(&(network->Lock));
  1621. if (NetworkId == network->Id) {
  1622. IF_CNDBG(CN_DEBUG_CONFIG) {
  1623. CNPRINT((
  1624. "[CNP] Deregistering network %u.\n",
  1625. NetworkId
  1626. ));
  1627. }
  1628. //
  1629. // Save a pointer to pending irp. Note this is protected
  1630. // by the list lock, not the object lock.
  1631. //
  1632. network->PendingDeleteIrp = Irp;
  1633. CnpDeleteNetwork(network, irql);
  1634. //
  1635. // Both locks were released.
  1636. // Irp will be completed when the network is destroyed
  1637. // or the irp is cancelled.
  1638. //
  1639. CnVerifyCpuLockMask(
  1640. 0, // Required
  1641. 0xFFFFFFFF, // Forbidden
  1642. 0 // Maximum
  1643. );
  1644. return(STATUS_PENDING);
  1645. }
  1646. CnReleaseLockFromDpc(&(network->Lock));
  1647. }
  1648. CnReleaseLock(&CnpNetworkListLock, irql);
  1649. CnAcquireCancelSpinLock(&(Irp->CancelIrql));
  1650. CnCompletePendingRequest(Irp, STATUS_CLUSTER_NETWORK_NOT_FOUND, 0);
  1651. CnVerifyCpuLockMask(
  1652. 0, // Required
  1653. 0xFFFFFFFF, // Forbidden
  1654. 0 // Maximum
  1655. );
  1656. return(STATUS_PENDING);
  1657. }
  1658. CnAssert(status == STATUS_CANCELLED);
  1659. CnReleaseLock(&CnpNetworkListLock, irql);
  1660. CnVerifyCpuLockMask(
  1661. 0, // Required
  1662. 0xFFFFFFFF, // Forbidden
  1663. 0 // Maximum
  1664. );
  1665. return(status);
  1666. } // CxDeregisterNetwork
  1667. NTSTATUS
  1668. CxOnlineNetwork(
  1669. IN CL_NETWORK_ID NetworkId,
  1670. IN PWCHAR TdiProviderName,
  1671. IN ULONG TdiProviderNameLength,
  1672. IN PTRANSPORT_ADDRESS TdiBindAddress,
  1673. IN ULONG TdiBindAddressLength,
  1674. IN PWCHAR AdapterName,
  1675. IN ULONG AdapterNameLength,
  1676. OUT PTDI_ADDRESS_INFO TdiBindAddressInfo,
  1677. IN ULONG TdiBindAddressInfoLength,
  1678. IN PIRP Irp OPTIONAL
  1679. )
  1680. /*++
  1681. Notes:
  1682. Each associated interface will be brought online when a heartbeat
  1683. is established for the target of the interface.
  1684. --*/
  1685. {
  1686. NTSTATUS status;
  1687. PCNP_NETWORK network;
  1688. OBJECT_ATTRIBUTES objectAttributes;
  1689. IO_STATUS_BLOCK iosb;
  1690. PFILE_FULL_EA_INFORMATION ea = NULL;
  1691. ULONG eaBufferLength;
  1692. HANDLE addressHandle = NULL;
  1693. PFILE_OBJECT addressFileObject = NULL;
  1694. PDEVICE_OBJECT addressDeviceObject = NULL;
  1695. BOOLEAN attached = FALSE;
  1696. UNICODE_STRING unicodeString;
  1697. TDI_REQUEST_KERNEL_QUERY_INFORMATION queryInfo;
  1698. PTDI_ADDRESS_INFO addressInfo;
  1699. //
  1700. // Allocate memory to hold the EA buffer we'll use to specify the
  1701. // transport address to NtCreateFile.
  1702. //
  1703. eaBufferLength = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
  1704. TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
  1705. TdiBindAddressLength;
  1706. ea = CnAllocatePool(eaBufferLength);
  1707. if (ea == NULL) {
  1708. IF_CNDBG(CN_DEBUG_CONFIG) {
  1709. CNPRINT((
  1710. "[CNP] memory allocation of %u bytes failed.\n",
  1711. eaBufferLength
  1712. ));
  1713. }
  1714. return(STATUS_INSUFFICIENT_RESOURCES);
  1715. }
  1716. //
  1717. // Initialize the EA using the network's transport information.
  1718. //
  1719. ea->NextEntryOffset = 0;
  1720. ea->Flags = 0;
  1721. ea->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
  1722. ea->EaValueLength = (USHORT) TdiBindAddressLength;
  1723. RtlMoveMemory(
  1724. ea->EaName,
  1725. TdiTransportAddress,
  1726. ea->EaNameLength + 1
  1727. );
  1728. RtlMoveMemory(
  1729. &(ea->EaName[ea->EaNameLength + 1]),
  1730. TdiBindAddress,
  1731. TdiBindAddressLength
  1732. );
  1733. RtlInitUnicodeString(&unicodeString, TdiProviderName);
  1734. network = CnpFindNetwork(NetworkId);
  1735. if (network == NULL) {
  1736. CnFreePool(ea);
  1737. return(STATUS_CLUSTER_NETWORK_NOT_FOUND);
  1738. }
  1739. if (network->State != ClusnetNetworkStateOffline) {
  1740. CnReleaseLock(&(network->Lock), network->Irql);
  1741. CnFreePool(ea);
  1742. return(STATUS_CLUSTER_NETWORK_ALREADY_ONLINE);
  1743. }
  1744. CnAssert(network->DatagramHandle == NULL);
  1745. CnAssert(network->DatagramFileObject == NULL);
  1746. CnAssert(network->DatagramDeviceObject == NULL);
  1747. CnAssert(network->ActiveRefCount == 0);
  1748. IF_CNDBG(CN_DEBUG_CONFIG) {
  1749. CNPRINT(("[CNP] Bringing network %u online...\n", NetworkId));
  1750. }
  1751. //
  1752. // Set the initial active refcount to 2. One reference will be removed
  1753. // when the network is successfully brought online. The other will be
  1754. // removed when the network is to be taken offline. Also increment the
  1755. // base refcount to account for the active refcount. Change to
  1756. // the online pending state.
  1757. //
  1758. network->ActiveRefCount = 2;
  1759. CnpReferenceNetwork(network);
  1760. network->State = ClusnetNetworkStateOnlinePending;
  1761. CnReleaseLock(&(network->Lock), network->Irql);
  1762. //
  1763. // Prepare for opening the address object.
  1764. //
  1765. InitializeObjectAttributes(
  1766. &objectAttributes,
  1767. &unicodeString,
  1768. OBJ_CASE_INSENSITIVE, // attributes
  1769. NULL,
  1770. NULL
  1771. );
  1772. //
  1773. // Attach to the system process so the handle we open will remain valid
  1774. // after the calling process goes away.
  1775. //
  1776. KeAttachProcess(CnSystemProcess);
  1777. attached = TRUE;
  1778. //
  1779. // Perform the actual open of the address object.
  1780. //
  1781. status = ZwCreateFile(
  1782. &addressHandle,
  1783. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  1784. &objectAttributes,
  1785. &iosb, // returned status information.
  1786. 0, // block size (unused).
  1787. 0, // file attributes.
  1788. 0, // not shareable
  1789. FILE_CREATE, // create disposition.
  1790. 0, // create options.
  1791. ea,
  1792. eaBufferLength
  1793. );
  1794. CnFreePool(ea); ea = NULL;
  1795. if (status != STATUS_SUCCESS) {
  1796. IF_CNDBG(CN_DEBUG_CONFIG) {
  1797. CNPRINT((
  1798. "[CNP] Failed to open address for network %u, status %lx.\n",
  1799. NetworkId,
  1800. status
  1801. ));
  1802. }
  1803. goto error_exit;
  1804. }
  1805. //
  1806. // Get a pointer to the file object of the address.
  1807. //
  1808. status = ObReferenceObjectByHandle(
  1809. addressHandle,
  1810. 0L, // DesiredAccess
  1811. NULL,
  1812. KernelMode,
  1813. &addressFileObject,
  1814. NULL
  1815. );
  1816. if (status != STATUS_SUCCESS) {
  1817. IF_CNDBG(CN_DEBUG_CONFIG) {
  1818. CNPRINT((
  1819. "[CNP] Failed to reference address handle, status %lx.\n",
  1820. status
  1821. ));
  1822. }
  1823. goto error_exit;
  1824. }
  1825. //
  1826. // Remember the device object to which we need to give requests for
  1827. // this address object. We can't just use the fileObject->DeviceObject
  1828. // pointer because there may be a device attached to the transport
  1829. // protocol.
  1830. //
  1831. addressDeviceObject = IoGetRelatedDeviceObject(
  1832. addressFileObject
  1833. );
  1834. //
  1835. // Adjust the StackSize of CdpDeviceObject so that we can pass CDP
  1836. // IRPs through for this network.
  1837. //
  1838. CnAdjustDeviceObjectStackSize(CdpDeviceObject, addressDeviceObject);
  1839. //
  1840. // Get the transport provider info
  1841. //
  1842. queryInfo.QueryType = TDI_QUERY_PROVIDER_INFO;
  1843. queryInfo.RequestConnectionInformation = NULL;
  1844. status = CnpIssueDeviceControl(
  1845. addressFileObject,
  1846. addressDeviceObject,
  1847. &queryInfo,
  1848. sizeof(queryInfo),
  1849. &(network->ProviderInfo),
  1850. sizeof(network->ProviderInfo),
  1851. TDI_QUERY_INFORMATION,
  1852. Irp
  1853. );
  1854. if (!NT_SUCCESS(status)) {
  1855. IF_CNDBG(CN_DEBUG_CONFIG) {
  1856. CNPRINT((
  1857. "[CNP] Failed to get provider info, status %lx\n",
  1858. status
  1859. ));
  1860. }
  1861. goto error_exit;
  1862. }
  1863. if (! ( network->ProviderInfo.ServiceFlags &
  1864. TDI_SERVICE_CONNECTIONLESS_MODE)
  1865. )
  1866. {
  1867. IF_CNDBG(CN_DEBUG_CONFIG) {
  1868. CNPRINT((
  1869. "[CNP] Provider doesn't support datagrams!\n"
  1870. ));
  1871. }
  1872. status = STATUS_CLUSTER_INVALID_NETWORK_PROVIDER;
  1873. goto error_exit;
  1874. }
  1875. //
  1876. // Get the address to which we were bound.
  1877. //
  1878. queryInfo.QueryType = TDI_QUERY_ADDRESS_INFO;
  1879. queryInfo.RequestConnectionInformation = NULL;
  1880. status = CnpIssueDeviceControl(
  1881. addressFileObject,
  1882. addressDeviceObject,
  1883. &queryInfo,
  1884. sizeof(queryInfo),
  1885. TdiBindAddressInfo,
  1886. TdiBindAddressInfoLength,
  1887. TDI_QUERY_INFORMATION,
  1888. Irp
  1889. );
  1890. if (!NT_SUCCESS(status)) {
  1891. IF_CNDBG(CN_DEBUG_CONFIG) {
  1892. CNPRINT((
  1893. "[CNP] Failed to get address info, status %lx\n",
  1894. status
  1895. ));
  1896. }
  1897. goto error_exit;
  1898. }
  1899. //
  1900. // Set up indication handlers on the address object. We are eligible
  1901. // to receive indications as soon as we do this.
  1902. //
  1903. status = CnpTdiSetEventHandler(
  1904. addressFileObject,
  1905. addressDeviceObject,
  1906. TDI_EVENT_ERROR,
  1907. CnpTdiErrorHandler,
  1908. network,
  1909. Irp
  1910. );
  1911. if ( !NT_SUCCESS(status) ) {
  1912. IF_CNDBG(CN_DEBUG_CONFIG) {
  1913. CNPRINT((
  1914. "[CNP] Setting TDI_EVENT_ERROR failed: %lx\n",
  1915. status
  1916. ));
  1917. }
  1918. goto error_exit;
  1919. }
  1920. status = CnpTdiSetEventHandler(
  1921. addressFileObject,
  1922. addressDeviceObject,
  1923. TDI_EVENT_RECEIVE_DATAGRAM,
  1924. CnpTdiReceiveDatagramHandler,
  1925. network,
  1926. Irp
  1927. );
  1928. if ( !NT_SUCCESS(status) ) {
  1929. IF_CNDBG(CN_DEBUG_CONFIG) {
  1930. CNPRINT((
  1931. "[CNP] Setting TDI_EVENT_RECEIVE_DATAGRAM failed: %lx\n",
  1932. status
  1933. ));
  1934. }
  1935. goto error_exit;
  1936. }
  1937. //
  1938. // We're done working with handles, so detach from the system process.
  1939. //
  1940. KeDetachProcess();
  1941. //
  1942. // Finish transition to online state. Note that an offline request
  1943. // could have been issued in the meantime.
  1944. //
  1945. CnAcquireLock(&(network->Lock), &(network->Irql));
  1946. network->DatagramHandle = addressHandle;
  1947. addressHandle = NULL;
  1948. network->DatagramFileObject = addressFileObject;
  1949. addressFileObject = NULL;
  1950. network->DatagramDeviceObject = addressDeviceObject;
  1951. addressDeviceObject = NULL;
  1952. //
  1953. // If an offline wasn't issued, change to the online state.
  1954. //
  1955. if (network->State == ClusnetNetworkStateOnlinePending) {
  1956. CnAssert(network->ActiveRefCount == 2);
  1957. network->State = ClusnetNetworkStateOnline;
  1958. IF_CNDBG(CN_DEBUG_CONFIG) {
  1959. CNPRINT(("[CNP] Network %u is now online.\n", NetworkId));
  1960. }
  1961. CnReleaseLock(&(network->Lock), network->Irql);
  1962. //
  1963. // Bring all of the interfaces on this network online.
  1964. //
  1965. // The network can't be taken offline because we still hold
  1966. // the 2nd active reference.
  1967. //
  1968. IF_CNDBG(CN_DEBUG_CONFIG) {
  1969. CNPRINT((
  1970. "[CNP] Bringing all interfaces on network %u online...\n",
  1971. network->Id
  1972. ));
  1973. }
  1974. CnpWalkInterfacesOnNetwork(network, CnpOnlinePendingInterfaceWrapper);
  1975. //
  1976. // Position the network in the network list according to
  1977. // multicast reachability.
  1978. //
  1979. CnpSortMulticastNetwork(network, TRUE, NULL);
  1980. //
  1981. // Reacquire the lock to drop the active reference.
  1982. //
  1983. CnAcquireLock(&(network->Lock), &(network->Irql));
  1984. }
  1985. else {
  1986. //
  1987. // An offline was issued. It will take effect when we
  1988. // remove our 2nd active reference. The offline operation removed
  1989. // the first one. No send threads could have accessed this network
  1990. // yet because we never brought the associated interfaces online.
  1991. //
  1992. CnAssert(network->State == ClusnetNetworkStateOfflinePending);
  1993. IF_CNDBG(CN_DEBUG_CONFIG) {
  1994. CNPRINT((
  1995. "[CNP] An offline request was issued on network %u during online pending.\n",
  1996. NetworkId
  1997. ));
  1998. }
  1999. }
  2000. CnpActiveDereferenceNetwork(network);
  2001. CnVerifyCpuLockMask(
  2002. 0, // Required
  2003. 0xFFFFFFFF, // Forbidden
  2004. 0 // Maximum
  2005. );
  2006. return(STATUS_SUCCESS);
  2007. error_exit:
  2008. if (addressFileObject != NULL) {
  2009. ObDereferenceObject(addressFileObject);
  2010. }
  2011. if (addressHandle != NULL) {
  2012. ZwClose(addressHandle);
  2013. }
  2014. KeDetachProcess();
  2015. CnAcquireLock(&(network->Lock), &(network->Irql));
  2016. if (network->State == ClusnetNetworkStateOnlinePending) {
  2017. //
  2018. // Remove our 2nd active reference and call the offline code.
  2019. // The offline function will release the network object lock.
  2020. //
  2021. CnAssert(network->ActiveRefCount == 2);
  2022. --(network->ActiveRefCount);
  2023. CnpOfflineNetwork(network);
  2024. }
  2025. else {
  2026. CnAssert(network->State == ClusnetNetworkStateOfflinePending);
  2027. //
  2028. // An offline was issued. It will take effect when we
  2029. // remove our 2nd active reference. The offline operation removed
  2030. // the first one. The dereference will release the network object
  2031. // lock.
  2032. //
  2033. CnAssert(network->State == ClusnetNetworkStateOfflinePending);
  2034. CnAssert(network->ActiveRefCount == 1);
  2035. CnpActiveDereferenceNetwork(network);
  2036. }
  2037. CnVerifyCpuLockMask(
  2038. 0, // Required
  2039. 0xFFFFFFFF, // Forbidden
  2040. 0 // Maximum
  2041. );
  2042. return(status);
  2043. } // CxOnlineNetwork
  2044. VOID
  2045. CxCancelOfflineNetwork(
  2046. PDEVICE_OBJECT DeviceObject,
  2047. PIRP Irp
  2048. )
  2049. /*++
  2050. Routine Description:
  2051. Cancellation handler for OfflineNetwork requests.
  2052. Return Value:
  2053. None.
  2054. Notes:
  2055. Called with cancel spinlock held.
  2056. Returns with cancel spinlock released.
  2057. --*/
  2058. {
  2059. PFILE_OBJECT fileObject;
  2060. CN_IRQL cancelIrql = Irp->CancelIrql;
  2061. PLIST_ENTRY entry;
  2062. PCNP_NETWORK network;
  2063. PCNP_NETWORK offlineNetwork = NULL;
  2064. CnMarkIoCancelLockAcquired();
  2065. IF_CNDBG(CN_DEBUG_CONFIG) {
  2066. CNPRINT((
  2067. "[CNP] Attempting to cancel OfflineNetwork irp %p\n",
  2068. Irp
  2069. ));
  2070. }
  2071. CnAssert(DeviceObject == CnDeviceObject);
  2072. fileObject = CnBeginCancelRoutine(Irp);
  2073. CnAcquireLockAtDpc(&CnpNetworkListLock);
  2074. CnReleaseCancelSpinLock(DISPATCH_LEVEL);
  2075. //
  2076. // We can only complete the irp if we can find it stashed in a
  2077. // network object. The network object could have been destroyed
  2078. // and the IRP completed before we acquired the CnpNetworkListLock.
  2079. //
  2080. for (entry = CnpNetworkList.Flink;
  2081. entry != &CnpNetworkList;
  2082. entry = entry->Flink
  2083. )
  2084. {
  2085. network = CONTAINING_RECORD(entry, CNP_NETWORK, Linkage);
  2086. CnAcquireLockAtDpc(&(network->Lock));
  2087. if (network->PendingOfflineIrp == Irp) {
  2088. IF_CNDBG(CN_DEBUG_CONFIG) {
  2089. CNPRINT((
  2090. "[CNP] Found offline irp on network %u\n",
  2091. network->Id
  2092. ));
  2093. }
  2094. network->PendingOfflineIrp = NULL;
  2095. offlineNetwork = network;
  2096. CnReleaseLockFromDpc(&(network->Lock));
  2097. break;
  2098. }
  2099. CnReleaseLockFromDpc(&(network->Lock));
  2100. }
  2101. if (offlineNetwork == NULL) {
  2102. for (entry = CnpDeletingNetworkList.Flink;
  2103. entry != &CnpDeletingNetworkList;
  2104. entry = entry->Flink
  2105. )
  2106. {
  2107. network = CONTAINING_RECORD(entry, CNP_NETWORK, Linkage);
  2108. CnAcquireLockAtDpc(&(network->Lock));
  2109. if (network->PendingOfflineIrp == Irp) {
  2110. IF_CNDBG(CN_DEBUG_CONFIG) {
  2111. CNPRINT((
  2112. "[CNP] Found offline irp on network %u\n",
  2113. network->Id
  2114. ));
  2115. }
  2116. network->PendingOfflineIrp = NULL;
  2117. offlineNetwork = network;
  2118. CnReleaseLockFromDpc(&(network->Lock));
  2119. break;
  2120. }
  2121. CnReleaseLockFromDpc(&(network->Lock));
  2122. }
  2123. }
  2124. CnReleaseLock(&CnpNetworkListLock, cancelIrql);
  2125. CnAcquireCancelSpinLock(&cancelIrql);
  2126. CnEndCancelRoutine(fileObject);
  2127. if (offlineNetwork != NULL) {
  2128. //
  2129. // Found the Irp. Now take it away and complete it.
  2130. // This releases the cancel spinlock
  2131. //
  2132. Irp->CancelIrql = cancelIrql;
  2133. CnCompletePendingRequest(Irp, STATUS_CANCELLED, 0);
  2134. }
  2135. else {
  2136. CnReleaseCancelSpinLock(cancelIrql);
  2137. }
  2138. CnVerifyCpuLockMask(
  2139. 0, // Required
  2140. 0xFFFFFFFF, // Forbidden
  2141. 0 // Maximum
  2142. );
  2143. return;
  2144. } // CnpCancelApiOfflineNetwork
  2145. NTSTATUS
  2146. CxOfflineNetwork(
  2147. IN CL_NETWORK_ID NetworkId,
  2148. IN PIRP Irp,
  2149. IN PIO_STACK_LOCATION IrpSp
  2150. )
  2151. /*++
  2152. Notes:
  2153. --*/
  2154. {
  2155. PCNP_NETWORK network;
  2156. CN_IRQL irql;
  2157. NTSTATUS status;
  2158. CnAcquireCancelSpinLock(&irql);
  2159. CnAcquireLockAtDpc(&CnpNetworkListLock);
  2160. status = CnMarkRequestPending(Irp, IrpSp, CxCancelOfflineNetwork);
  2161. CnReleaseCancelSpinLock(DISPATCH_LEVEL);
  2162. if (status != STATUS_CANCELLED) {
  2163. CnAssert(status == STATUS_SUCCESS);
  2164. network = CnpLockedFindNetwork(NetworkId, irql);
  2165. //
  2166. // CnpNetworkListLock was released.
  2167. //
  2168. if (network != NULL) {
  2169. if (network->State >= ClusnetNetworkStateOnlinePending) {
  2170. network->PendingOfflineIrp = Irp;
  2171. CnpOfflineNetwork(network);
  2172. return(STATUS_PENDING);
  2173. }
  2174. CnReleaseLock(&(network->Lock), network->Irql);
  2175. status = STATUS_CLUSTER_NETWORK_ALREADY_OFFLINE;
  2176. }
  2177. else {
  2178. status = STATUS_CLUSTER_NETWORK_NOT_FOUND;
  2179. }
  2180. CnAcquireCancelSpinLock(&irql);
  2181. Irp->CancelIrql = irql;
  2182. CnCompletePendingRequest(Irp, status, 0);
  2183. CnVerifyCpuLockMask(
  2184. 0, // Required
  2185. 0xFFFFFFFF, // Forbidden
  2186. 0 // Maximum
  2187. );
  2188. return(STATUS_PENDING);
  2189. }
  2190. CnAssert(status == STATUS_CANCELLED);
  2191. CnReleaseLock(&CnpNetworkListLock, irql);
  2192. CnVerifyCpuLockMask(
  2193. 0, // Required
  2194. 0xFFFFFFFF, // Forbidden
  2195. 0 // Maximum
  2196. );
  2197. return(status);
  2198. } // CxOfflineNetwork
  2199. NTSTATUS
  2200. CxSetNetworkRestriction(
  2201. IN CL_NETWORK_ID NetworkId,
  2202. IN BOOLEAN Restricted,
  2203. IN ULONG NewPriority
  2204. )
  2205. {
  2206. NTSTATUS status;
  2207. PCNP_NETWORK network;
  2208. network = CnpFindNetwork(NetworkId);
  2209. if (network != NULL) {
  2210. if (Restricted) {
  2211. IF_CNDBG(CN_DEBUG_CONFIG) {
  2212. CNPRINT((
  2213. "[CNP] Restricting network %u.\n",
  2214. network->Id
  2215. ));
  2216. }
  2217. network->Flags |= CNP_NET_FLAG_RESTRICTED;
  2218. }
  2219. else {
  2220. IF_CNDBG(CN_DEBUG_CONFIG) {
  2221. CNPRINT((
  2222. "[CNP] Unrestricting network %u.\n",
  2223. network->Id
  2224. ));
  2225. }
  2226. network->Flags &= ~CNP_NET_FLAG_RESTRICTED;
  2227. if (NewPriority != 0) {
  2228. network->Priority = NewPriority;
  2229. }
  2230. }
  2231. //
  2232. // Reference the network so it can't go away while we
  2233. // reprioritize the associated interfaces.
  2234. //
  2235. CnpReferenceNetwork(network);
  2236. CnReleaseLock(&(network->Lock), network->Irql);
  2237. IF_CNDBG(CN_DEBUG_CONFIG) {
  2238. CNPRINT((
  2239. "[CNP] Recalculating priority for all interfaces on network %u ...\n",
  2240. network->Id
  2241. ));
  2242. }
  2243. if (!Restricted) {
  2244. CnpWalkInterfacesOnNetwork(
  2245. network,
  2246. CnpRecalculateInterfacePriority
  2247. );
  2248. }
  2249. CnpWalkInterfacesOnNetwork(network, CnpReevaluateInterfaceRole);
  2250. //
  2251. // Reposition the network according to multicast reachability.
  2252. //
  2253. CnpSortMulticastNetwork(network, TRUE, NULL);
  2254. CnAcquireLock(&(network->Lock), &(network->Irql));
  2255. CnpDereferenceNetwork(network);
  2256. status = STATUS_SUCCESS;
  2257. }
  2258. else {
  2259. status = STATUS_CLUSTER_NETWORK_NOT_FOUND;
  2260. }
  2261. CnVerifyCpuLockMask(
  2262. 0, // Required
  2263. 0xFFFFFFFF, // Forbidden
  2264. 0 // Maximum
  2265. );
  2266. return(status);
  2267. } // CxSetNetworkRestriction
  2268. NTSTATUS
  2269. CxSetNetworkPriority(
  2270. IN CL_NETWORK_ID NetworkId,
  2271. IN ULONG Priority
  2272. )
  2273. {
  2274. NTSTATUS status;
  2275. PCNP_NETWORK network;
  2276. if (Priority == 0) {
  2277. return(STATUS_INVALID_PARAMETER);
  2278. }
  2279. network = CnpFindNetwork(NetworkId);
  2280. if (network != NULL) {
  2281. IF_CNDBG(CN_DEBUG_CONFIG) {
  2282. CNPRINT((
  2283. "[CNP] Network %u old priority %u, new priority %u.\n",
  2284. network->Id,
  2285. network->Priority,
  2286. Priority
  2287. ));
  2288. }
  2289. network->Priority = Priority;
  2290. //
  2291. // Reference the network so it can't go away while we
  2292. // reprioritize the associated interfaces.
  2293. //
  2294. CnpReferenceNetwork(network);
  2295. CnReleaseLock(&(network->Lock), network->Irql);
  2296. IF_CNDBG(CN_DEBUG_CONFIG) {
  2297. CNPRINT((
  2298. "[CNP] Recalculating priority for all interfaces on network %u ...\n",
  2299. network->Id
  2300. ));
  2301. }
  2302. CnpWalkInterfacesOnNetwork(network, CnpRecalculateInterfacePriority);
  2303. //
  2304. // Reposition the network according to multicast reachability.
  2305. //
  2306. CnpSortMulticastNetwork(network, TRUE, NULL);
  2307. CnAcquireLock(&(network->Lock), &(network->Irql));
  2308. CnpDereferenceNetwork(network);
  2309. status = STATUS_SUCCESS;
  2310. }
  2311. else {
  2312. status = STATUS_CLUSTER_NETWORK_NOT_FOUND;
  2313. }
  2314. CnVerifyCpuLockMask(
  2315. 0, // Required
  2316. 0xFFFFFFFF, // Forbidden
  2317. 0 // Maximum
  2318. );
  2319. return(status);
  2320. } // CxSetNetworkPriority
  2321. NTSTATUS
  2322. CxGetNetworkPriority(
  2323. IN CL_NETWORK_ID NetworkId,
  2324. OUT PULONG Priority
  2325. )
  2326. {
  2327. NTSTATUS status;
  2328. PCNP_NETWORK network;
  2329. network = CnpFindNetwork(NetworkId);
  2330. if (network != NULL) {
  2331. *Priority = network->Priority;
  2332. CnReleaseLock(&(network->Lock), network->Irql);
  2333. status = STATUS_SUCCESS;
  2334. }
  2335. else {
  2336. status = STATUS_CLUSTER_NETWORK_NOT_FOUND;
  2337. }
  2338. CnVerifyCpuLockMask(
  2339. 0, // Required
  2340. 0xFFFFFFFF, // Forbidden
  2341. 0 // Maximum
  2342. );
  2343. return(status);
  2344. } // CxGetNetworkPriority
  2345. NTSTATUS
  2346. CxGetNetworkState(
  2347. IN CL_NETWORK_ID NetworkId,
  2348. OUT PCLUSNET_NETWORK_STATE State
  2349. )
  2350. {
  2351. NTSTATUS status;
  2352. PCNP_NETWORK network;
  2353. network = CnpFindNetwork(NetworkId);
  2354. if (network != NULL) {
  2355. *State = network->State;
  2356. CnReleaseLock(&(network->Lock), network->Irql);
  2357. status = STATUS_SUCCESS;
  2358. }
  2359. else {
  2360. status = STATUS_CLUSTER_NETWORK_NOT_FOUND;
  2361. }
  2362. CnVerifyCpuLockMask(
  2363. 0, // Required
  2364. 0xFFFFFFFF, // Forbidden
  2365. 0 // Maximum
  2366. );
  2367. return(status);
  2368. } // CxGetNetworkState
  2369. NTSTATUS
  2370. CxUnreserveClusnetEndpoint(
  2371. VOID
  2372. )
  2373. /*++
  2374. Routine Description:
  2375. Unreserves port number previously reserved with
  2376. CxUnreserveClusnetEndpoint.
  2377. CnResource should already be held when this routine
  2378. is called. Alternately, this routine is called without
  2379. CnResource held during unload of the clusnet driver.
  2380. Arguments:
  2381. None.
  2382. Return Value:
  2383. Status of TCP/IP ioctl.
  2384. --*/
  2385. {
  2386. HANDLE tcpHandle = (HANDLE) NULL;
  2387. TCP_RESERVE_PORT_RANGE portRange;
  2388. NTSTATUS status = STATUS_SUCCESS;
  2389. // Check if we have a port reserved
  2390. if (CnpReservedClusnetPort != 0) {
  2391. status = CnpOpenDevice(
  2392. DD_TCP_DEVICE_NAME,
  2393. &tcpHandle
  2394. );
  2395. if (NT_SUCCESS(status)) {
  2396. // TCP/IP interprets port ranges in host order
  2397. portRange.LowerRange = CnpReservedClusnetPort;
  2398. portRange.UpperRange = CnpReservedClusnetPort;
  2399. status = CnpZwDeviceControl(
  2400. tcpHandle,
  2401. IOCTL_TCP_UNRESERVE_PORT_RANGE,
  2402. &portRange,
  2403. sizeof(portRange),
  2404. NULL,
  2405. 0
  2406. );
  2407. if (!NT_SUCCESS(status)) {
  2408. IF_CNDBG(CN_DEBUG_CONFIG) {
  2409. CNPRINT(("[Clusnet] Failed to unreserve "
  2410. "port %d: %lx\n",
  2411. CnpReservedClusnetPort, status));
  2412. }
  2413. } else {
  2414. IF_CNDBG(CN_DEBUG_CONFIG) {
  2415. CNPRINT(("[Clusnet] Unreserved "
  2416. "port %d.\n",
  2417. CnpReservedClusnetPort));
  2418. }
  2419. }
  2420. ZwClose(tcpHandle);
  2421. } else {
  2422. IF_CNDBG(CN_DEBUG_CONFIG) {
  2423. CNPRINT(("[Clusnet] Failed to open device %S, "
  2424. "status %lx\n",
  2425. DD_TCP_DEVICE_NAME, status));
  2426. }
  2427. }
  2428. CnpReservedClusnetPort = 0;
  2429. }
  2430. return status;
  2431. }
  2432. NTSTATUS
  2433. CxReserveClusnetEndpoint(
  2434. IN USHORT Port
  2435. )
  2436. /*++
  2437. Routine Description:
  2438. Reserves assigned clusnet endpoint port number so that
  2439. the TCP/IP driver will not hand it out to applications
  2440. requesting a wildcard port.
  2441. Arguments:
  2442. Port - port number to reserve, in host byte-order format
  2443. Return Value:
  2444. Status of TCP/IP ioctl.
  2445. --*/
  2446. {
  2447. NTSTATUS status = STATUS_SUCCESS;
  2448. HANDLE tcpHandle = (HANDLE) NULL;
  2449. TCP_RESERVE_PORT_RANGE portRange;
  2450. // Check for invalid port number 0
  2451. if (Port == 0) {
  2452. return STATUS_INVALID_PARAMETER;
  2453. }
  2454. // Check if we already have a port reserved.
  2455. if (CnpReservedClusnetPort != 0
  2456. && CnpReservedClusnetPort != Port) {
  2457. status = CxUnreserveClusnetEndpoint();
  2458. }
  2459. if (CnpReservedClusnetPort == 0) {
  2460. // Reserve Port with the TCP/IP driver.
  2461. status = CnpOpenDevice(
  2462. DD_TCP_DEVICE_NAME,
  2463. &tcpHandle
  2464. );
  2465. if (NT_SUCCESS(status)) {
  2466. // TCP/IP interprets port ranges in host order
  2467. portRange.LowerRange = Port;
  2468. portRange.UpperRange = Port;
  2469. status = CnpZwDeviceControl(
  2470. tcpHandle,
  2471. IOCTL_TCP_RESERVE_PORT_RANGE,
  2472. &portRange,
  2473. sizeof(portRange),
  2474. NULL,
  2475. 0
  2476. );
  2477. if (!NT_SUCCESS(status)) {
  2478. IF_CNDBG(CN_DEBUG_CONFIG) {
  2479. CNPRINT(("[Clusnet] Failed to reserve "
  2480. "port %d: %lx\n",
  2481. Port, status));
  2482. }
  2483. } else {
  2484. IF_CNDBG(CN_DEBUG_CONFIG) {
  2485. CNPRINT(("[Clusnet] Reserved "
  2486. "port %d.\n",
  2487. Port));
  2488. }
  2489. CnpReservedClusnetPort = Port;
  2490. }
  2491. ZwClose(tcpHandle);
  2492. } else {
  2493. IF_CNDBG(CN_DEBUG_CONFIG) {
  2494. CNPRINT(("[Clusnet] Failed to open device %S, "
  2495. "status %lx\n",
  2496. DD_TCP_DEVICE_NAME, status));
  2497. }
  2498. }
  2499. }
  2500. return status;
  2501. } // CxReserveClusnetEndpoint
  2502. NTSTATUS
  2503. CxConfigureMulticast(
  2504. IN CL_NETWORK_ID NetworkId,
  2505. IN ULONG MulticastNetworkBrand,
  2506. IN PTRANSPORT_ADDRESS TdiMcastBindAddress,
  2507. IN ULONG TdiMcastBindAddressLength,
  2508. IN PVOID Key,
  2509. IN ULONG KeyLength,
  2510. IN PIRP Irp
  2511. )
  2512. /*++
  2513. Routine Description:
  2514. Configures a network for multicast.
  2515. Notes:
  2516. The network multicast flag is turned off at the
  2517. beginning of this routine to prevent multicasts
  2518. during the transition. If the routine does not
  2519. complete successfully, the multicast flag is
  2520. purposely left cleared.
  2521. --*/
  2522. {
  2523. NTSTATUS status;
  2524. KIRQL irql;
  2525. PLIST_ENTRY entry;
  2526. PCNP_NETWORK network = NULL;
  2527. BOOLEAN networkLocked = FALSE;
  2528. BOOLEAN mcastEnabled = FALSE;
  2529. TDI_REQUEST_KERNEL_QUERY_INFORMATION queryInfo;
  2530. PTDI_ADDRESS_INFO addressInfo;
  2531. HANDLE networkHandle;
  2532. PFILE_OBJECT networkFileObject;
  2533. PDEVICE_OBJECT networkDeviceObject;
  2534. PCNP_MULTICAST_GROUP group = NULL;
  2535. PCNP_MULTICAST_GROUP delGroup = NULL;
  2536. PCNP_MULTICAST_GROUP currGroup = NULL;
  2537. PCNP_MULTICAST_GROUP prevGroup = NULL;
  2538. BOOLEAN prevGroupMatch = FALSE;
  2539. UCHAR addressInfoBuffer[FIELD_OFFSET(TDI_ADDRESS_INFO, Address) +
  2540. sizeof(TA_IP_ADDRESS)] = {0};
  2541. //
  2542. // Validate multicast bind address parameter. Even if this
  2543. // request only leaves a group, the multicast address data
  2544. // structure must be provided.
  2545. //
  2546. if (TdiMcastBindAddressLength != sizeof(TA_IP_ADDRESS)) {
  2547. return (STATUS_INVALID_PARAMETER);
  2548. }
  2549. //
  2550. // Acquire the lock on the local node, but go through the
  2551. // node table to be extra paranoid.
  2552. //
  2553. CnAcquireLock(&CnpNodeTableLock, &irql);
  2554. if (CnpLocalNode != NULL) {
  2555. CnAcquireLockAtDpc(&(CnpLocalNode->Lock));
  2556. CnReleaseLockFromDpc(&CnpNodeTableLock);
  2557. CnpLocalNode->Irql = irql;
  2558. //
  2559. // Find the network object in the network object table.
  2560. //
  2561. CnAcquireLockAtDpc(&CnpNetworkListLock);
  2562. for (entry = CnpNetworkList.Flink;
  2563. entry != &CnpNetworkList;
  2564. entry = entry->Flink
  2565. )
  2566. {
  2567. network = CONTAINING_RECORD(entry, CNP_NETWORK, Linkage);
  2568. CnAcquireLockAtDpc(&(network->Lock));
  2569. if (NetworkId == network->Id) {
  2570. //
  2571. // We now hold locks on the node, the network list,
  2572. // and the network.
  2573. //
  2574. // Verify the network state. Then take an active
  2575. // reference so that it doesn't disappear while
  2576. // we're working with it.
  2577. //
  2578. if ((network->State < ClusnetNetworkStateOnline) ||
  2579. (!CnpActiveReferenceNetwork(network))
  2580. ) {
  2581. CnReleaseLockFromDpc(&(network->Lock));
  2582. CnReleaseLockFromDpc(&CnpNetworkListLock);
  2583. CnReleaseLock(&(CnpLocalNode->Lock), CnpLocalNode->Irql);
  2584. return(STATUS_CLUSTER_INVALID_NETWORK);
  2585. }
  2586. //
  2587. // Clear the reachable set for this network.
  2588. //
  2589. CnpMulticastChangeNodeReachabilityLocked(
  2590. network,
  2591. CnpLocalNode,
  2592. FALSE,
  2593. TRUE,
  2594. NULL
  2595. );
  2596. //
  2597. // Remember whether the network was multicast-capable. Then
  2598. // clear the multicast capable flag so that we don't try to
  2599. // send multicasts during the transition period.
  2600. //
  2601. mcastEnabled = (BOOLEAN) CnpIsNetworkMulticastCapable(network);
  2602. network->Flags &= ~CNP_NET_FLAG_MULTICAST;
  2603. networkHandle = network->DatagramHandle;
  2604. networkFileObject = network->DatagramFileObject;
  2605. networkDeviceObject = network->DatagramDeviceObject;
  2606. currGroup = network->CurrentMcastGroup;
  2607. if (currGroup != NULL) {
  2608. CnpReferenceMulticastGroup(currGroup);
  2609. }
  2610. prevGroup = network->PreviousMcastGroup;
  2611. if (prevGroup != NULL) {
  2612. CnpReferenceMulticastGroup(prevGroup);
  2613. }
  2614. //
  2615. // Release the network lock.
  2616. //
  2617. CnReleaseLockFromDpc(&(network->Lock));
  2618. networkLocked = FALSE;
  2619. //
  2620. // Break out of the network search.
  2621. //
  2622. break;
  2623. } else {
  2624. CnReleaseLockFromDpc(&(network->Lock));
  2625. network = NULL;
  2626. }
  2627. }
  2628. //
  2629. // Release the network list lock.
  2630. //
  2631. CnReleaseLockFromDpc(&CnpNetworkListLock);
  2632. //
  2633. // Release the local node lock.
  2634. //
  2635. CnReleaseLock(&(CnpLocalNode->Lock), CnpLocalNode->Irql);
  2636. } else {
  2637. CnReleaseLock(&CnpNodeTableLock, irql);
  2638. CnTrace(CNP_NET_DETAIL, CnpTraceMcastPreConfigNoHost,
  2639. "[CNP] Cannot configure multicast for network %u "
  2640. "because local host not found.",
  2641. NetworkId
  2642. );
  2643. return(STATUS_HOST_UNREACHABLE);
  2644. }
  2645. //
  2646. // Verify that we found the network.
  2647. //
  2648. if (network == NULL) {
  2649. return (STATUS_CLUSTER_NETWORK_NOT_FOUND);
  2650. }
  2651. //
  2652. // Allocate a multicast group data structure with the
  2653. // new configuration parameters.
  2654. //
  2655. status = CnpAllocateMulticastGroup(
  2656. MulticastNetworkBrand,
  2657. TdiMcastBindAddress,
  2658. TdiMcastBindAddressLength,
  2659. Key,
  2660. KeyLength,
  2661. &group
  2662. );
  2663. if (!NT_SUCCESS(status)) {
  2664. IF_CNDBG(CN_DEBUG_NETOBJ) {
  2665. CNPRINT((
  2666. "[CNP] Failed to allocate mcast group, "
  2667. "status %lx\n",
  2668. status
  2669. ));
  2670. }
  2671. goto error_exit;
  2672. }
  2673. //
  2674. // Get the local interface address.
  2675. //
  2676. addressInfo = (PTDI_ADDRESS_INFO) &addressInfoBuffer[0];
  2677. queryInfo.QueryType = TDI_QUERY_ADDRESS_INFO;
  2678. queryInfo.RequestConnectionInformation = NULL;
  2679. status = CnpIssueDeviceControl(
  2680. networkFileObject,
  2681. networkDeviceObject,
  2682. &queryInfo,
  2683. sizeof(queryInfo),
  2684. addressInfo,
  2685. sizeof(addressInfoBuffer),
  2686. TDI_QUERY_INFORMATION,
  2687. Irp
  2688. );
  2689. if (!NT_SUCCESS(status)) {
  2690. IF_CNDBG(CN_DEBUG_NETOBJ) {
  2691. CNPRINT((
  2692. "[CNP] Failed to get address info, status %lx\n",
  2693. status
  2694. ));
  2695. }
  2696. goto error_exit;
  2697. }
  2698. //
  2699. // Determine if the multicast bind address is valid. If not,
  2700. // we are disabling.
  2701. //
  2702. if (CnpIsIPv4McastTransportAddress(TdiMcastBindAddress)) {
  2703. // temp vars for logging
  2704. ULONG mcastBindIp;
  2705. ULONG ifBindIp;
  2706. mcastBindIp = *((ULONG UNALIGNED *)
  2707. (&(((PTA_IP_ADDRESS)TdiMcastBindAddress)
  2708. ->Address[0].Address[0].in_addr)
  2709. )
  2710. );
  2711. ifBindIp = *((ULONG UNALIGNED *)
  2712. (&(((PTA_IP_ADDRESS)&(addressInfo->Address))
  2713. ->Address[0].Address[0].in_addr)
  2714. )
  2715. );
  2716. //
  2717. // We are trying to join a new multicast group. Fail
  2718. // immediately if there is no key.
  2719. //
  2720. if (KeyLength == 0) {
  2721. IF_CNDBG(CN_DEBUG_NETOBJ) {
  2722. CNPRINT((
  2723. "[CNP] Cannot configure new multicast group "
  2724. "without key.\n"
  2725. ));
  2726. }
  2727. status = STATUS_INVALID_PARAMETER;
  2728. goto error_exit;
  2729. }
  2730. //
  2731. // Configure basic multicast settings if not done
  2732. // previously (though this call is idempotent).
  2733. //
  2734. if (!mcastEnabled) {
  2735. status = CnpConfigureBasicMulticastSettings(
  2736. networkHandle,
  2737. networkFileObject,
  2738. networkDeviceObject,
  2739. addressInfo,
  2740. 1, // ttl
  2741. 0, // disable loopback
  2742. Irp
  2743. );
  2744. if (!NT_SUCCESS(status)) {
  2745. IF_CNDBG(CN_DEBUG_NETOBJ) {
  2746. CNPRINT((
  2747. "[CNP] Failed to configure basic "
  2748. "multicast settings, status %lx\n",
  2749. status
  2750. ));
  2751. }
  2752. goto error_exit;
  2753. }
  2754. }
  2755. //
  2756. // Add the group address if we are not already in
  2757. // this multicast group (e.g. the multicast bind
  2758. // address is the same as the current group or
  2759. // previous group).
  2760. //
  2761. if (prevGroup != NULL &&
  2762. CnpIsIPv4McastSameGroup(
  2763. prevGroup->McastTdiAddress,
  2764. TdiMcastBindAddress
  2765. )
  2766. ) {
  2767. prevGroupMatch = TRUE;
  2768. IF_CNDBG(CN_DEBUG_NETOBJ) {
  2769. CNPRINT(("[CNP] New mcast address matches "
  2770. "previous mcast address.\n"));
  2771. }
  2772. CnTrace(CNP_NET_DETAIL, CnpTraceMcastNewPrevGroupMatch,
  2773. "[CNP] New multicast group %!ipaddr! "
  2774. "for interface %!ipaddr!, network id %d, "
  2775. "matches previous group.",
  2776. mcastBindIp,
  2777. ifBindIp,
  2778. NetworkId
  2779. );
  2780. }
  2781. else if (currGroup != NULL &&
  2782. CnpIsIPv4McastSameGroup(
  2783. currGroup->McastTdiAddress,
  2784. TdiMcastBindAddress
  2785. )
  2786. ) {
  2787. IF_CNDBG(CN_DEBUG_NETOBJ) {
  2788. CNPRINT(("[CNP] New mcast address matches "
  2789. "current mcast address.\n"));
  2790. }
  2791. CnTrace(CNP_NET_DETAIL, CnpTraceMcastNewCurrGroupMatch,
  2792. "[CNP] New multicast group %!ipaddr! "
  2793. "for interface %!ipaddr!, network id %d, "
  2794. "matches current group.",
  2795. mcastBindIp,
  2796. ifBindIp,
  2797. NetworkId
  2798. );
  2799. } else {
  2800. status = CnpAddRemoveMulticastAddress(
  2801. networkHandle,
  2802. networkFileObject,
  2803. networkDeviceObject,
  2804. addressInfo,
  2805. TdiMcastBindAddress,
  2806. AO_OPTION_ADD_MCAST,
  2807. Irp
  2808. );
  2809. if (!NT_SUCCESS(status)) {
  2810. IF_CNDBG(CN_DEBUG_NETOBJ) {
  2811. CNPRINT((
  2812. "[CNP] Failed to add mcast address, "
  2813. "status %lx\n",
  2814. status
  2815. ));
  2816. }
  2817. CnTrace(CNP_NET_DETAIL, CnpTraceMcastAddGroupFailed,
  2818. "[CNP] Failed to add multicast group %!ipaddr! to "
  2819. "interface %!ipaddr! network id %d, "
  2820. "status %!status!.",
  2821. mcastBindIp,
  2822. ifBindIp,
  2823. NetworkId,
  2824. status
  2825. );
  2826. goto error_exit;
  2827. } else {
  2828. CnTrace(CNP_NET_DETAIL, CnpTraceMcastAddGroup,
  2829. "[CNP] Added multicast group %!ipaddr! to "
  2830. "interface %!ipaddr!, network id %d.",
  2831. mcastBindIp,
  2832. ifBindIp,
  2833. NetworkId
  2834. );
  2835. }
  2836. }
  2837. }
  2838. //
  2839. // Leave membership for previous group if
  2840. // - the previous group does not match the new group, AND
  2841. // - the previous group does not match the current group
  2842. //
  2843. if (!prevGroupMatch &&
  2844. prevGroup != NULL &&
  2845. CnpIsIPv4McastTransportAddress(prevGroup->McastTdiAddress)) {
  2846. // temp vars for logging
  2847. ULONG mcastBindIp;
  2848. ULONG ifBindIp;
  2849. mcastBindIp = *((ULONG UNALIGNED *)
  2850. (&(((PTA_IP_ADDRESS)prevGroup->McastTdiAddress)
  2851. ->Address[0].Address[0].in_addr)
  2852. )
  2853. );
  2854. ifBindIp = *((ULONG UNALIGNED *)
  2855. (&(((PTA_IP_ADDRESS)&(addressInfo->Address))
  2856. ->Address[0].Address[0].in_addr)
  2857. )
  2858. );
  2859. if (!CnpIsIPv4McastSameGroup(
  2860. prevGroup->McastTdiAddress,
  2861. currGroup->McastTdiAddress
  2862. )) {
  2863. status = CnpAddRemoveMulticastAddress(
  2864. networkHandle,
  2865. networkFileObject,
  2866. networkDeviceObject,
  2867. addressInfo,
  2868. prevGroup->McastTdiAddress,
  2869. AO_OPTION_DEL_MCAST,
  2870. Irp
  2871. );
  2872. if (!NT_SUCCESS(status)) {
  2873. IF_CNDBG(CN_DEBUG_NETOBJ) {
  2874. CNPRINT((
  2875. "[CNP] Failed to leave mcast group, "
  2876. "IF %d.%d.%d.%d, mcast addr %d.%d.%d.%d, "
  2877. "status %lx.\n",
  2878. CnpIpAddrPrintArgs(ifBindIp),
  2879. CnpIpAddrPrintArgs(mcastBindIp),
  2880. status
  2881. ));
  2882. }
  2883. CnTrace(CNP_NET_DETAIL, CnpTraceMcastLeaveGroupFailed,
  2884. "[CNP] Failed to leave multicast group %!ipaddr! on "
  2885. "interface %!ipaddr!, network id %d, "
  2886. "status %!status!. Continuing anyway.",
  2887. mcastBindIp,
  2888. ifBindIp,
  2889. NetworkId,
  2890. status
  2891. );
  2892. // not considered a fatal error
  2893. status = STATUS_SUCCESS;
  2894. } else {
  2895. CnTrace(CNP_NET_DETAIL, CnpTraceMcastLeaveGroup,
  2896. "[CNP] Left multicast group %!ipaddr! on "
  2897. "interface %!ipaddr!, network id %d.",
  2898. mcastBindIp,
  2899. ifBindIp,
  2900. NetworkId
  2901. );
  2902. }
  2903. } else {
  2904. IF_CNDBG(CN_DEBUG_NETOBJ) {
  2905. CNPRINT(("[CNP] Prev mcast address matches "
  2906. "current mcast address.\n"));
  2907. }
  2908. CnTrace(CNP_NET_DETAIL, CnpTraceMcastCurrPrevGroupMatch,
  2909. "[CNP] Previous multicast group %!ipaddr! "
  2910. "on interface %!ipaddr!, network id %d, "
  2911. "matches current group. Not leaving.",
  2912. mcastBindIp,
  2913. ifBindIp,
  2914. NetworkId
  2915. );
  2916. }
  2917. }
  2918. //
  2919. // Reacquire the network lock to make changes
  2920. // to the network object data structure, including
  2921. // shifting the multicast group data structures and
  2922. // turning on the multicast flag. The multicast flag
  2923. // was turned off earlier in this routine before
  2924. // starting the transition. It is only re-enabled if
  2925. // the new multicast bind address is a valid multicast
  2926. // address.
  2927. //
  2928. CnAcquireLock(&(network->Lock), &(network->Irql));
  2929. networkLocked = TRUE;
  2930. delGroup = network->PreviousMcastGroup;
  2931. network->PreviousMcastGroup = network->CurrentMcastGroup;
  2932. network->CurrentMcastGroup = group;
  2933. group = NULL;
  2934. if (CnpIsIPv4McastTransportAddress(TdiMcastBindAddress)) {
  2935. network->Flags |= CNP_NET_FLAG_MULTICAST;
  2936. }
  2937. CnReleaseLock(&(network->Lock), network->Irql);
  2938. networkLocked = FALSE;
  2939. //
  2940. // Transition into new multicast group, if appropriate.
  2941. //
  2942. if (CnpIsIPv4McastTransportAddress(TdiMcastBindAddress)) {
  2943. //
  2944. // Switch all outgoing heartbeats on this node to
  2945. // unicast with discovery.
  2946. //
  2947. CnpWalkInterfacesOnNetwork(
  2948. network,
  2949. CnpStartInterfaceMcastTransition
  2950. );
  2951. }
  2952. error_exit:
  2953. if (networkLocked) {
  2954. CnReleaseLock(&(network->Lock), network->Irql);
  2955. networkLocked = FALSE;
  2956. }
  2957. //
  2958. // Reposition the network according to multicast reachability.
  2959. //
  2960. CnpSortMulticastNetwork(network, TRUE, NULL);
  2961. CnAcquireLock(&(network->Lock), &(network->Irql));
  2962. CnpActiveDereferenceNetwork(network);
  2963. if (group != NULL) {
  2964. CnpDereferenceMulticastGroup(group);
  2965. }
  2966. if (currGroup != NULL) {
  2967. CnpDereferenceMulticastGroup(currGroup);
  2968. }
  2969. if (prevGroup != NULL) {
  2970. CnpDereferenceMulticastGroup(prevGroup);
  2971. }
  2972. if (delGroup != NULL) {
  2973. CnpDereferenceMulticastGroup(delGroup);
  2974. }
  2975. return(status);
  2976. } // CxConfigureMulticast
  2977. BOOLEAN
  2978. CnpSortMulticastNetwork(
  2979. IN PCNP_NETWORK Network,
  2980. IN BOOLEAN RaiseEvent,
  2981. OUT CX_CLUSTERSCREEN * McastReachableNodes OPTIONAL
  2982. )
  2983. /*++
  2984. Routine Description:
  2985. Wrapper for CnpSortMulticastNetworkLocked.
  2986. Return value:
  2987. TRUE if reachable node set changed
  2988. Notes:
  2989. Acquires and releases CnpNetworkListLock.
  2990. --*/
  2991. {
  2992. KIRQL irql;
  2993. BOOLEAN setChanged = FALSE;
  2994. CnVerifyCpuLockMask(
  2995. 0, // required
  2996. CNP_NETWORK_LIST_LOCK, // forbidden
  2997. CNP_NODE_OBJECT_LOCK_MAX // max
  2998. );
  2999. CnAcquireLock(&CnpNetworkListLock, &irql);
  3000. setChanged = CnpSortMulticastNetworkLocked(
  3001. Network,
  3002. RaiseEvent,
  3003. McastReachableNodes
  3004. );
  3005. CnReleaseLock(&CnpNetworkListLock, irql);
  3006. CnVerifyCpuLockMask(
  3007. 0, // required
  3008. CNP_NETWORK_LIST_LOCK, // forbidden
  3009. CNP_NODE_OBJECT_LOCK_MAX // max
  3010. );
  3011. return(setChanged);
  3012. } // CnpSortMulticastNetwork
  3013. BOOLEAN
  3014. CnpMulticastChangeNodeReachability(
  3015. IN PCNP_NETWORK Network,
  3016. IN PCNP_NODE Node,
  3017. IN BOOLEAN Reachable,
  3018. IN BOOLEAN RaiseEvent,
  3019. OUT CX_CLUSTERSCREEN * NewMcastReachableNodes
  3020. )
  3021. /*++
  3022. Routine Description:
  3023. Changes the multicast reachability state of Node
  3024. on Network.
  3025. If the set of reachable nodes changes, returns
  3026. the new screen through NewMcastReachableNodes.
  3027. Return value:
  3028. TRUE if set of reachable nodes changes.
  3029. Notes:
  3030. Called and returns with node lock held.
  3031. --*/
  3032. {
  3033. KIRQL irql;
  3034. BOOLEAN setChanged = FALSE;
  3035. CnVerifyCpuLockMask(
  3036. CNP_NODE_OBJECT_LOCK, // required
  3037. CNP_NETWORK_LIST_LOCK, // forbidden
  3038. CNP_NODE_OBJECT_LOCK_MAX // max
  3039. );
  3040. CnAcquireLock(&CnpNetworkListLock, &irql);
  3041. setChanged = CnpMulticastChangeNodeReachabilityLocked(
  3042. Network,
  3043. Node,
  3044. Reachable,
  3045. RaiseEvent,
  3046. NewMcastReachableNodes
  3047. );
  3048. CnReleaseLock(&CnpNetworkListLock, irql);
  3049. CnVerifyCpuLockMask(
  3050. CNP_NODE_OBJECT_LOCK, // required
  3051. CNP_NETWORK_LIST_LOCK, // forbidden
  3052. CNP_NODE_OBJECT_LOCK_MAX // max
  3053. );
  3054. return(setChanged);
  3055. } // CnpMulticastChangeNodeReachability
  3056. PCNP_NETWORK
  3057. CnpGetBestMulticastNetwork(
  3058. VOID
  3059. )
  3060. /*++
  3061. Routine Description:
  3062. Returns network object that currently has best
  3063. node reachability.
  3064. Return value:
  3065. Best network object, or NULL if there are no
  3066. internal multicast networks.
  3067. Notes:
  3068. Must not be called with network list lock held.
  3069. Returns with network locked (if found).
  3070. --*/
  3071. {
  3072. PCNP_NETWORK network = NULL;
  3073. KIRQL listIrql;
  3074. KIRQL networkIrql;
  3075. CnVerifyCpuLockMask(
  3076. 0, // required
  3077. (CNP_NETWORK_LIST_LOCK | CNP_NETWORK_OBJECT_LOCK), // forbidden
  3078. CNP_NODE_OBJECT_LOCK_MAX // max
  3079. );
  3080. CnAcquireLock(&CnpNetworkListLock, &listIrql);
  3081. if (!IsListEmpty(&CnpNetworkList)) {
  3082. network = CONTAINING_RECORD(
  3083. CnpNetworkList.Flink,
  3084. CNP_NETWORK,
  3085. Linkage
  3086. );
  3087. CnAcquireLock(&(network->Lock), &networkIrql);
  3088. if (CnpIsInternalMulticastNetwork(network)) {
  3089. CnReleaseLock(&CnpNetworkListLock, networkIrql);
  3090. network->Irql = listIrql;
  3091. CnVerifyCpuLockMask(
  3092. CNP_NETWORK_OBJECT_LOCK, // required
  3093. CNP_NETWORK_LIST_LOCK, // forbidden
  3094. CNP_NETWORK_OBJECT_LOCK_MAX // max
  3095. );
  3096. } else {
  3097. CnReleaseLock(&(network->Lock), networkIrql);
  3098. network = NULL;
  3099. }
  3100. }
  3101. if (network == NULL) {
  3102. CnReleaseLock(&CnpNetworkListLock, listIrql);
  3103. CnVerifyCpuLockMask(
  3104. 0, // required
  3105. (CNP_NETWORK_LIST_LOCK | CNP_NETWORK_OBJECT_LOCK), // forbidden
  3106. CNP_NODE_OBJECT_LOCK_MAX // max
  3107. );
  3108. }
  3109. return(network);
  3110. } // CnpGetBestMulticastNetwork
  3111. NTSTATUS
  3112. CxGetMulticastReachableSet(
  3113. IN CL_NETWORK_ID NetworkId,
  3114. OUT ULONG * NodeScreen
  3115. )
  3116. /*++
  3117. Routine Description:
  3118. Queries multicast reachable set for specified network.
  3119. The multicast reachable set is protected by the network
  3120. list lock.
  3121. --*/
  3122. {
  3123. KIRQL irql;
  3124. PLIST_ENTRY entry;
  3125. PCNP_NETWORK network;
  3126. CX_CLUSTERSCREEN nodeScreen;
  3127. BOOLEAN found = FALSE;
  3128. CnVerifyCpuLockMask(
  3129. 0, // required
  3130. CNP_NETWORK_LIST_LOCK, // forbidden
  3131. CNP_NODE_OBJECT_LOCK_MAX // max
  3132. );
  3133. CnAcquireLock(&CnpNetworkListLock, &irql);
  3134. for (entry = CnpNetworkList.Flink;
  3135. entry != &CnpNetworkList && !found;
  3136. entry = entry->Flink
  3137. )
  3138. {
  3139. network = CONTAINING_RECORD(entry, CNP_NETWORK, Linkage);
  3140. CnAcquireLockAtDpc(&(network->Lock));
  3141. if (NetworkId == network->Id) {
  3142. nodeScreen = network->McastReachableNodes;
  3143. found = TRUE;
  3144. }
  3145. CnReleaseLockFromDpc(&(network->Lock));
  3146. }
  3147. CnReleaseLock(&CnpNetworkListLock, irql);
  3148. if (!found) {
  3149. return(STATUS_CLUSTER_NETWORK_NOT_FOUND);
  3150. } else {
  3151. *NodeScreen = nodeScreen.UlongScreen;
  3152. return(STATUS_SUCCESS);
  3153. }
  3154. } // CxGetMulticastReachableSet