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.

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