diff --git a/src/core/net/ip6.cpp b/src/core/net/ip6.cpp index 6646a820e..e4b774130 100644 --- a/src/core/net/ip6.cpp +++ b/src/core/net/ip6.cpp @@ -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; } diff --git a/src/core/net/ip6_headers.cpp b/src/core/net/ip6_headers.cpp index 9406adf33..ff9585f6f 100644 --- a/src/core/net/ip6_headers.cpp +++ b/src/core/net/ip6_headers.cpp @@ -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(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(aHeaderSize % ExtensionHeader::kLengthUnitSize); + + VerifyOrExit(size != 0, error = kErrorAlready); + InitForPadSize(ExtensionHeader::kLengthUnitSize - size); + +exit: + return error; } } // namespace Ip6 diff --git a/src/core/net/ip6_headers.hpp b/src/core/net/ip6_headers.hpp index 47c5b339d..bb2ba1065 100644 --- a/src/core/net/ip6_headers.hpp +++ b/src/core/net/ip6_headers.hpp @@ -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(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 { -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; +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; /** diff --git a/src/core/net/ip6_mpl.cpp b/src/core/net/ip6_mpl.cpp index 9e2408f40..f39d83300 100644 --- a/src/core/net/ip6_mpl.cpp +++ b/src/core/net/ip6_mpl.cpp @@ -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().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().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: diff --git a/src/core/net/ip6_mpl.hpp b/src/core/net/ip6_mpl.hpp index bd66ffdc8..60fd6686f 100644 --- a/src/core/net/ip6_mpl.hpp +++ b/src/core/net/ip6_mpl.hpp @@ -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(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((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 /** diff --git a/src/core/thread/lowpan.cpp b/src/core/thread/lowpan.cpp index f4938cc33..a31519b3a 100644 --- a/src/core/thread/lowpan.cpp +++ b/src/core/thread/lowpan.cpp @@ -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;