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      * 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      * 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      * 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  * 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      * 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      * 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  * Implements IPv6 Fragment Header generation and parsing.
603  *
604  */
605 OT_TOOL_PACKED_BEGIN
606 class FragmentHeader
607 {
608 public:
609     /**
610      * 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      * 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      * 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      * Returns the Fragment Offset value.
638      *
639      * @returns The Fragment Offset value.
640      *
641      */
GetOffset(void) const642     uint16_t GetOffset(void) const { return (BigEndian::HostSwap16(mOffsetMore) & kOffsetMask) >> kOffsetOffset; }
643 
644     /**
645      * 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 = BigEndian::HostSwap16(mOffsetMore);
652         tmp          = (tmp & ~kOffsetMask) | ((aOffset << kOffsetOffset) & kOffsetMask);
653         mOffsetMore  = BigEndian::HostSwap16(tmp);
654     }
655 
656     /**
657      * Returns the M flag value.
658      *
659      * @returns The M flag value.
660      *
661      */
IsMoreFlagSet(void) const662     bool IsMoreFlagSet(void) const { return BigEndian::HostSwap16(mOffsetMore) & kMoreFlag; }
663 
664     /**
665      * Clears the M flag value.
666      *
667      */
ClearMoreFlag(void)668     void ClearMoreFlag(void) { mOffsetMore = BigEndian::HostSwap16(BigEndian::HostSwap16(mOffsetMore) & ~kMoreFlag); }
669 
670     /**
671      * Sets the M flag value.
672      *
673      */
SetMoreFlag(void)674     void SetMoreFlag(void) { mOffsetMore = BigEndian::HostSwap16(BigEndian::HostSwap16(mOffsetMore) | kMoreFlag); }
675 
676     /**
677      * 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      * 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      * 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      * 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      * 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