diff --git a/src/core/border_router/routing_manager.cpp b/src/core/border_router/routing_manager.cpp index b535a8c7c..ed59638d5 100644 --- a/src/core/border_router/routing_manager.cpp +++ b/src/core/border_router/routing_manager.cpp @@ -687,22 +687,6 @@ bool RoutingManager::IsValidOmrPrefix(const Ip6::Prefix &aPrefix) return (aPrefix.GetLength() == kOmrPrefixLength) && !aPrefix.IsLinkLocal() && !aPrefix.IsMulticast(); } -bool RoutingManager::IsValidOnLinkPrefix(const PrefixInfoOption &aPio) -{ - Ip6::Prefix prefix; - - aPio.GetPrefix(prefix); - - return IsValidOnLinkPrefix(prefix) && aPio.IsOnLinkFlagSet() && - (aPio.IsAutoAddrConfigFlagSet() || aPio.IsDhcp6PdPreferredFlagSet()); -} - -bool RoutingManager::IsValidOnLinkPrefix(const Ip6::Prefix &aOnLinkPrefix) -{ - return (aOnLinkPrefix.GetLength() == kOnLinkPrefixLength) && !aOnLinkPrefix.IsLinkLocal() && - !aOnLinkPrefix.IsMulticast(); -} - void RoutingManager::HandleRsSenderFinished(TimeMilli aStartTime) { // This is a callback from `RsSender` and is invoked when it @@ -889,12 +873,15 @@ void RoutingManager::LogRaHeader(const RouterAdvert::Header &aRaHeader) LogInfo("- RA Header - default route - lifetime:%u", aRaHeader.GetRouterLifetime()); } -void RoutingManager::LogPrefixInfoOption(const Ip6::Prefix &aPrefix, - uint32_t aValidLifetime, - uint32_t aPreferredLifetime) +void RoutingManager::LogPrefixInfoOption(const Ip6::Prefix &aPrefix, + uint32_t aValidLifetime, + uint32_t aPreferredLifetime, + PrefixInfoOption::Flags aFlags) { - LogInfo("- PIO %s (valid:%lu, preferred:%lu)", aPrefix.ToString().AsCString(), ToUlong(aValidLifetime), - ToUlong(aPreferredLifetime)); + LogInfo("- PIO %s (valid:%lu, preferred:%lu, flags - L:%u A:%u P:%u)", aPrefix.ToString().AsCString(), + ToUlong(aValidLifetime), ToUlong(aPreferredLifetime), (aFlags & PrefixInfoOption::kOnLinkFlag) ? 1 : 0, + (aFlags & PrefixInfoOption::kAutoConfigFlag) ? 1 : 0, + (aFlags & PrefixInfoOption::kDhcp6PdPreferredFlag) ? 1 : 0); } void RoutingManager::LogRouteInfoOption(const Ip6::Prefix &aPrefix, uint32_t aLifetime, RoutePreference aPreference) @@ -930,7 +917,7 @@ const char *RoutingManager::RouterAdvOriginToString(RouterAdvOrigin aRaOrigin) #else void RoutingManager::LogRaHeader(const RouterAdvert::Header &) {} -void RoutingManager::LogPrefixInfoOption(const Ip6::Prefix &, uint32_t, uint32_t) {} +void RoutingManager::LogPrefixInfoOption(const Ip6::Prefix &, uint32_t, uint32_t, PrefixInfoOption::Flags) {} void RoutingManager::LogRouteInfoOption(const Ip6::Prefix &, uint32_t, RoutePreference) {} void RoutingManager::LogRecursiveDnsServerOption(const Ip6::Address &, uint32_t) {} @@ -953,9 +940,11 @@ TimeMilli RoutingManager::LifetimedPrefix::CalculateExpirationTime(uint32_t aLif void RoutingManager::OnLinkPrefix::SetFrom(const PrefixInfoOption &aPio) { aPio.GetPrefix(mPrefix); - mValidLifetime = aPio.GetValidLifetime(); - mPreferredLifetime = aPio.GetPreferredLifetime(); - mLastUpdateTime = TimerMilli::GetNow(); + mValidLifetime = aPio.GetValidLifetime(); + mPreferredLifetime = aPio.GetPreferredLifetime(); + mAutoAddrConfigFlag = aPio.IsAutoAddrConfigFlagSet(); + mDhcp6PdPreferredFlag = aPio.IsDhcp6PdPreferredFlagSet(); + mLastUpdateTime = TimerMilli::GetNow(); } void RoutingManager::OnLinkPrefix::SetFrom(const PrefixTableEntry &aPrefixTableEntry) @@ -978,7 +967,7 @@ TimeMilli RoutingManager::OnLinkPrefix::GetStaleTime(void) const return CalculateExpirationTime(Min(kStaleTime, mPreferredLifetime)); } -void RoutingManager::OnLinkPrefix::AdoptValidAndPreferredLifetimesFrom(const OnLinkPrefix &aPrefix) +void RoutingManager::OnLinkPrefix::AdoptFlagsAndValidAndPreferredLifetimesFrom(const OnLinkPrefix &aPrefix) { constexpr uint32_t kTwoHoursInSeconds = 2 * 3600; @@ -1002,8 +991,10 @@ void RoutingManager::OnLinkPrefix::AdoptValidAndPreferredLifetimesFrom(const OnL mValidLifetime = kTwoHoursInSeconds; } - mPreferredLifetime = aPrefix.GetPreferredLifetime(); - mLastUpdateTime = aPrefix.GetLastUpdateTime(); + mPreferredLifetime = aPrefix.GetPreferredLifetime(); + mAutoAddrConfigFlag = aPrefix.mAutoAddrConfigFlag; + mDhcp6PdPreferredFlag = aPrefix.mDhcp6PdPreferredFlag; + mLastUpdateTime = aPrefix.GetLastUpdateTime(); } void RoutingManager::OnLinkPrefix::CopyInfoTo(PrefixTableEntry &aEntry, TimeMilli aNow) const @@ -1019,10 +1010,15 @@ bool RoutingManager::OnLinkPrefix::IsFavoredOver(const Ip6::Prefix &aPrefix) con { bool isFavored = false; - // Validate that the `OnLinkPrefix` is eligible to be considered a - // favored on-link prefix. It must not be deprecated and have a - // preferred lifetime exceeding a minimum (1800 seconds). + // Validate that the `OnLinkPrefix` is eligible to be a favored + // on-link prefix. It must have a valid length and either the + // AutoAddrConfig (`A`) or Dhcp6PdPreferred (`P`) flag. + // Additionally, it must not be deprecated and its preferred + // lifetime must be at least `kFavoredMinPreferredLifetime` + // (1800) seconds. + VerifyOrExit(mPrefix.GetLength() == kOnLinkPrefixLength); + VerifyOrExit(mAutoAddrConfigFlag || mDhcp6PdPreferredFlag); VerifyOrExit(!IsDeprecated()); VerifyOrExit(GetPreferredLifetime() >= kFavoredMinPreferredLifetime); @@ -1468,12 +1464,24 @@ void RoutingManager::RxRaTracker::ProcessPrefixInfoOption(const PrefixInfoOption Entry *entry; bool disregard; + // We track all valid PIO prefixes with the on-link (`L`) flag. The + // `OnLinkPrefix` entries store other PIO flags and are used by + // `DecisionFactors` to determine if a ULA or non-ULA on-link + // prefix has been observed. This decision then guides + // `RoutePublisher` on which route to publish. For determining the + // favored on-link prefix, only eligible `OnLinkPrefix` entries are + // considered. These entries must meet specific conditions, such as + // having a valid 64-bit length and either the AutoAddrConfig + // (`A`) and/or Dhcp6PdPreferred (`P`) flag set. The full set of + // conditions is covered in `OnLinkPrefix::IsFavoredOver()`. + VerifyOrExit(aPio.IsValid()); aPio.GetPrefix(prefix); + VerifyOrExit(!prefix.IsLinkLocal() && !prefix.IsMulticast()); - if (!IsValidOnLinkPrefix(aPio)) + if (!aPio.IsOnLinkFlagSet()) { - LogInfo("- PIO %s - ignore since not a valid on-link prefix", prefix.ToString().AsCString()); + aRouter.mOnLinkPrefixes.RemoveMatching(prefix); ExitNow(); } @@ -1487,7 +1495,7 @@ void RoutingManager::RxRaTracker::ProcessPrefixInfoOption(const PrefixInfoOption VerifyOrExit(!disregard); #endif - LogPrefixInfoOption(prefix, aPio.GetValidLifetime(), aPio.GetPreferredLifetime()); + LogPrefixInfoOption(prefix, aPio.GetValidLifetime(), aPio.GetPreferredLifetime(), aPio.GetFlags()); entry = aRouter.mOnLinkPrefixes.FindMatching(prefix); @@ -1511,7 +1519,7 @@ void RoutingManager::RxRaTracker::ProcessPrefixInfoOption(const PrefixInfoOption OnLinkPrefix newPrefix; newPrefix.SetFrom(aPio); - entry->AdoptValidAndPreferredLifetimesFrom(newPrefix); + entry->AdoptFlagsAndValidAndPreferredLifetimesFrom(newPrefix); } entry->SetDisregardFlag(disregard); @@ -3500,10 +3508,11 @@ Error RoutingManager::OnLinkPrefixManager::AppendCurPrefix(RouterAdvert::TxMessa // If in `kDeprecating` state, we include it as PIO with zero // preferred lifetime and the remaining valid lifetime. - Error error = kErrorNone; - uint32_t validLifetime = kDefaultOnLinkPrefixLifetime; - uint32_t preferredLifetime = kDefaultOnLinkPrefixLifetime; - TimeMilli now = TimerMilli::GetNow(); + Error error = kErrorNone; + uint32_t validLifetime = kDefaultOnLinkPrefixLifetime; + uint32_t preferredLifetime = kDefaultOnLinkPrefixLifetime; + TimeMilli now = TimerMilli::GetNow(); + PrefixInfoOption::Flags flags; switch (GetState()) { @@ -3522,9 +3531,11 @@ Error RoutingManager::OnLinkPrefixManager::AppendCurPrefix(RouterAdvert::TxMessa ExitNow(); } - SuccessOrExit(error = aRaMessage.AppendPrefixInfoOption(mLocalPrefix, validLifetime, preferredLifetime)); + flags = PrefixInfoOption::kOnLinkFlag | PrefixInfoOption::kAutoConfigFlag; - LogPrefixInfoOption(mLocalPrefix, validLifetime, preferredLifetime); + SuccessOrExit(error = aRaMessage.AppendPrefixInfoOption(mLocalPrefix, validLifetime, preferredLifetime, flags)); + + LogPrefixInfoOption(mLocalPrefix, validLifetime, preferredLifetime, flags); exit: return error; @@ -3532,9 +3543,10 @@ exit: Error RoutingManager::OnLinkPrefixManager::AppendOldPrefixes(RouterAdvert::TxMessage &aRaMessage) { - Error error = kErrorNone; - TimeMilli now = TimerMilli::GetNow(); - uint32_t validLifetime; + Error error = kErrorNone; + TimeMilli now = TimerMilli::GetNow(); + uint32_t validLifetime; + PrefixInfoOption::Flags flags; for (const OldPrefix &oldPrefix : mOldLocalPrefixes) { @@ -3544,9 +3556,12 @@ Error RoutingManager::OnLinkPrefixManager::AppendOldPrefixes(RouterAdvert::TxMes } validLifetime = TimeMilli::MsecToSec(oldPrefix.mExpireTime - now); - SuccessOrExit(error = aRaMessage.AppendPrefixInfoOption(oldPrefix.mPrefix, validLifetime, 0)); - LogPrefixInfoOption(oldPrefix.mPrefix, validLifetime, 0); + flags = PrefixInfoOption::kOnLinkFlag | PrefixInfoOption::kAutoConfigFlag; + + SuccessOrExit(error = aRaMessage.AppendPrefixInfoOption(oldPrefix.mPrefix, validLifetime, 0, flags)); + + LogPrefixInfoOption(oldPrefix.mPrefix, validLifetime, 0, flags); } exit: diff --git a/src/core/border_router/routing_manager.hpp b/src/core/border_router/routing_manager.hpp index 6900737b9..4501b2a95 100644 --- a/src/core/border_router/routing_manager.hpp +++ b/src/core/border_router/routing_manager.hpp @@ -875,7 +875,7 @@ private: bool IsDeprecated(void) const; TimeMilli GetDeprecationTime(void) const; TimeMilli GetStaleTime(void) const; - void AdoptValidAndPreferredLifetimesFrom(const OnLinkPrefix &aPrefix); + void AdoptFlagsAndValidAndPreferredLifetimesFrom(const OnLinkPrefix &aPrefix); void CopyInfoTo(PrefixTableEntry &aEntry, TimeMilli aNow) const; bool IsFavoredOver(const Ip6::Prefix &aPrefix) const; @@ -883,6 +883,8 @@ private: static constexpr uint32_t kFavoredMinPreferredLifetime = 1800; // In sec. uint32_t mPreferredLifetime; + bool mAutoAddrConfigFlag : 1; + bool mDhcp6PdPreferredFlag : 1; }; //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1870,11 +1872,12 @@ private: static TimeMilli CalculateExpirationTime(TimeMilli aUpdateTime, uint32_t aLifetime); static bool IsValidBrUlaPrefix(const Ip6::Prefix &aBrUlaPrefix); - static bool IsValidOnLinkPrefix(const PrefixInfoOption &aPio); - static bool IsValidOnLinkPrefix(const Ip6::Prefix &aOnLinkPrefix); static void LogRaHeader(const RouterAdvert::Header &aRaHeader); - static void LogPrefixInfoOption(const Ip6::Prefix &aPrefix, uint32_t aValidLifetime, uint32_t aPreferredLifetime); + static void LogPrefixInfoOption(const Ip6::Prefix &aPrefix, + uint32_t aValidLifetime, + uint32_t aPreferredLifetime, + PrefixInfoOption::Flags aFlags); static void LogRouteInfoOption(const Ip6::Prefix &aPrefix, uint32_t aLifetime, RoutePreference aPreference); static void LogRecursiveDnsServerOption(const Ip6::Address &aAddress, uint32_t aLifetime); diff --git a/src/core/net/nd6.cpp b/src/core/net/nd6.cpp index b4e2ec529..420f4bf00 100644 --- a/src/core/net/nd6.cpp +++ b/src/core/net/nd6.cpp @@ -292,9 +292,10 @@ exit: //---------------------------------------------------------------------------------------------------------------------- // RouterAdver::TxMessage -Error RouterAdvert::TxMessage::AppendPrefixInfoOption(const Prefix &aPrefix, - uint32_t aValidLifetime, - uint32_t aPreferredLifetime) +Error RouterAdvert::TxMessage::AppendPrefixInfoOption(const Prefix &aPrefix, + uint32_t aValidLifetime, + uint32_t aPreferredLifetime, + PrefixInfoOption::Flags aFlags) { Error error = kErrorNone; PrefixInfoOption *pio; @@ -303,8 +304,7 @@ Error RouterAdvert::TxMessage::AppendPrefixInfoOption(const Prefix &aPrefix, VerifyOrExit(pio != nullptr, error = kErrorNoBufs); pio->Init(); - pio->SetOnLinkFlag(); - pio->SetAutoAddrConfigFlag(); + pio->SetFlags(aFlags); pio->SetValidLifetime(aValidLifetime); pio->SetPreferredLifetime(aPreferredLifetime); pio->SetPrefix(aPrefix); diff --git a/src/core/net/nd6.hpp b/src/core/net/nd6.hpp index 4aef74166..a67c24a12 100644 --- a/src/core/net/nd6.hpp +++ b/src/core/net/nd6.hpp @@ -178,28 +178,48 @@ class PrefixInfoOption : public Option, private Clearable public: static constexpr Type kType = kTypePrefixInfo; ///< Prefix Information Option Type. + static constexpr uint8_t kOnLinkFlag = 0x80; ///< On-link - L flag. + static constexpr uint8_t kAutoConfigFlag = 0x40; ///< Autonomous address-configuration - A flag. + static constexpr uint8_t kDhcp6PdPreferredFlag = 0x10; ///< DHCPv6-PD preferred - P flag. + + typedef uint8_t Flags; ///< Represents the flags as a bitmap. + /** * Initializes the Prefix Info option with proper type and length and sets all other fields to zero. */ void Init(void); + /** + * Gets the raw flag bitmap. + * + * @return The flags bitmap. + */ + Flags GetFlags(void) const { return mFlags; } + + /** + * Sets the raw flag bitmap. + * + * @param[in] aFlags The flags bitmap. + */ + void SetFlags(Flags aFlags) { mFlags = aFlags; } + /** * Indicates whether or not the on-link flag is set. * * @retval TRUE The on-link flag is set. * @retval FALSE The on-link flag is not set. */ - bool IsOnLinkFlagSet(void) const { return (mFlags & kOnLinkFlagMask) != 0; } + bool IsOnLinkFlagSet(void) const { return (mFlags & kOnLinkFlag) != 0; } /** * Sets the on-link (L) flag. */ - void SetOnLinkFlag(void) { mFlags |= kOnLinkFlagMask; } + void SetOnLinkFlag(void) { mFlags |= kOnLinkFlag; } /** * Clears the on-link (L) flag. */ - void ClearOnLinkFlag(void) { mFlags &= ~kOnLinkFlagMask; } + void ClearOnLinkFlag(void) { mFlags &= ~kOnLinkFlag; } /** * Indicates whether or not the autonomous address-configuration (A) flag is set. @@ -207,17 +227,17 @@ public: * @retval TRUE The auto address-config flag is set. * @retval FALSE The auto address-config flag is not set. */ - bool IsAutoAddrConfigFlagSet(void) const { return (mFlags & kAutoConfigFlagMask) != 0; } + bool IsAutoAddrConfigFlagSet(void) const { return (mFlags & kAutoConfigFlag) != 0; } /** * Sets the autonomous address-configuration (A) flag. */ - void SetAutoAddrConfigFlag(void) { mFlags |= kAutoConfigFlagMask; } + void SetAutoAddrConfigFlag(void) { mFlags |= kAutoConfigFlag; } /** * Clears the autonomous address-configuration (A) flag. */ - void ClearAutoAddrConfigFlag(void) { mFlags &= ~kAutoConfigFlagMask; } + void ClearAutoAddrConfigFlag(void) { mFlags &= ~kAutoConfigFlag; } /** * Indicates whether or not the DhCPv6-PD Preferred (P) flag is set. @@ -225,7 +245,7 @@ public: * @retval TRUE The DHCPv6-PD Preferred (P) flag is set. * @retval FALSE The DHCPv6-PD Preferred (P) flag is not set. */ - bool IsDhcp6PdPreferredFlagSet(void) const { return (mFlags & kDhcp6PdPreferredFlagMask) != 0; } + bool IsDhcp6PdPreferredFlagSet(void) const { return (mFlags & kDhcp6PdPreferredFlag) != 0; } /** * Sets the valid lifetime of the prefix in seconds. @@ -308,10 +328,6 @@ private: // Reference for P Flag (DHCPv6-PD preferred flag): // https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.ietf-6man-pio-pflag.xml - static constexpr uint8_t kOnLinkFlagMask = 0x80; // On-link - L flag. - static constexpr uint8_t kAutoConfigFlagMask = 0x40; // Autonomous address-configuration - A flag. - static constexpr uint8_t kDhcp6PdPreferredFlagMask = 0x10; // DHCPv6-PD preferred - P flag. - uint8_t mPrefixLength; // The prefix length in bits. uint8_t mFlags; // The flags field. uint32_t mValidLifetime; // The valid lifetime of the prefix. @@ -898,17 +914,18 @@ public: /** * Appends a Prefix Info Option to the RA message. * - * The appended Prefix Info Option will have both on-link (L) and autonomous address-configuration (A) flags - * set. - * * @param[in] aPrefix The prefix. * @param[in] aValidLifetime The valid lifetime in seconds. * @param[in] aPreferredLifetime The preferred lifetime in seconds. + * @param[in] aFlags The PIO flags to use. * * @retval kErrorNone Option is appended successfully. * @retval kErrorNoBufs Insufficient available buffers to grow the message. */ - Error AppendPrefixInfoOption(const Prefix &aPrefix, uint32_t aValidLifetime, uint32_t aPreferredLifetime); + Error AppendPrefixInfoOption(const Prefix &aPrefix, + uint32_t aValidLifetime, + uint32_t aPreferredLifetime, + PrefixInfoOption::Flags aFlags); /** * Appends a Route Info Option to the RA message. diff --git a/tests/unit/test_routing_manager.cpp b/tests/unit/test_routing_manager.cpp index 4d969e563..78d9e508e 100644 --- a/tests/unit/test_routing_manager.cpp +++ b/tests/unit/test_routing_manager.cpp @@ -816,16 +816,27 @@ void VerifyNat64PrefixInNetData(const Ip6::Prefix &aNat64Prefix) struct Pio { - Pio(const Ip6::Prefix &aPrefix, uint32_t aValidLifetime, uint32_t aPreferredLifetime) + using Flags = Ip6::Nd::PrefixInfoOption::Flags; + + static constexpr Flags kOnLinkFlag = Ip6::Nd::PrefixInfoOption::kOnLinkFlag; + static constexpr Flags kAutoConfigFlag = Ip6::Nd::PrefixInfoOption::kAutoConfigFlag; + static constexpr Flags kDhcp6Flag = Ip6::Nd::PrefixInfoOption::kDhcp6PdPreferredFlag; + + Pio(const Ip6::Prefix &aPrefix, + uint32_t aValidLifetime, + uint32_t aPreferredLifetime, + Flags aFlags = kOnLinkFlag | kAutoConfigFlag) : mPrefix(aPrefix) , mValidLifetime(aValidLifetime) , mPreferredLifetime(aPreferredLifetime) + , mFlags(aFlags) { } const Ip6::Prefix &mPrefix; uint32_t mValidLifetime; uint32_t mPreferredLifetime; + Flags mFlags; }; struct Rio @@ -921,7 +932,8 @@ void BuildRouterAdvert(Ip6::Nd::RouterAdvert::TxMessage &aRaMsg, for (; aNumPios > 0; aPios++, aNumPios--) { - SuccessOrQuit(aRaMsg.AppendPrefixInfoOption(aPios->mPrefix, aPios->mValidLifetime, aPios->mPreferredLifetime)); + SuccessOrQuit(aRaMsg.AppendPrefixInfoOption(aPios->mPrefix, aPios->mValidLifetime, aPios->mPreferredLifetime, + aPios->mFlags)); } for (; aNumRios > 0; aRios++, aNumRios--) @@ -2050,6 +2062,115 @@ void TestDefaultRoute(void) FinalizeTest(); } +void TestNonUlaPioWithOnlyOnLinkFlag(void) +{ + static constexpr uint32_t kMaxRaTxInterval = 196; // In seconds + + Ip6::Prefix localOnLink; + Ip6::Prefix localOmr; + Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64); + Ip6::Address routerAddressA = AddressFromString("fd00::aaaa"); + uint16_t heapAllocations; + + Log("--------------------------------------------------------------------------------------------"); + Log("TestNonUlaPioWithOnlyOnLinkFlag"); + + InitTest(); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Start Routing Manager. Check emitted RS and RA messages. + + sRsEmitted = false; + sRaValidated = false; + sExpectedPio = kPioAdvertisingLocalOnLink; + sExpectedRios.Clear(); + + heapAllocations = sHeapAllocatedPtrs.GetLength(); + SuccessOrQuit(sInstance->Get().SetEnabled(true)); + + SuccessOrQuit(sInstance->Get().GetOnLinkPrefix(localOnLink)); + SuccessOrQuit(sInstance->Get().GetOmrPrefix(localOmr)); + + Log("Local on-link prefix is %s", localOnLink.ToString().AsCString()); + Log("Local OMR prefix is %s", localOmr.ToString().AsCString()); + + sExpectedRios.Add(localOmr); + + AdvanceTime(30000); + + VerifyOrQuit(sRsEmitted); + VerifyOrQuit(sRaValidated); + VerifyOrQuit(sExpectedRios.SawAll()); + Log("Received RA was validated"); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check the Network Data to include the local OMR and on-link prefix. + + VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false); + VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Send an RA from router A with a new on-link (PIO) with + // only on-link (L) flag (no A or P). + + SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime, Pio::kOnLinkFlag)}); + + sRaValidated = false; + + AdvanceTime(10000); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check the discovered prefix table and ensure info from router A + // is present in the table. + + VerifyPrefixTable({OnLinkPrefix(onLinkPrefix, kValidLitime, kPreferredLifetime, routerAddressA)}); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check the Network Data. Now that we have observed a non-ULA + // on-link prefix (even with only on-link `L` flag), a default + // route should be published. + + VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ true); + VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check that BR is still advertising its local on-link prefix. + + AdvanceTime(kMaxRaTxInterval * 1000); + + VerifyOrQuit(sRaValidated); + VerifyOrQuit(sExpectedRios.SawAll()); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Disallow responding to NS messages. This should cause + // the router A to be deemed unreachable and its prefix + // entries aged out and then removed. + + sRespondToNs = false; + + AdvanceTime(kValidLitime * 1000 + 1000); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check that the discovered prefix table is now empty. + + VerifyPrefixTableIsEmpty(); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Validate that the BR is no longer publishing a default route. + + VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false); + VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + SuccessOrQuit(sInstance->Get().SetEnabled(false)); + VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength()); + + Log("End of TestNonUlaPioWithOnlyOnLinkFlag"); + + FinalizeTest(); +} + void TestAdvNonUlaRoute(void) { Ip6::Prefix localOnLink; @@ -5001,6 +5122,7 @@ int main(void) ot::TestOmrSelection(); ot::TestOmrConfig(); ot::TestDefaultRoute(); + ot::TestNonUlaPioWithOnlyOnLinkFlag(); ot::TestAdvNonUlaRoute(); ot::TestFavoredOnLinkPrefix(); ot::TestLocalOnLinkPrefixDeprecation();