| /* |
| * |
| * Copyright (c) 2016 Nest Labs, Inc. |
| * All rights reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| |
| #if HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #include <algorithm> |
| #include <inttypes.h> |
| #include "SpinelNCPInstance.h" |
| #include "time-utils.h" |
| #include "assert-macros.h" |
| #include <syslog.h> |
| #include <errno.h> |
| #include "socket-utils.h" |
| #include <stdexcept> |
| #include <sys/file.h> |
| #include "SuperSocket.h" |
| #include "SpinelNCPTask.h" |
| #include "SpinelNCPTaskWake.h" |
| #include "SpinelNCPTaskSendCommand.h" |
| #include "SpinelNCPTaskJoin.h" |
| #include "SpinelNCPTaskGetNetworkTopology.h" |
| #include "SpinelNCPTaskGetMsgBufferCounters.h" |
| #include "SpinelNCPThreadDataset.h" |
| #include "any-to.h" |
| #include "spinel-extra.h" |
| #include "IPv6Helpers.h" |
| |
| #define kWPANTUND_Allowlist_RssiOverrideDisabled 127 |
| #define kWPANTUND_SpinelPropValueDumpLen 8 |
| |
| using namespace nl; |
| using namespace wpantund; |
| |
| WPANTUND_DEFINE_NCPINSTANCE_PLUGIN(spinel, SpinelNCPInstance); |
| |
| void |
| SpinelNCPInstance::handle_ncp_debug_stream(const uint8_t* data_ptr, int data_len) |
| { |
| static char linebuffer[NCP_DEBUG_LINE_LENGTH_MAX + 1]; |
| static int linepos = 0; |
| while (data_len--) { |
| char nextchar = *data_ptr++; |
| |
| if ((nextchar == '\t') || (nextchar >= 32)) { |
| linebuffer[linepos++] = nextchar; |
| } |
| |
| if ( (linepos != 0) |
| && ( (nextchar == '\n') |
| || (nextchar == '\r') |
| || (linepos >= (sizeof(linebuffer) - 1)) |
| ) |
| ) |
| { |
| // flush. |
| linebuffer[linepos] = 0; |
| syslog(LOG_WARNING, "NCP => %s\n", linebuffer); |
| linepos = 0; |
| } |
| } |
| } |
| |
| static const char * |
| ot_log_level_to_string(uint8_t log_level) |
| { |
| const char *retval = "----"; |
| |
| switch (log_level) |
| { |
| case SPINEL_NCP_LOG_LEVEL_EMERG: |
| retval = "EMRG"; |
| break; |
| |
| case SPINEL_NCP_LOG_LEVEL_ALERT: |
| retval = "ALRT"; |
| break; |
| |
| case SPINEL_NCP_LOG_LEVEL_CRIT: |
| retval = "CRIT"; |
| break; |
| |
| case SPINEL_NCP_LOG_LEVEL_ERR: |
| retval = "ERR "; |
| break; |
| |
| case SPINEL_NCP_LOG_LEVEL_WARN: |
| retval = "WARN"; |
| break; |
| |
| case SPINEL_NCP_LOG_LEVEL_NOTICE: |
| retval = "NOTE"; |
| break; |
| |
| case SPINEL_NCP_LOG_LEVEL_INFO: |
| retval = "INFO"; |
| break; |
| |
| case SPINEL_NCP_LOG_LEVEL_DEBUG: |
| retval = "DEBG"; |
| break; |
| } |
| |
| return retval; |
| } |
| |
| static const char * |
| ot_log_region_to_string(unsigned int log_region) |
| { |
| const char *retval = "---------"; |
| |
| switch (log_region) |
| { |
| case SPINEL_NCP_LOG_REGION_OT_API: |
| retval = "-API-----"; |
| break; |
| |
| case SPINEL_NCP_LOG_REGION_OT_MLE: |
| retval = "-MLE-----"; |
| break; |
| |
| case SPINEL_NCP_LOG_REGION_OT_COAP: |
| retval = "-COAP----"; |
| break; |
| |
| case SPINEL_NCP_LOG_REGION_OT_ARP: |
| retval = "-ARP-----"; |
| break; |
| |
| case SPINEL_NCP_LOG_REGION_OT_NET_DATA: |
| retval = "-N-DATA--"; |
| break; |
| |
| case SPINEL_NCP_LOG_REGION_OT_ICMP: |
| retval = "-ICMP----"; |
| break; |
| |
| case SPINEL_NCP_LOG_REGION_OT_IP6: |
| retval = "-IP6-----"; |
| break; |
| |
| case SPINEL_NCP_LOG_REGION_OT_MAC: |
| retval = "-MAC-----"; |
| break; |
| |
| case SPINEL_NCP_LOG_REGION_OT_MEM: |
| retval = "-MEM-----"; |
| break; |
| |
| case SPINEL_NCP_LOG_REGION_OT_NCP: |
| retval = "-NCP-----"; |
| break; |
| |
| case SPINEL_NCP_LOG_REGION_OT_MESH_COP: |
| retval = "-MESH-CP-"; |
| break; |
| |
| case SPINEL_NCP_LOG_REGION_OT_NET_DIAG: |
| retval = "-DIAG----"; |
| break; |
| |
| case SPINEL_NCP_LOG_REGION_OT_PLATFORM: |
| retval = "-PLAT----"; |
| break; |
| |
| case SPINEL_NCP_LOG_REGION_OT_CORE: |
| retval = "-CORE----"; |
| break; |
| |
| case SPINEL_NCP_LOG_REGION_OT_UTIL: |
| retval = "-UTIL----"; |
| break; |
| } |
| |
| return retval; |
| } |
| |
| void |
| SpinelNCPInstance::handle_ncp_log_stream(const uint8_t *data_in, int data_len) |
| { |
| spinel_ssize_t len; |
| char prefix_string[NCP_DEBUG_LINE_LENGTH_MAX + 1]; |
| const char *log_string; |
| |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| SPINEL_DATATYPE_UTF8_S, |
| &log_string |
| ); |
| require(len >= 0, bail); |
| |
| data_in += len; |
| data_len -= len; |
| |
| prefix_string[0] = 0; |
| |
| if ((data_len > 0) && mCapabilities.count(SPINEL_CAP_OPENTHREAD_LOG_METADATA)) { |
| uint8_t log_level; |
| unsigned int log_region; |
| uint64_t log_timestamp; |
| |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| ( |
| SPINEL_DATATYPE_UINT8_S |
| SPINEL_DATATYPE_UINT_PACKED_S |
| ), |
| &log_level, |
| &log_region |
| ); |
| require(len >= 0, bail); |
| |
| data_in += len; |
| data_len -= len; |
| |
| if (data_len >= sizeof(log_timestamp)) { |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| SPINEL_DATATYPE_UINT64_S, |
| &log_timestamp |
| ); |
| require(len >= 0, bail); |
| |
| snprintf( |
| prefix_string, |
| sizeof(prefix_string), |
| "[%013llu][%s]%s: ", |
| static_cast<unsigned long long>(log_timestamp), |
| ot_log_level_to_string(log_level), |
| ot_log_region_to_string(log_region) |
| ); |
| } else { |
| snprintf( |
| prefix_string, |
| sizeof(prefix_string), |
| "[%s]%s: ", |
| ot_log_level_to_string(log_level), |
| ot_log_region_to_string(log_region) |
| ); |
| } |
| } |
| |
| syslog(LOG_WARNING, "NCP => %s%s\n", prefix_string, log_string); |
| |
| bail: |
| return; |
| } |
| |
| void |
| SpinelNCPInstance::start_new_task(const boost::shared_ptr<SpinelNCPTask> &task) |
| { |
| if (ncp_state_is_detached_from_ncp(get_ncp_state())) { |
| task->finish(kWPANTUNDStatus_InvalidWhenDisabled); |
| } else if (PT_SCHEDULE(task->process_event(EVENT_STARTING_TASK))) { |
| |
| if (ncp_state_is_sleeping(get_ncp_state()) |
| && (dynamic_cast<const SpinelNCPTaskWake*>(task.get()) == NULL) |
| ) { |
| if (can_set_ncp_power() |
| || !mCapabilities.count(SPINEL_CAP_MCU_POWER_STATE) |
| ){ |
| start_new_task(boost::shared_ptr<SpinelNCPTask>(new SpinelNCPTaskWake(this, NilReturn()))); |
| } |
| } |
| |
| mTaskQueue.push_back(task); |
| } |
| } |
| |
| int |
| nl::wpantund::spinel_status_to_wpantund_status(int spinel_status) |
| { |
| wpantund_status_t ret; |
| switch (spinel_status) { |
| case SPINEL_STATUS_ALREADY: |
| ret = kWPANTUNDStatus_Already; |
| break; |
| case SPINEL_STATUS_BUSY: |
| ret = kWPANTUNDStatus_Busy; |
| break; |
| case SPINEL_STATUS_IN_PROGRESS: |
| ret = kWPANTUNDStatus_InProgress; |
| break; |
| case SPINEL_STATUS_JOIN_FAILURE: |
| ret = kWPANTUNDStatus_JoinFailedUnknown; |
| break; |
| case SPINEL_STATUS_JOIN_INCOMPATIBLE: |
| ret = kWPANTUNDStatus_JoinFailedAtScan; |
| break; |
| case SPINEL_STATUS_JOIN_SECURITY: |
| ret = kWPANTUNDStatus_JoinFailedAtAuthenticate; |
| break; |
| case SPINEL_STATUS_OK: |
| ret = kWPANTUNDStatus_Ok; |
| break; |
| case SPINEL_STATUS_PROP_NOT_FOUND: |
| ret = kWPANTUNDStatus_PropertyNotFound; |
| break; |
| case SPINEL_STATUS_INVALID_ARGUMENT: |
| ret = kWPANTUNDStatus_NCP_InvalidArgument; |
| break; |
| case SPINEL_STATUS_INVALID_STATE: |
| ret = kWPANTUNDStatus_InvalidForCurrentState; |
| break; |
| |
| default: |
| ret = WPANTUND_NCPERROR_TO_STATUS(spinel_status); |
| break; |
| } |
| |
| return ret; |
| } |
| |
| int |
| nl::wpantund::peek_ncp_callback_status(int event, va_list args) |
| { |
| int ret = 0; |
| |
| if (EVENT_NCP_PROP_VALUE_IS == event) { |
| va_list tmp; |
| va_copy(tmp, args); |
| unsigned int key = va_arg(tmp, unsigned int); |
| if (SPINEL_PROP_LAST_STATUS == key) { |
| const uint8_t* spinel_data_ptr = va_arg(tmp, const uint8_t*); |
| spinel_size_t spinel_data_len = va_arg(tmp, spinel_size_t); |
| |
| if (spinel_datatype_unpack(spinel_data_ptr, spinel_data_len, "i", &ret) <= 0) { |
| ret = SPINEL_STATUS_PARSE_ERROR; |
| } |
| } |
| va_end(tmp); |
| } else if (EVENT_NCP_RESET == event) { |
| va_list tmp; |
| va_copy(tmp, args); |
| ret = va_arg(tmp, int); |
| va_end(tmp); |
| } |
| |
| return ret; |
| } |
| |
| SpinelNCPInstance::SpinelNCPInstance(const Settings& settings) : |
| NCPInstanceBase(settings), mControlInterface(this), mVendorCustom(this) |
| { |
| mInboundFrameDataLen = 0; |
| mInboundFrameDataPtr = NULL; |
| mInboundFrameDataType = 0; |
| mInboundFrameHDLCCRC = 0; |
| mInboundFrameSize = 0; |
| mInboundHeader = 0; |
| mIsCommissioned = false; |
| mFilterRLOCAddresses = true; |
| mFilterALOCAddresses = true; |
| mTickleOnHostDidWake = false; |
| mIsPcapInProgress = false; |
| mLastHeader = 0; |
| mLastTID = 0; |
| mNetworkKeyIndex = 0; |
| mOutboundBufferEscapedLen = 0; |
| mOutboundBufferLen = 0; |
| mOutboundBufferSent = 0; |
| mOutboundBufferType = 0; |
| #if WPANTUND_NCP_RESET_EXPECTED_ON_START |
| mResetIsExpected = true; |
| #else |
| mResetIsExpected = false; |
| #endif |
| mSetSteeringDataWhenJoinable = false; |
| mSubPTIndex = 0; |
| mTXPower = 0; |
| mThreadMode = 0; |
| mXPANIDWasExplicitlySet = false; |
| mChannelManagerNewChannel = 0; |
| mMacFilterFixedRssi = -100; |
| mSupportedChannelMask = 0; |
| mPreferredChannelMask = 0; |
| mJoinerDiscernerBitLength = 0; |
| mCommissionerEnergyScanResult.clear(); |
| mCommissionerPanIdConflictResult.clear(); |
| |
| mSettings.clear(); |
| |
| regsiter_all_get_handlers(); |
| regsiter_all_set_handlers(); |
| regsiter_all_insert_handlers(); |
| regsiter_all_remove_handlers(); |
| |
| memset(mSteeringDataAddress, 0xff, sizeof(mSteeringDataAddress)); |
| |
| if (!settings.empty()) { |
| int status; |
| Settings::const_iterator iter; |
| |
| for(iter = settings.begin(); iter != settings.end(); iter++) { |
| if (!NCPInstanceBase::setup_property_supported_by_class(iter->first)) { |
| status = static_cast<NCPControlInterface&>(get_control_interface()) |
| .property_set_value(iter->first, iter->second); |
| |
| if (status != 0 && status != kWPANTUNDStatus_InProgress) { |
| syslog(LOG_WARNING, "Attempt to set property \"%s\" failed with err %s", iter->first.c_str(), wpantund_status_to_cstr(status)); |
| } |
| } |
| } |
| } |
| } |
| |
| SpinelNCPInstance::~SpinelNCPInstance() |
| { |
| } |
| |
| std::string |
| SpinelNCPInstance::thread_mode_to_string(uint8_t mode) |
| { |
| char c_string[400]; |
| |
| snprintf( |
| c_string, |
| sizeof(c_string), |
| "RxOnWhenIdle:%s FTD:%s FullNetData:%s SecDataReq:%s", |
| ((mode & SPINEL_THREAD_MODE_RX_ON_WHEN_IDLE) != 0) ? "yes" : "no", |
| ((mode & SPINEL_THREAD_MODE_FULL_THREAD_DEV) != 0) ? "yes" : "no", |
| ((mode & SPINEL_THREAD_MODE_FULL_NETWORK_DATA) != 0) ? "yes" : "no", |
| ((mode & SPINEL_THREAD_MODE_SECURE_DATA_REQUEST) != 0) ? "yes" : "no" |
| ); |
| |
| return c_string; |
| } |
| |
| uint8_t |
| SpinelNCPInstance::get_thread_mode(void) |
| { |
| return mThreadMode; |
| } |
| |
| bool |
| SpinelNCPInstance::setup_property_supported_by_class(const std::string& prop_name) |
| { |
| return NCPInstanceBase::setup_property_supported_by_class(prop_name); |
| } |
| |
| SpinelNCPControlInterface& |
| SpinelNCPInstance::get_control_interface() |
| { |
| return mControlInterface; |
| } |
| |
| std::set<std::string> |
| SpinelNCPInstance::get_supported_property_keys()const |
| { |
| std::set<std::string> properties (NCPInstanceBase::get_supported_property_keys()); |
| |
| properties.insert(kWPANTUNDProperty_ConfigNCPDriverName); |
| properties.insert(kWPANTUNDProperty_NCPChannel); |
| properties.insert(kWPANTUNDProperty_NCPChannelMask); |
| properties.insert(kWPANTUNDProperty_NCPPreferredChannelMask); |
| properties.insert(kWPANTUNDProperty_NCPFrequency); |
| properties.insert(kWPANTUNDProperty_NCPRSSI); |
| properties.insert(kWPANTUNDProperty_NCPExtendedAddress); |
| properties.insert(kWPANTUNDProperty_NCPCCAFailureRate); |
| properties.insert(kWPANTUNDProperty_NCPCapabilities); |
| |
| if (mCapabilities.count(SPINEL_CAP_ROLE_SLEEPY)) { |
| properties.insert(kWPANTUNDProperty_NCPSleepyPollInterval); |
| } |
| |
| properties.insert(kWPANTUNDProperty_ThreadRLOC16); |
| properties.insert(kWPANTUNDProperty_ThreadDeviceMode); |
| properties.insert(kWPANTUNDProperty_ThreadRouterID); |
| properties.insert(kWPANTUNDProperty_ThreadLeaderAddress); |
| properties.insert(kWPANTUNDProperty_ThreadLeaderRouterID); |
| properties.insert(kWPANTUNDProperty_ThreadLeaderWeight); |
| properties.insert(kWPANTUNDProperty_ThreadLeaderLocalWeight); |
| properties.insert(kWPANTUNDProperty_ThreadNetworkData); |
| properties.insert(kWPANTUNDProperty_ThreadNetworkDataVersion); |
| properties.insert(kWPANTUNDProperty_ThreadStableNetworkData); |
| properties.insert(kWPANTUNDProperty_ThreadStableNetworkDataVersion); |
| properties.insert(kWPANTUNDProperty_ThreadLeaderNetworkData); |
| properties.insert(kWPANTUNDProperty_ThreadStableLeaderNetworkData); |
| properties.insert(kWPANTUNDProperty_ThreadChildTable); |
| properties.insert(kWPANTUNDProperty_ThreadChildTableAddresses); |
| properties.insert(kWPANTUNDProperty_ThreadNeighborTable); |
| properties.insert(kWPANTUNDProperty_ThreadChildTimeout); |
| properties.insert(kWPANTUNDProperty_ThreadRouterTable); |
| properties.insert(kWPANTUNDProperty_ThreadParent); |
| properties.insert(kWPANTUNDProperty_ThreadOffMeshRoutes); |
| properties.insert(kWPANTUNDProperty_NetworkPartitionId); |
| properties.insert(kWPANTUNDProperty_ThreadRouterUpgradeThreshold); |
| properties.insert(kWPANTUNDProperty_ThreadRouterDowngradeThreshold); |
| properties.insert(kWPANTUNDProperty_ThreadActiveDataset); |
| properties.insert(kWPANTUNDProperty_ThreadPendingDataset); |
| properties.insert(kWPANTUNDProperty_ThreadAddressCacheTable); |
| properties.insert(kWPANTUNDProperty_OpenThreadSupportedRadioLinks); |
| |
| if (mCapabilities.count(SPINEL_CAP_NET_THREAD_1_2)) { |
| properties.insert(kWPANTUNDProperty_ThreadDomainName); |
| properties.insert(kWPANTUNDProperty_ThreadBackboneRouterPrimary); |
| } |
| |
| if (mCapabilities.count(SPINEL_CAP_THREAD_BACKBONE_ROUTER)) { |
| properties.insert(kWPANTUNDProperty_ThreadBackboneRouterLocalState); |
| properties.insert(kWPANTUNDProperty_ThreadBackboneRouterLocalConfig); |
| properties.insert(kWPANTUNDProperty_ThreadBackboneRouterLocalJitter); |
| } |
| |
| if (mCapabilities.count(SPINEL_CAP_ERROR_RATE_TRACKING)) { |
| properties.insert(kWPANTUNDProperty_ThreadNeighborTableErrorRates); |
| } |
| |
| if (mCapabilities.count(SPINEL_CAP_MULTI_RADIO)) { |
| properties.insert(kWPANTUNDProperty_OpenThreadNeighborTableMultiRadioInfo); |
| } |
| |
| if (mCapabilities.count(SPINEL_CAP_DUA)) { |
| properties.insert(kWPANTUNDProperty_ThreadDUAInterfaceIdentifier); |
| } |
| |
| if (mCapabilities.count(SPINEL_CAP_THREAD_COMMISSIONER)) { |
| properties.insert(kWPANTUNDProperty_CommissionerState); |
| properties.insert(kWPANTUNDProperty_CommissionerProvisioningUrl); |
| properties.insert(kWPANTUNDProperty_CommissionerSessionId); |
| properties.insert(kWPANTUNDProperty_CommissionerJoiners); |
| } |
| |
| if (mCapabilities.count(SPINEL_CAP_THREAD_JOINER)) { |
| properties.insert(kWPANTUNDProperty_JoinerState); |
| properties.insert(kWPANTUNDProperty_JoinerDiscernerValue); |
| properties.insert(kWPANTUNDProperty_JoinerDiscernerBitLength); |
| } |
| |
| if (mCapabilities.count(SPINEL_CAP_POSIX)) { |
| properties.insert(kWPANTUNDProperty_POSIXAppRCPVersion); |
| } |
| |
| if (mCapabilities.count(SPINEL_CAP_COUNTERS)) { |
| properties.insert(kWPANTUNDProperty_NCPCounterAllMac); |
| properties.insert(kWPANTUNDProperty_NCPCounter_TX_IP_SEC_TOTAL); |
| properties.insert(kWPANTUNDProperty_NCPCounter_TX_IP_INSEC_TOTAL); |
| properties.insert(kWPANTUNDProperty_NCPCounter_TX_IP_DROPPED); |
| properties.insert(kWPANTUNDProperty_NCPCounter_RX_IP_SEC_TOTAL); |
| properties.insert(kWPANTUNDProperty_NCPCounter_RX_IP_INSEC_TOTAL); |
| properties.insert(kWPANTUNDProperty_NCPCounter_RX_IP_DROPPED); |
| properties.insert(kWPANTUNDProperty_NCPCounter_TX_SPINEL_TOTAL); |
| properties.insert(kWPANTUNDProperty_NCPCounter_RX_SPINEL_TOTAL); |
| properties.insert(kWPANTUNDProperty_NCPCounter_RX_SPINEL_ERR); |
| properties.insert(kWPANTUNDProperty_NCPCounterThreadMle); |
| properties.insert(kWPANTUNDProperty_NCPCounterAllIPv6); |
| } |
| |
| if (mCapabilities.count(SPINEL_CAP_MAC_ALLOWLIST)) { |
| properties.insert(kWPANTUNDProperty_MACAllowlistEnabled); |
| properties.insert(kWPANTUNDProperty_MACAllowlistEntries); |
| properties.insert(kWPANTUNDProperty_MACDenylistEnabled); |
| properties.insert(kWPANTUNDProperty_MACDenylistEntries); |
| } |
| |
| if (mCapabilities.count(SPINEL_CAP_JAM_DETECT)) { |
| properties.insert(kWPANTUNDProperty_JamDetectionStatus); |
| properties.insert(kWPANTUNDProperty_JamDetectionEnable); |
| properties.insert(kWPANTUNDProperty_JamDetectionRssiThreshold); |
| properties.insert(kWPANTUNDProperty_JamDetectionWindow); |
| properties.insert(kWPANTUNDProperty_JamDetectionBusyPeriod); |
| properties.insert(kWPANTUNDProperty_JamDetectionDebugHistoryBitmap); |
| } |
| |
| if (mCapabilities.count(SPINEL_CAP_CHANNEL_MONITOR)) { |
| properties.insert(kWPANTUNDProperty_ChannelMonitorSampleInterval); |
| properties.insert(kWPANTUNDProperty_ChannelMonitorRssiThreshold); |
| properties.insert(kWPANTUNDProperty_ChannelMonitorSampleWindow); |
| properties.insert(kWPANTUNDProperty_ChannelMonitorSampleCount); |
| properties.insert(kWPANTUNDProperty_ChannelMonitorChannelQuality); |
| } |
| |
| if (mCapabilities.count(SPINEL_CAP_CHANNEL_MANAGER)) { |
| properties.insert(kWPANTUNDProperty_ChannelManagerNewChannel); |
| properties.insert(kWPANTUNDProperty_ChannelManagerDelay); |
| properties.insert(kWPANTUNDProperty_ChannelManagerAutoSelectEnabled); |
| properties.insert(kWPANTUNDProperty_ChannelManagerAutoSelectInterval); |
| properties.insert(kWPANTUNDProperty_ChannelManagerSupportedChannelMask); |
| properties.insert(kWPANTUNDProperty_ChannelManagerFavoredChannelMask); |
| } |
| |
| if (mCapabilities.count(SPINEL_CAP_THREAD_TMF_PROXY)) { |
| properties.insert(kWPANTUNDProperty_TmfProxyEnabled); |
| } |
| |
| if (mCapabilities.count(SPINEL_CAP_NEST_LEGACY_INTERFACE)) { |
| properties.insert(kWPANTUNDProperty_NestLabs_LegacyMeshLocalPrefix); |
| } |
| |
| if (mCapabilities.count(SPINEL_CAP_TIME_SYNC)) { |
| properties.insert(kWPANTUNDProperty_TimeSync_NetworkTime); |
| properties.insert(kWPANTUNDProperty_TimeSync_Period); |
| properties.insert(kWPANTUNDProperty_TimeSync_XtalThreshold); |
| } |
| |
| if (mCapabilities.count(SPINEL_CAP_THREAD_SERVICE)) { |
| properties.insert(kWPANTUNDProperty_ThreadServices); |
| properties.insert(kWPANTUNDProperty_ThreadLeaderServices); |
| } |
| |
| if (mCapabilities.count(SPINEL_CAP_THREAD_CSL_RECEIVER)) { |
| properties.insert(kWPANTUNDProperty_ThreadCslPeriod); |
| properties.insert(kWPANTUNDProperty_ThreadCslTimeout); |
| properties.insert(kWPANTUNDProperty_ThreadCslChannel); |
| } |
| |
| if (mCapabilities.count(SPINEL_CAP_RADIO_COEX)) { |
| properties.insert(kWPANTUNDProperty_NCPCoexEnable); |
| properties.insert(kWPANTUNDProperty_NCPCoexMetrics); |
| } |
| |
| if (mCapabilities.count(SPINEL_CAP_OPENTHREAD_LOG_METADATA)) { |
| properties.insert(kWPANTUNDProperty_OpenThreadLogTimestampBase); |
| } |
| |
| { |
| const std::set<std::string> vendor_props(mVendorCustom.get_supported_property_keys()); |
| properties.insert(vendor_props.begin(), vendor_props.end()); |
| } |
| |
| return properties; |
| } |
| |
| cms_t |
| SpinelNCPInstance::get_ms_to_next_event(void) |
| { |
| cms_t cms = NCPInstanceBase::get_ms_to_next_event(); |
| |
| if (ncp_state_is_detached_from_ncp(get_ncp_state())) { |
| return CMS_DISTANT_FUTURE; |
| } |
| |
| // If the control protothread hasn't even started, set cms to zero. |
| if (0 == mControlPT.lc) { |
| cms = 0; |
| } |
| |
| if (!mTaskQueue.empty()) { |
| int tmp_cms = mTaskQueue.front()->get_ms_to_next_event(); |
| if (tmp_cms < cms) { |
| cms = tmp_cms; |
| } |
| } |
| |
| if (cms > mVendorCustom.get_ms_to_next_event()) { |
| cms = mVendorCustom.get_ms_to_next_event(); |
| } |
| |
| if (cms < 0) { |
| cms = 0; |
| } |
| |
| return cms; |
| } |
| |
| static void |
| convert_rloc16_to_router_id(CallbackWithStatusArg1 cb, int status, const boost::any& value) |
| { |
| uint8_t router_id = 0; |
| |
| if (status == kWPANTUNDStatus_Ok) { |
| uint16_t rloc16 = any_to_int(value); |
| router_id = rloc16 >> 10; |
| } |
| cb(status, router_id); |
| } |
| |
| |
| |
| static int |
| unpack_commissioner_state(const uint8_t *data_in, spinel_size_t data_len, boost::any& value) |
| { |
| spinel_ssize_t len; |
| uint8_t state; |
| int ret = kWPANTUNDStatus_Ok; |
| |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| SPINEL_DATATYPE_UINT8_S, |
| &state |
| ); |
| |
| if (len > 0) { |
| switch (state) { |
| case SPINEL_MESHCOP_COMMISSIONER_STATE_DISABLED: |
| value = std::string(kWPANTUNDCommissionerState_Disabled); |
| break; |
| case SPINEL_MESHCOP_COMMISSIONER_STATE_PETITION: |
| value = std::string(kWPANTUNDCommissionerState_Petition); |
| break; |
| case SPINEL_MESHCOP_COMMISSIONER_STATE_ACTIVE: |
| value = std::string(kWPANTUNDCommissionerState_Active); |
| break; |
| default: |
| ret = kWPANTUNDStatus_Failure; |
| break; |
| } |
| } else { |
| ret = kWPANTUNDStatus_Failure; |
| } |
| |
| return ret; |
| } |
| |
| static int |
| unpack_commissioner_joiners(const uint8_t *data_in, spinel_size_t data_len, boost::any &value) |
| { |
| spinel_ssize_t len; |
| std::list<std::string> result; |
| char c_string[300]; |
| int ret = kWPANTUNDStatus_Ok; |
| |
| while (data_len > 0) { |
| const uint8_t *joiner_info_in; |
| spinel_size_t joiner_info_len; |
| uint32_t joiner_timeout; |
| const char *joiner_pskd; |
| const spinel_eui64_t *joiner_eui64 = NULL; |
| uint8_t discerner_bit_len; |
| uint64_t discerner_value; |
| bool any_joiner = false; |
| |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| SPINEL_DATATYPE_STRUCT_S( |
| SPINEL_DATATYPE_DATA_WLEN_S // Joiner Info struct (empty or EUI64 or Discerner) |
| SPINEL_DATATYPE_UINT32_S |
| SPINEL_DATATYPE_UTF8_S |
| ), |
| &joiner_info_in, &joiner_info_len, |
| &joiner_timeout, |
| &joiner_pskd |
| ); |
| |
| require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
| |
| data_in += len; |
| data_len -= len; |
| |
| switch (joiner_info_len) |
| { |
| case 0: |
| any_joiner = true; |
| break; |
| |
| case sizeof(spinel_eui64_t): |
| joiner_eui64 = (const spinel_eui64_t *)joiner_info_in; |
| break; |
| |
| default: |
| len = spinel_datatype_unpack( |
| joiner_info_in, |
| joiner_info_len, |
| ( |
| SPINEL_DATATYPE_UINT8_S |
| SPINEL_DATATYPE_UINT64_S |
| ), |
| &discerner_bit_len, |
| &discerner_value |
| ); |
| joiner_eui64 = NULL; |
| break; |
| } |
| |
| if (any_joiner) { |
| snprintf(c_string, sizeof(c_string), "any joiner, psk:%s, timeout:%.2f", joiner_pskd, joiner_timeout/1000.0); |
| |
| } else if (joiner_eui64 != NULL) { |
| snprintf(c_string, sizeof(c_string), "eui64:%02X%02X%02X%02X%02X%02X%02X%02X, psk:%s, timeout:%.2f", |
| joiner_eui64->bytes[0], joiner_eui64->bytes[1], joiner_eui64->bytes[2], joiner_eui64->bytes[3], |
| joiner_eui64->bytes[4], joiner_eui64->bytes[5], joiner_eui64->bytes[6], joiner_eui64->bytes[7], |
| joiner_pskd, joiner_timeout/1000.0); |
| |
| } else { |
| snprintf(c_string, sizeof(c_string), "discerner:%" PRIu64 ", bit-len:%d, psk:%s, timeout:%.2f", |
| discerner_value, discerner_bit_len, joiner_pskd, joiner_timeout/1000.0); |
| } |
| |
| result.push_back(std::string(c_string)); |
| } |
| |
| value = result; |
| |
| bail: |
| return ret; |
| } |
| |
| |
| static int |
| unpack_channel_mask(const uint8_t *data_in, spinel_size_t data_len, boost::any& value) |
| { |
| spinel_ssize_t len; |
| uint32_t channel_mask = 0; |
| uint8_t channel = 0xff; |
| int ret = kWPANTUNDStatus_Ok; |
| |
| while (data_len > 0) |
| { |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| SPINEL_DATATYPE_UINT8_S, |
| &channel |
| ); |
| |
| if ((len <= 0) || (channel >= 32)) { |
| ret = kWPANTUNDStatus_Failure; |
| break; |
| } |
| |
| channel_mask |= (1U << channel); |
| |
| data_in += len; |
| data_len -= len; |
| } |
| |
| if (ret == kWPANTUNDStatus_Ok) { |
| value = channel_mask; |
| } |
| |
| return ret; |
| } |
| |
| static int |
| unpack_mac_allowlist_entries(const uint8_t *data_in, spinel_size_t data_len, boost::any& value, bool as_val_map) |
| { |
| spinel_ssize_t len; |
| ValueMap entry; |
| std::list<ValueMap> result_as_val_map; |
| std::list<std::string> result_as_string; |
| const spinel_eui64_t *eui64 = NULL; |
| int8_t rssi = 0; |
| |
| int ret = kWPANTUNDStatus_Ok; |
| |
| while (data_len > 0) |
| { |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| SPINEL_DATATYPE_STRUCT_S( |
| SPINEL_DATATYPE_EUI64_S // Extended address |
| SPINEL_DATATYPE_INT8_S // Rssi |
| ), |
| &eui64, |
| &rssi |
| ); |
| |
| require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
| |
| if (as_val_map) { |
| entry.clear(); |
| entry[kWPANTUNDValueMapKey_Allowlist_ExtAddress] = Data(eui64->bytes, sizeof(spinel_eui64_t)); |
| |
| if (rssi != kWPANTUND_Allowlist_RssiOverrideDisabled) { |
| entry[kWPANTUNDValueMapKey_Allowlist_Rssi] = rssi; |
| } |
| |
| result_as_val_map.push_back(entry); |
| |
| } else { |
| char c_string[500]; |
| int index; |
| |
| index = snprintf(c_string, sizeof(c_string), "%02X%02X%02X%02X%02X%02X%02X%02X", |
| eui64->bytes[0], eui64->bytes[1], eui64->bytes[2], eui64->bytes[3], |
| eui64->bytes[4], eui64->bytes[5], eui64->bytes[6], eui64->bytes[7]); |
| |
| if (rssi != kWPANTUND_Allowlist_RssiOverrideDisabled) { |
| if (index >= 0 && index < sizeof(c_string)) { |
| snprintf(c_string + index, sizeof(c_string) - index, " fixed-rssi:%d", rssi); |
| } |
| } |
| |
| result_as_string.push_back(std::string(c_string)); |
| } |
| |
| data_len -= len; |
| data_in += len; |
| } |
| |
| if (as_val_map) { |
| value = result_as_val_map; |
| } else { |
| value = result_as_string; |
| } |
| |
| bail: |
| return ret; |
| } |
| |
| static int |
| unpack_mac_denylist_entries(const uint8_t *data_in, spinel_size_t data_len, boost::any& value, bool as_val_map) |
| { |
| spinel_ssize_t len; |
| ValueMap entry; |
| std::list<ValueMap> result_as_val_map; |
| std::list<std::string> result_as_string; |
| const spinel_eui64_t *eui64 = NULL; |
| |
| int ret = kWPANTUNDStatus_Ok; |
| |
| while (data_len > 0) |
| { |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| SPINEL_DATATYPE_STRUCT_S( |
| SPINEL_DATATYPE_EUI64_S // Extended address |
| ), |
| &eui64 |
| ); |
| |
| if (len <= 0) |
| { |
| ret = kWPANTUNDStatus_Failure; |
| break; |
| } |
| |
| if (as_val_map) { |
| entry.clear(); |
| entry[kWPANTUNDValueMapKey_Allowlist_ExtAddress] = Data(eui64->bytes, sizeof(spinel_eui64_t)); |
| result_as_val_map.push_back(entry); |
| |
| } else { |
| char c_string[500]; |
| int index; |
| |
| index = snprintf(c_string, sizeof(c_string), "%02X%02X%02X%02X%02X%02X%02X%02X", |
| eui64->bytes[0], eui64->bytes[1], eui64->bytes[2], eui64->bytes[3], |
| eui64->bytes[4], eui64->bytes[5], eui64->bytes[6], eui64->bytes[7]); |
| |
| result_as_string.push_back(std::string(c_string)); |
| } |
| |
| data_len -= len; |
| data_in += len; |
| } |
| |
| if (ret == kWPANTUNDStatus_Ok) { |
| |
| if (as_val_map) { |
| value = result_as_val_map; |
| } else { |
| value = result_as_string; |
| } |
| } |
| |
| return ret; |
| } |
| |
| static int |
| unpack_channel_occupancy(const uint8_t *data_in, spinel_size_t data_len, boost::any& value, bool as_val_map) |
| { |
| std::list<std::string> result_as_string; |
| std::list<ValueMap> result_as_val_map; |
| int ret = kWPANTUNDStatus_Ok; |
| |
| while (data_len > 0) |
| { |
| spinel_ssize_t len; |
| uint8_t channel; |
| uint16_t quality; |
| |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| SPINEL_DATATYPE_STRUCT_S( |
| SPINEL_DATATYPE_UINT8_S // Channel |
| SPINEL_DATATYPE_UINT16_S // Quality |
| ), |
| &channel, |
| &quality |
| ); |
| |
| require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
| |
| if (!as_val_map) { |
| char c_string[100]; |
| |
| snprintf(c_string, sizeof(c_string), "ch %d (0x%04x) %.2f%% busy ", channel, quality, |
| static_cast<double>(quality) * 100.0 / 0xffff); |
| |
| result_as_string.push_back(std::string(c_string)); |
| } else { |
| ValueMap entry; |
| |
| entry[kWPANTUNDValueMapKey_ChannelMonitor_Channel] = boost::any((int)channel); |
| entry[kWPANTUNDValueMapKey_ChannelMonitor_Quality] = boost::any((int)quality); |
| result_as_val_map.push_back(entry); |
| } |
| |
| data_in += len; |
| data_len -= len; |
| } |
| |
| if (as_val_map) { |
| value = result_as_val_map; |
| } else { |
| value = result_as_string; |
| } |
| |
| bail: |
| return ret; |
| } |
| |
| static int |
| unpack_ncp_counters_all_mac(const uint8_t *data_in, spinel_size_t data_len, boost::any& value, bool as_val_map) |
| { |
| std::list<std::string> result_as_string; |
| ValueMap result_as_val_map; |
| int ret = kWPANTUNDStatus_Ok; |
| spinel_ssize_t len; |
| |
| const char *tx_counter_names[] = { |
| kWPANTUNDValueMapKey_Counter_TxTotal, |
| kWPANTUNDValueMapKey_Counter_TxUnicast, |
| kWPANTUNDValueMapKey_Counter_TxBroadcast, |
| kWPANTUNDValueMapKey_Counter_TxAckRequested, |
| kWPANTUNDValueMapKey_Counter_TxAcked, |
| kWPANTUNDValueMapKey_Counter_TxNoAckRequested, |
| kWPANTUNDValueMapKey_Counter_TxData, |
| kWPANTUNDValueMapKey_Counter_TxDataPoll, |
| kWPANTUNDValueMapKey_Counter_TxBeacon, |
| kWPANTUNDValueMapKey_Counter_TxBeaconRequest, |
| kWPANTUNDValueMapKey_Counter_TxOther, |
| kWPANTUNDValueMapKey_Counter_TxRetry, |
| kWPANTUNDValueMapKey_Counter_TxErrCca, |
| kWPANTUNDValueMapKey_Counter_TxErrAbort, |
| kWPANTUNDValueMapKey_Counter_TxErrBusyChannel, |
| NULL |
| }; |
| |
| const char *rx_counter_names[] = { |
| kWPANTUNDValueMapKey_Counter_RxTotal, |
| kWPANTUNDValueMapKey_Counter_RxUnicast, |
| kWPANTUNDValueMapKey_Counter_RxBroadcast, |
| kWPANTUNDValueMapKey_Counter_RxData, |
| kWPANTUNDValueMapKey_Counter_RxDataPoll, |
| kWPANTUNDValueMapKey_Counter_RxBeacon, |
| kWPANTUNDValueMapKey_Counter_RxBeaconRequest, |
| kWPANTUNDValueMapKey_Counter_RxOther, |
| kWPANTUNDValueMapKey_Counter_RxAddressFiltered, |
| kWPANTUNDValueMapKey_Counter_RxDestAddrFiltered, |
| kWPANTUNDValueMapKey_Counter_RxDuplicated, |
| kWPANTUNDValueMapKey_Counter_RxErrNoFrame, |
| kWPANTUNDValueMapKey_Counter_RxErrUnknownNeighbor, |
| kWPANTUNDValueMapKey_Counter_RxErrInvalidSrcAddr, |
| kWPANTUNDValueMapKey_Counter_RxErrSec, |
| kWPANTUNDValueMapKey_Counter_RxErrFcs, |
| kWPANTUNDValueMapKey_Counter_RxErrOther, |
| NULL |
| }; |
| |
| for (int struct_index = 0; struct_index < 2; struct_index++) |
| { |
| const char **counter_names; |
| const uint8_t *struct_in = NULL; |
| unsigned int struct_len = 0; |
| spinel_size_t len; |
| |
| counter_names = (struct_index == 0) ? tx_counter_names : rx_counter_names; |
| |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| SPINEL_DATATYPE_DATA_WLEN_S, |
| &struct_in, |
| &struct_len |
| ); |
| |
| require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
| |
| data_in += len; |
| data_len -= len; |
| |
| while (*counter_names != NULL) { |
| uint32_t counter_value; |
| |
| len = spinel_datatype_unpack( |
| struct_in, |
| struct_len, |
| SPINEL_DATATYPE_UINT32_S, |
| &counter_value |
| ); |
| |
| require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
| |
| struct_in += len; |
| struct_len -= len; |
| |
| if (!as_val_map) { |
| char c_string[200]; |
| snprintf(c_string, sizeof(c_string), "%-20s = %d", *counter_names, counter_value); |
| result_as_string.push_back(std::string(c_string)); |
| } else { |
| result_as_val_map[*counter_names] = counter_value; |
| } |
| |
| counter_names++; |
| } |
| } |
| |
| if (as_val_map) { |
| value = result_as_val_map; |
| } else { |
| value = result_as_string; |
| } |
| |
| bail: |
| return ret; |
| } |
| |
| static int |
| unpack_ncp_counters_mle(const uint8_t *data_in, spinel_size_t data_len, boost::any& value, bool as_val_map) |
| { |
| std::list<std::string> result_as_string; |
| ValueMap result_as_val_map; |
| int ret = kWPANTUNDStatus_Ok; |
| spinel_ssize_t len; |
| |
| const char *mle_counter_names[] = { |
| kWPANTUNDValueMapKey_MleCounter_DisabledRole, |
| kWPANTUNDValueMapKey_MleCounter_DetachedRole, |
| kWPANTUNDValueMapKey_MleCounter_ChildRole, |
| kWPANTUNDValueMapKey_MleCounter_RouterRole, |
| kWPANTUNDValueMapKey_MleCounter_LeaderRole, |
| kWPANTUNDValueMapKey_MleCounter_AttachAttempts, |
| kWPANTUNDValueMapKey_MleCounter_PartitionIdChanges, |
| kWPANTUNDValueMapKey_MleCounter_BetterPartitionAttaches, |
| kWPANTUNDValueMapKey_MleCounter_ParentChanges, |
| NULL |
| }; |
| |
| const char **counter_names = mle_counter_names; |
| |
| while (*counter_names != NULL) { |
| uint16_t counter_value; |
| |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| SPINEL_DATATYPE_UINT16_S, |
| &counter_value |
| ); |
| |
| require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
| |
| data_in += len; |
| data_len -= len; |
| |
| if (!as_val_map) { |
| char c_string[200]; |
| snprintf(c_string, sizeof(c_string), "%-20s = %d", *counter_names, counter_value); |
| result_as_string.push_back(std::string(c_string)); |
| } else { |
| result_as_val_map[*counter_names] = counter_value; |
| } |
| |
| counter_names++; |
| } |
| |
| if (as_val_map) { |
| value = result_as_val_map; |
| } else { |
| value = result_as_string; |
| } |
| |
| bail: |
| return ret; |
| } |
| |
| static int |
| unpack_ncp_counters_ipv6(const uint8_t *data_in, spinel_size_t data_len, boost::any& value, bool as_val_map) |
| { |
| std::list<std::string> result_as_string; |
| ValueMap result_as_val_map; |
| int ret = kWPANTUNDStatus_Ok; |
| spinel_ssize_t len; |
| |
| const char *tx_counter_names[] = { |
| kWPANTUNDValueMapKey_IPv6Counter_TxSuccess, |
| kWPANTUNDValueMapKey_IPv6Counter_TxFailure, |
| NULL |
| }; |
| |
| const char *rx_counter_names[] = { |
| kWPANTUNDValueMapKey_IPv6Counter_RxSuccess, |
| kWPANTUNDValueMapKey_IPv6Counter_RxFailure, |
| NULL |
| }; |
| |
| for (int struct_index = 0; struct_index < 2; struct_index++) |
| { |
| const char **counter_names; |
| const uint8_t *struct_in = NULL; |
| unsigned int struct_len = 0; |
| spinel_size_t len; |
| |
| counter_names = (struct_index == 0) ? tx_counter_names : rx_counter_names; |
| |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| SPINEL_DATATYPE_DATA_WLEN_S, |
| &struct_in, |
| &struct_len |
| ); |
| |
| require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
| |
| data_in += len; |
| data_len -= len; |
| |
| while (*counter_names != NULL) { |
| uint32_t counter_value; |
| |
| len = spinel_datatype_unpack( |
| struct_in, |
| struct_len, |
| SPINEL_DATATYPE_UINT32_S, |
| &counter_value |
| ); |
| |
| require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
| |
| struct_in += len; |
| struct_len -= len; |
| |
| if (!as_val_map) { |
| char c_string[200]; |
| snprintf(c_string, sizeof(c_string), "%-20s = %d", *counter_names, counter_value); |
| result_as_string.push_back(std::string(c_string)); |
| } else { |
| result_as_val_map[*counter_names] = counter_value; |
| } |
| |
| counter_names++; |
| } |
| } |
| |
| if (as_val_map) { |
| value = result_as_val_map; |
| } else { |
| value = result_as_string; |
| } |
| |
| bail: |
| return ret; |
| } |
| |
| static int |
| unpack_coex_metrics(const uint8_t *data_in, spinel_size_t data_len, boost::any& value, bool as_val_map) |
| { |
| std::list<std::string> result_as_string; |
| ValueMap result_as_val_map; |
| int ret = kWPANTUNDStatus_Ok; |
| spinel_ssize_t len; |
| bool stopped; |
| uint32_t num_grant_glitch; |
| |
| const char *tx_coex_metrics_names[] = { |
| kWPANTUNDValueMapKey_CoexMetrics_NumTxRequest, |
| kWPANTUNDValueMapKey_CoexMetrics_NumTxGrantImmediate, |
| kWPANTUNDValueMapKey_CoexMetrics_NumTxGrantWait, |
| kWPANTUNDValueMapKey_CoexMetrics_NumTxGrantWaitActivated, |
| kWPANTUNDValueMapKey_CoexMetrics_NumTxGrantWaitTimeout, |
| kWPANTUNDValueMapKey_CoexMetrics_NumTxGrantDeactivatedDuringRequest, |
| kWPANTUNDValueMapKey_CoexMetrics_NumTxDelayedGrant, |
| kWPANTUNDValueMapKey_CoexMetrics_AvgTxRequestToGrantTime, |
| NULL |
| }; |
| |
| const char *rx_coex_metrics_names[] = { |
| kWPANTUNDValueMapKey_CoexMetrics_NumRxRequest, |
| kWPANTUNDValueMapKey_CoexMetrics_NumRxGrantImmediate, |
| kWPANTUNDValueMapKey_CoexMetrics_NumRxGrantWait, |
| kWPANTUNDValueMapKey_CoexMetrics_NumRxGrantWaitActivated, |
| kWPANTUNDValueMapKey_CoexMetrics_NumRxGrantWaitTimeout, |
| kWPANTUNDValueMapKey_CoexMetrics_NumRxGrantDeactivatedDuringRequest, |
| kWPANTUNDValueMapKey_CoexMetrics_NumRxDelayedGrant, |
| kWPANTUNDValueMapKey_CoexMetrics_AvgRxRequestToGrantTime, |
| kWPANTUNDValueMapKey_CoexMetrics_NumRxGrantNone, |
| NULL |
| }; |
| |
| for (int index = 0; index < 2; index++) |
| { |
| const char **counter_names; |
| const uint8_t *struct_in = NULL; |
| unsigned int struct_len = 0; |
| spinel_size_t len; |
| |
| counter_names = (index == 0) ? tx_coex_metrics_names : rx_coex_metrics_names; |
| |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| SPINEL_DATATYPE_DATA_WLEN_S, |
| &struct_in, |
| &struct_len |
| ); |
| |
| require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
| |
| data_in += len; |
| data_len -= len; |
| |
| while (*counter_names != NULL) { |
| uint32_t counter_value; |
| |
| len = spinel_datatype_unpack( |
| struct_in, |
| struct_len, |
| SPINEL_DATATYPE_UINT32_S, |
| &counter_value |
| ); |
| |
| require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
| |
| struct_in += len; |
| struct_len -= len; |
| |
| if (!as_val_map) { |
| char c_string[200]; |
| snprintf(c_string, sizeof(c_string), "%-20s = %u", *counter_names, counter_value); |
| result_as_string.push_back(std::string(c_string)); |
| } else { |
| result_as_val_map[*counter_names] = counter_value; |
| } |
| |
| counter_names++; |
| } |
| } |
| |
| len = spinel_datatype_unpack(data_in, data_len, SPINEL_DATATYPE_BOOL_S, &stopped); |
| require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
| data_in += len; |
| data_len -= len; |
| |
| len = spinel_datatype_unpack(data_in, data_len, SPINEL_DATATYPE_UINT32_S, &num_grant_glitch); |
| require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
| data_in += len; |
| data_len -= len; |
| |
| if (!as_val_map) { |
| char c_string[200]; |
| snprintf(c_string, sizeof(c_string), "%-20s = %u", kWPANTUNDValueMapKey_CoexMetrics_Stopped, stopped); |
| result_as_string.push_back(std::string(c_string)); |
| |
| snprintf(c_string, sizeof(c_string), "%-20s = %u", kWPANTUNDValueMapKey_CoexMetrics_NumGrantGlitch, num_grant_glitch); |
| result_as_string.push_back(std::string(c_string)); |
| } else { |
| result_as_val_map[kWPANTUNDValueMapKey_CoexMetrics_Stopped] = stopped; |
| result_as_val_map[kWPANTUNDValueMapKey_CoexMetrics_NumGrantGlitch] = num_grant_glitch; |
| } |
| |
| if (as_val_map) { |
| value = result_as_val_map; |
| } else { |
| value = result_as_string; |
| } |
| |
| bail: |
| return ret; |
| } |
| |
| |
| static int |
| unpack_mcu_power_state(const uint8_t *data_in, spinel_size_t data_len, boost::any& value) |
| { |
| spinel_ssize_t len; |
| uint8_t power_state; |
| int ret = kWPANTUNDStatus_Ok; |
| |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| SPINEL_DATATYPE_UINT8_S, |
| &power_state |
| ); |
| |
| require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
| |
| switch (power_state) |
| { |
| case SPINEL_MCU_POWER_STATE_ON: |
| value = std::string(kWPANTUNDNCPMCUPowerState_On); |
| break; |
| |
| case SPINEL_MCU_POWER_STATE_LOW_POWER: |
| value = std::string(kWPANTUNDNCPMCUPowerState_LowPower); |
| break; |
| |
| case SPINEL_MCU_POWER_STATE_OFF: |
| value = std::string(kWPANTUNDNCPMCUPowerState_Off); |
| break; |
| |
| default: |
| value = std::string("unknown"); |
| break; |
| } |
| |
| bail: |
| return ret; |
| } |
| |
| static int |
| unpack_parent_info(const uint8_t *data_in, spinel_size_t data_len, boost::any& value, bool as_val_map) |
| { |
| std::string result_as_string; |
| ValueMap result_as_val_map; |
| int ret = kWPANTUNDStatus_Ok; |
| spinel_ssize_t len; |
| const spinel_eui64_t *eui64 = NULL; |
| uint16_t rloc16; |
| uint32_t age; |
| int8_t average_rssi; |
| int8_t last_rssi; |
| uint8_t lqin; |
| uint8_t lqout; |
| |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| ( |
| SPINEL_DATATYPE_EUI64_S // EUI64 Address |
| SPINEL_DATATYPE_UINT16_S // Rloc16 |
| SPINEL_DATATYPE_UINT32_S // Age |
| SPINEL_DATATYPE_INT8_S // Average RSSI |
| SPINEL_DATATYPE_INT8_S // Last RSSI |
| SPINEL_DATATYPE_UINT8_S // LinkQuality In |
| SPINEL_DATATYPE_UINT8_S // LinkQuality Out |
| ), |
| &eui64, |
| &rloc16, |
| &age, |
| &average_rssi, |
| &last_rssi, |
| &lqin, |
| &lqout |
| ); |
| |
| require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
| |
| if (!as_val_map) { |
| char c_string[200]; |
| |
| snprintf(c_string, sizeof(c_string), |
| "%02X%02X%02X%02X%02X%02X%02X%02X, " |
| "RLOC16:%04x, " |
| "Age:%u, " |
| "AveRssi:%d, " |
| "LastRssi:%d, " |
| "LQIn:%d, " |
| "LQOut:%d", |
| eui64->bytes[0], eui64->bytes[1], eui64->bytes[2], eui64->bytes[3], |
| eui64->bytes[4], eui64->bytes[5], eui64->bytes[6], eui64->bytes[7], |
| rloc16, |
| age, |
| average_rssi, |
| last_rssi, |
| lqin, |
| lqout |
| ); |
| |
| value = std::string(c_string); |
| |
| } else { |
| ValueMap map; |
| uint64_t ext_addr; |
| |
| ext_addr = (uint64_t) eui64->bytes[7]; |
| ext_addr |= (uint64_t) eui64->bytes[6] << 8; |
| ext_addr |= (uint64_t) eui64->bytes[5] << 16; |
| ext_addr |= (uint64_t) eui64->bytes[4] << 24; |
| ext_addr |= (uint64_t) eui64->bytes[3] << 32; |
| ext_addr |= (uint64_t) eui64->bytes[2] << 40; |
| ext_addr |= (uint64_t) eui64->bytes[1] << 48; |
| ext_addr |= (uint64_t) eui64->bytes[0] << 56; |
| |
| map[kWPANTUNDValueMapKey_NetworkTopology_ExtAddress] = boost::any(ext_addr); |
| map[kWPANTUNDValueMapKey_NetworkTopology_RLOC16] = boost::any(rloc16); |
| map[kWPANTUNDValueMapKey_NetworkTopology_Age] = boost::any(age); |
| map[kWPANTUNDValueMapKey_NetworkTopology_AverageRssi] = boost::any(average_rssi); |
| map[kWPANTUNDValueMapKey_NetworkTopology_LastRssi] = boost::any(last_rssi); |
| map[kWPANTUNDValueMapKey_NetworkTopology_LinkQualityIn] = boost::any(lqin); |
| |
| value = map; |
| } |
| |
| bail: |
| return ret; |
| } |
| |
| static const char * |
| cache_table_entry_state_to_string(uint8_t state) |
| { |
| const char *str; |
| |
| switch (state) |
| { |
| case SPINEL_ADDRESS_CACHE_ENTRY_STATE_CACHED: |
| str = kWPANTUNDCacheTableEntryState_Cached; |
| break; |
| case SPINEL_ADDRESS_CACHE_ENTRY_STATE_SNOOPED: |
| str = kWPANTUNDCacheTableEntryState_Snooped; |
| break; |
| case SPINEL_ADDRESS_CACHE_ENTRY_STATE_QUERY: |
| str = kWPANTUNDCacheTableEntryState_Query; |
| break; |
| case SPINEL_ADDRESS_CACHE_ENTRY_STATE_RETRY_QUERY: |
| str = kWPANTUNDCacheTableEntryState_RetryQuery; |
| break; |
| default: |
| str = "unknown"; |
| break; |
| } |
| |
| return str; |
| } |
| |
| static int |
| unpack_address_cache_table(const uint8_t *data_in, spinel_size_t data_len, boost::any& value, bool as_val_map) |
| { |
| std::list<std::string> result_as_string; |
| std::list<ValueMap> result_as_val_map; |
| int ret = kWPANTUNDStatus_Ok; |
| |
| while (data_len > 0) |
| { |
| spinel_ssize_t len; |
| struct in6_addr *target_address = NULL; |
| uint16_t target_rloc16; |
| uint8_t age; |
| uint8_t state; |
| bool valid_last_trans; |
| uint32_t last_trans_time; |
| struct in6_addr *ml_eid = NULL; |
| bool can_evict; |
| uint16_t timeout; |
| uint16_t retry_delay; |
| const uint8_t *cached_struct_in = NULL; |
| unsigned int cached_struct_len = 0; |
| const uint8_t *other_struct_in = NULL; |
| unsigned int other_struct_len = 0; |
| |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| SPINEL_DATATYPE_STRUCT_S( |
| SPINEL_DATATYPE_IPv6ADDR_S // Target address |
| SPINEL_DATATYPE_UINT16_S // RLOC16 |
| SPINEL_DATATYPE_UINT8_S // Age |
| SPINEL_DATATYPE_UINT8_S // State |
| SPINEL_DATATYPE_DATA_WLEN_S // Cached struct info |
| SPINEL_DATATYPE_DATA_WLEN_S // Other struct info |
| ), |
| &target_address, |
| &target_rloc16, |
| &age, |
| &state, |
| &cached_struct_in, &cached_struct_len, |
| &other_struct_in, &other_struct_len |
| ); |
| |
| require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
| |
| data_in += len; |
| data_len -= len; |
| |
| if (state == SPINEL_ADDRESS_CACHE_ENTRY_STATE_CACHED) { |
| |
| len = spinel_datatype_unpack( |
| cached_struct_in, |
| cached_struct_len, |
| ( |
| SPINEL_DATATYPE_BOOL_S // Is Last Transaction Time valid? |
| SPINEL_DATATYPE_UINT32_S // Last Transaction Time |
| SPINEL_DATATYPE_IPv6ADDR_S // Mesh-local EID |
| ), |
| &valid_last_trans, |
| &last_trans_time, |
| &ml_eid |
| ); |
| |
| require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
| |
| } else { |
| |
| len = spinel_datatype_unpack( |
| other_struct_in, |
| other_struct_len, |
| ( |
| SPINEL_DATATYPE_BOOL_S // Can evict? |
| SPINEL_DATATYPE_UINT16_S // Timeout |
| SPINEL_DATATYPE_UINT16_S // Retry delay |
| ), |
| &can_evict, |
| &timeout, |
| &retry_delay |
| ); |
| |
| require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
| } |
| |
| if (!as_val_map) { |
| char c_string[500]; |
| int index = 0; |
| |
| index += snprintf( |
| c_string + index, sizeof(c_string) - index, |
| "%s -> 0x%04x, Age:%d, State:%s", |
| in6_addr_to_string(*target_address).c_str(), |
| target_rloc16, |
| age, |
| cache_table_entry_state_to_string(state) |
| ); |
| |
| if (state == SPINEL_ADDRESS_CACHE_ENTRY_STATE_CACHED) { |
| if (valid_last_trans) { |
| index += snprintf( |
| c_string + index, sizeof(c_string) - index, |
| ", LastTrans:%u, ML-EID:%s", |
| last_trans_time, |
| in6_addr_to_string(*ml_eid).c_str() |
| ); |
| } |
| } else { |
| index += snprintf( |
| c_string + index, sizeof(c_string) - index, |
| ", CanEvict:%s, Timeout:%d, RetryDelay:%d", |
| can_evict ? "yes" : "no", |
| timeout, |
| retry_delay |
| ); |
| } |
| |
| result_as_string.push_back(std::string(c_string)); |
| |
| } else { |
| ValueMap entry; |
| |
| entry[kWPANTUNDValueMapKey_AddressCacheTable_Address] = boost::any(in6_addr_to_string(*target_address)); |
| entry[kWPANTUNDValueMapKey_AddressCacheTable_RLOC16] = boost::any(target_rloc16); |
| entry[kWPANTUNDValueMapKey_AddressCacheTable_Age] = boost::any(age); |
| entry[kWPANTUNDValueMapKey_AddressCacheTable_State] = boost::any(std::string(cache_table_entry_state_to_string(state))); |
| |
| if (state == SPINEL_ADDRESS_CACHE_ENTRY_STATE_CACHED) { |
| if (valid_last_trans) { |
| entry[kWPANTUNDValueMapKey_AddressCacheTable_LastTrans] = boost::any(last_trans_time); |
| entry[kWPANTUNDValueMapKey_AddressCacheTable_MeshLocalEID] = boost::any(in6_addr_to_string(*ml_eid)); |
| } |
| } else { |
| entry[kWPANTUNDValueMapKey_AddressCacheTable_CanEvict] = boost::any(can_evict); |
| entry[kWPANTUNDValueMapKey_AddressCacheTable_Timeout] = boost::any(timeout); |
| entry[kWPANTUNDValueMapKey_AddressCacheTable_RetryDelay] = boost::any(retry_delay); |
| } |
| |
| result_as_val_map.push_back(entry); |
| } |
| } |
| |
| if (as_val_map) { |
| value = result_as_val_map; |
| } else { |
| value = result_as_string; |
| } |
| |
| bail: |
| return ret; |
| } |
| |
| static int |
| unpack_supported_radio_links(const uint8_t *data_in, spinel_size_t data_len, boost::any &value) |
| { |
| std::list<std::string> result; |
| int ret = kWPANTUNDStatus_Ok; |
| |
| while (data_len > 0) { |
| spinel_ssize_t len; |
| unsigned int value; |
| |
| len = spinel_packed_uint_decode(data_in, data_len, &value); |
| require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
| |
| data_in += len; |
| data_len -= len; |
| |
| result.push_back(std::string(spinel_radio_link_to_cstr(value))); |
| } |
| |
| value = result; |
| |
| bail: |
| return ret; |
| } |
| static int |
| unpack_neighbor_table_multi_radio_info(const uint8_t *data_in, spinel_size_t data_len, boost::any &value) |
| { |
| int ret = kWPANTUNDStatus_Ok; |
| std::list<std::string> result; |
| char c_string[200]; |
| int index; |
| |
| while (data_len > 0) { |
| spinel_ssize_t len = 0; |
| const uint8_t *entry_data; |
| spinel_size_t entry_len; |
| const spinel_eui64_t *eui64 = NULL; |
| uint16_t rloc16; |
| bool first_radio; |
| |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| SPINEL_DATATYPE_DATA_WLEN_S, |
| &entry_data, |
| &entry_len |
| ); |
| |
| require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
| |
| data_in += len; |
| data_len -= len; |
| |
| // Parse the entry_data (which contains info about a neighbor) |
| |
| len = spinel_datatype_unpack( |
| entry_data, |
| entry_len, |
| ( |
| SPINEL_DATATYPE_EUI64_S // EUI64 Address |
| SPINEL_DATATYPE_UINT16_S // Rloc16 |
| ), |
| &eui64, |
| &rloc16 |
| ); |
| |
| require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
| |
| index = 0; |
| |
| index += snprintf(c_string + index, sizeof(c_string) - index, |
| "%02X%02X%02X%02X%02X%02X%02X%02X, RLOC16:%04x, Radios:[", |
| eui64->bytes[0], eui64->bytes[1], eui64->bytes[2], eui64->bytes[3], |
| eui64->bytes[4], eui64->bytes[5], eui64->bytes[6], eui64->bytes[7], |
| rloc16 |
| ); |
| |
| require_action(index < sizeof(c_string), bail, ret = kWPANTUNDStatus_Failure); |
| |
| entry_data += len; |
| entry_len -= len; |
| |
| first_radio = true; |
| |
| while (entry_len > 0) { |
| const uint8_t *struct_data; |
| spinel_size_t struct_len; |
| unsigned int radio; |
| uint8_t preference; |
| |
| len = spinel_datatype_unpack( |
| entry_data, |
| entry_len, |
| SPINEL_DATATYPE_DATA_WLEN_S, |
| &struct_data, |
| &struct_len |
| ); |
| |
| require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
| |
| entry_data += len; |
| entry_len -= len; |
| |
| // Parse struct_data (contains info about a supported radio link type) |
| |
| len = spinel_datatype_unpack( |
| struct_data, |
| struct_len, |
| ( |
| SPINEL_DATATYPE_UINT_PACKED_S // Radio link |
| SPINEL_DATATYPE_UINT8_S // Preference |
| ), |
| &radio, |
| &preference |
| ); |
| |
| require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
| |
| struct_data += len; |
| struct_len -= len; |
| |
| index += snprintf(c_string + index, sizeof(c_string) - index, |
| "%s%s(%d)", |
| first_radio ? "" : ", ", |
| spinel_radio_link_to_cstr(radio), |
| preference |
| ); |
| |
| require_action(index < sizeof(c_string), bail, ret = kWPANTUNDStatus_Failure); |
| first_radio = false; |
| } |
| |
| index += snprintf(c_string + index, sizeof(c_string) - index, "]"); |
| require_action(index < sizeof(c_string), bail, ret = kWPANTUNDStatus_Failure); |
| |
| result.push_back(std::string(c_string)); |
| } |
| |
| value = result; |
| |
| bail: |
| return ret; |
| } |
| |
| static int |
| unpack_mesh_local_prefix(const uint8_t *data_in, spinel_size_t data_len, boost::any &value) |
| { |
| spinel_ssize_t len; |
| struct in6_addr *addr; |
| uint8_t prefix_len; |
| int ret = kWPANTUNDStatus_Failure; |
| |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| ( |
| SPINEL_DATATYPE_IPv6ADDR_S |
| SPINEL_DATATYPE_UINT8_S |
| ), |
| &addr, |
| &prefix_len |
| ); |
| |
| if (len > 0) |
| { |
| char str[10]; |
| snprintf(str, sizeof(str), "/%d", prefix_len); |
| |
| value = boost::any(in6_addr_to_string(*addr) + std::string(str)); |
| ret = kWPANTUNDStatus_Ok; |
| } |
| |
| return ret; |
| } |
| |
| static int |
| unpack_dataset(const uint8_t *data_in, spinel_size_t data_len, boost::any &value, bool as_val_map) |
| { |
| int ret = kWPANTUNDStatus_Ok; |
| ThreadDataset dataset; |
| ValueMap map; |
| std::list<std::string> list; |
| |
| ret = dataset.set_from_spinel_frame(data_in, data_len); |
| require_noerr(ret, bail); |
| |
| if (as_val_map) { |
| dataset.convert_to_valuemap(map); |
| value = map; |
| } else { |
| dataset.convert_to_string_list(list); |
| value = list; |
| } |
| |
| bail: |
| return ret; |
| } |
| |
| static int |
| unpack_server_leader_services_as_any(const uint8_t *data_in, spinel_size_t data_len, boost::any& value, bool as_val_map) |
| { |
| int ret = kWPANTUNDStatus_Ok; |
| spinel_ssize_t len; |
| uint8_t service_id; |
| uint32_t enterprise_number; |
| const uint8_t *service_data; |
| spinel_size_t service_data_len; |
| bool stable; |
| const uint8_t *server_data; |
| spinel_size_t server_data_len; |
| uint16_t rloc16; |
| int num_service = 0; |
| char c_string[500]; |
| |
| std::list<ValueMap> result_as_val_map_list; |
| std::list<std::string> result_as_string_list; |
| |
| while (data_len > 0) { |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| SPINEL_DATATYPE_STRUCT_S( |
| SPINEL_DATATYPE_UINT8_S // Service ID |
| SPINEL_DATATYPE_UINT32_S // Enterprise Number |
| SPINEL_DATATYPE_DATA_WLEN_S // Service Data |
| SPINEL_DATATYPE_BOOL_S // stable |
| SPINEL_DATATYPE_DATA_WLEN_S // Server Data |
| SPINEL_DATATYPE_UINT16_S // RLOC |
| ), |
| &service_id, |
| &enterprise_number, |
| &service_data, |
| &service_data_len, |
| &stable, |
| &server_data, |
| &server_data_len, |
| &rloc16 |
| ); |
| |
| if (len <= 0) { |
| break; |
| } |
| |
| if (as_val_map) { |
| ValueMap result_as_val_map; |
| result_as_val_map[kWPANTUNDValueMapKey_Service_ServiceId] = service_id; |
| result_as_val_map[kWPANTUNDValueMapKey_Service_EnterpriseNumber] = enterprise_number; |
| result_as_val_map[kWPANTUNDValueMapKey_Service_ServiceData] = Data(service_data, service_data_len); |
| result_as_val_map[kWPANTUNDValueMapKey_Service_Stable] = stable; |
| result_as_val_map[kWPANTUNDValueMapKey_Service_ServerData] = Data(server_data, server_data_len); |
| result_as_val_map[kWPANTUNDValueMapKey_Service_RLOC16] = rloc16; |
| result_as_val_map_list.push_back(result_as_val_map); |
| } else { |
| snprintf(c_string, sizeof(c_string), "ServiceId:%01x, EnterpriseNumber:%u, Stable:%d, RLOC16:%04x", service_id, enterprise_number, stable, rloc16); |
| result_as_string_list.push_back(std::string(c_string)); |
| } |
| |
| num_service++; |
| |
| data_in += len; |
| data_len -= len; |
| } |
| |
| if (as_val_map) { |
| value = result_as_val_map_list; |
| } else { |
| value = result_as_string_list; |
| } |
| |
| return ret; |
| } |
| |
| static int |
| unpack_mcu_dua_interface_identifier(const uint8_t *data_in, spinel_size_t data_len, boost::any& value) |
| { |
| std::string buff; |
| int ret = kWPANTUNDStatus_Ok; |
| |
| if (data_len == 0) |
| { |
| // When data_len == 0 an empty string will be returned. |
| value = buff; |
| } |
| else if (data_len == 8) |
| { |
| buff = std::string(data_len*2,0); |
| buff.resize(2 * data_len + 1); |
| |
| encode_data_into_string(data_in, data_len, &buff[0], buff.capacity(), 0); |
| value = buff; |
| } |
| else |
| { |
| ret = kWPANTUNDStatus_InvalidArgument; |
| } |
| |
| return ret; |
| } |
| |
| static int |
| unpack_meshcop_joiner_state(const uint8_t *data_in, spinel_size_t data_len, boost::any &value) |
| { |
| spinel_ssize_t len; |
| uint8_t joiner_state; |
| int ret = kWPANTUNDStatus_Ok; |
| |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| SPINEL_DATATYPE_UINT8_S, |
| &joiner_state |
| ); |
| |
| require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
| |
| switch (joiner_state) { |
| case SPINEL_MESHCOP_JOINER_STATE_IDLE: |
| value = std::string(kWPANTUNDThreadJoinerState_Idle); |
| break; |
| |
| case SPINEL_MESHCOP_JOINER_STATE_DISCOVER: |
| value = std::string(kWPANTUNDThreadJoinerState_Discover); |
| break; |
| |
| case SPINEL_MESHCOP_JOINER_STATE_CONNECTING: |
| value = std::string(kWPANTUNDThreadJoinerState_Connecting); |
| break; |
| |
| case SPINEL_MESHCOP_JOINER_STATE_CONNECTED: |
| value = std::string(kWPANTUNDThreadJoinerState_Connected); |
| break; |
| |
| case SPINEL_MESHCOP_JOINER_STATE_ENTRUST: |
| value = std::string(kWPANTUNDThreadJoinerState_Entrust); |
| break; |
| |
| case SPINEL_MESHCOP_JOINER_STATE_JOINED: |
| value = std::string(kWPANTUNDThreadJoinerState_Joined); |
| break; |
| |
| default: |
| value = std::string("unknown"); |
| break; |
| } |
| |
| bail: |
| return ret; |
| } |
| |
| static int |
| unpack_meshcop_joiner_discerner_value(const uint8_t *data_in, spinel_size_t data_len, boost::any &value) |
| { |
| spinel_ssize_t len; |
| uint8_t discerner_len; |
| uint64_t discerner_value = 0; |
| int ret = kWPANTUNDStatus_Ok; |
| |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| SPINEL_DATATYPE_UINT8_S, |
| &discerner_len |
| ); |
| |
| require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
| |
| if (discerner_len != 0) { |
| data_in += len; |
| data_len -= len; |
| |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| SPINEL_DATATYPE_UINT64_S, |
| &discerner_value |
| ); |
| } |
| |
| value = discerner_value; |
| |
| bail: |
| return ret; |
| } |
| |
| static int |
| unpack_thread_network_time_spinel(const uint8_t *data_in, spinel_size_t data_len, uint64_t &time, int8_t &time_sync_status) |
| { |
| return spinel_datatype_unpack( |
| data_in, |
| data_len, |
| ( |
| SPINEL_DATATYPE_UINT64_S // time |
| SPINEL_DATATYPE_INT8_S // time sync status |
| ), |
| &time, |
| &time_sync_status |
| ); |
| } |
| |
| static int |
| unpack_thread_network_time_as_string(const uint8_t *data_in, spinel_size_t data_len, std::string &result) |
| { |
| spinel_ssize_t len; |
| uint64_t time; |
| int8_t time_sync_status; |
| char c_string[500]; |
| int ret = kWPANTUNDStatus_Failure; |
| |
| len = unpack_thread_network_time_spinel(data_in, data_len, time, time_sync_status); |
| |
| if (len > 0) |
| { |
| ret = kWPANTUNDStatus_Ok; |
| snprintf(c_string, sizeof(c_string), "ThreadNetworkTime: %" PRIu64 ", TimeSyncStatus:%d", time, time_sync_status); |
| result.assign(c_string); |
| } |
| |
| return ret; |
| } |
| |
| static int |
| unpack_thread_network_time_as_valmap(const uint8_t *data_in, spinel_size_t data_len, ValueMap &result) |
| { |
| spinel_ssize_t len; |
| ValueMap entry; |
| uint64_t time; |
| int8_t time_sync_status; |
| int ret = kWPANTUNDStatus_Failure; |
| |
| len = unpack_thread_network_time_spinel(data_in, data_len, time, time_sync_status); |
| |
| if (len > 0) |
| { |
| ret = kWPANTUNDStatus_Ok; |
| result.clear(); |
| result[kWPANTUNDValueMapKey_TimeSync_Time] = time; |
| result[kWPANTUNDValueMapKey_TimeSync_Status] = time_sync_status; |
| #if APPEND_NETWORK_TIME_RECEIVED_MONOTONIC_TIMESTAMP |
| result[kWPANTUNDValueMapKey_TimeSync_ReceivedMonoTimeUs] = time_get_monotonic_us(); |
| #endif // APPEND_NETWORK_TIME_RECEIVED_MONOTONIC_TIMESTAMP |
| } |
| |
| return ret; |
| } |
| |
| static int |
| unpack_thread_network_time_as_any(const uint8_t *data_in, spinel_size_t data_len, boost::any& value, bool as_val_map) |
| { |
| ValueMap result_as_val_map; |
| std::list<ValueMap> result_as_val_map_list; |
| std::string result_as_string; |
| std::list<std::string> result_as_string_list; |
| int ret; |
| |
| if (as_val_map) |
| { |
| ret = unpack_thread_network_time_as_valmap(data_in, data_len, result_as_val_map); |
| |
| if (ret == kWPANTUNDStatus_Ok) |
| { |
| result_as_val_map_list.push_back(result_as_val_map); |
| value = result_as_val_map_list; |
| } |
| } |
| else |
| { |
| ret = unpack_thread_network_time_as_string(data_in, data_len, result_as_string); |
| |
| if (ret == kWPANTUNDStatus_Ok) |
| { |
| result_as_string_list.push_back(result_as_string); |
| value = result_as_string_list; |
| } |
| } |
| |
| return ret; |
| } |
| |
| static int |
| unpack_link_metrics_as_val_map(const uint8_t *data_in, spinel_size_t data_len, ValueMap &val_map) |
| { |
| spinel_ssize_t len; |
| uint8_t metric_type; |
| uint8_t *metric_ptr = NULL; |
| uint32_t metric_len = 0; |
| int ret = kWPANTUNDStatus_Failure; |
| |
| while (data_len > 0) { |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| ( |
| SPINEL_DATATYPE_STRUCT_S( |
| SPINEL_DATATYPE_UINT8_S |
| SPINEL_DATATYPE_DATA_S |
| ) |
| ), |
| &metric_type, |
| &metric_ptr, |
| &metric_len |
| ); |
| |
| require(len >= 0, bail); |
| data_in += len; |
| data_len -= len; |
| |
| switch (metric_type) { |
| case SPINEL_THREAD_LINK_METRIC_PDU_COUNT: |
| val_map[kWPANTUNDValueMapKey_LinkMetrics_PDUCount] = *reinterpret_cast<uint32_t*>(metric_ptr); |
| break; |
| case SPINEL_THREAD_LINK_METRIC_LQI: |
| val_map[kWPANTUNDValueMapKey_LinkMetrics_LQI] = static_cast<uint32_t>(*reinterpret_cast<uint8_t*>(metric_ptr)); |
| break; |
| case SPINEL_THREAD_LINK_METRIC_LINK_MARGIN: |
| val_map[kWPANTUNDValueMapKey_LinkMetrics_LinkMargin] = static_cast<uint32_t>(*reinterpret_cast<uint8_t*>(metric_ptr)); |
| break; |
| case SPINEL_THREAD_LINK_METRIC_RSSI: |
| val_map[kWPANTUNDValueMapKey_LinkMetrics_RSSI] = *reinterpret_cast<int8_t*>(metric_ptr); |
| break; |
| default: |
| goto bail; |
| } |
| } |
| |
| ret = kWPANTUNDStatus_Ok; |
| |
| bail: |
| return ret; |
| } |
| |
| static int |
| unpack_backbone_router_primary(const uint8_t *data_in, spinel_size_t data_len, boost::any& value) |
| { |
| spinel_ssize_t len; |
| char c_string[300]; |
| int ret = kWPANTUNDStatus_Ok; |
| uint16_t server = 0; |
| uint16_t delay = 0; |
| uint32_t timeout = 0; |
| uint8_t seqno = 0; |
| |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| ( |
| SPINEL_DATATYPE_UINT16_S |
| SPINEL_DATATYPE_UINT16_S |
| SPINEL_DATATYPE_UINT32_S |
| SPINEL_DATATYPE_UINT8_S |
| ), |
| &server, |
| &delay, |
| &timeout, |
| &seqno |
| ); |
| |
| if (len > 0) { |
| snprintf(c_string, sizeof(c_string), "server16 = 0x%04X, seqno = %hu, delay = %hu secs, timeout = %u secs", |
| server, (uint16_t)seqno, delay, timeout); |
| |
| value = std::string(c_string); |
| } else { |
| ret = kWPANTUNDStatus_Failure; |
| } |
| |
| return ret; |
| } |
| |
| static int |
| unpack_backbone_router_config(const uint8_t *data_in, spinel_size_t data_len, boost::any& value) |
| { |
| spinel_ssize_t len; |
| char c_string[300]; |
| int ret = kWPANTUNDStatus_Ok; |
| uint16_t delay = 0; |
| uint32_t timeout = 0; |
| uint8_t seqno = 0; |
| |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| ( |
| SPINEL_DATATYPE_UINT16_S |
| SPINEL_DATATYPE_UINT32_S |
| SPINEL_DATATYPE_UINT8_S |
| ), |
| &delay, |
| &timeout, |
| &seqno |
| ); |
| |
| if (len > 0) { |
| snprintf(c_string, sizeof(c_string), "seqno = %hu, delay = %hu secs, timeout = %u secs", |
| (uint16_t)seqno, delay, timeout); |
| |
| value = std::string(c_string); |
| } else { |
| ret = kWPANTUNDStatus_Failure; |
| } |
| |
| return ret; |
| } |
| |
| static int |
| unpack_backbone_router_state(const uint8_t *data_in, spinel_size_t data_len, boost::any& value) |
| { |
| spinel_ssize_t len; |
| uint8_t state; |
| int ret = kWPANTUNDStatus_Ok; |
| |
| len = spinel_datatype_unpack( |
| data_in, |
| data_len, |
| SPINEL_DATATYPE_UINT8_S, |
| &state |
| ); |
| |
| if (len > 0) { |
| switch (state) { |
| case SPINEL_THREAD_BACKBONE_ROUTER_STATE_DISABLED: |
| value = std::string(kWPANTUNDThreadBackboneRouterState_Disabled); |
| break; |
| case SPINEL_THREAD_BACKBONE_ROUTER_STATE_SECONDARY: |
| value = std::string(kWPANTUNDThreadBackboneRouterState_Secondary); |
| break; |
| case SPINEL_THREAD_BACKBONE_ROUTER_STATE_PRIMARY: |
| value = std::string(kWPANTUNDThreadBackboneRouterState_Primary); |
| break; |
| default: |
| ret = kWPANTUNDStatus_Failure; |
| break; |
| } |
| } else { |
| ret = kWPANTUNDStatus_Failure; |
| } |
| |
| return ret; |
| } |
| |
| void |
| SpinelNCPInstance::get_dataset_command_help(std::list<std::string> &list) |
| { |
| list.clear(); |
| list.push_back("List of valid commands:"); |
| list.push_back(" - `" kWPANTUNDDatasetCommand_Erase "`: Erase the local Dataset (all fields are un-set)"); |
| list.push_back(" - `" kWPANTUNDDatasetCommand_GetActive "`: Get the NCP's Active Operational Dataset and populate the local Dataset from it"); |
| list.push_back(" - `" kWPANTUNDDatasetCommand_SetActive "`: Set the NCP's Active Operational Dataset from the current local Dataset"); |
| list.push_back(" - `" kWPANTUNDDatasetCommand_SendMgmtGetActive "`: Send MGMT_GET_ACTIVE meshcop command requesting TLVs in current local Dataset"); |
| list.push_back(" - `" kWPANTUNDDatasetCommand_SendMgmtSetActive "`: Send MGMT_SET_ACTIVE meshcop command along with the current local Dataset"); |
| list.push_back(" - `" kWPANTUNDDatasetCommand_GetPending "`: Get the NCP's Pending Operational Dataset and populate the local DataSet from it"); |
| list.push_back(" - `" kWPANTUNDDatasetCommand_SetPending "`: Set the NCP's Pending Operational Dataset from the current local Dataset"); |
| list.push_back(" - `" kWPANTUNDDatasetCommand_SendMgmtGetPending "`: Send MGMT_GET_PENDING meshcop command requesting TLVs in the current local Dataset"); |
| list.push_back(" - `" kWPANTUNDDatasetCommand_SendMgmtSetPending "`: Send MGMT_SET_PENDING meshcop command along with the current local Dataset"); |
| } |
| |
| int |
| SpinelNCPInstance::unpack_and_set_local_dataset(const uint8_t *data_in, spinel_size_t data_len) |
| { |
| return mLocalDataset.set_from_spinel_frame(data_in, data_len); |
| } |
| |
| void |
| SpinelNCPInstance::perform_dataset_command(const std::string &command, CallbackWithStatus cb) |
| { |
| if (strcaseequal(command.c_str(), kWPANTUNDDatasetCommand_Erase)) { |
| mLocalDataset.clear(); |
| cb(kWPANTUNDStatus_Ok); |
| |
| } else if (strcaseequal(command.c_str(), kWPANTUNDDatasetCommand_GetActive)) { |
| get_spinel_prop_with_unpacker( |
| boost::bind(cb, _1), |
| SPINEL_PROP_THREAD_ACTIVE_DATASET, |
| boost::bind(&SpinelNCPInstance::unpack_and_set_local_dataset, this, _1, _2)); |
| |
| } else if (strcaseequal(command.c_str(), kWPANTUNDDatasetCommand_SetActive)) { |
| Data frame; |
| mLocalDataset.convert_to_spinel_frame(frame); |
| set_spinel_prop(frame, cb, SPINEL_PROP_THREAD_ACTIVE_DATASET, SPINEL_DATATYPE_DATA_C); |
| |
| } else if (strcaseequal(command.c_str(), kWPANTUNDDatasetCommand_SendMgmtGetActive)) { |
| Data frame; |
| mLocalDataset.convert_to_spinel_frame(frame, /* include_values */ false); |
| set_spinel_prop(frame, cb, SPINEL_PROP_THREAD_MGMT_GET_ACTIVE_DATASET, SPINEL_DATATYPE_DATA_C); |
| |
| } else if (strcaseequal(command.c_str(), kWPANTUNDDatasetCommand_SendMgmtSetActive)) { |
| Data frame; |
| mLocalDataset.convert_to_spinel_frame(frame); |
| set_spinel_prop(frame, cb, SPINEL_PROP_THREAD_MGMT_SET_ACTIVE_DATASET, SPINEL_DATATYPE_DATA_C); |
| |
| } else if (strcaseequal(command.c_str(), kWPANTUNDDatasetCommand_GetPending)) { |
| get_spinel_prop_with_unpacker( |
| boost::bind(cb, _1), |
| SPINEL_PROP_THREAD_PENDING_DATASET, |
| boost::bind(&SpinelNCPInstance::unpack_and_set_local_dataset, this, _1, _2)); |
| |
| } else if (strcaseequal(command.c_str(), kWPANTUNDDatasetCommand_SetPending)) { |
| Data frame; |
| mLocalDataset.convert_to_spinel_frame(frame); |
| set_spinel_prop(frame, cb, SPINEL_PROP_THREAD_PENDING_DATASET, SPINEL_DATATYPE_DATA_C); |
| |
| } else if (strcaseequal(command.c_str(), kWPANTUNDDatasetCommand_SendMgmtGetPending)) { |
| Data frame; |
| mLocalDataset.convert_to_spinel_frame(frame, /* include_values */ false); |
| set_spinel_prop(frame, cb, SPINEL_PROP_THREAD_MGMT_GET_PENDING_DATASET, SPINEL_DATATYPE_DATA_C); |
| |
| } else if (strcaseequal(command.c_str(), kWPANTUNDDatasetCommand_SendMgmtSetPending)) { |
| Data frame; |
| mLocalDataset.convert_to_spinel_frame(frame); |
| set_spinel_prop(frame, cb, SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET, SPINEL_DATATYPE_DATA_C); |
| |
| } else { |
| cb(kWPANTUNDStatus_InvalidArgument); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::update_node_type(NodeType new_node_type) |
| { |
| if (mNodeType != new_node_type) { |
| syslog( |
| LOG_NOTICE, |
| "Node type change: \"%s\" -> \"%s\"", |
| node_type_to_string(mNodeType).c_str(), |
| node_type_to_string(new_node_type).c_str() |
| ); |
| |
| mNodeType = new_node_type; |
| signal_property_changed(kWPANTUNDProperty_NetworkNodeType, node_type_to_string(mNodeType)); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::update_link_local_address(struct in6_addr *addr) |
| { |
| if (NULL != addr |
| && (0 != memcmp(mNCPLinkLocalAddress.s6_addr, addr->s6_addr, sizeof(mNCPLinkLocalAddress))) |
| ) { |
| memcpy((void*)mNCPLinkLocalAddress.s6_addr, (void*)addr->s6_addr, sizeof(mNCPLinkLocalAddress)); |
| signal_property_changed(kWPANTUNDProperty_IPv6LinkLocalAddress, in6_addr_to_string(*addr)); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::update_mesh_local_address(struct in6_addr *addr) |
| { |
| if (addr |
| && buffer_is_nonzero(addr->s6_addr, 8) |
| && (0 != memcmp(mNCPMeshLocalAddress.s6_addr, addr->s6_addr, sizeof(mNCPMeshLocalAddress))) |
| ) { |
| memcpy((void*)mNCPMeshLocalAddress.s6_addr, (void*)addr->s6_addr, sizeof(mNCPMeshLocalAddress)); |
| signal_property_changed(kWPANTUNDProperty_IPv6MeshLocalAddress, in6_addr_to_string(*addr)); |
| |
| // If mesh-local prefix gets changed we go through the |
| // list of IPv6 addresses and filter/remove any previously |
| // added RLOC addresses. |
| filter_addresses(); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::update_mesh_local_prefix(struct in6_addr *addr) |
| { |
| if (addr |
| && buffer_is_nonzero(addr->s6_addr, 8) |
| && (0 != memcmp(mNCPV6Prefix, addr, sizeof(mNCPV6Prefix))) |
| ) { |
| memcpy((void*)mNCPV6Prefix, (void*)addr, sizeof(mNCPV6Prefix)); |
| struct in6_addr prefix_addr (mNCPMeshLocalAddress); |
| // Zero out the lower 64 bits. |
| memset(prefix_addr.s6_addr+8, 0, 8); |
| signal_property_changed(kWPANTUNDProperty_IPv6MeshLocalPrefix, in6_addr_to_string(prefix_addr) + "/64"); |
| |
| // If mesh-local prefix gets changed we go through the |
| // list of IPv6 addresses and filter/remove any previously |
| // added RLOC addresses. |
| filter_addresses(); |
| } |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // Property Get Handlers |
| |
| void |
| SpinelNCPInstance::get_spinel_prop(CallbackWithStatusArg1 cb, spinel_prop_key_t prop_key, |
| const std::string &reply_format) |
| { |
| start_new_task(SpinelNCPTaskSendCommand::Factory(this) |
| .set_callback(cb) |
| .add_command(SpinelPackData(SPINEL_FRAME_PACK_CMD_PROP_VALUE_GET, prop_key)) |
| .set_reply_format(reply_format) |
| .finish() |
| ); |
| } |
| |
| void |
| SpinelNCPInstance::get_spinel_prop_with_unpacker(CallbackWithStatusArg1 cb, spinel_prop_key_t prop_key, |
| ReplyUnpacker unpacker) |
| { |
| start_new_task(SpinelNCPTaskSendCommand::Factory(this) |
| .set_callback(cb) |
| .add_command(SpinelPackData(SPINEL_FRAME_PACK_CMD_PROP_VALUE_GET, prop_key)) |
| .set_reply_unpacker(unpacker) |
| .finish() |
| ); |
| } |
| |
| void SpinelNCPInstance::check_capability_prop_get(CallbackWithStatusArg1 cb, const std::string &prop_name, |
| unsigned int capability, PropGetHandler handler) |
| { |
| if (mCapabilities.count(capability)) { |
| handler(cb, prop_name); |
| } else { |
| char error_msg[200]; |
| snprintf(error_msg, sizeof(error_msg), |
| "Capability %s (required for \"%s\") is not supported by NCP", spinel_capability_to_cstr(capability), |
| prop_name.c_str()); |
| cb(kWPANTUNDStatus_FeatureNotSupported, std::string(error_msg)); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::register_get_handler(const char *prop_name, PropGetHandler handler) |
| { |
| NCPInstanceBase::register_prop_get_handler(prop_name, handler); |
| } |
| |
| void |
| SpinelNCPInstance::register_get_handler_capability(const char *prop_name, unsigned int capability, |
| PropGetHandler handler) |
| { |
| register_get_handler( |
| prop_name, |
| boost::bind(&SpinelNCPInstance::check_capability_prop_get, this, _1, _2, capability, handler)); |
| } |
| |
| void |
| SpinelNCPInstance::register_get_handler_spinel_simple(const char *prop_name, spinel_prop_key_t prop_key, |
| const char *reply_format) |
| { |
| register_get_handler( |
| prop_name, |
| boost::bind(&SpinelNCPInstance::get_spinel_prop, this, _1, prop_key, std::string(reply_format))); |
| } |
| |
| void |
| SpinelNCPInstance::register_get_handler_spinel_unpacker(const char *prop_name, spinel_prop_key_t prop_key, |
| ReplyUnpacker unpacker) |
| { |
| register_get_handler( |
| prop_name, |
| boost::bind(&SpinelNCPInstance::get_spinel_prop_with_unpacker, this, _1, prop_key, unpacker)); |
| } |
| |
| void |
| SpinelNCPInstance::register_get_handler_capability_spinel_simple(const char *prop_name, unsigned int capability, |
| spinel_prop_key_t prop_key, const char *reply_format) |
| { |
| register_get_handler_capability( |
| prop_name, |
| capability, |
| boost::bind(&SpinelNCPInstance::get_spinel_prop, this, _1, prop_key, std::string(reply_format))); |
| } |
| |
| void |
| SpinelNCPInstance::register_get_handler_capability_spinel_unpacker(const char *prop_name, unsigned int capability, |
| spinel_prop_key_t prop_key, ReplyUnpacker unpacker) |
| { |
| register_get_handler_capability( |
| prop_name, |
| capability, |
| boost::bind(&SpinelNCPInstance::get_spinel_prop_with_unpacker, this, _1, prop_key, unpacker)); |
| } |
| |
| void |
| SpinelNCPInstance::regsiter_all_get_handlers(void) |
| { |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // Properties associated with a spinel property with simple packing format |
| |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_NCPCCAThreshold, |
| SPINEL_PROP_PHY_CCA_THRESHOLD, SPINEL_DATATYPE_INT8_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_NCPTXPower, |
| SPINEL_PROP_PHY_TX_POWER, SPINEL_DATATYPE_INT8_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_NCPFrequency, |
| SPINEL_PROP_PHY_FREQ, SPINEL_DATATYPE_INT32_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_NetworkKey, |
| SPINEL_PROP_NET_MASTER_KEY, SPINEL_DATATYPE_DATA_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_NetworkPSKc, |
| SPINEL_PROP_NET_PSKC, SPINEL_DATATYPE_DATA_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_NCPExtendedAddress, |
| SPINEL_PROP_MAC_EXTENDED_ADDR, SPINEL_DATATYPE_EUI64_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_NetworkKeyIndex, |
| SPINEL_PROP_NET_KEY_SEQUENCE_COUNTER, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_NetworkKeySwitchGuardTime, |
| SPINEL_PROP_NET_KEY_SWITCH_GUARDTIME, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_NetworkRole, |
| SPINEL_PROP_NET_ROLE, SPINEL_DATATYPE_UINT8_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_NetworkPartitionId, |
| SPINEL_PROP_NET_PARTITION_ID, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_ThreadRouterUpgradeThreshold, |
| SPINEL_PROP_THREAD_ROUTER_UPGRADE_THRESHOLD, SPINEL_DATATYPE_UINT8_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_ThreadRouterDowngradeThreshold, |
| SPINEL_PROP_THREAD_ROUTER_DOWNGRADE_THRESHOLD, SPINEL_DATATYPE_UINT8_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_NCPRSSI, |
| SPINEL_PROP_PHY_RSSI, SPINEL_DATATYPE_INT8_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_ThreadRLOC16, |
| SPINEL_PROP_THREAD_RLOC16, SPINEL_DATATYPE_UINT16_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_ThreadRouterSelectionJitter, |
| SPINEL_PROP_THREAD_ROUTER_SELECTION_JITTER, SPINEL_DATATYPE_UINT8_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_ThreadLeaderAddress, |
| SPINEL_PROP_THREAD_LEADER_ADDR, SPINEL_DATATYPE_IPv6ADDR_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_ThreadLeaderRouterID, |
| SPINEL_PROP_THREAD_LEADER_RID, SPINEL_DATATYPE_UINT8_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_ThreadLeaderWeight, |
| SPINEL_PROP_THREAD_LEADER_WEIGHT, SPINEL_DATATYPE_UINT8_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_ThreadLeaderLocalWeight, |
| SPINEL_PROP_THREAD_LOCAL_LEADER_WEIGHT, SPINEL_DATATYPE_UINT8_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_ThreadNetworkData, |
| SPINEL_PROP_THREAD_NETWORK_DATA, SPINEL_DATATYPE_DATA_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_ThreadNetworkDataVersion, |
| SPINEL_PROP_THREAD_NETWORK_DATA_VERSION, SPINEL_DATATYPE_UINT8_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_ThreadStableNetworkData, |
| SPINEL_PROP_THREAD_STABLE_NETWORK_DATA, SPINEL_DATATYPE_DATA_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_ThreadLeaderNetworkData, |
| SPINEL_PROP_THREAD_LEADER_NETWORK_DATA, SPINEL_DATATYPE_DATA_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_ThreadStableLeaderNetworkData, |
| SPINEL_PROP_THREAD_STABLE_LEADER_NETWORK_DATA, SPINEL_DATATYPE_DATA_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_ThreadStableNetworkDataVersion, |
| SPINEL_PROP_THREAD_STABLE_NETWORK_DATA_VERSION, SPINEL_DATATYPE_UINT8_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_ThreadRouterRoleEnabled, |
| SPINEL_PROP_THREAD_ROUTER_ROLE_ENABLED, SPINEL_DATATYPE_BOOL_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_ThreadDeviceMode, |
| SPINEL_PROP_THREAD_MODE, SPINEL_DATATYPE_UINT8_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_OpenThreadDebugTestAssert, |
| SPINEL_PROP_DEBUG_TEST_ASSERT, SPINEL_DATATYPE_BOOL_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_OpenThreadDebugTestWatchdog, |
| SPINEL_PROP_DEBUG_TEST_WATCHDOG, SPINEL_DATATYPE_BOOL_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_TmfProxyEnabled, |
| SPINEL_PROP_THREAD_TMF_PROXY_ENABLED, SPINEL_DATATYPE_BOOL_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_NCPCCAFailureRate, |
| SPINEL_PROP_MAC_CCA_FAILURE_RATE, SPINEL_DATATYPE_UINT16_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_ThreadChildTimeout, |
| SPINEL_PROP_THREAD_CHILD_TIMEOUT, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_OpenThreadLogLevel, |
| SPINEL_PROP_DEBUG_NCP_LOG_LEVEL, SPINEL_DATATYPE_UINT8_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_OpenThreadLogTimestampBase, |
| SPINEL_PROP_DEBUG_LOG_TIMESTAMP_BASE, SPINEL_DATATYPE_UINT64_S); |
| register_get_handler_spinel_simple( |
| kWPANTUNDProperty_OpenThreadTrelTestModeEnable, |
| SPINEL_PROP_DEBUG_TREL_TEST_MODE_ENABLE, SPINEL_DATATYPE_BOOL_S); |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // Properties requiring capability check and associated with a spinel property |
| // with simple packing format |
| |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPSleepyPollInterval, |
| SPINEL_CAP_ROLE_SLEEPY, |
| SPINEL_PROP_MAC_DATA_POLL_PERIOD, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_CommissionerProvisioningUrl, |
| SPINEL_CAP_THREAD_COMMISSIONER, |
| SPINEL_PROP_MESHCOP_COMMISSIONER_PROVISIONING_URL, SPINEL_DATATYPE_UTF8_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_CommissionerSessionId, |
| SPINEL_CAP_THREAD_COMMISSIONER, |
| SPINEL_PROP_MESHCOP_COMMISSIONER_SESSION_ID, SPINEL_DATATYPE_UINT16_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_MACAllowlistEnabled, |
| SPINEL_CAP_MAC_ALLOWLIST, |
| SPINEL_PROP_MAC_ALLOWLIST_ENABLED, SPINEL_DATATYPE_BOOL_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_MACDenylistEnabled, |
| SPINEL_CAP_MAC_ALLOWLIST, |
| SPINEL_PROP_MAC_DENYLIST_ENABLED, SPINEL_DATATYPE_BOOL_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_JamDetectionStatus, |
| SPINEL_CAP_JAM_DETECT, |
| SPINEL_PROP_JAM_DETECTED, SPINEL_DATATYPE_BOOL_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_JamDetectionEnable, |
| SPINEL_CAP_JAM_DETECT, |
| SPINEL_PROP_JAM_DETECT_ENABLE, SPINEL_DATATYPE_BOOL_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_JamDetectionRssiThreshold, |
| SPINEL_CAP_JAM_DETECT, |
| SPINEL_PROP_JAM_DETECT_RSSI_THRESHOLD, SPINEL_DATATYPE_INT8_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_JamDetectionWindow, |
| SPINEL_CAP_JAM_DETECT, |
| SPINEL_PROP_JAM_DETECT_WINDOW, SPINEL_DATATYPE_UINT8_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_JamDetectionBusyPeriod, |
| SPINEL_CAP_JAM_DETECT, |
| SPINEL_PROP_JAM_DETECT_BUSY, SPINEL_DATATYPE_UINT8_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_JamDetectionDebugHistoryBitmap, |
| SPINEL_CAP_JAM_DETECT, |
| SPINEL_PROP_JAM_DETECT_HISTORY_BITMAP, SPINEL_DATATYPE_UINT64_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_ChildSupervisionInterval, |
| SPINEL_CAP_CHILD_SUPERVISION, |
| SPINEL_PROP_CHILD_SUPERVISION_INTERVAL, SPINEL_DATATYPE_UINT16_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_ChildSupervisionCheckTimeout, |
| SPINEL_CAP_CHILD_SUPERVISION, |
| SPINEL_PROP_CHILD_SUPERVISION_CHECK_TIMEOUT, SPINEL_DATATYPE_UINT16_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_ChannelMonitorSampleInterval, |
| SPINEL_CAP_CHANNEL_MONITOR, |
| SPINEL_PROP_CHANNEL_MONITOR_SAMPLE_INTERVAL, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_ChannelMonitorRssiThreshold, |
| SPINEL_CAP_CHANNEL_MONITOR, |
| SPINEL_PROP_CHANNEL_MONITOR_RSSI_THRESHOLD, SPINEL_DATATYPE_INT8_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_ChannelMonitorSampleWindow, |
| SPINEL_CAP_CHANNEL_MONITOR, |
| SPINEL_PROP_CHANNEL_MONITOR_SAMPLE_WINDOW, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_ChannelMonitorSampleCount, |
| SPINEL_CAP_CHANNEL_MONITOR, |
| SPINEL_PROP_CHANNEL_MONITOR_SAMPLE_COUNT, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_ChannelManagerNewChannel, |
| SPINEL_CAP_CHANNEL_MANAGER, |
| SPINEL_PROP_CHANNEL_MANAGER_NEW_CHANNEL, SPINEL_DATATYPE_UINT8_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_ChannelManagerDelay, |
| SPINEL_CAP_CHANNEL_MANAGER, |
| SPINEL_PROP_CHANNEL_MANAGER_DELAY, SPINEL_DATATYPE_UINT16_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_ChannelManagerAutoSelectEnabled, |
| SPINEL_CAP_CHANNEL_MANAGER, |
| SPINEL_PROP_CHANNEL_MANAGER_AUTO_SELECT_ENABLED, SPINEL_DATATYPE_BOOL_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_ChannelManagerAutoSelectInterval, |
| SPINEL_CAP_CHANNEL_MANAGER, |
| SPINEL_PROP_CHANNEL_MANAGER_AUTO_SELECT_INTERVAL, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_ChannelManagerChannelSelect, |
| SPINEL_CAP_CHANNEL_MANAGER, |
| SPINEL_PROP_CHANNEL_MANAGER_CHANNEL_SELECT, SPINEL_DATATYPE_BOOL_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NestLabs_LegacyMeshLocalPrefix, |
| SPINEL_CAP_NEST_LEGACY_INTERFACE, |
| SPINEL_PROP_NEST_LEGACY_ULA_PREFIX, SPINEL_DATATYPE_DATA_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_TimeSync_Period, |
| SPINEL_CAP_TIME_SYNC, |
| SPINEL_PROP_TIME_SYNC_PERIOD, SPINEL_DATATYPE_UINT16_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_TimeSync_XtalThreshold, |
| SPINEL_CAP_TIME_SYNC, |
| SPINEL_PROP_TIME_SYNC_XTAL_THRESHOLD, SPINEL_DATATYPE_UINT16_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_TX_PKT_TOTAL, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_TX_PKT_TOTAL, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_TX_PKT_UNICAST, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_TX_PKT_UNICAST, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_TX_PKT_BROADCAST, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_TX_PKT_BROADCAST, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_TX_PKT_ACK_REQ, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_TX_PKT_ACK_REQ, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_TX_PKT_ACKED, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_TX_PKT_ACKED, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_TX_PKT_NO_ACK_REQ, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_TX_PKT_NO_ACK_REQ, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_TX_PKT_DATA, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_TX_PKT_DATA, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_TX_PKT_DATA_POLL, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_TX_PKT_DATA_POLL, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_TX_PKT_BEACON, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_TX_PKT_BEACON, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_TX_PKT_BEACON_REQ, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_TX_PKT_BEACON_REQ, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_TX_PKT_OTHER, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_TX_PKT_OTHER, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_TX_PKT_RETRY, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_TX_PKT_RETRY, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_TX_ERR_CCA, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_TX_ERR_CCA, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_TX_ERR_ABORT, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_TX_ERR_ABORT, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_RX_PKT_TOTAL, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_RX_PKT_TOTAL, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_RX_PKT_UNICAST, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_RX_PKT_UNICAST, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_RX_PKT_BROADCAST, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_RX_PKT_BROADCAST, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_RX_PKT_DATA, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_RX_PKT_DATA, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_RX_PKT_DATA_POLL, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_RX_PKT_DATA_POLL, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_RX_PKT_BEACON, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_RX_PKT_BEACON, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_RX_PKT_BEACON_REQ, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_RX_PKT_BEACON_REQ, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_RX_PKT_OTHER, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_RX_PKT_OTHER, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_RX_PKT_FILT_WL, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_RX_PKT_FILT_WL, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_RX_PKT_FILT_DA, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_RX_PKT_FILT_DA, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_RX_ERR_EMPTY, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_RX_ERR_EMPTY, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_RX_ERR_UKWN_NBR, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_RX_ERR_UKWN_NBR, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_RX_ERR_NVLD_SADDR, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_RX_ERR_NVLD_SADDR, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_RX_ERR_SECURITY, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_RX_ERR_SECURITY, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_RX_ERR_BAD_FCS, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_RX_ERR_BAD_FCS, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_RX_ERR_OTHER, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_RX_ERR_OTHER, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_TX_IP_SEC_TOTAL, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_TX_IP_SEC_TOTAL, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_TX_IP_INSEC_TOTAL, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_TX_IP_INSEC_TOTAL, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_TX_IP_DROPPED, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_TX_IP_DROPPED, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_RX_IP_SEC_TOTAL, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_RX_IP_SEC_TOTAL, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_RX_IP_INSEC_TOTAL, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_RX_IP_INSEC_TOTAL, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_RX_IP_DROPPED, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_RX_IP_DROPPED, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_TX_SPINEL_TOTAL, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_TX_SPINEL_TOTAL, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_RX_SPINEL_TOTAL, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_RX_SPINEL_TOTAL, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_RX_SPINEL_ERR, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_RX_SPINEL_ERR, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_IP_TX_SUCCESS, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_IP_TX_SUCCESS, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_IP_RX_SUCCESS, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_IP_RX_SUCCESS, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_IP_TX_FAILURE, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_IP_TX_FAILURE, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCounter_IP_RX_FAILURE, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_IP_RX_FAILURE, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_POSIXAppRCPVersion, |
| SPINEL_CAP_POSIX, |
| SPINEL_PROP_RCP_VERSION, SPINEL_DATATYPE_UTF8_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_OpenThreadSLAACEnabled, |
| SPINEL_CAP_SLAAC, |
| SPINEL_PROP_SLAAC_ENABLED, SPINEL_DATATYPE_BOOL_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_NCPCoexEnable, |
| SPINEL_CAP_RADIO_COEX, |
| SPINEL_PROP_RADIO_COEX_ENABLE, SPINEL_DATATYPE_BOOL_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_ThreadDomainName, |
| SPINEL_CAP_NET_THREAD_1_2, |
| SPINEL_PROP_THREAD_DOMAIN_NAME, SPINEL_DATATYPE_UTF8_S); |
| |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_ThreadCslPeriod, |
| SPINEL_CAP_THREAD_CSL_RECEIVER, |
| SPINEL_PROP_THREAD_CSL_PERIOD, SPINEL_DATATYPE_UINT16_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_ThreadCslTimeout, |
| SPINEL_CAP_THREAD_CSL_RECEIVER, |
| SPINEL_PROP_THREAD_CSL_TIMEOUT, SPINEL_DATATYPE_UINT32_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_ThreadCslChannel, |
| SPINEL_CAP_THREAD_CSL_RECEIVER, |
| SPINEL_PROP_THREAD_CSL_CHANNEL, SPINEL_DATATYPE_UINT8_S); |
| register_get_handler_capability_spinel_simple( |
| kWPANTUNDProperty_ThreadBackboneRouterLocalJitter, |
| SPINEL_CAP_THREAD_BACKBONE_ROUTER, |
| SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_REGISTRATION_JITTER, SPINEL_DATATYPE_UINT8_S); |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // Properties associated with a spinel property using an unpacker |
| |
| register_get_handler_spinel_unpacker( |
| kWPANTUNDProperty_NCPChannelMask, |
| SPINEL_PROP_PHY_CHAN_SUPPORTED, unpack_channel_mask); |
| register_get_handler_spinel_unpacker( |
| kWPANTUNDProperty_NCPPreferredChannelMask, |
| SPINEL_PROP_PHY_CHAN_PREFERRED, unpack_channel_mask); |
| register_get_handler_spinel_unpacker( |
| kWPANTUNDProperty_ThreadActiveDataset, |
| SPINEL_PROP_THREAD_ACTIVE_DATASET, boost::bind(unpack_dataset, _1, _2, _3, /* as_val_map */ false)); |
| register_get_handler_spinel_unpacker( |
| kWPANTUNDProperty_ThreadActiveDatasetAsValMap, |
| SPINEL_PROP_THREAD_ACTIVE_DATASET, boost::bind(unpack_dataset, _1, _2, _3, /* as_val_map */ true)); |
| register_get_handler_spinel_unpacker( |
| kWPANTUNDProperty_ThreadPendingDataset, |
| SPINEL_PROP_THREAD_PENDING_DATASET, boost::bind(unpack_dataset, _1, _2, _3, /* as_val_map */ false)); |
| register_get_handler_spinel_unpacker( |
| kWPANTUNDProperty_ThreadPendingDatasetAsValMap, |
| SPINEL_PROP_THREAD_PENDING_DATASET, boost::bind(unpack_dataset, _1, _2, _3, /* as_val_map */ true)); |
| register_get_handler_spinel_unpacker( |
| kWPANTUNDProperty_ThreadParent, |
| SPINEL_PROP_THREAD_PARENT, |
| boost::bind(unpack_parent_info, _1, _2, _3, /* as_val_map */ false)); |
| register_get_handler_spinel_unpacker( |
| kWPANTUNDProperty_ThreadParentAsValMap, |
| SPINEL_PROP_THREAD_PARENT, |
| boost::bind(unpack_parent_info, _1, _2, _3, /* as_val_map */ true)); |
| register_get_handler_spinel_unpacker( |
| kWPANTUNDProperty_ThreadAddressCacheTable, |
| SPINEL_PROP_THREAD_ADDRESS_CACHE_TABLE, |
| boost::bind(unpack_address_cache_table, _1, _2, _3, /* as_val_map */ false)); |
| register_get_handler_spinel_unpacker( |
| kWPANTUNDProperty_ThreadAddressCacheTableAsValMap, |
| SPINEL_PROP_THREAD_ADDRESS_CACHE_TABLE, |
| boost::bind(unpack_address_cache_table, _1, _2, _3, /* as_val_map */ true)); |
| register_get_handler_spinel_unpacker( |
| kWPANTUNDProperty_OpenThreadSupportedRadioLinks, |
| SPINEL_PROP_SUPPORTED_RADIO_LINKS, |
| unpack_supported_radio_links); |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // Properties requiring capability check and associated with a spinel property |
| // using an unpacker |
| |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_NCPMCUPowerState, |
| SPINEL_CAP_MCU_POWER_STATE, |
| SPINEL_PROP_MCU_POWER_STATE, unpack_mcu_power_state); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_JoinerState, |
| SPINEL_CAP_THREAD_JOINER, |
| SPINEL_PROP_MESHCOP_JOINER_STATE, unpack_meshcop_joiner_state); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_JoinerDiscernerValue, |
| SPINEL_CAP_THREAD_JOINER, |
| SPINEL_PROP_MESHCOP_JOINER_DISCERNER, unpack_meshcop_joiner_discerner_value); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_CommissionerState, |
| SPINEL_CAP_THREAD_COMMISSIONER, |
| SPINEL_PROP_MESHCOP_COMMISSIONER_STATE, unpack_commissioner_state); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_CommissionerJoiners, |
| SPINEL_CAP_THREAD_COMMISSIONER, |
| SPINEL_PROP_MESHCOP_COMMISSIONER_JOINERS, unpack_commissioner_joiners); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_MACAllowlistEntries, |
| SPINEL_CAP_MAC_ALLOWLIST, |
| SPINEL_PROP_MAC_ALLOWLIST, boost::bind(unpack_mac_allowlist_entries, _1, _2, _3, false)); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_MACAllowlistEntriesAsValMap, |
| SPINEL_CAP_MAC_ALLOWLIST, |
| SPINEL_PROP_MAC_ALLOWLIST, boost::bind(unpack_mac_allowlist_entries, _1, _2, _3, true)); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_MACDenylistEntries, |
| SPINEL_CAP_MAC_ALLOWLIST, |
| SPINEL_PROP_MAC_DENYLIST, boost::bind(unpack_mac_denylist_entries, _1, _2, _3, false)); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_MACDenylistEntriesAsValMap, |
| SPINEL_CAP_MAC_ALLOWLIST, |
| SPINEL_PROP_MAC_DENYLIST, boost::bind(unpack_mac_denylist_entries, _1, _2, _3, true)); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_MACFilterEntries, |
| SPINEL_CAP_MAC_ALLOWLIST, |
| SPINEL_PROP_MAC_FIXED_RSS, boost::bind(unpack_mac_allowlist_entries, _1, _2, _3, false)); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_MACFilterEntriesAsValMap, |
| SPINEL_CAP_MAC_ALLOWLIST, |
| SPINEL_PROP_MAC_FIXED_RSS, boost::bind(unpack_mac_allowlist_entries, _1, _2, _3, true)); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_ChannelMonitorChannelQuality, |
| SPINEL_CAP_CHANNEL_MONITOR, |
| SPINEL_PROP_CHANNEL_MONITOR_CHANNEL_OCCUPANCY, boost::bind(unpack_channel_occupancy, _1, _2, _3, false)); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_ChannelMonitorChannelQualityAsValMap, |
| SPINEL_CAP_CHANNEL_MONITOR, |
| SPINEL_PROP_CHANNEL_MONITOR_CHANNEL_OCCUPANCY, boost::bind(unpack_channel_occupancy, _1, _2, _3, true)); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_ChannelManagerSupportedChannelMask, |
| SPINEL_CAP_CHANNEL_MANAGER, |
| SPINEL_PROP_CHANNEL_MANAGER_SUPPORTED_CHANNELS, unpack_channel_mask); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_ChannelManagerFavoredChannelMask, |
| SPINEL_CAP_CHANNEL_MANAGER, |
| SPINEL_PROP_CHANNEL_MANAGER_FAVORED_CHANNELS, unpack_channel_mask); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_NCPCounterAllMac, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_ALL_MAC_COUNTERS, boost::bind(unpack_ncp_counters_all_mac, _1, _2, _3, false)); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_NCPCounterAllMacAsValMap, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_ALL_MAC_COUNTERS, boost::bind(unpack_ncp_counters_all_mac, _1, _2, _3, true)); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_NCPCounterThreadMle, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_MLE_COUNTERS, boost::bind(unpack_ncp_counters_mle, _1, _2, _3, false)); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_NCPCounterThreadMleAsValMap, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_MLE_COUNTERS, boost::bind(unpack_ncp_counters_mle, _1, _2, _3, true)); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_NCPCounterAllIPv6, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_ALL_IP_COUNTERS, boost::bind(unpack_ncp_counters_ipv6, _1, _2, _3, false)); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_NCPCounterAllIPv6AsValMap, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_ALL_IP_COUNTERS, boost::bind(unpack_ncp_counters_ipv6, _1, _2, _3, true)); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_TimeSync_NetworkTime, |
| SPINEL_CAP_TIME_SYNC, |
| SPINEL_PROP_THREAD_NETWORK_TIME, boost::bind(unpack_thread_network_time_as_any, _1, _2, _3, false)); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_TimeSync_NetworkTimeAsValMap, |
| SPINEL_CAP_TIME_SYNC, |
| SPINEL_PROP_THREAD_NETWORK_TIME, boost::bind(unpack_thread_network_time_as_any, _1, _2, _3, true)); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_ThreadLeaderServices, |
| SPINEL_CAP_THREAD_SERVICE, |
| SPINEL_PROP_SERVER_LEADER_SERVICES, boost::bind(unpack_server_leader_services_as_any, _1, _2, _3, false)); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_ThreadLeaderServicesAsValMap, |
| SPINEL_CAP_THREAD_SERVICE, |
| SPINEL_PROP_SERVER_LEADER_SERVICES, boost::bind(unpack_server_leader_services_as_any, _1, _2, _3, true)); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_NCPCoexMetrics, |
| SPINEL_CAP_RADIO_COEX, |
| SPINEL_PROP_RADIO_COEX_METRICS, boost::bind(unpack_coex_metrics, _1, _2, _3, false)); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_NCPCoexMetricsAsValMap, |
| SPINEL_CAP_RADIO_COEX, |
| SPINEL_PROP_RADIO_COEX_METRICS, boost::bind(unpack_coex_metrics, _1, _2, _3, true)); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_OpenThreadNeighborTableMultiRadioInfo, |
| SPINEL_CAP_MULTI_RADIO, |
| SPINEL_PROP_NEIGHBOR_TABLE_MULTI_RADIO_INFO, boost::bind(unpack_neighbor_table_multi_radio_info, _1, _2, _3)); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_ThreadDUAInterfaceIdentifier, |
| SPINEL_CAP_DUA, |
| SPINEL_PROP_THREAD_DUA_ID, unpack_mcu_dua_interface_identifier); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_ThreadBackboneRouterPrimary, |
| SPINEL_CAP_NET_THREAD_1_2, |
| SPINEL_PROP_THREAD_BACKBONE_ROUTER_PRIMARY, boost::bind(unpack_backbone_router_primary, _1, _2, _3)); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_ThreadBackboneRouterLocalState, |
| SPINEL_CAP_THREAD_BACKBONE_ROUTER, |
| SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_STATE, boost::bind(unpack_backbone_router_state, _1, _2, _3)); |
| register_get_handler_capability_spinel_unpacker( |
| kWPANTUNDProperty_ThreadBackboneRouterLocalConfig, |
| SPINEL_CAP_THREAD_BACKBONE_ROUTER, |
| SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_CONFIG, boost::bind(unpack_backbone_router_config, _1, _2, _3)); |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // Properties with a dedicated handler method |
| |
| register_get_handler( |
| kWPANTUNDProperty_ConfigNCPDriverName, |
| boost::bind(&SpinelNCPInstance::get_prop_ConfigNCPDriverName, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_NCPCapabilities, |
| boost::bind(&SpinelNCPInstance::get_prop_NCPCapabilities, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_NetworkIsCommissioned, |
| boost::bind(&SpinelNCPInstance::get_prop_NetworkIsCommissioned, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_ThreadRouterID, |
| boost::bind(&SpinelNCPInstance::get_prop_ThreadRouterID, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_ThreadConfigFilterRLOCAddresses, |
| boost::bind(&SpinelNCPInstance::get_prop_ThreadConfigFilterRLOCAddresses, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_ThreadConfigFilterALOCAddresses, |
| boost::bind(&SpinelNCPInstance::get_prop_ThreadConfigFilterALOCAddresses, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_IPv6MeshLocalPrefix, |
| boost::bind(&SpinelNCPInstance::get_prop_IPv6MeshLocalPrefix, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_IPv6MeshLocalAddress, |
| boost::bind(&SpinelNCPInstance::get_prop_IPv6MeshLocalAddress, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_IPv6LinkLocalAddress, |
| boost::bind(&SpinelNCPInstance::get_prop_IPv6LinkLocalAddress, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_ThreadChildTable, |
| boost::bind(&SpinelNCPInstance::get_prop_ThreadChildTable, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_ThreadChildTableAsValMap, |
| boost::bind(&SpinelNCPInstance::get_prop_ThreadChildTableAsValMap, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_ThreadChildTableAddresses, |
| boost::bind(&SpinelNCPInstance::get_prop_ThreadChildTableAddresses, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_ThreadNeighborTable, |
| boost::bind(&SpinelNCPInstance::get_prop_ThreadNeighborTable, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_ThreadNeighborTableAsValMap, |
| boost::bind(&SpinelNCPInstance::get_prop_ThreadNeighborTableAsValMap, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_ThreadRouterTable, |
| boost::bind(&SpinelNCPInstance::get_prop_ThreadRouterTable, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_ThreadRouterTableAsValMap, |
| boost::bind(&SpinelNCPInstance::get_prop_ThreadRouterTableAsValMap, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_OpenThreadMsgBufferCounters, |
| boost::bind(&SpinelNCPInstance::get_prop_OpenThreadMsgBufferCounters, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_OpenThreadMsgBufferCountersAsString, |
| boost::bind(&SpinelNCPInstance::get_prop_OpenThreadMsgBufferCountersAsString, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_OpenThreadSteeringDataSetWhenJoinable, |
| boost::bind(&SpinelNCPInstance::get_prop_OpenThreadSteeringDataSetWhenJoinable, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_OpenThreadSteeringDataAddress, |
| boost::bind(&SpinelNCPInstance::get_prop_OpenThreadSteeringDataAddress, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_DatasetActiveTimestamp, |
| boost::bind(&SpinelNCPInstance::get_prop_DatasetActiveTimestamp, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_DatasetPendingTimestamp, |
| boost::bind(&SpinelNCPInstance::get_prop_DatasetPendingTimestamp, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_DatasetMasterKey, |
| boost::bind(&SpinelNCPInstance::get_prop_DatasetMasterKey, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_DatasetNetworkName, |
| boost::bind(&SpinelNCPInstance::get_prop_DatasetNetworkName, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_DatasetExtendedPanId, |
| boost::bind(&SpinelNCPInstance::get_prop_DatasetExtendedPanId, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_DatasetMeshLocalPrefix, |
| boost::bind(&SpinelNCPInstance::get_prop_DatasetMeshLocalPrefix, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_DatasetDelay, |
| boost::bind(&SpinelNCPInstance::get_prop_DatasetDelay, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_DatasetPanId, |
| boost::bind(&SpinelNCPInstance::get_prop_DatasetPanId, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_DatasetChannel, |
| boost::bind(&SpinelNCPInstance::get_prop_DatasetChannel, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_DatasetPSKc, |
| boost::bind(&SpinelNCPInstance::get_prop_DatasetPSKc, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_DatasetChannelMaskPage0, |
| boost::bind(&SpinelNCPInstance::get_prop_DatasetChannelMaskPage0, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_DatasetSecPolicyKeyRotation, |
| boost::bind(&SpinelNCPInstance::get_prop_DatasetSecPolicyKeyRotation, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_DatasetSecPolicyFlags, |
| boost::bind(&SpinelNCPInstance::get_prop_DatasetSecPolicyFlags, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_DatasetRawTlvs, |
| boost::bind(&SpinelNCPInstance::get_prop_DatasetRawTlvs, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_DatasetDestIpAddress, |
| boost::bind(&SpinelNCPInstance::get_prop_DatasetDestIpAddress, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_DatasetAllFileds, |
| boost::bind(&SpinelNCPInstance::get_prop_DatasetAllFileds, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_DatasetAllFileds_AltString, |
| boost::bind(&SpinelNCPInstance::get_prop_DatasetAllFileds, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_DatasetAllFiledsAsValMap, |
| boost::bind(&SpinelNCPInstance::get_prop_DatasetAllFiledsAsValMap, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_DatasetCommand, |
| boost::bind(&SpinelNCPInstance::get_prop_DatasetCommand, this, _1)); |
| register_get_handler( |
| kWPANTUNDProperty_DaemonTickleOnHostDidWake, |
| boost::bind(&SpinelNCPInstance::get_prop_DaemonTickleOnHostDidWake, this, _1)); |
| |
| // Properties requiring capability check with a dedicated handler method |
| |
| register_get_handler_capability( |
| kWPANTUNDProperty_JoinerDiscernerBitLength, |
| SPINEL_CAP_THREAD_JOINER, |
| boost::bind(&SpinelNCPInstance::get_prop_JoinerDiscernerBitLength, this, _1)); |
| register_get_handler_capability( |
| kWPANTUNDProperty_CommissionerEnergyScanResult, |
| SPINEL_CAP_THREAD_COMMISSIONER, |
| boost::bind(&SpinelNCPInstance::get_prop_CommissionerEnergyScanResult, this, _1)); |
| register_get_handler_capability( |
| kWPANTUNDProperty_CommissionerPanIdConflictResult, |
| SPINEL_CAP_THREAD_COMMISSIONER, |
| boost::bind(&SpinelNCPInstance::get_prop_CommissionerPanIdConflictResult, this, _1)); |
| register_get_handler_capability( |
| kWPANTUNDCommissionerLinkMetricsQueryResult, |
| SPINEL_CAP_THREAD_LINK_METRICS, |
| boost::bind(&SpinelNCPInstance::get_prop_LinkMetricsQueryResult, this, _1)); |
| register_get_handler_capability( |
| kWPANTUNDCommissionerLinkMetricsMgmtResponse, |
| SPINEL_CAP_THREAD_LINK_METRICS, |
| boost::bind(&SpinelNCPInstance::get_prop_LinkMetricsMgmtResponse, this, _1)); |
| register_get_handler_capability( |
| kWPANTUNDCommissionerLinkMetricsLastEnhAckIe, |
| SPINEL_CAP_THREAD_LINK_METRICS, |
| boost::bind(&SpinelNCPInstance::get_prop_LinkMetricsLastEnhAckIe, this, _1)); |
| register_get_handler_capability( |
| kWPANTUNDProperty_ThreadMlrResponse, |
| SPINEL_CAP_NET_THREAD_1_2, |
| boost::bind(&SpinelNCPInstance::get_prop_MulticastListenerRegistrationResponse, this, _1)); |
| register_get_handler_capability( |
| kWPANTUNDProperty_ThreadNeighborTableErrorRates, |
| SPINEL_CAP_ERROR_RATE_TRACKING, |
| boost::bind(&SpinelNCPInstance::get_prop_ThreadNeighborTableErrorRates, this, _1)); |
| register_get_handler_capability( |
| kWPANTUNDProperty_ThreadNeighborTableErrorRatesAsValMap, |
| SPINEL_CAP_ERROR_RATE_TRACKING, |
| boost::bind(&SpinelNCPInstance::get_prop_ThreadNeighborTableErrorRatesAsValMap, this, _1)); |
| register_get_handler_capability( |
| kWPANTUNDProperty_POSIXAppRCPVersionCached, |
| SPINEL_CAP_POSIX, |
| boost::bind(&SpinelNCPInstance::get_prop_POSIXAppRCPVersionCached, this, _1)); |
| register_get_handler_capability( |
| kWPANTUNDProperty_MACFilterFixedRssi, |
| SPINEL_CAP_MAC_ALLOWLIST, |
| boost::bind(&SpinelNCPInstance::get_prop_MACFilterFixedRssi, this, _1)); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_ConfigNCPDriverName(CallbackWithStatusArg1 cb) |
| { |
| cb(kWPANTUNDStatus_Ok, boost::any(std::string("spinel"))); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_NCPCapabilities(CallbackWithStatusArg1 cb) |
| { |
| std::list<std::string> capability_list; |
| std::set<unsigned int>::iterator iter; |
| |
| for (iter = mCapabilities.begin(); iter != mCapabilities.end(); iter++) { |
| char str[200]; |
| snprintf(str, sizeof(str), "%s (%d)", spinel_capability_to_cstr(*iter), *iter); |
| capability_list.push_back(std::string(str)); |
| } |
| |
| cb(kWPANTUNDStatus_Ok, boost::any(capability_list)); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_NetworkIsCommissioned(CallbackWithStatusArg1 cb) |
| { |
| cb(kWPANTUNDStatus_Ok, boost::any(mIsCommissioned)); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_ThreadRouterID(CallbackWithStatusArg1 cb) |
| { |
| get_spinel_prop(boost::bind(convert_rloc16_to_router_id, cb, _1, _2), SPINEL_PROP_THREAD_RLOC16, |
| SPINEL_DATATYPE_UINT16_S); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_ThreadConfigFilterRLOCAddresses(CallbackWithStatusArg1 cb) |
| { |
| cb(kWPANTUNDStatus_Ok, boost::any(mFilterRLOCAddresses)); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_ThreadConfigFilterALOCAddresses(CallbackWithStatusArg1 cb) |
| { |
| cb(kWPANTUNDStatus_Ok, boost::any(mFilterALOCAddresses)); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_JoinerDiscernerBitLength(CallbackWithStatusArg1 cb) |
| { |
| cb(kWPANTUNDStatus_Ok, boost::any(mJoinerDiscernerBitLength)); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_CommissionerEnergyScanResult(CallbackWithStatusArg1 cb) |
| { |
| cb(kWPANTUNDStatus_Ok, boost::any(mCommissionerEnergyScanResult)); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_CommissionerPanIdConflictResult(CallbackWithStatusArg1 cb) |
| { |
| cb(kWPANTUNDStatus_Ok, boost::any(mCommissionerPanIdConflictResult)); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_IPv6MeshLocalPrefix(CallbackWithStatusArg1 cb) |
| { |
| if (!buffer_is_nonzero(mNCPV6Prefix, sizeof(mNCPV6Prefix))) { |
| get_spinel_prop_with_unpacker(cb, SPINEL_PROP_IPV6_ML_PREFIX, unpack_mesh_local_prefix); |
| } else { |
| struct in6_addr addr = mNCPMeshLocalAddress; |
| memset(addr.s6_addr + 8, 0, 8); |
| cb(kWPANTUNDStatus_Ok, boost::any(in6_addr_to_string(addr) + "/64")); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_IPv6MeshLocalAddress(CallbackWithStatusArg1 cb) |
| { |
| if (!buffer_is_nonzero(mNCPV6Prefix, sizeof(mNCPV6Prefix))) { |
| get_spinel_prop(cb, SPINEL_PROP_IPV6_ML_ADDR, SPINEL_DATATYPE_IPv6ADDR_S); |
| } else { |
| cb(kWPANTUNDStatus_Ok, boost::any(in6_addr_to_string(mNCPMeshLocalAddress))); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_IPv6LinkLocalAddress(CallbackWithStatusArg1 cb) |
| { |
| if (!IN6_IS_ADDR_LINKLOCAL(&mNCPLinkLocalAddress)) { |
| get_spinel_prop(cb, SPINEL_PROP_IPV6_LL_ADDR, SPINEL_DATATYPE_IPv6ADDR_S); |
| } else { |
| cb(kWPANTUNDStatus_Ok, boost::any(in6_addr_to_string(mNCPLinkLocalAddress))); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_LinkMetricsQueryResult(CallbackWithStatusArg1 cb) |
| { |
| cb(kWPANTUNDStatus_Ok, boost::any(mLinkMetricsQueryResult)); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_LinkMetricsMgmtResponse(CallbackWithStatusArg1 cb) |
| { |
| cb(kWPANTUNDStatus_Ok, boost::any(mLinkMetricsMgmtResponse)); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_LinkMetricsLastEnhAckIe(CallbackWithStatusArg1 cb) |
| { |
| cb(kWPANTUNDStatus_Ok, boost::any(mLinkMetricsLastEnhAckIe)); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_MulticastListenerRegistrationResponse(CallbackWithStatusArg1 cb) |
| { |
| cb(kWPANTUNDStatus_Ok, boost::any(mMulticastListenerRegistrationResponse)); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_ThreadChildTable(CallbackWithStatusArg1 cb) |
| { |
| start_new_task(boost::shared_ptr<SpinelNCPTask>( |
| new SpinelNCPTaskGetNetworkTopology( |
| this, |
| cb, |
| SpinelNCPTaskGetNetworkTopology::kChildTable, |
| SpinelNCPTaskGetNetworkTopology::kResultFormat_StringArray |
| ) |
| )); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_ThreadChildTableAsValMap(CallbackWithStatusArg1 cb) |
| { |
| start_new_task(boost::shared_ptr<SpinelNCPTask>( |
| new SpinelNCPTaskGetNetworkTopology( |
| this, |
| cb, |
| SpinelNCPTaskGetNetworkTopology::kChildTable, |
| SpinelNCPTaskGetNetworkTopology::kResultFormat_ValueMapArray |
| ) |
| )); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_ThreadChildTableAddresses(CallbackWithStatusArg1 cb) |
| { |
| start_new_task(boost::shared_ptr<SpinelNCPTask>( |
| new SpinelNCPTaskGetNetworkTopology( |
| this, |
| cb, |
| SpinelNCPTaskGetNetworkTopology::kChildTableAddresses, |
| SpinelNCPTaskGetNetworkTopology::kResultFormat_StringArray |
| ) |
| )); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_ThreadNeighborTable(CallbackWithStatusArg1 cb) |
| { |
| start_new_task(boost::shared_ptr<SpinelNCPTask>( |
| new SpinelNCPTaskGetNetworkTopology( |
| this, |
| cb, |
| SpinelNCPTaskGetNetworkTopology::kNeighborTable, |
| SpinelNCPTaskGetNetworkTopology::kResultFormat_StringArray |
| ) |
| )); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_ThreadNeighborTableAsValMap(CallbackWithStatusArg1 cb) |
| { |
| start_new_task(boost::shared_ptr<SpinelNCPTask>( |
| new SpinelNCPTaskGetNetworkTopology( |
| this, |
| cb, |
| SpinelNCPTaskGetNetworkTopology::kNeighborTable, |
| SpinelNCPTaskGetNetworkTopology::kResultFormat_ValueMapArray |
| ) |
| )); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_ThreadNeighborTableErrorRates(CallbackWithStatusArg1 cb) |
| { |
| start_new_task(boost::shared_ptr<SpinelNCPTask>( |
| new SpinelNCPTaskGetNetworkTopology( |
| this, |
| cb, |
| SpinelNCPTaskGetNetworkTopology::kNeighborTableErrorRates, |
| SpinelNCPTaskGetNetworkTopology::kResultFormat_StringArray |
| ) |
| )); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_ThreadNeighborTableErrorRatesAsValMap(CallbackWithStatusArg1 cb) |
| { |
| start_new_task(boost::shared_ptr<SpinelNCPTask>( |
| new SpinelNCPTaskGetNetworkTopology( |
| this, |
| cb, |
| SpinelNCPTaskGetNetworkTopology::kNeighborTableErrorRates, |
| SpinelNCPTaskGetNetworkTopology::kResultFormat_ValueMapArray |
| ) |
| )); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_ThreadRouterTable(CallbackWithStatusArg1 cb) |
| { |
| start_new_task(boost::shared_ptr<SpinelNCPTask>( |
| new SpinelNCPTaskGetNetworkTopology( |
| this, |
| cb, |
| SpinelNCPTaskGetNetworkTopology::kRouterTable, |
| SpinelNCPTaskGetNetworkTopology::kResultFormat_StringArray |
| ) |
| )); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_ThreadRouterTableAsValMap(CallbackWithStatusArg1 cb) |
| { |
| start_new_task(boost::shared_ptr<SpinelNCPTask>( |
| new SpinelNCPTaskGetNetworkTopology( |
| this, |
| cb, |
| SpinelNCPTaskGetNetworkTopology::kRouterTable, |
| SpinelNCPTaskGetNetworkTopology::kResultFormat_ValueMapArray |
| ) |
| )); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_OpenThreadMsgBufferCounters(CallbackWithStatusArg1 cb) |
| { |
| start_new_task(boost::shared_ptr<SpinelNCPTask>( |
| new SpinelNCPTaskGetMsgBufferCounters( |
| this, |
| cb, |
| SpinelNCPTaskGetMsgBufferCounters::kResultFormat_StringArray |
| ) |
| )); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_OpenThreadMsgBufferCountersAsString(CallbackWithStatusArg1 cb) |
| { |
| start_new_task(boost::shared_ptr<SpinelNCPTask>( |
| new SpinelNCPTaskGetMsgBufferCounters( |
| this, |
| cb, |
| SpinelNCPTaskGetMsgBufferCounters::kResultFormat_String |
| ) |
| )); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_OpenThreadSteeringDataSetWhenJoinable(CallbackWithStatusArg1 cb) |
| { |
| cb(0, boost::any(mSetSteeringDataWhenJoinable)); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_OpenThreadSteeringDataAddress(CallbackWithStatusArg1 cb) |
| { |
| cb(0, boost::any(nl::Data(mSteeringDataAddress, sizeof(mSteeringDataAddress)))); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_DatasetActiveTimestamp(CallbackWithStatusArg1 cb) |
| { |
| if (mLocalDataset.mActiveTimestamp.has_value()) { |
| cb(kWPANTUNDStatus_Ok, boost::any(mLocalDataset.mActiveTimestamp.get())); |
| } else { |
| cb(kWPANTUNDStatus_Ok, boost::any(Data())); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_DatasetPendingTimestamp(CallbackWithStatusArg1 cb) |
| { |
| if (mLocalDataset.mPendingTimestamp.has_value()) { |
| cb(kWPANTUNDStatus_Ok, boost::any(mLocalDataset.mPendingTimestamp.get())); |
| } else { |
| cb(kWPANTUNDStatus_Ok, boost::any(Data())); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_DatasetMasterKey(CallbackWithStatusArg1 cb) |
| { |
| if (mLocalDataset.mMasterKey.has_value()) { |
| cb(kWPANTUNDStatus_Ok, boost::any(mLocalDataset.mMasterKey.get())); |
| } else { |
| cb(kWPANTUNDStatus_Ok, boost::any(Data())); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_DatasetNetworkName(CallbackWithStatusArg1 cb) |
| { |
| if (mLocalDataset.mNetworkName.has_value()) { |
| cb(kWPANTUNDStatus_Ok, boost::any(mLocalDataset.mNetworkName.get())); |
| } else { |
| cb(kWPANTUNDStatus_Ok, boost::any(Data())); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_DatasetExtendedPanId(CallbackWithStatusArg1 cb) |
| { |
| if (mLocalDataset.mExtendedPanId.has_value()) { |
| cb(kWPANTUNDStatus_Ok, boost::any(mLocalDataset.mExtendedPanId.get())); |
| } else { |
| cb(kWPANTUNDStatus_Ok, boost::any(Data())); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_DatasetMeshLocalPrefix(CallbackWithStatusArg1 cb) |
| { |
| if (mLocalDataset.mMeshLocalPrefix.has_value()) { |
| cb(kWPANTUNDStatus_Ok, boost::any(in6_addr_to_string(mLocalDataset.mMeshLocalPrefix.get()))); |
| } else { |
| cb(kWPANTUNDStatus_Ok, boost::any(Data())); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_DatasetDelay(CallbackWithStatusArg1 cb) |
| { |
| if (mLocalDataset.mDelay.has_value()) { |
| cb(kWPANTUNDStatus_Ok, boost::any(mLocalDataset.mDelay.get())); |
| } else { |
| cb(kWPANTUNDStatus_Ok, boost::any(Data())); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_DatasetPanId(CallbackWithStatusArg1 cb) |
| { |
| if (mLocalDataset.mPanId.has_value()) { |
| cb(kWPANTUNDStatus_Ok, boost::any(mLocalDataset.mPanId.get())); |
| } else { |
| cb(kWPANTUNDStatus_Ok, boost::any(Data())); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_DatasetChannel(CallbackWithStatusArg1 cb) |
| { |
| if (mLocalDataset.mChannel.has_value()) { |
| cb(kWPANTUNDStatus_Ok, boost::any(mLocalDataset.mChannel.get())); |
| } else { |
| cb(kWPANTUNDStatus_Ok, boost::any(Data())); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_DatasetPSKc(CallbackWithStatusArg1 cb) |
| { |
| if (mLocalDataset.mPSKc.has_value()) { |
| cb(kWPANTUNDStatus_Ok, boost::any(mLocalDataset.mPSKc.get())); |
| } else { |
| cb(kWPANTUNDStatus_Ok, boost::any(Data())); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_DatasetChannelMaskPage0(CallbackWithStatusArg1 cb) |
| { |
| if (mLocalDataset.mChannelMaskPage0.has_value()) { |
| cb(kWPANTUNDStatus_Ok, boost::any(mLocalDataset.mChannelMaskPage0.get())); |
| } else { |
| cb(kWPANTUNDStatus_Ok, boost::any(Data())); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_DatasetSecPolicyKeyRotation(CallbackWithStatusArg1 cb) |
| { |
| if (mLocalDataset.mSecurityPolicy.has_value()) { |
| cb(kWPANTUNDStatus_Ok, boost::any(mLocalDataset.mSecurityPolicy.get().mKeyRotationTime)); |
| } else { |
| cb(kWPANTUNDStatus_Ok, boost::any(Data())); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_DatasetSecPolicyFlags(CallbackWithStatusArg1 cb) |
| { |
| if (mLocalDataset.mSecurityPolicy.has_value()) { |
| cb(kWPANTUNDStatus_Ok, boost::any(mLocalDataset.mSecurityPolicy.get().mFlags)); |
| } else { |
| cb(kWPANTUNDStatus_Ok, boost::any(Data())); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_DatasetRawTlvs(CallbackWithStatusArg1 cb) |
| { |
| if (mLocalDataset.mRawTlvs.has_value()) { |
| cb(kWPANTUNDStatus_Ok, boost::any(mLocalDataset.mRawTlvs.get())); |
| } else { |
| cb(kWPANTUNDStatus_Ok, boost::any(Data())); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_DatasetDestIpAddress(CallbackWithStatusArg1 cb) |
| { |
| if (mLocalDataset.mDestIpAddress.has_value()) { |
| cb(kWPANTUNDStatus_Ok, boost::any(in6_addr_to_string(mLocalDataset.mDestIpAddress.get()))); |
| } else { |
| cb(kWPANTUNDStatus_Ok, boost::any(Data())); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_DatasetAllFileds(CallbackWithStatusArg1 cb) |
| { |
| std::list<std::string> list; |
| mLocalDataset.convert_to_string_list(list); |
| cb(kWPANTUNDStatus_Ok, boost::any(list)); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_DatasetAllFiledsAsValMap(CallbackWithStatusArg1 cb) |
| { |
| ValueMap map; |
| mLocalDataset.convert_to_valuemap(map); |
| cb(kWPANTUNDStatus_Ok, boost::any(map)); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_DatasetCommand(CallbackWithStatusArg1 cb) |
| { |
| std::list<std::string> help_string; |
| get_dataset_command_help(help_string); |
| cb(kWPANTUNDStatus_Ok, boost::any(help_string)); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_DaemonTickleOnHostDidWake(CallbackWithStatusArg1 cb) |
| { |
| cb(kWPANTUNDStatus_Ok, boost::any(mTickleOnHostDidWake)); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_POSIXAppRCPVersionCached(CallbackWithStatusArg1 cb) |
| { |
| cb(kWPANTUNDStatus_Ok, boost::any(mRcpVersion)); |
| } |
| |
| void |
| SpinelNCPInstance::get_prop_MACFilterFixedRssi(CallbackWithStatusArg1 cb) |
| { |
| cb(kWPANTUNDStatus_Ok, boost::any(mMacFilterFixedRssi)); |
| } |
| |
| void |
| SpinelNCPInstance::property_get_value( |
| const std::string& key, |
| CallbackWithStatusArg1 cb |
| ) { |
| if (!is_initializing_ncp()) { |
| syslog(LOG_INFO, "property_get_value: key: \"%s\"", key.c_str()); |
| } |
| |
| if (mVendorCustom.is_property_key_supported(key)) { |
| mVendorCustom.property_get_value(key, cb); |
| } else { |
| NCPInstanceBase::property_get_value(key, cb); |
| } |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // Property Set Handlers |
| |
| void |
| SpinelNCPInstance::set_spinel_prop( |
| const boost::any &value, CallbackWithStatus cb, spinel_prop_key_t prop_key, char pack_type, unsigned int capability, |
| bool save_in_settings, const std::string &prop_name) |
| { |
| Data command = SpinelPackData(SPINEL_FRAME_PACK_CMD_PROP_VALUE_SET(SPINEL_DATATYPE_NULL_S), prop_key); |
| int status = SpinelAppendAny(command, value, pack_type); |
| |
| if (status != kWPANTUNDStatus_Ok) { |
| cb(status); |
| } else { |
| |
| if (save_in_settings) { |
| mSettings[prop_name] = SettingsEntry(command, capability); |
| } |
| |
| if (!capability || mCapabilities.count(capability)) { |
| start_new_task(SpinelNCPTaskSendCommand::Factory(this) |
| .set_callback(cb) |
| .add_command(command) |
| .finish() |
| ); |
| } else { |
| cb(kWPANTUNDStatus_FeatureNotSupported); |
| } |
| } |
| } |
| |
| void |
| SpinelNCPInstance::convert_value_prop_set(const boost::any &value, CallbackWithStatus cb, const std::string &prop_name, |
| ValueConverter converter, PropUpdateHandler handler) |
| { |
| boost::any converted_value; |
| int status = converter(value, converted_value); |
| |
| if (status == kWPANTUNDStatus_Ok) { |
| handler(converted_value, cb, prop_name); |
| } else { |
| cb(status); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::register_set_handler(const char *prop_name, PropUpdateHandler handler, ValueConverter converter) |
| { |
| if (converter.empty()) { |
| NCPInstanceBase::register_prop_set_handler(prop_name, handler); |
| } else { |
| |
| // If a `converter` function is given, use `convert_value_prop_set` |
| // which converts the value using the `converter` then passing the |
| // converted value to the original `handler`. |
| NCPInstanceBase::register_prop_set_handler( |
| prop_name, |
| boost::bind(&SpinelNCPInstance::convert_value_prop_set, _1, _2, _3, converter, handler)); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::register_set_handler_spinel(const char *prop_name, spinel_prop_key_t prop_key, char pack_type, |
| ValueConverter converter) |
| { |
| register_set_handler( |
| prop_name, |
| boost::bind(&SpinelNCPInstance::set_spinel_prop, this, _1, _2, prop_key, pack_type, 0, false, _3), |
| converter); |
| } |
| |
| void |
| SpinelNCPInstance::register_set_handler_spinel_persist(const char *prop_name, spinel_prop_key_t prop_key, |
| char pack_type, ValueConverter converter) |
| { |
| register_set_handler( |
| prop_name, |
| boost::bind(&SpinelNCPInstance::set_spinel_prop, this, _1, _2, prop_key, pack_type, 0, true, _3), |
| converter); |
| } |
| |
| void |
| SpinelNCPInstance::register_set_handler_capability_spinel(const char *prop_name, unsigned int capability, |
| spinel_prop_key_t prop_key, char pack_type, ValueConverter converter) |
| { |
| register_set_handler( |
| prop_name, |
| boost::bind(&SpinelNCPInstance::set_spinel_prop, this, _1, _2, prop_key, pack_type, capability, false, _3), |
| converter); |
| } |
| |
| void |
| SpinelNCPInstance::register_set_handler_capability_spinel_persist(const char *prop_name, unsigned int capability, |
| spinel_prop_key_t prop_key, char pack_type, ValueConverter converter) |
| { |
| register_set_handler( |
| prop_name, |
| boost::bind(&SpinelNCPInstance::set_spinel_prop, this, _1, _2, prop_key, pack_type, capability, true, _3), |
| converter); |
| } |
| |
| void |
| SpinelNCPInstance::regsiter_all_set_handlers(void) |
| { |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // Properties associated with a spinel property |
| |
| register_set_handler_spinel( |
| kWPANTUNDProperty_NCPChannel, |
| SPINEL_PROP_PHY_CHAN, SPINEL_DATATYPE_UINT8_C); |
| register_set_handler_spinel( |
| kWPANTUNDProperty_NetworkPANID, |
| SPINEL_PROP_MAC_15_4_PANID, SPINEL_DATATYPE_UINT16_C); |
| register_set_handler_spinel( |
| kWPANTUNDProperty_NetworkPSKc, |
| SPINEL_PROP_NET_PSKC, SPINEL_DATATYPE_DATA_C); |
| register_set_handler_spinel( |
| kWPANTUNDProperty_NetworkPartitionId, |
| SPINEL_PROP_NET_PARTITION_ID, SPINEL_DATATYPE_UINT32_C); |
| register_set_handler_spinel( |
| kWPANTUNDProperty_NCPMACAddress, |
| SPINEL_PROP_MAC_15_4_LADDR, SPINEL_DATATYPE_EUI64_C); |
| register_set_handler_spinel( |
| kWPANTUNDProperty_NCPExtendedAddress, |
| SPINEL_PROP_MAC_EXTENDED_ADDR, SPINEL_DATATYPE_EUI64_C); |
| register_set_handler_spinel( |
| kWPANTUNDProperty_NetworkKeyIndex, |
| SPINEL_PROP_NET_KEY_SEQUENCE_COUNTER, SPINEL_DATATYPE_UINT32_C); |
| register_set_handler_spinel( |
| kWPANTUNDProperty_NetworkKeySwitchGuardTime, |
| SPINEL_PROP_NET_KEY_SWITCH_GUARDTIME, SPINEL_DATATYPE_UINT32_C); |
| register_set_handler_spinel( |
| kWPANTUNDProperty_NetworkName, |
| SPINEL_PROP_NET_NETWORK_NAME, SPINEL_DATATYPE_UTF8_C); |
| register_set_handler_spinel( |
| kWPANTUNDProperty_NetworkRole, |
| SPINEL_PROP_NET_ROLE, SPINEL_DATATYPE_UINT8_C); |
| register_set_handler_spinel( |
| kWPANTUNDProperty_ThreadPreferredRouterID, |
| SPINEL_PROP_THREAD_PREFERRED_ROUTER_ID, SPINEL_DATATYPE_UINT8_C); |
| register_set_handler_spinel( |
| kWPANTUNDProperty_ThreadRouterRoleEnabled, |
| SPINEL_PROP_THREAD_ROUTER_ROLE_ENABLED, SPINEL_DATATYPE_BOOL_C); |
| register_set_handler_spinel( |
| kWPANTUNDProperty_ThreadRouterSelectionJitter, |
| SPINEL_PROP_THREAD_ROUTER_SELECTION_JITTER, SPINEL_DATATYPE_UINT8_C); |
| register_set_handler_spinel( |
| kWPANTUNDProperty_ThreadRouterUpgradeThreshold, |
| SPINEL_PROP_THREAD_ROUTER_UPGRADE_THRESHOLD, SPINEL_DATATYPE_UINT8_C); |
| register_set_handler_spinel( |
| kWPANTUNDProperty_ThreadRouterDowngradeThreshold, |
| SPINEL_PROP_THREAD_ROUTER_DOWNGRADE_THRESHOLD, SPINEL_DATATYPE_UINT8_C); |
| register_set_handler_spinel( |
| kWPANTUNDProperty_OpenThreadTrelTestModeEnable, |
| SPINEL_PROP_DEBUG_TREL_TEST_MODE_ENABLE, SPINEL_DATATYPE_BOOL_C); |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // Properties requiring persistence (saving in settings) and associated with a |
| // spinel property |
| |
| register_set_handler_spinel_persist( |
| kWPANTUNDProperty_NCPCCAThreshold, |
| SPINEL_PROP_PHY_CCA_THRESHOLD, SPINEL_DATATYPE_INT8_C); |
| register_set_handler_spinel_persist( |
| kWPANTUNDProperty_NCPTXPower, |
| SPINEL_PROP_PHY_TX_POWER, SPINEL_DATATYPE_INT8_C); |
| register_set_handler_spinel_persist( |
| kWPANTUNDProperty_ThreadChildTimeout, |
| SPINEL_PROP_THREAD_CHILD_TIMEOUT, SPINEL_DATATYPE_UINT32_C); |
| register_set_handler_spinel_persist( |
| kWPANTUNDProperty_ThreadDeviceMode, |
| SPINEL_PROP_THREAD_MODE, SPINEL_DATATYPE_UINT8_C); |
| register_set_handler_spinel_persist( |
| kWPANTUNDProperty_OpenThreadLogLevel, |
| SPINEL_PROP_DEBUG_NCP_LOG_LEVEL, SPINEL_DATATYPE_UINT8_C); |
| |
| // Properties with a `ValueConverter` |
| register_set_handler_spinel_persist( |
| kWPANTUNDProperty_NCPChannelMask, |
| SPINEL_PROP_PHY_CHAN_SUPPORTED, SPINEL_DATATYPE_DATA_C, |
| &SpinelNCPInstance::convert_value_channel_mask); |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // Properties requiring capability check and associated with a spinel property |
| |
| register_set_handler_capability_spinel( |
| kWPANTUNDProperty_MACAllowlistEnabled, |
| SPINEL_CAP_MAC_ALLOWLIST, |
| SPINEL_PROP_MAC_ALLOWLIST_ENABLED, SPINEL_DATATYPE_BOOL_C); |
| register_set_handler_capability_spinel( |
| kWPANTUNDProperty_MACDenylistEnabled, |
| SPINEL_CAP_MAC_ALLOWLIST, |
| SPINEL_PROP_MAC_DENYLIST_ENABLED, SPINEL_DATATYPE_BOOL_C); |
| register_set_handler_capability_spinel( |
| kWPANTUNDProperty_CommissionerProvisioningUrl, |
| SPINEL_CAP_THREAD_COMMISSIONER, |
| SPINEL_PROP_MESHCOP_COMMISSIONER_PROVISIONING_URL, SPINEL_DATATYPE_UTF8_C); |
| register_set_handler_capability_spinel( |
| kWPANTUNDProperty_CommissionerSendMgmtGet, |
| SPINEL_CAP_THREAD_COMMISSIONER, |
| SPINEL_PROP_MESHCOP_COMMISSIONER_MGMT_GET, SPINEL_DATATYPE_DATA_WLEN_C); |
| register_set_handler_capability_spinel( |
| kWPANTUNDProperty_CommissionerSendMgmtSet, |
| SPINEL_CAP_THREAD_COMMISSIONER, |
| SPINEL_PROP_MESHCOP_COMMISSIONER_MGMT_SET, SPINEL_DATATYPE_DATA_WLEN_C); |
| register_set_handler_capability_spinel( |
| kWPANTUNDProperty_ChannelManagerChannelSelect, |
| SPINEL_CAP_CHANNEL_MANAGER, |
| SPINEL_PROP_CHANNEL_MANAGER_CHANNEL_SELECT, SPINEL_DATATYPE_BOOL_C); |
| register_set_handler_capability_spinel( |
| kWPANTUNDProperty_TimeSync_Period, |
| SPINEL_CAP_TIME_SYNC, |
| SPINEL_PROP_TIME_SYNC_PERIOD, SPINEL_DATATYPE_UINT16_C); |
| register_set_handler_capability_spinel( |
| kWPANTUNDProperty_TimeSync_XtalThreshold, |
| SPINEL_CAP_TIME_SYNC, |
| SPINEL_PROP_TIME_SYNC_XTAL_THRESHOLD, SPINEL_DATATYPE_UINT16_C); |
| register_set_handler_capability_spinel( |
| kWPANTUNDProperty_OpenThreadLogTimestampBase, |
| SPINEL_CAP_OPENTHREAD_LOG_METADATA, |
| SPINEL_PROP_DEBUG_LOG_TIMESTAMP_BASE, SPINEL_DATATYPE_UINT64_C); |
| register_set_handler_capability_spinel( |
| kWPANTUNDProperty_ThreadDomainName, |
| SPINEL_CAP_NET_THREAD_1_2, |
| SPINEL_PROP_THREAD_DOMAIN_NAME, |
| SPINEL_DATATYPE_UTF8_C); |
| |
| register_set_handler_capability_spinel( |
| kWPANTUNDProperty_ThreadCslPeriod, |
| SPINEL_CAP_THREAD_CSL_RECEIVER, |
| SPINEL_PROP_THREAD_CSL_PERIOD, SPINEL_DATATYPE_UINT16_C); |
| register_set_handler_capability_spinel( |
| kWPANTUNDProperty_ThreadCslTimeout, |
| SPINEL_CAP_THREAD_CSL_RECEIVER, |
| SPINEL_PROP_THREAD_CSL_TIMEOUT, SPINEL_DATATYPE_UINT32_C); |
| register_set_handler_capability_spinel( |
| kWPANTUNDProperty_ThreadCslChannel, |
| SPINEL_CAP_THREAD_CSL_RECEIVER, |
| SPINEL_PROP_THREAD_CSL_CHANNEL, SPINEL_DATATYPE_UINT8_C); |
| register_set_handler_capability_spinel( |
| kWPANTUNDProperty_ThreadBackboneRouterLocalJitter, |
| SPINEL_CAP_THREAD_BACKBONE_ROUTER, |
| SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_REGISTRATION_JITTER, SPINEL_DATATYPE_UINT8_C); |
| |
| // Properties with a `ValueConverter` |
| register_set_handler_capability_spinel( |
| kWPANTUNDProperty_CommissionerState, |
| SPINEL_CAP_THREAD_COMMISSIONER, |
| SPINEL_PROP_MESHCOP_COMMISSIONER_STATE, SPINEL_DATATYPE_UINT8_C, |
| &SpinelNCPInstance::convert_value_CommissionerState); |
| register_set_handler_capability_spinel( |
| kWPANTUNDProperty_NCPCounterAllReset, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_RESET, SPINEL_DATATYPE_UINT8_C, |
| &SpinelNCPInstance::convert_value_counter_reset); |
| register_set_handler_capability_spinel( |
| kWPANTUNDProperty_NCPCounterAllMac, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_ALL_MAC_COUNTERS, SPINEL_DATATYPE_UINT8_C, |
| &SpinelNCPInstance::convert_value_counter_reset); |
| register_set_handler_capability_spinel( |
| kWPANTUNDProperty_NCPCounterThreadMle, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_MLE_COUNTERS, SPINEL_DATATYPE_UINT8_C, |
| &SpinelNCPInstance::convert_value_counter_reset); |
| register_set_handler_capability_spinel( |
| kWPANTUNDProperty_NCPCounterAllIPv6, |
| SPINEL_CAP_COUNTERS, |
| SPINEL_PROP_CNTR_ALL_IP_COUNTERS, SPINEL_DATATYPE_UINT8_C, |
| &SpinelNCPInstance::convert_value_counter_reset); |
| register_set_handler_capability_spinel( |
| kWPANTUNDProperty_ThreadDUAInterfaceIdentifier, |
| SPINEL_CAP_DUA, |
| SPINEL_PROP_THREAD_DUA_ID, SPINEL_DATATYPE_DATA_C, |
| &SpinelNCPInstance::convert_value_dua_interface_identifier); |
| register_set_handler_capability_spinel( |
| kWPANTUNDProperty_ThreadBackboneRouterLocalState, |
| SPINEL_CAP_THREAD_BACKBONE_ROUTER, |
| SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_STATE, SPINEL_DATATYPE_UINT8_C, |
| &SpinelNCPInstance::convert_value_BackboneRouterState); |
| register_set_handler_capability_spinel( |
| kWPANTUNDProperty_ThreadBackboneRouterLocalRegister, |
| SPINEL_CAP_THREAD_BACKBONE_ROUTER, |
| SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_REGISTER, SPINEL_DATATYPE_UINT8_C, |
| &SpinelNCPInstance::convert_value_BackboneRouterRegister); |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // Properties requiring capability check and persistence (saving in settings), |
| // and associated with a spinel property |
| |
| register_set_handler_capability_spinel_persist( |
| kWPANTUNDProperty_NCPSleepyPollInterval, |
| SPINEL_CAP_ROLE_SLEEPY, |
| SPINEL_PROP_MAC_DATA_POLL_PERIOD, SPINEL_DATATYPE_UINT32_C); |
| register_set_handler_capability_spinel_persist( |
| kWPANTUNDProperty_TmfProxyEnabled, |
| SPINEL_CAP_THREAD_TMF_PROXY, |
| SPINEL_PROP_THREAD_TMF_PROXY_ENABLED, SPINEL_DATATYPE_BOOL_C); |
| register_set_handler_capability_spinel_persist( |
| kWPANTUNDProperty_JamDetectionEnable, |
| SPINEL_CAP_JAM_DETECT, |
| SPINEL_PROP_JAM_DETECT_ENABLE, SPINEL_DATATYPE_BOOL_C); |
| register_set_handler_capability_spinel_persist( |
| kWPANTUNDProperty_JamDetectionRssiThreshold, |
| SPINEL_CAP_JAM_DETECT, |
| SPINEL_PROP_JAM_DETECT_RSSI_THRESHOLD, SPINEL_DATATYPE_INT8_C); |
| register_set_handler_capability_spinel_persist( |
| kWPANTUNDProperty_JamDetectionWindow, |
| SPINEL_CAP_JAM_DETECT, |
| SPINEL_PROP_JAM_DETECT_WINDOW, SPINEL_DATATYPE_UINT8_C); |
| register_set_handler_capability_spinel_persist( |
| kWPANTUNDProperty_JamDetectionBusyPeriod, |
| SPINEL_CAP_JAM_DETECT, |
| SPINEL_PROP_JAM_DETECT_BUSY, SPINEL_DATATYPE_UINT8_C); |
| register_set_handler_capability_spinel_persist( |
| kWPANTUNDProperty_NestLabs_LegacyMeshLocalPrefix, |
| SPINEL_CAP_NEST_LEGACY_INTERFACE, |
| SPINEL_PROP_NEST_LEGACY_ULA_PREFIX, SPINEL_DATATYPE_DATA_C); |
| register_set_handler_capability_spinel_persist( |
| kWPANTUNDProperty_ChildSupervisionInterval, |
| SPINEL_CAP_CHILD_SUPERVISION, |
| SPINEL_PROP_CHILD_SUPERVISION_INTERVAL, SPINEL_DATATYPE_UINT16_C); |
| register_set_handler_capability_spinel_persist( |
| kWPANTUNDProperty_ChildSupervisionCheckTimeout, |
| SPINEL_CAP_CHILD_SUPERVISION, |
| SPINEL_PROP_CHILD_SUPERVISION_CHECK_TIMEOUT, SPINEL_DATATYPE_UINT16_C); |
| register_set_handler_capability_spinel_persist( |
| kWPANTUNDProperty_ChannelManagerNewChannel, |
| SPINEL_CAP_CHANNEL_MANAGER, |
| SPINEL_PROP_CHANNEL_MANAGER_NEW_CHANNEL, SPINEL_DATATYPE_UINT8_C); |
| register_set_handler_capability_spinel_persist( |
| kWPANTUNDProperty_ChannelManagerDelay, |
| SPINEL_CAP_CHANNEL_MANAGER, |
| SPINEL_PROP_CHANNEL_MANAGER_DELAY, SPINEL_DATATYPE_UINT16_C); |
| register_set_handler_capability_spinel_persist( |
| kWPANTUNDProperty_ChannelManagerAutoSelectEnabled, |
| SPINEL_CAP_CHANNEL_MANAGER, |
| SPINEL_PROP_CHANNEL_MANAGER_AUTO_SELECT_ENABLED, SPINEL_DATATYPE_BOOL_C); |
| register_set_handler_capability_spinel_persist( |
| kWPANTUNDProperty_ChannelManagerAutoSelectInterval, |
| SPINEL_CAP_CHANNEL_MANAGER, |
| SPINEL_PROP_CHANNEL_MANAGER_AUTO_SELECT_INTERVAL, SPINEL_DATATYPE_UINT32_C); |
| register_set_handler_capability_spinel_persist( |
| kWPANTUNDProperty_OpenThreadSLAACEnabled, |
| SPINEL_CAP_SLAAC, |
| SPINEL_PROP_SLAAC_ENABLED, SPINEL_DATATYPE_BOOL_C); |
| register_set_handler_capability_spinel_persist( |
| kWPANTUNDProperty_NCPCoexEnable, |
| SPINEL_CAP_RADIO_COEX, |
| SPINEL_PROP_RADIO_COEX_ENABLE, SPINEL_DATATYPE_BOOL_C); |
| |
| // Properties with a `ValueConverter` |
| register_set_handler_capability_spinel_persist( |
| kWPANTUNDProperty_NCPMCUPowerState, |
| SPINEL_PROP_MCU_POWER_STATE, |
| SPINEL_PROP_MCU_POWER_STATE, SPINEL_DATATYPE_UINT8_C, |
| &SpinelNCPInstance::convert_value_NCPMCUPowerState); |
| register_set_handler_capability_spinel_persist( |
| kWPANTUNDProperty_ChannelManagerSupportedChannelMask, |
| SPINEL_CAP_CHANNEL_MANAGER, |
| SPINEL_PROP_CHANNEL_MANAGER_SUPPORTED_CHANNELS, SPINEL_DATATYPE_DATA_C, |
| &SpinelNCPInstance::convert_value_channel_mask); |
| register_set_handler_capability_spinel_persist( |
| kWPANTUNDProperty_ChannelManagerFavoredChannelMask, |
| SPINEL_CAP_CHANNEL_MANAGER, |
| SPINEL_PROP_CHANNEL_MANAGER_FAVORED_CHANNELS, SPINEL_DATATYPE_DATA_C, |
| &SpinelNCPInstance::convert_value_channel_mask); |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| // Properties with a dedicated handler method |
| |
| register_set_handler( |
| kWPANTUNDProperty_NetworkKey, |
| boost::bind(&SpinelNCPInstance::set_prop_NetworkKey, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_InterfaceUp, |
| boost::bind(&SpinelNCPInstance::set_prop_InterfaceUp, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_NetworkXPANID, |
| boost::bind(&SpinelNCPInstance::set_prop_NetworkXPANID, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_IPv6MeshLocalPrefix, |
| boost::bind(&SpinelNCPInstance::set_prop_IPv6MeshLocalPrefix, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_ThreadConfigFilterRLOCAddresses, |
| boost::bind(&SpinelNCPInstance::set_prop_ThreadConfigFilterRLOCAddresses, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_ThreadConfigFilterALOCAddresses, |
| boost::bind(&SpinelNCPInstance::set_prop_ThreadConfigFilterALOCAddresses, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_OpenThreadSteeringDataSetWhenJoinable, |
| boost::bind(&SpinelNCPInstance::set_prop_OpenThreadSteeringDataSetWhenJoinable, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_OpenThreadSteeringDataAddress, |
| boost::bind(&SpinelNCPInstance::set_prop_OpenThreadSteeringDataAddress, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_TmfProxyStream, |
| boost::bind(&SpinelNCPInstance::set_prop_TmfProxyStream, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_UdpForwardStream, |
| boost::bind(&SpinelNCPInstance::set_prop_UdpForwardStream, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_DatasetActiveTimestamp, |
| boost::bind(&SpinelNCPInstance::set_prop_DatasetActiveTimestamp, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_DatasetPendingTimestamp, |
| boost::bind(&SpinelNCPInstance::set_prop_DatasetPendingTimestamp, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_DatasetMasterKey, |
| boost::bind(&SpinelNCPInstance::set_prop_DatasetMasterKey, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_DatasetNetworkName, |
| boost::bind(&SpinelNCPInstance::set_prop_DatasetNetworkName, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_DatasetExtendedPanId, |
| boost::bind(&SpinelNCPInstance::set_prop_DatasetExtendedPanId, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_DatasetMeshLocalPrefix, |
| boost::bind(&SpinelNCPInstance::set_prop_DatasetMeshLocalPrefix, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_DatasetDelay, |
| boost::bind(&SpinelNCPInstance::set_prop_DatasetDelay, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_DatasetPanId, |
| boost::bind(&SpinelNCPInstance::set_prop_DatasetPanId, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_DatasetChannel, |
| boost::bind(&SpinelNCPInstance::set_prop_DatasetChannel, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_DatasetPSKc, |
| boost::bind(&SpinelNCPInstance::set_prop_DatasetPSKc, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_DatasetChannelMaskPage0, |
| boost::bind(&SpinelNCPInstance::set_prop_DatasetChannelMaskPage0, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_DatasetSecPolicyKeyRotation, |
| boost::bind(&SpinelNCPInstance::set_prop_DatasetSecPolicyKeyRotation, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_DatasetSecPolicyFlags, |
| boost::bind(&SpinelNCPInstance::set_prop_DatasetSecPolicyFlags, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_DatasetRawTlvs, |
| boost::bind(&SpinelNCPInstance::set_prop_DatasetRawTlvs, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_DatasetDestIpAddress, |
| boost::bind(&SpinelNCPInstance::set_prop_DatasetDestIpAddress, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_DatasetCommand, |
| boost::bind(&SpinelNCPInstance::set_prop_DatasetCommand, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_DaemonTickleOnHostDidWake, |
| boost::bind(&SpinelNCPInstance::set_prop_DaemonTickleOnHostDidWake, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_MACFilterFixedRssi, |
| boost::bind(&SpinelNCPInstance::set_prop_MACFilterFixedRssi, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_JoinerDiscernerBitLength, |
| boost::bind(&SpinelNCPInstance::set_prop_JoinerDiscernerBitLength, this, _1, _2)); |
| register_set_handler( |
| kWPANTUNDProperty_JoinerDiscernerValue, |
| boost::bind(&SpinelNCPInstance::set_prop_JoinerDiscernerValue, this, _1, _2)); |
| } |
| |
| int |
| SpinelNCPInstance::convert_value_NCPMCUPowerState(const boost::any &value, boost::any &value_out) |
| { |
| int ret = kWPANTUNDStatus_Ok; |
| std::string str = any_to_string(value); |
| |
| if (strcaseequal(str.c_str(), kWPANTUNDNCPMCUPowerState_On)) { |
| value_out = static_cast<uint8_t>(SPINEL_MCU_POWER_STATE_ON); |
| } else if (strcaseequal(str.c_str(), kWPANTUNDNCPMCUPowerState_LowPower) || strcaseequal(str.c_str(), "lp")) { |
| value_out = static_cast<uint8_t>(SPINEL_MCU_POWER_STATE_LOW_POWER); |
| } else if (strcaseequal(str.c_str(), "kWPANTUNDNCPMCUPowerState_Off")) { |
| value_out = static_cast<uint8_t>(SPINEL_MCU_POWER_STATE_OFF); |
| } else { |
| ret = kWPANTUNDStatus_InvalidArgument; |
| } |
| |
| return ret; |
| } |
| |
| int |
| SpinelNCPInstance::convert_value_channel_mask(const boost::any &value, boost::any &value_out) |
| { |
| uint32_t channel_mask = any_to_int(value); |
| Data mask_array(32); |
| |
| mask_array.clear(); |
| for (uint8_t channel = 0; channel < 32; channel++) { |
| if (channel_mask & (1U << channel)) { |
| mask_array.push_back(channel); |
| } |
| } |
| |
| value_out = mask_array; |
| return kWPANTUNDStatus_Ok; |
| } |
| |
| int |
| SpinelNCPInstance::convert_value_counter_reset(const boost::any &value, boost::any &value_out) |
| { |
| // When reseting all/subset of counters, the value written to |
| // related spinel property does not matter, so we just write |
| // value `1`. |
| |
| (void)value; |
| value_out = 1; |
| return kWPANTUNDStatus_Ok; |
| } |
| |
| int |
| SpinelNCPInstance::convert_value_CommissionerState(const boost::any &value, boost::any &value_out) |
| { |
| int ret = kWPANTUNDStatus_Ok; |
| std::string state_str = any_to_string(value); |
| const char *str = state_str.c_str(); |
| |
| if (strcaseequal(str, kWPANTUNDCommissionerState_Disabled) || strcaseequal(str, "stop") || strcaseequal(str, "off") |
| || strcaseequal(str, "0") || strcaseequal(str, "false") |
| ) { |
| value_out = static_cast<uint8_t>(SPINEL_MESHCOP_COMMISSIONER_STATE_DISABLED); |
| |
| } else if (strcaseequal(str, kWPANTUNDCommissionerState_Active) || strcaseequal(str, "start") || |
| strcaseequal(str, "on") || strcaseequal(str, "1") || strcaseequal(str, "true") |
| ) { |
| value_out = static_cast<uint8_t>(SPINEL_MESHCOP_COMMISSIONER_STATE_ACTIVE); |
| |
| } else { |
| ret = kWPANTUNDStatus_InvalidArgument; |
| } |
| |
| return ret; |
| } |
| |
| int |
| SpinelNCPInstance::convert_value_dua_interface_identifier(const boost::any &value, boost::any &value_out) |
| { |
| std::string state_str = any_to_string(value); |
| Data data; |
| int ret = kWPANTUNDStatus_Ok; |
| |
| if (state_str.length() == 16) |
| { |
| data.resize(8); |
| parse_string_into_data(data.data(), data.size(), state_str.c_str()); |
| } |
| else if (state_str.length() != 0) |
| { |
| ret = kWPANTUNDStatus_InvalidArgument; |
| } |
| else |
| { |
| // Intentionally leave empty data when state_str.length() == 0 |
| } |
| |
| value_out = data; |
| return ret; |
| } |
| |
| int |
| SpinelNCPInstance::convert_value_BackboneRouterState(const boost::any &value, boost::any &value_out) |
| { |
| int ret = kWPANTUNDStatus_Ok; |
| std::string state_str = any_to_string(value); |
| const char *str = state_str.c_str(); |
| |
| if (strcaseequal(str, kWPANTUNDThreadBackboneRouterState_Disabled) || strcaseequal(str, "stop") || strcaseequal(str, "off") |
| || strcaseequal(str, "0") || strcaseequal(str, "false") || strcaseequal(str, "disable") |
| ) { |
| value_out = static_cast<uint8_t>(SPINEL_THREAD_BACKBONE_ROUTER_STATE_DISABLED); |
| |
| } else if (strcaseequal(str, kWPANTUNDThreadBackboneRouterState_Primary) || strcaseequal(str, "start") || |
| strcaseequal(str, "on") || strcaseequal(str, "1") || strcaseequal(str, "true") || strcaseequal(str, "enable") |
| ) { |
| value_out = static_cast<uint8_t>(SPINEL_THREAD_BACKBONE_ROUTER_STATE_PRIMARY); |
| |
| } else { |
| ret = kWPANTUNDStatus_InvalidArgument; |
| } |
| |
| return ret; |
| } |
| |
| int |
| SpinelNCPInstance::convert_value_BackboneRouterRegister(const boost::any &value, boost::any &value_out) |
| { |
| // The value written to related spinel property does not matter, |
| // so we just write value `1`. |
| |
| (void)value; |
| value_out = 1; |
| return kWPANTUNDStatus_Ok; |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_NetworkKey(const boost::any &value, CallbackWithStatus cb) |
| { |
| Data network_key = any_to_data(value); |
| |
| if (!ncp_state_is_joining_or_joined(get_ncp_state())) { |
| mNetworkKey = network_key; |
| if (mNetworkKeyIndex == 0) { |
| mNetworkKeyIndex = 1; |
| } |
| } |
| |
| if (get_ncp_state() == CREDENTIALS_NEEDED) { |
| ValueMap options; |
| options[kWPANTUNDProperty_NetworkKey] = value; |
| start_new_task(boost::shared_ptr<SpinelNCPTask>( |
| new SpinelNCPTaskJoin( |
| this, |
| boost::bind(cb,_1), |
| options |
| ) |
| )); |
| } else { |
| set_spinel_prop(value, cb, SPINEL_PROP_NET_MASTER_KEY, SPINEL_DATATYPE_DATA_C); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_InterfaceUp(const boost::any &value, CallbackWithStatus cb) |
| { |
| bool isup = any_to_bool(value); |
| |
| if (isup) { |
| start_new_task(SpinelNCPTaskSendCommand::Factory(this) |
| .set_callback(cb) |
| .add_command(SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_SET(SPINEL_DATATYPE_BOOL_S), |
| SPINEL_PROP_NET_IF_UP, |
| true |
| )) |
| .add_command(SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_SET(SPINEL_DATATYPE_BOOL_S), |
| SPINEL_PROP_NET_STACK_UP, |
| true |
| )) |
| .finish() |
| ); |
| } else { |
| start_new_task(SpinelNCPTaskSendCommand::Factory(this) |
| .set_callback(cb) |
| .add_command(SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_SET(SPINEL_DATATYPE_BOOL_S), |
| SPINEL_PROP_NET_STACK_UP, |
| false |
| )) |
| .add_command(SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_SET(SPINEL_DATATYPE_BOOL_S), |
| SPINEL_PROP_NET_IF_UP, |
| false |
| )) |
| .finish() |
| ); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_NetworkXPANID(const boost::any &value, CallbackWithStatus cb) |
| { |
| mXPANIDWasExplicitlySet = true; |
| set_spinel_prop(value, cb, SPINEL_PROP_NET_XPANID, SPINEL_DATATYPE_DATA_C); |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_IPv6MeshLocalPrefix(const boost::any &value, CallbackWithStatus cb) |
| { |
| struct in6_addr addr = any_to_ipv6(value); |
| |
| start_new_task(SpinelNCPTaskSendCommand::Factory(this) |
| .set_callback(cb) |
| .add_command(SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_SET(SPINEL_DATATYPE_IPv6ADDR_S SPINEL_DATATYPE_UINT8_S), |
| SPINEL_PROP_IPV6_ML_PREFIX, |
| &addr, |
| 64 |
| )) |
| .finish() |
| ); |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_ThreadConfigFilterRLOCAddresses(const boost::any &value, CallbackWithStatus cb) |
| { |
| mFilterRLOCAddresses = any_to_bool(value); |
| cb(kWPANTUNDStatus_Ok); |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_ThreadConfigFilterALOCAddresses(const boost::any &value, CallbackWithStatus cb) |
| { |
| mFilterALOCAddresses = any_to_bool(value); |
| cb(kWPANTUNDStatus_Ok); |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_OpenThreadSteeringDataSetWhenJoinable(const boost::any &value, CallbackWithStatus cb) |
| { |
| mSetSteeringDataWhenJoinable = any_to_bool(value); |
| cb(kWPANTUNDStatus_Ok); |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_OpenThreadSteeringDataAddress(const boost::any &value, CallbackWithStatus cb) |
| { |
| Data address = any_to_data(value); |
| wpantund_status_t status = kWPANTUNDStatus_Ok; |
| |
| if (address.size() != sizeof(mSteeringDataAddress)) { |
| status = kWPANTUNDStatus_InvalidArgument; |
| } else { |
| memcpy(mSteeringDataAddress, address.data(), sizeof(mSteeringDataAddress)); |
| } |
| |
| cb (status); |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_TmfProxyStream(const boost::any &value, CallbackWithStatus cb) |
| { |
| Data packet = any_to_data(value); |
| |
| if (packet.size() > sizeof(uint16_t)*2) { |
| uint16_t port = (packet[packet.size() - sizeof(port)] << 8 | packet[packet.size() - sizeof(port) + 1]); |
| uint16_t locator = (packet[packet.size() - sizeof(locator) - sizeof(port)] << 8 | |
| packet[packet.size() - sizeof(locator) - sizeof(port) + 1]); |
| |
| packet.resize(packet.size() - sizeof(locator) - sizeof(port)); |
| |
| Data command = SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_SET( |
| SPINEL_DATATYPE_DATA_WLEN_S |
| SPINEL_DATATYPE_UINT16_S |
| SPINEL_DATATYPE_UINT16_S |
| ), |
| SPINEL_PROP_THREAD_TMF_PROXY_STREAM, |
| packet.data(), |
| packet.size(), |
| locator, |
| port |
| ); |
| |
| start_new_task(SpinelNCPTaskSendCommand::Factory(this) |
| .set_callback(cb) |
| .add_command(command) |
| .finish() |
| ); |
| } else { |
| cb(kWPANTUNDStatus_InvalidArgument); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_UdpForwardStream(const boost::any &value, CallbackWithStatus cb) |
| { |
| Data packet = any_to_data(value); |
| |
| if (packet.size() > sizeof(uint16_t) * 2 + sizeof(in6_addr)) { |
| in6_addr peer_addr; |
| const size_t payload_len = packet.size() - sizeof(uint16_t) * 2 - sizeof(struct in6_addr); |
| size_t i = payload_len; |
| const uint16_t peer_port = (packet[i] << 8 | packet[i + 1]); |
| i += sizeof(uint16_t); |
| memcpy(peer_addr.s6_addr, &packet[i], sizeof(peer_addr)); |
| i += sizeof(peer_addr); |
| const uint16_t sock_port = (packet[i] << 8 | packet[i + 1]); |
| |
| Data command = SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_SET( |
| SPINEL_DATATYPE_DATA_WLEN_S |
| SPINEL_DATATYPE_UINT16_S // Peer port |
| SPINEL_DATATYPE_IPv6ADDR_S // Peer address |
| SPINEL_DATATYPE_UINT16_S // Sock port |
| ), |
| SPINEL_PROP_THREAD_UDP_FORWARD_STREAM, |
| packet.data(), |
| payload_len, |
| peer_port, |
| &peer_addr, |
| sock_port |
| ); |
| |
| start_new_task(SpinelNCPTaskSendCommand::Factory(this) |
| .set_callback(cb) |
| .add_command(command) |
| .finish() |
| ); |
| } else { |
| cb(kWPANTUNDStatus_InvalidArgument); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_DatasetActiveTimestamp(const boost::any &value, CallbackWithStatus cb) |
| { |
| mLocalDataset.mActiveTimestamp = any_to_uint64(value); |
| cb(kWPANTUNDStatus_Ok); |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_DatasetPendingTimestamp(const boost::any &value, CallbackWithStatus cb) |
| { |
| mLocalDataset.mPendingTimestamp = any_to_uint64(value); |
| cb(kWPANTUNDStatus_Ok); |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_DatasetMasterKey(const boost::any &value, CallbackWithStatus cb) |
| { |
| Data master_key = any_to_data(value); |
| |
| if (master_key.size() == NCP_NETWORK_KEY_SIZE) { |
| mLocalDataset.mMasterKey = master_key; |
| cb(kWPANTUNDStatus_Ok); |
| } else { |
| cb(kWPANTUNDStatus_InvalidArgument); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_DatasetNetworkName(const boost::any &value, CallbackWithStatus cb) |
| { |
| mLocalDataset.mNetworkName = any_to_string(value); |
| cb(kWPANTUNDStatus_Ok); |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_DatasetExtendedPanId(const boost::any &value, CallbackWithStatus cb) |
| { |
| Data xpanid = any_to_data(value); |
| |
| if (xpanid.size() == sizeof(spinel_net_xpanid_t)) { |
| mLocalDataset.mExtendedPanId = any_to_data(value); |
| cb(kWPANTUNDStatus_Ok); |
| } else { |
| cb(kWPANTUNDStatus_InvalidArgument); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_DatasetMeshLocalPrefix(const boost::any &value, CallbackWithStatus cb) |
| { |
| mLocalDataset.mMeshLocalPrefix = any_to_ipv6(value); |
| cb(kWPANTUNDStatus_Ok); |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_DatasetDelay(const boost::any &value, CallbackWithStatus cb) |
| { |
| mLocalDataset.mDelay = static_cast<uint32_t>(any_to_int(value)); |
| cb(kWPANTUNDStatus_Ok); |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_DatasetPanId(const boost::any &value, CallbackWithStatus cb) |
| { |
| mLocalDataset.mPanId = static_cast<uint16_t>(any_to_int(value)); |
| cb(kWPANTUNDStatus_Ok); |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_DatasetChannel(const boost::any &value, CallbackWithStatus cb) |
| { |
| mLocalDataset.mChannel = static_cast<uint8_t>(any_to_int(value)); |
| cb(kWPANTUNDStatus_Ok); |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_DatasetPSKc(const boost::any &value, CallbackWithStatus cb) |
| { |
| Data pskc = any_to_data(value); |
| |
| if (pskc.size() <= sizeof(spinel_net_pskc_t)) { |
| mLocalDataset.mPSKc = any_to_data(value); |
| cb(kWPANTUNDStatus_Ok); |
| } else { |
| cb(kWPANTUNDStatus_InvalidArgument); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_DatasetChannelMaskPage0(const boost::any &value, CallbackWithStatus cb) |
| { |
| mLocalDataset.mChannelMaskPage0 = static_cast<uint32_t>(any_to_int(value)); |
| cb(kWPANTUNDStatus_Ok); |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_DatasetSecPolicyKeyRotation(const boost::any &value, CallbackWithStatus cb) |
| { |
| ThreadDataset::SecurityPolicy policy = mLocalDataset.mSecurityPolicy.get(); |
| policy.mKeyRotationTime = static_cast<uint16_t>(any_to_int(value)); |
| mLocalDataset.mSecurityPolicy = policy; |
| cb(kWPANTUNDStatus_Ok); |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_DatasetSecPolicyFlags(const boost::any &value, CallbackWithStatus cb) |
| { |
| ThreadDataset::SecurityPolicy policy = mLocalDataset.mSecurityPolicy.get(); |
| policy.mFlags = static_cast<uint8_t>(any_to_int(value)); |
| mLocalDataset.mSecurityPolicy = policy; |
| cb(kWPANTUNDStatus_Ok); |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_DatasetRawTlvs(const boost::any &value, CallbackWithStatus cb) |
| { |
| mLocalDataset.mRawTlvs = any_to_data(value); |
| cb(kWPANTUNDStatus_Ok); |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_DatasetDestIpAddress(const boost::any &value, CallbackWithStatus cb) |
| { |
| mLocalDataset.mDestIpAddress = any_to_ipv6(value); |
| cb(kWPANTUNDStatus_Ok); |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_DatasetCommand(const boost::any &value, CallbackWithStatus cb) |
| { |
| perform_dataset_command(any_to_string(value), cb); |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_DaemonTickleOnHostDidWake(const boost::any &value, CallbackWithStatus cb) |
| { |
| mTickleOnHostDidWake = any_to_bool(value); |
| syslog(LOG_INFO, "TickleOnHostDidWake is %sabled", mTickleOnHostDidWake ? "en" : "dis"); |
| cb(kWPANTUNDStatus_Ok); |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_MACFilterFixedRssi(const boost::any &value, CallbackWithStatus cb) |
| { |
| if (mCapabilities.count(SPINEL_CAP_MAC_ALLOWLIST)) { |
| mMacFilterFixedRssi = static_cast<int8_t>(any_to_int(value)); |
| cb(kWPANTUNDStatus_Ok); |
| } else { |
| cb(kWPANTUNDStatus_FeatureNotSupported); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_JoinerDiscernerBitLength(const boost::any &value, CallbackWithStatus cb) |
| { |
| if (mCapabilities.count(SPINEL_CAP_THREAD_JOINER)) { |
| mJoinerDiscernerBitLength = static_cast<uint8_t>(any_to_int(value)); |
| |
| // Setting Discerner length to zero is to clear any previous set Discerner value |
| if (mJoinerDiscernerBitLength == 0) { |
| |
| start_new_task(SpinelNCPTaskSendCommand::Factory(this) |
| .set_callback(cb) |
| .add_command(SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_SET(SPINEL_DATATYPE_UINT8_S), |
| SPINEL_PROP_MESHCOP_JOINER_DISCERNER, |
| mJoinerDiscernerBitLength |
| )) |
| .finish() |
| ); |
| |
| } else { |
| cb(kWPANTUNDStatus_Ok); |
| } |
| |
| } else { |
| cb(kWPANTUNDStatus_FeatureNotSupported); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::set_prop_JoinerDiscernerValue(const boost::any &value, CallbackWithStatus cb) |
| { |
| if (mCapabilities.count(SPINEL_CAP_THREAD_JOINER)) { |
| uint64_t discerner_value = any_to_uint64(value); |
| |
| start_new_task(SpinelNCPTaskSendCommand::Factory(this) |
| .set_callback(cb) |
| .add_command(SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_SET( |
| SPINEL_DATATYPE_UINT8_S |
| SPINEL_DATATYPE_UINT64_S |
| ), |
| SPINEL_PROP_MESHCOP_JOINER_DISCERNER, |
| mJoinerDiscernerBitLength, |
| discerner_value |
| )) |
| .finish() |
| ); |
| |
| } else { |
| cb(kWPANTUNDStatus_FeatureNotSupported); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::property_set_value( |
| const std::string& key, |
| const boost::any& value, |
| CallbackWithStatus cb |
| ) { |
| syslog(LOG_INFO, "property_set_value: key: \"%s\"", key.c_str()); |
| |
| // If we are disabled, then the only property we |
| // are allowed to set is kWPANTUNDProperty_DaemonEnabled. |
| if (!mEnabled && !strcaseequal(key.c_str(), kWPANTUNDProperty_DaemonEnabled)) { |
| cb(kWPANTUNDStatus_InvalidWhenDisabled); |
| return; |
| } |
| |
| try { |
| if (mVendorCustom.is_property_key_supported(key)) { |
| mVendorCustom.property_set_value(key, value, cb); |
| |
| } else { |
| NCPInstanceBase::property_set_value(key, value, cb); |
| } |
| |
| } catch (const boost::bad_any_cast &x) { |
| // We will get a bad_any_cast exception if the property is of |
| // the wrong type. |
| syslog(LOG_ERR,"property_set_value: Bad type for property \"%s\" (%s)", key.c_str(), x.what()); |
| cb(kWPANTUNDStatus_InvalidArgument); |
| } catch (const std::invalid_argument &x) { |
| // We will get a bad_any_cast exception if the property is of |
| // the wrong type. |
| syslog(LOG_ERR,"property_set_value: Invalid argument for property \"%s\" (%s)", key.c_str(), x.what()); |
| cb(kWPANTUNDStatus_InvalidArgument); |
| } |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // Property Insert Handlers |
| |
| void |
| SpinelNCPInstance::check_capability_prop_update(const boost::any &value, CallbackWithStatus cb, |
| const std::string &prop_name, unsigned int capability, PropUpdateHandler handler) |
| { |
| if (mCapabilities.count(capability)) { |
| handler(value, cb, prop_name); |
| } else { |
| cb(kWPANTUNDStatus_FeatureNotSupported); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::register_insert_handler(const char *prop_name, PropUpdateHandler handler) |
| { |
| NCPInstanceBase::register_prop_insert_handler(prop_name, handler); |
| } |
| |
| void |
| SpinelNCPInstance::register_insert_handler_capability(const char *prop_name, unsigned int capability, |
| PropUpdateHandler handler) |
| { |
| register_insert_handler( |
| prop_name, |
| boost::bind(&SpinelNCPInstance::check_capability_prop_update, this, _1, _2, _3, capability, handler)); |
| } |
| |
| void |
| SpinelNCPInstance::regsiter_all_insert_handlers(void) |
| { |
| register_insert_handler_capability( |
| kWPANTUNDProperty_MACAllowlistEntries, |
| SPINEL_CAP_MAC_ALLOWLIST, |
| boost::bind(&SpinelNCPInstance::insert_prop_MACAllowlistEntries, this, _1, _2)); |
| register_insert_handler_capability( |
| kWPANTUNDProperty_MACDenylistEntries, |
| SPINEL_CAP_MAC_ALLOWLIST, |
| boost::bind(&SpinelNCPInstance::insert_prop_MACDenylistEntries, this, _1, _2)); |
| register_insert_handler_capability( |
| kWPANTUNDProperty_MACFilterEntries, |
| SPINEL_CAP_MAC_ALLOWLIST, |
| boost::bind(&SpinelNCPInstance::insert_prop_MACFilterEntries, this, _1, _2)); |
| } |
| |
| void |
| SpinelNCPInstance::insert_prop_MACAllowlistEntries(const boost::any &value, CallbackWithStatus cb) |
| { |
| Data ext_address = any_to_data(value); |
| int8_t rssi = kWPANTUND_Allowlist_RssiOverrideDisabled; |
| |
| if (ext_address.size() == sizeof(spinel_eui64_t)) { |
| start_new_task(SpinelNCPTaskSendCommand::Factory(this) |
| .set_callback(cb) |
| .add_command( |
| SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_INSERT(SPINEL_DATATYPE_EUI64_S SPINEL_DATATYPE_INT8_S), |
| SPINEL_PROP_MAC_ALLOWLIST, |
| ext_address.data(), |
| rssi |
| ) |
| ) |
| .finish() |
| ); |
| } else { |
| cb(kWPANTUNDStatus_InvalidArgument); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::insert_prop_MACDenylistEntries(const boost::any &value, CallbackWithStatus cb) |
| { |
| Data ext_address = any_to_data(value); |
| int8_t rssi = kWPANTUND_Allowlist_RssiOverrideDisabled; |
| |
| if (ext_address.size() == sizeof(spinel_eui64_t)) { |
| start_new_task(SpinelNCPTaskSendCommand::Factory(this) |
| .set_callback(cb) |
| .add_command( |
| SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_INSERT(SPINEL_DATATYPE_EUI64_S SPINEL_DATATYPE_INT8_S), |
| SPINEL_PROP_MAC_DENYLIST, |
| ext_address.data(), |
| rssi |
| ) |
| ) |
| .finish() |
| ); |
| } else { |
| cb(kWPANTUNDStatus_InvalidArgument); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::insert_prop_MACFilterEntries(const boost::any &value, CallbackWithStatus cb) |
| { |
| Data ext_address = any_to_data(value); |
| |
| if (ext_address.size() == sizeof(spinel_eui64_t)) { |
| start_new_task(SpinelNCPTaskSendCommand::Factory(this) |
| .set_callback(cb) |
| .add_command( |
| SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_INSERT(SPINEL_DATATYPE_EUI64_S SPINEL_DATATYPE_INT8_S), |
| SPINEL_PROP_MAC_FIXED_RSS, |
| ext_address.data(), |
| mMacFilterFixedRssi |
| ) |
| ) |
| .finish() |
| ); |
| } else { |
| cb(kWPANTUNDStatus_InvalidArgument); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::property_insert_value(const std::string &key, const boost::any &value, CallbackWithStatus cb) |
| { |
| syslog(LOG_INFO, "property_insert_value: key: \"%s\"", key.c_str()); |
| |
| if (!mEnabled) { |
| cb(kWPANTUNDStatus_InvalidWhenDisabled); |
| return; |
| } |
| |
| try { |
| if (mVendorCustom.is_property_key_supported(key)) { |
| mVendorCustom.property_insert_value(key, value, cb); |
| |
| } else { |
| NCPInstanceBase::property_insert_value(key, value, cb); |
| } |
| } catch (const boost::bad_any_cast &x) { |
| // We will get a bad_any_cast exception if the property is of |
| // the wrong type. |
| syslog(LOG_ERR,"property_insert_value: Bad type for property \"%s\" (%s)", key.c_str(), x.what()); |
| cb(kWPANTUNDStatus_InvalidArgument); |
| } catch (const std::invalid_argument &x) { |
| // We will get a bad_any_cast exception if the property is of |
| // the wrong type. |
| syslog(LOG_ERR,"property_insert_value: Invalid argument for property \"%s\" (%s)", key.c_str(), x.what()); |
| cb(kWPANTUNDStatus_InvalidArgument); |
| } |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // Property Remove Handlers |
| |
| void |
| SpinelNCPInstance::register_remove_handler(const char *prop_name, PropUpdateHandler handler) |
| { |
| NCPInstanceBase::register_prop_remove_handler(prop_name, handler); |
| } |
| |
| void |
| SpinelNCPInstance::register_remove_handler_capability(const char *prop_name, unsigned int capability, |
| PropUpdateHandler handler) |
| { |
| register_remove_handler( |
| prop_name, |
| boost::bind(&SpinelNCPInstance::check_capability_prop_update, this, _1, _2, _3, capability, handler)); |
| } |
| |
| void |
| SpinelNCPInstance::regsiter_all_remove_handlers(void) |
| { |
| register_remove_handler_capability( |
| kWPANTUNDProperty_MACAllowlistEntries, |
| SPINEL_CAP_MAC_ALLOWLIST, |
| boost::bind(&SpinelNCPInstance::remove_prop_MACAllowlistEntries, this, _1, _2)); |
| register_remove_handler_capability( |
| kWPANTUNDProperty_MACDenylistEntries, |
| SPINEL_CAP_MAC_ALLOWLIST, |
| boost::bind(&SpinelNCPInstance::remove_prop_MACDenylistEntries, this, _1, _2)); |
| register_remove_handler_capability( |
| kWPANTUNDProperty_MACFilterEntries, |
| SPINEL_CAP_MAC_ALLOWLIST, |
| boost::bind(&SpinelNCPInstance::remove_prop_MACFilterEntries, this, _1, _2)); |
| } |
| |
| void |
| SpinelNCPInstance::remove_prop_MACAllowlistEntries(const boost::any &value, CallbackWithStatus cb) |
| { |
| Data ext_address = any_to_data(value); |
| |
| if (ext_address.size() == sizeof(spinel_eui64_t)) { |
| start_new_task(SpinelNCPTaskSendCommand::Factory(this) |
| .set_callback(cb) |
| .add_command( |
| SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_REMOVE(SPINEL_DATATYPE_EUI64_S), |
| SPINEL_PROP_MAC_ALLOWLIST, |
| ext_address.data() |
| ) |
| ) |
| .finish() |
| ); |
| } else { |
| cb(kWPANTUNDStatus_InvalidArgument); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::remove_prop_MACDenylistEntries(const boost::any &value, CallbackWithStatus cb) |
| { |
| Data ext_address = any_to_data(value); |
| |
| if (ext_address.size() == sizeof(spinel_eui64_t)) { |
| start_new_task(SpinelNCPTaskSendCommand::Factory(this) |
| .set_callback(cb) |
| .add_command( |
| SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_REMOVE(SPINEL_DATATYPE_EUI64_S), |
| SPINEL_PROP_MAC_DENYLIST, |
| ext_address.data() |
| ) |
| ) |
| .finish() |
| ); |
| } else { |
| cb(kWPANTUNDStatus_InvalidArgument); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::remove_prop_MACFilterEntries(const boost::any &value, CallbackWithStatus cb) |
| { |
| Data ext_address = any_to_data(value); |
| |
| if (ext_address.size() == sizeof(spinel_eui64_t)) { |
| start_new_task(SpinelNCPTaskSendCommand::Factory(this) |
| .set_callback(cb) |
| .add_command( |
| SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_REMOVE(SPINEL_DATATYPE_EUI64_S), |
| SPINEL_PROP_MAC_FIXED_RSS, |
| ext_address.data() |
| ) |
| ) |
| .finish() |
| ); |
| } else { |
| cb(kWPANTUNDStatus_InvalidArgument); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::property_remove_value(const std::string &key, const boost::any &value, CallbackWithStatus cb) |
| { |
| syslog(LOG_INFO, "property_remove_value: key: \"%s\"", key.c_str()); |
| |
| try { |
| if (mVendorCustom.is_property_key_supported(key)) { |
| mVendorCustom.property_remove_value(key, value, cb); |
| |
| } else { |
| NCPInstanceBase::property_remove_value(key, value, cb); |
| } |
| |
| } catch (const boost::bad_any_cast &x) { |
| // We will get a bad_any_cast exception if the property is of |
| // the wrong type. |
| syslog(LOG_ERR,"property_remove_value: Bad type for property \"%s\" (%s)", key.c_str(), x.what()); |
| cb(kWPANTUNDStatus_InvalidArgument); |
| } catch (const std::invalid_argument &x) { |
| // We will get a bad_any_cast exception if the property is of |
| // the wrong type. |
| syslog(LOG_ERR,"property_remove_value: Invalid argument for property \"%s\" (%s)", key.c_str(), x.what()); |
| cb(kWPANTUNDStatus_InvalidArgument); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::reset_tasks(wpantund_status_t status) |
| { |
| NCPInstanceBase::reset_tasks(status); |
| while(!mTaskQueue.empty()) { |
| mTaskQueue.front()->finish(status); |
| mTaskQueue.pop_front(); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::handle_ncp_spinel_value_is_ON_MESH_NETS(const uint8_t *value_data_ptr, spinel_size_t value_data_len) |
| { |
| std::multimap<IPv6Prefix, OnMeshPrefixEntry>::iterator iter; |
| std::multimap<IPv6Prefix, OnMeshPrefixEntry> on_mesh_prefixes(mOnMeshPrefixes); |
| int num_prefix = 0; |
| |
| while (value_data_len > 0) { |
| spinel_ssize_t len = 0; |
| struct in6_addr *prefix_addr = NULL; |
| uint8_t prefix_len = 0; |
| bool stable = false; |
| uint8_t flags = 0; |
| uint8_t flags_extended = 0; |
| uint16_t mesh_nets_flags = 0; |
| bool is_local = false; |
| uint16_t rloc16 = 0; |
| |
| len = spinel_datatype_unpack( |
| value_data_ptr, |
| value_data_len, |
| SPINEL_DATATYPE_STRUCT_S( |
| SPINEL_DATATYPE_IPv6ADDR_S // Prefix |
| SPINEL_DATATYPE_UINT8_S // Prefix length (in bits) |
| SPINEL_DATATYPE_BOOL_S // stable |
| SPINEL_DATATYPE_UINT8_S // flags |
| SPINEL_DATATYPE_BOOL_S // is_local |
| SPINEL_DATATYPE_UINT16_S // RLOC16 |
| SPINEL_DATATYPE_UINT8_S // flags extended |
| ), |
| &prefix_addr, |
| &prefix_len, |
| &stable, |
| &flags, |
| &is_local, |
| &rloc16, |
| &flags_extended |
| ); |
| |
| if (len <= 0) { |
| break; |
| } |
| |
| mesh_nets_flags = (flags_extended << 8) | flags; |
| |
| syslog( |
| LOG_INFO, |
| "[-NCP-]: On-mesh net [%d] \"%s/%d\" stable:%s local:%s flags:%s, rloc16:0x%04x", |
| num_prefix, |
| in6_addr_to_string(*prefix_addr).c_str(), |
| prefix_len, |
| stable ? "yes" : "no", |
| is_local ? "yes" : "no", |
| on_mesh_prefix_flags_to_string(mesh_nets_flags).c_str(), |
| rloc16 |
| ); |
| |
| num_prefix++; |
| |
| if (!is_local) { |
| |
| // Go through the `on_mesh_prefixes` list (which is the copy of mOnMeshPrefixes) |
| // and check if this entry is already on the list, if so remove it. |
| |
| IPv6Prefix prefix(*prefix_addr, prefix_len); |
| OnMeshPrefixEntry entry(kOriginThreadNCP, mesh_nets_flags, stable, rloc16); |
| |
| iter = on_mesh_prefixes.lower_bound(prefix); |
| |
| if (iter != on_mesh_prefixes.end()) { |
| std::multimap<IPv6Prefix, OnMeshPrefixEntry>::iterator upper_iter = on_mesh_prefixes.upper_bound(prefix); |
| |
| for (; iter != upper_iter; ++iter) { |
| if (iter->second == entry) { |
| on_mesh_prefixes.erase(iter); |
| break; |
| } |
| } |
| } |
| |
| on_mesh_prefix_was_added(kOriginThreadNCP, *prefix_addr, prefix_len, mesh_nets_flags, stable, rloc16); |
| } |
| |
| value_data_ptr += len; |
| value_data_len -= len; |
| } |
| |
| // Since this was the whole list, we need to remove any prefixes |
| // which originated from NCP that that weren't in the new list. |
| |
| for (iter = on_mesh_prefixes.begin(); iter != on_mesh_prefixes.end(); ++iter) { |
| if (iter->second.is_from_ncp()) { |
| on_mesh_prefix_was_removed( |
| kOriginThreadNCP, |
| iter->first.get_prefix(), |
| iter->first.get_length(), |
| iter->second.get_flags(), |
| iter->second.is_stable(), |
| iter->second.get_rloc() |
| ); |
| } |
| } |
| } |
| |
| void |
| SpinelNCPInstance::handle_ncp_spinel_value_is_OFF_MESH_ROUTES(const uint8_t* value_data_ptr, spinel_size_t value_data_len) |
| { |
| std::multimap<IPv6Prefix, OffMeshRouteEntry>::iterator iter; |
| std::multimap<IPv6Prefix, OffMeshRouteEntry> off_mesh_routes(mOffMeshRoutes); |
| int num_routes = 0; |
| |
| while (value_data_len > 0) { |
| spinel_ssize_t len; |
| struct in6_addr *route_prefix = NULL; |
| uint8_t prefix_len; |
| bool is_stable; |
| uint8_t flags; |
| bool is_local; |
| bool next_hop_is_this_device; |
| uint16_t rloc16; |
| RoutePreference preference; |
| |
| len = spinel_datatype_unpack( |
| value_data_ptr, |
| value_data_len, |
| SPINEL_DATATYPE_STRUCT_S( |
| SPINEL_DATATYPE_IPv6ADDR_S // Route Prefix |
| SPINEL_DATATYPE_UINT8_S // Prefix Length (in bits) |
| SPINEL_DATATYPE_BOOL_S // isStable |
| SPINEL_DATATYPE_UINT8_S // Flags |
| SPINEL_DATATYPE_BOOL_S // IsLocal |
| SPINEL_DATATYPE_BOOL_S // NextHopIsThisDevice |
| SPINEL_DATATYPE_UINT16_S // RLOC16 |
| ), |
| &route_prefix, |
| &prefix_len, |
| &is_stable, |
| &flags, |
| &is_local, |
| &next_hop_is_this_device, |
| &rloc16 |
| ); |
| |
| if (len <= 0) { |
| break; |
| } |
| |
| preference = convert_flags_to_route_preference(flags); |
| |
| syslog(LOG_INFO, "[-NCP-]: Off-mesh route [%d] \"%s/%d\" stable:%s local:%s preference:%s, next_hop_is_this_device:%s, rloc16:0x%0x", |
| num_routes, in6_addr_to_string(*route_prefix).c_str(), prefix_len, is_stable ? "yes" : "no", |
| is_local ? "yes" : "no", NCPControlInterface::external_route_priority_to_string(preference).c_str(), |
| next_hop_is_this_device ? "yes" : "no", rloc16); |
| |
| num_routes++; |
| |
| if (!is_local) { |
| |
| // Go through the `off_mesh_routes` list (which is the copy of mOffMeshRoutes) |
| // and check if this entry is already on the list, if so remove it. |
| |
| IPv6Prefix route(*route_prefix, prefix_len); |
| OffMeshRouteEntry entry(kOriginThreadNCP, preference, is_stable, rloc16, next_hop_is_this_device); |
| iter = off_mesh_routes.lower_bound(route); |
| |
| if (iter != off_mesh_routes.end()) { |
| std::multimap<IPv6Prefix, OffMeshRouteEntry>::iterator upper_iter = off_mesh_routes.upper_bound(route); |
| |
| for (; iter != upper_iter; ++iter) { |
| if (iter->second == entry) { |
| off_mesh_routes.erase(iter); |
| break; |
| } |
| } |
| } |
| |
| route_was_added(kOriginThreadNCP, *route_prefix, prefix_len, preference, is_stable, rloc16, |
| next_hop_is_this_device); |
| } |
| |
| value_data_ptr += len; |
| value_data_len -= len; |
| } |
| |
| // Since this was the whole list, we need to remove any routes |
| // which originated from NCP that that weren't in the new list. |
| |
| for (iter = off_mesh_routes.begin(); iter != off_mesh_routes.end(); ++iter) { |
| if (iter->second.is_from_ncp()) { |
| route_was_removed(kOriginThreadNCP, iter->first.get_prefix(), iter->first.get_length(), |
| iter->second.get_preference(), iter->second.is_stable(), iter->second.get_rloc()); |
| } |
| } |
| } |
| |
| void |
| SpinelNCPInstance::handle_ncp_spinel_value_is_SERVICES(const uint8_t* value_data_ptr, spinel_size_t value_data_len) |
| { |
| uint32_t enterprise_number; |
| const uint8_t *service_data_ptr = NULL; |
| spinel_size_t service_data_len = 0; |
| bool stable = false; |
| const uint8_t *server_data_ptr = NULL; |
| spinel_size_t server_data_len = 0; |
| uint16_t rloc16; |
| int num_services = 0; |
| spinel_ssize_t len; |
| |
| std::vector<ServiceEntry> entries(mServiceEntries); |
| std::vector<ServiceEntry>::iterator iter; |
| |
| while (value_data_len > 0) { |
| len = spinel_datatype_unpack( |
| value_data_ptr, |
| value_data_len, |
| SPINEL_DATATYPE_STRUCT_S( |
| SPINEL_DATATYPE_UINT32_S // Enterprise Number |
| SPINEL_DATATYPE_DATA_WLEN_S // Service Data |
| SPINEL_DATATYPE_BOOL_S // stable |
| SPINEL_DATATYPE_DATA_WLEN_S // Server Data |
| SPINEL_DATATYPE_UINT16_S // RLOC |
| ), |
| &enterprise_number, |
| &service_data_ptr, |
| &service_data_len, |
| &stable, |
| &server_data_ptr, |
| &server_data_len, |
| &rloc16 |
| ); |
| |
| if (len <= 0) { |
| break; |
| } |
| |
| syslog(LOG_INFO, "[-NCP-]: Service [%d] enterprise_number:%u stable:%s RLOC16:%04x", |
| num_services, enterprise_number, stable ? "yes" : "no", rloc16); |
| |
| Data service_data(service_data_ptr, service_data_len); |
| Data server_data(server_data_ptr, server_data_len); |
| |
| ServiceEntry entry(kOriginThreadNCP, enterprise_number, service_data, stable, server_data); |
| |
| iter = std::find(entries.begin(), entries.end(), entry); |
| if (iter != entries.end()) { |
| entries.erase(iter); |
| } |
| |
| service_was_added(kOriginThreadNCP, enterprise_number, service_data, stable, server_data); |
| |
| value_data_ptr += len; |
| value_data_len -= len; |
| num_services += 1; |
| } |
| |
| for (iter = entries.begin(); iter != entries.end(); ++iter) { |
| if (iter->is_from_ncp()) { |
| service_was_removed(kOriginThreadNCP, iter->get_enterprise_number(), iter->get_service_data()); |
| } |
| } |
| } |
| |
| void |
| SpinelNCPInstance::handle_ncp_spinel_value_is(spinel_prop_key_t key, const uint8_t* value_data_ptr, spinel_size_t value_data_len) |
| { |
| const uint8_t *original_value_data_ptr = value_data_ptr; |
| spinel_size_t original_value_data_len = value_data_len; |
| |
| if (key == SPINEL_PROP_LAST_STATUS) { |
| spinel_status_t status = SPINEL_STATUS_OK; |
| spinel_datatype_unpack(value_data_ptr, value_data_len, "i", &status); |
| syslog(LOG_INFO, "[-NCP-]: Last status (%s, %d)", spinel_status_to_cstr(status), status); |
| if ((status >= SPINEL_STATUS_RESET__BEGIN) && (status <= SPINEL_STATUS_RESET__END)) { |
| syslog(LOG_NOTICE, "[-NCP-]: NCP was reset (%s, %d)", spinel_status_to_cstr(status), status); |
| process_event(EVENT_NCP_RESET, status); |
| if (!mResetIsExpected && (mDriverState == NORMAL_OPERATION)) { |
| wpantund_status_t wstatus = kWPANTUNDStatus_NCP_Reset; |
| switch(status) { |
| case SPINEL_STATUS_RESET_CRASH: |
| case SPINEL_STATUS_RESET_FAULT: |
| case SPINEL_STATUS_RESET_ASSERT: |
| case SPINEL_STATUS_RESET_WATCHDOG: |
| case SPINEL_STATUS_RESET_OTHER: |
| wstatus = kWPANTUNDStatus_NCP_Crashed; |
| break; |
| default: |
| break; |
| } |
| reset_tasks(wstatus); |
| } |
| |
| if (mDriverState == NORMAL_OPERATION) { |
| reinitialize_ncp(); |
| } |
| mResetIsExpected = false; |
| return; |
| } else if ((status >= SPINEL_STATUS_JOIN__BEGIN) && (status <= SPINEL_STATUS_JOIN__END)) { |
| if (status == SPINEL_STATUS_JOIN_SUCCESS) { |
| change_ncp_state(COMMISSIONED); |
| } |
| else { |
| change_ncp_state(CREDENTIALS_NEEDED); |
| } |
| } else if (status == SPINEL_STATUS_INVALID_COMMAND) { |
| syslog(LOG_NOTICE, "[-NCP-]: COMMAND NOT RECOGNIZED"); |
| } |
| } else if (key == SPINEL_PROP_NCP_VERSION) { |
| const char* ncp_version = NULL; |
| spinel_ssize_t len = spinel_datatype_unpack(value_data_ptr, value_data_len, "U", &ncp_version); |
| if ((len <= 0) || (ncp_version == NULL)) { |
| syslog(LOG_CRIT, "[-NCP-]: Got a corrupted NCP version"); |
| // TODO: Properly handle NCP Misbehavior |
| change_ncp_state(FAULT); |
| } else { |
| set_ncp_version_string(ncp_version); |
| } |
| |
| } else if (key == SPINEL_PROP_INTERFACE_TYPE) { |
| unsigned int interface_type = 0; |
| spinel_datatype_unpack(value_data_ptr, value_data_len, "i", &interface_type); |
| |
| if (interface_type != SPINEL_PROTOCOL_TYPE_THREAD) { |
| syslog(LOG_CRIT, "[-NCP-]: NCP is using unsupported protocol type (%d)", interface_type); |
| change_ncp_state(FAULT); |
| } |
| |
| } else if (key == SPINEL_PROP_PROTOCOL_VERSION) { |
| unsigned int protocol_version_major = 0; |
| unsigned int protocol_version_minor = 0; |
| spinel_datatype_unpack(value_data_ptr, value_data_len, "ii", &protocol_version_major, &protocol_version_minor); |
| |
| if (protocol_version_major != SPINEL_PROTOCOL_VERSION_THREAD_MAJOR) { |
| syslog(LOG_CRIT, "[-NCP-]: NCP is using unsupported protocol version (NCP:%d, wpantund:%d)", protocol_version_major, SPINEL_PROTOCOL_VERSION_THREAD_MAJOR); |
| change_ncp_state(FAULT); |
| } |
| |
| if (protocol_version_minor != SPINEL_PROTOCOL_VERSION_THREAD_MINOR) { |
| syslog(LOG_WARNING, "[-NCP-]: NCP is using different protocol minor version (NCP:%d, wpantund:%d)", protocol_version_minor, SPINEL_PROTOCOL_VERSION_THREAD_MINOR); |
| } |
| |
| } else if (key == SPINEL_PROP_CAPS) { |
| const uint8_t* data_ptr = value_data_ptr; |
| spinel_size_t data_len = value_data_len; |
| std::set<unsigned int> capabilities; |
| |
| while(data_len != 0) { |
| unsigned int value = 0; |
| spinel_ssize_t parse_len = spinel_datatype_unpack(data_ptr, data_len, SPINEL_DATATYPE_UINT_PACKED_S, &value); |
| if (parse_len <= 0) { |
| syslog(LOG_WARNING, "[-NCP-]: Capability Parse failure"); |
| break; |
| } |
| capabilities.insert(value); |
| syslog(LOG_INFO, "[-NCP-]: Capability (%s, %d)", spinel_capability_to_cstr(value), value); |
| |
| data_ptr += parse_len; |
| data_len -= parse_len; |
| } |
| |
| if (capabilities != mCapabilities) { |
| mCapabilities = capabilities; |
| } |
| |
| } else if (key == SPINEL_PROP_NET_NETWORK_NAME) { |
| const char* value = NULL; |
| spinel_ssize_t len = spinel_datatype_unpack(value_data_ptr, value_data_len, "U", &value); |
| |
| if ((len <= 0) || (value == NULL)) { |
| syslog(LOG_CRIT, "[-NCP-]: Got a corrupted NCP version"); |
| // TODO: Properly handle NCP Misbehavior |
| change_ncp_state(FAULT); |
| } else { |
| syslog(LOG_INFO, "[-NCP-]: Network name \"%s\"", value); |
| if (mCurrentNetworkInstance.name != value) { |
| mCurrentNetworkInstance.name = value; |
| signal_property_changed(kWPANTUNDProperty_NetworkName, mCurrentNetworkInstance.name); |
| } |
| } |
| |
| } else if (key == SPINEL_PROP_MCU_POWER_STATE) { |
| uint8_t power_state = 0; |
| spinel_ssize_t len = 0; |
| |
| len = spinel_datatype_unpack(value_data_ptr, value_data_len, SPINEL_DATATYPE_UINT8_S, &power_state); |
| |
| if (len > 0) { |
| syslog(LOG_INFO, "[-NCP-]: MCU power state \"%s\" (%d)", |
| spinel_mcu_power_state_to_cstr(static_cast<spinel_mcu_power_state_t>(power_state)), power_state); |
| |
| switch (get_ncp_state()) { |
| case OFFLINE: |
| case COMMISSIONED: |
| if (power_state == SPINEL_MCU_POWER_STATE_LOW_POWER) { |
| change_ncp_state(DEEP_SLEEP); |
| } |
| break; |
| |
| case DEEP_SLEEP: |
| if (power_state == SPINEL_MCU_POWER_STATE_ON) { |
| change_ncp_state(mIsCommissioned ? COMMISSIONED : OFFLINE); |
| } |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| } else if (key == SPINEL_PROP_IPV6_LL_ADDR) { |
| struct in6_addr *addr = NULL; |
| |
| spinel_datatype_unpack(value_data_ptr, value_data_len, "6", &addr); |
| if (addr != NULL) { |
| syslog(LOG_INFO, "[-NCP-]: Link-local IPv6 address \"%s\"", in6_addr_to_string(*addr).c_str()); |
| } |
| update_link_local_address(addr); |
| |
| } else if (key == SPINEL_PROP_IPV6_ML_ADDR) { |
| struct in6_addr *addr = NULL; |
| spinel_datatype_unpack(value_data_ptr, value_data_len, "6", &addr); |
| if (addr != NULL) { |
| syslog(LOG_INFO, "[-NCP-]: Mesh-local IPv6 address \"%s\"", in6_addr_to_string(*addr).c_str()); |
| } |
| update_mesh_local_address(addr); |
| |
| } else if (key == SPINEL_PROP_IPV6_ML_PREFIX) { |
| struct in6_addr *addr = NULL; |
| spinel_datatype_unpack(value_data_ptr, value_data_len, "6", &addr); |
| if (addr != NULL) { |
| syslog(LOG_INFO, "[-NCP-]: Mesh-local prefix \"%s\"", (in6_addr_to_string(*addr) + "/64").c_str()); |
| } |
| update_mesh_local_prefix(addr); |
| |
| } else if (key == SPINEL_PROP_IPV6_ADDRESS_TABLE) { |
| std::map<struct in6_addr, UnicastAddressEntry>::const_iterator iter; |
| std::map<struct in6_addr, UnicastAddressEntry> unicast_addresses(mUnicastAddresses); |
| const struct in6_addr *addr = NULL; |
| int num_address = 0; |
| |
| while (value_data_len > 0) { |
| const uint8_t *entry_ptr = NULL; |
| spinel_size_t entry_len = 0; |
| spinel_ssize_t len = 0; |
| len = spinel_datatype_unpack(value_data_ptr, value_data_len, "D.", &entry_ptr, &entry_len); |
| if (len < 1) { |
| break; |
| } |
| |
| addr = reinterpret_cast<const struct in6_addr*>(entry_ptr); |
| syslog(LOG_INFO, "[-NCP-]: IPv6 address [%d] \"%s\"", num_address, in6_addr_to_string(*addr).c_str()); |
| num_address++; |
| unicast_addresses.erase(*addr); |
| handle_ncp_spinel_value_inserted(key, entry_ptr, entry_len); |
| |
| value_data_ptr += len; |
| value_data_len -= len; |
| } |
| |
| syslog(LOG_INFO, "[-NCP-]: IPv6 address: Total %d address%s", num_address, (num_address > 1) ? "es" : ""); |
| |
| // Since this was the whole list, we need to remove the addresses |
| // which originated from NCP that that weren't in the list. |
| for (iter = unicast_addresses.begin(); iter != unicast_addresses.end(); ++iter) { |
| if (iter->second.is_from_ncp()) { |
| unicast_address_was_removed(kOriginThreadNCP, iter->first); |
| } |
| } |
| |
| } else if (key == SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE) { |
| std::map<struct in6_addr, MulticastAddressEntry>::const_iterator iter; |
| std::map<struct in6_addr, MulticastAddressEntry> multicast_addresses(mMulticastAddresses); |
| const struct in6_addr *addr = NULL; |
| int num_address = 0; |
| |
| while (value_data_len > 0) { |
| const uint8_t *entry_ptr = NULL; |
| spinel_size_t entry_len = 0; |
| spinel_ssize_t len = 0; |
| len = spinel_datatype_unpack(value_data_ptr, value_data_len, "D.", &entry_ptr, &entry_len); |
| if (len < 1) { |
| break; |
| } |
| |
| addr = reinterpret_cast<const struct in6_addr*>(entry_ptr); |
| syslog(LOG_INFO, "[-NCP-]: Multicast IPv6 address [%d] \"%s\"", num_address, in6_addr_to_string(*addr).c_str()); |
| num_address++; |
| multicast_addresses.erase(*addr); |
| handle_ncp_spinel_value_inserted(key, entry_ptr, entry_len); |
| |
| value_data_ptr += len; |
| value_data_len -= len; |
| } |
| |
| // Since this was the whole list, we need to remove the addresses |
| // which originated from NCP that that weren't in the list. |
| for (iter = multicast_addresses.begin(); iter != multicast_addresses.end(); ++iter) { |
| if (iter->second.is_from_ncp()) { |
| multicast_address_was_left(kOriginThreadNCP, iter->first); |
| } |
| } |
| |
| } else if (key == SPINEL_PROP_HWADDR) { |
| nl::Data hwaddr(value_data_ptr, value_data_len); |
| if (value_data_len == sizeof(mMACHardwareAddress)) { |
| set_mac_hardware_address(value_data_ptr); |
| } |
| |
| } else if (key == SPINEL_PROP_MAC_15_4_LADDR) { |
| nl::Data hwaddr(value_data_ptr, value_data_len); |
| if (value_data_len == sizeof(mMACAddress)) { |
| set_mac_address(value_data_ptr); |
| } |
| |
| } else if (key == SPINEL_PROP_MAC_15_4_PANID) { |
| uint16_t panid; |
| spinel_datatype_unpack(value_data_ptr, value_data_len, SPINEL_DATATYPE_UINT16_S, &panid); |
| syslog(LOG_INFO, "[-NCP-]: PANID 0x%04X", panid); |
| if (panid != mCurrentNetworkInstance.panid) { |
| mCurrentNetworkInstance.panid = panid; |
| signal_property_changed(kWPANTUNDProperty_NetworkPANID, panid); |
| } |
| |
| } else if (key == SPINEL_PROP_NET_XPANID) { |
| nl::Data xpanid(value_data_ptr, value_data_len); |
| char cstr_buf[200]; |
| encode_data_into_string(value_data_ptr, value_data_len, cstr_buf, sizeof(cstr_buf), 0); |
| syslog(LOG_INFO, "[-NCP-] XPANID 0x%s", cstr_buf); |
| |
| if ((value_data_len == 8) && 0 != memcmp(xpanid.data(), mCurrentNetworkInstance.xpanid, 8)) { |
| memcpy(mCurrentNetworkInstance.xpanid, xpanid.data(), 8); |
| signal_property_changed(kWPANTUNDProperty_NetworkXPANID, xpanid); |
| } |
| |
| } else if (key == SPINEL_PROP_NET_PSKC) { |
| nl::Data network_pskc(value_data_ptr, value_data_len); |
| if (network_pskc != mNetworkPSKc) { |
| mNetworkPSKc = network_pskc; |
| signal_property_changed(kWPANTUNDProperty_NetworkPSKc, mNetworkPSKc); |
| } |
| |
| } else if (key == SPINEL_PROP_NET_MASTER_KEY) { |
| nl::Data network_key(value_data_ptr, value_data_len); |
| if (ncp_state_is_joining_or_joined(get_ncp_state())) { |
| if (network_key != mNetworkKey) { |
| mNetworkKey = network_key; |
| signal_property_changed(kWPANTUNDProperty_NetworkKey, mNetworkKey); |
| } |
| } |
| |
| } else if (key == SPINEL_PROP_NET_KEY_SEQUENCE_COUNTER) { |
| uint32_t network_key_index = 0; |
| spinel_ssize_t ret; |
| |
| ret = spinel_datatype_unpack(value_data_ptr, value_data_len, SPINEL_DATATYPE_UINT32_S, &network_key_index); |
| |
| __ASSERT_MACROS_check(ret > 0); |
| |
| if ((ret > 0) && (network_key_index != mNetworkKeyIndex)) { |
| mNetworkKeyIndex = network_key_index; |
| signal_property_changed(kWPANTUNDProperty_NetworkKeyIndex, mNetworkKeyIndex); |
| } |
| |
| } else if (key == SPINEL_PROP_PHY_CHAN) { |
| unsigned int value = 0; |
| spinel_ssize_t ret; |
| |
| ret = spinel_datatype_unpack(value_data_ptr, value_data_len, SPINEL_DATATYPE_UINT_PACKED_S, &value); |
| |
| __ASSERT_MACROS_check(ret > 0); |
| |
| if (ret > 0) { |
| syslog(LOG_INFO, "[-NCP-]: Channel %d", value); |
| if (value != mCurrentNetworkInstance.channel) { |
| mCurrentNetworkInstance.channel = value; |
| signal_property_changed(kWPANTUNDProperty_NCPChannel, mCurrentNetworkInstance.channel); |
| } |
| } |
| |
| } else if (key == SPINEL_PROP_PHY_CHAN_SUPPORTED) { |
| boost::any mask_value; |
| int ret = unpack_channel_mask(value_data_ptr, value_data_len, mask_value); |
| |
| if (ret == kWPANTUNDStatus_Ok) { |
| mSupportedChannelMask = any_to_int(mask_value); |
| syslog(LOG_INFO, "[-NCP-]: Supported Channel Mask 0x%x", mSupportedChannelMask); |
| } |
| |
| } else if (key == SPINEL_PROP_PHY_CHAN_PREFERRED) { |
| boost::any mask_value; |
| int ret = unpack_channel_mask(value_data_ptr, value_data_len, mask_value); |
| |
| if (ret == kWPANTUNDStatus_Ok) { |
| mPreferredChannelMask = any_to_int(mask_value); |
| syslog(LOG_INFO, "[-NCP-]: Preferred Channel Mask 0x%x", mPreferredChannelMask); |
| } |
| |
| } else if (key == SPINEL_PROP_PHY_TX_POWER) { |
| int8_t value = 0; |
| spinel_ssize_t ret; |
| |
| ret = spinel_datatype_unpack(value_data_ptr, value_data_len, SPINEL_DATATYPE_INT8_S, &value); |
| |
| __ASSERT_MACROS_check(ret > 0); |
| |
| if (ret > 0) { |
| syslog(LOG_INFO, "[-NCP-]: Tx power %d", value); |
| if (value != mTXPower) { |
| mTXPower = value; |
| signal_property_changed(kWPANTUNDProperty_NCPTXPower, mTXPower); |
| } |
| } |
| |
| } else if (key == SPINEL_PROP_STREAM_DEBUG) { |
| handle_ncp_debug_stream(value_data_ptr, value_data_len); |
| |
| } else if (key == SPINEL_PROP_STREAM_LOG) { |
| handle_ncp_log_stream(value_data_ptr, value_data_len); |
| |
| } else if (key == SPINEL_PROP_NET_ROLE) { |
| uint8_t value = 0; |
| spinel_ssize_t ret; |
| |
| ret = spinel_datatype_unpack(value_data_ptr, value_data_len, SPINEL_DATATYPE_UINT8_S, &value); |
| |
| __ASSERT_MACROS_check(ret > 0); |
| |
| if (ret > 0) { |
| syslog(LOG_INFO, "[-NCP-]: Net Role \"%s\" (%d)", spinel_net_role_to_cstr(value), value); |
| |
| if (ncp_state_is_joining_or_joined(get_ncp_state()) |
| && (value != SPINEL_NET_ROLE_DETACHED) |
| && (value != SPINEL_NET_ROLE_DISABLED) |
| ) { |
| change_ncp_state(ASSOCIATED); |
| } |
| |
| if (value == SPINEL_NET_ROLE_CHILD) { |
| if ((mThreadMode & SPINEL_THREAD_MODE_RX_ON_WHEN_IDLE) != 0) { |
| update_node_type(END_DEVICE); |
| } else { |
| update_node_type(SLEEPY_END_DEVICE); |
| } |
| |
| } else if (value == SPINEL_NET_ROLE_ROUTER) { |
| update_node_type(ROUTER); |
| |
| } else if (value == SPINEL_NET_ROLE_LEADER) { |
| update_node_type(LEADER); |
| |
| } else if (value == SPINEL_NET_ROLE_DETACHED || value == SPINEL_NET_ROLE_DISABLED) { |
| update_node_type(UNKNOWN); |
| if (ncp_state_is_associated(get_ncp_state())) { |
| change_ncp_state(ISOLATED); |
| } |
| } |
| } |
| |
| } else if (key == SPINEL_PROP_THREAD_MODE) { |
| uint8_t value = mThreadMode; |
| spinel_ssize_t ret; |
| |
| ret = spinel_datatype_unpack(value_data_ptr, value_data_len, SPINEL_DATATYPE_UINT8_S, &value); |
| |
| __ASSERT_MACROS_check(ret > 0); |
| |
| if (ret > 0) { |
| syslog(LOG_INFO, "[-NCP-]: Thread Mode \"%s\" (0x%02x)", thread_mode_to_string(value).c_str(), value); |
| mThreadMode = value; |
| |
| switch (get_ncp_state()) |
| { |
| case ISOLATED: |
| if ((mThreadMode & SPINEL_THREAD_MODE_RX_ON_WHEN_IDLE) != 0) { |
| change_ncp_state(ASSOCIATING); |
| } |
| break; |
| |
| case ASSOCIATING: |
| if (mIsCommissioned && ((mThreadMode & SPINEL_THREAD_MODE_RX_ON_WHEN_IDLE) == 0)) { |
| change_ncp_state(ISOLATED); |
| } |
| break; |
| |
| default: |
| break; |
| } |
| |
| switch (mNodeType) |
| { |
| case END_DEVICE: |
| case SLEEPY_END_DEVICE: |
| if ((mThreadMode & SPINEL_THREAD_MODE_RX_ON_WHEN_IDLE) != 0) { |
| update_node_type(END_DEVICE); |
| } else { |
| update_node_type(SLEEPY_END_DEVICE); |
| } |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| } else if (key == SPINEL_PROP_NET_SAVED) { |
| bool is_commissioned = false; |
| spinel_datatype_unpack(value_data_ptr, value_data_len, SPINEL_DATATYPE_BOOL_S, &is_commissioned); |
| syslog(LOG_INFO, "[-NCP-]: NetSaved (NCP is commissioned?) \"%s\" ", is_commissioned ? "yes" : "no"); |
| mIsCommissioned = is_commissioned; |
| if (mIsCommissioned && (get_ncp_state() == OFFLINE)) { |
| change_ncp_state(COMMISSIONED); |
| } else if (!mIsCommissioned && (get_ncp_state() == COMMISSIONED)) { |
| change_ncp_state(OFFLINE); |
| } |
| |
| } else if (key == SPINEL_PROP_NET_STACK_UP) { |
| bool is_stack_up = false; |
| spinel_datatype_unpack(value_data_ptr, value_data_len, SPINEL_DATATYPE_BOOL_S, &is_stack_up); |
| syslog(LOG_INFO, "[-NCP-]: Stack is %sup", is_stack_up ? "" : "not "); |
| |
| if (is_stack_up) { |
| if (!ncp_state_is_joining_or_joined(get_ncp_state())) { |
| if (mIsCommissioned && ((mThreadMode & SPINEL_THREAD_MODE_RX_ON_WHEN_IDLE) == 0)) { |
| change_ncp_state(ISOLATED); |
| } else { |
| change_ncp_state(ASSOCIATING); |
| } |
| } |
| } else { |
| if (!ncp_state_is_joining(get_ncp_state())) { |
| change_ncp_state(mIsCommissioned ? COMMISSIONED : OFFLINE); |
| } |
| } |
| |
| } else if (key == SPINEL_PROP_NET_IF_UP) { |
| bool is_if_up = false; |
| spinel_datatype_unpack(value_data_ptr, value_data_len, SPINEL_DATATYPE_BOOL_S, &is_if_up); |
| syslog(LOG_INFO, "[-NCP-]: Interface is %sup", is_if_up ? "" : "not "); |
| |
| if (ncp_state_is_interface_up(get_ncp_state()) && !is_if_up) { |
| change_ncp_state(mIsCommissioned ? COMMISSIONED : OFFLINE); |
| } |
| |
| } else if (key == SPINEL_PROP_MESHCOP_COMMISSIONER_STATE) { |
| boost::any value; |
| int status; |
| status = unpack_commissioner_state(value_data_ptr, value_data_len, value); |
| if (status == kWPANTUNDStatus_Ok) { |
| syslog(LOG_INFO, "[-NCP-]: Thread Commissioner state is \"%s\"", any_to_string(value).c_str()); |
| } |
| |
| } else if (key == SPINEL_PROP_THREAD_ON_MESH_NETS) { |
| handle_ncp_spinel_value_is_ON_MESH_NETS(value_data_ptr, value_data_len); |
| |
| } else if (key == SPINEL_PROP_THREAD_OFF_MESH_ROUTES) { |
| handle_ncp_spinel_value_is_OFF_MESH_ROUTES(value_data_ptr, value_data_len); |
| |
| } else if (key == SPINEL_PROP_SERVER_SERVICES) { |
| handle_ncp_spinel_value_is_SERVICES(value_data_ptr, value_data_len); |
| |
| } else if (key == SPINEL_PROP_THREAD_ASSISTING_PORTS) { |
| bool is_assisting = (value_data_len != 0); |
| uint16_t assisting_port(0); |
| |
| if (is_assisting) { |
| int i; |
| syslog(LOG_NOTICE, "Network is joinable"); |
| while (value_data_len > 0) { |
| i = spinel_datatype_unpack(value_data_ptr, value_data_len, SPINEL_DATATYPE_UINT16_S, &assisting_port); |
| if (i <= 0) { |
| break; |
| } |
| syslog(LOG_NOTICE, "Assisting on port %d", assisting_port); |
| value_data_ptr += i; |
| value_data_len -= i; |
| } |
| } else { |
| syslog(LOG_NOTICE, "Network is not joinable"); |
| } |
| |
| } else if (key == SPINEL_PROP_JAM_DETECTED) { |
| bool jamDetected = false; |
| |
| spinel_datatype_unpack(value_data_ptr, value_data_len, SPINEL_DATATYPE_BOOL_S, &jamDetected); |
| signal_property_changed(kWPANTUNDProperty_JamDetectionStatus, jamDetected); |
| |
| if (jamDetected) { |
| syslog(LOG_NOTICE, "Signal jamming is detected"); |
| } else { |
| syslog(LOG_NOTICE, "Signal jamming cleared"); |
| } |
| |
| } else if (key == SPINEL_PROP_CHANNEL_MANAGER_NEW_CHANNEL) { |
| uint8_t new_channel = 0; |
| spinel_ssize_t len; |
| |
| len = spinel_datatype_unpack(value_data_ptr, value_data_len, SPINEL_DATATYPE_UINT8_S, &new_channel); |
| |
| if ((len >= 0) && (new_channel != mChannelManagerNewChannel)) { |
| mChannelManagerNewChannel = new_channel; |
| signal_property_changed(kWPANTUNDProperty_ChannelManagerNewChannel, new_channel); |
| syslog(LOG_INFO, "[-NCP-]: ChannelManager about to switch to new channel %d", new_channel); |
| } |
| |
| } else if (key == SPINEL_PROP_STREAM_RAW) { |
| if (mPcapManager.is_enabled()) { |
| const uint8_t* frame_ptr(NULL); |
| unsigned int frame_len(0); |
| const uint8_t* meta_ptr(NULL); |
| unsigned int meta_len(0); |
| spinel_ssize_t ret; |
| PcapPacket packet; |
| uint16_t flags = 0; |
| |
| packet.set_timestamp().set_dlt(PCAP_DLT_IEEE802_15_4); |
| |
| // Unpack the packet. |
| ret = spinel_datatype_unpack( |
| value_data_ptr, |
| value_data_len, |
| SPINEL_DATATYPE_DATA_WLEN_S SPINEL_DATATYPE_DATA_S, |
| &frame_ptr, |
| &frame_len, |
| &meta_ptr, |
| &meta_len |
| ); |
| |
| require(ret > 0, bail); |
| |
| // Unpack the metadata. |
| ret = spinel_datatype_unpack( |
| meta_ptr, |
| meta_len, |
| SPINEL_DATATYPE_INT8_S // RSSI/TXPower |
| SPINEL_DATATYPE_INT8_S // Noise Floor |
| SPINEL_DATATYPE_UINT16_S, // Flags |
| NULL, // Ignore RSSI/TXPower |
| NULL, // Ignore Noise Floor |
| &flags |
| ); |
| |
| __ASSERT_MACROS_check(ret > 0); |
| |
| if ((flags & SPINEL_MD_FLAG_TX) == SPINEL_MD_FLAG_TX) |
| { |
| // Ignore FCS for transmitted packets |
| frame_len -= 2; |
| packet.set_dlt(PCAP_DLT_IEEE802_15_4_NOFCS); |
| } |
| |
| mPcapManager.push_packet( |
| packet |
| .append_ppi_field(PCAP_PPI_TYPE_SPINEL, meta_ptr, meta_len) |
| .append_payload(frame_ptr, frame_len) |
| ); |
| } |
| |
| } else if (key == SPINEL_PROP_THREAD_TMF_PROXY_STREAM) { |
| const uint8_t* frame_ptr(NULL); |
| unsigned int frame_len(0); |
| uint16_t locator = 0; |
| uint16_t port = 0; |
| spinel_ssize_t ret; |
| Data data; |
| |
| ret = spinel_datatype_unpack( |
| value_data_ptr, |
| value_data_len, |
| SPINEL_DATATYPE_DATA_S SPINEL_DATATYPE_UINT16_S SPINEL_DATATYPE_UINT16_S, |
| &frame_ptr, |
| &frame_len, |
| &locator, |
| &port |
| ); |
| |
| __ASSERT_MACROS_check(ret > 0); |
| |
| // Analyze the packet to determine if it should be dropped. |
| if ((ret > 0)) { |
| // append frame |
| data.append(frame_ptr, frame_len); |
| // pack the locator in big endian. |
| data.push_back(locator >> 8); |
| data.push_back(locator & 0xff); |
| // pack the port in big endian. |
| data.push_back(port >> 8); |
| data.push_back(port & 0xff); |
| signal_property_changed(kWPANTUNDProperty_TmfProxyStream, data); |
| } |
| |
| } else if (key == SPINEL_PROP_THREAD_UDP_FORWARD_STREAM) { |
| const uint8_t* frame_ptr(NULL); |
| unsigned int frame_len(0); |
| uint16_t peer_port = 0; |
| in6_addr *peer_addr; |
| uint16_t sock_port = 0; |
| spinel_ssize_t ret; |
| Data data; |
| |
| ret = spinel_datatype_unpack( |
| value_data_ptr, |
| value_data_len, |
| SPINEL_DATATYPE_DATA_S |
| SPINEL_DATATYPE_UINT16_S // Peer port |
| SPINEL_DATATYPE_IPv6ADDR_S // Peer address |
| SPINEL_DATATYPE_UINT16_S, // Sock port |
| &frame_ptr, |
| &frame_len, |
| &peer_port, |
| &peer_addr, |
| &sock_port |
| ); |
| |
| __ASSERT_MACROS_check(ret > 0); |
| |
| // Analyze the packet to determine if it should be dropped. |
| if (ret > 0) { |
| // append frame |
| data.append(frame_ptr, frame_len); |
| // pack the locator in big endian. |
| data.push_back(peer_port >> 8); |
| data.push_back(peer_port & 0xff); |
| data.append(peer_addr->s6_addr, sizeof(*peer_addr)); |
| // pack the port in big endian. |
| data.push_back(sock_port >> 8); |
| data.push_back(sock_port & 0xff); |
| signal_property_changed(kWPANTUNDProperty_UdpForwardStream, data); |
| } |
| |
| } else if ((key == SPINEL_PROP_STREAM_NET) || (key == SPINEL_PROP_STREAM_NET_INSECURE)) { |
| const uint8_t* frame_ptr(NULL); |
| unsigned int frame_len(0); |
| spinel_ssize_t ret; |
| uint8_t frame_data_type = FRAME_TYPE_DATA; |
| |
| if (SPINEL_PROP_STREAM_NET_INSECURE == key) { |
| frame_data_type = FRAME_TYPE_INSECURE_DATA; |
| } |
| |
| ret = spinel_datatype_unpack( |
| value_data_ptr, |
| value_data_len, |
| SPINEL_DATATYPE_DATA_S SPINEL_DATATYPE_DATA_S, |
| &frame_ptr, |
| &frame_len, |
| NULL, |
| NULL |
| ); |
| |
| __ASSERT_MACROS_check(ret > 0); |
| |
| // Analyze the packet to determine if it should be dropped. |
| if ((ret > 0) && should_forward_hostbound_frame(&frame_data_type, frame_ptr, frame_len)) { |
| if (static_cast<bool>(mLegacyInterface) && (frame_data_type == FRAME_TYPE_LEGACY_DATA)) { |
| handle_alt_ipv6_from_ncp(frame_ptr, frame_len); |
| } else { |
| handle_normal_ipv6_from_ncp(frame_ptr, frame_len); |
| } |
| } |
| } else if (key == SPINEL_PROP_THREAD_CHILD_TABLE) { |
| SpinelNCPTaskGetNetworkTopology::Table child_table; |
| SpinelNCPTaskGetNetworkTopology::Table::iterator it; |
| int num_children = 0; |
| |
| SpinelNCPTaskGetNetworkTopology::parse_child_table(value_data_ptr, value_data_len, child_table); |
| |
| for (it = child_table.begin(); it != child_table.end(); it++) |
| { |
| num_children++; |
| syslog(LOG_INFO, "[-NCP-] Child: %02d %s", num_children, it->get_as_string().c_str()); |
| } |
| syslog(LOG_INFO, "[-NCP-] Child: Total %d child%s", num_children, (num_children > 1) ? "ren" : ""); |
| |
| } else if (key == SPINEL_PROP_THREAD_NEIGHBOR_TABLE) { |
| SpinelNCPTaskGetNetworkTopology::Table neigh_table; |
| SpinelNCPTaskGetNetworkTopology::Table::iterator it; |
| int num_neighbor = 0; |
| |
| SpinelNCPTaskGetNetworkTopology::parse_neighbor_table(value_data_ptr, value_data_len, neigh_table); |
| |
| for (it = neigh_table.begin(); it != neigh_table.end(); it++) |
| { |
| num_neighbor++; |
| syslog(LOG_INFO, "[-NCP-] Neighbor: %02d %s", num_neighbor, it->get_as_string().c_str()); |
| } |
| syslog(LOG_INFO, "[-NCP-] Neighbor: Total %d neighbor%s", num_neighbor, (num_neighbor > 1) ? "s" : ""); |
| |
| } else if (key == SPINEL_PROP_THREAD_NEIGHBOR_TABLE_ERROR_RATES) { |
| SpinelNCPTaskGetNetworkTopology::Table neigh_table; |
| SpinelNCPTaskGetNetworkTopology::Table::iterator it; |
| int num_neighbor = 0; |
| |
| SpinelNCPTaskGetNetworkTopology::prase_neighbor_error_rates_table(value_data_ptr, value_data_len, neigh_table); |
| |
| for (it = neigh_table.begin(); it != neigh_table.end(); it++) |
| { |
| num_neighbor++; |
| syslog(LOG_INFO, "[-NCP-] Neighbor: %02d %s", num_neighbor, it->get_as_string().c_str()); |
| } |
| syslog(LOG_INFO, "[-NCP-] Neighbor: Total %d neighbor%s", num_neighbor, (num_neighbor > 1) ? "s" : ""); |
| |
| } else if (key == SPINEL_PROP_THREAD_ROUTER_TABLE) { |
| SpinelNCPTaskGetNetworkTopology::Table router_table; |
| SpinelNCPTaskGetNetworkTopology::Table::iterator it; |
| int num_router = 0; |
| |
| SpinelNCPTaskGetNetworkTopology::parse_router_table(value_data_ptr, value_data_len, router_table); |
| |
| for (it = router_table.begin(); it != router_table.end(); it++) |
| { |
| num_router++; |
| syslog(LOG_INFO, "[-NCP-] Router: %02d %s", num_router, it->get_as_string().c_str()); |
| } |
| syslog(LOG_INFO, "[-NCP-] Router: Total %d router%s", num_router, (num_router > 1) ? "s" : ""); |
| |
| |
| } else if (key == SPINEL_PROP_THREAD_ADDRESS_CACHE_TABLE) { |
| boost::any value; |
| if ((unpack_address_cache_table(value_data_ptr, value_data_len, value, false) == kWPANTUNDStatus_Ok) |
| && (value.type() == typeid(std::list<std::string>)) |
| ) { |
| std::list<std::string> list = boost::any_cast<std::list<std::string> >(value); |
| int num_entries = 0; |
| |
| for (std::list<std::string>::iterator it = list.begin(); it != list.end(); it++) { |
| num_entries++; |
| syslog(LOG_INFO, "[-NCP-] AddressCache: %02d %s", num_entries, it->c_str()); |
| } |
| syslog(LOG_INFO, "[-NCP-] AddressCache: Total %d entr%s", num_entries, (num_entries > 1) ? "ies" : "y"); |
| } |
| |
| } else if (key == SPINEL_PROP_NET_PARTITION_ID) { |
| uint32_t paritition_id = 0; |
| spinel_datatype_unpack(value_data_ptr, value_data_len, SPINEL_DATATYPE_UINT32_S, &paritition_id); |
| syslog(LOG_INFO, "[-NCP-] Partition id: %u (0x%x)", paritition_id, paritition_id); |
| |
| } else if (key == SPINEL_PROP_THREAD_LEADER_NETWORK_DATA) { |
| char net_data_cstr_buf[540]; |
| encode_data_into_string(value_data_ptr, value_data_len, net_data_cstr_buf, sizeof(net_data_cstr_buf), 0); |
| syslog(LOG_INFO, "[-NCP-] Leader network data: [%s]", net_data_cstr_buf); |
| |
| } else if (key == SPINEL_PROP_RCP_VERSION) { |
| const char *rcp_version = NULL; |
| spinel_ssize_t len; |
| |
| len = spinel_datatype_unpack(value_data_ptr, value_data_len, SPINEL_DATATYPE_UTF8_S, &rcp_version); |
| |
| if (len > 0) { |
| mRcpVersion = std::string(rcp_version); |
| syslog(LOG_NOTICE, "[-NCP-]: RCP is running \"%s\"", rcp_version); |
| } |
| |
| } else if (key == SPINEL_PROP_SLAAC_ENABLED) { |
| bool enabled; |
| spinel_ssize_t len; |
| |
| len = spinel_datatype_unpack(value_data_ptr, value_data_len, SPINEL_DATATYPE_BOOL_S, &enabled); |
| |
| if (len > 0) { |
| syslog(LOG_NOTICE, "[-NCP-]: SLAAC %sabled", enabled ? "en" : "dis"); |
| mNCPHandlesSLAAC = enabled; |
| } |
| |
| } else if (key == SPINEL_PROP_MESHCOP_JOINER_STATE) { |
| boost::any value; |
| |
| if (unpack_meshcop_joiner_state(value_data_ptr, value_data_len, value) == kWPANTUNDStatus_Ok) { |
| syslog(LOG_NOTICE, "[-NCP-]: Joiner state \"%s\"", any_to_string(value).c_str()); |
| } |
| |
| } else if (key == SPINEL_PROP_THREAD_NETWORK_TIME) { |
| ValueMap result; |
| std::string result_as_string; |
| |
| if (unpack_thread_network_time_as_valmap(value_data_ptr, value_data_len, result) == kWPANTUNDStatus_Ok) { |
| if (unpack_thread_network_time_as_string(value_data_ptr, value_data_len, result_as_string) == kWPANTUNDStatus_Ok) { |
| syslog(LOG_INFO, "[-NCP-]: Network time update: %s", result_as_string.c_str()); |
| } else { |
| syslog(LOG_WARNING, "[-NCP-]: Failed to extract network time update for logging"); |
| } |
| |
| handle_network_time_update(result); |
| } else { |
| syslog(LOG_WARNING, "[-NCP-]: Failed to unpack network time update"); |
| } |
| |
| } else if (key == SPINEL_PROP_THREAD_LINK_METRICS_QUERY_RESULT) { |
| spinel_ssize_t len; |
| struct in6_addr *source = NULL; |
| std::string source_str; |
| uint8_t status; |
| std::string status_str; |
| const uint8_t *struct_in = NULL; |
| unsigned int struct_len = 0; |
| |
| mLinkMetricsQueryResult.clear(); |
| |
| // Decode source and status |
| len = spinel_datatype_unpack( |
| value_data_ptr, |
| value_data_len, |
| ( |
| SPINEL_DATATYPE_IPv6ADDR_S |
| SPINEL_DATATYPE_UINT8_S |
| SPINEL_DATATYPE_DATA_WLEN_S |
| ), |
| &source, |
| &status, |
| &struct_in, |
| &struct_len |
| ); |
| |
| require(len >= 0, bail); |
| value_data_ptr += len; |
| value_data_len -= len; |
| |
| source_str = in6_addr_to_string(*source); |
| status_str = spinel_link_metrics_status_to_cstr(status); |
| |
| mLinkMetricsQueryResult[kWPANTUNDValueMapKey_LinkMetrics_Source] = source_str; |
| mLinkMetricsQueryResult[kWPANTUNDValueMapKey_LinkMetrics_Status] = status_str; |
| |
| unpack_link_metrics_as_val_map(struct_in, struct_len, mLinkMetricsQueryResult); |
| |
| } else if (key == SPINEL_PROP_THREAD_LINK_METRICS_MGMT_RESPONSE) { |
| spinel_ssize_t len; |
| struct in6_addr *source = NULL; |
| std::string source_str; |
| uint8_t status; |
| std::string status_str; |
| |
| // Decode source and status |
| len = spinel_datatype_unpack( |
| value_data_ptr, |
| value_data_len, |
| ( |
| SPINEL_DATATYPE_IPv6ADDR_S |
| SPINEL_DATATYPE_UINT8_S |
| ), |
| &source, |
| &status |
| ); |
| |
| require(len >= 0, bail); |
| value_data_ptr += len; |
| value_data_len -= len; |
| |
| source_str = in6_addr_to_string(*source); |
| status_str = spinel_link_metrics_status_to_cstr(status); |
| |
| mLinkMetricsMgmtResponse[kWPANTUNDValueMapKey_LinkMetrics_Source] = source_str; |
| mLinkMetricsMgmtResponse[kWPANTUNDValueMapKey_LinkMetrics_Status] = status_str; |
| |
| syslog(LOG_INFO, "Link Metrics Mqmt Response: %s (src: %s)", status_str.c_str(), source_str.c_str()); |
| |
| } else if (key == SPINEL_PROP_THREAD_LINK_METRICS_MGMT_ENH_ACK_IE) { |
| spinel_ssize_t len; |
| uint16_t short_addr = 0; |
| const spinel_eui64_t *eui64 = NULL; |
| const uint8_t *struct_in = NULL; |
| unsigned int struct_len = 0; |
| |
| mLinkMetricsLastEnhAckIe.clear(); |
| |
| len = spinel_datatype_unpack( |
| value_data_ptr, |
| value_data_len, |
| ( |
| SPINEL_DATATYPE_UINT16_S |
| SPINEL_DATATYPE_EUI64_S |
| SPINEL_DATATYPE_DATA_WLEN_S |
| ), |
| &short_addr, |
| &eui64, |
| &struct_in, |
| &struct_len |
| ); |
| |
| require(len >= 0, bail); |
| value_data_ptr += len; |
| value_data_len -= len; |
| |
| syslog(LOG_DEBUG, "Received Link Metrics Enh-ACK IE from 0x%02x", short_addr); |
| |
| unpack_link_metrics_as_val_map(value_data_ptr, value_data_len, mLinkMetricsLastEnhAckIe); |
| |
| } else if (key == SPINEL_PROP_THREAD_MLR_RESPONSE) { |
| |
| mMulticastListenerRegistrationResponse.clear(); |
| |
| spinel_ssize_t len; |
| uint8_t status; |
| uint8_t mlr_status; |
| const uint8_t *struct_in = NULL; |
| unsigned int struct_len = 0; |
| |
| len = spinel_datatype_unpack( |
| value_data_ptr, |
| value_data_len, |
| ( |
| SPINEL_DATATYPE_UINT8_S |
| SPINEL_DATATYPE_UINT8_S |
| ), |
| &status, |
| &mlr_status |
| ); |
| |
| require(len >= 0, bail); |
| value_data_ptr += len; |
| value_data_len -= len; |
| |
| mMulticastListenerRegistrationResponse[kWPANTUNDValueMapKey_ThreadMlrResponse_Status] = status; |
| mMulticastListenerRegistrationResponse[kWPANTUNDValueMapKey_ThreadMlrResponse_MlrStatus] = mlr_status; |
| |
| std::list<std::string> addrList; |
| |
| len = spinel_datatype_unpack( |
| value_data_ptr, |
| value_data_len, |
| SPINEL_DATATYPE_DATA_WLEN_S, |
| &struct_in, |
| &struct_len |
| ); |
| |
| require(len >= 0, bail); |
| value_data_ptr += len; |
| value_data_len -= len; |
| |
| while (struct_len != 0) |
| { |
| const in6_addr * failed_addr; |
| |
| len = spinel_datatype_unpack( |
| struct_in, |
| struct_len, |
| SPINEL_DATATYPE_IPv6ADDR_S, |
| &failed_addr |
| ); |
| |
| require(len > 0, bail); |
| |
| struct_in += len; |
| struct_len -= len; |
| |
| addrList.push_back(in6_addr_to_string(*failed_addr)); |
| } |
| |
| mMulticastListenerRegistrationResponse[kWPANTUNDValueMapKey_ThreadMlrResponse_Addresses] = addrList; |
| |
| syslog(LOG_DEBUG, "Received Multicast Listener Registration Response status=%u mlr_status=%u", |
| (unsigned)status, (unsigned)mlr_status); |
| } |
| |
| bail: |
| process_event(EVENT_NCP_PROP_VALUE_IS, key, original_value_data_ptr, original_value_data_len); |
| } |
| |
| void |
| SpinelNCPInstance::handle_ncp_spinel_value_inserted(spinel_prop_key_t key, const uint8_t* value_data_ptr, spinel_size_t value_data_len) |
| { |
| if (key == SPINEL_PROP_IPV6_ADDRESS_TABLE) { |
| struct in6_addr *addr = NULL; |
| uint8_t prefix_len = 0; |
| uint32_t valid_lifetime = 0xFFFFFFFF; |
| uint32_t preferred_lifetime = 0xFFFFFFFF; |
| |
| spinel_datatype_unpack(value_data_ptr, value_data_len, "6CLL", &addr, &prefix_len, &valid_lifetime, &preferred_lifetime); |
| |
| if (addr != NULL) { |
| if (!should_filter_address(*addr, prefix_len)) { |
| unicast_address_was_added(kOriginThreadNCP, *addr, prefix_len, valid_lifetime, preferred_lifetime); |
| } |
| } |
| |
| } else if (key == SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE) { |
| struct in6_addr *addr = NULL; |
| |
| spinel_datatype_unpack(value_data_ptr, value_data_len, "6", &addr); |
| |
| if ((addr != NULL) && !IN6_IS_ADDR_UNSPECIFIED(addr)) { |
| multicast_address_was_joined(kOriginThreadNCP, *addr); |
| } |
| |
| } else if (key == SPINEL_PROP_THREAD_CHILD_TABLE) { |
| SpinelNCPTaskGetNetworkTopology::TableEntry child_entry; |
| int status; |
| |
| status = SpinelNCPTaskGetNetworkTopology::parse_child_entry(value_data_ptr, value_data_len, child_entry); |
| |
| if (status == kWPANTUNDStatus_Ok) { |
| syslog(LOG_INFO, "[-NCP-]: ChildTable entry added: %s", child_entry.get_as_string().c_str()); |
| } |
| |
| } else if (key == SPINEL_PROP_THREAD_NEIGHBOR_TABLE) { |
| SpinelNCPTaskGetNetworkTopology::TableEntry neighbor_entry; |
| int status; |
| |
| status = SpinelNCPTaskGetNetworkTopology::parse_neighbor_entry(value_data_ptr, value_data_len, neighbor_entry); |
| |
| if (status == kWPANTUNDStatus_Ok) { |
| syslog(LOG_INFO, "[-NCP-]: Neighbor(Router) entry added: %s", neighbor_entry.get_as_string().c_str()); |
| } |
| |
| } else if (key == SPINEL_PROP_MESHCOP_COMMISSIONER_ENERGY_SCAN_RESULT) { |
| spinel_ssize_t len; |
| uint32_t channel_mask; |
| const uint8_t *energy_data = NULL; |
| unsigned int energy_data_len = 0; |
| ValueMap entry; |
| |
| len = spinel_datatype_unpack( |
| value_data_ptr, |
| value_data_len, |
| ( |
| SPINEL_DATATYPE_UINT32_S |
| SPINEL_DATATYPE_DATA_WLEN_S |
| ), |
| &channel_mask, |
| &energy_data, |
| &energy_data_len |
| ); |
| |
| __ASSERT_MACROS_check(len > 0); |
| |
| entry[kWPANTUNDValueMapKey_CommrEnergyScanResult_ChannelMask] = channel_mask; |
| entry[kWPANTUNDValueMapKey_CommrEnergyScanResult_Data] = Data(energy_data, energy_data_len); |
| |
| if (mCommissionerEnergyScanResult.size() == kMaxCommissionerEnergyScanResultEntries) { |
| mCommissionerEnergyScanResult.pop_front(); |
| } |
| |
| mCommissionerEnergyScanResult.push_back(entry); |
| |
| } else if (key == SPINEL_PROP_MESHCOP_COMMISSIONER_PAN_ID_CONFLICT_RESULT) { |
| spinel_ssize_t len; |
| uint16_t panid; |
| uint32_t channel_mask; |
| ValueMap entry; |
| |
| len = spinel_datatype_unpack( |
| value_data_ptr, |
| value_data_len, |
| ( |
| SPINEL_DATATYPE_UINT16_S |
| SPINEL_DATATYPE_UINT32_S |
| ), |
| &panid, |
| &channel_mask |
| ); |
| |
| __ASSERT_MACROS_check(len > 0); |
| |
| entry[kWPANTUNDValueMapKey_CommrPanIdConflict_PanId] = panid; |
| entry[kWPANTUNDValueMapKey_CommrPanIdConflict_ChannelMask] = channel_mask; |
| |
| if (mCommissionerPanIdConflictResult.size() == kMaxCommissionerPanIdConflictResultEntries) { |
| mCommissionerPanIdConflictResult.pop_front(); |
| } |
| |
| mCommissionerPanIdConflictResult.push_back(entry); |
| } |
| |
| process_event(EVENT_NCP_PROP_VALUE_INSERTED, key, value_data_ptr, value_data_len); |
| } |
| |
| void |
| SpinelNCPInstance::handle_ncp_spinel_value_removed(spinel_prop_key_t key, const uint8_t* value_data_ptr, spinel_size_t value_data_len) |
| { |
| if (key == SPINEL_PROP_THREAD_CHILD_TABLE) { |
| SpinelNCPTaskGetNetworkTopology::TableEntry child_entry; |
| int status; |
| |
| status = SpinelNCPTaskGetNetworkTopology::parse_child_entry(value_data_ptr, value_data_len, child_entry); |
| |
| if (status == kWPANTUNDStatus_Ok) { |
| syslog(LOG_INFO, "[-NCP-]: ChildTable entry removed: %s", child_entry.get_as_string().c_str()); |
| } |
| |
| } else if (key == SPINEL_PROP_THREAD_NEIGHBOR_TABLE) { |
| SpinelNCPTaskGetNetworkTopology::TableEntry neighbor_entry; |
| int status; |
| |
| status = SpinelNCPTaskGetNetworkTopology::parse_neighbor_entry(value_data_ptr, value_data_len, neighbor_entry); |
| |
| if (status == kWPANTUNDStatus_Ok) { |
| syslog(LOG_INFO, "[-NCP-]: Neighbor(Router) entry removed: %s", neighbor_entry.get_as_string().c_str()); |
| } |
| |
| } |
| |
| process_event(EVENT_NCP_PROP_VALUE_REMOVED, key, value_data_ptr, value_data_len); |
| } |
| |
| void |
| SpinelNCPInstance::handle_ncp_state_change(NCPState new_ncp_state, NCPState old_ncp_state) |
| { |
| NCPInstanceBase::handle_ncp_state_change(new_ncp_state, old_ncp_state); |
| |
| if ( ncp_state_is_joining_or_joined(old_ncp_state) |
| && (new_ncp_state == OFFLINE) |
| ) { |
| // Mark this as false so that if we are actually doing |
| // a pcap right now it will force the details to be updated |
| // on the NCP at the next run through the main loop. This |
| // allows us to go back to promiscuous-mode sniffing at |
| // disconnect |
| mIsPcapInProgress = false; |
| } |
| |
| if (ncp_state_is_associated(new_ncp_state) |
| && !ncp_state_is_associated(old_ncp_state) |
| ) { |
| mIsCommissioned = true; |
| start_new_task(SpinelNCPTaskSendCommand::Factory(this) |
| .add_command(SpinelPackData(SPINEL_FRAME_PACK_CMD_PROP_VALUE_GET, SPINEL_PROP_MAC_15_4_LADDR)) |
| .add_command(SpinelPackData(SPINEL_FRAME_PACK_CMD_PROP_VALUE_GET, SPINEL_PROP_IPV6_ML_ADDR)) |
| .add_command(SpinelPackData(SPINEL_FRAME_PACK_CMD_PROP_VALUE_GET, SPINEL_PROP_NET_XPANID)) |
| .add_command(SpinelPackData(SPINEL_FRAME_PACK_CMD_PROP_VALUE_GET, SPINEL_PROP_MAC_15_4_PANID)) |
| .add_command(SpinelPackData(SPINEL_FRAME_PACK_CMD_PROP_VALUE_GET, SPINEL_PROP_PHY_CHAN)) |
| .add_command(SpinelPackData(SPINEL_FRAME_PACK_CMD_PROP_VALUE_GET, SPINEL_PROP_IPV6_ADDRESS_TABLE)) |
| .finish() |
| ); |
| } else if (ncp_state_is_joining(new_ncp_state) |
| && !ncp_state_is_joining(old_ncp_state) |
| ) { |
| if (!buffer_is_nonzero(mNCPV6Prefix, 8)) { |
| start_new_task(SpinelNCPTaskSendCommand::Factory(this) |
| .add_command(SpinelPackData(SPINEL_FRAME_PACK_CMD_PROP_VALUE_GET, SPINEL_PROP_IPV6_ML_PREFIX)) |
| .finish() |
| ); |
| } |
| } |
| } |
| |
| void |
| SpinelNCPInstance::handle_ncp_spinel_callback(unsigned int command, const uint8_t* cmd_data_ptr, spinel_size_t cmd_data_len) |
| { |
| switch (command) { |
| case SPINEL_CMD_PROP_VALUE_IS: |
| case SPINEL_CMD_PROP_VALUE_INSERTED: |
| case SPINEL_CMD_PROP_VALUE_REMOVED: |
| { |
| spinel_prop_key_t key = SPINEL_PROP_LAST_STATUS; |
| uint8_t* value_data_ptr = NULL; |
| spinel_size_t value_data_len = 0; |
| spinel_ssize_t ret; |
| |
| ret = spinel_datatype_unpack(cmd_data_ptr, cmd_data_len, "CiiD", NULL, NULL, &key, &value_data_ptr, &value_data_len); |
| |
| __ASSERT_MACROS_check(ret != -1); |
| |
| if (ret == -1) { |
| break; |
| } |
| |
| switch (command) { |
| case SPINEL_CMD_PROP_VALUE_IS: |
| handle_ncp_spinel_value_is(key, value_data_ptr, value_data_len); |
| break; |
| case SPINEL_CMD_PROP_VALUE_INSERTED: |
| handle_ncp_spinel_value_inserted(key, value_data_ptr, value_data_len); |
| break; |
| case SPINEL_CMD_PROP_VALUE_REMOVED: |
| handle_ncp_spinel_value_removed(key, value_data_ptr, value_data_len); |
| break; |
| } |
| } |
| break; |
| |
| default: |
| process_event(EVENT_NCP(command), cmd_data_ptr[0], cmd_data_ptr, cmd_data_len); |
| } |
| } |
| |
| bool |
| SpinelNCPInstance::should_filter_address(const struct in6_addr &addr, uint8_t prefix_len) |
| { |
| static const uint8_t service_aloc_start = 0x10; |
| static const uint8_t service_aloc_end = 0x2F; |
| static const uint8_t rloc_bytes[] = {0x00,0x00,0x00,0xFF,0xFE,0x00}; |
| bool should_filter = false; |
| |
| if (mFilterRLOCAddresses) { |
| // Filter RLOC link-local or mesh-local addresses |
| |
| if (0 == memcmp(rloc_bytes, addr.s6_addr + 8, sizeof(rloc_bytes))) { |
| if( addr.s6_addr[ 14 ] == 0xFC ) { |
| if (addr.s6_addr[15] < service_aloc_start || addr.s6_addr[15] > service_aloc_end) |
| { |
| should_filter = mFilterALOCAddresses; |
| } |
| } else { |
| if (IN6_IS_ADDR_LINKLOCAL(&addr)) { |
| should_filter = true; |
| } |
| |
| if (buffer_is_nonzero(mNCPV6Prefix, sizeof(mNCPV6Prefix)) |
| && (0 == memcmp(mNCPV6Prefix, &addr, sizeof(mNCPV6Prefix))) |
| ) { |
| should_filter = true; |
| } |
| } |
| } |
| } |
| |
| return should_filter; |
| } |
| |
| void |
| SpinelNCPInstance::filter_addresses(void) |
| { |
| std::map<struct in6_addr, UnicastAddressEntry> unicast_addresses(mUnicastAddresses); |
| std::map<struct in6_addr, UnicastAddressEntry>::iterator iter; |
| |
| // We create a copy of mUnicastAddress map to iterate over |
| // since `mUnicastAddresses` entries can be removed while |
| // we filter and remove addresses. |
| |
| for (iter = unicast_addresses.begin(); iter != unicast_addresses.end(); ++iter) { |
| if (!iter->second.is_from_ncp()) { |
| continue; |
| } |
| |
| if (should_filter_address(iter->first, iter->second.get_prefix_len())) { |
| unicast_address_was_removed(kOriginThreadNCP, iter->first); |
| } |
| } |
| } |
| |
| void |
| SpinelNCPInstance::add_unicast_address_on_ncp(const struct in6_addr &addr, uint8_t prefix_len, CallbackWithStatus cb) |
| { |
| SpinelNCPTaskSendCommand::Factory factory(this); |
| |
| syslog(LOG_NOTICE, "Adding address \"%s/%d\" to NCP", in6_addr_to_string(addr).c_str(), prefix_len); |
| |
| factory.set_callback(cb); |
| |
| factory.add_command( |
| SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_INSERT( |
| SPINEL_DATATYPE_IPv6ADDR_S // Address |
| SPINEL_DATATYPE_UINT8_S // Prefix Length |
| SPINEL_DATATYPE_UINT32_S // Valid Lifetime |
| SPINEL_DATATYPE_UINT32_S // Preferred Lifetime |
| ), |
| SPINEL_PROP_IPV6_ADDRESS_TABLE, |
| &addr, |
| prefix_len, |
| UINT32_MAX, |
| UINT32_MAX |
| ) |
| ); |
| |
| start_new_task(factory.finish()); |
| } |
| |
| void |
| SpinelNCPInstance::remove_unicast_address_on_ncp(const struct in6_addr& addr, uint8_t prefix_len, CallbackWithStatus cb) |
| { |
| SpinelNCPTaskSendCommand::Factory factory(this); |
| |
| syslog(LOG_NOTICE, "Removing address \"%s/%d\" from NCP", in6_addr_to_string(addr).c_str(), prefix_len); |
| |
| factory.set_callback(cb); |
| |
| factory.add_command( |
| SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_REMOVE( |
| SPINEL_DATATYPE_IPv6ADDR_S // Address |
| SPINEL_DATATYPE_UINT8_S // Prefix |
| ), |
| SPINEL_PROP_IPV6_ADDRESS_TABLE, |
| &addr, |
| prefix_len |
| ) |
| ); |
| |
| start_new_task(factory.finish()); |
| } |
| |
| void |
| SpinelNCPInstance::add_multicast_address_on_ncp(const struct in6_addr &addr, CallbackWithStatus cb) |
| { |
| SpinelNCPTaskSendCommand::Factory factory(this); |
| |
| syslog(LOG_NOTICE, "Adding multicast address \"%s\" to NCP", in6_addr_to_string(addr).c_str()); |
| |
| factory.set_callback(cb); |
| |
| factory.add_command( |
| SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_INSERT( |
| SPINEL_DATATYPE_IPv6ADDR_S // Address |
| ), |
| SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE, |
| &addr |
| ) |
| ); |
| |
| start_new_task(factory.finish()); |
| } |
| |
| void |
| SpinelNCPInstance::remove_multicast_address_on_ncp(const struct in6_addr &addr, CallbackWithStatus cb) |
| { |
| SpinelNCPTaskSendCommand::Factory factory(this); |
| |
| syslog(LOG_NOTICE, "Removing multicast address \"%s\" from NCP", in6_addr_to_string(addr).c_str()); |
| |
| factory.set_callback(cb); |
| |
| factory.add_command( |
| SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_REMOVE( |
| SPINEL_DATATYPE_IPv6ADDR_S // Address |
| ), |
| SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE, |
| &addr |
| ) |
| ); |
| |
| start_new_task(factory.finish()); |
| } |
| |
| void |
| SpinelNCPInstance::add_service_on_ncp(uint32_t enterprise_number, const Data& service_data, bool stable, |
| const Data& server_data, CallbackWithStatus cb) |
| { |
| SpinelNCPTaskSendCommand::Factory factory(this); |
| |
| syslog(LOG_NOTICE, "Adding service with enterprise number:%u to NCP", enterprise_number); |
| |
| if (mCapabilities.count(SPINEL_CAP_THREAD_SERVICE) > 0) { |
| factory.set_lock_property(SPINEL_PROP_SERVER_ALLOW_LOCAL_DATA_CHANGE); |
| factory.set_callback(cb); |
| |
| factory.add_command(SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_INSERT( |
| SPINEL_DATATYPE_UINT32_S // Enterprise Number |
| SPINEL_DATATYPE_DATA_WLEN_S // Service Data |
| SPINEL_DATATYPE_BOOL_S // stable |
| SPINEL_DATATYPE_DATA_WLEN_S // Server Data |
| ), |
| SPINEL_PROP_SERVER_SERVICES, |
| enterprise_number, |
| service_data.data(), |
| service_data.size(), |
| stable, |
| server_data.data(), |
| server_data.size() |
| )); |
| |
| start_new_task(factory.finish()); |
| } else { |
| syslog(LOG_ERR, "%s capability not supported", spinel_capability_to_cstr(SPINEL_CAP_THREAD_SERVICE)); |
| cb(kWPANTUNDStatus_FeatureNotSupported); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::remove_service_on_ncp(uint32_t enterprise_number, const Data& service_data, CallbackWithStatus cb) |
| { |
| SpinelNCPTaskSendCommand::Factory factory(this); |
| |
| syslog(LOG_NOTICE, "Removing service with enterprise number:%u from NCP", enterprise_number); |
| |
| if (mCapabilities.count(SPINEL_CAP_THREAD_SERVICE) > 0) { |
| factory.set_lock_property(SPINEL_PROP_SERVER_ALLOW_LOCAL_DATA_CHANGE); |
| factory.set_callback(cb); |
| |
| factory.add_command(SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_REMOVE( |
| SPINEL_DATATYPE_UINT32_S // Enterprise Number |
| SPINEL_DATATYPE_DATA_WLEN_S // Service Data |
| ), |
| SPINEL_PROP_SERVER_SERVICES, |
| enterprise_number, |
| service_data.data(), |
| service_data.size() |
| )); |
| |
| start_new_task(factory.finish()); |
| } else { |
| syslog(LOG_ERR, "%s capability not supported", spinel_capability_to_cstr(SPINEL_CAP_THREAD_SERVICE)); |
| cb(kWPANTUNDStatus_FeatureNotSupported); |
| } |
| } |
| |
| void |
| SpinelNCPInstance::add_on_mesh_prefix_on_ncp(const struct in6_addr &prefix, uint8_t prefix_len, uint16_t flags, |
| bool stable, CallbackWithStatus cb) |
| { |
| SpinelNCPTaskSendCommand::Factory factory(this); |
| |
| syslog(LOG_NOTICE, "Adding on-mesh prefix \"%s/%d\" to NCP", in6_addr_to_string(prefix).c_str(), prefix_len); |
| |
| factory.set_lock_property(SPINEL_PROP_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE); |
| factory.set_callback(cb); |
| |
| factory.add_command(SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_INSERT( |
| SPINEL_DATATYPE_IPv6ADDR_S |
| SPINEL_DATATYPE_UINT8_S |
| SPINEL_DATATYPE_BOOL_S |
| SPINEL_DATATYPE_UINT8_S |
| SPINEL_DATATYPE_BOOL_S |
| SPINEL_DATATYPE_UINT16_S |
| SPINEL_DATATYPE_UINT8_S |
| ), |
| SPINEL_PROP_THREAD_ON_MESH_NETS, |
| &prefix, |
| prefix_len, |
| stable, |
| flags & 0xff, |
| false, |
| 0, |
| (flags >> 8) & 0xff |
| )); |
| |
| start_new_task(factory.finish()); |
| } |
| |
| void |
| SpinelNCPInstance::remove_on_mesh_prefix_on_ncp(const struct in6_addr &prefix, uint8_t prefix_len, uint16_t flags, |
| bool stable, CallbackWithStatus cb) |
| { |
| SpinelNCPTaskSendCommand::Factory factory(this); |
| |
| syslog(LOG_NOTICE, "Removing on-mesh prefix \"%s/%d\" from NCP", in6_addr_to_string(prefix).c_str(), prefix_len); |
| |
| factory.set_lock_property(SPINEL_PROP_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE); |
| factory.set_callback(cb); |
| |
| factory.add_command(SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_REMOVE( |
| SPINEL_DATATYPE_IPv6ADDR_S |
| SPINEL_DATATYPE_UINT8_S |
| SPINEL_DATATYPE_BOOL_S |
| SPINEL_DATATYPE_UINT8_S |
| ), |
| SPINEL_PROP_THREAD_ON_MESH_NETS, |
| &prefix, |
| prefix_len, |
| stable, |
| flags & 0xff |
| )); |
| |
| start_new_task(factory.finish()); |
| } |
| |
| void |
| SpinelNCPInstance::add_route_on_ncp(const struct in6_addr &route, uint8_t prefix_len, RoutePreference preference, |
| bool stable, CallbackWithStatus cb) |
| { |
| SpinelNCPTaskSendCommand::Factory factory(this); |
| |
| syslog(LOG_NOTICE, "Adding off-mesh route \"%s/%d\" with preference %s to NCP", in6_addr_to_string(route).c_str(), |
| prefix_len, NCPControlInterface::external_route_priority_to_string(preference).c_str()); |
| |
| factory.set_lock_property(SPINEL_PROP_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE); |
| factory.set_callback(cb); |
| |
| factory.add_command(SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_INSERT( |
| SPINEL_DATATYPE_IPv6ADDR_S |
| SPINEL_DATATYPE_UINT8_S |
| SPINEL_DATATYPE_BOOL_S |
| SPINEL_DATATYPE_UINT8_S |
| ), |
| SPINEL_PROP_THREAD_OFF_MESH_ROUTES, |
| &route, |
| prefix_len, |
| stable, |
| convert_route_preference_to_flags(preference) |
| )); |
| |
| start_new_task(factory.finish()); |
| } |
| |
| void |
| SpinelNCPInstance::remove_route_on_ncp(const struct in6_addr &route, uint8_t prefix_len, RoutePreference preference, |
| bool stable, CallbackWithStatus cb) |
| { |
| SpinelNCPTaskSendCommand::Factory factory(this); |
| |
| syslog(LOG_NOTICE, "Removing off-mesh route \"%s/%d\" with preference %s from NCP", in6_addr_to_string(route).c_str(), |
| prefix_len, NCPControlInterface::external_route_priority_to_string(preference).c_str()); |
| |
| factory.set_lock_property(SPINEL_PROP_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE); |
| factory.set_callback(cb); |
| |
| factory.add_command(SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_REMOVE( |
| SPINEL_DATATYPE_IPv6ADDR_S |
| SPINEL_DATATYPE_UINT8_S |
| SPINEL_DATATYPE_BOOL_S |
| SPINEL_DATATYPE_UINT8_S |
| ), |
| SPINEL_PROP_THREAD_OFF_MESH_ROUTES, |
| &route, |
| prefix_len, |
| stable, |
| convert_route_preference_to_flags(preference) |
| )); |
| |
| start_new_task(factory.finish()); |
| } |
| |
| SpinelNCPInstance::RoutePreference |
| SpinelNCPInstance::convert_flags_to_route_preference(uint8_t flags) |
| { |
| RoutePreference preference = NCPControlInterface::ROUTE_MEDIUM_PREFERENCE; |
| |
| switch (flags & SPINEL_NET_FLAG_PREFERENCE_MASK) { |
| case SPINEL_ROUTE_PREFERENCE_HIGH: |
| preference = NCPControlInterface::ROUTE_HIGH_PREFERENCE; |
| break; |
| |
| case SPINEL_ROUTE_PREFERENCE_MEDIUM: |
| preference = NCPControlInterface::ROUTE_MEDIUM_PREFERENCE; |
| break; |
| |
| case SPINEL_ROUTE_PREFERENCE_LOW: |
| preference = NCPControlInterface::ROUTE_LOW_PREFRENCE; |
| break; |
| |
| default: |
| syslog(LOG_WARNING, "Invalid RoutePreference flag 0x%02x (using MEDIUM instead)", flags); |
| break; |
| } |
| |
| return preference; |
| } |
| |
| uint8_t |
| SpinelNCPInstance::convert_route_preference_to_flags(RoutePreference preference) |
| { |
| uint8_t flags = SPINEL_ROUTE_PREFERENCE_MEDIUM; |
| |
| switch (preference) { |
| case NCPControlInterface::ROUTE_HIGH_PREFERENCE: |
| flags = SPINEL_ROUTE_PREFERENCE_HIGH; |
| break; |
| |
| case NCPControlInterface::ROUTE_MEDIUM_PREFERENCE: |
| flags = SPINEL_ROUTE_PREFERENCE_MEDIUM; |
| break; |
| |
| case NCPControlInterface::ROUTE_LOW_PREFRENCE: |
| flags = SPINEL_ROUTE_PREFERENCE_LOW; |
| break; |
| } |
| |
| return flags; |
| } |
| |
| void |
| SpinelNCPInstance::log_spinel_frame(SpinelFrameOrigin origin, const uint8_t *frame_ptr, spinel_size_t frame_len) |
| { |
| int logmask = setlogmask(0); |
| |
| setlogmask(logmask); |
| |
| if (logmask & LOG_MASK(LOG_INFO)) { |
| std::string log; |
| uint8_t header = 0; |
| unsigned int command = 0; |
| const uint8_t *cmd_payload_ptr = NULL; |
| spinel_size_t cmd_payload_len = 0; |
| spinel_ssize_t read_len; |
| uint8_t tid; |
| const char *command_str; |
| const char *origin_str = (origin == kDriverToNCP) ? "[->NCP]" : "[NCP->]"; |
| |
| read_len = spinel_datatype_unpack(frame_ptr, frame_len, "CiD", &header, &command, &cmd_payload_ptr, |
| &cmd_payload_len); |
| require_quiet(read_len > 0, bail); |
| |
| tid = SPINEL_HEADER_GET_TID(header); |
| command_str = spinel_command_to_cstr(command); |
| |
| switch (command) { |
| case SPINEL_CMD_NOOP: |
| case SPINEL_CMD_RESET: |
| case SPINEL_CMD_NET_CLEAR: |
| syslog(LOG_INFO, "%s (%d) %s", origin_str, tid, command_str); |
| break; |
| |
| case SPINEL_CMD_PROP_VALUE_GET: |
| case SPINEL_CMD_PROP_VALUE_SET: |
| case SPINEL_CMD_PROP_VALUE_INSERT: |
| case SPINEL_CMD_PROP_VALUE_REMOVE: |
| case SPINEL_CMD_PROP_VALUE_IS: |
| case SPINEL_CMD_PROP_VALUE_INSERTED: |
| case SPINEL_CMD_PROP_VALUE_REMOVED: |
| { |
| spinel_prop_key_t prop_key = SPINEL_PROP_LAST_STATUS; |
| const uint8_t *value_ptr = NULL; |
| spinel_size_t value_len = 0; |
| const char *prop_str; |
| bool skip_value_dump = false; |
| char value_dump_str[2 * kWPANTUND_SpinelPropValueDumpLen + 1]; |
| |
| read_len = spinel_datatype_unpack(cmd_payload_ptr, cmd_payload_len, "iD", &prop_key, &value_ptr, |
| &value_len); |
| require_quiet(read_len > 0, bail); |
| |
| prop_str = spinel_prop_key_to_cstr(prop_key); |
| |
| switch (prop_key) { |
| case SPINEL_PROP_STREAM_DEBUG: // Handled by `handle_ncp_debug_stream()` |
| case SPINEL_PROP_STREAM_LOG: // Handled by `handle_ncp_log_stream()` |
| case SPINEL_PROP_STREAM_NET: // Handled by `handle_normal_ipv6_from_ncp() |
| case SPINEL_PROP_STREAM_NET_INSECURE: // Handled by `handle_normal_ipv6_from_ncp() |
| // Skip logging any of above properties |
| goto bail; |
| |
| case SPINEL_PROP_NET_MASTER_KEY: |
| case SPINEL_PROP_THREAD_ACTIVE_DATASET: |
| case SPINEL_PROP_THREAD_PENDING_DATASET: |
| case SPINEL_PROP_MESHCOP_JOINER_COMMISSIONING: |
| case SPINEL_PROP_NET_PSKC: |
| case SPINEL_PROP_MESHCOP_COMMISSIONER_JOINERS: |
| // Hide the value by skipping value dump |
| skip_value_dump = true; |
| break; |
| |
| default: |
| skip_value_dump = false; |
| encode_data_into_string(value_ptr, value_len, value_dump_str, sizeof(value_dump_str), 0); |
| break; |
| } |
| |
| if (command == SPINEL_CMD_PROP_VALUE_GET) { |
| syslog(LOG_INFO, "%s (%d) %s(%s)", origin_str, tid, command_str, prop_str); |
| } else { |
| syslog(LOG_INFO, "%s (%d) %s(%s) [%s%s]", origin_str, tid, command_str, prop_str, |
| skip_value_dump ? "-- value hidden --" : value_dump_str, |
| skip_value_dump || (value_len <= kWPANTUND_SpinelPropValueDumpLen) ? "" : "..."); |
| } |
| } |
| break; |
| |
| case SPINEL_CMD_PEEK: |
| case SPINEL_CMD_POKE: |
| case SPINEL_CMD_PEEK_RET: |
| { |
| uint32_t address = 0; |
| uint16_t count = 0; |
| read_len = spinel_datatype_unpack(cmd_payload_ptr, cmd_payload_len, "LS", &address, &count); |
| require_quiet(read_len > 0, bail); |
| syslog(LOG_INFO, "%s (%d) %s(0x%x, %d)", origin_str, tid, command_str, address, count); |
| } |
| break; |
| |
| default: |
| syslog(LOG_INFO, "%s (%d) %s(cmd_id:%d)", origin_str, tid, command_str, command); |
| break; |
| } |
| } |
| |
| bail: |
| return; |
| } |
| |
| bool |
| SpinelNCPInstance::is_busy(void) |
| { |
| return NCPInstanceBase::is_busy() |
| || !mTaskQueue.empty(); |
| } |
| |
| void |
| SpinelNCPInstance::process(void) |
| { |
| NCPInstanceBase::process(); |
| |
| mVendorCustom.process(); |
| |
| if (!is_initializing_ncp() && mTaskQueue.empty()) { |
| bool x = mPcapManager.is_enabled(); |
| |
| if (mIsPcapInProgress != x) { |
| SpinelNCPTaskSendCommand::Factory factory(this); |
| |
| mIsPcapInProgress = x; |
| |
| factory.add_command(SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_SET(SPINEL_DATATYPE_BOOL_S), |
| SPINEL_PROP_MAC_RAW_STREAM_ENABLED, |
| mIsPcapInProgress |
| )); |
| |
| if (mIsPcapInProgress) { |
| factory.add_command(SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_SET(SPINEL_DATATYPE_BOOL_S), |
| SPINEL_PROP_NET_IF_UP, |
| true |
| )); |
| if (!ncp_state_is_joining_or_joined(get_ncp_state())) { |
| factory.add_command(SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_SET(SPINEL_DATATYPE_UINT8_S), |
| SPINEL_PROP_MAC_PROMISCUOUS_MODE, |
| SPINEL_MAC_PROMISCUOUS_MODE_FULL |
| )); |
| } |
| } else { |
| factory.add_command(SpinelPackData( |
| SPINEL_FRAME_PACK_CMD_PROP_VALUE_SET(SPINEL_DATATYPE_UINT8_S), |
| SPINEL_PROP_MAC_PROMISCUOUS_MODE, |
| SPINEL_MAC_PROMISCUOUS_MODE_OFF |
| )); |
| } |
| |
| start_new_task(factory.finish()); |
| NCPInstanceBase::process(); |
| } |
| } |
| } |