xref: /aosp_15_r20/external/openthread/src/core/net/ip6_headers.hpp (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
1 /*
2  *  Copyright (c) 2016, 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 IPv6 packet processing.
32  */
33 
34 #ifndef IP6_HEADERS_HPP_
35 #define IP6_HEADERS_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include <stddef.h>
40 
41 #include "common/clearable.hpp"
42 #include "common/encoding.hpp"
43 #include "common/message.hpp"
44 #include "net/ip6_address.hpp"
45 #include "net/ip6_types.hpp"
46 #include "net/netif.hpp"
47 #include "net/socket.hpp"
48 
49 namespace ot {
50 
51 /**
52  * @namespace ot::Ip6
53  *
54  * @brief
55  *   This namespace includes definitions for IPv6 networking.
56  *
57  */
58 namespace Ip6 {
59 
60 /**
61  * @addtogroup core-ipv6
62  *
63  * @brief
64  *   This module includes definitions for the IPv6 network layer.
65  *
66  * @{
67  *
68  * @defgroup core-ip6-icmp6 ICMPv6
69  * @defgroup core-ip6-ip6 IPv6
70  * @defgroup core-ip6-mpl MPL
71  * @defgroup core-ip6-netif Network Interfaces
72  *
73  * @}
74  *
75  */
76 
77 /**
78  * @addtogroup core-ip6-ip6
79  *
80  * @brief
81  *   This module includes definitions for core IPv6 networking.
82  *
83  * @{
84  *
85  */
86 
87 /**
88  * Implements IPv6 header generation and parsing.
89  *
90  */
91 OT_TOOL_PACKED_BEGIN
92 class Header : public Clearable<Header>
93 {
94 public:
95     static constexpr uint8_t kPayloadLengthFieldOffset = 4;  ///< Offset of Payload Length field in IPv6 header.
96     static constexpr uint8_t kNextHeaderFieldOffset    = 6;  ///< Offset of Next Header field in IPv6 header.
97     static constexpr uint8_t kHopLimitFieldOffset      = 7;  ///< Offset of Hop Limit field in IPv6 header.
98     static constexpr uint8_t kSourceFieldOffset        = 8;  ///< Offset of Source Address field in IPv6 header.
99     static constexpr uint8_t kDestinationFieldOffset   = 24; ///< Offset of Destination Address field in IPv6 header.
100 
101     /**
102      * Initializes the Version to 6 and sets Traffic Class and Flow fields to zero.
103      *
104      * The other fields in the IPv6 header remain unchanged.
105      *
106      */
InitVersionTrafficClassFlow(void)107     void InitVersionTrafficClassFlow(void) { SetVerionTrafficClassFlow(kVersTcFlowInit); }
108 
109     /**
110      * Indicates whether or not the header appears to be well-formed.
111      *
112      * @retval TRUE    If the header appears to be well-formed.
113      * @retval FALSE   If the header does not appear to be well-formed.
114      *
115      */
116     bool IsValid(void) const;
117 
118     /**
119      * Indicates whether or not the IPv6 Version is set to 6.
120      *
121      * @retval TRUE   If the IPv6 Version is set to 6.
122      * @retval FALSE  If the IPv6 Version is not set to 6.
123      *
124      */
IsVersion6(void) const125     bool IsVersion6(void) const { return (mVerTcFlow.m8[0] & kVersionMask) == kVersion6; }
126 
127     /**
128      * Gets the combination of Version, Traffic Class, and Flow fields as a 32-bit value.
129      *
130      * @returns The Version, Traffic Class, and Flow fields as a 32-bit value.
131      *
132      */
GetVerionTrafficClassFlow(void) const133     uint32_t GetVerionTrafficClassFlow(void) const { return BigEndian::HostSwap32(mVerTcFlow.m32); }
134 
135     /**
136      * Sets the combination of Version, Traffic Class, and Flow fields as a 32-bit value.
137      *
138      * @param[in] aVerTcFlow   The Version, Traffic Class, and Flow fields as a 32-bit value.
139      *
140      */
SetVerionTrafficClassFlow(uint32_t aVerTcFlow)141     void SetVerionTrafficClassFlow(uint32_t aVerTcFlow) { mVerTcFlow.m32 = BigEndian::HostSwap32(aVerTcFlow); }
142 
143     /**
144      * Gets the Traffic Class field.
145      *
146      * @returns The Traffic Class field.
147      *
148      */
GetTrafficClass(void) const149     uint8_t GetTrafficClass(void) const
150     {
151         return static_cast<uint8_t>((BigEndian::HostSwap16(mVerTcFlow.m16[0]) & kTrafficClassMask) >>
152                                     kTrafficClassOffset);
153     }
154 
155     /**
156      * Sets the Traffic Class filed.
157      *
158      * @param[in] aTc  The Traffic Class value.
159      *
160      */
SetTrafficClass(uint8_t aTc)161     void SetTrafficClass(uint8_t aTc)
162     {
163         mVerTcFlow.m16[0] =
164             BigEndian::HostSwap16((BigEndian::HostSwap16(mVerTcFlow.m16[0]) & ~kTrafficClassMask) |
165                                   ((static_cast<uint16_t>(aTc) << kTrafficClassOffset) & kTrafficClassMask));
166     }
167 
168     /**
169      * Gets the 6-bit Differentiated Services Code Point (DSCP) from Traffic Class field.
170      *
171      * @returns The DSCP value.
172      *
173      */
GetDscp(void) const174     uint8_t GetDscp(void) const
175     {
176         return static_cast<uint8_t>((BigEndian::HostSwap16(mVerTcFlow.m16[0]) & kDscpMask) >> kDscpOffset);
177     }
178 
179     /**
180      * Sets 6-bit Differentiated Services Code Point (DSCP) in IPv6 header.
181      *
182      * @param[in]  aDscp  The DSCP value.
183      *
184      */
SetDscp(uint8_t aDscp)185     void SetDscp(uint8_t aDscp)
186     {
187         mVerTcFlow.m16[0] = BigEndian::HostSwap16((BigEndian::HostSwap16(mVerTcFlow.m16[0]) & ~kDscpMask) |
188                                                   ((static_cast<uint16_t>(aDscp) << kDscpOffset) & kDscpMask));
189     }
190 
191     /**
192      * Gets the 2-bit Explicit Congestion Notification (ECN) from Traffic Class field.
193      *
194      * @returns The ECN value.
195      *
196      */
GetEcn(void) const197     Ecn GetEcn(void) const { return static_cast<Ecn>((mVerTcFlow.m8[1] & kEcnMask) >> kEcnOffset); }
198 
199     /**
200      * Sets the 2-bit Explicit Congestion Notification (ECN) in IPv6 header..
201      *
202      * @param[in]  aEcn  The ECN value.
203      *
204      */
SetEcn(Ecn aEcn)205     void SetEcn(Ecn aEcn) { mVerTcFlow.m8[1] = (mVerTcFlow.m8[1] & ~kEcnMask) | ((aEcn << kEcnOffset) & kEcnMask); }
206 
207     /**
208      * Gets the 20-bit Flow field.
209      *
210      * @returns  The Flow value.
211      *
212      */
GetFlow(void) const213     uint32_t GetFlow(void) const { return BigEndian::HostSwap32(mVerTcFlow.m32) & kFlowMask; }
214 
215     /**
216      * Sets the 20-bit Flow field in IPv6 header.
217      *
218      * @param[in] aFlow  The Flow value.
219      *
220      */
SetFlow(uint32_t aFlow)221     void SetFlow(uint32_t aFlow)
222     {
223         mVerTcFlow.m32 =
224             BigEndian::HostSwap32((BigEndian::HostSwap32(mVerTcFlow.m32) & ~kFlowMask) | (aFlow & kFlowMask));
225     }
226 
227     /**
228      * Returns the IPv6 Payload Length value.
229      *
230      * @returns The IPv6 Payload Length value.
231      *
232      */
GetPayloadLength(void) const233     uint16_t GetPayloadLength(void) const { return BigEndian::HostSwap16(mPayloadLength); }
234 
235     /**
236      * Sets the IPv6 Payload Length value.
237      *
238      * @param[in]  aLength  The IPv6 Payload Length value.
239      *
240      */
SetPayloadLength(uint16_t aLength)241     void SetPayloadLength(uint16_t aLength) { mPayloadLength = BigEndian::HostSwap16(aLength); }
242 
243     /**
244      * Returns the IPv6 Next Header value.
245      *
246      * @returns The IPv6 Next Header value.
247      *
248      */
GetNextHeader(void) const249     uint8_t GetNextHeader(void) const { return mNextHeader; }
250 
251     /**
252      * Sets the IPv6 Next Header value.
253      *
254      * @param[in]  aNextHeader  The IPv6 Next Header value.
255      *
256      */
SetNextHeader(uint8_t aNextHeader)257     void SetNextHeader(uint8_t aNextHeader) { mNextHeader = aNextHeader; }
258 
259     /**
260      * Returns the IPv6 Hop Limit value.
261      *
262      * @returns The IPv6 Hop Limit value.
263      *
264      */
GetHopLimit(void) const265     uint8_t GetHopLimit(void) const { return mHopLimit; }
266 
267     /**
268      * Sets the IPv6 Hop Limit value.
269      *
270      * @param[in]  aHopLimit  The IPv6 Hop Limit value.
271      *
272      */
SetHopLimit(uint8_t aHopLimit)273     void SetHopLimit(uint8_t aHopLimit) { mHopLimit = aHopLimit; }
274 
275     /**
276      * Returns the IPv6 Source address.
277      *
278      * @returns A reference to the IPv6 Source address.
279      *
280      */
GetSource(void)281     Address &GetSource(void) { return mSource; }
282 
283     /**
284      * Returns the IPv6 Source address.
285      *
286      * @returns A reference to the IPv6 Source address.
287      *
288      */
GetSource(void) const289     const Address &GetSource(void) const { return mSource; }
290 
291     /**
292      * Sets the IPv6 Source address.
293      *
294      * @param[in]  aSource  A reference to the IPv6 Source address.
295      *
296      */
SetSource(const Address & aSource)297     void SetSource(const Address &aSource) { mSource = aSource; }
298 
299     /**
300      * Returns the IPv6 Destination address.
301      *
302      * @returns A reference to the IPv6 Destination address.
303      *
304      */
GetDestination(void)305     Address &GetDestination(void) { return mDestination; }
306 
307     /**
308      * Returns the IPv6 Destination address.
309      *
310      * @returns A reference to the IPv6 Destination address.
311      *
312      */
GetDestination(void) const313     const Address &GetDestination(void) const { return mDestination; }
314 
315     /**
316      * Sets the IPv6 Destination address.
317      *
318      * @param[in]  aDestination  A reference to the IPv6 Destination address.
319      *
320      */
SetDestination(const Address & aDestination)321     void SetDestination(const Address &aDestination) { mDestination = aDestination; }
322 
323     /**
324      * Parses and validates the IPv6 header from a given message.
325      *
326      * The header is read from @p aMessage at offset zero.
327      *
328      * @param[in]  aMessage  The IPv6 message.
329      *
330      * @retval kErrorNone   Successfully parsed the IPv6 header from @p aMessage.
331      * @retval kErrorParse  Malformed IPv6 header or message (e.g., message does not contained expected payload length).
332      *
333      */
334     Error ParseFrom(const Message &aMessage);
335 
336 private:
337     // IPv6 header `mVerTcFlow` field:
338     //
339     // |             m16[0]            |            m16[1]             |
340     // |     m8[0]     |     m8[1]     |     m8[2]     |      m8[3]    |
341     // +---------------+---------------+---------------+---------------+
342     // |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|
343     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
344     // |Version|    DSCP   |ECN|             Flow Label                |
345     // |       | Traffic Class |                                       |
346     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
347 
348     static constexpr uint8_t  kVersion6           = 0x60;       // Use with `mVerTcFlow.m8[0]`
349     static constexpr uint8_t  kVersionMask        = 0xf0;       // Use with `mVerTcFlow.m8[0]`
350     static constexpr uint8_t  kTrafficClassOffset = 4;          // Use with `mVerTcFlow.m16[0]`
351     static constexpr uint16_t kTrafficClassMask   = 0x0ff0;     // Use with `mVerTcFlow.m16[0]`
352     static constexpr uint8_t  kDscpOffset         = 6;          // Use with `mVerTcFlow.m16[0]`
353     static constexpr uint16_t kDscpMask           = 0x0fc0;     // Use with `mVerTcFlow.m16[0]`
354     static constexpr uint8_t  kEcnOffset          = 4;          // Use with `mVerTcFlow.m8[1]`
355     static constexpr uint8_t  kEcnMask            = 0x30;       // Use with `mVerTcFlow.m8[1]`
356     static constexpr uint32_t kFlowMask           = 0x000fffff; // Use with `mVerTcFlow.m32`
357     static constexpr uint32_t kVersTcFlowInit     = 0x60000000; // Version 6, TC and flow zero.
358 
359     union OT_TOOL_PACKED_FIELD
360     {
361         uint8_t  m8[sizeof(uint32_t) / sizeof(uint8_t)];
362         uint16_t m16[sizeof(uint32_t) / sizeof(uint16_t)];
363         uint32_t m32;
364     } mVerTcFlow;
365     uint16_t mPayloadLength;
366     uint8_t  mNextHeader;
367     uint8_t  mHopLimit;
368     Address  mSource;
369     Address  mDestination;
370 } OT_TOOL_PACKED_END;
371 
372 /**
373  * Implements IPv6 Extension Header generation and processing.
374  *
375  */
376 OT_TOOL_PACKED_BEGIN
377 class ExtensionHeader
378 {
379 public:
380     /**
381      * This constant defines the size of Length unit in bytes.
382      *
383      * The Length field is in 8-bytes unit. The total size of `ExtensionHeader` MUST be a multiple of 8.
384      *
385      */
386     static constexpr uint16_t kLengthUnitSize = 8;
387 
388     /**
389      * Returns the IPv6 Next Header value.
390      *
391      * @returns The IPv6 Next Header value.
392      *
393      */
GetNextHeader(void) const394     uint8_t GetNextHeader(void) const { return mNextHeader; }
395 
396     /**
397      * Sets the IPv6 Next Header value.
398      *
399      * @param[in]  aNextHeader  The IPv6 Next Header value.
400      *
401      */
SetNextHeader(uint8_t aNextHeader)402     void SetNextHeader(uint8_t aNextHeader) { mNextHeader = aNextHeader; }
403 
404     /**
405      * Returns the IPv6 Header Extension Length value.
406      *
407      * The Length is in 8-byte units and does not include the first 8 bytes.
408      *
409      * @returns The IPv6 Header Extension Length value.
410      *
411      */
GetLength(void) const412     uint8_t GetLength(void) const { return mLength; }
413 
414     /**
415      * Sets the IPv6 Header Extension Length value.
416      *
417      * The Length is in 8-byte units and does not include the first 8 bytes.
418      *
419      * @param[in]  aLength  The IPv6 Header Extension Length value.
420      *
421      */
SetLength(uint8_t aLength)422     void SetLength(uint8_t aLength) { mLength = aLength; }
423 
424     /**
425      * Returns the size (number of bytes) of the Extension Header including Next Header and Length fields.
426      *
427      * @returns The size (number of bytes) of the Extension Header.
428      *
429      */
GetSize(void) const430     uint16_t GetSize(void) const { return kLengthUnitSize * (mLength + 1); }
431 
432 private:
433     // |     m8[0]     |     m8[1]     |     m8[2]     |      m8[3]    |
434     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
435     // | Next Header   | Header Length | . . .                         |
436     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
437 
438     uint8_t mNextHeader;
439     uint8_t mLength;
440 } OT_TOOL_PACKED_END;
441 
442 /**
443  * Implements IPv6 Hop-by-Hop Options Header generation and parsing.
444  *
445  */
446 OT_TOOL_PACKED_BEGIN
447 class HopByHopHeader : public ExtensionHeader
448 {
449 } OT_TOOL_PACKED_END;
450 
451 /**
452  * Implements IPv6 Options generation and parsing.
453  *
454  */
455 OT_TOOL_PACKED_BEGIN
456 class Option
457 {
458 public:
459     /**
460      * IPv6 Option Type actions for unrecognized IPv6 Options.
461      *
462      */
463     enum Action : uint8_t
464     {
465         kActionSkip      = 0x00, ///< Skip over this option and continue processing the header.
466         kActionDiscard   = 0x40, ///< Discard the packet.
467         kActionForceIcmp = 0x80, ///< Discard the packet and forcibly send an ICMP Parameter Problem.
468         kActionIcmp      = 0xc0, ///< Discard packet and conditionally send an ICMP Parameter Problem.
469     };
470 
471     /**
472      * Returns the IPv6 Option Type value.
473      *
474      * @returns The IPv6 Option Type value.
475      *
476      */
GetType(void) const477     uint8_t GetType(void) const { return mType; }
478 
479     /**
480      * Indicates whether IPv6 Option is padding (either Pad1 or PadN).
481      *
482      * @retval TRUE   The Option is padding.
483      * @retval FALSE  The Option is not padding.
484      *
485      */
IsPadding(void) const486     bool IsPadding(void) const { return (mType == kTypePad1) || (mType == kTypePadN); }
487 
488     /**
489      * Returns the IPv6 Option action for unrecognized IPv6 Options.
490      *
491      * @returns The IPv6 Option action for unrecognized IPv6 Options.
492      *
493      */
GetAction(void) const494     Action GetAction(void) const { return static_cast<Action>(mType & kActionMask); }
495 
496     /**
497      * Returns the IPv6 Option Length value.
498      *
499      * @returns The IPv6 Option Length value.
500      *
501      */
GetLength(void) const502     uint8_t GetLength(void) const { return mLength; }
503 
504     /**
505      * Returns the size (number of bytes) of the IPv6 Option.
506      *
507      * Returns the proper size of the Option independent of its type, particularly if Option is Pad1 (which
508      * does not follow the common Option header structure and has only Type field with no Length field). For other
509      * Option types, the returned size includes the Type and Length fields.
510      *
511      * @returns The size of the Option.
512      *
513      */
514     uint16_t GetSize(void) const;
515 
516     /**
517      * Parses and validates the IPv6 Option from a given message.
518      *
519      * The Option is read from @p aOffset in @p aMessage. This method then checks that the entire Option is present
520      * within @p aOffsetRange.
521      *
522      * @param[in]  aMessage      The IPv6 message.
523      * @param[in]  aOffsetRange  The offset range in @p aMessage to read the IPv6 Option.
524      *
525      * @retval kErrorNone   Successfully parsed the IPv6 option from @p aMessage.
526      * @retval kErrorParse  Malformed IPv6 Option or Option is not contained within @p aMessage and @p aOffsetRange.
527      *
528      */
529     Error ParseFrom(const Message &aMessage, const OffsetRange &aOffsetRange);
530 
531 protected:
532     static constexpr uint8_t kTypePad1 = 0x00; ///< Pad1 Option Type.
533     static constexpr uint8_t kTypePadN = 0x01; ///< PanN Option Type.
534 
535     /**
536      * Sets the IPv6 Option Type value.
537      *
538      * @param[in]  aType  The IPv6 Option Type value.
539      *
540      */
SetType(uint8_t aType)541     void SetType(uint8_t aType) { mType = aType; }
542 
543     /**
544      * Sets the IPv6 Option Length value.
545      *
546      * @param[in]  aLength  The IPv6 Option Length value.
547      *
548      */
SetLength(uint8_t aLength)549     void SetLength(uint8_t aLength) { mLength = aLength; }
550 
551 private:
552     static constexpr uint8_t kActionMask = 0xc0;
553 
554     uint8_t mType;
555     uint8_t mLength;
556 } OT_TOOL_PACKED_END;
557 
558 /**
559  * Implements IPv6 Pad Options (Pad1 or PadN) generation.
560  *
561  */
562 OT_TOOL_PACKED_BEGIN
563 class PadOption : public Option, private Clearable<PadOption>
564 {
565     friend class Clearable<PadOption>;
566 
567 public:
568     /**
569      * Initializes the Pad Option for a given total Pad size.
570      *
571      * The @p aPadSize MUST be from range 1-7. Otherwise the behavior of this method is undefined.
572      *
573      * @param[in]  aPadSize  The total number of needed padding bytes.
574      *
575      */
576     void InitForPadSize(uint8_t aPadSize);
577 
578     /**
579      * Initializes the Pad Option for padding an IPv6 Extension header with a given current size.
580      *
581      * The Extension Header Length is in 8-bytes unit, so the total size should be a multiple of 8. This method
582      * determines the Pad Option size needed for appending to Extension Header based on it current size @p aHeaderSize
583      * so to make it a multiple of 8. This method returns `kErrorAlready` when the @p aHeaderSize is already
584      * a multiple of 8 (i.e., no padding is needed).
585      *
586      * @param[in] aHeaderSize  The current IPv6 Extension header size (in bytes).
587      *
588      * @retval kErrorNone     The Pad Option is successfully initialized.
589      * @retval kErrorAlready  The @p aHeaderSize is already a multiple of 8 and no padding is needed.
590      *
591      */
592     Error InitToPadHeaderWithSize(uint16_t aHeaderSize);
593 
594 private:
595     static constexpr uint8_t kMaxLength = 5;
596 
597     uint8_t mPads[kMaxLength];
598 } OT_TOOL_PACKED_END;
599 
600 /**
601  * Implements IPv6 Fragment Header generation and parsing.
602  *
603  */
604 OT_TOOL_PACKED_BEGIN
605 class FragmentHeader
606 {
607 public:
608     /**
609      * Initializes the IPv6 Fragment header.
610      *
611      */
Init(void)612     void Init(void)
613     {
614         mReserved       = 0;
615         mOffsetMore     = 0;
616         mIdentification = 0;
617     }
618 
619     /**
620      * Returns the IPv6 Next Header value.
621      *
622      * @returns The IPv6 Next Header value.
623      *
624      */
GetNextHeader(void) const625     uint8_t GetNextHeader(void) const { return mNextHeader; }
626 
627     /**
628      * Sets the IPv6 Next Header value.
629      *
630      * @param[in]  aNextHeader  The IPv6 Next Header value.
631      *
632      */
SetNextHeader(uint8_t aNextHeader)633     void SetNextHeader(uint8_t aNextHeader) { mNextHeader = aNextHeader; }
634 
635     /**
636      * Returns the Fragment Offset value.
637      *
638      * @returns The Fragment Offset value.
639      *
640      */
GetOffset(void) const641     uint16_t GetOffset(void) const { return (BigEndian::HostSwap16(mOffsetMore) & kOffsetMask) >> kOffsetOffset; }
642 
643     /**
644      * Sets the Fragment Offset value.
645      *
646      * @param[in]  aOffset  The Fragment Offset value.
647      */
SetOffset(uint16_t aOffset)648     void SetOffset(uint16_t aOffset)
649     {
650         uint16_t tmp = BigEndian::HostSwap16(mOffsetMore);
651         tmp          = (tmp & ~kOffsetMask) | ((aOffset << kOffsetOffset) & kOffsetMask);
652         mOffsetMore  = BigEndian::HostSwap16(tmp);
653     }
654 
655     /**
656      * Returns the M flag value.
657      *
658      * @returns The M flag value.
659      *
660      */
IsMoreFlagSet(void) const661     bool IsMoreFlagSet(void) const { return BigEndian::HostSwap16(mOffsetMore) & kMoreFlag; }
662 
663     /**
664      * Clears the M flag value.
665      *
666      */
ClearMoreFlag(void)667     void ClearMoreFlag(void) { mOffsetMore = BigEndian::HostSwap16(BigEndian::HostSwap16(mOffsetMore) & ~kMoreFlag); }
668 
669     /**
670      * Sets the M flag value.
671      *
672      */
SetMoreFlag(void)673     void SetMoreFlag(void) { mOffsetMore = BigEndian::HostSwap16(BigEndian::HostSwap16(mOffsetMore) | kMoreFlag); }
674 
675     /**
676      * Returns the frame identification.
677      *
678      * @returns The frame identification.
679      *
680      */
GetIdentification(void) const681     uint32_t GetIdentification(void) const { return mIdentification; }
682 
683     /**
684      * Sets the frame identification.
685      *
686      * @param[in]  aIdentification  The fragment identification value.
687      */
SetIdentification(uint32_t aIdentification)688     void SetIdentification(uint32_t aIdentification) { mIdentification = aIdentification; }
689 
690     /**
691      * Returns the next valid payload length for a fragment.
692      *
693      * @param[in]  aLength  The payload length to be validated for a fragment.
694      *
695      * @returns Valid IPv6 fragment payload length.
696      *
697      */
MakeDivisibleByEight(uint16_t aLength)698     static inline uint16_t MakeDivisibleByEight(uint16_t aLength) { return aLength & 0xfff8; }
699 
700     /**
701      * Converts the fragment offset of 8-octet units into bytes.
702      *
703      * @param[in]  aOffset  The fragment offset in 8-octet units.
704      *
705      * @returns The fragment offset in bytes.
706      *
707      */
FragmentOffsetToBytes(uint16_t aOffset)708     static inline uint16_t FragmentOffsetToBytes(uint16_t aOffset) { return static_cast<uint16_t>(aOffset << 3); }
709 
710     /**
711      * Converts a fragment offset in bytes into a fragment offset in 8-octet units.
712      *
713      * @param[in]  aOffset  The fragment offset in bytes.
714      *
715      * @returns The fragment offset in 8-octet units.
716      */
BytesToFragmentOffset(uint16_t aOffset)717     static inline uint16_t BytesToFragmentOffset(uint16_t aOffset) { return aOffset >> 3; }
718 
719 private:
720     static constexpr uint8_t  kOffsetOffset = 3;
721     static constexpr uint16_t kOffsetMask   = 0xfff8;
722     static constexpr uint16_t kMoreFlag     = 1;
723 
724     uint8_t  mNextHeader;
725     uint8_t  mReserved;
726     uint16_t mOffsetMore;
727     uint32_t mIdentification;
728 } OT_TOOL_PACKED_END;
729 
730 /**
731  * @}
732  *
733  */
734 
735 } // namespace Ip6
736 } // namespace ot
737 
738 #endif // IP6_HEADERS_HPP_
739