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.

2098 lines
52 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. cnpif.c
  5. Abstract:
  6. Interface management routines for the Cluster Network Protocol.
  7. Author:
  8. Mike Massa (mikemas) January 6, 1997
  9. Revision History:
  10. Who When What
  11. -------- -------- ----------------------------------------------
  12. mikemas 01-06-97 created
  13. Notes:
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. #include "cnpif.tmh"
  18. #include <ntddndis.h>
  19. //
  20. // Routines exported within CNP
  21. //
  22. BOOLEAN
  23. CnpIsBetterInterface(
  24. PCNP_INTERFACE Interface1,
  25. PCNP_INTERFACE Interface2
  26. )
  27. {
  28. if ( (Interface2 == NULL)
  29. ||
  30. (Interface1->State > Interface2->State)
  31. ||
  32. ( (Interface1->State == Interface2->State)
  33. &&
  34. CnpIsHigherPriority(Interface1->Priority, Interface2->Priority)
  35. )
  36. )
  37. {
  38. return(TRUE);
  39. }
  40. return(FALSE);
  41. }
  42. VOID
  43. CnpWalkInterfacesOnNode(
  44. PCNP_NODE Node,
  45. PCNP_INTERFACE_UPDATE_ROUTINE UpdateRoutine
  46. )
  47. /*++
  48. Routine Description:
  49. Walks the interface list of a node and performs a specified
  50. operation on each interface.
  51. Arguments:
  52. Node - The node on which to operate.
  53. UpdateRoutine - The operation to perform on each interface.
  54. Return Value:
  55. None.
  56. Notes:
  57. Called with node object lock held.
  58. Valid Update Routines:
  59. CnpOnlinePendingInterfaceWrapper
  60. CnpOfflineInterfaceWrapper
  61. --*/
  62. {
  63. PLIST_ENTRY entry, nextEntry;
  64. PCNP_INTERFACE interface;
  65. CnVerifyCpuLockMask(
  66. CNP_NODE_OBJECT_LOCK, // Required
  67. 0, // Forbidden
  68. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  69. );
  70. entry = Node->InterfaceList.Flink;
  71. while (entry != &(Node->InterfaceList)) {
  72. //
  73. // Save a pointer to the next entry now in case we delete the
  74. // current entry.
  75. //
  76. nextEntry = entry->Flink;
  77. interface = CONTAINING_RECORD(
  78. entry,
  79. CNP_INTERFACE,
  80. NodeLinkage
  81. );
  82. CnAcquireLockAtDpc(&(interface->Network->Lock));
  83. interface->Network->Irql = DISPATCH_LEVEL;
  84. (*UpdateRoutine)(interface);
  85. //
  86. // The network object lock was released.
  87. //
  88. entry = nextEntry;
  89. }
  90. CnVerifyCpuLockMask(
  91. CNP_NODE_OBJECT_LOCK, // Required
  92. 0, // Forbidden
  93. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  94. );
  95. return;
  96. } // CnpWalkInterfacesOnNode
  97. VOID
  98. CnpWalkInterfacesOnNetwork(
  99. PCNP_NETWORK Network,
  100. PCNP_INTERFACE_UPDATE_ROUTINE UpdateRoutine
  101. )
  102. /*++
  103. Routine Description:
  104. Walks the node table and the interface list of each node looking
  105. for interfaces on a specified network. Performs a specified operation
  106. on each matching interface.
  107. Arguments:
  108. Network - The target network.
  109. UpdateRoutine - The operation to perform on each matching interface.
  110. Return Value:
  111. None.
  112. Notes:
  113. Called with no locks held.
  114. Valid Update Routines:
  115. CnpOnlinePendingInterfaceWrapper
  116. CnpOfflineInterfaceWrapper
  117. CnpDeleteInterface
  118. CnpRecalculateInterfacePriority
  119. --*/
  120. {
  121. ULONG i;
  122. CN_IRQL tableIrql;
  123. PCNP_NODE node;
  124. PLIST_ENTRY entry;
  125. PCNP_INTERFACE interface;
  126. CnVerifyCpuLockMask(
  127. 0, // Required
  128. CNP_LOCK_RANGE, // Forbidden
  129. CNP_PRECEEDING_LOCK_RANGE // Maximum
  130. );
  131. CnAcquireLock(&CnpNodeTableLock, &tableIrql);
  132. CnAssert(CnMinValidNodeId != ClusterInvalidNodeId);
  133. CnAssert(CnMaxValidNodeId != ClusterInvalidNodeId);
  134. for (i=CnMinValidNodeId; i <= CnMaxValidNodeId; i++) {
  135. node = CnpNodeTable[i];
  136. if (node != NULL) {
  137. CnAcquireLockAtDpc(&(node->Lock));
  138. CnReleaseLockFromDpc(&CnpNodeTableLock);
  139. node->Irql = tableIrql;
  140. for (entry = node->InterfaceList.Flink;
  141. entry != &(node->InterfaceList);
  142. entry = entry->Flink
  143. )
  144. {
  145. interface = CONTAINING_RECORD(
  146. entry,
  147. CNP_INTERFACE,
  148. NodeLinkage
  149. );
  150. if (interface->Network == Network) {
  151. CnAcquireLockAtDpc(&(Network->Lock));
  152. Network->Irql = DISPATCH_LEVEL;
  153. (*UpdateRoutine)(interface);
  154. //
  155. // The network object lock was released.
  156. // The node object lock is still held.
  157. //
  158. break;
  159. }
  160. }
  161. CnReleaseLock(&(node->Lock), node->Irql);
  162. CnAcquireLock(&CnpNodeTableLock, &tableIrql);
  163. }
  164. }
  165. CnReleaseLock(&CnpNodeTableLock, tableIrql);
  166. CnVerifyCpuLockMask(
  167. 0, // Required
  168. CNP_LOCK_RANGE, // Forbidden
  169. CNP_PRECEEDING_LOCK_RANGE // Maximum
  170. );
  171. return;
  172. } // CnpWalkInterfacesOnNetwork
  173. NTSTATUS
  174. CnpOnlinePendingInterface(
  175. PCNP_INTERFACE Interface
  176. )
  177. /*++
  178. Routine Description:
  179. Changes an Offline interface to the OnlinePending state.
  180. This will enable heartbeats over this interface. When a heartbeat
  181. is established, the interface will move to the Online state.
  182. Arguments:
  183. Interface - A pointer to the interface to change.
  184. Return Value:
  185. An NT status value.
  186. Notes:
  187. Called with associated node and network locks held.
  188. Returns with network lock released.
  189. Conforms to calling convention for PCNP_INTERFACE_UPDATE_ROUTINE.
  190. --*/
  191. {
  192. NTSTATUS status = STATUS_SUCCESS;
  193. PCNP_NODE node = Interface->Node;
  194. PCNP_NETWORK network = Interface->Network;
  195. CnVerifyCpuLockMask(
  196. (CNP_NODE_OBJECT_LOCK | CNP_NETWORK_OBJECT_LOCK), // Required
  197. 0, // Forbidden
  198. CNP_NETWORK_OBJECT_LOCK_MAX // Maximum
  199. );
  200. if ( (Interface->State == ClusnetInterfaceStateOffline) &&
  201. (network->State == ClusnetNetworkStateOnline)
  202. )
  203. {
  204. IF_CNDBG( CN_DEBUG_IFOBJ )
  205. CNPRINT((
  206. "[CNP] Moving interface (%u, %u) to OnlinePending state.\n",
  207. node->Id,
  208. network->Id
  209. ));
  210. Interface->State = ClusnetInterfaceStateOnlinePending;
  211. Interface->MissedHBs = 0;
  212. //
  213. // Send multicast discovery packets.
  214. //
  215. if (Interface->Node != CnpLocalNode
  216. && CnpIsNetworkMulticastCapable(network)) {
  217. Interface->McastDiscoverCount = CNP_INTERFACE_MCAST_DISCOVERY;
  218. }
  219. //
  220. // Place an active reference on the associated network.
  221. //
  222. CnpActiveReferenceNetwork(network);
  223. //
  224. // Update the node's CurrentInterface if appropriate.
  225. //
  226. if ( !CnpIsNetworkRestricted(network) &&
  227. CnpIsBetterInterface(Interface, node->CurrentInterface)
  228. )
  229. {
  230. node->CurrentInterface = Interface;
  231. IF_CNDBG( CN_DEBUG_IFOBJ )
  232. CNPRINT((
  233. "[CNP] Network %u is now the best route to node %u\n",
  234. network->Id,
  235. node->Id
  236. ));
  237. }
  238. }
  239. else {
  240. status = STATUS_CLUSTER_INVALID_REQUEST;
  241. }
  242. CnReleaseLockFromDpc(&(network->Lock));
  243. CnVerifyCpuLockMask(
  244. (CNP_NODE_OBJECT_LOCK), // Required
  245. 0, // Forbidden
  246. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  247. );
  248. return(status);
  249. } // CnpOnlinePendingInterface
  250. VOID
  251. CnpOnlinePendingInterfaceWrapper(
  252. PCNP_INTERFACE Interface
  253. )
  254. /*++
  255. Routine Description:
  256. Wrapper for CnpOnlinePendingInterface that conforms to the calling
  257. convention for PCNP_INTERFACE_UPDATE_ROUTINE.
  258. Arguments:
  259. Interface - A pointer to the interface to change.
  260. Return Value:
  261. None.
  262. Notes:
  263. Called with associated node and network locks held.
  264. Returns with network lock released.
  265. --*/
  266. {
  267. (VOID) CnpOnlinePendingInterface(Interface);
  268. return;
  269. } // CnpOnlinePendingInterfaceWrapper
  270. NTSTATUS
  271. CnpOfflineInterface(
  272. PCNP_INTERFACE Interface
  273. )
  274. /*++
  275. Routine Description:
  276. Called to change an interface to the Offline state
  277. when the associated network goes offline or the interface
  278. is being deleted.
  279. Arguments:
  280. Interface - A pointer to the interface to change.
  281. Return Value:
  282. An NT status value.
  283. Notes:
  284. Called with associated node and network locks held.
  285. Returns with network lock released.
  286. Conforms to calling convention for PCNP_INTERFACE_UPDATE_ROUTINE.
  287. --*/
  288. {
  289. NTSTATUS status = STATUS_SUCCESS;
  290. PCNP_NODE node = Interface->Node;
  291. PCNP_NETWORK network = Interface->Network;
  292. CnVerifyCpuLockMask(
  293. (CNP_NODE_OBJECT_LOCK | CNP_NETWORK_OBJECT_LOCK), // Required
  294. 0, // Forbidden
  295. CNP_NETWORK_OBJECT_LOCK_MAX // Maximum
  296. );
  297. if (Interface->State != ClusnetInterfaceStateOffline) {
  298. IF_CNDBG( CN_DEBUG_IFOBJ )
  299. CNPRINT((
  300. "[CNP] Moving interface (%u, %u) to Offline state.\n",
  301. node->Id,
  302. network->Id
  303. ));
  304. Interface->State = ClusnetInterfaceStateOffline;
  305. //
  306. // Release the network lock.
  307. //
  308. CnReleaseLock(&(network->Lock), network->Irql);
  309. //
  310. // Update the node's CurrentInterface value if appropriate.
  311. //
  312. if (node->CurrentInterface == Interface) {
  313. CnpUpdateNodeCurrentInterface(node);
  314. if ( !CnpIsNodeUnreachable(node)
  315. &&
  316. ( (node->CurrentInterface == NULL) ||
  317. ( node->CurrentInterface->State <
  318. ClusnetInterfaceStateOnlinePending
  319. )
  320. )
  321. )
  322. {
  323. //
  324. // This node is now unreachable.
  325. //
  326. CnpDeclareNodeUnreachable(node);
  327. }
  328. }
  329. //
  330. // Change the node's reachability status via this network.
  331. //
  332. CnpMulticastChangeNodeReachability(
  333. network,
  334. node,
  335. FALSE, // not reachable
  336. TRUE, // raise event
  337. NULL // OUT new mask
  338. );
  339. //
  340. // Remove the active reference on the associated network.
  341. // This releases the network lock.
  342. //
  343. CnAcquireLock(&(network->Lock), &(network->Irql));
  344. CnpActiveDereferenceNetwork(network);
  345. }
  346. else {
  347. CnAssert(network->Irql == DISPATCH_LEVEL);
  348. CnReleaseLockFromDpc(&(network->Lock));
  349. status = STATUS_CLUSTER_INVALID_REQUEST;
  350. }
  351. CnVerifyCpuLockMask(
  352. (CNP_NODE_OBJECT_LOCK), // Required
  353. 0, // Forbidden
  354. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  355. );
  356. return(status);
  357. } // CnpOfflineInterface
  358. VOID
  359. CnpOfflineInterfaceWrapper(
  360. PCNP_INTERFACE Interface
  361. )
  362. /*++
  363. Routine Description:
  364. Wrapper for CnpOfflineInterface that conforms to the calling
  365. convention for PCNP_INTERFACE_UPDATE_ROUTINE.
  366. Arguments:
  367. Interface - A pointer to the interface to change.
  368. Return Value:
  369. None.
  370. Notes:
  371. Called with associated node and network locks held.
  372. Returns with network lock released.
  373. --*/
  374. {
  375. (VOID) CnpOfflineInterface(Interface);
  376. return;
  377. } // CnpOfflineInterfaceWrapper
  378. NTSTATUS
  379. CnpOnlineInterface(
  380. PCNP_INTERFACE Interface
  381. )
  382. /*++
  383. Routine Description:
  384. Called to change an OnlinePending interface to the Online state
  385. after a heartbeat has been (re)established.
  386. Arguments:
  387. Interface - A pointer to the interface to change.
  388. Return Value:
  389. None.
  390. Notes:
  391. Called with associated node and network locks held.
  392. Returns with network lock released.
  393. --*/
  394. {
  395. NTSTATUS status = STATUS_SUCCESS;
  396. PCNP_NODE node = Interface->Node;
  397. PCNP_NETWORK network = Interface->Network;
  398. CnVerifyCpuLockMask(
  399. (CNP_NODE_OBJECT_LOCK | CNP_NETWORK_OBJECT_LOCK), // Required
  400. 0, // Forbidden
  401. CNP_NETWORK_OBJECT_LOCK_MAX // Maximum
  402. );
  403. if ( (network->State == ClusnetNetworkStateOnline) &&
  404. ( (Interface->State == ClusnetInterfaceStateOnlinePending) ||
  405. (Interface->State == ClusnetInterfaceStateUnreachable)
  406. )
  407. )
  408. {
  409. IF_CNDBG( CN_DEBUG_IFOBJ )
  410. CNPRINT((
  411. "[CNP] Moving interface (%u, %u) to Online state.\n",
  412. node->Id,
  413. network->Id
  414. ));
  415. //
  416. // Move the interface to the online state.
  417. //
  418. Interface->State = ClusnetInterfaceStateOnline;
  419. CnAssert(network->Irql == DISPATCH_LEVEL);
  420. CnReleaseLockFromDpc(&(network->Lock));
  421. //
  422. // Update the node's CurrentInterface if appropriate.
  423. //
  424. if (!CnpIsNetworkRestricted(network)) {
  425. if (CnpIsBetterInterface(Interface, node->CurrentInterface)) {
  426. node->CurrentInterface = Interface;
  427. IF_CNDBG( CN_DEBUG_IFOBJ )
  428. CNPRINT((
  429. "[CNP] Network %u is now the best route to node %u\n",
  430. network->Id,
  431. node->Id
  432. ));
  433. }
  434. if (CnpIsNodeUnreachable(node)) {
  435. CnpDeclareNodeReachable(node);
  436. }
  437. }
  438. }
  439. else {
  440. CnAssert(network->Irql == DISPATCH_LEVEL);
  441. CnReleaseLockFromDpc(&(network->Lock));
  442. status = STATUS_CLUSTER_INVALID_REQUEST;
  443. }
  444. CnVerifyCpuLockMask(
  445. (CNP_NODE_OBJECT_LOCK), // Required
  446. 0, // Forbidden
  447. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  448. );
  449. return(status);
  450. } // CnpOnlineInterface
  451. NTSTATUS
  452. CnpFailInterface(
  453. PCNP_INTERFACE Interface
  454. )
  455. /*++
  456. Routine Description:
  457. Called to change an Online or OnlinePending interface to the Failed
  458. state after the heartbeat has been lost for some time.
  459. Arguments:
  460. Interface - A pointer to the interface to change.
  461. Return Value:
  462. None.
  463. Notes:
  464. Called with associated node and network locks held.
  465. Returns with network lock released.
  466. --*/
  467. {
  468. NTSTATUS status = STATUS_SUCCESS;
  469. PCNP_NODE node = Interface->Node;
  470. PCNP_NETWORK network = Interface->Network;
  471. CnVerifyCpuLockMask(
  472. (CNP_NODE_OBJECT_LOCK | CNP_NETWORK_OBJECT_LOCK), // Required
  473. 0, // Forbidden
  474. CNP_NETWORK_OBJECT_LOCK_MAX // Maximum
  475. );
  476. if ( (network->State == ClusnetNetworkStateOnline) &&
  477. (Interface->State >= ClusnetInterfaceStateOnlinePending)
  478. )
  479. {
  480. IF_CNDBG( CN_DEBUG_IFOBJ )
  481. CNPRINT((
  482. "[CNP] Moving interface (%u, %u) to Failed state.\n",
  483. node->Id,
  484. network->Id
  485. ));
  486. Interface->State = ClusnetInterfaceStateUnreachable;
  487. CnAssert(network->Irql == DISPATCH_LEVEL);
  488. //
  489. // Reference the network so that it can't be deleted
  490. // while we release the lock.
  491. //
  492. CnpReferenceNetwork(network);
  493. CnReleaseLockFromDpc(&(network->Lock));
  494. //
  495. // Update the node's CurrentInterface value if appropriate.
  496. //
  497. if (node->CurrentInterface == Interface) {
  498. CnpUpdateNodeCurrentInterface(node);
  499. if ( (node->CurrentInterface == NULL)
  500. ||
  501. ( node->CurrentInterface->State <
  502. ClusnetInterfaceStateOnlinePending
  503. )
  504. )
  505. {
  506. //
  507. // This node is now unreachable.
  508. //
  509. CnpDeclareNodeUnreachable(node);
  510. }
  511. }
  512. //
  513. // Change the node's reachability status via this network.
  514. //
  515. CnpMulticastChangeNodeReachability(
  516. network,
  517. node,
  518. FALSE, // not reachable
  519. TRUE, // raise event
  520. NULL // OUT new mask
  521. );
  522. //
  523. // Drop the network reference. This releases the network
  524. // lock.
  525. //
  526. CnAcquireLock(&(network->Lock), &(network->Irql));
  527. CnpDereferenceNetwork(network);
  528. }
  529. else {
  530. CnAssert(network->Irql == DISPATCH_LEVEL);
  531. CnReleaseLockFromDpc(&(network->Lock));
  532. status = STATUS_CLUSTER_INVALID_REQUEST;
  533. }
  534. CnVerifyCpuLockMask(
  535. (CNP_NODE_OBJECT_LOCK), // Required
  536. 0, // Forbidden
  537. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  538. );
  539. return(status);
  540. } // CnpFailInterface
  541. VOID
  542. CnpDeleteInterface(
  543. IN PCNP_INTERFACE Interface
  544. )
  545. /*++
  546. /*++
  547. Routine Description:
  548. Called to delete an interface.
  549. Arguments:
  550. Interface - A pointer to the interface to delete.
  551. Return Value:
  552. None.
  553. Notes:
  554. Called with node and network object locks held.
  555. Returns with the network lock released.
  556. Conforms to calling convention for PCNP_INTERFACE_UPDATE_ROUTINE.
  557. --*/
  558. {
  559. CL_NODE_ID nodeId = Interface->Node->Id;
  560. CL_NETWORK_ID networkId = Interface->Network->Id;
  561. PCNP_NODE node = Interface->Node;
  562. PCNP_NETWORK network = Interface->Network;
  563. BOOLEAN isLocal = FALSE;
  564. CnVerifyCpuLockMask(
  565. (CNP_NODE_OBJECT_LOCK | CNP_NETWORK_OBJECT_LOCK), // Required
  566. 0, // Forbidden
  567. CNP_NETWORK_OBJECT_LOCK_MAX // Maximum
  568. );
  569. IF_CNDBG( CN_DEBUG_IFOBJ )
  570. CNPRINT((
  571. "[CNP] Deleting interface (%u, %u)\n",
  572. nodeId,
  573. networkId
  574. ));
  575. if (Interface->State >= ClusnetInterfaceStateUnreachable) {
  576. (VOID) CnpOfflineInterface(Interface);
  577. //
  578. // The call released the network lock.
  579. // Reacquire it.
  580. //
  581. CnAcquireLockAtDpc(&(network->Lock));
  582. network->Irql = DISPATCH_LEVEL;
  583. }
  584. //
  585. // Remove the interface from the node's interface list.
  586. //
  587. #if DBG
  588. {
  589. PLIST_ENTRY entry;
  590. PCNP_INTERFACE oldInterface = NULL;
  591. for (entry = node->InterfaceList.Flink;
  592. entry != &(node->InterfaceList);
  593. entry = entry->Flink
  594. )
  595. {
  596. oldInterface = CONTAINING_RECORD(
  597. entry,
  598. CNP_INTERFACE,
  599. NodeLinkage
  600. );
  601. if (oldInterface == Interface) {
  602. break;
  603. }
  604. }
  605. CnAssert(oldInterface == Interface);
  606. }
  607. #endif // DBG
  608. RemoveEntryList(&(Interface->NodeLinkage));
  609. //
  610. // Remove the base reference that this node had on the network.
  611. // This releases the network lock.
  612. //
  613. CnpDereferenceNetwork(network);
  614. //
  615. // Update the node's CurrentInterface if appropriate.
  616. //
  617. if (node->CurrentInterface == Interface) {
  618. if (IsListEmpty(&(node->InterfaceList))) {
  619. node->CurrentInterface = NULL;
  620. }
  621. else {
  622. CnpUpdateNodeCurrentInterface(node);
  623. }
  624. }
  625. CnFreePool(Interface);
  626. IF_CNDBG( CN_DEBUG_IFOBJ )
  627. CNPRINT((
  628. "[CNP] Deleted interface (%u, %u)\n",
  629. nodeId,
  630. networkId
  631. ));
  632. CnVerifyCpuLockMask(
  633. (CNP_NODE_OBJECT_LOCK), // Required
  634. 0, // Forbidden
  635. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  636. );
  637. return;
  638. } // CnpDeleteInterface
  639. VOID
  640. CnpReevaluateInterfaceRole(
  641. IN PCNP_INTERFACE Interface
  642. )
  643. /*++
  644. Routine Description:
  645. Reevaluates the role of an interface after the corresponding network's
  646. restriction state has been changed.
  647. Arguments:
  648. Interface - A pointer to the interface on which to operate.
  649. Return Value:
  650. None.
  651. Notes:
  652. Called with associated node and network locks held.
  653. Returns with network lock released.
  654. Conforms to calling convention for PCNP_INTERFACE_UPDATE_ROUTINE.
  655. --*/
  656. {
  657. PCNP_NODE node = Interface->Node;
  658. PCNP_NETWORK network = Interface->Network;
  659. BOOLEAN restricted = CnpIsNetworkRestricted(network);
  660. CnVerifyCpuLockMask(
  661. (CNP_NODE_OBJECT_LOCK | CNP_NETWORK_OBJECT_LOCK), // Required
  662. 0, // Forbidden
  663. CNP_NETWORK_OBJECT_LOCK_MAX // Maximum
  664. );
  665. //
  666. // We don't really need the network lock. It's just part of
  667. // the calling convention.
  668. //
  669. CnReleaseLockFromDpc(&(network->Lock));
  670. if (restricted) {
  671. if (node->CurrentInterface == Interface) {
  672. CnpUpdateNodeCurrentInterface(node);
  673. }
  674. }
  675. else if (node->CurrentInterface != Interface) {
  676. CnpUpdateNodeCurrentInterface(node);
  677. }
  678. CnVerifyCpuLockMask(
  679. (CNP_NODE_OBJECT_LOCK), // Required
  680. 0, // Forbidden
  681. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  682. );
  683. return;
  684. } // CnpReevaluateInterfaceRole
  685. VOID
  686. CnpRecalculateInterfacePriority(
  687. IN PCNP_INTERFACE Interface
  688. )
  689. /*++
  690. Routine Description:
  691. Recalculates the priority of interfaces which get their
  692. priority from their associated network. Called after the network's
  693. priority changes.
  694. Arguments:
  695. Interface - A pointer to the interface on which to operate.
  696. Return Value:
  697. None.
  698. Notes:
  699. Called with associated node and network locks held.
  700. Returns with network lock released.
  701. Conforms to calling convention for PCNP_INTERFACE_UPDATE_ROUTINE.
  702. --*/
  703. {
  704. PCNP_NODE node = Interface->Node;
  705. PCNP_NETWORK network = Interface->Network;
  706. ULONG networkPriority = network->Priority;
  707. ULONG oldPriority = Interface->Priority;
  708. BOOLEAN restricted = CnpIsNetworkRestricted(network);
  709. CnVerifyCpuLockMask(
  710. (CNP_NODE_OBJECT_LOCK | CNP_NETWORK_OBJECT_LOCK), // Required
  711. 0, // Forbidden
  712. CNP_NETWORK_OBJECT_LOCK_MAX // Maximum
  713. );
  714. //
  715. // We don't really need the network lock. It's just part of
  716. // the calling convention.
  717. //
  718. CnReleaseLockFromDpc(&(network->Lock));
  719. if (CnpIsInterfaceUsingNetworkPriority(Interface)) {
  720. Interface->Priority = networkPriority;
  721. if (!restricted) {
  722. if (Interface == node->CurrentInterface) {
  723. if (CnpIsLowerPriority(Interface->Priority, oldPriority)) {
  724. //
  725. // Our priority got worse. Recalculate the best route.
  726. //
  727. CnpUpdateNodeCurrentInterface(node);
  728. }
  729. //
  730. // Else, priority same or better. Nothing to do.
  731. //
  732. }
  733. else if ( CnpIsBetterInterface(
  734. Interface,
  735. node->CurrentInterface
  736. )
  737. )
  738. {
  739. //
  740. // Our priority got better.
  741. //
  742. IF_CNDBG(( CN_DEBUG_NODEOBJ | CN_DEBUG_NETOBJ ))
  743. CNPRINT((
  744. "[CNP] Network %u is now the best route to node %u\n",
  745. network->Id,
  746. node->Id
  747. ));
  748. node->CurrentInterface = Interface;
  749. }
  750. }
  751. }
  752. CnVerifyCpuLockMask(
  753. (CNP_NODE_OBJECT_LOCK), // Required
  754. 0, // Forbidden
  755. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  756. );
  757. return;
  758. } // CnpRecalculateInterfacePriority
  759. VOID
  760. CnpUpdateNodeCurrentInterface(
  761. IN PCNP_NODE Node
  762. )
  763. /*++
  764. Routine Description:
  765. Called to determine the best available interface for a node
  766. after one of its interfaces changes state or priority.
  767. Arguments:
  768. Node - A pointer to the node on which to operate.
  769. Return Value:
  770. None.
  771. Notes:
  772. Called with node object lock held.
  773. --*/
  774. {
  775. PLIST_ENTRY entry;
  776. PCNP_INTERFACE interface;
  777. PCNP_INTERFACE bestInterface = NULL;
  778. CnVerifyCpuLockMask(
  779. CNP_NODE_OBJECT_LOCK, // Required
  780. 0, // Forbidden
  781. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  782. );
  783. CnAssert(!IsListEmpty(&(Node->InterfaceList)));
  784. // CnAssert(Node->CurrentInterface != NULL);
  785. for (entry = Node->InterfaceList.Flink;
  786. entry != &(Node->InterfaceList);
  787. entry = entry->Flink
  788. )
  789. {
  790. interface = CONTAINING_RECORD(entry, CNP_INTERFACE, NodeLinkage);
  791. if ( !CnpIsNetworkRestricted(interface->Network) &&
  792. !CnpIsNetworkLocalDisconn(interface->Network) &&
  793. CnpIsBetterInterface(interface, bestInterface)
  794. )
  795. {
  796. bestInterface = interface;
  797. }
  798. }
  799. Node->CurrentInterface = bestInterface;
  800. IF_CNDBG(( CN_DEBUG_NODEOBJ | CN_DEBUG_NETOBJ )) {
  801. if (bestInterface == NULL) {
  802. CNPRINT((
  803. "[CNP] No route for node %u!!!!\n",
  804. Node->Id
  805. ));
  806. }
  807. else {
  808. CNPRINT((
  809. "[CNP] Best route for node %u is now network %u.\n",
  810. Node->Id,
  811. bestInterface->Network->Id
  812. ));
  813. }
  814. }
  815. CnVerifyCpuLockMask(
  816. CNP_NODE_OBJECT_LOCK, // Required
  817. 0, // Forbidden
  818. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  819. );
  820. return;
  821. } // CnpUpdateNodeCurrentInterface
  822. VOID
  823. CnpResetAndOnlinePendingInterface(
  824. IN PCNP_INTERFACE Interface
  825. )
  826. /*++
  827. Routine Description:
  828. Resets the sequence numbers used to authenticate packets
  829. sent by a node over a particular network. Also takes the
  830. node's interface online.
  831. This operation is performed when a node is joining a cluster.
  832. Arguments:
  833. Interface - A pointer to the interface on which to operate.
  834. Return Value:
  835. None.
  836. Notes:
  837. Called with associated node and network locks held.
  838. Returns with network lock released.
  839. Conforms to calling convention for PCNP_INTERFACE_UPDATE_ROUTINE.
  840. --*/
  841. {
  842. PCNP_NODE node = Interface->Node;
  843. PCNP_NETWORK network = Interface->Network;
  844. CnVerifyCpuLockMask(
  845. (CNP_NODE_OBJECT_LOCK | CNP_NETWORK_OBJECT_LOCK), // Required
  846. 0, // Forbidden
  847. CNP_NETWORK_OBJECT_LOCK_MAX // Maximum
  848. );
  849. IF_CNDBG(( CN_DEBUG_NODEOBJ | CN_DEBUG_NETOBJ ))
  850. CNPRINT((
  851. "[CNP] Reseting sequence numbers for node %u on network %u\n",
  852. node->Id,
  853. network->Id
  854. ));
  855. Interface->SequenceToSend = 0;
  856. Interface->LastSequenceReceived = 0;
  857. //
  858. // Take the interface online.
  859. //
  860. (VOID) CnpOnlinePendingInterface(Interface);
  861. CnVerifyCpuLockMask(
  862. (CNP_NODE_OBJECT_LOCK), // Required
  863. 0, // Forbidden
  864. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  865. );
  866. return;
  867. } // CnpRecalculateInterfacePriority
  868. NTSTATUS
  869. CnpFindInterface(
  870. IN CL_NODE_ID NodeId,
  871. IN CL_NETWORK_ID NetworkId,
  872. OUT PCNP_INTERFACE * Interface
  873. )
  874. {
  875. NTSTATUS status;
  876. PCNP_INTERFACE interface;
  877. PCNP_NODE node;
  878. PCNP_NETWORK network;
  879. PLIST_ENTRY entry;
  880. CnVerifyCpuLockMask(
  881. 0, // Required
  882. 0, // Forbidden
  883. CNP_PRECEEDING_LOCK_RANGE // Maximum
  884. );
  885. status = CnpValidateAndFindNode(NodeId, &node);
  886. if (status == STATUS_SUCCESS) {
  887. network = CnpFindNetwork(NetworkId);
  888. if (network != NULL) {
  889. for (entry = node->InterfaceList.Flink;
  890. entry != &(node->InterfaceList);
  891. entry = entry->Flink
  892. )
  893. {
  894. interface = CONTAINING_RECORD(
  895. entry,
  896. CNP_INTERFACE,
  897. NodeLinkage
  898. );
  899. if (interface->Network == network) {
  900. *Interface = interface;
  901. CnVerifyCpuLockMask(
  902. (CNP_NODE_OBJECT_LOCK | CNP_NETWORK_OBJECT_LOCK),
  903. 0, // Forbidden
  904. CNP_NETWORK_OBJECT_LOCK_MAX // Maximum
  905. );
  906. return(STATUS_SUCCESS);
  907. }
  908. }
  909. CnReleaseLock(&(network->Lock), network->Irql);
  910. }
  911. CnReleaseLock(&(node->Lock), node->Irql);
  912. }
  913. CnVerifyCpuLockMask(
  914. 0, // Required
  915. 0, // Forbidden
  916. CNP_PRECEEDING_LOCK_RANGE // Maximum
  917. );
  918. return(STATUS_CLUSTER_NETINTERFACE_NOT_FOUND);
  919. } // CnpFindInterface
  920. //
  921. // Cluster Transport Public Routines
  922. //
  923. NTSTATUS
  924. CxRegisterInterface(
  925. CL_NODE_ID NodeId,
  926. CL_NETWORK_ID NetworkId,
  927. ULONG Priority,
  928. PUWSTR AdapterId,
  929. ULONG AdapterIdLength,
  930. ULONG TdiAddressLength,
  931. PTRANSPORT_ADDRESS TdiAddress,
  932. PULONG MediaStatus
  933. )
  934. {
  935. NTSTATUS status;
  936. PLIST_ENTRY entry;
  937. PCNP_INTERFACE interface;
  938. PCNP_NODE node;
  939. PCNP_NETWORK network;
  940. ULONG allocSize;
  941. PWCHAR adapterDevNameBuffer = NULL;
  942. HANDLE adapterDevHandle = NULL;
  943. BOOLEAN localAdapter = FALSE;
  944. CnVerifyCpuLockMask(
  945. 0, // Required
  946. 0xFFFFFFFF, // Forbidden
  947. 0 // Maximum
  948. );
  949. //
  950. // Allocate and initialize an interface object.
  951. //
  952. allocSize = FIELD_OFFSET(CNP_INTERFACE, TdiAddress) + TdiAddressLength;
  953. interface = CnAllocatePool(allocSize);
  954. if (interface == NULL) {
  955. return(STATUS_INSUFFICIENT_RESOURCES);
  956. }
  957. RtlZeroMemory(interface, allocSize);
  958. CN_INIT_SIGNATURE(interface, CNP_INTERFACE_SIG);
  959. interface->State = ClusnetInterfaceStateOffline;
  960. RtlMoveMemory(&(interface->TdiAddress), TdiAddress, TdiAddressLength);
  961. interface->TdiAddressLength = TdiAddressLength;
  962. //
  963. // Register the new interface object
  964. //
  965. status = CnpValidateAndFindNode(NodeId, &node);
  966. if (NT_SUCCESS(status)) {
  967. //
  968. // If this adapter is on the local node, use the adapter ID
  969. // to find the corresponding WMI Provider ID.
  970. //
  971. localAdapter = (BOOLEAN)(node == CnpLocalNode);
  972. if (localAdapter) {
  973. PWCHAR adapterDevNamep, brace;
  974. PFILE_OBJECT adapterFileObject;
  975. PDEVICE_OBJECT adapterDeviceObject;
  976. // first drop the node lock
  977. CnReleaseLock(&(node->Lock), node->Irql);
  978. // allocate a buffer for the adapter device name
  979. allocSize = wcslen(L"\\Device\\") * sizeof(WCHAR)
  980. + AdapterIdLength
  981. + sizeof(UNICODE_NULL);
  982. brace = L"{";
  983. if (*((PWCHAR)AdapterId) != *brace) {
  984. allocSize += 2 * sizeof(WCHAR);
  985. }
  986. adapterDevNameBuffer = CnAllocatePool(allocSize);
  987. if (adapterDevNameBuffer == NULL) {
  988. status = STATUS_INSUFFICIENT_RESOURCES;
  989. goto error_exit;
  990. }
  991. // build the adapter device name from the adapter ID
  992. RtlZeroMemory(adapterDevNameBuffer, allocSize);
  993. adapterDevNamep = adapterDevNameBuffer;
  994. RtlCopyMemory(
  995. adapterDevNamep,
  996. L"\\Device\\",
  997. wcslen(L"\\Device\\") * sizeof(WCHAR)
  998. );
  999. adapterDevNamep += wcslen(L"\\Device\\");
  1000. if (*((PWCHAR)AdapterId) != *brace) {
  1001. *adapterDevNamep = *brace;
  1002. adapterDevNamep++;
  1003. }
  1004. RtlCopyMemory(adapterDevNamep, AdapterId, AdapterIdLength);
  1005. if (*((PWCHAR)AdapterId) != *brace) {
  1006. brace = L"}";
  1007. adapterDevNamep =
  1008. (PWCHAR)((PUCHAR)adapterDevNamep + AdapterIdLength);
  1009. *adapterDevNamep = *brace;
  1010. }
  1011. // open the adapter device
  1012. status = CnpOpenDevice(
  1013. adapterDevNameBuffer,
  1014. &adapterDevHandle
  1015. );
  1016. if (!NT_SUCCESS(status)) {
  1017. IF_CNDBG( CN_DEBUG_IFOBJ )
  1018. CNPRINT((
  1019. "[CNP] Failed to open adapter "
  1020. "device %S while registering "
  1021. "interface (%u, %u), status %lx.\n",
  1022. adapterDevNameBuffer,
  1023. NodeId,
  1024. NetworkId,
  1025. status
  1026. ));
  1027. goto error_exit;
  1028. }
  1029. status = ObReferenceObjectByHandle(
  1030. adapterDevHandle,
  1031. 0L, // DesiredAccess
  1032. NULL,
  1033. KernelMode,
  1034. &adapterFileObject,
  1035. NULL
  1036. );
  1037. if (!NT_SUCCESS(status)) {
  1038. IF_CNDBG( CN_DEBUG_IFOBJ )
  1039. CNPRINT((
  1040. "[CNP] Failed to reference handle "
  1041. "for adapter device %S while "
  1042. "registering interface (%u, %u), "
  1043. "status %lx.\n",
  1044. adapterDevNameBuffer,
  1045. NodeId,
  1046. NetworkId,
  1047. status
  1048. ));
  1049. ZwClose(adapterDevHandle);
  1050. adapterDevHandle = NULL;
  1051. goto error_exit;
  1052. }
  1053. adapterDeviceObject = IoGetRelatedDeviceObject(
  1054. adapterFileObject
  1055. );
  1056. // convert the adapter device object into the
  1057. // WMI provider ID
  1058. interface->AdapterWMIProviderId =
  1059. IoWMIDeviceObjectToProviderId(adapterDeviceObject);
  1060. IF_CNDBG( CN_DEBUG_IFOBJ )
  1061. CNPRINT((
  1062. "[CNP] Found WMI Provider ID %lx for adapter "
  1063. "device %S while "
  1064. "registering interface (%u, %u).\n",
  1065. interface->AdapterWMIProviderId,
  1066. adapterDevNameBuffer,
  1067. NodeId,
  1068. NetworkId
  1069. ));
  1070. // we no longer need the file object or device name
  1071. // buffer, but we hold onto the adapter device handle
  1072. // in order to query the current media status.
  1073. ObDereferenceObject(adapterFileObject);
  1074. CnFreePool(adapterDevNameBuffer);
  1075. adapterDevNameBuffer = NULL;
  1076. // reacquire the local node lock
  1077. status = CnpValidateAndFindNode(NodeId, &node);
  1078. if (!NT_SUCCESS(status)) {
  1079. status = STATUS_CLUSTER_NODE_NOT_FOUND;
  1080. goto error_exit;
  1081. }
  1082. }
  1083. network = CnpFindNetwork(NetworkId);
  1084. if (network != NULL) {
  1085. //
  1086. // Check if the specified interface already exists.
  1087. //
  1088. status = STATUS_SUCCESS;
  1089. for (entry = node->InterfaceList.Flink;
  1090. entry != &(node->InterfaceList);
  1091. entry = entry->Flink
  1092. )
  1093. {
  1094. PCNP_INTERFACE oldInterface = CONTAINING_RECORD(
  1095. entry,
  1096. CNP_INTERFACE,
  1097. NodeLinkage
  1098. );
  1099. if (oldInterface->Network == network) {
  1100. status = STATUS_CLUSTER_NETINTERFACE_EXISTS;
  1101. break;
  1102. }
  1103. }
  1104. if (NT_SUCCESS(status)) {
  1105. interface->Node = node;
  1106. interface->Network = network;
  1107. if (Priority != 0) {
  1108. interface->Priority = Priority;
  1109. }
  1110. else {
  1111. interface->Priority = network->Priority;
  1112. interface->Flags |= CNP_IF_FLAG_USE_NETWORK_PRIORITY;
  1113. }
  1114. IF_CNDBG( CN_DEBUG_IFOBJ )
  1115. CNPRINT((
  1116. "[CNP] Registering interface (%u, %u) pri %u...\n",
  1117. NodeId,
  1118. NetworkId,
  1119. interface->Priority
  1120. ));
  1121. //
  1122. // Place a reference on the network for this interface.
  1123. //
  1124. CnpReferenceNetwork(network);
  1125. //
  1126. // Insert the interface into the node's interface list.
  1127. //
  1128. InsertTailList(
  1129. &(node->InterfaceList),
  1130. &(interface->NodeLinkage)
  1131. );
  1132. //
  1133. // Update the node's CurrentInterface if appropriate.
  1134. //
  1135. if ( !CnpIsNetworkRestricted(network)
  1136. &&
  1137. CnpIsBetterInterface(interface, node->CurrentInterface)
  1138. )
  1139. {
  1140. IF_CNDBG( CN_DEBUG_IFOBJ )
  1141. CNPRINT((
  1142. "[CNP] Network %u is now the best route to node %u.\n",
  1143. network->Id,
  1144. node->Id
  1145. ));
  1146. node->CurrentInterface = interface;
  1147. }
  1148. IF_CNDBG( CN_DEBUG_IFOBJ )
  1149. CNPRINT((
  1150. "[CNP] Registered interface (%u, %u).\n",
  1151. NodeId,
  1152. NetworkId
  1153. ));
  1154. if (network->State == ClusnetNetworkStateOnline) {
  1155. (VOID) CnpOnlinePendingInterface(interface);
  1156. //
  1157. // The network lock was released.
  1158. //
  1159. }
  1160. else {
  1161. CnReleaseLockFromDpc(&(network->Lock));
  1162. }
  1163. CnReleaseLock(&(node->Lock), node->Irql);
  1164. //
  1165. // Determine the initial media status state of this
  1166. // interface if it is local.
  1167. //
  1168. if (localAdapter) {
  1169. CxQueryMediaStatus(
  1170. adapterDevHandle,
  1171. NetworkId,
  1172. MediaStatus
  1173. );
  1174. } else {
  1175. //
  1176. // Assume remote interfaces are connected
  1177. //
  1178. *MediaStatus = NdisMediaStateConnected;
  1179. }
  1180. if (adapterDevHandle != NULL) {
  1181. ZwClose(adapterDevHandle);
  1182. adapterDevHandle = NULL;
  1183. }
  1184. return(STATUS_SUCCESS);
  1185. }
  1186. CnReleaseLockFromDpc(&(network->Lock));
  1187. }
  1188. else {
  1189. status = STATUS_CLUSTER_NETWORK_NOT_FOUND;
  1190. }
  1191. CnReleaseLock(&(node->Lock), node->Irql);
  1192. }
  1193. else {
  1194. status = STATUS_CLUSTER_NODE_NOT_FOUND;
  1195. }
  1196. error_exit:
  1197. if (!NT_SUCCESS(status)) {
  1198. CnFreePool(interface);
  1199. }
  1200. if (adapterDevHandle != NULL) {
  1201. ZwClose(adapterDevHandle);
  1202. adapterDevHandle = NULL;
  1203. }
  1204. if (adapterDevNameBuffer != NULL) {
  1205. CnFreePool(adapterDevNameBuffer);
  1206. adapterDevNameBuffer = NULL;
  1207. }
  1208. CnVerifyCpuLockMask(
  1209. 0, // Required
  1210. 0xFFFFFFFF, // Forbidden
  1211. 0 // Maximum
  1212. );
  1213. return(status);
  1214. } // CxRegisterInterface
  1215. NTSTATUS
  1216. CxDeregisterInterface(
  1217. CL_NODE_ID NodeId,
  1218. CL_NETWORK_ID NetworkId
  1219. )
  1220. {
  1221. NTSTATUS status;
  1222. PCNP_INTERFACE interface;
  1223. ULONG i;
  1224. PCNP_NODE node;
  1225. PCNP_NETWORK network;
  1226. CN_IRQL tableIrql;
  1227. if ((NodeId == ClusterAnyNodeId) && (NetworkId == ClusterAnyNetworkId)) {
  1228. //
  1229. // Destroy all interfaces on all networks.
  1230. //
  1231. IF_CNDBG(( CN_DEBUG_IFOBJ | CN_DEBUG_CLEANUP ))
  1232. CNPRINT(("[CNP] Destroying all interfaces on all networks\n"));
  1233. CnAcquireLock(&CnpNodeTableLock, &tableIrql);
  1234. CnAssert(CnMinValidNodeId != ClusterInvalidNodeId);
  1235. CnAssert(CnMaxValidNodeId != ClusterInvalidNodeId);
  1236. for (i=CnMinValidNodeId; i <= CnMaxValidNodeId; i++) {
  1237. node = CnpNodeTable[i];
  1238. if (node != NULL) {
  1239. CnAcquireLockAtDpc(&(node->Lock));
  1240. CnReleaseLockFromDpc(&CnpNodeTableLock);
  1241. node->Irql = tableIrql;
  1242. CnpWalkInterfacesOnNode(node, CnpDeleteInterface);
  1243. CnReleaseLock(&(node->Lock), node->Irql);
  1244. CnAcquireLock(&CnpNodeTableLock, &tableIrql);
  1245. }
  1246. }
  1247. CnReleaseLock(&CnpNodeTableLock, tableIrql);
  1248. status = STATUS_SUCCESS;
  1249. }
  1250. else if (NodeId == ClusterAnyNodeId) {
  1251. //
  1252. // Destroy all interfaces on a specific network.
  1253. //
  1254. IF_CNDBG(( CN_DEBUG_IFOBJ | CN_DEBUG_NETOBJ | CN_DEBUG_CLEANUP ))
  1255. CNPRINT((
  1256. "[CNP] Destroying all interfaces on network %u\n",
  1257. NetworkId
  1258. ));
  1259. network = CnpFindNetwork(NetworkId);
  1260. if (network != NULL) {
  1261. CnpReferenceNetwork(network);
  1262. CnReleaseLock(&(network->Lock), network->Irql);
  1263. CnpWalkInterfacesOnNetwork(network, CnpDeleteInterface);
  1264. CnAcquireLock(&(network->Lock), &(network->Irql));
  1265. CnpDereferenceNetwork(network);
  1266. status = STATUS_SUCCESS;
  1267. }
  1268. else {
  1269. status = STATUS_CLUSTER_NETWORK_NOT_FOUND;
  1270. }
  1271. }
  1272. else if (NetworkId == ClusterAnyNetworkId) {
  1273. //
  1274. // Destroy all interfaces on a specified node.
  1275. //
  1276. IF_CNDBG(( CN_DEBUG_IFOBJ | CN_DEBUG_NODEOBJ | CN_DEBUG_CLEANUP ))
  1277. CNPRINT((
  1278. "[CNP] Destroying all interfaces on node %u\n",
  1279. NodeId
  1280. ));
  1281. status = CnpValidateAndFindNode(NodeId, &node);
  1282. if (status == STATUS_SUCCESS) {
  1283. CnpWalkInterfacesOnNode(node, CnpDeleteInterface);
  1284. CnReleaseLock(&(node->Lock), node->Irql);
  1285. }
  1286. }
  1287. else {
  1288. //
  1289. // Delete a specific interface
  1290. //
  1291. status = CnpFindInterface(NodeId, NetworkId, &interface);
  1292. if (NT_SUCCESS(status)) {
  1293. node = interface->Node;
  1294. CnpDeleteInterface(interface);
  1295. //
  1296. // The network lock was released.
  1297. //
  1298. CnReleaseLock(&(node->Lock), node->Irql);
  1299. }
  1300. }
  1301. return(status);
  1302. } // CxDeregisterNetwork
  1303. NTSTATUS
  1304. CxSetInterfacePriority(
  1305. IN CL_NODE_ID NodeId,
  1306. IN CL_NETWORK_ID NetworkId,
  1307. IN ULONG Priority
  1308. )
  1309. {
  1310. NTSTATUS status;
  1311. PCNP_INTERFACE interface;
  1312. PCNP_NODE node;
  1313. PCNP_NETWORK network;
  1314. ULONG oldPriority;
  1315. BOOLEAN restricted;
  1316. CnVerifyCpuLockMask(
  1317. 0, // Required
  1318. 0xFFFFFFFF, // Forbidden
  1319. 0 // Maximum
  1320. );
  1321. status = CnpFindInterface(NodeId, NetworkId, &interface);
  1322. if (status == STATUS_SUCCESS) {
  1323. node = interface->Node;
  1324. network = interface->Network;
  1325. oldPriority = interface->Priority;
  1326. restricted = CnpIsNetworkRestricted(network);
  1327. if (Priority != 0) {
  1328. interface->Priority = Priority;
  1329. interface->Flags &= ~(CNP_IF_FLAG_USE_NETWORK_PRIORITY);
  1330. }
  1331. else {
  1332. interface->Priority = network->Priority;
  1333. interface->Flags |= CNP_IF_FLAG_USE_NETWORK_PRIORITY;
  1334. }
  1335. IF_CNDBG( CN_DEBUG_IFOBJ )
  1336. CNPRINT((
  1337. "[CNP] Set interface (%u, %u) to priority %u\n",
  1338. NodeId,
  1339. NetworkId,
  1340. interface->Priority
  1341. ));
  1342. CnReleaseLockFromDpc(&(network->Lock));
  1343. if (!restricted) {
  1344. if (interface == node->CurrentInterface) {
  1345. if (interface->Priority > oldPriority) {
  1346. //
  1347. // Our priority got worse. Recalculate the best route.
  1348. //
  1349. CnpUpdateNodeCurrentInterface(node);
  1350. }
  1351. //
  1352. // Else interface priority is same or better. Nothing to do.
  1353. //
  1354. }
  1355. else if ( CnpIsBetterInterface(
  1356. interface,
  1357. node->CurrentInterface
  1358. )
  1359. )
  1360. {
  1361. //
  1362. // Our priority got better.
  1363. //
  1364. IF_CNDBG(( CN_DEBUG_NODEOBJ | CN_DEBUG_NETOBJ ))
  1365. CNPRINT((
  1366. "[CNP] Network %u is now the best route to node %u\n",
  1367. network->Id,
  1368. node->Id
  1369. ));
  1370. node->CurrentInterface = interface;
  1371. }
  1372. }
  1373. CnReleaseLock(&(node->Lock), node->Irql);
  1374. }
  1375. CnVerifyCpuLockMask(
  1376. 0, // Required
  1377. 0xFFFFFFFF, // Forbidden
  1378. 0 // Maximum
  1379. );
  1380. return(status);
  1381. } // CxSetInterfacePriority
  1382. NTSTATUS
  1383. CxGetInterfacePriority(
  1384. IN CL_NODE_ID NodeId,
  1385. IN CL_NETWORK_ID NetworkId,
  1386. OUT PULONG InterfacePriority,
  1387. OUT PULONG NetworkPriority
  1388. )
  1389. {
  1390. NTSTATUS status;
  1391. PCNP_INTERFACE interface;
  1392. PCNP_NODE node;
  1393. PCNP_NETWORK network;
  1394. CnVerifyCpuLockMask(
  1395. 0, // Required
  1396. 0xFFFFFFFF, // Forbidden
  1397. 0 // Maximum
  1398. );
  1399. status = CnpFindInterface(NodeId, NetworkId, &interface);
  1400. if (status == STATUS_SUCCESS) {
  1401. node = interface->Node;
  1402. network = interface->Network;
  1403. *NetworkPriority = network->Priority;
  1404. if (CnpIsInterfaceUsingNetworkPriority(interface)) {
  1405. *InterfacePriority = 0;
  1406. }
  1407. else {
  1408. *InterfacePriority = interface->Priority;
  1409. }
  1410. CnReleaseLockFromDpc(&(network->Lock));
  1411. CnReleaseLock(&(node->Lock), node->Irql);
  1412. }
  1413. CnVerifyCpuLockMask(
  1414. 0, // Required
  1415. 0xFFFFFFFF, // Forbidden
  1416. 0 // Maximum
  1417. );
  1418. return(status);
  1419. } // CxGetInterfacePriority
  1420. NTSTATUS
  1421. CxGetInterfaceState(
  1422. IN CL_NODE_ID NodeId,
  1423. IN CL_NETWORK_ID NetworkId,
  1424. OUT PCLUSNET_INTERFACE_STATE State
  1425. )
  1426. {
  1427. NTSTATUS status;
  1428. PCNP_INTERFACE interface;
  1429. PCNP_NODE node;
  1430. PCNP_NETWORK network;
  1431. CnVerifyCpuLockMask(
  1432. 0, // Required
  1433. 0xFFFFFFFF, // Forbidden
  1434. 0 // Maximum
  1435. );
  1436. status = CnpFindInterface(NodeId, NetworkId, &interface);
  1437. if (status == STATUS_SUCCESS) {
  1438. node = interface->Node;
  1439. network = interface->Network;
  1440. *State = interface->State;
  1441. CnAssert(network->Irql == DISPATCH_LEVEL);
  1442. CnReleaseLockFromDpc(&(network->Lock));
  1443. CnReleaseLock(&(node->Lock), node->Irql);
  1444. }
  1445. CnVerifyCpuLockMask(
  1446. 0, // Required
  1447. 0xFFFFFFFF, // Forbidden
  1448. 0 // Maximum
  1449. );
  1450. return(status);
  1451. } // CxGetInterfaceState
  1452. //
  1453. // Test APIs
  1454. //
  1455. #if DBG
  1456. NTSTATUS
  1457. CxOnlinePendingInterface(
  1458. IN CL_NODE_ID NodeId,
  1459. IN CL_NETWORK_ID NetworkId
  1460. )
  1461. {
  1462. NTSTATUS status;
  1463. PCNP_INTERFACE interface;
  1464. PCNP_NODE node;
  1465. PCNP_NETWORK network;
  1466. CnVerifyCpuLockMask(
  1467. 0, // Required
  1468. 0xFFFFFFFF, // Forbidden
  1469. 0 // Maximum
  1470. );
  1471. status = CnpFindInterface(NodeId, NetworkId, &interface);
  1472. if (status == STATUS_SUCCESS) {
  1473. node = interface->Node;
  1474. network = interface->Network;
  1475. status = CnpOnlinePendingInterface(interface);
  1476. //
  1477. // The network lock was released
  1478. //
  1479. CnReleaseLock(&(node->Lock), node->Irql);
  1480. }
  1481. CnVerifyCpuLockMask(
  1482. 0, // Required
  1483. 0xFFFFFFFF, // Forbidden
  1484. 0 // Maximum
  1485. );
  1486. return(status);
  1487. } // CxOnlinePendingInterface
  1488. NTSTATUS
  1489. CxOnlineInterface(
  1490. IN CL_NODE_ID NodeId,
  1491. IN CL_NETWORK_ID NetworkId
  1492. )
  1493. {
  1494. NTSTATUS status;
  1495. PCNP_INTERFACE interface;
  1496. PCNP_NODE node;
  1497. CnVerifyCpuLockMask(
  1498. 0, // Required
  1499. 0xFFFFFFFF, // Forbidden
  1500. 0 // Maximum
  1501. );
  1502. status = CnpFindInterface(NodeId, NetworkId, &interface);
  1503. if (status == STATUS_SUCCESS) {
  1504. node = interface->Node;
  1505. status = CnpOnlineInterface(interface);
  1506. //
  1507. // The network lock was released
  1508. //
  1509. CnReleaseLock(&(node->Lock), node->Irql);
  1510. }
  1511. CnVerifyCpuLockMask(
  1512. 0, // Required
  1513. 0xFFFFFFFF, // Forbidden
  1514. 0 // Maximum
  1515. );
  1516. return(status);
  1517. } // CxOnlineInterface
  1518. NTSTATUS
  1519. CxOfflineInterface(
  1520. IN CL_NODE_ID NodeId,
  1521. IN CL_NETWORK_ID NetworkId
  1522. )
  1523. {
  1524. NTSTATUS status;
  1525. PCNP_INTERFACE interface;
  1526. PCNP_NODE node;
  1527. CnVerifyCpuLockMask(
  1528. 0, // Required
  1529. 0xFFFFFFFF, // Forbidden
  1530. 0 // Maximum
  1531. );
  1532. status = CnpFindInterface(NodeId, NetworkId, &interface);
  1533. if (status == STATUS_SUCCESS) {
  1534. node = interface->Node;
  1535. status = CnpOfflineInterface(interface);
  1536. //
  1537. // The network lock was released
  1538. //
  1539. CnReleaseLock(&(node->Lock), node->Irql);
  1540. }
  1541. CnVerifyCpuLockMask(
  1542. 0, // Required
  1543. 0xFFFFFFFF, // Forbidden
  1544. 0 // Maximum
  1545. );
  1546. return(status);
  1547. } // CxOfflineInterface
  1548. NTSTATUS
  1549. CxFailInterface(
  1550. IN CL_NODE_ID NodeId,
  1551. IN CL_NETWORK_ID NetworkId
  1552. )
  1553. {
  1554. NTSTATUS status;
  1555. PCNP_INTERFACE interface;
  1556. PCNP_NODE node;
  1557. CnVerifyCpuLockMask(
  1558. 0, // Required
  1559. 0xFFFFFFFF, // Forbidden
  1560. 0 // Maximum
  1561. );
  1562. status = CnpFindInterface(NodeId, NetworkId, &interface);
  1563. if (status == STATUS_SUCCESS) {
  1564. node = interface->Node;
  1565. status = CnpFailInterface(interface);
  1566. //
  1567. // The network lock was released
  1568. //
  1569. CnReleaseLock(&(node->Lock), node->Irql);
  1570. }
  1571. CnVerifyCpuLockMask(
  1572. 0, // Required
  1573. 0xFFFFFFFF, // Forbidden
  1574. 0 // Maximum
  1575. );
  1576. return(status);
  1577. } // CxOfflineInterface
  1578. #endif // DBG