[spinel] add spinel property to send mgmt set dataset in TLVs format (#10587)

This commit adds a new spinel property
`SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS` to do network
migration operation on NCP.

The existing property `SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET`
cannot be used for two reasons:
1. It uses a structured format instead of raw TLVs format.
2. The set handler of `SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET`
   doesn't call `otDatasetSendMgmtPendingSet` with a callback. On NCP,
   we want to know the result of the MGMT_SET operation. (accepted,
   rejected or timeout)

This new property works similarly as
`SPINEL_PROP_NET_LEAVE_GRACEFULLY` added in
https://github.com/openthread/openthread/pull/10337

1. Host sets the property to NCP.
2. NCP will give an immediate response on the result of
   `otDatasetSendMgmtPendingSet`.
   - If succeeded, NCP will respond an empty property
     `SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS`
   - If failed, NCP will respond a LAST_STATUS of the error info.
3. When the callback of `otDatasetSendMgmtPendingSet` is called, NCP
   will send a notification of
   `SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS` to the host to
   notify the result of the operation.
This commit is contained in:
Li Cao
2024-08-07 21:43:22 -06:00
committed by GitHub
parent cc16fc2d67
commit d034b5c850
7 changed files with 66 additions and 0 deletions
+1
View File
@@ -1363,6 +1363,7 @@ const char *spinel_prop_key_to_cstr(spinel_prop_key_t prop_key)
{SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_REGISTER, "THREAD_BACKBONE_ROUTER_LOCAL_REGISTER"},
{SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_REGISTRATION_JITTER,
"THREAD_BACKBONE_ROUTER_LOCAL_REGISTRATION_JITTER"},
{SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS, "THREAD_MGMT_SET_PENDING_DATASET_TLVS"},
{SPINEL_PROP_MESHCOP_JOINER_STATE, "MESHCOP_JOINER_STATE"},
{SPINEL_PROP_MESHCOP_JOINER_COMMISSIONING, "MESHCOP_JOINER_COMMISSIONING"},
{SPINEL_PROP_IPV6_LL_ADDR, "IPV6_LL_ADDR"},
+19
View File
@@ -3412,6 +3412,25 @@ enum
*/
SPINEL_PROP_THREAD_PENDING_DATASET_TLVS = SPINEL_PROP_THREAD_EXT__BEGIN + 61,
/// Send MGMT_SET Thread Pending Operational Dataset (in TLV format).
/** Format: `D` - Write only
*
* This is write-only property. When written, it triggers a MGMT_PENDING_SET meshcop command to be sent to leader
* with the given Dataset.
*
* When setting this property, the spinel frame response will be:
* 1. A `LAST_STATUS` with the status of the transmission of MGMT_PENDING_SET command if it fails.
* 2. A `SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS` with no content.
*
* On response reception or timeout, another notification will be sent to the host:
* A `SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS` with a spinel_status_t indicating
* the result of MGMT_SET_PENDING.
*
* On write, any unknown/unsupported TLVs must be ignored.
*
*/
SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS = SPINEL_PROP_THREAD_EXT__BEGIN + 62,
SPINEL_PROP_THREAD_EXT__END = 0x1600,
SPINEL_PROP_IPV6__BEGIN = 0x60,
+1
View File
@@ -92,6 +92,7 @@ const ChangedPropsSet::Entry ChangedPropsSet::mSupportedProps[] = {
{SPINEL_PROP_THREAD_NETWORK_TIME, SPINEL_STATUS_OK, false},
#endif
{SPINEL_PROP_PARENT_RESPONSE_INFO, SPINEL_STATUS_OK, true},
{SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS, SPINEL_STATUS_OK, false},
};
uint8_t ChangedPropsSet::GetNumEntries(void) const
+1
View File
@@ -315,6 +315,7 @@ NcpBase::NcpBase(Instance *aInstance)
, mRxSpinelOutOfOrderTidCounter(0)
, mTxSpinelFrameCounter(0)
, mDidInitialUpdates(false)
, mDatasetSendMgmtPendingSetResult(SPINEL_STATUS_OK)
, mLogTimestampBase(0)
#if OPENTHREAD_CONFIG_DIAG_ENABLE
, mDiagOutput(nullptr)
+6
View File
@@ -624,6 +624,10 @@ protected:
void ThreadDetachGracefullyHandler(void);
static void DatasetSendMgmtPendingSetHandler(otError aResult, void *aContext);
void DatasetSendMgmtPendingSetHandler(otError aResult);
protected:
static NcpBase *sNcpInstance;
static spinel_status_t ThreadErrorToSpinelStatus(otError aError);
@@ -738,6 +742,8 @@ protected:
bool mDidInitialUpdates;
spinel_status_t mDatasetSendMgmtPendingSetResult;
uint64_t mLogTimestampBase; // Timestamp base used for logging
#if OPENTHREAD_CONFIG_DIAG_ENABLE
+2
View File
@@ -336,6 +336,7 @@ NcpBase::PropertyHandler NcpBase::FindGetPropertyHandler(spinel_prop_key_t aKey)
#endif
OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_THREAD_ACTIVE_DATASET_TLVS),
OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_THREAD_PENDING_DATASET_TLVS),
OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS),
#if OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE
OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_CHANNEL_MANAGER_NEW_CHANNEL),
OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_CHANNEL_MANAGER_DELAY),
@@ -607,6 +608,7 @@ NcpBase::PropertyHandler NcpBase::FindSetPropertyHandler(spinel_prop_key_t aKey)
#endif
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_THREAD_ACTIVE_DATASET_TLVS),
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_THREAD_PENDING_DATASET_TLVS),
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS),
#if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_MESHCOP_COMMISSIONER_ANNOUNCE_BEGIN),
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_MESHCOP_COMMISSIONER_ENERGY_SCAN),
+36
View File
@@ -1739,6 +1739,42 @@ exit:
return error;
}
void NcpBase::DatasetSendMgmtPendingSetHandler(otError aResult, void *aContext)
{
static_cast<NcpBase *>(aContext)->DatasetSendMgmtPendingSetHandler(aResult);
}
void NcpBase::DatasetSendMgmtPendingSetHandler(otError aResult)
{
mDatasetSendMgmtPendingSetResult = ThreadErrorToSpinelStatus(aResult);
mChangedPropsSet.AddProperty(SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS);
mUpdateChangedPropsTask.Post();
}
template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS>(void)
{
return mEncoder.WriteUint32(mDatasetSendMgmtPendingSetResult);
}
template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS>(void)
{
otError error = OT_ERROR_NONE;
otOperationalDataset emptyDataset;
const uint8_t *data;
uint16_t len;
memset(&emptyDataset, 0, sizeof(emptyDataset));
SuccessOrExit(error = mDecoder.ReadData(data, len));
VerifyOrExit(len < OT_OPERATIONAL_DATASET_MAX_LENGTH, error = OT_ERROR_PARSE);
error = otDatasetSendMgmtPendingSet(mInstance, &emptyDataset, data, static_cast<uint8_t>(len),
DatasetSendMgmtPendingSetHandler, this);
exit:
return error;
}
template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_MGMT_GET_ACTIVE_DATASET>(void)
{
otError error = OT_ERROR_NONE;