mirror of
https://github.com/espressif/openthread.git
synced 2026-06-05 21:14:49 +00:00
[mle] introduce RouteTlv::Data to represent parsed Route TLV (#13098)
This commit introduces a new model for handling `RouteTlv` by adding the `RouteTlv::Data` and `RouteTlv::Data::Entry` classes. Previously, `RouteTlv` directly represented the packed on-wire format, which made it difficult to work with, especially when supporting different configurations such as `OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE`. The new `RouteTlv::Data` class decouples the on-wire serialization from the in-memory representation, providing a cleaner API for parsing the TLV from a `Message` and accessing its entries and their properties (Router ID, Route Cost, and Link Qualities). This change improves code clarity and maintainability by providing a structured way to handle route information.
This commit is contained in:
committed by
GitHub
parent
c6fa686dd7
commit
181405efc9
@@ -4252,16 +4252,19 @@ exit:
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
Error Mle::RxMessage::ReadRouteTlv(RouteTlv &aRouteTlv) const
|
||||
{
|
||||
Error error;
|
||||
|
||||
SuccessOrExit(error = Tlv::FindTlv(*this, aRouteTlv));
|
||||
VerifyOrExit(aRouteTlv.IsValid(), error = kErrorParse);
|
||||
Error Mle::RxMessage::ReadRouteTlv(RouteTlv::Data &aRouteTlvData) const
|
||||
{
|
||||
Error error;
|
||||
OffsetRange offsetRange;
|
||||
|
||||
SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(*this, RouteTlv::kType, offsetRange));
|
||||
error = aRouteTlvData.ParseFrom(*this, offsetRange);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -1642,7 +1642,7 @@ private:
|
||||
Error ReadCslClockAccuracyTlv(Mac::CslAccuracy &aCslAccuracy) const;
|
||||
#endif
|
||||
#if OPENTHREAD_FTD
|
||||
Error ReadRouteTlv(RouteTlv &aRouteTlv) const;
|
||||
Error ReadRouteTlv(RouteTlv::Data &aRouteTlvData) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
@@ -2243,7 +2243,7 @@ private:
|
||||
bool IsRouterCountBelowUpgradeThreshold(void) const;
|
||||
void HandleTimeTick(void);
|
||||
void DecideWhetherToUpgrade(void);
|
||||
void DecideWhetherToDowngrade(uint8_t aNeighborId, const RouteTlv &aRouteTlv);
|
||||
void DecideWhetherToDowngrade(uint8_t aNeighborId, const RouteTlv::Data &aRouteTlvData);
|
||||
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
|
||||
void SetCcmEnabled(bool aEnabled);
|
||||
void SetThreadVersionCheckEnabled(bool aEnabled);
|
||||
@@ -2251,7 +2251,7 @@ private:
|
||||
|
||||
private:
|
||||
bool DetermineIfRouterRoleAllowed(void) const;
|
||||
bool NeighborHasComparableConnectivity(uint8_t aNeighborId, const RouteTlv &aRouteTlv) const;
|
||||
bool NeighborHasComparableConnectivity(uint8_t aNeighborId, const RouteTlv::Data &aRouteTlvData) const;
|
||||
|
||||
bool mRouterEligible : 1;
|
||||
bool mRouterRoleAllowed : 1;
|
||||
@@ -2466,7 +2466,7 @@ private:
|
||||
void HandleNetworkDataUpdateRouter(void);
|
||||
void HandleDiscoveryRequest(RxInfo &aRxInfo);
|
||||
void EstablishRouterLinkOnFtdChild(Router &aRouter, RxInfo &aRxInfo, uint8_t aLinkMargin);
|
||||
Error ProcessRouteTlv(const RouteTlv &aRouteTlv, RxInfo &aRxInfo);
|
||||
Error ProcessRouteTlv(const RouteTlv::Data &aRouteTlvData, RxInfo &aRxInfo);
|
||||
Error ReadAndProcessRouteTlvOnFtdChild(RxInfo &aRxInfo, uint8_t aParentId);
|
||||
void StopAdvertiseTrickleTimer(void);
|
||||
uint32_t DetermineAdvertiseIntervalMax(void) const;
|
||||
|
||||
+56
-51
@@ -899,7 +899,7 @@ void Mle::HandleLinkAcceptVariant(RxInfo &aRxInfo, MessageType aMessageType)
|
||||
uint32_t mleFrameCounter;
|
||||
uint8_t routerId;
|
||||
uint16_t address16;
|
||||
RouteTlv routeTlv;
|
||||
RouteTlv::Data routeTlvData;
|
||||
LeaderData leaderData;
|
||||
uint8_t linkMargin;
|
||||
bool shouldUpdateRoutes = false;
|
||||
@@ -969,8 +969,8 @@ void Mle::HandleLinkAcceptVariant(RxInfo &aRxInfo, MessageType aMessageType)
|
||||
SetLeaderData(leaderData);
|
||||
|
||||
mRouterTable.Clear();
|
||||
SuccessOrExit(error = aRxInfo.mMessage.ReadRouteTlv(routeTlv));
|
||||
SuccessOrExit(error = ProcessRouteTlv(routeTlv, aRxInfo));
|
||||
SuccessOrExit(error = aRxInfo.mMessage.ReadRouteTlv(routeTlvData));
|
||||
SuccessOrExit(error = ProcessRouteTlv(routeTlvData, aRxInfo));
|
||||
router = mRouterTable.FindRouterById(routerId);
|
||||
VerifyOrExit(router != nullptr);
|
||||
|
||||
@@ -1010,14 +1010,14 @@ void Mle::HandleLinkAcceptVariant(RxInfo &aRxInfo, MessageType aMessageType)
|
||||
IgnoreError(SendDataRequest(aRxInfo.mMessageInfo.GetPeerAddr()));
|
||||
}
|
||||
|
||||
switch (aRxInfo.mMessage.ReadRouteTlv(routeTlv))
|
||||
switch (aRxInfo.mMessage.ReadRouteTlv(routeTlvData))
|
||||
{
|
||||
case kErrorNone:
|
||||
VerifyOrExit(routeTlv.IsRouterIdSet(routerId), error = kErrorParse);
|
||||
VerifyOrExit(routeTlvData.IsAllocated(routerId), error = kErrorParse);
|
||||
|
||||
if (mRouterTable.IsRouteTlvIdSequenceMoreRecent(routeTlv))
|
||||
if (mRouterTable.IsRouteTlvIdSequenceMoreRecent(routeTlvData))
|
||||
{
|
||||
SuccessOrExit(error = ProcessRouteTlv(routeTlv, aRxInfo));
|
||||
SuccessOrExit(error = ProcessRouteTlv(routeTlvData, aRxInfo));
|
||||
router = mRouterTable.FindRouterById(routerId);
|
||||
OT_ASSERT(router != nullptr);
|
||||
}
|
||||
@@ -1061,7 +1061,7 @@ void Mle::HandleLinkAcceptVariant(RxInfo &aRxInfo, MessageType aMessageType)
|
||||
|
||||
if (shouldUpdateRoutes)
|
||||
{
|
||||
mRouterTable.UpdateRoutes(routeTlv, routerId);
|
||||
mRouterTable.UpdateRoutes(routeTlvData, routerId);
|
||||
}
|
||||
|
||||
aRxInfo.mClass = RxInfo::kAuthoritativeMessage;
|
||||
@@ -1093,9 +1093,9 @@ exit:
|
||||
LogProcessError(aMessageType, error);
|
||||
}
|
||||
|
||||
Error Mle::ProcessRouteTlv(const RouteTlv &aRouteTlv, RxInfo &aRxInfo)
|
||||
Error Mle::ProcessRouteTlv(const RouteTlv::Data &aRouteTlvData, RxInfo &aRxInfo)
|
||||
{
|
||||
// This method processes `aRouteTlv` read from an MLE message.
|
||||
// This method processes `aRouteTlvData` read from an MLE message.
|
||||
//
|
||||
// During processing of Route TLV, the entries in the router table
|
||||
// may shuffle. This method ensures that the `aRxInfo.mNeighbor`
|
||||
@@ -1112,7 +1112,7 @@ Error Mle::ProcessRouteTlv(const RouteTlv &aRouteTlv, RxInfo &aRxInfo)
|
||||
neighborRloc16 = aRxInfo.mNeighbor->GetRloc16();
|
||||
}
|
||||
|
||||
mRouterTable.UpdateRouterIdMask(aRouteTlv.GetRouterIdMask());
|
||||
mRouterTable.UpdateRouterIdMask(aRouteTlvData);
|
||||
|
||||
if (IsAttached() && !mRouterTable.IsAllocated(RouterIdFromRloc16(GetRloc16())))
|
||||
{
|
||||
@@ -1141,16 +1141,16 @@ Error Mle::ReadAndProcessRouteTlvOnFtdChild(RxInfo &aRxInfo, uint8_t aParentId)
|
||||
// It MUST be used only when device is acting as a child and
|
||||
// for a message received from device's current parent.
|
||||
|
||||
Error error = kErrorNone;
|
||||
RouteTlv routeTlv;
|
||||
Error error = kErrorNone;
|
||||
RouteTlv::Data routeTlvData;
|
||||
|
||||
VerifyOrExit(IsFullThreadDevice());
|
||||
|
||||
switch (aRxInfo.mMessage.ReadRouteTlv(routeTlv))
|
||||
switch (aRxInfo.mMessage.ReadRouteTlv(routeTlvData))
|
||||
{
|
||||
case kErrorNone:
|
||||
SuccessOrExit(error = ProcessRouteTlv(routeTlv, aRxInfo));
|
||||
mRouterTable.UpdateRouterOnFtdChild(routeTlv, aParentId);
|
||||
SuccessOrExit(error = ProcessRouteTlv(routeTlvData, aRxInfo));
|
||||
mRouterTable.UpdateRouterOnFtdChild(routeTlvData, aParentId);
|
||||
mRequestRouteTlv = false;
|
||||
break;
|
||||
case kErrorNotFound:
|
||||
@@ -1204,19 +1204,20 @@ Error Mle::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddress, co
|
||||
// - `aSourceAddress` is the read value from `SourceAddressTlv`.
|
||||
// - `aLeaderData` is the read value from `LeaderDataTlv`.
|
||||
|
||||
Error error = kErrorNone;
|
||||
uint8_t linkMargin = Get<Mac::Mac>().ComputeLinkMargin(aRxInfo.mMessage.GetAverageRss());
|
||||
RouteTlv routeTlv;
|
||||
Router *router;
|
||||
uint8_t routerId;
|
||||
uint32_t delay;
|
||||
Error error = kErrorNone;
|
||||
uint8_t linkMargin = Get<Mac::Mac>().ComputeLinkMargin(aRxInfo.mMessage.GetAverageRss());
|
||||
RouteTlv::Data routeTlvData;
|
||||
bool hasRouteTlv = false;
|
||||
Router *router;
|
||||
uint8_t routerId;
|
||||
uint32_t delay;
|
||||
|
||||
switch (aRxInfo.mMessage.ReadRouteTlv(routeTlv))
|
||||
switch (aRxInfo.mMessage.ReadRouteTlv(routeTlvData))
|
||||
{
|
||||
case kErrorNone:
|
||||
hasRouteTlv = true;
|
||||
break;
|
||||
case kErrorNotFound:
|
||||
routeTlv.SetLength(0); // Mark that a Route TLV was not included.
|
||||
break;
|
||||
default:
|
||||
ExitNow(error = kErrorParse);
|
||||
@@ -1232,11 +1233,11 @@ Error Mle::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddress, co
|
||||
|
||||
VerifyOrExit(linkMargin >= kPartitionMergeMinMargin, error = kErrorLinkMarginLow);
|
||||
|
||||
if (routeTlv.IsValid() && (mPreviousPartitionIdTimeout > 0) &&
|
||||
(aLeaderData.GetPartitionId() == mPreviousPartitionId))
|
||||
if (hasRouteTlv && (mPreviousPartitionIdTimeout > 0) && (aLeaderData.GetPartitionId() == mPreviousPartitionId))
|
||||
{
|
||||
VerifyOrExit(SerialNumber::IsGreater(routeTlv.GetRouterIdSequence(), mPreviousPartitionRouterIdSequence),
|
||||
error = kErrorDrop);
|
||||
VerifyOrExit(
|
||||
SerialNumber::IsGreater(routeTlvData.GetRouterIdSequence(), mPreviousPartitionRouterIdSequence),
|
||||
error = kErrorDrop);
|
||||
}
|
||||
|
||||
if (IsChild() && (aRxInfo.mNeighbor == &mParent))
|
||||
@@ -1244,7 +1245,8 @@ Error Mle::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddress, co
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
if (ComparePartitions(routeTlv.IsSingleton(), aLeaderData, IsSingleton(), mLeaderData) > 0
|
||||
if (hasRouteTlv &&
|
||||
ComparePartitions(routeTlvData.IsSingleton(), aLeaderData, IsSingleton(), mLeaderData) > 0
|
||||
#if OPENTHREAD_CONFIG_TIME_SYNC_REQUIRED
|
||||
// Allow a better partition if it also enables time sync.
|
||||
&& aRxInfo.mMessage.GetTimeSyncSeq() != OT_TIME_SYNC_INVALID_SEQ
|
||||
@@ -1274,7 +1276,7 @@ Error Mle::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddress, co
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
VerifyOrExit(IsRouterRloc16(aSourceAddress) && routeTlv.IsValid());
|
||||
VerifyOrExit(IsRouterRloc16(aSourceAddress) && hasRouteTlv);
|
||||
routerId = RouterIdFromRloc16(aSourceAddress);
|
||||
|
||||
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
|
||||
@@ -1284,9 +1286,9 @@ Error Mle::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddress, co
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Process `RouteTlv`
|
||||
|
||||
if (aRxInfo.IsNeighborStateValid() && mRouterTable.IsRouteTlvIdSequenceMoreRecent(routeTlv))
|
||||
if (aRxInfo.IsNeighborStateValid() && mRouterTable.IsRouteTlvIdSequenceMoreRecent(routeTlvData))
|
||||
{
|
||||
SuccessOrExit(error = ProcessRouteTlv(routeTlv, aRxInfo));
|
||||
SuccessOrExit(error = ProcessRouteTlv(routeTlvData, aRxInfo));
|
||||
}
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@@ -1305,7 +1307,7 @@ Error Mle::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddress, co
|
||||
ExitNow(error = kErrorDetached);
|
||||
}
|
||||
|
||||
mRouterTable.UpdateRouterOnFtdChild(routeTlv, routerId);
|
||||
mRouterTable.UpdateRouterOnFtdChild(routeTlvData, routerId);
|
||||
|
||||
mRoleTransitioner.DecideWhetherToUpgrade();
|
||||
}
|
||||
@@ -1330,7 +1332,7 @@ Error Mle::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddress, co
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Inform `RoleTransitioner` to decide whether we need to downgrade
|
||||
|
||||
mRoleTransitioner.DecideWhetherToDowngrade(routerId, routeTlv);
|
||||
mRoleTransitioner.DecideWhetherToDowngrade(routerId, routeTlvData);
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Update routers as a router or leader.
|
||||
@@ -1359,7 +1361,7 @@ Error Mle::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddress, co
|
||||
// unicast/multicast link request in progress
|
||||
|
||||
if (!router->IsStateValid() && !router->IsStateLinkRequest() && (linkMargin >= kLinkRequestMinMargin) &&
|
||||
routeTlv.IsRouterIdSet(mRouterId))
|
||||
routeTlvData.IsAllocated(mRouterId))
|
||||
{
|
||||
InitNeighbor(*router, aRxInfo);
|
||||
router->SetState(Neighbor::kStateLinkRequest);
|
||||
@@ -1371,7 +1373,7 @@ Error Mle::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddress, co
|
||||
|
||||
router->SetLastHeard(TimerMilli::GetNow());
|
||||
|
||||
mRouterTable.UpdateRoutes(routeTlv, routerId);
|
||||
mRouterTable.UpdateRoutes(routeTlvData, routerId);
|
||||
|
||||
exit:
|
||||
if (aRxInfo.mNeighbor && aRxInfo.mNeighbor->GetRloc16() != aSourceAddress)
|
||||
@@ -3724,11 +3726,11 @@ void Mle::FillConnectivityTlvValue(ConnectivityTlvValue &aTlvValue) const
|
||||
aTlvValue.InitFrom(connectivity);
|
||||
}
|
||||
|
||||
void Mle::RoleTransitioner::DecideWhetherToDowngrade(uint8_t aNeighborId, const RouteTlv &aRouteTlv)
|
||||
void Mle::RoleTransitioner::DecideWhetherToDowngrade(uint8_t aNeighborId, const RouteTlv::Data &aRouteTlvData)
|
||||
{
|
||||
// Determine whether all conditions are satisfied for the router
|
||||
// to downgrade after receiving info for a neighboring router
|
||||
// with Router ID `aNeighborId` along with its `aRouteTlv`.
|
||||
// with Router ID `aNeighborId` along with its `aRouteTlvData`.
|
||||
|
||||
uint8_t activeRouterCount = Get<RouterTable>().GetActiveRouterCount();
|
||||
uint8_t count;
|
||||
@@ -3773,7 +3775,7 @@ void Mle::RoleTransitioner::DecideWhetherToDowngrade(uint8_t aNeighborId, const
|
||||
// Check that the neighbor has as good or better-quality links to
|
||||
// same routers.
|
||||
|
||||
VerifyOrExit(NeighborHasComparableConnectivity(aNeighborId, aRouteTlv));
|
||||
VerifyOrExit(NeighborHasComparableConnectivity(aNeighborId, aRouteTlvData));
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
|
||||
// Check if we are eligible to be router due to being a BR.
|
||||
@@ -3787,21 +3789,22 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
bool Mle::RoleTransitioner::NeighborHasComparableConnectivity(uint8_t aNeighborId, const RouteTlv &aRouteTlv) const
|
||||
bool Mle::RoleTransitioner::NeighborHasComparableConnectivity(uint8_t aNeighborId,
|
||||
const RouteTlv::Data &aRouteTlvData) const
|
||||
{
|
||||
// Check whether the neighboring router with Router ID `aNeighborId`
|
||||
// (along with its `aRouteTlv`) has as good or better-quality links
|
||||
// to all our neighboring routers which have a two-way link quality
|
||||
// of two or better.
|
||||
// (along with its `aRouteTlvData`) has as good or better-quality
|
||||
// links to all our neighboring routers which have a two-way link
|
||||
// quality of two or better.
|
||||
|
||||
bool isComparable = true;
|
||||
|
||||
for (uint8_t routerId = 0, index = 0; routerId <= kMaxRouterId;
|
||||
index += aRouteTlv.IsRouterIdSet(routerId) ? 1 : 0, routerId++)
|
||||
for (uint8_t routerId = 0; routerId <= kMaxRouterId; routerId++)
|
||||
{
|
||||
const Router *router;
|
||||
LinkQuality localLinkQuality;
|
||||
LinkQuality peerLinkQuality;
|
||||
const Router *router;
|
||||
LinkQuality localLinkQuality;
|
||||
LinkQuality peerLinkQuality;
|
||||
const RouteTlv::Data::Entry *entry;
|
||||
|
||||
if ((routerId == Get<Mle>().mRouterId) || (routerId == aNeighborId))
|
||||
{
|
||||
@@ -3823,15 +3826,17 @@ bool Mle::RoleTransitioner::NeighborHasComparableConnectivity(uint8_t aNeighborI
|
||||
}
|
||||
|
||||
// `router` is our neighbor with two-way link quality of
|
||||
// at least two. Check that `aRouteTlv` has as good or
|
||||
// at least two. Check that `aRouteTlvData` has as good or
|
||||
// better-quality link to it as well.
|
||||
|
||||
if (!aRouteTlv.IsRouterIdSet(routerId))
|
||||
entry = aRouteTlvData.GetEntries().FindMatching(routerId);
|
||||
|
||||
if (entry == nullptr)
|
||||
{
|
||||
ExitNow(isComparable = false);
|
||||
}
|
||||
|
||||
peerLinkQuality = Min(aRouteTlv.GetLinkQualityIn(index), aRouteTlv.GetLinkQualityOut(index));
|
||||
peerLinkQuality = Min(entry->GetLinkQualityIn(), entry->GetLinkQualityOut());
|
||||
|
||||
if (peerLinkQuality < localLinkQuality)
|
||||
{
|
||||
|
||||
@@ -44,25 +44,82 @@ namespace Mle {
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// RouteTlv
|
||||
|
||||
void RouteTlv::Init(void)
|
||||
Error RouteTlv::Data::ParseFrom(const Message &aMessage, const OffsetRange &aOffsetRange)
|
||||
{
|
||||
SetType(kRoute);
|
||||
SetLength(sizeof(*this) - sizeof(Tlv));
|
||||
mRouterIdMask.Clear();
|
||||
ClearAllBytes(mRouteData);
|
||||
}
|
||||
Error error;
|
||||
RouterIdMask routerIdMask;
|
||||
OffsetRange offsetRange = aOffsetRange;
|
||||
#if OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
|
||||
bool isEven = true;
|
||||
#endif
|
||||
|
||||
bool RouteTlv::IsValid(void) const
|
||||
{
|
||||
bool isValid = false;
|
||||
SuccessOrExit(error = aMessage.Read(offsetRange, routerIdMask));
|
||||
offsetRange.AdvanceOffset(sizeof(routerIdMask));
|
||||
|
||||
VerifyOrExit(GetLength() >= sizeof(mRouterIdMask));
|
||||
mIdSequence = routerIdMask.GetSequence();
|
||||
|
||||
VerifyOrExit(mRouterIdMask.IsValid());
|
||||
isValid = (GetRouteDataEntryCount() >= mRouterIdMask.DetermineAllocatedCount());
|
||||
mEntries.Clear();
|
||||
|
||||
for (uint8_t routerId = 0; routerId <= kMaxRouterId; routerId++)
|
||||
{
|
||||
Entry *entry;
|
||||
|
||||
if (!routerIdMask.IsAllocated(routerId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
entry = mEntries.PushBack();
|
||||
|
||||
// If `mEntries` is full, it indicates that there are more than
|
||||
// `kMaxRouters` allocated IDs in the mask, which makes it invalid.
|
||||
|
||||
VerifyOrExit(entry != nullptr, error = kErrorParse);
|
||||
|
||||
entry->mRouterId = routerId;
|
||||
|
||||
#if !OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
|
||||
SuccessOrExit(error = aMessage.Read<uint8_t>(offsetRange, entry->mRouteData));
|
||||
offsetRange.AdvanceOffset(sizeof(uint8_t));
|
||||
#else
|
||||
{
|
||||
EntryType value;
|
||||
|
||||
SuccessOrExit(error = aMessage.Read<EntryType>(offsetRange, value));
|
||||
value = BigEndian::HostSwap16(value);
|
||||
|
||||
if (isEven)
|
||||
{
|
||||
entry->mRouteData = ReadBits<uint16_t, kEvenEntryMask>(value);
|
||||
offsetRange.AdvanceOffset(sizeof(uint8_t));
|
||||
}
|
||||
else
|
||||
{
|
||||
entry->mRouteData = ReadBits<uint16_t, kOddEntryMask>(value);
|
||||
offsetRange.AdvanceOffset(sizeof(uint16_t));
|
||||
}
|
||||
|
||||
isEven = !isEven;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
exit:
|
||||
return isValid;
|
||||
return error;
|
||||
}
|
||||
|
||||
bool RouteTlv::Data::IsAllocated(uint8_t aRouterId) const { return mEntries.FindMatching(aRouterId); }
|
||||
|
||||
void RouteTlv::Data::DetermineRouterIdMask(RouterIdMask &aRouterIdMask) const
|
||||
{
|
||||
aRouterIdMask.Clear();
|
||||
|
||||
aRouterIdMask.SetSequence(mIdSequence);
|
||||
|
||||
for (const Entry &entry : mEntries)
|
||||
{
|
||||
aRouterIdMask.Add(entry.mRouterId);
|
||||
}
|
||||
}
|
||||
|
||||
Error RouteTlv::AppendRouteDataEntry(Message &aMessage,
|
||||
|
||||
+128
-137
@@ -230,125 +230,142 @@ typedef UintTlvInfo<Tlv::kCslTimeout, uint32_t> CslTimeoutTlv;
|
||||
typedef UintTlvInfo<Tlv::kXtalAccuracy, uint16_t> XtalAccuracyTlv;
|
||||
|
||||
/**
|
||||
* Implements Route TLV generation and parsing.
|
||||
* Defines Route TLV constants and types.
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class RouteTlv : public Tlv, public TlvInfo<Tlv::kRoute>
|
||||
class RouteTlv : public TlvInfo<Tlv::kRoute>
|
||||
{
|
||||
#if !OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
|
||||
typedef uint8_t EntryType;
|
||||
#else
|
||||
typedef uint16_t EntryType;
|
||||
#endif
|
||||
|
||||
public:
|
||||
/**
|
||||
* Initializes the TLV.
|
||||
* Represents the parsed Route TLV data.
|
||||
*/
|
||||
void Init(void);
|
||||
|
||||
/**
|
||||
* Indicates whether or not the TLV appears to be well-formed.
|
||||
*
|
||||
* @retval TRUE If the TLV appears to be well-formed.
|
||||
* @retval FALSE If the TLV does not appear to be well-formed.
|
||||
*/
|
||||
bool IsValid(void) const;
|
||||
|
||||
/**
|
||||
* Returns the Router ID Sequence value.
|
||||
*
|
||||
* @returns The Router ID Sequence value.
|
||||
*/
|
||||
uint8_t GetRouterIdSequence(void) const { return mRouterIdMask.GetSequence(); }
|
||||
|
||||
/**
|
||||
* Gets the Router ID Mask.
|
||||
*
|
||||
* @returns The Router ID Mask.
|
||||
*/
|
||||
const RouterIdMask &GetRouterIdMask(void) const { return mRouterIdMask; }
|
||||
|
||||
/**
|
||||
* Gets the Router ID Mask.
|
||||
*
|
||||
* @returns The Router ID Mask.
|
||||
*/
|
||||
RouterIdMask &GetRouterIdMask(void) { return mRouterIdMask; }
|
||||
|
||||
/**
|
||||
* Indicates whether or not a Router ID bit is set.
|
||||
*
|
||||
* @param[in] aRouterId The Router ID.
|
||||
*
|
||||
* @retval TRUE If the Router ID bit is set.
|
||||
* @retval FALSE If the Router ID bit is not set.
|
||||
*/
|
||||
bool IsRouterIdSet(uint8_t aRouterId) const { return mRouterIdMask.IsAllocated(aRouterId); }
|
||||
|
||||
/**
|
||||
* Indicates whether the `RouteTlv` is a singleton, i.e., only one router is allocated.
|
||||
*
|
||||
* @retval TRUE It is a singleton.
|
||||
* @retval FALSE It is not a singleton.
|
||||
*/
|
||||
bool IsSingleton(void) const { return IsValid() && (mRouterIdMask.DetermineAllocatedCount() <= 1); }
|
||||
|
||||
/**
|
||||
* Returns the number of Route Data entries in the Route TLV.
|
||||
*
|
||||
* @returns The Route Data Entry Count.
|
||||
*/
|
||||
uint8_t GetRouteDataEntryCount(void) const
|
||||
class Data
|
||||
{
|
||||
#if !OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
|
||||
return GetLength() - sizeof(mRouterIdMask);
|
||||
#else
|
||||
return (GetLength() - sizeof(mRouterIdMask)) * 2 / 3;
|
||||
#endif
|
||||
}
|
||||
public:
|
||||
/**
|
||||
* Represents a single route entry.
|
||||
*/
|
||||
class Entry
|
||||
{
|
||||
friend class Data;
|
||||
|
||||
/**
|
||||
* Returns the Route Cost value for a given Router index.
|
||||
*
|
||||
* @param[in] aRouterIndex The Router index.
|
||||
*
|
||||
* @returns The Route Cost value for a given Router index.
|
||||
*/
|
||||
uint8_t GetRouteCost(uint8_t aRouterIndex) const
|
||||
{
|
||||
#if !OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
|
||||
return ReadBits<uint8_t, kRouteCostMask>(mRouteData[aRouterIndex]);
|
||||
#else
|
||||
return static_cast<uint8_t>(ReadBits<uint16_t, kRouteCostMask>(ReadEntry(aRouterIndex)));
|
||||
#endif
|
||||
}
|
||||
public:
|
||||
/**
|
||||
* Gets the Router ID.
|
||||
*
|
||||
* @returns The Router ID.
|
||||
*/
|
||||
uint8_t GetRouterId(void) const { return mRouterId; }
|
||||
|
||||
/**
|
||||
* Returns the Link Quality In value for a given Router index.
|
||||
*
|
||||
* @param[in] aRouterIndex The Router index.
|
||||
*
|
||||
* @returns The Link Quality In value for a given Router index.
|
||||
*/
|
||||
LinkQuality GetLinkQualityIn(uint8_t aRouterIndex) const
|
||||
{
|
||||
#if !OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
|
||||
return static_cast<LinkQuality>(ReadBits<uint8_t, kLinkQualityInMask>(mRouteData[aRouterIndex]));
|
||||
#else
|
||||
return static_cast<LinkQuality>(ReadBits<uint16_t, kLinkQualityInMask>(ReadEntry(aRouterIndex)));
|
||||
#endif
|
||||
}
|
||||
/**
|
||||
* Gets the Route Cost value.
|
||||
*
|
||||
* @returns The Route Cost value.
|
||||
*/
|
||||
uint8_t GetRouteCost(void) const
|
||||
{
|
||||
return static_cast<uint8_t>(ReadBits<EntryType, kRouteCostMask>(mRouteData));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Link Quality Out value for a given Router index.
|
||||
*
|
||||
* @param[in] aRouterIndex The Router index.
|
||||
*
|
||||
* @returns The Link Quality Out value for a given Router index.
|
||||
*/
|
||||
LinkQuality GetLinkQualityOut(uint8_t aRouterIndex) const
|
||||
{
|
||||
#if !OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
|
||||
return static_cast<LinkQuality>(ReadBits<uint8_t, kLinkQualityOutMask>(mRouteData[aRouterIndex]));
|
||||
#else
|
||||
return static_cast<LinkQuality>(ReadBits<uint16_t, kLinkQualityOutMask>(ReadEntry(aRouterIndex)));
|
||||
#endif
|
||||
}
|
||||
/**
|
||||
* Gets the Link Quality Out value.
|
||||
*
|
||||
* @returns The Link Quality Out value.
|
||||
*/
|
||||
LinkQuality GetLinkQualityOut(void) const
|
||||
{
|
||||
return static_cast<LinkQuality>(ReadBits<EntryType, kLinkQualityOutMask>(mRouteData));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Link Quality In value.
|
||||
*
|
||||
* @returns The Link Quality In value.
|
||||
*/
|
||||
LinkQuality GetLinkQualityIn(void) const
|
||||
{
|
||||
return static_cast<LinkQuality>(ReadBits<EntryType, kLinkQualityInMask>(mRouteData));
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the entry matches a given Router ID.
|
||||
*
|
||||
* @param[in] aRouterId The Router ID to match against.
|
||||
*
|
||||
* @retval TRUE The entry matches @p aRouterId.
|
||||
* @retval FALSE The entry does not match @p aRouterId.
|
||||
*/
|
||||
bool Matches(uint8_t aRouterId) const { return (mRouterId == aRouterId); }
|
||||
|
||||
private:
|
||||
uint8_t mRouterId;
|
||||
EntryType mRouteData;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents an array of route entries.
|
||||
*/
|
||||
typedef Array<Entry, kMaxRouters> EntryArray;
|
||||
|
||||
/**
|
||||
* Parses the Route TLV data from a given message and offset range.
|
||||
*
|
||||
* @param[in] aMessage The message to parse from.
|
||||
* @param[in] aOffsetRange The offset range within the message to read from.
|
||||
*
|
||||
* @retval kErrorNone Successfully parsed the Route TLV data.
|
||||
* @retval kErrorParse Failed to parse the Route TLV data.
|
||||
*/
|
||||
Error ParseFrom(const Message &aMessage, const OffsetRange &aOffsetRange);
|
||||
|
||||
/**
|
||||
* Gets the Router ID Sequence.
|
||||
*
|
||||
* @returns The Router ID Sequence.
|
||||
*/
|
||||
uint8_t GetRouterIdSequence(void) const { return mIdSequence; }
|
||||
|
||||
/**
|
||||
* Gets the array of route entries.
|
||||
*
|
||||
* @returns The array of route entries.
|
||||
*/
|
||||
const EntryArray &GetEntries(void) const { return mEntries; }
|
||||
|
||||
/**
|
||||
* Indicates whether a given Router ID is allocated in the route data.
|
||||
*
|
||||
* @param[in] aRouterId The Router ID to check.
|
||||
*
|
||||
* @retval TRUE The Router ID is allocated.
|
||||
* @retval FALSE The Router ID is not allocated.
|
||||
*/
|
||||
bool IsAllocated(uint8_t aRouterId) const;
|
||||
|
||||
/**
|
||||
* Indicates whether the Route TLV data is a singleton (at most one router is allocated).
|
||||
*
|
||||
* @retval TRUE It is a singleton.
|
||||
* @retval FALSE It is not a singleton.
|
||||
*/
|
||||
bool IsSingleton(void) const { return mEntries.GetLength() <= 1; }
|
||||
|
||||
/**
|
||||
* Determines the Router ID Mask from the route data.
|
||||
*
|
||||
* @param[out] aRouterIdMask A reference to a `RouterIdMask` to populate.
|
||||
*/
|
||||
void DetermineRouterIdMask(RouterIdMask &aRouterIdMask) const;
|
||||
|
||||
private:
|
||||
uint8_t mIdSequence;
|
||||
EntryArray mEntries;
|
||||
};
|
||||
|
||||
#if !OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
|
||||
/**
|
||||
@@ -394,21 +411,16 @@ private:
|
||||
// | LQOut | LQIn | Route Cost |
|
||||
// +---+---+---+---+---+---+---+---+
|
||||
|
||||
typedef uint8_t EntryType;
|
||||
|
||||
static constexpr uint8_t kLinkQualityOutMask = 0x03 << 6;
|
||||
static constexpr uint8_t kLinkQualityInMask = 0x03 << 4;
|
||||
static constexpr uint8_t kRouteCostMask = 0x0f << 0;
|
||||
|
||||
static constexpr uint16_t kMaxRouteDataSize = kMaxRouterId + 1;
|
||||
#else
|
||||
// Under `LOG_ROUTES` feature, Route Data is 12 bits per route
|
||||
// (1.5 bytes). The first 4 bits are link qualities (out/in),
|
||||
// remaining 8 bits are for the route cost. The even and odd
|
||||
// entries are staggered.
|
||||
|
||||
typedef uint16_t EntryType;
|
||||
|
||||
static constexpr uint16_t kEvenEntryMask = 0xfff << 4;
|
||||
static constexpr uint16_t kOddEntryMask = 0xfff << 0;
|
||||
|
||||
@@ -416,29 +428,8 @@ private:
|
||||
static constexpr uint16_t kLinkQualityInMask = 0x03 << 8;
|
||||
static constexpr uint16_t kRouteCostMask = 0xff << 0;
|
||||
|
||||
static constexpr uint16_t kMaxRouteDataSize = kMaxRouterId + 1 + kMaxRouterId / 2 + 1;
|
||||
|
||||
uint16_t ReadEntry(uint8_t aRouterIndex) const
|
||||
{
|
||||
uint16_t data;
|
||||
uint16_t offset = (aRouterIndex + aRouterIndex / 2);
|
||||
|
||||
if (aRouterIndex & 0x1)
|
||||
{
|
||||
data = ReadBits<uint16_t, kOddEntryMask>(BigEndian::ReadUint16(&mRouteData[offset]));
|
||||
}
|
||||
else
|
||||
{
|
||||
data = ReadBits<uint16_t, kEvenEntryMask>(BigEndian::ReadUint16(&mRouteData[offset]));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
|
||||
|
||||
RouterIdMask mRouterIdMask;
|
||||
uint8_t mRouteData[kMaxRouteDataSize];
|
||||
} OT_TOOL_PACKED_END;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents Leader Data TLV value.
|
||||
|
||||
@@ -1010,24 +1010,22 @@ Error Client::SendDiagnosticReset(const Ip6::Address &aDestination, const uint8_
|
||||
return SendCommand(kUriDiagnosticReset, Message::kPriorityNormal, aDestination, aTlvTypes, aCount);
|
||||
}
|
||||
|
||||
static void ParseRoute(const RouteTlv &aRouteTlv, otNetworkDiagRoute &aNetworkDiagRoute)
|
||||
void Client::GetRouteInfo(const RouteTlv::Data &aRouteTlvData, RouteInfo &aNetDiagRouteInfo)
|
||||
{
|
||||
uint8_t routeCount = 0;
|
||||
|
||||
for (uint8_t i = 0; i <= Mle::kMaxRouterId; ++i)
|
||||
aNetDiagRouteInfo.mIdSequence = aRouteTlvData.GetRouterIdSequence();
|
||||
|
||||
for (const RouteTlv::Data::Entry &entry : aRouteTlvData.GetEntries())
|
||||
{
|
||||
if (!aRouteTlv.IsRouterIdSet(i))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
aNetworkDiagRoute.mRouteData[routeCount].mRouterId = i;
|
||||
aNetworkDiagRoute.mRouteData[routeCount].mRouteCost = aRouteTlv.GetRouteCost(routeCount);
|
||||
aNetworkDiagRoute.mRouteData[routeCount].mLinkQualityIn = aRouteTlv.GetLinkQualityIn(routeCount);
|
||||
aNetworkDiagRoute.mRouteData[routeCount].mLinkQualityOut = aRouteTlv.GetLinkQualityOut(routeCount);
|
||||
++routeCount;
|
||||
aNetDiagRouteInfo.mRouteData[routeCount].mRouterId = entry.GetRouterId();
|
||||
aNetDiagRouteInfo.mRouteData[routeCount].mRouteCost = entry.GetRouteCost();
|
||||
aNetDiagRouteInfo.mRouteData[routeCount].mLinkQualityIn = entry.GetLinkQualityIn();
|
||||
aNetDiagRouteInfo.mRouteData[routeCount].mLinkQualityOut = entry.GetLinkQualityOut();
|
||||
routeCount++;
|
||||
}
|
||||
aNetworkDiagRoute.mRouteCount = routeCount;
|
||||
aNetworkDiagRoute.mIdSequence = aRouteTlv.GetRouterIdSequence();
|
||||
|
||||
aNetDiagRouteInfo.mRouteCount = routeCount;
|
||||
}
|
||||
|
||||
static Error ParseEnhancedRoute(const Message &aMessage, uint16_t aOffset, otNetworkDiagEnhRoute &aNetworkDiagEnhRoute)
|
||||
@@ -1167,13 +1165,10 @@ Error Client::GetNextDiagTlv(const Coap::Message &aMessage, Iterator &aIterator,
|
||||
|
||||
case Tlv::kRoute:
|
||||
{
|
||||
RouteTlv routeTlv;
|
||||
uint16_t bytesToRead = Min<uint16_t>(tlvInfo.GetSize(), sizeof(routeTlv));
|
||||
RouteTlv::Data routeTlvData;
|
||||
|
||||
VerifyOrExit(!tlvInfo.IsExtended(), error = kErrorParse);
|
||||
SuccessOrExit(error = aMessage.Read(offset, &routeTlv, bytesToRead));
|
||||
VerifyOrExit(routeTlv.IsValid(), error = kErrorParse);
|
||||
ParseRoute(routeTlv, aDiagTlv.mData.mRoute);
|
||||
SuccessOrExit(error = routeTlvData.ParseFrom(aMessage, tlvInfo.GetValueOffsetRange()));
|
||||
GetRouteInfo(routeTlvData, aDiagTlv.mData.mRoute);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -263,6 +263,7 @@ private:
|
||||
typedef otNetworkDiagData DiagData;
|
||||
typedef otNetworkDiagChildTable ChildTable;
|
||||
typedef otNetworkDiagIp6AddrList Ip6AddrList;
|
||||
typedef otNetworkDiagRoute RouteInfo;
|
||||
|
||||
Error SendCommand(Uri aUri,
|
||||
Message::Priority aPriority,
|
||||
@@ -285,6 +286,7 @@ private:
|
||||
static void ReadDiagData(DiagData &aDiagData, const Message &aMessage, const Tlv::Info &aTlvInfo);
|
||||
static Error ParseChildTable(ChildTable &aChildTable, const Message &aMessage, OffsetRange aOffsetRange);
|
||||
static void ParseIp6AddrList(Ip6AddrList &aIp6Addrs, const Message &aMessage, OffsetRange aOffsetRange);
|
||||
static void GetRouteInfo(const RouteTlv::Data &aRouteTlvData, RouteInfo &aNetDiagRouteInfo);
|
||||
|
||||
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
|
||||
static const char *UriToString(Uri aUri);
|
||||
|
||||
@@ -101,6 +101,21 @@ void ChildTableTlvEntry::Parse(ParseInfo &aParseInfo) const
|
||||
Mle::DeviceMode(mMode).Get(aParseInfo.mMode);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// RouteTlv
|
||||
|
||||
Error RouteTlv::FindIn(const Message &aMessage, RouteTlv::Data &aData)
|
||||
{
|
||||
Error error;
|
||||
OffsetRange offsetRange;
|
||||
|
||||
SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aMessage, kType, offsetRange));
|
||||
error = aData.ParseFrom(aMessage, offsetRange);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// EnhancedRouteTlvEntry
|
||||
|
||||
|
||||
@@ -296,21 +296,23 @@ typedef TlvInfo<Tlv::kConnectivity> ConnectivityTlv;
|
||||
/**
|
||||
* Implements Route TLV generation and parsing.
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class RouteTlv : public Mle::RouteTlv
|
||||
{
|
||||
public:
|
||||
static constexpr uint8_t kType = ot::NetworkDiagnostic::Tlv::kRoute; ///< The TLV Type value.
|
||||
|
||||
/**
|
||||
* Initializes the TLV.
|
||||
* Finds and parses a Route TLV in a given message.
|
||||
*
|
||||
* @param[in] aMessage The message to search within.
|
||||
* @param[out] aData A reference to a `Data` to populate upon success.
|
||||
*
|
||||
* @retval kErrorNone Successfully found and parsed the Route TLV.
|
||||
* @retval kErrorNotFound Could not find a Route TLV in @p aMessage.
|
||||
* @retval kErrorParse Found the Route TLV but failed to parse it.
|
||||
*/
|
||||
void Init(void)
|
||||
{
|
||||
Mle::RouteTlv::Init();
|
||||
ot::Tlv::SetType(kType);
|
||||
}
|
||||
} OT_TOOL_PACKED_END;
|
||||
static Error FindIn(const Message &aMessage, Data &aData);
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a Leader Data TLV value.
|
||||
|
||||
@@ -61,10 +61,10 @@ void RouterTable::Clear(void)
|
||||
SignalTableChanged(events);
|
||||
}
|
||||
|
||||
bool RouterTable::IsRouteTlvIdSequenceMoreRecent(const Mle::RouteTlv &aRouteTlv) const
|
||||
bool RouterTable::IsRouteTlvIdSequenceMoreRecent(const Mle::RouteTlv::Data &aRouteTlvData) const
|
||||
{
|
||||
return (GetActiveRouterCount() == 0) ||
|
||||
SerialNumber::IsGreater(aRouteTlv.GetRouterIdSequence(), GetRouterIdSequence());
|
||||
SerialNumber::IsGreater(aRouteTlvData.GetRouterIdSequence(), GetRouterIdSequence());
|
||||
}
|
||||
|
||||
void RouterTable::ClearNeighbors(void)
|
||||
@@ -525,6 +525,14 @@ uint16_t RouterTable::GetNextHop(uint16_t aDestRloc16) const
|
||||
return nextHopRloc16;
|
||||
}
|
||||
|
||||
void RouterTable::UpdateRouterIdMask(const Mle::RouteTlv::Data &aRouteTlvData)
|
||||
{
|
||||
Mle::RouterIdMask routerIdMask;
|
||||
|
||||
aRouteTlvData.DetermineRouterIdMask(routerIdMask);
|
||||
UpdateRouterIdMask(routerIdMask);
|
||||
}
|
||||
|
||||
void RouterTable::UpdateRouterIdMask(const Mle::RouterIdMask &aRouterIdMask)
|
||||
{
|
||||
bool shouldAdd = false;
|
||||
@@ -575,11 +583,12 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void RouterTable::UpdateRoutes(const Mle::RouteTlv &aRouteTlv, uint8_t aNeighborId)
|
||||
void RouterTable::UpdateRoutes(const Mle::RouteTlv::Data &aRouteTlvData, uint8_t aNeighborId)
|
||||
{
|
||||
Router *neighbor;
|
||||
Mle::RouterIdMask finitePathCostIds;
|
||||
uint8_t linkCostToNeighbor;
|
||||
Router *neighbor;
|
||||
Mle::RouterIdMask finitePathCostIds;
|
||||
uint8_t linkCostToNeighbor;
|
||||
const Mle::RouteTlv::Data::Entry *matchingEntry;
|
||||
|
||||
neighbor = FindRouterById(aNeighborId);
|
||||
VerifyOrExit(neighbor != nullptr);
|
||||
@@ -600,66 +609,51 @@ void RouterTable::UpdateRoutes(const Mle::RouteTlv &aRouteTlv, uint8_t aNeighbor
|
||||
}
|
||||
|
||||
// Find the entry corresponding to our Router ID in the received
|
||||
// `aRouteTlv` to get the `LinkQualityIn` from the perspective of
|
||||
// neighbor. We use this to update our `LinkQualityOut` to the
|
||||
// `aRouteTlvData` to get the `LinkQualityIn` from the perspective
|
||||
// of neighbor. We use this to update our `LinkQualityOut` to the
|
||||
// neighbor.
|
||||
|
||||
for (uint8_t routerId = 0, index = 0; routerId <= Mle::kMaxRouterId;
|
||||
index += aRouteTlv.IsRouterIdSet(routerId) ? 1 : 0, routerId++)
|
||||
matchingEntry = aRouteTlvData.GetEntries().FindMatching(Mle::RouterIdFromRloc16(Get<Mle::Mle>().GetRloc16()));
|
||||
|
||||
if (matchingEntry != nullptr)
|
||||
{
|
||||
if (!Get<Mle::Mle>().MatchesRouterId(routerId))
|
||||
LinkQuality linkQuality = matchingEntry->GetLinkQualityIn();
|
||||
|
||||
if (neighbor->GetLinkQualityOut() != linkQuality)
|
||||
{
|
||||
continue;
|
||||
neighbor->SetLinkQualityOut(linkQuality);
|
||||
SignalTableChanged(kEventLinkQualityOutChanged);
|
||||
}
|
||||
|
||||
if (aRouteTlv.IsRouterIdSet(routerId))
|
||||
// If the `aRouteTlvData` indicates that the neighboring
|
||||
// router claims to have no link to us (by setting its
|
||||
// `GetLinkQualityOut()` towards us as `kLinkQuality0`),
|
||||
// and we have previously established a link with it, and
|
||||
// our two-way link quality to this router is at least
|
||||
// `kLinkQuality2`, we schedule a unicast Advertisement to
|
||||
// be sent to this neighbor. This helps expedite recovery
|
||||
// from any temporary router link quality mismatch.
|
||||
// Otherwise, the neighboring router will continue to
|
||||
// advertise that it has no link to us until our next
|
||||
// trickle timer-triggered Advertisement transmission
|
||||
// (which can be up to 32 seconds later).
|
||||
|
||||
if (neighbor->IsStateValid() && (matchingEntry->GetLinkQualityOut() == kLinkQuality0) &&
|
||||
(neighbor->GetTwoWayLinkQuality() >= kLinkQuality2))
|
||||
{
|
||||
LinkQuality linkQuality = aRouteTlv.GetLinkQualityIn(index);
|
||||
|
||||
if (neighbor->GetLinkQualityOut() != linkQuality)
|
||||
{
|
||||
neighbor->SetLinkQualityOut(linkQuality);
|
||||
SignalTableChanged(kEventLinkQualityOutChanged);
|
||||
}
|
||||
|
||||
// If the `aRouteTlv` indicates that the neighboring
|
||||
// router claims to have no link to us (by setting its
|
||||
// `GetLinkQualityOut()` towards us as `kLinkQuality0`),
|
||||
// and we have previously established a link with it, and
|
||||
// our two-way link quality to this router is at least
|
||||
// `kLinkQuality2`, we schedule a unicast Advertisement to
|
||||
// be sent to this neighbor. This helps expedite recovery
|
||||
// from any temporary router link quality mismatch.
|
||||
// Otherwise, the neighboring router will continue to
|
||||
// advertise that it has no link to us until our next
|
||||
// trickle timer-triggered Advertisement transmission
|
||||
// (which can be up to 32 seconds later).
|
||||
|
||||
if (neighbor->IsStateValid() && (aRouteTlv.GetLinkQualityOut(index) == kLinkQuality0) &&
|
||||
(neighbor->GetTwoWayLinkQuality() >= kLinkQuality2))
|
||||
{
|
||||
Get<Mle::Mle>().ScheduleUnicastAdvertisementTo(*neighbor);
|
||||
}
|
||||
Get<Mle::Mle>().ScheduleUnicastAdvertisementTo(*neighbor);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
linkCostToNeighbor = GetLinkCost(*neighbor);
|
||||
|
||||
for (uint8_t routerId = 0, index = 0; routerId <= Mle::kMaxRouterId;
|
||||
index += aRouteTlv.IsRouterIdSet(routerId) ? 1 : 0, routerId++)
|
||||
for (const Mle::RouteTlv::Data::Entry &entry : aRouteTlvData.GetEntries())
|
||||
{
|
||||
Router *router;
|
||||
Router *nextHop;
|
||||
uint8_t cost;
|
||||
|
||||
if (!aRouteTlv.IsRouterIdSet(routerId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
router = FindRouterById(routerId);
|
||||
router = FindRouterById(entry.GetRouterId());
|
||||
|
||||
if (router == nullptr || Get<Mle::Mle>().HasRloc16(router->GetRloc16()) || router == neighbor)
|
||||
{
|
||||
@@ -668,7 +662,7 @@ void RouterTable::UpdateRoutes(const Mle::RouteTlv &aRouteTlv, uint8_t aNeighbor
|
||||
|
||||
nextHop = FindNextHopTowards(*router);
|
||||
|
||||
cost = aRouteTlv.GetRouteCost(index);
|
||||
cost = entry.GetRouteCost();
|
||||
cost = (cost == 0) ? Mle::kMaxRouteCost : cost;
|
||||
|
||||
if ((nextHop == nullptr) || (nextHop == neighbor))
|
||||
@@ -718,28 +712,27 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void RouterTable::UpdateRouterOnFtdChild(const Mle::RouteTlv &aRouteTlv, uint8_t aParentId)
|
||||
void RouterTable::UpdateRouterOnFtdChild(const Mle::RouteTlv::Data &aRouteTlvData, uint8_t aParentId)
|
||||
{
|
||||
for (uint8_t routerId = 0, index = 0; routerId <= Mle::kMaxRouterId;
|
||||
index += aRouteTlv.IsRouterIdSet(routerId) ? 1 : 0, routerId++)
|
||||
for (const Mle::RouteTlv::Data::Entry &entry : aRouteTlvData.GetEntries())
|
||||
{
|
||||
Router *router;
|
||||
uint8_t cost;
|
||||
uint8_t nextHopId;
|
||||
|
||||
if (!aRouteTlv.IsRouterIdSet(routerId) || (routerId == aParentId))
|
||||
if (entry.GetRouterId() == aParentId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
router = FindRouterById(routerId);
|
||||
router = FindRouterById(entry.GetRouterId());
|
||||
|
||||
if (router == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
cost = aRouteTlv.GetRouteCost(index);
|
||||
cost = entry.GetRouteCost();
|
||||
nextHopId = (cost == 0) ? Mle::kInvalidRouterId : aParentId;
|
||||
|
||||
if (router->SetNextHopAndCost(nextHopId, cost))
|
||||
|
||||
@@ -312,12 +312,12 @@ public:
|
||||
* Determines whether the Router ID Sequence in a received Route TLV is more recent than the current
|
||||
* Router ID Sequence being used by `RouterTable`.
|
||||
*
|
||||
* @param[in] aRouteTlv The Route TLV to compare.
|
||||
* @param[in] aRouteTlvData The Route TLV Data to compare.
|
||||
*
|
||||
* @retval TRUE The Router ID Sequence in @p aRouteTlv is more recent.
|
||||
* @retval FALSE The Router ID Sequence in @p aRouteTlv is not more recent.
|
||||
* @retval TRUE The Router ID Sequence in @p aRouteTlvData is more recent.
|
||||
* @retval FALSE The Router ID Sequence in @p aRouteTlvData is not more recent.
|
||||
*/
|
||||
bool IsRouteTlvIdSequenceMoreRecent(const Mle::RouteTlv &aRouteTlv) const;
|
||||
bool IsRouteTlvIdSequenceMoreRecent(const Mle::RouteTlv::Data &aRouteTlvData) const;
|
||||
|
||||
/**
|
||||
* Gets the number of router neighbors with `GetLinkQualityIn()` better than or equal to a given threshold.
|
||||
@@ -346,22 +346,29 @@ public:
|
||||
void UpdateRouterIdMask(const Mle::RouterIdMask &aRouterIdMask);
|
||||
|
||||
/**
|
||||
* Updates the routes based on a received `RouteTlv` from a neighboring router.
|
||||
* Updates the allocated Router ID mask from a received `RouteTlv::Data`.
|
||||
*
|
||||
* @param[in] aRouteTlv The received `RouteTlv`
|
||||
* @param[in] aNeighborId The router ID of neighboring router from which @p aRouteTlv is received.
|
||||
* @param[in] aRouteTlvData The received `RouteTlv::Data`.
|
||||
*/
|
||||
void UpdateRoutes(const Mle::RouteTlv &aRouteTlv, uint8_t aNeighborId);
|
||||
void UpdateRouterIdMask(const Mle::RouteTlv::Data &aRouteTlvData);
|
||||
|
||||
/**
|
||||
* Updates the routes on an FTD child based on a received `RouteTlv` from the parent.
|
||||
* Updates the routes based on a received `RouteTlv::Data` from a neighboring router.
|
||||
*
|
||||
* MUST be called when device is an FTD child and @p aRouteTlv is received from its current parent.
|
||||
* @param[in] aRouteTlvData The received `RouteTlv::Data`
|
||||
* @param[in] aNeighborId The router ID of neighboring router from which @p aRouteTlvData is received.
|
||||
*/
|
||||
void UpdateRoutes(const Mle::RouteTlv::Data &aRouteTlvData, uint8_t aNeighborId);
|
||||
|
||||
/**
|
||||
* Updates the routes on an FTD child based on a received `RouteTlv::Data` from the parent.
|
||||
*
|
||||
* @param[in] aRouteTlv The received `RouteTlv` from parent.
|
||||
* MUST be called when device is an FTD child and @p aRouteTlvData is received from its current parent.
|
||||
*
|
||||
* @param[in] aRouteTlvData The received `RouteTlvData` from parent.
|
||||
* @param[in] aParentId The Router ID of parent.
|
||||
*/
|
||||
void UpdateRouterOnFtdChild(const Mle::RouteTlv &aRouteTlv, uint8_t aParentId);
|
||||
void UpdateRouterOnFtdChild(const Mle::RouteTlv::Data &aRouteTlvData, uint8_t aParentId);
|
||||
|
||||
/**
|
||||
* Gets the allocated Router ID Mask.
|
||||
|
||||
@@ -467,15 +467,15 @@ void MeshDiag::HandleTimer(void) { Finalize(kErrorResponseTimeout); }
|
||||
|
||||
Error MeshDiag::RouterInfo::ParseFrom(const Message &aMessage)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
Mle::Mle &mle = aMessage.Get<Mle::Mle>();
|
||||
RouteTlv routeTlv;
|
||||
Error error = kErrorNone;
|
||||
Mle::Mle &mle = aMessage.Get<Mle::Mle>();
|
||||
RouteTlv::Data routeTlvData;
|
||||
|
||||
Clear();
|
||||
|
||||
SuccessOrExit(error = Tlv::Find<Address16Tlv>(aMessage, mRloc16));
|
||||
SuccessOrExit(error = Tlv::Find<ExtMacAddressTlv>(aMessage, AsCoreType(&mExtAddress)));
|
||||
SuccessOrExit(error = Tlv::FindTlv(aMessage, routeTlv));
|
||||
SuccessOrExit(error = RouteTlv::FindIn(aMessage, routeTlvData));
|
||||
|
||||
switch (error = Tlv::Find<VersionTlv>(aMessage, mVersion))
|
||||
{
|
||||
@@ -495,13 +495,9 @@ Error MeshDiag::RouterInfo::ParseFrom(const Message &aMessage)
|
||||
mIsLeader = (mRouterId == mle.GetLeaderId());
|
||||
mIsBorderRouter = aMessage.Get<NetworkData::Leader>().ContainsBorderRouterWithRloc(mRloc16);
|
||||
|
||||
for (uint8_t id = 0, index = 0; id <= Mle::kMaxRouterId; id++)
|
||||
for (const RouteTlv::Data::Entry &entry : routeTlvData.GetEntries())
|
||||
{
|
||||
if (routeTlv.IsRouterIdSet(id))
|
||||
{
|
||||
mLinkQualities[id] = routeTlv.GetLinkQualityIn(index);
|
||||
index++;
|
||||
}
|
||||
mLinkQualities[entry.GetRouterId()] = entry.GetLinkQualityIn();
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
Reference in New Issue
Block a user