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