1 /*
2  *  Copyright (c) 2016, 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 Thread Network Data TLVs.
32  */
33 
34 #ifndef NETWORK_DATA_TLVS_HPP_
35 #define NETWORK_DATA_TLVS_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include <openthread/netdata.h>
40 
41 #include "common/const_cast.hpp"
42 #include "common/debug.hpp"
43 #include "common/encoding.hpp"
44 #include "common/equatable.hpp"
45 #include "net/ip6_address.hpp"
46 #include "thread/network_data_types.hpp"
47 
48 namespace ot {
49 namespace NetworkData {
50 
51 using ot::Encoding::BigEndian::HostSwap16;
52 using ot::Encoding::BigEndian::HostSwap32;
53 
54 /**
55  * @addtogroup core-netdata-tlvs
56  *
57  * @brief
58  *   This module includes definitions for generating and processing Thread Network Data TLVs.
59  *
60  * @{
61  *
62  */
63 
64 class NetworkDataTlv;
65 
66 /**
67  * This template method casts a `NetworkDataTlv` pointer to a given subclass `TlvType` pointer.
68  *
69  * @tparam TlvType  The TLV type to cast into. MUST be a subclass of `NetworkDataTlv`.
70  *
71  * @param[in] aTlv   A pointer to a `NetworkDataTlv` to convert/cast to a `TlvType`.
72  *
73  * @returns A `TlvType` pointer to `aTlv`.
74  *
75  */
As(NetworkDataTlv * aTlv)76 template <class TlvType> TlvType *As(NetworkDataTlv *aTlv) { return static_cast<TlvType *>(aTlv); }
77 
78 /**
79  * This template method casts a `NetworkDataTlv` pointer to a given subclass `TlvType` pointer.
80  *
81  * @tparam TlvType  The TLV type to cast into. MUST be a subclass of `NetworkDataTlv`.
82  *
83  * @param[in] aTlv   A pointer to a `NetworkDataTlv` to convert/cast to a `TlvType`.
84  *
85  * @returns A `TlvType` pointer to `aTlv`.
86  *
87  */
As(const NetworkDataTlv * aTlv)88 template <class TlvType> const TlvType *As(const NetworkDataTlv *aTlv) { return static_cast<const TlvType *>(aTlv); }
89 
90 /**
91  * This template method casts a `NetworkDataTlv` reference to a given subclass `TlvType` reference.
92  *
93  * @tparam TlvType  The TLV type to cast into. MUST be a subclass of `NetworkDataTlv`.
94  *
95  * @param[in] aTlv   A reference to a `NetworkDataTlv` to convert/cast to a `TlvType`.
96  *
97  * @returns A `TlvType` reference to `aTlv`.
98  *
99  */
As(NetworkDataTlv & aTlv)100 template <class TlvType> TlvType &As(NetworkDataTlv &aTlv) { return static_cast<TlvType &>(aTlv); }
101 
102 /**
103  * This template method casts a `NetworkDataTlv` reference to a given subclass `TlvType` reference.
104  *
105  * @tparam TlvType  The TLV type to cast into. MUST be a subclass of `NetworkDataTlv`.
106  *
107  * @param[in] aTlv   A reference to a `NetworkDataTlv` to convert/cast to a `TlvType`.
108  *
109  * @returns A `TlvType` reference to `aTlv`.
110  *
111  */
As(const NetworkDataTlv & aTlv)112 template <class TlvType> const TlvType &As(const NetworkDataTlv &aTlv) { return static_cast<const TlvType &>(aTlv); }
113 
114 /**
115  * This class implements Thread Network Data TLV generation and parsing.
116  *
117  */
118 OT_TOOL_PACKED_BEGIN
119 class NetworkDataTlv
120 {
121 public:
122     /**
123      * Thread Network Data Type values.
124      *
125      */
126     enum Type : uint8_t
127     {
128         kTypeHasRoute          = 0, ///< Has Route TLV
129         kTypePrefix            = 1, ///< Prefix TLV
130         kTypeBorderRouter      = 2, ///< Border Router TLV
131         kTypeContext           = 3, ///< Context TLV
132         kTypeCommissioningData = 4, ///< Commissioning Dataset TLV
133         kTypeService           = 5, ///< Service TLV
134         kTypeServer            = 6, ///< Server TLV
135     };
136 
137     /**
138      * This method initializes the TLV.
139      *
140      */
Init(void)141     void Init(void)
142     {
143         mType   = 0;
144         mLength = 0;
145     }
146 
147     /**
148      * This method returns the Type value.
149      *
150      * @returns The Type value.
151      *
152      */
GetType(void) const153     Type GetType(void) const { return static_cast<Type>(mType >> kTypeOffset); }
154 
155     /**
156      * This method sets the Type value.
157      *
158      * @param[in]  aType  The Type value.
159      *
160      */
SetType(Type aType)161     void SetType(Type aType) { mType = (mType & ~kTypeMask) | ((aType << kTypeOffset) & kTypeMask); }
162 
163     /**
164      * This method returns the Length value.
165      *
166      * @returns The Length value.
167      *
168      */
GetLength(void) const169     uint8_t GetLength(void) const { return mLength; }
170 
171     /**
172      * This method sets the Length value.
173      *
174      * @param[in]  aLength  The Length value.
175      *
176      */
SetLength(uint8_t aLength)177     void SetLength(uint8_t aLength) { mLength = aLength; }
178 
179     /**
180      * This methods increases the Length value by a given amount.
181      *
182      * @param[in]  aIncrement  The increment amount to increase the length.
183      *
184      */
IncreaseLength(uint8_t aIncrement)185     void IncreaseLength(uint8_t aIncrement) { mLength += aIncrement; }
186 
187     /**
188      * This methods decreases the Length value by a given amount.
189      *
190      * @param[in]  aDecrement  The decrement amount to decrease the length.
191      *
192      */
DecreaseLength(uint8_t aDecrement)193     void DecreaseLength(uint8_t aDecrement) { mLength -= aDecrement; }
194 
195     /**
196      * This method returns the TLV's total size (number of bytes) including Type, Length, and Value fields.
197      *
198      * @returns The total size include Type, Length, and Value fields.
199      *
200      */
GetSize(void) const201     uint8_t GetSize(void) const { return sizeof(NetworkDataTlv) + mLength; }
202 
203     /**
204      * This method returns a pointer to the Value.
205      *
206      * @returns A pointer to the value.
207      *
208      */
GetValue(void)209     uint8_t *GetValue(void) { return reinterpret_cast<uint8_t *>(this) + sizeof(NetworkDataTlv); }
210 
211     /**
212      * This method returns a pointer to the Value.
213      *
214      * @returns A pointer to the value.
215      *
216      */
GetValue(void) const217     const uint8_t *GetValue(void) const { return reinterpret_cast<const uint8_t *>(this) + sizeof(NetworkDataTlv); }
218 
219     /**
220      * This method returns a pointer to the next Network Data TLV.
221      *
222      * @returns A pointer to the next Network Data TLV.
223      *
224      */
GetNext(void)225     NetworkDataTlv *GetNext(void)
226     {
227         return reinterpret_cast<NetworkDataTlv *>(reinterpret_cast<uint8_t *>(this) + sizeof(*this) + mLength);
228     }
229 
230     /**
231      * This method returns a pointer to the next Network Data TLV.
232      *
233      * @returns A pointer to the next Network Data TLV.
234      *
235      */
GetNext(void) const236     const NetworkDataTlv *GetNext(void) const
237     {
238         return reinterpret_cast<const NetworkDataTlv *>(reinterpret_cast<const uint8_t *>(this) + sizeof(*this) +
239                                                         mLength);
240     }
241 
242     /**
243      * This method clears the Stable bit.
244      *
245      */
ClearStable(void)246     void ClearStable(void) { mType &= ~kStableMask; }
247 
248     /**
249      * This method indicates whether or not the Stable bit is set.
250      *
251      * @retval TRUE   If the Stable bit is set.
252      * @retval FALSE  If the Stable bit is not set.
253      *
254      */
IsStable(void) const255     bool IsStable(void) const { return (mType & kStableMask); }
256 
257     /**
258      * This method sets the Stable bit.
259      *
260      */
SetStable(void)261     void SetStable(void) { mType |= kStableMask; }
262 
263     /**
264      * This static method searches in a given sequence of TLVs to find the first TLV with a given type.
265      *
266      * @param[in]  aStart  A pointer to the start of the sequence of TLVs to search within.
267      * @param[in]  aEnd    A pointer to the end of the sequence of TLVs.
268      * @param[in]  aType   The TLV type to find.
269      *
270      * @returns A pointer to the TLV if found, or `nullptr` if not found.
271      *
272      */
Find(NetworkDataTlv * aStart,NetworkDataTlv * aEnd,Type aType)273     static NetworkDataTlv *Find(NetworkDataTlv *aStart, NetworkDataTlv *aEnd, Type aType)
274     {
275         return AsNonConst(Find(AsConst(aStart), AsConst(aEnd), aType));
276     }
277 
278     /**
279      * This static method searches in a given sequence of TLVs to find the first TLV with a given type.
280      *
281      * @param[in]  aStart  A pointer to the start of the sequence of TLVs to search within.
282      * @param[in]  aEnd    A pointer to the end of the sequence of TLVs.
283      * @param[in]  aType   The TLV type to find.
284      *
285      * @returns A pointer to the TLV if found, or `nullptr` if not found.
286      *
287      */
288     static const NetworkDataTlv *Find(const NetworkDataTlv *aStart, const NetworkDataTlv *aEnd, Type aType);
289 
290     /**
291      * This template static method searches in a given sequence of TLVs to find the first TLV with a given type.
292      *
293      * @tparam     TlvType The TLV type to search for (MUST be a sub-class of `NetworkDataTlv`).
294      *
295      * @param[in]  aStart  A pointer to the start of the sequence of TLVs to search within.
296      * @param[in]  aEnd    A pointer to the end of the sequence of TLVs.
297      *
298      * @returns A pointer to the TLV if found, or `nullptr` if not found.
299      *
300      */
Find(NetworkDataTlv * aStart,NetworkDataTlv * aEnd)301     template <typename TlvType> static TlvType *Find(NetworkDataTlv *aStart, NetworkDataTlv *aEnd)
302     {
303         return As<TlvType>(Find(aStart, aEnd, TlvType::kType));
304     }
305 
306     /**
307      * This template static method searches in a given sequence of TLVs to find the first TLV with a given type.
308      *
309      * @tparam     TlvType The TLV type to search for (MUST be a sub-class of `NetworkDataTlv`).
310      *
311      * @param[in]  aStart  A pointer to the start of the sequence of TLVs to search within.
312      * @param[in]  aEnd    A pointer to the end of the sequence of TLVs.
313      *
314      * @returns A pointer to the TLV if found, or `nullptr` if not found.
315      *
316      */
Find(const NetworkDataTlv * aStart,const NetworkDataTlv * aEnd)317     template <typename TlvType> static const TlvType *Find(const NetworkDataTlv *aStart, const NetworkDataTlv *aEnd)
318     {
319         return As<TlvType>(Find(aStart, aEnd, TlvType::kType));
320     }
321 
322     /**
323      * This static method searches in a given sequence of TLVs to find the first TLV with a given TLV type and stable
324      * flag.
325      *
326      * @param[in]  aStart  A pointer to the start of the sequence of TLVs to search within.
327      * @param[in]  aEnd    A pointer to the end of the sequence of TLVs.
328      * @param[in]  aType   The TLV type to find.
329      * @param[in]  aStable TRUE to find a stable TLV, FALSE to find a TLV not marked as stable.
330      *
331      * @returns A pointer to the TLV if found, or `nullptr` if not found.
332      *
333      */
Find(NetworkDataTlv * aStart,NetworkDataTlv * aEnd,Type aType,bool aStable)334     static NetworkDataTlv *Find(NetworkDataTlv *aStart, NetworkDataTlv *aEnd, Type aType, bool aStable)
335     {
336         return AsNonConst(Find(AsConst(aStart), AsConst(aEnd), aType, aStable));
337     }
338 
339     /**
340      * This static method searches in a given sequence of TLVs to find the first TLV with a given TLV type and stable
341      * flag.
342      *
343      * @param[in]  aStart  A pointer to the start of the sequence of TLVs to search within.
344      * @param[in]  aEnd    A pointer to the end of the sequence of TLVs.
345      * @param[in]  aType   The TLV type to find.
346      * @param[in]  aStable TRUE to find a stable TLV, FALSE to find a TLV not marked as stable.
347      *
348      * @returns A pointer to the TLV if found, or `nullptr` if not found.
349      *
350      */
351     static const NetworkDataTlv *Find(const NetworkDataTlv *aStart,
352                                       const NetworkDataTlv *aEnd,
353                                       Type                  aType,
354                                       bool                  aStable);
355 
356     /**
357      * This template static method searches in a given sequence of TLVs to find the first TLV with a given TLV type and
358      * stable flag.
359      *
360      * @tparam     TlvType The TLV type to search for (MUST be a sub-class of `NetworkDataTlv`).
361      *
362      * @param[in]  aStart  A pointer to the start of the sequence of TLVs to search within.
363      * @param[in]  aEnd    A pointer to the end of the sequence of TLVs.
364      * @param[in]  aStable TRUE to find a stable TLV, FALSE to find a TLV not marked as stable.
365      *
366      * @returns A pointer to the TLV if found, or `nullptr` if not found.
367      *
368      */
Find(NetworkDataTlv * aStart,NetworkDataTlv * aEnd,bool aStable)369     template <typename TlvType> static TlvType *Find(NetworkDataTlv *aStart, NetworkDataTlv *aEnd, bool aStable)
370     {
371         return As<TlvType>(Find(aStart, aEnd, TlvType::kType, aStable));
372     }
373 
374     /**
375      * This template static method searches in a given sequence of TLVs to find the first TLV with a given TLV type and
376      * stable flag.
377      *
378      * @tparam     TlvType The TLV type to search for (MUST be a sub-class of `NetworkDataTlv`).
379      *
380      * @param[in]  aStart  A pointer to the start of the sequence of TLVs to search within.
381      * @param[in]  aEnd    A pointer to the end of the sequence of TLVs.
382      * @param[in]  aStable TRUE to find a stable TLV, FALSE to find a TLV not marked as stable.
383      *
384      * @returns A pointer to the TLV if found, or `nullptr` if not found.
385      *
386      */
387     template <typename TlvType>
Find(const NetworkDataTlv * aStart,const NetworkDataTlv * aEnd,bool aStable)388     static const TlvType *Find(const NetworkDataTlv *aStart, const NetworkDataTlv *aEnd, bool aStable)
389     {
390         return As<TlvType>(Find(aStart, aEnd, TlvType::kType, aStable));
391     }
392 
393 private:
394     static constexpr uint8_t kTypeOffset = 1;
395     static constexpr uint8_t kTypeMask   = 0x7f << kTypeOffset;
396     static constexpr uint8_t kStableMask = 1 << 0;
397 
398     uint8_t mType;
399     uint8_t mLength;
400 } OT_TOOL_PACKED_END;
401 
402 /**
403  * This class implements Has Route TLV entry generation and parsing.
404  *
405  */
406 OT_TOOL_PACKED_BEGIN
407 class HasRouteEntry : public Equatable<HasRouteEntry>
408 {
409     friend class ExternalRouteConfig;
410 
411 public:
412     /**
413      * This method initializes the header.
414      *
415      */
Init(void)416     void Init(void)
417     {
418         SetRloc(Mac::kShortAddrInvalid);
419         mFlags = 0;
420     }
421 
422     /**
423      * This method returns the RLOC16 value.
424      *
425      * @returns The RLOC16 value.
426      */
GetRloc(void) const427     uint16_t GetRloc(void) const { return HostSwap16(mRloc); }
428 
429     /**
430      * This method sets the RLOC16 value.
431      *
432      * @param[in]  aRloc16  The RLOC16 value.
433      *
434      */
SetRloc(uint16_t aRloc16)435     void SetRloc(uint16_t aRloc16) { mRloc = HostSwap16(aRloc16); }
436 
437     /**
438      * This method returns the Preference value.
439      *
440      * @returns The preference value.
441      *
442      */
GetPreference(void) const443     int8_t GetPreference(void) const { return PreferenceFromFlags(GetFlags()); }
444 
445     /**
446      * This method gets the Flags value.
447      *
448      * @returns The Flags value.
449      *
450      */
GetFlags(void) const451     uint8_t GetFlags(void) const { return mFlags; }
452 
453     /**
454      * This method sets the Flags value.
455      *
456      * @param[in]  aFlags  The Flags value.
457      *
458      */
SetFlags(uint8_t aFlags)459     void SetFlags(uint8_t aFlags) { mFlags = aFlags; }
460 
461     /**
462      * This method indicates whether or not the NAT64 flag is set.
463      *
464      * @retval TRUE   If the NAT64 flag is set.
465      * @retval FALSE  If the NAT64 flag is not set.
466      *
467      */
IsNat64(void) const468     bool IsNat64(void) const { return (mFlags & kNat64Flag) != 0; }
469 
470     /**
471      * This method returns a pointer to the next HasRouteEntry.
472      *
473      * @returns A pointer to the next HasRouteEntry.
474      *
475      */
GetNext(void)476     HasRouteEntry *GetNext(void) { return (this + 1); }
477 
478     /**
479      * This method returns a pointer to the next HasRouteEntry.
480      *
481      * @returns A pointer to the next HasRouteEntry.
482      *
483      */
GetNext(void) const484     const HasRouteEntry *GetNext(void) const { return (this + 1); }
485 
486     /**
487      * This static method returns an updated flags bitmask by removing the preference bits (sets them to zero) from a
488      * given flags bitmask.
489      *
490      * @param[in] aFlags  The flags bitmask.
491      *
492      * @returns An updated version @p aFlags with preference bits cleared.
493      *
494      */
FlagsWithoutPreference(uint8_t aFlags)495     static uint8_t FlagsWithoutPreference(uint8_t aFlags) { return (aFlags & ~kPreferenceMask); }
496 
497     /**
498      * This static method gets the preference field from a flags bitmask.
499      *
500      * @param[in] aFlags  The flags.
501      *
502      * @returns The preference field from the @p aFlags.
503      *
504      */
PreferenceFromFlags(uint8_t aFlags)505     static int8_t PreferenceFromFlags(uint8_t aFlags) { return RoutePreferenceFromValue(aFlags >> kPreferenceOffset); }
506 
507 private:
508     static constexpr uint8_t kPreferenceOffset = 6;
509     static constexpr uint8_t kPreferenceMask   = 3 << kPreferenceOffset;
510     static constexpr uint8_t kNat64Flag        = 1 << 5;
511 
512     uint16_t mRloc;
513     uint8_t  mFlags;
514 } OT_TOOL_PACKED_END;
515 
516 /**
517  * This class implements Has Route TLV generation and parsing.
518  *
519  */
520 OT_TOOL_PACKED_BEGIN
521 class HasRouteTlv : public NetworkDataTlv
522 {
523 public:
524     static constexpr Type kType = kTypeHasRoute; ///< The TLV Type.
525 
526     /**
527      * This method initializes the TLV.
528      *
529      */
Init(void)530     void Init(void)
531     {
532         NetworkDataTlv::Init();
533         SetType(kTypeHasRoute);
534         SetLength(0);
535     }
536 
537     /**
538      * This method returns the number of HasRoute entries.
539      *
540      * @returns The number of HasRoute entries.
541      *
542      */
GetNumEntries(void) const543     uint8_t GetNumEntries(void) const { return GetLength() / sizeof(HasRouteEntry); }
544 
545     /**
546      * This method returns a pointer to the HasRoute entry at a given index.
547      *
548      * @param[in]  aIndex  An index.
549      *
550      * @returns A pointer to the HasRoute entry at @p aIndex.
551      *
552      */
GetEntry(uint8_t aIndex)553     HasRouteEntry *GetEntry(uint8_t aIndex)
554     {
555         return reinterpret_cast<HasRouteEntry *>(GetValue() + (aIndex * sizeof(HasRouteEntry)));
556     }
557 
558     /**
559      * This method returns a pointer to the HasRoute entry at a given index.
560      *
561      * @param[in]  aIndex  An index.
562      *
563      * @returns A pointer to the HasRoute entry at @p aIndex.
564      *
565      */
GetEntry(uint8_t aIndex) const566     const HasRouteEntry *GetEntry(uint8_t aIndex) const
567     {
568         return reinterpret_cast<const HasRouteEntry *>(GetValue() + (aIndex * sizeof(HasRouteEntry)));
569     }
570 
571     /**
572      * This method returns a pointer to the first HasRouteEntry (at index 0'th).
573      *
574      * @returns A pointer to the first HasRouteEntry.
575      *
576      */
GetFirstEntry(void)577     HasRouteEntry *GetFirstEntry(void) { return reinterpret_cast<HasRouteEntry *>(GetValue()); }
578 
579     /**
580      * This method returns a pointer to the first HasRouteEntry (at index 0'th).
581      *
582      * @returns A pointer to the first HasRouteEntry.
583      *
584      */
GetFirstEntry(void) const585     const HasRouteEntry *GetFirstEntry(void) const { return reinterpret_cast<const HasRouteEntry *>(GetValue()); }
586 
587     /**
588      * This method returns a pointer to the last HasRouteEntry.
589      *
590      * If there are no entries the pointer will be invalid but guaranteed to be before the `GetFirstEntry()` pointer.
591      *
592      * @returns A pointer to the last HasRouteEntry.
593      *
594      */
GetLastEntry(void)595     HasRouteEntry *GetLastEntry(void)
596     {
597         return reinterpret_cast<HasRouteEntry *>(GetValue() + GetLength() - sizeof(HasRouteEntry));
598     }
599 
600     /**
601      * This method returns a pointer to the last HasRouteEntry.
602      *
603      * If there are no entries the pointer will be invalid but guaranteed to be before the `GetFirstEntry()` pointer.
604      *
605      * @returns A pointer to the last HasRouteEntry.
606      *
607      */
GetLastEntry(void) const608     const HasRouteEntry *GetLastEntry(void) const
609     {
610         return reinterpret_cast<const HasRouteEntry *>(GetValue() + GetLength() - sizeof(HasRouteEntry));
611     }
612 
613 } OT_TOOL_PACKED_END;
614 
615 /**
616  * This class implements Prefix TLV generation and parsing.
617  *
618  */
619 OT_TOOL_PACKED_BEGIN
620 class PrefixTlv : public NetworkDataTlv
621 {
622 public:
623     static constexpr Type kType = kTypePrefix; ///< The TLV Type.
624 
625     /**
626      * This method initializes the TLV.
627      *
628      * @param[in]  aDomainId      The Domain ID.
629      * @param[in]  aPrefixLength  The Prefix Length in bits.
630      * @param[in]  aPrefix        A pointer to the prefix.
631      *
632      */
Init(uint8_t aDomainId,uint8_t aPrefixLength,const uint8_t * aPrefix)633     void Init(uint8_t aDomainId, uint8_t aPrefixLength, const uint8_t *aPrefix)
634     {
635         NetworkDataTlv::Init();
636         SetType(kTypePrefix);
637         mDomainId     = aDomainId;
638         mPrefixLength = aPrefixLength;
639         memcpy(GetPrefix(), aPrefix, Ip6::Prefix::SizeForLength(aPrefixLength));
640         SetSubTlvsLength(0);
641     }
642 
643     /**
644      * This method initializes the TLV.
645      *
646      * @param[in]  aDomainId      The Domain ID.
647      * @param[in]  aPrefix        The Prefix.
648      *
649      */
Init(uint8_t aDomainId,const Ip6::Prefix aPrefix)650     void Init(uint8_t aDomainId, const Ip6::Prefix aPrefix)
651     {
652         Init(aDomainId, aPrefix.GetLength(), aPrefix.GetBytes());
653     }
654 
655     /**
656      * This method indicates whether or not the TLV appears to be well-formed.
657      *
658      * @retval TRUE   If the TLV appears to be well-formed.
659      * @retval FALSE  If the TLV does not appear to be well-formed.
660      *
661      */
IsValid(void) const662     bool IsValid(void) const
663     {
664         return ((GetLength() >= sizeof(*this) - sizeof(NetworkDataTlv)) &&
665                 (GetLength() >= Ip6::Prefix::SizeForLength(mPrefixLength) + sizeof(*this) - sizeof(NetworkDataTlv)) &&
666                 (Ip6::Prefix::SizeForLength(mPrefixLength) <= sizeof(Ip6::Address)));
667     }
668 
669     /**
670      * This method returns the Domain ID value.
671      *
672      * @returns The Domain ID value.
673      *
674      */
GetDomainId(void) const675     uint8_t GetDomainId(void) const { return mDomainId; }
676 
677     /**
678      * This method returns the Prefix Length value.
679      *
680      * @returns The Prefix Length value (in bits).
681      *
682      */
GetPrefixLength(void) const683     uint8_t GetPrefixLength(void) const { return mPrefixLength; }
684 
685     /**
686      * This method returns a pointer to the Prefix.
687      *
688      * @returns A pointer to the Prefix.
689      *
690      */
GetPrefix(void)691     uint8_t *GetPrefix(void) { return reinterpret_cast<uint8_t *>(this) + sizeof(*this); }
692 
693     /**
694      * This method returns a pointer to the Prefix.
695      *
696      * @returns A pointer to the Prefix.
697      *
698      */
GetPrefix(void) const699     const uint8_t *GetPrefix(void) const { return reinterpret_cast<const uint8_t *>(this) + sizeof(*this); }
700 
701     /**
702      * This method copies the Prefix from TLV into a given `Ip6::Prefix`.
703      *
704      * @param[out] aPrefix  An `Ip6::Prefix` to copy the Prefix from TLV into.
705      *
706      */
CopyPrefixTo(Ip6::Prefix & aPrefix) const707     void CopyPrefixTo(Ip6::Prefix &aPrefix) const { aPrefix.Set(GetPrefix(), GetPrefixLength()); }
708 
709     /**
710      * This method indicates whether the Prefix from TLV is equal to a given `Ip6::Prefix`.
711      *
712      * @param[in] aPrefix  A Prefix to compare with.
713      *
714      * @retval TRUE   The TLV's Prefix is equal to @p aPrefix.
715      * @retval FALSE  The TLV's Prefix is not equal to @p aPrefix.
716      *
717      */
IsEqual(Ip6::Prefix & aPrefix) const718     bool IsEqual(Ip6::Prefix &aPrefix) const { return aPrefix.IsEqual(GetPrefix(), GetPrefixLength()); }
719 
720     /**
721      * This method indicates whether the Prefix from TLV is equal to a given Prefix.
722      *
723      * @param[in]  aPrefix        A pointer to an IPv6 prefix to compare with.
724      * @param[in]  aPrefixLength  The prefix length pointed to by @p aPrefix (in bits).
725      *
726      * @retval TRUE   The TLV's Prefix is equal to @p aPrefix.
727      * @retval FALSE  The TLV's Prefix is not equal @p aPrefix.
728      *
729      */
IsEqual(const uint8_t * aPrefix,uint8_t aPrefixLength) const730     bool IsEqual(const uint8_t *aPrefix, uint8_t aPrefixLength) const
731     {
732         return (aPrefixLength == mPrefixLength) &&
733                (Ip6::Prefix::MatchLength(GetPrefix(), aPrefix, Ip6::Prefix::SizeForLength(aPrefixLength)) >=
734                 mPrefixLength);
735     }
736 
737     /**
738      * This method returns a pointer to the Sub-TLVs.
739      *
740      * @returns A pointer to the Sub-TLVs.
741      *
742      */
GetSubTlvs(void)743     NetworkDataTlv *GetSubTlvs(void)
744     {
745         return reinterpret_cast<NetworkDataTlv *>(GetPrefix() + Ip6::Prefix::SizeForLength(mPrefixLength));
746     }
747 
748     /**
749      * This method returns a pointer to the Sub-TLVs.
750      *
751      * @returns A pointer to the Sub-TLVs.
752      *
753      */
GetSubTlvs(void) const754     const NetworkDataTlv *GetSubTlvs(void) const
755     {
756         return reinterpret_cast<const NetworkDataTlv *>(GetPrefix() + Ip6::Prefix::SizeForLength(mPrefixLength));
757     }
758 
759     /**
760      * This method returns the Sub-TLVs length in bytes.
761      *
762      * @returns The Sub-TLVs length in bytes.
763      *
764      */
GetSubTlvsLength(void) const765     uint8_t GetSubTlvsLength(void) const
766     {
767         return GetLength() - (sizeof(*this) - sizeof(NetworkDataTlv) + Ip6::Prefix::SizeForLength(mPrefixLength));
768     }
769 
770     /**
771      * This method sets the Sub-TLVs length in bytes.
772      *
773      * @param[in]  aLength  The Sub-TLVs length in bytes.
774      *
775      */
SetSubTlvsLength(uint8_t aLength)776     void SetSubTlvsLength(uint8_t aLength)
777     {
778         SetLength(sizeof(*this) - sizeof(NetworkDataTlv) + Ip6::Prefix::SizeForLength(mPrefixLength) + aLength);
779     }
780 
781     /**
782      * This template method searches in the sub-TLVs to find the first one matching a given TLV type.
783      *
784      * @tparam     SubTlvType    The sub-TLV type to search for (MUST be a sub-class of `NetworkDataTlv`).
785      *
786      * @returns A pointer to the TLV if found, or `nullptr` if not found.
787      *
788      */
FindSubTlv(void)789     template <typename SubTlvType> SubTlvType *FindSubTlv(void)
790     {
791         return As<SubTlvType>(FindSubTlv(SubTlvType::kType));
792     }
793 
794     /**
795      * This template method searches in the sub-TLVs to find the first one matching a given TLV Type.
796      *
797      * @tparam     SubTlvType   The sub-TLV type to search for (MUST be a sub-class of `NetworkDataTlv`).
798      *
799      * @returns A pointer to the TLV if found, or `nullptr` if not found.
800      *
801      */
FindSubTlv(void) const802     template <typename SubTlvType> const SubTlvType *FindSubTlv(void) const
803     {
804         return As<SubTlvType>(FindSubTlv(SubTlvType::kType));
805     }
806 
807     /**
808      * This template method searches in the sub-TLVs to find the first one matching a given TLV type and stable flag.
809      *
810      * @tparam     SubTlvType    The sub-TLV type to search for (MUST be a sub-class of `NetworkDataTlv`).
811      *
812      * @param[in]  aStable       TRUE to find a stable TLV, FALSE to find a TLV not marked as stable.
813      *
814      * @returns A pointer to the TLV if found, or `nullptr` if not found.
815      *
816      */
FindSubTlv(bool aStable)817     template <typename SubTlvType> SubTlvType *FindSubTlv(bool aStable)
818     {
819         return As<SubTlvType>(FindSubTlv(static_cast<Type>(SubTlvType::kType), aStable));
820     }
821 
822     /**
823      * This template method searches in the sub-TLVs to find the first one matching a given TLV type and stable flag.
824      *
825      * @tparam     SubTlvType   The sub-TLV type to search for (MUST be a sub-class of `NetworkDataTlv`).
826      *
827      * @param[in]  aStable      TRUE to find a stable TLV, FALSE to find a TLV not marked as stable.
828      *
829      * @returns A pointer to the TLV if found, or `nullptr` if not found.
830      *
831      */
FindSubTlv(bool aStable) const832     template <typename SubTlvType> const SubTlvType *FindSubTlv(bool aStable) const
833     {
834         return As<SubTlvType>(FindSubTlv(static_cast<Type>(SubTlvType::kType), aStable));
835     }
836 
837     /**
838      * This method searches in the sub-TLVs to find the first one matching a given TLV type.
839      *
840      * @param[in]  aType        The sub-TLV type to search for.
841      *
842      * @returns A pointer to the TLV if found, or `nullptr` if not found.
843      *
844      */
FindSubTlv(Type aType)845     NetworkDataTlv *FindSubTlv(Type aType) { return AsNonConst(AsConst(this)->FindSubTlv(aType)); }
846 
847     /**
848      * This method searches in the sub-TLVs to find the first one matching a given TLV type.
849      *
850      * @param[in]  aType        The sub-TLV type to search for.
851      *
852      * @returns A pointer to the TLV if found, or `nullptr` if not found.
853      *
854      */
855     const NetworkDataTlv *FindSubTlv(Type aType) const;
856 
857     /**
858      * This method searches in the sub-TLVs to find the first one matching a given TLV type and stable flag.
859      *
860      * @param[in]  aType        The sub-TLV type to search for.
861      * @param[in]  aStable      TRUE to find a stable TLV, FALSE to find a TLV not marked as stable.
862      *
863      * @returns A pointer to the TLV if found, or `nullptr` if not found.
864      *
865      */
FindSubTlv(Type aType,bool aStable)866     NetworkDataTlv *FindSubTlv(Type aType, bool aStable)
867     {
868         return AsNonConst(AsConst(this)->FindSubTlv(aType, aStable));
869     }
870 
871     /**
872      * This method searches in the sub-TLVs to find the first one matching a given TLV type and stable flag.
873      *
874      * @param[in]  aType        The sub-TLV type to search for.
875      * @param[in]  aStable      TRUE to find a stable TLV, FALSE to find a TLV not marked as stable.
876      *
877      * @returns A pointer to the TLV if found, or `nullptr` if not found.
878      *
879      */
880     const NetworkDataTlv *FindSubTlv(Type aType, bool aStable) const;
881 
882     /**
883      * This static method calculates the total size (number of bytes) of a Prefix TLV with a given Prefix Length value.
884      *
885      * Note that the returned size does include the Type and Length fields in the TLV, but does not account for any
886      * sub TLVs of the Prefix TLV.
887      *
888      * @param[in]  aPrefixLength     A Prefix Length in bits.
889 
890      * @returns    The size (number of bytes) of the Prefix TLV.
891      *
892      */
CalculateSize(uint8_t aPrefixLength)893     static uint16_t CalculateSize(uint8_t aPrefixLength)
894     {
895         return sizeof(PrefixTlv) + Ip6::Prefix::SizeForLength(aPrefixLength);
896     }
897 
898 private:
899     uint8_t mDomainId;
900     uint8_t mPrefixLength;
901 } OT_TOOL_PACKED_END;
902 
903 /**
904  * This class implements Border Router Entry generation and parsing.
905  *
906  */
907 OT_TOOL_PACKED_BEGIN
908 class BorderRouterEntry : public Equatable<BorderRouterEntry>
909 {
910     friend class OnMeshPrefixConfig;
911 
912 public:
913     /**
914      * This method initializes the TLV.
915      *
916      */
Init(void)917     void Init(void)
918     {
919         SetRloc(Mac::kShortAddrInvalid);
920         mFlags = 0;
921     }
922 
923     /**
924      * This method returns the RLOC16 value.
925      *
926      * @returns The RLOC16 value.
927      */
GetRloc(void) const928     uint16_t GetRloc(void) const { return HostSwap16(mRloc); }
929 
930     /**
931      * This method sets the RLOC16 value.
932      *
933      * @param[in]  aRloc16  The RLOC16 value.
934      *
935      */
SetRloc(uint16_t aRloc16)936     void SetRloc(uint16_t aRloc16) { mRloc = HostSwap16(aRloc16); }
937 
938     /**
939      * This method returns the Flags value.
940      *
941      * @returns The Flags value.
942      *
943      */
GetFlags(void) const944     uint16_t GetFlags(void) const { return HostSwap16(mFlags); }
945 
946     /**
947      * This method sets the Flags value.
948      *
949      * @param[in]  aFlags  The Flags value.
950      *
951      */
SetFlags(uint16_t aFlags)952     void SetFlags(uint16_t aFlags) { mFlags = HostSwap16(aFlags); }
953 
954     /**
955      * This method returns the Preference value.
956      *
957      * @returns the Preference value.
958      *
959      */
GetPreference(void) const960     int8_t GetPreference(void) const { return PreferenceFromFlags(GetFlags()); }
961 
962     /**
963      * This method indicates whether or not the Preferred flag is set.
964      *
965      * @retval TRUE   If the Preferred flag is set.
966      * @retval FALSE  If the Preferred flag is not set.
967      *
968      */
IsPreferred(void) const969     bool IsPreferred(void) const { return (HostSwap16(mFlags) & kPreferredFlag) != 0; }
970 
971     /**
972      * This method indicates whether or not the SLAAC flag is set.
973      *
974      * @retval TRUE   If the SLAAC flag is set.
975      * @retval FALSE  If the SLAAC flag is not set.
976      *
977      */
IsSlaac(void) const978     bool IsSlaac(void) const { return (HostSwap16(mFlags) & kSlaacFlag) != 0; }
979 
980     /**
981      * This method indicates whether or not the DHCP flag is set.
982      *
983      * @retval TRUE   If the DHCP flag is set.
984      * @retval FALSE  If the DHCP flag is not set.
985      *
986      */
IsDhcp(void) const987     bool IsDhcp(void) const { return (HostSwap16(mFlags) & kDhcpFlag) != 0; }
988 
989     /**
990      * This method indicates whether or not the Configure flag is set.
991      *
992      * @retval TRUE   If the Configure flag is set.
993      * @retval FALSE  If the Configure flag is not set.
994      *
995      */
IsConfigure(void) const996     bool IsConfigure(void) const { return (HostSwap16(mFlags) & kConfigureFlag) != 0; }
997 
998     /**
999      * This method indicates whether or not the Default Route flag is set.
1000      *
1001      * @retval TRUE   If the Default Route flag is set.
1002      * @retval FALSE  If the Default Route flag is not set.
1003      *
1004      */
IsDefaultRoute(void) const1005     bool IsDefaultRoute(void) const { return (HostSwap16(mFlags) & kDefaultRouteFlag) != 0; }
1006 
1007     /**
1008      * This method indicates whether or not the On-Mesh flag is set.
1009      *
1010      * @retval TRUE   If the On-Mesh flag is set.
1011      * @retval FALSE  If the On-Mesh flag is not set.
1012      *
1013      */
IsOnMesh(void) const1014     bool IsOnMesh(void) const { return (HostSwap16(mFlags) & kOnMeshFlag) != 0; }
1015 
1016     /**
1017      * This method indicates whether or not the Nd-Dns flag is set.
1018      *
1019      * @retval TRUE   If the Nd-Dns flag is set.
1020      * @retval FALSE  If the Nd-Dns flag is not set.
1021      *
1022      */
IsNdDns(void) const1023     bool IsNdDns(void) const { return (HostSwap16(mFlags) & kNdDnsFlag) != 0; }
1024 
1025     /**
1026      * This method indicates whether or not the Domain Prefix flag is set.
1027      *
1028      * @retval TRUE   If the Domain Prefix flag is set.
1029      * @retval FALSE  If the Domain Prefix flag is not set.
1030      *
1031      */
IsDp(void) const1032     bool IsDp(void) const { return (HostSwap16(mFlags) & kDpFlag) != 0; }
1033 
1034     /**
1035      * This method returns a pointer to the next BorderRouterEntry
1036      *
1037      * @returns A pointer to the next BorderRouterEntry.
1038      *
1039      */
GetNext(void)1040     BorderRouterEntry *GetNext(void) { return (this + 1); }
1041 
1042     /**
1043      * This method returns a pointer to the next BorderRouterEntry
1044      *
1045      * @returns A pointer to the next BorderRouterEntry.
1046      *
1047      */
GetNext(void) const1048     const BorderRouterEntry *GetNext(void) const { return (this + 1); }
1049 
1050     /**
1051      * This static method returns an updated flags bitmask by removing the preference bits (sets them to zero) from a
1052      * given flags bitmask.
1053      *
1054      * @param[in] aFlags  The flags bitmask.
1055      *
1056      * @returns An updated version @p aFlags with preference bits cleared.
1057      *
1058      */
FlagsWithoutPreference(uint16_t aFlags)1059     static uint16_t FlagsWithoutPreference(uint16_t aFlags) { return (aFlags & ~kPreferenceMask); }
1060 
1061     /**
1062      * This static method gets the preference field from a flags bitmask.
1063      *
1064      * @param[in] aFlags  The flags.
1065      *
1066      * @returns The preference field from the @p aFlags.
1067      *
1068      */
PreferenceFromFlags(uint16_t aFlags)1069     static int8_t PreferenceFromFlags(uint16_t aFlags)
1070     {
1071         return RoutePreferenceFromValue(static_cast<uint8_t>(aFlags >> kPreferenceOffset));
1072     }
1073 
1074 private:
1075     static constexpr uint8_t  kPreferenceOffset = 14;
1076     static constexpr uint16_t kPreferenceMask   = 3 << kPreferenceOffset;
1077     static constexpr uint16_t kPreferredFlag    = 1 << 13;
1078     static constexpr uint16_t kSlaacFlag        = 1 << 12;
1079     static constexpr uint16_t kDhcpFlag         = 1 << 11;
1080     static constexpr uint16_t kConfigureFlag    = 1 << 10;
1081     static constexpr uint16_t kDefaultRouteFlag = 1 << 9;
1082     static constexpr uint16_t kOnMeshFlag       = 1 << 8;
1083     static constexpr uint16_t kNdDnsFlag        = 1 << 7;
1084     static constexpr uint16_t kDpFlag           = 1 << 6;
1085 
1086     uint16_t mRloc;
1087     uint16_t mFlags;
1088 } OT_TOOL_PACKED_END;
1089 
1090 /**
1091  * This class implements Border Router TLV generation and parsing.
1092  *
1093  */
1094 OT_TOOL_PACKED_BEGIN
1095 class BorderRouterTlv : public NetworkDataTlv
1096 {
1097 public:
1098     static constexpr Type kType = kTypeBorderRouter; ///< The TLV Type.
1099 
1100     /**
1101      * This method initializes the TLV.
1102      *
1103      */
Init(void)1104     void Init(void)
1105     {
1106         NetworkDataTlv::Init();
1107         SetType(kTypeBorderRouter);
1108         SetLength(0);
1109     }
1110 
1111     /**
1112      * This method returns the number of Border Router entries.
1113      *
1114      * @returns The number of Border Router entries.
1115      *
1116      */
GetNumEntries(void) const1117     uint8_t GetNumEntries(void) const { return GetLength() / sizeof(BorderRouterEntry); }
1118 
1119     /**
1120      * This method returns a pointer to the Border Router entry at a given index
1121      *
1122      * @param[in]  aIndex  The index.
1123      *
1124      * @returns A pointer to the Border Router entry at @p aIndex.
1125      *
1126      */
GetEntry(uint8_t aIndex)1127     BorderRouterEntry *GetEntry(uint8_t aIndex)
1128     {
1129         return reinterpret_cast<BorderRouterEntry *>(GetValue() + (aIndex * sizeof(BorderRouterEntry)));
1130     }
1131 
1132     /**
1133      * This method returns a pointer to the Border Router entry at a given index.
1134      *
1135      * @param[in]  aIndex  The index.
1136      *
1137      * @returns A pointer to the Border Router entry at @p aIndex
1138      *
1139      */
GetEntry(uint8_t aIndex) const1140     const BorderRouterEntry *GetEntry(uint8_t aIndex) const
1141     {
1142         return reinterpret_cast<const BorderRouterEntry *>(GetValue() + (aIndex * sizeof(BorderRouterEntry)));
1143     }
1144 
1145     /**
1146      * This method returns a pointer to the first BorderRouterEntry (at index 0'th).
1147      *
1148      * @returns A pointer to the first BorderRouterEntry.
1149      *
1150      */
GetFirstEntry(void)1151     BorderRouterEntry *GetFirstEntry(void) { return reinterpret_cast<BorderRouterEntry *>(GetValue()); }
1152 
1153     /**
1154      * This method returns a pointer to the first BorderRouterEntry (at index 0'th).
1155      *
1156      * @returns A pointer to the first BorderRouterEntry.
1157      *
1158      */
GetFirstEntry(void) const1159     const BorderRouterEntry *GetFirstEntry(void) const
1160     {
1161         return reinterpret_cast<const BorderRouterEntry *>(GetValue());
1162     }
1163 
1164     /**
1165      * This method returns a pointer to the last BorderRouterEntry.
1166      *
1167      * If there are no entries the pointer will be invalid but guaranteed to be before the `GetFirstEntry()` pointer.
1168      *
1169      * @returns A pointer to the last BorderRouterEntry.
1170      *
1171      */
GetLastEntry(void)1172     BorderRouterEntry *GetLastEntry(void)
1173     {
1174         return reinterpret_cast<BorderRouterEntry *>(GetValue() + GetLength() - sizeof(BorderRouterEntry));
1175     }
1176 
1177     /**
1178      * This method returns a pointer to the last BorderRouterEntry.
1179      *
1180      * If there are no entries the pointer will be invalid but guaranteed to be before the `GetFirstEntry()` pointer.
1181      *
1182      * @returns A pointer to the last BorderRouterEntry.
1183      *
1184      */
GetLastEntry(void) const1185     const BorderRouterEntry *GetLastEntry(void) const
1186     {
1187         return reinterpret_cast<const BorderRouterEntry *>(GetValue() + GetLength() - sizeof(BorderRouterEntry));
1188     }
1189 
1190 } OT_TOOL_PACKED_END;
1191 
1192 /**
1193  * This class implements Context TLV generation and processing.
1194  *
1195  */
1196 OT_TOOL_PACKED_BEGIN
1197 class ContextTlv : public NetworkDataTlv
1198 {
1199 public:
1200     static constexpr Type kType = kTypeContext; ///< The TLV Type.
1201 
1202     /**
1203      * This method initializes the Context TLV.
1204      *
1205      * @param[in]  aContextId      The Context ID value.
1206      * @param[in]  aContextLength  The Context Length value.
1207      *
1208      */
Init(uint8_t aContextId,uint8_t aContextLength)1209     void Init(uint8_t aContextId, uint8_t aContextLength)
1210     {
1211         NetworkDataTlv::Init();
1212         SetType(kTypeContext);
1213         SetLength(sizeof(ContextTlv) - sizeof(NetworkDataTlv));
1214         mFlags         = ((aContextId << kContextIdOffset) & kContextIdMask);
1215         mContextLength = aContextLength;
1216     }
1217 
1218     /**
1219      * This method indicates whether or not the Compress flag is set.
1220      *
1221      * @retval TRUE   The Compress flag is set.
1222      * @retval FALSE  The Compress flags is not set.
1223      *
1224      */
IsCompress(void) const1225     bool IsCompress(void) const { return (mFlags & kCompressFlag) != 0; }
1226 
1227     /**
1228      * This method clears the Compress flag.
1229      *
1230      */
ClearCompress(void)1231     void ClearCompress(void) { mFlags &= ~kCompressFlag; }
1232 
1233     /**
1234      * This method sets the Compress flag.
1235      *
1236      */
SetCompress(void)1237     void SetCompress(void) { mFlags |= kCompressFlag; }
1238 
1239     /**
1240      * This method returns the Context ID value.
1241      *
1242      * @returns The Context ID value.
1243      *
1244      */
GetContextId(void) const1245     uint8_t GetContextId(void) const { return mFlags & kContextIdMask; }
1246 
1247     /**
1248      * This method returns the Context Length value.
1249      *
1250      * @returns The Context Length value.
1251      *
1252      */
GetContextLength(void) const1253     uint8_t GetContextLength(void) const { return mContextLength; }
1254 
1255 private:
1256     static constexpr uint8_t kCompressFlag    = 1 << 4;
1257     static constexpr uint8_t kContextIdOffset = 0;
1258     static constexpr uint8_t kContextIdMask   = 0xf << kContextIdOffset;
1259 
1260     uint8_t mFlags;
1261     uint8_t mContextLength;
1262 } OT_TOOL_PACKED_END;
1263 
1264 /**
1265  * This class implements Commissioning Data TLV generation and parsing.
1266  *
1267  */
1268 OT_TOOL_PACKED_BEGIN
1269 class CommissioningDataTlv : public NetworkDataTlv
1270 {
1271 public:
1272     static constexpr Type kType = kTypeCommissioningData; ///< The TLV Type.
1273 
1274     /**
1275      * This method initializes the TLV.
1276      *
1277      */
Init(void)1278     void Init(void)
1279     {
1280         NetworkDataTlv::Init();
1281         SetType(kTypeCommissioningData);
1282         SetLength(0);
1283     }
1284 } OT_TOOL_PACKED_END;
1285 
1286 /**
1287  * This class implements Service Data TLV generation and parsing.
1288  *
1289  */
1290 OT_TOOL_PACKED_BEGIN
1291 class ServiceTlv : public NetworkDataTlv
1292 {
1293 public:
1294     static constexpr Type kType = kTypeService; ///< The TLV Type.
1295 
1296     static constexpr uint32_t kThreadEnterpriseNumber = 44970; ///< Thread enterprise number.
1297 
1298     /**
1299      * This method initializes the TLV.
1300      *
1301      * @param[in]  aServiceId          The Service Id value.
1302      * @param[in]  aEnterpriseNumber   The Enterprise Number.
1303      * @param[in]  aServiceData        The Service Data.
1304      *
1305      */
1306     void Init(uint8_t aServiceId, uint32_t aEnterpriseNumber, const ServiceData &aServiceData);
1307 
1308     /**
1309      * This method indicates whether or not the TLV appears to be well-formed.
1310      *
1311      * @retval TRUE   If the TLV appears to be well-formed.
1312      * @retval FALSE  If the TLV does not appear to be well-formed.
1313      *
1314      */
IsValid(void) const1315     bool IsValid(void) const
1316     {
1317         uint8_t length = GetLength();
1318 
1319         return (length >= sizeof(mFlagsServiceId)) &&
1320                (length >= kMinLength + (IsThreadEnterprise() ? 0 : sizeof(uint32_t))) &&
1321                (static_cast<uint16_t>(length) + sizeof(NetworkDataTlv) >=
1322                 CalculateSize(GetEnterpriseNumber(), GetServiceDataLength()));
1323     }
1324 
1325     /**
1326      * This method returns the Service ID. It is in range 0x00-0x0f.
1327      *
1328      * @returns the Service ID.
1329      *
1330      */
GetServiceId(void) const1331     uint8_t GetServiceId(void) const { return (mFlagsServiceId & kServiceIdMask); }
1332 
1333     /**
1334      * This method returns Enterprise Number field.
1335      *
1336      * @returns The Enterprise Number.
1337      *
1338      */
GetEnterpriseNumber(void) const1339     uint32_t GetEnterpriseNumber(void) const
1340     {
1341         return IsThreadEnterprise() ? static_cast<uint32_t>(kThreadEnterpriseNumber)
1342                                     : HostSwap32(mShared.mEnterpriseNumber);
1343     }
1344 
1345     /**
1346      * This method gets the Service Data.
1347      *
1348      * @param[out] aServiceData   A reference to a`ServiceData` to return the data.
1349      *
1350      */
GetServiceData(ServiceData & aServiceData) const1351     void GetServiceData(ServiceData &aServiceData) const
1352     {
1353         aServiceData.Init(GetServiceData(), GetServiceDataLength());
1354     }
1355 
1356     /**
1357      * This method gets Service Data length.
1358      *
1359      * @returns length of the Service Data field in bytes.
1360      *
1361      */
GetServiceDataLength(void) const1362     uint8_t GetServiceDataLength(void) const
1363     {
1364         return IsThreadEnterprise() ? mShared.mServiceDataLengthThreadEnterprise : mServiceDataLength;
1365     }
1366 
1367     /**
1368      * This method returns the Sub-TLVs length in bytes.
1369      *
1370      * @returns The Sub-TLVs length in bytes.
1371      *
1372      */
GetSubTlvsLength(void)1373     uint8_t GetSubTlvsLength(void) { return GetLength() - GetFieldsLength(); }
1374 
1375     /**
1376      * This method sets the Sub-TLVs length in bytes.
1377      *
1378      * @param[in]  aLength  The Sub-TLVs length in bytes.
1379      *
1380      */
SetSubTlvsLength(uint8_t aLength)1381     void SetSubTlvsLength(uint8_t aLength) { SetLength(GetFieldsLength() + aLength); }
1382 
1383     /**
1384      * This method returns a pointer to the Sub-TLVs.
1385      *
1386      * @returns A pointer to the Sub-TLVs.
1387      *
1388      */
GetSubTlvs(void)1389     NetworkDataTlv *GetSubTlvs(void) { return reinterpret_cast<NetworkDataTlv *>(GetValue() + GetFieldsLength()); }
1390 
1391     /**
1392      * This method returns a pointer to the Sub-TLVs.
1393      *
1394      * @returns A pointer to the Sub-TLVs.
1395      *
1396      */
GetSubTlvs(void) const1397     const NetworkDataTlv *GetSubTlvs(void) const
1398     {
1399         return reinterpret_cast<const NetworkDataTlv *>(GetValue() + GetFieldsLength());
1400     }
1401 
1402     /**
1403      * This static method calculates the total size (number of bytes) of a Service TLV with a given Enterprise Number
1404      * and Service Data length.
1405      *
1406      * Note that the returned size does include the Type and Length fields in the TLV, but does not account for any
1407      * sub-TLVs of the Service TLV.
1408      *
1409      * @param[in]  aEnterpriseNumber   A Enterprise Number.
1410      * @param[in]  aServiceDataLength  A Service Data length.
1411      *
1412      * @returns    The size (number of bytes) of the Service TLV.
1413      *
1414      */
CalculateSize(uint32_t aEnterpriseNumber,uint8_t aServiceDataLength)1415     static uint16_t CalculateSize(uint32_t aEnterpriseNumber, uint8_t aServiceDataLength)
1416     {
1417         return sizeof(NetworkDataTlv) + kMinLength + aServiceDataLength +
1418                ((aEnterpriseNumber == kThreadEnterpriseNumber) ? 0 : sizeof(uint32_t) /* mEnterpriseNumber  */);
1419     }
1420 
1421 private:
IsThreadEnterprise(void) const1422     bool IsThreadEnterprise(void) const { return (mFlagsServiceId & kThreadEnterpriseFlag) != 0; }
1423 
GetServiceData(void) const1424     const uint8_t *GetServiceData(void) const
1425     {
1426         return (IsThreadEnterprise() ? &mShared.mServiceDataLengthThreadEnterprise : &mServiceDataLength) +
1427                sizeof(uint8_t);
1428     }
1429 
GetFieldsLength(void) const1430     uint8_t GetFieldsLength(void) const
1431     {
1432         // Returns the length of TLV value's common fields (flags, enterprise
1433         // number and service data) excluding any sub-TLVs.
1434 
1435         return kMinLength + (IsThreadEnterprise() ? 0 : sizeof(uint32_t)) + GetServiceDataLength();
1436     }
1437 
1438     static constexpr uint8_t kThreadEnterpriseFlag = (1 << 7);
1439     static constexpr uint8_t kServiceIdMask        = 0xf;
1440     static constexpr uint8_t kMinLength            = sizeof(uint8_t) + sizeof(uint8_t); // Flags & Service Data length.
1441 
1442     // When `kThreadEnterpriseFlag is set in the `mFlagsServiceId`, the
1443     // `mEnterpriseNumber` field is elided and `mFlagsServiceId` is
1444     // immediately followed by the Service Data length field (which is
1445     // represented by `mServiceDataLengthThreadEnterprise`)
1446 
1447     uint8_t mFlagsServiceId;
1448     union OT_TOOL_PACKED_FIELD
1449     {
1450         uint32_t mEnterpriseNumber;
1451         uint8_t  mServiceDataLengthThreadEnterprise;
1452     } mShared;
1453     uint8_t mServiceDataLength;
1454 
1455 } OT_TOOL_PACKED_END;
1456 
1457 /**
1458  * This class implements Server Data TLV generation and parsing.
1459  *
1460  */
1461 OT_TOOL_PACKED_BEGIN
1462 class ServerTlv : public NetworkDataTlv
1463 {
1464 public:
1465     static constexpr Type kType = kTypeServer; ///< The TLV Type.
1466 
1467     /**
1468      * This method initializes the Server TLV.
1469      *
1470      * @param[in] aServer16          The Server16 value.
1471      * @param[in] aServerData        The Server Data.
1472      *
1473      */
Init(uint16_t aServer16,const ServerData & aServerData)1474     void Init(uint16_t aServer16, const ServerData &aServerData)
1475     {
1476         NetworkDataTlv::Init();
1477         SetType(kTypeServer);
1478         SetServer16(aServer16);
1479         aServerData.CopyBytesTo(GetServerData());
1480         SetLength(sizeof(*this) - sizeof(NetworkDataTlv) + aServerData.GetLength());
1481     }
1482 
1483     /**
1484      * This method indicates whether or not the TLV appears to be well-formed.
1485      *
1486      * @retval TRUE   If the TLV appears to be well-formed.
1487      * @retval FALSE  If the TLV does not appear to be well-formed.
1488      *
1489      */
IsValid(void) const1490     bool IsValid(void) const { return GetLength() >= (sizeof(*this) - sizeof(NetworkDataTlv)); }
1491 
1492     /**
1493      * This method returns the Server16 value.
1494      *
1495      * @returns The Server16 value.
1496      *
1497      */
GetServer16(void) const1498     uint16_t GetServer16(void) const { return HostSwap16(mServer16); }
1499 
1500     /*
1501      * This method sets the Server16 value.
1502      *
1503      * @param[in]  aServer16  The Server16 value.
1504      *
1505      */
SetServer16(uint16_t aServer16)1506     void SetServer16(uint16_t aServer16) { mServer16 = HostSwap16(aServer16); }
1507 
1508     /**
1509      * This method gets the Server Data.
1510      *
1511      * @param[out] aServerData   A reference to a`ServerData` to return the data.
1512      *
1513      */
GetServerData(ServerData & aServerData) const1514     void GetServerData(ServerData &aServerData) const { aServerData.Init(GetServerData(), GetServerDataLength()); }
1515 
1516     /**
1517      * This method returns the Server Data length in bytes.
1518      *
1519      * @returns The Server Data length in bytes.
1520      *
1521      */
GetServerDataLength(void) const1522     uint8_t GetServerDataLength(void) const { return GetLength() - (sizeof(*this) - sizeof(NetworkDataTlv)); }
1523 
1524     /**
1525      * This method indicates whether two Server TLVs fully match.
1526      *
1527      * @param[in]  aOther  Another Server TLV to compare with it.
1528      *
1529      * @retval TRUE  The two TLVs are equal.
1530      * @retval FALSE The two TLVs are not equal.
1531      *
1532      */
operator ==(const ServerTlv & aOther) const1533     bool operator==(const ServerTlv &aOther) const
1534     {
1535         return (GetLength() == aOther.GetLength()) && (memcmp(GetValue(), aOther.GetValue(), GetLength()) == 0);
1536     }
1537 
1538     /**
1539      * This static method calculates the total size (number of bytes) of a Service TLV with a given Server Data length.
1540      *
1541      * Note that the returned size does include the Type and Length fields in the TLV.
1542      *
1543      * @param[in]  aServerDataLength    Server Data length in bytes.
1544      *
1545      * @returns    The size (number of bytes) of the Server TLV.
1546      *
1547      */
CalculateSize(uint8_t aServerDataLength)1548     static uint16_t CalculateSize(uint8_t aServerDataLength) { return sizeof(ServerTlv) + aServerDataLength; }
1549 
1550 private:
GetServerData(void) const1551     const uint8_t *GetServerData(void) const { return reinterpret_cast<const uint8_t *>(this) + sizeof(*this); }
GetServerData(void)1552     uint8_t       *GetServerData(void) { return AsNonConst(AsConst(this)->GetServerData()); }
1553 
1554     uint16_t mServer16;
1555 } OT_TOOL_PACKED_END;
1556 
1557 /**
1558  * This class represents a Network Data TLV iterator.
1559  *
1560  */
1561 class TlvIterator
1562 {
1563 public:
1564     /**
1565      * This constructor initializes the `TlvIterator` to iterate over a given sequence of TLVs.
1566      *
1567      * @param[in] aStart  A pointer to the start of the TLV sequence.
1568      * @param[in] aEnd    A pointer to the end of the TLV sequence.
1569      *
1570      */
TlvIterator(const NetworkDataTlv * aStart,const NetworkDataTlv * aEnd)1571     TlvIterator(const NetworkDataTlv *aStart, const NetworkDataTlv *aEnd)
1572         : mStart(aStart)
1573         , mEnd(aEnd)
1574     {
1575     }
1576 
1577     /**
1578      * This constructor initializes the `TlvIterator` to iterate over TLVs from a given buffer.
1579      *
1580      * @param[in] aBuffer   A pointer to a buffer containing the TLVs.
1581      * @param[in] aLength   The length (number of bytes) of @p aBuffer.
1582      *
1583      */
TlvIterator(const uint8_t * aBuffer,uint8_t aLength)1584     TlvIterator(const uint8_t *aBuffer, uint8_t aLength)
1585         : TlvIterator(reinterpret_cast<const NetworkDataTlv *>(aBuffer),
1586                       reinterpret_cast<const NetworkDataTlv *>(aBuffer + aLength))
1587     {
1588     }
1589 
1590     /**
1591      * This constructor initializes the `TlvIterator` to iterate over sub-TLVs of a given Prefix TLV.
1592      *
1593      * @param[in] aPrefixTlv   A Prefix TLV to iterate over its sub-TLVs.
1594      *
1595      */
TlvIterator(const PrefixTlv & aPrefixTlv)1596     explicit TlvIterator(const PrefixTlv &aPrefixTlv)
1597         : TlvIterator(aPrefixTlv.GetSubTlvs(), aPrefixTlv.GetNext())
1598     {
1599     }
1600 
1601     /**
1602      * This constructor initializes the `TlvIterator` to iterate over sub-TLVs of a given Service TLV.
1603      *
1604      * @param[in] aServiceTlv   A Service TLV to iterate over its sub-TLVs.
1605      *
1606      */
TlvIterator(const ServiceTlv & aServiceTlv)1607     explicit TlvIterator(const ServiceTlv &aServiceTlv)
1608         : TlvIterator(aServiceTlv.GetSubTlvs(), aServiceTlv.GetNext())
1609     {
1610     }
1611 
1612     /**
1613      * This template method iterates to the next TLV with a given type.
1614      *
1615      * @tparam  TlvType The TLV Type to search for (MUST be a sub-class of `NetworkDataTlv`).
1616      *
1617      * @returns A pointer to the next TLV, or `nullptr` if it can not be found.
1618      *
1619      */
Iterate(void)1620     template <typename TlvType> const TlvType *Iterate(void) { return As<TlvType>(Iterate(TlvType::kType)); }
1621 
1622     /**
1623      * This template method iterates to the next TLV with a given type and stable flag.
1624      *
1625      * @tparam  TlvType The TLV Type to search for (MUST be a sub-class of `NetworkDataTlv`).
1626      *
1627      * @param[in]  aStable      TRUE to find a stable TLV, FALSE to find a TLV not marked as stable.
1628      *
1629      * @returns A pointer to the next TLV, or `nullptr` if it can not be found.
1630      *
1631      */
Iterate(bool aStable)1632     template <typename TlvType> const TlvType *Iterate(bool aStable)
1633     {
1634         return As<TlvType>(Iterate(TlvType::kType, aStable));
1635     }
1636 
1637 private:
1638     const NetworkDataTlv *Iterate(NetworkDataTlv::Type aType);
1639     const NetworkDataTlv *Iterate(NetworkDataTlv::Type aType, bool aStable);
1640 
1641     const NetworkDataTlv *mStart;
1642     const NetworkDataTlv *mEnd;
1643 };
1644 
1645 /**
1646  * @}
1647  *
1648  */
1649 
1650 } // namespace NetworkData
1651 } // namespace ot
1652 
1653 #endif // NETWORK_DATA_TLVS_HPP_
1654