[mle] introduce Connectivity and ConnectivityTlvValue types (#12300)

This change separates the Connectivity TLV value format from its
logical structure by introducing `ConnectivityTlvValue` (raw format)
and `Connectivity` (parsed info). This replaces the `ConnectivityTlv`
class and enables value format sharing between MLE and Network
Diagnostics (without improper TLV inheritance).

It also updates `ParentCandidate` to use the new `Connectivity` class
for better field encapsulation. It also updates `ConnectivityTlvValue`
parsing to handle optional fields and enforce spec-defined minimums
for these fields.
This commit is contained in:
Abtin Keshavarzian
2026-01-15 07:43:01 -08:00
committed by GitHub
parent e3b565cc40
commit 0e72f56941
9 changed files with 300 additions and 320 deletions
+40 -34
View File
@@ -3862,12 +3862,11 @@ exit:
Error Mle::TxMessage::AppendConnectivityTlv(void)
{
ConnectivityTlv tlv;
ConnectivityTlvValue tlvValue;
tlv.Init();
Get<Mle>().FillConnectivityTlv(tlv);
Get<Mle>().FillConnectivityTlvValue(tlvValue);
return tlv.AppendTo(*this);
return Tlv::Append<ConnectivityTlv>(*this, &tlvValue, sizeof(tlvValue));
}
Error Mle::TxMessage::AppendAddressRegistrationTlv(Child &aChild)
@@ -4071,6 +4070,20 @@ exit:
return error;
}
Error Mle::RxMessage::ReadConnectivityTlv(Connectivity &aConnectivity) const
{
Error error;
ConnectivityTlvValue tlvValue;
OffsetRange offsetRange;
SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(*this, ConnectivityTlv::kType, offsetRange));
SuccessOrExit(error = tlvValue.ParseFrom(*this, offsetRange));
tlvValue.GetConnectivity(aConnectivity);
exit:
return error;
}
Error Mle::RxMessage::ReadAndSetNetworkDataTlv(const LeaderData &aLeaderData) const
{
Error error;
@@ -5032,7 +5045,7 @@ bool Mle::Attacher::HasMoreChannelsToAnnounce(void) const
bool Mle::Attacher::IsBetterParent(uint16_t aRloc16,
uint8_t aTwoWayLinkMargin,
const ConnectivityTlv &aConnectivityTlv,
const Connectivity &aConnectivity,
uint16_t aVersion,
const Mac::CslAccuracy &aCslAccuracy)
{
@@ -5045,11 +5058,11 @@ bool Mle::Attacher::IsBetterParent(uint16_t aRloc16,
rval = ThreeWayCompare(IsRouterRloc16(aRloc16), IsRouterRloc16(mParentCandidate.GetRloc16()));
VerifyOrExit(rval == 0);
rval = ThreeWayCompare(aConnectivityTlv.GetParentPriority(), mParentCandidate.mPriority);
rval = ThreeWayCompare(aConnectivity.GetParentPriority(), mParentCandidate.mConnectivity.GetParentPriority());
VerifyOrExit(rval == 0);
// Prefer the parent with highest quality links (Link Quality 3 field in Connectivity TLV) to neighbors
rval = ThreeWayCompare(aConnectivityTlv.GetLinkQuality3(), mParentCandidate.mLinkQuality3);
rval = ThreeWayCompare(aConnectivity.GetNumLinkQuality3(), mParentCandidate.mConnectivity.GetNumLinkQuality3());
VerifyOrExit(rval == 0);
// Thread 1.2 Specification 4.5.2.1.2 Child Impacting Criteria
@@ -5057,17 +5070,17 @@ bool Mle::Attacher::IsBetterParent(uint16_t aRloc16,
rval = ThreeWayCompare(aVersion, mParentCandidate.GetVersion());
VerifyOrExit(rval == 0);
rval = ThreeWayCompare(aConnectivityTlv.GetSedBufferSize(), mParentCandidate.mSedBufferSize);
rval = ThreeWayCompare(aConnectivity.GetSedBufferSize(), mParentCandidate.mConnectivity.GetSedBufferSize());
VerifyOrExit(rval == 0);
rval = ThreeWayCompare(aConnectivityTlv.GetSedDatagramCount(), mParentCandidate.mSedDatagramCount);
rval = ThreeWayCompare(aConnectivity.GetSedDatagramCount(), mParentCandidate.mConnectivity.GetSedDatagramCount());
VerifyOrExit(rval == 0);
// Extra rules
rval = ThreeWayCompare(aConnectivityTlv.GetLinkQuality2(), mParentCandidate.mLinkQuality2);
rval = ThreeWayCompare(aConnectivity.GetNumLinkQuality2(), mParentCandidate.mConnectivity.GetNumLinkQuality2());
VerifyOrExit(rval == 0);
rval = ThreeWayCompare(aConnectivityTlv.GetLinkQuality1(), mParentCandidate.mLinkQuality1);
rval = ThreeWayCompare(aConnectivity.GetNumLinkQuality1(), mParentCandidate.mConnectivity.GetNumLinkQuality1());
VerifyOrExit(rval == 0);
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
@@ -5100,7 +5113,7 @@ void Mle::Attacher::HandleParentResponse(RxInfo &aRxInfo)
LeaderData leaderData;
uint8_t linkMarginOut;
uint8_t twoWayLinkMargin;
ConnectivityTlv connectivityTlv;
Connectivity connectivity;
uint32_t linkFrameCounter;
uint32_t mleFrameCounter;
Mac::ExtAddress extAddress;
@@ -5131,8 +5144,7 @@ void Mle::Attacher::HandleParentResponse(RxInfo &aRxInfo)
SuccessOrExit(error = Tlv::Find<LinkMarginTlv>(aRxInfo.mMessage, linkMarginOut));
twoWayLinkMargin = Min(Get<Mac::Mac>().ComputeLinkMargin(rss), linkMarginOut);
SuccessOrExit(error = Tlv::FindTlv(aRxInfo.mMessage, connectivityTlv));
VerifyOrExit(connectivityTlv.IsValid(), error = kErrorParse);
SuccessOrExit(error = aRxInfo.mMessage.ReadConnectivityTlv(connectivity));
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
switch (aRxInfo.mMessage.ReadCslClockAccuracyTlv(cslAccuracy))
@@ -5157,10 +5169,10 @@ void Mle::Attacher::HandleParentResponse(RxInfo &aRxInfo)
parentinfo.mExtAddr = extAddress;
parentinfo.mRloc16 = sourceAddress;
parentinfo.mRssi = rss;
parentinfo.mPriority = connectivityTlv.GetParentPriority();
parentinfo.mLinkQuality3 = connectivityTlv.GetLinkQuality3();
parentinfo.mLinkQuality2 = connectivityTlv.GetLinkQuality2();
parentinfo.mLinkQuality1 = connectivityTlv.GetLinkQuality1();
parentinfo.mPriority = connectivity.GetParentPriority();
parentinfo.mLinkQuality3 = connectivity.GetNumLinkQuality3();
parentinfo.mLinkQuality2 = connectivity.GetNumLinkQuality2();
parentinfo.mLinkQuality1 = connectivity.GetNumLinkQuality1();
parentinfo.mIsAttached = Get<Mle>().IsAttached();
mParentResponseCallback.Invoke(&parentinfo);
@@ -5173,9 +5185,9 @@ void Mle::Attacher::HandleParentResponse(RxInfo &aRxInfo)
if (Get<Mle>().IsFullThreadDevice() && !Get<Mle>().IsDetached())
{
bool isPartitionIdSame = (leaderData.GetPartitionId() == Get<Mle>().mLeaderData.GetPartitionId());
bool isIdSequenceSame = (connectivityTlv.GetIdSequence() == Get<RouterTable>().GetRouterIdSequence());
bool isIdSequenceSame = (connectivity.GetIdSequence() == Get<RouterTable>().GetRouterIdSequence());
bool isIdSequenceGreater =
SerialNumber::IsGreater(connectivityTlv.GetIdSequence(), Get<RouterTable>().GetRouterIdSequence());
SerialNumber::IsGreater(connectivity.GetIdSequence(), Get<RouterTable>().GetRouterIdSequence());
switch (mMode)
{
@@ -5194,7 +5206,7 @@ void Mle::Attacher::HandleParentResponse(RxInfo &aRxInfo)
case kBetterPartition:
VerifyOrExit(!isPartitionIdSame);
VerifyOrExit(ComparePartitions(connectivityTlv.IsSingleton(), leaderData, Get<Mle>().IsSingleton(),
VerifyOrExit(ComparePartitions(connectivity.IsSingleton(), leaderData, Get<Mle>().IsSingleton(),
Get<Mle>().mLeaderData) > 0);
break;
@@ -5217,8 +5229,8 @@ void Mle::Attacher::HandleParentResponse(RxInfo &aRxInfo)
#if OPENTHREAD_FTD
if (Get<Mle>().IsFullThreadDevice())
{
compare = ComparePartitions(connectivityTlv.IsSingleton(), leaderData, mParentCandidate.mIsSingleton,
mParentCandidate.mLeaderData);
compare = ComparePartitions(connectivity.IsSingleton(), leaderData,
mParentCandidate.mConnectivity.IsSingleton(), mParentCandidate.mLeaderData);
}
// Only consider partitions that are the same or better
@@ -5228,7 +5240,7 @@ void Mle::Attacher::HandleParentResponse(RxInfo &aRxInfo)
// Only consider better parents if the partitions are the same
if (compare == 0)
{
VerifyOrExit(IsBetterParent(sourceAddress, twoWayLinkMargin, connectivityTlv, version, cslAccuracy));
VerifyOrExit(IsBetterParent(sourceAddress, twoWayLinkMargin, connectivity, version, cslAccuracy));
}
}
@@ -5267,20 +5279,14 @@ void Mle::Attacher::HandleParentResponse(RxInfo &aRxInfo)
mParentCandidate.SetLinkQualityOut(LinkQualityForLinkMargin(linkMarginOut));
mParentCandidate.SetState(Neighbor::kStateParentResponse);
mParentCandidate.SetKeySequence(aRxInfo.mKeySequence);
mParentCandidate.SetLeaderCost(connectivityTlv.GetLeaderCost());
mParentCandidate.SetLeaderCost(connectivity.GetLeaderCost());
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
mParentCandidate.SetCslAccuracy(cslAccuracy);
#endif
mParentCandidate.mPriority = connectivityTlv.GetParentPriority();
mParentCandidate.mLinkQuality3 = connectivityTlv.GetLinkQuality3();
mParentCandidate.mLinkQuality2 = connectivityTlv.GetLinkQuality2();
mParentCandidate.mLinkQuality1 = connectivityTlv.GetLinkQuality1();
mParentCandidate.mSedBufferSize = connectivityTlv.GetSedBufferSize();
mParentCandidate.mSedDatagramCount = connectivityTlv.GetSedDatagramCount();
mParentCandidate.mLeaderData = leaderData;
mParentCandidate.mIsSingleton = connectivityTlv.IsSingleton();
mParentCandidate.mLinkMargin = twoWayLinkMargin;
mParentCandidate.mConnectivity = connectivity;
mParentCandidate.mLeaderData = leaderData;
mParentCandidate.mLinkMargin = twoWayLinkMargin;
exit:
LogProcessError(kTypeParentResponse, error);
+10 -14
View File
@@ -1033,11 +1033,11 @@ public:
const LeaderData &aLeaderDataB);
/**
* Fills an ConnectivityTlv.
* Fills a `ConnectivityTlvValue`.
*
* @param[out] aTlv A reference to the tlv to be filled.
* @param[out] aTlvValue A reference to a `ConnectivityTlvValue` be filled.
*/
void FillConnectivityTlv(ConnectivityTlv &aTlv);
void FillConnectivityTlvValue(ConnectivityTlvValue &aTlvValue) const;
/**
* Schedule tx of MLE Advertisement message (unicast) to the given neighboring router after a random delay.
@@ -1598,6 +1598,7 @@ private:
Error ReadFrameCounterTlvs(uint32_t &aLinkFrameCounter, uint32_t &aMleFrameCounter) const;
Error ReadTlvRequestTlv(TlvList &aTlvList) const;
Error ReadLeaderDataTlv(LeaderData &aLeaderData) const;
Error ReadConnectivityTlv(Connectivity &aConnectivity) const;
Error ReadAndSetNetworkDataTlv(const LeaderData &aLeaderData) const;
Error ReadAndSaveActiveDataset(const MeshCoP::Timestamp &aActiveTimestamp) const;
Error ReadAndSavePendingDataset(const MeshCoP::Timestamp &aPendingTimestamp) const;
@@ -1795,16 +1796,10 @@ private:
void Clear(void);
void CopyTo(Parent &aParent) const;
RxChallenge mRxChallenge;
int8_t mPriority;
uint8_t mLinkQuality3;
uint8_t mLinkQuality2;
uint8_t mLinkQuality1;
uint16_t mSedBufferSize;
uint8_t mSedDatagramCount;
uint8_t mLinkMargin;
LeaderData mLeaderData;
bool mIsSingleton;
RxChallenge mRxChallenge;
Connectivity mConnectivity;
uint8_t mLinkMargin;
LeaderData mLeaderData;
};
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -1925,7 +1920,7 @@ private:
bool PrepareAnnounceState(void);
bool IsBetterParent(uint16_t aRloc16,
uint8_t aTwoWayLinkMargin,
const ConnectivityTlv &aConnectivityTlv,
const Connectivity &aConnectivity,
uint16_t aVersion,
const Mac::CslAccuracy &aCslAccuracy);
@@ -2364,6 +2359,7 @@ private:
void ClearAlternateRloc16(void);
uint8_t SelectLeaderId(void) const;
uint32_t SelectPartitionId(void) const;
void DetermineConnectivity(Connectivity &aConnectivity) const;
void HandleDetachStart(void);
void HandleChildStart(void);
void HandleSecurityPolicyChanged(void);
+22 -22
View File
@@ -3660,38 +3660,30 @@ exit:
return;
}
void Mle::FillConnectivityTlv(ConnectivityTlv &aTlv)
void Mle::DetermineConnectivity(Connectivity &aConnectivity) const
{
int8_t parentPriority = kParentPriorityMedium;
aConnectivity.Clear();
if (mParentPriority != kParentPriorityUnspecified)
{
parentPriority = mParentPriority;
}
else
aConnectivity.mParentPriority = GetAssignParentPriority();
if (aConnectivity.mParentPriority == kParentPriorityUnspecified)
{
uint16_t numChildren = mChildTable.GetNumChildren(Child::kInStateValid);
uint16_t maxAllowed = mChildTable.GetMaxChildrenAllowed();
if ((maxAllowed - numChildren) < (maxAllowed / 3))
{
parentPriority = kParentPriorityLow;
aConnectivity.mParentPriority = kParentPriorityLow;
}
else
{
parentPriority = kParentPriorityMedium;
aConnectivity.mParentPriority = kParentPriorityMedium;
}
}
aTlv.SetParentPriority(parentPriority);
aTlv.SetLinkQuality1(0);
aTlv.SetLinkQuality2(0);
aTlv.SetLinkQuality3(0);
if (IsChild())
{
aTlv.IncrementLinkQuality(mParent.GetLinkQualityIn());
aConnectivity.IncrementNumForLinkQuality(mParent.GetLinkQualityIn());
}
for (const Router &router : Get<RouterTable>())
@@ -3706,14 +3698,22 @@ void Mle::FillConnectivityTlv(ConnectivityTlv &aTlv)
continue;
}
aTlv.IncrementLinkQuality(router.GetTwoWayLinkQuality());
aConnectivity.IncrementNumForLinkQuality(router.GetTwoWayLinkQuality());
}
aTlv.SetActiveRouters(mRouterTable.GetActiveRouterCount());
aTlv.SetLeaderCost(Min(mRouterTable.GetPathCostToLeader(), kMaxRouteCost));
aTlv.SetIdSequence(mRouterTable.GetRouterIdSequence());
aTlv.SetSedBufferSize(OPENTHREAD_CONFIG_DEFAULT_SED_BUFFER_SIZE);
aTlv.SetSedDatagramCount(OPENTHREAD_CONFIG_DEFAULT_SED_DATAGRAM_COUNT);
aConnectivity.mLeaderCost = Min(mRouterTable.GetPathCostToLeader(), kMaxRouteCost);
aConnectivity.mIdSequence = mRouterTable.GetRouterIdSequence();
aConnectivity.mActiveRouters = mRouterTable.GetActiveRouterCount();
aConnectivity.mSedBufferSize = Connectivity::kDefaultSedBufferSize;
aConnectivity.mSedDatagramCount = Connectivity::kDefaultSedDatagramCount;
}
void Mle::FillConnectivityTlvValue(ConnectivityTlvValue &aTlvValue) const
{
Connectivity connectivity;
DetermineConnectivity(connectivity);
aTlvValue.InitFrom(connectivity);
}
bool Mle::ShouldDowngrade(uint8_t aNeighborId, const RouteTlv &aRouteTlv) const
+63 -22
View File
@@ -41,6 +41,9 @@
namespace ot {
namespace Mle {
//---------------------------------------------------------------------------------------------------------------------
// RouteTlv
#if !OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
void RouteTlv::Init(void)
@@ -69,33 +72,68 @@ exit:
#endif // #if !OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
void ConnectivityTlv::IncrementLinkQuality(LinkQuality aLinkQuality)
//---------------------------------------------------------------------------------------------------------------------
// ConnectivityTlvValue
void ConnectivityTlvValue::InitFrom(const Connectivity &aConnectivity)
{
switch (aLinkQuality)
mFlags = 0;
WriteBits<uint8_t, kFlagsParentPriorityMask>(mFlags, Preference::To2BitUint(aConnectivity.GetParentPriority()));
mLinkQuality3 = aConnectivity.GetNumLinkQuality3();
mLinkQuality2 = aConnectivity.GetNumLinkQuality2();
mLinkQuality1 = aConnectivity.GetNumLinkQuality1();
mLeaderCost = aConnectivity.GetLeaderCost();
mIdSequence = aConnectivity.GetIdSequence();
mActiveRouters = aConnectivity.GetActiveRouterCount();
mSedBufferSize = BigEndian::HostSwap16(aConnectivity.GetSedBufferSize());
mSedDatagramCount = aConnectivity.GetSedDatagramCount();
}
void ConnectivityTlvValue::GetConnectivity(Connectivity &aConnectivity) const
{
aConnectivity.Clear();
aConnectivity.mParentPriority = Preference::From2BitUint(ReadBits<uint8_t, kFlagsParentPriorityMask>(mFlags));
aConnectivity.mLinkQuality3 = mLinkQuality3;
aConnectivity.mLinkQuality2 = mLinkQuality2;
aConnectivity.mLinkQuality1 = mLinkQuality1;
aConnectivity.mLeaderCost = mLeaderCost;
aConnectivity.mIdSequence = mIdSequence;
aConnectivity.mActiveRouters = mActiveRouters;
aConnectivity.mSedBufferSize = BigEndian::HostSwap16(mSedBufferSize);
aConnectivity.mSedDatagramCount = mSedDatagramCount;
}
Error ConnectivityTlvValue::ParseFrom(const Message &aMessage, const OffsetRange &aOffsetRange)
{
Error error = kErrorNone;
uint16_t size = aOffsetRange.GetLength();
// The `mSedBufferSize` and `mSedDatagramCount` fields are
// optional and are included as a pair. If the received TLV size
// indicates they are not present, we read the partial TLV value
// and then set the fields to their default minimum values.
// Otherwise, we read the full structure.
if (size == kMinSize)
{
case kLinkQuality0:
break;
case kLinkQuality1:
mLinkQuality1++;
break;
case kLinkQuality2:
mLinkQuality2++;
break;
case kLinkQuality3:
mLinkQuality3++;
break;
SuccessOrExit(error = aMessage.Read(aOffsetRange, this, size));
mSedBufferSize = BigEndian::HostSwap16(kMinSedBufferSize);
mSedDatagramCount = kMinSedDatagramCount;
}
else
{
SuccessOrExit(error = aMessage.Read(aOffsetRange, *this));
}
exit:
return error;
}
int8_t ConnectivityTlv::GetParentPriority(void) const
{
return Preference::From2BitUint(mFlags >> kFlagsParentPriorityOffset);
}
void ConnectivityTlv::SetParentPriority(int8_t aParentPriority)
{
mFlags = static_cast<uint8_t>(Preference::To2BitUint(aParentPriority) << kFlagsParentPriorityOffset);
}
//---------------------------------------------------------------------------------------------------------------------
// ChannelTlvValue
void ChannelTlvValue::SetChannelAndPage(uint16_t aChannel)
{
@@ -137,6 +175,9 @@ exit:
return isValid;
}
//---------------------------------------------------------------------------------------------------------------------
// LeaderDataTlvValue
LeaderDataTlvValue::LeaderDataTlvValue(const LeaderData &aLeaderData)
: mPartitionId(BigEndian::HostSwap32(aLeaderData.GetPartitionId()))
, mWeighting(aLeaderData.GetWeighting())
+35 -182
View File
@@ -653,207 +653,55 @@ public:
};
/**
* Implements Connectivity TLV generation and parsing.
* Represents a Connectivity TLV value.
*/
OT_TOOL_PACKED_BEGIN
class ConnectivityTlv : public Tlv, public TlvInfo<Tlv::kConnectivity>
class ConnectivityTlvValue
{
public:
/**
* Initializes the TLV.
* Initializes the Connectivity TLV value from a given `Connectivity` object.
*
* @param[in] aConnectivity The `Connectivity` to use for initialization.
*/
void Init(void)
{
SetType(kConnectivity);
SetLength(sizeof(*this) - sizeof(Tlv));
}
void InitFrom(const Connectivity &aConnectivity);
/**
* Indicates whether or not the TLV appears to be well-formed.
* Gets the connectivity information from the TLV value.
*
* @retval TRUE If the TLV appears to be well-formed.
* @retval FALSE If the TLV does not appear to be well-formed.
* @param[out] aConnectivity A reference to a `Connectivity` object to output the information.
*/
bool IsValid(void) const
{
return IsSedBufferingIncluded() ||
(GetLength() == sizeof(*this) - sizeof(Tlv) - sizeof(mSedBufferSize) - sizeof(mSedDatagramCount));
}
void GetConnectivity(Connectivity &aConnectivity) const;
/**
* Indicates whether or not the sed buffer size and datagram count are included.
* Parses a Connectivity TLV value from a given message.
*
* @retval TRUE If the sed buffer size and datagram count are included.
* @retval FALSE If the sed buffer size and datagram count are not included.
* The SED Buffer Size and Datagram Count fields are optional in the Connectivity TLV. If not present in the
* message, this method populates them with their default minimum values defined by Thread specification.
*
* @param[in] aMessage The message to parse from.
* @param[in] aOffsetRange The offset range within the message containing the TLV value.
*
* @retval kErrorNone Successfully parsed the TLV value.
* @retval kErrorParse Failed to parse the TLV value from the message.
*/
bool IsSedBufferingIncluded(void) const { return GetLength() >= sizeof(*this) - sizeof(Tlv); }
/**
* Returns the Parent Priority value.
*
* @returns The Parent Priority value.
*/
int8_t GetParentPriority(void) const;
/**
* Sets the Parent Priority value.
*
* @param[in] aParentPriority The Parent Priority value.
*/
void SetParentPriority(int8_t aParentPriority);
/**
* Returns the Link Quality 3 value.
*
* @returns The Link Quality 3 value.
*/
uint8_t GetLinkQuality3(void) const { return mLinkQuality3; }
/**
* Sets the Link Quality 3 value.
*
* @param[in] aLinkQuality The Link Quality 3 value.
*/
void SetLinkQuality3(uint8_t aLinkQuality) { mLinkQuality3 = aLinkQuality; }
/**
* Returns the Link Quality 2 value.
*
* @returns The Link Quality 2 value.
*/
uint8_t GetLinkQuality2(void) const { return mLinkQuality2; }
/**
* Sets the Link Quality 2 value.
*
* @param[in] aLinkQuality The Link Quality 2 value.
*/
void SetLinkQuality2(uint8_t aLinkQuality) { mLinkQuality2 = aLinkQuality; }
/**
* Sets the Link Quality 1 value.
*
* @returns The Link Quality 1 value.
*/
uint8_t GetLinkQuality1(void) const { return mLinkQuality1; }
/**
* Sets the Link Quality 1 value.
*
* @param[in] aLinkQuality The Link Quality 1 value.
*/
void SetLinkQuality1(uint8_t aLinkQuality) { mLinkQuality1 = aLinkQuality; }
/**
* Increments the Link Quality N field in TLV for a given Link Quality N (1,2,3).
*
* The Link Quality N field specifies the number of neighboring router devices with which the sender shares a link
* of quality N.
*
* @param[in] aLinkQuality The Link Quality N (1,2,3) field to update.
*/
void IncrementLinkQuality(LinkQuality aLinkQuality);
/**
* Sets the Active Routers value.
*
* @returns The Active Routers value.
*/
uint8_t GetActiveRouters(void) const { return mActiveRouters; }
/**
* Indicates whether or not the partition is a singleton based on Active Routers value.
*
* @retval TRUE The partition is a singleton.
* @retval FALSE The partition is not a singleton.
*/
bool IsSingleton(void) const { return (mActiveRouters <= 1); }
/**
* Sets the Active Routers value.
*
* @param[in] aActiveRouters The Active Routers value.
*/
void SetActiveRouters(uint8_t aActiveRouters) { mActiveRouters = aActiveRouters; }
/**
* Returns the Leader Cost value.
*
* @returns The Leader Cost value.
*/
uint8_t GetLeaderCost(void) const { return mLeaderCost; }
/**
* Sets the Leader Cost value.
*
* @param[in] aCost The Leader Cost value.
*/
void SetLeaderCost(uint8_t aCost) { mLeaderCost = aCost; }
/**
* Returns the ID Sequence value.
*
* @returns The ID Sequence value.
*/
uint8_t GetIdSequence(void) const { return mIdSequence; }
/**
* Sets the ID Sequence value.
*
* @param[in] aSequence The ID Sequence value.
*/
void SetIdSequence(uint8_t aSequence) { mIdSequence = aSequence; }
/**
* Returns the SED Buffer Size value.
*
* @returns The SED Buffer Size value.
*/
uint16_t GetSedBufferSize(void) const
{
uint16_t buffersize = OPENTHREAD_CONFIG_DEFAULT_SED_BUFFER_SIZE;
if (IsSedBufferingIncluded())
{
buffersize = BigEndian::HostSwap16(mSedBufferSize);
}
return buffersize;
}
/**
* Sets the SED Buffer Size value.
*
* @param[in] aSedBufferSize The SED Buffer Size value.
*/
void SetSedBufferSize(uint16_t aSedBufferSize) { mSedBufferSize = BigEndian::HostSwap16(aSedBufferSize); }
/**
* Returns the SED Datagram Count value.
*
* @returns The SED Datagram Count value.
*/
uint8_t GetSedDatagramCount(void) const
{
uint8_t count = OPENTHREAD_CONFIG_DEFAULT_SED_DATAGRAM_COUNT;
if (IsSedBufferingIncluded())
{
count = mSedDatagramCount;
}
return count;
}
/**
* Sets the SED Datagram Count value.
*
* @param[in] aSedDatagramCount The SED Datagram Count value.
*/
void SetSedDatagramCount(uint8_t aSedDatagramCount) { mSedDatagramCount = aSedDatagramCount; }
Error ParseFrom(const Message &aMessage, const OffsetRange &aOffsetRange);
private:
static constexpr uint8_t kFlagsParentPriorityOffset = 6;
static constexpr uint8_t kFlagsParentPriorityMask = (3 << kFlagsParentPriorityOffset);
static constexpr uint8_t kMinSize = 7; // Exclude the optional `mSedBufferSize` and `mSedDatagramCount`.
// The default minimum values to use when the optional fields
// `mSedBufferSize`, `mSedDatagramCount` are not included. These
// numbers are from Thread Conformance Specification 1.4.1-dr3:
// "A Thread Router MUST be able to buffer at least one 1280-octet
// IPv6 datagram destined for an attached SED".
static constexpr uint16_t kMinSedBufferSize = 1280;
static constexpr uint8_t kMinSedDatagramCount = 1;
uint8_t mFlags;
uint8_t mLinkQuality3;
uint8_t mLinkQuality2;
@@ -865,6 +713,11 @@ private:
uint8_t mSedDatagramCount;
} OT_TOOL_PACKED_END;
/**
* Defines Connectivity TLV constants.
*/
typedef TlvInfo<Tlv::kConnectivity> ConnectivityTlv;
/**
* Provides constants and methods for generation and parsing of Address Registration TLV.
*/
+21
View File
@@ -190,6 +190,27 @@ bool RxChallenge::operator==(const TxChallenge &aTxChallenge) const
return (mArray.GetLength() == kMaxSize) && (memcmp(mArray.GetArrayBuffer(), aTxChallenge.m8, kMaxSize) == 0);
}
//---------------------------------------------------------------------------------------------------------------------
// Connectivity
void Connectivity::IncrementNumForLinkQuality(uint8_t aLinkQuality)
{
switch (aLinkQuality)
{
case kLinkQuality1:
mLinkQuality1++;
break;
case kLinkQuality2:
mLinkQuality2++;
break;
case kLinkQuality3:
mLinkQuality3++;
break;
default:
break;
}
}
//---------------------------------------------------------------------------------------------------------------------
const char *RoleToString(DeviceRole aRole)
+89 -2
View File
@@ -42,10 +42,9 @@
#if OPENTHREAD_CONFIG_P2P_ENABLE
#include <openthread/provisional/p2p.h>
#endif
#include <openthread/netdiag.h>
#include <openthread/thread.h>
#if OPENTHREAD_FTD
#include <openthread/thread_ftd.h>
#endif
#include "common/array.hpp"
#include "common/as_core_type.hpp"
@@ -68,6 +67,8 @@ class Message;
namespace Mle {
class Mle;
/**
* @addtogroup core-mle-core
*
@@ -746,6 +747,92 @@ private:
uint8_t m8[RxChallenge::kMaxSize];
};
/**
* Represents device connectivity info from Connectivity TLV.
*/
class Connectivity : public otNetworkDiagConnectivity, public Clearable<Connectivity>
{
friend class Mle;
public:
/**
* Returns the Parent Priority value.
*
* @returns The Parent Priority value.
*/
int8_t GetParentPriority(void) const { return mParentPriority; }
/**
* Returns the number of neighbors with link quality 3.
*
* @returns The number of neighbors with link quality 3.
*/
uint8_t GetNumLinkQuality3(void) const { return mLinkQuality3; }
/**
* Returns the number of neighbors with link quality 2.
*
* @returns The number of neighbors with link quality 2.
*/
uint8_t GetNumLinkQuality2(void) const { return mLinkQuality2; }
/**
* Returns the number of neighbors with link quality 1.
*
* @returns The number of neighbors with link quality 1.
*/
uint8_t GetNumLinkQuality1(void) const { return mLinkQuality1; }
/**
* Returns the Leader Cost value.
*
* @returns The Leader Cost value.
*/
uint8_t GetLeaderCost(void) const { return mLeaderCost; }
/**
* Returns the Router ID Sequence value.
*
* @returns The Router ID Sequence value.
*/
uint8_t GetIdSequence(void) const { return mIdSequence; }
/**
* Returns the Active Routers value.
*
* @returns The Active Routers value.
*/
uint8_t GetActiveRouterCount(void) const { return mActiveRouters; }
/**
* Indicates whether or not the partition is a singleton based on Active Router Count.
*
* @retval TRUE The partition is a singleton.
* @retval FALSE The partition is not a singleton.
*/
bool IsSingleton(void) const { return (mActiveRouters <= 1); }
/**
* Returns the SED Buffer Size value.
*
* @returns The SED Buffer Size value.
*/
uint16_t GetSedBufferSize(void) const { return mSedBufferSize; }
/**
* Returns the SED Datagram Count value.
*
* @returns The SED Datagram Count value.
*/
uint8_t GetSedDatagramCount(void) const { return mSedDatagramCount; }
private:
static constexpr uint16_t kDefaultSedBufferSize = OPENTHREAD_CONFIG_DEFAULT_SED_BUFFER_SIZE;
static constexpr uint8_t kDefaultSedDatagramCount = OPENTHREAD_CONFIG_DEFAULT_SED_DATAGRAM_COUNT;
void IncrementNumForLinkQuality(uint8_t aLinkQuality);
};
/**
* Represents a MLE Key Material
*/
+6 -9
View File
@@ -549,11 +549,10 @@ Error Server::AppendDiagTlv(uint8_t aTlvType, Message &aMessage)
case Tlv::kConnectivity:
{
ConnectivityTlv tlv;
ConnectivityTlvValue tlvValue;
tlv.Init();
Get<Mle::Mle>().FillConnectivityTlv(tlv);
error = tlv.AppendTo(aMessage);
Get<Mle::Mle>().FillConnectivityTlvValue(tlvValue);
error = Tlv::Append<ConnectivityTlv>(aMessage, &tlvValue, sizeof(tlvValue));
break;
}
@@ -1298,12 +1297,10 @@ Error Client::GetNextDiagTlv(const Coap::Message &aMessage, Iterator &aIterator,
case Tlv::kConnectivity:
{
ConnectivityTlv connectivityTlv;
ConnectivityTlvValue tlvValue;
VerifyOrExit(!tlvInfo.mIsExtended, error = kErrorParse);
SuccessOrExit(error = aMessage.Read(offset, connectivityTlv));
VerifyOrExit(connectivityTlv.IsValid(), error = kErrorParse);
connectivityTlv.GetConnectivity(aDiagTlv.mData.mConnectivity);
SuccessOrExit(error = tlvValue.ParseFrom(aMessage, tlvInfo.mValueOffsetRange));
tlvValue.GetConnectivity(AsCoreType(&aDiagTlv.mData.mConnectivity));
break;
}
+14 -35
View File
@@ -39,6 +39,7 @@
#include <openthread/netdiag.h>
#include <openthread/thread.h>
#include "common/as_core_type.hpp"
#include "common/clearable.hpp"
#include "common/encoding.hpp"
#include "common/message.hpp"
@@ -276,45 +277,20 @@ typedef SimpleTlvInfo<Tlv::kBrLocalOnlinkPrefix, Ip6::NetworkPrefix> BrLocalOnli
*/
typedef SimpleTlvInfo<Tlv::kBrFavoredOnLinkPrefix, Ip6::NetworkPrefix> BrFavoredOnLinkPrefixTlv;
typedef otNetworkDiagConnectivity Connectivity; ///< Network Diagnostic Connectivity value.
/**
* Represents information parsed from Connectivity TLV.
*/
typedef Mle::Connectivity Connectivity;
/**
* Implements Connectivity TLV generation and parsing.
* Represents a Connectivity TLV value.
*/
OT_TOOL_PACKED_BEGIN
class ConnectivityTlv : public Mle::ConnectivityTlv
{
public:
static constexpr uint8_t kType = ot::NetworkDiagnostic::Tlv::kConnectivity; ///< The TLV Type value.
typedef Mle::ConnectivityTlvValue ConnectivityTlvValue;
/**
* Initializes the TLV.
*/
void Init(void)
{
Mle::ConnectivityTlv::Init();
ot::Tlv::SetType(kType);
}
/**
* Retrieves the `Connectivity` value.
*
* @param[out] aConnectivity A reference to `Connectivity` to populate.
*/
void GetConnectivity(Connectivity &aConnectivity) const
{
aConnectivity.mParentPriority = GetParentPriority();
aConnectivity.mLinkQuality3 = GetLinkQuality3();
aConnectivity.mLinkQuality2 = GetLinkQuality2();
aConnectivity.mLinkQuality1 = GetLinkQuality1();
aConnectivity.mLeaderCost = GetLeaderCost();
aConnectivity.mIdSequence = GetIdSequence();
aConnectivity.mActiveRouters = GetActiveRouters();
aConnectivity.mSedBufferSize = GetSedBufferSize();
aConnectivity.mSedDatagramCount = GetSedDatagramCount();
}
} OT_TOOL_PACKED_END;
/**
* Defines Connectivity TLV constants.
*/
typedef TlvInfo<Tlv::kConnectivity> ConnectivityTlv;
/**
* Implements Route TLV generation and parsing.
@@ -1126,6 +1102,9 @@ private:
} OT_TOOL_PACKED_END;
} // namespace NetworkDiagnostic
DefineCoreType(otNetworkDiagConnectivity, NetworkDiagnostic::Connectivity);
} // namespace ot
#endif // OT_CORE_THREAD_NETWORK_DIAGNOSTIC_TLVS_HPP_