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 using ot::Encoding::BigEndian::HostSwap16;
61 using ot::Encoding::BigEndian::HostSwap32;
62 
63 /**
64  * @addtogroup core-ipv6
65  *
66  * @brief
67  *   This module includes definitions for the IPv6 network layer.
68  *
69  * @{
70  *
71  * @defgroup core-ip6-icmp6 ICMPv6
72  * @defgroup core-ip6-ip6 IPv6
73  * @defgroup core-ip6-mpl MPL
74  * @defgroup core-ip6-netif Network Interfaces
75  *
76  * @}
77  *
78  */
79 
80 /**
81  * @addtogroup core-ip6-ip6
82  *
83  * @brief
84  *   This module includes definitions for core IPv6 networking.
85  *
86  * @{
87  *
88  */
89 
90 /**
91  * This class implements IPv6 header generation and parsing.
92  *
93  */
94 OT_TOOL_PACKED_BEGIN
95 class Header : public Clearable<Header>
96 {
97 public:
98     static constexpr uint8_t kPayloadLengthFieldOffset = 4;  ///< Offset of Payload Length field in IPv6 header.
99     static constexpr uint8_t kNextHeaderFieldOffset    = 6;  ///< Offset of Next Header field in IPv6 header.
100     static constexpr uint8_t kHopLimitFieldOffset      = 7;  ///< Offset of Hop Limit field in IPv6 header.
101     static constexpr uint8_t kSourceFieldOffset        = 8;  ///< Offset of Source Address field in IPv6 header.
102     static constexpr uint8_t kDestinationFieldOffset   = 24; ///< Offset of Destination Address field in IPv6 header.
103 
104     /**
105      * This method initializes the Version to 6 and sets Traffic Class and Flow fields to zero.
106      *
107      * The other fields in the IPv6 header remain unchanged.
108      *
109      */
InitVersionTrafficClassFlow(void)110     void InitVersionTrafficClassFlow(void) { SetVerionTrafficClassFlow(kVersTcFlowInit); }
111 
112     /**
113      * This method indicates whether or not the header appears to be well-formed.
114      *
115      * @retval TRUE    If the header appears to be well-formed.
116      * @retval FALSE   If the header does not appear to be well-formed.
117      *
118      */
119     bool IsValid(void) const;
120 
121     /**
122      * This method indicates whether or not the IPv6 Version is set to 6.
123      *
124      * @retval TRUE   If the IPv6 Version is set to 6.
125      * @retval FALSE  If the IPv6 Version is not set to 6.
126      *
127      */
IsVersion6(void) const128     bool IsVersion6(void) const { return (mVerTcFlow.m8[0] & kVersionMask) == kVersion6; }
129 
130     /**
131      * This method gets the combination of Version, Traffic Class, and Flow fields as a 32-bit value.
132      *
133      * @returns The Version, Traffic Class, and Flow fields as a 32-bit value.
134      *
135      */
GetVerionTrafficClassFlow(void) const136     uint32_t GetVerionTrafficClassFlow(void) const { return HostSwap32(mVerTcFlow.m32); }
137 
138     /**
139      * This method sets the combination of Version, Traffic Class, and Flow fields as a 32-bit value.
140      *
141      * @param[in] aVerTcFlow   The Version, Traffic Class, and Flow fields as a 32-bit value.
142      *
143      */
SetVerionTrafficClassFlow(uint32_t aVerTcFlow)144     void SetVerionTrafficClassFlow(uint32_t aVerTcFlow) { mVerTcFlow.m32 = HostSwap32(aVerTcFlow); }
145 
146     /**
147      * This method gets the Traffic Class field.
148      *
149      * @returns The Traffic Class field.
150      *
151      */
GetTrafficClass(void) const152     uint8_t GetTrafficClass(void) const
153     {
154         return static_cast<uint8_t>((HostSwap16(mVerTcFlow.m16[0]) & kTrafficClassMask) >> kTrafficClassOffset);
155     }
156 
157     /**
158      * This method sets the Traffic Class filed.
159      *
160      * @param[in] aTc  The Traffic Class value.
161      *
162      */
SetTrafficClass(uint8_t aTc)163     void SetTrafficClass(uint8_t aTc)
164     {
165         mVerTcFlow.m16[0] = HostSwap16((HostSwap16(mVerTcFlow.m16[0]) & ~kTrafficClassMask) |
166                                        ((static_cast<uint16_t>(aTc) << kTrafficClassOffset) & kTrafficClassMask));
167     }
168 
169     /**
170      * This method gets the 6-bit Differentiated Services Code Point (DSCP) from Traffic Class field.
171      *
172      * @returns The DSCP value.
173      *
174      */
GetDscp(void) const175     uint8_t GetDscp(void) const
176     {
177         return static_cast<uint8_t>((HostSwap16(mVerTcFlow.m16[0]) & kDscpMask) >> kDscpOffset);
178     }
179 
180     /**
181      * This method sets 6-bit Differentiated Services Code Point (DSCP) in IPv6 header.
182      *
183      * @param[in]  aDscp  The DSCP value.
184      *
185      */
SetDscp(uint8_t aDscp)186     void SetDscp(uint8_t aDscp)
187     {
188         mVerTcFlow.m16[0] = HostSwap16((HostSwap16(mVerTcFlow.m16[0]) & ~kDscpMask) |
189                                        ((static_cast<uint16_t>(aDscp) << kDscpOffset) & kDscpMask));
190     }
191 
192     /**
193      * This method gets the 2-bit Explicit Congestion Notification (ECN) from Traffic Class field.
194      *
195      * @returns The ECN value.
196      *
197      */
GetEcn(void) const198     Ecn GetEcn(void) const { return static_cast<Ecn>((mVerTcFlow.m8[1] & kEcnMask) >> kEcnOffset); }
199 
200     /**
201      * This method sets the 2-bit Explicit Congestion Notification (ECN) in IPv6 header..
202      *
203      * @param[in]  aEcn  The ECN value.
204      *
205      */
SetEcn(Ecn aEcn)206     void SetEcn(Ecn aEcn) { mVerTcFlow.m8[1] = (mVerTcFlow.m8[1] & ~kEcnMask) | ((aEcn << kEcnOffset) & kEcnMask); }
207 
208     /**
209      * This method gets the 20-bit Flow field.
210      *
211      * @returns  The Flow value.
212      *
213      */
GetFlow(void) const214     uint32_t GetFlow(void) const { return HostSwap32(mVerTcFlow.m32) & kFlowMask; }
215 
216     /**
217      * This method sets the 20-bit Flow field in IPv6 header.
218      *
219      * @param[in] aFlow  The Flow value.
220      *
221      */
SetFlow(uint32_t aFlow)222     void SetFlow(uint32_t aFlow)
223     {
224         mVerTcFlow.m32 = HostSwap32((HostSwap32(mVerTcFlow.m32) & ~kFlowMask) | (aFlow & kFlowMask));
225     }
226 
227     /**
228      * This method 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 HostSwap16(mPayloadLength); }
234 
235     /**
236      * This method 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 = HostSwap16(aLength); }
242 
243     /**
244      * This method 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      * This method 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      * This method 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      * This method 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      * This method 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      * This method 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      * This method 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      * This method 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      * This method 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      * This method 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      * This method 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  * This class 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      * This method 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      * This method 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      * This method 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      * This method 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      * This method 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  * This class 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  * This class 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      * This method 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      * This method 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      * This method 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      * This method 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      * This method returns the size (number of bytes) of the IPv6 Option.
506      *
507      * This method 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      * This method 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      * in @p aMessage before the @p aEndOffset.
521      *
522      * @param[in]  aMessage    The IPv6 message.
523      * @param[in]  aOffset     The offset in @p aMessage to read the IPv6 Option.
524      * @param[in]  aEndOffset  The end offset in @p aMessage.
525      *
526      * @retval kErrorNone   Successfully parsed the IPv6 option from @p aMessage.
527      * @retval kErrorParse  Malformed IPv6 Option or Option is not contained within @p aMessage by @p aEndOffset.
528      *
529      */
530     Error ParseFrom(const Message &aMessage, uint16_t aOffset, uint16_t aEndOffset);
531 
532 protected:
533     static constexpr uint8_t kTypePad1 = 0x00; ///< Pad1 Option Type.
534     static constexpr uint8_t kTypePadN = 0x01; ///< PanN Option Type.
535 
536     /**
537      * This method sets the IPv6 Option Type value.
538      *
539      * @param[in]  aType  The IPv6 Option Type value.
540      *
541      */
SetType(uint8_t aType)542     void SetType(uint8_t aType) { mType = aType; }
543 
544     /**
545      * This method sets the IPv6 Option Length value.
546      *
547      * @param[in]  aLength  The IPv6 Option Length value.
548      *
549      */
SetLength(uint8_t aLength)550     void SetLength(uint8_t aLength) { mLength = aLength; }
551 
552 private:
553     static constexpr uint8_t kActionMask = 0xc0;
554 
555     uint8_t mType;
556     uint8_t mLength;
557 } OT_TOOL_PACKED_END;
558 
559 /**
560  * This class implements IPv6 Pad Options (Pad1 or PadN) generation.
561  *
562  */
563 OT_TOOL_PACKED_BEGIN
564 class PadOption : public Option, private Clearable<PadOption>
565 {
566     friend class Clearable<PadOption>;
567 
568 public:
569     /**
570      * This method initializes the Pad Option for a given total Pad size.
571      *
572      * The @p aPadSize MUST be from range 1-7. Otherwise the behavior of this method is undefined.
573      *
574      * @param[in]  aPadSize  The total number of needed padding bytes.
575      *
576      */
577     void InitForPadSize(uint8_t aPadSize);
578 
579     /**
580      * This method initializes the Pad Option for padding an IPv6 Extension header with a given current size.
581      *
582      * The Extension Header Length is in 8-bytes unit, so the total size should be a multiple of 8. This method
583      * determines the Pad Option size needed for appending to Extension Header based on it current size @p aHeaderSize
584      * so to make it a multiple of 8. This method returns `kErrorAlready` when the @p aHeaderSize is already
585      * a multiple of 8 (i.e., no padding is needed).
586      *
587      * @param[in] aHeaderSize  The current IPv6 Extension header size (in bytes).
588      *
589      * @retval kErrorNone     The Pad Option is successfully initialized.
590      * @retval kErrorAlready  The @p aHeaderSize is already a multiple of 8 and no padding is needed.
591      *
592      */
593     Error InitToPadHeaderWithSize(uint16_t aHeaderSize);
594 
595 private:
596     static constexpr uint8_t kMaxLength = 5;
597 
598     uint8_t mPads[kMaxLength];
599 } OT_TOOL_PACKED_END;
600 
601 /**
602  * This class implements IPv6 Fragment Header generation and parsing.
603  *
604  */
605 OT_TOOL_PACKED_BEGIN
606 class FragmentHeader
607 {
608 public:
609     /**
610      * This method initializes the IPv6 Fragment header.
611      *
612      */
Init(void)613     void Init(void)
614     {
615         mReserved       = 0;
616         mOffsetMore     = 0;
617         mIdentification = 0;
618     }
619 
620     /**
621      * This method returns the IPv6 Next Header value.
622      *
623      * @returns The IPv6 Next Header value.
624      *
625      */
GetNextHeader(void) const626     uint8_t GetNextHeader(void) const { return mNextHeader; }
627 
628     /**
629      * This method sets the IPv6 Next Header value.
630      *
631      * @param[in]  aNextHeader  The IPv6 Next Header value.
632      *
633      */
SetNextHeader(uint8_t aNextHeader)634     void SetNextHeader(uint8_t aNextHeader) { mNextHeader = aNextHeader; }
635 
636     /**
637      * This method returns the Fragment Offset value.
638      *
639      * @returns The Fragment Offset value.
640      *
641      */
GetOffset(void) const642     uint16_t GetOffset(void) const { return (HostSwap16(mOffsetMore) & kOffsetMask) >> kOffsetOffset; }
643 
644     /**
645      * This method sets the Fragment Offset value.
646      *
647      * @param[in]  aOffset  The Fragment Offset value.
648      */
SetOffset(uint16_t aOffset)649     void SetOffset(uint16_t aOffset)
650     {
651         uint16_t tmp = HostSwap16(mOffsetMore);
652         tmp          = (tmp & ~kOffsetMask) | ((aOffset << kOffsetOffset) & kOffsetMask);
653         mOffsetMore  = HostSwap16(tmp);
654     }
655 
656     /**
657      * This method returns the M flag value.
658      *
659      * @returns The M flag value.
660      *
661      */
IsMoreFlagSet(void) const662     bool IsMoreFlagSet(void) const { return HostSwap16(mOffsetMore) & kMoreFlag; }
663 
664     /**
665      * This method clears the M flag value.
666      *
667      */
ClearMoreFlag(void)668     void ClearMoreFlag(void) { mOffsetMore = HostSwap16(HostSwap16(mOffsetMore) & ~kMoreFlag); }
669 
670     /**
671      * This method sets the M flag value.
672      *
673      */
SetMoreFlag(void)674     void SetMoreFlag(void) { mOffsetMore = HostSwap16(HostSwap16(mOffsetMore) | kMoreFlag); }
675 
676     /**
677      * This method returns the frame identification.
678      *
679      * @returns The frame identification.
680      *
681      */
GetIdentification(void) const682     uint32_t GetIdentification(void) const { return mIdentification; }
683 
684     /**
685      * This method sets the frame identification.
686      *
687      * @param[in]  aIdentification  The fragment identification value.
688      */
SetIdentification(uint32_t aIdentification)689     void SetIdentification(uint32_t aIdentification) { mIdentification = aIdentification; }
690 
691     /**
692      * This method returns the next valid payload length for a fragment.
693      *
694      * @param[in]  aLength  The payload length to be validated for a fragment.
695      *
696      * @returns Valid IPv6 fragment payload length.
697      *
698      */
MakeDivisibleByEight(uint16_t aLength)699     static inline uint16_t MakeDivisibleByEight(uint16_t aLength) { return aLength & 0xfff8; }
700 
701     /**
702      * This method converts the fragment offset of 8-octet units into bytes.
703      *
704      * @param[in]  aOffset  The fragment offset in 8-octet units.
705      *
706      * @returns The fragment offset in bytes.
707      *
708      */
FragmentOffsetToBytes(uint16_t aOffset)709     static inline uint16_t FragmentOffsetToBytes(uint16_t aOffset) { return static_cast<uint16_t>(aOffset << 3); }
710 
711     /**
712      * This method converts a fragment offset in bytes into a fragment offset in 8-octet units.
713      *
714      * @param[in]  aOffset  The fragment offset in bytes.
715      *
716      * @returns The fragment offset in 8-octet units.
717      */
BytesToFragmentOffset(uint16_t aOffset)718     static inline uint16_t BytesToFragmentOffset(uint16_t aOffset) { return aOffset >> 3; }
719 
720 private:
721     static constexpr uint8_t  kOffsetOffset = 3;
722     static constexpr uint16_t kOffsetMask   = 0xfff8;
723     static constexpr uint16_t kMoreFlag     = 1;
724 
725     uint8_t  mNextHeader;
726     uint8_t  mReserved;
727     uint16_t mOffsetMore;
728     uint32_t mIdentification;
729 } OT_TOOL_PACKED_END;
730 
731 /**
732  * @}
733  *
734  */
735 
736 } // namespace Ip6
737 } // namespace ot
738 
739 #endif // IP6_HEADERS_HPP_
740