From 0509a139e261bd176bde7de780d9372a21694922 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Fri, 4 Nov 2016 08:54:19 -0700 Subject: [PATCH] Add support to ncp for parsing/handling a generic alternate (legacy) network stack. (#920) This commit contains the following: - APIs/typedefs in `ncp.h` to define handlers and callbacks for a generic alternate (legacy) network stack - Support in `NcpBase` for parsing and handling of legacy network related commands/signals - New legacy network related spinel properties - Build feature "enable-legacy" to enable/disable this feature --- configure.ac | 32 +++++ include/ncp/ncp.h | 82 +++++++++++ include/openthread-windows-config.h | 5 +- src/ncp/ncp_base.cpp | 215 +++++++++++++++++++++++++++- src/ncp/ncp_base.hpp | 24 ++++ src/ncp/spinel.h | 11 ++ 6 files changed, 366 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 5246bce93..cb2a866cd 100644 --- a/configure.ac +++ b/configure.ac @@ -563,6 +563,37 @@ AC_SUBST(OPENTHREAD_ENABLE_DIAG) AM_CONDITIONAL([OPENTHREAD_ENABLE_DIAG], [test "${enable_diag}" = "yes"]) AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_DIAG],[${OPENTHREAD_ENABLE_DIAG}],[Define to 1 if you want to use diagnostics module]) +# +# Legacy Network +# + +AC_ARG_ENABLE(legacy, + [AS_HELP_STRING([--enable-legacy],[Enable legacy network support @<:@default=no@:>@.])], + [ + case "${enableval}" in + + no|yes) + enable_legacy=${enableval} + ;; + + *) + AC_MSG_ERROR([Invalid value ${enable_legacy} for --enable-legacy]) + ;; + esac + ], + [enable_legacy=no]) + +if test "$enable_legacy" = "yes"; then + OPENTHREAD_ENABLE_LEGACY=1 +else + OPENTHREAD_ENABLE_LEGACY=0 +fi + +AC_MSG_RESULT(${enable_legacy}) +AC_SUBST(OPENTHREAD_ENABLE_LEGACY) +AM_CONDITIONAL([OPENTHREAD_ENABLE_LEGACY], [test "${enable_legacy}" = "yes"]) +AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_LEGACY],[${OPENTHREAD_ENABLE_LEGACY}],[Define to 1 if you want to use legacy network support]) + # # Cli Logging # @@ -939,6 +970,7 @@ AC_MSG_NOTICE([ OpenThread Joiner support : ${enable_joiner} OpenThread DTLS support : ${enable_dtls} OpenThread Diagnostics support : ${enable_diag} + OpenThread Legacy network support : ${enable_legacy} OpenThread Cli logging support : ${enable_cli_logging} OpenThread Certification log support : ${enable_cert_log} OpenThread DHCPv6 Server support : ${enable_dhcp6_server} diff --git a/include/ncp/ncp.h b/include/ncp/ncp.h index 491416451..1e1e094b7 100644 --- a/include/ncp/ncp.h +++ b/include/ncp/ncp.h @@ -73,6 +73,88 @@ void otNcpInit(otInstance *aInstance); */ ThreadError otNcpStreamWrite(int aStreamId, const uint8_t *aDataPtr, int aDataLen); + +//----------------------------------------------------------------------------------------- +// Legacy network APIs + +#define OT_NCP_LEGACY_ULA_PREFIX_LENGTH 8 ///< Legacy ULA size (in bytes) + +/** + * Defines handler (function pointer) type for starting legacy network + * + * Invoked to start the legacy network. + * + */ +typedef void (*otNcpHandlerStartLegacy)(void); + +/** + * Defines handler (function pointer) type for stopping legacy network + * + * Invoked to stop the legacy network. + * + */ +typedef void (*otNcpHandlerStopLegacy)(void); + +/** + * Defines handler (function pointer) type for initiating joining process. + * + * @param[in] aExtAddress A pointer to the extended address for the node to join + * or NULL if desired to join any neighboring node. + * + * Invoked to initiate a legacy join procedure to any or a specific node. + * + */ +typedef void (*otNcpHandlerJoinLegacyNode)(const otExtAddress *aExtAddress); + +/** + * Defines handler (function pointer) type for setting the legacy ULA prefix. + * + * @param[in] aUlaPrefix A pointer to buffer containing the legacy ULA prefix. + * + * Invoked to set the legacy ULA prefix. + * + */ +typedef void (*otNcpHandlerSetLegacyUlaPrefix)(const uint8_t *aUlaPrefix); + +/** + * Defines a struct containing all the legacy handlers (function pointers). + * + */ +typedef struct otNcpLegacyHandlers +{ + otNcpHandlerStartLegacy mStartLegacy; + otNcpHandlerStopLegacy mStopLegacy; + otNcpHandlerJoinLegacyNode mJoinLegacyNode; + otNcpHandlerSetLegacyUlaPrefix mSetLegacyUlaPrefix; + +} otNcpLegacyHandlers; + +/** + * This callback is invoked by the legacy stack to notify that a new + * legacy node did join the network. + */ +void otNcpHandleLegacyNodeDidJoin(const otExtAddress *aExtAddr); + +/** + * This callback is invoked by the legacy stack to notify that the + * legacy ULA prefix has changed. + */ +void otNcpHandleDidReceiveNewLegacyUlaPrefix(const uint8_t *aUlaPrefix); + +/** + * This method registers a set of legacy handlers with NCP. + * + * The set of handlers provided by the struct @p aHandlers are used by + * NCP code to start/stop legacy network. + * The @p aHandlers can be NULL to disable legacy support on NCP. + * Individual handlers in the given handlers struct can also be NULL. + * + * @param[in] aHandlers A pointer to a handler struct. + * + */ +void otNcpRegisterLegacyHandlers(const otNcpLegacyHandlers *aHandlers); + + #ifdef __cplusplus } // extern "C" #endif diff --git a/include/openthread-windows-config.h b/include/openthread-windows-config.h index a62f89d7e..3fc3e4db2 100644 --- a/include/openthread-windows-config.h +++ b/include/openthread-windows-config.h @@ -32,6 +32,9 @@ /* Define to 1 if you want to use diagnostics module */ #define OPENTHREAD_ENABLE_DIAG 0 +/* Define to 1 if you want to enable legacy network. */ +#define OPENTHREAD_ENABLE_LEGACY 0 + /* Define to 1 to enable dtls support. */ #define OPENTHREAD_ENABLE_DTLS 1 @@ -85,5 +88,5 @@ // Disable a few warnings that we don't care about #pragma warning(disable:4200) // nonstandard extension used: zero-sized array in struct/union #pragma warning(disable:4201) // nonstandard extension used : nameless struct/union -#pragma warning(disable:4291) // no matching operator delete found +#pragma warning(disable:4291) // no matching operator delete found #pragma warning(disable:4815) // zero-sized array in stack object will have no elements diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index 54097df16..862f5bb0c 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -30,6 +30,12 @@ * This file implements a Spinel interface to the OpenThread stack. */ +#ifdef OPENTHREAD_CONFIG_FILE +#include OPENTHREAD_CONFIG_FILE +#else +#include +#endif + #include #include #include @@ -190,6 +196,10 @@ const NcpBase::GetPropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] = { SPINEL_PROP_CNTR_TX_SPINEL_TOTAL, &NcpBase::GetPropertyHandler_NCP_CNTR }, { SPINEL_PROP_CNTR_RX_SPINEL_TOTAL, &NcpBase::GetPropertyHandler_NCP_CNTR }, { SPINEL_PROP_CNTR_RX_SPINEL_ERR, &NcpBase::GetPropertyHandler_NCP_CNTR }, + +#if OPENTHREAD_ENABLE_LEGACY + { SPINEL_PROP_NEST_LEGACY_ULA_PREFIX, &NcpBase::GetPropertyHandler_NEST_LEGACY_ULA_PREFIX }, +#endif }; const NcpBase::SetPropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] = @@ -244,6 +254,10 @@ const NcpBase::SetPropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] = #if OPENTHREAD_ENABLE_DIAG { SPINEL_PROP_NEST_STREAM_MFG, &NcpBase::SetPropertyHandler_NEST_STREAM_MFG }, #endif + +#if OPENTHREAD_ENABLE_LEGACY + { SPINEL_PROP_NEST_LEGACY_ULA_PREFIX, &NcpBase::SetPropertyHandler_NEST_LEGACY_ULA_PREFIX }, +#endif }; const NcpBase::InsertPropertyHandlerEntry NcpBase::mInsertPropertyHandlerTable[] = @@ -450,10 +464,14 @@ NcpBase::NcpBase(otInstance *aInstance): otSetIcmpEchoEnabled(mInstance, false); mUpdateChangedPropsTask.Post(); + +#if OPENTHREAD_ENABLE_LEGACY + mLegacyNodeDidJoin = false; + mLegacyHandlers = NULL; + memset(mLegacyUlaPrefix, 0, sizeof(mLegacyUlaPrefix)); +#endif } - - // ---------------------------------------------------------------------------- // MARK: Outbound Datagram Handling // ---------------------------------------------------------------------------- @@ -756,6 +774,9 @@ void NcpBase::UpdateChangedProps(void) if ( (otGetDeviceRole(mInstance) == kDeviceRoleLeader) && otIsSingleton(mInstance) +#if OPENTHREAD_ENABLE_LEGACY + && !mLegacyNodeDidJoin +#endif ) { mChangedFlags &= ~static_cast(OT_NET_PARTITION_ID); otThreadStop(mInstance); @@ -1419,6 +1440,10 @@ ThreadError NcpBase::GetPropertyHandler_CAPS(uint8_t header, spinel_prop_key_t k SuccessOrExit(errorCode = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_ROLE_ROUTER)); #endif +#if OPENTHREAD_ENABLE_LEGACY + SuccessOrExit(errorCode = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_NEST_LEGACY_INTERFACE)); +#endif + // End adding capabilities ///////////////////////////////////////////////// SuccessOrExit(errorCode = OutboundFrameSend()); @@ -2725,6 +2750,19 @@ ThreadError NcpBase::GetPropertyHandler_NET_REQUIRE_JOIN_EXISTING(uint8_t header ); } +#if OPENTHREAD_ENABLE_LEGACY +ThreadError NcpBase::GetPropertyHandler_NEST_LEGACY_ULA_PREFIX(uint8_t header, spinel_prop_key_t key) +{ + return SendPropertyUpdate( + header, + SPINEL_CMD_PROP_VALUE_IS, + key, + SPINEL_DATATYPE_DATA_S, + mLegacyUlaPrefix, + sizeof(mLegacyUlaPrefix) + ); +} +#endif // OPENTHREAD_ENABLE_LEGACY // ---------------------------------------------------------------------------- // MARK: Individual Property Setters @@ -3171,10 +3209,32 @@ ThreadError NcpBase::SetPropertyHandler_NET_STACK_UP(uint8_t header, spinel_prop if (value != false) { errorCode = otThreadStart(mInstance); + +#if OPENTHREAD_ENABLE_LEGACY + mLegacyNodeDidJoin = false; + if (mLegacyHandlers != NULL) + { + if (mLegacyHandlers->mStartLegacy) + { + mLegacyHandlers->mStartLegacy(); + } + } +#endif // OPENTHREAD_ENABLE_LEGACY } else { errorCode = otThreadStop(mInstance); + +#if OPENTHREAD_ENABLE_LEGACY + mLegacyNodeDidJoin = false; + if (mLegacyHandlers != NULL) + { + if (mLegacyHandlers->mStopLegacy) + { + mLegacyHandlers->mStopLegacy(); + } + } +#endif // OPENTHREAD_ENABLE_LEGACY } } } @@ -4266,6 +4326,47 @@ ThreadError NcpBase::SetPropertyHandler_NEST_STREAM_MFG(uint8_t header, spinel_p } #endif +#if OPENTHREAD_ENABLE_LEGACY +ThreadError NcpBase::SetPropertyHandler_NEST_LEGACY_ULA_PREFIX(uint8_t header, spinel_prop_key_t key, + const uint8_t *value_ptr, uint16_t value_len) +{ + ThreadError errorCode = kThreadError_None; + const uint8_t *ptr = NULL; + spinel_size_t len; + spinel_ssize_t parsedLength; + + parsedLength = spinel_datatype_unpack( + value_ptr, + value_len, + SPINEL_DATATYPE_DATA_S, + &ptr, + &len + ); + + if ((parsedLength > 0) && (len <= sizeof(mLegacyUlaPrefix))) + { + memset(mLegacyUlaPrefix, 0, sizeof(mLegacyUlaPrefix)); + memcpy(mLegacyUlaPrefix, ptr, len); + + if (mLegacyHandlers) + { + if (mLegacyHandlers->mSetLegacyUlaPrefix) + { + mLegacyHandlers->mSetLegacyUlaPrefix(mLegacyUlaPrefix); + } + } + + errorCode = HandleCommandPropertyGet(header, key); + } + else + { + errorCode = SendLastStatus(header, SPINEL_STATUS_PARSE_ERROR); + } + + return errorCode; +} +#endif // OPENTHREAD_ENABLE_LEGACY + // ---------------------------------------------------------------------------- // MARK: Individual Property Inserters // ---------------------------------------------------------------------------- @@ -4830,6 +4931,85 @@ ThreadError NcpBase::RemovePropertyHandler_MAC_WHITELIST(uint8_t header, spinel_ return errorCode; } +#if OPENTHREAD_ENABLE_LEGACY + +void NcpBase::RegisterLegacyHandlers(const otNcpLegacyHandlers *aHandlers) +{ + mLegacyHandlers = aHandlers; + bool isEnabled; + + VerifyOrExit(mLegacyHandlers != NULL, ;); + + isEnabled = (otGetDeviceRole(mInstance) != kDeviceRoleDisabled); + + if (isEnabled) + { + if (mLegacyHandlers->mStartLegacy) + { + mLegacyHandlers->mStartLegacy(); + } + } + else + { + if (mLegacyHandlers->mStopLegacy) + { + mLegacyHandlers->mStopLegacy(); + } + } + + if (mLegacyHandlers->mSetLegacyUlaPrefix) + { + mLegacyHandlers->mSetLegacyUlaPrefix(mLegacyUlaPrefix); + } + +exit: + return; +} + +void NcpBase::HandleDidReceiveNewLegacyUlaPrefix(const uint8_t *aUlaPrefix) +{ + memcpy(mLegacyUlaPrefix, aUlaPrefix, OT_NCP_LEGACY_ULA_PREFIX_LENGTH); + + SuccessOrExit(OutboundFrameBegin()); + + SuccessOrExit( + OutboundFrameFeedPacked( + "Cii" SPINEL_DATATYPE_DATA_S, + SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, + SPINEL_CMD_PROP_VALUE_IS, + SPINEL_PROP_NEST_LEGACY_ULA_PREFIX, + aUlaPrefix, OT_NCP_LEGACY_ULA_PREFIX_LENGTH + )); + + OutboundFrameSend(); + +exit: + return; +} + +void NcpBase::HandleLegacyNodeDidJoin(const otExtAddress *aExtAddr) +{ + mLegacyNodeDidJoin = true; + + SuccessOrExit(OutboundFrameBegin()); + + SuccessOrExit( + OutboundFrameFeedPacked( + "Cii" SPINEL_DATATYPE_EUI64_S, + SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, + SPINEL_CMD_PROP_VALUE_IS, + SPINEL_PROP_NEST_LEGACY_JOINED_NODE, + aExtAddr->m8 + )); + + OutboundFrameSend(); + +exit: + return; +} + +#endif // OPENTHREAD_ENABLE_LEGACY + } // namespace Thread @@ -4852,3 +5032,34 @@ ThreadError otNcpStreamWrite(int aStreamId, const uint8_t* aDataPtr, int aDataLe static_cast(aDataLen) ); } + +// ---------------------------------------------------------------------------- +// MARK: Legacy network APIs +// ---------------------------------------------------------------------------- + +void otNcpRegisterLegacyHandlers(const otNcpLegacyHandlers *aHandlers) +{ +#if OPENTHREAD_ENABLE_LEGACY + Thread::sNcpContext->RegisterLegacyHandlers(aHandlers); +#else + (void)aHandlers; +#endif +} + +void otNcpHandleDidReceiveNewLegacyUlaPrefix(const uint8_t *aUlaPrefix) +{ +#if OPENTHREAD_ENABLE_LEGACY + Thread::sNcpContext->HandleDidReceiveNewLegacyUlaPrefix(aUlaPrefix); +#else + (void)aUlaPrefix; +#endif +} + +void otNcpHandleLegacyNodeDidJoin(const otExtAddress *aExtAddr) +{ +#if OPENTHREAD_ENABLE_LEGACY + Thread::sNcpContext->HandleLegacyNodeDidJoin(aExtAddr); +#else + (void)aExtAddr; +#endif +} diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index 935fb18fe..d125c5f6d 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -42,6 +42,7 @@ #include #include #include +#include #include "spinel.h" @@ -344,6 +345,10 @@ private: ThreadError GetPropertyHandler_THREAD_ON_MESH_NETS(uint8_t header, spinel_prop_key_t key); ThreadError GetPropertyHandler_NET_REQUIRE_JOIN_EXISTING(uint8_t header, spinel_prop_key_t key); +#if OPENTHREAD_ENABLE_LEGACY + ThreadError GetPropertyHandler_NEST_LEGACY_ULA_PREFIX(uint8_t header, spinel_prop_key_t key); +#endif + ThreadError SetPropertyHandler_POWER_STATE(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len); ThreadError SetPropertyHandler_PHY_TX_POWER(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, @@ -421,6 +426,11 @@ private: uint16_t value_len); #endif +#if OPENTHREAD_ENABLE_LEGACY + ThreadError SetPropertyHandler_NEST_LEGACY_ULA_PREFIX(uint8_t header, spinel_prop_key_t key, + const uint8_t *value_ptr, uint16_t value_len); +#endif + ThreadError InsertPropertyHandler_IPV6_ADDRESS_TABLE(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len); ThreadError InsertPropertyHandler_THREAD_LOCAL_ROUTES(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, @@ -445,6 +455,13 @@ private: ThreadError RemovePropertyHandler_THREAD_ACTIVE_ROUTER_IDS(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len); +#if OPENTHREAD_ENABLE_LEGACY +public: + void HandleLegacyNodeDidJoin(const otExtAddress *aExtAddr); + void HandleDidReceiveNewLegacyUlaPrefix(const uint8_t *aUlaPrefix); + void RegisterLegacyHandlers(const otNcpLegacyHandlers *aHandlers); +#endif + private: spinel_status_t mLastStatus; @@ -478,6 +495,13 @@ private: uint32_t mOutboundInsecureIpFrameCounter; // Number of insecure outbound data/IP frames. uint32_t mDroppedOutboundIpFrameCounter; // Number of dropped outbound data/IP frames. uint32_t mDroppedInboundIpFrameCounter; // Number of dropped inbound data/IP frames. + +#if OPENTHREAD_ENABLE_LEGACY + const otNcpLegacyHandlers *mLegacyHandlers; + uint8_t mLegacyUlaPrefix[OT_NCP_LEGACY_ULA_PREFIX_LENGTH]; + bool mLegacyNodeDidJoin; +#endif + }; } // namespace Thread diff --git a/src/ncp/spinel.h b/src/ncp/spinel.h index fa515d020..3aefbd0f4 100644 --- a/src/ncp/spinel.h +++ b/src/ncp/spinel.h @@ -827,6 +827,17 @@ typedef enum SPINEL_PROP_NEST__BEGIN = 15296, SPINEL_PROP_NEST_STREAM_MFG = SPINEL_PROP_NEST__BEGIN + 0, + + /// The legacy network ULA prefix (8 bytes) + /** Format: 'D' */ + SPINEL_PROP_NEST_LEGACY_ULA_PREFIX + = SPINEL_PROP_NEST__BEGIN + 1, + + /// A (newly) joined legacy node (this is signaled from NCP) + /** Format: 'E' */ + SPINEL_PROP_NEST_LEGACY_JOINED_NODE + = SPINEL_PROP_NEST__BEGIN + 2, + SPINEL_PROP_NEST__END = 15360, SPINEL_PROP_VENDOR__BEGIN = 15360,