1 /* 2 * Copyright (c) 2022, The OpenThread Authors. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. Neither the name of the copyright holder nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /** 30 * @file 31 * This file includes definitions for IPv4 packet processing. 32 */ 33 34 #ifndef IP4_TYPES_HPP_ 35 #define IP4_TYPES_HPP_ 36 37 #include "openthread-core-config.h" 38 39 #include <stddef.h> 40 41 #include <openthread/nat64.h> 42 43 #include "common/clearable.hpp" 44 #include "common/encoding.hpp" 45 #include "common/message.hpp" 46 #include "net/ip6_types.hpp" 47 #include "net/netif.hpp" 48 #include "net/socket.hpp" 49 #include "net/tcp6.hpp" 50 #include "net/udp6.hpp" 51 52 namespace ot { 53 54 namespace Ip6 { 55 // Forward declaration for ExtractFromIp4Address 56 class Address; 57 } // namespace Ip6 58 59 /** 60 * @namespace ot::Ip4 61 * 62 * @brief 63 * This namespace includes definitions for IPv4 networking used by NAT64. 64 */ 65 namespace Ip4 { 66 67 using Ecn = Ip6::Ecn; 68 69 /** 70 * @addtogroup core-ipv4 71 * 72 * @brief 73 * This module includes definitions for the IPv4 network layer. 74 */ 75 76 /** 77 * @addtogroup core-ip4-ip4 78 * 79 * @brief 80 * This module includes definitions for IPv4 networking used by NAT64. 81 * 82 * @{ 83 */ 84 85 // Forward declaration for Address::SynthesizeFromCidrAndHost 86 class Cidr; 87 88 /** 89 * Represents an IPv4 address. 90 */ 91 OT_TOOL_PACKED_BEGIN 92 class Address : public otIp4Address, public Equatable<Address>, public Clearable<Address> 93 { 94 public: 95 static constexpr uint16_t kSize = 4; ///< Size of an IPv4 Address (in bytes). 96 static constexpr uint16_t kAddressStringSize = 17; ///< String size used by `ToString()`. 97 98 /** 99 * Defines the fixed-length `String` object returned from `ToString()`. 100 */ 101 typedef String<kAddressStringSize> InfoString; 102 103 /** 104 * Gets the IPv4 address as a pointer to a byte array. 105 * 106 * @returns A pointer to a byte array containing the IPv4 address. 107 */ GetBytes(void) const108 const uint8_t *GetBytes(void) const { return mFields.m8; } 109 110 /** 111 * Sets the IPv4 address from a given byte array. 112 * 113 * @param[in] aBuffer Pointer to an array containing the IPv4 address. `kSize` bytes from the buffer 114 * are copied to form the IPv4 address. 115 */ SetBytes(const uint8_t * aBuffer)116 void SetBytes(const uint8_t *aBuffer) { memcpy(mFields.m8, aBuffer, kSize); } 117 118 /** 119 * Sets the IPv4 address from a given IPv4-mapped IPv6 address. 120 * 121 * @param[in] aIp6Address An IPv6 address. 122 * 123 * @retval kErrorNone Set the IPv4 address successfully. 124 * @retval kErrorPase The @p aIp6Address does not follow the IPv4-mapped IPv6 address format. 125 */ 126 Error ExtractFromIp4MappedIp6Address(const Ip6::Address &aIp6Address); 127 128 /** 129 * Sets the IPv4 address by performing NAT64 address translation from a given IPv6 address as specified 130 * in RFC 6052. 131 * 132 * The NAT64 @p aPrefixLength MUST be one of the following values: 32, 40, 48, 56, 64, or 96, otherwise the behavior 133 * of this method is undefined. 134 * 135 * @param[in] aPrefixLength The prefix length to use for IPv4/IPv6 translation. 136 * @param[in] aIp6Address The IPv6 address to translate to IPv4. 137 */ 138 void ExtractFromIp6Address(uint8_t aPrefixLength, const Ip6::Address &aIp6Address); 139 140 /** 141 * Sets the IPv4 address from the given CIDR and the host field. 142 * 143 * @param[in] aCidr The CIDR for the IPv4 address. 144 * @param[in] aHost The host bits of the IPv4 address in host byte order. The aHost will be masked by host mask. 145 */ 146 void SynthesizeFromCidrAndHost(const Cidr &aCidr, uint32_t aHost); 147 148 /** 149 * Parses an IPv4 address string terminated by `aTerminatorChar`. 150 * 151 * The string MUST follow the quad-dotted notation of four decimal values (ranging from 0 to 255 each). For 152 * example, "127.0.0.1" 153 * 154 * @param[in] aString A pointer to the null-terminated string. 155 * 156 * @retval kErrorNone Successfully parsed the IPv4 address string. 157 * @retval kErrorParse Failed to parse the IPv4 address string. 158 */ 159 Error FromString(const char *aString, char aTerminatorChar = kNullChar); 160 161 /** 162 * Converts the address to a string. 163 * 164 * The string format uses quad-dotted notation of four bytes in the address (e.g., "127.0.0.1"). 165 * 166 * If the resulting string does not fit in @p aBuffer (within its @p aSize characters), the string will be 167 * truncated but the outputted string is always null-terminated. 168 * 169 * @param[out] aBuffer A pointer to a char array to output the string (MUST NOT be `nullptr`). 170 * @param[in] aSize The size of @p aBuffer (in bytes). 171 */ 172 void ToString(char *aBuffer, uint16_t aSize) const; 173 174 /** 175 * Converts the IPv4 address to a string. 176 * 177 * The string format uses quad-dotted notation of four bytes in the address (e.g., "127.0.0.1"). 178 * 179 * @returns An `InfoString` representing the IPv4 address. 180 */ 181 InfoString ToString(void) const; 182 183 private: 184 void ToString(StringWriter &aWriter) const; 185 } OT_TOOL_PACKED_END; 186 187 /** 188 * Represents an IPv4 CIDR block. 189 */ 190 class Cidr : public otIp4Cidr, public Unequatable<Cidr>, public Clearable<Address> 191 { 192 friend class Address; 193 194 public: 195 static constexpr uint16_t kCidrSuffixSize = 3; ///< Suffix to represent CIDR (/dd). 196 197 /** 198 * Defines the fixed-length `String` object returned from `ToString()`. 199 */ 200 typedef String<Address::kAddressStringSize + kCidrSuffixSize> InfoString; 201 202 /** 203 * Converts the IPv4 CIDR string to binary. 204 * 205 * The string format uses quad-dotted notation of four bytes in the address with the length of prefix (e.g., 206 * "127.0.0.1/32"). 207 * 208 * @param[in] aString A pointer to the null-terminated string. 209 * 210 * @retval kErrorNone Successfully parsed the IPv4 CIDR string. 211 * @retval kErrorParse Failed to parse the IPv4 CIDR string. 212 */ 213 Error FromString(const char *aString); 214 215 /** 216 * Converts the IPv4 CIDR to a string. 217 * 218 * The string format uses quad-dotted notation of four bytes in the address with the length of prefix (e.g., 219 * "127.0.0.1/32"). 220 * 221 * If the resulting string does not fit in @p aBuffer (within its @p aSize characters), the string will be 222 * truncated but the outputted string is always null-terminated. 223 * 224 * @param[out] aBuffer A pointer to a char array to output the string (MUST NOT be `nullptr`). 225 * @param[in] aSize The size of @p aBuffer (in bytes). 226 */ 227 void ToString(char *aBuffer, uint16_t aSize) const; 228 229 /** 230 * Converts the IPv4 CIDR to a string. 231 * 232 * The string format uses quad-dotted notation of four bytes in the address with the length of prefix (e.g., 233 * "127.0.0.1/32"). 234 * 235 * @returns An `InfoString` representing the IPv4 cidr. 236 */ 237 InfoString ToString(void) const; 238 239 /** 240 * Gets the prefix as a pointer to a byte array. 241 * 242 * @returns A pointer to a byte array containing the Prefix. 243 */ GetBytes(void) const244 const uint8_t *GetBytes(void) const { return mAddress.mFields.m8; } 245 246 /** 247 * Overloads operator `==` to evaluate whether or not two prefixes are equal. 248 * 249 * @param[in] aOther The other prefix to compare with. 250 * 251 * @retval TRUE If the two prefixes are equal. 252 * @retval FALSE If the two prefixes are not equal. 253 */ 254 bool operator==(const Cidr &aOther) const; 255 256 /** 257 * Sets the CIDR. 258 * 259 * @param[in] aAddress A pointer to buffer containing the CIDR bytes. The length of aAddress should be 4 bytes. 260 * @param[in] aLength The length of CIDR in bits. 261 */ 262 void Set(const uint8_t *aAddress, uint8_t aLength); 263 264 private: HostMask(void) const265 uint32_t HostMask(void) const 266 { 267 // Note: Using LL suffix to make it a uint64 since /32 is a valid CIDR, and right shifting 32 bits is undefined 268 // for uint32. 269 return BigEndian::HostSwap32(0xffffffffLL >> mLength); 270 } 271 SubnetMask(void) const272 uint32_t SubnetMask(void) const { return ~HostMask(); } 273 274 void ToString(StringWriter &aWriter) const; 275 }; 276 277 /** 278 * Implements IPv4 header generation and parsing. 279 */ 280 OT_TOOL_PACKED_BEGIN 281 class Header : public Clearable<Header> 282 { 283 public: 284 static constexpr uint8_t kVersionIhlOffset = 0; 285 static constexpr uint8_t kTrafficClassOffset = 1; 286 static constexpr uint8_t kTotalLengthOffset = 2; 287 static constexpr uint8_t kIdentificationOffset = 4; 288 static constexpr uint8_t kFlagsFragmentOffset = 6; 289 static constexpr uint8_t kTtlOffset = 8; 290 static constexpr uint8_t kProtocolOffset = 9; 291 static constexpr uint8_t kHeaderChecksumOffset = 10; 292 static constexpr uint8_t kSourceAddressOffset = 12; 293 static constexpr uint8_t kDestinationAddressOffset = 16; 294 295 /** 296 * Indicates whether or not the header appears to be well-formed. 297 * 298 * @retval TRUE If the header appears to be well-formed. 299 * @retval FALSE If the header does not appear to be well-formed. 300 */ IsValid(void) const301 bool IsValid(void) const { return IsVersion4(); } 302 303 /** 304 * Initializes the Version to 4 and sets Traffic Class and Flow fields to zero. 305 * 306 * The other fields in the IPv4 header remain unchanged. 307 */ InitVersionIhl(void)308 void InitVersionIhl(void) { SetVersionIhl(kVersIhlInit); } 309 310 /** 311 * Sets the version and Ihl of the IPv4 header. 312 * 313 * @param[in] aVersionIhl The octet for the version and Ihl field. 314 */ SetVersionIhl(uint8_t aVersionIhl)315 void SetVersionIhl(uint8_t aVersionIhl) { mVersIhl = aVersionIhl; } 316 317 /** 318 * Indicates whether or not the IPv4 Version is set to 6. 319 * 320 * @retval TRUE If the IPv4 Version is set to 4. 321 * @retval FALSE If the IPv4 Version is not set to 4. 322 */ IsVersion4(void) const323 bool IsVersion4(void) const { return (mVersIhl & kVersionMask) == kVersion4; } 324 325 /** 326 * Returns the octet for DSCP + ECN. 327 * 328 * @retval The octet for DSCP and ECN. 329 */ GetDscpEcn(void) const330 uint8_t GetDscpEcn(void) const { return mDscpEcn; } 331 332 /** 333 * Gets the 6-bit Differentiated Services Code Point (DSCP) from Traffic Class field. 334 * 335 * @returns The DSCP value. 336 */ GetDscp(void) const337 uint8_t GetDscp(void) const { return (mDscpEcn & kDscpMask) >> kDscpOffset; } 338 339 /** 340 * Sets 6-bit Differentiated Services Code Point (DSCP) in IPv4 header. 341 * 342 * @param[in] aDscp The DSCP value. 343 */ SetDscp(uint8_t aDscp)344 void SetDscp(uint8_t aDscp) { mDscpEcn = static_cast<uint8_t>((mDscpEcn & ~kDscpMask) | (aDscp << kDscpOffset)); } 345 346 /** 347 * Gets the 2-bit Explicit Congestion Notification (ECN) from Traffic Class field. 348 * 349 * @returns The ECN value. 350 */ GetEcn(void) const351 Ecn GetEcn(void) const { return static_cast<Ecn>(mDscpEcn & kEcnMask); } 352 353 /** 354 * Sets the 2-bit Explicit Congestion Notification (ECN) in IPv4 header.. 355 * 356 * @param[in] aEcn The ECN value. 357 */ SetEcn(Ecn aEcn)358 void SetEcn(Ecn aEcn) { mDscpEcn = ((mDscpEcn & ~kEcnMask) | aEcn); } 359 360 /** 361 * Returns the IPv4 Payload Length value. 362 * 363 * @returns The IPv4 Payload Length value. 364 */ GetTotalLength(void) const365 uint16_t GetTotalLength(void) const { return BigEndian::HostSwap16(mTotalLength); } 366 367 /** 368 * Sets the IPv4 Payload Length value. 369 * 370 * @param[in] aLength The IPv4 Payload Length value. 371 */ SetTotalLength(uint16_t aLength)372 void SetTotalLength(uint16_t aLength) { mTotalLength = BigEndian::HostSwap16(aLength); } 373 374 /** 375 * Returns the IPv4 payload protocol. 376 * 377 * @returns The IPv4 payload protocol value. 378 */ GetProtocol(void) const379 uint8_t GetProtocol(void) const { return mProtocol; } 380 381 /** 382 * Sets the IPv4 payload protocol. 383 * 384 * @param[in] aProtocol The IPv4 payload protocol. 385 */ SetProtocol(uint8_t aProtocol)386 void SetProtocol(uint8_t aProtocol) { mProtocol = aProtocol; } 387 388 /** 389 * Returns the IPv4 header checksum, the checksum is in host endian. 390 * 391 * @returns The checksum field in the IPv4 header. 392 */ GetChecksum(void) const393 uint16_t GetChecksum(void) const { return BigEndian::HostSwap16(mHeaderChecksum); } 394 395 /** 396 * Sets the IPv4 header checksum, the checksum is in host endian. 397 * 398 * @param[in] aChecksum The checksum for the IPv4 header. 399 */ SetChecksum(uint16_t aChecksum)400 void SetChecksum(uint16_t aChecksum) { mHeaderChecksum = BigEndian::HostSwap16(aChecksum); } 401 402 /** 403 * Returns the IPv4 Identification value. 404 * 405 * @returns The IPv4 Identification value. 406 */ GetIdentification(void) const407 uint16_t GetIdentification(void) const { return BigEndian::HostSwap16(mIdentification); } 408 409 /** 410 * Sets the IPv4 Identification value. 411 * 412 * @param[in] aIdentification The IPv4 Identification value. 413 */ SetIdentification(uint16_t aIdentification)414 void SetIdentification(uint16_t aIdentification) { mIdentification = BigEndian::HostSwap16(aIdentification); } 415 416 /** 417 * Returns the IPv4 Time-to-Live value. 418 * 419 * @returns The IPv4 Time-to-Live value. 420 */ GetTtl(void) const421 uint8_t GetTtl(void) const { return mTtl; } 422 423 /** 424 * Sets the IPv4 Time-to-Live value. 425 * 426 * @param[in] aTtl The IPv4 Time-to-Live value. 427 */ SetTtl(uint8_t aTtl)428 void SetTtl(uint8_t aTtl) { mTtl = aTtl; } 429 430 /** 431 * Returns the IPv4 Source address. 432 * 433 * @returns A reference to the IPv4 Source address. 434 */ GetSource(void)435 Address &GetSource(void) { return mSource; } 436 437 /** 438 * Returns the IPv4 Source address. 439 * 440 * @returns A reference to the IPv4 Source address. 441 */ GetSource(void) const442 const Address &GetSource(void) const { return mSource; } 443 444 /** 445 * Sets the IPv4 Source address. 446 * 447 * @param[in] aSource A reference to the IPv4 Source address. 448 */ SetSource(const Address & aSource)449 void SetSource(const Address &aSource) { mSource = aSource; } 450 451 /** 452 * Returns the IPv4 Destination address. 453 * 454 * @returns A reference to the IPv4 Destination address. 455 */ GetDestination(void)456 Address &GetDestination(void) { return mDestination; } 457 458 /** 459 * Returns the IPv4 Destination address. 460 * 461 * @returns A reference to the IPv4 Destination address. 462 */ GetDestination(void) const463 const Address &GetDestination(void) const { return mDestination; } 464 465 /** 466 * Sets the IPv4 Destination address. 467 * 468 * @param[in] aDestination A reference to the IPv4 Destination address. 469 */ SetDestination(const Address & aDestination)470 void SetDestination(const Address &aDestination) { mDestination = aDestination; } 471 472 /** 473 * Parses and validates the IPv4 header from a given message. 474 * 475 * The header is read from @p aMessage at offset zero. 476 * 477 * @param[in] aMessage The IPv4 message. 478 * 479 * @retval kErrorNone Successfully parsed the IPv4 header from @p aMessage. 480 * @retval kErrorParse Malformed IPv4 header or message (e.g., message does not contained expected payload length). 481 */ 482 Error ParseFrom(const Message &aMessage); 483 484 /** 485 * Returns the Df flag in the IPv4 header. 486 * 487 * @returns Whether don't fragment flag is set. 488 */ GetDf(void) const489 bool GetDf(void) const { return BigEndian::HostSwap16(mFlagsFragmentOffset) & kFlagsDf; } 490 491 /** 492 * Returns the Mf flag in the IPv4 header. 493 * 494 * @returns Whether more fragments flag is set. 495 */ GetMf(void) const496 bool GetMf(void) const { return BigEndian::HostSwap16(mFlagsFragmentOffset) & kFlagsMf; } 497 498 /** 499 * Returns the fragment offset in the IPv4 header. 500 * 501 * @returns The fragment offset of the IPv4 packet. 502 */ GetFragmentOffset(void) const503 uint16_t GetFragmentOffset(void) const { return BigEndian::HostSwap16(mFlagsFragmentOffset) & kFragmentOffsetMask; } 504 505 private: 506 // IPv4 header 507 // 508 // +---------------+---------------+---------------+---------------+ 509 // |7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0| 510 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 511 // |Version| IHL | DSCP |ECN| Total Length | 512 // | Identification |Flags| Fragment Offset | 513 // | TTL | Protocol | Header Checksum | 514 // | Source IP Address | 515 // | Dest IP Address | 516 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 517 518 static constexpr uint8_t kVersion4 = 0x40; // Use with `mVersIhl` 519 static constexpr uint8_t kVersionMask = 0xf0; // Use with `mVersIhl` 520 static constexpr uint8_t kIhlMask = 0x0f; // Use with `mVersIhl` 521 static constexpr uint8_t kDscpOffset = 2; // Use with `mDscpEcn` 522 static constexpr uint16_t kDscpMask = 0xfc; // Use with `mDscpEcn` 523 static constexpr uint8_t kEcnOffset = 0; // Use with `mDscpEcn` 524 static constexpr uint8_t kEcnMask = 0x03; // Use with `mDscpEcn` 525 static constexpr uint16_t kFlagsMask = 0xe000; // Use with `mFlagsFragmentOffset` 526 static constexpr uint16_t kFlagsDf = 0x4000; // Use with `mFlagsFragmentOffset` 527 static constexpr uint16_t kFlagsMf = 0x2000; // Use with `mFlagsFragmentOffset` 528 static constexpr uint16_t kFragmentOffsetMask = 0x1fff; // Use with `mFlagsFragmentOffset` 529 static constexpr uint32_t kVersIhlInit = 0x45; // Version 4, Header length = 5x8 bytes. 530 531 uint8_t mVersIhl; 532 uint8_t mDscpEcn; 533 uint16_t mTotalLength; 534 uint16_t mIdentification; 535 uint16_t mFlagsFragmentOffset; 536 uint8_t mTtl; 537 uint8_t mProtocol; 538 uint16_t mHeaderChecksum; 539 Address mSource; 540 Address mDestination; 541 } OT_TOOL_PACKED_END; 542 543 /** 544 * Implements ICMP(v4). 545 * Note: ICMP(v4) messages will only be generated / handled by NAT64. So only header definition is required. 546 */ 547 class Icmp 548 { 549 public: 550 /** 551 * Represents an IPv4 ICMP header. 552 */ 553 OT_TOOL_PACKED_BEGIN 554 class Header : public Clearable<Header> 555 { 556 public: 557 static constexpr uint16_t kChecksumFieldOffset = 2; 558 // A few ICMP types, only the ICMP types work with NAT64 are listed here. 559 enum Type : uint8_t 560 { 561 kTypeEchoReply = 0, 562 kTypeDestinationUnreachable = 3, 563 kTypeEchoRequest = 8, 564 kTypeTimeExceeded = 11, 565 }; 566 567 enum Code : uint8_t 568 { 569 kCodeNone = 0, 570 // Destination Unreachable codes 571 kCodeNetworkUnreachable = 0, 572 kCodeHostUnreachable = 1, 573 kCodeProtocolUnreachable = 2, 574 kCodePortUnreachable = 3, 575 kCodeSourceRouteFailed = 5, 576 kCodeNetworkUnknown = 6, 577 kCodeHostUnknown = 7, 578 }; 579 580 /** 581 * Returns the type of the ICMP message. 582 * 583 * @returns The type field of the ICMP message. 584 */ GetType(void) const585 uint8_t GetType(void) const { return mType; } 586 587 /** 588 * Sets the type of the ICMP message. 589 * 590 * @param[in] aType The type of the ICMP message. 591 */ SetType(uint8_t aType)592 void SetType(uint8_t aType) { mType = aType; } 593 594 /** 595 * Returns the code of the ICMP message. 596 * 597 * @returns The code field of the ICMP message. 598 */ GetCode(void) const599 uint8_t GetCode(void) const { return mCode; } 600 601 /** 602 * Sets the code of the ICMP message. 603 * 604 * @param[in] aCode The code of the ICMP message. 605 */ SetCode(uint8_t aCode)606 void SetCode(uint8_t aCode) { mCode = aCode; } 607 608 /** 609 * Sets the checksum field in the ICMP message. 610 * 611 * @returns The checksum of the ICMP message. 612 */ GetChecksum(void) const613 uint16_t GetChecksum(void) const { return BigEndian::HostSwap16(mChecksum); } 614 615 /** 616 * Sets the checksum field in the ICMP message. 617 * 618 * @param[in] aChecksum The checksum of the ICMP message. 619 */ SetChecksum(uint16_t aChecksum)620 void SetChecksum(uint16_t aChecksum) { mChecksum = BigEndian::HostSwap16(aChecksum); } 621 622 /** 623 * Returns the ICMPv4 message ID for Echo Requests and Replies. 624 * 625 * @returns The ICMPv4 message ID. 626 */ GetId(void) const627 uint16_t GetId(void) const { return BigEndian::HostSwap16(mData.m16[0]); } 628 629 /** 630 * Sets the ICMPv4 message ID for Echo Requests and Replies. 631 * 632 * @param[in] aId The ICMPv4 message ID. 633 */ SetId(uint16_t aId)634 void SetId(uint16_t aId) { mData.m16[0] = BigEndian::HostSwap16(aId); } 635 636 /** 637 * Returns the rest of header field in the ICMP message. 638 * 639 * @returns The rest of header field in the ICMP message. The returned buffer has 4 octets. 640 */ GetRestOfHeader(void) const641 const uint8_t *GetRestOfHeader(void) const { return mData.m8; } 642 643 /** 644 * Sets the rest of header field in the ICMP message. 645 * 646 * @param[in] aRestOfHeader The rest of header field in the ICMP message. The buffer should have 4 octets. 647 */ SetRestOfHeader(const uint8_t * aRestOfHeader)648 void SetRestOfHeader(const uint8_t *aRestOfHeader) { memcpy(mData.m8, aRestOfHeader, sizeof(mData)); } 649 650 private: 651 uint8_t mType; 652 uint8_t mCode; 653 uint16_t mChecksum; 654 union OT_TOOL_PACKED_FIELD 655 { 656 uint8_t m8[4]; 657 uint16_t m16[2]; 658 uint32_t m32[1]; 659 } mData; 660 } OT_TOOL_PACKED_END; 661 }; 662 663 // Internet Protocol Numbers 664 static constexpr uint8_t kProtoTcp = Ip6::kProtoTcp; ///< Transmission Control Protocol 665 static constexpr uint8_t kProtoUdp = Ip6::kProtoUdp; ///< User Datagram 666 static constexpr uint8_t kProtoIcmp = 1; ///< ICMP for IPv4 667 668 using Tcp = Ip6::Tcp; // TCP in IPv4 is the same as TCP in IPv6 669 using Udp = Ip6::Udp; // UDP in IPv4 is the same as UDP in IPv6 670 671 /** 672 * Represents parsed IPv4 header along with UDP/TCP/ICMP4 headers from a received message/frame. 673 */ 674 class Headers : private Clearable<Headers> 675 { 676 friend class Clearable<Headers>; 677 678 public: 679 /** 680 * Parses the IPv4 and UDP/TCP/ICMP4 headers from a given message. 681 * 682 * @param[in] aMessage The message to parse the headers from. 683 * 684 * @retval kErrorNone The headers are parsed successfully. 685 * @retval kErrorParse Failed to parse the headers. 686 */ 687 Error ParseFrom(const Message &aMessage); 688 689 /** 690 * Returns the IPv4 header. 691 * 692 * @returns The IPv4 header. 693 */ GetIp4Header(void) const694 const Header &GetIp4Header(void) const { return mIp4Header; } 695 696 /** 697 * Returns the IP protocol number from IPv4 Protocol field. 698 * 699 * @returns The IP protocol number. 700 */ GetIpProto(void) const701 uint8_t GetIpProto(void) const { return mIp4Header.GetProtocol(); } 702 703 /** 704 * Returns the IPv4 header Total length value. 705 * 706 * @returns The IPv4 header Total length value. 707 */ GetIpLength(void) const708 uint8_t GetIpLength(void) const { return mIp4Header.GetTotalLength(); } 709 710 /** 711 * Returns the IPv4 TTL value. 712 * 713 * @returns The IPv4 TTL value. 714 */ GetIpTtl(void) const715 uint8_t GetIpTtl(void) const { return mIp4Header.GetTtl(); } 716 717 /** 718 * Indicates if the protocol number from IPv4 header is UDP. 719 * 720 * @retval TRUE If the protocol number in IPv4 header is UDP. 721 * @retval FALSE If the protocol number in IPv4 header is not UDP. 722 */ IsUdp(void) const723 bool IsUdp(void) const { return GetIpProto() == kProtoUdp; } 724 725 /** 726 * Indicates if the protocol number from IPv4 header is TCP. 727 * 728 * @retval TRUE If the protocol number in IPv4 header is TCP. 729 * @retval FALSE If the protocol number in IPv4 header is not TCP. 730 */ IsTcp(void) const731 bool IsTcp(void) const { return GetIpProto() == kProtoTcp; } 732 733 /** 734 * Indicates if the protocol number from IPv4 header is ICMPv4. 735 * 736 * @retval TRUE If the protocol number in IPv4 header is ICMPv4. 737 * @retval FALSE If the protocol number in IPv4 header is not ICMPv4. 738 */ IsIcmp4(void) const739 bool IsIcmp4(void) const { return GetIpProto() == kProtoIcmp; } 740 741 /** 742 * Returns the source IPv4 address from IPv4 header. 743 * 744 * @returns The source IPv4 address. 745 */ GetSourceAddress(void) const746 const Address &GetSourceAddress(void) const { return mIp4Header.GetSource(); } 747 748 /** 749 * Returns the destination IPv4 address from IPv4 header. 750 * 751 * @returns The destination IPv4 address. 752 */ GetDestinationAddress(void) const753 const Address &GetDestinationAddress(void) const { return mIp4Header.GetDestination(); } 754 755 /** 756 * Returns the UDP header. 757 * 758 * MUST be used when `IsUdp() == true`. Otherwise its behavior is undefined 759 * 760 * @returns The UDP header. 761 */ GetUdpHeader(void) const762 const Udp::Header &GetUdpHeader(void) const { return mHeader.mUdp; } 763 764 /** 765 * Returns the TCP header. 766 * 767 * MUST be used when `IsTcp() == true`. Otherwise its behavior is undefined 768 * 769 * @returns The TCP header. 770 */ GetTcpHeader(void) const771 const Tcp::Header &GetTcpHeader(void) const { return mHeader.mTcp; } 772 773 /** 774 * Returns the ICMPv4 header. 775 * 776 * MUST be used when `IsIcmp4() == true`. Otherwise its behavior is undefined 777 * 778 * @returns The ICMPv4 header. 779 */ GetIcmpHeader(void) const780 const Icmp::Header &GetIcmpHeader(void) const { return mHeader.mIcmp; } 781 782 /** 783 * Returns the source port number if the header is UDP or TCP, or zero otherwise 784 * 785 * @returns The source port number under UDP / TCP or zero. 786 */ 787 uint16_t GetSourcePort(void) const; 788 789 /** 790 * Returns the destination port number if the header is UDP or TCP, or zero otherwise. 791 * 792 * @returns The destination port number under UDP / TCP or zero. 793 */ 794 uint16_t GetDestinationPort(void) const; 795 796 /** 797 * Sets the destination port number if the header is UDP or TCP, does nothing otherwise 798 * 799 * @param[in] aDstPort The UDP / TCP destination Port. 800 */ 801 void SetDestinationPort(uint16_t aDstPort); 802 803 /** 804 * Returns the checksum values from corresponding UDP, TCP, or ICMPv4 header. 805 * 806 * @returns The checksum value. 807 */ 808 uint16_t GetChecksum(void) const; 809 810 private: 811 Header mIp4Header; 812 union 813 { 814 Udp::Header mUdp; 815 Tcp::Header mTcp; 816 Icmp::Header mIcmp; 817 } mHeader; 818 }; 819 820 /** 821 * @} 822 */ 823 824 } // namespace Ip4 825 826 DefineCoreType(otIp4Address, Ip4::Address); 827 DefineCoreType(otIp4Cidr, Ip4::Cidr); 828 829 } // namespace ot 830 831 #endif // IP4_TYPES_HPP_ 832