1 /*
2  *  Copyright (c) 2020, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file includes definitions for the RA-based routing management.
32  *
33  */
34 
35 #ifndef ROUTING_MANAGER_HPP_
36 #define ROUTING_MANAGER_HPP_
37 
38 #include "openthread-core-config.h"
39 
40 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
41 
42 #if !OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
43 #error "OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE is required for OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE."
44 #endif
45 
46 #if !OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE
47 #error "OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE is required for OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE."
48 #endif
49 
50 #include <openthread/border_routing.h>
51 #include <openthread/nat64.h>
52 #include <openthread/netdata.h>
53 
54 #include "border_router/infra_if.hpp"
55 #include "common/array.hpp"
56 #include "common/callback.hpp"
57 #include "common/error.hpp"
58 #include "common/heap_allocatable.hpp"
59 #include "common/heap_array.hpp"
60 #include "common/heap_data.hpp"
61 #include "common/linked_list.hpp"
62 #include "common/locator.hpp"
63 #include "common/message.hpp"
64 #include "common/notifier.hpp"
65 #include "common/owning_list.hpp"
66 #include "common/pool.hpp"
67 #include "common/string.hpp"
68 #include "common/timer.hpp"
69 #include "crypto/sha256.hpp"
70 #include "net/ip6.hpp"
71 #include "net/nat64_translator.hpp"
72 #include "net/nd6.hpp"
73 #include "thread/network_data.hpp"
74 
75 namespace ot {
76 
77 namespace BorderRouter {
78 
79 extern "C" void otPlatBorderRoutingProcessIcmp6Ra(otInstance *aInstance, const uint8_t *aMessage, uint16_t aLength);
80 extern "C" void otPlatBorderRoutingProcessDhcp6PdPrefix(otInstance                            *aInstance,
81                                                         const otBorderRoutingPrefixTableEntry *aPrefixInfo);
82 
83 /**
84  * Implements bi-directional routing between Thread and Infrastructure networks.
85  *
86  * The Border Routing manager works on both Thread interface and infrastructure interface.
87  * All ICMPv6 messages are sent/received on the infrastructure interface.
88  *
89  */
90 class RoutingManager : public InstanceLocator
91 {
92     friend class ot::Notifier;
93     friend class ot::Instance;
94 
95 #if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
96     friend void otPlatBorderRoutingProcessIcmp6Ra(otInstance *aInstance, const uint8_t *aMessage, uint16_t aLength);
97     friend void otPlatBorderRoutingProcessDhcp6PdPrefix(otInstance                            *aInstance,
98                                                         const otBorderRoutingPrefixTableEntry *aPrefixInfo);
99 #endif
100 
101 public:
102     typedef NetworkData::RoutePreference          RoutePreference;     ///< Route preference (high, medium, low).
103     typedef otBorderRoutingPrefixTableIterator    PrefixTableIterator; ///< Prefix Table Iterator.
104     typedef otBorderRoutingPrefixTableEntry       PrefixTableEntry;    ///< Prefix Table Entry.
105     typedef otBorderRoutingRouterEntry            RouterEntry;         ///< Router Entry.
106     typedef otPdProcessedRaInfo                   PdProcessedRaInfo;   ///< Data of PdProcessedRaInfo.
107     typedef otBorderRoutingRequestDhcp6PdCallback PdCallback;          ///< DHCPv6 PD callback.
108 
109     /**
110      * This constant specifies the maximum number of route prefixes that may be published by `RoutingManager`
111      * in Thread Network Data.
112      *
113      * This is used by `NetworkData::Publisher` to reserve entries for use by `RoutingManager`.
114      *
115      * The number of published entries accounts for:
116      * - Route prefix `fc00::/7` or `::/0`
117      * - One entry for NAT64 published prefix.
118      * - One extra entry for transitions.
119      *
120      */
121     static constexpr uint16_t kMaxPublishedPrefixes = 3;
122 
123     /**
124      * Represents the states of `RoutingManager`.
125      *
126      */
127     enum State : uint8_t
128     {
129         kStateUninitialized = OT_BORDER_ROUTING_STATE_UNINITIALIZED, ///< Uninitialized.
130         kStateDisabled      = OT_BORDER_ROUTING_STATE_DISABLED,      ///< Initialized but disabled.
131         kStateStopped       = OT_BORDER_ROUTING_STATE_STOPPED,       ///< Initialized & enabled, but currently stopped.
132         kStateRunning       = OT_BORDER_ROUTING_STATE_RUNNING,       ///< Initialized, enabled, and running.
133     };
134 
135     /**
136      * This enumeration represents the states of DHCPv6 PD in `RoutingManager`.
137      *
138      */
139     enum Dhcp6PdState : uint8_t
140     {
141         kDhcp6PdStateDisabled = OT_BORDER_ROUTING_DHCP6_PD_STATE_DISABLED, ///< Disabled.
142         kDhcp6PdStateStopped  = OT_BORDER_ROUTING_DHCP6_PD_STATE_STOPPED,  ///< Enabled, but currently stopped.
143         kDhcp6PdStateRunning  = OT_BORDER_ROUTING_DHCP6_PD_STATE_RUNNING,  ///< Enabled, and running.
144     };
145 
146     /**
147      * Initializes the routing manager.
148      *
149      * @param[in]  aInstance  A OpenThread instance.
150      *
151      */
152     explicit RoutingManager(Instance &aInstance);
153 
154     /**
155      * Initializes the routing manager on given infrastructure interface.
156      *
157      * @param[in]  aInfraIfIndex      An infrastructure network interface index.
158      * @param[in]  aInfraIfIsRunning  A boolean that indicates whether the infrastructure
159      *                                interface is running.
160      *
161      * @retval  kErrorNone         Successfully started the routing manager.
162      * @retval  kErrorInvalidArgs  The index of the infra interface is not valid.
163      *
164      */
165     Error Init(uint32_t aInfraIfIndex, bool aInfraIfIsRunning);
166 
167     /**
168      * Enables/disables the Border Routing Manager.
169      *
170      * @note  The Border Routing Manager is enabled by default.
171      *
172      * @param[in]  aEnabled   A boolean to enable/disable the Border Routing Manager.
173      *
174      * @retval  kErrorInvalidState   The Border Routing Manager is not initialized yet.
175      * @retval  kErrorNone           Successfully enabled/disabled the Border Routing Manager.
176      *
177      */
178     Error SetEnabled(bool aEnabled);
179 
180     /**
181      * Indicates whether or not it is currently running.
182      *
183      * In order for the `RoutingManager` to be running it needs to be initialized and enabled, and device being
184      * attached.
185      *
186      * @retval TRUE  The RoutingManager is currently running.
187      * @retval FALSE The RoutingManager is not running.
188      *
189      */
IsRunning(void) const190     bool IsRunning(void) const { return mIsRunning; }
191 
192     /**
193      * Gets the state of `RoutingManager`.
194      *
195      * @returns The current state of `RoutingManager`.
196      *
197      */
198     State GetState(void) const;
199 
200     /**
201      * Requests the Border Routing Manager to stop.
202      *
203      * If Border Routing Manager is running, calling this method immediately stops it and triggers the preparation
204      * and sending of a final Router Advertisement (RA) message on infrastructure interface which deprecates and/or
205      * removes any previously advertised PIO/RIO prefixes. If Routing Manager is not running (or not enabled), no
206      * action is taken.
207      *
208      * Note that this method does not change whether the Routing Manager is enabled or disabled (see `SetEnabled()`).
209      * It stops the Routing Manager temporarily. After calling this method if the device role gets changes (device
210      * gets attached) and/or the infra interface state gets changed, the Routing Manager may be started again.
211      *
212      */
RequestStop(void)213     void RequestStop(void) { Stop(); }
214 
215     /**
216      * Gets the current preference used when advertising Route Info Options (RIO) in Router Advertisement
217      * messages sent over the infrastructure link.
218      *
219      * The RIO preference is determined as follows:
220      *
221      * - If explicitly set by user by calling `SetRouteInfoOptionPreference()`, the given preference is used.
222      * - Otherwise, it is determined based on device's role: Medium preference when in router/leader role and low
223      *   preference when in child role.
224      *
225      * @returns The current Route Info Option preference.
226      *
227      */
GetRouteInfoOptionPreference(void) const228     RoutePreference GetRouteInfoOptionPreference(void) const { return mRioAdvertiser.GetPreference(); }
229 
230     /**
231      * Explicitly sets the preference to use when advertising Route Info Options (RIO) in Router
232      * Advertisement messages sent over the infrastructure link.
233      *
234      * After a call to this method, BR will use the given preference for all its advertised RIOs. The preference can be
235      * cleared by calling `ClearRouteInfoOptionPreference`()`.
236      *
237      * @param[in] aPreference   The route preference to use.
238      *
239      */
SetRouteInfoOptionPreference(RoutePreference aPreference)240     void SetRouteInfoOptionPreference(RoutePreference aPreference) { mRioAdvertiser.SetPreference(aPreference); }
241 
242     /**
243      * Clears a previously set preference value for advertised Route Info Options.
244      *
245      * After a call to this method, BR will use device role to determine the RIO preference: Medium preference when
246      * in router/leader role and low preference when in child role.
247      *
248      */
ClearRouteInfoOptionPreference(void)249     void ClearRouteInfoOptionPreference(void) { mRioAdvertiser.ClearPreference(); }
250 
251     /**
252      * Sets additional options to append at the end of emitted Router Advertisement (RA) messages.
253      *
254      * The content of @p aOptions is copied internally, so can be a temporary stack variable.
255      *
256      * Subsequent calls to this method will overwrite the previously set value.
257      *
258      * @param[in] aOptions   A pointer to the encoded options. Can be `nullptr` to clear.
259      * @param[in] aLength    Number of bytes in @p aOptions.
260      *
261      * @retval kErrorNone     Successfully set the extra option bytes.
262      * @retval kErrorNoBufs   Could not allocate buffer to save the buffer.
263      *
264      */
265     Error SetExtraRouterAdvertOptions(const uint8_t *aOptions, uint16_t aLength);
266 
267     /**
268      * Gets the current preference used for published routes in Network Data.
269      *
270      * The preference is determined as follows:
271      *
272      * - If explicitly set by user by calling `SetRoutePreference()`, the given preference is used.
273      * - Otherwise, it is determined automatically by `RoutingManager` based on the device's role and link quality.
274      *
275      * @returns The current published route preference.
276      *
277      */
GetRoutePreference(void) const278     RoutePreference GetRoutePreference(void) const { return mRoutePublisher.GetPreference(); }
279 
280     /**
281      * Explicitly sets the preference of published routes in Network Data.
282      *
283      * After a call to this method, BR will use the given preference. The preference can be cleared by calling
284      * `ClearRoutePreference`()`.
285      *
286      * @param[in] aPreference   The route preference to use.
287      *
288      */
SetRoutePreference(RoutePreference aPreference)289     void SetRoutePreference(RoutePreference aPreference) { mRoutePublisher.SetPreference(aPreference); }
290 
291     /**
292      * Clears a previously set preference value for published routes in Network Data.
293      *
294      * After a call to this method, BR will determine the preference automatically based on the device's role and
295      * link quality (to the parent when acting as end-device).
296      *
297      */
ClearRoutePreference(void)298     void ClearRoutePreference(void) { mRoutePublisher.ClearPreference(); }
299 
300     /**
301      * Returns the local generated off-mesh-routable (OMR) prefix.
302      *
303      * The randomly generated 64-bit prefix will be added to the Thread Network Data if there isn't already an OMR
304      * prefix.
305      *
306      * @param[out]  aPrefix  A reference to where the prefix will be output to.
307      *
308      * @retval  kErrorInvalidState  The Border Routing Manager is not initialized yet.
309      * @retval  kErrorNone          Successfully retrieved the OMR prefix.
310      *
311      */
312     Error GetOmrPrefix(Ip6::Prefix &aPrefix) const;
313 
314     /**
315      * Returns the currently favored off-mesh-routable (OMR) prefix.
316      *
317      * The favored OMR prefix can be discovered from Network Data or can be our local OMR prefix.
318      *
319      * An OMR prefix with higher preference is favored. If the preference is the same, then the smaller prefix (in the
320      * sense defined by `Ip6::Prefix`) is favored.
321      *
322      * @param[out] aPrefix         A reference to output the favored prefix.
323      * @param[out] aPreference     A reference to output the preference associated with the favored OMR prefix.
324      *
325      * @retval  kErrorInvalidState  The Border Routing Manager is not running yet.
326      * @retval  kErrorNone          Successfully retrieved the OMR prefix.
327      *
328      */
329     Error GetFavoredOmrPrefix(Ip6::Prefix &aPrefix, RoutePreference &aPreference) const;
330 
331     /**
332      * Returns the on-link prefix for the adjacent infrastructure link.
333      *
334      * The randomly generated 64-bit prefix will be advertised
335      * on the infrastructure link if there isn't already a usable
336      * on-link prefix being advertised on the link.
337      *
338      * @param[out]  aPrefix  A reference to where the prefix will be output to.
339      *
340      * @retval  kErrorInvalidState  The Border Routing Manager is not initialized yet.
341      * @retval  kErrorNone          Successfully retrieved the local on-link prefix.
342      *
343      */
344     Error GetOnLinkPrefix(Ip6::Prefix &aPrefix) const;
345 
346     /**
347      * Returns the favored on-link prefix for the adjacent infrastructure link.
348      *
349      * The favored prefix is either a discovered prefix on the infrastructure link or the local on-link prefix.
350      *
351      * @param[out]  aPrefix  A reference to where the prefix will be output to.
352      *
353      * @retval  kErrorInvalidState  The Border Routing Manager is not initialized yet.
354      * @retval  kErrorNone          Successfully retrieved the favored on-link prefix.
355      *
356      */
357     Error GetFavoredOnLinkPrefix(Ip6::Prefix &aPrefix) const;
358 
359 #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
360     /**
361      * Gets the state of NAT64 prefix publishing.
362      *
363      * @retval  kStateDisabled   NAT64 is disabled.
364      * @retval  kStateNotRunning NAT64 is enabled, but is not running since routing manager is not running.
365      * @retval  kStateIdle       NAT64 is enabled, but the border router is not publishing a NAT64 prefix. Usually
366      *                           when there is another border router publishing a NAT64 prefix with higher
367      *                           priority.
368      * @retval  kStateActive     The Border router is publishing a NAT64 prefix.
369      *
370      */
GetNat64PrefixManagerState(void) const371     Nat64::State GetNat64PrefixManagerState(void) const { return mNat64PrefixManager.GetState(); }
372 
373     /**
374      * Enable or disable NAT64 prefix publishing.
375      *
376      * @param[in]  aEnabled   A boolean to enable/disable NAT64 prefix publishing.
377      *
378      */
379     void SetNat64PrefixManagerEnabled(bool aEnabled);
380 
381     /**
382      * Returns the local NAT64 prefix.
383      *
384      * @param[out]  aPrefix  A reference to where the prefix will be output to.
385      *
386      * @retval  kErrorInvalidState  The Border Routing Manager is not initialized yet.
387      * @retval  kErrorNone          Successfully retrieved the NAT64 prefix.
388      *
389      */
390     Error GetNat64Prefix(Ip6::Prefix &aPrefix);
391 
392     /**
393      * Returns the currently favored NAT64 prefix.
394      *
395      * The favored NAT64 prefix can be discovered from infrastructure link or can be the local NAT64 prefix.
396      *
397      * @param[out] aPrefix           A reference to output the favored prefix.
398      * @param[out] aRoutePreference  A reference to output the preference associated with the favored prefix.
399      *
400      * @retval  kErrorInvalidState  The Border Routing Manager is not initialized yet.
401      * @retval  kErrorNone          Successfully retrieved the NAT64 prefix.
402      *
403      */
404     Error GetFavoredNat64Prefix(Ip6::Prefix &aPrefix, RoutePreference &aRoutePreference);
405 
406     /**
407      * Informs `RoutingManager` of the result of the discovery request of NAT64 prefix on infrastructure
408      * interface (`InfraIf::DiscoverNat64Prefix()`).
409      *
410      * @param[in]  aPrefix  The discovered NAT64 prefix on `InfraIf`.
411      *
412      */
HandleDiscoverNat64PrefixDone(const Ip6::Prefix & aPrefix)413     void HandleDiscoverNat64PrefixDone(const Ip6::Prefix &aPrefix) { mNat64PrefixManager.HandleDiscoverDone(aPrefix); }
414 
415 #endif // OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
416 
417     /**
418      * Processes a received ICMPv6 message from the infrastructure interface.
419      *
420      * Malformed or undesired messages are dropped silently.
421      *
422      * @param[in]  aPacket        The received ICMPv6 packet.
423      * @param[in]  aSrcAddress    The source address this message is sent from.
424      *
425      */
426     void HandleReceived(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress);
427 
428     /**
429      * Handles infrastructure interface state changes.
430      *
431      */
HandleInfraIfStateChanged(void)432     void HandleInfraIfStateChanged(void) { EvaluateState(); }
433 
434     /**
435      * Checks whether the on-mesh prefix configuration is a valid OMR prefix.
436      *
437      * @param[in] aOnMeshPrefixConfig  The on-mesh prefix configuration to check.
438      *
439      * @retval   TRUE    The prefix is a valid OMR prefix.
440      * @retval   FALSE   The prefix is not a valid OMR prefix.
441      *
442      */
443     static bool IsValidOmrPrefix(const NetworkData::OnMeshPrefixConfig &aOnMeshPrefixConfig);
444 
445     /**
446      * Checks whether a given prefix is a valid OMR prefix.
447      *
448      * @param[in]  aPrefix  The prefix to check.
449      *
450      * @retval   TRUE    The prefix is a valid OMR prefix.
451      * @retval   FALSE   The prefix is not a valid OMR prefix.
452      *
453      */
454     static bool IsValidOmrPrefix(const Ip6::Prefix &aPrefix);
455 
456     /**
457      * Initializes a `PrefixTableIterator`.
458      *
459      * An iterator can be initialized again to start from the beginning of the table.
460      *
461      * When iterating over entries in the table, to ensure the entry update times are consistent, they are given
462      * relative to the time the iterator was initialized.
463      *
464      * @param[out] aIterator  The iterator to initialize.
465      *
466      */
InitPrefixTableIterator(PrefixTableIterator & aIterator) const467     void InitPrefixTableIterator(PrefixTableIterator &aIterator) const { mRxRaTracker.InitIterator(aIterator); }
468 
469     /**
470      * Iterates over entries in the discovered prefix table.
471      *
472      * @param[in,out] aIterator  An iterator.
473      * @param[out]    aEntry     A reference to the entry to populate.
474      *
475      * @retval kErrorNone        Got the next entry, @p aEntry is updated and @p aIterator is advanced.
476      * @retval kErrorNotFound    No more entries in the table.
477      *
478      */
GetNextPrefixTableEntry(PrefixTableIterator & aIterator,PrefixTableEntry & aEntry) const479     Error GetNextPrefixTableEntry(PrefixTableIterator &aIterator, PrefixTableEntry &aEntry) const
480     {
481         return mRxRaTracker.GetNextEntry(aIterator, aEntry);
482     }
483 
484     /**
485      * Iterates over discovered router entries on infrastructure link.
486      *
487      * @param[in,out] aIterator  An iterator.
488      * @param[out]    aEntry     A reference to the entry to populate.
489      *
490      * @retval kErrorNone        Got the next router info, @p aEntry is updated and @p aIterator is advanced.
491      * @retval kErrorNotFound    No more routers.
492      *
493      */
GetNextRouterEntry(PrefixTableIterator & aIterator,RouterEntry & aEntry) const494     Error GetNextRouterEntry(PrefixTableIterator &aIterator, RouterEntry &aEntry) const
495     {
496         return mRxRaTracker.GetNextRouter(aIterator, aEntry);
497     }
498 
499 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
500     /**
501      * Determines whether to enable/disable SRP server when the auto-enable mode is changed on SRP server.
502      *
503      * This should be called from `Srp::Server` when auto-enable mode is changed.
504      *
505      */
506     void HandleSrpServerAutoEnableMode(void);
507 #endif
508 
509 #if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
510     /**
511      * Enables / Disables the DHCPv6 Prefix Delegation.
512      *
513      * @param[in] aEnabled  Whether to enable or disable.
514      *
515      */
SetDhcp6PdEnabled(bool aEnabled)516     void SetDhcp6PdEnabled(bool aEnabled) { return mPdPrefixManager.SetEnabled(aEnabled); }
517 
518     /**
519      * Returns the state DHCPv6 Prefix Delegation manager.
520      *
521      * @returns The DHCPv6 PD state.
522      *
523      */
GetDhcp6PdState(void) const524     Dhcp6PdState GetDhcp6PdState(void) const { return mPdPrefixManager.GetState(); }
525 
526     /**
527      * Sets the callback to notify when DHCPv6 Prefix Delegation manager state gets changed.
528      *
529      * @param[in] aCallback  A pointer to a callback function
530      * @param[in] aContext   A pointer to arbitrary context information.
531      *
532      */
SetRequestDhcp6PdCallback(PdCallback aCallback,void * aContext)533     void SetRequestDhcp6PdCallback(PdCallback aCallback, void *aContext)
534     {
535         mPdPrefixManager.SetStateCallback(aCallback, aContext);
536     }
537 
538     /**
539      * Returns the DHCPv6-PD based off-mesh-routable (OMR) prefix.
540      *
541      * @param[out] aPrefixInfo      A reference to where the prefix info will be output to.
542      *
543      * @retval kErrorNone           Successfully retrieved the OMR prefix.
544      * @retval kErrorNotFound       There are no valid PD prefix on this BR.
545      * @retval kErrorInvalidState   The Border Routing Manager is not initialized yet.
546      *
547      */
548     Error GetPdOmrPrefix(PrefixTableEntry &aPrefixInfo) const;
549 
550     /**
551      * Returns platform generated RA message processed counters and information.
552      *
553      * @param[out] aPdProcessedRaInfo  A reference to where the PD processed RA info will be output to.
554      *
555      * @retval kErrorNone           Successfully retrieved the Info.
556      * @retval kErrorNotFound       There are no valid RA process info on this BR.
557      * @retval kErrorInvalidState   The Border Routing Manager is not initialized yet.
558      *
559      */
560     Error GetPdProcessedRaInfo(PdProcessedRaInfo &aPdProcessedRaInfo);
561 
562 #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
563 
564 private:
565     //------------------------------------------------------------------------------------------------------------------
566     // Constants
567 
568     static constexpr uint8_t kMaxOnMeshPrefixes = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_ON_MESH_PREFIXES;
569 
570     // Prefix length in bits.
571     static constexpr uint8_t kOmrPrefixLength    = 64;
572     static constexpr uint8_t kOnLinkPrefixLength = 64;
573     static constexpr uint8_t kBrUlaPrefixLength  = 48;
574     static constexpr uint8_t kNat64PrefixLength  = 96;
575 
576     // Subnet IDs for OMR and NAT64 prefixes.
577     static constexpr uint16_t kOmrPrefixSubnetId   = 1;
578     static constexpr uint16_t kNat64PrefixSubnetId = 2;
579 
580     // Default valid lifetime. In seconds.
581     static constexpr uint32_t kDefaultOmrPrefixLifetime    = 1800;
582     static constexpr uint32_t kDefaultOnLinkPrefixLifetime = 1800;
583     static constexpr uint32_t kDefaultNat64PrefixLifetime  = 300;
584 
585     // The entry stale time in seconds.
586     //
587     // The amount of time that can pass after the last time an RA from
588     // a particular router has been received advertising an on-link
589     // or route prefix before we assume the prefix entry is stale.
590     //
591     // If multiple routers advertise the same on-link or route prefix,
592     // the stale time for the prefix is determined by the latest
593     // stale time among all corresponding entries. Stale time
594     // expiration triggers tx of Router Solicitation (RS) messages
595 
596     static constexpr uint32_t kStaleTime = 600; // 10 minutes.
597 
598     // RA transmission constants (in milliseconds). Initially, three
599     // RAs are sent with a short interval of 16 seconds (± 2 seconds
600     // jitter). Subsequently, a longer, regular RA beacon interval of
601     // 3 minutes (± 15 seconds jitter) is used. The actual interval is
602     // randomly selected within the range [interval - jitter,
603     // interval + jitter].
604 
605     static constexpr uint32_t kInitalRaTxCount    = 3;
606     static constexpr uint32_t kInitalRaInterval   = Time::kOneSecondInMsec * 16;
607     static constexpr uint16_t kInitialRaJitter    = Time::kOneSecondInMsec * 2;
608     static constexpr uint32_t kRaBeaconInterval   = Time::kOneSecondInMsec * 180; // 3 minutes
609     static constexpr uint16_t kRaBeaconJitter     = Time::kOneSecondInMsec * 15;
610     static constexpr uint32_t kMinDelayBetweenRas = Time::kOneSecondInMsec * 3;
611     static constexpr uint32_t kRsReplyInterval    = 250;
612     static constexpr uint16_t kRsReplyJitter      = 250;
613     static constexpr uint32_t kEvaluationInterval = Time::kOneSecondInMsec * 3;
614     static constexpr uint16_t kEvaluationJitter   = Time::kOneSecondInMsec * 1;
615 
616     //------------------------------------------------------------------------------------------------------------------
617     // Typedefs
618 
619     using Option                 = Ip6::Nd::Option;
620     using PrefixInfoOption       = Ip6::Nd::PrefixInfoOption;
621     using RouteInfoOption        = Ip6::Nd::RouteInfoOption;
622     using RaFlagsExtOption       = Ip6::Nd::RaFlagsExtOption;
623     using RouterAdvert           = Ip6::Nd::RouterAdvert;
624     using NeighborAdvertMessage  = Ip6::Nd::NeighborAdvertMessage;
625     using NeighborSolicitMessage = Ip6::Nd::NeighborSolicitMessage;
626     using RouterSolicitMessage   = Ip6::Nd::RouterSolicitMessage;
627 
628     //------------------------------------------------------------------------------------------------------------------
629     // Enumerations
630 
631     enum RouterAdvTxMode : uint8_t // Used in `SendRouterAdvertisement()`
632     {
633         kInvalidateAllPrevPrefixes,
634         kAdvPrefixesFromNetData,
635     };
636 
637     enum RouterAdvOrigin : uint8_t // Origin of a received Router Advert message.
638     {
639         kAnotherRouter,        // From another router on infra-if.
640         kThisBrRoutingManager, // From this BR generated by `RoutingManager` itself.
641         kThisBrOtherEntity,    // From this BR generated by another sw entity.
642     };
643 
644     enum ScheduleMode : uint8_t // Used in `ScheduleRoutingPolicyEvaluation()`
645     {
646         kImmediately,
647         kForNextRa,
648         kAfterRandomDelay,
649         kToReplyToRs,
650     };
651 
652     //------------------------------------------------------------------------------------------------------------------
653     // Nested types
654 
655     class LifetimedPrefix
656     {
657         // Represents an IPv6 prefix with its valid lifetime. Used as
658         // base class for `OnLinkPrefix` or `RoutePrefix`.
659 
660     public:
661         enum UlaChecker : bool
662         {
663             kIsNotUla = false,
664             kIsUla    = true,
665         };
666 
667         struct ExpirationChecker
668         {
ExpirationCheckerot::BorderRouter::RoutingManager::LifetimedPrefix::ExpirationChecker669             explicit ExpirationChecker(TimeMilli aNow) { mNow = aNow; }
670             TimeMilli mNow;
671         };
672 
GetPrefix(void) const673         const Ip6::Prefix &GetPrefix(void) const { return mPrefix; }
GetPrefix(void)674         Ip6::Prefix       &GetPrefix(void) { return mPrefix; }
GetLastUpdateTime(void) const675         const TimeMilli   &GetLastUpdateTime(void) const { return mLastUpdateTime; }
GetValidLifetime(void) const676         uint32_t           GetValidLifetime(void) const { return mValidLifetime; }
GetExpireTime(void) const677         TimeMilli          GetExpireTime(void) const { return CalculateExpirationTime(mValidLifetime); }
678 
Matches(const Ip6::Prefix & aPrefix) const679         bool Matches(const Ip6::Prefix &aPrefix) const { return (mPrefix == aPrefix); }
Matches(const UlaChecker & aIsUla) const680         bool Matches(const UlaChecker &aIsUla) const { return (mPrefix.IsUniqueLocal() == aIsUla); }
Matches(const ExpirationChecker & aChecker) const681         bool Matches(const ExpirationChecker &aChecker) const { return (GetExpireTime() <= aChecker.mNow); }
682 
SetStaleTimeCalculated(bool aFlag)683         void SetStaleTimeCalculated(bool aFlag) { mStaleTimeCalculated = aFlag; }
IsStaleTimeCalculated(void) const684         bool IsStaleTimeCalculated(void) const { return mStaleTimeCalculated; }
685 
686     protected:
687         LifetimedPrefix(void) = default;
688 
689         TimeMilli CalculateExpirationTime(uint32_t aLifetime) const;
690 
691         Ip6::Prefix mPrefix;
692         bool        mStaleTimeCalculated : 1;
693         uint32_t    mValidLifetime;
694         TimeMilli   mLastUpdateTime;
695     };
696 
697     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
698 
699     class OnLinkPrefix : public LifetimedPrefix, public Clearable<OnLinkPrefix>
700     {
701     public:
702         void      SetFrom(const PrefixInfoOption &aPio);
703         void      SetFrom(const PrefixTableEntry &aPrefixTableEntry);
GetPreferredLifetime(void) const704         uint32_t  GetPreferredLifetime(void) const { return mPreferredLifetime; }
ClearPreferredLifetime(void)705         void      ClearPreferredLifetime(void) { mPreferredLifetime = 0; }
706         bool      IsDeprecated(void) const;
707         TimeMilli GetDeprecationTime(void) const;
708         TimeMilli GetStaleTime(void) const;
709         void      AdoptValidAndPreferredLifetimesFrom(const OnLinkPrefix &aPrefix);
710         void      CopyInfoTo(PrefixTableEntry &aEntry, TimeMilli aNow) const;
711 
712     private:
713         uint32_t mPreferredLifetime;
714     };
715 
716     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
717 
718     class RoutePrefix : public LifetimedPrefix, public Clearable<RoutePrefix>
719     {
720     public:
721         void            SetFrom(const RouteInfoOption &aRio);
722         void            SetFrom(const RouterAdvert::Header &aRaHeader);
ClearValidLifetime(void)723         void            ClearValidLifetime(void) { mValidLifetime = 0; }
724         TimeMilli       GetStaleTime(void) const;
GetRoutePreference(void) const725         RoutePreference GetRoutePreference(void) const { return mRoutePreference; }
726         void            CopyInfoTo(PrefixTableEntry &aEntry, TimeMilli aNow) const;
727 
728     private:
729         RoutePreference mRoutePreference;
730     };
731 
732     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
733 
HandleRxRaTrackerSignalTask(void)734     void HandleRxRaTrackerSignalTask(void) { mRxRaTracker.HandleSignalTask(); }
HandleRxRaTrackerExpirationTimer(void)735     void HandleRxRaTrackerExpirationTimer(void) { mRxRaTracker.HandleExpirationTimer(); }
HandleRxRaTrackerStaleTimer(void)736     void HandleRxRaTrackerStaleTimer(void) { mRxRaTracker.HandleStaleTimer(); }
HandleRxRaTrackerRouterTimer(void)737     void HandleRxRaTrackerRouterTimer(void) { mRxRaTracker.HandleRouterTimer(); }
738 
739     class RxRaTracker : public InstanceLocator
740     {
741         // Processes received RA and NA messages tracking a table of active
742         // routers and their advertised on-link and route prefixes. Also
743         // manages prefix lifetimes and router reachability (sending NS probes
744         // as needed).
745         //
746         // When there is any change in the table (an entry is added, removed,
747         // or modified), it signals the change to `RoutingManager` by calling
748         // `HandleRaPrefixTableChanged()` callback. A `Tasklet` is used for
749         // signalling which ensures that if there are multiple changes within
750         // the same flow of execution, the callback is invoked after all the
751         // changes are processed.
752 
753     public:
754         explicit RxRaTracker(Instance &aInstance);
755 
756         void Start(void);
757         void Stop(void);
758 
759         void ProcessRouterAdvertMessage(const RouterAdvert::RxMessage &aRaMessage,
760                                         const Ip6::Address            &aSrcAddress,
761                                         RouterAdvOrigin                aRaOrigin);
762         void ProcessNeighborAdvertMessage(const NeighborAdvertMessage &aNaMessage);
763 
764         bool ContainsDefaultOrNonUlaRoutePrefix(void) const;
765         bool ContainsNonUlaOnLinkPrefix(void) const;
766         bool ContainsUlaOnLinkPrefix(void) const;
767 
768         void FindFavoredOnLinkPrefix(Ip6::Prefix &aPrefix) const;
769 
770         void HandleLocalOnLinkPrefixChanged(void);
771         void HandleNetDataChange(void);
772 
773         void RemoveOrDeprecateOldEntries(TimeMilli aTimeThreshold);
774 
GetLocalRaHeaderToMirror(void) const775         const RouterAdvert::Header &GetLocalRaHeaderToMirror(void) const { return mLocalRaHeader; }
776 
777         void DetermineAndSetFlags(RouterAdvert::Header &aHeader) const;
778 
779         void  InitIterator(PrefixTableIterator &aIterator) const;
780         Error GetNextEntry(PrefixTableIterator &aIterator, PrefixTableEntry &aEntry) const;
781         Error GetNextRouter(PrefixTableIterator &aIterator, RouterEntry &aEntry) const;
782 
783         void HandleSignalTask(void);
784         void HandleExpirationTimer(void);
785         void HandleStaleTimer(void);
786         void HandleRouterTimer(void);
787 
788     private:
789         static constexpr uint32_t kFavoredOnLinkPrefixMinPreferredLifetime = 1800; // In sec.
790 
791         //-  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
792 
793         template <class Type>
794         struct Entry : public Type,
795                        public LinkedListEntry<Entry<Type>>,
796 #if OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
797                        public Heap::Allocatable<Entry<Type>>
798 #else
799                        public InstanceLocatorInit
800 #endif
801         {
802 #if !OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
Initot::BorderRouter::RoutingManager::RxRaTracker::Entry803             void Init(Instance &aInstance) { InstanceLocatorInit::Init(aInstance); }
804             void Free(void);
805 #endif
806 
807             Entry<Type> *mNext;
808         };
809 
810         //-  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
811 
812         struct Router : public Clearable<Router>
813         {
814             // The timeout (in msec) for router staying in active state
815             // before starting the Neighbor Solicitation (NS) probes.
816             static constexpr uint32_t kActiveTimeout = OPENTHREAD_CONFIG_BORDER_ROUTING_ROUTER_ACTIVE_CHECK_TIMEOUT;
817 
818             static constexpr uint8_t  kMaxNsProbes          = 5;    // Max number of NS probe attempts.
819             static constexpr uint32_t kNsProbeRetryInterval = 1000; // In msec. Time between NS probe attempts.
820             static constexpr uint32_t kNsProbeTimeout       = 2000; // In msec. Max Wait time after last NS probe.
821             static constexpr uint32_t kJitter               = 2000; // In msec. Jitter to randomize probe starts.
822 
823             static_assert(kMaxNsProbes < 255, "kMaxNsProbes MUST not be 255");
824 
825             enum EmptyChecker : uint8_t
826             {
827                 kContainsNoEntriesOrFlags
828             };
829 
Matchesot::BorderRouter::RoutingManager::RxRaTracker::Router830             bool Matches(const Ip6::Address &aAddress) const { return aAddress == mAddress; }
831             bool Matches(EmptyChecker aChecker) const;
832             void CopyInfoTo(RouterEntry &aEntry, TimeMilli aNow) const;
833 
834             using OnLinkPrefixList = OwningList<Entry<OnLinkPrefix>>;
835             using RoutePrefixList  = OwningList<Entry<RoutePrefix>>;
836 
837             Ip6::Address     mAddress;
838             OnLinkPrefixList mOnLinkPrefixes;
839             RoutePrefixList  mRoutePrefixes;
840             TimeMilli        mLastUpdateTime;
841             TimeMilli        mTimeout;
842             uint8_t          mNsProbeCount;
843             bool             mManagedAddressConfigFlag : 1;
844             bool             mOtherConfigFlag : 1;
845             bool             mStubRouterFlag : 1;
846             bool             mIsLocalDevice : 1;
847         };
848 
849         //-  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
850 
851         class Iterator : public PrefixTableIterator
852         {
853         public:
854             enum Type : uint8_t
855             {
856                 kUnspecified,
857                 kRouterIterator,
858                 kPrefixIterator,
859             };
860 
861             enum EntryType : uint8_t
862             {
863                 kOnLinkPrefix,
864                 kRoutePrefix,
865             };
866 
867             void                 Init(const Entry<Router> *aRoutersHead);
868             Error                AdvanceToNextRouter(Type aType);
869             Error                AdvanceToNextEntry(void);
GetInitTime(void) const870             TimeMilli            GetInitTime(void) const { return TimeMilli(mData1); }
GetType(void) const871             Type                 GetType(void) const { return static_cast<Type>(mData2); }
GetRouter(void) const872             const Entry<Router> *GetRouter(void) const { return static_cast<const Entry<Router> *>(mPtr1); }
GetEntryType(void) const873             EntryType            GetEntryType(void) const { return static_cast<EntryType>(mData3); }
874 
GetEntry(void) const875             template <class PrefixType> const Entry<PrefixType> *GetEntry(void) const
876             {
877                 return static_cast<const Entry<PrefixType> *>(mPtr2);
878             }
879 
880         private:
SetRouter(const Entry<Router> * aRouter)881             void SetRouter(const Entry<Router> *aRouter) { mPtr1 = aRouter; }
SetInitTime(void)882             void SetInitTime(void) { mData1 = TimerMilli::GetNow().GetValue(); }
SetEntry(const void * aEntry)883             void SetEntry(const void *aEntry) { mPtr2 = aEntry; }
HasEntry(void) const884             bool HasEntry(void) const { return mPtr2 != nullptr; }
SetEntryType(EntryType aType)885             void SetEntryType(EntryType aType) { mData3 = aType; }
SetType(Type aType)886             void SetType(Type aType) { mData2 = aType; }
887         };
888 
889         //-  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
890 
891 #if !OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
892         static constexpr uint16_t kMaxRouters = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_ROUTERS;
893         static constexpr uint16_t kMaxEntries = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_PREFIXES;
894 
895         union SharedEntry
896         {
SharedEntry(void)897             SharedEntry(void) { mNext = nullptr; }
SetNext(SharedEntry * aNext)898             void               SetNext(SharedEntry *aNext) { mNext = aNext; }
GetNext(void)899             SharedEntry       *GetNext(void) { return mNext; }
GetNext(void) const900             const SharedEntry *GetNext(void) const { return mNext; }
901 
902             template <class PrefixType> Entry<PrefixType> &GetEntry(void);
903 
904             SharedEntry        *mNext;
905             Entry<OnLinkPrefix> mOnLinkEntry;
906             Entry<RoutePrefix>  mRouteEntry;
907         };
908 #endif
909 
910         //-  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
911 
912         void ProcessRaHeader(const RouterAdvert::Header &aRaHeader, Router &aRouter, RouterAdvOrigin aRaOrigin);
913         void ProcessPrefixInfoOption(const PrefixInfoOption &aPio, Router &aRouter);
914         void ProcessRouteInfoOption(const RouteInfoOption &aRio, Router &aRouter);
915         void ProcessRaFlagsExtOption(const RaFlagsExtOption &aFlagsOption, Router &aRouter);
916         bool ContainsOnLinkPrefix(OnLinkPrefix::UlaChecker aUlaChecker) const;
917         void RemoveOrDeprecateEntriesFromInactiveRouters(void);
918         void RemoveRoutersWithNoEntriesOrFlags(void);
919         void RemoveExpiredEntries(void);
920         void SignalTableChanged(void);
921         void ScheduleStaleTimer(void);
922         void DetermineStaleTimeFor(const OnLinkPrefix &aPrefix, NextFireTime &aStaleTime);
923         void DetermineStaleTimeFor(const RoutePrefix &aPrefix, NextFireTime &aStaleTime);
924         void UpdateRouterOnRx(Router &aRouter);
925         void SendNeighborSolicitToRouter(const Router &aRouter);
926 #if OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
AllocateEntry(void)927         template <class Type> Entry<Type> *AllocateEntry(void) { return Entry<Type>::Allocate(); }
928 #else
929         template <class Type> Entry<Type> *AllocateEntry(void);
930 #endif
931 
932         using SignalTask      = TaskletIn<RoutingManager, &RoutingManager::HandleRxRaTrackerSignalTask>;
933         using ExpirationTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleRxRaTrackerExpirationTimer>;
934         using StaleTimer      = TimerMilliIn<RoutingManager, &RoutingManager::HandleRxRaTrackerStaleTimer>;
935         using RouterTimer     = TimerMilliIn<RoutingManager, &RoutingManager::HandleRxRaTrackerRouterTimer>;
936         using RouterList      = OwningList<Entry<Router>>;
937 
938         RouterList           mRouters;
939         ExpirationTimer      mExpirationTimer;
940         StaleTimer           mStaleTimer;
941         RouterTimer          mRouterTimer;
942         SignalTask           mSignalTask;
943         RouterAdvert::Header mLocalRaHeader;
944         TimeMilli            mLocalRaHeaderUpdateTime;
945 #if !OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
946         Pool<SharedEntry, kMaxEntries>   mEntryPool;
947         Pool<Entry<Router>, kMaxRouters> mRouterPool;
948 #endif
949     };
950 
951     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
952 
953     class OmrPrefixManager;
954 
955     class OmrPrefix : public Clearable<OmrPrefix>
956     {
957         friend class OmrPrefixManager;
958 
959     public:
OmrPrefix(void)960         OmrPrefix(void) { Clear(); }
961 
IsEmpty(void) const962         bool               IsEmpty(void) const { return (mPrefix.GetLength() == 0); }
GetPrefix(void) const963         const Ip6::Prefix &GetPrefix(void) const { return mPrefix; }
GetPreference(void) const964         RoutePreference    GetPreference(void) const { return mPreference; }
IsDomainPrefix(void) const965         bool               IsDomainPrefix(void) const { return mIsDomainPrefix; }
966 
967     protected:
968         Ip6::Prefix     mPrefix;
969         RoutePreference mPreference;
970         bool            mIsDomainPrefix;
971     };
972 
973     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
974 
975     class FavoredOmrPrefix : public OmrPrefix
976     {
977         friend class OmrPrefixManager;
978 
979     public:
980         bool IsInfrastructureDerived(void) const;
981 
982     private:
983         void SetFrom(const NetworkData::OnMeshPrefixConfig &aOnMeshPrefixConfig);
984         void SetFrom(const OmrPrefix &aOmrPrefix);
985         bool IsFavoredOver(const NetworkData::OnMeshPrefixConfig &aOmrPrefixConfig) const;
986     };
987 
988     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
989 
990     class OmrPrefixManager : public InstanceLocator
991     {
992     public:
993         explicit OmrPrefixManager(Instance &aInstance);
994 
995         void                    Init(const Ip6::Prefix &aBrUlaPrefix);
996         void                    Start(void);
997         void                    Stop(void);
998         void                    Evaluate(void);
999         void                    UpdateDefaultRouteFlag(bool aDefaultRoute);
1000         bool                    ShouldAdvertiseLocalAsRio(void) const;
GetGeneratedPrefix(void) const1001         const Ip6::Prefix      &GetGeneratedPrefix(void) const { return mGeneratedPrefix; }
GetLocalPrefix(void) const1002         const OmrPrefix        &GetLocalPrefix(void) const { return mLocalPrefix; }
GetFavoredPrefix(void) const1003         const FavoredOmrPrefix &GetFavoredPrefix(void) const { return mFavoredPrefix; }
1004 
1005     private:
1006         static constexpr uint16_t kInfoStringSize = 85;
1007 
1008         typedef String<kInfoStringSize> InfoString;
1009 
1010         void       DetermineFavoredPrefix(void);
1011         Error      AddLocalToNetData(void);
1012         Error      AddOrUpdateLocalInNetData(void);
1013         void       RemoveLocalFromNetData(void);
1014         InfoString LocalToString(void) const;
1015 
1016         OmrPrefix        mLocalPrefix;
1017         Ip6::Prefix      mGeneratedPrefix;
1018         FavoredOmrPrefix mFavoredPrefix;
1019         bool             mIsLocalAddedInNetData;
1020         bool             mDefaultRoute;
1021     };
1022 
1023     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1024 
HandleOnLinkPrefixManagerTimer(void)1025     void HandleOnLinkPrefixManagerTimer(void) { mOnLinkPrefixManager.HandleTimer(); }
1026 
1027     class OnLinkPrefixManager : public InstanceLocator
1028     {
1029     public:
1030         explicit OnLinkPrefixManager(Instance &aInstance);
1031 
1032         // Max number of old on-link prefixes to retain to deprecate.
1033         static constexpr uint16_t kMaxOldPrefixes = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_OLD_ON_LINK_PREFIXES;
1034 
1035         void               Init(void);
1036         void               Start(void);
1037         void               Stop(void);
1038         void               Evaluate(void);
GetLocalPrefix(void) const1039         const Ip6::Prefix &GetLocalPrefix(void) const { return mLocalPrefix; }
GetFavoredDiscoveredPrefix(void) const1040         const Ip6::Prefix &GetFavoredDiscoveredPrefix(void) const { return mFavoredDiscoveredPrefix; }
1041         bool               IsInitalEvaluationDone(void) const;
1042         void               HandleRaPrefixTableChanged(void);
1043         bool               ShouldPublishUlaRoute(void) const;
1044         Error              AppendAsPiosTo(RouterAdvert::TxMessage &aRaMessage);
1045         void               HandleNetDataChange(void);
1046         void               HandleExtPanIdChange(void);
1047         void               HandleTimer(void);
1048 
1049     private:
1050         enum State : uint8_t // State of `mLocalPrefix`
1051         {
1052             kIdle,
1053             kPublishing,
1054             kAdvertising,
1055             kDeprecating,
1056         };
1057 
1058         struct OldPrefix
1059         {
Matchesot::BorderRouter::RoutingManager::OnLinkPrefixManager::OldPrefix1060             bool Matches(const Ip6::Prefix &aPrefix) const { return mPrefix == aPrefix; }
1061 
1062             Ip6::Prefix mPrefix;
1063             TimeMilli   mExpireTime;
1064         };
1065 
GetState(void) const1066         State GetState(void) const { return mState; }
1067         void  SetState(State aState);
1068         bool  IsPublishingOrAdvertising(void) const;
1069         void  GenerateLocalPrefix(void);
1070         void  PublishAndAdvertise(void);
1071         void  Deprecate(void);
1072         void  ResetExpireTime(TimeMilli aNow);
1073         Error AppendCurPrefix(RouterAdvert::TxMessage &aRaMessage);
1074         Error AppendOldPrefixes(RouterAdvert::TxMessage &aRaMessage);
1075         void  DeprecateOldPrefix(const Ip6::Prefix &aPrefix, TimeMilli aExpireTime);
1076         void  SavePrefix(const Ip6::Prefix &aPrefix, TimeMilli aExpireTime);
1077 
1078         static const char *StateToString(State aState);
1079 
1080         using ExpireTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleOnLinkPrefixManagerTimer>;
1081 
1082         Ip6::Prefix                       mLocalPrefix;
1083         State                             mState;
1084         TimeMilli                         mExpireTime;
1085         Ip6::Prefix                       mFavoredDiscoveredPrefix;
1086         Array<OldPrefix, kMaxOldPrefixes> mOldLocalPrefixes;
1087         ExpireTimer                       mTimer;
1088     };
1089 
1090     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1091 
HandleRioAdvertiserimer(void)1092     void HandleRioAdvertiserimer(void) { mRioAdvertiser.HandleTimer(); }
1093 
1094     class RioAdvertiser : public InstanceLocator
1095     {
1096         // Manages the list of prefixes advertised as RIO in emitted
1097         // RA. The RIO prefixes are discovered from on-mesh prefixes in
1098         // network data including OMR prefix from `OmrPrefixManager`.
1099         // It also handles deprecating removed prefixes.
1100 
1101     public:
1102         explicit RioAdvertiser(Instance &aInstance);
1103 
GetPreference(void) const1104         RoutePreference GetPreference(void) const { return mPreference; }
1105         void            SetPreference(RoutePreference aPreference);
1106         void            ClearPreference(void);
1107         void            HandleRoleChanged(void);
1108         Error           AppendRios(RouterAdvert::TxMessage &aRaMessage);
1109         Error           InvalidatPrevRios(RouterAdvert::TxMessage &aRaMessage);
HasAdvertised(const Ip6::Prefix & aPrefix) const1110         bool            HasAdvertised(const Ip6::Prefix &aPrefix) const { return mPrefixes.ContainsMatching(aPrefix); }
GetAdvertisedRioCount(void) const1111         uint16_t        GetAdvertisedRioCount(void) const { return mPrefixes.GetLength(); }
1112         void            HandleTimer(void);
1113 
1114     private:
1115         static constexpr uint32_t kDeprecationTime = TimeMilli::SecToMsec(300);
1116 
1117         struct RioPrefix : public Clearable<RioPrefix>
1118         {
Matchesot::BorderRouter::RoutingManager::RioAdvertiser::RioPrefix1119             bool Matches(const Ip6::Prefix &aPrefix) const { return (mPrefix == aPrefix); }
1120 
1121             Ip6::Prefix mPrefix;
1122             bool        mIsDeprecating;
1123             TimeMilli   mExpirationTime;
1124         };
1125 
1126         struct RioPrefixArray :
1127 #if OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
1128             public Heap::Array<RioPrefix>
1129 #else
1130             public Array<RioPrefix, 2 * kMaxOnMeshPrefixes>
1131 #endif
1132         {
1133             void Add(const Ip6::Prefix &aPrefix);
1134         };
1135 
1136         void  SetPreferenceBasedOnRole(void);
1137         void  UpdatePreference(RoutePreference aPreference);
1138         Error AppendRio(const Ip6::Prefix &aPrefix, uint32_t aRouteLifetime, RouterAdvert::TxMessage &aRaMessage);
1139 
1140         using RioTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleRioAdvertiserimer>;
1141 
1142         RioPrefixArray  mPrefixes;
1143         RioTimer        mTimer;
1144         RoutePreference mPreference;
1145         bool            mUserSetPreference;
1146     };
1147 
1148     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1149 
1150 #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
1151 
HandleNat64PrefixManagerTimer(void)1152     void HandleNat64PrefixManagerTimer(void) { mNat64PrefixManager.HandleTimer(); }
1153 
1154     class Nat64PrefixManager : public InstanceLocator
1155     {
1156     public:
1157         // This class manages the NAT64 related functions including
1158         // generation of local NAT64 prefix, discovery of infra
1159         // interface prefix, maintaining the discovered prefix
1160         // lifetime, and selection of the NAT64 prefix to publish in
1161         // Network Data.
1162         //
1163         // Calling methods except GenerateLocalPrefix and SetEnabled
1164         // when disabled becomes no-op.
1165 
1166         explicit Nat64PrefixManager(Instance &aInstance);
1167 
1168         void         SetEnabled(bool aEnabled);
1169         Nat64::State GetState(void) const;
1170 
1171         void Start(void);
1172         void Stop(void);
1173 
1174         void               GenerateLocalPrefix(const Ip6::Prefix &aBrUlaPrefix);
GetLocalPrefix(void) const1175         const Ip6::Prefix &GetLocalPrefix(void) const { return mLocalPrefix; }
1176         const Ip6::Prefix &GetFavoredPrefix(RoutePreference &aPreference) const;
1177         void               Evaluate(void);
1178         void               HandleDiscoverDone(const Ip6::Prefix &aPrefix);
1179         void               HandleTimer(void);
1180 
1181     private:
1182         void Discover(void);
1183         void Publish(void);
1184 
1185         using Nat64Timer = TimerMilliIn<RoutingManager, &RoutingManager::HandleNat64PrefixManagerTimer>;
1186 
1187         bool mEnabled;
1188 
1189         Ip6::Prefix     mInfraIfPrefix;       // The latest NAT64 prefix discovered on the infrastructure interface.
1190         Ip6::Prefix     mLocalPrefix;         // The local prefix (from BR ULA prefix).
1191         Ip6::Prefix     mPublishedPrefix;     // The prefix to publish in Net Data (empty or local or from infra-if).
1192         RoutePreference mPublishedPreference; // The published prefix preference.
1193         Nat64Timer      mTimer;
1194     };
1195 
1196 #endif // OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
1197 
1198     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1199 
HandleRoutePublisherTimer(void)1200     void HandleRoutePublisherTimer(void) { mRoutePublisher.HandleTimer(); }
1201 
1202     class RoutePublisher : public InstanceLocator // Manages the routes that are published in net data
1203     {
1204     public:
1205         explicit RoutePublisher(Instance &aInstance);
1206 
Start(void)1207         void Start(void) { Evaluate(); }
Stop(void)1208         void Stop(void) { Unpublish(); }
1209         void Evaluate(void);
1210 
1211         void UpdateAdvPioFlags(bool aAdvPioFlag);
1212 
GetPreference(void) const1213         RoutePreference GetPreference(void) const { return mPreference; }
1214         void            SetPreference(RoutePreference aPreference);
1215         void            ClearPreference(void);
1216 
1217         void HandleNotifierEvents(Events aEvents);
1218         void HandleTimer(void);
1219 
GetUlaPrefix(void)1220         static const Ip6::Prefix &GetUlaPrefix(void) { return AsCoreType(&kUlaPrefix); }
1221 
1222     private:
1223         static constexpr uint32_t kDelayBeforePrfUpdateOnLinkQuality3 = TimeMilli::SecToMsec(5 * 60);
1224 
1225         static const otIp6Prefix kUlaPrefix;
1226 
1227         enum State : uint8_t
1228         {
1229             kDoNotPublish,   // Do not publish any routes in network data.
1230             kPublishDefault, // Publish "::/0" route in network data.
1231             kPublishUla,     // Publish "fc00::/7" route in network data.
1232         };
1233 
1234         void DeterminePrefixFor(State aState, Ip6::Prefix &aPrefix) const;
1235         void UpdatePublishedRoute(State aNewState);
1236         void Unpublish(void);
1237         void SetPreferenceBasedOnRole(void);
1238         void UpdatePreference(RoutePreference aPreference);
1239 
1240         static const char *StateToString(State aState);
1241 
1242         using DelayTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleRoutePublisherTimer>;
1243 
1244         State           mState;
1245         RoutePreference mPreference;
1246         bool            mUserSetPreference;
1247         bool            mAdvPioFlag;
1248         DelayTimer      mTimer;
1249     };
1250 
1251     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1252 
1253     struct TxRaInfo
1254     {
1255         // Tracks info about emitted RA messages:
1256         //
1257         // - Number of RAs sent
1258         // - Last RA TX time
1259         // - Hashes of last TX RAs (to tell if a received RA is from
1260         //   `RoutingManager` itself).
1261 
1262         typedef Crypto::Sha256::Hash Hash;
1263 
1264         static constexpr uint16_t kNumHashEntries = 5;
1265 
TxRaInfoot::BorderRouter::RoutingManager::TxRaInfo1266         TxRaInfo(void)
1267             : mTxCount(0)
1268             , mLastTxTime(TimerMilli::GetNow() - kMinDelayBetweenRas)
1269             , mLastHashIndex(0)
1270         {
1271         }
1272 
1273         void        IncrementTxCountAndSaveHash(const InfraIf::Icmp6Packet &aRaMessage);
1274         bool        IsRaFromManager(const RouterAdvert::RxMessage &aRaMessage) const;
1275         static void CalculateHash(const RouterAdvert::RxMessage &aRaMessage, Hash &aHash);
1276 
1277         uint32_t  mTxCount;
1278         TimeMilli mLastTxTime;
1279         Hash      mHashes[kNumHashEntries];
1280         uint16_t  mLastHashIndex;
1281     };
1282 
1283     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1284 
HandleRsSenderTimer(void)1285     void HandleRsSenderTimer(void) { mRsSender.HandleTimer(); }
1286 
1287     class RsSender : public InstanceLocator
1288     {
1289     public:
1290         // This class implements tx of Router Solicitation (RS)
1291         // messages to discover other routers. `Start()` schedules
1292         // a cycle of RS transmissions of `kMaxTxCount` separated
1293         // by `kTxInterval`. At the end of cycle the callback
1294         // `HandleRsSenderFinished()` is invoked to inform end of
1295         // the cycle to `RoutingManager`.
1296 
1297         explicit RsSender(Instance &aInstance);
1298 
IsInProgress(void) const1299         bool IsInProgress(void) const { return mTimer.IsRunning(); }
1300         void Start(void);
1301         void Stop(void);
1302         void HandleTimer(void);
1303 
1304     private:
1305         // All time intervals are in msec.
1306         static constexpr uint32_t kMaxStartDelay     = 1000;        // Max random delay to send the first RS.
1307         static constexpr uint32_t kTxInterval        = 4000;        // Interval between RS tx.
1308         static constexpr uint32_t kRetryDelay        = kTxInterval; // Interval to wait to retry a failed RS tx.
1309         static constexpr uint32_t kWaitOnLastAttempt = 1000;        // Wait interval after last RS tx.
1310         static constexpr uint8_t  kMaxTxCount        = 3;           // Number of RS tx in one cycle.
1311 
1312         Error SendRs(void);
1313 
1314         using RsTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleRsSenderTimer>;
1315 
1316         uint8_t   mTxCount;
1317         RsTimer   mTimer;
1318         TimeMilli mStartTime;
1319     };
1320 
1321     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1322 
1323 #if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
1324 
HandlePdPrefixManagerTimer(void)1325     void HandlePdPrefixManagerTimer(void) { mPdPrefixManager.HandleTimer(); }
1326 
1327     class PdPrefixManager : public InstanceLocator
1328     {
1329     public:
1330         // This class implements handling (including management of the
1331         // lifetime) of the prefix obtained from platform's DHCPv6 PD
1332         // client.
1333 
1334         typedef Dhcp6PdState State;
1335 
1336         explicit PdPrefixManager(Instance &aInstance);
1337 
1338         void               SetEnabled(bool aEnabled);
Start(void)1339         void               Start(void) { StartStop(/* aStart= */ true); }
Stop(void)1340         void               Stop(void) { StartStop(/* aStart= */ false); }
IsRunning(void) const1341         bool               IsRunning(void) const { return GetState() == kDhcp6PdStateRunning; }
HasPrefix(void) const1342         bool               HasPrefix(void) const { return IsValidOmrPrefix(mPrefix.GetPrefix()); }
GetPrefix(void) const1343         const Ip6::Prefix &GetPrefix(void) const { return mPrefix.GetPrefix(); }
1344         State              GetState(void) const;
1345 
1346         void  ProcessRa(const uint8_t *aRouterAdvert, uint16_t aLength);
1347         void  ProcessPrefix(const PrefixTableEntry &aPrefixTableEntry);
1348         Error GetPrefixInfo(PrefixTableEntry &aInfo) const;
1349         Error GetProcessedRaInfo(PdProcessedRaInfo &aPdProcessedRaInfo) const;
HandleTimer(void)1350         void  HandleTimer(void) { WithdrawPrefix(); }
SetStateCallback(PdCallback aCallback,void * aContext)1351         void  SetStateCallback(PdCallback aCallback, void *aContext) { mStateCallback.Set(aCallback, aContext); }
1352 
1353     private:
1354         class PrefixEntry : public OnLinkPrefix
1355         {
1356         public:
PrefixEntry(void)1357             PrefixEntry(void) { Clear(); }
IsEmpty(void) const1358             bool IsEmpty(void) const { return (GetPrefix().GetLength() == 0); }
1359             bool IsValidPdPrefix(void) const;
1360             bool IsFavoredOver(const PrefixEntry &aOther) const;
1361         };
1362 
1363         void Process(const RouterAdvert::Icmp6Packet *aRaPacket, const PrefixTableEntry *aPrefixTableEntry);
1364         bool ProcessPrefixEntry(PrefixEntry &aEntry, PrefixEntry &aFavoredEntry);
1365         void EvaluateStateChange(State aOldState);
1366         void WithdrawPrefix(void);
1367         void StartStop(bool aStart);
1368 
1369         static const char *StateToString(State aState);
1370 
1371         using PrefixTimer   = TimerMilliIn<RoutingManager, &RoutingManager::HandlePdPrefixManagerTimer>;
1372         using StateCallback = Callback<PdCallback>;
1373 
1374         bool          mEnabled;
1375         bool          mIsRunning;
1376         uint32_t      mNumPlatformPioProcessed;
1377         uint32_t      mNumPlatformRaReceived;
1378         TimeMilli     mLastPlatformRaTime;
1379         StateCallback mStateCallback;
1380         PrefixTimer   mTimer;
1381         PrefixEntry   mPrefix;
1382     };
1383 
1384 #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
1385 
1386     //------------------------------------------------------------------------------------------------------------------
1387     // Methods
1388 
1389     void  EvaluateState(void);
1390     void  Start(void);
1391     void  Stop(void);
1392     void  HandleNotifierEvents(Events aEvents);
IsInitialized(void) const1393     bool  IsInitialized(void) const { return mInfraIf.IsInitialized(); }
IsEnabled(void) const1394     bool  IsEnabled(void) const { return mIsEnabled; }
1395     Error LoadOrGenerateRandomBrUlaPrefix(void);
1396 
1397     void EvaluateRoutingPolicy(void);
1398     bool IsInitalPolicyEvaluationDone(void) const;
1399     void ScheduleRoutingPolicyEvaluation(ScheduleMode aMode);
1400     void HandleRsSenderFinished(TimeMilli aStartTime);
1401     void SendRouterAdvertisement(RouterAdvTxMode aRaTxMode);
1402 
1403     void HandleRouterAdvertisement(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress);
1404     void HandleRouterSolicit(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress);
1405     void HandleNeighborAdvertisement(const InfraIf::Icmp6Packet &aPacket);
1406     bool NetworkDataContainsUlaRoute(void) const;
1407 
1408     void HandleRaPrefixTableChanged(void);
1409     void HandleLocalOnLinkPrefixChanged(void);
1410 
1411     static TimeMilli CalculateExpirationTime(TimeMilli aUpdateTime, uint32_t aLifetime);
1412 
1413     static bool IsValidBrUlaPrefix(const Ip6::Prefix &aBrUlaPrefix);
1414     static bool IsValidOnLinkPrefix(const PrefixInfoOption &aPio);
1415     static bool IsValidOnLinkPrefix(const Ip6::Prefix &aOnLinkPrefix);
1416 
1417     static void LogPrefixInfoOption(const Ip6::Prefix &aPrefix, uint32_t aValidLifetime, uint32_t aPreferredLifetime);
1418     static void LogRouteInfoOption(const Ip6::Prefix &aPrefix, uint32_t aLifetime, RoutePreference aPreference);
1419 
1420     static const char *RouterAdvOriginToString(RouterAdvOrigin aRaOrigin);
1421 
1422     //------------------------------------------------------------------------------------------------------------------
1423     // Variables
1424 
1425     using RoutingPolicyTimer = TimerMilliIn<RoutingManager, &RoutingManager::EvaluateRoutingPolicy>;
1426 
1427     // Indicates whether the Routing Manager is running (started).
1428     bool mIsRunning;
1429 
1430     // Indicates whether the Routing manager is enabled. The Routing
1431     // Manager will be stopped if we are disabled.
1432     bool mIsEnabled;
1433 
1434     InfraIf mInfraIf;
1435 
1436     // The /48 BR ULA prefix loaded from local persistent storage or
1437     // randomly generated if none is found in persistent storage.
1438     Ip6::Prefix mBrUlaPrefix;
1439 
1440     OmrPrefixManager mOmrPrefixManager;
1441 
1442     RioAdvertiser   mRioAdvertiser;
1443     RoutePreference mRioPreference;
1444     bool            mUserSetRioPreference;
1445 
1446     OnLinkPrefixManager mOnLinkPrefixManager;
1447 
1448     RxRaTracker mRxRaTracker;
1449 
1450     RoutePublisher mRoutePublisher;
1451 
1452 #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
1453     Nat64PrefixManager mNat64PrefixManager;
1454 #endif
1455 
1456 #if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
1457     PdPrefixManager mPdPrefixManager;
1458 #endif
1459 
1460     TxRaInfo   mTxRaInfo;
1461     RsSender   mRsSender;
1462     Heap::Data mExtraRaOptions;
1463 
1464     RoutingPolicyTimer mRoutingPolicyTimer;
1465 };
1466 
1467 #if !OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
1468 
1469 //----------------------------------------------------------------------------------------------------------------------
1470 // Template specializations and declarations
1471 
1472 template <>
1473 inline RoutingManager::RxRaTracker::Entry<RoutingManager::OnLinkPrefix>
GetEntry(void)1474     &RoutingManager::RxRaTracker::SharedEntry::GetEntry(void)
1475 {
1476     return mOnLinkEntry;
1477 }
1478 
1479 template <>
1480 inline RoutingManager::RxRaTracker::Entry<RoutingManager::RoutePrefix>
GetEntry(void)1481     &RoutingManager::RxRaTracker::SharedEntry::GetEntry(void)
1482 {
1483     return mRouteEntry;
1484 }
1485 
1486 // Declare template (full) specializations for `Router` type.
1487 
1488 template <>
1489 RoutingManager::RxRaTracker::Entry<RoutingManager::RxRaTracker::Router> *RoutingManager::RxRaTracker::AllocateEntry(
1490     void);
1491 
1492 template <> void RoutingManager::RxRaTracker::Entry<RoutingManager::RxRaTracker::Router>::Free(void);
1493 
1494 #endif // #if !OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
1495 
1496 } // namespace BorderRouter
1497 
1498 DefineMapEnum(otBorderRoutingState, BorderRouter::RoutingManager::State);
1499 
1500 } // namespace ot
1501 
1502 #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
1503 
1504 #endif // ROUTING_MANAGER_HPP_
1505