diff --git a/etc/visual-studio/libopenthread-ncp-spi.vcxproj b/etc/visual-studio/libopenthread-ncp-spi.vcxproj index d7adc3a5e..ae0b5f21d 100644 --- a/etc/visual-studio/libopenthread-ncp-spi.vcxproj +++ b/etc/visual-studio/libopenthread-ncp-spi.vcxproj @@ -66,6 +66,7 @@ + @@ -74,6 +75,7 @@ + diff --git a/etc/visual-studio/libopenthread-ncp-spi.vcxproj.filters b/etc/visual-studio/libopenthread-ncp-spi.vcxproj.filters index ad6f0f90b..5b94a7cdb 100644 --- a/etc/visual-studio/libopenthread-ncp-spi.vcxproj.filters +++ b/etc/visual-studio/libopenthread-ncp-spi.vcxproj.filters @@ -36,6 +36,9 @@ Source Files + + Source Files + Source Files @@ -59,6 +62,9 @@ Header Files + + Header Files + Header Files diff --git a/etc/visual-studio/libopenthread-ncp-uart.vcxproj b/etc/visual-studio/libopenthread-ncp-uart.vcxproj index 3e996c4cb..cfa765854 100644 --- a/etc/visual-studio/libopenthread-ncp-uart.vcxproj +++ b/etc/visual-studio/libopenthread-ncp-uart.vcxproj @@ -67,6 +67,7 @@ + @@ -76,6 +77,7 @@ + diff --git a/etc/visual-studio/libopenthread-ncp-uart.vcxproj.filters b/etc/visual-studio/libopenthread-ncp-uart.vcxproj.filters index 16df2e80e..544d4c8ea 100644 --- a/etc/visual-studio/libopenthread-ncp-uart.vcxproj.filters +++ b/etc/visual-studio/libopenthread-ncp-uart.vcxproj.filters @@ -42,6 +42,9 @@ Source Files + + Source Files + Source Files @@ -65,6 +68,9 @@ Header Files + + Header Files + Header Files diff --git a/include/openthread/thread_ftd.h b/include/openthread/thread_ftd.h index 4ed933b90..7aecdee6e 100644 --- a/include/openthread/thread_ftd.h +++ b/include/openthread/thread_ftd.h @@ -195,7 +195,7 @@ OTAPI otError OTCALL otThreadSetJoinerUdpPort(otInstance *aInstance, uint16_t aJ * @retval OT_ERROR_DISABLED_FEATURE Feature is disabled, not capable of setting steering data out of band. * */ -otError otThreadSetSteeringData(otInstance *aInstance, otExtAddress *aExtAddress); +otError otThreadSetSteeringData(otInstance *aInstance, const otExtAddress *aExtAddress); /** * Get the CONTEXT_ID_REUSE_DELAY parameter used in the Leader role. diff --git a/src/core/api/thread_ftd_api.cpp b/src/core/api/thread_ftd_api.cpp index 967304f3e..7e75026b3 100644 --- a/src/core/api/thread_ftd_api.cpp +++ b/src/core/api/thread_ftd_api.cpp @@ -237,7 +237,7 @@ exit: return error; } -otError otThreadSetSteeringData(otInstance *aInstance, otExtAddress *aExtAddress) +otError otThreadSetSteeringData(otInstance *aInstance, const otExtAddress *aExtAddress) { otError error; diff --git a/src/core/meshcop/meshcop_tlvs.cpp b/src/core/meshcop/meshcop_tlvs.cpp index bd5d15ecc..dcec31fe3 100644 --- a/src/core/meshcop/meshcop_tlvs.cpp +++ b/src/core/meshcop/meshcop_tlvs.cpp @@ -52,7 +52,7 @@ bool SteeringDataTlv::IsCleared(void) const return rval; } -void SteeringDataTlv::ComputeBloomFilter(otExtAddress *aExtAddress) +void SteeringDataTlv::ComputeBloomFilter(const otExtAddress *aExtAddress) { Crc16 ccitt(Crc16::kCcitt); Crc16 ansi(Crc16::kAnsi); diff --git a/src/core/meshcop/meshcop_tlvs.hpp b/src/core/meshcop/meshcop_tlvs.hpp index 663d76867..79f042148 100644 --- a/src/core/meshcop/meshcop_tlvs.hpp +++ b/src/core/meshcop/meshcop_tlvs.hpp @@ -646,7 +646,7 @@ public: * @param[in] aExtAddress Extended address * */ - void ComputeBloomFilter(otExtAddress *aExtAddress); + void ComputeBloomFilter(const otExtAddress *aExtAddress); private: uint8_t mSteeringData[OT_STEERING_DATA_MAX_LENGTH]; diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 6472e276e..e3ff118b7 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -2636,7 +2636,7 @@ exit: } #if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB -otError MleRouter::SetSteeringData(otExtAddress *aExtAddress) +otError MleRouter::SetSteeringData(const otExtAddress *aExtAddress) { otError error = OT_ERROR_NONE; uint8_t nullExtAddr[OT_EXT_ADDRESS_SIZE]; diff --git a/src/core/thread/mle_router_ftd.hpp b/src/core/thread/mle_router_ftd.hpp index a120e9b58..c58bd937b 100644 --- a/src/core/thread/mle_router_ftd.hpp +++ b/src/core/thread/mle_router_ftd.hpp @@ -670,7 +670,7 @@ public: * @retval OT_ERROR_NONE Steering data was set * */ - otError SetSteeringData(otExtAddress *aExtAddress); + otError SetSteeringData(const otExtAddress *aExtAddress); #endif // OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB /** diff --git a/src/core/thread/mle_router_mtd.hpp b/src/core/thread/mle_router_mtd.hpp index 2dd9a1cb8..7952717e3 100644 --- a/src/core/thread/mle_router_mtd.hpp +++ b/src/core/thread/mle_router_mtd.hpp @@ -127,7 +127,7 @@ public: otError SendChildUpdateRequest(void) { return Mle::SendChildUpdateRequest(); } #if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB - otError SetSteeringData(otExtAddress *) { return OT_ERROR_NOT_IMPLEMENTED; } + otError SetSteeringData(const otExtAddress *) { return OT_ERROR_NOT_IMPLEMENTED; } #endif // OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB otError GetMaxChildTimeout(uint32_t &) { return OT_ERROR_NOT_IMPLEMENTED; } diff --git a/src/ncp/Makefile.am b/src/ncp/Makefile.am index c9e2e6c78..cc77f1e2c 100644 --- a/src/ncp/Makefile.am +++ b/src/ncp/Makefile.am @@ -71,6 +71,8 @@ COMMON_SOURCES = \ ncp_buffer.hpp \ spinel.c \ spinel.h \ + spinel_decoder.hpp \ + spinel_decoder.cpp \ spinel_encoder.hpp \ spinel_encoder.cpp \ spinel_platform.h \ diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index 531e29340..768dc82c8 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -55,36 +55,13 @@ namespace ot { namespace Ncp { - // ---------------------------------------------------------------------------- -// MARK: Command/Property Jump Tables +// MARK: Property Handler Jump Tables and Methods // ---------------------------------------------------------------------------- -#define NCP_CMD_HANDLER_ENTRY(name) { SPINEL_CMD_##name, &NcpBase::CommandHandler_##name } - -const NcpBase::CommandHandlerEntry NcpBase::mCommandHandlerTable[] = -{ - NCP_CMD_HANDLER_ENTRY(NOOP), - NCP_CMD_HANDLER_ENTRY(RESET), - NCP_CMD_HANDLER_ENTRY(PROP_VALUE_GET), - NCP_CMD_HANDLER_ENTRY(PROP_VALUE_SET), - NCP_CMD_HANDLER_ENTRY(PROP_VALUE_INSERT), - NCP_CMD_HANDLER_ENTRY(PROP_VALUE_REMOVE), -#if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE - NCP_CMD_HANDLER_ENTRY(PEEK), - NCP_CMD_HANDLER_ENTRY(POKE), -#endif -#if OPENTHREAD_MTD || OPENTHREAD_FTD - NCP_CMD_HANDLER_ENTRY(NET_SAVE), - NCP_CMD_HANDLER_ENTRY(NET_CLEAR), - NCP_CMD_HANDLER_ENTRY(NET_RECALL), -#endif -}; - #define NCP_GET_PROP_HANDLER_ENTRY(name) { SPINEL_PROP_##name, &NcpBase::GetPropertyHandler_##name } -#define NCP_GET_PROP_HANDLER_ENTRY_METHOD(name, method) { SPINEL_PROP_##name, &NcpBase::GetPropertyHandler_##method } -const NcpBase::GetPropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] = +const NcpBase::PropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] = { NCP_GET_PROP_HANDLER_ENTRY(CAPS), NCP_GET_PROP_HANDLER_ENTRY(DEBUG_TEST_ASSERT), @@ -180,7 +157,6 @@ const NcpBase::GetPropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] = NCP_GET_PROP_HANDLER_ENTRY(NEST_LEGACY_ULA_PREFIX), NCP_GET_PROP_HANDLER_ENTRY(NEST_LEGACY_LAST_NODE_JOINED), #endif - NCP_GET_PROP_HANDLER_ENTRY(STREAM_NET), // MAC counters NCP_GET_PROP_HANDLER_ENTRY(CNTR_TX_PKT_TOTAL), NCP_GET_PROP_HANDLER_ENTRY(CNTR_TX_PKT_ACK_REQ), @@ -253,10 +229,9 @@ const NcpBase::GetPropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] = #define NCP_SET_PROP_HANDLER_ENTRY(name) { SPINEL_PROP_##name, &NcpBase::SetPropertyHandler_##name } -const NcpBase::SetPropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] = +const NcpBase::PropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] = { NCP_SET_PROP_HANDLER_ENTRY(POWER_STATE), - NCP_SET_PROP_HANDLER_ENTRY(HOST_POWER_STATE), NCP_SET_PROP_HANDLER_ENTRY(UNSOL_UPDATE_FILTER), NCP_SET_PROP_HANDLER_ENTRY(PHY_TX_POWER), NCP_SET_PROP_HANDLER_ENTRY(PHY_CHAN), @@ -270,7 +245,6 @@ const NcpBase::SetPropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] = NCP_SET_PROP_HANDLER_ENTRY(MAC_SRC_MATCH_SHORT_ADDRESSES), NCP_SET_PROP_HANDLER_ENTRY(MAC_SRC_MATCH_EXTENDED_ADDRESSES), NCP_SET_PROP_HANDLER_ENTRY(PHY_ENABLED), - NCP_SET_PROP_HANDLER_ENTRY(STREAM_RAW), #endif // OPENTHREAD_ENABLE_RAW_LINK_API #if OPENTHREAD_MTD || OPENTHREAD_FTD NCP_SET_PROP_HANDLER_ENTRY(MAC_DATA_POLL_PERIOD), @@ -313,9 +287,6 @@ const NcpBase::SetPropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] = NCP_SET_PROP_HANDLER_ENTRY(JAM_DETECT_WINDOW), NCP_SET_PROP_HANDLER_ENTRY(JAM_DETECT_BUSY), #endif -#if OPENTHREAD_ENABLE_DIAG - NCP_SET_PROP_HANDLER_ENTRY(NEST_STREAM_MFG), -#endif #if OPENTHREAD_ENABLE_LEGACY NCP_SET_PROP_HANDLER_ENTRY(NEST_LEGACY_ULA_PREFIX), #endif @@ -336,9 +307,6 @@ const NcpBase::SetPropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] = #if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB NCP_SET_PROP_HANDLER_ENTRY(THREAD_STEERING_DATA), #endif -#if OPENTHREAD_ENABLE_COMMISSIONER - NCP_SET_PROP_HANDLER_ENTRY(THREAD_COMMISSIONER_ENABLED), -#endif #if OPENTHREAD_ENABLE_TMF_PROXY NCP_SET_PROP_HANDLER_ENTRY(THREAD_TMF_PROXY_ENABLED), NCP_SET_PROP_HANDLER_ENTRY(THREAD_TMF_PROXY_STREAM), @@ -348,7 +316,7 @@ const NcpBase::SetPropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] = #define NCP_INSERT_PROP_HANDLER_ENTRY(name) { SPINEL_PROP_##name, &NcpBase::InsertPropertyHandler_##name } -const NcpBase::InsertPropertyHandlerEntry NcpBase::mInsertPropertyHandlerTable[] = +const NcpBase::PropertyHandlerEntry NcpBase::mInsertPropertyHandlerTable[] = { NCP_INSERT_PROP_HANDLER_ENTRY(UNSOL_UPDATE_FILTER), #if OPENTHREAD_ENABLE_RAW_LINK_API @@ -378,7 +346,7 @@ const NcpBase::InsertPropertyHandlerEntry NcpBase::mInsertPropertyHandlerTable[] #define NCP_REMOVE_PROP_HANDLER_ENTRY(name) { SPINEL_PROP_##name, &NcpBase::RemovePropertyHandler_##name } -const NcpBase::RemovePropertyHandlerEntry NcpBase::mRemovePropertyHandlerTable[] = +const NcpBase::PropertyHandlerEntry NcpBase::mRemovePropertyHandlerTable[] = { NCP_REMOVE_PROP_HANDLER_ENTRY(UNSOL_UPDATE_FILTER), #if OPENTHREAD_ENABLE_RAW_LINK_API @@ -535,6 +503,7 @@ NcpBase::NcpBase(otInstance *aInstance): mInstance(aInstance), mTxFrameBuffer(mTxBuffer, sizeof(mTxBuffer)), mEncoder(mTxFrameBuffer), + mDecoder(), mHostPowerStateInProgress(false), mLastStatus(SPINEL_STATUS_OK), mSupportedChannelMask(OT_RADIO_SUPPORTED_CHANNELS), @@ -617,48 +586,42 @@ NcpFrameBuffer::FrameTag NcpBase::GetLastOutboundFrameTag(void) void NcpBase::HandleReceive(const uint8_t *aBuf, uint16_t aBufLength) { + otError parseError = OT_ERROR_NONE; + otError responseError = OT_ERROR_NONE; uint8_t header = 0; unsigned int command = 0; - spinel_ssize_t parsedLength; - const uint8_t *argPtr = NULL; - unsigned int argLen = 0; - otError error = OT_ERROR_NONE; spinel_tid_t tid = 0; - parsedLength = spinel_datatype_unpack( - aBuf, - aBufLength, - SPINEL_DATATYPE_COMMAND_S SPINEL_DATATYPE_DATA_S, - &header, - &command, - &argPtr, - &argLen - ); - - tid = SPINEL_HEADER_GET_TID(header); + // Initialize the decoder with the newly received spinel frame. + mDecoder.Init(aBuf, aBufLength); // Receiving any message from the host has the side effect of transitioning the host power state to online. mHostPowerState = SPINEL_HOST_POWER_STATE_ONLINE; mHostPowerStateInProgress = false; - if (parsedLength == aBufLength) - { - error = HandleCommand(header, command, argPtr, static_cast(argLen)); + SuccessOrExit(parseError = mDecoder.ReadUint8(header)); + SuccessOrExit(parseError = mDecoder.ReadUintPacked(command)); - // Check if we may have missed a `tid` in the sequence. - if ((mNextExpectedTid != 0) && (tid != mNextExpectedTid)) - { - mRxSpinelOutOfOrderTidCounter++; - } + responseError = HandleCommand(header, command); - mNextExpectedTid = SPINEL_GET_NEXT_TID(tid); - } - else + tid = SPINEL_HEADER_GET_TID(header); + + // Check if we may have missed a `tid` in the sequence. + if ((mNextExpectedTid != 0) && (tid != mNextExpectedTid)) { - error = SendLastStatus(header, SPINEL_STATUS_PARSE_ERROR); + mRxSpinelOutOfOrderTidCounter++; } - if (error == OT_ERROR_NO_BUFS) + mNextExpectedTid = SPINEL_GET_NEXT_TID(tid); + +exit: + + if (parseError != OT_ERROR_NONE) + { + responseError = SendLastStatus(header, SPINEL_STATUS_PARSE_ERROR); + } + + if (responseError == OT_ERROR_NO_BUFS) { // If we cannot send a response due to buffer space not being // available, we remember the TID of command so to send an @@ -921,179 +884,310 @@ exit: } // ---------------------------------------------------------------------------- -// MARK: Inbound Command Handlers +// MARK: Inbound Command Handler // ---------------------------------------------------------------------------- -otError NcpBase::HandleCommand(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, uint16_t aArgLen) +otError NcpBase::HandleCommand(uint8_t aHeader, unsigned int aCommand) { - unsigned i; otError error = OT_ERROR_NONE; // Skip if this isn't a spinel frame VerifyOrExit((SPINEL_HEADER_FLAG & aHeader) == SPINEL_HEADER_FLAG, error = OT_ERROR_INVALID_ARGS); + mDisableStreamWrite = true; + // We only support IID zero for now. - VerifyOrExit( - SPINEL_HEADER_GET_IID(aHeader) == 0, - error = SendLastStatus(aHeader, SPINEL_STATUS_INVALID_INTERFACE) - ); + VerifyOrExit(SPINEL_HEADER_GET_IID(aHeader) == 0, error = SendLastStatus(aHeader, SPINEL_STATUS_INVALID_INTERFACE)); + + switch (aCommand) + { + case SPINEL_CMD_NOOP: + error = CommandHandler_NOOP(aHeader); + break; + + case SPINEL_CMD_RESET: + error = CommandHandler_RESET(aHeader); + break; + + case SPINEL_CMD_PROP_VALUE_GET: + case SPINEL_CMD_PROP_VALUE_SET: + case SPINEL_CMD_PROP_VALUE_INSERT: + case SPINEL_CMD_PROP_VALUE_REMOVE: + error = CommandHandler_PROP_VALUE_update(aHeader, aCommand); + break; + +#if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE + case SPINEL_CMD_PEEK: + error = CommandHandler_PEEK(aHeader); + break; + + case SPINEL_CMD_POKE: + error = CommandHandler_POKE(aHeader); + break; +#endif + +#if OPENTHREAD_MTD || OPENTHREAD_FTD + case SPINEL_CMD_NET_SAVE: + error = CommandHandler_NET_SAVE(aHeader); + break; + + case SPINEL_CMD_NET_CLEAR: + error = CommandHandler_NET_CLEAR(aHeader); + break; + + case SPINEL_CMD_NET_RECALL: + error = CommandHandler_NET_RECALL(aHeader); + break; +#endif // OPENTHREAD_MTD || OPENTHREAD_FTD + + default: + #if OPENTHREAD_ENABLE_SPINEL_VENDOR_SUPPORT - if (aCommand >= SPINEL_CMD_VENDOR__BEGIN && aCommand < SPINEL_CMD_VENDOR__END) - { - error = VendorCommandHandler(aHeader, aCommand, aArgPtr, aArgLen); - } - else -#endif // OPENTHREAD_ENABLE_SPINEL_VENDOR_SUPPORT - { - for (i = 0; i < sizeof(mCommandHandlerTable) / sizeof(mCommandHandlerTable[0]); i++) + if (aCommand >= SPINEL_CMD_VENDOR__BEGIN && aCommand < SPINEL_CMD_VENDOR__END) { - if (mCommandHandlerTable[i].mCommand == aCommand) - { - break; - } - } - - if (i < sizeof(mCommandHandlerTable) / sizeof(mCommandHandlerTable[0])) - { - error = (this->*mCommandHandlerTable[i].mHandler)(aHeader, aCommand, aArgPtr, aArgLen); - } - else - { - error = SendLastStatus(aHeader, SPINEL_STATUS_INVALID_COMMAND); - } - } - -exit: - return error; -} - -otError NcpBase::HandleCommandPropertyGet(uint8_t aHeader, spinel_prop_key_t aKey) -{ - unsigned i; - bool found = false; - otError error = OT_ERROR_NONE; - - for (i = 0; i < sizeof(mGetPropertyHandlerTable) / sizeof(mGetPropertyHandlerTable[0]); i++) - { - if (mGetPropertyHandlerTable[i].mPropKey == aKey) - { - found = true; + error = VendorCommandHandler(aHeader, aCommand); break; } - } +#endif - mDisableStreamWrite = true; - SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey)); - - if (found) - { - SuccessOrExit(error = (this->*mGetPropertyHandlerTable[i].mHandler)()); + error = SendLastStatus(aHeader, SPINEL_STATUS_INVALID_COMMAND); + break; } - else - { - SuccessOrExit(error = mEncoder.OverwriteWithLastStatusError(SPINEL_STATUS_PROP_NOT_FOUND)); - } - - SuccessOrExit(error = mEncoder.EndFrame()); exit: mDisableStreamWrite = false; return error; } -otError NcpBase::HandleCommandPropertySet(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) -{ - unsigned i; - otError error = OT_ERROR_NONE; +// ---------------------------------------------------------------------------- +// MARK: Property Get/Set/Insert/Remove Commands +// ---------------------------------------------------------------------------- - for (i = 0; i < sizeof(mSetPropertyHandlerTable) / sizeof(mSetPropertyHandlerTable[0]); i++) +NcpBase::PropertyHandler NcpBase::FindPropertyHandler(spinel_prop_key_t aKey, const PropertyHandlerEntry *aTableEntry, + size_t aTableLen) +{ + PropertyHandler handler = NULL; + + while (aTableLen--) { - if (mSetPropertyHandlerTable[i].mPropKey == aKey) + if (aTableEntry->mPropKey == aKey) { + handler = aTableEntry->mHandler; break; } + + aTableEntry++; } - if (i < sizeof(mSetPropertyHandlerTable) / sizeof(mSetPropertyHandlerTable[0])) - { - error = (this->*mSetPropertyHandlerTable[i].mHandler)(aHeader, aKey, aValuePtr, aValueLen); - } - else - { - error = SendLastStatus(aHeader, SPINEL_STATUS_PROP_NOT_FOUND); - } + return handler; +} +NcpBase::PropertyHandler NcpBase::FindGetPropertyHandler(spinel_prop_key_t aKey) +{ + return FindPropertyHandler( + aKey, + mGetPropertyHandlerTable, + sizeof(mGetPropertyHandlerTable) / sizeof(mGetPropertyHandlerTable[0]) + ); + +} + +NcpBase::PropertyHandler NcpBase::FindSetPropertyHandler(spinel_prop_key_t aKey) +{ + return FindPropertyHandler( + aKey, + mSetPropertyHandlerTable, + sizeof(mSetPropertyHandlerTable) / sizeof(mSetPropertyHandlerTable[0]) + ); +} + +NcpBase::PropertyHandler NcpBase::FindInsertPropertyHandler(spinel_prop_key_t aKey) +{ + return FindPropertyHandler( + aKey, + mInsertPropertyHandlerTable, + sizeof(mInsertPropertyHandlerTable) / sizeof(mInsertPropertyHandlerTable[0]) + ); +} + +NcpBase::PropertyHandler NcpBase::FindRemovePropertyHandler(spinel_prop_key_t aKey) +{ + return FindPropertyHandler( + aKey, + mRemovePropertyHandlerTable, + sizeof(mRemovePropertyHandlerTable) / sizeof(mRemovePropertyHandlerTable[0]) + ); +} + +otError NcpBase::HandleCommandPropertyGet(uint8_t aHeader, spinel_prop_key_t aKey) +{ + otError error = OT_ERROR_NONE; + PropertyHandler handler = FindGetPropertyHandler(aKey); + + VerifyOrExit(handler != NULL, error = SendLastStatus(aHeader, SPINEL_STATUS_PROP_NOT_FOUND)); + + SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey)); + SuccessOrExit(error = (this->*handler)()); + SuccessOrExit(error = mEncoder.EndFrame()); + +exit: return error; } -otError NcpBase::HandleCommandPropertyInsert(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +// Returns `true` and updates the `aError` on success. +bool NcpBase::HandlePropertySetForSpecialProperties(uint8_t aHeader, spinel_prop_key_t aKey, otError &aError) +{ + bool didHandle = true; + + // Here the properties that require special treatment are handled. + // These properties are expected to form the response from their + // set handler directly. + + switch (aKey) + { + case SPINEL_PROP_HOST_POWER_STATE: + ExitNow(aError = SetPropertyHandler_HOST_POWER_STATE(aHeader)); + +#if OPENTHREAD_ENABLE_DIAG + case SPINEL_PROP_NEST_STREAM_MFG: + ExitNow(aError = SetPropertyHandler_NEST_STREAM_MFG(aHeader)); +#endif + +#if OPENTHREAD_FTD && OPENTHREAD_ENABLE_COMMISSIONER + case SPINEL_PROP_THREAD_COMMISSIONER_ENABLED: + ExitNow(aError = SetPropertyHandler_THREAD_COMMISSIONER_ENABLED(aHeader)); +#endif + +#if OPENTHREAD_ENABLE_RAW_LINK_API + case SPINEL_PROP_STREAM_RAW: + ExitNow(aError = SetPropertyHandler_STREAM_RAW(aHeader)); +#endif + + default: + didHandle = false; + break; + } + +exit: + return didHandle; +} + +otError NcpBase::HandleCommandPropertySet(uint8_t aHeader, spinel_prop_key_t aKey) { - unsigned i; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_PROP_NOT_FOUND; + PropertyHandler handler = FindSetPropertyHandler(aKey); + const uint8_t *valuePtr; + uint16_t valueLen; - for (i = 0; i < sizeof(mInsertPropertyHandlerTable) / sizeof(mInsertPropertyHandlerTable[0]); i++) + if (handler == NULL) { - if (mInsertPropertyHandlerTable[i].mPropKey == aKey) - { - break; - } + // If there is no "set" handler, check if this property is one of the + // ones that require different treatment. + + bool didHandle = HandlePropertySetForSpecialProperties(aHeader, aKey, error); + + VerifyOrExit(!didHandle); + + ExitNow(error = SendLastStatus(aHeader, SPINEL_STATUS_PROP_NOT_FOUND)); } - if (i < sizeof(mInsertPropertyHandlerTable) / sizeof(mInsertPropertyHandlerTable[0])) - { - spinelError = ThreadErrorToSpinelStatus( - (this->*mInsertPropertyHandlerTable[i].mHandler)(aValuePtr, aValueLen)); - } + // Save current read position in the decoder. Read the entire + // content as a data blob (which can be used in forming the response + // if there is no associated get handler), then reset the read + // position back so that the handler method can parse the + // content. - if (spinelError == SPINEL_STATUS_OK) + mDecoder.SavePosition(); + mDecoder.ReadData(valuePtr, valueLen); + mDecoder.ResetToSaved(); + + error = (this->*handler)(); + + VerifyOrExit(error == OT_ERROR_NONE, error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error))); + + // Prepare the response. + + if ((handler = FindGetPropertyHandler(aKey)) != NULL) { - SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_INSERTED, aKey)); - SuccessOrExit(error = mEncoder.WriteData(aValuePtr, aValueLen)); + SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey)); + SuccessOrExit(error = (this->*handler)()); SuccessOrExit(error = mEncoder.EndFrame()); } else { - SuccessOrExit(error = SendLastStatus(aHeader, spinelError)); + if ((aKey == SPINEL_PROP_STREAM_NET) || (aKey == SPINEL_PROP_STREAM_NET_INSECURE) +#if OPENTHREAD_FTD && OPENTHREAD_ENABLE_TMF_PROXY + || (aKey == SPINEL_PROP_THREAD_TMF_PROXY_STREAM) +#endif + ) + { + // Only send a successful status for `STREAM` properties + // if the transaction id (TID) is non-zero. + + if (SPINEL_HEADER_GET_TID(aHeader) != 0) + { + error = SendLastStatus(aHeader, SPINEL_STATUS_OK); + } + + ExitNow(); + } + + // If there is no get handler for this property, echo the same + // value from input frame in the response. + + SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey)); + SuccessOrExit(error = mEncoder.WriteData(valuePtr, valueLen)); + SuccessOrExit(error = mEncoder.EndFrame()); } exit: return error; } -otError NcpBase::HandleCommandPropertyRemove(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::HandleCommandPropertyInsertRemove(uint8_t aHeader, spinel_prop_key_t aKey, unsigned int aCommand) { - unsigned i; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_PROP_NOT_FOUND; + PropertyHandler handler = NULL; + unsigned int responseCommand = 0; + const uint8_t *valuePtr; + uint16_t valueLen; - for (i = 0; i < sizeof(mRemovePropertyHandlerTable) / sizeof(mRemovePropertyHandlerTable[0]); i++) + switch (aCommand) { - if (mRemovePropertyHandlerTable[i].mPropKey == aKey) - { - break; - } + case SPINEL_CMD_PROP_VALUE_INSERT: + handler = FindInsertPropertyHandler(aKey); + responseCommand = SPINEL_CMD_PROP_VALUE_INSERTED; + break; + + case SPINEL_CMD_PROP_VALUE_REMOVE: + handler = FindRemovePropertyHandler(aKey); + responseCommand = SPINEL_CMD_PROP_VALUE_REMOVED; + break; + + default: + assert(false); + break; } - if (i < sizeof(mRemovePropertyHandlerTable) / sizeof(mRemovePropertyHandlerTable[0])) - { - spinelError = ThreadErrorToSpinelStatus( - (this->*mRemovePropertyHandlerTable[i].mHandler)(aValuePtr, aValueLen)); - } + VerifyOrExit(handler != NULL, error = SendLastStatus(aHeader, SPINEL_STATUS_PROP_NOT_FOUND)); - if (spinelError == SPINEL_STATUS_OK) - { - SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_REMOVED, aKey)); - SuccessOrExit(error = mEncoder.WriteData(aValuePtr, aValueLen)); - SuccessOrExit(error = mEncoder.EndFrame()); - } - else - { - SuccessOrExit(error = SendLastStatus(aHeader, spinelError)); - } + // Save current read position in the decoder. Read the entire + // content as a data blob (which is used in forming the response + // in case of success), then reset the read position back so + // that the `PropertyHandler` method can parse the content. + + mDecoder.SavePosition(); + mDecoder.ReadData(valuePtr, valueLen); + mDecoder.ResetToSaved(); + + error = (this->*handler)(); + + VerifyOrExit(error == OT_ERROR_NONE, error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error))); + + // Prepare the response + SuccessOrExit(error = mEncoder.BeginFrame(aHeader, responseCommand, aKey)); + SuccessOrExit(error = mEncoder.WriteData(valuePtr, valueLen)); + SuccessOrExit(error = mEncoder.EndFrame()); exit: return error; @@ -1120,43 +1214,20 @@ exit: return error; } -otError NcpBase::SendSetPropertyResponse(uint8_t aHeader, spinel_prop_key_t aKey, otError aError) -{ - if (aError == OT_ERROR_NONE) - { - aError = HandleCommandPropertyGet(aHeader, aKey); - } - else - { - aError = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(aError)); - } - - return aError; -} - // ---------------------------------------------------------------------------- // MARK: Individual Command Handlers // ---------------------------------------------------------------------------- -otError NcpBase::CommandHandler_NOOP(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, uint16_t aArgLen) +otError NcpBase::CommandHandler_NOOP(uint8_t aHeader) { - OT_UNUSED_VARIABLE(aCommand); - OT_UNUSED_VARIABLE(aArgPtr); - OT_UNUSED_VARIABLE(aArgLen); - return SendLastStatus(aHeader, SPINEL_STATUS_OK); } -otError NcpBase::CommandHandler_RESET(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, - uint16_t aArgLen) +otError NcpBase::CommandHandler_RESET(uint8_t aHeader) { otError error = OT_ERROR_NONE; - // We aren't using any of the arguments to this function. OT_UNUSED_VARIABLE(aHeader); - OT_UNUSED_VARIABLE(aCommand); - OT_UNUSED_VARIABLE(aArgPtr); - OT_UNUSED_VARIABLE(aArgLen); // Signal a platform reset. If implemented, this function // shouldn't return. @@ -1182,229 +1253,96 @@ otError NcpBase::CommandHandler_RESET(uint8_t aHeader, unsigned int aCommand, co return error; } -otError NcpBase::CommandHandler_PROP_VALUE_GET(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, - uint16_t aArgLen) +otError NcpBase::CommandHandler_PROP_VALUE_update(uint8_t aHeader, unsigned int aCommand) { - unsigned int propKey = 0; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; + unsigned int propKey = 0; - parsedLength = spinel_datatype_unpack(aArgPtr, aArgLen, SPINEL_DATATYPE_UINT_PACKED_S, &propKey); + error = mDecoder.ReadUintPacked(propKey); - if (parsedLength > 0) + VerifyOrExit(error == OT_ERROR_NONE, error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error))); + + switch (aCommand) { + case SPINEL_CMD_PROP_VALUE_GET: error = HandleCommandPropertyGet(aHeader, static_cast(propKey)); - } - else - { - error = SendLastStatus(aHeader, SPINEL_STATUS_PARSE_ERROR); + break; + + case SPINEL_CMD_PROP_VALUE_SET: + error = HandleCommandPropertySet(aHeader, static_cast(propKey)); + break; + + case SPINEL_CMD_PROP_VALUE_INSERT: + case SPINEL_CMD_PROP_VALUE_REMOVE: + error = HandleCommandPropertyInsertRemove(aHeader, static_cast(propKey), aCommand); + break; + + default: + break; } - OT_UNUSED_VARIABLE(aCommand); - - return error; -} - -otError NcpBase::CommandHandler_PROP_VALUE_SET(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, - uint16_t aArgLen) -{ - unsigned int propKey = 0; - spinel_ssize_t parsedLength; - const uint8_t *valuePtr; - unsigned int valueLen; - otError error = OT_ERROR_NONE; - - parsedLength = spinel_datatype_unpack( - aArgPtr, - aArgLen, - SPINEL_DATATYPE_UINT_PACKED_S SPINEL_DATATYPE_DATA_S, - &propKey, - &valuePtr, - &valueLen - ); - - if (parsedLength == aArgLen) - { - error = HandleCommandPropertySet( - aHeader, - static_cast(propKey), - valuePtr, - static_cast(valueLen) - ); - } - else - { - error = SendLastStatus(aHeader, SPINEL_STATUS_PARSE_ERROR); - } - - OT_UNUSED_VARIABLE(aCommand); - - return error; -} - -otError NcpBase::CommandHandler_PROP_VALUE_INSERT(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, - uint16_t aArgLen) -{ - unsigned int propKey = 0; - spinel_ssize_t parsedLength; - const uint8_t *valuePtr; - unsigned int valueLen; - otError error = OT_ERROR_NONE; - - parsedLength = spinel_datatype_unpack( - aArgPtr, - aArgLen, - SPINEL_DATATYPE_UINT_PACKED_S SPINEL_DATATYPE_DATA_S, - &propKey, - &valuePtr, - &valueLen - ); - - if (parsedLength == aArgLen) - { - error = HandleCommandPropertyInsert( - aHeader, - static_cast(propKey), - valuePtr, - static_cast(valueLen) - ); - } - else - { - error = SendLastStatus(aHeader, SPINEL_STATUS_PARSE_ERROR); - } - - OT_UNUSED_VARIABLE(aCommand); - - return error; -} - -otError NcpBase::CommandHandler_PROP_VALUE_REMOVE(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, - uint16_t aArgLen) -{ - unsigned int propKey = 0; - spinel_ssize_t parsedLength; - const uint8_t *valuePtr; - unsigned int valueLen; - otError error = OT_ERROR_NONE; - - parsedLength = spinel_datatype_unpack( - aArgPtr, - aArgLen, - SPINEL_DATATYPE_UINT_PACKED_S SPINEL_DATATYPE_DATA_S, - &propKey, - &valuePtr, - &valueLen - ); - - if (parsedLength == aArgLen) - { - error = HandleCommandPropertyRemove( - aHeader, - static_cast(propKey), - valuePtr, - static_cast(valueLen) - ); - } - else - { - error = SendLastStatus(aHeader, SPINEL_STATUS_PARSE_ERROR); - } - - OT_UNUSED_VARIABLE(aCommand); - +exit: return error; } #if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE -otError NcpBase::CommandHandler_PEEK(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, uint16_t aArgLen) +otError NcpBase::CommandHandler_PEEK(uint8_t aHeader) { - spinel_ssize_t parsedLength; + otError parseError = OT_ERROR_NONE; + otError responseError = OT_ERROR_NONE; uint32_t address; uint16_t count; - spinel_status_t spinelError = SPINEL_STATUS_OK; - otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aArgPtr, - aArgLen, - ( - SPINEL_DATATYPE_UINT32_S // Address - SPINEL_DATATYPE_UINT16_S // Count - ), - &address, - &count - ); + SuccessOrExit(parseError = mDecoder.ReadUint32(address)); + SuccessOrExit(parseError = mDecoder.ReadUint16(count)); - VerifyOrExit(parsedLength == aArgLen, spinelError = SPINEL_STATUS_PARSE_ERROR); - - VerifyOrExit(count != 0, spinelError = SPINEL_STATUS_INVALID_ARGUMENT); + VerifyOrExit(count != 0, parseError = OT_ERROR_INVALID_ARGS); if (mAllowPeekDelegate != NULL) { - VerifyOrExit(mAllowPeekDelegate(address, count), spinelError = SPINEL_STATUS_INVALID_ARGUMENT); + VerifyOrExit(mAllowPeekDelegate(address, count), parseError = OT_ERROR_INVALID_ARGS); } - SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PEEK_RET)); - SuccessOrExit(error = mEncoder.WriteUint32(address)); - SuccessOrExit(error = mEncoder.WriteUint16(count)); - SuccessOrExit(error = mEncoder.WriteData(reinterpret_cast(address), count)); - SuccessOrExit(error = mEncoder.EndFrame()); + SuccessOrExit(responseError = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PEEK_RET)); + SuccessOrExit(responseError = mEncoder.WriteUint32(address)); + SuccessOrExit(responseError = mEncoder.WriteUint16(count)); + SuccessOrExit(responseError = mEncoder.WriteData(reinterpret_cast(address), count)); + SuccessOrExit(responseError = mEncoder.EndFrame()); exit: - if (spinelError != SPINEL_STATUS_OK) + if (parseError != OT_ERROR_NONE) { - error = SendLastStatus(aHeader, spinelError); + responseError = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(parseError)); } - OT_UNUSED_VARIABLE(aCommand); - - return error; + return responseError; } -otError NcpBase::CommandHandler_POKE(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, uint16_t aArgLen) +otError NcpBase::CommandHandler_POKE(uint8_t aHeader) { - spinel_ssize_t parsedLength; + otError parseError = OT_ERROR_NONE; uint32_t address; uint16_t count; const uint8_t *dataPtr = NULL; - spinel_size_t dataLen; - spinel_status_t spinelError = SPINEL_STATUS_OK; - otError error = OT_ERROR_NONE; + uint16_t dataLen; - parsedLength = spinel_datatype_unpack( - aArgPtr, - aArgLen, - ( - SPINEL_DATATYPE_UINT32_S // Address - SPINEL_DATATYPE_UINT16_S // Count - SPINEL_DATATYPE_DATA_S // Bytes - ), - &address, - &count, - &dataPtr, - &dataLen - ); + SuccessOrExit(error = mDecoder.ReadUint32(address)); + SuccessOrExit(error = mDecoder.ReadUint16(count)); + SuccessOrExit(error = mDecoder.ReadData(dataPtr, dataLen)); - VerifyOrExit(parsedLength == aArgLen, spinelError = SPINEL_STATUS_PARSE_ERROR); - - VerifyOrExit(count != 0, spinelError = SPINEL_STATUS_INVALID_ARGUMENT); - VerifyOrExit(count <= dataLen, spinelError = SPINEL_STATUS_INVALID_ARGUMENT); + VerifyOrExit(count != 0, parseError = OT_ERROR_INVALID_ARGS); + VerifyOrExit(count <= dataLen, parseError = OT_ERROR_INVALID_ARGS); if (mAllowPokeDelegate != NULL) { - VerifyOrExit(mAllowPokeDelegate(address, count), spinelError = SPINEL_STATUS_INVALID_ARGUMENT); + VerifyOrExit(mAllowPokeDelegate(address, count), parseError = OT_ERROR_INVALID_ARGS); } memcpy(reinterpret_cast(address), dataPtr, count); exit: - error = SendLastStatus(aHeader, spinelError); - - OT_UNUSED_VARIABLE(aCommand); - - return error; + return SendLastStatus(aHeader, ThreadErrorToSpinelStatus(parseError)); } #endif // OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE @@ -1428,21 +1366,12 @@ otError NcpBase::GetPropertyHandler_PHY_CHAN(void) return mEncoder.WriteUint8(otLinkGetChannel(mInstance)); } -otError NcpBase::SetPropertyHandler_PHY_CHAN(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_PHY_CHAN(void) { unsigned int channel = 0; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT_PACKED_S, - &channel - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUintPacked(channel)); #if OPENTHREAD_MTD || OPENTHREAD_FTD error = otLinkSetChannel(mInstance, static_cast(channel)); @@ -1467,7 +1396,7 @@ otError NcpBase::SetPropertyHandler_PHY_CHAN(uint8_t aHeader, spinel_prop_key_t #endif // OPENTHREAD_ENABLE_RAW_LINK_API exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_MAC_PROMISCUOUS_MODE(void) @@ -1478,21 +1407,12 @@ otError NcpBase::GetPropertyHandler_MAC_PROMISCUOUS_MODE(void) ); } -otError NcpBase::SetPropertyHandler_MAC_PROMISCUOUS_MODE(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_MAC_PROMISCUOUS_MODE(void) { uint8_t mode = 0; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT8_S, - &mode - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUint8(mode)); switch (mode) { @@ -1511,7 +1431,7 @@ otError NcpBase::SetPropertyHandler_MAC_PROMISCUOUS_MODE(uint8_t aHeader, spinel } exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_MAC_15_4_PANID(void) @@ -1519,26 +1439,17 @@ otError NcpBase::GetPropertyHandler_MAC_15_4_PANID(void) return mEncoder.WriteUint16(otLinkGetPanId(mInstance)); } -otError NcpBase::SetPropertyHandler_MAC_15_4_PANID(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_MAC_15_4_PANID(void) { uint16_t panid; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT16_S, - &panid - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUint16(panid)); error = otLinkSetPanId(mInstance, panid); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_MAC_15_4_LADDR(void) @@ -1546,26 +1457,17 @@ otError NcpBase::GetPropertyHandler_MAC_15_4_LADDR(void) return mEncoder.WriteEui64(*otLinkGetExtendedAddress(mInstance)); } -otError NcpBase::SetPropertyHandler_MAC_15_4_LADDR(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_MAC_15_4_LADDR(void) { - otExtAddress *extAddress; - spinel_ssize_t parsedLength; + const otExtAddress *extAddress; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_EUI64_S, - &extAddress - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadEui64(extAddress)); error = otLinkSetExtendedAddress(mInstance, extAddress); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_MAC_15_4_SADDR(void) @@ -1578,27 +1480,18 @@ otError NcpBase::GetPropertyHandler_MAC_RAW_STREAM_ENABLED(void) return mEncoder.WriteBool(mIsRawStreamEnabled); } -otError NcpBase::SetPropertyHandler_MAC_RAW_STREAM_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_MAC_RAW_STREAM_ENABLED(void) { - bool value = false; - spinel_ssize_t parsedLength; + bool enabled = false; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_BOOL_S, - &value - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadBool(enabled)); #if OPENTHREAD_ENABLE_RAW_LINK_API if (otLinkRawIsEnabled(mInstance)) { - if (value) + if (enabled) { error = otLinkRawReceive(mInstance, mCurReceiveChannel, &NcpBase::LinkRawReceiveDone); } @@ -1610,10 +1503,10 @@ otError NcpBase::SetPropertyHandler_MAC_RAW_STREAM_ENABLED(uint8_t aHeader, spin #endif // OPENTHREAD_ENABLE_RAW_LINK_API - mIsRawStreamEnabled = value; + mIsRawStreamEnabled = enabled; exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_UNSOL_UPDATE_FILTER(void) @@ -1636,65 +1529,41 @@ exit: return error; } -otError NcpBase::SetPropertyHandler_UNSOL_UPDATE_FILTER(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_UNSOL_UPDATE_FILTER(void) { - spinel_ssize_t parsedLength; unsigned int propKey; otError error = OT_ERROR_NONE; - bool reportAsync; // First clear the current filter. mChangedPropsSet.ClearFilter(); - while (aValueLen > 0) + while (mDecoder.GetRemainingLengthInStruct() > 0) { - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT_PACKED_S, - &propKey - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(mDecoder.ReadUintPacked(propKey)); IgnoreReturnValue(mChangedPropsSet.EnablePropertyFilter(static_cast(propKey), true)); - - aValuePtr += parsedLength; - aValueLen -= parsedLength; } exit: // If we had an error, we may have actually changed - // the state of the filter---so we need to report + // the state of the filter, So we need to report // those incomplete changes via an asynchronous // change event. - reportAsync = (error != OT_ERROR_NONE); - error = SendSetPropertyResponse(aHeader, aKey, error); - - if (reportAsync) + if (error != OT_ERROR_NONE) { - HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, aKey); + HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_PROP_UNSOL_UPDATE_FILTER); } return error; } -otError NcpBase::InsertPropertyHandler_UNSOL_UPDATE_FILTER(const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::InsertPropertyHandler_UNSOL_UPDATE_FILTER(void) { - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; unsigned int propKey; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT_PACKED_S, - &propKey - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUintPacked(propKey)); error = mChangedPropsSet.EnablePropertyFilter(static_cast(propKey), true); @@ -1702,20 +1571,12 @@ exit: return error; } -otError NcpBase::RemovePropertyHandler_UNSOL_UPDATE_FILTER(const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::RemovePropertyHandler_UNSOL_UPDATE_FILTER(void) { - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; unsigned int propKey; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT_PACKED_S, - &propKey - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUintPacked(propKey)); error = mChangedPropsSet.EnablePropertyFilter(static_cast(propKey), false); @@ -1817,15 +1678,9 @@ otError NcpBase::GetPropertyHandler_POWER_STATE(void) return mEncoder.WriteUint8(SPINEL_POWER_STATE_ONLINE); // Always online at the moment } -otError NcpBase::SetPropertyHandler_POWER_STATE(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_POWER_STATE(void) { - // TODO: Implement POWER_STATE - OT_UNUSED_VARIABLE(aKey); - OT_UNUSED_VARIABLE(aValuePtr); - OT_UNUSED_VARIABLE(aValueLen); - - return SendLastStatus(aHeader, SPINEL_STATUS_UNIMPLEMENTED); + return OT_ERROR_NOT_IMPLEMENTED; } otError NcpBase::GetPropertyHandler_HWADDR(void) @@ -1847,30 +1702,29 @@ otError NcpBase::GetPropertyHandler_HOST_POWER_STATE(void) return mEncoder.WriteUint8(mHostPowerState); } -otError NcpBase::SetPropertyHandler_HOST_POWER_STATE(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +// Setting `HOST_POWER_STATE` is treated and implemented differently from other +// handlers as it requires two special behaviors (a) the response frame for the +// set operation should be tracked and only when it is delivered we can assume +// that host is sleep (b) the response is critical so if there is no spinel +// buffer to prepare the response, the current spinel header is saved to +// prepare and send the response as soon as buffer space becomes available. +otError NcpBase::SetPropertyHandler_HOST_POWER_STATE(uint8_t aHeader) { - uint8_t value; - spinel_ssize_t parsedLength; + uint8_t powerState; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT8_S, - &value - ); + error = mDecoder.ReadUint8(powerState); - if (parsedLength > 0) + if (error == OT_ERROR_NONE) { - switch (value) + switch (powerState) { case SPINEL_HOST_POWER_STATE_OFFLINE: case SPINEL_HOST_POWER_STATE_DEEP_SLEEP: case SPINEL_HOST_POWER_STATE_LOW_POWER: case SPINEL_HOST_POWER_STATE_ONLINE: // Adopt the requested power state. - mHostPowerState = static_cast(value); + mHostPowerState = static_cast(powerState); break; case SPINEL_HOST_POWER_STATE_RESERVED: @@ -1883,17 +1737,10 @@ otError NcpBase::SetPropertyHandler_HOST_POWER_STATE(uint8_t aHeader, spinel_pro mHostPowerState = SPINEL_HOST_POWER_STATE_LOW_POWER; break; } - } - else - { - error = OT_ERROR_PARSE; - } - if (error == OT_ERROR_NONE) - { mHostPowerStateHeader = 0; - error = HandleCommandPropertyGet(aHeader, aKey); + error = HandleCommandPropertyGet(aHeader, SPINEL_PROP_HOST_POWER_STATE); if (mHostPowerState != SPINEL_HOST_POWER_STATE_ONLINE) { @@ -1958,26 +1805,17 @@ otError NcpBase::GetPropertyHandler_PHY_TX_POWER(void) return mEncoder.WriteInt8(otLinkGetMaxTransmitPower(mInstance)); } -otError NcpBase::SetPropertyHandler_PHY_TX_POWER(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_PHY_TX_POWER(void) { - int8_t value = 0; - spinel_ssize_t parsedLength; + int8_t txPower = 0; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_INT8_S, - &value - ); + SuccessOrExit(error = mDecoder.ReadInt8(txPower)); - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); - - otLinkSetMaxTransmitPower(mInstance, value); + otLinkSetMaxTransmitPower(mInstance, txPower); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_DEBUG_TEST_ASSERT(void) @@ -2024,22 +1862,13 @@ otError NcpBase::GetPropertyHandler_DEBUG_NCP_LOG_LEVEL(void) return mEncoder.WriteUint8(logLevel); } -otError NcpBase::SetPropertyHandler_DEBUG_NCP_LOG_LEVEL(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_DEBUG_NCP_LOG_LEVEL(void) { uint8_t spinelNcpLogLevel = 0; otLogLevel logLevel; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT8_S, - &spinelNcpLogLevel - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUint8(spinelNcpLogLevel)); switch (spinelNcpLogLevel) { @@ -2074,7 +1903,7 @@ otError NcpBase::SetPropertyHandler_DEBUG_NCP_LOG_LEVEL(uint8_t aHeader, spinel_ error = otSetDynamicLogLevel(mInstance, logLevel); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } } // namespace Ncp diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index 266ffde77..4c55b7935 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -47,6 +47,7 @@ #include "changed_props_set.hpp" #include "common/tasklet.hpp" #include "ncp/ncp_buffer.hpp" +#include "ncp/spinel_decoder.hpp" #include "ncp/spinel_encoder.hpp" #include "spinel.h" @@ -54,37 +55,10 @@ namespace ot { namespace Ncp { -#define NCP_COMMAND_HANDLER(name) \ - otError CommandHandler_##name( \ - uint8_t aHeader, \ - unsigned int aCommand, \ - const uint8_t *aArgPtr, \ - uint16_t aArgLen \ - ) - - -#define NCP_GET_PROP_HANDLER(name) \ - otError GetPropertyHandler_##name(void) - -#define NCP_SET_PROP_HANDLER(name) \ - otError SetPropertyHandler_##name( \ - uint8_t aHeader, \ - spinel_prop_key_t aKey, \ - const uint8_t *aValuePtr, \ - uint16_t aValueLen \ - ) - -#define NCP_INSERT_PROP_HANDLER(name) \ - otError InsertPropertyHandler_##name( \ - const uint8_t *aValuePtr, \ - uint16_t aValueLen \ - ) - -#define NCP_REMOVE_PROP_HANDLER(name) \ - otError RemovePropertyHandler_##name( \ - const uint8_t *aValuePtr, \ - uint16_t aValueLen \ - ) +#define NCP_GET_PROP_HANDLER(name) otError GetPropertyHandler_##name(void) +#define NCP_SET_PROP_HANDLER(name) otError SetPropertyHandler_##name(void) +#define NCP_INSERT_PROP_HANDLER(name) otError InsertPropertyHandler_##name(void) +#define NCP_REMOVE_PROP_HANDLER(name) otError RemovePropertyHandler_##name(void) class NcpBase { @@ -107,7 +81,7 @@ public: static NcpBase *GetNcpInstance(void); /** - * This method sends data to host via specifiec stream. + * This method sends data to host via specific stream. * * * @param[in] aStreamId A numeric identifier for the stream to write to. @@ -190,64 +164,30 @@ public: bool ShouldDeferHostSend(void); private: - typedef otError(NcpBase::*CommandHandlerType)(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, - uint16_t aArgLen); + typedef otError (NcpBase::*PropertyHandler)(void); - typedef otError(NcpBase::*GetPropertyHandlerType)(void); - - typedef otError(NcpBase::*InsertRemovePropertyHandlerType)(const uint8_t *aValuePtr, uint16_t aValueLen); - - typedef otError(NcpBase::*SetPropertyHandlerType)(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen); - - struct CommandHandlerEntry - { - spinel_cid_t mCommand; - CommandHandlerType mHandler; - }; - - struct GetPropertyHandlerEntry + struct PropertyHandlerEntry { spinel_prop_key_t mPropKey; - GetPropertyHandlerType mHandler; - }; - - struct SetPropertyHandlerEntry - { - spinel_prop_key_t mPropKey; - SetPropertyHandlerType mHandler; - }; - - struct InsertPropertyHandlerEntry - { - spinel_prop_key_t mPropKey; - InsertRemovePropertyHandlerType mHandler; - }; - - struct RemovePropertyHandlerEntry - { - spinel_prop_key_t mPropKey; - InsertRemovePropertyHandlerType mHandler; + PropertyHandler mHandler; }; NcpFrameBuffer::FrameTag GetLastOutboundFrameTag(void); - otError HandleCommand(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, uint16_t aArgLen); + otError HandleCommand(uint8_t aHeader, unsigned int aCommand); + + PropertyHandler FindPropertyHandler(spinel_prop_key_t aKey, const PropertyHandlerEntry *aTable, size_t aTableLen); + PropertyHandler FindGetPropertyHandler(spinel_prop_key_t aKey); + PropertyHandler FindSetPropertyHandler(spinel_prop_key_t aKey); + PropertyHandler FindInsertPropertyHandler(spinel_prop_key_t aKey); + PropertyHandler FindRemovePropertyHandler(spinel_prop_key_t aKey); otError HandleCommandPropertyGet(uint8_t aHeader, spinel_prop_key_t aKey); - - otError HandleCommandPropertySet(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen); - - otError HandleCommandPropertyInsert(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen); - - otError HandleCommandPropertyRemove(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen); - + bool HandlePropertySetForSpecialProperties(uint8_t aHeader, spinel_prop_key_t aKey, otError &aError); + otError HandleCommandPropertySet(uint8_t aHeader, spinel_prop_key_t aKey); + otError HandleCommandPropertyInsertRemove(uint8_t aHeader, spinel_prop_key_t aKey, unsigned int aCommand); otError SendLastStatus(uint8_t aHeader, spinel_status_t aLastStatus); - otError SendSetPropertyResponse(uint8_t aHeader, spinel_prop_key_t aKey, otError aError); static void UpdateChangedProps(Tasklet &aTasklet); void UpdateChangedProps(void); @@ -300,19 +240,58 @@ private: #endif // OPENTHREAD_FTD && OPENTHREAD_ENABLE_TMF_PROXY #if OPENTHREAD_ENABLE_SPINEL_VENDOR_SUPPORT - otError VendorCommandHandler(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, uint16_t aArgLen); + otError VendorCommandHandler(uint8_t aHeader, unsigned int aCommand); #endif // OPENTHREAD_ENABLE_SPINEL_VENDOR_SUPPORT - NCP_COMMAND_HANDLER(NOOP); - NCP_COMMAND_HANDLER(RESET); - NCP_COMMAND_HANDLER(PROP_VALUE_GET); - NCP_COMMAND_HANDLER(PROP_VALUE_SET); - NCP_COMMAND_HANDLER(PROP_VALUE_INSERT); - NCP_COMMAND_HANDLER(PROP_VALUE_REMOVE); + otError CommandHandler_NOOP(uint8_t aHeader); + otError CommandHandler_RESET(uint8_t aHeader); + // Combined command handler for `VALUE_GET`, `VALUE_SET`, `VALUE_INSERT` and `VALUE_REMOVE`. + otError CommandHandler_PROP_VALUE_update(uint8_t aHeader, unsigned int aCommand); #if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE - NCP_COMMAND_HANDLER(PEEK); - NCP_COMMAND_HANDLER(POKE); + otError CommandHandler_PEEK(uint8_t aHeader); + otError CommandHandler_POKE(uint8_t aHeader); #endif +#if OPENTHREAD_MTD || OPENTHREAD_FTD + otError CommandHandler_NET_SAVE(uint8_t aHeader); + otError CommandHandler_NET_CLEAR(uint8_t aHeader); + otError CommandHandler_NET_RECALL(uint8_t aHeader); +#endif + + // ---------------------------------------------------------------------------- + // Property Handlers + // ---------------------------------------------------------------------------- + // + // There are 4 types of property handlers for "get", "set", "insert", and + // "remove" commands. + // + // "Get" handlers should get/retrieve the property value and then encode and + // write the value into the NCP buffer. If the "get" operation itself fails, + // "get" handler should write a `LAST_STATUS` with the error status into the NCP + // buffer. The `otError` returned from a "get" handler is the error of writing + // into the NCP buffer (e.g., running out buffer), and not of the "get" operation + // itself. + // + // "Set/Insert/Remove" handlers should first decode/parse the value from the + // input Spinel frame and then perform the corresponding set/insert/remove + // operation. They are not responsible for preparing the Spinel response and + // therefore should not write anything to the NCP buffer. The `otError` returned + // from a "set/insert/remove" handler indicates the error in either parsing of + // the input or the error of set/insert/remove operation. + // + // The corresponding command handler (e.g., `HandleCommandPropertySet()` for + // `VALUE_SET` command) will take care of preparing the Spinel response after + // invoking the "set/insert/remove" handler for a given property. For example, + // for a `VALUE_SET` command, if the "set" handler returns an error, then a + // `LAST_STATUS` update response is prepared, otherwise on success the "get" + // handler for the property is used to prepare a `VALUE_IS` Spinel response (in + // cases where there is no "get" handler for the property, the input value is + // echoed in the response). + // + // Few properties require special treatment where the response needs to be + // prepared directly in the "set" handler (e.g., `HOST_POWER_STATE` or + // `NEST_STREAM_MFG`). These properties have a different handler method format + // (they expect `aHeader` as an input argument) and are processed separately in + // `HandleCommandPropertySet()`. NCP_GET_PROP_HANDLER(LAST_STATUS); NCP_GET_PROP_HANDLER(PROTOCOL_VERSION); @@ -329,7 +308,6 @@ private: NCP_GET_PROP_HANDLER(HWADDR); NCP_GET_PROP_HANDLER(LOCK); NCP_GET_PROP_HANDLER(HOST_POWER_STATE); - NCP_SET_PROP_HANDLER(HOST_POWER_STATE); NCP_GET_PROP_HANDLER(UNSOL_UPDATE_FILTER); NCP_GET_PROP_HANDLER(UNSOL_UPDATE_LIST); @@ -372,14 +350,10 @@ private: NCP_REMOVE_PROP_HANDLER(MAC_SRC_MATCH_EXTENDED_ADDRESSES); NCP_SET_PROP_HANDLER(PHY_ENABLED); - NCP_SET_PROP_HANDLER(STREAM_RAW); #endif // OPENTHREAD_ENABLE_RAW_LINK_API // FTD or MTD handlers. #if OPENTHREAD_MTD || OPENTHREAD_FTD - NCP_COMMAND_HANDLER(NET_SAVE); - NCP_COMMAND_HANDLER(NET_CLEAR); - NCP_COMMAND_HANDLER(NET_RECALL); NCP_GET_PROP_HANDLER(MAC_EXTENDED_ADDR); NCP_GET_PROP_HANDLER(MAC_SCAN_MASK); @@ -462,7 +436,6 @@ private: #if OPENTHREAD_ENABLE_BORDER_ROUTER NCP_SET_PROP_HANDLER(THREAD_ALLOW_LOCAL_NET_DATA_CHANGE); #endif - NCP_GET_PROP_HANDLER(STREAM_NET); NCP_SET_PROP_HANDLER(STREAM_NET); NCP_GET_PROP_HANDLER(CNTR_TX_PKT_TOTAL); @@ -541,11 +514,7 @@ private: NCP_SET_PROP_HANDLER(THREAD_DISCOVERY_SCAN_ENABLE_FILTERING); NCP_GET_PROP_HANDLER(THREAD_DISCOVERY_SCAN_PANID); NCP_SET_PROP_HANDLER(THREAD_DISCOVERY_SCAN_PANID); -#if OPENTHREAD_ENABLE_COMMISSIONER - NCP_GET_PROP_HANDLER(THREAD_COMMISSIONER_ENABLED); - NCP_SET_PROP_HANDLER(THREAD_COMMISSIONER_ENABLED); - NCP_INSERT_PROP_HANDLER(THREAD_JOINERS); -#endif + #if OPENTHREAD_ENABLE_JAM_DETECTION NCP_GET_PROP_HANDLER(JAM_DETECTED); NCP_GET_PROP_HANDLER(JAM_DETECT_ENABLE); @@ -565,10 +534,6 @@ private: #endif NCP_SET_PROP_HANDLER(STREAM_NET_INSECURE); NCP_SET_PROP_HANDLER(CNTR_RESET); -#if OPENTHREAD_ENABLE_DIAG - NCP_SET_PROP_HANDLER(NEST_STREAM_MFG); -#endif - #endif // OPENTHREAD_MTD || OPENTHREAD_FTD #if OPENTHREAD_FTD @@ -596,6 +561,10 @@ private: #if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB NCP_SET_PROP_HANDLER(THREAD_STEERING_DATA); #endif +#if OPENTHREAD_ENABLE_COMMISSIONER + NCP_GET_PROP_HANDLER(THREAD_COMMISSIONER_ENABLED); + NCP_INSERT_PROP_HANDLER(THREAD_JOINERS); +#endif #if OPENTHREAD_ENABLE_TMF_PROXY NCP_GET_PROP_HANDLER(THREAD_TMF_PROXY_ENABLED); NCP_SET_PROP_HANDLER(THREAD_TMF_PROXY_ENABLED); @@ -604,6 +573,20 @@ private: NCP_REMOVE_PROP_HANDLER(THREAD_ACTIVE_ROUTER_IDS); #endif // OPENTHREAD_FTD + otError SetPropertyHandler_HOST_POWER_STATE(uint8_t aHeader); + +#if OPENTHREAD_ENABLE_DIAG + otError SetPropertyHandler_NEST_STREAM_MFG(uint8_t aHeader); +#endif + +#if OPENTHREAD_FTD && OPENTHREAD_ENABLE_COMMISSIONER + otError SetPropertyHandler_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader); +#endif // OPENTHREAD_FTD + +#if OPENTHREAD_ENABLE_RAW_LINK_API + otError SetPropertyHandler_STREAM_RAW(uint8_t aHeader); +#endif + protected: static NcpBase *sNcpInstance; static spinel_status_t ThreadErrorToSpinelStatus(otError aError); @@ -611,6 +594,7 @@ protected: otInstance *mInstance; NcpFrameBuffer mTxFrameBuffer; SpinelEncoder mEncoder; + SpinelDecoder mDecoder; bool mHostPowerStateInProgress; private: @@ -621,11 +605,10 @@ private: }; // Command Handlers - static const CommandHandlerEntry mCommandHandlerTable[]; - static const GetPropertyHandlerEntry mGetPropertyHandlerTable[]; - static const SetPropertyHandlerEntry mSetPropertyHandlerTable[]; - static const InsertPropertyHandlerEntry mInsertPropertyHandlerTable[]; - static const RemovePropertyHandlerEntry mRemovePropertyHandlerTable[]; + static const PropertyHandlerEntry mGetPropertyHandlerTable[]; + static const PropertyHandlerEntry mSetPropertyHandlerTable[]; + static const PropertyHandlerEntry mInsertPropertyHandlerTable[]; + static const PropertyHandlerEntry mRemovePropertyHandlerTable[]; spinel_status_t mLastStatus; uint32_t mSupportedChannelMask; diff --git a/src/ncp/ncp_base_ftd.cpp b/src/ncp/ncp_base_ftd.cpp index 193a6f0e5..83c7efe0a 100644 --- a/src/ncp/ncp_base_ftd.cpp +++ b/src/ncp/ncp_base_ftd.cpp @@ -113,26 +113,17 @@ otError NcpBase::GetPropertyHandler_THREAD_ROUTER_ROLE_ENABLED(void) return mEncoder.WriteBool(otThreadIsRouterRoleEnabled(mInstance)); } -otError NcpBase::SetPropertyHandler_THREAD_ROUTER_ROLE_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_THREAD_ROUTER_ROLE_ENABLED(void) { bool enabled; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_BOOL_S, - &enabled - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadBool(enabled)); otThreadSetRouterRoleEnabled(mInstance, enabled); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_NET_PSKC(void) @@ -140,28 +131,20 @@ otError NcpBase::GetPropertyHandler_NET_PSKC(void) return mEncoder.WriteData(otThreadGetPSKc(mInstance), sizeof(spinel_net_pskc_t)); } -otError NcpBase::SetPropertyHandler_NET_PSKC(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_NET_PSKC(void) { const uint8_t *ptr = NULL; - spinel_size_t len; - spinel_ssize_t parsedLength; + uint16_t len; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_DATA_S, - &ptr, - &len - ); + SuccessOrExit(error = mDecoder.ReadData(ptr, len)); - VerifyOrExit((parsedLength > 0) && (len == sizeof(spinel_net_pskc_t)), error = OT_ERROR_PARSE); + VerifyOrExit(len == sizeof(spinel_net_pskc_t), error = OT_ERROR_PARSE); error = otThreadSetPSKc(mInstance, ptr); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_THREAD_CHILD_COUNT_MAX(void) @@ -169,26 +152,17 @@ otError NcpBase::GetPropertyHandler_THREAD_CHILD_COUNT_MAX(void) return mEncoder.WriteUint8(otThreadGetMaxAllowedChildren(mInstance)); } -otError NcpBase::SetPropertyHandler_THREAD_CHILD_COUNT_MAX(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_THREAD_CHILD_COUNT_MAX(void) { uint8_t maxChildren = 0; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT8_S, - &maxChildren - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUint8(maxChildren)); error = otThreadSetMaxAllowedChildren(mInstance, maxChildren); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_THREAD_ROUTER_UPGRADE_THRESHOLD(void) @@ -196,26 +170,17 @@ otError NcpBase::GetPropertyHandler_THREAD_ROUTER_UPGRADE_THRESHOLD(void) return mEncoder.WriteUint8(otThreadGetRouterUpgradeThreshold(mInstance)); } -otError NcpBase::SetPropertyHandler_THREAD_ROUTER_UPGRADE_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_THREAD_ROUTER_UPGRADE_THRESHOLD(void) { uint8_t threshold = 0; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT8_S, - &threshold - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUint8(threshold)); otThreadSetRouterUpgradeThreshold(mInstance, threshold); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_THREAD_ROUTER_DOWNGRADE_THRESHOLD(void) @@ -223,26 +188,17 @@ otError NcpBase::GetPropertyHandler_THREAD_ROUTER_DOWNGRADE_THRESHOLD(void) return mEncoder.WriteUint8(otThreadGetRouterDowngradeThreshold(mInstance)); } -otError NcpBase::SetPropertyHandler_THREAD_ROUTER_DOWNGRADE_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_THREAD_ROUTER_DOWNGRADE_THRESHOLD(void) { uint8_t threshold = 0; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT8_S, - &threshold - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUint8(threshold)); otThreadSetRouterDowngradeThreshold(mInstance, threshold); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_THREAD_ROUTER_SELECTION_JITTER(void) @@ -250,26 +206,17 @@ otError NcpBase::GetPropertyHandler_THREAD_ROUTER_SELECTION_JITTER(void) return mEncoder.WriteUint8(otThreadGetRouterSelectionJitter(mInstance)); } -otError NcpBase::SetPropertyHandler_THREAD_ROUTER_SELECTION_JITTER(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_THREAD_ROUTER_SELECTION_JITTER(void) { uint8_t jitter = 0; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT8_S, - &jitter - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUint8(jitter)); otThreadSetRouterSelectionJitter(mInstance, jitter); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_THREAD_CONTEXT_REUSE_DELAY(void) @@ -277,26 +224,17 @@ otError NcpBase::GetPropertyHandler_THREAD_CONTEXT_REUSE_DELAY(void) return mEncoder.WriteUint32(otThreadGetContextIdReuseDelay(mInstance)); } -otError NcpBase::SetPropertyHandler_THREAD_CONTEXT_REUSE_DELAY(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_THREAD_CONTEXT_REUSE_DELAY(void) { uint32_t delay = 0; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT32_S, - &delay - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUint32(delay)); otThreadSetContextIdReuseDelay(mInstance, delay); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_THREAD_NETWORK_ID_TIMEOUT(void) @@ -304,26 +242,17 @@ otError NcpBase::GetPropertyHandler_THREAD_NETWORK_ID_TIMEOUT(void) return mEncoder.WriteUint8(otThreadGetNetworkIdTimeout(mInstance)); } -otError NcpBase::SetPropertyHandler_THREAD_NETWORK_ID_TIMEOUT(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_THREAD_NETWORK_ID_TIMEOUT(void) { uint8_t timeout = 0; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT8_S, - &timeout - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUint8(timeout)); otThreadSetNetworkIdTimeout(mInstance, timeout); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } #if OPENTHREAD_ENABLE_COMMISSIONER @@ -332,22 +261,12 @@ otError NcpBase::GetPropertyHandler_THREAD_COMMISSIONER_ENABLED(void) return mEncoder.WriteBool(otCommissionerGetState(mInstance) == OT_COMMISSIONER_STATE_ACTIVE); } -otError NcpBase::SetPropertyHandler_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader) { bool enabled = false; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_BOOL_S, - &enabled - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadBool(enabled)); if (enabled == false) { @@ -359,50 +278,26 @@ otError NcpBase::SetPropertyHandler_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader, } exit: - OT_UNUSED_VARIABLE(aKey); - return SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error)); } -otError NcpBase::InsertPropertyHandler_THREAD_JOINERS(const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::InsertPropertyHandler_THREAD_JOINERS(void) { - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - otExtAddress *extAddress = NULL; + const otExtAddress *extAddress = NULL; const char *aPSKd = NULL; uint32_t joinerTimeout = 0; VerifyOrExit(mAllowLocalNetworkDataChange == true, error = OT_ERROR_INVALID_STATE); - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - ( - SPINEL_DATATYPE_UTF8_S // PSK - SPINEL_DATATYPE_UINT32_S // Timeout - SPINEL_DATATYPE_EUI64_S // Extended address - ), - &aPSKd, - &joinerTimeout, - &extAddress - ); + SuccessOrExit(error = mDecoder.ReadUtf8(aPSKd)); + SuccessOrExit(error = mDecoder.ReadUint32(joinerTimeout)); - if (parsedLength <= 0) + if (mDecoder.ReadEui64(extAddress) != OT_ERROR_NONE) { - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - ( - SPINEL_DATATYPE_UTF8_S // PSK - SPINEL_DATATYPE_UINT32_S // Timeout - ), - &aPSKd, - &joinerTimeout - ); extAddress = NULL; } - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); error = otCommissionerAddJoiner(mInstance, extAddress, aPSKd, joinerTimeout); @@ -412,136 +307,74 @@ exit: #endif // OPENTHREAD_ENABLE_COMMISSIONER -otError NcpBase::SetPropertyHandler_THREAD_LOCAL_LEADER_WEIGHT(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_THREAD_LOCAL_LEADER_WEIGHT(void) { uint8_t weight; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT8_S, - &weight - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUint8(weight)); otThreadSetLocalLeaderWeight(mInstance, weight); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } #if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB -otError NcpBase::SetPropertyHandler_THREAD_STEERING_DATA(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_THREAD_STEERING_DATA(void) { - otExtAddress *extAddress; - spinel_ssize_t parsedLength; + const otExtAddress *extAddress; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_EUI64_S, - &extAddress - ); + SuccessOrExit(error = mDecoder.ReadEui64(extAddress)); - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); - - error = otThreadSetSteeringData(mInstance, extAddress); - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); + SuccessOrExit(error = otThreadSetSteeringData(mInstance, extAddress)); // Note that there is no get handler for this property - - SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey)); - SuccessOrExit(error = mEncoder.WriteEui64(*extAddress)); - SuccessOrExit(error = mEncoder.EndFrame()); + // so the response becomes `VALUE_IS` echo of the + // received content. exit: - if (spinelError != SPINEL_STATUS_OK) - { - error = SendLastStatus(aHeader, spinelError); - } - return error; } #endif // #if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB -otError NcpBase::SetPropertyHandler_THREAD_CHILD_TIMEOUT(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_THREAD_CHILD_TIMEOUT(void) { uint32_t timeout = 0; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT32_S, - &timeout - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUint32(timeout)); otThreadSetChildTimeout(mInstance, timeout); exit: - return SendSetPropertyResponse(aHeader, aKey, error); -} - -otError NcpBase::SetPropertyHandler_THREAD_PREFERRED_ROUTER_ID(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) -{ - uint8_t routerId = 0; - spinel_ssize_t parsedLength; - otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; - - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT8_S, - &routerId - ); - - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); - - error = otThreadSetPreferredRouterId(mInstance, routerId); - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - - // Note that there is no get handler for this property. - - SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey)); - SuccessOrExit(error = mEncoder.WriteUint8(routerId)); - SuccessOrExit(error = mEncoder.EndFrame()); - -exit: - if (spinelError != SPINEL_STATUS_OK) - { - error = SendLastStatus(aHeader, spinelError); - } - return error; } -otError NcpBase::RemovePropertyHandler_THREAD_ACTIVE_ROUTER_IDS(const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_THREAD_PREFERRED_ROUTER_ID(void) +{ + uint8_t routerId = 0; + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = mDecoder.ReadUint8(routerId)); + + SuccessOrExit(error = otThreadSetPreferredRouterId(mInstance, routerId)); + + // Note that there is no get handler for this property + // so the response becomes `VALUE_IS` echo of the + // received content. + +exit: + return error; +} + +otError NcpBase::RemovePropertyHandler_THREAD_ACTIVE_ROUTER_IDS(void) { - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; uint8_t routerId; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT8_S, - &routerId - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUint8(routerId)); error = otThreadReleaseRouterId(mInstance, routerId); @@ -563,37 +396,22 @@ otError NcpBase::GetPropertyHandler_THREAD_TMF_PROXY_ENABLED(void) return mEncoder.WriteBool(otTmfProxyIsEnabled(mInstance)); } -otError NcpBase::SetPropertyHandler_THREAD_TMF_PROXY_STREAM(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_THREAD_TMF_PROXY_STREAM(void) { const uint8_t *framePtr = NULL; - unsigned int frameLen = 0; + uint16_t frameLen = 0; uint16_t locator; uint16_t port; otMessage *message; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; // THREAD_TMF_PROXY_STREAM requires layer 2 security. message = otIp6NewMessage(mInstance, true); VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS); - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - ( - SPINEL_DATATYPE_DATA_WLEN_S // Frame data - SPINEL_DATATYPE_UINT16_S // Locator - SPINEL_DATATYPE_UINT16_S // Port - ), - &framePtr, - &frameLen, - &locator, - &port - ); - - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadDataWithLen(framePtr, frameLen)); + SuccessOrExit(error = mDecoder.ReadUint16(locator)); + SuccessOrExit(error = mDecoder.ReadUint16(port)); SuccessOrExit(error = otMessageAppend(message, framePtr, static_cast(frameLen))); @@ -610,40 +428,15 @@ exit: otMessageFree(message); } - if (error == OT_ERROR_NONE) - { - if (SPINEL_HEADER_GET_TID(aHeader) != 0) - { - // Only send a successful status update if - // there was a transaction id in the aHeader. - error = SendLastStatus(aHeader, SPINEL_STATUS_OK); - } - } - else - { - error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error)); - } - - OT_UNUSED_VARIABLE(aKey); - return error; } -otError NcpBase::SetPropertyHandler_THREAD_TMF_PROXY_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_THREAD_TMF_PROXY_ENABLED(void) { bool enabled; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_BOOL_S, - &enabled - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadBool(enabled)); if (enabled) { @@ -655,7 +448,7 @@ otError NcpBase::SetPropertyHandler_THREAD_TMF_PROXY_ENABLED(uint8_t aHeader, sp } exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } void NcpBase::HandleTmfProxyStream(otMessage *aMessage, uint16_t aLocator, uint16_t aPort, void *aContext) diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp index c240a27df..1fef0240b 100644 --- a/src/ncp/ncp_base_mtd.cpp +++ b/src/ncp/ncp_base_mtd.cpp @@ -177,26 +177,17 @@ otError NcpBase::GetPropertyHandler_MAC_DATA_POLL_PERIOD(void) return mEncoder.WriteUint32(otLinkGetPollPeriod(mInstance)); } -otError NcpBase::SetPropertyHandler_MAC_DATA_POLL_PERIOD(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_MAC_DATA_POLL_PERIOD(void) { uint32_t pollPeriod; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT32_S, - &pollPeriod - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUint32(pollPeriod)); otLinkSetPollPeriod(mInstance, pollPeriod); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_MAC_EXTENDED_ADDR(void) @@ -235,33 +226,18 @@ otError NcpBase::GetPropertyHandler_PHY_RSSI(void) return mEncoder.WriteInt8(otPlatRadioGetRssi(mInstance)); } -otError NcpBase::CommandHandler_NET_SAVE(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, - uint16_t aArgLen) +otError NcpBase::CommandHandler_NET_SAVE(uint8_t aHeader) { - OT_UNUSED_VARIABLE(aCommand); - OT_UNUSED_VARIABLE(aArgPtr); - OT_UNUSED_VARIABLE(aArgLen); - return SendLastStatus(aHeader, SPINEL_STATUS_UNIMPLEMENTED); } -otError NcpBase::CommandHandler_NET_CLEAR(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, - uint16_t aArgLen) +otError NcpBase::CommandHandler_NET_CLEAR(uint8_t aHeader) { - OT_UNUSED_VARIABLE(aCommand); - OT_UNUSED_VARIABLE(aArgPtr); - OT_UNUSED_VARIABLE(aArgLen); - return SendLastStatus(aHeader, ThreadErrorToSpinelStatus(otInstanceErasePersistentInfo(mInstance))); } -otError NcpBase::CommandHandler_NET_RECALL(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, - uint16_t aArgLen) +otError NcpBase::CommandHandler_NET_RECALL(uint8_t aHeader) { - OT_UNUSED_VARIABLE(aCommand); - OT_UNUSED_VARIABLE(aArgPtr); - OT_UNUSED_VARIABLE(aArgLen); - return SendLastStatus(aHeader, SPINEL_STATUS_UNIMPLEMENTED); } @@ -275,26 +251,17 @@ otError NcpBase::GetPropertyHandler_NET_IF_UP(void) return mEncoder.WriteBool(otIp6IsEnabled(mInstance)); } -otError NcpBase::SetPropertyHandler_NET_IF_UP(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_NET_IF_UP(void) { bool enabled = false; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_BOOL_S, - &enabled - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadBool(enabled)); error = otIp6SetEnabled(mInstance, enabled); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_NET_STACK_UP(void) @@ -302,21 +269,12 @@ otError NcpBase::GetPropertyHandler_NET_STACK_UP(void) return mEncoder.WriteBool(otThreadGetDeviceRole(mInstance) != OT_DEVICE_ROLE_DISABLED); } -otError NcpBase::SetPropertyHandler_NET_STACK_UP(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_NET_STACK_UP(void) { bool enabled = false; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_BOOL_S, - &enabled - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadBool(enabled)); // If the value has changed... if ((enabled != false) != (otThreadGetDeviceRole(mInstance) != OT_DEVICE_ROLE_DISABLED)) @@ -350,7 +308,7 @@ otError NcpBase::SetPropertyHandler_NET_STACK_UP(uint8_t aHeader, spinel_prop_ke } exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_NET_ROLE(void) @@ -380,22 +338,12 @@ otError NcpBase::GetPropertyHandler_NET_ROLE(void) return mEncoder.WriteUint8(role); } -otError NcpBase::SetPropertyHandler_NET_ROLE(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_NET_ROLE(void) { unsigned int role = 0; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT_PACKED_S, - &role - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); - + SuccessOrExit(error = mDecoder.ReadUintPacked(role)); switch (role) { @@ -419,7 +367,7 @@ otError NcpBase::SetPropertyHandler_NET_ROLE(uint8_t aHeader, spinel_prop_key_t } exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_NET_NETWORK_NAME(void) @@ -427,26 +375,17 @@ otError NcpBase::GetPropertyHandler_NET_NETWORK_NAME(void) return mEncoder.WriteUtf8(otThreadGetNetworkName(mInstance)); } -otError NcpBase::SetPropertyHandler_NET_NETWORK_NAME(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_NET_NETWORK_NAME(void) { const char *string = NULL; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UTF8_S, - &string - ); - - VerifyOrExit((parsedLength > 0) && (string != NULL), error = OT_ERROR_PARSE); + SuccessOrExit(mDecoder.ReadUtf8(string)); error = otThreadSetNetworkName(mInstance, string); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_NET_XPANID(void) @@ -454,28 +393,20 @@ otError NcpBase::GetPropertyHandler_NET_XPANID(void) return mEncoder.WriteData(otThreadGetExtendedPanId(mInstance), sizeof(spinel_net_xpanid_t)); } -otError NcpBase::SetPropertyHandler_NET_XPANID(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_NET_XPANID(void) { const uint8_t *ptr = NULL; - spinel_size_t len; - spinel_ssize_t parsedLength; + uint16_t len; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_DATA_S, - &ptr, - &len - ); + SuccessOrExit(error = mDecoder.ReadData(ptr, len)); - VerifyOrExit((parsedLength > 0) && (len == sizeof(spinel_net_xpanid_t)), error = OT_ERROR_PARSE); + VerifyOrExit(len == sizeof(spinel_net_xpanid_t), error = OT_ERROR_PARSE); error = otThreadSetExtendedPanId(mInstance, ptr); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_NET_MASTER_KEY(void) @@ -483,28 +414,20 @@ otError NcpBase::GetPropertyHandler_NET_MASTER_KEY(void) return mEncoder.WriteData(otThreadGetMasterKey(mInstance)->m8, OT_MASTER_KEY_SIZE); } -otError NcpBase::SetPropertyHandler_NET_MASTER_KEY(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_NET_MASTER_KEY(void) { const uint8_t *ptr = NULL; - spinel_size_t len; - spinel_ssize_t parsedLength; + uint16_t len; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_DATA_S, - &ptr, - &len - ); + SuccessOrExit(error = mDecoder.ReadData(ptr, len)); - VerifyOrExit((parsedLength > 0) && (len == OT_MASTER_KEY_SIZE), error = OT_ERROR_PARSE); + VerifyOrExit(len == OT_MASTER_KEY_SIZE, error = OT_ERROR_PARSE); error = otThreadSetMasterKey(mInstance, reinterpret_cast(ptr)); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_NET_KEY_SEQUENCE_COUNTER(void) @@ -512,26 +435,17 @@ otError NcpBase::GetPropertyHandler_NET_KEY_SEQUENCE_COUNTER(void) return mEncoder.WriteUint32(otThreadGetKeySequenceCounter(mInstance)); } -otError NcpBase::SetPropertyHandler_NET_KEY_SEQUENCE_COUNTER(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_NET_KEY_SEQUENCE_COUNTER(void) { - unsigned int keySeqCounter; - spinel_ssize_t parsedLength; + uint32_t keySeqCounter; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT32_S, - &keySeqCounter - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUint32(keySeqCounter)); otThreadSetKeySequenceCounter(mInstance, keySeqCounter); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_NET_PARTITION_ID(void) @@ -544,26 +458,17 @@ otError NcpBase::GetPropertyHandler_NET_KEY_SWITCH_GUARDTIME(void) return mEncoder.WriteUint32(otThreadGetKeySwitchGuardTime(mInstance)); } -otError NcpBase::SetPropertyHandler_NET_KEY_SWITCH_GUARDTIME(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_NET_KEY_SWITCH_GUARDTIME(void) { - unsigned int keyGuardTime; - spinel_ssize_t parsedLength; + uint32_t keyGuardTime; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT32_S, - &keyGuardTime - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUint32(keyGuardTime)); otThreadSetKeySwitchGuardTime(mInstance, keyGuardTime); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_THREAD_NETWORK_DATA_VERSION(void) @@ -735,57 +640,36 @@ exit: return error; } -otError NcpBase::SetPropertyHandler_THREAD_ASSISTING_PORTS(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_THREAD_ASSISTING_PORTS(void) { uint8_t numEntries = 0; const uint16_t *ports = otIp6GetUnsecurePorts(mInstance, &numEntries); - spinel_ssize_t parsedLength; - bool portsChanged = false; otError error = OT_ERROR_NONE; // First, we need to remove all of the current assisting ports. for (; numEntries != 0; ports++, numEntries--) { SuccessOrExit(error = otIp6RemoveUnsecurePort(mInstance, *ports)); - portsChanged = true; } - while (aValueLen >= 2) + while (mDecoder.GetRemainingLengthInStruct() >= sizeof(uint16_t)) { uint16_t port; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT16_S, - &port - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(mDecoder.ReadUint16(port)); SuccessOrExit(error = otIp6AddUnsecurePort(mInstance, port)); - - aValuePtr += parsedLength; - aValueLen -= parsedLength; - - portsChanged = true; } - // No error happened so the new state of ports will - // be reported in the response. - portsChanged = false; - exit: - error = SendSetPropertyResponse(aHeader, aKey, error); - if (portsChanged) + if (error != OT_ERROR_NONE) { // We had an error, but we've actually changed - // the state of these ports---so we need to report + // the state of these ports, so we need to report // those incomplete changes via an asynchronous // change event. - HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, aKey); + HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_PROP_THREAD_ASSISTING_PORTS); } return error; @@ -797,22 +681,13 @@ otError NcpBase::GetPropertyHandler_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE(void) } #if OPENTHREAD_ENABLE_BORDER_ROUTER -otError NcpBase::SetPropertyHandler_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE(void) { bool value = false; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; bool shouldRegisterWithLeader = false; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_BOOL_S, - &value - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadBool(value)); // Register any net data changes on transition from `true` to `false`. shouldRegisterWithLeader = (mAllowLocalNetworkDataChange == true) && (value == false); @@ -820,7 +695,6 @@ otError NcpBase::SetPropertyHandler_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE(uint8_t a mAllowLocalNetworkDataChange = value; exit: - error = SendSetPropertyResponse(aHeader, aKey, error); if (shouldRegisterWithLeader) { @@ -877,12 +751,10 @@ exit: } #if OPENTHREAD_ENABLE_BORDER_ROUTER -otError NcpBase::InsertPropertyHandler_THREAD_ON_MESH_NETS(const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::InsertPropertyHandler_THREAD_ON_MESH_NETS(void) { - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; otBorderRouterConfig borderRouterConfig; - otIp6Address *addrPtr; bool stable = false; uint8_t flags = 0; @@ -890,24 +762,11 @@ otError NcpBase::InsertPropertyHandler_THREAD_ON_MESH_NETS(const uint8_t *aValue VerifyOrExit(mAllowLocalNetworkDataChange == true, error = OT_ERROR_INVALID_STATE); - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - ( - SPINEL_DATATYPE_IPv6ADDR_S // On-mesh prefix - SPINEL_DATATYPE_UINT8_S // Prefix length (in bits) - SPINEL_DATATYPE_BOOL_S // Stable - SPINEL_DATATYPE_UINT8_S // Flags - ), - &addrPtr, - &borderRouterConfig.mPrefix.mLength, - &stable, - &flags - ); + SuccessOrExit(error = mDecoder.ReadIp6Address(borderRouterConfig.mPrefix.mPrefix)); + SuccessOrExit(error = mDecoder.ReadUint8(borderRouterConfig.mPrefix.mLength)); + SuccessOrExit(error = mDecoder.ReadBool(stable)); + SuccessOrExit(error = mDecoder.ReadUint8(flags)); - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); - - borderRouterConfig.mPrefix.mPrefix = *addrPtr; borderRouterConfig.mStable = stable; borderRouterConfig.mPreference = ((flags & SPINEL_NET_FLAG_PREFERENCE_MASK) >> SPINEL_NET_FLAG_PREFERENCE_OFFSET); @@ -924,31 +783,17 @@ exit: return error; } -otError NcpBase::RemovePropertyHandler_THREAD_ON_MESH_NETS(const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::RemovePropertyHandler_THREAD_ON_MESH_NETS(void) { - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; otIp6Prefix ip6Prefix; - otIp6Address *addrPtr; memset(&ip6Prefix, 0, sizeof(otIp6Prefix)); VerifyOrExit(mAllowLocalNetworkDataChange == true, error = OT_ERROR_INVALID_STATE); - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - ( - SPINEL_DATATYPE_IPv6ADDR_S // On-mesh prefix - SPINEL_DATATYPE_UINT8_S // Prefix length (in bits) - ), - &addrPtr, - &ip6Prefix.mLength - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); - - ip6Prefix.mPrefix = *addrPtr; + SuccessOrExit(error = mDecoder.ReadIp6Address(ip6Prefix.mPrefix)); + SuccessOrExit(error = mDecoder.ReadUint8(ip6Prefix.mLength)); error = otBorderRouterRemoveOnMeshPrefix(mInstance, &ip6Prefix); @@ -970,26 +815,9 @@ otError NcpBase::GetPropertyHandler_THREAD_DISCOVERY_SCAN_JOINER_FLAG(void) return mEncoder.WriteBool(mDiscoveryScanJoinerFlag); } -otError NcpBase::SetPropertyHandler_THREAD_DISCOVERY_SCAN_JOINER_FLAG(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_THREAD_DISCOVERY_SCAN_JOINER_FLAG(void) { - bool joinerFlag = false; - spinel_ssize_t parsedLength; - otError error = OT_ERROR_NONE; - - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_BOOL_S, - &joinerFlag - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); - - mDiscoveryScanJoinerFlag = joinerFlag; - -exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return mDecoder.ReadBool(mDiscoveryScanJoinerFlag); } otError NcpBase::GetPropertyHandler_THREAD_DISCOVERY_SCAN_ENABLE_FILTERING(void) @@ -997,27 +825,9 @@ otError NcpBase::GetPropertyHandler_THREAD_DISCOVERY_SCAN_ENABLE_FILTERING(void) return mEncoder.WriteBool(mDiscoveryScanEnableFiltering); } -otError NcpBase::SetPropertyHandler_THREAD_DISCOVERY_SCAN_ENABLE_FILTERING(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_THREAD_DISCOVERY_SCAN_ENABLE_FILTERING(void) { - bool enabled = false; - spinel_ssize_t parsedLength; - otError error = OT_ERROR_NONE; - - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_BOOL_S, - &enabled - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); - - mDiscoveryScanEnableFiltering = enabled; - -exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return mDecoder.ReadBool(mDiscoveryScanEnableFiltering); } otError NcpBase::GetPropertyHandler_THREAD_DISCOVERY_SCAN_PANID(void) @@ -1025,26 +835,9 @@ otError NcpBase::GetPropertyHandler_THREAD_DISCOVERY_SCAN_PANID(void) return mEncoder.WriteUint16(mDiscoveryScanPanId); } -otError NcpBase::SetPropertyHandler_THREAD_DISCOVERY_SCAN_PANID(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_THREAD_DISCOVERY_SCAN_PANID(void) { - uint16_t panid; - spinel_ssize_t parsedLength; - otError error = OT_ERROR_NONE; - - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT16_S, - &panid - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); - - mDiscoveryScanPanId = panid; - -exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return mDecoder.ReadUint16(mDiscoveryScanPanId); } otError NcpBase::GetPropertyHandler_IPV6_ML_PREFIX(void) @@ -1067,17 +860,20 @@ exit: return error; } -otError NcpBase::SetPropertyHandler_IPV6_ML_PREFIX(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_IPV6_ML_PREFIX(void) { otError error = OT_ERROR_NONE; + const uint8_t *meshLocalPrefix; + uint16_t prefixLength; - VerifyOrExit(aValueLen >= 8, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadData(meshLocalPrefix, prefixLength)); - error = otThreadSetMeshLocalPrefix(mInstance, aValuePtr); + VerifyOrExit(prefixLength >= 8, error = OT_ERROR_PARSE); + + error = otThreadSetMeshLocalPrefix(mInstance, meshLocalPrefix); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_IPV6_ML_ADDR(void) @@ -1124,37 +920,20 @@ exit: return error; } -otError NcpBase::InsertPropertyHandler_IPV6_ADDRESS_TABLE(const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::InsertPropertyHandler_IPV6_ADDRESS_TABLE(void) { - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; otNetifAddress netifAddr; - otIp6Address *addrPtr; uint32_t preferredLifetime; uint32_t validLifetime; - uint8_t prefixLen; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - ( - SPINEL_DATATYPE_IPv6ADDR_S // IPv6 address - SPINEL_DATATYPE_UINT8_S // Prefix length (in bits) - SPINEL_DATATYPE_UINT32_S // Preferred lifetime - SPINEL_DATATYPE_UINT32_S // Valid lifetime - ), - &addrPtr, - &prefixLen, - &preferredLifetime, - &validLifetime - ); + SuccessOrExit(error = mDecoder.ReadIp6Address(netifAddr.mAddress)); + SuccessOrExit(error = mDecoder.ReadUint8(netifAddr.mPrefixLength)); + SuccessOrExit(error = mDecoder.ReadUint32(preferredLifetime)); + SuccessOrExit(error = mDecoder.ReadUint32(validLifetime)); - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); - - netifAddr.mAddress = *addrPtr; - netifAddr.mPrefixLength = prefixLen; - netifAddr.mPreferred = preferredLifetime != 0; - netifAddr.mValid = validLifetime != 0; + netifAddr.mPreferred = (preferredLifetime != 0); + netifAddr.mValid = (validLifetime != 0); error = otIp6AddUnicastAddress(mInstance, &netifAddr); @@ -1162,20 +941,12 @@ exit: return error; } -otError NcpBase::RemovePropertyHandler_IPV6_ADDRESS_TABLE(const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::RemovePropertyHandler_IPV6_ADDRESS_TABLE(void) { - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - otIp6Address *addrPtr; + const otIp6Address *addrPtr; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_IPv6ADDR_S, - &addrPtr - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadIp6Address(addrPtr)); error = otIp6RemoveUnicastAddress(mInstance, addrPtr); @@ -1200,26 +971,17 @@ otError NcpBase::GetPropertyHandler_IPV6_ICMP_PING_OFFLOAD(void) return mEncoder.WriteBool(otIcmp6IsEchoEnabled(mInstance)); } -otError NcpBase::SetPropertyHandler_IPV6_ICMP_PING_OFFLOAD(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_IPV6_ICMP_PING_OFFLOAD(void) { bool enabled = false; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_BOOL_S, - &enabled - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadBool(enabled)); otIcmp6SetEchoEnabled(mInstance, enabled); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_IPV6_MULTICAST_ADDRESS_TABLE(void) @@ -1238,20 +1000,12 @@ exit: return error; } -otError NcpBase::InsertPropertyHandler_IPV6_MULTICAST_ADDRESS_TABLE(const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::InsertPropertyHandler_IPV6_MULTICAST_ADDRESS_TABLE(void) { - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - otIp6Address *addrPtr; + const otIp6Address *addrPtr; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_IPv6ADDR_S, // IPv6 address - &addrPtr - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadIp6Address(addrPtr)); error = otIp6SubscribeMulticastAddress(mInstance, addrPtr); @@ -1264,20 +1018,12 @@ exit: return error; } -otError NcpBase::RemovePropertyHandler_IPV6_MULTICAST_ADDRESS_TABLE(const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::RemovePropertyHandler_IPV6_MULTICAST_ADDRESS_TABLE(void) { - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - otIp6Address *addrPtr; + const otIp6Address *addrPtr; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_IPv6ADDR_S, - &addrPtr - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadIp6Address(addrPtr)); error = otIp6UnsubscribeMulticastAddress(mInstance, addrPtr); @@ -1298,27 +1044,18 @@ otError NcpBase::GetPropertyHandler_THREAD_RLOC16_DEBUG_PASSTHRU(void) return mEncoder.WriteBool(!otIp6IsReceiveFilterEnabled(mInstance)); } -otError NcpBase::SetPropertyHandler_THREAD_RLOC16_DEBUG_PASSTHRU(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_THREAD_RLOC16_DEBUG_PASSTHRU(void) { bool enabled = false; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_BOOL_S, - &enabled - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadBool(enabled)); // Note reverse logic: passthru enabled = filter disabled otIp6SetReceiveFilterEnabled(mInstance, !enabled); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_THREAD_OFF_MESH_ROUTES(void) @@ -1389,12 +1126,10 @@ static int FlagByteToExternalRoutePreference(uint8_t aFlags) return route_preference; } -otError NcpBase::InsertPropertyHandler_THREAD_OFF_MESH_ROUTES(const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::InsertPropertyHandler_THREAD_OFF_MESH_ROUTES(void) { - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; otExternalRouteConfig routeConfig; - otIp6Address *addrPtr; bool stable = false; uint8_t flags = 0; @@ -1402,24 +1137,11 @@ otError NcpBase::InsertPropertyHandler_THREAD_OFF_MESH_ROUTES(const uint8_t *aVa VerifyOrExit(mAllowLocalNetworkDataChange == true, error = OT_ERROR_INVALID_STATE); - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - ( - SPINEL_DATATYPE_IPv6ADDR_S // Route prefix - SPINEL_DATATYPE_UINT8_S // Prefix length (in bits) - SPINEL_DATATYPE_BOOL_S // Stable - SPINEL_DATATYPE_UINT8_S // Flags (Route Preference) - ), - &addrPtr, - &routeConfig.mPrefix.mLength, - &stable, - &flags - ); + SuccessOrExit(error = mDecoder.ReadIp6Address(routeConfig.mPrefix.mPrefix)); + SuccessOrExit(error = mDecoder.ReadUint8(routeConfig.mPrefix.mLength)); + SuccessOrExit(error = mDecoder.ReadBool(stable)); + SuccessOrExit(error = mDecoder.ReadUint8(flags)); - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); - - routeConfig.mPrefix.mPrefix = *addrPtr; routeConfig.mStable = stable; routeConfig.mPreference = FlagByteToExternalRoutePreference(flags); @@ -1429,31 +1151,17 @@ exit: return error; } -otError NcpBase::RemovePropertyHandler_THREAD_OFF_MESH_ROUTES(const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::RemovePropertyHandler_THREAD_OFF_MESH_ROUTES(void) { - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; otIp6Prefix ip6Prefix; - otIp6Address *addrPtr; memset(&ip6Prefix, 0, sizeof(otIp6Prefix)); VerifyOrExit(mAllowLocalNetworkDataChange == true, error = OT_ERROR_INVALID_STATE); - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - ( - SPINEL_DATATYPE_IPv6ADDR_S // Route prefix - SPINEL_DATATYPE_UINT8_S // Prefix length (in bits) - ), - &addrPtr, - &ip6Prefix.mLength - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); - - ip6Prefix.mPrefix = *addrPtr; + SuccessOrExit(error = mDecoder.ReadIp6Address(ip6Prefix.mPrefix)); + SuccessOrExit(error = mDecoder.ReadUint8(ip6Prefix.mLength)); error = otBorderRouterRemoveRoute(mInstance, &ip6Prefix); @@ -1468,45 +1176,26 @@ exit: } #endif // OPENTHREAD_ENABLE_BORDER_ROUTER -otError NcpBase::GetPropertyHandler_STREAM_NET(void) -{ - // TODO: Implement explicit data poll. - return mEncoder.OverwriteWithLastStatusError(SPINEL_STATUS_UNIMPLEMENTED); -} - -otError NcpBase::SetPropertyHandler_STREAM_NET(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_STREAM_NET(void) { const uint8_t *framePtr = NULL; - unsigned int frameLen = 0; + uint16_t frameLen = 0; const uint8_t *metaPtr = NULL; - unsigned int metaLen = 0; - otMessage *message; - spinel_ssize_t parsedLength; + uint16_t metaLen = 0; + otMessage *message = NULL; otError error = OT_ERROR_NONE; // STREAM_NET requires layer 2 security. message = otIp6NewMessage(mInstance, true); VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS); - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - ( - SPINEL_DATATYPE_DATA_WLEN_S // Frame data - SPINEL_DATATYPE_DATA_S // Meta data - ), - &framePtr, - &frameLen, - &metaPtr, - &metaLen - ); + SuccessOrExit(error = mDecoder.ReadDataWithLen(framePtr, frameLen)); + SuccessOrExit(error = mDecoder.ReadData(metaPtr, metaLen)); // We ignore metadata for now. // May later include TX power, allow retransmits, etc... OT_UNUSED_VARIABLE(metaPtr); OT_UNUSED_VARIABLE(metaLen); - OT_UNUSED_VARIABLE(parsedLength); SuccessOrExit(error = otMessageAppend(message, framePtr, static_cast(frameLen))); @@ -1527,23 +1216,12 @@ exit: if (error == OT_ERROR_NONE) { mInboundSecureIpFrameCounter++; - - if (SPINEL_HEADER_GET_TID(aHeader) != 0) - { - // Only send a successful status update if - // there was a transaction id in the aHeader. - error = SendLastStatus(aHeader, SPINEL_STATUS_OK); - } } else { mDroppedInboundIpFrameCounter++; - - error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error)); } - OT_UNUSED_VARIABLE(aKey); - return error; } @@ -1589,21 +1267,12 @@ exit: return error; } -otError NcpBase::SetPropertyHandler_JAM_DETECT_ENABLE(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_JAM_DETECT_ENABLE(void) { bool enabled; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_BOOL_S, - &enabled - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadBool(enabled)); if (enabled) { @@ -1615,73 +1284,46 @@ otError NcpBase::SetPropertyHandler_JAM_DETECT_ENABLE(uint8_t aHeader, spinel_pr } exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } -otError NcpBase::SetPropertyHandler_JAM_DETECT_RSSI_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_JAM_DETECT_RSSI_THRESHOLD(void) { int8_t threshold = 0; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_INT8_S, - &threshold - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadInt8(threshold)); error = otJamDetectionSetRssiThreshold(mInstance, threshold); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } -otError NcpBase::SetPropertyHandler_JAM_DETECT_WINDOW(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_JAM_DETECT_WINDOW(void) { uint8_t window = 0; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT8_S, - &window - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUint8(window)); error = otJamDetectionSetWindow(mInstance, window); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } -otError NcpBase::SetPropertyHandler_JAM_DETECT_BUSY(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_JAM_DETECT_BUSY(void) { uint8_t busy = 0; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT8_S, - &busy - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUint8(busy)); error = otJamDetectionSetBusyPeriod(mInstance, busy); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } void NcpBase::HandleJamStateChange_Jump(bool aJamState, void *aContext) @@ -2021,93 +1663,68 @@ exit: return error; } -otError NcpBase::SetPropertyHandler_MAC_WHITELIST(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_MAC_WHITELIST(void) { - bool reportAsync; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; // First, clear the address filter entries. otLinkFilterClearAddresses(mInstance); - while (aValueLen > 0) + while (mDecoder.GetRemainingLengthInStruct() > 0) { - otExtAddress *extAddress = NULL; + const otExtAddress *extAddress = NULL; int8_t rss; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_STRUCT_S( - SPINEL_DATATYPE_EUI64_S - SPINEL_DATATYPE_INT8_S - ), - &extAddress, - &rss - ); + SuccessOrExit(error = mDecoder.OpenStruct()); + SuccessOrExit(error = mDecoder.ReadEui64(extAddress)); - if (parsedLength <= 0) + if (!mDecoder.IsAllReadInStruct()) + { + SuccessOrExit(error = mDecoder.ReadInt8(rss)); + } + else { rss = OT_MAC_FILTER_FIXED_RSS_DISABLED; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_STRUCT_S( - SPINEL_DATATYPE_EUI64_S - ), - &extAddress - ); } - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.CloseStruct()); error = otLinkFilterAddAddress(mInstance, extAddress); - VerifyOrExit(error == OT_ERROR_NONE || error == OT_ERROR_ALREADY); + if (error == OT_ERROR_ALREADY) + { + error = OT_ERROR_NONE; + } + + SuccessOrExit(error); if (rss != OT_MAC_FILTER_FIXED_RSS_DISABLED) { SuccessOrExit(error = otLinkFilterAddRssIn(mInstance, extAddress, rss)); } - - aValuePtr += parsedLength; - aValueLen -= parsedLength; } exit: // If we had an error, we may have actually changed - // the state of the whitelist---so we need to report + // the state of the whitelist, so we need to report // those incomplete changes via an asynchronous // change event. - reportAsync = (error != OT_ERROR_NONE && error != OT_ERROR_ALREADY); - error = SendSetPropertyResponse(aHeader, aKey, error); - - if (reportAsync) + if (error != OT_ERROR_NONE) { - HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, aKey); + HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_PROP_MAC_WHITELIST); } return error; } -otError NcpBase::SetPropertyHandler_MAC_WHITELIST_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_MAC_WHITELIST_ENABLED(void) { bool enabled; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; otMacFilterAddressMode mode = OT_MAC_FILTER_ADDRESS_MODE_DISABLED; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_BOOL_S, - &enabled - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadBool(enabled)); if (enabled) { @@ -2117,75 +1734,55 @@ otError NcpBase::SetPropertyHandler_MAC_WHITELIST_ENABLED(uint8_t aHeader, spine error = otLinkFilterSetAddressMode(mInstance, mode); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } -otError NcpBase::SetPropertyHandler_MAC_BLACKLIST(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_MAC_BLACKLIST(void) { - bool reportAsync; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; // First, clear the address filter entries. otLinkFilterClearAddresses(mInstance); - while (aValueLen > 0) + while (mDecoder.GetRemainingLengthInStruct() > 0) { - otExtAddress *extAddress = NULL; + const otExtAddress *extAddress = NULL; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_STRUCT_S( - SPINEL_DATATYPE_EUI64_S - ), - &extAddress - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.OpenStruct()); + SuccessOrExit(error = mDecoder.ReadEui64(extAddress)); + SuccessOrExit(error = mDecoder.CloseStruct()); error = otLinkFilterRemoveAddress(mInstance, extAddress); - VerifyOrExit(error == OT_ERROR_NONE || error == OT_ERROR_ALREADY); + if (error == OT_ERROR_ALREADY) + { + error = OT_ERROR_NONE; + } - aValuePtr += parsedLength; - aValueLen -= parsedLength; + SuccessOrExit(error); } exit: // If we had an error, we may have actually changed - // the state of the blacklist---so we need to report + // the state of the blacklist, so we need to report // those incomplete changes via an asynchronous // change event. - reportAsync = (error != OT_ERROR_NONE && error != OT_ERROR_ALREADY); - error = SendSetPropertyResponse(aHeader, aKey, error); - - if (reportAsync) + if (error != OT_ERROR_NONE) { - HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, aKey); + HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_PROP_MAC_BLACKLIST); } return error; } -otError NcpBase::SetPropertyHandler_MAC_BLACKLIST_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_MAC_BLACKLIST_ENABLED(void) { bool enabled; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; otMacFilterAddressMode mode = OT_MAC_FILTER_ADDRESS_MODE_DISABLED; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_BOOL_S, - &enabled - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadBool(enabled)); if (enabled) { @@ -2195,68 +1792,48 @@ otError NcpBase::SetPropertyHandler_MAC_BLACKLIST_ENABLED(uint8_t aHeader, spine error = otLinkFilterSetAddressMode(mInstance, mode); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } -otError NcpBase::SetPropertyHandler_MAC_FIXED_RSS(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_MAC_FIXED_RSS(void) { - bool reportAsync; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; // First, clear the address filter entries. otLinkFilterClearRssIn(mInstance); - while (aValueLen > 0) + while (mDecoder.GetRemainingLengthInStruct() > 0) { - otExtAddress *extAddress; + const otExtAddress *extAddress; int8_t rss; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_STRUCT_S( - SPINEL_DATATYPE_EUI64_S - SPINEL_DATATYPE_INT8_S - ), - &extAddress, - &rss - ); + SuccessOrExit(error = mDecoder.OpenStruct()); - if (parsedLength < 0) + if (mDecoder.GetRemainingLengthInStruct() > sizeof(otExtAddress)) + { + SuccessOrExit(error = mDecoder.ReadEui64(extAddress)); + } + else { extAddress = NULL; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_STRUCT_S( - SPINEL_DATATYPE_INT8_S - ), - &rss - ); } - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadInt8(rss)); + + SuccessOrExit(error = mDecoder.CloseStruct()); SuccessOrExit(error = otLinkFilterAddRssIn(mInstance, extAddress, rss)); - - aValuePtr += parsedLength; - aValueLen -= parsedLength; } exit: // If we had an error, we may have actually changed - // the state of the RssIn filter---so we need to report + // the state of the RssIn filter, so we need to report // those incomplete changes via an asynchronous // change event. - reportAsync = (error != OT_ERROR_NONE); - error = SendSetPropertyResponse(aHeader, aKey, error); - - if (reportAsync) + if (error != OT_ERROR_NONE) { - HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, aKey); + HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_PROP_MAC_FIXED_RSS); } return error; @@ -2278,22 +1855,13 @@ otError NcpBase::GetPropertyHandler_THREAD_MODE(void) return mEncoder.WriteUint8(numericMode); } -otError NcpBase::SetPropertyHandler_THREAD_MODE(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_THREAD_MODE(void) { uint8_t numericMode = 0; otLinkModeConfig modeConfig; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT8_S, - &numericMode - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(mDecoder.ReadUint8(numericMode)); modeConfig.mRxOnWhenIdle = ((numericMode & SPINEL_THREAD_MODE_RX_ON_WHEN_IDLE) == SPINEL_THREAD_MODE_RX_ON_WHEN_IDLE); modeConfig.mSecureDataRequests = @@ -2304,7 +1872,7 @@ otError NcpBase::SetPropertyHandler_THREAD_MODE(uint8_t aHeader, spinel_prop_key error = otThreadSetLinkMode(mInstance, modeConfig); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_THREAD_CHILD_TIMEOUT(void) @@ -2322,61 +1890,31 @@ otError NcpBase::GetPropertyHandler_NET_REQUIRE_JOIN_EXISTING(void) return mEncoder.WriteBool(mRequireJoinExistingNetwork); } -otError NcpBase::SetPropertyHandler_NET_REQUIRE_JOIN_EXISTING(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_NET_REQUIRE_JOIN_EXISTING(void) { - bool value = mRequireJoinExistingNetwork; - spinel_ssize_t parsedLength; - otError error = OT_ERROR_NONE; - - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_BOOL_S, - &value - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); - - mRequireJoinExistingNetwork = value; - -exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return mDecoder.ReadBool(mRequireJoinExistingNetwork); } -otError NcpBase::SetPropertyHandler_STREAM_NET_INSECURE(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_STREAM_NET_INSECURE(void) { const uint8_t *framePtr = NULL; - unsigned int frameLen = 0; + uint16_t frameLen = 0; const uint8_t *metaPtr = NULL; - unsigned int metaLen = 0; - otMessage *message; - spinel_ssize_t parsedLength; + uint16_t metaLen = 0; + otMessage *message = NULL; otError error = OT_ERROR_NONE; // STREAM_NET_INSECURE packets are not secured at layer 2. message = otIp6NewMessage(mInstance, false); VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS); - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - ( - SPINEL_DATATYPE_DATA_WLEN_S // Frame data - SPINEL_DATATYPE_DATA_S // Meta data - ), - &framePtr, - &frameLen, - &metaPtr, - &metaLen - ); + SuccessOrExit(mDecoder.ReadDataWithLen(framePtr, frameLen)); + SuccessOrExit(mDecoder.ReadData(metaPtr, metaLen)); // We ignore metadata for now. // May later include TX power, allow retransmits, etc... OT_UNUSED_VARIABLE(metaPtr); OT_UNUSED_VARIABLE(metaLen); - OT_UNUSED_VARIABLE(parsedLength); SuccessOrExit(error = otMessageAppend(message, framePtr, static_cast(frameLen))); @@ -2400,41 +1938,21 @@ exit: { mInboundInsecureIpFrameCounter++; - if (SPINEL_HEADER_GET_TID(aHeader) != 0) - { - // Only send a successful status update if - // there was a transaction id in the aHeader. - error = SendLastStatus(aHeader, SPINEL_STATUS_OK); - } } else { mDroppedInboundIpFrameCounter++; - - error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error)); } - OT_UNUSED_VARIABLE(aKey); - return error; } - -otError NcpBase::SetPropertyHandler_CNTR_RESET(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_CNTR_RESET(void) { uint8_t value = 0; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT8_S, - &value - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUint8(value)); VerifyOrExit(value == 1, error = OT_ERROR_INVALID_ARGS); @@ -2442,70 +1960,41 @@ otError NcpBase::SetPropertyHandler_CNTR_RESET(uint8_t aHeader, spinel_prop_key_ error = OT_ERROR_NOT_IMPLEMENTED; exit: - OT_UNUSED_VARIABLE(aKey); - - // There is currently no getter for PROP_CNTR_RESET, so we just - // return SPINEL_STATUS_OK for success when the counters are reset. - - return SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error)); + return error; } - #if OPENTHREAD_ENABLE_DIAG -otError NcpBase::SetPropertyHandler_NEST_STREAM_MFG(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_NEST_STREAM_MFG(uint8_t aHeader) { - char *string = NULL; + const char *string = NULL; char *output = NULL; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UTF8_S, - &string - ); + error = mDecoder.ReadUtf8(string); - - - VerifyOrExit((parsedLength > 0) && (string != NULL), spinelError = SPINEL_STATUS_PARSE_ERROR); + VerifyOrExit(error == OT_ERROR_NONE, error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error))); // All diagnostics related features are processed within diagnostics module - output = otDiagProcessCmdLine(string); + output = otDiagProcessCmdLine(const_cast(string)); - SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey)); + // Prepare the response + SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, SPINEL_PROP_NEST_STREAM_MFG)); SuccessOrExit(error = mEncoder.WriteUtf8(output)); SuccessOrExit(error = mEncoder.EndFrame()); exit: - - if (spinelError != SPINEL_STATUS_OK) - { - error = SendLastStatus(aHeader, spinelError); - } - return error; } #endif // OPENTHREAD_ENABLE_DIAG -otError NcpBase::InsertPropertyHandler_THREAD_ASSISTING_PORTS(const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::InsertPropertyHandler_THREAD_ASSISTING_PORTS(void) { - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; uint16_t port; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT16_S, - &port - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUint16(port)); error = otIp6AddUnsecurePort(mInstance, port); exit: @@ -2514,34 +2003,18 @@ exit: #if OPENTHREAD_ENABLE_MAC_FILTER -otError NcpBase::InsertPropertyHandler_MAC_WHITELIST(const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::InsertPropertyHandler_MAC_WHITELIST(void) { - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - otExtAddress *extAddress = NULL; + const otExtAddress *extAddress = NULL; int8_t rss = OT_MAC_FILTER_FIXED_RSS_DISABLED; - if (aValueLen > static_cast(sizeof(otExtAddress))) - { - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_EUI64_S SPINEL_DATATYPE_INT8_S, - &extAddress, - &rss - ); - } - else - { - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_EUI64_S, - &extAddress - ); - } + SuccessOrExit(error = mDecoder.ReadEui64(extAddress)); - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + if (!mDecoder.IsAllRead()) + { + SuccessOrExit(error = mDecoder.ReadInt8(rss)); + } error = otLinkFilterAddAddress(mInstance, extAddress); @@ -2561,20 +2034,12 @@ exit: return error; } -otError NcpBase::InsertPropertyHandler_MAC_BLACKLIST(const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::InsertPropertyHandler_MAC_BLACKLIST(void) { - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - otExtAddress *extAddress = NULL; + const otExtAddress *extAddress = NULL; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_EUI64_S, - &extAddress - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadEui64(extAddress)); error = otLinkFilterAddAddress(mInstance, extAddress); @@ -2587,34 +2052,18 @@ exit: return error; } -otError NcpBase::InsertPropertyHandler_MAC_FIXED_RSS(const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::InsertPropertyHandler_MAC_FIXED_RSS(void) { - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - otExtAddress *extAddress = NULL; + const otExtAddress *extAddress = NULL; int8_t rss = OT_MAC_FILTER_FIXED_RSS_DISABLED; - if (aValueLen > sizeof(int8_t)) + if (mDecoder.GetRemainingLength() > sizeof(int8_t)) { - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_EUI64_S SPINEL_DATATYPE_INT8_S, - &extAddress, - &rss - ); - } - else - { - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_INT8_S, - &rss - ); + SuccessOrExit(mDecoder.ReadEui64(extAddress)); } - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(mDecoder.ReadInt8(rss)); error = otLinkFilterAddRssIn(mInstance, extAddress, rss); @@ -2624,20 +2073,12 @@ exit: #endif // OPENTHREAD_ENABLE_MAC_FILTER -otError NcpBase::RemovePropertyHandler_THREAD_ASSISTING_PORTS(const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::RemovePropertyHandler_THREAD_ASSISTING_PORTS(void) { - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; uint16_t port; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT16_S, - &port - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUint16(port)); error = otIp6RemoveUnsecurePort(mInstance, port); @@ -2653,20 +2094,12 @@ exit: #if OPENTHREAD_ENABLE_MAC_FILTER -otError NcpBase::RemovePropertyHandler_MAC_WHITELIST(const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::RemovePropertyHandler_MAC_WHITELIST(void) { - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - otExtAddress *extAddress = NULL; + const otExtAddress *extAddress = NULL; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_EUI64_S, - &extAddress - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadEui64(extAddress)); error = otLinkFilterRemoveAddress(mInstance, extAddress); @@ -2679,20 +2112,12 @@ exit: return error; } -otError NcpBase::RemovePropertyHandler_MAC_BLACKLIST(const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::RemovePropertyHandler_MAC_BLACKLIST(void) { - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - otExtAddress *extAddress = NULL; + const otExtAddress *extAddress = NULL; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_EUI64_S, - &extAddress - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadEui64(extAddress)); error = otLinkFilterRemoveAddress(mInstance, extAddress); @@ -2705,22 +2130,14 @@ exit: return error; } -otError NcpBase::RemovePropertyHandler_MAC_FIXED_RSS(const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::RemovePropertyHandler_MAC_FIXED_RSS(void) { - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - otExtAddress *extAddress = NULL; + const otExtAddress *extAddress = NULL; - if (aValueLen > 0) + if (mDecoder.GetRemainingLength() > 0) { - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_EUI64_S, - &extAddress - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadEui64(extAddress)); } error = otLinkFilterRemoveRssIn(mInstance, extAddress); @@ -2794,23 +2211,15 @@ otError NcpBase::GetPropertyHandler_NEST_LEGACY_ULA_PREFIX(void) return mEncoder.WriteData(mLegacyUlaPrefix, sizeof(mLegacyUlaPrefix)); } -otError NcpBase::SetPropertyHandler_NEST_LEGACY_ULA_PREFIX(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_NEST_LEGACY_ULA_PREFIX(void) { const uint8_t *ptr = NULL; - spinel_size_t len; - spinel_ssize_t parsedLength; + uint16_t len; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_DATA_S, - &ptr, - &len - ); + SuccessOrExit(error = mDecoder.ReadData(ptr, len)); - VerifyOrExit((parsedLength > 0) && (len <= sizeof(mLegacyUlaPrefix)), error = OT_ERROR_PARSE); + VerifyOrExit(len <= sizeof(mLegacyUlaPrefix), error = OT_ERROR_PARSE); memset(mLegacyUlaPrefix, 0, sizeof(mLegacyUlaPrefix)); memcpy(mLegacyUlaPrefix, ptr, len); @@ -2821,7 +2230,7 @@ otError NcpBase::SetPropertyHandler_NEST_LEGACY_ULA_PREFIX(uint8_t aHeader, spin } exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_NEST_LEGACY_LAST_NODE_JOINED(void) @@ -2858,24 +2267,27 @@ otError NcpBase::GetPropertyHandler_MAC_SCAN_MASK(void) return GetPropertyHandler_ChannelMaskHelper(mChannelMask); } -otError NcpBase::SetPropertyHandler_MAC_SCAN_MASK(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_MAC_SCAN_MASK(void) { uint32_t newMask = 0; otError error = OT_ERROR_NONE; + const uint8_t *valuePtr; + uint16_t valueLen; - for (; aValueLen != 0; aValueLen--, aValuePtr++) + SuccessOrExit(error = mDecoder.ReadData(valuePtr, valueLen)); + + for (; valueLen != 0; valueLen--, valuePtr++) { - VerifyOrExit(aValuePtr[0] <= 31, error = OT_ERROR_INVALID_ARGS); - VerifyOrExit((mSupportedChannelMask & (1 << aValuePtr[0])) != 0, error = OT_ERROR_INVALID_ARGS); + VerifyOrExit(valuePtr[0] <= 31, error = OT_ERROR_INVALID_ARGS); + VerifyOrExit((mSupportedChannelMask & (1 << valuePtr[0])) != 0, error = OT_ERROR_INVALID_ARGS); - newMask |= (1 << aValuePtr[0]); + newMask |= (1 << valuePtr[0]); } mChannelMask = newMask; exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } otError NcpBase::GetPropertyHandler_MAC_SCAN_PERIOD(void) @@ -2883,26 +2295,9 @@ otError NcpBase::GetPropertyHandler_MAC_SCAN_PERIOD(void) return mEncoder.WriteUint16(mScanPeriod); } -otError NcpBase::SetPropertyHandler_MAC_SCAN_PERIOD(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_MAC_SCAN_PERIOD(void) { - uint16_t period = mScanPeriod; - spinel_ssize_t parsedLength; - otError error = OT_ERROR_NONE; - - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT16_S, - &period - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); - - mScanPeriod = period; - -exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return mDecoder.ReadUint16(mScanPeriod); } otError NcpBase::GetPropertyHandler_MAC_SCAN_STATE(void) @@ -2942,21 +2337,12 @@ otError NcpBase::GetPropertyHandler_MAC_SCAN_STATE(void) return mEncoder.WriteUint8(scanState); } -otError NcpBase::SetPropertyHandler_MAC_SCAN_STATE(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_MAC_SCAN_STATE(void) { uint8_t state = 0; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT8_S, - &state - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUint8(state)); switch (state) { @@ -3041,7 +2427,7 @@ otError NcpBase::SetPropertyHandler_MAC_SCAN_STATE(uint8_t aHeader, spinel_prop_ } exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } void NcpBase::HandleActiveScanResult_Jump(otActiveScanResult *aResult, void *aContext) @@ -3098,7 +2484,7 @@ void NcpBase::HandleActiveScanResult(otActiveScanResult *aResult) } else { - // We are finished with the scan, send an unsolicated + // We are finished with the scan, send an unsolicited // scan state update. mChangedPropsSet.AddProperty(SPINEL_PROP_MAC_SCAN_STATE); mUpdateChangedPropsTask.Post(); @@ -3138,7 +2524,7 @@ void NcpBase::HandleEnergyScanResult(otEnergyScanResult *aResult) } else { - // We are finished with the scan, send an unsolicated + // We are finished with the scan, send an unsolicited // scan state update. mChangedPropsSet.AddProperty(SPINEL_PROP_MAC_SCAN_STATE); mUpdateChangedPropsTask.Post(); diff --git a/src/ncp/ncp_base_radio.cpp b/src/ncp/ncp_base_radio.cpp index ace98cade..4ada00ecb 100644 --- a/src/ncp/ncp_base_radio.cpp +++ b/src/ncp/ncp_base_radio.cpp @@ -193,142 +193,67 @@ exit: return; } -otError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_ENABLED(void) { bool enabled; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_BOOL_S, - &enabled - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadBool(enabled)); error = otLinkRawSrcMatchEnable(mInstance, enabled); exit: - return SendSetPropertyResponse(aHeader, aKey, error); -} - -otError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) -{ - otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; - const uint8_t *data = aValuePtr; - uint16_t dataLen = aValueLen; - - // Clear the list first - error = otLinkRawSrcMatchClearShortEntries(mInstance); - - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - - // Loop through the addresses and add them - while (dataLen >= sizeof(uint16_t)) - { - spinel_ssize_t parsedLength; - uint16_t short_address; - - parsedLength = spinel_datatype_unpack( - data, - dataLen, - SPINEL_DATATYPE_UINT16_S, - &short_address - ); - - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); - - data += parsedLength; - dataLen -= (uint16_t)parsedLength; - - error = otLinkRawSrcMatchAddShortEntry(mInstance, short_address); - - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - } - - SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey)); - SuccessOrExit(error = mEncoder.WriteData(aValuePtr, aValueLen)); - SuccessOrExit(error = mEncoder.EndFrame()); - -exit: - - if (spinelError != SPINEL_STATUS_OK) - { - error = SendLastStatus(aHeader, spinelError); - } - return error; } -otError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(void) { otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; - const uint8_t *data = aValuePtr; - uint16_t dataLen = aValueLen; // Clear the list first - error = otLinkRawSrcMatchClearExtEntries(mInstance); - - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); + SuccessOrExit(error = otLinkRawSrcMatchClearShortEntries(mInstance)); // Loop through the addresses and add them - while (dataLen >= sizeof(otExtAddress)) + while (mDecoder.GetRemainingLengthInStruct() >= sizeof(uint16_t)) { - spinel_ssize_t parsedLength; - otExtAddress *extAddress; + uint16_t shortAddress; - parsedLength = spinel_datatype_unpack( - data, - dataLen, - SPINEL_DATATYPE_EUI64_S, - &extAddress - ); + SuccessOrExit(error = mDecoder.ReadUint16(shortAddress)); - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); - - data += parsedLength; - dataLen -= (uint16_t)parsedLength; - - error = otLinkRawSrcMatchAddExtEntry(mInstance, extAddress); - - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); + SuccessOrExit(error = otLinkRawSrcMatchAddShortEntry(mInstance, shortAddress)); } - SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey)); - SuccessOrExit(error = mEncoder.WriteData(aValuePtr, aValueLen)); - SuccessOrExit(error = mEncoder.EndFrame()); - exit: - - if (spinelError != SPINEL_STATUS_OK) - { - error = SendLastStatus(aHeader, spinelError); - } - return error; } -otError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(void) +{ + otError error = OT_ERROR_NONE; + + // Clear the list first + SuccessOrExit(error = otLinkRawSrcMatchClearExtEntries(mInstance)); + + // Loop through the addresses and add them + while (mDecoder.GetRemainingLengthInStruct() >= sizeof(otExtAddress)) + { + const otExtAddress *extAddress; + + SuccessOrExit(error = mDecoder.ReadEui64(extAddress)); + + SuccessOrExit(error = otLinkRawSrcMatchAddExtEntry(mInstance, extAddress)); + } + +exit: + return error; +} + +otError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(void) { - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; uint16_t shortAddress; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT16_S, - &shortAddress - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUint16(shortAddress)); error = otLinkRawSrcMatchClearShortEntry(mInstance, shortAddress); @@ -336,20 +261,12 @@ exit: return error; } -otError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(void) { - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - otExtAddress *extAddress; + const otExtAddress *extAddress; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_EUI64_S, - &extAddress - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadEui64(extAddress));; error = otLinkRawSrcMatchClearExtEntry(mInstance, extAddress); @@ -357,41 +274,25 @@ exit: return error; } -otError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(void) { - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - uint16_t short_address; + uint16_t shortAddress; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT16_S, - &short_address - ); + SuccessOrExit(error = mDecoder.ReadUint16(shortAddress)); - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); - - error = otLinkRawSrcMatchAddShortEntry(mInstance, short_address); + error = otLinkRawSrcMatchAddShortEntry(mInstance, shortAddress); exit: return error; } -otError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(void) { - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - otExtAddress *extAddress = NULL; + const otExtAddress *extAddress = NULL; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_EUI64_S, - &extAddress - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadEui64(extAddress)); error = otLinkRawSrcMatchAddExtEntry(mInstance, extAddress); @@ -399,21 +300,12 @@ exit: return error; } -otError NcpBase::SetPropertyHandler_PHY_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_PHY_ENABLED(void) { bool value = false; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_BOOL_S, - &value - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadBool(value)); if (value == false) { @@ -437,64 +329,45 @@ otError NcpBase::SetPropertyHandler_PHY_ENABLED(uint8_t aHeader, spinel_prop_key } exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } -otError NcpBase::SetPropertyHandler_MAC_15_4_SADDR(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_MAC_15_4_SADDR(void) { uint16_t shortAddress; - spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT16_S, - &shortAddress - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + SuccessOrExit(error = mDecoder.ReadUint16(shortAddress)); error = otLinkRawSetShortAddress(mInstance, shortAddress); exit: - return SendSetPropertyResponse(aHeader, aKey, error); + return error; } -otError NcpBase::SetPropertyHandler_STREAM_RAW(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen) +otError NcpBase::SetPropertyHandler_STREAM_RAW(uint8_t aHeader) { - uint8_t *frame_buffer = NULL; + const uint8_t *frameBuffer = NULL; otRadioFrame *frame; - unsigned int frameLen = 0; - spinel_ssize_t parsedLength; + uint16_t frameLen = 0; otError error = OT_ERROR_NONE; VerifyOrExit(otLinkRawIsEnabled(mInstance), error = OT_ERROR_INVALID_STATE); frame = otLinkRawGetTransmitBuffer(mInstance); - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_DATA_WLEN_S - SPINEL_DATATYPE_UINT8_S - SPINEL_DATATYPE_INT8_S, - &frame_buffer, - &frameLen, - &frame->mChannel, - &frame->mPower - ); + SuccessOrExit(error = mDecoder.ReadDataWithLen(frameBuffer, frameLen)); + SuccessOrExit(error = mDecoder.ReadUint8(frame->mChannel)); + SuccessOrExit(error = mDecoder.ReadInt8(frame->mPower)); - VerifyOrExit(parsedLength > 0 && frameLen <= OT_RADIO_FRAME_MAX_SIZE, error = OT_ERROR_PARSE); + VerifyOrExit(frameLen <= OT_RADIO_FRAME_MAX_SIZE, error = OT_ERROR_PARSE); // Cache the transaction ID for async response mCurTransmitTID = SPINEL_HEADER_GET_TID(aHeader); // Update frame buffer and length frame->mLength = static_cast(frameLen); - memcpy(frame->mPsdu, frame_buffer, frame->mLength); + memcpy(frame->mPsdu, frameBuffer, frame->mLength); // TODO: This should be later added in the STREAM_RAW argument to allow user to directly specify it. frame->mMaxTxAttempts = OPENTHREAD_CONFIG_MAX_TX_ATTEMPTS_DIRECT; @@ -514,8 +387,6 @@ exit: error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error)); } - OT_UNUSED_VARIABLE(aKey); - return error; } diff --git a/src/ncp/spinel_decoder.cpp b/src/ncp/spinel_decoder.cpp new file mode 100644 index 000000000..08d0472e9 --- /dev/null +++ b/src/ncp/spinel_decoder.cpp @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2017, 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. + */ + +/** + * @file + * This file implements a spinel decoder. + */ + +#include + +#include "spinel_decoder.hpp" + +#include "common/code_utils.hpp" + +namespace ot { +namespace Ncp { + +SpinelDecoder::SpinelDecoder(void) : + mFrame(NULL), + mLength(0), + mIndex(0), + mEnd(0), + mNumOpenStructs(0), + mSavedNumOpenStructs(0), + mSavedIndex(0), + mSavedEnd(0) +{ +} + +void SpinelDecoder::Init(const uint8_t *aFrame, uint16_t aLength) +{ + mFrame = aFrame; + mLength = (mFrame != NULL) ? aLength : 0; + + Reset(); + ClearSavedPosition(); +} + +void SpinelDecoder::Reset(void) +{ + mIndex = 0; + mEnd = mLength; + mNumOpenStructs = 0; + ClearSavedPosition(); +} + +otError SpinelDecoder::ReadBool(bool &aBool) +{ + otError error = OT_ERROR_NONE; + uint8_t byte; + + SuccessOrExit(error = ReadUint8(byte)); + + // Boolean value are encoded in 8-bits as either 0x00 or 0x01. All other values are illegal. + if (byte == 0x00) + { + aBool = false; + } + else if (byte == 0x01) + { + aBool = true; + } + else + { + error = OT_ERROR_PARSE; + } + +exit: + return error; +} + +otError SpinelDecoder::ReadUint8(uint8_t &aUint8) +{ + otError error = OT_ERROR_NONE; + + VerifyOrExit(mIndex + sizeof(uint8_t) <= mEnd, error = OT_ERROR_PARSE); + aUint8 = mFrame[mIndex]; + mIndex += sizeof(uint8_t); + +exit: + return error; +} + +otError SpinelDecoder::ReadInt8(int8_t &aInt8) +{ + otError error = OT_ERROR_NONE; + uint8_t byte; + + SuccessOrExit(error = ReadUint8(byte)); + aInt8 = static_cast(byte); + +exit: + return error; +} + +otError SpinelDecoder::ReadUint16(uint16_t &aUint16) +{ + otError error = OT_ERROR_NONE; + + VerifyOrExit(mIndex + sizeof(uint16_t) <= mEnd, error = OT_ERROR_PARSE); + + aUint16 = static_cast(mFrame[mIndex] | (mFrame[mIndex + 1] << 8)); + + mIndex += sizeof(uint16_t); + +exit: + return error; +} + +otError SpinelDecoder::ReadInt16(int16_t &aInt16) +{ + otError error = OT_ERROR_NONE; + uint16_t u16; + + SuccessOrExit(error = ReadUint16(u16)); + aInt16 = static_cast(u16); + +exit: + return error; +} + +otError SpinelDecoder::ReadUint32(uint32_t &aUint32) +{ + otError error = OT_ERROR_NONE; + + VerifyOrExit(mIndex + sizeof(uint32_t) <= mEnd, error = OT_ERROR_PARSE); + + aUint32 = ((static_cast(mFrame[mIndex + 0]) << 0) | + (static_cast(mFrame[mIndex + 1]) << 8) | + (static_cast(mFrame[mIndex + 2]) << 16) | + (static_cast(mFrame[mIndex + 3]) << 24)); + + mIndex += sizeof(uint32_t); + +exit: + return error; +} + +otError SpinelDecoder::ReadInt32(int32_t &aInt32) +{ + otError error = OT_ERROR_NONE; + uint32_t u32; + + SuccessOrExit(error = ReadUint32(u32)); + aInt32 = static_cast(u32); + +exit: + return error; +} + +otError SpinelDecoder::ReadUintPacked(unsigned int &aUint) +{ + otError error = OT_ERROR_NONE; + spinel_ssize_t parsedLen; + unsigned int uint; + + parsedLen = spinel_packed_uint_decode(&mFrame[mIndex], mEnd - mIndex, &uint); + VerifyOrExit(parsedLen > 0, error = OT_ERROR_PARSE); + + mIndex += parsedLen; + aUint = uint; + +exit: + return error; +} + +// Reads an item of given size and updates the pointer `aPtr`. +otError SpinelDecoder::ReadItem(const uint8_t **aPtr, size_t aSize) +{ + otError error = OT_ERROR_NONE; + + VerifyOrExit(mIndex + aSize <= mEnd, error = OT_ERROR_PARSE); + + *aPtr = &mFrame[mIndex]; + + mIndex += aSize; + +exit: + return error; +} + +otError SpinelDecoder::ReadIp6Address(spinel_ipv6addr_t &aIp6Addr) +{ + otError error = OT_ERROR_NONE; + const spinel_ipv6addr_t *ipv6AddrPtr; + + SuccessOrExit(error = ReadIp6Address(ipv6AddrPtr)); + aIp6Addr = *ipv6AddrPtr; + +exit: + return error; +} + +otError SpinelDecoder::ReadIp6Address(otIp6Address &aIp6Addr) +{ + otError error = OT_ERROR_NONE; + const otIp6Address *ipv6AddrPtr; + + SuccessOrExit(error = ReadIp6Address(ipv6AddrPtr)); + aIp6Addr = *ipv6AddrPtr; + +exit: + return error; +} + +otError SpinelDecoder::ReadEui64(spinel_eui64_t &aEui64) +{ + otError error = OT_ERROR_NONE; + const spinel_eui64_t *eui64Ptr; + + SuccessOrExit(error = ReadEui64(eui64Ptr)); + aEui64 = *eui64Ptr; + +exit: + return error; +} + +otError SpinelDecoder::ReadEui64(otExtAddress &aEui64) +{ + otError error = OT_ERROR_NONE; + const otExtAddress *eui64Ptr; + + SuccessOrExit(error = ReadEui64(eui64Ptr)); + aEui64 = *eui64Ptr; + +exit: + return error; +} + +otError SpinelDecoder::ReadEui48(spinel_eui48_t &aEui48) +{ + otError error = OT_ERROR_NONE; + const spinel_eui48_t *eui48Ptr; + + SuccessOrExit(error = ReadEui48(eui48Ptr)); + aEui48 = *eui48Ptr; + +exit: + return error; +} + +otError SpinelDecoder::ReadUtf8(const char *&aUtf8) +{ + otError error = OT_ERROR_NONE; + size_t len; + + // Ensure there is at least one byte (for null character). + VerifyOrExit(mIndex + sizeof(uint8_t) <= mEnd, error = OT_ERROR_PARSE); + + len = strnlen(reinterpret_cast(&mFrame[mIndex]), mEnd - mIndex); + VerifyOrExit(len < static_cast(mEnd - mIndex), error = OT_ERROR_PARSE); + + aUtf8 = reinterpret_cast(&mFrame[mIndex]); + + mIndex += (len + sizeof(uint8_t)); // `sizeof(uint8_t)` is added for the terminating null character. + +exit: + return error; +} + +otError SpinelDecoder::ReadData(const uint8_t *&aData, uint16_t &aDataLen) +{ + aDataLen = mEnd - mIndex; + + return ReadItem(&aData, aDataLen); +} + +otError SpinelDecoder::ReadDataWithLen(const uint8_t *&aData, uint16_t &aDataLen) +{ + otError error = OT_ERROR_NONE; + uint16_t len; + + SuccessOrExit(error = ReadUint16(len)); + SuccessOrExit(error = ReadItem(&aData, len)); + aDataLen = len; + +exit: + return error; +} + +otError SpinelDecoder::OpenStruct(void) +{ + otError error = OT_ERROR_NONE; + uint16_t structLen; + + VerifyOrExit(mNumOpenStructs < kMaxNestedStructs, error = OT_ERROR_INVALID_STATE); + + SuccessOrExit(error = ReadUint16(structLen)); + VerifyOrExit(structLen <= mEnd - mIndex, error = OT_ERROR_PARSE); + + mPrevEnd[mNumOpenStructs] = mEnd; + mEnd = (mIndex + structLen); + mNumOpenStructs++; + +exit: + return error; +} + +otError SpinelDecoder::CloseStruct(void) +{ + otError error = OT_ERROR_NONE; + + VerifyOrExit(mNumOpenStructs > 0, error = OT_ERROR_INVALID_STATE); + + // If there is a saved position and it is contained + // within the current struct being closed, the saved + // position is cleared to ensure user cannot go back + // to middle of an already closed struct. + + if (IsSavedPositionValid() && (mNumOpenStructs == mSavedNumOpenStructs)) + { + ClearSavedPosition(); + } + + mNumOpenStructs--; + mIndex = mEnd; + mEnd = mPrevEnd[mNumOpenStructs]; + +exit: + return error; +} + +void SpinelDecoder::SavePosition(void) +{ + mSavedIndex = mIndex; + mSavedEnd = mEnd; + mSavedNumOpenStructs = mNumOpenStructs; +} + +otError SpinelDecoder::ResetToSaved(void) +{ + otError error = OT_ERROR_NONE; + + VerifyOrExit(IsSavedPositionValid(), error = OT_ERROR_INVALID_STATE); + + mIndex = mSavedIndex; + mEnd = mSavedEnd; + mNumOpenStructs = mSavedNumOpenStructs; + +exit: + return error; +} + +} // namespace Ncp +} // namespace ot diff --git a/src/ncp/spinel_decoder.hpp b/src/ncp/spinel_decoder.hpp new file mode 100644 index 000000000..e7a55fedc --- /dev/null +++ b/src/ncp/spinel_decoder.hpp @@ -0,0 +1,565 @@ +/* + * Copyright (c) 2017, 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. + */ + +/** + * @file + * This file contains the definitions of a spinel decoder. + */ + +#ifndef SPINEL_DECODER_HPP_ +#define SPINEL_DECODER_HPP_ + +#include + +#include +#include + +#include "openthread-core-config.h" +#include "ncp/spinel.h" + +namespace ot { +namespace Ncp { + +/** + * This class defines a spinel decoder. + * + */ +class SpinelDecoder +{ +public: + + /** + * This constructor initializes a `SpinelDecoder` object + * + */ + SpinelDecoder(void); + + /** + * This method initializes the decoder to start decoding a new given spinel encoded frame. + * + * It sets the read position to beginning of the frame and also erases/voids any saved positions (see + * `SavePosition()` and `ResetToSaved()` methods). + * + * @param[in] aFrame Pointer to the buffer containing the frame to be decoded. + * @param[in] aLength Length (number of bytes) of the frame. + * + */ + void Init(const uint8_t *aFrame, uint16_t aLength); + + /** + * This method returns a pointer to the frame. + * + * @returns A pointer to buffer containing current frame being decoded. + * + */ + const uint8_t *GetFrame(void) const { return mFrame; } + + /** + * This method returns the total length of current frame being decoded. + * + * @returns The length of current frame being decoded. + * + */ + uint16_t GetLength(void) const { return mLength; } + + /** + * This method returns the number of bytes that are already read/decoded from the frame. + * + * @returns The number of bytes already read from frame. + * + */ + uint16_t GetReadLength(void) const { return mIndex; } + + /** + * This method returns the number of remaining (not yet read/decoded) bytes in the frame. + * + * @returns The number of remaining unread bytes in the frame. + * + */ + uint16_t GetRemainingLength(void) const { return mLength - mIndex; } + + /** + * This method indicates whether or not all the bytes in the frame are read. + * + * @returns TRUE if all the bytes in the buffer are read, FALSE otherwise. + * + */ + bool IsAllRead(void) const { return (mIndex == mLength); } + + /** + * This method resets the read position to beginning of frame. It will also void/erase any previously saved + * position using `SavePosition()` method. + * + */ + void Reset(void); + + /** + * This method decodes and reads a boolean value form the frame. + * + * On success, the read position gets updated. + * + * @param[out] aBool Reference to variable to output the read value. + * + * @retval OT_ERROR_NONE Successfully read the value. + * @retval OT_ERROR_PARSE Failed to parse/decode the value. + * + */ + otError ReadBool(bool &aBool); + + /** + * This method decodes and reads an `int8_t` value form the frame. + * + * On success, the read position get updated. + * + * @param[out] aInt8 Reference to variable to output the read value. + * + * @retval OT_ERROR_NONE Successfully read the value. + * @retval OT_ERROR_PARSE Failed to parse/decode the value. + * + */ + otError ReadInt8(int8_t &aInt8); + + /** + * This method decodes and reads an `uint8_t` value form the frame. + * + * On success, the read position gets updated. + * + * @param[out] aUint8 Reference to variable to output the read value. + * + * @retval OT_ERROR_NONE Successfully read the value. + * @retval OT_ERROR_PARSE Failed to parse/decode the value. + * + */ + otError ReadUint8(uint8_t &aUint8); + + /** + * This method decodes and reads an `int16_t` value form the frame. + * + * On success, the read position gets updated. + * + * @param[out] aInt16 Reference to variable to output the read value. + * + * @retval OT_ERROR_NONE Successfully read the value. + * @retval OT_ERROR_PARSE Failed to parse/decode the value. + * + */ + otError ReadInt16(int16_t &aInt16); + + /** + * This method decodes and reads an `uint16_t` value form the frame. + * + * On success, the read position gets updated. + * + * @param[out] aUint16 Reference to variable to output the read value. + * + * @retval OT_ERROR_NONE Successfully read the value. + * @retval OT_ERROR_PARSE Failed to parse/decode the value. + * + */ + otError ReadUint16(uint16_t &aUint16); + + /** + * This method decodes and reads an `int32_t` value form the frame. + * + * On success, the read position gets updated. + * + * @param[out] aInt32 Reference to variable to output the read value. + * + * @retval OT_ERROR_NONE Successfully read the value. + * @retval OT_ERROR_PARSE Failed to parse/decode the value. + * + */ + otError ReadInt32(int32_t &aInt32); + + /** + * This method decodes and reads an `uint32_t` value form the frame. + * + * On success, the read position gets updated. + * + * @param[out] aUint32 Reference to variable to output the read value. + * + * @retval OT_ERROR_NONE Successfully read the value. + * @retval OT_ERROR_PARSE Failed to parse/decode the value. + * + */ + otError ReadUint32(uint32_t &aUint32); + + /** + * This method decodes (using spinel packed integer format) and reads an unsigned integer value form the frame. + * + * On success, the read position gets updated. + * + * @param[out] aUint Reference to variable to output the read value. + * + * @retval OT_ERROR_NONE Successfully read the value. + * @retval OT_ERROR_PARSE Failed to parse/decode the value. + * + */ + otError ReadUintPacked(unsigned int &aUint); + + /** + * This method decodes and reads an IPv6 address form the frame. + * + * On success, the read position gets updated. + * + * @param[out] aIp6AddrPtr Reference to IPv6 address pointer to output the value (as `spinel_ipv6addr_t`). + * On success, the pointer variable is updated. + * + * @retval OT_ERROR_NONE Successfully read the value. + * @retval OT_ERROR_PARSE Failed to parse/decode the value. + * + */ + otError ReadIp6Address(const spinel_ipv6addr_t *&aIp6AddrPtr) { + return ReadItem(reinterpret_cast(&aIp6AddrPtr), sizeof(spinel_ipv6addr_t)); + } + + /** + * This method decodes and reads an IPv6 address form the frame. + * + * On success, the read position gets updated. + * + * @param[out] aIp6AddrPtr Reference to IPv6 address pointer to output the value (as `otIp6Address`). + * On success, the pointer variable is updated. + * + * @retval OT_ERROR_NONE Successfully read the value. + * @retval OT_ERROR_PARSE Failed to parse/decode the value. + * + */ + otError ReadIp6Address(const otIp6Address *&aIp6AddrPtr) { + return ReadItem(reinterpret_cast(&aIp6AddrPtr), sizeof(spinel_ipv6addr_t)); + } + + /** + * This method decodes and reads an IPv6 address form the frame. + * + * On success, the read position gets updated. + * + * @param[out] aIp6AddrBufPtr Reference to a buffer pointer to output the value. + * On success, the pointer variable is updated. + * + * @retval OT_ERROR_NONE Successfully read the value. + * @retval OT_ERROR_PARSE Failed to parse/decode the value. + * + */ + otError ReadIp6Address(const uint8_t *&aIp6AddrBufPtr) { + return ReadItem(&aIp6AddrBufPtr, sizeof(spinel_ipv6addr_t)); + } + + /** + * This method decodes and reads an IPv6 address form the frame. + * + * On success, the read position gets updated and the IP address is copied into the given output variable. + * + * @param[out] aIp6Addr Reference to IPv6 address variable to output the value (as spinel_ipv6addr_t). + * On success, the address is copied into the output variable. + * + * @retval OT_ERROR_NONE Successfully read the value. + * @retval OT_ERROR_PARSE Failed to parse/decode the value. + * + */ + otError ReadIp6Address(spinel_ipv6addr_t &aIp6Addr); + + /** + * This method decodes and reads an IPv6 address form the frame. + * + * On success, the read position gets updated and the IP address is copied into the given output variable. + * + * @param[out] aIp6Addr Reference to IPv6 address variable to output the value (as otIp6Address). + * On success, the address is copied into the output variable. + * + * @retval OT_ERROR_NONE Successfully read the value. + * @retval OT_ERROR_PARSE Failed to parse/decode the value. + * + */ + otError ReadIp6Address(otIp6Address &aIp6Addr); + + /** + * This method decodes and reads an EUI64 value form the frame. + * + * On success, the read position gets updated. + * + * @param[out] aEui64Ptr Reference to an EUI64 pointer to output the value (as `spinel_eui64_t`). + * On success, the pointer variable is updated. + * + * @retval OT_ERROR_NONE Successfully read the value. + * @retval OT_ERROR_PARSE Failed to parse/decode the value. + * + */ + otError ReadEui64(const spinel_eui64_t *&aEui64Ptr) { + return ReadItem(reinterpret_cast(&aEui64Ptr), sizeof(spinel_eui64_t)); + } + + /** + * This method decodes and reads an EUI64 value form the frame. + * + * On success, the read position gets updated. + * + * @param[out] aEui64Ptr Reference to an EUI64 pointer to output the value (as `otExtAddress`). + * On success, the pointer variable is updated. + * + * @retval OT_ERROR_NONE Successfully read the value. + * @retval OT_ERROR_PARSE Failed to parse/decode the value. + * + */ + otError ReadEui64(const otExtAddress *&aEui64Ptr) { + return ReadItem(reinterpret_cast(&aEui64Ptr), sizeof(spinel_eui64_t)); + } + + /** + * This method decodes and reads an EUI64 value form the frame. + * + * On success, the read position gets updated. + * + * @param[out] aEui64BufPtr Reference to a buffer pointer to output the value. + * On success, the pointer variable is updated. + * + * @retval OT_ERROR_NONE Successfully read the value. + * @retval OT_ERROR_PARSE Failed to parse/decode the value. + * + */ + otError ReadEui64(const uint8_t *&aEui64BufPtr) { + return ReadItem(&aEui64BufPtr, sizeof(spinel_eui64_t)); + } + + /** + * This method decodes and reads an EUI64 value form the frame. + * + * On success, the read position gets updated and the EUI64 value is copied into the given output variable. + * + * @param[out] aEui64 Reference to EUI64 variable to output the value (as spinel_eui64_t). + * On success, the address is copied into the output variable. + * + * @retval OT_ERROR_NONE Successfully read the value. + * @retval OT_ERROR_PARSE Failed to parse/decode the value. + * + */ + otError ReadEui64(spinel_eui64_t &aEui64); + + /** + * This method decodes and reads an EUI64 value form the frame. + * + * On success, the read position gets updated and the EUI64 value is copied into the given output variable. + * + * @param[out] aEui64 Reference to EUI64 variable to output the value (as otExtAddress). + * On success, the address is copied into the output variable. + * + * @retval OT_ERROR_NONE Successfully read the value. + * @retval OT_ERROR_PARSE Failed to parse/decode the value. + * + */ + otError ReadEui64(otExtAddress &aEui64); + + /** + * This method decodes and reads an EUI48 value form the frame. + * + * On success, the read position gets updated. + * + * @param[out] aEui48Ptr Reference to an EUI48 pointer to output the value (as `spinel_eui48_t`). + * On success, the pointer variable is updated. + * + * @retval OT_ERROR_NONE Successfully read the value. + * @retval OT_ERROR_PARSE Failed to parse/decode the value. + * + */ + otError ReadEui48(const spinel_eui48_t *&aEui48Ptr) { + return ReadItem(reinterpret_cast(&aEui48Ptr), sizeof(spinel_eui48_t)); + } + + /** + * This method decodes and reads an EUI48 value form the frame. + * + * On success, the read position gets updated. + * + * @param[out] aEui48BufPtr Reference to a buffer pointer to output the value. + * On success, the pointer variable is updated. + * + * @retval OT_ERROR_NONE Successfully read the value. + * @retval OT_ERROR_PARSE Failed to parse/decode the value. + * + */ + otError ReadEui48(const uint8_t *&aEui48BufPtr) { + return ReadItem(&aEui48BufPtr, sizeof(spinel_eui48_t)); + } + + /** + * This method decodes and reads an EUI48 value form the frame. + * + * On success, the read position gets updated and the EUI48 value is copied into the given output variable. + * + * @param[out] aEui48 Reference to EUI48 variable to output the value (as spinel_eui48_t). + * On success, value is copied into the output variable. + * + * @retval OT_ERROR_NONE Successfully read the value. + * @retval OT_ERROR_PARSE Failed to parse/decode the value. + * + */ + otError ReadEui48(spinel_eui48_t &aEui48); + + /** + * This method decodes and reads a UTF8 string form the frame. + * + * On success, the read position gets updated. + * + * @param[out] aUt8 Reference to a `char` pointer to output the string. + * On success, the pointer variable is updated. + * + * @retval OT_ERROR_NONE Successfully read the value. + * @retval OT_ERROR_PARSE Failed to parse/decode the value. + * + */ + otError ReadUtf8(const char *&aUt8); + + /** + * This method decodes and reads a data blob (sequence of bytes) form the frame. + * + * On success, the read position gets updated. + * + * @param[out] aData Reference to pointer variable to output the data. + * On success, the pointer variable is updated. + * @param[out] aDataLength Reference to variable to out the data length (number of bytes). + * + * @retval OT_ERROR_NONE Successfully read the value. + * @retval OT_ERROR_PARSE Failed to parse/decode the value. + * + */ + otError ReadData(const uint8_t *&aData, uint16_t &aDataLen); + + /** + * This method decodes and reads a data blob (sequence of bytes) with data length. + * + * The data length is assumed to be prepended before the data content (encoded as a `uint16_t`). The size of the + * length field should not be included in the length value. This method corresponds to `SPINEL_DATATYPE_DATA_WLEN` + * type. + * + * @param[out] aData Reference to pointer variable to output the data. + * On success, the pointer variable is updated. + * @param[out] aDataLength Reference to variable to out the data length (number of bytes). + * + * @retval OT_ERROR_NONE Successfully read the value. + * @retval OT_ERROR_PARSE Failed to parse/decode the value. + * + */ + otError ReadDataWithLen(const uint8_t *&aData, uint16_t &aDataLen); + + /** + * This method opens a struct in the frame. + * + * After a successful call to this method, all the subsequent `Read()` methods decode and read the + * field/value from the current open struct until the struct is closed using `CloseStruct()` method. Structures can + * be nested. Up to `kMaxNestedStructs` nested structs can be opened at the same time. + * + * @retval OT_ERROR_NONE Successfully opened a struct. + * @retval OT_ERROR_PARSE Failed to parse/open a struct. + * @retval OT_ERROR_INVALID_STATE Already at the maximum number of nested open structures. + * + */ + otError OpenStruct(void); + + /** + * This method closes the most recently opened struct (using `OpenStruct()`) in the frame. + * + * On success, the read position is moved to end of the struct skipping any unread bytes within the struct. + * + * @retval OT_ERROR_NONE Successfully closed the struct. + * @retval OT_ERROR_INVALID_STATE There is no current open struct to close. + * + */ + otError CloseStruct(void); + + /** + * This method returns the number of remaining/unread bytes in the current inner-most open structure. + * + * If there is no currently open structure the number of remaining bytes in whole frame is returned instead. + * + * @returns The number of remaining unread bytes in the inner-most open structure. + * + */ + uint16_t GetRemainingLengthInStruct(void) const { return mEnd - mIndex; } + + /** + * This method indicates whether or not all the bytes in inner-most open structure are read. + * + * If there is no currently open structure, the whole frame is considered instead. + * + * @returns TRUE if all the bytes are read, FALSE otherwise. + * + */ + bool IsAllReadInStruct(void) const { return (mIndex == mEnd); } + + /** + * This method saves the current read position in the frame. + + * A subsequent call to `SavePosition()` will overwrite the previously saved position. The saved position can be + * used to to move the read position back (using `ResetToSaved()`) and re-read the same content. + * + * Saved position can be within an open struct, and it remembers its enclosing struct. When the enclosing struct is + * closed, the saved position will be voided and can no longer be used. This ensures that we cannot jump back to + * middle an already fully decoded/read and closed struct. + * + */ + void SavePosition(void); + + /** + * This method resets/moves the read position to a previously saved position. + * + * The saved position remembers its enclosing structure. When `ResetToSaved()` is called, the current open + * structure will be the same as when position was saved. + * + * @retval OT_ERROR_NONE Successfully reset the read position. + * @retval OT_ERROR_INVALID_STATE The saved position is not valid (there is no saved position or the saved + * position was voided since its enclosing struct was closed). + * + */ + otError ResetToSaved(void); + +private: + otError ReadItem(const uint8_t **aPtr, size_t aSize); + void ClearSavedPosition(void) { mSavedIndex = mLength; } + bool IsSavedPositionValid(void) const { return (mSavedIndex < mLength); } + + enum + { + kMaxNestedStructs = 4, ///< Maximum number of nested structs. + }; + + const uint8_t *mFrame; // Frame buffer + uint16_t mLength; // Total length of the buffer. + uint16_t mIndex; // Current read index. + uint16_t mEnd; // Current end index (end of struct if in a struct, or end of buffer otherwise). + uint8_t mNumOpenStructs; // Number of open structs. + + uint8_t mSavedNumOpenStructs; // Number of open structs when read position was saved. + uint16_t mSavedIndex; // Read index when position was saved. + uint16_t mSavedEnd; // End index when position was saved. + + uint16_t mPrevEnd[kMaxNestedStructs]; +}; + +} // namespace Ncp +} // namespace ot + +#endif // SPINEL_DECODER_HPP_ diff --git a/src/ncp/spinel_encoder.hpp b/src/ncp/spinel_encoder.hpp index c197e0532..fe40f80e1 100644 --- a/src/ncp/spinel_encoder.hpp +++ b/src/ncp/spinel_encoder.hpp @@ -571,7 +571,7 @@ public: * This method opens a struct in the current input frame. * * After a successful call to this method, all the subsequent `Write()` methods add the field/value to - * the current open struct until the struct is closed using `CloseStruct()` method. Structs can be nested. Up to + * the current open struct until the struct is closed using `CloseStruct()` method. Structures can be nested. Up to * `kMaxNestedStructs` nested structs can be opened at the same time. * * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this @@ -580,7 +580,7 @@ public: * If no buffer space is available, this method will discard and clear the frame and return error status * `OT_ERROR_NO_BUFS`. * - * @retval OT_ERROR_NONE Successfully added the message to the frame. + * @retval OT_ERROR_NONE Successfully opened the struct. * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to open the struct. * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame or if we reached * the maximum number of nested open structures. @@ -597,7 +597,7 @@ public: * If no buffer space is available, this method will discard and clear the frame and return error status * `OT_ERROR_NO_BUFS`. * - * @retval OT_ERROR_NONE Successfully added the message to the frame. + * @retval OT_ERROR_NONE Successfully closed the most recently opened struct. * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to open the struct. * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame or if there is no * open struct to close @@ -623,7 +623,7 @@ public: * The saved position must belong to the same input frame saved earlier with `SavePosition()`. This method cannot * be used if the input frame has an added `otMessage`. * - * @retval OT_ERROR_NONE Successfully reset the write position of current input frame.. + * @retval OT_ERROR_NONE Successfully reset the write position of current input frame. * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. * @retval OT_ERROR_INVALID_ARGS The saved position is not valid (does not belong to same input frame), or * the input frame has an added `otMessage`. diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am index bc17680c5..43c804f23 100644 --- a/tests/unit/Makefile.am +++ b/tests/unit/Makefile.am @@ -97,6 +97,7 @@ check_PROGRAMS = \ test-strlcat \ test-strlcpy \ test-strnlen \ + test-spinel-decoder \ test-spinel-encoder \ test-timer \ test-toolchain \ @@ -187,6 +188,9 @@ test_strlcpy_SOURCES = test_strlcpy.c test_strnlen_LDADD = $(COMMON_LDADD) test_strnlen_SOURCES = test_strnlen.c +test_spinel_decoder_LDADD = $(COMMON_LDADD) +test_spinel_decoder_SOURCES = test_platform.cpp test_spinel_decoder.cpp + test_spinel_encoder_LDADD = $(COMMON_LDADD) test_spinel_encoder_SOURCES = test_platform.cpp test_spinel_encoder.cpp diff --git a/tests/unit/test_spinel_decoder.cpp b/tests/unit/test_spinel_decoder.cpp new file mode 100644 index 000000000..056e85269 --- /dev/null +++ b/tests/unit/test_spinel_decoder.cpp @@ -0,0 +1,765 @@ +/* + * Copyright (c) 2017, 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. + */ + +#include + +#include + +#include "openthread-instance.h" +#include "common/code_utils.hpp" +#include "ncp/spinel_decoder.hpp" + +#include "test_util.h" + +namespace ot { +namespace Ncp { + +enum +{ + kTestBufferSize = 800, +}; + + +// Dump the buffer content to screen. +void DumpBuffer(const char *aTextMessage, uint8_t *aBuffer, uint16_t aBufferLength) +{ + enum + { + kBytesPerLine = 32, // Number of bytes per line. + }; + + char charBuff[kBytesPerLine + 1]; + uint16_t counter; + uint8_t byte; + + printf("\n%s - len = %u\n ", aTextMessage, aBufferLength); + + counter = 0; + + while (aBufferLength--) + { + byte = *aBuffer++; + printf("%02X ", byte); + charBuff[counter] = isprint(byte) ? static_cast(byte) : '.'; + counter++; + + if (counter == kBytesPerLine) + { + charBuff[counter] = 0; + printf(" %s\n ", charBuff); + counter = 0; + } + } + + charBuff[counter] = 0; + + while (counter++ < kBytesPerLine) + { + printf(" "); + } + + printf(" %s\n", charBuff); +} + +void TestSpinelDecoder(void) +{ + uint8_t buffer[kTestBufferSize]; + SpinelDecoder decoder; + + spinel_ssize_t frameLen; + + const bool kBool_1 = true; + const bool kBool_2 = false; + const uint8_t kUint8 = 0x42; + const int8_t kInt8 = -73; + const uint16_t kUint16 = 0xabcd; + const int16_t kInt16 = -567; + const uint32_t kUint32 = 0xdeadbeef; + const int32_t kInt32 = -123455678L; + + + const unsigned int kUint_1 = 9; + const unsigned int kUint_2 = 0xa3; + const unsigned int kUint_3 = 0x8765; + const unsigned int kUint_4 = SPINEL_MAX_UINT_PACKED - 1; + + + const spinel_ipv6addr_t kIp6Addr = + { + { 0x6B, 0x41, 0x65, 0x73, 0x42, 0x68, 0x61, 0x76, 0x54, 0x61, 0x72, 0x7A, 0x49, 0x69, 0x61, 0x4E } + }; + + const spinel_eui48_t kEui48 = + { + { 4, 8, 15, 16, 23, 42 } // "Lost" EUI48! + }; + + const spinel_eui64_t kEui64 = + { + { 2, 3, 5, 7, 11, 13, 17, 19 }, // "Prime" EUI64! + }; + + const char kString_1[] = "OpenThread"; + const char kString_2[] = ""; + + const uint16_t kData[] = { 10, 20, 3, 15, 1000, 60, 16 }; // ... then comes 17,18,19,20 :) + + bool b_1, b_2; + uint8_t u8; + int8_t i8; + uint16_t u16; + int16_t i16; + uint32_t u32; + int32_t i32; + unsigned int u_1, u_2, u_3, u_4; + const spinel_ipv6addr_t *ip6Addr; + const spinel_eui48_t *eui48; + const spinel_eui64_t *eui64; + const char *utf_1; + const char *utf_2; + const uint8_t *dataPtr_1; + const uint8_t *dataPtr_2; + uint16_t dataLen_1; + uint16_t dataLen_2; + + memset(buffer, 0, sizeof(buffer)); + + printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + printf("\nTest 1: Decoding simple types"); + + frameLen = spinel_datatype_pack( + buffer, + sizeof(buffer), + ( + SPINEL_DATATYPE_BOOL_S + SPINEL_DATATYPE_BOOL_S + SPINEL_DATATYPE_UINT8_S + SPINEL_DATATYPE_INT8_S + SPINEL_DATATYPE_UINT16_S + SPINEL_DATATYPE_INT16_S + SPINEL_DATATYPE_UINT32_S + SPINEL_DATATYPE_INT32_S + SPINEL_DATATYPE_UINT_PACKED_S + SPINEL_DATATYPE_UINT_PACKED_S + SPINEL_DATATYPE_UINT_PACKED_S + SPINEL_DATATYPE_UINT_PACKED_S + SPINEL_DATATYPE_IPv6ADDR_S + SPINEL_DATATYPE_EUI48_S + SPINEL_DATATYPE_EUI64_S + SPINEL_DATATYPE_UTF8_S + SPINEL_DATATYPE_UTF8_S + SPINEL_DATATYPE_DATA_WLEN_S + SPINEL_DATATYPE_DATA_S + ), + kBool_1, + kBool_2, + kUint8, + kInt8, + kUint16, + kInt16, + kUint32, + kInt32, + kUint_1, + kUint_2, + kUint_3, + kUint_4, + &kIp6Addr, + &kEui48, + &kEui64, + kString_1, + kString_2, + kData, sizeof(kData), + kData, sizeof(kData) + ); + + DumpBuffer("Packed Spinel Frame", buffer, static_cast(frameLen)); + + decoder.Init(buffer, static_cast(frameLen)); + + VerifyOrQuit(decoder.GetFrame() == &buffer[0], "GetFrame() failed."); + VerifyOrQuit(decoder.GetLength() == frameLen, "GetLength() failed."); + + VerifyOrQuit(decoder.GetReadLength() == 0, "GetReadLength() failed."); + VerifyOrQuit(decoder.GetRemainingLength() == frameLen, "GetRemainingLength() failed."); + VerifyOrQuit(decoder.IsAllRead() == false, "IsAllRead() failed."); + + SuccessOrQuit(decoder.ReadBool(b_1), "ReadBool() failed."); + SuccessOrQuit(decoder.ReadBool(b_2), "ReadBool() failed."); + SuccessOrQuit(decoder.ReadUint8(u8), "ReadUint8() failed."); + SuccessOrQuit(decoder.ReadInt8(i8), "ReadUint8() failed."); + SuccessOrQuit(decoder.ReadUint16(u16), "ReadUint16() failed."); + SuccessOrQuit(decoder.ReadInt16(i16), "ReadInt16() failed."); + SuccessOrQuit(decoder.ReadUint32(u32), "ReadUint32() failed."); + SuccessOrQuit(decoder.ReadInt32(i32), "ReadUint32() failed."); + + // Check the state + VerifyOrQuit(decoder.GetReadLength() != 0, "GetReadLength() failed."); + VerifyOrQuit(decoder.GetRemainingLength() == frameLen - decoder.GetReadLength(), + "GetRemainingLength() failed."); + VerifyOrQuit(decoder.IsAllRead() == false, "IsAllRead() failed."); + + SuccessOrQuit(decoder.ReadUintPacked(u_1), "ReadUintPacked() failed."); + SuccessOrQuit(decoder.ReadUintPacked(u_2), "ReadUintPacked() failed."); + SuccessOrQuit(decoder.ReadUintPacked(u_3), "ReadUintPacked() failed."); + SuccessOrQuit(decoder.ReadUintPacked(u_4), "ReadUintPacked() failed."); + SuccessOrQuit(decoder.ReadIp6Address(ip6Addr), "ReadIp6Addr() failed."); + SuccessOrQuit(decoder.ReadEui48(eui48), "ReadEui48() failed."); + SuccessOrQuit(decoder.ReadEui64(eui64), "ReadEui64() failed."); + SuccessOrQuit(decoder.ReadUtf8(utf_1), "ReadUtf8() failed."); + SuccessOrQuit(decoder.ReadUtf8(utf_2), "ReadUtf8() failed."); + SuccessOrQuit(decoder.ReadDataWithLen(dataPtr_1, dataLen_1), "ReadDataWithLen() failed."); + SuccessOrQuit(decoder.ReadData(dataPtr_2, dataLen_2), "ReadData() failed."); + + VerifyOrQuit(decoder.GetReadLength() == frameLen, "GetReadLength() failed."); + VerifyOrQuit(decoder.GetRemainingLength() == 0, "GetRemainingLength() failed."); + VerifyOrQuit(decoder.IsAllRead() == true, "IsAllRead() failed."); + + VerifyOrQuit(b_1 == kBool_1, "ReadBool() parse failed."); + VerifyOrQuit(b_2 == kBool_2, "ReadBool() parse failed."); + VerifyOrQuit(u8 == kUint8, "ReadUint8() parse failed."); + VerifyOrQuit(i8 == kInt8, "ReadUint8() parse failed."); + VerifyOrQuit(u16 == kUint16, "ReadUint16() parse failed."); + VerifyOrQuit(i16 == kInt16, "ReadInt16() parse failed."); + VerifyOrQuit(u32 == kUint32, "ReadUint32() parse failed."); + VerifyOrQuit(i32 == kInt32, "ReadUint32() parse failed."); + VerifyOrQuit(u_1 == kUint_1, "ReadUintPacked() parse failed."); + VerifyOrQuit(u_2 == kUint_2, "ReadUintPacked() parse failed."); + VerifyOrQuit(u_3 == kUint_3, "ReadUintPacked() parse failed."); + VerifyOrQuit(u_4 == kUint_4, "ReadUintPacked() parse failed."); + VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0, "ReadIp6Address() parse failed."); + VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0, "ReadEui48() parse failed."); + VerifyOrQuit(memcmp(eui64, &kEui64, sizeof(spinel_eui64_t)) == 0, "ReadEui64() parse failed."); + VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0, "ReadUtf8() parse failed."); + VerifyOrQuit(memcmp(utf_2, kString_2, sizeof(kString_2)) == 0, "ReadUtf8() parse failed."); + VerifyOrQuit(dataLen_1 == sizeof(kData), "ReadData() parse failed."); + VerifyOrQuit(memcmp(dataPtr_1, &kData, sizeof(kData)) == 0, "ReadData() parse failed."); + VerifyOrQuit(dataLen_2 == sizeof(kData), "ReadData() parse failed."); + VerifyOrQuit(memcmp(dataPtr_2, &kData, sizeof(kData)) == 0, "ReadData() parse failed."); + + printf(" -- PASS\n"); + + printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + printf("\nTest 2: Test Reset(), SavePosition(), ResetToSaved()"); + + // `ResetToSaved()` should fail if there is no saved position + VerifyOrQuit(decoder.ResetToSaved() == OT_ERROR_INVALID_STATE, "ResetToSaved() did not fail"); + + decoder.Reset(); + + VerifyOrQuit(decoder.GetFrame() == &buffer[0], "GetFrame() failed."); + VerifyOrQuit(decoder.GetLength() == frameLen, "GetLength() failed."); + VerifyOrQuit(decoder.GetReadLength() == 0, "GetReadLength() failed."); + VerifyOrQuit(decoder.GetRemainingLength() == frameLen, "GetRemainingLength() failed."); + VerifyOrQuit(decoder.IsAllRead() == false, "IsAllRead() failed."); + + SuccessOrQuit(decoder.ReadBool(b_1), "ReadBool() failed."); + SuccessOrQuit(decoder.ReadBool(b_2), "ReadBool() failed."); + SuccessOrQuit(decoder.ReadUint8(u8), "ReadUint8() failed."); + SuccessOrQuit(decoder.ReadInt8(i8), "ReadUint8() failed."); + SuccessOrQuit(decoder.ReadUint16(u16), "ReadUint16() failed."); + SuccessOrQuit(decoder.ReadInt16(i16), "ReadInt16() failed."); + SuccessOrQuit(decoder.ReadUint32(u32), "ReadUint32() failed."); + SuccessOrQuit(decoder.ReadInt32(i32), "ReadUint32() failed."); + + // `ResetToSaved()` should fail if there is no saved position + VerifyOrQuit(decoder.ResetToSaved() == OT_ERROR_INVALID_STATE, "ResetToSaved() did not fail"); + + // Save position + decoder.SavePosition(); + + SuccessOrQuit(decoder.ReadUintPacked(u_1), "ReadUintPacked() failed."); + SuccessOrQuit(decoder.ReadUintPacked(u_2), "ReadUintPacked() failed."); + SuccessOrQuit(decoder.ReadUintPacked(u_3), "ReadUintPacked() failed."); + SuccessOrQuit(decoder.ReadUintPacked(u_4), "ReadUintPacked() failed."); + SuccessOrQuit(decoder.ReadIp6Address(ip6Addr), "ReadIp6Addr() failed."); + + VerifyOrQuit(b_1 == kBool_1, "ReadBool() parse failed."); + VerifyOrQuit(b_2 == kBool_2, "ReadBool() parse failed."); + VerifyOrQuit(u8 == kUint8, "ReadUint8() parse failed."); + VerifyOrQuit(i8 == kInt8, "ReadUint8() parse failed."); + VerifyOrQuit(u16 == kUint16, "ReadUint16() parse failed."); + VerifyOrQuit(i16 == kInt16, "ReadInt16() parse failed."); + VerifyOrQuit(u32 == kUint32, "ReadUint32() parse failed."); + VerifyOrQuit(i32 == kInt32, "ReadUint32() parse failed."); + VerifyOrQuit(u_1 == kUint_1, "ReadUintPacked() parse failed."); + VerifyOrQuit(u_2 == kUint_2, "ReadUintPacked() parse failed."); + VerifyOrQuit(u_3 == kUint_3, "ReadUintPacked() parse failed."); + VerifyOrQuit(u_4 == kUint_4, "ReadUintPacked() parse failed."); + VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0, "ReadIp6Address() parse failed."); + + SuccessOrQuit(decoder.ResetToSaved(), "ResetToSaved() failed"); + + SuccessOrQuit(decoder.ReadUintPacked(u_1), "ReadUintPacked() failed."); + SuccessOrQuit(decoder.ReadUintPacked(u_2), "ReadUintPacked() failed."); + SuccessOrQuit(decoder.ReadUintPacked(u_3), "ReadUintPacked() failed."); + SuccessOrQuit(decoder.ReadUintPacked(u_4), "ReadUintPacked() failed."); + SuccessOrQuit(decoder.ReadIp6Address(ip6Addr), "ReadIp6Addr() failed."); + + VerifyOrQuit(u_1 == kUint_1, "ReadUintPacked() parse failed."); + VerifyOrQuit(u_2 == kUint_2, "ReadUintPacked() parse failed."); + VerifyOrQuit(u_3 == kUint_3, "ReadUintPacked() parse failed."); + VerifyOrQuit(u_4 == kUint_4, "ReadUintPacked() parse failed."); + VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0, "ReadIp6Address() parse failed."); + + // Go back to save position again. + SuccessOrQuit(decoder.ResetToSaved(), "ResetToSaved() failed"); + + SuccessOrQuit(decoder.ReadUintPacked(u_1), "ReadUintPacked() failed."); + SuccessOrQuit(decoder.ReadUintPacked(u_2), "ReadUintPacked() failed."); + SuccessOrQuit(decoder.ReadUintPacked(u_3), "ReadUintPacked() failed."); + SuccessOrQuit(decoder.ReadUintPacked(u_4), "ReadUintPacked() failed."); + SuccessOrQuit(decoder.ReadIp6Address(ip6Addr), "ReadIp6Addr() failed."); + + VerifyOrQuit(u_1 == kUint_1, "ReadUintPacked() parse failed."); + VerifyOrQuit(u_2 == kUint_2, "ReadUintPacked() parse failed."); + VerifyOrQuit(u_3 == kUint_3, "ReadUintPacked() parse failed."); + VerifyOrQuit(u_4 == kUint_4, "ReadUintPacked() parse failed."); + VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0, "ReadIp6Address() parse failed."); + + // Ensure saved position is cleared when decoder is reset or re-initialized. + + decoder.Reset(); + + // `ResetToSaved()` should fail if there is no saved position + VerifyOrQuit(decoder.ResetToSaved() == OT_ERROR_INVALID_STATE, "ResetToSaved() did not fail"); + + decoder.SavePosition(); + SuccessOrQuit(decoder.ResetToSaved(), "ResetToSaved() failed"); + + decoder.Init(buffer, static_cast(frameLen)); + VerifyOrQuit(decoder.ResetToSaved() == OT_ERROR_INVALID_STATE, "ResetToSaved() did not fail"); + + printf(" -- PASS\n"); + + printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + printf("\nTest 3: Test decoding a single simple struct."); + + frameLen = spinel_datatype_pack( + buffer, + sizeof(buffer), + ( + SPINEL_DATATYPE_UINT8_S + SPINEL_DATATYPE_STRUCT_S( + SPINEL_DATATYPE_UINT32_S + SPINEL_DATATYPE_EUI48_S + SPINEL_DATATYPE_UINT_PACKED_S + ) + SPINEL_DATATYPE_INT16_S + + ), + kUint8, + kUint32, + &kEui48, + kUint_3, + kInt16 + ); + + DumpBuffer("Packed Spinel Frame (single struct)", buffer, static_cast(frameLen)); + + decoder.Init(buffer, static_cast(frameLen)); + + SuccessOrQuit(decoder.ReadUint8(u8), "ReadUint8() failed."); + SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed."); + { + SuccessOrQuit(decoder.ReadUint32(u32), "ReadUint32() failed."); + SuccessOrQuit(decoder.ReadEui48(eui48), "ReadEui48() failed."); + SuccessOrQuit(decoder.ReadUintPacked(u_3), "ReadUintPacked() failed."); + } + SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed."); + SuccessOrQuit(decoder.ReadInt16(i16), "ReadInt16() failed."); + VerifyOrQuit(decoder.IsAllRead() == true, "IsAllRead() failed."); + + VerifyOrQuit(u8 == kUint8, "ReadUint8() parse failed."); + VerifyOrQuit(i16 == kInt16, "ReadInt16() parse failed."); + VerifyOrQuit(u32 == kUint32, "ReadUint32() parse failed."); + VerifyOrQuit(u_3 == kUint_3, "ReadUintPacked() parse failed."); + VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0, "ReadEui48() parse failed."); + + printf(" -- PASS\n"); + + printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + printf("\nTest 4: Test partial struct read"); + + // Re-use same frame as the previous test. + + decoder.Init(buffer, static_cast(frameLen)); + + SuccessOrQuit(decoder.ReadUint8(u8), "ReadUint8() failed."); + SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed."); + { + SuccessOrQuit(decoder.ReadUint32(u32), "ReadUint32() failed."); + // Skip the remaining fields in the struct + } + SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed."); + SuccessOrQuit(decoder.ReadInt16(i16), "ReadInt16() failed."); + + VerifyOrQuit(u8 == kUint8, "ReadUint8() parse failed."); + VerifyOrQuit(i16 == kInt16, "ReadInt16() parse failed."); + + printf(" -- PASS\n"); + + + printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + printf("\nTest 5: Test `GetRemainingLengthInStruct()` and `IsAllReadInStruct`() in and out of an struct"); + + // Re-use same frame as the previous test. + + decoder.Init(buffer, static_cast(frameLen)); + + VerifyOrQuit(decoder.GetFrame() == &buffer[0], "GetFrame() failed."); + VerifyOrQuit(decoder.GetLength() == frameLen, "GetLength() failed."); + + VerifyOrQuit(decoder.GetReadLength() == 0, "GetReadLength() failed."); + VerifyOrQuit(decoder.GetRemainingLength() == frameLen, "GetRemainingLength() failed."); + VerifyOrQuit(decoder.IsAllRead() == false, "IsAllRead() failed."); + + // When not in an struct, `etRemainingLengthInStruct()` should consider the whole frame. + VerifyOrQuit(decoder.GetRemainingLengthInStruct() == frameLen, "GetRemLengthInStruct() failed."); + VerifyOrQuit(decoder.IsAllReadInStruct() == false, "IsAllReadInStruct() failed."); + + SuccessOrQuit(decoder.ReadUint8(u8), "ReadUint8() failed."); + SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed."); + { + VerifyOrQuit(decoder.IsAllReadInStruct() == false, "IsAllReadInStruct() failed."); + + SuccessOrQuit(decoder.ReadUint32(u32), "ReadUint32() failed."); + SuccessOrQuit(decoder.ReadEui48(eui48), "ReadEui48() failed."); + SuccessOrQuit(decoder.ReadUintPacked(u_3), "ReadUintPacked() failed."); + + VerifyOrQuit(decoder.IsAllReadInStruct() == true, "IsAllReadInStruct() failed."); + VerifyOrQuit(decoder.GetRemainingLengthInStruct() == 0, "GetRemLengthInStruct() failed."); + + // Try reading beyond end of the struct and ensure it fails. + VerifyOrQuit(decoder.ReadUint8(u8) == OT_ERROR_PARSE, "ReadUint8() did not fail."); + + // `ReadData()` at end of struct should still succeed but return zero as the data length. + SuccessOrQuit(decoder.ReadData(dataPtr_1, dataLen_1), "ReadData() failed."); + VerifyOrQuit(dataLen_1 == 0, "ReadData() parse value failed."); + + } + SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed."); + + VerifyOrQuit(decoder.IsAllReadInStruct() == false, "IsAllReadInStruct() failed."); + SuccessOrQuit(decoder.ReadInt16(i16), "ReadInt16() failed."); + VerifyOrQuit(decoder.IsAllRead() == true, "IsAllRead() failed."); + + VerifyOrQuit(decoder.GetRemainingLengthInStruct() == 0, "GetRemLengthInStruct() failed."); + VerifyOrQuit(decoder.IsAllReadInStruct() == true, "IsAllReadInStruct() failed."); + + // `ReadData()` at end of frame should still succeed but return zero as the data length. + SuccessOrQuit(decoder.ReadData(dataPtr_1, dataLen_1), "ReadData() failed."); + VerifyOrQuit(dataLen_1 == 0, "ReadData() parse value failed."); + + VerifyOrQuit(u8 == kUint8, "ReadUint8() parse failed."); + VerifyOrQuit(i16 == kInt16, "ReadInt16() parse failed."); + VerifyOrQuit(u32 == kUint32, "ReadUint32() parse failed."); + VerifyOrQuit(u_3 == kUint_3, "ReadUintPacked() parse failed."); + VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0, "ReadEui48() parse failed."); + + printf(" -- PASS\n"); + + printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + printf("\nTest 6: Test multiple nested structs"); + + frameLen = spinel_datatype_pack( + buffer, + sizeof(buffer), + ( + SPINEL_DATATYPE_STRUCT_S( + SPINEL_DATATYPE_UINT8_S + SPINEL_DATATYPE_UTF8_S + SPINEL_DATATYPE_STRUCT_S( + SPINEL_DATATYPE_BOOL_S + SPINEL_DATATYPE_IPv6ADDR_S + ) + SPINEL_DATATYPE_UINT16_S + ) + SPINEL_DATATYPE_EUI48_S + SPINEL_DATATYPE_STRUCT_S( + SPINEL_DATATYPE_UINT32_S + ) + SPINEL_DATATYPE_INT32_S + ), + kUint8, + kString_1, + kBool_1, + &kIp6Addr, + kUint16, + &kEui48, + kUint32, + kInt32 + ); + + DumpBuffer("Packed Spinel Frame (multiple struct)", buffer, static_cast(frameLen)); + + decoder.Init(buffer, static_cast(frameLen)); + + SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed."); + { + SuccessOrQuit(decoder.ReadUint8(u8), "ReadUint8() failed."); + SuccessOrQuit(decoder.ReadUtf8(utf_1), "ReadUtf8() failed."); + SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed."); + { + SuccessOrQuit(decoder.ReadBool(b_1), "ReadBool() failed."); + SuccessOrQuit(decoder.ReadIp6Address(ip6Addr), "ReadIp6Addr() failed."); + + } + SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed."); + SuccessOrQuit(decoder.ReadUint16(u16), "ReadUint16() failed."); + } + SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed."); + SuccessOrQuit(decoder.ReadEui48(eui48), "ReadEui48() failed."); + SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed."); + { + SuccessOrQuit(decoder.ReadUint32(u32), "ReadUint32() failed."); + } + SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed."); + SuccessOrQuit(decoder.ReadInt32(i32), "WriteUint32() failed."); + + VerifyOrQuit(decoder.GetReadLength() == frameLen, "GetReadLength() failed."); + VerifyOrQuit(decoder.GetRemainingLength() == 0, "GetRemainingLength() failed."); + VerifyOrQuit(decoder.IsAllRead() == true, "IsAllRead() failed."); + + VerifyOrQuit(b_1 == kBool_1, "ReadBool() parse failed."); + VerifyOrQuit(u8 == kUint8, "ReadUint8() parse failed."); + VerifyOrQuit(u16 == kUint16, "ReadUint16() parse failed."); + VerifyOrQuit(u32 == kUint32, "ReadUint32() parse failed."); + VerifyOrQuit(i32 == kInt32, "ReadUint32() parse failed."); + VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0, "ReadIp6Address() parse failed."); + VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0, "ReadEui48() parse failed."); + VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0, "ReadUtf8() parse failed."); + + printf(" -- PASS\n"); + + printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + printf("\nTest 7: Test `SavePosition()`, `ResetToSaved()` for nested structs"); + + // Re-use same frame as the previous test. + + decoder.Init(buffer, static_cast(frameLen)); + + SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed."); + { + SuccessOrQuit(decoder.ReadUint8(u8), "ReadUint8() failed."); + + decoder.SavePosition(); + + SuccessOrQuit(decoder.ReadUtf8(utf_1), "ReadUtf8() failed."); + SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed."); + { + SuccessOrQuit(decoder.ReadBool(b_1), "ReadBool() failed."); + } + + // Verify the read content so far. + + VerifyOrQuit(u8 == kUint8, "ReadUint8() parse failed."); + VerifyOrQuit(b_1 == kBool_1, "ReadBool() parse failed."); + VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0, "ReadUtf8() parse failed."); + + // Do not close the inner struct and jump to previously saved position and re-read the content. + + SuccessOrQuit(decoder.ResetToSaved(), "ResetToSaved() failed."); + + SuccessOrQuit(decoder.ReadUtf8(utf_1), "ReadUtf8() failed."); + SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed."); + { + SuccessOrQuit(decoder.ReadBool(b_1), "ReadBool() failed."); + SuccessOrQuit(decoder.ReadIp6Address(ip6Addr), "ReadIp6Addr() failed."); + + } + SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed."); + SuccessOrQuit(decoder.ReadUint16(u16), "ReadUint16() failed."); + } + SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed."); + SuccessOrQuit(decoder.ReadEui48(eui48), "ReadEui48() failed."); + SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed."); + { + SuccessOrQuit(decoder.ReadUint32(u32), "ReadUint32() failed."); + } + SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed."); + SuccessOrQuit(decoder.ReadInt32(i32), "WriteUint32() failed."); + + VerifyOrQuit(decoder.GetReadLength() == frameLen, "GetReadLength() failed."); + VerifyOrQuit(decoder.GetRemainingLength() == 0, "GetRemainingLength() failed."); + VerifyOrQuit(decoder.IsAllRead() == true, "IsAllRead() failed."); + + VerifyOrQuit(b_1 == kBool_1, "ReadBool() parse failed."); + VerifyOrQuit(u8 == kUint8, "ReadUint8() parse failed."); + VerifyOrQuit(u16 == kUint16, "ReadUint16() parse failed."); + VerifyOrQuit(u32 == kUint32, "ReadUint32() parse failed."); + VerifyOrQuit(i32 == kInt32, "ReadUint32() parse failed."); + VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0, "ReadIp6Address() parse failed."); + VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0, "ReadEui48() parse failed."); + VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0, "ReadUtf8() parse failed."); + + printf(" -- PASS\n"); + + printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + printf("\nTest 8: Test saving position at start of an open struct"); + + // Re-use same frame as the previous test. + + decoder.Init(buffer, static_cast(frameLen)); + + SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed."); + { + SuccessOrQuit(decoder.ReadUint8(u8), "ReadUint8() failed."); + SuccessOrQuit(decoder.ReadUtf8(utf_1), "ReadUtf8() failed."); + SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed."); + { + // Save position at start of the struct + decoder.SavePosition(); + SuccessOrQuit(decoder.ReadBool(b_1), "ReadBool() failed."); + + // Verify the read content so far. + + VerifyOrQuit(u8 == kUint8, "ReadUint8() parse failed."); + VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0, "ReadUtf8() parse failed."); + VerifyOrQuit(b_1 == kBool_1, "ReadBool() parse failed."); + + // Do not close the struct and jump to the previously saved position and re-read the content. + + SuccessOrQuit(decoder.ResetToSaved(), "ResetToSaved() failed."); + SuccessOrQuit(decoder.ReadBool(b_1), "ReadBool() failed."); + SuccessOrQuit(decoder.ReadIp6Address(ip6Addr), "ReadIp6Addr() failed."); + + } + SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed."); + SuccessOrQuit(decoder.ReadUint16(u16), "ReadUint16() failed."); + } + SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed."); + SuccessOrQuit(decoder.ReadEui48(eui48), "ReadEui48() failed."); + SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed."); + { + SuccessOrQuit(decoder.ReadUint32(u32), "ReadUint32() failed."); + } + SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed."); + SuccessOrQuit(decoder.ReadInt32(i32), "WriteUint32() failed."); + + VerifyOrQuit(decoder.GetReadLength() == frameLen, "GetReadLength() failed."); + VerifyOrQuit(decoder.GetRemainingLength() == 0, "GetRemainingLength() failed."); + VerifyOrQuit(decoder.IsAllRead() == true, "IsAllRead() failed."); + + VerifyOrQuit(b_1 == kBool_1, "ReadBool() parse failed."); + VerifyOrQuit(u8 == kUint8, "ReadUint8() parse failed."); + VerifyOrQuit(u16 == kUint16, "ReadUint16() parse failed."); + VerifyOrQuit(u32 == kUint32, "ReadUint32() parse failed."); + VerifyOrQuit(i32 == kInt32, "ReadUint32() parse failed."); + VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0, "ReadIp6Address() parse failed."); + VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0, "ReadEui48() parse failed."); + VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0, "ReadUtf8() parse failed."); + + printf(" -- PASS\n"); + + printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + printf("\nTest 9: Test `ResetToSaved()` failure case (jumping back to a saved position closed struct)."); + + // Re-use same frame as the previous test. + + decoder.Init(buffer, static_cast(frameLen)); + + SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed."); + { + SuccessOrQuit(decoder.ReadUint8(u8), "ReadUint8() failed."); + SuccessOrQuit(decoder.ReadUtf8(utf_1), "ReadUtf8() failed."); + SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed."); + { + SuccessOrQuit(decoder.ReadBool(b_1), "ReadBool() failed."); + + decoder.SavePosition(); + + SuccessOrQuit(decoder.ReadIp6Address(ip6Addr), "ReadIp6Addr() failed."); + + } + SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed."); + SuccessOrQuit(decoder.ReadUint16(u16), "ReadUint16() failed."); + + // `ResetToSaved()` should fail sicne the enclosing struct for the saved position is closed. + VerifyOrQuit(decoder.ResetToSaved() == OT_ERROR_INVALID_STATE, "ResetToSaved() did not fail."); + } + + printf(" -- PASS\n"); + + printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + printf("\nTest 10: Testing error cases and failures. (e.g., wrong struct length)."); + + frameLen = spinel_datatype_pack( + buffer, + sizeof(buffer), + ( + SPINEL_DATATYPE_UINT8_S + SPINEL_DATATYPE_UINT16_S // Treat this as struct length + SPINEL_DATATYPE_BOOL_S + ), + kUint8, + 10, + kBool_1 + ); + + DumpBuffer("Packed Spinel Frame (incorrect format)", buffer, static_cast(frameLen)); + + decoder.Init(buffer, static_cast(frameLen)); + + decoder.SavePosition(); + + SuccessOrQuit(decoder.ReadUint8(u8), "ReadUint8() failed."); + VerifyOrQuit(u8 == kUint8, "ReadUint8() parse failed."); + + // `OpenStruct()` should fail, since it expects a length 10 but there are not enough + // bytes in the frame. + VerifyOrQuit(decoder.OpenStruct() == OT_ERROR_PARSE, "OpenStruct() did not fail."); + + decoder.ResetToSaved(); + + SuccessOrQuit(decoder.ReadUint8(u8), "ReadUint8() failed."); + VerifyOrQuit(u8 == kUint8, "ReadUint8() parse failed."); + VerifyOrQuit(decoder.ReadDataWithLen(dataPtr_1, dataLen_1) == OT_ERROR_PARSE, + "ReadDataWithLen() did not fail."); + + decoder.ResetToSaved(); + SuccessOrQuit(decoder.ReadUint8(u8), "ReadUint8() failed."); + SuccessOrQuit(decoder.ReadUint16(u16), "ReadUint16() failed."); + SuccessOrQuit(decoder.ReadBool(b_1), "ReadUint16() failed."); + + // Try reading beyond end of frame. + VerifyOrQuit(decoder.ReadUint8(u8) == OT_ERROR_PARSE, "ReadUint8() did not fail"); + + printf(" -- PASS\n"); +} + +} // namespace Ncp +} // namespace ot + +#ifdef ENABLE_TEST_MAIN +int main(void) +{ + ot::Ncp::TestSpinelDecoder(); + printf("\nAll tests passed.\n"); + return 0; +} +#endif