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