mirror of
https://github.com/espressif/openthread.git
synced 2026-08-06 02:37:47 +00:00
[tlv] handle Extended TLV and simplify searching for TLV in a message (#4152)
This commit contains the following change in `Tlv` class: - Changes `GetSize()`, `GetValue()` and `GetNext()` to ensure they work correctly independent of whether the TLV is an Extended TLV or not. - Defines a new common private static method `Tlv::Find()` which is then used to simplify `Tlv::Get()` and `Tlv::GetOffset()` and `Tlv::GetValueOffset()` implementations. - This change also ensures `Tlv::Get()` (which finds and reads a TLV of a given type within a message) work correctly for Extended TLVs.
This commit is contained in:
committed by
Jonathan Hui
parent
0e489b07e2
commit
3514458d5d
+83
-57
@@ -38,20 +38,36 @@
|
||||
|
||||
namespace ot {
|
||||
|
||||
otError Tlv::Get(const Message &aMessage, uint8_t aType, uint16_t aMaxLength, Tlv &aTlv)
|
||||
uint16_t Tlv::GetSize(void) const
|
||||
{
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
return IsExtended() ? sizeof(ExtendedTlv) + static_cast<const ExtendedTlv *>(this)->GetLength()
|
||||
: sizeof(Tlv) + GetLength();
|
||||
}
|
||||
|
||||
uint8_t *Tlv::GetValue(void)
|
||||
{
|
||||
return reinterpret_cast<uint8_t *>(this) + (IsExtended() ? sizeof(ExtendedTlv) : sizeof(Tlv));
|
||||
}
|
||||
|
||||
const uint8_t *Tlv::GetValue(void) const
|
||||
{
|
||||
return reinterpret_cast<const uint8_t *>(this) + (IsExtended() ? sizeof(ExtendedTlv) : sizeof(Tlv));
|
||||
}
|
||||
|
||||
otError Tlv::Get(const Message &aMessage, uint8_t aType, uint16_t aMaxSize, Tlv &aTlv)
|
||||
{
|
||||
otError error;
|
||||
uint16_t offset;
|
||||
uint16_t size;
|
||||
|
||||
SuccessOrExit(error = GetOffset(aMessage, aType, offset));
|
||||
aMessage.Read(offset, sizeof(Tlv), &aTlv);
|
||||
SuccessOrExit(error = Find(aMessage, aType, &offset, &size, NULL));
|
||||
|
||||
if (aMaxLength > sizeof(aTlv) + aTlv.GetLength())
|
||||
if (aMaxSize > size)
|
||||
{
|
||||
aMaxLength = sizeof(aTlv) + aTlv.GetLength();
|
||||
aMaxSize = size;
|
||||
}
|
||||
|
||||
aMessage.Read(offset, aMaxLength, &aTlv);
|
||||
aMessage.Read(offset, aMaxSize, &aTlv);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
@@ -59,77 +75,87 @@ exit:
|
||||
|
||||
otError Tlv::GetOffset(const Message &aMessage, uint8_t aType, uint16_t &aOffset)
|
||||
{
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
uint16_t offset = aMessage.GetOffset();
|
||||
uint16_t end = aMessage.GetLength();
|
||||
Tlv tlv;
|
||||
return Find(aMessage, aType, &aOffset, NULL, NULL);
|
||||
}
|
||||
|
||||
while (offset + sizeof(tlv) <= end)
|
||||
otError Tlv::GetValueOffset(const Message &aMessage, uint8_t aType, uint16_t &aValueOffset, uint16_t &aLength)
|
||||
{
|
||||
otError error;
|
||||
uint16_t offset;
|
||||
uint16_t size;
|
||||
bool isExtendedTlv;
|
||||
|
||||
SuccessOrExit(error = Find(aMessage, aType, &offset, &size, &isExtendedTlv));
|
||||
|
||||
if (!isExtendedTlv)
|
||||
{
|
||||
uint32_t length = sizeof(tlv);
|
||||
|
||||
aMessage.Read(offset, sizeof(tlv), &tlv);
|
||||
|
||||
if (tlv.GetLength() != kExtendedLength)
|
||||
{
|
||||
length += tlv.GetLength();
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t extLength;
|
||||
|
||||
VerifyOrExit(sizeof(extLength) == aMessage.Read(offset + sizeof(tlv), sizeof(extLength), &extLength));
|
||||
length += sizeof(extLength) + HostSwap16(extLength);
|
||||
}
|
||||
|
||||
VerifyOrExit(offset + length <= end);
|
||||
|
||||
if (tlv.GetType() == aType)
|
||||
{
|
||||
aOffset = offset;
|
||||
ExitNow(error = OT_ERROR_NONE);
|
||||
}
|
||||
|
||||
offset += static_cast<uint16_t>(length);
|
||||
aValueOffset = offset + sizeof(Tlv);
|
||||
aLength = size - sizeof(Tlv);
|
||||
}
|
||||
else
|
||||
{
|
||||
aValueOffset = offset + sizeof(ExtendedTlv);
|
||||
aLength = size - sizeof(ExtendedTlv);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Tlv::GetValueOffset(const Message &aMessage, uint8_t aType, uint16_t &aOffset, uint16_t &aLength)
|
||||
otError Tlv::Find(const Message &aMessage, uint8_t aType, uint16_t *aOffset, uint16_t *aSize, bool *aIsExtendedTlv)
|
||||
{
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
uint16_t offset = aMessage.GetOffset();
|
||||
uint16_t end = aMessage.GetLength();
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
uint16_t offset = aMessage.GetOffset();
|
||||
uint16_t remainingLen = aMessage.GetLength();
|
||||
Tlv tlv;
|
||||
uint16_t size;
|
||||
|
||||
while (offset + sizeof(tlv) <= end)
|
||||
VerifyOrExit(offset <= remainingLen);
|
||||
remainingLen -= offset;
|
||||
|
||||
while (true)
|
||||
{
|
||||
uint16_t length;
|
||||
VerifyOrExit(sizeof(Tlv) <= remainingLen);
|
||||
aMessage.Read(offset, sizeof(Tlv), &tlv);
|
||||
|
||||
aMessage.Read(offset, sizeof(tlv), &tlv);
|
||||
offset += sizeof(tlv);
|
||||
length = tlv.GetLength();
|
||||
|
||||
if (length == kExtendedLength)
|
||||
if (tlv.mLength != kExtendedLength)
|
||||
{
|
||||
VerifyOrExit(offset + sizeof(length) <= end);
|
||||
aMessage.Read(offset, sizeof(length), &length);
|
||||
offset += sizeof(length);
|
||||
length = HostSwap16(length);
|
||||
size = tlv.GetSize();
|
||||
}
|
||||
else
|
||||
{
|
||||
ExtendedTlv extTlv;
|
||||
|
||||
VerifyOrExit(sizeof(ExtendedTlv) <= remainingLen);
|
||||
aMessage.Read(offset, sizeof(ExtendedTlv), &extTlv);
|
||||
size = extTlv.GetSize();
|
||||
}
|
||||
|
||||
VerifyOrExit(length <= end - offset);
|
||||
VerifyOrExit(size <= remainingLen);
|
||||
|
||||
if (tlv.GetType() == aType)
|
||||
{
|
||||
aOffset = offset;
|
||||
aLength = length;
|
||||
ExitNow(error = OT_ERROR_NONE);
|
||||
if (aOffset != NULL)
|
||||
{
|
||||
*aOffset = offset;
|
||||
}
|
||||
|
||||
if (aSize != NULL)
|
||||
{
|
||||
*aSize = size;
|
||||
}
|
||||
|
||||
if (aIsExtendedTlv != NULL)
|
||||
{
|
||||
*aIsExtendedTlv = (tlv.mLength == kExtendedLength);
|
||||
}
|
||||
|
||||
error = OT_ERROR_NONE;
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
offset += length;
|
||||
offset += size;
|
||||
remainingLen -= size;
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
+60
-12
@@ -83,9 +83,22 @@ public:
|
||||
*/
|
||||
void SetType(uint8_t aType) { mType = aType; }
|
||||
|
||||
/**
|
||||
* This method indicates whether the TLV is an Extended TLV.
|
||||
*
|
||||
* @retval TRUE If the TLV is an Extended TLV.
|
||||
* @retval FALSE If the TLV is not an Extended TLV.
|
||||
*
|
||||
*/
|
||||
bool IsExtended(void) const { return (mLength == kExtendedLength); }
|
||||
|
||||
/**
|
||||
* This method returns the Length value.
|
||||
*
|
||||
* @note This method should be used when TLV is not an Extended TLV, otherwise the returned length from this method
|
||||
* would not be correct. When TLV is an Extended TLV, the TLV should be down-casted to the `ExtendedTlv` type and
|
||||
* the `ExtendedTlv::GetLength()` should be used instead.
|
||||
*
|
||||
* @returns The Length value.
|
||||
*
|
||||
*/
|
||||
@@ -100,65 +113,79 @@ public:
|
||||
void SetLength(uint8_t aLength) { mLength = aLength; }
|
||||
|
||||
/**
|
||||
* This method returns the total size including Type, Length, and Value fields.
|
||||
* This method returns the TLV's total size (number of bytes) including Type, Length, and Value fields.
|
||||
*
|
||||
* This method correctly returns the TLV size independent of whether the TLV is an Extended TLV or not.
|
||||
*
|
||||
* @returns The total size include Type, Length, and Value fields.
|
||||
*
|
||||
*/
|
||||
uint16_t GetSize(void) const { return sizeof(Tlv) + mLength; }
|
||||
uint16_t GetSize(void) const;
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the Value.
|
||||
*
|
||||
* This method can be used independent of whether the TLV is an Extended TLV or not.
|
||||
*
|
||||
* @returns A pointer to the value.
|
||||
*
|
||||
*/
|
||||
uint8_t *GetValue(void) { return reinterpret_cast<uint8_t *>(this) + sizeof(Tlv); }
|
||||
uint8_t *GetValue(void);
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the Value.
|
||||
*
|
||||
* This method can be used independent of whether the TLV is an Extended TLV or not.
|
||||
*
|
||||
* @returns A pointer to the value.
|
||||
*
|
||||
*/
|
||||
const uint8_t *GetValue(void) const { return reinterpret_cast<const uint8_t *>(this) + sizeof(Tlv); }
|
||||
const uint8_t *GetValue(void) const;
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the next TLV.
|
||||
*
|
||||
* This method correctly returns the next TLV independent of whether the current TLV is an Extended TLV or not.
|
||||
*
|
||||
* @returns A pointer to the next TLV.
|
||||
*
|
||||
*/
|
||||
Tlv *GetNext(void) { return reinterpret_cast<Tlv *>(reinterpret_cast<uint8_t *>(this) + sizeof(*this) + mLength); }
|
||||
Tlv *GetNext(void) { return reinterpret_cast<Tlv *>(reinterpret_cast<uint8_t *>(this) + GetSize()); }
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the next TLV.
|
||||
*
|
||||
* This method correctly returns the next TLV independent of whether the current TLV is an Extended TLV or not.
|
||||
*
|
||||
* @returns A pointer to the next TLV.
|
||||
*
|
||||
*/
|
||||
const Tlv *GetNext(void) const
|
||||
{
|
||||
return reinterpret_cast<const Tlv *>(reinterpret_cast<const uint8_t *>(this) + sizeof(*this) + mLength);
|
||||
return reinterpret_cast<const Tlv *>(reinterpret_cast<const uint8_t *>(this) + GetSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* This static method reads the requested TLV out of @p aMessage.
|
||||
*
|
||||
* This method can be used independent of whether the read TLV (from message) is an Extended TLV or not.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message.
|
||||
* @param[in] aType The Type value to search for.
|
||||
* @param[in] aMaxLength Maximum number of bytes to read.
|
||||
* @param[in] aMaxSize Maximum number of bytes to read.
|
||||
* @param[out] aTlv A reference to the TLV that will be copied to.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully copied the TLV.
|
||||
* @retval OT_ERROR_NOT_FOUND Could not find the TLV with Type @p aType.
|
||||
*
|
||||
*/
|
||||
static otError Get(const Message &aMessage, uint8_t aType, uint16_t aMaxLength, Tlv &aTlv);
|
||||
static otError Get(const Message &aMessage, uint8_t aType, uint16_t aMaxSize, Tlv &aTlv);
|
||||
|
||||
/**
|
||||
* This static method obtains the offset of a TLV within @p aMessage.
|
||||
*
|
||||
* This method can be used independent of whether the read TLV (from message) is an Extended TLV or not.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message.
|
||||
* @param[in] aType The Type value to search for.
|
||||
* @param[out] aOffset A reference to the offset of the TLV.
|
||||
@@ -172,6 +199,8 @@ public:
|
||||
/**
|
||||
* This static method finds the offset and length of a given TLV type.
|
||||
*
|
||||
* This method can be used independent of whether the read TLV (from message) is an Extended TLV or not.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message.
|
||||
* @param[in] aType The Type value to search for.
|
||||
* @param[out] aOffset The offset where the value starts.
|
||||
@@ -184,16 +213,35 @@ public:
|
||||
static otError GetValueOffset(const Message &aMessage, uint8_t aType, uint16_t &aOffset, uint16_t &aLength);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Length values.
|
||||
*
|
||||
*/
|
||||
enum
|
||||
{
|
||||
kExtendedLength = 255, ///< Extended Length value
|
||||
};
|
||||
|
||||
private:
|
||||
/**
|
||||
* This private static method searches within a given message for TLV type and outputs the TLV offset, size and
|
||||
* whether it is an Extended TLV.
|
||||
*
|
||||
* A NULL pointer can be used for output parameters @p aOffset, @p aSize, or @p aIsExtendedTlv if the parameter
|
||||
* is not required.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message to search within.
|
||||
* @param[in] aType The TLV type to search for.
|
||||
* @param[out] aOffset A pointer to a variable to output the offset to the start of the TLV.
|
||||
* @param[out] aSize A pointer to a variable to output the size (total number of bytes) of the TLV.
|
||||
* @param[out] aIsExtendedTlv A pointer to a boolean variable to output whether the found TLV is extended or not.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully found the TLV.
|
||||
* @retval OT_ERROR_NOT_FOUND Could not find the TLV with Type @p aType.
|
||||
*
|
||||
*/
|
||||
static otError Find(const Message &aMessage,
|
||||
uint8_t aType,
|
||||
uint16_t * aOffset,
|
||||
uint16_t * aSize,
|
||||
bool * aIsExtendedTlv);
|
||||
|
||||
uint8_t mType;
|
||||
uint8_t mLength;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
Reference in New Issue
Block a user