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/callback.hpp"
50 #include "common/clearable.hpp"
51 #include "common/locator.hpp"
52 #include "common/message.hpp"
53 #include "common/non_copyable.hpp"
54 #include "common/pool.hpp"
55 #include "net/ip6_address.hpp"
56 #include "thread/link_metrics_tlvs.hpp"
57 #include "thread/link_quality.hpp"
58 
59 namespace ot {
60 class Neighbor;
61 class UnitTester;
62 
63 namespace LinkMetrics {
64 
65 /**
66  * @addtogroup core-link-metrics
67  *
68  * @brief
69  *   This module includes definitions for Thread Link Metrics query and management.
70  *
71  * @{
72  */
73 
74 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
75 
76 /**
77  * Implements the Thread Link Metrics Initiator.
78  *
79  * The Initiator makes queries, configures Link Metrics probing at the Subject and generates reports of the results.
80  *
81  */
82 class Initiator : public InstanceLocator, private NonCopyable
83 {
84 public:
85     // Initiator callbacks
86     typedef otLinkMetricsReportCallback                ReportCallback;
87     typedef otLinkMetricsMgmtResponseCallback          MgmtResponseCallback;
88     typedef otLinkMetricsEnhAckProbingIeReportCallback EnhAckProbingIeReportCallback;
89 
90     /**
91      * Provides the info used for appending MLE Link Metric Query TLV.
92      *
93      */
94     struct QueryInfo : public Clearable<QueryInfo>
95     {
96         uint8_t mSeriesId;             ///< Series ID.
97         uint8_t mTypeIds[kMaxTypeIds]; ///< Type IDs.
98         uint8_t mTypeIdCount;          ///< Number of entries in `mTypeIds[]`.
99     };
100 
101     /**
102      * Initializes an instance of the Initiator class.
103      *
104      * @param[in]  aInstance  A reference to the OpenThread interface.
105      *
106      */
107     explicit Initiator(Instance &aInstance);
108 
109     /**
110      * Sends an MLE Data Request containing Link Metrics Query TLV to query Link Metrics data.
111      *
112      * It could be either a Single Probe or a Forward Tracking Series.
113      *
114      * @param[in]  aDestination       A reference to the IPv6 address of the destination.
115      * @param[in]  aSeriesId          The Series ID to query, 0 for single probe.
116      * @param[in]  aMetrics           A pointer to metrics to query.
117      *
118      * @retval kErrorNone             Successfully sent a Link Metrics query message.
119      * @retval kErrorNoBufs           Insufficient buffers to generate the MLE Data Request message.
120      * @retval kErrorInvalidArgs      Type IDs are not valid or exceed the count limit.
121      * @retval kErrorUnknownNeighbor  @p aDestination is not link-local or the neighbor is not found.
122      *
123      */
124     Error Query(const Ip6::Address &aDestination, uint8_t aSeriesId, const Metrics *aMetrics);
125 
126     /**
127      * Appends MLE Link Metrics Query TLV to a given message.
128      *
129      * @param[in] aMessage     The message to append to.
130      * @param[in] aInfo        The link metrics query info to use to prepare the message.
131      *
132      * @retval kErrorNone     Successfully appended the TLV to the message.
133      * @retval kErrorNoBufs   Insufficient buffers available to append the TLV.
134      *
135      */
136     Error AppendLinkMetricsQueryTlv(Message &aMessage, const QueryInfo &aInfo);
137 
138     /**
139      * Registers a callback to handle Link Metrics report received.
140      *
141      * @param[in]  aCallback  A pointer to a function that is called when a Link Metrics report is received.
142      * @param[in]  aContext   A pointer to application-specific context.
143      *
144      */
SetReportCallback(ReportCallback aCallback,void * aContext)145     void SetReportCallback(ReportCallback aCallback, void *aContext) { mReportCallback.Set(aCallback, aContext); }
146 
147     /**
148      * Handles the received Link Metrics report contained in @p aMessage.
149      *
150      * @param[in]  aMessage      A reference to the message.
151      * @param[in]  aOffsetRange  The offset range in @p aMessage where the metrics report sub-TLVs are present.
152      * @param[in]  aAddress      A reference to the source address of the message.
153      *
154      */
155     void HandleReport(const Message &aMessage, OffsetRange &aOffsetRange, const Ip6::Address &aAddress);
156 
157     /**
158      * Sends an MLE Link Metrics Management Request to configure/clear a Forward Tracking Series.
159      *
160      * @param[in] aDestination       A reference to the IPv6 address of the destination.
161      * @param[in] aSeriesId          The Series ID.
162      * @param[in] aSeriesFlags       The Series Flags info which specify what types of frames are to be accounted.
163      * @param[in] aMetrics           A pointer to flags specifying what metrics to query.
164      *
165      * @retval kErrorNone             Successfully sent a Link Metrics Management Request message.
166      * @retval kErrorNoBufs           Insufficient buffers to generate the MLE Link Metrics Management Request message.
167      * @retval kErrorInvalidArgs      @p aSeriesId is not within the valid range.
168      * @retval kErrorUnknownNeighbor  @p aDestination is not link-local or the neighbor is not found.
169      *
170      */
171     Error SendMgmtRequestForwardTrackingSeries(const Ip6::Address &aDestination,
172                                                uint8_t             aSeriesId,
173                                                const SeriesFlags  &aSeriesFlags,
174                                                const Metrics      *aMetrics);
175 
176     /**
177      * Registers a callback to handle Link Metrics Management Response received.
178      *
179      * @param[in]  aCallback A pointer to a function that is called when a Link Metrics Management Response is received.
180      * @param[in]  aContext  A pointer to application-specific context.
181      *
182      */
SetMgmtResponseCallback(MgmtResponseCallback aCallback,void * aContext)183     void SetMgmtResponseCallback(MgmtResponseCallback aCallback, void *aContext)
184     {
185         mMgmtResponseCallback.Set(aCallback, aContext);
186     }
187 
188     /**
189      * Sends an MLE Link Metrics Management Request to configure/clear a Enhanced-ACK Based Probing.
190      *
191      * @param[in] aDestination       A reference to the IPv6 address of the destination.
192      * @param[in] aEnhAckFlags       Enh-ACK Flags to indicate whether to register or clear the probing. `0` to clear
193      *                               and `1` to register. Other values are reserved.
194      * @param[in] aMetrics           A pointer to flags specifying what metrics to query. Should be `nullptr` when
195      *                               `aEnhAckFlags` is `0`.
196      *
197      * @retval kErrorNone             Successfully sent a Link Metrics Management Request message.
198      * @retval kErrorNoBufs           Insufficient buffers to generate the MLE Link Metrics Management Request message.
199      * @retval kErrorInvalidArgs      @p aEnhAckFlags is not a valid value or @p aMetrics isn't correct.
200      * @retval kErrorUnknownNeighbor  @p aDestination is not link-local or the neighbor is not found.
201      *
202      */
203     Error SendMgmtRequestEnhAckProbing(const Ip6::Address &aDestination,
204                                        EnhAckFlags         aEnhAckFlags,
205                                        const Metrics      *aMetrics);
206 
207     /**
208      * Registers a callback to handle Link Metrics when Enh-ACK Probing IE is received.
209      *
210      * @param[in]  aCallback A pointer to a function that is called when Enh-ACK Probing IE is received is received.
211      * @param[in]  aContext  A pointer to application-specific context.
212      *
213      */
SetEnhAckProbingCallback(EnhAckProbingIeReportCallback aCallback,void * aContext)214     void SetEnhAckProbingCallback(EnhAckProbingIeReportCallback aCallback, void *aContext)
215     {
216         mEnhAckProbingIeReportCallback.Set(aCallback, aContext);
217     }
218 
219     /**
220      * Handles the received Link Metrics Management Response contained in @p aMessage.
221      *
222      * @param[in]  aMessage    A reference to the message that contains the Link Metrics Management Response.
223      * @param[in]  aAddress    A reference to the source address of the message.
224      *
225      * @retval kErrorNone     Successfully handled the Link Metrics Management Response.
226      * @retval kErrorParse    Cannot parse sub-TLVs from @p aMessage successfully.
227      *
228      */
229     Error HandleManagementResponse(const Message &aMessage, const Ip6::Address &aAddress);
230 
231     /**
232      * Sends an MLE Link Probe message.
233      *
234      * @param[in] aDestination    A reference to the IPv6 address of the destination.
235      * @param[in] aSeriesId       The Series ID which the Probe message targets at.
236      * @param[in] aLength         The length of the data payload in Link Probe TLV, [0, 64].
237      *
238      * @retval kErrorNone             Successfully sent a Link Probe message.
239      * @retval kErrorNoBufs           Insufficient buffers to generate the MLE Link Probe message.
240      * @retval kErrorInvalidArgs      @p aSeriesId or @p aLength is not within the valid range.
241      * @retval kErrorUnknownNeighbor  @p aDestination is not link-local or the neighbor is not found.
242      *
243      */
244     Error SendLinkProbe(const Ip6::Address &aDestination, uint8_t aSeriesId, uint8_t aLength);
245 
246     /**
247      * Processes received Enh-ACK Probing IE data.
248      *
249      * @param[in] aData      A pointer to buffer containing the Enh-ACK Probing IE data.
250      * @param[in] aLength    The length of @p aData.
251      * @param[in] aNeighbor  The neighbor from which the Enh-ACK Probing IE was received.
252      *
253      */
254     void ProcessEnhAckIeData(const uint8_t *aData, uint8_t aLength, const Neighbor &aNeighbor);
255 
256 private:
257     static constexpr uint8_t kLinkProbeMaxLen = 64; // Max length of data payload in Link Probe TLV.
258 
259     Error FindNeighbor(const Ip6::Address &aDestination, Neighbor *&aNeighbor);
260 
261     Callback<ReportCallback>                mReportCallback;
262     Callback<MgmtResponseCallback>          mMgmtResponseCallback;
263     Callback<EnhAckProbingIeReportCallback> mEnhAckProbingIeReportCallback;
264 };
265 
266 #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
267 
268 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
269 
270 /**
271  * Implements the Thread Link Metrics Subject.
272  *
273  * The Subject responds queries with reports, handles Link Metrics Management Requests and Link Probe Messages.
274  *
275  */
276 class Subject : public InstanceLocator, private NonCopyable
277 {
278 public:
279     typedef otLinkMetricsEnhAckProbingIeReportCallback EnhAckProbingIeReportCallback;
280 
281     /**
282      * Initializes an instance of the Subject class.
283      *
284      * @param[in]  aInstance  A reference to the OpenThread interface.
285      *
286      */
287     explicit Subject(Instance &aInstance);
288 
289     /**
290      * Appends a Link Metrics Report to a message according to the Link Metrics query.
291      *
292      * @param[out]  aMessage           A reference to the message to append report.
293      * @param[in]   aRequestMessage    A reference to the message of the Data Request.
294      * @param[in]   aNeighbor          A reference to the neighbor who queries the report.
295      *
296      * @retval kErrorNone         Successfully appended the Thread Discovery TLV.
297      * @retval kErrorParse        Cannot parse query sub TLV successfully.
298      * @retval kErrorInvalidArgs  QueryId is invalid or any Type ID is invalid.
299      *
300      */
301     Error AppendReport(Message &aMessage, const Message &aRequestMessage, Neighbor &aNeighbor);
302 
303     /**
304      * Handles the received Link Metrics Management Request contained in @p aMessage and return a status.
305      *
306      * @param[in]   aMessage     A reference to the message that contains the Link Metrics Management Request.
307      * @param[in]   aNeighbor    A reference to the neighbor who sends the request.
308      * @param[out]  aStatus      A reference to the status which indicates the handling result.
309      *
310      * @retval kErrorNone     Successfully handled the Link Metrics Management Request.
311      * @retval kErrorParse    Cannot parse sub-TLVs from @p aMessage successfully.
312      *
313      */
314     Error HandleManagementRequest(const Message &aMessage, Neighbor &aNeighbor, Status &aStatus);
315 
316     /**
317      * Handles the Link Probe contained in @p aMessage.
318      *
319      * @param[in]   aMessage     A reference to the message that contains the Link Probe Message.
320      * @param[out]  aSeriesId    A reference to Series ID that parsed from the message.
321      *
322      * @retval kErrorNone     Successfully handled the Link Metrics Management Response.
323      * @retval kErrorParse    Cannot parse sub-TLVs from @p aMessage successfully.
324      *
325      */
326     Error HandleLinkProbe(const Message &aMessage, uint8_t &aSeriesId);
327 
328     /**
329      * Frees a SeriesInfo entry that was allocated from the Subject object.
330      *
331      * @param[in]  aSeries    A reference to the SeriesInfo to free.
332      *
333      */
334     void Free(SeriesInfo &aSeriesInfo);
335 
336 private:
337     // Max number of SeriesInfo that could be allocated by the pool.
338 #if OPENTHREAD_FTD
339     static constexpr uint16_t kMaxSeriesSupported = OPENTHREAD_CONFIG_MLE_LINK_METRICS_MAX_SERIES_SUPPORTED;
340 #elif OPENTHREAD_MTD
341     static constexpr uint16_t kMaxSeriesSupported = OPENTHREAD_CONFIG_MLE_LINK_METRICS_SERIES_MTD;
342 #endif
343 
344     static Error ReadTypeIdsFromMessage(const Message &aMessage, const OffsetRange &aOffsetRange, Metrics &aMetrics);
345     static Error AppendReportSubTlvToMessage(Message &aMessage, const MetricsValues &aValues);
346 
347     Status ConfigureForwardTrackingSeries(uint8_t        aSeriesId,
348                                           uint8_t        aSeriesFlags,
349                                           const Metrics &aMetrics,
350                                           Neighbor      &aNeighbor);
351     Status ConfigureEnhAckProbing(uint8_t aEnhAckFlags, const Metrics &aMetrics, Neighbor &aNeighbor);
352 
353     Pool<SeriesInfo, kMaxSeriesSupported> mSeriesInfoPool;
354 };
355 
356 #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
357 
358 uint8_t ScaleLinkMarginToRawValue(uint8_t aLinkMargin);
359 uint8_t ScaleRawValueToLinkMargin(uint8_t aRawValue);
360 uint8_t ScaleRssiToRawValue(int8_t aRssi);
361 int8_t  ScaleRawValueToRssi(uint8_t aRawValue);
362 
363 /**
364  * @}
365  */
366 
367 } // namespace LinkMetrics
368 } // namespace ot
369 
370 #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
371 
372 #endif // LINK_METRICS_HPP
373