| /* |
| * Copyright (c) 2016-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 minimal thread device required Spinel interface to the OpenThread stack. |
| */ |
| |
| #include "openthread-core-config.h" |
| |
| #include "ncp_base.hpp" |
| |
| #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
| #include <openthread/border_router.h> |
| #endif |
| #if OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE |
| #include <openthread/channel_monitor.h> |
| #endif |
| #if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE |
| #include <openthread/child_supervision.h> |
| #endif |
| #include <openthread/diag.h> |
| #include <openthread/icmp6.h> |
| #if OPENTHREAD_CONFIG_JAM_DETECTION_ENABLE |
| #include <openthread/jam_detection.h> |
| #endif |
| #include <openthread/ncp.h> |
| #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE |
| #include <openthread/network_time.h> |
| #endif |
| #include <openthread/platform/misc.h> |
| #include <openthread/platform/radio.h> |
| #if OPENTHREAD_FTD |
| #include <openthread/thread_ftd.h> |
| #endif |
| #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE |
| #include <openthread/server.h> |
| #endif |
| #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) |
| #include "openthread/backbone_router.h" |
| #endif |
| #if OPENTHREAD_CONFIG_SRP_CLIENT_BUFFERS_ENABLE |
| #include <openthread/srp_client_buffers.h> |
| #endif |
| #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE |
| #include <openthread/trel.h> |
| #endif |
| |
| #include "common/code_utils.hpp" |
| #include "common/debug.hpp" |
| #include "common/instance.hpp" |
| #include "common/string.hpp" |
| #include "net/ip6.hpp" |
| |
| #if OPENTHREAD_MTD || OPENTHREAD_FTD |
| |
| namespace ot { |
| namespace Ncp { |
| |
| static uint8_t BorderRouterConfigToFlagByte(const otBorderRouterConfig &aConfig) |
| { |
| uint8_t flags = 0; |
| |
| if (aConfig.mPreferred) |
| { |
| flags |= SPINEL_NET_FLAG_PREFERRED; |
| } |
| |
| if (aConfig.mSlaac) |
| { |
| flags |= SPINEL_NET_FLAG_SLAAC; |
| } |
| |
| if (aConfig.mDhcp) |
| { |
| flags |= SPINEL_NET_FLAG_DHCP; |
| } |
| |
| if (aConfig.mDefaultRoute) |
| { |
| flags |= SPINEL_NET_FLAG_DEFAULT_ROUTE; |
| } |
| |
| if (aConfig.mConfigure) |
| { |
| flags |= SPINEL_NET_FLAG_CONFIGURE; |
| } |
| |
| if (aConfig.mOnMesh) |
| { |
| flags |= SPINEL_NET_FLAG_ON_MESH; |
| } |
| |
| flags |= (static_cast<uint8_t>(aConfig.mPreference) << SPINEL_NET_FLAG_PREFERENCE_OFFSET); |
| |
| return flags; |
| } |
| |
| static uint8_t BorderRouterConfigToFlagByteExtended(const otBorderRouterConfig &aConfig) |
| { |
| uint8_t flags = 0; |
| |
| if (aConfig.mNdDns) |
| { |
| flags |= SPINEL_NET_FLAG_EXT_DNS; |
| } |
| |
| if (aConfig.mDp) |
| { |
| flags |= SPINEL_NET_FLAG_EXT_DP; |
| } |
| |
| return flags; |
| } |
| |
| static uint8_t ExternalRouteConfigToFlagByte(const otExternalRouteConfig &aConfig) |
| { |
| uint8_t flags = 0; |
| |
| switch (aConfig.mPreference) |
| { |
| case OT_ROUTE_PREFERENCE_LOW: |
| flags |= SPINEL_ROUTE_PREFERENCE_LOW; |
| break; |
| |
| case OT_ROUTE_PREFERENCE_HIGH: |
| flags |= SPINEL_ROUTE_PREFERENCE_HIGH; |
| break; |
| |
| case OT_ROUTE_PREFERENCE_MED: |
| default: |
| flags |= SPINEL_ROUTE_PREFERENCE_MEDIUM; |
| break; |
| } |
| |
| if (aConfig.mNat64) |
| { |
| flags |= SPINEL_ROUTE_FLAG_NAT64; |
| } |
| |
| return flags; |
| } |
| |
| uint8_t NcpBase::LinkFlagsToFlagByte(bool aRxOnWhenIdle, bool aDeviceType, bool aNetworkData) |
| { |
| uint8_t flags(0); |
| |
| if (aRxOnWhenIdle) |
| { |
| flags |= SPINEL_THREAD_MODE_RX_ON_WHEN_IDLE; |
| } |
| |
| if (aDeviceType) |
| { |
| flags |= SPINEL_THREAD_MODE_FULL_THREAD_DEV; |
| } |
| |
| if (aNetworkData) |
| { |
| flags |= SPINEL_THREAD_MODE_FULL_NETWORK_DATA; |
| } |
| |
| return flags; |
| } |
| |
| otError NcpBase::EncodeNeighborInfo(const otNeighborInfo &aNeighborInfo) |
| { |
| otError error; |
| uint8_t modeFlags; |
| |
| modeFlags = LinkFlagsToFlagByte(aNeighborInfo.mRxOnWhenIdle, aNeighborInfo.mFullThreadDevice, |
| aNeighborInfo.mFullNetworkData); |
| |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| |
| SuccessOrExit(error = mEncoder.WriteEui64(aNeighborInfo.mExtAddress)); |
| SuccessOrExit(error = mEncoder.WriteUint16(aNeighborInfo.mRloc16)); |
| SuccessOrExit(error = mEncoder.WriteUint32(aNeighborInfo.mAge)); |
| SuccessOrExit(error = mEncoder.WriteUint8(aNeighborInfo.mLinkQualityIn)); |
| SuccessOrExit(error = mEncoder.WriteInt8(aNeighborInfo.mAverageRssi)); |
| SuccessOrExit(error = mEncoder.WriteUint8(modeFlags)); |
| SuccessOrExit(error = mEncoder.WriteBool(aNeighborInfo.mIsChild)); |
| SuccessOrExit(error = mEncoder.WriteUint32(aNeighborInfo.mLinkFrameCounter)); |
| SuccessOrExit(error = mEncoder.WriteUint32(aNeighborInfo.mMleFrameCounter)); |
| SuccessOrExit(error = mEncoder.WriteInt8(aNeighborInfo.mLastRssi)); |
| |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| |
| exit: |
| return error; |
| } |
| |
| #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE |
| otError NcpBase::EncodeLinkMetricsValues(const otLinkMetricsValues *aMetricsValues) |
| { |
| otError error = OT_ERROR_NONE; |
| |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| |
| if (aMetricsValues->mMetrics.mPduCount) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| SuccessOrExit(error = mEncoder.WriteUint8(SPINEL_THREAD_LINK_METRIC_PDU_COUNT)); |
| SuccessOrExit(error = mEncoder.WriteUint32(aMetricsValues->mPduCountValue)); |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| if (aMetricsValues->mMetrics.mLqi) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| SuccessOrExit(error = mEncoder.WriteUint8(SPINEL_THREAD_LINK_METRIC_LQI)); |
| SuccessOrExit(error = mEncoder.WriteUint8(aMetricsValues->mLqiValue)); |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| if (aMetricsValues->mMetrics.mLinkMargin) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| SuccessOrExit(error = mEncoder.WriteUint8(SPINEL_THREAD_LINK_METRIC_LINK_MARGIN)); |
| SuccessOrExit(error = mEncoder.WriteUint8(aMetricsValues->mLinkMarginValue)); |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| if (aMetricsValues->mMetrics.mRssi) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| SuccessOrExit(error = mEncoder.WriteUint8(SPINEL_THREAD_LINK_METRIC_RSSI)); |
| SuccessOrExit(error = mEncoder.WriteInt8(aMetricsValues->mRssiValue)); |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| |
| exit: |
| return error; |
| } |
| #endif |
| |
| #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_CSL_PERIOD>(void) |
| { |
| uint16_t cslPeriod; |
| otError error = OT_ERROR_NONE; |
| |
| SuccessOrExit(error = mDecoder.ReadUint16(cslPeriod)); |
| |
| error = otLinkCslSetPeriod(mInstance, cslPeriod); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_CSL_PERIOD>(void) |
| { |
| return mEncoder.WriteUint16(otLinkCslGetPeriod(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_CSL_TIMEOUT>(void) |
| { |
| uint32_t cslTimeout; |
| otError error = OT_ERROR_NONE; |
| |
| SuccessOrExit(error = mDecoder.ReadUint32(cslTimeout)); |
| |
| error = otLinkCslSetTimeout(mInstance, cslTimeout); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_CSL_TIMEOUT>(void) |
| { |
| return mEncoder.WriteUint32(otLinkCslGetTimeout(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_CSL_CHANNEL>(void) |
| { |
| uint8_t cslChannel; |
| otError error = OT_ERROR_NONE; |
| |
| SuccessOrExit(error = mDecoder.ReadUint8(cslChannel)); |
| |
| error = otLinkCslSetChannel(mInstance, cslChannel); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_CSL_CHANNEL>(void) |
| { |
| return mEncoder.WriteUint8(otLinkCslGetChannel(mInstance)); |
| } |
| #endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE |
| |
| #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_MLR_REQUEST>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| otIp6Address addresses[kIp6AddressesNumMax]; |
| uint8_t addressesCount = 0U; |
| bool timeoutPresent = false; |
| uint32_t timeout; |
| |
| SuccessOrExit(error = mDecoder.OpenStruct()); |
| |
| while (mDecoder.GetRemainingLengthInStruct()) |
| { |
| VerifyOrExit(addressesCount < kIp6AddressesNumMax, error = OT_ERROR_NO_BUFS); |
| SuccessOrExit(error = mDecoder.ReadIp6Address(addresses[addressesCount])); |
| ++addressesCount; |
| } |
| |
| SuccessOrExit(error = mDecoder.CloseStruct()); |
| |
| while (mDecoder.GetRemainingLengthInStruct()) |
| { |
| uint8_t paramId; |
| |
| SuccessOrExit(error = mDecoder.OpenStruct()); |
| |
| SuccessOrExit(error = mDecoder.ReadUint8(paramId)); |
| |
| switch (paramId) |
| { |
| case SPINEL_THREAD_MLR_PARAMID_TIMEOUT: |
| SuccessOrExit(error = mDecoder.ReadUint32(timeout)); |
| timeoutPresent = true; |
| break; |
| |
| default: |
| ExitNow(error = OT_ERROR_INVALID_ARGS); |
| } |
| |
| SuccessOrExit(error = mDecoder.CloseStruct()); |
| } |
| |
| SuccessOrExit(error = otIp6RegisterMulticastListeners(mInstance, addresses, addressesCount, |
| timeoutPresent ? &timeout : nullptr, |
| &NcpBase::HandleMlrRegResult_Jump, this)); |
| exit: |
| return error; |
| } |
| |
| void NcpBase::HandleMlrRegResult_Jump(void * aContext, |
| otError aError, |
| uint8_t aMlrStatus, |
| const otIp6Address *aFailedAddresses, |
| uint8_t aFailedAddressNum) |
| { |
| static_cast<NcpBase *>(aContext)->HandleMlrRegResult(aError, aMlrStatus, aFailedAddresses, aFailedAddressNum); |
| } |
| |
| void NcpBase::HandleMlrRegResult(otError aError, |
| uint8_t aMlrStatus, |
| const otIp6Address *aFailedAddresses, |
| uint8_t aFailedAddressNum) |
| { |
| SuccessOrExit(mEncoder.BeginFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_CMD_PROP_VALUE_IS, |
| SPINEL_PROP_THREAD_MLR_RESPONSE)); |
| |
| SuccessOrExit(mEncoder.WriteUint8(static_cast<uint8_t>(ThreadErrorToSpinelStatus(aError)))); |
| SuccessOrExit(mEncoder.WriteUint8(aMlrStatus)); |
| |
| SuccessOrExit(mEncoder.OpenStruct()); |
| |
| if (aError == OT_ERROR_NONE) |
| { |
| for (size_t i = 0U; i < aFailedAddressNum; ++i) |
| { |
| SuccessOrExit(mEncoder.WriteIp6Address(aFailedAddresses[i])); |
| } |
| } |
| |
| SuccessOrExit(mEncoder.CloseStruct()); |
| |
| SuccessOrExit(mEncoder.EndFrame()); |
| |
| exit: |
| return; |
| } |
| #endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE |
| |
| #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_BACKBONE_ROUTER_PRIMARY>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| otBackboneRouterConfig bbrConfig; |
| |
| SuccessOrExit(error = otBackboneRouterGetPrimary(mInstance, &bbrConfig)); |
| |
| SuccessOrExit(error = mEncoder.WriteUint16(bbrConfig.mServer16)); |
| SuccessOrExit(error = mEncoder.WriteUint16(bbrConfig.mReregistrationDelay)); |
| SuccessOrExit(error = mEncoder.WriteUint32(bbrConfig.mMlrTimeout)); |
| SuccessOrExit(error = mEncoder.WriteUint8(bbrConfig.mSequenceNumber)); |
| |
| exit: |
| return error; |
| } |
| #endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MAC_DATA_POLL_PERIOD>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetPollPeriod(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MAC_DATA_POLL_PERIOD>(void) |
| { |
| uint32_t pollPeriod; |
| otError error = OT_ERROR_NONE; |
| |
| SuccessOrExit(error = mDecoder.ReadUint32(pollPeriod)); |
| |
| error = otLinkSetPollPeriod(mInstance, pollPeriod); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MAC_EXTENDED_ADDR>(void) |
| { |
| return mEncoder.WriteEui64(*otLinkGetExtendedAddress(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MAC_MAX_RETRY_NUMBER_DIRECT>(void) |
| { |
| return mEncoder.WriteUint8(otLinkGetMaxFrameRetriesDirect(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MAC_MAX_RETRY_NUMBER_DIRECT>(void) |
| { |
| uint8_t maxFrameRetriesDirect; |
| otError error = OT_ERROR_NONE; |
| |
| SuccessOrExit(error = mDecoder.ReadUint8(maxFrameRetriesDirect)); |
| otLinkSetMaxFrameRetriesDirect(mInstance, maxFrameRetriesDirect); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_PHY_CHAN_SUPPORTED>(void) |
| { |
| uint32_t newMask = 0; |
| otError error = OT_ERROR_NONE; |
| |
| SuccessOrExit(error = DecodeChannelMask(newMask)); |
| error = otLinkSetSupportedChannelMask(mInstance, newMask); |
| |
| exit: |
| return error; |
| } |
| |
| otError NcpBase::CommandHandler_NET_CLEAR(uint8_t aHeader) |
| { |
| return PrepareLastStatusResponse(aHeader, ThreadErrorToSpinelStatus(otInstanceErasePersistentInfo(mInstance))); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_NET_SAVED>(void) |
| { |
| return mEncoder.WriteBool(otDatasetIsCommissioned(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_NET_IF_UP>(void) |
| { |
| return mEncoder.WriteBool(otIp6IsEnabled(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_NET_IF_UP>(void) |
| { |
| bool enabled = false; |
| otError error = OT_ERROR_NONE; |
| |
| SuccessOrExit(error = mDecoder.ReadBool(enabled)); |
| |
| error = otIp6SetEnabled(mInstance, enabled); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_NET_STACK_UP>(void) |
| { |
| return mEncoder.WriteBool(otThreadGetDeviceRole(mInstance) != OT_DEVICE_ROLE_DISABLED); |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_NET_STACK_UP>(void) |
| { |
| bool enabled = false; |
| otError error = OT_ERROR_NONE; |
| |
| SuccessOrExit(error = mDecoder.ReadBool(enabled)); |
| |
| // If the value has changed... |
| if (enabled != (otThreadGetDeviceRole(mInstance) != OT_DEVICE_ROLE_DISABLED)) |
| { |
| if (enabled) |
| { |
| error = otThreadSetEnabled(mInstance, true); |
| StartLegacy(); |
| } |
| else |
| { |
| error = otThreadSetEnabled(mInstance, false); |
| StopLegacy(); |
| } |
| } |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_NET_ROLE>(void) |
| { |
| spinel_net_role_t role(SPINEL_NET_ROLE_DETACHED); |
| |
| switch (otThreadGetDeviceRole(mInstance)) |
| { |
| case OT_DEVICE_ROLE_DISABLED: |
| case OT_DEVICE_ROLE_DETACHED: |
| role = SPINEL_NET_ROLE_DETACHED; |
| break; |
| |
| case OT_DEVICE_ROLE_CHILD: |
| role = SPINEL_NET_ROLE_CHILD; |
| break; |
| |
| case OT_DEVICE_ROLE_ROUTER: |
| role = SPINEL_NET_ROLE_ROUTER; |
| break; |
| |
| case OT_DEVICE_ROLE_LEADER: |
| role = SPINEL_NET_ROLE_LEADER; |
| break; |
| } |
| |
| return mEncoder.WriteUint8(role); |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_NET_ROLE>(void) |
| { |
| unsigned int role = 0; |
| otError error = OT_ERROR_NONE; |
| |
| SuccessOrExit(error = mDecoder.ReadUintPacked(role)); |
| |
| switch (role) |
| { |
| case SPINEL_NET_ROLE_DETACHED: |
| error = otThreadBecomeDetached(mInstance); |
| break; |
| |
| #if OPENTHREAD_FTD |
| case SPINEL_NET_ROLE_ROUTER: |
| error = otThreadBecomeRouter(mInstance); |
| break; |
| |
| case SPINEL_NET_ROLE_LEADER: |
| error = otThreadBecomeLeader(mInstance); |
| break; |
| #endif // OPENTHREAD_FTD |
| |
| case SPINEL_NET_ROLE_CHILD: |
| error = otThreadBecomeChild(mInstance); |
| break; |
| } |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_NET_NETWORK_NAME>(void) |
| { |
| return mEncoder.WriteUtf8(otThreadGetNetworkName(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_NET_NETWORK_NAME>(void) |
| { |
| const char *string = nullptr; |
| otError error = OT_ERROR_NONE; |
| |
| SuccessOrExit(error = mDecoder.ReadUtf8(string)); |
| |
| error = otThreadSetNetworkName(mInstance, string); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_NET_XPANID>(void) |
| { |
| return mEncoder.WriteData(otThreadGetExtendedPanId(mInstance)->m8, sizeof(spinel_net_xpanid_t)); |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_NET_XPANID>(void) |
| { |
| const uint8_t *ptr = nullptr; |
| uint16_t len; |
| otError error = OT_ERROR_NONE; |
| |
| SuccessOrExit(error = mDecoder.ReadData(ptr, len)); |
| |
| VerifyOrExit(len == sizeof(spinel_net_xpanid_t), error = OT_ERROR_PARSE); |
| |
| error = otThreadSetExtendedPanId(mInstance, reinterpret_cast<const otExtendedPanId *>(ptr)); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_NET_NETWORK_KEY>(void) |
| { |
| otNetworkKey networkKey; |
| |
| otThreadGetNetworkKey(mInstance, &networkKey); |
| |
| return mEncoder.WriteData(networkKey.m8, OT_NETWORK_KEY_SIZE); |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_NET_NETWORK_KEY>(void) |
| { |
| const uint8_t *ptr = nullptr; |
| uint16_t len; |
| otError error = OT_ERROR_NONE; |
| |
| SuccessOrExit(error = mDecoder.ReadData(ptr, len)); |
| |
| VerifyOrExit(len == OT_NETWORK_KEY_SIZE, error = OT_ERROR_PARSE); |
| |
| error = otThreadSetNetworkKey(mInstance, reinterpret_cast<const otNetworkKey *>(ptr)); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_NET_KEY_SEQUENCE_COUNTER>(void) |
| { |
| return mEncoder.WriteUint32(otThreadGetKeySequenceCounter(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_NET_KEY_SEQUENCE_COUNTER>(void) |
| { |
| uint32_t keySeqCounter; |
| otError error = OT_ERROR_NONE; |
| |
| SuccessOrExit(error = mDecoder.ReadUint32(keySeqCounter)); |
| |
| otThreadSetKeySequenceCounter(mInstance, keySeqCounter); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_NET_PARTITION_ID>(void) |
| { |
| return mEncoder.WriteUint32(otThreadGetPartitionId(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_NET_KEY_SWITCH_GUARDTIME>(void) |
| { |
| return mEncoder.WriteUint32(otThreadGetKeySwitchGuardTime(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_NET_KEY_SWITCH_GUARDTIME>(void) |
| { |
| uint32_t keyGuardTime; |
| otError error = OT_ERROR_NONE; |
| |
| SuccessOrExit(error = mDecoder.ReadUint32(keyGuardTime)); |
| |
| otThreadSetKeySwitchGuardTime(mInstance, keyGuardTime); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_NETWORK_DATA_VERSION>(void) |
| { |
| return mEncoder.WriteUint8(otNetDataGetVersion(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_STABLE_NETWORK_DATA_VERSION>(void) |
| { |
| return mEncoder.WriteUint8(otNetDataGetStableVersion(mInstance)); |
| } |
| |
| #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_NETWORK_DATA>(void) |
| { |
| uint8_t networkData[255]; |
| uint8_t networkDataLen = 255; |
| |
| IgnoreError(otBorderRouterGetNetData(mInstance, |
| false, // Stable? |
| networkData, &networkDataLen)); |
| |
| return mEncoder.WriteData(networkData, networkDataLen); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_STABLE_NETWORK_DATA>(void) |
| { |
| uint8_t networkData[255]; |
| uint8_t networkDataLen = 255; |
| |
| IgnoreError(otBorderRouterGetNetData(mInstance, |
| true, // Stable? |
| networkData, &networkDataLen)); |
| |
| return mEncoder.WriteData(networkData, networkDataLen); |
| } |
| #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_LEADER_NETWORK_DATA>(void) |
| { |
| uint8_t networkData[255]; |
| uint8_t networkDataLen = 255; |
| |
| IgnoreError(otNetDataGet(mInstance, |
| false, // Stable? |
| networkData, &networkDataLen)); |
| |
| return mEncoder.WriteData(networkData, networkDataLen); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_STABLE_LEADER_NETWORK_DATA>(void) |
| { |
| uint8_t networkData[255]; |
| uint8_t networkDataLen = 255; |
| |
| IgnoreError(otNetDataGet(mInstance, |
| true, // Stable? |
| networkData, &networkDataLen)); |
| |
| return mEncoder.WriteData(networkData, networkDataLen); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_LEADER_RID>(void) |
| { |
| return mEncoder.WriteUint8(otThreadGetLeaderRouterId(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_LEADER_ADDR>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| otIp6Address address; |
| |
| error = otThreadGetLeaderRloc(mInstance, &address); |
| |
| if (error == OT_ERROR_NONE) |
| { |
| error = mEncoder.WriteIp6Address(address); |
| } |
| else |
| { |
| error = mEncoder.OverwriteWithLastStatusError(ThreadErrorToSpinelStatus(error)); |
| } |
| |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_PARENT>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| |
| otRouterInfo parentInfo; |
| |
| error = otThreadGetParentInfo(mInstance, &parentInfo); |
| |
| if (error == OT_ERROR_NONE) |
| { |
| if (parentInfo.mLinkEstablished) |
| { |
| int8_t averageRssi; |
| int8_t lastRssi; |
| |
| IgnoreError(otThreadGetParentAverageRssi(mInstance, &averageRssi)); |
| IgnoreError(otThreadGetParentLastRssi(mInstance, &lastRssi)); |
| |
| SuccessOrExit(error = mEncoder.WriteEui64(parentInfo.mExtAddress)); |
| SuccessOrExit(error = mEncoder.WriteUint16(parentInfo.mRloc16)); |
| SuccessOrExit(error = mEncoder.WriteUint32(parentInfo.mAge)); |
| SuccessOrExit(error = mEncoder.WriteInt8(averageRssi)); |
| SuccessOrExit(error = mEncoder.WriteInt8(lastRssi)); |
| SuccessOrExit(error = mEncoder.WriteUint8(parentInfo.mLinkQualityIn)); |
| SuccessOrExit(error = mEncoder.WriteUint8(parentInfo.mLinkQualityOut)); |
| } |
| else |
| { |
| SuccessOrExit(error = mEncoder.OverwriteWithLastStatusError(SPINEL_STATUS_ITEM_NOT_FOUND)); |
| } |
| } |
| else |
| { |
| error = mEncoder.OverwriteWithLastStatusError(ThreadErrorToSpinelStatus(error)); |
| } |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_NEIGHBOR_TABLE>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| otNeighborInfoIterator iter = OT_NEIGHBOR_INFO_ITERATOR_INIT; |
| otNeighborInfo neighInfo; |
| |
| while (otThreadGetNextNeighborInfo(mInstance, &iter, &neighInfo) == OT_ERROR_NONE) |
| { |
| SuccessOrExit(error = EncodeNeighborInfo(neighInfo)); |
| } |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_NEIGHBOR_TABLE_ERROR_RATES>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| otNeighborInfoIterator iter = OT_NEIGHBOR_INFO_ITERATOR_INIT; |
| otNeighborInfo neighInfo; |
| |
| while (otThreadGetNextNeighborInfo(mInstance, &iter, &neighInfo) == OT_ERROR_NONE) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| |
| SuccessOrExit(error = mEncoder.WriteEui64(neighInfo.mExtAddress)); |
| SuccessOrExit(error = mEncoder.WriteUint16(neighInfo.mRloc16)); |
| SuccessOrExit(error = mEncoder.WriteUint16(neighInfo.mFrameErrorRate)); |
| SuccessOrExit(error = mEncoder.WriteUint16(neighInfo.mMessageErrorRate)); |
| SuccessOrExit(error = mEncoder.WriteInt8(neighInfo.mAverageRssi)); |
| SuccessOrExit(error = mEncoder.WriteInt8(neighInfo.mLastRssi)); |
| |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_ASSISTING_PORTS>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| uint8_t numEntries = 0; |
| const uint16_t *ports = otIp6GetUnsecurePorts(mInstance, &numEntries); |
| |
| for (; numEntries != 0; ports++, numEntries--) |
| { |
| SuccessOrExit(error = mEncoder.WriteUint16(*ports)); |
| } |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_ASSISTING_PORTS>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| |
| // First, we need to remove all of the current assisting ports. |
| otIp6RemoveAllUnsecurePorts(mInstance); |
| |
| while (mDecoder.GetRemainingLengthInStruct() >= sizeof(uint16_t)) |
| { |
| uint16_t port; |
| |
| SuccessOrExit(error = mDecoder.ReadUint16(port)); |
| SuccessOrExit(error = otIp6AddUnsecurePort(mInstance, port)); |
| } |
| |
| exit: |
| |
| if (error != OT_ERROR_NONE) |
| { |
| // We had an error, but we've actually changed |
| // the state of these ports, so we need to report |
| // those incomplete changes via an asynchronous |
| // change event. |
| IgnoreError( |
| WritePropertyValueIsFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_PROP_THREAD_ASSISTING_PORTS)); |
| } |
| |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE>(void) |
| { |
| return mEncoder.WriteBool(mAllowLocalNetworkDataChange); |
| } |
| |
| #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE>(void) |
| { |
| bool value = false; |
| otError error = OT_ERROR_NONE; |
| bool shouldRegisterWithLeader = false; |
| |
| SuccessOrExit(error = mDecoder.ReadBool(value)); |
| |
| // Register any net data changes on transition from `true` to `false`. |
| shouldRegisterWithLeader = mAllowLocalNetworkDataChange && !value; |
| |
| mAllowLocalNetworkDataChange = value; |
| |
| exit: |
| |
| if (shouldRegisterWithLeader) |
| { |
| IgnoreError(otBorderRouterRegister(mInstance)); |
| } |
| |
| return error; |
| } |
| #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_ON_MESH_NETS>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| otBorderRouterConfig borderRouterConfig; |
| otNetworkDataIterator iter = OT_NETWORK_DATA_ITERATOR_INIT; |
| |
| // Fill from non-local network data first |
| while (otNetDataGetNextOnMeshPrefix(mInstance, &iter, &borderRouterConfig) == OT_ERROR_NONE) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| |
| SuccessOrExit(error = mEncoder.WriteIp6Address(borderRouterConfig.mPrefix.mPrefix)); |
| SuccessOrExit(error = mEncoder.WriteUint8(borderRouterConfig.mPrefix.mLength)); |
| SuccessOrExit(error = mEncoder.WriteBool(borderRouterConfig.mStable)); |
| SuccessOrExit(error = mEncoder.WriteUint8(BorderRouterConfigToFlagByte(borderRouterConfig))); |
| SuccessOrExit(error = mEncoder.WriteBool(false)); // isLocal |
| SuccessOrExit(error = mEncoder.WriteUint16(borderRouterConfig.mRloc16)); |
| SuccessOrExit(error = mEncoder.WriteUint8(BorderRouterConfigToFlagByteExtended(borderRouterConfig))); |
| |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
| |
| iter = OT_NETWORK_DATA_ITERATOR_INIT; |
| |
| // Fill from local network data last |
| while (otBorderRouterGetNextOnMeshPrefix(mInstance, &iter, &borderRouterConfig) == OT_ERROR_NONE) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| |
| SuccessOrExit(error = mEncoder.WriteIp6Address(borderRouterConfig.mPrefix.mPrefix)); |
| SuccessOrExit(error = mEncoder.WriteUint8(borderRouterConfig.mPrefix.mLength)); |
| SuccessOrExit(error = mEncoder.WriteBool(borderRouterConfig.mStable)); |
| SuccessOrExit(error = mEncoder.WriteUint8(BorderRouterConfigToFlagByte(borderRouterConfig))); |
| SuccessOrExit(error = mEncoder.WriteBool(true)); // isLocal |
| SuccessOrExit(error = mEncoder.WriteUint16(borderRouterConfig.mRloc16)); |
| SuccessOrExit(error = mEncoder.WriteUint8(BorderRouterConfigToFlagByteExtended(borderRouterConfig))); |
| |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
| |
| exit: |
| return error; |
| } |
| |
| #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
| template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_THREAD_ON_MESH_NETS>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| otBorderRouterConfig borderRouterConfig; |
| bool stable = false; |
| bool isLocal; |
| uint8_t flags = 0; |
| uint8_t flagsExtended = 0; |
| uint8_t prefixLength; |
| uint16_t rloc16; |
| |
| memset(&borderRouterConfig, 0, sizeof(otBorderRouterConfig)); |
| |
| VerifyOrExit(mAllowLocalNetworkDataChange, error = OT_ERROR_INVALID_STATE); |
| |
| SuccessOrExit(error = mDecoder.ReadIp6Address(borderRouterConfig.mPrefix.mPrefix)); |
| SuccessOrExit(error = mDecoder.ReadUint8(prefixLength)); |
| SuccessOrExit(error = mDecoder.ReadBool(stable)); |
| SuccessOrExit(error = mDecoder.ReadUint8(flags)); |
| |
| borderRouterConfig.mPrefix.mLength = prefixLength; |
| borderRouterConfig.mStable = stable; |
| borderRouterConfig.mPreference = ((flags & SPINEL_NET_FLAG_PREFERENCE_MASK) >> SPINEL_NET_FLAG_PREFERENCE_OFFSET); |
| borderRouterConfig.mPreferred = ((flags & SPINEL_NET_FLAG_PREFERRED) != 0); |
| borderRouterConfig.mSlaac = ((flags & SPINEL_NET_FLAG_SLAAC) != 0); |
| borderRouterConfig.mDhcp = ((flags & SPINEL_NET_FLAG_DHCP) != 0); |
| borderRouterConfig.mConfigure = ((flags & SPINEL_NET_FLAG_CONFIGURE) != 0); |
| borderRouterConfig.mDefaultRoute = ((flags & SPINEL_NET_FLAG_DEFAULT_ROUTE) != 0); |
| borderRouterConfig.mOnMesh = ((flags & SPINEL_NET_FLAG_ON_MESH) != 0); |
| |
| // A new field 'TLV flags extended' has been added to the SPINEL_PROP_THREAD_ON_MESH_NETS property. |
| // To correctly handle a new field for INSERT command, the additional fields 'isLocal' and 'rloc16' are read and |
| // ignored. |
| if ((mDecoder.ReadBool(isLocal) == OT_ERROR_NONE) && (mDecoder.ReadUint16(rloc16) == OT_ERROR_NONE) && |
| (mDecoder.ReadUint8(flagsExtended) == OT_ERROR_NONE)) |
| { |
| borderRouterConfig.mNdDns = ((flagsExtended & SPINEL_NET_FLAG_EXT_DNS) != 0); |
| borderRouterConfig.mDp = ((flagsExtended & SPINEL_NET_FLAG_EXT_DP) != 0); |
| } |
| |
| error = otBorderRouterAddOnMeshPrefix(mInstance, &borderRouterConfig); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyRemove<SPINEL_PROP_THREAD_ON_MESH_NETS>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| otIp6Prefix ip6Prefix; |
| uint8_t prefixLength; |
| |
| memset(&ip6Prefix, 0, sizeof(otIp6Prefix)); |
| |
| VerifyOrExit(mAllowLocalNetworkDataChange, error = OT_ERROR_INVALID_STATE); |
| |
| SuccessOrExit(error = mDecoder.ReadIp6Address(ip6Prefix.mPrefix)); |
| SuccessOrExit(error = mDecoder.ReadUint8(prefixLength)); |
| |
| ip6Prefix.mLength = prefixLength; |
| |
| error = otBorderRouterRemoveOnMeshPrefix(mInstance, &ip6Prefix); |
| |
| // If prefix was not on the list, "remove" command can be considred |
| // successful. |
| |
| if (error == OT_ERROR_NOT_FOUND) |
| { |
| error = OT_ERROR_NONE; |
| } |
| |
| exit: |
| return error; |
| } |
| #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
| |
| #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_SERVER_ALLOW_LOCAL_DATA_CHANGE>(void) |
| { |
| return mEncoder.WriteBool(mAllowLocalServerDataChange); |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_SERVER_ALLOW_LOCAL_DATA_CHANGE>(void) |
| { |
| bool value = false; |
| otError error = OT_ERROR_NONE; |
| bool shouldRegisterWithLeader = false; |
| |
| SuccessOrExit(error = mDecoder.ReadBool(value)); |
| |
| // Register any server data changes on transition from `true` to `false`. |
| shouldRegisterWithLeader = mAllowLocalServerDataChange && !value; |
| |
| mAllowLocalServerDataChange = value; |
| |
| exit: |
| |
| if (shouldRegisterWithLeader) |
| { |
| IgnoreError(otServerRegister(mInstance)); |
| } |
| |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_SERVER_SERVICES>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| otServiceConfig cfg; |
| bool stable; |
| const uint8_t * data; |
| uint16_t dataLen; |
| |
| VerifyOrExit(mAllowLocalServerDataChange, error = OT_ERROR_INVALID_STATE); |
| |
| SuccessOrExit(error = mDecoder.ReadUint32(cfg.mEnterpriseNumber)); |
| SuccessOrExit(error = mDecoder.ReadDataWithLen(data, dataLen)); |
| |
| VerifyOrExit((dataLen <= sizeof(cfg.mServiceData)), error = OT_ERROR_INVALID_ARGS); |
| memcpy(cfg.mServiceData, data, dataLen); |
| |
| static_assert((sizeof(cfg.mServiceData) <= UINT8_MAX), "Cannot handle full range of buffer length"); |
| cfg.mServiceDataLength = static_cast<uint8_t>(dataLen); |
| |
| SuccessOrExit(error = mDecoder.ReadBool(stable)); |
| cfg.mServerConfig.mStable = stable; |
| SuccessOrExit(error = mDecoder.ReadDataWithLen(data, dataLen)); |
| |
| VerifyOrExit((dataLen <= sizeof(cfg.mServerConfig.mServerData)), error = OT_ERROR_INVALID_ARGS); |
| memcpy(cfg.mServerConfig.mServerData, data, dataLen); |
| |
| static_assert((sizeof(cfg.mServerConfig.mServerData) <= UINT8_MAX), "Cannot handle full range of buffer length"); |
| cfg.mServerConfig.mServerDataLength = static_cast<uint8_t>(dataLen); |
| |
| SuccessOrExit(error = otServerAddService(mInstance, &cfg)); |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyRemove<SPINEL_PROP_SERVER_SERVICES>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| |
| uint32_t enterpriseNumber; |
| const uint8_t *serviceData; |
| uint16_t serviceDataLength; |
| |
| VerifyOrExit(mAllowLocalServerDataChange, error = OT_ERROR_INVALID_STATE); |
| |
| SuccessOrExit(error = mDecoder.ReadUint32(enterpriseNumber)); |
| SuccessOrExit(error = mDecoder.ReadDataWithLen(serviceData, serviceDataLength)); |
| |
| VerifyOrExit(serviceDataLength <= UINT8_MAX, error = OT_ERROR_INVALID_ARGS); |
| |
| SuccessOrExit(error = otServerRemoveService(mInstance, enterpriseNumber, serviceData, |
| static_cast<uint8_t>(serviceDataLength))); |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_SERVER_SERVICES>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT; |
| otServiceConfig cfg; |
| |
| while (otServerGetNextService(mInstance, &iterator, &cfg) == OT_ERROR_NONE) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| |
| SuccessOrExit(error = mEncoder.WriteUint32(cfg.mEnterpriseNumber)); |
| SuccessOrExit(error = mEncoder.WriteDataWithLen(cfg.mServiceData, cfg.mServiceDataLength)); |
| SuccessOrExit(error = mEncoder.WriteBool(cfg.mServerConfig.mStable)); |
| SuccessOrExit( |
| error = mEncoder.WriteDataWithLen(cfg.mServerConfig.mServerData, cfg.mServerConfig.mServerDataLength)); |
| SuccessOrExit(error = mEncoder.WriteUint16(cfg.mServerConfig.mRloc16)); |
| |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| exit: |
| return error; |
| } |
| #endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_SERVER_LEADER_SERVICES>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT; |
| otServiceConfig cfg; |
| |
| while (otNetDataGetNextService(mInstance, &iterator, &cfg) == OT_ERROR_NONE) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| |
| SuccessOrExit(error = mEncoder.WriteUint8(cfg.mServiceId)); |
| SuccessOrExit(error = mEncoder.WriteUint32(cfg.mEnterpriseNumber)); |
| SuccessOrExit(error = mEncoder.WriteDataWithLen(cfg.mServiceData, cfg.mServiceDataLength)); |
| SuccessOrExit(error = mEncoder.WriteBool(cfg.mServerConfig.mStable)); |
| SuccessOrExit( |
| error = mEncoder.WriteDataWithLen(cfg.mServerConfig.mServerData, cfg.mServerConfig.mServerDataLength)); |
| SuccessOrExit(error = mEncoder.WriteUint16(cfg.mServerConfig.mRloc16)); |
| |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_DISCOVERY_SCAN_JOINER_FLAG>(void) |
| { |
| return mEncoder.WriteBool(mDiscoveryScanJoinerFlag); |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_DISCOVERY_SCAN_JOINER_FLAG>(void) |
| { |
| return mDecoder.ReadBool(mDiscoveryScanJoinerFlag); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_DISCOVERY_SCAN_ENABLE_FILTERING>(void) |
| { |
| return mEncoder.WriteBool(mDiscoveryScanEnableFiltering); |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_DISCOVERY_SCAN_ENABLE_FILTERING>(void) |
| { |
| return mDecoder.ReadBool(mDiscoveryScanEnableFiltering); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_DISCOVERY_SCAN_PANID>(void) |
| { |
| return mEncoder.WriteUint16(mDiscoveryScanPanId); |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_DISCOVERY_SCAN_PANID>(void) |
| { |
| return mDecoder.ReadUint16(mDiscoveryScanPanId); |
| } |
| |
| otError NcpBase::EncodeOperationalDataset(const otOperationalDataset &aDataset) |
| { |
| otError error = OT_ERROR_NONE; |
| |
| if (aDataset.mComponents.mIsActiveTimestampPresent) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_DATASET_ACTIVE_TIMESTAMP)); |
| SuccessOrExit(error = mEncoder.WriteUint64(aDataset.mActiveTimestamp)); |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| if (aDataset.mComponents.mIsPendingTimestampPresent) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_DATASET_PENDING_TIMESTAMP)); |
| SuccessOrExit(error = mEncoder.WriteUint64(aDataset.mPendingTimestamp)); |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| if (aDataset.mComponents.mIsNetworkKeyPresent) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_NET_NETWORK_KEY)); |
| SuccessOrExit(error = mEncoder.WriteData(aDataset.mNetworkKey.m8, OT_NETWORK_KEY_SIZE)); |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| if (aDataset.mComponents.mIsNetworkNamePresent) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_NET_NETWORK_NAME)); |
| SuccessOrExit(error = mEncoder.WriteUtf8(aDataset.mNetworkName.m8)); |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| if (aDataset.mComponents.mIsExtendedPanIdPresent) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_NET_XPANID)); |
| SuccessOrExit(error = mEncoder.WriteData(aDataset.mExtendedPanId.m8, OT_EXT_PAN_ID_SIZE)); |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| if (aDataset.mComponents.mIsMeshLocalPrefixPresent) |
| { |
| otIp6Address addr; |
| |
| memcpy(addr.mFields.m8, aDataset.mMeshLocalPrefix.m8, 8); |
| memset(addr.mFields.m8 + 8, 0, 8); // Zero out the last 8 bytes. |
| |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_IPV6_ML_PREFIX)); |
| SuccessOrExit(error = mEncoder.WriteIp6Address(addr)); // Mesh local prefix |
| SuccessOrExit(error = mEncoder.WriteUint8(OT_IP6_PREFIX_BITSIZE)); // Prefix length (in bits) |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| if (aDataset.mComponents.mIsDelayPresent) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_DATASET_DELAY_TIMER)); |
| SuccessOrExit(error = mEncoder.WriteUint32(aDataset.mDelay)); |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| if (aDataset.mComponents.mIsPanIdPresent) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_MAC_15_4_PANID)); |
| SuccessOrExit(error = mEncoder.WriteUint16(aDataset.mPanId)); |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| if (aDataset.mComponents.mIsChannelPresent) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_PHY_CHAN)); |
| |
| // The channel is stored in Dataset as `uint16_t` (to accommodate |
| // larger number of channels in sub-GHz band), however the current |
| // definition of `SPINEL_PROP_PHY_CHAN` property limits the channel |
| // to a `uint8_t`. |
| |
| SuccessOrExit(error = mEncoder.WriteUint8(static_cast<uint8_t>(aDataset.mChannel))); |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| if (aDataset.mComponents.mIsPskcPresent) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_NET_PSKC)); |
| SuccessOrExit(error = mEncoder.WriteData(aDataset.mPskc.m8, sizeof(spinel_net_pskc_t))); |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| if (aDataset.mComponents.mIsSecurityPolicyPresent) |
| { |
| uint8_t flags[2]; |
| |
| static_cast<const SecurityPolicy &>(aDataset.mSecurityPolicy).GetFlags(flags, sizeof(flags)); |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_DATASET_SECURITY_POLICY)); |
| SuccessOrExit(error = mEncoder.WriteUint16(aDataset.mSecurityPolicy.mRotationTime)); |
| SuccessOrExit(error = mEncoder.WriteUint8(flags[0])); |
| if (otThreadGetVersion() >= OT_THREAD_VERSION_1_2) |
| { |
| SuccessOrExit(error = mEncoder.WriteUint8(flags[1])); |
| } |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| if (aDataset.mComponents.mIsChannelMaskPresent) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_PHY_CHAN_SUPPORTED)); |
| SuccessOrExit(error = EncodeChannelMask(aDataset.mChannelMask)); |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_ACTIVE_DATASET>(void) |
| { |
| otOperationalDataset dataset; |
| |
| IgnoreError(otDatasetGetActive(mInstance, &dataset)); |
| return EncodeOperationalDataset(dataset); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_PENDING_DATASET>(void) |
| { |
| otOperationalDataset dataset; |
| |
| IgnoreError(otDatasetGetPending(mInstance, &dataset)); |
| return EncodeOperationalDataset(dataset); |
| } |
| |
| otError NcpBase::DecodeOperationalDataset(otOperationalDataset &aDataset, |
| const uint8_t ** aTlvs, |
| uint8_t * aTlvsLength, |
| const otIp6Address ** aDestIpAddress, |
| bool aAllowEmptyValues) |
| { |
| otError error = OT_ERROR_NONE; |
| |
| memset(&aDataset, 0, sizeof(otOperationalDataset)); |
| |
| if (aTlvs != nullptr) |
| { |
| *aTlvs = nullptr; |
| } |
| |
| if (aTlvsLength != nullptr) |
| { |
| *aTlvsLength = 0; |
| } |
| |
| if (aDestIpAddress != nullptr) |
| { |
| *aDestIpAddress = nullptr; |
| } |
| |
| while (!mDecoder.IsAllReadInStruct()) |
| { |
| unsigned int propKey; |
| |
| SuccessOrExit(error = mDecoder.OpenStruct()); |
| SuccessOrExit(error = mDecoder.ReadUintPacked(propKey)); |
| |
| switch (static_cast<spinel_prop_key_t>(propKey)) |
| { |
| case SPINEL_PROP_DATASET_ACTIVE_TIMESTAMP: |
| |
| if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct()) |
| { |
| SuccessOrExit(error = mDecoder.ReadUint64(aDataset.mActiveTimestamp)); |
| } |
| |
| aDataset.mComponents.mIsActiveTimestampPresent = true; |
| break; |
| |
| case SPINEL_PROP_DATASET_PENDING_TIMESTAMP: |
| |
| if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct()) |
| { |
| SuccessOrExit(error = mDecoder.ReadUint64(aDataset.mPendingTimestamp)); |
| } |
| |
| aDataset.mComponents.mIsPendingTimestampPresent = true; |
| break; |
| |
| case SPINEL_PROP_NET_NETWORK_KEY: |
| |
| if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct()) |
| { |
| const uint8_t *key; |
| uint16_t len; |
| |
| SuccessOrExit(error = mDecoder.ReadData(key, len)); |
| VerifyOrExit(len == OT_NETWORK_KEY_SIZE, error = OT_ERROR_INVALID_ARGS); |
| memcpy(aDataset.mNetworkKey.m8, key, len); |
| } |
| |
| aDataset.mComponents.mIsNetworkKeyPresent = true; |
| break; |
| |
| case SPINEL_PROP_NET_NETWORK_NAME: |
| |
| if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct()) |
| { |
| const char *name; |
| size_t len; |
| |
| SuccessOrExit(error = mDecoder.ReadUtf8(name)); |
| len = strlen(name); |
| VerifyOrExit(len <= OT_NETWORK_NAME_MAX_SIZE, error = OT_ERROR_INVALID_ARGS); |
| memcpy(aDataset.mNetworkName.m8, name, len + 1); |
| } |
| |
| aDataset.mComponents.mIsNetworkNamePresent = true; |
| break; |
| |
| case SPINEL_PROP_NET_XPANID: |
| |
| if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct()) |
| { |
| const uint8_t *xpanid; |
| uint16_t len; |
| |
| SuccessOrExit(error = mDecoder.ReadData(xpanid, len)); |
| VerifyOrExit(len == OT_EXT_PAN_ID_SIZE, error = OT_ERROR_INVALID_ARGS); |
| memcpy(aDataset.mExtendedPanId.m8, xpanid, len); |
| } |
| |
| aDataset.mComponents.mIsExtendedPanIdPresent = true; |
| break; |
| |
| case SPINEL_PROP_IPV6_ML_PREFIX: |
| |
| if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct()) |
| { |
| const otIp6Address *addr; |
| uint8_t prefixLen; |
| |
| SuccessOrExit(error = mDecoder.ReadIp6Address(addr)); |
| SuccessOrExit(error = mDecoder.ReadUint8(prefixLen)); |
| VerifyOrExit(prefixLen == OT_IP6_PREFIX_BITSIZE, error = OT_ERROR_INVALID_ARGS); |
| memcpy(aDataset.mMeshLocalPrefix.m8, addr, OT_MESH_LOCAL_PREFIX_SIZE); |
| } |
| |
| aDataset.mComponents.mIsMeshLocalPrefixPresent = true; |
| break; |
| |
| case SPINEL_PROP_DATASET_DELAY_TIMER: |
| |
| if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct()) |
| { |
| SuccessOrExit(error = mDecoder.ReadUint32(aDataset.mDelay)); |
| } |
| |
| aDataset.mComponents.mIsDelayPresent = true; |
| break; |
| |
| case SPINEL_PROP_MAC_15_4_PANID: |
| |
| if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct()) |
| { |
| SuccessOrExit(error = mDecoder.ReadUint16(aDataset.mPanId)); |
| } |
| |
| aDataset.mComponents.mIsPanIdPresent = true; |
| break; |
| |
| case SPINEL_PROP_PHY_CHAN: |
| |
| if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct()) |
| { |
| uint8_t channel; |
| |
| SuccessOrExit(error = mDecoder.ReadUint8(channel)); |
| aDataset.mChannel = channel; |
| } |
| |
| aDataset.mComponents.mIsChannelPresent = true; |
| break; |
| |
| case SPINEL_PROP_NET_PSKC: |
| |
| if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct()) |
| { |
| const uint8_t *psk; |
| uint16_t len; |
| |
| SuccessOrExit(error = mDecoder.ReadData(psk, len)); |
| VerifyOrExit(len == OT_PSKC_MAX_SIZE, error = OT_ERROR_INVALID_ARGS); |
| memcpy(aDataset.mPskc.m8, psk, OT_PSKC_MAX_SIZE); |
| } |
| |
| aDataset.mComponents.mIsPskcPresent = true; |
| break; |
| |
| case SPINEL_PROP_DATASET_SECURITY_POLICY: |
| |
| if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct()) |
| { |
| uint8_t flags[2]; |
| uint8_t flagsLength = 1; |
| |
| SuccessOrExit(error = mDecoder.ReadUint16(aDataset.mSecurityPolicy.mRotationTime)); |
| SuccessOrExit(error = mDecoder.ReadUint8(flags[0])); |
| if (otThreadGetVersion() >= OT_THREAD_VERSION_1_2 && mDecoder.GetRemainingLengthInStruct() > 0) |
| { |
| SuccessOrExit(error = mDecoder.ReadUint8(flags[1])); |
| ++flagsLength; |
| } |
| static_cast<SecurityPolicy &>(aDataset.mSecurityPolicy).SetFlags(flags, flagsLength); |
| } |
| |
| aDataset.mComponents.mIsSecurityPolicyPresent = true; |
| break; |
| |
| case SPINEL_PROP_PHY_CHAN_SUPPORTED: |
| |
| if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct()) |
| { |
| uint8_t channel; |
| |
| aDataset.mChannelMask = 0; |
| |
| while (!mDecoder.IsAllReadInStruct()) |
| { |
| SuccessOrExit(error = mDecoder.ReadUint8(channel)); |
| VerifyOrExit(channel <= 31, error = OT_ERROR_INVALID_ARGS); |
| aDataset.mChannelMask |= (1UL << channel); |
| } |
| } |
| |
| aDataset.mComponents.mIsChannelMaskPresent = true; |
| break; |
| |
| case SPINEL_PROP_DATASET_RAW_TLVS: |
| |
| if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct()) |
| { |
| const uint8_t *tlvs; |
| uint16_t len; |
| |
| SuccessOrExit(error = mDecoder.ReadData(tlvs, len)); |
| VerifyOrExit(len <= 255, error = OT_ERROR_INVALID_ARGS); |
| |
| if (aTlvs != nullptr) |
| { |
| *aTlvs = tlvs; |
| } |
| |
| if (aTlvsLength != nullptr) |
| { |
| *aTlvsLength = static_cast<uint8_t>(len); |
| } |
| } |
| |
| break; |
| |
| case SPINEL_PROP_DATASET_DEST_ADDRESS: |
| |
| if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct()) |
| { |
| const otIp6Address *addr; |
| |
| SuccessOrExit(error = mDecoder.ReadIp6Address(addr)); |
| |
| if (aDestIpAddress != nullptr) |
| { |
| *aDestIpAddress = addr; |
| } |
| } |
| |
| break; |
| |
| default: |
| break; |
| } |
| |
| SuccessOrExit(error = mDecoder.CloseStruct()); |
| } |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_ACTIVE_DATASET>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| otOperationalDataset dataset; |
| |
| SuccessOrExit(error = DecodeOperationalDataset(dataset)); |
| error = otDatasetSetActive(mInstance, &dataset); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_PENDING_DATASET>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| otOperationalDataset dataset; |
| |
| SuccessOrExit(error = DecodeOperationalDataset(dataset)); |
| error = otDatasetSetPending(mInstance, &dataset); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_MGMT_SET_ACTIVE_DATASET>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| otOperationalDataset dataset; |
| const uint8_t * extraTlvs; |
| uint8_t extraTlvsLength; |
| |
| SuccessOrExit(error = DecodeOperationalDataset(dataset, &extraTlvs, &extraTlvsLength)); |
| error = otDatasetSendMgmtActiveSet(mInstance, &dataset, extraTlvs, extraTlvsLength, /* aCallback */ nullptr, |
| /* aContext */ nullptr); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| otOperationalDataset dataset; |
| const uint8_t * extraTlvs; |
| uint8_t extraTlvsLength; |
| |
| SuccessOrExit(error = DecodeOperationalDataset(dataset, &extraTlvs, &extraTlvsLength)); |
| error = otDatasetSendMgmtPendingSet(mInstance, &dataset, extraTlvs, extraTlvsLength, /* aCallback */ nullptr, |
| /* aContext */ nullptr); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_MGMT_GET_ACTIVE_DATASET>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| otOperationalDataset dataset; |
| const uint8_t * extraTlvs; |
| uint8_t extraTlvsLength; |
| const otIp6Address * destIpAddress; |
| |
| SuccessOrExit(error = DecodeOperationalDataset(dataset, &extraTlvs, &extraTlvsLength, &destIpAddress, true)); |
| error = otDatasetSendMgmtActiveGet(mInstance, &dataset.mComponents, extraTlvs, extraTlvsLength, destIpAddress); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_MGMT_GET_PENDING_DATASET>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| otOperationalDataset dataset; |
| const uint8_t * extraTlvs; |
| uint8_t extraTlvsLength; |
| const otIp6Address * destIpAddress; |
| |
| SuccessOrExit(error = DecodeOperationalDataset(dataset, &extraTlvs, &extraTlvsLength, &destIpAddress, true)); |
| error = otDatasetSendMgmtPendingGet(mInstance, &dataset.mComponents, extraTlvs, extraTlvsLength, destIpAddress); |
| |
| exit: |
| return error; |
| } |
| #if OPENTHREAD_CONFIG_JOINER_ENABLE |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MESHCOP_JOINER_STATE>(void) |
| { |
| spinel_meshcop_joiner_state_t state = SPINEL_MESHCOP_JOINER_STATE_IDLE; |
| |
| switch (otJoinerGetState(mInstance)) |
| { |
| case OT_JOINER_STATE_IDLE: |
| state = SPINEL_MESHCOP_JOINER_STATE_IDLE; |
| break; |
| case OT_JOINER_STATE_DISCOVER: |
| state = SPINEL_MESHCOP_JOINER_STATE_DISCOVER; |
| break; |
| case OT_JOINER_STATE_CONNECT: |
| state = SPINEL_MESHCOP_JOINER_STATE_CONNECTING; |
| break; |
| case OT_JOINER_STATE_CONNECTED: |
| state = SPINEL_MESHCOP_JOINER_STATE_CONNECTED; |
| break; |
| case OT_JOINER_STATE_ENTRUST: |
| state = SPINEL_MESHCOP_JOINER_STATE_ENTRUST; |
| break; |
| case OT_JOINER_STATE_JOINED: |
| state = SPINEL_MESHCOP_JOINER_STATE_JOINED; |
| break; |
| } |
| |
| return mEncoder.WriteUint8(state); |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_JOINER_COMMISSIONING>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| bool action = false; |
| const char *psk = nullptr; |
| const char *provisioningUrl = nullptr; |
| const char *vendorName = nullptr; |
| const char *vendorModel = nullptr; |
| const char *vendorSwVersion = nullptr; |
| const char *vendorData = nullptr; |
| |
| SuccessOrExit(error = mDecoder.ReadBool(action)); |
| |
| if (!action) |
| { |
| otJoinerStop(mInstance); |
| ExitNow(); |
| } |
| |
| SuccessOrExit(error = mDecoder.ReadUtf8(psk)); |
| |
| // Parse optional fields |
| |
| if (!mDecoder.IsAllReadInStruct()) |
| { |
| SuccessOrExit(error = mDecoder.ReadUtf8(provisioningUrl)); |
| } |
| |
| if (!mDecoder.IsAllReadInStruct()) |
| { |
| SuccessOrExit(error = mDecoder.ReadUtf8(vendorName)); |
| } |
| |
| if (!mDecoder.IsAllReadInStruct()) |
| { |
| SuccessOrExit(error = mDecoder.ReadUtf8(vendorModel)); |
| } |
| |
| if (!mDecoder.IsAllReadInStruct()) |
| { |
| SuccessOrExit(error = mDecoder.ReadUtf8(vendorSwVersion)); |
| } |
| |
| if (!mDecoder.IsAllReadInStruct()) |
| { |
| SuccessOrExit(error = mDecoder.ReadUtf8(vendorData)); |
| } |
| |
| // Use OpenThread default values for vendor name, mode, sw version if |
| // not specified or an empty string is given. |
| |
| if ((vendorName == nullptr) || (vendorName[0] == 0)) |
| { |
| vendorName = PACKAGE_NAME; |
| } |
| |
| if ((vendorModel == nullptr) || (vendorModel[0] == 0)) |
| { |
| vendorModel = OPENTHREAD_CONFIG_PLATFORM_INFO; |
| } |
| |
| if ((vendorSwVersion == nullptr) || (vendorSwVersion[0] == 0)) |
| { |
| vendorSwVersion = PACKAGE_VERSION; |
| } |
| |
| error = otJoinerStart(mInstance, psk, provisioningUrl, vendorName, vendorModel, vendorSwVersion, vendorData, |
| &NcpBase::HandleJoinerCallback_Jump, this); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MESHCOP_JOINER_DISCERNER>(void) |
| { |
| otError error; |
| const otJoinerDiscerner *discerner = otJoinerGetDiscerner(mInstance); |
| |
| if (discerner == nullptr) |
| { |
| SuccessOrExit(error = mEncoder.WriteUint8(0)); |
| } |
| else |
| { |
| SuccessOrExit(error = mEncoder.WriteUint8(discerner->mLength)); |
| SuccessOrExit(error = mEncoder.WriteUint64(discerner->mValue)); |
| } |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_JOINER_DISCERNER>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| otJoinerDiscerner discerner; |
| |
| SuccessOrExit(error = mDecoder.ReadUint8(discerner.mLength)); |
| |
| if (discerner.mLength == 0) |
| { |
| // Clearing any previously set Joiner Discerner |
| error = otJoinerSetDiscerner(mInstance, nullptr); |
| ExitNow(); |
| } |
| |
| SuccessOrExit(error = mDecoder.ReadUint64(discerner.mValue)); |
| error = otJoinerSetDiscerner(mInstance, &discerner); |
| |
| exit: |
| return error; |
| } |
| |
| #endif // OPENTHREAD_CONFIG_JOINER_ENABLE |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_IPV6_ML_PREFIX>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| const otMeshLocalPrefix *mlPrefix = otThreadGetMeshLocalPrefix(mInstance); |
| otIp6Address addr; |
| |
| VerifyOrExit(mlPrefix != nullptr); // If `mlPrefix` is nullptr send empty response. |
| |
| memcpy(addr.mFields.m8, mlPrefix->m8, 8); |
| |
| // Zero out the last 8 bytes. |
| memset(addr.mFields.m8 + 8, 0, 8); |
| |
| SuccessOrExit(error = mEncoder.WriteIp6Address(addr)); // Mesh local prefix |
| SuccessOrExit(error = mEncoder.WriteUint8(OT_IP6_PREFIX_BITSIZE)); // Prefix length (in bits) |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_IPV6_ML_PREFIX>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| const otIp6Address *meshLocalPrefix; |
| uint8_t prefixLength; |
| |
| SuccessOrExit(error = mDecoder.ReadIp6Address(meshLocalPrefix)); |
| SuccessOrExit(error = mDecoder.ReadUint8(prefixLength)); |
| VerifyOrExit(prefixLength == OT_IP6_PREFIX_BITSIZE, error = OT_ERROR_INVALID_ARGS); |
| |
| error = otThreadSetMeshLocalPrefix(mInstance, reinterpret_cast<const otMeshLocalPrefix *>(meshLocalPrefix)); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_IPV6_ML_ADDR>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| const otIp6Address *ml64 = otThreadGetMeshLocalEid(mInstance); |
| |
| VerifyOrExit(ml64 != nullptr); |
| SuccessOrExit(error = mEncoder.WriteIp6Address(*ml64)); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_IPV6_LL_ADDR>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| const otIp6Address *address = otThreadGetLinkLocalIp6Address(mInstance); |
| |
| VerifyOrExit(address != nullptr); |
| SuccessOrExit(error = mEncoder.WriteIp6Address(*address)); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_IPV6_ADDRESS_TABLE>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| |
| for (const otNetifAddress *address = otIp6GetUnicastAddresses(mInstance); address; address = address->mNext) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| |
| SuccessOrExit(error = mEncoder.WriteIp6Address(address->mAddress)); |
| SuccessOrExit(error = mEncoder.WriteUint8(address->mPrefixLength)); |
| SuccessOrExit(error = mEncoder.WriteUint32(address->mPreferred ? 0xffffffff : 0)); |
| SuccessOrExit(error = mEncoder.WriteUint32(address->mValid ? 0xffffffff : 0)); |
| |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_IPV6_ADDRESS_TABLE>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| otNetifAddress netifAddr; |
| uint32_t preferredLifetime; |
| uint32_t validLifetime; |
| |
| SuccessOrExit(error = mDecoder.ReadIp6Address(netifAddr.mAddress)); |
| SuccessOrExit(error = mDecoder.ReadUint8(netifAddr.mPrefixLength)); |
| SuccessOrExit(error = mDecoder.ReadUint32(preferredLifetime)); |
| SuccessOrExit(error = mDecoder.ReadUint32(validLifetime)); |
| |
| netifAddr.mAddressOrigin = OT_ADDRESS_ORIGIN_MANUAL; |
| netifAddr.mPreferred = (preferredLifetime != 0); |
| netifAddr.mValid = (validLifetime != 0); |
| |
| error = otIp6AddUnicastAddress(mInstance, &netifAddr); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyRemove<SPINEL_PROP_IPV6_ADDRESS_TABLE>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| const otIp6Address *addrPtr; |
| |
| SuccessOrExit(error = mDecoder.ReadIp6Address(addrPtr)); |
| |
| error = otIp6RemoveUnicastAddress(mInstance, addrPtr); |
| |
| // If address was not on the list, "remove" command is successful. |
| if (error == OT_ERROR_NOT_FOUND) |
| { |
| error = OT_ERROR_NONE; |
| } |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_IPV6_ROUTE_TABLE>(void) |
| { |
| // TODO: Implement get route table |
| return mEncoder.OverwriteWithLastStatusError(SPINEL_STATUS_UNIMPLEMENTED); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_IPV6_ICMP_PING_OFFLOAD>(void) |
| { |
| return mEncoder.WriteBool(otIcmp6GetEchoMode(mInstance) != OT_ICMP6_ECHO_HANDLER_DISABLED); |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_IPV6_ICMP_PING_OFFLOAD>(void) |
| { |
| bool enabled = false; |
| otError error = OT_ERROR_NONE; |
| |
| SuccessOrExit(error = mDecoder.ReadBool(enabled)); |
| |
| otIcmp6SetEchoMode(mInstance, enabled ? OT_ICMP6_ECHO_HANDLER_ALL : OT_ICMP6_ECHO_HANDLER_DISABLED); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| const otNetifMulticastAddress *address; |
| |
| for (address = otIp6GetMulticastAddresses(mInstance); address; address = address->mNext) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| SuccessOrExit(error = mEncoder.WriteIp6Address(address->mAddress)); |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| const otIp6Address *addrPtr; |
| |
| SuccessOrExit(error = mDecoder.ReadIp6Address(addrPtr)); |
| |
| error = otIp6SubscribeMulticastAddress(mInstance, addrPtr); |
| |
| if (error == OT_ERROR_ALREADY) |
| { |
| error = OT_ERROR_NONE; |
| } |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyRemove<SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| const otIp6Address *addrPtr; |
| |
| SuccessOrExit(error = mDecoder.ReadIp6Address(addrPtr)); |
| |
| error = otIp6UnsubscribeMulticastAddress(mInstance, addrPtr); |
| |
| // If the address was not on the list, "remove" command is successful, |
| // and we respond with a `SPINEL_STATUS_OK` status. |
| if (error == OT_ERROR_NOT_FOUND) |
| { |
| error = OT_ERROR_NONE; |
| } |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_IPV6_ICMP_PING_OFFLOAD_MODE>(void) |
| { |
| spinel_ipv6_icmp_ping_offload_mode_t mode = SPINEL_IPV6_ICMP_PING_OFFLOAD_DISABLED; |
| |
| switch (otIcmp6GetEchoMode(mInstance)) |
| { |
| case OT_ICMP6_ECHO_HANDLER_DISABLED: |
| mode = SPINEL_IPV6_ICMP_PING_OFFLOAD_DISABLED; |
| break; |
| case OT_ICMP6_ECHO_HANDLER_UNICAST_ONLY: |
| mode = SPINEL_IPV6_ICMP_PING_OFFLOAD_UNICAST_ONLY; |
| break; |
| case OT_ICMP6_ECHO_HANDLER_MULTICAST_ONLY: |
| mode = SPINEL_IPV6_ICMP_PING_OFFLOAD_MULTICAST_ONLY; |
| break; |
| case OT_ICMP6_ECHO_HANDLER_ALL: |
| mode = SPINEL_IPV6_ICMP_PING_OFFLOAD_ALL; |
| break; |
| }; |
| |
| return mEncoder.WriteUint8(mode); |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_IPV6_ICMP_PING_OFFLOAD_MODE>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| otIcmp6EchoMode mode = OT_ICMP6_ECHO_HANDLER_DISABLED; |
| uint8_t spinelMode; |
| |
| SuccessOrExit(error = mDecoder.ReadUint8(spinelMode)); |
| |
| switch (spinelMode) |
| { |
| case SPINEL_IPV6_ICMP_PING_OFFLOAD_DISABLED: |
| mode = OT_ICMP6_ECHO_HANDLER_DISABLED; |
| break; |
| case SPINEL_IPV6_ICMP_PING_OFFLOAD_UNICAST_ONLY: |
| mode = OT_ICMP6_ECHO_HANDLER_UNICAST_ONLY; |
| break; |
| case SPINEL_IPV6_ICMP_PING_OFFLOAD_MULTICAST_ONLY: |
| mode = OT_ICMP6_ECHO_HANDLER_MULTICAST_ONLY; |
| break; |
| case SPINEL_IPV6_ICMP_PING_OFFLOAD_ALL: |
| mode = OT_ICMP6_ECHO_HANDLER_ALL; |
| break; |
| }; |
| |
| otIcmp6SetEchoMode(mInstance, mode); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_RLOC16_DEBUG_PASSTHRU>(void) |
| { |
| // Note reverse logic: passthru enabled = filter disabled |
| return mEncoder.WriteBool(!otIp6IsReceiveFilterEnabled(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_RLOC16_DEBUG_PASSTHRU>(void) |
| { |
| bool enabled = false; |
| otError error = OT_ERROR_NONE; |
| |
| SuccessOrExit(error = mDecoder.ReadBool(enabled)); |
| |
| // Note reverse logic: passthru enabled = filter disabled |
| otIp6SetReceiveFilterEnabled(mInstance, !enabled); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_OFF_MESH_ROUTES>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| otExternalRouteConfig routeConfig; |
| otNetworkDataIterator iter = OT_NETWORK_DATA_ITERATOR_INIT; |
| |
| while (otNetDataGetNextRoute(mInstance, &iter, &routeConfig) == OT_ERROR_NONE) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| |
| SuccessOrExit(error = mEncoder.WriteIp6Address(routeConfig.mPrefix.mPrefix)); |
| SuccessOrExit(error = mEncoder.WriteUint8(routeConfig.mPrefix.mLength)); |
| SuccessOrExit(error = mEncoder.WriteBool(routeConfig.mStable)); |
| SuccessOrExit(error = mEncoder.WriteUint8(ExternalRouteConfigToFlagByte(routeConfig))); |
| SuccessOrExit(error = mEncoder.WriteBool(false)); // IsLocal |
| SuccessOrExit(error = mEncoder.WriteBool(routeConfig.mNextHopIsThisDevice)); |
| SuccessOrExit(error = mEncoder.WriteUint16(routeConfig.mRloc16)); |
| |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
| |
| iter = OT_NETWORK_DATA_ITERATOR_INIT; |
| |
| while (otBorderRouterGetNextRoute(mInstance, &iter, &routeConfig) == OT_ERROR_NONE) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| |
| SuccessOrExit(error = mEncoder.WriteIp6Address(routeConfig.mPrefix.mPrefix)); |
| SuccessOrExit(error = mEncoder.WriteUint8(routeConfig.mPrefix.mLength)); |
| SuccessOrExit(error = mEncoder.WriteBool(routeConfig.mStable)); |
| SuccessOrExit(error = mEncoder.WriteUint8(ExternalRouteConfigToFlagByte(routeConfig))); |
| SuccessOrExit(error = mEncoder.WriteBool(true)); // IsLocal |
| SuccessOrExit(error = mEncoder.WriteBool(routeConfig.mNextHopIsThisDevice)); |
| SuccessOrExit(error = mEncoder.WriteUint16(routeConfig.mRloc16)); |
| |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
| |
| exit: |
| return error; |
| } |
| |
| #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
| static int FlagByteToExternalRoutePreference(uint8_t aFlags) |
| { |
| int route_preference = 0; |
| |
| switch (aFlags & SPINEL_NET_FLAG_PREFERENCE_MASK) |
| { |
| case SPINEL_ROUTE_PREFERENCE_HIGH: |
| route_preference = OT_ROUTE_PREFERENCE_HIGH; |
| break; |
| |
| case SPINEL_ROUTE_PREFERENCE_MEDIUM: |
| route_preference = OT_ROUTE_PREFERENCE_MED; |
| break; |
| |
| case SPINEL_ROUTE_PREFERENCE_LOW: |
| route_preference = OT_ROUTE_PREFERENCE_LOW; |
| break; |
| } |
| |
| return route_preference; |
| } |
| |
| template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_THREAD_OFF_MESH_ROUTES>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| otExternalRouteConfig routeConfig; |
| bool stable = false; |
| uint8_t flags = 0; |
| uint8_t prefixLength; |
| |
| memset(&routeConfig, 0, sizeof(otExternalRouteConfig)); |
| |
| VerifyOrExit(mAllowLocalNetworkDataChange, error = OT_ERROR_INVALID_STATE); |
| |
| SuccessOrExit(error = mDecoder.ReadIp6Address(routeConfig.mPrefix.mPrefix)); |
| SuccessOrExit(error = mDecoder.ReadUint8(prefixLength)); |
| SuccessOrExit(error = mDecoder.ReadBool(stable)); |
| SuccessOrExit(error = mDecoder.ReadUint8(flags)); |
| |
| routeConfig.mPrefix.mLength = prefixLength; |
| routeConfig.mStable = stable; |
| routeConfig.mPreference = FlagByteToExternalRoutePreference(flags); |
| routeConfig.mNat64 = ((flags & SPINEL_ROUTE_FLAG_NAT64) != 0); |
| |
| error = otBorderRouterAddRoute(mInstance, &routeConfig); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyRemove<SPINEL_PROP_THREAD_OFF_MESH_ROUTES>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| otIp6Prefix ip6Prefix; |
| uint8_t prefixLength; |
| |
| memset(&ip6Prefix, 0, sizeof(otIp6Prefix)); |
| |
| VerifyOrExit(mAllowLocalNetworkDataChange, error = OT_ERROR_INVALID_STATE); |
| |
| SuccessOrExit(error = mDecoder.ReadIp6Address(ip6Prefix.mPrefix)); |
| SuccessOrExit(error = mDecoder.ReadUint8(prefixLength)); |
| |
| ip6Prefix.mLength = prefixLength; |
| |
| error = otBorderRouterRemoveRoute(mInstance, &ip6Prefix); |
| |
| // If the route prefix was not on the list, "remove" command is successful. |
| if (error == OT_ERROR_NOT_FOUND) |
| { |
| error = OT_ERROR_NONE; |
| } |
| |
| exit: |
| return error; |
| } |
| #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_STREAM_NET>(void) |
| { |
| const uint8_t *framePtr = nullptr; |
| uint16_t frameLen = 0; |
| const uint8_t *metaPtr = nullptr; |
| uint16_t metaLen = 0; |
| otMessage * message = nullptr; |
| otError error = OT_ERROR_NONE; |
| |
| 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... |
| |
| // STREAM_NET requires layer 2 security. |
| message = otIp6NewMessageFromBuffer(mInstance, framePtr, frameLen, nullptr); |
| VerifyOrExit(message != nullptr, error = OT_ERROR_NO_BUFS); |
| |
| error = otIp6Send(mInstance, message); |
| |
| exit: |
| |
| if (error == OT_ERROR_NONE) |
| { |
| mInboundSecureIpFrameCounter++; |
| } |
| else |
| { |
| mDroppedInboundIpFrameCounter++; |
| } |
| |
| return error; |
| } |
| |
| #if OPENTHREAD_CONFIG_JAM_DETECTION_ENABLE |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_JAM_DETECT_ENABLE>(void) |
| { |
| return mEncoder.WriteBool(otJamDetectionIsEnabled(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_JAM_DETECTED>(void) |
| { |
| return mEncoder.WriteBool(otJamDetectionGetState(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_JAM_DETECT_RSSI_THRESHOLD>(void) |
| { |
| return mEncoder.WriteInt8(otJamDetectionGetRssiThreshold(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_JAM_DETECT_WINDOW>(void) |
| { |
| return mEncoder.WriteUint8(otJamDetectionGetWindow(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_JAM_DETECT_BUSY>(void) |
| { |
| return mEncoder.WriteUint8(otJamDetectionGetBusyPeriod(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_JAM_DETECT_HISTORY_BITMAP>(void) |
| { |
| return mEncoder.WriteUint64(otJamDetectionGetHistoryBitmap(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_JAM_DETECT_ENABLE>(void) |
| { |
| bool enabled; |
| otError error = OT_ERROR_NONE; |
| |
| SuccessOrExit(error = mDecoder.ReadBool(enabled)); |
| |
| if (enabled) |
| { |
| IgnoreError(otJamDetectionStart(mInstance, &NcpBase::HandleJamStateChange_Jump, this)); |
| } |
| else |
| { |
| IgnoreError(otJamDetectionStop(mInstance)); |
| } |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_JAM_DETECT_RSSI_THRESHOLD>(void) |
| { |
| int8_t threshold = 0; |
| otError error = OT_ERROR_NONE; |
| |
| SuccessOrExit(error = mDecoder.ReadInt8(threshold)); |
| |
| error = otJamDetectionSetRssiThreshold(mInstance, threshold); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_JAM_DETECT_WINDOW>(void) |
| { |
| uint8_t window = 0; |
| otError error = OT_ERROR_NONE; |
| |
| SuccessOrExit(error = mDecoder.ReadUint8(window)); |
| |
| error = otJamDetectionSetWindow(mInstance, window); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_JAM_DETECT_BUSY>(void) |
| { |
| uint8_t busy = 0; |
| otError error = OT_ERROR_NONE; |
| |
| SuccessOrExit(error = mDecoder.ReadUint8(busy)); |
| |
| error = otJamDetectionSetBusyPeriod(mInstance, busy); |
| |
| exit: |
| return error; |
| } |
| |
| void NcpBase::HandleJamStateChange_Jump(bool aJamState, void *aContext) |
| { |
| static_cast<NcpBase *>(aContext)->HandleJamStateChange(aJamState); |
| } |
| |
| void NcpBase::HandleJamStateChange(bool aJamState) |
| { |
| OT_UNUSED_VARIABLE(aJamState); |
| |
| mChangedPropsSet.AddProperty(SPINEL_PROP_JAM_DETECTED); |
| mUpdateChangedPropsTask.Post(); |
| } |
| |
| #endif // OPENTHREAD_CONFIG_JAM_DETECTION_ENABLE |
| |
| #if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHILD_SUPERVISION_CHECK_TIMEOUT>(void) |
| { |
| return mEncoder.WriteUint16(otChildSupervisionGetCheckTimeout(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CHILD_SUPERVISION_CHECK_TIMEOUT>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| uint16_t timeout; |
| |
| SuccessOrExit(error = mDecoder.ReadUint16(timeout)); |
| otChildSupervisionSetCheckTimeout(mInstance, timeout); |
| |
| exit: |
| return error; |
| } |
| |
| #endif // OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE |
| |
| #if OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MONITOR_SAMPLE_INTERVAL>(void) |
| { |
| return mEncoder.WriteUint32(otChannelMonitorGetSampleInterval(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MONITOR_RSSI_THRESHOLD>(void) |
| { |
| return mEncoder.WriteInt8(otChannelMonitorGetRssiThreshold(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MONITOR_SAMPLE_WINDOW>(void) |
| { |
| return mEncoder.WriteUint32(otChannelMonitorGetSampleWindow(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MONITOR_SAMPLE_COUNT>(void) |
| { |
| return mEncoder.WriteUint32(otChannelMonitorGetSampleCount(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MONITOR_CHANNEL_OCCUPANCY>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| uint32_t channelMask = otLinkGetSupportedChannelMask(mInstance); |
| uint8_t channelNum = sizeof(channelMask) * CHAR_BIT; |
| |
| for (uint8_t channel = 0; channel < channelNum; channel++) |
| { |
| if (!((1UL << channel) & channelMask)) |
| { |
| continue; |
| } |
| |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| |
| SuccessOrExit(error = mEncoder.WriteUint8(channel)); |
| SuccessOrExit(error = mEncoder.WriteUint16(otChannelMonitorGetChannelOccupancy(mInstance, channel))); |
| |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| exit: |
| return error; |
| } |
| |
| #endif // OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MAC_CCA_FAILURE_RATE>(void) |
| { |
| return mEncoder.WriteUint16(otLinkGetCcaFailureRate(mInstance)); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_PKT_TOTAL>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxTotal); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_PKT_ACK_REQ>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxAckRequested); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_PKT_ACKED>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxAcked); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_PKT_NO_ACK_REQ>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxNoAckRequested); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_PKT_DATA>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxData); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_PKT_DATA_POLL>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxDataPoll); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_PKT_BEACON>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxBeacon); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_PKT_BEACON_REQ>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxBeaconRequest); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_PKT_OTHER>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxOther); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_PKT_RETRY>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxRetry); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_ERR_CCA>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxErrCca); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_PKT_UNICAST>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxUnicast); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_PKT_BROADCAST>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxBroadcast); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_ERR_ABORT>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxErrAbort); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_PKT_TOTAL>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxTotal); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_PKT_DATA>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxData); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_PKT_DATA_POLL>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxDataPoll); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_PKT_BEACON>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxBeacon); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_PKT_BEACON_REQ>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxBeaconRequest); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_PKT_OTHER>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxOther); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_PKT_FILT_WL>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxAddressFiltered); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_PKT_FILT_DA>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxDestAddrFiltered); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_PKT_DUP>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxDuplicated); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_PKT_UNICAST>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxUnicast); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_PKT_BROADCAST>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxBroadcast); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_ERR_EMPTY>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxErrNoFrame); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_ERR_UKWN_NBR>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxErrUnknownNeighbor); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_ERR_NVLD_SADDR>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxErrInvalidSrcAddr); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_ERR_SECURITY>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxErrSec); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_ERR_BAD_FCS>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxErrFcs); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_ERR_OTHER>(void) |
| { |
| return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxErrOther); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_IP_SEC_TOTAL>(void) |
| { |
| return mEncoder.WriteUint32(mInboundSecureIpFrameCounter); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_IP_INSEC_TOTAL>(void) |
| { |
| return mEncoder.WriteUint32(mInboundInsecureIpFrameCounter); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_IP_DROPPED>(void) |
| { |
| return mEncoder.WriteUint32(mDroppedInboundIpFrameCounter); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_IP_SEC_TOTAL>(void) |
| { |
| return mEncoder.WriteUint32(mOutboundSecureIpFrameCounter); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_IP_INSEC_TOTAL>(void) |
| { |
| return mEncoder.WriteUint32(mOutboundInsecureIpFrameCounter); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_IP_DROPPED>(void) |
| { |
| return mEncoder.WriteUint32(mDroppedOutboundIpFrameCounter); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_SPINEL_TOTAL>(void) |
| { |
| return mEncoder.WriteUint32(mTxSpinelFrameCounter); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_SPINEL_TOTAL>(void) |
| { |
| return mEncoder.WriteUint32(mRxSpinelFrameCounter); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_SPINEL_OUT_OF_ORDER_TID>(void) |
| { |
| return mEncoder.WriteUint32(mRxSpinelOutOfOrderTidCounter); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_SPINEL_ERR>(void) |
| { |
| return mEncoder.WriteUint32(mFramingErrorCounter); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_IP_TX_SUCCESS>(void) |
| { |
| return mEncoder.WriteUint32(otThreadGetIp6Counters(mInstance)->mTxSuccess); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_IP_RX_SUCCESS>(void) |
| { |
| return mEncoder.WriteUint32(otThreadGetIp6Counters(mInstance)->mRxSuccess); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_IP_TX_FAILURE>(void) |
| { |
| return mEncoder.WriteUint32(otThreadGetIp6Counters(mInstance)->mTxFailure); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_IP_RX_FAILURE>(void) |
| { |
| return mEncoder.WriteUint32(otThreadGetIp6Counters(mInstance)->mRxFailure); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MSG_BUFFER_COUNTERS>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| otBufferInfo bufferInfo; |
| |
| otMessageGetBufferInfo(mInstance, &bufferInfo); |
| |
| SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.mTotalBuffers)); |
| SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.mFreeBuffers)); |
| |
| SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.m6loSendQueue.mNumMessages)); |
| SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.m6loSendQueue.mNumBuffers)); |
| SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.m6loReassemblyQueue.mNumMessages)); |
| SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.m6loReassemblyQueue.mNumBuffers)); |
| SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.mIp6Queue.mNumMessages)); |
| SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.mIp6Queue.mNumBuffers)); |
| SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.mMplQueue.mNumMessages)); |
| SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.mMplQueue.mNumBuffers)); |
| SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.mMleQueue.mNumMessages)); |
| SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.mMleQueue.mNumBuffers)); |
| SuccessOrExit(error = mEncoder.WriteUint16(0)); // Write zero for ARP for backward compatibility. |
| SuccessOrExit(error = mEncoder.WriteUint16(0)); |
| SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.mCoapQueue.mNumMessages)); |
| SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.mCoapQueue.mNumBuffers)); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_ALL_MAC_COUNTERS>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| const otMacCounters *counters = otLinkGetCounters(mInstance); |
| |
| // Encode Tx related counters |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxTotal)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxUnicast)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxBroadcast)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxAckRequested)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxAcked)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxNoAckRequested)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxData)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxDataPoll)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxBeacon)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxBeaconRequest)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxOther)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxRetry)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxErrCca)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxErrAbort)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxErrBusyChannel)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxDirectMaxRetryExpiry)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxIndirectMaxRetryExpiry)); |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| |
| // Encode Rx related counters |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxTotal)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxUnicast)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxBroadcast)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxData)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxDataPoll)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxBeacon)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxBeaconRequest)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxOther)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxAddressFiltered)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxDestAddrFiltered)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxDuplicated)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxErrNoFrame)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxErrUnknownNeighbor)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxErrInvalidSrcAddr)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxErrSec)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxErrFcs)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxErrOther)); |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CNTR_ALL_MAC_COUNTERS>(void) |
| { |
| otLinkResetCounters(mInstance); |
| |
| return OT_ERROR_NONE; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_MLE_COUNTERS>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| const otMleCounters *counters = otThreadGetMleCounters(mInstance); |
| |
| OT_ASSERT(counters != nullptr); |
| |
| SuccessOrExit(error = mEncoder.WriteUint16(counters->mDisabledRole)); |
| SuccessOrExit(error = mEncoder.WriteUint16(counters->mDetachedRole)); |
| SuccessOrExit(error = mEncoder.WriteUint16(counters->mChildRole)); |
| SuccessOrExit(error = mEncoder.WriteUint16(counters->mRouterRole)); |
| SuccessOrExit(error = mEncoder.WriteUint16(counters->mLeaderRole)); |
| SuccessOrExit(error = mEncoder.WriteUint16(counters->mAttachAttempts)); |
| SuccessOrExit(error = mEncoder.WriteUint16(counters->mPartitionIdChanges)); |
| SuccessOrExit(error = mEncoder.WriteUint16(counters->mBetterPartitionAttachAttempts)); |
| SuccessOrExit(error = mEncoder.WriteUint16(counters->mParentChanges)); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CNTR_MLE_COUNTERS>(void) |
| { |
| otThreadResetMleCounters(mInstance); |
| |
| return OT_ERROR_NONE; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_ALL_IP_COUNTERS>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| const otIpCounters *counters = otThreadGetIp6Counters(mInstance); |
| |
| OT_ASSERT(counters != nullptr); |
| |
| // Encode Tx related counters |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxSuccess)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxFailure)); |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| |
| // Encode Rx related counters |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxSuccess)); |
| SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxFailure)); |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| |
| exit: |
| return error; |
| } |
| |
| #if OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_ENABLE |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_MAC_RETRY_HISTOGRAM>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| const uint32_t *histogramDirect; |
| const uint32_t *histogramIndirect; |
| uint8_t histogramDirectEntries; |
| uint8_t histogramIndirectEntries; |
| |
| histogramDirect = otLinkGetTxDirectRetrySuccessHistogram(mInstance, &histogramDirectEntries); |
| histogramIndirect = otLinkGetTxIndirectRetrySuccessHistogram(mInstance, &histogramIndirectEntries); |
| |
| OT_ASSERT((histogramDirectEntries == 0) || (histogramDirect != nullptr)); |
| OT_ASSERT((histogramIndirectEntries == 0) || (histogramIndirect != nullptr)); |
| |
| // Encode direct message retries histogram |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| for (uint8_t i = 0; i < histogramDirectEntries; i++) |
| { |
| SuccessOrExit(error = mEncoder.WriteUint32(histogramDirect[i])); |
| } |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| |
| // Encode indirect message retries histogram |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| for (uint8_t i = 0; i < histogramIndirectEntries; i++) |
| { |
| SuccessOrExit(error = mEncoder.WriteUint32(histogramIndirect[i])); |
| } |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CNTR_MAC_RETRY_HISTOGRAM>(void) |
| { |
| otLinkResetTxRetrySuccessHistogram(mInstance); |
| |
| return OT_ERROR_NONE; |
| } |
| #endif // OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_ENABLE |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CNTR_ALL_IP_COUNTERS>(void) |
| { |
| otThreadResetIp6Counters(mInstance); |
| |
| return OT_ERROR_NONE; |
| } |
| |
| #if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MAC_ALLOWLIST>(void) |
| { |
| otMacFilterEntry entry; |
| otMacFilterIterator iterator = OT_MAC_FILTER_ITERATOR_INIT; |
| otError error = OT_ERROR_NONE; |
| |
| while (otLinkFilterGetNextAddress(mInstance, &iterator, &entry) == OT_ERROR_NONE) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| |
| SuccessOrExit(error = mEncoder.WriteEui64(entry.mExtAddress)); |
| SuccessOrExit(error = mEncoder.WriteInt8(entry.mRssIn)); |
| |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MAC_ALLOWLIST_ENABLED>(void) |
| { |
| return mEncoder.WriteBool(otLinkFilterGetAddressMode(mInstance) == OT_MAC_FILTER_ADDRESS_MODE_ALLOWLIST); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MAC_DENYLIST>(void) |
| { |
| otMacFilterEntry entry; |
| otMacFilterIterator iterator = OT_MAC_FILTER_ITERATOR_INIT; |
| otError error = OT_ERROR_NONE; |
| |
| while (otLinkFilterGetNextAddress(mInstance, &iterator, &entry) == OT_ERROR_NONE) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| SuccessOrExit(error = mEncoder.WriteEui64(entry.mExtAddress)); |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MAC_DENYLIST_ENABLED>(void) |
| { |
| return mEncoder.WriteBool(otLinkFilterGetAddressMode(mInstance) == OT_MAC_FILTER_ADDRESS_MODE_DENYLIST); |
| } |
| |
| template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MAC_FIXED_RSS>(void) |
| { |
| otMacFilterEntry entry; |
| otMacFilterIterator iterator = OT_MAC_FILTER_ITERATOR_INIT; |
| otError error = OT_ERROR_NONE; |
| |
| while (otLinkFilterGetNextRssIn(mInstance, &iterator, &entry) == OT_ERROR_NONE) |
| { |
| SuccessOrExit(error = mEncoder.OpenStruct()); |
| |
| SuccessOrExit(error = mEncoder.WriteEui64(entry.mExtAddress)); |
| SuccessOrExit(error = mEncoder.WriteInt8(entry.mRssIn)); |
| |
| SuccessOrExit(error = mEncoder.CloseStruct()); |
| } |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MAC_ALLOWLIST>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| |
| // First, clear the address filter entries. |
| otLinkFilterClearAddresses(mInstance); |
| |
| while (mDecoder.GetRemainingLengthInStruct() > 0) |
| { |
| const otExtAddress *extAddress = nullptr; |
| int8_t rss; |
| |
| SuccessOrExit(error = mDecoder.OpenStruct()); |
| SuccessOrExit(error = mDecoder.ReadEui64(extAddress)); |
| |
| if (!mDecoder.IsAllReadInStruct()) |
| { |
| SuccessOrExit(error = mDecoder.ReadInt8(rss)); |
| } |
| else |
| { |
| rss = OT_MAC_FILTER_FIXED_RSS_DISABLED; |
| } |
| |
| SuccessOrExit(error = mDecoder.CloseStruct()); |
| |
| error = otLinkFilterAddAddress(mInstance, extAddress); |
| |
| 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)); |
| } |
| } |
| |
| exit: |
| // If we had an error, we may have actually changed |
| // the state of the allowlist, so we need to report |
| // those incomplete changes via an asynchronous |
| // change event. |
| |
| if (error != OT_ERROR_NONE) |
| { |
| IgnoreError(WritePropertyValueIsFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_PROP_MAC_ALLOWLIST)); |
| } |
| |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MAC_ALLOWLIST_ENABLED>(void) |
| { |
| bool enabled; |
| otError error = OT_ERROR_NONE; |
| otMacFilterAddressMode mode = OT_MAC_FILTER_ADDRESS_MODE_DISABLED; |
| |
| SuccessOrExit(error = mDecoder.ReadBool(enabled)); |
| |
| if (enabled) |
| { |
| mode = OT_MAC_FILTER_ADDRESS_MODE_ALLOWLIST; |
| } |
| |
| otLinkFilterSetAddressMode(mInstance, mode); |
| |
| exit: |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MAC_DENYLIST>(void) |
| { |
| otError error = OT_ERROR_NONE; |
| |
| // First, clear the address filter entries. |
| otLinkFilterClearAddresses(mInstance); |
| |
| while (mDecoder.GetRemainingLengthInStruct() > 0) |
| { |
| const otExtAddress *extAddress = nullptr; |
| |
| SuccessOrExit(error = mDecoder.OpenStruct()); |
| SuccessOrExit(error = mDecoder.ReadEui64(extAddress)); |
| SuccessOrExit(error = mDecoder.CloseStruct()); |
| |
| SuccessOrExit(error = otLinkFilterAddAddress(mInstance, extAddress)); |
| } |
| |
| exit: |
| // If we had an error, we may have actually changed |
| // the state of the denylist, so we need to report |
| // those incomplete changes via an asynchronous |
| // change event. |
| |
| if (error != OT_ERROR_NONE) |
| { |
| IgnoreError(WritePropertyValueIsFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_PROP_MAC_DENYLIST)); |
| } |
| |
| return error; |
| } |
| |
| template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MAC_DENYLIST_ENABLED>(void) |
| { |
| bool enabled; |
| otError error = OT_ERROR_NONE; |
| otMacFilterAddressMode mode = OT_MAC_FILTER_ADDRESS_MODE_DISABLED; |
| |
| SuccessOrExit(error = mDecoder.ReadBool(enabled)); |
| |
| if (enabled) |
| { |
| mode = OT_MAC_FILTER_ADDRESS_MODE_DENYLIST; |
| } |
| |
| otLinkFilterSetAddressMode(mInstance, mode); |
| |
| exit: |
| return error; |
| } |
| |
|