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/offset_range.hpp"
46 #include "common/type_traits.hpp"
47 
48 namespace ot {
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 the value of TLV treating it as a given simple TLV type.
179      *
180      * This method requires the TLV to be already validated, in particular, its length MUST NOT be less than the
181      * required size of the value type. The TLV MUST NOT be extended. If these conditions are not met, the behavior of
182      * this method is undefined.
183      *
184      * @tparam  SimpleTlvType   The simple TLV type to read (must be a sub-class of `SimpleTlvInfo`).
185      *
186      * @returns The TLV value as `SimpleTlvType::ValueType`.
187      *
188      */
ReadValueAs(void) const189     template <typename SimpleTlvType> const typename SimpleTlvType::ValueType &ReadValueAs(void) const
190     {
191         return *reinterpret_cast<const typename SimpleTlvType::ValueType *>(this + 1);
192     }
193 
194     /**
195      * Reads the value of TLV treating it as a given integer-value TLV type.
196      *
197      * This method requires the TLV to be already validated, in particular, its length MUST NOT be less than the
198      * required size of the value type. The TLV MUST NOT be extended. If these conditions are not met, the behavior of
199      * this method is undefined.
200      *
201      * @tparam  UintTlvType     The integer simple TLV type to read (must be a sub-class of `UintTlvInfo`).
202      *
203      * @returns The TLV value as `UintTlvInfo::UintValueType`.
204      *
205      */
ReadValueAs(void) const206     template <typename UintTlvType> typename UintTlvType::UintValueType ReadValueAs(void) const
207     {
208         return BigEndian::Read<typename UintTlvType::UintValueType>(reinterpret_cast<const uint8_t *>(this + 1));
209     }
210 
211     /**
212      * Writes the value of TLV treating it as a given simple TLV type.
213      *
214      * This method requires the TLV to be already validated, in particular, its length MUST NOT be less than the
215      * required size of the value type. The TLV MUST NOT be extended. If these conditions are not met, the behavior of
216      * this method is undefined.
217      *
218      * @tparam  SimpleTlvType   The simple TLV type to read (must be a sub-class of `SimpleTlvInfo`).
219      *
220      * @param[in] aValue   The new TLV value.
221      *
222      */
WriteValueAs(const typename SimpleTlvType::ValueType & aValue)223     template <typename SimpleTlvType> void WriteValueAs(const typename SimpleTlvType::ValueType &aValue)
224     {
225         memcpy(this + 1, &aValue, sizeof(aValue));
226     }
227 
228     /**
229      * Writes the value of TLV treating it as a given integer-value TLV type.
230      *
231      * This method requires the TLV to be already validated, in particular, its length MUST NOT be less than the
232      * required size of the value type. The TLV MUST NOT be extended. If these conditions are not met, the behavior of
233      * this method is undefined.
234      *
235      * @tparam  UintTlvType     The integer simple TLV type to read (must be a sub-class of `UintTlvInfo`).
236      *
237      * @param[in]  aValue   The new TLV value.
238      *
239      */
WriteValueAs(typename UintTlvType::UintValueType aValue)240     template <typename UintTlvType> void WriteValueAs(typename UintTlvType::UintValueType aValue)
241     {
242         return BigEndian::Write<typename UintTlvType::UintValueType>(aValue, reinterpret_cast<uint8_t *>(this + 1));
243     }
244 
245     //------------------------------------------------------------------------------------------------------------------
246     // Static methods for reading/finding/appending TLVs in a `Message`.
247 
248     /**
249      * Represents information for a parsed TLV from a message.
250      *
251      */
252     struct ParsedInfo
253     {
254         /**
255          * Parses the TLV from a given message at given offset, ensures the TLV is well-formed and its header and
256          * value are fully contained in the message.
257          *
258          * Can be used independent of whether the TLV is an Extended TLV or not.
259          *
260          * @param[in] aMessage      The message to read from.
261          * @param[in] aOffset       The offset in @p aMessage.
262          *
263          * @retval kErrorNone   Successfully parsed the TLV.
264          * @retval kErrorParse  The TLV was not well-formed or not fully contained in @p aMessage.
265          *
266          */
267         Error ParseFrom(const Message &aMessage, uint16_t aOffset);
268 
269         /**
270          * Parses the TLV from a given message for a given offset range, ensures the TLV is well-formed and its header
271          * and value are fully contained in the offset range and the message.
272          *
273          * Can be used independent of whether the TLV is an Extended TLV or not.
274          *
275          * @param[in] aMessage      The message to read from.
276          * @param[in] aOffsetRange  The offset range in @p aMessage.
277          *
278          * @retval kErrorNone   Successfully parsed the TLV.
279          * @retval kErrorParse  The TLV was not well-formed or not contained in @p aOffsetRange or @p aMessage.
280          *
281          */
282         Error ParseFrom(const Message &aMessage, const OffsetRange &aOffsetRange);
283 
284         /**
285          * Searches in a given message starting from message offset for a TLV of given type and if found, parses
286          * the TLV and validates that the entire TLV is present in the message.
287          *
288          * Can be used independent of whether the TLV is an Extended TLV or not.
289          *
290          * @param[in] aMessage  The message to search in.
291          * @param[in] aType     The TLV type to search for.
292          *
293          * @retval kErrorNone      Successfully found and parsed the TLV.
294          * @retval kErrorNotFound  Could not find the TLV, or the TLV was not well-formed.
295          *
296          */
297         Error FindIn(const Message &aMessage, uint8_t aType);
298 
299         /**
300          * Returns the full TLV size in bytes.
301          *
302          * @returns The TLV size in bytes.
303          *
304          */
GetSizeot::Tlv::ParsedInfo305         uint16_t GetSize(void) const { return mTlvOffsetRange.GetLength(); }
306 
307         uint8_t     mType;             ///< The TLV type
308         bool        mIsExtended;       ///< Whether the TLV is extended or not.
309         OffsetRange mTlvOffsetRange;   ///< Offset range containing the full TLV.
310         OffsetRange mValueOffsetRange; ///< Offset range containing the TLV's value.
311     };
312 
313     /**
314      * Reads a TLV's value in a message at a given offset expecting a minimum length for the value.
315      *
316      * Can be used independent of whether the read TLV (from the message) is an Extended TLV or not.
317      *
318      * @param[in]   aMessage    The message to read from.
319      * @param[in]   aOffset     The offset into the message pointing to the start of the TLV.
320      * @param[out]  aValue      A buffer to output the TLV's value, must contain (at least) @p aMinLength bytes.
321      * @param[in]   aMinLength  The minimum expected length of TLV and number of bytes to copy into @p aValue buffer.
322      *
323      * @retval kErrorNone        Successfully read the TLV and copied @p aMinLength into @p aValue.
324      * @retval kErrorParse       The TLV was not well-formed and could not be parsed.
325      *
326      */
327     static Error ReadTlvValue(const Message &aMessage, uint16_t aOffset, void *aValue, uint8_t aMinLength);
328 
329     /**
330      * Reads a simple TLV with a single non-integral value in a message at a given offset.
331      *
332      * @tparam      SimpleTlvType   The simple TLV type to read (must be a sub-class of `SimpleTlvInfo`).
333      *
334      * @param[in]   aMessage        The message to read from.
335      * @param[in]   aOffset         The offset into the message pointing to the start of the TLV.
336      * @param[out]  aValue          A reference to the value object to output the read value.
337      *
338      * @retval kErrorNone        Successfully read the TLV and updated the @p aValue.
339      * @retval kErrorParse       The TLV was not well-formed and could not be parsed.
340      *
341      */
342     template <typename SimpleTlvType>
Read(const Message & aMessage,uint16_t aOffset,typename SimpleTlvType::ValueType & aValue)343     static Error Read(const Message &aMessage, uint16_t aOffset, typename SimpleTlvType::ValueType &aValue)
344     {
345         return ReadTlvValue(aMessage, aOffset, &aValue, sizeof(aValue));
346     }
347 
348     /**
349      * Reads a simple TLV with a single integral value in a message at a given offset.
350      *
351      * @tparam      UintTlvType     The simple TLV type to read (must be a sub-class of `UintTlvInfo`).
352      *
353      * @param[in]   aMessage        The message to read from.
354      * @param[in]   aOffset         The offset into the message pointing to the start of the TLV.
355      * @param[out]  aValue          A reference to an unsigned int to output the read value.
356      *
357      * @retval kErrorNone        Successfully read the TLV and updated the @p aValue.
358      * @retval kErrorParse       The TLV was not well-formed and could not be parsed.
359      *
360      */
361     template <typename UintTlvType>
Read(const Message & aMessage,uint16_t aOffset,typename UintTlvType::UintValueType & aValue)362     static Error Read(const Message &aMessage, uint16_t aOffset, typename UintTlvType::UintValueType &aValue)
363     {
364         return ReadUintTlv(aMessage, aOffset, aValue);
365     }
366 
367     /**
368      * Reads a simple TLV with a UTF-8 string value in a message at a given offset.
369      *
370      * @tparam      StringTlvType   The simple TLV type to read (must be a sub-class of `StringTlvInfo`).
371      *
372      * @param[in]   aMessage        The message to read from.
373      * @param[in]   aOffset         The offset into the message pointing to the start of the TLV.
374      * @param[out]  aValue          A reference to the string buffer to output the read value.
375      *
376      * @retval kErrorNone        Successfully read the TLV and updated the @p aValue.
377      * @retval kErrorParse       The TLV was not well-formed and could not be parsed.
378      *
379      */
380     template <typename StringTlvType>
Read(const Message & aMessage,uint16_t aOffset,typename StringTlvType::StringType & aValue)381     static Error Read(const Message &aMessage, uint16_t aOffset, typename StringTlvType::StringType &aValue)
382     {
383         return ReadStringTlv(aMessage, aOffset, StringTlvType::kMaxStringLength, aValue);
384     }
385 
386     /**
387      * Searches for and reads a requested TLV out of a given message.
388      *
389      * Can be used independent of whether the read TLV (from message) is an Extended TLV or not.
390      *
391      * @param[in]   aMessage    A reference to the message.
392      * @param[in]   aType       The Type value to search for.
393      * @param[in]   aMaxSize    Maximum number of bytes to read.
394      * @param[out]  aTlv        A reference to the TLV that will be copied to.
395      *
396      * @retval kErrorNone       Successfully copied the TLV.
397      * @retval kErrorNotFound   Could not find the TLV with Type @p aType.
398      *
399      */
400     static Error FindTlv(const Message &aMessage, uint8_t aType, uint16_t aMaxSize, Tlv &aTlv);
401 
402     /**
403      * Searches for and reads a requested TLV out of a given message.
404      *
405      * Can be used independent of whether the read TLV (from message) is an Extended TLV or not.
406      *
407      * @param[in]   aMessage    A reference to the message.
408      * @param[in]   aType       The Type value to search for.
409      * @param[in]   aMaxSize    Maximum number of bytes to read.
410      * @param[out]  aTlv        A reference to the TLV that will be copied to.
411      * @param[out]  aOffset     A reference to return the offset to start of the TLV in @p aMessage.
412      *
413      * @retval kErrorNone       Successfully copied the TLV.
414      * @retval kErrorNotFound   Could not find the TLV with Type @p aType.
415      *
416      */
417     static Error FindTlv(const Message &aMessage, uint8_t aType, uint16_t aMaxSize, Tlv &aTlv, uint16_t &aOffset);
418 
419     /**
420      * Searches for and reads a requested TLV out of a given message.
421      *
422      * Can be used independent of whether the read TLV (from message) is an Extended TLV or not.
423      *
424      * @tparam      TlvType     The TlvType to search for (must be a sub-class of `Tlv`).
425      *
426      * @param[in]   aMessage    A reference to the message.
427      * @param[out]  aTlv        A reference to the TLV that will be copied to.
428      *
429      * @retval kErrorNone       Successfully copied the TLV.
430      * @retval kErrorNotFound   Could not find the TLV with Type @p aType.
431      *
432      */
FindTlv(const Message & aMessage,TlvType & aTlv)433     template <typename TlvType> static Error FindTlv(const Message &aMessage, TlvType &aTlv)
434     {
435         return FindTlv(aMessage, TlvType::kType, sizeof(TlvType), aTlv);
436     }
437 
438     /**
439      * Searches for and reads a requested TLV out of a given message.
440      *
441      * Can be used independent of whether the read TLV (from message) is an Extended TLV or not.
442      *
443      * @tparam      TlvType     The TlvType to search for (must be a sub-class of `Tlv`).
444      *
445      * @param[in]   aMessage    A reference to the message.
446      * @param[out]  aTlv        A reference to the TLV that will be copied to.
447      * @param[out]  aOffset     A reference to return the offset to start of the TLV in @p aMessage.
448      *
449      * @retval kErrorNone       Successfully copied the TLV.
450      * @retval kErrorNotFound   Could not find the TLV with Type @p aType.
451      *
452      */
FindTlv(const Message & aMessage,TlvType & aTlv,uint16_t & aOffset)453     template <typename TlvType> static Error FindTlv(const Message &aMessage, TlvType &aTlv, uint16_t &aOffset)
454     {
455         return FindTlv(aMessage, TlvType::kType, sizeof(TlvType), aTlv, aOffset);
456     }
457 
458     /**
459      * Finds the offset range of the TLV value for a given TLV type within @p aMessage.
460      *
461      * Can be used independent of whether the read TLV (from message) is an Extended TLV or not.
462      *
463      * @param[in]   aMessage      A reference to the message.
464      * @param[in]   aType         The Type value to search for.
465      * @param[out]  aOffsetRange  A reference to return the offset range of the TLV value when found.
466      *
467      * @retval kErrorNone       Successfully found the TLV.
468      * @retval kErrorNotFound   Could not find the TLV with Type @p aType.
469      *
470      */
471     static Error FindTlvValueOffsetRange(const Message &aMessage, uint8_t aType, OffsetRange &aOffsetRange);
472 
473     /**
474      * Searches for a TLV with a given type in a message, ensures its length is same or larger than
475      * an expected minimum value, and then reads its value into a given buffer.
476      *
477      * If the TLV length is smaller than the minimum length @p aLength, the TLV is considered invalid. In this case,
478      * this method returns `kErrorParse` and the @p aValue buffer is not updated.
479      *
480      * If the TLV length is larger than @p aLength, the TLV is considered valid, but only the first @p aLength bytes
481      * of the value are read and copied into the @p aValue buffer.
482      *
483      * @tparam       TlvType     The TLV type to find.
484      *
485      * @param[in]    aMessage    A reference to the message.
486      * @param[out]   aValue      A buffer to output the value (must contain at least @p aLength bytes).
487      * @param[in]    aLength     The expected (minimum) length of the TLV value.
488      *
489      * @retval kErrorNone       The TLV was found and read successfully. @p aValue is updated.
490      * @retval kErrorNotFound   Could not find the TLV with Type @p aType.
491      * @retval kErrorParse      TLV was found but it was not well-formed and could not be parsed.
492      *
493      */
Find(const Message & aMessage,void * aValue,uint8_t aLength)494     template <typename TlvType> static Error Find(const Message &aMessage, void *aValue, uint8_t aLength)
495     {
496         return FindTlv(aMessage, TlvType::kType, aValue, aLength);
497     }
498 
499     /**
500      * Searches for a simple TLV with a single non-integral value in a message, ensures its length is
501      * same or larger than the expected `ValueType` object size, and then reads its value into a value object reference.
502      *
503      * If the TLV length is smaller than the size of @p aValue, the TLV is considered invalid. In this case, this
504      * method returns `kErrorParse` and the @p aValue is not updated.
505      *
506      * If the TLV length is larger than the size of @p aValue, the TLV is considered valid, but the size of
507      * `ValueType` bytes are read and copied into the @p aValue.
508      *
509      * @tparam       SimpleTlvType   The simple TLV type to find (must be a sub-class of `SimpleTlvInfo`)
510      *
511      * @param[in]    aMessage        A reference to the message.
512      * @param[out]   aValue          A reference to the value object to output the read value.
513      *
514      * @retval kErrorNone         The TLV was found and read successfully. @p aValue is updated.
515      * @retval kErrorNotFound     Could not find the TLV with Type @p aType.
516      * @retval kErrorParse        TLV was found but it was not well-formed and could not be parsed.
517      *
518      */
519     template <typename SimpleTlvType>
Find(const Message & aMessage,typename SimpleTlvType::ValueType & aValue)520     static Error Find(const Message &aMessage, typename SimpleTlvType::ValueType &aValue)
521     {
522         return FindTlv(aMessage, SimpleTlvType::kType, &aValue, sizeof(aValue));
523     }
524 
525     /**
526      * Searches for a simple TLV with a single integral value in a message, and then reads its value
527      * into a given `uint` reference variable.
528      *
529      * If the TLV length is smaller than size of integral value, the TLV is considered invalid. In this case, this
530      * method returns `kErrorParse` and the @p aValue is not updated.
531      *
532      * @tparam       UintTlvType     The simple TLV type to find (must be a sub-class of `UintTlvInfo`)
533      *
534      * @param[in]    aMessage        A reference to the message.
535      * @param[out]   aValue          A reference to an unsigned int value to output the TLV's value.
536      *
537      * @retval kErrorNone         The TLV was found and read successfully. @p aValue is updated.
538      * @retval kErrorNotFound     Could not find the TLV with Type @p aType.
539      * @retval kErrorParse        TLV was found but it was not well-formed and could not be parsed.
540      *
541      */
542     template <typename UintTlvType>
Find(const Message & aMessage,typename UintTlvType::UintValueType & aValue)543     static Error Find(const Message &aMessage, typename UintTlvType::UintValueType &aValue)
544     {
545         return FindUintTlv(aMessage, UintTlvType::kType, aValue);
546     }
547 
548     /**
549      * Searches for a simple TLV with a UTF-8 string value in a message, and then reads its value
550      * into a given string buffer.
551      *
552      * If the TLV length is longer than maximum string length specified by `StringTlvType::kMaxStringLength` then
553      * only up to maximum length is read and returned. In this case `kErrorNone` is returned.
554      *
555      * The returned string in @p aValue is always null terminated.`StringTlvType::StringType` MUST have at least
556      * `kMaxStringLength + 1` chars.
557      *
558      * @tparam       StringTlvType  The simple TLV type to find (must be a sub-class of `StringTlvInfo`)
559      *
560      * @param[in]    aMessage        A reference to the message.
561      * @param[out]   aValue          A reference to a string buffer to output the TLV's value.
562      *
563      * @retval kErrorNone         The TLV was found and read successfully. @p aValue is updated.
564      * @retval kErrorNotFound     Could not find the TLV with Type @p aType.
565      * @retval kErrorParse        TLV was found but it was not well-formed and could not be parsed.
566      *
567      */
568     template <typename StringTlvType>
Find(const Message & aMessage,typename StringTlvType::StringType & aValue)569     static Error Find(const Message &aMessage, typename StringTlvType::StringType &aValue)
570     {
571         return FindStringTlv(aMessage, StringTlvType::kType, StringTlvType::kMaxStringLength, aValue);
572     }
573 
574     /**
575      * Appends a TLV with a given type and value to a message.
576      *
577      * If the TLV length is longer than maximum base TLV size defined by `kBaseTlvMaxLength` then
578      * appends extended TLV.
579      *
580      * On success this method grows the message by the size of the TLV.
581      *
582      * @param[in]  aMessage      The message to append to.
583      * @param[in]  aType         The TLV type to append.
584      * @param[in]  aValue        A buffer containing the TLV value.
585      * @param[in]  aLength       The value length (in bytes).
586      *
587      * @retval kErrorNone     Successfully appended the TLV to the message.
588      * @retval kErrorNoBufs   Insufficient available buffers to grow the message.
589      *
590      */
591     static Error AppendTlv(Message &aMessage, uint8_t aType, const void *aValue, uint16_t aLength);
592 
593     /**
594      * Appends a TLV with a given type and value to a message.
595      *
596      * On success this method grows the message by the size of the TLV.
597      *
598      * @tparam     TlvType       The TLV type to append.
599      *
600      * @param[in]  aMessage      A reference to the message to append to.
601      * @param[in]  aValue        A buffer containing the TLV value.
602      * @param[in]  aLength       The value length (in bytes).
603      *
604      * @retval kErrorNone     Successfully appended the TLV to the message.
605      * @retval kErrorNoBufs   Insufficient available buffers to grow the message.
606      *
607      */
Append(Message & aMessage,const void * aValue,uint8_t aLength)608     template <typename TlvType> static Error Append(Message &aMessage, const void *aValue, uint8_t aLength)
609     {
610         return AppendTlv(aMessage, TlvType::kType, aValue, aLength);
611     }
612 
613     /**
614      * Appends a simple TLV with a single (non-integral) value to a message.
615      *
616      * On success this method grows the message by the size of the TLV.
617      *
618      * @tparam     SimpleTlvType The simple TLV type to append (must be a sub-class of `SimpleTlvInfo`)
619      *
620      * @param[in]  aMessage      A reference to the message to append to.
621      * @param[in]  aValue        A reference to the object containing TLV's value.
622      *
623      * @retval kErrorNone     Successfully appended the TLV to the message.
624      * @retval kErrorNoBufs   Insufficient available buffers to grow the message.
625      *
626      */
627     template <typename SimpleTlvType>
Append(Message & aMessage,const typename SimpleTlvType::ValueType & aValue)628     static Error Append(Message &aMessage, const typename SimpleTlvType::ValueType &aValue)
629     {
630         return AppendTlv(aMessage, SimpleTlvType::kType, &aValue, sizeof(aValue));
631     }
632 
633     /**
634      * Appends a simple TLV with a single integral value to a message.
635      *
636      * On success this method grows the message by the size of the TLV.
637      *
638      * @tparam     UintTlvType   The simple TLV type to append (must be a sub-class of `UintTlvInfo`)
639      *
640      * @param[in]  aMessage      A reference to the message to append to.
641      * @param[in]  aValue        An unsigned int value to use as TLV's value.
642      *
643      * @retval kErrorNone     Successfully appended the TLV to the message.
644      * @retval kErrorNoBufs   Insufficient available buffers to grow the message.
645      *
646      */
Append(Message & aMessage,typename UintTlvType::UintValueType aValue)647     template <typename UintTlvType> static Error Append(Message &aMessage, typename UintTlvType::UintValueType aValue)
648     {
649         return AppendUintTlv(aMessage, UintTlvType::kType, aValue);
650     }
651 
652     /**
653      * Appends a simple TLV with a single UTF-8 string value to a message.
654      *
655      * On success this method grows the message by the size of the TLV.
656      *
657      * If the passed in @p aValue string length is longer than the maximum allowed length for the TLV as specified by
658      * `StringTlvType::kMaxStringLength`, the first maximum length chars are appended.
659      *
660      * The @p aValue can be `nullptr` in which case it is treated as an empty string.
661      *
662      * @tparam     StringTlvType  The simple TLV type to append (must be a sub-class of `StringTlvInfo`)
663      *
664      * @param[in]  aMessage       A reference to the message to append to.
665      * @param[in]  aValue         A pointer to a C string to append as TLV's value.
666      *
667      * @retval kErrorNone     Successfully appended the TLV to the message.
668      * @retval kErrorNoBufs   Insufficient available buffers to grow the message.
669      *
670      */
Append(Message & aMessage,const char * aValue)671     template <typename StringTlvType> static Error Append(Message &aMessage, const char *aValue)
672     {
673         return AppendStringTlv(aMessage, StringTlvType::kType, StringTlvType::kMaxStringLength, aValue);
674     }
675 
676     //------------------------------------------------------------------------------------------------------------------
677     // Static methods for finding TLVs within a sequence of TLVs.
678 
679     /**
680      * Searches in a given sequence of TLVs to find the first TLV of a given type.
681      *
682      * @param[in]  aTlvsStart  A pointer to the start of the sequence of TLVs to search within.
683      * @param[in]  aTlvsLength The length (number of bytes) in the TLV sequence.
684      * @param[in]  aType       The TLV type to search for.
685      *
686      * @returns A pointer to the TLV within the TLV sequence if found, or `nullptr` if not found.
687      *
688      */
689     static const Tlv *FindTlv(const void *aTlvsStart, uint16_t aTlvsLength, uint8_t aType);
690 
691     /**
692      * Searches in a given sequence of TLVs to find the first TLV of a given type.
693      *
694      * @param[in]  aTlvsStart  A pointer to the start of the sequence of TLVs to search within.
695      * @param[in]  aTlvsLength The length (number of bytes) in the TLV sequence.
696      * @param[in]  aType       The TLV type to search for.
697      *
698      * @returns A pointer to the TLV within the TLV sequence if found, or `nullptr` if not found.
699      *
700      */
FindTlv(void * aTlvsStart,uint16_t aTlvsLength,uint8_t aType)701     static Tlv *FindTlv(void *aTlvsStart, uint16_t aTlvsLength, uint8_t aType)
702     {
703         return AsNonConst(FindTlv(AsConst(aTlvsStart), aTlvsLength, aType));
704     }
705 
706     /**
707      * Searches in a given sequence of TLVs to find the first TLV with a give template `TlvType`.
708      *
709      * @tparam kTlvType        The TLV Type.
710      *
711      * @param[in]  aTlvsStart  A pointer to the start of the sequence of TLVs to search within.
712      * @param[in]  aTlvsLength The length (number of bytes) in TLV sequence.
713      *
714      * @returns A pointer to the TLV if found, or `nullptr` if not found.
715      *
716      */
Find(void * aTlvsStart,uint16_t aTlvsLength)717     template <typename TlvType> static TlvType *Find(void *aTlvsStart, uint16_t aTlvsLength)
718     {
719         return static_cast<TlvType *>(FindTlv(aTlvsStart, aTlvsLength, TlvType::kType));
720     }
721 
722     /**
723      * Searches in a given sequence of TLVs to find the first TLV with a give template `TlvType`.
724      *
725      * @tparam kTlvType        The TLV Type.
726      *
727      * @param[in]  aTlvsStart  A pointer to the start of the sequence of TLVs to search within.
728      * @param[in]  aTlvsLength The length (number of bytes) in TLV sequence.
729      *
730      * @returns A pointer to the TLV if found, or `nullptr` if not found.
731      *
732      */
Find(const void * aTlvsStart,uint16_t aTlvsLength)733     template <typename TlvType> static const TlvType *Find(const void *aTlvsStart, uint16_t aTlvsLength)
734     {
735         return static_cast<const TlvType *>(FindTlv(aTlvsStart, aTlvsLength, TlvType::kType));
736     }
737 
738 protected:
739     static const uint8_t kExtendedLength = 255; // Extended Length value.
740 
741 private:
742     static Error FindTlv(const Message &aMessage, uint8_t aType, void *aValue, uint16_t aLength);
743     static Error ReadStringTlv(const Message &aMessage, uint16_t aOffset, uint8_t aMaxStringLength, char *aValue);
744     static Error FindStringTlv(const Message &aMessage, uint8_t aType, uint8_t aMaxStringLength, char *aValue);
745     static Error AppendStringTlv(Message &aMessage, uint8_t aType, uint8_t aMaxStringLength, const char *aValue);
746     template <typename UintType> static Error ReadUintTlv(const Message &aMessage, uint16_t aOffset, UintType &aValue);
747     template <typename UintType> static Error FindUintTlv(const Message &aMessage, uint8_t aType, UintType &aValue);
748     template <typename UintType> static Error AppendUintTlv(Message &aMessage, uint8_t aType, UintType aValue);
749 
750     uint8_t mType;
751     uint8_t mLength;
752 } OT_TOOL_PACKED_END;
753 
754 OT_TOOL_PACKED_BEGIN
755 class ExtendedTlv : public Tlv
756 {
757 public:
758     /**
759      * Returns the Length value.
760      *
761      */
GetLength(void) const762     uint16_t GetLength(void) const { return BigEndian::HostSwap16(mLength); }
763 
764     /**
765      * Sets the Length value.
766      *
767      * @param[in]  aLength  The Length value.
768      *
769      */
SetLength(uint16_t aLength)770     void SetLength(uint16_t aLength)
771     {
772         Tlv::SetLength(kExtendedLength);
773         mLength = BigEndian::HostSwap16(aLength);
774     }
775 
776 private:
777     uint16_t mLength;
778 } OT_TOOL_PACKED_END;
779 
780 /**
781  * Casts a `Tlv` pointer to a given subclass `TlvType` pointer.
782  *
783  * @tparam TlvType  The TLV type to cast into. MUST be a subclass of `Tlv`.
784  *
785  * @param[in] aTlv   A pointer to a `Tlv` to convert/cast to a `TlvType`.
786  *
787  * @returns A `TlvType` pointer to `aTlv`.
788  *
789  */
As(Tlv * aTlv)790 template <class TlvType> TlvType *As(Tlv *aTlv) { return static_cast<TlvType *>(aTlv); }
791 
792 /**
793  * Casts a `Tlv` pointer to a given subclass `TlvType` pointer.
794  *
795  * @tparam TlvType  The TLV type to cast into. MUST be a subclass of `Tlv`.
796  *
797  * @param[in] aTlv   A pointer to a `Tlv` to convert/cast to a `TlvType`.
798  *
799  * @returns A `TlvType` pointer to `aTlv`.
800  *
801  */
As(const Tlv * aTlv)802 template <class TlvType> const TlvType *As(const Tlv *aTlv) { return static_cast<const TlvType *>(aTlv); }
803 
804 /**
805  * Casts a `Tlv` reference to a given subclass `TlvType` reference.
806  *
807  * @tparam TlvType  The TLV type to cast into. MUST be a subclass of `Tlv`.
808  *
809  * @param[in] aTlv   A reference to a `Tlv` to convert/cast to a `TlvType`.
810  *
811  * @returns A `TlvType` reference to `aTlv`.
812  *
813  */
As(Tlv & aTlv)814 template <class TlvType> TlvType &As(Tlv &aTlv) { return static_cast<TlvType &>(aTlv); }
815 
816 /**
817  * Casts a `Tlv` reference to a given subclass `TlvType` reference.
818  *
819  * @tparam TlvType  The TLV type to cast into. MUST be a subclass of `Tlv`.
820  *
821  * @param[in] aTlv   A reference to a `Tlv` to convert/cast to a `TlvType`.
822  *
823  * @returns A `TlvType` reference to `aTlv`.
824  *
825  */
As(const Tlv & aTlv)826 template <class TlvType> const TlvType &As(const Tlv &aTlv) { return static_cast<const TlvType &>(aTlv); }
827 
828 /**
829  * Defines constants for a TLV.
830  *
831  * @tparam kTlvTypeValue   The TLV Type value.
832  *
833  */
834 template <uint8_t kTlvTypeValue> class TlvInfo
835 {
836 public:
837     static constexpr uint8_t kType = kTlvTypeValue; ///< The TLV Type value.
838 };
839 
840 /**
841  * Defines constants and types for a simple TLV with an unsigned int value type.
842  *
843  * This class and its sub-classes are intended to be used as the template type in `Tlv::Append<UintTlvType>()`, and
844  * the related `Tlv::Find<UintTlvType>()` and `Tlv::Read<UintTlvType>()`.
845  *
846  * @tparam kTlvTypeValue   The TLV Type value.
847  * @tparam UintType        The TLV Value's type (must be an unsigned int, i.e. uint8_t, uint16_t, or uint32_t).
848  *
849  */
850 template <uint8_t kTlvTypeValue, typename UintType> class UintTlvInfo : public TlvInfo<kTlvTypeValue>
851 {
852 public:
853     static_assert(TypeTraits::IsSame<UintType, uint8_t>::kValue || TypeTraits::IsSame<UintType, uint16_t>::kValue ||
854                       TypeTraits::IsSame<UintType, uint32_t>::kValue,
855                   "UintTlv must be used used with unsigned int value type");
856 
857     typedef UintType UintValueType; ///< The TLV Value unsigned int type.
858 };
859 
860 /**
861  * Defines constants and types for a simple TLV with a single value.
862  *
863  * This class and its sub-classes are intended to be used as the template type in `Tlv::Append<SimpleTlvType>()`,
864  * and the related `Tlv::Find<SimpleTlvType>()` and `Tlv::Read<SimpleTlvType>()`.
865  *
866  * @tparam kTlvTypeValue   The TLV Type value.
867  * @tparam TlvValueType    The TLV Value's type (must not be an integral type).
868  *
869  */
870 template <uint8_t kTlvTypeValue, typename TlvValueType> class SimpleTlvInfo : public TlvInfo<kTlvTypeValue>
871 {
872 public:
873     static_assert(!TypeTraits::IsPointer<TlvValueType>::kValue, "TlvValueType must not be a pointer");
874     static_assert(!TypeTraits::IsSame<TlvValueType, uint8_t>::kValue, "SimpleTlv must not use int value type");
875     static_assert(!TypeTraits::IsSame<TlvValueType, uint16_t>::kValue, "SimpleTlv must not use int value type");
876     static_assert(!TypeTraits::IsSame<TlvValueType, uint32_t>::kValue, "SimpleTlv must not use int value type");
877     static_assert(!TypeTraits::IsSame<TlvValueType, int8_t>::kValue, "SimpleTlv must not use int value type");
878     static_assert(!TypeTraits::IsSame<TlvValueType, int16_t>::kValue, "SimpleTlv must not use int value type");
879     static_assert(!TypeTraits::IsSame<TlvValueType, int32_t>::kValue, "SimpleTlv must not use int value type");
880 
881     typedef TlvValueType ValueType; ///< The TLV Value type.
882 };
883 
884 /**
885  * Defines constants and types for a simple TLV with a UTF-8 string value.
886  *
887  * This class and its sub-classes are intended to be used as the template type in `Tlv::Append<StringTlvType>()`,
888  * and the related `Tlv::Find<StringTlvType>()` and `Tlv::Read<StringTlvType>()`.
889  *
890  * @tparam kTlvTypeValue        The TLV Type value.
891  * @tparam kTlvMaxValueLength   The maximum allowed string length (as TLV value).
892  *
893  */
894 template <uint8_t kTlvTypeValue, uint8_t kTlvMaxValueLength> class StringTlvInfo : public TlvInfo<kTlvTypeValue>
895 {
896 public:
897     static constexpr uint8_t kMaxStringLength = kTlvMaxValueLength; ///< Maximum string length.
898 
899     typedef char StringType[kMaxStringLength + 1]; ///< String buffer for TLV value.
900 };
901 
902 } // namespace ot
903 
904 #endif // TLVS_HPP_
905