[ncp] enhance unsolicited property/status updates (#1993)

This commit implements a new model for keeping track of unsolicited
property updates and how asynchronous `VALUE_IS` spinel frames are
emitted from NCP.  It also implements a mechanism for host to block
updates from certain filterable properties. The behavior can be
controlled through spinel properties `UNSOL_UPDATE_FILTER` and
`UNSOL_UPDATE_LIST` (tied to capability `CAP_UNSOL_UPDATE_FILTER`).

The new model is then used to track dropped IPv6 messages, end of
scan, change in jamming state, and a newly added STATUS_NOMEM report
in case of no NCP buffer space for log messages.
This commit is contained in:
Abtin Keshavarzian
2017-07-18 14:13:56 -07:00
committed by Jonathan Hui
parent cb463add61
commit 9839e9702b
4 changed files with 760 additions and 322 deletions
+536 -312
View File
File diff suppressed because it is too large Load Diff
+175 -6
View File
@@ -214,6 +214,7 @@ private:
static void UpdateChangedProps(Tasklet &aTasklet);
void UpdateChangedProps(void);
void ProcessThreadChangedFlags(void);
static void SendDoneTask(void *aContext);
void SendDoneTask(void);
@@ -344,6 +345,8 @@ private:
NCP_GET_PROP_HANDLER(HWADDR);
NCP_GET_PROP_HANDLER(LOCK);
NCP_GET_PROP_HANDLER(HOST_POWER_STATE);
NCP_GET_PROP_HANDLER(UNSOL_UPDATE_FILTER);
NCP_GET_PROP_HANDLER(UNSOL_UPDATE_LIST);
NCP_GET_PROP_HANDLER(PHY_ENABLED);
NCP_GET_PROP_HANDLER(PHY_FREQ);
NCP_GET_PROP_HANDLER(PHY_CHAN_SUPPORTED);
@@ -444,6 +447,7 @@ private:
#endif
#if OPENTHREAD_ENABLE_LEGACY
NCP_GET_PROP_HANDLER(NEST_LEGACY_ULA_PREFIX);
NCP_GET_PROP_HANDLER(NEST_LEGACY_LAST_NODE_JOINED);
#endif
// Property Set Handlers
@@ -452,6 +456,7 @@ private:
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);
@@ -539,6 +544,7 @@ private:
// Property Insert Handlers
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);
@@ -561,6 +567,7 @@ private:
// 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);
@@ -602,6 +609,169 @@ protected:
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).
@@ -614,18 +784,16 @@ private:
bool mDiscoveryScanJoinerFlag;
bool mDiscoveryScanEnableFiltering;
uint16_t mDiscoveryScanPanId;
Tasklet mUpdateChangedPropsTask;
uint32_t mChangedFlags;
bool mShouldSignalEndOfScan;
uint32_t mThreadChangedFlags;
ChangedPropsSet mChangedPropsSet;
spinel_host_power_state_t mHostPowerState;
bool mHostPowerStateInProgress;
NcpFrameBuffer::FrameTag mHostPowerReplyFrameTag;
uint8_t mHostPowerStateHeader;
#if OPENTHREAD_ENABLE_JAM_DETECTION
bool mShouldSignalJamStateChange;
#endif
#if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
otNcpDelegateAllowPeekPoke mAllowPeekDelegate;
otNcpDelegateAllowPeekPoke mAllowPokeDelegate;
@@ -661,6 +829,7 @@ private:
#if OPENTHREAD_ENABLE_LEGACY
const otNcpLegacyHandlers *mLegacyHandlers;
uint8_t mLegacyUlaPrefix[OT_NCP_LEGACY_ULA_PREFIX_LENGTH];
otExtAddress mLegacyLastJoinedNode;
bool mLegacyNodeDidJoin;
#endif
+14 -2
View File
@@ -972,6 +972,14 @@ spinel_prop_key_to_cstr(spinel_prop_key_t prop_key)
ret = "PROP_TRNG_RAW_32";
break;
case SPINEL_PROP_UNSOL_UPDATE_FILTER:
ret = "PROP_UNSOL_UPDATE_FILTER";
break;
case SPINEL_PROP_UNSOL_UPDATE_LIST:
ret = "PROP_UNSOL_UPDATE_LIST";
break;
case SPINEL_PROP_PHY_ENABLED:
ret = "PROP_PHY_ENABLED";
break;
@@ -1568,8 +1576,8 @@ spinel_prop_key_to_cstr(spinel_prop_key_t prop_key)
ret = "PROP_NEST_LEGACY_ULA_PREFIX";
break;
case SPINEL_PROP_NEST_LEGACY_JOINED_NODE:
ret = "PROP_NEST_LEGACY_JOINED_NODE";
case SPINEL_PROP_NEST_LEGACY_LAST_NODE_JOINED:
ret = "PROP_NEST_LEGACY_LAST_NODE_JOINED";
break;
case SPINEL_PROP_DEBUG_TEST_ASSERT:
@@ -1819,6 +1827,10 @@ const char *spinel_capability_to_cstr(unsigned int capability)
ret = "CAP_CMD_MULTI";
break;
case SPINEL_CAP_UNSOL_UPDATE_FILTER:
ret = "CAP_UNSOL_UPDATE_FILTER";
break;
case SPINEL_CAP_802_15_4_2003:
ret = "CAP_802_15_4_2003";
break;
+35 -2
View File
@@ -365,6 +365,7 @@ enum
SPINEL_CAP_GPIO = 9,
SPINEL_CAP_TRNG = 10,
SPINEL_CAP_CMD_MULTI = 11,
SPINEL_CAP_UNSOL_UPDATE_FILTER = 12,
SPINEL_CAP_802_15_4__BEGIN = 16,
SPINEL_CAP_802_15_4_2003 = (SPINEL_CAP_802_15_4__BEGIN + 0),
@@ -550,6 +551,37 @@ typedef enum
/// Raw samples from TRNG entropy source representing 32 bits of entropy.
SPINEL_PROP_TRNG_RAW_32 = SPINEL_PROP_BASE_EXT__BEGIN + 7,
/// NCP Unsolicited update filter
/** Format: `A(I)`
* Type: Read-Write (optional Insert-Remove)
* Required capability: `CAP_UNSOL_UPDATE_FILTER`
*
* Contains a list of properties which are excluded from generating
* unsolicited value updates. This property is empty after reset.
* In other words, the host may opt-out of unsolicited property updates
* for a specific property by adding that property id to this list.
* Hosts SHOULD NOT add properties to this list which are not
* present in `PROP_UNSOL_UPDATE_LIST`. If such properties are added,
* the NCP ignores the unsupported properties.
*/
SPINEL_PROP_UNSOL_UPDATE_FILTER = SPINEL_PROP_BASE_EXT__BEGIN + 8,
/// List of properties capable of generating unsolicited value update.
/** Format: `A(I)`
* Type: Read-Only
* Required capability: `CAP_UNSOL_UPDATE_FILTER`
*
* Contains a list of properties which are capable of generating
* unsolicited value updates. This list can be used when populating
* `PROP_UNSOL_UPDATE_FILTER` to disable all unsolicited property
* updates.
*
* This property is intended to effectively behave as a constant
* for a given NCP firmware.
*/
SPINEL_PROP_UNSOL_UPDATE_LIST = SPINEL_PROP_BASE_EXT__BEGIN + 9,
SPINEL_PROP_BASE_EXT__END = 0x1100,
SPINEL_PROP_PHY__BEGIN = 0x20,
@@ -1275,9 +1307,10 @@ typedef enum
/** Format: 'D' */
SPINEL_PROP_NEST_LEGACY_ULA_PREFIX = SPINEL_PROP_NEST__BEGIN + 1,
/// A (newly) joined legacy node (this is signaled from NCP)
/// The EUI64 of last node joined using legacy protocol (if none, all zero EUI64 is returned).
/** Format: 'E' */
SPINEL_PROP_NEST_LEGACY_JOINED_NODE = SPINEL_PROP_NEST__BEGIN + 2,
SPINEL_PROP_NEST_LEGACY_LAST_NODE_JOINED
= SPINEL_PROP_NEST__BEGIN + 2,
SPINEL_PROP_NEST__END = 15360,