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