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/encoding.hpp"
42 #include "common/message.hpp"
43 #include "net/ip6_address.hpp"
44 #include "net/netif.hpp"
45 #include "net/socket.hpp"
46 
47 namespace ot {
48 
49 /**
50  * @namespace ot::Ip6
51  *
52  * @brief
53  *   This namespace includes definitions for IPv6 networking.
54  *
55  */
56 namespace Ip6 {
57 
58 using ot::Encoding::BigEndian::HostSwap16;
59 using ot::Encoding::BigEndian::HostSwap32;
60 
61 /**
62  * @addtogroup core-ipv6
63  *
64  * @brief
65  *   This module includes definitions for the IPv6 network layer.
66  *
67  * @{
68  *
69  * @defgroup core-ip6-icmp6 ICMPv6
70  * @defgroup core-ip6-ip6 IPv6
71  * @defgroup core-ip6-mpl MPL
72  * @defgroup core-ip6-netif Network Interfaces
73  *
74  * @}
75  *
76  */
77 
78 /**
79  * @addtogroup core-ip6-ip6
80  *
81  * @brief
82  *   This module includes definitions for core IPv6 networking.
83  *
84  * @{
85  *
86  */
87 
88 // Internet Protocol Numbers
89 static constexpr uint8_t kProtoHopOpts  = OT_IP6_PROTO_HOP_OPTS; ///< IPv6 Hop-by-Hop Option
90 static constexpr uint8_t kProtoTcp      = OT_IP6_PROTO_TCP;      ///< Transmission Control Protocol
91 static constexpr uint8_t kProtoUdp      = OT_IP6_PROTO_UDP;      ///< User Datagram
92 static constexpr uint8_t kProtoIp6      = OT_IP6_PROTO_IP6;      ///< IPv6 encapsulation
93 static constexpr uint8_t kProtoRouting  = OT_IP6_PROTO_ROUTING;  ///< Routing Header for IPv6
94 static constexpr uint8_t kProtoFragment = OT_IP6_PROTO_FRAGMENT; ///< Fragment Header for IPv6
95 static constexpr uint8_t kProtoIcmp6    = OT_IP6_PROTO_ICMP6;    ///< ICMP for IPv6
96 static constexpr uint8_t kProtoNone     = OT_IP6_PROTO_NONE;     ///< No Next Header for IPv6
97 static constexpr uint8_t kProtoDstOpts  = OT_IP6_PROTO_DST_OPTS; ///< Destination Options for IPv6
98 
99 /**
100  * Class Selectors
101  */
102 enum IpDscpCs : uint8_t
103 {
104     kDscpCs0    = 0,    ///< Class selector codepoint 0
105     kDscpCs1    = 8,    ///< Class selector codepoint 8
106     kDscpCs2    = 16,   ///< Class selector codepoint 16
107     kDscpCs3    = 24,   ///< Class selector codepoint 24
108     kDscpCs4    = 32,   ///< Class selector codepoint 32
109     kDscpCs5    = 40,   ///< Class selector codepoint 40
110     kDscpCs6    = 48,   ///< Class selector codepoint 48
111     kDscpCs7    = 56,   ///< Class selector codepoint 56
112     kDscpCsMask = 0x38, ///< Class selector mask
113 };
114 
115 /**
116  * This class implements IPv6 header generation and parsing.
117  *
118  */
119 OT_TOOL_PACKED_BEGIN
120 class Header
121 {
122 public:
123     static constexpr uint8_t kPayloadLengthFieldOffset = 4;  ///< Offset of Payload Length field in IPv6 header.
124     static constexpr uint8_t kNextHeaderFieldOffset    = 6;  ///< Offset of Next Header field in IPv6 header.
125     static constexpr uint8_t kHopLimitFieldOffset      = 7;  ///< Offset of Hop Limit field in IPv6 header.
126     static constexpr uint8_t kSourceFieldOffset        = 8;  ///< Offset of Source Address field in IPv6 header.
127     static constexpr uint8_t kDestinationFieldOffset   = 24; ///< Offset of Destination Address field in IPv6 header.
128 
129     /**
130      * This method initializes the IPv6 header.
131      *
132      */
Init(void)133     void Init(void) { mVersionClassFlow.m32 = HostSwap32(kVersionClassFlowInit); }
134 
135     /**
136      * This method initializes the IPv6 header and sets Version, Traffic Control and Flow Label fields.
137      *
138      */
Init(uint32_t aVersionClassFlow)139     void Init(uint32_t aVersionClassFlow) { mVersionClassFlow.m32 = HostSwap32(aVersionClassFlow); }
140 
141     /**
142      * This method reads the IPv6 header from @p aMessage.
143      *
144      * @param[in]  aMessage  The IPv6 datagram.
145      *
146      * @retval kErrorNone   Successfully read the IPv6 header.
147      * @retval kErrorParse  Malformed IPv6 header.
148      *
149      */
150     Error Init(const Message &aMessage);
151 
152     /**
153      * This method indicates whether or not the header appears to be well-formed.
154      *
155      * @retval TRUE  if the header appears to be well-formed.
156      * @retval FALSE if the header does not appear to be well-formed.
157      *
158      */
159     bool IsValid(void) const;
160 
161     /**
162      * This method indicates whether or not the IPv6 Version is set to 6.
163      *
164      * @retval TRUE   If the IPv6 Version is set to 6.
165      * @retval FALSE  If the IPv6 Version is not set to 6.
166      *
167      */
IsVersion6(void) const168     bool IsVersion6(void) const { return (mVersionClassFlow.m8[0] & kVersionMask) == kVersion6; }
169 
170     /**
171      * This method returns the IPv6 DSCP value.
172      *
173      * @returns The IPv6 DSCP value.
174      *
175      */
GetDscp(void) const176     uint8_t GetDscp(void) const
177     {
178         return static_cast<uint8_t>((HostSwap16(mVersionClassFlow.m16[0]) & kDscpMask) >> kDscpOffset);
179     }
180 
181     /**
182      * This method sets the IPv6 DSCP value.
183      *
184      * @param[in]  aDscp  The IPv6 DSCP value.
185      *
186      */
SetDscp(uint8_t aDscp)187     void SetDscp(uint8_t aDscp)
188     {
189         mVersionClassFlow.m16[0] = HostSwap16((HostSwap16(mVersionClassFlow.m16[0]) & ~kDscpMask) |
190                                               ((static_cast<uint16_t>(aDscp) << kDscpOffset) & kDscpMask));
191     }
192 
193     /**
194      * This method returns the IPv6 ECN value.
195      *
196      * @returns The IPv6 ECN value.
197      *
198      */
GetEcn(void) const199     uint8_t GetEcn(void) const { return (mVersionClassFlow.m8[1] & kEcnMask) >> kEcnOffset; }
200 
201     /**
202      * This method sets the Ipv6 ECN value.
203      *
204      * @param[in]  aEcn  The Ipv6 ECN value.
205      *
206      */
SetEcn(uint8_t aEcn)207     void SetEcn(uint8_t aEcn)
208     {
209         mVersionClassFlow.m8[1] = (mVersionClassFlow.m8[1] & ~kEcnMask) | ((aEcn << kEcnOffset) & kEcnMask);
210     }
211 
212     /**
213      * This method returns the IPv6 Payload Length value.
214      *
215      * @returns The IPv6 Payload Length value.
216      *
217      */
GetPayloadLength(void) const218     uint16_t GetPayloadLength(void) const { return HostSwap16(mPayloadLength); }
219 
220     /**
221      * This method sets the IPv6 Payload Length value.
222      *
223      * @param[in]  aLength  The IPv6 Payload Length value.
224      *
225      */
SetPayloadLength(uint16_t aLength)226     void SetPayloadLength(uint16_t aLength) { mPayloadLength = HostSwap16(aLength); }
227 
228     /**
229      * This method returns the IPv6 Next Header value.
230      *
231      * @returns The IPv6 Next Header value.
232      *
233      */
GetNextHeader(void) const234     uint8_t GetNextHeader(void) const { return mNextHeader; }
235 
236     /**
237      * This method sets the IPv6 Next Header value.
238      *
239      * @param[in]  aNextHeader  The IPv6 Next Header value.
240      *
241      */
SetNextHeader(uint8_t aNextHeader)242     void SetNextHeader(uint8_t aNextHeader) { mNextHeader = aNextHeader; }
243 
244     /**
245      * This method returns the IPv6 Hop Limit value.
246      *
247      * @returns The IPv6 Hop Limit value.
248      *
249      */
GetHopLimit(void) const250     uint8_t GetHopLimit(void) const { return mHopLimit; }
251 
252     /**
253      * This method sets the IPv6 Hop Limit value.
254      *
255      * @param[in]  aHopLimit  The IPv6 Hop Limit value.
256      *
257      */
SetHopLimit(uint8_t aHopLimit)258     void SetHopLimit(uint8_t aHopLimit) { mHopLimit = aHopLimit; }
259 
260     /**
261      * This method returns the IPv6 Source address.
262      *
263      * @returns A reference to the IPv6 Source address.
264      *
265      */
GetSource(void)266     Address &GetSource(void) { return mSource; }
267 
268     /**
269      * This method returns the IPv6 Source address.
270      *
271      * @returns A reference to the IPv6 Source address.
272      *
273      */
GetSource(void) const274     const Address &GetSource(void) const { return mSource; }
275 
276     /**
277      * This method sets the IPv6 Source address.
278      *
279      * @param[in]  aSource  A reference to the IPv6 Source address.
280      *
281      */
SetSource(const Address & aSource)282     void SetSource(const Address &aSource) { mSource = aSource; }
283 
284     /**
285      * This method returns the IPv6 Destination address.
286      *
287      * @returns A reference to the IPv6 Destination address.
288      *
289      */
GetDestination(void)290     Address &GetDestination(void) { return mDestination; }
291 
292     /**
293      * This method returns the IPv6 Destination address.
294      *
295      * @returns A reference to the IPv6 Destination address.
296      *
297      */
GetDestination(void) const298     const Address &GetDestination(void) const { return mDestination; }
299 
300     /**
301      * This method sets the IPv6 Destination address.
302      *
303      * @param[in]  aDestination  A reference to the IPv6 Destination address.
304      *
305      */
SetDestination(const Address & aDestination)306     void SetDestination(const Address &aDestination) { mDestination = aDestination; }
307 
308 private:
309     static constexpr uint8_t  kVersion6             = 0x60;
310     static constexpr uint8_t  kVersionMask          = 0xf0;       // To use with `mVersionClassFlow.m8[0]`
311     static constexpr uint8_t  kDscpOffset           = 6;          // To use with `mVersionClassFlow.m16[0]`
312     static constexpr uint16_t kDscpMask             = 0x0fc0;     // To use with `mVersionClassFlow.m16[0]`
313     static constexpr uint8_t  kEcnOffset            = 4;          // To use with `mVersionClassFlow.m8[1]`
314     static constexpr uint8_t  kEcnMask              = 0x30;       // To use with `mVersionClassFlow.m8[1]`
315     static constexpr uint32_t kVersionClassFlowInit = 0x60000000; // Version 6, TC and flow zero.
316 
317     static constexpr uint8_t kEcnNotCapable = OT_ECN_NOT_CAPABLE; ///< Non-ECT
318     static constexpr uint8_t kEcnCapable0   = OT_ECN_CAPABLE_0;   ///< ECT(0)
319     static constexpr uint8_t kEcnCapable1   = OT_ECN_CAPABLE_1;   ///< ECT(1)
320     static constexpr uint8_t kEcnMarked     = OT_ECN_MARKED;      ///< Congestion encountered (CE)
321 
322     union OT_TOOL_PACKED_FIELD
323     {
324         uint8_t  m8[sizeof(uint32_t) / sizeof(uint8_t)];
325         uint16_t m16[sizeof(uint32_t) / sizeof(uint16_t)];
326         uint32_t m32;
327     } mVersionClassFlow;
328     uint16_t mPayloadLength;
329     uint8_t  mNextHeader;
330     uint8_t  mHopLimit;
331     Address  mSource;
332     Address  mDestination;
333 } OT_TOOL_PACKED_END;
334 
335 /**
336  * This class implements IPv6 Extension Header generation and processing.
337  *
338  */
339 OT_TOOL_PACKED_BEGIN
340 class ExtensionHeader
341 {
342 public:
343     /**
344      * This method returns the IPv6 Next Header value.
345      *
346      * @returns The IPv6 Next Header value.
347      *
348      */
GetNextHeader(void) const349     uint8_t GetNextHeader(void) const { return mNextHeader; }
350 
351     /**
352      * This method sets the IPv6 Next Header value.
353      *
354      * @param[in]  aNextHeader  The IPv6 Next Header value.
355      *
356      */
SetNextHeader(uint8_t aNextHeader)357     void SetNextHeader(uint8_t aNextHeader) { mNextHeader = aNextHeader; }
358 
359     /**
360      * This method returns the IPv6 Header Extension Length value.
361      *
362      * @returns The IPv6 Header Extension Length value.
363      *
364      */
GetLength(void) const365     uint8_t GetLength(void) const { return mLength; }
366 
367     /**
368      * This method sets the IPv6 Header Extension Length value.
369      *
370      * @param[in]  aLength  The IPv6 Header Extension Length value.
371      *
372      */
SetLength(uint8_t aLength)373     void SetLength(uint8_t aLength) { mLength = aLength; }
374 
375 private:
376     uint8_t mNextHeader;
377     uint8_t mLength;
378 } OT_TOOL_PACKED_END;
379 
380 /**
381  * This class implements IPv6 Hop-by-Hop Options Header generation and parsing.
382  *
383  */
384 OT_TOOL_PACKED_BEGIN
385 class HopByHopHeader : public ExtensionHeader
386 {
387 } OT_TOOL_PACKED_END;
388 
389 /**
390  * This class implements IPv6 Options generation and parsing.
391  *
392  */
393 OT_TOOL_PACKED_BEGIN
394 class OptionHeader
395 {
396 public:
397     /**
398      * Default constructor.
399      *
400      */
OptionHeader(void)401     OptionHeader(void)
402         : mType(0)
403         , mLength(0)
404     {
405     }
406 
407     /**
408      * This method returns the IPv6 Option Type value.
409      *
410      * @returns The IPv6 Option Type value.
411      *
412      */
GetType(void) const413     uint8_t GetType(void) const { return mType; }
414 
415     /**
416      * This method sets the IPv6 Option Type value.
417      *
418      * @param[in]  aType  The IPv6 Option Type value.
419      *
420      */
SetType(uint8_t aType)421     void SetType(uint8_t aType) { mType = aType; }
422 
423     /**
424      * IPv6 Option Type actions for unrecognized IPv6 Options.
425      *
426      */
427     enum Action : uint8_t
428     {
429         kActionSkip      = 0x00, ///< skip over this option and continue processing the header
430         kActionDiscard   = 0x40, ///< discard the packet
431         kActionForceIcmp = 0x80, ///< discard the packet and forcibly send an ICMP Parameter Problem
432         kActionIcmp      = 0xc0, ///< discard packet and conditionally send an ICMP Parameter Problem
433     };
434 
435     /**
436      * This method returns the IPv6 Option action for unrecognized IPv6 Options.
437      *
438      * @returns The IPv6 Option action for unrecognized IPv6 Options.
439      *
440      */
GetAction(void) const441     Action GetAction(void) const { return static_cast<Action>(mType & kActionMask); }
442 
443     /**
444      * This method returns the IPv6 Option Length value.
445      *
446      * @returns The IPv6 Option Length value.
447      *
448      */
GetLength(void) const449     uint8_t GetLength(void) const { return mLength; }
450 
451     /**
452      * This method sets the IPv6 Option Length value.
453      *
454      * @param[in]  aLength  The IPv6 Option Length value.
455      *
456      */
SetLength(uint8_t aLength)457     void SetLength(uint8_t aLength) { mLength = aLength; }
458 
459 private:
460     static constexpr uint8_t kActionMask = 0xc0;
461 
462     uint8_t mType;
463     uint8_t mLength;
464 } OT_TOOL_PACKED_END;
465 
466 /**
467  * This class implements IPv6 PadN Option generation and parsing.
468  *
469  */
470 OT_TOOL_PACKED_BEGIN
471 class OptionPadN : public OptionHeader
472 {
473 public:
474     static constexpr uint8_t kType      = 0x01; ///< PadN type
475     static constexpr uint8_t kData      = 0x00; ///< PadN specific data
476     static constexpr uint8_t kMaxLength = 0x05; ///< Maximum length of PadN option data
477 
478     /**
479      * This method initializes the PadN header.
480      *
481      * @param[in]  aPadLength  The length of needed padding. Allowed value from
482      *                         range 2-7.
483      *
484      */
Init(uint8_t aPadLength)485     void Init(uint8_t aPadLength)
486     {
487         SetType(kType);
488         SetLength(aPadLength - sizeof(OptionHeader));
489         memset(mPad, kData, aPadLength - sizeof(OptionHeader));
490     }
491 
492     /**
493      * This method returns the total IPv6 Option Length value including option
494      * header.
495      *
496      * @returns The total IPv6 Option Length.
497      *
498      */
GetTotalLength(void) const499     uint8_t GetTotalLength(void) const { return GetLength() + sizeof(OptionHeader); }
500 
501 private:
502     uint8_t mPad[kMaxLength];
503 } OT_TOOL_PACKED_END;
504 
505 /**
506  * This class implements IPv6 Pad1 Option generation and parsing. Pad1 does not follow default option header structure.
507  *
508  */
509 OT_TOOL_PACKED_BEGIN
510 class OptionPad1
511 {
512 public:
513     static constexpr uint8_t kType = 0x00;
514 
515     /**
516      * This method initializes the Pad1 header.
517      *
518      */
Init(void)519     void Init(void) { mType = kType; }
520 
521 private:
522     uint8_t mType;
523 } OT_TOOL_PACKED_END;
524 
525 /**
526  * This class implements IPv6 Fragment Header generation and parsing.
527  *
528  */
529 OT_TOOL_PACKED_BEGIN
530 class FragmentHeader
531 {
532 public:
533     /**
534      * This method initializes the IPv6 Fragment header.
535      *
536      */
Init(void)537     void Init(void)
538     {
539         mReserved       = 0;
540         mOffsetMore     = 0;
541         mIdentification = 0;
542     }
543 
544     /**
545      * This method returns the IPv6 Next Header value.
546      *
547      * @returns The IPv6 Next Header value.
548      *
549      */
GetNextHeader(void) const550     uint8_t GetNextHeader(void) const { return mNextHeader; }
551 
552     /**
553      * This method sets the IPv6 Next Header value.
554      *
555      * @param[in]  aNextHeader  The IPv6 Next Header value.
556      *
557      */
SetNextHeader(uint8_t aNextHeader)558     void SetNextHeader(uint8_t aNextHeader) { mNextHeader = aNextHeader; }
559 
560     /**
561      * This method returns the Fragment Offset value.
562      *
563      * @returns The Fragment Offset value.
564      *
565      */
GetOffset(void) const566     uint16_t GetOffset(void) const { return (HostSwap16(mOffsetMore) & kOffsetMask) >> kOffsetOffset; }
567 
568     /**
569      * This method sets the Fragment Offset value.
570      *
571      * @param[in]  aOffset  The Fragment Offset value.
572      */
SetOffset(uint16_t aOffset)573     void SetOffset(uint16_t aOffset)
574     {
575         uint16_t tmp = HostSwap16(mOffsetMore);
576         tmp          = (tmp & ~kOffsetMask) | ((aOffset << kOffsetOffset) & kOffsetMask);
577         mOffsetMore  = HostSwap16(tmp);
578     }
579 
580     /**
581      * This method returns the M flag value.
582      *
583      * @returns The M flag value.
584      *
585      */
IsMoreFlagSet(void) const586     bool IsMoreFlagSet(void) const { return HostSwap16(mOffsetMore) & kMoreFlag; }
587 
588     /**
589      * This method clears the M flag value.
590      *
591      */
ClearMoreFlag(void)592     void ClearMoreFlag(void) { mOffsetMore = HostSwap16(HostSwap16(mOffsetMore) & ~kMoreFlag); }
593 
594     /**
595      * This method sets the M flag value.
596      *
597      */
SetMoreFlag(void)598     void SetMoreFlag(void) { mOffsetMore = HostSwap16(HostSwap16(mOffsetMore) | kMoreFlag); }
599 
600     /**
601      * This method returns the frame identification.
602      *
603      * @returns The frame identification.
604      *
605      */
GetIdentification(void) const606     uint32_t GetIdentification(void) const { return mIdentification; }
607 
608     /**
609      * This method sets the frame identification.
610      *
611      * @param[in]  aIdentification  The fragment identification value.
612      */
SetIdentification(uint32_t aIdentification)613     void SetIdentification(uint32_t aIdentification) { mIdentification = aIdentification; }
614 
615     /**
616      * This method returns the next valid payload length for a fragment.
617      *
618      * @param[in]  aLength  The payload length to be validated for a fragment.
619      *
620      * @returns Valid IPv6 fragment payload length.
621      *
622      */
MakeDivisibleByEight(uint16_t aLength)623     static inline uint16_t MakeDivisibleByEight(uint16_t aLength) { return aLength & 0xfff8; }
624 
625     /**
626      * This method converts the fragment offset of 8-octet units into bytes.
627      *
628      * @param[in]  aOffset  The fragment offset in 8-octet units.
629      *
630      * @returns The fragment offset in bytes.
631      *
632      */
FragmentOffsetToBytes(uint16_t aOffset)633     static inline uint16_t FragmentOffsetToBytes(uint16_t aOffset) { return static_cast<uint16_t>(aOffset << 3); }
634 
635     /**
636      * This method converts a fragment offset in bytes into a fragment offset in 8-octet units.
637      *
638      * @param[in]  aOffset  The fragment offset in bytes.
639      *
640      * @returns The fragment offset in 8-octet units.
641      */
BytesToFragmentOffset(uint16_t aOffset)642     static inline uint16_t BytesToFragmentOffset(uint16_t aOffset) { return aOffset >> 3; }
643 
644 private:
645     static constexpr uint8_t  kOffsetOffset = 3;
646     static constexpr uint16_t kOffsetMask   = 0xfff8;
647     static constexpr uint16_t kMoreFlag     = 1;
648 
649     uint8_t  mNextHeader;
650     uint8_t  mReserved;
651     uint16_t mOffsetMore;
652     uint32_t mIdentification;
653 } OT_TOOL_PACKED_END;
654 
655 /**
656  * @}
657  *
658  */
659 
660 } // namespace Ip6
661 } // namespace ot
662 
663 #endif // IP6_HEADERS_HPP_
664