mirror of
https://github.com/espressif/openthread.git
synced 2026-08-26 04:09:52 +00:00
[ip6] add Option::ParseFrom() and common PadOption (#8719)
This commit contains changes related to handling of IPv6 Options. It adds a new method `Option::ParseFrom()` which parses and validates an IPv6 Option from a given message. This method handles the Pad1 Option as well as other Option Types. This makes it easier (and safer) to iterate through Options in an Extension Header. `Option::GetSize()` is also updated to return the correct size for Pad1 Option since Pad1 Option does not follow the common Option format (has Type field with no Length field). This commit also adds a common `PadOption` class which based on the desired padding size uses Pad1 or PadN as its type. It also provides `InitToPadHeaderWithSize()` which prepares the option with proper length to pad an Extension Header with a given current size (also determining whether or not padding is needed). This commit also updates `Ip6` methods to use `kLengthUnitSize` constant.
This commit is contained in:
+57
-85
@@ -192,17 +192,15 @@ Error Ip6::AddMplOption(Message &aMessage, Header &aHeader)
|
||||
Error error = kErrorNone;
|
||||
HopByHopHeader hbhHeader;
|
||||
MplOption mplOption;
|
||||
PadOption padOption;
|
||||
|
||||
hbhHeader.SetNextHeader(aHeader.GetNextHeader());
|
||||
hbhHeader.SetLength(0);
|
||||
mMpl.InitOption(mplOption, aHeader.GetSource());
|
||||
|
||||
// Mpl option may require two bytes padding.
|
||||
if ((mplOption.GetSize() + sizeof(hbhHeader)) % 8)
|
||||
// Check if MPL option may require padding
|
||||
if (padOption.InitToPadHeaderWithSize(sizeof(HopByHopHeader) + mplOption.GetSize()) == kErrorNone)
|
||||
{
|
||||
PadNOption padOption;
|
||||
|
||||
padOption.Init(2);
|
||||
SuccessOrExit(error = aMessage.PrependBytes(&padOption, padOption.GetSize()));
|
||||
}
|
||||
|
||||
@@ -256,35 +254,35 @@ Error Ip6::InsertMplOption(Message &aMessage, Header &aHeader)
|
||||
HopByHopHeader hbh;
|
||||
uint16_t hbhSize;
|
||||
MplOption mplOption;
|
||||
PadOption padOption;
|
||||
|
||||
// read existing hop-by-hop option header
|
||||
// Read existing hop-by-hop option header
|
||||
SuccessOrExit(error = aMessage.Read(0, hbh));
|
||||
hbhSize = hbh.GetSize();
|
||||
|
||||
VerifyOrExit(hbhSize <= aHeader.GetPayloadLength(), error = kErrorParse);
|
||||
|
||||
// increase existing hop-by-hop option header length by 8 bytes
|
||||
// Increment hop-by-hop option header length by one which
|
||||
// increases its total size by 8 bytes.
|
||||
hbh.SetLength(hbh.GetLength() + 1);
|
||||
aMessage.Write(0, hbh);
|
||||
|
||||
// make space for MPL Option + padding by shifting hop-by-hop option header
|
||||
SuccessOrExit(error = aMessage.InsertHeader(hbhSize, 8));
|
||||
// Make space for MPL Option + padding (8 bytes) at the end
|
||||
// of hop-by-hop header
|
||||
SuccessOrExit(error = aMessage.InsertHeader(hbhSize, ExtensionHeader::kLengthUnitSize));
|
||||
|
||||
// insert MPL Option
|
||||
// Insert MPL Option
|
||||
mMpl.InitOption(mplOption, aHeader.GetSource());
|
||||
aMessage.WriteBytes(hbhSize, &mplOption, mplOption.GetSize());
|
||||
|
||||
// insert Pad Option (if needed)
|
||||
if (mplOption.GetSize() % 8)
|
||||
// Insert Pad Option (if needed)
|
||||
if (padOption.InitToPadHeaderWithSize(mplOption.GetSize()) == kErrorNone)
|
||||
{
|
||||
PadNOption padOption;
|
||||
|
||||
padOption.Init(8 - (mplOption.GetSize() % 8));
|
||||
aMessage.WriteBytes(hbhSize + mplOption.GetSize(), &padOption, padOption.GetSize());
|
||||
}
|
||||
|
||||
// increase IPv6 Payload Length
|
||||
aHeader.SetPayloadLength(aHeader.GetPayloadLength() + 8);
|
||||
// Update IPv6 Payload Length
|
||||
aHeader.SetPayloadLength(aHeader.GetPayloadLength() + ExtensionHeader::kLengthUnitSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -325,6 +323,7 @@ Error Ip6::RemoveMplOption(Message &aMessage)
|
||||
Error error = kErrorNone;
|
||||
Header ip6Header;
|
||||
HopByHopHeader hbh;
|
||||
Option option;
|
||||
uint16_t offset;
|
||||
uint16_t endOffset;
|
||||
uint16_t mplOffset = 0;
|
||||
@@ -342,16 +341,18 @@ Error Ip6::RemoveMplOption(Message &aMessage)
|
||||
|
||||
offset += sizeof(hbh);
|
||||
|
||||
while (offset < endOffset)
|
||||
for (; offset < endOffset; offset += option.GetSize())
|
||||
{
|
||||
Option option;
|
||||
IgnoreError(option.ParseFrom(aMessage, offset, endOffset));
|
||||
|
||||
IgnoreError(aMessage.Read(offset, option));
|
||||
|
||||
switch (option.GetType())
|
||||
if (option.IsPadding())
|
||||
{
|
||||
case MplOption::kType:
|
||||
// if multiple MPL options exist, discard packet
|
||||
continue;
|
||||
}
|
||||
|
||||
if (option.GetType() == MplOption::kType)
|
||||
{
|
||||
// If multiple MPL options exist, discard packet
|
||||
VerifyOrExit(mplOffset == 0, error = kErrorParse);
|
||||
|
||||
mplOffset = offset;
|
||||
@@ -361,31 +362,20 @@ Error Ip6::RemoveMplOption(Message &aMessage)
|
||||
|
||||
if (mplOffset == sizeof(ip6Header) + sizeof(hbh) && hbh.GetLength() == 0)
|
||||
{
|
||||
// first and only IPv6 Option, remove IPv6 HBH Option header
|
||||
// First and only IPv6 Option, remove IPv6 HBH Option header
|
||||
remove = true;
|
||||
}
|
||||
else if (mplOffset + 8 == endOffset)
|
||||
else if (mplOffset + ExtensionHeader::kLengthUnitSize == endOffset)
|
||||
{
|
||||
// last IPv6 Option, remove last 8 bytes
|
||||
// Last IPv6 Option, remove the last 8 bytes
|
||||
remove = true;
|
||||
}
|
||||
|
||||
offset += option.GetSize();
|
||||
break;
|
||||
|
||||
case Pad1Option::kType:
|
||||
offset += sizeof(Pad1Option);
|
||||
break;
|
||||
|
||||
case PadNOption::kType:
|
||||
offset += option.GetSize();
|
||||
break;
|
||||
|
||||
default:
|
||||
// encountered another option, now just replace MPL Option with PadN
|
||||
}
|
||||
else
|
||||
{
|
||||
// Encountered another option, now just replace
|
||||
// MPL Option with Pad Option
|
||||
remove = false;
|
||||
offset += option.GetSize();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -394,30 +384,33 @@ Error Ip6::RemoveMplOption(Message &aMessage)
|
||||
|
||||
if (remove)
|
||||
{
|
||||
// last IPv6 Option, shrink HBH Option header
|
||||
aMessage.RemoveHeader(endOffset - 8, 8);
|
||||
// Last IPv6 Option, shrink HBH Option header by
|
||||
// 8 bytes (`kLengthUnitSize`)
|
||||
aMessage.RemoveHeader(endOffset - ExtensionHeader::kLengthUnitSize, ExtensionHeader::kLengthUnitSize);
|
||||
|
||||
if (mplOffset == sizeof(ip6Header) + sizeof(hbh))
|
||||
{
|
||||
// remove entire HBH header
|
||||
// Remove entire HBH header
|
||||
ip6Header.SetNextHeader(hbh.GetNextHeader());
|
||||
}
|
||||
else
|
||||
{
|
||||
// update HBH header length
|
||||
// Update HBH header length, decrement by one
|
||||
// which decreases its total size by 8 bytes.
|
||||
|
||||
hbh.SetLength(hbh.GetLength() - 1);
|
||||
aMessage.Write(sizeof(ip6Header), hbh);
|
||||
}
|
||||
|
||||
ip6Header.SetPayloadLength(ip6Header.GetPayloadLength() - 8);
|
||||
ip6Header.SetPayloadLength(ip6Header.GetPayloadLength() - ExtensionHeader::kLengthUnitSize);
|
||||
aMessage.Write(0, ip6Header);
|
||||
}
|
||||
else if (mplOffset != 0)
|
||||
{
|
||||
// replace MPL Option with PadN Option
|
||||
PadNOption padOption;
|
||||
// Replace MPL Option with Pad Option
|
||||
PadOption padOption;
|
||||
|
||||
padOption.Init(sizeof(Option) + mplLength);
|
||||
padOption.InitForPadSize(sizeof(Option) + mplLength);
|
||||
aMessage.WriteBytes(mplOffset, &padOption, padOption.GetSize());
|
||||
}
|
||||
|
||||
@@ -529,57 +522,36 @@ Error Ip6::HandleOptions(Message &aMessage, Header &aHeader, bool aIsOutbound, b
|
||||
Error error = kErrorNone;
|
||||
HopByHopHeader hbhHeader;
|
||||
Option option;
|
||||
uint16_t offset = aMessage.GetOffset();
|
||||
uint16_t endOffset;
|
||||
|
||||
SuccessOrExit(error = aMessage.Read(aMessage.GetOffset(), hbhHeader));
|
||||
endOffset = aMessage.GetOffset() + hbhHeader.GetSize();
|
||||
SuccessOrExit(error = aMessage.Read(offset, hbhHeader));
|
||||
|
||||
endOffset = offset + hbhHeader.GetSize();
|
||||
VerifyOrExit(endOffset <= aMessage.GetLength(), error = kErrorParse);
|
||||
|
||||
aMessage.MoveOffset(sizeof(option));
|
||||
offset += sizeof(HopByHopHeader);
|
||||
|
||||
while (aMessage.GetOffset() < endOffset)
|
||||
for (; offset < endOffset; offset += option.GetSize())
|
||||
{
|
||||
SuccessOrExit(error = aMessage.Read(aMessage.GetOffset(), option));
|
||||
SuccessOrExit(error = option.ParseFrom(aMessage, offset, endOffset));
|
||||
|
||||
if (option.GetType() == Pad1Option::kType)
|
||||
if (option.IsPadding())
|
||||
{
|
||||
aMessage.MoveOffset(sizeof(Pad1Option));
|
||||
continue;
|
||||
}
|
||||
|
||||
VerifyOrExit(aMessage.GetOffset() + option.GetSize() <= endOffset, error = kErrorParse);
|
||||
|
||||
switch (option.GetType())
|
||||
if (option.GetType() == MplOption::kType)
|
||||
{
|
||||
case MplOption::kType:
|
||||
SuccessOrExit(error = mMpl.ProcessOption(aMessage, aHeader.GetSource(), aIsOutbound, aReceive));
|
||||
break;
|
||||
|
||||
default:
|
||||
switch (option.GetAction())
|
||||
{
|
||||
case Option::kActionSkip:
|
||||
break;
|
||||
|
||||
case Option::kActionDiscard:
|
||||
ExitNow(error = kErrorDrop);
|
||||
|
||||
case Option::kActionForceIcmp:
|
||||
// TODO: send icmp error
|
||||
ExitNow(error = kErrorDrop);
|
||||
|
||||
case Option::kActionIcmp:
|
||||
// TODO: send icmp error
|
||||
ExitNow(error = kErrorDrop);
|
||||
}
|
||||
|
||||
break;
|
||||
SuccessOrExit(error = mMpl.ProcessOption(aMessage, offset, aHeader.GetSource(), aIsOutbound, aReceive));
|
||||
continue;
|
||||
}
|
||||
|
||||
aMessage.MoveOffset(option.GetSize());
|
||||
VerifyOrExit(option.GetAction() == Option::kActionSkip, error = kErrorDrop);
|
||||
}
|
||||
|
||||
aMessage.SetOffset(offset);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -67,13 +67,66 @@ bool Header::IsValid(void) const
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// PadNOption
|
||||
// Option
|
||||
|
||||
void PadNOption::Init(uint8_t aPadLength)
|
||||
Error Option::ParseFrom(const Message &aMessage, uint16_t aOffset, uint16_t aEndOffset)
|
||||
{
|
||||
SetType(kType);
|
||||
SetLength(aPadLength - sizeof(Option));
|
||||
memset(mPad, kData, aPadLength - sizeof(Option));
|
||||
Error error;
|
||||
|
||||
// Read the Type first to check for the Pad1 Option.
|
||||
// If it is not, then we read the full `Option` header.
|
||||
|
||||
SuccessOrExit(error = aMessage.Read(aOffset, this, sizeof(mType)));
|
||||
|
||||
if (mType == kTypePad1)
|
||||
{
|
||||
SetLength(0);
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
SuccessOrExit(error = aMessage.Read(aOffset, *this));
|
||||
|
||||
VerifyOrExit(aOffset + GetSize() <= aEndOffset, error = kErrorParse);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t Option::GetSize(void) const
|
||||
{
|
||||
return (mType == kTypePad1) ? sizeof(mType) : static_cast<uint16_t>(mLength) + sizeof(Option);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// PadOption
|
||||
|
||||
void PadOption::InitForPadSize(uint8_t aPadSize)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(mPads);
|
||||
|
||||
Clear();
|
||||
|
||||
if (aPadSize == 1)
|
||||
{
|
||||
SetType(kTypePad1);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetType(kTypePadN);
|
||||
SetLength(aPadSize - sizeof(Option));
|
||||
}
|
||||
}
|
||||
|
||||
Error PadOption::InitToPadHeaderWithSize(uint16_t aHeaderSize)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
uint8_t size = static_cast<uint8_t>(aHeaderSize % ExtensionHeader::kLengthUnitSize);
|
||||
|
||||
VerifyOrExit(size != 0, error = kErrorAlready);
|
||||
InitForPadSize(ExtensionHeader::kLengthUnitSize - size);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
} // namespace Ip6
|
||||
|
||||
@@ -377,6 +377,14 @@ OT_TOOL_PACKED_BEGIN
|
||||
class ExtensionHeader
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This constant defines the size of Length unit in bytes.
|
||||
*
|
||||
* The Length field is in 8-bytes unit. The total size of `ExtensionHeader` MUST be a multiple of 8.
|
||||
*
|
||||
*/
|
||||
static constexpr uint16_t kLengthUnitSize = 8;
|
||||
|
||||
/**
|
||||
* This method returns the IPv6 Next Header value.
|
||||
*
|
||||
@@ -419,11 +427,9 @@ public:
|
||||
* @returns The size (number of bytes) of the Extension Header.
|
||||
*
|
||||
*/
|
||||
uint16_t GetSize(void) const { return kLengthUnitInBytes * (mLength + 1); }
|
||||
uint16_t GetSize(void) const { return kLengthUnitSize * (mLength + 1); }
|
||||
|
||||
private:
|
||||
static constexpr uint16_t kLengthUnitInBytes = 8;
|
||||
|
||||
// | m8[0] | m8[1] | m8[2] | m8[3] |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Next Header | Header Length | . . . |
|
||||
@@ -450,22 +456,6 @@ OT_TOOL_PACKED_BEGIN
|
||||
class Option
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This method returns the IPv6 Option Type value.
|
||||
*
|
||||
* @returns The IPv6 Option Type value.
|
||||
*
|
||||
*/
|
||||
uint8_t GetType(void) const { return mType; }
|
||||
|
||||
/**
|
||||
* This method sets the IPv6 Option Type value.
|
||||
*
|
||||
* @param[in] aType The IPv6 Option Type value.
|
||||
*
|
||||
*/
|
||||
void SetType(uint8_t aType) { mType = aType; }
|
||||
|
||||
/**
|
||||
* IPv6 Option Type actions for unrecognized IPv6 Options.
|
||||
*
|
||||
@@ -478,6 +468,23 @@ public:
|
||||
kActionIcmp = 0xc0, ///< Discard packet and conditionally send an ICMP Parameter Problem.
|
||||
};
|
||||
|
||||
/**
|
||||
* This method returns the IPv6 Option Type value.
|
||||
*
|
||||
* @returns The IPv6 Option Type value.
|
||||
*
|
||||
*/
|
||||
uint8_t GetType(void) const { return mType; }
|
||||
|
||||
/**
|
||||
* This method indicates whether IPv6 Option is padding (either Pad1 or PadN).
|
||||
*
|
||||
* @retval TRUE The Option is padding.
|
||||
* @retval FALSE The Option is not padding.
|
||||
*
|
||||
*/
|
||||
bool IsPadding(void) const { return (mType == kTypePad1) || (mType == kTypePadN); }
|
||||
|
||||
/**
|
||||
* This method returns the IPv6 Option action for unrecognized IPv6 Options.
|
||||
*
|
||||
@@ -494,6 +501,46 @@ public:
|
||||
*/
|
||||
uint8_t GetLength(void) const { return mLength; }
|
||||
|
||||
/**
|
||||
* This method returns the size (number of bytes) of the IPv6 Option.
|
||||
*
|
||||
* This method returns the proper size of the Option independent of its type, particularly if Option is Pad1 (which
|
||||
* does not follow the common Option header structure and has only Type field with no Length field). For other
|
||||
* Option types, the returned size includes the Type and Length fields.
|
||||
*
|
||||
* @returns The size of the Option.
|
||||
*
|
||||
*/
|
||||
uint16_t GetSize(void) const;
|
||||
|
||||
/**
|
||||
* This method parses and validates the IPv6 Option from a given message.
|
||||
*
|
||||
* The Option is read from @p aOffset in @p aMessage. This method then checks that the entire Option is present
|
||||
* in @p aMessage before the @p aEndOffset.
|
||||
*
|
||||
* @param[in] aMessage The IPv6 message.
|
||||
* @param[in] aOffset The offset in @p aMessage to read the IPv6 Option.
|
||||
* @param[in] aEndOffset The end offset in @p aMessage.
|
||||
*
|
||||
* @retval kErrorNone Successfully parsed the IPv6 option from @p aMessage.
|
||||
* @retval kErrorParse Malformed IPv6 Option or Option is not contained within @p aMessage by @p aEndOffset.
|
||||
*
|
||||
*/
|
||||
Error ParseFrom(const Message &aMessage, uint16_t aOffset, uint16_t aEndOffset);
|
||||
|
||||
protected:
|
||||
static constexpr uint8_t kTypePad1 = 0x00; ///< Pad1 Option Type.
|
||||
static constexpr uint8_t kTypePadN = 0x01; ///< PanN Option Type.
|
||||
|
||||
/**
|
||||
* This method sets the IPv6 Option Type value.
|
||||
*
|
||||
* @param[in] aType The IPv6 Option Type value.
|
||||
*
|
||||
*/
|
||||
void SetType(uint8_t aType) { mType = aType; }
|
||||
|
||||
/**
|
||||
* This method sets the IPv6 Option Length value.
|
||||
*
|
||||
@@ -502,14 +549,6 @@ public:
|
||||
*/
|
||||
void SetLength(uint8_t aLength) { mLength = aLength; }
|
||||
|
||||
/**
|
||||
* This method returns the size (number of bytes) of the IPv6 Option including the Type and Length fields.
|
||||
*
|
||||
* @returns The size of the Option.
|
||||
*
|
||||
*/
|
||||
uint16_t GetSize(void) const { return static_cast<uint16_t>(mLength) + sizeof(Option); }
|
||||
|
||||
private:
|
||||
static constexpr uint8_t kActionMask = 0xc0;
|
||||
|
||||
@@ -518,47 +557,45 @@ private:
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class implements IPv6 PadN Option generation and parsing.
|
||||
* This class implements IPv6 Pad Options (Pad1 or PadN) generation.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class PadNOption : public Option
|
||||
class PadOption : public Option, private Clearable<PadOption>
|
||||
{
|
||||
public:
|
||||
static constexpr uint8_t kType = 0x01; ///< PadN type
|
||||
static constexpr uint8_t kData = 0x00; ///< PadN specific data
|
||||
static constexpr uint8_t kMaxLength = 0x05; ///< Maximum length of PadN option data
|
||||
friend class Clearable<PadOption>;
|
||||
|
||||
public:
|
||||
/**
|
||||
* This method initializes the PadN header.
|
||||
* This method initializes the Pad Option for a given total Pad size.
|
||||
*
|
||||
* @param[in] aPadLength The length of needed padding. Allowed value from range 2-7.
|
||||
* The @p aPadSize MUST be from range 1-7. Otherwise the behavior of this method is undefined.
|
||||
*
|
||||
* @param[in] aPadSize The total number of needed padding bytes.
|
||||
*
|
||||
*/
|
||||
void Init(uint8_t aPadLength);
|
||||
|
||||
private:
|
||||
uint8_t mPad[kMaxLength];
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class implements IPv6 Pad1 Option generation and parsing. Pad1 does not follow default option header structure.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class Pad1Option
|
||||
{
|
||||
public:
|
||||
static constexpr uint8_t kType = 0x00;
|
||||
void InitForPadSize(uint8_t aPadSize);
|
||||
|
||||
/**
|
||||
* This method initializes the Pad1 header.
|
||||
* This method initializes the Pad Option for padding an IPv6 Extension header with a given current size.
|
||||
*
|
||||
* The Extension Header Length is in 8-bytes unit, so the total size should be a multiple of 8. This method
|
||||
* determines the Pad Option size needed for appending to Extension Header based on it current size @p aHeaderSize
|
||||
* so to make it a multiple of 8. This method returns `kErrorAlready` when the @p aHeaderSize is already
|
||||
* a multiple of 8 (i.e., no padding is needed).
|
||||
*
|
||||
* @param[in] aHeaderSize The current IPv6 Extension header size (in bytes).
|
||||
*
|
||||
* @retval kErrorNone The Pad Option is successfully initialized.
|
||||
* @retval kErrorAlready The @p aHeaderSize is already a multiple of 8 and no padding is needed.
|
||||
*
|
||||
*/
|
||||
void Init(void) { mType = kType; }
|
||||
Error InitToPadHeaderWithSize(uint16_t aHeaderSize);
|
||||
|
||||
private:
|
||||
uint8_t mType;
|
||||
static constexpr uint8_t kMaxLength = 5;
|
||||
|
||||
uint8_t mPads[kMaxLength];
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
|
||||
+28
-12
@@ -34,6 +34,7 @@
|
||||
#include "ip6_mpl.hpp"
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/debug.hpp"
|
||||
#include "common/instance.hpp"
|
||||
#include "common/locator_getters.hpp"
|
||||
#include "common/message.hpp"
|
||||
@@ -54,34 +55,49 @@ Mpl::Mpl(Instance &aInstance)
|
||||
memset(mSeedSet, 0, sizeof(mSeedSet));
|
||||
}
|
||||
|
||||
void MplOption::Init(SeedIdLength aSeedIdLength)
|
||||
{
|
||||
SetType(kType);
|
||||
|
||||
switch (aSeedIdLength)
|
||||
{
|
||||
case kSeedIdLength0:
|
||||
SetLength(sizeof(*this) - sizeof(Option) - sizeof(mSeedId));
|
||||
break;
|
||||
case kSeedIdLength2:
|
||||
SetLength(sizeof(*this) - sizeof(Option));
|
||||
break;
|
||||
default:
|
||||
OT_ASSERT(false);
|
||||
}
|
||||
|
||||
mControl = aSeedIdLength;
|
||||
}
|
||||
|
||||
void Mpl::InitOption(MplOption &aOption, const Address &aAddress)
|
||||
{
|
||||
aOption.Init();
|
||||
aOption.SetSequence(mSequence++);
|
||||
|
||||
// Seed ID can be elided when `aAddress` is RLOC.
|
||||
if (aAddress == Get<Mle::Mle>().GetMeshLocal16())
|
||||
{
|
||||
aOption.SetSeedIdLength(MplOption::kSeedIdLength0);
|
||||
|
||||
// Decrease default option length.
|
||||
aOption.SetLength(aOption.GetLength() - sizeof(uint16_t));
|
||||
// Seed ID can be elided when `aAddress` is RLOC.
|
||||
aOption.Init(MplOption::kSeedIdLength0);
|
||||
}
|
||||
else
|
||||
{
|
||||
aOption.SetSeedIdLength(MplOption::kSeedIdLength2);
|
||||
aOption.Init(MplOption::kSeedIdLength2);
|
||||
aOption.SetSeedId(Get<Mle::Mle>().GetRloc16());
|
||||
}
|
||||
|
||||
aOption.SetSequence(mSequence++);
|
||||
}
|
||||
|
||||
Error Mpl::ProcessOption(Message &aMessage, const Address &aAddress, bool aIsOutbound, bool &aReceive)
|
||||
Error Mpl::ProcessOption(Message &aMessage, uint16_t aOffset, const Address &aAddress, bool aIsOutbound, bool &aReceive)
|
||||
{
|
||||
Error error;
|
||||
MplOption option;
|
||||
|
||||
// Read the min size bytes first, then check the expected
|
||||
// `SeedIdLength` and read the full `MplOption` if needed.
|
||||
SuccessOrExit(error = aMessage.Read(aMessage.GetOffset(), &option, MplOption::kMinSize));
|
||||
SuccessOrExit(error = aMessage.Read(aOffset, &option, MplOption::kMinSize));
|
||||
|
||||
switch (option.GetSeedIdLength())
|
||||
{
|
||||
@@ -92,7 +108,7 @@ Error Mpl::ProcessOption(Message &aMessage, const Address &aAddress, bool aIsOut
|
||||
break;
|
||||
|
||||
case MplOption::kSeedIdLength2:
|
||||
SuccessOrExit(error = aMessage.Read(aMessage.GetOffset(), option));
|
||||
SuccessOrExit(error = aMessage.Read(aOffset, option));
|
||||
break;
|
||||
|
||||
case MplOption::kSeedIdLength8:
|
||||
|
||||
+13
-24
@@ -68,18 +68,7 @@ public:
|
||||
static constexpr uint8_t kMinSize = (2 + sizeof(Option)); ///< Minimum size (num of bytes) of `MplOption`
|
||||
|
||||
/**
|
||||
* This method initializes the MPL header.
|
||||
*
|
||||
*/
|
||||
void Init(void)
|
||||
{
|
||||
SetType(kType);
|
||||
SetLength(sizeof(*this) - sizeof(Option));
|
||||
mControl = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* MPL Seed Id lengths.
|
||||
* MPL Seed Id Lengths.
|
||||
*
|
||||
*/
|
||||
enum SeedIdLength : uint8_t
|
||||
@@ -90,6 +79,16 @@ public:
|
||||
kSeedIdLength16 = 3 << 6, ///< 16-byte MPL Seed Id Length.
|
||||
};
|
||||
|
||||
/**
|
||||
* This method initializes the MPL Option.
|
||||
*
|
||||
* The @p aSeedIdLength MUST be either `kSeedIdLength0` or `kSeedIdLength2`. Other values are not supported.
|
||||
*
|
||||
* @param[in] aSeedIdLength The MPL Seed Id Length.
|
||||
*
|
||||
*/
|
||||
void Init(SeedIdLength aSeedIdLength);
|
||||
|
||||
/**
|
||||
* This method returns the MPL Seed Id Length value.
|
||||
*
|
||||
@@ -98,17 +97,6 @@ public:
|
||||
*/
|
||||
SeedIdLength GetSeedIdLength(void) const { return static_cast<SeedIdLength>(mControl & kSeedIdLengthMask); }
|
||||
|
||||
/**
|
||||
* This method sets the MPL Seed Id Length value.
|
||||
*
|
||||
* @param[in] aSeedIdLength The MPL Seed Length.
|
||||
*
|
||||
*/
|
||||
void SetSeedIdLength(SeedIdLength aSeedIdLength)
|
||||
{
|
||||
mControl = static_cast<uint8_t>((mControl & ~kSeedIdLengthMask) | aSeedIdLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the MPL M flag is set.
|
||||
*
|
||||
@@ -204,6 +192,7 @@ public:
|
||||
* timer expirations for subsequent retransmissions.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message.
|
||||
* @param[in] aOffset The offset in @p aMessage to read the MPL option.
|
||||
* @param[in] aAddress A reference to the IPv6 Source Address.
|
||||
* @param[in] aIsOutbound TRUE if this message was locally generated, FALSE otherwise.
|
||||
* @param[out] aReceive Set to FALSE if the MPL message is a duplicate and must not
|
||||
@@ -213,7 +202,7 @@ public:
|
||||
* @retval kErrorDrop The MPL message is a duplicate and should be dropped.
|
||||
*
|
||||
*/
|
||||
Error ProcessOption(Message &aMessage, const Address &aAddress, bool aIsOutbound, bool &aReceive);
|
||||
Error ProcessOption(Message &aMessage, uint16_t aOffset, const Address &aAddress, bool aIsOutbound, bool &aReceive);
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
/**
|
||||
|
||||
+14
-46
@@ -473,37 +473,20 @@ Error Lowpan::CompressExtensionHeader(Message &aMessage, FrameBuilder &aFrameBui
|
||||
if (aNextHeader == Ip6::kProtoHopOpts || aNextHeader == Ip6::kProtoDstOpts)
|
||||
{
|
||||
uint16_t offset = aMessage.GetOffset();
|
||||
uint16_t endOffset = offset + len;
|
||||
bool hasOption = false;
|
||||
Ip6::Option option;
|
||||
|
||||
while ((offset - aMessage.GetOffset()) < len)
|
||||
for (; offset < endOffset; offset += option.GetSize())
|
||||
{
|
||||
SuccessOrExit(error = aMessage.Read(offset, option));
|
||||
|
||||
if (option.GetType() == Ip6::Pad1Option::kType)
|
||||
{
|
||||
offset += sizeof(Ip6::Pad1Option);
|
||||
}
|
||||
else
|
||||
{
|
||||
offset += option.GetSize();
|
||||
}
|
||||
|
||||
SuccessOrExit(error = option.ParseFrom(aMessage, offset, endOffset));
|
||||
hasOption = true;
|
||||
}
|
||||
|
||||
if (hasOption)
|
||||
// Check if the last option can be compressed.
|
||||
if (hasOption && option.IsPadding())
|
||||
{
|
||||
// Check if the last option can be compressed.
|
||||
if (option.GetType() == Ip6::Pad1Option::kType)
|
||||
{
|
||||
padLength = sizeof(Ip6::Pad1Option);
|
||||
}
|
||||
else if (option.GetType() == Ip6::PadNOption::kType)
|
||||
{
|
||||
padLength = option.GetSize();
|
||||
}
|
||||
|
||||
padLength = option.GetSize();
|
||||
len -= padLength;
|
||||
}
|
||||
}
|
||||
@@ -850,11 +833,11 @@ exit:
|
||||
|
||||
Error Lowpan::DecompressExtensionHeader(Message &aMessage, FrameData &aFrameData)
|
||||
{
|
||||
Error error = kErrorParse;
|
||||
uint8_t hdr[2];
|
||||
uint8_t len;
|
||||
uint8_t ctl;
|
||||
uint8_t padLength;
|
||||
Error error = kErrorParse;
|
||||
uint8_t hdr[2];
|
||||
uint8_t len;
|
||||
uint8_t ctl;
|
||||
Ip6::PadOption padOption;
|
||||
|
||||
SuccessOrExit(aFrameData.ReadUint8(ctl));
|
||||
|
||||
@@ -888,26 +871,11 @@ Error Lowpan::DecompressExtensionHeader(Message &aMessage, FrameData &aFrameData
|
||||
// The RFC6282 says: "The trailing Pad1 or PadN option MAY be elided by the compressor.
|
||||
// A decompressor MUST ensure that the containing header is padded out to a multiple of 8 octets
|
||||
// in length, using a Pad1 or PadN option if necessary."
|
||||
padLength = 8 - ((len + sizeof(hdr)) & 0x07);
|
||||
|
||||
if (padLength != 8)
|
||||
if (padOption.InitToPadHeaderWithSize(len + sizeof(hdr)) == kErrorNone)
|
||||
{
|
||||
if (padLength == 1)
|
||||
{
|
||||
Ip6::Pad1Option pad1;
|
||||
|
||||
pad1.Init();
|
||||
SuccessOrExit(aMessage.AppendBytes(&pad1, padLength));
|
||||
}
|
||||
else
|
||||
{
|
||||
Ip6::PadNOption padn;
|
||||
|
||||
padn.Init(padLength);
|
||||
SuccessOrExit(aMessage.AppendBytes(&padn, padLength));
|
||||
}
|
||||
|
||||
aMessage.MoveOffset(padLength);
|
||||
SuccessOrExit(aMessage.AppendBytes(&padOption, padOption.GetSize()));
|
||||
aMessage.MoveOffset(padOption.GetSize());
|
||||
}
|
||||
|
||||
error = kErrorNone;
|
||||
|
||||
Reference in New Issue
Block a user