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