[udp/tcp/icmp] simplify Header parsing, and declare related types as nested (#5203)

This commit contains two main changes in `Ip6` modules: `Udp`, `Tcp`,
and `Icmp`. First, it simplifies the `Header` types defining constant
`enum` for byte offset of different fields in the header (these
replace the static methods and avoid use of `offsetof` macro). Second
change is it declare related types in each module as nested types of
the the main class (place them under the namespace of the main type).
For example `Icmp::Header`, `Udp::Socket` respectively replace
`IcmpHeader`, `UdpSocket` types.
diff --git a/src/core/api/icmp6_api.cpp b/src/core/api/icmp6_api.cpp
index f23f18f..aaa8100 100644
--- a/src/core/api/icmp6_api.cpp
+++ b/src/core/api/icmp6_api.cpp
@@ -58,7 +58,7 @@
 {
     Instance &instance = *static_cast<Instance *>(aInstance);
 
-    return instance.Get<Ip6::Icmp>().RegisterHandler(*static_cast<Ip6::IcmpHandler *>(aHandler));
+    return instance.Get<Ip6::Icmp>().RegisterHandler(*static_cast<Ip6::Icmp::Handler *>(aHandler));
 }
 
 otError otIcmp6SendEchoRequest(otInstance *         aInstance,
diff --git a/src/core/api/udp_api.cpp b/src/core/api/udp_api.cpp
index ef527a1..40d9e4f 100644
--- a/src/core/api/udp_api.cpp
+++ b/src/core/api/udp_api.cpp
@@ -51,9 +51,9 @@
 
 otError otUdpOpen(otInstance *aInstance, otUdpSocket *aSocket, otUdpReceive aCallback, void *aContext)
 {
-    otError         error;
-    Instance &      instance = *static_cast<Instance *>(aInstance);
-    Ip6::UdpSocket &socket   = *new (aSocket) Ip6::UdpSocket(instance.Get<Ip6::Udp>());
+    otError           error;
+    Instance &        instance = *static_cast<Instance *>(aInstance);
+    Ip6::Udp::Socket &socket   = *new (aSocket) Ip6::Udp::Socket(instance.Get<Ip6::Udp>());
 
     error = socket.Open(aCallback, aContext);
 
@@ -62,8 +62,8 @@
 
 otError otUdpClose(otUdpSocket *aSocket)
 {
-    otError         error  = OT_ERROR_INVALID_STATE;
-    Ip6::UdpSocket &socket = *static_cast<Ip6::UdpSocket *>(aSocket);
+    otError           error  = OT_ERROR_INVALID_STATE;
+    Ip6::Udp::Socket &socket = *static_cast<Ip6::Udp::Socket *>(aSocket);
 
     error = socket.Close();
 
@@ -72,19 +72,19 @@
 
 otError otUdpBind(otUdpSocket *aSocket, otSockAddr *aSockName)
 {
-    Ip6::UdpSocket &socket = *static_cast<Ip6::UdpSocket *>(aSocket);
+    Ip6::Udp::Socket &socket = *static_cast<Ip6::Udp::Socket *>(aSocket);
     return socket.Bind(*static_cast<const Ip6::SockAddr *>(aSockName));
 }
 
 otError otUdpConnect(otUdpSocket *aSocket, otSockAddr *aSockName)
 {
-    Ip6::UdpSocket &socket = *static_cast<Ip6::UdpSocket *>(aSocket);
+    Ip6::Udp::Socket &socket = *static_cast<Ip6::Udp::Socket *>(aSocket);
     return socket.Connect(*static_cast<const Ip6::SockAddr *>(aSockName));
 }
 
 otError otUdpSend(otUdpSocket *aSocket, otMessage *aMessage, const otMessageInfo *aMessageInfo)
 {
-    Ip6::UdpSocket &socket = *static_cast<Ip6::UdpSocket *>(aSocket);
+    Ip6::Udp::Socket &socket = *static_cast<Ip6::Udp::Socket *>(aSocket);
     return socket.SendTo(*static_cast<Message *>(aMessage), *static_cast<const Ip6::MessageInfo *>(aMessageInfo));
 }
 
@@ -132,14 +132,14 @@
 {
     Instance &instance = *static_cast<Instance *>(aInstance);
 
-    return instance.Get<Ip6::Udp>().AddReceiver(*static_cast<Ip6::UdpReceiver *>(aUdpReceiver));
+    return instance.Get<Ip6::Udp>().AddReceiver(*static_cast<Ip6::Udp::Receiver *>(aUdpReceiver));
 }
 
 otError otUdpRemoveReceiver(otInstance *aInstance, otUdpReceiver *aUdpReceiver)
 {
     Instance &instance = *static_cast<Instance *>(aInstance);
 
-    return instance.Get<Ip6::Udp>().RemoveReceiver(*static_cast<Ip6::UdpReceiver *>(aUdpReceiver));
+    return instance.Get<Ip6::Udp>().RemoveReceiver(*static_cast<Ip6::Udp::Receiver *>(aUdpReceiver));
 }
 
 otError otUdpSendDatagram(otInstance *aInstance, otMessage *aMessage, otMessageInfo *aMessageInfo)
diff --git a/src/core/coap/coap.hpp b/src/core/coap/coap.hpp
index d8f1729..828d91b 100644
--- a/src/core/coap/coap.hpp
+++ b/src/core/coap/coap.hpp
@@ -628,7 +628,7 @@
     static void    HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
     otError        Send(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
 
-    Ip6::UdpSocket mSocket;
+    Ip6::Udp::Socket mSocket;
 };
 
 } // namespace Coap
diff --git a/src/core/meshcop/border_agent.hpp b/src/core/meshcop/border_agent.hpp
index 6937c6b..78b9ca4 100644
--- a/src/core/meshcop/border_agent.hpp
+++ b/src/core/meshcop/border_agent.hpp
@@ -157,7 +157,7 @@
     Coap::Resource mPendingSet;
     Coap::Resource mProxyTransmit;
 
-    Ip6::UdpReceiver         mUdpReceiver; ///< The UDP receiver to receive packets from external commissioner
+    Ip6::Udp::Receiver       mUdpReceiver; ///< The UDP receiver to receive packets from external commissioner
     Ip6::NetifUnicastAddress mCommissionerAloc;
 
     TimerMilli         mTimer;
diff --git a/src/core/meshcop/dtls.hpp b/src/core/meshcop/dtls.hpp
index 9fc3d2b..e5b1c03 100644
--- a/src/core/meshcop/dtls.hpp
+++ b/src/core/meshcop/dtls.hpp
@@ -461,7 +461,7 @@
     void *           mContext;
 
     Ip6::MessageInfo mPeerAddress;
-    Ip6::UdpSocket   mSocket;
+    Ip6::Udp::Socket mSocket;
 
     TransportCallback mTransportCallback;
     void *            mTransportContext;
diff --git a/src/core/meshcop/joiner_router.hpp b/src/core/meshcop/joiner_router.hpp
index 83fe54c..0f26a7d 100644
--- a/src/core/meshcop/joiner_router.hpp
+++ b/src/core/meshcop/joiner_router.hpp
@@ -118,8 +118,8 @@
     otError        SendJoinerEntrust(const Ip6::MessageInfo &aMessageInfo);
     Coap::Message *PrepareJoinerEntrustMessage(void);
 
-    Ip6::UdpSocket mSocket;
-    Coap::Resource mRelayTransmit;
+    Ip6::Udp::Socket mSocket;
+    Coap::Resource   mRelayTransmit;
 
     TimerMilli   mTimer;
     MessageQueue mDelayedJoinEnts;
diff --git a/src/core/net/dhcp6_client.hpp b/src/core/net/dhcp6_client.hpp
index 5b68fb0..d0c5a07 100644
--- a/src/core/net/dhcp6_client.hpp
+++ b/src/core/net/dhcp6_client.hpp
@@ -151,7 +151,7 @@
     static bool HandleTrickleTimer(TrickleTimer &aTrickleTimer);
     bool        HandleTrickleTimer(void);
 
-    Ip6::UdpSocket mSocket;
+    Ip6::Udp::Socket mSocket;
 
     TrickleTimer mTrickleTimer;
 
diff --git a/src/core/net/dhcp6_server.hpp b/src/core/net/dhcp6_server.hpp
index 583be2c..528cac6 100644
--- a/src/core/net/dhcp6_server.hpp
+++ b/src/core/net/dhcp6_server.hpp
@@ -214,7 +214,7 @@
 
     otError SendReply(otIp6Address &aDst, uint8_t *aTransactionId, ClientIdentifier &aClientId, IaNa &aIaNa);
 
-    Ip6::UdpSocket mSocket;
+    Ip6::Udp::Socket mSocket;
 
     PrefixAgent mPrefixAgents[OPENTHREAD_CONFIG_DHCP6_SERVER_NUM_PREFIXES];
     uint8_t     mPrefixAgentsCount;
diff --git a/src/core/net/dns_client.hpp b/src/core/net/dns_client.hpp
index 9325624..3cd8f89 100644
--- a/src/core/net/dns_client.hpp
+++ b/src/core/net/dns_client.hpp
@@ -216,7 +216,7 @@
     static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
     void        HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
 
-    Ip6::UdpSocket mSocket;
+    Ip6::Udp::Socket mSocket;
 
     uint16_t     mMessageId;
     MessageQueue mPendingQueries;
diff --git a/src/core/net/icmp6.cpp b/src/core/net/icmp6.cpp
index 7eb28df..3341992 100644
--- a/src/core/net/icmp6.cpp
+++ b/src/core/net/icmp6.cpp
@@ -56,10 +56,10 @@
 
 Message *Icmp::NewMessage(uint16_t aReserved)
 {
-    return Get<Ip6>().NewMessage(sizeof(IcmpHeader) + aReserved);
+    return Get<Ip6>().NewMessage(sizeof(Header) + aReserved);
 }
 
-otError Icmp::RegisterHandler(IcmpHandler &aHandler)
+otError Icmp::RegisterHandler(Handler &aHandler)
 {
     return mHandlers.Add(aHandler);
 }
@@ -68,12 +68,12 @@
 {
     otError     error = OT_ERROR_NONE;
     MessageInfo messageInfoLocal;
-    IcmpHeader  icmpHeader;
+    Header      icmpHeader;
 
     messageInfoLocal = aMessageInfo;
 
-    icmpHeader.Init();
-    icmpHeader.SetType(IcmpHeader::kTypeEchoRequest);
+    icmpHeader.Clear();
+    icmpHeader.SetType(Header::kTypeEchoRequest);
     icmpHeader.SetId(aIdentifier);
     icmpHeader.SetSequence(mEchoSequence++);
 
@@ -87,16 +87,16 @@
     return error;
 }
 
-otError Icmp::SendError(IcmpHeader::Type   aType,
-                        IcmpHeader::Code   aCode,
+otError Icmp::SendError(Header::Type       aType,
+                        Header::Code       aCode,
                         const MessageInfo &aMessageInfo,
                         const Message &    aMessage)
 {
     otError           error = OT_ERROR_NONE;
     MessageInfo       messageInfoLocal;
     Message *         message = nullptr;
-    IcmpHeader        icmp6Header;
-    Header            ip6Header;
+    Header            icmp6Header;
+    ot::Ip6::Header   ip6Header;
     Message::Settings settings(Message::kWithLinkSecurity, Message::kPriorityNet);
 
     VerifyOrExit(aMessage.GetLength() >= sizeof(ip6Header), error = OT_ERROR_INVALID_ARGS);
@@ -118,7 +118,7 @@
 
     message->Write(sizeof(icmp6Header), sizeof(ip6Header), &ip6Header);
 
-    icmp6Header.Init();
+    icmp6Header.Clear();
     icmp6Header.SetType(aType);
     icmp6Header.SetCode(aCode);
     message->Write(0, sizeof(icmp6Header), &icmp6Header);
@@ -139,10 +139,10 @@
 
 otError Icmp::HandleMessage(Message &aMessage, MessageInfo &aMessageInfo)
 {
-    otError    error = OT_ERROR_NONE;
-    uint16_t   payloadLength;
-    IcmpHeader icmp6Header;
-    uint16_t   checksum;
+    otError  error = OT_ERROR_NONE;
+    uint16_t payloadLength;
+    Header   icmp6Header;
+    uint16_t checksum;
 
     VerifyOrExit(aMessage.Read(aMessage.GetOffset(), sizeof(icmp6Header), &icmp6Header) == sizeof(icmp6Header),
                  error = OT_ERROR_PARSE);
@@ -154,14 +154,14 @@
     checksum = aMessage.UpdateChecksum(checksum, aMessage.GetOffset(), payloadLength);
     VerifyOrExit(checksum == 0xffff, error = OT_ERROR_PARSE);
 
-    if (icmp6Header.GetType() == IcmpHeader::kTypeEchoRequest)
+    if (icmp6Header.GetType() == Header::kTypeEchoRequest)
     {
         SuccessOrExit(error = HandleEchoRequest(aMessage, aMessageInfo));
     }
 
     aMessage.MoveOffset(sizeof(icmp6Header));
 
-    for (IcmpHandler *handler = mHandlers.GetHead(); handler; handler = handler->GetNext())
+    for (Handler *handler = mHandlers.GetHead(); handler; handler = handler->GetNext())
     {
         handler->HandleReceiveMessage(aMessage, aMessageInfo, icmp6Header);
     }
@@ -196,7 +196,7 @@
 otError Icmp::HandleEchoRequest(Message &aRequestMessage, const MessageInfo &aMessageInfo)
 {
     otError     error = OT_ERROR_NONE;
-    IcmpHeader  icmp6Header;
+    Header      icmp6Header;
     Message *   replyMessage = nullptr;
     MessageInfo replyMessageInfo;
     uint16_t    payloadLength;
@@ -206,8 +206,8 @@
 
     otLogInfoIcmp("Received Echo Request");
 
-    icmp6Header.Init();
-    icmp6Header.SetType(IcmpHeader::kTypeEchoReply);
+    icmp6Header.Clear();
+    icmp6Header.SetType(Header::kTypeEchoReply);
 
     if ((replyMessage = Get<Ip6>().NewMessage(0)) == nullptr)
     {
@@ -215,11 +215,11 @@
         ExitNow();
     }
 
-    payloadLength = aRequestMessage.GetLength() - aRequestMessage.GetOffset() - IcmpHeader::GetDataOffset();
-    SuccessOrExit(error = replyMessage->SetLength(IcmpHeader::GetDataOffset() + payloadLength));
+    payloadLength = aRequestMessage.GetLength() - aRequestMessage.GetOffset() - Header::kDataFieldOffset;
+    SuccessOrExit(error = replyMessage->SetLength(Header::kDataFieldOffset + payloadLength));
 
-    replyMessage->Write(0, IcmpHeader::GetDataOffset(), &icmp6Header);
-    aRequestMessage.CopyTo(aRequestMessage.GetOffset() + IcmpHeader::GetDataOffset(), IcmpHeader::GetDataOffset(),
+    replyMessage->Write(0, Header::kDataFieldOffset, &icmp6Header);
+    aRequestMessage.CopyTo(aRequestMessage.GetOffset() + Header::kDataFieldOffset, Header::kDataFieldOffset,
                            payloadLength, *replyMessage);
 
     replyMessageInfo.SetPeerAddr(aMessageInfo.GetPeerAddr());
@@ -254,7 +254,7 @@
     }
 
     aChecksum = HostSwap16(aChecksum);
-    aMessage.Write(aMessage.GetOffset() + IcmpHeader::GetChecksumOffset(), sizeof(aChecksum), &aChecksum);
+    aMessage.Write(aMessage.GetOffset() + Header::kChecksumFieldOffset, sizeof(aChecksum), &aChecksum);
 }
 
 } // namespace Ip6
diff --git a/src/core/net/icmp6.hpp b/src/core/net/icmp6.hpp
index 690fb36..7992406 100644
--- a/src/core/net/icmp6.hpp
+++ b/src/core/net/icmp6.hpp
@@ -38,6 +38,7 @@
 
 #include <openthread/icmp6.h>
 
+#include "common/clearable.hpp"
 #include "common/encoding.hpp"
 #include "common/linked_list.hpp"
 #include "common/locator.hpp"
@@ -58,186 +59,6 @@
  *
  */
 
-/*
- * This class implements ICMPv6 header generation and parsing.
- *
- */
-OT_TOOL_PACKED_BEGIN
-class IcmpHeader : public otIcmp6Header
-{
-public:
-    /**
-     * This method initializes the ICMPv6 header to all zeros.
-     *
-     */
-    void Init(void)
-    {
-        mType        = 0;
-        mCode        = 0;
-        mChecksum    = 0;
-        mData.m32[0] = 0;
-    }
-
-    /**
-     * ICMPv6 Message Types
-     *
-     */
-    enum Type
-    {
-        kTypeDstUnreach       = OT_ICMP6_TYPE_DST_UNREACH,       ///< Destination Unreachable
-        kTypePacketToBig      = OT_ICMP6_TYPE_PACKET_TO_BIG,     ///< Packet To Big
-        kTypeTimeExceeded     = OT_ICMP6_TYPE_TIME_EXCEEDED,     ///< Time Exceeded
-        kTypeParameterProblem = OT_ICMP6_TYPE_PARAMETER_PROBLEM, ///< Parameter Problem
-        kTypeEchoRequest      = OT_ICMP6_TYPE_ECHO_REQUEST,      ///< Echo Request
-        kTypeEchoReply        = OT_ICMP6_TYPE_ECHO_REPLY,        ///< Echo Reply
-    };
-
-    /**
-     * ICMPv6 Message Codes
-     *
-     */
-    enum Code
-    {
-        kCodeDstUnreachNoRoute = OT_ICMP6_CODE_DST_UNREACH_NO_ROUTE, ///< Destination Unreachable No Route
-        kCodeFragmReasTimeEx   = OT_ICMP6_CODE_FRAGM_REAS_TIME_EX,   ///< Fragment Reassembly Time Exceeded
-    };
-
-    /**
-     * This method indicates whether the ICMPv6 message is an error message.
-     *
-     * @retval TRUE if the ICMPv6 message is an error message.
-     * @retval FALSE if the ICMPv6 message is an informational message.
-     *
-     */
-    bool IsError(void) const { return mType < OT_ICMP6_TYPE_ECHO_REQUEST; }
-
-    /**
-     * This method returns the ICMPv6 message type.
-     *
-     * @returns The ICMPv6 message type.
-     *
-     */
-    Type GetType(void) const { return static_cast<Type>(mType); }
-
-    /**
-     * This method sets the ICMPv6 message type.
-     *
-     * @param[in]  aType  The ICMPv6 message type.
-     *
-     */
-    void SetType(Type aType) { mType = static_cast<uint8_t>(aType); }
-
-    /**
-     * This method returns the ICMPv6 message code.
-     *
-     * @returns The ICMPv6 message code.
-     *
-     */
-    Code GetCode(void) const { return static_cast<Code>(mCode); }
-
-    /**
-     * This method sets the ICMPv6 message code.
-     *
-     * @param[in]  aCode  The ICMPv6 message code.
-     */
-    void SetCode(Code aCode) { mCode = static_cast<uint8_t>(aCode); }
-
-    /**
-     * This method returns the ICMPv6 message checksum.
-     *
-     * @returns The ICMPv6 message checksum.
-     *
-     */
-    uint16_t GetChecksum(void) const { return HostSwap16(mChecksum); }
-
-    /**
-     * This method sets the ICMPv6 message checksum.
-     *
-     * @param[in]  aChecksum  The ICMPv6 message checksum.
-     *
-     */
-    void SetChecksum(uint16_t aChecksum) { mChecksum = HostSwap16(aChecksum); }
-
-    /**
-     * This method returns the ICMPv6 message ID for Echo Requests and Replies.
-     *
-     * @returns The ICMPv6 message ID.
-     *
-     */
-    uint16_t GetId(void) const { return HostSwap16(mData.m16[0]); }
-
-    /**
-     * This method sets the ICMPv6 message ID for Echo Requests and Replies.
-     *
-     * @param[in]  aId  The ICMPv6 message ID.
-     *
-     */
-    void SetId(uint16_t aId) { mData.m16[0] = HostSwap16(aId); }
-
-    /**
-     * This method returns the ICMPv6 message sequence for Echo Requests and Replies.
-     *
-     * @returns The ICMPv6 message sequence.
-     *
-     */
-    uint16_t GetSequence(void) const { return HostSwap16(mData.m16[1]); }
-
-    /**
-     * This method sets the ICMPv6 message sequence for Echo Requests and Replies.
-     *
-     * @param[in]  aSequence  The ICMPv6 message sequence.
-     *
-     */
-    void SetSequence(uint16_t aSequence) { mData.m16[1] = HostSwap16(aSequence); }
-
-    /**
-     * This static method returns the byte offset of the Checksum field in the ICMPv6 header.
-     *
-     * @returns The byte offset of the Checksum field.
-     *
-     */
-    static uint8_t GetChecksumOffset(void) { return offsetof(otIcmp6Header, mChecksum); }
-
-    /**
-     * This static method returns the byte offset of the ICMPv6 payload.
-     *
-     * @returns The Byte offset of the ICMPv6 payload.
-     *
-     */
-    static uint8_t GetDataOffset(void) { return offsetof(otIcmp6Header, mData); }
-
-} OT_TOOL_PACKED_END;
-
-/**
- * This class implements ICMPv6 message handlers.
- *
- */
-class IcmpHandler : public otIcmp6Handler, public LinkedListEntry<IcmpHandler>
-{
-    friend class Icmp;
-
-public:
-    /**
-     * This constructor creates an ICMPv6 message handler.
-     *
-     * @param[in]  aCallback  A pointer to the function that is called when receiving an ICMPv6 message.
-     * @param[in]  aContext   A pointer to arbitrary context information.
-     *
-     */
-    IcmpHandler(otIcmp6ReceiveCallback aCallback, void *aContext)
-    {
-        mReceiveCallback = aCallback;
-        mContext         = aContext;
-        mNext            = nullptr;
-    }
-
-private:
-    void HandleReceiveMessage(Message &aMessage, const MessageInfo &aMessageInfo, const IcmpHeader &aIcmp6Header)
-    {
-        mReceiveCallback(mContext, &aMessage, &aMessageInfo, &aIcmp6Header);
-    }
-};
-
 /**
  * This class implements ICMPv6.
  *
@@ -245,6 +66,167 @@
 class Icmp : public InstanceLocator
 {
 public:
+    /*
+     * This class implements ICMPv6 header generation and parsing.
+     *
+     */
+    OT_TOOL_PACKED_BEGIN
+    class Header : public otIcmp6Header, public Clearable<Header>
+    {
+    public:
+        /**
+         * ICMPv6 Message Types
+         *
+         */
+        enum Type : uint8_t
+        {
+            kTypeDstUnreach       = OT_ICMP6_TYPE_DST_UNREACH,       ///< Destination Unreachable
+            kTypePacketToBig      = OT_ICMP6_TYPE_PACKET_TO_BIG,     ///< Packet To Big
+            kTypeTimeExceeded     = OT_ICMP6_TYPE_TIME_EXCEEDED,     ///< Time Exceeded
+            kTypeParameterProblem = OT_ICMP6_TYPE_PARAMETER_PROBLEM, ///< Parameter Problem
+            kTypeEchoRequest      = OT_ICMP6_TYPE_ECHO_REQUEST,      ///< Echo Request
+            kTypeEchoReply        = OT_ICMP6_TYPE_ECHO_REPLY,        ///< Echo Reply
+        };
+
+        /**
+         * ICMPv6 Message Codes
+         *
+         */
+        enum Code : uint8_t
+        {
+            kCodeDstUnreachNoRoute = OT_ICMP6_CODE_DST_UNREACH_NO_ROUTE, ///< Destination Unreachable No Route
+            kCodeFragmReasTimeEx   = OT_ICMP6_CODE_FRAGM_REAS_TIME_EX,   ///< Fragment Reassembly Time Exceeded
+        };
+
+        enum : uint8_t
+        {
+            kTypeFieldOffset     = 0, ///< The byte offset of Type field in ICMP6 header.
+            kCodeFieldOffset     = 1, ///< The byte offset of Code field in ICMP6 header.
+            kChecksumFieldOffset = 2, ///< The byte offset of Checksum field in ICMP6 header.
+            kDataFieldOffset     = 4, ///< The byte offset of Data field in ICMP6 header.
+        };
+
+        /**
+         * This method indicates whether the ICMPv6 message is an error message.
+         *
+         * @retval TRUE if the ICMPv6 message is an error message.
+         * @retval FALSE if the ICMPv6 message is an informational message.
+         *
+         */
+        bool IsError(void) const { return mType < OT_ICMP6_TYPE_ECHO_REQUEST; }
+
+        /**
+         * This method returns the ICMPv6 message type.
+         *
+         * @returns The ICMPv6 message type.
+         *
+         */
+        Type GetType(void) const { return static_cast<Type>(mType); }
+
+        /**
+         * This method sets the ICMPv6 message type.
+         *
+         * @param[in]  aType  The ICMPv6 message type.
+         *
+         */
+        void SetType(Type aType) { mType = static_cast<uint8_t>(aType); }
+
+        /**
+         * This method returns the ICMPv6 message code.
+         *
+         * @returns The ICMPv6 message code.
+         *
+         */
+        Code GetCode(void) const { return static_cast<Code>(mCode); }
+
+        /**
+         * This method sets the ICMPv6 message code.
+         *
+         * @param[in]  aCode  The ICMPv6 message code.
+         *
+         */
+        void SetCode(Code aCode) { mCode = static_cast<uint8_t>(aCode); }
+
+        /**
+         * This method returns the ICMPv6 message checksum.
+         *
+         * @returns The ICMPv6 message checksum.
+         *
+         */
+        uint16_t GetChecksum(void) const { return HostSwap16(mChecksum); }
+
+        /**
+         * This method sets the ICMPv6 message checksum.
+         *
+         * @param[in]  aChecksum  The ICMPv6 message checksum.
+         *
+         */
+        void SetChecksum(uint16_t aChecksum) { mChecksum = HostSwap16(aChecksum); }
+
+        /**
+         * This method returns the ICMPv6 message ID for Echo Requests and Replies.
+         *
+         * @returns The ICMPv6 message ID.
+         *
+         */
+        uint16_t GetId(void) const { return HostSwap16(mData.m16[0]); }
+
+        /**
+         * This method sets the ICMPv6 message ID for Echo Requests and Replies.
+         *
+         * @param[in]  aId  The ICMPv6 message ID.
+         *
+         */
+        void SetId(uint16_t aId) { mData.m16[0] = HostSwap16(aId); }
+
+        /**
+         * This method returns the ICMPv6 message sequence for Echo Requests and Replies.
+         *
+         * @returns The ICMPv6 message sequence.
+         *
+         */
+        uint16_t GetSequence(void) const { return HostSwap16(mData.m16[1]); }
+
+        /**
+         * This method sets the ICMPv6 message sequence for Echo Requests and Replies.
+         *
+         * @param[in]  aSequence  The ICMPv6 message sequence.
+         *
+         */
+        void SetSequence(uint16_t aSequence) { mData.m16[1] = HostSwap16(aSequence); }
+
+    } OT_TOOL_PACKED_END;
+
+    /**
+     * This class implements ICMPv6 message handlers.
+     *
+     */
+    class Handler : public otIcmp6Handler, public LinkedListEntry<Handler>
+    {
+        friend class Icmp;
+
+    public:
+        /**
+         * This constructor creates an ICMPv6 message handler.
+         *
+         * @param[in]  aCallback  A pointer to the function that is called when receiving an ICMPv6 message.
+         * @param[in]  aContext   A pointer to arbitrary context information.
+         *
+         */
+        Handler(otIcmp6ReceiveCallback aCallback, void *aContext)
+        {
+            mReceiveCallback = aCallback;
+            mContext         = aContext;
+            mNext            = nullptr;
+        }
+
+    private:
+        void HandleReceiveMessage(Message &aMessage, const MessageInfo &aMessageInfo, const Header &aIcmp6Header)
+        {
+            mReceiveCallback(mContext, &aMessage, &aMessageInfo, &aIcmp6Header);
+        }
+    };
+
     /**
      * This constructor initializes the object.
      *
@@ -272,7 +254,7 @@
      * @retval OT_ERROR_ALREADY  The ICMPv6 handler is already registered.
      *
      */
-    otError RegisterHandler(IcmpHandler &aHandler);
+    otError RegisterHandler(Handler &aHandler);
 
     /**
      * This method sends an ICMPv6 Echo Request message.
@@ -300,10 +282,7 @@
      * @retval OT_ERROR_NO_BUFS  Insufficient buffers available.
      *
      */
-    otError SendError(IcmpHeader::Type   aType,
-                      IcmpHeader::Code   aCode,
-                      const MessageInfo &aMessageInfo,
-                      const Message &    aMessage);
+    otError SendError(Header::Type aType, Header::Code aCode, const MessageInfo &aMessageInfo, const Message &aMessage);
 
     /**
      * This method handles an ICMPv6 message.
@@ -356,7 +335,7 @@
 private:
     otError HandleEchoRequest(Message &aRequestMessage, const MessageInfo &aMessageInfo);
 
-    LinkedList<IcmpHandler> mHandlers;
+    LinkedList<Handler> mHandlers;
 
     uint16_t        mEchoSequence;
     otIcmp6EchoMode mEchoMode;
diff --git a/src/core/net/ip6.cpp b/src/core/net/ip6.cpp
index dbfcc95..0ea4917 100644
--- a/src/core/net/ip6.cpp
+++ b/src/core/net/ip6.cpp
@@ -884,7 +884,7 @@
         else
         {
             otLogNoteIp6("Reassembly timeout.");
-            SendIcmpError(*message, IcmpHeader::kTypeTimeExceeded, IcmpHeader::kCodeFragmReasTimeEx);
+            SendIcmpError(*message, Icmp::Header::kTypeTimeExceeded, Icmp::Header::kCodeFragmReasTimeEx);
 
             mReassemblyList.Dequeue(*message);
             message->Free();
@@ -892,7 +892,7 @@
     }
 }
 
-void Ip6::SendIcmpError(Message &aMessage, IcmpHeader::Type aIcmpType, IcmpHeader::Code aIcmpCode)
+void Ip6::SendIcmpError(Message &aMessage, Icmp::Header::Type aIcmpType, Icmp::Header::Code aIcmpCode)
 {
     otError     error = OT_ERROR_NONE;
     Header      header;
@@ -1046,18 +1046,18 @@
         case kProtoIcmp6:
             if (mIcmp.ShouldHandleEchoRequest(aMessageInfo))
             {
-                IcmpHeader icmp;
+                Icmp::Header icmp;
                 aMessage.Read(aMessage.GetOffset(), sizeof(icmp), &icmp);
 
                 // do not pass ICMP Echo Request messages
-                VerifyOrExit(icmp.GetType() != IcmpHeader::kTypeEchoRequest, error = OT_ERROR_DROP);
+                VerifyOrExit(icmp.GetType() != Icmp::Header::kTypeEchoRequest, error = OT_ERROR_DROP);
             }
 
             break;
 
         case kProtoUdp:
         {
-            UdpHeader udp;
+            Udp::Header udp;
             aMessage.Read(aMessage.GetOffset(), sizeof(udp), &udp);
 
             switch (udp.GetDestinationPort())
diff --git a/src/core/net/ip6.hpp b/src/core/net/ip6.hpp
index fd06974..7a5fd90 100644
--- a/src/core/net/ip6.hpp
+++ b/src/core/net/ip6.hpp
@@ -372,7 +372,7 @@
     void        CleanupFragmentationBuffer(void);
     void        HandleUpdateTimer(void);
     void        UpdateReassemblyList(void);
-    void        SendIcmpError(Message &aMessage, IcmpHeader::Type aIcmpType, IcmpHeader::Code aIcmpCode);
+    void        SendIcmpError(Message &aMessage, Icmp::Header::Type aIcmpType, Icmp::Header::Code aIcmpCode);
     static void HandleTimer(Timer &aTimer);
 #endif
     otError AddMplOption(Message &aMessage, Header &aHeader);
diff --git a/src/core/net/ip6_filter.cpp b/src/core/net/ip6_filter.cpp
index 0139ea4..2bedada 100644
--- a/src/core/net/ip6_filter.cpp
+++ b/src/core/net/ip6_filter.cpp
@@ -55,11 +55,11 @@
 
 bool Filter::Accept(Message &aMessage) const
 {
-    bool      rval = false;
-    Header    ip6;
-    UdpHeader udp;
-    TcpHeader tcp;
-    uint16_t  dstport;
+    bool        rval = false;
+    Header      ip6;
+    Udp::Header udp;
+    Tcp::Header tcp;
+    uint16_t    dstport;
 
     // Allow all received IPv6 datagrams with link security enabled
     if (aMessage.IsLinkSecurityEnabled())
diff --git a/src/core/net/sntp_client.hpp b/src/core/net/sntp_client.hpp
index 76d4a9c..722b57f 100644
--- a/src/core/net/sntp_client.hpp
+++ b/src/core/net/sntp_client.hpp
@@ -583,7 +583,7 @@
     static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
     void        HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
 
-    Ip6::UdpSocket mSocket;
+    Ip6::Udp::Socket mSocket;
 
     MessageQueue mPendingQueries;
     TimerMilli   mRetransmissionTimer;
diff --git a/src/core/net/tcp.hpp b/src/core/net/tcp.hpp
index 78f598f..513ce77 100644
--- a/src/core/net/tcp.hpp
+++ b/src/core/net/tcp.hpp
@@ -40,6 +40,7 @@
 
 namespace ot {
 namespace Ip6 {
+namespace Tcp {
 
 /**
  * @addtogroup core-tcp
@@ -51,25 +52,12 @@
  *
  */
 
-OT_TOOL_PACKED_BEGIN
-struct TcpHeaderPoD
-{
-    uint16_t mSource;
-    uint16_t mDestination;
-    uint32_t mSequenceNumber;
-    uint32_t mAckNumber;
-    uint16_t mFlags;
-    uint16_t mWindow;
-    uint16_t mChecksum;
-    uint16_t mUrgentPointer;
-} OT_TOOL_PACKED_END;
-
 /**
  * This class implements TCP header parsing.
  *
  */
 OT_TOOL_PACKED_BEGIN
-class TcpHeader : private TcpHeaderPoD
+class Header
 {
 public:
     /**
@@ -136,6 +124,16 @@
      */
     uint16_t GetUrgentPointer(void) const { return HostSwap16(mUrgentPointer); }
 
+private:
+    uint16_t mSource;
+    uint16_t mDestination;
+    uint32_t mSequenceNumber;
+    uint32_t mAckNumber;
+    uint16_t mFlags;
+    uint16_t mWindow;
+    uint16_t mChecksum;
+    uint16_t mUrgentPointer;
+
 } OT_TOOL_PACKED_END;
 
 /**
@@ -143,6 +141,7 @@
  *
  */
 
+} // namespace Tcp
 } // namespace Ip6
 } // namespace ot
 
diff --git a/src/core/net/udp6.cpp b/src/core/net/udp6.cpp
index 9b74765..30bd144 100644
--- a/src/core/net/udp6.cpp
+++ b/src/core/net/udp6.cpp
@@ -60,18 +60,18 @@
 }
 #endif
 
-UdpSocket::UdpSocket(Udp &aUdp)
+Udp::Socket::Socket(Udp &aUdp)
     : InstanceLocator(aUdp.GetInstance())
 {
     mHandle = nullptr;
 }
 
-Message *UdpSocket::NewMessage(uint16_t aReserved, const Message::Settings &aSettings)
+Message *Udp::Socket::NewMessage(uint16_t aReserved, const Message::Settings &aSettings)
 {
     return Get<Udp>().NewMessage(aReserved, aSettings);
 }
 
-otError UdpSocket::Open(otUdpReceive aHandler, void *aContext)
+otError Udp::Socket::Open(otUdpReceive aHandler, void *aContext)
 {
     otError error = OT_ERROR_NONE;
 
@@ -92,7 +92,7 @@
     return error;
 }
 
-otError UdpSocket::Bind(const SockAddr &aSockAddr)
+otError Udp::Socket::Bind(const SockAddr &aSockAddr)
 {
     otError error = OT_ERROR_NONE;
 
@@ -118,7 +118,7 @@
     return error;
 }
 
-otError UdpSocket::Connect(const SockAddr &aSockAddr)
+otError Udp::Socket::Connect(const SockAddr &aSockAddr)
 {
     otError error = OT_ERROR_NONE;
 
@@ -133,7 +133,7 @@
     return error;
 }
 
-otError UdpSocket::Close(void)
+otError Udp::Socket::Close(void)
 {
     otError error = OT_ERROR_NONE;
 
@@ -151,7 +151,7 @@
     return error;
 }
 
-otError UdpSocket::SendTo(Message &aMessage, const MessageInfo &aMessageInfo)
+otError Udp::Socket::SendTo(Message &aMessage, const MessageInfo &aMessageInfo)
 {
     otError     error = OT_ERROR_NONE;
     MessageInfo messageInfoLocal;
@@ -202,7 +202,7 @@
     return error;
 }
 
-bool UdpSocket::Matches(const MessageInfo &aMessageInfo) const
+bool Udp::Socket::Matches(const MessageInfo &aMessageInfo) const
 {
     bool matches = false;
 
@@ -240,12 +240,12 @@
 {
 }
 
-otError Udp::AddReceiver(UdpReceiver &aReceiver)
+otError Udp::AddReceiver(Receiver &aReceiver)
 {
     return mReceivers.Add(aReceiver);
 }
 
-otError Udp::RemoveReceiver(UdpReceiver &aReceiver)
+otError Udp::RemoveReceiver(Receiver &aReceiver)
 {
     otError error;
 
@@ -256,12 +256,12 @@
     return error;
 }
 
-void Udp::AddSocket(UdpSocket &aSocket)
+void Udp::AddSocket(Socket &aSocket)
 {
     IgnoreError(mSockets.Add(aSocket));
 }
 
-void Udp::RemoveSocket(UdpSocket &aSocket)
+void Udp::RemoveSocket(Socket &aSocket)
 {
     SuccessOrExit(mSockets.Remove(aSocket));
     aSocket.SetNext(nullptr);
@@ -288,7 +288,7 @@
 
 Message *Udp::NewMessage(uint16_t aReserved, const Message::Settings &aSettings)
 {
-    return Get<Ip6>().NewMessage(sizeof(UdpHeader) + aReserved, aSettings);
+    return Get<Ip6>().NewMessage(sizeof(Header) + aReserved, aSettings);
 }
 
 otError Udp::SendDatagram(Message &aMessage, MessageInfo &aMessageInfo, uint8_t aIpProto)
@@ -306,7 +306,7 @@
     else
 #endif
     {
-        UdpHeader udpHeader;
+        Header udpHeader;
 
         udpHeader.SetSourcePort(aMessageInfo.mSockPort);
         udpHeader.SetDestinationPort(aMessageInfo.mPeerPort);
@@ -325,15 +325,15 @@
 
 otError Udp::HandleMessage(Message &aMessage, MessageInfo &aMessageInfo)
 {
-    otError   error = OT_ERROR_NONE;
-    UdpHeader udpHeader;
-    uint16_t  payloadLength;
-    uint16_t  checksum;
+    otError  error = OT_ERROR_NONE;
+    Header   udpHeader;
+    uint16_t payloadLength;
+    uint16_t checksum;
 
     payloadLength = aMessage.GetLength() - aMessage.GetOffset();
 
     // check length
-    VerifyOrExit(payloadLength >= sizeof(UdpHeader), error = OT_ERROR_PARSE);
+    VerifyOrExit(payloadLength >= sizeof(Header), error = OT_ERROR_PARSE);
 
     // verify checksum
     checksum = Ip6::ComputePseudoheaderChecksum(aMessageInfo.GetPeerAddr(), aMessageInfo.GetSockAddr(), payloadLength,
@@ -354,7 +354,7 @@
     VerifyOrExit(IsMle(GetInstance(), aMessageInfo.mSockPort), OT_NOOP);
 #endif
 
-    for (UdpReceiver *receiver = mReceivers.GetHead(); receiver; receiver = receiver->GetNext())
+    for (Receiver *receiver = mReceivers.GetHead(); receiver; receiver = receiver->GetNext())
     {
         VerifyOrExit(!receiver->HandleMessage(aMessage, aMessageInfo), OT_NOOP);
     }
@@ -367,8 +367,8 @@
 
 void Udp::HandlePayload(Message &aMessage, MessageInfo &aMessageInfo)
 {
-    UdpSocket *socket;
-    UdpSocket *prev;
+    Socket *socket;
+    Socket *prev;
 
     socket = mSockets.FindMatching(aMessageInfo, prev);
     VerifyOrExit(socket != nullptr, OT_NOOP);
@@ -391,7 +391,7 @@
     }
 
     aChecksum = HostSwap16(aChecksum);
-    aMessage.Write(aMessage.GetOffset() + UdpHeader::GetChecksumOffset(), sizeof(aChecksum), &aChecksum);
+    aMessage.Write(aMessage.GetOffset() + Header::kChecksumFieldOffset, sizeof(aChecksum), &aChecksum);
 }
 
 } // namespace Ip6
diff --git a/src/core/net/udp6.hpp b/src/core/net/udp6.hpp
index cca7cbe..ddb6e45 100644
--- a/src/core/net/udp6.hpp
+++ b/src/core/net/udp6.hpp
@@ -58,180 +58,266 @@
  */
 
 /**
- * This class implements a UDP receiver.
- *
- */
-class UdpReceiver : public otUdpReceiver, public LinkedListEntry<UdpReceiver>
-{
-    friend class Udp;
-
-public:
-    /**
-     * This constructor initializes the object.
-     *
-     * @param[in]   aUdpHandler     A pointer to the function to handle UDP message.
-     * @param[in]   aContext        A pointer to arbitrary context information.
-     *
-     */
-    UdpReceiver(otUdpHandler aHandler, void *aContext)
-    {
-        mNext    = nullptr;
-        mHandler = aHandler;
-        mContext = aContext;
-    }
-
-private:
-    bool HandleMessage(Message &aMessage, const MessageInfo &aMessageInfo)
-    {
-        return mHandler(mContext, &aMessage, &aMessageInfo);
-    }
-};
-
-/**
- * This class implements a UDP/IPv6 socket.
- *
- */
-class UdpSocket : public otUdpSocket, public InstanceLocator, public LinkedListEntry<UdpSocket>
-{
-    friend class Udp;
-    friend class LinkedList<UdpSocket>;
-
-public:
-    /**
-     * This constructor initializes the object.
-     *
-     * @param[in]  aUdp  A reference to the UDP transport object.
-     *
-     */
-    explicit UdpSocket(Udp &aUdp);
-
-    /**
-     * This method returns a new UDP message with sufficient header space reserved.
-     *
-     * @param[in]  aReserved  The number of header bytes to reserve after the UDP header.
-     * @param[in]  aSettings  The message settings (default is used if not provided).
-     *
-     * @returns A pointer to the message or nullptr if no buffers are available.
-     *
-     */
-    Message *NewMessage(uint16_t aReserved, const Message::Settings &aSettings = Message::Settings::GetDefault());
-
-    /**
-     * This method opens the UDP socket.
-     *
-     * @param[in]  aHandler  A pointer to a function that is called when receiving UDP messages.
-     * @param[in]  aContext  A pointer to arbitrary context information.
-     *
-     * @retval OT_ERROR_NONE     Successfully opened the socket.
-     * @retval OT_ERROR_ALREADY  The socket is already open.
-     *
-     */
-    otError Open(otUdpReceive aHandler, void *aContext);
-
-    /**
-     * This method binds the UDP socket.
-     *
-     * @param[in]  aSockAddr  A reference to the socket address.
-     *
-     * @retval OT_ERROR_NONE    Successfully bound the socket.
-     * @retval OT_ERROR_FAILED  Failed to bind UDP Socket.
-     *
-     */
-    otError Bind(const SockAddr &aSockAddr);
-
-    /**
-     * This method indicates whether or not the socket is bound.
-     *
-     * @retval TRUE if the socket is bound (i.e. source port is non-zero).
-     * @retval FALSE if the socket is not bound (source port is zero).
-     *
-     */
-    bool IsBound(void) const { return mSockName.mPort != 0; }
-
-    /**
-     * This method connects the UDP socket.
-     *
-     * @param[in]  aSockAddr  A reference to the socket address.
-     *
-     * @retval OT_ERROR_NONE    Successfully connected the socket.
-     * @retval OT_ERROR_FAILED  Failed to connect UDP Socket.
-     *
-     */
-    otError Connect(const SockAddr &aSockAddr);
-
-    /**
-     * This method closes the UDP socket.
-     *
-     * @retval OT_ERROR_NONE    Successfully closed the UDP socket.
-     * @retval OT_ERROR_FAILED  Failed to close UDP Socket.
-     *
-     */
-    otError Close(void);
-
-    /**
-     * This method sends a UDP message.
-     *
-     * @param[in]  aMessage      The message to send.
-     * @param[in]  aMessageInfo  The message info associated with @p aMessage.
-     *
-     * @retval OT_ERROR_NONE          Successfully sent the UDP message.
-     * @retval OT_ERROR_INVALID_ARGS  If no peer is specified in @p aMessageInfo or by connect().
-     * @retval OT_ERROR_NO_BUFS       Insufficient available buffer to add the UDP and IPv6 headers.
-     *
-     */
-    otError SendTo(Message &aMessage, const MessageInfo &aMessageInfo);
-
-    /**
-     * This method returns the local socket address.
-     *
-     * @returns A reference to the local socket address.
-     *
-     */
-    SockAddr &GetSockName(void) { return *static_cast<SockAddr *>(&mSockName); }
-
-    /**
-     * This method returns the local socket address.
-     *
-     * @returns A reference to the local socket address.
-     *
-     */
-    const SockAddr &GetSockName(void) const { return *static_cast<const SockAddr *>(&mSockName); }
-
-    /**
-     * This method returns the peer's socket address.
-     *
-     * @returns A reference to the peer's socket address.
-     *
-     */
-    SockAddr &GetPeerName(void) { return *static_cast<SockAddr *>(&mPeerName); }
-
-    /**
-     * This method returns the peer's socket address.
-     *
-     * @returns A reference to the peer's socket address.
-     *
-     */
-    const SockAddr &GetPeerName(void) const { return *static_cast<const SockAddr *>(&mPeerName); }
-
-private:
-    bool Matches(const MessageInfo &aMessageInfo) const;
-
-    void HandleUdpReceive(Message &aMessage, const MessageInfo &aMessageInfo)
-    {
-        mHandler(mContext, &aMessage, &aMessageInfo);
-    }
-};
-
-/**
  * This class implements core UDP message handling.
  *
  */
 class Udp : public InstanceLocator
 {
-    friend class UdpSocket;
-
 public:
     /**
+     * This class implements a UDP/IPv6 socket.
+     *
+     */
+    class Socket : public otUdpSocket, public InstanceLocator, public LinkedListEntry<Socket>
+    {
+        friend class Udp;
+        friend class LinkedList<Socket>;
+
+    public:
+        /**
+         * This constructor initializes the object.
+         *
+         * @param[in]  aUdp  A reference to the UDP transport object.
+         *
+         */
+        explicit Socket(Udp &aUdp);
+
+        /**
+         * This method returns a new UDP message with sufficient header space reserved.
+         *
+         * @param[in]  aReserved  The number of header bytes to reserve after the UDP header.
+         * @param[in]  aSettings  The message settings (default is used if not provided).
+         *
+         * @returns A pointer to the message or nullptr if no buffers are available.
+         *
+         */
+        Message *NewMessage(uint16_t aReserved, const Message::Settings &aSettings = Message::Settings::GetDefault());
+
+        /**
+         * This method opens the UDP socket.
+         *
+         * @param[in]  aHandler  A pointer to a function that is called when receiving UDP messages.
+         * @param[in]  aContext  A pointer to arbitrary context information.
+         *
+         * @retval OT_ERROR_NONE     Successfully opened the socket.
+         * @retval OT_ERROR_ALREADY  The socket is already open.
+         *
+         */
+        otError Open(otUdpReceive aHandler, void *aContext);
+
+        /**
+         * This method binds the UDP socket.
+         *
+         * @param[in]  aSockAddr  A reference to the socket address.
+         *
+         * @retval OT_ERROR_NONE    Successfully bound the socket.
+         * @retval OT_ERROR_FAILED  Failed to bind UDP Socket.
+         *
+         */
+        otError Bind(const SockAddr &aSockAddr);
+
+        /**
+         * This method indicates whether or not the socket is bound.
+         *
+         * @retval TRUE if the socket is bound (i.e. source port is non-zero).
+         * @retval FALSE if the socket is not bound (source port is zero).
+         *
+         */
+        bool IsBound(void) const { return mSockName.mPort != 0; }
+
+        /**
+         * This method connects the UDP socket.
+         *
+         * @param[in]  aSockAddr  A reference to the socket address.
+         *
+         * @retval OT_ERROR_NONE    Successfully connected the socket.
+         * @retval OT_ERROR_FAILED  Failed to connect UDP Socket.
+         *
+         */
+        otError Connect(const SockAddr &aSockAddr);
+
+        /**
+         * This method closes the UDP socket.
+         *
+         * @retval OT_ERROR_NONE    Successfully closed the UDP socket.
+         * @retval OT_ERROR_FAILED  Failed to close UDP Socket.
+         *
+         */
+        otError Close(void);
+
+        /**
+         * This method sends a UDP message.
+         *
+         * @param[in]  aMessage      The message to send.
+         * @param[in]  aMessageInfo  The message info associated with @p aMessage.
+         *
+         * @retval OT_ERROR_NONE          Successfully sent the UDP message.
+         * @retval OT_ERROR_INVALID_ARGS  If no peer is specified in @p aMessageInfo or by connect().
+         * @retval OT_ERROR_NO_BUFS       Insufficient available buffer to add the UDP and IPv6 headers.
+         *
+         */
+        otError SendTo(Message &aMessage, const MessageInfo &aMessageInfo);
+
+        /**
+         * This method returns the local socket address.
+         *
+         * @returns A reference to the local socket address.
+         *
+         */
+        SockAddr &GetSockName(void) { return *static_cast<SockAddr *>(&mSockName); }
+
+        /**
+         * This method returns the local socket address.
+         *
+         * @returns A reference to the local socket address.
+         *
+         */
+        const SockAddr &GetSockName(void) const { return *static_cast<const SockAddr *>(&mSockName); }
+
+        /**
+         * This method returns the peer's socket address.
+         *
+         * @returns A reference to the peer's socket address.
+         *
+         */
+        SockAddr &GetPeerName(void) { return *static_cast<SockAddr *>(&mPeerName); }
+
+        /**
+         * This method returns the peer's socket address.
+         *
+         * @returns A reference to the peer's socket address.
+         *
+         */
+        const SockAddr &GetPeerName(void) const { return *static_cast<const SockAddr *>(&mPeerName); }
+
+    private:
+        bool Matches(const MessageInfo &aMessageInfo) const;
+
+        void HandleUdpReceive(Message &aMessage, const MessageInfo &aMessageInfo)
+        {
+            mHandler(mContext, &aMessage, &aMessageInfo);
+        }
+    };
+
+    /**
+     * This class implements a UDP receiver.
+     *
+     */
+    class Receiver : public otUdpReceiver, public LinkedListEntry<Receiver>
+    {
+        friend class Udp;
+
+    public:
+        /**
+         * This constructor initializes the UDP receiver.
+         *
+         * @param[in]   aUdpHandler     A pointer to the function to handle UDP message.
+         * @param[in]   aContext        A pointer to arbitrary context information.
+         *
+         */
+        Receiver(otUdpHandler aHandler, void *aContext)
+        {
+            mNext    = nullptr;
+            mHandler = aHandler;
+            mContext = aContext;
+        }
+
+    private:
+        bool HandleMessage(Message &aMessage, const MessageInfo &aMessageInfo)
+        {
+            return mHandler(mContext, &aMessage, &aMessageInfo);
+        }
+    };
+
+    /**
+     * This class implements UDP header generation and parsing.
+     *
+     */
+    OT_TOOL_PACKED_BEGIN
+    class Header
+    {
+    public:
+        enum : uint8_t
+        {
+            kSourcePortFieldOffset = 0, ///< The byte offset of Source Port field in UDP header.
+            kDestPortFieldOffset   = 2, ///< The byte offset of Destination Port field in UDP header.
+            kLengthFieldOffset     = 4, ///< The byte offset of Length field in UDP header.
+            kChecksumFieldOffset   = 6, ///< The byte offset of Checksum field in UDP header.
+        };
+
+        /**
+         * This method returns the UDP Source Port.
+         *
+         * @returns The UDP Source Port.
+         *
+         */
+        uint16_t GetSourcePort(void) const { return HostSwap16(mSourcePort); }
+
+        /**
+         * This method sets the UDP Source Port.
+         *
+         * @param[in]  aPort  The UDP Source Port.
+         *
+         */
+        void SetSourcePort(uint16_t aPort) { mSourcePort = HostSwap16(aPort); }
+
+        /**
+         * This method returns the UDP Destination Port.
+         *
+         * @returns The UDP Destination Port.
+         *
+         */
+        uint16_t GetDestinationPort(void) const { return HostSwap16(mDestinationPort); }
+
+        /**
+         * This method sets the UDP Destination Port.
+         *
+         * @param[in]  aPort  The UDP Destination Port.
+         *
+         */
+        void SetDestinationPort(uint16_t aPort) { mDestinationPort = HostSwap16(aPort); }
+
+        /**
+         * This method returns the UDP Length.
+         *
+         * @returns The UDP Length.
+         *
+         */
+        uint16_t GetLength(void) const { return HostSwap16(mLength); }
+
+        /**
+         * This method sets the UDP Length.
+         *
+         * @param[in]  aLength  The UDP Length.
+         *
+         */
+        void SetLength(uint16_t aLength) { mLength = HostSwap16(aLength); }
+
+        /**
+         * This method returns the UDP Checksum.
+         *
+         * @returns The UDP Checksum.
+         *
+         */
+        uint16_t GetChecksum(void) const { return HostSwap16(mChecksum); }
+
+        /**
+         * This method sets the UDP Checksum.
+         *
+         * @param[in]  aChecksum  The UDP Checksum.
+         *
+         */
+        void SetChecksum(uint16_t aChecksum) { mChecksum = HostSwap16(aChecksum); }
+
+    private:
+        uint16_t mSourcePort;
+        uint16_t mDestinationPort;
+        uint16_t mLength;
+        uint16_t mChecksum;
+
+    } OT_TOOL_PACKED_END;
+
+    /**
      * This constructor initializes the object.
      *
      * @param[in]  aIp6  A reference to OpenThread instance.
@@ -248,7 +334,7 @@
      * @retval OT_ERROR_ALREADY The UDP receiver was already added.
      *
      */
-    otError AddReceiver(UdpReceiver &aReceiver);
+    otError AddReceiver(Receiver &aReceiver);
 
     /**
      * This method removes a UDP receiver.
@@ -259,7 +345,7 @@
      * @retval OT_ERROR_NOT_FOUND   The UDP receiver was not added.
      *
      */
-    otError RemoveReceiver(UdpReceiver &aReceiver);
+    otError RemoveReceiver(Receiver &aReceiver);
 
     /**
      * This method adds a UDP socket.
@@ -267,7 +353,7 @@
      * @param[in]  aSocket  A reference to the UDP socket.
      *
      */
-    void AddSocket(UdpSocket &aSocket);
+    void AddSocket(Socket &aSocket);
 
     /**
      * This method removes a UDP socket.
@@ -275,7 +361,7 @@
      * @param[in]  aSocket  A reference to the UDP socket.
      *
      */
-    void RemoveSocket(UdpSocket &aSocket);
+    void RemoveSocket(Socket &aSocket);
 
     /**
      * This method returns a new ephemeral port.
@@ -346,7 +432,7 @@
      * @returns A pointer to the head of UDP Socket linked list.
      *
      */
-    UdpSocket *GetUdpSockets(void) { return mSockets.GetHead(); }
+    Socket *GetUdpSockets(void) { return mSockets.GetHead(); }
 #endif
 
 #if OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE
@@ -371,114 +457,15 @@
         kDynamicPortMax = 65535, ///< Service Name and Transport Protocol Port Number Registry
     };
 
-    uint16_t                mEphemeralPort;
-    LinkedList<UdpReceiver> mReceivers;
-    LinkedList<UdpSocket>   mSockets;
+    uint16_t             mEphemeralPort;
+    LinkedList<Receiver> mReceivers;
+    LinkedList<Socket>   mSockets;
 #if OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE
     void *         mUdpForwarderContext;
     otUdpForwarder mUdpForwarder;
 #endif
 };
 
-OT_TOOL_PACKED_BEGIN
-struct UdpHeaderPoD
-{
-    uint16_t mSource;
-    uint16_t mDestination;
-    uint16_t mLength;
-    uint16_t mChecksum;
-} OT_TOOL_PACKED_END;
-
-/**
- * This class implements UDP header generation and parsing.
- *
- */
-OT_TOOL_PACKED_BEGIN
-class UdpHeader : private UdpHeaderPoD
-{
-public:
-    /**
-     * This method returns the UDP Source Port.
-     *
-     * @returns The UDP Source Port.
-     *
-     */
-    uint16_t GetSourcePort(void) const { return HostSwap16(mSource); }
-
-    /**
-     * This method sets the UDP Source Port.
-     *
-     * @param[in]  aPort  The UDP Source Port.
-     *
-     */
-    void SetSourcePort(uint16_t aPort) { mSource = HostSwap16(aPort); }
-
-    /**
-     * This method returns the UDP Destination Port.
-     *
-     * @returns The UDP Destination Port.
-     *
-     */
-    uint16_t GetDestinationPort(void) const { return HostSwap16(mDestination); }
-
-    /**
-     * This method sets the UDP Destination Port.
-     *
-     * @param[in]  aPort  The UDP Destination Port.
-     *
-     */
-    void SetDestinationPort(uint16_t aPort) { mDestination = HostSwap16(aPort); }
-
-    /**
-     * This method returns the UDP Length.
-     *
-     * @returns The UDP Length.
-     *
-     */
-    uint16_t GetLength(void) const { return HostSwap16(mLength); }
-
-    /**
-     * This method sets the UDP Length.
-     *
-     * @param[in]  aLength  The UDP Length.
-     *
-     */
-    void SetLength(uint16_t aLength) { mLength = HostSwap16(aLength); }
-
-    /**
-     * This method returns the UDP Checksum.
-     *
-     * @returns The UDP Checksum.
-     *
-     */
-    uint16_t GetChecksum(void) const { return HostSwap16(mChecksum); }
-
-    /**
-     * This method sets the UDP Checksum.
-     *
-     * @param[in]  aChecksum  The UDP Checksum.
-     *
-     */
-    void SetChecksum(uint16_t aChecksum) { mChecksum = HostSwap16(aChecksum); }
-
-    /**
-     * This static method returns the byte offset for the UDP Length.
-     *
-     * @returns The byte offset for the UDP Length.
-     *
-     */
-    static uint8_t GetLengthOffset(void) { return offsetof(UdpHeaderPoD, mLength); }
-
-    /**
-     * This static method returns the byte offset for the UDP Checksum.
-     *
-     * @returns The byte offset for the UDP Checksum.
-     *
-     */
-    static uint8_t GetChecksumOffset(void) { return offsetof(UdpHeaderPoD, mChecksum); }
-
-} OT_TOOL_PACKED_END;
-
 /**
  * @}
  *
diff --git a/src/core/thread/address_resolver.cpp b/src/core/thread/address_resolver.cpp
index b982fe2..c61f84a 100644
--- a/src/core/thread/address_resolver.cpp
+++ b/src/core/thread/address_resolver.cpp
@@ -937,19 +937,19 @@
 
     static_cast<AddressResolver *>(aContext)->HandleIcmpReceive(*static_cast<Message *>(aMessage),
                                                                 *static_cast<const Ip6::MessageInfo *>(aMessageInfo),
-                                                                *static_cast<const Ip6::IcmpHeader *>(aIcmpHeader));
+                                                                *static_cast<const Ip6::Icmp::Header *>(aIcmpHeader));
 }
 
-void AddressResolver::HandleIcmpReceive(Message &               aMessage,
-                                        const Ip6::MessageInfo &aMessageInfo,
-                                        const Ip6::IcmpHeader & aIcmpHeader)
+void AddressResolver::HandleIcmpReceive(Message &                aMessage,
+                                        const Ip6::MessageInfo & aMessageInfo,
+                                        const Ip6::Icmp::Header &aIcmpHeader)
 {
     OT_UNUSED_VARIABLE(aMessageInfo);
 
     Ip6::Header ip6Header;
 
-    VerifyOrExit(aIcmpHeader.GetType() == Ip6::IcmpHeader::kTypeDstUnreach, OT_NOOP);
-    VerifyOrExit(aIcmpHeader.GetCode() == Ip6::IcmpHeader::kCodeDstUnreachNoRoute, OT_NOOP);
+    VerifyOrExit(aIcmpHeader.GetType() == Ip6::Icmp::Header::kTypeDstUnreach, OT_NOOP);
+    VerifyOrExit(aIcmpHeader.GetCode() == Ip6::Icmp::Header::kCodeDstUnreachNoRoute, OT_NOOP);
     VerifyOrExit(aMessage.Read(aMessage.GetOffset(), sizeof(ip6Header), &ip6Header) == sizeof(ip6Header), OT_NOOP);
 
     Remove(ip6Header.GetDestination(), kReasonReceivedIcmpDstUnreachNoRoute);
diff --git a/src/core/thread/address_resolver.hpp b/src/core/thread/address_resolver.hpp
index 7acfaec..881dd8b 100644
--- a/src/core/thread/address_resolver.hpp
+++ b/src/core/thread/address_resolver.hpp
@@ -303,7 +303,9 @@
                                   otMessage *          aMessage,
                                   const otMessageInfo *aMessageInfo,
                                   const otIcmp6Header *aIcmpHeader);
-    void HandleIcmpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo, const Ip6::IcmpHeader &aIcmpHeader);
+    void        HandleIcmpReceive(Message &                aMessage,
+                                  const Ip6::MessageInfo & aMessageInfo,
+                                  const Ip6::Icmp::Header &aIcmpHeader);
 
     static void HandleTimer(Timer &aTimer);
     void        HandleTimer(void);
@@ -327,8 +329,8 @@
     CacheEntryList mQueryList;
     CacheEntryList mQueryRetryList;
 
-    Ip6::IcmpHandler mIcmpHandler;
-    TimerMilli       mTimer;
+    Ip6::Icmp::Handler mIcmpHandler;
+    TimerMilli         mTimer;
 };
 
 /**
diff --git a/src/core/thread/lowpan.cpp b/src/core/thread/lowpan.cpp
index dbccda4..bd4850e 100644
--- a/src/core/thread/lowpan.cpp
+++ b/src/core/thread/lowpan.cpp
@@ -562,12 +562,12 @@
 
 otError Lowpan::CompressUdp(Message &aMessage, BufferWriter &aBuf)
 {
-    otError        error       = OT_ERROR_NONE;
-    BufferWriter   buf         = aBuf;
-    uint16_t       startOffset = aMessage.GetOffset();
-    Ip6::UdpHeader udpHeader;
-    uint16_t       source;
-    uint16_t       destination;
+    otError          error       = OT_ERROR_NONE;
+    BufferWriter     buf         = aBuf;
+    uint16_t         startOffset = aMessage.GetOffset();
+    Ip6::Udp::Header udpHeader;
+    uint16_t         source;
+    uint16_t         destination;
 
     VerifyOrExit(aMessage.Read(aMessage.GetOffset(), sizeof(udpHeader), &udpHeader) == sizeof(udpHeader),
                  error = OT_ERROR_PARSE);
@@ -597,10 +597,11 @@
     else
     {
         SuccessOrExit(error = buf.Write(kUdpDispatch));
-        SuccessOrExit(error = buf.Write(&udpHeader, Ip6::UdpHeader::GetLengthOffset()));
+        SuccessOrExit(error = buf.Write(&udpHeader, Ip6::Udp::Header::kLengthFieldOffset));
     }
 
-    SuccessOrExit(error = buf.Write(reinterpret_cast<uint8_t *>(&udpHeader) + Ip6::UdpHeader::GetChecksumOffset(), 2));
+    SuccessOrExit(error =
+                      buf.Write(reinterpret_cast<uint8_t *>(&udpHeader) + Ip6::Udp::Header::kChecksumFieldOffset, 2));
 
     aMessage.MoveOffset(sizeof(udpHeader));
 
@@ -1010,7 +1011,7 @@
     return (error == OT_ERROR_NONE) ? static_cast<int>(cur - aBuf) : -1;
 }
 
-int Lowpan::DecompressUdpHeader(Ip6::UdpHeader &aUdpHeader, const uint8_t *aBuf, uint16_t aBufLength)
+int Lowpan::DecompressUdpHeader(Ip6::Udp::Header &aUdpHeader, const uint8_t *aBuf, uint16_t aBufLength)
 {
     otError        error = OT_ERROR_PARSE;
     const uint8_t *cur   = aBuf;
@@ -1077,8 +1078,8 @@
 
 int Lowpan::DecompressUdpHeader(Message &aMessage, const uint8_t *aBuf, uint16_t aBufLength, uint16_t aDatagramLength)
 {
-    Ip6::UdpHeader udpHeader;
-    int            headerLen = -1;
+    Ip6::Udp::Header udpHeader;
+    int              headerLen = -1;
 
     headerLen = DecompressUdpHeader(udpHeader, aBuf, aBufLength);
     VerifyOrExit(headerLen >= 0, OT_NOOP);
diff --git a/src/core/thread/lowpan.hpp b/src/core/thread/lowpan.hpp
index 01d972e..13bf9a4 100644
--- a/src/core/thread/lowpan.hpp
+++ b/src/core/thread/lowpan.hpp
@@ -309,7 +309,7 @@
      * @returns The size of the compressed header in bytes or -1 if decompression fails.
      *
      */
-    int DecompressUdpHeader(Ip6::UdpHeader &aUdpHeader, const uint8_t *aBuf, uint16_t aBufLength);
+    int DecompressUdpHeader(Ip6::Udp::Header &aUdpHeader, const uint8_t *aBuf, uint16_t aBufLength);
 
 private:
     enum
diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp
index 4ef78ac..6c183df 100644
--- a/src/core/thread/mesh_forwarder.cpp
+++ b/src/core/thread/mesh_forwarder.cpp
@@ -1242,12 +1242,12 @@
                                         const Mac::Address &aMacDest,
                                         Message::Priority & aPriority)
 {
-    otError         error = OT_ERROR_NONE;
-    Ip6::Header     ip6Header;
-    Ip6::UdpHeader  udpHeader;
-    Ip6::IcmpHeader icmpHeader;
-    uint8_t         headerLength;
-    bool            nextHeaderCompressed;
+    otError           error = OT_ERROR_NONE;
+    Ip6::Header       ip6Header;
+    Ip6::Udp::Header  udpHeader;
+    Ip6::Icmp::Header icmpHeader;
+    uint8_t           headerLength;
+    bool              nextHeaderCompressed;
 
     SuccessOrExit(error = DecompressIp6Header(aFrame, aFrameLength, aMacSource, aMacDest, ip6Header, headerLength,
                                               nextHeaderCompressed));
@@ -1278,8 +1278,8 @@
     }
     else
     {
-        VerifyOrExit(aFrameLength >= sizeof(Ip6::UdpHeader), error = OT_ERROR_PARSE);
-        memcpy(&udpHeader, aFrame, sizeof(Ip6::UdpHeader));
+        VerifyOrExit(aFrameLength >= sizeof(Ip6::Udp::Header), error = OT_ERROR_PARSE);
+        memcpy(&udpHeader, aFrame, sizeof(Ip6::Udp::Header));
     }
 
     if (udpHeader.GetDestinationPort() == Mle::kUdpPort || udpHeader.GetDestinationPort() == kCoapUdpPort)
@@ -1304,8 +1304,8 @@
     otError error = OT_ERROR_PARSE;
     union
     {
-        Ip6::UdpHeader udp;
-        Ip6::TcpHeader tcp;
+        Ip6::Udp::Header udp;
+        Ip6::Tcp::Header tcp;
     } header;
 
     aChecksum   = 0;
@@ -1318,7 +1318,8 @@
     switch (aIp6Header.GetNextHeader())
     {
     case Ip6::kProtoUdp:
-        VerifyOrExit(sizeof(Ip6::UdpHeader) == aMessage.Read(sizeof(Ip6::Header), sizeof(Ip6::UdpHeader), &header.udp),
+        VerifyOrExit(sizeof(Ip6::Udp::Header) ==
+                         aMessage.Read(sizeof(Ip6::Header), sizeof(Ip6::Udp::Header), &header.udp),
                      OT_NOOP);
         aChecksum   = header.udp.GetChecksum();
         aSourcePort = header.udp.GetSourcePort();
@@ -1326,7 +1327,8 @@
         break;
 
     case Ip6::kProtoTcp:
-        VerifyOrExit(sizeof(Ip6::TcpHeader) == aMessage.Read(sizeof(Ip6::Header), sizeof(Ip6::TcpHeader), &header.tcp),
+        VerifyOrExit(sizeof(Ip6::Tcp::Header) ==
+                         aMessage.Read(sizeof(Ip6::Header), sizeof(Ip6::Tcp::Header), &header.tcp),
                      OT_NOOP);
         aChecksum   = header.tcp.GetChecksum();
         aSourcePort = header.tcp.GetSourcePort();
diff --git a/src/core/thread/mesh_forwarder_ftd.cpp b/src/core/thread/mesh_forwarder_ftd.cpp
index 414467f..3110445 100644
--- a/src/core/thread/mesh_forwarder_ftd.cpp
+++ b/src/core/thread/mesh_forwarder_ftd.cpp
@@ -602,8 +602,8 @@
     messageInfo.GetPeerAddr() = Get<Mle::MleRouter>().GetMeshLocal16();
     messageInfo.GetPeerAddr().GetIid().SetLocator(aMeshSource);
 
-    IgnoreError(Get<Ip6::Icmp>().SendError(Ip6::IcmpHeader::kTypeDstUnreach, Ip6::IcmpHeader::kCodeDstUnreachNoRoute,
-                                           messageInfo, aMessage));
+    IgnoreError(Get<Ip6::Icmp>().SendError(Ip6::Icmp::Header::kTypeDstUnreach,
+                                           Ip6::Icmp::Header::kCodeDstUnreachNoRoute, messageInfo, aMessage));
 }
 
 void MeshForwarder::HandleMesh(uint8_t *               aFrame,
@@ -1051,8 +1051,8 @@
     uint16_t frameLength;
     union
     {
-        Ip6::UdpHeader udp;
-        Ip6::TcpHeader tcp;
+        Ip6::Udp::Header udp;
+        Ip6::Tcp::Header tcp;
     } header;
 
     aChecksum   = 0;
@@ -1076,13 +1076,13 @@
     case Ip6::kProtoUdp:
         if (nextHeaderCompressed)
         {
-            frameLength  = aMessage.Read(aOffset, sizeof(Ip6::UdpHeader), frameBuffer);
+            frameLength  = aMessage.Read(aOffset, sizeof(Ip6::Udp::Header), frameBuffer);
             headerLength = Get<Lowpan::Lowpan>().DecompressUdpHeader(header.udp, frameBuffer, frameLength);
             VerifyOrExit(headerLength >= 0, OT_NOOP);
         }
         else
         {
-            VerifyOrExit(sizeof(Ip6::UdpHeader) == aMessage.Read(aOffset, sizeof(Ip6::UdpHeader), &header.udp),
+            VerifyOrExit(sizeof(Ip6::Udp::Header) == aMessage.Read(aOffset, sizeof(Ip6::Udp::Header), &header.udp),
                          OT_NOOP);
         }
 
@@ -1092,7 +1092,8 @@
         break;
 
     case Ip6::kProtoTcp:
-        VerifyOrExit(sizeof(Ip6::TcpHeader) == aMessage.Read(aOffset, sizeof(Ip6::TcpHeader), &header.tcp), OT_NOOP);
+        VerifyOrExit(sizeof(Ip6::Tcp::Header) == aMessage.Read(aOffset, sizeof(Ip6::Tcp::Header), &header.tcp),
+                     OT_NOOP);
         aChecksum   = header.tcp.GetChecksum();
         aSourcePort = header.tcp.GetSourcePort();
         aDestPort   = header.tcp.GetDestinationPort();
diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp
index 5557fc6..a90f8f0 100644
--- a/src/core/thread/mle.hpp
+++ b/src/core/thread/mle.hpp
@@ -1741,8 +1741,8 @@
 
     Challenge mParentCandidateChallenge;
 
-    Ip6::UdpSocket mSocket;
-    uint32_t       mTimeout;
+    Ip6::Udp::Socket mSocket;
+    uint32_t         mTimeout;
 
 #if OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH
     uint16_t mPreviousParentRloc;
diff --git a/tests/unit/test_lowpan.hpp b/tests/unit/test_lowpan.hpp
index 6a1db05..16b5e5a 100644
--- a/tests/unit/test_lowpan.hpp
+++ b/tests/unit/test_lowpan.hpp
@@ -253,12 +253,12 @@
      * This fields represent uncompressed IPv6 packet.
      *
      */
-    Mac::Address   mMacSource;
-    Mac::Address   mMacDestination;
-    Ip6::Header    mIpHeader;
-    Payload        mExtHeader;
-    Ip6::Header    mIpTunneledHeader;
-    Ip6::UdpHeader mUdpHeader;
+    Mac::Address     mMacSource;
+    Mac::Address     mMacDestination;
+    Ip6::Header      mIpHeader;
+    Payload          mExtHeader;
+    Ip6::Header      mIpTunneledHeader;
+    Ip6::Udp::Header mUdpHeader;
 
     /**
      * This fields represent compressed IPv6 packet.