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.

4101 lines
125 KiB

  1. // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil -*- (for GNU Emacs)
  2. //
  3. // Copyright (c) 1998-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. // Routing routines for Internet Protocol Version 6.
  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. #include "icmp.h"
  22. #include "neighbor.h"
  23. #include "alloca.h"
  24. #include "ipinfo.h"
  25. #include "info.h"
  26. //
  27. // Forward declarations of internal functions.
  28. //
  29. extern void
  30. DestroyBCE(BindingCacheEntry *BCE);
  31. KSPIN_LOCK RouteCacheLock;
  32. KSPIN_LOCK RouteTableLock;
  33. struct RouteCache RouteCache;
  34. struct RouteTable RouteTable;
  35. ulong RouteCacheValidationCounter;
  36. struct BindingCache BindingCache;
  37. SitePrefixEntry *SitePrefixTable = NULL;
  38. LIST_ENTRY RouteNotifyQueue;
  39. int ForceRouterAdvertisements = FALSE;
  40. //* RemoveRTE
  41. //
  42. // Remove the RTE from the route table.
  43. //
  44. // Called with the route cache lock held.
  45. // Callable from a thread or DPC context.
  46. //
  47. void
  48. RemoveRTE(RouteTableEntry **PrevRTE, RouteTableEntry *RTE)
  49. {
  50. ASSERT(*RouteTable.Last == NULL);
  51. ASSERT(*PrevRTE == RTE);
  52. *PrevRTE = RTE->Next;
  53. if (RouteTable.Last == &RTE->Next)
  54. RouteTable.Last = PrevRTE;
  55. }
  56. //* InsertRTEAtFront
  57. //
  58. // Insert the RTE at the front of the route table.
  59. //
  60. // Called with the route cache lock held.
  61. // Callable from a thread or DPC context.
  62. //
  63. void
  64. InsertRTEAtFront(RouteTableEntry *RTE)
  65. {
  66. ASSERT(*RouteTable.Last == NULL);
  67. RTE->Next = RouteTable.First;
  68. RouteTable.First = RTE;
  69. if (RouteTable.Last == &RouteTable.First)
  70. RouteTable.Last = &RTE->Next;
  71. }
  72. //* InsertRTEAtBack
  73. //
  74. // Insert the RTE at the back of the route table.
  75. //
  76. // Called with the route cache lock held.
  77. // Callable from a thread or DPC context.
  78. //
  79. void
  80. InsertRTEAtBack(RouteTableEntry *RTE)
  81. {
  82. ASSERT(*RouteTable.Last == NULL);
  83. RTE->Next = NULL;
  84. *RouteTable.Last = RTE;
  85. RouteTable.Last = &RTE->Next;
  86. if (RouteTable.First == NULL)
  87. RouteTable.First = RTE;
  88. }
  89. //* InsertRCE
  90. //
  91. // Insert the RCE in the route cache.
  92. //
  93. // Called with the route cache lock held.
  94. // Callable from a thread or DPC context.
  95. //
  96. void
  97. InsertRCE(RouteCacheEntry *RCE)
  98. {
  99. RouteCacheEntry *AfterRCE = SentinelRCE;
  100. RCE->Prev = AfterRCE;
  101. (RCE->Next = AfterRCE->Next)->Prev = RCE;
  102. AfterRCE->Next = RCE;
  103. RouteCache.Count++;
  104. }
  105. //* RemoveRCE
  106. //
  107. // Remove the RCE from the route cache.
  108. //
  109. // Called with the route cache lock held.
  110. // Callable from a thread or DPC context.
  111. //
  112. void
  113. RemoveRCE(RouteCacheEntry *RCE)
  114. {
  115. RCE->Prev->Next = RCE->Next;
  116. RCE->Next->Prev = RCE->Prev;
  117. RouteCache.Count--;
  118. //
  119. // We must ensure that an RCE not in the route cache
  120. // has a null BCE. This is because DestroyBCE only
  121. // updates RCEs in the route cache.
  122. //
  123. RCE->BCE = NULL;
  124. }
  125. //* MoveToFrontRCE
  126. //
  127. // Move an RCE to the front of the list.
  128. //
  129. // Called with the route cache lock held.
  130. // Callable from a thread or DPC context.
  131. //
  132. void
  133. MoveToFrontRCE(RouteCacheEntry *RCE)
  134. {
  135. if (RCE->Prev != SentinelRCE) {
  136. RouteCacheEntry *AfterRCE = SentinelRCE;
  137. //
  138. // Remove the RCE from its current location.
  139. //
  140. RCE->Prev->Next = RCE->Next;
  141. RCE->Next->Prev = RCE->Prev;
  142. //
  143. // And put it at the front.
  144. //
  145. RCE->Prev = AfterRCE;
  146. (RCE->Next = AfterRCE->Next)->Prev = RCE;
  147. AfterRCE->Next = RCE;
  148. }
  149. }
  150. //* GetCareOfRCE
  151. //
  152. // Get the CareOfRCE, if any, for the specified RCE.
  153. //
  154. // Note that a reference is obtained for the CareOfRCE
  155. // and donated to the caller.
  156. //
  157. // Callable from a thread or DPC context.
  158. // Called with NO locks held.
  159. //
  160. RouteCacheEntry *
  161. GetCareOfRCE(RouteCacheEntry *RCE)
  162. {
  163. KIRQL OldIrql;
  164. RouteCacheEntry *CareOfRCE = NULL;
  165. if (RCE->BCE != NULL) {
  166. KeAcquireSpinLock(&RouteCacheLock, &OldIrql);
  167. if (RCE->BCE != NULL) {
  168. CareOfRCE = RCE->BCE->CareOfRCE;
  169. AddRefRCE(CareOfRCE);
  170. }
  171. KeReleaseSpinLock(&RouteCacheLock, OldIrql);
  172. }
  173. return CareOfRCE;
  174. }
  175. //* IsLoopbackRCE
  176. //
  177. // Does the effective RCE correspond to a loopback path?
  178. //
  179. // Called with NO locks held.
  180. //
  181. int
  182. IsLoopbackRCE(RouteCacheEntry *RCE)
  183. {
  184. RouteCacheEntry *CareOfRCE;
  185. int IsLoopback;
  186. CareOfRCE = GetCareOfRCE(RCE);
  187. if (CareOfRCE != NULL)
  188. RCE = CareOfRCE; // Update with the effective RCE.
  189. IsLoopback = RCE->NCE->IsLoopback;
  190. if (CareOfRCE != NULL)
  191. ReleaseRCE(CareOfRCE);
  192. return IsLoopback;
  193. }
  194. //* GetInitialRTTFromRCE
  195. // Helper routine to get interface specific RTT.
  196. //
  197. // Called with NO locks held.
  198. uint
  199. GetInitialRTTFromRCE(RouteCacheEntry *RCE)
  200. {
  201. RouteCacheEntry *CareOfRCE;
  202. NeighborCacheEntry *NCE;
  203. uint RTT;
  204. CareOfRCE = GetCareOfRCE(RCE);
  205. NCE = (CareOfRCE ? CareOfRCE : RCE)->NCE;
  206. RTT = NCE->IF->TcpInitialRTT;
  207. if (CareOfRCE)
  208. ReleaseRCE(CareOfRCE);
  209. return RTT;
  210. }
  211. //* IsDisconnectedAndNotLoopbackRCE
  212. //
  213. // Does the effective RCE have a disconnected outgoing interface
  214. // and not correspond to a loopback path?
  215. //
  216. // Called with NO locks held.
  217. //
  218. int
  219. IsDisconnectedAndNotLoopbackRCE(RouteCacheEntry *RCE)
  220. {
  221. RouteCacheEntry *CareOfRCE;
  222. int IsDisconnectedAndNotLoopback;
  223. CareOfRCE = GetCareOfRCE(RCE);
  224. if (CareOfRCE != NULL)
  225. RCE = CareOfRCE; // Update with the effective RCE.
  226. IsDisconnectedAndNotLoopback = !RCE->NCE->IsLoopback &&
  227. (RCE->NCE->IF->Flags & IF_FLAG_MEDIA_DISCONNECTED);
  228. if (CareOfRCE != NULL)
  229. ReleaseRCE(CareOfRCE);
  230. return IsDisconnectedAndNotLoopback;
  231. }
  232. //* GetV4Destination
  233. //
  234. // If sending via the RCE will result in tunneling a packet
  235. // to an IPv4 destination, returns the IPv4 destination address.
  236. // Otherwise returns INADDR_ANY.
  237. //
  238. IPAddr
  239. GetV4Destination(RouteCacheEntry *RCE)
  240. {
  241. RouteCacheEntry *CareOfRCE;
  242. NeighborCacheEntry *NCE;
  243. Interface *IF;
  244. IPAddr V4Dest;
  245. KIRQL OldIrql;
  246. CareOfRCE = GetCareOfRCE(RCE);
  247. if (CareOfRCE != NULL)
  248. RCE = CareOfRCE; // Update with the effective RCE.
  249. NCE = RCE->NCE;
  250. IF = NCE->IF;
  251. if (IsIPv4TunnelIF(IF)) {
  252. ASSERT(IF->LinkAddressLength == sizeof(IPAddr));
  253. KeAcquireSpinLock(&IF->LockNC, &OldIrql);
  254. if (NCE->NDState != ND_STATE_INCOMPLETE)
  255. V4Dest = * (IPAddr UNALIGNED *) NCE->LinkAddress;
  256. else
  257. V4Dest = INADDR_ANY;
  258. KeReleaseSpinLock(&IF->LockNC, OldIrql);
  259. }
  260. else {
  261. V4Dest = INADDR_ANY;
  262. }
  263. if (CareOfRCE != NULL)
  264. ReleaseRCE(CareOfRCE);
  265. return V4Dest;
  266. }
  267. //* ValidateCareOfRCE
  268. //
  269. // Helper function for ValidateRCE and RouteToDestination.
  270. //
  271. // Checks that the CareOfRCE (RCE->BCE->CareOfRCE) is still valid, and
  272. // if not, releases the existing CareOfRCE and updates RCE->BCE with a
  273. // new RCE.
  274. //
  275. // If the attempt to get a new RCE fails, the BCE is destroyed.
  276. //
  277. // Called with the route cache locked.
  278. //
  279. void
  280. ValidateCareOfRCE(RouteCacheEntry *RCE)
  281. {
  282. RouteCacheEntry *CareOfRCE;
  283. IPv6Addr *CareOfAddr;
  284. ushort CareOfScope;
  285. uint CareOfScopeId;
  286. RouteCacheEntry *NewRCE;
  287. IP_STATUS Status;
  288. ASSERT(RCE->BCE != NULL);
  289. CareOfRCE = RCE->BCE->CareOfRCE;
  290. if (CareOfRCE->Valid != RouteCacheValidationCounter) {
  291. //
  292. // Note that since we already hold the RouteCacheLock we
  293. // call FindOrCreateRoute instead of RouteToDestination.
  294. // Also, we assume the care-of address is scoped to the
  295. // same interface as before.
  296. //
  297. CareOfAddr = &(CareOfRCE->Destination);
  298. CareOfScope = AddressScope(CareOfAddr);
  299. CareOfScopeId = CareOfRCE->NTE->IF->ZoneIndices[CareOfScope];
  300. Status = FindOrCreateRoute(CareOfAddr, CareOfScopeId, NULL, &NewRCE);
  301. if (Status == IP_SUCCESS) {
  302. //
  303. // Update the binding cache entry.
  304. //
  305. ReleaseRCE(CareOfRCE);
  306. RCE->BCE->CareOfRCE = NewRCE;
  307. }
  308. else {
  309. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INTERNAL_ERROR,
  310. "ValidateCareOfRCE(%p): FindOrCreateRoute failed: %x\n",
  311. CareOfRCE, Status));
  312. //
  313. // Because we could not update the BCE, destroy it.
  314. //
  315. DestroyBCE(RCE->BCE);
  316. //
  317. // Destroy BCE should have removed our reference too.
  318. //
  319. ASSERT(RCE->BCE == NULL);
  320. }
  321. }
  322. }
  323. //* ValidateRCE
  324. //
  325. // Checks that an RCE is still valid, and if not, releases
  326. // the RCE and returns a reference for a new RCE.
  327. // In any case, returns a pointer to an RCE.
  328. //
  329. // REVIEW: Perhaps ValidateRCE should take an NTE argument.
  330. // On routers, if the caller is using a scoped source address,
  331. // which may be a different address than RCE->NTE,
  332. // then this will affect RouteToDestination.
  333. //
  334. // Called with NO locks held.
  335. //
  336. RouteCacheEntry *
  337. ValidateRCE(RouteCacheEntry *RCE)
  338. {
  339. if (RCE->Valid != RouteCacheValidationCounter) {
  340. RouteCacheEntry *NewRCE;
  341. IP_STATUS Status;
  342. //
  343. // Get a new RCE to replace the current RCE.
  344. // RouteToDestination will calculate ScopeId.
  345. // REVIEW: If this fails, then continue to use the current RCE.
  346. // This way our callers don't have to check for errors.
  347. //
  348. Status = RouteToDestination(&RCE->Destination, 0,
  349. CastFromNTE(RCE->NTE), RTD_FLAG_NORMAL,
  350. &NewRCE);
  351. if (Status == IP_SUCCESS) {
  352. ReleaseRCE(RCE);
  353. RCE = NewRCE;
  354. } else {
  355. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INTERNAL_ERROR,
  356. "ValidateRCE(%p): RouteToDestination failed: %x\n",
  357. RCE, Status));
  358. }
  359. }
  360. //
  361. // Validate and update the CareOfRCE before we return.
  362. //
  363. if (RCE->BCE != NULL) {
  364. KIRQL OldIrql;
  365. KeAcquireSpinLock(&RouteCacheLock, &OldIrql);
  366. if (RCE->BCE != NULL)
  367. ValidateCareOfRCE(RCE);
  368. KeReleaseSpinLock(&RouteCacheLock, OldIrql);
  369. }
  370. return RCE;
  371. }
  372. //* CreateOrReuseRoute
  373. //
  374. // Creates a new RCE. Attempts to reuse an existing RCE.
  375. //
  376. // Called with the route cache lock held.
  377. // Callable from a thread or DPC context.
  378. //
  379. // Returns NULL if a new RCE can not be allocated.
  380. // The RefCnt field in the returned RCE is initialized to one.
  381. //
  382. // REVIEW: Currently we have an upper-bound on the number of RCEs.
  383. // Probably a better scheme would take into account the time
  384. // since last use.
  385. //
  386. RouteCacheEntry *
  387. CreateOrReuseRoute(void)
  388. {
  389. RouteCacheEntry *RCE;
  390. if (RouteCache.Count >= RouteCache.Limit) {
  391. //
  392. // First search backwards for an unused RCE.
  393. //
  394. for (RCE = RouteCache.Last; RCE != SentinelRCE; RCE = RCE->Prev) {
  395. if (RCE->RefCnt == 1) {
  396. //
  397. // We can reuse this RCE.
  398. //
  399. RemoveRCE(RCE);
  400. ReleaseNCE(RCE->NCE);
  401. ReleaseNTE(RCE->NTE);
  402. return RCE;
  403. }
  404. }
  405. }
  406. //
  407. // Create a new RCE.
  408. //
  409. RCE = ExAllocatePool(NonPagedPool, sizeof *RCE);
  410. if (RCE == NULL)
  411. return NULL;
  412. RCE->RefCnt = 1;
  413. return RCE;
  414. }
  415. //* RouteCacheCheck
  416. //
  417. // Check the route cache's consistency. Ensure that
  418. // a) There is only one RCE for an interface/destination pair, and
  419. // b) There is at most one valid unconstrained RCE for the destination.
  420. //
  421. // Called with the route cache locked.
  422. //
  423. #if DBG
  424. void
  425. RouteCacheCheck(RouteCacheEntry *CheckRCE, ulong CurrentValidationCounter)
  426. {
  427. const IPv6Addr *Dest = &CheckRCE->Destination;
  428. Interface *IF = CheckRCE->NTE->IF;
  429. ushort Scope = AddressScope(Dest);
  430. uint ScopeId = IF->ZoneIndices[Scope];
  431. uint NumTotal = 0;
  432. uint NumUnconstrainedIF = 0;
  433. uint NumUnconstrained = 0;
  434. RouteCacheEntry *RCE;
  435. //
  436. // Scan the route cache looking for problems.
  437. //
  438. for (RCE = RouteCache.First; RCE != SentinelRCE; RCE = RCE->Next) {
  439. NumTotal++;
  440. if (IP6_ADDR_EQUAL(&RCE->Destination, Dest)) {
  441. if (RCE->NTE->IF == IF) {
  442. //
  443. // There should only be one RCE in the cache
  444. // for an interface/destination pair.
  445. // (There may be other, invalid RCEs not in the cache.)
  446. //
  447. ASSERT(RCE == CheckRCE);
  448. }
  449. //
  450. // RCE_FLAG_CONSTRAINED_IF implies RCE_FLAG_CONSTRAINED_SCOPEID.
  451. //
  452. ASSERT(!(RCE->Flags & RCE_FLAG_CONSTRAINED_IF) ||
  453. (RCE->Flags & RCE_FLAG_CONSTRAINED_SCOPEID));
  454. if (RCE->Valid == CurrentValidationCounter) {
  455. if ((RCE->NTE->IF->ZoneIndices[Scope] == ScopeId) &&
  456. !(RCE->Flags & RCE_FLAG_CONSTRAINED_IF))
  457. NumUnconstrainedIF++;
  458. if (!(RCE->Flags & RCE_FLAG_CONSTRAINED))
  459. NumUnconstrained++;
  460. }
  461. }
  462. }
  463. //
  464. // There should be at most one valid unconstrained RCE
  465. // for this scope-id/destination.
  466. //
  467. ASSERT(NumUnconstrainedIF <= 1);
  468. //
  469. // There should be at most one valid unconstrained RCE
  470. // for this destination.
  471. //
  472. ASSERT(NumUnconstrained <= 1);
  473. //
  474. // The total should be correct.
  475. //
  476. ASSERT(NumTotal == RouteCache.Count);
  477. }
  478. #else // DBG
  479. __inline void
  480. RouteCacheCheck(RouteCacheEntry *CheckRCE, ulong CurrentValidationCounter)
  481. {
  482. }
  483. #endif // DBG
  484. //* CanonicalizeScopeId
  485. //
  486. // Given an address and ScopeId, converts the ScopeId for internal usage.
  487. // Also returns the address scope.
  488. //
  489. // Returns FALSE if the ScopeId is invalid.
  490. //
  491. __inline int // Encourage the compiler to inline if it wishes.
  492. CanonicalizeScopeId(
  493. const IPv6Addr *Addr,
  494. uint *ScopeId,
  495. ushort *Scope)
  496. {
  497. //
  498. // The loopback address and global-scope addresses are special:
  499. // callers can supply a zero ScopeId without ambiguity.
  500. // See also DetermineScopeId and RouteToDestination.
  501. // For the moment, we enforce a zero ScopeId for those addresses
  502. // lest we confuse TCP & UDP by having two legal ScopeId values
  503. // for a single address which should be considered the same and
  504. // for which DetermineScopeId returns zero.
  505. //
  506. *Scope = AddressScope(Addr);
  507. if (IsLoopback(Addr)) {
  508. if (*ScopeId == 0)
  509. *ScopeId = LoopInterface->ZoneIndices[*Scope];
  510. else
  511. return FALSE;
  512. }
  513. else if (*Scope == ADE_GLOBAL) {
  514. if (*ScopeId == 0)
  515. *ScopeId = 1;
  516. else
  517. return FALSE;
  518. }
  519. return TRUE;
  520. }
  521. //* RouteToDestination - Find a route to a particular destination.
  522. //
  523. // Finds an existing, or creates a new, route cache entry for
  524. // a particular destination. Note the destination address may
  525. // only be valid in a particular scope.
  526. //
  527. // The optional NTEorIF argument specifies the interface
  528. // and/or the source address that should be used to reach the destination.
  529. // The Flags argument affects the interpretation of NTEorIF.
  530. // If RTD_FLAG_STRICT, then NTEorIF constrains whether or not it specifies
  531. // a forwarding interface. If RTD_FLAG_LOOSE, then NTEorIF is only used
  532. // for determining/checking ScopeId and otherwise does not constrain.
  533. //
  534. // Called with NO locks held.
  535. //
  536. // Return codes:
  537. // IP_NO_RESOURCES Couldn't allocate memory.
  538. // IP_PARAMETER_PROBLEM Illegal Dest/ScopeId.
  539. // IP_BAD_ROUTE Bad NTEorIF for this destination,
  540. // or could not find an NTE.
  541. // IP_DEST_NO_ROUTE No way to reach the destination.
  542. //
  543. // IP_DEST_NO_ROUTE can only be returned if NTEorIF is NULL.
  544. //
  545. // NB: The return code values and situations in which they are used
  546. // in RouteToDestination and its helper functions must be carefully
  547. // considered, both for RouteToDestination's own correctness
  548. // and for the correctness of callers.
  549. //
  550. IP_STATUS // Returns: whether call was sucessful and/or why not.
  551. RouteToDestination(
  552. const IPv6Addr *Dest, // Destination address to route to.
  553. uint ScopeId, // Scope id for Dest (may be 0).
  554. NetTableEntryOrInterface *NTEorIF, // IF to send from (may be NULL).
  555. uint Flags, // Control optional behaviors.
  556. RouteCacheEntry **ReturnRCE) // Returns pointer to cached route.
  557. {
  558. Interface *IF;
  559. KIRQL OldIrql;
  560. IP_STATUS ReturnValue;
  561. ushort Scope;
  562. //
  563. // Pre-calculate Scope for scoped addresses (saves time in the loop).
  564. // Note that callers can supply ScopeId == 0 for a scoped address,
  565. // meaning that they are not constraining the scoped address
  566. // to a particular zone.
  567. //
  568. if (! CanonicalizeScopeId(Dest, &ScopeId, &Scope))
  569. return IP_PARAMETER_PROBLEM;
  570. if (NTEorIF != NULL) {
  571. //
  572. // Our caller is constraining the originating interface.
  573. //
  574. IF = NTEorIF->IF;
  575. //
  576. // First, check this against ScopeId.
  577. //
  578. if (ScopeId == 0)
  579. ScopeId = IF->ZoneIndices[Scope];
  580. else if (ScopeId != IF->ZoneIndices[Scope])
  581. return IP_BAD_ROUTE;
  582. //
  583. // Depending on Flags and whether this is forwarding interface,
  584. // we may ignore this specification and look at all interfaces.
  585. // Logically, the packet is originated by the specified interface
  586. // but then internally forwarded to the outgoing interface.
  587. // (Although we will not decrement the Hop Count.)
  588. // As when forwarding, we check after finding the best route
  589. // if the route will cause the packet to leave
  590. // the scope of the source address.
  591. //
  592. // It is critical that the route cache lookup and FindNextHop
  593. // computation use only IF and not NTEorIF. This is necessary
  594. // for the maintenance of the cache invariants. Once we have
  595. // an RCE (or an error), then we can check against NTEorIF.
  596. //
  597. switch (Flags) {
  598. case RTD_FLAG_LOOSE:
  599. IF = NULL;
  600. break;
  601. case RTD_FLAG_NORMAL:
  602. if (IF->Flags & IF_FLAG_FORWARDS)
  603. IF = NULL;
  604. break;
  605. case RTD_FLAG_STRICT:
  606. break;
  607. default:
  608. ASSERT(! "bad RouteToDestination Flags");
  609. break;
  610. }
  611. }
  612. else {
  613. //
  614. // Our caller is not constraining the originating interface.
  615. //
  616. IF = NULL;
  617. }
  618. KeAcquireSpinLock(&RouteCacheLock, &OldIrql);
  619. ReturnValue = FindOrCreateRoute(Dest, ScopeId, IF, ReturnRCE);
  620. if ((NTEorIF != NULL) && (IF == NULL) && (Flags == RTD_FLAG_NORMAL)) {
  621. //
  622. // Our caller specified a forwarding interface,
  623. // and we ignored the interface constraint.
  624. // There are a couple cases in which we should
  625. // retry, preserving the interface constraint.
  626. // NB: In the IPv6Forward paths, NTEorIF is NULL.
  627. // So this check only applies to originating packets.
  628. //
  629. if (ReturnValue == IP_SUCCESS) {
  630. if (IsNTE(NTEorIF)) {
  631. RouteCacheEntry *RCE = *ReturnRCE;
  632. NetTableEntry *NTE = CastToNTE(NTEorIF);
  633. Interface *OriginatingIF = NTE->IF;
  634. Interface *OutgoingIF = RCE->NTE->IF;
  635. //
  636. // Does this route carry the packet outside
  637. // the scope of the specified source address?
  638. //
  639. if (OutgoingIF->ZoneIndices[NTE->Scope] !=
  640. OriginatingIF->ZoneIndices[NTE->Scope]) {
  641. ReleaseRCE(RCE);
  642. goto Retry;
  643. }
  644. }
  645. }
  646. else if (ReturnValue == IP_DEST_NO_ROUTE) {
  647. //
  648. // Retry, allowing the destination
  649. // to be considered on-link to the specified interface.
  650. //
  651. Retry:
  652. IF = NTEorIF->IF;
  653. ReturnValue = FindOrCreateRoute(Dest, ScopeId, IF, ReturnRCE);
  654. }
  655. }
  656. //
  657. // Validate and update the CareOfRCE before we return.
  658. //
  659. if ((ReturnValue == IP_SUCCESS) && ((*ReturnRCE)->BCE != NULL))
  660. ValidateCareOfRCE(*ReturnRCE);
  661. KeReleaseSpinLock(&RouteCacheLock, OldIrql);
  662. return ReturnValue;
  663. }
  664. //* FindOrCreateRoute
  665. //
  666. // Helper function for RouteToDestination and RedirectRouteCache.
  667. //
  668. // See the RouteToDestination description of return codes.
  669. // IP_DEST_NO_ROUTE can only be returned if IF is NULL.
  670. // RouteToDestination may retry FindOrCreateRoute with a non-null IF
  671. // when it gets IP_DEST_NO_ROUTE.
  672. //
  673. // Called with the route cache locked.
  674. //
  675. IP_STATUS
  676. FindOrCreateRoute(
  677. const IPv6Addr *Dest, // Destination address to route to.
  678. uint ScopeId, // Scope id for Dest (0 if non-scoped).
  679. Interface *IF, // IF to send from (may be NULL).
  680. RouteCacheEntry **ReturnRCE) // Returns pointer to cached route.
  681. {
  682. ulong CurrentValidationCounter;
  683. RouteCacheEntry *SaveRCE = NULL;
  684. RouteCacheEntry *RCE;
  685. RouteCacheEntry *NextRCE;
  686. Interface *TmpIF;
  687. NeighborCacheEntry *NCE;
  688. NetTableEntry *NTE;
  689. ushort Constrained;
  690. KIRQL OldIrql;
  691. IP_STATUS ReturnValue;
  692. ushort Scope;
  693. //
  694. // Precompute and save some time in the loop.
  695. //
  696. Scope = AddressScope(Dest);
  697. ASSERT((IF == NULL) ||
  698. ((ScopeId != 0) && (ScopeId == IF->ZoneIndices[Scope])));
  699. //
  700. // For consistency, snapshot RouteCacheValidationCounter.
  701. //
  702. CurrentValidationCounter = RouteCacheValidationCounter;
  703. //
  704. // Check for an existing route cache entry.
  705. // There are two main cases.
  706. //
  707. // If IF is not NULL, then there is at most one matching RCE
  708. // in the cache. If this RCE does not validate, then we can use
  709. // the results of FindNextHop/FindBestSourceAddress when creating
  710. // the new RCE.
  711. //
  712. // If IF is NULL, then there may be more than one matching RCE.
  713. // We can only reuse the results of the validating FindNextHop/
  714. // FindBestSourceAddress iff FindRoute returned Constrained == 0.
  715. //
  716. for (RCE = RouteCache.First; RCE != SentinelRCE; RCE = NextRCE) {
  717. NextRCE = RCE->Next;
  718. //
  719. // We want a route to the requested destination, obviously.
  720. //
  721. if (!IP6_ADDR_EQUAL(Dest, &RCE->Destination))
  722. continue;
  723. TmpIF = RCE->NTE->IF;
  724. //
  725. // Check for a caller-imposed interface constraint.
  726. //
  727. if (IF == NULL) {
  728. //
  729. // We're not constrained to a particular interface, so
  730. // there may be multiple routes to this destination in
  731. // the cache to choose from. Don't pick a constrained RCE.
  732. //
  733. if (RCE->Flags & RCE_FLAG_CONSTRAINED_IF) {
  734. //
  735. // If this RCE is invalid, then RCE_FLAG_CONSTRAINED_IF
  736. // might be stale information. We do not want to pass
  737. // by this RCE and then later create another RCE
  738. // for the same interface/destination pair.
  739. //
  740. if (RCE->Valid != CurrentValidationCounter)
  741. goto AttemptValidation;
  742. continue;
  743. }
  744. //
  745. // Check for a ScopeId constraint.
  746. //
  747. if (ScopeId == 0) {
  748. //
  749. // We're not constrained to a particular zone, so
  750. // there may be multiple routes to this destination in
  751. // the cache to choose from. Don't pick a constrained RCE.
  752. //
  753. if (RCE->Flags & RCE_FLAG_CONSTRAINED_SCOPEID) {
  754. //
  755. // If this RCE is invalid, RCE_FLAG_CONSTRAINED_SCOPEID
  756. // might be stale information. We do not want to pass
  757. // by this RCE and then later create another RCE
  758. // for the same interface/destination pair.
  759. //
  760. if (RCE->Valid != CurrentValidationCounter)
  761. goto AttemptValidation;
  762. continue;
  763. }
  764. } else {
  765. //
  766. // We're constrained to a particular zone.
  767. // If this route uses a different one, keep looking.
  768. //
  769. if (ScopeId != TmpIF->ZoneIndices[Scope])
  770. continue;
  771. }
  772. } else {
  773. //
  774. // We're constrained to a particular interface.
  775. // If this route uses a different one, keep looking.
  776. //
  777. if (IF != TmpIF)
  778. continue;
  779. ASSERT((ScopeId != 0) && (ScopeId == TmpIF->ZoneIndices[Scope]));
  780. }
  781. //
  782. // At this point, we have a RCE that matches our criteria.
  783. // As long as the RCE is still valid, we're done.
  784. //
  785. if (RCE->Valid == CurrentValidationCounter) {
  786. IF = TmpIF;
  787. goto ReturnRCE;
  788. }
  789. AttemptValidation:
  790. //
  791. // Something has changed in the routing state since the last
  792. // time this RCE was validated. Attempt to revalidate it.
  793. // We calculate a new NTE and NCE for this destination,
  794. // restricting ourselves to sending from the same interface.
  795. // Note that because we are validating an RCE,
  796. // the arguments to FindNextHop are completely dependent on
  797. // the contents of the RCE, not the arguments to FindOrCreateRoute.
  798. //
  799. ReturnValue = FindNextHop(TmpIF, Dest, TmpIF->ZoneIndices[Scope],
  800. &NCE, &Constrained);
  801. if (ReturnValue != IP_SUCCESS)
  802. goto RemoveAndContinue;
  803. ASSERT((IF == NULL) || (IF == TmpIF));
  804. ASSERT(TmpIF == RCE->NTE->IF);
  805. ASSERT(TmpIF == RCE->NCE->IF);
  806. NTE = FindBestSourceAddress(TmpIF, Dest);
  807. if (NTE == NULL) {
  808. ReleaseNCE(NCE);
  809. RemoveAndContinue:
  810. //
  811. // Bad news for this RCE.
  812. // We must remove it from the cache
  813. // before we continue searching,
  814. // lest we inadvertently create a second RCE
  815. // for the same interface/destination pair.
  816. //
  817. RemoveRCE(RCE);
  818. ReleaseRCE(RCE);
  819. continue;
  820. }
  821. //
  822. // If our new calculations yield the same NTE and NCE that
  823. // are present in the existing RCE, than we can just validate it.
  824. // Note that we check the NCE even if this is a Redirect RCE.
  825. // If the routing table changes, we want to start over with
  826. // a new first-hop, which might just redirect us again. Or might not.
  827. //
  828. if ((RCE->NTE == NTE) &&
  829. (RCE->NCE == NCE) &&
  830. (RCE->Flags == Constrained)) {
  831. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_STATE,
  832. "FindOrCreateRoute - validating RCE %p\n", RCE));
  833. RCE->Valid = CurrentValidationCounter;
  834. ReleaseNCE(NCE);
  835. ReleaseNTE(NTE);
  836. //
  837. // We need to check again that the RCE meets the criteria.
  838. // We may have checked the RCE validity because the RCE
  839. // appeared to be constrained and we need an unconstrained RCE.
  840. // So in that case, if the RCE validated we can't actually use it.
  841. // NB: ScopeId == 0 implies IF == NULL.
  842. //
  843. if ((ScopeId == 0) ?
  844. (Constrained & RCE_FLAG_CONSTRAINED) :
  845. ((IF == NULL) && (Constrained & RCE_FLAG_CONSTRAINED_IF)))
  846. continue;
  847. IF = TmpIF;
  848. goto ReturnRCE;
  849. }
  850. //
  851. // We can't just validate the existing RCE, we need to update
  852. // it. If the RCE has exactly one reference, we could update it
  853. // in place (this wouldn't work if it has more than one reference
  854. // since there is no way to signal the RCE's other users that the
  855. // NCE and/or NTE it caches has changed). But this wouldn't help
  856. // the case where we are called from ValidateRCE. And it would
  857. // require some care as to which information in the RCE is still
  858. // valid. So we ignore this optimization opportunity and will
  859. // create a new RCE instead.
  860. //
  861. // However, we can take advantage of another optimization. As
  862. // long as we're still limiting our interface choice to the one
  863. // that is present in the existing (invalid) RCE, and there isn't
  864. // a better route available, then we can use the NCE and NTE we
  865. // got from FindNextHop and FindBestSourceAddress above to create
  866. // our new RCE since we aren't going to find a better one.
  867. // NB: ScopeId == 0 implies IF == NULL.
  868. //
  869. if ((ScopeId == 0) ?
  870. !(Constrained & RCE_FLAG_CONSTRAINED) :
  871. ((IF != NULL) || !(Constrained & RCE_FLAG_CONSTRAINED_IF))) {
  872. //
  873. // Since some of the state information in the existing RCE
  874. // is still valid, we hang onto it so we can use it later
  875. // when creating the new RCE. We assume ownership of the
  876. // cache's reference for the invalid RCE.
  877. //
  878. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_STATE,
  879. "FindOrCreateRoute - saving RCE %p\n", RCE));
  880. RemoveRCE(RCE);
  881. SaveRCE = RCE;
  882. IF = TmpIF;
  883. goto HaveNCEandNTE;
  884. }
  885. ReleaseNTE(NTE);
  886. ReleaseNCE(NCE);
  887. //
  888. // Not valid, we keep looking for a valid matching RCE.
  889. //
  890. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_STATE,
  891. "FindOrCreateRoute - invalid RCE %p\n", RCE));
  892. }
  893. //
  894. // No existing RCE found. Before creating a new RCE,
  895. // we determine a next-hop neighbor (NCE) and
  896. // a best source address (NTE) for this destination.
  897. // The order is important: we want to avoid churning
  898. // the cache via CreateOrReuseRoute if we will just
  899. // get an error anyway.
  900. // This prevents a denial-of-service attack.
  901. //
  902. ReturnValue = FindNextHop(IF, Dest, ScopeId,
  903. &NCE, &Constrained);
  904. if (ReturnValue != IP_SUCCESS)
  905. goto ReturnError;
  906. ASSERT((IF == NULL) || (IF == NCE->IF));
  907. IF = NCE->IF;
  908. //
  909. // Find the best source address for this destination.
  910. // (The NTE from our caller might not be the best.)
  911. // By restricting ourselves to the interface returned
  912. // by FindNextHop above, we know we haven't left our
  913. // particular scope.
  914. //
  915. NTE = FindBestSourceAddress(IF, Dest);
  916. if (NTE == NULL) {
  917. //
  918. // We have no valid source address to use!
  919. //
  920. ReturnValue = IP_BAD_ROUTE;
  921. ReleaseNCE(NCE);
  922. goto ReturnError;
  923. }
  924. HaveNCEandNTE:
  925. //
  926. // Get a new route cache entry.
  927. // Because SaveRCE was just removed from the cache,
  928. // CreateOrReuseRoute will not find it.
  929. //
  930. RCE = CreateOrReuseRoute();
  931. if (RCE == NULL) {
  932. ReturnValue = IP_NO_RESOURCES;
  933. ReleaseNTE(NTE);
  934. ReleaseNCE(NCE);
  935. goto ReturnError;
  936. }
  937. //
  938. // FindOrCreateNeighbor/FindRoute (called from FindNextHop) gave
  939. // us a reference for the NCE. We donate that reference to the RCE.
  940. // Similarly, FindBestSourceAddress gave us a reference
  941. // for the NTE and we donate the reference to the RCE.
  942. //
  943. RCE->NCE = NCE;
  944. RCE->NTE = NTE;
  945. RCE->PathMTU = IF->LinkMTU;
  946. RCE->PMTULastSet = 0; // PMTU timer not running.
  947. RCE->Destination = *Dest;
  948. RCE->Type = RCE_TYPE_COMPUTED;
  949. RCE->Flags = Constrained;
  950. // Start with a value safely in the past.
  951. RCE->LastError = IPv6TickCount - ICMP_MIN_ERROR_INTERVAL;
  952. RCE->BCE = FindBindingCacheEntry(Dest);
  953. RCE->Valid = CurrentValidationCounter;
  954. //
  955. // Copy state from a previous RCE for this destination,
  956. // if we have it and the state is relevant.
  957. //
  958. if (SaveRCE != NULL) {
  959. ASSERT(SaveRCE->NTE->IF == RCE->NTE->IF);
  960. //
  961. // PathMTU is relevant if the next-hop neighbor is unchanged.
  962. //
  963. if (RCE->NCE == SaveRCE->NCE) {
  964. RCE->PathMTU = SaveRCE->PathMTU;
  965. RCE->PMTULastSet = SaveRCE->PMTULastSet;
  966. }
  967. //
  968. // ICMP rate-limiting information is always relevant.
  969. //
  970. RCE->LastError = SaveRCE->LastError;
  971. }
  972. //
  973. // Add the new route cache entry to the cache.
  974. //
  975. InsertRCE(RCE);
  976. ReturnRCE:
  977. //
  978. // If the RCE is not at the front of the cache, move it there.
  979. //
  980. MoveToFrontRCE(RCE);
  981. ASSERT(IF == RCE->NTE->IF);
  982. //
  983. // Check route cache consistency.
  984. //
  985. RouteCacheCheck(RCE, CurrentValidationCounter);
  986. AddRefRCE(RCE);
  987. ASSERT(RCE->RefCnt >= 2); // One held by the cache, one for our caller.
  988. *ReturnRCE = RCE;
  989. ReturnValue = IP_SUCCESS;
  990. ReturnError:
  991. if (SaveRCE != NULL)
  992. ReleaseRCE(SaveRCE);
  993. return ReturnValue;
  994. }
  995. //* FindNextHop
  996. //
  997. // Calculate the next hop to use for the destination.
  998. //
  999. // FindNextHop is just FindRoute plus some extra logic
  1000. // to handle the case where there is no route:
  1001. // RFC 2461 Section 5.2 specifies "If the Default Router List
  1002. // is empty, the sender assumes that the destination is on-link."
  1003. // The question is, on-link to which interface?
  1004. //
  1005. // Callable from DPC context, not from thread context.
  1006. // May be called with the RouteCacheLock held.
  1007. //
  1008. IP_STATUS
  1009. FindNextHop(
  1010. Interface *IF, // Outgoing IF (may be NULL).
  1011. const IPv6Addr *Dest, // Destination address to route to.
  1012. uint ScopeId, // Scope id for Dest (0 if non-scoped).
  1013. NeighborCacheEntry **ReturnNCE, // NCE for next hop.
  1014. ushort *ReturnConstrained)
  1015. {
  1016. NeighborCacheEntry *NCE;
  1017. IP_STATUS Status;
  1018. ushort Constrained;
  1019. ushort Scope;
  1020. Interface *ScopeIF;
  1021. Scope = AddressScope(Dest);
  1022. ASSERT((IF == NULL) ||
  1023. ((ScopeId != 0) && (ScopeId == IF->ZoneIndices[Scope])));
  1024. //
  1025. // An unspecified destination is never legal here.
  1026. //
  1027. if (IsUnspecified(Dest)) {
  1028. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  1029. "FindNextHop - inappropriate dest?\n"));
  1030. return IP_PARAMETER_PROBLEM;
  1031. }
  1032. //
  1033. // FindRoute treats link-local and multicast destinations
  1034. // somewhat specially. It also checks for on-link prefixes.
  1035. // It implements the On-Link Prefix List and Default Router List
  1036. // lookups specified in RFC 2461 section 5.2.
  1037. //
  1038. Status = FindRoute(IF, Dest, ScopeId, &NCE, ReturnConstrained);
  1039. if (Status == IP_SUCCESS)
  1040. goto ReturnSuccess;
  1041. //
  1042. // We have no route for the destination.
  1043. // We should treat the destination as being on-link.
  1044. // But on-link to which interface?
  1045. //
  1046. Status = FindDefaultInterfaceForZone(Scope, ScopeId,
  1047. &ScopeIF, &Constrained);
  1048. // FindDefaultInterfaceForZone must always initialize ScopeIF.
  1049. if (IF != NULL) {
  1050. //
  1051. // Assume that the destination is on-link
  1052. // to the specified interface.
  1053. //
  1054. AddRefIF(IF);
  1055. if (IF == ScopeIF) {
  1056. //
  1057. // If the IF argument were not specified,
  1058. // we would have chosen this same interface.
  1059. // Use Constrained value from FindDefaultInterfaceForZone.
  1060. //
  1061. }
  1062. else {
  1063. //
  1064. // We needed the IF argument.
  1065. //
  1066. Constrained = RCE_FLAG_CONSTRAINED;
  1067. }
  1068. if (ScopeIF != NULL)
  1069. ReleaseIF(ScopeIF);
  1070. }
  1071. else if (ScopeIF == NULL) {
  1072. //
  1073. // FindUniqueInterfaceFromZone returned either IP_DEST_NO_ROUTE
  1074. // (meaning the ScopeId did not specify a default interface)
  1075. // or IP_PARAMETER_PROBLEM (meaning the ScopeId was invalid).
  1076. //
  1077. ASSERT((Status == IP_DEST_NO_ROUTE) ||
  1078. (Status == IP_PARAMETER_PROBLEM));
  1079. return Status;
  1080. }
  1081. else {
  1082. //
  1083. // Use the default interface in the correct zone.
  1084. // Use Constrained value from FindDefaultInterfaceForZone.
  1085. //
  1086. IF = ScopeIF;
  1087. }
  1088. //
  1089. // Assume that the destination address is on-link.
  1090. // Search the interface's neighbor cache for the destination.
  1091. //
  1092. NCE = FindOrCreateNeighbor(IF, Dest);
  1093. ReleaseIF(IF);
  1094. if (NCE == NULL) {
  1095. return IP_NO_RESOURCES;
  1096. }
  1097. *ReturnConstrained = Constrained;
  1098. ReturnSuccess:
  1099. *ReturnNCE = NCE;
  1100. return IP_SUCCESS;
  1101. }
  1102. //* CompareRoutes
  1103. //
  1104. // Compares the desirability of two routes.
  1105. // >0 means A is preferred,
  1106. // 0 means no preference,
  1107. // <0 means B is preferred.
  1108. //
  1109. // It is very important that the comparison relation be transitive,
  1110. // to achieve predictable route selection.
  1111. //
  1112. // Called with the route table locked.
  1113. //
  1114. int
  1115. CompareRoutes(
  1116. RouteTableEntry *A,
  1117. int Areachable,
  1118. RouteTableEntry *B,
  1119. int Breachable)
  1120. {
  1121. uint Apref, Bpref;
  1122. //
  1123. // Compare reachability.
  1124. //
  1125. if (Areachable > Breachable)
  1126. return 1; // Prefer A.
  1127. else if (Breachable > Areachable)
  1128. return -1; // Prefer B.
  1129. //
  1130. // Compare prefix length.
  1131. //
  1132. if (A->PrefixLength > B->PrefixLength)
  1133. return 1; // Prefer A.
  1134. else if (B->PrefixLength > A->PrefixLength)
  1135. return -1; // Prefer B.
  1136. //
  1137. // Compare preference.
  1138. // Route & interface preference values are restricted
  1139. // so that these additions do not overflow.
  1140. //
  1141. Apref = A->IF->Preference + A->Preference;
  1142. Bpref = B->IF->Preference + B->Preference;
  1143. if (Apref < Bpref)
  1144. return 1; // Prefer A.
  1145. else if (Bpref < Apref)
  1146. return -1; // Prefer B.
  1147. return 0; // No preference.
  1148. }
  1149. //* FindRoute
  1150. //
  1151. // Given a destination address, checks the list of routes
  1152. // using the longest-matching-prefix algorithm
  1153. // to decide if we have a route to this address.
  1154. // If so, returns the neighbor through which we should route.
  1155. //
  1156. // If the optional IF is supplied, then this constrains the lookup
  1157. // to only use routes via the specified outgoing interface.
  1158. // If IF is specified then ScopeId should be specified.
  1159. //
  1160. // If the optional ScopeId is supplied, then this constraints the lookup
  1161. // to only use routes via interfaces in the correct zone for the
  1162. // scope of the destination address.
  1163. //
  1164. // The ReturnConstrained parameter returns an indication of whether the
  1165. // IF and ScopeId parameters constrained the returned NCE.
  1166. // That is, if IF is NULL and ScopeId is non-zero (for scoped destinations)
  1167. // then Constrained is always returned as zero. If IF is non-NULL and
  1168. // a different NCE is returned than would have been returned if IF were
  1169. // NULL, then Constrained is returned with RCE_FLAG_CONSTRAINED_IF set.
  1170. // Similarly, if ScopeId is non-zero and a different NCE is returned
  1171. // than would have been returned if ScopeId were zero, then Constrained
  1172. // is returned with RCE_FLAG_CONSTRAINED_SCOPEID set.
  1173. //
  1174. // NOTE: Any code path that changes any state used by FindRoute
  1175. // must use InvalidateRouteCache.
  1176. //
  1177. // Callable from DPC context, not from thread context.
  1178. // May be called with the RouteCacheLock held.
  1179. //
  1180. IP_STATUS
  1181. FindRoute(
  1182. Interface *IF,
  1183. const IPv6Addr *Dest,
  1184. uint ScopeId,
  1185. NeighborCacheEntry **ReturnNCE,
  1186. ushort *ReturnConstrained)
  1187. {
  1188. RouteTableEntry *RTE, **PrevRTE;
  1189. NeighborCacheEntry *NCE;
  1190. uint MinPrefixLength;
  1191. NeighborReachability Reachable;
  1192. ushort Scope;
  1193. //
  1194. // These variables track the best route that we can actually return,
  1195. // subject to the IF and ScopeId constraints.
  1196. //
  1197. NeighborCacheEntry *BestNCE = NULL; // Holds a reference.
  1198. RouteTableEntry *BestRTE; // Initialized when BestNCE is non-NULL.
  1199. NeighborReachability BestReachable; // Used when BestNCE is non-NULL.
  1200. //
  1201. // These variables track the best route in the right zone.
  1202. // They are only used if IF != NULL.
  1203. //
  1204. NeighborCacheEntry *BzoneNCE = NULL; // Does NOT hold a reference.
  1205. RouteTableEntry *BzoneRTE; // Initialized when BzoneNCE is non-NULL.
  1206. NeighborReachability BzoneReachable; // Used when BzoneNCE is non-NULL.
  1207. //
  1208. // These variables track the best unconstrained route.
  1209. // They are only used if IF != NULL or ScopeId != 0:
  1210. // in other words, if there is some constraint.
  1211. //
  1212. NeighborCacheEntry *BallNCE = NULL; // Does NOT hold a reference.
  1213. RouteTableEntry *BallRTE; // Initialized when BallNCE is non-NULL.
  1214. NeighborReachability BallReachable; // Used when BallNCE is non-NULL.
  1215. //
  1216. // Keep track of whether there could be a better route
  1217. // than the one we are returning, if a neighbor that is
  1218. // currently unreachable were reachable instead.
  1219. //
  1220. int CouldBeBetterReachable = FALSE;
  1221. //
  1222. // Keep track of whether the destination could be on-link
  1223. // to an interface.
  1224. //
  1225. int CouldBeBetterOnLink = FALSE;
  1226. //
  1227. // We enforce a minimum prefix length for "on-link" addresses.
  1228. // If we match a route that is shorter than the minimum prefix length,
  1229. // we treat the route as if it were on-link. The net effect is
  1230. // that a default route implies a default interface for multicast
  1231. // and link-local destinations. This may of course be overridden
  1232. // with the appropriate more-specific /8 or /10 route.
  1233. //
  1234. if (IsMulticast(Dest))
  1235. MinPrefixLength = 8;
  1236. else if (IsLinkLocal(Dest))
  1237. MinPrefixLength = 10;
  1238. else
  1239. MinPrefixLength = 0;
  1240. //
  1241. // Calculate the scope of the destination address.
  1242. //
  1243. Scope = AddressScope(Dest);
  1244. ASSERT((IF == NULL) ||
  1245. ((ScopeId != 0) && (ScopeId == IF->ZoneIndices[Scope])));
  1246. KeAcquireSpinLockAtDpcLevel(&RouteTableLock);
  1247. PrevRTE = &RouteTable.First;
  1248. while ((RTE = *PrevRTE) != NULL) {
  1249. //
  1250. // Does this route's prefix match that of our destination address?
  1251. //
  1252. if ((RTE->ValidLifetime != 0) &&
  1253. (RTE->PrefixLength >= MinPrefixLength) &&
  1254. HasPrefix(Dest, &RTE->Prefix, RTE->PrefixLength)) {
  1255. //
  1256. // We have a match against a potential route.
  1257. // Get a pointer to the next hop.
  1258. //
  1259. if (IsOnLinkRTE(RTE)) {
  1260. //
  1261. // Note that in some situations we will create an NCE
  1262. // that we will end up not using. That's OK.
  1263. //
  1264. NCE = FindOrCreateNeighbor(RTE->IF, Dest);
  1265. if (NCE == NULL) {
  1266. //
  1267. // Couldn't create a new neighbor.
  1268. // Just bail out now.
  1269. //
  1270. KeReleaseSpinLockFromDpcLevel(&RouteTableLock);
  1271. if (BestNCE != NULL)
  1272. ReleaseNCE(BestNCE);
  1273. return IP_NO_RESOURCES;
  1274. }
  1275. } else {
  1276. NCE = RTE->NCE;
  1277. AddRefNCE(NCE);
  1278. }
  1279. //
  1280. // Note that reachability state transitions
  1281. // must invalidate the route cache.
  1282. // A negative return value indicates
  1283. // that the neighbor was just found to be unreachable
  1284. // so we should round-robin.
  1285. //
  1286. Reachable = GetReachability(NCE);
  1287. if (Reachable < 0) {
  1288. //
  1289. // Time for round-robin. Move this route to the end
  1290. // and continue. The next time we get to this route,
  1291. // GetReachability will return a non-negative value.
  1292. //
  1293. // Because round-robin perturbs route table state,
  1294. // it "should" invalidate the route cache. However,
  1295. // this isn't necessary. The route cache is invalidated
  1296. // when NCE->DoRoundRobin is set to TRUE, and the
  1297. // round-robin is actually performed by FindRoute before
  1298. // returning any result that could depend on this
  1299. // route's position in the route table.
  1300. //
  1301. ReleaseNCE(NCE);
  1302. RemoveRTE(PrevRTE, RTE);
  1303. InsertRTEAtBack(RTE);
  1304. continue;
  1305. }
  1306. //
  1307. // Track the best route that we can actually return,
  1308. // subject to the IF and ScopeId constraints.
  1309. //
  1310. if ((IF == NULL) ?
  1311. ((ScopeId == 0) || (ScopeId == RTE->IF->ZoneIndices[Scope])) :
  1312. (IF == RTE->IF)) {
  1313. if (IsOnLinkRTE(RTE))
  1314. CouldBeBetterOnLink = TRUE;
  1315. if (BestNCE == NULL) {
  1316. //
  1317. // This is the first suitable next hop,
  1318. // so remember it.
  1319. //
  1320. RememberBest:
  1321. AddRefNCE(NCE);
  1322. BestNCE = NCE;
  1323. BestRTE = RTE;
  1324. BestReachable = Reachable;
  1325. }
  1326. else {
  1327. int Better;
  1328. Better = CompareRoutes(RTE, Reachable,
  1329. BestRTE, BestReachable);
  1330. //
  1331. // If this is a route via a currently-unreachable neighbor,
  1332. // check if it appears that it might be a better route
  1333. // if the neighbor were reachable.
  1334. //
  1335. if (!CouldBeBetterReachable &&
  1336. (Reachable == NeighborUnreachable) &&
  1337. (CompareRoutes(RTE, NeighborMayBeReachable,
  1338. BestRTE, BestReachable) > Better))
  1339. CouldBeBetterReachable = TRUE;
  1340. if (Better > 0) {
  1341. //
  1342. // This next hop looks better.
  1343. //
  1344. ReleaseNCE(BestNCE);
  1345. goto RememberBest;
  1346. }
  1347. }
  1348. }
  1349. //
  1350. // If there is a constraining interface, we also track
  1351. // the best next hop subject to the ScopeId constraint
  1352. // but NOT the interface constraint. Note that we do NOT
  1353. // hold a reference for BzoneNCE. All we need to know
  1354. // eventually is whether BzoneNCE == BestNCE and
  1355. // we hold a ref for BestNCE, which is good enough.
  1356. //
  1357. if ((IF != NULL) &&
  1358. (ScopeId == RTE->IF->ZoneIndices[Scope])) {
  1359. if (BzoneNCE == NULL) {
  1360. //
  1361. // This is the first suitable next hop,
  1362. // so remember it.
  1363. //
  1364. RememberBzone:
  1365. BzoneNCE = NCE;
  1366. BzoneRTE = RTE;
  1367. BzoneReachable = Reachable;
  1368. }
  1369. else if (CompareRoutes(RTE, Reachable,
  1370. BzoneRTE, BzoneReachable) > 0) {
  1371. //
  1372. // This next hop looks better.
  1373. //
  1374. goto RememberBzone;
  1375. }
  1376. }
  1377. //
  1378. // If there is a constraining interface or ScopeId, we also
  1379. // track the best overall next hop. Note that we do NOT
  1380. // hold a reference for BallNCE. All we need to know
  1381. // eventually is whether BallNCE == BestNCE and
  1382. // we hold a ref for BestNCE, which is good enough.
  1383. //
  1384. if ((IF != NULL) || (ScopeId != 0)) {
  1385. if (BallNCE == NULL) {
  1386. //
  1387. // This is the first suitable next hop,
  1388. // so remember it.
  1389. //
  1390. RememberBall:
  1391. BallNCE = NCE;
  1392. BallRTE = RTE;
  1393. BallReachable = Reachable;
  1394. }
  1395. else if (CompareRoutes(RTE, Reachable,
  1396. BallRTE, BallReachable) > 0) {
  1397. //
  1398. // This next hop looks better.
  1399. //
  1400. goto RememberBall;
  1401. }
  1402. }
  1403. ReleaseNCE(NCE);
  1404. }
  1405. //
  1406. // Move on to the next route.
  1407. //
  1408. PrevRTE = &RTE->Next;
  1409. }
  1410. ASSERT(PrevRTE == RouteTable.Last);
  1411. //
  1412. // If the destination could be on-link and we actually selected
  1413. // an on-link route, then we are OK. Otherwise, we need to check
  1414. // if the destination could be on-link to the interface
  1415. // that we selected. This implements one aspect of RFC 2461's
  1416. // conceptual sending algorithm - the Prefix List is consulted
  1417. // before the Default Router List. Note that RFC 2461 does not
  1418. // consider multi-interface hosts and we only enforce a preference for
  1419. // on-link routes within the context of a single interface.
  1420. // If we choose a router on an interface when we could have chosen
  1421. // on-link to the interface, the router would presumably just
  1422. // Redirect us, so it's better to just send on-link even if the
  1423. // destination is not reachable on-link. If the destination
  1424. // is on-link but not reachable via one interface,
  1425. // then we are happy to send off-link via another interface.
  1426. // This may or may not succeed in reaching the destination,
  1427. // but at least it has a chance of succeeding.
  1428. // The CouldBeBetterReachable code will periodically probe
  1429. // the destination's on-link reachability.
  1430. //
  1431. if (CouldBeBetterOnLink && IsOnLinkRTE(BestRTE))
  1432. CouldBeBetterOnLink = FALSE;
  1433. if (CouldBeBetterReachable || CouldBeBetterOnLink) {
  1434. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_STATE,
  1435. "FindRoute: 2nd pass: Dest %s "
  1436. "CBBReachable %d CBBOnLink %d BestRTE %p BestNCE %p\n",
  1437. FormatV6Address(Dest),
  1438. CouldBeBetterReachable, CouldBeBetterOnLink,
  1439. BestRTE, BestNCE));
  1440. //
  1441. // Make a second pass over the routes.
  1442. //
  1443. for (RTE = RouteTable.First; RTE != NULL; RTE = RTE->Next) {
  1444. //
  1445. // Does this route's prefix match that of our destination address?
  1446. // And check our interface/scope-id constraints.
  1447. //
  1448. if ((RTE->ValidLifetime != 0) &&
  1449. (RTE->PrefixLength >= MinPrefixLength) &&
  1450. HasPrefix(Dest, &RTE->Prefix, RTE->PrefixLength) &&
  1451. ((IF == NULL) ?
  1452. ((ScopeId == 0) || (ScopeId == RTE->IF->ZoneIndices[Scope])) :
  1453. (IF == RTE->IF))) {
  1454. //
  1455. // Would this be a better route
  1456. // if the neighbor were reachable?
  1457. //
  1458. if (CouldBeBetterReachable &&
  1459. CompareRoutes(RTE, NeighborMayBeReachable,
  1460. BestRTE, BestReachable) > 0) {
  1461. //
  1462. // OK, we want to know if this neighbor becomes reachable,
  1463. // because if it does we should change our routing.
  1464. //
  1465. if (IsOnLinkRTE(RTE))
  1466. NCE = FindOrCreateNeighbor(RTE->IF, Dest);
  1467. else
  1468. AddRefNCE(NCE = RTE->NCE);
  1469. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_STATE,
  1470. "FindRoute: CBBReachable: "
  1471. "BestRTE %p BestNCE %p RTE %p NCE %p\n",
  1472. BestRTE, BestNCE, RTE, NCE));
  1473. if (NCE != NULL) {
  1474. NeighborCacheProbeUnreachability(NCE);
  1475. ReleaseNCE(NCE);
  1476. }
  1477. }
  1478. //
  1479. // Is this an on-link route on the same interface
  1480. // that we chosen to use off-link?
  1481. //
  1482. if (CouldBeBetterOnLink &&
  1483. IsOnLinkRTE(RTE) && (RTE->IF == BestRTE->IF)) {
  1484. //
  1485. // OK, we want to send directly to this destination.
  1486. // Switch to the on-link NCE.
  1487. //
  1488. NCE = FindOrCreateNeighbor(RTE->IF, Dest);
  1489. ReleaseNCE(BestNCE);
  1490. if (NCE == NULL) {
  1491. KeReleaseSpinLockFromDpcLevel(&RouteTableLock);
  1492. return IP_NO_RESOURCES;
  1493. }
  1494. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_STATE,
  1495. "FindRoute: CBBOnLink: "
  1496. "BestRTE %p BestNCE %p RTE %p NCE %p\n",
  1497. BestRTE, BestNCE, RTE, NCE));
  1498. if (BallNCE == BestNCE)
  1499. BallNCE = NCE;
  1500. if (BzoneNCE == BestNCE)
  1501. BzoneNCE = NCE;
  1502. BestNCE = NCE;
  1503. CouldBeBetterOnLink = FALSE;
  1504. }
  1505. }
  1506. }
  1507. }
  1508. //
  1509. // We can drop the lock and still do comparisons
  1510. // against BallNCE and BzoneNCE.
  1511. //
  1512. KeReleaseSpinLockFromDpcLevel(&RouteTableLock);
  1513. if (BestNCE != NULL) {
  1514. *ReturnNCE = BestNCE;
  1515. if ((ScopeId == 0) || (BestNCE == BallNCE)) {
  1516. //
  1517. // The IF and ScopeId arguments did not affect our BestNCE choice.
  1518. //
  1519. *ReturnConstrained = 0;
  1520. }
  1521. else if ((IF == NULL) || (BestNCE == BzoneNCE)) {
  1522. //
  1523. // The IF argument did not affect our BestNCE choice,
  1524. // but the ScopeId argument did.
  1525. //
  1526. *ReturnConstrained = RCE_FLAG_CONSTRAINED_SCOPEID;
  1527. }
  1528. else {
  1529. //
  1530. // The IF argument affected our BestNCE choice.
  1531. //
  1532. *ReturnConstrained = RCE_FLAG_CONSTRAINED;
  1533. }
  1534. return IP_SUCCESS;
  1535. }
  1536. else {
  1537. //
  1538. // Didn't find a suitable next hop.
  1539. //
  1540. return IP_DEST_NO_ROUTE;
  1541. }
  1542. }
  1543. //* FlushRouteCache
  1544. //
  1545. // Flushes entries from the route cache.
  1546. // The Interface or the Address can be left unspecified.
  1547. // in which case all relevant entries are flushed.
  1548. //
  1549. // Note that even if an RCE has references,
  1550. // we can still remove it from the route cache.
  1551. // It will continue to exist until its ref count falls to zero,
  1552. // but subsequent calls to RouteToDestination will not find it.
  1553. //
  1554. // Called with NO locks held.
  1555. // Callable from thread or DPC context.
  1556. //
  1557. void
  1558. FlushRouteCache(Interface *IF, const IPv6Addr *Addr)
  1559. {
  1560. RouteCacheEntry *Delete = NULL;
  1561. RouteCacheEntry *RCE, *NextRCE;
  1562. KIRQL OldIrql;
  1563. //
  1564. // REVIEW: If both IF and Addr are specified,
  1565. // we can bail out of the loop early.
  1566. //
  1567. KeAcquireSpinLock(&RouteCacheLock, &OldIrql);
  1568. for (RCE = RouteCache.First; RCE != SentinelRCE; RCE = NextRCE) {
  1569. NextRCE = RCE->Next;
  1570. if (((IF == NULL) ||
  1571. (IF == RCE->NTE->IF)) &&
  1572. ((Addr == NULL) ||
  1573. IP6_ADDR_EQUAL(Addr, &RCE->Destination))) {
  1574. //
  1575. // We can remove this RCE from the cache.
  1576. //
  1577. RemoveRCE(RCE);
  1578. //
  1579. // Put it on our delete list.
  1580. //
  1581. RCE->Next = Delete;
  1582. Delete = RCE;
  1583. }
  1584. }
  1585. KeReleaseSpinLock(&RouteCacheLock, OldIrql);
  1586. //
  1587. // Release the RCE references that were held by the route cache.
  1588. //
  1589. while (Delete != NULL) {
  1590. RCE = Delete;
  1591. Delete = RCE->Next;
  1592. //
  1593. // Prevent use of this RCE by anyone who has it cached.
  1594. //
  1595. InvalidateRCE(RCE);
  1596. ReleaseRCE(RCE);
  1597. }
  1598. }
  1599. //* ReleaseRCE
  1600. //
  1601. // Releases a reference to an RCE.
  1602. // Sometimes called with the route cache lock held.
  1603. //
  1604. void
  1605. ReleaseRCE(RouteCacheEntry *RCE)
  1606. {
  1607. if (InterlockedDecrement(&RCE->RefCnt) == 0) {
  1608. //
  1609. // This RCE should be deallocated.
  1610. // It has already been removed from the cache.
  1611. //
  1612. ReleaseNTE(RCE->NTE);
  1613. ReleaseNCE(RCE->NCE);
  1614. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_STATE,
  1615. "Freeing RCE: %p\n",RCE));
  1616. ExFreePool(RCE);
  1617. }
  1618. }
  1619. //* FindNetworkWithAddress - Locate NTE with corresponding address and scope.
  1620. //
  1621. // Convert a source address to an NTE by scanning the list of NTEs,
  1622. // looking for an NTE with this address. If the address is scope
  1623. // specific, the ScopeId provided should identify the scope.
  1624. //
  1625. // Returns NULL if no matching NTE is found.
  1626. // If found, returns a reference for the NTE.
  1627. //
  1628. NetTableEntry *
  1629. FindNetworkWithAddress(const IPv6Addr *Source, uint ScopeId)
  1630. {
  1631. ushort Scope;
  1632. NetTableEntry *NTE;
  1633. KIRQL OldIrql;
  1634. //
  1635. // Canonicalize ScopeId and get Scope.
  1636. //
  1637. if (! CanonicalizeScopeId(Source, &ScopeId, &Scope))
  1638. return NULL;
  1639. KeAcquireSpinLock(&NetTableListLock, &OldIrql);
  1640. //
  1641. // Loop through all the NTEs on the NetTableList.
  1642. //
  1643. for (NTE = NetTableList; ; NTE = NTE->NextOnNTL) {
  1644. if (NTE == NULL)
  1645. goto Return;
  1646. //
  1647. // Have we found an NTE with matching address and ScopeId?
  1648. //
  1649. if (IP6_ADDR_EQUAL(&NTE->Address, Source) &&
  1650. (ScopeId == NTE->IF->ZoneIndices[Scope])) {
  1651. //
  1652. // Check that this NTE is valid.
  1653. // (For example, an NTE still doing DAD is invalid.)
  1654. //
  1655. if (!IsValidNTE(NTE)) {
  1656. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_RARE,
  1657. "FindNetworkWithAddress: invalid NTE\n"));
  1658. NTE = NULL;
  1659. goto Return;
  1660. }
  1661. break;
  1662. }
  1663. }
  1664. AddRefNTE(NTE);
  1665. Return:
  1666. KeReleaseSpinLock(&NetTableListLock, OldIrql);
  1667. return NTE;
  1668. }
  1669. //* InvalidateRouter
  1670. //
  1671. // Called when we know a neighbor is no longer a router.
  1672. // This function implements RFC 2461 section 7.3.3 -
  1673. // when a node detects that a router has changed to a host,
  1674. // the node MUST remove it from the Default Router List.
  1675. // For our implementation, this means removing autoconfigured
  1676. // routes from the routing table.
  1677. //
  1678. // Callable from a thread or DPC context.
  1679. // Called with NO locks held.
  1680. //
  1681. void
  1682. InvalidateRouter(NeighborCacheEntry *NCE)
  1683. {
  1684. CheckRtChangeContext Context;
  1685. RouteTableEntry *RTE, **PrevRTE;
  1686. InitCheckRtChangeContext(&Context);
  1687. KeAcquireSpinLock(&RouteTableLock, &Context.OldIrql);
  1688. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_STATE,
  1689. "Invalidating routes with NCE=%p\n", NCE));
  1690. PrevRTE = &RouteTable.First;
  1691. while((RTE = *PrevRTE) != NULL) {
  1692. if ((RTE->NCE == NCE) &&
  1693. (RTE->Type == RTE_TYPE_AUTOCONF)) {
  1694. //
  1695. // Remove the RTE from the list.
  1696. //
  1697. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_STATE,
  1698. "InvalidateRouter: removed RTE %p\n", RTE));
  1699. RemoveRTE(PrevRTE, RTE);
  1700. //
  1701. // Check for matching route change notification requests.
  1702. //
  1703. CheckRtChangeNotifyRequests(&Context, NULL, RTE);
  1704. //
  1705. // Release the RTE.
  1706. //
  1707. ReleaseNCE(NCE);
  1708. ExFreePool(RTE);
  1709. }
  1710. else {
  1711. PrevRTE = &RTE->Next;
  1712. }
  1713. }
  1714. ASSERT(PrevRTE == RouteTable.Last);
  1715. //
  1716. // Invalidate the route cache, even if the routing table has not changed.
  1717. // We must invalidate any RCEs that are using this NCE,
  1718. // perhaps because of a Redirect.
  1719. //
  1720. InvalidateRouteCache();
  1721. KeReleaseSpinLock(&RouteTableLock, Context.OldIrql);
  1722. if (Context.RequestList != NULL) {
  1723. //
  1724. // Complete the pending route change notifications.
  1725. //
  1726. CompleteRtChangeNotifyRequests(&Context);
  1727. }
  1728. }
  1729. //* RouteTableUpdate - Update the route table.
  1730. //
  1731. // Updates the route table by creating a new route
  1732. // or modifying the lifetime of an existing route.
  1733. //
  1734. // If the NCE is null, then the prefix is on-link.
  1735. // Otherwise the NCE specifies the next hop.
  1736. //
  1737. // REVIEW - Should we do anything special when we get identical
  1738. // routes with different next hops? Currently they both end up
  1739. // in the table, and FindRoute tries to pick the best one.
  1740. //
  1741. // Note that the ValidLifetime may be INFINITE_LIFETIME,
  1742. // whereas Neighbor Discovery does not allow an infinite value
  1743. // for router lifetimes on the wire.
  1744. //
  1745. // The Publish and Immortal boolean arguments control
  1746. // the respective flag bits in the RTE.
  1747. //
  1748. // The FileObject identifies the requestor of this update.
  1749. // It is used to suppress some route change notifications.
  1750. // It should be NULL for updates originating in the stack.
  1751. //
  1752. // The Type argument specifies the origin of the route (RTE_TYPE_* values).
  1753. // The stack itself doesn't care about most of the values.
  1754. // The exceptions are RTE_TYPE_SYSTEM, RTE_TYPE_MANUAL, RTE_TYPE_AUTOCONF.
  1755. // System routes (used for loopback) can not be created/deleted by users.
  1756. // Manual routes are affected by RouteTableReset.
  1757. // Auto-configured routes are affected by RouteTableResetAutoConfig.
  1758. // The Type of a route can not be updated after it is created.
  1759. //
  1760. // System routes and published routes survive in the route table
  1761. // even when their lifetime is zero. (Then they do not affect routing.)
  1762. // To delete a system route, specify a lifetime and type of zero.
  1763. //
  1764. // Error return values:
  1765. // STATUS_INSUFFICIENT_RESOURCES - Failed to allocate pool.
  1766. // STATUS_ACCESS_DENIED - Caller can not create/delete system route.
  1767. // STATUS_INVALID_PARAMETER_1 - Interface is disabled.
  1768. // STATUS_INVALID_PARAMETER_6 - Can not create route with zero Type.
  1769. // These values are chosen for the convenience of IoctlUpdateRouteTable,
  1770. // because our other callers only care about success/failure.
  1771. //
  1772. // Callable from a thread or DPC context.
  1773. // May be called with an interface lock held.
  1774. //
  1775. NTSTATUS
  1776. RouteTableUpdate(
  1777. PFILE_OBJECT FileObject,
  1778. Interface *IF,
  1779. NeighborCacheEntry *NCE,
  1780. const IPv6Addr *RoutePrefix,
  1781. uint PrefixLength,
  1782. uint SitePrefixLength,
  1783. uint ValidLifetime,
  1784. uint PreferredLifetime,
  1785. uint Pref,
  1786. uint Type,
  1787. int Publish,
  1788. int Immortal)
  1789. {
  1790. CheckRtChangeContext Context;
  1791. IPv6Addr Prefix;
  1792. RouteTableEntry *RTE, **PrevRTE;
  1793. int Delete;
  1794. NTSTATUS Status = STATUS_SUCCESS;
  1795. ASSERT((NCE == NULL) || (NCE->IF == IF));
  1796. ASSERT(SitePrefixLength <= PrefixLength);
  1797. ASSERT(PreferredLifetime <= ValidLifetime);
  1798. ASSERT(IsValidRouteTableType(Type));
  1799. //
  1800. // Ensure that the unused prefix bits are zero.
  1801. // This makes the prefix comparisons below safe.
  1802. //
  1803. CopyPrefix(&Prefix, RoutePrefix, PrefixLength);
  1804. Delete = FALSE;
  1805. InitCheckRtChangeContext(&Context);
  1806. KeAcquireSpinLock(&RouteTableLock, &Context.OldIrql);
  1807. if (IsDisabledIF(IF)) {
  1808. //
  1809. // Do not create routes on disabled interfaces.
  1810. // This check must be made after locking the route table,
  1811. // to prevent races with DestroyIF/RouteTableRemove.
  1812. //
  1813. Status = STATUS_INVALID_PARAMETER_1;
  1814. }
  1815. else {
  1816. //
  1817. // Search for an existing Route Table Entry.
  1818. //
  1819. for (PrevRTE = &RouteTable.First; ; PrevRTE = &RTE->Next) {
  1820. RTE = *PrevRTE;
  1821. if (RTE == NULL) {
  1822. ASSERT(PrevRTE == RouteTable.Last);
  1823. //
  1824. // No existing entry for this prefix.
  1825. // Create an entry if the lifetime is non-zero
  1826. // or this is a published route or a system route.
  1827. //
  1828. if ((ValidLifetime != 0) ||
  1829. Publish || (Type == RTE_TYPE_SYSTEM)) {
  1830. if ((Type == RTE_TYPE_SYSTEM) && (FileObject != NULL)) {
  1831. //
  1832. // Users can not create system routes.
  1833. //
  1834. Status = STATUS_ACCESS_DENIED;
  1835. break;
  1836. }
  1837. if (Type == 0) {
  1838. //
  1839. // The zero Type value can only be used
  1840. // for updating and deleting routes.
  1841. //
  1842. Status = STATUS_INVALID_PARAMETER_6;
  1843. break;
  1844. }
  1845. RTE = ExAllocatePool(NonPagedPool, sizeof *RTE);
  1846. if (RTE == NULL) {
  1847. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_NTOS_ERROR,
  1848. "RouteTableUpdate: out of pool\n"));
  1849. Status = STATUS_INSUFFICIENT_RESOURCES;
  1850. break;
  1851. }
  1852. RTE->Type = (ushort)Type;
  1853. RTE->Flags = 0;
  1854. RTE->IF = IF;
  1855. if (NCE != NULL)
  1856. AddRefNCE(NCE);
  1857. RTE->NCE = NCE;
  1858. RTE->Prefix = Prefix;
  1859. RTE->PrefixLength = PrefixLength;
  1860. RTE->SitePrefixLength = SitePrefixLength;
  1861. RTE->ValidLifetime = ValidLifetime;
  1862. RTE->PreferredLifetime = PreferredLifetime;
  1863. RTE->Preference = Pref;
  1864. if (Publish) {
  1865. RTE->Flags |= RTE_FLAG_PUBLISH;
  1866. ForceRouterAdvertisements = TRUE;
  1867. }
  1868. if (Immortal)
  1869. RTE->Flags |= RTE_FLAG_IMMORTAL;
  1870. //
  1871. // Add the new entry to the route table.
  1872. //
  1873. InsertRTEAtFront(RTE);
  1874. if (ValidLifetime != 0) {
  1875. //
  1876. // Invalidate the route cache, so the new route
  1877. // actually gets used.
  1878. //
  1879. InvalidateRouteCache();
  1880. }
  1881. else {
  1882. //
  1883. // Don't notify about this route,
  1884. // since it is being created as invalid.
  1885. //
  1886. RTE = NULL;
  1887. }
  1888. }
  1889. break;
  1890. }
  1891. if ((RTE->IF == IF) && (RTE->NCE == NCE) &&
  1892. IP6_ADDR_EQUAL(&RTE->Prefix, &Prefix) &&
  1893. (RTE->PrefixLength == PrefixLength)) {
  1894. //
  1895. // We have an existing route.
  1896. // Remove the route if the new lifetime is zero
  1897. // (and the route is not published or a system route)
  1898. // otherwise update the route.
  1899. // The Type == 0 clause allows system routes to be deleted.
  1900. //
  1901. if ((ValidLifetime == 0) &&
  1902. !Publish &&
  1903. ((RTE->Type != RTE_TYPE_SYSTEM) || (Type == 0))) {
  1904. if ((RTE->Type == RTE_TYPE_SYSTEM) &&
  1905. (FileObject != NULL)) {
  1906. //
  1907. // Users can not delete system routes.
  1908. //
  1909. Status = STATUS_ACCESS_DENIED;
  1910. break;
  1911. }
  1912. //
  1913. // Remove the RTE from the list.
  1914. // See similar code in RouteTableTimeout.
  1915. //
  1916. RemoveRTE(PrevRTE, RTE);
  1917. if (IsOnLinkRTE(RTE)) {
  1918. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_STATE,
  1919. "Route RTE %p %s/%u -> IF %p removed\n",
  1920. RTE,
  1921. FormatV6Address(&RTE->Prefix),
  1922. RTE->PrefixLength,
  1923. RTE->IF));
  1924. }
  1925. else {
  1926. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_STATE,
  1927. "Route RTE %p %s/%u -> NCE %p removed\n",
  1928. RTE,
  1929. FormatV6Address(&RTE->Prefix),
  1930. RTE->PrefixLength,
  1931. RTE->NCE));
  1932. //
  1933. // Although we release the RTE's reference for the NTE,
  1934. // our caller still holds a reference so RTE->NCE
  1935. // is still valid for CheckRtChangeNotifyRequests.
  1936. //
  1937. ReleaseNCE(RTE->NCE);
  1938. }
  1939. //
  1940. // If we are removing a published route,
  1941. // resend Router Advertisements promptly.
  1942. //
  1943. if (RTE->Flags & RTE_FLAG_PUBLISH)
  1944. ForceRouterAdvertisements = TRUE;
  1945. if (RTE->ValidLifetime == 0) {
  1946. //
  1947. // This route was already invalid.
  1948. // Delete the route structure now.
  1949. //
  1950. ExFreePool(RTE);
  1951. //
  1952. // Don't notify a route change;
  1953. // that was done when the route became invalid.
  1954. //
  1955. RTE = NULL;
  1956. }
  1957. else {
  1958. //
  1959. // Invalidate all cached routes,
  1960. // since we are removing a valid route.
  1961. //
  1962. InvalidateRouteCache();
  1963. //
  1964. // Delete the route structure after checking
  1965. // for route change notifications below.
  1966. //
  1967. Delete = TRUE;
  1968. //
  1969. // Update the route lifetimes, so the route info
  1970. // returned in the notification shows zero lifetime.
  1971. // But preserve the other route attributes.
  1972. //
  1973. RTE->ValidLifetime = RTE->PreferredLifetime = 0;
  1974. }
  1975. }
  1976. else {
  1977. uint OldLifetime = RTE->PreferredLifetime;
  1978. //
  1979. // If we are changing a published attribute of a route,
  1980. // or if we are changing the publishing status of a route,
  1981. // then resend Router Advertisements promptly.
  1982. //
  1983. if ((Publish &&
  1984. ((RTE->ValidLifetime != ValidLifetime) ||
  1985. (RTE->PreferredLifetime != PreferredLifetime) ||
  1986. (RTE->SitePrefixLength != SitePrefixLength))) ||
  1987. (!Publish != !(RTE->Flags & RTE_FLAG_PUBLISH)))
  1988. ForceRouterAdvertisements = TRUE;
  1989. //
  1990. // Pick up new attributes.
  1991. // We do NOT update RTE->Type.
  1992. //
  1993. RTE->SitePrefixLength = SitePrefixLength;
  1994. RTE->ValidLifetime = ValidLifetime;
  1995. RTE->PreferredLifetime = PreferredLifetime;
  1996. RTE->Flags = ((Publish ? RTE_FLAG_PUBLISH : 0) |
  1997. (Immortal ? RTE_FLAG_IMMORTAL : 0));
  1998. if (RTE->Preference != Pref) {
  1999. RTE->Preference = Pref;
  2000. InvalidateRouteCache();
  2001. }
  2002. if ((OldLifetime == 0) && (ValidLifetime != 0)) {
  2003. //
  2004. // This route was invalid but is now valid.
  2005. //
  2006. InvalidateRouteCache();
  2007. }
  2008. else {
  2009. //
  2010. // Do not check for route change notifications below.
  2011. //
  2012. RTE = NULL;
  2013. }
  2014. }
  2015. break;
  2016. }
  2017. } // end for
  2018. if (RTE != NULL) {
  2019. //
  2020. // This update resulted in adding or deleting a route,
  2021. // so check for matching route change notifications.
  2022. //
  2023. CheckRtChangeNotifyRequests(&Context, FileObject, RTE);
  2024. }
  2025. } // end if (! IsDisabledIF(IF))
  2026. KeReleaseSpinLock(&RouteTableLock, Context.OldIrql);
  2027. if (Delete)
  2028. ExFreePool(RTE);
  2029. if (Context.RequestList != NULL) {
  2030. //
  2031. // Complete the pending route change notifications.
  2032. //
  2033. CompleteRtChangeNotifyRequests(&Context);
  2034. }
  2035. return Status;
  2036. }
  2037. //* RouteTableResetAutoConfig
  2038. //
  2039. // Reset the lifetimes of all auto-configured routes for an interface.
  2040. // Also resets prefixes in the Site Prefix Table.
  2041. //
  2042. // Callable from a thread or DPC context.
  2043. // May be called with an interface lock held.
  2044. //
  2045. void
  2046. RouteTableResetAutoConfig(Interface *IF, uint MaxLifetime)
  2047. {
  2048. CheckRtChangeContext Context;
  2049. RouteTableEntry *RTE, **PrevRTE;
  2050. SitePrefixEntry *SPE;
  2051. InitCheckRtChangeContext(&Context);
  2052. KeAcquireSpinLock(&RouteTableLock, &Context.OldIrql);
  2053. //
  2054. // Reset all routes for this interface.
  2055. //
  2056. PrevRTE = &RouteTable.First;
  2057. while ((RTE = *PrevRTE) != NULL) {
  2058. if (RTE->IF == IF) {
  2059. //
  2060. // Is this an auto-configured route?
  2061. //
  2062. if (RTE->Type == RTE_TYPE_AUTOCONF) {
  2063. if (MaxLifetime == 0) {
  2064. //
  2065. // Invalidate all cached routes.
  2066. //
  2067. InvalidateRouteCache();
  2068. //
  2069. // Remove the RTE from the list.
  2070. //
  2071. RemoveRTE(PrevRTE, RTE);
  2072. //
  2073. // Check for matching route change notification requests.
  2074. //
  2075. CheckRtChangeNotifyRequests(&Context, NULL, RTE);
  2076. if (IsOnLinkRTE(RTE)) {
  2077. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_STATE,
  2078. "Route RTE %p %s/%u -> IF %p released\n",
  2079. RTE,
  2080. FormatV6Address(&RTE->Prefix),
  2081. RTE->PrefixLength,
  2082. RTE->IF));
  2083. }
  2084. else {
  2085. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_STATE,
  2086. "Route RTE %p %s/%u -> NCE %p released\n",
  2087. RTE,
  2088. FormatV6Address(&RTE->Prefix),
  2089. RTE->PrefixLength,
  2090. RTE->NCE));
  2091. ReleaseNCE(RTE->NCE);
  2092. }
  2093. //
  2094. // Free the RTE.
  2095. //
  2096. ExFreePool(RTE);
  2097. continue;
  2098. }
  2099. if (RTE->ValidLifetime > MaxLifetime) {
  2100. //
  2101. // Reset the lifetime to a small value.
  2102. //
  2103. RTE->ValidLifetime = MaxLifetime;
  2104. }
  2105. }
  2106. }
  2107. //
  2108. // Move to the next RTE.
  2109. //
  2110. PrevRTE = &RTE->Next;
  2111. }
  2112. ASSERT(PrevRTE == RouteTable.Last);
  2113. //
  2114. // Reset all site prefixes for this interface.
  2115. //
  2116. for (SPE = SitePrefixTable; SPE != NULL; SPE = SPE->Next) {
  2117. if (SPE->IF == IF) {
  2118. //
  2119. // Is this an auto-configured site prefix?
  2120. //
  2121. if (SPE->ValidLifetime != INFINITE_LIFETIME) {
  2122. //
  2123. // Reset the lifetime to a small value.
  2124. //
  2125. if (SPE->ValidLifetime > MaxLifetime)
  2126. SPE->ValidLifetime = MaxLifetime;
  2127. }
  2128. }
  2129. }
  2130. KeReleaseSpinLock(&RouteTableLock, Context.OldIrql);
  2131. if (Context.RequestList != NULL) {
  2132. //
  2133. // Complete the pending route change notifications.
  2134. //
  2135. CompleteRtChangeNotifyRequests(&Context);
  2136. }
  2137. }
  2138. //* RouteTableReset
  2139. //
  2140. // Removes all manually-configured routing state.
  2141. //
  2142. // Callable from a thread or DPC context.
  2143. // Called with NO locks held.
  2144. //
  2145. void
  2146. RouteTableReset(void)
  2147. {
  2148. CheckRtChangeContext Context;
  2149. RouteTableEntry *RTE, **PrevRTE;
  2150. InitCheckRtChangeContext(&Context);
  2151. KeAcquireSpinLock(&RouteTableLock, &Context.OldIrql);
  2152. //
  2153. // Remove all manually-configured routes.
  2154. //
  2155. PrevRTE = &RouteTable.First;
  2156. while ((RTE = *PrevRTE) != NULL) {
  2157. //
  2158. // Is this a manual route?
  2159. //
  2160. if (RTE->Type == RTE_TYPE_MANUAL) {
  2161. //
  2162. // Invalidate all cached routes.
  2163. //
  2164. InvalidateRouteCache();
  2165. //
  2166. // Remove the RTE from the list.
  2167. //
  2168. RemoveRTE(PrevRTE, RTE);
  2169. //
  2170. // Check for matching route change notification requests.
  2171. //
  2172. CheckRtChangeNotifyRequests(&Context, NULL, RTE);
  2173. if (IsOnLinkRTE(RTE)) {
  2174. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_STATE,
  2175. "Route RTE %p %s/%u -> IF %p released\n",
  2176. RTE,
  2177. FormatV6Address(&RTE->Prefix),
  2178. RTE->PrefixLength,
  2179. RTE->IF));
  2180. }
  2181. else {
  2182. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_STATE,
  2183. "Route RTE %p %s/%u -> NCE %p released\n",
  2184. RTE,
  2185. FormatV6Address(&RTE->Prefix),
  2186. RTE->PrefixLength,
  2187. RTE->NCE));
  2188. ReleaseNCE(RTE->NCE);
  2189. }
  2190. //
  2191. // Free the RTE.
  2192. //
  2193. ExFreePool(RTE);
  2194. continue;
  2195. }
  2196. //
  2197. // Move to the next RTE.
  2198. //
  2199. PrevRTE = &RTE->Next;
  2200. }
  2201. ASSERT(PrevRTE == RouteTable.Last);
  2202. KeReleaseSpinLock(&RouteTableLock, Context.OldIrql);
  2203. if (Context.RequestList != NULL) {
  2204. //
  2205. // Complete the pending route change notifications.
  2206. //
  2207. CompleteRtChangeNotifyRequests(&Context);
  2208. }
  2209. }
  2210. //* RouteTableRemove
  2211. //
  2212. // Releases all routing state associated with the interface.
  2213. //
  2214. // Callable from a thread or DPC context.
  2215. // Called with NO locks held.
  2216. //
  2217. void
  2218. RouteTableRemove(Interface *IF)
  2219. {
  2220. CheckRtChangeContext Context;
  2221. RouteTableEntry *RTE, **PrevRTE;
  2222. RouteCacheEntry *RCE, *NextRCE;
  2223. SitePrefixEntry *SPE, **PrevSPE;
  2224. BindingCacheEntry *BCE, *NextBCE;
  2225. KIRQL OldIrql;
  2226. InitCheckRtChangeContext(&Context);
  2227. KeAcquireSpinLock(&RouteTableLock, &Context.OldIrql);
  2228. //
  2229. // Remove routes for this interface.
  2230. //
  2231. PrevRTE = &RouteTable.First;
  2232. while ((RTE = *PrevRTE) != NULL) {
  2233. if (RTE->IF == IF) {
  2234. //
  2235. // Remove the RTE from the list.
  2236. //
  2237. RemoveRTE(PrevRTE, RTE);
  2238. //
  2239. // Check for matching route change notification requests.
  2240. //
  2241. CheckRtChangeNotifyRequests(&Context, NULL, RTE);
  2242. if (IsOnLinkRTE(RTE)) {
  2243. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_STATE,
  2244. "Route RTE %p %s/%u -> IF %p released\n", RTE,
  2245. FormatV6Address(&RTE->Prefix), RTE->PrefixLength,
  2246. RTE->IF));
  2247. }
  2248. else {
  2249. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_STATE,
  2250. "Route RTE %p %s/%u -> NCE %p released\n", RTE,
  2251. FormatV6Address(&RTE->Prefix), RTE->PrefixLength,
  2252. RTE->NCE));
  2253. ReleaseNCE(RTE->NCE);
  2254. }
  2255. //
  2256. // Free the RTE.
  2257. //
  2258. ExFreePool(RTE);
  2259. }
  2260. else {
  2261. //
  2262. // Move to the next RTE.
  2263. //
  2264. PrevRTE = &RTE->Next;
  2265. }
  2266. }
  2267. ASSERT(PrevRTE == RouteTable.Last);
  2268. //
  2269. // Invalidate all cached routes.
  2270. //
  2271. InvalidateRouteCache();
  2272. //
  2273. // Remove all site prefixes for this interface.
  2274. //
  2275. PrevSPE = &SitePrefixTable;
  2276. while ((SPE = *PrevSPE) != NULL) {
  2277. if (SPE->IF == IF) {
  2278. //
  2279. // Remove the SPE from the list.
  2280. //
  2281. *PrevSPE = SPE->Next;
  2282. //
  2283. // Release the SPE.
  2284. //
  2285. ExFreePool(SPE);
  2286. }
  2287. else {
  2288. //
  2289. // Move to the next SPE.
  2290. //
  2291. PrevSPE = &SPE->Next;
  2292. }
  2293. }
  2294. KeReleaseSpinLock(&RouteTableLock, Context.OldIrql);
  2295. if (Context.RequestList != NULL) {
  2296. //
  2297. // Complete the pending route change notifications.
  2298. //
  2299. CompleteRtChangeNotifyRequests(&Context);
  2300. }
  2301. KeAcquireSpinLock(&RouteCacheLock, &OldIrql);
  2302. //
  2303. // Remove cached routes for this interface.
  2304. //
  2305. for (RCE = RouteCache.First; RCE != SentinelRCE; RCE = NextRCE) {
  2306. NextRCE = RCE->Next;
  2307. if (RCE->NTE->IF == IF) {
  2308. RemoveRCE(RCE);
  2309. ReleaseRCE(RCE);
  2310. }
  2311. }
  2312. //
  2313. // Remove binding cache entries for this interface.
  2314. //
  2315. for (BCE = BindingCache.First; BCE != SentinelBCE; BCE = NextBCE) {
  2316. NextBCE = BCE->Next;
  2317. if (BCE->CareOfRCE->NTE->IF == IF)
  2318. DestroyBCE(BCE);
  2319. }
  2320. KeReleaseSpinLock(&RouteCacheLock, OldIrql);
  2321. }
  2322. //* RouteTableTimeout
  2323. //
  2324. // Called periodically from IPv6Timeout.
  2325. // Handles lifetime expiration of routing table entries.
  2326. //
  2327. void
  2328. RouteTableTimeout(void)
  2329. {
  2330. CheckRtChangeContext Context;
  2331. RouteTableEntry *RTE, **PrevRTE;
  2332. #if DBG
  2333. RouteCacheEntry *RCE;
  2334. uint RCECount;
  2335. #endif
  2336. InitCheckRtChangeContext(&Context);
  2337. KeAcquireSpinLock(&RouteTableLock, &Context.OldIrql);
  2338. PrevRTE = &RouteTable.First;
  2339. while ((RTE = *PrevRTE) != NULL) {
  2340. //
  2341. // First decrement the preferred lifetime.
  2342. //
  2343. if (!(RTE->Flags & RTE_FLAG_IMMORTAL) &&
  2344. (RTE->PreferredLifetime != 0) &&
  2345. (RTE->PreferredLifetime != INFINITE_LIFETIME))
  2346. RTE->PreferredLifetime--;
  2347. //
  2348. // Now check the valid lifetime.
  2349. // If the valid lifetime is zero, then
  2350. // the route is not valid and is not used.
  2351. // We delete invalid routes, unless they are published.
  2352. //
  2353. if (RTE->ValidLifetime == 0) {
  2354. //
  2355. // This is an invalid route, only kept around
  2356. // for purposes of generating Router Advertisements
  2357. // or because it is a system route.
  2358. //
  2359. ASSERT((RTE->Flags & RTE_FLAG_PUBLISH) ||
  2360. (RTE->Type == RTE_TYPE_SYSTEM));
  2361. }
  2362. else if (!(RTE->Flags & RTE_FLAG_IMMORTAL) &&
  2363. (RTE->ValidLifetime != INFINITE_LIFETIME) &&
  2364. (--RTE->ValidLifetime == 0)) {
  2365. //
  2366. // The route is now invalid.
  2367. // Invalidate all cached routes.
  2368. //
  2369. InvalidateRouteCache();
  2370. //
  2371. // Check for matching route change notification requests.
  2372. //
  2373. CheckRtChangeNotifyRequests(&Context, NULL, RTE);
  2374. if (!(RTE->Flags & RTE_FLAG_PUBLISH) &&
  2375. (RTE->Type != RTE_TYPE_SYSTEM)) {
  2376. //
  2377. // Remove the RTE from the list.
  2378. // See similar code in RouteTableUpdate.
  2379. //
  2380. RemoveRTE(PrevRTE, RTE);
  2381. if (IsOnLinkRTE(RTE)) {
  2382. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_STATE,
  2383. "Route RTE %p %s/%u -> IF %p timed out\n", RTE,
  2384. FormatV6Address(&RTE->Prefix),
  2385. RTE->PrefixLength,
  2386. RTE->IF));
  2387. }
  2388. else {
  2389. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_STATE,
  2390. "Route RTE %p %s/%u -> NCE %p timed out\n", RTE,
  2391. FormatV6Address(&RTE->Prefix),
  2392. RTE->PrefixLength,
  2393. RTE->NCE));
  2394. ReleaseNCE(RTE->NCE);
  2395. }
  2396. //
  2397. // Release the RTE and continue to the next RTE.
  2398. //
  2399. ExFreePool(RTE);
  2400. continue;
  2401. }
  2402. }
  2403. //
  2404. // Continue to the next RTE.
  2405. //
  2406. PrevRTE = &RTE->Next;
  2407. }
  2408. ASSERT(PrevRTE == RouteTable.Last);
  2409. KeReleaseSpinLock(&RouteTableLock, Context.OldIrql);
  2410. if (Context.RequestList != NULL) {
  2411. //
  2412. // Complete the pending route change notifications.
  2413. //
  2414. CompleteRtChangeNotifyRequests(&Context);
  2415. }
  2416. }
  2417. //* SitePrefixUpdate
  2418. //
  2419. // Updates the site prefix table by creating a new site prefix
  2420. // or modifying the lifetime of an existing site prefix.
  2421. //
  2422. // Callable from a thread or DPC context.
  2423. // May be called with an interface lock held.
  2424. //
  2425. void
  2426. SitePrefixUpdate(
  2427. Interface *IF,
  2428. const IPv6Addr *SitePrefix,
  2429. uint SitePrefixLength,
  2430. uint ValidLifetime)
  2431. {
  2432. IPv6Addr Prefix;
  2433. SitePrefixEntry *SPE, **PrevSPE;
  2434. KIRQL OldIrql;
  2435. //
  2436. // Ensure that the unused prefix bits are zero.
  2437. // This makes the prefix comparisons below safe.
  2438. //
  2439. CopyPrefix(&Prefix, SitePrefix, SitePrefixLength);
  2440. KeAcquireSpinLock(&RouteTableLock, &OldIrql);
  2441. //
  2442. // Search for an existing Site Prefix Entry.
  2443. //
  2444. for (PrevSPE = &SitePrefixTable; ; PrevSPE = &SPE->Next) {
  2445. SPE = *PrevSPE;
  2446. if (SPE == NULL) {
  2447. //
  2448. // No existing entry for this prefix.
  2449. // Create an entry if the lifetime is non-zero.
  2450. //
  2451. if (ValidLifetime != 0) {
  2452. SPE = ExAllocatePool(NonPagedPool, sizeof *SPE);
  2453. if (SPE == NULL)
  2454. break;
  2455. SPE->IF = IF;
  2456. SPE->Prefix = Prefix;
  2457. SPE->SitePrefixLength = SitePrefixLength;
  2458. SPE->ValidLifetime = ValidLifetime;
  2459. //
  2460. // Add the new entry to the table.
  2461. //
  2462. SPE->Next = SitePrefixTable;
  2463. SitePrefixTable = SPE;
  2464. }
  2465. break;
  2466. }
  2467. if ((SPE->IF == IF) &&
  2468. IP6_ADDR_EQUAL(&SPE->Prefix, &Prefix) &&
  2469. (SPE->SitePrefixLength == SitePrefixLength)) {
  2470. //
  2471. // We have an existing site prefix.
  2472. // Remove the prefix if the new lifetime is zero,
  2473. // otherwise update the prefix.
  2474. //
  2475. if (ValidLifetime == 0) {
  2476. //
  2477. // Remove the SPE from the list.
  2478. // See similar code in SitePrefixTimeout.
  2479. //
  2480. *PrevSPE = SPE->Next;
  2481. //
  2482. // Release the SPE.
  2483. //
  2484. ExFreePool(SPE);
  2485. }
  2486. else {
  2487. //
  2488. // Pick up new attributes.
  2489. //
  2490. SPE->ValidLifetime = ValidLifetime;
  2491. }
  2492. break;
  2493. }
  2494. }
  2495. KeReleaseSpinLock(&RouteTableLock, OldIrql);
  2496. }
  2497. //* SitePrefixMatch
  2498. //
  2499. // Checks the destination address against
  2500. // the prefixes in the Site Prefix Table.
  2501. // If there is a match, returns the site identifier
  2502. // associated with the matching prefix.
  2503. // If there is no match, returns zero.
  2504. //
  2505. // Callable from a thread or DPC context.
  2506. // Called with NO locks held.
  2507. //
  2508. uint
  2509. SitePrefixMatch(const IPv6Addr *Destination)
  2510. {
  2511. SitePrefixEntry *SPE;
  2512. KIRQL OldIrql;
  2513. uint MatchingSite = 0;
  2514. KeAcquireSpinLock(&RouteTableLock, &OldIrql);
  2515. for (SPE = SitePrefixTable; SPE != NULL; SPE = SPE->Next) {
  2516. //
  2517. // Does this site prefix match the destination address?
  2518. //
  2519. if (HasPrefix(Destination, &SPE->Prefix, SPE->SitePrefixLength)) {
  2520. //
  2521. // We have found a matching site prefix.
  2522. // No need to look further.
  2523. //
  2524. MatchingSite = SPE->IF->ZoneIndices[ADE_SITE_LOCAL];
  2525. break;
  2526. }
  2527. }
  2528. KeReleaseSpinLock(&RouteTableLock, OldIrql);
  2529. return MatchingSite;
  2530. }
  2531. //* SitePrefixTimeout
  2532. //
  2533. // Called periodically from IPv6Timeout.
  2534. // Handles lifetime expiration of site prefixes.
  2535. //
  2536. void
  2537. SitePrefixTimeout(void)
  2538. {
  2539. SitePrefixEntry *SPE, **PrevSPE;
  2540. KeAcquireSpinLockAtDpcLevel(&RouteTableLock);
  2541. PrevSPE = &SitePrefixTable;
  2542. while ((SPE = *PrevSPE) != NULL) {
  2543. if (SPE->ValidLifetime == 0) {
  2544. //
  2545. // Remove the SPE from the list.
  2546. //
  2547. *PrevSPE = SPE->Next;
  2548. //
  2549. // Release the SPE.
  2550. //
  2551. ExFreePool(SPE);
  2552. }
  2553. else {
  2554. if (SPE->ValidLifetime != INFINITE_LIFETIME)
  2555. SPE->ValidLifetime--;
  2556. PrevSPE = &SPE->Next;
  2557. }
  2558. }
  2559. KeReleaseSpinLockFromDpcLevel(&RouteTableLock);
  2560. }
  2561. //* ConfirmForwardReachability - tell ND that packets are getting through.
  2562. //
  2563. // Upper layers call this routine upon receiving acknowledgements that
  2564. // data sent by this node has arrived recently at the peer represented
  2565. // by this RCE. Such acknowledgements are considered to be proof of
  2566. // forward reachability for the purposes of Neighbor Discovery.
  2567. //
  2568. // Caller should be holding a reference on the RCE.
  2569. // Callable from a thread or DPC context.
  2570. //
  2571. void
  2572. ConfirmForwardReachability(RouteCacheEntry *RCE)
  2573. {
  2574. RouteCacheEntry *CareOfRCE; // CareOfRCE, if any, for this route.
  2575. NeighborCacheEntry *NCE; // First-hop neighbor for this route.
  2576. CareOfRCE = GetCareOfRCE(RCE);
  2577. NCE = (CareOfRCE ? CareOfRCE : RCE)->NCE;
  2578. NeighborCacheReachabilityConfirmation(NCE);
  2579. if (CareOfRCE != NULL)
  2580. ReleaseRCE(CareOfRCE);
  2581. }
  2582. //* ForwardReachabilityInDoubt - tell ND we're dubious.
  2583. //
  2584. // Upper layers call this routine when they don't receive acknowledgements
  2585. // which they'd otherwise expect if the peer represented by this RCE was
  2586. // still reachable. This calls into question whether the first-hop
  2587. // might be the problem, so we tell ND that we're suspicious of its
  2588. // reachable status.
  2589. //
  2590. // Caller should be holding a reference on the RCE.
  2591. // Callable from a thread or DPC context.
  2592. //
  2593. void
  2594. ForwardReachabilityInDoubt(RouteCacheEntry *RCE)
  2595. {
  2596. RouteCacheEntry *CareOfRCE; // CareOfRCE, if any, for this route.
  2597. NeighborCacheEntry *NCE; // First-hop neighbor for this route.
  2598. Interface *IF; // Interface we use to reach this neighbor.
  2599. KIRQL OldIrql; // Temporary place to stash the interrupt level.
  2600. CareOfRCE = GetCareOfRCE(RCE);
  2601. NCE = (CareOfRCE ? CareOfRCE : RCE)->NCE;
  2602. NeighborCacheReachabilityInDoubt(NCE);
  2603. if (CareOfRCE != NULL)
  2604. ReleaseRCE(CareOfRCE);
  2605. }
  2606. //* GetPathMTUFromRCE - lookup MTU to use in sending on this route.
  2607. //
  2608. // Get the PathMTU from an RCE.
  2609. //
  2610. // Note that PathMTU is volatile unless the RouteCacheLock
  2611. // is held. Furthermore the Interface's LinkMTU may have changed
  2612. // since the RCE was created, due to a Router Advertisement.
  2613. // (LinkMTU is always volatile.)
  2614. //
  2615. // Callable from a thread or DPC context.
  2616. // Called with NO locks held.
  2617. //
  2618. uint
  2619. GetPathMTUFromRCE(RouteCacheEntry *RCE)
  2620. {
  2621. uint PathMTU, LinkMTU;
  2622. KIRQL OldIrql;
  2623. LinkMTU = RCE->NCE->IF->LinkMTU;
  2624. PathMTU = RCE->PathMTU;
  2625. //
  2626. // We lazily check to see if it's time to probe for an increased Path
  2627. // MTU as this is perceived to be cheaper than routinely running through
  2628. // all our RCEs looking for one whose PMTU timer has expired.
  2629. //
  2630. if ((RCE->PMTULastSet != 0) &&
  2631. ((uint)(IPv6TickCount - RCE->PMTULastSet) >= PATH_MTU_RETRY_TIME)) {
  2632. //
  2633. // It's been at least 10 minutes since we last lowered our PMTU
  2634. // as the result of receiving a Path Too Big message. Bump it
  2635. // back up to the Link MTU to see if the path is larger now.
  2636. //
  2637. KeAcquireSpinLock(&RouteCacheLock, &OldIrql);
  2638. PathMTU = RCE->PathMTU = LinkMTU;
  2639. RCE->PMTULastSet = 0;
  2640. KeReleaseSpinLock(&RouteCacheLock, OldIrql);
  2641. }
  2642. //
  2643. // We lazily check to see if our Link MTU has shrunk below our Path MTU,
  2644. // as this is perceived to be cheaper than running through all our RCEs
  2645. // looking for a too big Path MTU when a Link MTU shrinks.
  2646. //
  2647. // REVIEW: A contrarian might point out that Link MTUs rarely (if ever)
  2648. // REVIEW: shrink, whereas we do this check on every packet sent.
  2649. //
  2650. if (PathMTU > LinkMTU) {
  2651. KeAcquireSpinLock(&RouteCacheLock, &OldIrql);
  2652. LinkMTU = RCE->NCE->IF->LinkMTU;
  2653. PathMTU = RCE->PathMTU;
  2654. if (PathMTU > LinkMTU) {
  2655. PathMTU = RCE->PathMTU = LinkMTU;
  2656. RCE->PMTULastSet = 0;
  2657. }
  2658. KeReleaseSpinLock(&RouteCacheLock, OldIrql);
  2659. }
  2660. return PathMTU;
  2661. }
  2662. //* GetEffectivePathMTUFromRCE
  2663. //
  2664. // Adjust the true path MTU to account for mobility and fragment headers.
  2665. // Determines PMTU available to upper layer protocols.
  2666. //
  2667. // Callable from a thread or DPC context.
  2668. // Called with NO locks held.
  2669. //
  2670. uint
  2671. GetEffectivePathMTUFromRCE(RouteCacheEntry *RCE)
  2672. {
  2673. uint PathMTU;
  2674. KIRQL OldIrql;
  2675. RouteCacheEntry *CareOfRCE;
  2676. CareOfRCE = GetCareOfRCE(RCE);
  2677. PathMTU = GetPathMTUFromRCE(CareOfRCE ? CareOfRCE : RCE);
  2678. if (PathMTU == 0) {
  2679. //
  2680. // We need to leave space for a fragment header in all
  2681. // packets we send to this destination.
  2682. //
  2683. PathMTU = IPv6_MINIMUM_MTU - sizeof(FragmentHeader);
  2684. }
  2685. if (CareOfRCE != NULL) {
  2686. //
  2687. // Mobility is in effect for this destination.
  2688. // Leave space for routing header.
  2689. //
  2690. PathMTU -= sizeof(IPv6RoutingHeader) + sizeof(IPv6Addr);
  2691. ReleaseRCE(CareOfRCE);
  2692. }
  2693. return PathMTU;
  2694. }
  2695. //* UpdatePathMTU
  2696. //
  2697. // Update the route cache with a new MTU obtained
  2698. // from a Packet Too Big message. Returns TRUE if this
  2699. // update modified a PMTU value we had cached previously.
  2700. //
  2701. // Callable from DPC context, not from thread context.
  2702. // Called with NO locks held.
  2703. //
  2704. int
  2705. UpdatePathMTU(
  2706. Interface *IF,
  2707. const IPv6Addr *Dest,
  2708. uint MTU)
  2709. {
  2710. RouteCacheEntry *RCE;
  2711. uint Now;
  2712. int Changed = FALSE;
  2713. KeAcquireSpinLockAtDpcLevel(&RouteCacheLock);
  2714. //
  2715. // Search the route cache for the appropriate RCE.
  2716. // There will be at most one.
  2717. //
  2718. for (RCE = RouteCache.First; RCE != SentinelRCE; RCE = RCE->Next) {
  2719. if (IP6_ADDR_EQUAL(&RCE->Destination, Dest) &&
  2720. (RCE->NTE->IF == IF)) {
  2721. //
  2722. // Update the path MTU.
  2723. // We never actually lower the path MTU below IPv6_MINIMUM_MTU.
  2724. // If this is requested, we instead start including fragment
  2725. // headers in all packets but we still use IPv6_MINIMUM_MTU.
  2726. //
  2727. if (MTU < RCE->PathMTU) {
  2728. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_STATE,
  2729. "UpdatePathMTU(RCE %p): new MTU %u for %s\n",
  2730. RCE, MTU, FormatV6Address(Dest)));
  2731. if (MTU < IPv6_MINIMUM_MTU)
  2732. RCE->PathMTU = 0; // Always include fragment header.
  2733. else
  2734. RCE->PathMTU = MTU;
  2735. Changed = TRUE;
  2736. //
  2737. // Timestamp it (starting the timer).
  2738. // A zero value means no timer, so don't use it.
  2739. //
  2740. Now = IPv6TickCount;
  2741. if (Now == 0)
  2742. Now = 1;
  2743. RCE->PMTULastSet = Now;
  2744. }
  2745. break;
  2746. }
  2747. }
  2748. KeReleaseSpinLockFromDpcLevel(&RouteCacheLock);
  2749. return Changed;
  2750. }
  2751. //* RedirectRouteCache
  2752. //
  2753. // Update the route cache to reflect a Redirect message.
  2754. //
  2755. // Callable from DPC context, not from thread context.
  2756. // Called with NO locks held.
  2757. //
  2758. IP_STATUS // Returns: IP_SUCCESS if redirect was legit, otherwise failure.
  2759. RedirectRouteCache(
  2760. const IPv6Addr *Source, // Source of the redirect.
  2761. const IPv6Addr *Dest, // Destination that is being redirected.
  2762. Interface *IF, // Interface that this all applies to.
  2763. NeighborCacheEntry *NCE) // New router for the destination.
  2764. {
  2765. RouteCacheEntry *RCE;
  2766. ushort DestScope;
  2767. uint DestScopeId;
  2768. IP_STATUS ReturnValue;
  2769. #if DBG
  2770. char Buffer1[INET6_ADDRSTRLEN], Buffer2[INET6_ADDRSTRLEN];
  2771. FormatV6AddressWorker(Buffer1, Dest);
  2772. FormatV6AddressWorker(Buffer2, &NCE->NeighborAddress);
  2773. #endif
  2774. //
  2775. // Our caller guarantees this.
  2776. //
  2777. ASSERT(IF == NCE->IF);
  2778. DestScope = AddressScope(Dest);
  2779. DestScopeId = IF->ZoneIndices[DestScope];
  2780. KeAcquireSpinLockAtDpcLevel(&RouteCacheLock);
  2781. //
  2782. // Get the current RCE for this destination.
  2783. //
  2784. ReturnValue = FindOrCreateRoute(Dest, DestScopeId, IF, &RCE);
  2785. if (ReturnValue == IP_SUCCESS) {
  2786. //
  2787. // We must check that the source of the redirect
  2788. // is the current next-hop neighbor.
  2789. // (This is a simple sanity check - it does not
  2790. // prevent clever neighbors from hijacking.)
  2791. //
  2792. if (!IP6_ADDR_EQUAL(&RCE->NCE->NeighborAddress, Source)) {
  2793. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_NET_ERROR,
  2794. "RedirectRouteCache(dest %s -> %s): hijack from %s\n",
  2795. Buffer1, Buffer2, FormatV6Address(Source)));
  2796. ReturnValue = IP_GENERAL_FAILURE;
  2797. }
  2798. else if (RCE->RefCnt == 2) {
  2799. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_STATE,
  2800. "RedirectRouteCache(dest %s -> %s): inplace %p\n",
  2801. Buffer1, Buffer2, RCE));
  2802. //
  2803. // There are no references to this RCE outside
  2804. // of the cache, so we can update it in place.
  2805. //
  2806. ReleaseNCE(RCE->NCE);
  2807. //
  2808. // It's still OK to compare against RCE->NCE.
  2809. //
  2810. goto UpdateRCE;
  2811. }
  2812. else {
  2813. RouteCacheEntry *NewRCE;
  2814. //
  2815. // Create a new route cache entry for the redirect.
  2816. // CreateOrReuseRoute will not return RCE,
  2817. // because we have an extra reference for it.
  2818. //
  2819. NewRCE = CreateOrReuseRoute();
  2820. if (NewRCE != NULL) {
  2821. ASSERT(NewRCE != RCE);
  2822. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_STATE,
  2823. "RedirectRouteCache(dest %s -> %s): old %p new %p\n",
  2824. Buffer1, Buffer2, RCE, NewRCE));
  2825. //
  2826. // Copy the RCE and fix up references.
  2827. // We must copy the correct validation counter value.
  2828. //
  2829. *NewRCE = *RCE;
  2830. NewRCE->RefCnt = 2; // One for the cache, one to release below.
  2831. // We do not AddRefNCE(NewRCE->NCE), see below.
  2832. AddRefNTE(NewRCE->NTE);
  2833. //
  2834. // Cause anyone who is using/caching the old RCE to notice
  2835. // that it is no longer valid, so they will find the new RCE.
  2836. // Then remove the old RCE from the cache.
  2837. //
  2838. RCE->Valid--; // RouteCacheValidationCounter increases.
  2839. RemoveRCE(RCE);
  2840. ReleaseRCE(RCE); // The cache's reference.
  2841. ReleaseRCE(RCE); // Reference from FindOrCreateRoute.
  2842. //
  2843. // Add the new route cache entry to the cache.
  2844. //
  2845. InsertRCE(NewRCE);
  2846. RCE = NewRCE;
  2847. UpdateRCE:
  2848. RCE->Type = RCE_TYPE_REDIRECT;
  2849. if (RCE->NCE != NCE) {
  2850. //
  2851. // Reset PMTU discovery.
  2852. //
  2853. RCE->PathMTU = IF->LinkMTU;
  2854. RCE->PMTULastSet = 0;
  2855. }
  2856. //
  2857. // At this point, RCE->NCE does NOT hold a reference.
  2858. //
  2859. AddRefNCE(NCE);
  2860. RCE->NCE = NCE;
  2861. }
  2862. else {
  2863. //
  2864. // Could not allocate a new RCE.
  2865. // REVIEW - Remove the old RCE from the cache?
  2866. //
  2867. ReturnValue = IP_NO_RESOURCES;
  2868. }
  2869. }
  2870. //
  2871. // Release our references.
  2872. //
  2873. ReleaseRCE(RCE);
  2874. }
  2875. KeReleaseSpinLockFromDpcLevel(&RouteCacheLock);
  2876. return ReturnValue;
  2877. }
  2878. //* InitRouting - Initialize the routing module.
  2879. //
  2880. void
  2881. InitRouting(void)
  2882. {
  2883. KeInitializeSpinLock(&RouteCacheLock);
  2884. KeInitializeSpinLock(&RouteTableLock);
  2885. // RouteCache.Limit initialized in ConfigureGlobalParameters.
  2886. RouteCache.First = RouteCache.Last = SentinelRCE;
  2887. RouteTable.First = NULL;
  2888. RouteTable.Last = &RouteTable.First;
  2889. // BindingCache.Limit initialized in ConfigureGlobalParameters.
  2890. BindingCache.First = BindingCache.Last = SentinelBCE;
  2891. InitializeListHead(&RouteNotifyQueue);
  2892. }
  2893. //* UnloadRouting
  2894. //
  2895. // Called when IPv6 stack is unloading.
  2896. //
  2897. void
  2898. UnloadRouting(void)
  2899. {
  2900. //
  2901. // With all the interfaces destroyed,
  2902. // there should be no routes left.
  2903. //
  2904. ASSERT(RouteTable.First == NULL);
  2905. ASSERT(RouteTable.Last == &RouteTable.First);
  2906. ASSERT(RouteCache.First == SentinelRCE);
  2907. ASSERT(RouteCache.Last == SentinelRCE);
  2908. ASSERT(BindingCache.First == SentinelBCE);
  2909. ASSERT(BindingCache.Last == SentinelBCE);
  2910. //
  2911. // Irps hold references for our device object,
  2912. // so pending notification requests prevent
  2913. // us from unloading.
  2914. //
  2915. ASSERT(RouteNotifyQueue.Flink == RouteNotifyQueue.Blink);
  2916. }
  2917. //* InsertBCE
  2918. //
  2919. // Insert the BCE in the binding cache.
  2920. //
  2921. // Called with the route cache lock held.
  2922. // Callable from a thread or DPC context.
  2923. //
  2924. void
  2925. InsertBCE(BindingCacheEntry *BCE)
  2926. {
  2927. BindingCacheEntry *AfterBCE = SentinelBCE;
  2928. RouteCacheEntry *RCE;
  2929. BCE->Prev = AfterBCE;
  2930. (BCE->Next = AfterBCE->Next)->Prev = BCE;
  2931. AfterBCE->Next = BCE;
  2932. BindingCache.Count++;
  2933. //
  2934. // Update any existing RCEs to point to this BCE.
  2935. //
  2936. for (RCE = RouteCache.First; RCE != SentinelRCE; RCE = RCE->Next) {
  2937. if (IP6_ADDR_EQUAL(&RCE->Destination, &BCE->HomeAddr))
  2938. RCE->BCE = BCE;
  2939. }
  2940. }
  2941. //* RemoveBCE
  2942. //
  2943. // Remove the BCE from the binding cache.
  2944. //
  2945. // Called with the route cache lock held.
  2946. // Callable from a thread or DPC context.
  2947. //
  2948. void
  2949. RemoveBCE(BindingCacheEntry *BCE)
  2950. {
  2951. RouteCacheEntry *RCE;
  2952. BCE->Prev->Next = BCE->Next;
  2953. BCE->Next->Prev = BCE->Prev;
  2954. BindingCache.Count--;
  2955. //
  2956. // Remove any references to this BCE from the route cache.
  2957. //
  2958. for (RCE = RouteCache.First; RCE != SentinelRCE; RCE = RCE->Next) {
  2959. if (RCE->BCE == BCE)
  2960. RCE->BCE = NULL;
  2961. }
  2962. }
  2963. //* MoveToFrontBCE
  2964. //
  2965. // Move an BCE to the front of the list.
  2966. //
  2967. // Called with the route cache lock held.
  2968. // Callable from a thread or DPC context.
  2969. //
  2970. void
  2971. MoveToFrontBCE(BindingCacheEntry *BCE)
  2972. {
  2973. if (BCE->Prev != SentinelBCE) {
  2974. BindingCacheEntry *AfterBCE = SentinelBCE;
  2975. //
  2976. // Remove the BCE from its current location.
  2977. //
  2978. BCE->Prev->Next = BCE->Next;
  2979. BCE->Next->Prev = BCE->Prev;
  2980. //
  2981. // And put it at the front.
  2982. //
  2983. BCE->Prev = AfterBCE;
  2984. (BCE->Next = AfterBCE->Next)->Prev = BCE;
  2985. AfterBCE->Next = BCE;
  2986. }
  2987. }
  2988. //* CreateBindingCacheEntry - create new BCE.
  2989. //
  2990. // Allocates a new Binding Cache entry.
  2991. // Returns NULL if a new BCE can not be allocated.
  2992. //
  2993. // Must be called with the RouteCache lock held.
  2994. //
  2995. BindingCacheEntry *
  2996. CreateOrReuseBindingCacheEntry()
  2997. {
  2998. BindingCacheEntry *BCE;
  2999. if (BindingCache.Count >= BindingCache.Limit) {
  3000. //
  3001. // Reuse the BCE at the end of the list.
  3002. //
  3003. BCE = BindingCache.Last;
  3004. RemoveBCE(BCE);
  3005. ReleaseRCE(BCE->CareOfRCE);
  3006. }
  3007. else {
  3008. //
  3009. // Allocate a new BCE.
  3010. //
  3011. BCE = ExAllocatePool(NonPagedPool, sizeof *BCE);
  3012. }
  3013. return BCE;
  3014. }
  3015. //* DestroyBCE - remove an entry from the BindingCache.
  3016. //
  3017. // Must be called with the RouteCache lock held.
  3018. //
  3019. void
  3020. DestroyBCE(BindingCacheEntry *BCE)
  3021. {
  3022. //
  3023. // Unchain the given BCE and destroy it.
  3024. //
  3025. RemoveBCE(BCE);
  3026. ReleaseRCE(BCE->CareOfRCE);
  3027. ExFreePool(BCE);
  3028. }
  3029. //* FindBindingCacheEntry
  3030. //
  3031. // Looks for a binding cache entry with the specified care-of address.
  3032. // Must be called with the route cache lock held.
  3033. //
  3034. BindingCacheEntry *
  3035. FindBindingCacheEntry(const IPv6Addr *HomeAddr)
  3036. {
  3037. BindingCacheEntry *BCE;
  3038. for (BCE = BindingCache.First; ; BCE = BCE->Next) {
  3039. if (BCE == SentinelBCE) {
  3040. //
  3041. // Did not find a matching entry.
  3042. //
  3043. BCE = NULL;
  3044. break;
  3045. }
  3046. if (IP6_ADDR_EQUAL(&BCE->HomeAddr, HomeAddr)) {
  3047. //
  3048. // Found a matching entry.
  3049. //
  3050. break;
  3051. }
  3052. }
  3053. return BCE;
  3054. }
  3055. //* CacheBindingUpdate - update the binding cache entry for an address.
  3056. //
  3057. // Find or Create (if necessary) an RCE to the CareOfAddress. This routine
  3058. // is called in response to a Binding Cache Update.
  3059. //
  3060. // Callable from DPC context, not from thread context.
  3061. // Called with NO locks held.
  3062. //
  3063. BindingUpdateDisposition // Returns: Binding Ack Status code.
  3064. CacheBindingUpdate(
  3065. IPv6BindingUpdateOption UNALIGNED *BindingUpdate,
  3066. const IPv6Addr *CareOfAddr, // Address to use for mobile node.
  3067. NetTableEntryOrInterface *NTEorIF, // NTE or IF receiving the BU.
  3068. const IPv6Addr *HomeAddr) // Mobile node's home address.
  3069. {
  3070. BindingCacheEntry *BCE;
  3071. BindingUpdateDisposition ReturnValue = IPV6_BINDING_ACCEPTED;
  3072. IP_STATUS Status;
  3073. int DeleteRequest; // Request is to delete an existing binding?
  3074. ushort SeqNo;
  3075. RouteCacheEntry *CareOfRCE;
  3076. ushort CareOfScope;
  3077. uint CareOfScopeId;
  3078. //
  3079. // Note that we assume the care-of address is scoped
  3080. // to the receiving interface, even when
  3081. // the care-of address is present in a suboption
  3082. // instead of the IPv6 source address field.
  3083. //
  3084. CareOfScope = AddressScope(CareOfAddr);
  3085. CareOfScopeId = NTEorIF->IF->ZoneIndices[CareOfScope];
  3086. //
  3087. // Is this Binding Update a request to remove entries
  3088. // from our binding cache?
  3089. //
  3090. DeleteRequest = ((BindingUpdate->Lifetime == 0) ||
  3091. IP6_ADDR_EQUAL(HomeAddr, CareOfAddr));
  3092. SeqNo = net_short(BindingUpdate->SeqNumber);
  3093. KeAcquireSpinLockAtDpcLevel(&RouteCacheLock);
  3094. //
  3095. // Search the binding cache for the home address.
  3096. //
  3097. for (BCE = BindingCache.First; BCE != SentinelBCE; BCE = BCE->Next) {
  3098. if (!IP6_ADDR_EQUAL(&BCE->HomeAddr, HomeAddr))
  3099. continue;
  3100. //
  3101. // We've found an existing entry for this home address.
  3102. // Verify the sequence number is greater than the cached binding's
  3103. // sequence number if there is one.
  3104. //
  3105. if ((short)(SeqNo - BCE->BindingSeqNumber) <= 0) {
  3106. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_NET_ERROR,
  3107. "CacheBindingUpdate: New sequence number too small "
  3108. "(old seqnum = %d, new seqnum = %d)\n",
  3109. BCE->BindingSeqNumber, SeqNo));
  3110. ReturnValue = IPV6_BINDING_SEQ_NO_TOO_SMALL;
  3111. goto Return;
  3112. }
  3113. //
  3114. // If the request is to delete the entry, do so and return.
  3115. //
  3116. if (DeleteRequest) {
  3117. DestroyBCE(BCE);
  3118. goto Return;
  3119. }
  3120. //
  3121. // Update the binding.
  3122. //
  3123. BCE->BindingLifetime =
  3124. ConvertSecondsToTicks(net_long(BindingUpdate->Lifetime));
  3125. BCE->BindingSeqNumber = SeqNo;
  3126. CareOfRCE = BCE->CareOfRCE;
  3127. //
  3128. // If the care-of address or scope-id has changed,
  3129. // then we need to create a new care-of RCE.
  3130. //
  3131. if (!IP6_ADDR_EQUAL(&CareOfRCE->Destination, CareOfAddr) ||
  3132. (CareOfScopeId != CareOfRCE->NTE->IF->ZoneIndices[CareOfScope])) {
  3133. RouteCacheEntry *NewRCE;
  3134. //
  3135. // Note that since we already hold the RouteCacheLock we
  3136. // call FindOrCreateRoute here instead of RouteToDestination.
  3137. //
  3138. Status = FindOrCreateRoute(CareOfAddr, CareOfScopeId, NULL,
  3139. &NewRCE);
  3140. if (Status == IP_SUCCESS) {
  3141. //
  3142. // Update the binding cache entry.
  3143. //
  3144. ReleaseRCE(CareOfRCE);
  3145. BCE->CareOfRCE = NewRCE;
  3146. }
  3147. else {
  3148. //
  3149. // Because we could not update the BCE,
  3150. // destroy it.
  3151. //
  3152. DestroyBCE(BCE);
  3153. if (Status == IP_NO_RESOURCES)
  3154. ReturnValue = IPV6_BINDING_NO_RESOURCES;
  3155. else
  3156. ReturnValue = IPV6_BINDING_REJECTED;
  3157. }
  3158. }
  3159. goto Return;
  3160. }
  3161. if (DeleteRequest) {
  3162. //
  3163. // We're done.
  3164. //
  3165. goto Return;
  3166. }
  3167. //
  3168. // We want to cache a binding and did not find an existing binding
  3169. // for the home address above. So we create a new binding cache entry.
  3170. //
  3171. BCE = CreateOrReuseBindingCacheEntry();
  3172. if (BCE == NULL) {
  3173. ReturnValue = IPV6_BINDING_NO_RESOURCES;
  3174. goto Return;
  3175. }
  3176. BCE->HomeAddr = *HomeAddr;
  3177. BCE->BindingLifetime =
  3178. ConvertSecondsToTicks(net_long(BindingUpdate->Lifetime));
  3179. BCE->BindingSeqNumber = SeqNo;
  3180. //
  3181. // Now create a new RCE for the care-of address.
  3182. // Note that since we already hold the RouteCacheLock we
  3183. // call FindOrCreateRoute here instead of RouteToDestination.
  3184. //
  3185. Status = FindOrCreateRoute(CareOfAddr, CareOfScopeId, NULL,
  3186. &BCE->CareOfRCE);
  3187. if (Status != IP_SUCCESS) {
  3188. //
  3189. // Couldn't get a route.
  3190. //
  3191. ExFreePool(BCE);
  3192. if (Status == IP_NO_RESOURCES)
  3193. ReturnValue = IPV6_BINDING_NO_RESOURCES;
  3194. else
  3195. ReturnValue = IPV6_BINDING_REJECTED;
  3196. } else {
  3197. //
  3198. // Now that the BCE is fully initialized,
  3199. // add it to the cache. This also updates existing RCEs.
  3200. //
  3201. InsertBCE(BCE);
  3202. }
  3203. Return:
  3204. KeReleaseSpinLockFromDpcLevel(&RouteCacheLock);
  3205. return ReturnValue;
  3206. }
  3207. //* BindingCacheTimeout
  3208. //
  3209. // Check for and handle binding cache lifetime expirations.
  3210. //
  3211. // Callable from DPC context, not from thread context.
  3212. // Called with NO locks held.
  3213. //
  3214. void
  3215. BindingCacheTimeout(void)
  3216. {
  3217. BindingCacheEntry *BCE, *NextBCE;
  3218. KeAcquireSpinLockAtDpcLevel(&RouteCacheLock);
  3219. //
  3220. // Search the route cache for all binding cache entries. Update
  3221. // their lifetimes, and remove if expired.
  3222. //
  3223. for (BCE = BindingCache.First; BCE != SentinelBCE; BCE = NextBCE) {
  3224. NextBCE = BCE->Next;
  3225. //
  3226. // REVIEW: The mobile IPv6 spec allows correspondent nodes to
  3227. // REVIEW: send a Binding Request when the current binding's
  3228. // REVIEW: lifetime is "close to expiration" in order to prevent
  3229. // REVIEW: the overhead of establishing a new binding after the
  3230. // REVIEW: current one expires. For now, we just let the binding
  3231. // REVIEW: expire.
  3232. //
  3233. if (--BCE->BindingLifetime == 0) {
  3234. //
  3235. // This binding cache entry has expired.
  3236. // Remove it from the Binding Cache.
  3237. //
  3238. DestroyBCE(BCE);
  3239. }
  3240. }
  3241. KeReleaseSpinLockFromDpcLevel(&RouteCacheLock);
  3242. }
  3243. //* RouterAdvertSend
  3244. //
  3245. // Sends a Router Advertisement.
  3246. // The advert is always sent to the all-nodes multicast address.
  3247. // Chooses a valid source address for the interface.
  3248. //
  3249. // Called with NO locks held.
  3250. // Callable from DPC context, not from thread context.
  3251. //
  3252. // REVIEW - Should this function be in route.c or neighbor.c? Or split up?
  3253. //
  3254. void
  3255. RouterAdvertSend(
  3256. Interface *IF, // Interface on which to send.
  3257. const IPv6Addr *Source, // Source address to use.
  3258. const IPv6Addr *Dest) // Destination address to use.
  3259. {
  3260. NDIS_STATUS Status;
  3261. NDIS_PACKET *Packet;
  3262. NDIS_BUFFER *Buffer;
  3263. uint PayloadLength;
  3264. uint Offset;
  3265. void *Mem, *MemLeft;
  3266. uint MemLen, MemLenLeft;
  3267. uint SourceOptionLength;
  3268. IPv6Header UNALIGNED *IP;
  3269. ICMPv6Header UNALIGNED *ICMP;
  3270. NDRouterAdvertisement UNALIGNED *RA;
  3271. void *SourceOption;
  3272. NDOptionMTU UNALIGNED *MTUOption;
  3273. void *LLDest;
  3274. KIRQL OldIrql;
  3275. int Forwards;
  3276. uint LinkMTU;
  3277. uint RouterLifetime;
  3278. uint DefaultRoutePreference;
  3279. RouteTableEntry *RTE;
  3280. ICMPv6OutStats.icmps_msgs++;
  3281. //
  3282. // For consistency, capture some volatile
  3283. // information in locals.
  3284. //
  3285. Forwards = IF->Flags & IF_FLAG_FORWARDS;
  3286. LinkMTU = IF->LinkMTU;
  3287. Offset = IF->LinkHeaderSize;
  3288. //
  3289. // Allocate a buffer for the advertisement.
  3290. // We typically do not use the entire buffer,
  3291. // but briefly allocating a large buffer is OK.
  3292. //
  3293. MemLen = Offset + LinkMTU;
  3294. Mem = ExAllocatePool(NonPagedPool, MemLen);
  3295. if (Mem == NULL) {
  3296. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_NTOS_ERROR,
  3297. "RouterAdvertSend - no memory?\n"));
  3298. ICMPv6OutStats.icmps_errors++;
  3299. return;
  3300. }
  3301. //
  3302. // Prepare IP header of the advertisement.
  3303. // We fill in the PayloadLength later.
  3304. //
  3305. IP = (IPv6Header UNALIGNED *)((uchar *)Mem + Offset);
  3306. IP->VersClassFlow = IP_VERSION;
  3307. IP->NextHeader = IP_PROTOCOL_ICMPv6;
  3308. IP->HopLimit = 255;
  3309. IP->Source = *Source;
  3310. IP->Dest = *Dest;
  3311. //
  3312. // Prepare ICMP header.
  3313. //
  3314. ICMP = (ICMPv6Header UNALIGNED *)(IP + 1);
  3315. ICMP->Type = ICMPv6_ROUTER_ADVERT;
  3316. ICMP->Code = 0;
  3317. ICMP->Checksum = 0;
  3318. //
  3319. // Prepare the Router Advertisement header.
  3320. // We fill in RouterLifetime and DefaultRoutePreference later.
  3321. //
  3322. RA = (NDRouterAdvertisement UNALIGNED *)(ICMP + 1);
  3323. RtlZeroMemory(RA, sizeof *RA);
  3324. MemLeft = (void *)(RA + 1);
  3325. if (IF->WriteLLOpt != NULL) {
  3326. //
  3327. // Include source link-layer address option if ND is enabled.
  3328. //
  3329. SourceOption = MemLeft;
  3330. SourceOptionLength = (IF->LinkAddressLength + 2 + 7) &~ 7;
  3331. ((uchar *)SourceOption)[0] = ND_OPTION_SOURCE_LINK_LAYER_ADDRESS;
  3332. ((uchar *)SourceOption)[1] = SourceOptionLength >> 3;
  3333. (*IF->WriteLLOpt)(IF->LinkContext, SourceOption, IF->LinkAddress);
  3334. MemLeft = (uchar *)SourceOption + SourceOptionLength;
  3335. }
  3336. //
  3337. // Always include MTU option.
  3338. //
  3339. MTUOption = (NDOptionMTU UNALIGNED *)MemLeft;
  3340. MTUOption->Type = ND_OPTION_MTU;
  3341. MTUOption->Length = 1;
  3342. MTUOption->Reserved = 0;
  3343. MTUOption->MTU = net_long(LinkMTU);
  3344. //
  3345. // OK, how much space is left?
  3346. //
  3347. MemLeft = (void *)(MTUOption + 1);
  3348. MemLenLeft = MemLen - (uint)((uchar *)MemLeft - (uchar *)Mem);
  3349. //
  3350. // Now we scan the routing table looking for published routes.
  3351. // We incrementally add Prefix Information and Route Information options,
  3352. // and we determine RouterLifetime and DefaultRoutePreference.
  3353. //
  3354. RouterLifetime = 0;
  3355. DefaultRoutePreference = (uint) -1;
  3356. KeAcquireSpinLock(&RouteTableLock, &OldIrql);
  3357. for (RTE = RouteTable.First; RTE != NULL; RTE = RTE->Next) {
  3358. //
  3359. // We only advertise published routes.
  3360. //
  3361. if (RTE->Flags & RTE_FLAG_PUBLISH) {
  3362. uint Life; // In seconds.
  3363. ushort PrefixScope = AddressScope(&RTE->Prefix);
  3364. //
  3365. // IoctlUpdateRouteTable guarantees this.
  3366. //
  3367. ASSERT(! IsLinkLocal(&RTE->Prefix));
  3368. if (IsOnLinkRTE(RTE) && (RTE->IF == IF)) {
  3369. NDOptionPrefixInformation UNALIGNED *Prefix;
  3370. //
  3371. // We generate a prefix-information option
  3372. // with the L and possibly the A bits set.
  3373. //
  3374. if (MemLenLeft < sizeof *Prefix)
  3375. break; // No room for more options.
  3376. Prefix = (NDOptionPrefixInformation *)MemLeft;
  3377. (uchar *)MemLeft += sizeof *Prefix;
  3378. MemLenLeft -= sizeof *Prefix;
  3379. Prefix->Type = ND_OPTION_PREFIX_INFORMATION;
  3380. Prefix->Length = 4;
  3381. Prefix->PrefixLength = (uchar)RTE->PrefixLength;
  3382. Prefix->Flags = ND_PREFIX_FLAG_ON_LINK;
  3383. if (RTE->PrefixLength == 64)
  3384. Prefix->Flags |= ND_PREFIX_FLAG_AUTONOMOUS;
  3385. Prefix->Reserved2 = 0;
  3386. Prefix->Prefix = RTE->Prefix;
  3387. //
  3388. // Is this also a site prefix?
  3389. // NB: The SitePrefixLength field overlaps Reserved2.
  3390. //
  3391. if (RTE->SitePrefixLength != 0) {
  3392. Prefix->Flags |= ND_PREFIX_FLAG_SITE_PREFIX;
  3393. Prefix->SitePrefixLength = (uchar)RTE->SitePrefixLength;
  3394. }
  3395. //
  3396. // ConvertTicksToSeconds preserves the infinite value.
  3397. //
  3398. Life = net_long(ConvertTicksToSeconds(RTE->ValidLifetime));
  3399. Prefix->ValidLifetime = Life;
  3400. Life = net_long(ConvertTicksToSeconds(RTE->PreferredLifetime));
  3401. Prefix->PreferredLifetime = Life;
  3402. }
  3403. else if (Forwards && (RTE->IF != IF) &&
  3404. (IF->ZoneIndices[PrefixScope] ==
  3405. RTE->IF->ZoneIndices[PrefixScope])) {
  3406. //
  3407. // We only advertise routes if we are forwarding
  3408. // and if we won't forward out the same interface:
  3409. // if such a router were published and used,
  3410. // we'd generate a Redirect, but better to avoid
  3411. // in the first place.
  3412. // Also, we keep scoped routes within their zone.
  3413. //
  3414. if (RTE->PrefixLength == 0) {
  3415. //
  3416. // We don't explicitly advertise zero-length prefixes.
  3417. // Instead we advertise a non-zero router lifetime.
  3418. //
  3419. if (RTE->ValidLifetime > RouterLifetime)
  3420. RouterLifetime = RTE->ValidLifetime;
  3421. if (RTE->Preference < DefaultRoutePreference)
  3422. DefaultRoutePreference = RTE->Preference;
  3423. }
  3424. else {
  3425. NDOptionRouteInformation UNALIGNED *Route;
  3426. uint OptionSize;
  3427. //
  3428. // We generate a route-information option.
  3429. //
  3430. if (RTE->PrefixLength <= 64)
  3431. OptionSize = 16;
  3432. else
  3433. OptionSize = 24;
  3434. if (MemLenLeft < OptionSize)
  3435. break; // No room for more options.
  3436. Route = (NDOptionRouteInformation *)MemLeft;
  3437. (uchar *)MemLeft += OptionSize;
  3438. MemLenLeft -= OptionSize;
  3439. Route->Type = ND_OPTION_ROUTE_INFORMATION;
  3440. Route->Length = OptionSize >> 3;
  3441. Route->PrefixLength = (uchar)RTE->PrefixLength;
  3442. Route->Flags = EncodeRoutePreference(RTE->Preference);
  3443. RtlCopyMemory(&Route->Prefix, &RTE->Prefix,
  3444. OptionSize - 8);
  3445. //
  3446. // ConvertTicksToSeconds preserves the infinite value.
  3447. //
  3448. Life = net_long(ConvertTicksToSeconds(RTE->ValidLifetime));
  3449. Route->RouteLifetime = Life;
  3450. }
  3451. }
  3452. }
  3453. }
  3454. KeReleaseSpinLock(&RouteTableLock, OldIrql);
  3455. if (RouterLifetime != 0) {
  3456. //
  3457. // We will be a default router. Calculate the 16-bit lifetime.
  3458. // Note that there is no infinite value on the wire.
  3459. //
  3460. RouterLifetime = ConvertTicksToSeconds(RouterLifetime);
  3461. if (RouterLifetime > 0xffff)
  3462. RouterLifetime = 0xffff;
  3463. RA->RouterLifetime = net_short((ushort)RouterLifetime);
  3464. RA->Flags = EncodeRoutePreference(DefaultRoutePreference);
  3465. }
  3466. //
  3467. // Calculate a payload length for the advertisement.
  3468. //
  3469. PayloadLength = (uint)((uchar *)MemLeft - (uchar *)ICMP);
  3470. IP->PayloadLength = net_short((ushort)PayloadLength);
  3471. //
  3472. // Now allocate and initialize an NDIS packet and buffer.
  3473. // This is much like IPv6AllocatePacket,
  3474. // except we already have the memory.
  3475. //
  3476. NdisAllocatePacket(&Status, &Packet, IPv6PacketPool);
  3477. if (Status != NDIS_STATUS_SUCCESS) {
  3478. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_NTOS_ERROR,
  3479. "RouterAdvertSend - couldn't allocate header!?!\n"));
  3480. ExFreePool(Mem);
  3481. ICMPv6OutStats.icmps_errors++;
  3482. return;
  3483. }
  3484. NdisAllocateBuffer(&Status, &Buffer, IPv6BufferPool,
  3485. Mem, Offset + sizeof(IPv6Header) + PayloadLength);
  3486. if (Status != NDIS_STATUS_SUCCESS) {
  3487. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_NTOS_ERROR,
  3488. "RouterAdvertSend - couldn't allocate buffer!?!\n"));
  3489. NdisFreePacket(Packet);
  3490. ExFreePool(Mem);
  3491. ICMPv6OutStats.icmps_errors++;
  3492. return;
  3493. }
  3494. InitializeNdisPacket(Packet);
  3495. PC(Packet)->CompletionHandler = IPv6PacketComplete;
  3496. NdisChainBufferAtFront(Packet, Buffer);
  3497. //
  3498. // Calculate the ICMPv6 checksum. It covers the entire ICMPv6 message
  3499. // starting with the ICMPv6 header, plus the IPv6 pseudo-header.
  3500. //
  3501. ICMP->Checksum = ChecksumPacket(
  3502. Packet, Offset + sizeof *IP, NULL, PayloadLength,
  3503. AlignAddr(&IP->Source), AlignAddr(&IP->Dest),
  3504. IP_PROTOCOL_ICMPv6);
  3505. ASSERT(ICMP->Checksum != 0);
  3506. //
  3507. // Calculate the link-level destination address.
  3508. // (The IPv6 destination is a multicast address.)
  3509. // We prevent loopback of all ND packets.
  3510. //
  3511. LLDest = alloca(IF->LinkAddressLength);
  3512. (*IF->ConvertAddr)(IF->LinkContext, AlignAddr(&IP->Dest), LLDest);
  3513. PC(Packet)->Flags = NDIS_FLAGS_MULTICAST_PACKET | NDIS_FLAGS_DONT_LOOPBACK;
  3514. //
  3515. // Before we transmit the packet (and lose ownership of the memory),
  3516. // make a pass over the packet, processing the options ourselves.
  3517. // This is like receiving our own RA, except we do not create routes.
  3518. // The options are well-formed of course.
  3519. //
  3520. Mem = (void *)(MTUOption + 1);
  3521. while (Mem < MemLeft) {
  3522. if (((uchar *)Mem)[0] == ND_OPTION_PREFIX_INFORMATION) {
  3523. NDOptionPrefixInformation UNALIGNED *Prefix =
  3524. (NDOptionPrefixInformation UNALIGNED *)Mem;
  3525. uint ValidLifetime, PreferredLifetime;
  3526. //
  3527. // Because we just constructed the prefix-information options,
  3528. // we know they are syntactically valid.
  3529. //
  3530. ValidLifetime = net_long(Prefix->ValidLifetime);
  3531. ValidLifetime = ConvertSecondsToTicks(ValidLifetime);
  3532. PreferredLifetime = net_long(Prefix->PreferredLifetime);
  3533. PreferredLifetime = ConvertSecondsToTicks(PreferredLifetime);
  3534. if ((IF->CreateToken != NULL) &&
  3535. (Prefix->Flags & ND_PREFIX_FLAG_AUTONOMOUS)) {
  3536. NetTableEntry *NTE;
  3537. //
  3538. // IoctlUpdateRouteTable only allows "proper" prefixes
  3539. // to be published.
  3540. //
  3541. ASSERT(!IsLinkLocal(AlignAddr(&Prefix->Prefix)));
  3542. ASSERT(!IsMulticast(AlignAddr(&Prefix->Prefix)));
  3543. ASSERT(Prefix->PrefixLength == 64);
  3544. //
  3545. // Perform stateless address autoconfiguration for this prefix.
  3546. //
  3547. AddrConfUpdate(IF, AlignAddr(&Prefix->Prefix),
  3548. ValidLifetime, PreferredLifetime,
  3549. TRUE, // Authenticated.
  3550. &NTE);
  3551. if (NTE != NULL) {
  3552. IPv6Addr NewAddr;
  3553. //
  3554. // Create the subnet anycast address for this prefix,
  3555. // if we created a corresponding unicast address.
  3556. //
  3557. CopyPrefix(&NewAddr, AlignAddr(&Prefix->Prefix), 64);
  3558. (void) FindOrCreateAAE(IF, &NewAddr, CastFromNTE(NTE));
  3559. ReleaseNTE(NTE);
  3560. }
  3561. }
  3562. if (Prefix->Flags & ND_PREFIX_FLAG_SITE_PREFIX) {
  3563. //
  3564. // Again, IoctlUpdateRouteTable enforces sanity checks.
  3565. //
  3566. ASSERT(!IsSiteLocal(AlignAddr(&Prefix->Prefix)));
  3567. ASSERT(Prefix->SitePrefixLength <= Prefix->PrefixLength);
  3568. ASSERT(Prefix->SitePrefixLength != 0);
  3569. SitePrefixUpdate(IF, AlignAddr(&Prefix->Prefix),
  3570. Prefix->SitePrefixLength, ValidLifetime);
  3571. }
  3572. }
  3573. (uchar *)Mem += ((uchar *)Mem)[1] << 3;
  3574. }
  3575. //
  3576. // Transmit the packet.
  3577. //
  3578. ICMPv6OutStats.icmps_typecount[ICMPv6_ROUTER_ADVERT]++;
  3579. IPv6SendLL(IF, Packet, Offset, LLDest);
  3580. }
  3581. //* GetBestRouteInfo
  3582. //
  3583. // Calculates the best source address and outgoing interface
  3584. // for the specified destination address.
  3585. //
  3586. IP_STATUS
  3587. GetBestRouteInfo(
  3588. const IPv6Addr *Addr,
  3589. ulong ScopeId,
  3590. IP6RouteEntry *Ire)
  3591. {
  3592. IP_STATUS Status;
  3593. RouteCacheEntry *RCE;
  3594. Status = RouteToDestination(Addr, ScopeId,
  3595. NULL, 0, &RCE);
  3596. if (Status != IP_SUCCESS) {
  3597. return Status;
  3598. }
  3599. Ire->ire_Length = sizeof(IP6RouteEntry);
  3600. Ire->ire_Source = RCE->NTE->Address;
  3601. Ire->ire_ScopeId = DetermineScopeId(&RCE->NTE->Address, RCE->NTE->IF);
  3602. Ire->ire_IfIndex = RCE->NTE->IF->Index;
  3603. ReleaseRCE(RCE);
  3604. return Status;
  3605. }