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