mirror of
https://github.com/espressif/openthread.git
synced 2026-09-10 11:10:08 +00:00
[network-diag] simplify ChildTableTlv generation and parsing (#12712)
This commit updates `ChildTableTlvEntry` to better support the packing and parsing of child entries in a `ChildTableTlv`. It introduces an `InitFrom()` method to encode an entry directly from a `Child` object, and a `Parse()` method to extract values into a `ParseInfo` struct, improving modularity and simplifying usage. Additionally, it consolidates the logic for calculating the timeout exponent and decoding it back to a timeout value directly within the `ChildTableTlvEntry` class. It also introduces `ParseChildTable()` in `NetworkDiagnostic::Client` to clean up the child table parsing loop.
This commit is contained in:
@@ -82,24 +82,14 @@ Error Server::AppendChildTable(Message &aMessage)
|
||||
|
||||
for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
|
||||
{
|
||||
uint8_t timeout = 0;
|
||||
ChildTableEntry entry;
|
||||
ChildTableTlvEntry entry;
|
||||
|
||||
if (++count > kMaxChildEntries)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
while (static_cast<uint32_t>(1 << timeout) < child.GetTimeout())
|
||||
{
|
||||
timeout++;
|
||||
}
|
||||
|
||||
entry.Clear();
|
||||
entry.SetTimeout(timeout + 4);
|
||||
entry.SetLinkQuality(child.GetLinkQualityIn());
|
||||
entry.SetChildId(Mle::ChildIdFromRloc16(child.GetRloc16()));
|
||||
entry.SetMode(child.GetDeviceMode());
|
||||
entry.InitFrom(child);
|
||||
|
||||
SuccessOrExit(error = aMessage.Append(entry));
|
||||
SuccessOrExit(error = Tlv::AdjustTlv(aMessage, tlvBookmark));
|
||||
@@ -1149,6 +1139,31 @@ void Client::ReadDiagData(DiagData &aDiagData, const Message &aMessage, const Tl
|
||||
aDiagData.mCount = static_cast<uint8_t>(aMessage.ReadBytes(offsetRange, aDiagData.m8));
|
||||
}
|
||||
|
||||
Error Client::ParseChildTable(ChildTable &aChildTable, const Message &aMessage, OffsetRange aOffsetRange)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
// `ChildTable` has a fixed array of Child Table entries. If there
|
||||
// are more entries in the message, we read and return as many as
|
||||
// can fit in array and ignore the rest.
|
||||
|
||||
aChildTable.mCount = 0;
|
||||
|
||||
while (!aOffsetRange.IsEmpty() && (aChildTable.mCount < GetArrayLength(aChildTable.mTable)))
|
||||
{
|
||||
ChildTableTlvEntry entry;
|
||||
|
||||
SuccessOrExit(error = aMessage.Read(aOffsetRange, entry));
|
||||
aOffsetRange.AdvanceOffset(sizeof(ChildTableTlvEntry));
|
||||
|
||||
entry.Parse(aChildTable.mTable[aChildTable.mCount]);
|
||||
aChildTable.mCount++;
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Client::ParseIp6AddrList(Ip6AddrList &aIp6Addrs, const Message &aMessage, OffsetRange aOffsetRange)
|
||||
{
|
||||
aIp6Addrs.mCount = 0;
|
||||
@@ -1272,39 +1287,8 @@ Error Client::GetNextDiagTlv(const Coap::Message &aMessage, Iterator &aIterator,
|
||||
break;
|
||||
|
||||
case Tlv::kChildTable:
|
||||
{
|
||||
uint16_t childInfoLength = GetArrayLength(aDiagTlv.mData.mChildTable.mTable);
|
||||
ChildInfo *childInfo = &aDiagTlv.mData.mChildTable.mTable[0];
|
||||
uint8_t &childCount = aDiagTlv.mData.mChildTable.mCount;
|
||||
OffsetRange offsetRange;
|
||||
|
||||
VerifyOrExit((tlvInfo.GetLength() % sizeof(ChildTableEntry)) == 0, error = kErrorParse);
|
||||
|
||||
// `DiagTlv` has a fixed array Child Table entries. If there
|
||||
// are more entries in the message, we read and return as
|
||||
// many as can fit in array and ignore the rest.
|
||||
|
||||
childCount = 0;
|
||||
offsetRange = tlvInfo.GetValueOffsetRange();
|
||||
|
||||
while (!offsetRange.IsEmpty() && (childCount < childInfoLength))
|
||||
{
|
||||
ChildTableEntry entry;
|
||||
|
||||
SuccessOrExit(error = aMessage.Read(offsetRange, entry));
|
||||
|
||||
childInfo->mTimeout = entry.GetTimeout();
|
||||
childInfo->mLinkQuality = entry.GetLinkQuality();
|
||||
childInfo->mChildId = entry.GetChildId();
|
||||
entry.GetMode().Get(childInfo->mMode);
|
||||
|
||||
childCount++;
|
||||
childInfo++;
|
||||
offsetRange.AdvanceOffset(sizeof(ChildTableEntry));
|
||||
}
|
||||
|
||||
SuccessOrExit(error = ParseChildTable(aDiagTlv.mData.mChildTable, aMessage, tlvInfo.GetValueOffsetRange()));
|
||||
break;
|
||||
}
|
||||
|
||||
case Tlv::kChannelPages:
|
||||
ReadDiagData(aDiagTlv.mData.mChannelPages, aMessage, tlvInfo);
|
||||
|
||||
@@ -281,6 +281,7 @@ public:
|
||||
|
||||
private:
|
||||
typedef otNetworkDiagData DiagData;
|
||||
typedef otNetworkDiagChildTable ChildTable;
|
||||
typedef otNetworkDiagIp6AddrList Ip6AddrList;
|
||||
|
||||
Error SendCommand(Uri aUri,
|
||||
@@ -301,8 +302,9 @@ private:
|
||||
|
||||
template <Uri kUri> void HandleTmf(Coap::Msg &aMsg);
|
||||
|
||||
static void ReadDiagData(DiagData &aDiagData, const Message &aMessage, const Tlv::Info &aTlvInfo);
|
||||
static void ParseIp6AddrList(Ip6AddrList &aIp6Addrs, const Message &aMessage, OffsetRange aOffsetRange);
|
||||
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);
|
||||
|
||||
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
|
||||
static const char *UriToString(Uri aUri);
|
||||
|
||||
@@ -38,6 +38,69 @@
|
||||
namespace ot {
|
||||
namespace NetworkDiagnostic {
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// ChildTableTlvEntry
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
|
||||
void ChildTableTlvEntry::InitFrom(const Child &aChild)
|
||||
{
|
||||
uint16_t encoded = 0;
|
||||
|
||||
// 1 0
|
||||
// 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// |TmoutExp |ILQ| Child ID |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
WriteBits<uint16_t, kTimeoutMask>(encoded, DetermineExponentFromTimeout(aChild.GetTimeout()));
|
||||
WriteBits<uint16_t, kIlqMask>(encoded, aChild.GetLinkQualityIn());
|
||||
WriteBits<uint16_t, kChildIdMask>(encoded, Mle::ChildIdFromRloc16(aChild.GetRloc16()));
|
||||
|
||||
mTimeoutIlqChildId = BigEndian::HostSwap16(encoded);
|
||||
mMode = aChild.GetDeviceMode().Get();
|
||||
}
|
||||
|
||||
uint8_t ChildTableTlvEntry::DetermineExponentFromTimeout(uint32_t aTimeout)
|
||||
{
|
||||
// The timeout is expressed as `2^(exponent - 4)` seconds. The
|
||||
// parent fills the exponent field with the closest
|
||||
// ceiling value based on the Child Timeout value.
|
||||
|
||||
uint8_t exponent;
|
||||
|
||||
for (exponent = kTimeoutExponentMin; exponent < kTimeoutExponentMax; exponent++)
|
||||
{
|
||||
if (DetermineTimeoutFromExponent(exponent) >= aTimeout)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return exponent;
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_FTD
|
||||
|
||||
uint32_t ChildTableTlvEntry::DetermineTimeoutFromExponent(uint8_t aExponent)
|
||||
{
|
||||
aExponent = Clamp(aExponent, kTimeoutExponentMin, kTimeoutExponentMax);
|
||||
|
||||
return static_cast<uint32_t>(1U) << (aExponent - kTimeoutExponentMin);
|
||||
}
|
||||
|
||||
void ChildTableTlvEntry::Parse(ParseInfo &aParseInfo) const
|
||||
{
|
||||
uint16_t encoded = BigEndian::HostSwap16(mTimeoutIlqChildId);
|
||||
|
||||
ClearAllBytes(aParseInfo);
|
||||
|
||||
aParseInfo.mTimeout = ReadBits<uint16_t, kTimeoutMask>(encoded);
|
||||
aParseInfo.mLinkQuality = static_cast<LinkQuality>(ReadBits<uint16_t, kIlqMask>(encoded));
|
||||
aParseInfo.mChildId = ReadBits<uint16_t, kChildIdMask>(encoded);
|
||||
Mle::DeviceMode(mMode).Get(aParseInfo.mMode);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// EnhancedRouteTlvEntry
|
||||
|
||||
|
||||
@@ -369,101 +369,69 @@ private:
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* Implements Child Table Entry generation and parsing.
|
||||
* Implements Child Table TLV Entry generation and parsing.
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class ChildTableEntry : public Clearable<ChildTableEntry>
|
||||
class ChildTableTlvEntry : public Clearable<ChildTableTlvEntry>
|
||||
{
|
||||
public:
|
||||
typedef otNetworkDiagChildEntry ParseInfo; ///< Parse entry info
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
/**
|
||||
* Returns the Timeout value.
|
||||
* Initializes the `ChildTableTlvEntry` from a given `Child` object.
|
||||
*
|
||||
* @returns The Timeout value.
|
||||
* @param[in] aChild The `Child` to initialize from.
|
||||
*/
|
||||
uint8_t GetTimeout(void) const
|
||||
{
|
||||
return static_cast<uint8_t>(ReadBits<uint16_t, kTimeoutMask>(GetTimeoutChildId()));
|
||||
}
|
||||
void InitFrom(const Child &aChild);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Sets the Timeout value.
|
||||
* Parses the TLV entry and populates the information in a given `ParseInfo` struct.
|
||||
*
|
||||
* @param[in] aTimeout The Timeout value.
|
||||
* @param[out] aParseInfo The `ParseInfo` structure to populate.
|
||||
*/
|
||||
void SetTimeout(uint8_t aTimeout)
|
||||
{
|
||||
SetTimeoutChildId(UpdateBits<uint16_t, kTimeoutMask>(GetTimeoutChildId(), aTimeout));
|
||||
}
|
||||
void Parse(ParseInfo &aParseInfo) const;
|
||||
|
||||
/**
|
||||
* The Link Quality value.
|
||||
* Determines the timeout value (in seconds) from a given exponent.
|
||||
*
|
||||
* @returns The Link Quality value.
|
||||
* The timeout is expressed as `2^(exponent - 4)` seconds.
|
||||
*
|
||||
* @param[in] aExponent The exponent value.
|
||||
*
|
||||
* @returns The timeout value (in seconds).
|
||||
*/
|
||||
LinkQuality GetLinkQuality(void) const
|
||||
{
|
||||
return static_cast<LinkQuality>(ReadBits<uint16_t, kLqiMask>(GetTimeoutChildId()));
|
||||
}
|
||||
static uint32_t DetermineTimeoutFromExponent(uint8_t aExponent);
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
/**
|
||||
* Set the Link Quality value.
|
||||
* Determines the exponent to use for a given timeout value (in seconds).
|
||||
*
|
||||
* @param[in] aLinkQuality The Link Quality value.
|
||||
*/
|
||||
void SetLinkQuality(LinkQuality aLinkQuality)
|
||||
{
|
||||
SetTimeoutChildId(UpdateBits<uint16_t, kLqiMask>(GetTimeoutChildId(), aLinkQuality));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Child ID value.
|
||||
* @param[in] aTimeout The timeout value (in seconds).
|
||||
*
|
||||
* @returns The Child ID value.
|
||||
* @returns The corresponding exponent.
|
||||
*/
|
||||
uint16_t GetChildId(void) const { return ReadBits<uint16_t, kChildIdMask>(GetTimeoutChildId()); }
|
||||
|
||||
/**
|
||||
* Sets the Child ID value.
|
||||
*
|
||||
* @param[in] aChildId The Child ID value.
|
||||
*/
|
||||
void SetChildId(uint16_t aChildId)
|
||||
{
|
||||
SetTimeoutChildId(UpdateBits<uint16_t, kChildIdMask>(GetTimeoutChildId(), aChildId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Device Mode
|
||||
*
|
||||
* @returns The Device Mode
|
||||
*/
|
||||
Mle::DeviceMode GetMode(void) const { return Mle::DeviceMode(mMode); }
|
||||
|
||||
/**
|
||||
* Sets the Device Mode.
|
||||
*
|
||||
* @param[in] aMode The Device Mode.
|
||||
*/
|
||||
void SetMode(Mle::DeviceMode aMode) { mMode = aMode.Get(); }
|
||||
static uint8_t DetermineExponentFromTimeout(uint32_t aTimeout);
|
||||
#endif
|
||||
|
||||
private:
|
||||
// 1 0
|
||||
// 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Timeout |LQI| Child ID |
|
||||
// |TmoutExp |ILQ| Child ID |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
static constexpr uint8_t kTimeoutOffset = 11;
|
||||
static constexpr uint8_t kLqiOffset = 9;
|
||||
static constexpr uint8_t kChildIdOffset = 0;
|
||||
static constexpr uint16_t kTimeoutMask = 0x1f << kTimeoutOffset;
|
||||
static constexpr uint16_t kLqiMask = 0x3 << kLqiOffset;
|
||||
static constexpr uint16_t kChildIdMask = 0x1ff << kChildIdOffset;
|
||||
static constexpr uint8_t kTimeoutOffset = 11;
|
||||
static constexpr uint8_t kIlqOffset = 9;
|
||||
static constexpr uint8_t kChildIdOffset = 0;
|
||||
static constexpr uint16_t kTimeoutMask = 0x1f << kTimeoutOffset;
|
||||
static constexpr uint16_t kIlqMask = 0x3 << kIlqOffset;
|
||||
static constexpr uint16_t kChildIdMask = 0x1ff << kChildIdOffset;
|
||||
static constexpr uint8_t kTimeoutExponentMin = 4;
|
||||
static constexpr uint8_t kTimeoutExponentMax = 0x1f;
|
||||
|
||||
uint16_t GetTimeoutChildId(void) const { return BigEndian::HostSwap16(mTimeoutChildId); }
|
||||
void SetTimeoutChildId(uint16_t aTimeoutChildIf) { mTimeoutChildId = BigEndian::HostSwap16(aTimeoutChildIf); }
|
||||
|
||||
uint16_t mTimeoutChildId;
|
||||
uint16_t mTimeoutIlqChildId;
|
||||
uint8_t mMode;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
|
||||
@@ -556,20 +556,23 @@ exit:
|
||||
|
||||
Error MeshDiag::ChildIterator::GetNextChildInfo(ChildInfo &aChildInfo)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
ChildTableEntry entry;
|
||||
Error error = kErrorNotFound;
|
||||
ChildTableTlvEntry entry;
|
||||
ChildTableTlvEntry::ParseInfo info;
|
||||
|
||||
VerifyOrExit(mMessage != nullptr, error = kErrorNotFound);
|
||||
VerifyOrExit(mMessage != nullptr);
|
||||
|
||||
VerifyOrExit(mMessage->Read(mOffsetRange, entry) == kErrorNone, error = kErrorNotFound);
|
||||
mOffsetRange.AdvanceOffset(sizeof(ChildTableEntry));
|
||||
SuccessOrExit(mMessage->Read(mOffsetRange, entry));
|
||||
mOffsetRange.AdvanceOffset(sizeof(ChildTableTlvEntry));
|
||||
|
||||
aChildInfo.mRloc16 = mParentRloc16 + entry.GetChildId();
|
||||
entry.GetMode().Get(aChildInfo.mMode);
|
||||
aChildInfo.mLinkQuality = entry.GetLinkQuality();
|
||||
entry.Parse(info);
|
||||
|
||||
aChildInfo.mRloc16 = mParentRloc16 + info.mChildId;
|
||||
aChildInfo.mMode = info.mMode;
|
||||
aChildInfo.mLinkQuality = info.mLinkQuality;
|
||||
aChildInfo.mIsThisDevice = mMessage->Get<Mle::Mle>().HasRloc16(aChildInfo.mRloc16);
|
||||
aChildInfo.mIsBorderRouter = mMessage->Get<NetworkData::Leader>().ContainsBorderRouterWithRloc(aChildInfo.mRloc16);
|
||||
error = kErrorNone;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
|
||||
Reference in New Issue
Block a user