diff --git a/src/ncp/ncp_host.cpp b/src/ncp/ncp_host.cpp index ddefe8581bb..996df859b7a 100644 --- a/src/ncp/ncp_host.cpp +++ b/src/ncp/ncp_host.cpp @@ -76,14 +76,16 @@ void NcpNetworkProperties::GetDatasetActiveTlvs(otOperationalDatasetTlvs &aDatas // ===================================== NcpHost ====================================== -NcpHost::NcpHost(const char *aInterfaceName, bool aDryRun) +NcpHost::NcpHost(const char *aInterfaceName, const char *aBackboneInterfaceName, bool aDryRun) : mSpinelDriver(*static_cast(otSysGetSpinelDriver())) , mNetif(mNcpSpinel) + , mInfraIf(mNcpSpinel) { memset(&mConfig, 0, sizeof(mConfig)); - mConfig.mInterfaceName = aInterfaceName; - mConfig.mDryRun = aDryRun; - mConfig.mSpeedUpFactor = 1; + mConfig.mInterfaceName = aInterfaceName; + mConfig.mBackboneInterfaceName = aBackboneInterfaceName; + mConfig.mDryRun = aDryRun; + mConfig.mSpeedUpFactor = 1; } const char *NcpHost::GetCoprocessorVersion(void) @@ -96,6 +98,7 @@ void NcpHost::Init(void) otSysInit(&mConfig); mNcpSpinel.Init(mSpinelDriver, *this); mNetif.Init(mConfig.mInterfaceName); + mInfraIf.Init(); mNcpSpinel.Ip6SetAddressCallback( [this](const std::vector &aAddrInfos) { mNetif.UpdateIp6UnicastAddresses(aAddrInfos); }); @@ -104,6 +107,15 @@ void NcpHost::Init(void) mNcpSpinel.NetifSetStateChangedCallback([this](bool aState) { mNetif.SetNetifState(aState); }); mNcpSpinel.Ip6SetReceiveCallback( [this](const uint8_t *aData, uint16_t aLength) { mNetif.Ip6Receive(aData, aLength); }); + mNcpSpinel.InfraIfSetIcmp6NdSendCallback( + [this](uint32_t aInfraIfIndex, const otIp6Address &aAddr, const uint8_t *aData, uint16_t aDataLen) { + OTBR_UNUSED_VARIABLE(mInfraIf.SendIcmp6Nd(aInfraIfIndex, aAddr, aData, aDataLen)); + }); + + if (mConfig.mBackboneInterfaceName != nullptr && strlen(mConfig.mBackboneInterfaceName) > 0) + { + mInfraIf.SetInfraIf(mConfig.mBackboneInterfaceName); + } } void NcpHost::Deinit(void) diff --git a/src/ncp/ncp_host.hpp b/src/ncp/ncp_host.hpp index 16f21669276..212dc63230d 100644 --- a/src/ncp/ncp_host.hpp +++ b/src/ncp/ncp_host.hpp @@ -75,10 +75,11 @@ class NcpHost : public MainloopProcessor, public ThreadHost, public NcpNetworkPr /** * Constructor. * - * @param[in] aInterfaceName A string of the NCP interface name. - * @param[in] aDryRun TRUE to indicate dry-run mode. FALSE otherwise. + * @param[in] aInterfaceName A string of the NCP interface name. + * @param[in] aBackboneInterfaceName A string of the backbone interface name. + * @param[in] aDryRun TRUE to indicate dry-run mode. FALSE otherwise. */ - NcpHost(const char *aInterfaceName, bool aDryRun); + NcpHost(const char *aInterfaceName, const char *aBackboneInterfaceName, bool aDryRun); /** * Destructor. @@ -109,6 +110,7 @@ class NcpHost : public MainloopProcessor, public ThreadHost, public NcpNetworkPr NcpSpinel mNcpSpinel; TaskRunner mTaskRunner; Netif mNetif; + InfraIf mInfraIf; }; } // namespace Ncp diff --git a/src/ncp/ncp_spinel.cpp b/src/ncp/ncp_spinel.cpp index 586cdd81fc1..1b9b08a95d4 100644 --- a/src/ncp/ncp_spinel.cpp +++ b/src/ncp/ncp_spinel.cpp @@ -413,6 +413,18 @@ void NcpSpinel::HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, ui break; } + case SPINEL_PROP_INFRA_IF_SEND_ICMP6: + { + uint32_t infraIfIndex; + const otIp6Address *destAddress; + const uint8_t *data; + uint16_t dataLen; + + SuccessOrExit(ParseInfraIfIcmp6Nd(aBuffer, aLength, infraIfIndex, destAddress, data, dataLen)); + SafeInvoke(mInfraIfIcmp6NdCallback, infraIfIndex, *destAddress, data, dataLen); + break; + } + default: otbrLogWarning("Received uncognized key: %u", aKey); break; @@ -431,7 +443,8 @@ otbrError NcpSpinel::HandleResponseForPropSet(spinel_tid_t aTid, OTBR_UNUSED_VARIABLE(aData); OTBR_UNUSED_VARIABLE(aLength); - otbrError error = OTBR_ERROR_NONE; + otbrError error = OTBR_ERROR_NONE; + spinel_status_t status = SPINEL_STATUS_OK; switch (mWaitingKeyTable[aTid]) { @@ -464,8 +477,6 @@ otbrError NcpSpinel::HandleResponseForPropSet(spinel_tid_t aTid, case SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS: if (aKey == SPINEL_PROP_LAST_STATUS) { // Failed case - spinel_status_t status = SPINEL_STATUS_OK; - SuccessOrExit(error = SpinelDataUnpack(aData, aLength, SPINEL_DATATYPE_UINT_PACKED_S, &status)); CallAndClear(mDatasetMgmtSetPendingTask, ot::Spinel::SpinelStatusToOtError(status)); } @@ -478,6 +489,18 @@ otbrError NcpSpinel::HandleResponseForPropSet(spinel_tid_t aTid, case SPINEL_PROP_STREAM_NET: break; + case SPINEL_PROP_INFRA_IF_STATE: + VerifyOrExit(aKey == SPINEL_PROP_LAST_STATUS, error = OTBR_ERROR_INVALID_STATE); + SuccessOrExit(error = SpinelDataUnpack(aData, aLength, SPINEL_DATATYPE_UINT_PACKED_S, &status)); + otbrLogInfo("Infra If state update result: %s", spinel_status_to_cstr(status)); + break; + + case SPINEL_PROP_INFRA_IF_RECV_ICMP6: + VerifyOrExit(aKey == SPINEL_PROP_LAST_STATUS, error = OTBR_ERROR_INVALID_STATE); + SuccessOrExit(error = SpinelDataUnpack(aData, aLength, SPINEL_DATATYPE_UINT_PACKED_S, &status)); + otbrLogInfo("Infra If handle ICMP6 ND result: %s", spinel_status_to_cstr(status)); + break; + default: VerifyOrExit(aKey == mWaitingKeyTable[aTid], error = OTBR_ERROR_INVALID_STATE); break; @@ -751,6 +774,72 @@ otError NcpSpinel::ParseOperationalDatasetTlvs(const uint8_t *aBuf, return error; } +otError NcpSpinel::ParseInfraIfIcmp6Nd(const uint8_t *aBuf, + uint8_t aLen, + uint32_t &aInfraIfIndex, + const otIp6Address *&aAddr, + const uint8_t *&aData, + uint16_t &aDataLen) +{ + otError error = OT_ERROR_NONE; + ot::Spinel::Decoder decoder; + + VerifyOrExit(aBuf != nullptr, error = OT_ERROR_INVALID_ARGS); + + decoder.Init(aBuf, aLen); + SuccessOrExit(error = decoder.ReadUint32(aInfraIfIndex)); + SuccessOrExit(error = decoder.ReadIp6Address(aAddr)); + SuccessOrExit(error = decoder.ReadDataWithLen(aData, aDataLen)); + +exit: + return error; +} + +otbrError NcpSpinel::SetInfraIf(uint32_t aInfraIfIndex, bool aIsRunning, const std::vector &aIp6Addresses) +{ + otbrError error = OTBR_ERROR_NONE; + EncodingFunc encodingFunc = [this, aInfraIfIndex, aIsRunning, &aIp6Addresses] { + otError error = OT_ERROR_NONE; + SuccessOrExit(error = mEncoder.WriteUint32(aInfraIfIndex)); + SuccessOrExit(error = mEncoder.WriteBool(aIsRunning)); + for (const Ip6Address &addr : aIp6Addresses) + { + SuccessOrExit(error = mEncoder.WriteIp6Address(reinterpret_cast(addr))); + } + exit: + return error; + }; + + SuccessOrExit(SetProperty(SPINEL_PROP_INFRA_IF_STATE, encodingFunc), error = OTBR_ERROR_OPENTHREAD); +exit: + return error; +} + +otbrError NcpSpinel::HandleIcmp6Nd(uint32_t aInfraIfIndex, + const Ip6Address &aIp6Address, + const uint8_t *aData, + uint16_t aDataLen) +{ + otbrError error = OTBR_ERROR_NONE; + EncodingFunc encodingFunc = [this, aInfraIfIndex, &aIp6Address, aData, aDataLen] { + otError error = OT_ERROR_NONE; + SuccessOrExit(error = mEncoder.WriteUint32(aInfraIfIndex)); + SuccessOrExit(error = mEncoder.WriteIp6Address(reinterpret_cast(aIp6Address))); + SuccessOrExit(error = mEncoder.WriteData(aData, aDataLen)); + exit: + return error; + }; + + SuccessOrExit(SetProperty(SPINEL_PROP_INFRA_IF_RECV_ICMP6, encodingFunc), error = OTBR_ERROR_OPENTHREAD); + +exit: + if (error != OTBR_ERROR_NONE) + { + otbrLogWarning("Failed to passthrough ICMP6 ND to NCP, %s", otbrErrorString(error)); + } + return error; +} + otDeviceRole NcpSpinel::SpinelRoleToDeviceRole(spinel_net_role_t aRole) { otDeviceRole role = OT_DEVICE_ROLE_DISABLED; diff --git a/src/ncp/ncp_spinel.hpp b/src/ncp/ncp_spinel.hpp index 8fd9481fee0..1a22d8c654a 100644 --- a/src/ncp/ncp_spinel.hpp +++ b/src/ncp/ncp_spinel.hpp @@ -50,6 +50,7 @@ #include "common/task_runner.hpp" #include "common/types.hpp" #include "ncp/async_task.hpp" +#include "ncp/posix/infra_if.hpp" #include "ncp/posix/netif.hpp" namespace otbr { @@ -84,13 +85,14 @@ class PropsObserver /** * The class provides methods for controlling the Thread stack on the network co-processor (NCP). */ -class NcpSpinel : public Netif::Dependencies +class NcpSpinel : public Netif::Dependencies, public InfraIf::Dependencies { public: using Ip6AddressTableCallback = std::function &)>; using Ip6MulticastAddressTableCallback = std::function &)>; using NetifStateChangedCallback = std::function; using Ip6ReceiveCallback = std::function; + using InfraIfSendIcmp6NdCallback = std::function; /** * Constructor. @@ -233,6 +235,17 @@ class NcpSpinel : public Netif::Dependencies mNetifStateChangedCallback = aCallback; } + /** + * This method sets the function to send an Icmp6 ND message on the infrastructure link. + * + * @param[in] aCallback The callback to send an Icmp6 ND message on the infrastructure link. + * + */ + void InfraIfSetIcmp6NdSendCallback(const InfraIfSendIcmp6NdCallback &aCallback) + { + mInfraIfIcmp6NdCallback = aCallback; + } + private: using FailureHandler = std::function; @@ -302,6 +315,20 @@ class NcpSpinel : public Netif::Dependencies otError ParseIp6MulticastAddresses(const uint8_t *aBuf, uint8_t aLen, std::vector &aAddressList); otError ParseIp6StreamNet(const uint8_t *aBuf, uint8_t aLen, const uint8_t *&aData, uint16_t &aDataLen); otError ParseOperationalDatasetTlvs(const uint8_t *aBuf, uint8_t aLen, otOperationalDatasetTlvs &aDatasetTlvs); + otError ParseInfraIfIcmp6Nd(const uint8_t *aBuf, + uint8_t aLen, + uint32_t &aInfraIfIndex, + const otIp6Address *&aAddr, + const uint8_t *&aData, + uint16_t &aDataLen); + + otbrError SetInfraIf(uint32_t aInfraIfIndex, + bool aIsRunning, + const std::vector &aIp6Addresses) override; + otbrError HandleIcmp6Nd(uint32_t aInfraIfIndex, + const Ip6Address &aIp6Address, + const uint8_t *aData, + uint16_t aDataLen) override; ot::Spinel::SpinelDriver *mSpinelDriver; uint16_t mCmdTidsInUse; ///< Used transaction ids. @@ -332,6 +359,7 @@ class NcpSpinel : public Netif::Dependencies Ip6MulticastAddressTableCallback mIp6MulticastAddressTableCallback; Ip6ReceiveCallback mIp6ReceiveCallback; NetifStateChangedCallback mNetifStateChangedCallback; + InfraIfSendIcmp6NdCallback mInfraIfIcmp6NdCallback; }; } // namespace Ncp diff --git a/src/ncp/thread_host.cpp b/src/ncp/thread_host.cpp index b5f1bf25dc0..3191ab1728a 100644 --- a/src/ncp/thread_host.cpp +++ b/src/ncp/thread_host.cpp @@ -71,7 +71,7 @@ std::unique_ptr ThreadHost::Create(const char * break; case OT_COPROCESSOR_NCP: - host = MakeUnique(aInterfaceName, aDryRun); + host = MakeUnique(aInterfaceName, aBackboneInterfaceName, aDryRun); break; default: