[routing-manager] append source link-layer option in ND6 message (#10647)

This commit introduces a platform API to get the InfraIf link-layer
address. And add the source link-layer address option to all ND6
messages generated from OpenThread.
This commit is contained in:
Zhangwx
2024-10-11 10:12:38 -07:00
committed by GitHub
parent c4262af670
commit 87474bdc88
9 changed files with 220 additions and 84 deletions
+1 -1
View File
@@ -52,7 +52,7 @@ extern "C" {
*
* @note This number versions both OpenThread platform and user APIs.
*/
#define OPENTHREAD_API_VERSION (453)
#define OPENTHREAD_API_VERSION (454)
/**
* @addtogroup api-instance
+28
View File
@@ -45,6 +45,17 @@
extern "C" {
#endif
#define OT_PLAT_INFRA_IF_MAX_LINK_LAYER_ADDR_LENGTH 16 ///< Maximum InfraIf Link-layer address length.
/**
* Represents an InfraIf Link-Layer Address.
*/
typedef struct otPlatInfraIfLinkLayerAddress
{
uint8_t mAddress[OT_PLAT_INFRA_IF_MAX_LINK_LAYER_ADDR_LENGTH]; ///< The link-layer address bytes.
uint8_t mLength; ///< The address length (number of bytes).
} otPlatInfraIfLinkLayerAddress;
/**
* @addtogroup plat-infra-if
*
@@ -154,6 +165,23 @@ extern void otPlatInfraIfDiscoverNat64PrefixDone(otInstance *aInstance,
uint32_t aInfraIfIndex,
const otIp6Prefix *aIp6Prefix);
/**
* Get the link-layer address of the infrastructure interface.
*
* OpenThread invokes this method when the address is required, for example: when generating an ND6 message
* which includes a source link-layer address option.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aInfraIfIndex The index of the infrastructure interface.
* @param[out] aInfraIfLinkLayerAddress A pointer to infrastructure interface link-layer address.
*
* @retval OT_ERROR_NONE Successfully get the infrastructure interface link-layer address.
* @retval OT_ERROR_FAILED Failed to get the infrastructure interface link-layer address.
*/
otError otPlatGetInfraIfLinkLayerAddress(otInstance *aInstance,
uint32_t aIfIndex,
otPlatInfraIfLinkLayerAddress *aInfraIfLinkLayerAddress);
/**
* @}
*/
+12
View File
@@ -137,6 +137,11 @@ exit:
}
}
Error InfraIf::GetLinkLayerAddress(LinkLayerAddress &aLinkLayerAddress)
{
return otPlatGetInfraIfLinkLayerAddress(&GetInstance(), mIfIndex, &aLinkLayerAddress);
}
Error InfraIf::HandleStateChanged(uint32_t aIfIndex, bool aIsRunning)
{
Error error = kErrorNone;
@@ -217,4 +222,11 @@ OT_TOOL_WEAK otError otPlatInfraIfSendIcmp6Nd(uint32_t, const otIp6Address *, co
OT_TOOL_WEAK otError otPlatInfraIfDiscoverNat64Prefix(uint32_t) { return OT_ERROR_FAILED; }
#endif
extern "C" OT_TOOL_WEAK otError otPlatGetInfraIfLinkLayerAddress(otInstance *,
uint32_t,
otPlatInfraIfLinkLayerAddress *)
{
return OT_ERROR_FAILED;
}
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
+13 -2
View File
@@ -57,8 +57,9 @@ class InfraIf : public InstanceLocator
public:
static constexpr uint16_t kInfoStringSize = 20; ///< Max chars for the info string (`ToString()`).
typedef String<kInfoStringSize> InfoString; ///< String type returned from `ToString()`.
typedef Data<kWithUint16Length> Icmp6Packet; ///< An IMCPv6 packet (data containing the IP payload)
typedef String<kInfoStringSize> InfoString; ///< String type returned from `ToString()`.
typedef Data<kWithUint16Length> Icmp6Packet; ///< An IMCPv6 packet (data containing the IP payload)
typedef otPlatInfraIfLinkLayerAddress LinkLayerAddress; ///< A link-layer address
/**
* Initializes the `InfraIf`.
@@ -113,6 +114,16 @@ public:
*/
void SetIfIndex(uint32_t aIfIndex) { mIfIndex = aIfIndex; }
/**
* Gets the infrastructure interface link-layer address.
*
* @param[out] aLinkLayerAddress A reference to return the interface link-layer address.
*
* @retval kErrorNone Successfully get the infrastructure interface link-layer address.
* @retval kErrorFailed Failed to get the infrastructure interface link-layer address.
*/
Error GetLinkLayerAddress(LinkLayerAddress &aLinkLayerAddress);
/**
* Indicates whether or not the infra interface has the given IPv6 address assigned.
*
+37 -10
View File
@@ -574,6 +574,7 @@ void RoutingManager::SendRouterAdvertisement(RouterAdvTxMode aRaTxMode)
RouterAdvert::Header header;
Ip6::Address destAddress;
InfraIf::Icmp6Packet packet;
LinkLayerAddress linkAddr;
LogInfo("Preparing RA");
@@ -589,7 +590,7 @@ void RoutingManager::SendRouterAdvertisement(RouterAdvTxMode aRaTxMode)
mRxRaTracker.SetHeaderFlagsOn(header);
header.SetSnacRouterFlag();
SuccessOrExit(error = raMsg.AppendHeader(header));
SuccessOrExit(error = raMsg.Append(header));
LogRaHeader(header);
@@ -608,11 +609,18 @@ void RoutingManager::SendRouterAdvertisement(RouterAdvTxMode aRaTxMode)
SuccessOrExit(error = mRioAdvertiser.AppendRios(raMsg));
}
if (Get<InfraIf>().GetLinkLayerAddress(linkAddr) == kErrorNone)
{
SuccessOrExit(error = raMsg.AppendLinkLayerOption(linkAddr, Option::kSourceLinkLayerAddr));
}
if (mExtraRaOptions.GetLength() > 0)
{
SuccessOrExit(error = raMsg.AppendBytes(mExtraRaOptions.GetBytes(), mExtraRaOptions.GetLength()));
}
// A valid RA message should contain at lease one option.
// Exit when the size of packet is less than the size of header.
VerifyOrExit(raMsg.ContainsAnyOptions());
destAddress.SetToLinkLocalAllNodesMulticast();
@@ -1796,13 +1804,22 @@ void RoutingManager::RxRaTracker::HandleRouterTimer(void)
void RoutingManager::RxRaTracker::SendNeighborSolicitToRouter(const Router &aRouter)
{
InfraIf::Icmp6Packet packet;
NeighborSolicitMessage neighborSolicitMsg;
InfraIf::Icmp6Packet packet;
NeighborSolicitHeader nsHdr;
TxMessage nsMsg;
LinkLayerAddress linkAddr;
VerifyOrExit(!Get<RoutingManager>().mRsSender.IsInProgress());
neighborSolicitMsg.SetTargetAddress(aRouter.mAddress);
packet.InitFrom(neighborSolicitMsg);
nsHdr.SetTargetAddress(aRouter.mAddress);
SuccessOrExit(nsMsg.Append(nsHdr));
if (Get<InfraIf>().GetLinkLayerAddress(linkAddr) == kErrorNone)
{
SuccessOrExit(nsMsg.AppendLinkLayerOption(linkAddr, Option::kSourceLinkLayerAddr));
}
nsMsg.GetAsPacket(packet);
IgnoreError(Get<RoutingManager>().mInfraIf.Send(packet, aRouter.mAddress));
@@ -3786,11 +3803,20 @@ void RoutingManager::RsSender::Stop(void) { mTimer.Stop(); }
Error RoutingManager::RsSender::SendRs(void)
{
Ip6::Address destAddress;
RouterSolicitMessage routerSolicit;
RouterSolicitHeader rsHdr;
TxMessage rsMsg;
LinkLayerAddress linkAddr;
InfraIf::Icmp6Packet packet;
Error error;
packet.InitFrom(routerSolicit);
SuccessOrExit(error = rsMsg.Append(rsHdr));
if (Get<InfraIf>().GetLinkLayerAddress(linkAddr) == kErrorNone)
{
SuccessOrExit(error = rsMsg.AppendLinkLayerOption(linkAddr, Option::kSourceLinkLayerAddr));
}
rsMsg.GetAsPacket(packet);
destAddress.SetToLinkLocalAllRoutersMulticast();
error = Get<RoutingManager>().mInfraIf.Send(packet, destAddress);
@@ -3803,6 +3829,7 @@ Error RoutingManager::RsSender::SendRs(void)
{
Get<Ip6::Ip6>().GetBorderRoutingCounters().mRsTxFailure++;
}
exit:
return error;
}
@@ -3996,7 +4023,7 @@ void RoutingManager::PdPrefixManager::ProcessRa(const uint8_t *aRouterAdvert, co
// part of the DHCPv6 prefix delegation process for distributing
// prefixes to interfaces.
RouterAdvert::Icmp6Packet packet;
InfraIf::Icmp6Packet packet;
packet.Init(aRouterAdvert, aLength);
Process(&packet, nullptr);
@@ -4012,8 +4039,8 @@ void RoutingManager::PdPrefixManager::ProcessPrefix(const PrefixTableEntry &aPre
Process(nullptr, &aPrefixTableEntry);
}
void RoutingManager::PdPrefixManager::Process(const RouterAdvert::Icmp6Packet *aRaPacket,
const PrefixTableEntry *aPrefixTableEntry)
void RoutingManager::PdPrefixManager::Process(const InfraIf::Icmp6Packet *aRaPacket,
const PrefixTableEntry *aPrefixTableEntry)
{
// Processes DHCPv6 Prefix Delegation (PD) prefixes, either from
// an RA message or directly set. Requires either `aRaPacket` or
+11 -8
View File
@@ -642,13 +642,16 @@ private:
//------------------------------------------------------------------------------------------------------------------
// Typedefs
using Option = Ip6::Nd::Option;
using PrefixInfoOption = Ip6::Nd::PrefixInfoOption;
using RouteInfoOption = Ip6::Nd::RouteInfoOption;
using RouterAdvert = Ip6::Nd::RouterAdvert;
using NeighborAdvertMessage = Ip6::Nd::NeighborAdvertMessage;
using NeighborSolicitMessage = Ip6::Nd::NeighborSolicitMessage;
using RouterSolicitMessage = Ip6::Nd::RouterSolicitMessage;
using Option = Ip6::Nd::Option;
using PrefixInfoOption = Ip6::Nd::PrefixInfoOption;
using RouteInfoOption = Ip6::Nd::RouteInfoOption;
using RaFlagsExtOption = Ip6::Nd::RaFlagsExtOption;
using RouterAdvert = Ip6::Nd::RouterAdvert;
using NeighborAdvertMessage = Ip6::Nd::NeighborAdvertMessage;
using TxMessage = Ip6::Nd::TxMessage;
using NeighborSolicitHeader = Ip6::Nd::NeighborSolicitHeader;
using RouterSolicitHeader = Ip6::Nd::RouterSolicitHeader;
using LinkLayerAddress = InfraIf::LinkLayerAddress;
//------------------------------------------------------------------------------------------------------------------
// Enumerations
@@ -1488,7 +1491,7 @@ private:
bool IsFavoredOver(const PrefixEntry &aOther) const;
};
void Process(const RouterAdvert::Icmp6Packet *aRaPacket, const PrefixTableEntry *aPrefixTableEntry);
void Process(const InfraIf::Icmp6Packet *aRaPacket, const PrefixTableEntry *aPrefixTableEntry);
bool ProcessPrefixEntry(PrefixEntry &aEntry, PrefixEntry &aFavoredEntry);
void EvaluateStateChange(State aOldState);
void WithdrawPrefix(void);
+34 -9
View File
@@ -208,9 +208,9 @@ void RouterAdvert::Header::SetDefaultRouterPreference(RoutePreference aPreferenc
}
//----------------------------------------------------------------------------------------------------------------------
// RouterAdver::TxMessage
// TxMessage
Option *RouterAdvert::TxMessage::AppendOption(uint16_t aOptionSize)
Option *TxMessage::AppendOption(uint16_t aOptionSize)
{
// This method appends an option with a given size to the RA
// message by reserving space in the data buffer if there is
@@ -228,7 +228,7 @@ exit:
return option;
}
Error RouterAdvert::TxMessage::AppendBytes(const uint8_t *aBytes, uint16_t aLength)
Error TxMessage::AppendBytes(const uint8_t *aBytes, uint16_t aLength)
{
Error error = kErrorNone;
@@ -244,11 +244,36 @@ exit:
return error;
}
Error RouterAdvert::TxMessage::AppendHeader(const Header &aHeader)
Error TxMessage::AppendLinkLayerOption(LinkLayerAddress &aLinkLayerAddress, Option::Type aType)
{
return AppendBytes(reinterpret_cast<const uint8_t *>(&aHeader), sizeof(Header));
Error error;
Option option;
uint16_t size;
size = sizeof(Option) + aLinkLayerAddress.mLength;
option.SetType(aType);
option.SetSize(size);
SuccessOrExit(error = Append(option));
SuccessOrExit(error = AppendBytes(aLinkLayerAddress.mAddress, aLinkLayerAddress.mLength));
// `SetSize()` rounds up to ensure the option's size is a multiple
// of `kLengthUnit = 8` bytes and ends on a 64-bit boundary. Append
// any necessary zero padding bytes.
for (; size < option.GetSize(); size++)
{
SuccessOrExit(error = Append<uint8_t>(0));
}
exit:
return error;
}
//----------------------------------------------------------------------------------------------------------------------
// RouterAdver::TxMessage
Error RouterAdvert::TxMessage::AppendPrefixInfoOption(const Prefix &aPrefix,
uint32_t aValidLifetime,
uint32_t aPreferredLifetime)
@@ -290,18 +315,18 @@ exit:
}
//----------------------------------------------------------------------------------------------------------------------
// RouterSolicitMessage
// RouterSolicitHeader
RouterSolicitMessage::RouterSolicitMessage(void)
RouterSolicitHeader::RouterSolicitHeader(void)
{
mHeader.Clear();
mHeader.SetType(Icmp::Header::kTypeRouterSolicit);
}
//----------------------------------------------------------------------------------------------------------------------
// NeighborSolicitMessage
// NeighborSolicitHeader
NeighborSolicitMessage::NeighborSolicitMessage(void)
NeighborSolicitHeader::NeighborSolicitHeader(void)
{
OT_UNUSED_VARIABLE(mChecksum);
OT_UNUSED_VARIABLE(mReserved);
+79 -49
View File
@@ -43,21 +43,26 @@
#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 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.
@@ -73,6 +78,8 @@ class Option
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.
kTypeRaFlagsExtension = 26, ///< RA Flags Extension Option.
@@ -481,6 +488,66 @@ private:
static_assert(sizeof(RaFlagsExtOption) == 8, "invalid RaFlagsExtOption 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.
*/
@@ -635,8 +702,6 @@ public:
static_assert(sizeof(Header) == 16, "Invalid RA `Header`");
typedef Data<kWithUint16Length> Icmp6Packet; ///< A data buffer containing an ICMPv6 packet.
/**
* Represents a received RA message.
*/
@@ -716,26 +781,9 @@ public:
/**
* Represents an RA message to be sent.
*/
class TxMessage
class TxMessage : public ot::Ip6::Nd::TxMessage
{
public:
/**
* Gets the prepared RA message as an `Icmp6Packet`.
*
* @param[out] aPacket A reference to an `Icmp6Packet`.
*/
void GetAsPacket(Icmp6Packet &aPacket) const { aPacket.Init(mArray.AsCArray(), mArray.GetLength()); }
/**
* Appends the RA header.
*
* @param[in] aHeader The RA header.
*
* @retval kErrorNone Header is written successfully.
* @retval kErrorNoBufs Insufficient available buffers to grow the message.
*/
Error AppendHeader(const Header &aHeader);
/**
* Appends a Prefix Info Option to the RA message.
*
@@ -763,17 +811,6 @@ public:
*/
Error AppendRouteInfoOption(const Prefix &aPrefix, uint32_t aRouteLifetime, RoutePreference aPreference);
/**
* Appends bytes from a given buffer to the RA 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);
/**
* Indicates whether or not the received RA message contains any options.
*
@@ -781,13 +818,6 @@ public:
* @retval FALSE If the RA message contains no options.
*/
bool ContainsAnyOptions(void) const { return (mArray.GetLength() > sizeof(Header)); }
private:
static constexpr uint16_t kCapacityIncrement = 256;
Option *AppendOption(uint16_t aOptionSize);
Heap::Array<uint8_t, kCapacityIncrement> mArray;
};
RouterAdvert(void) = delete;
@@ -800,37 +830,37 @@ public:
* https://tools.ietf.org/html/rfc4861#section-4.1
*/
OT_TOOL_PACKED_BEGIN
class RouterSolicitMessage
class RouterSolicitHeader
{
public:
/**
* Initializes the Router Solicitation message.
*/
RouterSolicitMessage(void);
RouterSolicitHeader(void);
private:
Icmp::Header mHeader; // The common ICMPv6 header.
} OT_TOOL_PACKED_END;
static_assert(sizeof(RouterSolicitMessage) == 8, "invalid RouterSolicitMessage structure");
static_assert(sizeof(RouterSolicitHeader) == 8, "invalid RouterSolicitHeader structure");
/**
* Represents a Neighbor Solicitation (NS) message.
*/
OT_TOOL_PACKED_BEGIN
class NeighborSolicitMessage : public Clearable<NeighborSolicitMessage>
class NeighborSolicitHeader : public Clearable<NeighborSolicitHeader>
{
public:
/**
* Initializes the Neighbor Solicitation message.
* Initializes the Neighbor Solicitation message header.
*
*/
NeighborSolicitMessage(void);
NeighborSolicitHeader(void);
/**
* Indicates whether the Neighbor Solicitation message is valid (proper Type and Code).
*
* @retval TRUE If the message is valid.
* @retval FALSE If the message is not valid.
* @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); }
@@ -876,7 +906,7 @@ private:
Address mTargetAddress;
} OT_TOOL_PACKED_END;
static_assert(sizeof(NeighborSolicitMessage) == 24, "Invalid NeighborSolicitMessage definition");
static_assert(sizeof(NeighborSolicitHeader) == 24, "Invalid NeighborSolicitHeader definition");
/**
* Represents a Neighbor Advertisement (NA) message.
+5 -5
View File
@@ -126,7 +126,7 @@ static otRadioFrame sRadioTxFrame;
static uint8_t sRadioTxFramePsdu[OT_RADIO_FRAME_MAX_SIZE];
static bool sRadioTxOngoing = false;
using Icmp6Packet = Ip6::Nd::RouterAdvert::Icmp6Packet;
using Icmp6Packet = Ip6::Nd::Icmp6Packet;
enum ExpectedPio
{
@@ -332,12 +332,12 @@ otError otPlatInfraIfSendIcmp6Nd(uint32_t aInfraIfIndex,
case Ip6::Icmp::Header::kTypeNeighborSolicit:
{
const Ip6::Nd::NeighborSolicitMessage *nsMsg =
reinterpret_cast<const Ip6::Nd::NeighborSolicitMessage *>(packet.GetBytes());
const Ip6::Nd::NeighborSolicitHeader *nsMsg =
reinterpret_cast<const Ip6::Nd::NeighborSolicitHeader *>(packet.GetBytes());
Log(" Neighbor Solicit message");
VerifyOrQuit(packet.GetLength() >= sizeof(Ip6::Nd::NeighborSolicitMessage));
VerifyOrQuit(packet.GetLength() >= sizeof(Ip6::Nd::NeighborSolicitHeader));
VerifyOrQuit(nsMsg->IsValid());
sNsEmitted = true;
@@ -875,7 +875,7 @@ void BuildRouterAdvert(Ip6::Nd::RouterAdvert::TxMessage &aRaMsg,
header.SetSnacRouterFlag();
}
SuccessOrQuit(aRaMsg.AppendHeader(header));
SuccessOrQuit(aRaMsg.Append(header));
for (; aNumPios > 0; aPios++, aNumPios--)
{