[nedata] add API to retrieve Commissioning Dataset (#9551)

This commit adds `otNetDataGetCommissioningDataset()` as a public
API to retrieve the Commissioning Dataset from the Network Data.

It also updates CLI `netdata show` command to output the Commissioning
Dataset information. The documentation in `README_NETDATA.md` and
in `cli_network_data` are also updated. The test scripts that parse
`netdata show` output are also updated.
This commit is contained in:
Abtin Keshavarzian
2023-10-23 05:17:51 -07:00
committed by GitHub
parent a7643db4f2
commit 28f30b3ce8
15 changed files with 288 additions and 161 deletions
+1
View File
@@ -111,6 +111,7 @@ typedef struct otCommissioningDataset
bool mIsSessionIdSet : 1; ///< TRUE if Commissioner Session Id is set, FALSE otherwise.
bool mIsSteeringDataSet : 1; ///< TRUE if Steering Data is set, FALSE otherwise.
bool mIsJoinerUdpPortSet : 1; ///< TRUE if Joiner UDP Port is set, FALSE otherwise.
bool mHasExtraTlv : 1; ///< TRUE if the Dataset contains any extra unknown sub-TLV, FALSE otherwise.
} otCommissioningDataset;
#define OT_JOINER_MAX_PSKD_LENGTH 32 ///< Maximum string length of a Joiner PSKd (does not include null char).
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (367)
#define OPENTHREAD_API_VERSION (368)
/**
* @addtogroup api-instance
+10
View File
@@ -35,6 +35,7 @@
#ifndef OPENTHREAD_NETDATA_H_
#define OPENTHREAD_NETDATA_H_
#include <openthread/commissioner.h>
#include <openthread/ip6.h>
#ifdef __cplusplus
@@ -242,6 +243,15 @@ otError otNetDataGetNextLowpanContextInfo(otInstance *aInstance,
otNetworkDataIterator *aIterator,
otLowpanContextInfo *aContextInfo);
/**
* Gets the Commissioning Dataset from the partition's Network Data.
*
* @param[in] aInstance A pointer to the OpenThread instance.
* @param[out] aDataset A pointer to a `otCommissioningDataset` to populate.
*
*/
void otNetDataGetCommissioningDataset(otInstance *aInstance, otCommissioningDataset *aDataset);
/**
* Get the Network Data Version.
*
+11
View File
@@ -379,6 +379,15 @@ Service entries are listed under `Services` header:
- Context ID
- Compress flag (`c` if marked or `-` otherwise).
Commissioning Dataset information is printed under `Commissioning` header:
- Session ID if present in Dataset or `-` otherwise
- Border Agent RLOC16 (in hex) if present in Dataset or `-` otherwise
- Joiner UDP port number if present in Dataset or `-` otherwise
- Steering Data (as hex bytes) if present in Dataset or `-` otherwise
- Flags:
- e: if Dataset contains any extra unknown TLV
Print Network Data received from the Leader.
```bash
@@ -392,6 +401,8 @@ Services:
44970 5d fddead00beef00007bad0069ce45948504d2 s a000
Contexts:
fd00:dead:beef:cafe::/64 1 c
Commissioning:
1248 dc00 9988 00000000000120000000000000000000 e
Done
```
+38
View File
@@ -662,6 +662,33 @@ exit:
return;
}
void NetworkData::OutputCommissioningDataset(bool aLocal)
{
otCommissioningDataset dataset;
VerifyOrExit(!aLocal);
otNetDataGetCommissioningDataset(GetInstancePtr(), &dataset);
OutputLine("Commissioning:");
dataset.mIsSessionIdSet ? OutputFormat("%u ", dataset.mSessionId) : OutputFormat("- ");
dataset.mIsLocatorSet ? OutputFormat("%04x ", dataset.mLocator) : OutputFormat("- ");
dataset.mIsJoinerUdpPortSet ? OutputFormat("%u ", dataset.mJoinerUdpPort) : OutputFormat("- ");
dataset.mIsSteeringDataSet ? OutputBytes(dataset.mSteeringData.m8, dataset.mSteeringData.mLength)
: OutputFormat("-");
if (dataset.mHasExtraTlv)
{
OutputFormat(" e");
}
OutputNewLine();
exit:
return;
}
otError NetworkData::OutputBinary(bool aLocal)
{
otError error;
@@ -701,6 +728,8 @@ exit:
* 44970 01 9a04b000000e10 s 4000
* Contexts:
* fd00:dead:beef:cafe::/64 1 c
* Commissioning:
* 1248 dc00 9988 00000000000120000000000000000000 e
* Done
* @endcode
* @code
@@ -751,6 +780,14 @@ exit:
* * Context ID
* * Compress flag (`c` if marked or `-` otherwise).
* @par
* Commissioning Dataset information is printed under `Commissioning` header:
* * Session ID if present in Dataset or `-` otherwise
* * Border Agent RLOC16 (in hex) if present in Dataset or `-` otherwise
* * Joiner UDP port number if present in Dataset or `-` otherwise
* * Steering Data (as hex bytes) if present in Dataset or `-` otherwise
* * Flags:
* * e: If Dataset contains any extra unknown TLV
* @par
* @moreinfo{@netdata}.
* @csa{br omrprefix}
* @csa{br onlinkprefix}
@@ -809,6 +846,7 @@ template <> otError NetworkData::Process<Cmd("show")>(Arg aArgs[])
OutputRoutes(local);
OutputServices(local);
OutputLowpanContexts(local);
OutputCommissioningDataset(local);
error = OT_ERROR_NONE;
}
+1
View File
@@ -143,6 +143,7 @@ private:
void OutputRoutes(bool aLocal);
void OutputServices(bool aLocal);
void OutputLowpanContexts(bool aLocal);
void OutputCommissioningDataset(bool aLocal);
#if OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL
static void HandleNetdataFull(void *aContext) { static_cast<NetworkData *>(aContext)->HandleNetdataFull(); }
+5
View File
@@ -104,6 +104,11 @@ otError otNetDataGetNextLowpanContextInfo(otInstance *aInstance,
AsCoreType(aContextInfo));
}
void otNetDataGetCommissioningDataset(otInstance *aInstance, otCommissioningDataset *aDataset)
{
return AsCoreType(aInstance).Get<NetworkData::Leader>().GetCommissioningDataset(AsCoreType(aDataset));
}
uint8_t otNetDataGetVersion(otInstance *aInstance)
{
return AsCoreType(aInstance).Get<Mle::MleRouter>().GetLeaderData().GetDataVersion(NetworkData::kFullSet);
+5 -3
View File
@@ -392,8 +392,8 @@ exit:
void Commissioner::SendCommissionerSet(void)
{
Error error = kErrorNone;
Dataset dataset;
Error error = kErrorNone;
CommissioningDataset dataset;
VerifyOrExit(mState == kStateActive, error = kErrorInvalidState);
@@ -671,7 +671,9 @@ exit:
return;
}
Error Commissioner::SendMgmtCommissionerSetRequest(const Dataset &aDataset, const uint8_t *aTlvs, uint8_t aLength)
Error Commissioner::SendMgmtCommissionerSetRequest(const CommissioningDataset &aDataset,
const uint8_t *aTlvs,
uint8_t aLength)
{
Error error = kErrorNone;
Coap::Message *message;
+1 -130
View File
@@ -96,134 +96,6 @@ public:
typedef otCommissionerStateCallback StateCallback; ///< State change callback function pointer type.
typedef otCommissionerJoinerCallback JoinerCallback; ///< Joiner state change callback function pointer type.
/**
* Represents a Commissioning Dataset.
*
*/
class Dataset : public otCommissioningDataset, public Clearable<Dataset>
{
public:
/**
* Indicates whether or not the Border Router RLOC16 Locator is set in the Dataset.
*
* @returns TRUE if Border Router RLOC16 Locator is set, FALSE otherwise.
*
*/
bool IsLocatorSet(void) const { return mIsLocatorSet; }
/**
* Gets the Border Router RLOC16 Locator in the Dataset.
*
* MUST be used when Locator is set in the Dataset, otherwise its behavior is undefined.
*
* @returns The Border Router RLOC16 Locator in the Dataset.
*
*/
uint16_t GetLocator(void) const { return mLocator; }
/**
* Sets the Border Router RLOCG16 Locator in the Dataset.
*
* @param[in] aLocator A Locator.
*
*/
void SetLocator(uint16_t aLocator)
{
mIsLocatorSet = true;
mLocator = aLocator;
}
/**
* Indicates whether or not the Session ID is set in the Dataset.
*
* @returns TRUE if Session ID is set, FALSE otherwise.
*
*/
bool IsSessionIdSet(void) const { return mIsSessionIdSet; }
/**
* Gets the Session ID in the Dataset.
*
* MUST be used when Session ID is set in the Dataset, otherwise its behavior is undefined.
*
* @returns The Session ID in the Dataset.
*
*/
uint16_t GetSessionId(void) const { return mSessionId; }
/**
* Sets the Session ID in the Dataset.
*
* @param[in] aSessionId The Session ID.
*
*/
void SetSessionId(uint16_t aSessionId)
{
mIsSessionIdSet = true;
mSessionId = aSessionId;
}
/**
* Indicates whether or not the Steering Data is set in the Dataset.
*
* @returns TRUE if Steering Data is set, FALSE otherwise.
*
*/
bool IsSteeringDataSet(void) const { return mIsSteeringDataSet; }
/**
* Gets the Steering Data in the Dataset.
*
* MUST be used when Steering Data is set in the Dataset, otherwise its behavior is undefined.
*
* @returns The Steering Data in the Dataset.
*
*/
const SteeringData &GetSteeringData(void) const { return AsCoreType(&mSteeringData); }
/**
* Returns a reference to the Steering Data in the Dataset to be updated by caller.
*
* @returns A reference to the Steering Data in the Dataset.
*
*/
SteeringData &UpdateSteeringData(void)
{
mIsSteeringDataSet = true;
return AsCoreType(&mSteeringData);
}
/**
* Indicates whether or not the Joiner UDP port is set in the Dataset.
*
* @returns TRUE if Joiner UDP port is set, FALSE otherwise.
*
*/
bool IsJoinerUdpPortSet(void) const { return mIsJoinerUdpPortSet; }
/**
* Gets the Joiner UDP port in the Dataset.
*
* MUST be used when Joiner UDP port is set in the Dataset, otherwise its behavior is undefined.
*
* @returns The Joiner UDP port in the Dataset.
*
*/
uint16_t GetJoinerUdpPort(void) const { return mJoinerUdpPort; }
/**
* Sets the Joiner UDP Port in the Dataset.
*
* @param[in] aJoinerUdpPort The Joiner UDP Port.
*
*/
void SetJoinerUdpPort(uint16_t aJoinerUdpPort)
{
mIsJoinerUdpPortSet = true;
mJoinerUdpPort = aJoinerUdpPort;
}
};
/**
* Initializes the Commissioner object.
*
@@ -460,7 +332,7 @@ public:
* @retval kErrorInvalidState Commissioner service is not started.
*
*/
Error SendMgmtCommissionerSetRequest(const Dataset &aDataset, const uint8_t *aTlvs, uint8_t aLength);
Error SendMgmtCommissionerSetRequest(const CommissioningDataset &aDataset, const uint8_t *aTlvs, uint8_t aLength);
/**
* Returns a reference to the AnnounceBeginClient instance.
@@ -633,7 +505,6 @@ DeclareTmfHandler(Commissioner, kUriJoinerFinalize);
DefineMapEnum(otCommissionerState, MeshCoP::Commissioner::State);
DefineMapEnum(otCommissionerJoinerEvent, MeshCoP::Commissioner::JoinerEvent);
DefineCoreType(otCommissioningDataset, MeshCoP::Commissioner::Dataset);
} // namespace ot
+129
View File
@@ -406,6 +406,134 @@ private:
void UpdateBloomFilter(const HashBitIndexes &aIndexes);
};
/**
* Represents a Commissioning Dataset.
*
*/
class CommissioningDataset : public otCommissioningDataset, public Clearable<CommissioningDataset>
{
public:
/**
* Indicates whether or not the Border Router RLOC16 Locator is set in the Dataset.
*
* @returns TRUE if Border Router RLOC16 Locator is set, FALSE otherwise.
*
*/
bool IsLocatorSet(void) const { return mIsLocatorSet; }
/**
* Gets the Border Router RLOC16 Locator in the Dataset.
*
* MUST be used when Locator is set in the Dataset, otherwise its behavior is undefined.
*
* @returns The Border Router RLOC16 Locator in the Dataset.
*
*/
uint16_t GetLocator(void) const { return mLocator; }
/**
* Sets the Border Router RLOCG16 Locator in the Dataset.
*
* @param[in] aLocator A Locator.
*
*/
void SetLocator(uint16_t aLocator)
{
mIsLocatorSet = true;
mLocator = aLocator;
}
/**
* Indicates whether or not the Session ID is set in the Dataset.
*
* @returns TRUE if Session ID is set, FALSE otherwise.
*
*/
bool IsSessionIdSet(void) const { return mIsSessionIdSet; }
/**
* Gets the Session ID in the Dataset.
*
* MUST be used when Session ID is set in the Dataset, otherwise its behavior is undefined.
*
* @returns The Session ID in the Dataset.
*
*/
uint16_t GetSessionId(void) const { return mSessionId; }
/**
* Sets the Session ID in the Dataset.
*
* @param[in] aSessionId The Session ID.
*
*/
void SetSessionId(uint16_t aSessionId)
{
mIsSessionIdSet = true;
mSessionId = aSessionId;
}
/**
* Indicates whether or not the Steering Data is set in the Dataset.
*
* @returns TRUE if Steering Data is set, FALSE otherwise.
*
*/
bool IsSteeringDataSet(void) const { return mIsSteeringDataSet; }
/**
* Gets the Steering Data in the Dataset.
*
* MUST be used when Steering Data is set in the Dataset, otherwise its behavior is undefined.
*
* @returns The Steering Data in the Dataset.
*
*/
const SteeringData &GetSteeringData(void) const { return static_cast<const SteeringData &>(mSteeringData); }
/**
* Returns a reference to the Steering Data in the Dataset to be updated by caller.
*
* @returns A reference to the Steering Data in the Dataset.
*
*/
SteeringData &UpdateSteeringData(void)
{
mIsSteeringDataSet = true;
return static_cast<SteeringData &>(mSteeringData);
}
/**
* Indicates whether or not the Joiner UDP port is set in the Dataset.
*
* @returns TRUE if Joiner UDP port is set, FALSE otherwise.
*
*/
bool IsJoinerUdpPortSet(void) const { return mIsJoinerUdpPortSet; }
/**
* Gets the Joiner UDP port in the Dataset.
*
* MUST be used when Joiner UDP port is set in the Dataset, otherwise its behavior is undefined.
*
* @returns The Joiner UDP port in the Dataset.
*
*/
uint16_t GetJoinerUdpPort(void) const { return mJoinerUdpPort; }
/**
* Sets the Joiner UDP Port in the Dataset.
*
* @param[in] aJoinerUdpPort The Joiner UDP Port.
*
*/
void SetJoinerUdpPort(uint16_t aJoinerUdpPort)
{
mIsJoinerUdpPortSet = true;
mJoinerUdpPort = aJoinerUdpPort;
}
};
/**
* Generates PSKc.
*
@@ -455,6 +583,7 @@ inline void LogError(const char *, Error) {}
DefineCoreType(otJoinerPskd, MeshCoP::JoinerPskd);
DefineCoreType(otJoinerDiscerner, MeshCoP::JoinerDiscerner);
DefineCoreType(otSteeringData, MeshCoP::SteeringData);
DefineCoreType(otCommissioningDataset, MeshCoP::CommissioningDataset);
} // namespace ot
+58 -23
View File
@@ -458,6 +458,44 @@ exit:
return error;
}
void LeaderBase::GetCommissioningDataset(MeshCoP::CommissioningDataset &aDataset) const
{
const CommissioningDataTlv *dataTlv = FindCommissioningData();
const MeshCoP::Tlv *subTlv;
const MeshCoP::Tlv *endTlv;
aDataset.Clear();
VerifyOrExit(dataTlv != nullptr);
aDataset.mIsLocatorSet = (FindBorderAgentRloc(aDataset.mLocator) == kErrorNone);
aDataset.mIsSessionIdSet = (FindCommissioningSessionId(aDataset.mSessionId) == kErrorNone);
aDataset.mIsJoinerUdpPortSet = (FindJoinerUdpPort(aDataset.mJoinerUdpPort) == kErrorNone);
aDataset.mIsSteeringDataSet = (FindSteeringData(AsCoreType(&aDataset.mSteeringData)) == kErrorNone);
// Determine if the Commissioning data has any extra unknown TLVs
subTlv = reinterpret_cast<const MeshCoP::Tlv *>(dataTlv->GetValue());
endTlv = reinterpret_cast<const MeshCoP::Tlv *>(dataTlv->GetValue() + dataTlv->GetLength());
for (; subTlv < endTlv; subTlv = subTlv->GetNext())
{
switch (subTlv->GetType())
{
case MeshCoP::Tlv::kBorderAgentLocator:
case MeshCoP::Tlv::kSteeringData:
case MeshCoP::Tlv::kJoinerUdpPort:
case MeshCoP::Tlv::kCommissionerSessionId:
break;
default:
ExitNow(aDataset.mHasExtraTlv = true);
}
}
exit:
return;
}
Error LeaderBase::FindBorderAgentRloc(uint16_t &aRloc16) const
{
return ReadCommissioningDataUint16SubTlv(MeshCoP::Tlv::kBorderAgentLocator, aRloc16);
@@ -473,23 +511,25 @@ Error LeaderBase::FindJoinerUdpPort(uint16_t &aPort) const
return ReadCommissioningDataUint16SubTlv(MeshCoP::Tlv::kJoinerUdpPort, aPort);
}
Error LeaderBase::FindSteeringData(MeshCoP::SteeringData &aSteeringData) const
{
Error error = kErrorNone;
const MeshCoP::SteeringDataTlv *steeringDataTlv = FindInCommissioningData<MeshCoP::SteeringDataTlv>();
VerifyOrExit(steeringDataTlv != nullptr, error = kErrorNotFound);
steeringDataTlv->CopyTo(aSteeringData);
exit:
return error;
}
bool LeaderBase::IsJoiningAllowed(void) const
{
bool isAllowed = false;
const MeshCoP::SteeringDataTlv *steeringDataTlv;
bool isAllowed = false;
MeshCoP::SteeringData steeringData;
VerifyOrExit(FindInCommissioningData<MeshCoP::BorderAgentLocatorTlv>() != nullptr);
steeringDataTlv = FindInCommissioningData<MeshCoP::SteeringDataTlv>();
VerifyOrExit(steeringDataTlv != nullptr);
for (int i = 0; i < steeringDataTlv->GetLength(); i++)
{
if (steeringDataTlv->GetValue()[i] != 0)
{
ExitNow(isAllowed = true);
}
}
SuccessOrExit(FindSteeringData(steeringData));
isAllowed = !steeringData.IsEmpty();
exit:
return isAllowed;
@@ -497,16 +537,11 @@ exit:
Error LeaderBase::SteeringDataCheck(const FilterIndexes &aFilterIndexes) const
{
Error error = kErrorNone;
const MeshCoP::SteeringDataTlv *steeringDataTlv;
MeshCoP::SteeringData steeringData;
Error error = kErrorInvalidState;
MeshCoP::SteeringData steeringData;
steeringDataTlv = FindInCommissioningData<MeshCoP::SteeringDataTlv>();
VerifyOrExit(steeringDataTlv != nullptr, error = kErrorInvalidState);
steeringDataTlv->CopyTo(steeringData);
VerifyOrExit(steeringData.Contains(aFilterIndexes), error = kErrorNotFound);
SuccessOrExit(FindSteeringData(steeringData));
error = steeringData.Contains(aFilterIndexes) ? kErrorNone : kErrorNotFound;
exit:
return error;
+19
View File
@@ -181,6 +181,14 @@ public:
uint16_t aOffset,
uint16_t aLength);
/**
* Gets the Commissioning Dataset from Network Data.
*
* @param[out] aDataset A reference to a `MeshCoP::CommissioningDataset` to populate.
*
*/
void GetCommissioningDataset(MeshCoP::CommissioningDataset &aDataset) const;
/**
* Searches for given sub-TLV in Commissioning Data TLV.
*
@@ -243,6 +251,17 @@ public:
*/
Error FindJoinerUdpPort(uint16_t &aPort) const;
/**
* Finds and read the Steering Data in Commissioning Data TLV.
*
* @param[out] aSteeringData A reference to return the read Steering Data.
*
* @retval kErrorNone Successfully read the Steering Data, @p aSteeringData is updated.
* @retval kErrorNotFound Did not find Steering Data sub-TLV.
*
*/
Error FindSteeringData(MeshCoP::SteeringData &aSteeringData) const;
/**
* Indicates whether or not the Commissioning Data TLV indicates Joining is allowed.
*
+2 -2
View File
@@ -2336,8 +2336,8 @@ class NodeImpl:
def get_netdata(self):
raw_netdata = self.netdata_show()
netdata = {'Prefixes': [], 'Routes': [], 'Services': [], 'Contexts': []}
key_list = ['Prefixes', 'Routes', 'Services', 'Contexts']
netdata = {'Prefixes': [], 'Routes': [], 'Services': [], 'Contexts': [], 'Commissioning': []}
key_list = ['Prefixes', 'Routes', 'Services', 'Contexts', 'Commissioning']
key = None
for i in range(0, len(raw_netdata)):
+3 -1
View File
@@ -387,11 +387,13 @@ class Node(object):
routes_index = outputs.index('Routes:')
services_index = outputs.index('Services:')
contexts_index = outputs.index('Contexts:')
commissioning_index = outputs.index('Commissioning:')
result = {}
result['prefixes'] = outputs[1:routes_index]
result['routes'] = outputs[routes_index + 1:services_index]
result['services'] = outputs[services_index + 1:contexts_index]
result['contexts'] = outputs[contexts_index + 1:]
result['contexts'] = outputs[contexts_index + 1:commissioning_index]
result['commissioning'] = outputs[commissioning_index + 1:]
return result
+4 -1
View File
@@ -1701,7 +1701,7 @@ class OpenThreadTHCI(object):
@watched
def getNetworkData(self):
lines = self.__executeCommand('netdata show')
prefixes, routes, services, contexts = [], [], [], []
prefixes, routes, services, contexts, commissioning = [], [], [], []
classify = None
for line in lines:
@@ -1713,6 +1713,8 @@ class OpenThreadTHCI(object):
classify = services
elif line == 'Contexts:':
classify = contexts
elif line == 'Commissioning':
classify = commissioning
elif line == 'Done':
classify = None
else:
@@ -1723,6 +1725,7 @@ class OpenThreadTHCI(object):
'Routes': routes,
'Services': services,
'Contexts': contexts,
'Commissioning': commissioning,
}
@API