[routing-manager] construct RA dynamically using Heap::Array (#9924)

This commit enhances flexibility in Router Advertisement (RA) message
construction by employing `Heap::Array`. This eliminates the need for
a pre-allocated buffer and removes the constraint of predetermining
the maximum RA message size.

Additionally, introduces `TxMessage` and `RxMessage` nested classes
within `Ip6::Nd::RouterAdvert` for efficient handling of outgoing and
incoming RA messages:
- `TxMessage`: Facilitates appending elements to an RA message with
  dynamic buffer allocation.
- `RxMessage`: Enables parsing and iterating over options within a
  received RA message.
This commit is contained in:
Abtin Keshavarzian
2024-03-13 11:15:49 -07:00
committed by GitHub
parent c4d7859d07
commit cf6dcc5bc7
5 changed files with 335 additions and 283 deletions
+94 -85
View File
@@ -571,35 +571,24 @@ exit:
void RoutingManager::SendRouterAdvertisement(RouterAdvTxMode aRaTxMode)
{
// RA message max length is derived to accommodate:
//
// - The RA header.
// - One RA Flags Extensions Option (with stub router flag).
// - One PIO for current local on-link prefix.
// - At most `kMaxOldPrefixes` for old deprecating on-link prefixes.
// - At most 3 times `kMaxOnMeshPrefixes` RIO for on-mesh prefixes.
// Factor three is used for RIOs to account for any new prefix
// with older prefixes entries being deprecated and prefixes
// being invalidated.
static constexpr uint16_t kMaxRaLength =
sizeof(Ip6::Nd::RouterAdvertMessage::Header) + sizeof(Ip6::Nd::RaFlagsExtOption) +
sizeof(Ip6::Nd::PrefixInfoOption) + sizeof(Ip6::Nd::PrefixInfoOption) * OnLinkPrefixManager::kMaxOldPrefixes +
3 * kMaxOnMeshPrefixes * (sizeof(Ip6::Nd::RouteInfoOption) + sizeof(Ip6::Prefix));
uint8_t buffer[kMaxRaLength];
Ip6::Nd::RouterAdvertMessage raMsg(mRaInfo.mHeader, buffer);
Error error = kErrorNone;
Ip6::Nd::RouterAdvert::TxMessage raMsg;
Ip6::Nd::RouterAdvert::Header header;
Ip6::Address destAddress;
InfraIf::Icmp6Packet packet;
LogInfo("Preparing RA");
mDiscoveredPrefixTable.DetermineAndSetFlags(raMsg);
header = mRaInfo.mHeader;
mDiscoveredPrefixTable.DetermineAndSetFlags(header);
LogInfo("- RA Header - flags - M:%u O:%u", raMsg.GetHeader().IsManagedAddressConfigFlagSet(),
raMsg.GetHeader().IsOtherConfigFlagSet());
LogInfo("- RA Header - default route - lifetime:%u", raMsg.GetHeader().GetRouterLifetime());
SuccessOrExit(error = raMsg.AppendHeader(header));
LogInfo("- RA Header - flags - M:%u O:%u", header.IsManagedAddressConfigFlagSet(), header.IsOtherConfigFlagSet());
LogInfo("- RA Header - default route - lifetime:%u", header.GetRouterLifetime());
#if OPENTHREAD_CONFIG_BORDER_ROUTING_STUB_ROUTER_FLAG_IN_EMITTED_RA_ENABLE
SuccessOrAssert(raMsg.AppendFlagsExtensionOption(/* aStubRouterFlag */ true));
SuccessOrExit(error = raMsg.AppendFlagsExtensionOption(/* aStubRouterFlag */ true));
LogInfo("- FlagsExt - StubRouter:1");
#endif
@@ -607,45 +596,40 @@ void RoutingManager::SendRouterAdvertisement(RouterAdvTxMode aRaTxMode)
// advertised or deprecated and for old prefix if is being
// deprecated.
mOnLinkPrefixManager.AppendAsPiosTo(raMsg);
SuccessOrExit(error = mOnLinkPrefixManager.AppendAsPiosTo(raMsg));
if (aRaTxMode == kInvalidateAllPrevPrefixes)
{
mRioAdvertiser.InvalidatPrevRios(raMsg);
SuccessOrExit(error = mRioAdvertiser.InvalidatPrevRios(raMsg));
}
else
{
mRioAdvertiser.AppendRios(raMsg);
SuccessOrExit(error = mRioAdvertiser.AppendRios(raMsg));
}
if (raMsg.ContainsAnyOptions())
VerifyOrExit(raMsg.ContainsAnyOptions());
++mRaInfo.mTxCount;
destAddress.SetToLinkLocalAllNodesMulticast();
raMsg.GetAsPacket(packet);
SuccessOrExit(error = mInfraIf.Send(packet, destAddress));
mRaInfo.mLastTxTime = TimerMilli::GetNow();
Get<Ip6::Ip6>().GetBorderRoutingCounters().mRaTxSuccess++;
LogInfo("Sent RA on %s", mInfraIf.ToString().AsCString());
DumpDebg("[BR-CERT] direction=send | type=RA |", packet.GetBytes(), packet.GetLength());
exit:
if (error != kErrorNone)
{
Error error;
Ip6::Address destAddress;
++mRaInfo.mTxCount;
destAddress.SetToLinkLocalAllNodesMulticast();
error = mInfraIf.Send(raMsg.GetAsPacket(), destAddress);
if (error == kErrorNone)
{
mRaInfo.mLastTxTime = TimerMilli::GetNow();
Get<Ip6::Ip6>().GetBorderRoutingCounters().mRaTxSuccess++;
LogInfo("Sent RA on %s", mInfraIf.ToString().AsCString());
DumpDebg("[BR-CERT] direction=send | type=RA |", raMsg.GetAsPacket().GetBytes(),
raMsg.GetAsPacket().GetLength());
}
else
{
Get<Ip6::Ip6>().GetBorderRoutingCounters().mRaTxFailure++;
LogWarn("Failed to send RA on %s: %s", mInfraIf.ToString().AsCString(), ErrorToString(error));
}
Get<Ip6::Ip6>().GetBorderRoutingCounters().mRaTxFailure++;
LogWarn("Failed to send RA on %s: %s", mInfraIf.ToString().AsCString(), ErrorToString(error));
}
}
bool RoutingManager::IsReceivedRouterAdvertFromManager(const Ip6::Nd::RouterAdvertMessage &aRaMessage) const
bool RoutingManager::IsReceivedRouterAdvertFromManager(const Ip6::Nd::RouterAdvert::RxMessage &aRaMessage) const
{
// Determines whether or not a received RA message was prepared by
// by `RoutingManager` itself.
@@ -797,7 +781,7 @@ exit:
void RoutingManager::HandleRouterAdvertisement(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress)
{
Ip6::Nd::RouterAdvertMessage routerAdvMessage(aPacket);
Ip6::Nd::RouterAdvert::RxMessage routerAdvMessage(aPacket);
OT_ASSERT(mIsRunning);
@@ -946,11 +930,11 @@ bool RoutingManager::NetworkDataContainsUlaRoute(void) const
return contains;
}
void RoutingManager::UpdateRouterAdvertHeader(const Ip6::Nd::RouterAdvertMessage *aRouterAdvertMessage)
void RoutingManager::UpdateRouterAdvertHeader(const Ip6::Nd::RouterAdvert::RxMessage *aRouterAdvertMessage)
{
// Updates the `mRaInfo` from the given RA message.
Ip6::Nd::RouterAdvertMessage::Header oldHeader;
Ip6::Nd::RouterAdvert::Header oldHeader;
if (aRouterAdvertMessage != nullptr)
{
@@ -1060,8 +1044,9 @@ RoutingManager::DiscoveredPrefixTable::DiscoveredPrefixTable(Instance &aInstance
{
}
void RoutingManager::DiscoveredPrefixTable::ProcessRouterAdvertMessage(const Ip6::Nd::RouterAdvertMessage &aRaMessage,
const Ip6::Address &aSrcAddress)
void RoutingManager::DiscoveredPrefixTable::ProcessRouterAdvertMessage(
const Ip6::Nd::RouterAdvert::RxMessage &aRaMessage,
const Ip6::Address &aSrcAddress)
{
// Process a received RA message and update the prefix table.
@@ -1120,8 +1105,8 @@ exit:
return;
}
void RoutingManager::DiscoveredPrefixTable::ProcessRaHeader(const Ip6::Nd::RouterAdvertMessage::Header &aRaHeader,
Router &aRouter)
void RoutingManager::DiscoveredPrefixTable::ProcessRaHeader(const Ip6::Nd::RouterAdvert::Header &aRaHeader,
Router &aRouter)
{
Entry *entry;
Ip6::Prefix prefix;
@@ -1660,10 +1645,10 @@ exit:
return;
}
void RoutingManager::DiscoveredPrefixTable::DetermineAndSetFlags(Ip6::Nd::RouterAdvertMessage &aRaMessage) const
void RoutingManager::DiscoveredPrefixTable::DetermineAndSetFlags(Ip6::Nd::RouterAdvert::Header &aHeader) const
{
// Determine the `M` and `O` flags to include in the RA message
// header `aRaMessage` to be emitted.
// header to be emitted.
//
// If any discovered router on infrastructure which is not itself a
// stub router (e.g., another Thread BR) includes the `M` or `O`
@@ -1686,12 +1671,12 @@ void RoutingManager::DiscoveredPrefixTable::DetermineAndSetFlags(Ip6::Nd::Router
if (router.mManagedAddressConfigFlag)
{
aRaMessage.GetHeader().SetManagedAddressConfigFlag();
aHeader.SetManagedAddressConfigFlag();
}
if (router.mOtherConfigFlag)
{
aRaMessage.GetHeader().SetOtherConfigFlag();
aHeader.SetOtherConfigFlag();
}
}
}
@@ -1778,7 +1763,7 @@ void RoutingManager::DiscoveredPrefixTable::Iterator::Advance(AdvanceMode aMode)
//---------------------------------------------------------------------------------------------------------------------
// DiscoveredPrefixTable::Entry
void RoutingManager::DiscoveredPrefixTable::Entry::SetFrom(const Ip6::Nd::RouterAdvertMessage::Header &aRaHeader)
void RoutingManager::DiscoveredPrefixTable::Entry::SetFrom(const Ip6::Nd::RouterAdvert::Header &aRaHeader)
{
mPrefix.Clear();
mType = kTypeRoute;
@@ -2528,13 +2513,18 @@ bool RoutingManager::OnLinkPrefixManager::IsPublishingOrAdvertising(void) const
return (GetState() == kPublishing) || (GetState() == kAdvertising);
}
void RoutingManager::OnLinkPrefixManager::AppendAsPiosTo(Ip6::Nd::RouterAdvertMessage &aRaMessage)
Error RoutingManager::OnLinkPrefixManager::AppendAsPiosTo(Ip6::Nd::RouterAdvert::TxMessage &aRaMessage)
{
AppendCurPrefix(aRaMessage);
AppendOldPrefixes(aRaMessage);
Error error;
SuccessOrExit(error = AppendCurPrefix(aRaMessage));
error = AppendOldPrefixes(aRaMessage);
exit:
return error;
}
void RoutingManager::OnLinkPrefixManager::AppendCurPrefix(Ip6::Nd::RouterAdvertMessage &aRaMessage)
Error RoutingManager::OnLinkPrefixManager::AppendCurPrefix(Ip6::Nd::RouterAdvert::TxMessage &aRaMessage)
{
// Append the local on-link prefix to the `aRaMessage` as a PIO
// only if it is being advertised or deprecated.
@@ -2543,6 +2533,7 @@ void RoutingManager::OnLinkPrefixManager::AppendCurPrefix(Ip6::Nd::RouterAdvertM
// 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();
@@ -2564,17 +2555,18 @@ void RoutingManager::OnLinkPrefixManager::AppendCurPrefix(Ip6::Nd::RouterAdvertM
ExitNow();
}
SuccessOrAssert(aRaMessage.AppendPrefixInfoOption(mLocalPrefix, validLifetime, preferredLifetime));
SuccessOrExit(error = aRaMessage.AppendPrefixInfoOption(mLocalPrefix, validLifetime, preferredLifetime));
LogPrefixInfoOption(mLocalPrefix, validLifetime, preferredLifetime);
exit:
return;
return error;
}
void RoutingManager::OnLinkPrefixManager::AppendOldPrefixes(Ip6::Nd::RouterAdvertMessage &aRaMessage)
Error RoutingManager::OnLinkPrefixManager::AppendOldPrefixes(Ip6::Nd::RouterAdvert::TxMessage &aRaMessage)
{
TimeMilli now = TimerMilli::GetNow();
Error error = kErrorNone;
TimeMilli now = TimerMilli::GetNow();
uint32_t validLifetime;
for (const OldPrefix &oldPrefix : mOldLocalPrefixes)
@@ -2585,10 +2577,13 @@ void RoutingManager::OnLinkPrefixManager::AppendOldPrefixes(Ip6::Nd::RouterAdver
}
validLifetime = TimeMilli::MsecToSec(oldPrefix.mExpireTime - now);
SuccessOrAssert(aRaMessage.AppendPrefixInfoOption(oldPrefix.mPrefix, validLifetime, 0));
SuccessOrExit(error = aRaMessage.AppendPrefixInfoOption(oldPrefix.mPrefix, validLifetime, 0));
LogPrefixInfoOption(oldPrefix.mPrefix, validLifetime, 0);
}
exit:
return error;
}
void RoutingManager::OnLinkPrefixManager::HandleNetDataChange(void)
@@ -2824,11 +2819,13 @@ exit:
return;
}
void RoutingManager::RioAdvertiser::InvalidatPrevRios(Ip6::Nd::RouterAdvertMessage &aRaMessage)
Error RoutingManager::RioAdvertiser::InvalidatPrevRios(Ip6::Nd::RouterAdvert::TxMessage &aRaMessage)
{
Error error = kErrorNone;
for (const RioPrefix &prefix : mPrefixes)
{
AppendRio(prefix.mPrefix, /* aRouteLifetime */ 0, aRaMessage);
SuccessOrExit(error = AppendRio(prefix.mPrefix, /* aRouteLifetime */ 0, aRaMessage));
}
#if OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
@@ -2837,10 +2834,14 @@ void RoutingManager::RioAdvertiser::InvalidatPrevRios(Ip6::Nd::RouterAdvertMessa
mPrefixes.Clear();
mTimer.Stop();
exit:
return error;
}
void RoutingManager::RioAdvertiser::AppendRios(Ip6::Nd::RouterAdvertMessage &aRaMessage)
Error RoutingManager::RioAdvertiser::AppendRios(Ip6::Nd::RouterAdvert::TxMessage &aRaMessage)
{
Error error = kErrorNone;
TimeMilli now = TimerMilli::GetNow();
TimeMilli nextTime = now.GetDistantFuture();
RioPrefixArray oldPrefixes;
@@ -2928,7 +2929,7 @@ void RoutingManager::RioAdvertiser::AppendRios(Ip6::Nd::RouterAdvertMessage &aRa
{
if (now >= prefix.mExpirationTime)
{
AppendRio(prefix.mPrefix, /* aRouteLifetime */ 0, aRaMessage);
SuccessOrExit(error = AppendRio(prefix.mPrefix, /* aRouteLifetime */ 0, aRaMessage));
continue;
}
}
@@ -2941,7 +2942,7 @@ void RoutingManager::RioAdvertiser::AppendRios(Ip6::Nd::RouterAdvertMessage &aRa
if (mPrefixes.PushBack(prefix) != kErrorNone)
{
LogWarn("Too many deprecating on-mesh prefixes, removing %s", prefix.mPrefix.ToString().AsCString());
AppendRio(prefix.mPrefix, /* aRouteLifetime */ 0, aRaMessage);
SuccessOrExit(error = AppendRio(prefix.mPrefix, /* aRouteLifetime */ 0, aRaMessage));
}
nextTime = Min(nextTime, prefix.mExpirationTime);
@@ -2958,21 +2959,29 @@ void RoutingManager::RioAdvertiser::AppendRios(Ip6::Nd::RouterAdvertMessage &aRa
lifetime = TimeMilli::MsecToSec(prefix.mExpirationTime - now);
}
AppendRio(prefix.mPrefix, lifetime, aRaMessage);
SuccessOrExit(error = AppendRio(prefix.mPrefix, lifetime, aRaMessage));
}
if (nextTime != now.GetDistantFuture())
{
mTimer.FireAtIfEarlier(nextTime);
}
exit:
return error;
}
void RoutingManager::RioAdvertiser::AppendRio(const Ip6::Prefix &aPrefix,
uint32_t aRouteLifetime,
Ip6::Nd::RouterAdvertMessage &aRaMessage)
Error RoutingManager::RioAdvertiser::AppendRio(const Ip6::Prefix &aPrefix,
uint32_t aRouteLifetime,
Ip6::Nd::RouterAdvert::TxMessage &aRaMessage)
{
SuccessOrAssert(aRaMessage.AppendRouteInfoOption(aPrefix, aRouteLifetime, mPreference));
Error error;
SuccessOrExit(error = aRaMessage.AppendRouteInfoOption(aPrefix, aRouteLifetime, mPreference));
LogRouteInfoOption(aPrefix, aRouteLifetime, mPreference);
exit:
return error;
}
void RoutingManager::RioAdvertiser::HandleTimer(void)
@@ -3655,12 +3664,12 @@ exit:
void RoutingManager::PdPrefixManager::ProcessPlatformGeneratedRa(const uint8_t *aRouterAdvert, const uint16_t aLength)
{
Error error = kErrorNone;
Ip6::Nd::RouterAdvertMessage::Icmp6Packet packet;
Error error = kErrorNone;
Ip6::Nd::RouterAdvert::Icmp6Packet packet;
VerifyOrExit(IsRunning(), LogWarn("Ignore platform generated RA since PD is disabled or not running."));
packet.Init(aRouterAdvert, aLength);
error = Process(Ip6::Nd::RouterAdvertMessage(packet));
error = Process(Ip6::Nd::RouterAdvert::RxMessage(packet));
mNumPlatformRaReceived++;
mLastPlatformRaTime = TimerMilli::GetNow();
@@ -3671,7 +3680,7 @@ exit:
}
}
Error RoutingManager::PdPrefixManager::Process(const Ip6::Nd::RouterAdvertMessage &aMessage)
Error RoutingManager::PdPrefixManager::Process(const Ip6::Nd::RouterAdvert::RxMessage &aMessage)
{
Error error = kErrorNone;
DiscoveredPrefixTable::Entry favoredEntry;
+23 -21
View File
@@ -630,8 +630,8 @@ private:
public:
explicit DiscoveredPrefixTable(Instance &aInstance);
void ProcessRouterAdvertMessage(const Ip6::Nd::RouterAdvertMessage &aRaMessage,
const Ip6::Address &aSrcAddress);
void ProcessRouterAdvertMessage(const Ip6::Nd::RouterAdvert::RxMessage &aRaMessage,
const Ip6::Address &aSrcAddress);
void ProcessNeighborAdvertMessage(const Ip6::Nd::NeighborAdvertMessage &aNaMessage);
bool ContainsDefaultOrNonUlaRoutePrefix(void) const;
@@ -648,7 +648,7 @@ private:
TimeMilli CalculateNextStaleTime(TimeMilli aNow) const;
void DetermineAndSetFlags(Ip6::Nd::RouterAdvertMessage &aRaMessage) const;
void DetermineAndSetFlags(Ip6::Nd::RouterAdvert::Header &aHeader) const;
void InitIterator(PrefixTableIterator &aIterator) const;
Error GetNextEntry(PrefixTableIterator &aIterator, PrefixTableEntry &aEntry) const;
@@ -724,7 +724,7 @@ private:
TimeMilli mNow;
};
void SetFrom(const Ip6::Nd::RouterAdvertMessage::Header &aRaHeader);
void SetFrom(const Ip6::Nd::RouterAdvert::Header &aRaHeader);
void SetFrom(const Ip6::Nd::PrefixInfoOption &aPio);
void SetFrom(const Ip6::Nd::RouteInfoOption &aRio);
Type GetType(void) const { return mType; }
@@ -824,7 +824,7 @@ private:
void SetInitTime(void) { mData32 = TimerMilli::GetNow().GetValue(); }
};
void ProcessRaHeader(const Ip6::Nd::RouterAdvertMessage::Header &aRaHeader, Router &aRouter);
void ProcessRaHeader(const Ip6::Nd::RouterAdvert::Header &aRaHeader, Router &aRouter);
void ProcessPrefixInfoOption(const Ip6::Nd::PrefixInfoOption &aPio, Router &aRouter);
void ProcessRouteInfoOption(const Ip6::Nd::RouteInfoOption &aRio, Router &aRouter);
void ProcessRaFlagsExtOption(const Ip6::Nd::RaFlagsExtOption &aFlagsOption, Router &aRouter);
@@ -951,7 +951,7 @@ private:
bool IsInitalEvaluationDone(void) const;
void HandleDiscoveredPrefixTableChanged(void);
bool ShouldPublishUlaRoute(void) const;
void AppendAsPiosTo(Ip6::Nd::RouterAdvertMessage &aRaMessage);
Error AppendAsPiosTo(Ip6::Nd::RouterAdvert::TxMessage &aRaMessage);
bool IsPublishingOrAdvertising(void) const;
void HandleNetDataChange(void);
void HandleExtPanIdChange(void);
@@ -980,8 +980,8 @@ private:
void PublishAndAdvertise(void);
void Deprecate(void);
void ResetExpireTime(TimeMilli aNow);
void AppendCurPrefix(Ip6::Nd::RouterAdvertMessage &aRaMessage);
void AppendOldPrefixes(Ip6::Nd::RouterAdvertMessage &aRaMessage);
Error AppendCurPrefix(Ip6::Nd::RouterAdvert::TxMessage &aRaMessage);
Error AppendOldPrefixes(Ip6::Nd::RouterAdvert::TxMessage &aRaMessage);
void DeprecateOldPrefix(const Ip6::Prefix &aPrefix, TimeMilli aExpireTime);
void SavePrefix(const Ip6::Prefix &aPrefix, TimeMilli aExpireTime);
@@ -1013,8 +1013,8 @@ private:
void SetPreference(RoutePreference aPreference);
void ClearPreference(void);
void HandleRoleChanged(void);
void AppendRios(Ip6::Nd::RouterAdvertMessage &aRaMessage);
void InvalidatPrevRios(Ip6::Nd::RouterAdvertMessage &aRaMessage);
Error AppendRios(Ip6::Nd::RouterAdvert::TxMessage &aRaMessage);
Error InvalidatPrevRios(Ip6::Nd::RouterAdvert::TxMessage &aRaMessage);
bool HasAdvertised(const Ip6::Prefix &aPrefix) const { return mPrefixes.ContainsMatching(aPrefix); }
uint16_t GetAdvertisedRioCount(void) const { return mPrefixes.GetLength(); }
void HandleTimer(void);
@@ -1041,9 +1041,11 @@ private:
void Add(const Ip6::Prefix &aPrefix);
};
void SetPreferenceBasedOnRole(void);
void UpdatePreference(RoutePreference aPreference);
void AppendRio(const Ip6::Prefix &aPrefix, uint32_t aRouteLifetime, Ip6::Nd::RouterAdvertMessage &aRaMessage);
void SetPreferenceBasedOnRole(void);
void UpdatePreference(RoutePreference aPreference);
Error AppendRio(const Ip6::Prefix &aPrefix,
uint32_t aRouteLifetime,
Ip6::Nd::RouterAdvert::TxMessage &aRaMessage);
using RioTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleRioAdvertiserimer>;
@@ -1167,11 +1169,11 @@ private:
{
}
Ip6::Nd::RouterAdvertMessage::Header mHeader;
TimeMilli mHeaderUpdateTime;
bool mIsHeaderFromHost;
uint32_t mTxCount;
TimeMilli mLastTxTime;
Ip6::Nd::RouterAdvert::Header mHeader;
TimeMilli mHeaderUpdateTime;
bool mIsHeaderFromHost;
uint32_t mTxCount;
TimeMilli mLastTxTime;
};
void HandleRsSenderTimer(void) { mRsSender.HandleTimer(); }
@@ -1246,7 +1248,7 @@ private:
}
private:
Error Process(const Ip6::Nd::RouterAdvertMessage &aMessage);
Error Process(const Ip6::Nd::RouterAdvert::RxMessage &aMessage);
void EvaluateStateChange(Dhcp6PdState aOldState);
void WithdrawPrefix(void);
void StartStop(bool aStart);
@@ -1287,8 +1289,8 @@ private:
void UpdateDiscoveredPrefixTableOnNetDataChange(void);
bool NetworkDataContainsOmrPrefix(const Ip6::Prefix &aPrefix) const;
bool NetworkDataContainsUlaRoute(void) const;
void UpdateRouterAdvertHeader(const Ip6::Nd::RouterAdvertMessage *aRouterAdvertMessage);
bool IsReceivedRouterAdvertFromManager(const Ip6::Nd::RouterAdvertMessage &aRaMessage) const;
void UpdateRouterAdvertHeader(const Ip6::Nd::RouterAdvert::RxMessage *aRouterAdvertMessage);
bool IsReceivedRouterAdvertFromManager(const Ip6::Nd::RouterAdvert::RxMessage &aRaMessage) const;
void ResetDiscoveredPrefixStaleTimer(void);
static bool IsValidBrUlaPrefix(const Ip6::Prefix &aBrUlaPrefix);
+38 -19
View File
@@ -36,6 +36,7 @@
#include "common/as_core_type.hpp"
#include "common/code_utils.hpp"
#include "instance/instance.hpp"
namespace ot {
namespace Ip6 {
@@ -181,9 +182,9 @@ void RaFlagsExtOption::Init(void)
}
//----------------------------------------------------------------------------------------------------------------------
// RouterAdverMessage::Header
// RouterAdver::Header
void RouterAdvertMessage::Header::SetToDefault(void)
void RouterAdvert::Header::SetToDefault(void)
{
OT_UNUSED_VARIABLE(mCode);
OT_UNUSED_VARIABLE(mCurHopLimit);
@@ -194,21 +195,21 @@ void RouterAdvertMessage::Header::SetToDefault(void)
mType = Icmp::Header::kTypeRouterAdvert;
}
RoutePreference RouterAdvertMessage::Header::GetDefaultRouterPreference(void) const
RoutePreference RouterAdvert::Header::GetDefaultRouterPreference(void) const
{
return NetworkData::RoutePreferenceFromValue((mFlags & kPreferenceMask) >> kPreferenceOffset);
}
void RouterAdvertMessage::Header::SetDefaultRouterPreference(RoutePreference aPreference)
void RouterAdvert::Header::SetDefaultRouterPreference(RoutePreference aPreference)
{
mFlags &= ~kPreferenceMask;
mFlags |= (NetworkData::RoutePreferenceToValue(aPreference) << kPreferenceOffset) & kPreferenceMask;
}
//----------------------------------------------------------------------------------------------------------------------
// RouterAdverMessage
// RouterAdver::TxMessage
Option *RouterAdvertMessage::AppendOption(uint16_t aOptionSize)
Option *RouterAdvert::TxMessage::AppendOption(uint16_t aOptionSize)
{
// This method appends an option with a given size to the RA
// message by reserving space in the data buffer if there is
@@ -217,21 +218,39 @@ Option *RouterAdvertMessage::AppendOption(uint16_t aOptionSize)
// initialized and populated by the caller.
Option *option = nullptr;
uint32_t newLength = mData.GetLength();
uint16_t oldLength = mArray.GetLength();
newLength += aOptionSize;
VerifyOrExit(newLength <= mMaxLength);
option = reinterpret_cast<Option *>(AsNonConst(GetDataEnd()));
mData.SetLength(static_cast<uint16_t>(newLength));
SuccessOrExit(AppendBytes(nullptr, aOptionSize));
option = reinterpret_cast<Option *>(&mArray[oldLength]);
exit:
return option;
}
Error RouterAdvertMessage::AppendPrefixInfoOption(const Prefix &aPrefix,
uint32_t aValidLifetime,
uint32_t aPreferredLifetime)
Error RouterAdvert::TxMessage::AppendBytes(const uint8_t *aBytes, uint16_t aLength)
{
Error error = kErrorNone;
for (; aLength > 0; aLength--)
{
uint8_t byte;
byte = (aBytes == nullptr) ? 0 : *aBytes++;
SuccessOrExit(error = mArray.PushBack(byte));
}
exit:
return error;
}
Error RouterAdvert::TxMessage::AppendHeader(const Header &aHeader)
{
return AppendBytes(reinterpret_cast<const uint8_t *>(&aHeader), sizeof(Header));
}
Error RouterAdvert::TxMessage::AppendPrefixInfoOption(const Prefix &aPrefix,
uint32_t aValidLifetime,
uint32_t aPreferredLifetime)
{
Error error = kErrorNone;
PrefixInfoOption *pio;
@@ -250,9 +269,9 @@ exit:
return error;
}
Error RouterAdvertMessage::AppendRouteInfoOption(const Prefix &aPrefix,
uint32_t aRouteLifetime,
RoutePreference aPreference)
Error RouterAdvert::TxMessage::AppendRouteInfoOption(const Prefix &aPrefix,
uint32_t aRouteLifetime,
RoutePreference aPreference)
{
Error error = kErrorNone;
RouteInfoOption *rio;
@@ -269,7 +288,7 @@ exit:
return error;
}
Error RouterAdvertMessage::AppendFlagsExtensionOption(bool aStubRouterFlag)
Error RouterAdvert::TxMessage::AppendFlagsExtensionOption(bool aStubRouterFlag)
{
Error error = kErrorNone;
RaFlagsExtOption *flagsOption;
+141 -116
View File
@@ -47,6 +47,7 @@
#include "common/const_cast.hpp"
#include "common/encoding.hpp"
#include "common/equatable.hpp"
#include "common/heap_array.hpp"
#include "net/icmp6.hpp"
#include "net/ip6.hpp"
#include "thread/network_data_types.hpp"
@@ -67,7 +68,7 @@ typedef NetworkData::RoutePreference RoutePreference; ///< Route Preference
OT_TOOL_PACKED_BEGIN
class Option
{
friend class RouterAdvertMessage;
friend class RouterAdvert;
public:
enum Type : uint8_t
@@ -525,14 +526,14 @@ private:
static_assert(sizeof(RaFlagsExtOption) == 8, "invalid RaFlagsExtOption structure");
/**
* Represents a Router Advertisement message.
* Defines Router Advertisement components.
*
*/
class RouterAdvertMessage
class RouterAdvert
{
public:
/**
* Implements the RA message header.
* Represent an RA message header.
*
* See section 2.2 of RFC 4191 [https://datatracker.ietf.org/doc/html/rfc4191]
*
@@ -673,135 +674,159 @@ public:
typedef Data<kWithUint16Length> Icmp6Packet; ///< A data buffer containing an ICMPv6 packet.
/**
* Initializes the RA message from a received packet data buffer.
*
* @param[in] aPacket A received packet data.
* Represents a received RA message.
*
*/
explicit RouterAdvertMessage(const Icmp6Packet &aPacket)
: mData(aPacket)
, mMaxLength(0)
class RxMessage
{
}
public:
/**
* Initializes the RA message from a received packet data buffer.
*
* @param[in] aPacket A received packet data.
*
*/
explicit RxMessage(const Icmp6Packet &aPacket)
: mData(aPacket)
{
}
/**
* Gets the RA message as an `Icmp6Packet`.
*
* @returns The RA message as an `Icmp6Packet`.
*
*/
const Icmp6Packet &GetAsPacket(void) const { return mData; }
/**
* Indicates whether or not the received RA message is valid.
*
* @retval TRUE If the RA message is valid.
* @retval FALSE If the RA message is not valid.
*
*/
bool IsValid(void) const
{
return (mData.GetBytes() != nullptr) && (mData.GetLength() >= sizeof(Header)) &&
(GetHeader().GetType() == Icmp::Header::kTypeRouterAdvert);
}
/**
* Gets the RA message's header.
*
* @returns The RA message's header.
*
*/
const Header &GetHeader(void) const { return *reinterpret_cast<const Header *>(mData.GetBytes()); }
/**
* Indicates whether or not the received RA message contains any options.
*
* @retval TRUE If the RA message contains at least one option.
* @retval FALSE If the RA message contains no options.
*
*/
bool ContainsAnyOptions(void) const { return (mData.GetLength() > sizeof(Header)); }
// The following methods are intended to support range-based `for`
// loop iteration over `Option`s in the RA message.
Option::Iterator begin(void) const { return Option::Iterator(GetOptionStart(), GetDataEnd()); }
Option::Iterator end(void) const { return Option::Iterator(); }
private:
const uint8_t *GetOptionStart(void) const { return (mData.GetBytes() + sizeof(Header)); }
const uint8_t *GetDataEnd(void) const { return mData.GetBytes() + mData.GetLength(); }
Data<kWithUint16Length> mData;
};
/**
* This template constructor initializes the RA message with a given header using a given buffer to store the RA
* message.
*
* @tparam kBufferSize The size of the buffer used to store the RA message.
*
* @param[in] aHeader The RA message header.
* @param[in] aBuffer The data buffer to store the RA message in.
* Represents an RA message to be sent.
*
*/
template <uint16_t kBufferSize>
RouterAdvertMessage(const Header &aHeader, uint8_t (&aBuffer)[kBufferSize])
: mMaxLength(kBufferSize)
class TxMessage
{
static_assert(kBufferSize >= sizeof(Header), "Buffer for RA msg is too small");
public:
/**
* Gets the prepared RA message as an `Icmp6Packet`.
*
* @param[out] aPacket A reference to an `Icmp6Packet`.
*
*/
void GetAsPacket(Icmp6Packet &aPacket) const { aPacket.Init(mArray.AsCArray(), mArray.GetLength()); }
memcpy(aBuffer, &aHeader, sizeof(Header));
mData.Init(aBuffer, sizeof(Header));
}
/**
* Appends the RA header.
*
* @param[in] aHeader The RA header.
*
* @retval kErrorNone Header is written successfully.
* @retval kErrorNoBufs Insufficient available buffers to grow the message.
*
*/
Error AppendHeader(const Header &aHeader);
/**
* Gets the RA message as an `Icmp6Packet`.
*
* @returns The RA message as an `Icmp6Packet`.
*
*/
const Icmp6Packet &GetAsPacket(void) const { return mData; }
/**
* 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.
*
* @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);
/**
* Indicates whether or not the RA message is valid.
*
* @retval TRUE If the RA message is valid.
* @retval FALSE If the RA message is not valid.
*
*/
bool IsValid(void) const
{
return (mData.GetBytes() != nullptr) && (mData.GetLength() >= sizeof(Header)) &&
(GetHeader().GetType() == Icmp::Header::kTypeRouterAdvert);
}
/**
* Appends a Route Info Option to the RA message.
*
* @param[in] aPrefix The prefix.
* @param[in] aRouteLifetime The route lifetime in seconds.
* @param[in] aPreference The route preference.
*
* @retval kErrorNone Option is appended successfully.
* @retval kErrorNoBufs Insufficient available buffers to grow the message.
*
*/
Error AppendRouteInfoOption(const Prefix &aPrefix, uint32_t aRouteLifetime, RoutePreference aPreference);
/**
* Gets the RA message's header.
*
* @returns The RA message's header.
*
*/
const Header &GetHeader(void) const { return *reinterpret_cast<const Header *>(mData.GetBytes()); }
/**
* Appends a Flags Extension Option to the RA message.
*
* @param[in] aStubRouterFlag The stub router flag.
*
* @retval kErrorNone Option is appended successfully.
* @retval kErrorNoBufs Insufficient available buffers to grow the message.
*
*/
Error AppendFlagsExtensionOption(bool aStubRouterFlag);
/**
* Gets the RA message's header.
*
* @returns The RA message's header.
*
*/
Header &GetHeader(void) { return *reinterpret_cast<Header *>(AsNonConst(mData.GetBytes())); }
/**
* Indicates whether or not the received RA message contains any options.
*
* @retval TRUE If the RA message contains at least one option.
* @retval FALSE If the RA message contains no options.
*
*/
bool ContainsAnyOptions(void) const { return (mArray.GetLength() > sizeof(Header)); }
/**
* 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.
*
* @retval kErrorNone Option is appended successfully.
* @retval kErrorNoBufs No more space in the buffer to append the option.
*
*/
Error AppendPrefixInfoOption(const Prefix &aPrefix, uint32_t aValidLifetime, uint32_t aPreferredLifetime);
private:
static constexpr uint16_t kCapacityIncrement = 256;
/**
* Appends a Route Info Option to the RA message.
*
* @param[in] aPrefix The prefix.
* @param[in] aRouteLifetime The route lifetime in seconds.
* @param[in] aPreference The route preference.
*
* @retval kErrorNone Option is appended successfully.
* @retval kErrorNoBufs No more space in the buffer to append the option.
*
*/
Error AppendRouteInfoOption(const Prefix &aPrefix, uint32_t aRouteLifetime, RoutePreference aPreference);
Error AppendBytes(const uint8_t *aBytes, uint16_t aLength);
Option *AppendOption(uint16_t aOptionSize);
/**
* Appends a Flags Extension Option to the RA message.
*
* @param[in] aStubRouterFlag The stub router flag.
*
* @retval kErrorNone Option is appended successfully.
* @retval kErrorNoBufs No more space in the buffer to append the option.
*
*/
Error AppendFlagsExtensionOption(bool aStubRouterFlag);
Heap::Array<uint8_t, kCapacityIncrement> mArray;
};
/**
* Indicates whether or not the RA message contains any options.
*
* @retval TRUE If the RA message contains at least one option.
* @retval FALSE If the RA message contains no options.
*
*/
bool ContainsAnyOptions(void) const { return (mData.GetLength() > sizeof(Header)); }
// The following methods are intended to support range-based `for`
// loop iteration over `Option`s in the RA message.
Option::Iterator begin(void) const { return Option::Iterator(GetOptionStart(), GetDataEnd()); }
Option::Iterator end(void) const { return Option::Iterator(); }
private:
const uint8_t *GetOptionStart(void) const { return (mData.GetBytes() + sizeof(Header)); }
const uint8_t *GetDataEnd(void) const { return mData.GetBytes() + mData.GetLength(); }
Option *AppendOption(uint16_t aOptionSize);
Data<kWithUint16Length> mData;
uint16_t mMaxLength;
RouterAdvert(void) = delete;
};
/**
+39 -42
View File
@@ -126,7 +126,7 @@ static otRadioFrame sRadioTxFrame;
static uint8_t sRadioTxFramePsdu[OT_RADIO_FRAME_MAX_SIZE];
static bool sRadioTxOngoing = false;
using Icmp6Packet = Ip6::Nd::RouterAdvertMessage::Icmp6Packet;
using Icmp6Packet = Ip6::Nd::RouterAdvert::Icmp6Packet;
enum ExpectedPio
{
@@ -414,7 +414,7 @@ void ValidateRouterAdvert(const Icmp6Packet &aPacket)
{
constexpr uint8_t kMaxPrefixes = 16;
Ip6::Nd::RouterAdvertMessage raMsg(aPacket);
Ip6::Nd::RouterAdvert::RxMessage raMsg(aPacket);
bool sawExpectedPio = false;
Array<Ip6::Prefix, kMaxPrefixes> pioPrefixes;
Array<Ip6::Prefix, kMaxPrefixes> rioPrefixes;
@@ -570,7 +570,7 @@ exit:
void LogRouterAdvert(const Icmp6Packet &aPacket)
{
Ip6::Nd::RouterAdvertMessage raMsg(aPacket);
Ip6::Nd::RouterAdvert::RxMessage raMsg(aPacket);
VerifyOrQuit(raMsg.IsValid());
@@ -854,17 +854,15 @@ struct RaFlags : public Clearable<RaFlags>
bool mStubRouterFlag;
};
template <size_t N>
uint16_t BuildRouterAdvert(uint8_t (&aBuffer)[N],
const Pio *aPios,
uint16_t aNumPios,
const Rio *aRios,
uint16_t aNumRios,
const DefaultRoute &aDefaultRoute,
const RaFlags &aRaFlags)
void BuildRouterAdvert(Ip6::Nd::RouterAdvert::TxMessage &aRaMsg,
const Pio *aPios,
uint16_t aNumPios,
const Rio *aRios,
uint16_t aNumRios,
const DefaultRoute &aDefaultRoute,
const RaFlags &aRaFlags)
{
Ip6::Nd::RouterAdvertMessage::Header header;
uint16_t length;
Ip6::Nd::RouterAdvert::Header header;
header.SetRouterLifetime(aDefaultRoute.mLifetime);
header.SetDefaultRouterPreference(aDefaultRoute.mPreference);
@@ -879,29 +877,22 @@ uint16_t BuildRouterAdvert(uint8_t (&aBuffer)[N],
header.SetOtherConfigFlag();
}
SuccessOrQuit(aRaMsg.AppendHeader(header));
if (aRaFlags.mStubRouterFlag)
{
Ip6::Nd::RouterAdvertMessage raMsg(header, aBuffer);
if (aRaFlags.mStubRouterFlag)
{
SuccessOrQuit(raMsg.AppendFlagsExtensionOption(/* aStubRouterFlag */ true));
}
for (; aNumPios > 0; aPios++, aNumPios--)
{
SuccessOrQuit(
raMsg.AppendPrefixInfoOption(aPios->mPrefix, aPios->mValidLifetime, aPios->mPreferredLifetime));
}
for (; aNumRios > 0; aRios++, aNumRios--)
{
SuccessOrQuit(raMsg.AppendRouteInfoOption(aRios->mPrefix, aRios->mValidLifetime, aRios->mPreference));
}
length = raMsg.GetAsPacket().GetLength();
SuccessOrQuit(aRaMsg.AppendFlagsExtensionOption(/* aStubRouterFlag */ true));
}
return length;
for (; aNumPios > 0; aPios++, aNumPios--)
{
SuccessOrQuit(aRaMsg.AppendPrefixInfoOption(aPios->mPrefix, aPios->mValidLifetime, aPios->mPreferredLifetime));
}
for (; aNumRios > 0; aRios++, aNumRios--)
{
SuccessOrQuit(aRaMsg.AppendRouteInfoOption(aRios->mPrefix, aRios->mValidLifetime, aRios->mPreference));
}
}
void SendRouterAdvert(const Ip6::Address &aRouterAddress,
@@ -912,12 +903,15 @@ void SendRouterAdvert(const Ip6::Address &aRouterAddress,
const DefaultRoute &aDefaultRoute,
const RaFlags &aRaFlags)
{
uint8_t buffer[kMaxRaSize];
uint16_t length = BuildRouterAdvert(buffer, aPios, aNumPios, aRios, aNumRios, aDefaultRoute, aRaFlags);
Ip6::Nd::RouterAdvert::TxMessage raMsg;
Icmp6Packet packet;
SendRouterAdvert(aRouterAddress, buffer, length);
BuildRouterAdvert(raMsg, aPios, aNumPios, aRios, aNumRios, aDefaultRoute, aRaFlags);
raMsg.GetAsPacket(packet);
SendRouterAdvert(aRouterAddress, packet);
Log("Sending RA from router %s", aRouterAddress.ToString().AsCString());
LogRouterAdvert(buffer, length);
LogRouterAdvert(packet);
}
template <uint16_t kNumPios, uint16_t kNumRios>
@@ -963,13 +957,16 @@ void SendRouterAdvert(const Ip6::Address &aRouterAddress, const RaFlags &aRaFlag
template <uint16_t kNumPios> void SendRouterAdvertToBorderRoutingProcessIcmp6Ra(const Pio (&aPios)[kNumPios])
{
uint8_t buffer[kMaxRaSize];
uint16_t length = BuildRouterAdvert(buffer, aPios, kNumPios, nullptr, 0,
DefaultRoute(0, NetworkData::kRoutePreferenceMedium), RaFlags());
Ip6::Nd::RouterAdvert::TxMessage raMsg;
Icmp6Packet packet;
otPlatBorderRoutingProcessIcmp6Ra(sInstance, buffer, length);
BuildRouterAdvert(raMsg, aPios, kNumPios, nullptr, 0, DefaultRoute(0, NetworkData::kRoutePreferenceMedium),
RaFlags());
raMsg.GetAsPacket(packet);
otPlatBorderRoutingProcessIcmp6Ra(sInstance, packet.GetBytes(), packet.GetLength());
Log("Passing RA to otPlatBorderRoutingProcessIcmp6Ra");
LogRouterAdvert(buffer, length);
LogRouterAdvert(packet);
}
struct OnLinkPrefix : public Pio