blob: 819c8e210636c9385e108eb517b55890040c2bef [file]
/*
* Copyright (c) 2020, 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 Neighbor Discovery (ND).
*
* See RFC 4861 (https://tools.ietf.org/html/rfc4861) and RFC 4191 (https://tools.ietf.org/html/rfc4191).
*/
#ifndef OT_CORE_NET_ND6_HPP_
#define OT_CORE_NET_ND6_HPP_
#include "openthread-core-config.h"
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
#include <stdint.h>
#include <openthread/netdata.h>
#include <openthread/platform/infra_if.h>
#include <openthread/platform/toolchain.h>
#include "border_router/infra_if.hpp"
#include "common/const_cast.hpp"
#include "common/encoding.hpp"
#include "common/equatable.hpp"
#include "common/heap_array.hpp"
#include "net/icmp6.hpp"
#include "net/ip6.hpp"
#include "net/ip6_headers.hpp"
#include "thread/network_data_types.hpp"
namespace ot {
namespace Ip6 {
namespace Nd {
typedef NetworkData::RoutePreference RoutePreference; ///< Route Preference
typedef Data<kWithUint16Length> Icmp6Packet; ///< A data buffer for an ICMPv6 packet.
typedef otPlatInfraIfLinkLayerAddress LinkLayerAddress; ///< An infra-if link-layer address.
/**
* Represents the variable length options in Neighbor Discovery messages.
*
* @sa PrefixInfoOption
* @sa RouteInfoOption
*/
OT_TOOL_PACKED_BEGIN
class Option
{
friend class RouterAdvert;
public:
enum Type : uint8_t
{
kSourceLinkLayerAddr = 1, ///< Source Link Layer Address Option.
kTargetLinkLayerAddr = 2, ///< Target Link Layer Address Option.
kTypePrefixInfo = 3, ///< Prefix Information Option.
kTypeRouteInfo = 24, ///< Route Information Option.
kTypeRecursiveDnsServer = 25, ///< Recursive DNS Server (RDNSS) Option.
kTypeRaFlagsExtension = 26, ///< RA Flags Extension Option.
kTypeNat64Prefix = 38, ///< NAT64 Prefix Option (aka PREF64 Option).
};
static constexpr uint16_t kLengthUnit = 8; ///< The unit of length in octets.
/**
* Gets the option type.
*
* @returns The option type.
*/
uint8_t GetType(void) const { return mType; }
/**
* Sets the option type.
*
* @param[in] aType The option type.
*/
void SetType(Type aType) { mType = aType; }
/**
* Sets the length based on a given total option size in bytes.
*
* Th option must end on a 64-bit boundary, so the length is derived as `(aSize + 7) / 8 * 8`.
*
* @param[in] aSize The size of option in bytes.
*/
void SetSize(uint16_t aSize) { mLength = static_cast<uint8_t>(DivideAndRoundUp(aSize, kLengthUnit)); }
/**
* Returns the size of the option in bytes.
*
* @returns The size of the option in bytes.
*/
uint16_t GetSize(void) const { return mLength * kLengthUnit; }
/**
* Sets the length of the option (in unit of 8 bytes).
*
* @param[in] aLength The length of the option in unit of 8 bytes.
*/
void SetLength(uint8_t aLength) { mLength = aLength; }
/**
* Returns the length of the option (in unit of 8 bytes).
*
* @returns The length of the option in unit of 8 bytes.
*/
uint16_t GetLength(void) const { return mLength; }
/**
* Indicates whether or not this option is valid.
*
* @retval TRUE The option is valid.
* @retval FALSE The option is not valid.
*/
bool IsValid(void) const { return mLength > 0; }
private:
class Iterator : public Unequatable<Iterator>
{
public:
Iterator(void);
Iterator(const void *aStart, const void *aEnd);
const Option &operator*(void) { return *mOption; }
void operator++(void) { Advance(); }
void operator++(int) { Advance(); }
bool operator==(const Iterator &aOther) const { return mOption == aOther.mOption; }
private:
static const Option *Next(const Option *aOption);
void Advance(void);
const Option *Validate(const Option *aOption) const;
const Option *mOption;
const Option *mEnd;
};
uint8_t mType; // Type of the option.
uint8_t mLength; // Length of the option in unit of 8 octets, including the `mType` and `mLength` fields.
} OT_TOOL_PACKED_END;
/**
* Represents the Prefix Information Option.
*
* See section 4.6.2 of RFC 4861 for definition of this option [https://tools.ietf.org/html/rfc4861#section-4.6.2]
*/
OT_TOOL_PACKED_BEGIN
class PrefixInfoOption : public Option, private Clearable<PrefixInfoOption>
{
friend class Clearable<PrefixInfoOption>;
public:
static constexpr Type kType = kTypePrefixInfo; ///< Prefix Information Option Type.
static constexpr uint8_t kOnLinkFlag = 0x80; ///< On-link - L flag.
static constexpr uint8_t kAutoConfigFlag = 0x40; ///< Autonomous address-configuration - A flag.
static constexpr uint8_t kDhcp6PdPreferredFlag = 0x10; ///< DHCPv6-PD preferred - P flag.
typedef uint8_t Flags; ///< Represents the flags as a bitmap.
/**
* Initializes the Prefix Info option with proper type and length and sets all other fields to zero.
*/
void Init(void);
/**
* Gets the raw flag bitmap.
*
* @return The flags bitmap.
*/
Flags GetFlags(void) const { return mFlags; }
/**
* Sets the raw flag bitmap.
*
* @param[in] aFlags The flags bitmap.
*/
void SetFlags(Flags aFlags) { mFlags = aFlags; }
/**
* Indicates whether or not the on-link flag is set.
*
* @retval TRUE The on-link flag is set.
* @retval FALSE The on-link flag is not set.
*/
bool IsOnLinkFlagSet(void) const { return (mFlags & kOnLinkFlag) != 0; }
/**
* Sets the on-link (L) flag.
*/
void SetOnLinkFlag(void) { mFlags |= kOnLinkFlag; }
/**
* Clears the on-link (L) flag.
*/
void ClearOnLinkFlag(void) { mFlags &= ~kOnLinkFlag; }
/**
* Indicates whether or not the autonomous address-configuration (A) flag is set.
*
* @retval TRUE The auto address-config flag is set.
* @retval FALSE The auto address-config flag is not set.
*/
bool IsAutoAddrConfigFlagSet(void) const { return (mFlags & kAutoConfigFlag) != 0; }
/**
* Sets the autonomous address-configuration (A) flag.
*/
void SetAutoAddrConfigFlag(void) { mFlags |= kAutoConfigFlag; }
/**
* Clears the autonomous address-configuration (A) flag.
*/
void ClearAutoAddrConfigFlag(void) { mFlags &= ~kAutoConfigFlag; }
/**
* Indicates whether or not the DhCPv6-PD Preferred (P) flag is set.
*
* @retval TRUE The DHCPv6-PD Preferred (P) flag is set.
* @retval FALSE The DHCPv6-PD Preferred (P) flag is not set.
*/
bool IsDhcp6PdPreferredFlagSet(void) const { return (mFlags & kDhcp6PdPreferredFlag) != 0; }
/**
* Sets the valid lifetime of the prefix in seconds.
*
* @param[in] aValidLifetime The valid lifetime in seconds.
*/
void SetValidLifetime(uint32_t aValidLifetime) { mValidLifetime = BigEndian::HostSwap32(aValidLifetime); }
/**
* THis method gets the valid lifetime of the prefix in seconds.
*
* @returns The valid lifetime in seconds.
*/
uint32_t GetValidLifetime(void) const { return BigEndian::HostSwap32(mValidLifetime); }
/**
* Sets the preferred lifetime of the prefix in seconds.
*
* @param[in] aPreferredLifetime The preferred lifetime in seconds.
*/
void SetPreferredLifetime(uint32_t aPreferredLifetime)
{
mPreferredLifetime = BigEndian::HostSwap32(aPreferredLifetime);
}
/**
* THis method returns the preferred lifetime of the prefix in seconds.
*
* @returns The preferred lifetime in seconds.
*/
uint32_t GetPreferredLifetime(void) const { return BigEndian::HostSwap32(mPreferredLifetime); }
/**
* Returns the prefix length (in bits).
*
* @returns The prefix length (in bits).
*/
uint8_t GetPrefixLength(void) const { return mPrefixLength; }
/**
* Sets the prefix length (in bits).
*
* @param[in] aPrefixLength The prefix length (in bits).
*/
void SetPrefixLength(uint8_t aPrefixLength) { mPrefixLength = aPrefixLength; }
/**
* Sets the prefix.
*
* @param[in] aPrefix The prefix contained in this option.
*/
void SetPrefix(const Prefix &aPrefix);
/**
* Gets the prefix in this option.
*
* @param[out] aPrefix Reference to a `Prefix` to return the prefix.
*/
void GetPrefix(Prefix &aPrefix) const;
/**
* Indicates whether or not the option is valid.
*
* @retval TRUE The option is valid
* @retval FALSE The option is not valid.
*/
bool IsValid(void) const;
PrefixInfoOption(void) = delete;
private:
// Prefix Information Option
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type | Length | Prefix Length |L|A|R|P| Rsvd1 |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Valid Lifetime |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Preferred Lifetime |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Reserved2 |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// + +
// | |
// + Prefix +
// | |
// + +
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Reference for P Flag (DHCPv6-PD preferred flag):
// https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.ietf-6man-pio-pflag.xml
uint8_t mPrefixLength; // The prefix length in bits.
uint8_t mFlags; // The flags field.
uint32_t mValidLifetime; // The valid lifetime of the prefix.
uint32_t mPreferredLifetime; // The preferred lifetime of the prefix.
uint32_t mReserved2; // The reserved field.
Address mPrefix; // The prefix.
} OT_TOOL_PACKED_END;
static_assert(sizeof(PrefixInfoOption) == 32, "invalid PrefixInfoOption structure");
/**
* Represents the Route Information Option.
*
* See section 2.3 of RFC 4191 for definition of this option. [https://tools.ietf.org/html/rfc4191#section-2.3]
*/
OT_TOOL_PACKED_BEGIN
class RouteInfoOption : public Option, private Clearable<RouteInfoOption>
{
friend class Clearable<RouteInfoOption>;
public:
static constexpr uint16_t kMinSize = kLengthUnit; ///< Minimum size (in bytes) of a Route Info Option
static constexpr Type kType = kTypeRouteInfo; ///< Route Information Option Type.
/**
* Initializes the option setting the type and clearing (setting to zero) all other fields.
*/
void Init(void);
/**
* Sets the route preference.
*
* @param[in] aPreference The route preference.
*/
void SetPreference(RoutePreference aPreference);
/**
* Gets the route preference.
*
* @returns The route preference.
*/
RoutePreference GetPreference(void) const;
/**
* Sets the lifetime of the route in seconds.
*
* @param[in] aLifetime The lifetime of the route in seconds.
*/
void SetRouteLifetime(uint32_t aLifetime) { mRouteLifetime = BigEndian::HostSwap32(aLifetime); }
/**
* Gets Route Lifetime in seconds.
*
* @returns The Route Lifetime in seconds.
*/
uint32_t GetRouteLifetime(void) const { return BigEndian::HostSwap32(mRouteLifetime); }
/**
* Sets the prefix and adjusts the option length based on the prefix length.
*
* @param[in] aPrefix The prefix contained in this option.
*/
void SetPrefix(const Prefix &aPrefix);
/**
* Gets the prefix in this option.
*
* @param[out] aPrefix Reference to a `Prefix` to return the prefix.
*/
void GetPrefix(Prefix &aPrefix) const;
/**
* Tells whether this option is valid.
*
* @returns A boolean indicates whether this option is valid.
*/
bool IsValid(void) const;
/**
* Calculates the minimum option length for a given prefix length.
*
* The option length (which is in unit of 8 octets) can be 1, 2, or 3 depending on the prefix length. It can be 1
* for a zero prefix length, 2 if the prefix length is not greater than 64, and 3 otherwise.
*
* @param[in] aPrefixLength The prefix length (in bits).
*
* @returns The option length (in unit of 8 octet) for @p aPrefixLength.
*/
static uint8_t OptionLengthForPrefix(uint8_t aPrefixLength);
/**
* Calculates the minimum option size (in bytes) for a given prefix length.
*
* @param[in] aPrefixLength The prefix length (in bits).
*
* @returns The option size (in bytes) for @p aPrefixLength.
*/
static uint16_t OptionSizeForPrefix(uint8_t aPrefixLength)
{
return kLengthUnit * OptionLengthForPrefix(aPrefixLength);
}
RouteInfoOption(void) = delete;
private:
// Route Information Option
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type | Length | Prefix Length |Resvd|Prf|Resvd|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Route Lifetime |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Prefix (Variable Length) |
// . .
// . .
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
static constexpr uint8_t kPreferenceOffset = 3;
static constexpr uint8_t kPreferenceMask = 3 << kPreferenceOffset;
uint8_t *GetPrefixBytes(void) { return AsNonConst(AsConst(this)->GetPrefixBytes()); }
const uint8_t *GetPrefixBytes(void) const { return reinterpret_cast<const uint8_t *>(this) + sizeof(*this); }
uint8_t mPrefixLength; // The prefix length in bits.
uint8_t mResvdPrf; // The preference.
uint32_t mRouteLifetime; // The lifetime in seconds.
// Followed by prefix bytes (variable length).
} OT_TOOL_PACKED_END;
static_assert(sizeof(RouteInfoOption) == 8, "invalid RouteInfoOption structure");
/**
* Represents an RA Flags Extension Option.
*
* See RFC-5175 [https://tools.ietf.org/html/rfc5175]
*/
OT_TOOL_PACKED_BEGIN
class RaFlagsExtOption : public Option, private Clearable<RaFlagsExtOption>
{
friend class Clearable<RaFlagsExtOption>;
public:
static constexpr Type kType = kTypeRaFlagsExtension; ///< RA Flags Extension Option type.
/**
* Initializes the RA Flags Extension option with proper type and length and sets all flags to zero.
*/
void Init(void);
/**
* Tells whether this option is valid.
*
* @returns A boolean indicates whether this option is valid.
*/
bool IsValid(void) const { return GetSize() >= sizeof(*this); }
RaFlagsExtOption(void) = delete;
private:
// RA Flags Extension Option
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type | Length | Bit fields available ..
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// ... for assignment |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ .
uint8_t mFlags[6];
} OT_TOOL_PACKED_END;
static_assert(sizeof(RaFlagsExtOption) == 8, "invalid RaFlagsExtOption structure");
/**
* Represents the NAT64 Prefix Option (aka PREF64 Option).
*
* See section 4 of RFC 8781 for definition of this option [https://tools.ietf.org/html/rfc8781#section-4]
*/
OT_TOOL_PACKED_BEGIN
class Nat64PrefixOption : public Option, private Clearable<Nat64PrefixOption>
{
friend class Clearable<Nat64PrefixOption>;
public:
static constexpr Type kType = kTypeNat64Prefix; ///< NAT64 Prefix Option Type.
/**
* Initializes the NAT64 Prefix option with proper type and length and sets all other fields to zero.
*/
void Init(void);
/**
* Sets the NAT64 prefix lifetime.
*
* @param[in] aLifetime The prefix lifetime in seconds.
*/
void SetLifetime(uint32_t aLifetime);
/**
* Returns the NAT64 prefix lifetime in seconds.
*
* The NAT64 prefix lifetime is encoded by scaled lifetime in units of 8 seconds.
*
* @returns The prefix lifetime in seconds.
*/
uint32_t GetLifetime(void) const
{
return (BigEndian::HostSwap16(mPrefixAttr) >> kScaledLifetimeOffset) * kLifetimeScalingUnit;
}
/**
* Sets the prefix.
*
* @param[in] aPrefix The prefix contained in this option.
*
* @retval kErrorNone Successfully set the prefix.
* @retval kErrorInvalidArgs The prefix length in @p aPrefix is not a valid NAT64 prefix length (must be one of
* 32, 40, 48, 56, 64, or 96).
*/
Error SetPrefix(const Prefix &aPrefix);
/**
* Gets the prefix in this option.
*
* @param[out] aPrefix Reference to a `Prefix` to return the prefix.
*
* @retval kErrorNone Successfully retrieved the prefix.
* @retval kErrorParse The Prefix Length Code is not valid.
*/
Error GetPrefix(Prefix &aPrefix) const;
/**
* Indicates whether or not the option is valid.
*
* @retval TRUE The option is valid
* @retval FALSE The option is not valid.
*/
bool IsValid(void) const;
Nat64PrefixOption(void) = delete;
private:
// NAT64 Prefix Option
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type | Length | Scaled Lifetime | PLC |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// + +
// | Highest 96 bits of the Prefix |
// + +
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
static constexpr uint32_t kLifetimeScalingUnit = 8; // Lifetime is scaled in units of 8 seconds.
static constexpr uint16_t kScaledLifetimeOffset = 3; // Scaled Lifetime offset in `mPrefixAttr`.
static constexpr uint16_t kPrefixLengthCodeMask = 0x07; // Prefix Length Code mask in `mPrefixAttr`.
static const uint8_t kPrefixLengths[]; // Map from prefix length code to prefix length in bits.
/**
* Returns the NAT64 prefix length code.
*
* The prefix length code values 0, 1, 2, 3, 4, and 5 indicate the NAT64 prefix length of 96, 64, 56, 48, 40, and 32
* bits, respectively.
*
* @returns The prefix length code.
*/
uint8_t GetPrefixLengthCode(void) const { return BigEndian::HostSwap16(mPrefixAttr) & kPrefixLengthCodeMask; }
/**
* Sets the NAT64 prefix length code.
*
* @param[in] aPrefixLengthCode The prefix length code.
*/
void SetPrefixLengthCode(const uint8_t aPrefixLengthCode);
uint16_t mPrefixAttr; // The prefix attributes (Scaled Lifetime and Prefix Length Code).
uint8_t mPrefixMsb[12];
} OT_TOOL_PACKED_END;
static_assert(sizeof(Nat64PrefixOption) == 16, "invalid Nat64PrefixOption structure");
/**
* Represents the Recursive DNS Server (RDNSS) Option.
*
* See section 5.1 of RFC 8106 [https://datatracker.ietf.org/doc/html/rfc8106#section-5.1].
*/
OT_TOOL_PACKED_BEGIN
class RecursiveDnsServerOption : public Option, private Clearable<RecursiveDnsServerOption>
{
friend class Clearable<RecursiveDnsServerOption>;
public:
static constexpr uint16_t kMinSize = kLengthUnit; ///< Minimum size (in bytes) of a RDNSS Option.
static constexpr Type kType = kTypeRecursiveDnsServer; ///< Route Information Option Type.
/**
* Initializes the option setting the type and clearing (setting to zero) all other fields.
*/
void Init(void);
/**
* Tells whether this option is valid.
*
* @returns A boolean indicates whether this option is valid.
*/
bool IsValid(void) const { return (GetLength() > 0); }
/**
* Sets the Lifetime field.
*
* @param[in] aLifetime The lifetime in seconds.
*/
void SetLifetime(uint32_t aLifetime) { mLifetime = BigEndian::HostSwap32(aLifetime); }
/**
* Gets the Lifetime fields
*
* @returns The Lifetime in seconds.
*/
uint32_t GetLifetime(void) const { return BigEndian::HostSwap32(mLifetime); }
/**
* Gets the numbers of IPv6 addresses.
*
* @returns Number of IPv6 addresses.
*/
uint16_t GetNumAddresses(void) const { return IsValid() ? (GetLength() - 1) / 2 : 0; }
/**
* Returns a pointer to array of IPv6 addresses of DNS server.
*
* @returns A pointer to the array of IPv6 addresses.
*/
const Address *GetAddresses(void) const
{
return reinterpret_cast<const Address *>(reinterpret_cast<const uint8_t *>(this) + sizeof(*this));
}
/**
* Returns a pointer to array of IPv6 addresses of DNS server.
*
* @returns A pointer to the array of IPv6 addresses.
*/
Address *GetAddresses(void) { return AsNonConst(AsConst(this)->GetAddresses()); }
/**
* Returns the IPv6 address at a given index.
*
* Caller MUST ensure that @p aIndex is valid and smaller than `GetNumberOfAddresses()`. Otherwise the behavior
* of this method is undefined.
*
* @param[in] aIndex The index.
*
* @returns The IPv6 address at @p aIndex.
*/
const Address &GetAddressAt(uint16_t aIndex) const { return GetAddresses()[aIndex]; }
/**
* Calculates the option length for a given number of IPv6 addresses.
*
* @param[in] aNumAddresses Number of IPv6 addresses
*
* @returns The option length (in unit of 8 octets) for @p aNumAddresses.
*/
static uint8_t OptionLengthFor(uint8_t aNumAddresses);
RecursiveDnsServerOption(void) = delete;
private:
// RDNSS Option
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type | Length | Reserved |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Lifetime |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// : Addresses of IPv6 Recursive DNS Servers :
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
uint16_t mReserved;
uint32_t mLifetime;
// Followed by IPv6 Addresses of DNS servers (variable length).
} OT_TOOL_PACKED_END;
static_assert(sizeof(RecursiveDnsServerOption) == 8, "invalid RecursiveDnsServerOption structure");
/**
* Defines the ND6 Tx Message.
*/
class TxMessage
{
public:
/**
* Gets the prepared ND6 message as an `Icmp6Packet`.
*
* @param[out] aPacket A reference to an `Icmp6Packet`.
*/
void GetAsPacket(Icmp6Packet &aPacket) const { aPacket.Init(mArray.AsCArray(), mArray.GetLength()); }
/**
* Appends bytes from a given buffer to the ND6 message.
*
* @param[in] aBytes A pointer to the buffer containing the bytes to append.
* @param[in] aLength The buffer length.
*
* @retval kErrorNone Bytes are appended successfully.
* @retval kErrorNoBufs Insufficient available buffers to grow the message.
*/
Error AppendBytes(const uint8_t *aBytes, uint16_t aLength);
/**
* Appends a Source/Target Link Layer Address Option to the ND6 message.
*
* @param[in] aLinkLayerAddress The AIL Layer Address.
* @param[in] aType The type of Link Layer Address Option, Source or Target
*
* @retval kErrorNone Option is appended successfully.
* @retval kErrorNoBufs Insufficient available buffers to grow the message.
*/
Error AppendLinkLayerOption(LinkLayerAddress &aLinkLayerAddress, Option::Type aType);
/**
* Appends an object to the ND6 message.
*
* @tparam ObjectType The object type to append to the message.
*
* @param[in] aObject A reference to the object to append to the message.
*
* @retval kErrorNone Successfully appended the object.
* @retval kErrorNoBufs Insufficient available buffers to grow the message.
*/
template <typename ObjectType> Error Append(const ObjectType &aObject)
{
static_assert(!TypeTraits::IsPointer<ObjectType>::kValue, "ObjectType must not be a pointer");
return AppendBytes(reinterpret_cast<const uint8_t *>(&aObject), sizeof(ObjectType));
}
protected:
static constexpr uint16_t kCapacityIncrement = 256;
Option *AppendOption(uint16_t aOptionSize);
Heap::Array<uint8_t, kCapacityIncrement> mArray;
};
/**
* Defines Router Advertisement components.
*/
class RouterAdvert
{
public:
/**
* Represent an RA message header.
*
* See section 2.2 of RFC 4191 [https://datatracker.ietf.org/doc/html/rfc4191]
*/
OT_TOOL_PACKED_BEGIN
class Header : public Equatable<Header>, public Clearable<Header>
{
friend class Clearable<Header>;
public:
/**
* Initializes the Router Advertisement message with
* zero router lifetime, reachable time and retransmission timer.
*/
Header(void) { SetToDefault(); }
/**
* Indicates whether the header is valid by checking the type field to match Router Advertisement ICMPv6 type.
*
* @retval TRUE The header is valid.
* @retval FALSE The header is not valid.
*/
bool IsValid(void) const { return GetType() == Icmp::Header::kTypeRouterAdvert; }
/**
* Sets the RA message to default values.
*/
void SetToDefault(void);
/**
* Sets the checksum value.
*
* @param[in] aChecksum The checksum value.
*/
void SetChecksum(uint16_t aChecksum) { mChecksum = BigEndian::HostSwap16(aChecksum); }
/**
* Sets the Router Lifetime in seconds.
*
* @param[in] aRouterLifetime The router lifetime in seconds.
*/
void SetRouterLifetime(uint16_t aRouterLifetime) { mRouterLifetime = BigEndian::HostSwap16(aRouterLifetime); }
/**
* Gets the Router Lifetime (in seconds).
*
* Router Lifetime set to zero indicates that the sender is not a default router.
*
* @returns The router lifetime in seconds.
*/
uint16_t GetRouterLifetime(void) const { return BigEndian::HostSwap16(mRouterLifetime); }
/**
* Sets the default router preference.
*
* @param[in] aPreference The router preference.
*/
void SetDefaultRouterPreference(RoutePreference aPreference);
/**
* Gets the default router preference.
*
* @returns The router preference.
*/
RoutePreference GetDefaultRouterPreference(void) const;
/**
* Indicates whether or not the Managed Address Config Flag is set in the RA message header.
*
* @retval TRUE The Managed Address Config Flag is set.
* @retval FALSE The Managed Address Config Flag is not set.
*/
bool IsManagedAddressConfigFlagSet(void) const { return (mFlags & kManagedAddressConfigFlag) != 0; }
/**
* Sets the Managed Address Config Flag in the RA message.
*/
void SetManagedAddressConfigFlag(void) { mFlags |= kManagedAddressConfigFlag; }
/**
* Indicates whether or not the Other Config Flag is set in the RA message header.
*
* @retval TRUE The Other Config Flag is set.
* @retval FALSE The Other Config Flag is not set.
*/
bool IsOtherConfigFlagSet(void) const { return (mFlags & kOtherConfigFlag) != 0; }
/**
* Sets the Other Config Flag in the RA message.
*/
void SetOtherConfigFlag(void) { mFlags |= kOtherConfigFlag; }
/**
* Indicates whether or not the SNAC Router Flag is set in the RA message header.
*
* @retval TRUE The SNAC Router Flag is set.
* @retval FALSE The SNAC Router Flag is not set.
*/
bool IsSnacRouterFlagSet(void) const { return (mFlags & kSnacRouterFlag) != 0; }
/**
* Sets the SNAC Router Flag in the RA message header.
*/
void SetSnacRouterFlag(void) { mFlags |= kSnacRouterFlag; }
/**
* This method returns the ICMPv6 message type.
*
* @returns The ICMPv6 message type.
*/
Icmp::Header::Type GetType(void) const { return static_cast<Icmp::Header::Type>(mType); }
private:
// Router Advertisement Message
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type | Code | Checksum |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Cur Hop Limit |M|O| |Prf| |S| | Router Lifetime |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Reachable Time |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Retrans Timer |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Options ...
// +-+-+-+-+-+-+-+-+-+-+-+-
static constexpr uint8_t kManagedAddressConfigFlag = 1 << 7;
static constexpr uint8_t kOtherConfigFlag = 1 << 6;
static constexpr uint8_t kSnacRouterFlag = 1 << 1;
static constexpr uint8_t kPreferenceOffset = 3;
static constexpr uint8_t kPreferenceMask = 3 << kPreferenceOffset;
uint8_t mType;
uint8_t mCode;
uint16_t mChecksum;
uint8_t mCurHopLimit;
uint8_t mFlags;
uint16_t mRouterLifetime;
uint32_t mReachableTime;
uint32_t mRetransTimer;
} OT_TOOL_PACKED_END;
static_assert(sizeof(Header) == 16, "Invalid RA `Header`");
/**
* Represents a received RA message.
*/
class RxMessage
{
public:
/**
* Initializes the RA message from a received packet data buffer.
*
* @param[in] aPacket A received packet data.
*/
explicit RxMessage(const Icmp6Packet &aPacket)
: mData(aPacket)
{
}
/**
* Gets the RA message as an `Icmp6Packet`.
*
* @returns The RA message as an `Icmp6Packet`.
*/
const Icmp6Packet &GetAsPacket(void) const { return mData; }
/**
* Indicates whether or not the received RA message is valid.
*
* @retval TRUE If the RA message is valid.
* @retval FALSE If the RA message is not valid.
*/
bool IsValid(void) const
{
return (mData.GetBytes() != nullptr) && (mData.GetLength() >= sizeof(Header)) &&
(GetHeader().GetType() == Icmp::Header::kTypeRouterAdvert);
}
/**
* Gets the RA message's header.
*
* @returns The RA message's header.
*/
const Header &GetHeader(void) const { return *reinterpret_cast<const Header *>(mData.GetBytes()); }
/**
* Indicates whether or not the received RA message contains any options.
*
* @retval TRUE If the RA message contains at least one option.
* @retval FALSE If the RA message contains no options.
*/
bool ContainsAnyOptions(void) const { return (mData.GetLength() > sizeof(Header)); }
/**
* Returns pointer to the start of option bytes (after header).
*
* @returns Pointer to start of options.
*/
const uint8_t *GetOptionStart(void) const { return (mData.GetBytes() + sizeof(Header)); }
/**
* Gets the length (number of bytes) of options.
*
* @returns Number of bytes after header specifying RA options.
*/
uint16_t GetOptionLength(void) const { return ContainsAnyOptions() ? mData.GetLength() - sizeof(Header) : 0; }
// The following methods are intended to support range-based `for`
// loop iteration over `Option`s in the RA message.
Option::Iterator begin(void) const { return Option::Iterator(GetOptionStart(), GetDataEnd()); }
Option::Iterator end(void) const { return Option::Iterator(); }
private:
const uint8_t *GetDataEnd(void) const { return mData.GetBytes() + mData.GetLength(); }
Data<kWithUint16Length> mData;
};
/**
* Represents an RA message to be sent.
*/
class TxMessage : public ot::Ip6::Nd::TxMessage
{
public:
/**
* Appends a Prefix Info Option to the RA message.
*
* @param[in] aPrefix The prefix.
* @param[in] aValidLifetime The valid lifetime in seconds.
* @param[in] aPreferredLifetime The preferred lifetime in seconds.
* @param[in] aFlags The PIO flags to use.
*
* @retval kErrorNone Option is appended successfully.
* @retval kErrorNoBufs Insufficient available buffers to grow the message.
*/
Error AppendPrefixInfoOption(const Prefix &aPrefix,
uint32_t aValidLifetime,
uint32_t aPreferredLifetime,
PrefixInfoOption::Flags aFlags);
/**
* Appends a Route Info Option to the RA message.
*
* @param[in] aPrefix The prefix.
* @param[in] aRouteLifetime The route lifetime in seconds.
* @param[in] aPreference The route preference.
*
* @retval kErrorNone Option is appended successfully.
* @retval kErrorNoBufs Insufficient available buffers to grow the message.
*/
Error AppendRouteInfoOption(const Prefix &aPrefix, uint32_t aRouteLifetime, RoutePreference aPreference);
/**
* Appends a NAT64 Prefix Option to the RA message.
*
* @note This is intended for testing only. An OTBR should not advertise a NAT64 prefix option; it should only
* process received ones.
*
* @param[in] aPrefix The prefix.
* @param[in] aLifetime The lifetime in seconds.
*
* @retval kErrorNone Option is appended successfully.
* @retval kErrorInvalidArgs Unsupported length for NAT64 prefix.
* @retval kErrorNoBufs Insufficient available buffers to grow the message.
*/
Error AppendNat64PrefixOption(const Prefix &aPrefix, uint32_t aLifetime);
/**
* Append a Recursive DNS Server Option to the RA message.
*
* @note This is intended for testing only. An OTBR should not advertise an RDNSS option; it should only
* process received ones.
*
* @param[in] aAddresses A pointer to an array of IPv6 addresses.
* @param[in] aNumAddresses Number of addresses in @p aAddresses array.
* @param[in] aLifetime The lifetime in seconds.
*
* @retval kErrorNone Option is appended successfully.
* @retval kErrorNoBufs Insufficient available buffers to grow the message.
*/
Error AppendRecursiveDnsServerOption(const Address *aAddresses, uint8_t aNumAddresses, uint32_t aLifetime);
/**
* Indicates whether or not the received RA message contains any options.
*
* @retval TRUE If the RA message contains at least one option.
* @retval FALSE If the RA message contains no options.
*/
bool ContainsAnyOptions(void) const { return (mArray.GetLength() > sizeof(Header)); }
};
RouterAdvert(void) = delete;
};
/**
* Implements the Router Solicitation message.
*
* See section 4.1 of RFC 4861 for definition of this message.
* https://tools.ietf.org/html/rfc4861#section-4.1
*/
OT_TOOL_PACKED_BEGIN
class RouterSolicitHeader
{
public:
/**
* Initializes the Router Solicitation message.
*/
RouterSolicitHeader(void);
private:
Icmp::Header mHeader; // The common ICMPv6 header.
} OT_TOOL_PACKED_END;
static_assert(sizeof(RouterSolicitHeader) == 8, "invalid RouterSolicitHeader structure");
/**
* Represents a Neighbor Solicitation (NS) message.
*/
OT_TOOL_PACKED_BEGIN
class NeighborSolicitHeader : public Clearable<NeighborSolicitHeader>
{
public:
/**
* Initializes the Neighbor Solicitation message header.
*/
NeighborSolicitHeader(void);
/**
* Indicates whether the Neighbor Solicitation message is valid (proper Type and Code).
*
* @retval TRUE If the message header is valid.
* @retval FALSE If the message header is not valid.
*/
bool IsValid(void) const { return (mType == Icmp::Header::kTypeNeighborSolicit) && (mCode == 0); }
/**
* Gets the Target Address field.
*
* @returns The Target Address.
*/
const Address &GetTargetAddress(void) const { return mTargetAddress; }
/**
* Sets the Target Address field.
*
* @param[in] aTargetAddress The Target Address.
*/
void SetTargetAddress(const Address &aTargetAddress) { mTargetAddress = aTargetAddress; }
private:
// Neighbor Solicitation Message (RFC 4861)
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type | Code | Checksum |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Reserved |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// + +
// | |
// + Target Address +
// | |
// + +
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Options ...
// +-+-+-+-+-+-+-+-+-+-+-+-
uint8_t mType;
uint8_t mCode;
uint16_t mChecksum;
uint32_t mReserved;
Address mTargetAddress;
} OT_TOOL_PACKED_END;
static_assert(sizeof(NeighborSolicitHeader) == 24, "Invalid NeighborSolicitHeader definition");
/**
* Represents a Neighbor Advertisement (NA) message.
*/
OT_TOOL_PACKED_BEGIN
class NeighborAdvertMessage : public Clearable<NeighborAdvertMessage>
{
public:
NeighborAdvertMessage(void);
/**
* Indicates whether the Neighbor Advertisement message is valid (proper Type and Code).
*
* @retval TRUE If the message is valid.
* @retval FALSE If the message is not valid.
*/
bool IsValid(void) const { return (mType == Icmp::Header::kTypeNeighborAdvert) && (mCode == 0); }
/**
* Indicates whether or not the Router Flag is set in the NA message.
*
* @retval TRUE The Router Flag is set.
* @retval FALSE The Router Flag is not set.
*/
bool IsRouterFlagSet(void) const { return (mFlags & kRouterFlag) != 0; }
/**
* Sets the Router Flag in the NA message.
*/
void SetRouterFlag(void) { mFlags |= kRouterFlag; }
/**
* Indicates whether or not the Solicited Flag is set in the NA message.
*
* @retval TRUE The Solicited Flag is set.
* @retval FALSE The Solicited Flag is not set.
*/
bool IsSolicitedFlagSet(void) const { return (mFlags & kSolicitedFlag) != 0; }
/**
* Sets the Solicited Flag in the NA message.
*/
void SetSolicitedFlag(void) { mFlags |= kSolicitedFlag; }
/**
* Indicates whether or not the Override Flag is set in the NA message.
*
* @retval TRUE The Override Flag is set.
* @retval FALSE The Override Flag is not set.
*/
bool IsOverrideFlagSet(void) const { return (mFlags & kOverrideFlag) != 0; }
/**
* Sets the Override Flag in the NA message.
*/
void SetOverrideFlag(void) { mFlags |= kOverrideFlag; }
/**
* Gets the Target Address field.
*
* @returns The Target Address.
*/
const Address &GetTargetAddress(void) const { return mTargetAddress; }
/**
* Sets the Target Address field.
*
* @param[in] aTargetAddress The Target Address.
*/
void SetTargetAddress(const Address &aTargetAddress) { mTargetAddress = aTargetAddress; }
private:
// Neighbor Advertisement Message (RFC 4861)
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type | Code | Checksum |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |R|S|O| Reserved |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// + +
// | |
// + Target Address +
// | |
// + +
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Options ...
// +-+-+-+-+-+-+-+-+-+-+-+-
static constexpr uint8_t kRouterFlag = (1 << 7);
static constexpr uint8_t kSolicitedFlag = (1 << 6);
static constexpr uint8_t kOverrideFlag = (1 << 5);
uint8_t mType;
uint8_t mCode;
uint16_t mChecksum;
uint8_t mFlags;
uint8_t mReserved[3];
Address mTargetAddress;
} OT_TOOL_PACKED_END;
static_assert(sizeof(NeighborAdvertMessage) == 24, "Invalid NeighborAdvertMessage definition");
} // namespace Nd
} // namespace Ip6
} // namespace ot
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
#endif // OT_CORE_NET_ND6_HPP_