mirror of
https://github.com/espressif/openthread.git
synced 2026-08-11 13:17:48 +00:00
[tlv] add helper read/append methods for TLVs with simple types (#4635)
This commit adds helper static methods in `Tlv` class to directly read the value of simple TLVs from a `Message`, or append a simple TLV to a message. The simple TLVs are the ones with single unsigned integer value (e.g., MLE Frame Counter TLV, MeshCop Scan Duration TLV, etc), or a value that can be treated as an array of bytes (e.g., MeshCop PSKc TLV, etc).
This commit is contained in:
committed by
Jonathan Hui
parent
c54238fdd6
commit
19ed02842c
+105
-4
@@ -55,6 +55,15 @@ const uint8_t *Tlv::GetValue(void) const
|
||||
return reinterpret_cast<const uint8_t *>(this) + (IsExtended() ? sizeof(ExtendedTlv) : sizeof(Tlv));
|
||||
}
|
||||
|
||||
otError Tlv::AppendTo(Message &aMessage) const
|
||||
{
|
||||
uint32_t size = GetSize();
|
||||
|
||||
assert(size <= UINT16_MAX);
|
||||
|
||||
return aMessage.Append(this, static_cast<uint16_t>(size));
|
||||
}
|
||||
|
||||
otError Tlv::Get(const Message &aMessage, uint8_t aType, uint16_t aMaxSize, Tlv &aTlv)
|
||||
{
|
||||
otError error;
|
||||
@@ -165,13 +174,105 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Tlv::AppendTo(Message &aMessage) const
|
||||
otError Tlv::ReadUint8Tlv(const Message &aMessage, uint8_t aType, uint8_t &aValue)
|
||||
{
|
||||
uint32_t size = GetSize();
|
||||
otError error = OT_ERROR_NONE;
|
||||
TlvUint8 tlv8;
|
||||
|
||||
assert(size <= UINT16_MAX);
|
||||
SuccessOrExit(error = Get(aMessage, aType, sizeof(tlv8), tlv8));
|
||||
VerifyOrExit(tlv8.IsValid(), error = OT_ERROR_PARSE);
|
||||
aValue = tlv8.GetUint8Value();
|
||||
|
||||
return aMessage.Append(this, static_cast<uint16_t>(size));
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Tlv::ReadUint16Tlv(const Message &aMessage, uint8_t aType, uint16_t &aValue)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
TlvUint16 tlv16;
|
||||
|
||||
SuccessOrExit(error = Get(aMessage, aType, sizeof(tlv16), tlv16));
|
||||
VerifyOrExit(tlv16.IsValid(), error = OT_ERROR_PARSE);
|
||||
aValue = tlv16.GetUint16Value();
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Tlv::ReadUint32Tlv(const Message &aMessage, uint8_t aType, uint32_t &aValue)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
TlvUint32 tlv32;
|
||||
|
||||
SuccessOrExit(error = Get(aMessage, aType, sizeof(tlv32), tlv32));
|
||||
VerifyOrExit(tlv32.IsValid(), error = OT_ERROR_PARSE);
|
||||
aValue = tlv32.GetUint32Value();
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Tlv::ReadTlv(const Message &aMessage, uint8_t aType, void *aValue, uint8_t aLength)
|
||||
{
|
||||
otError error;
|
||||
uint16_t offset;
|
||||
uint16_t length;
|
||||
|
||||
SuccessOrExit(error = GetValueOffset(aMessage, aType, offset, length));
|
||||
VerifyOrExit(length >= aLength, error = OT_ERROR_PARSE);
|
||||
aMessage.Read(offset, aLength, static_cast<uint8_t *>(aValue));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Tlv::AppendUint8Tlv(Message &aMessage, uint8_t aType, uint8_t aValue)
|
||||
{
|
||||
TlvUint8 tlv8;
|
||||
|
||||
tlv8.Init(aType);
|
||||
tlv8.SetUint8Value(aValue);
|
||||
|
||||
return tlv8.AppendTo(aMessage);
|
||||
}
|
||||
|
||||
otError Tlv::AppendUint16Tlv(Message &aMessage, uint8_t aType, uint16_t aValue)
|
||||
{
|
||||
TlvUint16 tlv16;
|
||||
|
||||
tlv16.Init(aType);
|
||||
tlv16.SetUint16Value(aValue);
|
||||
|
||||
return tlv16.AppendTo(aMessage);
|
||||
}
|
||||
|
||||
otError Tlv::AppendUint32Tlv(Message &aMessage, uint8_t aType, uint32_t aValue)
|
||||
{
|
||||
TlvUint32 tlv32;
|
||||
|
||||
tlv32.Init(aType);
|
||||
tlv32.SetUint32Value(aValue);
|
||||
|
||||
return tlv32.AppendTo(aMessage);
|
||||
}
|
||||
|
||||
otError Tlv::AppendTlv(Message &aMessage, uint8_t aType, const uint8_t *aValue, uint8_t aLength)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
Tlv tlv;
|
||||
|
||||
assert(aLength <= Tlv::kBaseTlvMaxLength);
|
||||
|
||||
tlv.SetType(aType);
|
||||
tlv.SetLength(aLength);
|
||||
SuccessOrExit(error = aMessage.Append(&tlv, sizeof(tlv)));
|
||||
|
||||
VerifyOrExit(aLength > 0);
|
||||
error = aMessage.Append(aValue, aLength);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
} // namespace ot
|
||||
|
||||
+275
-3
@@ -163,6 +163,19 @@ public:
|
||||
return reinterpret_cast<const Tlv *>(reinterpret_cast<const uint8_t *>(this) + GetSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method appends a TLV to the end of the message.
|
||||
*
|
||||
* On success, this method grows the message by the size of the TLV.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message to append to.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully appended the TLV to the message.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient available buffers to grow the message.
|
||||
*
|
||||
*/
|
||||
otError AppendTo(Message &aMessage) const;
|
||||
|
||||
/**
|
||||
* This static method reads the requested TLV out of @p aMessage.
|
||||
*
|
||||
@@ -211,17 +224,129 @@ public:
|
||||
static otError GetValueOffset(const Message &aMessage, uint8_t aType, uint16_t &aOffset, uint16_t &aLength);
|
||||
|
||||
/**
|
||||
* This method appends a TLV to the end of the message.
|
||||
* This static method searches for a TLV with a given type in a message and reads its value as an `uint8_t`.
|
||||
*
|
||||
* On success, this method grows the message by the size of the TLV.
|
||||
* @param[in] aMessage A reference to the message.
|
||||
* @param[in] aType The TLV type to search for.
|
||||
* @param[out] aValue A reference to a `uint8_t` to output the TLV's value.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully found the TLV and updated @p aValue.
|
||||
* @retval OT_ERROR_NOT_FOUND Could not find the TLV with Type @p aType.
|
||||
* @retval OT_ERROR_PARSE TLV was found but it was not well-formed and could not be parsed.
|
||||
*
|
||||
*/
|
||||
static otError ReadUint8Tlv(const Message &aMessage, uint8_t aType, uint8_t &aValue);
|
||||
|
||||
/**
|
||||
* This static method searches for a TLV with a given type in a message and reads its value as an `uint16_t`.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message.
|
||||
* @param[in] aType The TLV type to search for.
|
||||
* @param[out] aValue A reference to a `uint16_t` to output the TLV's value.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully found the TLV and updated @p aValue.
|
||||
* @retval OT_ERROR_NOT_FOUND Could not find the TLV with Type @p aType.
|
||||
* @retval OT_ERROR_PARSE TLV was found but it was not well-formed and could not be parsed.
|
||||
*
|
||||
*/
|
||||
static otError ReadUint16Tlv(const Message &aMessage, uint8_t aType, uint16_t &aValue);
|
||||
|
||||
/**
|
||||
* This static method searches for a TLV with a given type in a message and reads its value as an `uint32_t`.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message.
|
||||
* @param[in] aType The TLV type to search for.
|
||||
* @param[out] aValue A reference to a `uint32_t` to output the TLV's value.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully found the TLV and updated @p aValue.
|
||||
* @retval OT_ERROR_NOT_FOUND Could not find the TLV with Type @p aType.
|
||||
* @retval OT_ERROR_PARSE TLV was found but it was not well-formed and could not be parsed.
|
||||
*
|
||||
*/
|
||||
static otError ReadUint32Tlv(const Message &aMessage, uint8_t aType, uint32_t &aValue);
|
||||
|
||||
/**
|
||||
* This static method searches for a TLV with a given type in a message, ensures its length is same or larger than
|
||||
* an expected minimum value, and then reads its value into a given buffer.
|
||||
*
|
||||
* If the TLV length is smaller than the minimum length @p aLength, the TLV is considered invalid. In this case,
|
||||
* this method returns `OT_ERROR_PARSE` and the @p aValue buffer is not updated.
|
||||
*
|
||||
* If the TLV is length is larger than @p aLength, the TLV is considered valid, but only the @aLength first bytes
|
||||
* of the value are read and copied into the @p aValue buffer.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message.
|
||||
* @param[in] aType The TLV type to search for.
|
||||
* @param[out] aValue A buffer to output the value (must contain at least @p aLength bytes).
|
||||
* @param[in] aLength The expected (minimum) length of the TLV value.
|
||||
*
|
||||
* @retval OT_ERROR_NONE The TLV was found and read successfully. @p @aValue is updated.
|
||||
* @retval OT_ERROR_NOT_FOUND Could not find the TLV with Type @p aType.
|
||||
* @retval OT_ERROR_PARSE TLV was found but it was not well-formed and could not be parsed.
|
||||
*
|
||||
*/
|
||||
static otError ReadTlv(const Message &aMessage, uint8_t aType, void *aValue, uint8_t aLength);
|
||||
|
||||
/**
|
||||
* This static method appends a simple TLV with a given type and an `uint8_t` value to a message.
|
||||
*
|
||||
* On success this method grows the message by the size of the TLV.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message to append to.
|
||||
* @param[in] aType The TLV type.
|
||||
* @param[in] aValue The TLV value (`uint8_t`).
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully appended the TLV to the message.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient available buffers to grow the message.
|
||||
*
|
||||
*/
|
||||
otError AppendTo(Message &aMessage) const;
|
||||
static otError AppendUint8Tlv(Message &aMessage, uint8_t aType, uint8_t aValue);
|
||||
|
||||
/**
|
||||
* This static method appends a simple TLV with a given type and an `uint16_t` value to a message.
|
||||
*
|
||||
* On success this method grows the message by the size of the TLV.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message to append to.
|
||||
* @param[in] aType The TLV type.
|
||||
* @param[in] aValue The TLV value (`uint16_t`).
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully appended the TLV to the message.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient available buffers to grow the message.
|
||||
*
|
||||
*/
|
||||
static otError AppendUint16Tlv(Message &aMessage, uint8_t aType, uint16_t aValue);
|
||||
|
||||
/**
|
||||
* This static method appends a (simple) TLV with a given type and an `uint32_t` value to a message.
|
||||
*
|
||||
* On success this method grows the message by the size of the TLV.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message to append to.
|
||||
* @param[in] aType The TLV type.
|
||||
* @param[in] aValue The TLV value (`uint32_t`).
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully appended the TLV to the message.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient available buffers to grow the message.
|
||||
*
|
||||
*/
|
||||
static otError AppendUint32Tlv(Message &aMessage, uint8_t aType, uint32_t aValue);
|
||||
|
||||
/**
|
||||
* This static method appends a TLV with a given type and value to a message.
|
||||
*
|
||||
* On success this method grows the message by the size of the TLV.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message to append to.
|
||||
* @param[in] aType The TLV type.
|
||||
* @param[in] aValue A buffer containing the TLV value.
|
||||
* @param[in] aLength The value length (in bytes).
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully appended the TLV to the message.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient available buffers to grow the message.
|
||||
*
|
||||
*/
|
||||
static otError AppendTlv(Message &aMessage, uint8_t aType, const uint8_t *aValue, uint8_t aLength);
|
||||
|
||||
protected:
|
||||
enum
|
||||
@@ -283,6 +408,153 @@ private:
|
||||
uint16_t mLength;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class implements a simple TLV with a `uint8_t` value.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class TlvUint8 : public Tlv
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This method initializes the TLV.
|
||||
*
|
||||
* @param[in] aType The Type value.
|
||||
*
|
||||
*/
|
||||
void Init(uint8_t aType)
|
||||
{
|
||||
SetType(aType);
|
||||
SetLength(sizeof(*this) - sizeof(Tlv));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the TLV appears to be well-formed.
|
||||
*
|
||||
* @retval TRUE If the TLV appears to be well-formed.
|
||||
* @retval FALSE If the TLV does not appear to be well-formed.
|
||||
*
|
||||
*/
|
||||
bool IsValid(void) const { return GetLength() >= sizeof(*this) - sizeof(Tlv); }
|
||||
|
||||
/**
|
||||
* This method returns the `uint8_t` value.
|
||||
*
|
||||
* @returns The `uint8_t` value.
|
||||
*
|
||||
*/
|
||||
uint8_t GetUint8Value(void) const { return mValue; }
|
||||
|
||||
/**
|
||||
* This method sets the `uint8_t` value.
|
||||
*
|
||||
* @param[in] aValue The `uint8_t` value.
|
||||
*
|
||||
*/
|
||||
void SetUint8Value(uint8_t aValue) { mValue = aValue; }
|
||||
|
||||
private:
|
||||
uint8_t mValue;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class implements a simple TLV with a `uint16_t` value.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class TlvUint16 : public Tlv
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This method initializes the TLV.
|
||||
*
|
||||
* @param[in] aType The Type value.
|
||||
*
|
||||
*/
|
||||
void Init(uint8_t aType)
|
||||
{
|
||||
SetType(aType);
|
||||
SetLength(sizeof(*this) - sizeof(Tlv));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the TLV appears to be well-formed.
|
||||
*
|
||||
* @retval TRUE If the TLV appears to be well-formed.
|
||||
* @retval FALSE If the TLV does not appear to be well-formed.
|
||||
*
|
||||
*/
|
||||
bool IsValid(void) const { return GetLength() >= sizeof(*this) - sizeof(Tlv); }
|
||||
|
||||
/**
|
||||
* This method returns the `uint16_t` value.
|
||||
*
|
||||
* @returns The `uint16_t` value.
|
||||
*
|
||||
*/
|
||||
uint16_t GetUint16Value(void) const { return HostSwap16(mValue); }
|
||||
|
||||
/**
|
||||
* This method sets the `uint16_t` value.
|
||||
*
|
||||
* @param[in] aValue The `uint16_t` value.
|
||||
*
|
||||
*/
|
||||
void SetUint16Value(uint16_t aValue) { mValue = HostSwap16(aValue); }
|
||||
|
||||
private:
|
||||
uint16_t mValue;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class implements a simple TLV with a `uint32_t` value.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class TlvUint32 : public Tlv
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This method initializes the TLV.
|
||||
*
|
||||
* @param[in] aType The Type value.
|
||||
*
|
||||
*/
|
||||
void Init(uint8_t aType)
|
||||
{
|
||||
SetType(aType);
|
||||
SetLength(sizeof(*this) - sizeof(Tlv));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the TLV appears to be well-formed.
|
||||
*
|
||||
* @retval TRUE If the TLV appears to be well-formed.
|
||||
* @retval FALSE If the TLV does not appear to be well-formed.
|
||||
*
|
||||
*/
|
||||
bool IsValid(void) const { return GetLength() >= sizeof(*this) - sizeof(Tlv); }
|
||||
|
||||
/**
|
||||
* This method returns the `uint32_t` value.
|
||||
*
|
||||
* @returns The `uint32_t` value.
|
||||
*
|
||||
*/
|
||||
uint32_t GetUint32Value(void) const { return HostSwap32(mValue); }
|
||||
|
||||
/**
|
||||
* This method sets the `uint32_t` value.
|
||||
*
|
||||
* @param[in] aValue The `uint32_t` value.
|
||||
*
|
||||
*/
|
||||
void SetUint32Value(uint32_t aValue) { mValue = HostSwap32(aValue); }
|
||||
|
||||
private:
|
||||
uint32_t mValue;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
} // namespace ot
|
||||
|
||||
#endif // TLVS_HPP_
|
||||
|
||||
Reference in New Issue
Block a user