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/as_core_type.hpp" 49 #include "common/clearable.hpp" 50 #include "common/locator.hpp" 51 #include "common/message.hpp" 52 #include "common/non_copyable.hpp" 53 #include "common/pool.hpp" 54 #include "net/ip6_address.hpp" 55 #include "thread/link_metrics_tlvs.hpp" 56 #include "thread/link_quality.hpp" 57 58 namespace ot { 59 class Neighbor; 60 61 namespace LinkMetrics { 62 63 /** 64 * @addtogroup core-link-metrics 65 * 66 * @brief 67 * This module includes definitions for Thread Link Metrics query and management. 68 * 69 * @{ 70 */ 71 72 /** 73 * This type represents the results (values) for a set of metrics. 74 * 75 * @sa otLinkMetricsValues. 76 * 77 */ 78 class MetricsValues : public otLinkMetricsValues, public Clearable<MetricsValues> 79 { 80 public: 81 /** 82 * This method gets the metrics flags. 83 * 84 * @returns The metrics flags. 85 * 86 */ GetMetrics(void)87 Metrics &GetMetrics(void) { return static_cast<Metrics &>(mMetrics); } 88 89 /** 90 * This method gets the metrics flags. 91 * 92 * @returns The metrics flags. 93 * 94 */ GetMetrics(void) const95 const Metrics &GetMetrics(void) const { return static_cast<const Metrics &>(mMetrics); } 96 97 /** 98 * This method set the metrics flags. 99 * 100 * @param[in] aMetrics The metrics flags to set from. 101 * 102 */ SetMetrics(const Metrics & aMetrics)103 void SetMetrics(const Metrics &aMetrics) { mMetrics = aMetrics; } 104 }; 105 106 /** 107 * This class represents one Series that is being tracked by the Subject. 108 * 109 * When an Initiator successfully configured a Forward Tracking Series, the Subject would use an instance of this class 110 * to track the information of the Series. The Subject has a `Pool` of `SeriesInfo`. It would allocate one when a new 111 * Series comes, and free it when a Series finishes. 112 * 113 * This class inherits `LinkedListEntry` and each `Neighbor` has a list of `SeriesInfo` so that the Subject could track 114 * per Series initiated by neighbors as long as it has available resources. 115 * 116 */ 117 class SeriesInfo : public LinkedListEntry<SeriesInfo> 118 { 119 friend class LinkedList<SeriesInfo>; 120 friend class LinkedListEntry<SeriesInfo>; 121 122 public: 123 /** 124 * This constant represents Link Probe when filtering frames to be accounted using Series Flag. There's 125 * already `kFcfFrameData`, `kFcfFrameAck` and `kFcfFrameMacCmd`. This item is added so that we can 126 * filter a Link Probe for series in the same way as other frames. 127 * 128 */ 129 static constexpr uint8_t kSeriesTypeLinkProbe = 0; 130 131 /** 132 * This method initializes the SeriesInfo object. 133 * 134 * @param[in] aSeriesId The Series ID. 135 * @param[in] aSeriesFlags The Series Flags which specify what types of frames are to be accounted. 136 * @param[in] aMetrics Metrics to query. 137 * 138 */ 139 void Init(uint8_t aSeriesId, const SeriesFlags &aSeriesFlags, const Metrics &aMetrics); 140 141 /** 142 * This method gets the Series ID. 143 * 144 * @returns The Series ID. 145 * 146 */ GetSeriesId(void) const147 uint8_t GetSeriesId(void) const { return mSeriesId; } 148 149 /** 150 * This method gets the PDU count. 151 * 152 * @returns The PDU count. 153 * 154 */ GetPduCount(void) const155 uint32_t GetPduCount(void) const { return mPduCount; } 156 157 /** 158 * This method gets the average LQI. 159 * 160 * @returns The average LQI. 161 * 162 */ GetAverageLqi(void) const163 uint8_t GetAverageLqi(void) const { return mLqiAverager.GetAverage(); } 164 165 /** 166 * This method gets the average RSS. 167 * 168 * @returns The average RSS. 169 * 170 */ GetAverageRss(void) const171 int8_t GetAverageRss(void) const { return mRssAverager.GetAverage(); } 172 173 /** 174 * This method aggregates the Link Metrics data of a frame into this series. 175 * 176 * @param[in] aFrameType The type of the frame. 177 * @param[in] aLqi The LQI value. 178 * @param[in] aRss The RSS value. 179 * 180 */ 181 void AggregateLinkMetrics(uint8_t aFrameType, uint8_t aLqi, int8_t aRss); 182 183 /** 184 * This methods gets the metrics. 185 * 186 * @returns The metrics associated with `SeriesInfo`. 187 * 188 */ GetLinkMetrics(void) const189 const Metrics &GetLinkMetrics(void) const { return mMetrics; } 190 191 private: Matches(const uint8_t & aSeriesId) const192 bool Matches(const uint8_t &aSeriesId) const { return mSeriesId == aSeriesId; } 193 bool IsFrameTypeMatch(uint8_t aFrameType) const; 194 195 SeriesInfo *mNext; 196 uint8_t mSeriesId; 197 SeriesFlags mSeriesFlags; 198 Metrics mMetrics; 199 RssAverager mRssAverager; 200 LqiAverager mLqiAverager; 201 uint32_t mPduCount; 202 }; 203 204 /** 205 * This enumeration type represent Link Metrics Status. 206 * 207 */ 208 enum Status : uint8_t 209 { 210 kStatusSuccess = OT_LINK_METRICS_STATUS_SUCCESS, 211 kStatusCannotSupportNewSeries = OT_LINK_METRICS_STATUS_CANNOT_SUPPORT_NEW_SERIES, 212 kStatusSeriesIdAlreadyRegistered = OT_LINK_METRICS_STATUS_SERIESID_ALREADY_REGISTERED, 213 kStatusSeriesIdNotRecognized = OT_LINK_METRICS_STATUS_SERIESID_NOT_RECOGNIZED, 214 kStatusNoMatchingFramesReceived = OT_LINK_METRICS_STATUS_NO_MATCHING_FRAMES_RECEIVED, 215 kStatusOtherError = OT_LINK_METRICS_STATUS_OTHER_ERROR, 216 }; 217 218 /** 219 * This class implements Thread Link Metrics query and management. 220 * 221 */ 222 class LinkMetrics : public InstanceLocator, private NonCopyable 223 { 224 friend class ot::Neighbor; 225 226 public: 227 typedef otLinkMetricsReportCallback ReportCallback; 228 typedef otLinkMetricsMgmtResponseCallback MgmtResponseCallback; 229 typedef otLinkMetricsEnhAckProbingIeReportCallback EnhAckProbingIeReportCallback; 230 231 /** 232 * This constructor initializes an instance of the LinkMetrics class. 233 * 234 * @param[in] aInstance A reference to the OpenThread interface. 235 * 236 */ 237 explicit LinkMetrics(Instance &aInstance); 238 239 /** 240 * This method sends an MLE Data Request containing Link Metrics Query TLV to query Link Metrics data. 241 * 242 * It could be either a Single Probe or a Forward Tracking Series. 243 * 244 * @param[in] aDestination A reference to the IPv6 address of the destination. 245 * @param[in] aSeriesId The Series ID to query, 0 for single probe. 246 * @param[in] aMetrics A pointer to metrics to query. 247 * 248 * @retval kErrorNone Successfully sent a Link Metrics query message. 249 * @retval kErrorNoBufs Insufficient buffers to generate the MLE Data Request message. 250 * @retval kErrorInvalidArgs TypeIdFlags are not valid or exceed the count limit. 251 * @retval kErrorUnknownNeighbor @p aDestination is not link-local or the neighbor is not found. 252 * 253 */ 254 Error Query(const Ip6::Address &aDestination, uint8_t aSeriesId, const Metrics *aMetrics); 255 256 /** 257 * This method sends an MLE Link Metrics Management Request to configure/clear a Forward Tracking Series. 258 * 259 * @param[in] aDestination A reference to the IPv6 address of the destination. 260 * @param[in] aSeriesId The Series ID. 261 * @param[in] aSeriesFlags The Series Flags info which specify what types of frames are to be accounted. 262 * @param[in] aMetrics A pointer to flags specifying what metrics to query. 263 * 264 * @retval kErrorNone Successfully sent a Link Metrics Management Request message. 265 * @retval kErrorNoBufs Insufficient buffers to generate the MLE Link Metrics Management Request message. 266 * @retval kErrorInvalidArgs @p aSeriesId is not within the valid range. 267 * @retval kErrorUnknownNeighbor @p aDestination is not link-local or the neighbor is not found. 268 * 269 */ 270 Error SendMgmtRequestForwardTrackingSeries(const Ip6::Address & aDestination, 271 uint8_t aSeriesId, 272 const SeriesFlags::Info &aSeriesFlags, 273 const Metrics * aMetrics); 274 275 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE 276 /** 277 * This method sends an MLE Link Metrics Management Request to configure/clear a Enhanced-ACK Based Probing. 278 * 279 * @param[in] aDestination A reference to the IPv6 address of the destination. 280 * @param[in] aEnhAckFlags Enh-ACK Flags to indicate whether to register or clear the probing. `0` to clear 281 * and `1` to register. Other values are reserved. 282 * @param[in] aMetrics A pointer to flags specifying what metrics to query. Should be `nullptr` when 283 * `aEnhAckFlags` is `0`. 284 * 285 * @retval kErrorNone Successfully sent a Link Metrics Management Request message. 286 * @retval kErrorNoBufs Insufficient buffers to generate the MLE Link Metrics Management Request message. 287 * @retval kErrorInvalidArgs @p aEnhAckFlags is not a valid value or @p aMetrics isn't correct. 288 * @retval kErrorUnknownNeighbor @p aDestination is not link-local or the neighbor is not found. 289 * 290 */ 291 Error SendMgmtRequestEnhAckProbing(const Ip6::Address &aDestination, 292 EnhAckFlags aEnhAckFlags, 293 const Metrics * aMetrics); 294 295 /** 296 * This method sends an MLE Link Probe message. 297 * 298 * @param[in] aDestination A reference to the IPv6 address of the destination. 299 * @param[in] aSeriesId The Series ID which the Probe message targets at. 300 * @param[in] aLength The length of the data payload in Link Probe TLV, [0, 64]. 301 * 302 * @retval kErrorNone Successfully sent a Link Probe message. 303 * @retval kErrorNoBufs Insufficient buffers to generate the MLE Link Probe message. 304 * @retval kErrorInvalidArgs @p aSeriesId or @p aLength is not within the valid range. 305 * @retval kErrorUnknownNeighbor @p aDestination is not link-local or the neighbor is not found. 306 * 307 */ 308 Error SendLinkProbe(const Ip6::Address &aDestination, uint8_t aSeriesId, uint8_t aLength); 309 #endif 310 311 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 312 /** 313 * This method appends a Link Metrics Report to a message according to the Link Metrics query. 314 * 315 * @param[out] aMessage A reference to the message to append report. 316 * @param[in] aRequestMessage A reference to the message of the Data Request. 317 * @param[in] aNeighbor A reference to the neighbor who queries the report. 318 * 319 * @retval kErrorNone Successfully appended the Thread Discovery TLV. 320 * @retval kErrorParse Cannot parse query sub TLV successfully. 321 * @retval kErrorInvalidArgs QueryId is invalid or any Type ID is invalid. 322 * 323 */ 324 Error AppendReport(Message &aMessage, const Message &aRequestMessage, Neighbor &aNeighbor); 325 #endif 326 /** 327 * This method handles the received Link Metrics Management Request contained in @p aMessage and return a status. 328 * 329 * @param[in] aMessage A reference to the message that contains the Link Metrics Management Request. 330 * @param[in] aNeighbor A reference to the neighbor who sends the request. 331 * @param[out] aStatus A reference to the status which indicates the handling result. 332 * 333 * @retval kErrorNone Successfully handled the Link Metrics Management Request. 334 * @retval kErrorParse Cannot parse sub-TLVs from @p aMessage successfully. 335 * 336 */ 337 Error HandleManagementRequest(const Message &aMessage, Neighbor &aNeighbor, Status &aStatus); 338 339 /** 340 * This method handles the received Link Metrics Management Response contained in @p aMessage. 341 * 342 * @param[in] aMessage A reference to the message that contains the Link Metrics Management Response. 343 * @param[in] aAddress A reference to the source address of the message. 344 * 345 * @retval kErrorNone Successfully handled the Link Metrics Management Response. 346 * @retval kErrorParse Cannot parse sub-TLVs from @p aMessage successfully. 347 * 348 */ 349 Error HandleManagementResponse(const Message &aMessage, const Ip6::Address &aAddress); 350 351 /** 352 * This method handles the received Link Metrics report contained in @p aMessage. 353 * 354 * @param[in] aMessage A reference to the message. 355 * @param[in] aOffset The offset in bytes where the metrics report sub-TLVs start. 356 * @param[in] aLength The length of the metrics report sub-TLVs in bytes. 357 * @param[in] aAddress A reference to the source address of the message. 358 * 359 */ 360 void HandleReport(const Message &aMessage, uint16_t aOffset, uint16_t aLength, const Ip6::Address &aAddress); 361 362 /** 363 * This method handles the Link Probe contained in @p aMessage. 364 * 365 * @param[in] aMessage A reference to the message that contains the Link Probe Message. 366 * @param[out] aSeriesId A reference to Series ID that parsed from the message. 367 * 368 * @retval kErrorNone Successfully handled the Link Metrics Management Response. 369 * @retval kErrorParse Cannot parse sub-TLVs from @p aMessage successfully. 370 * 371 */ 372 Error HandleLinkProbe(const Message &aMessage, uint8_t &aSeriesId); 373 374 /** 375 * This method registers a callback to handle Link Metrics report received. 376 * 377 * @param[in] aCallback A pointer to a function that is called when a Link Metrics report is received. 378 * @param[in] aContext A pointer to application-specific context. 379 * 380 */ 381 void SetReportCallback(ReportCallback aCallback, void *aContext); 382 383 /** 384 * This method registers a callback to handle Link Metrics Management Response received. 385 * 386 * @param[in] aCallback A pointer to a function that is called when a Link Metrics Management Response is received. 387 * @param[in] aContext A pointer to application-specific context. 388 * 389 */ 390 void SetMgmtResponseCallback(MgmtResponseCallback aCallback, void *aContext); 391 392 /** 393 * This method registers a callback to handle Link Metrics when Enh-ACK Probing IE is received. 394 * 395 * @param[in] aCallback A pointer to a function that is called when Enh-ACK Probing IE is received is received. 396 * @param[in] aContext A pointer to application-specific context. 397 * 398 */ 399 void SetEnhAckProbingCallback(EnhAckProbingIeReportCallback aCallback, void *aContext); 400 401 /** 402 * This method processes received Enh-ACK Probing IE data. 403 * 404 * @param[in] aData A pointer to buffer containing the Enh-ACK Probing IE data. 405 * @param[in] aLength The length of @p aData. 406 * @param[in] aNeighbor The neighbor from which the Enh-ACK Probing IE was received. 407 * 408 */ 409 void ProcessEnhAckIeData(const uint8_t *aData, uint8_t aLength, const Neighbor &aNeighbor); 410 411 private: 412 static constexpr uint8_t kMaxTypeIdFlags = 4; 413 414 // Max number of SeriesInfo that could be allocated by the pool. 415 static constexpr uint16_t kMaxSeriesSupported = OPENTHREAD_CONFIG_MLE_LINK_METRICS_MAX_SERIES_SUPPORTED; 416 417 static constexpr uint8_t kQueryIdSingleProbe = 0; // This query ID represents Single Probe. 418 static constexpr uint8_t kSeriesIdAllSeries = 255; // This series ID represents all series. 419 static constexpr uint8_t kLinkProbeMaxLen = 64; // Max length of data payload in Link Probe TLV. 420 421 Error SendLinkMetricsQuery(const Ip6::Address &aDestination, 422 uint8_t aSeriesId, 423 const TypeIdFlags * aTypeIdFlags, 424 uint8_t aTypeIdFlagsCount); 425 426 Status ConfigureForwardTrackingSeries(uint8_t aSeriesId, 427 const SeriesFlags &aSeriesFlags, 428 const Metrics & aMetrics, 429 Neighbor & aNeighbor); 430 431 Status ConfigureEnhAckProbing(EnhAckFlags aEnhAckFlags, const Metrics &aMetrics, Neighbor &aNeighbor); 432 433 Neighbor *GetNeighborFromLinkLocalAddr(const Ip6::Address &aDestination); 434 435 static Error ReadTypeIdFlagsFromMessage(const Message &aMessage, 436 uint8_t aStartPos, 437 uint8_t aEndPos, 438 Metrics & aMetrics); 439 static Error AppendReportSubTlvToMessage(Message &aMessage, uint8_t &aLength, const MetricsValues &aValues); 440 static Error AppendStatusSubTlvToMessage(Message &aMessage, uint8_t &aLength, Status aStatus); 441 442 ReportCallback mReportCallback; 443 void * mReportCallbackContext; 444 MgmtResponseCallback mMgmtResponseCallback; 445 void * mMgmtResponseCallbackContext; 446 EnhAckProbingIeReportCallback mEnhAckProbingIeReportCallback; 447 void * mEnhAckProbingIeReportCallbackContext; 448 449 Pool<SeriesInfo, kMaxSeriesSupported> mSeriesInfoPool; 450 }; 451 452 /** 453 * @} 454 */ 455 456 } // namespace LinkMetrics 457 458 DefineCoreType(otLinkMetrics, LinkMetrics::Metrics); 459 DefineCoreType(otLinkMetricsValues, LinkMetrics::MetricsValues); 460 DefineMapEnum(otLinkMetricsEnhAckFlags, LinkMetrics::EnhAckFlags); 461 462 } // namespace ot 463 464 #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 465 466 #endif // LINK_METRICS_HPP 467