diff --git a/src/lib/spinel/spinel.c b/src/lib/spinel/spinel.c index b5bc04fdd..b39b4348c 100644 --- a/src/lib/spinel/spinel.c +++ b/src/lib/spinel/spinel.c @@ -1414,6 +1414,8 @@ const char *spinel_prop_key_to_cstr(spinel_prop_key_t prop_key) {SPINEL_PROP_SRP_SERVER_ENABLED, "SPINEL_PROP_SRP_SERVER_ENABLED"}, {SPINEL_PROP_SRP_SERVER_AUTO_ENABLE_MODE, "SPINEL_PROP_SRP_SERVER_AUTO_ENABLE_MODE"}, {SPINEL_PROP_DNSSD_STATE, "DNSSD_STATE"}, + {SPINEL_PROP_DNSSD_REQUEST_RESULT, "DNSSD_REQUEST_RESULT"}, + {SPINEL_PROP_DNSSD_HOST, "DNSSD_HOST"}, {SPINEL_PROP_PARENT_RESPONSE_INFO, "PARENT_RESPONSE_INFO"}, {SPINEL_PROP_SLAAC_ENABLED, "SLAAC_ENABLED"}, {SPINEL_PROP_SUPPORTED_RADIO_LINKS, "SUPPORTED_RADIO_LINKS"}, diff --git a/src/lib/spinel/spinel.h b/src/lib/spinel/spinel.h index 281f902bd..162f14de3 100644 --- a/src/lib/spinel/spinel.h +++ b/src/lib/spinel/spinel.h @@ -4785,17 +4785,6 @@ enum SPINEL_PROP_SRP_SERVER__BEGIN = 0x920, - SPINEL_PROP_DNSSD__BEGIN = 0x930, - - /// Dnssd State - /** Format `b`: Write-only - * - * `C`: The dnssd state. - */ - SPINEL_PROP_DNSSD_STATE = SPINEL_PROP_DNSSD__BEGIN + 1, - - SPINEL_PROP_DNSSD__END = 0x950, - /// SRP server state. /** Format `b` * Type: Read-Write @@ -4814,6 +4803,41 @@ enum SPINEL_PROP_SRP_SERVER__END = 0x930, + SPINEL_PROP_DNSSD__BEGIN = 0x930, + + /// Dnssd State + /** Format `C`: Write-only + * + * `C`: The dnssd state. + */ + SPINEL_PROP_DNSSD_STATE = SPINEL_PROP_DNSSD__BEGIN + 1, + + /// Dnssd Request Result + /** Format `CLD`: Write + * + * `C` : The result of the request. A unsigned int8 corresponds to otError. + * `L` : The Dnssd Request ID. + * `D` : The context of the request. (A pointer to the callback for the request) + * + * Host uses this property to notify the NCP of the result of NCP's DNS-SD request. + */ + SPINEL_PROP_DNSSD_REQUEST_RESULT = SPINEL_PROP_DNSSD__BEGIN + 2, + + /// DNS-SD Host + /** Format `USA(6)LD`: Inserted/Removed + * + * `U` : The host name. + * `S` : The count of IPv6 addresses. + * `A(6)` : The IPv6 addresses of the host. + * `L` : The Dnssd Request ID. + * `D` : The context of the request. (A pointer to the callback for the request) + * + * NCP uses this property to register/unregister a DNS-SD host. + */ + SPINEL_PROP_DNSSD_HOST = SPINEL_PROP_DNSSD__BEGIN + 3, + + SPINEL_PROP_DNSSD__END = 0x950, + SPINEL_PROP_NEST__BEGIN = 0x3BC0, SPINEL_PROP_NEST_STREAM_MFG = SPINEL_PROP_NEST__BEGIN + 0, diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index a8e95b9ce..c3db7f543 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -53,6 +53,7 @@ #if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE #include #endif +#include #include "changed_props_set.hpp" #include "common/tasklet.hpp" @@ -245,6 +246,28 @@ public: uint16_t aBufferLength); #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_NCP_DNSSD_ENABLE && OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE + /** + * Registers or updates a host on the infrastructure network's DNS-SD module (on host). + * + * @param[in] aHost Information about the host to register. + * @param[in] aRequestId The ID associated with this request. + * @param[in] aCallback The callback function pointer to report the outcome (may be NULL if no callback needed). + */ + void DnssdRegisterHost(const otPlatDnssdHost *aHost, + otPlatDnssdRequestId aRequestId, + otPlatDnssdRegisterCallback aCallback); + + /** + * Unregisters a host on the infrastructure network's DNS-SD module (on host). + * + * @param[in] aHost Information about the host to register. + * @param[in] aRequestId The ID associated with this request. + * @param[in] aCallback The callback function pointer to report the outcome (may be NULL if no callback needed). + */ + void DnssdUnregisterHost(const otPlatDnssdHost *aHost, + otPlatDnssdRequestId aRequestId, + otPlatDnssdRegisterCallback aCallback); + /** * Gets the Dnssd state. * @@ -780,6 +803,34 @@ protected: #endif #if OPENTHREAD_CONFIG_NCP_DNSSD_ENABLE && OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE + + template + void DnssdUpdate(const DnssdObjType *Obj, + otPlatDnssdRequestId aRequestId, + otPlatDnssdRegisterCallback aCallback, + bool aRegister) + { + otError error = OT_ERROR_NONE; + uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_TX_NOTIFICATION_IID; + spinel_command_t cmd = aRegister ? SPINEL_CMD_PROP_VALUE_INSERTED : SPINEL_CMD_PROP_VALUE_REMOVED; + + VerifyOrExit(mDnssdState == OT_PLAT_DNSSD_READY, error = OT_ERROR_INVALID_STATE); + + SuccessOrExit(error = mEncoder.BeginFrame(header, cmd)); + SuccessOrExit(error = EncodeDnssd(Obj)); + SuccessOrExit(error = mEncoder.WriteUint32(aRequestId)); + SuccessOrExit(error = mEncoder.WriteData(reinterpret_cast(&aCallback), sizeof(aCallback))); + SuccessOrExit(error = mEncoder.EndFrame()); + + exit: + if (error != OT_ERROR_NONE) + { + aCallback(mInstance, aRequestId, error); + } + } + + template otError EncodeDnssd(const DnssdObjType *aObj); + otPlatDnssdState mDnssdState; #endif #endif diff --git a/src/ncp/ncp_base_dispatcher.cpp b/src/ncp/ncp_base_dispatcher.cpp index 1dcb76027..60db0e65f 100644 --- a/src/ncp/ncp_base_dispatcher.cpp +++ b/src/ncp/ncp_base_dispatcher.cpp @@ -537,6 +537,7 @@ NcpBase::PropertyHandler NcpBase::FindSetPropertyHandler(spinel_prop_key_t aKey) #endif #if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE && OPENTHREAD_CONFIG_NCP_DNSSD_ENABLE OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_DNSSD_STATE), + OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_DNSSD_REQUEST_RESULT), #endif #endif // OPENTHREAD_FTD #if OPENTHREAD_MTD || OPENTHREAD_FTD diff --git a/src/ncp/ncp_base_ftd.cpp b/src/ncp/ncp_base_ftd.cpp index a0db64948..066919a84 100644 --- a/src/ncp/ncp_base_ftd.cpp +++ b/src/ncp/ncp_base_ftd.cpp @@ -1566,6 +1566,36 @@ exit: #if OPENTHREAD_CONFIG_NCP_DNSSD_ENABLE && OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE +template <> otError NcpBase::EncodeDnssd(const otPlatDnssdHost *aHost) +{ + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_DNSSD_HOST)); + SuccessOrExit(error = mEncoder.WriteUtf8(aHost->mHostName == nullptr ? "" : aHost->mHostName)); + SuccessOrExit(error = mEncoder.WriteUint16(aHost->mAddressesLength)); + for (uint8_t i = 0; i < aHost->mAddressesLength; i++) + { + SuccessOrExit(error = mEncoder.WriteIp6Address(aHost->mAddresses[i])); + } + +exit: + return error; +} + +void NcpBase::DnssdRegisterHost(const otPlatDnssdHost *aHost, + otPlatDnssdRequestId aRequestId, + otPlatDnssdRegisterCallback aCallback) +{ + DnssdUpdate(aHost, aRequestId, aCallback, /* aRegister */ true); +} + +void NcpBase::DnssdUnregisterHost(const otPlatDnssdHost *aHost, + otPlatDnssdRequestId aRequestId, + otPlatDnssdRegisterCallback aCallback) +{ + DnssdUpdate(aHost, aRequestId, aCallback, /* aRegister */ false); +} + otPlatDnssdState NcpBase::DnssdGetState(void) { return mDnssdState; } template <> otError NcpBase::HandlePropertySet(void) @@ -1585,6 +1615,26 @@ exit: return error; } +template <> otError NcpBase::HandlePropertySet(void) +{ + otError error = OT_ERROR_NONE; + otPlatDnssdRequestId requestId; + uint8_t result; + otPlatDnssdRegisterCallback callback = nullptr; + const uint8_t *context; + uint16_t contextLen; + + SuccessOrExit(error = mDecoder.ReadUint8(result)); + SuccessOrExit(error = mDecoder.ReadUint32(requestId)); + SuccessOrExit(error = mDecoder.ReadData(context, contextLen)); + VerifyOrExit(contextLen == sizeof(otPlatDnssdRegisterCallback), error = OT_ERROR_PARSE); + callback = *reinterpret_cast(context); + callback(mInstance, requestId, static_cast(result)); + +exit: + return error; +} + #endif // OPENTHREAD_CONFIG_NCP_DNSSD_ENABLE && OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE } // namespace Ncp diff --git a/src/ncp/platform/dnssd.cpp b/src/ncp/platform/dnssd.cpp index 2dbc39e8f..58f662576 100644 --- a/src/ncp/platform/dnssd.cpp +++ b/src/ncp/platform/dnssd.cpp @@ -67,9 +67,9 @@ void otPlatDnssdRegisterHost(otInstance *aInstance, otPlatDnssdRegisterCallback aCallback) { OT_UNUSED_VARIABLE(aInstance); - OT_UNUSED_VARIABLE(aHost); - OT_UNUSED_VARIABLE(aRequestId); - OT_UNUSED_VARIABLE(aCallback); + ot::Ncp::NcpBase *ncp = ot::Ncp::NcpBase::GetNcpInstance(); + + ncp->DnssdRegisterHost(aHost, aRequestId, aCallback); } void otPlatDnssdUnregisterHost(otInstance *aInstance, @@ -78,9 +78,9 @@ void otPlatDnssdUnregisterHost(otInstance *aInstance, otPlatDnssdRegisterCallback aCallback) { OT_UNUSED_VARIABLE(aInstance); - OT_UNUSED_VARIABLE(aHost); - OT_UNUSED_VARIABLE(aRequestId); - OT_UNUSED_VARIABLE(aCallback); + ot::Ncp::NcpBase *ncp = ot::Ncp::NcpBase::GetNcpInstance(); + + ncp->DnssdUnregisterHost(aHost, aRequestId, aCallback); } void otPlatDnssdRegisterKey(otInstance *aInstance, diff --git a/tests/unit/test_ncp_dnssd.cpp b/tests/unit/test_ncp_dnssd.cpp index 9c1c6e6d9..336c4cc7d 100644 --- a/tests/unit/test_ncp_dnssd.cpp +++ b/tests/unit/test_ncp_dnssd.cpp @@ -42,6 +42,8 @@ namespace ot { constexpr uint16_t kMaxSpinelBufferSize = 2048; +static uint32_t sRequestId; +static uint8_t sError; static otError GenerateSpinelDnssdSetStateFrame(otPlatDnssdState aState, uint8_t *aBuf, uint16_t &aLen) { @@ -63,6 +65,35 @@ exit: return error; } +static void TestPlatDnssdRegisterCallback(otInstance *aInstance, otPlatDnssdRequestId aRequestId, otError aError) +{ + sRequestId = aRequestId; + sError = aError; +} + +static otError GenerateSpinelDnssdRequestResultFrame(uint32_t aRequestId, otError aError, uint8_t *aBuf, uint16_t &aLen) +{ + otError error = OT_ERROR_NONE; + uint8_t buf[kMaxSpinelBufferSize]; + Spinel::Buffer ncpBuffer(buf, kMaxSpinelBufferSize); + Spinel::Encoder encoder(ncpBuffer); + otPlatDnssdRegisterCallback callback = &TestPlatDnssdRegisterCallback; + + uint8_t header = SPINEL_HEADER_FLAG | 0 /* Iid */ | 1 /* Tid */; + SuccessOrExit(error = encoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_DNSSD_REQUEST_RESULT)); + SuccessOrExit(error = encoder.WriteUint8(aError)); + SuccessOrExit(error = encoder.WriteUint32(aRequestId)); + SuccessOrExit(error = encoder.WriteData(reinterpret_cast(&callback), sizeof(callback))); + SuccessOrExit(error = encoder.EndFrame()); + + SuccessOrExit(ncpBuffer.OutFrameBegin()); + aLen = ncpBuffer.OutFrameGetLength(); + VerifyOrExit(ncpBuffer.OutFrameRead(aLen, aBuf) == aLen, error = OT_ERROR_FAILED); + +exit: + return error; +} + void TestNcpDnssdGetState(void) { Instance *instance = static_cast(testInitInstance()); @@ -81,6 +112,35 @@ void TestNcpDnssdGetState(void) VerifyOrQuit(dnssdState == OT_PLAT_DNSSD_READY); } +void TestNcpDnssdRegistrations(void) +{ + Instance *instance = static_cast(testInitInstance()); + Ncp::NcpBase ncpBase(instance); + + uint8_t recvBuf[kMaxSpinelBufferSize]; + uint16_t recvLen; + otPlatDnssdHost dnssdHost; + + sRequestId = 0; // Use 0 to indicate `sRequestId` hasn't been set. + + // Register a dnssd host when the dnssd state is DISABLED + dnssdHost.mHostName = "ot-test"; + dnssdHost.mAddressesLength = 0; + otPlatDnssdRegisterHost(instance, &dnssdHost, 1 /* aRequestId */, TestPlatDnssdRegisterCallback); + VerifyOrQuit(sRequestId == 1); + VerifyOrQuit(sError == OT_ERROR_INVALID_STATE); + + // Set the dnssd state to READY + SuccessOrQuit(GenerateSpinelDnssdSetStateFrame(OT_PLAT_DNSSD_READY, recvBuf, recvLen)); + ncpBase.HandleReceive(recvBuf, recvLen); + + otPlatDnssdUnregisterHost(instance, &dnssdHost, 2 /* aRequestId */, TestPlatDnssdRegisterCallback); + SuccessOrQuit(GenerateSpinelDnssdRequestResultFrame(2 /* aRequestId */, OT_ERROR_NOT_FOUND, recvBuf, recvLen)); + ncpBase.HandleReceive(recvBuf, recvLen); + VerifyOrQuit(sRequestId == 2); + VerifyOrQuit(sError == OT_ERROR_NOT_FOUND); +} + } // namespace ot #endif // OPENTHREAD_CONFIG_NCP_DNSSD_ENABLE && OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE @@ -89,6 +149,7 @@ int main(void) { #if OPENTHREAD_CONFIG_NCP_DNSSD_ENABLE && OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE ot::TestNcpDnssdGetState(); + ot::TestNcpDnssdRegistrations(); #endif printf("All tests passed\n"); return 0;