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 MLE TLVs.
32  */
33 
34 #ifndef TLVS_HPP_
35 #define TLVS_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include <openthread/thread.h>
40 #include <openthread/platform/toolchain.h>
41 
42 #include "common/encoding.hpp"
43 #include "common/error.hpp"
44 #include "common/type_traits.hpp"
45 
46 namespace ot {
47 
48 using ot::Encoding::BigEndian::HostSwap16;
49 
50 class Message;
51 
52 /**
53  * Implements TLV generation and parsing.
54  *
55  */
56 OT_TOOL_PACKED_BEGIN
57 class Tlv
58 {
59 public:
60     /**
61      * The maximum length of the Base TLV format.
62      *
63      */
64     static constexpr uint8_t kBaseTlvMaxLength = OT_NETWORK_BASE_TLV_MAX_LENGTH;
65 
66     /**
67      * Returns the Type value.
68      *
69      * @returns The Type value.
70      *
71      */
GetType(void) const72     uint8_t GetType(void) const { return mType; }
73 
74     /**
75      * Sets the Type value.
76      *
77      * @param[in]  aType  The Type value.
78      *
79      */
SetType(uint8_t aType)80     void SetType(uint8_t aType) { mType = aType; }
81 
82     /**
83      * Indicates whether the TLV is an Extended TLV.
84      *
85      * @retval TRUE  If the TLV is an Extended TLV.
86      * @retval FALSE If the TLV is not an Extended TLV.
87      *
88      */
IsExtended(void) const89     bool IsExtended(void) const { return (mLength == kExtendedLength); }
90 
91     /**
92      * Returns the Length value.
93      *
94      * @note This method should be used when TLV is not an Extended TLV, otherwise the returned length from this method
95      * would not be correct. When TLV is an Extended TLV, the TLV should be down-casted to the `ExtendedTlv` type and
96      * the `ExtendedTlv::GetLength()` should be used instead.
97      *
98      * @returns The Length value.
99      *
100      */
GetLength(void) const101     uint8_t GetLength(void) const { return mLength; }
102 
103     /**
104      * Sets the Length value.
105      *
106      * @param[in]  aLength  The Length value.
107      *
108      */
SetLength(uint8_t aLength)109     void SetLength(uint8_t aLength) { mLength = aLength; }
110 
111     /**
112      * Returns the TLV's total size (number of bytes) including Type, Length, and Value fields.
113      *
114      * Correctly returns the TLV size independent of whether the TLV is an Extended TLV or not.
115      *
116      * @returns The total size include Type, Length, and Value fields.
117      *
118      */
119     uint32_t GetSize(void) const;
120 
121     /**
122      * Returns a pointer to the Value.
123      *
124      * Can be used independent of whether the TLV is an Extended TLV or not.
125      *
126      * @returns A pointer to the value.
127      *
128      */
129     uint8_t *GetValue(void);
130 
131     /**
132      * Returns a pointer to the Value.
133      *
134      * Can be used independent of whether the TLV is an Extended TLV or not.
135      *
136      * @returns A pointer to the value.
137      *
138      */
139     const uint8_t *GetValue(void) const;
140 
141     /**
142      * Returns a pointer to the next TLV.
143      *
144      * Correctly returns the next TLV independent of whether the current TLV is an Extended TLV or not.
145      *
146      * @returns A pointer to the next TLV.
147      *
148      */
GetNext(void)149     Tlv *GetNext(void) { return reinterpret_cast<Tlv *>(reinterpret_cast<uint8_t *>(this) + GetSize()); }
150 
151     /**
152      * Returns a pointer to the next TLV.
153      *
154      * Correctly returns the next TLV independent of whether the current TLV is an Extended TLV or not.
155      *
156      * @returns A pointer to the next TLV.
157      *
158      */
GetNext(void) const159     const Tlv *GetNext(void) const
160     {
161         return reinterpret_cast<const Tlv *>(reinterpret_cast<const uint8_t *>(this) + GetSize());
162     }
163 
164     /**
165      * Appends a TLV to the end of the message.
166      *
167      * On success, this method grows the message by the size of the TLV.
168      *
169      * @param[in]  aMessage      A reference to the message to append to.
170      *
171      * @retval kErrorNone     Successfully appended the TLV to the message.
172      * @retval kErrorNoBufs   Insufficient available buffers to grow the message.
173      *
174      */
175     Error AppendTo(Message &aMessage) const;
176 
177     /**
178      * Reads a TLV's value in a message at a given offset expecting a minimum length for the value.
179      *
180      * Can be used independent of whether the read TLV (from the message) is an Extended TLV or not.
181      *
182      * @param[in]   aMessage    The message to read from.
183      * @param[in]   aOffset     The offset into the message pointing to the start of the TLV.
184      * @param[out]  aValue      A buffer to output the TLV's value, must contain (at least) @p aMinLength bytes.
185      * @param[in]   aMinLength  The minimum expected length of TLV and number of bytes to copy into @p aValue buffer.
186      *
187      * @retval kErrorNone        Successfully read the TLV and copied @p aMinLength into @p aValue.
188      * @retval kErrorParse       The TLV was not well-formed and could not be parsed.
189      *
190      */
191     static Error ReadTlvValue(const Message &aMessage, uint16_t aOffset, void *aValue, uint8_t aMinLength);
192 
193     /**
194      * Reads a simple TLV with a single non-integral value in a message at a given offset.
195      *
196      * @tparam      SimpleTlvType   The simple TLV type to read (must be a sub-class of `SimpleTlvInfo`).
197      *
198      * @param[in]   aMessage        The message to read from.
199      * @param[in]   aOffset         The offset into the message pointing to the start of the TLV.
200      * @param[out]  aValue          A reference to the value object to output the read value.
201      *
202      * @retval kErrorNone        Successfully read the TLV and updated the @p aValue.
203      * @retval kErrorParse       The TLV was not well-formed and could not be parsed.
204      *
205      */
206     template <typename SimpleTlvType>
Read(const Message & aMessage,uint16_t aOffset,typename SimpleTlvType::ValueType & aValue)207     static Error Read(const Message &aMessage, uint16_t aOffset, typename SimpleTlvType::ValueType &aValue)
208     {
209         return ReadTlvValue(aMessage, aOffset, &aValue, sizeof(aValue));
210     }
211 
212     /**
213      * Reads a simple TLV with a single integral value in a message at a given offset.
214      *
215      * @tparam      UintTlvType     The simple TLV type to read (must be a sub-class of `UintTlvInfo`).
216      *
217      * @param[in]   aMessage        The message to read from.
218      * @param[in]   aOffset         The offset into the message pointing to the start of the TLV.
219      * @param[out]  aValue          A reference to an unsigned int to output the read value.
220      *
221      * @retval kErrorNone        Successfully read the TLV and updated the @p aValue.
222      * @retval kErrorParse       The TLV was not well-formed and could not be parsed.
223      *
224      */
225     template <typename UintTlvType>
Read(const Message & aMessage,uint16_t aOffset,typename UintTlvType::UintValueType & aValue)226     static Error Read(const Message &aMessage, uint16_t aOffset, typename UintTlvType::UintValueType &aValue)
227     {
228         return ReadUintTlv(aMessage, aOffset, aValue);
229     }
230 
231     /**
232      * Reads a simple TLV with a UTF-8 string value in a message at a given offset.
233      *
234      * @tparam      StringTlvType   The simple TLV type to read (must be a sub-class of `StringTlvInfo`).
235      *
236      * @param[in]   aMessage        The message to read from.
237      * @param[in]   aOffset         The offset into the message pointing to the start of the TLV.
238      * @param[out]  aValue          A reference to the string buffer to output the read value.
239      *
240      * @retval kErrorNone        Successfully read the TLV and updated the @p aValue.
241      * @retval kErrorParse       The TLV was not well-formed and could not be parsed.
242      *
243      */
244     template <typename StringTlvType>
Read(const Message & aMessage,uint16_t aOffset,typename StringTlvType::StringType & aValue)245     static Error Read(const Message &aMessage, uint16_t aOffset, typename StringTlvType::StringType &aValue)
246     {
247         return ReadStringTlv(aMessage, aOffset, StringTlvType::kMaxStringLength, aValue);
248     }
249 
250     /**
251      * Searches for and reads a requested TLV out of a given message.
252      *
253      * Can be used independent of whether the read TLV (from message) is an Extended TLV or not.
254      *
255      * @param[in]   aMessage    A reference to the message.
256      * @param[in]   aType       The Type value to search for.
257      * @param[in]   aMaxSize    Maximum number of bytes to read.
258      * @param[out]  aTlv        A reference to the TLV that will be copied to.
259      *
260      * @retval kErrorNone       Successfully copied the TLV.
261      * @retval kErrorNotFound   Could not find the TLV with Type @p aType.
262      *
263      */
264     static Error FindTlv(const Message &aMessage, uint8_t aType, uint16_t aMaxSize, Tlv &aTlv);
265 
266     /**
267      * Searches for and reads a requested TLV out of a given message.
268      *
269      * Can be used independent of whether the read TLV (from message) is an Extended TLV or not.
270      *
271      * @param[in]   aMessage    A reference to the message.
272      * @param[in]   aType       The Type value to search for.
273      * @param[in]   aMaxSize    Maximum number of bytes to read.
274      * @param[out]  aTlv        A reference to the TLV that will be copied to.
275      * @param[out]  aOffset     A reference to return the offset to start of the TLV in @p aMessage.
276      *
277      * @retval kErrorNone       Successfully copied the TLV.
278      * @retval kErrorNotFound   Could not find the TLV with Type @p aType.
279      *
280      */
281     static Error FindTlv(const Message &aMessage, uint8_t aType, uint16_t aMaxSize, Tlv &aTlv, uint16_t &aOffset);
282 
283     /**
284      * Searches for and reads a requested TLV out of a given message.
285      *
286      * Can be used independent of whether the read TLV (from message) is an Extended TLV or not.
287      *
288      * @tparam      TlvType     The TlvType to search for (must be a sub-class of `Tlv`).
289      *
290      * @param[in]   aMessage    A reference to the message.
291      * @param[out]  aTlv        A reference to the TLV that will be copied to.
292      *
293      * @retval kErrorNone       Successfully copied the TLV.
294      * @retval kErrorNotFound   Could not find the TLV with Type @p aType.
295      *
296      */
FindTlv(const Message & aMessage,TlvType & aTlv)297     template <typename TlvType> static Error FindTlv(const Message &aMessage, TlvType &aTlv)
298     {
299         return FindTlv(aMessage, TlvType::kType, sizeof(TlvType), aTlv);
300     }
301 
302     /**
303      * Searches for and reads a requested TLV out of a given message.
304      *
305      * Can be used independent of whether the read TLV (from message) is an Extended TLV or not.
306      *
307      * @tparam      TlvType     The TlvType to search for (must be a sub-class of `Tlv`).
308      *
309      * @param[in]   aMessage    A reference to the message.
310      * @param[out]  aTlv        A reference to the TLV that will be copied to.
311      * @param[out]  aOffset     A reference to return the offset to start of the TLV in @p aMessage.
312      *
313      * @retval kErrorNone       Successfully copied the TLV.
314      * @retval kErrorNotFound   Could not find the TLV with Type @p aType.
315      *
316      */
FindTlv(const Message & aMessage,TlvType & aTlv,uint16_t & aOffset)317     template <typename TlvType> static Error FindTlv(const Message &aMessage, TlvType &aTlv, uint16_t &aOffset)
318     {
319         return FindTlv(aMessage, TlvType::kType, sizeof(TlvType), aTlv, aOffset);
320     }
321 
322     /**
323      * Finds the offset and length of TLV value for a given TLV type within @p aMessage.
324      *
325      * Can be used independent of whether the read TLV (from message) is an Extended TLV or not.
326      *
327      * @param[in]   aMessage      A reference to the message.
328      * @param[in]   aType         The Type value to search for.
329      * @param[out]  aValueOffset  The offset where the value starts.
330      * @param[out]  aLength       The length of the value.
331      *
332      * @retval kErrorNone       Successfully found the TLV.
333      * @retval kErrorNotFound   Could not find the TLV with Type @p aType.
334      *
335      */
336     static Error FindTlvValueOffset(const Message &aMessage, uint8_t aType, uint16_t &aValueOffset, uint16_t &aLength);
337 
338     /**
339      * Finds the start and end offset of TLV value for a given TLV type with @p aMessage.
340      *
341      * Can be used independent of whether the read TLV (from message) is an Extended TLV or not.
342      *
343      * @param[in]   aMessage           A reference to the message.
344      * @param[in]   aType              The Type value to search for.
345      * @param[out]  aValueStartOffset  The offset where the value starts.
346      * @param[out]  aValueEndOffset    The offset immediately after the last byte of value.
347      *
348      * @retval kErrorNone       Successfully found the TLV.
349      * @retval kErrorNotFound   Could not find the TLV with Type @p aType.
350      *
351      */
352     static Error FindTlvValueStartEndOffsets(const Message &aMessage,
353                                              uint8_t        aType,
354                                              uint16_t      &aValueStartOffset,
355                                              uint16_t      &aValueEndOffset);
356 
357     /**
358      * Searches for a TLV with a given type in a message, ensures its length is same or larger than
359      * an expected minimum value, and then reads its value into a given buffer.
360      *
361      * If the TLV length is smaller than the minimum length @p aLength, the TLV is considered invalid. In this case,
362      * this method returns `kErrorParse` and the @p aValue buffer is not updated.
363      *
364      * If the TLV length is larger than @p aLength, the TLV is considered valid, but only the first @p aLength bytes
365      * of the value are read and copied into the @p aValue buffer.
366      *
367      * @tparam       TlvType     The TLV type to find.
368      *
369      * @param[in]    aMessage    A reference to the message.
370      * @param[out]   aValue      A buffer to output the value (must contain at least @p aLength bytes).
371      * @param[in]    aLength     The expected (minimum) length of the TLV value.
372      *
373      * @retval kErrorNone       The TLV was found and read successfully. @p aValue is updated.
374      * @retval kErrorNotFound   Could not find the TLV with Type @p aType.
375      * @retval kErrorParse      TLV was found but it was not well-formed and could not be parsed.
376      *
377      */
Find(const Message & aMessage,void * aValue,uint8_t aLength)378     template <typename TlvType> static Error Find(const Message &aMessage, void *aValue, uint8_t aLength)
379     {
380         return FindTlv(aMessage, TlvType::kType, aValue, aLength);
381     }
382 
383     /**
384      * Searches for a simple TLV with a single non-integral value in a message, ensures its length is
385      * same or larger than the expected `ValueType` object size, and then reads its value into a value object reference.
386      *
387      * If the TLV length is smaller than the size of @p aValue, the TLV is considered invalid. In this case, this
388      * method returns `kErrorParse` and the @p aValue is not updated.
389      *
390      * If the TLV length is larger than the size of @p aValue, the TLV is considered valid, but the size of
391      * `ValueType` bytes are read and copied into the @p aValue.
392      *
393      * @tparam       SimpleTlvType   The simple TLV type to find (must be a sub-class of `SimpleTlvInfo`)
394      *
395      * @param[in]    aMessage        A reference to the message.
396      * @param[out]   aValue          A reference to the value object to output the read value.
397      *
398      * @retval kErrorNone         The TLV was found and read successfully. @p aValue is updated.
399      * @retval kErrorNotFound     Could not find the TLV with Type @p aType.
400      * @retval kErrorParse        TLV was found but it was not well-formed and could not be parsed.
401      *
402      */
403     template <typename SimpleTlvType>
Find(const Message & aMessage,typename SimpleTlvType::ValueType & aValue)404     static Error Find(const Message &aMessage, typename SimpleTlvType::ValueType &aValue)
405     {
406         return FindTlv(aMessage, SimpleTlvType::kType, &aValue, sizeof(aValue));
407     }
408 
409     /**
410      * Searches for a simple TLV with a single integral value in a message, and then reads its value
411      * into a given `uint` reference variable.
412      *
413      * If the TLV length is smaller than size of integral value, the TLV is considered invalid. In this case, this
414      * method returns `kErrorParse` and the @p aValue is not updated.
415      *
416      * @tparam       UintTlvType     The simple TLV type to find (must be a sub-class of `UintTlvInfo`)
417      *
418      * @param[in]    aMessage        A reference to the message.
419      * @param[out]   aValue          A reference to an unsigned int value to output the TLV's value.
420      *
421      * @retval kErrorNone         The TLV was found and read successfully. @p aValue is updated.
422      * @retval kErrorNotFound     Could not find the TLV with Type @p aType.
423      * @retval kErrorParse        TLV was found but it was not well-formed and could not be parsed.
424      *
425      */
426     template <typename UintTlvType>
Find(const Message & aMessage,typename UintTlvType::UintValueType & aValue)427     static Error Find(const Message &aMessage, typename UintTlvType::UintValueType &aValue)
428     {
429         return FindUintTlv(aMessage, UintTlvType::kType, aValue);
430     }
431 
432     /**
433      * Searches for a simple TLV with a UTF-8 string value in a message, and then reads its value
434      * into a given string buffer.
435      *
436      * If the TLV length is longer than maximum string length specified by `StringTlvType::kMaxStringLength` then
437      * only up to maximum length is read and returned. In this case `kErrorNone` is returned.
438      *
439      * The returned string in @p aValue is always null terminated.`StringTlvType::StringType` MUST have at least
440      * `kMaxStringLength + 1` chars.
441      *
442      * @tparam       StringTlvType  The simple TLV type to find (must be a sub-class of `StringTlvInfo`)
443      *
444      * @param[in]    aMessage        A reference to the message.
445      * @param[out]   aValue          A reference to a string buffer to output the TLV's value.
446      *
447      * @retval kErrorNone         The TLV was found and read successfully. @p aValue is updated.
448      * @retval kErrorNotFound     Could not find the TLV with Type @p aType.
449      * @retval kErrorParse        TLV was found but it was not well-formed and could not be parsed.
450      *
451      */
452     template <typename StringTlvType>
Find(const Message & aMessage,typename StringTlvType::StringType & aValue)453     static Error Find(const Message &aMessage, typename StringTlvType::StringType &aValue)
454     {
455         return FindStringTlv(aMessage, StringTlvType::kType, StringTlvType::kMaxStringLength, aValue);
456     }
457 
458     /**
459      * Appends a TLV with a given type and value to a message.
460      *
461      * On success this method grows the message by the size of the TLV.
462      *
463      * @tparam     TlvType       The TLV type to append.
464      *
465      * @param[in]  aMessage      A reference to the message to append to.
466      * @param[in]  aValue        A buffer containing the TLV value.
467      * @param[in]  aLength       The value length (in bytes).
468      *
469      * @retval kErrorNone     Successfully appended the TLV to the message.
470      * @retval kErrorNoBufs   Insufficient available buffers to grow the message.
471      *
472      */
Append(Message & aMessage,const void * aValue,uint8_t aLength)473     template <typename TlvType> static Error Append(Message &aMessage, const void *aValue, uint8_t aLength)
474     {
475         return AppendTlv(aMessage, TlvType::kType, aValue, aLength);
476     }
477 
478     /**
479      * Appends a simple TLV with a single (non-integral) value to a message.
480      *
481      * On success this method grows the message by the size of the TLV.
482      *
483      * @tparam     SimpleTlvType The simple TLV type to append (must be a sub-class of `SimpleTlvInfo`)
484      *
485      * @param[in]  aMessage      A reference to the message to append to.
486      * @param[in]  aValue        A reference to the object containing TLV's value.
487      *
488      * @retval kErrorNone     Successfully appended the TLV to the message.
489      * @retval kErrorNoBufs   Insufficient available buffers to grow the message.
490      *
491      */
492     template <typename SimpleTlvType>
Append(Message & aMessage,const typename SimpleTlvType::ValueType & aValue)493     static Error Append(Message &aMessage, const typename SimpleTlvType::ValueType &aValue)
494     {
495         return AppendTlv(aMessage, SimpleTlvType::kType, &aValue, sizeof(aValue));
496     }
497 
498     /**
499      * Appends a simple TLV with a single integral value to a message.
500      *
501      * On success this method grows the message by the size of the TLV.
502      *
503      * @tparam     UintTlvType   The simple TLV type to append (must be a sub-class of `UintTlvInfo`)
504      *
505      * @param[in]  aMessage      A reference to the message to append to.
506      * @param[in]  aValue        An unsigned int value to use as TLV's value.
507      *
508      * @retval kErrorNone     Successfully appended the TLV to the message.
509      * @retval kErrorNoBufs   Insufficient available buffers to grow the message.
510      *
511      */
Append(Message & aMessage,typename UintTlvType::UintValueType aValue)512     template <typename UintTlvType> static Error Append(Message &aMessage, typename UintTlvType::UintValueType aValue)
513     {
514         return AppendUintTlv(aMessage, UintTlvType::kType, aValue);
515     }
516 
517     /**
518      * Appends a simple TLV with a single UTF-8 string value to a message.
519      *
520      * On success this method grows the message by the size of the TLV.
521      *
522      * If the passed in @p aValue string length is longer than the maximum allowed length for the TLV as specified by
523      * `StringTlvType::kMaxStringLength`, the first maximum length chars are appended.
524      *
525      * The @p aValue can be `nullptr` in which case it is treated as an empty string.
526      *
527      * @tparam     StringTlvType  The simple TLV type to append (must be a sub-class of `StringTlvInfo`)
528      *
529      * @param[in]  aMessage       A reference to the message to append to.
530      * @param[in]  aValue         A pointer to a C string to append as TLV's value.
531      *
532      * @retval kErrorNone     Successfully appended the TLV to the message.
533      * @retval kErrorNoBufs   Insufficient available buffers to grow the message.
534      *
535      */
Append(Message & aMessage,const char * aValue)536     template <typename StringTlvType> static Error Append(Message &aMessage, const char *aValue)
537     {
538         return AppendStringTlv(aMessage, StringTlvType::kType, StringTlvType::kMaxStringLength, aValue);
539     }
540 
541 protected:
542     static const uint8_t kExtendedLength = 255; // Extended Length value.
543 
544 private:
545     struct ParsedInfo
546     {
547         Error ParseFrom(const Message &aMessage, uint16_t aOffset);
548         Error FindIn(const Message &aMessage, uint8_t aType);
549 
550         uint8_t  mType;
551         uint16_t mLength;
552         uint16_t mOffset;
553         uint16_t mValueOffset;
554         uint16_t mSize;
555     };
556 
557     static Error FindTlv(const Message &aMessage, uint8_t aType, void *aValue, uint8_t aLength);
558     static Error AppendTlv(Message &aMessage, uint8_t aType, const void *aValue, uint8_t aLength);
559     static Error ReadStringTlv(const Message &aMessage, uint16_t aOffset, uint8_t aMaxStringLength, char *aValue);
560     static Error FindStringTlv(const Message &aMessage, uint8_t aType, uint8_t aMaxStringLength, char *aValue);
561     static Error AppendStringTlv(Message &aMessage, uint8_t aType, uint8_t aMaxStringLength, const char *aValue);
562     template <typename UintType> static Error ReadUintTlv(const Message &aMessage, uint16_t aOffset, UintType &aValue);
563     template <typename UintType> static Error FindUintTlv(const Message &aMessage, uint8_t aType, UintType &aValue);
564     template <typename UintType> static Error AppendUintTlv(Message &aMessage, uint8_t aType, UintType aValue);
565 
566     uint8_t mType;
567     uint8_t mLength;
568 } OT_TOOL_PACKED_END;
569 
570 OT_TOOL_PACKED_BEGIN
571 class ExtendedTlv : public Tlv
572 {
573 public:
574     /**
575      * Returns the Length value.
576      *
577      */
GetLength(void) const578     uint16_t GetLength(void) const { return HostSwap16(mLength); }
579 
580     /**
581      * Sets the Length value.
582      *
583      * @param[in]  aLength  The Length value.
584      *
585      */
SetLength(uint16_t aLength)586     void SetLength(uint16_t aLength)
587     {
588         Tlv::SetLength(kExtendedLength);
589         mLength = HostSwap16(aLength);
590     }
591 
592 private:
593     uint16_t mLength;
594 } OT_TOOL_PACKED_END;
595 
596 /**
597  * Casts a `Tlv` pointer to a given subclass `TlvType` pointer.
598  *
599  * @tparam TlvType  The TLV type to cast into. MUST be a subclass of `Tlv`.
600  *
601  * @param[in] aTlv   A pointer to a `Tlv` to convert/cast to a `TlvType`.
602  *
603  * @returns A `TlvType` pointer to `aTlv`.
604  *
605  */
As(Tlv * aTlv)606 template <class TlvType> TlvType *As(Tlv *aTlv) { return static_cast<TlvType *>(aTlv); }
607 
608 /**
609  * Casts a `Tlv` pointer to a given subclass `TlvType` pointer.
610  *
611  * @tparam TlvType  The TLV type to cast into. MUST be a subclass of `Tlv`.
612  *
613  * @param[in] aTlv   A pointer to a `Tlv` to convert/cast to a `TlvType`.
614  *
615  * @returns A `TlvType` pointer to `aTlv`.
616  *
617  */
As(const Tlv * aTlv)618 template <class TlvType> const TlvType *As(const Tlv *aTlv) { return static_cast<const TlvType *>(aTlv); }
619 
620 /**
621  * Casts a `Tlv` reference to a given subclass `TlvType` reference.
622  *
623  * @tparam TlvType  The TLV type to cast into. MUST be a subclass of `Tlv`.
624  *
625  * @param[in] aTlv   A reference to a `Tlv` to convert/cast to a `TlvType`.
626  *
627  * @returns A `TlvType` reference to `aTlv`.
628  *
629  */
As(Tlv & aTlv)630 template <class TlvType> TlvType &As(Tlv &aTlv) { return static_cast<TlvType &>(aTlv); }
631 
632 /**
633  * Casts a `Tlv` reference to a given subclass `TlvType` reference.
634  *
635  * @tparam TlvType  The TLV type to cast into. MUST be a subclass of `Tlv`.
636  *
637  * @param[in] aTlv   A reference to a `Tlv` to convert/cast to a `TlvType`.
638  *
639  * @returns A `TlvType` reference to `aTlv`.
640  *
641  */
As(const Tlv & aTlv)642 template <class TlvType> const TlvType &As(const Tlv &aTlv) { return static_cast<const TlvType &>(aTlv); }
643 
644 /**
645  * Defines constants for a TLV.
646  *
647  * @tparam kTlvTypeValue   The TLV Type value.
648  *
649  */
650 template <uint8_t kTlvTypeValue> class TlvInfo
651 {
652 public:
653     static constexpr uint8_t kType = kTlvTypeValue; ///< The TLV Type value.
654 };
655 
656 /**
657  * Defines constants and types for a simple TLV with an unsigned int value type.
658  *
659  * This class and its sub-classes are intended to be used as the template type in `Tlv::Append<UintTlvType>()`, and
660  * the related `Tlv::Find<UintTlvType>()` and `Tlv::Read<UintTlvType>()`.
661  *
662  * @tparam kTlvTypeValue   The TLV Type value.
663  * @tparam UintType        The TLV Value's type (must be an unsigned int, i.e. uint8_t, uint16_t, or uint32_t).
664  *
665  */
666 template <uint8_t kTlvTypeValue, typename UintType> class UintTlvInfo : public TlvInfo<kTlvTypeValue>
667 {
668 public:
669     static_assert(TypeTraits::IsSame<UintType, uint8_t>::kValue || TypeTraits::IsSame<UintType, uint16_t>::kValue ||
670                       TypeTraits::IsSame<UintType, uint32_t>::kValue,
671                   "UintTlv must be used used with unsigned int value type");
672 
673     typedef UintType UintValueType; ///< The TLV Value unsigned int type.
674 };
675 
676 /**
677  * Defines constants and types for a simple TLV with a single value.
678  *
679  * This class and its sub-classes are intended to be used as the template type in `Tlv::Append<SimpleTlvType>()`,
680  * and the related `Tlv::Find<SimpleTlvType>()` and `Tlv::Read<SimpleTlvType>()`.
681  *
682  * @tparam kTlvTypeValue   The TLV Type value.
683  * @tparam TlvValueType    The TLV Value's type (must not be an integral type).
684  *
685  */
686 template <uint8_t kTlvTypeValue, typename TlvValueType> class SimpleTlvInfo : public TlvInfo<kTlvTypeValue>
687 {
688 public:
689     static_assert(!TypeTraits::IsPointer<TlvValueType>::kValue, "TlvValueType must not be a pointer");
690     static_assert(!TypeTraits::IsSame<TlvValueType, uint8_t>::kValue, "SimpleTlv must not use int value type");
691     static_assert(!TypeTraits::IsSame<TlvValueType, uint16_t>::kValue, "SimpleTlv must not use int value type");
692     static_assert(!TypeTraits::IsSame<TlvValueType, uint32_t>::kValue, "SimpleTlv must not use int value type");
693     static_assert(!TypeTraits::IsSame<TlvValueType, int8_t>::kValue, "SimpleTlv must not use int value type");
694     static_assert(!TypeTraits::IsSame<TlvValueType, int16_t>::kValue, "SimpleTlv must not use int value type");
695     static_assert(!TypeTraits::IsSame<TlvValueType, int32_t>::kValue, "SimpleTlv must not use int value type");
696 
697     typedef TlvValueType ValueType; ///< The TLV Value type.
698 };
699 
700 /**
701  * Defines constants and types for a simple TLV with a UTF-8 string value.
702  *
703  * This class and its sub-classes are intended to be used as the template type in `Tlv::Append<StringTlvType>()`,
704  * and the related `Tlv::Find<StringTlvType>()` and `Tlv::Read<StringTlvType>()`.
705  *
706  * @tparam kTlvTypeValue        The TLV Type value.
707  * @tparam kTlvMaxValueLength   The maximum allowed string length (as TLV value).
708  *
709  */
710 template <uint8_t kTlvTypeValue, uint8_t kTlvMaxValueLength> class StringTlvInfo : public TlvInfo<kTlvTypeValue>
711 {
712 public:
713     static constexpr uint8_t kMaxStringLength = kTlvMaxValueLength; ///< Maximum string length.
714 
715     typedef char StringType[kMaxStringLength + 1]; ///< String buffer for TLV value.
716 };
717 
718 } // namespace ot
719 
720 #endif // TLVS_HPP_
721