1 /* 2 * Copyright (c) 2020, The OpenThread Authors. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. Neither the name of the copyright holder nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /** 30 * @file 31 * This file includes definitions for Thread Link Metrics query and management. 32 */ 33 34 #ifndef LINK_METRICS_HPP_ 35 #define LINK_METRICS_HPP_ 36 37 #include "openthread-core-config.h" 38 39 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 40 41 #if (OPENTHREAD_CONFIG_THREAD_VERSION < OT_THREAD_VERSION_1_2) 42 #error "Thread 1.2 or higher version is required for OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE" \ 43 "and OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE." 44 #endif 45 46 #include <openthread/link.h> 47 48 #include "common/clearable.hpp" 49 #include "common/locator.hpp" 50 #include "common/message.hpp" 51 #include "common/non_copyable.hpp" 52 #include "common/pool.hpp" 53 #include "net/ip6_address.hpp" 54 #include "thread/link_metrics_tlvs.hpp" 55 #include "thread/link_quality.hpp" 56 57 namespace ot { 58 class Neighbor; 59 60 namespace LinkMetrics { 61 62 /** 63 * @addtogroup core-link-metrics 64 * 65 * @brief 66 * This module includes definitions for Thread Link Metrics query and management. 67 * 68 * @{ 69 */ 70 71 /** 72 * This type represents the results (values) for a set of metrics. 73 * 74 * @sa otLinkMetricsValues. 75 * 76 */ 77 class MetricsValues : public otLinkMetricsValues, public Clearable<MetricsValues> 78 { 79 public: 80 /** 81 * This method gets the metrics flags. 82 * 83 * @returns The metrics flags. 84 * 85 */ GetMetrics(void)86 Metrics &GetMetrics(void) { return static_cast<Metrics &>(mMetrics); } 87 88 /** 89 * This method gets the metrics flags. 90 * 91 * @returns The metrics flags. 92 * 93 */ GetMetrics(void) const94 const Metrics &GetMetrics(void) const { return static_cast<const Metrics &>(mMetrics); } 95 96 /** 97 * This method set the metrics flags. 98 * 99 * @param[in] aMetrics The metrics flags to set from. 100 * 101 */ SetMetrics(const Metrics & aMetrics)102 void SetMetrics(const Metrics &aMetrics) { mMetrics = aMetrics; } 103 }; 104 105 /** 106 * This class represents one Series that is being tracked by the Subject. 107 * 108 * When an Initiator successfully configured a Forward Tracking Series, the Subject would use an instance of this class 109 * to track the information of the Series. The Subject has a `Pool` of `SeriesInfo`. It would allocate one when a new 110 * Series comes, and free it when a Series finishes. 111 * 112 * This class inherits `LinkedListEntry` and each `Neighbor` has a list of `SeriesInfo` so that the Subject could track 113 * per Series initiated by neighbors as long as it has available resources. 114 * 115 */ 116 class SeriesInfo : public LinkedListEntry<SeriesInfo> 117 { 118 friend class LinkedList<SeriesInfo>; 119 friend class LinkedListEntry<SeriesInfo>; 120 121 public: 122 /** 123 * This constant represents Link Probe when filtering frames to be accounted using Series Flag. There's 124 * already `kFcfFrameData`, `kFcfFrameAck` and `kFcfFrameMacCmd`. This item is added so that we can 125 * filter a Link Probe for series in the same way as other frames. 126 * 127 */ 128 static constexpr uint8_t kSeriesTypeLinkProbe = 0; 129 130 /** 131 * This method initializes the SeriesInfo object. 132 * 133 * @param[in] aSeriesId The Series ID. 134 * @param[in] aSeriesFlags The Series Flags which specify what types of frames are to be accounted. 135 * @param[in] aMetrics Metrics to query. 136 * 137 */ 138 void Init(uint8_t aSeriesId, const SeriesFlags &aSeriesFlags, const Metrics &aMetrics); 139 140 /** 141 * This method gets the Series ID. 142 * 143 * @returns The Series ID. 144 * 145 */ GetSeriesId(void) const146 uint8_t GetSeriesId(void) const { return mSeriesId; } 147 148 /** 149 * This method gets the PDU count. 150 * 151 * @returns The PDU count. 152 * 153 */ GetPduCount(void) const154 uint32_t GetPduCount(void) const { return mPduCount; } 155 156 /** 157 * This method gets the average LQI. 158 * 159 * @returns The average LQI. 160 * 161 */ GetAverageLqi(void) const162 uint8_t GetAverageLqi(void) const { return mLqiAverager.GetAverage(); } 163 164 /** 165 * This method gets the average RSS. 166 * 167 * @returns The average RSS. 168 * 169 */ GetAverageRss(void) const170 int8_t GetAverageRss(void) const { return mRssAverager.GetAverage(); } 171 172 /** 173 * This method aggregates the Link Metrics data of a frame into this series. 174 * 175 * @param[in] aFrameType The type of the frame. 176 * @param[in] aLqi The LQI value. 177 * @param[in] aRss The RSS value. 178 * 179 */ 180 void AggregateLinkMetrics(uint8_t aFrameType, uint8_t aLqi, int8_t aRss); 181 182 /** 183 * This methods gets the metrics. 184 * 185 * @returns The metrics associated with `SeriesInfo`. 186 * 187 */ GetLinkMetrics(void) const188 const Metrics &GetLinkMetrics(void) const { return mMetrics; } 189 190 private: Matches(const uint8_t & aSeriesId) const191 bool Matches(const uint8_t &aSeriesId) const { return mSeriesId == aSeriesId; } 192 bool IsFrameTypeMatch(uint8_t aFrameType) const; 193 194 SeriesInfo *mNext; 195 uint8_t mSeriesId; 196 SeriesFlags mSeriesFlags; 197 Metrics mMetrics; 198 RssAverager mRssAverager; 199 LqiAverager mLqiAverager; 200 uint32_t mPduCount; 201 }; 202 203 /** 204 * This enumeration type represent Link Metrics Status. 205 * 206 */ 207 enum Status : uint8_t 208 { 209 kStatusSuccess = OT_LINK_METRICS_STATUS_SUCCESS, 210 kStatusCannotSupportNewSeries = OT_LINK_METRICS_STATUS_CANNOT_SUPPORT_NEW_SERIES, 211 kStatusSeriesIdAlreadyRegistered = OT_LINK_METRICS_STATUS_SERIESID_ALREADY_REGISTERED, 212 kStatusSeriesIdNotRecognized = OT_LINK_METRICS_STATUS_SERIESID_NOT_RECOGNIZED, 213 kStatusNoMatchingFramesReceived = OT_LINK_METRICS_STATUS_NO_MATCHING_FRAMES_RECEIVED, 214 kStatusOtherError = OT_LINK_METRICS_STATUS_OTHER_ERROR, 215 }; 216 217 /** 218 * This class implements Thread Link Metrics query and management. 219 * 220 */ 221 class LinkMetrics : public InstanceLocator, private NonCopyable 222 { 223 friend class ot::Neighbor; 224 225 public: 226 typedef otLinkMetricsReportCallback ReportCallback; 227 typedef otLinkMetricsMgmtResponseCallback MgmtResponseCallback; 228 typedef otLinkMetricsEnhAckProbingIeReportCallback EnhAckProbingIeReportCallback; 229 230 /** 231 * This constructor initializes an instance of the LinkMetrics class. 232 * 233 * @param[in] aInstance A reference to the OpenThread interface. 234 * 235 */ 236 explicit LinkMetrics(Instance &aInstance); 237 238 /** 239 * This method sends an MLE Data Request containing Link Metrics Query TLV to query Link Metrics data. 240 * 241 * It could be either a Single Probe or a Forward Tracking Series. 242 * 243 * @param[in] aDestination A reference to the IPv6 address of the destination. 244 * @param[in] aSeriesId The Series ID to query, 0 for single probe. 245 * @param[in] aMetrics A pointer to metrics to query. 246 * 247 * @retval kErrorNone Successfully sent a Link Metrics query message. 248 * @retval kErrorNoBufs Insufficient buffers to generate the MLE Data Request message. 249 * @retval kErrorInvalidArgs TypeIdFlags are not valid or exceed the count limit. 250 * @retval kErrorUnknownNeighbor @p aDestination is not link-local or the neighbor is not found. 251 * 252 */ 253 Error Query(const Ip6::Address &aDestination, uint8_t aSeriesId, const Metrics *aMetrics); 254 255 /** 256 * This method sends an MLE Link Metrics Management Request to configure/clear a Forward Tracking Series. 257 * 258 * @param[in] aDestination A reference to the IPv6 address of the destination. 259 * @param[in] aSeriesId The Series ID. 260 * @param[in] aSeriesFlags The Series Flags info which specify what types of frames are to be accounted. 261 * @param[in] aMetrics A pointer to flags specifying what metrics to query. 262 * 263 * @retval kErrorNone Successfully sent a Link Metrics Management Request message. 264 * @retval kErrorNoBufs Insufficient buffers to generate the MLE Link Metrics Management Request message. 265 * @retval kErrorInvalidArgs @p aSeriesId is not within the valid range. 266 * @retval kErrorUnknownNeighbor @p aDestination is not link-local or the neighbor is not found. 267 * 268 */ 269 Error SendMgmtRequestForwardTrackingSeries(const Ip6::Address & aDestination, 270 uint8_t aSeriesId, 271 const SeriesFlags::Info &aSeriesFlags, 272 const Metrics * aMetrics); 273 274 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE 275 /** 276 * This method sends an MLE Link Metrics Management Request to configure/clear a Enhanced-ACK Based Probing. 277 * 278 * @param[in] aDestination A reference to the IPv6 address of the destination. 279 * @param[in] aEnhAckFlags Enh-ACK Flags to indicate whether to register or clear the probing. `0` to clear 280 * and `1` to register. Other values are reserved. 281 * @param[in] aMetrics A pointer to flags specifying what metrics to query. Should be `nullptr` when 282 * `aEnhAckFlags` is `0`. 283 * 284 * @retval kErrorNone Successfully sent a Link Metrics Management Request message. 285 * @retval kErrorNoBufs Insufficient buffers to generate the MLE Link Metrics Management Request message. 286 * @retval kErrorInvalidArgs @p aEnhAckFlags is not a valid value or @p aMetrics isn't correct. 287 * @retval kErrorUnknownNeighbor @p aDestination is not link-local or the neighbor is not found. 288 * 289 */ 290 Error SendMgmtRequestEnhAckProbing(const Ip6::Address &aDestination, 291 EnhAckFlags aEnhAckFlags, 292 const Metrics * aMetrics); 293 294 /** 295 * This method sends an MLE Link Probe message. 296 * 297 * @param[in] aDestination A reference to the IPv6 address of the destination. 298 * @param[in] aSeriesId The Series ID which the Probe message targets at. 299 * @param[in] aLength The length of the data payload in Link Probe TLV, [0, 64]. 300 * 301 * @retval kErrorNone Successfully sent a Link Probe message. 302 * @retval kErrorNoBufs Insufficient buffers to generate the MLE Link Probe message. 303 * @retval kErrorInvalidArgs @p aSeriesId or @p aLength is not within the valid range. 304 * @retval kErrorUnknownNeighbor @p aDestination is not link-local or the neighbor is not found. 305 * 306 */ 307 Error SendLinkProbe(const Ip6::Address &aDestination, uint8_t aSeriesId, uint8_t aLength); 308 #endif 309 310 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 311 /** 312 * This method appends a Link Metrics Report to a message according to the Link Metrics query. 313 * 314 * @param[out] aMessage A reference to the message to append report. 315 * @param[in] aRequestMessage A reference to the message of the Data Request. 316 * @param[in] aNeighbor A reference to the neighbor who queries the report. 317 * 318 * @retval kErrorNone Successfully appended the Thread Discovery TLV. 319 * @retval kErrorParse Cannot parse query sub TLV successfully. 320 * @retval kErrorInvalidArgs QueryId is invalid or any Type ID is invalid. 321 * 322 */ 323 Error AppendReport(Message &aMessage, const Message &aRequestMessage, Neighbor &aNeighbor); 324 #endif 325 /** 326 * This method handles the received Link Metrics Management Request contained in @p aMessage and return a status. 327 * 328 * @param[in] aMessage A reference to the message that contains the Link Metrics Management Request. 329 * @param[in] aNeighbor A reference to the neighbor who sends the request. 330 * @param[out] aStatus A reference to the status which indicates the handling result. 331 * 332 * @retval kErrorNone Successfully handled the Link Metrics Management Request. 333 * @retval kErrorParse Cannot parse sub-TLVs from @p aMessage successfully. 334 * 335 */ 336 Error HandleManagementRequest(const Message &aMessage, Neighbor &aNeighbor, Status &aStatus); 337 338 /** 339 * This method handles the received Link Metrics Management Response contained in @p aMessage. 340 * 341 * @param[in] aMessage A reference to the message that contains the Link Metrics Management Response. 342 * @param[in] aAddress A reference to the source address of the message. 343 * 344 * @retval kErrorNone Successfully handled the Link Metrics Management Response. 345 * @retval kErrorParse Cannot parse sub-TLVs from @p aMessage successfully. 346 * 347 */ 348 Error HandleManagementResponse(const Message &aMessage, const Ip6::Address &aAddress); 349 350 /** 351 * This method handles the received Link Metrics report contained in @p aMessage. 352 * 353 * @param[in] aMessage A reference to the message. 354 * @param[in] aOffset The offset in bytes where the metrics report sub-TLVs start. 355 * @param[in] aLength The length of the metrics report sub-TLVs in bytes. 356 * @param[in] aAddress A reference to the source address of the message. 357 * 358 */ 359 void HandleReport(const Message &aMessage, uint16_t aOffset, uint16_t aLength, const Ip6::Address &aAddress); 360 361 /** 362 * This method handles the Link Probe contained in @p aMessage. 363 * 364 * @param[in] aMessage A reference to the message that contains the Link Probe Message. 365 * @param[out] aSeriesId A reference to Series ID that parsed from the message. 366 * 367 * @retval kErrorNone Successfully handled the Link Metrics Management Response. 368 * @retval kErrorParse Cannot parse sub-TLVs from @p aMessage successfully. 369 * 370 */ 371 Error HandleLinkProbe(const Message &aMessage, uint8_t &aSeriesId); 372 373 /** 374 * This method registers a callback to handle Link Metrics report received. 375 * 376 * @param[in] aCallback A pointer to a function that is called when a Link Metrics report is received. 377 * @param[in] aContext A pointer to application-specific context. 378 * 379 */ 380 void SetReportCallback(ReportCallback aCallback, void *aContext); 381 382 /** 383 * This method registers a callback to handle Link Metrics Management Response received. 384 * 385 * @param[in] aCallback A pointer to a function that is called when a Link Metrics Management Response is received. 386 * @param[in] aContext A pointer to application-specific context. 387 * 388 */ 389 void SetMgmtResponseCallback(MgmtResponseCallback aCallback, void *aContext); 390 391 /** 392 * This method registers a callback to handle Link Metrics when Enh-ACK Probing IE is received. 393 * 394 * @param[in] aCallback A pointer to a function that is called when Enh-ACK Probing IE is received is received. 395 * @param[in] aContext A pointer to application-specific context. 396 * 397 */ 398 void SetEnhAckProbingCallback(EnhAckProbingIeReportCallback aCallback, void *aContext); 399 400 /** 401 * This method processes received Enh-ACK Probing IE data. 402 * 403 * @param[in] aData A pointer to buffer containing the Enh-ACK Probing IE data. 404 * @param[in] aLen The length of @p aData. 405 * @param[in] aNeighbor The neighbor from which the Enh-ACK Probing IE was received. 406 * 407 */ 408 void ProcessEnhAckIeData(const uint8_t *aData, uint8_t aLength, const Neighbor &aNeighbor); 409 410 private: 411 static constexpr uint8_t kMaxTypeIdFlags = 4; 412 413 // Max number of SeriesInfo that could be allocated by the pool. 414 static constexpr uint16_t kMaxSeriesSupported = OPENTHREAD_CONFIG_MLE_LINK_METRICS_MAX_SERIES_SUPPORTED; 415 416 static constexpr uint8_t kQueryIdSingleProbe = 0; // This query ID represents Single Probe. 417 static constexpr uint8_t kSeriesIdAllSeries = 255; // This series ID represents all series. 418 static constexpr uint8_t kLinkProbeMaxLen = 64; // Max length of data payload in Link Probe TLV. 419 420 Error SendLinkMetricsQuery(const Ip6::Address &aDestination, 421 uint8_t aSeriesId, 422 const TypeIdFlags * aTypeIdFlags, 423 uint8_t aTypeIdFlagsCount); 424 425 Status ConfigureForwardTrackingSeries(uint8_t aSeriesId, 426 const SeriesFlags &aSeriesFlags, 427 const Metrics & aMetrics, 428 Neighbor & aNeighbor); 429 430 Status ConfigureEnhAckProbing(EnhAckFlags aEnhAckFlags, const Metrics &aMetrics, Neighbor &aNeighbor); 431 432 Neighbor *GetNeighborFromLinkLocalAddr(const Ip6::Address &aDestination); 433 434 static Error ReadTypeIdFlagsFromMessage(const Message &aMessage, 435 uint8_t aStartPos, 436 uint8_t aEndPos, 437 Metrics & aMetrics); 438 static Error AppendReportSubTlvToMessage(Message &aMessage, uint8_t &aLength, const MetricsValues &aValues); 439 static Error AppendStatusSubTlvToMessage(Message &aMessage, uint8_t &aLength, Status aStatus); 440 441 ReportCallback mReportCallback; 442 void * mReportCallbackContext; 443 MgmtResponseCallback mMgmtResponseCallback; 444 void * mMgmtResponseCallbackContext; 445 EnhAckProbingIeReportCallback mEnhAckProbingIeReportCallback; 446 void * mEnhAckProbingIeReportCallbackContext; 447 448 Pool<SeriesInfo, kMaxSeriesSupported> mSeriesInfoPool; 449 }; 450 451 /** 452 * @} 453 */ 454 455 } // namespace LinkMetrics 456 } // namespace ot 457 458 #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 459 460 #endif // LINK_METRICS_HPP 461