[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:
Abtin Keshavarzian
2020-03-09 11:39:09 -07:00
committed by Jonathan Hui
parent c54238fdd6
commit 19ed02842c
2 changed files with 380 additions and 7 deletions
+105 -4
View File
@@ -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
View File
@@ -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_