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 */ 66 namespace Ip4 { 67 68 using Encoding::BigEndian::HostSwap16; 69 using Encoding::BigEndian::HostSwap32; 70 71 using Ecn = Ip6::Ecn; 72 73 /** 74 * @addtogroup core-ipv4 75 * 76 * @brief 77 * This module includes definitions for the IPv4 network layer. 78 * 79 */ 80 81 /** 82 * @addtogroup core-ip4-ip4 83 * 84 * @brief 85 * This module includes definitions for IPv4 networking used by NAT64. 86 * 87 * @{ 88 * 89 */ 90 91 // Forward declaration for Address::SynthesizeFromCidrAndHost 92 class Cidr; 93 94 /** 95 * This class represents an IPv4 address. 96 * 97 */ 98 OT_TOOL_PACKED_BEGIN 99 class Address : public otIp4Address, public Equatable<Address>, public Clearable<Address> 100 { 101 public: 102 static constexpr uint16_t kSize = 4; ///< Size of an IPv4 Address (in bytes). 103 static constexpr uint16_t kAddressStringSize = 17; ///< String size used by `ToString()`. 104 105 /** 106 * This type defines the fixed-length `String` object returned from `ToString()`. 107 * 108 */ 109 typedef String<kAddressStringSize> InfoString; 110 111 /** 112 * This method gets the IPv4 address as a pointer to a byte array. 113 * 114 * @returns A pointer to a byte array containing the IPv4 address. 115 * 116 */ GetBytes(void) const117 const uint8_t *GetBytes(void) const { return mFields.m8; } 118 119 /** 120 * This method sets the IPv4 address from a given byte array. 121 * 122 * @param[in] aBuffer Pointer to an array containing the IPv4 address. `kSize` bytes from the buffer 123 * are copied to form the IPv4 address. 124 * 125 */ SetBytes(const uint8_t * aBuffer)126 void SetBytes(const uint8_t *aBuffer) { memcpy(mFields.m8, aBuffer, kSize); } 127 128 /** 129 * This method 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 */ 139 void ExtractFromIp6Address(uint8_t aPrefixLength, const Ip6::Address &aIp6Address); 140 141 /** 142 * This method sets the IPv4 address from the given CIDR and the host field. 143 * 144 * @param[in] aCidr The CIDR for the IPv4 address. 145 * @param[in] aHost The host bits of the IPv4 address in host byte order. The aHost will be masked by host mask. 146 * 147 */ 148 void SynthesizeFromCidrAndHost(const Cidr &aCidr, uint32_t aHost); 149 150 /** 151 * This method parses an IPv4 address string. 152 * 153 * The string MUST follow the quad-dotted notation of four decimal values (ranging from 0 to 255 each). For 154 * example, "127.0.0.1" 155 * 156 * @param[in] aString A pointer to the null-terminated string. 157 * 158 * @retval kErrorNone Successfully parsed the IPv4 address string. 159 * @retval kErrorParse Failed to parse the IPv4 address string. 160 * 161 */ 162 Error FromString(const char *aString); 163 164 /** 165 * This method converts the IPv4 address to a string. 166 * 167 * The string format uses quad-dotted notation of four bytes in the address (e.g., "127.0.0.1"). 168 * 169 * @returns An `InfoString` representing the IPv4 address. 170 * 171 */ 172 InfoString ToString(void) const; 173 } OT_TOOL_PACKED_END; 174 175 /** 176 * This class represents an IPv4 CIDR block. 177 * 178 */ 179 class Cidr : public otIp4Cidr, public Unequatable<Cidr>, public Clearable<Address> 180 { 181 friend class Address; 182 183 public: 184 static constexpr uint16_t kCidrSuffixSize = 3; ///< Suffix to represent CIDR (/dd). 185 186 /** 187 * This type defines the fixed-length `String` object returned from `ToString()`. 188 * 189 */ 190 typedef String<Address::kAddressStringSize + kCidrSuffixSize> InfoString; 191 192 /** 193 * This method converts the IPv4 CIDR to a string. 194 * 195 * The string format uses quad-dotted notation of four bytes in the address with the length of prefix (e.g., 196 * "127.0.0.1/32"). 197 * 198 * @returns An `InfoString` representing the IPv4 cidr. 199 * 200 */ 201 InfoString ToString(void) const; 202 203 /** 204 * This method gets the prefix as a pointer to a byte array. 205 * 206 * @returns A pointer to a byte array containing the Prefix. 207 * 208 */ GetBytes(void) const209 const uint8_t *GetBytes(void) const { return mAddress.mFields.m8; } 210 211 /** 212 * This method overloads operator `==` to evaluate whether or not two prefixes are equal. 213 * 214 * @param[in] aOther The other prefix to compare with. 215 * 216 * @retval TRUE If the two prefixes are equal. 217 * @retval FALSE If the two prefixes are not equal. 218 * 219 */ 220 bool operator==(const Cidr &aOther) const; 221 222 /** 223 * This method sets the CIDR. 224 * 225 * @param[in] aAddress A pointer to buffer containing the CIDR bytes. The length of aAddress should be 4 bytes. 226 * @param[in] aLength The length of CIDR in bits. 227 * 228 */ 229 void Set(const uint8_t *aAddress, uint8_t aLength); 230 231 private: HostMask(void) const232 uint32_t HostMask(void) const 233 { 234 // Note: Using LL suffix to make it a uint64 since /32 is a valid CIDR, and right shifting 32 bits is undefined 235 // for uint32. 236 return HostSwap32(0xffffffffLL >> mLength); 237 } 238 SubnetMask(void) const239 uint32_t SubnetMask(void) const { return ~HostMask(); } 240 }; 241 242 /** 243 * This class implements IPv4 header generation and parsing. 244 * 245 */ 246 OT_TOOL_PACKED_BEGIN 247 class Header : public Clearable<Header> 248 { 249 public: 250 static constexpr uint8_t kVersionIhlOffset = 0; 251 static constexpr uint8_t kTrafficClassOffset = 1; 252 static constexpr uint8_t kTotalLengthOffset = 2; 253 static constexpr uint8_t kIdenficationOffset = 4; 254 static constexpr uint8_t kFlagsFragmentOffset = 6; 255 static constexpr uint8_t kTtlOffset = 8; 256 static constexpr uint8_t kProtocolOffset = 9; 257 static constexpr uint8_t kHeaderChecksumOffset = 10; 258 static constexpr uint8_t kSourceAddressOffset = 12; 259 static constexpr uint8_t kDestinationAddressOffset = 16; 260 261 /** 262 * This method indicates whether or not the header appears to be well-formed. 263 * 264 * @retval TRUE If the header appears to be well-formed. 265 * @retval FALSE If the header does not appear to be well-formed. 266 * 267 */ IsValid(void) const268 bool IsValid(void) const { return IsVersion4(); } 269 270 /** 271 * This method initializes the Version to 4 and sets Traffic Class and Flow fields to zero. 272 * 273 * The other fields in the IPv4 header remain unchanged. 274 * 275 */ InitVersionIhl(void)276 void InitVersionIhl(void) { SetVersionIhl(kVersIhlInit); } 277 278 /** 279 * This method sets the version and Ihl of the IPv4 header. 280 * 281 * @param[in] aVersionIhl The octet for the version and Ihl field. 282 * 283 */ SetVersionIhl(uint8_t aVersionIhl)284 void SetVersionIhl(uint8_t aVersionIhl) { mVersIhl = aVersionIhl; } 285 286 /** 287 * This method indicates whether or not the IPv4 Version is set to 6. 288 * 289 * @retval TRUE If the IPv4 Version is set to 4. 290 * @retval FALSE If the IPv4 Version is not set to 4. 291 * 292 */ IsVersion4(void) const293 bool IsVersion4(void) const { return (mVersIhl & kVersionMask) == kVersion4; } 294 295 /** 296 * This method returns the octet for DSCP + ECN. 297 * 298 * @retval The octet for DSCP and ECN. 299 * 300 */ GetDscpEcn(void) const301 uint8_t GetDscpEcn(void) const { return mDscpEcn; } 302 303 /** 304 * This method gets the 6-bit Differentiated Services Code Point (DSCP) from Traffic Class field. 305 * 306 * @returns The DSCP value. 307 * 308 */ GetDscp(void) const309 uint8_t GetDscp(void) const { return (mDscpEcn & kDscpMask) >> kDscpOffset; } 310 311 /** 312 * This method sets 6-bit Differentiated Services Code Point (DSCP) in IPv4 header. 313 * 314 * @param[in] aDscp The DSCP value. 315 * 316 */ SetDscp(uint8_t aDscp)317 void SetDscp(uint8_t aDscp) { mDscpEcn = static_cast<uint8_t>((mDscpEcn & ~kDscpMask) | (aDscp << kDscpOffset)); } 318 319 /** 320 * This method gets the 2-bit Explicit Congestion Notification (ECN) from Traffic Class field. 321 * 322 * @returns The ECN value. 323 * 324 */ GetEcn(void) const325 Ecn GetEcn(void) const { return static_cast<Ecn>(mDscpEcn & kEcnMask); } 326 327 /** 328 * This method sets the 2-bit Explicit Congestion Notification (ECN) in IPv4 header.. 329 * 330 * @param[in] aEcn The ECN value. 331 * 332 */ SetEcn(Ecn aEcn)333 void SetEcn(Ecn aEcn) { mDscpEcn = ((mDscpEcn & ~kEcnMask) | aEcn); } 334 335 /** 336 * This method returns the IPv4 Payload Length value. 337 * 338 * @returns The IPv4 Payload Length value. 339 * 340 */ GetTotalLength(void) const341 uint16_t GetTotalLength(void) const { return HostSwap16(mTotalLength); } 342 343 /** 344 * This method sets the IPv4 Payload Length value. 345 * 346 * @param[in] aLength The IPv4 Payload Length value. 347 * 348 */ SetTotalLength(uint16_t aLength)349 void SetTotalLength(uint16_t aLength) { mTotalLength = HostSwap16(aLength); } 350 351 /** 352 * This method returns the IPv4 payload protocol. 353 * 354 * @returns The IPv4 payload protocol value. 355 * 356 */ GetProtocol(void) const357 uint8_t GetProtocol(void) const { return mProtocol; } 358 359 /** 360 * This method sets the IPv4 payload protocol. 361 * 362 * @param[in] aProtocol The IPv4 payload protocol. 363 * 364 */ SetProtocol(uint8_t aProtocol)365 void SetProtocol(uint8_t aProtocol) { mProtocol = aProtocol; } 366 367 /** 368 * This method returns the IPv4 header checksum, the checksum is in host endian. 369 * 370 * @returns The checksum field in the IPv4 header. 371 * 372 */ GetChecksum(void) const373 uint16_t GetChecksum(void) const { return HostSwap16(mHeaderChecksum); } 374 375 /** 376 * This method sets the IPv4 header checksum, the checksum is in host endian. 377 * 378 * @param[in] aChecksum The checksum for the IPv4 header. 379 * 380 */ SetChecksum(uint16_t aChecksum)381 void SetChecksum(uint16_t aChecksum) { mHeaderChecksum = HostSwap16(aChecksum); } 382 383 /** 384 * This method returns the IPv4 Identification value. 385 * 386 * @returns The IPv4 Identification value. 387 * 388 */ GetIdentification(void) const389 uint16_t GetIdentification(void) const { return HostSwap16(mIdentification); } 390 391 /** 392 * This method sets the IPv4 Identification value. 393 * 394 * @param[in] aIdentification The IPv4 Identification value. 395 * 396 */ SetIdentification(uint16_t aIdentification)397 void SetIdentification(uint16_t aIdentification) { mIdentification = HostSwap16(aIdentification); } 398 399 /** 400 * This method returns the IPv4 Time-to-Live value. 401 * 402 * @returns The IPv4 Time-to-Live value. 403 * 404 */ GetTtl(void) const405 uint8_t GetTtl(void) const { return mTtl; } 406 407 /** 408 * This method sets the IPv4 Time-to-Live value. 409 * 410 * @param[in] aTtl The IPv4 Time-to-Live value. 411 * 412 */ SetTtl(uint8_t aTtl)413 void SetTtl(uint8_t aTtl) { mTtl = aTtl; } 414 415 /** 416 * This method returns the IPv4 Source address. 417 * 418 * @returns A reference to the IPv4 Source address. 419 * 420 */ GetSource(void)421 Address &GetSource(void) { return mSource; } 422 423 /** 424 * This method returns the IPv4 Source address. 425 * 426 * @returns A reference to the IPv4 Source address. 427 * 428 */ GetSource(void) const429 const Address &GetSource(void) const { return mSource; } 430 431 /** 432 * This method sets the IPv4 Source address. 433 * 434 * @param[in] aSource A reference to the IPv4 Source address. 435 * 436 */ SetSource(const Address & aSource)437 void SetSource(const Address &aSource) { mSource = aSource; } 438 439 /** 440 * This method returns the IPv4 Destination address. 441 * 442 * @returns A reference to the IPv4 Destination address. 443 * 444 */ GetDestination(void)445 Address &GetDestination(void) { return mDestination; } 446 447 /** 448 * This method returns the IPv4 Destination address. 449 * 450 * @returns A reference to the IPv4 Destination address. 451 * 452 */ GetDestination(void) const453 const Address &GetDestination(void) const { return mDestination; } 454 455 /** 456 * This method sets the IPv4 Destination address. 457 * 458 * @param[in] aDestination A reference to the IPv4 Destination address. 459 * 460 */ SetDestination(const Address & aDestination)461 void SetDestination(const Address &aDestination) { mDestination = aDestination; } 462 463 /** 464 * This method parses and validates the IPv4 header from a given message. 465 * 466 * The header is read from @p aMessage at offset zero. 467 * 468 * @param[in] aMessage The IPv4 message. 469 * 470 * @retval kErrorNone Successfully parsed the IPv4 header from @p aMessage. 471 * @retval kErrorParse Malformed IPv4 header or message (e.g., message does not contained expected payload length). 472 * 473 */ 474 Error ParseFrom(const Message &aMessage); 475 476 /** 477 * This method returns the Df flag in the IPv4 header. 478 * 479 * @returns Whether don't fragment flag is set. 480 * 481 */ GetDf(void) const482 bool GetDf(void) const { return HostSwap16(mFlagsFargmentOffset) & kFlagsDf; } 483 484 /** 485 * This method returns the Mf flag in the IPv4 header. 486 * 487 * @returns Whether more fragments flag is set. 488 * 489 */ GetMf(void) const490 bool GetMf(void) const { return HostSwap16(mFlagsFargmentOffset) & kFlagsMf; } 491 492 /** 493 * This method returns the fragment offset in the IPv4 header. 494 * 495 * @returns The fragment offset of the IPv4 packet. 496 * 497 */ GetFragmentOffset(void) const498 uint16_t GetFragmentOffset(void) const { return HostSwap16(mFlagsFargmentOffset) & kFragmentOffsetMask; } 499 500 private: 501 // IPv4 header 502 // 503 // +---------------+---------------+---------------+---------------+ 504 // |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| 505 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 506 // |Version| IHL | DSCP |ECN| Total Length | 507 // | Identification |Flags| Fragment Offset | 508 // | TTL | Protocol | Header Checksum | 509 // | Source IP Address | 510 // | Dest IP Address | 511 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 512 513 static constexpr uint8_t kVersion4 = 0x40; // Use with `mVersIhl` 514 static constexpr uint8_t kVersionMask = 0xf0; // Use with `mVersIhl` 515 static constexpr uint8_t kIhlMask = 0x0f; // Use with `mVersIhl` 516 static constexpr uint8_t kDscpOffset = 2; // Use with `mDscpEcn` 517 static constexpr uint16_t kDscpMask = 0xfc; // Use with `mDscpEcn` 518 static constexpr uint8_t kEcnOffset = 0; // Use with `mDscpEcn` 519 static constexpr uint8_t kEcnMask = 0x03; // Use with `mDscpEcn` 520 static constexpr uint16_t kFlagsMask = 0xe000; // Use with `mFlagsFragmentOffset` 521 static constexpr uint16_t kFlagsDf = 0x4000; // Use with `mFlagsFragmentOffset` 522 static constexpr uint16_t kFlagsMf = 0x2000; // Use with `mFlagsFragmentOffset` 523 static constexpr uint16_t kFragmentOffsetMask = 0x1fff; // Use with `mFlagsFragmentOffset` 524 static constexpr uint32_t kVersIhlInit = 0x45; // Version 4, Header length = 5x8 bytes. 525 526 uint8_t mVersIhl; 527 uint8_t mDscpEcn; 528 uint16_t mTotalLength; 529 uint16_t mIdentification; 530 uint16_t mFlagsFargmentOffset; 531 uint8_t mTtl; 532 uint8_t mProtocol; 533 uint16_t mHeaderChecksum; 534 Address mSource; 535 Address mDestination; 536 } OT_TOOL_PACKED_END; 537 538 /** 539 * This class implements ICMP(v4). 540 * Note: ICMP(v4) messages will only be generated / handled by NAT64. So only header defination is required. 541 * 542 */ 543 class Icmp 544 { 545 public: 546 /** 547 * This class represents an IPv4 ICMP header. 548 * 549 */ 550 OT_TOOL_PACKED_BEGIN 551 class Header : public Clearable<Header> 552 { 553 public: 554 static constexpr uint16_t kChecksumFieldOffset = 2; 555 // A few ICMP types, only the ICMP types work with NAT64 are listed here. 556 enum Type : uint8_t 557 { 558 kTypeEchoReply = 0, 559 kTypeDestinationUnreachable = 3, 560 kTypeEchoRequest = 8, 561 kTypeTimeExceeded = 11, 562 }; 563 564 enum Code : uint8_t 565 { 566 kCodeNone = 0, 567 // Destination Unreachable codes 568 kCodeNetworkUnreachable = 0, 569 kCodeHostUnreachable = 1, 570 kCodeProtocolUnreachable = 2, 571 kCodePortUnreachable = 3, 572 kCodeSourceRouteFailed = 5, 573 kCodeNetworkUnknown = 6, 574 kCodeHostUnknown = 7, 575 }; 576 577 /** 578 * This method returns the type of the ICMP message. 579 * 580 * @returns The type field of the ICMP message. 581 * 582 */ GetType(void) const583 uint8_t GetType(void) const { return mType; } 584 585 /** 586 * This method sets the type of the ICMP message. 587 * 588 * @param[in] aType The type of the ICMP message. 589 * 590 */ SetType(uint8_t aType)591 void SetType(uint8_t aType) { mType = aType; } 592 593 /** 594 * This method returns the code of the ICMP message. 595 * 596 * @returns The code field of the ICMP message. 597 * 598 */ GetCode(void) const599 uint8_t GetCode(void) const { return mCode; } 600 601 /** 602 * This method sets the code of the ICMP message. 603 * 604 * @param[in] aCode The code of the ICMP message. 605 * 606 */ SetCode(uint8_t aCode)607 void SetCode(uint8_t aCode) { mCode = aCode; } 608 609 /** 610 * This method sets the checksum field in the ICMP message. 611 * 612 * @returns The checksum of the ICMP message. 613 * 614 */ GetChecksum(void) const615 uint16_t GetChecksum(void) const { return HostSwap16(mChecksum); } 616 617 /** 618 * This method sets the checksum field in the ICMP message. 619 * 620 * @param[in] aChecksum The checksum of the ICMP message. 621 * 622 */ SetChecksum(uint16_t aChecksum)623 void SetChecksum(uint16_t aChecksum) { mChecksum = HostSwap16(aChecksum); } 624 625 /** 626 * This method returns the rest of header field in the ICMP message. 627 * 628 * @returns The rest of header field in the ICMP message. The returned buffer has 4 octets. 629 * 630 */ GetRestOfHeader(void) const631 const uint8_t *GetRestOfHeader(void) const { return mRestOfHeader; } 632 633 /** 634 * This method sets the rest of header field in the ICMP message. 635 * 636 * @param[in] aRestOfHeader The rest of header field in the ICMP message. The buffer should have 4 octets. 637 * 638 */ SetRestOfHeader(const uint8_t * aRestOfheader)639 void SetRestOfHeader(const uint8_t *aRestOfheader) 640 { 641 memcpy(mRestOfHeader, aRestOfheader, sizeof(mRestOfHeader)); 642 } 643 644 private: 645 uint8_t mType; 646 uint8_t mCode; 647 uint16_t mChecksum; 648 uint8_t mRestOfHeader[4]; 649 } OT_TOOL_PACKED_END; 650 }; 651 652 // Internet Protocol Numbers 653 static constexpr uint8_t kProtoTcp = Ip6::kProtoTcp; ///< Transmission Control Protocol 654 static constexpr uint8_t kProtoUdp = Ip6::kProtoUdp; ///< User Datagram 655 static constexpr uint8_t kProtoIcmp = 1; ///< ICMP for IPv4 656 657 using Tcp = Ip6::Tcp; // TCP in IPv4 is the same as TCP in IPv6 658 using Udp = Ip6::Udp; // UDP in IPv4 is the same as UDP in IPv6 659 660 /** 661 * @} 662 * 663 */ 664 665 } // namespace Ip4 666 667 DefineCoreType(otIp4Address, Ip4::Address); 668 DefineCoreType(otIp4Cidr, Ip4::Cidr); 669 670 } // namespace ot 671 672 #endif // IP4_TYPES_HPP_ 673