1 /*
2 * Copyright (c) 2016, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /**
30 * @file
31 * This file includes definitions for generating and processing MLE TLVs.
32 */
33
34 #ifndef TLVS_HPP_
35 #define TLVS_HPP_
36
37 #include "openthread-core-config.h"
38
39 #include <openthread/thread.h>
40 #include <openthread/platform/toolchain.h>
41
42 #include "common/encoding.hpp"
43 #include "common/error.hpp"
44 #include "common/type_traits.hpp"
45
46 namespace ot {
47
48 using ot::Encoding::BigEndian::HostSwap16;
49
50 class Message;
51
52 /**
53 * This class 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 * This method 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 * This method 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 * This method 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 * This method 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 * This method 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 * This method returns the TLV's total size (number of bytes) including Type, Length, and Value fields.
113 *
114 * This method 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 * This method returns a pointer to the Value.
123 *
124 * This method 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 * This method returns a pointer to the Value.
133 *
134 * This method 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 * This method returns a pointer to the next TLV.
143 *
144 * This method 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 * This method returns a pointer to the next TLV.
153 *
154 * This method 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 * This method 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 * This static method reads a TLV in a message at a given offset expecting a minimum length for the value.
179 *
180 * @param[in] aMessage The message to read from.
181 * @param[in] aOffset The offset into the message pointing to the start of the TLV.
182 * @param[out] aValue A buffer to output the TLV's value, must contain (at least) @p aMinLength bytes.
183 * @param[in] aMinLength The minimum expected length of TLV and number of bytes to copy into @p aValue buffer.
184 *
185 * @retval kErrorNone Successfully read the TLV and copied @p aMinLength into @p aValue.
186 * @retval kErrorParse The TLV was not well-formed and could not be parsed.
187 *
188 */
189 static Error ReadTlv(const Message &aMessage, uint16_t aOffset, void *aValue, uint8_t aMinLength);
190
191 /**
192 * This static method reads a simple TLV with a single non-integral value in a message at a given offset.
193 *
194 * @tparam SimpleTlvType The simple TLV type to read (must be a sub-class of `SimpleTlvInfo`).
195 *
196 * @param[in] aMessage The message to read from.
197 * @param[in] aOffset The offset into the message pointing to the start of the TLV.
198 * @param[out] aValue A reference to the value object to output the read value.
199 *
200 * @retval kErrorNone Successfully read the TLV and updated the @p aValue.
201 * @retval kErrorParse The TLV was not well-formed and could not be parsed.
202 *
203 */
204 template <typename SimpleTlvType>
Read(const Message & aMessage,uint16_t aOffset,typename SimpleTlvType::ValueType & aValue)205 static Error Read(const Message &aMessage, uint16_t aOffset, typename SimpleTlvType::ValueType &aValue)
206 {
207 return ReadTlv(aMessage, aOffset, &aValue, sizeof(aValue));
208 }
209
210 /**
211 * This static method reads a simple TLV with a single integral value in a message at a given offset.
212 *
213 * @tparam UintTlvType The simple TLV type to read (must be a sub-class of `UintTlvInfo`).
214 *
215 * @param[in] aMessage The message to read from.
216 * @param[in] aOffset The offset into the message pointing to the start of the TLV.
217 * @param[out] aValue A reference to an unsigned int to output the read value.
218 *
219 * @retval kErrorNone Successfully read the TLV and updated the @p aValue.
220 * @retval kErrorParse The TLV was not well-formed and could not be parsed.
221 *
222 */
223 template <typename UintTlvType>
Read(const Message & aMessage,uint16_t aOffset,typename UintTlvType::UintValueType & aValue)224 static Error Read(const Message &aMessage, uint16_t aOffset, typename UintTlvType::UintValueType &aValue)
225 {
226 return ReadUintTlv(aMessage, aOffset, aValue);
227 }
228
229 /**
230 * This static method searches for and reads a requested TLV out of a given message.
231 *
232 * This method can be used independent of whether the read TLV (from message) is an Extended TLV or not.
233 *
234 * @param[in] aMessage A reference to the message.
235 * @param[in] aType The Type value to search for.
236 * @param[in] aMaxSize Maximum number of bytes to read.
237 * @param[out] aTlv A reference to the TLV that will be copied to.
238 *
239 * @retval kErrorNone Successfully copied the TLV.
240 * @retval kErrorNotFound Could not find the TLV with Type @p aType.
241 *
242 */
243 static Error FindTlv(const Message &aMessage, uint8_t aType, uint16_t aMaxSize, Tlv &aTlv);
244
245 /**
246 * This static method searches for and reads a requested TLV out of a given message.
247 *
248 * This method can be used independent of whether the read TLV (from message) is an Extended TLV or not.
249 *
250 * @tparam TlvType The TlvType to search for (must be a sub-class of `Tlv`).
251 *
252 * @param[in] aMessage A reference to the message.
253 * @param[out] aTlv A reference to the TLV that will be copied to.
254 *
255 * @retval kErrorNone Successfully copied the TLV.
256 * @retval kErrorNotFound Could not find the TLV with Type @p aType.
257 *
258 */
FindTlv(const Message & aMessage,TlvType & aTlv)259 template <typename TlvType> static Error FindTlv(const Message &aMessage, TlvType &aTlv)
260 {
261 return FindTlv(aMessage, TlvType::kType, sizeof(TlvType), aTlv);
262 }
263
264 /**
265 * This static method obtains the offset of a TLV within @p aMessage.
266 *
267 * This method can be used independent of whether the read TLV (from message) is an Extended TLV or not.
268 *
269 * @param[in] aMessage A reference to the message.
270 * @param[in] aType The Type value to search for.
271 * @param[out] aOffset A reference to the offset of the TLV.
272 *
273 * @retval kErrorNone Successfully copied the TLV.
274 * @retval kErrorNotFound Could not find the TLV with Type @p aType.
275 *
276 */
277 static Error FindTlvOffset(const Message &aMessage, uint8_t aType, uint16_t &aOffset);
278
279 /**
280 * This static method finds the offset and length of a given TLV type.
281 *
282 * This method can be used independent of whether the read TLV (from message) is an Extended TLV or not.
283 *
284 * @param[in] aMessage A reference to the message.
285 * @param[in] aType The Type value to search for.
286 * @param[out] aValueOffset The offset where the value starts.
287 * @param[out] aLength The length of the value.
288 *
289 * @retval kErrorNone Successfully found the TLV.
290 * @retval kErrorNotFound Could not find the TLV with Type @p aType.
291 *
292 */
293 static Error FindTlvValueOffset(const Message &aMessage, uint8_t aType, uint16_t &aValueOffset, uint16_t &aLength);
294
295 /**
296 * This static method searches for a TLV with a given type in a message, ensures its length is same or larger than
297 * an expected minimum value, and then reads its value into a given buffer.
298 *
299 * If the TLV length is smaller than the minimum length @p aLength, the TLV is considered invalid. In this case,
300 * this method returns `kErrorParse` and the @p aValue buffer is not updated.
301 *
302 * If the TLV length is larger than @p aLength, the TLV is considered valid, but only the first @p aLength bytes
303 * of the value are read and copied into the @p aValue buffer.
304 *
305 * @tparam TlvType The TLV type to find.
306 *
307 * @param[in] aMessage A reference to the message.
308 * @param[out] aValue A buffer to output the value (must contain at least @p aLength bytes).
309 * @param[in] aLength The expected (minimum) length of the TLV value.
310 *
311 * @retval kErrorNone The TLV was found and read successfully. @p aValue is updated.
312 * @retval kErrorNotFound Could not find the TLV with Type @p aType.
313 * @retval kErrorParse TLV was found but it was not well-formed and could not be parsed.
314 *
315 */
Find(const Message & aMessage,void * aValue,uint8_t aLength)316 template <typename TlvType> static Error Find(const Message &aMessage, void *aValue, uint8_t aLength)
317 {
318 return FindTlv(aMessage, TlvType::kType, aValue, aLength);
319 }
320
321 /**
322 * This static method searches for a simple TLV with a single non-integral value in a message, ensures its length is
323 * same or larger than the expected `ValueType` object size, and then reads its value into a value object reference.
324 *
325 * If the TLV length is smaller than the size of @p aValue, the TLV is considered invalid. In this case, this
326 * method returns `kErrorParse` and the @p aValue is not updated.
327 *
328 * If the TLV length is larger than the size of @p aValue, the TLV is considered valid, but the size of
329 * `ValueType` bytes are read and copied into the @p aValue.
330 *
331 * @tparam SimpleTlvType The simple TLV type to find (must be a sub-class of `SimpleTlvInfo`)
332 *
333 * @param[in] aMessage A reference to the message.
334 * @param[out] aValue A reference to the value object to output the read value.
335 *
336 * @retval kErrorNone The TLV was found and read successfully. @p aValue is updated.
337 * @retval kErrorNotFound Could not find the TLV with Type @p aType.
338 * @retval kErrorParse TLV was found but it was not well-formed and could not be parsed.
339 *
340 */
341 template <typename SimpleTlvType>
Find(const Message & aMessage,typename SimpleTlvType::ValueType & aValue)342 static Error Find(const Message &aMessage, typename SimpleTlvType::ValueType &aValue)
343 {
344 return FindTlv(aMessage, SimpleTlvType::kType, &aValue, sizeof(aValue));
345 }
346
347 /**
348 * This static method searches for a simple TLV with a single integral value in a message, and then reads its value
349 * into a given `uint` reference variable.
350 *
351 * If the TLV length is smaller than size of integral value, the TLV is considered invalid. In this case, this
352 * method returns `kErrorParse` and the @p aValue is not updated.
353 *
354 * @tparam UintTlvType The simple TLV type to find (must be a sub-class of `UintTlvInfo`)
355 *
356 * @param[in] aMessage A reference to the message.
357 * @param[out] aValue A reference to an unsigned int value to output the TLV's value.
358 *
359 * @retval kErrorNone The TLV was found and read successfully. @p aValue is updated.
360 * @retval kErrorNotFound Could not find the TLV with Type @p aType.
361 * @retval kErrorParse TLV was found but it was not well-formed and could not be parsed.
362 *
363 */
364 template <typename UintTlvType>
Find(const Message & aMessage,typename UintTlvType::UintValueType & aValue)365 static Error Find(const Message &aMessage, typename UintTlvType::UintValueType &aValue)
366 {
367 return FindUintTlv(aMessage, UintTlvType::kType, aValue);
368 }
369
370 /**
371 * This static method appends a TLV with a given type and value to a message.
372 *
373 * On success this method grows the message by the size of the TLV.
374 *
375 * @tparam TlvType The TLV type to append.
376 *
377 * @param[in] aMessage A reference to the message to append to.
378 * @param[in] aValue A buffer containing the TLV value.
379 * @param[in] aLength The value length (in bytes).
380 *
381 * @retval kErrorNone Successfully appended the TLV to the message.
382 * @retval kErrorNoBufs Insufficient available buffers to grow the message.
383 *
384 */
Append(Message & aMessage,const void * aValue,uint8_t aLength)385 template <typename TlvType> static Error Append(Message &aMessage, const void *aValue, uint8_t aLength)
386 {
387 return AppendTlv(aMessage, TlvType::kType, aValue, aLength);
388 }
389
390 /**
391 * This static method appends a simple TLV with a single (non-integral) value to a message.
392 *
393 * On success this method grows the message by the size of the TLV.
394 *
395 * @tparam SimpleTlvType The simple TLV type to append (must be a sub-class of `SimpleTlvInfo`)
396 *
397 * @param[in] aMessage A reference to the message to append to.
398 * @param[in] aValue A reference to the object containing TLV's value.
399 *
400 * @retval kErrorNone Successfully appended the TLV to the message.
401 * @retval kErrorNoBufs Insufficient available buffers to grow the message.
402 *
403 */
404 template <typename SimpleTlvType>
Append(Message & aMessage,const typename SimpleTlvType::ValueType & aValue)405 static Error Append(Message &aMessage, const typename SimpleTlvType::ValueType &aValue)
406 {
407 return AppendTlv(aMessage, SimpleTlvType::kType, &aValue, sizeof(aValue));
408 }
409
410 /**
411 * This static method appends a simple TLV with a single integral value to a message.
412 *
413 * On success this method grows the message by the size of the TLV.
414 *
415 * @tparam UintTlvType The simple TLV type to append (must be a sub-class of `UintTlvInfo`)
416 *
417 * @param[in] aMessage A reference to the message to append to.
418 * @param[in] aValue An unsigned int value to use as TLV's value.
419 *
420 * @retval kErrorNone Successfully appended the TLV to the message.
421 * @retval kErrorNoBufs Insufficient available buffers to grow the message.
422 *
423 */
Append(Message & aMessage,typename UintTlvType::UintValueType aValue)424 template <typename UintTlvType> static Error Append(Message &aMessage, typename UintTlvType::UintValueType aValue)
425 {
426 return AppendUintTlv(aMessage, UintTlvType::kType, aValue);
427 }
428
429 protected:
430 static const uint8_t kExtendedLength = 255; // Extended Length value.
431
432 private:
433 static Error Find(const Message &aMessage, uint8_t aType, uint16_t *aOffset, uint16_t *aSize, bool *aIsExtendedTlv);
434 static Error FindTlv(const Message &aMessage, uint8_t aType, void *aValue, uint8_t aLength);
435 static Error AppendTlv(Message &aMessage, uint8_t aType, const void *aValue, uint8_t aLength);
436 template <typename UintType> static Error ReadUintTlv(const Message &aMessage, uint16_t aOffset, UintType &aValue);
437 template <typename UintType> static Error FindUintTlv(const Message &aMessage, uint8_t aType, UintType &aValue);
438 template <typename UintType> static Error AppendUintTlv(Message &aMessage, uint8_t aType, UintType aValue);
439
440 uint8_t mType;
441 uint8_t mLength;
442 } OT_TOOL_PACKED_END;
443
444 OT_TOOL_PACKED_BEGIN
445 class ExtendedTlv : public Tlv
446 {
447 public:
448 /**
449 * This method returns the Length value.
450 *
451 */
GetLength(void) const452 uint16_t GetLength(void) const { return HostSwap16(mLength); }
453
454 /**
455 * This method sets the Length value.
456 *
457 * @param[in] aLength The Length value.
458 *
459 */
SetLength(uint16_t aLength)460 void SetLength(uint16_t aLength)
461 {
462 Tlv::SetLength(kExtendedLength);
463 mLength = HostSwap16(aLength);
464 }
465
466 private:
467 uint16_t mLength;
468 } OT_TOOL_PACKED_END;
469
470 /**
471 * This template method casts a `Tlv` pointer to a given subclass `TlvType` pointer.
472 *
473 * @tparam TlvType The TLV type to cast into. MUST be a subclass of `Tlv`.
474 *
475 * @param[in] aTlv A pointer to a `Tlv` to convert/cast to a `TlvType`.
476 *
477 * @returns A `TlvType` pointer to `aTlv`.
478 *
479 */
As(Tlv * aTlv)480 template <class TlvType> TlvType *As(Tlv *aTlv)
481 {
482 return static_cast<TlvType *>(aTlv);
483 }
484
485 /**
486 * This template method casts a `Tlv` pointer to a given subclass `TlvType` pointer.
487 *
488 * @tparam TlvType The TLV type to cast into. MUST be a subclass of `Tlv`.
489 *
490 * @param[in] aTlv A pointer to a `Tlv` to convert/cast to a `TlvType`.
491 *
492 * @returns A `TlvType` pointer to `aTlv`.
493 *
494 */
As(const Tlv * aTlv)495 template <class TlvType> const TlvType *As(const Tlv *aTlv)
496 {
497 return static_cast<const TlvType *>(aTlv);
498 }
499
500 /**
501 * This template method casts a `Tlv` reference to a given subclass `TlvType` reference.
502 *
503 * @tparam TlvType The TLV type to cast into. MUST be a subclass of `Tlv`.
504 *
505 * @param[in] aTlv A reference to a `Tlv` to convert/cast to a `TlvType`.
506 *
507 * @returns A `TlvType` reference to `aTlv`.
508 *
509 */
As(Tlv & aTlv)510 template <class TlvType> TlvType &As(Tlv &aTlv)
511 {
512 return static_cast<TlvType &>(aTlv);
513 }
514
515 /**
516 * This template method casts a `Tlv` reference to a given subclass `TlvType` reference.
517 *
518 * @tparam TlvType The TLV type to cast into. MUST be a subclass of `Tlv`.
519 *
520 * @param[in] aTlv A reference to a `Tlv` to convert/cast to a `TlvType`.
521 *
522 * @returns A `TlvType` reference to `aTlv`.
523 *
524 */
As(const Tlv & aTlv)525 template <class TlvType> const TlvType &As(const Tlv &aTlv)
526 {
527 return static_cast<const TlvType &>(aTlv);
528 }
529
530 /**
531 * This class defines constants for a TLV.
532 *
533 * @tparam kTlvTypeValue The TLV Type value.
534 *
535 */
536 template <uint8_t kTlvTypeValue> class TlvInfo
537 {
538 public:
539 static constexpr uint8_t kType = kTlvTypeValue; ///< The TLV Type value.
540 };
541
542 /**
543 * This class defines constants and types for a simple TLV with an unsigned int value type.
544 *
545 * This class and its sub-classes are intended to be used as the template type in `Tlv::Append<UintTlvType>()`, and
546 * the related `Tlv::Find<UintTlvType>()` and `Tlv::Read<UintTlvType>()`.
547 *
548 * @tparam kTlvTypeValue The TLV Type value.
549 * @tparam UintType The TLV Value's type (must be an unsigned int, i.e. uint8_t, uint16_t, or uint32_t).
550 *
551 */
552 template <uint8_t kTlvTypeValue, typename UintType> class UintTlvInfo : public TlvInfo<kTlvTypeValue>
553 {
554 public:
555 static_assert(TypeTraits::IsSame<UintType, uint8_t>::kValue || TypeTraits::IsSame<UintType, uint16_t>::kValue ||
556 TypeTraits::IsSame<UintType, uint32_t>::kValue,
557 "UintTlv must be used used with unsigned int value type");
558
559 typedef UintType UintValueType; ///< The TLV Value unsigned int type.
560 };
561
562 /**
563 * This class defines constants and types for a simple TLV with a single value.
564 *
565 * This class and its sub-classes are intended to be used as the template type in `Tlv::Append<SimpleTlvType>()`,
566 * and the related `Tlv::Find<SimpleTlvType>()` and `Tlv::Read<SimpleTlvType>()`.
567 *
568 * @tparam kTlvTypeValue The TLV Type value.
569 * @tparam TlvValueType The TLV Value's type (must not be an integral type).
570 *
571 */
572 template <uint8_t kTlvTypeValue, typename TlvValueType> class SimpleTlvInfo : public TlvInfo<kTlvTypeValue>
573 {
574 public:
575 static_assert(!TypeTraits::IsPointer<TlvValueType>::kValue, "TlvValueType must not be a pointer");
576 static_assert(!TypeTraits::IsSame<TlvValueType, uint8_t>::kValue, "SimpleTlv must not use int value type");
577 static_assert(!TypeTraits::IsSame<TlvValueType, uint16_t>::kValue, "SimpleTlv must not use int value type");
578 static_assert(!TypeTraits::IsSame<TlvValueType, uint32_t>::kValue, "SimpleTlv must not use int value type");
579 static_assert(!TypeTraits::IsSame<TlvValueType, int8_t>::kValue, "SimpleTlv must not use int value type");
580 static_assert(!TypeTraits::IsSame<TlvValueType, int16_t>::kValue, "SimpleTlv must not use int value type");
581 static_assert(!TypeTraits::IsSame<TlvValueType, int32_t>::kValue, "SimpleTlv must not use int value type");
582
583 typedef TlvValueType ValueType; ///< The TLV Value type.
584 };
585
586 } // namespace ot
587
588 #endif // TLVS_HPP_
589