diff --git a/.github/workflows/ncp_mode.yml b/.github/workflows/ncp_mode.yml index 1584aaab63d..2e614459d81 100644 --- a/.github/workflows/ncp_mode.yml +++ b/.github/workflows/ncp_mode.yml @@ -76,6 +76,6 @@ jobs: --build-arg OTBR_OPTIONS="${OTBR_OPTIONS}" - name: Run run: | - top_builddir="./build/temp" tests/scripts/ncp_mode build_ot_sim expect + top_builddir="./build/temp" tests/scripts/ncp_mode build_ot_sim expect - name: Codecov uses: codecov/codecov-action@v5 diff --git a/src/agent/application.cpp b/src/agent/application.cpp index fb6cee2cb46..4d0d3df71ec 100644 --- a/src/agent/application.cpp +++ b/src/agent/application.cpp @@ -288,6 +288,12 @@ void Application::DeinitRcpMode(void) void Application::InitNcpMode(void) { +#if OTBR_ENABLE_MDNS + otbr::Ncp::NcpHost &ncpHost = static_cast(mHost); + ncpHost.SetMdnsPublisher(mPublisher.get()); + mMdnsStateSubject.AddObserver(ncpHost); + mPublisher->Start(); +#endif #if OTBR_ENABLE_DBUS_SERVER mDBusAgent->Init(*mBorderAgent); #endif @@ -295,7 +301,9 @@ void Application::InitNcpMode(void) void Application::DeinitNcpMode(void) { - /* empty */ +#if OTBR_ENABLE_MDNS + mPublisher->Stop(); +#endif } } // namespace otbr diff --git a/src/ncp/ncp_host.cpp b/src/ncp/ncp_host.cpp index b37a4a51b98..9409727fcf2 100644 --- a/src/ncp/ncp_host.cpp +++ b/src/ncp/ncp_host.cpp @@ -134,6 +134,16 @@ void NcpHost::Init(void) { mInfraIf.SetInfraIf(mConfig.mBackboneInterfaceName); } + +#if OTBR_ENABLE_SRP_ADVERTISING_PROXY +#if OTBR_ENABLE_SRP_SERVER_AUTO_ENABLE_MODE + // Let SRP server use auto-enable mode. The auto-enable mode delegates the control of SRP server to the Border + // Routing Manager. SRP server automatically starts when bi-directional connectivity is ready. + mNcpSpinel.SrpServerSetAutoEnableMode(/* aEnabled */ true); +#else + mNcpSpinel.SrpServerSetEnabled(/* aEnabled */ true); +#endif +#endif } void NcpHost::Deinit(void) @@ -255,5 +265,15 @@ void NcpHost::Update(MainloopContext &aMainloop) mNetif.UpdateFdSet(&aMainloop); } +void NcpHost::SetMdnsPublisher(otbr::Mdns::Publisher *aPublisher) +{ + mNcpSpinel.SetMdnsPublisher(aPublisher); +} + +void NcpHost::HandleMdnsState(otbr::Mdns::Publisher::State aState) +{ + mNcpSpinel.DnssdSetState(aState); +} + } // namespace Ncp } // namespace otbr diff --git a/src/ncp/ncp_host.hpp b/src/ncp/ncp_host.hpp index 9a94f2fd870..d561dad7e33 100644 --- a/src/ncp/ncp_host.hpp +++ b/src/ncp/ncp_host.hpp @@ -38,6 +38,7 @@ #include "lib/spinel/spinel_driver.hpp" #include "common/mainloop.hpp" +#include "mdns/mdns.hpp" #include "ncp/ncp_spinel.hpp" #include "ncp/thread_host.hpp" #include "posix/netif.hpp" @@ -72,7 +73,7 @@ class NcpNetworkProperties : virtual public NetworkProperties, public PropsObser otOperationalDatasetTlvs mDatasetActiveTlvs; }; -class NcpHost : public MainloopProcessor, public ThreadHost, public NcpNetworkProperties +class NcpHost : public MainloopProcessor, public ThreadHost, public NcpNetworkProperties, public Mdns::StateObserver { public: /** @@ -119,7 +120,11 @@ class NcpHost : public MainloopProcessor, public ThreadHost, public NcpNetworkPr void Update(MainloopContext &aMainloop) override; void Process(const MainloopContext &aMainloop) override; + void SetMdnsPublisher(otbr::Mdns::Publisher *aPublisher); + private: + void HandleMdnsState(otbr::Mdns::Publisher::State aState) override; + ot::Spinel::SpinelDriver &mSpinelDriver; otPlatformConfig mConfig; NcpSpinel mNcpSpinel; diff --git a/src/ncp/ncp_spinel.cpp b/src/ncp/ncp_spinel.cpp index ed40d54d823..439a9fb8114 100644 --- a/src/ncp/ncp_spinel.cpp +++ b/src/ncp/ncp_spinel.cpp @@ -36,6 +36,7 @@ #include #include +#include #include "common/code_utils.hpp" #include "common/logging.hpp" @@ -44,6 +45,7 @@ #include "lib/spinel/spinel_driver.hpp" #include "lib/spinel/spinel_encoder.hpp" #include "lib/spinel/spinel_helper.hpp" +#include "lib/spinel/spinel_prop_codec.hpp" namespace otbr { namespace Ncp { @@ -58,6 +60,7 @@ NcpSpinel::NcpSpinel(void) , mEncoder(mNcpBuffer) , mIid(SPINEL_HEADER_INVALID_IID) , mPropsObserver(nullptr) + , mPublisher(nullptr) { std::fill_n(mWaitingKeyTable, SPINEL_PROP_LAST_STATUS, sizeof(mWaitingKeyTable)); memset(mCmdTable, 0, sizeof(mCmdTable)); @@ -76,6 +79,7 @@ void NcpSpinel::Deinit(void) mSpinelDriver = nullptr; mIp6AddressTableCallback = nullptr; mNetifStateChangedCallback = nullptr; + mPublisher = nullptr; } otbrError NcpSpinel::SpinelDataUnpack(const uint8_t *aDataIn, spinel_size_t aDataLen, const char *aPackFormat, ...) @@ -224,6 +228,43 @@ void NcpSpinel::ThreadErasePersistentInfo(AsyncTaskPtr aAsyncTask) } } +void NcpSpinel::SrpServerSetAutoEnableMode(bool aEnabled) +{ + otError error; + EncodingFunc encodingFunc = [aEnabled](ot::Spinel::Encoder &aEncoder) { return aEncoder.WriteBool(aEnabled); }; + + error = SetProperty(SPINEL_PROP_SRP_SERVER_AUTO_ENABLE_MODE, encodingFunc); + if (error != OT_ERROR_NONE) + { + otbrLogWarning("Failed to call SrpServerSetAutoEnableMode, %s", otThreadErrorToString(error)); + } +} + +void NcpSpinel::SrpServerSetEnabled(bool aEnabled) +{ + otError error; + EncodingFunc encodingFunc = [aEnabled](ot::Spinel::Encoder &aEncoder) { return aEncoder.WriteBool(aEnabled); }; + + error = SetProperty(SPINEL_PROP_SRP_SERVER_ENABLED, encodingFunc); + if (error != OT_ERROR_NONE) + { + otbrLogWarning("Failed to call SrpServerSetEnabled, %s", otThreadErrorToString(error)); + } +} + +void NcpSpinel::DnssdSetState(Mdns::Publisher::State aState) +{ + otError error; + otPlatDnssdState state = (aState == Mdns::Publisher::State::kReady) ? OT_PLAT_DNSSD_READY : OT_PLAT_DNSSD_STOPPED; + EncodingFunc encodingFunc = [state](ot::Spinel::Encoder &aEncoder) { return aEncoder.WriteUint8(state); }; + + error = SetProperty(SPINEL_PROP_DNSSD_STATE, encodingFunc); + if (error != OT_ERROR_NONE) + { + otbrLogWarning("Failed to call DnssdSetState, %s", otThreadErrorToString(error)); + } +} + void NcpSpinel::HandleReceivedFrame(const uint8_t *aFrame, uint16_t aLength, uint8_t aHeader, @@ -272,8 +313,19 @@ void NcpSpinel::HandleNotification(const uint8_t *aFrame, uint16_t aLength) SuccessOrExit(error = SpinelDataUnpack(aFrame, aLength, kSpinelDataUnpackFormat, &header, &cmd, &key, &data, &len)); VerifyOrExit(SPINEL_HEADER_GET_TID(header) == 0, error = OTBR_ERROR_PARSE); - VerifyOrExit(cmd == SPINEL_CMD_PROP_VALUE_IS); - HandleValueIs(key, data, static_cast(len)); + + switch (cmd) + { + case SPINEL_CMD_PROP_VALUE_IS: + HandleValueIs(key, data, static_cast(len)); + break; + case SPINEL_CMD_PROP_VALUE_INSERTED: + HandleValueInserted(key, data, static_cast(len)); + break; + case SPINEL_CMD_PROP_VALUE_REMOVED: + HandleValueRemoved(key, data, static_cast(len)); + break; + } exit: otbrLogResult(error, "%s", __FUNCTION__); @@ -439,6 +491,177 @@ void NcpSpinel::HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, ui return; } +static std::string KeyNameFor(const otPlatDnssdKey &aKey) +{ + std::string name(aKey.mName); + + if (aKey.mServiceType != nullptr) + { + name += "."; + name += aKey.mServiceType; + } + return name; +} + +void NcpSpinel::HandleValueInserted(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength) +{ + otbrError error = OTBR_ERROR_NONE; + ot::Spinel::Decoder decoder; + + VerifyOrExit(aBuffer != nullptr, error = OTBR_ERROR_INVALID_ARGS); + decoder.Init(aBuffer, aLength); + + switch (aKey) + { + case SPINEL_PROP_DNSSD_HOST: + { + Mdns::Publisher::AddressList addressList; + otPlatDnssdHost host; + otPlatDnssdRequestId requestId; + const uint8_t *callbackData; + uint16_t callbackDataSize; + std::vector callbackDataCopy; + + SuccessOrExit(ot::Spinel::DecodeDnssdHost(decoder, host, requestId, callbackData, callbackDataSize)); + for (uint16_t i = 0; i < host.mAddressesLength; i++) + { + addressList.push_back(Ip6Address(host.mAddresses[i].mFields.m8)); + } + callbackDataCopy.assign(callbackData, callbackData + callbackDataSize); + + mPublisher->PublishHost(host.mHostName, addressList, [this, requestId, callbackDataCopy](otbrError aError) { + OT_UNUSED_VARIABLE(SendDnssdResult(requestId, callbackDataCopy, OtbrErrorToOtError(aError))); + }); + break; + } + case SPINEL_PROP_DNSSD_SERVICE: + { + otPlatDnssdService service; + Mdns::Publisher::SubTypeList subTypeList; + const char *subTypeArray[kMaxSubTypes]; + uint16_t subTypeCount; + Mdns::Publisher::TxtData txtData; + otPlatDnssdRequestId requestId; + const uint8_t *callbackData; + uint16_t callbackDataSize; + std::vector callbackDataCopy; + + SuccessOrExit(ot::Spinel::DecodeDnssdService(decoder, service, subTypeArray, subTypeCount, requestId, + callbackData, callbackDataSize)); + for (uint16_t i = 0; i < subTypeCount; i++) + { + subTypeList.push_back(subTypeArray[i]); + } + txtData.assign(service.mTxtData, service.mTxtData + service.mTxtDataLength); + callbackDataCopy.assign(callbackData, callbackData + callbackDataSize); + + mPublisher->PublishService(service.mHostName, service.mServiceInstance, service.mServiceType, subTypeList, + service.mPort, txtData, [this, requestId, callbackDataCopy](otbrError aError) { + OT_UNUSED_VARIABLE( + SendDnssdResult(requestId, callbackDataCopy, OtbrErrorToOtError(aError))); + }); + break; + } + case SPINEL_PROP_DNSSD_KEY_RECORD: + { + otPlatDnssdKey key; + Mdns::Publisher::KeyData keyData; + otPlatDnssdRequestId requestId; + const uint8_t *callbackData; + uint16_t callbackDataSize; + std::vector callbackDataCopy; + + SuccessOrExit(ot::Spinel::DecodeDnssdKey(decoder, key, requestId, callbackData, callbackDataSize)); + keyData.assign(key.mKeyData, key.mKeyData + key.mKeyDataLength); + callbackDataCopy.assign(callbackData, callbackData + callbackDataSize); + + mPublisher->PublishKey(KeyNameFor(key), keyData, [this, requestId, callbackDataCopy](otbrError aError) { + OT_UNUSED_VARIABLE(SendDnssdResult(requestId, callbackDataCopy, OtbrErrorToOtError(aError))); + }); + break; + } + default: + error = OTBR_ERROR_DROPPED; + break; + } + +exit: + otbrLogResult(error, "HandleValueInserted, key:%u", aKey); + return; +} + +void NcpSpinel::HandleValueRemoved(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength) +{ + otbrError error = OTBR_ERROR_NONE; + ot::Spinel::Decoder decoder; + + VerifyOrExit(aBuffer != nullptr, error = OTBR_ERROR_INVALID_ARGS); + decoder.Init(aBuffer, aLength); + + switch (aKey) + { + case SPINEL_PROP_DNSSD_HOST: + { + otPlatDnssdHost host; + otPlatDnssdRequestId requestId; + const uint8_t *callbackData; + uint16_t callbackDataSize; + std::vector callbackDataCopy; + + SuccessOrExit(ot::Spinel::DecodeDnssdHost(decoder, host, requestId, callbackData, callbackDataSize)); + callbackDataCopy.assign(callbackData, callbackData + callbackDataSize); + + mPublisher->UnpublishHost(host.mHostName, [this, requestId, callbackDataCopy](otbrError aError) { + OT_UNUSED_VARIABLE(SendDnssdResult(requestId, callbackDataCopy, OtbrErrorToOtError(aError))); + }); + break; + } + case SPINEL_PROP_DNSSD_SERVICE: + { + otPlatDnssdService service; + const char *subTypeArray[kMaxSubTypes]; + uint16_t subTypeCount; + otPlatDnssdRequestId requestId; + const uint8_t *callbackData; + uint16_t callbackDataSize; + std::vector callbackDataCopy; + + SuccessOrExit(ot::Spinel::DecodeDnssdService(decoder, service, subTypeArray, subTypeCount, requestId, + callbackData, callbackDataSize)); + callbackDataCopy.assign(callbackData, callbackData + callbackDataSize); + + mPublisher->UnpublishService( + service.mHostName, service.mServiceType, [this, requestId, callbackDataCopy](otbrError aError) { + OT_UNUSED_VARIABLE(SendDnssdResult(requestId, callbackDataCopy, OtbrErrorToOtError(aError))); + }); + break; + } + case SPINEL_PROP_DNSSD_KEY_RECORD: + { + otPlatDnssdKey key; + otPlatDnssdRequestId requestId; + const uint8_t *callbackData; + uint16_t callbackDataSize; + std::vector callbackDataCopy; + + SuccessOrExit(ot::Spinel::DecodeDnssdKey(decoder, key, requestId, callbackData, callbackDataSize)); + callbackDataCopy.assign(callbackData, callbackData + callbackDataSize); + + mPublisher->UnpublishKey(KeyNameFor(key), [this, requestId, callbackDataCopy](otbrError aError) { + OT_UNUSED_VARIABLE(SendDnssdResult(requestId, callbackDataCopy, OtbrErrorToOtError(aError))); + }); + break; + } + default: + error = OTBR_ERROR_DROPPED; + break; + } + +exit: + otbrLogResult(error, "HandleValueRemoved, key:%u", aKey); + return; +} + otbrError NcpSpinel::HandleResponseForPropSet(spinel_tid_t aTid, spinel_prop_key_t aKey, const uint8_t *aData, @@ -801,6 +1024,31 @@ otError NcpSpinel::ParseInfraIfIcmp6Nd(const uint8_t *aBuf, return error; } +otError NcpSpinel::SendDnssdResult(otPlatDnssdRequestId aRequestId, + const std::vector &aCallbackData, + otError aError) +{ + otError error; + EncodingFunc encodingFunc = [aRequestId, &aCallbackData, aError](ot::Spinel::Encoder &aEncoder) { + otError error = OT_ERROR_NONE; + + SuccessOrExit(aEncoder.WriteUint8(aError)); + SuccessOrExit(aEncoder.WriteUint32(aRequestId)); + SuccessOrExit(aEncoder.WriteData(aCallbackData.data(), aCallbackData.size())); + + exit: + return error; + }; + + error = SetProperty(SPINEL_PROP_DNSSD_REQUEST_RESULT, encodingFunc); + if (error != OT_ERROR_NONE) + { + otbrLogWarning("Failed to SendDnssdResult, %s", otThreadErrorToString(error)); + } + + return error; +} + otbrError NcpSpinel::SetInfraIf(uint32_t aInfraIfIndex, bool aIsRunning, const std::vector &aIp6Addresses) { otbrError error = OTBR_ERROR_NONE; diff --git a/src/ncp/ncp_spinel.hpp b/src/ncp/ncp_spinel.hpp index bb79274413b..bae24693626 100644 --- a/src/ncp/ncp_spinel.hpp +++ b/src/ncp/ncp_spinel.hpp @@ -37,10 +37,13 @@ #include #include +#include + #include #include #include #include +#include #include "lib/spinel/spinel.h" #include "lib/spinel/spinel_buffer.hpp" @@ -49,6 +52,7 @@ #include "common/task_runner.hpp" #include "common/types.hpp" +#include "mdns/mdns.hpp" #include "ncp/async_task.hpp" #include "ncp/posix/infra_if.hpp" #include "ncp/posix/netif.hpp" @@ -245,10 +249,43 @@ class NcpSpinel : public Netif::Dependencies, public InfraIf::Dependencies mInfraIfIcmp6NdCallback = aCallback; } + /** + * This method enables/disables the SRP Server on NCP. + * + * @param[in] aEnable A boolean to enable/disable the SRP server. + * + */ + void SrpServerSetEnabled(bool aEnabled); + + /** + * This method enables/disables the auto-enable mode on SRP Server on NCP. + * + * @param[in] aEnable A boolean to enable/disable the SRP server. + * + */ + void SrpServerSetAutoEnableMode(bool aEnabled); + + /** + * This method sets the dnssd state on NCP. + * + * @param[in] aState The dnssd state. + * + */ + void DnssdSetState(Mdns::Publisher::State aState); + + /** + * This method sets the mDNS Publisher object. + * + * @param[in] aPublisher A pointer to the mDNS Publisher object. + */ + void SetMdnsPublisher(otbr::Mdns::Publisher *aPublisher) { mPublisher = aPublisher; } + private: using FailureHandler = std::function; - static constexpr uint8_t kMaxTids = 16; + static constexpr uint8_t kMaxTids = 16; + static constexpr uint16_t kCallbackDataMaxSize = sizeof(uint64_t); // Maximum size of a function pointer. + static constexpr uint16_t kMaxSubTypes = 8; // Maximum number of sub types in a MDNS service. template static void SafeInvoke(Function &aFunc, Args &&...aArgs) { @@ -282,6 +319,8 @@ class NcpSpinel : public Netif::Dependencies, public InfraIf::Dependencies void HandleNotification(const uint8_t *aFrame, uint16_t aLength); void HandleResponse(spinel_tid_t aTid, const uint8_t *aFrame, uint16_t aLength); void HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength); + void HandleValueInserted(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength); + void HandleValueRemoved(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength); otbrError HandleResponseForPropSet(spinel_tid_t aTid, spinel_prop_key_t aKey, const uint8_t *aData, @@ -320,6 +359,7 @@ class NcpSpinel : public Netif::Dependencies, public InfraIf::Dependencies const otIp6Address *&aAddr, const uint8_t *&aData, uint16_t &aDataLen); + otError SendDnssdResult(otPlatDnssdRequestId aRequestId, const std::vector &aCallbackData, otError aError); otbrError SetInfraIf(uint32_t aInfraIfIndex, bool aIsRunning, @@ -345,7 +385,8 @@ class NcpSpinel : public Netif::Dependencies, public InfraIf::Dependencies TaskRunner mTaskRunner; - PropsObserver *mPropsObserver; + PropsObserver *mPropsObserver; + otbr::Mdns::Publisher *mPublisher; AsyncTaskPtr mDatasetSetActiveTask; AsyncTaskPtr mDatasetMgmtSetPendingTask; diff --git a/tests/scripts/bootstrap.sh b/tests/scripts/bootstrap.sh index 6d32cea0a77..99e4b969b20 100755 --- a/tests/scripts/bootstrap.sh +++ b/tests/scripts/bootstrap.sh @@ -118,6 +118,10 @@ case "$(uname)" in configure_network fi + if [ "$BUILD_TARGET" == ncp_mode ]; then + sudo apt-get install --no-install-recommends -y avahi-daemon avahi-utils + fi + if [ "$BUILD_TARGET" == scan-build ]; then pip3 install -U cmake sudo apt-get install --no-install-recommends -y clang clang-tools diff --git a/tests/scripts/expect/ncp_schedule_migration.exp b/tests/scripts/expect/ncp_schedule_migration.exp old mode 100644 new mode 100755 diff --git a/tests/scripts/expect/ncp_srp_server.exp b/tests/scripts/expect/ncp_srp_server.exp new file mode 100755 index 00000000000..b7d6ab24529 --- /dev/null +++ b/tests/scripts/expect/ncp_srp_server.exp @@ -0,0 +1,77 @@ +#!/usr/bin/expect -f +# +# Copyright (c) 2024, 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. +# +source "tests/scripts/expect/_common.exp" + +set ptys [create_socat 1] +set pty1 [lindex $ptys 0] +set pty2 [lindex $ptys 1] +set container "otbr-ncp" + +set dataset "0e080000000000010000000300001435060004001fffe002087d61eb42cdc48d6a0708fd0d07fca1b9f0500510ba088fc2bd6c3b3897f7a10f58263ff3030f4f70656e5468726561642d353234660102524f04109dc023ccd447b12b50997ef68020f19e0c0402a0f7f8" +set dataset_dbus "0x0e,0x08,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x14,0x35,0x06,0x00,0x04,0x00,0x1f,0xff,0xe0,0x02,0x08,0x7d,0x61,0xeb,0x42,0xcd,0xc4,0x8d,0x6a,0x07,0x08,0xfd,0x0d,0x07,0xfc,0xa1,0xb9,0xf0,0x50,0x05,0x10,0xba,0x08,0x8f,0xc2,0xbd,0x6c,0x3b,0x38,0x97,0xf7,0xa1,0x0f,0x58,0x26,0x3f,0xf3,0x03,0x0f,0x4f,0x70,0x65,0x6e,0x54,0x68,0x72,0x65,0x61,0x64,0x2d,0x35,0x32,0x34,0x66,0x01,0x02,0x52,0x4f,0x04,0x10,0x9d,0xc0,0x23,0xcc,0xd4,0x47,0xb1,0x2b,0x50,0x99,0x7e,0xf6,0x80,0x20,0xf1,0x9e,0x0c,0x04,0x02,0xa0,0xf7,0xf8" + +start_otbr_docker $container $::env(EXP_OT_NCP_PATH) 2 $pty1 $pty2 +spawn_node 3 otbr-docker $container +sleep 5 + +send "dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 io.openthread.BorderRouter.Join \"array:byte:${dataset_dbus}\"\n" +expect "app#" +sleep 20 + +spawn_node 4 cli $::env(EXP_OT_CLI_PATH) +send "dataset set active ${dataset}\n" +expect_line "Done" +send "mode rn\r\n" +expect_line "Done" +send "ifconfig up\r\n" +expect_line "Done" +send "thread start\r\n" +expect_line "Done" +wait_for "state" "child" +set omr_addr [get_omr_addr] +sleep 1 + +send "srp client autostart enable\r\n" +expect_line "Done" +send "srp client host name otbr-ncp-test\r\n" +expect_line "Done" +send "srp client host address $omr_addr\r\n" +expect_line "Done" +send "srp client service add ot-service _ipps._tcp 12345\r\n" +expect_line "Done" +sleep 1 + +spawn avahi-browse -r _ipps._tcp +expect backbone1 +send "\003" +expect eof + +exec sudo docker stop $container +exec sudo docker rm $container +dispose_all diff --git a/tests/scripts/ncp_mode b/tests/scripts/ncp_mode index b555f3fdec9..2544bf5b397 100755 --- a/tests/scripts/ncp_mode +++ b/tests/scripts/ncp_mode @@ -136,6 +136,7 @@ do_build_ot_simulation() OT_CMAKE_BUILD_DIR=${ABS_TOP_OT_BUILDDIR}/ncp "${ABS_TOP_OT_SRCDIR}"/script/cmake-build simulation \ -DOT_MTD=OFF -DOT_RCP=OFF -DOT_APP_CLI=OFF -DOT_APP_RCP=OFF \ -DOT_BORDER_ROUTING=ON -DOT_NCP_INFRA_IF=ON -DOT_SIMULATION_INFRA_IF=OFF \ + -DOT_SRP_SERVER=ON -DOT_SRP_ADV_PROXY=ON -DOT_PLATFORM_DNSSD=ON -DOT_SIMULATION_DNSSD=OFF -DOT_NCP_DNSSD=ON \ -DBUILD_TESTING=OFF OT_CMAKE_BUILD_DIR=${ABS_TOP_OT_BUILDDIR}/cli "${ABS_TOP_OT_SRCDIR}"/script/cmake-build simulation \ -DOT_MTD=OFF -DOT_RCP=OFF -DOT_APP_NCP=OFF -DOT_APP_RCP=OFF \ @@ -152,6 +153,7 @@ do_build_otbr_docker() "-DOTBR_TELEMETRY_DATA_API=ON" "-DOTBR_TREL=ON" "-DOTBR_LINK_METRICS_TELEMETRY=ON" + "-DOTBR_SRP_ADVERTISING_PROXY=ON" ) sudo docker build -t "${OTBR_DOCKER_IMAGE}" \ -f ./etc/docker/Dockerfile . \