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