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  * This class 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      * This structure 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      * This constructor 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      * This method 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      * This method 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      * This method 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      * This method handles the received Link Metrics report contained in @p aMessage.
149      *
150      * @param[in]  aMessage      A reference to the message.
151      * @param[in]  aOffset       The offset in bytes where the metrics report sub-TLVs start.
152      * @param[in]  aLength       The length of the metrics report sub-TLVs in bytes.
153      * @param[in]  aAddress      A reference to the source address of the message.
154      *
155      */
156     void HandleReport(const Message &aMessage, uint16_t aOffset, uint16_t aLength, const Ip6::Address &aAddress);
157 
158     /**
159      * This method sends an MLE Link Metrics Management Request to configure/clear a Forward Tracking Series.
160      *
161      * @param[in] aDestination       A reference to the IPv6 address of the destination.
162      * @param[in] aSeriesId          The Series ID.
163      * @param[in] aSeriesFlags       The Series Flags info which specify what types of frames are to be accounted.
164      * @param[in] aMetrics           A pointer to flags specifying what metrics to query.
165      *
166      * @retval kErrorNone             Successfully sent a Link Metrics Management Request message.
167      * @retval kErrorNoBufs           Insufficient buffers to generate the MLE Link Metrics Management Request message.
168      * @retval kErrorInvalidArgs      @p aSeriesId is not within the valid range.
169      * @retval kErrorUnknownNeighbor  @p aDestination is not link-local or the neighbor is not found.
170      *
171      */
172     Error SendMgmtRequestForwardTrackingSeries(const Ip6::Address &aDestination,
173                                                uint8_t             aSeriesId,
174                                                const SeriesFlags  &aSeriesFlags,
175                                                const Metrics      *aMetrics);
176 
177     /**
178      * This method registers a callback to handle Link Metrics Management Response received.
179      *
180      * @param[in]  aCallback A pointer to a function that is called when a Link Metrics Management Response is received.
181      * @param[in]  aContext  A pointer to application-specific context.
182      *
183      */
SetMgmtResponseCallback(MgmtResponseCallback aCallback,void * aContext)184     void SetMgmtResponseCallback(MgmtResponseCallback aCallback, void *aContext)
185     {
186         mMgmtResponseCallback.Set(aCallback, aContext);
187     }
188 
189     /**
190      * This method sends an MLE Link Metrics Management Request to configure/clear a Enhanced-ACK Based Probing.
191      *
192      * @param[in] aDestination       A reference to the IPv6 address of the destination.
193      * @param[in] aEnhAckFlags       Enh-ACK Flags to indicate whether to register or clear the probing. `0` to clear
194      *                               and `1` to register. Other values are reserved.
195      * @param[in] aMetrics           A pointer to flags specifying what metrics to query. Should be `nullptr` when
196      *                               `aEnhAckFlags` is `0`.
197      *
198      * @retval kErrorNone             Successfully sent a Link Metrics Management Request message.
199      * @retval kErrorNoBufs           Insufficient buffers to generate the MLE Link Metrics Management Request message.
200      * @retval kErrorInvalidArgs      @p aEnhAckFlags is not a valid value or @p aMetrics isn't correct.
201      * @retval kErrorUnknownNeighbor  @p aDestination is not link-local or the neighbor is not found.
202      *
203      */
204     Error SendMgmtRequestEnhAckProbing(const Ip6::Address &aDestination,
205                                        EnhAckFlags         aEnhAckFlags,
206                                        const Metrics      *aMetrics);
207 
208     /**
209      * This method registers a callback to handle Link Metrics when Enh-ACK Probing IE is received.
210      *
211      * @param[in]  aCallback A pointer to a function that is called when Enh-ACK Probing IE is received is received.
212      * @param[in]  aContext  A pointer to application-specific context.
213      *
214      */
SetEnhAckProbingCallback(EnhAckProbingIeReportCallback aCallback,void * aContext)215     void SetEnhAckProbingCallback(EnhAckProbingIeReportCallback aCallback, void *aContext)
216     {
217         mEnhAckProbingIeReportCallback.Set(aCallback, aContext);
218     }
219 
220     /**
221      * This method handles the received Link Metrics Management Response contained in @p aMessage.
222      *
223      * @param[in]  aMessage    A reference to the message that contains the Link Metrics Management Response.
224      * @param[in]  aAddress    A reference to the source address of the message.
225      *
226      * @retval kErrorNone     Successfully handled the Link Metrics Management Response.
227      * @retval kErrorParse    Cannot parse sub-TLVs from @p aMessage successfully.
228      *
229      */
230     Error HandleManagementResponse(const Message &aMessage, const Ip6::Address &aAddress);
231 
232     /**
233      * This method sends an MLE Link Probe message.
234      *
235      * @param[in] aDestination    A reference to the IPv6 address of the destination.
236      * @param[in] aSeriesId       The Series ID which the Probe message targets at.
237      * @param[in] aLength         The length of the data payload in Link Probe TLV, [0, 64].
238      *
239      * @retval kErrorNone             Successfully sent a Link Probe message.
240      * @retval kErrorNoBufs           Insufficient buffers to generate the MLE Link Probe message.
241      * @retval kErrorInvalidArgs      @p aSeriesId or @p aLength is not within the valid range.
242      * @retval kErrorUnknownNeighbor  @p aDestination is not link-local or the neighbor is not found.
243      *
244      */
245     Error SendLinkProbe(const Ip6::Address &aDestination, uint8_t aSeriesId, uint8_t aLength);
246 
247     /**
248      * This method processes received Enh-ACK Probing IE data.
249      *
250      * @param[in] aData      A pointer to buffer containing the Enh-ACK Probing IE data.
251      * @param[in] aLength    The length of @p aData.
252      * @param[in] aNeighbor  The neighbor from which the Enh-ACK Probing IE was received.
253      *
254      */
255     void ProcessEnhAckIeData(const uint8_t *aData, uint8_t aLength, const Neighbor &aNeighbor);
256 
257 private:
258     static constexpr uint8_t kLinkProbeMaxLen = 64; // Max length of data payload in Link Probe TLV.
259 
260     Error FindNeighbor(const Ip6::Address &aDestination, Neighbor *&aNeighbor);
261 
262     Callback<ReportCallback>                mReportCallback;
263     Callback<MgmtResponseCallback>          mMgmtResponseCallback;
264     Callback<EnhAckProbingIeReportCallback> mEnhAckProbingIeReportCallback;
265 };
266 
267 #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
268 
269 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
270 
271 /**
272  * This class implements the Thread Link Metrics Subject.
273  *
274  * The Subject reponds queries with reports, handles Link Metrics Management Requests and Link Probe Messages.
275  *
276  */
277 class Subject : public InstanceLocator, private NonCopyable
278 {
279 public:
280     typedef otLinkMetricsEnhAckProbingIeReportCallback EnhAckProbingIeReportCallback;
281 
282     /**
283      * This constructor initializes an instance of the Subject class.
284      *
285      * @param[in]  aInstance  A reference to the OpenThread interface.
286      *
287      */
288     explicit Subject(Instance &aInstance);
289 
290     /**
291      * This method appends a Link Metrics Report to a message according to the Link Metrics query.
292      *
293      * @param[out]  aMessage           A reference to the message to append report.
294      * @param[in]   aRequestMessage    A reference to the message of the Data Request.
295      * @param[in]   aNeighbor          A reference to the neighbor who queries the report.
296      *
297      * @retval kErrorNone         Successfully appended the Thread Discovery TLV.
298      * @retval kErrorParse        Cannot parse query sub TLV successfully.
299      * @retval kErrorInvalidArgs  QueryId is invalid or any Type ID is invalid.
300      *
301      */
302     Error AppendReport(Message &aMessage, const Message &aRequestMessage, Neighbor &aNeighbor);
303 
304     /**
305      * This method handles the received Link Metrics Management Request contained in @p aMessage and return a status.
306      *
307      * @param[in]   aMessage     A reference to the message that contains the Link Metrics Management Request.
308      * @param[in]   aNeighbor    A reference to the neighbor who sends the request.
309      * @param[out]  aStatus      A reference to the status which indicates the handling result.
310      *
311      * @retval kErrorNone     Successfully handled the Link Metrics Management Request.
312      * @retval kErrorParse    Cannot parse sub-TLVs from @p aMessage successfully.
313      *
314      */
315     Error HandleManagementRequest(const Message &aMessage, Neighbor &aNeighbor, Status &aStatus);
316 
317     /**
318      * This method handles the Link Probe contained in @p aMessage.
319      *
320      * @param[in]   aMessage     A reference to the message that contains the Link Probe Message.
321      * @param[out]  aSeriesId    A reference to Series ID that parsed from the message.
322      *
323      * @retval kErrorNone     Successfully handled the Link Metrics Management Response.
324      * @retval kErrorParse    Cannot parse sub-TLVs from @p aMessage successfully.
325      *
326      */
327     Error HandleLinkProbe(const Message &aMessage, uint8_t &aSeriesId);
328 
329     /**
330      * This method frees a SeriesInfo entry that was allocated from the Subject object.
331      *
332      * @param[in]  aSeries    A reference to the SeriesInfo to free.
333      *
334      */
335     void Free(SeriesInfo &aSeriesInfo);
336 
337 private:
338     // Max number of SeriesInfo that could be allocated by the pool.
339     static constexpr uint16_t kMaxSeriesSupported = OPENTHREAD_CONFIG_MLE_LINK_METRICS_MAX_SERIES_SUPPORTED;
340 
341     static Error ReadTypeIdsFromMessage(const Message &aMessage,
342                                         uint16_t       aStartOffset,
343                                         uint16_t       aEndOffset,
344                                         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