diff --git a/etc/visual-studio/libopenthread-ncp-spi.vcxproj b/etc/visual-studio/libopenthread-ncp-spi.vcxproj
index 2b01424c6..694b1b32e 100644
--- a/etc/visual-studio/libopenthread-ncp-spi.vcxproj
+++ b/etc/visual-studio/libopenthread-ncp-spi.vcxproj
@@ -58,12 +58,17 @@
+
+
+
+
+
@@ -72,4 +77,4 @@
-
\ No newline at end of file
+
diff --git a/etc/visual-studio/libopenthread-ncp-spi.vcxproj.filters b/etc/visual-studio/libopenthread-ncp-spi.vcxproj.filters
index a2f8547ca..c58c45d1c 100644
--- a/etc/visual-studio/libopenthread-ncp-spi.vcxproj.filters
+++ b/etc/visual-studio/libopenthread-ncp-spi.vcxproj.filters
@@ -15,9 +15,21 @@
+
+ Source Files
+
Source Files
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
Source Files
@@ -29,6 +41,9 @@
+
+ Header Files
+
Header Files
@@ -42,4 +57,4 @@
Header Files
-
\ No newline at end of file
+
diff --git a/etc/visual-studio/libopenthread-ncp-uart.vcxproj b/etc/visual-studio/libopenthread-ncp-uart.vcxproj
index e7c59740e..201bd4177 100644
--- a/etc/visual-studio/libopenthread-ncp-uart.vcxproj
+++ b/etc/visual-studio/libopenthread-ncp-uart.vcxproj
@@ -58,13 +58,18 @@
+
+
+
+
+
diff --git a/etc/visual-studio/libopenthread-ncp-uart.vcxproj.filters b/etc/visual-studio/libopenthread-ncp-uart.vcxproj.filters
index ff54433e5..7f5765def 100644
--- a/etc/visual-studio/libopenthread-ncp-uart.vcxproj.filters
+++ b/etc/visual-studio/libopenthread-ncp-uart.vcxproj.filters
@@ -15,12 +15,24 @@
+
+ Source Files
+
Source Files
Source Files
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
Source Files
@@ -32,6 +44,9 @@
+
+ Header Files
+
Header Files
diff --git a/include/openthread/ncp.h b/include/openthread/ncp.h
index 2cd1d4a35..e1ddb471e 100644
--- a/include/openthread/ncp.h
+++ b/include/openthread/ncp.h
@@ -173,12 +173,18 @@ typedef struct otNcpLegacyHandlers
/**
* This callback is invoked by the legacy stack to notify that a new
* legacy node did join the network.
+ *
+ * @param[in] aExtAddr A pointer to the extended address of the joined node.
+ *
*/
void otNcpHandleLegacyNodeDidJoin(const otExtAddress *aExtAddr);
/**
* This callback is invoked by the legacy stack to notify that the
* legacy ULA prefix has changed.
+ *
+ * param[in] aUlaPrefix A pointer to the received ULA prefix.
+ *
*/
void otNcpHandleDidReceiveNewLegacyUlaPrefix(const uint8_t *aUlaPrefix);
diff --git a/src/ncp/Makefile.am b/src/ncp/Makefile.am
index e187cf6d5..9b5697613 100644
--- a/src/ncp/Makefile.am
+++ b/src/ncp/Makefile.am
@@ -61,8 +61,13 @@ libopenthread_ncp_ftd_a_CPPFLAGS = \
$(NULL)
COMMON_SOURCES = \
- ncp_base.cpp \
+ changed_props_set.cpp \
+ changed_props_set.hpp \
ncp_base.hpp \
+ ncp_base.cpp \
+ ncp_base_mtd.cpp \
+ ncp_base_ftd.cpp \
+ ncp_base_radio.cpp \
ncp_buffer.cpp \
ncp_buffer.hpp \
spinel.c \
diff --git a/src/ncp/changed_props_set.cpp b/src/ncp/changed_props_set.cpp
new file mode 100644
index 000000000..bd0b98dbe
--- /dev/null
+++ b/src/ncp/changed_props_set.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2016-2017, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "changed_props_set.hpp"
+
+namespace ot {
+namespace Ncp {
+
+// ----------------------------------------------------------------------------
+// MARK: ChangedPropsSet class
+// ----------------------------------------------------------------------------
+
+// Defines the list of properties that can support unsolicited update.
+//
+// Note that {`SPINEL_PROP_LAST_STATUS`, `SPINEL_STATUS_RESET_UNKNOWN`} should be first entry to ensure that RESET is
+// reported before any other property update.
+//
+// Since a `uint32_t` is used as bit-mask to track which entries are in the changed set, we should ensure that the
+// number of entries in the list is always less than or equal to 32.
+//
+const ChangedPropsSet::Entry ChangedPropsSet::mSupportedProps[] =
+{
+ // Spinel property Status (if prop is `LAST_STATUS`) IsFilterable?
+
+ { SPINEL_PROP_LAST_STATUS, SPINEL_STATUS_RESET_UNKNOWN, false }, // 0
+ { SPINEL_PROP_STREAM_DEBUG, SPINEL_STATUS_OK, true }, // 1
+ { SPINEL_PROP_IPV6_ADDRESS_TABLE, SPINEL_STATUS_OK, true }, // 2
+ { SPINEL_PROP_NET_ROLE, SPINEL_STATUS_OK, true }, // 3
+ { SPINEL_PROP_IPV6_LL_ADDR, SPINEL_STATUS_OK, true }, // 4
+ { SPINEL_PROP_IPV6_ML_ADDR, SPINEL_STATUS_OK, true }, // 5
+ { SPINEL_PROP_NET_PARTITION_ID, SPINEL_STATUS_OK, true }, // 6
+ { SPINEL_PROP_NET_KEY_SEQUENCE_COUNTER, SPINEL_STATUS_OK, true }, // 7
+ { SPINEL_PROP_THREAD_LEADER_NETWORK_DATA, SPINEL_STATUS_OK, true }, // 8
+ { SPINEL_PROP_THREAD_CHILD_TABLE, SPINEL_STATUS_OK, true }, // 9
+ { SPINEL_PROP_THREAD_ON_MESH_NETS, SPINEL_STATUS_OK, true }, // 10
+ { SPINEL_PROP_THREAD_OFF_MESH_ROUTES, SPINEL_STATUS_OK, true }, // 11
+ { SPINEL_PROP_NET_STACK_UP, SPINEL_STATUS_OK, true }, // 12
+ { SPINEL_PROP_NET_REQUIRE_JOIN_EXISTING, SPINEL_STATUS_OK, true }, // 13
+ { SPINEL_PROP_LAST_STATUS, SPINEL_STATUS_NOMEM, true }, // 14
+ { SPINEL_PROP_LAST_STATUS, SPINEL_STATUS_DROPPED, true }, // 15
+#if OPENTHREAD_ENABLE_JAM_DETECTION
+ { SPINEL_PROP_JAM_DETECTED, SPINEL_STATUS_OK, true }, // 16
+#endif
+#if OPENTHREAD_ENABLE_LEGACY
+ { SPINEL_PROP_NEST_LEGACY_ULA_PREFIX, SPINEL_STATUS_OK, true }, // 17
+ { SPINEL_PROP_NEST_LEGACY_LAST_NODE_JOINED, SPINEL_STATUS_OK, true }, // 18
+#endif
+ { SPINEL_PROP_LAST_STATUS, SPINEL_STATUS_JOIN_FAILURE, false }, // 19
+ { SPINEL_PROP_MAC_SCAN_STATE, SPINEL_STATUS_OK, false }, // 20
+};
+
+uint8_t ChangedPropsSet::GetNumEntries(void) const
+{
+ return (sizeof(mSupportedProps) / sizeof(mSupportedProps[0]));
+}
+
+void ChangedPropsSet::Add(spinel_prop_key_t aPropKey, spinel_status_t aStatus)
+{
+ uint8_t numEntries;
+ const Entry *entry;
+
+ entry = GetSupportedEntries(numEntries);
+
+ for (uint8_t index = 0; index < numEntries; index++, entry++)
+ {
+ if ((entry->mPropKey == aPropKey) && (entry->mStatus == aStatus))
+ {
+ if (!IsEntryFiltered(index))
+ {
+ SetBit(mChangedSet, index);
+ }
+
+ break;
+ }
+ }
+}
+
+otError ChangedPropsSet::EnablePropertyFilter(spinel_prop_key_t aPropKey, bool aEnable)
+{
+ uint8_t numEntries;
+ const Entry *entry;
+ bool didFind = false;
+
+ entry = GetSupportedEntries(numEntries);
+
+ for (uint8_t index = 0; index < numEntries; index++, entry++)
+ {
+ if (entry->mFilterable && (entry->mPropKey == aPropKey))
+ {
+ if (aEnable)
+ {
+ SetBit(mFilterSet, index);
+
+ // If filter is enabled for a property, the `mChangedSet` is cleared
+ // for the same property so to ensure a pending update is also filtered.
+
+ ClearBit(mChangedSet, index);
+ }
+ else
+ {
+ ClearBit(mFilterSet, index);
+ }
+
+ didFind = true;
+
+ // Continue the search only if the prop key is `LAST_STATUS`, as
+ // we have multiple filterable `LAST_STATUS` entries in the table
+ // with different error status (DROPPED and NOMEM).
+
+ if (aPropKey != SPINEL_PROP_LAST_STATUS)
+ {
+ break;
+ }
+ }
+ }
+
+ return didFind ? OT_ERROR_NONE : OT_ERROR_INVALID_ARGS;
+}
+
+bool ChangedPropsSet::IsPropertyFiltered(spinel_prop_key_t aPropKey) const
+{
+ bool isFiltered = false;
+ uint8_t numEntries;
+ const Entry *entry;
+
+ entry = GetSupportedEntries(numEntries);
+
+ for (uint8_t index = 0; index < numEntries; index++, entry++)
+ {
+ if (entry->mFilterable && (entry->mPropKey == aPropKey))
+ {
+ isFiltered = IsEntryFiltered(index);
+
+ break;
+ }
+ }
+
+ return isFiltered;
+}
+
+} // namespace Ncp
+} // namespace ot
diff --git a/src/ncp/changed_props_set.hpp b/src/ncp/changed_props_set.hpp
new file mode 100644
index 000000000..c420e0b87
--- /dev/null
+++ b/src/ncp/changed_props_set.hpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2016-2017, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * This file contains definitions a spinel interface to the OpenThread stack.
+ */
+
+#ifndef CHANGED_PROPS_SET_HPP_
+#define CHANGED_PROPS_SET_HPP_
+
+#include
+
+#include "spinel.h"
+
+namespace ot {
+namespace Ncp {
+
+/**
+ * Defines a class to track a set of property/status changes that require update to host. The properties that can
+ * be added to this set must support sending unsolicited updates. This class also provides mechanism for user
+ * to block certain filterable properties disallowing the unsolicited update from them.
+ *
+ */
+class ChangedPropsSet
+{
+public:
+ /**
+ * Defines an entry in the set/list.
+ *
+ */
+ struct Entry
+ {
+ spinel_prop_key_t mPropKey; ///< The spinel property key.
+ spinel_status_t mStatus; ///< The spinel status (used only if prop key is `LAST_STATUS`).
+ bool mFilterable; ///< Indicates whether the entry can be filtered
+ };
+
+ /**
+ * This constructor initializes the set.
+ *
+ */
+ ChangedPropsSet(void):
+ mChangedSet(0),
+ mFilterSet(0)
+ { }
+
+ /**
+ * This method clears the set.
+ *
+ */
+ void Clear(void) { mChangedSet = 0; }
+
+ /**
+ * This method indicates if the set is empty or not.
+ *
+ * @returns TRUE if the set if empty, FALSE otherwise.
+ *
+ */
+ bool IsEmpty(void) const { return (mChangedSet == 0); }
+
+ /**
+ * This method adds a property to the set. The property added must be in the list of supported properties
+ * capable of sending unsolicited update, otherwise the input is ignored.
+ *
+ * Note that if the property is already in the set, adding it again does not change the set.
+ *
+ * @param[in] aPropKey The spinel property key to be added to the set
+ *
+ */
+ void AddProperty(spinel_prop_key_t aPropKey) { Add(aPropKey, SPINEL_STATUS_OK); }
+
+ /**
+ * This method adds a `LAST_STATUS` update to the set. The update must be in list of supported entries.
+ *
+ * @param[in] aStatus The spinel status update to be added to set.
+ *
+ */
+ void AddLastStatus(spinel_status_t aStatus) { Add(SPINEL_PROP_LAST_STATUS, aStatus); }
+
+ /**
+ * This method returns a pointer to array of entries of supported property/status updates. The list includes
+ * all properties that can generate unsolicited update.
+ *
+ * @param[out] aNumEntries A reference to output the number of entries in the list.
+ *
+ * @returns A pointer to the supported entries array.
+ *
+ */
+ const Entry *GetSupportedEntries(uint8_t &aNumEntries) const {
+ aNumEntries = GetNumEntries();
+ return &mSupportedProps[0];
+ }
+
+ /**
+ * This method returns a pointer to the entry associated with a given index.
+ *
+ * @param[in] aIndex The index to an entry.
+ *
+ * @returns A pointer to the entry associated with @p aIndex, or NULL if the index is beyond end of array.
+ *
+ */
+ const Entry *GetEntry(uint8_t aIndex) const {
+ return (aIndex < GetNumEntries()) ? &mSupportedProps[aIndex] : NULL;
+ }
+
+ /**
+ * This method indicates if the entry associated with an index is in the set (i.e., it has been changed and
+ * requires an unsolicited update).
+ *
+ * @param[in] aIndex The index to an entry.
+ *
+ * @returns TRUE if the entry is in the set, FALSE otherwise.
+ *
+ */
+ bool IsEntryChanged(uint8_t aIndex) const { return IsBitSet(mChangedSet, aIndex); }
+
+ /**
+ * This method removes an entry associated with an index in the set.
+ *
+ * Note that if the property/entry is not in the set, removing it simply does nothing.
+ *
+ * @param[in] aIndex Index of entry to be removed.
+ *
+ */
+ void RemoveEntry(uint8_t aIndex) { ClearBit(mChangedSet, aIndex); }
+
+ /**
+ * This method enables/disables filtering of a given property.
+ *
+ * @param[in] aPropKey The property key to filter.
+ * @param[in] aEnable TRUE to enable filtering, FALSE to disable.
+ *
+ * @retval OT_ERROR_NONE Filter state for given property updated successfully.
+ * @retval OT_ERROR_INVALID_ARGS The given property is not valid (i.e., not capable of unsolicited update).
+ *
+ */
+ otError EnablePropertyFilter(spinel_prop_key_t aPropKey, bool aEnable);
+
+ /**
+ * This method determines whether filtering is enabled for an entry associated with an index.
+ *
+ * @param[in] aIndex Index of entry to be checked.
+ *
+ * @returns TRUE if the filter is enabled for the given entry, FALSE otherwise.
+ *
+ */
+ bool IsEntryFiltered(uint8_t aIndex) const { return IsBitSet(mFilterSet, aIndex); }
+
+ /**
+ * This method determines whether filtering is enabled for a given property key.
+ *
+ * @param[in] aPropKey The property key to check.
+ *
+ * @returns TRUE if the filter is enabled for the given property, FALSE if the property is not filtered or if
+ * it is not filterable.
+ *
+ */
+ bool IsPropertyFiltered(spinel_prop_key_t aPropKey) const;
+
+ /**
+ * This method clears the filter.
+ *
+ */
+ void ClearFilter(void) { mFilterSet = 0; }
+
+private:
+ uint8_t GetNumEntries(void) const;
+ void Add(spinel_prop_key_t aPropKey, spinel_status_t aStatus);
+
+ static void SetBit (uint32_t &aBitset, uint8_t aBitIndex) { aBitset |= (1U << aBitIndex); }
+ static void ClearBit(uint32_t &aBitset, uint8_t aBitIndex) { aBitset &= ~(1U << aBitIndex); }
+ static bool IsBitSet(uint32_t aBitset, uint8_t aBitIndex) { return (aBitset & (1U << aBitIndex)) != 0; }
+
+ static const Entry mSupportedProps[];
+
+ uint32_t mChangedSet;
+ uint32_t mFilterSet;
+};
+
+} // namespace Ncp
+} // namespace ot
+
+#endif // CHANGED_PROPS_SET_HPP
diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp
index 25eee16fe..86ca5b9ad 100644
--- a/src/ncp/ncp_base.cpp
+++ b/src/ncp/ncp_base.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, The OpenThread Authors.
+ * Copyright (c) 2016-2017, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,7 +27,7 @@
/**
* @file
- * This file implements a Spinel interface to the OpenThread stack.
+ * This file implements general thread device required Spinel interface to the OpenThread stack.
*/
#include
@@ -37,32 +37,12 @@
#include
#include
-#if OPENTHREAD_ENABLE_TMF_PROXY && OPENTHREAD_FTD
-#include
-#endif
-
-#if OPENTHREAD_ENABLE_BORDER_ROUTER
-#include
-#endif
-
-#if OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
-#include
-#endif
-
#include
#include
-#if OPENTHREAD_ENABLE_JAM_DETECTION
-#include
-#endif
-
#include
#include
-#if OPENTHREAD_FTD
-#include
-#endif
-
#include
#include
@@ -73,8 +53,8 @@
#include "net/ip6.hpp"
namespace ot {
+namespace Ncp {
-#define NCP_INVALID_SCAN_CHANNEL (-1)
// ----------------------------------------------------------------------------
// MARK: Command/Property Jump Tables
@@ -90,13 +70,15 @@ const NcpBase::CommandHandlerEntry NcpBase::mCommandHandlerTable[] =
NCP_CMD_HANDLER_ENTRY(PROP_VALUE_SET),
NCP_CMD_HANDLER_ENTRY(PROP_VALUE_INSERT),
NCP_CMD_HANDLER_ENTRY(PROP_VALUE_REMOVE),
- NCP_CMD_HANDLER_ENTRY(NET_SAVE),
- NCP_CMD_HANDLER_ENTRY(NET_CLEAR),
- NCP_CMD_HANDLER_ENTRY(NET_RECALL),
#if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
NCP_CMD_HANDLER_ENTRY(PEEK),
NCP_CMD_HANDLER_ENTRY(POKE),
#endif
+#if OPENTHREAD_MTD || OPENTHREAD_FTD
+ NCP_CMD_HANDLER_ENTRY(NET_SAVE),
+ NCP_CMD_HANDLER_ENTRY(NET_CLEAR),
+ NCP_CMD_HANDLER_ENTRY(NET_RECALL),
+#endif
};
#define NCP_GET_PROP_HANDLER_ENTRY(name) { SPINEL_PROP_##name, &NcpBase::GetPropertyHandler_##name }
@@ -104,101 +86,89 @@ const NcpBase::CommandHandlerEntry NcpBase::mCommandHandlerTable[] =
const NcpBase::GetPropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] =
{
- NCP_GET_PROP_HANDLER_ENTRY(LAST_STATUS),
- NCP_GET_PROP_HANDLER_ENTRY(PROTOCOL_VERSION),
- NCP_GET_PROP_HANDLER_ENTRY(INTERFACE_TYPE),
- NCP_GET_PROP_HANDLER_ENTRY(VENDOR_ID),
NCP_GET_PROP_HANDLER_ENTRY(CAPS),
- NCP_GET_PROP_HANDLER_ENTRY(NCP_VERSION),
- NCP_GET_PROP_HANDLER_ENTRY(INTERFACE_COUNT),
- NCP_GET_PROP_HANDLER_ENTRY(POWER_STATE),
+ NCP_GET_PROP_HANDLER_ENTRY(DEBUG_TEST_ASSERT),
+ NCP_GET_PROP_HANDLER_ENTRY(DEBUG_NCP_LOG_LEVEL),
NCP_GET_PROP_HANDLER_ENTRY(HWADDR),
- NCP_GET_PROP_HANDLER_ENTRY(LOCK),
NCP_GET_PROP_HANDLER_ENTRY(HOST_POWER_STATE),
- NCP_GET_PROP_HANDLER_ENTRY(UNSOL_UPDATE_FILTER),
- NCP_GET_PROP_HANDLER_ENTRY(UNSOL_UPDATE_LIST),
+ NCP_GET_PROP_HANDLER_ENTRY(INTERFACE_COUNT),
+ NCP_GET_PROP_HANDLER_ENTRY(INTERFACE_TYPE),
+ NCP_GET_PROP_HANDLER_ENTRY(LAST_STATUS),
+ NCP_GET_PROP_HANDLER_ENTRY(LOCK),
NCP_GET_PROP_HANDLER_ENTRY(PHY_ENABLED),
- NCP_GET_PROP_HANDLER_ENTRY(PHY_FREQ),
- NCP_GET_PROP_HANDLER_ENTRY(PHY_CHAN_SUPPORTED),
NCP_GET_PROP_HANDLER_ENTRY(PHY_CHAN),
- NCP_GET_PROP_HANDLER_ENTRY(PHY_RSSI),
- NCP_GET_PROP_HANDLER_ENTRY(PHY_TX_POWER),
NCP_GET_PROP_HANDLER_ENTRY(PHY_RX_SENSITIVITY),
- NCP_GET_PROP_HANDLER_ENTRY(MAC_SCAN_STATE),
- NCP_GET_PROP_HANDLER_ENTRY(MAC_SCAN_MASK),
- NCP_GET_PROP_HANDLER_ENTRY(MAC_SCAN_PERIOD),
+ NCP_GET_PROP_HANDLER_ENTRY(PHY_TX_POWER),
+ NCP_GET_PROP_HANDLER_ENTRY(POWER_STATE),
+ NCP_GET_PROP_HANDLER_ENTRY(PROTOCOL_VERSION),
NCP_GET_PROP_HANDLER_ENTRY(MAC_15_4_PANID),
NCP_GET_PROP_HANDLER_ENTRY(MAC_15_4_LADDR),
NCP_GET_PROP_HANDLER_ENTRY(MAC_15_4_SADDR),
NCP_GET_PROP_HANDLER_ENTRY(MAC_RAW_STREAM_ENABLED),
NCP_GET_PROP_HANDLER_ENTRY(MAC_PROMISCUOUS_MODE),
- NCP_GET_PROP_HANDLER_ENTRY(MAC_EXTENDED_ADDR),
+ NCP_GET_PROP_HANDLER_ENTRY(NCP_VERSION),
+ NCP_GET_PROP_HANDLER_ENTRY(UNSOL_UPDATE_FILTER),
+ NCP_GET_PROP_HANDLER_ENTRY(UNSOL_UPDATE_LIST),
+ NCP_GET_PROP_HANDLER_ENTRY(VENDOR_ID),
+
+#if OPENTHREAD_MTD || OPENTHREAD_FTD
NCP_GET_PROP_HANDLER_ENTRY(MAC_DATA_POLL_PERIOD),
- NCP_GET_PROP_HANDLER_ENTRY(NET_SAVED),
+ NCP_GET_PROP_HANDLER_ENTRY(MAC_EXTENDED_ADDR),
+ NCP_GET_PROP_HANDLER_ENTRY(MAC_SCAN_STATE),
+ NCP_GET_PROP_HANDLER_ENTRY(MAC_SCAN_MASK),
+ NCP_GET_PROP_HANDLER_ENTRY(MAC_SCAN_PERIOD),
+#if OPENTHREAD_ENABLE_MAC_FILTER
+ NCP_GET_PROP_HANDLER_ENTRY(MAC_BLACKLIST),
+ NCP_GET_PROP_HANDLER_ENTRY(MAC_BLACKLIST_ENABLED),
+ NCP_GET_PROP_HANDLER_ENTRY(MAC_FIXED_RSS),
+ NCP_GET_PROP_HANDLER_ENTRY(MAC_WHITELIST),
+ NCP_GET_PROP_HANDLER_ENTRY(MAC_WHITELIST_ENABLED),
+#endif
+ NCP_GET_PROP_HANDLER_ENTRY(MSG_BUFFER_COUNTERS),
+ NCP_GET_PROP_HANDLER_ENTRY(PHY_CHAN_SUPPORTED),
+ NCP_GET_PROP_HANDLER_ENTRY(PHY_FREQ),
+ NCP_GET_PROP_HANDLER_ENTRY(PHY_RSSI),
NCP_GET_PROP_HANDLER_ENTRY(NET_IF_UP),
- NCP_GET_PROP_HANDLER_ENTRY(NET_STACK_UP),
- NCP_GET_PROP_HANDLER_ENTRY(NET_ROLE),
- NCP_GET_PROP_HANDLER_ENTRY(NET_NETWORK_NAME),
- NCP_GET_PROP_HANDLER_ENTRY(NET_XPANID),
- NCP_GET_PROP_HANDLER_ENTRY(NET_MASTER_KEY),
NCP_GET_PROP_HANDLER_ENTRY(NET_KEY_SEQUENCE_COUNTER),
- NCP_GET_PROP_HANDLER_ENTRY(NET_PARTITION_ID),
NCP_GET_PROP_HANDLER_ENTRY(NET_KEY_SWITCH_GUARDTIME),
+ NCP_GET_PROP_HANDLER_ENTRY(NET_MASTER_KEY),
+ NCP_GET_PROP_HANDLER_ENTRY(NET_NETWORK_NAME),
+ NCP_GET_PROP_HANDLER_ENTRY(NET_PARTITION_ID),
+ NCP_GET_PROP_HANDLER_ENTRY(NET_REQUIRE_JOIN_EXISTING),
+ NCP_GET_PROP_HANDLER_ENTRY(NET_ROLE),
+ NCP_GET_PROP_HANDLER_ENTRY(NET_SAVED),
+ NCP_GET_PROP_HANDLER_ENTRY(NET_STACK_UP),
+ NCP_GET_PROP_HANDLER_ENTRY(NET_XPANID),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_ALLOW_LOCAL_NET_DATA_CHANGE),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_ASSISTING_PORTS),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_CHILD_TIMEOUT),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_DISCOVERY_SCAN_JOINER_FLAG),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_DISCOVERY_SCAN_ENABLE_FILTERING),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_DISCOVERY_SCAN_PANID),
NCP_GET_PROP_HANDLER_ENTRY(THREAD_LEADER_ADDR),
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_PARENT),
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_NEIGHBOR_TABLE),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_LEADER_NETWORK_DATA),
NCP_GET_PROP_HANDLER_ENTRY(THREAD_LEADER_RID),
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_LEADER_WEIGHT),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_MODE),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_NEIGHBOR_TABLE),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_NETWORK_DATA_VERSION),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_OFF_MESH_ROUTES),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_ON_MESH_NETS),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_PARENT),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_RLOC16),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_RLOC16_DEBUG_PASSTHRU),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_STABLE_LEADER_NETWORK_DATA),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_STABLE_NETWORK_DATA_VERSION),
#if OPENTHREAD_ENABLE_BORDER_ROUTER
NCP_GET_PROP_HANDLER_ENTRY(THREAD_NETWORK_DATA),
NCP_GET_PROP_HANDLER_ENTRY(THREAD_STABLE_NETWORK_DATA),
#endif
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_NETWORK_DATA_VERSION),
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_STABLE_NETWORK_DATA_VERSION),
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_LEADER_NETWORK_DATA),
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_STABLE_LEADER_NETWORK_DATA),
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_OFF_MESH_ROUTES),
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_ASSISTING_PORTS),
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_ALLOW_LOCAL_NET_DATA_CHANGE),
-#if OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_COMMISSIONER_ENABLED),
-#endif
-#if OPENTHREAD_ENABLE_MAC_FILTER
- NCP_GET_PROP_HANDLER_ENTRY(MAC_WHITELIST),
- NCP_GET_PROP_HANDLER_ENTRY(MAC_WHITELIST_ENABLED),
- NCP_GET_PROP_HANDLER_ENTRY(MAC_BLACKLIST),
- NCP_GET_PROP_HANDLER_ENTRY(MAC_BLACKLIST_ENABLED),
- NCP_GET_PROP_HANDLER_ENTRY(MAC_FIXED_RSS),
-#endif
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_MODE),
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_CHILD_TIMEOUT),
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_RLOC16),
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_ON_MESH_NETS),
- NCP_GET_PROP_HANDLER_ENTRY(NET_REQUIRE_JOIN_EXISTING),
+ NCP_GET_PROP_HANDLER_ENTRY(IPV6_ADDRESS_TABLE),
+ NCP_GET_PROP_HANDLER_ENTRY(IPV6_ICMP_PING_OFFLOAD),
+ NCP_GET_PROP_HANDLER_ENTRY(IPV6_LL_ADDR),
NCP_GET_PROP_HANDLER_ENTRY(IPV6_ML_PREFIX),
NCP_GET_PROP_HANDLER_ENTRY(IPV6_ML_ADDR),
- NCP_GET_PROP_HANDLER_ENTRY(IPV6_LL_ADDR),
- NCP_GET_PROP_HANDLER_ENTRY(IPV6_ADDRESS_TABLE),
- NCP_GET_PROP_HANDLER_ENTRY(IPV6_ROUTE_TABLE),
- NCP_GET_PROP_HANDLER_ENTRY(IPV6_ICMP_PING_OFFLOAD),
NCP_GET_PROP_HANDLER_ENTRY(IPV6_MULTICAST_ADDRESS_TABLE),
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_RLOC16_DEBUG_PASSTHRU),
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_DISCOVERY_SCAN_JOINER_FLAG),
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_DISCOVERY_SCAN_ENABLE_FILTERING),
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_DISCOVERY_SCAN_PANID),
- NCP_GET_PROP_HANDLER_ENTRY(STREAM_NET),
-#if OPENTHREAD_FTD
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_CHILD_TABLE),
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_LOCAL_LEADER_WEIGHT),
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_ROUTER_ROLE_ENABLED),
- NCP_GET_PROP_HANDLER_ENTRY(NET_PSKC),
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_CHILD_COUNT_MAX),
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_ROUTER_UPGRADE_THRESHOLD),
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_ROUTER_DOWNGRADE_THRESHOLD),
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_CONTEXT_REUSE_DELAY),
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_NETWORK_ID_TIMEOUT),
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_ROUTER_SELECTION_JITTER),
-#endif
+ NCP_GET_PROP_HANDLER_ENTRY(IPV6_ROUTE_TABLE),
#if OPENTHREAD_ENABLE_JAM_DETECTION
NCP_GET_PROP_HANDLER_ENTRY(JAM_DETECT_ENABLE),
NCP_GET_PROP_HANDLER_ENTRY(JAM_DETECTED),
@@ -207,9 +177,11 @@ const NcpBase::GetPropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] =
NCP_GET_PROP_HANDLER_ENTRY(JAM_DETECT_BUSY),
NCP_GET_PROP_HANDLER_ENTRY(JAM_DETECT_HISTORY_BITMAP),
#endif
-#if OPENTHREAD_ENABLE_TMF_PROXY && OPENTHREAD_FTD
- NCP_GET_PROP_HANDLER_ENTRY(THREAD_TMF_PROXY_ENABLED),
+#if OPENTHREAD_ENABLE_LEGACY
+ NCP_GET_PROP_HANDLER_ENTRY(NEST_LEGACY_ULA_PREFIX),
+ NCP_GET_PROP_HANDLER_ENTRY(NEST_LEGACY_LAST_NODE_JOINED),
#endif
+ NCP_GET_PROP_HANDLER_ENTRY(STREAM_NET),
// MAC counters
NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_TX_PKT_TOTAL, MAC_CNTR),
NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_TX_PKT_ACK_REQ, MAC_CNTR),
@@ -257,14 +229,27 @@ const NcpBase::GetPropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] =
NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_IP_RX_SUCCESS, IP_CNTR),
NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_IP_TX_FAILURE, IP_CNTR),
NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_IP_RX_FAILURE, IP_CNTR),
+#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
- NCP_GET_PROP_HANDLER_ENTRY(MSG_BUFFER_COUNTERS),
- NCP_GET_PROP_HANDLER_ENTRY(DEBUG_TEST_ASSERT),
- NCP_GET_PROP_HANDLER_ENTRY(DEBUG_NCP_LOG_LEVEL),
-#if OPENTHREAD_ENABLE_LEGACY
- NCP_GET_PROP_HANDLER_ENTRY(NEST_LEGACY_ULA_PREFIX),
- NCP_GET_PROP_HANDLER_ENTRY(NEST_LEGACY_LAST_NODE_JOINED),
+#if OPENTHREAD_FTD
+ NCP_GET_PROP_HANDLER_ENTRY(NET_PSKC),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_LEADER_WEIGHT),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_CHILD_TABLE),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_LOCAL_LEADER_WEIGHT),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_ROUTER_ROLE_ENABLED),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_CHILD_COUNT_MAX),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_ROUTER_UPGRADE_THRESHOLD),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_ROUTER_DOWNGRADE_THRESHOLD),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_CONTEXT_REUSE_DELAY),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_NETWORK_ID_TIMEOUT),
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_ROUTER_SELECTION_JITTER),
+#if OPENTHREAD_ENABLE_COMMISSIONER
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_COMMISSIONER_ENABLED),
#endif
+#if OPENTHREAD_ENABLE_TMF_PROXY
+ NCP_GET_PROP_HANDLER_ENTRY(THREAD_TMF_PROXY_ENABLED),
+#endif
+#endif // OPENTHREAD_FTD
};
#define NCP_SET_PROP_HANDLER_ENTRY(name) { SPINEL_PROP_##name, &NcpBase::SetPropertyHandler_##name }
@@ -274,21 +259,25 @@ const NcpBase::SetPropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] =
NCP_SET_PROP_HANDLER_ENTRY(POWER_STATE),
NCP_SET_PROP_HANDLER_ENTRY(HOST_POWER_STATE),
NCP_SET_PROP_HANDLER_ENTRY(UNSOL_UPDATE_FILTER),
-#if OPENTHREAD_ENABLE_RAW_LINK_API
- NCP_SET_PROP_HANDLER_ENTRY(PHY_ENABLED),
- NCP_SET_PROP_HANDLER_ENTRY(MAC_15_4_SADDR),
- NCP_SET_PROP_HANDLER_ENTRY(STREAM_RAW),
-#endif // OPENTHREAD_ENABLE_RAW_LINK_API
NCP_SET_PROP_HANDLER_ENTRY(PHY_TX_POWER),
NCP_SET_PROP_HANDLER_ENTRY(PHY_CHAN),
NCP_SET_PROP_HANDLER_ENTRY(MAC_PROMISCUOUS_MODE),
+ NCP_SET_PROP_HANDLER_ENTRY(MAC_15_4_PANID),
+ NCP_SET_PROP_HANDLER_ENTRY(MAC_15_4_LADDR),
+ NCP_SET_PROP_HANDLER_ENTRY(MAC_RAW_STREAM_ENABLED),
+#if OPENTHREAD_ENABLE_RAW_LINK_API
+ NCP_SET_PROP_HANDLER_ENTRY(MAC_15_4_SADDR),
+ NCP_SET_PROP_HANDLER_ENTRY(MAC_SRC_MATCH_ENABLED),
+ NCP_SET_PROP_HANDLER_ENTRY(MAC_SRC_MATCH_SHORT_ADDRESSES),
+ NCP_SET_PROP_HANDLER_ENTRY(MAC_SRC_MATCH_EXTENDED_ADDRESSES),
+ NCP_SET_PROP_HANDLER_ENTRY(PHY_ENABLED),
+ NCP_SET_PROP_HANDLER_ENTRY(STREAM_RAW),
+#endif // OPENTHREAD_ENABLE_RAW_LINK_API
+#if OPENTHREAD_MTD || OPENTHREAD_FTD
+ NCP_SET_PROP_HANDLER_ENTRY(MAC_DATA_POLL_PERIOD),
NCP_SET_PROP_HANDLER_ENTRY(MAC_SCAN_MASK),
NCP_SET_PROP_HANDLER_ENTRY(MAC_SCAN_STATE),
NCP_SET_PROP_HANDLER_ENTRY(MAC_SCAN_PERIOD),
- NCP_SET_PROP_HANDLER_ENTRY(MAC_15_4_PANID),
- NCP_SET_PROP_HANDLER_ENTRY(MAC_15_4_LADDR),
- NCP_SET_PROP_HANDLER_ENTRY(MAC_DATA_POLL_PERIOD),
- NCP_SET_PROP_HANDLER_ENTRY(MAC_RAW_STREAM_ENABLED),
NCP_SET_PROP_HANDLER_ENTRY(NET_IF_UP),
NCP_SET_PROP_HANDLER_ENTRY(NET_STACK_UP),
NCP_SET_PROP_HANDLER_ENTRY(NET_ROLE),
@@ -309,11 +298,6 @@ const NcpBase::SetPropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] =
NCP_SET_PROP_HANDLER_ENTRY(MAC_BLACKLIST),
NCP_SET_PROP_HANDLER_ENTRY(MAC_BLACKLIST_ENABLED),
NCP_SET_PROP_HANDLER_ENTRY(MAC_FIXED_RSS),
-#endif
-#if OPENTHREAD_ENABLE_RAW_LINK_API
- NCP_SET_PROP_HANDLER_ENTRY(MAC_SRC_MATCH_ENABLED),
- NCP_SET_PROP_HANDLER_ENTRY(MAC_SRC_MATCH_SHORT_ADDRESSES),
- NCP_SET_PROP_HANDLER_ENTRY(MAC_SRC_MATCH_EXTENDED_ADDRESSES),
#endif
NCP_SET_PROP_HANDLER_ENTRY(THREAD_MODE),
NCP_SET_PROP_HANDLER_ENTRY(NET_REQUIRE_JOIN_EXISTING),
@@ -324,6 +308,20 @@ const NcpBase::SetPropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] =
#if OPENTHREAD_ENABLE_BORDER_ROUTER
NCP_SET_PROP_HANDLER_ENTRY(THREAD_ALLOW_LOCAL_NET_DATA_CHANGE),
#endif
+#if OPENTHREAD_ENABLE_JAM_DETECTION
+ NCP_SET_PROP_HANDLER_ENTRY(JAM_DETECT_ENABLE),
+ NCP_SET_PROP_HANDLER_ENTRY(JAM_DETECT_RSSI_THRESHOLD),
+ NCP_SET_PROP_HANDLER_ENTRY(JAM_DETECT_WINDOW),
+ NCP_SET_PROP_HANDLER_ENTRY(JAM_DETECT_BUSY),
+#endif
+#if OPENTHREAD_ENABLE_DIAG
+ NCP_SET_PROP_HANDLER_ENTRY(NEST_STREAM_MFG),
+#endif
+#if OPENTHREAD_ENABLE_LEGACY
+ NCP_SET_PROP_HANDLER_ENTRY(NEST_LEGACY_ULA_PREFIX),
+#endif
+ NCP_SET_PROP_HANDLER_ENTRY(CNTR_RESET),
+#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
#if OPENTHREAD_FTD
NCP_SET_PROP_HANDLER_ENTRY(NET_PSKC),
NCP_SET_PROP_HANDLER_ENTRY(THREAD_CHILD_TIMEOUT),
@@ -339,28 +337,14 @@ const NcpBase::SetPropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] =
#if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB
NCP_SET_PROP_HANDLER_ENTRY(THREAD_STEERING_DATA),
#endif
-#endif // #if OPENTHREAD_FTD
-#if OPENTHREAD_ENABLE_JAM_DETECTION
- NCP_SET_PROP_HANDLER_ENTRY(JAM_DETECT_ENABLE),
- NCP_SET_PROP_HANDLER_ENTRY(JAM_DETECT_RSSI_THRESHOLD),
- NCP_SET_PROP_HANDLER_ENTRY(JAM_DETECT_WINDOW),
- NCP_SET_PROP_HANDLER_ENTRY(JAM_DETECT_BUSY),
+#if OPENTHREAD_ENABLE_COMMISSIONER
+ NCP_SET_PROP_HANDLER_ENTRY(THREAD_COMMISSIONER_ENABLED),
#endif
-#if OPENTHREAD_ENABLE_TMF_PROXY && OPENTHREAD_FTD
+#if OPENTHREAD_ENABLE_TMF_PROXY
NCP_SET_PROP_HANDLER_ENTRY(THREAD_TMF_PROXY_ENABLED),
NCP_SET_PROP_HANDLER_ENTRY(THREAD_TMF_PROXY_STREAM),
#endif
-#if OPENTHREAD_ENABLE_DIAG
- NCP_SET_PROP_HANDLER_ENTRY(NEST_STREAM_MFG),
-#endif
-#if OPENTHREAD_ENABLE_LEGACY
- NCP_SET_PROP_HANDLER_ENTRY(NEST_LEGACY_ULA_PREFIX),
-#endif
-
-#if OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
- NCP_SET_PROP_HANDLER_ENTRY(THREAD_COMMISSIONER_ENABLED),
-#endif
- NCP_SET_PROP_HANDLER_ENTRY(CNTR_RESET),
+#endif // #if OPENTHREAD_FTD
};
#define NCP_INSERT_PROP_HANDLER_ENTRY(name) { SPINEL_PROP_##name, &NcpBase::InsertPropertyHandler_##name }
@@ -372,6 +356,7 @@ const NcpBase::InsertPropertyHandlerEntry NcpBase::mInsertPropertyHandlerTable[]
NCP_INSERT_PROP_HANDLER_ENTRY(MAC_SRC_MATCH_SHORT_ADDRESSES),
NCP_INSERT_PROP_HANDLER_ENTRY(MAC_SRC_MATCH_EXTENDED_ADDRESSES),
#endif
+#if OPENTHREAD_MTD || OPENTHREAD_FTD
NCP_INSERT_PROP_HANDLER_ENTRY(IPV6_ADDRESS_TABLE),
NCP_INSERT_PROP_HANDLER_ENTRY(IPV6_MULTICAST_ADDRESS_TABLE),
NCP_INSERT_PROP_HANDLER_ENTRY(THREAD_ASSISTING_PORTS),
@@ -379,14 +364,17 @@ const NcpBase::InsertPropertyHandlerEntry NcpBase::mInsertPropertyHandlerTable[]
NCP_INSERT_PROP_HANDLER_ENTRY(THREAD_OFF_MESH_ROUTES),
NCP_INSERT_PROP_HANDLER_ENTRY(THREAD_ON_MESH_NETS),
#endif
-#if OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
- NCP_INSERT_PROP_HANDLER_ENTRY(THREAD_JOINERS),
-#endif
#if OPENTHREAD_ENABLE_MAC_FILTER
NCP_INSERT_PROP_HANDLER_ENTRY(MAC_WHITELIST),
NCP_INSERT_PROP_HANDLER_ENTRY(MAC_BLACKLIST),
NCP_INSERT_PROP_HANDLER_ENTRY(MAC_FIXED_RSS),
#endif
+#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
+#if OPENTHREAD_FTD
+#if OPENTHREAD_ENABLE_COMMISSIONER
+ NCP_INSERT_PROP_HANDLER_ENTRY(THREAD_JOINERS),
+#endif
+#endif // OPENTHREAD_FTD
};
#define NCP_REMOVE_PROP_HANDLER_ENTRY(name) { SPINEL_PROP_##name, &NcpBase::RemovePropertyHandler_##name }
@@ -398,6 +386,7 @@ const NcpBase::RemovePropertyHandlerEntry NcpBase::mRemovePropertyHandlerTable[]
NCP_REMOVE_PROP_HANDLER_ENTRY(MAC_SRC_MATCH_SHORT_ADDRESSES),
NCP_REMOVE_PROP_HANDLER_ENTRY(MAC_SRC_MATCH_EXTENDED_ADDRESSES),
#endif
+#if OPENTHREAD_MTD || OPENTHREAD_FTD
NCP_REMOVE_PROP_HANDLER_ENTRY(IPV6_ADDRESS_TABLE),
NCP_REMOVE_PROP_HANDLER_ENTRY(IPV6_MULTICAST_ADDRESS_TABLE),
#if OPENTHREAD_ENABLE_BORDER_ROUTER
@@ -410,6 +399,7 @@ const NcpBase::RemovePropertyHandlerEntry NcpBase::mRemovePropertyHandlerTable[]
NCP_REMOVE_PROP_HANDLER_ENTRY(MAC_BLACKLIST),
NCP_REMOVE_PROP_HANDLER_ENTRY(MAC_FIXED_RSS),
#endif
+#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
#if OPENTHREAD_FTD
NCP_REMOVE_PROP_HANDLER_ENTRY(THREAD_ACTIVE_ROUTER_IDS),
#endif
@@ -419,7 +409,7 @@ const NcpBase::RemovePropertyHandlerEntry NcpBase::mRemovePropertyHandlerTable[]
// MARK: Utility Functions
// ----------------------------------------------------------------------------
-static spinel_status_t ThreadErrorToSpinelStatus(otError aError)
+spinel_status_t NcpBase::ThreadErrorToSpinelStatus(otError aError)
{
spinel_status_t ret;
@@ -536,124 +526,6 @@ static spinel_status_t ResetReasonToSpinelStatus(otPlatResetReason aReason)
return ret;
}
-static uint8_t BorderRouterConfigToFlagByte(const otBorderRouterConfig &aConfig)
-{
- uint8_t flags(0);
-
- if (aConfig.mPreferred)
- {
- flags |= SPINEL_NET_FLAG_PREFERRED;
- }
-
- if (aConfig.mSlaac)
- {
- flags |= SPINEL_NET_FLAG_SLAAC;
- }
-
- if (aConfig.mDhcp)
- {
- flags |= SPINEL_NET_FLAG_DHCP;
- }
-
- if (aConfig.mDefaultRoute)
- {
- flags |= SPINEL_NET_FLAG_DEFAULT_ROUTE;
- }
-
- if (aConfig.mConfigure)
- {
- flags |= SPINEL_NET_FLAG_CONFIGURE;
- }
-
- if (aConfig.mOnMesh)
- {
- flags |= SPINEL_NET_FLAG_ON_MESH;
- }
-
- flags |= (aConfig.mPreference << SPINEL_NET_FLAG_PREFERENCE_OFFSET);
-
- return flags;
-}
-
-static uint8_t LinkFlagsToFlagByte(bool aRxOnWhenIdle, bool aSecureDataRequests, bool aDeviceType, bool aNetworkData)
-{
- uint8_t flags(0);
-
- if (aRxOnWhenIdle)
- {
- flags |= SPINEL_THREAD_MODE_RX_ON_WHEN_IDLE;
- }
-
- if (aSecureDataRequests)
- {
- flags |= SPINEL_THREAD_MODE_SECURE_DATA_REQUEST;
- }
-
- if (aDeviceType)
- {
- flags |= SPINEL_THREAD_MODE_FULL_FUNCTION_DEV;
- }
-
- if (aNetworkData)
- {
- flags |= SPINEL_THREAD_MODE_FULL_NETWORK_DATA;
- }
-
- return flags;
-}
-
-static uint8_t ExternalRoutePreferenceToFlagByte(int aPreference)
-{
- uint8_t flags;
-
- switch (aPreference)
- {
- case OT_ROUTE_PREFERENCE_LOW:
- flags = SPINEL_ROUTE_PREFERENCE_LOW;
- break;
-
- case OT_ROUTE_PREFERENCE_MED:
- flags = SPINEL_ROUTE_PREFERENCE_MEDIUM;
- break;
-
- case OT_ROUTE_PREFERENCE_HIGH:
- flags = SPINEL_ROUTE_PREFERENCE_HIGH;
- break;
-
- default:
- flags = SPINEL_ROUTE_PREFERENCE_MEDIUM;
- break;
- }
-
- return flags;
-}
-
-#if OPENTHREAD_ENABLE_BORDER_ROUTER
-
-static int FlagByteToExternalRoutePreference(uint8_t aFlags)
-{
- int route_preference = 0;
-
- switch (aFlags & SPINEL_NET_FLAG_PREFERENCE_MASK)
- {
- case SPINEL_ROUTE_PREFERENCE_HIGH:
- route_preference = OT_ROUTE_PREFERENCE_HIGH;
- break;
-
- case SPINEL_ROUTE_PREFERENCE_MEDIUM:
- route_preference = OT_ROUTE_PREFERENCE_MED;
- break;
-
- case SPINEL_ROUTE_PREFERENCE_LOW:
- route_preference = OT_ROUTE_PREFERENCE_LOW;
- break;
- }
-
- return route_preference;
-}
-
-#endif // OPENTHREAD_ENABLE_BORDER_ROUTER
-
// ----------------------------------------------------------------------------
// MARK: Class Boilerplate
// ----------------------------------------------------------------------------
@@ -691,19 +563,20 @@ NcpBase::NcpBase(otInstance *aInstance):
#if OPENTHREAD_ENABLE_RAW_LINK_API
mCurTransmitTID(0),
mCurReceiveChannel(OPENTHREAD_CONFIG_DEFAULT_CHANNEL),
- mCurScanChannel(NCP_INVALID_SCAN_CHANNEL),
+ mCurScanChannel(kInvalidScanChannel),
#endif // OPENTHREAD_ENABLE_RAW_LINK_API
-
- mFramingErrorCounter(0),
- mRxSpinelFrameCounter(0),
- mRxSpinelOutOfOrderTidCounter(0),
- mTxSpinelFrameCounter(0),
+#if OPENTHREAD_MTD || OPENTHREAD_FTD
mInboundSecureIpFrameCounter(0),
mInboundInsecureIpFrameCounter(0),
mOutboundSecureIpFrameCounter(0),
mOutboundInsecureIpFrameCounter(0),
mDroppedOutboundIpFrameCounter(0),
- mDroppedInboundIpFrameCounter(0)
+ mDroppedInboundIpFrameCounter(0),
+#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
+ mFramingErrorCounter(0),
+ mRxSpinelFrameCounter(0),
+ mRxSpinelOutOfOrderTidCounter(0),
+ mTxSpinelFrameCounter(0)
{
assert(mInstance != NULL);
@@ -711,21 +584,21 @@ NcpBase::NcpBase(otInstance *aInstance):
mTxFrameBuffer.SetFrameRemovedCallback(&NcpBase::HandleFrameRemovedFromNcpBuffer, this);
+#if OPENTHREAD_MTD || OPENTHREAD_FTD
otSetStateChangedCallback(mInstance, &NcpBase::HandleNetifStateChanged, this);
otIp6SetReceiveCallback(mInstance, &NcpBase::HandleDatagramFromStack, this);
otIp6SetReceiveFilterEnabled(mInstance, true);
otLinkSetPcapCallback(mInstance, &NcpBase::HandleRawFrame, static_cast(this));
otIcmp6SetEchoEnabled(mInstance, false);
-
- mChangedPropsSet.AddLastStatus(SPINEL_STATUS_RESET_UNKNOWN);
- mUpdateChangedPropsTask.Post();
-
#if OPENTHREAD_ENABLE_LEGACY
mLegacyNodeDidJoin = false;
mLegacyHandlers = NULL;
memset(mLegacyUlaPrefix, 0, sizeof(mLegacyUlaPrefix));
memset(&mLegacyLastJoinedNode, 0, sizeof(mLegacyLastJoinedNode));
#endif
+#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
+ mChangedPropsSet.AddLastStatus(SPINEL_STATUS_RESET_UNKNOWN);
+ mUpdateChangedPropsTask.Post();
}
NcpBase *NcpBase::GetNcpInstance(void)
@@ -774,772 +647,6 @@ NcpFrameBuffer::FrameTag NcpBase::GetLastOutboundFrameTag(void)
return mTxFrameBuffer.InFrameGetLastTag();
}
-#if OPENTHREAD_ENABLE_TMF_PROXY && OPENTHREAD_FTD
-void NcpBase::HandleTmfProxyStream(otMessage *aMessage, uint16_t aLocator, uint16_t aPort, void *aContext)
-{
- static_cast(aContext)->HandleTmfProxyStream(aMessage, aLocator, aPort);
-}
-
-void NcpBase::HandleTmfProxyStream(otMessage *aMessage, uint16_t aLocator, uint16_t aPort)
-{
- otError error = OT_ERROR_NONE;
- uint16_t length = otMessageGetLength(aMessage);
- uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0;
-
- SuccessOrExit(error = OutboundFrameBegin(header));
-
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_COMMAND_PROP_S SPINEL_DATATYPE_UINT16_S,
- header,
- SPINEL_CMD_PROP_VALUE_IS,
- SPINEL_PROP_THREAD_TMF_PROXY_STREAM,
- length
- ));
-
- SuccessOrExit(error = OutboundFrameFeedMessage(aMessage));
-
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_UINT16_S SPINEL_DATATYPE_UINT16_S,
- aLocator,
- aPort
- ));
-
- // Set the `aMessage` pointer to NULL to indicate that it does
- // not need to be freed at the exit. The `aMessage` is now owned
- // by the OutboundFrame and will be freed when the frame is either
- // successfully sent and then removed, or if the frame gets
- // discarded.
- aMessage = NULL;
-
- SuccessOrExit(error = OutboundFrameSend());
-
-exit:
-
- if (aMessage != NULL)
- {
- otMessageFree(aMessage);
- }
-
- if (error != OT_ERROR_NONE)
- {
- mChangedPropsSet.AddLastStatus(SPINEL_STATUS_DROPPED);
- mUpdateChangedPropsTask.Post();
- }
-}
-#endif // OPENTHREAD_ENABLE_TMF_PROXY && OPENTHREAD_FTD
-
-// ----------------------------------------------------------------------------
-// MARK: Outbound Datagram Handling
-// ----------------------------------------------------------------------------
-
-void NcpBase::HandleDatagramFromStack(otMessage *aMessage, void *aContext)
-{
- static_cast(aContext)->HandleDatagramFromStack(aMessage);
-}
-
-void NcpBase::HandleDatagramFromStack(otMessage *aMessage)
-{
- otError error = OT_ERROR_NONE;
- uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0;
- bool isSecure = otMessageIsLinkSecurityEnabled(aMessage);
- uint16_t length = otMessageGetLength(aMessage);
-
- SuccessOrExit(error = OutboundFrameBegin(header));
-
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_COMMAND_PROP_S SPINEL_DATATYPE_UINT16_S,
- header,
- SPINEL_CMD_PROP_VALUE_IS,
- isSecure ? SPINEL_PROP_STREAM_NET : SPINEL_PROP_STREAM_NET_INSECURE,
- length
- ));
-
- SuccessOrExit(error = OutboundFrameFeedMessage(aMessage));
-
- // Set the `aMessage` pointer to NULL to indicate that it does
- // not need to be freed at the exit. The `aMessage` is now owned
- // by the OutboundFrame and will be freed when the frame is either
- // successfully sent and then removed, or if the frame gets
- // discarded.
- aMessage = NULL;
-
- // Append any metadata (rssi, lqi, channel, etc) here!
-
- SuccessOrExit(error = OutboundFrameSend());
-
-exit:
-
- if (aMessage != NULL)
- {
- otMessageFree(aMessage);
- }
-
- if (error != OT_ERROR_NONE)
- {
- mChangedPropsSet.AddLastStatus(SPINEL_STATUS_DROPPED);
- mUpdateChangedPropsTask.Post();
- mDroppedOutboundIpFrameCounter++;
- }
- else
- {
- if (isSecure)
- {
- mOutboundSecureIpFrameCounter++;
- }
- else
- {
- mOutboundInsecureIpFrameCounter++;
- }
- }
-}
-
-// ----------------------------------------------------------------------------
-// MARK: Raw frame handling
-// ----------------------------------------------------------------------------
-
-void NcpBase::HandleRawFrame(const otRadioFrame *aFrame, void *aContext)
-{
- static_cast(aContext)->HandleRawFrame(aFrame);
-}
-
-void NcpBase::HandleRawFrame(const otRadioFrame *aFrame)
-{
- uint16_t flags = 0;
- uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0;
-
- if (!mIsRawStreamEnabled)
- {
- goto exit;
- }
-
- SuccessOrExit(OutboundFrameBegin(header));
-
- if (aFrame->mDidTX)
- {
- flags |= SPINEL_MD_FLAG_TX;
- }
-
- // Append frame header and frame length
- SuccessOrExit(
- OutboundFrameFeedPacked(
- SPINEL_DATATYPE_COMMAND_PROP_S SPINEL_DATATYPE_UINT16_S,
- header,
- SPINEL_CMD_PROP_VALUE_IS,
- SPINEL_PROP_STREAM_RAW,
- aFrame->mLength
- ));
-
- // Append the frame contents
- SuccessOrExit(OutboundFrameFeedData(aFrame->mPsdu, aFrame->mLength));
-
- // Append metadata (rssi, etc)
- SuccessOrExit(
- OutboundFrameFeedPacked(
- SPINEL_DATATYPE_INT8_S
- SPINEL_DATATYPE_INT8_S
- SPINEL_DATATYPE_UINT16_S
- SPINEL_DATATYPE_STRUCT_S( // PHY-data
- SPINEL_DATATYPE_NULL_S // Empty for now
- )
- SPINEL_DATATYPE_STRUCT_S( // Vendor-data
- SPINEL_DATATYPE_NULL_S // Empty for now
- ),
- aFrame->mPower, // TX Power
- -128, // Noise Floor (Currently unused)
- flags // Flags
-
- // Skip PHY and Vendor data for now
- ));
-
- SuccessOrExit(OutboundFrameSend());
-
-exit:
- return;
-}
-
-
-// ----------------------------------------------------------------------------
-// MARK: Scan Results Glue
-// ----------------------------------------------------------------------------
-
-void NcpBase::HandleActiveScanResult_Jump(otActiveScanResult *aResult, void *aContext)
-{
- static_cast(aContext)->HandleActiveScanResult(aResult);
-}
-
-void NcpBase::HandleActiveScanResult(otActiveScanResult *aResult)
-{
- otError error;
-
- if (aResult)
- {
- uint8_t flags = static_cast(aResult->mVersion << SPINEL_BEACON_THREAD_FLAG_VERSION_SHIFT);
-
- if (aResult->mIsJoinable)
- {
- flags |= SPINEL_BEACON_THREAD_FLAG_JOINABLE;
- }
-
- if (aResult->mIsNative)
- {
- flags |= SPINEL_BEACON_THREAD_FLAG_NATIVE;
- }
-
- error = SendPropertyUpdate(
- SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
- SPINEL_CMD_PROP_VALUE_INSERTED,
- SPINEL_PROP_MAC_SCAN_BEACON,
- SPINEL_DATATYPE_MAC_SCAN_RESULT_S(
- SPINEL_802_15_4_DATATYPE_MAC_SCAN_RESULT_V1_S,
- SPINEL_NET_DATATYPE_MAC_SCAN_RESULT_V2_S
- ),
- aResult->mChannel, // Channel
- aResult->mRssi, // RSSI
- // "mac-layer data"
- aResult->mExtAddress.m8, // laddr
- 0xFFFF, // saddr, not given
- aResult->mPanId, // panid
- aResult->mLqi, // lqi
- // "net-layer data"
- SPINEL_PROTOCOL_TYPE_THREAD, // type
- flags, // flags
- aResult->mNetworkName.m8, // network name
- aResult->mExtendedPanId.m8, OT_EXT_PAN_ID_SIZE, // xpanid
- aResult->mSteeringData.m8, aResult->mSteeringData.mLength // steering data
- );
-
- if (error != OT_ERROR_NONE)
- {
- mChangedPropsSet.AddLastStatus(SPINEL_STATUS_NOMEM);
- mUpdateChangedPropsTask.Post();
- }
- }
- else
- {
- // We are finished with the scan, so send out
- // a property update indicating such.
- error = SendPropertyUpdate(
- SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
- SPINEL_CMD_PROP_VALUE_IS,
- SPINEL_PROP_MAC_SCAN_STATE,
- SPINEL_DATATYPE_UINT8_S,
- SPINEL_SCAN_STATE_IDLE
- );
-
- // If we could not send the end of scan indicator message now (no
- // buffer space), we add the MAC_SCAN_STATE property to changed
- // property set so that the update is sent when buffer becomes
- // available.
- if (error != OT_ERROR_NONE)
- {
- mChangedPropsSet.AddProperty(SPINEL_PROP_MAC_SCAN_STATE);
- }
- }
-}
-
-void NcpBase::HandleEnergyScanResult_Jump(otEnergyScanResult *aResult, void *aContext)
-{
- static_cast(aContext)->HandleEnergyScanResult(aResult);
-}
-
-void NcpBase::HandleEnergyScanResult(otEnergyScanResult *aResult)
-{
- otError error;
-
- if (aResult)
- {
- error = SendPropertyUpdate(
- SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
- SPINEL_CMD_PROP_VALUE_INSERTED,
- SPINEL_PROP_MAC_ENERGY_SCAN_RESULT,
- (
- SPINEL_DATATYPE_UINT8_S // Channel
- SPINEL_DATATYPE_INT8_S // Rssi
- ),
- aResult->mChannel,
- aResult->mMaxRssi
- );
-
- if (error != OT_ERROR_NONE)
- {
- mChangedPropsSet.AddLastStatus(SPINEL_STATUS_NOMEM);
- mUpdateChangedPropsTask.Post();
- }
- }
- else
- {
- // We are finished with the scan, so send out
- // a property update indicating such.
- error = SendPropertyUpdate(
- SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
- SPINEL_CMD_PROP_VALUE_IS,
- SPINEL_PROP_MAC_SCAN_STATE,
- SPINEL_DATATYPE_UINT8_S,
- SPINEL_SCAN_STATE_IDLE
- );
-
- // If we could not send the end of scan indicator message now (no
- // buffer space), we add the MAC_SCAN_STATE property to changed
- // property set so that the update is sent when buffer becomes
- // available.
- if (error != OT_ERROR_NONE)
- {
- mChangedPropsSet.AddProperty(SPINEL_PROP_MAC_SCAN_STATE);
- }
- }
-}
-
-// ----------------------------------------------------------------------------
-// MARK: Raw Link-Layer Datapath Glue
-// ----------------------------------------------------------------------------
-
-#if OPENTHREAD_ENABLE_RAW_LINK_API
-
-void NcpBase::LinkRawReceiveDone(otInstance *, otRadioFrame *aFrame, otError aError)
-{
- sNcpInstance->LinkRawReceiveDone(aFrame, aError);
-}
-
-void NcpBase::LinkRawReceiveDone(otRadioFrame *aFrame, otError aError)
-{
- uint16_t flags = 0;
- uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0;
-
- SuccessOrExit(OutboundFrameBegin(header));
-
- if (aFrame->mDidTX)
- {
- flags |= SPINEL_MD_FLAG_TX;
- }
-
- // Append frame header and frame length
- SuccessOrExit(
- OutboundFrameFeedPacked(
- SPINEL_DATATYPE_COMMAND_PROP_S SPINEL_DATATYPE_UINT16_S,
- header,
- SPINEL_CMD_PROP_VALUE_IS,
- SPINEL_PROP_STREAM_RAW,
- (aError == OT_ERROR_NONE) ? aFrame->mLength : 0
- ));
-
- if (aError == OT_ERROR_NONE)
- {
- // Append the frame contents
- SuccessOrExit(OutboundFrameFeedData(aFrame->mPsdu, aFrame->mLength));
- }
-
- // Append metadata (rssi, etc)
- SuccessOrExit(
- OutboundFrameFeedPacked(
- SPINEL_DATATYPE_INT8_S
- SPINEL_DATATYPE_INT8_S
- SPINEL_DATATYPE_UINT16_S
- SPINEL_DATATYPE_STRUCT_S( // PHY-data
- SPINEL_DATATYPE_UINT8_S // 802.15.4 channel
- SPINEL_DATATYPE_UINT8_S // 802.15.4 LQI
- SPINEL_DATATYPE_UINT32_S // The timestamp milliseconds
- SPINEL_DATATYPE_UINT16_S // The timestamp microseconds
- )
- SPINEL_DATATYPE_STRUCT_S( // Vendor-data
- SPINEL_DATATYPE_UINT_PACKED_S
- ),
- aFrame->mPower, // TX Power
- -128, // Noise Floor (Currently unused)
- flags, // Flags
- aFrame->mChannel, // Receive channel
- aFrame->mLqi, // Link quality indicator
- aFrame->mMsec, // The timestamp milliseconds
- aFrame->mUsec, // The timestamp microseconds, offset to mMsec
- aError // Receive error
- ));
-
- SuccessOrExit(OutboundFrameSend());
-
-exit:
- return;
-}
-
-void NcpBase::LinkRawTransmitDone(otInstance *, otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError)
-{
- sNcpInstance->LinkRawTransmitDone(aFrame, aAckFrame, aError);
-}
-
-void NcpBase::LinkRawTransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError)
-{
- if (mCurTransmitTID)
- {
- uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0 | mCurTransmitTID;
- bool framePending = (aAckFrame != NULL && static_cast(aAckFrame)->GetFramePending());
-
- // Clear cached transmit TID
- mCurTransmitTID = 0;
-
- SuccessOrExit(OutboundFrameBegin(header));
-
- SuccessOrExit(OutboundFrameFeedPacked(
- SPINEL_DATATYPE_COMMAND_PROP_S SPINEL_DATATYPE_UINT_PACKED_S SPINEL_DATATYPE_BOOL_S,
- header,
- SPINEL_CMD_PROP_VALUE_IS,
- SPINEL_PROP_LAST_STATUS,
- ThreadErrorToSpinelStatus(aError),
- framePending
- ));
-
- if (aAckFrame && aError == OT_ERROR_NONE)
- {
- SuccessOrExit(OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT16_S, aAckFrame->mLength));
- SuccessOrExit(OutboundFrameFeedData(aAckFrame->mPsdu, aAckFrame->mLength));
- SuccessOrExit(OutboundFrameFeedPacked(
- SPINEL_DATATYPE_INT8_S
- SPINEL_DATATYPE_INT8_S
- SPINEL_DATATYPE_UINT16_S
- SPINEL_DATATYPE_STRUCT_S( // PHY-data
- SPINEL_DATATYPE_UINT8_S // 802.15.4 channel
- SPINEL_DATATYPE_UINT8_S // 802.15.4 LQI
- ),
- aAckFrame->mPower, // RSSI
- -128, // Noise Floor (Currently unused)
- 0, // Flags
- aAckFrame->mChannel, // Receive channel
- aAckFrame->mLqi, // Link quality indicator
- aFrame->mMsec, // The timestamp milliseconds
- aFrame->mUsec // The timestamp microseconds, offset to mMsec
- ));
- }
-
- SuccessOrExit(OutboundFrameSend());
- }
-
-exit:
- OT_UNUSED_VARIABLE(aFrame);
- return;
-}
-
-void NcpBase::LinkRawEnergyScanDone(otInstance *, int8_t aEnergyScanMaxRssi)
-{
- sNcpInstance->LinkRawEnergyScanDone(aEnergyScanMaxRssi);
-}
-
-void NcpBase::LinkRawEnergyScanDone(int8_t aEnergyScanMaxRssi)
-{
- SendPropertyUpdate(
- SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
- SPINEL_CMD_PROP_VALUE_IS,
- SPINEL_PROP_MAC_ENERGY_SCAN_RESULT,
- SPINEL_DATATYPE_UINT8_S
- SPINEL_DATATYPE_INT8_S,
- mCurScanChannel,
- aEnergyScanMaxRssi
- );
-
- // Clear current scan channel
- mCurScanChannel = NCP_INVALID_SCAN_CHANNEL;
-
- // Make sure we are back listening on the original receive channel,
- // since the energy scan could have been on a different channel.
- otLinkRawReceive(mInstance, mCurReceiveChannel, &NcpBase::LinkRawReceiveDone);
-
- // We are finished with the scan, so send out
- // a property update indicating such.
- SendPropertyUpdate(
- SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
- SPINEL_CMD_PROP_VALUE_IS,
- SPINEL_PROP_MAC_SCAN_STATE,
- SPINEL_DATATYPE_UINT8_S,
- SPINEL_SCAN_STATE_IDLE
- );
-}
-
-#endif // OPENTHREAD_ENABLE_RAW_LINK_API
-
-
-// ----------------------------------------------------------------------------
-// MARK: ChangedPropsSet class
-// ----------------------------------------------------------------------------
-
-// Defines the list of properties that can support unsolicited update.
-//
-// Note that {`SPINEL_PROP_LAST_STATUS`, `SPINEL_STATUS_RESET_UNKNOWN`} should be first entry to ensure that RESET is
-// reported before any other property update.
-//
-// Since a `uint32_t` is used as bit-mask to track which entries are in the changed set, we should ensure that the
-// number of entries in the list is always less than or equal to 32.
-//
-const NcpBase::ChangedPropsSet::Entry NcpBase::ChangedPropsSet::mSupportedProps[] =
-{
- // Spinel property Status (if prop is `LAST_STATUS`) IsFilterable?
-
- { SPINEL_PROP_LAST_STATUS, SPINEL_STATUS_RESET_UNKNOWN, false }, // 0
- { SPINEL_PROP_STREAM_DEBUG, SPINEL_STATUS_OK, true }, // 1
- { SPINEL_PROP_IPV6_ADDRESS_TABLE, SPINEL_STATUS_OK, true }, // 2
- { SPINEL_PROP_NET_ROLE, SPINEL_STATUS_OK, true }, // 3
- { SPINEL_PROP_IPV6_LL_ADDR, SPINEL_STATUS_OK, true }, // 4
- { SPINEL_PROP_IPV6_ML_ADDR, SPINEL_STATUS_OK, true }, // 5
- { SPINEL_PROP_NET_PARTITION_ID, SPINEL_STATUS_OK, true }, // 6
- { SPINEL_PROP_NET_KEY_SEQUENCE_COUNTER, SPINEL_STATUS_OK, true }, // 7
- { SPINEL_PROP_THREAD_LEADER_NETWORK_DATA, SPINEL_STATUS_OK, true }, // 8
- { SPINEL_PROP_THREAD_CHILD_TABLE, SPINEL_STATUS_OK, true }, // 9
- { SPINEL_PROP_THREAD_ON_MESH_NETS, SPINEL_STATUS_OK, true }, // 10
- { SPINEL_PROP_THREAD_OFF_MESH_ROUTES, SPINEL_STATUS_OK, true }, // 11
- { SPINEL_PROP_NET_STACK_UP, SPINEL_STATUS_OK, true }, // 12
- { SPINEL_PROP_NET_REQUIRE_JOIN_EXISTING, SPINEL_STATUS_OK, true }, // 13
- { SPINEL_PROP_LAST_STATUS, SPINEL_STATUS_NOMEM, true }, // 14
- { SPINEL_PROP_LAST_STATUS, SPINEL_STATUS_DROPPED, true }, // 15
-#if OPENTHREAD_ENABLE_JAM_DETECTION
- { SPINEL_PROP_JAM_DETECTED, SPINEL_STATUS_OK, true }, // 16
-#endif
-#if OPENTHREAD_ENABLE_LEGACY
- { SPINEL_PROP_NEST_LEGACY_ULA_PREFIX, SPINEL_STATUS_OK, true }, // 17
- { SPINEL_PROP_NEST_LEGACY_LAST_NODE_JOINED, SPINEL_STATUS_OK, true }, // 18
-#endif
- { SPINEL_PROP_LAST_STATUS, SPINEL_STATUS_JOIN_FAILURE, false }, // 19
- { SPINEL_PROP_MAC_SCAN_STATE, SPINEL_STATUS_OK, false }, // 20
- { SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE, SPINEL_STATUS_OK, true }, // 21
-};
-
-uint8_t NcpBase::ChangedPropsSet::GetNumEntries(void) const
-{
- return (sizeof(mSupportedProps) / sizeof(mSupportedProps[0]));
-}
-
-void NcpBase::ChangedPropsSet::Add(spinel_prop_key_t aPropKey, spinel_status_t aStatus)
-{
- uint8_t numEntries;
- const Entry *entry;
-
- entry = GetSupportedEntries(numEntries);
-
- for (uint8_t index = 0; index < numEntries; index++, entry++)
- {
- if ((entry->mPropKey == aPropKey) && (entry->mStatus == aStatus))
- {
- if (!IsEntryFiltered(index))
- {
- SetBit(mChangedSet, index);
- }
-
- break;
- }
- }
-}
-
-otError NcpBase::ChangedPropsSet::EnablePropertyFilter(spinel_prop_key_t aPropKey, bool aEnable)
-{
- uint8_t numEntries;
- const Entry *entry;
- bool didFind = false;
-
- entry = GetSupportedEntries(numEntries);
-
- for (uint8_t index = 0; index < numEntries; index++, entry++)
- {
- if (entry->mFilterable && (entry->mPropKey == aPropKey))
- {
- if (aEnable)
- {
- SetBit(mFilterSet, index);
-
- // If filter is enabled for a property, the `mChangedSet` is cleared
- // for the same property so to ensure a pending update is also filtered.
-
- ClearBit(mChangedSet, index);
- }
- else
- {
- ClearBit(mFilterSet, index);
- }
-
- didFind = true;
-
- // Continue the search only if the prop key is `LAST_STATUS`, as
- // we have multiple filterable `LAST_STATUS` entries in the table
- // with different error status (DROPPED and NOMEM).
-
- if (aPropKey != SPINEL_PROP_LAST_STATUS)
- {
- break;
- }
- }
- }
-
- return didFind ? OT_ERROR_NONE : OT_ERROR_INVALID_ARGS;
-}
-
-bool NcpBase::ChangedPropsSet::IsPropertyFiltered(spinel_prop_key_t aPropKey) const
-{
- bool isFiltered = false;
- uint8_t numEntries;
- const Entry *entry;
-
- entry = GetSupportedEntries(numEntries);
-
- for (uint8_t index = 0; index < numEntries; index++, entry++)
- {
- if (entry->mFilterable && (entry->mPropKey == aPropKey))
- {
- isFiltered = IsEntryFiltered(index);
-
- break;
- }
- }
-
- return isFiltered;
-}
-
-// ----------------------------------------------------------------------------
-// MARK: Property/Status Changed
-// ----------------------------------------------------------------------------
-
-void NcpBase::HandleNetifStateChanged(uint32_t aFlags, void *aContext)
-{
- NcpBase *ncp = static_cast(aContext);
-
- ncp->mThreadChangedFlags |= aFlags;
- ncp->mUpdateChangedPropsTask.Post();
-}
-
-void NcpBase::UpdateChangedProps(Tasklet &aTasklet)
-{
- OT_UNUSED_VARIABLE(aTasklet);
- GetNcpInstance()->UpdateChangedProps();
-}
-
-void NcpBase::UpdateChangedProps(void)
-{
- uint8_t numEntries;
- spinel_prop_key_t propKey;
- const ChangedPropsSet::Entry *entry;
-
- ProcessThreadChangedFlags();
-
- VerifyOrExit(!mChangedPropsSet.IsEmpty());
-
- entry = mChangedPropsSet.GetSupportedEntries(numEntries);
-
- for (uint8_t index = 0; index < numEntries; index++, entry++)
- {
- if (!mChangedPropsSet.IsEntryChanged(index))
- {
- continue;
- }
-
- propKey = entry->mPropKey;
-
- if (propKey == SPINEL_PROP_LAST_STATUS)
- {
- spinel_status_t status = entry->mStatus;
-
- if (status == SPINEL_STATUS_RESET_UNKNOWN)
- {
- status = ResetReasonToSpinelStatus(otPlatGetResetReason(mInstance));
- }
-
- SuccessOrExit(SendLastStatus(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, status));
- }
- else
- {
- SuccessOrExit(HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, propKey));
- }
-
- mChangedPropsSet.RemoveEntry(index);
- VerifyOrExit(!mChangedPropsSet.IsEmpty());
- }
-
-exit:
- return;
-}
-
-void NcpBase::ProcessThreadChangedFlags(void)
-{
- static const struct
- {
- uint32_t mThreadFlag;
- spinel_prop_key_t mPropKey;
- } kFlags[] =
- {
- { OT_CHANGED_IP6_ADDRESS_ADDED, SPINEL_PROP_IPV6_ADDRESS_TABLE },
- { OT_CHANGED_IP6_ADDRESS_REMOVED, SPINEL_PROP_IPV6_ADDRESS_TABLE },
- { OT_CHANGED_THREAD_ROLE, SPINEL_PROP_NET_ROLE },
- { OT_CHANGED_THREAD_LL_ADDR, SPINEL_PROP_IPV6_LL_ADDR },
- { OT_CHANGED_THREAD_ML_ADDR, SPINEL_PROP_IPV6_ML_ADDR },
- { OT_CHANGED_THREAD_PARTITION_ID, SPINEL_PROP_NET_PARTITION_ID },
- { OT_CHANGED_THREAD_KEY_SEQUENCE_COUNTER, SPINEL_PROP_NET_KEY_SEQUENCE_COUNTER },
- { OT_CHANGED_THREAD_NETDATA, SPINEL_PROP_THREAD_LEADER_NETWORK_DATA },
- { OT_CHANGED_THREAD_CHILD_ADDED, SPINEL_PROP_THREAD_CHILD_TABLE },
- { OT_CHANGED_THREAD_CHILD_REMOVED, SPINEL_PROP_THREAD_CHILD_TABLE },
- { OT_CHANGED_IP6_MULTICAST_SUBSRCRIBED, SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE },
- { OT_CHANGED_IP6_MULTICAST_UNSUBSRCRIBED, SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE },
- };
-
- VerifyOrExit(mThreadChangedFlags != 0);
-
- // If thread role has changed, check for possible "join" error.
-
- if ((mThreadChangedFlags & OT_CHANGED_THREAD_ROLE) != 0)
- {
- if (mRequireJoinExistingNetwork)
- {
- switch (otThreadGetDeviceRole(mInstance))
- {
- case OT_DEVICE_ROLE_DETACHED:
- case OT_DEVICE_ROLE_DISABLED:
- break;
-
- default:
- mRequireJoinExistingNetwork = false;
- mChangedPropsSet.AddProperty(SPINEL_PROP_NET_REQUIRE_JOIN_EXISTING);
- break;
- }
-
- if ((otThreadGetDeviceRole(mInstance) == OT_DEVICE_ROLE_LEADER)
- && otThreadIsSingleton(mInstance)
-#if OPENTHREAD_ENABLE_LEGACY
- && !mLegacyNodeDidJoin
-#endif
- )
- {
- mThreadChangedFlags &= ~static_cast(OT_CHANGED_THREAD_PARTITION_ID);
- otThreadSetEnabled(mInstance, false);
-
- mChangedPropsSet.AddProperty(SPINEL_PROP_NET_STACK_UP);
- mChangedPropsSet.AddLastStatus(SPINEL_STATUS_JOIN_FAILURE);
- }
- }
- }
-
- // Convert OT_CHANGED flags to corresponding NCP property update.
-
- for (unsigned i = 0; i < sizeof(kFlags) / sizeof(kFlags[0]); i++)
- {
- uint32_t threadFlag = kFlags[i].mThreadFlag;
-
- if (mThreadChangedFlags & threadFlag)
- {
- mChangedPropsSet.AddProperty(kFlags[i].mPropKey);
-
- if (threadFlag == OT_CHANGED_THREAD_NETDATA)
- {
- mChangedPropsSet.AddProperty(SPINEL_PROP_THREAD_ON_MESH_NETS);
- mChangedPropsSet.AddProperty(SPINEL_PROP_THREAD_OFF_MESH_ROUTES);
- }
-
- mThreadChangedFlags &= ~threadFlag;
- VerifyOrExit(mThreadChangedFlags != 0);
- }
- }
-
- // Clear any remaining ThreadFlag that has no matching
- // NCP property update (e.g., OT_CHANGED_THREAD_RLOC_ADDED)
-
- mThreadChangedFlags = 0;
-
-exit:
- return;
-}
-
// ----------------------------------------------------------------------------
// MARK: Serial Traffic Glue
// ----------------------------------------------------------------------------
@@ -1710,6 +817,108 @@ void NcpBase::IncrementFrameErrorCounter(void)
mFramingErrorCounter++;
}
+otError NcpBase::StreamWrite(int aStreamId, const uint8_t *aDataPtr, int aDataLen)
+{
+ otError error = OT_ERROR_NONE;
+ spinel_prop_key_t streamPropKey;
+
+ if (aStreamId == 0)
+ {
+ streamPropKey = SPINEL_PROP_STREAM_DEBUG;
+ }
+ else
+ {
+ streamPropKey = static_cast(aStreamId);
+ }
+
+ VerifyOrExit(!mDisableStreamWrite, error = OT_ERROR_INVALID_STATE);
+ VerifyOrExit(!mChangedPropsSet.IsPropertyFiltered(streamPropKey), error = OT_ERROR_INVALID_STATE);
+
+ error = SendPropertyUpdate(
+ SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
+ SPINEL_CMD_PROP_VALUE_IS,
+ streamPropKey,
+ aDataPtr,
+ static_cast(aDataLen)
+ );
+
+ if (error != OT_ERROR_NONE)
+ {
+ mChangedPropsSet.AddLastStatus(SPINEL_STATUS_NOMEM);
+ mUpdateChangedPropsTask.Post();
+ }
+
+exit:
+ return error;
+}
+
+#if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
+
+void NcpBase::RegisterPeekPokeDelagates(otNcpDelegateAllowPeekPoke aAllowPeekDelegate,
+ otNcpDelegateAllowPeekPoke aAllowPokeDelegate)
+{
+ mAllowPeekDelegate = aAllowPeekDelegate;
+ mAllowPokeDelegate = aAllowPokeDelegate;
+}
+
+#endif // OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
+// ----------------------------------------------------------------------------
+// MARK: Property/Status Changed
+// ----------------------------------------------------------------------------
+
+void NcpBase::UpdateChangedProps(Tasklet &aTasklet)
+{
+ OT_UNUSED_VARIABLE(aTasklet);
+ GetNcpInstance()->UpdateChangedProps();
+}
+
+void NcpBase::UpdateChangedProps(void)
+{
+ uint8_t numEntries;
+ spinel_prop_key_t propKey;
+ const ChangedPropsSet::Entry *entry;
+
+#if OPENTHREAD_MTD || OPENTHREAD_FTD
+ ProcessThreadChangedFlags();
+#endif
+
+ VerifyOrExit(!mChangedPropsSet.IsEmpty());
+
+ entry = mChangedPropsSet.GetSupportedEntries(numEntries);
+
+ for (uint8_t index = 0; index < numEntries; index++, entry++)
+ {
+ if (!mChangedPropsSet.IsEntryChanged(index))
+ {
+ continue;
+ }
+
+ propKey = entry->mPropKey;
+
+ if (propKey == SPINEL_PROP_LAST_STATUS)
+ {
+ spinel_status_t status = entry->mStatus;
+
+ if (status == SPINEL_STATUS_RESET_UNKNOWN)
+ {
+ status = ResetReasonToSpinelStatus(otPlatGetResetReason(mInstance));
+ }
+
+ SuccessOrExit(SendLastStatus(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, status));
+ }
+ else
+ {
+ SuccessOrExit(HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, propKey));
+ }
+
+ mChangedPropsSet.RemoveEntry(index);
+ VerifyOrExit(!mChangedPropsSet.IsEmpty());
+ }
+
+exit:
+ return;
+}
+
// ----------------------------------------------------------------------------
// MARK: Inbound Command Handlers
// ----------------------------------------------------------------------------
@@ -1857,7 +1066,6 @@ otError NcpBase::HandleCommandPropertyRemove(uint8_t aHeader, spinel_prop_key_t
// MARK: Outbound Command Handlers
// ----------------------------------------------------------------------------
-
otError NcpBase::SendLastStatus(uint8_t aHeader, spinel_status_t aLastStatus)
{
if (SPINEL_HEADER_GET_IID(aHeader) == 0)
@@ -1932,6 +1140,20 @@ exit:
return error;
}
+otError NcpBase::SendSetPropertyResponse(uint8_t aHeader, spinel_prop_key_t aKey, otError aError)
+{
+ if (aError == OT_ERROR_NONE)
+ {
+ aError = HandleCommandPropertyGet(aHeader, aKey);
+ }
+ else
+ {
+ aError = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(aError));
+ }
+
+ return aError;
+}
+
otError NcpBase::OutboundFrameFeedVPacked(const char *aPackFormat, va_list aArgs)
{
uint8_t buf[96];
@@ -1988,12 +1210,14 @@ otError NcpBase::CommandHandler_RESET(uint8_t aHeader, unsigned int aCommand, co
// shouldn't return.
otInstanceReset(mInstance);
+#if OPENTHREAD_MTD || OPENTHREAD_FTD
// We only get to this point if the
// platform doesn't support resetting.
// In such a case we fake it.
otThreadSetEnabled(mInstance, false);
otIp6SetEnabled(mInstance, false);
+#endif
error = SendLastStatus(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_STATUS_RESET_SOFTWARE);
@@ -2140,36 +1364,6 @@ otError NcpBase::CommandHandler_PROP_VALUE_REMOVE(uint8_t aHeader, unsigned int
return error;
}
-otError NcpBase::CommandHandler_NET_SAVE(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr,
- uint16_t aArgLen)
-{
- OT_UNUSED_VARIABLE(aCommand);
- OT_UNUSED_VARIABLE(aArgPtr);
- OT_UNUSED_VARIABLE(aArgLen);
-
- return SendLastStatus(aHeader, SPINEL_STATUS_UNIMPLEMENTED);
-}
-
-otError NcpBase::CommandHandler_NET_CLEAR(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr,
- uint16_t aArgLen)
-{
- OT_UNUSED_VARIABLE(aCommand);
- OT_UNUSED_VARIABLE(aArgPtr);
- OT_UNUSED_VARIABLE(aArgLen);
-
- return SendLastStatus(aHeader, ThreadErrorToSpinelStatus(otInstanceErasePersistentInfo(mInstance)));
-}
-
-otError NcpBase::CommandHandler_NET_RECALL(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr,
- uint16_t aArgLen)
-{
- OT_UNUSED_VARIABLE(aCommand);
- OT_UNUSED_VARIABLE(aArgPtr);
- OT_UNUSED_VARIABLE(aArgLen);
-
- return SendLastStatus(aHeader, SPINEL_STATUS_UNIMPLEMENTED);
-}
-
#if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
otError NcpBase::CommandHandler_PEEK(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, uint16_t aArgLen)
@@ -2273,10 +1467,380 @@ exit:
#endif // OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
+
// ----------------------------------------------------------------------------
-// MARK: Individual Property Getters
+// MARK: Individual Property Getters and Setters
// ----------------------------------------------------------------------------
+otError NcpBase::GetPropertyHandler_PHY_CHAN(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT8_S,
+ otLinkGetChannel(mInstance)
+ );
+}
+
+otError NcpBase::SetPropertyHandler_PHY_CHAN(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ unsigned int channel = 0;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT_PACKED_S,
+ &channel
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+#if OPENTHREAD_MTD || OPENTHREAD_FTD
+ error = otLinkSetChannel(mInstance, static_cast(channel));
+#endif
+
+#if OPENTHREAD_ENABLE_RAW_LINK_API
+
+ SuccessOrExit(error);
+
+ // Cache the channel. If the raw link layer isn't enabled yet, the otSetChannel call
+ // doesn't call into the radio layer to set the channel. We will have to do it
+ // manually whenever the radios are enabled and/or raw stream is enabled.
+ mCurReceiveChannel = static_cast(channel);
+
+ // Make sure we are update the receiving channel if raw link is enabled and we have raw
+ // stream enabled already
+ if (otLinkRawIsEnabled(mInstance) && mIsRawStreamEnabled)
+ {
+ error = otLinkRawReceive(mInstance, mCurReceiveChannel, &NcpBase::LinkRawReceiveDone);
+ }
+
+#endif // OPENTHREAD_ENABLE_RAW_LINK_API
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_MAC_PROMISCUOUS_MODE(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_INT8_S,
+ otPlatRadioGetPromiscuous(mInstance)
+ ? SPINEL_MAC_PROMISCUOUS_MODE_FULL
+ : SPINEL_MAC_PROMISCUOUS_MODE_OFF
+ );
+}
+
+otError NcpBase::SetPropertyHandler_MAC_PROMISCUOUS_MODE(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ uint8_t mode = 0;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT8_S,
+ &mode
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ switch (mode)
+ {
+ case SPINEL_MAC_PROMISCUOUS_MODE_OFF:
+ otPlatRadioSetPromiscuous(mInstance, false);
+ break;
+
+ case SPINEL_MAC_PROMISCUOUS_MODE_NETWORK:
+ case SPINEL_MAC_PROMISCUOUS_MODE_FULL:
+ otPlatRadioSetPromiscuous(mInstance, true);
+ break;
+
+ default:
+ error = OT_ERROR_INVALID_ARGS;
+ break;
+ }
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_MAC_15_4_PANID(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT16_S,
+ otLinkGetPanId(mInstance)
+ );
+}
+
+otError NcpBase::SetPropertyHandler_MAC_15_4_PANID(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ uint16_t panid;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT16_S,
+ &panid
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ error = otLinkSetPanId(mInstance, panid);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_MAC_15_4_LADDR(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_EUI64_S,
+ otLinkGetExtendedAddress(mInstance)
+ );
+}
+
+otError NcpBase::SetPropertyHandler_MAC_15_4_LADDR(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ otExtAddress *extAddress;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_EUI64_S,
+ &extAddress
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ error = otLinkSetExtendedAddress(mInstance, extAddress);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_MAC_RAW_STREAM_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_BOOL_S,
+ mIsRawStreamEnabled
+ );
+}
+
+otError NcpBase::SetPropertyHandler_MAC_RAW_STREAM_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ bool value = false;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_BOOL_S,
+ &value
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+#if OPENTHREAD_ENABLE_RAW_LINK_API
+
+ if (otLinkRawIsEnabled(mInstance))
+ {
+ if (value)
+ {
+ error = otLinkRawReceive(mInstance, mCurReceiveChannel, &NcpBase::LinkRawReceiveDone);
+ }
+ else
+ {
+ error = otLinkRawSleep(mInstance);
+ }
+ }
+
+#endif // OPENTHREAD_ENABLE_RAW_LINK_API
+
+ mIsRawStreamEnabled = value;
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_UNSOL_UPDATE_FILTER(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otError error = OT_ERROR_NONE;
+ uint8_t numEntries;
+ const ChangedPropsSet::Entry *entry;
+
+ SuccessOrExit(error = OutboundFrameBegin(aHeader));
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_COMMAND_PROP_S,
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey
+ ));
+
+ entry = mChangedPropsSet.GetSupportedEntries(numEntries);
+
+ for (uint8_t index = 0; index < numEntries; index++, entry++)
+ {
+ if (mChangedPropsSet.IsEntryFiltered(index))
+ {
+ SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, entry->mPropKey));
+ }
+ }
+
+ SuccessOrExit(error = OutboundFrameSend());
+
+exit:
+ return error;
+}
+
+otError NcpBase::SetPropertyHandler_UNSOL_UPDATE_FILTER(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ unsigned int propKey;
+ otError error = OT_ERROR_NONE;
+ bool reportAsync;
+
+ // First clear the current filter.
+ mChangedPropsSet.ClearFilter();
+
+ while (aValueLen > 0)
+ {
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT_PACKED_S,
+ &propKey
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ IgnoreReturnValue(mChangedPropsSet.EnablePropertyFilter(static_cast(propKey), true));
+
+ aValuePtr += parsedLength;
+ aValueLen -= parsedLength;
+ }
+
+exit:
+ // If we had an error, we may have actually changed
+ // the state of the filter---so we need to report
+ // those incomplete changes via an asynchronous
+ // change event.
+ reportAsync = (error != OT_ERROR_NONE);
+
+ error = SendSetPropertyResponse(aHeader, aKey, error);
+
+ if (reportAsync)
+ {
+ HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, aKey);
+ }
+
+ return error;
+}
+
+otError NcpBase::InsertPropertyHandler_UNSOL_UPDATE_FILTER(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ unsigned int propKey;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT_PACKED_S,
+ &propKey
+ );
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ error = mChangedPropsSet.EnablePropertyFilter(static_cast(propKey), true);
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_INSERTED,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+
+otError NcpBase::RemovePropertyHandler_UNSOL_UPDATE_FILTER(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ unsigned int propKey;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT_PACKED_S,
+ &propKey
+ );
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ error = mChangedPropsSet.EnablePropertyFilter(static_cast(propKey), false);
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_INSERTED,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+
otError NcpBase::GetPropertyHandler_LAST_STATUS(uint8_t aHeader, spinel_prop_key_t aKey)
{
return SendPropertyUpdate(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey, SPINEL_DATATYPE_UINT_PACKED_S, mLastStatus);
@@ -2334,18 +1898,19 @@ otError NcpBase::GetPropertyHandler_CAPS(uint8_t aHeader, spinel_prop_key_t aKey
// Begin adding capabilities //////////////////////////////////////////////
- SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_NET_THREAD_1_0));
SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_COUNTERS));
SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_UNSOL_UPDATE_FILTER));
-#if OPENTHREAD_ENABLE_MAC_FILTER
- SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_MAC_WHITELIST));
-#endif
-
#if OPENTHREAD_ENABLE_RAW_LINK_API
SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_MAC_RAW));
#endif
+#if OPENTHREAD_MTD || OPENTHREAD_FTD
+ SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_NET_THREAD_1_0));
+#if OPENTHREAD_ENABLE_MAC_FILTER
+ SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_MAC_WHITELIST));
+#endif
+
#if OPENTHREAD_ENABLE_JAM_DETECTION
SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_JAM_DETECT));
#endif
@@ -2371,10 +1936,11 @@ otError NcpBase::GetPropertyHandler_CAPS(uint8_t aHeader, spinel_prop_key_t aKey
SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_NEST_LEGACY_INTERFACE));
#endif
-#if OPENTHREAD_ENABLE_TMF_PROXY && OPENTHREAD_FTD
+#if OPENTHREAD_ENABLE_TMF_PROXY
SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_THREAD_TMF_PROXY));
#endif
+#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
// End adding capabilities /////////////////////////////////////////////////
SuccessOrExit(error = OutboundFrameSend());
@@ -2417,10 +1983,21 @@ otError NcpBase::GetPropertyHandler_POWER_STATE(uint8_t aHeader, spinel_prop_key
);
}
+otError NcpBase::SetPropertyHandler_POWER_STATE(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ // TODO: Implement POWER_STATE
+ OT_UNUSED_VARIABLE(aKey);
+ OT_UNUSED_VARIABLE(aValuePtr);
+ OT_UNUSED_VARIABLE(aValueLen);
+
+ return SendLastStatus(aHeader, SPINEL_STATUS_UNIMPLEMENTED);
+}
+
otError NcpBase::GetPropertyHandler_HWADDR(uint8_t aHeader, spinel_prop_key_t aKey)
{
otExtAddress hwAddr;
- otLinkGetFactoryAssignedIeeeEui64(mInstance, &hwAddr);
+ otPlatRadioGetIeeeEui64(mInstance, hwAddr.m8);
return SendPropertyUpdate(
aHeader,
@@ -2450,2106 +2027,6 @@ otError NcpBase::GetPropertyHandler_HOST_POWER_STATE(uint8_t aHeader, spinel_pro
);
}
-otError NcpBase::GetPropertyHandler_UNSOL_UPDATE_FILTER(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otError error = OT_ERROR_NONE;
- uint8_t numEntries;
- const ChangedPropsSet::Entry *entry;
-
- SuccessOrExit(error = OutboundFrameBegin(aHeader));
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_COMMAND_PROP_S,
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey
- ));
-
- entry = mChangedPropsSet.GetSupportedEntries(numEntries);
-
- for (uint8_t index = 0; index < numEntries; index++, entry++)
- {
- if (mChangedPropsSet.IsEntryFiltered(index))
- {
- SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, entry->mPropKey));
- }
- }
-
- SuccessOrExit(error = OutboundFrameSend());
-
-exit:
- return error;
-}
-
-otError NcpBase::GetPropertyHandler_UNSOL_UPDATE_LIST(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otError error = OT_ERROR_NONE;
- uint8_t numEntries;
- const ChangedPropsSet::Entry *entry;
-
- SuccessOrExit(error = OutboundFrameBegin(aHeader));
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_COMMAND_PROP_S,
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey
- ));
-
- entry = mChangedPropsSet.GetSupportedEntries(numEntries);
-
- for (uint8_t index = 0; index < numEntries; index++, entry++)
- {
- if (entry->mFilterable)
- {
- SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, entry->mPropKey));
- }
- }
-
- SuccessOrExit(error = OutboundFrameSend());
-
-exit:
- return error;
-}
-
-otError NcpBase::GetPropertyHandler_PHY_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_BOOL_S,
-#if OPENTHREAD_ENABLE_RAW_LINK_API
- otLinkRawIsEnabled(mInstance)
-#else
- false
-#endif // OPENTHREAD_ENABLE_RAW_LINK_API
- );
-}
-
-otError NcpBase::GetPropertyHandler_PHY_FREQ(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- uint32_t freq_khz(0);
- const uint8_t chan(otLinkGetChannel(mInstance));
-
- if (chan == 0)
- {
- freq_khz = 868300;
- }
- else if (chan < 11)
- {
- freq_khz = 906000 - (2000 * 1) + 2000 * (chan);
- }
- else if (chan < 26)
- {
- freq_khz = 2405000 - (5000 * 11) + 5000 * (chan);
- }
-
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT32_S,
- freq_khz
- );
-}
-
-otError NcpBase::GetPropertyHandler_PHY_CHAN_SUPPORTED(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return GetPropertyHandler_ChannelMaskHelper(aHeader, aKey, mSupportedChannelMask);
-}
-
-otError NcpBase::GetPropertyHandler_PHY_CHAN(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT8_S,
- otLinkGetChannel(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_PHY_RSSI(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_INT8_S,
- otPlatRadioGetRssi(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_PHY_TX_POWER(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_INT8_S,
- otLinkGetMaxTransmitPower(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_PHY_RX_SENSITIVITY(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_INT8_S,
- otPlatRadioGetReceiveSensitivity(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_MAC_SCAN_STATE(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otError error = OT_ERROR_NONE;
-
-#if OPENTHREAD_ENABLE_RAW_LINK_API
-
- if (otLinkRawIsEnabled(mInstance))
- {
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT8_S,
- mCurScanChannel == NCP_INVALID_SCAN_CHANNEL
- ? SPINEL_SCAN_STATE_IDLE
- : SPINEL_SCAN_STATE_ENERGY
- );
- }
- else
-
-#endif // OPENTHREAD_ENABLE_RAW_LINK_API
-
- {
- if (otLinkIsActiveScanInProgress(mInstance))
- {
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT8_S,
- SPINEL_SCAN_STATE_BEACON
- );
- }
- else if (otLinkIsEnergyScanInProgress(mInstance))
- {
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT8_S,
- SPINEL_SCAN_STATE_ENERGY
- );
- }
- else if (otThreadIsDiscoverInProgress(mInstance))
- {
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT8_S,
- SPINEL_SCAN_STATE_DISCOVER
- );
- }
- else
- {
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT8_S,
- SPINEL_SCAN_STATE_IDLE
- );
- }
- }
-
- return error;
-}
-
-otError NcpBase::GetPropertyHandler_MAC_SCAN_PERIOD(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT16_S,
- mScanPeriod
- );
-}
-
-otError NcpBase::GetPropertyHandler_ChannelMaskHelper(uint8_t aHeader, spinel_prop_key_t aKey, uint32_t aChannelMask)
-{
- otError error = OT_ERROR_NONE;
-
- SuccessOrExit(error = OutboundFrameBegin(aHeader));
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_COMMAND_PROP_S,
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey
- ));
-
- for (int i = 0; i < 32; i++)
- {
- if (0 != (aChannelMask & (1 << i)))
- {
- SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT8_S, i));
- }
- }
-
- SuccessOrExit(error = OutboundFrameSend());
-
-exit:
- return error;
-}
-
-otError NcpBase::GetPropertyHandler_MAC_SCAN_MASK(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return GetPropertyHandler_ChannelMaskHelper(aHeader, aKey, mChannelMask);
-}
-
-otError NcpBase::GetPropertyHandler_MAC_15_4_PANID(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT16_S,
- otLinkGetPanId(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_MAC_PROMISCUOUS_MODE(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_INT8_S,
- otPlatRadioGetPromiscuous(mInstance)
- ? SPINEL_MAC_PROMISCUOUS_MODE_FULL
- : SPINEL_MAC_PROMISCUOUS_MODE_OFF
- );
-}
-
-otError NcpBase::GetPropertyHandler_MAC_15_4_LADDR(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_EUI64_S,
- otLinkGetExtendedAddress(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_MAC_15_4_SADDR(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT16_S,
- otLinkGetShortAddress(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_MAC_EXTENDED_ADDR(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_EUI64_S,
- otLinkGetExtendedAddress(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_MAC_DATA_POLL_PERIOD(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT32_S,
- otLinkGetPollPeriod(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_MAC_RAW_STREAM_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_BOOL_S,
- mIsRawStreamEnabled
- );
-}
-
-otError NcpBase::GetPropertyHandler_NET_SAVED(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_BOOL_S,
- otDatasetIsCommissioned(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_NET_IF_UP(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_BOOL_S,
- otIp6IsEnabled(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_NET_STACK_UP(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_BOOL_S,
- otThreadGetDeviceRole(mInstance) != OT_DEVICE_ROLE_DISABLED
- );
-}
-
-otError NcpBase::GetPropertyHandler_NET_ROLE(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- spinel_net_role_t role(SPINEL_NET_ROLE_DETACHED);
-
- switch (otThreadGetDeviceRole(mInstance))
- {
- case OT_DEVICE_ROLE_DISABLED:
- case OT_DEVICE_ROLE_DETACHED:
- role = SPINEL_NET_ROLE_DETACHED;
- break;
-
- case OT_DEVICE_ROLE_CHILD:
- role = SPINEL_NET_ROLE_CHILD;
- break;
-
- case OT_DEVICE_ROLE_ROUTER:
- role = SPINEL_NET_ROLE_ROUTER;
- break;
-
- case OT_DEVICE_ROLE_LEADER:
- role = SPINEL_NET_ROLE_LEADER;
- break;
- }
-
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT8_S,
- role
- );
-}
-
-otError NcpBase::GetPropertyHandler_NET_NETWORK_NAME(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UTF8_S,
- otThreadGetNetworkName(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_NET_XPANID(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_DATA_S,
- otThreadGetExtendedPanId(mInstance),
- sizeof(spinel_net_xpanid_t)
- );
-}
-
-otError NcpBase::GetPropertyHandler_NET_MASTER_KEY(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_DATA_S,
- otThreadGetMasterKey(mInstance)->m8,
- OT_MASTER_KEY_SIZE
- );
-}
-
-otError NcpBase::GetPropertyHandler_NET_KEY_SEQUENCE_COUNTER(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT32_S,
- otThreadGetKeySequenceCounter(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_NET_PARTITION_ID(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT32_S,
- otThreadGetPartitionId(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_NET_KEY_SWITCH_GUARDTIME(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT32_S,
- otThreadGetKeySwitchGuardTime(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_THREAD_NETWORK_DATA_VERSION(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT8_S,
- otNetDataGetVersion(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_THREAD_STABLE_NETWORK_DATA_VERSION(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT8_S,
- otNetDataGetStableVersion(mInstance)
- );
-}
-
-#if OPENTHREAD_ENABLE_BORDER_ROUTER
-otError NcpBase::GetPropertyHandler_THREAD_NETWORK_DATA(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otError error = OT_ERROR_NONE;
- uint8_t networkData[255];
- uint8_t networkDataLen = 255;
-
- otBorderRouterGetNetData(
- mInstance,
- false, // Stable?
- networkData,
- &networkDataLen
- );
-
- SuccessOrExit(error = OutboundFrameBegin(aHeader));
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_COMMAND_PROP_S,
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey
- ));
- SuccessOrExit(error = OutboundFrameFeedData(networkData, networkDataLen));
- SuccessOrExit(error = OutboundFrameSend());
-
-exit:
- return error;
-}
-
-otError NcpBase::GetPropertyHandler_THREAD_STABLE_NETWORK_DATA(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otError error = OT_ERROR_NONE;
- uint8_t networkData[255];
- uint8_t networkDataLen = 255;
-
- otBorderRouterGetNetData(
- mInstance,
- true, // Stable?
- networkData,
- &networkDataLen
- );
-
- SuccessOrExit(error = OutboundFrameBegin(aHeader));
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_COMMAND_PROP_S,
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey
- ));
- SuccessOrExit(error = OutboundFrameFeedData(networkData, networkDataLen));
- SuccessOrExit(error = OutboundFrameSend());
-
-exit:
- return error;
-}
-#endif // OPENTHREAD_ENABLE_BORDER_ROUTER
-
-otError NcpBase::GetPropertyHandler_THREAD_LEADER_NETWORK_DATA(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otError error = OT_ERROR_NONE;
- uint8_t networkData[255];
- uint8_t networkDataLen = 255;
-
- otNetDataGet(
- mInstance,
- false, // Stable?
- networkData,
- &networkDataLen
- );
-
- SuccessOrExit(error = OutboundFrameBegin(aHeader));
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_COMMAND_PROP_S,
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey
- ));
- SuccessOrExit(error = OutboundFrameFeedData(networkData, networkDataLen));
- SuccessOrExit(error = OutboundFrameSend());
-
-exit:
- return error;
-}
-
-otError NcpBase::GetPropertyHandler_THREAD_STABLE_LEADER_NETWORK_DATA(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otError error = OT_ERROR_NONE;
- uint8_t networkData[255];
- uint8_t networkDataLen = 255;
-
- otNetDataGet(
- mInstance,
- true, // Stable?
- networkData,
- &networkDataLen
- );
-
- SuccessOrExit(error = OutboundFrameBegin(aHeader));
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_COMMAND_PROP_S,
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey
- ));
- SuccessOrExit(error = OutboundFrameFeedData(networkData, networkDataLen));
- SuccessOrExit(error = OutboundFrameSend());
-
-exit:
- return error;
-}
-
-otError NcpBase::GetPropertyHandler_THREAD_LEADER_RID(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT8_S,
- otThreadGetLeaderRouterId(mInstance)
- );
-}
-
-#if OPENTHREAD_FTD
-otError NcpBase::GetPropertyHandler_THREAD_LOCAL_LEADER_WEIGHT(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT8_S,
- otThreadGetLocalLeaderWeight(mInstance)
- );
-}
-#endif // OPENTHREAD_FTD
-
-otError NcpBase::GetPropertyHandler_THREAD_LEADER_WEIGHT(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT8_S,
- otThreadGetLeaderWeight(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_THREAD_LEADER_ADDR(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otError error = OT_ERROR_NONE;
- otIp6Address address;
-
- error = otThreadGetLeaderRloc(mInstance, &address);
-
- if (error == OT_ERROR_NONE)
- {
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_IPv6ADDR_S,
- &address
- );
- }
- else
- {
- error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
- }
-
- return error;
-}
-
-otError NcpBase::GetPropertyHandler_THREAD_PARENT(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otError error = OT_ERROR_NONE;
- otRouterInfo parentInfo;
-
- error = otThreadGetParentInfo(mInstance, &parentInfo);
-
- if (error == OT_ERROR_NONE)
- {
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- (
- SPINEL_DATATYPE_EUI64_S // Parent's extended address
- SPINEL_DATATYPE_UINT16_S // Parent's rloc16
- ),
- parentInfo.mExtAddress.m8,
- parentInfo.mRloc16
- );
- }
- else
- {
- error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
- }
-
- return error;
-}
-
-#if OPENTHREAD_FTD
-otError NcpBase::GetPropertyHandler_THREAD_CHILD_TABLE(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otError error = OT_ERROR_NONE;
- otChildInfo childInfo;
- uint8_t maxChildren;
- uint8_t modeFlags;
-
- mDisableStreamWrite = true;
-
- SuccessOrExit(error = OutboundFrameBegin(aHeader));
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_COMMAND_PROP_S,
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey
- ));
-
- maxChildren = otThreadGetMaxAllowedChildren(mInstance);
-
- for (uint8_t index = 0; index < maxChildren; index++)
- {
- error = otThreadGetChildInfoByIndex(mInstance, index, &childInfo);
-
- if (error != OT_ERROR_NONE)
- {
- continue;
- }
-
- modeFlags = LinkFlagsToFlagByte(
- childInfo.mRxOnWhenIdle,
- childInfo.mSecureDataRequest,
- childInfo.mFullFunction,
- childInfo.mFullNetworkData
- );
-
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_STRUCT_S(
- SPINEL_DATATYPE_EUI64_S // EUI64 Address
- SPINEL_DATATYPE_UINT16_S // Rloc16
- SPINEL_DATATYPE_UINT32_S // Timeout
- SPINEL_DATATYPE_UINT32_S // Age
- SPINEL_DATATYPE_UINT8_S // Network Data Version
- SPINEL_DATATYPE_UINT8_S // Link Quality In
- SPINEL_DATATYPE_INT8_S // Average RSS
- SPINEL_DATATYPE_UINT8_S // Mode (flags)
- SPINEL_DATATYPE_INT8_S // Most recent RSS
- ),
- childInfo.mExtAddress.m8,
- childInfo.mRloc16,
- childInfo.mTimeout,
- childInfo.mAge,
- childInfo.mNetworkDataVersion,
- childInfo.mLinkQualityIn,
- childInfo.mAverageRssi,
- modeFlags,
- childInfo.mLastRssi
- ));
- }
-
- SuccessOrExit(error = OutboundFrameSend());
-
-exit:
- mDisableStreamWrite = false;
- return error;
-}
-#endif // OPENTHREAD_FTD
-
-otError NcpBase::GetPropertyHandler_THREAD_NEIGHBOR_TABLE(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otError error = OT_ERROR_NONE;
- otNeighborInfoIterator iter = OT_NEIGHBOR_INFO_ITERATOR_INIT;
- otNeighborInfo neighInfo;
- uint8_t modeFlags;
-
- mDisableStreamWrite = true;
-
- SuccessOrExit(error = OutboundFrameBegin(aHeader));
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_COMMAND_PROP_S,
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey
- ));
-
- while (otThreadGetNextNeighborInfo(mInstance, &iter, &neighInfo) == OT_ERROR_NONE)
- {
- modeFlags = LinkFlagsToFlagByte(
- neighInfo.mRxOnWhenIdle,
- neighInfo.mSecureDataRequest,
- neighInfo.mFullFunction,
- neighInfo.mFullNetworkData
- );
-
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_STRUCT_S(
- SPINEL_DATATYPE_EUI64_S // EUI64 Address
- SPINEL_DATATYPE_UINT16_S // Rloc16
- SPINEL_DATATYPE_UINT32_S // Age
- SPINEL_DATATYPE_UINT8_S // Link Quality In
- SPINEL_DATATYPE_INT8_S // Average RSS
- SPINEL_DATATYPE_UINT8_S // Mode (flags)
- SPINEL_DATATYPE_BOOL_S // Is Child
- SPINEL_DATATYPE_UINT32_S // Link Frame Counter
- SPINEL_DATATYPE_UINT32_S // MLE Frame Counter
- SPINEL_DATATYPE_INT8_S // Most recent RSS
- ),
- neighInfo.mExtAddress.m8,
- neighInfo.mRloc16,
- neighInfo.mAge,
- neighInfo.mLinkQualityIn,
- neighInfo.mAverageRssi,
- modeFlags,
- neighInfo.mIsChild,
- neighInfo.mLinkFrameCounter,
- neighInfo.mMleFrameCounter,
- neighInfo.mLastRssi
- ));
- }
-
- SuccessOrExit(error = OutboundFrameSend());
-
-exit:
- mDisableStreamWrite = false;
- return error;
-}
-
-otError NcpBase::GetPropertyHandler_THREAD_ASSISTING_PORTS(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otError error = OT_ERROR_NONE;
- uint8_t numEntries = 0;
- const uint16_t *ports = otIp6GetUnsecurePorts(mInstance, &numEntries);
-
- SuccessOrExit(error = OutboundFrameBegin(aHeader));
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_COMMAND_PROP_S,
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey
- ));
-
- for (; numEntries != 0; ports++, numEntries--)
- {
- SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT16_S, *ports));
- }
-
- SuccessOrExit(error = OutboundFrameSend());
-
-exit:
- return error;
-}
-
-otError NcpBase::GetPropertyHandler_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_BOOL_S,
- mAllowLocalNetworkDataChange
- );
-}
-
-#if OPENTHREAD_FTD
-otError NcpBase::GetPropertyHandler_THREAD_ROUTER_ROLE_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_BOOL_S,
- otThreadIsRouterRoleEnabled(mInstance)
- );
-}
-#endif // OPENTHREAD_FTD
-
-otError NcpBase::GetPropertyHandler_THREAD_ON_MESH_NETS(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otError error = OT_ERROR_NONE;
- otBorderRouterConfig borderRouterConfig;
- uint8_t flags;
-
- mDisableStreamWrite = true;
-
- SuccessOrExit(error = OutboundFrameBegin(aHeader));
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_COMMAND_PROP_S,
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey
- ));
-
- // Fill from non-local network data first
- for (otNetworkDataIterator iter = OT_NETWORK_DATA_ITERATOR_INIT ;;)
- {
- error = otNetDataGetNextOnMeshPrefix(mInstance, &iter, &borderRouterConfig);
-
- if (error != OT_ERROR_NONE)
- {
- break;
- }
-
- flags = BorderRouterConfigToFlagByte(borderRouterConfig);
-
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_STRUCT_S(
- SPINEL_DATATYPE_IPv6ADDR_S // IPv6 Prefix
- SPINEL_DATATYPE_UINT8_S // Prefix Length (in bits)
- SPINEL_DATATYPE_BOOL_S // isStable
- SPINEL_DATATYPE_UINT8_S // Flags
- SPINEL_DATATYPE_BOOL_S // isLocal
- ),
- &borderRouterConfig.mPrefix,
- 64,
- borderRouterConfig.mStable,
- flags,
- false
- ));
- }
-
-#if OPENTHREAD_ENABLE_BORDER_ROUTER
- // Fill from local network data last
- for (otNetworkDataIterator iter = OT_NETWORK_DATA_ITERATOR_INIT ;;)
- {
- error = otBorderRouterGetNextOnMeshPrefix(mInstance, &iter, &borderRouterConfig);
-
- if (error != OT_ERROR_NONE)
- {
- break;
- }
-
- flags = BorderRouterConfigToFlagByte(borderRouterConfig);
-
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_STRUCT_S(
- SPINEL_DATATYPE_IPv6ADDR_S // IPv6 Prefix
- SPINEL_DATATYPE_UINT8_S // Prefix Length (in bits)
- SPINEL_DATATYPE_BOOL_S // isStable
- SPINEL_DATATYPE_UINT8_S // Flags
- SPINEL_DATATYPE_BOOL_S // isLocal
- ),
- &borderRouterConfig.mPrefix,
- 64,
- borderRouterConfig.mStable,
- flags,
- true
- ));
- }
-#endif // OPENTHREAD_ENABLE_BORDER_ROUTER
-
- SuccessOrExit(error = OutboundFrameSend());
-
-exit:
- mDisableStreamWrite = false;
- return error;
-}
-
-otError NcpBase::GetPropertyHandler_THREAD_DISCOVERY_SCAN_JOINER_FLAG(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_BOOL_S,
- mDiscoveryScanJoinerFlag
- );
-}
-
-otError NcpBase::GetPropertyHandler_THREAD_DISCOVERY_SCAN_ENABLE_FILTERING(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_BOOL_S,
- mDiscoveryScanEnableFiltering
- );
-}
-
-otError NcpBase::GetPropertyHandler_THREAD_DISCOVERY_SCAN_PANID(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT16_S,
- mDiscoveryScanPanId
- );
-}
-
-otError NcpBase::GetPropertyHandler_IPV6_ML_PREFIX(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otError error = OT_ERROR_NONE;
- const uint8_t *mlPrefix = otThreadGetMeshLocalPrefix(mInstance);
-
- if (mlPrefix)
- {
- otIp6Address addr;
-
- memcpy(addr.mFields.m8, mlPrefix, 8);
-
- // Zero out the last 8 bytes.
- memset(addr.mFields.m8 + 8, 0, 8);
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- (
- SPINEL_DATATYPE_IPv6ADDR_S // Mesh-local IPv6 address
- SPINEL_DATATYPE_UINT8_S // Prefix length (in bits)
- ),
- &addr,
- 64
- );
- }
- else
- {
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_VOID_S
- );
- }
-
- return error;
-}
-
-otError NcpBase::GetPropertyHandler_IPV6_ML_ADDR(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otError error = OT_ERROR_NONE;
- const otIp6Address *ml64 = otThreadGetMeshLocalEid(mInstance);
-
- if (ml64)
- {
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_IPv6ADDR_S,
- ml64
- );
- }
- else
- {
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_VOID_S
- );
- }
-
- return error;
-}
-
-otError NcpBase::GetPropertyHandler_IPV6_LL_ADDR(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otError error = OT_ERROR_NONE;
- const otIp6Address *address = otThreadGetLinkLocalIp6Address(mInstance);
-
- if (address)
- {
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_IPv6ADDR_S,
- address
- );
- }
- else
- {
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_VOID_S
- );
- }
-
- return error;
-}
-
-otError NcpBase::GetPropertyHandler_IPV6_ADDRESS_TABLE(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otError error = OT_ERROR_NONE;
-
- mDisableStreamWrite = true;
-
- SuccessOrExit(error = OutboundFrameBegin(aHeader));
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_COMMAND_PROP_S,
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey
- ));
-
- for (const otNetifAddress *address = otIp6GetUnicastAddresses(mInstance); address; address = address->mNext)
- {
-
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_STRUCT_S(
- SPINEL_DATATYPE_IPv6ADDR_S // IPv6 address
- SPINEL_DATATYPE_UINT8_S // Prefix length (in bits)
- SPINEL_DATATYPE_UINT32_S // Preferred lifetime
- SPINEL_DATATYPE_UINT32_S // Valid lifetime
- ),
- &address->mAddress,
- address->mPrefixLength,
- address->mPreferred ? 0xffffffff : 0,
- address->mValid ? 0xffffffff : 0
- ));
- }
-
- SuccessOrExit(error = OutboundFrameSend());
-
-exit:
- mDisableStreamWrite = false;
- return error;
-}
-
-otError NcpBase::GetPropertyHandler_IPV6_ROUTE_TABLE(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- // TODO: Implement get route table
- OT_UNUSED_VARIABLE(aKey);
-
- return SendLastStatus(aHeader, SPINEL_STATUS_UNIMPLEMENTED);
-}
-
-otError NcpBase::GetPropertyHandler_IPV6_ICMP_PING_OFFLOAD(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_BOOL_S,
- otIcmp6IsEchoEnabled(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_IPV6_MULTICAST_ADDRESS_TABLE(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otError error = OT_ERROR_NONE;
- const otNetifMulticastAddress *address;
-
- mDisableStreamWrite = true;
-
- SuccessOrExit(error = OutboundFrameBegin(aHeader));
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_COMMAND_PROP_S,
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey
- ));
-
- for (address = otIp6GetMulticastAddresses(mInstance); address; address = address->mNext)
- {
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_STRUCT_S(
- SPINEL_DATATYPE_IPv6ADDR_S // IPv6 address
- ),
- &address->mAddress
- ));
- }
-
- SuccessOrExit(error = OutboundFrameSend());
-
-exit:
- mDisableStreamWrite = false;
- return error;
-}
-
-otError NcpBase::GetPropertyHandler_THREAD_RLOC16_DEBUG_PASSTHRU(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- // Note reverse logic: passthru enabled = filter disabled
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_BOOL_S,
- !otIp6IsReceiveFilterEnabled(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_THREAD_OFF_MESH_ROUTES(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otError error = OT_ERROR_NONE;
- otExternalRouteConfig external_route_config;
- otNetworkDataIterator iter = OT_NETWORK_DATA_ITERATOR_INIT;
-
- mDisableStreamWrite = true;
-
- SuccessOrExit(error = OutboundFrameBegin(aHeader));
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_COMMAND_PROP_S,
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey
- ));
-
- while (otNetDataGetNextRoute(mInstance, &iter, &external_route_config) == OT_ERROR_NONE)
- {
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_STRUCT_S(
- SPINEL_DATATYPE_IPv6ADDR_S // IPv6 Prefix
- SPINEL_DATATYPE_UINT8_S // Prefix Length (in bits)
- SPINEL_DATATYPE_BOOL_S // IsStable
- SPINEL_DATATYPE_UINT8_S // Route Preference Flags
- SPINEL_DATATYPE_BOOL_S // IsLocal
- SPINEL_DATATYPE_BOOL_S // NextHopIsThisDevice
- ),
- &external_route_config.mPrefix.mPrefix,
- external_route_config.mPrefix.mLength,
- external_route_config.mStable,
- ExternalRoutePreferenceToFlagByte(external_route_config.mPreference),
- false,
- external_route_config.mNextHopIsThisDevice
- ));
- }
-
-#if OPENTHREAD_ENABLE_BORDER_ROUTER
- while (otBorderRouterGetNextRoute(mInstance, &iter, &external_route_config) == OT_ERROR_NONE)
- {
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_STRUCT_S(
- SPINEL_DATATYPE_IPv6ADDR_S // IPv6 Prefix
- SPINEL_DATATYPE_UINT8_S // Prefix Length (in bits)
- SPINEL_DATATYPE_BOOL_S // IsStable
- SPINEL_DATATYPE_UINT8_S // Route Preference Flags
- SPINEL_DATATYPE_BOOL_S // IsLocal
- SPINEL_DATATYPE_BOOL_S // NextHopIsThisDevice
- ),
- &external_route_config.mPrefix.mPrefix,
- external_route_config.mPrefix.mLength,
- external_route_config.mStable,
- ExternalRoutePreferenceToFlagByte(external_route_config.mPreference),
- true,
- external_route_config.mNextHopIsThisDevice
- ));
- }
-#endif // OPENTHREAD_ENABLE_BORDER_ROUTER
-
- SuccessOrExit(error = OutboundFrameSend());
-
-exit:
- mDisableStreamWrite = false;
- return error;
-}
-
-otError NcpBase::GetPropertyHandler_STREAM_NET(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- // TODO: Implement explicit data poll.
- OT_UNUSED_VARIABLE(aKey);
-
- return SendLastStatus(aHeader, SPINEL_STATUS_UNIMPLEMENTED);
-}
-
-#if OPENTHREAD_ENABLE_TMF_PROXY && OPENTHREAD_FTD
-otError NcpBase::GetPropertyHandler_THREAD_TMF_PROXY_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_BOOL_S,
- otTmfProxyIsEnabled(mInstance)
- );
-}
-#endif // OPENTHREAD_ENABLE_TMF_PROXY && OPENTHREAD_FTD
-
-#if OPENTHREAD_ENABLE_JAM_DETECTION
-
-otError NcpBase::GetPropertyHandler_JAM_DETECT_ENABLE(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_BOOL_S,
- otJamDetectionIsEnabled(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_JAM_DETECTED(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_BOOL_S,
- otJamDetectionGetState(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_JAM_DETECT_RSSI_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_INT8_S,
- otJamDetectionGetRssiThreshold(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_JAM_DETECT_WINDOW(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT8_S,
- otJamDetectionGetWindow(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_JAM_DETECT_BUSY(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT8_S,
- otJamDetectionGetBusyPeriod(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_JAM_DETECT_HISTORY_BITMAP(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- uint64_t historyBitmap = otJamDetectionGetHistoryBitmap(mInstance);
-
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- (
- SPINEL_DATATYPE_UINT32_S // History bitmap - bits 0-31
- SPINEL_DATATYPE_UINT32_S // History bitmap - bits 32-63
- ),
- static_cast(historyBitmap & 0xffffffff),
- static_cast(historyBitmap >> 32)
- );
-}
-
-#endif // OPENTHREAD_ENABLE_JAM_DETECTION
-
-otError NcpBase::GetPropertyHandler_MAC_CNTR(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- uint32_t value;
- const otMacCounters *macCounters;
- otError error = OT_ERROR_NONE;
-
- macCounters = otLinkGetCounters(mInstance);
-
- assert(macCounters != NULL);
-
- switch (aKey)
- {
- case SPINEL_PROP_CNTR_TX_PKT_TOTAL:
- value = macCounters->mTxTotal;
- break;
-
- case SPINEL_PROP_CNTR_TX_PKT_ACK_REQ:
- value = macCounters->mTxAckRequested;
- break;
-
- case SPINEL_PROP_CNTR_TX_PKT_ACKED:
- value = macCounters->mTxAcked;
- break;
-
- case SPINEL_PROP_CNTR_TX_PKT_NO_ACK_REQ:
- value = macCounters->mTxNoAckRequested;
- break;
-
- case SPINEL_PROP_CNTR_TX_PKT_DATA:
- value = macCounters->mTxData;
- break;
-
- case SPINEL_PROP_CNTR_TX_PKT_DATA_POLL:
- value = macCounters->mTxDataPoll;
- break;
-
- case SPINEL_PROP_CNTR_TX_PKT_BEACON:
- value = macCounters->mTxBeacon;
- break;
-
- case SPINEL_PROP_CNTR_TX_PKT_BEACON_REQ:
- value = macCounters->mTxBeaconRequest;
- break;
-
- case SPINEL_PROP_CNTR_TX_PKT_OTHER:
- value = macCounters->mTxOther;
- break;
-
- case SPINEL_PROP_CNTR_TX_PKT_RETRY:
- value = macCounters->mTxRetry;
- break;
-
- case SPINEL_PROP_CNTR_TX_ERR_CCA:
- value = macCounters->mTxErrCca;
- break;
-
- case SPINEL_PROP_CNTR_TX_PKT_UNICAST:
- value = macCounters->mTxUnicast;
- break;
-
- case SPINEL_PROP_CNTR_TX_PKT_BROADCAST:
- value = macCounters->mTxBroadcast;
- break;
-
- case SPINEL_PROP_CNTR_TX_ERR_ABORT:
- value = macCounters->mTxErrAbort;
- break;
-
- case SPINEL_PROP_CNTR_RX_PKT_TOTAL:
- value = macCounters->mRxTotal;
- break;
-
- case SPINEL_PROP_CNTR_RX_PKT_DATA:
- value = macCounters->mRxData;
- break;
-
- case SPINEL_PROP_CNTR_RX_PKT_DATA_POLL:
- value = macCounters->mRxDataPoll;
- break;
-
- case SPINEL_PROP_CNTR_RX_PKT_BEACON:
- value = macCounters->mRxBeacon;
- break;
-
- case SPINEL_PROP_CNTR_RX_PKT_BEACON_REQ:
- value = macCounters->mRxBeaconRequest;
- break;
-
- case SPINEL_PROP_CNTR_RX_PKT_OTHER:
- value = macCounters->mRxOther;
- break;
-
- case SPINEL_PROP_CNTR_RX_PKT_FILT_WL:
- value = macCounters->mRxWhitelistFiltered;
- break;
-
- case SPINEL_PROP_CNTR_RX_PKT_FILT_DA:
- value = macCounters->mRxDestAddrFiltered;
- break;
-
- case SPINEL_PROP_CNTR_RX_PKT_DUP:
- value = macCounters->mRxDuplicated;
- break;
-
- case SPINEL_PROP_CNTR_RX_PKT_UNICAST:
- value = macCounters->mRxUnicast;
- break;
-
- case SPINEL_PROP_CNTR_RX_PKT_BROADCAST:
- value = macCounters->mRxBroadcast;
- break;
-
- case SPINEL_PROP_CNTR_RX_ERR_EMPTY:
- value = macCounters->mRxErrNoFrame;
- break;
-
- case SPINEL_PROP_CNTR_RX_ERR_UKWN_NBR:
- value = macCounters->mRxErrUnknownNeighbor;
- break;
-
- case SPINEL_PROP_CNTR_RX_ERR_NVLD_SADDR:
- value = macCounters->mRxErrInvalidSrcAddr;
- break;
-
- case SPINEL_PROP_CNTR_RX_ERR_SECURITY:
- value = macCounters->mRxErrSec;
- break;
-
- case SPINEL_PROP_CNTR_RX_ERR_BAD_FCS:
- value = macCounters->mRxErrFcs;
- break;
-
- case SPINEL_PROP_CNTR_RX_ERR_OTHER:
- value = macCounters->mRxErrOther;
- break;
-
- default:
- error = SendLastStatus(aHeader, SPINEL_STATUS_INTERNAL_ERROR);
- ExitNow();
- }
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT32_S,
- value
- );
-
-exit:
- return error;
-}
-
-otError NcpBase::GetPropertyHandler_NCP_CNTR(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- uint32_t value;
- otError error = OT_ERROR_NONE;
-
- switch (aKey)
- {
- case SPINEL_PROP_CNTR_TX_IP_SEC_TOTAL:
- value = mInboundSecureIpFrameCounter;
- break;
-
- case SPINEL_PROP_CNTR_TX_IP_INSEC_TOTAL:
- value = mInboundInsecureIpFrameCounter;
- break;
-
- case SPINEL_PROP_CNTR_TX_IP_DROPPED:
- value = mDroppedInboundIpFrameCounter;
- break;
-
- case SPINEL_PROP_CNTR_RX_IP_SEC_TOTAL:
- value = mOutboundSecureIpFrameCounter;
- break;
-
- case SPINEL_PROP_CNTR_RX_IP_INSEC_TOTAL:
- value = mOutboundInsecureIpFrameCounter;
- break;
-
- case SPINEL_PROP_CNTR_RX_IP_DROPPED:
- value = mDroppedOutboundIpFrameCounter;
- break;
-
- case SPINEL_PROP_CNTR_TX_SPINEL_TOTAL:
- value = mTxSpinelFrameCounter;
- break;
-
- case SPINEL_PROP_CNTR_RX_SPINEL_TOTAL:
- value = mRxSpinelFrameCounter;
- break;
-
- case SPINEL_PROP_CNTR_RX_SPINEL_OUT_OF_ORDER_TID:
- value = mRxSpinelOutOfOrderTidCounter;
- break;
-
- case SPINEL_PROP_CNTR_RX_SPINEL_ERR:
- value = mFramingErrorCounter;
- break;
-
- default:
- error = SendLastStatus(aHeader, SPINEL_STATUS_INTERNAL_ERROR);
- ExitNow();
- }
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT32_S,
- value
- );
-
-exit:
- return error;
-}
-
-otError NcpBase::GetPropertyHandler_IP_CNTR(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- uint32_t value;
- otError error = OT_ERROR_NONE;
-
- const otIpCounters *counters = otThreadGetIp6Counters(mInstance);
-
- switch (aKey)
- {
- case SPINEL_PROP_CNTR_IP_TX_SUCCESS:
- value = counters->mTxSuccess;
- break;
-
- case SPINEL_PROP_CNTR_IP_RX_SUCCESS:
- value = counters->mRxSuccess;
- break;
-
- case SPINEL_PROP_CNTR_IP_TX_FAILURE:
- value = counters->mTxFailure;
- break;
-
- case SPINEL_PROP_CNTR_IP_RX_FAILURE:
- value = counters->mRxFailure;
- break;
-
- default:
- error = SendLastStatus(aHeader, SPINEL_STATUS_INTERNAL_ERROR);
- ExitNow();
- break;
- }
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT32_S,
- value
- );
-
-exit:
- return error;
-}
-
-otError NcpBase::GetPropertyHandler_MSG_BUFFER_COUNTERS(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otError error = OT_ERROR_NONE;
- otBufferInfo bufferInfo;
-
- otMessageGetBufferInfo(mInstance, &bufferInfo);
-
- SuccessOrExit(error = OutboundFrameBegin(aHeader));
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_COMMAND_PROP_S,
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey
- ));
-
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- (
- SPINEL_DATATYPE_UINT16_S // Total buffers
- SPINEL_DATATYPE_UINT16_S // Free buffers
- SPINEL_DATATYPE_UINT16_S // Lowpan send messages
- SPINEL_DATATYPE_UINT16_S // Lowpan send buffers
- SPINEL_DATATYPE_UINT16_S // Lowpan reassembly messages
- SPINEL_DATATYPE_UINT16_S // Lowpan reassembly buffers
- SPINEL_DATATYPE_UINT16_S // Ip6 messages
- SPINEL_DATATYPE_UINT16_S // Ip6 buffers
- SPINEL_DATATYPE_UINT16_S // Mpl messages
- SPINEL_DATATYPE_UINT16_S // Mpl buffers
- SPINEL_DATATYPE_UINT16_S // Mle messages
- SPINEL_DATATYPE_UINT16_S // Mle buffers
- SPINEL_DATATYPE_UINT16_S // Arp messages
- SPINEL_DATATYPE_UINT16_S // Arp buffers
- SPINEL_DATATYPE_UINT16_S // Coap messages
- SPINEL_DATATYPE_UINT16_S // Coap buffers
- ),
- bufferInfo.mTotalBuffers,
- bufferInfo.mFreeBuffers,
- bufferInfo.m6loSendMessages,
- bufferInfo.m6loSendBuffers,
- bufferInfo.m6loReassemblyMessages,
- bufferInfo.m6loReassemblyBuffers,
- bufferInfo.mIp6Messages,
- bufferInfo.mIp6Buffers,
- bufferInfo.mMplMessages,
- bufferInfo.mMplBuffers,
- bufferInfo.mMleMessages,
- bufferInfo.mMleBuffers,
- bufferInfo.mArpMessages,
- bufferInfo.mArpBuffers,
- bufferInfo.mCoapMessages,
- bufferInfo.mCoapBuffers
- ));
-
- SuccessOrExit(error = OutboundFrameSend());
-
-exit:
- return error;
-}
-
-otError NcpBase::GetPropertyHandler_DEBUG_TEST_ASSERT(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- assert(false);
-
- // We only get to this point if `assert(false)`
- // does not cause an NCP reset on the platform.
- // In such a case we return `false` as the
- // property value to indicate this.
-
- OT_UNREACHABLE_CODE(
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_BOOL_S,
- false
- );
- )
-}
-
-otError NcpBase::GetPropertyHandler_DEBUG_NCP_LOG_LEVEL(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- uint8_t logLevel = 0;
-
- switch (otGetDynamicLogLevel(mInstance))
- {
- case OT_LOG_LEVEL_NONE:
- logLevel = SPINEL_NCP_LOG_LEVEL_EMERG;
- break;
-
- case OT_LOG_LEVEL_CRIT:
- logLevel = SPINEL_NCP_LOG_LEVEL_CRIT;
- break;
-
- case OT_LOG_LEVEL_WARN:
- logLevel = SPINEL_NCP_LOG_LEVEL_WARN;
- break;
-
- case OT_LOG_LEVEL_INFO:
- logLevel = SPINEL_NCP_LOG_LEVEL_INFO;
- break;
-
- case OT_LOG_LEVEL_DEBG:
- logLevel = SPINEL_NCP_LOG_LEVEL_DEBUG;
- break;
- }
-
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT8_S,
- logLevel
- );
-}
-
-#if OPENTHREAD_ENABLE_MAC_FILTER
-
-otError NcpBase::GetPropertyHandler_MAC_WHITELIST(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otMacFilterEntry entry;
- otMacFilterIterator iterator = OT_MAC_FILTER_ITERATOR_INIT;
- otError error = OT_ERROR_NONE;
-
- mDisableStreamWrite = true;
-
- SuccessOrExit(error = OutboundFrameBegin(aHeader));
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_COMMAND_PROP_S,
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey
- ));
-
- while (otLinkFilterGetNextAddress(mInstance, &iterator, &entry) == OT_ERROR_NONE)
- {
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_STRUCT_S(
- SPINEL_DATATYPE_EUI64_S // Extended address
- SPINEL_DATATYPE_INT8_S // Rss
- ),
- entry.mExtAddress.m8,
- entry.mRssIn
- ));
- }
-
- SuccessOrExit(error = OutboundFrameSend());
-
-exit:
- mDisableStreamWrite = false;
- return error;
-}
-
-otError NcpBase::GetPropertyHandler_MAC_WHITELIST_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otMacFilterAddressMode mode = otLinkFilterGetAddressMode(mInstance);
- bool isEnabled = (mode == OT_MAC_FILTER_ADDRESS_MODE_WHITELIST) ? true : false;
-
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_BOOL_S,
- isEnabled
- );
-}
-
-otError NcpBase::GetPropertyHandler_MAC_BLACKLIST(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otMacFilterEntry entry;
- otMacFilterIterator iterator = OT_MAC_FILTER_ITERATOR_INIT;
- otError error = OT_ERROR_NONE;
-
- mDisableStreamWrite = true;
-
- SuccessOrExit(error = OutboundFrameBegin(aHeader));
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_COMMAND_PROP_S,
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey
- ));
-
- while (otLinkFilterGetNextAddress(mInstance, &iterator, &entry) == OT_ERROR_NONE)
- {
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_STRUCT_S(
- SPINEL_DATATYPE_EUI64_S // Extended address
- ),
- entry.mExtAddress.m8
- ));
- }
-
- SuccessOrExit(error = OutboundFrameSend());
-
-exit:
- mDisableStreamWrite = false;
- return error;
-}
-
-otError NcpBase::GetPropertyHandler_MAC_BLACKLIST_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otMacFilterAddressMode mode = otLinkFilterGetAddressMode(mInstance);
- bool isEnabled = (mode == OT_MAC_FILTER_ADDRESS_MODE_BLACKLIST) ? true : false;
-
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_BOOL_S,
- isEnabled
- );
-}
-
-otError NcpBase::GetPropertyHandler_MAC_FIXED_RSS(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- otMacFilterEntry entry;
- otMacFilterIterator iterator = OT_MAC_FILTER_ITERATOR_INIT;
- otError error = OT_ERROR_NONE;
-
- mDisableStreamWrite = true;
-
- SuccessOrExit(error = OutboundFrameBegin(aHeader));
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_COMMAND_PROP_S,
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey
- ));
-
- while (otLinkFilterGetNextRssIn(mInstance, &iterator, &entry) == OT_ERROR_NONE)
- {
- SuccessOrExit(
- error = OutboundFrameFeedPacked(
- SPINEL_DATATYPE_STRUCT_S(
- SPINEL_DATATYPE_EUI64_S // Extended address
- SPINEL_DATATYPE_INT8_S // Rss
- ),
- entry.mExtAddress.m8,
- entry.mRssIn
- ));
- }
-
- SuccessOrExit(error = OutboundFrameSend());
-
-exit:
- mDisableStreamWrite = false;
- return error;
-}
-
-#endif // OPENTHREAD_ENABLE_MAC_FILTER
-
-#if OPENTHREAD_FTD
-otError NcpBase::GetPropertyHandler_NET_PSKC(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_DATA_S,
- otThreadGetPSKc(mInstance),
- sizeof(spinel_net_pskc_t)
- );
-}
-#endif // OPENTHREAD_FTD
-
-otError NcpBase::GetPropertyHandler_THREAD_MODE(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- uint8_t numericMode;
- otLinkModeConfig modeConfig = otThreadGetLinkMode(mInstance);
-
- numericMode = LinkFlagsToFlagByte(
- modeConfig.mRxOnWhenIdle,
- modeConfig.mSecureDataRequests,
- modeConfig.mDeviceType,
- modeConfig.mNetworkData
- );
-
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT8_S,
- numericMode
- );
-}
-
-#if OPENTHREAD_FTD
-otError NcpBase::GetPropertyHandler_THREAD_CHILD_COUNT_MAX(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT8_S,
- otThreadGetMaxAllowedChildren(mInstance)
- );
-}
-#endif // OPENTHREAD_FTD
-
-otError NcpBase::GetPropertyHandler_THREAD_CHILD_TIMEOUT(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT32_S,
- otThreadGetChildTimeout(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_THREAD_RLOC16(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT16_S,
- otThreadGetRloc16(mInstance)
- );
-}
-
-#if OPENTHREAD_FTD
-otError NcpBase::GetPropertyHandler_THREAD_ROUTER_UPGRADE_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT8_S,
- otThreadGetRouterUpgradeThreshold(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_THREAD_ROUTER_DOWNGRADE_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT8_S,
- otThreadGetRouterDowngradeThreshold(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_THREAD_ROUTER_SELECTION_JITTER(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT8_S,
- otThreadGetRouterSelectionJitter(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_THREAD_CONTEXT_REUSE_DELAY(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT32_S,
- otThreadGetContextIdReuseDelay(mInstance)
- );
-}
-
-otError NcpBase::GetPropertyHandler_THREAD_NETWORK_ID_TIMEOUT(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT8_S,
- otThreadGetNetworkIdTimeout(mInstance)
- );
-}
-#endif // OPENTHREAD_FTD
-
-#if OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
-otError NcpBase::GetPropertyHandler_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- bool enabled = false;
-
- if (otCommissionerGetState(mInstance) == OT_COMMISSIONER_STATE_ACTIVE)
- {
- enabled = true;
- }
-
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_BOOL_S,
- enabled
- );
-}
-#endif
-
-otError NcpBase::GetPropertyHandler_NET_REQUIRE_JOIN_EXISTING(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_BOOL_S,
- mRequireJoinExistingNetwork
- );
-}
-
-#if OPENTHREAD_ENABLE_LEGACY
-otError NcpBase::GetPropertyHandler_NEST_LEGACY_ULA_PREFIX(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_DATA_S,
- mLegacyUlaPrefix,
- sizeof(mLegacyUlaPrefix)
- );
-}
-
-otError NcpBase::GetPropertyHandler_NEST_LEGACY_LAST_NODE_JOINED(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- if (!mLegacyNodeDidJoin)
- {
- memset(&mLegacyLastJoinedNode, 0, sizeof(mLegacyLastJoinedNode));
- }
-
- return SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_EUI64_S,
- &mLegacyLastJoinedNode,
- sizeof(mLegacyLastJoinedNode)
- );
-}
-#endif // OPENTHREAD_ENABLE_LEGACY
-
-// ----------------------------------------------------------------------------
-// MARK: Individual Property Setters
-// ----------------------------------------------------------------------------
-
-otError NcpBase::SendSetPropertyResponse(uint8_t aHeader, spinel_prop_key_t aKey, otError aError)
-{
- if (aError == OT_ERROR_NONE)
- {
- aError = HandleCommandPropertyGet(aHeader, aKey);
- }
- else
- {
- aError = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(aError));
- }
-
- return aError;
-}
-
-otError NcpBase::SetPropertyHandler_POWER_STATE(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- // TODO: Implement POWER_STATE
- OT_UNUSED_VARIABLE(aKey);
- OT_UNUSED_VARIABLE(aValuePtr);
- OT_UNUSED_VARIABLE(aValueLen);
-
- return SendLastStatus(aHeader, SPINEL_STATUS_UNIMPLEMENTED);
-}
-
otError NcpBase::SetPropertyHandler_HOST_POWER_STATE(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
uint16_t aValueLen)
{
@@ -4631,95 +2108,58 @@ otError NcpBase::SetPropertyHandler_HOST_POWER_STATE(uint8_t aHeader, spinel_pro
return error;
}
-otError NcpBase::SetPropertyHandler_UNSOL_UPDATE_FILTER(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::GetPropertyHandler_UNSOL_UPDATE_LIST(uint8_t aHeader, spinel_prop_key_t aKey)
{
- spinel_ssize_t parsedLength;
- unsigned int propKey;
otError error = OT_ERROR_NONE;
- bool reportAsync;
+ uint8_t numEntries;
+ const ChangedPropsSet::Entry *entry;
- // First clear the current filter.
- mChangedPropsSet.ClearFilter();
+ SuccessOrExit(error = OutboundFrameBegin(aHeader));
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_COMMAND_PROP_S,
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey
+ ));
- while (aValueLen > 0)
+ entry = mChangedPropsSet.GetSupportedEntries(numEntries);
+
+ for (uint8_t index = 0; index < numEntries; index++, entry++)
{
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT_PACKED_S,
- &propKey
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- IgnoreReturnValue(mChangedPropsSet.EnablePropertyFilter(static_cast(propKey), true));
-
- aValuePtr += parsedLength;
- aValueLen -= parsedLength;
+ if (entry->mFilterable)
+ {
+ SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, entry->mPropKey));
+ }
}
+ SuccessOrExit(error = OutboundFrameSend());
+
exit:
- // If we had an error, we may have actually changed
- // the state of the filter---so we need to report
- // those incomplete changes via an asynchronous
- // change event.
- reportAsync = (error != OT_ERROR_NONE);
-
- error = SendSetPropertyResponse(aHeader, aKey, error);
-
- if (reportAsync)
- {
- HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, aKey);
- }
-
return error;
}
-#if OPENTHREAD_ENABLE_RAW_LINK_API
-
-otError NcpBase::SetPropertyHandler_PHY_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::GetPropertyHandler_PHY_RX_SENSITIVITY(uint8_t aHeader, spinel_prop_key_t aKey)
{
- bool value = false;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &value
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- if (value == false)
- {
- // If we have raw stream enabled stop receiving
- if (mIsRawStreamEnabled)
- {
- otLinkRawSleep(mInstance);
- }
-
- error = otLinkRawSetEnable(mInstance, false);
- }
- else
- {
- error = otLinkRawSetEnable(mInstance, true);
-
- // If we have raw stream enabled already, start receiving
- if (error == OT_ERROR_NONE && mIsRawStreamEnabled)
- {
- error = otLinkRawReceive(mInstance, mCurReceiveChannel, &NcpBase::LinkRawReceiveDone);
- }
- }
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_INT8_S,
+ otPlatRadioGetReceiveSensitivity(mInstance)
+ );
}
-#endif // OPENTHREAD_ENABLE_RAW_LINK_API
+otError NcpBase::GetPropertyHandler_PHY_TX_POWER(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_INT8_S,
+ otLinkGetMaxTransmitPower(mInstance)
+ );
+}
otError NcpBase::SetPropertyHandler_PHY_TX_POWER(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
uint16_t aValueLen)
@@ -4743,1857 +2183,62 @@ exit:
return SendSetPropertyResponse(aHeader, aKey, error);
}
-otError NcpBase::SetPropertyHandler_PHY_CHAN(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::GetPropertyHandler_DEBUG_TEST_ASSERT(uint8_t aHeader, spinel_prop_key_t aKey)
{
- unsigned int channel = 0;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
+ assert(false);
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT_PACKED_S,
- &channel
- );
+ // We only get to this point if `assert(false)`
+ // does not cause an NCP reset on the platform.
+ // In such a case we return `false` as the
+ // property value to indicate this.
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- error = otLinkSetChannel(mInstance, static_cast(channel));
-
-#if OPENTHREAD_ENABLE_RAW_LINK_API
-
- SuccessOrExit(error);
-
- // Cache the channel. If the raw link layer isn't enabled yet, the otSetChannel call
- // doesn't call into the radio layer to set the channel. We will have to do it
- // manually whenever the radios are enabled and/or raw stream is enabled.
- mCurReceiveChannel = static_cast(channel);
-
- // Make sure we are update the receiving channel if raw link is enabled and we have raw
- // stream enabled already
- if (otLinkRawIsEnabled(mInstance) && mIsRawStreamEnabled)
- {
- error = otLinkRawReceive(mInstance, mCurReceiveChannel, &NcpBase::LinkRawReceiveDone);
- }
-
-#endif // OPENTHREAD_ENABLE_RAW_LINK_API
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ OT_UNREACHABLE_CODE(
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_BOOL_S,
+ false
+ );
+ )
}
-otError NcpBase::SetPropertyHandler_MAC_PROMISCUOUS_MODE(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::GetPropertyHandler_DEBUG_NCP_LOG_LEVEL(uint8_t aHeader, spinel_prop_key_t aKey)
{
- uint8_t mode = 0;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
+ uint8_t logLevel = 0;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &mode
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- switch (mode)
+ switch (otGetDynamicLogLevel(mInstance))
{
- case SPINEL_MAC_PROMISCUOUS_MODE_OFF:
- otPlatRadioSetPromiscuous(mInstance, false);
+ case OT_LOG_LEVEL_NONE:
+ logLevel = SPINEL_NCP_LOG_LEVEL_EMERG;
break;
- case SPINEL_MAC_PROMISCUOUS_MODE_NETWORK:
- case SPINEL_MAC_PROMISCUOUS_MODE_FULL:
- otPlatRadioSetPromiscuous(mInstance, true);
+ case OT_LOG_LEVEL_CRIT:
+ logLevel = SPINEL_NCP_LOG_LEVEL_CRIT;
break;
- default:
- error = OT_ERROR_INVALID_ARGS;
+ case OT_LOG_LEVEL_WARN:
+ logLevel = SPINEL_NCP_LOG_LEVEL_WARN;
+ break;
+
+ case OT_LOG_LEVEL_INFO:
+ logLevel = SPINEL_NCP_LOG_LEVEL_INFO;
+ break;
+
+ case OT_LOG_LEVEL_DEBG:
+ logLevel = SPINEL_NCP_LOG_LEVEL_DEBUG;
break;
}
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT8_S,
+ logLevel
+ );
}
-otError NcpBase::SetPropertyHandler_MAC_SCAN_MASK(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- uint32_t newMask = 0;
- otError error = OT_ERROR_NONE;
-
- for (; aValueLen != 0; aValueLen--, aValuePtr++)
- {
- VerifyOrExit(aValuePtr[0] <= 31, error = OT_ERROR_INVALID_ARGS);
- VerifyOrExit((mSupportedChannelMask & (1 << aValuePtr[0])) != 0, error = OT_ERROR_INVALID_ARGS);
-
- newMask |= (1 << aValuePtr[0]);
- }
-
- mChannelMask = newMask;
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_MAC_SCAN_PERIOD(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- uint16_t period = mScanPeriod;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT16_S,
- &period
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- mScanPeriod = period;
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_NET_REQUIRE_JOIN_EXISTING(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- bool value = mRequireJoinExistingNetwork;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &value
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- mRequireJoinExistingNetwork = value;
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-static bool HasOnly1BitSet(uint32_t aValue)
-{
- return aValue != 0 && ((aValue & (aValue - 1)) == 0);
-}
-
-static uint8_t IndexOfMSB(uint32_t aValue)
-{
- uint8_t index = 0;
-
- while (aValue >>= 1)
- {
- index++;
- }
-
- return index;
-}
-
-otError NcpBase::SetPropertyHandler_MAC_SCAN_STATE(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- uint8_t state = 0;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &state
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- switch (state)
- {
- case SPINEL_SCAN_STATE_IDLE:
- error = OT_ERROR_NONE;
- break;
-
- case SPINEL_SCAN_STATE_BEACON:
-#if OPENTHREAD_ENABLE_RAW_LINK_API
- if (otLinkRawIsEnabled(mInstance))
- {
- error = OT_ERROR_NOT_IMPLEMENTED;
- }
- else
-#endif // OPENTHREAD_ENABLE_RAW_LINK_API
- {
- error = otLinkActiveScan(
- mInstance,
- mChannelMask,
- mScanPeriod,
- &HandleActiveScanResult_Jump,
- this
- );
- }
-
- SuccessOrExit(error);
- break;
-
- case SPINEL_SCAN_STATE_ENERGY:
-#if OPENTHREAD_ENABLE_RAW_LINK_API
- if (otLinkRawIsEnabled(mInstance))
- {
- uint8_t scanChannel;
-
- // Make sure we aren't already scanning and that we have
- // only 1 bit set for the channel mask.
- VerifyOrExit(mCurScanChannel == NCP_INVALID_SCAN_CHANNEL, error = OT_ERROR_INVALID_STATE);
- VerifyOrExit(HasOnly1BitSet(mChannelMask), error = OT_ERROR_INVALID_ARGS);
-
- scanChannel = IndexOfMSB(mChannelMask);
- mCurScanChannel = (int8_t)scanChannel;
-
- error = otLinkRawEnergyScan(
- mInstance,
- scanChannel,
- mScanPeriod,
- LinkRawEnergyScanDone
- );
- }
- else
-#endif // OPENTHREAD_ENABLE_RAW_LINK_API
- {
- error = otLinkEnergyScan(
- mInstance,
- mChannelMask,
- mScanPeriod,
- &HandleEnergyScanResult_Jump,
- this
- );
- }
-
- SuccessOrExit(error);
- break;
-
- case SPINEL_SCAN_STATE_DISCOVER:
- error = otThreadDiscover(
- mInstance,
- mChannelMask,
- mDiscoveryScanPanId,
- mDiscoveryScanJoinerFlag,
- mDiscoveryScanEnableFiltering,
- &HandleActiveScanResult_Jump,
- this
- );
-
- SuccessOrExit(error);
- break;
-
- default:
- error = OT_ERROR_INVALID_ARGS;
- break;
- }
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_MAC_15_4_PANID(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- uint16_t panid;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT16_S,
- &panid
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- error = otLinkSetPanId(mInstance, panid);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_MAC_15_4_LADDR(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- otExtAddress *extAddress;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_EUI64_S,
- &extAddress
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- error = otLinkSetExtendedAddress(mInstance, extAddress);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_MAC_DATA_POLL_PERIOD(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- uint32_t pollPeriod;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT32_S,
- &pollPeriod
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- otLinkSetPollPeriod(mInstance, pollPeriod);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_MAC_RAW_STREAM_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- bool value = false;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &value
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
-#if OPENTHREAD_ENABLE_RAW_LINK_API
-
- if (otLinkRawIsEnabled(mInstance))
- {
- if (value)
- {
- error = otLinkRawReceive(mInstance, mCurReceiveChannel, &NcpBase::LinkRawReceiveDone);
- }
- else
- {
- error = otLinkRawSleep(mInstance);
- }
- }
-
-#endif // OPENTHREAD_ENABLE_RAW_LINK_API
-
- mIsRawStreamEnabled = value;
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-#if OPENTHREAD_ENABLE_RAW_LINK_API
-
-otError NcpBase::SetPropertyHandler_MAC_15_4_SADDR(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- uint16_t shortAddress;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT16_S,
- &shortAddress
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- error = otLinkRawSetShortAddress(mInstance, shortAddress);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_STREAM_RAW(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- uint8_t *frame_buffer = NULL;
- otRadioFrame *frame;
- unsigned int frameLen = 0;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- VerifyOrExit(otLinkRawIsEnabled(mInstance), error = OT_ERROR_INVALID_STATE);
-
- frame = otLinkRawGetTransmitBuffer(mInstance);
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_DATA_WLEN_S
- SPINEL_DATATYPE_UINT8_S
- SPINEL_DATATYPE_INT8_S,
- &frame_buffer,
- &frameLen,
- &frame->mChannel,
- &frame->mPower
- );
-
- VerifyOrExit(parsedLength > 0 && frameLen <= OT_RADIO_FRAME_MAX_SIZE, error = OT_ERROR_PARSE);
-
- // Cache the transaction ID for async response
- mCurTransmitTID = SPINEL_HEADER_GET_TID(aHeader);
-
- // Update frame buffer and length
- frame->mLength = static_cast(frameLen);
- memcpy(frame->mPsdu, frame_buffer, frame->mLength);
-
- // TODO: This should be later added in the STREAM_RAW argument to allow user to directly specify it.
- frame->mMaxTxAttempts = OPENTHREAD_CONFIG_MAX_TX_ATTEMPTS_DIRECT;
-
- // Pass frame to the radio layer. Note, this fails if we
- // haven't enabled raw stream or are already transmitting.
- error = otLinkRawTransmit(mInstance, frame, &NcpBase::LinkRawTransmitDone);
-
-exit:
-
- if (error == OT_ERROR_NONE)
- {
- // Don't do anything here yet. We will complete the transaction when we get a transmit done callback
- }
- else
- {
- error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
- }
-
- OT_UNUSED_VARIABLE(aKey);
-
- return error;
-}
-
-#endif // OPENTHREAD_ENABLE_RAW_LINK_API
-
-otError NcpBase::SetPropertyHandler_NET_IF_UP(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- bool enabled = false;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &enabled
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- error = otIp6SetEnabled(mInstance, enabled);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_NET_STACK_UP(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- bool enabled = false;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &enabled
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- // If the value has changed...
- if ((enabled != false) != (otThreadGetDeviceRole(mInstance) != OT_DEVICE_ROLE_DISABLED))
- {
- if (enabled != false)
- {
- error = otThreadSetEnabled(mInstance, true);
-
-#if OPENTHREAD_ENABLE_LEGACY
- mLegacyNodeDidJoin = false;
-
- if ((mLegacyHandlers != NULL) && (mLegacyHandlers->mStartLegacy != NULL))
- {
- mLegacyHandlers->mStartLegacy();
- }
-#endif // OPENTHREAD_ENABLE_LEGACY
- }
- else
- {
- error = otThreadSetEnabled(mInstance, false);
-
-#if OPENTHREAD_ENABLE_LEGACY
- mLegacyNodeDidJoin = false;
-
- if ((mLegacyHandlers != NULL) && (mLegacyHandlers->mStopLegacy != NULL))
- {
- mLegacyHandlers->mStopLegacy();
- }
-#endif // OPENTHREAD_ENABLE_LEGACY
- }
- }
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_NET_ROLE(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- unsigned int role = 0;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT_PACKED_S,
- &role
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
-
- switch (role)
- {
- case SPINEL_NET_ROLE_DETACHED:
- error = otThreadBecomeDetached(mInstance);
- break;
-
-#if OPENTHREAD_FTD
- case SPINEL_NET_ROLE_ROUTER:
- error = otThreadBecomeRouter(mInstance);
- break;
-
- case SPINEL_NET_ROLE_LEADER:
- error = otThreadBecomeLeader(mInstance);
- break;
-#endif // OPENTHREAD_FTD
-
- case SPINEL_NET_ROLE_CHILD:
- error = otThreadBecomeChild(mInstance);
- break;
- }
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_NET_NETWORK_NAME(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- const char *string = NULL;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UTF8_S,
- &string
- );
-
- VerifyOrExit((parsedLength > 0) && (string != NULL), error = OT_ERROR_PARSE);
-
- error = otThreadSetNetworkName(mInstance, string);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_NET_XPANID(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- const uint8_t *ptr = NULL;
- spinel_size_t len;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_DATA_S,
- &ptr,
- &len
- );
-
- VerifyOrExit((parsedLength > 0) && (len == sizeof(spinel_net_xpanid_t)), error = OT_ERROR_PARSE);
-
- error = otThreadSetExtendedPanId(mInstance, ptr);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_NET_MASTER_KEY(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- const uint8_t *ptr = NULL;
- spinel_size_t len;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_DATA_S,
- &ptr,
- &len
- );
-
- VerifyOrExit((parsedLength > 0) && (len == OT_MASTER_KEY_SIZE), error = OT_ERROR_PARSE);
-
- error = otThreadSetMasterKey(mInstance, reinterpret_cast(ptr));
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_NET_KEY_SEQUENCE_COUNTER(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- unsigned int keySeqCounter;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT32_S,
- &keySeqCounter
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- otThreadSetKeySequenceCounter(mInstance, keySeqCounter);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_NET_KEY_SWITCH_GUARDTIME(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- unsigned int keyGuardTime;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT32_S,
- &keyGuardTime
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- otThreadSetKeySwitchGuardTime(mInstance, keyGuardTime);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-#if OPENTHREAD_FTD
-otError NcpBase::SetPropertyHandler_THREAD_LOCAL_LEADER_WEIGHT(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- uint8_t weight;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &weight
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- otThreadSetLocalLeaderWeight(mInstance, weight);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-#endif // OPENTHREAD_FTD
-
-otError NcpBase::SetPropertyHandler_STREAM_NET_INSECURE(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- const uint8_t *framePtr = NULL;
- unsigned int frameLen = 0;
- const uint8_t *metaPtr = NULL;
- unsigned int metaLen = 0;
- otMessage *message;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- // STREAM_NET_INSECURE packets are not secured at layer 2.
- message = otIp6NewMessage(mInstance, false);
- VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS);
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- (
- SPINEL_DATATYPE_DATA_WLEN_S // Frame data
- SPINEL_DATATYPE_DATA_S // Meta data
- ),
- &framePtr,
- &frameLen,
- &metaPtr,
- &metaLen
- );
-
- // We ignore metadata for now.
- // May later include TX power, allow retransmits, etc...
- OT_UNUSED_VARIABLE(metaPtr);
- OT_UNUSED_VARIABLE(metaLen);
- OT_UNUSED_VARIABLE(parsedLength);
-
- SuccessOrExit(error = otMessageAppend(message, framePtr, static_cast(frameLen)));
-
- // Ensure the insecure message is forwarded using direct transmission.
- otMessageSetDirectTransmission(message, true);
-
- error = otIp6Send(mInstance, message);
-
- // `otIp6Send()` takes ownership of `message` (in both success or
- // failure cases). `message` is set to NULL so it is not freed at
- // exit.
- message = NULL;
-
-exit:
- if (message != NULL)
- {
- otMessageFree(message);
- }
-
- if (error == OT_ERROR_NONE)
- {
- mInboundInsecureIpFrameCounter++;
-
- if (SPINEL_HEADER_GET_TID(aHeader) != 0)
- {
- // Only send a successful status update if
- // there was a transaction id in the aHeader.
- error = SendLastStatus(aHeader, SPINEL_STATUS_OK);
- }
- }
- else
- {
- mDroppedInboundIpFrameCounter++;
-
- error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
- }
-
- OT_UNUSED_VARIABLE(aKey);
-
- return error;
-}
-
-#if OPENTHREAD_ENABLE_TMF_PROXY && OPENTHREAD_FTD
-otError NcpBase::SetPropertyHandler_THREAD_TMF_PROXY_STREAM(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- const uint8_t *framePtr = NULL;
- unsigned int frameLen = 0;
- uint16_t locator;
- uint16_t port;
- otMessage *message;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- // THREAD_TMF_PROXY_STREAM requires layer 2 security.
- message = otIp6NewMessage(mInstance, true);
- VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS);
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- (
- SPINEL_DATATYPE_DATA_WLEN_S // Frame data
- SPINEL_DATATYPE_UINT16_S // Locator
- SPINEL_DATATYPE_UINT16_S // Port
- ),
- &framePtr,
- &frameLen,
- &locator,
- &port
- );
-
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- SuccessOrExit(error = otMessageAppend(message, framePtr, static_cast(frameLen)));
-
- error = otTmfProxySend(mInstance, message, locator, port);
-
- // `otTmfProxySend()` takes ownership of `message` (in both success
- // or failure cases). `message` is set to NULL so it is not freed at
- // exit.
- message = NULL;
-
-exit:
- if (message != NULL)
- {
- otMessageFree(message);
- }
-
- if (error == OT_ERROR_NONE)
- {
- if (SPINEL_HEADER_GET_TID(aHeader) != 0)
- {
- // Only send a successful status update if
- // there was a transaction id in the aHeader.
- error = SendLastStatus(aHeader, SPINEL_STATUS_OK);
- }
- }
- else
- {
- error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
- }
-
- OT_UNUSED_VARIABLE(aKey);
-
- return error;
-}
-#endif // OPENTHREAD_ENABLE_TMF_PROXY && OPENTHREAD_FTD
-
-otError NcpBase::SetPropertyHandler_STREAM_NET(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- const uint8_t *framePtr = NULL;
- unsigned int frameLen = 0;
- const uint8_t *metaPtr = NULL;
- unsigned int metaLen = 0;
- otMessage *message;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- // STREAM_NET requires layer 2 security.
- message = otIp6NewMessage(mInstance, true);
- VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS);
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- (
- SPINEL_DATATYPE_DATA_WLEN_S // Frame data
- SPINEL_DATATYPE_DATA_S // Meta data
- ),
- &framePtr,
- &frameLen,
- &metaPtr,
- &metaLen
- );
-
- // We ignore metadata for now.
- // May later include TX power, allow retransmits, etc...
- OT_UNUSED_VARIABLE(metaPtr);
- OT_UNUSED_VARIABLE(metaLen);
- OT_UNUSED_VARIABLE(parsedLength);
-
- SuccessOrExit(error = otMessageAppend(message, framePtr, static_cast(frameLen)));
-
- error = otIp6Send(mInstance, message);
-
- // `otIp6Send()` takes ownership of `message` (in both success or
- // failure cases). `message` is set to NULL so it is not freed at
- // exit.
- message = NULL;
-
-exit:
-
- if (message != NULL)
- {
- otMessageFree(message);
- }
-
- if (error == OT_ERROR_NONE)
- {
- mInboundSecureIpFrameCounter++;
-
- if (SPINEL_HEADER_GET_TID(aHeader) != 0)
- {
- // Only send a successful status update if
- // there was a transaction id in the aHeader.
- error = SendLastStatus(aHeader, SPINEL_STATUS_OK);
- }
- }
- else
- {
- mDroppedInboundIpFrameCounter++;
-
- error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
- }
-
- OT_UNUSED_VARIABLE(aKey);
-
- return error;
-}
-
-otError NcpBase::SetPropertyHandler_IPV6_ML_PREFIX(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- otError error = OT_ERROR_NONE;
-
- VerifyOrExit(aValueLen >= 8, error = OT_ERROR_PARSE);
-
- error = otThreadSetMeshLocalPrefix(mInstance, aValuePtr);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_IPV6_ICMP_PING_OFFLOAD(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- bool enabled = false;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &enabled
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- otIcmp6SetEchoEnabled(mInstance, enabled);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_THREAD_RLOC16_DEBUG_PASSTHRU(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- bool enabled = false;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &enabled
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- // Note reverse logic: passthru enabled = filter disabled
- otIp6SetReceiveFilterEnabled(mInstance, !enabled);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_THREAD_DISCOVERY_SCAN_JOINER_FLAG(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- bool joinerFlag = false;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &joinerFlag
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- mDiscoveryScanJoinerFlag = joinerFlag;
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_THREAD_DISCOVERY_SCAN_ENABLE_FILTERING(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- bool enabled = false;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &enabled
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- mDiscoveryScanEnableFiltering = enabled;
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_THREAD_DISCOVERY_SCAN_PANID(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- uint16_t panid;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT16_S,
- &panid
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- mDiscoveryScanPanId = panid;
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_THREAD_ASSISTING_PORTS(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- uint8_t numEntries = 0;
- const uint16_t *ports = otIp6GetUnsecurePorts(mInstance, &numEntries);
- spinel_ssize_t parsedLength;
- bool portsChanged = false;
- otError error = OT_ERROR_NONE;
-
- // First, we need to remove all of the current assisting ports.
- for (; numEntries != 0; ports++, numEntries--)
- {
- SuccessOrExit(error = otIp6RemoveUnsecurePort(mInstance, *ports));
- portsChanged = true;
- }
-
- while (aValueLen >= 2)
- {
- uint16_t port;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT16_S,
- &port
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- SuccessOrExit(error = otIp6AddUnsecurePort(mInstance, port));
-
- aValuePtr += parsedLength;
- aValueLen -= parsedLength;
-
- portsChanged = true;
- }
-
- // No error happened so the new state of ports will
- // be reported in the response.
- portsChanged = false;
-
-exit:
- error = SendSetPropertyResponse(aHeader, aKey, error);
-
- if (portsChanged)
- {
- // We had an error, but we've actually changed
- // the state of these ports---so we need to report
- // those incomplete changes via an asynchronous
- // change event.
- HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, aKey);
- }
-
- return error;
-}
-
-#if OPENTHREAD_ENABLE_BORDER_ROUTER
-otError NcpBase::SetPropertyHandler_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- bool value = false;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- bool shouldRegisterWithLeader = false;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &value
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- // Register any net data changes on transition from `true` to `false`.
- shouldRegisterWithLeader = (mAllowLocalNetworkDataChange == true) && (value == false);
-
- mAllowLocalNetworkDataChange = value;
-
-exit:
- error = SendSetPropertyResponse(aHeader, aKey, error);
-
- if (shouldRegisterWithLeader)
- {
- otBorderRouterRegister(mInstance);
- }
-
- return error;
-}
-#endif // OPENTHREAD_ENABLE_BORDER_ROUTER
-
-#if OPENTHREAD_FTD
-otError NcpBase::SetPropertyHandler_THREAD_ROUTER_ROLE_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- bool enabled;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &enabled
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- otThreadSetRouterRoleEnabled(mInstance, enabled);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-#if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB
-otError NcpBase::SetPropertyHandler_THREAD_STEERING_DATA(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- otExtAddress *extAddress;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_EUI64_S,
- &extAddress
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- error = otThreadSetSteeringData(mInstance, extAddress);
-
-exit:
-
- if (error == OT_ERROR_NONE)
- {
- // Note that there is no get handler for this property.
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_EUI64_S,
- extAddress->m8
- );
- }
- else
- {
- error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
- }
-
- return error;
-}
-#endif // #if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB
-#endif // #if OPENTHREAD_FTD
-
-otError NcpBase::SetPropertyHandler_CNTR_RESET(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- uint8_t value = 0;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &value
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- VerifyOrExit(value == 1, error = OT_ERROR_INVALID_ARGS);
-
- // TODO: Implement counter reset!
- error = OT_ERROR_NOT_IMPLEMENTED;
-
-exit:
- OT_UNUSED_VARIABLE(aKey);
-
- // There is currently no getter for PROP_CNTR_RESET, so we just
- // return SPINEL_STATUS_OK for success when the counters are reset.
-
- return SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
-}
-
-#if OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
-
-otError NcpBase::SetPropertyHandler_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- bool enabled = false;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &enabled
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- if (enabled == false)
- {
- error = otCommissionerStop(mInstance);
- }
- else
- {
- error = otCommissionerStart(mInstance);
- }
-
-exit:
- OT_UNUSED_VARIABLE(aKey);
-
- return SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
-}
-
-#endif // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
-
-#if OPENTHREAD_ENABLE_MAC_FILTER
-
-otError NcpBase::SetPropertyHandler_MAC_WHITELIST(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- bool reportAsync;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- // First, clear the address filter entries.
- otLinkFilterClearAddresses(mInstance);
-
- while (aValueLen > 0)
- {
- otExtAddress *extAddress = NULL;
- int8_t rss;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_STRUCT_S(
- SPINEL_DATATYPE_EUI64_S
- SPINEL_DATATYPE_INT8_S
- ),
- &extAddress,
- &rss
- );
-
- if (parsedLength <= 0)
- {
- rss = OT_MAC_FILTER_FIXED_RSS_DISABLED;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_STRUCT_S(
- SPINEL_DATATYPE_EUI64_S
- ),
- &extAddress
- );
- }
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- error = otLinkFilterAddAddress(mInstance, extAddress);
-
- VerifyOrExit(error == OT_ERROR_NONE || error == OT_ERROR_ALREADY);
-
- if (rss != OT_MAC_FILTER_FIXED_RSS_DISABLED)
- {
- SuccessOrExit(error = otLinkFilterAddRssIn(mInstance, extAddress, rss));
- }
-
- aValuePtr += parsedLength;
- aValueLen -= parsedLength;
- }
-
-exit:
- // If we had an error, we may have actually changed
- // the state of the whitelist---so we need to report
- // those incomplete changes via an asynchronous
- // change event.
- reportAsync = (error != OT_ERROR_NONE && error != OT_ERROR_ALREADY);
-
- error = SendSetPropertyResponse(aHeader, aKey, error);
-
- if (reportAsync)
- {
- HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, aKey);
- }
-
- return error;
-}
-
-otError NcpBase::SetPropertyHandler_MAC_WHITELIST_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- bool enabled;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- otMacFilterAddressMode mode = OT_MAC_FILTER_ADDRESS_MODE_DISABLED;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &enabled
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- if (enabled)
- {
- mode = OT_MAC_FILTER_ADDRESS_MODE_WHITELIST;
- }
-
- error = otLinkFilterSetAddressMode(mInstance, mode);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_MAC_BLACKLIST(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- bool reportAsync;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- // First, clear the address filter entries.
- otLinkFilterClearAddresses(mInstance);
-
- while (aValueLen > 0)
- {
- otExtAddress *extAddress = NULL;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_STRUCT_S(
- SPINEL_DATATYPE_EUI64_S
- ),
- &extAddress
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- error = otLinkFilterRemoveAddress(mInstance, extAddress);
-
- VerifyOrExit(error == OT_ERROR_NONE || error == OT_ERROR_ALREADY);
-
- aValuePtr += parsedLength;
- aValueLen -= parsedLength;
- }
-
-exit:
- // If we had an error, we may have actually changed
- // the state of the blacklist---so we need to report
- // those incomplete changes via an asynchronous
- // change event.
- reportAsync = (error != OT_ERROR_NONE && error != OT_ERROR_ALREADY);
-
- error = SendSetPropertyResponse(aHeader, aKey, error);
-
- if (reportAsync)
- {
- HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, aKey);
- }
-
- return error;
-}
-
-otError NcpBase::SetPropertyHandler_MAC_BLACKLIST_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- bool enabled;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- otMacFilterAddressMode mode = OT_MAC_FILTER_ADDRESS_MODE_DISABLED;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &enabled
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- if (enabled)
- {
- mode = OT_MAC_FILTER_ADDRESS_MODE_BLACKLIST;
- }
-
- error = otLinkFilterSetAddressMode(mInstance, mode);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_MAC_FIXED_RSS(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- bool reportAsync;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- // First, clear the address filter entries.
- otLinkFilterClearRssIn(mInstance);
-
- while (aValueLen > 0)
- {
- otExtAddress *extAddress;
- int8_t rss;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_STRUCT_S(
- SPINEL_DATATYPE_EUI64_S
- SPINEL_DATATYPE_INT8_S
- ),
- &extAddress,
- &rss
- );
-
- if (parsedLength < 0)
- {
- extAddress = NULL;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_STRUCT_S(
- SPINEL_DATATYPE_INT8_S
- ),
- &rss
- );
- }
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- SuccessOrExit(error = otLinkFilterAddRssIn(mInstance, extAddress, rss));
-
- aValuePtr += parsedLength;
- aValueLen -= parsedLength;
- }
-
-exit:
- // If we had an error, we may have actually changed
- // the state of the RssIn filter---so we need to report
- // those incomplete changes via an asynchronous
- // change event.
- reportAsync = (error != OT_ERROR_NONE);
-
- error = SendSetPropertyResponse(aHeader, aKey, error);
-
- if (reportAsync)
- {
- HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, aKey);
- }
-
- return error;
-}
-
-#endif // OPENTHREAD_ENABLE_MAC_FILTER
-
-#if OPENTHREAD_ENABLE_RAW_LINK_API
-
-otError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- bool enabled;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &enabled
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- error = otLinkRawSrcMatchEnable(mInstance, enabled);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- const uint8_t *data = aValuePtr;
- uint16_t dataLen = aValueLen;
-
- // Clear the list first
- error = otLinkRawSrcMatchClearShortEntries(mInstance);
-
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- // Loop through the addresses and add them
- while (dataLen >= sizeof(uint16_t))
- {
- spinel_ssize_t parsedLength;
- uint16_t short_address;
-
- parsedLength = spinel_datatype_unpack(
- data,
- dataLen,
- SPINEL_DATATYPE_UINT16_S,
- &short_address
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- data += parsedLength;
- dataLen -= (uint16_t)parsedLength;
-
- error = otLinkRawSrcMatchAddShortEntry(mInstance, short_address);
-
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
- }
-
- error =
- SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- aValuePtr,
- aValueLen
- );
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-
-otError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- const uint8_t *data = aValuePtr;
- uint16_t dataLen = aValueLen;
-
- // Clear the list first
- error = otLinkRawSrcMatchClearExtEntries(mInstance);
-
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- // Loop through the addresses and add them
- while (dataLen >= sizeof(otExtAddress))
- {
- spinel_ssize_t parsedLength;
- otExtAddress *extAddress;
-
- parsedLength = spinel_datatype_unpack(
- data,
- dataLen,
- SPINEL_DATATYPE_EUI64_S,
- &extAddress
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- data += parsedLength;
- dataLen -= (uint16_t)parsedLength;
-
- error = otLinkRawSrcMatchAddExtEntry(mInstance, extAddress);
-
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
- }
-
- error =
- SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- aValuePtr,
- aValueLen
- );
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-
-#endif
-
-#if OPENTHREAD_FTD
-
-otError NcpBase::SetPropertyHandler_NET_PSKC(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- const uint8_t *ptr = NULL;
- spinel_size_t len;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_DATA_S,
- &ptr,
- &len
- );
-
- VerifyOrExit((parsedLength > 0) && (len == sizeof(spinel_net_pskc_t)), error = OT_ERROR_PARSE);
-
- error = otThreadSetPSKc(mInstance, ptr);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-#endif // OPENTHREAD_FTD
-
-otError NcpBase::SetPropertyHandler_THREAD_MODE(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- uint8_t numericMode = 0;
- otLinkModeConfig modeConfig;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &numericMode
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- modeConfig.mRxOnWhenIdle = ((numericMode & SPINEL_THREAD_MODE_RX_ON_WHEN_IDLE) == SPINEL_THREAD_MODE_RX_ON_WHEN_IDLE);
- modeConfig.mSecureDataRequests =
- ((numericMode & SPINEL_THREAD_MODE_SECURE_DATA_REQUEST) == SPINEL_THREAD_MODE_SECURE_DATA_REQUEST);
- modeConfig.mDeviceType = ((numericMode & SPINEL_THREAD_MODE_FULL_FUNCTION_DEV) == SPINEL_THREAD_MODE_FULL_FUNCTION_DEV);
- modeConfig.mNetworkData = ((numericMode & SPINEL_THREAD_MODE_FULL_NETWORK_DATA) == SPINEL_THREAD_MODE_FULL_NETWORK_DATA);
-
- error = otThreadSetLinkMode(mInstance, modeConfig);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-#if OPENTHREAD_FTD
-
-otError NcpBase::SetPropertyHandler_THREAD_CHILD_COUNT_MAX(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- uint8_t maxChildren = 0;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &maxChildren
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- error = otThreadSetMaxAllowedChildren(mInstance, maxChildren);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_THREAD_CHILD_TIMEOUT(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- uint32_t timeout = 0;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT32_S,
- &timeout
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- otThreadSetChildTimeout(mInstance, timeout);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_THREAD_ROUTER_UPGRADE_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- uint8_t threshold = 0;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &threshold
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- otThreadSetRouterUpgradeThreshold(mInstance, threshold);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_THREAD_ROUTER_DOWNGRADE_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- uint8_t threshold = 0;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &threshold
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- otThreadSetRouterDowngradeThreshold(mInstance, threshold);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_THREAD_ROUTER_SELECTION_JITTER(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- uint8_t jitter = 0;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &jitter
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- otThreadSetRouterSelectionJitter(mInstance, jitter);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_THREAD_PREFERRED_ROUTER_ID(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- uint8_t routerId = 0;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &routerId
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- error = otThreadSetPreferredRouterId(mInstance, routerId);
-
-exit:
- if (error == OT_ERROR_NONE)
- {
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- SPINEL_DATATYPE_UINT8_S,
- routerId
- );
- }
- else
- {
- error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
- }
-
- return error;
-}
-
-#endif // OPENTHREAD_FTD
-
otError NcpBase::SetPropertyHandler_DEBUG_NCP_LOG_LEVEL(uint8_t aHeader, spinel_prop_key_t aKey,
const uint8_t *aValuePtr, uint16_t aValueLen)
{
@@ -6647,1492 +2292,9 @@ exit:
return SendSetPropertyResponse(aHeader, aKey, error);
}
-#if OPENTHREAD_FTD
-
-otError NcpBase::SetPropertyHandler_THREAD_CONTEXT_REUSE_DELAY(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- uint32_t delay = 0;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT32_S,
- &delay
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- otThreadSetContextIdReuseDelay(mInstance, delay);
-
- exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_THREAD_NETWORK_ID_TIMEOUT(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- uint8_t timeout = 0;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &timeout
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- otThreadSetNetworkIdTimeout(mInstance, timeout);
-
- exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-#endif // OPENTHREAD_FTD
-
-#if OPENTHREAD_ENABLE_TMF_PROXY && OPENTHREAD_FTD
-
-otError NcpBase::SetPropertyHandler_THREAD_TMF_PROXY_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- bool enabled;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &enabled
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- if (enabled)
- {
- error = otTmfProxyStart(mInstance, &NcpBase::HandleTmfProxyStream, this);
- }
- else
- {
- error = otTmfProxyStop(mInstance);
- }
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-#endif // OPENTHREAD_ENABLE_TMF_PROXY && OPENTHREAD_FTD
-
-#if OPENTHREAD_ENABLE_JAM_DETECTION
-
-otError NcpBase::SetPropertyHandler_JAM_DETECT_ENABLE(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- bool enabled;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &enabled
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- if (enabled)
- {
- otJamDetectionStart(mInstance, &NcpBase::HandleJamStateChange_Jump, this);
- }
- else
- {
- otJamDetectionStop(mInstance);
- }
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_JAM_DETECT_RSSI_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- int8_t threshold = 0;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_INT8_S,
- &threshold
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- error = otJamDetectionSetRssiThreshold(mInstance, threshold);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_JAM_DETECT_WINDOW(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- uint8_t window = 0;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &window
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- error = otJamDetectionSetWindow(mInstance, window);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_JAM_DETECT_BUSY(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- uint8_t busy = 0;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &busy
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- error = otJamDetectionSetBusyPeriod(mInstance, busy);
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-void NcpBase::HandleJamStateChange_Jump(bool aJamState, void *aContext)
-{
- static_cast(aContext)->HandleJamStateChange(aJamState);
-}
-
-void NcpBase::HandleJamStateChange(bool aJamState)
-{
- OT_UNUSED_VARIABLE(aJamState);
-
- mChangedPropsSet.AddProperty(SPINEL_PROP_JAM_DETECTED);
- mUpdateChangedPropsTask.Post();
-}
-
-#endif // OPENTHREAD_ENABLE_JAM_DETECTION
-
-#if OPENTHREAD_ENABLE_DIAG
-
-otError NcpBase::SetPropertyHandler_NEST_STREAM_MFG(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- char *string = NULL;
- char *output = NULL;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UTF8_S,
- &string
- );
-
- if ((parsedLength > 0) && (string != NULL))
- {
- // all diagnostics related features are processed within diagnostics module
- output = otDiagProcessCmdLine(string);
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_IS,
- aKey,
- reinterpret_cast(output),
- static_cast(strlen(output) + 1)
- );
- }
- else
- {
- error = SendLastStatus(aHeader, SPINEL_STATUS_PARSE_ERROR);
- }
-
- return error;
-}
-
-#endif // OPENTHREAD_ENABLE_DIAG
-
-#if OPENTHREAD_ENABLE_LEGACY
-
-otError NcpBase::SetPropertyHandler_NEST_LEGACY_ULA_PREFIX(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- const uint8_t *ptr = NULL;
- spinel_size_t len;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_DATA_S,
- &ptr,
- &len
- );
-
- VerifyOrExit((parsedLength > 0) && (len <= sizeof(mLegacyUlaPrefix)), error = OT_ERROR_PARSE);
-
- memset(mLegacyUlaPrefix, 0, sizeof(mLegacyUlaPrefix));
- memcpy(mLegacyUlaPrefix, ptr, len);
-
- if ((mLegacyHandlers != NULL) && (mLegacyHandlers->mSetLegacyUlaPrefix != NULL))
- {
- mLegacyHandlers->mSetLegacyUlaPrefix(mLegacyUlaPrefix);
- }
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-#endif // OPENTHREAD_ENABLE_LEGACY
-
-// ----------------------------------------------------------------------------
-// MARK: Individual Property Inserters
-// ----------------------------------------------------------------------------
-
-otError NcpBase::InsertPropertyHandler_UNSOL_UPDATE_FILTER(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- unsigned int propKey;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT_PACKED_S,
- &propKey
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- error = mChangedPropsSet.EnablePropertyFilter(static_cast(propKey), true);
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_INSERTED,
- aKey,
- aValuePtr,
- aValueLen
- );
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-
-#if OPENTHREAD_ENABLE_RAW_LINK_API
-
-otError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- uint16_t short_address;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT16_S,
- &short_address
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- error = otLinkRawSrcMatchAddShortEntry(mInstance, short_address);
-
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_INSERTED,
- aKey,
- aValuePtr,
- aValueLen
- );
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-
-otError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- otExtAddress *extAddress = NULL;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_EUI64_S,
- &extAddress
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- error = otLinkRawSrcMatchAddExtEntry(mInstance, extAddress);
-
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_INSERTED,
- aKey,
- aValuePtr,
- aValueLen
- );
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-
-#endif
-
-otError NcpBase::InsertPropertyHandler_IPV6_ADDRESS_TABLE(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- otNetifAddress netifAddr;
- otIp6Address *addrPtr;
- uint32_t preferredLifetime;
- uint32_t validLifetime;
- uint8_t prefixLen;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- (
- SPINEL_DATATYPE_IPv6ADDR_S // IPv6 address
- SPINEL_DATATYPE_UINT8_S // Prefix length (in bits)
- SPINEL_DATATYPE_UINT32_S // Preferred lifetime
- SPINEL_DATATYPE_UINT32_S // Valid lifetime
- ),
- &addrPtr,
- &prefixLen,
- &preferredLifetime,
- &validLifetime
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- netifAddr.mAddress = *addrPtr;
- netifAddr.mPrefixLength = prefixLen;
- netifAddr.mPreferred = preferredLifetime != 0;
- netifAddr.mValid = validLifetime != 0;
-
- error = otIp6AddUnicastAddress(mInstance, &netifAddr);
-
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_INSERTED,
- aKey,
- aValuePtr,
- aValueLen
- );
-
- spinelError = SPINEL_STATUS_OK;
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-
-otError NcpBase::InsertPropertyHandler_IPV6_MULTICAST_ADDRESS_TABLE(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- otIp6Address *addrPtr;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_IPv6ADDR_S, // IPv6 address
- &addrPtr
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- error = otIp6SubscribeMulticastAddress(mInstance, addrPtr);
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_INSERTED,
- aKey,
- aValuePtr,
- aValueLen
- );
-
- spinelError = SPINEL_STATUS_OK;
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-
-#if OPENTHREAD_ENABLE_BORDER_ROUTER
-otError NcpBase::InsertPropertyHandler_THREAD_OFF_MESH_ROUTES(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- otExternalRouteConfig routeConfig;
- otIp6Address *addrPtr;
- bool stable = false;
- uint8_t flags = 0;
-
- memset(&routeConfig, 0, sizeof(otExternalRouteConfig));
-
- VerifyOrExit(mAllowLocalNetworkDataChange == true, spinelError = SPINEL_STATUS_INVALID_STATE);
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- (
- SPINEL_DATATYPE_IPv6ADDR_S // Route prefix
- SPINEL_DATATYPE_UINT8_S // Prefix length (in bits)
- SPINEL_DATATYPE_BOOL_S // Stable
- SPINEL_DATATYPE_UINT8_S // Flags (Route Preference)
- ),
- &addrPtr,
- &routeConfig.mPrefix.mLength,
- &stable,
- &flags
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- routeConfig.mPrefix.mPrefix = *addrPtr;
- routeConfig.mStable = stable;
- routeConfig.mPreference = FlagByteToExternalRoutePreference(flags);
-
- error = otBorderRouterAddRoute(mInstance, &routeConfig);
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_INSERTED,
- aKey,
- aValuePtr,
- aValueLen
- );
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-
-otError NcpBase::InsertPropertyHandler_THREAD_ON_MESH_NETS(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- otBorderRouterConfig borderRouterConfig;
- otIp6Address *addrPtr;
- bool stable = false;
- uint8_t flags = 0;
-
- memset(&borderRouterConfig, 0, sizeof(otBorderRouterConfig));
-
- VerifyOrExit(mAllowLocalNetworkDataChange == true, spinelError = SPINEL_STATUS_INVALID_STATE);
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- (
- SPINEL_DATATYPE_IPv6ADDR_S // On-mesh prefix
- SPINEL_DATATYPE_UINT8_S // Prefix length (in bits)
- SPINEL_DATATYPE_BOOL_S // Stable
- SPINEL_DATATYPE_UINT8_S // Flags
- ),
- &addrPtr,
- &borderRouterConfig.mPrefix.mLength,
- &stable,
- &flags
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- borderRouterConfig.mPrefix.mPrefix = *addrPtr;
- borderRouterConfig.mStable = stable;
- borderRouterConfig.mPreference =
- ((flags & SPINEL_NET_FLAG_PREFERENCE_MASK) >> SPINEL_NET_FLAG_PREFERENCE_OFFSET);
- borderRouterConfig.mPreferred = ((flags & SPINEL_NET_FLAG_PREFERRED) != 0);
- borderRouterConfig.mSlaac = ((flags & SPINEL_NET_FLAG_SLAAC) != 0);
- borderRouterConfig.mDhcp = ((flags & SPINEL_NET_FLAG_DHCP) != 0);
- borderRouterConfig.mConfigure = ((flags & SPINEL_NET_FLAG_CONFIGURE) != 0);
- borderRouterConfig.mDefaultRoute = ((flags & SPINEL_NET_FLAG_DEFAULT_ROUTE) != 0);
- borderRouterConfig.mOnMesh = ((flags & SPINEL_NET_FLAG_ON_MESH) != 0);
-
- error = otBorderRouterAddOnMeshPrefix(mInstance, &borderRouterConfig);
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_INSERTED,
- aKey,
- aValuePtr,
- aValueLen
- );
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-#endif // OPENTHREAD_ENABLE_BORDER_ROUTER
-
-otError NcpBase::InsertPropertyHandler_THREAD_ASSISTING_PORTS(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- uint16_t port;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT16_S,
- &port
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- error = otIp6AddUnsecurePort(mInstance, port);
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_INSERTED,
- aKey,
- aValuePtr,
- aValueLen
- );
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-
-#if OPENTHREAD_ENABLE_MAC_FILTER
-
-otError NcpBase::InsertPropertyHandler_MAC_WHITELIST(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- otExtAddress *extAddress = NULL;
- int8_t rss = OT_MAC_FILTER_FIXED_RSS_DISABLED;
-
- if (aValueLen > static_cast(sizeof(otExtAddress)))
- {
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_EUI64_S SPINEL_DATATYPE_INT8_S,
- &extAddress,
- &rss
- );
- }
- else
- {
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_EUI64_S,
- &extAddress
- );
- }
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- error = otLinkFilterAddAddress(mInstance, extAddress);
-
- VerifyOrExit(error == OT_ERROR_NONE || error == OT_ERROR_ALREADY, spinelError = ThreadErrorToSpinelStatus(error));
-
- if (rss != OT_MAC_FILTER_FIXED_RSS_DISABLED)
- {
- error = otLinkFilterAddRssIn(mInstance, extAddress, rss);
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
- }
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_INSERTED,
- aKey,
- aValuePtr,
- aValueLen
- );
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-
-otError NcpBase::InsertPropertyHandler_MAC_BLACKLIST(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- otExtAddress *extAddress = NULL;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_EUI64_S,
- &extAddress
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- error = otLinkFilterAddAddress(mInstance, extAddress);
-
- VerifyOrExit(error == OT_ERROR_NONE || error == OT_ERROR_ALREADY, spinelError = ThreadErrorToSpinelStatus(error));
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_INSERTED,
- aKey,
- aValuePtr,
- aValueLen
- );
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-
-otError NcpBase::InsertPropertyHandler_MAC_FIXED_RSS(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- otExtAddress *extAddress = NULL;
- int8_t rss = OT_MAC_FILTER_FIXED_RSS_DISABLED;
-
- if (aValueLen > sizeof(int8_t))
- {
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_EUI64_S SPINEL_DATATYPE_INT8_S,
- &extAddress,
- &rss
- );
- }
- else
- {
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_INT8_S,
- &rss
- );
- }
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- error = otLinkFilterAddRssIn(mInstance, extAddress, rss);
-
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_INSERTED,
- aKey,
- aValuePtr,
- aValueLen
- );
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-
-#endif // OPENTHREAD_ENABLE_MAC_FILTER
-
-#if OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
-otError NcpBase::InsertPropertyHandler_THREAD_JOINERS(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- otExtAddress *extAddress = NULL;
- const char *aPSKd = NULL;
- uint32_t joinerTimeout = 0;
-
- VerifyOrExit(mAllowLocalNetworkDataChange == true, spinelError = SPINEL_STATUS_INVALID_STATE);
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- (
- SPINEL_DATATYPE_UTF8_S // PSK
- SPINEL_DATATYPE_UINT32_S // Timeout
- SPINEL_DATATYPE_EUI64_S // Extended address
- ),
- &aPSKd,
- &joinerTimeout,
- &extAddress
- );
-
- if (parsedLength <= 0)
- {
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- (
- SPINEL_DATATYPE_UTF8_S // PSK
- SPINEL_DATATYPE_UINT32_S // Timeout
- ),
- &aPSKd,
- &joinerTimeout
- );
- extAddress = NULL;
- }
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- error = otCommissionerAddJoiner(mInstance, extAddress, aPSKd, joinerTimeout);
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_INSERTED,
- aKey,
- aValuePtr,
- aValueLen
- );
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-#endif // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
-
-// ----------------------------------------------------------------------------
-// MARK: Individual Property Removers
-// ----------------------------------------------------------------------------
-
-otError NcpBase::RemovePropertyHandler_UNSOL_UPDATE_FILTER(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- unsigned int propKey;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT_PACKED_S,
- &propKey
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- error = mChangedPropsSet.EnablePropertyFilter(static_cast(propKey), false);
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_INSERTED,
- aKey,
- aValuePtr,
- aValueLen
- );
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-
-#if OPENTHREAD_ENABLE_RAW_LINK_API
-otError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- uint16_t shortAddress;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT16_S,
- &shortAddress
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- error = otLinkRawSrcMatchClearShortEntry(mInstance, shortAddress);
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_REMOVED,
- aKey,
- aValuePtr,
- aValueLen
- );
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-
-otError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- otExtAddress *extAddress;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_EUI64_S,
- &extAddress
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- error = otLinkRawSrcMatchClearExtEntry(mInstance, extAddress);
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_REMOVED,
- aKey,
- aValuePtr,
- aValueLen
- );
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-#endif // #if OPENTHREAD_ENABLE_RAW_LINK_API
-
-otError NcpBase::RemovePropertyHandler_IPV6_ADDRESS_TABLE(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- otIp6Address *addrPtr;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_IPv6ADDR_S,
- &addrPtr
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- error = otIp6RemoveUnicastAddress(mInstance, addrPtr);
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_REMOVED,
- aKey,
- aValuePtr,
- aValueLen
- );
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-
-otError NcpBase::RemovePropertyHandler_IPV6_MULTICAST_ADDRESS_TABLE(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- otIp6Address *addrPtr;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_IPv6ADDR_S,
- &addrPtr
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- error = otIp6UnsubscribeMulticastAddress(mInstance, addrPtr);
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_REMOVED,
- aKey,
- aValuePtr,
- aValueLen
- );
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-
-#if OPENTHREAD_ENABLE_BORDER_ROUTER
-otError NcpBase::RemovePropertyHandler_THREAD_OFF_MESH_ROUTES(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- otIp6Prefix ip6Prefix;
- otIp6Address *addrPtr;
-
- memset(&ip6Prefix, 0, sizeof(otIp6Prefix));
-
- VerifyOrExit(mAllowLocalNetworkDataChange == true, spinelError = SPINEL_STATUS_INVALID_STATE);
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- (
- SPINEL_DATATYPE_IPv6ADDR_S // Route prefix
- SPINEL_DATATYPE_UINT8_S // Prefix length (in bits)
- ),
- &addrPtr,
- &ip6Prefix.mLength
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- ip6Prefix.mPrefix = *addrPtr;
-
- error = otBorderRouterRemoveRoute(mInstance, &ip6Prefix);
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_REMOVED,
- aKey,
- aValuePtr,
- aValueLen
- );
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-
-otError NcpBase::RemovePropertyHandler_THREAD_ON_MESH_NETS(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- otIp6Prefix ip6Prefix;
- otIp6Address *addrPtr;
-
- memset(&ip6Prefix, 0, sizeof(otIp6Prefix));
-
- VerifyOrExit(mAllowLocalNetworkDataChange == true, spinelError = SPINEL_STATUS_INVALID_STATE);
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- (
- SPINEL_DATATYPE_IPv6ADDR_S // On-mesh prefix
- SPINEL_DATATYPE_UINT8_S // Prefix length (in bits)
- ),
- &addrPtr,
- &ip6Prefix.mLength
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- ip6Prefix.mPrefix = *addrPtr;
-
- error = otBorderRouterRemoveOnMeshPrefix(mInstance, &ip6Prefix);
-
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_REMOVED,
- aKey,
- aValuePtr,
- aValueLen
- );
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-#endif
-
-otError NcpBase::RemovePropertyHandler_THREAD_ASSISTING_PORTS(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- uint16_t port;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT16_S,
- &port
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- error = otIp6RemoveUnsecurePort(mInstance, port);
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_REMOVED,
- aKey,
- aValuePtr,
- aValueLen
- );
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-
-#if OPENTHREAD_FTD
-otError NcpBase::RemovePropertyHandler_THREAD_ACTIVE_ROUTER_IDS(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- uint8_t routerId;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &routerId
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- error = otThreadReleaseRouterId(mInstance, routerId);
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_REMOVED,
- aKey,
- aValuePtr,
- aValueLen
- );
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-#endif // OPENTHREAD_FTD
-
-#if OPENTHREAD_ENABLE_MAC_FILTER
-
-otError NcpBase::RemovePropertyHandler_MAC_WHITELIST(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- otExtAddress *extAddress = NULL;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_EUI64_S,
- &extAddress
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- error = otLinkFilterRemoveAddress(mInstance, extAddress);
-
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_REMOVED,
- aKey,
- aValuePtr,
- aValueLen
- );
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-
-otError NcpBase::RemovePropertyHandler_MAC_BLACKLIST(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- otExtAddress *extAddress = NULL;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_EUI64_S,
- &extAddress
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- error = otLinkFilterRemoveAddress(mInstance, extAddress);
-
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_REMOVED,
- aKey,
- aValuePtr,
- aValueLen
- );
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-
-otError NcpBase::RemovePropertyHandler_MAC_FIXED_RSS(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- otExtAddress *extAddress = NULL;
-
- if (aValueLen > 0)
- {
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_EUI64_S,
- &extAddress
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
- }
-
- error = otLinkFilterRemoveRssIn(mInstance, extAddress);
-
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- error = SendPropertyUpdate(
- aHeader,
- SPINEL_CMD_PROP_VALUE_REMOVED,
- aKey,
- aValuePtr,
- aValueLen
- );
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
- return error;
-}
-
-#endif // OPENTHREAD_ENABLE_MAC_FILTER
-
-#if OPENTHREAD_ENABLE_LEGACY
-
-void NcpBase::RegisterLegacyHandlers(const otNcpLegacyHandlers *aHandlers)
-{
- mLegacyHandlers = aHandlers;
- bool isEnabled;
-
- VerifyOrExit(mLegacyHandlers != NULL);
-
- isEnabled = (otThreadGetDeviceRole(mInstance) != OT_DEVICE_ROLE_DISABLED);
-
- if (isEnabled)
- {
- if (mLegacyHandlers->mStartLegacy)
- {
- mLegacyHandlers->mStartLegacy();
- }
- }
- else
- {
- if (mLegacyHandlers->mStopLegacy)
- {
- mLegacyHandlers->mStopLegacy();
- }
- }
-
- if (mLegacyHandlers->mSetLegacyUlaPrefix)
- {
- mLegacyHandlers->mSetLegacyUlaPrefix(mLegacyUlaPrefix);
- }
-
-exit:
- return;
-}
-
-void NcpBase::HandleDidReceiveNewLegacyUlaPrefix(const uint8_t *aUlaPrefix)
-{
- memcpy(mLegacyUlaPrefix, aUlaPrefix, OT_NCP_LEGACY_ULA_PREFIX_LENGTH);
- mChangedPropsSet.AddProperty(SPINEL_PROP_NEST_LEGACY_ULA_PREFIX);
- mUpdateChangedPropsTask.Post();
-}
-
-void NcpBase::HandleLegacyNodeDidJoin(const otExtAddress *aExtAddr)
-{
- mLegacyNodeDidJoin = true;
- mLegacyLastJoinedNode = *aExtAddr;
- mChangedPropsSet.AddProperty(SPINEL_PROP_NEST_LEGACY_LAST_NODE_JOINED);
- mUpdateChangedPropsTask.Post();
-}
-
-#endif // OPENTHREAD_ENABLE_LEGACY
-
-otError NcpBase::StreamWrite(int aStreamId, const uint8_t *aDataPtr, int aDataLen)
-{
- otError error = OT_ERROR_NONE;
- spinel_prop_key_t streamPropKey;
-
- if (aStreamId == 0)
- {
- streamPropKey = SPINEL_PROP_STREAM_DEBUG;
- }
- else
- {
- streamPropKey = static_cast(aStreamId);
- }
-
- VerifyOrExit(!mDisableStreamWrite, error = OT_ERROR_INVALID_STATE);
- VerifyOrExit(!mChangedPropsSet.IsPropertyFiltered(streamPropKey), error = OT_ERROR_INVALID_STATE);
-
- error = SendPropertyUpdate(
- SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
- SPINEL_CMD_PROP_VALUE_IS,
- streamPropKey,
- aDataPtr,
- static_cast(aDataLen)
- );
-
- if (error != OT_ERROR_NONE)
- {
- mChangedPropsSet.AddLastStatus(SPINEL_STATUS_NOMEM);
- mUpdateChangedPropsTask.Post();
- }
-
-exit:
- return error;
-}
-
-#if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
-
-void NcpBase::RegisterPeekPokeDelagates(otNcpDelegateAllowPeekPoke aAllowPeekDelegate,
- otNcpDelegateAllowPeekPoke aAllowPokeDelegate)
-{
- mAllowPeekDelegate = aAllowPeekDelegate;
- mAllowPokeDelegate = aAllowPokeDelegate;
-}
-
-#endif // OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
-
+} // namespace Ncp
} // namespace ot
-// ----------------------------------------------------------------------------
-// MARK: Virtual Datastream I/O (Public API)
-// ----------------------------------------------------------------------------
-
-otError otNcpStreamWrite(int aStreamId, const uint8_t *aDataPtr, int aDataLen)
-{
- otError error = OT_ERROR_INVALID_STATE;
- ot::NcpBase *ncp = ot::NcpBase::GetNcpInstance();
-
- if (ncp != NULL)
- {
- error = ncp->StreamWrite(aStreamId, aDataPtr, aDataLen);
- }
-
- return error;
-}
-
// ----------------------------------------------------------------------------
// MARK: Peek/Poke delegate API
// ----------------------------------------------------------------------------
@@ -8143,7 +2305,7 @@ otError otNcpRegisterPeekPokeDelagates(otNcpDelegateAllowPeekPoke aAllowPeekDele
otError error = OT_ERROR_NONE;
#if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
- ot::NcpBase *ncp = ot::NcpBase::GetNcpInstance();
+ ot::Ncp::NcpBase *ncp = ot::Ncp::NcpBase::GetNcpInstance();
if (ncp != NULL)
{
@@ -8161,50 +2323,18 @@ otError otNcpRegisterPeekPokeDelagates(otNcpDelegateAllowPeekPoke aAllowPeekDele
}
// ----------------------------------------------------------------------------
-// MARK: Legacy network APIs
+// MARK: Virtual Datastream I/O (Public API)
// ----------------------------------------------------------------------------
-void otNcpRegisterLegacyHandlers(const otNcpLegacyHandlers *aHandlers)
+otError otNcpStreamWrite(int aStreamId, const uint8_t *aDataPtr, int aDataLen)
{
-#if OPENTHREAD_ENABLE_LEGACY
- ot::NcpBase *ncp = ot::NcpBase::GetNcpInstance();
+ otError error = OT_ERROR_INVALID_STATE;
+ ot::Ncp::NcpBase *ncp = ot::Ncp::NcpBase::GetNcpInstance();
if (ncp != NULL)
{
- ncp->RegisterLegacyHandlers(aHandlers);
+ error = ncp->StreamWrite(aStreamId, aDataPtr, aDataLen);
}
-#else
- OT_UNUSED_VARIABLE(aHandlers);
-#endif
-}
-
-void otNcpHandleDidReceiveNewLegacyUlaPrefix(const uint8_t *aUlaPrefix)
-{
-#if OPENTHREAD_ENABLE_LEGACY
- ot::NcpBase *ncp = ot::NcpBase::GetNcpInstance();
-
- if (ncp != NULL)
- {
- ncp->HandleDidReceiveNewLegacyUlaPrefix(aUlaPrefix);
- }
-
-#else
- OT_UNUSED_VARIABLE(aUlaPrefix);
-#endif
-}
-
-void otNcpHandleLegacyNodeDidJoin(const otExtAddress *aExtAddr)
-{
-#if OPENTHREAD_ENABLE_LEGACY
- ot::NcpBase *ncp = ot::NcpBase::GetNcpInstance();
-
- if (ncp != NULL)
- {
- ncp->HandleLegacyNodeDidJoin(aExtAddr);
- }
-
-#else
- OT_UNUSED_VARIABLE(aExtAddr);
-#endif
+ return error;
}
diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp
index 738da413f..b03d51448 100644
--- a/src/ncp/ncp_base.hpp
+++ b/src/ncp/ncp_base.hpp
@@ -35,17 +35,23 @@
#include
+#if OPENTHREAD_MTD || OPENTHREAD_FTD
#include
+#else
+#include
+#endif
#include
#include
#include
-#include "openthread-core-config.h"
-#include "spinel.h"
+#include "changed_props_set.hpp"
#include "common/tasklet.hpp"
#include "ncp/ncp_buffer.hpp"
+#include "spinel.h"
+
namespace ot {
+namespace Ncp {
#define NCP_COMMAND_HANDLER(name) \
otError CommandHandler_##name( \
@@ -101,13 +107,75 @@ public:
/**
* This static method returns the pointer to the single NCP instance.
*
- @returns Pointer to the single NCP instance.
+ * @returns Pointer to the single NCP instance.
*
*/
static NcpBase *GetNcpInstance(void);
-protected:
+ /**
+ * This method sends data to host via specifiec stream.
+ *
+ *
+ * @param[in] aStreamId A numeric identifier for the stream to write to.
+ * If set to '0', will default to the debug stream.
+ * @param[in] aDataPtr A pointer to the data to send on the stream.
+ * If aDataLen is non-zero, this param MUST NOT be NULL.
+ * @param[in] aDataLen The number of bytes of data from aDataPtr to send.
+ *
+ * @retval OT_ERROR_NONE The data was queued for delivery to the host.
+ * @retval OT_ERROR_BUSY There are not enough resources to complete this
+ * request. This is usually a temporary condition.
+ * @retval OT_ERROR_INVALID_ARGS The given aStreamId was invalid.
+ *
+ */
+ otError StreamWrite(int aStreamId, const uint8_t *aDataPtr, int aDataLen);
+#if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
+ /**
+ * This method registers peek/poke delegate functions with NCP module.
+ *
+ * @param[in] aAllowPeekDelegate Delegate function pointer for peek operation.
+ * @param[in] aAllowPokeDelegate Delegate function pointer for poke operation.
+ *
+ * @retval OT_ERROR_NONE Successfully registered delegate functions.
+ * @retval OT_ERROR_DISABLED_FEATURE Peek/Poke feature is disabled (by a build-time configuration option).
+ *
+ */
+ void RegisterPeekPokeDelagates(otNcpDelegateAllowPeekPoke aAllowPeekDelegate,
+ otNcpDelegateAllowPeekPoke aAllowPokeDelegate);
+#endif
+
+#if OPENTHREAD_MTD || OPENTHREAD_FTD
+#if OPENTHREAD_ENABLE_LEGACY
+ /**
+ * This callback is invoked by the legacy stack to notify that a new
+ * legacy node did join the network.
+ *
+ * @param[in] aExtAddr The extended address of the joined node.
+ *
+ */
+ void HandleLegacyNodeDidJoin(const otExtAddress *aExtAddr);
+
+ /**
+ * This callback is invoked by the legacy stack to notify that the
+ * legacy ULA prefix has changed.
+ *
+ * param[in] aUlaPrefix The changed ULA prefix.
+ *
+ */
+ void HandleDidReceiveNewLegacyUlaPrefix(const uint8_t *aUlaPrefix);
+
+ /**
+ * This method registers a set of legacy handlers with NCP.
+ *
+ * @param[in] aHandlers A pointer to a handler struct.
+ *
+ */
+ void RegisterLegacyHandlers(const otNcpLegacyHandlers *aHandlers);
+#endif
+#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
+
+protected:
/**
* This method is called to start a new outbound frame.
*
@@ -151,7 +219,8 @@ protected:
/**
* This method finalizes and sends the current outbound frame
*
- * If no buffer space is available, this method should discard and clear the frame before returning an error status.
+ * If no buffer space is available, this method should discard and clear the frame
+ * before returning an error status.
*
* @retval OT_ERROR_NONE Successfully added the message to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add message.
@@ -160,13 +229,10 @@ protected:
otError OutboundFrameEnd(void);
/**
- * This method is called by the framer whenever a framing error
- * is detected.
+ * This method is called by the framer whenever a framing error is detected.
*/
void IncrementFrameErrorCounter(void);
-protected:
-
/**
* Called by the subclass to indicate when a frame has been received.
*/
@@ -183,95 +249,6 @@ protected:
bool ShouldDeferHostSend(void);
private:
-
- otError OutboundFrameSend(void);
-
- NcpFrameBuffer::FrameTag GetLastOutboundFrameTag(void);
-
-#if OPENTHREAD_ENABLE_TMF_PROXY && OPENTHREAD_FTD
- static void HandleTmfProxyStream(otMessage *aMessage, uint16_t aLocator, uint16_t aPort, void *aContext);
- void HandleTmfProxyStream(otMessage *aMessage, uint16_t aLocator, uint16_t aPort);
-#endif // OPENTHREAD_ENABLE_TMF_PROXY && OPENTHREAD_FTD
-
- static void HandleFrameRemovedFromNcpBuffer(void *aContext, NcpFrameBuffer::FrameTag aFrameTag,
- NcpFrameBuffer::Priority aPriority, NcpFrameBuffer *aNcpBuffer);
- void HandleFrameRemovedFromNcpBuffer(NcpFrameBuffer::FrameTag aFrameTag);
-
- static void HandleDatagramFromStack(otMessage *aMessage, void *aContext);
- void HandleDatagramFromStack(otMessage *aMessage);
-
- static void HandleRawFrame(const otRadioFrame *aFrame, void *aContext);
- void HandleRawFrame(const otRadioFrame *aFrame);
-
- static void HandleActiveScanResult_Jump(otActiveScanResult *aResult, void *aContext);
- void HandleActiveScanResult(otActiveScanResult *aResult);
-
- static void HandleEnergyScanResult_Jump(otEnergyScanResult *aResult, void *aContext);
- void HandleEnergyScanResult(otEnergyScanResult *aResult);
-
- static void HandleJamStateChange_Jump(bool aJamState, void *aContext);
- void HandleJamStateChange(bool aJamState);
-
- static void UpdateChangedProps(Tasklet &aTasklet);
- void UpdateChangedProps(void);
- void ProcessThreadChangedFlags(void);
-
- static void SendDoneTask(void *aContext);
- void SendDoneTask(void);
-
-#if OPENTHREAD_ENABLE_RAW_LINK_API
-
- static void LinkRawReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError);
- void LinkRawReceiveDone(otRadioFrame *aFrame, otError aError);
-
- static void LinkRawTransmitDone(otInstance *aInstance, otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError);
- void LinkRawTransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError);
-
- static void LinkRawEnergyScanDone(otInstance *aInstance, int8_t aEnergyScanMaxRssi);
- void LinkRawEnergyScanDone(int8_t aEnergyScanMaxRssi);
-
-#endif // OPENTHREAD_ENABLE_RAW_LINK_API
-
- static void HandleNetifStateChanged(uint32_t aFlags, void *aContext);
-
-private:
-
- otError OutboundFrameFeedPacked(const char *aPackFormat, ...);
-
- otError OutboundFrameFeedVPacked(const char *aPackFormat, va_list aArgs);
-
-private:
-
- otError HandleCommand(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, uint16_t aArgLen);
-
- otError HandleCommandPropertyGet(uint8_t aHeader, spinel_prop_key_t aKey);
-
- otError HandleCommandPropertySet(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen);
-
- otError HandleCommandPropertyInsert(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen);
-
- otError HandleCommandPropertyRemove(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen);
-
- otError SendLastStatus(uint8_t aHeader, spinel_status_t aLastStatus);
-
- otError GetPropertyHandler_ChannelMaskHelper(uint8_t aHeader, spinel_prop_key_t aKey, uint32_t channel_mask);
-
-private:
-
- otError SendPropertyUpdate(uint8_t aHeader, uint8_t aCommand, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen);
-
- otError SendPropertyUpdate(uint8_t aHeader, uint8_t aCommand, spinel_prop_key_t aKey, otMessage *message);
-
- otError SendPropertyUpdate(uint8_t aHeader, uint8_t aCommand, spinel_prop_key_t aKey, const char *format, ...);
-
- otError SendSetPropertyResponse(uint8_t aHeader, spinel_prop_key_t aKey, otError aError);
-
-private:
-
typedef otError(NcpBase::*CommandHandlerType)(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr,
uint16_t aArgLen);
@@ -310,13 +287,88 @@ private:
SetPropertyHandlerType mHandler;
};
- static const CommandHandlerEntry mCommandHandlerTable[];
- static const GetPropertyHandlerEntry mGetPropertyHandlerTable[];
- static const SetPropertyHandlerEntry mSetPropertyHandlerTable[];
- static const InsertPropertyHandlerEntry mInsertPropertyHandlerTable[];
- static const RemovePropertyHandlerEntry mRemovePropertyHandlerTable[];
+ otError OutboundFrameSend(void);
- // Command Handlers
+ NcpFrameBuffer::FrameTag GetLastOutboundFrameTag(void);
+
+ otError OutboundFrameFeedPacked(const char *aPackFormat, ...);
+
+ otError OutboundFrameFeedVPacked(const char *aPackFormat, va_list aArgs);
+
+
+ otError HandleCommand(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, uint16_t aArgLen);
+
+ otError HandleCommandPropertyGet(uint8_t aHeader, spinel_prop_key_t aKey);
+
+ otError HandleCommandPropertySet(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen);
+
+ otError HandleCommandPropertyInsert(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen);
+
+ otError HandleCommandPropertyRemove(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen);
+
+
+ otError SendLastStatus(uint8_t aHeader, spinel_status_t aLastStatus);
+
+ otError SendPropertyUpdate(uint8_t aHeader, uint8_t aCommand, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen);
+
+ otError SendPropertyUpdate(uint8_t aHeader, uint8_t aCommand, spinel_prop_key_t aKey, otMessage *message);
+
+ otError SendPropertyUpdate(uint8_t aHeader, uint8_t aCommand, spinel_prop_key_t aKey, const char *format, ...);
+
+ otError SendSetPropertyResponse(uint8_t aHeader, spinel_prop_key_t aKey, otError aError);
+
+ static void UpdateChangedProps(Tasklet &aTasklet);
+ void UpdateChangedProps(void);
+
+ static void HandleFrameRemovedFromNcpBuffer(void *aContext, NcpFrameBuffer::FrameTag aFrameTag,
+ NcpFrameBuffer::Priority aPriority, NcpFrameBuffer *aNcpBuffer);
+ void HandleFrameRemovedFromNcpBuffer(NcpFrameBuffer::FrameTag aFrameTag);
+
+#if OPENTHREAD_ENABLE_RAW_LINK_API
+
+ static void LinkRawReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError);
+ void LinkRawReceiveDone(otRadioFrame *aFrame, otError aError);
+
+ static void LinkRawTransmitDone(otInstance *aInstance, otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError);
+ void LinkRawTransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError);
+
+ static void LinkRawEnergyScanDone(otInstance *aInstance, int8_t aEnergyScanMaxRssi);
+ void LinkRawEnergyScanDone(int8_t aEnergyScanMaxRssi);
+
+ static void HandleRawFrame(const otRadioFrame *aFrame, void *aContext);
+ void HandleRawFrame(const otRadioFrame *aFrame);
+#endif // OPENTHREAD_ENABLE_RAW_LINK_API
+
+#if OPENTHREAD_MTD || OPENTHREAD_FTD
+ static void HandleNetifStateChanged(uint32_t aFlags, void *aContext);
+ void ProcessThreadChangedFlags(void);
+
+ static void HandleDatagramFromStack(otMessage *aMessage, void *aContext);
+ void HandleDatagramFromStack(otMessage *aMessage);
+
+ static void HandleActiveScanResult_Jump(otActiveScanResult *aResult, void *aContext);
+ void HandleActiveScanResult(otActiveScanResult *aResult);
+
+ static void HandleEnergyScanResult_Jump(otEnergyScanResult *aResult, void *aContext);
+ void HandleEnergyScanResult(otEnergyScanResult *aResult);
+
+ static void HandleJamStateChange_Jump(bool aJamState, void *aContext);
+ void HandleJamStateChange(bool aJamState);
+
+ static void SendDoneTask(void *aContext);
+ void SendDoneTask(void);
+
+ otError GetPropertyHandler_ChannelMaskHelper(uint8_t aHeader, spinel_prop_key_t aKey, uint32_t channel_mask);
+#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
+
+#if OPENTHREAD_FTD && OPENTHREAD_ENABLE_TMF_PROXY
+ static void HandleTmfProxyStream(otMessage *aMessage, uint16_t aLocator, uint16_t aPort, void *aContext);
+ void HandleTmfProxyStream(otMessage *aMessage, uint16_t aLocator, uint16_t aPort);
+#endif // OPENTHREAD_FTD && OPENTHREAD_ENABLE_TMF_PROXY
NCP_COMMAND_HANDLER(NOOP);
NCP_COMMAND_HANDLER(RESET);
@@ -324,66 +376,138 @@ private:
NCP_COMMAND_HANDLER(PROP_VALUE_SET);
NCP_COMMAND_HANDLER(PROP_VALUE_INSERT);
NCP_COMMAND_HANDLER(PROP_VALUE_REMOVE);
- NCP_COMMAND_HANDLER(NET_SAVE);
- NCP_COMMAND_HANDLER(NET_CLEAR);
- NCP_COMMAND_HANDLER(NET_RECALL);
#if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
NCP_COMMAND_HANDLER(PEEK);
NCP_COMMAND_HANDLER(POKE);
#endif
- // Property Get Handlers
-
NCP_GET_PROP_HANDLER(LAST_STATUS);
NCP_GET_PROP_HANDLER(PROTOCOL_VERSION);
NCP_GET_PROP_HANDLER(INTERFACE_TYPE);
NCP_GET_PROP_HANDLER(VENDOR_ID);
NCP_GET_PROP_HANDLER(CAPS);
+ NCP_GET_PROP_HANDLER(DEBUG_TEST_ASSERT);
+ NCP_GET_PROP_HANDLER(DEBUG_NCP_LOG_LEVEL);
+ NCP_SET_PROP_HANDLER(DEBUG_NCP_LOG_LEVEL);
NCP_GET_PROP_HANDLER(NCP_VERSION);
NCP_GET_PROP_HANDLER(INTERFACE_COUNT);
NCP_GET_PROP_HANDLER(POWER_STATE);
+ NCP_SET_PROP_HANDLER(POWER_STATE);
NCP_GET_PROP_HANDLER(HWADDR);
NCP_GET_PROP_HANDLER(LOCK);
NCP_GET_PROP_HANDLER(HOST_POWER_STATE);
+ NCP_SET_PROP_HANDLER(HOST_POWER_STATE);
NCP_GET_PROP_HANDLER(UNSOL_UPDATE_FILTER);
NCP_GET_PROP_HANDLER(UNSOL_UPDATE_LIST);
+
+ NCP_GET_PROP_HANDLER(PHY_RX_SENSITIVITY);
+ NCP_GET_PROP_HANDLER(PHY_TX_POWER);
+ NCP_SET_PROP_HANDLER(PHY_TX_POWER);
+ NCP_SET_PROP_HANDLER(PHY_CHAN);
+ NCP_GET_PROP_HANDLER(PHY_CHAN);
+
+ NCP_GET_PROP_HANDLER(MAC_15_4_PANID);
+ NCP_SET_PROP_HANDLER(MAC_15_4_PANID);
+ NCP_GET_PROP_HANDLER(MAC_15_4_LADDR);
+ NCP_SET_PROP_HANDLER(MAC_15_4_LADDR);
+ NCP_GET_PROP_HANDLER(MAC_15_4_SADDR);
+#if OPENTHREAD_ENABLE_RAW_LINK_API
+ NCP_SET_PROP_HANDLER(MAC_15_4_SADDR);
+#endif
+ NCP_GET_PROP_HANDLER(MAC_PROMISCUOUS_MODE);
+ NCP_SET_PROP_HANDLER(MAC_PROMISCUOUS_MODE);
+ NCP_GET_PROP_HANDLER(MAC_RAW_STREAM_ENABLED);
+ NCP_SET_PROP_HANDLER(MAC_RAW_STREAM_ENABLED);
+ NCP_GET_PROP_HANDLER(MAC_DATA_POLL_PERIOD);
+ NCP_SET_PROP_HANDLER(MAC_DATA_POLL_PERIOD);
+
+ NCP_SET_PROP_HANDLER(UNSOL_UPDATE_FILTER);
+
+ NCP_INSERT_PROP_HANDLER(UNSOL_UPDATE_FILTER);
+ NCP_REMOVE_PROP_HANDLER(UNSOL_UPDATE_FILTER);
+
+#if OPENTHREAD_ENABLE_RAW_LINK_API
+ NCP_SET_PROP_HANDLER(MAC_SRC_MATCH_ENABLED);
+
+ NCP_SET_PROP_HANDLER(MAC_SRC_MATCH_SHORT_ADDRESSES);
+ NCP_INSERT_PROP_HANDLER(MAC_SRC_MATCH_SHORT_ADDRESSES);
+ NCP_REMOVE_PROP_HANDLER(MAC_SRC_MATCH_SHORT_ADDRESSES);
+
+ NCP_SET_PROP_HANDLER(MAC_SRC_MATCH_EXTENDED_ADDRESSES);
+ NCP_INSERT_PROP_HANDLER(MAC_SRC_MATCH_EXTENDED_ADDRESSES);
+ NCP_REMOVE_PROP_HANDLER(MAC_SRC_MATCH_EXTENDED_ADDRESSES);
+
NCP_GET_PROP_HANDLER(PHY_ENABLED);
+ NCP_SET_PROP_HANDLER(PHY_ENABLED);
+ NCP_SET_PROP_HANDLER(STREAM_RAW);
+#endif // OPENTHREAD_ENABLE_RAW_LINK_API
+
+ // FTD or MTD handlers.
+#if OPENTHREAD_MTD || OPENTHREAD_FTD
+ NCP_COMMAND_HANDLER(NET_SAVE);
+ NCP_COMMAND_HANDLER(NET_CLEAR);
+ NCP_COMMAND_HANDLER(NET_RECALL);
+
+ NCP_GET_PROP_HANDLER(MAC_EXTENDED_ADDR);
+ NCP_GET_PROP_HANDLER(MAC_SCAN_MASK);
+ NCP_SET_PROP_HANDLER(MAC_SCAN_MASK);
+ NCP_GET_PROP_HANDLER(MAC_SCAN_PERIOD);
+ NCP_SET_PROP_HANDLER(MAC_SCAN_PERIOD);
+ NCP_GET_PROP_HANDLER(MAC_SCAN_STATE);
+ NCP_SET_PROP_HANDLER(MAC_SCAN_STATE);
+
NCP_GET_PROP_HANDLER(PHY_FREQ);
NCP_GET_PROP_HANDLER(PHY_CHAN_SUPPORTED);
- NCP_GET_PROP_HANDLER(PHY_CHAN);
NCP_GET_PROP_HANDLER(PHY_RSSI);
- NCP_GET_PROP_HANDLER(PHY_TX_POWER);
- NCP_GET_PROP_HANDLER(PHY_RX_SENSITIVITY);
- NCP_GET_PROP_HANDLER(MAC_SCAN_STATE);
- NCP_GET_PROP_HANDLER(MAC_15_4_PANID);
- NCP_GET_PROP_HANDLER(MAC_15_4_LADDR);
- NCP_GET_PROP_HANDLER(MAC_15_4_SADDR);
- NCP_GET_PROP_HANDLER(MAC_RAW_STREAM_ENABLED);
- NCP_GET_PROP_HANDLER(MAC_EXTENDED_ADDR);
- NCP_GET_PROP_HANDLER(MAC_DATA_POLL_PERIOD);
+
NCP_GET_PROP_HANDLER(NET_SAVED);
NCP_GET_PROP_HANDLER(NET_IF_UP);
+ NCP_SET_PROP_HANDLER(NET_IF_UP);
NCP_GET_PROP_HANDLER(NET_STACK_UP);
+ NCP_SET_PROP_HANDLER(NET_STACK_UP);
NCP_GET_PROP_HANDLER(NET_ROLE);
+ NCP_SET_PROP_HANDLER(NET_ROLE);
NCP_GET_PROP_HANDLER(NET_NETWORK_NAME);
+ NCP_SET_PROP_HANDLER(NET_NETWORK_NAME);
NCP_GET_PROP_HANDLER(NET_XPANID);
+ NCP_SET_PROP_HANDLER(NET_XPANID);
NCP_GET_PROP_HANDLER(NET_MASTER_KEY);
+ NCP_SET_PROP_HANDLER(NET_MASTER_KEY);
NCP_GET_PROP_HANDLER(NET_KEY_SEQUENCE_COUNTER);
+ NCP_SET_PROP_HANDLER(NET_KEY_SEQUENCE_COUNTER);
NCP_GET_PROP_HANDLER(NET_PARTITION_ID);
NCP_GET_PROP_HANDLER(NET_KEY_SWITCH_GUARDTIME);
+ NCP_SET_PROP_HANDLER(NET_KEY_SWITCH_GUARDTIME);
NCP_GET_PROP_HANDLER(THREAD_LEADER);
NCP_GET_PROP_HANDLER(IPV6_ML_PREFIX);
+ NCP_SET_PROP_HANDLER(IPV6_ML_PREFIX);
NCP_GET_PROP_HANDLER(IPV6_ML_ADDR);
NCP_GET_PROP_HANDLER(IPV6_LL_ADDR);
+
NCP_GET_PROP_HANDLER(IPV6_ADDRESS_TABLE);
+ NCP_INSERT_PROP_HANDLER(IPV6_ADDRESS_TABLE);
+ NCP_REMOVE_PROP_HANDLER(IPV6_ADDRESS_TABLE);
+
NCP_GET_PROP_HANDLER(IPV6_ROUTE_TABLE);
NCP_GET_PROP_HANDLER(IPV6_ICMP_PING_OFFLOAD);
+ NCP_SET_PROP_HANDLER(IPV6_ICMP_PING_OFFLOAD);
+
NCP_GET_PROP_HANDLER(IPV6_MULTICAST_ADDRESS_TABLE);
+ NCP_INSERT_PROP_HANDLER(IPV6_MULTICAST_ADDRESS_TABLE);
+ NCP_REMOVE_PROP_HANDLER(IPV6_MULTICAST_ADDRESS_TABLE);
+
NCP_GET_PROP_HANDLER(THREAD_RLOC16_DEBUG_PASSTHRU);
+ NCP_SET_PROP_HANDLER(THREAD_RLOC16_DEBUG_PASSTHRU);
NCP_GET_PROP_HANDLER(THREAD_OFF_MESH_ROUTES);
- NCP_GET_PROP_HANDLER(STREAM_NET);
- NCP_GET_PROP_HANDLER(MAC_SCAN_MASK);
- NCP_GET_PROP_HANDLER(MAC_SCAN_PERIOD);
+#if OPENTHREAD_ENABLE_BORDER_ROUTER
+ NCP_INSERT_PROP_HANDLER(THREAD_OFF_MESH_ROUTES);
+ NCP_REMOVE_PROP_HANDLER(THREAD_OFF_MESH_ROUTES);
+#endif
+ NCP_GET_PROP_HANDLER(THREAD_ON_MESH_NETS);
+#if OPENTHREAD_ENABLE_BORDER_ROUTER
+ NCP_INSERT_PROP_HANDLER(THREAD_ON_MESH_NETS);
+ NCP_REMOVE_PROP_HANDLER(THREAD_ON_MESH_NETS);
+#endif
NCP_GET_PROP_HANDLER(THREAD_LEADER_ADDR);
NCP_GET_PROP_HANDLER(THREAD_PARENT);
NCP_GET_PROP_HANDLER(THREAD_NEIGHBOR_TABLE);
@@ -397,386 +521,134 @@ private:
NCP_GET_PROP_HANDLER(THREAD_STABLE_NETWORK_DATA_VERSION);
NCP_GET_PROP_HANDLER(THREAD_LEADER_NETWORK_DATA);
NCP_GET_PROP_HANDLER(THREAD_STABLE_LEADER_NETWORK_DATA);
- NCP_GET_PROP_HANDLER(MAC_PROMISCUOUS_MODE);
NCP_GET_PROP_HANDLER(THREAD_ASSISTING_PORTS);
+ NCP_SET_PROP_HANDLER(THREAD_ASSISTING_PORTS);
+ NCP_INSERT_PROP_HANDLER(THREAD_ASSISTING_PORTS);
+ NCP_REMOVE_PROP_HANDLER(THREAD_ASSISTING_PORTS);
NCP_GET_PROP_HANDLER(THREAD_ALLOW_LOCAL_NET_DATA_CHANGE);
+#if OPENTHREAD_ENABLE_BORDER_ROUTER
+ NCP_SET_PROP_HANDLER(THREAD_ALLOW_LOCAL_NET_DATA_CHANGE);
+#endif
+ NCP_GET_PROP_HANDLER(STREAM_NET);
+ NCP_SET_PROP_HANDLER(STREAM_NET);
NCP_GET_PROP_HANDLER(MAC_CNTR);
NCP_GET_PROP_HANDLER(NCP_CNTR);
NCP_GET_PROP_HANDLER(IP_CNTR);
NCP_GET_PROP_HANDLER(MSG_BUFFER_COUNTERS);
#if OPENTHREAD_ENABLE_MAC_FILTER
- NCP_GET_PROP_HANDLER(MAC_WHITELIST);
NCP_GET_PROP_HANDLER(MAC_WHITELIST_ENABLED);
- NCP_GET_PROP_HANDLER(MAC_BLACKLIST);
+ NCP_SET_PROP_HANDLER(MAC_WHITELIST_ENABLED);
+ NCP_GET_PROP_HANDLER(MAC_WHITELIST);
+ NCP_SET_PROP_HANDLER(MAC_WHITELIST);
+ NCP_INSERT_PROP_HANDLER(MAC_WHITELIST);
+ NCP_REMOVE_PROP_HANDLER(MAC_WHITELIST);
+ NCP_INSERT_PROP_HANDLER(MAC_BLACKLIST);
+ NCP_REMOVE_PROP_HANDLER(MAC_BLACKLIST);
NCP_GET_PROP_HANDLER(MAC_BLACKLIST_ENABLED);
+ NCP_SET_PROP_HANDLER(MAC_BLACKLIST_ENABLED);
+ NCP_SET_PROP_HANDLER(MAC_BLACKLIST);
+ NCP_GET_PROP_HANDLER(MAC_BLACKLIST);
NCP_GET_PROP_HANDLER(MAC_FIXED_RSS);
+ NCP_SET_PROP_HANDLER(MAC_FIXED_RSS);
+ NCP_INSERT_PROP_HANDLER(MAC_FIXED_RSS);
+ NCP_REMOVE_PROP_HANDLER(MAC_FIXED_RSS);
#endif
NCP_GET_PROP_HANDLER(THREAD_MODE);
+ NCP_SET_PROP_HANDLER(THREAD_MODE);
NCP_GET_PROP_HANDLER(THREAD_CHILD_TIMEOUT);
NCP_GET_PROP_HANDLER(THREAD_RLOC16);
- NCP_GET_PROP_HANDLER(THREAD_ON_MESH_NETS);
NCP_GET_PROP_HANDLER(NET_REQUIRE_JOIN_EXISTING);
- NCP_GET_PROP_HANDLER(DEBUG_TEST_ASSERT);
- NCP_GET_PROP_HANDLER(DEBUG_NCP_LOG_LEVEL);
+ NCP_SET_PROP_HANDLER(NET_REQUIRE_JOIN_EXISTING);
NCP_GET_PROP_HANDLER(THREAD_DISCOVERY_SCAN_JOINER_FLAG);
+ NCP_SET_PROP_HANDLER(THREAD_DISCOVERY_SCAN_JOINER_FLAG);
NCP_GET_PROP_HANDLER(THREAD_DISCOVERY_SCAN_ENABLE_FILTERING);
+ NCP_SET_PROP_HANDLER(THREAD_DISCOVERY_SCAN_ENABLE_FILTERING);
NCP_GET_PROP_HANDLER(THREAD_DISCOVERY_SCAN_PANID);
-#if OPENTHREAD_FTD
- NCP_GET_PROP_HANDLER(THREAD_CHILD_TABLE);
- NCP_GET_PROP_HANDLER(THREAD_LOCAL_LEADER_WEIGHT);
- NCP_GET_PROP_HANDLER(THREAD_ROUTER_ROLE_ENABLED);
- NCP_GET_PROP_HANDLER(NET_PSKC);
- NCP_GET_PROP_HANDLER(THREAD_CHILD_COUNT_MAX);
- NCP_GET_PROP_HANDLER(THREAD_ROUTER_UPGRADE_THRESHOLD);
- NCP_GET_PROP_HANDLER(THREAD_ROUTER_DOWNGRADE_THRESHOLD);
- NCP_GET_PROP_HANDLER(THREAD_ROUTER_SELECTION_JITTER);
- NCP_GET_PROP_HANDLER(THREAD_CONTEXT_REUSE_DELAY);
- NCP_GET_PROP_HANDLER(THREAD_NETWORK_ID_TIMEOUT);
-#endif // #if OPENTHREAD_FTD
+ NCP_SET_PROP_HANDLER(THREAD_DISCOVERY_SCAN_PANID);
#if OPENTHREAD_ENABLE_COMMISSIONER
NCP_GET_PROP_HANDLER(THREAD_COMMISSIONER_ENABLED);
+ NCP_SET_PROP_HANDLER(THREAD_COMMISSIONER_ENABLED);
+ NCP_INSERT_PROP_HANDLER(THREAD_JOINERS);
#endif
- NCP_GET_PROP_HANDLER(THREAD_TMF_PROXY_ENABLED);
#if OPENTHREAD_ENABLE_JAM_DETECTION
- NCP_GET_PROP_HANDLER(JAM_DETECT_ENABLE);
NCP_GET_PROP_HANDLER(JAM_DETECTED);
+ NCP_GET_PROP_HANDLER(JAM_DETECT_ENABLE);
+ NCP_SET_PROP_HANDLER(JAM_DETECT_ENABLE);
NCP_GET_PROP_HANDLER(JAM_DETECT_RSSI_THRESHOLD);
+ NCP_SET_PROP_HANDLER(JAM_DETECT_RSSI_THRESHOLD);
NCP_GET_PROP_HANDLER(JAM_DETECT_WINDOW);
+ NCP_SET_PROP_HANDLER(JAM_DETECT_WINDOW);
NCP_GET_PROP_HANDLER(JAM_DETECT_BUSY);
+ NCP_SET_PROP_HANDLER(JAM_DETECT_BUSY);
NCP_GET_PROP_HANDLER(JAM_DETECT_HISTORY_BITMAP);
#endif
#if OPENTHREAD_ENABLE_LEGACY
NCP_GET_PROP_HANDLER(NEST_LEGACY_ULA_PREFIX);
+ NCP_SET_PROP_HANDLER(NEST_LEGACY_ULA_PREFIX);
NCP_GET_PROP_HANDLER(NEST_LEGACY_LAST_NODE_JOINED);
#endif
-
- // Property Set Handlers
-
- NCP_SET_PROP_HANDLER(POWER_STATE);
- NCP_SET_PROP_HANDLER(HOST_POWER_STATE);
- NCP_SET_PROP_HANDLER(PHY_TX_POWER);
- NCP_SET_PROP_HANDLER(PHY_CHAN);
- NCP_SET_PROP_HANDLER(UNSOL_UPDATE_FILTER);
- NCP_SET_PROP_HANDLER(MAC_SCAN_MASK);
- NCP_SET_PROP_HANDLER(MAC_SCAN_STATE);
- NCP_SET_PROP_HANDLER(MAC_15_4_PANID);
- NCP_SET_PROP_HANDLER(MAC_15_4_LADDR);
- NCP_SET_PROP_HANDLER(MAC_DATA_POLL_PERIOD);
- NCP_SET_PROP_HANDLER(MAC_RAW_STREAM_ENABLED);
-#if OPENTHREAD_ENABLE_RAW_LINK_API
- NCP_SET_PROP_HANDLER(MAC_15_4_SADDR);
- NCP_SET_PROP_HANDLER(STREAM_RAW);
-#endif
- NCP_SET_PROP_HANDLER(NET_IF_UP);
- NCP_SET_PROP_HANDLER(NET_STACK_UP);
- NCP_SET_PROP_HANDLER(NET_ROLE);
- NCP_SET_PROP_HANDLER(NET_NETWORK_NAME);
- NCP_SET_PROP_HANDLER(NET_XPANID);
- NCP_SET_PROP_HANDLER(NET_MASTER_KEY);
- NCP_SET_PROP_HANDLER(NET_KEY_SEQUENCE_COUNTER);
- NCP_SET_PROP_HANDLER(NET_KEY_SWITCH_GUARDTIME);
NCP_SET_PROP_HANDLER(STREAM_NET_INSECURE);
- NCP_SET_PROP_HANDLER(STREAM_NET);
- NCP_SET_PROP_HANDLER(IPV6_ML_PREFIX);
- NCP_SET_PROP_HANDLER(IPV6_ICMP_PING_OFFLOAD);
- NCP_SET_PROP_HANDLER(THREAD_RLOC16_DEBUG_PASSTHRU);
- NCP_SET_PROP_HANDLER(THREAD_TMF_PROXY_STREAM);
-#if OPENTHREAD_ENABLE_RAW_LINK_API
- NCP_SET_PROP_HANDLER(PHY_ENABLED);
-#endif
- NCP_SET_PROP_HANDLER(MAC_PROMISCUOUS_MODE);
- NCP_SET_PROP_HANDLER(MAC_SCAN_PERIOD);
-#if OPENTHREAD_ENABLE_MAC_FILTER
- NCP_SET_PROP_HANDLER(MAC_WHITELIST);
- NCP_SET_PROP_HANDLER(MAC_WHITELIST_ENABLED);
- NCP_SET_PROP_HANDLER(MAC_BLACKLIST);
- NCP_SET_PROP_HANDLER(MAC_BLACKLIST_ENABLED);
- NCP_SET_PROP_HANDLER(MAC_FIXED_RSS);
-#endif
-#if OPENTHREAD_ENABLE_RAW_LINK_API
- NCP_SET_PROP_HANDLER(MAC_SRC_MATCH_ENABLED);
- NCP_SET_PROP_HANDLER(MAC_SRC_MATCH_SHORT_ADDRESSES);
- NCP_SET_PROP_HANDLER(MAC_SRC_MATCH_EXTENDED_ADDRESSES);
-#endif
- NCP_SET_PROP_HANDLER(THREAD_MODE);
-#if OPENTHREAD_ENABLE_BORDER_ROUTER
- NCP_SET_PROP_HANDLER(THREAD_ALLOW_LOCAL_NET_DATA_CHANGE);
-#endif
-#if OPENTHREAD_FTD
- NCP_SET_PROP_HANDLER(NET_PSKC);
- NCP_SET_PROP_HANDLER(THREAD_LOCAL_LEADER_WEIGHT);
- NCP_SET_PROP_HANDLER(THREAD_CHILD_COUNT_MAX);
- NCP_SET_PROP_HANDLER(THREAD_CHILD_TIMEOUT);
- NCP_SET_PROP_HANDLER(THREAD_ROUTER_UPGRADE_THRESHOLD);
- NCP_SET_PROP_HANDLER(THREAD_ROUTER_DOWNGRADE_THRESHOLD);
- NCP_SET_PROP_HANDLER(THREAD_ROUTER_SELECTION_JITTER);
- NCP_SET_PROP_HANDLER(THREAD_CONTEXT_REUSE_DELAY);
- NCP_SET_PROP_HANDLER(THREAD_NETWORK_ID_TIMEOUT);
- NCP_SET_PROP_HANDLER(THREAD_PREFERRED_ROUTER_ID);
- NCP_SET_PROP_HANDLER(THREAD_ROUTER_ROLE_ENABLED);
-#if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB
- NCP_SET_PROP_HANDLER(THREAD_STEERING_DATA);
-#endif
-#endif // #if OPENTHREAD_FTD
- NCP_SET_PROP_HANDLER(THREAD_DISCOVERY_SCAN_JOINER_FLAG);
- NCP_SET_PROP_HANDLER(THREAD_DISCOVERY_SCAN_ENABLE_FILTERING);
- NCP_SET_PROP_HANDLER(THREAD_DISCOVERY_SCAN_PANID);
- NCP_SET_PROP_HANDLER(THREAD_ASSISTING_PORTS);
- NCP_SET_PROP_HANDLER(NET_REQUIRE_JOIN_EXISTING);
NCP_SET_PROP_HANDLER(CNTR_RESET);
- NCP_SET_PROP_HANDLER(DEBUG_NCP_LOG_LEVEL);
-#if OPENTHREAD_ENABLE_COMMISSIONER
- NCP_SET_PROP_HANDLER(THREAD_COMMISSIONER_ENABLED);
-#endif
- NCP_SET_PROP_HANDLER(THREAD_TMF_PROXY_ENABLED);
-#if OPENTHREAD_ENABLE_JAM_DETECTION
- NCP_SET_PROP_HANDLER(JAM_DETECT_ENABLE);
- NCP_SET_PROP_HANDLER(JAM_DETECT_RSSI_THRESHOLD);
- NCP_SET_PROP_HANDLER(JAM_DETECT_WINDOW);
- NCP_SET_PROP_HANDLER(JAM_DETECT_BUSY);
-#endif
#if OPENTHREAD_ENABLE_DIAG
NCP_SET_PROP_HANDLER(NEST_STREAM_MFG);
#endif
-#if OPENTHREAD_ENABLE_LEGACY
- NCP_SET_PROP_HANDLER(NEST_LEGACY_ULA_PREFIX);
-#endif
- // Property Insert Handlers
+#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
- NCP_INSERT_PROP_HANDLER(UNSOL_UPDATE_FILTER);
-#if OPENTHREAD_ENABLE_RAW_LINK_API
- NCP_INSERT_PROP_HANDLER(MAC_SRC_MATCH_SHORT_ADDRESSES);
- NCP_INSERT_PROP_HANDLER(MAC_SRC_MATCH_EXTENDED_ADDRESSES);
-#endif
- NCP_INSERT_PROP_HANDLER(IPV6_ADDRESS_TABLE);
- NCP_INSERT_PROP_HANDLER(IPV6_MULTICAST_ADDRESS_TABLE);
-#if OPENTHREAD_ENABLE_BORDER_ROUTER
- NCP_INSERT_PROP_HANDLER(THREAD_OFF_MESH_ROUTES);
- NCP_INSERT_PROP_HANDLER(THREAD_ON_MESH_NETS);
-#endif
- NCP_INSERT_PROP_HANDLER(THREAD_ASSISTING_PORTS);
-#if OPENTHREAD_ENABLE_MAC_FILTER
- NCP_INSERT_PROP_HANDLER(MAC_WHITELIST);
- NCP_INSERT_PROP_HANDLER(MAC_BLACKLIST);
- NCP_INSERT_PROP_HANDLER(MAC_FIXED_RSS);
-#endif
-#if OPENTHREAD_ENABLE_COMMISSIONER
- NCP_INSERT_PROP_HANDLER(THREAD_JOINERS);
-#endif
-
- // Property Remove Handlers
-
- NCP_REMOVE_PROP_HANDLER(UNSOL_UPDATE_FILTER);
-#if OPENTHREAD_ENABLE_RAW_LINK_API
- NCP_REMOVE_PROP_HANDLER(MAC_SRC_MATCH_SHORT_ADDRESSES);
- NCP_REMOVE_PROP_HANDLER(MAC_SRC_MATCH_EXTENDED_ADDRESSES);
-#endif
- NCP_REMOVE_PROP_HANDLER(IPV6_ADDRESS_TABLE);
- NCP_REMOVE_PROP_HANDLER(IPV6_MULTICAST_ADDRESS_TABLE);
-#if OPENTHREAD_ENABLE_BORDER_ROUTER
- NCP_REMOVE_PROP_HANDLER(THREAD_OFF_MESH_ROUTES);
- NCP_REMOVE_PROP_HANDLER(THREAD_ON_MESH_NETS);
-#endif
- NCP_REMOVE_PROP_HANDLER(THREAD_ASSISTING_PORTS);
-#if OPENTHREAD_ENABLE_MAC_FILTER
- NCP_REMOVE_PROP_HANDLER(MAC_WHITELIST);
- NCP_REMOVE_PROP_HANDLER(MAC_BLACKLIST);
- NCP_REMOVE_PROP_HANDLER(MAC_FIXED_RSS);
-#endif
#if OPENTHREAD_FTD
+ NCP_GET_PROP_HANDLER(NET_PSKC);
+ NCP_SET_PROP_HANDLER(NET_PSKC);
+ NCP_GET_PROP_HANDLER(THREAD_CHILD_TABLE);
+ NCP_GET_PROP_HANDLER(THREAD_CHILD_COUNT_MAX);
+ NCP_SET_PROP_HANDLER(THREAD_CHILD_COUNT_MAX);
+ NCP_SET_PROP_HANDLER(THREAD_CHILD_TIMEOUT);
+ NCP_GET_PROP_HANDLER(THREAD_CONTEXT_REUSE_DELAY);
+ NCP_SET_PROP_HANDLER(THREAD_CONTEXT_REUSE_DELAY);
+ NCP_GET_PROP_HANDLER(THREAD_LOCAL_LEADER_WEIGHT);
+ NCP_SET_PROP_HANDLER(THREAD_LOCAL_LEADER_WEIGHT);
+ NCP_GET_PROP_HANDLER(THREAD_NETWORK_ID_TIMEOUT);
+ NCP_SET_PROP_HANDLER(THREAD_NETWORK_ID_TIMEOUT);
+ NCP_GET_PROP_HANDLER(THREAD_ROUTER_ROLE_ENABLED);
+ NCP_SET_PROP_HANDLER(THREAD_ROUTER_ROLE_ENABLED);
+ NCP_GET_PROP_HANDLER(THREAD_ROUTER_UPGRADE_THRESHOLD);
+ NCP_SET_PROP_HANDLER(THREAD_ROUTER_UPGRADE_THRESHOLD);
+ NCP_GET_PROP_HANDLER(THREAD_ROUTER_DOWNGRADE_THRESHOLD);
+ NCP_SET_PROP_HANDLER(THREAD_ROUTER_DOWNGRADE_THRESHOLD);
+ NCP_GET_PROP_HANDLER(THREAD_ROUTER_SELECTION_JITTER);
+ NCP_SET_PROP_HANDLER(THREAD_ROUTER_SELECTION_JITTER);
+ NCP_SET_PROP_HANDLER(THREAD_PREFERRED_ROUTER_ID);
+#if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB
+ NCP_SET_PROP_HANDLER(THREAD_STEERING_DATA);
+#endif
+#if OPENTHREAD_ENABLE_TMF_PROXY
+ NCP_GET_PROP_HANDLER(THREAD_TMF_PROXY_ENABLED);
+ NCP_SET_PROP_HANDLER(THREAD_TMF_PROXY_ENABLED);
+ NCP_SET_PROP_HANDLER(THREAD_TMF_PROXY_STREAM);
+#endif
NCP_REMOVE_PROP_HANDLER(THREAD_ACTIVE_ROUTER_IDS);
-#endif
-
-public:
- otError StreamWrite(int aStreamId, const uint8_t *aDataPtr, int aDataLen);
-
-#if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
- void RegisterPeekPokeDelagates(otNcpDelegateAllowPeekPoke aAllowPeekDelegate,
- otNcpDelegateAllowPeekPoke aAllowPokeDelegate);
-#endif
-
-#if OPENTHREAD_ENABLE_LEGACY
-public:
- void HandleLegacyNodeDidJoin(const otExtAddress *aExtAddr);
- void HandleDidReceiveNewLegacyUlaPrefix(const uint8_t *aUlaPrefix);
- void RegisterLegacyHandlers(const otNcpLegacyHandlers *aHandlers);
-#endif
+#endif // OPENTHREAD_FTD
protected:
static NcpBase *sNcpInstance;
+ static spinel_status_t ThreadErrorToSpinelStatus(otError aError);
+ static uint8_t LinkFlagsToFlagByte(bool aRxOnWhenIdle, bool aSecureDataRequests, bool aDeviceType, bool aNetworkData);
otInstance *mInstance;
NcpFrameBuffer mTxFrameBuffer;
private:
-
- /**
- * Defines a class to track a set of property/status changes that require update to host. The properties that can
- * be added to this set must support sending unsolicited updates. This class also provides mechanism for user
- * to block certain filterable properties disallowing the unsolicited update from them.
- *
- */
- class ChangedPropsSet
- {
- public:
- /**
- * Defines an entry in the set/list.
- *
- */
- struct Entry
- {
- spinel_prop_key_t mPropKey; ///< The spinel property key.
- spinel_status_t mStatus; ///< The spinel status (used only if prop key is `LAST_STATUS`).
- bool mFilterable; ///< Indicates whether the entry can be filtered
- };
-
- /**
- * This constructor initializes the set.
- *
- */
- ChangedPropsSet(void):
- mChangedSet(0),
- mFilterSet(0)
- { }
-
- /**
- * This method clears the set.
- *
- */
- void Clear(void) { mChangedSet = 0; }
-
- /**
- * This method indicates if the set is empty or not.
- *
- * @returns TRUE if the set if empty, FALSE otherwise.
- *
- */
- bool IsEmpty(void) const { return (mChangedSet == 0); }
-
- /**
- * This method adds a property to the set. The property added must be in the list of supported properties
- * capable of sending unsolicited update, otherwise the input is ignored.
- *
- * Note that if the property is already in the set, adding it again does not change the set.
- *
- * @param[in] aPropKey The spinel property key to be added to the set
- *
- */
- void AddProperty(spinel_prop_key_t aPropKey) { Add(aPropKey, SPINEL_STATUS_OK); }
-
- /**
- * This method adds a `LAST_STATUS` update to the set. The update must be in list of supported entries.
- *
- * @param[in] aStatus The spinel status update to be added to set.
- *
- */
- void AddLastStatus(spinel_status_t aStatus) { Add(SPINEL_PROP_LAST_STATUS, aStatus); }
-
- /**
- * This method returns a pointer to array of entries of supported property/status updates. The list includes
- * all properties that can generate unsolicited update.
- *
- * @param[out] aNumEntries A reference to output the number of entries in the list.
- *
- * @returns A pointer to the supported entries array.
- *
- */
- const Entry *GetSupportedEntries(uint8_t &aNumEntries) const {
- aNumEntries = GetNumEntries();
- return &mSupportedProps[0];
- }
-
- /**
- * This method returns a pointer to the entry associated with a given index.
- *
- * @param[in] aIndex The index to an entry.
- *
- * @returns A pointer to the entry associated with @p aIndex, or NULL if the index is beyond end of array.
- *
- */
- const Entry *GetEntry(uint8_t aIndex) const {
- return (aIndex < GetNumEntries()) ? &mSupportedProps[aIndex] : NULL;
- }
-
- /**
- * This method indicates if the entry associated with an index is in the set (i.e., it has been changed and
- * requires an unsolicited update).
- *
- * @param[in] aIndex The index to an entry.
- *
- * @returns TRUE if the entry is in the set, FALSE otherwise.
- *
- */
- bool IsEntryChanged(uint8_t aIndex) const { return IsBitSet(mChangedSet, aIndex); }
-
- /**
- * This method removes an entry associated with an index in the set.
- *
- * Note that if the property/entry is not in the set, removing it simply does nothing.
- *
- * @param[in] aIndex Index of entry to be removed.
- *
- */
- void RemoveEntry(uint8_t aIndex) { ClearBit(mChangedSet, aIndex); }
-
- /**
- * This method enables/disables filtering of a given property.
- *
- * @param[in] aPropKey The property key to filter.
- * @param[in] aEnable TRUE to enable filtering, FALSE to disable.
- *
- * @retval OT_ERROR_NONE Filter state for given property updated successfully.
- * @retval OT_ERROR_INVALID_ARGS The given property is not valid (i.e., not capable of unsolicited update).
- *
- */
- otError EnablePropertyFilter(spinel_prop_key_t aPropKey, bool aEnable);
-
- /**
- * This method determines whether filtering is enabled for an entry associated with an index.
- *
- * @param[in] aIndex Index of entry to be checked.
- *
- * @returns TRUE if the filter is enabled for the given entry, FALSE otherwise.
- *
- */
- bool IsEntryFiltered(uint8_t aIndex) const { return IsBitSet(mFilterSet, aIndex); }
-
- /**
- * This method determines whether filtering is enabled for a given property key.
- *
- * @param[in] aPropKey The property key to check.
- *
- * @returns TRUE if the filter is enabled for the given property, FALSE if the property is not filtered or if
- * it is not filterable.
- *
- */
- bool IsPropertyFiltered(spinel_prop_key_t aPropKey) const;
-
- /**
- * This method clears the filter.
- *
- */
- void ClearFilter(void) { mFilterSet = 0; }
-
- private:
- uint8_t GetNumEntries(void) const;
- void Add(spinel_prop_key_t aPropKey, spinel_status_t aStatus);
-
- static void SetBit (uint32_t &aBitset, uint8_t aBitIndex) { aBitset |= (1U << aBitIndex); }
- static void ClearBit(uint32_t &aBitset, uint8_t aBitIndex) { aBitset &= ~(1U << aBitIndex); }
- static bool IsBitSet(uint32_t aBitset, uint8_t aBitIndex) { return (aBitset & (1U << aBitIndex)) != 0; }
-
- static const Entry mSupportedProps[];
-
- uint32_t mChangedSet;
- uint32_t mFilterSet;
- };
-
enum
{
kTxBufferSize = OPENTHREAD_CONFIG_NCP_TX_BUFFER_SIZE, // Tx Buffer size (used by mTxFrameBuffer).
+ kInvalidScanChannel = -1, // Invalid scan channel.
};
+ // Command Handlers
+ static const CommandHandlerEntry mCommandHandlerTable[];
+ static const GetPropertyHandlerEntry mGetPropertyHandlerTable[];
+ static const SetPropertyHandlerEntry mSetPropertyHandlerTable[];
+ static const InsertPropertyHandlerEntry mInsertPropertyHandlerTable[];
+ static const RemovePropertyHandlerEntry mRemovePropertyHandlerTable[];
+
spinel_status_t mLastStatus;
uint32_t mSupportedChannelMask;
uint32_t mChannelMask;
@@ -789,6 +661,8 @@ private:
uint32_t mThreadChangedFlags;
ChangedPropsSet mChangedPropsSet;
+ uint32_t mChangedFlags;
+ bool mShouldSignalEndOfScan;
spinel_host_power_state_t mHostPowerState;
bool mHostPowerStateInProgress;
NcpFrameBuffer::FrameTag mHostPowerReplyFrameTag;
@@ -815,16 +689,19 @@ private:
int8_t mCurScanChannel;
#endif // OPENTHREAD_ENABLE_RAW_LINK_API
- uint32_t mFramingErrorCounter; // Number of improperly formed received spinel frames.
- uint32_t mRxSpinelFrameCounter; // Number of received (inbound) spinel frames.
- uint32_t mRxSpinelOutOfOrderTidCounter; // Number of out of order received spinel frames (tid increase > 1).
- uint32_t mTxSpinelFrameCounter; // Number of sent (outbound) spinel frames.
+#if OPENTHREAD_MTD || OPENTHREAD_FTD
uint32_t mInboundSecureIpFrameCounter; // Number of secure inbound data/IP frames.
uint32_t mInboundInsecureIpFrameCounter; // Number of insecure inbound data/IP frames.
uint32_t mOutboundSecureIpFrameCounter; // Number of secure outbound data/IP frames.
uint32_t mOutboundInsecureIpFrameCounter; // Number of insecure outbound data/IP frames.
uint32_t mDroppedOutboundIpFrameCounter; // Number of dropped outbound data/IP frames.
uint32_t mDroppedInboundIpFrameCounter; // Number of dropped inbound data/IP frames.
+#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
+ uint32_t mFramingErrorCounter; // Number of improperly formed received spinel frames.
+ uint32_t mRxSpinelFrameCounter; // Number of received (inbound) spinel frames.
+ uint32_t mRxSpinelOutOfOrderTidCounter; // Number of out of order received spinel frames (tid increase > 1).
+ uint32_t mTxSpinelFrameCounter; // Number of sent (outbound) spinel frames.
+
#if OPENTHREAD_ENABLE_LEGACY
const otNcpLegacyHandlers *mLegacyHandlers;
@@ -835,6 +712,7 @@ private:
};
+} // namespace Ncp
} // namespace ot
#endif // NCP_BASE_HPP_
diff --git a/src/ncp/ncp_base_ftd.cpp b/src/ncp/ncp_base_ftd.cpp
new file mode 100644
index 000000000..17948513d
--- /dev/null
+++ b/src/ncp/ncp_base_ftd.cpp
@@ -0,0 +1,857 @@
+/*
+ * Copyright (c) 2016-2017, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * This file implements full thread device specified Spinel interface to the OpenThread stack.
+ */
+
+#include
+#include "ncp_base.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#if OPENTHREAD_ENABLE_TMF_PROXY
+#include
+#endif
+
+#include "openthread-instance.h"
+#include "common/code_utils.hpp"
+#include "common/debug.hpp"
+#if OPENTHREAD_ENABLE_COMMISSIONER
+#include "meshcop/commissioner.hpp"
+#endif
+#include "net/ip6.hpp"
+
+#if OPENTHREAD_FTD
+namespace ot {
+namespace Ncp {
+
+otError NcpBase::GetPropertyHandler_THREAD_LOCAL_LEADER_WEIGHT(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT8_S,
+ otThreadGetLocalLeaderWeight(mInstance)
+ );
+}
+
+otError NcpBase::GetPropertyHandler_THREAD_LEADER_WEIGHT(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT8_S,
+ otThreadGetLeaderWeight(mInstance)
+ );
+}
+
+otError NcpBase::GetPropertyHandler_THREAD_CHILD_TABLE(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otError error = OT_ERROR_NONE;
+ otChildInfo childInfo;
+ uint8_t maxChildren;
+ uint8_t modeFlags;
+
+ mDisableStreamWrite = true;
+
+ SuccessOrExit(error = OutboundFrameBegin(aHeader));
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_COMMAND_PROP_S,
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey
+ ));
+
+ maxChildren = otThreadGetMaxAllowedChildren(mInstance);
+
+ for (uint8_t index = 0; index < maxChildren; index++)
+ {
+ error = otThreadGetChildInfoByIndex(mInstance, index, &childInfo);
+
+ if (error != OT_ERROR_NONE)
+ {
+ continue;
+ }
+
+ modeFlags = LinkFlagsToFlagByte(
+ childInfo.mRxOnWhenIdle,
+ childInfo.mSecureDataRequest,
+ childInfo.mFullFunction,
+ childInfo.mFullNetworkData
+ );
+
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_STRUCT_S(
+ SPINEL_DATATYPE_EUI64_S // EUI64 Address
+ SPINEL_DATATYPE_UINT16_S // Rloc16
+ SPINEL_DATATYPE_UINT32_S // Timeout
+ SPINEL_DATATYPE_UINT32_S // Age
+ SPINEL_DATATYPE_UINT8_S // Network Data Version
+ SPINEL_DATATYPE_UINT8_S // Link Quality In
+ SPINEL_DATATYPE_INT8_S // Average RSS
+ SPINEL_DATATYPE_UINT8_S // Mode (flags)
+ SPINEL_DATATYPE_INT8_S // Most recent RSS
+ ),
+ childInfo.mExtAddress.m8,
+ childInfo.mRloc16,
+ childInfo.mTimeout,
+ childInfo.mAge,
+ childInfo.mNetworkDataVersion,
+ childInfo.mLinkQualityIn,
+ childInfo.mAverageRssi,
+ modeFlags,
+ childInfo.mLastRssi
+ ));
+ }
+
+ SuccessOrExit(error = OutboundFrameSend());
+
+exit:
+ mDisableStreamWrite = false;
+ return error;
+}
+
+otError NcpBase::GetPropertyHandler_THREAD_ROUTER_ROLE_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_BOOL_S,
+ otThreadIsRouterRoleEnabled(mInstance)
+ );
+}
+
+otError NcpBase::SetPropertyHandler_THREAD_ROUTER_ROLE_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ bool enabled;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_BOOL_S,
+ &enabled
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ otThreadSetRouterRoleEnabled(mInstance, enabled);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_NET_PSKC(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_DATA_S,
+ otThreadGetPSKc(mInstance),
+ sizeof(spinel_net_pskc_t)
+ );
+}
+
+otError NcpBase::SetPropertyHandler_NET_PSKC(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ const uint8_t *ptr = NULL;
+ spinel_size_t len;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_DATA_S,
+ &ptr,
+ &len
+ );
+
+ VerifyOrExit((parsedLength > 0) && (len == sizeof(spinel_net_pskc_t)), error = OT_ERROR_PARSE);
+
+ error = otThreadSetPSKc(mInstance, ptr);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_THREAD_CHILD_COUNT_MAX(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT8_S,
+ otThreadGetMaxAllowedChildren(mInstance)
+ );
+}
+
+otError NcpBase::SetPropertyHandler_THREAD_CHILD_COUNT_MAX(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ uint8_t maxChildren = 0;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT8_S,
+ &maxChildren
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ error = otThreadSetMaxAllowedChildren(mInstance, maxChildren);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_THREAD_ROUTER_UPGRADE_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT8_S,
+ otThreadGetRouterUpgradeThreshold(mInstance)
+ );
+}
+
+otError NcpBase::SetPropertyHandler_THREAD_ROUTER_UPGRADE_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ uint8_t threshold = 0;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT8_S,
+ &threshold
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ otThreadSetRouterUpgradeThreshold(mInstance, threshold);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_THREAD_ROUTER_DOWNGRADE_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT8_S,
+ otThreadGetRouterDowngradeThreshold(mInstance)
+ );
+}
+
+otError NcpBase::SetPropertyHandler_THREAD_ROUTER_DOWNGRADE_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ uint8_t threshold = 0;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT8_S,
+ &threshold
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ otThreadSetRouterDowngradeThreshold(mInstance, threshold);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_THREAD_ROUTER_SELECTION_JITTER(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT8_S,
+ otThreadGetRouterSelectionJitter(mInstance)
+ );
+}
+
+otError NcpBase::SetPropertyHandler_THREAD_ROUTER_SELECTION_JITTER(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ uint8_t jitter = 0;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT8_S,
+ &jitter
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ otThreadSetRouterSelectionJitter(mInstance, jitter);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_THREAD_CONTEXT_REUSE_DELAY(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT32_S,
+ otThreadGetContextIdReuseDelay(mInstance)
+ );
+}
+
+otError NcpBase::SetPropertyHandler_THREAD_CONTEXT_REUSE_DELAY(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ uint32_t delay = 0;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT32_S,
+ &delay
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ otThreadSetContextIdReuseDelay(mInstance, delay);
+
+ exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_THREAD_NETWORK_ID_TIMEOUT(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT8_S,
+ otThreadGetNetworkIdTimeout(mInstance)
+ );
+}
+
+otError NcpBase::SetPropertyHandler_THREAD_NETWORK_ID_TIMEOUT(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ uint8_t timeout = 0;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT8_S,
+ &timeout
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ otThreadSetNetworkIdTimeout(mInstance, timeout);
+
+ exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+#if OPENTHREAD_ENABLE_COMMISSIONER
+otError NcpBase::GetPropertyHandler_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ bool enabled = false;
+
+ if (otCommissionerGetState(mInstance) == OT_COMMISSIONER_STATE_ACTIVE)
+ {
+ enabled = true;
+ }
+
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_BOOL_S,
+ enabled
+ );
+}
+
+otError NcpBase::SetPropertyHandler_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ bool enabled = false;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_BOOL_S,
+ &enabled
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ if (enabled == false)
+ {
+ error = otCommissionerStop(mInstance);
+ }
+ else
+ {
+ error = otCommissionerStart(mInstance);
+ }
+
+exit:
+ OT_UNUSED_VARIABLE(aKey);
+
+ return SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
+}
+
+otError NcpBase::InsertPropertyHandler_THREAD_JOINERS(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ otExtAddress *extAddress = NULL;
+ const char *aPSKd = NULL;
+ uint32_t joinerTimeout = 0;
+
+ VerifyOrExit(mAllowLocalNetworkDataChange == true, spinelError = SPINEL_STATUS_INVALID_STATE);
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ (
+ SPINEL_DATATYPE_UTF8_S // PSK
+ SPINEL_DATATYPE_UINT32_S // Timeout
+ SPINEL_DATATYPE_EUI64_S // Extended address
+ ),
+ &aPSKd,
+ &joinerTimeout,
+ &extAddress
+ );
+
+ if (parsedLength <= 0)
+ {
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ (
+ SPINEL_DATATYPE_UTF8_S // PSK
+ SPINEL_DATATYPE_UINT32_S // Timeout
+ ),
+ &aPSKd,
+ &joinerTimeout
+ );
+ extAddress = NULL;
+ }
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ error = otCommissionerAddJoiner(mInstance, extAddress, aPSKd, joinerTimeout);
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_INSERTED,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+
+#endif // OPENTHREAD_ENABLE_COMMISSIONER
+
+otError NcpBase::SetPropertyHandler_THREAD_LOCAL_LEADER_WEIGHT(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ uint8_t weight;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT8_S,
+ &weight
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ otThreadSetLocalLeaderWeight(mInstance, weight);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+#if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB
+otError NcpBase::SetPropertyHandler_THREAD_STEERING_DATA(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ otExtAddress *extAddress;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_EUI64_S,
+ &extAddress
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ error = otThreadSetSteeringData(mInstance, extAddress);
+
+exit:
+
+ if (error == OT_ERROR_NONE)
+ {
+ // Note that there is no get handler for this property.
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_EUI64_S,
+ extAddress->m8
+ );
+ }
+ else
+ {
+ error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
+ }
+
+ return error;
+}
+#endif // #if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB
+
+otError NcpBase::SetPropertyHandler_THREAD_CHILD_TIMEOUT(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ uint32_t timeout = 0;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT32_S,
+ &timeout
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ otThreadSetChildTimeout(mInstance, timeout);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::SetPropertyHandler_THREAD_PREFERRED_ROUTER_ID(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ uint8_t routerId = 0;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT8_S,
+ &routerId
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ error = otThreadSetPreferredRouterId(mInstance, routerId);
+
+exit:
+ if (error == OT_ERROR_NONE)
+ {
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT8_S,
+ routerId
+ );
+ }
+ else
+ {
+ error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
+ }
+
+ return error;
+}
+
+otError NcpBase::RemovePropertyHandler_THREAD_ACTIVE_ROUTER_IDS(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ uint8_t routerId;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT8_S,
+ &routerId
+ );
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ error = otThreadReleaseRouterId(mInstance, routerId);
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_REMOVED,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+
+#if OPENTHREAD_ENABLE_TMF_PROXY
+otError NcpBase::GetPropertyHandler_THREAD_TMF_PROXY_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_BOOL_S,
+ otTmfProxyIsEnabled(mInstance)
+ );
+}
+
+otError NcpBase::SetPropertyHandler_THREAD_TMF_PROXY_STREAM(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ const uint8_t *framePtr = NULL;
+ unsigned int frameLen = 0;
+ uint16_t locator;
+ uint16_t port;
+ otMessage *message;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ // THREAD_TMF_PROXY_STREAM requires layer 2 security.
+ message = otIp6NewMessage(mInstance, true);
+ VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS);
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ (
+ SPINEL_DATATYPE_DATA_WLEN_S // Frame data
+ SPINEL_DATATYPE_UINT16_S // Locator
+ SPINEL_DATATYPE_UINT16_S // Port
+ ),
+ &framePtr,
+ &frameLen,
+ &locator,
+ &port
+ );
+
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ SuccessOrExit(error = otMessageAppend(message, framePtr, static_cast(frameLen)));
+
+ error = otTmfProxySend(mInstance, message, locator, port);
+
+ // `otTmfProxySend()` takes ownership of `message` (in both success
+ // or failure cases). `message` is set to NULL so it is not freed at
+ // exit.
+ message = NULL;
+
+exit:
+ if (message != NULL)
+ {
+ otMessageFree(message);
+ }
+
+ if (error == OT_ERROR_NONE)
+ {
+ if (SPINEL_HEADER_GET_TID(aHeader) != 0)
+ {
+ // Only send a successful status update if
+ // there was a transaction id in the aHeader.
+ error = SendLastStatus(aHeader, SPINEL_STATUS_OK);
+ }
+ }
+ else
+ {
+ error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
+ }
+
+ OT_UNUSED_VARIABLE(aKey);
+
+ return error;
+}
+
+otError NcpBase::SetPropertyHandler_THREAD_TMF_PROXY_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ bool enabled;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_BOOL_S,
+ &enabled
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ if (enabled)
+ {
+ error = otTmfProxyStart(mInstance, &NcpBase::HandleTmfProxyStream, this);
+ }
+ else
+ {
+ error = otTmfProxyStop(mInstance);
+ }
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+void NcpBase::HandleTmfProxyStream(otMessage *aMessage, uint16_t aLocator, uint16_t aPort, void *aContext)
+{
+ static_cast(aContext)->HandleTmfProxyStream(aMessage, aLocator, aPort);
+}
+
+void NcpBase::HandleTmfProxyStream(otMessage *aMessage, uint16_t aLocator, uint16_t aPort)
+{
+ otError error = OT_ERROR_NONE;
+ uint16_t length = otMessageGetLength(aMessage);
+ uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0;
+
+ SuccessOrExit(error = OutboundFrameBegin(header));
+
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_COMMAND_PROP_S SPINEL_DATATYPE_UINT16_S,
+ header,
+ SPINEL_CMD_PROP_VALUE_IS,
+ SPINEL_PROP_THREAD_TMF_PROXY_STREAM,
+ length
+ ));
+
+ SuccessOrExit(error = OutboundFrameFeedMessage(aMessage));
+
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_UINT16_S SPINEL_DATATYPE_UINT16_S,
+ aLocator,
+ aPort
+ ));
+
+ // Set the `aMessage` pointer to NULL to indicate that it does
+ // not need to be freed at the exit. The `aMessage` is now owned
+ // by the OutboundFrame and will be freed when the frame is either
+ // successfully sent and then removed, or if the frame gets
+ // discarded.
+ aMessage = NULL;
+
+ SuccessOrExit(error = OutboundFrameSend());
+
+exit:
+
+ if (aMessage != NULL)
+ {
+ otMessageFree(aMessage);
+ }
+
+ if (error != OT_ERROR_NONE)
+ {
+ mChangedPropsSet.AddLastStatus(SPINEL_STATUS_DROPPED);
+ mUpdateChangedPropsTask.Post();
+ }
+}
+#endif // OPENTHREAD_ENABLE_TMF_PROXY
+
+} // namespace Ncp
+} // namespace ot
+
+#endif // OPENTHREAD_FTD
diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp
new file mode 100644
index 000000000..f846d1d3a
--- /dev/null
+++ b/src/ncp/ncp_base_mtd.cpp
@@ -0,0 +1,4268 @@
+/*
+ * Copyright (c) 2016-2017, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * This file implements minimal thread device required Spinel interface to the OpenThread stack.
+ */
+
+#include
+#include "ncp_base.hpp"
+
+#if OPENTHREAD_ENABLE_BORDER_ROUTER
+#include
+#endif
+#include
+#include
+#if OPENTHREAD_ENABLE_JAM_DETECTION
+#include
+#endif
+#include
+#include
+#include
+#include
+#if OPENTHREAD_FTD
+#include
+#endif
+
+#include "openthread-instance.h"
+#include "common/code_utils.hpp"
+#include "common/debug.hpp"
+#include "net/ip6.hpp"
+
+#if OPENTHREAD_MTD || OPENTHREAD_FTD
+
+namespace ot {
+namespace Ncp {
+
+static bool HasOnly1BitSet(uint32_t aValue)
+{
+ return aValue != 0 && ((aValue & (aValue - 1)) == 0);
+}
+
+static uint8_t IndexOfMSB(uint32_t aValue)
+{
+ uint8_t index = 0;
+
+ while (aValue >>= 1)
+ {
+ index++;
+ }
+
+ return index;
+}
+
+static uint8_t BorderRouterConfigToFlagByte(const otBorderRouterConfig &aConfig)
+{
+ uint8_t flags(0);
+
+ if (aConfig.mPreferred)
+ {
+ flags |= SPINEL_NET_FLAG_PREFERRED;
+ }
+
+ if (aConfig.mSlaac)
+ {
+ flags |= SPINEL_NET_FLAG_SLAAC;
+ }
+
+ if (aConfig.mDhcp)
+ {
+ flags |= SPINEL_NET_FLAG_DHCP;
+ }
+
+ if (aConfig.mDefaultRoute)
+ {
+ flags |= SPINEL_NET_FLAG_DEFAULT_ROUTE;
+ }
+
+ if (aConfig.mConfigure)
+ {
+ flags |= SPINEL_NET_FLAG_CONFIGURE;
+ }
+
+ if (aConfig.mOnMesh)
+ {
+ flags |= SPINEL_NET_FLAG_ON_MESH;
+ }
+
+ flags |= (aConfig.mPreference << SPINEL_NET_FLAG_PREFERENCE_OFFSET);
+
+ return flags;
+}
+
+static uint8_t ExternalRoutePreferenceToFlagByte(int aPreference)
+{
+ uint8_t flags;
+
+ switch (aPreference)
+ {
+ case OT_ROUTE_PREFERENCE_LOW:
+ flags = SPINEL_ROUTE_PREFERENCE_LOW;
+ break;
+
+ case OT_ROUTE_PREFERENCE_MED:
+ flags = SPINEL_ROUTE_PREFERENCE_MEDIUM;
+ break;
+
+ case OT_ROUTE_PREFERENCE_HIGH:
+ flags = SPINEL_ROUTE_PREFERENCE_HIGH;
+ break;
+
+ default:
+ flags = SPINEL_ROUTE_PREFERENCE_MEDIUM;
+ break;
+ }
+
+ return flags;
+}
+
+uint8_t NcpBase::LinkFlagsToFlagByte(bool aRxOnWhenIdle, bool aSecureDataRequests, bool aDeviceType, bool aNetworkData)
+{
+ uint8_t flags(0);
+
+ if (aRxOnWhenIdle)
+ {
+ flags |= SPINEL_THREAD_MODE_RX_ON_WHEN_IDLE;
+ }
+
+ if (aSecureDataRequests)
+ {
+ flags |= SPINEL_THREAD_MODE_SECURE_DATA_REQUEST;
+ }
+
+ if (aDeviceType)
+ {
+ flags |= SPINEL_THREAD_MODE_FULL_FUNCTION_DEV;
+ }
+
+ if (aNetworkData)
+ {
+ flags |= SPINEL_THREAD_MODE_FULL_NETWORK_DATA;
+ }
+
+ return flags;
+}
+
+otError NcpBase::GetPropertyHandler_MAC_DATA_POLL_PERIOD(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT32_S,
+ otLinkGetPollPeriod(mInstance)
+ );
+}
+
+otError NcpBase::SetPropertyHandler_MAC_DATA_POLL_PERIOD(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ uint32_t pollPeriod;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT32_S,
+ &pollPeriod
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ otLinkSetPollPeriod(mInstance, pollPeriod);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+
+otError NcpBase::GetPropertyHandler_MAC_EXTENDED_ADDR(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_EUI64_S,
+ otLinkGetExtendedAddress(mInstance)
+ );
+}
+
+otError NcpBase::GetPropertyHandler_PHY_FREQ(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ uint32_t freq_khz(0);
+ const uint8_t chan(otLinkGetChannel(mInstance));
+
+ if (chan == 0)
+ {
+ freq_khz = 868300;
+ }
+ else if (chan < 11)
+ {
+ freq_khz = 906000 - (2000 * 1) + 2000 * (chan);
+ }
+ else if (chan < 26)
+ {
+ freq_khz = 2405000 - (5000 * 11) + 5000 * (chan);
+ }
+
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT32_S,
+ freq_khz
+ );
+}
+
+otError NcpBase::GetPropertyHandler_PHY_CHAN_SUPPORTED(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return GetPropertyHandler_ChannelMaskHelper(aHeader, aKey, mSupportedChannelMask);
+}
+
+otError NcpBase::GetPropertyHandler_PHY_RSSI(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_INT8_S,
+ otPlatRadioGetRssi(mInstance)
+ );
+}
+
+otError NcpBase::CommandHandler_NET_SAVE(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr,
+ uint16_t aArgLen)
+{
+ OT_UNUSED_VARIABLE(aCommand);
+ OT_UNUSED_VARIABLE(aArgPtr);
+ OT_UNUSED_VARIABLE(aArgLen);
+
+ return SendLastStatus(aHeader, SPINEL_STATUS_UNIMPLEMENTED);
+}
+
+otError NcpBase::CommandHandler_NET_CLEAR(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr,
+ uint16_t aArgLen)
+{
+ OT_UNUSED_VARIABLE(aCommand);
+ OT_UNUSED_VARIABLE(aArgPtr);
+ OT_UNUSED_VARIABLE(aArgLen);
+
+ return SendLastStatus(aHeader, ThreadErrorToSpinelStatus(otInstanceErasePersistentInfo(mInstance)));
+}
+
+otError NcpBase::CommandHandler_NET_RECALL(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr,
+ uint16_t aArgLen)
+{
+ OT_UNUSED_VARIABLE(aCommand);
+ OT_UNUSED_VARIABLE(aArgPtr);
+ OT_UNUSED_VARIABLE(aArgLen);
+
+ return SendLastStatus(aHeader, SPINEL_STATUS_UNIMPLEMENTED);
+}
+
+otError NcpBase::GetPropertyHandler_NET_SAVED(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_BOOL_S,
+ otDatasetIsCommissioned(mInstance)
+ );
+}
+
+otError NcpBase::GetPropertyHandler_NET_IF_UP(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_BOOL_S,
+ otIp6IsEnabled(mInstance)
+ );
+}
+
+otError NcpBase::SetPropertyHandler_NET_IF_UP(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ bool enabled = false;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_BOOL_S,
+ &enabled
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ error = otIp6SetEnabled(mInstance, enabled);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_NET_STACK_UP(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_BOOL_S,
+ otThreadGetDeviceRole(mInstance) != OT_DEVICE_ROLE_DISABLED
+ );
+}
+
+otError NcpBase::SetPropertyHandler_NET_STACK_UP(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ bool enabled = false;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_BOOL_S,
+ &enabled
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ // If the value has changed...
+ if ((enabled != false) != (otThreadGetDeviceRole(mInstance) != OT_DEVICE_ROLE_DISABLED))
+ {
+ if (enabled != false)
+ {
+ error = otThreadSetEnabled(mInstance, true);
+
+#if OPENTHREAD_ENABLE_LEGACY
+ mLegacyNodeDidJoin = false;
+
+ if ((mLegacyHandlers != NULL) && (mLegacyHandlers->mStartLegacy != NULL))
+ {
+ mLegacyHandlers->mStartLegacy();
+ }
+#endif // OPENTHREAD_ENABLE_LEGACY
+ }
+ else
+ {
+ error = otThreadSetEnabled(mInstance, false);
+
+#if OPENTHREAD_ENABLE_LEGACY
+ mLegacyNodeDidJoin = false;
+
+ if ((mLegacyHandlers != NULL) && (mLegacyHandlers->mStopLegacy != NULL))
+ {
+ mLegacyHandlers->mStopLegacy();
+ }
+#endif // OPENTHREAD_ENABLE_LEGACY
+ }
+ }
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_NET_ROLE(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ spinel_net_role_t role(SPINEL_NET_ROLE_DETACHED);
+
+ switch (otThreadGetDeviceRole(mInstance))
+ {
+ case OT_DEVICE_ROLE_DISABLED:
+ case OT_DEVICE_ROLE_DETACHED:
+ role = SPINEL_NET_ROLE_DETACHED;
+ break;
+
+ case OT_DEVICE_ROLE_CHILD:
+ role = SPINEL_NET_ROLE_CHILD;
+ break;
+
+ case OT_DEVICE_ROLE_ROUTER:
+ role = SPINEL_NET_ROLE_ROUTER;
+ break;
+
+ case OT_DEVICE_ROLE_LEADER:
+ role = SPINEL_NET_ROLE_LEADER;
+ break;
+ }
+
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT8_S,
+ role
+ );
+}
+
+otError NcpBase::SetPropertyHandler_NET_ROLE(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ unsigned int role = 0;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT_PACKED_S,
+ &role
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+
+ switch (role)
+ {
+ case SPINEL_NET_ROLE_DETACHED:
+ error = otThreadBecomeDetached(mInstance);
+ break;
+
+#if OPENTHREAD_FTD
+ case SPINEL_NET_ROLE_ROUTER:
+ error = otThreadBecomeRouter(mInstance);
+ break;
+
+ case SPINEL_NET_ROLE_LEADER:
+ error = otThreadBecomeLeader(mInstance);
+ break;
+#endif // OPENTHREAD_FTD
+
+ case SPINEL_NET_ROLE_CHILD:
+ error = otThreadBecomeChild(mInstance);
+ break;
+ }
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_NET_NETWORK_NAME(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UTF8_S,
+ otThreadGetNetworkName(mInstance)
+ );
+}
+
+otError NcpBase::SetPropertyHandler_NET_NETWORK_NAME(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ const char *string = NULL;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UTF8_S,
+ &string
+ );
+
+ VerifyOrExit((parsedLength > 0) && (string != NULL), error = OT_ERROR_PARSE);
+
+ error = otThreadSetNetworkName(mInstance, string);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_NET_XPANID(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_DATA_S,
+ otThreadGetExtendedPanId(mInstance),
+ sizeof(spinel_net_xpanid_t)
+ );
+}
+
+otError NcpBase::SetPropertyHandler_NET_XPANID(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ const uint8_t *ptr = NULL;
+ spinel_size_t len;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_DATA_S,
+ &ptr,
+ &len
+ );
+
+ VerifyOrExit((parsedLength > 0) && (len == sizeof(spinel_net_xpanid_t)), error = OT_ERROR_PARSE);
+
+ error = otThreadSetExtendedPanId(mInstance, ptr);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_NET_MASTER_KEY(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_DATA_S,
+ otThreadGetMasterKey(mInstance)->m8,
+ OT_MASTER_KEY_SIZE
+ );
+}
+
+otError NcpBase::SetPropertyHandler_NET_MASTER_KEY(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ const uint8_t *ptr = NULL;
+ spinel_size_t len;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_DATA_S,
+ &ptr,
+ &len
+ );
+
+ VerifyOrExit((parsedLength > 0) && (len == OT_MASTER_KEY_SIZE), error = OT_ERROR_PARSE);
+
+ error = otThreadSetMasterKey(mInstance, reinterpret_cast(ptr));
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_NET_KEY_SEQUENCE_COUNTER(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT32_S,
+ otThreadGetKeySequenceCounter(mInstance)
+ );
+}
+
+otError NcpBase::SetPropertyHandler_NET_KEY_SEQUENCE_COUNTER(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ unsigned int keySeqCounter;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT32_S,
+ &keySeqCounter
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ otThreadSetKeySequenceCounter(mInstance, keySeqCounter);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_NET_PARTITION_ID(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT32_S,
+ otThreadGetPartitionId(mInstance)
+ );
+}
+
+otError NcpBase::GetPropertyHandler_NET_KEY_SWITCH_GUARDTIME(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT32_S,
+ otThreadGetKeySwitchGuardTime(mInstance)
+ );
+}
+
+otError NcpBase::SetPropertyHandler_NET_KEY_SWITCH_GUARDTIME(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ unsigned int keyGuardTime;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT32_S,
+ &keyGuardTime
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ otThreadSetKeySwitchGuardTime(mInstance, keyGuardTime);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_THREAD_NETWORK_DATA_VERSION(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT8_S,
+ otNetDataGetVersion(mInstance)
+ );
+}
+
+otError NcpBase::GetPropertyHandler_THREAD_STABLE_NETWORK_DATA_VERSION(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT8_S,
+ otNetDataGetStableVersion(mInstance)
+ );
+}
+
+#if OPENTHREAD_ENABLE_BORDER_ROUTER
+otError NcpBase::GetPropertyHandler_THREAD_NETWORK_DATA(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otError error = OT_ERROR_NONE;
+ uint8_t networkData[255];
+ uint8_t networkDataLen = 255;
+
+ otBorderRouterGetNetData(
+ mInstance,
+ false, // Stable?
+ networkData,
+ &networkDataLen
+ );
+
+ SuccessOrExit(error = OutboundFrameBegin(aHeader));
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_COMMAND_PROP_S,
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey
+ ));
+ SuccessOrExit(error = OutboundFrameFeedData(networkData, networkDataLen));
+ SuccessOrExit(error = OutboundFrameSend());
+
+exit:
+ return error;
+}
+
+otError NcpBase::GetPropertyHandler_THREAD_STABLE_NETWORK_DATA(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otError error = OT_ERROR_NONE;
+ uint8_t networkData[255];
+ uint8_t networkDataLen = 255;
+
+ otBorderRouterGetNetData(
+ mInstance,
+ true, // Stable?
+ networkData,
+ &networkDataLen
+ );
+
+ SuccessOrExit(error = OutboundFrameBegin(aHeader));
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_COMMAND_PROP_S,
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey
+ ));
+ SuccessOrExit(error = OutboundFrameFeedData(networkData, networkDataLen));
+ SuccessOrExit(error = OutboundFrameSend());
+
+exit:
+ return error;
+}
+#endif // OPENTHREAD_ENABLE_BORDER_ROUTER
+
+otError NcpBase::GetPropertyHandler_THREAD_LEADER_NETWORK_DATA(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otError error = OT_ERROR_NONE;
+ uint8_t networkData[255];
+ uint8_t networkDataLen = 255;
+
+ otNetDataGet(
+ mInstance,
+ false, // Stable?
+ networkData,
+ &networkDataLen
+ );
+
+ SuccessOrExit(error = OutboundFrameBegin(aHeader));
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_COMMAND_PROP_S,
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey
+ ));
+ SuccessOrExit(error = OutboundFrameFeedData(networkData, networkDataLen));
+ SuccessOrExit(error = OutboundFrameSend());
+
+exit:
+ return error;
+}
+
+otError NcpBase::GetPropertyHandler_THREAD_STABLE_LEADER_NETWORK_DATA(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otError error = OT_ERROR_NONE;
+ uint8_t networkData[255];
+ uint8_t networkDataLen = 255;
+
+ otNetDataGet(
+ mInstance,
+ true, // Stable?
+ networkData,
+ &networkDataLen
+ );
+
+ SuccessOrExit(error = OutboundFrameBegin(aHeader));
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_COMMAND_PROP_S,
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey
+ ));
+ SuccessOrExit(error = OutboundFrameFeedData(networkData, networkDataLen));
+ SuccessOrExit(error = OutboundFrameSend());
+
+exit:
+ return error;
+}
+
+otError NcpBase::GetPropertyHandler_THREAD_LEADER_RID(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT8_S,
+ otThreadGetLeaderRouterId(mInstance)
+ );
+}
+
+
+
+otError NcpBase::GetPropertyHandler_THREAD_LEADER_ADDR(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otError error = OT_ERROR_NONE;
+ otIp6Address address;
+
+ error = otThreadGetLeaderRloc(mInstance, &address);
+
+ if (error == OT_ERROR_NONE)
+ {
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_IPv6ADDR_S,
+ &address
+ );
+ }
+ else
+ {
+ error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
+ }
+
+ return error;
+}
+
+otError NcpBase::GetPropertyHandler_THREAD_PARENT(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otError error = OT_ERROR_NONE;
+ otRouterInfo parentInfo;
+
+ error = otThreadGetParentInfo(mInstance, &parentInfo);
+
+ if (error == OT_ERROR_NONE)
+ {
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ (
+ SPINEL_DATATYPE_EUI64_S // Parent's extended address
+ SPINEL_DATATYPE_UINT16_S // Parent's rloc16
+ ),
+ parentInfo.mExtAddress.m8,
+ parentInfo.mRloc16
+ );
+ }
+ else
+ {
+ error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
+ }
+
+ return error;
+}
+
+otError NcpBase::GetPropertyHandler_THREAD_NEIGHBOR_TABLE(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otError error = OT_ERROR_NONE;
+ otNeighborInfoIterator iter = OT_NEIGHBOR_INFO_ITERATOR_INIT;
+ otNeighborInfo neighInfo;
+ uint8_t modeFlags;
+
+ mDisableStreamWrite = true;
+
+ SuccessOrExit(error = OutboundFrameBegin(aHeader));
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_COMMAND_PROP_S,
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey
+ ));
+
+ while (otThreadGetNextNeighborInfo(mInstance, &iter, &neighInfo) == OT_ERROR_NONE)
+ {
+ modeFlags = LinkFlagsToFlagByte(
+ neighInfo.mRxOnWhenIdle,
+ neighInfo.mSecureDataRequest,
+ neighInfo.mFullFunction,
+ neighInfo.mFullNetworkData
+ );
+
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_STRUCT_S(
+ SPINEL_DATATYPE_EUI64_S // EUI64 Address
+ SPINEL_DATATYPE_UINT16_S // Rloc16
+ SPINEL_DATATYPE_UINT32_S // Age
+ SPINEL_DATATYPE_UINT8_S // Link Quality In
+ SPINEL_DATATYPE_INT8_S // Average RSS
+ SPINEL_DATATYPE_UINT8_S // Mode (flags)
+ SPINEL_DATATYPE_BOOL_S // Is Child
+ SPINEL_DATATYPE_UINT32_S // Link Frame Counter
+ SPINEL_DATATYPE_UINT32_S // MLE Frame Counter
+ SPINEL_DATATYPE_INT8_S // Most recent RSS
+ ),
+ neighInfo.mExtAddress.m8,
+ neighInfo.mRloc16,
+ neighInfo.mAge,
+ neighInfo.mLinkQualityIn,
+ neighInfo.mAverageRssi,
+ modeFlags,
+ neighInfo.mIsChild,
+ neighInfo.mLinkFrameCounter,
+ neighInfo.mMleFrameCounter,
+ neighInfo.mLastRssi
+ ));
+ }
+
+ SuccessOrExit(error = OutboundFrameSend());
+
+exit:
+ mDisableStreamWrite = false;
+ return error;
+}
+
+otError NcpBase::GetPropertyHandler_THREAD_ASSISTING_PORTS(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otError error = OT_ERROR_NONE;
+ uint8_t numEntries = 0;
+ const uint16_t *ports = otIp6GetUnsecurePorts(mInstance, &numEntries);
+
+ SuccessOrExit(error = OutboundFrameBegin(aHeader));
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_COMMAND_PROP_S,
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey
+ ));
+
+ for (; numEntries != 0; ports++, numEntries--)
+ {
+ SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT16_S, *ports));
+ }
+
+ SuccessOrExit(error = OutboundFrameSend());
+
+exit:
+ return error;
+}
+
+otError NcpBase::SetPropertyHandler_THREAD_ASSISTING_PORTS(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ uint8_t numEntries = 0;
+ const uint16_t *ports = otIp6GetUnsecurePorts(mInstance, &numEntries);
+ spinel_ssize_t parsedLength;
+ bool portsChanged = false;
+ otError error = OT_ERROR_NONE;
+
+ // First, we need to remove all of the current assisting ports.
+ for (; numEntries != 0; ports++, numEntries--)
+ {
+ SuccessOrExit(error = otIp6RemoveUnsecurePort(mInstance, *ports));
+ portsChanged = true;
+ }
+
+ while (aValueLen >= 2)
+ {
+ uint16_t port;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT16_S,
+ &port
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ SuccessOrExit(error = otIp6AddUnsecurePort(mInstance, port));
+
+ aValuePtr += parsedLength;
+ aValueLen -= parsedLength;
+
+ portsChanged = true;
+ }
+
+ // No error happened so the new state of ports will
+ // be reported in the response.
+ portsChanged = false;
+
+exit:
+ error = SendSetPropertyResponse(aHeader, aKey, error);
+
+ if (portsChanged)
+ {
+ // We had an error, but we've actually changed
+ // the state of these ports---so we need to report
+ // those incomplete changes via an asynchronous
+ // change event.
+ HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, aKey);
+ }
+
+ return error;
+}
+
+otError NcpBase::GetPropertyHandler_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_BOOL_S,
+ mAllowLocalNetworkDataChange
+ );
+}
+
+#if OPENTHREAD_ENABLE_BORDER_ROUTER
+otError NcpBase::SetPropertyHandler_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ bool value = false;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ bool shouldRegisterWithLeader = false;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_BOOL_S,
+ &value
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ // Register any net data changes on transition from `true` to `false`.
+ shouldRegisterWithLeader = (mAllowLocalNetworkDataChange == true) && (value == false);
+
+ mAllowLocalNetworkDataChange = value;
+
+exit:
+ error = SendSetPropertyResponse(aHeader, aKey, error);
+
+ if (shouldRegisterWithLeader)
+ {
+ otBorderRouterRegister(mInstance);
+ }
+
+ return error;
+}
+#endif // OPENTHREAD_ENABLE_BORDER_ROUTER
+
+otError NcpBase::GetPropertyHandler_THREAD_ON_MESH_NETS(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otError error = OT_ERROR_NONE;
+ otBorderRouterConfig borderRouterConfig;
+ uint8_t flags;
+
+ mDisableStreamWrite = true;
+
+ SuccessOrExit(error = OutboundFrameBegin(aHeader));
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_COMMAND_PROP_S,
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey
+ ));
+
+ // Fill from non-local network data first
+ for (otNetworkDataIterator iter = OT_NETWORK_DATA_ITERATOR_INIT ;;)
+ {
+ error = otNetDataGetNextOnMeshPrefix(mInstance, &iter, &borderRouterConfig);
+
+ if (error != OT_ERROR_NONE)
+ {
+ break;
+ }
+
+ flags = BorderRouterConfigToFlagByte(borderRouterConfig);
+
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_STRUCT_S(
+ SPINEL_DATATYPE_IPv6ADDR_S // IPv6 Prefix
+ SPINEL_DATATYPE_UINT8_S // Prefix Length (in bits)
+ SPINEL_DATATYPE_BOOL_S // isStable
+ SPINEL_DATATYPE_UINT8_S // Flags
+ SPINEL_DATATYPE_BOOL_S // isLocal
+ ),
+ &borderRouterConfig.mPrefix,
+ 64,
+ borderRouterConfig.mStable,
+ flags,
+ false
+ ));
+ }
+
+#if OPENTHREAD_ENABLE_BORDER_ROUTER
+ // Fill from local network data last
+ for (otNetworkDataIterator iter = OT_NETWORK_DATA_ITERATOR_INIT ;;)
+ {
+ error = otBorderRouterGetNextOnMeshPrefix(mInstance, &iter, &borderRouterConfig);
+
+ if (error != OT_ERROR_NONE)
+ {
+ break;
+ }
+
+ flags = BorderRouterConfigToFlagByte(borderRouterConfig);
+
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_STRUCT_S(
+ SPINEL_DATATYPE_IPv6ADDR_S // IPv6 Prefix
+ SPINEL_DATATYPE_UINT8_S // Prefix Length (in bits)
+ SPINEL_DATATYPE_BOOL_S // isStable
+ SPINEL_DATATYPE_UINT8_S // Flags
+ SPINEL_DATATYPE_BOOL_S // isLocal
+ ),
+ &borderRouterConfig.mPrefix,
+ 64,
+ borderRouterConfig.mStable,
+ flags,
+ true
+ ));
+ }
+#endif // OPENTHREAD_ENABLE_BORDER_ROUTER
+
+ SuccessOrExit(error = OutboundFrameSend());
+
+exit:
+ mDisableStreamWrite = false;
+ return error;
+}
+
+#if OPENTHREAD_ENABLE_BORDER_ROUTER
+otError NcpBase::InsertPropertyHandler_THREAD_ON_MESH_NETS(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ otBorderRouterConfig borderRouterConfig;
+ otIp6Address *addrPtr;
+ bool stable = false;
+ uint8_t flags = 0;
+
+ memset(&borderRouterConfig, 0, sizeof(otBorderRouterConfig));
+
+ VerifyOrExit(mAllowLocalNetworkDataChange == true, spinelError = SPINEL_STATUS_INVALID_STATE);
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ (
+ SPINEL_DATATYPE_IPv6ADDR_S // On-mesh prefix
+ SPINEL_DATATYPE_UINT8_S // Prefix length (in bits)
+ SPINEL_DATATYPE_BOOL_S // Stable
+ SPINEL_DATATYPE_UINT8_S // Flags
+ ),
+ &addrPtr,
+ &borderRouterConfig.mPrefix.mLength,
+ &stable,
+ &flags
+ );
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ borderRouterConfig.mPrefix.mPrefix = *addrPtr;
+ borderRouterConfig.mStable = stable;
+ borderRouterConfig.mPreference =
+ ((flags & SPINEL_NET_FLAG_PREFERENCE_MASK) >> SPINEL_NET_FLAG_PREFERENCE_OFFSET);
+ borderRouterConfig.mPreferred = ((flags & SPINEL_NET_FLAG_PREFERRED) != 0);
+ borderRouterConfig.mSlaac = ((flags & SPINEL_NET_FLAG_SLAAC) != 0);
+ borderRouterConfig.mDhcp = ((flags & SPINEL_NET_FLAG_DHCP) != 0);
+ borderRouterConfig.mConfigure = ((flags & SPINEL_NET_FLAG_CONFIGURE) != 0);
+ borderRouterConfig.mDefaultRoute = ((flags & SPINEL_NET_FLAG_DEFAULT_ROUTE) != 0);
+ borderRouterConfig.mOnMesh = ((flags & SPINEL_NET_FLAG_ON_MESH) != 0);
+
+ error = otBorderRouterAddOnMeshPrefix(mInstance, &borderRouterConfig);
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_INSERTED,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+
+otError NcpBase::RemovePropertyHandler_THREAD_ON_MESH_NETS(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ otIp6Prefix ip6Prefix;
+ otIp6Address *addrPtr;
+
+ memset(&ip6Prefix, 0, sizeof(otIp6Prefix));
+
+ VerifyOrExit(mAllowLocalNetworkDataChange == true, spinelError = SPINEL_STATUS_INVALID_STATE);
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ (
+ SPINEL_DATATYPE_IPv6ADDR_S // On-mesh prefix
+ SPINEL_DATATYPE_UINT8_S // Prefix length (in bits)
+ ),
+ &addrPtr,
+ &ip6Prefix.mLength
+ );
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ ip6Prefix.mPrefix = *addrPtr;
+
+ error = otBorderRouterRemoveOnMeshPrefix(mInstance, &ip6Prefix);
+
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_REMOVED,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+#endif // OPENTHREAD_ENABLE_BORDER_ROUTER
+
+otError NcpBase::GetPropertyHandler_THREAD_DISCOVERY_SCAN_JOINER_FLAG(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_BOOL_S,
+ mDiscoveryScanJoinerFlag
+ );
+}
+
+otError NcpBase::SetPropertyHandler_THREAD_DISCOVERY_SCAN_JOINER_FLAG(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ bool joinerFlag = false;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_BOOL_S,
+ &joinerFlag
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ mDiscoveryScanJoinerFlag = joinerFlag;
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_THREAD_DISCOVERY_SCAN_ENABLE_FILTERING(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_BOOL_S,
+ mDiscoveryScanEnableFiltering
+ );
+}
+
+otError NcpBase::SetPropertyHandler_THREAD_DISCOVERY_SCAN_ENABLE_FILTERING(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ bool enabled = false;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_BOOL_S,
+ &enabled
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ mDiscoveryScanEnableFiltering = enabled;
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_THREAD_DISCOVERY_SCAN_PANID(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT16_S,
+ mDiscoveryScanPanId
+ );
+}
+
+otError NcpBase::SetPropertyHandler_THREAD_DISCOVERY_SCAN_PANID(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ uint16_t panid;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT16_S,
+ &panid
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ mDiscoveryScanPanId = panid;
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_IPV6_ML_PREFIX(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otError error = OT_ERROR_NONE;
+ const uint8_t *mlPrefix = otThreadGetMeshLocalPrefix(mInstance);
+
+ if (mlPrefix)
+ {
+ otIp6Address addr;
+
+ memcpy(addr.mFields.m8, mlPrefix, 8);
+
+ // Zero out the last 8 bytes.
+ memset(addr.mFields.m8 + 8, 0, 8);
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ (
+ SPINEL_DATATYPE_IPv6ADDR_S // Mesh-local IPv6 address
+ SPINEL_DATATYPE_UINT8_S // Prefix length (in bits)
+ ),
+ &addr,
+ 64
+ );
+ }
+ else
+ {
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_VOID_S
+ );
+ }
+
+ return error;
+}
+
+otError NcpBase::SetPropertyHandler_IPV6_ML_PREFIX(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ otError error = OT_ERROR_NONE;
+
+ VerifyOrExit(aValueLen >= 8, error = OT_ERROR_PARSE);
+
+ error = otThreadSetMeshLocalPrefix(mInstance, aValuePtr);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_IPV6_ML_ADDR(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otError error = OT_ERROR_NONE;
+ const otIp6Address *ml64 = otThreadGetMeshLocalEid(mInstance);
+
+ if (ml64)
+ {
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_IPv6ADDR_S,
+ ml64
+ );
+ }
+ else
+ {
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_VOID_S
+ );
+ }
+
+ return error;
+}
+
+otError NcpBase::GetPropertyHandler_IPV6_LL_ADDR(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otError error = OT_ERROR_NONE;
+ const otIp6Address *address = otThreadGetLinkLocalIp6Address(mInstance);
+
+ if (address)
+ {
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_IPv6ADDR_S,
+ address
+ );
+ }
+ else
+ {
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_VOID_S
+ );
+ }
+
+ return error;
+}
+
+otError NcpBase::GetPropertyHandler_IPV6_ADDRESS_TABLE(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otError error = OT_ERROR_NONE;
+
+ mDisableStreamWrite = true;
+
+ SuccessOrExit(error = OutboundFrameBegin(aHeader));
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_COMMAND_PROP_S,
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey
+ ));
+
+ for (const otNetifAddress *address = otIp6GetUnicastAddresses(mInstance); address; address = address->mNext)
+ {
+
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_STRUCT_S(
+ SPINEL_DATATYPE_IPv6ADDR_S // IPv6 address
+ SPINEL_DATATYPE_UINT8_S // Prefix length (in bits)
+ SPINEL_DATATYPE_UINT32_S // Preferred lifetime
+ SPINEL_DATATYPE_UINT32_S // Valid lifetime
+ ),
+ &address->mAddress,
+ address->mPrefixLength,
+ address->mPreferred ? 0xffffffff : 0,
+ address->mValid ? 0xffffffff : 0
+ ));
+ }
+
+ SuccessOrExit(error = OutboundFrameSend());
+
+exit:
+ mDisableStreamWrite = false;
+ return error;
+}
+
+otError NcpBase::InsertPropertyHandler_IPV6_ADDRESS_TABLE(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ otNetifAddress netifAddr;
+ otIp6Address *addrPtr;
+ uint32_t preferredLifetime;
+ uint32_t validLifetime;
+ uint8_t prefixLen;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ (
+ SPINEL_DATATYPE_IPv6ADDR_S // IPv6 address
+ SPINEL_DATATYPE_UINT8_S // Prefix length (in bits)
+ SPINEL_DATATYPE_UINT32_S // Preferred lifetime
+ SPINEL_DATATYPE_UINT32_S // Valid lifetime
+ ),
+ &addrPtr,
+ &prefixLen,
+ &preferredLifetime,
+ &validLifetime
+ );
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ netifAddr.mAddress = *addrPtr;
+ netifAddr.mPrefixLength = prefixLen;
+ netifAddr.mPreferred = preferredLifetime != 0;
+ netifAddr.mValid = validLifetime != 0;
+
+ error = otIp6AddUnicastAddress(mInstance, &netifAddr);
+
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_INSERTED,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+ spinelError = SPINEL_STATUS_OK;
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+
+otError NcpBase::RemovePropertyHandler_IPV6_ADDRESS_TABLE(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ otIp6Address *addrPtr;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_IPv6ADDR_S,
+ &addrPtr
+ );
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ error = otIp6RemoveUnicastAddress(mInstance, addrPtr);
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_REMOVED,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+
+otError NcpBase::GetPropertyHandler_IPV6_ROUTE_TABLE(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ // TODO: Implement get route table
+ OT_UNUSED_VARIABLE(aKey);
+
+ return SendLastStatus(aHeader, SPINEL_STATUS_UNIMPLEMENTED);
+}
+
+otError NcpBase::GetPropertyHandler_IPV6_ICMP_PING_OFFLOAD(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_BOOL_S,
+ otIcmp6IsEchoEnabled(mInstance)
+ );
+}
+
+otError NcpBase::SetPropertyHandler_IPV6_ICMP_PING_OFFLOAD(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ bool enabled = false;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_BOOL_S,
+ &enabled
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ otIcmp6SetEchoEnabled(mInstance, enabled);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_IPV6_MULTICAST_ADDRESS_TABLE(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otError error = OT_ERROR_NONE;
+ const otNetifMulticastAddress *address;
+
+ mDisableStreamWrite = true;
+
+ SuccessOrExit(error = OutboundFrameBegin(aHeader));
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_COMMAND_PROP_S,
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey
+ ));
+
+ for (address = otIp6GetMulticastAddresses(mInstance); address; address = address->mNext)
+ {
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_STRUCT_S(
+ SPINEL_DATATYPE_IPv6ADDR_S // IPv6 address
+ ),
+ &address->mAddress
+ ));
+ }
+
+ SuccessOrExit(error = OutboundFrameSend());
+
+exit:
+ mDisableStreamWrite = false;
+ return error;
+}
+
+otError NcpBase::InsertPropertyHandler_IPV6_MULTICAST_ADDRESS_TABLE(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ otIp6Address *addrPtr;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_IPv6ADDR_S, // IPv6 address
+ &addrPtr
+ );
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ error = otIp6SubscribeMulticastAddress(mInstance, addrPtr);
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_INSERTED,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+ spinelError = SPINEL_STATUS_OK;
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+
+otError NcpBase::RemovePropertyHandler_IPV6_MULTICAST_ADDRESS_TABLE(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ otIp6Address *addrPtr;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_IPv6ADDR_S,
+ &addrPtr
+ );
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ error = otIp6UnsubscribeMulticastAddress(mInstance, addrPtr);
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_REMOVED,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+
+otError NcpBase::GetPropertyHandler_THREAD_RLOC16_DEBUG_PASSTHRU(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ // Note reverse logic: passthru enabled = filter disabled
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_BOOL_S,
+ !otIp6IsReceiveFilterEnabled(mInstance)
+ );
+}
+
+otError NcpBase::SetPropertyHandler_THREAD_RLOC16_DEBUG_PASSTHRU(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ bool enabled = false;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_BOOL_S,
+ &enabled
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ // Note reverse logic: passthru enabled = filter disabled
+ otIp6SetReceiveFilterEnabled(mInstance, !enabled);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_THREAD_OFF_MESH_ROUTES(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otError error = OT_ERROR_NONE;
+ otExternalRouteConfig external_route_config;
+ otNetworkDataIterator iter = OT_NETWORK_DATA_ITERATOR_INIT;
+
+ mDisableStreamWrite = true;
+
+ SuccessOrExit(error = OutboundFrameBegin(aHeader));
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_COMMAND_PROP_S,
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey
+ ));
+
+ while (otNetDataGetNextRoute(mInstance, &iter, &external_route_config) == OT_ERROR_NONE)
+ {
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_STRUCT_S(
+ SPINEL_DATATYPE_IPv6ADDR_S // IPv6 Prefix
+ SPINEL_DATATYPE_UINT8_S // Prefix Length (in bits)
+ SPINEL_DATATYPE_BOOL_S // IsStable
+ SPINEL_DATATYPE_UINT8_S // Route Preference Flags
+ SPINEL_DATATYPE_BOOL_S // IsLocal
+ SPINEL_DATATYPE_BOOL_S // NextHopIsThisDevice
+ ),
+ &external_route_config.mPrefix.mPrefix,
+ external_route_config.mPrefix.mLength,
+ external_route_config.mStable,
+ ExternalRoutePreferenceToFlagByte(external_route_config.mPreference),
+ false,
+ external_route_config.mNextHopIsThisDevice
+ ));
+ }
+
+#if OPENTHREAD_ENABLE_BORDER_ROUTER
+ while (otBorderRouterGetNextRoute(mInstance, &iter, &external_route_config) == OT_ERROR_NONE)
+ {
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_STRUCT_S(
+ SPINEL_DATATYPE_IPv6ADDR_S // IPv6 Prefix
+ SPINEL_DATATYPE_UINT8_S // Prefix Length (in bits)
+ SPINEL_DATATYPE_BOOL_S // IsStable
+ SPINEL_DATATYPE_UINT8_S // Route Preference Flags
+ SPINEL_DATATYPE_BOOL_S // IsLocal
+ SPINEL_DATATYPE_BOOL_S // NextHopIsThisDevice
+ ),
+ &external_route_config.mPrefix.mPrefix,
+ external_route_config.mPrefix.mLength,
+ external_route_config.mStable,
+ ExternalRoutePreferenceToFlagByte(external_route_config.mPreference),
+ true,
+ external_route_config.mNextHopIsThisDevice
+ ));
+ }
+#endif // OPENTHREAD_ENABLE_BORDER_ROUTER
+
+ SuccessOrExit(error = OutboundFrameSend());
+
+exit:
+ mDisableStreamWrite = false;
+ return error;
+}
+
+#if OPENTHREAD_ENABLE_BORDER_ROUTER
+static int FlagByteToExternalRoutePreference(uint8_t aFlags)
+{
+ int route_preference = 0;
+
+ switch (aFlags & SPINEL_NET_FLAG_PREFERENCE_MASK)
+ {
+ case SPINEL_ROUTE_PREFERENCE_HIGH:
+ route_preference = OT_ROUTE_PREFERENCE_HIGH;
+ break;
+
+ case SPINEL_ROUTE_PREFERENCE_MEDIUM:
+ route_preference = OT_ROUTE_PREFERENCE_MED;
+ break;
+
+ case SPINEL_ROUTE_PREFERENCE_LOW:
+ route_preference = OT_ROUTE_PREFERENCE_LOW;
+ break;
+ }
+
+ return route_preference;
+}
+
+otError NcpBase::InsertPropertyHandler_THREAD_OFF_MESH_ROUTES(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ otExternalRouteConfig routeConfig;
+ otIp6Address *addrPtr;
+ bool stable = false;
+ uint8_t flags = 0;
+
+ memset(&routeConfig, 0, sizeof(otExternalRouteConfig));
+
+ VerifyOrExit(mAllowLocalNetworkDataChange == true, spinelError = SPINEL_STATUS_INVALID_STATE);
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ (
+ SPINEL_DATATYPE_IPv6ADDR_S // Route prefix
+ SPINEL_DATATYPE_UINT8_S // Prefix length (in bits)
+ SPINEL_DATATYPE_BOOL_S // Stable
+ SPINEL_DATATYPE_UINT8_S // Flags (Route Preference)
+ ),
+ &addrPtr,
+ &routeConfig.mPrefix.mLength,
+ &stable,
+ &flags
+ );
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ routeConfig.mPrefix.mPrefix = *addrPtr;
+ routeConfig.mStable = stable;
+ routeConfig.mPreference = FlagByteToExternalRoutePreference(flags);
+
+ error = otBorderRouterAddRoute(mInstance, &routeConfig);
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_INSERTED,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+
+otError NcpBase::RemovePropertyHandler_THREAD_OFF_MESH_ROUTES(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ otIp6Prefix ip6Prefix;
+ otIp6Address *addrPtr;
+
+ memset(&ip6Prefix, 0, sizeof(otIp6Prefix));
+
+ VerifyOrExit(mAllowLocalNetworkDataChange == true, spinelError = SPINEL_STATUS_INVALID_STATE);
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ (
+ SPINEL_DATATYPE_IPv6ADDR_S // Route prefix
+ SPINEL_DATATYPE_UINT8_S // Prefix length (in bits)
+ ),
+ &addrPtr,
+ &ip6Prefix.mLength
+ );
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ ip6Prefix.mPrefix = *addrPtr;
+
+ error = otBorderRouterRemoveRoute(mInstance, &ip6Prefix);
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_REMOVED,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+#endif // OPENTHREAD_ENABLE_BORDER_ROUTER
+
+otError NcpBase::GetPropertyHandler_STREAM_NET(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ // TODO: Implement explicit data poll.
+ OT_UNUSED_VARIABLE(aKey);
+
+ return SendLastStatus(aHeader, SPINEL_STATUS_UNIMPLEMENTED);
+}
+
+otError NcpBase::SetPropertyHandler_STREAM_NET(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ const uint8_t *framePtr = NULL;
+ unsigned int frameLen = 0;
+ const uint8_t *metaPtr = NULL;
+ unsigned int metaLen = 0;
+ otMessage *message;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ // STREAM_NET requires layer 2 security.
+ message = otIp6NewMessage(mInstance, true);
+ VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS);
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ (
+ SPINEL_DATATYPE_DATA_WLEN_S // Frame data
+ SPINEL_DATATYPE_DATA_S // Meta data
+ ),
+ &framePtr,
+ &frameLen,
+ &metaPtr,
+ &metaLen
+ );
+
+ // We ignore metadata for now.
+ // May later include TX power, allow retransmits, etc...
+ OT_UNUSED_VARIABLE(metaPtr);
+ OT_UNUSED_VARIABLE(metaLen);
+ OT_UNUSED_VARIABLE(parsedLength);
+
+ SuccessOrExit(error = otMessageAppend(message, framePtr, static_cast(frameLen)));
+
+ error = otIp6Send(mInstance, message);
+
+ // `otIp6Send()` takes ownership of `message` (in both success or
+ // failure cases). `message` is set to NULL so it is not freed at
+ // exit.
+ message = NULL;
+
+exit:
+
+ if (message != NULL)
+ {
+ otMessageFree(message);
+ }
+
+ if (error == OT_ERROR_NONE)
+ {
+ mInboundSecureIpFrameCounter++;
+
+ if (SPINEL_HEADER_GET_TID(aHeader) != 0)
+ {
+ // Only send a successful status update if
+ // there was a transaction id in the aHeader.
+ error = SendLastStatus(aHeader, SPINEL_STATUS_OK);
+ }
+ }
+ else
+ {
+ mDroppedInboundIpFrameCounter++;
+
+ error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
+ }
+
+ OT_UNUSED_VARIABLE(aKey);
+
+ return error;
+}
+
+#if OPENTHREAD_ENABLE_JAM_DETECTION
+
+otError NcpBase::GetPropertyHandler_JAM_DETECT_ENABLE(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_BOOL_S,
+ otJamDetectionIsEnabled(mInstance)
+ );
+}
+
+otError NcpBase::GetPropertyHandler_JAM_DETECTED(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_BOOL_S,
+ otJamDetectionGetState(mInstance)
+ );
+}
+
+otError NcpBase::GetPropertyHandler_JAM_DETECT_RSSI_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_INT8_S,
+ otJamDetectionGetRssiThreshold(mInstance)
+ );
+}
+
+otError NcpBase::GetPropertyHandler_JAM_DETECT_WINDOW(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT8_S,
+ otJamDetectionGetWindow(mInstance)
+ );
+}
+
+otError NcpBase::GetPropertyHandler_JAM_DETECT_BUSY(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT8_S,
+ otJamDetectionGetBusyPeriod(mInstance)
+ );
+}
+
+otError NcpBase::GetPropertyHandler_JAM_DETECT_HISTORY_BITMAP(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ uint64_t historyBitmap = otJamDetectionGetHistoryBitmap(mInstance);
+
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ (
+ SPINEL_DATATYPE_UINT32_S // History bitmap - bits 0-31
+ SPINEL_DATATYPE_UINT32_S // History bitmap - bits 32-63
+ ),
+ static_cast(historyBitmap & 0xffffffff),
+ static_cast(historyBitmap >> 32)
+ );
+}
+
+otError NcpBase::SetPropertyHandler_JAM_DETECT_ENABLE(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ bool enabled;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_BOOL_S,
+ &enabled
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ if (enabled)
+ {
+ otJamDetectionStart(mInstance, &NcpBase::HandleJamStateChange_Jump, this);
+ }
+ else
+ {
+ otJamDetectionStop(mInstance);
+ }
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::SetPropertyHandler_JAM_DETECT_RSSI_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ int8_t threshold = 0;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_INT8_S,
+ &threshold
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ error = otJamDetectionSetRssiThreshold(mInstance, threshold);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::SetPropertyHandler_JAM_DETECT_WINDOW(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ uint8_t window = 0;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT8_S,
+ &window
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ error = otJamDetectionSetWindow(mInstance, window);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::SetPropertyHandler_JAM_DETECT_BUSY(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ uint8_t busy = 0;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT8_S,
+ &busy
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ error = otJamDetectionSetBusyPeriod(mInstance, busy);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+void NcpBase::HandleJamStateChange_Jump(bool aJamState, void *aContext)
+{
+ static_cast(aContext)->HandleJamStateChange(aJamState);
+}
+
+void NcpBase::HandleJamStateChange(bool aJamState)
+{
+ OT_UNUSED_VARIABLE(aJamState);
+
+ mChangedPropsSet.AddProperty(SPINEL_PROP_JAM_DETECTED);
+ mUpdateChangedPropsTask.Post();
+}
+
+#endif // OPENTHREAD_ENABLE_JAM_DETECTION
+
+otError NcpBase::GetPropertyHandler_MAC_CNTR(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ uint32_t value;
+ const otMacCounters *macCounters;
+ otError error = OT_ERROR_NONE;
+
+ macCounters = otLinkGetCounters(mInstance);
+
+ assert(macCounters != NULL);
+
+ switch (aKey)
+ {
+ case SPINEL_PROP_CNTR_TX_PKT_TOTAL:
+ value = macCounters->mTxTotal;
+ break;
+
+ case SPINEL_PROP_CNTR_TX_PKT_ACK_REQ:
+ value = macCounters->mTxAckRequested;
+ break;
+
+ case SPINEL_PROP_CNTR_TX_PKT_ACKED:
+ value = macCounters->mTxAcked;
+ break;
+
+ case SPINEL_PROP_CNTR_TX_PKT_NO_ACK_REQ:
+ value = macCounters->mTxNoAckRequested;
+ break;
+
+ case SPINEL_PROP_CNTR_TX_PKT_DATA:
+ value = macCounters->mTxData;
+ break;
+
+ case SPINEL_PROP_CNTR_TX_PKT_DATA_POLL:
+ value = macCounters->mTxDataPoll;
+ break;
+
+ case SPINEL_PROP_CNTR_TX_PKT_BEACON:
+ value = macCounters->mTxBeacon;
+ break;
+
+ case SPINEL_PROP_CNTR_TX_PKT_BEACON_REQ:
+ value = macCounters->mTxBeaconRequest;
+ break;
+
+ case SPINEL_PROP_CNTR_TX_PKT_OTHER:
+ value = macCounters->mTxOther;
+ break;
+
+ case SPINEL_PROP_CNTR_TX_PKT_RETRY:
+ value = macCounters->mTxRetry;
+ break;
+
+ case SPINEL_PROP_CNTR_TX_ERR_CCA:
+ value = macCounters->mTxErrCca;
+ break;
+
+ case SPINEL_PROP_CNTR_TX_PKT_UNICAST:
+ value = macCounters->mTxUnicast;
+ break;
+
+ case SPINEL_PROP_CNTR_TX_PKT_BROADCAST:
+ value = macCounters->mTxBroadcast;
+ break;
+
+ case SPINEL_PROP_CNTR_TX_ERR_ABORT:
+ value = macCounters->mTxErrAbort;
+ break;
+
+ case SPINEL_PROP_CNTR_RX_PKT_TOTAL:
+ value = macCounters->mRxTotal;
+ break;
+
+ case SPINEL_PROP_CNTR_RX_PKT_DATA:
+ value = macCounters->mRxData;
+ break;
+
+ case SPINEL_PROP_CNTR_RX_PKT_DATA_POLL:
+ value = macCounters->mRxDataPoll;
+ break;
+
+ case SPINEL_PROP_CNTR_RX_PKT_BEACON:
+ value = macCounters->mRxBeacon;
+ break;
+
+ case SPINEL_PROP_CNTR_RX_PKT_BEACON_REQ:
+ value = macCounters->mRxBeaconRequest;
+ break;
+
+ case SPINEL_PROP_CNTR_RX_PKT_OTHER:
+ value = macCounters->mRxOther;
+ break;
+
+ case SPINEL_PROP_CNTR_RX_PKT_FILT_WL:
+ value = macCounters->mRxWhitelistFiltered;
+ break;
+
+ case SPINEL_PROP_CNTR_RX_PKT_FILT_DA:
+ value = macCounters->mRxDestAddrFiltered;
+ break;
+
+ case SPINEL_PROP_CNTR_RX_PKT_DUP:
+ value = macCounters->mRxDuplicated;
+ break;
+
+ case SPINEL_PROP_CNTR_RX_PKT_UNICAST:
+ value = macCounters->mRxUnicast;
+ break;
+
+ case SPINEL_PROP_CNTR_RX_PKT_BROADCAST:
+ value = macCounters->mRxBroadcast;
+ break;
+
+ case SPINEL_PROP_CNTR_RX_ERR_EMPTY:
+ value = macCounters->mRxErrNoFrame;
+ break;
+
+ case SPINEL_PROP_CNTR_RX_ERR_UKWN_NBR:
+ value = macCounters->mRxErrUnknownNeighbor;
+ break;
+
+ case SPINEL_PROP_CNTR_RX_ERR_NVLD_SADDR:
+ value = macCounters->mRxErrInvalidSrcAddr;
+ break;
+
+ case SPINEL_PROP_CNTR_RX_ERR_SECURITY:
+ value = macCounters->mRxErrSec;
+ break;
+
+ case SPINEL_PROP_CNTR_RX_ERR_BAD_FCS:
+ value = macCounters->mRxErrFcs;
+ break;
+
+ case SPINEL_PROP_CNTR_RX_ERR_OTHER:
+ value = macCounters->mRxErrOther;
+ break;
+
+ default:
+ error = SendLastStatus(aHeader, SPINEL_STATUS_INTERNAL_ERROR);
+ ExitNow();
+ }
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT32_S,
+ value
+ );
+
+exit:
+ return error;
+}
+
+otError NcpBase::GetPropertyHandler_NCP_CNTR(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ uint32_t value;
+ otError error = OT_ERROR_NONE;
+
+ switch (aKey)
+ {
+ case SPINEL_PROP_CNTR_TX_IP_SEC_TOTAL:
+ value = mInboundSecureIpFrameCounter;
+ break;
+
+ case SPINEL_PROP_CNTR_TX_IP_INSEC_TOTAL:
+ value = mInboundInsecureIpFrameCounter;
+ break;
+
+ case SPINEL_PROP_CNTR_TX_IP_DROPPED:
+ value = mDroppedInboundIpFrameCounter;
+ break;
+
+ case SPINEL_PROP_CNTR_RX_IP_SEC_TOTAL:
+ value = mOutboundSecureIpFrameCounter;
+ break;
+
+ case SPINEL_PROP_CNTR_RX_IP_INSEC_TOTAL:
+ value = mOutboundInsecureIpFrameCounter;
+ break;
+
+ case SPINEL_PROP_CNTR_RX_IP_DROPPED:
+ value = mDroppedOutboundIpFrameCounter;
+ break;
+
+ case SPINEL_PROP_CNTR_TX_SPINEL_TOTAL:
+ value = mTxSpinelFrameCounter;
+ break;
+
+ case SPINEL_PROP_CNTR_RX_SPINEL_TOTAL:
+ value = mRxSpinelFrameCounter;
+ break;
+
+ case SPINEL_PROP_CNTR_RX_SPINEL_OUT_OF_ORDER_TID:
+ value = mRxSpinelOutOfOrderTidCounter;
+ break;
+
+ case SPINEL_PROP_CNTR_RX_SPINEL_ERR:
+ value = mFramingErrorCounter;
+ break;
+
+ default:
+ error = SendLastStatus(aHeader, SPINEL_STATUS_INTERNAL_ERROR);
+ ExitNow();
+ }
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT32_S,
+ value
+ );
+
+exit:
+ return error;
+}
+
+otError NcpBase::GetPropertyHandler_IP_CNTR(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ uint32_t value;
+ otError error = OT_ERROR_NONE;
+
+ const otIpCounters *counters = otThreadGetIp6Counters(mInstance);
+
+ switch (aKey)
+ {
+ case SPINEL_PROP_CNTR_IP_TX_SUCCESS:
+ value = counters->mTxSuccess;
+ break;
+
+ case SPINEL_PROP_CNTR_IP_RX_SUCCESS:
+ value = counters->mRxSuccess;
+ break;
+
+ case SPINEL_PROP_CNTR_IP_TX_FAILURE:
+ value = counters->mTxFailure;
+ break;
+
+ case SPINEL_PROP_CNTR_IP_RX_FAILURE:
+ value = counters->mRxFailure;
+ break;
+
+ default:
+ error = SendLastStatus(aHeader, SPINEL_STATUS_INTERNAL_ERROR);
+ ExitNow();
+ break;
+ }
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT32_S,
+ value
+ );
+
+exit:
+ return error;
+}
+
+otError NcpBase::GetPropertyHandler_MSG_BUFFER_COUNTERS(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otError error = OT_ERROR_NONE;
+ otBufferInfo bufferInfo;
+
+ otMessageGetBufferInfo(mInstance, &bufferInfo);
+
+ SuccessOrExit(error = OutboundFrameBegin(aHeader));
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_COMMAND_PROP_S,
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey
+ ));
+
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ (
+ SPINEL_DATATYPE_UINT16_S // Total buffers
+ SPINEL_DATATYPE_UINT16_S // Free buffers
+ SPINEL_DATATYPE_UINT16_S // Lowpan send messages
+ SPINEL_DATATYPE_UINT16_S // Lowpan send buffers
+ SPINEL_DATATYPE_UINT16_S // Lowpan reassembly messages
+ SPINEL_DATATYPE_UINT16_S // Lowpan reassembly buffers
+ SPINEL_DATATYPE_UINT16_S // Ip6 messages
+ SPINEL_DATATYPE_UINT16_S // Ip6 buffers
+ SPINEL_DATATYPE_UINT16_S // Mpl messages
+ SPINEL_DATATYPE_UINT16_S // Mpl buffers
+ SPINEL_DATATYPE_UINT16_S // Mle messages
+ SPINEL_DATATYPE_UINT16_S // Mle buffers
+ SPINEL_DATATYPE_UINT16_S // Arp messages
+ SPINEL_DATATYPE_UINT16_S // Arp buffers
+ SPINEL_DATATYPE_UINT16_S // Coap messages
+ SPINEL_DATATYPE_UINT16_S // Coap buffers
+ ),
+ bufferInfo.mTotalBuffers,
+ bufferInfo.mFreeBuffers,
+ bufferInfo.m6loSendMessages,
+ bufferInfo.m6loSendBuffers,
+ bufferInfo.m6loReassemblyMessages,
+ bufferInfo.m6loReassemblyBuffers,
+ bufferInfo.mIp6Messages,
+ bufferInfo.mIp6Buffers,
+ bufferInfo.mMplMessages,
+ bufferInfo.mMplBuffers,
+ bufferInfo.mMleMessages,
+ bufferInfo.mMleBuffers,
+ bufferInfo.mArpMessages,
+ bufferInfo.mArpBuffers,
+ bufferInfo.mCoapMessages,
+ bufferInfo.mCoapBuffers
+ ));
+
+ SuccessOrExit(error = OutboundFrameSend());
+
+exit:
+ return error;
+}
+
+#if OPENTHREAD_ENABLE_MAC_FILTER
+
+otError NcpBase::GetPropertyHandler_MAC_WHITELIST(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otMacFilterEntry entry;
+ otMacFilterIterator iterator = OT_MAC_FILTER_ITERATOR_INIT;
+ otError error = OT_ERROR_NONE;
+
+ mDisableStreamWrite = true;
+
+ SuccessOrExit(error = OutboundFrameBegin(aHeader));
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_COMMAND_PROP_S,
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey
+ ));
+
+ while (otLinkFilterGetNextAddress(mInstance, &iterator, &entry) == OT_ERROR_NONE)
+ {
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_STRUCT_S(
+ SPINEL_DATATYPE_EUI64_S // Extended address
+ SPINEL_DATATYPE_INT8_S // Rss
+ ),
+ entry.mExtAddress.m8,
+ entry.mRssIn
+ ));
+ }
+
+ SuccessOrExit(error = OutboundFrameSend());
+
+exit:
+ mDisableStreamWrite = false;
+ return error;
+}
+
+otError NcpBase::GetPropertyHandler_MAC_WHITELIST_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otMacFilterAddressMode mode = otLinkFilterGetAddressMode(mInstance);
+ bool isEnabled = (mode == OT_MAC_FILTER_ADDRESS_MODE_WHITELIST) ? true : false;
+
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_BOOL_S,
+ isEnabled
+ );
+}
+
+otError NcpBase::GetPropertyHandler_MAC_BLACKLIST(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otMacFilterEntry entry;
+ otMacFilterIterator iterator = OT_MAC_FILTER_ITERATOR_INIT;
+ otError error = OT_ERROR_NONE;
+
+ mDisableStreamWrite = true;
+
+ SuccessOrExit(error = OutboundFrameBegin(aHeader));
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_COMMAND_PROP_S,
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey
+ ));
+
+ while (otLinkFilterGetNextAddress(mInstance, &iterator, &entry) == OT_ERROR_NONE)
+ {
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_STRUCT_S(
+ SPINEL_DATATYPE_EUI64_S // Extended address
+ ),
+ entry.mExtAddress.m8
+ ));
+ }
+
+ SuccessOrExit(error = OutboundFrameSend());
+
+exit:
+ mDisableStreamWrite = false;
+ return error;
+}
+
+otError NcpBase::GetPropertyHandler_MAC_BLACKLIST_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otMacFilterAddressMode mode = otLinkFilterGetAddressMode(mInstance);
+ bool isEnabled = (mode == OT_MAC_FILTER_ADDRESS_MODE_BLACKLIST) ? true : false;
+
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_BOOL_S,
+ isEnabled
+ );
+}
+
+otError NcpBase::GetPropertyHandler_MAC_FIXED_RSS(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otMacFilterEntry entry;
+ otMacFilterIterator iterator = OT_MAC_FILTER_ITERATOR_INIT;
+ otError error = OT_ERROR_NONE;
+
+ mDisableStreamWrite = true;
+
+ SuccessOrExit(error = OutboundFrameBegin(aHeader));
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_COMMAND_PROP_S,
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey
+ ));
+
+ while (otLinkFilterGetNextRssIn(mInstance, &iterator, &entry) == OT_ERROR_NONE)
+ {
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_STRUCT_S(
+ SPINEL_DATATYPE_EUI64_S // Extended address
+ SPINEL_DATATYPE_INT8_S // Rss
+ ),
+ entry.mExtAddress.m8,
+ entry.mRssIn
+ ));
+ }
+
+ SuccessOrExit(error = OutboundFrameSend());
+
+exit:
+ mDisableStreamWrite = false;
+ return error;
+}
+
+otError NcpBase::SetPropertyHandler_MAC_WHITELIST(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ bool reportAsync;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ // First, clear the address filter entries.
+ otLinkFilterClearAddresses(mInstance);
+
+ while (aValueLen > 0)
+ {
+ otExtAddress *extAddress = NULL;
+ int8_t rss;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_STRUCT_S(
+ SPINEL_DATATYPE_EUI64_S
+ SPINEL_DATATYPE_INT8_S
+ ),
+ &extAddress,
+ &rss
+ );
+
+ if (parsedLength <= 0)
+ {
+ rss = OT_MAC_FILTER_FIXED_RSS_DISABLED;
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_STRUCT_S(
+ SPINEL_DATATYPE_EUI64_S
+ ),
+ &extAddress
+ );
+ }
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ error = otLinkFilterAddAddress(mInstance, extAddress);
+
+ VerifyOrExit(error == OT_ERROR_NONE || error == OT_ERROR_ALREADY);
+
+ if (rss != OT_MAC_FILTER_FIXED_RSS_DISABLED)
+ {
+ SuccessOrExit(error = otLinkFilterAddRssIn(mInstance, extAddress, rss));
+ }
+
+ aValuePtr += parsedLength;
+ aValueLen -= parsedLength;
+ }
+
+exit:
+ // If we had an error, we may have actually changed
+ // the state of the whitelist---so we need to report
+ // those incomplete changes via an asynchronous
+ // change event.
+ reportAsync = (error != OT_ERROR_NONE && error != OT_ERROR_ALREADY);
+
+ error = SendSetPropertyResponse(aHeader, aKey, error);
+
+ if (reportAsync)
+ {
+ HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, aKey);
+ }
+
+ return error;
+}
+
+otError NcpBase::SetPropertyHandler_MAC_WHITELIST_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ bool enabled;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ otMacFilterAddressMode mode = OT_MAC_FILTER_ADDRESS_MODE_DISABLED;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_BOOL_S,
+ &enabled
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ if (enabled)
+ {
+ mode = OT_MAC_FILTER_ADDRESS_MODE_WHITELIST;
+ }
+
+ error = otLinkFilterSetAddressMode(mInstance, mode);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::SetPropertyHandler_MAC_BLACKLIST(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ bool reportAsync;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ // First, clear the address filter entries.
+ otLinkFilterClearAddresses(mInstance);
+
+ while (aValueLen > 0)
+ {
+ otExtAddress *extAddress = NULL;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_STRUCT_S(
+ SPINEL_DATATYPE_EUI64_S
+ ),
+ &extAddress
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ error = otLinkFilterRemoveAddress(mInstance, extAddress);
+
+ VerifyOrExit(error == OT_ERROR_NONE || error == OT_ERROR_ALREADY);
+
+ aValuePtr += parsedLength;
+ aValueLen -= parsedLength;
+ }
+
+exit:
+ // If we had an error, we may have actually changed
+ // the state of the blacklist---so we need to report
+ // those incomplete changes via an asynchronous
+ // change event.
+ reportAsync = (error != OT_ERROR_NONE && error != OT_ERROR_ALREADY);
+
+ error = SendSetPropertyResponse(aHeader, aKey, error);
+
+ if (reportAsync)
+ {
+ HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, aKey);
+ }
+
+ return error;
+}
+
+otError NcpBase::SetPropertyHandler_MAC_BLACKLIST_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ bool enabled;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ otMacFilterAddressMode mode = OT_MAC_FILTER_ADDRESS_MODE_DISABLED;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_BOOL_S,
+ &enabled
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ if (enabled)
+ {
+ mode = OT_MAC_FILTER_ADDRESS_MODE_BLACKLIST;
+ }
+
+ error = otLinkFilterSetAddressMode(mInstance, mode);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::SetPropertyHandler_MAC_FIXED_RSS(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ bool reportAsync;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ // First, clear the address filter entries.
+ otLinkFilterClearRssIn(mInstance);
+
+ while (aValueLen > 0)
+ {
+ otExtAddress *extAddress;
+ int8_t rss;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_STRUCT_S(
+ SPINEL_DATATYPE_EUI64_S
+ SPINEL_DATATYPE_INT8_S
+ ),
+ &extAddress,
+ &rss
+ );
+
+ if (parsedLength < 0)
+ {
+ extAddress = NULL;
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_STRUCT_S(
+ SPINEL_DATATYPE_INT8_S
+ ),
+ &rss
+ );
+ }
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ SuccessOrExit(error = otLinkFilterAddRssIn(mInstance, extAddress, rss));
+
+ aValuePtr += parsedLength;
+ aValueLen -= parsedLength;
+ }
+
+exit:
+ // If we had an error, we may have actually changed
+ // the state of the RssIn filter---so we need to report
+ // those incomplete changes via an asynchronous
+ // change event.
+ reportAsync = (error != OT_ERROR_NONE);
+
+ error = SendSetPropertyResponse(aHeader, aKey, error);
+
+ if (reportAsync)
+ {
+ HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, aKey);
+ }
+
+ return error;
+}
+#endif // OPENTHREAD_ENABLE_MAC_FILTER
+
+otError NcpBase::GetPropertyHandler_THREAD_MODE(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ uint8_t numericMode;
+ otLinkModeConfig modeConfig = otThreadGetLinkMode(mInstance);
+
+ numericMode = LinkFlagsToFlagByte(
+ modeConfig.mRxOnWhenIdle,
+ modeConfig.mSecureDataRequests,
+ modeConfig.mDeviceType,
+ modeConfig.mNetworkData
+ );
+
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT8_S,
+ numericMode
+ );
+}
+
+otError NcpBase::SetPropertyHandler_THREAD_MODE(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ uint8_t numericMode = 0;
+ otLinkModeConfig modeConfig;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT8_S,
+ &numericMode
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ modeConfig.mRxOnWhenIdle = ((numericMode & SPINEL_THREAD_MODE_RX_ON_WHEN_IDLE) == SPINEL_THREAD_MODE_RX_ON_WHEN_IDLE);
+ modeConfig.mSecureDataRequests =
+ ((numericMode & SPINEL_THREAD_MODE_SECURE_DATA_REQUEST) == SPINEL_THREAD_MODE_SECURE_DATA_REQUEST);
+ modeConfig.mDeviceType = ((numericMode & SPINEL_THREAD_MODE_FULL_FUNCTION_DEV) == SPINEL_THREAD_MODE_FULL_FUNCTION_DEV);
+ modeConfig.mNetworkData = ((numericMode & SPINEL_THREAD_MODE_FULL_NETWORK_DATA) == SPINEL_THREAD_MODE_FULL_NETWORK_DATA);
+
+ error = otThreadSetLinkMode(mInstance, modeConfig);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+
+otError NcpBase::GetPropertyHandler_THREAD_CHILD_TIMEOUT(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT32_S,
+ otThreadGetChildTimeout(mInstance)
+ );
+}
+
+otError NcpBase::GetPropertyHandler_THREAD_RLOC16(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT16_S,
+ otThreadGetRloc16(mInstance)
+ );
+}
+
+otError NcpBase::GetPropertyHandler_NET_REQUIRE_JOIN_EXISTING(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_BOOL_S,
+ mRequireJoinExistingNetwork
+ );
+}
+
+otError NcpBase::SetPropertyHandler_NET_REQUIRE_JOIN_EXISTING(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ bool value = mRequireJoinExistingNetwork;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_BOOL_S,
+ &value
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ mRequireJoinExistingNetwork = value;
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::SetPropertyHandler_STREAM_NET_INSECURE(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ const uint8_t *framePtr = NULL;
+ unsigned int frameLen = 0;
+ const uint8_t *metaPtr = NULL;
+ unsigned int metaLen = 0;
+ otMessage *message;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ // STREAM_NET_INSECURE packets are not secured at layer 2.
+ message = otIp6NewMessage(mInstance, false);
+ VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS);
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ (
+ SPINEL_DATATYPE_DATA_WLEN_S // Frame data
+ SPINEL_DATATYPE_DATA_S // Meta data
+ ),
+ &framePtr,
+ &frameLen,
+ &metaPtr,
+ &metaLen
+ );
+
+ // We ignore metadata for now.
+ // May later include TX power, allow retransmits, etc...
+ OT_UNUSED_VARIABLE(metaPtr);
+ OT_UNUSED_VARIABLE(metaLen);
+ OT_UNUSED_VARIABLE(parsedLength);
+
+ SuccessOrExit(error = otMessageAppend(message, framePtr, static_cast(frameLen)));
+
+ // Ensure the insecure message is forwarded using direct transmission.
+ otMessageSetDirectTransmission(message, true);
+
+ error = otIp6Send(mInstance, message);
+
+ // `otIp6Send()` takes ownership of `message` (in both success or
+ // failure cases). `message` is set to NULL so it is not freed at
+ // exit.
+ message = NULL;
+
+exit:
+ if (message != NULL)
+ {
+ otMessageFree(message);
+ }
+
+ if (error == OT_ERROR_NONE)
+ {
+ mInboundInsecureIpFrameCounter++;
+
+ if (SPINEL_HEADER_GET_TID(aHeader) != 0)
+ {
+ // Only send a successful status update if
+ // there was a transaction id in the aHeader.
+ error = SendLastStatus(aHeader, SPINEL_STATUS_OK);
+ }
+ }
+ else
+ {
+ mDroppedInboundIpFrameCounter++;
+
+ error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
+ }
+
+ OT_UNUSED_VARIABLE(aKey);
+
+ return error;
+}
+
+
+otError NcpBase::SetPropertyHandler_CNTR_RESET(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ uint8_t value = 0;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT8_S,
+ &value
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ VerifyOrExit(value == 1, error = OT_ERROR_INVALID_ARGS);
+
+ // TODO: Implement counter reset!
+ error = OT_ERROR_NOT_IMPLEMENTED;
+
+exit:
+ OT_UNUSED_VARIABLE(aKey);
+
+ // There is currently no getter for PROP_CNTR_RESET, so we just
+ // return SPINEL_STATUS_OK for success when the counters are reset.
+
+ return SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
+}
+
+
+#if OPENTHREAD_ENABLE_DIAG
+
+otError NcpBase::SetPropertyHandler_NEST_STREAM_MFG(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ char *string = NULL;
+ char *output = NULL;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UTF8_S,
+ &string
+ );
+
+ if ((parsedLength > 0) && (string != NULL))
+ {
+ // all diagnostics related features are processed within diagnostics module
+ output = otDiagProcessCmdLine(string);
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ reinterpret_cast(output),
+ static_cast(strlen(output) + 1)
+ );
+ }
+ else
+ {
+ error = SendLastStatus(aHeader, SPINEL_STATUS_PARSE_ERROR);
+ }
+
+ return error;
+}
+
+#endif // OPENTHREAD_ENABLE_DIAG
+
+otError NcpBase::InsertPropertyHandler_THREAD_ASSISTING_PORTS(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ uint16_t port;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT16_S,
+ &port
+ );
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ error = otIp6AddUnsecurePort(mInstance, port);
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_INSERTED,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+
+#if OPENTHREAD_ENABLE_MAC_FILTER
+
+otError NcpBase::InsertPropertyHandler_MAC_WHITELIST(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ otExtAddress *extAddress = NULL;
+ int8_t rss = OT_MAC_FILTER_FIXED_RSS_DISABLED;
+
+ if (aValueLen > static_cast(sizeof(otExtAddress)))
+ {
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_EUI64_S SPINEL_DATATYPE_INT8_S,
+ &extAddress,
+ &rss
+ );
+ }
+ else
+ {
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_EUI64_S,
+ &extAddress
+ );
+ }
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ error = otLinkFilterAddAddress(mInstance, extAddress);
+
+ VerifyOrExit(error == OT_ERROR_NONE || error == OT_ERROR_ALREADY, spinelError = ThreadErrorToSpinelStatus(error));
+
+ if (rss != OT_MAC_FILTER_FIXED_RSS_DISABLED)
+ {
+ error = otLinkFilterAddRssIn(mInstance, extAddress, rss);
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+ }
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_INSERTED,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+
+otError NcpBase::InsertPropertyHandler_MAC_BLACKLIST(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ otExtAddress *extAddress = NULL;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_EUI64_S,
+ &extAddress
+ );
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ error = otLinkFilterAddAddress(mInstance, extAddress);
+
+ VerifyOrExit(error == OT_ERROR_NONE || error == OT_ERROR_ALREADY, spinelError = ThreadErrorToSpinelStatus(error));
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_INSERTED,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+
+otError NcpBase::InsertPropertyHandler_MAC_FIXED_RSS(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ otExtAddress *extAddress = NULL;
+ int8_t rss = OT_MAC_FILTER_FIXED_RSS_DISABLED;
+
+ if (aValueLen > sizeof(int8_t))
+ {
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_EUI64_S SPINEL_DATATYPE_INT8_S,
+ &extAddress,
+ &rss
+ );
+ }
+ else
+ {
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_INT8_S,
+ &rss
+ );
+ }
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ error = otLinkFilterAddRssIn(mInstance, extAddress, rss);
+
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_INSERTED,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+
+#endif // OPENTHREAD_ENABLE_MAC_FILTER
+
+otError NcpBase::RemovePropertyHandler_THREAD_ASSISTING_PORTS(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ uint16_t port;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT16_S,
+ &port
+ );
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ error = otIp6RemoveUnsecurePort(mInstance, port);
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_REMOVED,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+
+#if OPENTHREAD_ENABLE_MAC_FILTER
+
+otError NcpBase::RemovePropertyHandler_MAC_WHITELIST(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ otExtAddress *extAddress = NULL;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_EUI64_S,
+ &extAddress
+ );
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ error = otLinkFilterRemoveAddress(mInstance, extAddress);
+
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_REMOVED,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+
+otError NcpBase::RemovePropertyHandler_MAC_BLACKLIST(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ otExtAddress *extAddress = NULL;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_EUI64_S,
+ &extAddress
+ );
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ error = otLinkFilterRemoveAddress(mInstance, extAddress);
+
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_REMOVED,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+
+otError NcpBase::RemovePropertyHandler_MAC_FIXED_RSS(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ otExtAddress *extAddress = NULL;
+
+ if (aValueLen > 0)
+ {
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_EUI64_S,
+ &extAddress
+ );
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+ }
+
+ error = otLinkFilterRemoveRssIn(mInstance, extAddress);
+
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_REMOVED,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+
+#endif // OPENTHREAD_ENABLE_MAC_FILTER
+
+#if OPENTHREAD_ENABLE_LEGACY
+
+void NcpBase::RegisterLegacyHandlers(const otNcpLegacyHandlers *aHandlers)
+{
+ mLegacyHandlers = aHandlers;
+ bool isEnabled;
+
+ VerifyOrExit(mLegacyHandlers != NULL);
+
+ isEnabled = (otThreadGetDeviceRole(mInstance) != OT_DEVICE_ROLE_DISABLED);
+
+ if (isEnabled)
+ {
+ if (mLegacyHandlers->mStartLegacy)
+ {
+ mLegacyHandlers->mStartLegacy();
+ }
+ }
+ else
+ {
+ if (mLegacyHandlers->mStopLegacy)
+ {
+ mLegacyHandlers->mStopLegacy();
+ }
+ }
+
+ if (mLegacyHandlers->mSetLegacyUlaPrefix)
+ {
+ mLegacyHandlers->mSetLegacyUlaPrefix(mLegacyUlaPrefix);
+ }
+
+exit:
+ return;
+}
+
+void NcpBase::HandleDidReceiveNewLegacyUlaPrefix(const uint8_t *aUlaPrefix)
+{
+ memcpy(mLegacyUlaPrefix, aUlaPrefix, OT_NCP_LEGACY_ULA_PREFIX_LENGTH);
+ mChangedPropsSet.AddProperty(SPINEL_PROP_NEST_LEGACY_ULA_PREFIX);
+ mUpdateChangedPropsTask.Post();
+}
+
+void NcpBase::HandleLegacyNodeDidJoin(const otExtAddress *aExtAddr)
+{
+ mLegacyNodeDidJoin = true;
+ mLegacyLastJoinedNode = *aExtAddr;
+ mChangedPropsSet.AddProperty(SPINEL_PROP_NEST_LEGACY_LAST_NODE_JOINED);
+ mUpdateChangedPropsTask.Post();
+}
+
+#endif // OPENTHREAD_ENABLE_LEGACY
+
+#if OPENTHREAD_ENABLE_LEGACY
+otError NcpBase::GetPropertyHandler_NEST_LEGACY_ULA_PREFIX(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_DATA_S,
+ mLegacyUlaPrefix,
+ sizeof(mLegacyUlaPrefix)
+ );
+}
+
+otError NcpBase::SetPropertyHandler_NEST_LEGACY_ULA_PREFIX(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ const uint8_t *ptr = NULL;
+ spinel_size_t len;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_DATA_S,
+ &ptr,
+ &len
+ );
+
+ VerifyOrExit((parsedLength > 0) && (len <= sizeof(mLegacyUlaPrefix)), error = OT_ERROR_PARSE);
+
+ memset(mLegacyUlaPrefix, 0, sizeof(mLegacyUlaPrefix));
+ memcpy(mLegacyUlaPrefix, ptr, len);
+
+ if ((mLegacyHandlers != NULL) && (mLegacyHandlers->mSetLegacyUlaPrefix != NULL))
+ {
+ mLegacyHandlers->mSetLegacyUlaPrefix(mLegacyUlaPrefix);
+ }
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_NEST_LEGACY_LAST_NODE_JOINED(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ if (!mLegacyNodeDidJoin)
+ {
+ memset(&mLegacyLastJoinedNode, 0, sizeof(mLegacyLastJoinedNode));
+ }
+
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_EUI64_S,
+ &mLegacyLastJoinedNode,
+ sizeof(mLegacyLastJoinedNode)
+ );
+}
+#endif // OPENTHREAD_ENABLE_LEGACY
+
+otError NcpBase::GetPropertyHandler_ChannelMaskHelper(uint8_t aHeader, spinel_prop_key_t aKey, uint32_t aChannelMask)
+{
+ otError error = OT_ERROR_NONE;
+
+ SuccessOrExit(error = OutboundFrameBegin(aHeader));
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_COMMAND_PROP_S,
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey
+ ));
+
+ for (int i = 0; i < 32; i++)
+ {
+ if (0 != (aChannelMask & (1 << i)))
+ {
+ SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT8_S, i));
+ }
+ }
+
+ SuccessOrExit(error = OutboundFrameSend());
+
+exit:
+ return error;
+}
+
+
+otError NcpBase::GetPropertyHandler_MAC_SCAN_MASK(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return GetPropertyHandler_ChannelMaskHelper(aHeader, aKey, mChannelMask);
+}
+
+otError NcpBase::SetPropertyHandler_MAC_SCAN_MASK(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ uint32_t newMask = 0;
+ otError error = OT_ERROR_NONE;
+
+ for (; aValueLen != 0; aValueLen--, aValuePtr++)
+ {
+ VerifyOrExit(aValuePtr[0] <= 31, error = OT_ERROR_INVALID_ARGS);
+ VerifyOrExit((mSupportedChannelMask & (1 << aValuePtr[0])) != 0, error = OT_ERROR_INVALID_ARGS);
+
+ newMask |= (1 << aValuePtr[0]);
+ }
+
+ mChannelMask = newMask;
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_MAC_SCAN_PERIOD(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT16_S,
+ mScanPeriod
+ );
+}
+
+otError NcpBase::SetPropertyHandler_MAC_SCAN_PERIOD(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ uint16_t period = mScanPeriod;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT16_S,
+ &period
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ mScanPeriod = period;
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_MAC_SCAN_STATE(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otError error = OT_ERROR_NONE;
+
+#if OPENTHREAD_ENABLE_RAW_LINK_API
+
+ if (otLinkRawIsEnabled(mInstance))
+ {
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT8_S,
+ mCurScanChannel == kInvalidScanChannel
+ ? SPINEL_SCAN_STATE_IDLE
+ : SPINEL_SCAN_STATE_ENERGY
+ );
+ }
+ else
+
+#endif // OPENTHREAD_ENABLE_RAW_LINK_API
+ {
+ if (otLinkIsActiveScanInProgress(mInstance))
+ {
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT8_S,
+ SPINEL_SCAN_STATE_BEACON
+ );
+ }
+ else if (otLinkIsEnergyScanInProgress(mInstance))
+ {
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT8_S,
+ SPINEL_SCAN_STATE_ENERGY
+ );
+ }
+ else if (otThreadIsDiscoverInProgress(mInstance))
+ {
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT8_S,
+ SPINEL_SCAN_STATE_DISCOVER
+ );
+ }
+ else
+ {
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT8_S,
+ SPINEL_SCAN_STATE_IDLE
+ );
+ }
+ }
+
+ return error;
+}
+
+otError NcpBase::SetPropertyHandler_MAC_SCAN_STATE(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ uint8_t state = 0;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT8_S,
+ &state
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ switch (state)
+ {
+ case SPINEL_SCAN_STATE_IDLE:
+ error = OT_ERROR_NONE;
+ break;
+
+ case SPINEL_SCAN_STATE_BEACON:
+#if OPENTHREAD_ENABLE_RAW_LINK_API
+ if (otLinkRawIsEnabled(mInstance))
+ {
+ error = OT_ERROR_NOT_IMPLEMENTED;
+ }
+ else
+#endif // OPENTHREAD_ENABLE_RAW_LINK_API
+ {
+ error = otLinkActiveScan(
+ mInstance,
+ mChannelMask,
+ mScanPeriod,
+ &HandleActiveScanResult_Jump,
+ this
+ );
+ }
+
+ SuccessOrExit(error);
+ break;
+
+ case SPINEL_SCAN_STATE_ENERGY:
+#if OPENTHREAD_ENABLE_RAW_LINK_API
+ if (otLinkRawIsEnabled(mInstance))
+ {
+ uint8_t scanChannel;
+
+ // Make sure we aren't already scanning and that we have
+ // only 1 bit set for the channel mask.
+ VerifyOrExit(mCurScanChannel == kInvalidScanChannel, error = OT_ERROR_INVALID_STATE);
+ VerifyOrExit(HasOnly1BitSet(mChannelMask), error = OT_ERROR_INVALID_ARGS);
+
+ scanChannel = IndexOfMSB(mChannelMask);
+ mCurScanChannel = (int8_t)scanChannel;
+
+ error = otLinkRawEnergyScan(
+ mInstance,
+ scanChannel,
+ mScanPeriod,
+ LinkRawEnergyScanDone
+ );
+ }
+ else
+#endif // OPENTHREAD_ENABLE_RAW_LINK_API
+ {
+ error = otLinkEnergyScan(
+ mInstance,
+ mChannelMask,
+ mScanPeriod,
+ &HandleEnergyScanResult_Jump,
+ this
+ );
+ }
+
+ SuccessOrExit(error);
+ break;
+
+ case SPINEL_SCAN_STATE_DISCOVER:
+ error = otThreadDiscover(
+ mInstance,
+ mChannelMask,
+ mDiscoveryScanPanId,
+ mDiscoveryScanJoinerFlag,
+ mDiscoveryScanEnableFiltering,
+ &HandleActiveScanResult_Jump,
+ this
+ );
+
+ SuccessOrExit(error);
+ break;
+
+ default:
+ error = OT_ERROR_INVALID_ARGS;
+ break;
+ }
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+void NcpBase::HandleActiveScanResult_Jump(otActiveScanResult *aResult, void *aContext)
+{
+ static_cast(aContext)->HandleActiveScanResult(aResult);
+}
+
+// ----------------------------------------------------------------------------
+// MARK: Scan Results Glue
+// ----------------------------------------------------------------------------
+
+void NcpBase::HandleActiveScanResult(otActiveScanResult *aResult)
+{
+ otError error;
+
+ if (aResult)
+ {
+ uint8_t flags = static_cast(aResult->mVersion << SPINEL_BEACON_THREAD_FLAG_VERSION_SHIFT);
+
+ if (aResult->mIsJoinable)
+ {
+ flags |= SPINEL_BEACON_THREAD_FLAG_JOINABLE;
+ }
+
+ if (aResult->mIsNative)
+ {
+ flags |= SPINEL_BEACON_THREAD_FLAG_NATIVE;
+ }
+
+ error = SendPropertyUpdate(
+ SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
+ SPINEL_CMD_PROP_VALUE_INSERTED,
+ SPINEL_PROP_MAC_SCAN_BEACON,
+ SPINEL_DATATYPE_MAC_SCAN_RESULT_S(
+ SPINEL_802_15_4_DATATYPE_MAC_SCAN_RESULT_V1_S,
+ SPINEL_NET_DATATYPE_MAC_SCAN_RESULT_V2_S
+ ),
+ aResult->mChannel, // Channel
+ aResult->mRssi, // RSSI
+ // "mac-layer data"
+ aResult->mExtAddress.m8, // laddr
+ 0xFFFF, // saddr, not given
+ aResult->mPanId, // panid
+ aResult->mLqi, // lqi
+ // "net-layer data"
+ SPINEL_PROTOCOL_TYPE_THREAD, // type
+ flags, // flags
+ aResult->mNetworkName.m8, // network name
+ aResult->mExtendedPanId.m8, OT_EXT_PAN_ID_SIZE, // xpanid
+ aResult->mSteeringData.m8, aResult->mSteeringData.mLength // steering data
+ );
+
+ if (error != OT_ERROR_NONE)
+ {
+ mChangedPropsSet.AddLastStatus(SPINEL_STATUS_NOMEM);
+ mUpdateChangedPropsTask.Post();
+ }
+ }
+ else
+ {
+ // We are finished with the scan, so send out
+ // a property update indicating such.
+ error = SendPropertyUpdate(
+ SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
+ SPINEL_CMD_PROP_VALUE_IS,
+ SPINEL_PROP_MAC_SCAN_STATE,
+ SPINEL_DATATYPE_UINT8_S,
+ SPINEL_SCAN_STATE_IDLE
+ );
+
+ // If we could not send the end of scan indicator message now (no
+ // buffer space), we add the MAC_SCAN_STATE property to changed
+ // property set so that the update is sent when buffer becomes
+ // available.
+ if (error != OT_ERROR_NONE)
+ {
+ mChangedPropsSet.AddProperty(SPINEL_PROP_MAC_SCAN_STATE);
+ }
+ }
+}
+
+void NcpBase::HandleEnergyScanResult_Jump(otEnergyScanResult *aResult, void *aContext)
+{
+ static_cast(aContext)->HandleEnergyScanResult(aResult);
+}
+
+void NcpBase::HandleEnergyScanResult(otEnergyScanResult *aResult)
+{
+ otError error;
+
+ if (aResult)
+ {
+ error = SendPropertyUpdate(
+ SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
+ SPINEL_CMD_PROP_VALUE_INSERTED,
+ SPINEL_PROP_MAC_ENERGY_SCAN_RESULT,
+ (
+ SPINEL_DATATYPE_UINT8_S // Channel
+ SPINEL_DATATYPE_INT8_S // Rssi
+ ),
+ aResult->mChannel,
+ aResult->mMaxRssi
+ );
+
+ if (error != OT_ERROR_NONE)
+ {
+ mChangedPropsSet.AddLastStatus(SPINEL_STATUS_NOMEM);
+ mUpdateChangedPropsTask.Post();
+ }
+ }
+ else
+ {
+ // We are finished with the scan, so send out
+ // a property update indicating such.
+ error = SendPropertyUpdate(
+ SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
+ SPINEL_CMD_PROP_VALUE_IS,
+ SPINEL_PROP_MAC_SCAN_STATE,
+ SPINEL_DATATYPE_UINT8_S,
+ SPINEL_SCAN_STATE_IDLE
+ );
+
+ // If we could not send the end of scan indicator message now (no
+ // buffer space), we add the MAC_SCAN_STATE property to changed
+ // property set so that the update is sent when buffer becomes
+ // available.
+ if (error != OT_ERROR_NONE)
+ {
+ mChangedPropsSet.AddProperty(SPINEL_PROP_MAC_SCAN_STATE);
+ }
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// MARK: Outbound Datagram Handling
+// ----------------------------------------------------------------------------
+
+void NcpBase::HandleDatagramFromStack(otMessage *aMessage, void *aContext)
+{
+ static_cast(aContext)->HandleDatagramFromStack(aMessage);
+}
+
+void NcpBase::HandleDatagramFromStack(otMessage *aMessage)
+{
+ otError error = OT_ERROR_NONE;
+ uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0;
+ bool isSecure = otMessageIsLinkSecurityEnabled(aMessage);
+ uint16_t length = otMessageGetLength(aMessage);
+
+ SuccessOrExit(error = OutboundFrameBegin(header));
+
+ SuccessOrExit(
+ error = OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_COMMAND_PROP_S SPINEL_DATATYPE_UINT16_S,
+ header,
+ SPINEL_CMD_PROP_VALUE_IS,
+ isSecure ? SPINEL_PROP_STREAM_NET : SPINEL_PROP_STREAM_NET_INSECURE,
+ length
+ ));
+
+ SuccessOrExit(error = OutboundFrameFeedMessage(aMessage));
+
+ // Set the `aMessage` pointer to NULL to indicate that it does
+ // not need to be freed at the exit. The `aMessage` is now owned
+ // by the OutboundFrame and will be freed when the frame is either
+ // successfully sent and then removed, or if the frame gets
+ // discarded.
+ aMessage = NULL;
+
+ // Append any metadata (rssi, lqi, channel, etc) here!
+
+ SuccessOrExit(error = OutboundFrameSend());
+
+exit:
+
+ if (aMessage != NULL)
+ {
+ otMessageFree(aMessage);
+ }
+
+ if (error != OT_ERROR_NONE)
+ {
+ mChangedPropsSet.AddLastStatus(SPINEL_STATUS_DROPPED);
+ mUpdateChangedPropsTask.Post();
+ mDroppedOutboundIpFrameCounter++;
+ }
+ else
+ {
+ if (isSecure)
+ {
+ mOutboundSecureIpFrameCounter++;
+ }
+ else
+ {
+ mOutboundInsecureIpFrameCounter++;
+ }
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// MARK: Property/Status Changed
+// ----------------------------------------------------------------------------
+
+void NcpBase::HandleNetifStateChanged(uint32_t aFlags, void *aContext)
+{
+ NcpBase *ncp = static_cast(aContext);
+
+ ncp->mThreadChangedFlags |= aFlags;
+ ncp->mUpdateChangedPropsTask.Post();
+}
+
+void NcpBase::ProcessThreadChangedFlags(void)
+{
+ static const struct
+ {
+ uint32_t mThreadFlag;
+ spinel_prop_key_t mPropKey;
+ } kFlags[] =
+ {
+ { OT_CHANGED_IP6_ADDRESS_ADDED, SPINEL_PROP_IPV6_ADDRESS_TABLE },
+ { OT_CHANGED_IP6_ADDRESS_REMOVED, SPINEL_PROP_IPV6_ADDRESS_TABLE },
+ { OT_CHANGED_THREAD_ROLE, SPINEL_PROP_NET_ROLE },
+ { OT_CHANGED_THREAD_LL_ADDR, SPINEL_PROP_IPV6_LL_ADDR },
+ { OT_CHANGED_THREAD_ML_ADDR, SPINEL_PROP_IPV6_ML_ADDR },
+ { OT_CHANGED_THREAD_PARTITION_ID, SPINEL_PROP_NET_PARTITION_ID },
+ { OT_CHANGED_THREAD_KEY_SEQUENCE_COUNTER, SPINEL_PROP_NET_KEY_SEQUENCE_COUNTER },
+ { OT_CHANGED_THREAD_NETDATA, SPINEL_PROP_THREAD_LEADER_NETWORK_DATA },
+ { OT_CHANGED_THREAD_CHILD_ADDED, SPINEL_PROP_THREAD_CHILD_TABLE },
+ { OT_CHANGED_THREAD_CHILD_REMOVED, SPINEL_PROP_THREAD_CHILD_TABLE },
+ { OT_CHANGED_IP6_MULTICAST_SUBSRCRIBED, SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE },
+ { OT_CHANGED_IP6_MULTICAST_UNSUBSRCRIBED, SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE },
+ };
+
+ VerifyOrExit(mThreadChangedFlags != 0);
+
+ // If thread role has changed, check for possible "join" error.
+
+ if ((mThreadChangedFlags & OT_CHANGED_THREAD_ROLE) != 0)
+ {
+ if (mRequireJoinExistingNetwork)
+ {
+ switch (otThreadGetDeviceRole(mInstance))
+ {
+ case OT_DEVICE_ROLE_DETACHED:
+ case OT_DEVICE_ROLE_DISABLED:
+ break;
+
+ default:
+ mRequireJoinExistingNetwork = false;
+ mChangedPropsSet.AddProperty(SPINEL_PROP_NET_REQUIRE_JOIN_EXISTING);
+ break;
+ }
+
+ if ((otThreadGetDeviceRole(mInstance) == OT_DEVICE_ROLE_LEADER)
+ && otThreadIsSingleton(mInstance)
+#if OPENTHREAD_ENABLE_LEGACY
+ && !mLegacyNodeDidJoin
+#endif
+ )
+ {
+ mThreadChangedFlags &= ~static_cast(OT_CHANGED_THREAD_PARTITION_ID);
+ otThreadSetEnabled(mInstance, false);
+
+ mChangedPropsSet.AddProperty(SPINEL_PROP_NET_STACK_UP);
+ mChangedPropsSet.AddLastStatus(SPINEL_STATUS_JOIN_FAILURE);
+ }
+ }
+ }
+
+ // Convert OT_CHANGED flags to corresponding NCP property update.
+
+ for (unsigned i = 0; i < sizeof(kFlags) / sizeof(kFlags[0]); i++)
+ {
+ uint32_t threadFlag = kFlags[i].mThreadFlag;
+
+ if (mThreadChangedFlags & threadFlag)
+ {
+ mChangedPropsSet.AddProperty(kFlags[i].mPropKey);
+
+ if (threadFlag == OT_CHANGED_THREAD_NETDATA)
+ {
+ mChangedPropsSet.AddProperty(SPINEL_PROP_THREAD_ON_MESH_NETS);
+ mChangedPropsSet.AddProperty(SPINEL_PROP_THREAD_OFF_MESH_ROUTES);
+ }
+
+ mThreadChangedFlags &= ~threadFlag;
+ VerifyOrExit(mThreadChangedFlags != 0);
+ }
+ }
+
+ // Clear any remaining ThreadFlag that has no matching
+ // NCP property update (e.g., OT_CHANGED_THREAD_RLOC_ADDED)
+
+ mThreadChangedFlags = 0;
+
+exit:
+ return;
+}
+
+
+} // namespace Ncp
+} // namespace ot
+
+// ----------------------------------------------------------------------------
+// MARK: Legacy network APIs
+// ----------------------------------------------------------------------------
+
+void otNcpRegisterLegacyHandlers(const otNcpLegacyHandlers *aHandlers)
+{
+#if OPENTHREAD_ENABLE_LEGACY
+ ot::Ncp::NcpBase *ncp = ot::Ncp::NcpBase::GetNcpInstance();
+
+ if (ncp != NULL)
+ {
+ ncp->RegisterLegacyHandlers(aHandlers);
+ }
+
+#else
+ OT_UNUSED_VARIABLE(aHandlers);
+#endif
+}
+
+void otNcpHandleDidReceiveNewLegacyUlaPrefix(const uint8_t *aUlaPrefix)
+{
+#if OPENTHREAD_ENABLE_LEGACY
+ ot::Ncp::NcpBase *ncp = ot::Ncp::NcpBase::GetNcpInstance();
+
+ if (ncp != NULL)
+ {
+ ncp->HandleDidReceiveNewLegacyUlaPrefix(aUlaPrefix);
+ }
+
+#else
+ OT_UNUSED_VARIABLE(aUlaPrefix);
+#endif
+}
+
+void otNcpHandleLegacyNodeDidJoin(const otExtAddress *aExtAddr)
+{
+#if OPENTHREAD_ENABLE_LEGACY
+ ot::Ncp::NcpBase *ncp = ot::Ncp::NcpBase::GetNcpInstance();
+
+ if (ncp != NULL)
+ {
+ ncp->HandleLegacyNodeDidJoin(aExtAddr);
+ }
+
+#else
+ OT_UNUSED_VARIABLE(aExtAddr);
+#endif
+}
+
+#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
diff --git a/src/ncp/ncp_base_radio.cpp b/src/ncp/ncp_base_radio.cpp
new file mode 100644
index 000000000..84c461676
--- /dev/null
+++ b/src/ncp/ncp_base_radio.cpp
@@ -0,0 +1,712 @@
+/*
+ * Copyright (c) 2016-2017, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * This file implements raw link required Spinel interface to the OpenThread stack.
+ */
+
+#include
+
+#include "ncp_base.hpp"
+
+#include
+
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+
+#include "openthread-instance.h"
+#include "common/code_utils.hpp"
+#include "common/debug.hpp"
+#include "net/ip6.hpp"
+
+#if OPENTHREAD_ENABLE_RAW_LINK_API
+namespace ot {
+namespace Ncp {
+
+// ----------------------------------------------------------------------------
+// MARK: Raw Link-Layer Datapath Glue
+// ----------------------------------------------------------------------------
+
+void NcpBase::LinkRawReceiveDone(otInstance *, otRadioFrame *aFrame, otError aError)
+{
+ sNcpInstance->LinkRawReceiveDone(aFrame, aError);
+}
+
+void NcpBase::LinkRawReceiveDone(otRadioFrame *aFrame, otError aError)
+{
+ uint16_t flags = 0;
+ uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0;
+
+ SuccessOrExit(OutboundFrameBegin(header));
+
+ if (aFrame->mDidTX)
+ {
+ flags |= SPINEL_MD_FLAG_TX;
+ }
+
+ // Append frame header and frame length
+ SuccessOrExit(
+ OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_COMMAND_PROP_S SPINEL_DATATYPE_UINT16_S,
+ header,
+ SPINEL_CMD_PROP_VALUE_IS,
+ SPINEL_PROP_STREAM_RAW,
+ (aError == OT_ERROR_NONE) ? aFrame->mLength : 0
+ ));
+
+ if (aError == OT_ERROR_NONE)
+ {
+ // Append the frame contents
+ SuccessOrExit(OutboundFrameFeedData(aFrame->mPsdu, aFrame->mLength));
+ }
+
+ // Append metadata (rssi, etc)
+ SuccessOrExit(
+ OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_INT8_S
+ SPINEL_DATATYPE_INT8_S
+ SPINEL_DATATYPE_UINT16_S
+ SPINEL_DATATYPE_STRUCT_S( // PHY-data
+ SPINEL_DATATYPE_UINT8_S // 802.15.4 channel
+ SPINEL_DATATYPE_UINT8_S // 802.15.4 LQI
+ SPINEL_DATATYPE_UINT32_S // The timestamp milliseconds
+ SPINEL_DATATYPE_UINT16_S // The timestamp microseconds
+ )
+ SPINEL_DATATYPE_STRUCT_S( // Vendor-data
+ SPINEL_DATATYPE_UINT_PACKED_S
+ ),
+ aFrame->mPower, // TX Power
+ -128, // Noise Floor (Currently unused)
+ flags, // Flags
+ aFrame->mChannel, // Receive channel
+ aFrame->mLqi, // Link quality indicator
+ aFrame->mMsec, // The timestamp milliseconds
+ aFrame->mUsec, // The timestamp microseconds, offset to mMsec
+ aError // Receive error
+ ));
+
+ SuccessOrExit(OutboundFrameSend());
+
+exit:
+ return;
+}
+
+void NcpBase::LinkRawTransmitDone(otInstance *, otRadioFrame *aFrame,
+ otRadioFrame *aAckFrame, otError aError)
+{
+ sNcpInstance->LinkRawTransmitDone(aFrame, aAckFrame, aError);
+}
+
+void NcpBase::LinkRawTransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError)
+{
+ if (mCurTransmitTID)
+ {
+ uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0 | mCurTransmitTID;
+ bool framePending = (aAckFrame != NULL && static_cast(aAckFrame)->GetFramePending());
+
+ // Clear cached transmit TID
+ mCurTransmitTID = 0;
+
+ SuccessOrExit(OutboundFrameBegin(header));
+
+ SuccessOrExit(OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_COMMAND_PROP_S SPINEL_DATATYPE_UINT_PACKED_S SPINEL_DATATYPE_BOOL_S,
+ header,
+ SPINEL_CMD_PROP_VALUE_IS,
+ SPINEL_PROP_LAST_STATUS,
+ ThreadErrorToSpinelStatus(aError),
+ framePending
+ ));
+
+ if (aAckFrame && aError == OT_ERROR_NONE)
+ {
+ SuccessOrExit(OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT16_S, aAckFrame->mLength));
+ SuccessOrExit(OutboundFrameFeedData(aAckFrame->mPsdu, aAckFrame->mLength));
+ SuccessOrExit(OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_INT8_S
+ SPINEL_DATATYPE_INT8_S
+ SPINEL_DATATYPE_UINT16_S
+ SPINEL_DATATYPE_STRUCT_S( // PHY-data
+ SPINEL_DATATYPE_UINT8_S // 802.15.4 channel
+ SPINEL_DATATYPE_UINT8_S // 802.15.4 LQI
+ ),
+ aAckFrame->mPower, // RSSI
+ -128, // Noise Floor (Currently unused)
+ 0, // Flags
+ aAckFrame->mChannel, // Receive channel
+ aAckFrame->mLqi, // Link quality indicator
+ aFrame->mMsec, // The timestamp milliseconds
+ aFrame->mUsec // The timestamp microseconds, offset to mMsec
+ ));
+ }
+
+ SuccessOrExit(OutboundFrameSend());
+ }
+
+exit:
+ OT_UNUSED_VARIABLE(aFrame);
+ return;
+}
+
+void NcpBase::LinkRawEnergyScanDone(otInstance *, int8_t aEnergyScanMaxRssi)
+{
+ sNcpInstance->LinkRawEnergyScanDone(aEnergyScanMaxRssi);
+}
+
+void NcpBase::LinkRawEnergyScanDone(int8_t aEnergyScanMaxRssi)
+{
+ SendPropertyUpdate(
+ SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
+ SPINEL_CMD_PROP_VALUE_IS,
+ SPINEL_PROP_MAC_ENERGY_SCAN_RESULT,
+ SPINEL_DATATYPE_UINT8_S
+ SPINEL_DATATYPE_INT8_S,
+ mCurScanChannel,
+ aEnergyScanMaxRssi
+ );
+
+ // Clear current scan channel
+ mCurScanChannel = kInvalidScanChannel;
+
+ // Make sure we are back listening on the original receive channel,
+ // since the energy scan could have been on a different channel.
+ otLinkRawReceive(mInstance, mCurReceiveChannel, &NcpBase::LinkRawReceiveDone);
+
+ // We are finished with the scan, so send out
+ // a property update indicating such.
+ SendPropertyUpdate(
+ SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
+ SPINEL_CMD_PROP_VALUE_IS,
+ SPINEL_PROP_MAC_SCAN_STATE,
+ SPINEL_DATATYPE_UINT8_S,
+ SPINEL_SCAN_STATE_IDLE
+ );
+}
+
+// ----------------------------------------------------------------------------
+// MARK: Raw frame handling
+// ----------------------------------------------------------------------------
+
+void NcpBase::HandleRawFrame(const otRadioFrame *aFrame, void *aContext)
+{
+ static_cast(aContext)->HandleRawFrame(aFrame);
+}
+
+void NcpBase::HandleRawFrame(const otRadioFrame *aFrame)
+{
+ uint16_t flags = 0;
+ uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0;
+
+ if (!mIsRawStreamEnabled)
+ {
+ goto exit;
+ }
+
+ SuccessOrExit(OutboundFrameBegin(header));
+
+ if (aFrame->mDidTX)
+ {
+ flags |= SPINEL_MD_FLAG_TX;
+ }
+
+ // Append frame header and frame length
+ SuccessOrExit(
+ OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_COMMAND_PROP_S SPINEL_DATATYPE_UINT16_S,
+ header,
+ SPINEL_CMD_PROP_VALUE_IS,
+ SPINEL_PROP_STREAM_RAW,
+ aFrame->mLength
+ ));
+
+ // Append the frame contents
+ SuccessOrExit(OutboundFrameFeedData(aFrame->mPsdu, aFrame->mLength));
+
+ // Append metadata (rssi, etc)
+ SuccessOrExit(
+ OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_INT8_S
+ SPINEL_DATATYPE_INT8_S
+ SPINEL_DATATYPE_UINT16_S
+ SPINEL_DATATYPE_STRUCT_S( // PHY-data
+ SPINEL_DATATYPE_NULL_S // Empty for now
+ )
+ SPINEL_DATATYPE_STRUCT_S( // Vendor-data
+ SPINEL_DATATYPE_NULL_S // Empty for now
+ ),
+ aFrame->mPower, // TX Power
+ -128, // Noise Floor (Currently unused)
+ flags // Flags
+
+ // Skip PHY and Vendor data for now
+ ));
+
+ SuccessOrExit(OutboundFrameSend());
+
+exit:
+ return;
+}
+
+otError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ bool enabled;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_BOOL_S,
+ &enabled
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ error = otLinkRawSrcMatchEnable(mInstance, enabled);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ const uint8_t *data = aValuePtr;
+ uint16_t dataLen = aValueLen;
+
+ // Clear the list first
+ error = otLinkRawSrcMatchClearShortEntries(mInstance);
+
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+
+ // Loop through the addresses and add them
+ while (dataLen >= sizeof(uint16_t))
+ {
+ spinel_ssize_t parsedLength;
+ uint16_t short_address;
+
+ parsedLength = spinel_datatype_unpack(
+ data,
+ dataLen,
+ SPINEL_DATATYPE_UINT16_S,
+ &short_address
+ );
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ data += parsedLength;
+ dataLen -= (uint16_t)parsedLength;
+
+ error = otLinkRawSrcMatchAddShortEntry(mInstance, short_address);
+
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+ }
+
+ error =
+ SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+
+otError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ const uint8_t *data = aValuePtr;
+ uint16_t dataLen = aValueLen;
+
+ // Clear the list first
+ error = otLinkRawSrcMatchClearExtEntries(mInstance);
+
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+
+ // Loop through the addresses and add them
+ while (dataLen >= sizeof(otExtAddress))
+ {
+ spinel_ssize_t parsedLength;
+ otExtAddress *extAddress;
+
+ parsedLength = spinel_datatype_unpack(
+ data,
+ dataLen,
+ SPINEL_DATATYPE_EUI64_S,
+ &extAddress
+ );
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ data += parsedLength;
+ dataLen -= (uint16_t)parsedLength;
+
+ error = otLinkRawSrcMatchAddExtEntry(mInstance, extAddress);
+
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+ }
+
+ error =
+ SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+
+otError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ uint16_t shortAddress;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT16_S,
+ &shortAddress
+ );
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ error = otLinkRawSrcMatchClearShortEntry(mInstance, shortAddress);
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_REMOVED,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+
+otError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ otExtAddress *extAddress;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_EUI64_S,
+ &extAddress
+ );
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ error = otLinkRawSrcMatchClearExtEntry(mInstance, extAddress);
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_REMOVED,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+
+otError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ uint16_t short_address;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT16_S,
+ &short_address
+ );
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ error = otLinkRawSrcMatchAddShortEntry(mInstance, short_address);
+
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_INSERTED,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+
+otError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(uint8_t aHeader, spinel_prop_key_t aKey,
+ const uint8_t *aValuePtr, uint16_t aValueLen)
+{
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+ spinel_status_t spinelError = SPINEL_STATUS_OK;
+ otExtAddress *extAddress = NULL;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_EUI64_S,
+ &extAddress
+ );
+
+ VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
+
+ error = otLinkRawSrcMatchAddExtEntry(mInstance, extAddress);
+
+ VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+
+ error = SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_INSERTED,
+ aKey,
+ aValuePtr,
+ aValueLen
+ );
+
+exit:
+
+ if (spinelError != SPINEL_STATUS_OK)
+ {
+ error = SendLastStatus(aHeader, spinelError);
+ }
+
+ return error;
+}
+
+otError NcpBase::GetPropertyHandler_PHY_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_BOOL_S,
+ otLinkRawIsEnabled(mInstance)
+ );
+}
+
+otError NcpBase::SetPropertyHandler_PHY_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ bool value = false;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_BOOL_S,
+ &value
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ if (value == false)
+ {
+ // If we have raw stream enabled stop receiving
+ if (mIsRawStreamEnabled)
+ {
+ otLinkRawSleep(mInstance);
+ }
+
+ error = otLinkRawSetEnable(mInstance, false);
+ }
+ else
+ {
+ error = otLinkRawSetEnable(mInstance, true);
+
+ // If we have raw stream enabled already, start receiving
+ if (error == OT_ERROR_NONE && mIsRawStreamEnabled)
+ {
+ error = otLinkRawReceive(mInstance, mCurReceiveChannel, &NcpBase::LinkRawReceiveDone);
+ }
+ }
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::GetPropertyHandler_MAC_15_4_SADDR(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ return SendPropertyUpdate(
+ aHeader,
+ SPINEL_CMD_PROP_VALUE_IS,
+ aKey,
+ SPINEL_DATATYPE_UINT16_S,
+ otLinkGetShortAddress(mInstance)
+ );
+}
+
+otError NcpBase::SetPropertyHandler_MAC_15_4_SADDR(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ uint16_t shortAddress;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_UINT16_S,
+ &shortAddress
+ );
+
+ VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+
+ error = otLinkRawSetShortAddress(mInstance, shortAddress);
+
+exit:
+ return SendSetPropertyResponse(aHeader, aKey, error);
+}
+
+otError NcpBase::SetPropertyHandler_STREAM_RAW(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
+ uint16_t aValueLen)
+{
+ uint8_t *frame_buffer = NULL;
+ otRadioFrame *frame;
+ unsigned int frameLen = 0;
+ spinel_ssize_t parsedLength;
+ otError error = OT_ERROR_NONE;
+
+ VerifyOrExit(otLinkRawIsEnabled(mInstance), error = OT_ERROR_INVALID_STATE);
+
+ frame = otLinkRawGetTransmitBuffer(mInstance);
+
+ parsedLength = spinel_datatype_unpack(
+ aValuePtr,
+ aValueLen,
+ SPINEL_DATATYPE_DATA_WLEN_S
+ SPINEL_DATATYPE_UINT8_S
+ SPINEL_DATATYPE_INT8_S,
+ &frame_buffer,
+ &frameLen,
+ &frame->mChannel,
+ &frame->mPower
+ );
+
+ VerifyOrExit(parsedLength > 0 && frameLen <= OT_RADIO_FRAME_MAX_SIZE, error = OT_ERROR_PARSE);
+
+ // Cache the transaction ID for async response
+ mCurTransmitTID = SPINEL_HEADER_GET_TID(aHeader);
+
+ // Update frame buffer and length
+ frame->mLength = static_cast(frameLen);
+ memcpy(frame->mPsdu, frame_buffer, frame->mLength);
+
+ // TODO: This should be later added in the STREAM_RAW argument to allow user to directly specify it.
+ frame->mMaxTxAttempts = OPENTHREAD_CONFIG_MAX_TX_ATTEMPTS_DIRECT;
+
+ // Pass frame to the radio layer. Note, this fails if we
+ // haven't enabled raw stream or are already transmitting.
+ error = otLinkRawTransmit(mInstance, frame, &NcpBase::LinkRawTransmitDone);
+
+exit:
+
+ if (error == OT_ERROR_NONE)
+ {
+ // Don't do anything here yet. We will complete the transaction when we get a transmit done callback
+ }
+ else
+ {
+ error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
+ }
+
+ OT_UNUSED_VARIABLE(aKey);
+
+ return error;
+}
+
+} // namespace Ncp
+} // namespace ot
+
+#endif // OPENTHREAD_ENABLE_RAW_LINK_API
diff --git a/src/ncp/ncp_buffer.cpp b/src/ncp/ncp_buffer.cpp
index 8cf79d167..a33c8f178 100644
--- a/src/ncp/ncp_buffer.cpp
+++ b/src/ncp/ncp_buffer.cpp
@@ -38,6 +38,7 @@
#include "common/debug.hpp"
namespace ot {
+namespace Ncp {
const NcpFrameBuffer::FrameTag NcpFrameBuffer::kInvalidTag = NULL;
@@ -902,4 +903,5 @@ NcpFrameBuffer::FrameTag NcpFrameBuffer::OutFrameGetTag(void)
return IsEmpty() ? kInvalidTag : mReadFrameStart[mReadDirection];
}
+} // namespace Ncp
} // namespace ot
diff --git a/src/ncp/ncp_buffer.hpp b/src/ncp/ncp_buffer.hpp
index 6d6c39c0e..ba49a62fe 100644
--- a/src/ncp/ncp_buffer.hpp
+++ b/src/ncp/ncp_buffer.hpp
@@ -38,6 +38,7 @@
#include
namespace ot {
+namespace Ncp {
/**
@@ -626,6 +627,7 @@ private:
uint8_t * mReadMessageTail; // Pointer to end of current part in mMessageBuffer.
};
+} // namespace Ncp
} // namespace ot
#endif // NCP_FRAME_BUFFER_HPP_
diff --git a/src/ncp/ncp_spi.cpp b/src/ncp/ncp_spi.cpp
index 744250db6..14c186ce2 100644
--- a/src/ncp/ncp_spi.cpp
+++ b/src/ncp/ncp_spi.cpp
@@ -53,6 +53,7 @@
#if OPENTHREAD_ENABLE_NCP_SPI
namespace ot {
+namespace Ncp {
static otDEFINE_ALIGNED_VAR(sNcpRaw, sizeof(NcpSpi), uint64_t);
@@ -377,6 +378,7 @@ void NcpSpi::HandleRxFrame(void)
}
}
+} // namespace Ncp
} // namespace ot
#endif // OPENTHREAD_ENABLE_NCP_SPI
diff --git a/src/ncp/ncp_spi.hpp b/src/ncp/ncp_spi.hpp
index 55cbf2276..b565e3fca 100644
--- a/src/ncp/ncp_spi.hpp
+++ b/src/ncp/ncp_spi.hpp
@@ -38,6 +38,7 @@
#include "ncp/ncp_base.hpp"
namespace ot {
+namespace Ncp {
class NcpSpi : public NcpBase
{
@@ -105,6 +106,7 @@ private:
uint8_t mEmptyReceiveFrame[kSpiHeaderLength];
};
+} // namespace Ncp
} // namespace ot
#endif // NCP_SPI_HPP_
diff --git a/src/ncp/ncp_uart.cpp b/src/ncp/ncp_uart.cpp
index 88982b4c4..b97bbb2f8 100644
--- a/src/ncp/ncp_uart.cpp
+++ b/src/ncp/ncp_uart.cpp
@@ -51,6 +51,7 @@
#if OPENTHREAD_ENABLE_NCP_UART
namespace ot {
+namespace Ncp {
static otDEFINE_ALIGNED_VAR(sNcpRaw, sizeof(NcpUart), uint64_t);
@@ -301,6 +302,7 @@ void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat
#endif
#endif // OPENTHREAD_ENABLE_CLI_LOGGING
+} // namespace Ncp
} // namespace ot
#endif // OPENTHREAD_ENABLE_NCP_UART
diff --git a/src/ncp/ncp_uart.hpp b/src/ncp/ncp_uart.hpp
index a80d2a824..0bced9ce6 100644
--- a/src/ncp/ncp_uart.hpp
+++ b/src/ncp/ncp_uart.hpp
@@ -39,6 +39,7 @@
#include "ncp/ncp_base.hpp"
namespace ot {
+namespace Ncp {
class NcpUart : public NcpBase
{
@@ -116,6 +117,7 @@ private:
Tasklet mUartSendTask;
};
+} // namespace Ncp
} // namespace ot
#endif // NCP_UART_HPP_
diff --git a/tests/unit/test_ncp_buffer.cpp b/tests/unit/test_ncp_buffer.cpp
index f52c861dc..645a8cde7 100644
--- a/tests/unit/test_ncp_buffer.cpp
+++ b/tests/unit/test_ncp_buffer.cpp
@@ -39,6 +39,7 @@
#include "test_util.h"
namespace ot {
+namespace Ncp {
// This module implements unit-test for NcpFrameBuffer class.
@@ -1089,13 +1090,14 @@ void TestFuzzNcpFrameBuffer(void)
testFreeInstance(sInstance);
}
+} // namespace Ncp
} // namespace ot
#ifdef ENABLE_TEST_MAIN
int main(void)
{
- ot::TestNcpFrameBuffer();
- ot::TestFuzzNcpFrameBuffer();
+ ot::Ncp::TestNcpFrameBuffer();
+ ot::Ncp::TestFuzzNcpFrameBuffer();
printf("\nAll tests passed.\n");
return 0;
}
diff --git a/tests/unit/test_windows.cpp b/tests/unit/test_windows.cpp
index cfd002387..524595e8a 100644
--- a/tests/unit/test_windows.cpp
+++ b/tests/unit/test_windows.cpp
@@ -71,10 +71,11 @@ void TestMessageQueue();
void TestPriorityQueue();
// test_ncp_buffer.cpp
-namespace ot
-{
+namespace ot {
+namespace Ncp {
void TestNcpFrameBuffer(void);
}
+}
// test_timer.cpp
int TestOneTimer();
@@ -162,7 +163,7 @@ namespace ot
TEST_METHOD(TestTenTimers) { ::TestTenTimers(); }
// test_ncp_buffer.cpp
- TEST_METHOD(TestNcpFrameBuffer) { ot::TestNcpFrameBuffer(); }
+ TEST_METHOD(TestNcpFrameBuffer) { ot::Ncp::TestNcpFrameBuffer(); }
// test_toolchain.cpp
TEST_METHOD(test_packed1) { ::test_packed1(); }