From 07cfc9a7d194eae4c3b143d6d59e768a8d8a3375 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 18 Aug 2020 18:49:23 -0700 Subject: [PATCH] [ip6] simplify `Ip6:Header` and misc. enhancements (#5413) This commit contain a list of smaller enhancements in `Ip6` modules: - Simplify `Ip6::Header` removing the PoD definition and providing `enum` constants for the byte offset to different fields in the header (replacing/removing static methods). - Declare some of the `Ip6` methods as `private`. - Remove error logs (not used/applicable anymore). - Simplify checking of `destPort` in `ProcessReceiveCallback()`. - Specify `int` size of `enum` definitions (declare internally-used `enum`s a `private`). - Add unit test `TestIp6Header()`. --- src/core/net/ip6.cpp | 134 +++++++++++-------------- src/core/net/ip6.hpp | 82 +++++++-------- src/core/net/ip6_headers.hpp | 124 +++++++++-------------- src/core/net/ip6_mpl.cpp | 4 +- src/core/thread/lowpan.cpp | 2 +- src/core/thread/mesh_forwarder_ftd.cpp | 2 +- tests/unit/test_ip6_address.cpp | 60 +++++++++++ 7 files changed, 206 insertions(+), 202 deletions(-) diff --git a/src/core/net/ip6.cpp b/src/core/net/ip6.cpp index d85dfb13e..0fd12dbe5 100644 --- a/src/core/net/ip6.cpp +++ b/src/core/net/ip6.cpp @@ -458,11 +458,10 @@ void Ip6::EnqueueDatagram(Message &aMessage) otError Ip6::SendDatagram(Message &aMessage, MessageInfo &aMessageInfo, uint8_t aIpProto) { - otError error = OT_ERROR_NONE; - Header header; - uint16_t payloadLength = aMessage.GetLength(); - uint16_t checksum; - const NetifUnicastAddress *source; + otError error = OT_ERROR_NONE; + Header header; + uint16_t payloadLength = aMessage.GetLength(); + uint16_t checksum; header.Init(); header.SetDscp(PriorityToDscp(aMessage.GetPriority())); @@ -480,7 +479,9 @@ otError Ip6::SendDatagram(Message &aMessage, MessageInfo &aMessageInfo, uint8_t if (aMessageInfo.GetSockAddr().IsUnspecified() || aMessageInfo.GetSockAddr().IsMulticast()) { - VerifyOrExit((source = SelectSourceAddress(aMessageInfo)) != nullptr, error = OT_ERROR_INVALID_SOURCE_ADDRESS); + const NetifUnicastAddress *source = SelectSourceAddress(aMessageInfo); + + VerifyOrExit(source != nullptr, error = OT_ERROR_INVALID_SOURCE_ADDRESS); header.SetSource(source->GetAddress()); } else @@ -497,7 +498,6 @@ otError Ip6::SendDatagram(Message &aMessage, MessageInfo &aMessageInfo, uint8_t SuccessOrExit(error = aMessage.Prepend(&header, sizeof(header))); - // compute checksum checksum = ComputePseudoheaderChecksum(header.GetSource(), header.GetDestination(), payloadLength, aIpProto); switch (aIpProto) @@ -519,9 +519,9 @@ otError Ip6::SendDatagram(Message &aMessage, MessageInfo &aMessageInfo, uint8_t #if OPENTHREAD_FTD if (Get().HasSleepyChildWithAddress(header.GetDestination())) { - Message *messageCopy = nullptr; + Message *messageCopy = aMessage.Clone(); - if ((messageCopy = aMessage.Clone()) != nullptr) + if (messageCopy != nullptr) { otLogInfoIp6("Message copy for indirect transmission to sleepy children"); EnqueueDatagram(*messageCopy); @@ -536,19 +536,16 @@ otError Ip6::SendDatagram(Message &aMessage, MessageInfo &aMessageInfo, uint8_t SuccessOrExit(error = AddTunneledMplOption(aMessage, header, aMessageInfo)); } -exit: - - if (error == OT_ERROR_NONE) + if (aMessage.GetLength() > kMaxDatagramLength) { - if (aMessage.GetLength() > kMaxDatagramLength) - { - error = FragmentDatagram(aMessage, aIpProto); - } - else - { - EnqueueDatagram(aMessage); - } + error = FragmentDatagram(aMessage, aIpProto); } + else + { + EnqueueDatagram(aMessage); + } + +exit: return error; } @@ -844,13 +841,12 @@ exit: void Ip6::CleanupFragmentationBuffer(void) { - for (Message *message = mReassemblyList.GetHead(); message;) - { - Message *next = message->GetNext(); + Message *message; + while ((message = mReassemblyList.GetHead()) != nullptr) + { mReassemblyList.Dequeue(*message); message->Free(); - message = next; } } @@ -1010,13 +1006,16 @@ otError Ip6::HandlePayload(Message &aMessage, MessageInfo &aMessageInfo, uint8_t { otLogNoteIp6("Error UDP Checksum"); } - ExitNow(); + break; case kProtoIcmp6: - ExitNow(error = mIcmp.HandleMessage(aMessage, aMessageInfo)); + error = mIcmp.HandleMessage(aMessage, aMessageInfo); + break; + + default: + break; } -exit: return error; } @@ -1025,8 +1024,8 @@ otError Ip6::ProcessReceiveCallback(const Message & aMessage, uint8_t aIpProto, bool aFromNcpHost) { - otError error = OT_ERROR_NONE; - Message *messageCopy = nullptr; + otError error = OT_ERROR_NONE; + Message *messageCopy; VerifyOrExit(!aFromNcpHost, error = OT_ERROR_NO_ROUTE); VerifyOrExit(mReceiveIp6DatagramCallback != nullptr, error = OT_ERROR_NO_ROUTE); @@ -1058,42 +1057,32 @@ otError Ip6::ProcessReceiveCallback(const Message & aMessage, case kProtoUdp: { Udp::Header udp; + uint16_t destPort; + aMessage.Read(aMessage.GetOffset(), sizeof(udp), &udp); - switch (udp.GetDestinationPort()) + destPort = udp.GetDestinationPort(); + + if ((destPort == Mle::kUdpPort) && + (aMessageInfo.GetSockAddr().IsLinkLocal() || aMessageInfo.GetSockAddr().IsLinkLocalMulticast())) { - case Mle::kUdpPort: - // do not pass MLE messages - if (aMessageInfo.GetSockAddr().IsLinkLocal() || aMessageInfo.GetSockAddr().IsLinkLocalMulticast()) - { - ExitNow(error = OT_ERROR_NO_ROUTE); - } - - break; - -#if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE == 0 - case kCoapUdpPort: - - // do not pass TMF messages - if (Get().IsTmfMessage(aMessageInfo)) - { - ExitNow(error = OT_ERROR_NO_ROUTE); - } - - break; -#endif // OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE - - default: -#if OPENTHREAD_FTD - if (udp.GetDestinationPort() == Get().GetJoinerUdpPort()) - { - ExitNow(error = OT_ERROR_NO_ROUTE); - } -#endif - break; + ExitNow(error = OT_ERROR_NO_ROUTE); } +#if !OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE + else if ((destPort == kCoapUdpPort) && Get().IsTmfMessage(aMessageInfo)) + { + // do not pass TMF messages + ExitNow(error = OT_ERROR_NO_ROUTE); + } +#endif +#if OPENTHREAD_FTD + if (destPort == Get().GetJoinerUdpPort()) + { + ExitNow(error = OT_ERROR_NO_ROUTE); + } +#endif break; } @@ -1103,26 +1092,18 @@ otError Ip6::ProcessReceiveCallback(const Message & aMessage, } // make a copy of the datagram to pass to host - VerifyOrExit((messageCopy = aMessage.Clone()) != nullptr, error = OT_ERROR_NO_BUFS); + messageCopy = aMessage.Clone(); + + if (messageCopy == nullptr) + { + otLogWarnIp6("Failed to pass up message (len: %d) to host - out of message buffer.", aMessage.GetLength()); + ExitNow(error = OT_ERROR_NO_BUFS); + } + IgnoreError(RemoveMplOption(*messageCopy)); mReceiveIp6DatagramCallback(messageCopy, mReceiveIp6DatagramCallbackContext); exit: - - switch (error) - { - case OT_ERROR_NO_BUFS: - otLogWarnIp6("Failed to pass up message (len: %d) to host - out of message buffer.", aMessage.GetLength()); - break; - - case OT_ERROR_DROP: - otLogNoteIp6("Dropping message (len: %d) from local host since next hop is the host.", aMessage.GetLength()); - break; - - default: - break; - } - return error; } @@ -1138,7 +1119,6 @@ otError Ip6::SendRaw(Message &aMessage) messageInfo.SetPeerAddr(header.GetSource()); messageInfo.SetSockAddr(header.GetDestination()); messageInfo.SetHopLimit(header.GetHopLimit()); - messageInfo.SetLinkInfo(nullptr); if (header.GetDestination().IsMulticast()) { @@ -1292,7 +1272,7 @@ otError Ip6::HandleDatagram(Message &aMessage, Netif *aNetif, const void *aLinkM else { hopLimit = header.GetHopLimit(); - aMessage.Write(Header::GetHopLimitOffset(), Header::GetHopLimitSize(), &hopLimit); + aMessage.Write(Header::kHopLimitFieldOffset, sizeof(hopLimit), &hopLimit); #if OPENTHREAD_CONFIG_UNSECURE_TRAFFIC_MANAGED_BY_STACK_ENABLE // check whether source port is an unsecure port diff --git a/src/core/net/ip6.hpp b/src/core/net/ip6.hpp index 7a5fd90b4..4f66d2a92 100644 --- a/src/core/net/ip6.hpp +++ b/src/core/net/ip6.hpp @@ -102,18 +102,32 @@ using ot::Encoding::BigEndian::HostSwap32; class Ip6 : public InstanceLocator, private NonCopyable { friend class ot::Instance; + friend class Mpl; public: - enum + enum : uint16_t { - kDefaultHopLimit = OPENTHREAD_CONFIG_IP6_HOP_LIMIT_DEFAULT, - kMaxDatagramLength = OPENTHREAD_CONFIG_IP6_MAX_DATAGRAM_LENGTH, + /** + * The max datagram length (in bytes) of an IPv6 message. + * + */ + kMaxDatagramLength = OPENTHREAD_CONFIG_IP6_MAX_DATAGRAM_LENGTH, + + /** + * The max datagram length (in bytes) of an unfragmented IPv6 message. + * + */ kMaxAssembledDatagramLength = OPENTHREAD_CONFIG_IP6_MAX_ASSEMBLED_DATAGRAM, - kIp6ReassemblyTimeout = OPENTHREAD_CONFIG_IP6_REASSEMBLY_TIMEOUT, - kMinimalMtu = 1280, - kStateUpdatePeriod = 1000, }; + /** + * This constructor initializes the object. + * + * @param[in] aInstance A reference to the otInstance object. + * + */ + explicit Ip6(Instance &aInstance); + /** * This method allocates a new message buffer from the buffer pool. * @@ -152,16 +166,6 @@ public: */ Message *NewMessage(const uint8_t *aData, uint16_t aDataLength); - /** - * This method converts the message priority level to IPv6 DSCP value. - * - * @param[in] aPriority The message priority level. - * - * @returns The IPv6 DSCP value. - * - */ - static uint8_t PriorityToDscp(Message::Priority aPriority); - /** * This method converts the IPv6 DSCP value to message priority level. * @@ -172,14 +176,6 @@ public: */ static Message::Priority DscpToPriority(uint8_t aDscp); - /** - * This constructor initializes the object. - * - * @param[in] aInstance A reference to the otInstance object. - * - */ - explicit Ip6(Instance &aInstance); - /** * This method sends an IPv6 datagram. * @@ -227,24 +223,6 @@ public: */ otError HandleDatagram(Message &aMessage, Netif *aNetif, const void *aLinkMessageInfo, bool aFromNcpHost); - /** - * This methods adds a full IPv6 packet to the transmit queue. - * - * @param aMessage A reference to the message. - */ - void EnqueueDatagram(Message &aMessage); - - /** - * This static method updates a checksum. - * - * @param[in] aChecksum The checksum value to update. - * @param[in] aAddress A reference to an IPv6 address. - * - * @returns The updated checksum. - * - */ - static uint16_t UpdateChecksum(uint16_t aChecksum, const Address &aAddress); - /** * This static method computes the pseudoheader checksum. * @@ -344,16 +322,30 @@ public: static const char *IpProtoToString(uint8_t aIpProto); private: - enum + enum : uint8_t { - kDefaultIp6MessagePriority = Message::kPriorityNormal, + kDefaultHopLimit = OPENTHREAD_CONFIG_IP6_HOP_LIMIT_DEFAULT, + kIp6ReassemblyTimeout = OPENTHREAD_CONFIG_IP6_REASSEMBLY_TIMEOUT, + }; + + enum : uint16_t + { + kMinimalMtu = 1280, + }; + + enum : uint32_t + { + kStateUpdatePeriod = 1000, }; static void HandleSendQueue(Tasklet &aTasklet); void HandleSendQueue(void); - static otError GetDatagramPriority(const uint8_t *aData, uint16_t aDataLen, Message::Priority &aPriority); + static uint8_t PriorityToDscp(Message::Priority aPriority); + static otError GetDatagramPriority(const uint8_t *aData, uint16_t aDataLen, Message::Priority &aPriority); + static uint16_t UpdateChecksum(uint16_t aChecksum, const Address &aAddress); + void EnqueueDatagram(Message &aMessage); otError ProcessReceiveCallback(const Message & aMessage, const MessageInfo &aMessageInfo, uint8_t aIpProto, diff --git a/src/core/net/ip6_headers.hpp b/src/core/net/ip6_headers.hpp index 5a1f750a5..ed70339da 100644 --- a/src/core/net/ip6_headers.hpp +++ b/src/core/net/ip6_headers.hpp @@ -117,54 +117,34 @@ enum IpDscpCs kDscpCsMask = 0x38, ///< Class selector mask }; -enum -{ - kVersionClassFlowSize = 4, ///< Combined size of Version, Class, Flow Label in bytes. -}; - -/** - * This structure represents an IPv6 header. - * - */ -OT_TOOL_PACKED_BEGIN -struct HeaderPoD -{ - union OT_TOOL_PACKED_FIELD - { - uint8_t m8[kVersionClassFlowSize / sizeof(uint8_t)]; - uint16_t m16[kVersionClassFlowSize / sizeof(uint16_t)]; - uint32_t m32[kVersionClassFlowSize / sizeof(uint32_t)]; - } mVersionClassFlow; ///< Version, Class, Flow Label - uint16_t mPayloadLength; ///< Payload Length - uint8_t mNextHeader; ///< Next Header - uint8_t mHopLimit; ///< Hop Limit - otIp6Address mSource; ///< Source - otIp6Address mDestination; ///< Destination -} OT_TOOL_PACKED_END; - /** * This class implements IPv6 header generation and parsing. * */ OT_TOOL_PACKED_BEGIN -class Header : private HeaderPoD +class Header { public: + enum : uint8_t + { + kPayloadLengthFieldOffset = 4, ///< The byte offset of Payload Length field in IPv6 header. + kNextHeaderFieldOffset = 6, ///< The byte offset of Next Header field in IPv6 header. + kHopLimitFieldOffset = 7, ///< The byte offset of Hop Limit field in IPv6 header. + kSourceFieldOffset = 8, ///< The byte offset of Source Address field in IPv6 header. + kDestinationFieldOffset = 24, ///< The byte offset of Destination Address field in IPv6 header. + }; + /** * This method initializes the IPv6 header. * */ - void Init(void) - { - mVersionClassFlow.m32[0] = 0; - mVersionClassFlow.m8[0] = kVersion6; - } + void Init(void) { mVersionClassFlow.m32 = HostSwap32(kVersionClassFlowInit); } /** * This method initializes the IPv6 header and sets Version, Traffic Control and Flow Label fields. * */ - void Init(uint32_t aVersionClassFlow) { mVersionClassFlow.m32[0] = HostSwap32(aVersionClassFlow); } + void Init(uint32_t aVersionClassFlow) { mVersionClassFlow.m32 = HostSwap32(aVersionClassFlow); } /** * This method reads the IPv6 header from @p aMessage. @@ -203,7 +183,7 @@ public: */ uint8_t GetDscp(void) const { - return static_cast((HostSwap32(mVersionClassFlow.m32[0]) & kDscpMask) >> kDscpOffset); + return static_cast((HostSwap16(mVersionClassFlow.m16[0]) & kDscpMask) >> kDscpOffset); } /** @@ -214,9 +194,8 @@ public: */ void SetDscp(uint8_t aDscp) { - uint32_t tmp = HostSwap32(mVersionClassFlow.m32[0]); - tmp = (tmp & static_cast(~kDscpMask)) | ((static_cast(aDscp) << kDscpOffset) & kDscpMask); - mVersionClassFlow.m32[0] = HostSwap32(tmp); + mVersionClassFlow.m16[0] = HostSwap16((HostSwap16(mVersionClassFlow.m16[0]) & ~kDscpMask) | + ((static_cast(aDscp) << kDscpOffset) & kDscpMask)); } /** @@ -273,7 +252,7 @@ public: * @returns A reference to the IPv6 Source address. * */ - Address &GetSource(void) { return static_cast
(mSource); } + Address &GetSource(void) { return mSource; } /** * This method sets the IPv6 Source address. @@ -289,7 +268,7 @@ public: * @returns A reference to the IPv6 Destination address. * */ - Address &GetDestination(void) { return static_cast
(mDestination); } + Address &GetDestination(void) { return mDestination; } /** * This method sets the IPv6 Destination address. @@ -299,46 +278,35 @@ public: */ void SetDestination(const Address &aDestination) { mDestination = aDestination; } - /** - * This static method returns the byte offset of the IPv6 Payload Length field. - * - * @returns The byte offset of the IPv6 Payload Length field. - * - */ - static uint8_t GetPayloadLengthOffset(void) { return offsetof(HeaderPoD, mPayloadLength); } - - /** - * This static method returns the byte offset of the IPv6 Hop Limit field. - * - * @returns The byte offset of the IPv6 Hop Limit field. - * - */ - static uint8_t GetHopLimitOffset(void) { return offsetof(HeaderPoD, mHopLimit); } - - /** - * This static method returns the size of the IPv6 Hop Limit field. - * - * @returns The size of the IPv6 Hop Limit field. - * - */ - static uint8_t GetHopLimitSize(void) { return sizeof(uint8_t); } - - /** - * This static method returns the byte offset of the IPv6 Destination field. - * - * @returns The byte offset of the IPv6 Destination field. - * - */ - static uint8_t GetDestinationOffset(void) { return offsetof(HeaderPoD, mDestination); } - private: - enum + enum : uint8_t { kVersion6 = 0x60, - kVersionMask = 0xf0, - kDscpOffset = 22, - kDscpMask = 0xfc00000, + kVersionMask = 0xf0, // To use with `mVersionClassFlow.m8[0]` + kDscpOffset = 6, // To use with `mVersionClassFlow.m16[0]` }; + + enum : uint16_t + { + kDscpMask = 0x0fc0, // To use with `mVersionClassFlow.m16[0]` + }; + + enum : uint32_t + { + kVersionClassFlowInit = 0x60000000, // Version 6, TC and flow zero. + }; + + union OT_TOOL_PACKED_FIELD + { + uint8_t m8[sizeof(uint32_t) / sizeof(uint8_t)]; + uint16_t m16[sizeof(uint32_t) / sizeof(uint16_t)]; + uint32_t m32; + } mVersionClassFlow; + uint16_t mPayloadLength; + uint8_t mNextHeader; + uint8_t mHopLimit; + Address mSource; + Address mDestination; } OT_TOOL_PACKED_END; /** @@ -433,13 +401,12 @@ public: * IPv6 Option Type actions for unrecognized IPv6 Options. * */ - enum Action + enum Action : uint8_t { kActionSkip = 0x00, ///< skip over this option and continue processing the header kActionDiscard = 0x40, ///< discard the packet kActionForceIcmp = 0x80, ///< discard the packet and forcibly send an ICMP Parameter Problem kActionIcmp = 0xc0, ///< discard packet and conditionally send an ICMP Parameter Problem - kActionMask = 0xc0, ///< mask for action bits }; /** @@ -467,6 +434,11 @@ public: void SetLength(uint8_t aLength) { mLength = aLength; } private: + enum : uint8_t + { + kActionMask = 0xc0, + }; + uint8_t mType; uint8_t mLength; } OT_TOOL_PACKED_END; diff --git a/src/core/net/ip6_mpl.cpp b/src/core/net/ip6_mpl.cpp index 5ab0f417b..91c7feb6f 100644 --- a/src/core/net/ip6_mpl.cpp +++ b/src/core/net/ip6_mpl.cpp @@ -314,9 +314,9 @@ void Mpl::AddBufferedMessage(Message &aMessage, uint16_t aSeedId, uint8_t aSeque if (!aIsOutbound) { - aMessage.Read(Header::GetHopLimitOffset(), Header::GetHopLimitSize(), &hopLimit); + aMessage.Read(Header::kHopLimitFieldOffset, sizeof(hopLimit), &hopLimit); VerifyOrExit(hopLimit-- > 1, error = OT_ERROR_DROP); - messageCopy->Write(Header::GetHopLimitOffset(), Header::GetHopLimitSize(), &hopLimit); + messageCopy->Write(Header::kHopLimitFieldOffset, sizeof(hopLimit), &hopLimit); } metadata.mSeedId = aSeedId; diff --git a/src/core/thread/lowpan.cpp b/src/core/thread/lowpan.cpp index b32ae7de9..ffe629973 100644 --- a/src/core/thread/lowpan.cpp +++ b/src/core/thread/lowpan.cpp @@ -1177,7 +1177,7 @@ int Lowpan::Decompress(Message & aMessage, HostSwap16(aMessage.GetOffset() - currentOffset - sizeof(Ip6::Header) + aBufLength - compressedLength); } - aMessage.Write(currentOffset + Ip6::Header::GetPayloadLengthOffset(), sizeof(ip6PayloadLength), &ip6PayloadLength); + aMessage.Write(currentOffset + Ip6::Header::kPayloadLengthFieldOffset, sizeof(ip6PayloadLength), &ip6PayloadLength); error = OT_ERROR_NONE; diff --git a/src/core/thread/mesh_forwarder_ftd.cpp b/src/core/thread/mesh_forwarder_ftd.cpp index ab8aee021..5a0a23c98 100644 --- a/src/core/thread/mesh_forwarder_ftd.cpp +++ b/src/core/thread/mesh_forwarder_ftd.cpp @@ -150,7 +150,7 @@ void MeshForwarder::HandleResolved(const Ip6::Address &aEid, otError aError) continue; } - cur->Read(Ip6::Header::GetDestinationOffset(), sizeof(ip6Dst), &ip6Dst); + cur->Read(Ip6::Header::kDestinationFieldOffset, sizeof(ip6Dst), &ip6Dst); if (ip6Dst == aEid) { diff --git a/tests/unit/test_ip6_address.cpp b/tests/unit/test_ip6_address.cpp index db4f39908..e4a3615f7 100644 --- a/tests/unit/test_ip6_address.cpp +++ b/tests/unit/test_ip6_address.cpp @@ -28,10 +28,14 @@ #include +#include "common/encoding.hpp" #include "net/ip6_address.hpp" +#include "net/ip6_headers.hpp" #include "test_util.h" +using ot::Encoding::BigEndian::ReadUint16; + struct Ip6AddressStringTestVector { const char * mString; @@ -274,11 +278,67 @@ void TestIp6Prefix(void) } } +void TestIp6Header(void) +{ + ot::Ip6::Header header; + ot::Ip6::Address source; + ot::Ip6::Address destination; + const uint8_t * headerBytes = reinterpret_cast(&header); + + enum : uint16_t + { + kPayloadLength = 650, + }; + + enum : uint8_t + { + kHopLimit = 0xd1, + }; + + memset(&header, 0, sizeof(header)); + + SuccessOrQuit(source.FromString("0102:0304:0506:0708:090a:0b0c:0d0e:0f12"), "Address::FromString() failed"); + SuccessOrQuit(destination.FromString("1122:3344:5566::7788:99aa:bbcc:ddee:ff23"), "Address::FromString() failed"); + + header.Init(); + VerifyOrQuit(header.IsVersion6(), "Header::Init() failed"); + + header.SetDscp(ot::Ip6::kDscpCs7); + header.SetPayloadLength(kPayloadLength); + header.SetNextHeader(ot::Ip6::kProtoUdp); + header.SetHopLimit(kHopLimit); + header.SetSource(source); + header.SetDestination(destination); + + VerifyOrQuit(header.IsValid(), "Header::IsValid() failed"); + VerifyOrQuit(header.IsVersion6(), "Header::Init() failed"); + + VerifyOrQuit(header.GetDscp() == ot::Ip6::kDscpCs7, "Get/SetDscp() failed"); + VerifyOrQuit(header.GetPayloadLength() == kPayloadLength, "Get/SetPayloadLength() failed"); + VerifyOrQuit(header.GetNextHeader() == ot::Ip6::kProtoUdp, "Get/SetNextHeader() failed"); + VerifyOrQuit(header.GetHopLimit() == kHopLimit, "Get/SetHopLimit() failed"); + VerifyOrQuit(header.GetSource() == source, "Get/SetSource() failed"); + VerifyOrQuit(header.GetDestination() == destination, "Get/SetSource() failed"); + + // Verify the offsets to different fields. + + VerifyOrQuit(ReadUint16(headerBytes + ot::Ip6::Header::kPayloadLengthFieldOffset) == kPayloadLength, + "kPayloadLengthFieldOffset is incorrect"); + VerifyOrQuit(headerBytes[ot::Ip6::Header::kNextHeaderFieldOffset] == ot::Ip6::kProtoUdp, + "kNextHeaderFieldOffset is incorrect"); + VerifyOrQuit(headerBytes[ot::Ip6::Header::kHopLimitFieldOffset] == kHopLimit, "kHopLimitFieldOffset is incorrect"); + VerifyOrQuit(memcmp(&headerBytes[ot::Ip6::Header::kSourceFieldOffset], &source, sizeof(source)) == 0, + "kSourceFieldOffset is incorrect"); + VerifyOrQuit(memcmp(&headerBytes[ot::Ip6::Header::kDestinationFieldOffset], &destination, sizeof(destination)) == 0, + "kSourceFieldOffset is incorrect"); +} + int main(void) { TestIp6AddressSetPrefix(); TestIp6AddressFromString(); TestIp6Prefix(); + TestIp6Header(); printf("All tests passed\n"); return 0; }