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

828 lines
24 KiB

  1. // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil -*- (for GNU Emacs)
  2. //
  3. // Copyright (c) 2000 Microsoft Corporation
  4. //
  5. // This file is part of the Microsoft Research IPv6 Network Protocol Stack.
  6. // You should have received a copy of the Microsoft End-User License Agreement
  7. // for this software along with this release; see the file "license.txt".
  8. // If not, please see http://www.research.microsoft.com/msripv6/license.htm,
  9. // or write to Microsoft Research, One Microsoft Way, Redmond, WA 98052-6399.
  10. //
  11. // Abstract:
  12. //
  13. // Source address selection and destination address ordering.
  14. //
  15. #include "oscfg.h"
  16. #include "ndis.h"
  17. #include "ip6imp.h"
  18. #include "ip6def.h"
  19. #include "route.h"
  20. #include "select.h"
  21. KSPIN_LOCK SelectLock;
  22. PrefixPolicyEntry *PrefixPolicyTable;
  23. PrefixPolicyEntry PrefixPolicyNull;
  24. //* InitSelect
  25. //
  26. // Initialize the address selection module.
  27. //
  28. void
  29. InitSelect(void)
  30. {
  31. KeInitializeSpinLock(&SelectLock);
  32. //
  33. // The default prefix policy, when nothing in the table matches.
  34. // (Normally there will be a ::/0 policy.)
  35. //
  36. PrefixPolicyNull.Precedence = (uint) -1;
  37. PrefixPolicyNull.SrcLabel = (uint) -1;
  38. PrefixPolicyNull.DstLabel = (uint) -1;
  39. //
  40. // Configure persistent policies from the registry.
  41. //
  42. ConfigurePrefixPolicies();
  43. }
  44. //* UnloadSelect
  45. //
  46. // Called when the IPv6 stack is unloading.
  47. //
  48. void
  49. UnloadSelect(void)
  50. {
  51. PrefixPolicyReset();
  52. }
  53. //* PrefixPolicyReset
  54. //
  55. // Deletes all prefix policies.
  56. // Called with no locks held.
  57. //
  58. void
  59. PrefixPolicyReset(void)
  60. {
  61. PrefixPolicyEntry *List;
  62. PrefixPolicyEntry *PPE;
  63. KIRQL OldIrql;
  64. //
  65. // Free the prefix policies.
  66. //
  67. KeAcquireSpinLock(&SelectLock, &OldIrql);
  68. List = PrefixPolicyTable;
  69. PrefixPolicyTable = NULL;
  70. KeReleaseSpinLock(&SelectLock, OldIrql);
  71. while ((PPE = List) != NULL) {
  72. List = PPE->Next;
  73. ExFreePool(PPE);
  74. }
  75. }
  76. //* PrefixPolicyUpdate
  77. //
  78. // Updates the prefix policy table by creating a new policy entry
  79. // or updating an existing entry.
  80. //
  81. void
  82. PrefixPolicyUpdate(
  83. const IPv6Addr *PolicyPrefix,
  84. uint PrefixLength,
  85. uint Precedence,
  86. uint SrcLabel,
  87. uint DstLabel)
  88. {
  89. IPv6Addr Prefix;
  90. PrefixPolicyEntry *PPE;
  91. KIRQL OldIrql;
  92. ASSERT((Precedence != (uint)-1) &&
  93. (SrcLabel != (uint)-1) &&
  94. (DstLabel != (uint)-1));
  95. //
  96. // Ensure that the unused prefix bits are zero.
  97. // This makes the prefix comparisons below safe.
  98. //
  99. CopyPrefix(&Prefix, PolicyPrefix, PrefixLength);
  100. KeAcquireSpinLock(&SelectLock, &OldIrql);
  101. for (PPE = PrefixPolicyTable; ; PPE = PPE->Next) {
  102. if (PPE == NULL) {
  103. //
  104. // The prefix policy does not exist, so create it.
  105. //
  106. PPE = ExAllocatePool(NonPagedPool, sizeof *PPE);
  107. if (PPE == NULL) {
  108. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_NTOS_ERROR,
  109. "PrefixPolicyUpdate: out of pool\n"));
  110. break;
  111. }
  112. PPE->Prefix = Prefix;
  113. PPE->PrefixLength = PrefixLength;
  114. PPE->Precedence = Precedence;
  115. PPE->SrcLabel = SrcLabel;
  116. PPE->DstLabel = DstLabel;
  117. PPE->Next = PrefixPolicyTable;
  118. PrefixPolicyTable = PPE;
  119. break;
  120. }
  121. if ((PPE->PrefixLength == PrefixLength) &&
  122. IP6_ADDR_EQUAL(&PPE->Prefix, &Prefix)) {
  123. //
  124. // Update the existing policy.
  125. //
  126. PPE->Precedence = Precedence;
  127. PPE->SrcLabel = SrcLabel;
  128. PPE->DstLabel = DstLabel;
  129. break;
  130. }
  131. }
  132. KeReleaseSpinLock(&SelectLock, OldIrql);
  133. }
  134. //* PrefixPolicyDelete
  135. //
  136. // Updates the prefix policy table by deleting a policy entry.
  137. //
  138. void
  139. PrefixPolicyDelete(
  140. const IPv6Addr *PolicyPrefix,
  141. uint PrefixLength)
  142. {
  143. IPv6Addr Prefix;
  144. PrefixPolicyEntry **PrevPPE;
  145. PrefixPolicyEntry *PPE;
  146. KIRQL OldIrql;
  147. //
  148. // Ensure that the unused prefix bits are zero.
  149. // This makes the prefix comparisons below safe.
  150. //
  151. CopyPrefix(&Prefix, PolicyPrefix, PrefixLength);
  152. KeAcquireSpinLock(&SelectLock, &OldIrql);
  153. for (PrevPPE = &PrefixPolicyTable; ; PrevPPE = &PPE->Next) {
  154. PPE = *PrevPPE;
  155. if (PPE == NULL) {
  156. //
  157. // The prefix policy does not exist, so do nothing.
  158. //
  159. break;
  160. }
  161. if ((PPE->PrefixLength == PrefixLength) &&
  162. IP6_ADDR_EQUAL(&PPE->Prefix, &Prefix)) {
  163. //
  164. // Delete the prefix policy.
  165. //
  166. *PrevPPE = PPE->Next;
  167. ExFreePool(PPE);
  168. break;
  169. }
  170. }
  171. KeReleaseSpinLock(&SelectLock, OldIrql);
  172. }
  173. void
  174. PrefixPolicyLookup(
  175. const IPv6Addr *Addr,
  176. uint *Precedence,
  177. uint *SrcLabel,
  178. uint *DstLabel)
  179. {
  180. PrefixPolicyEntry *PPE, *BestPPE = NULL;
  181. KIRQL OldIrql;
  182. KeAcquireSpinLock(&SelectLock, &OldIrql);
  183. for (PPE = PrefixPolicyTable; PPE != NULL; PPE = PPE->Next) {
  184. if (HasPrefix(Addr, &PPE->Prefix, PPE->PrefixLength)) {
  185. if ((BestPPE == NULL) ||
  186. (BestPPE->PrefixLength < PPE->PrefixLength)) {
  187. //
  188. // So far this is our best match.
  189. //
  190. BestPPE = PPE;
  191. }
  192. }
  193. }
  194. if (BestPPE == NULL) {
  195. //
  196. // There were no matches, so return default values.
  197. //
  198. BestPPE = &PrefixPolicyNull;
  199. }
  200. //
  201. // Return information from the best matching policy.
  202. //
  203. if (Precedence != NULL)
  204. *Precedence = BestPPE->Precedence;
  205. if (SrcLabel != NULL)
  206. *SrcLabel = BestPPE->SrcLabel;
  207. if (DstLabel != NULL)
  208. *DstLabel = BestPPE->DstLabel;
  209. KeReleaseSpinLock(&SelectLock, OldIrql);
  210. }
  211. //* FindBestSourceAddress
  212. //
  213. // Given an outgoing interface and a destination address,
  214. // finds the best source address (NTE) to use.
  215. //
  216. // May be called with the route cache lock held.
  217. //
  218. // If found, returns a reference for the NTE.
  219. //
  220. NetTableEntry *
  221. FindBestSourceAddress(
  222. Interface *IF, // Interface we're sending from.
  223. const IPv6Addr *Dest) // Destination we're sending to.
  224. {
  225. NetTableEntry *BestNTE = NULL;
  226. ushort DestScope;
  227. uint Length, BestLength = 0;
  228. uint DstLabel, SrcLabel, BestSrcLabel = 0;
  229. AddressEntry *ADE;
  230. NetTableEntry *NTE;
  231. KIRQL OldIrql;
  232. DestScope = AddressScope(Dest);
  233. PrefixPolicyLookup(Dest, NULL, NULL, &DstLabel);
  234. KeAcquireSpinLock(&IF->Lock, &OldIrql);
  235. for (ADE = IF->ADE; ADE != NULL; ADE = ADE->Next) {
  236. NTE = (NetTableEntry *)ADE;
  237. //
  238. // Only consider valid (preferred & deprecated) unicast addresses.
  239. //
  240. if ((NTE->Type == ADE_UNICAST) && IsValidNTE(NTE)) {
  241. Length = CommonPrefixLength(Dest, &NTE->Address);
  242. if (Length == IPV6_ADDRESS_LENGTH) {
  243. //
  244. // Rule 1: Prefer same address.
  245. // No need to keep looking.
  246. //
  247. BestNTE = NTE;
  248. break;
  249. }
  250. PrefixPolicyLookup(&NTE->Address, NULL, &SrcLabel, NULL);
  251. if (BestNTE == NULL) {
  252. //
  253. // We don't have a choice yet, so take what we can get.
  254. //
  255. FoundAddress:
  256. BestNTE = NTE;
  257. BestSrcLabel = SrcLabel;
  258. BestLength = Length;
  259. }
  260. else if (BestNTE->Scope != NTE->Scope) {
  261. //
  262. // Rule 2: Prefer appropriate scope.
  263. // If one is bigger & one smaller than the destination,
  264. // we should use the address that is bigger.
  265. // If both are bigger than the destination,
  266. // we should use the address with smaller scope.
  267. // If both are smaller than the destination,
  268. // we should use the address with larger scope.
  269. //
  270. if (BestNTE->Scope < NTE->Scope) {
  271. if (BestNTE->Scope < DestScope)
  272. goto FoundAddress;
  273. }
  274. else {
  275. if (DestScope <= NTE->Scope)
  276. goto FoundAddress;
  277. }
  278. }
  279. else if (BestNTE->DADState != NTE->DADState) {
  280. //
  281. // Rule 3: Avoid deprecated addresses.
  282. //
  283. if (BestNTE->DADState < NTE->DADState)
  284. goto FoundAddress;
  285. }
  286. //
  287. // Rule 4: Prefer home addresses.
  288. // Not yet implemented, pending mobility support.
  289. //
  290. // Rule 5: Prefer outgoing interface.
  291. // Not needed, because we only consider addresses
  292. // assigned to the outgoing interface.
  293. //
  294. else if ((BestSrcLabel == DstLabel) != (SrcLabel == DstLabel)) {
  295. //
  296. // Rule 6: Prefer matching label.
  297. // One source address has a label matching
  298. // the destination, and the other doesn't.
  299. // Choose the one with the matching label.
  300. //
  301. if (SrcLabel == DstLabel)
  302. goto FoundAddress;
  303. }
  304. else if ((BestNTE->AddrConf == ADDR_CONF_TEMPORARY) !=
  305. (NTE->AddrConf == ADDR_CONF_TEMPORARY)) {
  306. //
  307. // Rule 7: Prefer temporary addresses.
  308. //
  309. if (NTE->AddrConf == ADDR_CONF_TEMPORARY)
  310. goto FoundAddress;
  311. }
  312. else {
  313. //
  314. // Rule 8: Use longest matching prefix.
  315. //
  316. if (BestLength < Length)
  317. goto FoundAddress;
  318. }
  319. }
  320. }
  321. if (BestNTE != NULL)
  322. AddRefNTE(BestNTE);
  323. KeReleaseSpinLock(&IF->Lock, OldIrql);
  324. return BestNTE;
  325. }
  326. //* ProcessSiteLocalAddresses
  327. //
  328. // Examines the input array of addresses
  329. // and either removes unqualified site-local addresses
  330. // or qualifies them with the appropriate site scope-id,
  331. // depending on whether there are any global addresses
  332. // in the array that match in the site prefix table.
  333. //
  334. // Rearranges the key array, not the input address array.
  335. // Modifies the scope-ids of site-local addresses in the array.
  336. //
  337. void
  338. ProcessSiteLocalAddresses(
  339. TDI_ADDRESS_IP6 *Addrs,
  340. uint *Key,
  341. uint *pNumAddrs)
  342. {
  343. uint NumAddrs = *pNumAddrs;
  344. int SawSiteLocal = FALSE;
  345. int SawGlobal = FALSE;
  346. uint i;
  347. //
  348. // First see if there are unqualified site-local addresses
  349. // and global addresses in the array.
  350. //
  351. for (i = 0; i < NumAddrs; i++) {
  352. TDI_ADDRESS_IP6 *Tdi = &Addrs[Key[i]];
  353. IPv6Addr *Addr = (IPv6Addr *) &Tdi->sin6_addr;
  354. if (IsGlobal(Addr))
  355. SawGlobal = TRUE;
  356. else if (IsSiteLocal(Addr)) {
  357. if (Tdi->sin6_scope_id == 0)
  358. SawSiteLocal = TRUE;
  359. }
  360. }
  361. if (SawSiteLocal && SawGlobal) {
  362. uint ScopeId = 0;
  363. //
  364. // Check the global addresses against the site-prefix table,
  365. // to determine the appropriate site scope-id.
  366. // If we don't find a matching global address,
  367. // we remove the site-local addresses.
  368. // If we do find matching global addresses
  369. // (all with the same site scope-id),
  370. // then we update the site-local addresses' scope-id.
  371. //
  372. for (i = 0; i < NumAddrs; i++) {
  373. TDI_ADDRESS_IP6 *Tdi = &Addrs[Key[i]];
  374. IPv6Addr *Addr = (IPv6Addr *) &Tdi->sin6_addr;
  375. if (IsGlobal(Addr)) {
  376. uint ThisScopeId;
  377. ThisScopeId = SitePrefixMatch(Addr);
  378. if (ThisScopeId != 0) {
  379. //
  380. // This global address matches a site prefix.
  381. //
  382. if (ScopeId == 0) {
  383. //
  384. // Save the scope-id, but keep looking.
  385. //
  386. ScopeId = ThisScopeId;
  387. }
  388. else if (ScopeId != ThisScopeId) {
  389. //
  390. // We have found an inconsistency, so remove
  391. // all unqualified site-local addresses.
  392. //
  393. ScopeId = 0;
  394. break;
  395. }
  396. }
  397. }
  398. }
  399. if (ScopeId == 0) {
  400. uint j = 0;
  401. //
  402. // Remove all unqualified site-local addresses.
  403. //
  404. for (i = 0; i < NumAddrs; i++) {
  405. TDI_ADDRESS_IP6 *Tdi = &Addrs[Key[i]];
  406. IPv6Addr *Addr = (IPv6Addr *) &Tdi->sin6_addr;
  407. if (IsSiteLocal(Addr) &&
  408. (Tdi->sin6_scope_id == 0)) {
  409. //
  410. // Exclude this address from the key array.
  411. //
  412. ;
  413. }
  414. else {
  415. //
  416. // Include this address in the key array.
  417. //
  418. Key[j++] = Key[i];
  419. }
  420. }
  421. *pNumAddrs = j;
  422. }
  423. else {
  424. //
  425. // Set the scope-id of unqualified site-local addresses.
  426. //
  427. for (i = 0; i < NumAddrs; i++) {
  428. TDI_ADDRESS_IP6 *Tdi = &Addrs[Key[i]];
  429. IPv6Addr *Addr = (IPv6Addr *) &Tdi->sin6_addr;
  430. if (IsSiteLocal(Addr) &&
  431. (Tdi->sin6_scope_id == 0))
  432. Tdi->sin6_scope_id = ScopeId;
  433. }
  434. }
  435. }
  436. }
  437. //
  438. // Records some information about a destination address:
  439. // Its precedence, whether the preferred source address
  440. // for the destination "matches" the destination,
  441. // and if it does match, the common prefix length
  442. // of the two addresses.
  443. //
  444. typedef struct SortAddrInfo {
  445. uint Preference;
  446. uint Precedence; // -1 indicates no precedence.
  447. ushort Scope;
  448. uchar Flags;
  449. uchar CommonPrefixLen; // Valid if not SAI_FLAG_DONTUSE.
  450. } SortAddrInfo;
  451. #define SAI_FLAG_DONTUSE 0x1
  452. #define SAI_FLAG_SCOPE_MISMATCH 0x2
  453. #define SAI_FLAG_DEPRECATED 0x4
  454. #define SAI_FLAG_LABEL_MISMATCH 0x8
  455. //* CompareSortAddrInfo
  456. //
  457. // Compares two addresses A & B and returns
  458. // an indication of their relative desirability
  459. // as destination addresses:
  460. // >0 means A is preferred,
  461. // 0 means no preference,
  462. // <0 means B is preferred.
  463. //
  464. // Instead of looking directly at the addresses,
  465. // we look at some precomputed information.
  466. //
  467. int
  468. CompareSortAddrInfo(SortAddrInfo *A, SortAddrInfo *B)
  469. {
  470. //
  471. // Rule 1: Avoid unusable destinations.
  472. //
  473. if (A->Flags & SAI_FLAG_DONTUSE) {
  474. if (B->Flags & SAI_FLAG_DONTUSE)
  475. return 0; // No preference.
  476. else
  477. return -1; // Prefer B.
  478. }
  479. else {
  480. if (B->Flags & SAI_FLAG_DONTUSE)
  481. return 1; // Prefer A.
  482. else
  483. ; // Fall through to code below.
  484. }
  485. if ((A->Flags & SAI_FLAG_SCOPE_MISMATCH) !=
  486. (B->Flags & SAI_FLAG_SCOPE_MISMATCH)) {
  487. //
  488. // Rule 2: Prefer matching scope.
  489. //
  490. if (A->Flags & SAI_FLAG_SCOPE_MISMATCH)
  491. return -1; // Prefer B.
  492. else
  493. return 1; // Prefer A.
  494. }
  495. if ((A->Flags & SAI_FLAG_DEPRECATED) !=
  496. (B->Flags & SAI_FLAG_DEPRECATED)) {
  497. //
  498. // Rule 3: Avoid deprecated addresses.
  499. //
  500. if (A->Flags & SAI_FLAG_DEPRECATED)
  501. return -1; // Prefer B.
  502. else
  503. return 1; // Prefer A.
  504. }
  505. //
  506. // Rule 4: Prefer home addresses.
  507. // Not yet implemented, pending mobility support.
  508. //
  509. if ((A->Flags & SAI_FLAG_LABEL_MISMATCH) !=
  510. (B->Flags & SAI_FLAG_LABEL_MISMATCH)) {
  511. //
  512. // Rule 5: Prefer matching label.
  513. //
  514. if (A->Flags & SAI_FLAG_LABEL_MISMATCH)
  515. return -1; // Prefer B.
  516. else
  517. return 1; // Prefer A.
  518. }
  519. if ((A->Precedence != (uint)-1) &&
  520. (B->Precedence != (uint)-1) &&
  521. (A->Precedence != B->Precedence)) {
  522. //
  523. // Rule 6: Prefer higher precedence.
  524. //
  525. if (A->Precedence > B->Precedence)
  526. return 1; // Prefer A.
  527. else
  528. return -1; // Prefer B.
  529. }
  530. if (A->Preference != B->Preference) {
  531. //
  532. // Rule 7: Prefer *lower* preference.
  533. // For example, this is used to prefer destinations reached via
  534. // physical (native) interfaces over virtual (tunnel) interfaces.
  535. //
  536. if (A->Preference < B->Preference)
  537. return 1; // Prefer A.
  538. else
  539. return -1; // Prefer B.
  540. }
  541. if (A->Scope != B->Scope) {
  542. //
  543. // Rule 8: Prefer smaller scope.
  544. //
  545. if (A->Scope < B->Scope)
  546. return 1; // Prefer A.
  547. else
  548. return -1; // Prefer B.
  549. }
  550. if (A->CommonPrefixLen != B->CommonPrefixLen) {
  551. //
  552. // Rule 9: Use longest matching prefix.
  553. //
  554. if (A->CommonPrefixLen > B->CommonPrefixLen)
  555. return 1; // Prefer A.
  556. else
  557. return -1; // Prefer B.
  558. }
  559. //
  560. // We have no preference.
  561. //
  562. return 0;
  563. }
  564. //* SortDestAddresses
  565. //
  566. // Sorts the input array of addresses,
  567. // from most preferred destination to least preferred.
  568. //
  569. // The address array is read-only;
  570. // the Key array of indices is sorted.
  571. //
  572. void
  573. SortDestAddresses(
  574. const TDI_ADDRESS_IP6 *Addrs,
  575. uint *Key,
  576. uint NumAddrs)
  577. {
  578. SortAddrInfo *Info;
  579. uint i, j;
  580. Info = ExAllocatePool(NonPagedPool, sizeof *Info * NumAddrs);
  581. if (Info == NULL) {
  582. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_NTOS_ERROR,
  583. "SortDestAddresses: no pool\n"));
  584. return;
  585. }
  586. //
  587. // Calculate some information about each destination address.
  588. // This will be the basis for our sort.
  589. //
  590. for (i = 0; i < NumAddrs; i++) {
  591. SortAddrInfo *info = &Info[i];
  592. const TDI_ADDRESS_IP6 *Tdi = &Addrs[Key[i]];
  593. const IPv6Addr *Addr = (const IPv6Addr *) &Tdi->sin6_addr;
  594. uint DstLabel, SrcLabel;
  595. //
  596. // Lookup the precedence of this destination address and
  597. // the desired label for source addresses used
  598. // with this destination.
  599. //
  600. PrefixPolicyLookup(Addr, &info->Precedence, NULL, &DstLabel);
  601. if (IsV4Mapped(Addr)) {
  602. IPAddr V4Dest = ExtractV4Address(Addr);
  603. IPAddr V4Source;
  604. info->Scope = V4AddressScope(V4Dest);
  605. if (TunnelGetSourceAddress(V4Dest, &V4Source)) {
  606. IPv6Addr Source;
  607. //
  608. // Create an IPv4-mapped address.
  609. //
  610. CreateV4Mapped(&Source, V4Source);
  611. info->Flags = 0;
  612. info->CommonPrefixLen = (uchar)
  613. CommonPrefixLength(Addr, &Source);
  614. if (V4AddressScope(V4Source) != info->Scope)
  615. info->Flags |= SAI_FLAG_SCOPE_MISMATCH;
  616. //
  617. // Lookup the label of the preferred source address.
  618. //
  619. PrefixPolicyLookup(&Source, NULL, &SrcLabel, NULL);
  620. //
  621. // We do not know interface/route metrics
  622. // for IPv4, so just use zero.
  623. //
  624. info->Preference = 0;
  625. if ((DstLabel != (uint)-1) &&
  626. (SrcLabel != (uint)-1) &&
  627. (DstLabel != SrcLabel)) {
  628. //
  629. // The best source address for this destination
  630. // does not match the destination.
  631. //
  632. info->Flags |= SAI_FLAG_LABEL_MISMATCH;
  633. }
  634. }
  635. else
  636. info->Flags = SAI_FLAG_DONTUSE;
  637. }
  638. else {
  639. RouteCacheEntry *RCE;
  640. info->Scope = AddressScope(Addr);
  641. //
  642. // Find the preferred source address for this destination.
  643. //
  644. if (RouteToDestination(Addr, Tdi->sin6_scope_id,
  645. NULL, 0, &RCE) == IP_SUCCESS) {
  646. const IPv6Addr *Source = &RCE->NTE->Address;
  647. Interface *IF = RCE->NCE->IF;
  648. info->Flags = 0;
  649. info->CommonPrefixLen = (uchar)
  650. CommonPrefixLength(Addr, Source);
  651. if (RCE->NTE->Scope != info->Scope)
  652. info->Flags |= SAI_FLAG_SCOPE_MISMATCH;
  653. if (RCE->NTE->DADState != DAD_STATE_PREFERRED)
  654. info->Flags |= SAI_FLAG_DEPRECATED;
  655. //
  656. // Lookup the label of the preferred source address.
  657. //
  658. PrefixPolicyLookup(Source, NULL, &SrcLabel, NULL);
  659. //
  660. // REVIEW - Instead of using interface preference,
  661. // would it be better to cache interface+route preference
  662. // in the RCE?
  663. //
  664. info->Preference = IF->Preference;
  665. //
  666. // If the next-hop is definitely unreachable,
  667. // then we don't want to use this destination.
  668. // NB: No locking here, this is a heuristic check.
  669. //
  670. if ((IF->Flags & IF_FLAG_MEDIA_DISCONNECTED) ||
  671. RCE->NCE->IsUnreachable)
  672. info->Flags |= SAI_FLAG_DONTUSE;
  673. ReleaseRCE(RCE);
  674. if ((DstLabel != (uint)-1) &&
  675. (SrcLabel != (uint)-1) &&
  676. (DstLabel != SrcLabel)) {
  677. //
  678. // The best source address for this destination
  679. // does not match the destination.
  680. //
  681. info->Flags |= SAI_FLAG_LABEL_MISMATCH;
  682. }
  683. }
  684. else
  685. info->Flags = SAI_FLAG_DONTUSE;
  686. }
  687. }
  688. //
  689. // Perform the actual sort operation.
  690. // Because we expect NumAddrs to be small,
  691. // we use a simple quadratic sort.
  692. //
  693. ASSERT(NumAddrs > 0);
  694. for (i = 0; i < NumAddrs - 1; i++) {
  695. for (j = i + 1; j < NumAddrs; j++) {
  696. int Compare;
  697. //
  698. // As a tie-breaker, if the comparison function
  699. // has no preference we look at the original
  700. // position of the two addresses and prefer
  701. // the one that came first.
  702. //
  703. Compare = CompareSortAddrInfo(&Info[i], &Info[j]);
  704. if ((Compare < 0) ||
  705. ((Compare == 0) && (Key[j] < Key[i]))) {
  706. uint TempKey;
  707. SortAddrInfo TempInfo;
  708. //
  709. // Address j is preferred over address i,
  710. // so swap addresses i & j to put j first.
  711. //
  712. TempKey = Key[i];
  713. Key[i] = Key[j];
  714. Key[j] = TempKey;
  715. //
  716. // We also have to swap the address info.
  717. //
  718. TempInfo = Info[i];
  719. Info[i] = Info[j];
  720. Info[j] = TempInfo;
  721. }
  722. }
  723. }
  724. ExFreePool(Info);
  725. }