From 531339b65d2a7ed2ca71870c27f1dbe9dbcd5234 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 13 Sep 2022 08:44:45 -0700 Subject: [PATCH] [link-metrics] simplify preparation of MLE Data Request (#8142) This commit simplifies the preparation of MLE Data Request message which include a Link Metrics Query TLV and its sub-TLVs. --- src/core/thread/link_metrics.cpp | 72 +++++++++++++------------------- src/core/thread/link_metrics.hpp | 28 ++++++++++--- src/core/thread/mle.cpp | 21 ++++++---- src/core/thread/mle.hpp | 33 ++++++++++----- 4 files changed, 87 insertions(+), 67 deletions(-) diff --git a/src/core/thread/link_metrics.cpp b/src/core/thread/link_metrics.cpp index 024bbab53..6ecf26d1e 100644 --- a/src/core/thread/link_metrics.cpp +++ b/src/core/thread/link_metrics.cpp @@ -64,25 +64,29 @@ LinkMetrics::LinkMetrics(Instance &aInstance) Error LinkMetrics::Query(const Ip6::Address &aDestination, uint8_t aSeriesId, const Metrics *aMetrics) { - Error error; - TypeIdFlags typeIdFlags[kMaxTypeIdFlags]; - uint8_t typeIdFlagsCount = 0; - Neighbor * neighbor = GetNeighborFromLinkLocalAddr(aDestination); + static const uint8_t kTlvs[] = {Mle::Tlv::kLinkMetricsReport}; + + Error error; + Neighbor *neighbor = GetNeighborFromLinkLocalAddr(aDestination); + QueryInfo info; VerifyOrExit(neighbor != nullptr, error = kErrorUnknownNeighbor); VerifyOrExit(neighbor->IsThreadVersion1p2OrHigher(), error = kErrorNotCapable); + info.Clear(); + info.mSeriesId = aSeriesId; + if (aMetrics != nullptr) { - typeIdFlagsCount = TypeIdFlagsFromMetrics(typeIdFlags, *aMetrics); + info.mTypeIdCount = TypeIdFlagsFromMetrics(info.mTypeIds, *aMetrics); } if (aSeriesId != 0) { - VerifyOrExit(typeIdFlagsCount == 0, error = kErrorInvalidArgs); + VerifyOrExit(info.mTypeIdCount == 0, error = kErrorInvalidArgs); } - error = SendLinkMetricsQuery(aDestination, aSeriesId, typeIdFlags, typeIdFlagsCount); + error = Get().SendDataRequest(aDestination, kTlvs, sizeof(kTlvs), /* aDelay */ 0, info); exit: return error; @@ -560,52 +564,32 @@ exit: return; } -Error LinkMetrics::SendLinkMetricsQuery(const Ip6::Address &aDestination, - uint8_t aSeriesId, - const TypeIdFlags * aTypeIdFlags, - uint8_t aTypeIdFlagsCount) +Error LinkMetrics::AppendLinkMetricsQueryTlv(Message &aMessage, const QueryInfo &aInfo) { - // LinkMetricsQuery Tlv + LinkMetricsQueryId sub-TLV (value-length: 1 byte) + - // LinkMetricsQueryOptions sub-TLV (value-length: `kMaxTypeIdFlags` bytes) - constexpr uint16_t kBufferSize = sizeof(Tlv) * 3 + sizeof(uint8_t) + sizeof(TypeIdFlags) * kMaxTypeIdFlags; + Error error = kErrorNone; + Tlv tlv; - Error error = kErrorNone; - QueryOptionsSubTlv queryOptionsTlv; - uint8_t length = 0; - static const uint8_t tlvs[] = {Mle::Tlv::kLinkMetricsReport}; - uint8_t buf[kBufferSize]; - Tlv * tlv = reinterpret_cast(buf); - Tlv subTlv; + // The MLE Link Metrics Query TLV has two sub-TLVs: + // - Query ID sub-TLV with series ID as value. + // - Query Options sub-TLV with Type IDs as value. - // Link Metrics Query TLV - tlv->SetType(Mle::Tlv::kLinkMetricsQuery); - length += sizeof(Tlv); + tlv.SetType(Mle::Tlv::kLinkMetricsQuery); + tlv.SetLength(sizeof(Tlv) + sizeof(uint8_t) + ((aInfo.mTypeIdCount == 0) ? 0 : (sizeof(Tlv) + aInfo.mTypeIdCount))); - // Link Metrics Query ID sub-TLV - subTlv.SetType(SubTlv::kQueryId); - subTlv.SetLength(sizeof(uint8_t)); - memcpy(buf + length, &subTlv, sizeof(subTlv)); - length += sizeof(subTlv); - memcpy(buf + length, &aSeriesId, sizeof(aSeriesId)); - length += sizeof(aSeriesId); + SuccessOrExit(error = aMessage.Append(tlv)); - // Link Metrics Query Options sub-TLV - if (aTypeIdFlagsCount > 0) + SuccessOrExit(error = Tlv::Append(aMessage, aInfo.mSeriesId)); + + if (aInfo.mTypeIdCount != 0) { + QueryOptionsSubTlv queryOptionsTlv; + queryOptionsTlv.Init(); - queryOptionsTlv.SetLength(aTypeIdFlagsCount * sizeof(TypeIdFlags)); - - memcpy(buf + length, &queryOptionsTlv, sizeof(queryOptionsTlv)); - length += sizeof(queryOptionsTlv); - memcpy(buf + length, aTypeIdFlags, queryOptionsTlv.GetLength()); - length += queryOptionsTlv.GetLength(); + queryOptionsTlv.SetLength(aInfo.mTypeIdCount); + SuccessOrExit(error = aMessage.Append(queryOptionsTlv)); + SuccessOrExit(error = aMessage.AppendBytes(aInfo.mTypeIds, aInfo.mTypeIdCount)); } - // Set Length for Link Metrics Report TLV - tlv->SetLength(length - sizeof(Tlv)); - - SuccessOrExit(error = Get().SendDataRequest(aDestination, tlvs, sizeof(tlvs), 0, buf, length)); - exit: return error; } diff --git a/src/core/thread/link_metrics.hpp b/src/core/thread/link_metrics.hpp index 742223853..702e7982a 100644 --- a/src/core/thread/link_metrics.hpp +++ b/src/core/thread/link_metrics.hpp @@ -84,6 +84,17 @@ public: typedef otLinkMetricsMgmtResponseCallback MgmtResponseCallback; typedef otLinkMetricsEnhAckProbingIeReportCallback EnhAckProbingIeReportCallback; + /** + * This structure provides the info used for appending MLE Link Metric Query TLV. + * + */ + struct QueryInfo : public Clearable + { + uint8_t mSeriesId; ///< Series ID. + TypeIdFlags mTypeIds[kMaxTypeIdFlags]; ///< Type ID flags. + uint8_t mTypeIdCount; ///< Number of entries in `mTypeIds[]`. + }; + /** * This constructor initializes an instance of the LinkMetrics class. * @@ -264,6 +275,18 @@ public: */ void ProcessEnhAckIeData(const uint8_t *aData, uint8_t aLength, const Neighbor &aNeighbor); + /** + * This method appends MLE Link Metrics Query TLV to a given message. + * + * @param[in] aMessage The message to append to. + * @param[in] aInfo The link metrics query info to use to prepare the message. + * + * @retval kErrorNone Successfully appended the TLV to the message. + * @retval kErrorNoBufs Insufficient buffers available to append the TLV. + * + */ + Error AppendLinkMetricsQueryTlv(Message &aMessage, const QueryInfo &aInfo); + private: // Max number of SeriesInfo that could be allocated by the pool. static constexpr uint16_t kMaxSeriesSupported = OPENTHREAD_CONFIG_MLE_LINK_METRICS_MAX_SERIES_SUPPORTED; @@ -277,11 +300,6 @@ private: static constexpr int32_t kMinRssi = -130; static constexpr int32_t kMaxRssi = 0; - Error SendLinkMetricsQuery(const Ip6::Address &aDestination, - uint8_t aSeriesId, - const TypeIdFlags * aTypeIdFlags, - uint8_t aTypeIdFlagsCount); - Status ConfigureForwardTrackingSeries(uint8_t aSeriesId, uint8_t aSeriesFlags, const Metrics &aMetrics, diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index b277dfd10..286d97abc 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -1797,12 +1797,15 @@ exit: return error; } -Error Mle::SendDataRequest(const Ip6::Address &aDestination, - const uint8_t * aTlvs, - uint8_t aTlvsLength, - uint16_t aDelay, - const uint8_t * aExtraTlvs, - uint8_t aExtraTlvsLength) +#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE +Error Mle::SendDataRequest(const Ip6::Address & aDestination, + const uint8_t * aTlvs, + uint8_t aTlvsLength, + uint16_t aDelay, + const LinkMetrics::LinkMetrics::QueryInfo *aQueryInfo) +#else +Error Mle::SendDataRequest(const Ip6::Address &aDestination, const uint8_t *aTlvs, uint8_t aTlvsLength, uint16_t aDelay) +#endif { Error error = kErrorNone; TxMessage *message; @@ -1812,10 +1815,12 @@ Error Mle::SendDataRequest(const Ip6::Address &aDestination, VerifyOrExit((message = NewMleMessage(kCommandDataRequest)) != nullptr, error = kErrorNoBufs); SuccessOrExit(error = message->AppendTlvRequestTlv(aTlvs, aTlvsLength)); - if (aExtraTlvs != nullptr && aExtraTlvsLength > 0) +#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE + if (aQueryInfo != nullptr) { - SuccessOrExit(error = message->AppendBytes(aExtraTlvs, aExtraTlvsLength)); + SuccessOrExit(error = Get().AppendLinkMetricsQueryTlv(*message, *aQueryInfo)); } +#endif if (aDelay) { diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index 961065026..ec4abe749 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -1447,26 +1447,29 @@ protected: */ Mac::ShortAddress GetNextHop(uint16_t aDestination) const; +#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE /** - * This method generates an MLE Data Request message. + * This method generates an MLE Data Request message which includes a Link Metrics Query TLV. * * @param[in] aDestination A reference to the IPv6 address of the destination. * @param[in] aTlvs A pointer to requested TLV types. * @param[in] aTlvsLength The number of TLV types in @p aTlvs. * @param[in] aDelay Delay in milliseconds before the Data Request message is sent. - * @param[in] aExtraTlvs A pointer to extra TLVs. - * @param[in] aExtraTlvsLength Length of extra TLVs. + * @param[in] aQueryInfo A Link Metrics query info. * * @retval kErrorNone Successfully generated an MLE Data Request message. * @retval kErrorNoBufs Insufficient buffers to generate the MLE Data Request message. * */ - Error SendDataRequest(const Ip6::Address &aDestination, - const uint8_t * aTlvs, - uint8_t aTlvsLength, - uint16_t aDelay, - const uint8_t * aExtraTlvs, - uint8_t aExtraTlvsLength); + Error SendDataRequest(const Ip6::Address & aDestination, + const uint8_t * aTlvs, + uint8_t aTlvsLength, + uint16_t aDelay, + const LinkMetrics::LinkMetrics::QueryInfo &aQueryInfo) + { + return SendDataRequest(aDestination, aTlvs, aTlvsLength, aDelay, &aQueryInfo); + } +#endif /** * This method generates an MLE Data Request message. @@ -1484,7 +1487,7 @@ protected: template Error SendDataRequest(const Ip6::Address &aDestination, const uint8_t (&aTlvs)[kArrayLength], uint16_t aDelay = 0) { - return SendDataRequest(aDestination, aTlvs, kArrayLength, aDelay, nullptr, 0); + return SendDataRequest(aDestination, aTlvs, kArrayLength, aDelay); } /** @@ -1888,6 +1891,16 @@ private: bool IsDetachingGracefully(void) { return mDetachGracefullyTimer.IsRunning(); } Error SendChildUpdateRequest(bool aAppendChallenge, uint32_t aTimeout); +#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE + Error SendDataRequest(const Ip6::Address & aDestination, + const uint8_t * aTlvs, + uint8_t aTlvsLength, + uint16_t aDelay, + const LinkMetrics::LinkMetrics::QueryInfo *aQueryInfo = nullptr); +#else + Error SendDataRequest(const Ip6::Address &aDestination, const uint8_t *aTlvs, uint8_t aTlvsLength, uint16_t aDelay); +#endif + #if OPENTHREAD_FTD static void HandleDetachGracefullyAddressReleaseResponse(void * aContext, otMessage * aMessage,