diff --git a/include/openthread/platform/toolchain.h b/include/openthread/platform/toolchain.h index 0741f175d..0bfd0a6f4 100644 --- a/include/openthread/platform/toolchain.h +++ b/include/openthread/platform/toolchain.h @@ -310,6 +310,10 @@ extern "C" { #define UINT32_MAX 0xffffffff #endif +#ifndef UINT8_MAX +#define UINT8_MAX 0xff +#endif + #endif #endif diff --git a/include/openthread/server.h b/include/openthread/server.h index e9b52e444..170f377f3 100644 --- a/include/openthread/server.h +++ b/include/openthread/server.h @@ -123,10 +123,10 @@ OTAPI otError OTCALL otServerAddService(otInstance *aInstance, const otServiceCo * @sa otServerRegister * */ -OTAPI otError OTCALL otServerRemoveService(otInstance *aInstance, - uint32_t aEnterpriseNumber, - uint8_t * aServiceData, - uint8_t aServiceDataLength); +OTAPI otError OTCALL otServerRemoveService(otInstance * aInstance, + uint32_t aEnterpriseNumber, + const uint8_t *aServiceData, + uint8_t aServiceDataLength); /** * This function gets the next service in the local Network Data. diff --git a/src/core/api/server_api.cpp b/src/core/api/server_api.cpp index 306dc0222..d29bdcdbc 100644 --- a/src/core/api/server_api.cpp +++ b/src/core/api/server_api.cpp @@ -64,10 +64,10 @@ otError otServerAddService(otInstance *aInstance, const otServiceConfig *aConfig aConfig->mServerConfig.mServerDataLength); } -otError otServerRemoveService(otInstance *aInstance, - uint32_t aEnterpriseNumber, - uint8_t * aServiceData, - uint8_t aServiceDataLength) +otError otServerRemoveService(otInstance * aInstance, + uint32_t aEnterpriseNumber, + const uint8_t *aServiceData, + uint8_t aServiceDataLength) { Instance &instance = *static_cast(aInstance); diff --git a/src/core/openthread-core-config-check.h b/src/core/openthread-core-config-check.h index a22d54e66..384348f5d 100644 --- a/src/core/openthread-core-config-check.h +++ b/src/core/openthread-core-config-check.h @@ -53,4 +53,8 @@ "OPENTHREAD_CONFIG_MAX_TX_ATTEMPTS_INDIRECT_PER_POLL was replaced by OPENTHREAD_CONFIG_MAC_MAX_FRAME_RETRIES_INDIRECT." #endif +#ifdef OPENTHREAD_CONFIG_MAX_SERVER_ALOCS +#error "OPENTHREAD_CONFIG_MAX_SERVER_ALOCS was replaced by OPENTHREAD_CONFIG_MAX_SERVICE_ALOCS" +#endif + #endif // OPENTHREAD_CORE_CONFIG_CHECK_H_ diff --git a/src/core/openthread-core-default-config.h b/src/core/openthread-core-default-config.h index ecca7ee20..a4860eca6 100644 --- a/src/core/openthread-core-default-config.h +++ b/src/core/openthread-core-default-config.h @@ -370,13 +370,13 @@ #endif /** - * @def OPENTHREAD_CONFIG_MAX_SERVER_ALOCS + * @def OPENTHREAD_CONFIG_MAX_SERVICE_ALOCS * * The maximum number of supported Service ALOCs registrations for this device. * */ -#ifndef OPENTHREAD_CONFIG_MAX_SERVER_ALOCS -#define OPENTHREAD_CONFIG_MAX_SERVER_ALOCS 1 +#ifndef OPENTHREAD_CONFIG_MAX_SERVICE_ALOCS +#define OPENTHREAD_CONFIG_MAX_SERVICE_ALOCS 1 #endif /** diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index 07afdb056..c01a2fc39 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -1790,7 +1790,7 @@ private: Ip6::NetifUnicastAddress mLeaderAloc; #if OPENTHREAD_ENABLE_SERVICE - Ip6::NetifUnicastAddress mServiceAlocs[OPENTHREAD_CONFIG_MAX_SERVER_ALOCS]; + Ip6::NetifUnicastAddress mServiceAlocs[OPENTHREAD_CONFIG_MAX_SERVICE_ALOCS]; #endif otMleCounters mCounters; diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index bc6db31bd..016e92d3f 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -228,6 +228,9 @@ NcpBase::NcpBase(Instance *aInstance) , mPcapEnabled(false) , mDisableStreamWrite(false) , mShouldEmitChildTableUpdate(false) +#if OPENTHREAD_ENABLE_SERVICE + , mAllowLocalServerDataChange(false) +#endif #if OPENTHREAD_FTD , mPreferredRouteId(0) #endif @@ -1820,6 +1823,10 @@ template <> otError NcpBase::HandlePropertyGet(void) SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_THREAD_UDP_FORWARD)); #endif +#if OPENTHREAD_ENABLE_SERVICE + SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_THREAD_SERVICE)); +#endif + #endif // OPENTHREAD_MTD || OPENTHREAD_FTD exit: diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index 2991147a1..6c495a79d 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -543,6 +543,9 @@ protected: bool mPcapEnabled; bool mDisableStreamWrite; bool mShouldEmitChildTableUpdate; +#if OPENTHREAD_ENABLE_SERVICE + bool mAllowLocalServerDataChange; +#endif #if OPENTHREAD_FTD #if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB diff --git a/src/ncp/ncp_base_dispatcher.cpp b/src/ncp/ncp_base_dispatcher.cpp index 41d1f5187..8d8893029 100644 --- a/src/ncp/ncp_base_dispatcher.cpp +++ b/src/ncp/ncp_base_dispatcher.cpp @@ -516,6 +516,17 @@ NcpBase::PropertyHandler NcpBase::FindGetPropertyHandler(spinel_prop_key_t aKey) handler = &NcpBase::HandlePropertyGet; break; #endif +#if OPENTHREAD_ENABLE_SERVICE + case SPINEL_PROP_SERVER_ALLOW_LOCAL_DATA_CHANGE: + handler = &NcpBase::HandlePropertyGet; + break; + case SPINEL_PROP_SERVER_SERVICES: + handler = &NcpBase::HandlePropertyGet; + break; + case SPINEL_PROP_SERVER_LEADER_SERVICES: + handler = &NcpBase::HandlePropertyGet; + break; +#endif #endif // OPENTHREAD_MTD || OPENTHREAD_FTD // -------------------------------------------------------------------------- @@ -852,6 +863,11 @@ NcpBase::PropertyHandler NcpBase::FindSetPropertyHandler(spinel_prop_key_t aKey) handler = &NcpBase::HandlePropertySet; break; #endif +#if OPENTHREAD_ENABLE_SERVICE + case SPINEL_PROP_SERVER_ALLOW_LOCAL_DATA_CHANGE: + handler = &NcpBase::HandlePropertySet; + break; +#endif #endif // OPENTHREAD_MTD || OPENTHREAD_FTD // -------------------------------------------------------------------------- @@ -1032,6 +1048,11 @@ NcpBase::PropertyHandler NcpBase::FindInsertPropertyHandler(spinel_prop_key_t aK handler = &NcpBase::HandlePropertyInsert; break; #endif +#if OPENTHREAD_ENABLE_SERVICE + case SPINEL_PROP_SERVER_SERVICES: + handler = &NcpBase::HandlePropertyInsert; + break; +#endif #endif // OPENTHREAD_MTD || OPENTHREAD_FTD // -------------------------------------------------------------------------- @@ -1112,6 +1133,11 @@ NcpBase::PropertyHandler NcpBase::FindRemovePropertyHandler(spinel_prop_key_t aK handler = &NcpBase::HandlePropertyRemove; break; #endif +#if OPENTHREAD_ENABLE_SERVICE + case SPINEL_PROP_SERVER_SERVICES: + handler = &NcpBase::HandlePropertyRemove; + break; +#endif #endif // OPENTHREAD_MTD || OPENTHREAD_FTD // -------------------------------------------------------------------------- diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp index 8063a4999..d1baca1c9 100644 --- a/src/ncp/ncp_base_mtd.cpp +++ b/src/ncp/ncp_base_mtd.cpp @@ -57,6 +57,9 @@ #if OPENTHREAD_FTD #include #endif +#if OPENTHREAD_ENABLE_SERVICE +#include +#endif #include "common/code_utils.hpp" #include "common/debug.hpp" @@ -818,6 +821,140 @@ exit: } #endif // OPENTHREAD_ENABLE_BORDER_ROUTER +#if OPENTHREAD_ENABLE_SERVICE + +template <> otError NcpBase::HandlePropertyGet(void) +{ + return mEncoder.WriteBool(mAllowLocalServerDataChange); +} + +template <> otError NcpBase::HandlePropertySet(void) +{ + bool value = false; + otError error = OT_ERROR_NONE; + bool shouldRegisterWithLeader = false; + + SuccessOrExit(error = mDecoder.ReadBool(value)); + + // Register any server data changes on transition from `true` to `false`. + shouldRegisterWithLeader = (mAllowLocalServerDataChange == true) && (value == false); + + mAllowLocalServerDataChange = value; + +exit: + + if (shouldRegisterWithLeader) + { + otServerRegister(mInstance); + } + + return error; +} + +template <> otError NcpBase::HandlePropertyInsert(void) +{ + otError error = OT_ERROR_NONE; + otServiceConfig cfg; + bool stable; + const uint8_t * data; + uint16_t dataLen; + + VerifyOrExit(mAllowLocalServerDataChange == true, error = OT_ERROR_INVALID_STATE); + + SuccessOrExit(error = mDecoder.ReadUint32(cfg.mEnterpriseNumber)); + SuccessOrExit(error = mDecoder.ReadDataWithLen(data, dataLen)); + + VerifyOrExit((dataLen <= sizeof(cfg.mServiceData)), error = OT_ERROR_INVALID_ARGS); + memcpy(cfg.mServiceData, data, dataLen); + + OT_STATIC_ASSERT((sizeof(cfg.mServiceData) <= UINT8_MAX), "Cannot handle full range of buffer length"); + cfg.mServiceDataLength = static_cast(dataLen); + + SuccessOrExit(error = mDecoder.ReadBool(stable)); + cfg.mServerConfig.mStable = stable; + SuccessOrExit(error = mDecoder.ReadDataWithLen(data, dataLen)); + + VerifyOrExit((dataLen <= sizeof(cfg.mServerConfig.mServerData)), error = OT_ERROR_INVALID_ARGS); + memcpy(cfg.mServerConfig.mServerData, data, dataLen); + + OT_STATIC_ASSERT((sizeof(cfg.mServerConfig.mServerData) <= UINT8_MAX), "Cannot handle full range of buffer length"); + cfg.mServerConfig.mServerDataLength = static_cast(dataLen); + + SuccessOrExit(error = otServerAddService(mInstance, &cfg)); +exit: + return error; +} + +template <> otError NcpBase::HandlePropertyRemove(void) +{ + otError error = OT_ERROR_NONE; + + uint32_t enterpriseNumber; + const uint8_t *serviceData; + uint16_t serviceDataLength; + + VerifyOrExit(mAllowLocalServerDataChange == true, error = OT_ERROR_INVALID_STATE); + + SuccessOrExit(error = mDecoder.ReadUint32(enterpriseNumber)); + SuccessOrExit(error = mDecoder.ReadDataWithLen(serviceData, serviceDataLength)); + + VerifyOrExit(serviceDataLength <= UINT8_MAX, error = OT_ERROR_INVALID_ARGS); + + SuccessOrExit(error = otServerRemoveService(mInstance, enterpriseNumber, serviceData, + static_cast(serviceDataLength))); +exit: + return error; +} + +template <> otError NcpBase::HandlePropertyGet(void) +{ + otError error = OT_ERROR_NONE; + otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT; + otServiceConfig cfg; + + while (otServerGetNextService(mInstance, &iterator, &cfg) == OT_ERROR_NONE) + { + SuccessOrExit(error = mEncoder.OpenStruct()); + + SuccessOrExit(error = mEncoder.WriteUint32(cfg.mEnterpriseNumber)); + SuccessOrExit(error = mEncoder.WriteDataWithLen(cfg.mServiceData, cfg.mServiceDataLength)); + SuccessOrExit(error = mEncoder.WriteBool(cfg.mServerConfig.mStable)); + SuccessOrExit( + error = mEncoder.WriteDataWithLen(cfg.mServerConfig.mServerData, cfg.mServerConfig.mServerDataLength)); + SuccessOrExit(error = mEncoder.WriteUint16(cfg.mServerConfig.mRloc16)); + + SuccessOrExit(error = mEncoder.CloseStruct()); + } +exit: + return error; +} + +template <> otError NcpBase::HandlePropertyGet(void) +{ + otError error = OT_ERROR_NONE; + otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT; + otServiceConfig cfg; + + while (otServerGetNextLeaderService(mInstance, &iterator, &cfg) == OT_ERROR_NONE) + { + SuccessOrExit(error = mEncoder.OpenStruct()); + + SuccessOrExit(error = mEncoder.WriteUint8(cfg.mServiceID)); + SuccessOrExit(error = mEncoder.WriteUint32(cfg.mEnterpriseNumber)); + SuccessOrExit(error = mEncoder.WriteDataWithLen(cfg.mServiceData, cfg.mServiceDataLength)); + SuccessOrExit(error = mEncoder.WriteBool(cfg.mServerConfig.mStable)); + SuccessOrExit( + error = mEncoder.WriteDataWithLen(cfg.mServerConfig.mServerData, cfg.mServerConfig.mServerDataLength)); + SuccessOrExit(error = mEncoder.WriteUint16(cfg.mServerConfig.mRloc16)); + + SuccessOrExit(error = mEncoder.CloseStruct()); + } +exit: + return error; +} + +#endif // OPENTHREAD_ENABLE_SERVICE + template <> otError NcpBase::HandlePropertyGet(void) { return mEncoder.WriteBool(mDiscoveryScanJoinerFlag); diff --git a/src/ncp/spinel.c b/src/ncp/spinel.c index ee0de41d4..2175cbe44 100644 --- a/src/ncp/spinel.c +++ b/src/ncp/spinel.c @@ -1855,6 +1855,18 @@ const char *spinel_prop_key_to_cstr(spinel_prop_key_t prop_key) ret = "SLAAC_ENABLED"; break; + case SPINEL_PROP_SERVER_ALLOW_LOCAL_DATA_CHANGE: + ret = "SERVER_ALLOW_LOCAL_DATA_CHANGE"; + break; + + case SPINEL_PROP_SERVER_SERVICES: + ret = "SERVER_SERVICES"; + break; + + case SPINEL_PROP_SERVER_LEADER_SERVICES: + ret = "SERVER_LEADER_SERVICES"; + break; + case SPINEL_PROP_UART_BITRATE: ret = "UART_BITRATE"; break; @@ -2512,6 +2524,10 @@ const char *spinel_capability_to_cstr(unsigned int capability) ret = "THREAD_BORDER_ROUTER"; break; + case SPINEL_CAP_THREAD_SERVICE: + ret = "THREAD_SERVICE"; + break; + case SPINEL_CAP_NEST_LEGACY_INTERFACE: ret = "NEST_LEGACY_INTERFACE"; break; diff --git a/src/ncp/spinel.h b/src/ncp/spinel.h index e96c014d8..3eed685c4 100644 --- a/src/ncp/spinel.h +++ b/src/ncp/spinel.h @@ -787,6 +787,7 @@ enum SPINEL_CAP_THREAD_UDP_FORWARD = (SPINEL_CAP_THREAD__BEGIN + 2), SPINEL_CAP_THREAD_JOINER = (SPINEL_CAP_THREAD__BEGIN + 3), SPINEL_CAP_THREAD_BORDER_ROUTER = (SPINEL_CAP_THREAD__BEGIN + 4), + SPINEL_CAP_THREAD_SERVICE = (SPINEL_CAP_THREAD__BEGIN + 5), SPINEL_CAP_THREAD__END = 1152, SPINEL_CAP_NEST__BEGIN = 15296, @@ -819,6 +820,7 @@ enum * Stream | 0x070 - 0x07F, 0x1700 - 0x17FF | Stream * MeshCop | 0x080 - 0x08F, 0x1800 - 0x18FF | Thread Mesh Commissioning * OpenThread | 0x1900 - 0x19FF | OpenThread specific + * Server | 0x0A0 - 0x0AF | ALOC Service Server * Interface | 0x100 - 0x1FF | Interface (e.g., UART) * PIB | 0x400 - 0x4FF | 802.15.4 PIB * Counter | 0x500 - 0x7FF | Counters (MAC, IP, etc). @@ -3039,6 +3041,58 @@ typedef enum SPINEL_PROP_OPENTHREAD__END = 0x2000, + SPINEL_PROP_SERVER__BEGIN = 0xA0, + + /// Server Allow Local Network Data Change + /** Format `b` - Read-write + * + * Required capability: SPINEL_CAP_THREAD_SERVICE + * + * Set to true before changing local server net data. Set to false when finished. + * This allows changes to be aggregated into a single event. + * + */ + SPINEL_PROP_SERVER_ALLOW_LOCAL_DATA_CHANGE = SPINEL_PROP_SERVER__BEGIN + 0, + + // Server Services + /** Format: `A(t(LdbdS))` + * + * This property provides all services registered on the device + * + * Required capability: SPINEL_CAP_THREAD_SERVICE + * + * Array of structures containing: + * + * `L`: Enterprise Number + * `d`: Service Data + * `b`: Stable + * `d`: Server Data + * `S`: RLOC + * + */ + SPINEL_PROP_SERVER_SERVICES = SPINEL_PROP_SERVER__BEGIN + 1, + + // Server Leader Services + /** Format: `A(t(CLdbdS))` + * + * This property provides all services registered on the leader + * + * Required capability: SPINEL_CAP_THREAD_SERVICE + * + * Array of structures containing: + * + * `C`: Service ID + * `L`: Enterprise Number + * `d`: Service Data + * `b`: Stable + * `d`: Server Data + * `S`: RLOC + * + */ + SPINEL_PROP_SERVER_LEADER_SERVICES = SPINEL_PROP_SERVER__BEGIN + 2, + + SPINEL_PROP_SERVER__END = 0xB0, + SPINEL_PROP_INTERFACE__BEGIN = 0x100, /// UART Bitrate