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