blob: c6846a7fc58489c4e25bf241bdcf9068f74fc6f4 [file] [log] [blame]
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file includes definitions for IPv6 packet processing.
*/
#ifndef IP6_HEADERS_HPP_
#define IP6_HEADERS_HPP_
#include "openthread-core-config.h"
#include <stddef.h>
#include "common/clearable.hpp"
#include "common/encoding.hpp"
#include "common/message.hpp"
#include "net/ip6_address.hpp"
#include "net/ip6_types.hpp"
#include "net/netif.hpp"
#include "net/socket.hpp"
namespace ot {
/**
* @namespace ot::Ip6
*
* @brief
* This namespace includes definitions for IPv6 networking.
*
*/
namespace Ip6 {
using ot::Encoding::BigEndian::HostSwap16;
using ot::Encoding::BigEndian::HostSwap32;
/**
* @addtogroup core-ipv6
*
* @brief
* This module includes definitions for the IPv6 network layer.
*
* @{
*
* @defgroup core-ip6-icmp6 ICMPv6
* @defgroup core-ip6-ip6 IPv6
* @defgroup core-ip6-mpl MPL
* @defgroup core-ip6-netif Network Interfaces
*
* @}
*
*/
/**
* @addtogroup core-ip6-ip6
*
* @brief
* This module includes definitions for core IPv6 networking.
*
* @{
*
*/
/**
* This class implements IPv6 header generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class Header : public Clearable<Header>
{
public:
static constexpr uint8_t kPayloadLengthFieldOffset = 4; ///< Offset of Payload Length field in IPv6 header.
static constexpr uint8_t kNextHeaderFieldOffset = 6; ///< Offset of Next Header field in IPv6 header.
static constexpr uint8_t kHopLimitFieldOffset = 7; ///< Offset of Hop Limit field in IPv6 header.
static constexpr uint8_t kSourceFieldOffset = 8; ///< Offset of Source Address field in IPv6 header.
static constexpr uint8_t kDestinationFieldOffset = 24; ///< Offset of Destination Address field in IPv6 header.
/**
* This method initializes the Version to 6 and sets Traffic Class and Flow fields to zero.
*
* The other fields in the IPv6 header remain unchanged.
*
*/
void InitVersionTrafficClassFlow(void) { SetVerionTrafficClassFlow(kVersTcFlowInit); }
/**
* This method indicates whether or not the header appears to be well-formed.
*
* @retval TRUE If the header appears to be well-formed.
* @retval FALSE If the header does not appear to be well-formed.
*
*/
bool IsValid(void) const;
/**
* This method indicates whether or not the IPv6 Version is set to 6.
*
* @retval TRUE If the IPv6 Version is set to 6.
* @retval FALSE If the IPv6 Version is not set to 6.
*
*/
bool IsVersion6(void) const { return (mVerTcFlow.m8[0] & kVersionMask) == kVersion6; }
/**
* This method gets the combination of Version, Traffic Class, and Flow fields as a 32-bit value.
*
* @returns The Version, Traffic Class, and Flow fields as a 32-bit value.
*
*/
uint32_t GetVerionTrafficClassFlow(void) const { return HostSwap32(mVerTcFlow.m32); }
/**
* This method sets the combination of Version, Traffic Class, and Flow fields as a 32-bit value.
*
* @param[in] aVerTcFlow The Version, Traffic Class, and Flow fields as a 32-bit value.
*
*/
void SetVerionTrafficClassFlow(uint32_t aVerTcFlow) { mVerTcFlow.m32 = HostSwap32(aVerTcFlow); }
/**
* This method gets the Traffic Class field.
*
* @returns The Traffic Class field.
*
*/
uint8_t GetTrafficClass(void) const
{
return static_cast<uint8_t>((HostSwap16(mVerTcFlow.m16[0]) & kTrafficClassMask) >> kTrafficClassOffset);
}
/**
* This method sets the Traffic Class filed.
*
* @param[in] aTc The Traffic Class value.
*
*/
void SetTrafficClass(uint8_t aTc)
{
mVerTcFlow.m16[0] = HostSwap16((HostSwap16(mVerTcFlow.m16[0]) & ~kTrafficClassMask) |
((static_cast<uint16_t>(aTc) << kTrafficClassOffset) & kTrafficClassMask));
}
/**
* This method gets the 6-bit Differentiated Services Code Point (DSCP) from Traffic Class field.
*
* @returns The DSCP value.
*
*/
uint8_t GetDscp(void) const
{
return static_cast<uint8_t>((HostSwap16(mVerTcFlow.m16[0]) & kDscpMask) >> kDscpOffset);
}
/**
* This method sets 6-bit Differentiated Services Code Point (DSCP) in IPv6 header.
*
* @param[in] aDscp The DSCP value.
*
*/
void SetDscp(uint8_t aDscp)
{
mVerTcFlow.m16[0] = HostSwap16((HostSwap16(mVerTcFlow.m16[0]) & ~kDscpMask) |
((static_cast<uint16_t>(aDscp) << kDscpOffset) & kDscpMask));
}
/**
* This method gets the 2-bit Explicit Congestion Notification (ECN) from Traffic Class field.
*
* @returns The ECN value.
*
*/
Ecn GetEcn(void) const { return static_cast<Ecn>((mVerTcFlow.m8[1] & kEcnMask) >> kEcnOffset); }
/**
* This method sets the 2-bit Explicit Congestion Notification (ECN) in IPv6 header..
*
* @param[in] aEcn The ECN value.
*
*/
void SetEcn(Ecn aEcn) { mVerTcFlow.m8[1] = (mVerTcFlow.m8[1] & ~kEcnMask) | ((aEcn << kEcnOffset) & kEcnMask); }
/**
* This method gets the 20-bit Flow field.
*
* @returns The Flow value.
*
*/
uint32_t GetFlow(void) const { return HostSwap32(mVerTcFlow.m32) & kFlowMask; }
/**
* This method sets the 20-bit Flow field in IPv6 header.
*
* @param[in] aFlow The Flow value.
*
*/
void SetFlow(uint32_t aFlow)
{
mVerTcFlow.m32 = HostSwap32((HostSwap32(mVerTcFlow.m32) & ~kFlowMask) | (aFlow & kFlowMask));
}
/**
* This method returns the IPv6 Payload Length value.
*
* @returns The IPv6 Payload Length value.
*
*/
uint16_t GetPayloadLength(void) const { return HostSwap16(mPayloadLength); }
/**
* This method sets the IPv6 Payload Length value.
*
* @param[in] aLength The IPv6 Payload Length value.
*
*/
void SetPayloadLength(uint16_t aLength) { mPayloadLength = HostSwap16(aLength); }
/**
* This method returns the IPv6 Next Header value.
*
* @returns The IPv6 Next Header value.
*
*/
uint8_t GetNextHeader(void) const { return mNextHeader; }
/**
* This method sets the IPv6 Next Header value.
*
* @param[in] aNextHeader The IPv6 Next Header value.
*
*/
void SetNextHeader(uint8_t aNextHeader) { mNextHeader = aNextHeader; }
/**
* This method returns the IPv6 Hop Limit value.
*
* @returns The IPv6 Hop Limit value.
*
*/
uint8_t GetHopLimit(void) const { return mHopLimit; }
/**
* This method sets the IPv6 Hop Limit value.
*
* @param[in] aHopLimit The IPv6 Hop Limit value.
*
*/
void SetHopLimit(uint8_t aHopLimit) { mHopLimit = aHopLimit; }
/**
* This method returns the IPv6 Source address.
*
* @returns A reference to the IPv6 Source address.
*
*/
Address &GetSource(void) { return mSource; }
/**
* This method returns the IPv6 Source address.
*
* @returns A reference to the IPv6 Source address.
*
*/
const Address &GetSource(void) const { return mSource; }
/**
* This method sets the IPv6 Source address.
*
* @param[in] aSource A reference to the IPv6 Source address.
*
*/
void SetSource(const Address &aSource) { mSource = aSource; }
/**
* This method returns the IPv6 Destination address.
*
* @returns A reference to the IPv6 Destination address.
*
*/
Address &GetDestination(void) { return mDestination; }
/**
* This method returns the IPv6 Destination address.
*
* @returns A reference to the IPv6 Destination address.
*
*/
const Address &GetDestination(void) const { return mDestination; }
/**
* This method sets the IPv6 Destination address.
*
* @param[in] aDestination A reference to the IPv6 Destination address.
*
*/
void SetDestination(const Address &aDestination) { mDestination = aDestination; }
/**
* This method parses and validates the IPv6 header from a given message.
*
* The header is read from @p aMessage at offset zero.
*
* @param[in] aMessage The IPv6 message.
*
* @retval kErrorNone Successfully parsed the IPv6 header from @p aMessage.
* @retval kErrorParse Malformed IPv6 header or message (e.g., message does not contained expected payload length).
*
*/
Error ParseFrom(const Message &aMessage);
private:
// IPv6 header `mVerTcFlow` field:
//
// | m16[0] | m16[1] |
// | m8[0] | m8[1] | m8[2] | m8[3] |
// +---------------+---------------+---------------+---------------+
// |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|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |Version| DSCP |ECN| Flow Label |
// | | Traffic Class | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
static constexpr uint8_t kVersion6 = 0x60; // Use with `mVerTcFlow.m8[0]`
static constexpr uint8_t kVersionMask = 0xf0; // Use with `mVerTcFlow.m8[0]`
static constexpr uint8_t kTrafficClassOffset = 4; // Use with `mVerTcFlow.m16[0]`
static constexpr uint16_t kTrafficClassMask = 0x0ff0; // Use with `mVerTcFlow.m16[0]`
static constexpr uint8_t kDscpOffset = 6; // Use with `mVerTcFlow.m16[0]`
static constexpr uint16_t kDscpMask = 0x0fc0; // Use with `mVerTcFlow.m16[0]`
static constexpr uint8_t kEcnOffset = 4; // Use with `mVerTcFlow.m8[1]`
static constexpr uint8_t kEcnMask = 0x30; // Use with `mVerTcFlow.m8[1]`
static constexpr uint32_t kFlowMask = 0x000fffff; // Use with `mVerTcFlow.m32`
static constexpr uint32_t kVersTcFlowInit = 0x60000000; // Version 6, TC and flow zero.
union OT_TOOL_PACKED_FIELD
{
uint8_t m8[sizeof(uint32_t) / sizeof(uint8_t)];
uint16_t m16[sizeof(uint32_t) / sizeof(uint16_t)];
uint32_t m32;
} mVerTcFlow;
uint16_t mPayloadLength;
uint8_t mNextHeader;
uint8_t mHopLimit;
Address mSource;
Address mDestination;
} OT_TOOL_PACKED_END;
/**
* This class implements IPv6 Extension Header generation and processing.
*
*/
OT_TOOL_PACKED_BEGIN
class ExtensionHeader
{
public:
/**
* This method returns the IPv6 Next Header value.
*
* @returns The IPv6 Next Header value.
*
*/
uint8_t GetNextHeader(void) const { return mNextHeader; }
/**
* This method sets the IPv6 Next Header value.
*
* @param[in] aNextHeader The IPv6 Next Header value.
*
*/
void SetNextHeader(uint8_t aNextHeader) { mNextHeader = aNextHeader; }
/**
* This method returns the IPv6 Header Extension Length value.
*
* @returns The IPv6 Header Extension Length value.
*
*/
uint8_t GetLength(void) const { return mLength; }
/**
* This method sets the IPv6 Header Extension Length value.
*
* @param[in] aLength The IPv6 Header Extension Length value.
*
*/
void SetLength(uint8_t aLength) { mLength = aLength; }
private:
uint8_t mNextHeader;
uint8_t mLength;
} OT_TOOL_PACKED_END;
/**
* This class implements IPv6 Hop-by-Hop Options Header generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class HopByHopHeader : public ExtensionHeader
{
} OT_TOOL_PACKED_END;
/**
* This class implements IPv6 Options generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class OptionHeader
{
public:
/**
* Default constructor.
*
*/
OptionHeader(void)
: mType(0)
, mLength(0)
{
}
/**
* This method returns the IPv6 Option Type value.
*
* @returns The IPv6 Option Type value.
*
*/
uint8_t GetType(void) const { return mType; }
/**
* This method sets the IPv6 Option Type value.
*
* @param[in] aType The IPv6 Option Type value.
*
*/
void SetType(uint8_t aType) { mType = aType; }
/**
* IPv6 Option Type actions for unrecognized IPv6 Options.
*
*/
enum Action : uint8_t
{
kActionSkip = 0x00, ///< skip over this option and continue processing the header
kActionDiscard = 0x40, ///< discard the packet
kActionForceIcmp = 0x80, ///< discard the packet and forcibly send an ICMP Parameter Problem
kActionIcmp = 0xc0, ///< discard packet and conditionally send an ICMP Parameter Problem
};
/**
* This method returns the IPv6 Option action for unrecognized IPv6 Options.
*
* @returns The IPv6 Option action for unrecognized IPv6 Options.
*
*/
Action GetAction(void) const { return static_cast<Action>(mType & kActionMask); }
/**
* This method returns the IPv6 Option Length value.
*
* @returns The IPv6 Option Length value.
*
*/
uint8_t GetLength(void) const { return mLength; }
/**
* This method sets the IPv6 Option Length value.
*
* @param[in] aLength The IPv6 Option Length value.
*
*/
void SetLength(uint8_t aLength) { mLength = aLength; }
private:
static constexpr uint8_t kActionMask = 0xc0;
uint8_t mType;
uint8_t mLength;
} OT_TOOL_PACKED_END;
/**
* This class implements IPv6 PadN Option generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class OptionPadN : public OptionHeader
{
public:
static constexpr uint8_t kType = 0x01; ///< PadN type
static constexpr uint8_t kData = 0x00; ///< PadN specific data
static constexpr uint8_t kMaxLength = 0x05; ///< Maximum length of PadN option data
/**
* This method initializes the PadN header.
*
* @param[in] aPadLength The length of needed padding. Allowed value from
* range 2-7.
*
*/
void Init(uint8_t aPadLength)
{
SetType(kType);
SetLength(aPadLength - sizeof(OptionHeader));
memset(mPad, kData, aPadLength - sizeof(OptionHeader));
}
/**
* This method returns the total IPv6 Option Length value including option
* header.
*
* @returns The total IPv6 Option Length.
*
*/
uint8_t GetTotalLength(void) const { return GetLength() + sizeof(OptionHeader); }
private:
uint8_t mPad[kMaxLength];
} OT_TOOL_PACKED_END;
/**
* This class implements IPv6 Pad1 Option generation and parsing. Pad1 does not follow default option header structure.
*
*/
OT_TOOL_PACKED_BEGIN
class OptionPad1
{
public:
static constexpr uint8_t kType = 0x00;
/**
* This method initializes the Pad1 header.
*
*/
void Init(void) { mType = kType; }
private:
uint8_t mType;
} OT_TOOL_PACKED_END;
/**
* This class implements IPv6 Fragment Header generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class FragmentHeader
{
public:
/**
* This method initializes the IPv6 Fragment header.
*
*/
void Init(void)
{
mReserved = 0;
mOffsetMore = 0;
mIdentification = 0;
}
/**
* This method returns the IPv6 Next Header value.
*
* @returns The IPv6 Next Header value.
*
*/
uint8_t GetNextHeader(void) const { return mNextHeader; }
/**
* This method sets the IPv6 Next Header value.
*
* @param[in] aNextHeader The IPv6 Next Header value.
*
*/
void SetNextHeader(uint8_t aNextHeader) { mNextHeader = aNextHeader; }
/**
* This method returns the Fragment Offset value.
*
* @returns The Fragment Offset value.
*
*/
uint16_t GetOffset(void) const { return (HostSwap16(mOffsetMore) & kOffsetMask) >> kOffsetOffset; }
/**
* This method sets the Fragment Offset value.
*
* @param[in] aOffset The Fragment Offset value.
*/
void SetOffset(uint16_t aOffset)
{
uint16_t tmp = HostSwap16(mOffsetMore);
tmp = (tmp & ~kOffsetMask) | ((aOffset << kOffsetOffset) & kOffsetMask);
mOffsetMore = HostSwap16(tmp);
}
/**
* This method returns the M flag value.
*
* @returns The M flag value.
*
*/
bool IsMoreFlagSet(void) const { return HostSwap16(mOffsetMore) & kMoreFlag; }
/**
* This method clears the M flag value.
*
*/
void ClearMoreFlag(void) { mOffsetMore = HostSwap16(HostSwap16(mOffsetMore) & ~kMoreFlag); }
/**
* This method sets the M flag value.
*
*/
void SetMoreFlag(void) { mOffsetMore = HostSwap16(HostSwap16(mOffsetMore) | kMoreFlag); }
/**
* This method returns the frame identification.
*
* @returns The frame identification.
*
*/
uint32_t GetIdentification(void) const { return mIdentification; }
/**
* This method sets the frame identification.
*
* @param[in] aIdentification The fragment identification value.
*/
void SetIdentification(uint32_t aIdentification) { mIdentification = aIdentification; }
/**
* This method returns the next valid payload length for a fragment.
*
* @param[in] aLength The payload length to be validated for a fragment.
*
* @returns Valid IPv6 fragment payload length.
*
*/
static inline uint16_t MakeDivisibleByEight(uint16_t aLength) { return aLength & 0xfff8; }
/**
* This method converts the fragment offset of 8-octet units into bytes.
*
* @param[in] aOffset The fragment offset in 8-octet units.
*
* @returns The fragment offset in bytes.
*
*/
static inline uint16_t FragmentOffsetToBytes(uint16_t aOffset) { return static_cast<uint16_t>(aOffset << 3); }
/**
* This method converts a fragment offset in bytes into a fragment offset in 8-octet units.
*
* @param[in] aOffset The fragment offset in bytes.
*
* @returns The fragment offset in 8-octet units.
*/
static inline uint16_t BytesToFragmentOffset(uint16_t aOffset) { return aOffset >> 3; }
private:
static constexpr uint8_t kOffsetOffset = 3;
static constexpr uint16_t kOffsetMask = 0xfff8;
static constexpr uint16_t kMoreFlag = 1;
uint8_t mNextHeader;
uint8_t mReserved;
uint16_t mOffsetMore;
uint32_t mIdentification;
} OT_TOOL_PACKED_END;
/**
* @}
*
*/
} // namespace Ip6
} // namespace ot
#endif // IP6_HEADERS_HPP_