From 87474bdc888dff440f14a2709acd3e65cbfdc8af Mon Sep 17 00:00:00 2001 From: Zhangwx Date: Sat, 12 Oct 2024 01:12:38 +0800 Subject: [PATCH] [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. --- include/openthread/instance.h | 2 +- include/openthread/platform/infra_if.h | 28 +++++ src/core/border_router/infra_if.cpp | 12 ++ src/core/border_router/infra_if.hpp | 15 ++- src/core/border_router/routing_manager.cpp | 47 ++++++-- src/core/border_router/routing_manager.hpp | 19 +-- src/core/net/nd6.cpp | 43 +++++-- src/core/net/nd6.hpp | 128 +++++++++++++-------- tests/unit/test_routing_manager.cpp | 10 +- 9 files changed, 220 insertions(+), 84 deletions(-) diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 70629db17..0c63af600 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -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 diff --git a/include/openthread/platform/infra_if.h b/include/openthread/platform/infra_if.h index 171cbb1cc..e4cd34ec7 100644 --- a/include/openthread/platform/infra_if.h +++ b/include/openthread/platform/infra_if.h @@ -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); + /** * @} */ diff --git a/src/core/border_router/infra_if.cpp b/src/core/border_router/infra_if.cpp index acee7f9ea..ce4492793 100644 --- a/src/core/border_router/infra_if.cpp +++ b/src/core/border_router/infra_if.cpp @@ -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 diff --git a/src/core/border_router/infra_if.hpp b/src/core/border_router/infra_if.hpp index 2de461cde..9bae2f9ec 100644 --- a/src/core/border_router/infra_if.hpp +++ b/src/core/border_router/infra_if.hpp @@ -57,8 +57,9 @@ class InfraIf : public InstanceLocator public: static constexpr uint16_t kInfoStringSize = 20; ///< Max chars for the info string (`ToString()`). - typedef String InfoString; ///< String type returned from `ToString()`. - typedef Data Icmp6Packet; ///< An IMCPv6 packet (data containing the IP payload) + typedef String InfoString; ///< String type returned from `ToString()`. + typedef Data 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. * diff --git a/src/core/border_router/routing_manager.cpp b/src/core/border_router/routing_manager.cpp index 3f4d065df..dfa1cdbb8 100644 --- a/src/core/border_router/routing_manager.cpp +++ b/src/core/border_router/routing_manager.cpp @@ -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().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().mRsSender.IsInProgress()); - neighborSolicitMsg.SetTargetAddress(aRouter.mAddress); - packet.InitFrom(neighborSolicitMsg); + nsHdr.SetTargetAddress(aRouter.mAddress); + SuccessOrExit(nsMsg.Append(nsHdr)); + + if (Get().GetLinkLayerAddress(linkAddr) == kErrorNone) + { + SuccessOrExit(nsMsg.AppendLinkLayerOption(linkAddr, Option::kSourceLinkLayerAddr)); + } + + nsMsg.GetAsPacket(packet); IgnoreError(Get().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().GetLinkLayerAddress(linkAddr) == kErrorNone) + { + SuccessOrExit(error = rsMsg.AppendLinkLayerOption(linkAddr, Option::kSourceLinkLayerAddr)); + } + + rsMsg.GetAsPacket(packet); destAddress.SetToLinkLocalAllRoutersMulticast(); error = Get().mInfraIf.Send(packet, destAddress); @@ -3803,6 +3829,7 @@ Error RoutingManager::RsSender::SendRs(void) { Get().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 diff --git a/src/core/border_router/routing_manager.hpp b/src/core/border_router/routing_manager.hpp index f2a175ad4..e92651614 100644 --- a/src/core/border_router/routing_manager.hpp +++ b/src/core/border_router/routing_manager.hpp @@ -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); diff --git a/src/core/net/nd6.cpp b/src/core/net/nd6.cpp index 24f9e2d2f..3e55126fd 100644 --- a/src/core/net/nd6.cpp +++ b/src/core/net/nd6.cpp @@ -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(&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(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); diff --git a/src/core/net/nd6.hpp b/src/core/net/nd6.hpp index 955f23c50..0bb7e7fae 100644 --- a/src/core/net/nd6.hpp +++ b/src/core/net/nd6.hpp @@ -43,21 +43,26 @@ #include #include +#include #include +#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 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 Error Append(const ObjectType &aObject) + { + static_assert(!TypeTraits::IsPointer::kValue, "ObjectType must not be a pointer"); + + return AppendBytes(reinterpret_cast(&aObject), sizeof(ObjectType)); + } + +protected: + static constexpr uint16_t kCapacityIncrement = 256; + + Option *AppendOption(uint16_t aOptionSize); + + Heap::Array mArray; +}; + /** * Defines Router Advertisement components. */ @@ -635,8 +702,6 @@ public: static_assert(sizeof(Header) == 16, "Invalid RA `Header`"); - typedef Data 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 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 +class NeighborSolicitHeader : public Clearable { 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. diff --git a/tests/unit/test_routing_manager.cpp b/tests/unit/test_routing_manager.cpp index 44fa71115..50b3b3dc2 100644 --- a/tests/unit/test_routing_manager.cpp +++ b/tests/unit/test_routing_manager.cpp @@ -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(packet.GetBytes()); + const Ip6::Nd::NeighborSolicitHeader *nsMsg = + reinterpret_cast(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--) {