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

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