diff --git a/src/core/net/ip4_types.cpp b/src/core/net/ip4_types.cpp index 472dee003..63811d289 100644 --- a/src/core/net/ip4_types.cpp +++ b/src/core/net/ip4_types.cpp @@ -214,5 +214,121 @@ exit: return error; } +//--------------------------------------------------------------------------------------------------------------------- +// Headers + +Error Headers::ParseFrom(const Message &aMessage) +{ + Error error = kErrorParse; + + Clear(); + + SuccessOrExit(mIp4Header.ParseFrom(aMessage)); + + switch (mIp4Header.GetProtocol()) + { + case kProtoUdp: + SuccessOrExit(aMessage.Read(sizeof(Header), mHeader.mUdp)); + break; + case kProtoTcp: + SuccessOrExit(aMessage.Read(sizeof(Header), mHeader.mTcp)); + break; + case kProtoIcmp: + SuccessOrExit(aMessage.Read(sizeof(Header), mHeader.mIcmp)); + break; + default: + break; + } + + error = kErrorNone; + +exit: + return error; +} + +uint16_t Headers::GetSourcePort(void) const +{ + uint16_t port = 0; + + switch (GetIpProto()) + { + case kProtoUdp: + port = mHeader.mUdp.GetSourcePort(); + break; + + case kProtoTcp: + port = mHeader.mTcp.GetSourcePort(); + break; + + default: + break; + } + + return port; +} + +uint16_t Headers::GetDestinationPort(void) const +{ + uint16_t port = 0; + + switch (GetIpProto()) + { + case kProtoUdp: + port = mHeader.mUdp.GetDestinationPort(); + break; + + case kProtoTcp: + port = mHeader.mTcp.GetDestinationPort(); + break; + + default: + break; + } + + return port; +} + +void Headers::SetDestinationPort(uint16_t aDstPort) +{ + switch (GetIpProto()) + { + case kProtoUdp: + mHeader.mUdp.SetDestinationPort(aDstPort); + break; + + case kProtoTcp: + mHeader.mTcp.SetDestinationPort(aDstPort); + break; + + default: + break; + } +} + +uint16_t Headers::GetChecksum(void) const +{ + uint16_t checksum = 0; + + switch (GetIpProto()) + { + case kProtoUdp: + checksum = mHeader.mUdp.GetChecksum(); + break; + + case kProtoTcp: + checksum = mHeader.mTcp.GetChecksum(); + break; + + case kProtoIcmp: + checksum = mHeader.mIcmp.GetChecksum(); + break; + + default: + break; + } + + return checksum; +} + } // namespace Ip4 } // namespace ot diff --git a/src/core/net/ip4_types.hpp b/src/core/net/ip4_types.hpp index 1f67e958e..2743687ad 100644 --- a/src/core/net/ip4_types.hpp +++ b/src/core/net/ip4_types.hpp @@ -619,28 +619,44 @@ public: */ void SetChecksum(uint16_t aChecksum) { mChecksum = BigEndian::HostSwap16(aChecksum); } + /** + * Returns the ICMPv4 message ID for Echo Requests and Replies. + * + * @returns The ICMPv4 message ID. + */ + uint16_t GetId(void) const { return BigEndian::HostSwap16(mData.m16[0]); } + + /** + * Sets the ICMPv4 message ID for Echo Requests and Replies. + * + * @param[in] aId The ICMPv4 message ID. + */ + void SetId(uint16_t aId) { mData.m16[0] = BigEndian::HostSwap16(aId); } + /** * Returns the rest of header field in the ICMP message. * * @returns The rest of header field in the ICMP message. The returned buffer has 4 octets. */ - const uint8_t *GetRestOfHeader(void) const { return mRestOfHeader; } + const uint8_t *GetRestOfHeader(void) const { return mData.m8; } /** * Sets the rest of header field in the ICMP message. * * @param[in] aRestOfHeader The rest of header field in the ICMP message. The buffer should have 4 octets. */ - void SetRestOfHeader(const uint8_t *aRestOfHeader) - { - memcpy(mRestOfHeader, aRestOfHeader, sizeof(mRestOfHeader)); - } + void SetRestOfHeader(const uint8_t *aRestOfHeader) { memcpy(mData.m8, aRestOfHeader, sizeof(mData)); } private: uint8_t mType; uint8_t mCode; uint16_t mChecksum; - uint8_t mRestOfHeader[4]; + union OT_TOOL_PACKED_FIELD + { + uint8_t m8[4]; + uint16_t m16[2]; + uint32_t m32[1]; + } mData; } OT_TOOL_PACKED_END; }; @@ -652,6 +668,155 @@ static constexpr uint8_t kProtoIcmp = 1; ///< ICMP for IPv4 using Tcp = Ip6::Tcp; // TCP in IPv4 is the same as TCP in IPv6 using Udp = Ip6::Udp; // UDP in IPv4 is the same as UDP in IPv6 +/** + * Represents parsed IPv4 header along with UDP/TCP/ICMP4 headers from a received message/frame. + */ +class Headers : private Clearable +{ + friend class Clearable; + +public: + /** + * Parses the IPv4 and UDP/TCP/ICMP4 headers from a given message. + * + * @param[in] aMessage The message to parse the headers from. + * + * @retval kErrorNone The headers are parsed successfully. + * @retval kErrorParse Failed to parse the headers. + */ + Error ParseFrom(const Message &aMessage); + + /** + * Returns the IPv4 header. + * + * @returns The IPv4 header. + */ + const Header &GetIp4Header(void) const { return mIp4Header; } + + /** + * Returns the IP protocol number from IPv4 Protocol field. + * + * @returns The IP protocol number. + */ + uint8_t GetIpProto(void) const { return mIp4Header.GetProtocol(); } + + /** + * Returns the IPv4 header Total length value. + * + * @returns The IPv4 header Total length value. + */ + uint8_t GetIpLength(void) const { return mIp4Header.GetTotalLength(); } + + /** + * Returns the IPv4 TTL value. + * + * @returns The IPv4 TTL value. + */ + uint8_t GetIpTtl(void) const { return mIp4Header.GetTtl(); } + + /** + * Indicates if the protocol number from IPv4 header is UDP. + * + * @retval TRUE If the protocol number in IPv4 header is UDP. + * @retval FALSE If the protocol number in IPv4 header is not UDP. + */ + bool IsUdp(void) const { return GetIpProto() == kProtoUdp; } + + /** + * Indicates if the protocol number from IPv4 header is TCP. + * + * @retval TRUE If the protocol number in IPv4 header is TCP. + * @retval FALSE If the protocol number in IPv4 header is not TCP. + */ + bool IsTcp(void) const { return GetIpProto() == kProtoTcp; } + + /** + * Indicates if the protocol number from IPv4 header is ICMPv4. + * + * @retval TRUE If the protocol number in IPv4 header is ICMPv4. + * @retval FALSE If the protocol number in IPv4 header is not ICMPv4. + */ + bool IsIcmp4(void) const { return GetIpProto() == kProtoIcmp; } + + /** + * Returns the source IPv4 address from IPv4 header. + * + * @returns The source IPv4 address. + */ + const Address &GetSourceAddress(void) const { return mIp4Header.GetSource(); } + + /** + * Returns the destination IPv4 address from IPv4 header. + * + * @returns The destination IPv4 address. + */ + const Address &GetDestinationAddress(void) const { return mIp4Header.GetDestination(); } + + /** + * Returns the UDP header. + * + * MUST be used when `IsUdp() == true`. Otherwise its behavior is undefined + * + * @returns The UDP header. + */ + const Udp::Header &GetUdpHeader(void) const { return mHeader.mUdp; } + + /** + * Returns the TCP header. + * + * MUST be used when `IsTcp() == true`. Otherwise its behavior is undefined + * + * @returns The TCP header. + */ + const Tcp::Header &GetTcpHeader(void) const { return mHeader.mTcp; } + + /** + * Returns the ICMPv4 header. + * + * MUST be used when `IsIcmp4() == true`. Otherwise its behavior is undefined + * + * @returns The ICMPv4 header. + */ + const Icmp::Header &GetIcmpHeader(void) const { return mHeader.mIcmp; } + + /** + * Returns the source port number if the header is UDP or TCP, or zero otherwise + * + * @returns The source port number under UDP / TCP or zero. + */ + uint16_t GetSourcePort(void) const; + + /** + * Returns the destination port number if the header is UDP or TCP, or zero otherwise. + * + * @returns The destination port number under UDP / TCP or zero. + */ + uint16_t GetDestinationPort(void) const; + + /** + * Sets the destination port number if the header is UDP or TCP, does nothing otherwise + * + * @param[in] aDstPort The UDP / TCP destination Port. + */ + void SetDestinationPort(uint16_t aDstPort); + + /** + * Returns the checksum values from corresponding UDP, TCP, or ICMPv4 header. + * + * @returns The checksum value. + */ + uint16_t GetChecksum(void) const; + +private: + Header mIp4Header; + union + { + Udp::Header mUdp; + Tcp::Header mTcp; + Icmp::Header mIcmp; + } mHeader; +}; + /** * @} */ diff --git a/src/core/net/ip6.cpp b/src/core/net/ip6.cpp index 1c635a7d7..972c4f855 100644 --- a/src/core/net/ip6.cpp +++ b/src/core/net/ip6.cpp @@ -1619,6 +1619,23 @@ uint16_t Headers::GetSourcePort(void) const return port; } +void Headers::SetSourcePort(uint16_t aSrcPort) +{ + switch (GetIpProto()) + { + case kProtoUdp: + mHeader.mUdp.SetSourcePort(aSrcPort); + break; + + case kProtoTcp: + mHeader.mTcp.SetSourcePort(aSrcPort); + break; + + default: + break; + } +} + uint16_t Headers::GetDestinationPort(void) const { uint16_t port = 0; diff --git a/src/core/net/ip6.hpp b/src/core/net/ip6.hpp index 9e34cc61d..d06270965 100644 --- a/src/core/net/ip6.hpp +++ b/src/core/net/ip6.hpp @@ -466,6 +466,20 @@ public: */ uint8_t GetIpProto(void) const { return mIp6Header.GetNextHeader(); } + /** + * Returns the IPv6 Payload Length value. + * + * @returns The IPv6 Payload Length value. + */ + uint8_t GetIpLength(void) const { return mIp6Header.GetPayloadLength(); } + + /** + * Returns the IPv6 Hop Limit value. + * + * @returns The IPv6 Hop Limit value. + */ + uint8_t GetIpHopLimit(void) const { return mIp6Header.GetHopLimit(); } + /** * Returns the 2-bit Explicit Congestion Notification (ECN) from Traffic Class field from IPv6 header. * @@ -545,6 +559,13 @@ public: */ uint16_t GetSourcePort(void) const; + /** + * Sets the source port number if the header is UDP or TCP, does nothing otherwise + * + * @param[in] aSrcPort The UDP / TCP source Port. + */ + void SetSourcePort(uint16_t aSrcPort); + /** * Returns the destination port number if header is UDP or TCP, or zero otherwise. * diff --git a/src/core/net/tcp6.hpp b/src/core/net/tcp6.hpp index 158a42873..6c65ff4d2 100644 --- a/src/core/net/tcp6.hpp +++ b/src/core/net/tcp6.hpp @@ -533,6 +533,20 @@ public: */ uint16_t GetDestinationPort(void) const { return BigEndian::HostSwap16(mDestination); } + /** + * Sets the TCP Source Port. + * + * @param[in] aPort The TCP Source Port. + */ + void SetSourcePort(uint16_t aPort) { mSource = BigEndian::HostSwap16(aPort); } + + /** + * Sets the TCP Destination Port. + * + * @param[in] aPort The TCP Destination Port. + */ + void SetDestinationPort(uint16_t aPort) { mDestination = BigEndian::HostSwap16(aPort); } + /** * Returns the TCP Sequence Number. *