• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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