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 generating and processing Link Metrics TLVs.
32  *
33  */
34 
35 #ifndef LINK_METRICS_TLVS_HPP_
36 #define LINK_METRICS_TLVS_HPP_
37 
38 #include "openthread-core-config.h"
39 
40 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
41 
42 #include <openthread/link_metrics.h>
43 
44 #include "common/clearable.hpp"
45 #include "common/encoding.hpp"
46 #include "common/message.hpp"
47 #include "common/tlvs.hpp"
48 
49 namespace ot {
50 namespace LinkMetrics {
51 
52 /**
53  * This type represents Link Metric Flags indicating a set of metrics.
54  *
55  * @sa otLinkMetrics
56  *
57  */
58 class Metrics : public otLinkMetrics, public Clearable<Metrics>
59 {
60 };
61 
62 /**
63  * This class defines constants related to Link Metrics Sub-TLVs.
64  *
65  */
66 class SubTlv
67 {
68 public:
69     /**
70      * Link Metrics Sub-TLV types.
71      *
72      */
73     enum Type : uint8_t
74     {
75         kReport        = 0, ///< Report Sub-TLV
76         kQueryId       = 1, ///< Query ID Sub-TLV
77         kQueryOptions  = 2, ///< Query Options Sub-TLV
78         kFwdProbingReg = 3, ///< Forward Probing Registration Sub-TLV
79         kStatus        = 5, ///< Status Sub-TLV
80         kEnhAckConfig  = 7, ///< Enhanced ACK Configuration Sub-TLV
81     };
82 };
83 
84 /**
85  * This class defines Link Metrics Query ID Sub-TLV constants and types.
86  *
87  */
88 typedef UintTlvInfo<SubTlv::kQueryId, uint8_t> QueryIdSubTlv;
89 
90 /**
91  * This class implements Link Metrics Type ID Flags generation and parsing.
92  *
93  */
94 OT_TOOL_PACKED_BEGIN class TypeIdFlags
95 {
96     static constexpr uint8_t kExtendedFlag     = 1 << 7;
97     static constexpr uint8_t kLengthOffset     = 6;
98     static constexpr uint8_t kLengthFlag       = 1 << kLengthOffset;
99     static constexpr uint8_t kTypeEnumOffset   = 3;
100     static constexpr uint8_t kTypeEnumMask     = 7 << kTypeEnumOffset;
101     static constexpr uint8_t kMetricEnumOffset = 0;
102     static constexpr uint8_t kMetricEnumMask   = 7 << kMetricEnumOffset;
103 
104 public:
105     /**
106      * This enumeration specifies the Length field in Type ID Flags.
107      *
108      */
109     enum Length
110     {
111         kShortLength    = 0, ///< Short value length (1 byte value)
112         kExtendedLength = 1, ///< Extended value length (4 bytes value)
113     };
114 
115     /**
116      * This enumeration specifies the Type values in Type ID Flags.
117      *
118      */
119     enum TypeEnum : uint8_t
120     {
121         kTypeCountSummation   = 0, ///< Count or summation
122         kTypeExpMovingAverage = 1, ///< Exponential moving average.
123         kTypeReserved         = 2, ///< Reserved for future use.
124     };
125 
126     /**
127      * This enumeration specifies the Metric values in Type ID Flag.
128      *
129      */
130     enum MetricEnum : uint8_t
131     {
132         kMetricPdusReceived = 0, ///< Number of PDUs received.
133         kMetricLqi          = 1, ///< Link Quality Indicator.
134         kMetricLinkMargin   = 2, ///< Link Margin.
135         kMetricRssi         = 3, ///< RSSI in dbm.
136     };
137 
138     /**
139      * This constant defines the raw value for Type ID Flag for PDU.
140      *
141      */
142     static constexpr uint8_t kPdu = (kExtendedLength << kLengthOffset) | (kTypeCountSummation << kTypeEnumOffset) |
143                                     (kMetricPdusReceived << kMetricEnumOffset);
144 
145     /**
146      * This constant defines the raw value for Type ID Flag for LQI.
147      *
148      */
149     static constexpr uint8_t kLqi = (kShortLength << kLengthOffset) | (kTypeExpMovingAverage << kTypeEnumOffset) |
150                                     (kMetricLqi << kMetricEnumOffset);
151 
152     /**
153      * This constant defines the raw value for Type ID Flag for Link Margin.
154      *
155      */
156     static constexpr uint8_t kLinkMargin = (kShortLength << kLengthOffset) |
157                                            (kTypeExpMovingAverage << kTypeEnumOffset) |
158                                            (kMetricLinkMargin << kMetricEnumOffset);
159 
160     /**
161      * This constant defines the raw value for Type ID Flag for RSSI
162      *
163      */
164     static constexpr uint8_t kRssi = (kShortLength << kLengthOffset) | (kTypeExpMovingAverage << kTypeEnumOffset) |
165                                      (kMetricRssi << kMetricEnumOffset);
166 
167     /**
168      * Default constructor.
169      *
170      */
171     TypeIdFlags(void) = default;
172 
173     /**
174      * Constructor to initialize from raw value.
175      *
176      * @param[in] aFlags  The raw flags value.
177      *
178      */
TypeIdFlags(uint8_t aFlags)179     explicit TypeIdFlags(uint8_t aFlags)
180         : mFlags(aFlags)
181     {
182     }
183 
184     /**
185      * This method initializes the Type ID value
186      *
187      */
Init(void)188     void Init(void) { mFlags = 0; }
189 
190     /**
191      * This method clears the Extended flag.
192      *
193      */
ClearExtendedFlag(void)194     void ClearExtendedFlag(void) { mFlags &= ~kExtendedFlag; }
195 
196     /**
197      * This method sets the Extended flag, indicating an additional second flags byte after the current 1-byte flags.
198      * MUST NOT set in Thread 1.2.1.
199      *
200      */
SetExtendedFlag(void)201     void SetExtendedFlag(void) { mFlags |= kExtendedFlag; }
202 
203     /**
204      * This method indicates whether or not the Extended flag is set.
205      *
206      * @retval true   The Extended flag is set.
207      * @retval false  The Extended flag is not set.
208      *
209      */
IsExtendedFlagSet(void) const210     bool IsExtendedFlagSet(void) const { return (mFlags & kExtendedFlag) != 0; }
211 
212     /**
213      * This method clears value length flag.
214      *
215      */
ClearLengthFlag(void)216     void ClearLengthFlag(void) { mFlags &= ~kLengthFlag; }
217 
218     /**
219      * This method sets the value length flag.
220      *
221      */
SetLengthFlag(void)222     void SetLengthFlag(void) { mFlags |= kLengthFlag; }
223 
224     /**
225      * This method indicates whether or not the value length flag is set.
226      *
227      * @retval true   The value length flag is set, extended value length (4 bytes)
228      * @retval false  The value length flag is not set, short value length (1 byte)
229      *
230      */
IsLengthFlagSet(void) const231     bool IsLengthFlagSet(void) const { return (mFlags & kLengthFlag) != 0; }
232 
233     /**
234      * This method sets the Type/Average Enum.
235      *
236      * @param[in]  aTypeEnum  Type/Average Enum.
237      *
238      */
SetTypeEnum(TypeEnum aTypeEnum)239     void SetTypeEnum(TypeEnum aTypeEnum)
240     {
241         mFlags = (mFlags & ~kTypeEnumMask) | ((aTypeEnum << kTypeEnumOffset) & kTypeEnumMask);
242     }
243 
244     /**
245      * This method returns the Type/Average Enum.
246      *
247      * @returns The Type/Average Enum.
248      *
249      */
GetTypeEnum(void) const250     TypeEnum GetTypeEnum(void) const { return static_cast<TypeEnum>((mFlags & kTypeEnumMask) >> kTypeEnumOffset); }
251 
252     /**
253      * This method sets the Metric Enum.
254      *
255      * @param[in]  aMetricEnum  Metric Enum.
256      *
257      */
SetMetricEnum(MetricEnum aMetricEnum)258     void SetMetricEnum(MetricEnum aMetricEnum)
259     {
260         mFlags = (mFlags & ~kMetricEnumMask) | ((aMetricEnum << kMetricEnumOffset) & kMetricEnumMask);
261     }
262 
263     /**
264      * This method returns the Metric Enum.
265      *
266      * @returns The Metric Enum.
267      *
268      */
GetMetricEnum(void) const269     MetricEnum GetMetricEnum(void) const
270     {
271         return static_cast<MetricEnum>((mFlags & kMetricEnumMask) >> kMetricEnumOffset);
272     }
273 
274     /**
275      * This method returns the raw value of the entire TypeIdFlags.
276      *
277      * @returns The raw value of TypeIdFlags.
278      *
279      */
GetRawValue(void) const280     uint8_t GetRawValue(void) const { return mFlags; }
281 
282     /**
283      * This method sets the raw value of the entire TypeIdFlags.
284      *
285      * @param[in]  aFlags  The raw flags value.
286      *
287      */
SetRawValue(uint8_t aFlags)288     void SetRawValue(uint8_t aFlags) { mFlags = aFlags; }
289 
290 private:
291     uint8_t mFlags;
292 } OT_TOOL_PACKED_END;
293 
294 /**
295  * This class implements Link Metrics Report Sub-TLV generation and parsing.
296  *
297  */
298 OT_TOOL_PACKED_BEGIN
299 class ReportSubTlv : public Tlv, public TlvInfo<SubTlv::kReport>
300 {
301 public:
302     /**
303      * This method initializes the TLV.
304      *
305      */
Init(void)306     void Init(void)
307     {
308         SetType(SubTlv::kReport);
309         SetLength(sizeof(*this) - sizeof(Tlv));
310     }
311 
312     /**
313      * This method indicates whether or not the TLV appears to be well-formed.
314      *
315      * @retval true   The TLV appears to be well-formed.
316      * @retval false  The TLV does not appear to be well-formed.
317      *
318      */
IsValid(void) const319     bool IsValid(void) const { return GetLength() >= sizeof(TypeIdFlags) + sizeof(uint8_t); }
320 
321     /**
322      * This method returns the Link Metrics Type ID.
323      *
324      * @returns The Link Metrics Type ID.
325      *
326      */
GetMetricsTypeId(void) const327     TypeIdFlags GetMetricsTypeId(void) const { return mMetricsTypeId; }
328 
329     /**
330      * This method sets the Link Metrics Type ID.
331      *
332      * @param[in]  aMetricsTypeID  The Link Metrics Type ID to set.
333      *
334      */
SetMetricsTypeId(TypeIdFlags aMetricsTypeId)335     void SetMetricsTypeId(TypeIdFlags aMetricsTypeId)
336     {
337         mMetricsTypeId = aMetricsTypeId;
338 
339         if (!aMetricsTypeId.IsLengthFlagSet())
340         {
341             SetLength(sizeof(*this) - sizeof(Tlv) - sizeof(uint32_t) + sizeof(uint8_t)); // The value is 1 byte long
342         }
343     }
344 
345     /**
346      * This method returns the metric value in 8 bits.
347      *
348      * @returns The metric value.
349      *
350      */
GetMetricsValue8(void) const351     uint8_t GetMetricsValue8(void) const { return mMetricsValue.m8; }
352 
353     /**
354      * This method returns the metric value in 32 bits.
355      *
356      * @returns The metric value.
357      *
358      */
GetMetricsValue32(void) const359     uint32_t GetMetricsValue32(void) const { return mMetricsValue.m32; }
360 
361     /**
362      * This method sets the metric value (8 bits).
363      *
364      * @param[in]  aMetricsValue  Metrics value.
365      *
366      */
SetMetricsValue8(uint8_t aMetricsValue)367     void SetMetricsValue8(uint8_t aMetricsValue) { mMetricsValue.m8 = aMetricsValue; }
368 
369     /**
370      * This method sets the metric value (32 bits).
371      *
372      * @param[in]  aMetricsValue  Metrics value.
373      *
374      */
SetMetricsValue32(uint32_t aMetricsValue)375     void SetMetricsValue32(uint32_t aMetricsValue) { mMetricsValue.m32 = aMetricsValue; }
376 
377 private:
378     TypeIdFlags mMetricsTypeId;
379     union
380     {
381         uint8_t  m8;
382         uint32_t m32;
383     } mMetricsValue;
384 } OT_TOOL_PACKED_END;
385 
386 /**
387  * This class implements Link Metrics Query Options Sub-TLV generation and parsing.
388  *
389  */
390 OT_TOOL_PACKED_BEGIN
391 class QueryOptionsSubTlv : public Tlv, public TlvInfo<SubTlv::kQueryOptions>
392 {
393 public:
394     /**
395      * This method initializes the TLV.
396      *
397      */
Init(void)398     void Init(void)
399     {
400         SetType(SubTlv::kQueryOptions);
401         SetLength(0);
402     }
403 
404     /**
405      * This method indicates whether or not the TLV appears to be well-formed.
406      *
407      * @retval TRUE   If the TLV appears to be well-formed.
408      * @retval FALSE  If the TLV does not appear to be well-formed.
409      *
410      */
IsValid(void) const411     bool IsValid(void) const { return GetLength() >= sizeof(TypeIdFlags); }
412 
413 } OT_TOOL_PACKED_END;
414 
415 /**
416  * This class implements Series Flags for Forward Tracking Series.
417  *
418  */
419 OT_TOOL_PACKED_BEGIN
420 class SeriesFlags
421 {
422 public:
423     /**
424      * This type represents which frames to be accounted in a Forward Tracking Series.
425      *
426      * @sa otLinkMetricsSeriesFlags
427      *
428      */
429     typedef otLinkMetricsSeriesFlags Info;
430 
431     /**
432      * Default constructor.
433      *
434      */
SeriesFlags(void)435     SeriesFlags(void)
436         : mFlags(0)
437     {
438     }
439 
440     /**
441      * This method sets the values from an `Info` object.
442      *
443      * @param[in]  aSeriesFlags  The `Info` object.
444      *
445      */
SetFrom(const Info & aSeriesFlags)446     void SetFrom(const Info &aSeriesFlags)
447     {
448         Clear();
449 
450         if (aSeriesFlags.mLinkProbe)
451         {
452             SetLinkProbeFlag();
453         }
454 
455         if (aSeriesFlags.mMacData)
456         {
457             SetMacDataFlag();
458         }
459 
460         if (aSeriesFlags.mMacDataRequest)
461         {
462             SetMacDataRequestFlag();
463         }
464 
465         if (aSeriesFlags.mMacAck)
466         {
467             SetMacAckFlag();
468         }
469     }
470 
471     /**
472      * This method clears the Link Probe flag.
473      *
474      */
ClearLinkProbeFlag(void)475     void ClearLinkProbeFlag(void) { mFlags &= ~kLinkProbeFlag; }
476 
477     /**
478      * This method sets the Link Probe flag.
479      *
480      */
SetLinkProbeFlag(void)481     void SetLinkProbeFlag(void) { mFlags |= kLinkProbeFlag; }
482 
483     /**
484      * This method indicates whether or not the Link Probe flag is set.
485      *
486      * @retval true   The Link Probe flag is set.
487      * @retval false  The Link Probe flag is not set.
488      *
489      */
IsLinkProbeFlagSet(void) const490     bool IsLinkProbeFlagSet(void) const { return (mFlags & kLinkProbeFlag) != 0; }
491 
492     /**
493      * This method clears the MAC Data flag.
494      *
495      */
ClearMacDataFlag(void)496     void ClearMacDataFlag(void) { mFlags &= ~kMacDataFlag; }
497 
498     /**
499      * This method sets the MAC Data flag.
500      *
501      */
SetMacDataFlag(void)502     void SetMacDataFlag(void) { mFlags |= kMacDataFlag; }
503 
504     /**
505      * This method indicates whether or not the MAC Data flag is set.
506      *
507      * @retval true   The MAC Data flag is set.
508      * @retval false  The MAC Data flag is not set.
509      *
510      */
IsMacDataFlagSet(void) const511     bool IsMacDataFlagSet(void) const { return (mFlags & kMacDataFlag) != 0; }
512 
513     /**
514      * This method clears the MAC Data Request flag.
515      *
516      */
ClearMacDataRequestFlag(void)517     void ClearMacDataRequestFlag(void) { mFlags &= ~kMacDataRequestFlag; }
518 
519     /**
520      * This method sets the MAC Data Request flag.
521      *
522      */
SetMacDataRequestFlag(void)523     void SetMacDataRequestFlag(void) { mFlags |= kMacDataRequestFlag; }
524 
525     /**
526      * This method indicates whether or not the MAC Data Request flag is set.
527      *
528      * @retval true   The MAC Data Request flag is set.
529      * @retval false  The MAC Data Request flag is not set.
530      *
531      */
IsMacDataRequestFlagSet(void) const532     bool IsMacDataRequestFlagSet(void) const { return (mFlags & kMacDataRequestFlag) != 0; }
533 
534     /**
535      * This method clears the Mac Ack flag.
536      *
537      */
ClearMacAckFlag(void)538     void ClearMacAckFlag(void) { mFlags &= ~kMacAckFlag; }
539 
540     /**
541      * This method sets the Mac Ack flag.
542      *
543      */
SetMacAckFlag(void)544     void SetMacAckFlag(void) { mFlags |= kMacAckFlag; }
545 
546     /**
547      * This method indicates whether or not the Mac Ack flag is set.
548      *
549      * @retval true   The Mac Ack flag is set.
550      * @retval false  The Mac Ack flag is not set.
551      *
552      */
IsMacAckFlagSet(void) const553     bool IsMacAckFlagSet(void) const { return (mFlags & kMacAckFlag) != 0; }
554 
555     /**
556      * This method returns the raw value of flags.
557      *
558      */
GetRawValue(void) const559     uint8_t GetRawValue(void) const { return mFlags; }
560 
561     /**
562      * This method clears the all the flags.
563      *
564      */
Clear(void)565     void Clear(void) { mFlags = 0; }
566 
567 private:
568     static constexpr uint8_t kLinkProbeFlag      = 1 << 0;
569     static constexpr uint8_t kMacDataFlag        = 1 << 1;
570     static constexpr uint8_t kMacDataRequestFlag = 1 << 2;
571     static constexpr uint8_t kMacAckFlag         = 1 << 3;
572 
573     uint8_t mFlags;
574 } OT_TOOL_PACKED_END;
575 
576 /**
577  * This enumeration type represent Enhanced-ACK Flags.
578  *
579  */
580 enum EnhAckFlags : uint8_t
581 {
582     kEnhAckClear    = OT_LINK_METRICS_ENH_ACK_CLEAR,    ///< Clear.
583     kEnhAckRegister = OT_LINK_METRICS_ENH_ACK_REGISTER, ///< Register.
584 };
585 
TypeIdFlagsFromMetrics(TypeIdFlags aTypeIdFlags[],const Metrics & aMetrics)586 static uint8_t TypeIdFlagsFromMetrics(TypeIdFlags aTypeIdFlags[], const Metrics &aMetrics)
587 {
588     uint8_t count = 0;
589 
590     if (aMetrics.mPduCount)
591     {
592         aTypeIdFlags[count++].SetRawValue(TypeIdFlags::kPdu);
593     }
594 
595     if (aMetrics.mLqi)
596     {
597         aTypeIdFlags[count++].SetRawValue(TypeIdFlags::kLqi);
598     }
599 
600     if (aMetrics.mLinkMargin)
601     {
602         aTypeIdFlags[count++].SetRawValue(TypeIdFlags::kLinkMargin);
603     }
604 
605     if (aMetrics.mRssi)
606     {
607         aTypeIdFlags[count++].SetRawValue(TypeIdFlags::kRssi);
608     }
609 
610 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
611     if (aMetrics.mReserved)
612     {
613         for (uint8_t i = 0; i < count; i++)
614         {
615             aTypeIdFlags[i].SetTypeEnum(TypeIdFlags::kTypeReserved);
616         }
617     }
618 #endif
619 
620     return count;
621 }
622 
623 OT_TOOL_PACKED_BEGIN
624 class EnhAckConfigSubTlv : public Tlv, public TlvInfo<SubTlv::kEnhAckConfig>
625 {
626 public:
627     /**
628      * Default constructor
629      *
630      */
EnhAckConfigSubTlv(void)631     EnhAckConfigSubTlv(void) { Init(); }
632 
633     /**
634      * This method initializes the TLV.
635      *
636      */
Init(void)637     void Init(void)
638     {
639         SetType(SubTlv::kEnhAckConfig);
640         SetLength(sizeof(EnhAckFlags));
641     }
642 
643     /**
644      * This method sets Enhanced ACK Flags.
645      *
646      * @param[in] aEnhAckFlags  The value of Enhanced ACK Flags.
647      *
648      */
SetEnhAckFlags(EnhAckFlags aEnhAckFlags)649     void SetEnhAckFlags(EnhAckFlags aEnhAckFlags)
650     {
651         memcpy(mSubTlvs + kEnhAckFlagsOffset, &aEnhAckFlags, sizeof(aEnhAckFlags));
652     }
653 
654     /**
655      * This method sets Type ID Flags.
656      *
657      * @param[in] aMetrics  A metrics flags to indicate the Type ID Flags.
658      *
659      */
SetTypeIdFlags(const Metrics & aMetrics)660     void SetTypeIdFlags(const Metrics &aMetrics)
661     {
662         uint8_t count;
663 
664         count = TypeIdFlagsFromMetrics(reinterpret_cast<TypeIdFlags *>(mSubTlvs + kTypeIdFlagsOffset), aMetrics);
665 
666         OT_ASSERT(count <= kMaxTypeIdFlagsEnhAck);
667 
668         SetLength(sizeof(EnhAckFlags) + sizeof(TypeIdFlags) * count);
669     }
670 
671 private:
672     static constexpr uint8_t  kMaxTypeIdFlagsEnhAck = 3;
673     static constexpr uint8_t  kEnhAckFlagsOffset    = 0;
674     static constexpr uint16_t kTypeIdFlagsOffset    = sizeof(TypeIdFlags);
675 
676     uint8_t mSubTlvs[sizeof(EnhAckFlags) + sizeof(TypeIdFlags) * kMaxTypeIdFlagsEnhAck];
677 } OT_TOOL_PACKED_END;
678 
679 } // namespace LinkMetrics
680 } // namespace ot
681 
682 #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
683 
684 #endif // LINK_METRICS_TLVS_HPP_
685