diff --git a/src/core/thread/network_diagnostic.cpp b/src/core/thread/network_diagnostic.cpp index 5d5f97fa2..9e927ae9f 100644 --- a/src/core/thread/network_diagnostic.cpp +++ b/src/core/thread/network_diagnostic.cpp @@ -188,11 +188,8 @@ exit: Error NetworkDiagnostic::AppendIp6AddressList(Message &aMessage) { - Error error = kErrorNone; - Ip6AddressListTlv tlv; - uint8_t count = 0; - - tlv.Init(); + Error error = kErrorNone; + uint16_t count = 0; for (const Ip6::Netif::UnicastAddress &addr : Get().GetUnicastAddresses()) { @@ -200,8 +197,22 @@ Error NetworkDiagnostic::AppendIp6AddressList(Message &aMessage) count++; } - tlv.SetLength(count * sizeof(Ip6::Address)); - SuccessOrExit(error = aMessage.Append(tlv)); + if (count * Ip6::Address::kSize <= Tlv::kBaseTlvMaxLength) + { + Tlv tlv; + + tlv.SetType(NetworkDiagnosticTlv::kIp6AddressList); + tlv.SetLength(static_cast(count * Ip6::Address::kSize)); + SuccessOrExit(error = aMessage.Append(tlv)); + } + else + { + ExtendedTlv extTlv; + + extTlv.SetType(NetworkDiagnosticTlv::kIp6AddressList); + extTlv.SetLength(count * Ip6::Address::kSize); + SuccessOrExit(error = aMessage.Append(extTlv)); + } for (const Ip6::Netif::UnicastAddress &addr : Get().GetUnicastAddresses()) { @@ -209,50 +220,48 @@ Error NetworkDiagnostic::AppendIp6AddressList(Message &aMessage) } exit: - return error; } #if OPENTHREAD_FTD Error NetworkDiagnostic::AppendChildTable(Message &aMessage) { - Error error = kErrorNone; - uint16_t count = 0; - uint8_t timeout = 0; - ChildTableTlv tlv; - ChildTableEntry entry; + Error error = kErrorNone; + uint16_t count = 0; - tlv.Init(); + count = Min(Get().GetNumChildren(Child::kInStateValid), kMaxChildEntries); - count = Get().GetNumChildren(Child::kInStateValid); - - // The length of the Child Table TLV may exceed the outgoing link's MTU (1280B). - // As a workaround we limit the number of entries in the Child Table TLV, - // also to avoid using extended TLV format. The issue is processed by the - // Thread Group (SPEC-894). - if (count > (Tlv::kBaseTlvMaxLength / sizeof(ChildTableEntry))) + if (count * sizeof(ChildTableEntry) <= Tlv::kBaseTlvMaxLength) { - count = Tlv::kBaseTlvMaxLength / sizeof(ChildTableEntry); + Tlv tlv; + + tlv.SetType(NetworkDiagnosticTlv::kChildTable); + tlv.SetLength(static_cast(count * sizeof(ChildTableEntry))); + SuccessOrExit(error = aMessage.Append(tlv)); } + else + { + ExtendedTlv extTlv; - tlv.SetLength(static_cast(count * sizeof(ChildTableEntry))); - - SuccessOrExit(error = aMessage.Append(tlv)); + extTlv.SetType(NetworkDiagnosticTlv::kChildTable); + extTlv.SetLength(count * sizeof(ChildTableEntry)); + SuccessOrExit(error = aMessage.Append(extTlv)); + } for (Child &child : Get().Iterate(Child::kInStateValid)) { - VerifyOrExit(count--); + uint8_t timeout = 0; + ChildTableEntry entry; - timeout = 0; + VerifyOrExit(count--); while (static_cast(1 << timeout) < child.GetTimeout()) { timeout++; } - entry.SetReserved(0); + entry.Clear(); entry.SetTimeout(timeout + 4); - entry.SetChildId(Mle::ChildIdFromRloc16(child.GetRloc16())); entry.SetMode(child.GetDeviceMode()); @@ -260,7 +269,6 @@ Error NetworkDiagnostic::AppendChildTable(Message &aMessage) } exit: - return error; } #endif // OPENTHREAD_FTD @@ -297,8 +305,6 @@ Error NetworkDiagnostic::FillRequestedTlvs(const Message & aRequest, { SuccessOrExit(error = aRequest.Read(offset, type)); - LogInfo("Type %d", type); - switch (type) { case NetworkDiagnosticTlv::kExtMacAddress: @@ -362,10 +368,8 @@ Error NetworkDiagnostic::FillRequestedTlvs(const Message & aRequest, } case NetworkDiagnosticTlv::kIp6AddressList: - { SuccessOrExit(error = AppendIp6AddressList(aResponse)); break; - } case NetworkDiagnosticTlv::kMacCounters: { @@ -619,36 +623,47 @@ static inline void ParseMacCounters(const MacCountersTlv &aMacCountersTlv, otNet aMacCounters.mIfOutDiscards = aMacCountersTlv.GetIfOutDiscards(); } -static inline void ParseChildEntry(const ChildTableEntry &aChildTableTlvEntry, otNetworkDiagChildEntry &aChildEntry) +Error NetworkDiagnostic::GetNextDiagTlv(const Coap::Message &aMessage, Iterator &aIterator, TlvInfo &aTlvInfo) { - aChildEntry.mTimeout = aChildTableTlvEntry.GetTimeout(); - aChildEntry.mChildId = aChildTableTlvEntry.GetChildId(); - aChildTableTlvEntry.GetMode().Get(aChildEntry.mMode); -} + Error error = kErrorNotFound; + uint16_t offset = (aIterator == 0) ? aMessage.GetOffset() : aIterator; -Error NetworkDiagnostic::GetNextDiagTlv(const Coap::Message &aMessage, - Iterator & aIterator, - otNetworkDiagTlv & aNetworkDiagTlv) -{ - Error error = kErrorNone; - uint16_t offset = aMessage.GetOffset() + aIterator; - NetworkDiagnosticTlv tlv; - - while (true) + while (offset < aMessage.GetLength()) { - uint16_t tlvTotalLength; + bool skipTlv = false; + uint16_t valueOffset; + uint16_t tlvLength; + union + { + Tlv tlv; + ExtendedTlv extTlv; + }; - VerifyOrExit(aMessage.Read(offset, tlv) == kErrorNone, error = kErrorNotFound); + SuccessOrExit(error = aMessage.Read(offset, tlv)); + + if (tlv.IsExtended()) + { + SuccessOrExit(error = aMessage.Read(offset, extTlv)); + valueOffset = offset + sizeof(ExtendedTlv); + tlvLength = extTlv.GetLength(); + } + else + { + valueOffset = offset + sizeof(Tlv); + tlvLength = tlv.GetLength(); + } + + VerifyOrExit(offset + tlv.GetSize() <= aMessage.GetLength(), error = kErrorParse); switch (tlv.GetType()) { case NetworkDiagnosticTlv::kExtMacAddress: - SuccessOrExit( - error = Tlv::Read(aMessage, offset, AsCoreType(&aNetworkDiagTlv.mData.mExtAddress))); + SuccessOrExit(error = + Tlv::Read(aMessage, offset, AsCoreType(&aTlvInfo.mData.mExtAddress))); break; case NetworkDiagnosticTlv::kAddress16: - SuccessOrExit(error = Tlv::Read(aMessage, offset, aNetworkDiagTlv.mData.mAddr16)); + SuccessOrExit(error = Tlv::Read(aMessage, offset, aTlvInfo.mData.mAddr16)); break; case NetworkDiagnosticTlv::kMode: @@ -656,137 +671,159 @@ Error NetworkDiagnostic::GetNextDiagTlv(const Coap::Message &aMessage, uint8_t mode; SuccessOrExit(error = Tlv::Read(aMessage, offset, mode)); - Mle::DeviceMode(mode).Get(aNetworkDiagTlv.mData.mMode); + Mle::DeviceMode(mode).Get(aTlvInfo.mData.mMode); break; } case NetworkDiagnosticTlv::kTimeout: - SuccessOrExit(error = Tlv::Read(aMessage, offset, aNetworkDiagTlv.mData.mTimeout)); + SuccessOrExit(error = Tlv::Read(aMessage, offset, aTlvInfo.mData.mTimeout)); break; case NetworkDiagnosticTlv::kConnectivity: { - ConnectivityTlv connectivity; + ConnectivityTlv connectivityTlv; - SuccessOrExit(error = aMessage.Read(offset, connectivity)); - VerifyOrExit(connectivity.IsValid(), error = kErrorParse); - connectivity.GetConnectivity(aNetworkDiagTlv.mData.mConnectivity); + VerifyOrExit(!tlv.IsExtended(), error = kErrorParse); + SuccessOrExit(error = aMessage.Read(offset, connectivityTlv)); + VerifyOrExit(connectivityTlv.IsValid(), error = kErrorParse); + connectivityTlv.GetConnectivity(aTlvInfo.mData.mConnectivity); break; } case NetworkDiagnosticTlv::kRoute: { - RouteTlv route; + RouteTlv routeTlv; + uint16_t bytesToRead = static_cast(Min(tlv.GetSize(), static_cast(sizeof(routeTlv)))); - tlvTotalLength = sizeof(tlv) + tlv.GetLength(); - VerifyOrExit(tlvTotalLength <= sizeof(route), error = kErrorParse); - SuccessOrExit(error = aMessage.Read(offset, &route, tlvTotalLength)); - VerifyOrExit(route.IsValid(), error = kErrorParse); - - ParseRoute(route, aNetworkDiagTlv.mData.mRoute); + VerifyOrExit(!tlv.IsExtended(), error = kErrorParse); + SuccessOrExit(error = aMessage.Read(offset, &routeTlv, bytesToRead)); + VerifyOrExit(routeTlv.IsValid(), error = kErrorParse); + ParseRoute(routeTlv, aTlvInfo.mData.mRoute); break; } case NetworkDiagnosticTlv::kLeaderData: { - LeaderDataTlv leaderData; + LeaderDataTlv leaderDataTlv; - SuccessOrExit(error = aMessage.Read(offset, leaderData)); - VerifyOrExit(leaderData.IsValid(), error = kErrorParse); - leaderData.Get(AsCoreType(&aNetworkDiagTlv.mData.mLeaderData)); + VerifyOrExit(!tlv.IsExtended(), error = kErrorParse); + SuccessOrExit(error = aMessage.Read(offset, leaderDataTlv)); + VerifyOrExit(leaderDataTlv.IsValid(), error = kErrorParse); + leaderDataTlv.Get(AsCoreType(&aTlvInfo.mData.mLeaderData)); break; } case NetworkDiagnosticTlv::kNetworkData: - { - NetworkDataTlv networkData; + static_assert(sizeof(aTlvInfo.mData.mNetworkData.m8) >= NetworkData::NetworkData::kMaxSize, + "NetworkData array in `otNetworkDiagTlv` is too small"); - tlvTotalLength = sizeof(tlv) + tlv.GetLength(); - VerifyOrExit(tlvTotalLength <= sizeof(networkData), error = kErrorParse); - SuccessOrExit(error = aMessage.Read(offset, &networkData, tlvTotalLength)); - VerifyOrExit(networkData.IsValid(), error = kErrorParse); - VerifyOrExit(sizeof(aNetworkDiagTlv.mData.mNetworkData.m8) >= networkData.GetLength(), error = kErrorParse); - - memcpy(aNetworkDiagTlv.mData.mNetworkData.m8, networkData.GetNetworkData(), networkData.GetLength()); - aNetworkDiagTlv.mData.mNetworkData.mCount = networkData.GetLength(); + VerifyOrExit(tlvLength <= NetworkData::NetworkData::kMaxSize, error = kErrorParse); + aTlvInfo.mData.mNetworkData.mCount = static_cast(tlvLength); + aMessage.ReadBytes(valueOffset, aTlvInfo.mData.mNetworkData.m8, tlvLength); break; - } case NetworkDiagnosticTlv::kIp6AddressList: { - Ip6AddressListTlv &ip6AddrList = As(tlv); + uint16_t addrListLength = GetArrayLength(aTlvInfo.mData.mIp6AddrList.mList); + Ip6::Address *addrEntry = AsCoreTypePtr(&aTlvInfo.mData.mIp6AddrList.mList[0]); + uint8_t & addrCount = aTlvInfo.mData.mIp6AddrList.mCount; + + VerifyOrExit((tlvLength % Ip6::Address::kSize) == 0, error = kErrorParse); + + // `TlvInfo` has a fixed array for IPv6 addresses. If there + // are more addresses in the message, we read and return as + // many as can fit in array and ignore the rest. + + addrCount = 0; + + while ((tlvLength > 0) && (addrCount < addrListLength)) + { + SuccessOrExit(error = aMessage.Read(valueOffset, *addrEntry)); + addrCount++; + addrEntry++; + valueOffset += Ip6::Address::kSize; + tlvLength -= Ip6::Address::kSize; + } - VerifyOrExit(ip6AddrList.IsValid(), error = kErrorParse); - VerifyOrExit(sizeof(aNetworkDiagTlv.mData.mIp6AddrList.mList) >= ip6AddrList.GetLength(), - error = kErrorParse); - SuccessOrExit(error = aMessage.Read(offset + sizeof(ip6AddrList), aNetworkDiagTlv.mData.mIp6AddrList.mList, - ip6AddrList.GetLength())); - aNetworkDiagTlv.mData.mIp6AddrList.mCount = ip6AddrList.GetLength() / OT_IP6_ADDRESS_SIZE; break; } case NetworkDiagnosticTlv::kMacCounters: { - MacCountersTlv macCounters; + MacCountersTlv macCountersTlv; - SuccessOrExit(error = aMessage.Read(offset, macCounters)); - VerifyOrExit(macCounters.IsValid(), error = kErrorParse); - - ParseMacCounters(macCounters, aNetworkDiagTlv.mData.mMacCounters); + SuccessOrExit(error = aMessage.Read(offset, macCountersTlv)); + VerifyOrExit(macCountersTlv.IsValid(), error = kErrorParse); + ParseMacCounters(macCountersTlv, aTlvInfo.mData.mMacCounters); break; } case NetworkDiagnosticTlv::kBatteryLevel: - SuccessOrExit(error = Tlv::Read(aMessage, offset, aNetworkDiagTlv.mData.mBatteryLevel)); + SuccessOrExit(error = Tlv::Read(aMessage, offset, aTlvInfo.mData.mBatteryLevel)); break; case NetworkDiagnosticTlv::kSupplyVoltage: - SuccessOrExit(error = Tlv::Read(aMessage, offset, aNetworkDiagTlv.mData.mSupplyVoltage)); + SuccessOrExit(error = Tlv::Read(aMessage, offset, aTlvInfo.mData.mSupplyVoltage)); break; case NetworkDiagnosticTlv::kChildTable: { - ChildTableTlv &childTable = As(tlv); + uint16_t childInfoLength = GetArrayLength(aTlvInfo.mData.mChildTable.mTable); + ChildInfo *childInfo = &aTlvInfo.mData.mChildTable.mTable[0]; + uint8_t & childCount = aTlvInfo.mData.mChildTable.mCount; - VerifyOrExit(childTable.IsValid(), error = kErrorParse); - VerifyOrExit(childTable.GetNumEntries() <= GetArrayLength(aNetworkDiagTlv.mData.mChildTable.mTable), - error = kErrorParse); + VerifyOrExit((tlvLength % sizeof(ChildTableEntry)) == 0, error = kErrorParse); - for (uint8_t i = 0; i < childTable.GetNumEntries(); ++i) + // `TlvInfo` 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; + + while ((tlvLength > 0) && (childCount < childInfoLength)) { - ChildTableEntry childEntry; - VerifyOrExit(childTable.ReadEntry(childEntry, aMessage, offset, i) == kErrorNone, error = kErrorParse); - ParseChildEntry(childEntry, aNetworkDiagTlv.mData.mChildTable.mTable[i]); + ChildTableEntry entry; + + SuccessOrExit(error = aMessage.Read(valueOffset, entry)); + + childInfo->mTimeout = entry.GetTimeout(); + childInfo->mChildId = entry.GetChildId(); + entry.GetMode().Get(childInfo->mMode); + + childCount++; + childInfo++; + tlvLength -= sizeof(ChildTableEntry); + valueOffset += sizeof(ChildTableEntry); } - aNetworkDiagTlv.mData.mChildTable.mCount = childTable.GetNumEntries(); + break; } case NetworkDiagnosticTlv::kChannelPages: - { - VerifyOrExit(sizeof(aNetworkDiagTlv.mData.mChannelPages.m8) >= tlv.GetLength(), error = kErrorParse); - SuccessOrExit( - error = aMessage.Read(offset + sizeof(tlv), aNetworkDiagTlv.mData.mChannelPages.m8, tlv.GetLength())); - aNetworkDiagTlv.mData.mChannelPages.mCount = tlv.GetLength(); + aTlvInfo.mData.mChannelPages.mCount = + static_cast(Min(tlvLength, GetArrayLength(aTlvInfo.mData.mChannelPages.m8))); + aMessage.ReadBytes(valueOffset, aTlvInfo.mData.mChannelPages.m8, aTlvInfo.mData.mChannelPages.mCount); break; - } case NetworkDiagnosticTlv::kMaxChildTimeout: - SuccessOrExit(error = - Tlv::Read(aMessage, offset, aNetworkDiagTlv.mData.mMaxChildTimeout)); + SuccessOrExit(error = Tlv::Read(aMessage, offset, aTlvInfo.mData.mMaxChildTimeout)); break; default: - // Ignore unrecognized Network Diagnostic TLV silently and - // continue to top of the `while(true)` loop. - offset += tlv.GetSize(); - continue; + // Skip unrecognized TLVs. + skipTlv = true; + break; } - // Exit if a TLV is recognized and parsed successfully. - aNetworkDiagTlv.mType = tlv.GetType(); - aIterator = static_cast(offset - aMessage.GetOffset() + tlv.GetSize()); - ExitNow(); + offset += tlv.GetSize(); + + if (!skipTlv) + { + // Exit if a TLV is recognized and parsed successfully. + aTlvInfo.mType = tlv.GetType(); + aIterator = offset; + ExitNow(); + } } exit: diff --git a/src/core/thread/network_diagnostic.hpp b/src/core/thread/network_diagnostic.hpp index ac9084b8c..ef8399700 100644 --- a/src/core/thread/network_diagnostic.hpp +++ b/src/core/thread/network_diagnostic.hpp @@ -76,6 +76,18 @@ public: static constexpr Iterator kIteratorInit = OT_NETWORK_DIAGNOSTIC_ITERATOR_INIT; ///< Initializer for Iterator. + /** + * This type represents parsed information from a Network Diagnostic TLV. + * + */ + typedef otNetworkDiagTlv TlvInfo; + + /** + * This structure represents parsed information from Network Diagnostic Child Table entry. + * + */ + typedef otNetworkDiagChildEntry ChildInfo; + /** * This constructor initializes the object. * @@ -116,16 +128,18 @@ public: * @param[in] aMessage A message. * @param[in,out] aIterator The Network Diagnostic iterator. To get the first TLV set it to * `kIteratorInit`. - * @param[out] aNetworkDiagTlv A reference to a Network Diagnostic TLV to output the next TLV. + * @param[out] aTlvInfo A reference to a `TlvInfo` to output the next TLV data. * * @retval kErrorNone Successfully found the next Network Diagnostic TLV. * @retval kErrorNotFound No subsequent Network Diagnostic TLV exists in the message. * @retval kErrorParse Parsing the next Network Diagnostic failed. * */ - static Error GetNextDiagTlv(const Coap::Message &aMessage, Iterator &aIterator, otNetworkDiagTlv &aNetworkDiagTlv); + static Error GetNextDiagTlv(const Coap::Message &aMessage, Iterator &aIterator, TlvInfo &aTlvInfo); private: + static constexpr uint16_t kMaxChildEntries = 398; + enum CommandType : uint8_t { kDiagnosticGet, diff --git a/src/core/thread/network_diagnostic_tlvs.hpp b/src/core/thread/network_diagnostic_tlvs.hpp index c1a97ccb9..f50418fdf 100644 --- a/src/core/thread/network_diagnostic_tlvs.hpp +++ b/src/core/thread/network_diagnostic_tlvs.hpp @@ -38,6 +38,7 @@ #include +#include "common/clearable.hpp" #include "common/encoding.hpp" #include "common/message.hpp" #include "common/tlvs.hpp" @@ -126,6 +127,18 @@ typedef UintTlvInfo ModeTlv; */ typedef UintTlvInfo TimeoutTlv; +/** + * This class defines Network Data TLV constants and types. + * + */ +typedef TlvInfo NetworkDataTlv; + +/** + * This class defines IPv6 Address List TLV constants and types. + * + */ +typedef TlvInfo Ip6AddressListTlv; + /** * This class defines Battery Level TLV constants and types. * @@ -138,6 +151,12 @@ typedef UintTlvInfo BatteryLevelTl */ typedef UintTlvInfo SupplyVoltageTlv; +/** + * This class defines Child Table TLV constants and types. + * + */ +typedef TlvInfo ChildTableTlv; + /** * This class defines Max Child Timeout TLV constants and types. * @@ -229,95 +248,6 @@ public: } } OT_TOOL_PACKED_END; -/** - * This class implements Network Data TLV generation and parsing. - * - */ -OT_TOOL_PACKED_BEGIN -class NetworkDataTlv : public NetworkDiagnosticTlv, public TlvInfo -{ -public: - /** - * This method initializes the TLV. - * - */ - void Init(void) - { - SetType(kNetworkData); - SetLength(sizeof(*this) - sizeof(NetworkDiagnosticTlv)); - } - - /** - * This method 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 { return GetLength() < sizeof(*this) - sizeof(NetworkDiagnosticTlv); } - - /** - * This method returns a pointer to the Network Data. - * - * @returns A pointer to the Network Data. - * - */ - uint8_t *GetNetworkData(void) { return mNetworkData; } - - /** - * This method sets the Network Data. - * - * @param[in] aNetworkData A pointer to the Network Data. - * - */ - void SetNetworkData(const uint8_t *aNetworkData) { memcpy(mNetworkData, aNetworkData, GetLength()); } - -private: - uint8_t mNetworkData[255]; -} OT_TOOL_PACKED_END; - -/** - * This class implements IPv6 Address List TLV generation and parsing. - * - */ -OT_TOOL_PACKED_BEGIN -class Ip6AddressListTlv : public NetworkDiagnosticTlv, public TlvInfo -{ -public: - /** - * This method initializes the TLV. - * - */ - void Init(void) - { - SetType(kIp6AddressList); - SetLength(sizeof(*this) - sizeof(NetworkDiagnosticTlv)); - } - - /** - * This method 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 { return !IsExtended() && (GetLength() % sizeof(Ip6::Address) == 0); } - - /** - * This method returns a pointer to the IPv6 address entry. - * - * @param[in] aIndex The index into the IPv6 address list. - * - * @returns A reference to the IPv6 address. - * - */ - const Ip6::Address &GetIp6Address(uint8_t aIndex) const - { - return *reinterpret_cast(GetValue() + (aIndex * sizeof(Ip6::Address))); - } - -} OT_TOOL_PACKED_END; - /** * This class implements Mac Counters TLV generation and parsing. * @@ -514,26 +444,16 @@ private: * */ OT_TOOL_PACKED_BEGIN -class ChildTableEntry +class ChildTableEntry : public Clearable { public: - /** - * Default constructor. - * - */ - ChildTableEntry(void) - : mTimeoutRsvChildId(0) - , mMode(0) - { - } - /** * This method returns the Timeout value. * * @returns The Timeout value. * */ - uint8_t GetTimeout(void) const { return (HostSwap16(mTimeoutRsvChildId) & kTimeoutMask) >> kTimeoutOffset; } + uint8_t GetTimeout(void) const { return (GetTimeoutChildId() & kTimeoutMask) >> kTimeoutOffset; } /** * This method sets the Timeout value. @@ -543,8 +463,7 @@ public: */ void SetTimeout(uint8_t aTimeout) { - mTimeoutRsvChildId = HostSwap16((HostSwap16(mTimeoutRsvChildId) & ~kTimeoutMask) | - ((aTimeout << kTimeoutOffset) & kTimeoutMask)); + SetTimeoutChildId((GetTimeoutChildId() & ~kTimeoutMask) | ((aTimeout << kTimeoutOffset) & kTimeoutMask)); } /** @@ -553,7 +472,7 @@ public: * @returns The Child ID value. * */ - uint16_t GetChildId(void) const { return HostSwap16(mTimeoutRsvChildId) & kChildIdMask; } + uint16_t GetChildId(void) const { return (GetTimeoutChildId() & kChildIdMask) >> kChildIdOffset; } /** * This method sets the Child ID value. @@ -563,7 +482,7 @@ public: */ void SetChildId(uint16_t aChildId) { - mTimeoutRsvChildId = HostSwap16((HostSwap16(mTimeoutRsvChildId) & ~kChildIdMask) | (aChildId & kChildIdMask)); + SetTimeoutChildId((GetTimeoutChildId() & ~kChildIdMask) | ((aChildId << kChildIdOffset) & kChildIdMask)); } /** @@ -582,108 +501,25 @@ public: */ void SetMode(Mle::DeviceMode aMode) { mMode = aMode.Get(); } - /** - * This method returns the Reserved value. - * - * @returns The Reserved value. - * - */ - uint8_t GetReserved(void) const { return (HostSwap16(mTimeoutRsvChildId) & kReservedMask) >> kReservedOffset; } - - /** - * This method sets the Reserved value. - * - * @param[in] aReserved The Reserved value. - * - */ - void SetReserved(uint8_t aReserved) - { - mTimeoutRsvChildId = HostSwap16((HostSwap16(mTimeoutRsvChildId) & ~kReservedMask) | - ((aReserved << kReservedOffset) & kReservedMask)); - } - private: - static constexpr uint8_t kTimeoutOffset = 11; - static constexpr uint8_t kReservedOffset = 9; - static constexpr uint16_t kTimeoutMask = 0xf800; - static constexpr uint16_t kReservedMask = 0x0600; - static constexpr uint16_t kChildIdMask = 0x1ff; + // 1 0 + // 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Timeout |RSV| Child ID | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - uint16_t mTimeoutRsvChildId; + static constexpr uint8_t kTimeoutOffset = 11; + static constexpr uint8_t kChildIdOffset = 0; + static constexpr uint16_t kTimeoutMask = 0x1f << kTimeoutOffset; + static constexpr uint16_t kChildIdMask = 0x1ff << kChildIdOffset; + + uint16_t GetTimeoutChildId(void) const { return HostSwap16(mTimeoutChildId); } + void SetTimeoutChildId(uint16_t aTimeoutChildIf) { mTimeoutChildId = HostSwap16(aTimeoutChildIf); } + + uint16_t mTimeoutChildId; uint8_t mMode; } OT_TOOL_PACKED_END; -/** - * This class implements Child Table TLV generation and parsing. - * - */ -OT_TOOL_PACKED_BEGIN -class ChildTableTlv : public NetworkDiagnosticTlv, public TlvInfo -{ -public: - /** - * This method initializes the TLV. - * - */ - void Init(void) - { - SetType(kChildTable); - SetLength(sizeof(*this) - sizeof(NetworkDiagnosticTlv)); - } - - /** - * This method 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 { return (GetLength() % sizeof(ChildTableEntry)) == 0; } - - /** - * This method returns the number of Child Table entries. - * - * @returns The number of Child Table entries. - * - */ - uint8_t GetNumEntries(void) const { return GetLength() / sizeof(ChildTableEntry); } - - /** - * This method returns the Child Table entry at @p aIndex. - * - * @param[in] aIndex The index into the Child Table list. - * - * @returns A reference to the Child Table entry. - * - */ - ChildTableEntry &GetEntry(uint16_t aIndex) - { - return *reinterpret_cast(GetValue() + (aIndex * sizeof(ChildTableEntry))); - } - - /** - * This method reads the Child Table entry at @p aIndex. - * - * @param[out] aEntry A reference to a ChildTableEntry. - * @param[in] aMessage A reference to the message. - * @param[in] aOffset The offset of the ChildTableTLV in aMessage. - * @param[in] aIndex The index into the Child Table list. - * - * @retval kErrorNotFound No such entry is found. - * @retval kErrorNone Successfully read the entry. - * - */ - Error ReadEntry(ChildTableEntry &aEntry, const Message &aMessage, uint16_t aOffset, uint8_t aIndex) const - { - return ((aIndex < GetNumEntries()) && - (aMessage.Read(aOffset + sizeof(ChildTableTlv) + (aIndex * sizeof(ChildTableEntry)), aEntry) == - kErrorNone)) - ? kErrorNone - : kErrorInvalidArgs; - } - -} OT_TOOL_PACKED_END; - /** * This class implements Channel Pages TLV generation and parsing. *