Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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